Merge commit 'linus/master' into HEAD
authorVegard Nossum <vegard.nossum@gmail.com>
Mon, 15 Jun 2009 13:50:49 +0000 (15:50 +0200)
committerVegard Nossum <vegard.nossum@gmail.com>
Mon, 15 Jun 2009 13:50:49 +0000 (15:50 +0200)
Conflicts:
MAINTAINERS

Signed-off-by: Vegard Nossum <vegard.nossum@gmail.com>
2145 files changed:
.gitignore
Documentation/Changes
Documentation/CodingStyle
Documentation/DMA-API.txt
Documentation/RCU/rculist_nulls.txt
Documentation/SM501.txt
Documentation/SubmittingPatches
Documentation/arm/Samsung-S3C24XX/GPIO.txt
Documentation/block/deadline-iosched.txt
Documentation/braille-console.txt
Documentation/dell_rbu.txt
Documentation/development-process/5.Posting
Documentation/driver-model/devres.txt
Documentation/edac.txt
Documentation/fb/sh7760fb.txt
Documentation/feature-removal-schedule.txt
Documentation/filesystems/autofs4-mount-control.txt
Documentation/filesystems/caching/netfs-api.txt
Documentation/filesystems/debugfs.txt [new file with mode: 0644]
Documentation/filesystems/ext4.txt
Documentation/filesystems/fiemap.txt
Documentation/filesystems/nfs-rdma.txt
Documentation/filesystems/proc.txt
Documentation/filesystems/sysfs-pci.txt
Documentation/filesystems/vfat.txt
Documentation/gpio.txt
Documentation/i2c/busses/i2c-ocores
Documentation/ide/ide.txt
Documentation/kbuild/kconfig.txt
Documentation/kbuild/modules.txt
Documentation/kdump/kdump.txt
Documentation/kernel-parameters.txt
Documentation/kobject.txt
Documentation/laptops/acer-wmi.txt
Documentation/laptops/sony-laptop.txt
Documentation/laptops/thinkpad-acpi.txt
Documentation/lguest/Makefile
Documentation/lguest/lguest.c
Documentation/lguest/lguest.txt
Documentation/local_ops.txt
Documentation/memory-hotplug.txt
Documentation/mn10300/ABI.txt
Documentation/mtd/nand_ecc.txt
Documentation/networking/bonding.txt
Documentation/networking/can.txt
Documentation/networking/dm9000.txt
Documentation/networking/l2tp.txt
Documentation/networking/netdevices.txt
Documentation/networking/phonet.txt
Documentation/networking/regulatory.txt
Documentation/power/devices.txt
Documentation/power/regulator/consumer.txt
Documentation/power/regulator/overview.txt
Documentation/power/s2ram.txt
Documentation/power/userland-swsusp.txt
Documentation/powerpc/booting-without-of.txt
Documentation/powerpc/dts-bindings/fsl/board.txt
Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm.txt
Documentation/powerpc/dts-bindings/fsl/cpm_qe/gpio.txt
Documentation/powerpc/dts-bindings/fsl/msi-pic.txt
Documentation/powerpc/dts-bindings/fsl/pmc.txt
Documentation/powerpc/qe_firmware.txt
Documentation/rbtree.txt
Documentation/s390/Debugging390.txt
Documentation/scheduler/sched-nice-design.txt
Documentation/scsi/aic79xx.txt
Documentation/scsi/ncr53c8xx.txt
Documentation/scsi/sym53c8xx_2.txt
Documentation/sound/alsa/ALSA-Configuration.txt
Documentation/sound/alsa/HD-Audio-Models.txt
Documentation/sound/alsa/HD-Audio.txt
Documentation/sound/alsa/Procfile.txt
Documentation/sound/alsa/README.maya44 [new file with mode: 0644]
Documentation/sound/alsa/hda_codec.txt
Documentation/sound/alsa/soc/dapm.txt
Documentation/sysctl/vm.txt
Documentation/timers/hpet.txt
Documentation/timers/timer_stats.txt
Documentation/trace/ftrace.txt
Documentation/trace/kmemtrace.txt
Documentation/usb/WUSB-Design-overview.txt
Documentation/usb/anchors.txt
Documentation/usb/callbacks.txt
Documentation/video4linux/cx18.txt
Documentation/x86/x86_64/boot-options.txt
Documentation/x86/x86_64/machinecheck
MAINTAINERS
Makefile
README
arch/alpha/include/asm/atomic.h
arch/alpha/include/asm/bitsperlong.h [new file with mode: 0644]
arch/alpha/include/asm/page.h
arch/alpha/include/asm/signal.h
arch/alpha/include/asm/suspend.h [deleted file]
arch/alpha/include/asm/types.h
arch/alpha/mm/extable.c
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/boot/compressed/Makefile
arch/arm/boot/compressed/head.S
arch/arm/common/Kconfig
arch/arm/common/Makefile
arch/arm/common/clkdev.c
arch/arm/common/sharpsl_pm.c [deleted file]
arch/arm/common/vic.c
arch/arm/configs/cm_x300_defconfig
arch/arm/configs/davinci_all_defconfig
arch/arm/configs/ep93xx_defconfig
arch/arm/configs/kirkwood_defconfig
arch/arm/configs/magician_defconfig
arch/arm/configs/mx21_defconfig [new file with mode: 0644]
arch/arm/configs/omap3_evm_defconfig [new file with mode: 0644]
arch/arm/configs/omap_4430sdp_defconfig [new file with mode: 0644]
arch/arm/configs/omap_zoom2_defconfig [new file with mode: 0644]
arch/arm/configs/orion5x_defconfig
arch/arm/configs/rx51_defconfig
arch/arm/configs/stmp378x_defconfig [new file with mode: 0644]
arch/arm/configs/stmp37xx_defconfig [new file with mode: 0644]
arch/arm/configs/u300_defconfig [new file with mode: 0644]
arch/arm/configs/w90p910_defconfig
arch/arm/include/asm/atomic.h
arch/arm/include/asm/bitsperlong.h [new file with mode: 0644]
arch/arm/include/asm/cacheflush.h
arch/arm/include/asm/cputype.h
arch/arm/include/asm/hardware/arm_twd.h [deleted file]
arch/arm/include/asm/hardware/cache-l2x0.h
arch/arm/include/asm/hardware/pl080.h [new file with mode: 0644]
arch/arm/include/asm/hardware/sharpsl_pm.h [deleted file]
arch/arm/include/asm/hardware/vic.h
arch/arm/include/asm/localtimer.h [new file with mode: 0644]
arch/arm/include/asm/mach/map.h
arch/arm/include/asm/mman.h
arch/arm/include/asm/page.h
arch/arm/include/asm/pgtable.h
arch/arm/include/asm/processor.h
arch/arm/include/asm/ptrace.h
arch/arm/include/asm/signal.h
arch/arm/include/asm/sizes.h
arch/arm/include/asm/smp.h
arch/arm/include/asm/smp_scu.h [new file with mode: 0644]
arch/arm/include/asm/smp_twd.h [new file with mode: 0644]
arch/arm/include/asm/suspend.h [deleted file]
arch/arm/include/asm/tlbflush.h
arch/arm/include/asm/uaccess.h
arch/arm/kernel/Makefile
arch/arm/kernel/entry-armv.S
arch/arm/kernel/entry-common.S
arch/arm/kernel/process.c
arch/arm/kernel/signal.c
arch/arm/kernel/smp.c
arch/arm/kernel/smp_scu.c [new file with mode: 0644]
arch/arm/kernel/smp_twd.c [new file with mode: 0644]
arch/arm/kernel/vmlinux.lds.S
arch/arm/lib/Makefile
arch/arm/lib/clear_user.S
arch/arm/lib/copy_to_user.S
arch/arm/lib/uaccess_with_memcpy.c [new file with mode: 0644]
arch/arm/mach-at91/board-afeb-9260v1.c
arch/arm/mach-at91/board-sam9g20ek.c
arch/arm/mach-at91/clock.c
arch/arm/mach-at91/include/mach/at91_pmc.h
arch/arm/mach-davinci/Kconfig
arch/arm/mach-davinci/Makefile
arch/arm/mach-davinci/board-dm355-evm.c [new file with mode: 0644]
arch/arm/mach-davinci/board-dm355-leopard.c [new file with mode: 0644]
arch/arm/mach-davinci/board-dm644x-evm.c
arch/arm/mach-davinci/board-dm646x-evm.c [new file with mode: 0644]
arch/arm/mach-davinci/board-sffsdr.c [new file with mode: 0644]
arch/arm/mach-davinci/clock.c
arch/arm/mach-davinci/clock.h
arch/arm/mach-davinci/common.c [new file with mode: 0644]
arch/arm/mach-davinci/cp_intc.c [new file with mode: 0644]
arch/arm/mach-davinci/devices.c
arch/arm/mach-davinci/dm355.c [new file with mode: 0644]
arch/arm/mach-davinci/dm644x.c
arch/arm/mach-davinci/dm646x.c [new file with mode: 0644]
arch/arm/mach-davinci/gpio.c
arch/arm/mach-davinci/id.c [deleted file]
arch/arm/mach-davinci/include/mach/board-dm6446evm.h [deleted file]
arch/arm/mach-davinci/include/mach/common.h
arch/arm/mach-davinci/include/mach/cp_intc.h [new file with mode: 0644]
arch/arm/mach-davinci/include/mach/cputype.h
arch/arm/mach-davinci/include/mach/debug-macro.S
arch/arm/mach-davinci/include/mach/dm355.h [new file with mode: 0644]
arch/arm/mach-davinci/include/mach/dm644x.h
arch/arm/mach-davinci/include/mach/dm646x.h [new file with mode: 0644]
arch/arm/mach-davinci/include/mach/edma.h
arch/arm/mach-davinci/include/mach/emac.h [new file with mode: 0644]
arch/arm/mach-davinci/include/mach/entry-macro.S
arch/arm/mach-davinci/include/mach/gpio.h
arch/arm/mach-davinci/include/mach/irqs.h
arch/arm/mach-davinci/include/mach/memory.h
arch/arm/mach-davinci/include/mach/mmc.h [new file with mode: 0644]
arch/arm/mach-davinci/include/mach/mux.h
arch/arm/mach-davinci/include/mach/psc.h
arch/arm/mach-davinci/include/mach/serial.h
arch/arm/mach-davinci/include/mach/sram.h [new file with mode: 0644]
arch/arm/mach-davinci/include/mach/time.h [new file with mode: 0644]
arch/arm/mach-davinci/include/mach/uncompress.h
arch/arm/mach-davinci/io.c
arch/arm/mach-davinci/irq.c
arch/arm/mach-davinci/mux.c
arch/arm/mach-davinci/psc.c
arch/arm/mach-davinci/serial.c
arch/arm/mach-davinci/sram.c [new file with mode: 0644]
arch/arm/mach-davinci/time.c
arch/arm/mach-ep93xx/Kconfig
arch/arm/mach-ep93xx/Makefile
arch/arm/mach-ep93xx/Makefile.boot
arch/arm/mach-ep93xx/clock.c
arch/arm/mach-ep93xx/core.c
arch/arm/mach-ep93xx/edb9302.c [deleted file]
arch/arm/mach-ep93xx/edb9302a.c [deleted file]
arch/arm/mach-ep93xx/edb9307.c [deleted file]
arch/arm/mach-ep93xx/edb9307a.c [deleted file]
arch/arm/mach-ep93xx/edb9312.c [deleted file]
arch/arm/mach-ep93xx/edb9315.c [deleted file]
arch/arm/mach-ep93xx/edb9315a.c [deleted file]
arch/arm/mach-ep93xx/edb93xx.c [new file with mode: 0644]
arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
arch/arm/mach-ep93xx/include/mach/memory.h
arch/arm/mach-imx/Kconfig [deleted file]
arch/arm/mach-imx/Makefile [deleted file]
arch/arm/mach-imx/Makefile.boot [deleted file]
arch/arm/mach-imx/clock.c [deleted file]
arch/arm/mach-imx/cpufreq.c [deleted file]
arch/arm/mach-imx/dma.c [deleted file]
arch/arm/mach-imx/generic.c [deleted file]
arch/arm/mach-imx/generic.h [deleted file]
arch/arm/mach-imx/include/mach/debug-macro.S [deleted file]
arch/arm/mach-imx/include/mach/dma.h [deleted file]
arch/arm/mach-imx/include/mach/entry-macro.S [deleted file]
arch/arm/mach-imx/include/mach/gpio.h [deleted file]
arch/arm/mach-imx/include/mach/hardware.h [deleted file]
arch/arm/mach-imx/include/mach/imx-dma.h [deleted file]
arch/arm/mach-imx/include/mach/imx-regs.h [deleted file]
arch/arm/mach-imx/include/mach/imx-uart.h [deleted file]
arch/arm/mach-imx/include/mach/io.h [deleted file]
arch/arm/mach-imx/include/mach/irqs.h [deleted file]
arch/arm/mach-imx/include/mach/memory.h [deleted file]
arch/arm/mach-imx/include/mach/mmc.h [deleted file]
arch/arm/mach-imx/include/mach/mx1ads.h [deleted file]
arch/arm/mach-imx/include/mach/spi_imx.h [deleted file]
arch/arm/mach-imx/include/mach/system.h [deleted file]
arch/arm/mach-imx/include/mach/timex.h [deleted file]
arch/arm/mach-imx/include/mach/uncompress.h [deleted file]
arch/arm/mach-imx/include/mach/vmalloc.h [deleted file]
arch/arm/mach-imx/irq.c [deleted file]
arch/arm/mach-imx/leds-mx1ads.c [deleted file]
arch/arm/mach-imx/leds.c [deleted file]
arch/arm/mach-imx/leds.h [deleted file]
arch/arm/mach-imx/mx1ads.c [deleted file]
arch/arm/mach-imx/time.c [deleted file]
arch/arm/mach-ixp4xx/Kconfig
arch/arm/mach-ixp4xx/Makefile
arch/arm/mach-ixp4xx/goramo_mlr.c [new file with mode: 0644]
arch/arm/mach-ixp4xx/include/mach/cpu.h
arch/arm/mach-ixp4xx/include/mach/qmgr.h
arch/arm/mach-ixp4xx/ixp4xx_npe.c
arch/arm/mach-ixp4xx/ixp4xx_qmgr.c
arch/arm/mach-kirkwood/Kconfig
arch/arm/mach-kirkwood/Makefile
arch/arm/mach-kirkwood/addr-map.c
arch/arm/mach-kirkwood/common.c
arch/arm/mach-kirkwood/common.h
arch/arm/mach-kirkwood/cpuidle.c [new file with mode: 0644]
arch/arm/mach-kirkwood/db88f6281-bp-setup.c
arch/arm/mach-kirkwood/include/mach/bridge-regs.h
arch/arm/mach-kirkwood/include/mach/io.h
arch/arm/mach-kirkwood/include/mach/kirkwood.h
arch/arm/mach-kirkwood/mpp.c
arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c [new file with mode: 0644]
arch/arm/mach-kirkwood/pcie.c
arch/arm/mach-kirkwood/rd88f6192-nas-setup.c
arch/arm/mach-kirkwood/rd88f6281-setup.c
arch/arm/mach-kirkwood/sheevaplug-setup.c
arch/arm/mach-mmp/include/mach/irqs.h
arch/arm/mach-mmp/include/mach/mfp-pxa168.h
arch/arm/mach-mmp/include/mach/mfp-pxa910.h
arch/arm/mach-mmp/include/mach/pxa168.h
arch/arm/mach-mmp/include/mach/pxa910.h
arch/arm/mach-mmp/include/mach/regs-apbc.h
arch/arm/mach-mmp/pxa168.c
arch/arm/mach-mmp/pxa910.c
arch/arm/mach-mv78xx0/irq.c
arch/arm/mach-mx1/generic.c
arch/arm/mach-mx1/mx1ads.c
arch/arm/mach-mx1/scb9328.c
arch/arm/mach-mx2/Kconfig
arch/arm/mach-mx2/Makefile
arch/arm/mach-mx2/clock_imx21.c
arch/arm/mach-mx2/generic.c
arch/arm/mach-mx2/mx21ads.c [new file with mode: 0644]
arch/arm/mach-mx2/mx27ads.c
arch/arm/mach-mx2/mx27lite.c [new file with mode: 0644]
arch/arm/mach-mx2/mx27pdk.c [new file with mode: 0644]
arch/arm/mach-mx2/pcm038.c
arch/arm/mach-mx2/pcm970-baseboard.c
arch/arm/mach-mx3/Kconfig
arch/arm/mach-mx3/Makefile
arch/arm/mach-mx3/armadillo5x0.c [new file with mode: 0644]
arch/arm/mach-mx3/clock-imx35.c
arch/arm/mach-mx3/clock.c
arch/arm/mach-mx3/devices.c
arch/arm/mach-mx3/devices.h
arch/arm/mach-mx3/iomux.c
arch/arm/mach-mx3/mm.c
arch/arm/mach-mx3/mx31ads.c
arch/arm/mach-mx3/mx31lilly-db.c [new file with mode: 0644]
arch/arm/mach-mx3/mx31lilly.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/mx31pdk.c
arch/arm/mach-mx3/mx35pdk.c [new file with mode: 0644]
arch/arm/mach-mx3/pcm037.c
arch/arm/mach-mx3/pcm043.c [new file with mode: 0644]
arch/arm/mach-mx3/qong.c
arch/arm/mach-netx/generic.c
arch/arm/mach-omap1/Kconfig
arch/arm/mach-omap1/Makefile
arch/arm/mach-omap1/board-nokia770.c
arch/arm/mach-omap1/clock.c
arch/arm/mach-omap1/pm.c
arch/arm/mach-omap1/pm.h [new file with mode: 0644]
arch/arm/mach-omap1/serial.c
arch/arm/mach-omap1/sleep.S
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-4430sdp.c [new file with mode: 0644]
arch/arm/mach-omap2/board-ldp.c
arch/arm/mach-omap2/board-omap3beagle.c
arch/arm/mach-omap2/board-omap3evm.c [new file with mode: 0644]
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-zoom-debugboard.c [new file with mode: 0644]
arch/arm/mach-omap2/board-zoom2.c [new file with mode: 0644]
arch/arm/mach-omap2/clock.c
arch/arm/mach-omap2/clock24xx.c
arch/arm/mach-omap2/clock24xx.h
arch/arm/mach-omap2/clock34xx.c
arch/arm/mach-omap2/clock34xx.h
arch/arm/mach-omap2/clockdomains.h
arch/arm/mach-omap2/cm-regbits-34xx.h
arch/arm/mach-omap2/cm.h
arch/arm/mach-omap2/gpmc-onenand.c [new file with mode: 0644]
arch/arm/mach-omap2/gpmc-smc91x.c [new file with mode: 0644]
arch/arm/mach-omap2/gpmc.c
arch/arm/mach-omap2/id.c
arch/arm/mach-omap2/io.c
arch/arm/mach-omap2/iommu2.c [new file with mode: 0644]
arch/arm/mach-omap2/irq.c
arch/arm/mach-omap2/mmc-twl4030.c
arch/arm/mach-omap2/mmc-twl4030.h
arch/arm/mach-omap2/omap-headsmp.S [new file with mode: 0644]
arch/arm/mach-omap2/omap-smp.c [new file with mode: 0644]
arch/arm/mach-omap2/omap3-iommu.c [new file with mode: 0644]
arch/arm/mach-omap2/pm-debug.c [new file with mode: 0644]
arch/arm/mach-omap2/pm.c [deleted file]
arch/arm/mach-omap2/pm.h [new file with mode: 0644]
arch/arm/mach-omap2/pm24xx.c [new file with mode: 0644]
arch/arm/mach-omap2/pm34xx.c [new file with mode: 0644]
arch/arm/mach-omap2/prcm-common.h
arch/arm/mach-omap2/prm.h
arch/arm/mach-omap2/sdram-micron-mt46h32m32lf-6.h [new file with mode: 0644]
arch/arm/mach-omap2/sdram-qimonda-hyb18m512160af-6.h [new file with mode: 0644]
arch/arm/mach-omap2/sdrc.c
arch/arm/mach-omap2/sdrc2xxx.c
arch/arm/mach-omap2/serial.c
arch/arm/mach-omap2/sleep24xx.S
arch/arm/mach-omap2/sleep34xx.S [new file with mode: 0644]
arch/arm/mach-omap2/sram242x.S
arch/arm/mach-omap2/sram243x.S
arch/arm/mach-omap2/sram34xx.S
arch/arm/mach-omap2/timer-gp.c
arch/arm/mach-omap2/timer-mpu.c [new file with mode: 0644]
arch/arm/mach-omap2/usb-musb.c
arch/arm/mach-orion5x/addr-map.c
arch/arm/mach-orion5x/common.c
arch/arm/mach-orion5x/common.h
arch/arm/mach-orion5x/include/mach/bridge-regs.h
arch/arm/mach-orion5x/include/mach/orion5x.h
arch/arm/mach-orion5x/include/mach/system.h
arch/arm/mach-orion5x/mpp.c
arch/arm/mach-orion5x/mss2-setup.c
arch/arm/mach-orion5x/ts78xx-fpga.h
arch/arm/mach-orion5x/ts78xx-setup.c
arch/arm/mach-orion5x/wnr854t-setup.c
arch/arm/mach-pxa/Kconfig
arch/arm/mach-pxa/Makefile
arch/arm/mach-pxa/clock.c
arch/arm/mach-pxa/cm-x270.c
arch/arm/mach-pxa/cm-x300.c
arch/arm/mach-pxa/corgi.c
arch/arm/mach-pxa/corgi_pm.c
arch/arm/mach-pxa/cpufreq-pxa2xx.c
arch/arm/mach-pxa/csb726.c
arch/arm/mach-pxa/devices.c
arch/arm/mach-pxa/em-x270.c
arch/arm/mach-pxa/ezx.c
arch/arm/mach-pxa/hx4700.c [new file with mode: 0644]
arch/arm/mach-pxa/imote2.c
arch/arm/mach-pxa/include/mach/hx4700.h [new file with mode: 0644]
arch/arm/mach-pxa/include/mach/i2c.h [deleted file]
arch/arm/mach-pxa/include/mach/irqs.h
arch/arm/mach-pxa/include/mach/mfp-pxa320.h
arch/arm/mach-pxa/include/mach/palmld.h
arch/arm/mach-pxa/include/mach/pm.h
arch/arm/mach-pxa/include/mach/pxa27x.h
arch/arm/mach-pxa/include/mach/sharpsl_pm.h [new file with mode: 0644]
arch/arm/mach-pxa/include/mach/uncompress.h
arch/arm/mach-pxa/littleton.c
arch/arm/mach-pxa/magician.c
arch/arm/mach-pxa/mainstone.c
arch/arm/mach-pxa/mioa701.c
arch/arm/mach-pxa/palmld.c
arch/arm/mach-pxa/palmt5.c
arch/arm/mach-pxa/palmte2.c
arch/arm/mach-pxa/palmtx.c
arch/arm/mach-pxa/pcm990-baseboard.c
arch/arm/mach-pxa/pm.c
arch/arm/mach-pxa/poodle.c
arch/arm/mach-pxa/pwm.c [deleted file]
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/stargate2.c [new file with mode: 0644]
arch/arm/mach-pxa/tosa.c
arch/arm/mach-pxa/trizeps4.c
arch/arm/mach-pxa/viper.c
arch/arm/mach-pxa/zylonite_pxa300.c
arch/arm/mach-realview/Kconfig
arch/arm/mach-realview/Makefile
arch/arm/mach-realview/core.c
arch/arm/mach-realview/core.h
arch/arm/mach-realview/include/mach/board-eb.h
arch/arm/mach-realview/include/mach/board-pb1176.h
arch/arm/mach-realview/include/mach/board-pb11mp.h
arch/arm/mach-realview/include/mach/board-pba8.h
arch/arm/mach-realview/include/mach/board-pbx.h [new file with mode: 0644]
arch/arm/mach-realview/include/mach/debug-macro.S
arch/arm/mach-realview/include/mach/irqs-eb.h [new file with mode: 0644]
arch/arm/mach-realview/include/mach/irqs-pb1176.h [new file with mode: 0644]
arch/arm/mach-realview/include/mach/irqs-pb11mp.h [new file with mode: 0644]
arch/arm/mach-realview/include/mach/irqs-pba8.h [new file with mode: 0644]
arch/arm/mach-realview/include/mach/irqs-pbx.h [new file with mode: 0644]
arch/arm/mach-realview/include/mach/irqs.h
arch/arm/mach-realview/include/mach/scu.h [deleted file]
arch/arm/mach-realview/include/mach/uncompress.h
arch/arm/mach-realview/localtimer.c
arch/arm/mach-realview/platsmp.c
arch/arm/mach-realview/realview_eb.c
arch/arm/mach-realview/realview_pb1176.c
arch/arm/mach-realview/realview_pb11mp.c
arch/arm/mach-realview/realview_pbx.c [new file with mode: 0644]
arch/arm/mach-s3c2400/gpio.c
arch/arm/mach-s3c2410/Kconfig
arch/arm/mach-s3c2410/dma.c
arch/arm/mach-s3c2410/gpio.c
arch/arm/mach-s3c2410/h1940-bluetooth.c
arch/arm/mach-s3c2410/include/mach/dma.h
arch/arm/mach-s3c2410/include/mach/gpio-core.h
arch/arm/mach-s3c2410/include/mach/gpio-fns.h [new file with mode: 0644]
arch/arm/mach-s3c2410/include/mach/gpio-nrs.h
arch/arm/mach-s3c2410/include/mach/gpio.h
arch/arm/mach-s3c2410/include/mach/hardware.h
arch/arm/mach-s3c2410/include/mach/map.h
arch/arm/mach-s3c2410/include/mach/regs-gpio.h
arch/arm/mach-s3c2410/include/mach/system-reset.h
arch/arm/mach-s3c2410/mach-amlm5900.c
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/pm.c
arch/arm/mach-s3c2410/usb-simtec.c
arch/arm/mach-s3c2412/Kconfig
arch/arm/mach-s3c2412/dma.c
arch/arm/mach-s3c2412/mach-jive.c
arch/arm/mach-s3c2412/mach-smdk2413.c
arch/arm/mach-s3c2440/Kconfig
arch/arm/mach-s3c2440/dma.c
arch/arm/mach-s3c2440/mach-anubis.c
arch/arm/mach-s3c2440/mach-at2440evb.c
arch/arm/mach-s3c2440/mach-nexcoder.c
arch/arm/mach-s3c2440/mach-osiris.c
arch/arm/mach-s3c2443/dma.c
arch/arm/mach-s3c6400/Kconfig
arch/arm/mach-s3c6400/Makefile
arch/arm/mach-s3c6400/include/mach/dma.h
arch/arm/mach-s3c6400/include/mach/map.h
arch/arm/mach-s3c6400/include/mach/regs-clock.h [new file with mode: 0644]
arch/arm/mach-s3c6400/include/mach/system.h
arch/arm/mach-s3c6400/mach-smdk6400.c [new file with mode: 0644]
arch/arm/mach-s3c6400/s3c6400.c [new file with mode: 0644]
arch/arm/mach-s3c6400/setup-sdhci.c [new file with mode: 0644]
arch/arm/mach-s3c6410/Kconfig
arch/arm/mach-s3c6410/Makefile
arch/arm/mach-s3c6410/cpu.c
arch/arm/mach-s3c6410/mach-anw6410.c [new file with mode: 0644]
arch/arm/mach-s3c6410/mach-ncp.c [new file with mode: 0644]
arch/arm/mach-s3c6410/mach-smdk6410.c
arch/arm/mach-s3c6410/setup-sdhci.c
arch/arm/mach-sa1100/collie_pm.c [deleted file]
arch/arm/mach-sa1100/jornada720_ssp.c
arch/arm/mach-stmp378x/Makefile [new file with mode: 0644]
arch/arm/mach-stmp378x/Makefile.boot [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/entry-macro.S [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/irqs.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/pins.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-apbh.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-apbx.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-audioin.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-audioout.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-bch.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-clkctrl.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-dcp.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-digctl.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-dram.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-dri.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-ecc8.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-emi.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-gpmi.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-i2c.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-icoll.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-ir.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-lcdif.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-lradc.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-ocotp.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-pinctrl.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-power.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-pwm.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-pxp.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-rtc.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-saif.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-spdif.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-ssp.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-sydma.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-timrot.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-tvenc.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-uartapp.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-uartdbg.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-usbctrl.h [new file with mode: 0644]
arch/arm/mach-stmp378x/include/mach/regs-usbphy.h [new file with mode: 0644]
arch/arm/mach-stmp378x/stmp378x.c [new file with mode: 0644]
arch/arm/mach-stmp378x/stmp378x.h [new file with mode: 0644]
arch/arm/mach-stmp378x/stmp378x_devb.c [new file with mode: 0644]
arch/arm/mach-stmp37xx/Makefile [new file with mode: 0644]
arch/arm/mach-stmp37xx/Makefile.boot [new file with mode: 0644]
arch/arm/mach-stmp37xx/include/mach/entry-macro.S [new file with mode: 0644]
arch/arm/mach-stmp37xx/include/mach/irqs.h [new file with mode: 0644]
arch/arm/mach-stmp37xx/include/mach/pins.h [new file with mode: 0644]
arch/arm/mach-stmp37xx/include/mach/regs-apbh.h [new file with mode: 0644]
arch/arm/mach-stmp37xx/include/mach/regs-apbx.h [new file with mode: 0644]
arch/arm/mach-stmp37xx/include/mach/regs-audioin.h [new file with mode: 0644]
arch/arm/mach-stmp37xx/include/mach/regs-audioout.h [new file with mode: 0644]
arch/arm/mach-stmp37xx/include/mach/regs-clkctrl.h [new file with mode: 0644]
arch/arm/mach-stmp37xx/include/mach/regs-digctl.h [new file with mode: 0644]
arch/arm/mach-stmp37xx/include/mach/regs-ecc8.h [new file with mode: 0644]
arch/arm/mach-stmp37xx/include/mach/regs-gpmi.h [new file with mode: 0644]
arch/arm/mach-stmp37xx/include/mach/regs-i2c.h [new file with mode: 0644]
arch/arm/mach-stmp37xx/include/mach/regs-icoll.h [new file with mode: 0644]
arch/arm/mach-stmp37xx/include/mach/regs-lcdif.h [new file with mode: 0644]
arch/arm/mach-stmp37xx/include/mach/regs-lradc.h [new file with mode: 0644]
arch/arm/mach-stmp37xx/include/mach/regs-pinctrl.h [new file with mode: 0644]
arch/arm/mach-stmp37xx/include/mach/regs-power.h [new file with mode: 0644]
arch/arm/mach-stmp37xx/include/mach/regs-pwm.h [new file with mode: 0644]
arch/arm/mach-stmp37xx/include/mach/regs-rtc.h [new file with mode: 0644]
arch/arm/mach-stmp37xx/include/mach/regs-ssp.h [new file with mode: 0644]
arch/arm/mach-stmp37xx/include/mach/regs-timrot.h [new file with mode: 0644]
arch/arm/mach-stmp37xx/include/mach/regs-uartapp.h [new file with mode: 0644]
arch/arm/mach-stmp37xx/include/mach/regs-uartdbg.h [new file with mode: 0644]
arch/arm/mach-stmp37xx/include/mach/regs-usbctl.h [new file with mode: 0644]
arch/arm/mach-stmp37xx/include/mach/regs-usbctrl.h [new file with mode: 0644]
arch/arm/mach-stmp37xx/include/mach/regs-usbphy.h [new file with mode: 0644]
arch/arm/mach-stmp37xx/stmp37xx.c [new file with mode: 0644]
arch/arm/mach-stmp37xx/stmp37xx.h [new file with mode: 0644]
arch/arm/mach-stmp37xx/stmp37xx_devb.c [new file with mode: 0644]
arch/arm/mach-u300/Kconfig [new file with mode: 0644]
arch/arm/mach-u300/Makefile [new file with mode: 0644]
arch/arm/mach-u300/Makefile.boot [new file with mode: 0644]
arch/arm/mach-u300/clock.c [new file with mode: 0644]
arch/arm/mach-u300/clock.h [new file with mode: 0644]
arch/arm/mach-u300/core.c [new file with mode: 0644]
arch/arm/mach-u300/gpio.c [new file with mode: 0644]
arch/arm/mach-u300/include/mach/clkdev.h [new file with mode: 0644]
arch/arm/mach-u300/include/mach/debug-macro.S [new file with mode: 0644]
arch/arm/mach-u300/include/mach/entry-macro.S [new file with mode: 0644]
arch/arm/mach-u300/include/mach/gpio.h [new file with mode: 0644]
arch/arm/mach-u300/include/mach/hardware.h [new file with mode: 0644]
arch/arm/mach-u300/include/mach/io.h [new file with mode: 0644]
arch/arm/mach-u300/include/mach/irqs.h [new file with mode: 0644]
arch/arm/mach-u300/include/mach/memory.h [new file with mode: 0644]
arch/arm/mach-u300/include/mach/platform.h [new file with mode: 0644]
arch/arm/mach-u300/include/mach/syscon.h [new file with mode: 0644]
arch/arm/mach-u300/include/mach/system.h [new file with mode: 0644]
arch/arm/mach-u300/include/mach/timex.h [new file with mode: 0644]
arch/arm/mach-u300/include/mach/u300-regs.h [new file with mode: 0644]
arch/arm/mach-u300/include/mach/uncompress.h [new file with mode: 0644]
arch/arm/mach-u300/include/mach/vmalloc.h [new file with mode: 0644]
arch/arm/mach-u300/mmc.c [new file with mode: 0644]
arch/arm/mach-u300/mmc.h [new file with mode: 0644]
arch/arm/mach-u300/padmux.c [new file with mode: 0644]
arch/arm/mach-u300/padmux.h [new file with mode: 0644]
arch/arm/mach-u300/timer.c [new file with mode: 0644]
arch/arm/mach-u300/u300.c [new file with mode: 0644]
arch/arm/mach-versatile/core.c
arch/arm/mach-w90x900/Makefile
arch/arm/mach-w90x900/clock.c [new file with mode: 0644]
arch/arm/mach-w90x900/clock.h [new file with mode: 0644]
arch/arm/mach-w90x900/cpu.h
arch/arm/mach-w90x900/gpio.c [new file with mode: 0644]
arch/arm/mach-w90x900/include/mach/clkdev.h [new file with mode: 0644]
arch/arm/mach-w90x900/include/mach/gpio.h [new file with mode: 0644]
arch/arm/mach-w90x900/include/mach/irqs.h
arch/arm/mach-w90x900/include/mach/map.h
arch/arm/mach-w90x900/include/mach/regs-clock.h [new file with mode: 0644]
arch/arm/mach-w90x900/include/mach/regs-usb.h [new file with mode: 0644]
arch/arm/mach-w90x900/mach-w90p910evb.c
arch/arm/mach-w90x900/mfp-w90p910.c [new file with mode: 0644]
arch/arm/mach-w90x900/w90p910.c
arch/arm/mm/Kconfig
arch/arm/mm/abort-ev6.S
arch/arm/mm/ioremap.c
arch/arm/mm/mmu.c
arch/arm/mm/proc-v6.S
arch/arm/mm/proc-v7.S
arch/arm/mm/tlb-v7.S
arch/arm/oprofile/op_model_mpcore.c
arch/arm/plat-mxc/Kconfig
arch/arm/plat-mxc/Makefile
arch/arm/plat-mxc/gpio.c
arch/arm/plat-mxc/include/mach/board-armadillo5x0.h [new file with mode: 0644]
arch/arm/plat-mxc/include/mach/board-mx21ads.h [new file with mode: 0644]
arch/arm/plat-mxc/include/mach/board-mx27lite.h [new file with mode: 0644]
arch/arm/plat-mxc/include/mach/board-mx27pdk.h [new file with mode: 0644]
arch/arm/plat-mxc/include/mach/board-mx31ads.h
arch/arm/plat-mxc/include/mach/board-mx31lilly.h [new file with mode: 0644]
arch/arm/plat-mxc/include/mach/board-mx31lite.h
arch/arm/plat-mxc/include/mach/board-mx31moboard.h
arch/arm/plat-mxc/include/mach/board-mx31pdk.h
arch/arm/plat-mxc/include/mach/board-mx35pdk.h [new file with mode: 0644]
arch/arm/plat-mxc/include/mach/board-pcm037.h
arch/arm/plat-mxc/include/mach/board-pcm038.h
arch/arm/plat-mxc/include/mach/board-pcm043.h [new file with mode: 0644]
arch/arm/plat-mxc/include/mach/board-qong.h
arch/arm/plat-mxc/include/mach/common.h
arch/arm/plat-mxc/include/mach/debug-macro.S
arch/arm/plat-mxc/include/mach/gpio.h
arch/arm/plat-mxc/include/mach/imx-uart.h
arch/arm/plat-mxc/include/mach/imxfb.h
arch/arm/plat-mxc/include/mach/iomux-mx3.h
arch/arm/plat-mxc/include/mach/iomux-mx35.h [new file with mode: 0644]
arch/arm/plat-mxc/include/mach/iomux-v3.h [new file with mode: 0644]
arch/arm/plat-mxc/include/mach/memory.h
arch/arm/plat-mxc/include/mach/mx1.h
arch/arm/plat-mxc/include/mach/mx3x.h
arch/arm/plat-mxc/include/mach/mxc_timer.h [deleted file]
arch/arm/plat-mxc/include/mach/usb.h
arch/arm/plat-mxc/iomux-v3.c [new file with mode: 0644]
arch/arm/plat-mxc/irq.c
arch/arm/plat-mxc/pwm.c
arch/arm/plat-mxc/time.c
arch/arm/plat-omap/Kconfig
arch/arm/plat-omap/Makefile
arch/arm/plat-omap/clock.c
arch/arm/plat-omap/common.c
arch/arm/plat-omap/devices.c
arch/arm/plat-omap/dma.c
arch/arm/plat-omap/dmtimer.c
arch/arm/plat-omap/gpio.c
arch/arm/plat-omap/i2c.c
arch/arm/plat-omap/include/mach/clock.h
arch/arm/plat-omap/include/mach/common.h
arch/arm/plat-omap/include/mach/control.h
arch/arm/plat-omap/include/mach/cpu.h
arch/arm/plat-omap/include/mach/debug-macro.S
arch/arm/plat-omap/include/mach/dma.h
arch/arm/plat-omap/include/mach/entry-macro.S
arch/arm/plat-omap/include/mach/gpmc-smc91x.h [new file with mode: 0644]
arch/arm/plat-omap/include/mach/hardware.h
arch/arm/plat-omap/include/mach/hwa742.h
arch/arm/plat-omap/include/mach/io.h
arch/arm/plat-omap/include/mach/iommu.h [new file with mode: 0644]
arch/arm/plat-omap/include/mach/iommu2.h [new file with mode: 0644]
arch/arm/plat-omap/include/mach/iovmm.h [new file with mode: 0644]
arch/arm/plat-omap/include/mach/irqs.h
arch/arm/plat-omap/include/mach/keypad.h
arch/arm/plat-omap/include/mach/memory.h
arch/arm/plat-omap/include/mach/omap24xx.h
arch/arm/plat-omap/include/mach/omap34xx.h
arch/arm/plat-omap/include/mach/omap44xx.h [new file with mode: 0644]
arch/arm/plat-omap/include/mach/onenand.h
arch/arm/plat-omap/include/mach/pm.h [deleted file]
arch/arm/plat-omap/include/mach/serial.h
arch/arm/plat-omap/include/mach/smp.h [new file with mode: 0644]
arch/arm/plat-omap/include/mach/sram.h
arch/arm/plat-omap/include/mach/usb.h
arch/arm/plat-omap/include/mach/vmalloc.h
arch/arm/plat-omap/io.c
arch/arm/plat-omap/iommu.c [new file with mode: 0644]
arch/arm/plat-omap/iopgtable.h [new file with mode: 0644]
arch/arm/plat-omap/iovmm.c [new file with mode: 0644]
arch/arm/plat-omap/mcbsp.c
arch/arm/plat-omap/mux.c
arch/arm/plat-omap/sram.c
arch/arm/plat-orion/gpio.c
arch/arm/plat-orion/include/plat/gpio.h
arch/arm/plat-orion/include/plat/orion5x_wdt.h [deleted file]
arch/arm/plat-orion/include/plat/orion_wdt.h [new file with mode: 0644]
arch/arm/plat-orion/time.c
arch/arm/plat-pxa/Makefile
arch/arm/plat-pxa/include/plat/i2c.h [new file with mode: 0644]
arch/arm/plat-pxa/pwm.c [new file with mode: 0644]
arch/arm/plat-s3c/Kconfig
arch/arm/plat-s3c/Makefile
arch/arm/plat-s3c/dev-usb-hsotg.c [new file with mode: 0644]
arch/arm/plat-s3c/dev-usb.c [new file with mode: 0644]
arch/arm/plat-s3c/dma.c [new file with mode: 0644]
arch/arm/plat-s3c/gpio.c
arch/arm/plat-s3c/include/plat/adc.h
arch/arm/plat-s3c/include/plat/clock.h
arch/arm/plat-s3c/include/plat/cpu.h
arch/arm/plat-s3c/include/plat/devs.h
arch/arm/plat-s3c/include/plat/dma-core.h [new file with mode: 0644]
arch/arm/plat-s3c/include/plat/dma.h [new file with mode: 0644]
arch/arm/plat-s3c/include/plat/gpio-core.h
arch/arm/plat-s3c/include/plat/pm.h
arch/arm/plat-s3c/include/plat/regs-serial.h
arch/arm/plat-s3c/include/plat/sdhci.h
arch/arm/plat-s3c/include/plat/udc-hs.h [new file with mode: 0644]
arch/arm/plat-s3c/include/plat/watchdog-reset.h [new file with mode: 0644]
arch/arm/plat-s3c/pm-gpio.c [new file with mode: 0644]
arch/arm/plat-s3c/pm.c
arch/arm/plat-s3c24xx/Kconfig
arch/arm/plat-s3c24xx/adc.c
arch/arm/plat-s3c24xx/common-smdk.c
arch/arm/plat-s3c24xx/devs.c
arch/arm/plat-s3c24xx/dma.c
arch/arm/plat-s3c24xx/gpio.c
arch/arm/plat-s3c24xx/gpiolib.c
arch/arm/plat-s3c24xx/include/plat/dma-plat.h [new file with mode: 0644]
arch/arm/plat-s3c24xx/include/plat/dma.h [deleted file]
arch/arm/plat-s3c24xx/include/plat/map.h
arch/arm/plat-s3c24xx/include/plat/pm-core.h
arch/arm/plat-s3c24xx/include/plat/regs-dma.h [new file with mode: 0644]
arch/arm/plat-s3c24xx/pm.c
arch/arm/plat-s3c24xx/setup-i2c.c
arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c
arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c
arch/arm/plat-s3c64xx/Kconfig
arch/arm/plat-s3c64xx/Makefile
arch/arm/plat-s3c64xx/clock.c
arch/arm/plat-s3c64xx/cpu.c
arch/arm/plat-s3c64xx/dma.c [new file with mode: 0644]
arch/arm/plat-s3c64xx/gpiolib.c
arch/arm/plat-s3c64xx/include/plat/dma-plat.h [new file with mode: 0644]
arch/arm/plat-s3c64xx/include/plat/irqs.h
arch/arm/plat-s3c64xx/include/plat/pm-core.h [new file with mode: 0644]
arch/arm/plat-s3c64xx/include/plat/regs-clock.h
arch/arm/plat-s3c64xx/include/plat/s3c6400.h
arch/arm/plat-s3c64xx/irq-eint.c
arch/arm/plat-s3c64xx/irq-pm.c [new file with mode: 0644]
arch/arm/plat-s3c64xx/irq.c
arch/arm/plat-s3c64xx/pm.c [new file with mode: 0644]
arch/arm/plat-s3c64xx/s3c6400-clock.c
arch/arm/plat-s3c64xx/setup-sdhci-gpio.c [new file with mode: 0644]
arch/arm/plat-s3c64xx/sleep.S [new file with mode: 0644]
arch/arm/plat-stmp3xxx/Kconfig [new file with mode: 0644]
arch/arm/plat-stmp3xxx/Makefile [new file with mode: 0644]
arch/arm/plat-stmp3xxx/clock.c [new file with mode: 0644]
arch/arm/plat-stmp3xxx/clock.h [new file with mode: 0644]
arch/arm/plat-stmp3xxx/core.c [new file with mode: 0644]
arch/arm/plat-stmp3xxx/devices.c [new file with mode: 0644]
arch/arm/plat-stmp3xxx/dma.c [new file with mode: 0644]
arch/arm/plat-stmp3xxx/include/mach/clkdev.h [new file with mode: 0644]
arch/arm/plat-stmp3xxx/include/mach/cputype.h [new file with mode: 0644]
arch/arm/plat-stmp3xxx/include/mach/debug-macro.S [new file with mode: 0644]
arch/arm/plat-stmp3xxx/include/mach/dma.h [new file with mode: 0644]
arch/arm/plat-stmp3xxx/include/mach/gpio.h [new file with mode: 0644]
arch/arm/plat-stmp3xxx/include/mach/gpmi.h [new file with mode: 0644]
arch/arm/plat-stmp3xxx/include/mach/hardware.h [new file with mode: 0644]
arch/arm/plat-stmp3xxx/include/mach/io.h [new file with mode: 0644]
arch/arm/plat-stmp3xxx/include/mach/memory.h [new file with mode: 0644]
arch/arm/plat-stmp3xxx/include/mach/mmc.h [new file with mode: 0644]
arch/arm/plat-stmp3xxx/include/mach/pinmux.h [new file with mode: 0644]
arch/arm/plat-stmp3xxx/include/mach/pins.h [new file with mode: 0644]
arch/arm/plat-stmp3xxx/include/mach/platform.h [new file with mode: 0644]
arch/arm/plat-stmp3xxx/include/mach/stmp3xxx.h [new file with mode: 0644]
arch/arm/plat-stmp3xxx/include/mach/system.h [new file with mode: 0644]
arch/arm/plat-stmp3xxx/include/mach/timex.h [new file with mode: 0644]
arch/arm/plat-stmp3xxx/include/mach/uncompress.h [new file with mode: 0644]
arch/arm/plat-stmp3xxx/include/mach/vmalloc.h [new file with mode: 0644]
arch/arm/plat-stmp3xxx/irq.c [new file with mode: 0644]
arch/arm/plat-stmp3xxx/pinmux.c [new file with mode: 0644]
arch/arm/plat-stmp3xxx/timer.c [new file with mode: 0644]
arch/arm/vfp/vfphw.S
arch/arm/vfp/vfpmodule.c
arch/avr32/boards/atngw100/Kconfig
arch/avr32/boards/atngw100/Kconfig_mrmt [new file with mode: 0644]
arch/avr32/boards/atngw100/Makefile
arch/avr32/boards/atngw100/mrmt.c [new file with mode: 0644]
arch/avr32/boards/atngw100/setup.c
arch/avr32/boards/merisc/setup.c
arch/avr32/boards/mimc200/setup.c
arch/avr32/configs/atngw100_mrmt_defconfig [new file with mode: 0644]
arch/avr32/include/asm/atomic.h
arch/avr32/include/asm/bitsperlong.h [new file with mode: 0644]
arch/avr32/include/asm/hw_irq.h
arch/avr32/include/asm/mman.h
arch/avr32/include/asm/signal.h
arch/avr32/include/asm/termios.h
arch/avr32/kernel/module.c
arch/avr32/kernel/traps.c
arch/avr32/mach-at32ap/include/mach/board.h
arch/blackfin/Kconfig
arch/blackfin/Kconfig.debug
arch/blackfin/configs/BF518F-EZBRD_defconfig
arch/blackfin/configs/BF526-EZBRD_defconfig
arch/blackfin/configs/BF527-EZKIT_defconfig
arch/blackfin/configs/BF533-EZKIT_defconfig
arch/blackfin/configs/BF533-STAMP_defconfig
arch/blackfin/configs/BF537-STAMP_defconfig
arch/blackfin/configs/BF538-EZKIT_defconfig
arch/blackfin/configs/BF548-EZKIT_defconfig
arch/blackfin/configs/BF561-EZKIT_defconfig
arch/blackfin/configs/BlackStamp_defconfig
arch/blackfin/configs/CM-BF527_defconfig
arch/blackfin/configs/CM-BF533_defconfig
arch/blackfin/configs/CM-BF537E_defconfig
arch/blackfin/configs/CM-BF537U_defconfig
arch/blackfin/configs/CM-BF548_defconfig
arch/blackfin/configs/CM-BF561_defconfig
arch/blackfin/configs/H8606_defconfig
arch/blackfin/configs/IP0X_defconfig
arch/blackfin/configs/PNAV-10_defconfig
arch/blackfin/configs/SRV1_defconfig
arch/blackfin/configs/TCM-BF537_defconfig
arch/blackfin/include/asm/atomic.h
arch/blackfin/include/asm/bitsperlong.h [new file with mode: 0644]
arch/blackfin/include/asm/cacheflush.h
arch/blackfin/include/asm/cplb.h
arch/blackfin/include/asm/dma.h
arch/blackfin/include/asm/elf.h
arch/blackfin/include/asm/entry.h
arch/blackfin/include/asm/gptimers.h
arch/blackfin/include/asm/io.h
arch/blackfin/include/asm/ipipe.h
arch/blackfin/include/asm/page.h
arch/blackfin/include/asm/pda.h
arch/blackfin/include/asm/processor.h
arch/blackfin/include/asm/signal.h
arch/blackfin/include/asm/time.h
arch/blackfin/include/asm/uaccess.h
arch/blackfin/kernel/bfin_dma_5xx.c
arch/blackfin/kernel/bfin_gpio.c
arch/blackfin/kernel/bfin_ksyms.c
arch/blackfin/kernel/cplb-mpu/cacheinit.c
arch/blackfin/kernel/cplb-mpu/cplbinit.c
arch/blackfin/kernel/cplb-nompu/cacheinit.c
arch/blackfin/kernel/early_printk.c
arch/blackfin/kernel/gptimers.c
arch/blackfin/kernel/ipipe.c
arch/blackfin/kernel/irqchip.c
arch/blackfin/kernel/kgdb.c
arch/blackfin/kernel/module.c
arch/blackfin/kernel/process.c
arch/blackfin/kernel/setup.c
arch/blackfin/kernel/sys_bfin.c
arch/blackfin/kernel/time-ts.c
arch/blackfin/kernel/time.c
arch/blackfin/kernel/traps.c
arch/blackfin/kernel/vmlinux.lds.S
arch/blackfin/mach-bf518/Kconfig
arch/blackfin/mach-bf518/boards/ezbrd.c
arch/blackfin/mach-bf518/include/mach/anomaly.h
arch/blackfin/mach-bf518/include/mach/portmux.h
arch/blackfin/mach-bf527/Kconfig
arch/blackfin/mach-bf527/boards/cm_bf527.c
arch/blackfin/mach-bf527/boards/ezbrd.c
arch/blackfin/mach-bf527/boards/ezkit.c
arch/blackfin/mach-bf527/include/mach/anomaly.h
arch/blackfin/mach-bf533/Kconfig
arch/blackfin/mach-bf533/boards/H8606.c
arch/blackfin/mach-bf533/boards/cm_bf533.c
arch/blackfin/mach-bf533/boards/ezkit.c
arch/blackfin/mach-bf533/boards/stamp.c
arch/blackfin/mach-bf533/include/mach/anomaly.h
arch/blackfin/mach-bf537/Kconfig
arch/blackfin/mach-bf537/boards/cm_bf537.c
arch/blackfin/mach-bf537/boards/pnav10.c
arch/blackfin/mach-bf537/boards/stamp.c
arch/blackfin/mach-bf537/boards/tcm_bf537.c
arch/blackfin/mach-bf537/include/mach/anomaly.h
arch/blackfin/mach-bf538/Kconfig
arch/blackfin/mach-bf538/include/mach/anomaly.h
arch/blackfin/mach-bf538/include/mach/blackfin.h
arch/blackfin/mach-bf538/include/mach/cdefBF538.h
arch/blackfin/mach-bf538/include/mach/defBF539.h
arch/blackfin/mach-bf548/Kconfig
arch/blackfin/mach-bf548/boards/ezkit.c
arch/blackfin/mach-bf548/include/mach/anomaly.h
arch/blackfin/mach-bf548/include/mach/portmux.h
arch/blackfin/mach-bf561/Kconfig
arch/blackfin/mach-bf561/boards/cm_bf561.c
arch/blackfin/mach-bf561/coreb.c
arch/blackfin/mach-bf561/include/mach/anomaly.h
arch/blackfin/mach-bf561/include/mach/cdefBF561.h
arch/blackfin/mach-bf561/include/mach/defBF561.h
arch/blackfin/mach-bf561/smp.c
arch/blackfin/mach-common/arch_checks.c
arch/blackfin/mach-common/cache.S
arch/blackfin/mach-common/clocks-init.c
arch/blackfin/mach-common/cpufreq.c
arch/blackfin/mach-common/entry.S
arch/blackfin/mach-common/head.S
arch/blackfin/mach-common/interrupt.S
arch/blackfin/mach-common/ints-priority.c
arch/blackfin/mach-common/smp.c
arch/blackfin/mm/blackfin_sram.h
arch/blackfin/mm/init.c
arch/blackfin/mm/isram-driver.c
arch/blackfin/mm/sram-alloc.c
arch/cris/include/asm/atomic.h
arch/cris/include/asm/bitsperlong.h [new file with mode: 0644]
arch/cris/include/asm/mman.h
arch/cris/include/asm/page.h
arch/cris/include/asm/signal.h
arch/cris/kernel/module.c
arch/frv/include/asm/atomic.h
arch/frv/include/asm/bitsperlong.h [new file with mode: 0644]
arch/frv/include/asm/mman.h
arch/frv/include/asm/page.h
arch/frv/include/asm/pci.h
arch/frv/include/asm/signal.h
arch/frv/include/asm/termios.h
arch/frv/kernel/module.c
arch/h8300/include/asm/atomic.h
arch/h8300/include/asm/bitsperlong.h [new file with mode: 0644]
arch/h8300/include/asm/mman.h
arch/h8300/include/asm/page.h
arch/h8300/include/asm/signal.h
arch/h8300/kernel/module.c
arch/ia64/include/asm/atomic.h
arch/ia64/include/asm/bitsperlong.h [new file with mode: 0644]
arch/ia64/include/asm/mman.h
arch/ia64/include/asm/signal.h
arch/ia64/include/asm/suspend.h [deleted file]
arch/ia64/include/asm/types.h
arch/ia64/mm/extable.c
arch/m32r/include/asm/atomic.h
arch/m32r/include/asm/bitsperlong.h [new file with mode: 0644]
arch/m32r/include/asm/mman.h
arch/m32r/include/asm/page.h
arch/m32r/include/asm/pci.h
arch/m32r/include/asm/signal.h
arch/m32r/kernel/module.c
arch/m68k/include/asm/atomic_mm.h
arch/m68k/include/asm/atomic_no.h
arch/m68k/include/asm/bitsperlong.h [new file with mode: 0644]
arch/m68k/include/asm/mman.h
arch/m68k/include/asm/page_mm.h
arch/m68k/include/asm/page_no.h
arch/m68k/include/asm/signal.h
arch/m68k/include/asm/suspend.h [deleted file]
arch/m68k/kernel/module.c
arch/m68knommu/kernel/module.c
arch/microblaze/Kconfig
arch/microblaze/Makefile
arch/microblaze/boot/Makefile
arch/microblaze/configs/mmu_defconfig [new file with mode: 0644]
arch/microblaze/include/asm/Kbuild
arch/microblaze/include/asm/atomic.h
arch/microblaze/include/asm/bitsperlong.h [new file with mode: 0644]
arch/microblaze/include/asm/cacheflush.h
arch/microblaze/include/asm/checksum.h
arch/microblaze/include/asm/current.h
arch/microblaze/include/asm/dma-mapping.h
arch/microblaze/include/asm/dma.h
arch/microblaze/include/asm/elf.h
arch/microblaze/include/asm/entry.h
arch/microblaze/include/asm/exceptions.h
arch/microblaze/include/asm/flat.h
arch/microblaze/include/asm/gpio.h
arch/microblaze/include/asm/io.h
arch/microblaze/include/asm/mmu.h
arch/microblaze/include/asm/mmu_context.h
arch/microblaze/include/asm/mmu_context_mm.h [new file with mode: 0644]
arch/microblaze/include/asm/mmu_context_no.h [new file with mode: 0644]
arch/microblaze/include/asm/page.h
arch/microblaze/include/asm/pgalloc.h
arch/microblaze/include/asm/pgtable.h
arch/microblaze/include/asm/posix_types.h
arch/microblaze/include/asm/processor.h
arch/microblaze/include/asm/ptrace.h
arch/microblaze/include/asm/registers.h
arch/microblaze/include/asm/sections.h
arch/microblaze/include/asm/segment.h
arch/microblaze/include/asm/setup.h
arch/microblaze/include/asm/signal.h
arch/microblaze/include/asm/stat.h
arch/microblaze/include/asm/string.h
arch/microblaze/include/asm/syscalls.h
arch/microblaze/include/asm/termios.h
arch/microblaze/include/asm/thread_info.h
arch/microblaze/include/asm/tlb.h
arch/microblaze/include/asm/tlbflush.h
arch/microblaze/include/asm/uaccess.h
arch/microblaze/include/asm/unaligned.h
arch/microblaze/kernel/Makefile
arch/microblaze/kernel/asm-offsets.c
arch/microblaze/kernel/early_printk.c
arch/microblaze/kernel/entry-nommu.S
arch/microblaze/kernel/entry.S [new file with mode: 0644]
arch/microblaze/kernel/exceptions.c
arch/microblaze/kernel/head.S
arch/microblaze/kernel/hw_exception_handler.S
arch/microblaze/kernel/microblaze_ksyms.c
arch/microblaze/kernel/misc.S [new file with mode: 0644]
arch/microblaze/kernel/process.c
arch/microblaze/kernel/prom.c
arch/microblaze/kernel/setup.c
arch/microblaze/kernel/signal.c
arch/microblaze/kernel/syscall_table.S
arch/microblaze/kernel/traps.c
arch/microblaze/kernel/vmlinux.lds.S
arch/microblaze/lib/Makefile
arch/microblaze/lib/checksum.c
arch/microblaze/lib/memcpy.c
arch/microblaze/lib/uaccess_old.S [new file with mode: 0644]
arch/microblaze/mm/Makefile
arch/microblaze/mm/fault.c [new file with mode: 0644]
arch/microblaze/mm/init.c
arch/microblaze/mm/mmu_context.c [new file with mode: 0644]
arch/microblaze/mm/pgtable.c [new file with mode: 0644]
arch/mips/include/asm/atomic.h
arch/mips/include/asm/bitsperlong.h [new file with mode: 0644]
arch/mips/include/asm/page.h
arch/mips/include/asm/signal.h
arch/mips/include/asm/suspend.h [deleted file]
arch/mips/include/asm/types.h
arch/mips/kernel/module.c
arch/mn10300/include/asm/atomic.h
arch/mn10300/include/asm/bitsperlong.h [new file with mode: 0644]
arch/mn10300/include/asm/mman.h
arch/mn10300/include/asm/ptrace.h
arch/mn10300/include/asm/setup.h
arch/mn10300/include/asm/signal.h
arch/mn10300/kernel/module.c
arch/parisc/include/asm/atomic.h
arch/parisc/include/asm/bitsperlong.h [new file with mode: 0644]
arch/parisc/include/asm/page.h
arch/parisc/include/asm/types.h
arch/parisc/include/asm/uaccess.h
arch/parisc/kernel/module.c
arch/powerpc/include/asm/atomic.h
arch/powerpc/include/asm/bitsperlong.h [new file with mode: 0644]
arch/powerpc/include/asm/mman.h
arch/powerpc/include/asm/mpc52xx_psc.h
arch/powerpc/include/asm/page_32.h
arch/powerpc/include/asm/page_64.h
arch/powerpc/include/asm/signal.h
arch/powerpc/include/asm/termios.h
arch/powerpc/include/asm/types.h
arch/powerpc/kernel/module.c
arch/powerpc/kernel/power7-pmu.c
arch/powerpc/mm/slb.c
arch/s390/Kconfig
arch/s390/include/asm/atomic.h
arch/s390/include/asm/bitsperlong.h [new file with mode: 0644]
arch/s390/include/asm/compat.h
arch/s390/include/asm/cpu.h [deleted file]
arch/s390/include/asm/cputime.h
arch/s390/include/asm/ftrace.h
arch/s390/include/asm/lowcore.h
arch/s390/include/asm/mman.h
arch/s390/include/asm/page.h
arch/s390/include/asm/pgtable.h
arch/s390/include/asm/seccomp.h [new file with mode: 0644]
arch/s390/include/asm/signal.h
arch/s390/include/asm/spinlock.h
arch/s390/include/asm/suspend.h [deleted file]
arch/s390/include/asm/syscall.h
arch/s390/include/asm/termios.h
arch/s390/include/asm/thread_info.h
arch/s390/include/asm/types.h
arch/s390/include/asm/uaccess.h
arch/s390/include/asm/unistd.h
arch/s390/kernel/Makefile
arch/s390/kernel/compat_wrapper.S
arch/s390/kernel/early.c
arch/s390/kernel/entry.S
arch/s390/kernel/entry64.S
arch/s390/kernel/ftrace.c [new file with mode: 0644]
arch/s390/kernel/head.S
arch/s390/kernel/kprobes.c
arch/s390/kernel/mcount.S
arch/s390/kernel/module.c
arch/s390/kernel/nmi.c
arch/s390/kernel/process.c
arch/s390/kernel/ptrace.c
arch/s390/kernel/s390_ext.c
arch/s390/kernel/sclp.S [new file with mode: 0644]
arch/s390/kernel/setup.c
arch/s390/kernel/signal.c
arch/s390/kernel/smp.c
arch/s390/kernel/syscalls.S
arch/s390/kernel/time.c
arch/s390/kernel/vdso.c
arch/s390/kernel/vmlinux.lds.S
arch/s390/kernel/vtime.c
arch/s390/kvm/kvm-s390.c
arch/s390/lib/spinlock.c
arch/s390/mm/Makefile
arch/s390/mm/fault.c
arch/s390/mm/maccess.c [new file with mode: 0644]
arch/s390/mm/mmap.c
arch/s390/mm/pgtable.c
arch/sh/include/asm/atomic.h
arch/sh/include/asm/bitsperlong.h [new file with mode: 0644]
arch/sh/include/asm/mman.h
arch/sh/include/asm/page.h
arch/sh/include/asm/signal.h
arch/sh/kernel/module.c
arch/sparc/include/asm/atomic_32.h
arch/sparc/include/asm/atomic_64.h
arch/sparc/include/asm/bitsperlong.h [new file with mode: 0644]
arch/sparc/include/asm/mman.h
arch/sparc/include/asm/page_32.h
arch/sparc/include/asm/page_64.h
arch/sparc/include/asm/signal.h
arch/sparc/include/asm/types.h
arch/sparc/include/asm/uaccess_32.h
arch/sparc/include/asm/uaccess_64.h
arch/sparc/kernel/module.c
arch/sparc/mm/extable.c
arch/um/include/asm/page.h
arch/um/include/asm/pgtable.h
arch/um/include/asm/suspend.h [deleted file]
arch/um/sys-i386/Makefile
arch/um/sys-x86_64/Makefile
arch/um/sys-x86_64/um_module.c [deleted file]
arch/x86/Kconfig
arch/x86/crypto/Makefile
arch/x86/crypto/aesni-intel_glue.c
arch/x86/crypto/fpu.c [new file with mode: 0644]
arch/x86/include/asm/atomic_32.h
arch/x86/include/asm/atomic_64.h
arch/x86/include/asm/bitsperlong.h [new file with mode: 0644]
arch/x86/include/asm/entry_arch.h
arch/x86/include/asm/hardirq.h
arch/x86/include/asm/hw_irq.h
arch/x86/include/asm/irq_vectors.h
arch/x86/include/asm/lguest.h
arch/x86/include/asm/lguest_hcall.h
arch/x86/include/asm/mce.h
arch/x86/include/asm/mman.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/page.h
arch/x86/include/asm/pgtable_32_types.h
arch/x86/include/asm/signal.h
arch/x86/include/asm/tlbflush.h
arch/x86/include/asm/types.h
arch/x86/kernel/Makefile
arch/x86/kernel/acpi/sleep.c
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/nmi.c
arch/x86/kernel/apm_32.c
arch/x86/kernel/asm-offsets_32.c
arch/x86/kernel/cpu/mcheck/Makefile
arch/x86/kernel/cpu/mcheck/k7.c
arch/x86/kernel/cpu/mcheck/mce-inject.c [new file with mode: 0644]
arch/x86/kernel/cpu/mcheck/mce-internal.h [new file with mode: 0644]
arch/x86/kernel/cpu/mcheck/mce-severity.c [new file with mode: 0644]
arch/x86/kernel/cpu/mcheck/mce.c [new file with mode: 0644]
arch/x86/kernel/cpu/mcheck/mce.h
arch/x86/kernel/cpu/mcheck/mce_32.c [deleted file]
arch/x86/kernel/cpu/mcheck/mce_64.c [deleted file]
arch/x86/kernel/cpu/mcheck/mce_amd_64.c
arch/x86/kernel/cpu/mcheck/mce_intel.c [new file with mode: 0644]
arch/x86/kernel/cpu/mcheck/mce_intel_64.c
arch/x86/kernel/cpu/mcheck/non-fatal.c
arch/x86/kernel/cpu/mcheck/p4.c
arch/x86/kernel/cpu/mcheck/p5.c
arch/x86/kernel/cpu/mcheck/p6.c
arch/x86/kernel/cpu/mcheck/therm_throt.c
arch/x86/kernel/cpu/mcheck/threshold.c
arch/x86/kernel/cpu/mcheck/winchip.c
arch/x86/kernel/cpu/perf_counter.c
arch/x86/kernel/entry_64.S
arch/x86/kernel/irq.c
arch/x86/kernel/irqinit.c
arch/x86/kernel/module.c [new file with mode: 0644]
arch/x86/kernel/module_32.c [deleted file]
arch/x86/kernel/module_64.c [deleted file]
arch/x86/kernel/setup.c
arch/x86/kernel/signal.c
arch/x86/kernel/smp.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/traps.c
arch/x86/kernel/vmlinux.lds.S
arch/x86/lguest/Kconfig
arch/x86/lguest/boot.c
arch/x86/lguest/i386_head.S
arch/x86/mm/init_32.c
arch/x86/power/Makefile
arch/x86/power/cpu.c [new file with mode: 0644]
arch/x86/power/cpu_32.c [deleted file]
arch/x86/power/cpu_64.c [deleted file]
arch/xtensa/include/asm/atomic.h
arch/xtensa/include/asm/bitsperlong.h [new file with mode: 0644]
arch/xtensa/include/asm/page.h
arch/xtensa/kernel/module.c
crypto/Kconfig
crypto/algboss.c
crypto/api.c
crypto/cryptd.c
crypto/internal.h
crypto/pcompress.c
crypto/tcrypt.c
crypto/testmgr.c
crypto/testmgr.h
crypto/zlib.c
drivers/ata/Kconfig
drivers/ata/Makefile
drivers/ata/libata-acpi.c
drivers/ata/libata-eh.c
drivers/ata/pata_palmld.c [new file with mode: 0644]
drivers/base/bus.c
drivers/base/firmware_class.c
drivers/base/platform.c
drivers/base/power/main.c
drivers/base/sys.c
drivers/block/Kconfig
drivers/block/virtio_blk.c
drivers/char/Kconfig
drivers/char/agp/intel-agp.c
drivers/char/amiserial.c
drivers/char/hw_random/Kconfig
drivers/char/hw_random/Makefile
drivers/char/hw_random/mxc-rnga.c [new file with mode: 0644]
drivers/char/hw_random/omap-rng.c
drivers/char/hw_random/timeriomem-rng.c
drivers/char/hw_random/via-rng.c
drivers/char/hw_random/virtio-rng.c
drivers/char/virtio_console.c
drivers/char/vt.c
drivers/connector/Kconfig
drivers/crypto/Kconfig
drivers/crypto/hifn_795x.c
drivers/crypto/padlock-aes.c
drivers/crypto/talitos.c
drivers/edac/e752x_edac.c
drivers/gpio/Kconfig
drivers/gpu/drm/drm_bufs.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_hashtab.c
drivers/gpu/drm/drm_mm.c
drivers/gpu/drm/drm_modes.c
drivers/gpu/drm/drm_stub.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_suspend.c
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_bios.h
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_fb.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_tv.c
drivers/gpu/drm/radeon/r600_cp.c
drivers/gpu/drm/radeon/radeon_cp.c
drivers/gpu/drm/radeon/radeon_drv.h
drivers/gpu/drm/via/via_dmablit.c
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-apple.c
drivers/hid/hid-core.c
drivers/hid/hid-debug.c
drivers/hid/hid-drff.c
drivers/hid/hid-gaff.c
drivers/hid/hid-ids.h
drivers/hid/hid-lgff.c
drivers/hid/hid-ntrig.c
drivers/hid/hid-sjoy.c [new file with mode: 0644]
drivers/hid/hid-tmff.c
drivers/hid/hid-wacom.c [new file with mode: 0644]
drivers/hid/hid-zpff.c
drivers/hid/hidraw.c
drivers/hid/usbhid/hid-core.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-bfin-twi.c
drivers/i2c/busses/i2c-ocores.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/busses/i2c-pxa.c
drivers/i2c/busses/i2c-s3c2410.c
drivers/ide/Kconfig
drivers/ide/at91_ide.c
drivers/ide/au1xxx-ide.c
drivers/ide/buddha.c
drivers/ide/cmd640.c
drivers/ide/cs5520.c
drivers/ide/delkin_cb.c
drivers/ide/falconide.c
drivers/ide/gayle.c
drivers/ide/hpt366.c
drivers/ide/icside.c
drivers/ide/ide-4drives.c
drivers/ide/ide-atapi.c
drivers/ide/ide-cs.c
drivers/ide/ide-disk.c
drivers/ide/ide-dma.c
drivers/ide/ide-eh.c
drivers/ide/ide-gd.c
drivers/ide/ide-generic.c
drivers/ide/ide-h8300.c
drivers/ide/ide-io.c
drivers/ide/ide-iops.c
drivers/ide/ide-legacy.c
drivers/ide/ide-pnp.c
drivers/ide/ide-probe.c
drivers/ide/ide-tape.c
drivers/ide/ide-taskfile.c
drivers/ide/ide.c
drivers/ide/ide_platform.c
drivers/ide/macide.c
drivers/ide/palm_bk3710.c
drivers/ide/pdc202xx_new.c
drivers/ide/pdc202xx_old.c
drivers/ide/pmac.c
drivers/ide/q40ide.c
drivers/ide/rapide.c
drivers/ide/scc_pata.c
drivers/ide/setup-pci.c
drivers/ide/sgiioc4.c
drivers/ide/siimage.c
drivers/ide/sl82c105.c
drivers/ide/tx4938ide.c
drivers/ide/tx4939ide.c
drivers/infiniband/hw/amso1100/c2_cq.c
drivers/infiniband/hw/cxgb3/cxio_wr.h
drivers/infiniband/hw/cxgb3/iwch_provider.c
drivers/infiniband/hw/ehca/ehca_classes_pSeries.h
drivers/infiniband/hw/ehca/ehca_irq.c
drivers/infiniband/hw/ehca/ehca_main.c
drivers/infiniband/hw/ehca/ehca_qp.c
drivers/infiniband/hw/ehca/hcp_if.c
drivers/infiniband/hw/ehca/hcp_if.h
drivers/infiniband/hw/ehca/hcp_phyp.c
drivers/infiniband/hw/ehca/hcp_phyp.h
drivers/infiniband/hw/ehca/ipz_pt_fn.c
drivers/infiniband/hw/mlx4/qp.c
drivers/infiniband/hw/mthca/mthca_cmd.c
drivers/infiniband/hw/mthca/mthca_dev.h
drivers/infiniband/hw/mthca/mthca_eq.c
drivers/infiniband/hw/mthca/mthca_main.c
drivers/infiniband/hw/mthca/mthca_mr.c
drivers/infiniband/hw/mthca/mthca_profile.c
drivers/infiniband/hw/nes/nes_hw.c
drivers/infiniband/ulp/iser/iscsi_iser.c
drivers/input/misc/Kconfig
drivers/input/serio/Kconfig
drivers/input/serio/ambakmi.c
drivers/isdn/divert/isdn_divert.c
drivers/isdn/mISDN/dsp_core.c
drivers/leds/leds-h1940.c
drivers/leds/leds-s3c24xx.c
drivers/lguest/Kconfig
drivers/lguest/core.c
drivers/lguest/hypercalls.c
drivers/lguest/interrupts_and_traps.c
drivers/lguest/lg.h
drivers/lguest/lguest_device.c
drivers/lguest/lguest_user.c
drivers/lguest/page_tables.c
drivers/lguest/segments.c
drivers/media/dvb/dvb-usb/Kconfig
drivers/media/video/Kconfig
drivers/media/video/hdpvr/hdpvr-video.c
drivers/message/fusion/lsi/mpi_history.txt
drivers/message/fusion/mptbase.c
drivers/message/fusion/mptbase.h
drivers/message/fusion/mptctl.c
drivers/message/fusion/mptdebug.h
drivers/message/fusion/mptfc.c
drivers/message/fusion/mptsas.c
drivers/message/fusion/mptsas.h
drivers/message/fusion/mptscsih.c
drivers/message/fusion/mptscsih.h
drivers/message/fusion/mptspi.c
drivers/mfd/t7l66xb.c
drivers/mfd/tc6387xb.c
drivers/mfd/tc6393xb.c
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/cb710/Kconfig [new file with mode: 0644]
drivers/misc/cb710/Makefile [new file with mode: 0644]
drivers/misc/cb710/core.c [new file with mode: 0644]
drivers/misc/cb710/debug.c [new file with mode: 0644]
drivers/misc/cb710/sgbuf2.c [new file with mode: 0644]
drivers/mmc/card/block.c
drivers/mmc/core/core.c
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/atmel-mci-regs.h
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/cb710-mmc.c [new file with mode: 0644]
drivers/mmc/host/cb710-mmc.h [new file with mode: 0644]
drivers/mmc/host/mmc_spi.c
drivers/mmc/host/mmci.c
drivers/mmc/host/mxcmmc.c
drivers/mmc/host/omap.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/pxamci.c
drivers/mmc/host/s3cmci.c
drivers/mmc/host/sdhci-pltfm.c [new file with mode: 0644]
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mmc/host/tmio_mmc.c
drivers/mmc/host/tmio_mmc.h
drivers/mtd/Kconfig
drivers/mtd/devices/Kconfig
drivers/mtd/nand/Kconfig
drivers/mtd/onenand/omap2.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/appletalk/ltpc.c
drivers/net/arm/ixp4xx_eth.c
drivers/net/b44.h
drivers/net/bnx2.c
drivers/net/bnx2.h
drivers/net/cnic.c [new file with mode: 0644]
drivers/net/cnic.h [new file with mode: 0644]
drivers/net/cnic_defs.h [new file with mode: 0644]
drivers/net/cnic_if.h [new file with mode: 0644]
drivers/net/e100.c
drivers/net/e1000e/e1000.h
drivers/net/ehea/ehea.h
drivers/net/igbvf/igbvf.h
drivers/net/ipg.h
drivers/net/mlx4/en_netdev.c
drivers/net/mlx4/eq.c
drivers/net/mlx4/main.c
drivers/net/mlx4/mr.c
drivers/net/mlx4/profile.c
drivers/net/niu.h
drivers/net/qlge/qlge_main.c
drivers/net/qlge/qlge_mpi.c
drivers/net/skfp/h/smt.h
drivers/net/smc91x.h
drivers/net/tokenring/3c359.c
drivers/net/tokenring/lanstreamer.c
drivers/net/tokenring/olympic.c
drivers/net/ucc_geth_ethtool.c
drivers/net/usb/usbnet.c
drivers/net/virtio_net.c
drivers/net/wan/ixp4xx_hss.c
drivers/net/wireless/Kconfig
drivers/net/wireless/hostap/Kconfig
drivers/net/wireless/iwlwifi/Kconfig
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/Kconfig
drivers/net/wireless/rt2x00/rt2x00lib.h
drivers/net/wireless/wavelan_cs.c
drivers/of/Kconfig
drivers/pci/hotplug/sgi_hotplug.c
drivers/pcmcia/Kconfig
drivers/pcmcia/Makefile
drivers/pcmcia/pxa2xx_stargate2.c [new file with mode: 0644]
drivers/pnp/resource.c
drivers/rtc/rtc-ep93xx.c
drivers/rtc/rtc-pl030.c
drivers/rtc/rtc-pl031.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_diag.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_fba.c
drivers/s390/block/dasd_int.h
drivers/s390/block/dcssblk.c
drivers/s390/char/con3270.c
drivers/s390/char/tty3270.c
drivers/s390/cio/cio.c
drivers/s390/cio/device_ops.c
drivers/s390/cio/qdio_main.c
drivers/s390/cio/qdio_perf.c
drivers/s390/cio/qdio_perf.h
drivers/s390/kvm/kvm_virtio.c
drivers/s390/net/Kconfig
drivers/s390/scsi/zfcp_ccw.c
drivers/s390/scsi/zfcp_dbf.c
drivers/s390/scsi/zfcp_def.h
drivers/s390/scsi/zfcp_erp.c
drivers/s390/scsi/zfcp_ext.h
drivers/s390/scsi/zfcp_fc.c
drivers/s390/scsi/zfcp_fsf.c
drivers/s390/scsi/zfcp_scsi.c
drivers/scsi/Kconfig
drivers/scsi/Makefile
drivers/scsi/NCR_D700.c
drivers/scsi/bnx2i/57xx_iscsi_constants.h [new file with mode: 0644]
drivers/scsi/bnx2i/57xx_iscsi_hsi.h [new file with mode: 0644]
drivers/scsi/bnx2i/Kconfig [new file with mode: 0644]
drivers/scsi/bnx2i/Makefile [new file with mode: 0644]
drivers/scsi/bnx2i/bnx2i.h [new file with mode: 0644]
drivers/scsi/bnx2i/bnx2i_hwi.c [new file with mode: 0644]
drivers/scsi/bnx2i/bnx2i_init.c [new file with mode: 0644]
drivers/scsi/bnx2i/bnx2i_iscsi.c [new file with mode: 0644]
drivers/scsi/bnx2i/bnx2i_sysfs.c [new file with mode: 0644]
drivers/scsi/cxgb3i/cxgb3i.h
drivers/scsi/cxgb3i/cxgb3i_iscsi.c
drivers/scsi/cxgb3i/cxgb3i_offload.c
drivers/scsi/cxgb3i/cxgb3i_offload.h
drivers/scsi/device_handler/scsi_dh_rdac.c
drivers/scsi/dpt/osd_util.h
drivers/scsi/fcoe/fcoe.c
drivers/scsi/fcoe/fcoe.h
drivers/scsi/fcoe/libfcoe.c
drivers/scsi/fnic/fnic_main.c
drivers/scsi/gdth_proc.c
drivers/scsi/ibmvscsi/ibmvfc.c
drivers/scsi/ibmvscsi/ibmvfc.h
drivers/scsi/ibmvscsi/ibmvscsi.c
drivers/scsi/ibmvscsi/ibmvscsi.h
drivers/scsi/ibmvscsi/viosrp.h
drivers/scsi/ipr.c
drivers/scsi/libfc/fc_exch.c
drivers/scsi/libfc/fc_fcp.c
drivers/scsi/libfc/fc_rport.c
drivers/scsi/libiscsi.c
drivers/scsi/libiscsi_tcp.c
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_ct.c
drivers/scsi/lpfc/lpfc_debugfs.c
drivers/scsi/lpfc/lpfc_disc.h
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_hw.h
drivers/scsi/lpfc/lpfc_hw4.h [new file with mode: 0644]
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_logmsg.h
drivers/scsi/lpfc/lpfc_mbox.c
drivers/scsi/lpfc/lpfc_mem.c
drivers/scsi/lpfc/lpfc_nportdisc.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_scsi.h
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli.h
drivers/scsi/lpfc/lpfc_sli4.h [new file with mode: 0644]
drivers/scsi/lpfc/lpfc_version.h
drivers/scsi/lpfc/lpfc_vport.c
drivers/scsi/megaraid.h
drivers/scsi/megaraid/mbox_defs.h
drivers/scsi/mpt2sas/mpt2sas_base.h
drivers/scsi/mpt2sas/mpt2sas_ctl.c
drivers/scsi/mpt2sas/mpt2sas_scsih.c
drivers/scsi/mpt2sas/mpt2sas_transport.c
drivers/scsi/mvsas.c [deleted file]
drivers/scsi/mvsas/Kconfig [new file with mode: 0644]
drivers/scsi/mvsas/Makefile [new file with mode: 0644]
drivers/scsi/mvsas/mv_64xx.c [new file with mode: 0644]
drivers/scsi/mvsas/mv_64xx.h [new file with mode: 0644]
drivers/scsi/mvsas/mv_94xx.c [new file with mode: 0644]
drivers/scsi/mvsas/mv_94xx.h [new file with mode: 0644]
drivers/scsi/mvsas/mv_chips.h [new file with mode: 0644]
drivers/scsi/mvsas/mv_defs.h [new file with mode: 0644]
drivers/scsi/mvsas/mv_init.c [new file with mode: 0644]
drivers/scsi/mvsas/mv_sas.c [new file with mode: 0644]
drivers/scsi/mvsas/mv_sas.h [new file with mode: 0644]
drivers/scsi/osd/Kbuild
drivers/scsi/osd/Makefile [deleted file]
drivers/scsi/osd/osd_initiator.c
drivers/scsi/osd/osd_uld.c
drivers/scsi/qla1280.c
drivers/scsi/qla1280.h
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_dbg.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_fw.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_gs.c
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_iocb.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_mid.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_sup.c
drivers/scsi/qla2xxx/qla_version.h
drivers/scsi/scsi.c
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_error.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_scan.c
drivers/scsi/scsi_transport_iscsi.c
drivers/scsi/sd.c
drivers/scsi/st.c
drivers/scsi/sym53c8xx_2/sym_glue.c
drivers/scsi/sym53c8xx_2/sym_hipd.c
drivers/scsi/sym53c8xx_2/sym_hipd.h
drivers/serial/Kconfig
drivers/serial/amba-pl010.c
drivers/serial/amba-pl011.c
drivers/serial/imx.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/amba-pl022.c [new file with mode: 0644]
drivers/spi/spi_s3c24xx_gpio.c
drivers/staging/go7007/go7007.txt
drivers/staging/panel/lcd-panel-cgram.txt
drivers/staging/rt2860/common/mlme.c
drivers/staging/rt2870/common/mlme.c
drivers/staging/rt3070/common/mlme.c
drivers/staging/wlan-ng/hfa384x_usb.c
drivers/usb/Kconfig
drivers/usb/host/ohci-ep93xx.c
drivers/usb/serial/io_ti.c
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/amba-clcd.c
drivers/video/aty/aty128fb.c
drivers/video/cyber2000fb.c
drivers/video/mx3fb.c
drivers/video/omap/hwa742.c
drivers/video/pxa168fb.c [new file with mode: 0644]
drivers/video/pxa168fb.h [new file with mode: 0644]
drivers/video/uvesafb.c
drivers/virtio/virtio.c
drivers/virtio/virtio_balloon.c
drivers/virtio/virtio_pci.c
drivers/virtio/virtio_ring.c
drivers/w1/Kconfig
drivers/w1/masters/Kconfig
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/iop_wdt.c
drivers/watchdog/orion5x_wdt.c [deleted file]
drivers/watchdog/orion_wdt.c [new file with mode: 0644]
drivers/xen/manage.c
fs/Kconfig
fs/bio.c
fs/compat.c
fs/compat_ioctl.c
fs/configfs/configfs_internal.h
fs/configfs/dir.c
fs/configfs/inode.c
fs/dlm/dir.c
fs/dlm/lockspace.c
fs/dlm/lowcomms.c
fs/dlm/lowcomms.h
fs/dlm/member.c
fs/dlm/requestqueue.c
fs/eventfd.c
fs/exofs/common.h
fs/exofs/inode.c
fs/exofs/osd.c
fs/ext2/ext2.h
fs/fuse/Makefile
fs/fuse/cuse.c [new file with mode: 0644]
fs/fuse/dev.c
fs/fuse/dir.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/fuse/inode.c
fs/gfs2/Makefile
fs/gfs2/bmap.c
fs/gfs2/glock.c
fs/gfs2/log.c
fs/gfs2/lops.c
fs/gfs2/ops_fstype.c
fs/gfs2/rgrp.c
fs/gfs2/super.c
fs/gfs2/trace_gfs2.h [new file with mode: 0644]
fs/inode.c
fs/partitions/check.c
fs/xfs/Kconfig
fs/xfs/Makefile
fs/xfs/linux-2.6/xfs_acl.c [new file with mode: 0644]
fs/xfs/linux-2.6/xfs_ioctl.c
fs/xfs/linux-2.6/xfs_iops.c
fs/xfs/linux-2.6/xfs_lrw.c
fs/xfs/linux-2.6/xfs_quotaops.c
fs/xfs/linux-2.6/xfs_super.c
fs/xfs/linux-2.6/xfs_sync.c
fs/xfs/linux-2.6/xfs_sync.h
fs/xfs/linux-2.6/xfs_xattr.c
fs/xfs/quota/xfs_dquot.c
fs/xfs/quota/xfs_dquot.h
fs/xfs/quota/xfs_dquot_item.c
fs/xfs/quota/xfs_qm.c
fs/xfs/quota/xfs_qm.h
fs/xfs/quota/xfs_qm_bhv.c
fs/xfs/quota/xfs_qm_stats.c
fs/xfs/quota/xfs_qm_syscalls.c
fs/xfs/quota/xfs_trans_dquot.c
fs/xfs/xfs_acl.c [deleted file]
fs/xfs/xfs_acl.h
fs/xfs/xfs_ag.h
fs/xfs/xfs_arch.h
fs/xfs/xfs_attr.c
fs/xfs/xfs_bmap.c
fs/xfs/xfs_bmap_btree.c
fs/xfs/xfs_filestream.c
fs/xfs/xfs_fs.h
fs/xfs/xfs_iget.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_iomap.c
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_mount.c
fs/xfs/xfs_mount.h
fs/xfs/xfs_qmops.c [deleted file]
fs/xfs/xfs_quota.h
fs/xfs/xfs_rename.c
fs/xfs/xfs_rw.c
fs/xfs/xfs_trans.c
fs/xfs/xfs_utils.c
fs/xfs/xfs_vnodeops.c
fs/xfs/xfs_vnodeops.h
include/asm-generic/Kbuild
include/asm-generic/Kbuild.asm
include/asm-generic/atomic-long.h [new file with mode: 0644]
include/asm-generic/atomic.h
include/asm-generic/auxvec.h [new file with mode: 0644]
include/asm-generic/bitops.h
include/asm-generic/bitops/atomic.h
include/asm-generic/bitsperlong.h [new file with mode: 0644]
include/asm-generic/bugs.h [new file with mode: 0644]
include/asm-generic/cache.h [new file with mode: 0644]
include/asm-generic/cacheflush.h [new file with mode: 0644]
include/asm-generic/checksum.h [new file with mode: 0644]
include/asm-generic/current.h [new file with mode: 0644]
include/asm-generic/delay.h [new file with mode: 0644]
include/asm-generic/dma.h [new file with mode: 0644]
include/asm-generic/fb.h [new file with mode: 0644]
include/asm-generic/getorder.h [new file with mode: 0644]
include/asm-generic/hardirq.h [new file with mode: 0644]
include/asm-generic/hw_irq.h [new file with mode: 0644]
include/asm-generic/int-l64.h
include/asm-generic/int-ll64.h
include/asm-generic/io.h [new file with mode: 0644]
include/asm-generic/ioctls.h [new file with mode: 0644]
include/asm-generic/ipcbuf.h [new file with mode: 0644]
include/asm-generic/irq.h [new file with mode: 0644]
include/asm-generic/irqflags.h [new file with mode: 0644]
include/asm-generic/kmap_types.h [new file with mode: 0644]
include/asm-generic/linkage.h [new file with mode: 0644]
include/asm-generic/mman-common.h [new file with mode: 0644]
include/asm-generic/mman.h
include/asm-generic/mmu.h [new file with mode: 0644]
include/asm-generic/mmu_context.h [new file with mode: 0644]
include/asm-generic/module.h [new file with mode: 0644]
include/asm-generic/msgbuf.h [new file with mode: 0644]
include/asm-generic/mutex.h [new file with mode: 0644]
include/asm-generic/page.h
include/asm-generic/param.h [new file with mode: 0644]
include/asm-generic/parport.h [new file with mode: 0644]
include/asm-generic/pci.h
include/asm-generic/pgalloc.h [new file with mode: 0644]
include/asm-generic/posix_types.h [new file with mode: 0644]
include/asm-generic/rtc.h
include/asm-generic/scatterlist.h [new file with mode: 0644]
include/asm-generic/segment.h [new file with mode: 0644]
include/asm-generic/sembuf.h [new file with mode: 0644]
include/asm-generic/serial.h [new file with mode: 0644]
include/asm-generic/setup.h [new file with mode: 0644]
include/asm-generic/shmbuf.h [new file with mode: 0644]
include/asm-generic/shmparam.h [new file with mode: 0644]
include/asm-generic/signal-defs.h [new file with mode: 0644]
include/asm-generic/signal.h
include/asm-generic/socket.h [new file with mode: 0644]
include/asm-generic/sockios.h [new file with mode: 0644]
include/asm-generic/spinlock.h [new file with mode: 0644]
include/asm-generic/stat.h [new file with mode: 0644]
include/asm-generic/string.h [new file with mode: 0644]
include/asm-generic/swab.h [new file with mode: 0644]
include/asm-generic/syscalls.h [new file with mode: 0644]
include/asm-generic/system.h [new file with mode: 0644]
include/asm-generic/termbits.h [new file with mode: 0644]
include/asm-generic/termios-base.h [new file with mode: 0644]
include/asm-generic/termios.h
include/asm-generic/timex.h [new file with mode: 0644]
include/asm-generic/tlbflush.h [new file with mode: 0644]
include/asm-generic/types.h [new file with mode: 0644]
include/asm-generic/uaccess-unaligned.h [new file with mode: 0644]
include/asm-generic/uaccess.h
include/asm-generic/ucontext.h [new file with mode: 0644]
include/asm-generic/unaligned.h [new file with mode: 0644]
include/asm-generic/unistd.h [new file with mode: 0644]
include/asm-generic/user.h [new file with mode: 0644]
include/asm-generic/vga.h [new file with mode: 0644]
include/asm-generic/vmlinux.lds.h
include/drm/drmP.h
include/drm/drm_hashtab.h
include/drm/drm_mm.h [new file with mode: 0644]
include/drm/drm_pciids.h
include/linux/amba/pl022.h [new file with mode: 0644]
include/linux/amba/serial.h
include/linux/atmel-mci.h
include/linux/blkdev.h
include/linux/cb710.h [new file with mode: 0644]
include/linux/clk.h
include/linux/compiler.h
include/linux/device.h
include/linux/dlm.h
include/linux/fuse.h
include/linux/genhd.h
include/linux/gfp.h
include/linux/hid.h
include/linux/i2c-ocores.h
include/linux/ide.h
include/linux/if_ether.h
include/linux/init.h
include/linux/interrupt.h
include/linux/keyboard.h
include/linux/lguest.h
include/linux/lguest_launcher.h
include/linux/mfd/tmio.h
include/linux/mlx4/device.h
include/linux/mlx4/qp.h
include/linux/module.h
include/linux/moduleparam.h
include/linux/page_cgroup.h
include/linux/pci_ids.h
include/linux/perf_counter.h
include/linux/pm.h
include/linux/pnp.h
include/linux/section-names.h [deleted file]
include/linux/slab.h
include/linux/slob_def.h
include/linux/slub_def.h
include/linux/suspend.h
include/linux/syscalls.h
include/linux/ultrasound.h
include/linux/virtio.h
include/linux/virtio_config.h
include/linux/virtio_pci.h
include/linux/virtio_ring.h
include/scsi/fc/fc_fip.h
include/scsi/iscsi_if.h
include/scsi/libfc.h
include/scsi/libiscsi.h
include/scsi/osd_attributes.h
include/scsi/osd_initiator.h
include/scsi/osd_protocol.h
include/scsi/scsi_transport_iscsi.h
include/sound/asound.h
include/sound/core.h
include/sound/driver.h [deleted file]
include/sound/pcm.h
include/sound/soc-dai.h
include/sound/soc-dapm.h
include/sound/soc.h
include/sound/wm9081.h [new file with mode: 0644]
include/video/pxa168fb.h [new file with mode: 0644]
init/Kconfig
init/main.c
kernel/irq/handle.c
kernel/kallsyms.c
kernel/kexec.c
kernel/module.c
kernel/params.c
kernel/perf_counter.c
kernel/power/Kconfig
kernel/power/Makefile
kernel/power/disk.c [deleted file]
kernel/power/hibernate.c [new file with mode: 0644]
kernel/power/hibernate_nvs.c [new file with mode: 0644]
kernel/power/main.c
kernel/power/power.h
kernel/power/poweroff.c
kernel/power/snapshot.c
kernel/power/suspend.c [new file with mode: 0644]
kernel/power/suspend_test.c [new file with mode: 0644]
kernel/power/swsusp.c
kernel/rtmutex.c
kernel/sched.c
kernel/timer.c
lib/Makefile
lib/checksum.c [new file with mode: 0644]
lib/extable.c
mm/maccess.c
mm/page_cgroup.c
mm/slab.c
mm/slub.c
mm/vmscan.c
net/9p/trans_virtio.c
net/ipv6/Kconfig
net/ipv6/addrconf.c
net/netfilter/Kconfig
net/netfilter/nf_conntrack_acct.c
scripts/Makefile.headersinst
scripts/basic/docproc.c
scripts/basic/fixdep.c
scripts/checksyscalls.sh
scripts/config
scripts/gcc-version.sh
scripts/headers.sh
scripts/headers_check.pl
scripts/kallsyms.c
scripts/kconfig/.gitignore
scripts/kconfig/Makefile
scripts/kconfig/conf.c
scripts/kconfig/confdata.c
scripts/kconfig/lkc.h
scripts/kconfig/lxdialog/checklist.c
scripts/kconfig/mconf.c
scripts/kconfig/qconf.cc
scripts/kconfig/util.c
scripts/kernel-doc
scripts/mod/file2alias.c
scripts/mod/modpost.c
scripts/package/builddeb
scripts/recordmcount.pl
scripts/setlocalversion
scripts/unifdef.c
scripts/ver_linux
sound/aoa/fabrics/layout.c
sound/aoa/soundbus/i2sbus/core.c
sound/arm/aaci.c
sound/core/Kconfig
sound/core/init.c
sound/core/jack.c
sound/core/oss/pcm_oss.c
sound/core/pcm_lib.c
sound/core/pcm_native.c
sound/core/seq/Kconfig [new file with mode: 0644]
sound/core/seq/Makefile
sound/drivers/opl3/Makefile
sound/drivers/opl4/Makefile
sound/isa/Kconfig
sound/isa/es1688/es1688.c
sound/isa/gus/gusextreme.c
sound/isa/sb/Makefile
sound/isa/sc6000.c
sound/mips/sgio2audio.c
sound/oss/msnd.c
sound/parisc/harmony.c
sound/pci/Kconfig
sound/pci/Makefile
sound/pci/au88x0/au88x0_core.c
sound/pci/aw2/aw2-saa7146.c
sound/pci/bt87x.c
sound/pci/ca0106/ca0106_main.c
sound/pci/ca0106/ca0106_mixer.c
sound/pci/ctxfi/Makefile [new file with mode: 0644]
sound/pci/ctxfi/ct20k1reg.h [new file with mode: 0644]
sound/pci/ctxfi/ct20k2reg.h [new file with mode: 0644]
sound/pci/ctxfi/ctamixer.c [new file with mode: 0644]
sound/pci/ctxfi/ctamixer.h [new file with mode: 0644]
sound/pci/ctxfi/ctatc.c [new file with mode: 0644]
sound/pci/ctxfi/ctatc.h [new file with mode: 0644]
sound/pci/ctxfi/ctdaio.c [new file with mode: 0644]
sound/pci/ctxfi/ctdaio.h [new file with mode: 0644]
sound/pci/ctxfi/cthardware.c [new file with mode: 0644]
sound/pci/ctxfi/cthardware.h [new file with mode: 0644]
sound/pci/ctxfi/cthw20k1.c [new file with mode: 0644]
sound/pci/ctxfi/cthw20k1.h [new file with mode: 0644]
sound/pci/ctxfi/cthw20k2.c [new file with mode: 0644]
sound/pci/ctxfi/cthw20k2.h [new file with mode: 0644]
sound/pci/ctxfi/ctimap.c [new file with mode: 0644]
sound/pci/ctxfi/ctimap.h [new file with mode: 0644]
sound/pci/ctxfi/ctmixer.c [new file with mode: 0644]
sound/pci/ctxfi/ctmixer.h [new file with mode: 0644]
sound/pci/ctxfi/ctpcm.c [new file with mode: 0644]
sound/pci/ctxfi/ctpcm.h [new file with mode: 0644]
sound/pci/ctxfi/ctresource.c [new file with mode: 0644]
sound/pci/ctxfi/ctresource.h [new file with mode: 0644]
sound/pci/ctxfi/ctsrc.c [new file with mode: 0644]
sound/pci/ctxfi/ctsrc.h [new file with mode: 0644]
sound/pci/ctxfi/cttimer.c [new file with mode: 0644]
sound/pci/ctxfi/cttimer.h [new file with mode: 0644]
sound/pci/ctxfi/ctvmem.c [new file with mode: 0644]
sound/pci/ctxfi/ctvmem.h [new file with mode: 0644]
sound/pci/ctxfi/xfi.c [new file with mode: 0644]
sound/pci/emu10k1/Makefile
sound/pci/emu10k1/emu10k1x.c
sound/pci/emu10k1/emupcm.c
sound/pci/hda/Kconfig
sound/pci/hda/Makefile
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_hwdep.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_proc.c
sound/pci/hda/patch_ca0110.c [new file with mode: 0644]
sound/pci/hda/patch_nvhdmi.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.h
sound/pci/ice1712/ice1724.c
sound/pci/ice1712/maya44.c [new file with mode: 0644]
sound/pci/ice1712/maya44.h [new file with mode: 0644]
sound/pci/lx6464es/Makefile [new file with mode: 0644]
sound/pci/lx6464es/lx6464es.c [new file with mode: 0644]
sound/pci/lx6464es/lx6464es.h [new file with mode: 0644]
sound/pci/lx6464es/lx_core.c [new file with mode: 0644]
sound/pci/lx6464es/lx_core.h [new file with mode: 0644]
sound/pci/lx6464es/lx_defs.h [new file with mode: 0644]
sound/pci/oxygen/oxygen_pcm.c
sound/pci/oxygen/virtuoso.c
sound/pci/riptide/riptide.c
sound/pci/rme9652/hdsp.c
sound/pci/rme9652/hdspm.c
sound/pci/sis7019.h
sound/pci/vx222/vx222_ops.c
sound/ppc/awacs.c
sound/ppc/beep.c
sound/ppc/burgundy.c
sound/ppc/daca.c
sound/ppc/keywest.c
sound/ppc/pmac.c
sound/ppc/snd_ps3.c
sound/ppc/tumbler.c
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/atmel/Kconfig
sound/soc/atmel/Makefile
sound/soc/atmel/playpaq_wm8510.c
sound/soc/atmel/snd-soc-afeb9260.c [new file with mode: 0644]
sound/soc/blackfin/bf5xx-ac97.c
sound/soc/blackfin/bf5xx-sport.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ac97.c
sound/soc/codecs/ad1980.c
sound/soc/codecs/cs4270.c
sound/soc/codecs/spdif_transciever.c [new file with mode: 0644]
sound/soc/codecs/spdif_transciever.h [new file with mode: 0644]
sound/soc/codecs/ssm2602.c
sound/soc/codecs/stac9766.c [new file with mode: 0644]
sound/soc/codecs/stac9766.h [new file with mode: 0644]
sound/soc/codecs/tlv320aic23.c
sound/soc/codecs/twl4030.c
sound/soc/codecs/twl4030.h
sound/soc/codecs/uda134x.c
sound/soc/codecs/wm8350.c
sound/soc/codecs/wm8350.h
sound/soc/codecs/wm8400.c
sound/soc/codecs/wm8510.c
sound/soc/codecs/wm8580.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8900.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8940.c [new file with mode: 0644]
sound/soc/codecs/wm8940.h [new file with mode: 0644]
sound/soc/codecs/wm8960.c [new file with mode: 0644]
sound/soc/codecs/wm8960.h [new file with mode: 0644]
sound/soc/codecs/wm8988.c [new file with mode: 0644]
sound/soc/codecs/wm8988.h [new file with mode: 0644]
sound/soc/codecs/wm8990.c
sound/soc/codecs/wm9081.c [new file with mode: 0644]
sound/soc/codecs/wm9081.h [new file with mode: 0644]
sound/soc/codecs/wm9705.c
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9713.c
sound/soc/fsl/Kconfig
sound/soc/fsl/Makefile
sound/soc/fsl/efika-audio-fabric.c [new file with mode: 0644]
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/mpc5200_dma.c [new file with mode: 0644]
sound/soc/fsl/mpc5200_dma.h [new file with mode: 0644]
sound/soc/fsl/mpc5200_psc_ac97.c [new file with mode: 0644]
sound/soc/fsl/mpc5200_psc_ac97.h [new file with mode: 0644]
sound/soc/fsl/mpc5200_psc_i2s.c
sound/soc/fsl/mpc5200_psc_i2s.h [new file with mode: 0644]
sound/soc/fsl/pcm030-audio-fabric.c [new file with mode: 0644]
sound/soc/omap/Kconfig
sound/soc/omap/Makefile
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 [new file with mode: 0644]
sound/soc/omap/omap3pandora.c
sound/soc/omap/overo.c
sound/soc/omap/sdp3430.c
sound/soc/pxa/Kconfig
sound/soc/pxa/Makefile
sound/soc/pxa/em-x270.c
sound/soc/pxa/imote2.c [new file with mode: 0644]
sound/soc/pxa/magician.c
sound/soc/pxa/palm27x.c
sound/soc/pxa/pxa-ssp.c
sound/soc/pxa/pxa2xx-i2s.c
sound/soc/s3c24xx/neo1973_wm8753.c
sound/soc/s3c24xx/s3c-i2s-v2.c
sound/soc/s3c24xx/s3c2412-i2s.c
sound/soc/s3c24xx/s3c2443-ac97.c
sound/soc/s3c24xx/s3c24xx-i2s.c
sound/soc/s3c24xx/s3c24xx-pcm.c
sound/soc/s3c24xx/s3c64xx-i2s.c
sound/soc/s3c24xx/s3c64xx-i2s.h
sound/soc/s6000/Kconfig [new file with mode: 0644]
sound/soc/s6000/Makefile [new file with mode: 0644]
sound/soc/s6000/s6000-i2s.c [new file with mode: 0644]
sound/soc/s6000/s6000-i2s.h [new file with mode: 0644]
sound/soc/s6000/s6000-pcm.c [new file with mode: 0644]
sound/soc/s6000/s6000-pcm.h [new file with mode: 0644]
sound/soc/s6000/s6105-ipcam.c [new file with mode: 0644]
sound/soc/sh/ssi.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/txx9/Kconfig [new file with mode: 0644]
sound/soc/txx9/Makefile [new file with mode: 0644]
sound/soc/txx9/txx9aclc-ac97.c [new file with mode: 0644]
sound/soc/txx9/txx9aclc-generic.c [new file with mode: 0644]
sound/soc/txx9/txx9aclc.c [new file with mode: 0644]
sound/soc/txx9/txx9aclc.h [new file with mode: 0644]
sound/synth/Makefile
sound/synth/emux/Makefile
sound/usb/caiaq/audio.c
sound/usb/caiaq/device.c
sound/usb/caiaq/device.h
sound/usb/caiaq/midi.c
sound/usb/usbaudio.c
sound/usb/usbmixer.c
sound/usb/usbquirks.h
tools/perf/builtin-record.c
tools/perf/design.txt
tools/perf/perf.h
tools/perf/util/parse-events.c

index 51bd99d6a260263f28617dca7d576af1deb4b027..cecb3b040cc17d22acdb9268e130a459e771608a 100644 (file)
@@ -3,7 +3,7 @@
 # subdirectories here. Add them in the ".gitignore" file
 # in that subdirectory instead.
 #
-# NOTE! Please use 'git-ls-files -i --exclude-standard'
+# NOTE! Please use 'git ls-files -i --exclude-standard'
 # command after changing this file, to see if there are
 # any tracked files which get ignored after the change.
 #
@@ -25,6 +25,8 @@
 *.elf
 *.bin
 *.gz
+*.lzma
+*.patch
 
 #
 # Top-level generic files
@@ -62,6 +64,12 @@ series
 cscope.*
 ncscope.*
 
+# gnu global files
+GPATH
+GRTAGS
+GSYMS
+GTAGS
+
 *.orig
 *~
 \#*#
index b95082be4d5eec7656e858685bd28f5b871a1efd..664392481c840980090b6e79ec35753d3f6a9272 100644 (file)
@@ -29,7 +29,7 @@ hardware, for example, you probably needn't concern yourself with
 isdn4k-utils.
 
 o  Gnu C                  3.2                     # gcc --version
-o  Gnu make               3.79.1                  # make --version
+o  Gnu make               3.80                    # make --version
 o  binutils               2.12                    # ld -v
 o  util-linux             2.10o                   # fdformat --version
 o  module-init-tools      0.9.10                  # depmod -V
@@ -48,6 +48,7 @@ o  procps                 3.2.0                   # ps --version
 o  oprofile               0.9                     # oprofiled --version
 o  udev                   081                     # udevinfo -V
 o  grub                   0.93                    # grub --version
+o  mcelog                0.6
 
 Kernel compilation
 ==================
@@ -61,7 +62,7 @@ computer.
 Make
 ----
 
-You will need Gnu make 3.79.1 or later to build the kernel.
+You will need Gnu make 3.80 or later to build the kernel.
 
 Binutils
 --------
@@ -276,6 +277,16 @@ before running exportfs or mountd.  It is recommended that all NFS
 services be protected from the internet-at-large by a firewall where
 that is possible.
 
+mcelog
+------
+
+In Linux 2.6.31+ the i386 kernel needs to run the mcelog utility
+as a regular cronjob similar to the x86-64 kernel to process and log
+machine check events when CONFIG_X86_NEW_MCE is enabled. Machine check
+events are errors reported by the CPU. Processing them is strongly encouraged.
+All x86-64 kernels since 2.6.4 require the mcelog utility to
+process machine checks.
+
 Getting updated software
 ========================
 
@@ -365,6 +376,10 @@ FUSE
 ----
 o <http://sourceforge.net/projects/fuse>
 
+mcelog
+------
+o <ftp://ftp.kernel.org/pub/linux/utils/cpu/mce/mcelog/>
+
 Networking
 **********
 
index 72968cd5eaf3286f08cc6eb7dfb3115ff9c5ce90..8bb37237ebd25b19759cc47874c63155406ea28f 100644 (file)
@@ -698,8 +698,8 @@ very often is not. Abundant use of the inline keyword leads to a much bigger
 kernel, which in turn slows the system as a whole down, due to a bigger
 icache footprint for the CPU and simply because there is less memory
 available for the pagecache. Just think about it; a pagecache miss causes a
-disk seek, which easily takes 5 miliseconds. There are a LOT of cpu cycles
-that can go into these 5 miliseconds.
+disk seek, which easily takes 5 milliseconds. There are a LOT of cpu cycles
+that can go into these 5 milliseconds.
 
 A reasonable rule of thumb is to not put inline at functions that have more
 than 3 lines of code in them. An exception to this rule are the cases where
index 25fb8bcf32a276f280d44aa53a4f2712a14257f4..5aceb88b3f8b622c8c23ed288f37f42de705c904 100644 (file)
@@ -676,8 +676,8 @@ this directory the following files can currently be found:
        dma-api/all_errors      This file contains a numeric value. If this
                                value is not equal to zero the debugging code
                                will print a warning for every error it finds
-                               into the kernel log. Be carefull with this
-                               option. It can easily flood your logs.
+                               into the kernel log. Be careful with this
+                               option, as it can easily flood your logs.
 
        dma-api/disabled        This read-only file contains the character 'Y'
                                if the debugging code is disabled. This can
index 6389dec33459e84228ef43a00f9d80be158bab5d..93cb28d05dcd92da30dde47ec58205e2b0851022 100644 (file)
@@ -118,7 +118,7 @@ to another chain) checking the final 'nulls' value if
 the lookup met the end of chain. If final 'nulls' value
 is not the slot number, then we must restart the lookup at
 the beginning. If the object was moved to the same chain,
-then the reader doesnt care : It might eventually
+then the reader doesn't care : It might eventually
 scan the list again without harm.
 
 
index 6fc656035925a91b219ab70e4a9333d14a486cb9..561826f82093574bc61d887cae0436935d317c5e 100644 (file)
@@ -5,7 +5,7 @@ Copyright 2006, 2007 Simtec Electronics
 
 The Silicon Motion SM501 multimedia companion chip is a multifunction device
 which may provide numerous interfaces including USB host controller USB gadget,
-Asyncronous Serial ports, Audio functions and a dual display video interface.
+asynchronous serial ports, audio functions, and a dual display video interface.
 The device may be connected by PCI or local bus with varying functions enabled.
 
 Core
index f309d3c6221c3699a0c0b97fbe689faed09e4d2f..5c555a8b39e553cf0c3117026ebf37d481c588b6 100644 (file)
@@ -91,6 +91,10 @@ Be as specific as possible.  The WORST descriptions possible include
 things like "update driver X", "bug fix for driver X", or "this patch
 includes updates for subsystem X.  Please apply."
 
+The maintainer will thank you if you write your patch description in a
+form which can be easily pulled into Linux's source code management
+system, git, as a "commit log".  See #15, below.
+
 If your description starts to get long, that's a sign that you probably
 need to split up your patch.  See #3, next.
 
@@ -183,8 +187,9 @@ Even if the maintainer did not respond in step #4, make sure to ALWAYS
 copy the maintainer when you change their code.
 
 For small patches you may want to CC the Trivial Patch Monkey
-trivial@kernel.org managed by Jesper Juhl; which collects "trivial"
-patches. Trivial patches must qualify for one of the following rules:
+trivial@kernel.org which collects "trivial" patches. Have a look
+into the MAINTAINERS file for its current manager.
+Trivial patches must qualify for one of the following rules:
  Spelling fixes in documentation
  Spelling fixes which could break grep(1)
  Warning fixes (cluttering with useless warnings is bad)
@@ -196,7 +201,6 @@ patches. Trivial patches must qualify for one of the following rules:
  since people copy, as long as it's trivial)
  Any fix by the author/maintainer of the file (ie. patch monkey
  in re-transmission mode)
-URL: <http://www.kernel.org/pub/linux/kernel/people/juhl/trivial/>
 
 
 
@@ -405,7 +409,14 @@ person it names.  This tag documents that potentially interested parties
 have been included in the discussion
 
 
-14) Using Tested-by: and Reviewed-by:
+14) Using Reported-by:, Tested-by: and Reviewed-by:
+
+If this patch fixes a problem reported by somebody else, consider adding a
+Reported-by: tag to credit the reporter for their contribution.  Please
+note that this tag should not be added without the reporter's permission,
+especially if the problem was not reported in a public forum.  That said,
+if we diligently credit our bug reporters, they will, hopefully, be
+inspired to help us again in the future.
 
 A Tested-by: tag indicates that the patch has been successfully tested (in
 some environment) by the person named.  This tag informs maintainers that
@@ -444,7 +455,7 @@ offer a Reviewed-by tag for a patch.  This tag serves to give credit to
 reviewers and to inform maintainers of the degree of review which has been
 done on the patch.  Reviewed-by: tags, when supplied by reviewers known to
 understand the subject area and to perform thorough reviews, will normally
-increase the liklihood of your patch getting into the kernel.
+increase the likelihood of your patch getting into the kernel.
 
 
 15) The canonical patch format
@@ -485,12 +496,33 @@ phrase" should not be a filename.  Do not use the same "summary
 phrase" for every patch in a whole patch series (where a "patch
 series" is an ordered sequence of multiple, related patches).
 
-Bear in mind that the "summary phrase" of your email becomes
-a globally-unique identifier for that patch.  It propagates
-all the way into the git changelog.  The "summary phrase" may
-later be used in developer discussions which refer to the patch.
-People will want to google for the "summary phrase" to read
-discussion regarding that patch.
+Bear in mind that the "summary phrase" of your email becomes a
+globally-unique identifier for that patch.  It propagates all the way
+into the git changelog.  The "summary phrase" may later be used in
+developer discussions which refer to the patch.  People will want to
+google for the "summary phrase" to read discussion regarding that
+patch.  It will also be the only thing that people may quickly see
+when, two or three months later, they are going through perhaps
+thousands of patches using tools such as "gitk" or "git log
+--oneline".
+
+For these reasons, the "summary" must be no more than 70-75
+characters, and it must describe both what the patch changes, as well
+as why the patch might be necessary.  It is challenging to be both
+succinct and descriptive, but that is what a well-written summary
+should do.
+
+The "summary phrase" may be prefixed by tags enclosed in square
+brackets: "Subject: [PATCH tag] <summary phrase>".  The tags are not
+considered part of the summary phrase, but describe how the patch
+should be treated.  Common tags might include a version descriptor if
+the multiple versions of the patch have been sent out in response to
+comments (i.e., "v1, v2, v3"), or "RFC" to indicate a request for
+comments.  If there are four patches in a patch series the individual
+patches may be numbered like this: 1/4, 2/4, 3/4, 4/4.  This assures
+that developers understand the order in which the patches should be
+applied and that they have reviewed or applied all of the patches in
+the patch series.
 
 A couple of example Subjects:
 
@@ -510,19 +542,31 @@ the patch author in the changelog.
 The explanation body will be committed to the permanent source
 changelog, so should make sense to a competent reader who has long
 since forgotten the immediate details of the discussion that might
-have led to this patch.
+have led to this patch.  Including symptoms of the failure which the
+patch addresses (kernel log messages, oops messages, etc.) is
+especially useful for people who might be searching the commit logs
+looking for the applicable patch.  If a patch fixes a compile failure,
+it may not be necessary to include _all_ of the compile failures; just
+enough that it is likely that someone searching for the patch can find
+it.  As in the "summary phrase", it is important to be both succinct as
+well as descriptive.
 
 The "---" marker line serves the essential purpose of marking for patch
 handling tools where the changelog message ends.
 
 One good use for the additional comments after the "---" marker is for
-a diffstat, to show what files have changed, and the number of inserted
-and deleted lines per file.  A diffstat is especially useful on bigger
-patches.  Other comments relevant only to the moment or the maintainer,
-not suitable for the permanent changelog, should also go here.
-Use diffstat options "-p 1 -w 70" so that filenames are listed from the
-top of the kernel source tree and don't use too much horizontal space
-(easily fit in 80 columns, maybe with some indentation).
+a diffstat, to show what files have changed, and the number of
+inserted and deleted lines per file.  A diffstat is especially useful
+on bigger patches.  Other comments relevant only to the moment or the
+maintainer, not suitable for the permanent changelog, should also go
+here.  A good example of such comments might be "patch changelogs"
+which describe what has changed between the v1 and v2 version of the
+patch.
+
+If you are going to include a diffstat after the "---" marker, please
+use diffstat options "-p 1 -w 70" so that filenames are listed from
+the top of the kernel source tree and don't use too much horizontal
+space (easily fit in 80 columns, maybe with some indentation).
 
 See more details on the proper patch format in the following
 references.
index ea7ccfc4b274f5dcf269d9d239c8aeaf36cb4a6c..948c8718d967b41c1f3c43e4356a5deb26ce3d15 100644 (file)
@@ -51,7 +51,7 @@ PIN Numbers
 -----------
 
   Each pin has an unique number associated with it in regs-gpio.h,
-  eg S3C2410_GPA0 or S3C2410_GPF1. These defines are used to tell
+  eg S3C2410_GPA(0) or S3C2410_GPF(1). These defines are used to tell
   the GPIO functions which pin is to be used.
 
 
@@ -65,11 +65,11 @@ Configuring a pin
 
   Eg:
 
-     s3c2410_gpio_cfgpin(S3C2410_GPA0, S3C2410_GPA0_ADDR0);
-     s3c2410_gpio_cfgpin(S3C2410_GPE8, S3C2410_GPE8_SDDAT1);
+     s3c2410_gpio_cfgpin(S3C2410_GPA(0), S3C2410_GPA0_ADDR0);
+     s3c2410_gpio_cfgpin(S3C2410_GPE(8), S3C2410_GPE8_SDDAT1);
 
-   which would turn GPA0 into the lowest Address line A0, and set
-   GPE8 to be connected to the SDIO/MMC controller's SDDAT1 line.
+   which would turn GPA(0) into the lowest Address line A0, and set
+   GPE(8) to be connected to the SDIO/MMC controller's SDDAT1 line.
 
 
 Reading the current configuration
index 72576769e0f4976fead6933727edc02f2704092e..2d82c80322cbb225313778dafb3df989cf2a52fa 100644 (file)
@@ -58,7 +58,7 @@ same criteria as reads.
 front_merges   (bool)
 ------------
 
-Sometimes it happens that a request enters the io scheduler that is contigious
+Sometimes it happens that a request enters the io scheduler that is contiguous
 with a request that is already on the queue. Either it fits in the back of that
 request, or it fits at the front. That is called either a back merge candidate
 or a front merge candidate. Due to the way files are typically laid out,
index 000b0fbdc105f054b63a838f6fc36f7a816ce45a..d0d042c2fd5e9e319657117b3de567b2d42a995a 100644 (file)
@@ -27,7 +27,7 @@ parameter.
 
 For simplicity, only one braille console can be enabled, other uses of
 console=brl,... will be discarded.  Also note that it does not interfere with
-the console selection mecanism described in serial-console.txt
+the console selection mechanism described in serial-console.txt
 
 For now, only the VisioBraille device is supported.
 
index c11b931f8f980f53f1389f617b642bb90608df58..15174985ad08d0262c5f15288a0feb51916c3fb1 100644 (file)
@@ -76,9 +76,9 @@ Do the steps below to download the BIOS image.
 
 The /sys/class/firmware/dell_rbu/ entries will remain till the following is
 done.
-echo -1 > /sys/class/firmware/dell_rbu/loading.
+echo -1 > /sys/class/firmware/dell_rbu/loading
 Until this step is completed the driver cannot be unloaded.
-Also echoing either mono ,packet or init in to image_type will free up the
+Also echoing either monopacket or init in to image_type will free up the
 memory allocated by the driver.
 
 If a user by accident executes steps 1 and 3 above without executing step 2;
index dd48132a74dde478542e9817c63051e4cef9d00a..f622c1e9f0f926c43c54b7d0fdd6627ef3b447a6 100644 (file)
@@ -119,7 +119,7 @@ which takes quite a bit of time and thought after the "real work" has been
 done.  When done properly, though, it is time well spent.
 
 
-5.4: PATCH FORMATTING
+5.4: PATCH FORMATTING AND CHANGELOGS
 
 So now you have a perfect series of patches for posting, but the work is
 not done quite yet.  Each patch needs to be formatted into a message which
@@ -146,8 +146,33 @@ that end, each patch will be composed of the following:
  - One or more tag lines, with, at a minimum, one Signed-off-by: line from
    the author of the patch.  Tags will be described in more detail below.
 
-The above three items should, normally, be the text used when committing
-the change to a revision control system.  They are followed by:
+The items above, together, form the changelog for the patch.  Writing good
+changelogs is a crucial but often-neglected art; it's worth spending
+another moment discussing this issue.  When writing a changelog, you should
+bear in mind that a number of different people will be reading your words.
+These include subsystem maintainers and reviewers who need to decide
+whether the patch should be included, distributors and other maintainers
+trying to decide whether a patch should be backported to other kernels, bug
+hunters wondering whether the patch is responsible for a problem they are
+chasing, users who want to know how the kernel has changed, and more.  A
+good changelog conveys the needed information to all of these people in the
+most direct and concise way possible.
+
+To that end, the summary line should describe the effects of and motivation
+for the change as well as possible given the one-line constraint.  The
+detailed description can then amplify on those topics and provide any
+needed additional information.  If the patch fixes a bug, cite the commit
+which introduced the bug if possible.  If a problem is associated with
+specific log or compiler output, include that output to help others
+searching for a solution to the same problem.  If the change is meant to
+support other changes coming in later patch, say so.  If internal APIs are
+changed, detail those changes and how other developers should respond.  In
+general, the more you can put yourself into the shoes of everybody who will
+be reading your changelog, the better that changelog (and the kernel as a
+whole) will be.
+
+Needless to say, the changelog should be the text used when committing the
+change to a revision control system.  It will be followed by:
 
  - The patch itself, in the unified ("-u") patch format.  Using the "-p"
    option to diff will associate function names with changes, making the
index 387b8a720f4a6fdc3bb1cd01a4aff8b7ac6cd263..d79aead9418be01011cdf87c0b37084186ae39fb 100644 (file)
@@ -188,7 +188,7 @@ For example, you can do something like the following.
 
   void my_midlayer_destroy_something()
   {
-       devres_release_group(dev, my_midlayer_create_soemthing);
+       devres_release_group(dev, my_midlayer_create_something);
   }
 
 
index 8eda3fb664166726163bf59565c9d52c76af6c79..06f8f46692dc5e26cebdd7e6251ec38f308b9c1f 100644 (file)
@@ -23,8 +23,8 @@ first time, it was renamed to 'EDAC'.
 The bluesmoke project at sourceforge.net is now utilized as a 'staging area'
 for EDAC development, before it is sent upstream to kernel.org
 
-At the bluesmoke/EDAC project site, is a series of quilt patches against
-recent kernels, stored in a SVN respository. For easier downloading, there
+At the bluesmoke/EDAC project site is a series of quilt patches against
+recent kernels, stored in a SVN repository. For easier downloading, there
 is also a tarball snapshot available.
 
 ============================================================================
@@ -73,9 +73,9 @@ the vendor should tie the parity status bits to 0 if they do not intend
 to generate parity.  Some vendors do not do this, and thus the parity bit
 can "float" giving false positives.
 
-In the kernel there is a pci device attribute located in sysfs that is
+In the kernel there is a PCI device attribute located in sysfs that is
 checked by the EDAC PCI scanning code. If that attribute is set,
-PCI parity/error scannining is skipped for that device. The attribute
+PCI parity/error scanning is skipped for that device. The attribute
 is:
 
        broken_parity_status
index c87bfe5c630a16893aed884a86f6e39506d94182..b994c3b1054995aecc045fae1594e6b370d1d217 100644 (file)
@@ -1,7 +1,7 @@
 SH7760/SH7763 integrated LCDC Framebuffer driver
 ================================================
 
-0. Overwiew
+0. Overview
 -----------
 The SH7760/SH7763 have an integrated LCD Display controller (LCDC) which
 supports (in theory) resolutions ranging from 1x1 to 1024x1024,
index de491a3e23131001c7e308e30aa12f8326159f69..ec9ef5d0d7b3b3af5d12c595edd7ddb048be6f2b 100644 (file)
@@ -437,3 +437,13 @@ 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_X86_OLD_MCE
+When:  2.6.32
+Why:   Remove the old legacy 32bit machine check code. This has been
+       superseded by the newer machine check code from the 64bit port,
+       but the old version has been kept around for easier testing. Note this
+       doesn't impact the old P5 and WinChip machine check handlers.
+Who:   Andi Kleen <andi@firstfloor.org>
index c6341745df37523d368464e05ee085653bddaa32..8f78ded4b648697490495e0e684f7d98790c6ad0 100644 (file)
@@ -369,7 +369,7 @@ The call requires an initialized struct autofs_dev_ioctl. There are two
 possible variations. Both use the path field set to the path of the mount
 point to check and the size field adjusted appropriately. One uses the
 ioctlfd field to identify a specific mount point to check while the other
-variation uses the path and optionaly arg1 set to an autofs mount type.
+variation uses the path and optionally arg1 set to an autofs mount type.
 The call returns 1 if this is a mount point and sets arg1 to the device
 number of the mount and field arg2 to the relevant super block magic
 number (described below) or 0 if it isn't a mountpoint. In both cases
index 4db125b3a5c6ab2e4ddf3539dc8add47e0f71895..2666b1ed5e9e6515cdda71c878f846438167a0b1 100644 (file)
@@ -184,7 +184,7 @@ This has the following fields:
      have index children.
 
      If this function is not supplied or if it returns NULL then the first
-     cache in the parent's list will be chosed, or failing that, the first
+     cache in the parent's list will be chosen, or failing that, the first
      cache in the master list.
 
  (4) A function to retrieve an object's key from the netfs [mandatory].
diff --git a/Documentation/filesystems/debugfs.txt b/Documentation/filesystems/debugfs.txt
new file mode 100644 (file)
index 0000000..ed52af6
--- /dev/null
@@ -0,0 +1,158 @@
+Copyright 2009 Jonathan Corbet <corbet@lwn.net>
+
+Debugfs exists as a simple way for kernel developers to make information
+available to user space.  Unlike /proc, which is only meant for information
+about a process, or sysfs, which has strict one-value-per-file rules,
+debugfs has no rules at all.  Developers can put any information they want
+there.  The debugfs filesystem is also intended to not serve as a stable
+ABI to user space; in theory, there are no stability constraints placed on
+files exported there.  The real world is not always so simple, though [1];
+even debugfs interfaces are best designed with the idea that they will need
+to be maintained forever.
+
+Debugfs is typically mounted with a command like:
+
+    mount -t debugfs none /sys/kernel/debug
+
+(Or an equivalent /etc/fstab line). 
+
+Note that the debugfs API is exported GPL-only to modules.
+
+Code using debugfs should include <linux/debugfs.h>.  Then, the first order
+of business will be to create at least one directory to hold a set of
+debugfs files:
+
+    struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
+
+This call, if successful, will make a directory called name underneath the
+indicated parent directory.  If parent is NULL, the directory will be
+created in the debugfs root.  On success, the return value is a struct
+dentry pointer which can be used to create files in the directory (and to
+clean it up at the end).  A NULL return value indicates that something went
+wrong.  If ERR_PTR(-ENODEV) is returned, that is an indication that the
+kernel has been built without debugfs support and none of the functions
+described below will work.
+
+The most general way to create a file within a debugfs directory is with:
+
+    struct dentry *debugfs_create_file(const char *name, mode_t mode,
+                                      struct dentry *parent, void *data,
+                                      const struct file_operations *fops);
+
+Here, name is the name of the file to create, mode describes the access
+permissions the file should have, parent indicates the directory which
+should hold the file, data will be stored in the i_private field of the
+resulting inode structure, and fops is a set of file operations which
+implement the file's behavior.  At a minimum, the read() and/or write()
+operations should be provided; others can be included as needed.  Again,
+the return value will be a dentry pointer to the created file, NULL for
+error, or ERR_PTR(-ENODEV) if debugfs support is missing.
+
+In a number of cases, the creation of a set of file operations is not
+actually necessary; the debugfs code provides a number of helper functions
+for simple situations.  Files containing a single integer value can be
+created with any of:
+
+    struct dentry *debugfs_create_u8(const char *name, mode_t mode,
+                                    struct dentry *parent, u8 *value);
+    struct dentry *debugfs_create_u16(const char *name, mode_t mode,
+                                     struct dentry *parent, u16 *value);
+    struct dentry *debugfs_create_u32(const char *name, mode_t mode,
+                                     struct dentry *parent, u32 *value);
+    struct dentry *debugfs_create_u64(const char *name, mode_t mode,
+                                     struct dentry *parent, u64 *value);
+
+These files support both reading and writing the given value; if a specific
+file should not be written to, simply set the mode bits accordingly.  The
+values in these files are in decimal; if hexadecimal is more appropriate,
+the following functions can be used instead:
+
+    struct dentry *debugfs_create_x8(const char *name, mode_t mode,
+                                    struct dentry *parent, u8 *value);
+    struct dentry *debugfs_create_x16(const char *name, mode_t mode,
+                                     struct dentry *parent, u16 *value);
+    struct dentry *debugfs_create_x32(const char *name, mode_t mode,
+                                     struct dentry *parent, u32 *value);
+
+Note that there is no debugfs_create_x64().
+
+These functions are useful as long as the developer knows the size of the
+value to be exported.  Some types can have different widths on different
+architectures, though, complicating the situation somewhat.  There is a
+function meant to help out in one special case:
+
+    struct dentry *debugfs_create_size_t(const char *name, mode_t mode,
+                                        struct dentry *parent, 
+                                        size_t *value);
+
+As might be expected, this function will create a debugfs file to represent
+a variable of type size_t.
+
+Boolean values can be placed in debugfs with:
+
+    struct dentry *debugfs_create_bool(const char *name, mode_t mode,
+                                      struct dentry *parent, u32 *value);
+
+A read on the resulting file will yield either Y (for non-zero values) or
+N, followed by a newline.  If written to, it will accept either upper- or
+lower-case values, or 1 or 0.  Any other input will be silently ignored.
+
+Finally, a block of arbitrary binary data can be exported with:
+
+    struct debugfs_blob_wrapper {
+       void *data;
+       unsigned long size;
+    };
+
+    struct dentry *debugfs_create_blob(const char *name, mode_t mode,
+                                      struct dentry *parent,
+                                      struct debugfs_blob_wrapper *blob);
+
+A read of this file will return the data pointed to by the
+debugfs_blob_wrapper structure.  Some drivers use "blobs" as a simple way
+to return several lines of (static) formatted text output.  This function
+can be used to export binary information, but there does not appear to be
+any code which does so in the mainline.  Note that all files created with
+debugfs_create_blob() are read-only.
+
+There are a couple of other directory-oriented helper functions:
+
+    struct dentry *debugfs_rename(struct dentry *old_dir, 
+                                 struct dentry *old_dentry,
+                                 struct dentry *new_dir, 
+                                 const char *new_name);
+
+    struct dentry *debugfs_create_symlink(const char *name, 
+                                          struct dentry *parent,
+                                         const char *target);
+
+A call to debugfs_rename() will give a new name to an existing debugfs
+file, possibly in a different directory.  The new_name must not exist prior
+to the call; the return value is old_dentry with updated information.
+Symbolic links can be created with debugfs_create_symlink().
+
+There is one important thing that all debugfs users must take into account:
+there is no automatic cleanup of any directories created in debugfs.  If a
+module is unloaded without explicitly removing debugfs entries, the result
+will be a lot of stale pointers and no end of highly antisocial behavior.
+So all debugfs users - at least those which can be built as modules - must
+be prepared to remove all files and directories they create there.  A file
+can be removed with:
+
+    void debugfs_remove(struct dentry *dentry);
+
+The dentry value can be NULL, in which case nothing will be removed.
+
+Once upon a time, debugfs users were required to remember the dentry
+pointer for every debugfs file they created so that all files could be
+cleaned up.  We live in more civilized times now, though, and debugfs users
+can call:
+
+    void debugfs_remove_recursive(struct dentry *dentry);
+
+If this function is passed a pointer for the dentry corresponding to the
+top-level directory, the entire hierarchy below that directory will be
+removed.
+
+Notes:
+       [1] http://lwn.net/Articles/309298/
index 97882df0486567c229bb0ee867752da15b24089f..608fdba97b72c5c95dec4d28cbb8364132a8a90d 100644 (file)
@@ -294,7 +294,7 @@ max_batch_time=usec Maximum amount of time ext4 should wait for
                        amount of time (on average) that it takes to
                        finish committing a transaction.  Call this time
                        the "commit time".  If the time that the
-                       transactoin has been running is less than the
+                       transaction has been running is less than the
                        commit time, ext4 will try sleeping for the
                        commit time to see if other operations will join
                        the transaction.   The commit time is capped by
@@ -328,7 +328,7 @@ noauto_da_alloc             replacing existing files via patterns such as
                        journal commit, in the default data=ordered
                        mode, the data blocks of the new file are forced
                        to disk before the rename() operation is
-                       commited.  This provides roughly the same level
+                       committed.  This provides roughly the same level
                        of guarantees as ext3, and avoids the
                        "zero-length" problem that can happen when a
                        system crashes before the delayed allocation
@@ -358,7 +358,7 @@ written to the journal first, and then to its final location.
 In the event of a crash, the journal can be replayed, bringing both data and
 metadata into a consistent state.  This mode is the slowest except when data
 needs to be read from and written to disk at the same time where it
-outperforms all others modes.  Curently ext4 does not have delayed
+outperforms all others modes.  Currently ext4 does not have delayed
 allocation support if this data journalling mode is selected.
 
 References
index 1e3defcfe50b2eafd9f6ac0fcf6f624bca3da43b..606233cd4618991a50847d45e19b2bd75cf7b0dc 100644 (file)
@@ -204,7 +204,7 @@ fiemap_check_flags() helper:
 
 int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags);
 
-The struct fieinfo should be passed in as recieved from ioctl_fiemap(). The
+The struct fieinfo should be passed in as received from ioctl_fiemap(). The
 set of fiemap flags which the fs understands should be passed via fs_flags. If
 fiemap_check_flags finds invalid user flags, it will place the bad values in
 fieinfo->fi_flags and return -EBADR. If the file system gets -EBADR, from
index 85eaeaddd27c3eddcce4f3e9301e178f90cbb620..e386f7e4bcee1e4c8d5b0f08872c877097e6f9f9 100644 (file)
@@ -100,7 +100,7 @@ Installation
     $ sudo cp utils/mount/mount.nfs /sbin/mount.nfs
 
     In this location, mount.nfs will be invoked automatically for NFS mounts
-    by the system mount commmand.
+    by the system mount command.
 
     NOTE: mount.nfs and therefore nfs-utils-1.1.2 or greater is only needed
     on the NFS client machine. You do not need this specific version of
index ce84cfc9eae0a923f7aca7ae1e03797a7a7bea7e..cd8717a362712fbb537bf562eaa95b0be778dd3b 100644 (file)
@@ -366,7 +366,7 @@ just those considered 'most important'.  The new vectors are:
   RES, CAL, TLB -- rescheduling, call and TLB flush interrupts are
   sent from one CPU to another per the needs of the OS.  Typically,
   their statistics are used by kernel developers and interested users to
-  determine the occurance of interrupt of the given type.
+  determine the occurrence of interrupts of the given type.
 
 The above IRQ vectors are displayed only when relevent.  For example,
 the threshold vector does not exist on x86_64 platforms.  Others are
@@ -551,7 +551,7 @@ Committed_AS: The amount of memory presently allocated on the system.
               memory once that memory has been successfully allocated.
 VmallocTotal: total size of vmalloc memory area
  VmallocUsed: amount of vmalloc area which is used
-VmallocChunk: largest contigious block of vmalloc area which is free
+VmallocChunk: largest contiguous block of vmalloc area which is free
 
 ..............................................................................
 
index 26e4b8bc53ee097b0660650b83d276751855b1ea..85354b32d731cc409dfcc082c30277fefdf11850 100644 (file)
@@ -72,7 +72,7 @@ The 'rom' file is special in that it provides read-only access to the device's
 ROM file, if available.  It's disabled by default, however, so applications
 should write the string "1" to the file to enable it before attempting a read
 call, and disable it following the access by writing "0" to the file.  Note
-that the device must be enabled for a rom read to return data succesfully.
+that the device must be enabled for a rom read to return data successfully.
 In the event a driver is not bound to the device, it can be enabled using the
 'enable' file, documented above.
 
index 3a5ddc96901a665e3801d8ebf80c817e2efb5fc2..5147be5e13cd6376c9dac99cad8ffc186a201ab1 100644 (file)
@@ -124,10 +124,10 @@ sys_immutable -- If set, ATTR_SYS attribute on FAT is handled as
 flush         -- If set, the filesystem will try to flush to disk more
                 early than normal. Not set by default.
 
-rodir        -- FAT has the ATTR_RO (read-only) attribute. But on Windows,
-                the ATTR_RO of the directory will be just ignored actually,
-                and is used by only applications as flag. E.g. it's setted
-                for the customized folder.
+rodir        -- FAT has the ATTR_RO (read-only) attribute. On Windows,
+                the ATTR_RO of the directory will just be ignored,
+                and is used only by applications as a flag (e.g. it's set
+                for the customized folder).
 
                 If you want to use ATTR_RO as read-only flag even for
                 the directory, set this option.
index 145c25a170c7abf6e0e489fba4c00b4784759dca..e4b6985044a263249976cc0ca985529555007462 100644 (file)
@@ -458,7 +458,7 @@ debugfs interface, since it provides control over GPIO direction and
 value instead of just showing a gpio state summary.  Plus, it could be
 present on production systems without debugging support.
 
-Given approprate hardware documentation for the system, userspace could
+Given appropriate hardware documentation for the system, userspace could
 know for example that GPIO #23 controls the write protect line used to
 protect boot loader segments in flash memory.  System upgrade procedures
 may need to temporarily remove that protection, first importing a GPIO,
index cfcebb10d14edb0e70af97d2b4ec0df4378eed05..c269aaa2f26a1aefde7bf60a069d9f544c13c009 100644 (file)
@@ -20,6 +20,8 @@ platform_device with the base address and interrupt number. The
 dev.platform_data of the device should also point to a struct
 ocores_i2c_platform_data (see linux/i2c-ocores.h) describing the
 distance between registers and the input clock speed.
+There is also a possibility to attach a list of i2c_board_info which
+the i2c-ocores driver will add to the bus upon creation.
 
 E.G. something like:
 
@@ -36,9 +38,24 @@ static struct resource ocores_resources[] = {
        },
 };
 
+/* optional board info */
+struct i2c_board_info ocores_i2c_board_info[] = {
+       {
+               I2C_BOARD_INFO("tsc2003", 0x48),
+               .platform_data = &tsc2003_platform_data,
+               .irq = TSC_IRQ
+       },
+       {
+               I2C_BOARD_INFO("adv7180", 0x42 >> 1),
+               .irq = ADV_IRQ
+       }
+};
+
 static struct ocores_i2c_platform_data myi2c_data = {
        .regstep        = 2,            /* two bytes between registers */
        .clock_khz      = 50000,        /* input clock of 50MHz */
+       .devices        = ocores_i2c_board_info, /* optional table of devices */
+       .num_devices    = ARRAY_SIZE(ocores_i2c_board_info), /* table size */
 };
 
 static struct platform_device myi2c = {
index 0c78f4b1d9d9f1df5298e9147c058a32aee90353..e77bebfa7b0d9b7cd459050970581034281538ee 100644 (file)
@@ -216,6 +216,8 @@ Other kernel parameters for ide_core are:
 
 * "noflush=[interface_number.device_number]" to disable flush requests
 
+* "nohpa=[interface_number.device_number]" to disable Host Protected Area
+
 * "noprobe=[interface_number.device_number]" to skip probing
 
 * "nowerr=[interface_number.device_number]" to ignore the WRERR_STAT bit
index 26a7c0a93193065256d388eaf25731080a898743..849b5e56d06fc95927f47aaa8b006cfb73cf34c6 100644 (file)
@@ -35,48 +35,26 @@ new .config files to see the differences:
 
 (Yes, we need something better here.)
 
-
-======================================================================
-menuconfig
---------------------------------------------------
-
-SEARCHING for CONFIG symbols
-
-Searching in menuconfig:
-
-       The Search function searches for kernel configuration symbol
-       names, so you have to know something close to what you are
-       looking for.
-
-       Example:
-               /hotplug
-               This lists all config symbols that contain "hotplug",
-               e.g., HOTPLUG, HOTPLUG_CPU, MEMORY_HOTPLUG.
-
-       For search help, enter / followed TAB-TAB-TAB (to highlight
-       <Help>) and Enter.  This will tell you that you can also use
-       regular expressions (regexes) in the search string, so if you
-       are not interested in MEMORY_HOTPLUG, you could try
-
-               /^hotplug
-
-
 ______________________________________________________________________
-Color Themes for 'menuconfig'
+Environment variables for '*config'
 
-It is possible to select different color themes using the variable
-MENUCONFIG_COLOR.  To select a theme use:
+KCONFIG_CONFIG
+--------------------------------------------------
+This environment variable can be used to specify a default kernel config
+file name to override the default name of ".config".
 
-       make MENUCONFIG_COLOR=<theme> menuconfig
+KCONFIG_OVERWRITECONFIG
+--------------------------------------------------
+If you set KCONFIG_OVERWRITECONFIG in the environment, Kconfig will not
+break symlinks when .config is a symlink to somewhere else.
 
-Available themes are:
-  mono       => selects colors suitable for monochrome displays
-  blackbg    => selects a color scheme with black background
-  classic    => theme with blue background. The classic look
-  bluetitle  => a LCD friendly version of classic. (default)
+KCONFIG_NOTIMESTAMP
+--------------------------------------------------
+If this environment variable exists and is non-null, the timestamp line
+in generated .config files is omitted.
 
 ______________________________________________________________________
-Environment variables in 'menuconfig'
+Environment variables for '{allyes/allmod/allno/rand}config'
 
 KCONFIG_ALLCONFIG
 --------------------------------------------------
@@ -95,8 +73,7 @@ values.
 This enables you to create "miniature" config (miniconfig) or custom
 config files containing just the config symbols that you are interested
 in.  Then the kernel config system generates the full .config file,
-including dependencies of your miniconfig file, based on the miniconfig
-file.
+including symbols of your miniconfig file.
 
 This 'KCONFIG_ALLCONFIG' file is a config file which contains
 (usually a subset of all) preset config symbols.  These variable
@@ -113,26 +90,14 @@ These examples will disable most options (allnoconfig) but enable or
 disable the options that are explicitly listed in the specified
 mini-config files.
 
+______________________________________________________________________
+Environment variables for 'silentoldconfig'
+
 KCONFIG_NOSILENTUPDATE
 --------------------------------------------------
 If this variable has a non-blank value, it prevents silent kernel
 config udpates (requires explicit updates).
 
-KCONFIG_CONFIG
---------------------------------------------------
-This environment variable can be used to specify a default kernel config
-file name to override the default name of ".config".
-
-KCONFIG_OVERWRITECONFIG
---------------------------------------------------
-If you set KCONFIG_OVERWRITECONFIG in the environment, Kconfig will not
-break symlinks when .config is a symlink to somewhere else.
-
-KCONFIG_NOTIMESTAMP
---------------------------------------------------
-If this environment variable exists and is non-null, the timestamp line
-in generated .config files is omitted.
-
 KCONFIG_AUTOCONFIG
 --------------------------------------------------
 This environment variable can be set to specify the path & name of the
@@ -143,15 +108,54 @@ KCONFIG_AUTOHEADER
 This environment variable can be set to specify the path & name of the
 "autoconf.h" (header) file.  Its default value is "include/linux/autoconf.h".
 
+
+======================================================================
+menuconfig
+--------------------------------------------------
+
+SEARCHING for CONFIG symbols
+
+Searching in menuconfig:
+
+       The Search function searches for kernel configuration symbol
+       names, so you have to know something close to what you are
+       looking for.
+
+       Example:
+               /hotplug
+               This lists all config symbols that contain "hotplug",
+               e.g., HOTPLUG, HOTPLUG_CPU, MEMORY_HOTPLUG.
+
+       For search help, enter / followed TAB-TAB-TAB (to highlight
+       <Help>) and Enter.  This will tell you that you can also use
+       regular expressions (regexes) in the search string, so if you
+       are not interested in MEMORY_HOTPLUG, you could try
+
+               /^hotplug
+
 ______________________________________________________________________
-menuconfig User Interface Options
-----------------------------------------------------------------------
+User interface options for 'menuconfig'
+
+MENUCONFIG_COLOR
+--------------------------------------------------
+It is possible to select different color themes using the variable
+MENUCONFIG_COLOR.  To select a theme use:
+
+       make MENUCONFIG_COLOR=<theme> menuconfig
+
+Available themes are:
+  mono       => selects colors suitable for monochrome displays
+  blackbg    => selects a color scheme with black background
+  classic    => theme with blue background. The classic look
+  bluetitle  => a LCD friendly version of classic. (default)
+
 MENUCONFIG_MODE
 --------------------------------------------------
 This mode shows all sub-menus in one large tree.
 
 Example:
-       MENUCONFIG_MODE=single_menu make menuconfig
+       make MENUCONFIG_MODE=single_menu menuconfig
+
 
 ======================================================================
 xconfig
index b1096da953c8a9c5105686b7702bde502113b3d1..0767cf69c69ea9b1d0cd809460931b9a203a6b23 100644 (file)
@@ -275,7 +275,7 @@ following files:
 
                KERNELDIR := /lib/modules/`uname -r`/build
                all::
-                       $(MAKE) -C $KERNELDIR M=`pwd` $@
+                       $(MAKE) -C $(KERNELDIR) M=`pwd` $@
 
                # Module specific targets
                genbin:
index 3f4bc840da8b7c068076dd057216e846e098db9f..cab61d84225977e68b421701bc2c2cac5758bceb 100644 (file)
@@ -108,7 +108,7 @@ There are two possible methods of using Kdump.
 
 2) Or use the system kernel binary itself as dump-capture kernel and there is
    no need to build a separate dump-capture kernel. This is possible
-   only with the architecutres which support a relocatable kernel. As
+   only with the architectures which support a relocatable kernel. As
    of today, i386, x86_64, ppc64 and ia64 architectures support relocatable
    kernel.
 
@@ -222,7 +222,7 @@ Dump-capture kernel config options (Arch Dependent, ia64)
 ----------------------------------------------------------
 
 - No specific options are required to create a dump-capture kernel
-  for ia64, other than those specified in the arch idependent section
+  for ia64, other than those specified in the arch independent section
   above. This means that it is possible to use the system kernel
   as a dump-capture kernel if desired.
 
index 7bcdebffdab3850d9d3471a2f3ca5ea3b1f0b32a..5f66ba295c5d376599e6942b4f917ad38d9dab9e 100644 (file)
@@ -887,11 +887,8 @@ and is between 256 and 4096 characters. It is defined in the file
 
        ide-core.nodma= [HW] (E)IDE subsystem
                        Format: =0.0 to prevent dma on hda, =0.1 hdb =1.0 hdc
-                       .vlb_clock .pci_clock .noflush .noprobe .nowerr .cdrom
-                       .chs .ignore_cable are additional options
-                       See Documentation/ide/ide.txt.
-
-       idebus=         [HW] (E)IDE subsystem - VLB/PCI bus speed
+                       .vlb_clock .pci_clock .noflush .nohpa .noprobe .nowerr
+                       .cdrom .chs .ignore_cable are additional options
                        See Documentation/ide/ide.txt.
 
        ide-pci-generic.all-generic-ide [HW] (E)IDE subsystem
@@ -1076,7 +1073,7 @@ and is between 256 and 4096 characters. It is defined in the file
 
        kgdboc=         [HW] kgdb over consoles.
                        Requires a tty driver that supports console polling.
-                       (only serial suported for now)
+                       (only serial supported for now)
                        Format: <serial_device>[,baud]
 
        kmac=           [MIPS] korina ethernet MAC address.
@@ -1405,7 +1402,7 @@ and is between 256 and 4096 characters. It is defined in the file
                        ('y', default) or cooked coordinates ('n')
 
        mtrr_chunk_size=nn[KMG] [X86]
-                       used for mtrr cleanup. It is largest continous chunk
+                       used for mtrr cleanup. It is largest continuous chunk
                        that could hold holes aka. UC entries.
 
        mtrr_gran_size=nn[KMG] [X86]
index b2e374586bd8627719167011a992ec3eb81a1c96..c79ab996dadaea7a6e630fd9326c6a1b5adfd86e 100644 (file)
@@ -132,7 +132,7 @@ kobject_name():
     const char *kobject_name(const struct kobject * kobj);
 
 There is a helper function to both initialize and add the kobject to the
-kernel at the same time, called supprisingly enough kobject_init_and_add():
+kernel at the same time, called surprisingly enough kobject_init_and_add():
 
     int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
                              struct kobject *parent, const char *fmt, ...);
index 5ee2a02b3b40977623c88c8c08a1b877d5b2621b..0768fcc3ba3e58966cb73b7c104b2a84f3c2c279 100644 (file)
@@ -40,7 +40,7 @@ NOTE: The Acer Aspire One is not supported hardware. It cannot work with
 acer-wmi until Acer fix their ACPI-WMI implementation on them, so has been
 blacklisted until that happens.
 
-Please see the website for the current list of known working hardare:
+Please see the website for the current list of known working hardware:
 
 http://code.google.com/p/aceracpi/wiki/SupportedHardware
 
index 8b2bc1572d98eae5fe8e2c78dd0be77bee1d9326..23ce7d350d1abad3b19a382830dd4741ad3b2be9 100644 (file)
@@ -22,7 +22,7 @@ If your laptop model supports it, you will find sysfs files in the
 /sys/class/backlight/sony/
 directory. You will be able to query and set the current screen
 brightness:
-       brightness              get/set screen brightness (an iteger
+       brightness              get/set screen brightness (an integer
                                between 0 and 7)
        actual_brightness       reading from this file will query the HW
                                to get real brightness value
index e7e9a69069e13f82dba072430ceb887f2e415384..78e354b42f6785cd07a0e12b56b482fde4b8d10b 100644 (file)
@@ -506,7 +506,7 @@ generate input device EV_KEY events.
 In addition to the EV_KEY events, thinkpad-acpi may also issue EV_SW
 events for switches:
 
-SW_RFKILL_ALL  T60 and later hardare rfkill rocker switch
+SW_RFKILL_ALL  T60 and later hardware rfkill rocker switch
 SW_TABLET_MODE Tablet ThinkPads HKEY events 0x5009 and 0x500A
 
 Non hot-key ACPI HKEY event map:
index 1f4f9e888bd1ab0ae834bb1a87ccfcf6ed26c6de..28c8cdfcafd8693898ae4c4a4d9bc5f4f9f77d62 100644 (file)
@@ -1,6 +1,5 @@
 # This creates the demonstration utility "lguest" which runs a Linux guest.
-CFLAGS:=-Wall -Wmissing-declarations -Wmissing-prototypes -O3 -I../../include -I../../arch/x86/include -U_FORTIFY_SOURCE
-LDLIBS:=-lz
+CFLAGS:=-m32 -Wall -Wmissing-declarations -Wmissing-prototypes -O3 -I../../include -I../../arch/x86/include -U_FORTIFY_SOURCE
 
 all: lguest
 
index d36fcc0f2715c705d0f70d1aa9c13e20b8aaa917..9ebcd6ef361b565fc331bd09c202866f403fcf99 100644 (file)
@@ -16,6 +16,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
+#include <sys/eventfd.h>
 #include <fcntl.h>
 #include <stdbool.h>
 #include <errno.h>
@@ -59,7 +60,6 @@ typedef uint8_t u8;
 /*:*/
 
 #define PAGE_PRESENT 0x7       /* Present, RW, Execute */
-#define NET_PEERNUM 1
 #define BRIDGE_PFX "bridge:"
 #ifndef SIOCBRADDIF
 #define SIOCBRADDIF    0x89a2          /* add interface to bridge      */
@@ -76,19 +76,12 @@ static bool verbose;
        do { if (verbose) printf(args); } while(0)
 /*:*/
 
-/* File descriptors for the Waker. */
-struct {
-       int pipe[2];
-       int lguest_fd;
-} waker_fds;
-
 /* The pointer to the start of guest memory. */
 static void *guest_base;
 /* The maximum guest physical address allowed, and maximum possible. */
 static unsigned long guest_limit, guest_max;
-/* The pipe for signal hander to write to. */
-static int timeoutpipe[2];
-static unsigned int timeout_usec = 500;
+/* The /dev/lguest file descriptor. */
+static int lguest_fd;
 
 /* a per-cpu variable indicating whose vcpu is currently running */
 static unsigned int __thread cpu_id;
@@ -96,11 +89,6 @@ static unsigned int __thread cpu_id;
 /* This is our list of devices. */
 struct device_list
 {
-       /* Summary information about the devices in our list: ready to pass to
-        * select() to ask which need servicing.*/
-       fd_set infds;
-       int max_infd;
-
        /* Counter to assign interrupt numbers. */
        unsigned int next_irq;
 
@@ -126,22 +114,21 @@ struct device
        /* The linked-list pointer. */
        struct device *next;
 
-       /* The this device's descriptor, as mapped into the Guest. */
+       /* The device's descriptor, as mapped into the Guest. */
        struct lguest_device_desc *desc;
 
+       /* We can't trust desc values once Guest has booted: we use these. */
+       unsigned int feature_len;
+       unsigned int num_vq;
+
        /* The name of this device, for --verbose. */
        const char *name;
 
-       /* If handle_input is set, it wants to be called when this file
-        * descriptor is ready. */
-       int fd;
-       bool (*handle_input)(int fd, struct device *me);
-
        /* Any queues attached to this device */
        struct virtqueue *vq;
 
-       /* Handle status being finalized (ie. feature bits stable). */
-       void (*ready)(struct device *me);
+       /* Is it operational */
+       bool running;
 
        /* Device-specific data. */
        void *priv;
@@ -164,22 +151,28 @@ struct virtqueue
        /* Last available index we saw. */
        u16 last_avail_idx;
 
-       /* The routine to call when the Guest pings us, or timeout. */
-       void (*handle_output)(int fd, struct virtqueue *me, bool timeout);
+       /* How many are used since we sent last irq? */
+       unsigned int pending_used;
 
-       /* Outstanding buffers */
-       unsigned int inflight;
+       /* Eventfd where Guest notifications arrive. */
+       int eventfd;
 
-       /* Is this blocked awaiting a timer? */
-       bool blocked;
+       /* Function for the thread which is servicing this virtqueue. */
+       void (*service)(struct virtqueue *vq);
+       pid_t thread;
 };
 
 /* Remember the arguments to the program so we can "reboot" */
 static char **main_args;
 
-/* Since guest is UP and we don't run at the same time, we don't need barriers.
- * But I include them in the code in case others copy it. */
-#define wmb()
+/* The original tty settings to restore on exit. */
+static struct termios orig_term;
+
+/* We have to be careful with barriers: our devices are all run in separate
+ * threads and so we need to make sure that changes visible to the Guest happen
+ * in precise order. */
+#define wmb() __asm__ __volatile__("" : : : "memory")
+#define mb() __asm__ __volatile__("" : : : "memory")
 
 /* Convert an iovec element to the given type.
  *
@@ -245,7 +238,7 @@ static void iov_consume(struct iovec iov[], unsigned num_iov, unsigned len)
 static u8 *get_feature_bits(struct device *dev)
 {
        return (u8 *)(dev->desc + 1)
-               + dev->desc->num_vq * sizeof(struct lguest_vqconfig);
+               + dev->num_vq * sizeof(struct lguest_vqconfig);
 }
 
 /*L:100 The Launcher code itself takes us out into userspace, that scary place
@@ -505,99 +498,19 @@ static void concat(char *dst, char *args[])
  * saw the arguments it expects when we looked at initialize() in lguest_user.c:
  * the base of Guest "physical" memory, the top physical page to allow and the
  * entry point for the Guest. */
-static int tell_kernel(unsigned long start)
+static void tell_kernel(unsigned long start)
 {
        unsigned long args[] = { LHREQ_INITIALIZE,
                                 (unsigned long)guest_base,
                                 guest_limit / getpagesize(), start };
-       int fd;
-
        verbose("Guest: %p - %p (%#lx)\n",
                guest_base, guest_base + guest_limit, guest_limit);
-       fd = open_or_die("/dev/lguest", O_RDWR);
-       if (write(fd, args, sizeof(args)) < 0)
+       lguest_fd = open_or_die("/dev/lguest", O_RDWR);
+       if (write(lguest_fd, args, sizeof(args)) < 0)
                err(1, "Writing to /dev/lguest");
-
-       /* We return the /dev/lguest file descriptor to control this Guest */
-       return fd;
 }
 /*:*/
 
-static void add_device_fd(int fd)
-{
-       FD_SET(fd, &devices.infds);
-       if (fd > devices.max_infd)
-               devices.max_infd = fd;
-}
-
-/*L:200
- * The Waker.
- *
- * With console, block and network devices, we can have lots of input which we
- * need to process.  We could try to tell the kernel what file descriptors to
- * watch, but handing a file descriptor mask through to the kernel is fairly
- * icky.
- *
- * Instead, we clone off a thread which watches the file descriptors and writes
- * the LHREQ_BREAK command to the /dev/lguest file descriptor to tell the Host
- * stop running the Guest.  This causes the Launcher to return from the
- * /dev/lguest read with -EAGAIN, where it will write to /dev/lguest to reset
- * the LHREQ_BREAK and wake us up again.
- *
- * This, of course, is merely a different *kind* of icky.
- *
- * Given my well-known antipathy to threads, I'd prefer to use processes.  But
- * it's easier to share Guest memory with threads, and trivial to share the
- * devices.infds as the Launcher changes it.
- */
-static int waker(void *unused)
-{
-       /* Close the write end of the pipe: only the Launcher has it open. */
-       close(waker_fds.pipe[1]);
-
-       for (;;) {
-               fd_set rfds = devices.infds;
-               unsigned long args[] = { LHREQ_BREAK, 1 };
-               unsigned int maxfd = devices.max_infd;
-
-               /* We also listen to the pipe from the Launcher. */
-               FD_SET(waker_fds.pipe[0], &rfds);
-               if (waker_fds.pipe[0] > maxfd)
-                       maxfd = waker_fds.pipe[0];
-
-               /* Wait until input is ready from one of the devices. */
-               select(maxfd+1, &rfds, NULL, NULL, NULL);
-
-               /* Message from Launcher? */
-               if (FD_ISSET(waker_fds.pipe[0], &rfds)) {
-                       char c;
-                       /* If this fails, then assume Launcher has exited.
-                        * Don't do anything on exit: we're just a thread! */
-                       if (read(waker_fds.pipe[0], &c, 1) != 1)
-                               _exit(0);
-                       continue;
-               }
-
-               /* Send LHREQ_BREAK command to snap the Launcher out of it. */
-               pwrite(waker_fds.lguest_fd, args, sizeof(args), cpu_id);
-       }
-       return 0;
-}
-
-/* This routine just sets up a pipe to the Waker process. */
-static void setup_waker(int lguest_fd)
-{
-       /* This pipe is closed when Launcher dies, telling Waker. */
-       if (pipe(waker_fds.pipe) != 0)
-               err(1, "Creating pipe for Waker");
-
-       /* Waker also needs to know the lguest fd */
-       waker_fds.lguest_fd = lguest_fd;
-
-       if (clone(waker, malloc(4096) + 4096, CLONE_VM | SIGCHLD, NULL) == -1)
-               err(1, "Creating Waker");
-}
-
 /*
  * Device Handling.
  *
@@ -623,49 +536,90 @@ static void *_check_pointer(unsigned long addr, unsigned int size,
 /* Each buffer in the virtqueues is actually a chain of descriptors.  This
  * function returns the next descriptor in the chain, or vq->vring.num if we're
  * at the end. */
-static unsigned next_desc(struct virtqueue *vq, unsigned int i)
+static unsigned next_desc(struct vring_desc *desc,
+                         unsigned int i, unsigned int max)
 {
        unsigned int next;
 
        /* If this descriptor says it doesn't chain, we're done. */
-       if (!(vq->vring.desc[i].flags & VRING_DESC_F_NEXT))
-               return vq->vring.num;
+       if (!(desc[i].flags & VRING_DESC_F_NEXT))
+               return max;
 
        /* Check they're not leading us off end of descriptors. */
-       next = vq->vring.desc[i].next;
+       next = desc[i].next;
        /* Make sure compiler knows to grab that: we don't want it changing! */
        wmb();
 
-       if (next >= vq->vring.num)
+       if (next >= max)
                errx(1, "Desc next is %u", next);
 
        return next;
 }
 
+/* This actually sends the interrupt for this virtqueue */
+static void trigger_irq(struct virtqueue *vq)
+{
+       unsigned long buf[] = { LHREQ_IRQ, vq->config.irq };
+
+       /* Don't inform them if nothing used. */
+       if (!vq->pending_used)
+               return;
+       vq->pending_used = 0;
+
+       /* If they don't want an interrupt, don't send one, unless empty. */
+       if ((vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)
+           && lg_last_avail(vq) != vq->vring.avail->idx)
+               return;
+
+       /* Send the Guest an interrupt tell them we used something up. */
+       if (write(lguest_fd, buf, sizeof(buf)) != 0)
+               err(1, "Triggering irq %i", vq->config.irq);
+}
+
 /* This looks in the virtqueue and for the first available buffer, and converts
  * it to an iovec for convenient access.  Since descriptors consist of some
  * number of output then some number of input descriptors, it's actually two
  * iovecs, but we pack them into one and note how many of each there were.
  *
- * This function returns the descriptor number found, or vq->vring.num (which
- * is never a valid descriptor number) if none was found. */
-static unsigned get_vq_desc(struct virtqueue *vq,
-                           struct iovec iov[],
-                           unsigned int *out_num, unsigned int *in_num)
+ * This function returns the descriptor number found. */
+static unsigned wait_for_vq_desc(struct virtqueue *vq,
+                                struct iovec iov[],
+                                unsigned int *out_num, unsigned int *in_num)
 {
-       unsigned int i, head;
-       u16 last_avail;
+       unsigned int i, head, max;
+       struct vring_desc *desc;
+       u16 last_avail = lg_last_avail(vq);
+
+       while (last_avail == vq->vring.avail->idx) {
+               u64 event;
+
+               /* OK, tell Guest about progress up to now. */
+               trigger_irq(vq);
+
+               /* OK, now we need to know about added descriptors. */
+               vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY;
+
+               /* They could have slipped one in as we were doing that: make
+                * sure it's written, then check again. */
+               mb();
+               if (last_avail != vq->vring.avail->idx) {
+                       vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY;
+                       break;
+               }
+
+               /* Nothing new?  Wait for eventfd to tell us they refilled. */
+               if (read(vq->eventfd, &event, sizeof(event)) != sizeof(event))
+                       errx(1, "Event read failed?");
+
+               /* We don't need to be notified again. */
+               vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY;
+       }
 
        /* Check it isn't doing very strange things with descriptor numbers. */
-       last_avail = lg_last_avail(vq);
        if ((u16)(vq->vring.avail->idx - last_avail) > vq->vring.num)
                errx(1, "Guest moved used index from %u to %u",
                     last_avail, vq->vring.avail->idx);
 
-       /* If there's nothing new since last we looked, return invalid. */
-       if (vq->vring.avail->idx == last_avail)
-               return vq->vring.num;
-
        /* Grab the next descriptor number they're advertising, and increment
         * the index we've seen. */
        head = vq->vring.avail->ring[last_avail % vq->vring.num];
@@ -678,15 +632,28 @@ static unsigned get_vq_desc(struct virtqueue *vq,
        /* When we start there are none of either input nor output. */
        *out_num = *in_num = 0;
 
+       max = vq->vring.num;
+       desc = vq->vring.desc;
        i = head;
+
+       /* If this is an indirect entry, then this buffer contains a descriptor
+        * table which we handle as if it's any normal descriptor chain. */
+       if (desc[i].flags & VRING_DESC_F_INDIRECT) {
+               if (desc[i].len % sizeof(struct vring_desc))
+                       errx(1, "Invalid size for indirect buffer table");
+
+               max = desc[i].len / sizeof(struct vring_desc);
+               desc = check_pointer(desc[i].addr, desc[i].len);
+               i = 0;
+       }
+
        do {
                /* Grab the first descriptor, and check it's OK. */
-               iov[*out_num + *in_num].iov_len = vq->vring.desc[i].len;
+               iov[*out_num + *in_num].iov_len = desc[i].len;
                iov[*out_num + *in_num].iov_base
-                       = check_pointer(vq->vring.desc[i].addr,
-                                       vq->vring.desc[i].len);
+                       = check_pointer(desc[i].addr, desc[i].len);
                /* If this is an input descriptor, increment that count. */
-               if (vq->vring.desc[i].flags & VRING_DESC_F_WRITE)
+               if (desc[i].flags & VRING_DESC_F_WRITE)
                        (*in_num)++;
                else {
                        /* If it's an output descriptor, they're all supposed
@@ -697,11 +664,10 @@ static unsigned get_vq_desc(struct virtqueue *vq,
                }
 
                /* If we've got too many, that implies a descriptor loop. */
-               if (*out_num + *in_num > vq->vring.num)
+               if (*out_num + *in_num > max)
                        errx(1, "Looped descriptor");
-       } while ((i = next_desc(vq, i)) != vq->vring.num);
+       } while ((i = next_desc(desc, i, max)) != max);
 
-       vq->inflight++;
        return head;
 }
 
@@ -719,44 +685,20 @@ static void add_used(struct virtqueue *vq, unsigned int head, int len)
        /* Make sure buffer is written before we update index. */
        wmb();
        vq->vring.used->idx++;
-       vq->inflight--;
-}
-
-/* This actually sends the interrupt for this virtqueue */
-static void trigger_irq(int fd, struct virtqueue *vq)
-{
-       unsigned long buf[] = { LHREQ_IRQ, vq->config.irq };
-
-       /* If they don't want an interrupt, don't send one, unless empty. */
-       if ((vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)
-           && vq->inflight)
-               return;
-
-       /* Send the Guest an interrupt tell them we used something up. */
-       if (write(fd, buf, sizeof(buf)) != 0)
-               err(1, "Triggering irq %i", vq->config.irq);
+       vq->pending_used++;
 }
 
 /* And here's the combo meal deal.  Supersize me! */
-static void add_used_and_trigger(int fd, struct virtqueue *vq,
-                                unsigned int head, int len)
+static void add_used_and_trigger(struct virtqueue *vq, unsigned head, int len)
 {
        add_used(vq, head, len);
-       trigger_irq(fd, vq);
+       trigger_irq(vq);
 }
 
 /*
  * The Console
  *
- * Here is the input terminal setting we save, and the routine to restore them
- * on exit so the user gets their terminal back. */
-static struct termios orig_term;
-static void restore_term(void)
-{
-       tcsetattr(STDIN_FILENO, TCSANOW, &orig_term);
-}
-
-/* We associate some data with the console for our exit hack. */
+ * We associate some data with the console for our exit hack. */
 struct console_abort
 {
        /* How many times have they hit ^C? */
@@ -766,276 +708,275 @@ struct console_abort
 };
 
 /* This is the routine which handles console input (ie. stdin). */
-static bool handle_console_input(int fd, struct device *dev)
+static void console_input(struct virtqueue *vq)
 {
        int len;
        unsigned int head, in_num, out_num;
-       struct iovec iov[dev->vq->vring.num];
-       struct console_abort *abort = dev->priv;
-
-       /* First we need a console buffer from the Guests's input virtqueue. */
-       head = get_vq_desc(dev->vq, iov, &out_num, &in_num);
-
-       /* If they're not ready for input, stop listening to this file
-        * descriptor.  We'll start again once they add an input buffer. */
-       if (head == dev->vq->vring.num)
-               return false;
+       struct console_abort *abort = vq->dev->priv;
+       struct iovec iov[vq->vring.num];
 
+       /* Make sure there's a descriptor waiting. */
+       head = wait_for_vq_desc(vq, iov, &out_num, &in_num);
        if (out_num)
                errx(1, "Output buffers in console in queue?");
 
-       /* This is why we convert to iovecs: the readv() call uses them, and so
-        * it reads straight into the Guest's buffer. */
-       len = readv(dev->fd, iov, in_num);
+       /* Read it in. */
+       len = readv(STDIN_FILENO, iov, in_num);
        if (len <= 0) {
-               /* This implies that the console is closed, is /dev/null, or
-                * something went terribly wrong. */
+               /* Ran out of input? */
                warnx("Failed to get console input, ignoring console.");
-               /* Put the input terminal back. */
-               restore_term();
-               /* Remove callback from input vq, so it doesn't restart us. */
-               dev->vq->handle_output = NULL;
-               /* Stop listening to this fd: don't call us again. */
-               return false;
+               /* For simplicity, dying threads kill the whole Launcher.  So
+                * just nap here. */
+               for (;;)
+                       pause();
        }
 
-       /* Tell the Guest about the new input. */
-       add_used_and_trigger(fd, dev->vq, head, len);
+       add_used_and_trigger(vq, head, len);
 
        /* Three ^C within one second?  Exit.
         *
-        * This is such a hack, but works surprisingly well.  Each ^C has to be
-        * in a buffer by itself, so they can't be too fast.  But we check that
-        * we get three within about a second, so they can't be too slow. */
-       if (len == 1 && ((char *)iov[0].iov_base)[0] == 3) {
-               if (!abort->count++)
-                       gettimeofday(&abort->start, NULL);
-               else if (abort->count == 3) {
-                       struct timeval now;
-                       gettimeofday(&now, NULL);
-                       if (now.tv_sec <= abort->start.tv_sec+1) {
-                               unsigned long args[] = { LHREQ_BREAK, 0 };
-                               /* Close the fd so Waker will know it has to
-                                * exit. */
-                               close(waker_fds.pipe[1]);
-                               /* Just in case Waker is blocked in BREAK, send
-                                * unbreak now. */
-                               write(fd, args, sizeof(args));
-                               exit(2);
-                       }
-                       abort->count = 0;
-               }
-       } else
-               /* Any other key resets the abort counter. */
+        * This is such a hack, but works surprisingly well.  Each ^C has to
+        * be in a buffer by itself, so they can't be too fast.  But we check
+        * that we get three within about a second, so they can't be too
+        * slow. */
+       if (len != 1 || ((char *)iov[0].iov_base)[0] != 3) {
                abort->count = 0;
+               return;
+       }
 
-       /* Everything went OK! */
-       return true;
+       abort->count++;
+       if (abort->count == 1)
+               gettimeofday(&abort->start, NULL);
+       else if (abort->count == 3) {
+               struct timeval now;
+               gettimeofday(&now, NULL);
+               /* Kill all Launcher processes with SIGINT, like normal ^C */
+               if (now.tv_sec <= abort->start.tv_sec+1)
+                       kill(0, SIGINT);
+               abort->count = 0;
+       }
 }
 
-/* Handling output for console is simple: we just get all the output buffers
- * and write them to stdout. */
-static void handle_console_output(int fd, struct virtqueue *vq, bool timeout)
+/* This is the routine which handles console output (ie. stdout). */
+static void console_output(struct virtqueue *vq)
 {
        unsigned int head, out, in;
-       int len;
        struct iovec iov[vq->vring.num];
 
-       /* Keep getting output buffers from the Guest until we run out. */
-       while ((head = get_vq_desc(vq, iov, &out, &in)) != vq->vring.num) {
-               if (in)
-                       errx(1, "Input buffers in output queue?");
-               len = writev(STDOUT_FILENO, iov, out);
-               add_used_and_trigger(fd, vq, head, len);
+       head = wait_for_vq_desc(vq, iov, &out, &in);
+       if (in)
+               errx(1, "Input buffers in console output queue?");
+       while (!iov_empty(iov, out)) {
+               int len = writev(STDOUT_FILENO, iov, out);
+               if (len <= 0)
+                       err(1, "Write to stdout gave %i", len);
+               iov_consume(iov, out, len);
        }
-}
-
-/* This is called when we no longer want to hear about Guest changes to a
- * virtqueue.  This is more efficient in high-traffic cases, but it means we
- * have to set a timer to check if any more changes have occurred. */
-static void block_vq(struct virtqueue *vq)
-{
-       struct itimerval itm;
-
-       vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY;
-       vq->blocked = true;
-
-       itm.it_interval.tv_sec = 0;
-       itm.it_interval.tv_usec = 0;
-       itm.it_value.tv_sec = 0;
-       itm.it_value.tv_usec = timeout_usec;
-
-       setitimer(ITIMER_REAL, &itm, NULL);
+       add_used(vq, head, 0);
 }
 
 /*
  * The Network
  *
  * Handling output for network is also simple: we get all the output buffers
- * and write them (ignoring the first element) to this device's file descriptor
- * (/dev/net/tun).
+ * and write them to /dev/net/tun.
  */
-static void handle_net_output(int fd, struct virtqueue *vq, bool timeout)
+struct net_info {
+       int tunfd;
+};
+
+static void net_output(struct virtqueue *vq)
 {
-       unsigned int head, out, in, num = 0;
-       int len;
+       struct net_info *net_info = vq->dev->priv;
+       unsigned int head, out, in;
        struct iovec iov[vq->vring.num];
-       static int last_timeout_num;
-
-       /* Keep getting output buffers from the Guest until we run out. */
-       while ((head = get_vq_desc(vq, iov, &out, &in)) != vq->vring.num) {
-               if (in)
-                       errx(1, "Input buffers in output queue?");
-               len = writev(vq->dev->fd, iov, out);
-               if (len < 0)
-                       err(1, "Writing network packet to tun");
-               add_used_and_trigger(fd, vq, head, len);
-               num++;
-       }
 
-       /* Block further kicks and set up a timer if we saw anything. */
-       if (!timeout && num)
-               block_vq(vq);
-
-       /* We never quite know how long should we wait before we check the
-        * queue again for more packets.  We start at 500 microseconds, and if
-        * we get fewer packets than last time, we assume we made the timeout
-        * too small and increase it by 10 microseconds.  Otherwise, we drop it
-        * by one microsecond every time.  It seems to work well enough. */
-       if (timeout) {
-               if (num < last_timeout_num)
-                       timeout_usec += 10;
-               else if (timeout_usec > 1)
-                       timeout_usec--;
-               last_timeout_num = num;
-       }
+       head = wait_for_vq_desc(vq, iov, &out, &in);
+       if (in)
+               errx(1, "Input buffers in net output queue?");
+       if (writev(net_info->tunfd, iov, out) < 0)
+               errx(1, "Write to tun failed?");
+       add_used(vq, head, 0);
+}
+
+/* Will reading from this file descriptor block? */
+static bool will_block(int fd)
+{
+       fd_set fdset;
+       struct timeval zero = { 0, 0 };
+       FD_ZERO(&fdset);
+       FD_SET(fd, &fdset);
+       return select(fd+1, &fdset, NULL, NULL, &zero) != 1;
 }
 
-/* This is where we handle a packet coming in from the tun device to our
+/* This is where we handle packets coming in from the tun device to our
  * Guest. */
-static bool handle_tun_input(int fd, struct device *dev)
+static void net_input(struct virtqueue *vq)
 {
-       unsigned int head, in_num, out_num;
        int len;
-       struct iovec iov[dev->vq->vring.num];
-
-       /* First we need a network buffer from the Guests's recv virtqueue. */
-       head = get_vq_desc(dev->vq, iov, &out_num, &in_num);
-       if (head == dev->vq->vring.num) {
-               /* Now, it's expected that if we try to send a packet too
-                * early, the Guest won't be ready yet.  Wait until the device
-                * status says it's ready. */
-               /* FIXME: Actually want DRIVER_ACTIVE here. */
-
-               /* Now tell it we want to know if new things appear. */
-               dev->vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY;
-               wmb();
-
-               /* We'll turn this back on if input buffers are registered. */
-               return false;
-       } else if (out_num)
-               errx(1, "Output buffers in network recv queue?");
-
-       /* Read the packet from the device directly into the Guest's buffer. */
-       len = readv(dev->fd, iov, in_num);
-       if (len <= 0)
-               err(1, "reading network");
+       unsigned int head, out, in;
+       struct iovec iov[vq->vring.num];
+       struct net_info *net_info = vq->dev->priv;
 
-       /* Tell the Guest about the new packet. */
-       add_used_and_trigger(fd, dev->vq, head, len);
+       head = wait_for_vq_desc(vq, iov, &out, &in);
+       if (out)
+               errx(1, "Output buffers in net input queue?");
 
-       verbose("tun input packet len %i [%02x %02x] (%s)\n", len,
-               ((u8 *)iov[1].iov_base)[0], ((u8 *)iov[1].iov_base)[1],
-               head != dev->vq->vring.num ? "sent" : "discarded");
+       /* Deliver interrupt now, since we're about to sleep. */
+       if (vq->pending_used && will_block(net_info->tunfd))
+               trigger_irq(vq);
 
-       /* All good. */
-       return true;
+       len = readv(net_info->tunfd, iov, in);
+       if (len <= 0)
+               err(1, "Failed to read from tun.");
+       add_used(vq, head, len);
 }
 
-/*L:215 This is the callback attached to the network and console input
- * virtqueues: it ensures we try again, in case we stopped console or net
- * delivery because Guest didn't have any buffers. */
-static void enable_fd(int fd, struct virtqueue *vq, bool timeout)
+/* This is the helper to create threads. */
+static int do_thread(void *_vq)
 {
-       add_device_fd(vq->dev->fd);
-       /* Snap the Waker out of its select loop. */
-       write(waker_fds.pipe[1], "", 1);
+       struct virtqueue *vq = _vq;
+
+       for (;;)
+               vq->service(vq);
+       return 0;
 }
 
-static void net_enable_fd(int fd, struct virtqueue *vq, bool timeout)
+/* When a child dies, we kill our entire process group with SIGTERM.  This
+ * also has the side effect that the shell restores the console for us! */
+static void kill_launcher(int signal)
 {
-       /* We don't need to know again when Guest refills receive buffer. */
-       vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY;
-       enable_fd(fd, vq, timeout);
+       kill(0, SIGTERM);
 }
 
-/* When the Guest tells us they updated the status field, we handle it. */
-static void update_device_status(struct device *dev)
+static void reset_device(struct device *dev)
 {
        struct virtqueue *vq;
 
-       /* This is a reset. */
-       if (dev->desc->status == 0) {
-               verbose("Resetting device %s\n", dev->name);
+       verbose("Resetting device %s\n", dev->name);
 
-               /* Clear any features they've acked. */
-               memset(get_feature_bits(dev) + dev->desc->feature_len, 0,
-                      dev->desc->feature_len);
+       /* Clear any features they've acked. */
+       memset(get_feature_bits(dev) + dev->feature_len, 0, dev->feature_len);
 
-               /* Zero out the virtqueues. */
-               for (vq = dev->vq; vq; vq = vq->next) {
-                       memset(vq->vring.desc, 0,
-                              vring_size(vq->config.num, LGUEST_VRING_ALIGN));
-                       lg_last_avail(vq) = 0;
+       /* We're going to be explicitly killing threads, so ignore them. */
+       signal(SIGCHLD, SIG_IGN);
+
+       /* Zero out the virtqueues, get rid of their threads */
+       for (vq = dev->vq; vq; vq = vq->next) {
+               if (vq->thread != (pid_t)-1) {
+                       kill(vq->thread, SIGTERM);
+                       waitpid(vq->thread, NULL, 0);
+                       vq->thread = (pid_t)-1;
                }
-       } else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) {
+               memset(vq->vring.desc, 0,
+                      vring_size(vq->config.num, LGUEST_VRING_ALIGN));
+               lg_last_avail(vq) = 0;
+       }
+       dev->running = false;
+
+       /* Now we care if threads die. */
+       signal(SIGCHLD, (void *)kill_launcher);
+}
+
+static void create_thread(struct virtqueue *vq)
+{
+       /* Create stack for thread and run it.  Since stack grows
+        * upwards, we point the stack pointer to the end of this
+        * region. */
+       char *stack = malloc(32768);
+       unsigned long args[] = { LHREQ_EVENTFD,
+                                vq->config.pfn*getpagesize(), 0 };
+
+       /* Create a zero-initialized eventfd. */
+       vq->eventfd = eventfd(0, 0);
+       if (vq->eventfd < 0)
+               err(1, "Creating eventfd");
+       args[2] = vq->eventfd;
+
+       /* Attach an eventfd to this virtqueue: it will go off
+        * when the Guest does an LHCALL_NOTIFY for this vq. */
+       if (write(lguest_fd, &args, sizeof(args)) != 0)
+               err(1, "Attaching eventfd");
+
+       /* CLONE_VM: because it has to access the Guest memory, and
+        * SIGCHLD so we get a signal if it dies. */
+       vq->thread = clone(do_thread, stack + 32768, CLONE_VM | SIGCHLD, vq);
+       if (vq->thread == (pid_t)-1)
+               err(1, "Creating clone");
+       /* We close our local copy, now the child has it. */
+       close(vq->eventfd);
+}
+
+static void start_device(struct device *dev)
+{
+       unsigned int i;
+       struct virtqueue *vq;
+
+       verbose("Device %s OK: offered", dev->name);
+       for (i = 0; i < dev->feature_len; i++)
+               verbose(" %02x", get_feature_bits(dev)[i]);
+       verbose(", accepted");
+       for (i = 0; i < dev->feature_len; i++)
+               verbose(" %02x", get_feature_bits(dev)
+                       [dev->feature_len+i]);
+
+       for (vq = dev->vq; vq; vq = vq->next) {
+               if (vq->service)
+                       create_thread(vq);
+       }
+       dev->running = true;
+}
+
+static void cleanup_devices(void)
+{
+       struct device *dev;
+
+       for (dev = devices.dev; dev; dev = dev->next)
+               reset_device(dev);
+
+       /* If we saved off the original terminal settings, restore them now. */
+       if (orig_term.c_lflag & (ISIG|ICANON|ECHO))
+               tcsetattr(STDIN_FILENO, TCSANOW, &orig_term);
+}
+
+/* When the Guest tells us they updated the status field, we handle it. */
+static void update_device_status(struct device *dev)
+{
+       /* A zero status is a reset, otherwise it's a set of flags. */
+       if (dev->desc->status == 0)
+               reset_device(dev);
+       else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) {
                warnx("Device %s configuration FAILED", dev->name);
+               if (dev->running)
+                       reset_device(dev);
        } else if (dev->desc->status & VIRTIO_CONFIG_S_DRIVER_OK) {
-               unsigned int i;
-
-               verbose("Device %s OK: offered", dev->name);
-               for (i = 0; i < dev->desc->feature_len; i++)
-                       verbose(" %02x", get_feature_bits(dev)[i]);
-               verbose(", accepted");
-               for (i = 0; i < dev->desc->feature_len; i++)
-                       verbose(" %02x", get_feature_bits(dev)
-                               [dev->desc->feature_len+i]);
-
-               if (dev->ready)
-                       dev->ready(dev);
+               if (!dev->running)
+                       start_device(dev);
        }
 }
 
 /* This is the generic routine we call when the Guest uses LHCALL_NOTIFY. */
-static void handle_output(int fd, unsigned long addr)
+static void handle_output(unsigned long addr)
 {
        struct device *i;
-       struct virtqueue *vq;
 
-       /* Check each device and virtqueue. */
+       /* Check each device. */
        for (i = devices.dev; i; i = i->next) {
+               struct virtqueue *vq;
+
                /* Notifications to device descriptors update device status. */
                if (from_guest_phys(addr) == i->desc) {
                        update_device_status(i);
                        return;
                }
 
-               /* Notifications to virtqueues mean output has occurred. */
+               /* Devices *can* be used before status is set to DRIVER_OK. */
                for (vq = i->vq; vq; vq = vq->next) {
-                       if (vq->config.pfn != addr/getpagesize())
+                       if (addr != vq->config.pfn*getpagesize())
                                continue;
-
-                       /* Guest should acknowledge (and set features!)  before
-                        * using the device. */
-                       if (i->desc->status == 0) {
-                               warnx("%s gave early output", i->name);
-                               return;
-                       }
-
-                       if (strcmp(vq->dev->name, "console") != 0)
-                               verbose("Output to %s\n", vq->dev->name);
-                       if (vq->handle_output)
-                               vq->handle_output(fd, vq, false);
+                       if (i->running)
+                               errx(1, "Notification on running %s", i->name);
+                       start_device(i);
                        return;
                }
        }
@@ -1049,71 +990,6 @@ static void handle_output(int fd, unsigned long addr)
              strnlen(from_guest_phys(addr), guest_limit - addr));
 }
 
-static void handle_timeout(int fd)
-{
-       char buf[32];
-       struct device *i;
-       struct virtqueue *vq;
-
-       /* Clear the pipe */
-       read(timeoutpipe[0], buf, sizeof(buf));
-
-       /* Check each device and virtqueue: flush blocked ones. */
-       for (i = devices.dev; i; i = i->next) {
-               for (vq = i->vq; vq; vq = vq->next) {
-                       if (!vq->blocked)
-                               continue;
-
-                       vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY;
-                       vq->blocked = false;
-                       if (vq->handle_output)
-                               vq->handle_output(fd, vq, true);
-               }
-       }
-}
-
-/* This is called when the Waker wakes us up: check for incoming file
- * descriptors. */
-static void handle_input(int fd)
-{
-       /* select() wants a zeroed timeval to mean "don't wait". */
-       struct timeval poll = { .tv_sec = 0, .tv_usec = 0 };
-
-       for (;;) {
-               struct device *i;
-               fd_set fds = devices.infds;
-               int num;
-
-               num = select(devices.max_infd+1, &fds, NULL, NULL, &poll);
-               /* Could get interrupted */
-               if (num < 0)
-                       continue;
-               /* If nothing is ready, we're done. */
-               if (num == 0)
-                       break;
-
-               /* Otherwise, call the device(s) which have readable file
-                * descriptors and a method of handling them.  */
-               for (i = devices.dev; i; i = i->next) {
-                       if (i->handle_input && FD_ISSET(i->fd, &fds)) {
-                               if (i->handle_input(fd, i))
-                                       continue;
-
-                               /* If handle_input() returns false, it means we
-                                * should no longer service it.  Networking and
-                                * console do this when there's no input
-                                * buffers to deliver into.  Console also uses
-                                * it when it discovers that stdin is closed. */
-                               FD_CLR(i->fd, &devices.infds);
-                       }
-               }
-
-               /* Is this the timeout fd? */
-               if (FD_ISSET(timeoutpipe[0], &fds))
-                       handle_timeout(fd);
-       }
-}
-
 /*L:190
  * Device Setup
  *
@@ -1129,8 +1005,8 @@ static void handle_input(int fd)
 static u8 *device_config(const struct device *dev)
 {
        return (void *)(dev->desc + 1)
-               + dev->desc->num_vq * sizeof(struct lguest_vqconfig)
-               + dev->desc->feature_len * 2;
+               + dev->num_vq * sizeof(struct lguest_vqconfig)
+               + dev->feature_len * 2;
 }
 
 /* This routine allocates a new "struct lguest_device_desc" from descriptor
@@ -1159,7 +1035,7 @@ static struct lguest_device_desc *new_dev_desc(u16 type)
 /* Each device descriptor is followed by the description of its virtqueues.  We
  * specify how many descriptors the virtqueue is to have. */
 static void add_virtqueue(struct device *dev, unsigned int num_descs,
-                         void (*handle_output)(int, struct virtqueue *, bool))
+                         void (*service)(struct virtqueue *))
 {
        unsigned int pages;
        struct virtqueue **i, *vq = malloc(sizeof(*vq));
@@ -1174,8 +1050,8 @@ static void add_virtqueue(struct device *dev, unsigned int num_descs,
        vq->next = NULL;
        vq->last_avail_idx = 0;
        vq->dev = dev;
-       vq->inflight = 0;
-       vq->blocked = false;
+       vq->service = service;
+       vq->thread = (pid_t)-1;
 
        /* Initialize the configuration. */
        vq->config.num = num_descs;
@@ -1191,6 +1067,7 @@ static void add_virtqueue(struct device *dev, unsigned int num_descs,
         * yet, otherwise we'd be overwriting them. */
        assert(dev->desc->config_len == 0 && dev->desc->feature_len == 0);
        memcpy(device_config(dev), &vq->config, sizeof(vq->config));
+       dev->num_vq++;
        dev->desc->num_vq++;
 
        verbose("Virtqueue page %#lx\n", to_guest_phys(p));
@@ -1199,15 +1076,6 @@ static void add_virtqueue(struct device *dev, unsigned int num_descs,
         * second.  */
        for (i = &dev->vq; *i; i = &(*i)->next);
        *i = vq;
-
-       /* Set the routine to call when the Guest does something to this
-        * virtqueue. */
-       vq->handle_output = handle_output;
-
-       /* As an optimization, set the advisory "Don't Notify Me" flag if we
-        * don't have a handler */
-       if (!handle_output)
-               vq->vring.used->flags = VRING_USED_F_NO_NOTIFY;
 }
 
 /* The first half of the feature bitmask is for us to advertise features.  The
@@ -1219,7 +1087,7 @@ static void add_feature(struct device *dev, unsigned bit)
        /* We can't extend the feature bits once we've added config bytes */
        if (dev->desc->feature_len <= bit / CHAR_BIT) {
                assert(dev->desc->config_len == 0);
-               dev->desc->feature_len = (bit / CHAR_BIT) + 1;
+               dev->feature_len = dev->desc->feature_len = (bit/CHAR_BIT) + 1;
        }
 
        features[bit / CHAR_BIT] |= (1 << (bit % CHAR_BIT));
@@ -1243,22 +1111,17 @@ static void set_config(struct device *dev, unsigned len, const void *conf)
  * calling new_dev_desc() to allocate the descriptor and device memory.
  *
  * See what I mean about userspace being boring? */
-static struct device *new_device(const char *name, u16 type, int fd,
-                                bool (*handle_input)(int, struct device *))
+static struct device *new_device(const char *name, u16 type)
 {
        struct device *dev = malloc(sizeof(*dev));
 
        /* Now we populate the fields one at a time. */
-       dev->fd = fd;
-       /* If we have an input handler for this file descriptor, then we add it
-        * to the device_list's fdset and maxfd. */
-       if (handle_input)
-               add_device_fd(dev->fd);
        dev->desc = new_dev_desc(type);
-       dev->handle_input = handle_input;
        dev->name = name;
        dev->vq = NULL;
-       dev->ready = NULL;
+       dev->feature_len = 0;
+       dev->num_vq = 0;
+       dev->running = false;
 
        /* Append to device list.  Prepending to a single-linked list is
         * easier, but the user expects the devices to be arranged on the bus
@@ -1286,13 +1149,10 @@ static void setup_console(void)
                 * raw input stream to the Guest. */
                term.c_lflag &= ~(ISIG|ICANON|ECHO);
                tcsetattr(STDIN_FILENO, TCSANOW, &term);
-               /* If we exit gracefully, the original settings will be
-                * restored so the user can see what they're typing. */
-               atexit(restore_term);
        }
 
-       dev = new_device("console", VIRTIO_ID_CONSOLE,
-                        STDIN_FILENO, handle_console_input);
+       dev = new_device("console", VIRTIO_ID_CONSOLE);
+
        /* We store the console state in dev->priv, and initialize it. */
        dev->priv = malloc(sizeof(struct console_abort));
        ((struct console_abort *)dev->priv)->count = 0;
@@ -1301,31 +1161,13 @@ static void setup_console(void)
         * they put something the input queue, we make sure we're listening to
         * stdin.  When they put something in the output queue, we write it to
         * stdout. */
-       add_virtqueue(dev, VIRTQUEUE_NUM, enable_fd);
-       add_virtqueue(dev, VIRTQUEUE_NUM, handle_console_output);
+       add_virtqueue(dev, VIRTQUEUE_NUM, console_input);
+       add_virtqueue(dev, VIRTQUEUE_NUM, console_output);
 
-       verbose("device %u: console\n", devices.device_num++);
+       verbose("device %u: console\n", ++devices.device_num);
 }
 /*:*/
 
-static void timeout_alarm(int sig)
-{
-       write(timeoutpipe[1], "", 1);
-}
-
-static void setup_timeout(void)
-{
-       if (pipe(timeoutpipe) != 0)
-               err(1, "Creating timeout pipe");
-
-       if (fcntl(timeoutpipe[1], F_SETFL,
-                 fcntl(timeoutpipe[1], F_GETFL) | O_NONBLOCK) != 0)
-               err(1, "Making timeout pipe nonblocking");
-
-       add_device_fd(timeoutpipe[0]);
-       signal(SIGALRM, timeout_alarm);
-}
-
 /*M:010 Inter-guest networking is an interesting area.  Simplest is to have a
  * --sharenet=<name> option which opens or creates a named pipe.  This can be
  * used to send packets to another guest in a 1:1 manner.
@@ -1447,21 +1289,23 @@ static int get_tun_device(char tapif[IFNAMSIZ])
 static void setup_tun_net(char *arg)
 {
        struct device *dev;
-       int netfd, ipfd;
+       struct net_info *net_info = malloc(sizeof(*net_info));
+       int ipfd;
        u32 ip = INADDR_ANY;
        bool bridging = false;
        char tapif[IFNAMSIZ], *p;
        struct virtio_net_config conf;
 
-       netfd = get_tun_device(tapif);
+       net_info->tunfd = get_tun_device(tapif);
 
        /* First we create a new network device. */
-       dev = new_device("net", VIRTIO_ID_NET, netfd, handle_tun_input);
+       dev = new_device("net", VIRTIO_ID_NET);
+       dev->priv = net_info;
 
        /* Network devices need a receive and a send queue, just like
         * console. */
-       add_virtqueue(dev, VIRTQUEUE_NUM, net_enable_fd);
-       add_virtqueue(dev, VIRTQUEUE_NUM, handle_net_output);
+       add_virtqueue(dev, VIRTQUEUE_NUM, net_input);
+       add_virtqueue(dev, VIRTQUEUE_NUM, net_output);
 
        /* We need a socket to perform the magic network ioctls to bring up the
         * tap interface, connect to the bridge etc.  Any socket will do! */
@@ -1502,6 +1346,8 @@ static void setup_tun_net(char *arg)
        add_feature(dev, VIRTIO_NET_F_HOST_TSO4);
        add_feature(dev, VIRTIO_NET_F_HOST_TSO6);
        add_feature(dev, VIRTIO_NET_F_HOST_ECN);
+       /* We handle indirect ring entries */
+       add_feature(dev, VIRTIO_RING_F_INDIRECT_DESC);
        set_config(dev, sizeof(conf), &conf);
 
        /* We don't need the socket any more; setup is done. */
@@ -1550,20 +1396,18 @@ struct vblk_info
  * Remember that the block device is handled by a separate I/O thread.  We head
  * straight into the core of that thread here:
  */
-static bool service_io(struct device *dev)
+static void blk_request(struct virtqueue *vq)
 {
-       struct vblk_info *vblk = dev->priv;
+       struct vblk_info *vblk = vq->dev->priv;
        unsigned int head, out_num, in_num, wlen;
        int ret;
        u8 *in;
        struct virtio_blk_outhdr *out;
-       struct iovec iov[dev->vq->vring.num];
+       struct iovec iov[vq->vring.num];
        off64_t off;
 
-       /* See if there's a request waiting.  If not, nothing to do. */
-       head = get_vq_desc(dev->vq, iov, &out_num, &in_num);
-       if (head == dev->vq->vring.num)
-               return false;
+       /* Get the next request. */
+       head = wait_for_vq_desc(vq, iov, &out_num, &in_num);
 
        /* Every block request should contain at least one output buffer
         * (detailing the location on disk and the type of request) and one
@@ -1637,83 +1481,21 @@ static bool service_io(struct device *dev)
        if (out->type & VIRTIO_BLK_T_BARRIER)
                fdatasync(vblk->fd);
 
-       /* We can't trigger an IRQ, because we're not the Launcher.  It does
-        * that when we tell it we're done. */
-       add_used(dev->vq, head, wlen);
-       return true;
-}
-
-/* This is the thread which actually services the I/O. */
-static int io_thread(void *_dev)
-{
-       struct device *dev = _dev;
-       struct vblk_info *vblk = dev->priv;
-       char c;
-
-       /* Close other side of workpipe so we get 0 read when main dies. */
-       close(vblk->workpipe[1]);
-       /* Close the other side of the done_fd pipe. */
-       close(dev->fd);
-
-       /* When this read fails, it means Launcher died, so we follow. */
-       while (read(vblk->workpipe[0], &c, 1) == 1) {
-               /* We acknowledge each request immediately to reduce latency,
-                * rather than waiting until we've done them all.  I haven't
-                * measured to see if it makes any difference.
-                *
-                * That would be an interesting test, wouldn't it?  You could
-                * also try having more than one I/O thread. */
-               while (service_io(dev))
-                       write(vblk->done_fd, &c, 1);
-       }
-       return 0;
-}
-
-/* Now we've seen the I/O thread, we return to the Launcher to see what happens
- * when that thread tells us it's completed some I/O. */
-static bool handle_io_finish(int fd, struct device *dev)
-{
-       char c;
-
-       /* If the I/O thread died, presumably it printed the error, so we
-        * simply exit. */
-       if (read(dev->fd, &c, 1) != 1)
-               exit(1);
-
-       /* It did some work, so trigger the irq. */
-       trigger_irq(fd, dev->vq);
-       return true;
-}
-
-/* When the Guest submits some I/O, we just need to wake the I/O thread. */
-static void handle_virtblk_output(int fd, struct virtqueue *vq, bool timeout)
-{
-       struct vblk_info *vblk = vq->dev->priv;
-       char c = 0;
-
-       /* Wake up I/O thread and tell it to go to work! */
-       if (write(vblk->workpipe[1], &c, 1) != 1)
-               /* Presumably it indicated why it died. */
-               exit(1);
+       add_used(vq, head, wlen);
 }
 
 /*L:198 This actually sets up a virtual block device. */
 static void setup_block_file(const char *filename)
 {
-       int p[2];
        struct device *dev;
        struct vblk_info *vblk;
-       void *stack;
        struct virtio_blk_config conf;
 
-       /* This is the pipe the I/O thread will use to tell us I/O is done. */
-       pipe(p);
-
        /* The device responds to return from I/O thread. */
-       dev = new_device("block", VIRTIO_ID_BLOCK, p[0], handle_io_finish);
+       dev = new_device("block", VIRTIO_ID_BLOCK);
 
        /* The device has one virtqueue, where the Guest places requests. */
-       add_virtqueue(dev, VIRTQUEUE_NUM, handle_virtblk_output);
+       add_virtqueue(dev, VIRTQUEUE_NUM, blk_request);
 
        /* Allocate the room for our own bookkeeping */
        vblk = dev->priv = malloc(sizeof(*vblk));
@@ -1735,49 +1517,29 @@ static void setup_block_file(const char *filename)
 
        set_config(dev, sizeof(conf), &conf);
 
-       /* The I/O thread writes to this end of the pipe when done. */
-       vblk->done_fd = p[1];
-
-       /* This is the second pipe, which is how we tell the I/O thread about
-        * more work. */
-       pipe(vblk->workpipe);
-
-       /* Create stack for thread and run it.  Since stack grows upwards, we
-        * point the stack pointer to the end of this region. */
-       stack = malloc(32768);
-       /* SIGCHLD - We dont "wait" for our cloned thread, so prevent it from
-        * becoming a zombie. */
-       if (clone(io_thread, stack + 32768, CLONE_VM | SIGCHLD, dev) == -1)
-               err(1, "Creating clone");
-
-       /* We don't need to keep the I/O thread's end of the pipes open. */
-       close(vblk->done_fd);
-       close(vblk->workpipe[0]);
-
        verbose("device %u: virtblock %llu sectors\n",
-               devices.device_num, le64_to_cpu(conf.capacity));
+               ++devices.device_num, le64_to_cpu(conf.capacity));
 }
 
+struct rng_info {
+       int rfd;
+};
+
 /* Our random number generator device reads from /dev/random into the Guest's
  * input buffers.  The usual case is that the Guest doesn't want random numbers
  * and so has no buffers although /dev/random is still readable, whereas
  * console is the reverse.
  *
  * The same logic applies, however. */
-static bool handle_rng_input(int fd, struct device *dev)
+static void rng_input(struct virtqueue *vq)
 {
        int len;
        unsigned int head, in_num, out_num, totlen = 0;
-       struct iovec iov[dev->vq->vring.num];
+       struct rng_info *rng_info = vq->dev->priv;
+       struct iovec iov[vq->vring.num];
 
        /* First we need a buffer from the Guests's virtqueue. */
-       head = get_vq_desc(dev->vq, iov, &out_num, &in_num);
-
-       /* If they're not ready for input, stop listening to this file
-        * descriptor.  We'll start again once they add an input buffer. */
-       if (head == dev->vq->vring.num)
-               return false;
-
+       head = wait_for_vq_desc(vq, iov, &out_num, &in_num);
        if (out_num)
                errx(1, "Output buffers in rng?");
 
@@ -1785,7 +1547,7 @@ static bool handle_rng_input(int fd, struct device *dev)
         * it reads straight into the Guest's buffer.  We loop to make sure we
         * fill it. */
        while (!iov_empty(iov, in_num)) {
-               len = readv(dev->fd, iov, in_num);
+               len = readv(rng_info->rfd, iov, in_num);
                if (len <= 0)
                        err(1, "Read from /dev/random gave %i", len);
                iov_consume(iov, in_num, len);
@@ -1793,25 +1555,23 @@ static bool handle_rng_input(int fd, struct device *dev)
        }
 
        /* Tell the Guest about the new input. */
-       add_used_and_trigger(fd, dev->vq, head, totlen);
-
-       /* Everything went OK! */
-       return true;
+       add_used(vq, head, totlen);
 }
 
 /* And this creates a "hardware" random number device for the Guest. */
 static void setup_rng(void)
 {
        struct device *dev;
-       int fd;
+       struct rng_info *rng_info = malloc(sizeof(*rng_info));
 
-       fd = open_or_die("/dev/random", O_RDONLY);
+       rng_info->rfd = open_or_die("/dev/random", O_RDONLY);
 
        /* The device responds to return from I/O thread. */
-       dev = new_device("rng", VIRTIO_ID_RNG, fd, handle_rng_input);
+       dev = new_device("rng", VIRTIO_ID_RNG);
+       dev->priv = rng_info;
 
        /* The device has one virtqueue, where the Guest places inbufs. */
-       add_virtqueue(dev, VIRTQUEUE_NUM, enable_fd);
+       add_virtqueue(dev, VIRTQUEUE_NUM, rng_input);
 
        verbose("device %u: rng\n", devices.device_num++);
 }
@@ -1827,17 +1587,18 @@ static void __attribute__((noreturn)) restart_guest(void)
        for (i = 3; i < FD_SETSIZE; i++)
                close(i);
 
-       /* The exec automatically gets rid of the I/O and Waker threads. */
+       /* Reset all the devices (kills all threads). */
+       cleanup_devices();
+
        execv(main_args[0], main_args);
        err(1, "Could not exec %s", main_args[0]);
 }
 
 /*L:220 Finally we reach the core of the Launcher which runs the Guest, serves
  * its input and output, and finally, lays it to rest. */
-static void __attribute__((noreturn)) run_guest(int lguest_fd)
+static void __attribute__((noreturn)) run_guest(void)
 {
        for (;;) {
-               unsigned long args[] = { LHREQ_BREAK, 0 };
                unsigned long notify_addr;
                int readval;
 
@@ -1848,8 +1609,7 @@ static void __attribute__((noreturn)) run_guest(int lguest_fd)
                /* One unsigned long means the Guest did HCALL_NOTIFY */
                if (readval == sizeof(notify_addr)) {
                        verbose("Notify on address %#lx\n", notify_addr);
-                       handle_output(lguest_fd, notify_addr);
-                       continue;
+                       handle_output(notify_addr);
                /* ENOENT means the Guest died.  Reading tells us why. */
                } else if (errno == ENOENT) {
                        char reason[1024] = { 0 };
@@ -1858,19 +1618,9 @@ static void __attribute__((noreturn)) run_guest(int lguest_fd)
                /* ERESTART means that we need to reboot the guest */
                } else if (errno == ERESTART) {
                        restart_guest();
-               /* EAGAIN means a signal (timeout).
-                * Anything else means a bug or incompatible change. */
-               } else if (errno != EAGAIN)
+               /* Anything else means a bug or incompatible change. */
+               } else
                        err(1, "Running guest failed");
-
-               /* Only service input on thread for CPU 0. */
-               if (cpu_id != 0)
-                       continue;
-
-               /* Service input, then unset the BREAK to release the Waker. */
-               handle_input(lguest_fd);
-               if (pwrite(lguest_fd, args, sizeof(args), cpu_id) < 0)
-                       err(1, "Resetting break");
        }
 }
 /*L:240
@@ -1904,8 +1654,8 @@ int main(int argc, char *argv[])
        /* Memory, top-level pagetable, code startpoint and size of the
         * (optional) initrd. */
        unsigned long mem = 0, start, initrd_size = 0;
-       /* Two temporaries and the /dev/lguest file descriptor. */
-       int i, c, lguest_fd;
+       /* Two temporaries. */
+       int i, c;
        /* The boot information for the Guest. */
        struct boot_params *boot;
        /* If they specify an initrd file to load. */
@@ -1913,18 +1663,10 @@ int main(int argc, char *argv[])
 
        /* Save the args: we "reboot" by execing ourselves again. */
        main_args = argv;
-       /* We don't "wait" for the children, so prevent them from becoming
-        * zombies. */
-       signal(SIGCHLD, SIG_IGN);
 
-       /* First we initialize the device list.  Since console and network
-        * device receive input from a file descriptor, we keep an fdset
-        * (infds) and the maximum fd number (max_infd) with the head of the
-        * list.  We also keep a pointer to the last device.  Finally, we keep
-        * the next interrupt number to use for devices (1: remember that 0 is
-        * used by the timer). */
-       FD_ZERO(&devices.infds);
-       devices.max_infd = -1;
+       /* First we initialize the device list.  We keep a pointer to the last
+        * device, and the next interrupt number to use for devices (1:
+        * remember that 0 is used by the timer). */
        devices.lastdev = NULL;
        devices.next_irq = 1;
 
@@ -1982,9 +1724,6 @@ int main(int argc, char *argv[])
        /* We always have a console device */
        setup_console();
 
-       /* We can timeout waiting for Guest network transmit. */
-       setup_timeout();
-
        /* Now we load the kernel */
        start = load_kernel(open_or_die(argv[optind+1], O_RDONLY));
 
@@ -2023,15 +1762,16 @@ int main(int argc, char *argv[])
 
        /* We tell the kernel to initialize the Guest: this returns the open
         * /dev/lguest file descriptor. */
-       lguest_fd = tell_kernel(start);
+       tell_kernel(start);
+
+       /* Ensure that we terminate if a child dies. */
+       signal(SIGCHLD, kill_launcher);
 
-       /* We clone off a thread, which wakes the Launcher whenever one of the
-        * input file descriptors needs attention.  We call this the Waker, and
-        * we'll cover it in a moment. */
-       setup_waker(lguest_fd);
+       /* If we exit via err(), this kills all the threads, restores tty. */
+       atexit(cleanup_devices);
 
        /* Finally, run the Guest.  This doesn't return. */
-       run_guest(lguest_fd);
+       run_guest();
 }
 /*:*/
 
index 28c747362f958162e70c5b092fad444d22e7d12e..efb3a6a045a284a43593fb531d936736c939bbf3 100644 (file)
@@ -37,7 +37,6 @@ Running Lguest:
      "Paravirtualized guest support" = Y
         "Lguest guest support" = Y
      "High Memory Support" = off/4GB
-     "PAE (Physical Address Extension) Support" = N
      "Alignment value to which kernel should be aligned" = 0x100000
         (CONFIG_PARAVIRT=y, CONFIG_LGUEST_GUEST=y, CONFIG_HIGHMEM64G=n and
          CONFIG_PHYSICAL_ALIGN=0x100000)
index 23045b8b50f090ff806624c763fb2313c1ad9494..300da4bdfdbd703c4809bc4b3ec5433dfe634d1e 100644 (file)
@@ -34,7 +34,7 @@ out of order wrt other memory writes by the owner CPU.
 
 It can be done by slightly modifying the standard atomic operations : only
 their UP variant must be kept. It typically means removing LOCK prefix (on
-i386 and x86_64) and any SMP sychronization barrier. If the architecture does
+i386 and x86_64) and any SMP synchronization barrier. If the architecture does
 not have a different behavior between SMP and UP, including asm-generic/local.h
 in your architecture's local.h is sufficient.
 
index 4c2ecf537a4ad5d1edf47d5c5295416650364bd3..bbc8a6a3692169a53aeb9ac1ab271018a53531d0 100644 (file)
@@ -73,13 +73,13 @@ this phase is triggered automatically. ACPI can notify this event. If not,
 (see Section 4.).
 
 Logical Memory Hotplug phase is to change memory state into
-avaiable/unavailable for users. Amount of memory from user's view is
+available/unavailable for users. Amount of memory from user's view is
 changed by this phase. The kernel makes all memory in it as free pages
 when a memory range is available.
 
 In this document, this phase is described as online/offline.
 
-Logical Memory Hotplug phase is triggred by write of sysfs file by system
+Logical Memory Hotplug phase is triggered by write of sysfs file by system
 administrator. For the hot-add case, it must be executed after Physical Hotplug
 phase by hand.
 (However, if you writes udev's hotplug scripts for memory hotplug, these
@@ -334,7 +334,7 @@ MEMORY_CANCEL_ONLINE
   Generated if MEMORY_GOING_ONLINE fails.
 
 MEMORY_ONLINE
-  Generated when memory has succesfully brought online. The callback may
+  Generated when memory has successfully brought online. The callback may
   allocate pages from the new memory.
 
 MEMORY_GOING_OFFLINE
@@ -359,7 +359,7 @@ The third argument is passed by pointer of struct memory_notify.
 struct memory_notify {
        unsigned long start_pfn;
        unsigned long nr_pages;
-       int status_cahnge_nid;
+       int status_change_nid;
 }
 
 start_pfn is start_pfn of online/offline memory.
index 1fef1f06dfd233f44c4f0c46e2754337e3d483a3..d3507bad428d0f816617cc452dd706a4556f295b 100644 (file)
@@ -26,7 +26,7 @@ registers and the stack. If the first argument is a 64-bit value, it will be
 passed in D0:D1. If the first argument is not a 64-bit value, but the second
 is, the second will be passed entirely on the stack and D1 will be unused.
 
-Arguments smaller than 32-bits are not coelesced within a register or a stack
+Arguments smaller than 32-bits are not coalesced within a register or a stack
 word. For example, two byte-sized arguments will always be passed in separate
 registers or word-sized stack slots.
 
index bdf93b7f0f2448bf3a2fd04d51cba13fe1e8029f..274821b35a7f1ce8e511f036a2008e2225342883 100644 (file)
@@ -50,7 +50,7 @@ byte 255:  bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0   rp1 rp3 rp5 ... rp15
            cp5  cp5  cp5  cp5  cp4  cp4  cp4  cp4
 
 This figure represents a sector of 256 bytes.
-cp is my abbreviaton for column parity, rp for row parity.
+cp is my abbreviation for column parity, rp for row parity.
 
 Let's start to explain column parity.
 cp0 is the parity that belongs to all bit0, bit2, bit4, bit6.
@@ -560,7 +560,7 @@ Measuring this code again showed big gain. When executing the original
 linux code 1 million times, this took about 1 second on my system.
 (using time to measure the performance). After this iteration I was back
 to 0.075 sec. Actually I had to decide to start measuring over 10
-million interations in order not to loose too much accuracy. This one
+million iterations in order not to lose too much accuracy. This one
 definitely seemed to be the jackpot!
 
 There is a little bit more room for improvement though. There are three
@@ -571,8 +571,8 @@ loop; This eliminates 3 statements per loop. Of course after the loop we
 need to correct by adding:
     rp4 ^= rp4_6;
     rp6 ^= rp4_6
-Furthermore there are 4 sequential assingments to rp8. This can be
-encoded slightly more efficient by saving tmppar before those 4 lines
+Furthermore there are 4 sequential assignments to rp8. This can be
+encoded slightly more efficiently by saving tmppar before those 4 lines
 and later do rp8 = rp8 ^ tmppar ^ notrp8;
 (where notrp8 is the value of rp8 before those 4 lines).
 Again a use of the commutative property of xor.
@@ -622,7 +622,7 @@ Not a big change, but every penny counts :-)
 Analysis 7
 ==========
 
-Acutally this made things worse. Not very much, but I don't want to move
+Actually this made things worse. Not very much, but I don't want to move
 into the wrong direction. Maybe something to investigate later. Could
 have to do with caching again.
 
@@ -642,7 +642,7 @@ Analysis 8
 This makes things worse. Let's stick with attempt 6 and continue from there.
 Although it seems that the code within the loop cannot be optimised
 further there is still room to optimize the generation of the ecc codes.
-We can simply calcualate the total parity. If this is 0 then rp4 = rp5
+We can simply calculate the total parity. If this is 0 then rp4 = rp5
 etc. If the parity is 1, then rp4 = !rp5;
 But if rp4 = rp5 we do not need rp5 etc. We can just write the even bits
 in the result byte and then do something like
index 08762750f12109acd05ab26c63efa1973fe2adad..d5181ce9ff625d80c8f7d3647cf137b07beb06fa 100644 (file)
@@ -221,7 +221,7 @@ ad_select
 
                - Any slave's 802.3ad association state changes
 
-               - The bond's adminstrative state changes to up
+               - The bond's administrative state changes to up
 
        count or 2
 
@@ -369,7 +369,7 @@ fail_over_mac
                When this policy is used in conjuction with the mii
                monitor, devices which assert link up prior to being
                able to actually transmit and receive are particularly
-               susecptible to loss of the gratuitous ARP, and an
+               susceptible to loss of the gratuitous ARP, and an
                appropriate updelay setting may be required.
 
        follow or 2
@@ -1794,7 +1794,7 @@ target to query.
 generally referred to as "trunk failover."  This is a feature of the
 switch that causes the link state of a particular switch port to be set
 down (or up) when the state of another switch port goes down (or up).
-It's purpose is to propogate link failures from logically "exterior" ports
+Its purpose is to propagate link failures from logically "exterior" ports
 to the logically "interior" ports that bonding is able to monitor via
 miimon.  Availability and configuration for trunk failover varies by
 switch, but this can be a viable alternative to the ARP monitor when using
index 2035bc4932f224685992ca57b29e64de5da4934e..463d9e029ef3a4a702a85410119827333e0ee7bc 100644 (file)
@@ -327,7 +327,7 @@ solution for a couple of reasons:
             return 1;
     }
 
-    /* paraniod check ... */
+    /* paranoid check ... */
     if (nbytes < sizeof(struct can_frame)) {
             fprintf(stderr, "read: incomplete CAN frame\n");
             return 1;
index 65df3dea55613bd581dd787305054b7062657507..5552e2e575c54119b63ebe91c97a030048140430 100644 (file)
@@ -129,7 +129,7 @@ PHY Link state polling
 ----------------------
 
 The driver keeps track of the link state and informs the network core
-about link (carrier) availablilty. This is managed by several methods
+about link (carrier) availability. This is managed by several methods
 depending on the version of the chip and on which PHY is being used.
 
 For the internal PHY, the original (and currently default) method is
index 2451f551c505ffce5bb2d324b59219ebe051be96..63214b280e0026c9711ea08ec0f1111e41524599 100644 (file)
@@ -158,7 +158,7 @@ Sample Userspace Code
         }
         return 0;
 
-Miscellanous
+Miscellaneous
 ============
 
 The PPPoL2TP driver was developed as part of the OpenL2TP project by
index a2ab6a0b116d96ff8e6198154d5f455cac2fec5e..87b3d15f523ad49863d927801269efd1b5fb65de 100644 (file)
@@ -74,7 +74,7 @@ dev->hard_start_xmit:
        for this and return NETDEV_TX_LOCKED when the spin lock fails.
        The locking there should also properly protect against 
        set_multicast_list. Note that the use of NETIF_F_LLTX is deprecated.
-       Dont use it for new drivers.
+       Don't use it for new drivers.
 
        Context: Process with BHs disabled or BH (timer),
                 will be called with interrupts disabled by netconsole.
index 6a07e45d4a9307aa208b88ae84cd97ab490fd0ac..6e8ce09f9c734e95f74d90c1ae11c5664b6d1ee4 100644 (file)
@@ -36,7 +36,7 @@ Phonet packets have a common header as follows:
 On Linux, the link-layer header includes the pn_media byte (see below).
 The next 7 bytes are part of the network-layer header.
 
-The device ID is split: the 6 higher-order bits consitute the device
+The device ID is split: the 6 higher-order bits constitute the device
 address, while the 2 lower-order bits are used for multiplexing, as are
 the 8-bit object identifiers. As such, Phonet can be considered as a
 network layer with 6 bits of address space and 10 bits for transport
index dcf31648414ad8423e934851bea5ee38b0d09f2f..eaa1a25946c1d011c0a51a2fed1b9f1d7047829c 100644 (file)
@@ -89,7 +89,7 @@ added to this document when its support is enabled.
 Device drivers who provide their own built regulatory domain
 do not need a callback as the channels registered by them are
 the only ones that will be allowed and therefore *additional*
-cannels cannot be enabled.
+channels cannot be enabled.
 
 Example code - drivers hinting an alpha2:
 ------------------------------------------
index 421e7d00ffd03a81fa1573656b39d489b045cd23..c9abbd86bc187bd8dddf88c14f295babf708e2bb 100644 (file)
@@ -75,9 +75,6 @@ may need to apply in domain-specific ways to their devices:
 struct bus_type {
        ...
        int  (*suspend)(struct device *dev, pm_message_t state);
-       int  (*suspend_late)(struct device *dev, pm_message_t state);
-
-       int  (*resume_early)(struct device *dev);
        int  (*resume)(struct device *dev);
 };
 
@@ -226,20 +223,7 @@ The phases are seen by driver notifications issued in this order:
 
        This call should handle parts of device suspend logic that require
        sleeping.  It probably does work to quiesce the device which hasn't
-       been abstracted into class.suspend() or bus.suspend_late().
-
-   3   bus.suspend_late(dev, message) is called with IRQs disabled, and
-       with only one CPU active.  Until the bus.resume_early() phase
-       completes (see later), IRQs are not enabled again.  This method
-       won't be exposed by all busses; for message based busses like USB,
-       I2C, or SPI, device interactions normally require IRQs.  This bus
-       call may be morphed into a driver call with bus-specific parameters.
-
-       This call might save low level hardware state that might otherwise
-       be lost in the upcoming low power state, and actually put the
-       device into a low power state ... so that in some cases the device
-       may stay partly usable until this late.  This "late" call may also
-       help when coping with hardware that behaves badly.
+       been abstracted into class.suspend().
 
 The pm_message_t parameter is currently used to refine those semantics
 (described later).
@@ -351,19 +335,11 @@ devices processing each phase's calls before the next phase begins.
 
 The phases are seen by driver notifications issued in this order:
 
-   1   bus.resume_early(dev) is called with IRQs disabled, and with
-       only one CPU active.  As with bus.suspend_late(), this method
-       won't be supported on busses that require IRQs in order to
-       interact with devices.
-
-       This reverses the effects of bus.suspend_late().
-
-   2   bus.resume(dev) is called next.  This may be morphed into a device
-       driver call with bus-specific parameters; implementations may sleep.
-
-       This reverses the effects of bus.suspend().
+   1   bus.resume(dev) reverses the effects of bus.suspend().  This may
+       be morphed into a device driver call with bus-specific parameters;
+       implementations may sleep.
 
-   3   class.resume(dev) is called for devices associated with a class
+   2   class.resume(dev) is called for devices associated with a class
        that has such a method.  Implementations may sleep.
 
        This reverses the effects of class.suspend(), and would usually
index 82b7a43aadba7255381aef69951a304efc217fa6..5f83fd24ea8437ca16792874d937eacbaf01cfb3 100644 (file)
@@ -178,5 +178,5 @@ Consumers can uregister interest by calling :-
 int regulator_unregister_notifier(struct regulator *regulator,
                                struct notifier_block *nb);
 
-Regulators use the kernel notifier framework to send event to thier interested
+Regulators use the kernel notifier framework to send event to their interested
 consumers.
index bdcb332bd7fbea329f23e6ce9b68dd761e8da2d8..0cded696ca01cdc0ebb9a97deec4f80ede656809 100644 (file)
@@ -119,7 +119,7 @@ Some terms used in this document:-
                    battery power, USB power)
 
                    Regulator Domains: is the new current limit within the
-                   regulator operating parameters for input/ouput voltage.
+                   regulator operating parameters for input/output voltage.
 
                    If the regulator request passes all the constraint tests
                    then the new regulator value is applied.
index 2ebdc6091ce17ff6464aeb4cec35939983045de6..514b94fc931e09b337fd297401d9f9c1aa391dac 100644 (file)
@@ -63,7 +63,7 @@ hardware during resume operations where a value can be set that will
 survive a reboot.
 
 Consequence is that after a resume (even if it is successful) your system
-clock will have a value corresponding to the magic mumber instead of the
+clock will have a value corresponding to the magic number instead of the
 correct date/time! It is therefore advisable to use a program like ntp-date
 or rdate to reset the correct date/time from an external time source when
 using this trace option.
index 7b99636564c8cbc608ff6fb1a24b883c254bf8e3..b967cd9137d653a95b34f135f3d09ec5b61c9e8b 100644 (file)
@@ -109,7 +109,7 @@ unfreeze user space processes frozen by SNAPSHOT_UNFREEZE if they are
 still frozen when the device is being closed).
 
 Currently it is assumed that the userland utilities reading/writing the
-snapshot image from/to the kernel will use a swap parition, called the resume
+snapshot image from/to the kernel will use a swap partition, called the resume
 partition, or a swap file as storage space (if a swap file is used, the resume
 partition is the partition that holds this file).  However, this is not really
 required, as they can use, for example, a special (blank) suspend partition or
index d16b7a1c3793e859c160238614666d67aa4b9321..8d999d862d0e646ffb9c7949898d3987fc2004a4 100644 (file)
@@ -1356,7 +1356,7 @@ platforms are moved over to use the flattened-device-tree model.
     - phy-map           : 1 cell, optional, bitmap of addresses to probe the PHY
                          for, used if phy-address is absent. bit 0x00000001 is
                          MDIO address 0.
-                         For Axon it can be absent, thouugh my current driver
+                         For Axon it can be absent, though my current driver
                          doesn't handle phy-address yet so for now, keep
                          0x00ffffff in it.
     - rx-fifo-size-gige : 1 cell, Rx fifo size in bytes for 1000 Mb/sec
@@ -1438,7 +1438,7 @@ platforms are moved over to use the flattened-device-tree model.
 
    The Xilinx EDK toolchain ships with a set of IP cores (devices) for use
    in Xilinx Spartan and Virtex FPGAs.  The devices cover the whole range
-   of standard device types (network, serial, etc.) and miscellanious
+   of standard device types (network, serial, etc.) and miscellaneous
    devices (gpio, LCD, spi, etc).  Also, since these devices are
    implemented within the fpga fabric every instance of the device can be
    synthesised with different options that change the behaviour.
index 6c974d28eeb404f03c63d3d0b79bfd5a5b00675b..e8b5bc24d0acab21dd1efd094fc8940cf7c0b63a 100644 (file)
@@ -38,7 +38,7 @@ Required properities:
 - reg : Should contain the address and the length of the GPIO bank
   register.
 - #gpio-cells : Should be two. The first cell is the pin number and the
-  second cell is used to specify optional paramters (currently unused).
+  second cell is used to specify optional parameters (currently unused).
 - gpio-controller : Marks the port as GPIO controller.
 
 Example:
index 088fc471e03a7eb9bc64b9943170df5125634559..160c752484b4a74ea11ff6366a6b6613f97af316 100644 (file)
@@ -19,7 +19,7 @@ Example:
        reg = <119c0 30>;
      }
 
-* Properties common to mulitple CPM/QE devices
+* Properties common to multiple CPM/QE devices
 
 - fsl,cpm-command : This value is ORed with the opcode and command flag
                     to specify the device on which a CPM command operates.
index 1815dfede1bc8b201f46c6b989b0a868236a3aed..349f79fd7076a63b3ad373e0d473f7e00f484c14 100644 (file)
@@ -11,7 +11,7 @@ Required properties:
   "fsl,cpm1-pario-bank-c", "fsl,cpm1-pario-bank-d",
   "fsl,cpm1-pario-bank-e", "fsl,cpm2-pario-bank"
 - #gpio-cells : Should be two. The first cell is the pin number and the
-  second cell is used to specify optional paramters (currently unused).
+  second cell is used to specify optional parameters (currently unused).
 - gpio-controller : Marks the port as GPIO controller.
 
 Example of three SOC GPIO banks defined as gpio-controller nodes:
index b26b91992c5589cd3c6e289d8b616f87ceeb3dce..bcc30bac6831cd055f0f6d2262c80a52303a8d9a 100644 (file)
@@ -1,6 +1,6 @@
 * Freescale MSI interrupt controller
 
-Reguired properities:
+Required properties:
 - compatible : compatible list, contains 2 entries,
   first is "fsl,CHIP-msi", where CHIP is the processor(mpc8610, mpc8572,
   etc.) and the second is "fsl,mpic-msi" or "fsl,ipic-msi" depending on
index 02f6f43ee1b7f0c24a3ea39e0d87ee170ddf7ba0..07256b7ffcaab2ba57b33cf279df45d830ce33b3 100644 (file)
@@ -15,8 +15,8 @@ Properties:
   compatible; all statements below that apply to "fsl,mpc8548-pmc" also
   apply to "fsl,mpc8641d-pmc".
 
-  Compatibility does not include bit assigments in SCCR/PMCDR/DEVDISR; these
-  bit assigments are indicated via the sleep specifier in each device's
+  Compatibility does not include bit assignments in SCCR/PMCDR/DEVDISR; these
+  bit assignments are indicated via the sleep specifier in each device's
   sleep property.
 
 - reg: For devices compatible with "fsl,mpc8349-pmc", the first resource
index 06da4d4b44f9c0d3f81bcbddb01ccc5c76ae01d8..2031ddb33d097d4d78496caadbf16f74481839c3 100644 (file)
@@ -225,7 +225,7 @@ For example, to match the 8323, revision 1.0:
      soc.major = 1
      soc.minor = 0
 
-'padding' is neccessary for structure alignment.  This field ensures that the
+'padding' is necessary for structure alignment.  This field ensures that the
 'extended_modes' field is aligned on a 64-bit boundary.
 
 'extended_modes' is a bitfield that defines special functionality which has an
index 7224459b469e8bf76da4af840468e4dd9d44a520..aae8355d3166ddde11436ca5a21bd7e234e68806 100644 (file)
@@ -131,8 +131,8 @@ Example:
        }
 
        /* Add new node and rebalance tree. */
-       rb_link_node(data->node, parent, new);
-       rb_insert_color(data->node, root);
+       rb_link_node(&data->node, parent, new);
+       rb_insert_color(&data->node, root);
 
        return TRUE;
   }
@@ -146,10 +146,10 @@ To remove an existing node from a tree, call:
 
 Example:
 
-  struct mytype *data = mysearch(mytree, "walrus");
+  struct mytype *data = mysearch(&mytree, "walrus");
 
   if (data) {
-       rb_erase(data->node, mytree);
+       rb_erase(&data->node, &mytree);
        myfree(data);
   }
 
@@ -188,5 +188,5 @@ Example:
 
   struct rb_node *node;
   for (node = rb_first(&mytree); node; node = rb_next(node))
-       printk("key=%s\n", rb_entry(node, int, keystring));
+       printk("key=%s\n", rb_entry(node, struct mytype, node)->keystring);
 
index 10711d9f078860513959b4cbf7dfa7d71e21a409..1eb576a023bdedafd6f5f8fda4d0efb657e9ffaa 100644 (file)
@@ -1984,7 +1984,7 @@ break *$pc
 
 break *0x400618
 
-heres a really useful one for large programs
+Here's a really useful one for large programs
 rbr
 Set a breakpoint for all functions matching REGEXP
 e.g.
@@ -2211,7 +2211,7 @@ Breakpoint 2 at 0x4d87a4: file top.c, line 2609.
 #5  0x51692c in readline_internal () at readline.c:521
 #6  0x5164fe in readline (prompt=0x7ffff810 "\177\81ÿ\81øx\177\81ÿ\81÷\81Ø\177\81ÿ\81øx\81À")
     at readline.c:349
-#7  0x4d7a8a in command_line_input (prrompt=0x564420 "(gdb) ", repeat=1,
+#7  0x4d7a8a in command_line_input (prompt=0x564420 "(gdb) ", repeat=1,
     annotation_suffix=0x4d6b44 "prompt") at top.c:2091
 #8  0x4d6cf0 in command_loop () at top.c:1345
 #9  0x4e25bc in main (argc=1, argv=0x7ffffdf4) at main.c:635
index e2bae5a577e326d5146ba4c6b77cc2e19af136a3..3ac1e46d53652a2ce4279a19abc51ffed1069b39 100644 (file)
@@ -55,7 +55,7 @@ To sum it up: we always wanted to make nice levels more consistent, but
 within the constraints of HZ and jiffies and their nasty design level
 coupling to timeslices and granularity it was not really viable.
 
-The second (less frequent but still periodically occuring) complaint
+The second (less frequent but still periodically occurring) complaint
 about Linux's nice level support was its assymetry around the origo
 (which you can see demonstrated in the picture above), or more
 accurately: the fact that nice level behavior depended on the _absolute_
index 683ccae00ad412aa498e979d574627e87ade2088..c014eccaf19fb96b51074c505e7529785b809232 100644 (file)
@@ -194,7 +194,7 @@ The following information is available in this file:
           - Packetized SCSI Protocol at 160MB/s and 320MB/s
           - Quick Arbitration Selection (QAS)
           - Retained Training Information (Rev B. ASIC only)
-        - Interrupt Coalessing
+        - Interrupt Coalescing
         - Initiator Mode (target mode not currently 
           supported)
         - Support for the PCI-X standard up to 133MHz
index 230e30846ef2c1537619a2b8e0118a3cbc098acd..08e2b4d04aabbebeee6ac61e4305ec5246919fb9 100644 (file)
@@ -206,7 +206,7 @@ of MOVE MEMORY instructions.
 The 896 and the 895A allows handling of the phase mismatch context from 
 SCRIPTS (avoids the phase mismatch interrupt that stops the SCSI processor 
 until the C code has saved the context of the transfer).
-Implementing this without using LOAD/STORE instructions would be painfull 
+Implementing this without using LOAD/STORE instructions would be painful 
 and I didn't even want to try it.
 
 The 896 chip supports 64 bit PCI transactions and addressing, while the 
@@ -240,7 +240,7 @@ characteristics. This feature may also reduce average command latency.
 In order to really gain advantage of this feature, devices must have 
 a reasonable cache size (No miracle is to be expected for a low-end 
 hard disk with 128 KB or less).
-Some kown SCSI devices do not properly support tagged command queuing.
+Some known SCSI devices do not properly support tagged command queuing.
 Generally, firmware revisions that fix this kind of problems are available 
 at respective vendor web/ftp sites.
 All I can say is that the hard disks I use on my machines behave well with 
index 49ea5c58c6bc9121bf24f3c9524dfc6e98df15be..eb9a7b905b64c059b902df2353022d7f0e42dd60 100644 (file)
@@ -206,7 +206,7 @@ characteristics. This feature may also reduce average command latency.
 In order to really gain advantage of this feature, devices must have 
 a reasonable cache size (No miracle is to be expected for a low-end 
 hard disk with 128 KB or less).
-Some kown old SCSI devices do not properly support tagged command queuing.
+Some known old SCSI devices do not properly support tagged command queuing.
 Generally, firmware revisions that fix this kind of problems are available 
 at respective vendor web/ftp sites.
 All I can say is that I never have had problem with tagged queuing using 
index 012858d2b11935aa711e4cf9d2d8fbe637403813..4252697a95d6f41c23b1a0a8e7375f98626a3bac 100644 (file)
@@ -460,6 +460,25 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     The power-management is supported.
 
+  Module snd-ctxfi
+  ----------------
+
+    Module for Creative Sound Blaster X-Fi boards (20k1 / 20k2 chips)
+       * Creative Sound Blaster X-Fi Titanium Fatal1ty Champion Series
+       * Creative Sound Blaster X-Fi Titanium Fatal1ty Professional Series
+       * Creative Sound Blaster X-Fi Titanium Professional Audio
+       * Creative Sound Blaster X-Fi Titanium
+       * Creative Sound Blaster X-Fi Elite Pro
+       * Creative Sound Blaster X-Fi Platinum
+       * Creative Sound Blaster X-Fi Fatal1ty
+       * Creative Sound Blaster X-Fi XtremeGamer
+       * Creative Sound Blaster X-Fi XtremeMusic
+
+    reference_rate     - reference sample rate, 44100 or 48000 (default)
+    multiple           - multiple to ref. sample rate, 1 or 2 (default)
+
+    This module supports multiple cards.
+
   Module snd-darla20
   ------------------
 
@@ -754,7 +773,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     single_cmd  - Use single immediate commands to communicate with
                codecs (for debugging only)
     enable_msi - Enable Message Signaled Interrupt (MSI) (default = off)
-    power_save - Automatic power-saving timtout (in second, 0 =
+    power_save - Automatic power-saving timeout (in second, 0 =
                disable)
     power_save_controller - Reset HD-audio controller in power-saving mode
                (default = on)
@@ -925,6 +944,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
                        * Onkyo SE-90PCI
                        * Onkyo SE-200PCI
                        * ESI Juli@
+                       * ESI Maya44
                        * Hercules Fortissimo IV
                        * EGO-SYS WaveTerminal 192M
 
@@ -933,7 +953,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
                  prodigy71xt, prodigy71hifi, prodigyhd2, prodigy192,
                  juli, aureon51, aureon71, universe, ap192, k8x800,
                  phase22, phase28, ms300, av710, se200pci, se90pci,
-                 fortissimo4, sn25p, WT192M
+                 fortissimo4, sn25p, WT192M, maya44
 
     This module supports multiple cards and autoprobe.
 
@@ -1093,6 +1113,13 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     This module supports multiple cards.
     The driver requires the firmware loader support on kernel.
 
+  Module snd-lx6464es
+  -------------------
+
+    Module for Digigram LX6464ES boards
+
+    This module supports multiple cards.
+
   Module snd-maestro3
   -------------------
 
@@ -1543,13 +1570,15 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
   Module snd-sc6000
   -----------------
 
-    Module for Gallant SC-6000 soundcard.
+    Module for Gallant SC-6000 soundcard and later models: SC-6600
+    and SC-7000.
 
     port       - Port # (0x220 or 0x240)
     mss_port   - MSS Port # (0x530 or 0xe80)
     irq                - IRQ # (5,7,9,10,11)
     mpu_irq    - MPU-401 IRQ # (5,7,9,10) ,0 - no MPU-401 irq
     dma                - DMA # (1,3,0)
+    joystick   - Enable gameport - 0 = disable (default), 1 = enable
 
     This module supports multiple cards.
 
@@ -1859,7 +1888,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
   -------------------
 
     Module for sound cards based on the Asus AV100/AV200 chips,
-    i.e., Xonar D1, DX, D2, D2X, HDAV1.3 (Deluxe), and Essence STX.
+    i.e., Xonar D1, DX, D2, D2X, HDAV1.3 (Deluxe), Essence ST
+    (Deluxe) and Essence STX.
 
     This module supports autoprobe and multiple cards.
 
index 322869fc8a9e867e3b21073d64378c82c6e8aad7..de8e10a94103008a6f92df4ad49539a2b81d4178 100644 (file)
@@ -36,6 +36,7 @@ ALC260
   acer         Acer TravelMate
   will         Will laptops (PB V7900)
   replacer     Replacer 672V
+  favorit100   Maxdata Favorit 100XS
   basic                fixed pin assignment (old default model)
   test         for testing/debugging purpose, almost all controls can
                adjusted.  Appearing only when compiled with
@@ -85,10 +86,11 @@ ALC269
   eeepc-p703   ASUS Eeepc P703 P900A
   eeepc-p901   ASUS Eeepc P901 S101
   fujitsu      FSC Amilo
+  lifebook     Fujitsu Lifebook S6420
   auto         auto-config reading BIOS (default)
 
-ALC662/663
-==========
+ALC662/663/272
+==============
   3stack-dig   3-stack (2-channel) with SPDIF
   3stack-6ch    3-stack (6-channel)
   3stack-6ch-dig 3-stack (6-channel) with SPDIF
@@ -107,6 +109,9 @@ ALC662/663
   asus-mode4   ASUS
   asus-mode5   ASUS
   asus-mode6   ASUS
+  dell         Dell with ALC272
+  dell-zm1     Dell ZM1 with ALC272
+  samsung-nc10 Samsung NC10 mini notebook
   auto         auto-config reading BIOS (default)
 
 ALC882/885
@@ -118,6 +123,7 @@ ALC882/885
   asus-a7j     ASUS A7J
   asus-a7m     ASUS A7M
   macpro       MacPro support
+  mb5          Macbook 5,1
   mbp3         Macbook Pro rev3
   imac24       iMac 24'' with jack detection
   w2jc         ASUS W2JC
@@ -133,10 +139,12 @@ ALC883/888
   acer         Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc)
   acer-aspire  Acer Aspire 9810
   acer-aspire-4930g Acer Aspire 4930G
+  acer-aspire-8930g Acer Aspire 8930G
   medion       Medion Laptops
   medion-md2   Medion MD2
   targa-dig    Targa/MSI
-  targa-2ch-dig        Targs/MSI with 2-channel
+  targa-2ch-dig        Targa/MSI with 2-channel
+  targa-8ch-dig Targa/MSI with 8-channel (MSI GX620)
   laptop-eapd   3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE)
   lenovo-101e  Lenovo 101E
   lenovo-nb0763        Lenovo NB0763
@@ -150,6 +158,9 @@ ALC883/888
   fujitsu-pi2515 Fujitsu AMILO Pi2515
   fujitsu-xa3530 Fujitsu AMILO XA3530
   3stack-6ch-intel Intel DG33* boards
+  asus-p5q     ASUS P5Q-EM boards
+  mb31         MacBook 3,1
+  sony-vaio-tt  Sony VAIO TT
   auto         auto-config reading BIOS (default)
 
 ALC861/660
@@ -348,6 +359,7 @@ STAC92HD71B*
   hp-m4                HP mini 1000
   hp-dv5       HP dv series
   hp-hdx       HP HDX series
+  hp-dv4-1222nr        HP dv4-1222nr (with LED support)
   auto         BIOS setup (default)
 
 STAC92HD73*
index 88b7433d2f117900e8c21823cc6917c736cb8e4e..71ac995b19151f71a691cb444e97275c0f1cf49c 100644 (file)
@@ -16,7 +16,7 @@ methods for the       HD-audio hardware.
 The HD-audio component consists of two parts: the controller chip and 
 the codec chips on the HD-audio bus.  Linux provides a single driver
 for all controllers, snd-hda-intel.  Although the driver name contains
-a word of a well-known harware vendor, it's not specific to it but for
+a word of a well-known hardware vendor, it's not specific to it but for
 all controller chips by other companies.  Since the HD-audio
 controllers are supposed to be compatible, the single snd-hda-driver
 should work in most cases.  But, not surprisingly, there are known
index cfac20cf9e33fa150a6cf69f4e6d624e8116caa9..381908d8ca4231dde74f5c138b200782036760c1 100644 (file)
@@ -88,26 +88,34 @@ card*/pcm*/info
        substreams, etc.
 
 card*/pcm*/xrun_debug
-       This file appears when CONFIG_SND_DEBUG=y.
-       This shows the status of xrun (= buffer overrun/xrun) debug of
-       ALSA PCM middle layer, as an integer from 0 to 2.  The value
-       can be changed by writing to this file, such as
-
-                # cat 2 > /proc/asound/card0/pcm0p/xrun_debug
-
-       When this value is greater than 0, the driver will show the
-       messages to kernel log when an xrun is detected.  The debug
-       message is shown also when the invalid H/W pointer is detected
-       at the update of periods (usually called from the interrupt
+       This file appears when CONFIG_SND_DEBUG=y and
+       CONFIG_PCM_XRUN_DEBUG=y.
+       This shows the status of xrun (= buffer overrun/xrun) and
+       invalid PCM position debug/check of ALSA PCM middle layer.
+       It takes an integer value, can be changed by writing to this
+       file, such as
+
+                # cat 5 > /proc/asound/card0/pcm0p/xrun_debug
+
+       The value consists of the following bit flags:
+         bit 0 = Enable XRUN/jiffies debug messages
+         bit 1 = Show stack trace at XRUN / jiffies check
+         bit 2 = Enable additional jiffies check
+
+       When the bit 0 is set, the driver will show the messages to
+       kernel log when an xrun is detected.  The debug message is
+       shown also when the invalid H/W pointer is detected at the
+       update of periods (usually called from the interrupt
        handler).
 
-       When this value is greater than 1, the driver will show the
-       stack trace additionally.  This may help the debugging.
+       When the bit 1 is set, the driver will show the stack trace
+       additionally.  This may help the debugging.
 
-       Since 2.6.30, this option also enables the hwptr check using
+       Since 2.6.30, this option can enable the hwptr check using
        jiffies.  This detects spontaneous invalid pointer callback
        values, but can be lead to too much corrections for a (mostly
        buggy) hardware that doesn't give smooth pointer updates.
+       This feature is enabled via the bit 2.
 
 card*/pcm*/sub*/info
        The general information of this PCM sub-stream.
diff --git a/Documentation/sound/alsa/README.maya44 b/Documentation/sound/alsa/README.maya44
new file mode 100644 (file)
index 0000000..0e41576
--- /dev/null
@@ -0,0 +1,163 @@
+NOTE: The following is the original document of Rainer's patch that the
+current maya44 code based on.  Some contents might be obsoleted, but I
+keep here as reference -- tiwai
+
+----------------------------------------------------------------
+STATE OF DEVELOPMENT:
+
+This driver is being developed on the initiative of Piotr Makowski (oponek@gmail.com) and financed by Lars Bergmann.
+Development is carried out by Rainer Zimmermann (mail@lightshed.de).
+
+ESI provided a sample Maya44 card for the development work.
+
+However, unfortunately it has turned out difficult to get detailed programming information, so I (Rainer Zimmermann) had to find out some card-specific information by experiment and conjecture. Some information (in particular, several GPIO bits) is still missing.
+
+This is the first testing version of the Maya44 driver released to the alsa-devel mailing list (Feb 5, 2008).
+
+
+The following functions work, as tested by Rainer Zimmermann and Piotr Makowski:
+
+- playback and capture at all sampling rates
+- input/output level
+- crossmixing
+- line/mic switch
+- phantom power switch
+- analogue monitor a.k.a bypass
+
+
+The following functions *should* work, but are not fully tested:
+
+- Channel 3+4 analogue - S/PDIF input switching
+- S/PDIF output
+- all inputs/outputs on the M/IO/DIO extension card
+- internal/external clock selection
+
+
+*In particular, we would appreciate testing of these functions by anyone who has access to an M/IO/DIO extension card.*
+
+
+Things that do not seem to work:
+
+- The level meters ("multi track") in 'alsamixer' do not seem to react to signals in (if this is a bug, it would probably be in the existing ICE1724 code).
+
+- Ardour 2.1 seems to work only via JACK, not using ALSA directly or via OSS. This still needs to be tracked down.
+
+
+DRIVER DETAILS:
+
+the following files were added:
+
+pci/ice1724/maya44.c        - Maya44 specific code
+pci/ice1724/maya44.h
+pci/ice1724/ice1724.patch
+pci/ice1724/ice1724.h.patch - PROPOSED patch to ice1724.h (see SAMPLING RATES)
+i2c/other/wm8776.c  - low-level access routines for Wolfson WM8776 codecs 
+include/wm8776.h
+
+
+Note that the wm8776.c code is meant to be card-independent and does not actually register the codec with the ALSA infrastructure.
+This is done in maya44.c, mainly because some of the WM8776 controls are used in Maya44-specific ways, and should be named appropriately.
+
+
+the following files were created in pci/ice1724, simply #including the corresponding file from the alsa-kernel tree:
+
+wtm.h
+vt1720_mobo.h
+revo.h
+prodigy192.h
+pontis.h
+phase.h
+maya44.h
+juli.h
+aureon.h
+amp.h
+envy24ht.h
+se.h
+prodigy_hifi.h
+
+
+*I hope this is the correct way to do things.*
+
+
+SAMPLING RATES:
+
+The Maya44 card (or more exactly, the Wolfson WM8776 codecs) allow a maximum sampling rate of 192 kHz for playback and 92 kHz for capture.
+
+As the ICE1724 chip only allows one global sampling rate, this is handled as follows:
+
+* setting the sampling rate on any open PCM device on the maya44 card will always set the *global* sampling rate for all playback and capture channels.
+
+* In the current state of the driver, setting rates of up to 192 kHz is permitted even for capture devices.
+
+*AVOID CAPTURING AT RATES ABOVE 96kHz*, even though it may appear to work. The codec cannot actually capture at such rates, meaning poor quality.
+
+
+I propose some additional code for limiting the sampling rate when setting on a capture pcm device. However because of the global sampling rate, this logic would be somewhat problematic.
+
+The proposed code (currently deactivated) is in ice1712.h.patch, ice1724.c and maya44.c (in pci/ice1712).
+
+
+SOUND DEVICES:
+
+PCM devices correspond to inputs/outputs as follows (assuming Maya44 is card #0):
+
+hw:0,0 input - stereo, analog input 1+2
+hw:0,0 output - stereo, analog output 1+2
+hw:0,1 input - stereo, analog input 3+4 OR S/PDIF input
+hw:0,1 output - stereo, analog output 3+4 (and SPDIF out)
+
+
+NAMING OF MIXER CONTROLS:
+
+(for more information about the signal flow, please refer to the block diagram on p.24 of the ESI Maya44 manual, or in the ESI windows software).
+
+
+PCM: (digital) output level for channel 1+2
+PCM 1: same for channel 3+4
+
+Mic Phantom+48V: switch for +48V phantom power for electrostatic microphones on input 1/2.
+    Make sure this is not turned on while any other source is connected to input 1/2.
+    It might damage the source and/or the maya44 card.
+
+Mic/Line input: if switch is is on, input jack 1/2 is microphone input (mono), otherwise line input (stereo).
+
+Bypass: analogue bypass from ADC input to output for channel 1+2. Same as "Monitor" in the windows driver.
+Bypass 1: same for channel 3+4.
+
+Crossmix: cross-mixer from channels 1+2 to channels 3+4
+Crossmix 1: cross-mixer from channels 3+4 to channels 1+2
+
+IEC958 Output: switch for S/PDIF output.
+    This is not supported by the ESI windows driver.
+    S/PDIF should output the same signal as channel 3+4. [untested!]
+
+
+Digitial output selectors:
+
+    These switches allow a direct digital routing from the ADCs to the DACs.
+    Each switch determines where the digital input data to one of the DACs comes from.
+    They are not supported by the ESI windows driver.
+    For normal operation, they should all be set to "PCM out".
+
+H/W: Output source channel 1
+H/W 1: Output source channel 2
+H/W 2: Output source channel 3
+H/W 3: Output source channel 4
+
+H/W 4 ... H/W 9: unknown function, left in to enable testing.
+    Possibly some of these control S/PDIF output(s).
+    If these turn out to be unused, they will go away in later driver versions.
+
+Selectable values for each of the digital output selectors are:
+   "PCM out" -> DAC output of the corresponding channel (default setting)
+   "Input 1"...
+   "Input 4" -> direct routing from ADC output of the selected input channel
+
+
+--------
+
+Feb 14, 2008
+Rainer Zimmermann
+mail@lightshed.de
+
index 34e87ec1379c8e6af81d90608125628535ad107a..de8efbc7e4bd8fc80f2844998b08fe8362803aaa 100644 (file)
@@ -114,7 +114,7 @@ For writing a sequence of verbs, use snd_hda_sequence_write().
 
 There are variants of cached read/write, snd_hda_codec_write_cache(),
 snd_hda_sequence_write_cache().  These are used for recording the
-register states for the power-mangement resume.  When no PM is needed,
+register states for the power-management resume.  When no PM is needed,
 these are equivalent with non-cached version.
 
 To retrieve the number of sub nodes connected to the given node, use
index 9e6763264a2ee1cb5b549cc27c51f47557d3ba0d..9ac842be9b4fccff2c2841d1fd88ab4be321d467 100644 (file)
@@ -62,6 +62,7 @@ Audio DAPM widgets fall into a number of types:-
  o Mic        - Mic (and optional Jack)
  o Line       - Line Input/Output (and optional Jack)
  o Speaker    - Speaker
+ o Supply     - Power or clock supply widget used by other widgets.
  o Pre        - Special PRE widget (exec before all others)
  o Post       - Special POST widget (exec after all others)
 
index c302ddf629a0bef9d04014b7ee014acd2c092cb0..6fab2dcbb4d37f4a02accdcae64ebc8ede16cd9f 100644 (file)
@@ -358,7 +358,7 @@ nr_pdflush_threads
 The current number of pdflush threads.  This value is read-only.
 The value changes according to the number of dirty pages in the system.
 
-When neccessary, additional pdflush threads are created, one per second, up to
+When necessary, additional pdflush threads are created, one per second, up to
 nr_pdflush_threads_max.
 
 ==============================================================
@@ -565,7 +565,7 @@ swappiness
 
 This control is used to define how aggressive the kernel will swap
 memory pages.  Higher values will increase agressiveness, lower values
-descrease the amount of swap.
+decrease the amount of swap.
 
 The default value is 60.
 
index e7c09abcfab424d12f9628e06d594327cf475c93..04763a32552005b2a1956effd872db4296f77bd8 100644 (file)
@@ -7,7 +7,7 @@ by Intel and Microsoft which can be found at
 
 Each HPET has one fixed-rate counter (at 10+ MHz, hence "High Precision")
 and up to 32 comparators.  Normally three or more comparators are provided,
-each of which can generate oneshot interupts and at least one of which has
+each of which can generate oneshot interrupts and at least one of which has
 additional hardware to support periodic interrupts.  The comparators are
 also called "timers", which can be misleading since usually timers are
 independent of each other ... these share a counter, complicating resets.
index 20d368c59814206d82dfa2236bdf6764fd5bee85..9bd00fc2e8233d72699680bc6e447105fc080923 100644 (file)
@@ -62,7 +62,7 @@ Timerstats sample period: 3.888770 s
 
 The first column is the number of events, the second column the pid, the third
 column is the name of the process. The forth column shows the function which
-initialized the timer and in parantheses the callback function which was
+initialized the timer and in parenthesis the callback function which was
 executed on expiry.
 
     Thomas, Ingo
index 2a82d8602944abca930635cff44f37c52238529d..7bd27f0e288008c641c31474341a2dd84ef8bf73 100644 (file)
@@ -1834,4 +1834,4 @@ an error.
 -----------
 
 More details can be found in the source code, in the
-kernel/tracing/*.c files.
+kernel/trace/*.c files.
index a956d9b7f943231284aa16e5eecc2acb35586766..6308735e58ca213d7bb06ad47df7dca371f256f7 100644 (file)
@@ -64,7 +64,7 @@ III. Quick usage guide
 CONFIG_KMEMTRACE).
 
 2) Get the userspace tool and build it:
-$ git-clone git://repo.or.cz/kmemtrace-user.git                # current repository
+$ git clone git://repo.or.cz/kmemtrace-user.git                # current repository
 $ cd kmemtrace-user/
 $ ./autogen.sh
 $ ./configure
index 4c3d62c7843acf694fa376444380d3e48a8c2f2e..c480e9c32dbd2df8a93851259d6e6b4f133d12c5 100644 (file)
@@ -84,7 +84,7 @@ The different logical parts of this driver are:
 
       *UWB*: the Ultra-Wide-Band stack -- manages the radio and
       associated spectrum to allow for devices sharing it. Allows to
-      control bandwidth assingment, beaconing, scanning, etc
+      control bandwidth assignment, beaconing, scanning, etc
 
     *
 
@@ -184,7 +184,7 @@ and sends the replies and notifications back to the API
 [/uwb_rc_neh_grok()/]. Notifications are handled to the UWB daemon, that
 is chartered, among other things, to keep the tab of how the UWB radio
 neighborhood looks, creating and destroying devices as they show up or
-dissapear.
+disappear.
 
 Command execution is very simple: a command block is sent and a event
 block or reply is expected back. For sending/receiving command/events, a
@@ -333,7 +333,7 @@ read descriptors and move our data.
 
 *Device life cycle and keep alives*
 
-Everytime there is a succesful transfer to/from a device, we update a
+Every time there is a successful transfer to/from a device, we update a
 per-device activity timestamp. If not, every now and then we check and
 if the activity timestamp gets old, we ping the device by sending it a
 Keep Alive IE; it responds with a /DN_Alive/ pong during the DNTS (this
@@ -411,7 +411,7 @@ context (wa_xfer) and submit it. When the xfer is done, our callback is
 called and we assign the status bits and release the xfer resources.
 
 In dequeue() we are basically cancelling/aborting the transfer. We issue
-a xfer abort request to the HC, cancell all the URBs we had submitted
+a xfer abort request to the HC, cancel all the URBs we had submitted
 and not yet done and when all that is done, the xfer callback will be
 called--this will call the URB callback.
 
index 6f24f566955ada1439c0f34acb0a6c4e1573d704..fe6a99a32bbd9ec4de38711be9c5e4cd1473d565 100644 (file)
@@ -27,7 +27,7 @@ Association and disassociation of URBs with anchors
 
 An association of URBs to an anchor is made by an explicit
 call to usb_anchor_urb(). The association is maintained until
-an URB is finished by (successfull) completion. Thus disassociation
+an URB is finished by (successful) completion. Thus disassociation
 is automatic. A function is provided to forcibly finish (kill)
 all URBs associated with an anchor.
 Furthermore, disassociation can be made with usb_unanchor_urb()
@@ -76,4 +76,4 @@ usb_get_from_anchor()
 Returns the oldest anchored URB of an anchor. The URB is unanchored
 and returned with a reference. As you may mix URBs to several
 destinations in one anchor you have no guarantee the chronologically
-first submitted URB is returned.
\ No newline at end of file
+first submitted URB is returned.
index 7c812411945b5e14d919911b7fad8ca79e897501..bfb36b34b79e41f427702542252b27e4bfd08a1d 100644 (file)
@@ -65,7 +65,7 @@ Accept or decline an interface. If you accept the device return 0,
 otherwise -ENODEV or -ENXIO. Other error codes should be used only if a
 genuine error occurred during initialisation which prevented a driver
 from accepting a device that would else have been accepted.
-You are strongly encouraged to use usbcore'sfacility,
+You are strongly encouraged to use usbcore's facility,
 usb_set_intfdata(), to associate a data structure with an interface, so
 that you know which internal state and identity you associate with a
 particular interface. The device will not be suspended and you may do IO
index 914cb7e734a20b773709cb067804e07576881097..4652c0f5da327f715fb22a03328c9d8e4db6dc60 100644 (file)
@@ -11,7 +11,7 @@ encoder chip:
 2) Some people have problems getting the i2c bus to work.
    The symptom is that the eeprom cannot be read and the card is
    unusable. This is probably fixed, but if you have problems
-   then post to the video4linux or ivtv-users mailinglist.
+   then post to the video4linux or ivtv-users mailing list.
 
 3) VBI (raw or sliced) has not yet been implemented.
 
index 2db5893d6c97234ded88dbc8b52daaa8defc3af4..29a6ff8bc7d34f02c99c402e048851ab3715a995 100644 (file)
@@ -5,21 +5,51 @@ only the AMD64 specific ones are listed here.
 
 Machine check
 
-   mce=off disable machine check
-   mce=bootlog Enable logging of machine checks left over from booting.
-               Disabled by default on AMD because some BIOS leave bogus ones.
-               If your BIOS doesn't do that it's a good idea to enable though
-               to make sure you log even machine check events that result
-               in a reboot. On Intel systems it is enabled by default.
+   Please see Documentation/x86/x86_64/machinecheck for sysfs runtime tunables.
+
+   mce=off
+               Disable machine check
+   mce=no_cmci
+               Disable CMCI(Corrected Machine Check Interrupt) that
+               Intel processor supports.  Usually this disablement is
+               not recommended, but it might be handy if your hardware
+               is misbehaving.
+               Note that you'll get more problems without CMCI than with
+               due to the shared banks, i.e. you might get duplicated
+               error logs.
+   mce=dont_log_ce
+               Don't make logs for corrected errors.  All events reported
+               as corrected are silently cleared by OS.
+               This option will be useful if you have no interest in any
+               of corrected errors.
+   mce=ignore_ce
+               Disable features for corrected errors, e.g. polling timer
+               and CMCI.  All events reported as corrected are not cleared
+               by OS and remained in its error banks.
+               Usually this disablement is not recommended, however if
+               there is an agent checking/clearing corrected errors
+               (e.g. BIOS or hardware monitoring applications), conflicting
+               with OS's error handling, and you cannot deactivate the agent,
+               then this option will be a help.
+   mce=bootlog
+               Enable logging of machine checks left over from booting.
+               Disabled by default on AMD because some BIOS leave bogus ones.
+               If your BIOS doesn't do that it's a good idea to enable though
+               to make sure you log even machine check events that result
+               in a reboot. On Intel systems it is enabled by default.
    mce=nobootlog
                Disable boot machine check logging.
-   mce=tolerancelevel (number)
+   mce=tolerancelevel[,monarchtimeout] (number,number)
+               tolerance levels:
                0: always panic on uncorrected errors, log corrected errors
                1: panic or SIGBUS on uncorrected errors, log corrected errors
                2: SIGBUS or log uncorrected errors, log corrected errors
                3: never panic or SIGBUS, log all errors (for testing only)
                Default is 1
                Can be also set using sysfs which is preferable.
+               monarchtimeout:
+               Sets the time in us to wait for other CPUs on machine checks. 0
+               to disable.
 
    nomce (for compatibility with i386): same as mce=off
 
index a05e58e7b159b4dda2910eab39b6372b648f3c19..b1fb30273286c7ae6878f6b43fecb6df8f8f1603 100644 (file)
@@ -41,7 +41,9 @@ check_interval
        the polling interval.  When the poller stops finding MCEs, it
        triggers an exponential backoff (poll less often) on the polling
        interval. The check_interval variable is both the initial and
-       maximum polling interval.
+       maximum polling interval. 0 means no polling for corrected machine
+       check errors (but some corrected errors might be still reported
+       in other ways)
 
 tolerant
        Tolerance level. When a machine check exception occurs for a non
@@ -67,6 +69,10 @@ trigger
        Program to run when a machine check event is detected.
        This is an alternative to running mcelog regularly from cron
        and allows to detect events faster.
+monarch_timeout
+       How long to wait for the other CPUs to machine check too on a
+       exception. 0 to disable waiting for other CPUs.
+       Unit: us
 
 TBD document entries for AMD threshold interrupt configuration
 
index 358c5807adf7117c5714d5d9382d9775fcfc1790..22a91178148bee4731f3192478ac214ee773a8c4 100644 (file)
@@ -681,6 +681,13 @@ M: sakoman@gmail.com
 L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
 S:     Maintained
 
+ARM/H4700 (HP IPAQ HX4700) MACHINE SUPPORT
+P:     Philipp Zabel
+M:     philipp.zabel@gmail.com
+S:     Maintained
+F:     arch/arm/mach-pxa/hx4700.c
+F:     arch/arm/mach-pxa/include/mach/hx4700.h
+
 ARM/HP JORNADA 7XX MACHINE SUPPORT
 P:     Kristoffer Ericson
 M:     kristoffer.ericson@gmail.com
@@ -2105,6 +2112,15 @@ W:       http://sourceforge.net/projects/lpfcxxxx
 S:     Supported
 F:     drivers/scsi/lpfc/
 
+ENE CB710 FLASH CARD READER DRIVER
+P:     MichaÅ‚ MirosÅ‚aw
+M:     mirq-linux@rere.qmqm.pl
+L:     linux-kernel@vger.kernel.org
+S:     Maintained
+F:     drivers/misc/cb710/
+F:     drivers/mmc/host/cb710-mmc.*
+F:     include/linux/cb710.h
+
 EPSON 1355 FRAMEBUFFER DRIVER
 P:     Christopher Hoover
 M:     ch@murgatroid.com
@@ -2351,7 +2367,7 @@ F:        fs/freevxfs/
 
 FREEZER
 P:     Pavel Machek
-M:     pavel@suse.cz
+M:     pavel@ucw.cz
 P:     Rafael J. Wysocki
 M:     rjw@sisk.pl
 L:     linux-pm@lists.linux-foundation.org
@@ -3376,6 +3392,10 @@ P:       Catalin Marinas
 M:     catalin.marinas@arm.com
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
+F:     Documentation/kmemleak.txt
+F:     include/linux/kmemleak.h
+F:     mm/kmemleak.c
+F:     mm/kmemleak-test.c
 
 KMEMTRACE
 P:     Eduard - Gabriel Munteanu
@@ -4163,6 +4183,69 @@ S:       Maintained
 F:     drivers/video/riva/
 F:     drivers/video/nvidia/
 
+OMAP SUPPORT
+P:     Tony Lindgren <tony@atomide.com>
+M:     tony@atomide.com
+L:     linux-omap@vger.kernel.org
+W:     http://www.muru.com/linux/omap/
+W:     http://linux.omap.com/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap-2.6.git
+S:     Maintained
+F:     arch/arm/*omap*
+
+OMAP CLOCK FRAMEWORK SUPPORT
+P:     Paul Walmsley
+M:     paul@pwsan.com
+L:     linux-omap@vger.kernel.org
+S:     Maintained
+F:     arch/arm/*omap*/*clock*
+
+OMAP POWER MANAGEMENT SUPPORT
+P:     Kevin Hilman
+M:     khilman@deeprootsystems.com
+L:     linux-omap@vger.kernel.org
+S:     Maintained
+F:     arch/arm/*omap*/*pm*
+
+OMAP AUDIO SUPPORT
+P:     Jarkko Nikula
+M:     jhnikula@gmail.com
+L:     alsa-devel@alsa-project.org (subscribers-only)
+L:     linux-omap@vger.kernel.org
+S:     Maintained
+F:     sound/soc/omap/
+
+OMAP FRAMEBUFFER SUPPORT
+P:     Imre Deak
+M:     imre.deak@nokia.com
+L:     linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
+L:     linux-omap@vger.kernel.org
+S:     Maintained
+F:     drivers/video/omap/
+
+OMAP MMC SUPPORT
+P:     Jarkko Lavinen
+M:     jarkko.lavinen@nokia.com
+L:     linux-kernel@vger.kernel.org
+L:     linux-omap@vger.kernel.org
+S:     Maintained
+F:     drivers/mmc/host/*omap*
+
+OMAP RANDOM NUMBER GENERATOR SUPPORT
+P:     Deepak Saxena
+M:     dsaxena@plexity.net
+S:     Maintained
+F:     drivers/char/hw_random/omap-rng.c
+
+OMAP USB SUPPORT
+P:     Felipe Balbi
+M:     felipe.balbi@nokia.com
+P:     David Brownell
+M:     dbrownell@users.sourceforge.net
+L:     linux-usb@vger.kernel.org
+L:     linux-omap@vger.kernel.org
+S:     Maintained
+
 OMFS FILESYSTEM
 P:     Bob Copeland
 M:     me@bobcopeland.com
@@ -4601,7 +4684,7 @@ F:        drivers/media/video/pvrusb2/
 
 PXA2xx/PXA3xx SUPPORT
 P:     Eric Miao
-M:     eric.miao@marvell.com
+M:     eric.y.miao@gmail.com
 P:     Russell King
 M:     linux@arm.linux.org.uk
 L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
@@ -4611,23 +4694,24 @@ F:      drivers/pcmcia/pxa2xx*
 F:     drivers/spi/pxa2xx*
 F:     drivers/usb/gadget/pxa2*
 F:     include/sound/pxa2xx-lib.h
-F:     sound/soc/pxa/pxa2xx*
+F:     sound/arm/pxa*
+F:     sound/soc/pxa
 
 PXA168 SUPPORT
 P:     Eric Miao
-M:     eric.miao@marvell.com
+M:     eric.y.miao@gmail.com
 P:     Jason Chagas
 M:     jason.chagas@marvell.com
 L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ycmiao/pxa-linux-2.6.git
-S:     Supported
+S:     Maintained
 
 PXA910 SUPPORT
 P:     Eric Miao
-M:     eric.miao@marvell.com
+M:     eric.y.miao@gmail.com
 L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ycmiao/pxa-linux-2.6.git
-S:     Supported
+S:     Maintained
 
 PXA MMCI DRIVER
 S:     Orphan
@@ -5148,7 +5232,6 @@ P:        Vincent Sanders
 M:     support@simtec.co.uk
 W:     http://www.simtec.co.uk/products/EB110ATX/
 S:     Supported
-F:     arch/arm/mach-ebsa110/
 
 SIMTEC EB2410ITX (BAST)
 P:     Ben Dooks
@@ -5339,11 +5422,12 @@ P:      Liam Girdwood
 M:     lrg@slimlogic.co.uk
 P:     Mark Brown
 M:     broonie@opensource.wolfsonmicro.com
-T:     git git://opensource.wolfsonmicro.com/linux-2.6-asoc
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git
 L:     alsa-devel@alsa-project.org (subscribers-only)
 W:     http://alsa-project.org/main/index.php/ASoC
 S:     Supported
 F:     sound/soc/
+F:     include/sound/soc*
 
 SPARC + UltraSPARC (sparc/sparc64)
 P:     David S. Miller
@@ -5561,20 +5645,6 @@ F:       drivers/misc/tifm*
 F:     drivers/mmc/host/tifm_sd.c
 F:     include/linux/tifm.h
 
-TI OMAP MMC INTERFACE DRIVER
-P:     Carlos Aguiar, Anderson Briglia and Syed Khasim
-M:     linux-omap@vger.kernel.org
-W:     http://linux.omap.com
-W:     http://www.muru.com/linux/omap/
-S:     Maintained
-F:     drivers/mmc/host/omap.c
-
-TI OMAP RANDOM NUMBER GENERATOR SUPPORT
-P:     Deepak Saxena
-M:     dsaxena@plexity.net
-S:     Maintained
-F:     drivers/char/hw_random/omap-rng.c
-
 TIPC NETWORK LAYER
 P:     Per Liden
 M:     per.liden@ericsson.com
index 03373bb703ca9cd4d8cde6403502357815b7e531..ea63667617f3543220eb4ffae6c915cfeb6aea3f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -35,10 +35,8 @@ MAKEFLAGS += -rR --no-print-directory
 # To put more focus on warnings, be less verbose as default
 # Use 'make V=1' to see the full commands
 
-ifdef V
-  ifeq ("$(origin V)", "command line")
-    KBUILD_VERBOSE = $(V)
-  endif
+ifeq ("$(origin V)", "command line")
+  KBUILD_VERBOSE = $(V)
 endif
 ifndef KBUILD_VERBOSE
   KBUILD_VERBOSE = 0
@@ -54,10 +52,8 @@ endif
 # See the file "Documentation/sparse.txt" for more details, including
 # where to get the "sparse" utility.
 
-ifdef C
-  ifeq ("$(origin C)", "command line")
-    KBUILD_CHECKSRC = $(C)
-  endif
+ifeq ("$(origin C)", "command line")
+  KBUILD_CHECKSRC = $(C)
 endif
 ifndef KBUILD_CHECKSRC
   KBUILD_CHECKSRC = 0
@@ -69,12 +65,10 @@ endif
 ifdef SUBDIRS
   KBUILD_EXTMOD ?= $(SUBDIRS)
 endif
-ifdef M
-  ifeq ("$(origin M)", "command line")
-    KBUILD_EXTMOD := $(M)
-  endif
-endif
 
+ifeq ("$(origin M)", "command line")
+  KBUILD_EXTMOD := $(M)
+endif
 
 # kbuild supports saving output files in a separate directory.
 # To locate output files in a separate directory two syntaxes are supported.
@@ -98,10 +92,8 @@ ifeq ($(KBUILD_SRC),)
 
 # OK, Make called in directory where kernel src resides
 # Do we want to locate output files in a separate directory?
-ifdef O
-  ifeq ("$(origin O)", "command line")
-    KBUILD_OUTPUT := $(O)
-  endif
+ifeq ("$(origin O)", "command line")
+  KBUILD_OUTPUT := $(O)
 endif
 
 # That's our default target when none is given on the command line
diff --git a/README b/README
index d6c6c742c1d78aea9f64e4307e36e06a2a0959da..737838fe73cce73cc3be8b7c797156d6497a8b16 100644 (file)
--- a/README
+++ b/README
@@ -174,8 +174,17 @@ CONFIGURING the kernel:
        "make silentoldconfig"
                           Like above, but avoids cluttering the screen
                           with questions already answered.
+                          Additionally updates the dependencies.
        "make defconfig"   Create a ./.config file by using the default
-                          symbol values from arch/$ARCH/defconfig.
+                          symbol values from either arch/$ARCH/defconfig
+                          or arch/$ARCH/configs/${PLATFORM}_defconfig,
+                          depending on the architecture.
+       "make ${PLATFORM}_defconfig"
+                         Create a ./.config file by using the default
+                         symbol values from
+                         arch/$ARCH/configs/${PLATFORM}_defconfig.
+                         Use "make help" to get a list of all available
+                         platforms of your architecture.
        "make allyesconfig"
                           Create a ./.config file by setting symbol
                           values to 'y' as much as possible.
index 62b363584b2bda3761263d53a7cd17c30890debe..610dff44d94b9bfae101f76149f965b4400d07ff 100644 (file)
@@ -256,5 +256,5 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
 #define smp_mb__before_atomic_inc()    smp_mb()
 #define smp_mb__after_atomic_inc()     smp_mb()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* _ALPHA_ATOMIC_H */
diff --git a/arch/alpha/include/asm/bitsperlong.h b/arch/alpha/include/asm/bitsperlong.h
new file mode 100644 (file)
index 0000000..ad57f78
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __ASM_ALPHA_BITSPERLONG_H
+#define __ASM_ALPHA_BITSPERLONG_H
+
+#define __BITS_PER_LONG 64
+
+#include <asm-generic/bitsperlong.h>
+
+#endif /* __ASM_ALPHA_BITSPERLONG_H */
index 0995f9d13417241e283cad83bd4f0729af014c66..07af062544fb75fd68866e05d4983850863b0f45 100644 (file)
@@ -93,6 +93,6 @@ typedef struct page *pgtable_t;
                                         VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
 #include <asm-generic/memory_model.h>
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* _ALPHA_PAGE_H */
index 13c2305d35ef781b2f784ea553856c53c3ee28fc..a9388300abb13b75c2d9cdbbfc0f682ba2465e00 100644 (file)
@@ -111,7 +111,7 @@ typedef unsigned long sigset_t;
 #define SIG_UNBLOCK        2   /* for unblocking signals */
 #define SIG_SETMASK        3   /* for setting the signal mask */
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 #ifdef __KERNEL__
 struct osf_sigaction {
diff --git a/arch/alpha/include/asm/suspend.h b/arch/alpha/include/asm/suspend.h
deleted file mode 100644 (file)
index c7042d5..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ALPHA_SUSPEND_H
-#define __ALPHA_SUSPEND_H
-
-/* Dummy include. */
-
-#endif  /* __ALPHA_SUSPEND_H */
index f072f344497e7adba62719db66324bb11144c5ae..bd621ecd1eb33a21516af7ac6c3629b0f098e65b 100644 (file)
@@ -25,9 +25,6 @@ typedef unsigned int umode_t;
  * These aren't exported outside the kernel to avoid name space clashes
  */
 #ifdef __KERNEL__
-
-#define BITS_PER_LONG 64
-
 #ifndef __ASSEMBLY__
 
 typedef u64 dma_addr_t;
index 62dc379d301af9f1f00e824a2088eb487f77f39f..813c9b63c0e17de3577b5924b54072ad382244d9 100644 (file)
@@ -48,6 +48,27 @@ void sort_extable(struct exception_table_entry *start,
             cmp_ex, swap_ex);
 }
 
+#ifdef CONFIG_MODULES
+/*
+ * Any entry referring to the module init will be at the beginning or
+ * the end.
+ */
+void trim_init_extable(struct module *m)
+{
+       /*trim the beginning*/
+       while (m->num_exentries &&
+              within_module_init(ex_to_addr(&m->extable[0]), m)) {
+               m->extable++;
+               m->num_exentries--;
+       }
+       /*trim the end*/
+       while (m->num_exentries &&
+              within_module_init(ex_to_addr(&m->extable[m->num_exentries-1]),
+                                 m))
+               m->num_exentries--;
+}
+#endif /* CONFIG_MODULES */
+
 const struct exception_table_entry *
 search_extable(const struct exception_table_entry *first,
               const struct exception_table_entry *last,
index 9d02cdb15b23dc6d4524cf61db4153c810639580..29475101a7b38adfb5de3c68e446f64d623a7f68 100644 (file)
@@ -34,15 +34,12 @@ config SYS_SUPPORTS_APM_EMULATION
 
 config GENERIC_GPIO
        bool
-       default n
 
 config GENERIC_TIME
        bool
-       default n
 
 config GENERIC_CLOCKEVENTS
        bool
-       default n
 
 config GENERIC_CLOCKEVENTS_BROADCAST
        bool
@@ -55,7 +52,6 @@ config MMU
 
 config NO_IOPORT
        bool
-       default n
 
 config EISA
        bool
@@ -126,11 +122,9 @@ config RWSEM_XCHGADD_ALGORITHM
 
 config ARCH_HAS_ILOG2_U32
        bool
-       default n
 
 config ARCH_HAS_ILOG2_U64
        bool
-       default n
 
 config GENERIC_HWEIGHT
        bool
@@ -253,6 +247,14 @@ config ARCH_CLPS711X
        help
          Support for Cirrus Logic 711x/721x based boards.
 
+config ARCH_GEMINI
+       bool "Cortina Systems Gemini"
+       select CPU_FA526
+       select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
+       help
+         Support for the Cortina Systems Gemini family SoCs
+
 config ARCH_EBSA110
        bool "EBSA-110"
        select CPU_SA110
@@ -277,14 +279,6 @@ config ARCH_EP93XX
        help
          This enables support for the Cirrus EP93xx series of CPUs.
 
-config ARCH_GEMINI
-       bool "Cortina Systems Gemini"
-       select CPU_FA526
-       select GENERIC_GPIO
-       select ARCH_REQUIRE_GPIOLIB
-       help
-         Support for the Cortina Systems Gemini family SoCs
-
 config ARCH_FOOTBRIDGE
        bool "FootBridge"
        select CPU_SA110
@@ -293,6 +287,30 @@ config ARCH_FOOTBRIDGE
          Support for systems based on the DC21285 companion chip
          ("FootBridge"), such as the Simtec CATS and the Rebel NetWinder.
 
+config ARCH_MXC
+       bool "Freescale MXC/iMX-based"
+       select GENERIC_TIME
+       select GENERIC_CLOCKEVENTS
+       select ARCH_MTD_XIP
+       select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
+       select HAVE_CLK
+       help
+         Support for Freescale MXC/iMX-based family of processors
+
+config ARCH_STMP3XXX
+       bool "Freescale STMP3xxx"
+       select CPU_ARM926T
+       select HAVE_CLK
+       select COMMON_CLKDEV
+       select ARCH_REQUIRE_GPIOLIB
+       select GENERIC_TIME
+       select GENERIC_CLOCKEVENTS
+       select GENERIC_GPIO
+       select USB_ARCH_HAS_EHCI
+       help
+         Support for systems based on the Freescale 3xxx CPUs.
+
 config ARCH_NETX
        bool "Hilscher NetX based"
        select CPU_ARM926T
@@ -309,15 +327,6 @@ config ARCH_H720X
        help
          This enables support for systems based on the Hynix HMS720x
 
-config ARCH_IMX
-       bool "IMX"
-       select CPU_ARM920T
-       select GENERIC_GPIO
-       select GENERIC_TIME
-       select GENERIC_CLOCKEVENTS
-       help
-         Support for Motorola's i.MX family of processors (MX1, MXL).
-
 config ARCH_IOP13XX
        bool "IOP13xx-based"
        depends on MMU
@@ -398,6 +407,7 @@ config ARCH_KIRKWOOD
        select CPU_FEROCEON
        select PCI
        select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
        select PLAT_ORION
@@ -405,28 +415,6 @@ config ARCH_KIRKWOOD
          Support for the following Marvell Kirkwood series SoCs:
          88F6180, 88F6192 and 88F6281.
 
-config ARCH_KS8695
-       bool "Micrel/Kendin KS8695"
-       select CPU_ARM922T
-       select GENERIC_GPIO
-        select ARCH_REQUIRE_GPIOLIB
-       help
-         Support for Micrel/Kendin KS8695 "Centaur" (ARM922T) based
-         System-on-Chip devices.
-
-config ARCH_NS9XXX
-       bool "NetSilicon NS9xxx"
-       select CPU_ARM926T
-       select GENERIC_GPIO
-       select GENERIC_TIME
-       select GENERIC_CLOCKEVENTS
-       select HAVE_CLK
-       help
-         Say Y here if you intend to run this kernel on a NetSilicon NS9xxx
-         System.
-
-         <http://www.digi.com/products/microprocessors/index.jsp>
-
 config ARCH_LOKI
        bool "Marvell Loki (88RC8480)"
        select CPU_FEROCEON
@@ -441,6 +429,7 @@ config ARCH_MV78XX0
        select CPU_FEROCEON
        select PCI
        select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
        select PLAT_ORION
@@ -448,23 +437,13 @@ config ARCH_MV78XX0
          Support for the following Marvell MV78xx0 series SoCs:
          MV781x0, MV782x0.
 
-config ARCH_MXC
-       bool "Freescale MXC/iMX-based"
-       select GENERIC_TIME
-       select GENERIC_CLOCKEVENTS
-       select ARCH_MTD_XIP
-       select GENERIC_GPIO
-       select ARCH_REQUIRE_GPIOLIB
-       select HAVE_CLK
-       help
-         Support for Freescale MXC/iMX-based family of processors
-
 config ARCH_ORION5X
        bool "Marvell Orion"
        depends on MMU
        select CPU_FEROCEON
        select PCI
        select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
        select PLAT_ORION
@@ -473,6 +452,52 @@ config ARCH_ORION5X
          Orion-1 (5181), Orion-VoIP (5181L), Orion-NAS (5182),
          Orion-2 (5281), Orion-1-90 (6183).
 
+config ARCH_MMP
+       bool "Marvell PXA168/910"
+       depends on MMU
+       select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
+       select HAVE_CLK
+       select COMMON_CLKDEV
+       select GENERIC_TIME
+       select GENERIC_CLOCKEVENTS
+       select TICK_ONESHOT
+       select PLAT_PXA
+       help
+         Support for Marvell's PXA168/910 processor line.
+
+config ARCH_KS8695
+       bool "Micrel/Kendin KS8695"
+       select CPU_ARM922T
+       select GENERIC_GPIO
+        select ARCH_REQUIRE_GPIOLIB
+       help
+         Support for Micrel/Kendin KS8695 "Centaur" (ARM922T) based
+         System-on-Chip devices.
+
+config ARCH_NS9XXX
+       bool "NetSilicon NS9xxx"
+       select CPU_ARM926T
+       select GENERIC_GPIO
+       select GENERIC_TIME
+       select GENERIC_CLOCKEVENTS
+       select HAVE_CLK
+       help
+         Say Y here if you intend to run this kernel on a NetSilicon NS9xxx
+         System.
+
+         <http://www.digi.com/products/microprocessors/index.jsp>
+
+config ARCH_W90X900
+       bool "Nuvoton W90X900 CPU"
+       select CPU_ARM926T
+       select ARCH_REQUIRE_GPIOLIB
+       select GENERIC_GPIO
+       select COMMON_CLKDEV
+       help
+               Support for Nuvoton (Winbond logic dept.) ARM9 processor,You
+               can login www.mcuos.com or www.nuvoton.com to know more.
+
 config ARCH_PNX4008
        bool "Philips Nexperia PNX4008 Mobile"
        select CPU_ARM926T
@@ -495,19 +520,16 @@ config ARCH_PXA
        help
          Support for Intel/Marvell's PXA2xx/PXA3xx processor line.
 
-config ARCH_MMP
-       bool "Marvell PXA168/910"
-       depends on MMU
-       select GENERIC_GPIO
-       select ARCH_REQUIRE_GPIOLIB
-       select HAVE_CLK
-       select COMMON_CLKDEV
+config ARCH_MSM
+       bool "Qualcomm MSM"
+       select CPU_V6
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
-       select TICK_ONESHOT
-       select PLAT_PXA
        help
-         Support for Marvell's PXA168/910 processor line.
+         Support for Qualcomm MSM7K based systems.  This runs on the ARM11
+         apps processor of the MSM7K and depends on a shared memory
+         interface to the ARM9 modem processor which runs the baseband stack
+         and controls some vital subsystems (clock and power control, etc).
 
 config ARCH_RPC
        bool "RiscPC"
@@ -576,6 +598,20 @@ config ARCH_LH7A40X
          core with a wide array of integrated devices for
          hand-held and low-power applications.
 
+config ARCH_U300
+       bool "ST-Ericsson U300 Series"
+       depends on MMU
+       select CPU_ARM926T
+       select ARM_AMBA
+       select ARM_VIC
+       select GENERIC_TIME
+       select GENERIC_CLOCKEVENTS
+       select HAVE_CLK
+       select COMMON_CLKDEV
+       select GENERIC_GPIO
+       help
+         Support for ST-Ericsson U300 series mobile platforms.
+
 config ARCH_DAVINCI
        bool "TI DaVinci"
        select CPU_ARM926T
@@ -587,6 +623,7 @@ config ARCH_DAVINCI
        select ZONE_DMA
        select HAVE_IDE
        select COMMON_CLKDEV
+       select GENERIC_ALLOCATOR
        help
          Support for TI's DaVinci platform.
 
@@ -600,24 +637,6 @@ config ARCH_OMAP
        help
          Support for TI's OMAP platform (OMAP1 and OMAP2).
 
-config ARCH_MSM
-       bool "Qualcomm MSM"
-       select CPU_V6
-       select GENERIC_TIME
-       select GENERIC_CLOCKEVENTS
-       help
-         Support for Qualcomm MSM7K based systems.  This runs on the ARM11
-         apps processor of the MSM7K and depends on a shared memory
-         interface to the ARM9 modem processor which runs the baseband stack
-         and controls some vital subsystems (clock and power control, etc).
-
-config ARCH_W90X900
-       bool "Nuvoton W90X900 CPU"
-       select CPU_ARM926T
-       help
-               Support for Nuvoton (Winbond logic dept.) ARM9 processor,You
-               can login www.mcuos.com or www.nuvoton.com to know more.
-
 endchoice
 
 source "arch/arm/mach-clps711x/Kconfig"
@@ -681,9 +700,9 @@ source "arch/arm/mach-s3c6400/Kconfig"
 source "arch/arm/mach-s3c6410/Kconfig"
 endif
 
-source "arch/arm/mach-lh7a40x/Kconfig"
+source "arch/arm/plat-stmp3xxx/Kconfig"
 
-source "arch/arm/mach-imx/Kconfig"
+source "arch/arm/mach-lh7a40x/Kconfig"
 
 source "arch/arm/mach-h720x/Kconfig"
 
@@ -707,6 +726,8 @@ source "arch/arm/mach-ks8695/Kconfig"
 
 source "arch/arm/mach-msm/Kconfig"
 
+source "arch/arm/mach-u300/Kconfig"
+
 source "arch/arm/mach-w90x900/Kconfig"
 
 # Definitions to make life easier
@@ -859,8 +880,11 @@ source "kernel/time/Kconfig"
 
 config SMP
        bool "Symmetric Multi-Processing (EXPERIMENTAL)"
-       depends on EXPERIMENTAL && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP)
+       depends on EXPERIMENTAL && (REALVIEW_EB_ARM11MP || REALVIEW_EB_A9MP ||\
+                MACH_REALVIEW_PB11MP || MACH_REALVIEW_PBX || ARCH_OMAP4)
+       depends on GENERIC_CLOCKEVENTS
        select USE_GENERIC_SMP_HELPERS
+       select HAVE_ARM_SCU if (ARCH_REALVIEW || ARCH_OMAP4)
        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
@@ -878,6 +902,18 @@ config SMP
 
          If you don't know what to do here, say N.
 
+config HAVE_ARM_SCU
+       bool
+       depends on SMP
+       help
+         This option enables support for the ARM system coherency unit
+
+config HAVE_ARM_TWD
+       bool
+       depends on SMP
+       help
+         This options enables support for the ARM timer and watchdog unit
+
 choice
        prompt "Memory split"
        default VMSPLIT_3G
@@ -916,8 +952,10 @@ config HOTPLUG_CPU
 
 config LOCAL_TIMERS
        bool "Use local timer interrupts"
-       depends on SMP && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || REALVIEW_EB_A9MP)
+       depends on SMP && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || \
+               REALVIEW_EB_A9MP || MACH_REALVIEW_PBX || ARCH_OMAP4)
        default y
+       select HAVE_ARM_TWD if (ARCH_REALVIEW || ARCH_OMAP4)
        help
          Enable support for local timers on SMP platforms, rather then the
          legacy IPI broadcast method.  Local timers allows the system
@@ -979,7 +1017,6 @@ config OABI_COMPAT
 
 config ARCH_HAS_HOLES_MEMORYMODEL
        bool
-       default n
 
 # Discontigmem is deprecated
 config ARCH_DISCONTIGMEM_ENABLE
@@ -1022,12 +1059,12 @@ source "mm/Kconfig"
 config LEDS
        bool "Timer and CPU usage LEDs"
        depends on ARCH_CDB89712 || ARCH_EBSA110 || \
-                  ARCH_EBSA285 || ARCH_IMX || ARCH_INTEGRATOR || \
+                  ARCH_EBSA285 || ARCH_INTEGRATOR || \
                   ARCH_LUBBOCK || MACH_MAINSTONE || ARCH_NETWINDER || \
                   ARCH_OMAP || ARCH_P720T || ARCH_PXA_IDP || \
                   ARCH_SA1100 || ARCH_SHARK || ARCH_VERSATILE || \
                   ARCH_AT91 || ARCH_DAVINCI || \
-                  ARCH_KS8695 || MACH_RD88F5182
+                  ARCH_KS8695 || MACH_RD88F5182 || ARCH_REALVIEW
        help
          If you say Y here, the LEDs on your machine will be used
          to provide useful information about your current system status.
@@ -1085,6 +1122,22 @@ config ALIGNMENT_TRAP
          correct operation of some network protocols. With an IP-only
          configuration it is safe to say N, otherwise say Y.
 
+config UACCESS_WITH_MEMCPY
+       bool "Use kernel mem{cpy,set}() for {copy_to,clear}_user() (EXPERIMENTAL)"
+       depends on MMU && EXPERIMENTAL
+       default y if CPU_FEROCEON
+       help
+         Implement faster copy_to_user and clear_user methods for CPU
+         cores where a 8-word STM instruction give significantly higher
+         memory write throughput than a sequence of individual 32bit stores.
+
+         A possible side effect is a slight increase in scheduling latency
+         between threads sharing the same address space if they invoke
+         such copy operations with large buffers.
+
+         However, if the CPU data cache is using a write-allocate mode,
+         this option is unlikely to provide any performance gain.
+
 endmenu
 
 menu "Boot options"
@@ -1188,7 +1241,7 @@ endmenu
 
 menu "CPU Power Management"
 
-if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX || ARCH_PXA)
+if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_PXA)
 
 source "drivers/cpufreq/Kconfig"
 
@@ -1213,14 +1266,11 @@ config CPU_FREQ_INTEGRATOR
 
          If in doubt, say Y.
 
-config CPU_FREQ_IMX
-       tristate "CPUfreq driver for i.MX CPUs"
-       depends on ARCH_IMX && CPU_FREQ
-       default n
-       help
-         This enables the CPUfreq driver for i.MX CPUs.
-
-         If in doubt, say N.
+config CPU_FREQ_PXA
+       bool
+       depends on CPU_FREQ && ARCH_PXA && PXA25x
+       default y
+       select CPU_FREQ_DEFAULT_GOV_USERSPACE
 
 endif
 
index e84729bf13d4c3f617f1c7dd6c177fe8493c9597..c877d6df23d116286d17e51429058135f022de70 100644 (file)
@@ -11,6 +11,9 @@
 # Copyright (C) 1995-2001 by Russell King
 
 LDFLAGS_vmlinux        :=-p --no-undefined -X
+ifeq ($(CONFIG_CPU_ENDIAN_BE8),y)
+LDFLAGS_vmlinux        += --be8
+endif
 CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET)
 OBJCOPYFLAGS   :=-O binary -R .note -R .note.gnu.build-id -R .comment -S
 GZFLAGS                :=-9
@@ -99,64 +102,73 @@ CHECKFLAGS += -D__arm__
 #Default value
 head-y         := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o
 textofs-y      := 0x00008000
-
- machine-$(CONFIG_ARCH_RPC)       := rpc
- machine-$(CONFIG_ARCH_EBSA110)           := ebsa110
- machine-$(CONFIG_FOOTBRIDGE)     := footbridge
- machine-$(CONFIG_ARCH_SHARK)     := shark
- machine-$(CONFIG_ARCH_SA1100)    := sa1100
-ifeq ($(CONFIG_ARCH_SA1100),y)
+textofs-$(CONFIG_ARCH_CLPS711X) := 0x00028000
 # SA1111 DMA bug: we don't want the kernel to live in precious DMA-able memory
- textofs-$(CONFIG_SA1111)         := 0x00208000
+ifeq ($(CONFIG_ARCH_SA1100),y)
+textofs-$(CONFIG_SA1111) := 0x00208000
 endif
- machine-$(CONFIG_ARCH_PXA)       := pxa
- machine-$(CONFIG_ARCH_MMP)       := mmp
-    plat-$(CONFIG_PLAT_PXA)       := pxa
- machine-$(CONFIG_ARCH_L7200)     := l7200
- machine-$(CONFIG_ARCH_INTEGRATOR) := integrator
- machine-$(CONFIG_ARCH_GEMINI)     := gemini
- textofs-$(CONFIG_ARCH_CLPS711X)   := 0x00028000
- machine-$(CONFIG_ARCH_CLPS711X)   := clps711x
- machine-$(CONFIG_ARCH_IOP32X)    := iop32x
- machine-$(CONFIG_ARCH_IOP33X)    := iop33x
- machine-$(CONFIG_ARCH_IOP13XX)           := iop13xx
-    plat-$(CONFIG_PLAT_IOP)       := iop
- machine-$(CONFIG_ARCH_IXP4XX)    := ixp4xx
- machine-$(CONFIG_ARCH_IXP2000)    := ixp2000
- machine-$(CONFIG_ARCH_IXP23XX)    := ixp23xx
- machine-$(CONFIG_ARCH_OMAP1)     := omap1
- machine-$(CONFIG_ARCH_OMAP2)     := omap2
- machine-$(CONFIG_ARCH_OMAP3)     := omap2
-    plat-$(CONFIG_ARCH_OMAP)      := omap
- machine-$(CONFIG_ARCH_S3C2410)           := s3c2410 s3c2400 s3c2412 s3c2440 s3c2442 s3c2443
- machine-$(CONFIG_ARCH_S3C24A0)           := s3c24a0
-    plat-$(CONFIG_PLAT_S3C24XX)           := s3c24xx s3c
- machine-$(CONFIG_ARCH_S3C64XX)           := s3c6400 s3c6410
-    plat-$(CONFIG_PLAT_S3C64XX)           := s3c64xx s3c
- machine-$(CONFIG_ARCH_LH7A40X)           := lh7a40x
- machine-$(CONFIG_ARCH_VERSATILE)  := versatile
- machine-$(CONFIG_ARCH_IMX)       := imx
- machine-$(CONFIG_ARCH_H720X)     := h720x
- machine-$(CONFIG_ARCH_AAEC2000)   := aaec2000
- machine-$(CONFIG_ARCH_REALVIEW)   := realview
- machine-$(CONFIG_ARCH_AT91)      := at91
- machine-$(CONFIG_ARCH_EP93XX)    := ep93xx
- machine-$(CONFIG_ARCH_PNX4008)           := pnx4008
- machine-$(CONFIG_ARCH_NETX)      := netx
- machine-$(CONFIG_ARCH_NS9XXX)    := ns9xxx
- machine-$(CONFIG_ARCH_DAVINCI)           := davinci
- machine-$(CONFIG_ARCH_KIRKWOOD)   := kirkwood
- machine-$(CONFIG_ARCH_KS8695)     := ks8695
-    plat-$(CONFIG_ARCH_MXC)       := mxc
- machine-$(CONFIG_ARCH_MX2)       := mx2
- machine-$(CONFIG_ARCH_MX3)       := mx3
- machine-$(CONFIG_ARCH_MX1)       := mx1
- machine-$(CONFIG_ARCH_ORION5X)           := orion5x
-    plat-$(CONFIG_PLAT_ORION)     := orion
- machine-$(CONFIG_ARCH_MSM)       := msm
- machine-$(CONFIG_ARCH_LOKI)       := loki
- machine-$(CONFIG_ARCH_MV78XX0)    := mv78xx0
- machine-$(CONFIG_ARCH_W90X900)    := w90x900
+
+# Machine directory name.  This list is sorted alphanumerically
+# by CONFIG_* macro name.
+machine-$(CONFIG_ARCH_AAEC2000)                := aaec2000
+machine-$(CONFIG_ARCH_AT91)            := at91
+machine-$(CONFIG_ARCH_CLPS711X)                := clps711x
+machine-$(CONFIG_ARCH_DAVINCI)         := davinci
+machine-$(CONFIG_ARCH_EBSA110)         := ebsa110
+machine-$(CONFIG_ARCH_EP93XX)          := ep93xx
+machine-$(CONFIG_ARCH_GEMINI)          := gemini
+machine-$(CONFIG_ARCH_H720X)           := h720x
+machine-$(CONFIG_ARCH_INTEGRATOR)      := integrator
+machine-$(CONFIG_ARCH_IOP13XX)         := iop13xx
+machine-$(CONFIG_ARCH_IOP32X)          := iop32x
+machine-$(CONFIG_ARCH_IOP33X)          := iop33x
+machine-$(CONFIG_ARCH_IXP2000)         := ixp2000
+machine-$(CONFIG_ARCH_IXP23XX)         := ixp23xx
+machine-$(CONFIG_ARCH_IXP4XX)          := ixp4xx
+machine-$(CONFIG_ARCH_KIRKWOOD)                := kirkwood
+machine-$(CONFIG_ARCH_KS8695)          := ks8695
+machine-$(CONFIG_ARCH_L7200)           := l7200
+machine-$(CONFIG_ARCH_LH7A40X)         := lh7a40x
+machine-$(CONFIG_ARCH_LOKI)            := loki
+machine-$(CONFIG_ARCH_MMP)             := mmp
+machine-$(CONFIG_ARCH_MSM)             := msm
+machine-$(CONFIG_ARCH_MV78XX0)         := mv78xx0
+machine-$(CONFIG_ARCH_MX1)             := mx1
+machine-$(CONFIG_ARCH_MX2)             := mx2
+machine-$(CONFIG_ARCH_MX3)             := mx3
+machine-$(CONFIG_ARCH_NETX)            := netx
+machine-$(CONFIG_ARCH_NS9XXX)          := ns9xxx
+machine-$(CONFIG_ARCH_OMAP1)           := omap1
+machine-$(CONFIG_ARCH_OMAP2)           := omap2
+machine-$(CONFIG_ARCH_OMAP3)           := omap2
+machine-$(CONFIG_ARCH_OMAP4)           := omap2
+machine-$(CONFIG_ARCH_ORION5X)         := orion5x
+machine-$(CONFIG_ARCH_PNX4008)         := pnx4008
+machine-$(CONFIG_ARCH_PXA)             := pxa
+machine-$(CONFIG_ARCH_REALVIEW)                := realview
+machine-$(CONFIG_ARCH_RPC)             := rpc
+machine-$(CONFIG_ARCH_S3C2410)         := s3c2410 s3c2400 s3c2412 s3c2440 s3c2442 s3c2443
+machine-$(CONFIG_ARCH_S3C24A0)         := s3c24a0
+machine-$(CONFIG_ARCH_S3C64XX)         := s3c6400 s3c6410
+machine-$(CONFIG_ARCH_SA1100)          := sa1100
+machine-$(CONFIG_ARCH_SHARK)           := shark
+machine-$(CONFIG_ARCH_STMP378X)                := stmp378x
+machine-$(CONFIG_ARCH_STMP37XX)                := stmp37xx
+machine-$(CONFIG_ARCH_U300)            := u300
+machine-$(CONFIG_ARCH_VERSATILE)       := versatile
+machine-$(CONFIG_ARCH_W90X900)         := w90x900
+machine-$(CONFIG_FOOTBRIDGE)           := footbridge
+
+# Platform directory name.  This list is sorted alphanumerically
+# by CONFIG_* macro name.
+plat-$(CONFIG_ARCH_MXC)                := mxc
+plat-$(CONFIG_ARCH_OMAP)       := omap
+plat-$(CONFIG_PLAT_IOP)                := iop
+plat-$(CONFIG_PLAT_ORION)      := orion
+plat-$(CONFIG_PLAT_PXA)                := pxa
+plat-$(CONFIG_PLAT_S3C24XX)    := s3c24xx s3c
+plat-$(CONFIG_PLAT_S3C64XX)    := s3c64xx s3c
+plat-$(CONFIG_ARCH_STMP3XXX)   := stmp3xxx
 
 ifeq ($(CONFIG_ARCH_EBSA110),y)
 # This is what happens if you forget the IOCS16 line.
index fbe5eef1f6c9c031b2763e1ba9bb734de941f91b..ce39dc5400858891dc17be16de158fb6db041627 100644 (file)
@@ -40,7 +40,7 @@ ifeq ($(CONFIG_PXA_SHARPSL),y)
 OBJS           += head-sharpsl.o
 endif
 
-ifeq ($(CONFIG_CPU_BIG_ENDIAN),y)
+ifeq ($(CONFIG_CPU_ENDIAN_BE32),y)
 ifeq ($(CONFIG_CPU_CP15),y)
 OBJS           += big-endian.o
 else
@@ -78,6 +78,9 @@ EXTRA_AFLAGS  := -Wa,-march=all
 # linker symbols.  We only define initrd_phys and params_phys if the
 # machine class defined the corresponding makefile variable.
 LDFLAGS_vmlinux := --defsym zreladdr=$(ZRELADDR)
+ifeq ($(CONFIG_CPU_ENDIAN_BE8),y)
+LDFLAGS_vmlinux += --be8
+endif
 ifneq ($(INITRD_PHYS),)
 LDFLAGS_vmlinux += --defsym initrd_phys=$(INITRD_PHYS)
 endif
index b371fba1b954ce73bb9a881bde9575407b1d0669..01d49be3b2cafe62b9e86fb57ac884fa314136dc 100644 (file)
@@ -438,6 +438,9 @@ __armv4_mmu_cache_on:
                mrc     p15, 0, r0, c1, c0, 0   @ read control reg
                orr     r0, r0, #0x5000         @ I-cache enable, RR cache replacement
                orr     r0, r0, #0x0030
+#ifdef CONFIG_CPU_ENDIAN_BE8
+               orr     r0, r0, #1 << 25        @ big-endian page tables
+#endif
                bl      __common_mmu_cache_on
                mov     r0, #0
                mcr     p15, 0, r0, c8, c7, 0   @ flush I,D TLBs
@@ -455,6 +458,9 @@ __armv7_mmu_cache_on:
                mrc     p15, 0, r0, c1, c0, 0   @ read control reg
                orr     r0, r0, #0x5000         @ I-cache enable, RR cache replacement
                orr     r0, r0, #0x003c         @ write buffer
+#ifdef CONFIG_CPU_ENDIAN_BE8
+               orr     r0, r0, #1 << 25        @ big-endian page tables
+#endif
                orrne   r0, r0, #1              @ MMU enabled
                movne   r1, #-1
                mcrne   p15, 0, r3, c2, c0, 0   @ load page table pointer
index a2cd9beaf37daeb85c20627255b808f0fdf883a6..4efbb9df0444c6aaa249090b48e6ff7e56d9e259 100644 (file)
@@ -4,6 +4,14 @@ config ARM_GIC
 config ARM_VIC
        bool
 
+config ARM_VIC_NR
+       int
+       default 2
+       depends on ARM_VIC
+       help
+         The maximum number of VICs available in the system, for
+         power management.
+
 config ICST525
        bool
 
@@ -27,10 +35,6 @@ config SHARP_LOCOMO
 config SHARP_PARAM
        bool
 
-config SHARPSL_PM
-       bool
-       select APM_EMULATION
-
 config SHARP_SCOOP
        bool
 
index 7cb7961d81cb977ec2b56b45208188875980966f..76be7ff2a7ca37a55814071da882c0e374a39475 100644 (file)
@@ -12,7 +12,6 @@ obj-$(CONFIG_DMABOUNCE)               += dmabounce.o
 obj-$(CONFIG_TIMER_ACORN)      += time-acorn.o
 obj-$(CONFIG_SHARP_LOCOMO)     += locomo.o
 obj-$(CONFIG_SHARP_PARAM)      += sharpsl_param.o
-obj-$(CONFIG_SHARPSL_PM)       += sharpsl_pm.o
 obj-$(CONFIG_SHARP_SCOOP)      += scoop.o
 obj-$(CONFIG_ARCH_IXP2000)     += uengine.o
 obj-$(CONFIG_ARCH_IXP23XX)     += uengine.o
index 5589444ff4376bc88f3e37b4042cf03f000548cd..f37afd9422f3b1905884f525b58b19fcc4dd65f9 100644 (file)
@@ -135,6 +135,24 @@ struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id,
 }
 EXPORT_SYMBOL(clkdev_alloc);
 
+int clk_add_alias(const char *alias, const char *alias_dev_name, char *id,
+       struct device *dev)
+{
+       struct clk *r = clk_get(dev, id);
+       struct clk_lookup *l;
+
+       if (IS_ERR(r))
+               return PTR_ERR(r);
+
+       l = clkdev_alloc(r, alias, alias_dev_name);
+       clk_put(r);
+       if (!l)
+               return -ENODEV;
+       clkdev_add(l);
+       return 0;
+}
+EXPORT_SYMBOL(clk_add_alias);
+
 /*
  * clkdev_drop - remove a clock dynamically allocated
  */
diff --git a/arch/arm/common/sharpsl_pm.c b/arch/arm/common/sharpsl_pm.c
deleted file mode 100644 (file)
index 140f1d7..0000000
+++ /dev/null
@@ -1,859 +0,0 @@
-/*
- * Battery and Power Management code for the Sharp SL-C7xx and SL-Cxx00
- * series of PDAs
- *
- * Copyright (c) 2004-2005 Richard Purdie
- *
- * Based on code written by Sharp for 2.4 kernels
- *
- * This 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.
- *
- */
-
-#undef DEBUG
-
-#include <linux/module.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/apm_bios.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/leds.h>
-#include <linux/apm-emulation.h>
-#include <linux/suspend.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <mach/pm.h>
-#include <mach/pxa2xx-regs.h>
-#include <mach/regs-rtc.h>
-#include <mach/sharpsl.h>
-#include <asm/hardware/sharpsl_pm.h>
-
-/*
- * Constants
- */
-#define SHARPSL_CHARGE_ON_TIME_INTERVAL        (msecs_to_jiffies(1*60*1000))  /* 1 min */
-#define SHARPSL_CHARGE_FINISH_TIME             (msecs_to_jiffies(10*60*1000)) /* 10 min */
-#define SHARPSL_BATCHK_TIME                    (msecs_to_jiffies(15*1000))    /* 15 sec */
-#define SHARPSL_BATCHK_TIME_SUSPEND            (60*10)                        /* 10 min */
-
-#define SHARPSL_WAIT_CO_TIME                   15  /* 15 sec */
-#define SHARPSL_WAIT_DISCHARGE_ON              100 /* 100 msec */
-#define SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP   10  /* 10 msec */
-#define SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT   10  /* 10 msec */
-#define SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN   10  /* 10 msec */
-#define SHARPSL_CHARGE_WAIT_TIME               15  /* 15 msec */
-#define SHARPSL_CHARGE_CO_CHECK_TIME           5   /* 5 msec */
-#define SHARPSL_CHARGE_RETRY_CNT               1   /* eqv. 10 min */
-
-/*
- * Prototypes
- */
-#ifdef CONFIG_PM
-static int sharpsl_off_charge_battery(void);
-static int sharpsl_check_battery_voltage(void);
-static int sharpsl_fatal_check(void);
-#endif
-static int sharpsl_check_battery_temp(void);
-static int sharpsl_ac_check(void);
-static int sharpsl_average_value(int ad);
-static void sharpsl_average_clear(void);
-static void sharpsl_charge_toggle(struct work_struct *private_);
-static void sharpsl_battery_thread(struct work_struct *private_);
-
-
-/*
- * Variables
- */
-struct sharpsl_pm_status sharpsl_pm;
-DECLARE_DELAYED_WORK(toggle_charger, sharpsl_charge_toggle);
-DECLARE_DELAYED_WORK(sharpsl_bat, sharpsl_battery_thread);
-DEFINE_LED_TRIGGER(sharpsl_charge_led_trigger);
-
-
-static int get_percentage(int voltage)
-{
-       int i = sharpsl_pm.machinfo->bat_levels - 1;
-       int bl_status = sharpsl_pm.machinfo->backlight_get_status ? sharpsl_pm.machinfo->backlight_get_status() : 0;
-       struct battery_thresh *thresh;
-
-       if (sharpsl_pm.charge_mode == CHRG_ON)
-               thresh = bl_status ? sharpsl_pm.machinfo->bat_levels_acin_bl : sharpsl_pm.machinfo->bat_levels_acin;
-       else
-               thresh = bl_status ? sharpsl_pm.machinfo->bat_levels_noac_bl : sharpsl_pm.machinfo->bat_levels_noac;
-
-       while (i > 0 && (voltage > thresh[i].voltage))
-               i--;
-
-       return thresh[i].percentage;
-}
-
-static int get_apm_status(int voltage)
-{
-       int low_thresh, high_thresh;
-
-       if (sharpsl_pm.charge_mode == CHRG_ON) {
-               high_thresh = sharpsl_pm.machinfo->status_high_acin;
-               low_thresh = sharpsl_pm.machinfo->status_low_acin;
-       } else {
-               high_thresh = sharpsl_pm.machinfo->status_high_noac;
-               low_thresh = sharpsl_pm.machinfo->status_low_noac;
-       }
-
-       if (voltage >= high_thresh)
-               return APM_BATTERY_STATUS_HIGH;
-       if (voltage >= low_thresh)
-               return APM_BATTERY_STATUS_LOW;
-       return APM_BATTERY_STATUS_CRITICAL;
-}
-
-void sharpsl_battery_kick(void)
-{
-       schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(125));
-}
-EXPORT_SYMBOL(sharpsl_battery_kick);
-
-
-static void sharpsl_battery_thread(struct work_struct *private_)
-{
-       int voltage, percent, apm_status, i = 0;
-
-       if (!sharpsl_pm.machinfo)
-               return;
-
-       sharpsl_pm.battstat.ac_status = (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN) ? APM_AC_ONLINE : APM_AC_OFFLINE);
-
-       /* Corgi cannot confirm when battery fully charged so periodically kick! */
-       if (!sharpsl_pm.machinfo->batfull_irq && (sharpsl_pm.charge_mode == CHRG_ON)
-                       && time_after(jiffies, sharpsl_pm.charge_start_time +  SHARPSL_CHARGE_ON_TIME_INTERVAL))
-               schedule_delayed_work(&toggle_charger, 0);
-
-       while(1) {
-               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");
-                       break;
-               }
-       }
-
-       voltage = sharpsl_average_value(voltage);
-       apm_status = get_apm_status(voltage);
-       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) {
-               sharpsl_pm.battstat.mainbat_voltage = voltage;
-               sharpsl_pm.battstat.mainbat_status = apm_status;
-               sharpsl_pm.battstat.mainbat_percent = percent;
-       }
-
-       dev_dbg(sharpsl_pm.dev, "Battery: voltage: %d, status: %d, percentage: %d, time: %ld\n", voltage,
-                       sharpsl_pm.battstat.mainbat_status, sharpsl_pm.battstat.mainbat_percent, jiffies);
-
-#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))) {
-               if (!(sharpsl_pm.flags & SHARPSL_BL_LIMIT)) {
-                       sharpsl_pm.machinfo->backlight_limit(1);
-                       sharpsl_pm.flags |= SHARPSL_BL_LIMIT;
-               }
-       } else if (sharpsl_pm.flags & SHARPSL_BL_LIMIT) {
-               sharpsl_pm.machinfo->backlight_limit(0);
-               sharpsl_pm.flags &= ~SHARPSL_BL_LIMIT;
-       }
-#endif
-
-       /* 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.flags |= SHARPSL_APM_QUEUED;
-               dev_err(sharpsl_pm.dev, "Fatal Off\n");
-               apm_queue_event(APM_CRITICAL_SUSPEND);
-       }
-
-       schedule_delayed_work(&sharpsl_bat, SHARPSL_BATCHK_TIME);
-}
-
-void sharpsl_pm_led(int val)
-{
-       if (val == SHARPSL_LED_ERROR) {
-               dev_err(sharpsl_pm.dev, "Charging Error!\n");
-       } else if (val == SHARPSL_LED_ON) {
-               dev_dbg(sharpsl_pm.dev, "Charge LED On\n");
-               led_trigger_event(sharpsl_charge_led_trigger, LED_FULL);
-       } else {
-               dev_dbg(sharpsl_pm.dev, "Charge LED Off\n");
-               led_trigger_event(sharpsl_charge_led_trigger, LED_OFF);
-       }
-}
-
-static void sharpsl_charge_on(void)
-{
-       dev_dbg(sharpsl_pm.dev, "Turning Charger On\n");
-
-       sharpsl_pm.full_count = 0;
-       sharpsl_pm.charge_mode = CHRG_ON;
-       schedule_delayed_work(&toggle_charger, msecs_to_jiffies(250));
-       schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(500));
-}
-
-static void sharpsl_charge_off(void)
-{
-       dev_dbg(sharpsl_pm.dev, "Turning Charger Off\n");
-
-       sharpsl_pm.machinfo->charge(0);
-       sharpsl_pm_led(SHARPSL_LED_OFF);
-       sharpsl_pm.charge_mode = CHRG_OFF;
-
-       schedule_delayed_work(&sharpsl_bat, 0);
-}
-
-static void sharpsl_charge_error(void)
-{
-       sharpsl_pm_led(SHARPSL_LED_ERROR);
-       sharpsl_pm.machinfo->charge(0);
-       sharpsl_pm.charge_mode = CHRG_ERROR;
-}
-
-static void sharpsl_charge_toggle(struct work_struct *private_)
-{
-       dev_dbg(sharpsl_pm.dev, "Toogling Charger at time: %lx\n", jiffies);
-
-       if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) {
-               sharpsl_charge_off();
-               return;
-       } else if ((sharpsl_check_battery_temp() < 0) || (sharpsl_ac_check() < 0)) {
-               sharpsl_charge_error();
-               return;
-       }
-
-       sharpsl_pm_led(SHARPSL_LED_ON);
-       sharpsl_pm.machinfo->charge(0);
-       mdelay(SHARPSL_CHARGE_WAIT_TIME);
-       sharpsl_pm.machinfo->charge(1);
-
-       sharpsl_pm.charge_start_time = jiffies;
-}
-
-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);
-
-       sharpsl_average_clear();
-       if (acin && (sharpsl_pm.charge_mode != CHRG_ON))
-               sharpsl_charge_on();
-       else if (sharpsl_pm.charge_mode == CHRG_ON)
-               sharpsl_charge_off();
-
-       schedule_delayed_work(&sharpsl_bat, 0);
-}
-
-
-irqreturn_t sharpsl_ac_isr(int irq, void *dev_id)
-{
-       /* Delay the event slightly to debounce */
-       /* Must be a smaller delay than the chrg_full_isr below */
-       mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250));
-
-       return IRQ_HANDLED;
-}
-
-static void sharpsl_chrg_full_timer(unsigned long data)
-{
-       dev_dbg(sharpsl_pm.dev, "Charge Full at time: %lx\n", jiffies);
-
-       sharpsl_pm.full_count++;
-
-       if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) {
-               dev_dbg(sharpsl_pm.dev, "Charge Full: AC removed - stop charging!\n");
-               if (sharpsl_pm.charge_mode == CHRG_ON)
-                       sharpsl_charge_off();
-       } else if (sharpsl_pm.full_count < 2) {
-               dev_dbg(sharpsl_pm.dev, "Charge Full: Count too low\n");
-               schedule_delayed_work(&toggle_charger, 0);
-       } else if (time_after(jiffies, sharpsl_pm.charge_start_time + SHARPSL_CHARGE_FINISH_TIME)) {
-               dev_dbg(sharpsl_pm.dev, "Charge Full: Interrupt generated too slowly - retry.\n");
-               schedule_delayed_work(&toggle_charger, 0);
-       } else {
-               sharpsl_charge_off();
-               sharpsl_pm.charge_mode = CHRG_DONE;
-               dev_dbg(sharpsl_pm.dev, "Charge Full: Charging Finished\n");
-       }
-}
-
-/* Charging Finished Interrupt (Not present on Corgi) */
-/* Can trigger at the same time as an AC status change so
-   delay until after that has been processed */
-irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id)
-{
-       if (sharpsl_pm.flags & SHARPSL_SUSPENDED)
-               return IRQ_HANDLED;
-
-       /* delay until after any ac interrupt */
-       mod_timer(&sharpsl_pm.chrg_full_timer, jiffies + msecs_to_jiffies(500));
-
-       return IRQ_HANDLED;
-}
-
-irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id)
-{
-       int is_fatal = 0;
-
-       if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_LOCK)) {
-               dev_err(sharpsl_pm.dev, "Battery now Unlocked! Suspending.\n");
-               is_fatal = 1;
-       }
-
-       if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_FATAL)) {
-               dev_err(sharpsl_pm.dev, "Fatal Batt Error! Suspending.\n");
-               is_fatal = 1;
-       }
-
-       if (!(sharpsl_pm.flags & SHARPSL_APM_QUEUED) && is_fatal) {
-               sharpsl_pm.flags |= SHARPSL_APM_QUEUED;
-               apm_queue_event(APM_CRITICAL_SUSPEND);
-       }
-
-       return IRQ_HANDLED;
-}
-
-/*
- * Maintain an average of the last 10 readings
- */
-#define SHARPSL_CNV_VALUE_NUM    10
-static int sharpsl_ad_index;
-
-static void sharpsl_average_clear(void)
-{
-       sharpsl_ad_index = 0;
-}
-
-static int sharpsl_average_value(int ad)
-{
-       int i, ad_val = 0;
-       static int sharpsl_ad[SHARPSL_CNV_VALUE_NUM+1];
-
-       if (sharpsl_pm.battstat.mainbat_status != APM_BATTERY_STATUS_HIGH) {
-               sharpsl_ad_index = 0;
-               return 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++)
-                       sharpsl_ad[i] = sharpsl_ad[i+1];
-               sharpsl_ad_index = SHARPSL_CNV_VALUE_NUM - 1;
-       }
-       for (i=0; i < sharpsl_ad_index; i++)
-               ad_val += sharpsl_ad[i];
-
-       return (ad_val / sharpsl_ad_index);
-}
-
-/*
- * Take an array of 5 integers, remove the maximum and minimum values
- * and return the average.
- */
-static int get_select_val(int *val)
-{
-       int i, j, k, temp, sum = 0;
-
-       /* Find MAX val */
-       temp = val[0];
-       j=0;
-       for (i=1; i<5; i++) {
-               if (temp < val[i]) {
-                       temp = val[i];
-                       j = i;
-               }
-       }
-
-       /* Find MIN val */
-       temp = val[4];
-       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 )
-                       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);
-}
-
-static int sharpsl_check_battery_temp(void)
-{
-       int val, i, buff[5];
-
-       /* Check battery temperature */
-       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);
-               buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_TEMP);
-               sharpsl_pm.machinfo->measure_temp(0);
-       }
-
-       val = get_select_val(buff);
-
-       dev_dbg(sharpsl_pm.dev, "Temperature: %d\n", val);
-       if (val > sharpsl_pm.machinfo->charge_on_temp) {
-               printk(KERN_WARNING "Not charging: temperature out of limits.\n");
-               return -1;
-       }
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int sharpsl_check_battery_voltage(void)
-{
-       int val, i, buff[5];
-
-       /* disable charge, enable discharge */
-       sharpsl_pm.machinfo->charge(0);
-       sharpsl_pm.machinfo->discharge(1);
-       mdelay(SHARPSL_WAIT_DISCHARGE_ON);
-
-       if (sharpsl_pm.machinfo->discharge1)
-               sharpsl_pm.machinfo->discharge1(1);
-
-       /* Check battery voltage */
-       for (i=0; i<5; i++) {
-               buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT);
-               mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT);
-       }
-
-       if (sharpsl_pm.machinfo->discharge1)
-               sharpsl_pm.machinfo->discharge1(0);
-
-       sharpsl_pm.machinfo->discharge(0);
-
-       val = get_select_val(buff);
-       dev_dbg(sharpsl_pm.dev, "Battery Voltage: %d\n", val);
-
-       if (val < sharpsl_pm.machinfo->charge_on_volt)
-               return -1;
-
-       return 0;
-}
-#endif
-
-static int sharpsl_ac_check(void)
-{
-       int temp, i, buff[5];
-
-       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);
-
-       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");
-               return -1;
-       }
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int sharpsl_pm_suspend(struct platform_device *pdev, pm_message_t state)
-{
-       sharpsl_pm.flags |= SHARPSL_SUSPENDED;
-       flush_scheduled_work();
-
-       if (sharpsl_pm.charge_mode == CHRG_ON)
-               sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG;
-       else
-               sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG;
-
-       return 0;
-}
-
-static int sharpsl_pm_resume(struct platform_device *pdev)
-{
-       /* Clear the reset source indicators as they break the bootloader upon reboot */
-       RCSR = 0x0f;
-       sharpsl_average_clear();
-       sharpsl_pm.flags &= ~SHARPSL_APM_QUEUED;
-       sharpsl_pm.flags &= ~SHARPSL_SUSPENDED;
-
-       return 0;
-}
-
-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, "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))) {
-               dev_dbg(sharpsl_pm.dev, "Activating Offline Charger...\n");
-               sharpsl_pm.charge_mode = CHRG_OFF;
-               sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG;
-               sharpsl_off_charge_battery();
-       }
-
-       sharpsl_pm.machinfo->presuspend();
-
-       PEDR = 0xffffffff; /* clear it */
-
-       sharpsl_pm.flags &= ~SHARPSL_ALARM_ACTIVE;
-       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);
-               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);
-       } else {
-               dev_dbg(sharpsl_pm.dev, "No alarms set.\n");
-       }
-
-       pxa_pm_enter(state);
-
-       sharpsl_pm.machinfo->postsuspend();
-
-       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.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()) {
-                       dev_dbg(sharpsl_pm.dev, "Charging. Suspend...\n");
-                       corgi_goto_sleep(alarm_time, alarm_enable, state);
-                       return 1;
-               }
-               dev_dbg(sharpsl_pm.dev, "User triggered wakeup in offline charger.\n");
-       }
-
-       if ((!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_LOCK)) || (sharpsl_fatal_check() < 0) )
-       {
-               dev_err(sharpsl_pm.dev, "Fatal condition. Suspend.\n");
-               corgi_goto_sleep(alarm_time, alarm_enable, state);
-               return 1;
-       }
-
-       return 0;
-}
-
-static int corgi_pxa_pm_enter(suspend_state_t state)
-{
-       unsigned long alarm_time = RTAR;
-       unsigned int alarm_status = ((RTSR & RTSR_ALE) != 0);
-
-       dev_dbg(sharpsl_pm.dev, "SharpSL suspending for first time.\n");
-
-       corgi_goto_sleep(alarm_time, alarm_status, state);
-
-       while (corgi_enter_suspend(alarm_time,alarm_status,state))
-               {}
-
-       if (sharpsl_pm.machinfo->earlyresume)
-               sharpsl_pm.machinfo->earlyresume();
-
-       dev_dbg(sharpsl_pm.dev, "SharpSL resuming...\n");
-
-       return 0;
-}
-
-/*
- * Check for fatal battery errors
- * Fatal returns -1
- */
-static int sharpsl_fatal_check(void)
-{
-       int buff[5], temp, i, acin;
-
-       dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check entered\n");
-
-       /* Check AC-Adapter */
-       acin = sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN);
-
-       if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) {
-               sharpsl_pm.machinfo->charge(0);
-               udelay(100);
-               sharpsl_pm.machinfo->discharge(1);      /* enable discharge */
-               mdelay(SHARPSL_WAIT_DISCHARGE_ON);
-       }
-
-       if (sharpsl_pm.machinfo->discharge1)
-               sharpsl_pm.machinfo->discharge1(1);
-
-       /* Check battery : check inserting battery ? */
-       for (i=0; i<5; i++) {
-               buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT);
-               mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT);
-       }
-
-       if (sharpsl_pm.machinfo->discharge1)
-               sharpsl_pm.machinfo->discharge1(0);
-
-       if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) {
-               udelay(100);
-               sharpsl_pm.machinfo->charge(1);
-               sharpsl_pm.machinfo->discharge(0);
-       }
-
-       temp = get_select_val(buff);
-       dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check: acin: %d, discharge voltage: %d, no discharge: %ld\n", acin, temp, sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT));
-
-       if ((acin && (temp < sharpsl_pm.machinfo->fatal_acin_volt)) ||
-                       (!acin && (temp < sharpsl_pm.machinfo->fatal_noacin_volt)))
-               return -1;
-       return 0;
-}
-
-static int sharpsl_off_charge_error(void)
-{
-       dev_err(sharpsl_pm.dev, "Offline Charger: Error occurred.\n");
-       sharpsl_pm.machinfo->charge(0);
-       sharpsl_pm_led(SHARPSL_LED_ERROR);
-       sharpsl_pm.charge_mode = CHRG_ERROR;
-       return 1;
-}
-
-/*
- * Charging Control while suspended
- * Return 1 - go straight to sleep
- * Return 0 - sleep or wakeup depending on other factors
- */
-static int sharpsl_off_charge_battery(void)
-{
-       int time;
-
-       dev_dbg(sharpsl_pm.dev, "Charge Mode: %d\n", sharpsl_pm.charge_mode);
-
-       if (sharpsl_pm.charge_mode == CHRG_OFF) {
-               dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 1\n");
-
-               /* AC Check */
-               if ((sharpsl_ac_check() < 0) || (sharpsl_check_battery_temp() < 0))
-                       return sharpsl_off_charge_error();
-
-               /* Start Charging */
-               sharpsl_pm_led(SHARPSL_LED_ON);
-               sharpsl_pm.machinfo->charge(0);
-               mdelay(SHARPSL_CHARGE_WAIT_TIME);
-               sharpsl_pm.machinfo->charge(1);
-
-               sharpsl_pm.charge_mode = CHRG_ON;
-               sharpsl_pm.full_count = 0;
-
-               return 1;
-       } else if (sharpsl_pm.charge_mode != CHRG_ON) {
-               return 1;
-       }
-
-       if (sharpsl_pm.full_count == 0) {
-               int time;
-
-               dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 2\n");
-
-               if ((sharpsl_check_battery_temp() < 0) || (sharpsl_check_battery_voltage() < 0))
-                       return sharpsl_off_charge_error();
-
-               sharpsl_pm.machinfo->charge(0);
-               mdelay(SHARPSL_CHARGE_WAIT_TIME);
-               sharpsl_pm.machinfo->charge(1);
-               sharpsl_pm.charge_mode = CHRG_ON;
-
-               mdelay(SHARPSL_CHARGE_CO_CHECK_TIME);
-
-               time = RCNR;
-               while(1) {
-                       /* Check if any wakeup event had occurred */
-                       if (sharpsl_pm.machinfo->charger_wakeup() != 0)
-                               return 0;
-                       /* Check for timeout */
-                       if ((RCNR - time) > SHARPSL_WAIT_CO_TIME)
-                               return 1;
-                       if (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_CHRGFULL)) {
-                               dev_dbg(sharpsl_pm.dev, "Offline Charger: Charge full occurred. Retrying to check\n");
-                               sharpsl_pm.full_count++;
-                               sharpsl_pm.machinfo->charge(0);
-                               mdelay(SHARPSL_CHARGE_WAIT_TIME);
-                               sharpsl_pm.machinfo->charge(1);
-                               return 1;
-                       }
-               }
-       }
-
-       dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 3\n");
-
-       mdelay(SHARPSL_CHARGE_CO_CHECK_TIME);
-
-       time = RCNR;
-       while(1) {
-               /* Check if any wakeup event had occurred */
-               if (sharpsl_pm.machinfo->charger_wakeup() != 0)
-                       return 0;
-               /* Check for timeout */
-               if ((RCNR-time) > SHARPSL_WAIT_CO_TIME) {
-                       if (sharpsl_pm.full_count > SHARPSL_CHARGE_RETRY_CNT) {
-                               dev_dbg(sharpsl_pm.dev, "Offline Charger: Not charged sufficiently. Retrying.\n");
-                               sharpsl_pm.full_count = 0;
-                       }
-                       sharpsl_pm.full_count++;
-                       return 1;
-               }
-               if (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_CHRGFULL)) {
-                       dev_dbg(sharpsl_pm.dev, "Offline Charger: Charging complete.\n");
-                       sharpsl_pm_led(SHARPSL_LED_OFF);
-                       sharpsl_pm.machinfo->charge(0);
-                       sharpsl_pm.charge_mode = CHRG_DONE;
-                       return 1;
-               }
-       }
-}
-#else
-#define sharpsl_pm_suspend     NULL
-#define sharpsl_pm_resume      NULL
-#endif
-
-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);
-}
-
-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);
-}
-
-static DEVICE_ATTR(battery_percentage, 0444, battery_percentage_show, NULL);
-static DEVICE_ATTR(battery_voltage, 0444, battery_voltage_show, NULL);
-
-extern void (*apm_get_power_status)(struct apm_power_info *);
-
-static void sharpsl_apm_get_power_status(struct apm_power_info *info)
-{
-       info->ac_line_status = sharpsl_pm.battstat.ac_status;
-
-       if (sharpsl_pm.charge_mode == CHRG_ON)
-               info->battery_status = APM_BATTERY_STATUS_CHARGING;
-       else
-               info->battery_status = sharpsl_pm.battstat.mainbat_status;
-
-       info->battery_flag = (1 << info->battery_status);
-       info->battery_life = sharpsl_pm.battstat.mainbat_percent;
-}
-
-#ifdef CONFIG_PM
-static struct platform_suspend_ops sharpsl_pm_ops = {
-       .enter          = corgi_pxa_pm_enter,
-       .valid          = suspend_valid_only_mem,
-};
-#endif
-
-static int __init sharpsl_pm_probe(struct platform_device *pdev)
-{
-       int ret;
-
-       if (!pdev->dev.platform_data)
-               return -EINVAL;
-
-       sharpsl_pm.dev = &pdev->dev;
-       sharpsl_pm.machinfo = pdev->dev.platform_data;
-       sharpsl_pm.charge_mode = CHRG_OFF;
-       sharpsl_pm.flags = 0;
-
-       init_timer(&sharpsl_pm.ac_timer);
-       sharpsl_pm.ac_timer.function = sharpsl_ac_timer;
-
-       init_timer(&sharpsl_pm.chrg_full_timer);
-       sharpsl_pm.chrg_full_timer.function = sharpsl_chrg_full_timer;
-
-       led_trigger_register_simple("sharpsl-charge", &sharpsl_charge_led_trigger);
-
-       sharpsl_pm.machinfo->init();
-
-       ret = device_create_file(&pdev->dev, &dev_attr_battery_percentage);
-       ret |= device_create_file(&pdev->dev, &dev_attr_battery_voltage);
-       if (ret != 0)
-               dev_warn(&pdev->dev, "Failed to register attributes (%d)\n", ret);
-
-       apm_get_power_status = sharpsl_apm_get_power_status;
-
-#ifdef CONFIG_PM
-       suspend_set_ops(&sharpsl_pm_ops);
-#endif
-
-       mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250));
-
-       return 0;
-}
-
-static int sharpsl_pm_remove(struct platform_device *pdev)
-{
-       suspend_set_ops(NULL);
-
-       device_remove_file(&pdev->dev, &dev_attr_battery_percentage);
-       device_remove_file(&pdev->dev, &dev_attr_battery_voltage);
-
-       led_trigger_unregister_simple(sharpsl_charge_led_trigger);
-
-       sharpsl_pm.machinfo->exit();
-
-       del_timer_sync(&sharpsl_pm.chrg_full_timer);
-       del_timer_sync(&sharpsl_pm.ac_timer);
-
-       return 0;
-}
-
-static struct platform_driver sharpsl_pm_driver = {
-       .probe          = sharpsl_pm_probe,
-       .remove         = sharpsl_pm_remove,
-       .suspend        = sharpsl_pm_suspend,
-       .resume         = sharpsl_pm_resume,
-       .driver         = {
-               .name           = "sharpsl-pm",
-       },
-};
-
-static int __devinit sharpsl_pm_init(void)
-{
-       return platform_driver_register(&sharpsl_pm_driver);
-}
-
-static void sharpsl_pm_exit(void)
-{
-       platform_driver_unregister(&sharpsl_pm_driver);
-}
-
-late_initcall(sharpsl_pm_init);
-module_exit(sharpsl_pm_exit);
index b2a781d9ce05a875d2ab30f7375307bec7575b21..887c6eb3a18a45e1a794a10ca0b7abbd8137c01d 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/io.h>
+#include <linux/sysdev.h>
 
 #include <asm/mach/irq.h>
 #include <asm/hardware/vic.h>
@@ -39,11 +40,219 @@ static void vic_unmask_irq(unsigned int irq)
        writel(1 << irq, base + VIC_INT_ENABLE);
 }
 
+/**
+ * vic_init2 - common initialisation code
+ * @base: Base of the VIC.
+ *
+ * Common initialisation code for registeration
+ * and resume.
+*/
+static void vic_init2(void __iomem *base)
+{
+       int i;
+
+       for (i = 0; i < 16; i++) {
+               void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4);
+               writel(VIC_VECT_CNTL_ENABLE | i, reg);
+       }
+
+       writel(32, base + VIC_PL190_DEF_VECT_ADDR);
+}
+
+#if defined(CONFIG_PM)
+/**
+ * struct vic_device - VIC PM device
+ * @sysdev: The system device which is registered.
+ * @irq: The IRQ number for the base of the VIC.
+ * @base: The register base for the VIC.
+ * @resume_sources: A bitmask of interrupts for resume.
+ * @resume_irqs: The IRQs enabled for resume.
+ * @int_select: Save for VIC_INT_SELECT.
+ * @int_enable: Save for VIC_INT_ENABLE.
+ * @soft_int: Save for VIC_INT_SOFT.
+ * @protect: Save for VIC_PROTECT.
+ */
+struct vic_device {
+       struct sys_device sysdev;
+
+       void __iomem    *base;
+       int             irq;
+       u32             resume_sources;
+       u32             resume_irqs;
+       u32             int_select;
+       u32             int_enable;
+       u32             soft_int;
+       u32             protect;
+};
+
+/* we cannot allocate memory when VICs are initially registered */
+static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
+
+static inline struct vic_device *to_vic(struct sys_device *sys)
+{
+       return container_of(sys, struct vic_device, sysdev);
+}
+
+static int vic_id;
+
+static int vic_class_resume(struct sys_device *dev)
+{
+       struct vic_device *vic = to_vic(dev);
+       void __iomem *base = vic->base;
+
+       printk(KERN_DEBUG "%s: resuming vic at %p\n", __func__, base);
+
+       /* re-initialise static settings */
+       vic_init2(base);
+
+       writel(vic->int_select, base + VIC_INT_SELECT);
+       writel(vic->protect, base + VIC_PROTECT);
+
+       /* set the enabled ints and then clear the non-enabled */
+       writel(vic->int_enable, base + VIC_INT_ENABLE);
+       writel(~vic->int_enable, base + VIC_INT_ENABLE_CLEAR);
+
+       /* and the same for the soft-int register */
+
+       writel(vic->soft_int, base + VIC_INT_SOFT);
+       writel(~vic->soft_int, base + VIC_INT_SOFT_CLEAR);
+
+       return 0;
+}
+
+static int vic_class_suspend(struct sys_device *dev, pm_message_t state)
+{
+       struct vic_device *vic = to_vic(dev);
+       void __iomem *base = vic->base;
+
+       printk(KERN_DEBUG "%s: suspending vic at %p\n", __func__, base);
+
+       vic->int_select = readl(base + VIC_INT_SELECT);
+       vic->int_enable = readl(base + VIC_INT_ENABLE);
+       vic->soft_int = readl(base + VIC_INT_SOFT);
+       vic->protect = readl(base + VIC_PROTECT);
+
+       /* set the interrupts (if any) that are used for
+        * resuming the system */
+
+       writel(vic->resume_irqs, base + VIC_INT_ENABLE);
+       writel(~vic->resume_irqs, base + VIC_INT_ENABLE_CLEAR);
+
+       return 0;
+}
+
+struct sysdev_class vic_class = {
+       .name           = "vic",
+       .suspend        = vic_class_suspend,
+       .resume         = vic_class_resume,
+};
+
+/**
+ * vic_pm_register - Register a VIC for later power management control
+ * @base: The base address of the VIC.
+ * @irq: The base IRQ for the VIC.
+ * @resume_sources: bitmask of interrupts allowed for resume sources.
+ *
+ * Register the VIC with the system device tree so that it can be notified
+ * of suspend and resume requests and ensure that the correct actions are
+ * taken to re-instate the settings on resume.
+ */
+static void __init vic_pm_register(void __iomem *base, unsigned int irq, u32 resume_sources)
+{
+       struct vic_device *v;
+
+       if (vic_id >= ARRAY_SIZE(vic_devices))
+               printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
+       else {
+               v = &vic_devices[vic_id];
+               v->base = base;
+               v->resume_sources = resume_sources;
+               v->irq = irq;
+               vic_id++;
+       }
+}
+
+/**
+ * vic_pm_init - initicall to register VIC pm
+ *
+ * This is called via late_initcall() to register
+ * the resources for the VICs due to the early
+ * nature of the VIC's registration.
+*/
+static int __init vic_pm_init(void)
+{
+       struct vic_device *dev = vic_devices;
+       int err;
+       int id;
+
+       if (vic_id == 0)
+               return 0;
+
+       err = sysdev_class_register(&vic_class);
+       if (err) {
+               printk(KERN_ERR "%s: cannot register class\n", __func__);
+               return err;
+       }
+
+       for (id = 0; id < vic_id; id++, dev++) {
+               dev->sysdev.id = id;
+               dev->sysdev.cls = &vic_class;
+
+               err = sysdev_register(&dev->sysdev);
+               if (err) {
+                       printk(KERN_ERR "%s: failed to register device\n",
+                              __func__);
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+late_initcall(vic_pm_init);
+
+static struct vic_device *vic_from_irq(unsigned int irq)
+{
+        struct vic_device *v = vic_devices;
+       unsigned int base_irq = irq & ~31;
+       int id;
+
+       for (id = 0; id < vic_id; id++, v++) {
+               if (v->irq == base_irq)
+                       return v;
+       }
+
+       return NULL;
+}
+
+static int vic_set_wake(unsigned int irq, unsigned int on)
+{
+       struct vic_device *v = vic_from_irq(irq);
+       unsigned int off = irq & 31;
+
+       if (!v)
+               return -EINVAL;
+
+       if (on)
+               v->resume_irqs |= 1 << off;
+       else
+               v->resume_irqs &= ~(1 << off);
+
+       return 0;
+}
+
+#else
+static inline void vic_pm_register(void __iomem *base, unsigned int irq, u32 arg1) { }
+
+#define vic_set_wake NULL
+#endif /* CONFIG_PM */
+
 static struct irq_chip vic_chip = {
        .name   = "VIC",
        .ack    = vic_mask_irq,
        .mask   = vic_mask_irq,
        .unmask = vic_unmask_irq,
+       .set_wake = vic_set_wake,
 };
 
 /**
@@ -51,9 +260,10 @@ static struct irq_chip vic_chip = {
  * @base: iomem base address
  * @irq_start: starting interrupt number, must be muliple of 32
  * @vic_sources: bitmask of interrupt sources to allow
+ * @resume_sources: bitmask of interrupt sources to allow for resume
  */
 void __init vic_init(void __iomem *base, unsigned int irq_start,
-                    u32 vic_sources)
+                    u32 vic_sources, u32 resume_sources)
 {
        unsigned int i;
 
@@ -77,12 +287,7 @@ void __init vic_init(void __iomem *base, unsigned int irq_start,
                writel(value, base + VIC_PL190_VECT_ADDR);
        }
 
-       for (i = 0; i < 16; i++) {
-               void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4);
-               writel(VIC_VECT_CNTL_ENABLE | i, reg);
-       }
-
-       writel(32, base + VIC_PL190_DEF_VECT_ADDR);
+       vic_init2(base);
 
        for (i = 0; i < 32; i++) {
                if (vic_sources & (1 << i)) {
@@ -94,4 +299,6 @@ void __init vic_init(void __iomem *base, unsigned int irq_start,
                        set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
                }
        }
+
+       vic_pm_register(base, irq_start, resume_sources);
 }
index 227da0843eadf14e033e0a4a1ae2fbf397a69d89..d18d21bb41e4ff31553a737c5b41d9c65d95f3a1 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.27-rc3
-# Tue Aug 19 11:26:54 2008
+# Linux kernel version: 2.6.30-rc8
+# Thu Jun  4 09:53:21 2009
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -22,8 +22,6 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 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
@@ -44,15 +42,24 @@ CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
 # CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU 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
-# 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
@@ -61,31 +68,37 @@ CONFIG_NAMESPACES=y
 # 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 is not set
 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 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
 CONFIG_ELF_CORE=y
-CONFIG_COMPAT_BRK=y
 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
 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
@@ -93,19 +106,13 @@ CONFIG_SLUB=y
 # CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
-# CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set
-# CONFIG_HAVE_IOREMAP_PROT is not set
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
-# CONFIG_HAVE_ARCH_TRACEHOOK is not set
-# CONFIG_HAVE_DMA_ATTRS is not set
-# CONFIG_USE_GENERIC_SMP_HELPERS is not set
 CONFIG_HAVE_CLK=y
-CONFIG_PROC_PAGE_MONITOR=y
+# CONFIG_SLOW_WORK is not set
 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
@@ -113,11 +120,8 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 # CONFIG_MODVERSIONS is not set
 # 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_BLK_DEV_BSG is not set
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
@@ -133,7 +137,7 @@ CONFIG_IOSCHED_CFQ=y
 CONFIG_DEFAULT_CFQ=y
 # CONFIG_DEFAULT_NOOP is not set
 CONFIG_DEFAULT_IOSCHED="cfq"
-CONFIG_CLASSIC_RCU=y
+CONFIG_FREEZER=y
 
 #
 # System Type
@@ -143,10 +147,10 @@ CONFIG_CLASSIC_RCU=y
 # 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_EBSA110 is not set
 # CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_GEMINI is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_NETX is not set
 # CONFIG_ARCH_H720X is not set
@@ -167,14 +171,17 @@ CONFIG_CLASSIC_RCU=y
 # CONFIG_ARCH_ORION5X is not set
 # CONFIG_ARCH_PNX4008 is not set
 CONFIG_ARCH_PXA=y
+# CONFIG_ARCH_MMP 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_DAVINCI is not set
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_MSM7X00A is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_W90X900 is not set
 
 #
 # Intel PXA2xx/PXA3xx Implementations
@@ -187,16 +194,24 @@ CONFIG_CPU_PXA300=y
 # CONFIG_CPU_PXA310 is not set
 # CONFIG_CPU_PXA320 is not set
 # CONFIG_CPU_PXA930 is not set
+# CONFIG_CPU_PXA935 is not set
 # CONFIG_ARCH_GUMSTIX is not set
+# CONFIG_MACH_INTELMOTE2 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_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
@@ -204,19 +219,15 @@ CONFIG_CPU_PXA300=y
 # CONFIG_MACH_ARMCORE is not set
 CONFIG_MACH_CM_X300=y
 # 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 is not set
 CONFIG_PXA3xx=y
 # CONFIG_PXA_PWM is not set
-
-#
-# Boot options
-#
-
-#
-# Power management
-#
+CONFIG_PLAT_PXA=y
 
 #
 # Processor Type
@@ -241,6 +252,7 @@ CONFIG_IO_36=y
 CONFIG_OUTER_CACHE=y
 CONFIG_CACHE_XSC3L2=y
 CONFIG_IWMMXT=y
+CONFIG_COMMON_CLKDEV=y
 
 #
 # Bus support
@@ -256,25 +268,33 @@ CONFIG_TICK_ONESHOT=y
 CONFIG_NO_HZ=y
 # 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 is not set
 CONFIG_HZ=100
 CONFIG_AEABI=y
 CONFIG_OABI_COMPAT=y
-# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+# 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
 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_PHYS_ADDR_T_64BIT is not set
+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_ALIGNMENT_TRAP=y
 
 #
@@ -287,7 +307,7 @@ CONFIG_CMDLINE="root=/dev/mtdblock5 rootfstype=jffs2 console=ttyS2,38400"
 # CONFIG_KEXEC is not set
 
 #
-# CPU Frequency scaling
+# CPU Power Management
 #
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_TABLE=y
@@ -304,6 +324,7 @@ CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
 # CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
 # CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+# CONFIG_CPU_IDLE is not set
 
 #
 # Floating point emulation
@@ -320,6 +341,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
 
@@ -376,6 +399,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # 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
@@ -385,7 +409,9 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
 # CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
 
 #
 # Network testing
@@ -407,8 +433,7 @@ CONFIG_BT_HIDP=m
 #
 # Bluetooth device drivers
 #
-CONFIG_BT_HCIUSB=m
-CONFIG_BT_HCIUSB_SCO=y
+# CONFIG_BT_HCIBTUSB is not set
 # CONFIG_BT_HCIBTSDIO is not set
 # CONFIG_BT_HCIUART is not set
 # CONFIG_BT_HCIBCM203X is not set
@@ -416,19 +441,15 @@ CONFIG_BT_HCIUSB_SCO=y
 # CONFIG_BT_HCIBFUSB is not set
 # CONFIG_BT_HCIVHCI is not set
 # CONFIG_AF_RXRPC is not set
-
-#
-# Wireless
-#
+CONFIG_WIRELESS=y
 # CONFIG_CFG80211 is not set
+# 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
-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_WIMAX is not set
 # CONFIG_RFKILL is not set
 # CONFIG_NET_9P is not set
 
@@ -453,6 +474,7 @@ CONFIG_MTD=y
 # CONFIG_MTD_DEBUG 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
@@ -494,7 +516,6 @@ CONFIG_MTD_CFI_I2=y
 # Mapping drivers for chip access
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
-# CONFIG_MTD_SHARP_SL is not set
 # CONFIG_MTD_PLATRAM is not set
 
 #
@@ -516,15 +537,22 @@ CONFIG_MTD_NAND=y
 # CONFIG_MTD_NAND_ECC_SMC is not set
 # CONFIG_MTD_NAND_MUSEUM_IDS is not set
 # CONFIG_MTD_NAND_H1900 is not set
+# CONFIG_MTD_NAND_GPIO is not set
 CONFIG_MTD_NAND_IDS=y
 # CONFIG_MTD_NAND_DISKONCHIP is not set
 # CONFIG_MTD_NAND_SHARPSL is not set
 CONFIG_MTD_NAND_PXA3xx=y
+# CONFIG_MTD_NAND_PXA3xx_BUILTIN 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
 #
@@ -585,11 +613,15 @@ CONFIG_SCSI_WAIT_SCAN=m
 # 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_COMPAT_NET_DEV_OPS=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_MACVLAN is not set
@@ -604,11 +636,17 @@ CONFIG_MII=y
 CONFIG_DM9000=y
 CONFIG_DM9000_DEBUGLEVEL=0
 CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL=y
+# 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_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
@@ -624,9 +662,12 @@ CONFIG_LIBERTAS_SDIO=m
 # CONFIG_LIBERTAS_DEBUG is not set
 # CONFIG_USB_ZD1201 is not set
 # CONFIG_USB_NET_RNDIS_WLAN is not set
-# CONFIG_IWLWIFI_LEDS is not set
 # CONFIG_HOSTAP is not set
 
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
 #
 # USB Network Adapters
 #
@@ -677,18 +718,21 @@ CONFIG_KEYBOARD_PXA27x=m
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TABLET is not set
 CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879 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_UCB1400 is not set
 # CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
 # CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
 # CONFIG_INPUT_MISC is not set
 
 #
@@ -721,10 +765,10 @@ 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 is not set
 # CONFIG_IPMI_HANDLER is not set
 # CONFIG_HW_RANDOM is not set
-# CONFIG_NVRAM is not set
 # CONFIG_R3964 is not set
 # CONFIG_RAW_DRIVER is not set
 # CONFIG_TCG_TPM is not set
@@ -763,12 +807,8 @@ CONFIG_I2C_PXA=y
 # Miscellaneous I2C Chip support
 #
 # CONFIG_DS1682 is not set
-# CONFIG_EEPROM_AT24 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
@@ -781,6 +821,10 @@ CONFIG_GPIOLIB=y
 # CONFIG_DEBUG_GPIO is not set
 # CONFIG_GPIO_SYSFS is not set
 
+#
+# Memory mapped GPIO expanders:
+#
+
 #
 # I2C GPIO expanders:
 #
@@ -798,12 +842,14 @@ CONFIG_GPIO_PCA953X=y
 # 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
 
 #
 # Sonics Silicon Backplane
 #
-CONFIG_SSB_POSSIBLE=y
 # CONFIG_SSB is not set
 
 #
@@ -811,12 +857,19 @@ CONFIG_SSB_POSSIBLE=y
 #
 # 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_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_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
 
 #
 # Multimedia devices
@@ -842,6 +895,7 @@ CONFIG_SSB_POSSIBLE=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
@@ -862,12 +916,15 @@ CONFIG_FB_CFB_IMAGEBLIT=y
 #
 # CONFIG_FB_S1D13XXX is not set
 CONFIG_FB_PXA=y
+# CONFIG_FB_PXA_OVERLAY is not set
 # CONFIG_FB_PXA_SMARTPANEL is not set
 # CONFIG_FB_PXA_PARAMETERS is not set
 # CONFIG_FB_MBX is not set
 # CONFIG_FB_W100 is not set
-# CONFIG_FB_AM200EPD 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
 
 #
@@ -899,9 +956,11 @@ 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_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
@@ -916,12 +975,15 @@ CONFIG_SND_DRIVERS=y
 # CONFIG_SND_SERIAL_U16550 is not set
 # CONFIG_SND_MPU401 is not set
 CONFIG_SND_ARM=y
+CONFIG_SND_PXA2XX_LIB=m
 # 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_SOC=m
 CONFIG_SND_PXA2XX_SOC=m
+CONFIG_SND_SOC_I2C_AND_SPI=m
+# CONFIG_SND_SOC_ALL_CODECS is not set
 # CONFIG_SOUND_PRIME is not set
 CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
@@ -932,9 +994,39 @@ CONFIG_HID_DEBUG=y
 # USB Input Devices
 #
 CONFIG_USB_HID=y
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
+# CONFIG_HID_PID is not set
 # CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+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_DRAGONRISE_FF is not set
+CONFIG_HID_EZKEY=y
+CONFIG_HID_KYE=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_KENSINGTON=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_NTRIG=y
+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_TOPSEED=y
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF is not set
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
@@ -952,11 +1044,14 @@ CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_SUSPEND 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_OXU210HP_HCD is not set
 # CONFIG_USB_ISP116X_HCD is not set
 # CONFIG_USB_ISP1760_HCD is not set
 CONFIG_USB_OHCI_HCD=y
@@ -965,6 +1060,7 @@ CONFIG_USB_OHCI_HCD=y
 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
 
 #
@@ -973,20 +1069,20 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 # 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_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_DPCM is not set
 # CONFIG_USB_STORAGE_USBAT is not set
 # CONFIG_USB_STORAGE_SDDR09 is not set
 # CONFIG_USB_STORAGE_SDDR55 is not set
@@ -994,7 +1090,6 @@ CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_ALAUDA is not set
 # CONFIG_USB_STORAGE_ONETOUCH is not set
 # CONFIG_USB_STORAGE_KARMA is not set
-# CONFIG_USB_STORAGE_SIERRA is not set
 # CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
 # CONFIG_USB_LIBUSUAL is not set
 
@@ -1015,6 +1110,7 @@ CONFIG_USB_STORAGE=y
 # 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
@@ -1022,7 +1118,6 @@ 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
@@ -1031,13 +1126,20 @@ CONFIG_USB_STORAGE=y
 # 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=m
 # CONFIG_MMC_DEBUG is not set
 # CONFIG_MMC_UNSAFE_RESUME is not set
 
 #
-# MMC/SD Card Drivers
+# MMC/SD/SDIO Card Drivers
 #
 CONFIG_MMC_BLOCK=m
 CONFIG_MMC_BLOCK_BOUNCE=y
@@ -1045,10 +1147,12 @@ CONFIG_MMC_BLOCK_BOUNCE=y
 # CONFIG_MMC_TEST is not set
 
 #
-# MMC/SD Host Controller Drivers
+# MMC/SD/SDIO Host Controller Drivers
 #
 CONFIG_MMC_PXA=m
 # CONFIG_MMC_SDHCI is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 
@@ -1057,7 +1161,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_PCA955X is not set
+# CONFIG_LEDS_BD2802 is not set
 
 #
 # LED Triggers
@@ -1065,7 +1172,13 @@ CONFIG_LEDS_GPIO=y
 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_RTC_LIB=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_HCTOSYS=y
@@ -1096,6 +1209,7 @@ CONFIG_RTC_INTF_DEV=y
 # 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
 
 #
 # SPI RTC drivers
@@ -1105,28 +1219,27 @@ CONFIG_RTC_INTF_DEV=y
 # 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_V3020 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+CONFIG_RTC_DRV_V3020=y
 
 #
 # on-CPU RTC drivers
 #
 CONFIG_RTC_DRV_SA1100=y
+# CONFIG_RTC_DRV_PXA is not set
 # CONFIG_DMADEVICES is not set
-
-#
-# Voltage and Current regulators
-#
+# CONFIG_AUXDISPLAY is not set
 # CONFIG_REGULATOR is not set
-# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
-# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
-# CONFIG_REGULATOR_BQ24022 is not set
 # CONFIG_UIO is not set
+# CONFIG_STAGING is not set
 
 #
 # File systems
@@ -1135,15 +1248,18 @@ 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_EXT4DEV_FS 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 is not set
 # CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
 CONFIG_DNOTIFY=y
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY_USER=y
@@ -1152,6 +1268,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -1173,15 +1294,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
@@ -1201,6 +1320,7 @@ CONFIG_JFFS2_ZLIB=y
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN 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
@@ -1209,6 +1329,7 @@ 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
@@ -1313,6 +1434,7 @@ CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
 # CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_DETECT_HUNG_TASK is not set
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
@@ -1329,6 +1451,7 @@ CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_HIGHMEM is not set
 CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_DEBUG_VM is not set
@@ -1336,22 +1459,38 @@ CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_DEBUG_MEMORY_INIT=y
 # CONFIG_DEBUG_LIST is not set
 # CONFIG_DEBUG_SG is not set
-CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_NOTIFIERS 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_FAULT_INJECTION is not set
 # CONFIG_LATENCYTOP is not set
 CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_HAVE_FTRACE=y
-CONFIG_HAVE_DYNAMIC_FTRACE=y
-# CONFIG_FTRACE is not set
+# 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_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 is not set
 # CONFIG_DEBUG_STACK_USAGE is not set
@@ -1363,17 +1502,28 @@ CONFIG_DEBUG_LL=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=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
@@ -1442,15 +1592,21 @@ CONFIG_CRYPTO_DES=y
 # 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 is not set
+# 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 is not set
 # CONFIG_CRC16 is not set
 CONFIG_CRC_T10DIF=y
@@ -1460,7 +1616,10 @@ CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
-CONFIG_PLIST=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
index eb2738b5be5f0eb601c21cb5e486bc032cf8fc14..ac18662f38cc10a9e664efa1efc42c3fb3e859da 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc2
-# Wed Apr 15 08:16:53 2009
+# Linux kernel version: 2.6.30-rc7
+# Tue May 26 07:24:28 2009
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -179,6 +179,7 @@ CONFIG_ARCH_DAVINCI=y
 # CONFIG_ARCH_OMAP is not set
 # CONFIG_ARCH_MSM is not set
 # CONFIG_ARCH_W90X900 is not set
+CONFIG_AINTC=y
 
 #
 # TI DaVinci Implementations
@@ -188,11 +189,17 @@ CONFIG_ARCH_DAVINCI=y
 # DaVinci Core Type
 #
 CONFIG_ARCH_DAVINCI_DM644x=y
+CONFIG_ARCH_DAVINCI_DM355=y
+CONFIG_ARCH_DAVINCI_DM646x=y
 
 #
 # DaVinci Board Type
 #
 CONFIG_MACH_DAVINCI_EVM=y
+CONFIG_MACH_SFFSDR=y
+CONFIG_MACH_DAVINCI_DM355_EVM=y
+CONFIG_MACH_DM355_LEOPARD=y
+CONFIG_MACH_DAVINCI_DM6467_EVM=y
 CONFIG_DAVINCI_MUX=y
 CONFIG_DAVINCI_MUX_DEBUG=y
 CONFIG_DAVINCI_MUX_WARNINGS=y
@@ -245,7 +252,7 @@ CONFIG_PREEMPT=y
 CONFIG_HZ=100
 CONFIG_AEABI=y
 # CONFIG_OABI_COMPAT is not set
-CONFIG_ARCH_FLATMEM_HAS_HOLES=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 is not set
@@ -661,7 +668,10 @@ CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 # CONFIG_AX88796 is not set
 # CONFIG_SMC91X is not set
-# CONFIG_DM9000 is not set
+CONFIG_TI_DAVINCI_EMAC=y
+CONFIG_DM9000=y
+CONFIG_DM9000_DEBUGLEVEL=4
+# CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL is not set
 # CONFIG_ETHOC is not set
 # CONFIG_SMC911X is not set
 # CONFIG_SMSC911X is not set
@@ -963,6 +973,7 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_MFD_CORE is not set
 # CONFIG_MFD_SM501 is not set
 # CONFIG_MFD_ASIC3 is not set
+# CONFIG_MFD_DM355EVM_MSP is not set
 # CONFIG_HTC_EGPIO is not set
 # CONFIG_HTC_PASIC3 is not set
 # CONFIG_TPS65010 is not set
@@ -1317,6 +1328,7 @@ CONFIG_MMC_BLOCK=m
 # MMC/SD/SDIO Host Controller Drivers
 #
 # CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_DAVINCI is not set
 # CONFIG_MEMSTICK is not set
 # CONFIG_ACCESSIBILITY is not set
 CONFIG_NEW_LEDS=y
@@ -1778,6 +1790,7 @@ CONFIG_CRC32=y
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
 CONFIG_DECOMPRESS_GZIP=y
+CONFIG_GENERIC_ALLOCATOR=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
index 3f89d5f25bcef998f1caf44f539706b6f9784771..3fb083b81b0a53b41c06b3617a7c2bf2ee7cf07c 100644 (file)
@@ -1,12 +1,19 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.20-rc1
-# Sat Dec 16 06:05:24 2006
+# Linux kernel version: 2.6.30-rc3
+# Tue May 19 12:26:49 2009
 #
 CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
 # CONFIG_GENERIC_TIME is not set
+# CONFIG_GENERIC_CLOCKEVENTS is not set
 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
@@ -15,42 +22,54 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # 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_VECTORS_BASE=0xffff0000
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=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_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
 # CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU 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
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
 CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_RELAY is not set
-CONFIG_INITRAMFS_SOURCE=""
+# 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_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -58,31 +77,38 @@ 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_SLAB=y
+CONFIG_AIO=y
 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_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
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
-# CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
-
-#
-# Block layer
-#
 CONFIG_BLOCK=y
 # CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
 
 #
 # IO Schedulers
@@ -96,6 +122,7 @@ CONFIG_DEFAULT_DEADLINE=y
 # CONFIG_DEFAULT_CFQ is not set
 # CONFIG_DEFAULT_NOOP is not set
 CONFIG_DEFAULT_IOSCHED="deadline"
+# CONFIG_FREEZER is not set
 
 #
 # System Type
@@ -105,29 +132,40 @@ CONFIG_DEFAULT_IOSCHED="deadline"
 # 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=y
 # CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC 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
-# CONFIG_ARCH_IOP13XX is not set
-# CONFIG_ARCH_IXP4XX is not set
-# CONFIG_ARCH_IXP2000 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_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
 # CONFIG_ARCH_OMAP is not set
 
 #
@@ -138,14 +176,24 @@ CONFIG_CRUNCH=y
 #
 # EP93xx Platforms
 #
+# CONFIG_EP93XX_SDCE0_PHYS_OFFSET is not set
+CONFIG_EP93XX_SDCE3_SYNC_PHYS_OFFSET=y
 CONFIG_MACH_ADSSPHERE=y
+CONFIG_MACH_EDB93XX=y
+CONFIG_MACH_EDB9301=y
 CONFIG_MACH_EDB9302=y
-CONFIG_MACH_EDB9302A=y
+CONFIG_MACH_EDB9307=y
 CONFIG_MACH_EDB9312=y
 CONFIG_MACH_EDB9315=y
-CONFIG_MACH_EDB9315A=y
 CONFIG_MACH_GESBC9312=y
+CONFIG_MACH_MICRO9=y
+CONFIG_MACH_MICRO9H=y
+CONFIG_MACH_MICRO9M=y
+CONFIG_MACH_MICRO9L=y
 CONFIG_MACH_TS72XX=y
+CONFIG_EP93XX_EARLY_UART1=y
+# CONFIG_EP93XX_EARLY_UART2 is not set
+# CONFIG_EP93XX_EARLY_UART3 is not set
 
 #
 # Processor Type
@@ -154,6 +202,7 @@ CONFIG_CPU_32=y
 CONFIG_CPU_ARM920T=y
 CONFIG_CPU_32v4T=y
 CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_PABRT_NOIFAR=y
 CONFIG_CPU_CACHE_V4WT=y
 CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_COPY_V4WB=y
@@ -168,34 +217,47 @@ 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_OUTER_CACHE is not set
 CONFIG_ARM_VIC=y
+CONFIG_COMMON_CLKDEV=y
 
 #
 # Bus support
 #
 CONFIG_ARM_AMBA=y
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
 # CONFIG_PCCARD is not set
 
 #
 # Kernel Features
 #
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
 # CONFIG_PREEMPT is not set
 CONFIG_HZ=100
-# CONFIG_AEABI is not set
-# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=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_SPARSEMEM_STATIC is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
 CONFIG_SPLIT_PTLOCK_CPUS=4096
-# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
 CONFIG_ALIGNMENT_TRAP=y
 
 #
@@ -205,6 +267,12 @@ CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="console=ttyAM0,115200 root=/dev/nfs ip=bootp"
 # CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_IDLE is not set
 
 #
 # Floating point emulation
@@ -221,32 +289,31 @@ CONFIG_FPE_NWFPE_XP=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
 
 #
 # Power management options
 #
 # CONFIG_PM is not set
-# CONFIG_APM is not set
-
-#
-# Networking
-#
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_NET=y
 
 #
 # Networking options
 #
-# CONFIG_NETDEBUG is not set
 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=y
+# CONFIG_NET_KEY_MIGRATE is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ADVANCED_ROUTER is not set
@@ -267,6 +334,7 @@ CONFIG_SYN_COOKIES=y
 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
@@ -276,6 +344,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 CONFIG_IPV6=y
 # 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
@@ -289,25 +358,15 @@ CONFIG_IPV6=y
 # CONFIG_IPV6_SIT is not set
 # CONFIG_IPV6_TUNNEL is not set
 # CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
 # 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
@@ -317,20 +376,28 @@ CONFIG_IPV6=y
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
+# CONFIG_PHONET 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_IEEE80211 is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_OLD_REGULATORY is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_LIB80211 is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -339,41 +406,39 @@ CONFIG_IPV6=y
 #
 # Generic Driver Options
 #
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 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
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
 # CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
 CONFIG_MTD_CONCAT=y
 CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
 CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
 # CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
 # CONFIG_MTD_REDBOOT_PARTS_READONLY 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
@@ -404,16 +469,13 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 CONFIG_MTD_ROM=y
 # CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_OBSOLETE_CHIPS 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=1
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
 # CONFIG_MTD_ARM_INTEGRATOR is not set
 # CONFIG_MTD_PLATRAM is not set
 
@@ -431,49 +493,58 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=1
 # 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=y
 CONFIG_MTD_NAND_VERIFY_WRITE=y
 # CONFIG_MTD_NAND_ECC_SMC is not set
-CONFIG_MTD_NAND_TS7250=y
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
+# CONFIG_MTD_NAND_TS7250 is not set
 CONFIG_MTD_NAND_IDS=y
 # CONFIG_MTD_NAND_DISKONCHIP is not set
 # CONFIG_MTD_NAND_NANDSIM is not set
-
-#
-# OneNAND Flash Device Drivers
-#
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
 # CONFIG_MTD_ONENAND is not set
 
 #
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
+# LPDDR flash memory drivers
 #
+# CONFIG_MTD_LPDDR is not set
 
 #
-# Block devices
+# 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_NBD=y
 # CONFIG_BLK_DEV_UB is not set
 # CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH 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_LEGACY=y
+# 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 is not set
@@ -495,6 +566,7 @@ CONFIG_BLK_DEV_SD=y
 # 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
@@ -502,92 +574,71 @@ CONFIG_BLK_DEV_SD=y
 # CONFIG_SCSI_SPI_ATTRS is not set
 # CONFIG_SCSI_FC_ATTRS is not set
 # CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_ATTRS is not set
 # CONFIG_SCSI_SAS_LIBSAS is not set
-
-#
-# SCSI low-level drivers
-#
+# 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
-
-#
-# Serial ATA (prod) and Parallel ATA (experimental) drivers
-#
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
 # CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
 # CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-
-#
-# I2O device support
-#
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
+CONFIG_COMPAT_NET_DEV_OPS=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
-
-#
-# PHY device support
-#
+# CONFIG_VETH is not set
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 CONFIG_EP93XX_ETH=y
+# CONFIG_AX88796 is not set
 # CONFIG_SMC91X is not set
 # 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_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
 
 #
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-
-#
-# Token Ring devices
+# Wireless LAN
 #
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Enable WiMAX (Networking options) to see the WiMAX drivers
 #
-# CONFIG_NET_RADIO is not set
 
 #
-# Wan interfaces
+# USB Network Adapters
 #
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+CONFIG_USB_RTL8150=y
+# CONFIG_USB_USBNET is not set
 # CONFIG_WAN is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
-# CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
 
 #
@@ -605,6 +656,7 @@ CONFIG_EP93XX_ETH=y
 # Character devices
 #
 # CONFIG_VT is not set
+CONFIG_DEVKMEM=y
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
@@ -621,104 +673,101 @@ CONFIG_SERIAL_AMBA_PL010_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 is not set
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
-
-#
-# Watchdog Device Drivers
-#
-# CONFIG_SOFT_WATCHDOG is not set
-CONFIG_EP93XX_WATCHDOG=y
-
-#
-# USB-based Watchdog Cards
-#
-# CONFIG_USBPCWATCHDOG is not set
 # CONFIG_HW_RANDOM is not set
-# CONFIG_NVRAM is not set
-# CONFIG_DTLK 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_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
 
 #
-# TPM devices
+# I2C Hardware Bus support
 #
-# CONFIG_TCG_TPM is not set
 
 #
-# I2C support
+# I2C system bus drivers (mostly embedded / system-on-chip)
 #
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
 
 #
-# I2C Algorithms
+# External I2C/SMBus adapter drivers
 #
-CONFIG_I2C_ALGOBIT=y
-# CONFIG_I2C_ALGOPCF is not set
-# CONFIG_I2C_ALGOPCA is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
 
 #
-# I2C Hardware Bus support
+# Other I2C/SMBus bus drivers
 #
-# CONFIG_I2C_OCORES is not set
-# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
 # CONFIG_I2C_STUB is not set
-# CONFIG_I2C_PCA_ISA is not set
 
 #
 # Miscellaneous I2C Chip support
 #
-# CONFIG_SENSORS_DS1337 is not set
-# CONFIG_SENSORS_DS1374 is not set
-CONFIG_EEPROM_LEGACY=y
+# CONFIG_DS1682 is not set
 # 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=y
 CONFIG_I2C_DEBUG_ALGO=y
 CONFIG_I2C_DEBUG_BUS=y
 CONFIG_I2C_DEBUG_CHIP=y
+# CONFIG_SPI is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
 
 #
-# SPI support
+# Memory mapped GPIO expanders:
 #
-# CONFIG_SPI is not set
-# CONFIG_SPI_MASTER is not set
 
 #
-# Dallas's 1-wire bus
+# I2C GPIO expanders:
 #
-# CONFIG_W1 is not set
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
 
 #
-# Hardware Monitoring support
+# PCI GPIO expanders:
 #
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
-# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 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_ASB100 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_FSCHER is not set
-# CONFIG_SENSORS_FSCPOS 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
@@ -732,158 +781,188 @@ CONFIG_HWMON=y
 # 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_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_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_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
 
 #
-# Misc devices
+# Watchdog Device Drivers
 #
-# CONFIG_TIFM_CORE is not set
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_EP93XX_WATCHDOG=y
 
 #
-# LED devices
+# USB-based Watchdog Cards
 #
-# CONFIG_NEW_LEDS is not set
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
 
 #
-# LED drivers
+# Sonics Silicon Backplane
 #
+# CONFIG_SSB is not set
 
 #
-# LED Triggers
+# 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_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_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
 
 #
-# Digital Video Broadcasting Devices
+# Multimedia drivers
 #
-# CONFIG_DVB is not set
-# CONFIG_USB_DABUSB is not set
+# CONFIG_DAB is not set
 
 #
 # Graphics support
 #
-# CONFIG_FIRMWARE_EDID 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
 
 #
-# Sound
+# Display device support
 #
+# CONFIG_DISPLAY_SUPPORT is not set
 # CONFIG_SOUND is not set
-
-#
-# USB support
-#
+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 is not set
 
 #
 # Miscellaneous USB options
 #
 CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_BANDWIDTH is not set
+CONFIG_USB_DEVICE_CLASS=y
 CONFIG_USB_DYNAMIC_MINORS=y
-# CONFIG_USB_MULTITHREAD_PROBE 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_OXU210HP_HCD is not set
 # CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
 CONFIG_USB_OHCI_HCD=y
-# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+# 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
 
 #
 # 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_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_DPCM 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_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
 # CONFIG_USB_LIBUSUAL is not set
 
-#
-# USB Input Devices
-#
-
-#
-# USB HID Boot Protocol drivers
-#
-
 #
 # USB Imaging devices
 #
 # CONFIG_USB_MDC800 is not set
 # CONFIG_USB_MICROTEK is not set
 
-#
-# USB Network Adapters
-#
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
-CONFIG_USB_RTL8150=y
-# CONFIG_USB_USBNET_MII is not set
-# CONFIG_USB_USBNET is not set
-# CONFIG_USB_MON is not set
-
 #
 # USB port drivers
 #
-
-#
-# USB Serial Converter support
-#
 CONFIG_USB_SERIAL=y
 CONFIG_USB_SERIAL_CONSOLE=y
+# CONFIG_USB_EZUSB is not set
 # CONFIG_USB_SERIAL_GENERIC is not set
 # CONFIG_USB_SERIAL_AIRCABLE is not set
-# CONFIG_USB_SERIAL_AIRPRIME is not set
 # CONFIG_USB_SERIAL_ARK3116 is not set
 # CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_CH341 is not set
 # CONFIG_USB_SERIAL_WHITEHEAT is not set
 # CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_CP2101 is not set
+# CONFIG_USB_SERIAL_CP210X is not set
 # CONFIG_USB_SERIAL_CYPRESS_M8 is not set
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
@@ -895,6 +974,7 @@ CONFIG_USB_SERIAL_CONSOLE=y
 # CONFIG_USB_SERIAL_EDGEPORT_TI is not set
 # CONFIG_USB_SERIAL_GARMIN is not set
 # CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_IUU is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
 # CONFIG_USB_SERIAL_KEYSPAN is not set
 # CONFIG_USB_SERIAL_KLSI is not set
@@ -902,16 +982,23 @@ CONFIG_USB_SERIAL_CONSOLE=y
 # CONFIG_USB_SERIAL_MCT_U232 is not set
 # CONFIG_USB_SERIAL_MOS7720 is not set
 # CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_MOTOROLA is not set
 # CONFIG_USB_SERIAL_NAVMAN is not set
 CONFIG_USB_SERIAL_PL2303=y
+# CONFIG_USB_SERIAL_OTI6858 is not set
+# CONFIG_USB_SERIAL_QUALCOMM is not set
+# CONFIG_USB_SERIAL_SPCP8X5 is not set
 # CONFIG_USB_SERIAL_HP4X is not set
 # CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_SIEMENS_MPI is not set
 # CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
+# CONFIG_USB_SERIAL_SYMBOL is not set
 # CONFIG_USB_SERIAL_TI is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
 # CONFIG_USB_SERIAL_OPTION is not set
 # CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_OPTICON is not set
 # CONFIG_USB_SERIAL_DEBUG is not set
 
 #
@@ -920,38 +1007,34 @@ CONFIG_USB_SERIAL_PL2303=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
+# 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_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
-
-#
-# USB DSL modem support
-#
-
-#
-# USB Gadget Support
-#
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
 # CONFIG_USB_GADGET is not set
 
 #
-# MMC/SD Card support
+# OTG and related infrastructure
 #
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_NOP_USB_XCEIV is not set
 # CONFIG_MMC is not set
-
-#
-# Real Time Clock
-#
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_NEW_LEDS is not set
 CONFIG_RTC_LIB=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_HCTOSYS=y
@@ -965,24 +1048,55 @@ 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
 
 #
-# RTC drivers
+# I2C RTC drivers
 #
-# CONFIG_RTC_DRV_X1205 is not set
 CONFIG_RTC_DRV_DS1307=y
-# CONFIG_RTC_DRV_DS1553 is not set
-# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
 # CONFIG_RTC_DRV_DS1672 is not set
-# CONFIG_RTC_DRV_DS1742 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_RS5C372 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
+
+#
+# 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=y
+# 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_EP93XX=y
+# CONFIG_RTC_DRV_PL030 is not set
 # CONFIG_RTC_DRV_PL031 is not set
-# CONFIG_RTC_DRV_TEST is not set
-# CONFIG_RTC_DRV_V3020 is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
 
 #
 # File systems
@@ -991,26 +1105,30 @@ 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_EXT4DEV_FS 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_FILE_LOCKING=y
 # CONFIG_XFS_FS is not set
-# CONFIG_GFS2_FS is not set
 # CONFIG_OCFS2_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_DNOTIFY=y
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY_USER=y
 # CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=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
 #
@@ -1032,16 +1150,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_RAMFS=y
 # 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
@@ -1049,33 +1164,35 @@ 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_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 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
-
-#
-# Network File Systems
-#
+# 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 is not set
-# CONFIG_NFS_DIRECTIO is not set
-# CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
 CONFIG_NFS_COMMON=y
@@ -1087,7 +1204,6 @@ CONFIG_SUNRPC=y
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -1109,10 +1225,7 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_SUN_PARTITION is not set
 # CONFIG_KARMA_PARTITION is not set
 # CONFIG_EFI_PARTITION is not set
-
-#
-# Native Language Support
-#
+# CONFIG_SYSV68_PARTITION is not set
 CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
 CONFIG_NLS_CODEPAGE_437=y
@@ -1153,49 +1266,83 @@ CONFIG_NLS_ISO8859_1=y
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_U is not set
 # CONFIG_NLS_UTF8 is not set
-
-#
-# Distributed Lock Manager
-#
 # CONFIG_DLM is not set
 
-#
-# Profiling support
-#
-# CONFIG_PROFILING 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_UNUSED_SYMBOLS is not set
 # CONFIG_DEBUG_FS is not set
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
-CONFIG_LOG_BUF_SHIFT=14
+# 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=y
 # CONFIG_DEBUG_SLAB_LEAK 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_RWSEMS 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 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_FRAME_POINTER=y
-CONFIG_FORCED_INLINING=y
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS 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_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
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_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_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=y
 # CONFIG_DEBUG_ICEDCC is not set
 
@@ -1204,21 +1351,115 @@ CONFIG_DEBUG_LL=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=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=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
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# 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 is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
 
 #
-# Cryptographic options
+# Random Number Generation
 #
-# CONFIG_CRYPTO is not set
+# 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=y
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
-CONFIG_PLIST=y
-CONFIG_IOMAP_COPY=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
index dcf8153a947dc684114f75150fb3840246a06dec..0a1abb978d7efe4b8b475fc588eee5a1e4e54deb 100644 (file)
@@ -182,6 +182,7 @@ CONFIG_ARCH_KIRKWOOD=y
 CONFIG_MACH_DB88F6281_BP=y
 CONFIG_MACH_RD88F6192_NAS=y
 CONFIG_MACH_RD88F6281=y
+CONFIG_MACH_MV88F6281GTW_GE=y
 CONFIG_MACH_SHEEVAPLUG=y
 CONFIG_MACH_TS219=y
 CONFIG_PLAT_ORION=y
@@ -270,7 +271,9 @@ CONFIG_CMDLINE=""
 #
 # CPU Power Management
 #
-# CONFIG_CPU_IDLE is not set
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
 
 #
 # Floating point emulation
index f56837f69ca7323130828ab367e736e59ca98ea6..957fd5fa27ca26d6b375dee680e4a426b5e863d5 100644 (file)
@@ -190,6 +190,7 @@ CONFIG_ARCH_PXA=y
 # CONFIG_MACH_SAAR is not set
 # CONFIG_MACH_ARMCORE is not set
 # CONFIG_MACH_CM_X300 is not set
+CONFIG_MACH_H4700=y
 CONFIG_MACH_MAGICIAN=y
 # CONFIG_MACH_MIOA701 is not set
 # CONFIG_MACH_PCM027 is not set
@@ -828,7 +829,7 @@ CONFIG_SSB_POSSIBLE=y
 #
 # CONFIG_MFD_CORE is not set
 # CONFIG_MFD_SM501 is not set
-# CONFIG_MFD_ASIC3 is not set
+CONFIG_MFD_ASIC3=y
 CONFIG_HTC_EGPIO=y
 CONFIG_HTC_PASIC3=y
 # CONFIG_TPS65010 is not set
@@ -891,7 +892,7 @@ CONFIG_FB_PXA_OVERLAY=y
 # CONFIG_FB_PXA_SMARTPANEL is not set
 # CONFIG_FB_PXA_PARAMETERS is not set
 # CONFIG_FB_MBX is not set
-# CONFIG_FB_W100 is not set
+CONFIG_FB_W100=y
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FB_METRONOME is not set
 # CONFIG_FB_MB862XX is not set
diff --git a/arch/arm/configs/mx21_defconfig b/arch/arm/configs/mx21_defconfig
new file mode 100644 (file)
index 0000000..4b04290
--- /dev/null
@@ -0,0 +1,1170 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.30-rc1
+# Tue Apr 14 16:58:09 2009
+#
+CONFIG_ARM=y
+CONFIG_HAVE_PWM=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
+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_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"
+
+#
+# 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 is not set
+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_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_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=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+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
+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_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# 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_LBD 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 is not set
+
+#
+# System Type
+#
+# 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_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X 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_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=y
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MMP 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_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_W90X900 is not set
+
+#
+# Freescale MXC Implementations
+#
+# CONFIG_ARCH_MX1 is not set
+CONFIG_ARCH_MX2=y
+# CONFIG_ARCH_MX3 is not set
+CONFIG_MACH_MX21=y
+# CONFIG_MACH_MX27 is not set
+
+#
+# MX2 platforms:
+#
+CONFIG_MACH_MX21ADS=y
+# CONFIG_MXC_IRQ_PRIOR is not set
+CONFIG_MXC_PWM=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_NOIFAR=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_OUTER_CACHE 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=y
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=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_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# 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 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 is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_UNIX is not set
+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=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_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 is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# 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_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_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_WIRELESS_OLD_REGULATORY is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_LIB80211 is not set
+# CONFIG_MAC80211 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_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=3
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY 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=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 is not set
+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_OTP 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
+# 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_COMPAT is not set
+# CONFIG_MTD_ARM_INTEGRATOR 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_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_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_NAND_MXC=y
+# 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_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH 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_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_COMPAT_NET_DEV_OPS=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 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 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_CS89x0=y
+CONFIG_CS89x0_NONISA_IRQ=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# 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
+
+#
+# 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 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_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 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 is not set
+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=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=1
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_IMX=y
+CONFIG_SERIAL_IMX_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 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=y
+CONFIG_I2C_BOARDINFO=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_GPIO is not set
+CONFIG_I2C_IMX=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
+
+#
+# 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_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 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_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# 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:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 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_THERMAL_HWMON 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_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
+
+#
+# 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_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_IMX=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
+#
+# 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 is not set
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+# 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 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 is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT 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_MXC=y
+# CONFIG_MMC_SPI is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_UIO is not set
+# 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 is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+# 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_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_VFAT_FS is not set
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+# 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_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_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 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 is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# 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 is not set
+# 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 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 is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_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_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_FIPS is not set
+# 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
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C 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 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 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_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/arm/configs/omap3_evm_defconfig b/arch/arm/configs/omap3_evm_defconfig
new file mode 100644 (file)
index 0000000..28be17f
--- /dev/null
@@ -0,0 +1,1528 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.30-rc5
+# Mon May 18 14:01:52 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
+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_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"
+
+#
+# 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_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_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_STRIP_ASM_SYMS 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
+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_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
+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_LBD 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=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_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_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_FOOTBRIDGE 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
+# 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_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_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MMP 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_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_W90X900 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
+
+#
+# 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 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=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=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=y
+# CONFIG_MACH_OMAP3_PANDORA is not set
+# CONFIG_MACH_OMAP_3430SDP is not set
+# CONFIG_MACH_NOKIA_RX51 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_IFAR=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_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
+#
+# 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 is not set
+CONFIG_HZ=128
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=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_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# 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=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_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_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_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_WIRELESS_OLD_REGULATORY is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_LIB80211 is not set
+# CONFIG_MAC80211 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_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=y
+# CONFIG_MTD_DEBUG is not set
+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=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_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_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 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_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
+
+#
+# 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
+# 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_COMPAT_NET_DEV_OPS=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 is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+CONFIG_SMC911X=y
+# 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_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# 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
+
+#
+# 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=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_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_GPIO 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_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_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_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# 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_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 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_GPIO is not set
+CONFIG_SPI_OMAP24XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 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_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=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_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_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_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=y
+# CONFIG_USB_DABUSB 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 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=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_DRAGONRISE_FF 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 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_GREENASIA_FF is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF 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=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_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
+# 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_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_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_PXA27X is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_IMX 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_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+CONFIG_USB_ZERO=m
+# CONFIG_USB_ZERO_HNPTEST 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=m
+# CONFIG_MMC_SPI is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# 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
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+CONFIG_REGULATOR_TWL4030=y
+# CONFIG_UIO 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=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_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+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 is not set
+# 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_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_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_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_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_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_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
+
+#
+# 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_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_FIPS is not set
+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
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# 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
diff --git a/arch/arm/configs/omap_4430sdp_defconfig b/arch/arm/configs/omap_4430sdp_defconfig
new file mode 100644 (file)
index 0000000..23e43ea
--- /dev/null
@@ -0,0 +1,866 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.30-rc7
+# Tue Jun  9 12:36:23 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_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_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"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=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_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_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 is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+# CONFIG_ELF_CORE is not set
+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
+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_MARKERS 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
+CONFIG_HAVE_CLK=y
+# 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_STOP_MACHINE=y
+CONFIG_BLOCK=y
+# CONFIG_LBD 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=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_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_NETX is not set
+# CONFIG_ARCH_H720X 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_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+
+#
+# TI OMAP Implementations
+#
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_ARCH_OMAP2 is not set
+# CONFIG_ARCH_OMAP3 is not set
+CONFIG_ARCH_OMAP4=y
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# 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=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+
+#
+# OMAP Board Type
+#
+CONFIG_MACH_OMAP_4430SDP=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_IFAR=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 is not set
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+CONFIG_CPU_DCACHE_DISABLE=y
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+# 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
+
+#
+# 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_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 is not set
+CONFIG_HZ=128
+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_UNEVICTABLE_LRU is not set
+CONFIG_HAVE_MLOCK=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/ram0 rw mem=128M console=ttyS0,115200n8 initrd=0x81600000,20M ramdisk_size=20480"
+# 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 is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+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 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+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_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_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_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
+
+#
+# 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
+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:
+#
+# 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
+
+#
+# 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
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+CONFIG_DAB=y
+
+#
+# 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_ACCESSIBILITY is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_UIO 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=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_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+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_NILFS2_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=y
+# 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_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS 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_FRAME_POINTER=y
+# 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_FAULT_INJECTION is not set
+# 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_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
+
+#
+# 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_FIPS is not set
+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
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# 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
diff --git a/arch/arm/configs/omap_zoom2_defconfig b/arch/arm/configs/omap_zoom2_defconfig
new file mode 100644 (file)
index 0000000..213fe9c
--- /dev/null
@@ -0,0 +1,1211 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.27-rc5
+# Fri Oct 10 11:49:41 2008
+#
+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
+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_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# 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_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 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_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_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=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_COMPAT_BRK=y
+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_VM_EVENT_COUNTERS=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_EFFICIENT_UNALIGNED_ACCESS is not set
+# CONFIG_HAVE_IOREMAP_PROT is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_ARCH_TRACEHOOK is not set
+# CONFIG_HAVE_DMA_ATTRS is not set
+# CONFIG_USE_GENERIC_SMP_HELPERS is not set
+CONFIG_HAVE_CLK=y
+CONFIG_PROC_PAGE_MONITOR=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
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+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_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_CLASSIC_RCU=y
+
+#
+# System Type
+#
+# 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_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE 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
+# 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_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_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_MSM7X00A 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
+
+#
+# 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_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_SERIAL_WAKE=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_OMAP_ZOOM2=y
+# CONFIG_MACH_OVERO is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# 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_IFAR=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_OUTER_CACHE is not set
+
+#
+# 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_PREEMPT is not set
+CONFIG_HZ=128
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE 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=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# 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 Frequency scaling
+#
+# CONFIG_CPU_FREQ 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_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_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_NET_SCHED 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_PHONET is not set
+# CONFIG_WIRELESS 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_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_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_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_ENCLOSURE_SERVICES 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
+
+#
+# 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
+# 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_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH 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_SMC911X is not set
+CONFIG_SMSC911X=y
+# 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_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# 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
+
+#
+# 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_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO 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_TOUCHIT213 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_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM 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_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# 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
+
+#
+# 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_AT24 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_ISP1301_OMAP 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_OMAP24XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# 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_W1=y
+
+#
+# 1-wire Bus Masters
+#
+# CONFIG_W1_MASTER_DS2482 is not set
+# CONFIG_W1_MASTER_DS1WM is not set
+# CONFIG_W1_MASTER_GPIO is not set
+
+#
+# 1-wire Slaves
+#
+# CONFIG_W1_SLAVE_THERM is not set
+# CONFIG_W1_SLAVE_SMEM is not set
+# CONFIG_W1_SLAVE_DS2433 is not set
+# CONFIG_W1_SLAVE_DS2760 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_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 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
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+CONFIG_DAB=y
+
+#
+# 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_SND=y
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS 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_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_SOC 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
+# CONFIG_USB_SUPPORT is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD 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 Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_OMAP is not set
+# CONFIG_MMC_SPI is not set
+# CONFIG_NEW_LEDS 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
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS 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_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_DMADEVICES is not set
+
+#
+# Voltage and Current regulators
+#
+# CONFIG_REGULATOR is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_UIO 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_FS_XATTR is not set
+# CONFIG_EXT4DEV_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_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+CONFIG_PRINT_QUOTA_WARNING=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
+
+#
+# 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_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_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_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_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_SUNRPC_REGISTER_V4 is not set
+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
+
+#
+# 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_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_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_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_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_HAVE_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+# CONFIG_FTRACE is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB 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=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# 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=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
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C 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_LZO is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+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_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
index 5b98f7645119ce0627e90a99dc9c889d1a303a98..9e2385293ecbc52449933bfa60adb3247d4286c6 100644 (file)
@@ -903,7 +903,8 @@ CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=16
 # CONFIG_IPMI_HANDLER is not set
-# CONFIG_HW_RANDOM is not set
+CONFIG_HW_RANDOM=m
+CONFIG_HW_RANDOM_TIMERIOMEM=m
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
 # CONFIG_RAW_DRIVER is not set
index 593102da8cd74bdc90ceffdaaf24777c42c39f52..eb2cb31825c0b4a797258f652ef75d54f96233cb 100644 (file)
@@ -282,7 +282,7 @@ CONFIG_ALIGNMENT_TRAP=y
 #
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="init=/sbin/preinit ubi.mtd=4 root=ubi0:rootfs rootfstype=ubifs rw console=ttyMTD5"
+CONFIG_CMDLINE="init=/sbin/preinit ubi.mtd=rootfs root=ubi0:rootfs rootfstype=ubifs rootflags=bulk_read,no_chk_data_crc rw console=ttyMTD,log console=tty0"
 # CONFIG_XIP_KERNEL is not set
 # CONFIG_KEXEC is not set
 
diff --git a/arch/arm/configs/stmp378x_defconfig b/arch/arm/configs/stmp378x_defconfig
new file mode 100644 (file)
index 0000000..44461f1
--- /dev/null
@@ -0,0 +1,1141 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.30-rc2
+# Thu Apr 23 02:44: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
+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_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"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION="-default"
+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_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_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 is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_INITRAMFS_ROOT_UID=0
+CONFIG_INITRAMFS_ROOT_GID=0
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_INITRAMFS_COMPRESSION_NONE is not set
+CONFIG_INITRAMFS_COMPRESSION_GZIP=y
+# CONFIG_INITRAMFS_COMPRESSION_BZIP2 is not set
+# CONFIG_INITRAMFS_COMPRESSION_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=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_STRIP_ASM_SYMS=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
+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_TRACEPOINTS=y
+CONFIG_MARKERS=y
+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
+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=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_BLOCK=y
+CONFIG_LBD=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_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_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_FOOTBRIDGE 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
+# 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_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_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MMP 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_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_W90X900 is not set
+CONFIG_ARCH_STMP3XXX=y
+
+#
+# Freescale STMP3xxx implementations
+#
+# CONFIG_ARCH_STMP37XX is not set
+CONFIG_ARCH_STMP378X=y
+# CONFIG_MACH_STMP37XX is not set
+CONFIG_MACH_STMP378X=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_NOIFAR=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_OUTER_CACHE 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=y
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+CONFIG_HIGHMEM=y
+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_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttySDBG0,115200 mem=32M"
+# 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 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 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=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=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=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# 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 is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP 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_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+# CONFIG_NET_SCH_CBQ is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_MULTIQ is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TEQL is not set
+# CONFIG_NET_SCH_TBF is not set
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_DSMARK is not set
+# CONFIG_NET_SCH_NETEM is not set
+# CONFIG_NET_SCH_DRR is not set
+
+#
+# Classification
+#
+# CONFIG_NET_CLS_BASIC is not set
+# CONFIG_NET_CLS_TCINDEX is not set
+# CONFIG_NET_CLS_ROUTE4 is not set
+# CONFIG_NET_CLS_FW is not set
+# CONFIG_NET_CLS_U32 is not set
+# CONFIG_NET_CLS_RSVP is not set
+# CONFIG_NET_CLS_RSVP6 is not set
+# CONFIG_NET_CLS_FLOW is not set
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_SCH_FIFO=y
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN 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 is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_FIB_RULES=y
+# 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_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 is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_PARTITIONS is not set
+# CONFIG_MTD_TESTS is not set
+
+#
+# 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_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 is not set
+# CONFIG_MTD_JEDECPROBE 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_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_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=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_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_PLATFORM 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=y
+
+#
+# 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=y
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=4
+CONFIG_BLK_DEV_RAM_SIZE=6144
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH 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=y
+# 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
+# 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 is not set
+# CONFIG_MD is not set
+# CONFIG_NETDEVICES is not set
+# CONFIG_ISDN 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=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=320
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=240
+# 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_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# 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_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_AD7879 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_TOUCHIT213 is not set
+CONFIG_INPUT_MISC=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 is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# 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 is not set
+
+#
+# Non-8250 serial port support
+#
+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
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI 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
+
+#
+# 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
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
+# CONFIG_VIDEO_ALLOW_V4L1 is not set
+# CONFIG_VIDEO_V4L1_COMPAT is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_VIDEO_MEDIA=y
+
+#
+# Multimedia drivers
+#
+# CONFIG_MEDIA_ATTACH is not set
+CONFIG_VIDEO_V4L2=y
+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 is not set
+
+#
+# Encoders/decoders and other helper chips
+#
+
+#
+# Audio decoders
+#
+
+#
+# RDS decoders
+#
+
+#
+# Video decoders
+#
+
+#
+# Video and audio decoders
+#
+
+#
+# MPEG video encoders
+#
+# CONFIG_VIDEO_CX2341X is not set
+
+#
+# Video encoders
+#
+
+#
+# Video improvement chips
+#
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_SOC_CAMERA is not set
+# CONFIG_RADIO_ADAPTERS is not set
+# CONFIG_DAB 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 is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# 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_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=y
+CONFIG_LCD_CLASS_DEVICE=y
+# CONFIG_LCD_ILI9320 is not set
+# CONFIG_LCD_PLATFORM is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
+
+#
+# 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 is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_UIO is not set
+# 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 is not set
+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_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+# 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=m
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_NETWORK_FILESYSTEMS 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 is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ 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=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 is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+CONFIG_DEBUG_OBJECTS=y
+CONFIG_DEBUG_OBJECTS_SELFTEST=y
+CONFIG_DEBUG_OBJECTS_FREE=y
+CONFIG_DEBUG_OBJECTS_TIMERS=y
+CONFIG_DEBUG_OBJECTS_ENABLE_DEFAULT=1
+CONFIG_DEBUG_SLAB=y
+CONFIG_DEBUG_SLAB_LEAK=y
+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=y
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
+CONFIG_DEBUG_KOBJECT=y
+# CONFIG_DEBUG_HIGHMEM 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_FRAME_POINTER=y
+# 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_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_PAGE_POISONING is not set
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_RING_BUFFER=y
+CONFIG_TRACING=y
+CONFIG_TRACING_SUPPORT=y
+
+#
+# Tracers
+#
+CONFIG_FUNCTION_TRACER=y
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+CONFIG_CONTEXT_SWITCH_TRACER=y
+# CONFIG_EVENT_TRACER is not set
+CONFIG_BOOT_TRACER=y
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_STACK_TRACER=y
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+CONFIG_BLK_DEV_IO_TRACE=y
+# CONFIG_FTRACE_STARTUP_TEST 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 is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
+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_DEFAULT_MMAP_MIN_ADDR=0
+# CONFIG_SECURITY_TOMOYO is not set
+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
+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=m
+
+#
+# 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=y
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C 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=m
+# 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=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=m
+CONFIG_CRC16=y
+# 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_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/arm/configs/stmp37xx_defconfig b/arch/arm/configs/stmp37xx_defconfig
new file mode 100644 (file)
index 0000000..401279d
--- /dev/null
@@ -0,0 +1,1002 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.29.1
+# Mon Apr 20 04:41:26 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
+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_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"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION="-default"
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=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_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_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 is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_INITRAMFS_ROOT_UID=0
+CONFIG_INITRAMFS_ROOT_GID=0
+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
+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_TRACEPOINTS=y
+CONFIG_MARKERS=y
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+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=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_BLOCK=y
+CONFIG_LBD=y
+CONFIG_BLK_DEV_IO_TRACE=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_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_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE 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
+# 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_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_PNX4008 is not set
+# CONFIG_ARCH_PXA 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_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_W90X900 is not set
+CONFIG_ARCH_STMP3XXX=y
+
+#
+# Freescale STMP3xxx implementations
+#
+CONFIG_ARCH_STMP37XX=y
+# CONFIG_ARCH_STMP378X is not set
+CONFIG_MACH_STMP37XX=y
+# CONFIG_MACH_STMP378X 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_NOIFAR=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_OUTER_CACHE 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=y
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL 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_UNEVICTABLE_LRU=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttySDBG0,115200 mem=32M lcd_panel=lms350 rdinit=/bin/sh ignore_loglevel"
+# 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 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 is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_COMPAT_NET_DEV_OPS=y
+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=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=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=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# 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 is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP 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_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+# CONFIG_NET_SCH_CBQ is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_MULTIQ is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TEQL is not set
+# CONFIG_NET_SCH_TBF is not set
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_DSMARK is not set
+# CONFIG_NET_SCH_NETEM is not set
+# CONFIG_NET_SCH_DRR is not set
+
+#
+# Classification
+#
+# CONFIG_NET_CLS_BASIC is not set
+# CONFIG_NET_CLS_TCINDEX is not set
+# CONFIG_NET_CLS_ROUTE4 is not set
+# CONFIG_NET_CLS_FW is not set
+# CONFIG_NET_CLS_U32 is not set
+# CONFIG_NET_CLS_RSVP is not set
+# CONFIG_NET_CLS_RSVP6 is not set
+# CONFIG_NET_CLS_FLOW is not set
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_SCH_FIFO=y
+# 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_PHONET is not set
+CONFIG_FIB_RULES=y
+# 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_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 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=y
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=4
+CONFIG_BLK_DEV_RAM_SIZE=6144
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH 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=y
+# 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
+# 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_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_NETDEVICES is not set
+# CONFIG_ISDN 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=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=320
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=240
+# 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_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# 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_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# 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_TOUCHIT213 is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_UINPUT is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# 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 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_STMP_DBG is not set
+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_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
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI 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
+
+#
+# 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
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
+# CONFIG_VIDEO_ALLOW_V4L1 is not set
+# CONFIG_VIDEO_V4L1_COMPAT is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_VIDEO_MEDIA=y
+
+#
+# Multimedia drivers
+#
+# CONFIG_MEDIA_ATTACH is not set
+CONFIG_VIDEO_V4L2=y
+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 is not set
+
+#
+# Encoders/decoders and other helper chips
+#
+
+#
+# Audio decoders
+#
+
+#
+# Video decoders
+#
+
+#
+# Video and audio decoders
+#
+
+#
+# MPEG video encoders
+#
+# CONFIG_VIDEO_CX2341X is not set
+
+#
+# Video encoders
+#
+
+#
+# Video improvement chips
+#
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_SOC_CAMERA is not set
+# CONFIG_RADIO_ADAPTERS is not set
+# CONFIG_DAB 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 is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# 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_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+# CONFIG_LCD_ILI9320 is not set
+# CONFIG_LCD_PLATFORM is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
+
+#
+# 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 is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_UIO is not set
+# 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 is not set
+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_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS 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=m
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_NETWORK_FILESYSTEMS 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 is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_SECTION_MISMATCH=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_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_PREEMPT=y
+# 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_STACKTRACE=y
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# 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_FRAME_POINTER=y
+# 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_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_RING_BUFFER=y
+CONFIG_TRACING=y
+
+#
+# Tracers
+#
+CONFIG_FUNCTION_TRACER=y
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+CONFIG_CONTEXT_SWITCH_TRACER=y
+CONFIG_BOOT_TRACER=y
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_STACK_TRACER=y
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB 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=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
+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_DEFAULT_MMAP_MIN_ADDR=0
+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
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# 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=m
+
+#
+# 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=y
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C 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=m
+# 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=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_LZO=y
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=y
+# 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_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/u300_defconfig b/arch/arm/configs/u300_defconfig
new file mode 100644 (file)
index 0000000..2d827e1
--- /dev/null
@@ -0,0 +1,1115 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.30-rc6
+# Mon Jun  1 09:18:22 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
+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_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"
+
+#
+# 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 is not set
+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_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_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_STRIP_ASM_SYMS 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 is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+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_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
+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_LBD 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=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+# CONFIG_FREEZER is not set
+
+#
+# System Type
+#
+# 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_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
+# 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_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_U300=y
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+
+#
+# ST-Ericsson AB U300/U330/U335/U365 Platform
+#
+
+#
+# ST-Ericsson Mobile Platform Products
+#
+CONFIG_MACH_U300=y
+
+#
+# ST-Ericsson U300/U330/U335/U365 Feature Selections
+#
+# CONFIG_MACH_U300_BS2X is not set
+# CONFIG_MACH_U300_BS330 is not set
+CONFIG_MACH_U300_BS335=y
+# CONFIG_MACH_U300_BS365 is not set
+# CONFIG_MACH_U300_SINGLE_RAM is not set
+CONFIG_MACH_U300_DUAL_RAM=y
+CONFIG_U300_DEBUG=y
+# CONFIG_MACH_U300_SEMI_IS_SHARED is not set
+
+#
+# All the settings below must match the bootloader's settings
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_NOIFAR=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_OUTER_CACHE is not set
+CONFIG_ARM_VIC=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_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=y
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=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_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/mtdblock2 rw rootfstype=yaffs2 console=ttyAMA0,115200n8 ab3100.force=0,0x48 mtdparts=u300nand:128k@0x0(bootrecords)ro,8064k@128k(free)ro,253952k@8192k(platform) lpj=515072"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+
+#
+# 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_SUSPEND is not set
+# CONFIG_APM_EMULATION 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_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 is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# 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_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_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_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+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_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
+# 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 is not set
+# CONFIG_MTD_JEDECPROBE 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_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_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 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=y
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO 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_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_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH 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_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 is not set
+# CONFIG_ISDN 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=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_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_GPIO 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 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=y
+CONFIG_LEGACY_PTY_COUNT=16
+# 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=y
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_CHARDEV is not set
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_GPIO is not set
+# 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
+
+#
+# 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_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 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_GPIO is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+# 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_BQ27x00 is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_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_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_PMIC_DA903X is not set
+# 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 is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB 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 is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# 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_ARMCLCD 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_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
+
+#
+# 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 is not set
+# CONFIG_LOGO is not set
+CONFIG_SOUND=y
+# CONFIG_SOUND_OSS_CORE is not set
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+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_HRTIMER is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_DRIVERS is not set
+# CONFIG_SND_ARM is not set
+# CONFIG_SND_SPI is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+# CONFIG_SOUND_PRIME is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT 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_ARMMMCI=y
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_SPI is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY 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_LP5521 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 is not set
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+# 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
+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
+
+#
+# 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
+
+#
+# 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_PL030 is not set
+# CONFIG_RTC_DRV_PL031 is not set
+CONFIG_DMADEVICES=y
+
+#
+# DMA Devices
+#
+# 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_BQ24022 is not set
+# CONFIG_UIO is not set
+# 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 is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=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_FAT_FS=y
+# CONFIG_MSDOS_FS is not set
+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 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_NILFS2_FS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# 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 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 is not set
+# CONFIG_DETECT_HUNG_TASK is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS 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 is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS 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_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
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_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_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 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_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
index 56bda7c6d670f37620a704071ee4a5c5ad7396b2..5245655a0ad32d913a4c5a4463b8bfbe40e387f7 100644 (file)
@@ -1,11 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.27-rc8-git8
-# Sat Nov 15 10:05:00 2008
+# Linux kernel version: 2.6.30
+# Wed Jun 10 22:09:25 2009
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
-# CONFIG_GENERIC_GPIO is not set
+CONFIG_GENERIC_GPIO=y
 # CONFIG_GENERIC_TIME is not set
 # CONFIG_GENERIC_CLOCKEVENTS is not set
 CONFIG_MMU=y
@@ -22,8 +22,6 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_ARCH_SUPPORTS_AOUT=y
-CONFIG_ZONE_DMA=y
 CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_VECTORS_BASE=0xffff0000
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
@@ -42,10 +40,19 @@ CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=17
-# CONFIG_CGROUPS is not set
 # CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
 CONFIG_SYSFS_DEPRECATED=y
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_RELAY=y
@@ -56,52 +63,53 @@ 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_INITRAMFS_COMPRESSION_NONE is not set
+# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
+# CONFIG_INITRAMFS_COMPRESSION_BZIP2 is not set
+# CONFIG_INITRAMFS_COMPRESSION_LZMA is not set
 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_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 CONFIG_ELF_CORE=y
-CONFIG_COMPAT_BRK=y
 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
 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_TRACEPOINTS=y
 # CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
-# CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set
-# CONFIG_HAVE_IOREMAP_PROT is not set
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
-# CONFIG_HAVE_ARCH_TRACEHOOK is not set
-# CONFIG_HAVE_DMA_ATTRS is not set
-# CONFIG_USE_GENERIC_SMP_HELPERS is not set
-# CONFIG_HAVE_CLK is not set
-CONFIG_PROC_PAGE_MONITOR=y
+# CONFIG_SLOW_WORK is not set
 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 is not set
 CONFIG_BLOCK=y
 CONFIG_LBD=y
-CONFIG_BLK_DEV_IO_TRACE=y
-CONFIG_LSF=y
 CONFIG_BLK_DEV_BSG=y
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
@@ -117,7 +125,7 @@ CONFIG_IOSCHED_CFQ=y
 CONFIG_DEFAULT_CFQ=y
 # CONFIG_DEFAULT_NOOP is not set
 CONFIG_DEFAULT_IOSCHED="cfq"
-CONFIG_CLASSIC_RCU=y
+# CONFIG_FREEZER is not set
 
 #
 # System Type
@@ -127,10 +135,10 @@ CONFIG_CLASSIC_RCU=y
 # 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_EBSA110 is not set
 # CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_GEMINI is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_NETX is not set
 # CONFIG_ARCH_H720X is not set
@@ -151,23 +159,17 @@ CONFIG_CLASSIC_RCU=y
 # CONFIG_ARCH_ORION5X is not set
 # CONFIG_ARCH_PNX4008 is not set
 # CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MMP 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_DAVINCI is not set
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_MSM7X00A is not set
+# CONFIG_ARCH_MSM is not set
 CONFIG_ARCH_W90X900=y
-
-#
-# Boot options
-#
-
-#
-# Power management
-#
 CONFIG_CPU_W90P910=y
 
 #
@@ -198,6 +200,7 @@ CONFIG_ARM_THUMB=y
 # CONFIG_CPU_DCACHE_WRITETHROUGH is not set
 # CONFIG_CPU_CACHE_ROUND_ROBIN is not set
 # CONFIG_OUTER_CACHE is not set
+CONFIG_COMMON_CLKDEV=y
 
 #
 # Bus support
@@ -209,27 +212,32 @@ CONFIG_ARM_THUMB=y
 #
 # Kernel Features
 #
-# CONFIG_TICK_ONESHOT is not set
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
 CONFIG_PREEMPT=y
 CONFIG_HZ=100
 CONFIG_AEABI=y
 CONFIG_OABI_COMPAT=y
-CONFIG_ARCH_FLATMEM_HAS_HOLES=y
-# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+# 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 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_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
 CONFIG_ALIGNMENT_TRAP=y
 
 #
@@ -237,11 +245,16 @@ CONFIG_ALIGNMENT_TRAP=y
 #
 CONFIG_ZBOOT_ROM_TEXT=0
 CONFIG_ZBOOT_ROM_BSS=0
-CONFIG_CMDLINE="root=/dev/ram0 console=ttyS0,115200n8 initrd=0xa00000,4000000 mem=64M"
+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
 #
@@ -258,6 +271,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
 
@@ -282,11 +297,93 @@ CONFIG_FW_LOADER=y
 CONFIG_FIRMWARE_IN_KERNEL=y
 CONFIG_EXTRA_FIRMWARE=""
 # CONFIG_SYS_HYPERVISOR is not set
-# CONFIG_MTD 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
@@ -300,9 +397,41 @@ CONFIG_HAVE_IDE=y
 # SCSI device support
 #
 # CONFIG_RAID_ATTRS is not set
-# CONFIG_SCSI is not set
-# CONFIG_SCSI_DMA 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
+
+#
+# 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
+# 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
 
@@ -354,38 +483,57 @@ CONFIG_HW_CONSOLE=y
 #
 # Serial drivers
 #
-# CONFIG_SERIAL_8250 is not set
+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_W90X900=y
-# CONFIG_SERIAL_W90X900_PORT1 is not set
-# CONFIG_SERIAL_W90X900_PORT2 is not set
-# CONFIG_SERIAL_W90X900_PORT3 is not set
-# CONFIG_SERIAL_W90X900_PORT4 is not set
-CONFIG_SERIAL_W90X900_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 is not set
 # CONFIG_IPMI_HANDLER is not set
 # CONFIG_HW_RANDOM is not set
-# CONFIG_NVRAM 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
+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:
+#
 # 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
 
 #
 # Sonics Silicon Backplane
 #
-CONFIG_SSB_POSSIBLE=y
 # CONFIG_SSB is not set
 
 #
@@ -393,10 +541,11 @@ CONFIG_SSB_POSSIBLE=y
 #
 # 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
 
 #
 # Multimedia devices
@@ -433,33 +582,131 @@ CONFIG_SSB_POSSIBLE=y
 CONFIG_DUMMY_CONSOLE=y
 # CONFIG_SOUND is not set
 # CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+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_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_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
+
+#
+# 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_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_ACCESSIBILITY is not set
 # CONFIG_NEW_LEDS is not set
 CONFIG_RTC_LIB=y
 # CONFIG_RTC_CLASS is not set
 # CONFIG_DMADEVICES is not set
-
-#
-# Voltage and Current regulators
-#
+# CONFIG_AUXDISPLAY is not set
 # CONFIG_REGULATOR is not set
-# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
-# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
-# CONFIG_REGULATOR_BQ24022 is not set
 # CONFIG_UIO is not set
+# CONFIG_STAGING is not set
 
 #
 # File systems
 #
 # CONFIG_EXT2_FS is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_EXT4DEV_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_FILE_LOCKING=y
 # CONFIG_XFS_FS is not set
 # CONFIG_GFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
 # CONFIG_DNOTIFY is not set
 # CONFIG_INOTIFY is not set
 # CONFIG_QUOTA is not set
@@ -468,6 +715,11 @@ CONFIG_FS_POSIX_ACL=y
 # CONFIG_FUSE_FS is not set
 CONFIG_GENERIC_ACL=y
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -486,15 +738,13 @@ CONFIG_GENERIC_ACL=y
 #
 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
-
-#
-# Miscellaneous filesystems
-#
+CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
@@ -502,15 +752,22 @@ CONFIG_TMPFS_POSIX_ACL=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_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
+# CONFIG_NILFS2_FS is not set
 
 #
 # Partition Types
@@ -586,18 +843,36 @@ CONFIG_FRAME_WARN=1024
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
 # CONFIG_DEBUG_KERNEL is not set
+CONFIG_STACKTRACE=y
 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_FTRACE=y
-CONFIG_HAVE_DYNAMIC_FTRACE=y
-# CONFIG_FTRACE is not set
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_RING_BUFFER=y
+CONFIG_TRACING=y
+CONFIG_TRACING_SUPPORT=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_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=y
+# CONFIG_FTRACE_STARTUP_TEST 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
 
 #
@@ -605,14 +880,15 @@ CONFIG_HAVE_ARCH_KGDB=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 is not set
+CONFIG_BINARY_PRINTF=y
 
 #
 # Library routines
 #
-# 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 is not set
 # CONFIG_CRC16 is not set
 # CONFIG_CRC_T10DIF is not set
@@ -620,7 +896,10 @@ CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_CRC32 is not set
 # CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
-CONFIG_PLIST=y
+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 16b52f397983f7ead8079769a772265cab71657f..9e07fe50702913f6324b21faa9dbee4640334b20 100644 (file)
@@ -249,6 +249,6 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
 #define smp_mb__before_atomic_inc()    smp_mb()
 #define smp_mb__after_atomic_inc()     smp_mb()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif
 #endif
diff --git a/arch/arm/include/asm/bitsperlong.h b/arch/arm/include/asm/bitsperlong.h
new file mode 100644 (file)
index 0000000..6dc0bb0
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/bitsperlong.h>
index bb7d695f3900f70d635a3597cd19d7cb68c0d732..1a711ea8418b6045c581a576caa3f85496ee2673 100644 (file)
@@ -429,6 +429,14 @@ static inline void flush_anon_page(struct vm_area_struct *vma,
                __flush_anon_page(vma, page, vmaddr);
 }
 
+#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
+static inline void flush_kernel_dcache_page(struct page *page)
+{
+       /* highmem pages are always flushed upon kunmap already */
+       if ((cache_is_vivt() || cache_is_vipt_aliasing()) && !PageHighMem(page))
+               __cpuc_flush_dcache_page(page_address(page));
+}
+
 #define flush_dcache_mmap_lock(mapping) \
        spin_lock_irq(&(mapping)->tree_lock)
 #define flush_dcache_mmap_unlock(mapping) \
index 7b9d27e749b8e8afefbff6a292bbb334adcac636..b3e656c6fb78e20fb58fb2d361e4a2b968bfe8b7 100644 (file)
@@ -8,6 +8,21 @@
 #define CPUID_TCM      2
 #define CPUID_TLBTYPE  3
 
+#define CPUID_EXT_PFR0 "c1, 0"
+#define CPUID_EXT_PFR1 "c1, 1"
+#define CPUID_EXT_DFR0 "c1, 2"
+#define CPUID_EXT_AFR0 "c1, 3"
+#define CPUID_EXT_MMFR0        "c1, 4"
+#define CPUID_EXT_MMFR1        "c1, 5"
+#define CPUID_EXT_MMFR2        "c1, 6"
+#define CPUID_EXT_MMFR3        "c1, 7"
+#define CPUID_EXT_ISAR0        "c2, 0"
+#define CPUID_EXT_ISAR1        "c2, 1"
+#define CPUID_EXT_ISAR2        "c2, 2"
+#define CPUID_EXT_ISAR3        "c2, 3"
+#define CPUID_EXT_ISAR4        "c2, 4"
+#define CPUID_EXT_ISAR5        "c2, 5"
+
 #ifdef CONFIG_CPU_CP15
 #define read_cpuid(reg)                                                        \
        ({                                                              \
                    : "cc");                                            \
                __val;                                                  \
        })
+#define read_cpuid_ext(ext_reg)                                                \
+       ({                                                              \
+               unsigned int __val;                                     \
+               asm("mrc        p15, 0, %0, c0, " ext_reg               \
+                   : "=r" (__val)                                      \
+                   :                                                   \
+                   : "cc");                                            \
+               __val;                                                  \
+       })
 #else
 extern unsigned int processor_id;
 #define read_cpuid(reg) (processor_id)
+#define read_cpuid_ext(reg) 0
 #endif
 
 /*
diff --git a/arch/arm/include/asm/hardware/arm_twd.h b/arch/arm/include/asm/hardware/arm_twd.h
deleted file mode 100644 (file)
index e521b70..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef __ASM_HARDWARE_TWD_H
-#define __ASM_HARDWARE_TWD_H
-
-#define TWD_TIMER_LOAD                         0x00
-#define TWD_TIMER_COUNTER              0x04
-#define TWD_TIMER_CONTROL              0x08
-#define TWD_TIMER_INTSTAT              0x0C
-
-#define TWD_WDOG_LOAD                  0x20
-#define TWD_WDOG_COUNTER               0x24
-#define TWD_WDOG_CONTROL               0x28
-#define TWD_WDOG_INTSTAT               0x2C
-#define TWD_WDOG_RESETSTAT             0x30
-#define TWD_WDOG_DISABLE               0x34
-
-#define TWD_TIMER_CONTROL_ENABLE       (1 << 0)
-#define TWD_TIMER_CONTROL_ONESHOT      (0 << 1)
-#define TWD_TIMER_CONTROL_PERIODIC     (1 << 1)
-#define TWD_TIMER_CONTROL_IT_ENABLE    (1 << 2)
-
-#endif
index 64f2252a25cdc4fd5048ba28f9b9872267aebcdd..cdb9022716fd249a31f775589000e5b101fdcd93 100644 (file)
@@ -24,6 +24,8 @@
 #define L2X0_CACHE_TYPE                        0x004
 #define L2X0_CTRL                      0x100
 #define L2X0_AUX_CTRL                  0x104
+#define L2X0_TAG_LATENCY_CTRL          0x108
+#define L2X0_DATA_LATENCY_CTRL         0x10C
 #define L2X0_EVENT_CNT_CTRL            0x200
 #define L2X0_EVENT_CNT1_CFG            0x204
 #define L2X0_EVENT_CNT0_CFG            0x208
diff --git a/arch/arm/include/asm/hardware/pl080.h b/arch/arm/include/asm/hardware/pl080.h
new file mode 100644 (file)
index 0000000..6a6c66b
--- /dev/null
@@ -0,0 +1,138 @@
+/* arch/arm/include/asm/hardware/pl080.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      http://armlinux.simtec.co.uk/
+ *      Ben Dooks <ben@simtec.co.uk>
+ *
+ * ARM PrimeCell PL080 DMA controller
+ *
+ * This 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.
+*/
+
+/* Note, there are some Samsung updates to this controller block which
+ * make it not entierly compatible with the PL080 specification from
+ * ARM. When in doubt, check the Samsung documentation first.
+ *
+ * The Samsung defines are PL080S, and add an extra controll register,
+ * the ability to move more than 2^11 counts of data and some extra
+ * OneNAND features.
+*/
+
+#define PL080_INT_STATUS                       (0x00)
+#define PL080_TC_STATUS                                (0x04)
+#define PL080_TC_CLEAR                         (0x08)
+#define PL080_ERR_STATUS                       (0x0C)
+#define PL080_ERR_CLEAR                                (0x10)
+#define PL080_RAW_TC_STATUS                    (0x14)
+#define PL080_RAW_ERR_STATUS                   (0x18)
+#define PL080_EN_CHAN                          (0x1c)
+#define PL080_SOFT_BREQ                                (0x20)
+#define PL080_SOFT_SREQ                                (0x24)
+#define PL080_SOFT_LBREQ                       (0x28)
+#define PL080_SOFT_LSREQ                       (0x2C)
+
+#define PL080_CONFIG                           (0x30)
+#define PL080_CONFIG_M2_BE                     (1 << 2)
+#define PL080_CONFIG_M1_BE                     (1 << 1)
+#define PL080_CONFIG_ENABLE                    (1 << 0)
+
+#define PL080_SYNC                             (0x34)
+
+/* Per channel configuration registers */
+
+#define PL008_Cx_STRIDE                                (0x20)
+#define PL080_Cx_BASE(x)                       ((0x100 + (x * 0x20)))
+#define PL080_Cx_SRC_ADDR(x)                   ((0x100 + (x * 0x20)))
+#define PL080_Cx_DST_ADDR(x)                   ((0x104 + (x * 0x20)))
+#define PL080_Cx_LLI(x)                                ((0x108 + (x * 0x20)))
+#define PL080_Cx_CONTROL(x)                    ((0x10C + (x * 0x20)))
+#define PL080_Cx_CONFIG(x)                     ((0x110 + (x * 0x20)))
+#define PL080S_Cx_CONTROL2(x)                  ((0x110 + (x * 0x20)))
+#define PL080S_Cx_CONFIG(x)                    ((0x114 + (x * 0x20)))
+
+#define PL080_CH_SRC_ADDR                      (0x00)
+#define PL080_CH_DST_ADDR                      (0x04)
+#define PL080_CH_LLI                           (0x08)
+#define PL080_CH_CONTROL                       (0x0C)
+#define PL080_CH_CONFIG                                (0x10)
+#define PL080S_CH_CONTROL2                     (0x10)
+#define PL080S_CH_CONFIG                       (0x14)
+
+#define PL080_LLI_ADDR_MASK                    (0x3fffffff << 2)
+#define PL080_LLI_ADDR_SHIFT                   (2)
+#define PL080_LLI_LM_AHB2                      (1 << 0)
+
+#define PL080_CONTROL_TC_IRQ_EN                        (1 << 31)
+#define PL080_CONTROL_PROT_MASK                        (0x7 << 28)
+#define PL080_CONTROL_PROT_SHIFT               (28)
+#define PL080_CONTROL_PROT_SYS                 (1 << 28)
+#define PL080_CONTROL_DST_INCR                 (1 << 27)
+#define PL080_CONTROL_SRC_INCR                 (1 << 26)
+#define PL080_CONTROL_DST_AHB2                 (1 << 25)
+#define PL080_CONTROL_SRC_AHB2                 (1 << 24)
+#define PL080_CONTROL_DWIDTH_MASK              (0x7 << 21)
+#define PL080_CONTROL_DWIDTH_SHIFT             (21)
+#define PL080_CONTROL_SWIDTH_MASK              (0x7 << 18)
+#define PL080_CONTROL_SWIDTH_SHIFT             (18)
+#define PL080_CONTROL_DB_SIZE_MASK             (0x7 << 15)
+#define PL080_CONTROL_DB_SIZE_SHIFT            (15)
+#define PL080_CONTROL_SB_SIZE_MASK             (0x7 << 12)
+#define PL080_CONTROL_SB_SIZE_SHIFT            (12)
+#define PL080_CONTROL_TRANSFER_SIZE_MASK       (0xfff << 0)
+#define PL080_CONTROL_TRANSFER_SIZE_SHIFT      (0)
+
+#define PL080_BSIZE_1                          (0x0)
+#define PL080_BSIZE_4                          (0x1)
+#define PL080_BSIZE_8                          (0x2)
+#define PL080_BSIZE_16                         (0x3)
+#define PL080_BSIZE_32                         (0x4)
+#define PL080_BSIZE_64                         (0x5)
+#define PL080_BSIZE_128                                (0x6)
+#define PL080_BSIZE_256                                (0x7)
+
+#define PL080_WIDTH_8BIT                       (0x0)
+#define PL080_WIDTH_16BIT                      (0x1)
+#define PL080_WIDTH_32BIT                      (0x2)
+
+#define PL080_CONFIG_HALT                      (1 << 18)
+#define PL080_CONFIG_ACTIVE                    (1 << 17)  /* RO */
+#define PL080_CONFIG_LOCK                      (1 << 16)
+#define PL080_CONFIG_TC_IRQ_MASK               (1 << 15)
+#define PL080_CONFIG_ERR_IRQ_MASK              (1 << 14)
+#define PL080_CONFIG_FLOW_CONTROL_MASK         (0x7 << 11)
+#define PL080_CONFIG_FLOW_CONTROL_SHIFT                (11)
+#define PL080_CONFIG_DST_SEL_MASK              (0xf << 6)
+#define PL080_CONFIG_DST_SEL_SHIFT             (6)
+#define PL080_CONFIG_SRC_SEL_MASK              (0xf << 1)
+#define PL080_CONFIG_SRC_SEL_SHIFT             (1)
+#define PL080_CONFIG_ENABLE                    (1 << 0)
+
+#define PL080_FLOW_MEM2MEM                     (0x0)
+#define PL080_FLOW_MEM2PER                     (0x1)
+#define PL080_FLOW_PER2MEM                     (0x2)
+#define PL080_FLOW_SRC2DST                     (0x3)
+#define PL080_FLOW_SRC2DST_DST                 (0x4)
+#define PL080_FLOW_MEM2PER_PER                 (0x5)
+#define PL080_FLOW_PER2MEM_PER                 (0x6)
+#define PL080_FLOW_SRC2DST_SRC                 (0x7)
+
+/* DMA linked list chain structure */
+
+struct pl080_lli {
+       u32     src_addr;
+       u32     dst_addr;
+       u32     next_lli;
+       u32     control0;
+};
+
+struct pl080s_lli {
+       u32     src_addr;
+       u32     dst_addr;
+       u32     next_lli;
+       u32     control0;
+       u32     control1;
+};
+
diff --git a/arch/arm/include/asm/hardware/sharpsl_pm.h b/arch/arm/include/asm/hardware/sharpsl_pm.h
deleted file mode 100644 (file)
index 2d00db2..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * SharpSL Battery/PM Driver
- *
- * Copyright (c) 2004-2005 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/interrupt.h>
-
-struct sharpsl_charger_machinfo {
-       void (*init)(void);
-       void (*exit)(void);
-       int gpio_acin;
-       int gpio_batfull;
-       int batfull_irq;
-       int gpio_batlock;
-       int gpio_fatal;
-       void (*discharge)(int);
-       void (*discharge1)(int);
-       void (*charge)(int);
-       void (*measure_temp)(int);
-       void (*presuspend)(void);
-       void (*postsuspend)(void);
-       void (*earlyresume)(void);
-       unsigned long (*read_devdata)(int);
-#define SHARPSL_BATT_VOLT       1
-#define SHARPSL_BATT_TEMP       2
-#define SHARPSL_ACIN_VOLT       3
-#define SHARPSL_STATUS_ACIN     4
-#define SHARPSL_STATUS_LOCK     5
-#define SHARPSL_STATUS_CHRGFULL 6
-#define SHARPSL_STATUS_FATAL    7
-       unsigned long (*charger_wakeup)(void);
-       int (*should_wakeup)(unsigned int resume_on_alarm);
-       void (*backlight_limit)(int);
-       int (*backlight_get_status) (void);
-       int charge_on_volt;
-       int charge_on_temp;
-       int charge_acin_high;
-       int charge_acin_low;
-       int fatal_acin_volt;
-       int fatal_noacin_volt;
-       int bat_levels;
-       struct battery_thresh *bat_levels_noac;
-       struct battery_thresh *bat_levels_acin;
-       struct battery_thresh *bat_levels_noac_bl;
-       struct battery_thresh *bat_levels_acin_bl;
-       int status_high_acin;
-       int status_low_acin;
-       int status_high_noac;
-       int status_low_noac;
-};
-
-struct battery_thresh {
-       int voltage;
-       int percentage;
-};
-
-struct battery_stat {
-       int ac_status;         /* APM AC Present/Not Present */
-       int mainbat_status;    /* APM Main Battery Status */
-       int mainbat_percent;   /* Main Battery Percentage Charge */
-       int mainbat_voltage;   /* Main Battery Voltage */
-};
-
-struct sharpsl_pm_status {
-       struct device *dev;
-       struct timer_list ac_timer;
-       struct timer_list chrg_full_timer;
-
-       int charge_mode;
-#define CHRG_ERROR    (-1)
-#define CHRG_OFF      (0)
-#define CHRG_ON       (1)
-#define CHRG_DONE     (2)
-
-       unsigned int flags;
-#define SHARPSL_SUSPENDED       (1 << 0)  /* Device is Suspended */
-#define SHARPSL_ALARM_ACTIVE    (1 << 1)  /* Alarm is for charging event (not user) */
-#define SHARPSL_BL_LIMIT        (1 << 2)  /* Backlight Intensity Limited */
-#define SHARPSL_APM_QUEUED      (1 << 3)  /* APM Event Queued */
-#define SHARPSL_DO_OFFLINE_CHRG (1 << 4)  /* Trigger the offline charger */
-
-       int full_count;
-       unsigned long charge_start_time;
-       struct sharpsl_charger_machinfo *machinfo;
-       struct battery_stat battstat;
-};
-
-extern struct sharpsl_pm_status sharpsl_pm;
-
-
-#define SHARPSL_LED_ERROR  2
-#define SHARPSL_LED_ON     1
-#define SHARPSL_LED_OFF    0
-
-void sharpsl_battery_kick(void);
-void sharpsl_pm_led(int val);
-irqreturn_t sharpsl_ac_isr(int irq, void *dev_id);
-irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id);
-irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id);
-
index f87328d4a180e284d99b061de2fb9697719efebe..5d72550a809766cd98d6006221fd142af86cb815 100644 (file)
@@ -41,7 +41,7 @@
 #define VIC_PL192_VECT_ADDR            0xF00
 
 #ifndef __ASSEMBLY__
-void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources);
+void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
 #endif
 
 #endif
diff --git a/arch/arm/include/asm/localtimer.h b/arch/arm/include/asm/localtimer.h
new file mode 100644 (file)
index 0000000..50c7e7c
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *  arch/arm/include/asm/localtimer.h
+ *
+ *  Copyright (C) 2004-2005 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.
+ */
+#ifndef __ASM_ARM_LOCALTIMER_H
+#define __ASM_ARM_LOCALTIMER_H
+
+struct clock_event_device;
+
+/*
+ * Setup a per-cpu timer, whether it be a local timer or dummy broadcast
+ */
+void percpu_timer_setup(void);
+
+/*
+ * Called from assembly, this is the local timer IRQ handler
+ */
+asmlinkage void do_local_timer(struct pt_regs *);
+
+
+#ifdef CONFIG_LOCAL_TIMERS
+
+#ifdef CONFIG_HAVE_ARM_TWD
+
+#include "smp_twd.h"
+
+#define local_timer_ack()      twd_timer_ack()
+#define local_timer_stop()     twd_timer_stop()
+
+#else
+
+/*
+ * Platform provides this to acknowledge a local timer IRQ.
+ * Returns true if the local timer IRQ is to be processed.
+ */
+int local_timer_ack(void);
+
+/*
+ * Stop a local timer interrupt.
+ */
+void local_timer_stop(void);
+
+#endif
+
+/*
+ * Setup a local timer interrupt for a CPU.
+ */
+void local_timer_setup(struct clock_event_device *);
+
+#else
+
+static inline void local_timer_stop(void)
+{
+}
+
+#endif
+
+#endif
index 58cf91f38e6f5f798ff571ea73e9112f6c049b68..742c2aaeb02031d4d4e77dbf11e653910887343b 100644 (file)
@@ -30,6 +30,14 @@ struct map_desc {
 
 #ifdef CONFIG_MMU
 extern void iotable_init(struct map_desc *, int);
+
+struct mem_type;
+extern const struct mem_type *get_mem_type(unsigned int type);
+/*
+ * external interface to remap single page with appropriate type
+ */
+extern int ioremap_page(unsigned long virt, unsigned long phys,
+                       const struct mem_type *mtype);
 #else
 #define iotable_init(map,num)  do { } while (0)
 #endif
index 54570d2e95b7b4856430550f75022853a966434a..fc26976d8e3a7090716e8f5624bee962ebcb283a 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __ARM_MMAN_H__
 #define __ARM_MMAN_H__
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 #define MAP_GROWSDOWN  0x0100          /* stack-like segment */
 #define MAP_DENYWRITE  0x0800          /* ETXTBSY */
index 7b522770f29dc6e967f3c719817925ebf753c6e1..be962c1349c4aa17a65f4cd364fd6221f1ea83bc 100644 (file)
@@ -202,6 +202,6 @@ typedef struct page *pgtable_t;
        (((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \
         VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif
index 110295c5461dc2dd471f7172b31daf7eb589b244..1cd2d6416bda447da0a64276ab2d302ff785cd19 100644 (file)
@@ -342,7 +342,7 @@ static inline pte_t *pmd_page_vaddr(pmd_t pmd)
        return __va(ptr);
 }
 
-#define pmd_page(pmd) virt_to_page(__va(pmd_val(pmd)))
+#define pmd_page(pmd)          pfn_to_page(__phys_to_pfn(pmd_val(pmd)))
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
index 1845892260e762fad61c6f093529bdd5ab7a920f..6a89567ffc5bc49a326c0a56747aced339fd53db 100644 (file)
@@ -71,6 +71,7 @@ struct thread_struct {
                regs->ARM_cpsr = USR26_MODE;                            \
        if (elf_hwcap & HWCAP_THUMB && pc & 1)                          \
                regs->ARM_cpsr |= PSR_T_BIT;                            \
+       regs->ARM_cpsr |= PSR_ENDSTATE;                                 \
        regs->ARM_pc = pc & ~1;         /* pc */                        \
        regs->ARM_sp = sp;              /* sp */                        \
        regs->ARM_r2 = stack[2];        /* r2 (envp) */                 \
index 236a06b9b7ce0e9e4bb11caa5a48e48759a59ef7..67b833c9b6b9cdb2d8784eb7e2e9ab97c10be082 100644 (file)
@@ -50,6 +50,7 @@
 #define PSR_F_BIT      0x00000040
 #define PSR_I_BIT      0x00000080
 #define PSR_A_BIT      0x00000100
+#define PSR_E_BIT      0x00000200
 #define PSR_J_BIT      0x01000000
 #define PSR_Q_BIT      0x08000000
 #define PSR_V_BIT      0x10000000
 #define PSR_x          0x0000ff00      /* Extension            */
 #define PSR_c          0x000000ff      /* Control              */
 
+/*
+ * ARMv7 groups of APSR bits
+ */
+#define PSR_ISET_MASK  0x01000010      /* ISA state (J, T) mask */
+#define PSR_IT_MASK    0x0600fc00      /* If-Then execution state mask */
+#define PSR_ENDIAN_MASK        0x00000200      /* Endianness state mask */
+
+/*
+ * Default endianness state
+ */
+#ifdef CONFIG_CPU_ENDIAN_BE8
+#define PSR_ENDSTATE   PSR_E_BIT
+#else
+#define PSR_ENDSTATE   0
+#endif
+
 #ifndef __ASSEMBLY__
 
 /*
index d0fb487aba4f268811d96abc1a37cec2d3bbfdfd..43ba0fb1c8ad2b774e42041715c1276b226ba7bf 100644 (file)
@@ -111,7 +111,7 @@ typedef unsigned long sigset_t;
 #define MINSIGSTKSZ    2048
 #define SIGSTKSZ       8192
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
index ada93a8fc2ef6ed426cf5ac61ba27b3926ee402e..4fc1565e4f930860722bca331330d0606e494d1c 100644 (file)
@@ -29,6 +29,7 @@
 #define SZ_512                         0x00000200
 
 #define SZ_1K                           0x00000400
+#define SZ_2K                           0x00000800
 #define SZ_4K                           0x00001000
 #define SZ_8K                           0x00002000
 #define SZ_16K                          0x00004000
index 5995935338e17f40d28d85ecf8488a9a63ed3244..a06e735b262ad26efe2a79d164670a763cdf2090 100644 (file)
@@ -41,7 +41,7 @@ extern void show_ipi_list(struct seq_file *p);
 asmlinkage void do_IPI(struct pt_regs *regs);
 
 /*
- * Setup the SMP cpu_possible_map
+ * Setup the set of possible CPUs (via set_cpu_possible)
  */
 extern void smp_init_cpus(void);
 
@@ -55,11 +55,6 @@ extern void smp_store_cpu_info(unsigned int cpuid);
  */
 extern void smp_cross_call(const struct cpumask *mask);
 
-/*
- * Broadcast a clock event to other CPUs.
- */
-extern void smp_timer_broadcast(const struct cpumask *mask);
-
 /*
  * Boot a secondary CPU, and assign it the specified idle task.
  * This also gives us the initial stack to use for this CPU.
@@ -100,44 +95,9 @@ extern void arch_send_call_function_single_ipi(int cpu);
 extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
 #define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask
 
-/*
- * Local timer interrupt handling function (can be IPI'ed).
- */
-extern void local_timer_interrupt(void);
-
-#ifdef CONFIG_LOCAL_TIMERS
-
-/*
- * Stop a local timer interrupt.
- */
-extern void local_timer_stop(void);
-
-/*
- * Platform provides this to acknowledge a local timer IRQ
- */
-extern int local_timer_ack(void);
-
-#else
-
-static inline void local_timer_stop(void)
-{
-}
-
-#endif
-
-/*
- * Setup a local timer interrupt for a CPU.
- */
-extern void local_timer_setup(void);
-
 /*
  * show local interrupt info
  */
 extern void show_local_irqs(struct seq_file *);
 
-/*
- * Called from assembly, this is the local timer IRQ handler
- */
-asmlinkage void do_local_timer(struct pt_regs *);
-
 #endif /* ifndef __ASM_ARM_SMP_H */
diff --git a/arch/arm/include/asm/smp_scu.h b/arch/arm/include/asm/smp_scu.h
new file mode 100644 (file)
index 0000000..2376835
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __ASMARM_ARCH_SCU_H
+#define __ASMARM_ARCH_SCU_H
+
+unsigned int scu_get_core_count(void __iomem *);
+void scu_enable(void __iomem *);
+
+#endif
diff --git a/arch/arm/include/asm/smp_twd.h b/arch/arm/include/asm/smp_twd.h
new file mode 100644 (file)
index 0000000..7be0978
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef __ASMARM_SMP_TWD_H
+#define __ASMARM_SMP_TWD_H
+
+struct clock_event_device;
+
+extern void __iomem *twd_base;
+
+void twd_timer_stop(void);
+int twd_timer_ack(void);
+void twd_timer_setup(struct clock_event_device *);
+
+#endif
diff --git a/arch/arm/include/asm/suspend.h b/arch/arm/include/asm/suspend.h
deleted file mode 100644 (file)
index cf0d0bd..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#ifndef _ASMARM_SUSPEND_H
-#define _ASMARM_SUSPEND_H
-
-#endif
index a62218013c78bd80447013c5f9f8872c010cd638..c964f3fc3bc57e906c452cbbe059fed506c19ee8 100644 (file)
 #define TLB_V6_I_ASID  (1 << 18)
 
 #define TLB_BTB                (1 << 28)
+
+/* Unified Inner Shareable TLB operations (ARMv7 MP extensions) */
+#define TLB_V7_UIS_PAGE        (1 << 19)
+#define TLB_V7_UIS_FULL (1 << 20)
+#define TLB_V7_UIS_ASID (1 << 21)
+
 #define TLB_L2CLEAN_FR (1 << 29)               /* Feroceon */
 #define TLB_DCLEAN     (1 << 30)
 #define TLB_WB         (1 << 31)
 # define v6wbi_always_flags    (-1UL)
 #endif
 
+#ifdef CONFIG_SMP
+#define v7wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BTB | \
+                        TLB_V7_UIS_FULL | TLB_V7_UIS_PAGE | TLB_V7_UIS_ASID)
+#else
+#define v7wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BTB | \
+                        TLB_V6_U_FULL | TLB_V6_U_PAGE | TLB_V6_U_ASID)
+#endif
+
 #ifdef CONFIG_CPU_TLB_V7
-# define v7wbi_possible_flags  v6wbi_tlb_flags
-# define v7wbi_always_flags    v6wbi_tlb_flags
+# define v7wbi_possible_flags  v7wbi_tlb_flags
+# define v7wbi_always_flags    v7wbi_tlb_flags
 # ifdef _TLB
 #  define MULTI_TLB 1
 # else
@@ -316,6 +330,8 @@ static inline void local_flush_tlb_all(void)
                asm("mcr p15, 0, %0, c8, c6, 0" : : "r" (zero) : "cc");
        if (tlb_flag(TLB_V4_I_FULL | TLB_V6_I_FULL))
                asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
+       if (tlb_flag(TLB_V7_UIS_FULL))
+               asm("mcr p15, 0, %0, c8, c3, 0" : : "r" (zero) : "cc");
 
        if (tlb_flag(TLB_BTB)) {
                /* flush the branch target cache */
@@ -351,6 +367,8 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm)
                asm("mcr p15, 0, %0, c8, c6, 2" : : "r" (asid) : "cc");
        if (tlb_flag(TLB_V6_I_ASID))
                asm("mcr p15, 0, %0, c8, c5, 2" : : "r" (asid) : "cc");
+       if (tlb_flag(TLB_V7_UIS_ASID))
+               asm("mcr p15, 0, %0, c8, c3, 2" : : "r" (asid) : "cc");
 
        if (tlb_flag(TLB_BTB)) {
                /* flush the branch target cache */
@@ -389,6 +407,8 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
                asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (uaddr) : "cc");
        if (tlb_flag(TLB_V6_I_PAGE))
                asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (uaddr) : "cc");
+       if (tlb_flag(TLB_V7_UIS_PAGE))
+               asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (uaddr) : "cc");
 
        if (tlb_flag(TLB_BTB)) {
                /* flush the branch target cache */
@@ -424,6 +444,8 @@ static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
                asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (kaddr) : "cc");
        if (tlb_flag(TLB_V6_I_PAGE))
                asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (kaddr) : "cc");
+       if (tlb_flag(TLB_V7_UIS_PAGE))
+               asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (kaddr) : "cc");
 
        if (tlb_flag(TLB_BTB)) {
                /* flush the branch target cache */
index 7897464e0c24260fe002e0ffac839444c35d5079..0da9bc9b3b1dfbc3fe519a373633fae8a96ba4e9 100644 (file)
@@ -386,7 +386,9 @@ do {                                                                        \
 #ifdef CONFIG_MMU
 extern unsigned long __must_check __copy_from_user(void *to, const void __user *from, unsigned long n);
 extern unsigned long __must_check __copy_to_user(void __user *to, const void *from, unsigned long n);
+extern unsigned long __must_check __copy_to_user_std(void __user *to, const void *from, unsigned long n);
 extern unsigned long __must_check __clear_user(void __user *addr, unsigned long n);
+extern unsigned long __must_check __clear_user_std(void __user *addr, unsigned long n);
 #else
 #define __copy_from_user(to,from,n)    (memcpy(to, (void __force *)from, n), 0)
 #define __copy_to_user(to,from,n)      (memcpy((void __force *)to, from, n), 0)
index 11a5197a221f74da0303581fa787814a9c46f904..ff89d0b3abc50c7b5c4049fa0823f1ef1d8dd79a 100644 (file)
@@ -22,6 +22,8 @@ obj-$(CONFIG_ARTHUR)          += arthur.o
 obj-$(CONFIG_ISA_DMA)          += dma-isa.o
 obj-$(CONFIG_PCI)              += bios32.o isa.o
 obj-$(CONFIG_SMP)              += smp.o
+obj-$(CONFIG_HAVE_ARM_SCU)     += smp_scu.o
+obj-$(CONFIG_HAVE_ARM_TWD)     += smp_twd.o
 obj-$(CONFIG_DYNAMIC_FTRACE)   += ftrace.o
 obj-$(CONFIG_KEXEC)            += machine_kexec.o relocate_kernel.o
 obj-$(CONFIG_KPROBES)          += kprobes.o kprobes-decode.o
index 83b1da6b7baaa44cbfd220876503b9d755c1acd3..fc8af43c50001e3c9907ea3f22023a405497da64 100644 (file)
@@ -482,6 +482,9 @@ __und_usr:
        subeq   r4, r2, #4                      @ ARM instr at LR - 4
        subne   r4, r2, #2                      @ Thumb instr at LR - 2
 1:     ldreqt  r0, [r4]
+#ifdef CONFIG_CPU_ENDIAN_BE8
+       reveq   r0, r0                          @ little endian instruction
+#endif
        beq     call_fpe
        @ Thumb instruction
 #if __LINUX_ARM_ARCH__ >= 7
index b55cb0331809ebc025344d9156c300dd2fdc9edf..366e5097a41a4f535d1d24ddccab44f13580fb64 100644 (file)
@@ -210,6 +210,9 @@ ENTRY(vector_swi)
   A710(        teq     ip, #0x0f000000                                         )
   A710(        bne     .Larm710bug                                             )
 #endif
+#ifdef CONFIG_CPU_ENDIAN_BE8
+       rev     r10, r10                        @ little endian instruction
+#endif
 
 #elif defined(CONFIG_AEABI)
 
index c3265a2e7cd43278686b1d2e4168bb84554d9d6a..1585423699ee94e70ec73cab014d856f5f332365 100644 (file)
@@ -365,7 +365,7 @@ pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
        regs.ARM_r2 = (unsigned long)fn;
        regs.ARM_r3 = (unsigned long)do_exit;
        regs.ARM_pc = (unsigned long)kernel_thread_helper;
-       regs.ARM_cpsr = SVC_MODE;
+       regs.ARM_cpsr = SVC_MODE | PSR_ENDSTATE;
 
        return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
 }
index 80b8b5c7e07a1a472b1b18458c41d32412e642e6..442b87476f97105963df1862efcf089bc542f7d0 100644 (file)
@@ -426,9 +426,13 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka,
                 */
                thumb = handler & 1;
 
-               if (thumb)
+               if (thumb) {
                        cpsr |= PSR_T_BIT;
-               else
+#if __LINUX_ARM_ARCH__ >= 7
+                       /* clear the If-Then Thumb-2 execution state */
+                       cpsr &= ~PSR_IT_MASK;
+#endif
+               } else
                        cpsr &= ~PSR_T_BIT;
        }
 #endif
index 6014dfd22af44a56270890726f63b565ac9620a4..de885fd256c519b220e6d48d86996e1f7027cd5d 100644 (file)
 #include <linux/smp.h>
 #include <linux/seq_file.h>
 #include <linux/irq.h>
+#include <linux/percpu.h>
+#include <linux/clockchips.h>
 
 #include <asm/atomic.h>
 #include <asm/cacheflush.h>
 #include <asm/cpu.h>
+#include <asm/cputype.h>
 #include <asm/mmu_context.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 #include <asm/processor.h>
 #include <asm/tlbflush.h>
 #include <asm/ptrace.h>
+#include <asm/localtimer.h>
 
 /*
  * as from 2.5, kernels no longer have an init_tasks structure
@@ -163,7 +167,7 @@ int __cpuexit __cpu_disable(void)
         * Take this CPU offline.  Once we clear this, we can't return,
         * and we must not schedule until we're ready to give up the cpu.
         */
-       cpu_clear(cpu, cpu_online_map);
+       set_cpu_online(cpu, false);
 
        /*
         * OK - migrate IRQs away from this CPU
@@ -274,9 +278,9 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
        local_fiq_enable();
 
        /*
-        * Setup local timer for this CPU.
+        * Setup the percpu timer for this CPU.
         */
-       local_timer_setup();
+       percpu_timer_setup();
 
        calibrate_delay();
 
@@ -285,7 +289,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
        /*
         * OK, now it's safe to let the boot CPU continue
         */
-       cpu_set(cpu, cpu_online_map);
+       set_cpu_online(cpu, true);
 
        /*
         * OK, it's off to the idle thread for us
@@ -383,10 +387,16 @@ void show_local_irqs(struct seq_file *p)
        seq_putc(p, '\n');
 }
 
+/*
+ * Timer (local or broadcast) support
+ */
+static DEFINE_PER_CPU(struct clock_event_device, percpu_clockevent);
+
 static void ipi_timer(void)
 {
+       struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent);
        irq_enter();
-       local_timer_interrupt();
+       evt->event_handler(evt);
        irq_exit();
 }
 
@@ -405,6 +415,42 @@ asmlinkage void __exception do_local_timer(struct pt_regs *regs)
 }
 #endif
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
+static void smp_timer_broadcast(const struct cpumask *mask)
+{
+       send_ipi_message(mask, IPI_TIMER);
+}
+
+static void broadcast_timer_set_mode(enum clock_event_mode mode,
+       struct clock_event_device *evt)
+{
+}
+
+static void local_timer_setup(struct clock_event_device *evt)
+{
+       evt->name       = "dummy_timer";
+       evt->features   = CLOCK_EVT_FEAT_ONESHOT |
+                         CLOCK_EVT_FEAT_PERIODIC |
+                         CLOCK_EVT_FEAT_DUMMY;
+       evt->rating     = 400;
+       evt->mult       = 1;
+       evt->set_mode   = broadcast_timer_set_mode;
+       evt->broadcast  = smp_timer_broadcast;
+
+       clockevents_register_device(evt);
+}
+#endif
+
+void __cpuinit percpu_timer_setup(void)
+{
+       unsigned int cpu = smp_processor_id();
+       struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
+
+       evt->cpumask = cpumask_of(cpu);
+
+       local_timer_setup(evt);
+}
+
 static DEFINE_SPINLOCK(stop_lock);
 
 /*
@@ -417,7 +463,7 @@ static void ipi_cpu_stop(unsigned int cpu)
        dump_stack();
        spin_unlock(&stop_lock);
 
-       cpu_clear(cpu, cpu_online_map);
+       set_cpu_online(cpu, false);
 
        local_fiq_disable();
        local_irq_disable();
@@ -501,11 +547,6 @@ void smp_send_reschedule(int cpu)
        send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE);
 }
 
-void smp_timer_broadcast(const struct cpumask *mask)
-{
-       send_ipi_message(mask, IPI_TIMER);
-}
-
 void smp_send_stop(void)
 {
        cpumask_t mask = cpu_online_map;
@@ -545,6 +586,12 @@ struct tlb_args {
        unsigned long ta_end;
 };
 
+/* all SMP configurations have the extended CPUID registers */
+static inline int tlb_ops_need_broadcast(void)
+{
+       return ((read_cpuid_ext(CPUID_EXT_MMFR3) >> 12) & 0xf) < 2;
+}
+
 static inline void ipi_flush_tlb_all(void *ignored)
 {
        local_flush_tlb_all();
@@ -587,51 +634,61 @@ static inline void ipi_flush_tlb_kernel_range(void *arg)
 
 void flush_tlb_all(void)
 {
-       on_each_cpu(ipi_flush_tlb_all, NULL, 1);
+       if (tlb_ops_need_broadcast())
+               on_each_cpu(ipi_flush_tlb_all, NULL, 1);
+       else
+               local_flush_tlb_all();
 }
 
 void flush_tlb_mm(struct mm_struct *mm)
 {
-       on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, &mm->cpu_vm_mask);
+       if (tlb_ops_need_broadcast())
+               on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, &mm->cpu_vm_mask);
+       else
+               local_flush_tlb_mm(mm);
 }
 
 void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
 {
-       struct tlb_args ta;
-
-       ta.ta_vma = vma;
-       ta.ta_start = uaddr;
-
-       on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, &vma->vm_mm->cpu_vm_mask);
+       if (tlb_ops_need_broadcast()) {
+               struct tlb_args ta;
+               ta.ta_vma = vma;
+               ta.ta_start = uaddr;
+               on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, &vma->vm_mm->cpu_vm_mask);
+       } else
+               local_flush_tlb_page(vma, uaddr);
 }
 
 void flush_tlb_kernel_page(unsigned long kaddr)
 {
-       struct tlb_args ta;
-
-       ta.ta_start = kaddr;
-
-       on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1);
+       if (tlb_ops_need_broadcast()) {
+               struct tlb_args ta;
+               ta.ta_start = kaddr;
+               on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1);
+       } else
+               local_flush_tlb_kernel_page(kaddr);
 }
 
 void flush_tlb_range(struct vm_area_struct *vma,
                      unsigned long start, unsigned long end)
 {
-       struct tlb_args ta;
-
-       ta.ta_vma = vma;
-       ta.ta_start = start;
-       ta.ta_end = end;
-
-       on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, &vma->vm_mm->cpu_vm_mask);
+       if (tlb_ops_need_broadcast()) {
+               struct tlb_args ta;
+               ta.ta_vma = vma;
+               ta.ta_start = start;
+               ta.ta_end = end;
+               on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, &vma->vm_mm->cpu_vm_mask);
+       } else
+               local_flush_tlb_range(vma, start, end);
 }
 
 void flush_tlb_kernel_range(unsigned long start, unsigned long end)
 {
-       struct tlb_args ta;
-
-       ta.ta_start = start;
-       ta.ta_end = end;
-
-       on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1);
+       if (tlb_ops_need_broadcast()) {
+               struct tlb_args ta;
+               ta.ta_start = start;
+               ta.ta_end = end;
+               on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1);
+       } else
+               local_flush_tlb_kernel_range(start, end);
 }
diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c
new file mode 100644 (file)
index 0000000..d3831f6
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ *  linux/arch/arm/kernel/smp_scu.c
+ *
+ *  Copyright (C) 2002 ARM Ltd.
+ *  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/init.h>
+#include <linux/io.h>
+
+#include <asm/smp_scu.h>
+#include <asm/cacheflush.h>
+
+#define SCU_CTRL               0x00
+#define SCU_CONFIG             0x04
+#define SCU_CPU_STATUS         0x08
+#define SCU_INVALIDATE         0x0c
+#define SCU_FPGA_REVISION      0x10
+
+/*
+ * Get the number of CPU cores from the SCU configuration
+ */
+unsigned int __init scu_get_core_count(void __iomem *scu_base)
+{
+       unsigned int ncores = __raw_readl(scu_base + SCU_CONFIG);
+       return (ncores & 0x03) + 1;
+}
+
+/*
+ * Enable the SCU
+ */
+void __init scu_enable(void __iomem *scu_base)
+{
+       u32 scu_ctrl;
+
+       scu_ctrl = __raw_readl(scu_base + SCU_CTRL);
+       scu_ctrl |= 1;
+       __raw_writel(scu_ctrl, scu_base + SCU_CTRL);
+
+       /*
+        * Ensure that the data accessed by CPU0 before the SCU was
+        * initialised is visible to the other CPUs.
+        */
+       flush_cache_all();
+}
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
new file mode 100644 (file)
index 0000000..d8c88c6
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ *  linux/arch/arm/kernel/smp_twd.c
+ *
+ *  Copyright (C) 2002 ARM Ltd.
+ *  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/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/smp.h>
+#include <linux/jiffies.h>
+#include <linux/clockchips.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <asm/smp_twd.h>
+#include <asm/hardware/gic.h>
+
+#define TWD_TIMER_LOAD                         0x00
+#define TWD_TIMER_COUNTER              0x04
+#define TWD_TIMER_CONTROL              0x08
+#define TWD_TIMER_INTSTAT              0x0C
+
+#define TWD_WDOG_LOAD                  0x20
+#define TWD_WDOG_COUNTER               0x24
+#define TWD_WDOG_CONTROL               0x28
+#define TWD_WDOG_INTSTAT               0x2C
+#define TWD_WDOG_RESETSTAT             0x30
+#define TWD_WDOG_DISABLE               0x34
+
+#define TWD_TIMER_CONTROL_ENABLE       (1 << 0)
+#define TWD_TIMER_CONTROL_ONESHOT      (0 << 1)
+#define TWD_TIMER_CONTROL_PERIODIC     (1 << 1)
+#define TWD_TIMER_CONTROL_IT_ENABLE    (1 << 2)
+
+/* set up by the platform code */
+void __iomem *twd_base;
+
+static unsigned long twd_timer_rate;
+
+static void twd_set_mode(enum clock_event_mode mode,
+                       struct clock_event_device *clk)
+{
+       unsigned long ctrl;
+
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               /* timer load already set up */
+               ctrl = TWD_TIMER_CONTROL_ENABLE | TWD_TIMER_CONTROL_IT_ENABLE
+                       | TWD_TIMER_CONTROL_PERIODIC;
+               break;
+       case CLOCK_EVT_MODE_ONESHOT:
+               /* period set, and timer enabled in 'next_event' hook */
+               ctrl = TWD_TIMER_CONTROL_IT_ENABLE | TWD_TIMER_CONTROL_ONESHOT;
+               break;
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+       default:
+               ctrl = 0;
+       }
+
+       __raw_writel(ctrl, twd_base + TWD_TIMER_CONTROL);
+}
+
+static int twd_set_next_event(unsigned long evt,
+                       struct clock_event_device *unused)
+{
+       unsigned long ctrl = __raw_readl(twd_base + TWD_TIMER_CONTROL);
+
+       ctrl |= TWD_TIMER_CONTROL_ENABLE;
+
+       __raw_writel(evt, twd_base + TWD_TIMER_COUNTER);
+       __raw_writel(ctrl, twd_base + TWD_TIMER_CONTROL);
+
+       return 0;
+}
+
+/*
+ * local_timer_ack: checks for a local timer interrupt.
+ *
+ * If a local timer interrupt has occurred, acknowledge and return 1.
+ * Otherwise, return 0.
+ */
+int twd_timer_ack(void)
+{
+       if (__raw_readl(twd_base + TWD_TIMER_INTSTAT)) {
+               __raw_writel(1, twd_base + TWD_TIMER_INTSTAT);
+               return 1;
+       }
+
+       return 0;
+}
+
+static void __cpuinit twd_calibrate_rate(void)
+{
+       unsigned long load, count;
+       u64 waitjiffies;
+
+       /*
+        * If this is the first time round, we need to work out how fast
+        * the timer ticks
+        */
+       if (twd_timer_rate == 0) {
+               printk(KERN_INFO "Calibrating local timer... ");
+
+               /* Wait for a tick to start */
+               waitjiffies = get_jiffies_64() + 1;
+
+               while (get_jiffies_64() < waitjiffies)
+                       udelay(10);
+
+               /* OK, now the tick has started, let's get the timer going */
+               waitjiffies += 5;
+
+                                /* enable, no interrupt or reload */
+               __raw_writel(0x1, twd_base + TWD_TIMER_CONTROL);
+
+                                /* maximum value */
+               __raw_writel(0xFFFFFFFFU, twd_base + TWD_TIMER_COUNTER);
+
+               while (get_jiffies_64() < waitjiffies)
+                       udelay(10);
+
+               count = __raw_readl(twd_base + TWD_TIMER_COUNTER);
+
+               twd_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5);
+
+               printk("%lu.%02luMHz.\n", twd_timer_rate / 1000000,
+                       (twd_timer_rate / 100000) % 100);
+       }
+
+       load = twd_timer_rate / HZ;
+
+       __raw_writel(load, twd_base + TWD_TIMER_LOAD);
+}
+
+/*
+ * Setup the local clock events for a CPU.
+ */
+void __cpuinit twd_timer_setup(struct clock_event_device *clk)
+{
+       unsigned long flags;
+
+       twd_calibrate_rate();
+
+       clk->name = "local_timer";
+       clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+       clk->rating = 350;
+       clk->set_mode = twd_set_mode;
+       clk->set_next_event = twd_set_next_event;
+       clk->shift = 20;
+       clk->mult = div_sc(twd_timer_rate, NSEC_PER_SEC, clk->shift);
+       clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk);
+       clk->min_delta_ns = clockevent_delta2ns(0xf, clk);
+
+       /* Make sure our local interrupt controller has this enabled */
+       local_irq_save(flags);
+       get_irq_chip(clk->irq)->unmask(clk->irq);
+       local_irq_restore(flags);
+
+       clockevents_register_device(clk);
+}
+
+/*
+ * take a local timer down
+ */
+void __cpuexit twd_timer_stop(void)
+{
+       __raw_writel(0, twd_base + TWD_TIMER_CONTROL);
+}
index c90f27250eadd71ac093eb40b2113a5147f94f22..6c0779792546d5c58d4ab722d4b3e037022a1ffa 100644 (file)
@@ -141,6 +141,7 @@ SECTIONS
 
        .data : AT(__data_loc) {
                _data = .;              /* address in memory */
+               _sdata = .;
 
                /*
                 * first, the init task union, aligned
@@ -192,6 +193,7 @@ SECTIONS
                __bss_start = .;        /* BSS                          */
                *(.bss)
                *(COMMON)
+               __bss_stop = .;
                _end = .;
        }
                                        /* Stabs debugging sections.    */
index 866f84a586ff7281b7aa70ab9af4a89d80a88079..030ba7219f482bfd9873b196d1a8634d5fc2eacb 100644 (file)
@@ -29,6 +29,9 @@ else
 endif
 endif
 
+# using lib_ here won't override already available weak symbols
+obj-$(CONFIG_UACCESS_WITH_MEMCPY) += uaccess_with_memcpy.o
+
 lib-$(CONFIG_MMU) += $(mmu-y)
 
 ifeq ($(CONFIG_CPU_32v3),y)
index 4d6bc71231f3a2da61bc2f88a6860ba18e074e59..844f56785ebc539c684d04185a93f5323a6ed7c2 100644 (file)
@@ -18,7 +18,8 @@
  *          : sz   - number of bytes to clear
  * Returns  : number of bytes NOT cleared
  */
-ENTRY(__clear_user)
+ENTRY(__clear_user_std)
+WEAK(__clear_user)
                stmfd   sp!, {r1, lr}
                mov     r2, #0
                cmp     r1, #4
index 22f968bbdffda4172b783ea7cf4c91899b2f02b6..878820f0a32014974550b60acdcf2cb49a430021 100644 (file)
@@ -86,7 +86,8 @@
 
        .text
 
-ENTRY(__copy_to_user)
+ENTRY(__copy_to_user_std)
+WEAK(__copy_to_user)
 
 #include "copy_template.S"
 
diff --git a/arch/arm/lib/uaccess_with_memcpy.c b/arch/arm/lib/uaccess_with_memcpy.c
new file mode 100644 (file)
index 0000000..6b967ff
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ *  linux/arch/arm/lib/uaccess_with_memcpy.c
+ *
+ *  Written by: Lennert Buytenhek and Nicolas Pitre
+ *  Copyright (C) 2009 Marvell Semiconductor
+ *
+ * This 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/ctype.h>
+#include <linux/uaccess.h>
+#include <linux/rwsem.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/hardirq.h> /* for in_atomic() */
+#include <asm/current.h>
+#include <asm/page.h>
+
+static int
+pin_page_for_write(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp)
+{
+       unsigned long addr = (unsigned long)_addr;
+       pgd_t *pgd;
+       pmd_t *pmd;
+       pte_t *pte;
+       spinlock_t *ptl;
+
+       pgd = pgd_offset(current->mm, addr);
+       if (unlikely(pgd_none(*pgd) || pgd_bad(*pgd)))
+               return 0;
+
+       pmd = pmd_offset(pgd, addr);
+       if (unlikely(pmd_none(*pmd) || pmd_bad(*pmd)))
+               return 0;
+
+       pte = pte_offset_map_lock(current->mm, pmd, addr, &ptl);
+       if (unlikely(!pte_present(*pte) || !pte_young(*pte) ||
+           !pte_write(*pte) || !pte_dirty(*pte))) {
+               pte_unmap_unlock(pte, ptl);
+               return 0;
+       }
+
+       *ptep = pte;
+       *ptlp = ptl;
+
+       return 1;
+}
+
+static unsigned long noinline
+__copy_to_user_memcpy(void __user *to, const void *from, unsigned long n)
+{
+       int atomic;
+
+       if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
+               memcpy((void *)to, from, n);
+               return 0;
+       }
+
+       /* the mmap semaphore is taken only if not in an atomic context */
+       atomic = in_atomic();
+
+       if (!atomic)
+               down_read(&current->mm->mmap_sem);
+       while (n) {
+               pte_t *pte;
+               spinlock_t *ptl;
+               int tocopy;
+
+               while (!pin_page_for_write(to, &pte, &ptl)) {
+                       if (!atomic)
+                               up_read(&current->mm->mmap_sem);
+                       if (__put_user(0, (char __user *)to))
+                               goto out;
+                       if (!atomic)
+                               down_read(&current->mm->mmap_sem);
+               }
+
+               tocopy = (~(unsigned long)to & ~PAGE_MASK) + 1;
+               if (tocopy > n)
+                       tocopy = n;
+
+               memcpy((void *)to, from, tocopy);
+               to += tocopy;
+               from += tocopy;
+               n -= tocopy;
+
+               pte_unmap_unlock(pte, ptl);
+       }
+       if (!atomic)
+               up_read(&current->mm->mmap_sem);
+
+out:
+       return n;
+}
+
+unsigned long
+__copy_to_user(void __user *to, const void *from, unsigned long n)
+{
+       /*
+        * This test is stubbed out of the main function above to keep
+        * the overhead for small copies low by avoiding a large
+        * register dump on the stack just to reload them right away.
+        * With frame pointer disabled, tail call optimization kicks in
+        * as well making this test almost invisible.
+        */
+       if (n < 64)
+               return __copy_to_user_std(to, from, n);
+       return __copy_to_user_memcpy(to, from, n);
+}
+       
+static unsigned long noinline
+__clear_user_memset(void __user *addr, unsigned long n)
+{
+       if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
+               memset((void *)addr, 0, n);
+               return 0;
+       }
+
+       down_read(&current->mm->mmap_sem);
+       while (n) {
+               pte_t *pte;
+               spinlock_t *ptl;
+               int tocopy;
+
+               while (!pin_page_for_write(addr, &pte, &ptl)) {
+                       up_read(&current->mm->mmap_sem);
+                       if (__put_user(0, (char __user *)addr))
+                               goto out;
+                       down_read(&current->mm->mmap_sem);
+               }
+
+               tocopy = (~(unsigned long)addr & ~PAGE_MASK) + 1;
+               if (tocopy > n)
+                       tocopy = n;
+
+               memset((void *)addr, 0, tocopy);
+               addr += tocopy;
+               n -= tocopy;
+
+               pte_unmap_unlock(pte, ptl);
+       }
+       up_read(&current->mm->mmap_sem);
+
+out:
+       return n;
+}
+
+unsigned long __clear_user(void __user *addr, unsigned long n)
+{
+       /* See rational for this in __copy_to_user() above. */
+       if (n < 64)
+               return __clear_user_std(addr, n);
+       return __clear_user_memset(addr, n);
+}
+
+#if 0
+
+/*
+ * This code is disabled by default, but kept around in case the chosen
+ * thresholds need to be revalidated.  Some overhead (small but still)
+ * would be implied by a runtime determined variable threshold, and
+ * so far the measurement on concerned targets didn't show a worthwhile
+ * variation.
+ *
+ * Note that a fairly precise sched_clock() implementation is needed
+ * for results to make some sense.
+ */
+
+#include <linux/vmalloc.h>
+
+static int __init test_size_treshold(void)
+{
+       struct page *src_page, *dst_page;
+       void *user_ptr, *kernel_ptr;
+       unsigned long long t0, t1, t2;
+       int size, ret;
+
+       ret = -ENOMEM;
+       src_page = alloc_page(GFP_KERNEL);
+       if (!src_page)
+               goto no_src;
+       dst_page = alloc_page(GFP_KERNEL);
+       if (!dst_page)
+               goto no_dst;
+       kernel_ptr = page_address(src_page);
+       user_ptr = vmap(&dst_page, 1, VM_IOREMAP, __pgprot(__P010));
+       if (!user_ptr)
+               goto no_vmap;
+
+       /* warm up the src page dcache */
+       ret = __copy_to_user_memcpy(user_ptr, kernel_ptr, PAGE_SIZE);
+
+       for (size = PAGE_SIZE; size >= 4; size /= 2) {
+               t0 = sched_clock();
+               ret |= __copy_to_user_memcpy(user_ptr, kernel_ptr, size);
+               t1 = sched_clock();
+               ret |= __copy_to_user_std(user_ptr, kernel_ptr, size);
+               t2 = sched_clock();
+               printk("copy_to_user: %d %llu %llu\n", size, t1 - t0, t2 - t1);
+       }
+
+       for (size = PAGE_SIZE; size >= 4; size /= 2) {
+               t0 = sched_clock();
+               ret |= __clear_user_memset(user_ptr, size);
+               t1 = sched_clock();
+               ret |= __clear_user_std(user_ptr, size);
+               t2 = sched_clock();
+               printk("clear_user: %d %llu %llu\n", size, t1 - t0, t2 - t1);
+       }
+
+       if (ret)
+               ret = -EFAULT;
+
+       vunmap(user_ptr);
+no_vmap:
+       put_page(dst_page);
+no_dst:
+       put_page(src_page);
+no_src:
+       return ret;
+}
+
+subsys_initcall(test_size_treshold);
+
+#endif
index e263fda3e2d123ac04b1450695b03a59fd200f59..970fd6b6753ea0d1285ffcd390d7ffe17a0ca497 100644 (file)
@@ -156,6 +156,8 @@ static struct atmel_nand_data __initdata afeb9260_nand_data = {
  * MCI (SD/MMC)
  */
 static struct at91_mmc_data __initdata afeb9260_mmc_data = {
+       .det_pin        = AT91_PIN_PC9,
+       .wp_pin         = AT91_PIN_PC4,
        .slot_b         = 1,
        .wire4          = 1,
 };
@@ -164,6 +166,8 @@ static struct at91_mmc_data __initdata afeb9260_mmc_data = {
 
 static struct i2c_board_info __initdata afeb9260_i2c_devices[] = {
        {
+               I2C_BOARD_INFO("tlv320aic23", 0x1a),
+       }, {
                I2C_BOARD_INFO("fm3130", 0x68),
        }, {
                I2C_BOARD_INFO("24c64", 0x50),
@@ -196,6 +200,8 @@ static void __init afeb9260_board_init(void)
        /* I2C */
        at91_add_device_i2c(afeb9260_i2c_devices,
                        ARRAY_SIZE(afeb9260_i2c_devices));
+       /* Audio */
+       at91_add_device_ssc(AT91SAM9260_ID_SSC, ATMEL_SSC_TX);
 }
 
 MACHINE_START(AFEB9260, "Custom afeb9260 board")
index 438efbb1748274cf7daa04110ebdaf9ae9aadf20..cc270beadd5d67bea4389fd6eed8113177bb3135 100644 (file)
@@ -218,6 +218,13 @@ static struct gpio_led ek_leds[] = {
        }
 };
 
+static struct i2c_board_info __initdata ek_i2c_devices[] = {
+       {
+               I2C_BOARD_INFO("24c512", 0x50),
+       },
+};
+
+
 static void __init ek_board_init(void)
 {
        /* Serial */
@@ -235,7 +242,7 @@ static void __init ek_board_init(void)
        /* MMC */
        at91_add_device_mmc(0, &ek_mmc_data);
        /* I2C */
-       at91_add_device_i2c(NULL, 0);
+       at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
        /* LEDs */
        at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
        /* PCK0 provides MCLK to the WM8731 */
index e4345106ee57ea1da11416c1a6abbc9a1baed94a..bac578fe0d3d38ca0680145209888522282dfb93 100644 (file)
 #define clk_is_sys(x)          ((x)->type & CLK_TYPE_SYSTEM)
 
 
+/*
+ * Chips have some kind of clocks : group them by functionality
+ */
+#define cpu_has_utmi()         (  cpu_is_at91cap9() \
+                               || cpu_is_at91sam9rl())
+
+#define cpu_has_800M_plla()    (cpu_is_at91sam9g20())
+
+#define cpu_has_pllb()         (!cpu_is_at91sam9rl())
+
+#define cpu_has_upll()         (0)
+
+/* USB host HS & FS */
+#define cpu_has_uhp()          (!cpu_is_at91sam9rl())
+
+/* USB device FS only */
+#define cpu_has_udpfs()                (!cpu_is_at91sam9rl())
+
+
 static LIST_HEAD(clocks);
 static DEFINE_SPINLOCK(clk_lock);
 
@@ -140,7 +159,7 @@ static struct clk utmi_clk = {
 };
 static struct clk uhpck = {
        .name           = "uhpck",
-       .parent         = &pllb,
+       /*.parent               = ... we choose parent at runtime */
        .mode           = pmc_sys_mode,
 };
 
@@ -173,7 +192,11 @@ static struct clk __init *at91_css_to_clk(unsigned long css)
                case AT91_PMC_CSS_PLLA:
                        return &plla;
                case AT91_PMC_CSS_PLLB:
-                       return &pllb;
+                       if (cpu_has_upll())
+                               /* CSS_PLLB == CSS_UPLL */
+                               return &utmi_clk;
+                       else if (cpu_has_pllb())
+                               return &pllb;
        }
 
        return NULL;
@@ -322,7 +345,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
                        u32     pckr;
 
                        pckr = at91_sys_read(AT91_PMC_PCKR(clk->id));
-                       pckr &= AT91_PMC_CSS_PLLB;      /* clock selection */
+                       pckr &= AT91_PMC_CSS;   /* clock selection */
                        pckr |= prescale << 2;
                        at91_sys_write(AT91_PMC_PCKR(clk->id), pckr);
                        clk->rate_hz = actual;
@@ -361,7 +384,7 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
 }
 EXPORT_SYMBOL(clk_set_parent);
 
-/* establish PCK0..PCK3 parentage and rate */
+/* establish PCK0..PCKN parentage and rate */
 static void __init init_programmable_clock(struct clk *clk)
 {
        struct clk      *parent;
@@ -389,11 +412,13 @@ static int at91_clk_show(struct seq_file *s, void *unused)
        seq_printf(s, "MOR  = %8x\n", at91_sys_read(AT91_CKGR_MOR));
        seq_printf(s, "MCFR = %8x\n", at91_sys_read(AT91_CKGR_MCFR));
        seq_printf(s, "PLLA = %8x\n", at91_sys_read(AT91_CKGR_PLLAR));
-       if (!cpu_is_at91sam9rl())
+       if (cpu_has_pllb())
                seq_printf(s, "PLLB = %8x\n", at91_sys_read(AT91_CKGR_PLLBR));
-       if (cpu_is_at91cap9() || cpu_is_at91sam9rl())
+       if (cpu_has_utmi())
                seq_printf(s, "UCKR = %8x\n", uckr = at91_sys_read(AT91_CKGR_UCKR));
        seq_printf(s, "MCKR = %8x\n", at91_sys_read(AT91_PMC_MCKR));
+       if (cpu_has_upll())
+               seq_printf(s, "USB  = %8x\n", at91_sys_read(AT91_PMC_USB));
        seq_printf(s, "SR   = %8x\n", sr = at91_sys_read(AT91_PMC_SR));
 
        seq_printf(s, "\n");
@@ -554,16 +579,60 @@ static struct clk *const standard_pmc_clocks[] __initdata = {
        &clk32k,
        &main_clk,
        &plla,
-       &pllb,
-
-       /* PLLB children (USB) */
-       &udpck,
-       &uhpck,
 
        /* MCK */
        &mck
 };
 
+/* PLLB generated USB full speed clock init */
+static void __init at91_pllb_usbfs_clock_init(unsigned long main_clock)
+{
+       /*
+        * USB clock init:  choose 48 MHz PLLB value,
+        * disable 48MHz clock during usb peripheral suspend.
+        *
+        * REVISIT:  assumes MCK doesn't derive from PLLB!
+        */
+       uhpck.parent = &pllb;
+
+       at91_pllb_usb_init = at91_pll_calc(main_clock, 48000000 * 2) | AT91_PMC_USB96M;
+       pllb.rate_hz = at91_pll_rate(&pllb, main_clock, at91_pllb_usb_init);
+       if (cpu_is_at91rm9200()) {
+               uhpck.pmc_mask = AT91RM9200_PMC_UHP;
+               udpck.pmc_mask = AT91RM9200_PMC_UDP;
+               at91_sys_write(AT91_PMC_SCER, AT91RM9200_PMC_MCKUDP);
+       } else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) {
+               uhpck.pmc_mask = AT91SAM926x_PMC_UHP;
+               udpck.pmc_mask = AT91SAM926x_PMC_UDP;
+       } else if (cpu_is_at91cap9()) {
+               uhpck.pmc_mask = AT91CAP9_PMC_UHP;
+       }
+       at91_sys_write(AT91_CKGR_PLLBR, 0);
+
+       udpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init);
+       uhpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init);
+}
+
+/* UPLL generated USB full speed clock init */
+static void __init at91_upll_usbfs_clock_init(unsigned long main_clock)
+{
+       /*
+        * USB clock init: choose 480 MHz from UPLL,
+        */
+       unsigned int usbr = AT91_PMC_USBS_UPLL;
+
+       /* Setup divider by 10 to reach 48 MHz */
+       usbr |= ((10 - 1) << 8) & AT91_PMC_OHCIUSBDIV;
+
+       at91_sys_write(AT91_PMC_USB, usbr);
+
+       /* Now set uhpck values */
+       uhpck.parent = &utmi_clk;
+       uhpck.pmc_mask = AT91SAM926x_PMC_UHP;
+       uhpck.rate_hz = utmi_clk.parent->rate_hz;
+       uhpck.rate_hz /= 1 + ((at91_sys_read(AT91_PMC_USB) & AT91_PMC_OHCIUSBDIV) >> 8);
+}
+
 int __init at91_clock_init(unsigned long main_clock)
 {
        unsigned tmp, freq, mckr;
@@ -585,43 +654,37 @@ int __init at91_clock_init(unsigned long main_clock)
 
        /* report if PLLA is more than mildly overclocked */
        plla.rate_hz = at91_pll_rate(&plla, main_clock, at91_sys_read(AT91_CKGR_PLLAR));
-       if ((!cpu_is_at91sam9g20() && plla.rate_hz > 209000000)
-          || (cpu_is_at91sam9g20() && plla.rate_hz > 800000000))
+       if ((!cpu_has_800M_plla() && plla.rate_hz > 209000000)
+          || (cpu_has_800M_plla() && plla.rate_hz > 800000000))
                pr_info("Clocks: PLLA overclocked, %ld MHz\n", plla.rate_hz / 1000000);
 
-       /*
-        * USB clock init:  choose 48 MHz PLLB value,
-        * disable 48MHz clock during usb peripheral suspend.
-        *
-        * REVISIT:  assumes MCK doesn't derive from PLLB!
-        */
-       at91_pllb_usb_init = at91_pll_calc(main_clock, 48000000 * 2) | AT91_PMC_USB96M;
-       pllb.rate_hz = at91_pll_rate(&pllb, main_clock, at91_pllb_usb_init);
-       if (cpu_is_at91rm9200()) {
-               uhpck.pmc_mask = AT91RM9200_PMC_UHP;
-               udpck.pmc_mask = AT91RM9200_PMC_UDP;
-               at91_sys_write(AT91_PMC_SCER, AT91RM9200_PMC_MCKUDP);
-       } else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) {
-               uhpck.pmc_mask = AT91SAM926x_PMC_UHP;
-               udpck.pmc_mask = AT91SAM926x_PMC_UDP;
-       } else if (cpu_is_at91cap9()) {
-               uhpck.pmc_mask = AT91CAP9_PMC_UHP;
+
+       if (cpu_has_upll() && !cpu_has_pllb()) {
+               /* setup UTMI clock as the fourth primary clock
+                * (instead of pllb) */
+               utmi_clk.type |= CLK_TYPE_PRIMARY;
+               utmi_clk.id = 3;
        }
-       at91_sys_write(AT91_CKGR_PLLBR, 0);
 
-       udpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init);
-       uhpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init);
 
        /*
         * USB HS clock init
         */
-       if (cpu_is_at91cap9() || cpu_is_at91sam9rl()) {
+       if (cpu_has_utmi())
                /*
                 * multiplier is hard-wired to 40
                 * (obtain the USB High Speed 480 MHz when input is 12 MHz)
                 */
                utmi_clk.rate_hz = 40 * utmi_clk.parent->rate_hz;
-       }
+
+       /*
+        * USB FS clock init
+        */
+       if (cpu_has_pllb())
+               at91_pllb_usbfs_clock_init(main_clock);
+       if (cpu_has_upll())
+               /* assumes that we choose UPLL for USB and not PLLA */
+               at91_upll_usbfs_clock_init(main_clock);
 
        /*
         * MCK and CPU derive from one of those primary clocks.
@@ -631,21 +694,31 @@ int __init at91_clock_init(unsigned long main_clock)
        mck.parent = at91_css_to_clk(mckr & AT91_PMC_CSS);
        freq = mck.parent->rate_hz;
        freq /= (1 << ((mckr & AT91_PMC_PRES) >> 2));                           /* prescale */
-       if (cpu_is_at91rm9200())
+       if (cpu_is_at91rm9200()) {
                mck.rate_hz = freq / (1 + ((mckr & AT91_PMC_MDIV) >> 8));       /* mdiv */
-       else if (cpu_is_at91sam9g20()) {
+       else if (cpu_is_at91sam9g20()) {
                mck.rate_hz = (mckr & AT91_PMC_MDIV) ?
                        freq / ((mckr & AT91_PMC_MDIV) >> 7) : freq;    /* mdiv ; (x >> 7) = ((x >> 8) * 2) */
                if (mckr & AT91_PMC_PDIV)
                        freq /= 2;              /* processor clock division */
-       } else
+       } else {
                mck.rate_hz = freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8));      /* mdiv */
+       }
 
        /* Register the PMC's standard clocks */
        for (i = 0; i < ARRAY_SIZE(standard_pmc_clocks); i++)
                list_add_tail(&standard_pmc_clocks[i]->node, &clocks);
 
-       if (cpu_is_at91cap9() || cpu_is_at91sam9rl())
+       if (cpu_has_pllb())
+               list_add_tail(&pllb.node, &clocks);
+
+       if (cpu_has_uhp())
+               list_add_tail(&uhpck.node, &clocks);
+
+       if (cpu_has_udpfs())
+               list_add_tail(&udpck.node, &clocks);
+
+       if (cpu_has_utmi())
                list_add_tail(&utmi_clk.node, &clocks);
 
        /* MCK and CPU clock are "always on" */
index 9561e33b8a9af76ecd3eb91670254f549065b639..64589eaaaee8f8d57ae9044ed587eaa2bd329f66 100644 (file)
@@ -23,7 +23,7 @@
 #define                AT91_PMC_PCK            (1 <<  0)               /* Processor Clock */
 #define                AT91RM9200_PMC_UDP      (1 <<  1)               /* USB Devcice Port Clock [AT91RM9200 only] */
 #define                AT91RM9200_PMC_MCKUDP   (1 <<  2)               /* USB Device Port Master Clock Automatic Disable on Suspend [AT91RM9200 only] */
-#define                AT91CAP9_PMC_DDR        (1 <<  2)               /* DDR Clock [AT91CAP9 revC only] */
+#define                AT91CAP9_PMC_DDR        (1 <<  2)               /* DDR Clock [CAP9 revC & some SAM9 only] */
 #define                AT91RM9200_PMC_UHP      (1 <<  4)               /* USB Host Port Clock [AT91RM9200 only] */
 #define                AT91SAM926x_PMC_UHP     (1 <<  6)               /* USB Host Port Clock [AT91SAM926x only] */
 #define                AT91CAP9_PMC_UHP        (1 <<  6)               /* USB Host Port Clock [AT91CAP9 only] */
 #define        AT91_PMC_PCDR           (AT91_PMC + 0x14)       /* Peripheral Clock Disable Register */
 #define        AT91_PMC_PCSR           (AT91_PMC + 0x18)       /* Peripheral Clock Status Register */
 
-#define        AT91_CKGR_UCKR          (AT91_PMC + 0x1C)       /* UTMI Clock Register [SAM9RL, CAP9] */
+#define        AT91_CKGR_UCKR          (AT91_PMC + 0x1C)       /* UTMI Clock Register [some SAM9, CAP9] */
 #define                AT91_PMC_UPLLEN         (1   << 16)             /* UTMI PLL Enable */
 #define                AT91_PMC_UPLLCOUNT      (0xf << 20)             /* UTMI PLL Start-up Time */
 #define                AT91_PMC_BIASEN         (1   << 24)             /* UTMI BIAS Enable */
-#define                AT91_PMC_BIASCOUNT      (0xf << 28)             /* UTMI PLL Start-up Time */
+#define                AT91_PMC_BIASCOUNT      (0xf << 28)             /* UTMI BIAS Start-up Time */
 
 #define        AT91_CKGR_MOR           (AT91_PMC + 0x20)       /* Main Oscillator Register [not on SAM9RL] */
 #define                AT91_PMC_MOSCEN         (1    << 0)             /* Main Oscillator Enable */
@@ -72,6 +72,7 @@
 #define                        AT91_PMC_CSS_MAIN               (1 << 0)
 #define                        AT91_PMC_CSS_PLLA               (2 << 0)
 #define                        AT91_PMC_CSS_PLLB               (3 << 0)
+#define                        AT91_PMC_CSS_UPLL               (3 << 0)        /* [some SAM9 only] */
 #define                AT91_PMC_PRES           (7 <<  2)               /* Master Clock Prescaler */
 #define                        AT91_PMC_PRES_1                 (0 << 2)
 #define                        AT91_PMC_PRES_2                 (1 << 2)
 #define                        AT91SAM9_PMC_MDIV_1             (0 << 8)        /* [SAM9,CAP9 only] */
 #define                        AT91SAM9_PMC_MDIV_2             (1 << 8)
 #define                        AT91SAM9_PMC_MDIV_4             (2 << 8)
-#define                        AT91SAM9_PMC_MDIV_6             (3 << 8)
+#define                        AT91SAM9_PMC_MDIV_6             (3 << 8)        /* [some SAM9 only] */
+#define                        AT91SAM9_PMC_MDIV_3             (3 << 8)        /* [some SAM9 only] */
 #define                AT91_PMC_PDIV           (1 << 12)               /* Processor Clock Division [some SAM9 only] */
 #define                        AT91_PMC_PDIV_1                 (0 << 12)
 #define                        AT91_PMC_PDIV_2                 (1 << 12)
+#define                AT91_PMC_PLLADIV2       (1 << 12)               /* PLLA divisor by 2 [some SAM9 only] */
+#define                        AT91_PMC_PLLADIV2_OFF           (0 << 12)
+#define                        AT91_PMC_PLLADIV2_ON            (1 << 12)
 
-#define        AT91_PMC_PCKR(n)        (AT91_PMC + 0x40 + ((n) * 4))   /* Programmable Clock 0-3 Registers */
+#define        AT91_PMC_USB            (AT91_PMC + 0x38)       /* USB Clock Register [some SAM9 only] */
+#define                AT91_PMC_USBS           (0x1 <<  0)             /* USB OHCI Input clock selection */
+#define                        AT91_PMC_USBS_PLLA              (0 << 0)
+#define                        AT91_PMC_USBS_UPLL              (1 << 0)
+#define                AT91_PMC_OHCIUSBDIV     (0xF <<  8)             /* Divider for USB OHCI Clock */
+
+#define        AT91_PMC_PCKR(n)        (AT91_PMC + 0x40 + ((n) * 4))   /* Programmable Clock 0-N Registers */
+#define                AT91_PMC_CSSMCK         (0x1 <<  8)             /* CSS or Master Clock Selection */
+#define                        AT91_PMC_CSSMCK_CSS             (0 << 8)
+#define                        AT91_PMC_CSSMCK_MCK             (1 << 8)
 
 #define        AT91_PMC_IER            (AT91_PMC + 0x60)       /* Interrupt Enable Register */
 #define        AT91_PMC_IDR            (AT91_PMC + 0x64)       /* Interrupt Disable Register */
 #define                AT91_PMC_LOCKA          (1 <<  1)               /* PLLA Lock */
 #define                AT91_PMC_LOCKB          (1 <<  2)               /* PLLB Lock */
 #define                AT91_PMC_MCKRDY         (1 <<  3)               /* Master Clock */
-#define                AT91_PMC_LOCKU          (1 <<  6)               /* UPLL Lock [AT91CAP9 only] */
+#define                AT91_PMC_LOCKU          (1 <<  6)               /* UPLL Lock [some SAM9, AT91CAP9 only] */
 #define                AT91_PMC_OSCSEL         (1 <<  7)               /* Slow Clock Oscillator [AT91CAP9 revC only] */
 #define                AT91_PMC_PCK0RDY        (1 <<  8)               /* Programmable Clock 0 */
 #define                AT91_PMC_PCK1RDY        (1 <<  9)               /* Programmable Clock 1 */
index a9c78bc72b84e9a21e036592b951e3da0df6b469..be747f5c6cd8a86db5b265d8f4f9af3eebd9f93b 100644 (file)
@@ -1,11 +1,26 @@
 if ARCH_DAVINCI
 
+config AINTC
+       bool
+
+config CP_INTC
+       bool
+
 menu "TI DaVinci Implementations"
 
 comment "DaVinci Core Type"
 
 config ARCH_DAVINCI_DM644x
        bool "DaVinci 644x based system"
+       select AINTC
+
+config ARCH_DAVINCI_DM355
+        bool "DaVinci 355 based system"
+       select AINTC
+
+config ARCH_DAVINCI_DM646x
+        bool "DaVinci 646x based system"
+       select AINTC
 
 comment "DaVinci Board Type"
 
@@ -17,6 +32,34 @@ config MACH_DAVINCI_EVM
          Configure this option to specify the whether the board used
          for development is a DM644x EVM
 
+config MACH_SFFSDR
+       bool "Lyrtech SFFSDR"
+       depends on ARCH_DAVINCI_DM644x
+       help
+         Say Y here to select the Lyrtech Small Form Factor
+         Software Defined Radio (SFFSDR) board.
+
+config MACH_DAVINCI_DM355_EVM
+       bool "TI DM355 EVM"
+       depends on ARCH_DAVINCI_DM355
+       help
+         Configure this option to specify the whether the board used
+         for development is a DM355 EVM
+
+config MACH_DM355_LEOPARD
+       bool "DM355 Leopard board"
+       depends on ARCH_DAVINCI_DM355
+       help
+         Configure this option to specify the whether the board used
+         for development is a DM355 Leopard board.
+
+config MACH_DAVINCI_DM6467_EVM
+       bool "TI DM6467 EVM"
+       depends on ARCH_DAVINCI_DM646x
+       help
+         Configure this option to specify the whether the board used
+         for development is a DM6467 EVM
+
 
 config DAVINCI_MUX
        bool "DAVINCI multiplexing support"
index 1674661942f3116f984cd9679937487cca7d845c..059ab78084baa32e04cf723efc2e2684dcc763d7 100644 (file)
@@ -4,13 +4,22 @@
 #
 
 # Common objects
-obj-y                  := time.o irq.o clock.o serial.o io.o id.o psc.o \
-                          gpio.o devices.o dma.o usb.o
+obj-y                  := time.o clock.o serial.o io.o psc.o \
+                          gpio.o devices.o dma.o usb.o common.o sram.o
 
 obj-$(CONFIG_DAVINCI_MUX)              += mux.o
 
 # Chip specific
 obj-$(CONFIG_ARCH_DAVINCI_DM644x)       += dm644x.o
+obj-$(CONFIG_ARCH_DAVINCI_DM355)        += dm355.o
+obj-$(CONFIG_ARCH_DAVINCI_DM646x)       += dm646x.o
+
+obj-$(CONFIG_AINTC)                    += irq.o
+obj-$(CONFIG_CP_INTC)                  += cp_intc.o
 
 # Board specific
 obj-$(CONFIG_MACH_DAVINCI_EVM)         += board-dm644x-evm.o
+obj-$(CONFIG_MACH_SFFSDR)              += board-sffsdr.o
+obj-$(CONFIG_MACH_DAVINCI_DM355_EVM)   += board-dm355-evm.o
+obj-$(CONFIG_MACH_DM355_LEOPARD)       += board-dm355-leopard.o
+obj-$(CONFIG_MACH_DAVINCI_DM6467_EVM)  += board-dm646x-evm.o
diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c
new file mode 100644 (file)
index 0000000..5ac2f56
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * TI DaVinci EVM board support
+ *
+ * Author: Kevin Hilman, Deep Root Systems, LLC
+ *
+ * 2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/eeprom.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/flash.h>
+
+#include <mach/hardware.h>
+#include <mach/dm355.h>
+#include <mach/psc.h>
+#include <mach/common.h>
+#include <mach/i2c.h>
+#include <mach/serial.h>
+#include <mach/nand.h>
+#include <mach/mmc.h>
+#include <mach/common.h>
+
+#define DAVINCI_ASYNC_EMIF_CONTROL_BASE                0x01e10000
+#define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE       0x02000000
+
+/* NOTE:  this is geared for the standard config, with a socketed
+ * 2 GByte Micron NAND (MT29F16G08FAA) using 128KB sectors.  If you
+ * swap chips, maybe with a different block size, partitioning may
+ * need to be changed.
+ */
+#define NAND_BLOCK_SIZE                SZ_128K
+
+static struct mtd_partition davinci_nand_partitions[] = {
+       {
+               /* UBL (a few copies) plus U-Boot */
+               .name           = "bootloader",
+               .offset         = 0,
+               .size           = 15 * NAND_BLOCK_SIZE,
+               .mask_flags     = MTD_WRITEABLE, /* force read-only */
+       }, {
+               /* U-Boot environment */
+               .name           = "params",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 1 * NAND_BLOCK_SIZE,
+               .mask_flags     = 0,
+       }, {
+               .name           = "kernel",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_4M,
+               .mask_flags     = 0,
+       }, {
+               .name           = "filesystem1",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_512M,
+               .mask_flags     = 0,
+       }, {
+               .name           = "filesystem2",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = MTDPART_SIZ_FULL,
+               .mask_flags     = 0,
+       }
+       /* two blocks with bad block table (and mirror) at the end */
+};
+
+static struct davinci_nand_pdata davinci_nand_data = {
+       .mask_chipsel           = BIT(14),
+       .parts                  = davinci_nand_partitions,
+       .nr_parts               = ARRAY_SIZE(davinci_nand_partitions),
+       .ecc_mode               = NAND_ECC_HW_SYNDROME,
+       .options                = NAND_USE_FLASH_BBT,
+};
+
+static struct resource davinci_nand_resources[] = {
+       {
+               .start          = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE,
+               .end            = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE + SZ_32M - 1,
+               .flags          = IORESOURCE_MEM,
+       }, {
+               .start          = DAVINCI_ASYNC_EMIF_CONTROL_BASE,
+               .end            = DAVINCI_ASYNC_EMIF_CONTROL_BASE + SZ_4K - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device davinci_nand_device = {
+       .name                   = "davinci_nand",
+       .id                     = 0,
+
+       .num_resources          = ARRAY_SIZE(davinci_nand_resources),
+       .resource               = davinci_nand_resources,
+
+       .dev                    = {
+               .platform_data  = &davinci_nand_data,
+       },
+};
+
+static struct davinci_i2c_platform_data i2c_pdata = {
+       .bus_freq       = 400   /* kHz */,
+       .bus_delay      = 0     /* usec */,
+};
+
+static int dm355evm_mmc_gpios = -EINVAL;
+
+static void dm355evm_mmcsd_gpios(unsigned gpio)
+{
+       gpio_request(gpio + 0, "mmc0_ro");
+       gpio_request(gpio + 1, "mmc0_cd");
+       gpio_request(gpio + 2, "mmc1_ro");
+       gpio_request(gpio + 3, "mmc1_cd");
+
+       /* we "know" these are input-only so we don't
+        * need to call gpio_direction_input()
+        */
+
+       dm355evm_mmc_gpios = gpio;
+}
+
+static struct i2c_board_info dm355evm_i2c_info[] = {
+       { I2C_BOARD_INFO("dm355evm_msp", 0x25),
+               .platform_data = dm355evm_mmcsd_gpios,
+               /* plus irq */ },
+       /* { I2C_BOARD_INFO("tlv320aic3x", 0x1b), }, */
+       /* { I2C_BOARD_INFO("tvp5146", 0x5d), }, */
+};
+
+static void __init evm_init_i2c(void)
+{
+       davinci_init_i2c(&i2c_pdata);
+
+       gpio_request(5, "dm355evm_msp");
+       gpio_direction_input(5);
+       dm355evm_i2c_info[0].irq = gpio_to_irq(5);
+
+       i2c_register_board_info(1, dm355evm_i2c_info,
+                       ARRAY_SIZE(dm355evm_i2c_info));
+}
+
+static struct resource dm355evm_dm9000_rsrc[] = {
+       {
+               /* addr */
+               .start  = 0x04014000,
+               .end    = 0x04014001,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               /* data */
+               .start  = 0x04014002,
+               .end    = 0x04014003,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .flags  = IORESOURCE_IRQ
+                       | IORESOURCE_IRQ_HIGHEDGE /* rising (active high) */,
+       },
+};
+
+static struct platform_device dm355evm_dm9000 = {
+       .name           = "dm9000",
+       .id             = -1,
+       .resource       = dm355evm_dm9000_rsrc,
+       .num_resources  = ARRAY_SIZE(dm355evm_dm9000_rsrc),
+};
+
+static struct platform_device *davinci_evm_devices[] __initdata = {
+       &dm355evm_dm9000,
+       &davinci_nand_device,
+};
+
+static struct davinci_uart_config uart_config __initdata = {
+       .enabled_uarts = (1 << 0),
+};
+
+static void __init dm355_evm_map_io(void)
+{
+       dm355_init();
+}
+
+static int dm355evm_mmc_get_cd(int module)
+{
+       if (!gpio_is_valid(dm355evm_mmc_gpios))
+               return -ENXIO;
+       /* low == card present */
+       return !gpio_get_value_cansleep(dm355evm_mmc_gpios + 2 * module + 1);
+}
+
+static int dm355evm_mmc_get_ro(int module)
+{
+       if (!gpio_is_valid(dm355evm_mmc_gpios))
+               return -ENXIO;
+       /* high == card's write protect switch active */
+       return gpio_get_value_cansleep(dm355evm_mmc_gpios + 2 * module + 0);
+}
+
+static struct davinci_mmc_config dm355evm_mmc_config = {
+       .get_cd         = dm355evm_mmc_get_cd,
+       .get_ro         = dm355evm_mmc_get_ro,
+       .wires          = 4,
+       .max_freq       = 50000000,
+       .caps           = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
+       .version        = MMC_CTLR_VERSION_1,
+};
+
+/* Don't connect anything to J10 unless you're only using USB host
+ * mode *and* have to do so with some kind of gender-bender.  If
+ * you have proper Mini-B or Mini-A cables (or Mini-A adapters)
+ * the ID pin won't need any help.
+ */
+#ifdef CONFIG_USB_MUSB_PERIPHERAL
+#define USB_ID_VALUE   0       /* ID pulled high; *should* float */
+#else
+#define USB_ID_VALUE   1       /* ID pulled low */
+#endif
+
+static struct spi_eeprom at25640a = {
+       .byte_len       = SZ_64K / 8,
+       .name           = "at25640a",
+       .page_size      = 32,
+       .flags          = EE_ADDR2,
+};
+
+static struct spi_board_info dm355_evm_spi_info[] __initconst = {
+       {
+               .modalias       = "at25",
+               .platform_data  = &at25640a,
+               .max_speed_hz   = 10 * 1000 * 1000,     /* at 3v3 */
+               .bus_num        = 0,
+               .chip_select    = 0,
+               .mode           = SPI_MODE_0,
+       },
+};
+
+static __init void dm355_evm_init(void)
+{
+       struct clk *aemif;
+
+       gpio_request(1, "dm9000");
+       gpio_direction_input(1);
+       dm355evm_dm9000_rsrc[2].start = gpio_to_irq(1);
+
+       aemif = clk_get(&dm355evm_dm9000.dev, "aemif");
+       if (IS_ERR(aemif))
+               WARN("%s: unable to get AEMIF clock\n", __func__);
+       else
+               clk_enable(aemif);
+
+       platform_add_devices(davinci_evm_devices,
+                            ARRAY_SIZE(davinci_evm_devices));
+       evm_init_i2c();
+       davinci_serial_init(&uart_config);
+
+       /* NOTE:  NAND flash timings set by the UBL are slower than
+        * needed by MT29F16G08FAA chips ... EMIF.A1CR is 0x40400204
+        * but could be 0x0400008c for about 25% faster page reads.
+        */
+
+       gpio_request(2, "usb_id_toggle");
+       gpio_direction_output(2, USB_ID_VALUE);
+       /* irlml6401 switches over 1A in under 8 msec */
+       setup_usb(500, 8);
+
+       davinci_setup_mmc(0, &dm355evm_mmc_config);
+       davinci_setup_mmc(1, &dm355evm_mmc_config);
+
+       dm355_init_spi0(BIT(0), dm355_evm_spi_info,
+                       ARRAY_SIZE(dm355_evm_spi_info));
+}
+
+static __init void dm355_evm_irq_init(void)
+{
+       davinci_irq_init();
+}
+
+MACHINE_START(DAVINCI_DM355_EVM, "DaVinci DM355 EVM")
+       .phys_io      = IO_PHYS,
+       .io_pg_offst  = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
+       .boot_params  = (0x80000100),
+       .map_io       = dm355_evm_map_io,
+       .init_irq     = dm355_evm_irq_init,
+       .timer        = &davinci_timer,
+       .init_machine = dm355_evm_init,
+MACHINE_END
diff --git a/arch/arm/mach-davinci/board-dm355-leopard.c b/arch/arm/mach-davinci/board-dm355-leopard.c
new file mode 100644 (file)
index 0000000..28c9008
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * DM355 leopard board support
+ *
+ * Based on board-dm355-evm.c
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/eeprom.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/flash.h>
+
+#include <mach/hardware.h>
+#include <mach/dm355.h>
+#include <mach/psc.h>
+#include <mach/common.h>
+#include <mach/i2c.h>
+#include <mach/serial.h>
+#include <mach/nand.h>
+#include <mach/mmc.h>
+#include <mach/common.h>
+
+#define DAVINCI_ASYNC_EMIF_CONTROL_BASE                0x01e10000
+#define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE       0x02000000
+
+/* NOTE:  this is geared for the standard config, with a socketed
+ * 2 GByte Micron NAND (MT29F16G08FAA) using 128KB sectors.  If you
+ * swap chips, maybe with a different block size, partitioning may
+ * need to be changed.
+ */
+#define NAND_BLOCK_SIZE                SZ_128K
+
+static struct mtd_partition davinci_nand_partitions[] = {
+       {
+               /* UBL (a few copies) plus U-Boot */
+               .name           = "bootloader",
+               .offset         = 0,
+               .size           = 15 * NAND_BLOCK_SIZE,
+               .mask_flags     = MTD_WRITEABLE, /* force read-only */
+       }, {
+               /* U-Boot environment */
+               .name           = "params",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 1 * NAND_BLOCK_SIZE,
+               .mask_flags     = 0,
+       }, {
+               .name           = "kernel",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_4M,
+               .mask_flags     = 0,
+       }, {
+               .name           = "filesystem1",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_512M,
+               .mask_flags     = 0,
+       }, {
+               .name           = "filesystem2",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = MTDPART_SIZ_FULL,
+               .mask_flags     = 0,
+       }
+       /* two blocks with bad block table (and mirror) at the end */
+};
+
+static struct davinci_nand_pdata davinci_nand_data = {
+       .mask_chipsel           = BIT(14),
+       .parts                  = davinci_nand_partitions,
+       .nr_parts               = ARRAY_SIZE(davinci_nand_partitions),
+       .ecc_mode               = NAND_ECC_HW_SYNDROME,
+       .options                = NAND_USE_FLASH_BBT,
+};
+
+static struct resource davinci_nand_resources[] = {
+       {
+               .start          = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE,
+               .end            = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE + SZ_32M - 1,
+               .flags          = IORESOURCE_MEM,
+       }, {
+               .start          = DAVINCI_ASYNC_EMIF_CONTROL_BASE,
+               .end            = DAVINCI_ASYNC_EMIF_CONTROL_BASE + SZ_4K - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device davinci_nand_device = {
+       .name                   = "davinci_nand",
+       .id                     = 0,
+
+       .num_resources          = ARRAY_SIZE(davinci_nand_resources),
+       .resource               = davinci_nand_resources,
+
+       .dev                    = {
+               .platform_data  = &davinci_nand_data,
+       },
+};
+
+static struct davinci_i2c_platform_data i2c_pdata = {
+       .bus_freq       = 400   /* kHz */,
+       .bus_delay      = 0     /* usec */,
+};
+
+static int leopard_mmc_gpio = -EINVAL;
+
+static void dm355leopard_mmcsd_gpios(unsigned gpio)
+{
+       gpio_request(gpio + 0, "mmc0_ro");
+       gpio_request(gpio + 1, "mmc0_cd");
+       gpio_request(gpio + 2, "mmc1_ro");
+       gpio_request(gpio + 3, "mmc1_cd");
+
+       /* we "know" these are input-only so we don't
+        * need to call gpio_direction_input()
+        */
+
+       leopard_mmc_gpio = gpio;
+}
+
+static struct i2c_board_info dm355leopard_i2c_info[] = {
+       { I2C_BOARD_INFO("dm355leopard_msp", 0x25),
+               .platform_data = dm355leopard_mmcsd_gpios,
+               /* plus irq */ },
+       /* { I2C_BOARD_INFO("tlv320aic3x", 0x1b), }, */
+       /* { I2C_BOARD_INFO("tvp5146", 0x5d), }, */
+};
+
+static void __init leopard_init_i2c(void)
+{
+       davinci_init_i2c(&i2c_pdata);
+
+       gpio_request(5, "dm355leopard_msp");
+       gpio_direction_input(5);
+       dm355leopard_i2c_info[0].irq = gpio_to_irq(5);
+
+       i2c_register_board_info(1, dm355leopard_i2c_info,
+                       ARRAY_SIZE(dm355leopard_i2c_info));
+}
+
+static struct resource dm355leopard_dm9000_rsrc[] = {
+       {
+               /* addr */
+               .start  = 0x04000000,
+               .end    = 0x04000001,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               /* data */
+               .start  = 0x04000016,
+               .end    = 0x04000017,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .flags  = IORESOURCE_IRQ
+                       | IORESOURCE_IRQ_HIGHEDGE /* rising (active high) */,
+       },
+};
+
+static struct platform_device dm355leopard_dm9000 = {
+       .name           = "dm9000",
+       .id             = -1,
+       .resource       = dm355leopard_dm9000_rsrc,
+       .num_resources  = ARRAY_SIZE(dm355leopard_dm9000_rsrc),
+};
+
+static struct platform_device *davinci_leopard_devices[] __initdata = {
+       &dm355leopard_dm9000,
+       &davinci_nand_device,
+};
+
+static struct davinci_uart_config uart_config __initdata = {
+       .enabled_uarts = (1 << 0),
+};
+
+static void __init dm355_leopard_map_io(void)
+{
+       dm355_init();
+}
+
+static int dm355leopard_mmc_get_cd(int module)
+{
+       if (!gpio_is_valid(leopard_mmc_gpio))
+               return -ENXIO;
+       /* low == card present */
+       return !gpio_get_value_cansleep(leopard_mmc_gpio + 2 * module + 1);
+}
+
+static int dm355leopard_mmc_get_ro(int module)
+{
+       if (!gpio_is_valid(leopard_mmc_gpio))
+               return -ENXIO;
+       /* high == card's write protect switch active */
+       return gpio_get_value_cansleep(leopard_mmc_gpio + 2 * module + 0);
+}
+
+static struct davinci_mmc_config dm355leopard_mmc_config = {
+       .get_cd         = dm355leopard_mmc_get_cd,
+       .get_ro         = dm355leopard_mmc_get_ro,
+       .wires          = 4,
+       .max_freq       = 50000000,
+       .caps           = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
+};
+
+/* Don't connect anything to J10 unless you're only using USB host
+ * mode *and* have to do so with some kind of gender-bender.  If
+ * you have proper Mini-B or Mini-A cables (or Mini-A adapters)
+ * the ID pin won't need any help.
+ */
+#ifdef CONFIG_USB_MUSB_PERIPHERAL
+#define USB_ID_VALUE   0       /* ID pulled high; *should* float */
+#else
+#define USB_ID_VALUE   1       /* ID pulled low */
+#endif
+
+static struct spi_eeprom at25640a = {
+       .byte_len       = SZ_64K / 8,
+       .name           = "at25640a",
+       .page_size      = 32,
+       .flags          = EE_ADDR2,
+};
+
+static struct spi_board_info dm355_leopard_spi_info[] __initconst = {
+       {
+               .modalias       = "at25",
+               .platform_data  = &at25640a,
+               .max_speed_hz   = 10 * 1000 * 1000,     /* at 3v3 */
+               .bus_num        = 0,
+               .chip_select    = 0,
+               .mode           = SPI_MODE_0,
+       },
+};
+
+static __init void dm355_leopard_init(void)
+{
+       struct clk *aemif;
+
+       gpio_request(9, "dm9000");
+       gpio_direction_input(9);
+       dm355leopard_dm9000_rsrc[2].start = gpio_to_irq(9);
+
+       aemif = clk_get(&dm355leopard_dm9000.dev, "aemif");
+       if (IS_ERR(aemif))
+               WARN("%s: unable to get AEMIF clock\n", __func__);
+       else
+               clk_enable(aemif);
+
+       platform_add_devices(davinci_leopard_devices,
+                            ARRAY_SIZE(davinci_leopard_devices));
+       leopard_init_i2c();
+       davinci_serial_init(&uart_config);
+
+       /* NOTE:  NAND flash timings set by the UBL are slower than
+        * needed by MT29F16G08FAA chips ... EMIF.A1CR is 0x40400204
+        * but could be 0x0400008c for about 25% faster page reads.
+        */
+
+       gpio_request(2, "usb_id_toggle");
+       gpio_direction_output(2, USB_ID_VALUE);
+       /* irlml6401 switches over 1A in under 8 msec */
+       setup_usb(500, 8);
+
+       davinci_setup_mmc(0, &dm355leopard_mmc_config);
+       davinci_setup_mmc(1, &dm355leopard_mmc_config);
+
+       dm355_init_spi0(BIT(0), dm355_leopard_spi_info,
+                       ARRAY_SIZE(dm355_leopard_spi_info));
+}
+
+static __init void dm355_leopard_irq_init(void)
+{
+       davinci_irq_init();
+}
+
+MACHINE_START(DM355_LEOPARD, "DaVinci DM355 leopard")
+       .phys_io      = IO_PHYS,
+       .io_pg_offst  = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
+       .boot_params  = (0x80000100),
+       .map_io       = dm355_leopard_map_io,
+       .init_irq     = dm355_leopard_irq_init,
+       .timer        = &davinci_timer,
+       .init_machine = dm355_leopard_init,
+MACHINE_END
index b2e7f9c63bc531d2d2981127c5c1936079bb3e6a..d9d40450bdc5d8c018b03c18305d282d1160faab 100644 (file)
 #include <linux/gpio.h>
 #include <linux/leds.h>
 #include <linux/memory.h>
-#include <linux/etherdevice.h>
 
 #include <linux/i2c.h>
 #include <linux/i2c/pcf857x.h>
 #include <linux/i2c/at24.h>
-
+#include <linux/etherdevice.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
@@ -44,6 +43,9 @@
 #include <mach/mux.h>
 #include <mach/psc.h>
 #include <mach/nand.h>
+#include <mach/mmc.h>
+#include <mach/emac.h>
+#include <mach/common.h>
 
 #define DM644X_EVM_PHY_MASK            (0x2)
 #define DM644X_EVM_MDIO_FREQUENCY      (2200000) /* PHY bus frequency */
@@ -436,45 +438,15 @@ static struct pcf857x_platform_data pcf_data_u35 = {
  *  - 0x0039, 1 byte NTSC vs PAL (bit 0x80 == PAL)
  *  - ... newer boards may have more
  */
-static struct memory_accessor *at24_mem_acc;
-
-static void at24_setup(struct memory_accessor *mem_acc, void *context)
-{
-       DECLARE_MAC_BUF(mac_str);
-       char mac_addr[6];
-
-       at24_mem_acc = mem_acc;
-
-       /* Read MAC addr from EEPROM */
-       if (at24_mem_acc->read(at24_mem_acc, mac_addr, 0x7f00, 6) == 6) {
-               printk(KERN_INFO "Read MAC addr from EEPROM: %s\n",
-                      print_mac(mac_str, mac_addr));
-       }
-}
 
 static struct at24_platform_data eeprom_info = {
        .byte_len       = (256*1024) / 8,
        .page_size      = 64,
        .flags          = AT24_FLAG_ADDR16,
-       .setup          = at24_setup,
+       .setup          = davinci_get_mac_addr,
+       .context        = (void *)0x7f00,
 };
 
-int dm6446evm_eeprom_read(void *buf, off_t off, size_t count)
-{
-       if (at24_mem_acc)
-               return at24_mem_acc->read(at24_mem_acc, buf, off, count);
-       return -ENODEV;
-}
-EXPORT_SYMBOL(dm6446evm_eeprom_read);
-
-int dm6446evm_eeprom_write(void *buf, off_t off, size_t count)
-{
-       if (at24_mem_acc)
-               return at24_mem_acc->write(at24_mem_acc, buf, off, count);
-       return -ENODEV;
-}
-EXPORT_SYMBOL(dm6446evm_eeprom_write);
-
 /*
  * MSP430 supports RTC, card detection, input from IR remote, and
  * a bit more.  It triggers interrupts on GPIO(7) from pressing
@@ -545,6 +517,27 @@ static int dm6444evm_msp430_get_pins(void)
        return (buf[3] << 8) | buf[2];
 }
 
+static int dm6444evm_mmc_get_cd(int module)
+{
+       int status = dm6444evm_msp430_get_pins();
+
+       return (status < 0) ? status : !(status & BIT(1));
+}
+
+static int dm6444evm_mmc_get_ro(int module)
+{
+       int status = dm6444evm_msp430_get_pins();
+
+       return (status < 0) ? status : status & BIT(6 + 8);
+}
+
+static struct davinci_mmc_config dm6446evm_mmc_config = {
+       .get_cd         = dm6444evm_mmc_get_cd,
+       .get_ro         = dm6444evm_mmc_get_ro,
+       .wires          = 4,
+       .version        = MMC_CTLR_VERSION_1
+};
+
 static struct i2c_board_info __initdata i2c_info[] =  {
        {
                I2C_BOARD_INFO("dm6446evm_msp", 0x23),
@@ -598,7 +591,6 @@ static struct davinci_uart_config uart_config __initdata = {
 static void __init
 davinci_evm_map_io(void)
 {
-       davinci_map_common_io();
        dm644x_init();
 }
 
@@ -639,6 +631,7 @@ static int davinci_phy_fixup(struct phy_device *phydev)
 static __init void davinci_evm_init(void)
 {
        struct clk *aemif_clk;
+       struct davinci_soc_info *soc_info = &davinci_soc_info;
 
        aemif_clk = clk_get(NULL, "aemif");
        clk_enable(aemif_clk);
@@ -671,8 +664,13 @@ static __init void davinci_evm_init(void)
                             ARRAY_SIZE(davinci_evm_devices));
        evm_init_i2c();
 
+       davinci_setup_mmc(0, &dm6446evm_mmc_config);
+
        davinci_serial_init(&uart_config);
 
+       soc_info->emac_pdata->phy_mask = DM644X_EVM_PHY_MASK;
+       soc_info->emac_pdata->mdio_max_freq = DM644X_EVM_MDIO_FREQUENCY;
+
        /* Register the fixup for PHY on DaVinci */
        phy_register_fixup_for_uid(LXT971_PHY_ID, LXT971_PHY_MASK,
                                        davinci_phy_fixup);
diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c
new file mode 100644 (file)
index 0000000..e17de63
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * TI DaVinci DM646X EVM board
+ *
+ * Derived from: arch/arm/mach-davinci/board-evm.c
+ * Copyright (C) 2006 Texas Instruments.
+ *
+ * (C) 2007-2008, MontaVista Software, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+/**************************************************************************
+ * Included Files
+ **************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/major.h>
+#include <linux/root_dev.h>
+#include <linux/dma-mapping.h>
+#include <linux/serial.h>
+#include <linux/serial_8250.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/i2c/at24.h>
+#include <linux/i2c/pcf857x.h>
+#include <linux/etherdevice.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/flash.h>
+
+#include <mach/dm646x.h>
+#include <mach/common.h>
+#include <mach/psc.h>
+#include <mach/serial.h>
+#include <mach/i2c.h>
+#include <mach/mmc.h>
+#include <mach/emac.h>
+#include <mach/common.h>
+
+#define DM646X_EVM_PHY_MASK            (0x2)
+#define DM646X_EVM_MDIO_FREQUENCY      (2200000) /* PHY bus frequency */
+
+static struct davinci_uart_config uart_config __initdata = {
+       .enabled_uarts = (1 << 0),
+};
+
+/* LEDS */
+
+static struct gpio_led evm_leds[] = {
+       { .name = "DS1", .active_low = 1, },
+       { .name = "DS2", .active_low = 1, },
+       { .name = "DS3", .active_low = 1, },
+       { .name = "DS4", .active_low = 1, },
+};
+
+static __initconst struct gpio_led_platform_data evm_led_data = {
+       .num_leds = ARRAY_SIZE(evm_leds),
+       .leds     = evm_leds,
+};
+
+static struct platform_device *evm_led_dev;
+
+static int evm_led_setup(struct i2c_client *client, int gpio,
+                       unsigned int ngpio, void *c)
+{
+       struct gpio_led *leds = evm_leds;
+       int status;
+
+       while (ngpio--) {
+               leds->gpio = gpio++;
+               leds++;
+       };
+
+       evm_led_dev = platform_device_alloc("leds-gpio", 0);
+       platform_device_add_data(evm_led_dev, &evm_led_data,
+                               sizeof(evm_led_data));
+
+       evm_led_dev->dev.parent = &client->dev;
+       status = platform_device_add(evm_led_dev);
+       if (status < 0) {
+               platform_device_put(evm_led_dev);
+               evm_led_dev = NULL;
+       }
+       return status;
+}
+
+static int evm_led_teardown(struct i2c_client *client, int gpio,
+                               unsigned ngpio, void *c)
+{
+       if (evm_led_dev) {
+               platform_device_unregister(evm_led_dev);
+               evm_led_dev = NULL;
+       }
+       return 0;
+}
+
+static int evm_sw_gpio[4] = { -EINVAL, -EINVAL, -EINVAL, -EINVAL };
+
+static int evm_sw_setup(struct i2c_client *client, int gpio,
+                       unsigned ngpio, void *c)
+{
+       int status;
+       int i;
+       char label[10];
+
+       for (i = 0; i < 4; ++i) {
+               snprintf(label, 10, "user_sw%d", i);
+               status = gpio_request(gpio, label);
+               if (status)
+                       goto out_free;
+               evm_sw_gpio[i] = gpio++;
+
+               status = gpio_direction_input(evm_sw_gpio[i]);
+               if (status) {
+                       gpio_free(evm_sw_gpio[i]);
+                       evm_sw_gpio[i] = -EINVAL;
+                       goto out_free;
+               }
+
+               status = gpio_export(evm_sw_gpio[i], 0);
+               if (status) {
+                       gpio_free(evm_sw_gpio[i]);
+                       evm_sw_gpio[i] = -EINVAL;
+                       goto out_free;
+               }
+       }
+       return status;
+out_free:
+       for (i = 0; i < 4; ++i) {
+               if (evm_sw_gpio[i] != -EINVAL) {
+                       gpio_free(evm_sw_gpio[i]);
+                       evm_sw_gpio[i] = -EINVAL;
+               }
+       }
+       return status;
+}
+
+static int evm_sw_teardown(struct i2c_client *client, int gpio,
+                       unsigned ngpio, void *c)
+{
+       int i;
+
+       for (i = 0; i < 4; ++i) {
+               if (evm_sw_gpio[i] != -EINVAL) {
+                       gpio_unexport(evm_sw_gpio[i]);
+                       gpio_free(evm_sw_gpio[i]);
+                       evm_sw_gpio[i] = -EINVAL;
+               }
+       }
+       return 0;
+}
+
+static int evm_pcf_setup(struct i2c_client *client, int gpio,
+                       unsigned int ngpio, void *c)
+{
+       int status;
+
+       if (ngpio < 8)
+               return -EINVAL;
+
+       status = evm_sw_setup(client, gpio, 4, c);
+       if (status)
+               return status;
+
+       return evm_led_setup(client, gpio+4, 4, c);
+}
+
+static int evm_pcf_teardown(struct i2c_client *client, int gpio,
+                       unsigned int ngpio, void *c)
+{
+       BUG_ON(ngpio < 8);
+
+       evm_sw_teardown(client, gpio, 4, c);
+       evm_led_teardown(client, gpio+4, 4, c);
+
+       return 0;
+}
+
+static struct pcf857x_platform_data pcf_data = {
+       .gpio_base      = DAVINCI_N_GPIO+1,
+       .setup          = evm_pcf_setup,
+       .teardown       = evm_pcf_teardown,
+};
+
+/* Most of this EEPROM is unused, but U-Boot uses some data:
+ *  - 0x7f00, 6 bytes Ethernet Address
+ *  - ... newer boards may have more
+ */
+
+static struct at24_platform_data eeprom_info = {
+       .byte_len       = (256*1024) / 8,
+       .page_size      = 64,
+       .flags          = AT24_FLAG_ADDR16,
+       .setup          = davinci_get_mac_addr,
+       .context        = (void *)0x7f00,
+};
+
+static struct i2c_board_info __initdata i2c_info[] =  {
+       {
+               I2C_BOARD_INFO("24c256", 0x50),
+               .platform_data  = &eeprom_info,
+       },
+       {
+               I2C_BOARD_INFO("pcf8574a", 0x38),
+               .platform_data  = &pcf_data,
+       },
+};
+
+static struct davinci_i2c_platform_data i2c_pdata = {
+       .bus_freq       = 100 /* kHz */,
+       .bus_delay      = 0 /* usec */,
+};
+
+static void __init evm_init_i2c(void)
+{
+       davinci_init_i2c(&i2c_pdata);
+       i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info));
+}
+
+static void __init davinci_map_io(void)
+{
+       dm646x_init();
+}
+
+static __init void evm_init(void)
+{
+       struct davinci_soc_info *soc_info = &davinci_soc_info;
+
+       evm_init_i2c();
+       davinci_serial_init(&uart_config);
+
+       soc_info->emac_pdata->phy_mask = DM646X_EVM_PHY_MASK;
+       soc_info->emac_pdata->mdio_max_freq = DM646X_EVM_MDIO_FREQUENCY;
+}
+
+static __init void davinci_dm646x_evm_irq_init(void)
+{
+       davinci_irq_init();
+}
+
+MACHINE_START(DAVINCI_DM6467_EVM, "DaVinci DM646x EVM")
+       .phys_io      = IO_PHYS,
+       .io_pg_offst  = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
+       .boot_params  = (0x80000100),
+       .map_io       = davinci_map_io,
+       .init_irq     = davinci_dm646x_evm_irq_init,
+       .timer        = &davinci_timer,
+       .init_machine = evm_init,
+MACHINE_END
+
diff --git a/arch/arm/mach-davinci/board-sffsdr.c b/arch/arm/mach-davinci/board-sffsdr.c
new file mode 100644 (file)
index 0000000..748a8e4
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * Lyrtech SFFSDR board support.
+ *
+ * Copyright (C) 2008 Philip Balister, OpenSDR <philip@opensdr.com>
+ * Copyright (C) 2008 Lyrtech <www.lyrtech.com>
+ *
+ * Based on DV-EVM platform, original copyright follows:
+ *
+ * Copyright (C) 2007 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c/at24.h>
+#include <linux/etherdevice.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/io.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/flash.h>
+
+#include <mach/dm644x.h>
+#include <mach/common.h>
+#include <mach/i2c.h>
+#include <mach/serial.h>
+#include <mach/psc.h>
+#include <mach/mux.h>
+#include <mach/common.h>
+
+#define SFFSDR_PHY_MASK                (0x2)
+#define SFFSDR_MDIO_FREQUENCY  (2200000) /* PHY bus frequency */
+
+#define DAVINCI_ASYNC_EMIF_CONTROL_BASE   0x01e00000
+#define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE  0x02000000
+
+struct mtd_partition davinci_sffsdr_nandflash_partition[] = {
+       /* U-Boot Environment: Block 0
+        * UBL:                Block 1
+        * U-Boot:             Blocks 6-7 (256 kb)
+        * Integrity Kernel:   Blocks 8-31 (3 Mb)
+        * Integrity Data:     Blocks 100-END
+        */
+       {
+               .name           = "Linux Kernel",
+               .offset         = 32 * SZ_128K,
+               .size           = 16 * SZ_128K, /* 2 Mb */
+               .mask_flags     = MTD_WRITEABLE, /* Force read-only */
+       },
+       {
+               .name           = "Linux ROOT",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 256 * SZ_128K, /* 32 Mb */
+               .mask_flags     = 0, /* R/W */
+       },
+};
+
+static struct flash_platform_data davinci_sffsdr_nandflash_data = {
+       .parts          = davinci_sffsdr_nandflash_partition,
+       .nr_parts       = ARRAY_SIZE(davinci_sffsdr_nandflash_partition),
+};
+
+static struct resource davinci_sffsdr_nandflash_resource[] = {
+       {
+               .start          = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE,
+               .end            = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE + SZ_16M - 1,
+               .flags          = IORESOURCE_MEM,
+       }, {
+               .start          = DAVINCI_ASYNC_EMIF_CONTROL_BASE,
+               .end            = DAVINCI_ASYNC_EMIF_CONTROL_BASE + SZ_4K - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device davinci_sffsdr_nandflash_device = {
+       .name           = "davinci_nand", /* Name of driver */
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &davinci_sffsdr_nandflash_data,
+       },
+       .num_resources  = ARRAY_SIZE(davinci_sffsdr_nandflash_resource),
+       .resource       = davinci_sffsdr_nandflash_resource,
+};
+
+static struct emac_platform_data sffsdr_emac_pdata = {
+       .phy_mask       = SFFSDR_PHY_MASK,
+       .mdio_max_freq  = SFFSDR_MDIO_FREQUENCY,
+};
+
+static struct at24_platform_data eeprom_info = {
+       .byte_len       = (64*1024) / 8,
+       .page_size      = 32,
+       .flags          = AT24_FLAG_ADDR16,
+};
+
+static struct i2c_board_info __initdata i2c_info[] =  {
+       {
+               I2C_BOARD_INFO("24lc64", 0x50),
+               .platform_data  = &eeprom_info,
+       },
+       /* Other I2C devices:
+        * MSP430,  addr 0x23 (not used)
+        * PCA9543, addr 0x70 (setup done by U-Boot)
+        * ADS7828, addr 0x48 (ADC for voltage monitoring.)
+        */
+};
+
+static struct davinci_i2c_platform_data i2c_pdata = {
+       .bus_freq       = 20 /* kHz */,
+       .bus_delay      = 100 /* usec */,
+};
+
+static void __init sffsdr_init_i2c(void)
+{
+       davinci_init_i2c(&i2c_pdata);
+       i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info));
+}
+
+static struct platform_device *davinci_sffsdr_devices[] __initdata = {
+       &davinci_sffsdr_nandflash_device,
+};
+
+static struct davinci_uart_config uart_config __initdata = {
+       .enabled_uarts = (1 << 0),
+};
+
+static void __init davinci_sffsdr_map_io(void)
+{
+       dm644x_init();
+}
+
+static __init void davinci_sffsdr_init(void)
+{
+       struct davinci_soc_info *soc_info = &davinci_soc_info;
+
+       platform_add_devices(davinci_sffsdr_devices,
+                            ARRAY_SIZE(davinci_sffsdr_devices));
+       sffsdr_init_i2c();
+       davinci_serial_init(&uart_config);
+       soc_info->emac_pdata->phy_mask = SFFSDR_PHY_MASK;
+       soc_info->emac_pdata->mdio_max_freq = SFFSDR_MDIO_FREQUENCY;
+       setup_usb(0, 0); /* We support only peripheral mode. */
+
+       /* mux VLYNQ pins */
+       davinci_cfg_reg(DM644X_VLYNQEN);
+       davinci_cfg_reg(DM644X_VLYNQWD);
+}
+
+static __init void davinci_sffsdr_irq_init(void)
+{
+       davinci_irq_init();
+}
+
+MACHINE_START(SFFSDR, "Lyrtech SFFSDR")
+       /* Maintainer: Hugo Villeneuve hugo.villeneuve@lyrtech.com */
+       .phys_io      = IO_PHYS,
+       .io_pg_offst  = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
+       .boot_params  = (DAVINCI_DDR_BASE + 0x100),
+       .map_io       = davinci_sffsdr_map_io,
+       .init_irq     = davinci_sffsdr_irq_init,
+       .timer        = &davinci_timer,
+       .init_machine = davinci_sffsdr_init,
+MACHINE_END
index f0baaa15a57e661c2991fe85d883376eb35dd11f..39bf321d70a274a4c0514e7f41619df4e188fad5 100644 (file)
@@ -42,7 +42,8 @@ static void __clk_enable(struct clk *clk)
        if (clk->parent)
                __clk_enable(clk->parent);
        if (clk->usecount++ == 0 && (clk->flags & CLK_PSC))
-               davinci_psc_config(psc_domain(clk), clk->lpsc, 1);
+               davinci_psc_config(psc_domain(clk), clk->psc_ctlr,
+                               clk->lpsc, 1);
 }
 
 static void __clk_disable(struct clk *clk)
@@ -50,7 +51,8 @@ static void __clk_disable(struct clk *clk)
        if (WARN_ON(clk->usecount == 0))
                return;
        if (--clk->usecount == 0 && !(clk->flags & CLK_PLL))
-               davinci_psc_config(psc_domain(clk), clk->lpsc, 0);
+               davinci_psc_config(psc_domain(clk), clk->psc_ctlr,
+                               clk->lpsc, 0);
        if (clk->parent)
                __clk_disable(clk->parent);
 }
@@ -164,11 +166,11 @@ static int __init clk_disable_unused(void)
                        continue;
 
                /* ignore if in Disabled or SwRstDisable states */
-               if (!davinci_psc_is_clk_active(ck->lpsc))
+               if (!davinci_psc_is_clk_active(ck->psc_ctlr, ck->lpsc))
                        continue;
 
                pr_info("Clocks: disable unused %s\n", ck->name);
-               davinci_psc_config(psc_domain(ck), ck->lpsc, 0);
+               davinci_psc_config(psc_domain(ck), ck->psc_ctlr, ck->lpsc, 0);
        }
        spin_unlock_irq(&clockfw_lock);
 
index 35736ec202f82ec7bdb570c13ea2bf931c7aa55e..27233cb4a2fbeeaca1e66a9bff1a1d96f4e36734 100644 (file)
@@ -67,6 +67,7 @@ struct clk {
        u8                      usecount;
        u8                      flags;
        u8                      lpsc;
+       u8                      psc_ctlr;
        struct clk              *parent;
        struct pll_data         *pll_data;
        u32                     div_reg;
@@ -93,4 +94,7 @@ struct davinci_clk {
        }
 
 int davinci_clk_init(struct davinci_clk *clocks);
+
+extern struct platform_device davinci_wdt_device;
+
 #endif
diff --git a/arch/arm/mach-davinci/common.c b/arch/arm/mach-davinci/common.c
new file mode 100644 (file)
index 0000000..61ede19
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Code commons to all DaVinci SoCs.
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * 2009 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/etherdevice.h>
+
+#include <asm/tlb.h>
+#include <asm/mach/map.h>
+
+#include <mach/common.h>
+#include <mach/cputype.h>
+#include <mach/emac.h>
+
+#include "clock.h"
+
+struct davinci_soc_info davinci_soc_info;
+EXPORT_SYMBOL(davinci_soc_info);
+
+void __iomem *davinci_intc_base;
+int davinci_intc_type;
+
+void davinci_get_mac_addr(struct memory_accessor *mem_acc, void *context)
+{
+       char *mac_addr = davinci_soc_info.emac_pdata->mac_addr;
+       off_t offset = (off_t)context;
+
+       /* Read MAC addr from EEPROM */
+       if (mem_acc->read(mem_acc, mac_addr, offset, ETH_ALEN) == ETH_ALEN)
+               pr_info("Read MAC addr from EEPROM: %pM\n", mac_addr);
+}
+
+static struct davinci_id * __init davinci_get_id(u32 jtag_id)
+{
+       int i;
+       struct davinci_id *dip;
+       u8 variant = (jtag_id & 0xf0000000) >> 28;
+       u16 part_no = (jtag_id & 0x0ffff000) >> 12;
+
+       for (i = 0, dip = davinci_soc_info.ids; i < davinci_soc_info.ids_num;
+                       i++, dip++)
+               /* Don't care about the manufacturer right now */
+               if ((dip->part_no == part_no) && (dip->variant == variant))
+                       return dip;
+
+       return NULL;
+}
+
+void __init davinci_common_init(struct davinci_soc_info *soc_info)
+{
+       int ret;
+       struct davinci_id *dip;
+
+       if (!soc_info) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       memcpy(&davinci_soc_info, soc_info, sizeof(struct davinci_soc_info));
+
+       if (davinci_soc_info.io_desc && (davinci_soc_info.io_desc_num > 0))
+               iotable_init(davinci_soc_info.io_desc,
+                               davinci_soc_info.io_desc_num);
+
+       /*
+        * Normally devicemaps_init() would flush caches and tlb after
+        * mdesc->map_io(), but we must also do it here because of the CPU
+        * revision check below.
+        */
+       local_flush_tlb_all();
+       flush_cache_all();
+
+       /*
+        * We want to check CPU revision early for cpu_is_xxxx() macros.
+        * IO space mapping must be initialized before we can do that.
+        */
+       davinci_soc_info.jtag_id = __raw_readl(davinci_soc_info.jtag_id_base);
+
+       dip = davinci_get_id(davinci_soc_info.jtag_id);
+       if (!dip) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       davinci_soc_info.cpu_id = dip->cpu_id;
+       pr_info("DaVinci %s variant 0x%x\n", dip->name, dip->variant);
+
+       if (davinci_soc_info.cpu_clks) {
+               ret = davinci_clk_init(davinci_soc_info.cpu_clks);
+
+               if (ret != 0)
+                       goto err;
+       }
+
+       davinci_intc_base = davinci_soc_info.intc_base;
+       davinci_intc_type = davinci_soc_info.intc_type;
+       return;
+
+err:
+       pr_err("davinci_common_init: SoC Initialization failed\n");
+}
diff --git a/arch/arm/mach-davinci/cp_intc.c b/arch/arm/mach-davinci/cp_intc.c
new file mode 100644 (file)
index 0000000..96c8e97
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * TI Common Platform Interrupt Controller (cp_intc) driver
+ *
+ * Author: Steve Chen <schen@mvista.com>
+ * Copyright (C) 2008-2009, MontaVista Software, Inc. <source@mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <mach/cp_intc.h>
+
+static void __iomem *cp_intc_base;
+
+static inline unsigned int cp_intc_read(unsigned offset)
+{
+       return __raw_readl(cp_intc_base + offset);
+}
+
+static inline void cp_intc_write(unsigned long value, unsigned offset)
+{
+       __raw_writel(value, cp_intc_base + offset);
+}
+
+static void cp_intc_ack_irq(unsigned int irq)
+{
+       cp_intc_write(irq, CP_INTC_SYS_STAT_IDX_CLR);
+}
+
+/* Disable interrupt */
+static void cp_intc_mask_irq(unsigned int irq)
+{
+       /* XXX don't know why we need to disable nIRQ here... */
+       cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_CLR);
+       cp_intc_write(irq, CP_INTC_SYS_ENABLE_IDX_CLR);
+       cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_SET);
+}
+
+/* Enable interrupt */
+static void cp_intc_unmask_irq(unsigned int irq)
+{
+       cp_intc_write(irq, CP_INTC_SYS_ENABLE_IDX_SET);
+}
+
+static int cp_intc_set_irq_type(unsigned int irq, unsigned int flow_type)
+{
+       unsigned reg            = BIT_WORD(irq);
+       unsigned mask           = BIT_MASK(irq);
+       unsigned polarity       = cp_intc_read(CP_INTC_SYS_POLARITY(reg));
+       unsigned type           = cp_intc_read(CP_INTC_SYS_TYPE(reg));
+
+       switch (flow_type) {
+       case IRQ_TYPE_EDGE_RISING:
+               polarity |= mask;
+               type |= mask;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               polarity &= ~mask;
+               type |= mask;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               polarity |= mask;
+               type &= ~mask;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               polarity &= ~mask;
+               type &= ~mask;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       cp_intc_write(polarity, CP_INTC_SYS_POLARITY(reg));
+       cp_intc_write(type, CP_INTC_SYS_TYPE(reg));
+
+       return 0;
+}
+
+static struct irq_chip cp_intc_irq_chip = {
+       .name           = "cp_intc",
+       .ack            = cp_intc_ack_irq,
+       .mask           = cp_intc_mask_irq,
+       .unmask         = cp_intc_unmask_irq,
+       .set_type       = cp_intc_set_irq_type,
+};
+
+void __init cp_intc_init(void __iomem *base, unsigned short num_irq,
+                        u8 *irq_prio)
+{
+       unsigned num_reg        = BITS_TO_LONGS(num_irq);
+       int i;
+
+       cp_intc_base = base;
+
+       cp_intc_write(0, CP_INTC_GLOBAL_ENABLE);
+
+       /* Disable all host interrupts */
+       cp_intc_write(0, CP_INTC_HOST_ENABLE(0));
+
+       /* Disable system interrupts */
+       for (i = 0; i < num_reg; i++)
+               cp_intc_write(~0, CP_INTC_SYS_ENABLE_CLR(i));
+
+       /* Set to normal mode, no nesting, no priority hold */
+       cp_intc_write(0, CP_INTC_CTRL);
+       cp_intc_write(0, CP_INTC_HOST_CTRL);
+
+       /* Clear system interrupt status */
+       for (i = 0; i < num_reg; i++)
+               cp_intc_write(~0, CP_INTC_SYS_STAT_CLR(i));
+
+       /* Enable nIRQ (what about nFIQ?) */
+       cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_SET);
+
+       /*
+        * Priority is determined by host channel: lower channel number has
+        * higher priority i.e. channel 0 has highest priority and channel 31
+        * had the lowest priority.
+        */
+       num_reg = (num_irq + 3) >> 2;   /* 4 channels per register */
+       if (irq_prio) {
+               unsigned j, k;
+               u32 val;
+
+               for (k = i = 0; i < num_reg; i++) {
+                       for (val = j = 0; j < 4; j++, k++) {
+                               val >>= 8;
+                               if (k < num_irq)
+                                       val |= irq_prio[k] << 24;
+                       }
+
+                       cp_intc_write(val, CP_INTC_CHAN_MAP(i));
+               }
+       } else  {
+               /*
+                * Default everything to channel 15 if priority not specified.
+                * Note that channel 0-1 are mapped to nFIQ and channels 2-31
+                * are mapped to nIRQ.
+                */
+               for (i = 0; i < num_reg; i++)
+                       cp_intc_write(0x0f0f0f0f, CP_INTC_CHAN_MAP(i));
+       }
+
+       /* Set up genirq dispatching for cp_intc */
+       for (i = 0; i < num_irq; i++) {
+               set_irq_chip(i, &cp_intc_irq_chip);
+               set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+               set_irq_handler(i, handle_edge_irq);
+       }
+
+       /* Enable global interrupt */
+       cp_intc_write(1, CP_INTC_GLOBAL_ENABLE);
+}
index a31370b93dd287c91b3b70068b6866add80a5cf3..de16f347566a7e21a63e0678f181c8f7c1d974b7 100644 (file)
 #include <mach/irqs.h>
 #include <mach/cputype.h>
 #include <mach/mux.h>
+#include <mach/edma.h>
+#include <mach/mmc.h>
+#include <mach/time.h>
 
 #define DAVINCI_I2C_BASE            0x01C21000
+#define DAVINCI_MMCSD0_BASE         0x01E10000
+#define DM355_MMCSD0_BASE           0x01E11000
+#define DM355_MMCSD1_BASE           0x01E00000
 
 static struct resource i2c_resources[] = {
        {
@@ -54,3 +60,208 @@ void __init davinci_init_i2c(struct davinci_i2c_platform_data *pdata)
        (void) platform_device_register(&davinci_i2c_device);
 }
 
+#if    defined(CONFIG_MMC_DAVINCI) || defined(CONFIG_MMC_DAVINCI_MODULE)
+
+static u64 mmcsd0_dma_mask = DMA_BIT_MASK(32);
+
+static struct resource mmcsd0_resources[] = {
+       {
+               /* different on dm355 */
+               .start = DAVINCI_MMCSD0_BASE,
+               .end   = DAVINCI_MMCSD0_BASE + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       /* IRQs:  MMC/SD, then SDIO */
+       {
+               .start = IRQ_MMCINT,
+               .flags = IORESOURCE_IRQ,
+       }, {
+               /* different on dm355 */
+               .start = IRQ_SDIOINT,
+               .flags = IORESOURCE_IRQ,
+       },
+       /* DMA channels: RX, then TX */
+       {
+               .start = DAVINCI_DMA_MMCRXEVT,
+               .flags = IORESOURCE_DMA,
+       }, {
+               .start = DAVINCI_DMA_MMCTXEVT,
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+static struct platform_device davinci_mmcsd0_device = {
+       .name = "davinci_mmc",
+       .id = 0,
+       .dev = {
+               .dma_mask = &mmcsd0_dma_mask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+       },
+       .num_resources = ARRAY_SIZE(mmcsd0_resources),
+       .resource = mmcsd0_resources,
+};
+
+static u64 mmcsd1_dma_mask = DMA_BIT_MASK(32);
+
+static struct resource mmcsd1_resources[] = {
+       {
+               .start = DM355_MMCSD1_BASE,
+               .end   = DM355_MMCSD1_BASE + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       /* IRQs:  MMC/SD, then SDIO */
+       {
+               .start = IRQ_DM355_MMCINT1,
+               .flags = IORESOURCE_IRQ,
+       }, {
+               .start = IRQ_DM355_SDIOINT1,
+               .flags = IORESOURCE_IRQ,
+       },
+       /* DMA channels: RX, then TX */
+       {
+               .start = 30,    /* rx */
+               .flags = IORESOURCE_DMA,
+       }, {
+               .start = 31,    /* tx */
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+static struct platform_device davinci_mmcsd1_device = {
+       .name = "davinci_mmc",
+       .id = 1,
+       .dev = {
+               .dma_mask = &mmcsd1_dma_mask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+       },
+       .num_resources = ARRAY_SIZE(mmcsd1_resources),
+       .resource = mmcsd1_resources,
+};
+
+
+void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config)
+{
+       struct platform_device  *pdev = NULL;
+
+       if (WARN_ON(cpu_is_davinci_dm646x()))
+               return;
+
+       /* REVISIT: update PINMUX, ARM_IRQMUX, and EDMA_EVTMUX here too;
+        * for example if MMCSD1 is used for SDIO, maybe DAT2 is unused.
+        *
+        * FIXME dm6441 (no MMC/SD), dm357 (one), and dm335 (two) are
+        * not handled right here ...
+        */
+       switch (module) {
+       case 1:
+               if (!cpu_is_davinci_dm355())
+                       break;
+
+               /* REVISIT we may not need all these pins if e.g. this
+                * is a hard-wired SDIO device...
+                */
+               davinci_cfg_reg(DM355_SD1_CMD);
+               davinci_cfg_reg(DM355_SD1_CLK);
+               davinci_cfg_reg(DM355_SD1_DATA0);
+               davinci_cfg_reg(DM355_SD1_DATA1);
+               davinci_cfg_reg(DM355_SD1_DATA2);
+               davinci_cfg_reg(DM355_SD1_DATA3);
+
+               pdev = &davinci_mmcsd1_device;
+               break;
+       case 0:
+               if (cpu_is_davinci_dm355()) {
+                       mmcsd0_resources[0].start = DM355_MMCSD0_BASE;
+                       mmcsd0_resources[0].end = DM355_MMCSD0_BASE + SZ_4K - 1;
+                       mmcsd0_resources[2].start = IRQ_DM355_SDIOINT0;
+
+                       /* expose all 6 MMC0 signals:  CLK, CMD, DATA[0..3] */
+                       davinci_cfg_reg(DM355_MMCSD0);
+
+                       /* enable RX EDMA */
+                       davinci_cfg_reg(DM355_EVT26_MMC0_RX);
+               }
+
+               else if (cpu_is_davinci_dm644x()) {
+                       /* REVISIT: should this be in board-init code? */
+                       void __iomem *base =
+                               IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE);
+
+                       /* Power-on 3.3V IO cells */
+                       __raw_writel(0, base + DM64XX_VDD3P3V_PWDN);
+                       /*Set up the pull regiter for MMC */
+                       davinci_cfg_reg(DM644X_MSTK);
+               }
+
+               pdev = &davinci_mmcsd0_device;
+               break;
+       }
+
+       if (WARN_ON(!pdev))
+               return;
+
+       pdev->dev.platform_data = config;
+       platform_device_register(pdev);
+}
+
+#else
+
+void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config)
+{
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+static struct resource wdt_resources[] = {
+       {
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+struct platform_device davinci_wdt_device = {
+       .name           = "watchdog",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(wdt_resources),
+       .resource       = wdt_resources,
+};
+
+static void davinci_init_wdt(void)
+{
+       struct davinci_soc_info *soc_info = &davinci_soc_info;
+
+       wdt_resources[0].start = (resource_size_t)soc_info->wdt_base;
+       wdt_resources[0].end = (resource_size_t)soc_info->wdt_base + SZ_1K - 1;
+
+       platform_device_register(&davinci_wdt_device);
+}
+
+/*-------------------------------------------------------------------------*/
+
+struct davinci_timer_instance davinci_timer_instance[2] = {
+       {
+               .base           = IO_ADDRESS(DAVINCI_TIMER0_BASE),
+               .bottom_irq     = IRQ_TINT0_TINT12,
+               .top_irq        = IRQ_TINT0_TINT34,
+       },
+       {
+               .base           = IO_ADDRESS(DAVINCI_TIMER1_BASE),
+               .bottom_irq     = IRQ_TINT1_TINT12,
+               .top_irq        = IRQ_TINT1_TINT34,
+       },
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init davinci_init_devices(void)
+{
+       /* please keep these calls, and their implementations above,
+        * in alphabetical order so they're easier to sort through.
+        */
+       davinci_init_wdt();
+
+       return 0;
+}
+arch_initcall(davinci_init_devices);
+
diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c
new file mode 100644 (file)
index 0000000..baaaf32
--- /dev/null
@@ -0,0 +1,730 @@
+/*
+ * TI DaVinci DM355 chip specific setup
+ *
+ * Author: Kevin Hilman, Deep Root Systems, LLC
+ *
+ * 2007 (c) Deep Root Systems, LLC. 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/clk.h>
+#include <linux/serial_8250.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/gpio.h>
+
+#include <linux/spi/spi.h>
+
+#include <asm/mach/map.h>
+
+#include <mach/dm355.h>
+#include <mach/clock.h>
+#include <mach/cputype.h>
+#include <mach/edma.h>
+#include <mach/psc.h>
+#include <mach/mux.h>
+#include <mach/irqs.h>
+#include <mach/time.h>
+#include <mach/serial.h>
+#include <mach/common.h>
+
+#include "clock.h"
+#include "mux.h"
+
+#define DM355_UART2_BASE       (IO_PHYS + 0x206000)
+
+/*
+ * Device specific clocks
+ */
+#define DM355_REF_FREQ         24000000        /* 24 or 36 MHz */
+
+static struct pll_data pll1_data = {
+       .num       = 1,
+       .phys_base = DAVINCI_PLL1_BASE,
+       .flags     = PLL_HAS_PREDIV | PLL_HAS_POSTDIV,
+};
+
+static struct pll_data pll2_data = {
+       .num       = 2,
+       .phys_base = DAVINCI_PLL2_BASE,
+       .flags     = PLL_HAS_PREDIV,
+};
+
+static struct clk ref_clk = {
+       .name = "ref_clk",
+       /* FIXME -- crystal rate is board-specific */
+       .rate = DM355_REF_FREQ,
+};
+
+static struct clk pll1_clk = {
+       .name = "pll1",
+       .parent = &ref_clk,
+       .flags = CLK_PLL,
+       .pll_data = &pll1_data,
+};
+
+static struct clk pll1_aux_clk = {
+       .name = "pll1_aux_clk",
+       .parent = &pll1_clk,
+       .flags = CLK_PLL | PRE_PLL,
+};
+
+static struct clk pll1_sysclk1 = {
+       .name = "pll1_sysclk1",
+       .parent = &pll1_clk,
+       .flags = CLK_PLL,
+       .div_reg = PLLDIV1,
+};
+
+static struct clk pll1_sysclk2 = {
+       .name = "pll1_sysclk2",
+       .parent = &pll1_clk,
+       .flags = CLK_PLL,
+       .div_reg = PLLDIV2,
+};
+
+static struct clk pll1_sysclk3 = {
+       .name = "pll1_sysclk3",
+       .parent = &pll1_clk,
+       .flags = CLK_PLL,
+       .div_reg = PLLDIV3,
+};
+
+static struct clk pll1_sysclk4 = {
+       .name = "pll1_sysclk4",
+       .parent = &pll1_clk,
+       .flags = CLK_PLL,
+       .div_reg = PLLDIV4,
+};
+
+static struct clk pll1_sysclkbp = {
+       .name = "pll1_sysclkbp",
+       .parent = &pll1_clk,
+       .flags = CLK_PLL | PRE_PLL,
+       .div_reg = BPDIV
+};
+
+static struct clk vpss_dac_clk = {
+       .name = "vpss_dac",
+       .parent = &pll1_sysclk3,
+       .lpsc = DM355_LPSC_VPSS_DAC,
+};
+
+static struct clk vpss_master_clk = {
+       .name = "vpss_master",
+       .parent = &pll1_sysclk4,
+       .lpsc = DAVINCI_LPSC_VPSSMSTR,
+       .flags = CLK_PSC,
+};
+
+static struct clk vpss_slave_clk = {
+       .name = "vpss_slave",
+       .parent = &pll1_sysclk4,
+       .lpsc = DAVINCI_LPSC_VPSSSLV,
+};
+
+
+static struct clk clkout1_clk = {
+       .name = "clkout1",
+       .parent = &pll1_aux_clk,
+       /* NOTE:  clkout1 can be externally gated by muxing GPIO-18 */
+};
+
+static struct clk clkout2_clk = {
+       .name = "clkout2",
+       .parent = &pll1_sysclkbp,
+};
+
+static struct clk pll2_clk = {
+       .name = "pll2",
+       .parent = &ref_clk,
+       .flags = CLK_PLL,
+       .pll_data = &pll2_data,
+};
+
+static struct clk pll2_sysclk1 = {
+       .name = "pll2_sysclk1",
+       .parent = &pll2_clk,
+       .flags = CLK_PLL,
+       .div_reg = PLLDIV1,
+};
+
+static struct clk pll2_sysclkbp = {
+       .name = "pll2_sysclkbp",
+       .parent = &pll2_clk,
+       .flags = CLK_PLL | PRE_PLL,
+       .div_reg = BPDIV
+};
+
+static struct clk clkout3_clk = {
+       .name = "clkout3",
+       .parent = &pll2_sysclkbp,
+       /* NOTE:  clkout3 can be externally gated by muxing GPIO-16 */
+};
+
+static struct clk arm_clk = {
+       .name = "arm_clk",
+       .parent = &pll1_sysclk1,
+       .lpsc = DAVINCI_LPSC_ARM,
+       .flags = ALWAYS_ENABLED,
+};
+
+/*
+ * NOT LISTED below, and not touched by Linux
+ *   - in SyncReset state by default
+ *     .lpsc = DAVINCI_LPSC_TPCC,
+ *     .lpsc = DAVINCI_LPSC_TPTC0,
+ *     .lpsc = DAVINCI_LPSC_TPTC1,
+ *     .lpsc = DAVINCI_LPSC_DDR_EMIF, .parent = &sysclk2_clk,
+ *     .lpsc = DAVINCI_LPSC_MEMSTICK,
+ *   - in Enabled state by default
+ *     .lpsc = DAVINCI_LPSC_SYSTEM_SUBSYS,
+ *     .lpsc = DAVINCI_LPSC_SCR2,      // "bus"
+ *     .lpsc = DAVINCI_LPSC_SCR3,      // "bus"
+ *     .lpsc = DAVINCI_LPSC_SCR4,      // "bus"
+ *     .lpsc = DAVINCI_LPSC_CROSSBAR,  // "emulation"
+ *     .lpsc = DAVINCI_LPSC_CFG27,     // "test"
+ *     .lpsc = DAVINCI_LPSC_CFG3,      // "test"
+ *     .lpsc = DAVINCI_LPSC_CFG5,      // "test"
+ */
+
+static struct clk mjcp_clk = {
+       .name = "mjcp",
+       .parent = &pll1_sysclk1,
+       .lpsc = DAVINCI_LPSC_IMCOP,
+};
+
+static struct clk uart0_clk = {
+       .name = "uart0",
+       .parent = &pll1_aux_clk,
+       .lpsc = DAVINCI_LPSC_UART0,
+};
+
+static struct clk uart1_clk = {
+       .name = "uart1",
+       .parent = &pll1_aux_clk,
+       .lpsc = DAVINCI_LPSC_UART1,
+};
+
+static struct clk uart2_clk = {
+       .name = "uart2",
+       .parent = &pll1_sysclk2,
+       .lpsc = DAVINCI_LPSC_UART2,
+};
+
+static struct clk i2c_clk = {
+       .name = "i2c",
+       .parent = &pll1_aux_clk,
+       .lpsc = DAVINCI_LPSC_I2C,
+};
+
+static struct clk asp0_clk = {
+       .name = "asp0",
+       .parent = &pll1_sysclk2,
+       .lpsc = DAVINCI_LPSC_McBSP,
+};
+
+static struct clk asp1_clk = {
+       .name = "asp1",
+       .parent = &pll1_sysclk2,
+       .lpsc = DM355_LPSC_McBSP1,
+};
+
+static struct clk mmcsd0_clk = {
+       .name = "mmcsd0",
+       .parent = &pll1_sysclk2,
+       .lpsc = DAVINCI_LPSC_MMC_SD,
+};
+
+static struct clk mmcsd1_clk = {
+       .name = "mmcsd1",
+       .parent = &pll1_sysclk2,
+       .lpsc = DM355_LPSC_MMC_SD1,
+};
+
+static struct clk spi0_clk = {
+       .name = "spi0",
+       .parent = &pll1_sysclk2,
+       .lpsc = DAVINCI_LPSC_SPI,
+};
+
+static struct clk spi1_clk = {
+       .name = "spi1",
+       .parent = &pll1_sysclk2,
+       .lpsc = DM355_LPSC_SPI1,
+};
+
+static struct clk spi2_clk = {
+       .name = "spi2",
+       .parent = &pll1_sysclk2,
+       .lpsc = DM355_LPSC_SPI2,
+};
+
+static struct clk gpio_clk = {
+       .name = "gpio",
+       .parent = &pll1_sysclk2,
+       .lpsc = DAVINCI_LPSC_GPIO,
+};
+
+static struct clk aemif_clk = {
+       .name = "aemif",
+       .parent = &pll1_sysclk2,
+       .lpsc = DAVINCI_LPSC_AEMIF,
+};
+
+static struct clk pwm0_clk = {
+       .name = "pwm0",
+       .parent = &pll1_aux_clk,
+       .lpsc = DAVINCI_LPSC_PWM0,
+};
+
+static struct clk pwm1_clk = {
+       .name = "pwm1",
+       .parent = &pll1_aux_clk,
+       .lpsc = DAVINCI_LPSC_PWM1,
+};
+
+static struct clk pwm2_clk = {
+       .name = "pwm2",
+       .parent = &pll1_aux_clk,
+       .lpsc = DAVINCI_LPSC_PWM2,
+};
+
+static struct clk pwm3_clk = {
+       .name = "pwm3",
+       .parent = &pll1_aux_clk,
+       .lpsc = DM355_LPSC_PWM3,
+};
+
+static struct clk timer0_clk = {
+       .name = "timer0",
+       .parent = &pll1_aux_clk,
+       .lpsc = DAVINCI_LPSC_TIMER0,
+};
+
+static struct clk timer1_clk = {
+       .name = "timer1",
+       .parent = &pll1_aux_clk,
+       .lpsc = DAVINCI_LPSC_TIMER1,
+};
+
+static struct clk timer2_clk = {
+       .name = "timer2",
+       .parent = &pll1_aux_clk,
+       .lpsc = DAVINCI_LPSC_TIMER2,
+       .usecount = 1,              /* REVISIT: why cant' this be disabled? */
+};
+
+static struct clk timer3_clk = {
+       .name = "timer3",
+       .parent = &pll1_aux_clk,
+       .lpsc = DM355_LPSC_TIMER3,
+};
+
+static struct clk rto_clk = {
+       .name = "rto",
+       .parent = &pll1_aux_clk,
+       .lpsc = DM355_LPSC_RTO,
+};
+
+static struct clk usb_clk = {
+       .name = "usb",
+       .parent = &pll1_sysclk2,
+       .lpsc = DAVINCI_LPSC_USB,
+};
+
+static struct davinci_clk dm355_clks[] = {
+       CLK(NULL, "ref", &ref_clk),
+       CLK(NULL, "pll1", &pll1_clk),
+       CLK(NULL, "pll1_sysclk1", &pll1_sysclk1),
+       CLK(NULL, "pll1_sysclk2", &pll1_sysclk2),
+       CLK(NULL, "pll1_sysclk3", &pll1_sysclk3),
+       CLK(NULL, "pll1_sysclk4", &pll1_sysclk4),
+       CLK(NULL, "pll1_aux", &pll1_aux_clk),
+       CLK(NULL, "pll1_sysclkbp", &pll1_sysclkbp),
+       CLK(NULL, "vpss_dac", &vpss_dac_clk),
+       CLK(NULL, "vpss_master", &vpss_master_clk),
+       CLK(NULL, "vpss_slave", &vpss_slave_clk),
+       CLK(NULL, "clkout1", &clkout1_clk),
+       CLK(NULL, "clkout2", &clkout2_clk),
+       CLK(NULL, "pll2", &pll2_clk),
+       CLK(NULL, "pll2_sysclk1", &pll2_sysclk1),
+       CLK(NULL, "pll2_sysclkbp", &pll2_sysclkbp),
+       CLK(NULL, "clkout3", &clkout3_clk),
+       CLK(NULL, "arm", &arm_clk),
+       CLK(NULL, "mjcp", &mjcp_clk),
+       CLK(NULL, "uart0", &uart0_clk),
+       CLK(NULL, "uart1", &uart1_clk),
+       CLK(NULL, "uart2", &uart2_clk),
+       CLK("i2c_davinci.1", NULL, &i2c_clk),
+       CLK("soc-audio.0", NULL, &asp0_clk),
+       CLK("soc-audio.1", NULL, &asp1_clk),
+       CLK("davinci_mmc.0", NULL, &mmcsd0_clk),
+       CLK("davinci_mmc.1", NULL, &mmcsd1_clk),
+       CLK(NULL, "spi0", &spi0_clk),
+       CLK(NULL, "spi1", &spi1_clk),
+       CLK(NULL, "spi2", &spi2_clk),
+       CLK(NULL, "gpio", &gpio_clk),
+       CLK(NULL, "aemif", &aemif_clk),
+       CLK(NULL, "pwm0", &pwm0_clk),
+       CLK(NULL, "pwm1", &pwm1_clk),
+       CLK(NULL, "pwm2", &pwm2_clk),
+       CLK(NULL, "pwm3", &pwm3_clk),
+       CLK(NULL, "timer0", &timer0_clk),
+       CLK(NULL, "timer1", &timer1_clk),
+       CLK("watchdog", NULL, &timer2_clk),
+       CLK(NULL, "timer3", &timer3_clk),
+       CLK(NULL, "rto", &rto_clk),
+       CLK(NULL, "usb", &usb_clk),
+       CLK(NULL, NULL, NULL),
+};
+
+/*----------------------------------------------------------------------*/
+
+static u64 dm355_spi0_dma_mask = DMA_BIT_MASK(32);
+
+static struct resource dm355_spi0_resources[] = {
+       {
+               .start = 0x01c66000,
+               .end   = 0x01c667ff,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_DM355_SPINT0_1,
+               .flags = IORESOURCE_IRQ,
+       },
+       /* Not yet used, so not included:
+        * IORESOURCE_IRQ:
+        *  - IRQ_DM355_SPINT0_0
+        * IORESOURCE_DMA:
+        *  - DAVINCI_DMA_SPI_SPIX
+        *  - DAVINCI_DMA_SPI_SPIR
+        */
+};
+
+static struct platform_device dm355_spi0_device = {
+       .name = "spi_davinci",
+       .id = 0,
+       .dev = {
+               .dma_mask = &dm355_spi0_dma_mask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+       },
+       .num_resources = ARRAY_SIZE(dm355_spi0_resources),
+       .resource = dm355_spi0_resources,
+};
+
+void __init dm355_init_spi0(unsigned chipselect_mask,
+               struct spi_board_info *info, unsigned len)
+{
+       /* for now, assume we need MISO */
+       davinci_cfg_reg(DM355_SPI0_SDI);
+
+       /* not all slaves will be wired up */
+       if (chipselect_mask & BIT(0))
+               davinci_cfg_reg(DM355_SPI0_SDENA0);
+       if (chipselect_mask & BIT(1))
+               davinci_cfg_reg(DM355_SPI0_SDENA1);
+
+       spi_register_board_info(info, len);
+
+       platform_device_register(&dm355_spi0_device);
+}
+
+/*----------------------------------------------------------------------*/
+
+#define PINMUX0                0x00
+#define PINMUX1                0x04
+#define PINMUX2                0x08
+#define PINMUX3                0x0c
+#define PINMUX4                0x10
+#define INTMUX         0x18
+#define EVTMUX         0x1c
+
+/*
+ * Device specific mux setup
+ *
+ *     soc     description     mux  mode   mode  mux    dbg
+ *                             reg  offset mask  mode
+ */
+static const struct mux_config dm355_pins[] = {
+#ifdef CONFIG_DAVINCI_MUX
+MUX_CFG(DM355, MMCSD0,         4,   2,     1,    0,     false)
+
+MUX_CFG(DM355, SD1_CLK,        3,   6,     1,    1,     false)
+MUX_CFG(DM355, SD1_CMD,        3,   7,     1,    1,     false)
+MUX_CFG(DM355, SD1_DATA3,      3,   8,     3,    1,     false)
+MUX_CFG(DM355, SD1_DATA2,      3,   10,    3,    1,     false)
+MUX_CFG(DM355, SD1_DATA1,      3,   12,    3,    1,     false)
+MUX_CFG(DM355, SD1_DATA0,      3,   14,    3,    1,     false)
+
+MUX_CFG(DM355, I2C_SDA,        3,   19,    1,    1,     false)
+MUX_CFG(DM355, I2C_SCL,        3,   20,    1,    1,     false)
+
+MUX_CFG(DM355, MCBSP0_BDX,     3,   0,     1,    1,     false)
+MUX_CFG(DM355, MCBSP0_X,       3,   1,     1,    1,     false)
+MUX_CFG(DM355, MCBSP0_BFSX,    3,   2,     1,    1,     false)
+MUX_CFG(DM355, MCBSP0_BDR,     3,   3,     1,    1,     false)
+MUX_CFG(DM355, MCBSP0_R,       3,   4,     1,    1,     false)
+MUX_CFG(DM355, MCBSP0_BFSR,    3,   5,     1,    1,     false)
+
+MUX_CFG(DM355, SPI0_SDI,       4,   1,     1,    0,     false)
+MUX_CFG(DM355, SPI0_SDENA0,    4,   0,     1,    0,     false)
+MUX_CFG(DM355, SPI0_SDENA1,    3,   28,    1,    1,     false)
+
+INT_CFG(DM355,  INT_EDMA_CC,         2,    1,    1,     false)
+INT_CFG(DM355,  INT_EDMA_TC0_ERR,     3,    1,    1,     false)
+INT_CFG(DM355,  INT_EDMA_TC1_ERR,     4,    1,    1,     false)
+
+EVT_CFG(DM355,  EVT8_ASP1_TX,        0,    1,    0,     false)
+EVT_CFG(DM355,  EVT9_ASP1_RX,        1,    1,    0,     false)
+EVT_CFG(DM355,  EVT26_MMC0_RX,       2,    1,    0,     false)
+#endif
+};
+
+static u8 dm355_default_priorities[DAVINCI_N_AINTC_IRQ] = {
+       [IRQ_DM355_CCDC_VDINT0]         = 2,
+       [IRQ_DM355_CCDC_VDINT1]         = 6,
+       [IRQ_DM355_CCDC_VDINT2]         = 6,
+       [IRQ_DM355_IPIPE_HST]           = 6,
+       [IRQ_DM355_H3AINT]              = 6,
+       [IRQ_DM355_IPIPE_SDR]           = 6,
+       [IRQ_DM355_IPIPEIFINT]          = 6,
+       [IRQ_DM355_OSDINT]              = 7,
+       [IRQ_DM355_VENCINT]             = 6,
+       [IRQ_ASQINT]                    = 6,
+       [IRQ_IMXINT]                    = 6,
+       [IRQ_USBINT]                    = 4,
+       [IRQ_DM355_RTOINT]              = 4,
+       [IRQ_DM355_UARTINT2]            = 7,
+       [IRQ_DM355_TINT6]               = 7,
+       [IRQ_CCINT0]                    = 5,    /* dma */
+       [IRQ_CCERRINT]                  = 5,    /* dma */
+       [IRQ_TCERRINT0]                 = 5,    /* dma */
+       [IRQ_TCERRINT]                  = 5,    /* dma */
+       [IRQ_DM355_SPINT2_1]            = 7,
+       [IRQ_DM355_TINT7]               = 4,
+       [IRQ_DM355_SDIOINT0]            = 7,
+       [IRQ_MBXINT]                    = 7,
+       [IRQ_MBRINT]                    = 7,
+       [IRQ_MMCINT]                    = 7,
+       [IRQ_DM355_MMCINT1]             = 7,
+       [IRQ_DM355_PWMINT3]             = 7,
+       [IRQ_DDRINT]                    = 7,
+       [IRQ_AEMIFINT]                  = 7,
+       [IRQ_DM355_SDIOINT1]            = 4,
+       [IRQ_TINT0_TINT12]              = 2,    /* clockevent */
+       [IRQ_TINT0_TINT34]              = 2,    /* clocksource */
+       [IRQ_TINT1_TINT12]              = 7,    /* DSP timer */
+       [IRQ_TINT1_TINT34]              = 7,    /* system tick */
+       [IRQ_PWMINT0]                   = 7,
+       [IRQ_PWMINT1]                   = 7,
+       [IRQ_PWMINT2]                   = 7,
+       [IRQ_I2C]                       = 3,
+       [IRQ_UARTINT0]                  = 3,
+       [IRQ_UARTINT1]                  = 3,
+       [IRQ_DM355_SPINT0_0]            = 3,
+       [IRQ_DM355_SPINT0_1]            = 3,
+       [IRQ_DM355_GPIO0]               = 3,
+       [IRQ_DM355_GPIO1]               = 7,
+       [IRQ_DM355_GPIO2]               = 4,
+       [IRQ_DM355_GPIO3]               = 4,
+       [IRQ_DM355_GPIO4]               = 7,
+       [IRQ_DM355_GPIO5]               = 7,
+       [IRQ_DM355_GPIO6]               = 7,
+       [IRQ_DM355_GPIO7]               = 7,
+       [IRQ_DM355_GPIO8]               = 7,
+       [IRQ_DM355_GPIO9]               = 7,
+       [IRQ_DM355_GPIOBNK0]            = 7,
+       [IRQ_DM355_GPIOBNK1]            = 7,
+       [IRQ_DM355_GPIOBNK2]            = 7,
+       [IRQ_DM355_GPIOBNK3]            = 7,
+       [IRQ_DM355_GPIOBNK4]            = 7,
+       [IRQ_DM355_GPIOBNK5]            = 7,
+       [IRQ_DM355_GPIOBNK6]            = 7,
+       [IRQ_COMMTX]                    = 7,
+       [IRQ_COMMRX]                    = 7,
+       [IRQ_EMUINT]                    = 7,
+};
+
+/*----------------------------------------------------------------------*/
+
+static const s8 dma_chan_dm355_no_event[] = {
+       12, 13, 24, 56, 57,
+       58, 59, 60, 61, 62,
+       63,
+       -1
+};
+
+static struct edma_soc_info dm355_edma_info = {
+       .n_channel      = 64,
+       .n_region       = 4,
+       .n_slot         = 128,
+       .n_tc           = 2,
+       .noevent        = dma_chan_dm355_no_event,
+};
+
+static struct resource edma_resources[] = {
+       {
+               .name   = "edma_cc",
+               .start  = 0x01c00000,
+               .end    = 0x01c00000 + SZ_64K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .name   = "edma_tc0",
+               .start  = 0x01c10000,
+               .end    = 0x01c10000 + SZ_1K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .name   = "edma_tc1",
+               .start  = 0x01c10400,
+               .end    = 0x01c10400 + SZ_1K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = IRQ_CCINT0,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .start  = IRQ_CCERRINT,
+               .flags  = IORESOURCE_IRQ,
+       },
+       /* not using (or muxing) TC*_ERR */
+};
+
+static struct platform_device dm355_edma_device = {
+       .name                   = "edma",
+       .id                     = -1,
+       .dev.platform_data      = &dm355_edma_info,
+       .num_resources          = ARRAY_SIZE(edma_resources),
+       .resource               = edma_resources,
+};
+
+/*----------------------------------------------------------------------*/
+
+static struct map_desc dm355_io_desc[] = {
+       {
+               .virtual        = IO_VIRT,
+               .pfn            = __phys_to_pfn(IO_PHYS),
+               .length         = IO_SIZE,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = SRAM_VIRT,
+               .pfn            = __phys_to_pfn(0x00010000),
+               .length         = SZ_32K,
+               /* MT_MEMORY_NONCACHED requires supersection alignment */
+               .type           = MT_DEVICE,
+       },
+};
+
+/* Contents of JTAG ID register used to identify exact cpu type */
+static struct davinci_id dm355_ids[] = {
+       {
+               .variant        = 0x0,
+               .part_no        = 0xb73b,
+               .manufacturer   = 0x00f,
+               .cpu_id         = DAVINCI_CPU_ID_DM355,
+               .name           = "dm355",
+       },
+};
+
+static void __iomem *dm355_psc_bases[] = {
+       IO_ADDRESS(DAVINCI_PWR_SLEEP_CNTRL_BASE),
+};
+
+/*
+ * T0_BOT: Timer 0, bottom:  clockevent source for hrtimers
+ * T0_TOP: Timer 0, top   :  clocksource for generic timekeeping
+ * T1_BOT: Timer 1, bottom:  (used by DSP in TI DSPLink code)
+ * T1_TOP: Timer 1, top   :  <unused>
+ */
+struct davinci_timer_info dm355_timer_info = {
+       .timers         = davinci_timer_instance,
+       .clockevent_id  = T0_BOT,
+       .clocksource_id = T0_TOP,
+};
+
+static struct plat_serial8250_port dm355_serial_platform_data[] = {
+       {
+               .mapbase        = DAVINCI_UART0_BASE,
+               .irq            = IRQ_UARTINT0,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+                                 UPF_IOREMAP,
+               .iotype         = UPIO_MEM,
+               .regshift       = 2,
+       },
+       {
+               .mapbase        = DAVINCI_UART1_BASE,
+               .irq            = IRQ_UARTINT1,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+                                 UPF_IOREMAP,
+               .iotype         = UPIO_MEM,
+               .regshift       = 2,
+       },
+       {
+               .mapbase        = DM355_UART2_BASE,
+               .irq            = IRQ_DM355_UARTINT2,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+                                 UPF_IOREMAP,
+               .iotype         = UPIO_MEM,
+               .regshift       = 2,
+       },
+       {
+               .flags          = 0
+       },
+};
+
+static struct platform_device dm355_serial_device = {
+       .name                   = "serial8250",
+       .id                     = PLAT8250_DEV_PLATFORM,
+       .dev                    = {
+               .platform_data  = dm355_serial_platform_data,
+       },
+};
+
+static struct davinci_soc_info davinci_soc_info_dm355 = {
+       .io_desc                = dm355_io_desc,
+       .io_desc_num            = ARRAY_SIZE(dm355_io_desc),
+       .jtag_id_base           = IO_ADDRESS(0x01c40028),
+       .ids                    = dm355_ids,
+       .ids_num                = ARRAY_SIZE(dm355_ids),
+       .cpu_clks               = dm355_clks,
+       .psc_bases              = dm355_psc_bases,
+       .psc_bases_num          = ARRAY_SIZE(dm355_psc_bases),
+       .pinmux_base            = IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE),
+       .pinmux_pins            = dm355_pins,
+       .pinmux_pins_num        = ARRAY_SIZE(dm355_pins),
+       .intc_base              = IO_ADDRESS(DAVINCI_ARM_INTC_BASE),
+       .intc_type              = DAVINCI_INTC_TYPE_AINTC,
+       .intc_irq_prios         = dm355_default_priorities,
+       .intc_irq_num           = DAVINCI_N_AINTC_IRQ,
+       .timer_info             = &dm355_timer_info,
+       .wdt_base               = IO_ADDRESS(DAVINCI_WDOG_BASE),
+       .gpio_base              = IO_ADDRESS(DAVINCI_GPIO_BASE),
+       .gpio_num               = 104,
+       .gpio_irq               = IRQ_DM355_GPIOBNK0,
+       .serial_dev             = &dm355_serial_device,
+       .sram_dma               = 0x00010000,
+       .sram_len               = SZ_32K,
+};
+
+void __init dm355_init(void)
+{
+       davinci_common_init(&davinci_soc_info_dm355);
+}
+
+static int __init dm355_init_devices(void)
+{
+       if (!cpu_is_davinci_dm355())
+               return 0;
+
+       davinci_cfg_reg(DM355_INT_EDMA_CC);
+       platform_device_register(&dm355_edma_device);
+       return 0;
+}
+postcore_initcall(dm355_init_devices);
index d428ef192eac8ff66e160f8d2378e9c652fbad53..fb5449b3c97bdc777a5dfeb7a5cc955a2ae8b491 100644 (file)
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/clk.h>
+#include <linux/serial_8250.h>
 #include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <asm/mach/map.h>
 
 #include <mach/dm644x.h>
 #include <mach/clock.h>
@@ -20,6 +24,9 @@
 #include <mach/irqs.h>
 #include <mach/psc.h>
 #include <mach/mux.h>
+#include <mach/time.h>
+#include <mach/serial.h>
+#include <mach/common.h>
 
 #include "clock.h"
 #include "mux.h"
@@ -312,7 +319,14 @@ struct davinci_clk dm644x_clks[] = {
        CLK(NULL, NULL, NULL),
 };
 
-#if defined(CONFIG_TI_DAVINCI_EMAC) || defined(CONFIG_TI_DAVINCI_EMAC_MODULE)
+static struct emac_platform_data dm644x_emac_pdata = {
+       .ctrl_reg_offset        = DM644X_EMAC_CNTRL_OFFSET,
+       .ctrl_mod_reg_offset    = DM644X_EMAC_CNTRL_MOD_OFFSET,
+       .ctrl_ram_offset        = DM644X_EMAC_CNTRL_RAM_OFFSET,
+       .mdio_reg_offset        = DM644X_EMAC_MDIO_OFFSET,
+       .ctrl_ram_size          = DM644X_EMAC_CNTRL_RAM_SIZE,
+       .version                = EMAC_VERSION_1,
+};
 
 static struct resource dm644x_emac_resources[] = {
        {
@@ -330,11 +344,15 @@ static struct resource dm644x_emac_resources[] = {
 static struct platform_device dm644x_emac_device = {
        .name           = "davinci_emac",
        .id             = 1,
+       .dev = {
+              .platform_data   = &dm644x_emac_pdata,
+       },
        .num_resources  = ARRAY_SIZE(dm644x_emac_resources),
        .resource       = dm644x_emac_resources,
 };
 
-#endif
+#define PINMUX0                0x00
+#define PINMUX1                0x04
 
 /*
  * Device specific mux setup
@@ -343,6 +361,7 @@ static struct platform_device dm644x_emac_device = {
  *                             reg  offset mask  mode
  */
 static const struct mux_config dm644x_pins[] = {
+#ifdef CONFIG_DAVINCI_MUX
 MUX_CFG(DM644X, HDIREN,                0,   16,    1,    1,     true)
 MUX_CFG(DM644X, ATAEN,         0,   17,    1,    1,     true)
 MUX_CFG(DM644X, ATAEN_DISABLE, 0,   17,    1,    0,     true)
@@ -383,8 +402,76 @@ MUX_CFG(DM644X, RGB666,            0,   22,    1,    1,     true)
 
 MUX_CFG(DM644X, LOEEN,         0,   24,    1,    1,     true)
 MUX_CFG(DM644X, LFLDEN,                0,   25,    1,    1,     false)
+#endif
 };
 
+/* FIQ are pri 0-1; otherwise 2-7, with 7 lowest priority */
+static u8 dm644x_default_priorities[DAVINCI_N_AINTC_IRQ] = {
+       [IRQ_VDINT0]            = 2,
+       [IRQ_VDINT1]            = 6,
+       [IRQ_VDINT2]            = 6,
+       [IRQ_HISTINT]           = 6,
+       [IRQ_H3AINT]            = 6,
+       [IRQ_PRVUINT]           = 6,
+       [IRQ_RSZINT]            = 6,
+       [7]                     = 7,
+       [IRQ_VENCINT]           = 6,
+       [IRQ_ASQINT]            = 6,
+       [IRQ_IMXINT]            = 6,
+       [IRQ_VLCDINT]           = 6,
+       [IRQ_USBINT]            = 4,
+       [IRQ_EMACINT]           = 4,
+       [14]                    = 7,
+       [15]                    = 7,
+       [IRQ_CCINT0]            = 5,    /* dma */
+       [IRQ_CCERRINT]          = 5,    /* dma */
+       [IRQ_TCERRINT0]         = 5,    /* dma */
+       [IRQ_TCERRINT]          = 5,    /* dma */
+       [IRQ_PSCIN]             = 7,
+       [21]                    = 7,
+       [IRQ_IDE]               = 4,
+       [23]                    = 7,
+       [IRQ_MBXINT]            = 7,
+       [IRQ_MBRINT]            = 7,
+       [IRQ_MMCINT]            = 7,
+       [IRQ_SDIOINT]           = 7,
+       [28]                    = 7,
+       [IRQ_DDRINT]            = 7,
+       [IRQ_AEMIFINT]          = 7,
+       [IRQ_VLQINT]            = 4,
+       [IRQ_TINT0_TINT12]      = 2,    /* clockevent */
+       [IRQ_TINT0_TINT34]      = 2,    /* clocksource */
+       [IRQ_TINT1_TINT12]      = 7,    /* DSP timer */
+       [IRQ_TINT1_TINT34]      = 7,    /* system tick */
+       [IRQ_PWMINT0]           = 7,
+       [IRQ_PWMINT1]           = 7,
+       [IRQ_PWMINT2]           = 7,
+       [IRQ_I2C]               = 3,
+       [IRQ_UARTINT0]          = 3,
+       [IRQ_UARTINT1]          = 3,
+       [IRQ_UARTINT2]          = 3,
+       [IRQ_SPINT0]            = 3,
+       [IRQ_SPINT1]            = 3,
+       [45]                    = 7,
+       [IRQ_DSP2ARM0]          = 4,
+       [IRQ_DSP2ARM1]          = 4,
+       [IRQ_GPIO0]             = 7,
+       [IRQ_GPIO1]             = 7,
+       [IRQ_GPIO2]             = 7,
+       [IRQ_GPIO3]             = 7,
+       [IRQ_GPIO4]             = 7,
+       [IRQ_GPIO5]             = 7,
+       [IRQ_GPIO6]             = 7,
+       [IRQ_GPIO7]             = 7,
+       [IRQ_GPIOBNK0]          = 7,
+       [IRQ_GPIOBNK1]          = 7,
+       [IRQ_GPIOBNK2]          = 7,
+       [IRQ_GPIOBNK3]          = 7,
+       [IRQ_GPIOBNK4]          = 7,
+       [IRQ_COMMTX]            = 7,
+       [IRQ_COMMRX]            = 7,
+       [IRQ_EMUINT]            = 7,
+};
 
 /*----------------------------------------------------------------------*/
 
@@ -444,10 +531,118 @@ static struct platform_device dm644x_edma_device = {
 };
 
 /*----------------------------------------------------------------------*/
+
+static struct map_desc dm644x_io_desc[] = {
+       {
+               .virtual        = IO_VIRT,
+               .pfn            = __phys_to_pfn(IO_PHYS),
+               .length         = IO_SIZE,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = SRAM_VIRT,
+               .pfn            = __phys_to_pfn(0x00008000),
+               .length         = SZ_16K,
+               /* MT_MEMORY_NONCACHED requires supersection alignment */
+               .type           = MT_DEVICE,
+       },
+};
+
+/* Contents of JTAG ID register used to identify exact cpu type */
+static struct davinci_id dm644x_ids[] = {
+       {
+               .variant        = 0x0,
+               .part_no        = 0xb700,
+               .manufacturer   = 0x017,
+               .cpu_id         = DAVINCI_CPU_ID_DM6446,
+               .name           = "dm6446",
+       },
+};
+
+static void __iomem *dm644x_psc_bases[] = {
+       IO_ADDRESS(DAVINCI_PWR_SLEEP_CNTRL_BASE),
+};
+
+/*
+ * T0_BOT: Timer 0, bottom:  clockevent source for hrtimers
+ * T0_TOP: Timer 0, top   :  clocksource for generic timekeeping
+ * T1_BOT: Timer 1, bottom:  (used by DSP in TI DSPLink code)
+ * T1_TOP: Timer 1, top   :  <unused>
+ */
+struct davinci_timer_info dm644x_timer_info = {
+       .timers         = davinci_timer_instance,
+       .clockevent_id  = T0_BOT,
+       .clocksource_id = T0_TOP,
+};
+
+static struct plat_serial8250_port dm644x_serial_platform_data[] = {
+       {
+               .mapbase        = DAVINCI_UART0_BASE,
+               .irq            = IRQ_UARTINT0,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+                                 UPF_IOREMAP,
+               .iotype         = UPIO_MEM,
+               .regshift       = 2,
+       },
+       {
+               .mapbase        = DAVINCI_UART1_BASE,
+               .irq            = IRQ_UARTINT1,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+                                 UPF_IOREMAP,
+               .iotype         = UPIO_MEM,
+               .regshift       = 2,
+       },
+       {
+               .mapbase        = DAVINCI_UART2_BASE,
+               .irq            = IRQ_UARTINT2,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+                                 UPF_IOREMAP,
+               .iotype         = UPIO_MEM,
+               .regshift       = 2,
+       },
+       {
+               .flags          = 0
+       },
+};
+
+static struct platform_device dm644x_serial_device = {
+       .name                   = "serial8250",
+       .id                     = PLAT8250_DEV_PLATFORM,
+       .dev                    = {
+               .platform_data  = dm644x_serial_platform_data,
+       },
+};
+
+static struct davinci_soc_info davinci_soc_info_dm644x = {
+       .io_desc                = dm644x_io_desc,
+       .io_desc_num            = ARRAY_SIZE(dm644x_io_desc),
+       .jtag_id_base           = IO_ADDRESS(0x01c40028),
+       .ids                    = dm644x_ids,
+       .ids_num                = ARRAY_SIZE(dm644x_ids),
+       .cpu_clks               = dm644x_clks,
+       .psc_bases              = dm644x_psc_bases,
+       .psc_bases_num          = ARRAY_SIZE(dm644x_psc_bases),
+       .pinmux_base            = IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE),
+       .pinmux_pins            = dm644x_pins,
+       .pinmux_pins_num        = ARRAY_SIZE(dm644x_pins),
+       .intc_base              = IO_ADDRESS(DAVINCI_ARM_INTC_BASE),
+       .intc_type              = DAVINCI_INTC_TYPE_AINTC,
+       .intc_irq_prios         = dm644x_default_priorities,
+       .intc_irq_num           = DAVINCI_N_AINTC_IRQ,
+       .timer_info             = &dm644x_timer_info,
+       .wdt_base               = IO_ADDRESS(DAVINCI_WDOG_BASE),
+       .gpio_base              = IO_ADDRESS(DAVINCI_GPIO_BASE),
+       .gpio_num               = 71,
+       .gpio_irq               = IRQ_GPIOBNK0,
+       .serial_dev             = &dm644x_serial_device,
+       .emac_pdata             = &dm644x_emac_pdata,
+       .sram_dma               = 0x00008000,
+       .sram_len               = SZ_16K,
+};
+
 void __init dm644x_init(void)
 {
-       davinci_clk_init(dm644x_clks);
-       davinci_mux_register(dm644x_pins, ARRAY_SIZE(dm644x_pins));
+       davinci_common_init(&davinci_soc_info_dm644x);
 }
 
 static int __init dm644x_init_devices(void)
@@ -456,6 +651,7 @@ static int __init dm644x_init_devices(void)
                return 0;
 
        platform_device_register(&dm644x_edma_device);
+       platform_device_register(&dm644x_emac_device);
        return 0;
 }
 postcore_initcall(dm644x_init_devices);
diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c
new file mode 100644 (file)
index 0000000..334f071
--- /dev/null
@@ -0,0 +1,636 @@
+/*
+ * TI DaVinci DM644x chip specific setup
+ *
+ * Author: Kevin Hilman, Deep Root Systems, LLC
+ *
+ * 2007 (c) Deep Root Systems, LLC. 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/clk.h>
+#include <linux/serial_8250.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <asm/mach/map.h>
+
+#include <mach/dm646x.h>
+#include <mach/clock.h>
+#include <mach/cputype.h>
+#include <mach/edma.h>
+#include <mach/irqs.h>
+#include <mach/psc.h>
+#include <mach/mux.h>
+#include <mach/time.h>
+#include <mach/serial.h>
+#include <mach/common.h>
+
+#include "clock.h"
+#include "mux.h"
+
+/*
+ * Device specific clocks
+ */
+#define DM646X_REF_FREQ                27000000
+#define DM646X_AUX_FREQ                24000000
+
+static struct pll_data pll1_data = {
+       .num       = 1,
+       .phys_base = DAVINCI_PLL1_BASE,
+};
+
+static struct pll_data pll2_data = {
+       .num       = 2,
+       .phys_base = DAVINCI_PLL2_BASE,
+};
+
+static struct clk ref_clk = {
+       .name = "ref_clk",
+       .rate = DM646X_REF_FREQ,
+};
+
+static struct clk aux_clkin = {
+       .name = "aux_clkin",
+       .rate = DM646X_AUX_FREQ,
+};
+
+static struct clk pll1_clk = {
+       .name = "pll1",
+       .parent = &ref_clk,
+       .pll_data = &pll1_data,
+       .flags = CLK_PLL,
+};
+
+static struct clk pll1_sysclk1 = {
+       .name = "pll1_sysclk1",
+       .parent = &pll1_clk,
+       .flags = CLK_PLL,
+       .div_reg = PLLDIV1,
+};
+
+static struct clk pll1_sysclk2 = {
+       .name = "pll1_sysclk2",
+       .parent = &pll1_clk,
+       .flags = CLK_PLL,
+       .div_reg = PLLDIV2,
+};
+
+static struct clk pll1_sysclk3 = {
+       .name = "pll1_sysclk3",
+       .parent = &pll1_clk,
+       .flags = CLK_PLL,
+       .div_reg = PLLDIV3,
+};
+
+static struct clk pll1_sysclk4 = {
+       .name = "pll1_sysclk4",
+       .parent = &pll1_clk,
+       .flags = CLK_PLL,
+       .div_reg = PLLDIV4,
+};
+
+static struct clk pll1_sysclk5 = {
+       .name = "pll1_sysclk5",
+       .parent = &pll1_clk,
+       .flags = CLK_PLL,
+       .div_reg = PLLDIV5,
+};
+
+static struct clk pll1_sysclk6 = {
+       .name = "pll1_sysclk6",
+       .parent = &pll1_clk,
+       .flags = CLK_PLL,
+       .div_reg = PLLDIV6,
+};
+
+static struct clk pll1_sysclk8 = {
+       .name = "pll1_sysclk8",
+       .parent = &pll1_clk,
+       .flags = CLK_PLL,
+       .div_reg = PLLDIV8,
+};
+
+static struct clk pll1_sysclk9 = {
+       .name = "pll1_sysclk9",
+       .parent = &pll1_clk,
+       .flags = CLK_PLL,
+       .div_reg = PLLDIV9,
+};
+
+static struct clk pll1_sysclkbp = {
+       .name = "pll1_sysclkbp",
+       .parent = &pll1_clk,
+       .flags = CLK_PLL | PRE_PLL,
+       .div_reg = BPDIV,
+};
+
+static struct clk pll1_aux_clk = {
+       .name = "pll1_aux_clk",
+       .parent = &pll1_clk,
+       .flags = CLK_PLL | PRE_PLL,
+};
+
+static struct clk pll2_clk = {
+       .name = "pll2_clk",
+       .parent = &ref_clk,
+       .pll_data = &pll2_data,
+       .flags = CLK_PLL,
+};
+
+static struct clk pll2_sysclk1 = {
+       .name = "pll2_sysclk1",
+       .parent = &pll2_clk,
+       .flags = CLK_PLL,
+       .div_reg = PLLDIV1,
+};
+
+static struct clk dsp_clk = {
+       .name = "dsp",
+       .parent = &pll1_sysclk1,
+       .lpsc = DM646X_LPSC_C64X_CPU,
+       .flags = PSC_DSP,
+       .usecount = 1,                  /* REVISIT how to disable? */
+};
+
+static struct clk arm_clk = {
+       .name = "arm",
+       .parent = &pll1_sysclk2,
+       .lpsc = DM646X_LPSC_ARM,
+       .flags = ALWAYS_ENABLED,
+};
+
+static struct clk uart0_clk = {
+       .name = "uart0",
+       .parent = &aux_clkin,
+       .lpsc = DM646X_LPSC_UART0,
+};
+
+static struct clk uart1_clk = {
+       .name = "uart1",
+       .parent = &aux_clkin,
+       .lpsc = DM646X_LPSC_UART1,
+};
+
+static struct clk uart2_clk = {
+       .name = "uart2",
+       .parent = &aux_clkin,
+       .lpsc = DM646X_LPSC_UART2,
+};
+
+static struct clk i2c_clk = {
+       .name = "I2CCLK",
+       .parent = &pll1_sysclk3,
+       .lpsc = DM646X_LPSC_I2C,
+};
+
+static struct clk gpio_clk = {
+       .name = "gpio",
+       .parent = &pll1_sysclk3,
+       .lpsc = DM646X_LPSC_GPIO,
+};
+
+static struct clk aemif_clk = {
+       .name = "aemif",
+       .parent = &pll1_sysclk3,
+       .lpsc = DM646X_LPSC_AEMIF,
+       .flags = ALWAYS_ENABLED,
+};
+
+static struct clk emac_clk = {
+       .name = "emac",
+       .parent = &pll1_sysclk3,
+       .lpsc = DM646X_LPSC_EMAC,
+};
+
+static struct clk pwm0_clk = {
+       .name = "pwm0",
+       .parent = &pll1_sysclk3,
+       .lpsc = DM646X_LPSC_PWM0,
+       .usecount = 1,            /* REVIST: disabling hangs system */
+};
+
+static struct clk pwm1_clk = {
+       .name = "pwm1",
+       .parent = &pll1_sysclk3,
+       .lpsc = DM646X_LPSC_PWM1,
+       .usecount = 1,            /* REVIST: disabling hangs system */
+};
+
+static struct clk timer0_clk = {
+       .name = "timer0",
+       .parent = &pll1_sysclk3,
+       .lpsc = DM646X_LPSC_TIMER0,
+};
+
+static struct clk timer1_clk = {
+       .name = "timer1",
+       .parent = &pll1_sysclk3,
+       .lpsc = DM646X_LPSC_TIMER1,
+};
+
+static struct clk timer2_clk = {
+       .name = "timer2",
+       .parent = &pll1_sysclk3,
+       .flags = ALWAYS_ENABLED, /* no LPSC, always enabled; c.f. spruep9a */
+};
+
+static struct clk vpif0_clk = {
+       .name = "vpif0",
+       .parent = &ref_clk,
+       .lpsc = DM646X_LPSC_VPSSMSTR,
+       .flags = ALWAYS_ENABLED,
+};
+
+static struct clk vpif1_clk = {
+       .name = "vpif1",
+       .parent = &ref_clk,
+       .lpsc = DM646X_LPSC_VPSSSLV,
+       .flags = ALWAYS_ENABLED,
+};
+
+struct davinci_clk dm646x_clks[] = {
+       CLK(NULL, "ref", &ref_clk),
+       CLK(NULL, "aux", &aux_clkin),
+       CLK(NULL, "pll1", &pll1_clk),
+       CLK(NULL, "pll1_sysclk", &pll1_sysclk1),
+       CLK(NULL, "pll1_sysclk", &pll1_sysclk2),
+       CLK(NULL, "pll1_sysclk", &pll1_sysclk3),
+       CLK(NULL, "pll1_sysclk", &pll1_sysclk4),
+       CLK(NULL, "pll1_sysclk", &pll1_sysclk5),
+       CLK(NULL, "pll1_sysclk", &pll1_sysclk6),
+       CLK(NULL, "pll1_sysclk", &pll1_sysclk8),
+       CLK(NULL, "pll1_sysclk", &pll1_sysclk9),
+       CLK(NULL, "pll1_sysclk", &pll1_sysclkbp),
+       CLK(NULL, "pll1_aux", &pll1_aux_clk),
+       CLK(NULL, "pll2", &pll2_clk),
+       CLK(NULL, "pll2_sysclk1", &pll2_sysclk1),
+       CLK(NULL, "dsp", &dsp_clk),
+       CLK(NULL, "arm", &arm_clk),
+       CLK(NULL, "uart0", &uart0_clk),
+       CLK(NULL, "uart1", &uart1_clk),
+       CLK(NULL, "uart2", &uart2_clk),
+       CLK("i2c_davinci.1", NULL, &i2c_clk),
+       CLK(NULL, "gpio", &gpio_clk),
+       CLK(NULL, "aemif", &aemif_clk),
+       CLK("davinci_emac.1", NULL, &emac_clk),
+       CLK(NULL, "pwm0", &pwm0_clk),
+       CLK(NULL, "pwm1", &pwm1_clk),
+       CLK(NULL, "timer0", &timer0_clk),
+       CLK(NULL, "timer1", &timer1_clk),
+       CLK("watchdog", NULL, &timer2_clk),
+       CLK(NULL, "vpif0", &vpif0_clk),
+       CLK(NULL, "vpif1", &vpif1_clk),
+       CLK(NULL, NULL, NULL),
+};
+
+static struct emac_platform_data dm646x_emac_pdata = {
+       .ctrl_reg_offset        = DM646X_EMAC_CNTRL_OFFSET,
+       .ctrl_mod_reg_offset    = DM646X_EMAC_CNTRL_MOD_OFFSET,
+       .ctrl_ram_offset        = DM646X_EMAC_CNTRL_RAM_OFFSET,
+       .mdio_reg_offset        = DM646X_EMAC_MDIO_OFFSET,
+       .ctrl_ram_size          = DM646X_EMAC_CNTRL_RAM_SIZE,
+       .version                = EMAC_VERSION_2,
+};
+
+static struct resource dm646x_emac_resources[] = {
+       {
+               .start  = DM646X_EMAC_BASE,
+               .end    = DM646X_EMAC_BASE + 0x47ff,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = IRQ_DM646X_EMACRXTHINT,
+               .end    = IRQ_DM646X_EMACRXTHINT,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .start  = IRQ_DM646X_EMACRXINT,
+               .end    = IRQ_DM646X_EMACRXINT,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .start  = IRQ_DM646X_EMACTXINT,
+               .end    = IRQ_DM646X_EMACTXINT,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .start  = IRQ_DM646X_EMACMISCINT,
+               .end    = IRQ_DM646X_EMACMISCINT,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device dm646x_emac_device = {
+       .name           = "davinci_emac",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &dm646x_emac_pdata,
+       },
+       .num_resources  = ARRAY_SIZE(dm646x_emac_resources),
+       .resource       = dm646x_emac_resources,
+};
+
+#define PINMUX0                0x00
+#define PINMUX1                0x04
+
+/*
+ * Device specific mux setup
+ *
+ *     soc     description     mux  mode   mode  mux    dbg
+ *                             reg  offset mask  mode
+ */
+static const struct mux_config dm646x_pins[] = {
+#ifdef CONFIG_DAVINCI_MUX
+MUX_CFG(DM646X, ATAEN,         0,   0,     1,    1,     true)
+
+MUX_CFG(DM646X, AUDCK1,                0,   29,    1,    0,     false)
+
+MUX_CFG(DM646X, AUDCK0,                0,   28,    1,    0,     false)
+
+MUX_CFG(DM646X, CRGMUX,                        0,   24,    7,    5,     true)
+
+MUX_CFG(DM646X, STSOMUX_DISABLE,       0,   22,    3,    0,     true)
+
+MUX_CFG(DM646X, STSIMUX_DISABLE,       0,   20,    3,    0,     true)
+
+MUX_CFG(DM646X, PTSOMUX_DISABLE,       0,   18,    3,    0,     true)
+
+MUX_CFG(DM646X, PTSIMUX_DISABLE,       0,   16,    3,    0,     true)
+
+MUX_CFG(DM646X, STSOMUX,               0,   22,    3,    2,     true)
+
+MUX_CFG(DM646X, STSIMUX,               0,   20,    3,    2,     true)
+
+MUX_CFG(DM646X, PTSOMUX_PARALLEL,      0,   18,    3,    2,     true)
+
+MUX_CFG(DM646X, PTSIMUX_PARALLEL,      0,   16,    3,    2,     true)
+
+MUX_CFG(DM646X, PTSOMUX_SERIAL,                0,   18,    3,    3,     true)
+
+MUX_CFG(DM646X, PTSIMUX_SERIAL,                0,   16,    3,    3,     true)
+#endif
+};
+
+static u8 dm646x_default_priorities[DAVINCI_N_AINTC_IRQ] = {
+       [IRQ_DM646X_VP_VERTINT0]        = 7,
+       [IRQ_DM646X_VP_VERTINT1]        = 7,
+       [IRQ_DM646X_VP_VERTINT2]        = 7,
+       [IRQ_DM646X_VP_VERTINT3]        = 7,
+       [IRQ_DM646X_VP_ERRINT]          = 7,
+       [IRQ_DM646X_RESERVED_1]         = 7,
+       [IRQ_DM646X_RESERVED_2]         = 7,
+       [IRQ_DM646X_WDINT]              = 7,
+       [IRQ_DM646X_CRGENINT0]          = 7,
+       [IRQ_DM646X_CRGENINT1]          = 7,
+       [IRQ_DM646X_TSIFINT0]           = 7,
+       [IRQ_DM646X_TSIFINT1]           = 7,
+       [IRQ_DM646X_VDCEINT]            = 7,
+       [IRQ_DM646X_USBINT]             = 7,
+       [IRQ_DM646X_USBDMAINT]          = 7,
+       [IRQ_DM646X_PCIINT]             = 7,
+       [IRQ_CCINT0]                    = 7,    /* dma */
+       [IRQ_CCERRINT]                  = 7,    /* dma */
+       [IRQ_TCERRINT0]                 = 7,    /* dma */
+       [IRQ_TCERRINT]                  = 7,    /* dma */
+       [IRQ_DM646X_TCERRINT2]          = 7,
+       [IRQ_DM646X_TCERRINT3]          = 7,
+       [IRQ_DM646X_IDE]                = 7,
+       [IRQ_DM646X_HPIINT]             = 7,
+       [IRQ_DM646X_EMACRXTHINT]        = 7,
+       [IRQ_DM646X_EMACRXINT]          = 7,
+       [IRQ_DM646X_EMACTXINT]          = 7,
+       [IRQ_DM646X_EMACMISCINT]        = 7,
+       [IRQ_DM646X_MCASP0TXINT]        = 7,
+       [IRQ_DM646X_MCASP0RXINT]        = 7,
+       [IRQ_AEMIFINT]                  = 7,
+       [IRQ_DM646X_RESERVED_3]         = 7,
+       [IRQ_DM646X_MCASP1TXINT]        = 7,    /* clockevent */
+       [IRQ_TINT0_TINT34]              = 7,    /* clocksource */
+       [IRQ_TINT1_TINT12]              = 7,    /* DSP timer */
+       [IRQ_TINT1_TINT34]              = 7,    /* system tick */
+       [IRQ_PWMINT0]                   = 7,
+       [IRQ_PWMINT1]                   = 7,
+       [IRQ_DM646X_VLQINT]             = 7,
+       [IRQ_I2C]                       = 7,
+       [IRQ_UARTINT0]                  = 7,
+       [IRQ_UARTINT1]                  = 7,
+       [IRQ_DM646X_UARTINT2]           = 7,
+       [IRQ_DM646X_SPINT0]             = 7,
+       [IRQ_DM646X_SPINT1]             = 7,
+       [IRQ_DM646X_DSP2ARMINT]         = 7,
+       [IRQ_DM646X_RESERVED_4]         = 7,
+       [IRQ_DM646X_PSCINT]             = 7,
+       [IRQ_DM646X_GPIO0]              = 7,
+       [IRQ_DM646X_GPIO1]              = 7,
+       [IRQ_DM646X_GPIO2]              = 7,
+       [IRQ_DM646X_GPIO3]              = 7,
+       [IRQ_DM646X_GPIO4]              = 7,
+       [IRQ_DM646X_GPIO5]              = 7,
+       [IRQ_DM646X_GPIO6]              = 7,
+       [IRQ_DM646X_GPIO7]              = 7,
+       [IRQ_DM646X_GPIOBNK0]           = 7,
+       [IRQ_DM646X_GPIOBNK1]           = 7,
+       [IRQ_DM646X_GPIOBNK2]           = 7,
+       [IRQ_DM646X_DDRINT]             = 7,
+       [IRQ_DM646X_AEMIFINT]           = 7,
+       [IRQ_COMMTX]                    = 7,
+       [IRQ_COMMRX]                    = 7,
+       [IRQ_EMUINT]                    = 7,
+};
+
+/*----------------------------------------------------------------------*/
+
+static const s8 dma_chan_dm646x_no_event[] = {
+        0,  1,  2,  3, 13,
+       14, 15, 24, 25, 26,
+       27, 30, 31, 54, 55,
+       56,
+       -1
+};
+
+static struct edma_soc_info dm646x_edma_info = {
+       .n_channel      = 64,
+       .n_region       = 6,    /* 0-1, 4-7 */
+       .n_slot         = 512,
+       .n_tc           = 4,
+       .noevent        = dma_chan_dm646x_no_event,
+};
+
+static struct resource edma_resources[] = {
+       {
+               .name   = "edma_cc",
+               .start  = 0x01c00000,
+               .end    = 0x01c00000 + SZ_64K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .name   = "edma_tc0",
+               .start  = 0x01c10000,
+               .end    = 0x01c10000 + SZ_1K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .name   = "edma_tc1",
+               .start  = 0x01c10400,
+               .end    = 0x01c10400 + SZ_1K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .name   = "edma_tc2",
+               .start  = 0x01c10800,
+               .end    = 0x01c10800 + SZ_1K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .name   = "edma_tc3",
+               .start  = 0x01c10c00,
+               .end    = 0x01c10c00 + SZ_1K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = IRQ_CCINT0,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .start  = IRQ_CCERRINT,
+               .flags  = IORESOURCE_IRQ,
+       },
+       /* not using TC*_ERR */
+};
+
+static struct platform_device dm646x_edma_device = {
+       .name                   = "edma",
+       .id                     = -1,
+       .dev.platform_data      = &dm646x_edma_info,
+       .num_resources          = ARRAY_SIZE(edma_resources),
+       .resource               = edma_resources,
+};
+
+/*----------------------------------------------------------------------*/
+
+static struct map_desc dm646x_io_desc[] = {
+       {
+               .virtual        = IO_VIRT,
+               .pfn            = __phys_to_pfn(IO_PHYS),
+               .length         = IO_SIZE,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = SRAM_VIRT,
+               .pfn            = __phys_to_pfn(0x00010000),
+               .length         = SZ_32K,
+               /* MT_MEMORY_NONCACHED requires supersection alignment */
+               .type           = MT_DEVICE,
+       },
+};
+
+/* Contents of JTAG ID register used to identify exact cpu type */
+static struct davinci_id dm646x_ids[] = {
+       {
+               .variant        = 0x0,
+               .part_no        = 0xb770,
+               .manufacturer   = 0x017,
+               .cpu_id         = DAVINCI_CPU_ID_DM6467,
+               .name           = "dm6467",
+       },
+};
+
+static void __iomem *dm646x_psc_bases[] = {
+       IO_ADDRESS(DAVINCI_PWR_SLEEP_CNTRL_BASE),
+};
+
+/*
+ * T0_BOT: Timer 0, bottom:  clockevent source for hrtimers
+ * T0_TOP: Timer 0, top   :  clocksource for generic timekeeping
+ * T1_BOT: Timer 1, bottom:  (used by DSP in TI DSPLink code)
+ * T1_TOP: Timer 1, top   :  <unused>
+ */
+struct davinci_timer_info dm646x_timer_info = {
+       .timers         = davinci_timer_instance,
+       .clockevent_id  = T0_BOT,
+       .clocksource_id = T0_TOP,
+};
+
+static struct plat_serial8250_port dm646x_serial_platform_data[] = {
+       {
+               .mapbase        = DAVINCI_UART0_BASE,
+               .irq            = IRQ_UARTINT0,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+                                 UPF_IOREMAP,
+               .iotype         = UPIO_MEM32,
+               .regshift       = 2,
+       },
+       {
+               .mapbase        = DAVINCI_UART1_BASE,
+               .irq            = IRQ_UARTINT1,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+                                 UPF_IOREMAP,
+               .iotype         = UPIO_MEM32,
+               .regshift       = 2,
+       },
+       {
+               .mapbase        = DAVINCI_UART2_BASE,
+               .irq            = IRQ_DM646X_UARTINT2,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+                                 UPF_IOREMAP,
+               .iotype         = UPIO_MEM32,
+               .regshift       = 2,
+       },
+       {
+               .flags          = 0
+       },
+};
+
+static struct platform_device dm646x_serial_device = {
+       .name                   = "serial8250",
+       .id                     = PLAT8250_DEV_PLATFORM,
+       .dev                    = {
+               .platform_data  = dm646x_serial_platform_data,
+       },
+};
+
+static struct davinci_soc_info davinci_soc_info_dm646x = {
+       .io_desc                = dm646x_io_desc,
+       .io_desc_num            = ARRAY_SIZE(dm646x_io_desc),
+       .jtag_id_base           = IO_ADDRESS(0x01c40028),
+       .ids                    = dm646x_ids,
+       .ids_num                = ARRAY_SIZE(dm646x_ids),
+       .cpu_clks               = dm646x_clks,
+       .psc_bases              = dm646x_psc_bases,
+       .psc_bases_num          = ARRAY_SIZE(dm646x_psc_bases),
+       .pinmux_base            = IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE),
+       .pinmux_pins            = dm646x_pins,
+       .pinmux_pins_num        = ARRAY_SIZE(dm646x_pins),
+       .intc_base              = IO_ADDRESS(DAVINCI_ARM_INTC_BASE),
+       .intc_type              = DAVINCI_INTC_TYPE_AINTC,
+       .intc_irq_prios         = dm646x_default_priorities,
+       .intc_irq_num           = DAVINCI_N_AINTC_IRQ,
+       .timer_info             = &dm646x_timer_info,
+       .wdt_base               = IO_ADDRESS(DAVINCI_WDOG_BASE),
+       .gpio_base              = IO_ADDRESS(DAVINCI_GPIO_BASE),
+       .gpio_num               = 43, /* Only 33 usable */
+       .gpio_irq               = IRQ_DM646X_GPIOBNK0,
+       .serial_dev             = &dm646x_serial_device,
+       .emac_pdata             = &dm646x_emac_pdata,
+       .sram_dma               = 0x10010000,
+       .sram_len               = SZ_32K,
+};
+
+void __init dm646x_init(void)
+{
+       davinci_common_init(&davinci_soc_info_dm646x);
+}
+
+static int __init dm646x_init_devices(void)
+{
+       if (!cpu_is_davinci_dm646x())
+               return 0;
+
+       platform_device_register(&dm646x_edma_device);
+       platform_device_register(&dm646x_emac_device);
+       return 0;
+}
+postcore_initcall(dm646x_init_devices);
index 1aba41c6351ea68d92884e56ebbd10ae86b237a7..1b6532159c58813b8973aa906bcec26c9ea138de 100644 (file)
@@ -23,6 +23,7 @@
 #include <mach/cputype.h>
 #include <mach/irqs.h>
 #include <mach/hardware.h>
+#include <mach/common.h>
 #include <mach/gpio.h>
 
 #include <asm/mach/irq.h>
@@ -37,14 +38,13 @@ struct davinci_gpio {
 
 static struct davinci_gpio chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)];
 
-static unsigned __initdata ngpio;
-
 /* create a non-inlined version */
 static struct gpio_controller __iomem * __init gpio2controller(unsigned gpio)
 {
        return __gpio_to_controller(gpio);
 }
 
+static int __init davinci_gpio_irq_setup(void);
 
 /*--------------------------------------------------------------------------*/
 
@@ -115,23 +115,16 @@ davinci_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 static int __init davinci_gpio_setup(void)
 {
        int i, base;
+       unsigned ngpio;
+       struct davinci_soc_info *soc_info = &davinci_soc_info;
 
-       /* The gpio banks conceptually expose a segmented bitmap,
+       /*
+        * The gpio banks conceptually expose a segmented bitmap,
         * and "ngpio" is one more than the largest zero-based
         * bit index that's valid.
         */
-       if (cpu_is_davinci_dm355()) {           /* or dm335() */
-               ngpio = 104;
-       } else if (cpu_is_davinci_dm644x()) {   /* or dm337() */
-               ngpio = 71;
-       } else if (cpu_is_davinci_dm646x()) {
-               /* NOTE:  each bank has several "reserved" bits,
-                * unusable as GPIOs.  Only 33 of the GPIO numbers
-                * are usable, and we're not rejecting the others.
-                */
-               ngpio = 43;
-       } else {
-               /* if cpu_is_davinci_dm643x() ngpio = 111 */
+       ngpio = soc_info->gpio_num;
+       if (ngpio == 0) {
                pr_err("GPIO setup:  how many GPIOs?\n");
                return -EINVAL;
        }
@@ -157,6 +150,7 @@ static int __init davinci_gpio_setup(void)
                gpiochip_add(&chips[i].chip);
        }
 
+       davinci_gpio_irq_setup();
        return 0;
 }
 pure_initcall(davinci_gpio_setup);
@@ -187,10 +181,15 @@ static void gpio_irq_enable(unsigned irq)
 {
        struct gpio_controller *__iomem g = get_irq_chip_data(irq);
        u32 mask = __gpio_mask(irq_to_gpio(irq));
+       unsigned status = irq_desc[irq].status;
+
+       status &= IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING;
+       if (!status)
+               status = IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING;
 
-       if (irq_desc[irq].status & IRQ_TYPE_EDGE_FALLING)
+       if (status & IRQ_TYPE_EDGE_FALLING)
                __raw_writel(mask, &g->set_falling);
-       if (irq_desc[irq].status & IRQ_TYPE_EDGE_RISING)
+       if (status & IRQ_TYPE_EDGE_RISING)
                __raw_writel(mask, &g->set_rising);
 }
 
@@ -205,10 +204,13 @@ static int gpio_irq_type(unsigned irq, unsigned trigger)
        irq_desc[irq].status &= ~IRQ_TYPE_SENSE_MASK;
        irq_desc[irq].status |= trigger;
 
-       __raw_writel(mask, (trigger & IRQ_TYPE_EDGE_FALLING)
-                    ? &g->set_falling : &g->clr_falling);
-       __raw_writel(mask, (trigger & IRQ_TYPE_EDGE_RISING)
-                    ? &g->set_rising : &g->clr_rising);
+       /* don't enable the IRQ if it's currently disabled */
+       if (irq_desc[irq].depth == 0) {
+               __raw_writel(mask, (trigger & IRQ_TYPE_EDGE_FALLING)
+                            ? &g->set_falling : &g->clr_falling);
+               __raw_writel(mask, (trigger & IRQ_TYPE_EDGE_RISING)
+                            ? &g->set_rising : &g->clr_rising);
+       }
        return 0;
 }
 
@@ -230,6 +232,7 @@ gpio_irq_handler(unsigned irq, struct irq_desc *desc)
                mask <<= 16;
 
        /* temporarily mask (level sensitive) parent IRQ */
+       desc->chip->mask(irq);
        desc->chip->ack(irq);
        while (1) {
                u32             status;
@@ -268,17 +271,15 @@ gpio_irq_handler(unsigned irq, struct irq_desc *desc)
 static int __init davinci_gpio_irq_setup(void)
 {
        unsigned        gpio, irq, bank;
-       unsigned        bank_irq;
        struct clk      *clk;
        u32             binten = 0;
+       unsigned        ngpio, bank_irq;
+       struct davinci_soc_info *soc_info = &davinci_soc_info;
+
+       ngpio = soc_info->gpio_num;
 
-       if (cpu_is_davinci_dm355()) {           /* or dm335() */
-               bank_irq = IRQ_DM355_GPIOBNK0;
-       } else if (cpu_is_davinci_dm644x()) {
-               bank_irq = IRQ_GPIOBNK0;
-       } else if (cpu_is_davinci_dm646x()) {
-               bank_irq = IRQ_DM646X_GPIOBNK0;
-       } else {
+       bank_irq = soc_info->gpio_irq;
+       if (bank_irq == 0) {
                printk(KERN_ERR "Don't know first GPIO bank IRQ.\n");
                return -EINVAL;
        }
@@ -318,11 +319,9 @@ static int __init davinci_gpio_irq_setup(void)
        /* BINTEN -- per-bank interrupt enable. genirq would also let these
         * bits be set/cleared dynamically.
         */
-       __raw_writel(binten, (void *__iomem)
-                    IO_ADDRESS(DAVINCI_GPIO_BASE + 0x08));
+       __raw_writel(binten, soc_info->gpio_base + 0x08);
 
        printk(KERN_INFO "DaVinci: %d gpio irqs\n", irq - gpio_to_irq(0));
 
        return 0;
 }
-arch_initcall(davinci_gpio_irq_setup);
diff --git a/arch/arm/mach-davinci/id.c b/arch/arm/mach-davinci/id.c
deleted file mode 100644 (file)
index 018b994..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Davinci CPU identification code
- *
- * Copyright (C) 2006 Komal Shah <komal_shah802003@yahoo.com>
- *
- * Derived from OMAP1 CPU identification code.
- *
- * This 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/init.h>
-#include <linux/io.h>
-
-#define JTAG_ID_BASE           IO_ADDRESS(0x01c40028)
-
-static unsigned int davinci_revision;
-
-struct davinci_id {
-       u8      variant;        /* JTAG ID bits 31:28 */
-       u16     part_no;        /* JTAG ID bits 27:12 */
-       u32     manufacturer;   /* JTAG ID bits 11:1 */
-       u32     type;           /* Cpu id bits [31:8], cpu class bits [7:0] */
-};
-
-/* Register values to detect the DaVinci version */
-static struct davinci_id davinci_ids[] __initdata = {
-       {
-               /* DM6446 */
-               .part_no      = 0xb700,
-               .variant      = 0x0,
-               .manufacturer = 0x017,
-               .type         = 0x64460000,
-       },
-       {
-               /* DM646X */
-               .part_no      = 0xb770,
-               .variant      = 0x0,
-               .manufacturer = 0x017,
-               .type         = 0x64670000,
-       },
-       {
-               /* DM355 */
-               .part_no        = 0xb73b,
-               .variant        = 0x0,
-               .manufacturer   = 0x00f,
-               .type           = 0x03550000,
-       },
-};
-
-/*
- * Get Device Part No. from JTAG ID register
- */
-static u16 __init davinci_get_part_no(void)
-{
-       u32 dev_id, part_no;
-
-       dev_id = __raw_readl(JTAG_ID_BASE);
-
-       part_no = ((dev_id >> 12) & 0xffff);
-
-       return part_no;
-}
-
-/*
- * Get Device Revision from JTAG ID register
- */
-static u8 __init davinci_get_variant(void)
-{
-       u32 variant;
-
-       variant = __raw_readl(JTAG_ID_BASE);
-
-       variant = (variant >> 28) & 0xf;
-
-       return variant;
-}
-
-unsigned int davinci_rev(void)
-{
-       return davinci_revision >> 16;
-}
-EXPORT_SYMBOL(davinci_rev);
-
-void __init davinci_check_revision(void)
-{
-       int i;
-       u16 part_no;
-       u8 variant;
-
-       part_no = davinci_get_part_no();
-       variant = davinci_get_variant();
-
-       /* First check only the major version in a safe way */
-       for (i = 0; i < ARRAY_SIZE(davinci_ids); i++) {
-               if (part_no == (davinci_ids[i].part_no)) {
-                       davinci_revision = davinci_ids[i].type;
-                       break;
-               }
-       }
-
-       /* Check if we can find the dev revision */
-       for (i = 0; i < ARRAY_SIZE(davinci_ids); i++) {
-               if (part_no == davinci_ids[i].part_no &&
-                   variant == davinci_ids[i].variant) {
-                       davinci_revision = davinci_ids[i].type;
-                       break;
-               }
-       }
-
-       printk(KERN_INFO "DaVinci DM%04x variant 0x%x\n",
-              davinci_rev(), variant);
-}
diff --git a/arch/arm/mach-davinci/include/mach/board-dm6446evm.h b/arch/arm/mach-davinci/include/mach/board-dm6446evm.h
deleted file mode 100644 (file)
index 3216f21..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * DaVinci DM6446 EVM board specific headers
- *
- * Author: Kevin Hilman, Deep Root Systems, LLC
- *
- * 2007 (c) Deep Root Systems, LLC. 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 ifndef.
- */
-
-#ifndef _MACH_DAVINCI_DM6446EVM_H
-#define _MACH_DAVINCI_DM6446EVM_H
-
-#include <linux/types.h>
-
-int dm6446evm_eeprom_read(char *buf, off_t off, size_t count);
-int dm6446evm_eeprom_write(char *buf, off_t off, size_t count);
-
-#endif
index 1917709762507c01d54dcd14be933e94e4c8b9a4..a1f03b606d8f1fc3ca0bacb4aeb7fa486ce567d1 100644 (file)
@@ -17,7 +17,8 @@ struct sys_timer;
 extern struct sys_timer davinci_timer;
 
 extern void davinci_irq_init(void);
-extern void davinci_map_common_io(void);
+extern void __iomem *davinci_intc_base;
+extern int davinci_intc_type;
 
 /* parameters describe VBUS sourcing for host mode */
 extern void setup_usb(unsigned mA, unsigned potpgt_msec);
@@ -25,4 +26,56 @@ extern void setup_usb(unsigned mA, unsigned potpgt_msec);
 /* parameters describe VBUS sourcing for host mode */
 extern void setup_usb(unsigned mA, unsigned potpgt_msec);
 
+struct davinci_timer_instance {
+       void __iomem    *base;
+       u32             bottom_irq;
+       u32             top_irq;
+       unsigned long   cmp_off;
+       unsigned int    cmp_irq;
+};
+
+struct davinci_timer_info {
+       struct davinci_timer_instance   *timers;
+       unsigned int                    clockevent_id;
+       unsigned int                    clocksource_id;
+};
+
+/* SoC specific init support */
+struct davinci_soc_info {
+       struct map_desc                 *io_desc;
+       unsigned long                   io_desc_num;
+       u32                             cpu_id;
+       u32                             jtag_id;
+       void __iomem                    *jtag_id_base;
+       struct davinci_id               *ids;
+       unsigned long                   ids_num;
+       struct davinci_clk              *cpu_clks;
+       void __iomem                    **psc_bases;
+       unsigned long                   psc_bases_num;
+       void __iomem                    *pinmux_base;
+       const struct mux_config         *pinmux_pins;
+       unsigned long                   pinmux_pins_num;
+       void __iomem                    *intc_base;
+       int                             intc_type;
+       u8                              *intc_irq_prios;
+       unsigned long                   intc_irq_num;
+       struct davinci_timer_info       *timer_info;
+       void __iomem                    *wdt_base;
+       void __iomem                    *gpio_base;
+       unsigned                        gpio_num;
+       unsigned                        gpio_irq;
+       struct platform_device          *serial_dev;
+       struct emac_platform_data       *emac_pdata;
+       dma_addr_t                      sram_dma;
+       unsigned                        sram_len;
+};
+
+extern struct davinci_soc_info davinci_soc_info;
+
+extern void davinci_common_init(struct davinci_soc_info *soc_info);
+
+/* standard place to map on-chip SRAMs; they *may* support DMA */
+#define SRAM_VIRT      0xfffe0000
+#define SRAM_SIZE      SZ_128K
+
 #endif /* __ARCH_ARM_MACH_DAVINCI_COMMON_H */
diff --git a/arch/arm/mach-davinci/include/mach/cp_intc.h b/arch/arm/mach-davinci/include/mach/cp_intc.h
new file mode 100644 (file)
index 0000000..c4d27ee
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * TI Common Platform Interrupt Controller (cp_intc) definitions
+ *
+ * Author: Steve Chen <schen@mvista.com>
+ * Copyright (C) 2008-2009, MontaVista Software, Inc. <source@mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+#ifndef __ASM_HARDWARE_CP_INTC_H
+#define __ASM_HARDWARE_CP_INTC_H
+
+#define CP_INTC_REV                    0x00
+#define CP_INTC_CTRL                   0x04
+#define CP_INTC_HOST_CTRL              0x0C
+#define CP_INTC_GLOBAL_ENABLE          0x10
+#define CP_INTC_GLOBAL_NESTING_LEVEL   0x1C
+#define CP_INTC_SYS_STAT_IDX_SET       0x20
+#define CP_INTC_SYS_STAT_IDX_CLR       0x24
+#define CP_INTC_SYS_ENABLE_IDX_SET     0x28
+#define CP_INTC_SYS_ENABLE_IDX_CLR     0x2C
+#define CP_INTC_GLOBAL_WAKEUP_ENABLE   0x30
+#define CP_INTC_HOST_ENABLE_IDX_SET    0x34
+#define CP_INTC_HOST_ENABLE_IDX_CLR    0x38
+#define CP_INTC_PACING_PRESCALE        0x40
+#define CP_INTC_VECTOR_BASE            0x50
+#define CP_INTC_VECTOR_SIZE            0x54
+#define CP_INTC_VECTOR_NULL            0x58
+#define CP_INTC_PRIO_IDX               0x80
+#define CP_INTC_PRIO_VECTOR            0x84
+#define CP_INTC_SECURE_ENABLE          0x90
+#define CP_INTC_SECURE_PRIO_IDX        0x94
+#define CP_INTC_PACING_PARAM(n)        (0x0100 + (n << 4))
+#define CP_INTC_PACING_DEC(n)          (0x0104 + (n << 4))
+#define CP_INTC_PACING_MAP(n)          (0x0108 + (n << 4))
+#define CP_INTC_SYS_RAW_STAT(n)        (0x0200 + (n << 2))
+#define CP_INTC_SYS_STAT_CLR(n)        (0x0280 + (n << 2))
+#define CP_INTC_SYS_ENABLE_SET(n)      (0x0300 + (n << 2))
+#define CP_INTC_SYS_ENABLE_CLR(n)      (0x0380 + (n << 2))
+#define CP_INTC_CHAN_MAP(n)            (0x0400 + (n << 2))
+#define CP_INTC_HOST_MAP(n)            (0x0800 + (n << 2))
+#define CP_INTC_HOST_PRIO_IDX(n)       (0x0900 + (n << 2))
+#define CP_INTC_SYS_POLARITY(n)        (0x0D00 + (n << 2))
+#define CP_INTC_SYS_TYPE(n)            (0x0D80 + (n << 2))
+#define CP_INTC_WAKEUP_ENABLE(n)       (0x0E00 + (n << 2))
+#define CP_INTC_DEBUG_SELECT(n)        (0x0F00 + (n << 2))
+#define CP_INTC_SYS_SECURE_ENABLE(n)   (0x1000 + (n << 2))
+#define CP_INTC_HOST_NESTING_LEVEL(n)  (0x1100 + (n << 2))
+#define CP_INTC_HOST_ENABLE(n)         (0x1500 + (n << 2))
+#define CP_INTC_HOST_PRIO_VECTOR(n)    (0x1600 + (n << 2))
+#define CP_INTC_VECTOR_ADDR(n)         (0x2000 + (n << 2))
+
+void __init cp_intc_init(void __iomem *base, unsigned short num_irq,
+                        u8 *irq_prio);
+
+#endif /* __ASM_HARDWARE_CP_INTC_H */
index 27cfb1b3a662da65351a3a01a7b55b84ad34101e..d12a5ed2959a533a030cb467d146e29041ec6b6a 100644 (file)
 #ifndef _ASM_ARCH_CPU_H
 #define _ASM_ARCH_CPU_H
 
-extern unsigned int davinci_rev(void);
+#include <mach/common.h>
 
-#define IS_DAVINCI_CPU(type, id)                       \
-static inline int is_davinci_dm ##type(void)           \
-{                                                      \
-       return (davinci_rev() == (id)) ? 1 : 0;         \
+struct davinci_id {
+       u8      variant;        /* JTAG ID bits 31:28 */
+       u16     part_no;        /* JTAG ID bits 27:12 */
+       u16     manufacturer;   /* JTAG ID bits 11:1 */
+       u32     cpu_id;
+       char    *name;
+};
+
+/* Can use lower 16 bits of cpu id  for a variant when required */
+#define        DAVINCI_CPU_ID_DM6446           0x64460000
+#define        DAVINCI_CPU_ID_DM6467           0x64670000
+#define        DAVINCI_CPU_ID_DM355            0x03550000
+
+#define IS_DAVINCI_CPU(type, id)                                       \
+static inline int is_davinci_ ##type(void)                             \
+{                                                                      \
+       return (davinci_soc_info.cpu_id == (id));                       \
 }
 
-IS_DAVINCI_CPU(644x, 0x6446)
-IS_DAVINCI_CPU(646x, 0x6467)
-IS_DAVINCI_CPU(355, 0x355)
+IS_DAVINCI_CPU(dm644x, DAVINCI_CPU_ID_DM6446)
+IS_DAVINCI_CPU(dm646x, DAVINCI_CPU_ID_DM6467)
+IS_DAVINCI_CPU(dm355, DAVINCI_CPU_ID_DM355)
 
 #ifdef CONFIG_ARCH_DAVINCI_DM644x
 #define cpu_is_davinci_dm644x() is_davinci_dm644x()
index e6c0f0d5d06273525a69745a28e6d79e4aae841b..de3fc2182b47be849d7b7e98ec64cd0179471357 100644 (file)
@@ -9,6 +9,16 @@
  * or implied.
  */
 
+/* Modifications
+ * Jan 2009    Chaithrika U S  Added senduart, busyuart, waituart
+ *                             macros, based on debug-8250.S file
+ *                             but using 32-bit accesses required for
+ *                              some davinci devices.
+ */
+
+#include <linux/serial_reg.h>
+#define UART_SHIFT     2
+
                .macro addruart, rx
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ MMU enabled?
                orr     \rx, \rx, #0x00c20000   @ UART 0
                .endm
 
-#define UART_SHIFT     2
-#include <asm/hardware/debug-8250.S>
+               .macro  senduart,rd,rx
+               str     \rd, [\rx, #UART_TX << UART_SHIFT]
+               .endm
+
+               .macro  busyuart,rd,rx
+1002:          ldr     \rd, [\rx, #UART_LSR << UART_SHIFT]
+               and     \rd, \rd, #UART_LSR_TEMT | UART_LSR_THRE
+               teq     \rd, #UART_LSR_TEMT | UART_LSR_THRE
+               bne     1002b
+               .endm
+
+               .macro  waituart,rd,rx
+#ifdef FLOW_CONTROL
+1001:          ldr     \rd, [\rx, #UART_MSR << UART_SHIFT]
+               tst     \rd, #UART_MSR_CTS
+               beq     1001b
+#endif
+               .endm
+
diff --git a/arch/arm/mach-davinci/include/mach/dm355.h b/arch/arm/mach-davinci/include/mach/dm355.h
new file mode 100644 (file)
index 0000000..54903b7
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Chip specific defines for DM355 SoC
+ *
+ * Author: Kevin Hilman, Deep Root Systems, LLC
+ *
+ * 2007 (c) Deep Root Systems, LLC. 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_DM355_H
+#define __ASM_ARCH_DM355_H
+
+#include <mach/hardware.h>
+
+struct spi_board_info;
+
+void __init dm355_init(void);
+void dm355_init_spi0(unsigned chipselect_mask,
+               struct spi_board_info *info, unsigned len);
+
+#endif /* __ASM_ARCH_DM355_H */
index 3dcb9f4e58b47bb5f58bdf3e5db2fe0686b42093..15d42b92a8c92300554232b3f858f46d64c5ca86 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <linux/platform_device.h>
 #include <mach/hardware.h>
+#include <mach/emac.h>
 
 #define DM644X_EMAC_BASE               (0x01C80000)
 #define DM644X_EMAC_CNTRL_OFFSET       (0x0000)
diff --git a/arch/arm/mach-davinci/include/mach/dm646x.h b/arch/arm/mach-davinci/include/mach/dm646x.h
new file mode 100644 (file)
index 0000000..1fc764c
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Chip specific defines for DM646x SoC
+ *
+ * Author: Kevin Hilman, Deep Root Systems, LLC
+ *
+ * 2007 (c) Deep Root Systems, LLC. 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_DM646X_H
+#define __ASM_ARCH_DM646X_H
+
+#include <mach/hardware.h>
+#include <mach/emac.h>
+
+#define DM646X_EMAC_BASE               (0x01C80000)
+#define DM646X_EMAC_CNTRL_OFFSET       (0x0000)
+#define DM646X_EMAC_CNTRL_MOD_OFFSET   (0x1000)
+#define DM646X_EMAC_CNTRL_RAM_OFFSET   (0x2000)
+#define DM646X_EMAC_MDIO_OFFSET                (0x4000)
+#define DM646X_EMAC_CNTRL_RAM_SIZE     (0x2000)
+
+void __init dm646x_init(void);
+
+#endif /* __ASM_ARCH_DM646X_H */
index f6fc5396dafcdfeb9f9824e1da6faaa07a64e805..24a379239d7f836c3794af1e5d8218dac37463f4 100644 (file)
@@ -208,10 +208,6 @@ void edma_clear_event(unsigned channel);
 void edma_pause(unsigned channel);
 void edma_resume(unsigned channel);
 
-/* UNRELATED TO DMA */
-int davinci_alloc_iram(unsigned size);
-void davinci_free_iram(unsigned addr, unsigned size);
-
 /* platform_data for EDMA driver */
 struct edma_soc_info {
 
diff --git a/arch/arm/mach-davinci/include/mach/emac.h b/arch/arm/mach-davinci/include/mach/emac.h
new file mode 100644 (file)
index 0000000..beff4fb
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * TI DaVinci EMAC platform support
+ *
+ * Author: Kevin Hilman, Deep Root Systems, LLC
+ *
+ * 2007 (c) Deep Root Systems, LLC. 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_DAVINCI_EMAC_H
+#define _MACH_DAVINCI_EMAC_H
+
+#include <linux/if_ether.h>
+#include <linux/memory.h>
+
+struct emac_platform_data {
+       char mac_addr[ETH_ALEN];
+       u32 ctrl_reg_offset;
+       u32 ctrl_mod_reg_offset;
+       u32 ctrl_ram_offset;
+       u32 mdio_reg_offset;
+       u32 ctrl_ram_size;
+       u32 phy_mask;
+       u32 mdio_max_freq;
+       u8 rmii_en;
+       u8 version;
+};
+
+enum {
+       EMAC_VERSION_1, /* DM644x */
+       EMAC_VERSION_2, /* DM646x */
+};
+
+void davinci_get_mac_addr(struct memory_accessor *mem_acc, void *context);
+#endif
index 039b84f933b327742460ef7bdb13ae9ecedfb0e6..fbdebc7cb409828dddaf0d8f6e575309ca07be0f 100644 (file)
                .endm
 
                .macro  get_irqnr_preamble, base, tmp
-               ldr \base, =IO_ADDRESS(DAVINCI_ARM_INTC_BASE)
+               ldr \base, =davinci_intc_base
+               ldr \base, [\base]
                .endm
 
                .macro  arch_ret_to_user, tmp1, tmp2
                .endm
 
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
+#if defined(CONFIG_AINTC) && defined(CONFIG_CP_INTC)
+               ldr \tmp, =davinci_intc_type
+               ldr \tmp, [\tmp]
+               cmp \tmp, #DAVINCI_INTC_TYPE_CP_INTC
+               beq 1001f
+#endif
+#if defined(CONFIG_AINTC)
                ldr \tmp, [\base, #0x14]
-               mov \tmp, \tmp, lsr #2
+               movs \tmp, \tmp, lsr #2
                sub \irqnr, \tmp, #1
-               cmp \tmp, #0
+               b 1002f
+#endif
+#if defined(CONFIG_CP_INTC)
+1001:          ldr \irqnr, [\base, #0x80] /* get irq number */
+               and \irqnr, \irqnr, #0xff  /* irq is in bits 0-9 */
+               mov \tmp, \irqnr, lsr #3
+               and \tmp, \tmp, #0xfc
+               add \tmp, \tmp, #0x280 /* get the register offset */
+               ldr \irqstat, [\base, \tmp] /* get the intc status */
+               cmp \irqstat, #0x0
+#endif
+1002:
                .endm
 
                .macro  irq_prio_table
index efe3281364e6367f681926625d782ac628e1d00a..ae07455683162117c30fec9e3cf0ea157ca8dd2d 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm-generic/gpio.h>
 
 #include <mach/irqs.h>
+#include <mach/common.h>
 
 #define DAVINCI_GPIO_BASE 0x01C67000
 
@@ -67,15 +68,16 @@ static inline struct gpio_controller *__iomem
 __gpio_to_controller(unsigned gpio)
 {
        void *__iomem ptr;
+       void __iomem *base = davinci_soc_info.gpio_base;
 
        if (gpio < 32 * 1)
-               ptr = IO_ADDRESS(DAVINCI_GPIO_BASE + 0x10);
+               ptr = base + 0x10;
        else if (gpio < 32 * 2)
-               ptr = IO_ADDRESS(DAVINCI_GPIO_BASE + 0x38);
+               ptr = base + 0x38;
        else if (gpio < 32 * 3)
-               ptr = IO_ADDRESS(DAVINCI_GPIO_BASE + 0x60);
+               ptr = base + 0x60;
        else if (gpio < 32 * 4)
-               ptr = IO_ADDRESS(DAVINCI_GPIO_BASE + 0x88);
+               ptr = base + 0x88;
        else
                ptr = NULL;
        return ptr;
@@ -142,13 +144,13 @@ static inline int gpio_to_irq(unsigned gpio)
 {
        if (gpio >= DAVINCI_N_GPIO)
                return -EINVAL;
-       return DAVINCI_N_AINTC_IRQ + gpio;
+       return davinci_soc_info.intc_irq_num + gpio;
 }
 
 static inline int irq_to_gpio(unsigned irq)
 {
        /* caller guarantees gpio_to_irq() succeeded */
-       return irq - DAVINCI_N_AINTC_IRQ;
+       return irq - davinci_soc_info.intc_irq_num;
 }
 
 #endif                         /* __DAVINCI_GPIO_H */
index 18066074c9959a5498f88d9313a913c2089b42ac..bc5d6aaa69a3ed86e52c4aa55742ac6b8747d06e 100644 (file)
@@ -30,6 +30,9 @@
 /* Base address */
 #define DAVINCI_ARM_INTC_BASE 0x01C48000
 
+#define DAVINCI_INTC_TYPE_AINTC                0
+#define DAVINCI_INTC_TYPE_CP_INTC      1
+
 /* Interrupt lines */
 #define IRQ_VDINT0       0
 #define IRQ_VDINT1       1
index 86c25c7f3ce30f2014a98d50511ab3dc048c9e6f..c712c7cdf38f60af046ca3920d5fd32e351fd095 100644 (file)
@@ -21,7 +21,6 @@
  * Definitions
  **************************************************************************/
 #define DAVINCI_DDR_BASE    0x80000000
-#define DAVINCI_IRAM_BASE   0x00008000 /* ARM Internal RAM */
 
 #define PHYS_OFFSET DAVINCI_DDR_BASE
 
diff --git a/arch/arm/mach-davinci/include/mach/mmc.h b/arch/arm/mach-davinci/include/mach/mmc.h
new file mode 100644 (file)
index 0000000..5a85e24
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ *  Board-specific MMC configuration
+ */
+
+#ifndef _DAVINCI_MMC_H
+#define _DAVINCI_MMC_H
+
+#include <linux/types.h>
+#include <linux/mmc/host.h>
+
+struct davinci_mmc_config {
+       /* get_cd()/get_wp() may sleep */
+       int     (*get_cd)(int module);
+       int     (*get_ro)(int module);
+       /* wires == 0 is equivalent to wires == 4 (4-bit parallel) */
+       u8      wires;
+
+       u32     max_freq;
+
+       /* any additional host capabilities: OR'd in to mmc->f_caps */
+       u32     caps;
+
+       /* Version of the MMC/SD controller */
+       u8      version;
+};
+void davinci_setup_mmc(int module, struct davinci_mmc_config *config);
+
+enum {
+       MMC_CTLR_VERSION_1 = 0, /* DM644x and DM355 */
+       MMC_CTLR_VERSION_2,     /* DA830 */
+};
+
+#endif
index bae22cb3e27b6443c71f2bb6a448d0f85b254a08..27378458542fe80ce107aed2cccfeec48f08cf54 100644 (file)
 #ifndef __INC_MACH_MUX_H
 #define __INC_MACH_MUX_H
 
-/* System module registers */
-#define PINMUX0                        0x00
-#define PINMUX1                        0x04
-/* dm355 only */
-#define PINMUX2                        0x08
-#define PINMUX3                        0x0c
-#define PINMUX4                        0x10
-#define INTMUX                 0x18
-#define EVTMUX                 0x1c
-
 struct mux_config {
        const char *name;
        const char *mux_reg_name;
@@ -168,15 +158,9 @@ enum davinci_dm355_index {
 
 #ifdef CONFIG_DAVINCI_MUX
 /* setup pin muxing */
-extern void davinci_mux_init(void);
-extern int davinci_mux_register(const struct mux_config *pins,
-                               unsigned long size);
 extern int davinci_cfg_reg(unsigned long reg_cfg);
 #else
 /* boot loader does it all (no warnings from CONFIG_DAVINCI_MUX_WARNINGS) */
-static inline void davinci_mux_init(void) {}
-static inline int davinci_mux_register(const struct mux_config *pins,
-                                      unsigned long size) { return 0; }
 static inline int davinci_cfg_reg(unsigned long reg_cfg) { return 0; }
 #endif
 
index 55a90d419fac2b17dc62732b98365e531c8a56a9..ab8a2586d1cc7e2767043166f2c40ed4bb5cd052 100644 (file)
@@ -27,6 +27,8 @@
 #ifndef __ASM_ARCH_PSC_H
 #define __ASM_ARCH_PSC_H
 
+#define        DAVINCI_PWR_SLEEP_CNTRL_BASE    0x01C41000
+
 /* Power and Sleep Controller (PSC) Domains */
 #define DAVINCI_GPSC_ARMDOMAIN      0
 #define DAVINCI_GPSC_DSPDOMAIN      1
 #define DM646X_LPSC_TIMER1         35
 #define DM646X_LPSC_ARM_INTC       45
 
-extern int davinci_psc_is_clk_active(unsigned int id);
-extern void davinci_psc_config(unsigned int domain, unsigned int id,
-                              char enable);
+extern int davinci_psc_is_clk_active(unsigned int ctlr, unsigned int id);
+extern void davinci_psc_config(unsigned int domain, unsigned int ctlr,
+               unsigned int id, char enable);
 
 #endif /* __ASM_ARCH_PSC_H */
index 632847d74a1ce9ea1eb491502b6003b6dc529ab7..794fa5cf93c1556784eb11890dd4946c8159906b 100644 (file)
@@ -18,8 +18,6 @@
 #define DAVINCI_UART1_BASE     (IO_PHYS + 0x20400)
 #define DAVINCI_UART2_BASE     (IO_PHYS + 0x20800)
 
-#define DM355_UART2_BASE       (IO_PHYS + 0x206000)
-
 /* DaVinci UART register offsets */
 #define UART_DAVINCI_PWREMU            0x0c
 #define UART_DM646X_SCR                        0x10
@@ -30,6 +28,6 @@ struct davinci_uart_config {
        unsigned int enabled_uarts;
 };
 
-extern void davinci_serial_init(struct davinci_uart_config *);
+extern int davinci_serial_init(struct davinci_uart_config *);
 
 #endif /* __ASM_ARCH_SERIAL_H */
diff --git a/arch/arm/mach-davinci/include/mach/sram.h b/arch/arm/mach-davinci/include/mach/sram.h
new file mode 100644 (file)
index 0000000..111f7cc
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * mach/sram.h - DaVinci simple SRAM allocator
+ *
+ * Copyright (C) 2009 David Brownell
+ *
+ * This 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 __MACH_SRAM_H
+#define __MACH_SRAM_H
+
+/* ARBITRARY:  SRAM allocations are multiples of this 2^N size */
+#define SRAM_GRANULARITY       512
+
+/*
+ * SRAM allocations return a CPU virtual address, or NULL on error.
+ * If a DMA address is requested and the SRAM supports DMA, its
+ * mapped address is also returned.
+ *
+ * Errors include SRAM memory not being available, and requesting
+ * DMA mapped SRAM on systems which don't allow that.
+ */
+extern void *sram_alloc(size_t len, dma_addr_t *dma);
+extern void sram_free(void *addr, size_t len);
+
+#endif /* __MACH_SRAM_H */
diff --git a/arch/arm/mach-davinci/include/mach/time.h b/arch/arm/mach-davinci/include/mach/time.h
new file mode 100644 (file)
index 0000000..1c971d8
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Local header file for DaVinci time code.
+ *
+ * Author: Kevin Hilman, MontaVista Software, Inc. <source@mvista.com>
+ *
+ * 2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#ifndef __ARCH_ARM_MACH_DAVINCI_TIME_H
+#define __ARCH_ARM_MACH_DAVINCI_TIME_H
+
+#define DAVINCI_TIMER0_BASE            (IO_PHYS + 0x21400)
+#define DAVINCI_TIMER1_BASE            (IO_PHYS + 0x21800)
+#define DAVINCI_WDOG_BASE              (IO_PHYS + 0x21C00)
+
+enum {
+       T0_BOT,
+       T0_TOP,
+       T1_BOT,
+       T1_TOP,
+       NUM_TIMERS
+};
+
+#define IS_TIMER1(id)          (id & 0x2)
+#define IS_TIMER0(id)          (!IS_TIMER1(id))
+#define IS_TIMER_TOP(id)       ((id & 0x1))
+#define IS_TIMER_BOT(id)       (!IS_TIMER_TOP(id))
+
+#define ID_TO_TIMER(id)                (IS_TIMER1(id) != 0)
+
+extern struct davinci_timer_instance davinci_timer_instance[];
+
+#endif /* __ARCH_ARM_MACH_DAVINCI_TIME_H */
index 8c165def37b6d853f958db165de5b315ef48526d..1e27475f9a2322f1a4f61e25fd1a1e5858e29fc2 100644 (file)
 #include <linux/serial_reg.h>
 #include <mach/serial.h>
 
+#include <asm/mach-types.h>
+
+extern unsigned int __machine_arch_type;
+
+static u32 *uart;
+
+static u32 *get_uart_base(void)
+{
+       /* Add logic here for new platforms, using __macine_arch_type */
+       return (u32 *)DAVINCI_UART0_BASE;
+}
+
 /* PORT_16C550A, in polled non-fifo mode */
 
 static void putc(char c)
 {
-       volatile u32 *uart = (volatile void *) DAVINCI_UART0_BASE;
+       if (!uart)
+               uart = get_uart_base();
 
        while (!(uart[UART_LSR] & UART_LSR_THRE))
                barrier();
@@ -26,7 +39,9 @@ static void putc(char c)
 
 static inline void flush(void)
 {
-       volatile u32 *uart = (volatile void *) DAVINCI_UART0_BASE;
+       if (!uart)
+               uart = get_uart_base();
+
        while (!(uart[UART_LSR] & UART_LSR_THRE))
                barrier();
 }
index a548abb513e2d559108a53184cb5abaa90c9df09..49912b48b1b0f7a26c2b65729686687f84bb460a 100644 (file)
@@ -9,47 +9,9 @@
  */
 
 #include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/io.h>
 
 #include <asm/tlb.h>
-#include <asm/memory.h>
-
-#include <asm/mach/map.h>
-#include <mach/clock.h>
-
-extern void davinci_check_revision(void);
-
-/*
- * The machine specific code may provide the extra mapping besides the
- * default mapping provided here.
- */
-static struct map_desc davinci_io_desc[] __initdata = {
-       {
-               .virtual        = IO_VIRT,
-               .pfn            = __phys_to_pfn(IO_PHYS),
-               .length         = IO_SIZE,
-               .type           = MT_DEVICE
-       },
-};
-
-void __init davinci_map_common_io(void)
-{
-       iotable_init(davinci_io_desc, ARRAY_SIZE(davinci_io_desc));
-
-       /* Normally devicemaps_init() would flush caches and tlb after
-        * mdesc->map_io(), but we must also do it here because of the CPU
-        * revision check below.
-        */
-       local_flush_tlb_all();
-       flush_cache_all();
-
-       /* We want to check CPU revision early for cpu_is_xxxx() macros.
-        * IO space mapping must be initialized before we can do that.
-        */
-       davinci_check_revision();
-}
 
 #define BETWEEN(p, st, sz)     ((p) >= (st) && (p) < ((st) + (sz)))
 #define XLATE(p, pst, vst)     ((void __iomem *)((p) - (pst) + (vst)))
index 5a324c90e291f4c0ce88d4fef865654d4ab51498..af92ffee84714067f3e4ef543762ec758bf98a52 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <mach/hardware.h>
 #include <mach/cputype.h>
+#include <mach/common.h>
 #include <asm/mach/irq.h>
 
 #define IRQ_BIT(irq)           ((irq) & 0x1f)
 #define IRQ_INTPRI0_REG_OFFSET 0x0030
 #define IRQ_INTPRI7_REG_OFFSET 0x004C
 
-const u8 *davinci_def_priorities;
-
-#define INTC_BASE IO_ADDRESS(DAVINCI_ARM_INTC_BASE)
-
 static inline unsigned int davinci_irq_readl(int offset)
 {
-       return __raw_readl(INTC_BASE + offset);
+       return __raw_readl(davinci_intc_base + offset);
 }
 
 static inline void davinci_irq_writel(unsigned long value, int offset)
 {
-       __raw_writel(value, INTC_BASE + offset);
+       __raw_writel(value, davinci_intc_base + offset);
 }
 
 /* Disable interrupt */
@@ -113,217 +110,11 @@ static struct irq_chip davinci_irq_chip_0 = {
        .unmask = davinci_unmask_irq,
 };
 
-/* FIQ are pri 0-1; otherwise 2-7, with 7 lowest priority */
-static const u8 dm644x_default_priorities[DAVINCI_N_AINTC_IRQ] __initdata = {
-       [IRQ_VDINT0]            = 2,
-       [IRQ_VDINT1]            = 6,
-       [IRQ_VDINT2]            = 6,
-       [IRQ_HISTINT]           = 6,
-       [IRQ_H3AINT]            = 6,
-       [IRQ_PRVUINT]           = 6,
-       [IRQ_RSZINT]            = 6,
-       [7]                     = 7,
-       [IRQ_VENCINT]           = 6,
-       [IRQ_ASQINT]            = 6,
-       [IRQ_IMXINT]            = 6,
-       [IRQ_VLCDINT]           = 6,
-       [IRQ_USBINT]            = 4,
-       [IRQ_EMACINT]           = 4,
-       [14]                    = 7,
-       [15]                    = 7,
-       [IRQ_CCINT0]            = 5,    /* dma */
-       [IRQ_CCERRINT]          = 5,    /* dma */
-       [IRQ_TCERRINT0]         = 5,    /* dma */
-       [IRQ_TCERRINT]          = 5,    /* dma */
-       [IRQ_PSCIN]             = 7,
-       [21]                    = 7,
-       [IRQ_IDE]               = 4,
-       [23]                    = 7,
-       [IRQ_MBXINT]            = 7,
-       [IRQ_MBRINT]            = 7,
-       [IRQ_MMCINT]            = 7,
-       [IRQ_SDIOINT]           = 7,
-       [28]                    = 7,
-       [IRQ_DDRINT]            = 7,
-       [IRQ_AEMIFINT]          = 7,
-       [IRQ_VLQINT]            = 4,
-       [IRQ_TINT0_TINT12]      = 2,    /* clockevent */
-       [IRQ_TINT0_TINT34]      = 2,    /* clocksource */
-       [IRQ_TINT1_TINT12]      = 7,    /* DSP timer */
-       [IRQ_TINT1_TINT34]      = 7,    /* system tick */
-       [IRQ_PWMINT0]           = 7,
-       [IRQ_PWMINT1]           = 7,
-       [IRQ_PWMINT2]           = 7,
-       [IRQ_I2C]               = 3,
-       [IRQ_UARTINT0]          = 3,
-       [IRQ_UARTINT1]          = 3,
-       [IRQ_UARTINT2]          = 3,
-       [IRQ_SPINT0]            = 3,
-       [IRQ_SPINT1]            = 3,
-       [45]                    = 7,
-       [IRQ_DSP2ARM0]          = 4,
-       [IRQ_DSP2ARM1]          = 4,
-       [IRQ_GPIO0]             = 7,
-       [IRQ_GPIO1]             = 7,
-       [IRQ_GPIO2]             = 7,
-       [IRQ_GPIO3]             = 7,
-       [IRQ_GPIO4]             = 7,
-       [IRQ_GPIO5]             = 7,
-       [IRQ_GPIO6]             = 7,
-       [IRQ_GPIO7]             = 7,
-       [IRQ_GPIOBNK0]          = 7,
-       [IRQ_GPIOBNK1]          = 7,
-       [IRQ_GPIOBNK2]          = 7,
-       [IRQ_GPIOBNK3]          = 7,
-       [IRQ_GPIOBNK4]          = 7,
-       [IRQ_COMMTX]            = 7,
-       [IRQ_COMMRX]            = 7,
-       [IRQ_EMUINT]            = 7,
-};
-
-static const u8 dm646x_default_priorities[DAVINCI_N_AINTC_IRQ] = {
-       [IRQ_DM646X_VP_VERTINT0]        = 7,
-       [IRQ_DM646X_VP_VERTINT1]        = 7,
-       [IRQ_DM646X_VP_VERTINT2]        = 7,
-       [IRQ_DM646X_VP_VERTINT3]        = 7,
-       [IRQ_DM646X_VP_ERRINT]          = 7,
-       [IRQ_DM646X_RESERVED_1]         = 7,
-       [IRQ_DM646X_RESERVED_2]         = 7,
-       [IRQ_DM646X_WDINT]              = 7,
-       [IRQ_DM646X_CRGENINT0]          = 7,
-       [IRQ_DM646X_CRGENINT1]          = 7,
-       [IRQ_DM646X_TSIFINT0]           = 7,
-       [IRQ_DM646X_TSIFINT1]           = 7,
-       [IRQ_DM646X_VDCEINT]            = 7,
-       [IRQ_DM646X_USBINT]             = 7,
-       [IRQ_DM646X_USBDMAINT]          = 7,
-       [IRQ_DM646X_PCIINT]             = 7,
-       [IRQ_CCINT0]                    = 7,    /* dma */
-       [IRQ_CCERRINT]                  = 7,    /* dma */
-       [IRQ_TCERRINT0]                 = 7,    /* dma */
-       [IRQ_TCERRINT]                  = 7,    /* dma */
-       [IRQ_DM646X_TCERRINT2]          = 7,
-       [IRQ_DM646X_TCERRINT3]          = 7,
-       [IRQ_DM646X_IDE]                = 7,
-       [IRQ_DM646X_HPIINT]             = 7,
-       [IRQ_DM646X_EMACRXTHINT]        = 7,
-       [IRQ_DM646X_EMACRXINT]          = 7,
-       [IRQ_DM646X_EMACTXINT]          = 7,
-       [IRQ_DM646X_EMACMISCINT]        = 7,
-       [IRQ_DM646X_MCASP0TXINT]        = 7,
-       [IRQ_DM646X_MCASP0RXINT]        = 7,
-       [IRQ_AEMIFINT]                  = 7,
-       [IRQ_DM646X_RESERVED_3]         = 7,
-       [IRQ_DM646X_MCASP1TXINT]        = 7,    /* clockevent */
-       [IRQ_TINT0_TINT34]              = 7,    /* clocksource */
-       [IRQ_TINT1_TINT12]              = 7,    /* DSP timer */
-       [IRQ_TINT1_TINT34]              = 7,    /* system tick */
-       [IRQ_PWMINT0]                   = 7,
-       [IRQ_PWMINT1]                   = 7,
-       [IRQ_DM646X_VLQINT]             = 7,
-       [IRQ_I2C]                       = 7,
-       [IRQ_UARTINT0]                  = 7,
-       [IRQ_UARTINT1]                  = 7,
-       [IRQ_DM646X_UARTINT2]           = 7,
-       [IRQ_DM646X_SPINT0]             = 7,
-       [IRQ_DM646X_SPINT1]             = 7,
-       [IRQ_DM646X_DSP2ARMINT]         = 7,
-       [IRQ_DM646X_RESERVED_4]         = 7,
-       [IRQ_DM646X_PSCINT]             = 7,
-       [IRQ_DM646X_GPIO0]              = 7,
-       [IRQ_DM646X_GPIO1]              = 7,
-       [IRQ_DM646X_GPIO2]              = 7,
-       [IRQ_DM646X_GPIO3]              = 7,
-       [IRQ_DM646X_GPIO4]              = 7,
-       [IRQ_DM646X_GPIO5]              = 7,
-       [IRQ_DM646X_GPIO6]              = 7,
-       [IRQ_DM646X_GPIO7]              = 7,
-       [IRQ_DM646X_GPIOBNK0]           = 7,
-       [IRQ_DM646X_GPIOBNK1]           = 7,
-       [IRQ_DM646X_GPIOBNK2]           = 7,
-       [IRQ_DM646X_DDRINT]             = 7,
-       [IRQ_DM646X_AEMIFINT]           = 7,
-       [IRQ_COMMTX]                    = 7,
-       [IRQ_COMMRX]                    = 7,
-       [IRQ_EMUINT]                    = 7,
-};
-
-static const u8 dm355_default_priorities[DAVINCI_N_AINTC_IRQ] = {
-       [IRQ_DM355_CCDC_VDINT0]         = 2,
-       [IRQ_DM355_CCDC_VDINT1]         = 6,
-       [IRQ_DM355_CCDC_VDINT2]         = 6,
-       [IRQ_DM355_IPIPE_HST]           = 6,
-       [IRQ_DM355_H3AINT]              = 6,
-       [IRQ_DM355_IPIPE_SDR]           = 6,
-       [IRQ_DM355_IPIPEIFINT]          = 6,
-       [IRQ_DM355_OSDINT]              = 7,
-       [IRQ_DM355_VENCINT]             = 6,
-       [IRQ_ASQINT]                    = 6,
-       [IRQ_IMXINT]                    = 6,
-       [IRQ_USBINT]                    = 4,
-       [IRQ_DM355_RTOINT]              = 4,
-       [IRQ_DM355_UARTINT2]            = 7,
-       [IRQ_DM355_TINT6]               = 7,
-       [IRQ_CCINT0]                    = 5,    /* dma */
-       [IRQ_CCERRINT]                  = 5,    /* dma */
-       [IRQ_TCERRINT0]                 = 5,    /* dma */
-       [IRQ_TCERRINT]                  = 5,    /* dma */
-       [IRQ_DM355_SPINT2_1]            = 7,
-       [IRQ_DM355_TINT7]               = 4,
-       [IRQ_DM355_SDIOINT0]            = 7,
-       [IRQ_MBXINT]                    = 7,
-       [IRQ_MBRINT]                    = 7,
-       [IRQ_MMCINT]                    = 7,
-       [IRQ_DM355_MMCINT1]             = 7,
-       [IRQ_DM355_PWMINT3]             = 7,
-       [IRQ_DDRINT]                    = 7,
-       [IRQ_AEMIFINT]                  = 7,
-       [IRQ_DM355_SDIOINT1]            = 4,
-       [IRQ_TINT0_TINT12]              = 2,    /* clockevent */
-       [IRQ_TINT0_TINT34]              = 2,    /* clocksource */
-       [IRQ_TINT1_TINT12]              = 7,    /* DSP timer */
-       [IRQ_TINT1_TINT34]              = 7,    /* system tick */
-       [IRQ_PWMINT0]                   = 7,
-       [IRQ_PWMINT1]                   = 7,
-       [IRQ_PWMINT2]                   = 7,
-       [IRQ_I2C]                       = 3,
-       [IRQ_UARTINT0]                  = 3,
-       [IRQ_UARTINT1]                  = 3,
-       [IRQ_DM355_SPINT0_0]            = 3,
-       [IRQ_DM355_SPINT0_1]            = 3,
-       [IRQ_DM355_GPIO0]               = 3,
-       [IRQ_DM355_GPIO1]               = 7,
-       [IRQ_DM355_GPIO2]               = 4,
-       [IRQ_DM355_GPIO3]               = 4,
-       [IRQ_DM355_GPIO4]               = 7,
-       [IRQ_DM355_GPIO5]               = 7,
-       [IRQ_DM355_GPIO6]               = 7,
-       [IRQ_DM355_GPIO7]               = 7,
-       [IRQ_DM355_GPIO8]               = 7,
-       [IRQ_DM355_GPIO9]               = 7,
-       [IRQ_DM355_GPIOBNK0]            = 7,
-       [IRQ_DM355_GPIOBNK1]            = 7,
-       [IRQ_DM355_GPIOBNK2]            = 7,
-       [IRQ_DM355_GPIOBNK3]            = 7,
-       [IRQ_DM355_GPIOBNK4]            = 7,
-       [IRQ_DM355_GPIOBNK5]            = 7,
-       [IRQ_DM355_GPIOBNK6]            = 7,
-       [IRQ_COMMTX]                    = 7,
-       [IRQ_COMMRX]                    = 7,
-       [IRQ_EMUINT]                    = 7,
-};
-
 /* ARM Interrupt Controller Initialization */
 void __init davinci_irq_init(void)
 {
        unsigned i;
-
-       if (cpu_is_davinci_dm644x())
-               davinci_def_priorities = dm644x_default_priorities;
-       else if (cpu_is_davinci_dm646x())
-               davinci_def_priorities = dm646x_default_priorities;
-       else if (cpu_is_davinci_dm355())
-               davinci_def_priorities = dm355_default_priorities;
+       const u8 *davinci_def_priorities = davinci_soc_info.intc_irq_prios;
 
        /* Clear all interrupt requests */
        davinci_irq_writel(~0x0, FIQ_REG0_OFFSET);
index bbba0b247a447bd7e17a2f86ee35bffc66343de3..d310f579aa853329f811699d7ed93cf22525b2bf 100644 (file)
 
 #include <mach/hardware.h>
 #include <mach/mux.h>
-
-static const struct mux_config *mux_table;
-static unsigned long pin_table_sz;
-
-int __init davinci_mux_register(const struct mux_config *pins,
-                               unsigned long size)
-{
-       mux_table = pins;
-       pin_table_sz = size;
-
-       return 0;
-}
+#include <mach/common.h>
 
 /*
  * Sets the DAVINCI MUX register based on the table
@@ -40,23 +29,24 @@ int __init davinci_mux_register(const struct mux_config *pins,
 int __init_or_module davinci_cfg_reg(const unsigned long index)
 {
        static DEFINE_SPINLOCK(mux_spin_lock);
-       void __iomem *base = IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE);
+       struct davinci_soc_info *soc_info = &davinci_soc_info;
+       void __iomem *base = soc_info->pinmux_base;
        unsigned long flags;
        const struct mux_config *cfg;
        unsigned int reg_orig = 0, reg = 0;
        unsigned int mask, warn = 0;
 
-       if (!mux_table)
+       if (!soc_info->pinmux_pins)
                BUG();
 
-       if (index >= pin_table_sz) {
+       if (index >= soc_info->pinmux_pins_num) {
                printk(KERN_ERR "Invalid pin mux index: %lu (%lu)\n",
-                      index, pin_table_sz);
+                      index, soc_info->pinmux_pins_num);
                dump_stack();
                return -ENODEV;
        }
 
-       cfg = &mux_table[index];
+       cfg = &soc_info->pinmux_pins[index];
 
        if (cfg->name == NULL) {
                printk(KERN_ERR "No entry for the specified index\n");
index 84171abf5f7b25453af26092006939617ac99237..a78b657e916e9c44425e8c913e6160bc833089bc 100644 (file)
@@ -28,8 +28,6 @@
 #include <mach/psc.h>
 #include <mach/mux.h>
 
-#define DAVINCI_PWR_SLEEP_CNTRL_BASE 0x01C41000
-
 /* PSC register offsets */
 #define EPCPR          0x070
 #define PTCMD          0x120
 #define MDSTAT_STATE_MASK 0x1f
 
 /* Return nonzero iff the domain's clock is active */
-int __init davinci_psc_is_clk_active(unsigned int id)
+int __init davinci_psc_is_clk_active(unsigned int ctlr, unsigned int id)
 {
-       void __iomem *psc_base = IO_ADDRESS(DAVINCI_PWR_SLEEP_CNTRL_BASE);
-       u32 mdstat = __raw_readl(psc_base + MDSTAT + 4 * id);
+       void __iomem *psc_base;
+       u32 mdstat;
+       struct davinci_soc_info *soc_info = &davinci_soc_info;
+
+       if (!soc_info->psc_bases || (ctlr >= soc_info->psc_bases_num)) {
+               pr_warning("PSC: Bad psc data: 0x%x[%d]\n",
+                               (int)soc_info->psc_bases, ctlr);
+               return 0;
+       }
+
+       psc_base = soc_info->psc_bases[ctlr];
+       mdstat = __raw_readl(psc_base + MDSTAT + 4 * id);
 
        /* if clocked, state can be "Enable" or "SyncReset" */
        return mdstat & BIT(12);
 }
 
 /* Enable or disable a PSC domain */
-void davinci_psc_config(unsigned int domain, unsigned int id, char enable)
+void davinci_psc_config(unsigned int domain, unsigned int ctlr,
+               unsigned int id, char enable)
 {
        u32 epcpr, ptcmd, ptstat, pdstat, pdctl1, mdstat, mdctl;
-       void __iomem *psc_base = IO_ADDRESS(DAVINCI_PWR_SLEEP_CNTRL_BASE);
+       void __iomem *psc_base;
+       struct davinci_soc_info *soc_info = &davinci_soc_info;
        u32 next_state = enable ? 0x3 : 0x2; /* 0x3 enables, 0x2 disables */
 
+       if (!soc_info->psc_bases || (ctlr >= soc_info->psc_bases_num)) {
+               pr_warning("PSC: Bad psc data: 0x%x[%d]\n",
+                               (int)soc_info->psc_bases, ctlr);
+               return;
+       }
+
+       psc_base = soc_info->psc_bases[ctlr];
+
        mdctl = __raw_readl(psc_base + MDCTL + 4 * id);
        mdctl &= ~MDSTAT_STATE_MASK;
        mdctl |= next_state;
index 695075796522af28163b975daea57533c2e61bf7..c530c7333d0a311c314c7ef3d2bd8291afc1bd89 100644 (file)
@@ -33,6 +33,8 @@
 #include <mach/serial.h>
 #include <mach/irqs.h>
 #include <mach/cputype.h>
+#include <mach/common.h>
+
 #include "clock.h"
 
 static inline unsigned int serial_read_reg(struct plat_serial8250_port *up,
@@ -49,44 +51,6 @@ static inline void serial_write_reg(struct plat_serial8250_port *p, int offset,
        __raw_writel(value, IO_ADDRESS(p->mapbase) + offset);
 }
 
-static struct plat_serial8250_port serial_platform_data[] = {
-       {
-               .mapbase        = DAVINCI_UART0_BASE,
-               .irq            = IRQ_UARTINT0,
-               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
-                                 UPF_IOREMAP,
-               .iotype         = UPIO_MEM,
-               .regshift       = 2,
-       },
-       {
-               .mapbase        = DAVINCI_UART1_BASE,
-               .irq            = IRQ_UARTINT1,
-               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
-                                 UPF_IOREMAP,
-               .iotype         = UPIO_MEM,
-               .regshift       = 2,
-       },
-       {
-               .mapbase        = DAVINCI_UART2_BASE,
-               .irq            = IRQ_UARTINT2,
-               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
-                                 UPF_IOREMAP,
-               .iotype         = UPIO_MEM,
-               .regshift       = 2,
-       },
-       {
-               .flags          = 0
-       },
-};
-
-static struct platform_device serial_device = {
-       .name                   = "serial8250",
-       .id                     = PLAT8250_DEV_PLATFORM,
-       .dev                    = {
-               .platform_data  = serial_platform_data,
-       },
-};
-
 static void __init davinci_serial_reset(struct plat_serial8250_port *p)
 {
        unsigned int pwremu = 0;
@@ -106,35 +70,22 @@ static void __init davinci_serial_reset(struct plat_serial8250_port *p)
                                 UART_DM646X_SCR_TX_WATERMARK);
 }
 
-void __init davinci_serial_init(struct davinci_uart_config *info)
+int __init davinci_serial_init(struct davinci_uart_config *info)
 {
        int i;
        char name[16];
        struct clk *uart_clk;
-       struct device *dev = &serial_device.dev;
+       struct davinci_soc_info *soc_info = &davinci_soc_info;
+       struct device *dev = &soc_info->serial_dev->dev;
+       struct plat_serial8250_port *p = dev->platform_data;
 
        /*
         * Make sure the serial ports are muxed on at this point.
-        * You have to mux them off in device drivers later on
-        * if not needed.
+        * You have to mux them off in device drivers later on if not needed.
         */
-       for (i = 0; i < DAVINCI_MAX_NR_UARTS; i++) {
-               struct plat_serial8250_port *p = serial_platform_data + i;
-
-               if (!(info->enabled_uarts & (1 << i))) {
-                       p->flags = 0;
+       for (i = 0; i < DAVINCI_MAX_NR_UARTS; i++, p++) {
+               if (!(info->enabled_uarts & (1 << i)))
                        continue;
-               }
-
-               if (cpu_is_davinci_dm646x())
-                       p->iotype = UPIO_MEM32;
-
-               if (cpu_is_davinci_dm355()) {
-                       if (i == 2) {
-                               p->mapbase = (unsigned long)DM355_UART2_BASE;
-                               p->irq = IRQ_DM355_UARTINT2;
-                       }
-               }
 
                sprintf(name, "uart%d", i);
                uart_clk = clk_get(dev, name);
@@ -147,11 +98,6 @@ void __init davinci_serial_init(struct davinci_uart_config *info)
                        davinci_serial_reset(p);
                }
        }
-}
 
-static int __init davinci_init(void)
-{
-       return platform_device_register(&serial_device);
+       return platform_device_register(soc_info->serial_dev);
 }
-
-arch_initcall(davinci_init);
diff --git a/arch/arm/mach-davinci/sram.c b/arch/arm/mach-davinci/sram.c
new file mode 100644 (file)
index 0000000..db54b2a
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * mach-davinci/sram.c - DaVinci simple SRAM allocator
+ *
+ * Copyright (C) 2009 David Brownell
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/genalloc.h>
+
+#include <mach/common.h>
+#include <mach/memory.h>
+#include <mach/sram.h>
+
+
+static struct gen_pool *sram_pool;
+
+void *sram_alloc(size_t len, dma_addr_t *dma)
+{
+       unsigned long vaddr;
+       dma_addr_t dma_base = davinci_soc_info.sram_dma;
+
+       if (dma)
+               *dma = 0;
+       if (!sram_pool || (dma && !dma_base))
+               return NULL;
+
+       vaddr = gen_pool_alloc(sram_pool, len);
+       if (!vaddr)
+               return NULL;
+
+       if (dma)
+               *dma = dma_base + (vaddr - SRAM_VIRT);
+       return (void *)vaddr;
+
+}
+EXPORT_SYMBOL(sram_alloc);
+
+void sram_free(void *addr, size_t len)
+{
+       gen_pool_free(sram_pool, (unsigned long) addr, len);
+}
+EXPORT_SYMBOL(sram_free);
+
+
+/*
+ * REVISIT This supports CPU and DMA access to/from SRAM, but it
+ * doesn't (yet?) support some other notable uses of SRAM:  as TCM
+ * for data and/or instructions; and holding code needed to enter
+ * and exit suspend states (while DRAM can't be used).
+ */
+static int __init sram_init(void)
+{
+       unsigned len = davinci_soc_info.sram_len;
+       int status = 0;
+
+       if (len) {
+               len = min(len, SRAM_SIZE);
+               sram_pool = gen_pool_create(ilog2(SRAM_GRANULARITY), -1);
+               if (!sram_pool)
+                       status = -ENOMEM;
+       }
+       if (sram_pool)
+               status = gen_pool_add(sram_pool, SRAM_VIRT, len, -1);
+       WARN_ON(status < 0);
+       return status;
+}
+core_initcall(sram_init);
+
index 494e01bff5c3ad6d4bd8e82ce357a746f8e70ca9..0884ca57bfb09c961d60baf15d8cbe0c55b5479d 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/device.h>
+#include <linux/platform_device.h>
 
 #include <mach/hardware.h>
 #include <asm/system.h>
 #include <asm/errno.h>
 #include <mach/io.h>
 #include <mach/cputype.h>
+#include <mach/time.h>
 #include "clock.h"
 
 static struct clock_event_device clockevent_davinci;
 static unsigned int davinci_clock_tick_rate;
 
-#define DAVINCI_TIMER0_BASE (IO_PHYS + 0x21400)
-#define DAVINCI_TIMER1_BASE (IO_PHYS + 0x21800)
-#define DAVINCI_WDOG_BASE   (IO_PHYS + 0x21C00)
-
-enum {
-       T0_BOT = 0, T0_TOP, T1_BOT, T1_TOP, NUM_TIMERS,
-};
-
-#define IS_TIMER1(id)    (id & 0x2)
-#define IS_TIMER0(id)    (!IS_TIMER1(id))
-#define IS_TIMER_TOP(id) ((id & 0x1))
-#define IS_TIMER_BOT(id) (!IS_TIMER_TOP(id))
-
-static int timer_irqs[NUM_TIMERS] = {
-       IRQ_TINT0_TINT12,
-       IRQ_TINT0_TINT34,
-       IRQ_TINT1_TINT12,
-       IRQ_TINT1_TINT34,
-};
-
 /*
  * This driver configures the 2 64-bit count-up timers as 4 independent
  * 32-bit count-up timers used as follows:
- *
- * T0_BOT: Timer 0, bottom:  clockevent source for hrtimers
- * T0_TOP: Timer 0, top   :  clocksource for generic timekeeping
- * T1_BOT: Timer 1, bottom:  (used by DSP in TI DSPLink code)
- * T1_TOP: Timer 1, top   :  <unused>
  */
-#define TID_CLOCKEVENT  T0_BOT
-#define TID_CLOCKSOURCE T0_TOP
+
+enum {
+       TID_CLOCKEVENT,
+       TID_CLOCKSOURCE,
+};
 
 /* Timer register offsets */
-#define PID12                        0x0
-#define TIM12                        0x10
-#define TIM34                        0x14
-#define PRD12                        0x18
-#define PRD34                        0x1c
-#define TCR                          0x20
-#define TGCR                         0x24
-#define WDTCR                        0x28
+#define PID12                  0x0
+#define TIM12                  0x10
+#define TIM34                  0x14
+#define PRD12                  0x18
+#define PRD34                  0x1c
+#define TCR                    0x20
+#define TGCR                   0x24
+#define WDTCR                  0x28
+
+/* Offsets of the 8 compare registers */
+#define        CMP12_0                 0x60
+#define        CMP12_1                 0x64
+#define        CMP12_2                 0x68
+#define        CMP12_3                 0x6c
+#define        CMP12_4                 0x70
+#define        CMP12_5                 0x74
+#define        CMP12_6                 0x78
+#define        CMP12_7                 0x7c
 
 /* Timer register bitfields */
 #define TCR_ENAMODE_DISABLE          0x0
@@ -105,6 +95,7 @@ struct timer_s {
        unsigned int id;
        unsigned long period;
        unsigned long opts;
+       unsigned long flags;
        void __iomem *base;
        unsigned long tim_off;
        unsigned long prd_off;
@@ -114,30 +105,58 @@ struct timer_s {
 static struct timer_s timers[];
 
 /* values for 'opts' field of struct timer_s */
-#define TIMER_OPTS_DISABLED   0x00
-#define TIMER_OPTS_ONESHOT    0x01
-#define TIMER_OPTS_PERIODIC   0x02
+#define TIMER_OPTS_DISABLED            0x01
+#define TIMER_OPTS_ONESHOT             0x02
+#define TIMER_OPTS_PERIODIC            0x04
+#define TIMER_OPTS_STATE_MASK          0x07
+
+#define TIMER_OPTS_USE_COMPARE         0x80000000
+#define USING_COMPARE(t)               ((t)->opts & TIMER_OPTS_USE_COMPARE)
+
+static char *id_to_name[] = {
+       [T0_BOT]        = "timer0_0",
+       [T0_TOP]        = "timer0_1",
+       [T1_BOT]        = "timer1_0",
+       [T1_TOP]        = "timer1_1",
+};
 
 static int timer32_config(struct timer_s *t)
 {
-       u32 tcr = __raw_readl(t->base + TCR);
-
-       /* disable timer */
-       tcr &= ~(TCR_ENAMODE_MASK << t->enamode_shift);
-       __raw_writel(tcr, t->base + TCR);
-
-       /* reset counter to zero, set new period */
-       __raw_writel(0, t->base + t->tim_off);
-       __raw_writel(t->period, t->base + t->prd_off);
-
-       /* Set enable mode */
-       if (t->opts & TIMER_OPTS_ONESHOT) {
-               tcr |= TCR_ENAMODE_ONESHOT << t->enamode_shift;
-       } else if (t->opts & TIMER_OPTS_PERIODIC) {
-               tcr |= TCR_ENAMODE_PERIODIC << t->enamode_shift;
+       u32 tcr;
+       struct davinci_soc_info *soc_info = &davinci_soc_info;
+
+       if (USING_COMPARE(t)) {
+               struct davinci_timer_instance *dtip =
+                               soc_info->timer_info->timers;
+               int event_timer = ID_TO_TIMER(timers[TID_CLOCKEVENT].id);
+
+               /*
+                * Next interrupt should be the current time reg value plus
+                * the new period (using 32-bit unsigned addition/wrapping
+                * to 0 on overflow).  This assumes that the clocksource
+                * is setup to count to 2^32-1 before wrapping around to 0.
+                */
+               __raw_writel(__raw_readl(t->base + t->tim_off) + t->period,
+                       t->base + dtip[event_timer].cmp_off);
+       } else {
+               tcr = __raw_readl(t->base + TCR);
+
+               /* disable timer */
+               tcr &= ~(TCR_ENAMODE_MASK << t->enamode_shift);
+               __raw_writel(tcr, t->base + TCR);
+
+               /* reset counter to zero, set new period */
+               __raw_writel(0, t->base + t->tim_off);
+               __raw_writel(t->period, t->base + t->prd_off);
+
+               /* Set enable mode */
+               if (t->opts & TIMER_OPTS_ONESHOT)
+                       tcr |= TCR_ENAMODE_ONESHOT << t->enamode_shift;
+               else if (t->opts & TIMER_OPTS_PERIODIC)
+                       tcr |= TCR_ENAMODE_PERIODIC << t->enamode_shift;
+
+               __raw_writel(tcr, t->base + TCR);
        }
-
-       __raw_writel(tcr, t->base + TCR);
        return 0;
 }
 
@@ -182,13 +201,14 @@ static struct timer_s timers[] = {
 
 static void __init timer_init(void)
 {
-       u32 phys_bases[] = {DAVINCI_TIMER0_BASE, DAVINCI_TIMER1_BASE};
+       struct davinci_soc_info *soc_info = &davinci_soc_info;
+       struct davinci_timer_instance *dtip = soc_info->timer_info->timers;
        int i;
 
        /* Global init of each 64-bit timer as a whole */
        for(i=0; i<2; i++) {
                u32 tgcr;
-               void __iomem *base = IO_ADDRESS(phys_bases[i]);
+               void __iomem *base = dtip[i].base;
 
                /* Disabled, Internal clock source */
                __raw_writel(0, base + TCR);
@@ -214,33 +234,33 @@ static void __init timer_init(void)
        /* Init of each timer as a 32-bit timer */
        for (i=0; i< ARRAY_SIZE(timers); i++) {
                struct timer_s *t = &timers[i];
-               u32 phys_base;
-
-               if (t->name) {
-                       t->id = i;
-                       phys_base = (IS_TIMER1(t->id) ?
-                              DAVINCI_TIMER1_BASE : DAVINCI_TIMER0_BASE);
-                       t->base = IO_ADDRESS(phys_base);
-
-                       if (IS_TIMER_BOT(t->id)) {
-                               t->enamode_shift = 6;
-                               t->tim_off = TIM12;
-                               t->prd_off = PRD12;
-                       } else {
-                               t->enamode_shift = 22;
-                               t->tim_off = TIM34;
-                               t->prd_off = PRD34;
-                       }
-
-                       /* Register interrupt */
-                       t->irqaction.name = t->name;
-                       t->irqaction.dev_id = (void *)t;
-                       if (t->irqaction.handler != NULL) {
-                               setup_irq(timer_irqs[t->id], &t->irqaction);
-                       }
-
-                       timer32_config(&timers[i]);
+               int timer = ID_TO_TIMER(t->id);
+               u32 irq;
+
+               t->base = dtip[timer].base;
+
+               if (IS_TIMER_BOT(t->id)) {
+                       t->enamode_shift = 6;
+                       t->tim_off = TIM12;
+                       t->prd_off = PRD12;
+                       irq = dtip[timer].bottom_irq;
+               } else {
+                       t->enamode_shift = 22;
+                       t->tim_off = TIM34;
+                       t->prd_off = PRD34;
+                       irq = dtip[timer].top_irq;
+               }
+
+               /* Register interrupt */
+               t->irqaction.name = t->name;
+               t->irqaction.dev_id = (void *)t;
+
+               if (t->irqaction.handler != NULL) {
+                       irq = USING_COMPARE(t) ? dtip[i].cmp_irq : irq;
+                       setup_irq(irq, &t->irqaction);
                }
+
+               timer32_config(&timers[i]);
        }
 }
 
@@ -255,7 +275,6 @@ static cycle_t read_cycles(struct clocksource *cs)
 }
 
 static struct clocksource clocksource_davinci = {
-       .name           = "timer0_1",
        .rating         = 300,
        .read           = read_cycles,
        .mask           = CLOCKSOURCE_MASK(32),
@@ -284,15 +303,18 @@ static void davinci_set_mode(enum clock_event_mode mode,
        switch (mode) {
        case CLOCK_EVT_MODE_PERIODIC:
                t->period = davinci_clock_tick_rate / (HZ);
-               t->opts = TIMER_OPTS_PERIODIC;
+               t->opts &= ~TIMER_OPTS_STATE_MASK;
+               t->opts |= TIMER_OPTS_PERIODIC;
                timer32_config(t);
                break;
        case CLOCK_EVT_MODE_ONESHOT:
-               t->opts = TIMER_OPTS_ONESHOT;
+               t->opts &= ~TIMER_OPTS_STATE_MASK;
+               t->opts |= TIMER_OPTS_ONESHOT;
                break;
        case CLOCK_EVT_MODE_UNUSED:
        case CLOCK_EVT_MODE_SHUTDOWN:
-               t->opts = TIMER_OPTS_DISABLED;
+               t->opts &= ~TIMER_OPTS_STATE_MASK;
+               t->opts |= TIMER_OPTS_DISABLED;
                break;
        case CLOCK_EVT_MODE_RESUME:
                break;
@@ -300,7 +322,6 @@ static void davinci_set_mode(enum clock_event_mode mode,
 }
 
 static struct clock_event_device clockevent_davinci = {
-       .name           = "timer0_0",
        .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
        .shift          = 32,
        .set_next_event = davinci_set_next_event,
@@ -311,10 +332,42 @@ static struct clock_event_device clockevent_davinci = {
 static void __init davinci_timer_init(void)
 {
        struct clk *timer_clk;
-
+       struct davinci_soc_info *soc_info = &davinci_soc_info;
+       unsigned int clockevent_id;
+       unsigned int clocksource_id;
        static char err[] __initdata = KERN_ERR
                "%s: can't register clocksource!\n";
 
+       clockevent_id = soc_info->timer_info->clockevent_id;
+       clocksource_id = soc_info->timer_info->clocksource_id;
+
+       timers[TID_CLOCKEVENT].id = clockevent_id;
+       timers[TID_CLOCKSOURCE].id = clocksource_id;
+
+       /*
+        * If using same timer for both clock events & clocksource,
+        * a compare register must be used to generate an event interrupt.
+        * This is equivalent to a oneshot timer only (not periodic).
+        */
+       if (clockevent_id == clocksource_id) {
+               struct davinci_timer_instance *dtip =
+                               soc_info->timer_info->timers;
+               int event_timer = ID_TO_TIMER(clockevent_id);
+
+               /* Only bottom timers can use compare regs */
+               if (IS_TIMER_TOP(clockevent_id))
+                       pr_warning("davinci_timer_init: Invalid use"
+                               " of system timers.  Results unpredictable.\n");
+               else if ((dtip[event_timer].cmp_off == 0)
+                               || (dtip[event_timer].cmp_irq == 0))
+                       pr_warning("davinci_timer_init:  Invalid timer instance"
+                               " setup.  Results unpredictable.\n");
+               else {
+                       timers[TID_CLOCKEVENT].opts |= TIMER_OPTS_USE_COMPARE;
+                       clockevent_davinci.features = CLOCK_EVT_FEAT_ONESHOT;
+               }
+       }
+
        /* init timer hw */
        timer_init();
 
@@ -325,6 +378,7 @@ static void __init davinci_timer_init(void)
        davinci_clock_tick_rate = clk_get_rate(timer_clk);
 
        /* setup clocksource */
+       clocksource_davinci.name = id_to_name[clocksource_id];
        clocksource_davinci.mult =
                clocksource_khz2mult(davinci_clock_tick_rate/1000,
                                     clocksource_davinci.shift);
@@ -332,12 +386,12 @@ static void __init davinci_timer_init(void)
                printk(err, clocksource_davinci.name);
 
        /* setup clockevent */
+       clockevent_davinci.name = id_to_name[timers[TID_CLOCKEVENT].id];
        clockevent_davinci.mult = div_sc(davinci_clock_tick_rate, NSEC_PER_SEC,
                                         clockevent_davinci.shift);
        clockevent_davinci.max_delta_ns =
                clockevent_delta2ns(0xfffffffe, &clockevent_davinci);
-       clockevent_davinci.min_delta_ns =
-               clockevent_delta2ns(1, &clockevent_davinci);
+       clockevent_davinci.min_delta_ns = 50000; /* 50 usec */
 
        clockevent_davinci.cpumask = cpumask_of(0);
        clockevents_register_device(&clockevent_davinci);
@@ -349,15 +403,14 @@ struct sys_timer davinci_timer = {
 
 
 /* reset board using watchdog timer */
-void davinci_watchdog_reset(void) {
+void davinci_watchdog_reset(void)
+{
        u32 tgcr, wdtcr;
-       void __iomem *base = IO_ADDRESS(DAVINCI_WDOG_BASE);
-       struct device dev;
+       struct davinci_soc_info *soc_info = &davinci_soc_info;
+       void __iomem *base = soc_info->wdt_base;
        struct clk *wd_clk;
-       char *name = "watchdog";
 
-       dev_set_name(&dev, name);
-       wd_clk = clk_get(&dev, NULL);
+       wd_clk = clk_get(&davinci_wdt_device.dev, NULL);
        if (WARN_ON(IS_ERR(wd_clk)))
                return;
        clk_enable(wd_clk);
index 56bddcef6905fac93749b3520ef3eb9440283034..d7291c682a64622f45e5a243aebfab1384538017 100644 (file)
@@ -9,87 +9,135 @@ config CRUNCH
 
 comment "EP93xx Platforms"
 
+choice
+       prompt "EP93xx first SDRAM bank selection"
+       default EP93XX_SDCE3_SYNC_PHYS_OFFSET
+
+config EP93XX_SDCE3_SYNC_PHYS_OFFSET
+       bool "0x00000000 - SDCE3/SyncBoot"
+       help
+         Select this option if you want support for EP93xx boards with the
+         first SDRAM bank at 0x00000000
+
+config EP93XX_SDCE0_PHYS_OFFSET
+       bool "0xc0000000 - SDCEO"
+       help
+         Select this option if you want support for EP93xx boards with the
+         first SDRAM bank at 0xc0000000
+
+endchoice
+
 config MACH_ADSSPHERE
        bool "Support ADS Sphere"
+       depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET
        help
          Say 'Y' here if you want your kernel to support the ADS
          Sphere board.
 
+config MACH_EDB93XX
+       bool
+
+config MACH_EDB9301
+       bool "Support Cirrus Logic EDB9301"
+       depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET
+       select MACH_EDB93XX
+       help
+         Say 'Y' here if you want your kernel to support the Cirrus
+         Logic EDB9301 Evaluation Board.
+
 config MACH_EDB9302
        bool "Support Cirrus Logic EDB9302"
+       depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET
+       select MACH_EDB93XX
        help
          Say 'Y' here if you want your kernel to support the Cirrus
          Logic EDB9302 Evaluation Board.
 
 config MACH_EDB9302A
        bool "Support Cirrus Logic EDB9302A"
+       depends on EP93XX_SDCE0_PHYS_OFFSET
+       select MACH_EDB93XX
        help
          Say 'Y' here if you want your kernel to support the Cirrus
          Logic EDB9302A Evaluation Board.
 
 config MACH_EDB9307
        bool "Support Cirrus Logic EDB9307"
+       depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET
+       select MACH_EDB93XX
        help
          Say 'Y' here if you want your kernel to support the Cirrus
          Logic EDB9307 Evaluation Board.
 
 config MACH_EDB9307A
        bool "Support Cirrus Logic EDB9307A"
+       depends on EP93XX_SDCE0_PHYS_OFFSET
+       select MACH_EDB93XX
        help
          Say 'Y' here if you want your kernel to support the Cirrus
          Logic EDB9307A Evaluation Board.
 
 config MACH_EDB9312
        bool "Support Cirrus Logic EDB9312"
+       depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET
+       select MACH_EDB93XX
        help
          Say 'Y' here if you want your kernel to support the Cirrus
          Logic EDB9312 Evaluation Board.
 
 config MACH_EDB9315
        bool "Support Cirrus Logic EDB9315"
+       depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET
+       select MACH_EDB93XX
        help
          Say 'Y' here if you want your kernel to support the Cirrus
          Logic EDB9315 Evaluation Board.
 
 config MACH_EDB9315A
        bool "Support Cirrus Logic EDB9315A"
+       depends on EP93XX_SDCE0_PHYS_OFFSET
+       select MACH_EDB93XX
        help
          Say 'Y' here if you want your kernel to support the Cirrus
          Logic EDB9315A Evaluation Board.
 
 config MACH_GESBC9312
+       depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET
        bool "Support Glomation GESBC-9312-sx"
        help
          Say 'Y' here if you want your kernel to support the Glomation
          GESBC-9312-sx board.
 
 config MACH_MICRO9
-        bool
-        default n
+       bool
 
 config MACH_MICRO9H
-       bool "Support Contec Hypercontrol Micro9-H"
-       select MACH_MICRO9
-       help
-         Say 'Y' here if you want your kernel to support the
-         Contec Hypercontrol Micro9-H board.
+       bool "Support Contec Hypercontrol Micro9-H"
+       depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET
+       select MACH_MICRO9
+       help
+         Say 'Y' here if you want your kernel to support the
+         Contec Hypercontrol Micro9-H board.
 
 config MACH_MICRO9M
-       bool "Support Contec Hypercontrol Micro9-M"
-       select MACH_MICRO9
-       help
-         Say 'Y' here if you want your kernel to support the
-         Contec Hypercontrol Micro9-M board.
+       bool "Support Contec Hypercontrol Micro9-M"
+       depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET
+       select MACH_MICRO9
+       help
+         Say 'Y' here if you want your kernel to support the
+         Contec Hypercontrol Micro9-M board.
 
 config MACH_MICRO9L
-       bool "Support Contec Hypercontrol Micro9-L"
-       select MACH_MICRO9
-       help
-         Say 'Y' here if you want your kernel to support the
-         Contec Hypercontrol Micro9-L board.
+       bool "Support Contec Hypercontrol Micro9-L"
+       depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET
+       select MACH_MICRO9
+       help
+         Say 'Y' here if you want your kernel to support the
+         Contec Hypercontrol Micro9-L board.
 
 config MACH_TS72XX
        bool "Support Technologic Systems TS-72xx SBC"
+       depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET
        help
          Say 'Y' here if you want your kernel to support the
          Technologic Systems TS-72xx board.
index 9522e205b73fc7a5a04a966893885f6e770f16d7..eae6199a9891af49845774d9ddfc5f9b9e903007 100644 (file)
@@ -7,13 +7,7 @@ obj-n                  :=
 obj-                   :=
 
 obj-$(CONFIG_MACH_ADSSPHERE)   += adssphere.o
-obj-$(CONFIG_MACH_EDB9302)     += edb9302.o
-obj-$(CONFIG_MACH_EDB9302A)    += edb9302a.o
-obj-$(CONFIG_MACH_EDB9307)     += edb9307.o
-obj-$(CONFIG_MACH_EDB9307A)    += edb9307a.o
-obj-$(CONFIG_MACH_EDB9312)     += edb9312.o
-obj-$(CONFIG_MACH_EDB9315)     += edb9315.o
-obj-$(CONFIG_MACH_EDB9315A)    += edb9315a.o
+obj-$(CONFIG_MACH_EDB93XX)     += edb93xx.o
 obj-$(CONFIG_MACH_GESBC9312)   += gesbc9312.o
 obj-$(CONFIG_MACH_MICRO9)      += micro9.o
 obj-$(CONFIG_MACH_TS72XX)      += ts72xx.o
index d5561ad15badcef26897b1f938355c05b5c6a592..27a085a8f12a8020e237517809f3f65cabeccf21 100644 (file)
@@ -1,2 +1,5 @@
-   zreladdr-y  := 0x00008000
-params_phys-y  := 0x00000100
+   zreladdr-$(CONFIG_EP93XX_SDCE3_SYNC_PHYS_OFFSET)    := 0x00008000
+params_phys-$(CONFIG_EP93XX_SDCE3_SYNC_PHYS_OFFSET)    := 0x00000100
+
+   zreladdr-$(CONFIG_EP93XX_SDCE0_PHYS_OFFSET)         := 0xc0008000
+params_phys-$(CONFIG_EP93XX_SDCE0_PHYS_OFFSET)         := 0xc0000100
index b2eede5531c8fab5840e8e0bb75944f350773ced..6c4c1633ed123c8457fd20a4f1c51c6bafe39534 100644 (file)
@@ -72,58 +72,58 @@ static struct clk clk_h;
 static struct clk clk_p;
 static struct clk clk_pll2;
 static struct clk clk_usb_host = {
-       .enable_reg     = EP93XX_SYSCON_CLOCK_CONTROL,
-       .enable_mask    = EP93XX_SYSCON_CLOCK_USH_EN,
+       .enable_reg     = EP93XX_SYSCON_PWRCNT,
+       .enable_mask    = EP93XX_SYSCON_PWRCNT_USH_EN,
 };
 
 /* DMA Clocks */
 static struct clk clk_m2p0 = {
-       .enable_reg     = EP93XX_SYSCON_CLOCK_CONTROL,
-       .enable_mask    = 0x00020000,
+       .enable_reg     = EP93XX_SYSCON_PWRCNT,
+       .enable_mask    = EP93XX_SYSCON_PWRCNT_DMA_M2P0,
 };
 static struct clk clk_m2p1 = {
-       .enable_reg     = EP93XX_SYSCON_CLOCK_CONTROL,
-       .enable_mask    = 0x00010000,
+       .enable_reg     = EP93XX_SYSCON_PWRCNT,
+       .enable_mask    = EP93XX_SYSCON_PWRCNT_DMA_M2P1,
 };
 static struct clk clk_m2p2 = {
-       .enable_reg     = EP93XX_SYSCON_CLOCK_CONTROL,
-       .enable_mask    = 0x00080000,
+       .enable_reg     = EP93XX_SYSCON_PWRCNT,
+       .enable_mask    = EP93XX_SYSCON_PWRCNT_DMA_M2P2,
 };
 static struct clk clk_m2p3 = {
-       .enable_reg     = EP93XX_SYSCON_CLOCK_CONTROL,
-       .enable_mask    = 0x00040000,
+       .enable_reg     = EP93XX_SYSCON_PWRCNT,
+       .enable_mask    = EP93XX_SYSCON_PWRCNT_DMA_M2P3,
 };
 static struct clk clk_m2p4 = {
-       .enable_reg     = EP93XX_SYSCON_CLOCK_CONTROL,
-       .enable_mask    = 0x00200000,
+       .enable_reg     = EP93XX_SYSCON_PWRCNT,
+       .enable_mask    = EP93XX_SYSCON_PWRCNT_DMA_M2P4,
 };
 static struct clk clk_m2p5 = {
-       .enable_reg     = EP93XX_SYSCON_CLOCK_CONTROL,
-       .enable_mask    = 0x00100000,
+       .enable_reg     = EP93XX_SYSCON_PWRCNT,
+       .enable_mask    = EP93XX_SYSCON_PWRCNT_DMA_M2P5,
 };
 static struct clk clk_m2p6 = {
-       .enable_reg     = EP93XX_SYSCON_CLOCK_CONTROL,
-       .enable_mask    = 0x00800000,
+       .enable_reg     = EP93XX_SYSCON_PWRCNT,
+       .enable_mask    = EP93XX_SYSCON_PWRCNT_DMA_M2P6,
 };
 static struct clk clk_m2p7 = {
-       .enable_reg     = EP93XX_SYSCON_CLOCK_CONTROL,
-       .enable_mask    = 0x00400000,
+       .enable_reg     = EP93XX_SYSCON_PWRCNT,
+       .enable_mask    = EP93XX_SYSCON_PWRCNT_DMA_M2P7,
 };
 static struct clk clk_m2p8 = {
-       .enable_reg     = EP93XX_SYSCON_CLOCK_CONTROL,
-       .enable_mask    = 0x02000000,
+       .enable_reg     = EP93XX_SYSCON_PWRCNT,
+       .enable_mask    = EP93XX_SYSCON_PWRCNT_DMA_M2P8,
 };
 static struct clk clk_m2p9 = {
-       .enable_reg     = EP93XX_SYSCON_CLOCK_CONTROL,
-       .enable_mask    = 0x01000000,
+       .enable_reg     = EP93XX_SYSCON_PWRCNT,
+       .enable_mask    = EP93XX_SYSCON_PWRCNT_DMA_M2P9,
 };
 static struct clk clk_m2m0 = {
-       .enable_reg     = EP93XX_SYSCON_CLOCK_CONTROL,
-       .enable_mask    = 0x04000000,
+       .enable_reg     = EP93XX_SYSCON_PWRCNT,
+       .enable_mask    = EP93XX_SYSCON_PWRCNT_DMA_M2M0,
 };
 static struct clk clk_m2m1 = {
-       .enable_reg     = EP93XX_SYSCON_CLOCK_CONTROL,
-       .enable_mask    = 0x08000000,
+       .enable_reg     = EP93XX_SYSCON_PWRCNT,
+       .enable_mask    = EP93XX_SYSCON_PWRCNT_DMA_M2M1,
 };
 
 #define INIT_CK(dev,con,ck)                                    \
@@ -138,7 +138,7 @@ static struct clk_lookup clocks[] = {
        INIT_CK(NULL, "hclk", &clk_h),
        INIT_CK(NULL, "pclk", &clk_p),
        INIT_CK(NULL, "pll2", &clk_pll2),
-       INIT_CK(NULL, "usb_host", &clk_usb_host),
+       INIT_CK("ep93xx-ohci", NULL, &clk_usb_host),
        INIT_CK(NULL, "m2p0", &clk_m2p0),
        INIT_CK(NULL, "m2p1", &clk_m2p1),
        INIT_CK(NULL, "m2p2", &clk_m2p2),
@@ -186,8 +186,8 @@ static unsigned long get_uart_rate(struct clk *clk)
 {
        u32 value;
 
-       value = __raw_readl(EP93XX_SYSCON_CLOCK_CONTROL);
-       if (value & EP93XX_SYSCON_CLOCK_UARTBAUD)
+       value = __raw_readl(EP93XX_SYSCON_PWRCNT);
+       if (value & EP93XX_SYSCON_PWRCNT_UARTBAUD)
                return EP93XX_EXT_CLK_RATE;
        else
                return EP93XX_EXT_CLK_RATE / 2;
index ae24486f858a4a9d2e7482c67298c7e12c603b89..204dc5cbd0b88367001cad3ec38855bf8832cd5c 100644 (file)
@@ -155,7 +155,7 @@ static unsigned char gpio_int_unmasked[3];
 static unsigned char gpio_int_enabled[3];
 static unsigned char gpio_int_type1[3];
 static unsigned char gpio_int_type2[3];
-static unsigned char gpio_int_debouce[3];
+static unsigned char gpio_int_debounce[3];
 
 /* Port ordering is: A B F */
 static const u8 int_type1_register_offset[3]   = { 0x90, 0xac, 0x4c };
@@ -192,11 +192,11 @@ void ep93xx_gpio_int_debounce(unsigned int irq, int enable)
        int port_mask = 1 << (line & 7);
 
        if (enable)
-               gpio_int_debouce[port] |= port_mask;
+               gpio_int_debounce[port] |= port_mask;
        else
-               gpio_int_debouce[port] &= ~port_mask;
+               gpio_int_debounce[port] &= ~port_mask;
 
-       __raw_writeb(gpio_int_debouce[port],
+       __raw_writeb(gpio_int_debounce[port],
                EP93XX_GPIO_REG(int_debounce_register_offset[port]));
 }
 EXPORT_SYMBOL(ep93xx_gpio_int_debounce);
@@ -362,8 +362,8 @@ void __init ep93xx_init_irq(void)
 {
        int gpio_irq;
 
-       vic_init((void *)EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK);
-       vic_init((void *)EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK);
+       vic_init((void *)EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK, 0);
+       vic_init((void *)EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK, 0);
 
        for (gpio_irq = gpio_to_irq(0);
             gpio_irq <= gpio_to_irq(EP93XX_GPIO_LINE_MAX_IRQ); ++gpio_irq) {
@@ -450,10 +450,19 @@ static struct amba_device uart3_device = {
 };
 
 
+static struct resource ep93xx_rtc_resource[] = {
+       {
+               .start          = EP93XX_RTC_PHYS_BASE,
+               .end            = EP93XX_RTC_PHYS_BASE + 0x10c - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+};
+
 static struct platform_device ep93xx_rtc_device = {
-       .name           = "ep93xx-rtc",
-       .id             = -1,
-       .num_resources  = 0,
+       .name           = "ep93xx-rtc",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(ep93xx_rtc_resource),
+       .resource       = ep93xx_rtc_resource,
 };
 
 
diff --git a/arch/arm/mach-ep93xx/edb9302.c b/arch/arm/mach-ep93xx/edb9302.c
deleted file mode 100644 (file)
index 8bf8d7c..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * arch/arm/mach-ep93xx/edb9302.c
- * Cirrus Logic EDB9302 support.
- *
- * Copyright (C) 2006 George Kashperko <george@chas.com.ua>
- *
- * 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/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/mtd/physmap.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/i2c.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-static struct physmap_flash_data edb9302_flash_data = {
-       .width          = 2,
-};
-
-static struct resource edb9302_flash_resource = {
-       .start          = EP93XX_CS6_PHYS_BASE,
-       .end            = EP93XX_CS6_PHYS_BASE + SZ_16M - 1,
-       .flags          = IORESOURCE_MEM,
-};
-
-static struct platform_device edb9302_flash = {
-       .name           = "physmap-flash",
-       .id             = 0,
-       .dev            = {
-               .platform_data  = &edb9302_flash_data,
-       },
-       .num_resources  = 1,
-       .resource       = &edb9302_flash_resource,
-};
-
-static struct ep93xx_eth_data edb9302_eth_data = {
-       .phy_id         = 1,
-};
-
-static void __init edb9302_init_machine(void)
-{
-       ep93xx_init_devices();
-       platform_device_register(&edb9302_flash);
-
-       ep93xx_register_eth(&edb9302_eth_data, 1);
-}
-
-MACHINE_START(EDB9302, "Cirrus Logic EDB9302 Evaluation Board")
-       /* Maintainer: George Kashperko <george@chas.com.ua> */
-       .phys_io        = EP93XX_APB_PHYS_BASE,
-       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
-       .boot_params    = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
-       .map_io         = ep93xx_map_io,
-       .init_irq       = ep93xx_init_irq,
-       .timer          = &ep93xx_timer,
-       .init_machine   = edb9302_init_machine,
-MACHINE_END
diff --git a/arch/arm/mach-ep93xx/edb9302a.c b/arch/arm/mach-ep93xx/edb9302a.c
deleted file mode 100644 (file)
index a352c57..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * arch/arm/mach-ep93xx/edb9302a.c
- * Cirrus Logic EDB9302A support.
- *
- * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/mtd/physmap.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/i2c.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-static struct physmap_flash_data edb9302a_flash_data = {
-       .width          = 2,
-};
-
-static struct resource edb9302a_flash_resource = {
-       .start          = EP93XX_CS6_PHYS_BASE,
-       .end            = EP93XX_CS6_PHYS_BASE + SZ_16M - 1,
-       .flags          = IORESOURCE_MEM,
-};
-
-static struct platform_device edb9302a_flash = {
-       .name           = "physmap-flash",
-       .id             = 0,
-       .dev            = {
-               .platform_data  = &edb9302a_flash_data,
-       },
-       .num_resources  = 1,
-       .resource       = &edb9302a_flash_resource,
-};
-
-static struct ep93xx_eth_data edb9302a_eth_data = {
-       .phy_id         = 1,
-};
-
-static void __init edb9302a_init_machine(void)
-{
-       ep93xx_init_devices();
-       platform_device_register(&edb9302a_flash);
-
-       ep93xx_register_eth(&edb9302a_eth_data, 1);
-}
-
-MACHINE_START(EDB9302A, "Cirrus Logic EDB9302A Evaluation Board")
-       /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
-       .phys_io        = EP93XX_APB_PHYS_BASE,
-       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
-       .boot_params    = EP93XX_SDCE0_PHYS_BASE + 0x100,
-       .map_io         = ep93xx_map_io,
-       .init_irq       = ep93xx_init_irq,
-       .timer          = &ep93xx_timer,
-       .init_machine   = edb9302a_init_machine,
-MACHINE_END
diff --git a/arch/arm/mach-ep93xx/edb9307.c b/arch/arm/mach-ep93xx/edb9307.c
deleted file mode 100644 (file)
index 5ab22f6..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * arch/arm/mach-ep93xx/edb9307.c
- * Cirrus Logic EDB9307 support.
- *
- * Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/mtd/physmap.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/i2c.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-static struct physmap_flash_data edb9307_flash_data = {
-       .width          = 4,
-};
-
-static struct resource edb9307_flash_resource = {
-       .start          = EP93XX_CS6_PHYS_BASE,
-       .end            = EP93XX_CS6_PHYS_BASE + SZ_32M - 1,
-       .flags          = IORESOURCE_MEM,
-};
-
-static struct platform_device edb9307_flash = {
-       .name           = "physmap-flash",
-       .id             = 0,
-       .dev            = {
-               .platform_data  = &edb9307_flash_data,
-       },
-       .num_resources  = 1,
-       .resource       = &edb9307_flash_resource,
-};
-
-static struct ep93xx_eth_data edb9307_eth_data = {
-       .phy_id         = 1,
-};
-
-static void __init edb9307_init_machine(void)
-{
-       ep93xx_init_devices();
-       platform_device_register(&edb9307_flash);
-
-       ep93xx_register_eth(&edb9307_eth_data, 1);
-}
-
-MACHINE_START(EDB9307, "Cirrus Logic EDB9307 Evaluation Board")
-       /* Maintainer: Herbert Valerio Riedel <hvr@gnu.org> */
-       .phys_io        = EP93XX_APB_PHYS_BASE,
-       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
-       .boot_params    = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
-       .map_io         = ep93xx_map_io,
-       .init_irq       = ep93xx_init_irq,
-       .timer          = &ep93xx_timer,
-       .init_machine   = edb9307_init_machine,
-MACHINE_END
diff --git a/arch/arm/mach-ep93xx/edb9307a.c b/arch/arm/mach-ep93xx/edb9307a.c
deleted file mode 100644 (file)
index 6171167..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * arch/arm/mach-ep93xx/edb9307a.c
- * Cirrus Logic EDB9307A support.
- *
- * Copyright (C) 2008 H Hartley Sweeten <hsweeten@visionengravers.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/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/mtd/physmap.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/i2c.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-static struct physmap_flash_data edb9307a_flash_data = {
-       .width          = 2,
-};
-
-static struct resource edb9307a_flash_resource = {
-       .start          = EP93XX_CS6_PHYS_BASE,
-       .end            = EP93XX_CS6_PHYS_BASE + SZ_16M - 1,
-       .flags          = IORESOURCE_MEM,
-};
-
-static struct platform_device edb9307a_flash = {
-       .name           = "physmap-flash",
-       .id             = 0,
-       .dev            = {
-               .platform_data  = &edb9307a_flash_data,
-       },
-       .num_resources  = 1,
-       .resource       = &edb9307a_flash_resource,
-};
-
-static struct ep93xx_eth_data edb9307a_eth_data = {
-       .phy_id         = 1,
-};
-
-static struct i2c_board_info __initdata edb9307a_i2c_data[] = {
-       {
-               /* On-board battery backed RTC */
-               I2C_BOARD_INFO("isl1208", 0x6f),
-       },
-       /*
-        * The I2C signals are also routed to the Expansion Connector (J4)
-        */
-};
-
-static void __init edb9307a_init_machine(void)
-{
-       ep93xx_init_devices();
-       platform_device_register(&edb9307a_flash);
-
-       ep93xx_register_eth(&edb9307a_eth_data, 1);
-
-       ep93xx_init_i2c(edb9307a_i2c_data, ARRAY_SIZE(edb9307a_i2c_data));
-}
-
-MACHINE_START(EDB9307A, "Cirrus Logic EDB9307A Evaluation Board")
-       /* Maintainer: H Hartley Sweeten <hsweeten@visionengravers.com> */
-       .phys_io        = EP93XX_APB_PHYS_BASE,
-       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
-       .boot_params    = EP93XX_SDCE0_PHYS_BASE + 0x100,
-       .map_io         = ep93xx_map_io,
-       .init_irq       = ep93xx_init_irq,
-       .timer          = &ep93xx_timer,
-       .init_machine   = edb9307a_init_machine,
-MACHINE_END
diff --git a/arch/arm/mach-ep93xx/edb9312.c b/arch/arm/mach-ep93xx/edb9312.c
deleted file mode 100644 (file)
index d7179f6..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * arch/arm/mach-ep93xx/edb9312.c
- * Cirrus Logic EDB9312 support.
- *
- * Copyright (C) 2006 Infosys Technologies Limited
- *     Toufeeq Hussain <toufeeq_hussain@infosys.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/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/mtd/physmap.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/i2c.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-static struct physmap_flash_data edb9312_flash_data = {
-       .width          = 4,
-};
-
-static struct resource edb9312_flash_resource = {
-       .start          = EP93XX_CS6_PHYS_BASE,
-       .end            = EP93XX_CS6_PHYS_BASE + SZ_32M - 1,
-       .flags          = IORESOURCE_MEM,
-};
-
-static struct platform_device edb9312_flash = {
-       .name           = "physmap-flash",
-       .id             = 0,
-       .dev            = {
-               .platform_data  = &edb9312_flash_data,
-       },
-       .num_resources  = 1,
-       .resource       = &edb9312_flash_resource,
-};
-
-static struct ep93xx_eth_data edb9312_eth_data = {
-       .phy_id         = 1,
-};
-
-static void __init edb9312_init_machine(void)
-{
-       ep93xx_init_devices();
-       platform_device_register(&edb9312_flash);
-
-       ep93xx_register_eth(&edb9312_eth_data, 1);
-}
-
-MACHINE_START(EDB9312, "Cirrus Logic EDB9312 Evaluation Board")
-       /* Maintainer: Toufeeq Hussain <toufeeq_hussain@infosys.com> */
-       .phys_io        = EP93XX_APB_PHYS_BASE,
-       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
-       .boot_params    = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
-       .map_io         = ep93xx_map_io,
-       .init_irq       = ep93xx_init_irq,
-       .timer          = &ep93xx_timer,
-       .init_machine   = edb9312_init_machine,
-MACHINE_END
diff --git a/arch/arm/mach-ep93xx/edb9315.c b/arch/arm/mach-ep93xx/edb9315.c
deleted file mode 100644 (file)
index 025af6e..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * arch/arm/mach-ep93xx/edb9315.c
- * Cirrus Logic EDB9315 support.
- *
- * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/mtd/physmap.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/i2c.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-static struct physmap_flash_data edb9315_flash_data = {
-       .width          = 4,
-};
-
-static struct resource edb9315_flash_resource = {
-       .start          = EP93XX_CS6_PHYS_BASE,
-       .end            = EP93XX_CS6_PHYS_BASE + SZ_32M - 1,
-       .flags          = IORESOURCE_MEM,
-};
-
-static struct platform_device edb9315_flash = {
-       .name           = "physmap-flash",
-       .id             = 0,
-       .dev            = {
-               .platform_data  = &edb9315_flash_data,
-       },
-       .num_resources  = 1,
-       .resource       = &edb9315_flash_resource,
-};
-
-static struct ep93xx_eth_data edb9315_eth_data = {
-       .phy_id         = 1,
-};
-
-static void __init edb9315_init_machine(void)
-{
-       ep93xx_init_devices();
-       platform_device_register(&edb9315_flash);
-
-       ep93xx_register_eth(&edb9315_eth_data, 1);
-}
-
-MACHINE_START(EDB9315, "Cirrus Logic EDB9315 Evaluation Board")
-       /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
-       .phys_io        = EP93XX_APB_PHYS_BASE,
-       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
-       .boot_params    = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
-       .map_io         = ep93xx_map_io,
-       .init_irq       = ep93xx_init_irq,
-       .timer          = &ep93xx_timer,
-       .init_machine   = edb9315_init_machine,
-MACHINE_END
diff --git a/arch/arm/mach-ep93xx/edb9315a.c b/arch/arm/mach-ep93xx/edb9315a.c
deleted file mode 100644 (file)
index 4c9cc8a..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * arch/arm/mach-ep93xx/edb9315a.c
- * Cirrus Logic EDB9315A support.
- *
- * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/mtd/physmap.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/i2c.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-static struct physmap_flash_data edb9315a_flash_data = {
-       .width          = 2,
-};
-
-static struct resource edb9315a_flash_resource = {
-       .start          = EP93XX_CS6_PHYS_BASE,
-       .end            = EP93XX_CS6_PHYS_BASE + SZ_16M - 1,
-       .flags          = IORESOURCE_MEM,
-};
-
-static struct platform_device edb9315a_flash = {
-       .name           = "physmap-flash",
-       .id             = 0,
-       .dev            = {
-               .platform_data  = &edb9315a_flash_data,
-       },
-       .num_resources  = 1,
-       .resource       = &edb9315a_flash_resource,
-};
-
-static struct ep93xx_eth_data edb9315a_eth_data = {
-       .phy_id         = 1,
-};
-
-static void __init edb9315a_init_machine(void)
-{
-       ep93xx_init_devices();
-       platform_device_register(&edb9315a_flash);
-
-       ep93xx_register_eth(&edb9315a_eth_data, 1);
-}
-
-MACHINE_START(EDB9315A, "Cirrus Logic EDB9315A Evaluation Board")
-       /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
-       .phys_io        = EP93XX_APB_PHYS_BASE,
-       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
-       .boot_params    = EP93XX_SDCE0_PHYS_BASE + 0x100,
-       .map_io         = ep93xx_map_io,
-       .init_irq       = ep93xx_init_irq,
-       .timer          = &ep93xx_timer,
-       .init_machine   = edb9315a_init_machine,
-MACHINE_END
diff --git a/arch/arm/mach-ep93xx/edb93xx.c b/arch/arm/mach-ep93xx/edb93xx.c
new file mode 100644 (file)
index 0000000..e9e45b9
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * arch/arm/mach-ep93xx/edb93xx.c
+ * Cirrus Logic EDB93xx Development Board support.
+ *
+ * EDB93XX, EDB9301, EDB9307A
+ * Copyright (C) 2008-2009 H Hartley Sweeten <hsweeten@visionengravers.com>
+ *
+ * EDB9302
+ * Copyright (C) 2006 George Kashperko <george@chas.com.ua>
+ *
+ * EDB9302A, EDB9315, EDB9315A
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ *
+ * EDB9307
+ * Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org>
+ *
+ * EDB9312
+ * Copyright (C) 2006 Infosys Technologies Limited
+ *                    Toufeeq Hussain <toufeeq_hussain@infosys.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/mm.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+static struct physmap_flash_data edb93xx_flash_data;
+
+static struct resource edb93xx_flash_resource = {
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device edb93xx_flash = {
+       .name           = "physmap-flash",
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &edb93xx_flash_data,
+       },
+       .num_resources  = 1,
+       .resource       = &edb93xx_flash_resource,
+};
+
+static void __init __edb93xx_register_flash(unsigned int width,
+                       resource_size_t start, resource_size_t size)
+{
+       edb93xx_flash_data.width        = width;
+       edb93xx_flash_resource.start    = start;
+       edb93xx_flash_resource.end      = start + size - 1;
+
+       platform_device_register(&edb93xx_flash);
+}
+
+static void __init edb93xx_register_flash(void)
+{
+       if (machine_is_edb9307() || machine_is_edb9312() ||
+           machine_is_edb9315()) {
+               __edb93xx_register_flash(4, EP93XX_CS6_PHYS_BASE, SZ_32M);
+       } else {
+               __edb93xx_register_flash(2, EP93XX_CS6_PHYS_BASE, SZ_16M);
+       }
+}
+
+static struct ep93xx_eth_data edb93xx_eth_data = {
+       .phy_id         = 1,
+};
+
+static struct i2c_board_info __initdata edb93xxa_i2c_data[] = {
+       {
+               I2C_BOARD_INFO("isl1208", 0x6f),
+       },
+};
+
+static struct i2c_board_info __initdata edb93xx_i2c_data[] = {
+       {
+               I2C_BOARD_INFO("ds1337", 0x68),
+       },
+};
+
+static void __init edb93xx_register_i2c(void)
+{
+       if (machine_is_edb9302a() || machine_is_edb9307a() ||
+           machine_is_edb9315a()) {
+               ep93xx_register_i2c(edb93xxa_i2c_data,
+                               ARRAY_SIZE(edb93xxa_i2c_data));
+       } else if (machine_is_edb9307() || machine_is_edb9312() ||
+                  machine_is_edb9315()) {
+               ep93xx_register_i2c(edb93xx_i2c_data,
+                               ARRAY_SIZE(edb93xx_i2c_data));
+       }
+}
+
+static void __init edb93xx_init_machine(void)
+{
+       ep93xx_init_devices();
+       edb93xx_register_flash();
+       ep93xx_register_eth(&edb93xx_eth_data, 1);
+       edb93xx_register_i2c();
+}
+
+
+#ifdef CONFIG_MACH_EDB9301
+MACHINE_START(EDB9301, "Cirrus Logic EDB9301 Evaluation Board")
+       /* Maintainer: H Hartley Sweeten <hsweeten@visionengravers.com> */
+       .phys_io        = EP93XX_APB_PHYS_BASE,
+       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+       .boot_params    = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
+       .map_io         = ep93xx_map_io,
+       .init_irq       = ep93xx_init_irq,
+       .timer          = &ep93xx_timer,
+       .init_machine   = edb93xx_init_machine,
+MACHINE_END
+#endif
+
+#ifdef CONFIG_MACH_EDB9302
+MACHINE_START(EDB9302, "Cirrus Logic EDB9302 Evaluation Board")
+       /* Maintainer: George Kashperko <george@chas.com.ua> */
+       .phys_io        = EP93XX_APB_PHYS_BASE,
+       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+       .boot_params    = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
+       .map_io         = ep93xx_map_io,
+       .init_irq       = ep93xx_init_irq,
+       .timer          = &ep93xx_timer,
+       .init_machine   = edb93xx_init_machine,
+MACHINE_END
+#endif
+
+#ifdef CONFIG_MACH_EDB9302A
+MACHINE_START(EDB9302A, "Cirrus Logic EDB9302A Evaluation Board")
+       /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
+       .phys_io        = EP93XX_APB_PHYS_BASE,
+       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+       .boot_params    = EP93XX_SDCE0_PHYS_BASE + 0x100,
+       .map_io         = ep93xx_map_io,
+       .init_irq       = ep93xx_init_irq,
+       .timer          = &ep93xx_timer,
+       .init_machine   = edb93xx_init_machine,
+MACHINE_END
+#endif
+
+#ifdef CONFIG_MACH_EDB9307
+MACHINE_START(EDB9307, "Cirrus Logic EDB9307 Evaluation Board")
+       /* Maintainer: Herbert Valerio Riedel <hvr@gnu.org> */
+       .phys_io        = EP93XX_APB_PHYS_BASE,
+       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+       .boot_params    = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
+       .map_io         = ep93xx_map_io,
+       .init_irq       = ep93xx_init_irq,
+       .timer          = &ep93xx_timer,
+       .init_machine   = edb93xx_init_machine,
+MACHINE_END
+#endif
+
+#ifdef CONFIG_MACH_EDB9307A
+MACHINE_START(EDB9307A, "Cirrus Logic EDB9307A Evaluation Board")
+       /* Maintainer: H Hartley Sweeten <hsweeten@visionengravers.com> */
+       .phys_io        = EP93XX_APB_PHYS_BASE,
+       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+       .boot_params    = EP93XX_SDCE0_PHYS_BASE + 0x100,
+       .map_io         = ep93xx_map_io,
+       .init_irq       = ep93xx_init_irq,
+       .timer          = &ep93xx_timer,
+       .init_machine   = edb93xx_init_machine,
+MACHINE_END
+#endif
+
+#ifdef CONFIG_MACH_EDB9312
+MACHINE_START(EDB9312, "Cirrus Logic EDB9312 Evaluation Board")
+       /* Maintainer: Toufeeq Hussain <toufeeq_hussain@infosys.com> */
+       .phys_io        = EP93XX_APB_PHYS_BASE,
+       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+       .boot_params    = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
+       .map_io         = ep93xx_map_io,
+       .init_irq       = ep93xx_init_irq,
+       .timer          = &ep93xx_timer,
+       .init_machine   = edb93xx_init_machine,
+MACHINE_END
+#endif
+
+#ifdef CONFIG_MACH_EDB9315
+MACHINE_START(EDB9315, "Cirrus Logic EDB9315 Evaluation Board")
+       /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
+       .phys_io        = EP93XX_APB_PHYS_BASE,
+       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+       .boot_params    = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
+       .map_io         = ep93xx_map_io,
+       .init_irq       = ep93xx_init_irq,
+       .timer          = &ep93xx_timer,
+       .init_machine   = edb93xx_init_machine,
+MACHINE_END
+#endif
+
+#ifdef CONFIG_MACH_EDB9315A
+MACHINE_START(EDB9315A, "Cirrus Logic EDB9315A Evaluation Board")
+       /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
+       .phys_io        = EP93XX_APB_PHYS_BASE,
+       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+       .boot_params    = EP93XX_SDCE0_PHYS_BASE + 0x100,
+       .map_io         = ep93xx_map_io,
+       .init_irq       = ep93xx_init_irq,
+       .timer          = &ep93xx_timer,
+       .init_machine   = edb93xx_init_machine,
+MACHINE_END
+#endif
index 1732de7629a5dd245bdb6e96e0b3e8aac203ad4e..967c079180dbc8b3e7b453296a20c699baa4065c 100644 (file)
 #define EP93XX_PWM_BASE                        (EP93XX_APB_VIRT_BASE + 0x00110000)
 
 #define EP93XX_RTC_BASE                        (EP93XX_APB_VIRT_BASE + 0x00120000)
+#define EP93XX_RTC_PHYS_BASE           (EP93XX_APB_PHYS_BASE + 0x00120000)
 
 #define EP93XX_SYSCON_BASE             (EP93XX_APB_VIRT_BASE + 0x00130000)
 #define EP93XX_SYSCON_REG(x)           (EP93XX_SYSCON_BASE + (x))
 #define EP93XX_SYSCON_POWER_STATE      EP93XX_SYSCON_REG(0x00)
-#define EP93XX_SYSCON_CLOCK_CONTROL    EP93XX_SYSCON_REG(0x04)
-#define EP93XX_SYSCON_CLOCK_UARTBAUD   0x20000000
-#define EP93XX_SYSCON_CLOCK_USH_EN     0x10000000
+#define EP93XX_SYSCON_PWRCNT           EP93XX_SYSCON_REG(0x04)
+#define EP93XX_SYSCON_PWRCNT_FIR_EN    (1<<31)
+#define EP93XX_SYSCON_PWRCNT_UARTBAUD  (1<<29)
+#define EP93XX_SYSCON_PWRCNT_USH_EN    (1<<28)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2M1  (1<<27)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2M0  (1<<26)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P8  (1<<25)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P9  (1<<24)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P6  (1<<23)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P7  (1<<22)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P4  (1<<21)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P5  (1<<20)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P2  (1<<19)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P3  (1<<18)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P0  (1<<17)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P1  (1<<16)
 #define EP93XX_SYSCON_HALT             EP93XX_SYSCON_REG(0x08)
 #define EP93XX_SYSCON_STANDBY          EP93XX_SYSCON_REG(0x0c)
 #define EP93XX_SYSCON_CLOCK_SET1       EP93XX_SYSCON_REG(0x20)
index 5c80c3c8158dc01145f14cd2964b2e25463ee3e4..925b12ea0990bde4d9df1500854717877d9f8b0f 100644 (file)
@@ -5,6 +5,12 @@
 #ifndef __ASM_ARCH_MEMORY_H
 #define __ASM_ARCH_MEMORY_H
 
+#if defined(CONFIG_EP93XX_SDCE3_SYNC_PHYS_OFFSET)
 #define PHYS_OFFSET            UL(0x00000000)
+#elif defined(CONFIG_EP93XX_SDCE0_PHYS_OFFSET)
+#define PHYS_OFFSET            UL(0xc0000000)
+#else
+#error "Kconfig bug: No EP93xx PHYS_OFFSET set"
+#endif
 
 #endif
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
deleted file mode 100644 (file)
index cddd194..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-menu "IMX Implementations"
-       depends on ARCH_IMX
-
-config ARCH_MX1ADS
-       bool "mx1ads"
-       depends on ARCH_IMX
-       select ISA
-       help
-         Say Y here if you are using the Motorola MX1ADS board
-
-endmenu
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
deleted file mode 100644 (file)
index b047c7e..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-
-# Object file lists.
-
-obj-y                  += irq.o time.o dma.o generic.o clock.o
-
-obj-$(CONFIG_CPU_FREQ_IMX)     += cpufreq.o
-
-# Specific board support
-obj-$(CONFIG_ARCH_MX1ADS) += mx1ads.o
-
-# Support for blinky lights
-led-y := leds.o
-
-obj-$(CONFIG_LEDS)     +=  $(led-y)
-led-$(CONFIG_ARCH_MX1ADS) += leds-mx1ads.o
diff --git a/arch/arm/mach-imx/Makefile.boot b/arch/arm/mach-imx/Makefile.boot
deleted file mode 100644 (file)
index fd72ce5..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-    zreladdr-$(CONFIG_ARCH_MX1ADS)     := 0x08008000
-
diff --git a/arch/arm/mach-imx/clock.c b/arch/arm/mach-imx/clock.c
deleted file mode 100644 (file)
index cf332ae..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- *  Copyright (C) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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/device.h>
-#include <linux/list.h>
-#include <linux/math64.h>
-#include <linux/err.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-
-/*
- * Very simple approach: We can't disable clocks, so we do
- * not need refcounting
- */
-
-struct clk {
-       struct list_head node;
-       const char *name;
-       unsigned long (*get_rate)(void);
-};
-
-/*
- *  get the system pll clock in Hz
- *
- *                  mfi + mfn / (mfd +1)
- *  f = 2 * f_ref * --------------------
- *                        pd + 1
- */
-static unsigned long imx_decode_pll(unsigned int pll, u32 f_ref)
-{
-       unsigned long long ll;
-       unsigned long quot;
-
-       u32 mfi = (pll >> 10) & 0xf;
-       u32 mfn = pll & 0x3ff;
-       u32 mfd = (pll >> 16) & 0x3ff;
-       u32 pd =  (pll >> 26) & 0xf;
-
-       mfi = mfi <= 5 ? 5 : mfi;
-
-       ll = 2 * (unsigned long long)f_ref *
-               ((mfi << 16) + (mfn << 16) / (mfd + 1));
-       quot = (pd + 1) * (1 << 16);
-       ll += quot / 2;
-       do_div(ll, quot);
-       return (unsigned long)ll;
-}
-
-static unsigned long imx_get_system_clk(void)
-{
-       u32 f_ref = (CSCR & CSCR_SYSTEM_SEL) ? 16000000 : (CLK32 * 512);
-
-       return imx_decode_pll(SPCTL0, f_ref);
-}
-
-static unsigned long imx_get_mcu_clk(void)
-{
-       return imx_decode_pll(MPCTL0, CLK32 * 512);
-}
-
-/*
- *  get peripheral clock 1 ( UART[12], Timer[12], PWM )
- */
-static unsigned long imx_get_perclk1(void)
-{
-       return imx_get_system_clk() / (((PCDR) & 0xf)+1);
-}
-
-/*
- *  get peripheral clock 2 ( LCD, SD, SPI[12] )
- */
-static unsigned long imx_get_perclk2(void)
-{
-       return imx_get_system_clk() / (((PCDR>>4) & 0xf)+1);
-}
-
-/*
- *  get peripheral clock 3 ( SSI )
- */
-static unsigned long imx_get_perclk3(void)
-{
-       return imx_get_system_clk() / (((PCDR>>16) & 0x7f)+1);
-}
-
-/*
- *  get hclk ( SDRAM, CSI, Memory Stick, I2C, DMA )
- */
-static unsigned long imx_get_hclk(void)
-{
-       return imx_get_system_clk() / (((CSCR>>10) & 0xf)+1);
-}
-
-static struct clk clk_system_clk = {
-       .name = "system_clk",
-       .get_rate = imx_get_system_clk,
-};
-
-static struct clk clk_hclk = {
-       .name = "hclk",
-       .get_rate = imx_get_hclk,
-};
-
-static struct clk clk_mcu_clk = {
-       .name = "mcu_clk",
-       .get_rate = imx_get_mcu_clk,
-};
-
-static struct clk clk_perclk1 = {
-       .name = "perclk1",
-       .get_rate = imx_get_perclk1,
-};
-
-static struct clk clk_uart_clk = {
-       .name = "uart_clk",
-       .get_rate = imx_get_perclk1,
-};
-
-static struct clk clk_perclk2 = {
-       .name = "perclk2",
-       .get_rate = imx_get_perclk2,
-};
-
-static struct clk clk_perclk3 = {
-       .name = "perclk3",
-       .get_rate = imx_get_perclk3,
-};
-
-static struct clk *clks[] = {
-       &clk_perclk1,
-       &clk_perclk2,
-       &clk_perclk3,
-       &clk_system_clk,
-       &clk_hclk,
-       &clk_mcu_clk,
-       &clk_uart_clk,
-};
-
-static LIST_HEAD(clocks);
-static DEFINE_MUTEX(clocks_mutex);
-
-struct clk *clk_get(struct device *dev, const char *id)
-{
-       struct clk *p, *clk = ERR_PTR(-ENOENT);
-
-       mutex_lock(&clocks_mutex);
-       list_for_each_entry(p, &clocks, node) {
-               if (!strcmp(p->name, id)) {
-                       clk = p;
-                       goto found;
-               }
-       }
-
-found:
-       mutex_unlock(&clocks_mutex);
-
-       return clk;
-}
-EXPORT_SYMBOL(clk_get);
-
-void clk_put(struct clk *clk)
-{
-}
-EXPORT_SYMBOL(clk_put);
-
-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->get_rate();
-}
-EXPORT_SYMBOL(clk_get_rate);
-
-int imx_clocks_init(void)
-{
-       int i;
-
-       mutex_lock(&clocks_mutex);
-       for (i = 0; i < ARRAY_SIZE(clks); i++)
-               list_add(&clks[i]->node, &clocks);
-       mutex_unlock(&clocks_mutex);
-
-       return 0;
-}
-
diff --git a/arch/arm/mach-imx/cpufreq.c b/arch/arm/mach-imx/cpufreq.c
deleted file mode 100644 (file)
index 434b4ca..0000000
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * cpu.c: clock scaling for the iMX
- *
- * Copyright (C) 2000 2001, The Delft University of Technology
- * Copyright (c) 2004 Sascha Hauer <sascha@saschahauer.de>
- * Copyright (C) 2006 Inky Lung <ilung@cwlinux.com>
- * Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com>
- *
- * Based on SA1100 version written by:
- * - Johan Pouwelse (J.A.Pouwelse@its.tudelft.nl): initial version
- * - Erik Mouw (J.A.K.Mouw@its.tudelft.nl):
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-/*#define DEBUG*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/cpufreq.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <asm/system.h>
-
-#include <mach/hardware.h>
-
-#include "generic.h"
-
-#ifndef __val2mfld
-#define __val2mfld(mask,val) (((mask)&~((mask)<<1))*(val)&(mask))
-#endif
-#ifndef __mfld2val
-#define __mfld2val(mask,val) (((val)&(mask))/((mask)&~((mask)<<1)))
-#endif
-
-#define CR_920T_CLOCK_MODE     0xC0000000
-#define CR_920T_FASTBUS_MODE   0x00000000
-#define CR_920T_ASYNC_MODE     0xC0000000
-
-static u32 mpctl0_at_boot;
-static u32 bclk_div_at_boot;
-
-static struct clk *system_clk, *mcu_clk;
-
-static void imx_set_async_mode(void)
-{
-       adjust_cr(CR_920T_CLOCK_MODE, CR_920T_ASYNC_MODE);
-}
-
-static void imx_set_fastbus_mode(void)
-{
-       adjust_cr(CR_920T_CLOCK_MODE, CR_920T_FASTBUS_MODE);
-}
-
-static void imx_set_mpctl0(u32 mpctl0)
-{
-       unsigned long flags;
-
-       if (mpctl0 == 0) {
-               local_irq_save(flags);
-               CSCR &= ~CSCR_MPEN;
-               local_irq_restore(flags);
-               return;
-       }
-
-       local_irq_save(flags);
-       MPCTL0 = mpctl0;
-       CSCR |= CSCR_MPEN;
-       local_irq_restore(flags);
-}
-
-/**
- * imx_compute_mpctl - compute new PLL parameters
- * @new_mpctl: pointer to location assigned by new PLL control register value
- * @cur_mpctl: current PLL control register parameters
- * @f_ref:     reference source frequency Hz
- * @freq:      required frequency in Hz
- * @relation:  is one of %CPUFREQ_RELATION_L (supremum)
- *             and %CPUFREQ_RELATION_H (infimum)
- */
-long imx_compute_mpctl(u32 *new_mpctl, u32 cur_mpctl, u32 f_ref, unsigned long freq, int relation)
-{
-        u32 mfi;
-        u32 mfn;
-        u32 mfd;
-        u32 pd;
-       unsigned long long ll;
-       long l;
-       long quot;
-
-       /* Fdppl=2*Fref*(MFI+MFN/(MFD+1))/(PD+1) */
-       /*  PD=<0,15>, MFD=<1,1023>, MFI=<5,15> MFN=<0,1022> */
-
-       if (cur_mpctl) {
-               mfd = ((cur_mpctl >> 16) & 0x3ff) + 1;
-               pd =  ((cur_mpctl >> 26) & 0xf) + 1;
-       } else {
-               pd=2; mfd=313;
-       }
-
-       /* pd=2; mfd=313; mfi=8; mfn=183; */
-       /* (MFI+MFN/(MFD)) = Fdppl / (2*Fref) * (PD); */
-
-       quot = (f_ref + (1 << 9)) >> 10;
-       l = (freq * pd + quot) / (2 * quot);
-       mfi = l >> 10;
-       mfn = ((l & ((1 << 10) - 1)) * mfd + (1 << 9)) >> 10;
-
-       mfd -= 1;
-       pd -= 1;
-
-       *new_mpctl = ((mfi & 0xf) << 10) | (mfn & 0x3ff) | ((mfd & 0x3ff) << 16)
-               | ((pd & 0xf) << 26);
-
-       ll = 2 * (unsigned long long)f_ref * ( (mfi<<16) + (mfn<<16) / (mfd+1) );
-       quot = (pd+1) * (1<<16);
-       ll += quot / 2;
-       do_div(ll, quot);
-       freq = ll;
-
-       pr_debug(KERN_DEBUG "imx: new PLL parameters pd=%d mfd=%d mfi=%d mfn=%d, freq=%ld\n",
-               pd, mfd, mfi, mfn, freq);
-
-       return freq;
-}
-
-
-static int imx_verify_speed(struct cpufreq_policy *policy)
-{
-       if (policy->cpu != 0)
-               return -EINVAL;
-
-       cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, policy->cpuinfo.max_freq);
-
-       return 0;
-}
-
-static unsigned int imx_get_speed(unsigned int cpu)
-{
-       unsigned int freq;
-       unsigned int cr;
-       unsigned int cscr;
-       unsigned int bclk_div;
-
-       if (cpu)
-               return 0;
-
-       cscr = CSCR;
-       bclk_div = __mfld2val(CSCR_BCLK_DIV, cscr) + 1;
-       cr = get_cr();
-
-       if((cr & CR_920T_CLOCK_MODE) == CR_920T_FASTBUS_MODE) {
-               freq = clk_get_rate(system_clk);
-               freq = (freq + bclk_div/2) / bclk_div;
-       } else {
-               freq = clk_get_rate(mcu_clk);
-               if (cscr & CSCR_MPU_PRESC)
-                       freq /= 2;
-       }
-
-       freq = (freq + 500) / 1000;
-
-       return freq;
-}
-
-static int imx_set_target(struct cpufreq_policy *policy,
-                         unsigned int target_freq,
-                         unsigned int relation)
-{
-       struct cpufreq_freqs freqs;
-       u32 mpctl0 = 0;
-       u32 cscr;
-       unsigned long flags;
-       long freq;
-       long sysclk;
-       unsigned int bclk_div = bclk_div_at_boot;
-
-       /*
-        * Some governors do not respects CPU and policy lower limits
-        * which leads to bad things (division by zero etc), ensure
-        * that such things do not happen.
-        */
-       if(target_freq < policy->cpuinfo.min_freq)
-               target_freq = policy->cpuinfo.min_freq;
-
-       if(target_freq < policy->min)
-               target_freq = policy->min;
-
-       freq = target_freq * 1000;
-
-       pr_debug(KERN_DEBUG "imx: requested frequency %ld Hz, mpctl0 at boot 0x%08x\n",
-                       freq, mpctl0_at_boot);
-
-       sysclk = clk_get_rate(system_clk);
-
-       if (freq > sysclk / bclk_div_at_boot + 1000000) {
-               freq = imx_compute_mpctl(&mpctl0, mpctl0_at_boot, CLK32 * 512, freq, relation);
-               if (freq < 0) {
-                       printk(KERN_WARNING "imx: target frequency %ld Hz cannot be set\n", freq);
-                       return -EINVAL;
-               }
-       } else {
-               if(freq + 1000 < sysclk) {
-                       if (relation == CPUFREQ_RELATION_L)
-                               bclk_div = (sysclk - 1000) / freq;
-                       else
-                               bclk_div = (sysclk + freq + 1000) / freq;
-
-                       if(bclk_div > 16)
-                               bclk_div = 16;
-                       if(bclk_div < bclk_div_at_boot)
-                               bclk_div = bclk_div_at_boot;
-               }
-               freq = (sysclk + bclk_div / 2) / bclk_div;
-       }
-
-       freqs.old = imx_get_speed(0);
-       freqs.new = (freq + 500) / 1000;
-       freqs.cpu = 0;
-       freqs.flags = 0;
-
-       cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-
-       local_irq_save(flags);
-
-       imx_set_fastbus_mode();
-
-       imx_set_mpctl0(mpctl0);
-
-       cscr = CSCR;
-       cscr &= ~CSCR_BCLK_DIV;
-       cscr |= __val2mfld(CSCR_BCLK_DIV, bclk_div - 1);
-       CSCR = cscr;
-
-       if(mpctl0) {
-               CSCR |= CSCR_MPLL_RESTART;
-
-               /* Wait until MPLL is stabilized */
-               while( CSCR & CSCR_MPLL_RESTART );
-
-               imx_set_async_mode();
-       }
-
-       local_irq_restore(flags);
-
-       cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-
-       pr_debug(KERN_INFO "imx: set frequency %ld Hz, running from %s\n",
-                       freq, mpctl0? "MPLL": "SPLL");
-
-       return 0;
-}
-
-static int __init imx_cpufreq_driver_init(struct cpufreq_policy *policy)
-{
-       printk(KERN_INFO "i.MX cpu freq change driver v1.0\n");
-
-       if (policy->cpu != 0)
-               return -EINVAL;
-
-       policy->cur = policy->min = policy->max = imx_get_speed(0);
-       policy->cpuinfo.min_freq = 8000;
-       policy->cpuinfo.max_freq = 200000;
-        /* Manual states, that PLL stabilizes in two CLK32 periods */
-       policy->cpuinfo.transition_latency = 4 * 1000000000LL / CLK32;
-       return 0;
-}
-
-static struct cpufreq_driver imx_driver = {
-       .flags          = CPUFREQ_STICKY,
-       .verify         = imx_verify_speed,
-       .target         = imx_set_target,
-       .get            = imx_get_speed,
-       .init           = imx_cpufreq_driver_init,
-       .name           = "imx",
-};
-
-static int __init imx_cpufreq_init(void)
-{
-       bclk_div_at_boot = __mfld2val(CSCR_BCLK_DIV, CSCR) + 1;
-       mpctl0_at_boot = 0;
-
-       system_clk = clk_get(NULL, "system_clk");
-       if (IS_ERR(system_clk))
-               return PTR_ERR(system_clk);
-
-       mcu_clk = clk_get(NULL, "mcu_clk");
-       if (IS_ERR(mcu_clk)) {
-               clk_put(system_clk);
-               return PTR_ERR(mcu_clk);
-       }
-
-       if((CSCR & CSCR_MPEN) &&
-          ((get_cr() & CR_920T_CLOCK_MODE) != CR_920T_FASTBUS_MODE))
-               mpctl0_at_boot = MPCTL0;
-
-       return cpufreq_register_driver(&imx_driver);
-}
-
-arch_initcall(imx_cpufreq_init);
-
diff --git a/arch/arm/mach-imx/dma.c b/arch/arm/mach-imx/dma.c
deleted file mode 100644 (file)
index 1536583..0000000
+++ /dev/null
@@ -1,597 +0,0 @@
-/*
- *  linux/arch/arm/mach-imx/dma.c
- *
- *  imx DMA registration and IRQ dispatching
- *
- *  This 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.
- *
- *  2004-03-03 Sascha Hauer <sascha@saschahauer.de>
- *             initial version heavily inspired by
- *             linux/arch/arm/mach-pxa/dma.c
- *
- *  2005-04-17 Pavel Pisa <pisa@cmp.felk.cvut.cz>
- *             Changed to support scatter gather DMA
- *             by taking Russell's code from RiscPC
- *
- *  2006-05-31 Pavel Pisa <pisa@cmp.felk.cvut.cz>
- *             Corrected error handling code.
- *
- */
-
-#undef DEBUG
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/errno.h>
-
-#include <asm/scatterlist.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <mach/hardware.h>
-#include <mach/dma.h>
-#include <mach/imx-dma.h>
-
-struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS];
-
-/*
- * imx_dma_sg_next - prepare next chunk for scatter-gather DMA emulation
- * @dma_ch: i.MX DMA channel number
- * @lastcount: number of bytes transferred during last transfer
- *
- * Functions prepares DMA controller for next sg data chunk transfer.
- * The @lastcount argument informs function about number of bytes transferred
- * during last block. Zero value can be used for @lastcount to setup DMA
- * for the first chunk.
- */
-static inline int imx_dma_sg_next(imx_dmach_t dma_ch, unsigned int lastcount)
-{
-       struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
-       unsigned int nextcount;
-       unsigned int nextaddr;
-
-       if (!imxdma->name) {
-               printk(KERN_CRIT "%s: called for  not allocated channel %d\n",
-                      __func__, dma_ch);
-               return 0;
-       }
-
-       imxdma->resbytes -= lastcount;
-
-       if (!imxdma->sg) {
-               pr_debug("imxdma%d: no sg data\n", dma_ch);
-               return 0;
-       }
-
-       imxdma->sgbc += lastcount;
-       if ((imxdma->sgbc >= imxdma->sg->length) || !imxdma->resbytes) {
-               if ((imxdma->sgcount <= 1) || !imxdma->resbytes) {
-                       pr_debug("imxdma%d: sg transfer limit reached\n",
-                                dma_ch);
-                       imxdma->sgcount=0;
-                       imxdma->sg = NULL;
-                       return 0;
-               } else {
-                       imxdma->sgcount--;
-                       imxdma->sg++;
-                       imxdma->sgbc = 0;
-               }
-       }
-       nextcount = imxdma->sg->length - imxdma->sgbc;
-       nextaddr = imxdma->sg->dma_address + imxdma->sgbc;
-
-       if(imxdma->resbytes < nextcount)
-               nextcount = imxdma->resbytes;
-
-       if ((imxdma->dma_mode & DMA_MODE_MASK) == DMA_MODE_READ)
-               DAR(dma_ch) = nextaddr;
-       else
-               SAR(dma_ch) = nextaddr;
-
-       CNTR(dma_ch) = nextcount;
-       pr_debug("imxdma%d: next sg chunk dst 0x%08x, src 0x%08x, size 0x%08x\n",
-                dma_ch, DAR(dma_ch), SAR(dma_ch), CNTR(dma_ch));
-
-       return nextcount;
-}
-
-/*
- * imx_dma_setup_sg_base - scatter-gather DMA emulation
- * @dma_ch: i.MX DMA channel number
- * @sg: pointer to the scatter-gather list/vector
- * @sgcount: scatter-gather list hungs count
- *
- * Functions sets up i.MX DMA state for emulated scatter-gather transfer
- * and sets up channel registers to be ready for the first chunk
- */
-static int
-imx_dma_setup_sg_base(imx_dmach_t dma_ch,
-                     struct scatterlist *sg, unsigned int sgcount)
-{
-       struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
-
-       imxdma->sg = sg;
-       imxdma->sgcount = sgcount;
-       imxdma->sgbc = 0;
-       return imx_dma_sg_next(dma_ch, 0);
-}
-
-/**
- * imx_dma_setup_single - setup i.MX DMA channel for linear memory to/from device transfer
- * @dma_ch: i.MX DMA channel number
- * @dma_address: the DMA/physical memory address of the linear data block
- *             to transfer
- * @dma_length: length of the data block in bytes
- * @dev_addr: physical device port address
- * @dmamode: DMA transfer mode, %DMA_MODE_READ from the device to the memory
- *           or %DMA_MODE_WRITE from memory to the device
- *
- * The function setups DMA channel source and destination addresses for transfer
- * specified by provided parameters. The scatter-gather emulation is disabled,
- * because linear data block
- * form the physical address range is transferred.
- * Return value: if incorrect parameters are provided -%EINVAL.
- *             Zero indicates success.
- */
-int
-imx_dma_setup_single(imx_dmach_t dma_ch, dma_addr_t dma_address,
-                    unsigned int dma_length, unsigned int dev_addr,
-                    unsigned int dmamode)
-{
-       struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
-
-       imxdma->sg = NULL;
-       imxdma->sgcount = 0;
-       imxdma->dma_mode = dmamode;
-       imxdma->resbytes = dma_length;
-
-       if (!dma_address) {
-               printk(KERN_ERR "imxdma%d: imx_dma_setup_single null address\n",
-                      dma_ch);
-               return -EINVAL;
-       }
-
-       if (!dma_length) {
-               printk(KERN_ERR "imxdma%d: imx_dma_setup_single zero length\n",
-                      dma_ch);
-               return -EINVAL;
-       }
-
-       if ((dmamode & DMA_MODE_MASK) == DMA_MODE_READ) {
-               pr_debug("imxdma%d: mx_dma_setup_single2dev dma_addressg=0x%08x dma_length=%d dev_addr=0x%08x for read\n",
-                       dma_ch, (unsigned int)dma_address, dma_length,
-                       dev_addr);
-               SAR(dma_ch) = dev_addr;
-               DAR(dma_ch) = (unsigned int)dma_address;
-       } else if ((dmamode & DMA_MODE_MASK) == DMA_MODE_WRITE) {
-               pr_debug("imxdma%d: mx_dma_setup_single2dev dma_addressg=0x%08x dma_length=%d dev_addr=0x%08x for write\n",
-                       dma_ch, (unsigned int)dma_address, dma_length,
-                       dev_addr);
-               SAR(dma_ch) = (unsigned int)dma_address;
-               DAR(dma_ch) = dev_addr;
-       } else {
-               printk(KERN_ERR "imxdma%d: imx_dma_setup_single bad dmamode\n",
-                      dma_ch);
-               return -EINVAL;
-       }
-
-       CNTR(dma_ch) = dma_length;
-
-       return 0;
-}
-
-/**
- * imx_dma_setup_sg - setup i.MX DMA channel SG list to/from device transfer
- * @dma_ch: i.MX DMA channel number
- * @sg: pointer to the scatter-gather list/vector
- * @sgcount: scatter-gather list hungs count
- * @dma_length: total length of the transfer request in bytes
- * @dev_addr: physical device port address
- * @dmamode: DMA transfer mode, %DMA_MODE_READ from the device to the memory
- *           or %DMA_MODE_WRITE from memory to the device
- *
- * The function sets up DMA channel state and registers to be ready for transfer
- * specified by provided parameters. The scatter-gather emulation is set up
- * according to the parameters.
- *
- * The full preparation of the transfer requires setup of more register
- * by the caller before imx_dma_enable() can be called.
- *
- * %BLR(dma_ch) holds transfer burst length in bytes, 0 means 64 bytes
- *
- * %RSSR(dma_ch) has to be set to the DMA request line source %DMA_REQ_xxx
- *
- * %CCR(dma_ch) has to specify transfer parameters, the next settings is typical
- * for linear or simple scatter-gather transfers if %DMA_MODE_READ is specified
- *
- * %CCR_DMOD_LINEAR | %CCR_DSIZ_32 | %CCR_SMOD_FIFO | %CCR_SSIZ_x
- *
- * The typical setup for %DMA_MODE_WRITE is specified by next options combination
- *
- * %CCR_SMOD_LINEAR | %CCR_SSIZ_32 | %CCR_DMOD_FIFO | %CCR_DSIZ_x
- *
- * Be careful here and do not mistakenly mix source and target device
- * port sizes constants, they are really different:
- * %CCR_SSIZ_8, %CCR_SSIZ_16, %CCR_SSIZ_32,
- * %CCR_DSIZ_8, %CCR_DSIZ_16, %CCR_DSIZ_32
- *
- * Return value: if incorrect parameters are provided -%EINVAL.
- * Zero indicates success.
- */
-int
-imx_dma_setup_sg(imx_dmach_t dma_ch,
-                struct scatterlist *sg, unsigned int sgcount, unsigned int dma_length,
-                unsigned int dev_addr, unsigned int dmamode)
-{
-       int res;
-       struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
-
-       imxdma->sg = NULL;
-       imxdma->sgcount = 0;
-       imxdma->dma_mode = dmamode;
-       imxdma->resbytes = dma_length;
-
-       if (!sg || !sgcount) {
-               printk(KERN_ERR "imxdma%d: imx_dma_setup_sg epty sg list\n",
-                      dma_ch);
-               return -EINVAL;
-       }
-
-       if (!sg->length) {
-               printk(KERN_ERR "imxdma%d: imx_dma_setup_sg zero length\n",
-                      dma_ch);
-               return -EINVAL;
-       }
-
-       if ((dmamode & DMA_MODE_MASK) == DMA_MODE_READ) {
-               pr_debug("imxdma%d: mx_dma_setup_sg2dev sg=%p sgcount=%d total length=%d dev_addr=0x%08x for read\n",
-                       dma_ch, sg, sgcount, dma_length, dev_addr);
-               SAR(dma_ch) = dev_addr;
-       } else if ((dmamode & DMA_MODE_MASK) == DMA_MODE_WRITE) {
-               pr_debug("imxdma%d: mx_dma_setup_sg2dev sg=%p sgcount=%d total length=%d dev_addr=0x%08x for write\n",
-                       dma_ch, sg, sgcount, dma_length, dev_addr);
-               DAR(dma_ch) = dev_addr;
-       } else {
-               printk(KERN_ERR "imxdma%d: imx_dma_setup_sg bad dmamode\n",
-                      dma_ch);
-               return -EINVAL;
-       }
-
-       res = imx_dma_setup_sg_base(dma_ch, sg, sgcount);
-       if (res <= 0) {
-               printk(KERN_ERR "imxdma%d: no sg chunk ready\n", dma_ch);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/**
- * imx_dma_setup_handlers - setup i.MX DMA channel end and error notification handlers
- * @dma_ch: i.MX DMA channel number
- * @irq_handler: the pointer to the function called if the transfer
- *             ends successfully
- * @err_handler: the pointer to the function called if the premature
- *             end caused by error occurs
- * @data: user specified value to be passed to the handlers
- */
-int
-imx_dma_setup_handlers(imx_dmach_t dma_ch,
-                      void (*irq_handler) (int, void *),
-                      void (*err_handler) (int, void *, int),
-                      void *data)
-{
-       struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
-       unsigned long flags;
-
-       if (!imxdma->name) {
-               printk(KERN_CRIT "%s: called for  not allocated channel %d\n",
-                      __func__, dma_ch);
-               return -ENODEV;
-       }
-
-       local_irq_save(flags);
-       DISR = (1 << dma_ch);
-       imxdma->irq_handler = irq_handler;
-       imxdma->err_handler = err_handler;
-       imxdma->data = data;
-       local_irq_restore(flags);
-       return 0;
-}
-
-/**
- * imx_dma_enable - function to start i.MX DMA channel operation
- * @dma_ch: i.MX DMA channel number
- *
- * The channel has to be allocated by driver through imx_dma_request()
- * or imx_dma_request_by_prio() function.
- * The transfer parameters has to be set to the channel registers through
- * call of the imx_dma_setup_single() or imx_dma_setup_sg() function
- * and registers %BLR(dma_ch), %RSSR(dma_ch) and %CCR(dma_ch) has to
- * be set prior this function call by the channel user.
- */
-void imx_dma_enable(imx_dmach_t dma_ch)
-{
-       struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
-       unsigned long flags;
-
-       pr_debug("imxdma%d: imx_dma_enable\n", dma_ch);
-
-       if (!imxdma->name) {
-               printk(KERN_CRIT "%s: called for  not allocated channel %d\n",
-                      __func__, dma_ch);
-               return;
-       }
-
-       local_irq_save(flags);
-       DISR = (1 << dma_ch);
-       DIMR &= ~(1 << dma_ch);
-       CCR(dma_ch) |= CCR_CEN;
-       local_irq_restore(flags);
-}
-
-/**
- * imx_dma_disable - stop, finish i.MX DMA channel operatin
- * @dma_ch: i.MX DMA channel number
- */
-void imx_dma_disable(imx_dmach_t dma_ch)
-{
-       unsigned long flags;
-
-       pr_debug("imxdma%d: imx_dma_disable\n", dma_ch);
-
-       local_irq_save(flags);
-       DIMR |= (1 << dma_ch);
-       CCR(dma_ch) &= ~CCR_CEN;
-       DISR = (1 << dma_ch);
-       local_irq_restore(flags);
-}
-
-/**
- * imx_dma_request - request/allocate specified channel number
- * @dma_ch: i.MX DMA channel number
- * @name: the driver/caller own non-%NULL identification
- */
-int imx_dma_request(imx_dmach_t dma_ch, const char *name)
-{
-       struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
-       unsigned long flags;
-
-       /* basic sanity checks */
-       if (!name)
-               return -EINVAL;
-
-       if (dma_ch >= IMX_DMA_CHANNELS) {
-               printk(KERN_CRIT "%s: called for  non-existed channel %d\n",
-                      __func__, dma_ch);
-               return -EINVAL;
-       }
-
-       local_irq_save(flags);
-       if (imxdma->name) {
-               local_irq_restore(flags);
-               return -ENODEV;
-       }
-
-       imxdma->name = name;
-       imxdma->irq_handler = NULL;
-       imxdma->err_handler = NULL;
-       imxdma->data = NULL;
-       imxdma->sg = NULL;
-       local_irq_restore(flags);
-       return 0;
-}
-
-/**
- * imx_dma_free - release previously acquired channel
- * @dma_ch: i.MX DMA channel number
- */
-void imx_dma_free(imx_dmach_t dma_ch)
-{
-       unsigned long flags;
-       struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
-
-       if (!imxdma->name) {
-               printk(KERN_CRIT
-                      "%s: trying to free channel %d which is already freed\n",
-                      __func__, dma_ch);
-               return;
-       }
-
-       local_irq_save(flags);
-       /* Disable interrupts */
-       DIMR |= (1 << dma_ch);
-       CCR(dma_ch) &= ~CCR_CEN;
-       imxdma->name = NULL;
-       local_irq_restore(flags);
-}
-
-/**
- * imx_dma_request_by_prio - find and request some of free channels best suiting requested priority
- * @name: the driver/caller own non-%NULL identification
- * @prio: one of the hardware distinguished priority level:
- *        %DMA_PRIO_HIGH, %DMA_PRIO_MEDIUM, %DMA_PRIO_LOW
- *
- * This function tries to find free channel in the specified priority group
- * if the priority cannot be achieved it tries to look for free channel
- * in the higher and then even lower priority groups.
- *
- * Return value: If there is no free channel to allocate, -%ENODEV is returned.
- *               On successful allocation channel is returned.
- */
-imx_dmach_t imx_dma_request_by_prio(const char *name, imx_dma_prio prio)
-{
-       int i;
-       int best;
-
-       switch (prio) {
-       case (DMA_PRIO_HIGH):
-               best = 8;
-               break;
-       case (DMA_PRIO_MEDIUM):
-               best = 4;
-               break;
-       case (DMA_PRIO_LOW):
-       default:
-               best = 0;
-               break;
-       }
-
-       for (i = best; i < IMX_DMA_CHANNELS; i++) {
-               if (!imx_dma_request(i, name)) {
-                       return i;
-               }
-       }
-
-       for (i = best - 1; i >= 0; i--) {
-               if (!imx_dma_request(i, name)) {
-                       return i;
-               }
-       }
-
-       printk(KERN_ERR "%s: no free DMA channel found\n", __func__);
-
-       return -ENODEV;
-}
-
-static irqreturn_t dma_err_handler(int irq, void *dev_id)
-{
-       int i, disr = DISR;
-       struct imx_dma_channel *channel;
-       unsigned int err_mask = DBTOSR | DRTOSR | DSESR | DBOSR;
-       int errcode;
-
-       DISR = disr & err_mask;
-       for (i = 0; i < IMX_DMA_CHANNELS; i++) {
-               if(!(err_mask & (1 << i)))
-                       continue;
-               channel = &imx_dma_channels[i];
-               errcode = 0;
-
-               if (DBTOSR & (1 << i)) {
-                       DBTOSR = (1 << i);
-                       errcode |= IMX_DMA_ERR_BURST;
-               }
-               if (DRTOSR & (1 << i)) {
-                       DRTOSR = (1 << i);
-                       errcode |= IMX_DMA_ERR_REQUEST;
-               }
-               if (DSESR & (1 << i)) {
-                       DSESR = (1 << i);
-                       errcode |= IMX_DMA_ERR_TRANSFER;
-               }
-               if (DBOSR & (1 << i)) {
-                       DBOSR = (1 << i);
-                       errcode |= IMX_DMA_ERR_BUFFER;
-               }
-
-               /*
-                * The cleaning of @sg field would be questionable
-                * there, because its value can help to compute
-                * remaining/transferred bytes count in the handler
-                */
-               /*imx_dma_channels[i].sg = NULL;*/
-
-               if (channel->name && channel->err_handler) {
-                       channel->err_handler(i, channel->data, errcode);
-                       continue;
-               }
-
-               imx_dma_channels[i].sg = NULL;
-
-               printk(KERN_WARNING
-                      "DMA timeout on channel %d (%s) -%s%s%s%s\n",
-                      i, channel->name,
-                      errcode&IMX_DMA_ERR_BURST?    " burst":"",
-                      errcode&IMX_DMA_ERR_REQUEST?  " request":"",
-                      errcode&IMX_DMA_ERR_TRANSFER? " transfer":"",
-                      errcode&IMX_DMA_ERR_BUFFER?   " buffer":"");
-       }
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t dma_irq_handler(int irq, void *dev_id)
-{
-       int i, disr = DISR;
-
-       pr_debug("imxdma: dma_irq_handler called, disr=0x%08x\n",
-                    disr);
-
-       DISR = disr;
-       for (i = 0; i < IMX_DMA_CHANNELS; i++) {
-               if (disr & (1 << i)) {
-                       struct imx_dma_channel *channel = &imx_dma_channels[i];
-                       if (channel->name) {
-                               if (imx_dma_sg_next(i, CNTR(i))) {
-                                       CCR(i) &= ~CCR_CEN;
-                                       mb();
-                                       CCR(i) |= CCR_CEN;
-                               } else {
-                                       if (channel->irq_handler)
-                                               channel->irq_handler(i,
-                                                       channel->data);
-                               }
-                       } else {
-                               /*
-                                * IRQ for an unregistered DMA channel:
-                                * let's clear the interrupts and disable it.
-                                */
-                               printk(KERN_WARNING
-                                      "spurious IRQ for DMA channel %d\n", i);
-                       }
-               }
-       }
-       return IRQ_HANDLED;
-}
-
-static int __init imx_dma_init(void)
-{
-       int ret;
-       int i;
-
-       /* reset DMA module */
-       DCR = DCR_DRST;
-
-       ret = request_irq(DMA_INT, dma_irq_handler, 0, "DMA", NULL);
-       if (ret) {
-               printk(KERN_CRIT "Wow!  Can't register IRQ for DMA\n");
-               return ret;
-       }
-
-       ret = request_irq(DMA_ERR, dma_err_handler, 0, "DMA", NULL);
-       if (ret) {
-               printk(KERN_CRIT "Wow!  Can't register ERRIRQ for DMA\n");
-               free_irq(DMA_INT, NULL);
-       }
-
-       /* enable DMA module */
-       DCR = DCR_DEN;
-
-       /* clear all interrupts */
-       DISR = (1 << IMX_DMA_CHANNELS) - 1;
-
-       /* enable interrupts */
-       DIMR = (1 << IMX_DMA_CHANNELS) - 1;
-
-       for (i = 0; i < IMX_DMA_CHANNELS; i++) {
-               imx_dma_channels[i].sg = NULL;
-               imx_dma_channels[i].dma_num = i;
-       }
-
-       return ret;
-}
-
-arch_initcall(imx_dma_init);
-
-EXPORT_SYMBOL(imx_dma_setup_single);
-EXPORT_SYMBOL(imx_dma_setup_sg);
-EXPORT_SYMBOL(imx_dma_setup_handlers);
-EXPORT_SYMBOL(imx_dma_enable);
-EXPORT_SYMBOL(imx_dma_disable);
-EXPORT_SYMBOL(imx_dma_request);
-EXPORT_SYMBOL(imx_dma_free);
-EXPORT_SYMBOL(imx_dma_request_by_prio);
-EXPORT_SYMBOL(imx_dma_channels);
diff --git a/arch/arm/mach-imx/generic.c b/arch/arm/mach-imx/generic.c
deleted file mode 100644 (file)
index 05f1739..0000000
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- *  arch/arm/mach-imx/generic.c
- *
- *  author: Sascha Hauer
- *  Created: april 20th, 2004
- *  Copyright: Synertronixx GmbH
- *
- *  Common code for i.MX machines
- *
- * 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/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-
-#include <asm/errno.h>
-#include <mach/hardware.h>
-#include <mach/imx-regs.h>
-
-#include <asm/mach/map.h>
-#include <mach/mmc.h>
-#include <mach/gpio.h>
-
-unsigned long imx_gpio_alloc_map[(GPIO_PORT_MAX + 1) * 32 / BITS_PER_LONG];
-
-void imx_gpio_mode(int gpio_mode)
-{
-       unsigned int pin = gpio_mode & GPIO_PIN_MASK;
-       unsigned int port = (gpio_mode & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
-       unsigned int ocr = (gpio_mode & GPIO_OCR_MASK) >> GPIO_OCR_SHIFT;
-       unsigned int tmp;
-
-       /* Pullup enable */
-       if(gpio_mode & GPIO_PUEN)
-               PUEN(port) |= (1<<pin);
-       else
-               PUEN(port) &= ~(1<<pin);
-
-       /* Data direction */
-       if(gpio_mode & GPIO_OUT)
-               DDIR(port) |= 1<<pin;
-       else
-               DDIR(port) &= ~(1<<pin);
-
-       /* Primary / alternate function */
-       if(gpio_mode & GPIO_AF)
-               GPR(port) |= (1<<pin);
-       else
-               GPR(port) &= ~(1<<pin);
-
-       /* use as gpio? */
-       if(gpio_mode &  GPIO_GIUS)
-               GIUS(port) |= (1<<pin);
-       else
-               GIUS(port) &= ~(1<<pin);
-
-       /* Output / input configuration */
-       /* FIXME: I'm not very sure about OCR and ICONF, someone
-        * should have a look over it
-        */
-       if(pin<16) {
-               tmp = OCR1(port);
-               tmp &= ~( 3<<(pin*2));
-               tmp |= (ocr << (pin*2));
-               OCR1(port) = tmp;
-
-               ICONFA1(port) &= ~( 3<<(pin*2));
-               ICONFA1(port) |= ((gpio_mode >> GPIO_AOUT_SHIFT) & 3) << (pin * 2);
-               ICONFB1(port) &= ~( 3<<(pin*2));
-               ICONFB1(port) |= ((gpio_mode >> GPIO_BOUT_SHIFT) & 3) << (pin * 2);
-       } else {
-               tmp = OCR2(port);
-               tmp &= ~( 3<<((pin-16)*2));
-               tmp |= (ocr << ((pin-16)*2));
-               OCR2(port) = tmp;
-
-               ICONFA2(port) &= ~( 3<<((pin-16)*2));
-               ICONFA2(port) |= ((gpio_mode >> GPIO_AOUT_SHIFT) & 3) << ((pin-16) * 2);
-               ICONFB2(port) &= ~( 3<<((pin-16)*2));
-               ICONFB2(port) |= ((gpio_mode >> GPIO_BOUT_SHIFT) & 3) << ((pin-16) * 2);
-       }
-}
-
-EXPORT_SYMBOL(imx_gpio_mode);
-
-int imx_gpio_request(unsigned gpio, const char *label)
-{
-       if(gpio >= (GPIO_PORT_MAX + 1) * 32) {
-               printk(KERN_ERR "imx_gpio: Attempt to request nonexistent GPIO %d for \"%s\"\n",
-                       gpio, label ? label : "?");
-               return -EINVAL;
-       }
-
-       if(test_and_set_bit(gpio, imx_gpio_alloc_map)) {
-               printk(KERN_ERR "imx_gpio: GPIO %d already used. Allocation for \"%s\" failed\n",
-                       gpio, label ? label : "?");
-               return -EBUSY;
-       }
-
-       return 0;
-}
-
-EXPORT_SYMBOL(imx_gpio_request);
-
-void imx_gpio_free(unsigned gpio)
-{
-       if(gpio >= (GPIO_PORT_MAX + 1) * 32)
-               return;
-
-       clear_bit(gpio, imx_gpio_alloc_map);
-}
-
-EXPORT_SYMBOL(imx_gpio_free);
-
-int imx_gpio_direction_input(unsigned gpio)
-{
-       imx_gpio_mode(gpio | GPIO_IN | GPIO_GIUS | GPIO_DR);
-       return 0;
-}
-
-EXPORT_SYMBOL(imx_gpio_direction_input);
-
-int imx_gpio_direction_output(unsigned gpio, int value)
-{
-       imx_gpio_set_value(gpio, value);
-       imx_gpio_mode(gpio | GPIO_OUT | GPIO_GIUS | GPIO_DR);
-       return 0;
-}
-
-EXPORT_SYMBOL(imx_gpio_direction_output);
-
-int imx_gpio_setup_multiple_pins(const int *pin_list, unsigned count,
-                               int alloc_mode, const char *label)
-{
-       const int *p = pin_list;
-       int i;
-       unsigned gpio;
-       unsigned mode;
-
-       for (i = 0; i < count; i++) {
-               gpio = *p & (GPIO_PIN_MASK | GPIO_PORT_MASK);
-               mode = *p & ~(GPIO_PIN_MASK | GPIO_PORT_MASK);
-
-               if (gpio >= (GPIO_PORT_MAX + 1) * 32)
-                       goto setup_error;
-
-               if (alloc_mode & IMX_GPIO_ALLOC_MODE_RELEASE)
-                       imx_gpio_free(gpio);
-               else if (!(alloc_mode & IMX_GPIO_ALLOC_MODE_NO_ALLOC))
-                       if (imx_gpio_request(gpio, label))
-                               if (!(alloc_mode & IMX_GPIO_ALLOC_MODE_TRY_ALLOC))
-                                       goto setup_error;
-
-               if (!(alloc_mode & (IMX_GPIO_ALLOC_MODE_ALLOC_ONLY |
-                                   IMX_GPIO_ALLOC_MODE_RELEASE)))
-                       imx_gpio_mode(gpio | mode);
-
-               p++;
-       }
-       return 0;
-
-setup_error:
-       if(alloc_mode & (IMX_GPIO_ALLOC_MODE_NO_ALLOC |
-                        IMX_GPIO_ALLOC_MODE_TRY_ALLOC))
-               return -EINVAL;
-
-       while (p != pin_list) {
-               p--;
-               gpio = *p & (GPIO_PIN_MASK | GPIO_PORT_MASK);
-               imx_gpio_free(gpio);
-       }
-
-       return -EINVAL;
-}
-
-EXPORT_SYMBOL(imx_gpio_setup_multiple_pins);
-
-void __imx_gpio_set_value(unsigned gpio, int value)
-{
-       imx_gpio_set_value_inline(gpio, value);
-}
-
-EXPORT_SYMBOL(__imx_gpio_set_value);
-
-int imx_gpio_to_irq(unsigned gpio)
-{
-       return IRQ_GPIOA(0) + gpio;
-}
-
-EXPORT_SYMBOL(imx_gpio_to_irq);
-
-int imx_irq_to_gpio(unsigned irq)
-{
-       if (irq < IRQ_GPIOA(0))
-               return -EINVAL;
-       return irq - IRQ_GPIOA(0);
-}
-
-EXPORT_SYMBOL(imx_irq_to_gpio);
-
-static struct resource imx_mmc_resources[] = {
-       [0] = {
-               .start  = 0x00214000,
-               .end    = 0x002140FF,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = (SDHC_INT),
-               .end    = (SDHC_INT),
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static u64 imxmmmc_dmamask = 0xffffffffUL;
-
-static struct platform_device imx_mmc_device = {
-       .name           = "imx-mmc",
-       .id             = 0,
-       .dev            = {
-               .dma_mask = &imxmmmc_dmamask,
-               .coherent_dma_mask = 0xffffffff,
-       },
-       .num_resources  = ARRAY_SIZE(imx_mmc_resources),
-       .resource       = imx_mmc_resources,
-};
-
-void __init imx_set_mmc_info(struct imxmmc_platform_data *info)
-{
-       imx_mmc_device.dev.platform_data = info;
-}
-
-static struct platform_device *devices[] __initdata = {
-       &imx_mmc_device,
-};
-
-static struct map_desc imx_io_desc[] __initdata = {
-       {
-               .virtual        = IMX_IO_BASE,
-               .pfn            = __phys_to_pfn(IMX_IO_PHYS),
-               .length         = IMX_IO_SIZE,
-               .type           = MT_DEVICE
-       }
-};
-
-void __init
-imx_map_io(void)
-{
-       iotable_init(imx_io_desc, ARRAY_SIZE(imx_io_desc));
-}
-
-static int __init imx_init(void)
-{
-       return platform_add_devices(devices, ARRAY_SIZE(devices));
-}
-
-subsys_initcall(imx_init);
diff --git a/arch/arm/mach-imx/generic.h b/arch/arm/mach-imx/generic.h
deleted file mode 100644 (file)
index e91003e..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- *  linux/arch/arm/mach-imx/generic.h
- *
- * Author:     Sascha Hauer <sascha@saschahauer.de>
- * Copyright:  Synertronixx GmbH
- *
- * This 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.
- */
-
-extern void __init imx_map_io(void);
-extern void __init imx_init_irq(void);
-
-struct sys_timer;
-extern struct sys_timer imx_timer;
diff --git a/arch/arm/mach-imx/include/mach/debug-macro.S b/arch/arm/mach-imx/include/mach/debug-macro.S
deleted file mode 100644 (file)
index 87802bb..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/* arch/arm/mach-imx/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, #0x00000000        @ physical
-               movne   \rx, #0xe0000000        @ virtual
-               orreq   \rx, \rx, #0x00200000   @ physical
-               orr     \rx, \rx, #0x00006000   @ UART1 offset
-               .endm
-
-               .macro  senduart,rd,rx
-               str     \rd, [\rx, #0x40]       @ TXDATA
-               .endm
-
-               .macro  waituart,rd,rx
-               .endm
-
-               .macro  busyuart,rd,rx
-1002:          ldr     \rd, [\rx, #0x98]       @ SR2
-               tst     \rd, #1 << 3            @ TXDC
-               beq     1002b                   @ wait until transmit done
-               .endm
diff --git a/arch/arm/mach-imx/include/mach/dma.h b/arch/arm/mach-imx/include/mach/dma.h
deleted file mode 100644 (file)
index 621ff2c..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- *  linux/include/asm-arm/imxads/dma.h
- *
- *  Copyright (C) 1997,1998 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
- */
-
-#ifndef __ASM_ARCH_DMA_H
-#define __ASM_ARCH_DMA_H
-
-typedef enum {
-       DMA_PRIO_HIGH = 0,
-       DMA_PRIO_MEDIUM = 1,
-       DMA_PRIO_LOW = 2
-} imx_dma_prio;
-
-#define DMA_REQ_UART3_T        2
-#define DMA_REQ_UART3_R        3
-#define DMA_REQ_SSI2_T         4
-#define DMA_REQ_SSI2_R         5
-#define DMA_REQ_CSI_STAT       6
-#define DMA_REQ_CSI_R          7
-#define DMA_REQ_MSHC           8
-#define DMA_REQ_DSPA_DCT_DOUT  9
-#define DMA_REQ_DSPA_DCT_DIN  10
-#define DMA_REQ_DSPA_MAC      11
-#define DMA_REQ_EXT           12
-#define DMA_REQ_SDHC          13
-#define DMA_REQ_SPI1_R        14
-#define DMA_REQ_SPI1_T        15
-#define DMA_REQ_SSI_T         16
-#define DMA_REQ_SSI_R         17
-#define DMA_REQ_ASP_DAC       18
-#define DMA_REQ_ASP_ADC       19
-#define DMA_REQ_USP_EP(x)    (20+(x))
-#define DMA_REQ_SPI2_R        26
-#define DMA_REQ_SPI2_T        27
-#define DMA_REQ_UART2_T       28
-#define DMA_REQ_UART2_R       29
-#define DMA_REQ_UART1_T       30
-#define DMA_REQ_UART1_R       31
-
-#endif                         /* _ASM_ARCH_DMA_H */
diff --git a/arch/arm/mach-imx/include/mach/entry-macro.S b/arch/arm/mach-imx/include/mach/entry-macro.S
deleted file mode 100644 (file)
index e4db679..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * arch/arm/mach-imx/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for iMX-based platforms
- *
- * This file is licensed under  the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-#include <mach/hardware.h>
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  get_irqnr_preamble, base, tmp
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
-#define AITC_NIVECSR   0x40
-               .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
-               ldr     \base, =IO_ADDRESS(IMX_AITC_BASE)
-               @ Load offset & priority of the highest priority
-               @ interrupt pending.
-               ldr     \irqstat, [\base, #AITC_NIVECSR]
-               @ Shift off the priority leaving the offset or
-               @ "interrupt number", use arithmetic shift to
-               @ transform illegal source (0xffff) as -1
-               mov     \irqnr, \irqstat, asr #16
-               adds    \tmp, \irqnr, #1
-               .endm
diff --git a/arch/arm/mach-imx/include/mach/gpio.h b/arch/arm/mach-imx/include/mach/gpio.h
deleted file mode 100644 (file)
index 6c2942f..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-#ifndef _IMX_GPIO_H
-
-#include <linux/kernel.h>
-#include <mach/hardware.h>
-#include <mach/imx-regs.h>
-
-#define IMX_GPIO_ALLOC_MODE_NORMAL     0
-#define IMX_GPIO_ALLOC_MODE_NO_ALLOC   1
-#define IMX_GPIO_ALLOC_MODE_TRY_ALLOC  2
-#define IMX_GPIO_ALLOC_MODE_ALLOC_ONLY 4
-#define IMX_GPIO_ALLOC_MODE_RELEASE    8
-
-extern int imx_gpio_request(unsigned gpio, const char *label);
-
-extern void imx_gpio_free(unsigned gpio);
-
-extern int imx_gpio_setup_multiple_pins(const int *pin_list, unsigned count,
-                                       int alloc_mode, const char *label);
-
-extern int imx_gpio_direction_input(unsigned gpio);
-
-extern int imx_gpio_direction_output(unsigned gpio, int value);
-
-extern void __imx_gpio_set_value(unsigned gpio, int value);
-
-static inline int imx_gpio_get_value(unsigned gpio)
-{
-       return SSR(gpio >> GPIO_PORT_SHIFT) & (1 << (gpio & GPIO_PIN_MASK));
-}
-
-static inline void imx_gpio_set_value_inline(unsigned gpio, int value)
-{
-       unsigned long flags;
-
-       raw_local_irq_save(flags);
-       if(value)
-               DR(gpio >> GPIO_PORT_SHIFT) |= (1 << (gpio & GPIO_PIN_MASK));
-       else
-               DR(gpio >> GPIO_PORT_SHIFT) &= ~(1 << (gpio & GPIO_PIN_MASK));
-       raw_local_irq_restore(flags);
-}
-
-static inline void imx_gpio_set_value(unsigned gpio, int value)
-{
-       if(__builtin_constant_p(gpio))
-               imx_gpio_set_value_inline(gpio, value);
-       else
-               __imx_gpio_set_value(gpio, value);
-}
-
-extern int imx_gpio_to_irq(unsigned gpio);
-
-extern int imx_irq_to_gpio(unsigned irq);
-
-/*-------------------------------------------------------------------------*/
-
-/* Wrappers for "new style" GPIO calls. These calls i.MX specific versions
- * to allow future extension of GPIO logic.
- */
-
-static inline int gpio_request(unsigned gpio, const char *label)
-{
-       return imx_gpio_request(gpio, label);
-}
-
-static inline void gpio_free(unsigned gpio)
-{
-       might_sleep();
-
-       imx_gpio_free(gpio);
-}
-
-static inline  int gpio_direction_input(unsigned gpio)
-{
-       return imx_gpio_direction_input(gpio);
-}
-
-static inline int gpio_direction_output(unsigned gpio, int value)
-{
-       return imx_gpio_direction_output(gpio, value);
-}
-
-static inline int gpio_get_value(unsigned gpio)
-{
-       return imx_gpio_get_value(gpio);
-}
-
-static inline void gpio_set_value(unsigned gpio, int value)
-{
-       imx_gpio_set_value(gpio, value);
-}
-
-#include <asm-generic/gpio.h>          /* cansleep wrappers */
-
-static inline int gpio_to_irq(unsigned gpio)
-{
-       return imx_gpio_to_irq(gpio);
-}
-
-static inline int irq_to_gpio(unsigned irq)
-{
-       return imx_irq_to_gpio(irq);
-}
-
-
-#endif
diff --git a/arch/arm/mach-imx/include/mach/hardware.h b/arch/arm/mach-imx/include/mach/hardware.h
deleted file mode 100644 (file)
index c73e9e7..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- *  arch/arm/mach-imx/include/mach/hardware.h
- *
- *  Copyright (C) 1999 ARM Limited.
- *
- * 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_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
-
-#include <asm/sizes.h>
-#include "imx-regs.h"
-
-#ifndef __ASSEMBLY__
-# define __REG(x)      (*((volatile u32 *)IO_ADDRESS(x)))
-
-# define __REG2(x,y)        (*(volatile u32 *)((u32)&__REG(x) + (y)))
-#endif
-
-/*
- * Memory map
- */
-
-#define IMX_IO_PHYS            0x00200000
-#define IMX_IO_SIZE            0x00100000
-#define IMX_IO_BASE            0xe0000000
-
-#define IMX_CS0_PHYS           0x10000000
-#define IMX_CS0_SIZE           0x02000000
-#define IMX_CS0_VIRT           0xe8000000
-
-#define IMX_CS1_PHYS           0x12000000
-#define IMX_CS1_SIZE           0x01000000
-#define IMX_CS1_VIRT           0xea000000
-
-#define IMX_CS2_PHYS           0x13000000
-#define IMX_CS2_SIZE           0x01000000
-#define IMX_CS2_VIRT           0xeb000000
-
-#define IMX_CS3_PHYS           0x14000000
-#define IMX_CS3_SIZE           0x01000000
-#define IMX_CS3_VIRT           0xec000000
-
-#define IMX_CS4_PHYS           0x15000000
-#define IMX_CS4_SIZE           0x01000000
-#define IMX_CS4_VIRT           0xed000000
-
-#define IMX_CS5_PHYS           0x16000000
-#define IMX_CS5_SIZE           0x01000000
-#define IMX_CS5_VIRT           0xee000000
-
-#define IMX_FB_VIRT            0xF1000000
-#define IMX_FB_SIZE            (256*1024)
-
-/* macro to get at IO space when running virtually */
-#define IO_ADDRESS(x) ((x) | IMX_IO_BASE)
-
-#ifndef __ASSEMBLY__
-/*
- * Handy routine to set GPIO functions
- */
-extern void imx_gpio_mode( int gpio_mode );
-
-#endif
-
-#define MAXIRQNUM                       62
-#define MAXFIQNUM                       62
-#define MAXSWINUM                       62
-
-/*
- * Use SDRAM for memory
- */
-#define MEM_SIZE               0x01000000
-
-#ifdef CONFIG_ARCH_MX1ADS
-#include "mx1ads.h"
-#endif
-
-#endif
diff --git a/arch/arm/mach-imx/include/mach/imx-dma.h b/arch/arm/mach-imx/include/mach/imx-dma.h
deleted file mode 100644 (file)
index bbe54df..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- *  linux/include/asm-arm/imxads/dma.h
- *
- *  Copyright (C) 1997,1998 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
- */
-
-#include <mach/dma.h>
-
-#ifndef __ASM_ARCH_IMX_DMA_H
-#define __ASM_ARCH_IMX_DMA_H
-
-#define IMX_DMA_CHANNELS  11
-
-/*
- * struct imx_dma_channel - i.MX specific DMA extension
- * @name: name specified by DMA client
- * @irq_handler: client callback for end of transfer
- * @err_handler: client callback for error condition
- * @data: clients context data for callbacks
- * @dma_mode: direction of the transfer %DMA_MODE_READ or %DMA_MODE_WRITE
- * @sg: pointer to the actual read/written chunk for scatter-gather emulation
- * @sgbc: counter of processed bytes in the actual read/written chunk
- * @resbytes: total residual number of bytes to transfer
- *            (it can be lower or same as sum of SG mapped chunk sizes)
- * @sgcount: number of chunks to be read/written
- *
- * Structure is used for IMX DMA processing. It would be probably good
- * @struct dma_struct in the future for external interfacing and use
- * @struct imx_dma_channel only as extension to it.
- */
-
-struct imx_dma_channel {
-       const char *name;
-       void (*irq_handler) (int, void *);
-       void (*err_handler) (int, void *, int errcode);
-       void *data;
-       unsigned int  dma_mode;
-       struct scatterlist *sg;
-       unsigned int sgbc;
-       unsigned int sgcount;
-       unsigned int resbytes;
-       int dma_num;
-};
-
-extern struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS];
-
-#define IMX_DMA_ERR_BURST     1
-#define IMX_DMA_ERR_REQUEST   2
-#define IMX_DMA_ERR_TRANSFER  4
-#define IMX_DMA_ERR_BUFFER    8
-
-/* The type to distinguish channel numbers parameter from ordinal int type */
-typedef int imx_dmach_t;
-
-#define DMA_MODE_READ          0
-#define DMA_MODE_WRITE         1
-#define DMA_MODE_MASK          1
-
-int
-imx_dma_setup_single(imx_dmach_t dma_ch, dma_addr_t dma_address,
-               unsigned int dma_length, unsigned int dev_addr, unsigned int dmamode);
-
-int
-imx_dma_setup_sg(imx_dmach_t dma_ch,
-                struct scatterlist *sg, unsigned int sgcount, unsigned int dma_length,
-                unsigned int dev_addr, unsigned int dmamode);
-
-int
-imx_dma_setup_handlers(imx_dmach_t dma_ch,
-               void (*irq_handler) (int, void *),
-               void (*err_handler) (int, void *, int), void *data);
-
-void imx_dma_enable(imx_dmach_t dma_ch);
-
-void imx_dma_disable(imx_dmach_t dma_ch);
-
-int imx_dma_request(imx_dmach_t dma_ch, const char *name);
-
-void imx_dma_free(imx_dmach_t dma_ch);
-
-imx_dmach_t imx_dma_request_by_prio(const char *name, imx_dma_prio prio);
-
-
-#endif /* _ASM_ARCH_IMX_DMA_H */
diff --git a/arch/arm/mach-imx/include/mach/imx-regs.h b/arch/arm/mach-imx/include/mach/imx-regs.h
deleted file mode 100644 (file)
index 490297f..0000000
+++ /dev/null
@@ -1,376 +0,0 @@
-#ifndef _IMX_REGS_H
-#define _IMX_REGS_H
-/* ------------------------------------------------------------------------
- *  Motorola IMX system registers
- * ------------------------------------------------------------------------
- *
- */
-
-/*
- *  Register BASEs, based on OFFSETs
- *
- */
-#define IMX_AIPI1_BASE             (0x00000 + IMX_IO_BASE)
-#define IMX_WDT_BASE               (0x01000 + IMX_IO_BASE)
-#define IMX_TIM1_BASE              (0x02000 + IMX_IO_BASE)
-#define IMX_TIM2_BASE              (0x03000 + IMX_IO_BASE)
-#define IMX_RTC_BASE               (0x04000 + IMX_IO_BASE)
-#define IMX_LCDC_BASE              (0x05000 + IMX_IO_BASE)
-#define IMX_UART1_BASE             (0x06000 + IMX_IO_BASE)
-#define IMX_UART2_BASE             (0x07000 + IMX_IO_BASE)
-#define IMX_PWM_BASE               (0x08000 + IMX_IO_BASE)
-#define IMX_DMAC_BASE              (0x09000 + IMX_IO_BASE)
-#define IMX_AIPI2_BASE             (0x10000 + IMX_IO_BASE)
-#define IMX_SIM_BASE               (0x11000 + IMX_IO_BASE)
-#define IMX_USBD_BASE              (0x12000 + IMX_IO_BASE)
-#define IMX_SPI1_BASE              (0x13000 + IMX_IO_BASE)
-#define IMX_MMC_BASE               (0x14000 + IMX_IO_BASE)
-#define IMX_ASP_BASE               (0x15000 + IMX_IO_BASE)
-#define IMX_BTA_BASE               (0x16000 + IMX_IO_BASE)
-#define IMX_I2C_BASE               (0x17000 + IMX_IO_BASE)
-#define IMX_SSI_BASE               (0x18000 + IMX_IO_BASE)
-#define IMX_SPI2_BASE              (0x19000 + IMX_IO_BASE)
-#define IMX_MSHC_BASE              (0x1A000 + IMX_IO_BASE)
-#define IMX_PLL_BASE               (0x1B000 + IMX_IO_BASE)
-#define IMX_GPIO_BASE              (0x1C000 + IMX_IO_BASE)
-#define IMX_EIM_BASE               (0x20000 + IMX_IO_BASE)
-#define IMX_SDRAMC_BASE            (0x21000 + IMX_IO_BASE)
-#define IMX_MMA_BASE               (0x22000 + IMX_IO_BASE)
-#define IMX_AITC_BASE              (0x23000 + IMX_IO_BASE)
-#define IMX_CSI_BASE               (0x24000 + IMX_IO_BASE)
-
-/* PLL registers */
-#define CSCR   __REG(IMX_PLL_BASE)        /* Clock Source Control Register */
-#define CSCR_SPLL_RESTART      (1<<22)
-#define CSCR_MPLL_RESTART      (1<<21)
-#define CSCR_SYSTEM_SEL                (1<<16)
-#define CSCR_BCLK_DIV          (0xf<<10)
-#define CSCR_MPU_PRESC         (1<<15)
-#define CSCR_SPEN              (1<<1)
-#define CSCR_MPEN              (1<<0)
-
-#define MPCTL0 __REG(IMX_PLL_BASE + 0x4)  /* MCU PLL Control Register 0 */
-#define MPCTL1 __REG(IMX_PLL_BASE + 0x8)  /* MCU PLL and System Clock Register 1 */
-#define SPCTL0 __REG(IMX_PLL_BASE + 0xc)  /* System PLL Control Register 0 */
-#define SPCTL1 __REG(IMX_PLL_BASE + 0x10) /* System PLL Control Register 1 */
-#define PCDR   __REG(IMX_PLL_BASE + 0x20) /* Peripheral Clock Divider Register */
-
-/*
- *  GPIO Module and I/O Multiplexer
- *  x = 0..3 for reg_A, reg_B, reg_C, reg_D
- */
-#define DDIR(x)    __REG2(IMX_GPIO_BASE + 0x00, ((x) & 3) << 8)
-#define OCR1(x)    __REG2(IMX_GPIO_BASE + 0x04, ((x) & 3) << 8)
-#define OCR2(x)    __REG2(IMX_GPIO_BASE + 0x08, ((x) & 3) << 8)
-#define ICONFA1(x) __REG2(IMX_GPIO_BASE + 0x0c, ((x) & 3) << 8)
-#define ICONFA2(x) __REG2(IMX_GPIO_BASE + 0x10, ((x) & 3) << 8)
-#define ICONFB1(x) __REG2(IMX_GPIO_BASE + 0x14, ((x) & 3) << 8)
-#define ICONFB2(x) __REG2(IMX_GPIO_BASE + 0x18, ((x) & 3) << 8)
-#define DR(x)      __REG2(IMX_GPIO_BASE + 0x1c, ((x) & 3) << 8)
-#define GIUS(x)    __REG2(IMX_GPIO_BASE + 0x20, ((x) & 3) << 8)
-#define SSR(x)     __REG2(IMX_GPIO_BASE + 0x24, ((x) & 3) << 8)
-#define ICR1(x)    __REG2(IMX_GPIO_BASE + 0x28, ((x) & 3) << 8)
-#define ICR2(x)    __REG2(IMX_GPIO_BASE + 0x2c, ((x) & 3) << 8)
-#define IMR(x)     __REG2(IMX_GPIO_BASE + 0x30, ((x) & 3) << 8)
-#define ISR(x)     __REG2(IMX_GPIO_BASE + 0x34, ((x) & 3) << 8)
-#define GPR(x)     __REG2(IMX_GPIO_BASE + 0x38, ((x) & 3) << 8)
-#define SWR(x)     __REG2(IMX_GPIO_BASE + 0x3c, ((x) & 3) << 8)
-#define PUEN(x)    __REG2(IMX_GPIO_BASE + 0x40, ((x) & 3) << 8)
-
-#define GPIO_PORT_MAX  3
-
-#define GPIO_PIN_MASK 0x1f
-#define GPIO_PORT_MASK (0x3 << 5)
-
-#define GPIO_PORT_SHIFT 5
-#define GPIO_PORTA (0<<5)
-#define GPIO_PORTB (1<<5)
-#define GPIO_PORTC (2<<5)
-#define GPIO_PORTD (3<<5)
-
-#define GPIO_OUT   (1<<7)
-#define GPIO_IN    (0<<7)
-#define GPIO_PUEN  (1<<8)
-
-#define GPIO_PF    (0<<9)
-#define GPIO_AF    (1<<9)
-
-#define GPIO_OCR_SHIFT 10
-#define GPIO_OCR_MASK (3<<10)
-#define GPIO_AIN   (0<<10)
-#define GPIO_BIN   (1<<10)
-#define GPIO_CIN   (2<<10)
-#define GPIO_DR    (3<<10)
-
-#define GPIO_AOUT_SHIFT 12
-#define GPIO_AOUT_MASK (3<<12)
-#define GPIO_AOUT     (0<<12)
-#define GPIO_AOUT_ISR (1<<12)
-#define GPIO_AOUT_0   (2<<12)
-#define GPIO_AOUT_1   (3<<12)
-
-#define GPIO_BOUT_SHIFT 14
-#define GPIO_BOUT_MASK (3<<14)
-#define GPIO_BOUT      (0<<14)
-#define GPIO_BOUT_ISR  (1<<14)
-#define GPIO_BOUT_0    (2<<14)
-#define GPIO_BOUT_1    (3<<14)
-
-#define GPIO_GIUS      (1<<16)
-
-/* assignements for GPIO alternate/primary functions */
-
-/* FIXME: This list is not completed. The correct directions are
- * missing on some (many) pins
- */
-#define PA0_AIN_SPI2_CLK     ( GPIO_GIUS | GPIO_PORTA | GPIO_OUT | 0 )
-#define PA0_AF_ETMTRACESYNC  ( GPIO_PORTA | GPIO_AF | 0 )
-#define PA1_AOUT_SPI2_RXD    ( GPIO_GIUS | GPIO_PORTA | GPIO_IN | 1 )
-#define PA1_PF_TIN           ( GPIO_PORTA | GPIO_PF | 1 )
-#define PA2_PF_PWM0          ( GPIO_PORTA | GPIO_OUT | GPIO_PF | 2 )
-#define PA3_PF_CSI_MCLK      ( GPIO_PORTA | GPIO_PF | 3 )
-#define PA4_PF_CSI_D0        ( GPIO_PORTA | GPIO_PF | 4 )
-#define PA5_PF_CSI_D1        ( GPIO_PORTA | GPIO_PF | 5 )
-#define PA6_PF_CSI_D2        ( GPIO_PORTA | GPIO_PF | 6 )
-#define PA7_PF_CSI_D3        ( GPIO_PORTA | GPIO_PF | 7 )
-#define PA8_PF_CSI_D4        ( GPIO_PORTA | GPIO_PF | 8 )
-#define PA9_PF_CSI_D5        ( GPIO_PORTA | GPIO_PF | 9 )
-#define PA10_PF_CSI_D6       ( GPIO_PORTA | GPIO_PF | 10 )
-#define PA11_PF_CSI_D7       ( GPIO_PORTA | GPIO_PF | 11 )
-#define PA12_PF_CSI_VSYNC    ( GPIO_PORTA | GPIO_PF | 12 )
-#define PA13_PF_CSI_HSYNC    ( GPIO_PORTA | GPIO_PF | 13 )
-#define PA14_PF_CSI_PIXCLK   ( GPIO_PORTA | GPIO_PF | 14 )
-#define PA15_PF_I2C_SDA      ( GPIO_PORTA | GPIO_OUT | GPIO_PF | 15 )
-#define PA16_PF_I2C_SCL      ( GPIO_PORTA | GPIO_OUT | GPIO_PF | 16 )
-#define PA17_AF_ETMTRACEPKT4 ( GPIO_PORTA | GPIO_AF | 17 )
-#define PA17_AIN_SPI2_SS     ( GPIO_GIUS | GPIO_PORTA | GPIO_OUT | 17 )
-#define PA18_AF_ETMTRACEPKT5 ( GPIO_PORTA | GPIO_AF | 18 )
-#define PA19_AF_ETMTRACEPKT6 ( GPIO_PORTA | GPIO_AF | 19 )
-#define PA20_AF_ETMTRACEPKT7 ( GPIO_PORTA | GPIO_AF | 20 )
-#define PA21_PF_A0           ( GPIO_PORTA | GPIO_PF | 21 )
-#define PA22_PF_CS4          ( GPIO_PORTA | GPIO_PF | 22 )
-#define PA23_PF_CS5          ( GPIO_PORTA | GPIO_PF | 23 )
-#define PA24_PF_A16          ( GPIO_PORTA | GPIO_PF | 24 )
-#define PA24_AF_ETMTRACEPKT0 ( GPIO_PORTA | GPIO_AF | 24 )
-#define PA25_PF_A17          ( GPIO_PORTA | GPIO_PF | 25 )
-#define PA25_AF_ETMTRACEPKT1 ( GPIO_PORTA | GPIO_AF | 25 )
-#define PA26_PF_A18          ( GPIO_PORTA | GPIO_PF | 26 )
-#define PA26_AF_ETMTRACEPKT2 ( GPIO_PORTA | GPIO_AF | 26 )
-#define PA27_PF_A19          ( GPIO_PORTA | GPIO_PF | 27 )
-#define PA27_AF_ETMTRACEPKT3 ( GPIO_PORTA | GPIO_AF | 27 )
-#define PA28_PF_A20          ( GPIO_PORTA | GPIO_PF | 28 )
-#define PA28_AF_ETMPIPESTAT0 ( GPIO_PORTA | GPIO_AF | 28 )
-#define PA29_PF_A21          ( GPIO_PORTA | GPIO_PF | 29 )
-#define PA29_AF_ETMPIPESTAT1 ( GPIO_PORTA | GPIO_AF | 29 )
-#define PA30_PF_A22          ( GPIO_PORTA | GPIO_PF | 30 )
-#define PA30_AF_ETMPIPESTAT2 ( GPIO_PORTA | GPIO_AF | 30 )
-#define PA31_PF_A23          ( GPIO_PORTA | GPIO_PF | 31 )
-#define PA31_AF_ETMTRACECLK  ( GPIO_PORTA | GPIO_AF | 31 )
-#define PB8_PF_SD_DAT0       ( GPIO_PORTB | GPIO_PF | GPIO_PUEN | 8 )
-#define PB8_AF_MS_PIO        ( GPIO_PORTB | GPIO_AF | 8 )
-#define PB9_PF_SD_DAT1       ( GPIO_PORTB | GPIO_PF | GPIO_PUEN  | 9 )
-#define PB9_AF_MS_PI1        ( GPIO_PORTB | GPIO_AF | 9 )
-#define PB10_PF_SD_DAT2      ( GPIO_PORTB | GPIO_PF | GPIO_PUEN  | 10 )
-#define PB10_AF_MS_SCLKI     ( GPIO_PORTB | GPIO_AF | 10 )
-#define PB11_PF_SD_DAT3      ( GPIO_PORTB | GPIO_PF | 11 )
-#define PB11_AF_MS_SDIO      ( GPIO_PORTB | GPIO_AF | 11 )
-#define PB12_PF_SD_CLK       ( GPIO_PORTB | GPIO_PF | 12 )
-#define PB12_AF_MS_SCLK0     ( GPIO_PORTB | GPIO_AF | 12 )
-#define PB13_PF_SD_CMD       ( GPIO_PORTB | GPIO_PF | GPIO_PUEN | 13 )
-#define PB13_AF_MS_BS        ( GPIO_PORTB | GPIO_AF | 13 )
-#define PB14_AF_SSI_RXFS     ( GPIO_PORTB | GPIO_AF | 14 )
-#define PB15_AF_SSI_RXCLK    ( GPIO_PORTB | GPIO_AF | 15 )
-#define PB16_AF_SSI_RXDAT    ( GPIO_PORTB | GPIO_IN | GPIO_AF | 16 )
-#define PB17_AF_SSI_TXDAT    ( GPIO_PORTB | GPIO_OUT | GPIO_AF | 17 )
-#define PB18_AF_SSI_TXFS     ( GPIO_PORTB | GPIO_AF | 18 )
-#define PB19_AF_SSI_TXCLK    ( GPIO_PORTB | GPIO_AF | 19 )
-#define PB20_PF_USBD_AFE     ( GPIO_PORTB | GPIO_PF | 20 )
-#define PB21_PF_USBD_OE      ( GPIO_PORTB | GPIO_PF | 21 )
-#define PB22_PFUSBD_RCV      ( GPIO_PORTB | GPIO_PF | 22 )
-#define PB23_PF_USBD_SUSPND  ( GPIO_PORTB | GPIO_PF | 23 )
-#define PB24_PF_USBD_VP      ( GPIO_PORTB | GPIO_PF | 24 )
-#define PB25_PF_USBD_VM      ( GPIO_PORTB | GPIO_PF | 25 )
-#define PB26_PF_USBD_VPO     ( GPIO_PORTB | GPIO_PF | 26 )
-#define PB27_PF_USBD_VMO     ( GPIO_PORTB | GPIO_PF | 27 )
-#define PB28_PF_UART2_CTS    ( GPIO_PORTB | GPIO_OUT | GPIO_PF | 28 )
-#define PB29_PF_UART2_RTS    ( GPIO_PORTB | GPIO_IN | GPIO_PF | 29 )
-#define PB30_PF_UART2_TXD    ( GPIO_PORTB | GPIO_OUT | GPIO_PF | 30 )
-#define PB31_PF_UART2_RXD    ( GPIO_PORTB | GPIO_IN | GPIO_PF | 31 )
-#define PC3_PF_SSI_RXFS      ( GPIO_PORTC | GPIO_PF | 3 )
-#define PC4_PF_SSI_RXCLK     ( GPIO_PORTC | GPIO_PF | 4 )
-#define PC5_PF_SSI_RXDAT     ( GPIO_PORTC | GPIO_IN | GPIO_PF | 5 )
-#define PC6_PF_SSI_TXDAT     ( GPIO_PORTC | GPIO_OUT | GPIO_PF | 6 )
-#define PC7_PF_SSI_TXFS      ( GPIO_PORTC | GPIO_PF | 7 )
-#define PC8_PF_SSI_TXCLK     ( GPIO_PORTC | GPIO_PF | 8 )
-#define PC9_PF_UART1_CTS     ( GPIO_PORTC | GPIO_OUT | GPIO_PF | 9 )
-#define PC10_PF_UART1_RTS    ( GPIO_PORTC | GPIO_IN | GPIO_PF | 10 )
-#define PC11_PF_UART1_TXD    ( GPIO_PORTC | GPIO_OUT | GPIO_PF | 11 )
-#define PC12_PF_UART1_RXD    ( GPIO_PORTC | GPIO_IN | GPIO_PF | 12 )
-#define PC13_PF_SPI1_SPI_RDY ( GPIO_PORTC | GPIO_PF | 13 )
-#define PC14_PF_SPI1_SCLK    ( GPIO_PORTC | GPIO_PF | 14 )
-#define PC15_PF_SPI1_SS      ( GPIO_PORTC | GPIO_PF | 15 )
-#define PC16_PF_SPI1_MISO    ( GPIO_PORTC | GPIO_PF | 16 )
-#define PC17_PF_SPI1_MOSI    ( GPIO_PORTC | GPIO_PF | 17 )
-#define PC24_BIN_UART3_RI    ( GPIO_GIUS | GPIO_PORTC | GPIO_OUT | GPIO_BIN | 24 )
-#define PC25_BIN_UART3_DSR   ( GPIO_GIUS | GPIO_PORTC | GPIO_OUT | GPIO_BIN | 25 )
-#define PC26_AOUT_UART3_DTR  ( GPIO_GIUS | GPIO_PORTC | GPIO_IN | 26 )
-#define PC27_BIN_UART3_DCD   ( GPIO_GIUS | GPIO_PORTC | GPIO_OUT | GPIO_BIN | 27 )
-#define PC28_BIN_UART3_CTS   ( GPIO_GIUS | GPIO_PORTC | GPIO_OUT | GPIO_BIN | 28 )
-#define PC29_AOUT_UART3_RTS  ( GPIO_GIUS | GPIO_PORTC | GPIO_IN | 29 )
-#define PC30_BIN_UART3_TX    ( GPIO_GIUS | GPIO_PORTC | GPIO_BIN | 30 )
-#define PC31_AOUT_UART3_RX   ( GPIO_GIUS | GPIO_PORTC | GPIO_IN | 31)
-#define PD6_PF_LSCLK         ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 6 )
-#define PD7_PF_REV           ( GPIO_PORTD | GPIO_PF | 7 )
-#define PD7_AF_UART2_DTR     ( GPIO_GIUS | GPIO_PORTD | GPIO_IN | GPIO_AF | 7 )
-#define PD7_AIN_SPI2_SCLK    ( GPIO_GIUS | GPIO_PORTD | GPIO_AIN | 7 )
-#define PD8_PF_CLS           ( GPIO_PORTD | GPIO_PF | 8 )
-#define PD8_AF_UART2_DCD     ( GPIO_PORTD | GPIO_OUT | GPIO_AF | 8 )
-#define PD8_AIN_SPI2_SS      ( GPIO_GIUS | GPIO_PORTD | GPIO_AIN | 8 )
-#define PD9_PF_PS            ( GPIO_PORTD | GPIO_PF | 9 )
-#define PD9_AF_UART2_RI      ( GPIO_PORTD | GPIO_OUT | GPIO_AF | 9 )
-#define PD9_AOUT_SPI2_RXD    ( GPIO_GIUS | GPIO_PORTD | GPIO_IN | 9 )
-#define PD10_PF_SPL_SPR      ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 10 )
-#define PD10_AF_UART2_DSR    ( GPIO_PORTD | GPIO_OUT | GPIO_AF | 10 )
-#define PD10_AIN_SPI2_TXD    ( GPIO_GIUS | GPIO_PORTD | GPIO_OUT | 10 )
-#define PD11_PF_CONTRAST     ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 11 )
-#define PD12_PF_ACD_OE       ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 12 )
-#define PD13_PF_LP_HSYNC     ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 13 )
-#define PD14_PF_FLM_VSYNC    ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 14 )
-#define PD15_PF_LD0          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 15 )
-#define PD16_PF_LD1          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 16 )
-#define PD17_PF_LD2          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 17 )
-#define PD18_PF_LD3          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 18 )
-#define PD19_PF_LD4          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 19 )
-#define PD20_PF_LD5          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 20 )
-#define PD21_PF_LD6          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 21 )
-#define PD22_PF_LD7          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 22 )
-#define PD23_PF_LD8          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 23 )
-#define PD24_PF_LD9          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 24 )
-#define PD25_PF_LD10         ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 25 )
-#define PD26_PF_LD11         ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 26 )
-#define PD27_PF_LD12         ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 27 )
-#define PD28_PF_LD13         ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 28 )
-#define PD29_PF_LD14         ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 29 )
-#define PD30_PF_LD15         ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 30 )
-#define PD31_PF_TMR2OUT      ( GPIO_PORTD | GPIO_PF | 31 )
-#define PD31_BIN_SPI2_TXD    ( GPIO_GIUS | GPIO_PORTD | GPIO_BIN | 31 )
-
-/*
- * PWM controller
- */
-#define PWMC   __REG(IMX_PWM_BASE + 0x00)      /* PWM Control Register         */
-#define PWMS   __REG(IMX_PWM_BASE + 0x04)      /* PWM Sample Register          */
-#define PWMP   __REG(IMX_PWM_BASE + 0x08)      /* PWM Period Register          */
-#define PWMCNT __REG(IMX_PWM_BASE + 0x0C)      /* PWM Counter Register         */
-
-#define PWMC_HCTR              (0x01<<18)              /* Halfword FIFO Data Swapping  */
-#define PWMC_BCTR              (0x01<<17)              /* Byte FIFO Data Swapping      */
-#define PWMC_SWR               (0x01<<16)              /* Software Reset               */
-#define PWMC_CLKSRC            (0x01<<15)              /* Clock Source                 */
-#define PWMC_PRESCALER(x)      (((x-1) & 0x7F) << 8)   /* PRESCALER                    */
-#define PWMC_IRQ               (0x01<< 7)              /* Interrupt Request            */
-#define PWMC_IRQEN             (0x01<< 6)              /* Interrupt Request Enable     */
-#define PWMC_FIFOAV            (0x01<< 5)              /* FIFO Available               */
-#define PWMC_EN                        (0x01<< 4)              /* Enables/Disables the PWM     */
-#define PWMC_REPEAT(x)         (((x) & 0x03) << 2)     /* Sample Repeats               */
-#define PWMC_CLKSEL(x)         (((x) & 0x03) << 0)     /* Clock Selection              */
-
-#define PWMS_SAMPLE(x)         ((x) & 0xFFFF)          /* Contains a two-sample word   */
-#define PWMP_PERIOD(x)         ((x) & 0xFFFF)          /* Represents the PWM's period  */
-#define PWMC_COUNTER(x)                ((x) & 0xFFFF)          /* Represents the current count value   */
-
-/*
- *  DMA Controller
- */
-#define DCR     __REG(IMX_DMAC_BASE +0x00)     /* DMA Control Register */
-#define DISR    __REG(IMX_DMAC_BASE +0x04)     /* DMA Interrupt status Register */
-#define DIMR    __REG(IMX_DMAC_BASE +0x08)     /* DMA Interrupt mask Register */
-#define DBTOSR  __REG(IMX_DMAC_BASE +0x0c)     /* DMA Burst timeout status Register */
-#define DRTOSR  __REG(IMX_DMAC_BASE +0x10)     /* DMA Request timeout Register */
-#define DSESR   __REG(IMX_DMAC_BASE +0x14)     /* DMA Transfer Error Status Register */
-#define DBOSR   __REG(IMX_DMAC_BASE +0x18)     /* DMA Buffer overflow status Register */
-#define DBTOCR  __REG(IMX_DMAC_BASE +0x1c)     /* DMA Burst timeout control Register */
-#define WSRA    __REG(IMX_DMAC_BASE +0x40)     /* W-Size Register A */
-#define XSRA    __REG(IMX_DMAC_BASE +0x44)     /* X-Size Register A */
-#define YSRA    __REG(IMX_DMAC_BASE +0x48)     /* Y-Size Register A */
-#define WSRB    __REG(IMX_DMAC_BASE +0x4c)     /* W-Size Register B */
-#define XSRB    __REG(IMX_DMAC_BASE +0x50)     /* X-Size Register B */
-#define YSRB    __REG(IMX_DMAC_BASE +0x54)     /* Y-Size Register B */
-#define SAR(x)  __REG2( IMX_DMAC_BASE + 0x80, (x) << 6)        /* Source Address Registers */
-#define DAR(x)  __REG2( IMX_DMAC_BASE + 0x84, (x) << 6)        /* Destination Address Registers */
-#define CNTR(x) __REG2( IMX_DMAC_BASE + 0x88, (x) << 6)        /* Count Registers */
-#define CCR(x)  __REG2( IMX_DMAC_BASE + 0x8c, (x) << 6)        /* Control Registers */
-#define RSSR(x) __REG2( IMX_DMAC_BASE + 0x90, (x) << 6)        /* Request source select Registers */
-#define BLR(x)  __REG2( IMX_DMAC_BASE + 0x94, (x) << 6)        /* Burst length Registers */
-#define RTOR(x) __REG2( IMX_DMAC_BASE + 0x98, (x) << 6)        /* Request timeout Registers */
-#define BUCR(x) __REG2( IMX_DMAC_BASE + 0x98, (x) << 6)        /* Bus Utilization Registers */
-
-#define DCR_DRST           (1<<1)
-#define DCR_DEN            (1<<0)
-#define DBTOCR_EN          (1<<15)
-#define DBTOCR_CNT(x)      ((x) & 0x7fff )
-#define CNTR_CNT(x)        ((x) & 0xffffff )
-#define CCR_DMOD_LINEAR    ( 0x0 << 12 )
-#define CCR_DMOD_2D        ( 0x1 << 12 )
-#define CCR_DMOD_FIFO      ( 0x2 << 12 )
-#define CCR_DMOD_EOBFIFO   ( 0x3 << 12 )
-#define CCR_SMOD_LINEAR    ( 0x0 << 10 )
-#define CCR_SMOD_2D        ( 0x1 << 10 )
-#define CCR_SMOD_FIFO      ( 0x2 << 10 )
-#define CCR_SMOD_EOBFIFO   ( 0x3 << 10 )
-#define CCR_MDIR_DEC       (1<<9)
-#define CCR_MSEL_B         (1<<8)
-#define CCR_DSIZ_32        ( 0x0 << 6 )
-#define CCR_DSIZ_8         ( 0x1 << 6 )
-#define CCR_DSIZ_16        ( 0x2 << 6 )
-#define CCR_SSIZ_32        ( 0x0 << 4 )
-#define CCR_SSIZ_8         ( 0x1 << 4 )
-#define CCR_SSIZ_16        ( 0x2 << 4 )
-#define CCR_REN            (1<<3)
-#define CCR_RPT            (1<<2)
-#define CCR_FRC            (1<<1)
-#define CCR_CEN            (1<<0)
-#define RTOR_EN            (1<<15)
-#define RTOR_CLK           (1<<14)
-#define RTOR_PSC           (1<<13)
-
-/*
- *  Interrupt controller
- */
-
-#define IMX_INTCNTL        __REG(IMX_AITC_BASE+0x00)
-#define INTCNTL_FIAD       (1<<19)
-#define INTCNTL_NIAD       (1<<20)
-
-#define IMX_NIMASK         __REG(IMX_AITC_BASE+0x04)
-#define IMX_INTENNUM       __REG(IMX_AITC_BASE+0x08)
-#define IMX_INTDISNUM      __REG(IMX_AITC_BASE+0x0c)
-#define IMX_INTENABLEH     __REG(IMX_AITC_BASE+0x10)
-#define IMX_INTENABLEL     __REG(IMX_AITC_BASE+0x14)
-
-/*
- *  General purpose timers
- */
-#define IMX_TCTL(x)        __REG( 0x00 + (x))
-#define TCTL_SWR           (1<<15)
-#define TCTL_FRR           (1<<8)
-#define TCTL_CAP_RIS       (1<<6)
-#define TCTL_CAP_FAL       (2<<6)
-#define TCTL_CAP_RIS_FAL   (3<<6)
-#define TCTL_OM            (1<<5)
-#define TCTL_IRQEN         (1<<4)
-#define TCTL_CLK_PCLK1     (1<<1)
-#define TCTL_CLK_PCLK1_16  (2<<1)
-#define TCTL_CLK_TIN       (3<<1)
-#define TCTL_CLK_32        (4<<1)
-#define TCTL_TEN           (1<<0)
-
-#define IMX_TPRER(x)       __REG( 0x04 + (x))
-#define IMX_TCMP(x)        __REG( 0x08 + (x))
-#define IMX_TCR(x)         __REG( 0x0C + (x))
-#define IMX_TCN(x)         __REG( 0x10 + (x))
-#define IMX_TSTAT(x)       __REG( 0x14 + (x))
-#define TSTAT_CAPT         (1<<1)
-#define TSTAT_COMP         (1<<0)
-
-#endif                         // _IMX_REGS_H
diff --git a/arch/arm/mach-imx/include/mach/imx-uart.h b/arch/arm/mach-imx/include/mach/imx-uart.h
deleted file mode 100644 (file)
index d54eb1d..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef ASMARM_ARCH_UART_H
-#define ASMARM_ARCH_UART_H
-
-#define IMXUART_HAVE_RTSCTS (1<<0)
-
-struct imxuart_platform_data {
-       int (*init)(struct platform_device *pdev);
-       void (*exit)(struct platform_device *pdev);
-       unsigned int flags;
-};
-
-#endif
diff --git a/arch/arm/mach-imx/include/mach/io.h b/arch/arm/mach-imx/include/mach/io.h
deleted file mode 100644 (file)
index 9e197ae..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- *  arch/arm/mach-imxads/include/mach/io.h
- *
- *  Copyright (C) 1999 ARM Limited
- *
- * 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_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-#define __io(a)                __typesafe_io(a)
-#define __mem_pci(a)   (a)
-
-#endif
diff --git a/arch/arm/mach-imx/include/mach/irqs.h b/arch/arm/mach-imx/include/mach/irqs.h
deleted file mode 100644 (file)
index 67812c5..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- *  arch/arm/mach-imxads/include/mach/irqs.h
- *
- *  Copyright (C) 1999 ARM Limited
- *  Copyright (C) 2000 Deep Blue Solutions 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.
- *
- * 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 __ARM_IRQS_H__
-#define __ARM_IRQS_H__
-
-/* Use the imx definitions */
-#include <mach/hardware.h>
-
-/*
- *  IMX Interrupt numbers
- *
- */
-#define INT_SOFTINT                 0
-#define CSI_INT                     6
-#define DSPA_MAC_INT                7
-#define DSPA_INT                    8
-#define COMP_INT                    9
-#define MSHC_XINT                   10
-#define GPIO_INT_PORTA              11
-#define GPIO_INT_PORTB              12
-#define GPIO_INT_PORTC              13
-#define LCDC_INT                    14
-#define SIM_INT                     15
-#define SIM_DATA_INT                16
-#define RTC_INT                     17
-#define RTC_SAMINT                  18
-#define UART2_MINT_PFERR            19
-#define UART2_MINT_RTS              20
-#define UART2_MINT_DTR              21
-#define UART2_MINT_UARTC            22
-#define UART2_MINT_TX               23
-#define UART2_MINT_RX               24
-#define UART1_MINT_PFERR            25
-#define UART1_MINT_RTS              26
-#define UART1_MINT_DTR              27
-#define UART1_MINT_UARTC            28
-#define UART1_MINT_TX               29
-#define UART1_MINT_RX               30
-#define VOICE_DAC_INT               31
-#define VOICE_ADC_INT               32
-#define PEN_DATA_INT                33
-#define PWM_INT                     34
-#define SDHC_INT                    35
-#define I2C_INT                     39
-#define CSPI_INT                    41
-#define SSI_TX_INT                  42
-#define SSI_TX_ERR_INT              43
-#define SSI_RX_INT                  44
-#define SSI_RX_ERR_INT              45
-#define TOUCH_INT                   46
-#define USBD_INT0                   47
-#define USBD_INT1                   48
-#define USBD_INT2                   49
-#define USBD_INT3                   50
-#define USBD_INT4                   51
-#define USBD_INT5                   52
-#define USBD_INT6                   53
-#define BTSYS_INT                   55
-#define BTTIM_INT                   56
-#define BTWUI_INT                   57
-#define TIM2_INT                    58
-#define TIM1_INT                    59
-#define DMA_ERR                     60
-#define DMA_INT                     61
-#define GPIO_INT_PORTD              62
-
-#define IMX_IRQS                         (64)
-
-/* note: the IMX has four gpio ports (A-D), but only
- *       the following pins are connected to the outside
- *       world:
- *
- * PORT A: bits 0-31
- * PORT B: bits 8-31
- * PORT C: bits 3-17
- * PORT D: bits 6-31
- *
- * We map these interrupts straight on. As a result we have
- * several holes in the interrupt mapping. We do this for two
- * reasons:
- *   - mapping the interrupts without holes would get
- *     far more complicated
- *   - Motorola could well decide to bring some processor
- *     with more pins connected
- */
-
-#define IRQ_GPIOA(x)  (IMX_IRQS + x)
-#define IRQ_GPIOB(x)  (IRQ_GPIOA(32) + x)
-#define IRQ_GPIOC(x)  (IRQ_GPIOB(32) + x)
-#define IRQ_GPIOD(x)  (IRQ_GPIOC(32) + x)
-
-/* decode irq number to use with IMR(x), ISR(x) and friends */
-#define IRQ_TO_REG(irq) ((irq - IMX_IRQS) >> 5)
-
-/* all normal IRQs can be FIQs */
-#define FIQ_START      0
-/* switch betwean IRQ and FIQ */
-extern int imx_set_irq_fiq(unsigned int irq, unsigned int type);
-
-#define NR_IRQS (IRQ_GPIOD(32) + 1)
-#define IRQ_GPIO(x)
-#endif
diff --git a/arch/arm/mach-imx/include/mach/memory.h b/arch/arm/mach-imx/include/mach/memory.h
deleted file mode 100644 (file)
index a93df7c..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- *  arch/arm/mach-imx/include/mach/memory.h
- *
- *  Copyright (C) 1999 ARM Limited
- *  Copyright (C) 2002 Shane Nay (shane@minirl.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#ifndef __ASM_ARCH_MMU_H
-#define __ASM_ARCH_MMU_H
-
-#define PHYS_OFFSET    UL(0x08000000)
-
-#endif
diff --git a/arch/arm/mach-imx/include/mach/mmc.h b/arch/arm/mach-imx/include/mach/mmc.h
deleted file mode 100644 (file)
index 4712f35..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef ASMARM_ARCH_MMC_H
-#define ASMARM_ARCH_MMC_H
-
-#include <linux/mmc/host.h>
-
-struct device;
-
-struct imxmmc_platform_data {
-       int (*card_present)(struct device *);
-       int (*get_ro)(struct device *);
-};
-
-extern void imx_set_mmc_info(struct imxmmc_platform_data *info);
-
-#endif
diff --git a/arch/arm/mach-imx/include/mach/mx1ads.h b/arch/arm/mach-imx/include/mach/mx1ads.h
deleted file mode 100644 (file)
index def05d5..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * arch/arm/mach-imx/include/mach/mx1ads.h
- *
- * Copyright (C) 2004 Robert Schwebel, Pengutronix
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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_MX1ADS_H
-#define __ASM_ARCH_MX1ADS_H
-
-/* ------------------------------------------------------------------------ */
-/* Memory Map for the M9328MX1ADS (MX1ADS) Board                            */
-/* ------------------------------------------------------------------------ */
-
-#define MX1ADS_FLASH_PHYS              0x10000000
-#define MX1ADS_FLASH_SIZE              (16*1024*1024)
-
-#define IMX_FB_PHYS                    (0x0C000000 - 0x40000)
-
-#define CLK32 32000
-
-#endif /* __ASM_ARCH_MX1ADS_H */
diff --git a/arch/arm/mach-imx/include/mach/spi_imx.h b/arch/arm/mach-imx/include/mach/spi_imx.h
deleted file mode 100644 (file)
index 4186430..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * arch/arm/mach-imx/include/mach/spi_imx.h
- *
- * Copyright (C) 2006 SWAPP
- *     Andrea Paterniani <a.paterniani@swapp-eng.it>
- *
- * Initial version inspired by:
- *     linux-2.6.17-rc3-mm1/arch/arm/mach-pxa/include/mach/pxa2xx_spi.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 Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef SPI_IMX_H_
-#define SPI_IMX_H_
-
-
-/*-------------------------------------------------------------------------*/
-/**
- * struct spi_imx_master - device.platform_data for SPI controller devices.
- * @num_chipselect: chipselects are used to distinguish individual
- *     SPI slaves, and are numbered from zero to num_chipselects - 1.
- *     each slave has a chipselect signal, but it's common that not
- *     every chipselect is connected to a slave.
- * @enable_dma: if true enables DMA driven transfers.
-*/
-struct spi_imx_master {
-       u8 num_chipselect;
-       u8 enable_dma:1;
-};
-/*-------------------------------------------------------------------------*/
-
-
-/*-------------------------------------------------------------------------*/
-/**
- * struct spi_imx_chip - spi_board_info.controller_data for SPI
- * slave devices, copied to spi_device.controller_data.
- * @enable_loopback : used for test purpouse to internally connect RX and TX
- *     sections.
- * @enable_dma : enables dma transfer (provided that controller driver has
- *     dma enabled too).
- * @ins_ss_pulse : enable /SS pulse insertion between SPI burst.
- * @bclk_wait : number of bclk waits between each bits_per_word SPI burst.
- * @cs_control : function pointer to board-specific function to assert/deassert
- *     I/O port to control HW generation of devices chip-select.
-*/
-struct spi_imx_chip {
-       u8      enable_loopback:1;
-       u8      enable_dma:1;
-       u8      ins_ss_pulse:1;
-       u16     bclk_wait:15;
-       void (*cs_control)(u32 control);
-};
-
-/* Chip-select state */
-#define SPI_CS_ASSERT                  (1 << 0)
-#define SPI_CS_DEASSERT                        (1 << 1)
-/*-------------------------------------------------------------------------*/
-
-
-#endif /* SPI_IMX_H_*/
diff --git a/arch/arm/mach-imx/include/mach/system.h b/arch/arm/mach-imx/include/mach/system.h
deleted file mode 100644 (file)
index 46d4ca9..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- *  arch/arm/mach-imxads/include/mach/system.h
- *
- *  Copyright (C) 1999 ARM Limited
- *  Copyright (C) 2000 Deep Blue Solutions 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.
- *
- * 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_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static 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)
-{
-       cpu_reset(0);
-}
-
-#endif
diff --git a/arch/arm/mach-imx/include/mach/timex.h b/arch/arm/mach-imx/include/mach/timex.h
deleted file mode 100644 (file)
index e22ba78..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- *  linux/include/asm-arm/imx/timex.h
- *
- *  Copyright (C) 1999 ARM Limited
- *
- * 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_TIMEX_H
-#define __ASM_ARCH_TIMEX_H
-
-#define CLOCK_TICK_RATE                (16000000)
-
-#endif
diff --git a/arch/arm/mach-imx/include/mach/uncompress.h b/arch/arm/mach-imx/include/mach/uncompress.h
deleted file mode 100644 (file)
index 70523e6..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- *  arch/arm/mach-imxads/include/mach/uncompress.h
- *
- *
- *
- *  Copyright (C) 1999 ARM Limited
- *  Copyright (C) Shane Nay (shane@minirl.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 UART(x) (*(volatile unsigned long *)(serial_port + (x)))
-
-#define UART1_BASE 0x206000
-#define UART2_BASE 0x207000
-#define USR2 0x98
-#define USR2_TXFE (1<<14)
-#define TXR  0x40
-#define UCR1 0x80
-#define UCR1_UARTEN 1
-
-/*
- * The following code assumes the serial port has already been
- * initialized by the bootloader.  We search for the first enabled
- * port in the most probable order.  If you didn't setup a port in
- * your bootloader then nothing will appear (which might be desired).
- *
- * This does not append a newline
- */
-static void putc(int c)
-{
-       unsigned long serial_port;
-
-       do {
-               serial_port = UART1_BASE;
-               if ( UART(UCR1) & UCR1_UARTEN )
-                       break;
-               serial_port = UART2_BASE;
-               if ( UART(UCR1) & UCR1_UARTEN )
-                       break;
-               return;
-       } while(0);
-
-       while (!(UART(USR2) & USR2_TXFE))
-               barrier();
-
-       UART(TXR) = c;
-}
-
-static inline void flush(void)
-{
-}
-
-/*
- * nothing to do
- */
-#define arch_decomp_setup()
-
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-imx/include/mach/vmalloc.h b/arch/arm/mach-imx/include/mach/vmalloc.h
deleted file mode 100644 (file)
index 7d7cb0b..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *  arch/arm/mach-imx/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 + 0x10000000)
diff --git a/arch/arm/mach-imx/irq.c b/arch/arm/mach-imx/irq.c
deleted file mode 100644 (file)
index 531b95d..0000000
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- *  linux/arch/arm/mach-imx/irq.c
- *
- *  Copyright (C) 1999 ARM Limited
- *  Copyright (C) 2002 Shane Nay (shane@minirl.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
- *
- *  03/03/2004   Sascha Hauer <sascha@saschahauer.de>
- *               Copied from the motorola bsp package and added gpio demux
- *               interrupt handler
- */
-
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-
-#include <asm/mach/irq.h>
-
-/*
- *
- * We simply use the ENABLE DISABLE registers inside of the IMX
- * to turn on/off specific interrupts.
- *
- */
-
-#define INTCNTL_OFF               0x00
-#define NIMASK_OFF                0x04
-#define INTENNUM_OFF              0x08
-#define INTDISNUM_OFF             0x0C
-#define INTENABLEH_OFF            0x10
-#define INTENABLEL_OFF            0x14
-#define INTTYPEH_OFF              0x18
-#define INTTYPEL_OFF              0x1C
-#define NIPRIORITY_OFF(x)         (0x20+4*(7-(x)))
-#define NIVECSR_OFF               0x40
-#define FIVECSR_OFF               0x44
-#define INTSRCH_OFF               0x48
-#define INTSRCL_OFF               0x4C
-#define INTFRCH_OFF               0x50
-#define INTFRCL_OFF               0x54
-#define NIPNDH_OFF                0x58
-#define NIPNDL_OFF                0x5C
-#define FIPNDH_OFF                0x60
-#define FIPNDL_OFF                0x64
-
-#define VA_AITC_BASE              IO_ADDRESS(IMX_AITC_BASE)
-#define IMX_AITC_INTCNTL         (VA_AITC_BASE + INTCNTL_OFF)
-#define IMX_AITC_NIMASK          (VA_AITC_BASE + NIMASK_OFF)
-#define IMX_AITC_INTENNUM        (VA_AITC_BASE + INTENNUM_OFF)
-#define IMX_AITC_INTDISNUM       (VA_AITC_BASE + INTDISNUM_OFF)
-#define IMX_AITC_INTENABLEH      (VA_AITC_BASE + INTENABLEH_OFF)
-#define IMX_AITC_INTENABLEL      (VA_AITC_BASE + INTENABLEL_OFF)
-#define IMX_AITC_INTTYPEH        (VA_AITC_BASE + INTTYPEH_OFF)
-#define IMX_AITC_INTTYPEL        (VA_AITC_BASE + INTTYPEL_OFF)
-#define IMX_AITC_NIPRIORITY(x)   (VA_AITC_BASE + NIPRIORITY_OFF(x))
-#define IMX_AITC_NIVECSR         (VA_AITC_BASE + NIVECSR_OFF)
-#define IMX_AITC_FIVECSR         (VA_AITC_BASE + FIVECSR_OFF)
-#define IMX_AITC_INTSRCH         (VA_AITC_BASE + INTSRCH_OFF)
-#define IMX_AITC_INTSRCL         (VA_AITC_BASE + INTSRCL_OFF)
-#define IMX_AITC_INTFRCH         (VA_AITC_BASE + INTFRCH_OFF)
-#define IMX_AITC_INTFRCL         (VA_AITC_BASE + INTFRCL_OFF)
-#define IMX_AITC_NIPNDH          (VA_AITC_BASE + NIPNDH_OFF)
-#define IMX_AITC_NIPNDL          (VA_AITC_BASE + NIPNDL_OFF)
-#define IMX_AITC_FIPNDH          (VA_AITC_BASE + FIPNDH_OFF)
-#define IMX_AITC_FIPNDL          (VA_AITC_BASE + FIPNDL_OFF)
-
-#if 0
-#define DEBUG_IRQ(fmt...)      printk(fmt)
-#else
-#define DEBUG_IRQ(fmt...)      do { } while (0)
-#endif
-
-static void
-imx_mask_irq(unsigned int irq)
-{
-       __raw_writel(irq, IMX_AITC_INTDISNUM);
-}
-
-static void
-imx_unmask_irq(unsigned int irq)
-{
-       __raw_writel(irq, IMX_AITC_INTENNUM);
-}
-
-#ifdef CONFIG_FIQ
-int imx_set_irq_fiq(unsigned int irq, unsigned int type)
-{
-       unsigned int irqt;
-
-       if (irq >= IMX_IRQS)
-               return -EINVAL;
-
-       if (irq < IMX_IRQS / 2) {
-               irqt = __raw_readl(IMX_AITC_INTTYPEL) & ~(1 << irq);
-               __raw_writel(irqt | (!!type << irq), IMX_AITC_INTTYPEL);
-       } else {
-               irq -= IMX_IRQS / 2;
-               irqt = __raw_readl(IMX_AITC_INTTYPEH) & ~(1 << irq);
-               __raw_writel(irqt | (!!type << irq), IMX_AITC_INTTYPEH);
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL(imx_set_irq_fiq);
-#endif /* CONFIG_FIQ */
-
-static int
-imx_gpio_irq_type(unsigned int _irq, unsigned int type)
-{
-       unsigned int irq_type = 0, irq, reg, bit;
-
-       irq = _irq - IRQ_GPIOA(0);
-       reg = irq >> 5;
-       bit = 1 << (irq % 32);
-
-       if (type == IRQ_TYPE_PROBE) {
-               /* Don't mess with enabled GPIOs using preconfigured edges or
-                  GPIOs set to alternate function during probe */
-               /* TODO: support probe */
-//              if ((GPIO_IRQ_rising_edge[idx] | GPIO_IRQ_falling_edge[idx]) &
-//                  GPIO_bit(gpio))
-//                      return 0;
-//              if (GAFR(gpio) & (0x3 << (((gpio) & 0xf)*2)))
-//                      return 0;
-//              type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
-       }
-
-       GIUS(reg) |= bit;
-       DDIR(reg) &= ~(bit);
-
-       DEBUG_IRQ("setting type of irq %d to ", _irq);
-
-       if (type & IRQ_TYPE_EDGE_RISING) {
-               DEBUG_IRQ("rising edges\n");
-               irq_type = 0x0;
-       }
-       if (type & IRQ_TYPE_EDGE_FALLING) {
-               DEBUG_IRQ("falling edges\n");
-               irq_type = 0x1;
-       }
-       if (type & IRQ_TYPE_LEVEL_LOW) {
-               DEBUG_IRQ("low level\n");
-               irq_type = 0x3;
-       }
-       if (type & IRQ_TYPE_LEVEL_HIGH) {
-               DEBUG_IRQ("high level\n");
-               irq_type = 0x2;
-       }
-
-       if (irq % 32 < 16) {
-               ICR1(reg) = (ICR1(reg) & ~(0x3 << ((irq % 16) * 2))) |
-                   (irq_type << ((irq % 16) * 2));
-       } else {
-               ICR2(reg) = (ICR2(reg) & ~(0x3 << ((irq % 16) * 2))) |
-                   (irq_type << ((irq % 16) * 2));
-       }
-
-       return 0;
-
-}
-
-static void
-imx_gpio_ack_irq(unsigned int irq)
-{
-       DEBUG_IRQ("%s: irq %d\n", __func__, irq);
-       ISR(IRQ_TO_REG(irq)) = 1 << ((irq - IRQ_GPIOA(0)) % 32);
-}
-
-static void
-imx_gpio_mask_irq(unsigned int irq)
-{
-       DEBUG_IRQ("%s: irq %d\n", __func__, irq);
-       IMR(IRQ_TO_REG(irq)) &= ~( 1 << ((irq - IRQ_GPIOA(0)) % 32));
-}
-
-static void
-imx_gpio_unmask_irq(unsigned int irq)
-{
-       DEBUG_IRQ("%s: irq %d\n", __func__, irq);
-       IMR(IRQ_TO_REG(irq)) |= 1 << ((irq - IRQ_GPIOA(0)) % 32);
-}
-
-static void
-imx_gpio_handler(unsigned int mask, unsigned int irq,
-                 struct irq_desc *desc)
-{
-       while (mask) {
-               if (mask & 1) {
-                       DEBUG_IRQ("handling irq %d\n", irq);
-                       generic_handle_irq(irq);
-               }
-               irq++;
-               mask >>= 1;
-       }
-}
-
-static void
-imx_gpioa_demux_handler(unsigned int irq_unused, struct irq_desc *desc)
-{
-       unsigned int mask, irq;
-
-       mask = ISR(0);
-       irq = IRQ_GPIOA(0);
-       imx_gpio_handler(mask, irq, desc);
-}
-
-static void
-imx_gpiob_demux_handler(unsigned int irq_unused, struct irq_desc *desc)
-{
-       unsigned int mask, irq;
-
-       mask = ISR(1);
-       irq = IRQ_GPIOB(0);
-       imx_gpio_handler(mask, irq, desc);
-}
-
-static void
-imx_gpioc_demux_handler(unsigned int irq_unused, struct irq_desc *desc)
-{
-       unsigned int mask, irq;
-
-       mask = ISR(2);
-       irq = IRQ_GPIOC(0);
-       imx_gpio_handler(mask, irq, desc);
-}
-
-static void
-imx_gpiod_demux_handler(unsigned int irq_unused, struct irq_desc *desc)
-{
-       unsigned int mask, irq;
-
-       mask = ISR(3);
-       irq = IRQ_GPIOD(0);
-       imx_gpio_handler(mask, irq, desc);
-}
-
-static struct irq_chip imx_internal_chip = {
-       .name = "MPU",
-       .ack = imx_mask_irq,
-       .mask = imx_mask_irq,
-       .unmask = imx_unmask_irq,
-};
-
-static struct irq_chip imx_gpio_chip = {
-       .name = "GPIO",
-       .ack = imx_gpio_ack_irq,
-       .mask = imx_gpio_mask_irq,
-       .unmask = imx_gpio_unmask_irq,
-       .set_type = imx_gpio_irq_type,
-};
-
-void __init
-imx_init_irq(void)
-{
-       unsigned int irq;
-
-       DEBUG_IRQ("Initializing imx interrupts\n");
-
-       /* Disable all interrupts initially. */
-       /* Do not rely on the bootloader. */
-       __raw_writel(0, IMX_AITC_INTENABLEH);
-       __raw_writel(0, IMX_AITC_INTENABLEL);
-
-       /* Mask all GPIO interrupts as well */
-       IMR(0) = 0;
-       IMR(1) = 0;
-       IMR(2) = 0;
-       IMR(3) = 0;
-
-       for (irq = 0; irq < IMX_IRQS; irq++) {
-               set_irq_chip(irq, &imx_internal_chip);
-               set_irq_handler(irq, handle_level_irq);
-               set_irq_flags(irq, IRQF_VALID);
-       }
-
-       for (irq = IRQ_GPIOA(0); irq < IRQ_GPIOD(32); irq++) {
-               set_irq_chip(irq, &imx_gpio_chip);
-               set_irq_handler(irq, handle_edge_irq);
-               set_irq_flags(irq, IRQF_VALID);
-       }
-
-       set_irq_chained_handler(GPIO_INT_PORTA, imx_gpioa_demux_handler);
-       set_irq_chained_handler(GPIO_INT_PORTB, imx_gpiob_demux_handler);
-       set_irq_chained_handler(GPIO_INT_PORTC, imx_gpioc_demux_handler);
-       set_irq_chained_handler(GPIO_INT_PORTD, imx_gpiod_demux_handler);
-
-       /* Release masking of interrupts according to priority */
-       __raw_writel(-1, IMX_AITC_NIMASK);
-
-#ifdef CONFIG_FIQ
-       /* Initialize FIQ */
-       init_FIQ();
-#endif
-}
diff --git a/arch/arm/mach-imx/leds-mx1ads.c b/arch/arm/mach-imx/leds-mx1ads.c
deleted file mode 100644 (file)
index 1d48f27..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * linux/arch/arm/mach-imx/leds-mx1ads.c
- *
- * Copyright (c) 2004 Sascha Hauer <sascha@saschahauer.de>
- *
- * Original (leds-footbridge.c) by Russell King
- *
- * This 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/io.h>
-#include <mach/hardware.h>
-#include <asm/system.h>
-#include <asm/leds.h>
-#include "leds.h"
-
-/*
- * The MX1ADS Board has only one usable LED,
- * so select only the timer led or the
- * cpu usage led
- */
-void
-mx1ads_leds_event(led_event_t ledevt)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       switch (ledevt) {
-#ifdef CONFIG_LEDS_CPU
-       case led_idle_start:
-               DR(0) &= ~(1<<2);
-               break;
-
-       case led_idle_end:
-               DR(0) |= 1<<2;
-               break;
-#endif
-
-#ifdef CONFIG_LEDS_TIMER
-       case led_timer:
-               DR(0) ^= 1<<2;
-#endif
-       default:
-               break;
-       }
-       local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-imx/leds.c b/arch/arm/mach-imx/leds.c
deleted file mode 100644 (file)
index cf30803..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * linux/arch/arm/mach-imx/leds.c
- *
- * Copyright (C) 2004 Sascha Hauer <sascha@saschahauer.de>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-
-#include "leds.h"
-
-static int __init
-leds_init(void)
-{
-       if (machine_is_mx1ads()) {
-               leds_event = mx1ads_leds_event;
-       }
-
-       return 0;
-}
-
-__initcall(leds_init);
diff --git a/arch/arm/mach-imx/leds.h b/arch/arm/mach-imx/leds.h
deleted file mode 100644 (file)
index 49dc1c1..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * arch/arm/mach-imx/leds.h
- *
- * Copyright (c) 2004 Sascha Hauer <sascha@saschahauer.de>
- *
- * blinky lights for IMX-based systems
- *
- */
-extern void mx1ads_leds_event(led_event_t evt);
diff --git a/arch/arm/mach-imx/mx1ads.c b/arch/arm/mach-imx/mx1ads.c
deleted file mode 100644 (file)
index 87fa1ff..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * arch/arm/mach-imx/mx1ads.c
- *
- * Initially based on:
- *     linux-2.6.7-imx/arch/arm/mach-imx/scb9328.c
- *     Copyright (c) 2004 Sascha Hauer <sascha@saschahauer.de>
- *
- * 2004 (c) MontaVista Software, Inc.
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/device.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <asm/system.h>
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-
-#include <asm/mach/map.h>
-#include <asm/mach-types.h>
-
-#include <asm/mach/arch.h>
-#include <mach/mmc.h>
-#include <mach/imx-uart.h>
-#include <linux/interrupt.h>
-#include "generic.h"
-
-static struct resource cs89x0_resources[] = {
-       [0] = {
-               .start  = IMX_CS4_PHYS + 0x300,
-               .end    = IMX_CS4_PHYS + 0x300 + 16,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = IRQ_GPIOC(17),
-               .end    = IRQ_GPIOC(17),
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device cs89x0_device = {
-       .name           = "cirrus-cs89x0",
-       .num_resources  = ARRAY_SIZE(cs89x0_resources),
-       .resource       = cs89x0_resources,
-};
-
-static struct imxuart_platform_data uart_pdata = {
-       .flags = IMXUART_HAVE_RTSCTS,
-};
-
-static struct resource imx_uart1_resources[] = {
-       [0] = {
-               .start  = 0x00206000,
-               .end    = 0x002060FF,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = (UART1_MINT_RX),
-               .end    = (UART1_MINT_RX),
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .start  = (UART1_MINT_TX),
-               .end    = (UART1_MINT_TX),
-               .flags  = IORESOURCE_IRQ,
-       },
-       [3] = {
-               .start  = UART1_MINT_RTS,
-               .end    = UART1_MINT_RTS,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device imx_uart1_device = {
-       .name           = "imx-uart",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(imx_uart1_resources),
-       .resource       = imx_uart1_resources,
-       .dev = {
-               .platform_data = &uart_pdata,
-       }
-};
-
-static struct resource imx_uart2_resources[] = {
-       [0] = {
-               .start  = 0x00207000,
-               .end    = 0x002070FF,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = (UART2_MINT_RX),
-               .end    = (UART2_MINT_RX),
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .start  = (UART2_MINT_TX),
-               .end    = (UART2_MINT_TX),
-               .flags  = IORESOURCE_IRQ,
-       },
-       [3] = {
-               .start  = UART2_MINT_RTS,
-               .end    = UART2_MINT_RTS,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device imx_uart2_device = {
-       .name           = "imx-uart",
-       .id             = 1,
-       .num_resources  = ARRAY_SIZE(imx_uart2_resources),
-       .resource       = imx_uart2_resources,
-       .dev = {
-               .platform_data = &uart_pdata,
-       }
-};
-
-static struct platform_device *devices[] __initdata = {
-       &cs89x0_device,
-       &imx_uart1_device,
-       &imx_uart2_device,
-};
-
-#if defined(CONFIG_MMC_IMX) || defined(CONFIG_MMC_IMX_MODULE)
-static int mx1ads_mmc_card_present(struct device *dev)
-{
-       /* MMC/SD Card Detect is PB 20 on MX1ADS V1.0.7 */
-       return (SSR(1) & (1 << 20) ? 0 : 1);
-}
-
-static struct imxmmc_platform_data mx1ads_mmc_info = {
-       .card_present = mx1ads_mmc_card_present,
-};
-#endif
-
-static void __init
-mx1ads_init(void)
-{
-#ifdef CONFIG_LEDS
-       imx_gpio_mode(GPIO_PORTA | GPIO_OUT | 2);
-#endif
-#if defined(CONFIG_MMC_IMX) || defined(CONFIG_MMC_IMX_MODULE)
-       /* SD/MMC card detect */
-       imx_gpio_mode(GPIO_PORTB | GPIO_GIUS | GPIO_IN | 20);
-       imx_set_mmc_info(&mx1ads_mmc_info);
-#endif
-
-       imx_gpio_mode(PC9_PF_UART1_CTS);
-       imx_gpio_mode(PC10_PF_UART1_RTS);
-       imx_gpio_mode(PC11_PF_UART1_TXD);
-       imx_gpio_mode(PC12_PF_UART1_RXD);
-
-       imx_gpio_mode(PB28_PF_UART2_CTS);
-       imx_gpio_mode(PB29_PF_UART2_RTS);
-       imx_gpio_mode(PB30_PF_UART2_TXD);
-       imx_gpio_mode(PB31_PF_UART2_RXD);
-
-       platform_add_devices(devices, ARRAY_SIZE(devices));
-}
-
-static void __init
-mx1ads_map_io(void)
-{
-       imx_map_io();
-}
-
-MACHINE_START(MX1ADS, "Motorola MX1ADS")
-       /* Maintainer: Sascha Hauer, Pengutronix */
-       .phys_io        = 0x00200000,
-       .io_pg_offst    = ((0xe0000000) >> 18) & 0xfffc,
-       .boot_params    = 0x08000100,
-       .map_io         = mx1ads_map_io,
-       .init_irq       = imx_init_irq,
-       .timer          = &imx_timer,
-       .init_machine   = mx1ads_init,
-MACHINE_END
diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c
deleted file mode 100644 (file)
index 5aef18b..0000000
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- *  linux/arch/arm/mach-imx/time.c
- *
- *  Copyright (C) 2000-2001 Deep Blue Solutions
- *  Copyright (C) 2002 Shane Nay (shane@minirl.com)
- *  Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.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/sched.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/time.h>
-#include <linux/clocksource.h>
-#include <linux/clockchips.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-#include <asm/irq.h>
-#include <asm/mach/time.h>
-
-/* Use timer 1 as system timer */
-#define TIMER_BASE IMX_TIM1_BASE
-
-static struct clock_event_device clockevent_imx;
-static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
-
-/*
- * IRQ handler for the timer
- */
-static irqreturn_t
-imx_timer_interrupt(int irq, void *dev_id)
-{
-       struct clock_event_device *evt = &clockevent_imx;
-       uint32_t tstat;
-       irqreturn_t ret = IRQ_NONE;
-
-       /* clear the interrupt */
-       tstat = IMX_TSTAT(TIMER_BASE);
-       IMX_TSTAT(TIMER_BASE) = 0;
-
-       if (tstat & TSTAT_COMP) {
-               evt->event_handler(evt);
-               ret = IRQ_HANDLED;
-       }
-
-       return ret;
-}
-
-static struct irqaction imx_timer_irq = {
-       .name           = "i.MX Timer Tick",
-       .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-       .handler        = imx_timer_interrupt,
-};
-
-/*
- * Set up timer hardware into expected mode and state.
- */
-static void __init imx_timer_hardware_init(void)
-{
-       /*
-        * Initialise to a known state (all timers off, and timing reset)
-        */
-       IMX_TCTL(TIMER_BASE) = 0;
-       IMX_TPRER(TIMER_BASE) = 0;
-
-       IMX_TCTL(TIMER_BASE) = TCTL_FRR | TCTL_CLK_PCLK1 | TCTL_TEN;
-}
-
-cycle_t imx_get_cycles(struct clocksource *cs)
-{
-       return IMX_TCN(TIMER_BASE);
-}
-
-static struct clocksource clocksource_imx = {
-       .name           = "imx_timer1",
-       .rating         = 200,
-       .read           = imx_get_cycles,
-       .mask           = 0xFFFFFFFF,
-       .shift          = 20,
-       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-static int __init imx_clocksource_init(unsigned long rate)
-{
-       clocksource_imx.mult =
-               clocksource_hz2mult(rate, clocksource_imx.shift);
-       clocksource_register(&clocksource_imx);
-
-       return 0;
-}
-
-static int imx_set_next_event(unsigned long evt,
-                                 struct clock_event_device *unused)
-{
-       unsigned long tcmp;
-
-       tcmp = IMX_TCN(TIMER_BASE) + evt;
-       IMX_TCMP(TIMER_BASE) = tcmp;
-
-       return (int32_t)(tcmp - IMX_TCN(TIMER_BASE)) < 0 ? -ETIME : 0;
-}
-
-#ifdef DEBUG
-static const char *clock_event_mode_label[]={
-       [CLOCK_EVT_MODE_PERIODIC] = "CLOCK_EVT_MODE_PERIODIC",
-       [CLOCK_EVT_MODE_ONESHOT]  = "CLOCK_EVT_MODE_ONESHOT",
-       [CLOCK_EVT_MODE_SHUTDOWN] = "CLOCK_EVT_MODE_SHUTDOWN",
-       [CLOCK_EVT_MODE_UNUSED]   = "CLOCK_EVT_MODE_UNUSED"
-};
-#endif /*DEBUG*/
-
-static void imx_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
-{
-       unsigned long flags;
-
-       /*
-        * The timer interrupt generation is disabled at least
-        * for enough time to call imx_set_next_event()
-        */
-       local_irq_save(flags);
-       /* Disable interrupt in GPT module */
-       IMX_TCTL(TIMER_BASE) &= ~TCTL_IRQEN;
-       if (mode != clockevent_mode) {
-               /* Set event time into far-far future */
-               IMX_TCMP(TIMER_BASE) = IMX_TCN(TIMER_BASE) - 3;
-               /* Clear pending interrupt */
-               IMX_TSTAT(TIMER_BASE) &= ~TSTAT_COMP;
-       }
-
-#ifdef DEBUG
-       printk(KERN_INFO "imx_set_mode: changing mode from %s to %s\n",
-               clock_event_mode_label[clockevent_mode], clock_event_mode_label[mode]);
-#endif /*DEBUG*/
-
-       /* Remember timer mode */
-       clockevent_mode = mode;
-       local_irq_restore(flags);
-
-       switch (mode) {
-       case CLOCK_EVT_MODE_PERIODIC:
-               printk(KERN_ERR "imx_set_mode: Periodic mode is not supported for i.MX\n");
-               break;
-       case CLOCK_EVT_MODE_ONESHOT:
-               /*
-                * Do not put overhead of interrupt enable/disable into
-                * imx_set_next_event(), the core has about 4 minutes
-                * to call imx_set_next_event() or shutdown clock after
-                * mode switching
-                */
-               local_irq_save(flags);
-               IMX_TCTL(TIMER_BASE) |= TCTL_IRQEN;
-               local_irq_restore(flags);
-               break;
-       case CLOCK_EVT_MODE_SHUTDOWN:
-       case CLOCK_EVT_MODE_UNUSED:
-       case CLOCK_EVT_MODE_RESUME:
-               /* Left event sources disabled, no more interrupts appears */
-               break;
-       }
-}
-
-static struct clock_event_device clockevent_imx = {
-       .name           = "imx_timer1",
-       .features       = CLOCK_EVT_FEAT_ONESHOT,
-       .shift          = 32,
-       .set_mode       = imx_set_mode,
-       .set_next_event = imx_set_next_event,
-       .rating         = 200,
-};
-
-static int __init imx_clockevent_init(unsigned long rate)
-{
-       clockevent_imx.mult = div_sc(rate, NSEC_PER_SEC,
-                                       clockevent_imx.shift);
-       clockevent_imx.max_delta_ns =
-               clockevent_delta2ns(0xfffffffe, &clockevent_imx);
-       clockevent_imx.min_delta_ns =
-               clockevent_delta2ns(0xf, &clockevent_imx);
-
-       clockevent_imx.cpumask = cpumask_of(0);
-
-       clockevents_register_device(&clockevent_imx);
-
-       return 0;
-}
-
-extern int imx_clocks_init(void);
-
-static void __init imx_timer_init(void)
-{
-       struct clk *clk;
-       unsigned long rate;
-
-       imx_clocks_init();
-
-       clk = clk_get(NULL, "perclk1");
-       clk_enable(clk);
-       rate = clk_get_rate(clk);
-
-       imx_timer_hardware_init();
-       imx_clocksource_init(rate);
-
-       imx_clockevent_init(rate);
-
-       /*
-        * Make irqs happen for the system timer
-        */
-       setup_irq(TIM1_INT, &imx_timer_irq);
-}
-
-struct sys_timer imx_timer = {
-       .init           = imx_timer_init,
-};
index 2c5a02b8520e4b4a79c8f38ce6e01e7836de441a..264f4d59f898158bdd0175ed9ccf17b1fb3392ef 100644 (file)
@@ -78,6 +78,12 @@ config MACH_IXDP465
          IXDP465 Development Platform (Also known as BMP).
          For more information on this platform, see <file:Documentation/arm/IXP4xx>.
 
+config MACH_GORAMO_MLR
+       bool "GORAMO Multi Link Router"
+       help
+         Say 'Y' here if you want your kernel to support GORAMO
+         MultiLink router.
+
 config MACH_KIXRP435
        bool "KIXRP435"
        help
index 2e6bbf927a743f8a594172d71aa942a60c674f83..47d1f60d23fa83db17a9ea83626faf8d7ae6da86 100644 (file)
@@ -30,6 +30,7 @@ obj-$(CONFIG_MACH_DSMG600)      += dsmg600-setup.o
 obj-$(CONFIG_MACH_GATEWAY7001) += gateway7001-setup.o
 obj-$(CONFIG_MACH_WG302V2)     += wg302v2-setup.o
 obj-$(CONFIG_MACH_FSG)         += fsg-setup.o
+obj-$(CONFIG_MACH_GORAMO_MLR)  += goramo_mlr.o
 
 obj-$(CONFIG_PCI)              += $(obj-pci-$(CONFIG_PCI)) common-pci.o
 obj-$(CONFIG_IXP4XX_QMGR)      += ixp4xx_qmgr.o
diff --git a/arch/arm/mach-ixp4xx/goramo_mlr.c b/arch/arm/mach-ixp4xx/goramo_mlr.c
new file mode 100644 (file)
index 0000000..a733b8f
--- /dev/null
@@ -0,0 +1,507 @@
+/*
+ * Goramo MultiLink router platform code
+ * Copyright (C) 2006-2009 Krzysztof Halasa <khc@pm.waw.pl>
+ */
+
+#include <linux/delay.h>
+#include <linux/hdlc.h>
+#include <linux/i2c-gpio.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/serial_8250.h>
+#include <asm/mach-types.h>
+#include <asm/system.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
+#include <asm/mach/pci.h>
+
+#define xgpio_irq(n)           (IRQ_IXP4XX_GPIO ## n)
+#define gpio_irq(n)            xgpio_irq(n)
+
+#define SLOT_ETHA              0x0B    /* IDSEL = AD21 */
+#define SLOT_ETHB              0x0C    /* IDSEL = AD20 */
+#define SLOT_MPCI              0x0D    /* IDSEL = AD19 */
+#define SLOT_NEC               0x0E    /* IDSEL = AD18 */
+
+#define IRQ_ETHA               IRQ_IXP4XX_GPIO4
+#define IRQ_ETHB               IRQ_IXP4XX_GPIO5
+#define IRQ_NEC                        IRQ_IXP4XX_GPIO3
+#define IRQ_MPCI               IRQ_IXP4XX_GPIO12
+
+/* GPIO lines */
+#define GPIO_SCL               0
+#define GPIO_SDA               1
+#define GPIO_STR               2
+#define GPIO_HSS0_DCD_N                6
+#define GPIO_HSS1_DCD_N                7
+#define GPIO_HSS0_CTS_N                10
+#define GPIO_HSS1_CTS_N                11
+#define GPIO_HSS1_RTS_N                13
+#define GPIO_HSS0_RTS_N                14
+
+/* Control outputs from 74HC4094 */
+#define CONTROL_HSS0_CLK_INT   0
+#define CONTROL_HSS1_CLK_INT   1
+#define CONTROL_HSS0_DTR_N     2
+#define CONTROL_HSS1_DTR_N     3
+#define CONTROL_EXT            4
+#define CONTROL_AUTO_RESET     5
+#define CONTROL_PCI_RESET_N    6
+#define CONTROL_EEPROM_WC_N    7
+
+/* offsets from start of flash ROM = 0x50000000 */
+#define CFG_ETH0_ADDRESS       0x40 /* 6 bytes */
+#define CFG_ETH1_ADDRESS       0x46 /* 6 bytes */
+#define CFG_REV                        0x4C /* u32 */
+#define CFG_SDRAM_SIZE         0x50 /* u32 */
+#define CFG_SDRAM_CONF         0x54 /* u32 */
+#define CFG_SDRAM_MODE         0x58 /* u32 */
+#define CFG_SDRAM_REFRESH      0x5C /* u32 */
+
+#define CFG_HW_BITS            0x60 /* u32 */
+#define  CFG_HW_USB_PORTS      0x00000007 /* 0 = no NEC chip, 1-5 = ports # */
+#define  CFG_HW_HAS_PCI_SLOT   0x00000008
+#define  CFG_HW_HAS_ETH0       0x00000010
+#define  CFG_HW_HAS_ETH1       0x00000020
+#define  CFG_HW_HAS_HSS0       0x00000040
+#define  CFG_HW_HAS_HSS1       0x00000080
+#define  CFG_HW_HAS_UART0      0x00000100
+#define  CFG_HW_HAS_UART1      0x00000200
+#define  CFG_HW_HAS_EEPROM     0x00000400
+
+#define FLASH_CMD_READ_ARRAY   0xFF
+#define FLASH_CMD_READ_ID      0x90
+#define FLASH_SER_OFF          0x102 /* 0x81 in 16-bit mode */
+
+static u32 hw_bits = 0xFFFFFFFD;    /* assume all hardware present */;
+static u8 control_value;
+
+static void set_scl(u8 value)
+{
+       gpio_line_set(GPIO_SCL, !!value);
+       udelay(3);
+}
+
+static void set_sda(u8 value)
+{
+       gpio_line_set(GPIO_SDA, !!value);
+       udelay(3);
+}
+
+static void set_str(u8 value)
+{
+       gpio_line_set(GPIO_STR, !!value);
+       udelay(3);
+}
+
+static inline void set_control(int line, int value)
+{
+       if (value)
+               control_value |=  (1 << line);
+       else
+               control_value &= ~(1 << line);
+}
+
+
+static void output_control(void)
+{
+       int i;
+
+       gpio_line_config(GPIO_SCL, IXP4XX_GPIO_OUT);
+       gpio_line_config(GPIO_SDA, IXP4XX_GPIO_OUT);
+
+       for (i = 0; i < 8; i++) {
+               set_scl(0);
+               set_sda(control_value & (0x80 >> i)); /* MSB first */
+               set_scl(1);     /* active edge */
+       }
+
+       set_str(1);
+       set_str(0);
+
+       set_scl(0);
+       set_sda(1);             /* Be ready for START */
+       set_scl(1);
+}
+
+
+static void (*set_carrier_cb_tab[2])(void *pdev, int carrier);
+
+static int hss_set_clock(int port, unsigned int clock_type)
+{
+       int ctrl_int = port ? CONTROL_HSS1_CLK_INT : CONTROL_HSS0_CLK_INT;
+
+       switch (clock_type) {
+       case CLOCK_DEFAULT:
+       case CLOCK_EXT:
+               set_control(ctrl_int, 0);
+               output_control();
+               return CLOCK_EXT;
+
+       case CLOCK_INT:
+               set_control(ctrl_int, 1);
+               output_control();
+               return CLOCK_INT;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static irqreturn_t hss_dcd_irq(int irq, void *pdev)
+{
+       int i, port = (irq == gpio_irq(GPIO_HSS1_DCD_N));
+       gpio_line_get(port ? GPIO_HSS1_DCD_N : GPIO_HSS0_DCD_N, &i);
+       set_carrier_cb_tab[port](pdev, !i);
+       return IRQ_HANDLED;
+}
+
+
+static int hss_open(int port, void *pdev,
+                   void (*set_carrier_cb)(void *pdev, int carrier))
+{
+       int i, irq;
+
+       if (!port)
+               irq = gpio_irq(GPIO_HSS0_DCD_N);
+       else
+               irq = gpio_irq(GPIO_HSS1_DCD_N);
+
+       gpio_line_get(port ? GPIO_HSS1_DCD_N : GPIO_HSS0_DCD_N, &i);
+       set_carrier_cb(pdev, !i);
+
+       set_carrier_cb_tab[!!port] = set_carrier_cb;
+
+       if ((i = request_irq(irq, hss_dcd_irq, 0, "IXP4xx HSS", pdev)) != 0) {
+               printk(KERN_ERR "ixp4xx_hss: failed to request IRQ%i (%i)\n",
+                      irq, i);
+               return i;
+       }
+
+       set_control(port ? CONTROL_HSS1_DTR_N : CONTROL_HSS0_DTR_N, 0);
+       output_control();
+       gpio_line_set(port ? GPIO_HSS1_RTS_N : GPIO_HSS0_RTS_N, 0);
+       return 0;
+}
+
+static void hss_close(int port, void *pdev)
+{
+       free_irq(port ? gpio_irq(GPIO_HSS1_DCD_N) : gpio_irq(GPIO_HSS0_DCD_N),
+                pdev);
+       set_carrier_cb_tab[!!port] = NULL; /* catch bugs */
+
+       set_control(port ? CONTROL_HSS1_DTR_N : CONTROL_HSS0_DTR_N, 1);
+       output_control();
+       gpio_line_set(port ? GPIO_HSS1_RTS_N : GPIO_HSS0_RTS_N, 1);
+}
+
+
+/* Flash memory */
+static struct flash_platform_data flash_data = {
+       .map_name       = "cfi_probe",
+       .width          = 2,
+};
+
+static struct resource flash_resource = {
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device device_flash = {
+       .name           = "IXP4XX-Flash",
+       .id             = 0,
+       .dev            = { .platform_data = &flash_data },
+       .num_resources  = 1,
+       .resource       = &flash_resource,
+};
+
+
+/* I^2C interface */
+static struct i2c_gpio_platform_data i2c_data = {
+       .sda_pin        = GPIO_SDA,
+       .scl_pin        = GPIO_SCL,
+};
+
+static struct platform_device device_i2c = {
+       .name           = "i2c-gpio",
+       .id             = 0,
+       .dev            = { .platform_data = &i2c_data },
+};
+
+
+/* IXP425 2 UART ports */
+static struct resource uart_resources[] = {
+       {
+               .start          = IXP4XX_UART1_BASE_PHYS,
+               .end            = IXP4XX_UART1_BASE_PHYS + 0x0fff,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = IXP4XX_UART2_BASE_PHYS,
+               .end            = IXP4XX_UART2_BASE_PHYS + 0x0fff,
+               .flags          = IORESOURCE_MEM,
+       }
+};
+
+static struct plat_serial8250_port uart_data[] = {
+       {
+               .mapbase        = IXP4XX_UART1_BASE_PHYS,
+               .membase        = (char __iomem *)IXP4XX_UART1_BASE_VIRT +
+                       REG_OFFSET,
+               .irq            = IRQ_IXP4XX_UART1,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+               .iotype         = UPIO_MEM,
+               .regshift       = 2,
+               .uartclk        = IXP4XX_UART_XTAL,
+       },
+       {
+               .mapbase        = IXP4XX_UART2_BASE_PHYS,
+               .membase        = (char __iomem *)IXP4XX_UART2_BASE_VIRT +
+                       REG_OFFSET,
+               .irq            = IRQ_IXP4XX_UART2,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+               .iotype         = UPIO_MEM,
+               .regshift       = 2,
+               .uartclk        = IXP4XX_UART_XTAL,
+       },
+       { },
+};
+
+static struct platform_device device_uarts = {
+       .name                   = "serial8250",
+       .id                     = PLAT8250_DEV_PLATFORM,
+       .dev.platform_data      = uart_data,
+       .num_resources          = 2,
+       .resource               = uart_resources,
+};
+
+
+/* Built-in 10/100 Ethernet MAC interfaces */
+static struct eth_plat_info eth_plat[] = {
+       {
+               .phy            = 0,
+               .rxq            = 3,
+               .txreadyq       = 32,
+       }, {
+               .phy            = 1,
+               .rxq            = 4,
+               .txreadyq       = 33,
+       }
+};
+
+static struct platform_device device_eth_tab[] = {
+       {
+               .name                   = "ixp4xx_eth",
+               .id                     = IXP4XX_ETH_NPEB,
+               .dev.platform_data      = eth_plat,
+       }, {
+               .name                   = "ixp4xx_eth",
+               .id                     = IXP4XX_ETH_NPEC,
+               .dev.platform_data      = eth_plat + 1,
+       }
+};
+
+
+/* IXP425 2 synchronous serial ports */
+static struct hss_plat_info hss_plat[] = {
+       {
+               .set_clock      = hss_set_clock,
+               .open           = hss_open,
+               .close          = hss_close,
+               .txreadyq       = 34,
+       }, {
+               .set_clock      = hss_set_clock,
+               .open           = hss_open,
+               .close          = hss_close,
+               .txreadyq       = 35,
+       }
+};
+
+static struct platform_device device_hss_tab[] = {
+       {
+               .name                   = "ixp4xx_hss",
+               .id                     = 0,
+               .dev.platform_data      = hss_plat,
+       }, {
+               .name                   = "ixp4xx_hss",
+               .id                     = 1,
+               .dev.platform_data      = hss_plat + 1,
+       }
+};
+
+
+static struct platform_device *device_tab[6] __initdata = {
+       &device_flash,          /* index 0 */
+};
+
+static inline u8 __init flash_readb(u8 __iomem *flash, u32 addr)
+{
+#ifdef __ARMEB__
+       return __raw_readb(flash + addr);
+#else
+       return __raw_readb(flash + (addr ^ 3));
+#endif
+}
+
+static inline u16 __init flash_readw(u8 __iomem *flash, u32 addr)
+{
+#ifdef __ARMEB__
+       return __raw_readw(flash + addr);
+#else
+       return __raw_readw(flash + (addr ^ 2));
+#endif
+}
+
+static void __init gmlr_init(void)
+{
+       u8 __iomem *flash;
+       int i, devices = 1; /* flash */
+
+       ixp4xx_sys_init();
+
+       if ((flash = ioremap(IXP4XX_EXP_BUS_BASE_PHYS, 0x80)) == NULL)
+               printk(KERN_ERR "goramo-mlr: unable to access system"
+                      " configuration data\n");
+       else {
+               system_rev = __raw_readl(flash + CFG_REV);
+               hw_bits = __raw_readl(flash + CFG_HW_BITS);
+
+               for (i = 0; i < ETH_ALEN; i++) {
+                       eth_plat[0].hwaddr[i] =
+                               flash_readb(flash, CFG_ETH0_ADDRESS + i);
+                       eth_plat[1].hwaddr[i] =
+                               flash_readb(flash, CFG_ETH1_ADDRESS + i);
+               }
+
+               __raw_writew(FLASH_CMD_READ_ID, flash);
+               system_serial_high = flash_readw(flash, FLASH_SER_OFF);
+               system_serial_high <<= 16;
+               system_serial_high |= flash_readw(flash, FLASH_SER_OFF + 2);
+               system_serial_low = flash_readw(flash, FLASH_SER_OFF + 4);
+               system_serial_low <<= 16;
+               system_serial_low |= flash_readw(flash, FLASH_SER_OFF + 6);
+               __raw_writew(FLASH_CMD_READ_ARRAY, flash);
+
+               iounmap(flash);
+       }
+
+       switch (hw_bits & (CFG_HW_HAS_UART0 | CFG_HW_HAS_UART1)) {
+       case CFG_HW_HAS_UART0:
+               memset(&uart_data[1], 0, sizeof(uart_data[1]));
+               device_uarts.num_resources = 1;
+               break;
+
+       case CFG_HW_HAS_UART1:
+               device_uarts.dev.platform_data = &uart_data[1];
+               device_uarts.resource = &uart_resources[1];
+               device_uarts.num_resources = 1;
+               break;
+       }
+       if (hw_bits & (CFG_HW_HAS_UART0 | CFG_HW_HAS_UART1))
+               device_tab[devices++] = &device_uarts; /* max index 1 */
+
+       if (hw_bits & CFG_HW_HAS_ETH0)
+               device_tab[devices++] = &device_eth_tab[0]; /* max index 2 */
+       if (hw_bits & CFG_HW_HAS_ETH1)
+               device_tab[devices++] = &device_eth_tab[1]; /* max index 3 */
+
+       if (hw_bits & CFG_HW_HAS_HSS0)
+               device_tab[devices++] = &device_hss_tab[0]; /* max index 4 */
+       if (hw_bits & CFG_HW_HAS_HSS1)
+               device_tab[devices++] = &device_hss_tab[1]; /* max index 5 */
+
+       if (hw_bits & CFG_HW_HAS_EEPROM)
+               device_tab[devices++] = &device_i2c; /* max index 6 */
+
+       gpio_line_config(GPIO_SCL, IXP4XX_GPIO_OUT);
+       gpio_line_config(GPIO_SDA, IXP4XX_GPIO_OUT);
+       gpio_line_config(GPIO_STR, IXP4XX_GPIO_OUT);
+       gpio_line_config(GPIO_HSS0_RTS_N, IXP4XX_GPIO_OUT);
+       gpio_line_config(GPIO_HSS1_RTS_N, IXP4XX_GPIO_OUT);
+       gpio_line_config(GPIO_HSS0_DCD_N, IXP4XX_GPIO_IN);
+       gpio_line_config(GPIO_HSS1_DCD_N, IXP4XX_GPIO_IN);
+       set_irq_type(gpio_irq(GPIO_HSS0_DCD_N), IRQ_TYPE_EDGE_BOTH);
+       set_irq_type(gpio_irq(GPIO_HSS1_DCD_N), IRQ_TYPE_EDGE_BOTH);
+
+       set_control(CONTROL_HSS0_DTR_N, 1);
+       set_control(CONTROL_HSS1_DTR_N, 1);
+       set_control(CONTROL_EEPROM_WC_N, 1);
+       set_control(CONTROL_PCI_RESET_N, 1);
+       output_control();
+
+       msleep(1);            /* Wait for PCI devices to initialize */
+
+       flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
+       flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1;
+
+       platform_add_devices(device_tab, devices);
+}
+
+
+#ifdef CONFIG_PCI
+static void __init gmlr_pci_preinit(void)
+{
+       set_irq_type(IRQ_ETHA, IRQ_TYPE_LEVEL_LOW);
+       set_irq_type(IRQ_ETHB, IRQ_TYPE_LEVEL_LOW);
+       set_irq_type(IRQ_NEC, IRQ_TYPE_LEVEL_LOW);
+       set_irq_type(IRQ_MPCI, IRQ_TYPE_LEVEL_LOW);
+       ixp4xx_pci_preinit();
+}
+
+static void __init gmlr_pci_postinit(void)
+{
+       if ((hw_bits & CFG_HW_USB_PORTS) >= 2 &&
+           (hw_bits & CFG_HW_USB_PORTS) < 5) {
+               /* need to adjust number of USB ports on NEC chip */
+               u32 value, addr = BIT(32 - SLOT_NEC) | 0xE0;
+               if (!ixp4xx_pci_read(addr, NP_CMD_CONFIGREAD, &value)) {
+                       value &= ~7;
+                       value |= (hw_bits & CFG_HW_USB_PORTS);
+                       ixp4xx_pci_write(addr, NP_CMD_CONFIGWRITE, value);
+               }
+       }
+}
+
+static int __init gmlr_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+       switch(slot) {
+       case SLOT_ETHA: return IRQ_ETHA;
+       case SLOT_ETHB: return IRQ_ETHB;
+       case SLOT_NEC:  return IRQ_NEC;
+       default:        return IRQ_MPCI;
+       }
+}
+
+static struct hw_pci gmlr_hw_pci __initdata = {
+       .nr_controllers = 1,
+       .preinit        = gmlr_pci_preinit,
+       .postinit       = gmlr_pci_postinit,
+       .swizzle        = pci_std_swizzle,
+       .setup          = ixp4xx_setup,
+       .scan           = ixp4xx_scan_bus,
+       .map_irq        = gmlr_map_irq,
+};
+
+static int __init gmlr_pci_init(void)
+{
+       if (machine_is_goramo_mlr() &&
+           (hw_bits & (CFG_HW_USB_PORTS | CFG_HW_HAS_PCI_SLOT)))
+               pci_common_init(&gmlr_hw_pci);
+       return 0;
+}
+
+subsys_initcall(gmlr_pci_init);
+#endif /* CONFIG_PCI */
+
+
+MACHINE_START(GORAMO_MLR, "MultiLink")
+       /* Maintainer: Krzysztof Halasa */
+       .phys_io        = IXP4XX_PERIPHERAL_BASE_PHYS,
+       .io_pg_offst    = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC,
+       .map_io         = ixp4xx_map_io,
+       .init_irq       = ixp4xx_init_irq,
+       .timer          = &ixp4xx_timer,
+       .boot_params    = 0x0100,
+       .init_machine   = gmlr_init,
+MACHINE_END
index def7773be67cc222ecd28e9aa1ad7db795eb1b5b..b2ef65db0e914c7f5137f5df0d8e035c3f91551a 100644 (file)
@@ -26,6 +26,8 @@
 #define IXP46X_PROCESSOR_ID_VALUE      0x69054200 /* including IXP455 */
 #define IXP46X_PROCESSOR_ID_MASK       0xfffffff0
 
+#define cpu_is_ixp42x_rev_a0() ((read_cpuid_id() & (IXP42X_PROCESSOR_ID_MASK | 0xF)) == \
+                               IXP42X_PROCESSOR_ID_VALUE)
 #define cpu_is_ixp42x()        ((read_cpuid_id() & IXP42X_PROCESSOR_ID_MASK) == \
                         IXP42X_PROCESSOR_ID_VALUE)
 #define cpu_is_ixp43x()        ((read_cpuid_id() & IXP43X_PROCESSOR_ID_MASK) == \
 
 static inline u32 ixp4xx_read_feature_bits(void)
 {
-       unsigned int val = ~*IXP4XX_EXP_CFG2;
+       u32 val = ~*IXP4XX_EXP_CFG2;
 
+       if (cpu_is_ixp42x_rev_a0())
+               return IXP42X_FEATURE_MASK & ~(IXP4XX_FEATURE_RCOMP |
+                                              IXP4XX_FEATURE_AES);
        if (cpu_is_ixp42x())
                return val & IXP42X_FEATURE_MASK;
        if (cpu_is_ixp43x())
index 0cbe6ceb67c5a012837221f8e9a95509689dea94..9e7cad2d54cb9e9add09c676378e7956b6d70b71 100644 (file)
@@ -15,7 +15,7 @@
 #define DEBUG_QMGR     0
 
 #define HALF_QUEUES    32
-#define QUEUES         64      /* only 32 lower queues currently supported */
+#define QUEUES         64
 #define MAX_QUEUE_LENGTH 4     /* in dwords */
 
 #define QUEUE_STAT1_EMPTY              1 /* queue status bits */
@@ -110,48 +110,95 @@ static inline u32 qmgr_get_entry(unsigned int queue)
        return val;
 }
 
-static inline int qmgr_get_stat1(unsigned int queue)
+static inline int __qmgr_get_stat1(unsigned int queue)
 {
        extern struct qmgr_regs __iomem *qmgr_regs;
        return (__raw_readl(&qmgr_regs->stat1[queue >> 3])
                >> ((queue & 7) << 2)) & 0xF;
 }
 
-static inline int qmgr_get_stat2(unsigned int queue)
+static inline int __qmgr_get_stat2(unsigned int queue)
 {
        extern struct qmgr_regs __iomem *qmgr_regs;
+       BUG_ON(queue >= HALF_QUEUES);
        return (__raw_readl(&qmgr_regs->stat2[queue >> 4])
                >> ((queue & 0xF) << 1)) & 0x3;
 }
 
+/**
+ * qmgr_stat_empty() - checks if a hardware queue is empty
+ * @queue:     queue number
+ *
+ * Returns non-zero value if the queue is empty.
+ */
 static inline int qmgr_stat_empty(unsigned int queue)
 {
-       return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_EMPTY);
+       BUG_ON(queue >= HALF_QUEUES);
+       return __qmgr_get_stat1(queue) & QUEUE_STAT1_EMPTY;
 }
 
-static inline int qmgr_stat_nearly_empty(unsigned int queue)
+/**
+ * qmgr_stat_below_low_watermark() - checks if a queue is below low watermark
+ * @queue:     queue number
+ *
+ * Returns non-zero value if the queue is below low watermark.
+ */
+static inline int qmgr_stat_below_low_watermark(unsigned int queue)
 {
-       return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_EMPTY);
+       extern struct qmgr_regs __iomem *qmgr_regs;
+       if (queue >= HALF_QUEUES)
+               return (__raw_readl(&qmgr_regs->statne_h) >>
+                       (queue - HALF_QUEUES)) & 0x01;
+       return __qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_EMPTY;
 }
 
-static inline int qmgr_stat_nearly_full(unsigned int queue)
+/**
+ * qmgr_stat_above_high_watermark() - checks if a queue is above high watermark
+ * @queue:     queue number
+ *
+ * Returns non-zero value if the queue is above high watermark
+ */
+static inline int qmgr_stat_above_high_watermark(unsigned int queue)
 {
-       return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_FULL);
+       BUG_ON(queue >= HALF_QUEUES);
+       return __qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_FULL;
 }
 
+/**
+ * qmgr_stat_full() - checks if a hardware queue is full
+ * @queue:     queue number
+ *
+ * Returns non-zero value if the queue is full.
+ */
 static inline int qmgr_stat_full(unsigned int queue)
 {
-       return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_FULL);
+       extern struct qmgr_regs __iomem *qmgr_regs;
+       if (queue >= HALF_QUEUES)
+               return (__raw_readl(&qmgr_regs->statf_h) >>
+                       (queue - HALF_QUEUES)) & 0x01;
+       return __qmgr_get_stat1(queue) & QUEUE_STAT1_FULL;
 }
 
+/**
+ * qmgr_stat_underflow() - checks if a hardware queue experienced underflow
+ * @queue:     queue number
+ *
+ * Returns non-zero value if the queue experienced underflow.
+ */
 static inline int qmgr_stat_underflow(unsigned int queue)
 {
-       return !!(qmgr_get_stat2(queue) & QUEUE_STAT2_UNDERFLOW);
+       return __qmgr_get_stat2(queue) & QUEUE_STAT2_UNDERFLOW;
 }
 
+/**
+ * qmgr_stat_overflow() - checks if a hardware queue experienced overflow
+ * @queue:     queue number
+ *
+ * Returns non-zero value if the queue experienced overflow.
+ */
 static inline int qmgr_stat_overflow(unsigned int queue)
 {
-       return !!(qmgr_get_stat2(queue) & QUEUE_STAT2_OVERFLOW);
+       return __qmgr_get_stat2(queue) & QUEUE_STAT2_OVERFLOW;
 }
 
 #endif
index 7bb8e778e4b6eecc286368c90dda2dce0a3d421d..47ac69c7ec7891a6bbbd07765fa264210746df35 100644 (file)
@@ -386,15 +386,6 @@ static int npe_reset(struct npe *npe)
        /* reset the NPE */
        ixp4xx_write_feature_bits(val &
                                  ~(IXP4XX_FEATURE_RESET_NPEA << npe->id));
-       for (i = 0; i < MAX_RETRIES; i++) {
-               if (!(ixp4xx_read_feature_bits() &
-                     (IXP4XX_FEATURE_RESET_NPEA << npe->id)))
-                       break;  /* reset completed */
-               udelay(1);
-       }
-       if (i == MAX_RETRIES)
-               return -ETIMEDOUT;
-
        /* deassert reset */
        ixp4xx_write_feature_bits(val |
                                  (IXP4XX_FEATURE_RESET_NPEA << npe->id));
index bfddc73d0a200b358b80761891106e5237b22799..bfdbe4b5a3cc860eb4bc96c6a1714a6bae6cb7ff 100644 (file)
@@ -18,8 +18,8 @@ struct qmgr_regs __iomem *qmgr_regs;
 static struct resource *mem_res;
 static spinlock_t qmgr_lock;
 static u32 used_sram_bitmap[4]; /* 128 16-dword pages */
-static void (*irq_handlers[HALF_QUEUES])(void *pdev);
-static void *irq_pdevs[HALF_QUEUES];
+static void (*irq_handlers[QUEUES])(void *pdev);
+static void *irq_pdevs[QUEUES];
 
 #if DEBUG_QMGR
 char qmgr_queue_descs[QUEUES][32];
@@ -28,51 +28,112 @@ char qmgr_queue_descs[QUEUES][32];
 void qmgr_set_irq(unsigned int queue, int src,
                  void (*handler)(void *pdev), void *pdev)
 {
-       u32 __iomem *reg = &qmgr_regs->irqsrc[queue / 8]; /* 8 queues / u32 */
-       int bit = (queue % 8) * 4; /* 3 bits + 1 reserved bit per queue */
        unsigned long flags;
 
-       src &= 7;
        spin_lock_irqsave(&qmgr_lock, flags);
-       __raw_writel((__raw_readl(reg) & ~(7 << bit)) | (src << bit), reg);
+       if (queue < HALF_QUEUES) {
+               u32 __iomem *reg;
+               int bit;
+               BUG_ON(src > QUEUE_IRQ_SRC_NOT_FULL);
+               reg = &qmgr_regs->irqsrc[queue >> 3]; /* 8 queues per u32 */
+               bit = (queue % 8) * 4; /* 3 bits + 1 reserved bit per queue */
+               __raw_writel((__raw_readl(reg) & ~(7 << bit)) | (src << bit),
+                            reg);
+       } else
+               /* IRQ source for queues 32-63 is fixed */
+               BUG_ON(src != QUEUE_IRQ_SRC_NOT_NEARLY_EMPTY);
+
        irq_handlers[queue] = handler;
        irq_pdevs[queue] = pdev;
        spin_unlock_irqrestore(&qmgr_lock, flags);
 }
 
 
-static irqreturn_t qmgr_irq1(int irq, void *pdev)
+static irqreturn_t qmgr_irq1_a0(int irq, void *pdev)
 {
-       int i;
-       u32 val = __raw_readl(&qmgr_regs->irqstat[0]);
-       __raw_writel(val, &qmgr_regs->irqstat[0]); /* ACK */
-
-       for (i = 0; i < HALF_QUEUES; i++)
-               if (val & (1 << i))
+       int i, ret = 0;
+       u32 en_bitmap, src, stat;
+
+       /* ACK - it may clear any bits so don't rely on it */
+       __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[0]);
+
+       en_bitmap = qmgr_regs->irqen[0];
+       while (en_bitmap) {
+               i = __fls(en_bitmap); /* number of the last "low" queue */
+               en_bitmap &= ~BIT(i);
+               src = qmgr_regs->irqsrc[i >> 3];
+               stat = qmgr_regs->stat1[i >> 3];
+               if (src & 4) /* the IRQ condition is inverted */
+                       stat = ~stat;
+               if (stat & BIT(src & 3)) {
                        irq_handlers[i](irq_pdevs[i]);
+                       ret = IRQ_HANDLED;
+               }
+       }
+       return ret;
+}
+
+
+static irqreturn_t qmgr_irq2_a0(int irq, void *pdev)
+{
+       int i, ret = 0;
+       u32 req_bitmap;
+
+       /* ACK - it may clear any bits so don't rely on it */
+       __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[1]);
+
+       req_bitmap = qmgr_regs->irqen[1] & qmgr_regs->statne_h;
+       while (req_bitmap) {
+               i = __fls(req_bitmap); /* number of the last "high" queue */
+               req_bitmap &= ~BIT(i);
+               irq_handlers[HALF_QUEUES + i](irq_pdevs[HALF_QUEUES + i]);
+               ret = IRQ_HANDLED;
+       }
+       return ret;
+}
 
-       return val ? IRQ_HANDLED : 0;
+
+static irqreturn_t qmgr_irq(int irq, void *pdev)
+{
+       int i, half = (irq == IRQ_IXP4XX_QM1 ? 0 : 1);
+       u32 req_bitmap = __raw_readl(&qmgr_regs->irqstat[half]);
+
+       if (!req_bitmap)
+               return 0;
+       __raw_writel(req_bitmap, &qmgr_regs->irqstat[half]); /* ACK */
+
+       while (req_bitmap) {
+               i = __fls(req_bitmap); /* number of the last queue */
+               req_bitmap &= ~BIT(i);
+               i += half * HALF_QUEUES;
+               irq_handlers[i](irq_pdevs[i]);
+       }
+       return IRQ_HANDLED;
 }
 
 
 void qmgr_enable_irq(unsigned int queue)
 {
        unsigned long flags;
+       int half = queue / 32;
+       u32 mask = 1 << (queue & (HALF_QUEUES - 1));
 
        spin_lock_irqsave(&qmgr_lock, flags);
-       __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) | (1 << queue),
-                    &qmgr_regs->irqen[0]);
+       __raw_writel(__raw_readl(&qmgr_regs->irqen[half]) | mask,
+                    &qmgr_regs->irqen[half]);
        spin_unlock_irqrestore(&qmgr_lock, flags);
 }
 
 void qmgr_disable_irq(unsigned int queue)
 {
        unsigned long flags;
+       int half = queue / 32;
+       u32 mask = 1 << (queue & (HALF_QUEUES - 1));
 
        spin_lock_irqsave(&qmgr_lock, flags);
-       __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) & ~(1 << queue),
-                    &qmgr_regs->irqen[0]);
-       __raw_writel(1 << queue, &qmgr_regs->irqstat[0]); /* clear */
+       __raw_writel(__raw_readl(&qmgr_regs->irqen[half]) & ~mask,
+                    &qmgr_regs->irqen[half]);
+       __raw_writel(mask, &qmgr_regs->irqstat[half]); /* clear */
        spin_unlock_irqrestore(&qmgr_lock, flags);
 }
 
@@ -98,8 +159,7 @@ int __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
        u32 cfg, addr = 0, mask[4]; /* in 16-dwords */
        int err;
 
-       if (queue >= HALF_QUEUES)
-               return -ERANGE;
+       BUG_ON(queue >= QUEUES);
 
        if ((nearly_empty_watermark | nearly_full_watermark) & ~7)
                return -EINVAL;
@@ -180,7 +240,7 @@ void qmgr_release_queue(unsigned int queue)
 {
        u32 cfg, addr, mask[4];
 
-       BUG_ON(queue >= HALF_QUEUES); /* not in valid range */
+       BUG_ON(queue >= QUEUES); /* not in valid range */
 
        spin_lock_irq(&qmgr_lock);
        cfg = __raw_readl(&qmgr_regs->sram[queue]);
@@ -224,6 +284,8 @@ void qmgr_release_queue(unsigned int queue)
 static int qmgr_init(void)
 {
        int i, err;
+       irq_handler_t handler1, handler2;
+
        mem_res = request_mem_region(IXP4XX_QMGR_BASE_PHYS,
                                     IXP4XX_QMGR_REGION_SIZE,
                                     "IXP4xx Queue Manager");
@@ -247,23 +309,42 @@ static int qmgr_init(void)
                __raw_writel(0, &qmgr_regs->irqen[i]);
        }
 
+       __raw_writel(0xFFFFFFFF, &qmgr_regs->statne_h);
+       __raw_writel(0, &qmgr_regs->statf_h);
+
        for (i = 0; i < QUEUES; i++)
                __raw_writel(0, &qmgr_regs->sram[i]);
 
-       err = request_irq(IRQ_IXP4XX_QM1, qmgr_irq1, 0,
-                         "IXP4xx Queue Manager", NULL);
+       if (cpu_is_ixp42x_rev_a0()) {
+               handler1 = qmgr_irq1_a0;
+               handler2 = qmgr_irq2_a0;
+       } else
+               handler1 = handler2 = qmgr_irq;
+
+       err = request_irq(IRQ_IXP4XX_QM1, handler1, 0, "IXP4xx Queue Manager",
+                         NULL);
        if (err) {
-               printk(KERN_ERR "qmgr: failed to request IRQ%i\n",
-                      IRQ_IXP4XX_QM1);
+               printk(KERN_ERR "qmgr: failed to request IRQ%i (%i)\n",
+                      IRQ_IXP4XX_QM1, err);
                goto error_irq;
        }
 
+       err = request_irq(IRQ_IXP4XX_QM2, handler2, 0, "IXP4xx Queue Manager",
+                         NULL);
+       if (err) {
+               printk(KERN_ERR "qmgr: failed to request IRQ%i (%i)\n",
+                      IRQ_IXP4XX_QM2, err);
+               goto error_irq2;
+       }
+
        used_sram_bitmap[0] = 0xF; /* 4 first pages reserved for config */
        spin_lock_init(&qmgr_lock);
 
        printk(KERN_INFO "IXP4xx Queue Manager initialized.\n");
        return 0;
 
+error_irq2:
+       free_irq(IRQ_IXP4XX_QM1, NULL);
 error_irq:
        iounmap(qmgr_regs);
 error_map:
@@ -274,7 +355,9 @@ error_map:
 static void qmgr_remove(void)
 {
        free_irq(IRQ_IXP4XX_QM1, NULL);
+       free_irq(IRQ_IXP4XX_QM2, NULL);
        synchronize_irq(IRQ_IXP4XX_QM1);
+       synchronize_irq(IRQ_IXP4XX_QM2);
        iounmap(qmgr_regs);
        release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE);
 }
index b5421cccd7e18508e76886e23e8df314b49cd360..25100f7acf4c4483a632a69ba3d5092cdd305ae6 100644 (file)
@@ -20,6 +20,12 @@ config MACH_RD88F6281
          Say 'Y' here if you want your kernel to support the
          Marvell RD-88F6281 Reference Board.
 
+config MACH_MV88F6281GTW_GE
+       bool "Marvell 88F6281 GTW GE Board"
+       help
+         Say 'Y' here if you want your kernel to support the
+         Marvell 88F6281 GTW GE Board.
+
 config MACH_SHEEVAPLUG
        bool "Marvell SheevaPlug Reference Board"
        help
index 8f03c9b9bdd99d9ff74a3c5365272601d381f018..9dd680e964d6a6d89814344cd8cea23f9186371a 100644 (file)
@@ -3,5 +3,8 @@ obj-y                           += common.o addr-map.o irq.o pcie.o mpp.o
 obj-$(CONFIG_MACH_DB88F6281_BP)                += db88f6281-bp-setup.o
 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_CPU_IDLE)                 += cpuidle.o
index 5db4f0bbe5ee2c020320b4ef4bf09826e2d1521e..1da5d1c18ecbbcb4bc5488bc60cea453c0f04d6b 100644 (file)
@@ -20,6 +20,7 @@
  */
 #define TARGET_DDR             0
 #define TARGET_DEV_BUS         1
+#define TARGET_SRAM            3
 #define TARGET_PCIE            4
 #define ATTR_DEV_SPI_ROM       0x1e
 #define ATTR_DEV_BOOT          0x1d
@@ -30,6 +31,7 @@
 #define ATTR_DEV_CS0           0x3e
 #define ATTR_PCIE_IO           0xe0
 #define ATTR_PCIE_MEM          0xe8
+#define ATTR_SRAM              0x01
 
 /*
  * Helpers to get DDR bank info
@@ -48,7 +50,6 @@
 
 
 struct mbus_dram_target_info kirkwood_mbus_dram_info;
-static int __initdata win_alloc_count;
 
 static int __init cpu_win_can_remap(int win)
 {
@@ -112,7 +113,11 @@ void __init kirkwood_setup_cpu_mbus(void)
        setup_cpu_win(2, KIRKWOOD_NAND_MEM_PHYS_BASE, KIRKWOOD_NAND_MEM_SIZE,
                      TARGET_DEV_BUS, ATTR_DEV_NAND, -1);
 
-       win_alloc_count = 3;
+       /*
+        * Setup window for SRAM.
+        */
+       setup_cpu_win(3, KIRKWOOD_SRAM_PHYS_BASE, KIRKWOOD_SRAM_SIZE,
+                     TARGET_SRAM, ATTR_SRAM, -1);
 
        /*
         * Setup MBUS dram target info.
@@ -140,8 +145,3 @@ void __init kirkwood_setup_cpu_mbus(void)
        }
        kirkwood_mbus_dram_info.num_cs = cs;
 }
-
-void __init kirkwood_setup_sram_win(u32 base, u32 size)
-{
-       setup_cpu_win(win_alloc_count++, base, size, 0x03, 0x00, -1);
-}
index be1ca28fed3fb9eceb03394338eaaf5166821a06..0f6919838011cf2d6e8712f173ea1ef4064506ba 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/mv643xx_eth.h>
 #include <linux/mv643xx_i2c.h>
 #include <linux/ata_platform.h>
+#include <linux/mtd/nand.h>
 #include <linux/spi/orion_spi.h>
 #include <net/dsa.h>
 #include <asm/page.h>
@@ -29,6 +30,7 @@
 #include <plat/mvsdio.h>
 #include <plat/mv_xor.h>
 #include <plat/orion_nand.h>
+#include <plat/orion_wdt.h>
 #include <plat/time.h>
 #include "common.h"
 
@@ -54,6 +56,13 @@ void __init kirkwood_map_io(void)
        iotable_init(kirkwood_io_desc, ARRAY_SIZE(kirkwood_io_desc));
 }
 
+/*
+ * Default clock control bits.  Any bit _not_ set in this variable
+ * will be cleared from the hardware after platform devices have been
+ * registered.  Some reserved bits must be set to 1.
+ */
+unsigned int kirkwood_clk_ctrl = CGC_DUNIT | CGC_RESERVED;
+       
 
 /*****************************************************************************
  * EHCI
@@ -95,6 +104,7 @@ static struct platform_device kirkwood_ehci = {
 
 void __init kirkwood_ehci_init(void)
 {
+       kirkwood_clk_ctrl |= CGC_USB0;
        platform_device_register(&kirkwood_ehci);
 }
 
@@ -151,6 +161,7 @@ static struct platform_device kirkwood_ge00 = {
 
 void __init kirkwood_ge00_init(struct mv643xx_eth_platform_data *eth_data)
 {
+       kirkwood_clk_ctrl |= CGC_GE0;
        eth_data->shared = &kirkwood_ge00_shared;
        kirkwood_ge00.dev.platform_data = eth_data;
 
@@ -212,6 +223,7 @@ static struct platform_device kirkwood_ge01 = {
 
 void __init kirkwood_ge01_init(struct mv643xx_eth_platform_data *eth_data)
 {
+       kirkwood_clk_ctrl |= CGC_GE1;
        eth_data->shared = &kirkwood_ge01_shared;
        kirkwood_ge01.dev.platform_data = eth_data;
 
@@ -257,6 +269,43 @@ void __init kirkwood_ge00_switch_init(struct dsa_platform_data *d, int irq)
 }
 
 
+/*****************************************************************************
+ * NAND flash
+ ****************************************************************************/
+static struct resource kirkwood_nand_resource = {
+       .flags          = IORESOURCE_MEM,
+       .start          = KIRKWOOD_NAND_MEM_PHYS_BASE,
+       .end            = KIRKWOOD_NAND_MEM_PHYS_BASE +
+                               KIRKWOOD_NAND_MEM_SIZE - 1,
+};
+
+static struct orion_nand_data kirkwood_nand_data = {
+       .cle            = 0,
+       .ale            = 1,
+       .width          = 8,
+};
+
+static struct platform_device kirkwood_nand_flash = {
+       .name           = "orion_nand",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &kirkwood_nand_data,
+       },
+       .resource       = &kirkwood_nand_resource,
+       .num_resources  = 1,
+};
+
+void __init kirkwood_nand_init(struct mtd_partition *parts, int nr_parts,
+                              int chip_delay)
+{
+       kirkwood_clk_ctrl |= CGC_RUNIT;
+       kirkwood_nand_data.parts = parts;
+       kirkwood_nand_data.nr_parts = nr_parts;
+       kirkwood_nand_data.chip_delay = chip_delay;
+       platform_device_register(&kirkwood_nand_flash);
+}
+
+
 /*****************************************************************************
  * SoC RTC
  ****************************************************************************/
@@ -301,6 +350,9 @@ static struct platform_device kirkwood_sata = {
 
 void __init kirkwood_sata_init(struct mv_sata_platform_data *sata_data)
 {
+       kirkwood_clk_ctrl |= CGC_SATA0;
+       if (sata_data->n_ports > 1)
+               kirkwood_clk_ctrl |= CGC_SATA1;
        sata_data->dram = &kirkwood_mbus_dram_info;
        kirkwood_sata.dev.platform_data = sata_data;
        platform_device_register(&kirkwood_sata);
@@ -346,6 +398,7 @@ void __init kirkwood_sdio_init(struct mvsdio_platform_data *mvsdio_data)
        else
                mvsdio_data->clock = 200000000;
        mvsdio_data->dram = &kirkwood_mbus_dram_info;
+       kirkwood_clk_ctrl |= CGC_SDIO;
        kirkwood_sdio.dev.platform_data = mvsdio_data;
        platform_device_register(&kirkwood_sdio);
 }
@@ -377,6 +430,7 @@ static struct platform_device kirkwood_spi = {
 
 void __init kirkwood_spi_init()
 {
+       kirkwood_clk_ctrl |= CGC_RUNIT;
        platform_device_register(&kirkwood_spi);
 }
 
@@ -506,6 +560,43 @@ void __init kirkwood_uart1_init(void)
 }
 
 
+/*****************************************************************************
+ * Cryptographic Engines and Security Accelerator (CESA)
+ ****************************************************************************/
+
+static struct resource kirkwood_crypto_res[] = {
+       {
+               .name   = "regs",
+               .start  = CRYPTO_PHYS_BASE,
+               .end    = CRYPTO_PHYS_BASE + 0xffff,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .name   = "sram",
+               .start  = KIRKWOOD_SRAM_PHYS_BASE,
+               .end    = KIRKWOOD_SRAM_PHYS_BASE + KIRKWOOD_SRAM_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .name   = "crypto interrupt",
+               .start  = IRQ_KIRKWOOD_CRYPTO,
+               .end    = IRQ_KIRKWOOD_CRYPTO,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device kirkwood_crypto_device = {
+       .name           = "mv_crypto",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(kirkwood_crypto_res),
+       .resource       = kirkwood_crypto_res,
+};
+
+void __init kirkwood_crypto_init(void)
+{
+       kirkwood_clk_ctrl |= CGC_CRYPTO;
+       platform_device_register(&kirkwood_crypto_device);
+}
+
+
 /*****************************************************************************
  * XOR
  ****************************************************************************/
@@ -597,6 +688,7 @@ static struct platform_device kirkwood_xor01_channel = {
 
 static void __init kirkwood_xor0_init(void)
 {
+       kirkwood_clk_ctrl |= CGC_XOR0;
        platform_device_register(&kirkwood_xor0_shared);
 
        /*
@@ -695,6 +787,7 @@ static struct platform_device kirkwood_xor11_channel = {
 
 static void __init kirkwood_xor1_init(void)
 {
+       kirkwood_clk_ctrl |= CGC_XOR1;
        platform_device_register(&kirkwood_xor1_shared);
 
        /*
@@ -712,6 +805,29 @@ static void __init kirkwood_xor1_init(void)
 }
 
 
+/*****************************************************************************
+ * Watchdog
+ ****************************************************************************/
+static struct orion_wdt_platform_data kirkwood_wdt_data = {
+       .tclk           = 0,
+};
+
+static struct platform_device kirkwood_wdt_device = {
+       .name           = "orion_wdt",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &kirkwood_wdt_data,
+       },
+       .num_resources  = 0,
+};
+
+static void __init kirkwood_wdt_init(void)
+{
+       kirkwood_wdt_data.tclk = kirkwood_tclk;
+       platform_device_register(&kirkwood_wdt_device);
+}
+
+
 /*****************************************************************************
  * Time handling
  ****************************************************************************/
@@ -804,6 +920,49 @@ void __init kirkwood_init(void)
 
        /* internal devices that every board has */
        kirkwood_rtc_init();
+       kirkwood_wdt_init();
        kirkwood_xor0_init();
        kirkwood_xor1_init();
+       kirkwood_crypto_init();
+}
+
+static int __init kirkwood_clock_gate(void)
+{
+       unsigned int curr = readl(CLOCK_GATING_CTRL);
+
+       printk(KERN_DEBUG "Gating clock of unused units\n");
+       printk(KERN_DEBUG "before: 0x%08x\n", curr);
+
+       /* Make sure those units are accessible */
+       writel(curr | CGC_SATA0 | CGC_SATA1 | CGC_PEX0, CLOCK_GATING_CTRL);
+
+       /* For SATA: first shutdown the phy */
+       if (!(kirkwood_clk_ctrl & CGC_SATA0)) {
+               /* Disable PLL and IVREF */
+               writel(readl(SATA0_PHY_MODE_2) & ~0xf, SATA0_PHY_MODE_2);
+               /* Disable PHY */
+               writel(readl(SATA0_IF_CTRL) | 0x200, SATA0_IF_CTRL);
+       }
+       if (!(kirkwood_clk_ctrl & CGC_SATA1)) {
+               /* Disable PLL and IVREF */
+               writel(readl(SATA1_PHY_MODE_2) & ~0xf, SATA1_PHY_MODE_2);
+               /* Disable PHY */
+               writel(readl(SATA1_IF_CTRL) | 0x200, SATA1_IF_CTRL);
+       }
+       
+       /* For PCIe: first shutdown the phy */
+       if (!(kirkwood_clk_ctrl & CGC_PEX0)) {
+               writel(readl(PCIE_LINK_CTRL) | 0x10, PCIE_LINK_CTRL);
+               while (1)
+                       if (readl(PCIE_STATUS) & 0x1)
+                               break;
+               writel(readl(PCIE_LINK_CTRL) & ~0x10, PCIE_LINK_CTRL);
+       }
+
+       /* Now gate clock the required units */
+       writel(kirkwood_clk_ctrl, CLOCK_GATING_CTRL);
+       printk(KERN_DEBUG " after: 0x%08x\n", readl(CLOCK_GATING_CTRL));
+
+       return 0;
 }
+late_initcall(kirkwood_clock_gate);
index 6ee88406f381a4f76771501433b694b16d740d27..d7de43464358de708078d1650422ecd044045ee0 100644 (file)
@@ -15,6 +15,7 @@ struct dsa_platform_data;
 struct mv643xx_eth_platform_data;
 struct mv_sata_platform_data;
 struct mvsdio_platform_data;
+struct mtd_partition;
 
 /*
  * Basic Kirkwood init functions used early by machine-setup.
@@ -25,7 +26,6 @@ void kirkwood_init_irq(void);
 
 extern struct mbus_dram_target_info kirkwood_mbus_dram_info;
 void kirkwood_setup_cpu_mbus(void);
-void kirkwood_setup_sram_win(u32 base, u32 size);
 
 void kirkwood_pcie_id(u32 *dev, u32 *rev);
 
@@ -40,9 +40,11 @@ void kirkwood_spi_init(void);
 void kirkwood_i2c_init(void);
 void kirkwood_uart0_init(void);
 void kirkwood_uart1_init(void);
+void kirkwood_nand_init(struct mtd_partition *parts, int nr_parts, int delay);
 
 extern int kirkwood_tclk;
 extern struct sys_timer kirkwood_timer;
 
+#define ARRAY_AND_SIZE(x)      (x), ARRAY_SIZE(x)
 
 #endif
diff --git a/arch/arm/mach-kirkwood/cpuidle.c b/arch/arm/mach-kirkwood/cpuidle.c
new file mode 100644 (file)
index 0000000..f68d33f
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * arch/arm/mach-kirkwood/cpuidle.c
+ *
+ * CPU idle Marvell Kirkwood SoCs
+ *
+ * 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 DDR self refresh in order
+ * to implement two idle states -
+ * #1 wait-for-interrupt
+ * #2 wait-for-interrupt and DDR self refresh
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/cpuidle.h>
+#include <linux/io.h>
+#include <asm/proc-fns.h>
+#include <mach/kirkwood.h>
+
+#define KIRKWOOD_MAX_STATES    2
+
+static struct cpuidle_driver kirkwood_idle_driver = {
+       .name =         "kirkwood_idle",
+       .owner =        THIS_MODULE,
+};
+
+static DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device);
+
+/* Actual code that puts the SoC in different idle states */
+static int kirkwood_enter_idle(struct cpuidle_device *dev,
+                              struct cpuidle_state *state)
+{
+       struct timeval before, after;
+       int idle_time;
+
+       local_irq_disable();
+       do_gettimeofday(&before);
+       if (state == &dev->states[0])
+               /* Wait for interrupt state */
+               cpu_do_idle();
+       else if (state == &dev->states[1]) {
+               /*
+                * Following write will put DDR in self refresh.
+                * Note that we have 256 cycles before DDR puts it
+                * self in self-refresh, so the wait-for-interrupt
+                * call afterwards won't get the DDR from self refresh
+                * mode.
+                */
+               writel(0x7, DDR_OPERATION_BASE);
+               cpu_do_idle();
+       }
+       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 kirkwood_init_cpuidle(void)
+{
+       struct cpuidle_device *device;
+
+       cpuidle_register_driver(&kirkwood_idle_driver);
+
+       device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id());
+       device->state_count = KIRKWOOD_MAX_STATES;
+
+       /* Wait for interrupt state */
+       device->states[0].enter = kirkwood_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 DDR self refresh state */
+       device->states[1].enter = kirkwood_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, "DDR SR");
+       strcpy(device->states[1].desc, "WFI and DDR Self Refresh");
+
+       if (cpuidle_register_device(device)) {
+               printk(KERN_ERR "kirkwood_init_cpuidle: Failed registering\n");
+               return -EIO;
+       }
+       return 0;
+}
+
+device_initcall(kirkwood_init_cpuidle);
index 5505d58377524d6c45ed8a42fbe9794d90215a53..39bdf4bcace959322cc966d613cc976007dbe020 100644 (file)
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/ata_platform.h>
 #include <linux/mv643xx_eth.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <mach/kirkwood.h>
-#include <plat/orion_nand.h>
 #include <plat/mvsdio.h>
 #include "common.h"
 #include "mpp.h"
@@ -39,32 +37,6 @@ static struct mtd_partition db88f6281_nand_parts[] = {
        },
 };
 
-static struct resource db88f6281_nand_resource = {
-       .flags          = IORESOURCE_MEM,
-       .start          = KIRKWOOD_NAND_MEM_PHYS_BASE,
-       .end            = KIRKWOOD_NAND_MEM_PHYS_BASE +
-                         KIRKWOOD_NAND_MEM_SIZE - 1,
-};
-
-static struct orion_nand_data db88f6281_nand_data = {
-       .parts          = db88f6281_nand_parts,
-       .nr_parts       = ARRAY_SIZE(db88f6281_nand_parts),
-       .cle            = 0,
-       .ale            = 1,
-       .width          = 8,
-       .chip_delay     = 25,
-};
-
-static struct platform_device db88f6281_nand_flash = {
-       .name           = "orion_nand",
-       .id             = -1,
-       .dev            = {
-               .platform_data  = &db88f6281_nand_data,
-       },
-       .resource       = &db88f6281_nand_resource,
-       .num_resources  = 1,
-};
-
 static struct mv643xx_eth_platform_data db88f6281_ge00_data = {
        .phy_addr       = MV643XX_ETH_PHY_ADDR(8),
 };
@@ -92,13 +64,12 @@ static void __init db88f6281_init(void)
        kirkwood_init();
        kirkwood_mpp_conf(db88f6281_mpp_config);
 
+       kirkwood_nand_init(ARRAY_AND_SIZE(db88f6281_nand_parts), 25);
        kirkwood_ehci_init();
        kirkwood_ge00_init(&db88f6281_ge00_data);
        kirkwood_sata_init(&db88f6281_sata_data);
        kirkwood_uart0_init();
        kirkwood_sdio_init(&db88f6281_mvsdio_data);
-       
-       platform_device_register(&db88f6281_nand_flash);
 }
 
 static int __init db88f6281_pci_init(void)
index 4f7029f521cc8027205e6cef90a58eb6a0c3e7d2..9e80d9232c831e315783509b71a837de115b92b9 100644 (file)
 #define CPU_RESET              0x00000002
 
 #define RSTOUTn_MASK           (BRIDGE_VIRT_BASE | 0x0108)
+#define WDT_RESET_OUT_EN       0x00000002
 #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 WDT_INT_REQ            0x0008
+
 #define BRIDGE_MASK            (BRIDGE_VIRT_BASE | 0x0114)
 #define BRIDGE_INT_TIMER0      0x0002
 #define BRIDGE_INT_TIMER1      0x0004
 #define L2_CONFIG_REG          (BRIDGE_VIRT_BASE | 0x0128)
 #define L2_WRITETHROUGH                0x00000010
 
+#define CLOCK_GATING_CTRL      (BRIDGE_VIRT_BASE | 0x11c)
+#define CGC_GE0                        (1 << 0)
+#define CGC_PEX0               (1 << 2)
+#define CGC_USB0               (1 << 3)
+#define CGC_SDIO               (1 << 4)
+#define CGC_TSU                        (1 << 5)
+#define CGC_DUNIT              (1 << 6)
+#define CGC_RUNIT              (1 << 7)
+#define CGC_XOR0               (1 << 8)
+#define CGC_AUDIO              (1 << 9)
+#define CGC_SATA0              (1 << 14)
+#define CGC_SATA1              (1 << 15)
+#define CGC_XOR1               (1 << 16)
+#define CGC_CRYPTO             (1 << 17)
+#define CGC_GE1                        (1 << 19)
+#define CGC_TDM                        (1 << 20)
+#define CGC_RESERVED           ((1 << 18) | (0x6 << 21))
+
 #endif
index be07be0ef5224e829799e61faaad975949f88c5d..a643a846d5fb3252a368c3e3a2d7c2d50f817233 100644 (file)
@@ -19,6 +19,31 @@ static inline void __iomem *__io(unsigned long addr)
                                        + KIRKWOOD_PCIE_IO_VIRT_BASE);
 }
 
+static inline void __iomem *
+__arch_ioremap(unsigned long paddr, size_t size, unsigned int mtype)
+{
+       void __iomem *retval;
+       unsigned long offs = paddr - KIRKWOOD_REGS_PHYS_BASE;
+       if (mtype == MT_DEVICE && size && offs < KIRKWOOD_REGS_SIZE &&
+           size <= KIRKWOOD_REGS_SIZE && offs + size <= KIRKWOOD_REGS_SIZE) {
+               retval = (void __iomem *)KIRKWOOD_REGS_VIRT_BASE + offs;
+       } else {
+               retval = __arm_ioremap(paddr, size, mtype);
+       }
+
+       return retval;
+}
+
+static inline void
+__arch_iounmap(void __iomem *addr)
+{
+       if (addr < (void __iomem *)KIRKWOOD_REGS_VIRT_BASE ||
+           addr >= (void __iomem *)(KIRKWOOD_REGS_VIRT_BASE + KIRKWOOD_REGS_SIZE))
+               __iounmap(addr);
+}
+
+#define __arch_ioremap(p, s, m)        __arch_ioremap(p, s, m)
+#define __arch_iounmap(a)      __arch_iounmap(a)
 #define __io(a)                        __io(a)
 #define __mem_pci(a)           (a)
 
index b3e13958821dc7d275b8d36e6fea7e37852e6d06..07af858814a0dc418b0d50e68293d1d82ca2d4b9 100644 (file)
  * f1000000    on-chip peripheral registers
  * f2000000    PCIe I/O space
  * f3000000    NAND controller address window
+ * f4000000    Security Accelerator SRAM
  *
  * virt                phys            size
  * fee00000    f1000000        1M      on-chip peripheral registers
  * fef00000    f2000000        1M      PCIe I/O space
  */
 
+#define KIRKWOOD_SRAM_PHYS_BASE                0xf4000000
+#define KIRKWOOD_SRAM_SIZE             SZ_2K
+
 #define KIRKWOOD_NAND_MEM_PHYS_BASE    0xf3000000
-#define KIRKWOOD_NAND_MEM_SIZE         SZ_64K /* 1K is sufficient, but 64K
-                                               * is the minimal window size
-                                               */
+#define KIRKWOOD_NAND_MEM_SIZE         SZ_1K
 
 #define KIRKWOOD_PCIE_IO_PHYS_BASE     0xf2000000
 #define KIRKWOOD_PCIE_IO_VIRT_BASE     0xfef00000
@@ -48,6 +50,7 @@
  */
 #define DDR_VIRT_BASE          (KIRKWOOD_REGS_VIRT_BASE | 0x00000)
 #define  DDR_WINDOW_CPU_BASE   (DDR_VIRT_BASE | 0x1500)
+#define DDR_OPERATION_BASE     (DDR_VIRT_BASE | 0x1418)
 
 #define DEV_BUS_PHYS_BASE      (KIRKWOOD_REGS_PHYS_BASE | 0x10000)
 #define DEV_BUS_VIRT_BASE      (KIRKWOOD_REGS_VIRT_BASE | 0x10000)
 
 #define BRIDGE_VIRT_BASE       (KIRKWOOD_REGS_VIRT_BASE | 0x20000)
 
+#define CRYPTO_PHYS_BASE       (KIRKWOOD_REGS_PHYS_BASE | 0x30000)
+
 #define PCIE_VIRT_BASE         (KIRKWOOD_REGS_VIRT_BASE | 0x40000)
+#define PCIE_LINK_CTRL         (PCIE_VIRT_BASE | 0x70)
+#define PCIE_STATUS            (PCIE_VIRT_BASE | 0x1a04)
 
 #define USB_PHYS_BASE          (KIRKWOOD_REGS_PHYS_BASE | 0x50000)
 
 #define GE01_PHYS_BASE         (KIRKWOOD_REGS_PHYS_BASE | 0x74000)
 
 #define SATA_PHYS_BASE         (KIRKWOOD_REGS_PHYS_BASE | 0x80000)
+#define SATA_VIRT_BASE         (KIRKWOOD_REGS_VIRT_BASE | 0x80000)
+#define SATA0_IF_CTRL          (SATA_VIRT_BASE | 0x2050)
+#define SATA0_PHY_MODE_2       (SATA_VIRT_BASE | 0x2330)
+#define SATA1_IF_CTRL          (SATA_VIRT_BASE | 0x4050)
+#define SATA1_PHY_MODE_2       (SATA_VIRT_BASE | 0x4330)
 
 #define SDIO_PHYS_BASE         (KIRKWOOD_REGS_PHYS_BASE | 0x90000)
 
index 63c44934391ac5c68e62350004bbcfa129d49eda..a5900f64e38c112e7fb195ea2cdca7281cc64af7 100644 (file)
@@ -48,6 +48,9 @@ void __init kirkwood_mpp_conf(unsigned int *mpp_list)
        if (!variant_mask)
                return;
 
+       /* Initialize gpiolib. */
+       orion_gpio_init();
+
        printk(KERN_DEBUG "initial MPP regs:");
        for (i = 0; i < MPP_NR_REGS; i++) {
                mpp_ctrl[i] = readl(MPP_CTRL(i));
diff --git a/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c b/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c
new file mode 100644 (file)
index 0000000..0358f45
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c
+ *
+ * Marvell 88F6281 GTW GE 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/pci.h>
+#include <linux/irq.h>
+#include <linux/mtd/physmap.h>
+#include <linux/timer.h>
+#include <linux/mv643xx_eth.h>
+#include <linux/ethtool.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+#include <linux/spi/flash.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/orion_spi.h>
+#include <net/dsa.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/pci.h>
+#include <mach/kirkwood.h>
+#include "common.h"
+#include "mpp.h"
+
+static struct mv643xx_eth_platform_data mv88f6281gtw_ge_ge00_data = {
+       .phy_addr       = MV643XX_ETH_PHY_NONE,
+       .speed          = SPEED_1000,
+       .duplex         = DUPLEX_FULL,
+};
+
+static struct dsa_chip_data mv88f6281gtw_ge_switch_chip_data = {
+       .port_names[0]  = "lan1",
+       .port_names[1]  = "lan2",
+       .port_names[2]  = "lan3",
+       .port_names[3]  = "lan4",
+       .port_names[4]  = "wan",
+       .port_names[5]  = "cpu",
+};
+
+static struct dsa_platform_data mv88f6281gtw_ge_switch_plat_data = {
+       .nr_chips       = 1,
+       .chip           = &mv88f6281gtw_ge_switch_chip_data,
+};
+
+static const struct flash_platform_data mv88f6281gtw_ge_spi_slave_data = {
+       .type           = "mx25l12805d",
+};
+
+static struct spi_board_info __initdata mv88f6281gtw_ge_spi_slave_info[] = {
+       {
+               .modalias       = "m25p80",
+               .platform_data  = &mv88f6281gtw_ge_spi_slave_data,
+               .irq            = -1,
+               .max_speed_hz   = 50000000,
+               .bus_num        = 0,
+               .chip_select    = 0,
+       },
+};
+
+static struct gpio_keys_button mv88f6281gtw_ge_button_pins[] = {
+       {
+               .code           = KEY_RESTART,
+               .gpio           = 47,
+               .desc           = "SWR Button",
+               .active_low     = 1,
+       }, {
+               .code           = KEY_F1,
+               .gpio           = 46,
+               .desc           = "WPS Button(F1)",
+               .active_low     = 1,
+       },
+};
+
+static struct gpio_keys_platform_data mv88f6281gtw_ge_button_data = {
+       .buttons        = mv88f6281gtw_ge_button_pins,
+       .nbuttons       = ARRAY_SIZE(mv88f6281gtw_ge_button_pins),
+};
+
+static struct platform_device mv88f6281gtw_ge_buttons = {
+       .name           = "gpio-keys",
+       .id             = -1,
+       .num_resources  = 0,
+       .dev            = {
+               .platform_data  = &mv88f6281gtw_ge_button_data,
+       },
+};
+
+static struct gpio_led mv88f6281gtw_ge_led_pins[] = {
+       {
+               .name           = "gtw:green:Status",
+               .gpio           = 20,
+               .active_low     = 0,
+       }, {
+               .name           = "gtw:red:Status",
+               .gpio           = 21,
+               .active_low     = 0,
+       }, {
+               .name           = "gtw:green:USB",
+               .gpio           = 12,
+               .active_low     = 0,
+       },
+};
+
+static struct gpio_led_platform_data mv88f6281gtw_ge_led_data = {
+       .leds           = mv88f6281gtw_ge_led_pins,
+       .num_leds       = ARRAY_SIZE(mv88f6281gtw_ge_led_pins),
+};
+
+static struct platform_device mv88f6281gtw_ge_leds = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &mv88f6281gtw_ge_led_data,
+       },
+};
+
+static unsigned int mv88f6281gtw_ge_mpp_config[] __initdata = {
+       MPP12_GPO,      /* Status#_USB pin  */
+       MPP20_GPIO,     /* Status#_GLED pin */
+       MPP21_GPIO,     /* Status#_RLED pin */
+       MPP46_GPIO,     /* WPS_Switch pin   */
+       MPP47_GPIO,     /* SW_Init pin      */
+       0
+};
+
+static void __init mv88f6281gtw_ge_init(void)
+{
+       /*
+        * Basic setup. Needs to be called early.
+        */
+       kirkwood_init();
+       kirkwood_mpp_conf(mv88f6281gtw_ge_mpp_config);
+
+       kirkwood_ehci_init();
+       kirkwood_ge00_init(&mv88f6281gtw_ge_ge00_data);
+       kirkwood_ge00_switch_init(&mv88f6281gtw_ge_switch_plat_data, NO_IRQ);
+       spi_register_board_info(mv88f6281gtw_ge_spi_slave_info,
+                               ARRAY_SIZE(mv88f6281gtw_ge_spi_slave_info));
+       kirkwood_spi_init();
+       kirkwood_uart0_init();
+       platform_device_register(&mv88f6281gtw_ge_leds);
+       platform_device_register(&mv88f6281gtw_ge_buttons);
+}
+
+static int __init mv88f6281gtw_ge_pci_init(void)
+{
+       if (machine_is_mv88f6281gtw_ge())
+               kirkwood_pcie_init();
+
+       return 0;
+}
+subsys_initcall(mv88f6281gtw_ge_pci_init);
+
+MACHINE_START(MV88F6281GTW_GE, "Marvell 88F6281 GTW GE Board")
+       /* Maintainer: Lennert Buytenhek <buytenh@marvell.com> */
+       .phys_io        = KIRKWOOD_REGS_PHYS_BASE,
+       .io_pg_offst    = ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
+       .boot_params    = 0x00000100,
+       .init_machine   = mv88f6281gtw_ge_init,
+       .map_io         = kirkwood_map_io,
+       .init_irq       = kirkwood_init_irq,
+       .timer          = &kirkwood_timer,
+MACHINE_END
index 73fccacd1a73d25a861b8da1fc18ff812b1e091e..d90b9aae308de44dd872a5b5379dbcc33cd5d43c 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/irq.h>
 #include <asm/mach/pci.h>
 #include <plat/pcie.h>
+#include <mach/bridge-regs.h>
 #include "common.h"
 
 
@@ -95,6 +96,7 @@ static struct pci_ops pcie_ops = {
 static int kirkwood_pcie_setup(int nr, struct pci_sys_data *sys)
 {
        struct resource *res;
+       extern unsigned int kirkwood_clk_ctrl;
 
        /*
         * Generic PCIe unit setup.
@@ -133,6 +135,8 @@ static int kirkwood_pcie_setup(int nr, struct pci_sys_data *sys)
        sys->resource[2] = NULL;
        sys->io_offset = 0;
 
+       kirkwood_clk_ctrl |= CGC_PEX0;
+
        return 1;
 }
 
index 2f0e4ef3db0f44bd6766af9db41402f5c87617a2..8bf4153d0840f3a2ac08fff3adbf2ebca5308258 100644 (file)
@@ -11,8 +11,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/partitions.h>
 #include <linux/ata_platform.h>
 #include <linux/mv643xx_eth.h>
 #include <linux/spi/flash.h>
index 31e996d65fc46523845420eac063a29fcacaef40..31708ddbc83e13d5d97b31bdbaf3c13eeb735c1a 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/irq.h>
-#include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/ata_platform.h>
 #include <linux/mv643xx_eth.h>
@@ -22,7 +21,6 @@
 #include <asm/mach/arch.h>
 #include <mach/kirkwood.h>
 #include <plat/mvsdio.h>
-#include <plat/orion_nand.h>
 #include "common.h"
 #include "mpp.h"
 
@@ -42,32 +40,6 @@ static struct mtd_partition rd88f6281_nand_parts[] = {
        },
 };
 
-static struct resource rd88f6281_nand_resource = {
-       .flags          = IORESOURCE_MEM,
-       .start          = KIRKWOOD_NAND_MEM_PHYS_BASE,
-       .end            = KIRKWOOD_NAND_MEM_PHYS_BASE +
-                         KIRKWOOD_NAND_MEM_SIZE - 1,
-};
-
-static struct orion_nand_data rd88f6281_nand_data = {
-       .parts          = rd88f6281_nand_parts,
-       .nr_parts       = ARRAY_SIZE(rd88f6281_nand_parts),
-       .cle            = 0,
-       .ale            = 1,
-       .width          = 8,
-       .chip_delay     = 25,
-};
-
-static struct platform_device rd88f6281_nand_flash = {
-       .name           = "orion_nand",
-       .id             = -1,
-       .dev            = {
-               .platform_data  = &rd88f6281_nand_data,
-       },
-       .resource       = &rd88f6281_nand_resource,
-       .num_resources  = 1,
-};
-
 static struct mv643xx_eth_platform_data rd88f6281_ge00_data = {
        .phy_addr       = MV643XX_ETH_PHY_NONE,
        .speed          = SPEED_1000,
@@ -114,6 +86,7 @@ static void __init rd88f6281_init(void)
        kirkwood_init();
        kirkwood_mpp_conf(rd88f6281_mpp_config);
 
+       kirkwood_nand_init(ARRAY_AND_SIZE(rd88f6281_nand_parts), 25);
        kirkwood_ehci_init();
 
        kirkwood_ge00_init(&rd88f6281_ge00_data);
@@ -129,8 +102,6 @@ static void __init rd88f6281_init(void)
        kirkwood_sata_init(&rd88f6281_sata_data);
        kirkwood_sdio_init(&rd88f6281_mvsdio_data);
        kirkwood_uart0_init();
-
-       platform_device_register(&rd88f6281_nand_flash);
 }
 
 static int __init rd88f6281_pci_init(void)
index 831e4a56cae121e436d1f554c882d15fc9067534..c7319eeac8bbcddf0eafa3d501a3500b63128a92 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mv643xx_eth.h>
 #include <linux/gpio.h>
@@ -20,7 +19,6 @@
 #include <asm/mach/arch.h>
 #include <mach/kirkwood.h>
 #include <plat/mvsdio.h>
-#include <plat/orion_nand.h>
 #include "common.h"
 #include "mpp.h"
 
@@ -40,38 +38,12 @@ static struct mtd_partition sheevaplug_nand_parts[] = {
        },
 };
 
-static struct resource sheevaplug_nand_resource = {
-       .flags          = IORESOURCE_MEM,
-       .start          = KIRKWOOD_NAND_MEM_PHYS_BASE,
-       .end            = KIRKWOOD_NAND_MEM_PHYS_BASE +
-                         KIRKWOOD_NAND_MEM_SIZE - 1,
-};
-
-static struct orion_nand_data sheevaplug_nand_data = {
-       .parts          = sheevaplug_nand_parts,
-       .nr_parts       = ARRAY_SIZE(sheevaplug_nand_parts),
-       .cle            = 0,
-       .ale            = 1,
-       .width          = 8,
-       .chip_delay     = 25,
-};
-
-static struct platform_device sheevaplug_nand_flash = {
-       .name           = "orion_nand",
-       .id             = -1,
-       .dev            = {
-               .platform_data  = &sheevaplug_nand_data,
-       },
-       .resource       = &sheevaplug_nand_resource,
-       .num_resources  = 1,
-};
-
 static struct mv643xx_eth_platform_data sheevaplug_ge00_data = {
        .phy_addr       = MV643XX_ETH_PHY_ADDR(0),
 };
 
 static struct mvsdio_platform_data sheevaplug_mvsdio_data = {
-       // unfortunately the CD signal has not been connected */
+       /* unfortunately the CD signal has not been connected */
 };
 
 static struct gpio_led sheevaplug_led_pins[] = {
@@ -111,6 +83,7 @@ static void __init sheevaplug_init(void)
        kirkwood_mpp_conf(sheevaplug_mpp_config);
 
        kirkwood_uart0_init();
+       kirkwood_nand_init(ARRAY_AND_SIZE(sheevaplug_nand_parts), 25);
 
        if (gpio_request(29, "USB Power Enable") != 0 ||
            gpio_direction_output(29, 1) != 0)
@@ -120,7 +93,6 @@ static void __init sheevaplug_init(void)
        kirkwood_ge00_init(&sheevaplug_ge00_data);
        kirkwood_sdio_init(&sheevaplug_mvsdio_data);
 
-       platform_device_register(&sheevaplug_nand_flash);
        platform_device_register(&sheevaplug_leds);
 }
 
index e83e45ebf7a45a3e2b292272130f9212442af315..16295cfd5e29d702684108f2a94829bdb20b9cf4 100644 (file)
@@ -52,6 +52,7 @@
 /*
  * Interrupt numbers for PXA910
  */
+#define IRQ_PXA910_NONE                        (-1)
 #define IRQ_PXA910_AIRQ                        0
 #define IRQ_PXA910_SSP3                        1
 #define IRQ_PXA910_SSP2                        2
index 2e914649b9e44075d5af3b17d147c793b5134375..3b216bf41e7f0d2387b1ac2a01b386e021d2fcc7 100644 (file)
 #define GPIO58_LCD_PCLK_WR     MFP_CFG(GPIO58, AF1)
 #define GPIO85_LCD_VSYNC       MFP_CFG(GPIO85, AF1)
 
+/* I2C */
+#define GPIO105_CI2C_SDA       MFP_CFG(GPIO105, AF1)
+#define GPIO106_CI2C_SCL       MFP_CFG(GPIO106, AF1)
+
 /* I2S */
 #define GPIO113_I2S_MCLK       MFP_CFG(GPIO113,AF6)
 #define GPIO114_I2S_FRM                MFP_CFG(GPIO114,AF1)
 #define GPIO116_I2S_RXD                MFP_CFG(GPIO116,AF2)
 #define GPIO117_I2S_TXD                MFP_CFG(GPIO117,AF2)
 
+/* PWM */
+#define GPIO96_PWM3_OUT                MFP_CFG(GPIO96, AF1)
+#define GPIO97_PWM2_OUT                MFP_CFG(GPIO97, AF1)
+#define GPIO98_PWM1_OUT                MFP_CFG(GPIO98, AF1)
+#define GPIO104_PWM4_OUT       MFP_CFG(GPIO104, AF1)
+#define GPIO106_PWM2_OUT       MFP_CFG(GPIO106, AF2)
+#define GPIO74_PWM4_OUT                MFP_CFG(GPIO74, AF2)
+#define GPIO75_PWM3_OUT                MFP_CFG(GPIO75, AF2)
+#define GPIO76_PWM2_OUT                MFP_CFG(GPIO76, AF2)
+#define GPIO77_PWM1_OUT                MFP_CFG(GPIO77, AF2)
+#define GPIO82_PWM4_OUT                MFP_CFG(GPIO82, AF2)
+#define GPIO83_PWM3_OUT                MFP_CFG(GPIO83, AF2)
+#define GPIO84_PWM2_OUT                MFP_CFG(GPIO84, AF2)
+#define GPIO85_PWM1_OUT                MFP_CFG(GPIO85, AF2)
+#define GPIO84_PWM1_OUT                MFP_CFG(GPIO84, AF4)
+#define GPIO122_PWM3_OUT       MFP_CFG(GPIO122, AF3)
+#define GPIO123_PWM1_OUT       MFP_CFG(GPIO123, AF1)
+#define GPIO124_PWM2_OUT       MFP_CFG(GPIO124, AF1)
+#define GPIO125_PWM3_OUT       MFP_CFG(GPIO125, AF1)
+#define GPIO126_PWM4_OUT       MFP_CFG(GPIO126, AF1)
+#define GPIO86_PWM1_OUT                MFP_CFG(GPIO86, AF2)
+#define GPIO86_PWM2_OUT                MFP_CFG(GPIO86, AF3)
+
 #endif /* __ASM_MACH_MFP_PXA168_H */
index d97de36c50adbf75016a047f8b87f86f1385c313..bf1189ff9a34bd62fad9f8ab2c90c04e4703671b 100644 (file)
 #define MMC1_CD_MMC1_CD                MFP_CFG_DRV(MMC1_CD, AF0, MEDIUM)
 #define MMC1_WP_MMC1_WP                MFP_CFG_DRV(MMC1_WP, AF0, MEDIUM)
 
+/* PWM */
+#define GPIO27 PWM3 AF2                MFP_CFG(GPIO27, AF2)
+#define GPIO51_PWM2_OUT                MFP_CFG(GPIO51, AF2)
+#define GPIO117_PWM1_OUT       MFP_CFG(GPIO117, AF2)
+#define GPIO118_PWM2_OUT       MFP_CFG(GPIO118, AF2)
+#define GPIO119_PWM3_OUT       MFP_CFG(GPIO119, AF2)
+#define GPIO120_PWM4_OUT       MFP_CFG(GPIO120, AF2)
+
 #endif /* __ASM_MACH MFP_PXA910_H */
index ef0a8a2076e9580570e36569eca15dea7aa0ed45..6bf1f0eefcd1bf8ac88245c6808073ccb6ab0ff3 100644 (file)
@@ -1,10 +1,18 @@
 #ifndef __ASM_MACH_PXA168_H
 #define __ASM_MACH_PXA168_H
 
+#include <linux/i2c.h>
 #include <mach/devices.h>
+#include <plat/i2c.h>
 
 extern struct pxa_device_desc pxa168_device_uart1;
 extern struct pxa_device_desc pxa168_device_uart2;
+extern struct pxa_device_desc pxa168_device_twsi0;
+extern struct pxa_device_desc pxa168_device_twsi1;
+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;
 
 static inline int pxa168_add_uart(int id)
 {
@@ -20,4 +28,40 @@ static inline int pxa168_add_uart(int id)
 
        return pxa_register_device(d, NULL, 0);
 }
+
+static inline int pxa168_add_twsi(int id, struct i2c_pxa_platform_data *data,
+                                 struct i2c_board_info *info, unsigned size)
+{
+       struct pxa_device_desc *d = NULL;
+       int ret;
+
+       switch (id) {
+       case 0: d = &pxa168_device_twsi0; break;
+       case 1: d = &pxa168_device_twsi1; break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = i2c_register_board_info(id, info, size);
+       if (ret)
+               return ret;
+
+       return pxa_register_device(d, data, sizeof(*data));
+}
+
+static inline int pxa168_add_pwm(int id)
+{
+       struct pxa_device_desc *d = NULL;
+
+       switch (id) {
+       case 1: d = &pxa168_device_pwm1; break;
+       case 2: d = &pxa168_device_pwm2; break;
+       case 3: d = &pxa168_device_pwm3; break;
+       case 4: d = &pxa168_device_pwm4; break;
+       default:
+               return -EINVAL;
+       }
+
+       return pxa_register_device(d, NULL, 0);
+}
 #endif /* __ASM_MACH_PXA168_H */
index b7aeaf574c3688ff6b7c00695bb9fa032acd50ea..6ae1ed7a0a9f2559dc6a993134e1375c28f00841 100644 (file)
@@ -1,10 +1,18 @@
 #ifndef __ASM_MACH_PXA910_H
 #define __ASM_MACH_PXA910_H
 
+#include <linux/i2c.h>
 #include <mach/devices.h>
+#include <plat/i2c.h>
 
 extern struct pxa_device_desc pxa910_device_uart1;
 extern struct pxa_device_desc pxa910_device_uart2;
+extern struct pxa_device_desc pxa910_device_twsi0;
+extern struct pxa_device_desc pxa910_device_twsi1;
+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;
 
 static inline int pxa910_add_uart(int id)
 {
@@ -20,4 +28,40 @@ static inline int pxa910_add_uart(int id)
 
        return pxa_register_device(d, NULL, 0);
 }
+
+static inline int pxa910_add_twsi(int id, struct i2c_pxa_platform_data *data,
+                                 struct i2c_board_info *info, unsigned size)
+{
+       struct pxa_device_desc *d = NULL;
+       int ret;
+
+       switch (id) {
+       case 0: d = &pxa910_device_twsi0; break;
+       case 1: d = &pxa910_device_twsi1; break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = i2c_register_board_info(id, info, size);
+       if (ret)
+               return ret;
+
+       return pxa_register_device(d, data, sizeof(*data));
+}
+
+static inline int pxa910_add_pwm(int id)
+{
+       struct pxa_device_desc *d = NULL;
+
+       switch (id) {
+       case 1: d = &pxa910_device_pwm1; break;
+       case 2: d = &pxa910_device_pwm2; break;
+       case 3: d = &pxa910_device_pwm3; break;
+       case 4: d = &pxa910_device_pwm4; break;
+       default:
+               return -EINVAL;
+       }
+
+       return pxa_register_device(d, NULL, 0);
+}
 #endif /* __ASM_MACH_PXA910_H */
index c6b8c9dc202668f776a6768eff1685abeedb7f9b..98ccbee4bd0c756d285be6e0a3549f5162b1ba0f 100644 (file)
 #define APBC_PXA168_UART1      APBC_REG(0x000)
 #define APBC_PXA168_UART2      APBC_REG(0x004)
 #define APBC_PXA168_GPIO       APBC_REG(0x008)
-#define APBC_PXA168_PWM0       APBC_REG(0x00c)
-#define APBC_PXA168_PWM1       APBC_REG(0x010)
+#define APBC_PXA168_PWM1       APBC_REG(0x00c)
+#define APBC_PXA168_PWM2       APBC_REG(0x010)
+#define APBC_PXA168_PWM3       APBC_REG(0x014)
+#define APBC_PXA168_PWM4       APBC_REG(0x018)
 #define APBC_PXA168_SSP1       APBC_REG(0x01c)
 #define APBC_PXA168_SSP2       APBC_REG(0x020)
 #define APBC_PXA168_RTC                APBC_REG(0x028)
 #define APBC_PXA910_UART0      APBC_REG(0x000)
 #define APBC_PXA910_UART1      APBC_REG(0x004)
 #define APBC_PXA910_GPIO       APBC_REG(0x008)
-#define APBC_PXA910_PWM0       APBC_REG(0x00c)
-#define APBC_PXA910_PWM1       APBC_REG(0x010)
-#define APBC_PXA910_PWM2       APBC_REG(0x014)
-#define APBC_PXA910_PWM3       APBC_REG(0x018)
+#define APBC_PXA910_PWM1       APBC_REG(0x00c)
+#define APBC_PXA910_PWM2       APBC_REG(0x010)
+#define APBC_PXA910_PWM3       APBC_REG(0x014)
+#define APBC_PXA910_PWM4       APBC_REG(0x018)
 #define APBC_PXA910_SSP1       APBC_REG(0x01c)
 #define APBC_PXA910_SSP2       APBC_REG(0x020)
 #define APBC_PXA910_IPC                APBC_REG(0x024)
index ae924468658c4d2d272e3af1234a0ab714cdeedb..71b1ae338753355c20a978a9388c5f5500186b93 100644 (file)
@@ -65,11 +65,23 @@ void __init pxa168_init_irq(void)
 /* APB peripheral clocks */
 static APBC_CLK(uart1, PXA168_UART1, 1, 14745600);
 static APBC_CLK(uart2, PXA168_UART2, 1, 14745600);
+static APBC_CLK(twsi0, PXA168_TWSI0, 1, 33000000);
+static APBC_CLK(twsi1, PXA168_TWSI1, 1, 33000000);
+static APBC_CLK(pwm1, PXA168_PWM1, 1, 13000000);
+static APBC_CLK(pwm2, PXA168_PWM2, 1, 13000000);
+static APBC_CLK(pwm3, PXA168_PWM3, 1, 13000000);
+static APBC_CLK(pwm4, PXA168_PWM4, 1, 13000000);
 
 /* device and clock bindings */
 static struct clk_lookup pxa168_clkregs[] = {
        INIT_CLKREG(&clk_uart1, "pxa2xx-uart.0", NULL),
        INIT_CLKREG(&clk_uart2, "pxa2xx-uart.1", NULL),
+       INIT_CLKREG(&clk_twsi0, "pxa2xx-i2c.0", NULL),
+       INIT_CLKREG(&clk_twsi1, "pxa2xx-i2c.1", NULL),
+       INIT_CLKREG(&clk_pwm1, "pxa168-pwm.0", NULL),
+       INIT_CLKREG(&clk_pwm2, "pxa168-pwm.1", NULL),
+       INIT_CLKREG(&clk_pwm3, "pxa168-pwm.2", NULL),
+       INIT_CLKREG(&clk_pwm4, "pxa168-pwm.3", NULL),
 };
 
 static int __init pxa168_init(void)
@@ -109,3 +121,9 @@ struct sys_timer pxa168_timer = {
 /* on-chip devices */
 PXA168_DEVICE(uart1, "pxa2xx-uart", 0, UART1, 0xd4017000, 0x30, 21, 22);
 PXA168_DEVICE(uart2, "pxa2xx-uart", 1, UART2, 0xd4018000, 0x30, 23, 24);
+PXA168_DEVICE(twsi0, "pxa2xx-i2c", 0, TWSI0, 0xd4011000, 0x28);
+PXA168_DEVICE(twsi1, "pxa2xx-i2c", 1, TWSI1, 0xd4025000, 0x28);
+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);
index 453f8f7758bff45b046dc1cf06e52c8ccfa8b125..5882ca6b49fba82911b18c35fe7e4ea9a5ec03db 100644 (file)
@@ -103,11 +103,23 @@ void __init pxa910_init_irq(void)
 /* APB peripheral clocks */
 static APBC_CLK(uart1, PXA910_UART0, 1, 14745600);
 static APBC_CLK(uart2, PXA910_UART1, 1, 14745600);
+static APBC_CLK(twsi0, PXA168_TWSI0, 1, 33000000);
+static APBC_CLK(twsi1, PXA168_TWSI1, 1, 33000000);
+static APBC_CLK(pwm1, PXA910_PWM1, 1, 13000000);
+static APBC_CLK(pwm2, PXA910_PWM2, 1, 13000000);
+static APBC_CLK(pwm3, PXA910_PWM3, 1, 13000000);
+static APBC_CLK(pwm4, PXA910_PWM4, 1, 13000000);
 
 /* device and clock bindings */
 static struct clk_lookup pxa910_clkregs[] = {
        INIT_CLKREG(&clk_uart1, "pxa2xx-uart.0", NULL),
        INIT_CLKREG(&clk_uart2, "pxa2xx-uart.1", NULL),
+       INIT_CLKREG(&clk_twsi0, "pxa2xx-i2c.0", NULL),
+       INIT_CLKREG(&clk_twsi1, "pxa2xx-i2c.1", NULL),
+       INIT_CLKREG(&clk_pwm1, "pxa910-pwm.0", NULL),
+       INIT_CLKREG(&clk_pwm2, "pxa910-pwm.1", NULL),
+       INIT_CLKREG(&clk_pwm3, "pxa910-pwm.2", NULL),
+       INIT_CLKREG(&clk_pwm4, "pxa910-pwm.3", NULL),
 };
 
 static int __init pxa910_init(void)
@@ -156,3 +168,9 @@ struct sys_timer pxa910_timer = {
  */
 PXA910_DEVICE(uart1, "pxa2xx-uart", 0, UART2, 0xd4017000, 0x30, 21, 22);
 PXA910_DEVICE(uart2, "pxa2xx-uart", 1, UART3, 0xd4018000, 0x30, 23, 24);
+PXA910_DEVICE(twsi0, "pxa2xx-i2c", 0, TWSI0, 0xd4011000, 0x28);
+PXA910_DEVICE(twsi1, "pxa2xx-i2c", 1, TWSI1, 0xd4025000, 0x28);
+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);
index f289b0ea7dcf8005a1f8cbab8d5fdb0744ec1667..22b4ff893b3c6c04d13fc680f39ab43ae7ac2e3e 100644 (file)
@@ -28,6 +28,9 @@ void __init mv78xx0_init_irq(void)
 {
        int i;
 
+       /* Initialize gpiolib. */
+       orion_gpio_init();
+
        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));
        orion_irq_init(64, (void __iomem *)(IRQ_VIRT_BASE + IRQ_MASK_ERR_OFF));
index 0dec6f300ffc140da11ce1937e84323af90a6e40..7622c9b38c972d64432cc6475565cb71d1e2a414 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <asm/mach/map.h>
 
+#include <mach/common.h>
 #include <mach/hardware.h>
 
 static struct map_desc imx_io_desc[] __initdata = {
@@ -37,7 +38,9 @@ static struct map_desc imx_io_desc[] __initdata = {
        }
 };
 
-void __init mxc_map_io(void)
+void __init mx1_map_io(void)
 {
+       mxc_set_cpu_type(MXC_CPU_MX1);
+
        iotable_init(imx_io_desc, ARRAY_SIZE(imx_io_desc));
 }
index e54057fb855b102a5b00a34ed5efc8f849ab4d33..e5b0c0a83c3bfe5150a78d840f208a5e793b9d61 100644 (file)
  * warranty of any kind, whether express or implied.
  */
 
-#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/i2c/pcf857x.h>
 #include <linux/init.h>
+#include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/physmap.h>
-#include <linux/i2c.h>
-#include <linux/i2c/pcf857x.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 
-#include <mach/irqs.h>
-#include <mach/hardware.h>
 #include <mach/common.h>
-#include <mach/imx-uart.h>
-#include <mach/irqs.h>
+#include <mach/hardware.h>
 #include <mach/i2c.h>
+#include <mach/imx-uart.h>
 #include <mach/iomux.h>
+#include <mach/irqs.h>
+
 #include "devices.h"
 
-/*
- * UARTs platform data
- */
-static int mxc_uart1_pins[] = {
+static int mx1ads_pins[] = {
+       /* UART1 */
        PC9_PF_UART1_CTS,
        PC10_PF_UART1_RTS,
        PC11_PF_UART1_TXD,
        PC12_PF_UART1_RXD,
-};
-
-static int uart1_mxc_init(struct platform_device *pdev)
-{
-       return mxc_gpio_setup_multiple_pins(mxc_uart1_pins,
-                       ARRAY_SIZE(mxc_uart1_pins), "UART1");
-}
-
-static int uart1_mxc_exit(struct platform_device *pdev)
-{
-       mxc_gpio_release_multiple_pins(mxc_uart1_pins,
-                       ARRAY_SIZE(mxc_uart1_pins));
-       return 0;
-}
-
-static int mxc_uart2_pins[] = {
+       /* UART2 */
        PB28_PF_UART2_CTS,
        PB29_PF_UART2_RTS,
        PB30_PF_UART2_TXD,
        PB31_PF_UART2_RXD,
+       /* I2C */
+       PA15_PF_I2C_SDA,
+       PA16_PF_I2C_SCL,
+       /* SPI */
+       PC13_PF_SPI1_SPI_RDY,
+       PC14_PF_SPI1_SCLK,
+       PC15_PF_SPI1_SS,
+       PC16_PF_SPI1_MISO,
+       PC17_PF_SPI1_MOSI,
 };
 
-static int uart2_mxc_init(struct platform_device *pdev)
-{
-       return mxc_gpio_setup_multiple_pins(mxc_uart2_pins,
-                       ARRAY_SIZE(mxc_uart2_pins), "UART2");
-}
-
-static int uart2_mxc_exit(struct platform_device *pdev)
-{
-       mxc_gpio_release_multiple_pins(mxc_uart2_pins,
-                       ARRAY_SIZE(mxc_uart2_pins));
-       return 0;
-}
+/*
+ * UARTs platform data
+ */
 
 static struct imxuart_platform_data uart_pdata[] = {
        {
-               .init = uart1_mxc_init,
-               .exit = uart1_mxc_exit,
                .flags = IMXUART_HAVE_RTSCTS,
        }, {
-               .init = uart2_mxc_init,
-               .exit = uart2_mxc_exit,
                .flags = IMXUART_HAVE_RTSCTS,
        },
 };
@@ -111,24 +90,6 @@ static struct platform_device flash_device = {
 /*
  * I2C
  */
-
-static int i2c_pins[] = {
-       PA15_PF_I2C_SDA,
-       PA16_PF_I2C_SCL,
-};
-
-static int i2c_init(struct device *dev)
-{
-       return mxc_gpio_setup_multiple_pins(i2c_pins,
-                       ARRAY_SIZE(i2c_pins), "I2C");
-}
-
-static void i2c_exit(struct device *dev)
-{
-       mxc_gpio_release_multiple_pins(i2c_pins,
-                       ARRAY_SIZE(i2c_pins));
-}
-
 static struct pcf857x_platform_data pcf857x_data[] = {
        {
                .gpio_base = 4 * 32,
@@ -139,8 +100,6 @@ static struct pcf857x_platform_data pcf857x_data[] = {
 
 static struct imxi2c_platform_data mx1ads_i2c_data = {
        .bitrate = 100000,
-       .init = i2c_init,
-       .exit = i2c_exit,
 };
 
 static struct i2c_board_info mx1ads_i2c_devices[] = {
@@ -160,6 +119,9 @@ static struct i2c_board_info mx1ads_i2c_devices[] = {
  */
 static void __init mx1ads_init(void)
 {
+       mxc_gpio_setup_multiple_pins(mx1ads_pins,
+               ARRAY_SIZE(mx1ads_pins), "mx1ads");
+
        /* UART */
        mxc_register_device(&imx_uart1_device, &uart_pdata[0]);
        mxc_register_device(&imx_uart2_device, &uart_pdata[1]);
@@ -188,7 +150,7 @@ MACHINE_START(MX1ADS, "Freescale MX1ADS")
        .phys_io        = IMX_IO_PHYS,
        .io_pg_offst    = (IMX_IO_BASE >> 18) & 0xfffc,
        .boot_params    = PHYS_OFFSET + 0x100,
-       .map_io         = mxc_map_io,
+       .map_io         = mx1_map_io,
        .init_irq       = mxc_init_irq,
        .timer          = &mx1ads_timer,
        .init_machine   = mx1ads_init,
@@ -198,7 +160,7 @@ MACHINE_START(MXLADS, "Freescale MXLADS")
        .phys_io        = IMX_IO_PHYS,
        .io_pg_offst    = (IMX_IO_BASE >> 18) & 0xfffc,
        .boot_params    = PHYS_OFFSET + 0x100,
-       .map_io         = mxc_map_io,
+       .map_io         = mx1_map_io,
        .init_irq       = mxc_init_irq,
        .timer          = &mx1ads_timer,
        .init_machine   = mx1ads_init,
index 0e71f3fa28bf3ba5a916a632768d3e2d92a0ed4f..20e0b5bcdffcdc65538616d23cd25ba395e365e8 100644 (file)
@@ -153,7 +153,7 @@ MACHINE_START(SCB9328, "Synertronixx scb9328")
        .phys_io        = 0x00200000,
        .io_pg_offst    = ((0xe0200000) >> 18) & 0xfffc,
        .boot_params    = 0x08000100,
-       .map_io         = mxc_map_io,
+       .map_io         = mx1_map_io,
        .init_irq       = mxc_init_irq,
        .timer          = &scb9328_timer,
        .init_machine   = scb9328_init,
index 42a788842f496e2d284fb6fad7adc2045f703826..c77da586b71da81e6fe9f4ede2fb7b837c8388a5 100644 (file)
@@ -18,6 +18,13 @@ endchoice
 
 comment "MX2 platforms:"
 
+config MACH_MX21ADS
+       bool "MX21ADS platform"
+       depends on MACH_MX21
+       help
+         Include support for MX21ADS platform. This includes specific
+         configurations for the board and its peripherals.
+
 config MACH_MX27ADS
        bool "MX27ADS platform"
        depends on MACH_MX27
@@ -46,4 +53,18 @@ config MACH_PCM970_BASEBOARD
 
 endchoice
 
+config MACH_MX27_3DS
+       bool "MX27PDK platform"
+       depends on MACH_MX27
+       help
+         Include support for MX27PDK platform. This includes specific
+         configurations for the board and its peripherals.
+
+config MACH_MX27LITE
+       bool "LogicPD MX27 LITEKIT platform"
+       depends on MACH_MX27
+       help
+         Include support for MX27 LITEKIT platform. This includes specific
+         configurations for the board and its peripherals.
+
 endif
index 950649a9154065f69d63ca0bd6dcc4343d43e814..b9b1cca4e9bc2c98082080d48133aa3b4e17abb4 100644 (file)
@@ -11,6 +11,10 @@ obj-$(CONFIG_MACH_MX21) += clock_imx21.o
 obj-$(CONFIG_MACH_MX27) += cpu_imx27.o
 obj-$(CONFIG_MACH_MX27) += clock_imx27.o
 
+obj-$(CONFIG_MACH_MX21ADS) += mx21ads.o
 obj-$(CONFIG_MACH_MX27ADS) += mx27ads.o
 obj-$(CONFIG_MACH_PCM038) += pcm038.o
 obj-$(CONFIG_MACH_PCM970_BASEBOARD) += pcm970-baseboard.o
+obj-$(CONFIG_MACH_MX27_3DS) += mx27pdk.o
+obj-$(CONFIG_MACH_MX27LITE) += mx27lite.o
+
index e4b08ca804eaeded273ff239227e498d753528d8..0850fb88ec15f4dc9e41d3c4bd6e04e6a66e58ab 100644 (file)
@@ -48,6 +48,25 @@ static void _clk_disable(struct clk *clk)
        __raw_writel(reg, clk->enable_reg);
 }
 
+static unsigned long _clk_generic_round_rate(struct clk *clk,
+                       unsigned long rate,
+                       u32 max_divisor)
+{
+       u32 div;
+       unsigned long parent_rate;
+
+       parent_rate = clk_get_rate(clk->parent);
+
+       div = parent_rate / rate;
+       if (parent_rate % rate)
+               div++;
+
+       if (div > max_divisor)
+               div = max_divisor;
+
+       return parent_rate / div;
+}
+
 static int _clk_spll_enable(struct clk *clk)
 {
        u32 reg;
@@ -78,19 +97,7 @@ static void _clk_spll_disable(struct clk *clk)
 static unsigned long _clk_perclkx_round_rate(struct clk *clk,
                                             unsigned long rate)
 {
-       u32 div;
-       unsigned long parent_rate;
-
-       parent_rate = clk_get_rate(clk->parent);
-
-       div = parent_rate / rate;
-       if (parent_rate % rate)
-               div++;
-
-       if (div > 64)
-               div = 64;
-
-       return parent_rate / div;
+       return _clk_generic_round_rate(clk, rate, 64);
 }
 
 static int _clk_perclkx_set_rate(struct clk *clk, unsigned long rate)
@@ -130,6 +137,32 @@ static unsigned long _clk_usb_recalc(struct clk *clk)
        return parent_rate / (usb_pdf + 1U);
 }
 
+static unsigned long _clk_usb_round_rate(struct clk *clk,
+                                            unsigned long rate)
+{
+       return _clk_generic_round_rate(clk, rate, 8);
+}
+
+static int _clk_usb_set_rate(struct clk *clk, unsigned long rate)
+{
+       u32 reg;
+       u32 div;
+       unsigned long parent_rate;
+
+       parent_rate = clk_get_rate(clk->parent);
+
+       div = parent_rate / rate;
+       if (div > 8 || div < 1 || ((parent_rate / div) != rate))
+               return -EINVAL;
+       div--;
+
+       reg = CSCR() & ~CCM_CSCR_USB_MASK;
+       reg |= div << CCM_CSCR_USB_OFFSET;
+       __raw_writel(reg, CCM_CSCR);
+
+       return 0;
+}
+
 static unsigned long _clk_ssix_recalc(struct clk *clk, unsigned long pdf)
 {
        unsigned long parent_rate;
@@ -595,11 +628,14 @@ static struct clk csi_clk[] = {
 static struct clk usb_clk[] = {
        {
                .parent = &spll_clk,
+               .secondary = &usb_clk[1],
                .get_rate = _clk_usb_recalc,
                .enable = _clk_enable,
                .enable_reg = CCM_PCCR_USBOTG_REG,
                .enable_shift = CCM_PCCR_USBOTG_OFFSET,
                .disable = _clk_disable,
+               .round_rate = _clk_usb_round_rate,
+               .set_rate = _clk_usb_set_rate,
        }, {
                .parent = &hclk_clk,
                .enable = _clk_enable,
@@ -768,18 +804,7 @@ static struct clk rtc_clk = {
 
 static unsigned long _clk_clko_round_rate(struct clk *clk, unsigned long rate)
 {
-       u32 div;
-       unsigned long parent_rate;
-
-       parent_rate = clk_get_rate(clk->parent);
-       div = parent_rate / rate;
-       if (parent_rate % rate)
-               div++;
-
-       if (div > 8)
-               div = 8;
-
-       return parent_rate / div;
+       return _clk_generic_round_rate(clk, rate, 8);
 }
 
 static int _clk_clko_set_rate(struct clk *clk, unsigned long rate)
@@ -921,7 +946,7 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK(NULL, "cspi3", cspi_clk[2])
        _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk[0])
        _REGISTER_CLOCK(NULL, "csi", csi_clk[0])
-       _REGISTER_CLOCK(NULL, "usb", usb_clk[0])
+       _REGISTER_CLOCK("imx21-hcd.0", NULL, usb_clk[0])
        _REGISTER_CLOCK(NULL, "ssi1", ssi_clk[0])
        _REGISTER_CLOCK(NULL, "ssi2", ssi_clk[1])
        _REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk)
index bd51dd04948eee62cb0415fe5ebc806a2ac287a0..169372f69d8f80871229669ad732e7c5593517e3 100644 (file)
@@ -69,7 +69,17 @@ static struct map_desc mxc_io_desc[] __initdata = {
  * system startup to create static physical to virtual
  * memory map for the IO modules.
  */
-void __init mxc_map_io(void)
+void __init mx21_map_io(void)
 {
+       mxc_set_cpu_type(MXC_CPU_MX21);
+
        iotable_init(mxc_io_desc, ARRAY_SIZE(mxc_io_desc));
 }
+
+void __init mx27_map_io(void)
+{
+       mxc_set_cpu_type(MXC_CPU_MX27);
+
+       iotable_init(mxc_io_desc, ARRAY_SIZE(mxc_io_desc));
+}
+
diff --git a/arch/arm/mach-mx2/mx21ads.c b/arch/arm/mach-mx2/mx21ads.c
new file mode 100644 (file)
index 0000000..a5ee461
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ *  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/physmap.h>
+#include <linux/gpio.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 <mach/imx-uart.h>
+#include <mach/imxfb.h>
+#include <mach/iomux.h>
+#include <mach/mxc_nand.h>
+#include <mach/mmc.h>
+#include <mach/board-mx21ads.h>
+
+#include "devices.h"
+
+static unsigned int mx21ads_pins[] = {
+
+       /* CS8900A */
+       (GPIO_PORTE | GPIO_GPIO | GPIO_IN | 11),
+
+       /* UART1 */
+       PE12_PF_UART1_TXD,
+       PE13_PF_UART1_RXD,
+       PE14_PF_UART1_CTS,
+       PE15_PF_UART1_RTS,
+
+       /* UART3 (IrDA) - only TXD and RXD */
+       PE8_PF_UART3_TXD,
+       PE9_PF_UART3_RXD,
+
+       /* UART4 */
+       PB26_AF_UART4_RTS,
+       PB28_AF_UART4_TXD,
+       PB29_AF_UART4_CTS,
+       PB31_AF_UART4_RXD,
+
+       /* LCDC */
+       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,
+       PA24_PF_REV,     /* Sharp panel dedicated signal */
+       PA25_PF_CLS,     /* Sharp panel dedicated signal */
+       PA26_PF_PS,      /* Sharp panel dedicated signal */
+       PA27_PF_SPL_SPR, /* Sharp panel dedicated signal */
+       PA28_PF_HSYNC,
+       PA29_PF_VSYNC,
+       PA30_PF_CONTRAST,
+       PA31_PF_OE_ACD,
+
+       /* MMC/SDHC */
+       PE18_PF_SD1_D0,
+       PE19_PF_SD1_D1,
+       PE20_PF_SD1_D2,
+       PE21_PF_SD1_D3,
+       PE22_PF_SD1_CMD,
+       PE23_PF_SD1_CLK,
+
+       /* NFC */
+       PF0_PF_NRFB,
+       PF1_PF_NFCE,
+       PF2_PF_NFWP,
+       PF3_PF_NFCLE,
+       PF4_PF_NFALE,
+       PF5_PF_NFRE,
+       PF6_PF_NFWE,
+       PF7_PF_NFIO0,
+       PF8_PF_NFIO1,
+       PF9_PF_NFIO2,
+       PF10_PF_NFIO3,
+       PF11_PF_NFIO4,
+       PF12_PF_NFIO5,
+       PF13_PF_NFIO6,
+       PF14_PF_NFIO7,
+};
+
+/* ADS's NOR flash: 2x AM29BDS128HE9VKI on 32-bit bus */
+static struct physmap_flash_data mx21ads_flash_data = {
+       .width = 4,
+};
+
+static struct resource mx21ads_flash_resource = {
+       .start = CS0_BASE_ADDR,
+       .end = CS0_BASE_ADDR + 0x02000000 - 1,
+       .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device mx21ads_nor_mtd_device = {
+       .name = "physmap-flash",
+       .id = 0,
+       .dev = {
+               .platform_data = &mx21ads_flash_data,
+       },
+       .num_resources = 1,
+       .resource = &mx21ads_flash_resource,
+};
+
+static struct imxuart_platform_data uart_pdata = {
+       .flags = IMXUART_HAVE_RTSCTS,
+};
+
+static struct imxuart_platform_data uart_norts_pdata = {
+};
+
+
+static int mx21ads_fb_init(struct platform_device *pdev)
+{
+       u16 tmp;
+
+       tmp = __raw_readw(MX21ADS_IO_REG);
+       tmp |= MX21ADS_IO_LCDON;
+       __raw_writew(tmp, MX21ADS_IO_REG);
+       return 0;
+}
+
+static void mx21ads_fb_exit(struct platform_device *pdev)
+{
+       u16 tmp;
+
+       tmp = __raw_readw(MX21ADS_IO_REG);
+       tmp &= ~MX21ADS_IO_LCDON;
+       __raw_writew(tmp, MX21ADS_IO_REG);
+}
+
+/*
+ * Connected is a portrait Sharp-QVGA display
+ * of type: LQ035Q7DB02
+ */
+static struct imx_fb_platform_data mx21ads_fb_data = {
+       .pixclock       = 188679, /* in ps */
+       .xres           = 240,
+       .yres           = 320,
+
+       .bpp            = 16,
+       .hsync_len      = 2,
+       .left_margin    = 6,
+       .right_margin   = 16,
+
+       .vsync_len      = 1,
+       .upper_margin   = 8,
+       .lower_margin   = 10,
+       .fixed_screen_cpu = 0,
+
+       .pcr            = 0xFB108BC7,
+       .pwmr           = 0x00A901ff,
+       .lscr1          = 0x00120300,
+       .dmacr          = 0x00020008,
+
+       .init = mx21ads_fb_init,
+       .exit = mx21ads_fb_exit,
+};
+
+static int mx21ads_sdhc_get_ro(struct device *dev)
+{
+       return (__raw_readw(MX21ADS_IO_REG) & MX21ADS_IO_SD_WP) ? 1 : 0;
+}
+
+static int mx21ads_sdhc_init(struct device *dev, irq_handler_t detect_irq,
+       void *data)
+{
+       int ret;
+
+       ret = request_irq(IRQ_GPIOD(25), detect_irq,
+               IRQF_TRIGGER_FALLING, "mmc-detect", data);
+       if (ret)
+               goto out;
+       return 0;
+out:
+       return ret;
+}
+
+static void mx21ads_sdhc_exit(struct device *dev, void *data)
+{
+       free_irq(IRQ_GPIOD(25), data);
+}
+
+static struct imxmmc_platform_data mx21ads_sdhc_pdata = {
+       .ocr_avail = MMC_VDD_29_30 | MMC_VDD_30_31, /* 3.0V */
+       .get_ro = mx21ads_sdhc_get_ro,
+       .init = mx21ads_sdhc_init,
+       .exit = mx21ads_sdhc_exit,
+};
+
+static struct mxc_nand_platform_data mx21ads_nand_board_info = {
+       .width = 1,
+       .hw_ecc = 1,
+};
+
+static struct map_desc mx21ads_io_desc[] __initdata = {
+       /*
+        * Memory-mapped I/O on MX21ADS Base board:
+        *   - CS8900A Ethernet controller
+        *   - ST16C2552CJ UART
+        *   - CPU and Base board version
+        *   - Base board I/O register
+        */
+       {
+               .virtual = MX21ADS_MMIO_BASE_ADDR,
+               .pfn = __phys_to_pfn(CS1_BASE_ADDR),
+               .length = MX21ADS_MMIO_SIZE,
+               .type = MT_DEVICE,
+       },
+};
+
+static void __init mx21ads_map_io(void)
+{
+       mx21_map_io();
+       iotable_init(mx21ads_io_desc, ARRAY_SIZE(mx21ads_io_desc));
+}
+
+static struct platform_device *platform_devices[] __initdata = {
+       &mx21ads_nor_mtd_device,
+};
+
+static void __init mx21ads_board_init(void)
+{
+       mxc_gpio_setup_multiple_pins(mx21ads_pins, ARRAY_SIZE(mx21ads_pins),
+                       "mx21ads");
+
+       mxc_register_device(&mxc_uart_device0, &uart_pdata);
+       mxc_register_device(&mxc_uart_device2, &uart_norts_pdata);
+       mxc_register_device(&mxc_uart_device3, &uart_pdata);
+       mxc_register_device(&mxc_fb_device, &mx21ads_fb_data);
+       mxc_register_device(&mxc_sdhc_device0, &mx21ads_sdhc_pdata);
+       mxc_register_device(&mxc_nand_device, &mx21ads_nand_board_info);
+
+       platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+}
+
+static void __init mx21ads_timer_init(void)
+{
+       mx21_clocks_init(32768, 26000000);
+}
+
+static struct sys_timer mx21ads_timer = {
+       .init   = mx21ads_timer_init,
+};
+
+MACHINE_START(MX21ADS, "Freescale i.MX21ADS")
+       /* maintainer: Freescale Semiconductor, Inc. */
+       .phys_io        = AIPI_BASE_ADDR,
+       .io_pg_offst    = ((AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
+       .boot_params    = PHYS_OFFSET + 0x100,
+       .map_io         = mx21ads_map_io,
+       .init_irq       = mxc_init_irq,
+       .init_machine   = mx21ads_board_init,
+       .timer          = &mx21ads_timer,
+MACHINE_END
index 4a3b097adc12afa6e8c88e3c081a3ac334789064..02daddac6995e735e5babd33167b1c49083de099 100644 (file)
@@ -23,6 +23,8 @@
 #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 <mach/imx-uart.h>
 #include <mach/iomux.h>
 #include <mach/board-mx27ads.h>
+#include <mach/mxc_nand.h>
+#include <mach/i2c.h>
+#include <mach/imxfb.h>
+#include <mach/mmc.h>
 
 #include "devices.h"
 
+static unsigned int mx27ads_pins[] = {
+       /* 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,
+       /* 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,
+       PA24_PF_REV,
+       PA25_PF_CLS,
+       PA26_PF_PS,
+       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,
+       /* 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 mx27ads_nand_board_info = {
+       .width = 1,
+       .hw_ecc = 1,
+};
+
 /* ADS's NOR flash */
 static struct physmap_flash_data mx27ads_flash_data = {
        .width = 2,
@@ -58,189 +168,113 @@ static struct platform_device mx27ads_nor_mtd_device = {
        .resource = &mx27ads_flash_resource,
 };
 
-static int mxc_uart0_pins[] = {
-       PE12_PF_UART1_TXD,
-       PE13_PF_UART1_RXD,
-       PE14_PF_UART1_CTS,
-       PE15_PF_UART1_RTS
+static struct imxi2c_platform_data mx27ads_i2c_data = {
+       .bitrate = 100000,
 };
 
-static int uart_mxc_port0_init(struct platform_device *pdev)
-{
-       return mxc_gpio_setup_multiple_pins(mxc_uart0_pins,
-                       ARRAY_SIZE(mxc_uart0_pins), "UART0");
-}
-
-static int uart_mxc_port0_exit(struct platform_device *pdev)
-{
-       mxc_gpio_release_multiple_pins(mxc_uart0_pins,
-                       ARRAY_SIZE(mxc_uart0_pins));
-       return 0;
-}
-
-static int mxc_uart1_pins[] = {
-       PE3_PF_UART2_CTS,
-       PE4_PF_UART2_RTS,
-       PE6_PF_UART2_TXD,
-       PE7_PF_UART2_RXD
+static struct i2c_board_info mx27ads_i2c_devices[] = {
 };
 
-static int uart_mxc_port1_init(struct platform_device *pdev)
+void lcd_power(int on)
 {
-       return mxc_gpio_setup_multiple_pins(mxc_uart1_pins,
-                       ARRAY_SIZE(mxc_uart1_pins), "UART1");
+       if (on)
+               __raw_writew(PBC_BCTRL1_LCDON, PBC_BCTRL1_SET_REG);
+       else
+               __raw_writew(PBC_BCTRL1_LCDON, PBC_BCTRL1_CLEAR_REG);
 }
 
-static int uart_mxc_port1_exit(struct platform_device *pdev)
-{
-       mxc_gpio_release_multiple_pins(mxc_uart1_pins,
-                       ARRAY_SIZE(mxc_uart1_pins));
-       return 0;
-}
-
-static int mxc_uart2_pins[] = {
-       PE8_PF_UART3_TXD,
-       PE9_PF_UART3_RXD,
-       PE10_PF_UART3_CTS,
-       PE11_PF_UART3_RTS
+static struct imx_fb_platform_data mx27ads_fb_data = {
+       .pixclock       = 188679,
+       .xres           = 240,
+       .yres           = 320,
+
+       .bpp            = 16,
+       .hsync_len      = 1,
+       .left_margin    = 9,
+       .right_margin   = 16,
+
+       .vsync_len      = 1,
+       .upper_margin   = 7,
+       .lower_margin   = 9,
+       .fixed_screen_cpu = 0,
+
+       /*
+        * - HSYNC active high
+        * - VSYNC active high
+        * - clk notenabled while idle
+        * - clock inverted
+        * - data not inverted
+        * - data enable low active
+        * - enable sharp mode
+        */
+       .pcr            = 0xFB008BC0,
+       .pwmr           = 0x00A903FF,
+       .lscr1          = 0x00120300,
+       .dmacr          = 0x00020010,
+
+       .lcd_power      = lcd_power,
 };
 
-static int uart_mxc_port2_init(struct platform_device *pdev)
+static int mx27ads_sdhc1_init(struct device *dev, irq_handler_t detect_irq,
+                             void *data)
 {
-       return mxc_gpio_setup_multiple_pins(mxc_uart2_pins,
-                       ARRAY_SIZE(mxc_uart2_pins), "UART2");
+       return request_irq(IRQ_GPIOE(21), detect_irq, IRQF_TRIGGER_RISING,
+                          "sdhc1-card-detect", data);
 }
 
-static int uart_mxc_port2_exit(struct platform_device *pdev)
+static int mx27ads_sdhc2_init(struct device *dev, irq_handler_t detect_irq,
+                             void *data)
 {
-       mxc_gpio_release_multiple_pins(mxc_uart2_pins,
-                       ARRAY_SIZE(mxc_uart2_pins));
-       return 0;
+       return request_irq(IRQ_GPIOB(7), detect_irq, IRQF_TRIGGER_RISING,
+                          "sdhc2-card-detect", data);
 }
 
-static int mxc_uart3_pins[] = {
-       PB26_AF_UART4_RTS,
-       PB28_AF_UART4_TXD,
-       PB29_AF_UART4_CTS,
-       PB31_AF_UART4_RXD
-};
-
-static int uart_mxc_port3_init(struct platform_device *pdev)
+static void mx27ads_sdhc1_exit(struct device *dev, void *data)
 {
-       return mxc_gpio_setup_multiple_pins(mxc_uart3_pins,
-                       ARRAY_SIZE(mxc_uart3_pins), "UART3");
+       free_irq(IRQ_GPIOE(21), data);
 }
 
-static int uart_mxc_port3_exit(struct platform_device *pdev)
+static void mx27ads_sdhc2_exit(struct device *dev, void *data)
 {
-       mxc_gpio_release_multiple_pins(mxc_uart3_pins,
-                       ARRAY_SIZE(mxc_uart3_pins));
-       return 0;
+       free_irq(IRQ_GPIOB(7), data);
 }
 
-static int mxc_uart4_pins[] = {
-       PB18_AF_UART5_TXD,
-       PB19_AF_UART5_RXD,
-       PB20_AF_UART5_CTS,
-       PB21_AF_UART5_RTS
+static struct imxmmc_platform_data sdhc1_pdata = {
+       .init = mx27ads_sdhc1_init,
+       .exit = mx27ads_sdhc1_exit,
 };
 
-static int uart_mxc_port4_init(struct platform_device *pdev)
-{
-       return mxc_gpio_setup_multiple_pins(mxc_uart4_pins,
-                       ARRAY_SIZE(mxc_uart4_pins), "UART4");
-}
-
-static int uart_mxc_port4_exit(struct platform_device *pdev)
-{
-       mxc_gpio_release_multiple_pins(mxc_uart4_pins,
-                       ARRAY_SIZE(mxc_uart4_pins));
-       return 0;
-}
-
-static int mxc_uart5_pins[] = {
-       PB10_AF_UART6_TXD,
-       PB12_AF_UART6_CTS,
-       PB11_AF_UART6_RXD,
-       PB13_AF_UART6_RTS
+static struct imxmmc_platform_data sdhc2_pdata = {
+       .init = mx27ads_sdhc2_init,
+       .exit = mx27ads_sdhc2_exit,
 };
 
-static int uart_mxc_port5_init(struct platform_device *pdev)
-{
-       return mxc_gpio_setup_multiple_pins(mxc_uart5_pins,
-                       ARRAY_SIZE(mxc_uart5_pins), "UART5");
-}
-
-static int uart_mxc_port5_exit(struct platform_device *pdev)
-{
-       mxc_gpio_release_multiple_pins(mxc_uart5_pins,
-                       ARRAY_SIZE(mxc_uart5_pins));
-       return 0;
-}
-
 static struct platform_device *platform_devices[] __initdata = {
        &mx27ads_nor_mtd_device,
        &mxc_fec_device,
+       &mxc_w1_master_device,
 };
 
-static int mxc_fec_pins[] = {
-       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
-};
-
-static void gpio_fec_active(void)
-{
-       mxc_gpio_setup_multiple_pins(mxc_fec_pins,
-                       ARRAY_SIZE(mxc_fec_pins), "FEC");
-}
-
 static struct imxuart_platform_data uart_pdata[] = {
        {
-               .init = uart_mxc_port0_init,
-               .exit = uart_mxc_port0_exit,
                .flags = IMXUART_HAVE_RTSCTS,
        }, {
-               .init = uart_mxc_port1_init,
-               .exit = uart_mxc_port1_exit,
                .flags = IMXUART_HAVE_RTSCTS,
        }, {
-               .init = uart_mxc_port2_init,
-               .exit = uart_mxc_port2_exit,
                .flags = IMXUART_HAVE_RTSCTS,
        }, {
-               .init = uart_mxc_port3_init,
-               .exit = uart_mxc_port3_exit,
                .flags = IMXUART_HAVE_RTSCTS,
        }, {
-               .init = uart_mxc_port4_init,
-               .exit = uart_mxc_port4_exit,
                .flags = IMXUART_HAVE_RTSCTS,
        }, {
-               .init = uart_mxc_port5_init,
-               .exit = uart_mxc_port5_exit,
                .flags = IMXUART_HAVE_RTSCTS,
        },
 };
 
 static void __init mx27ads_board_init(void)
 {
-       gpio_fec_active();
+       mxc_gpio_setup_multiple_pins(mx27ads_pins, ARRAY_SIZE(mx27ads_pins),
+                       "mx27ads");
 
        mxc_register_device(&mxc_uart_device0, &uart_pdata[0]);
        mxc_register_device(&mxc_uart_device1, &uart_pdata[1]);
@@ -248,6 +282,15 @@ static void __init mx27ads_board_init(void)
        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, &mx27ads_nand_board_info);
+
+       /* only the i2c master 1 is used on this CPU card */
+       i2c_register_board_info(1, mx27ads_i2c_devices,
+                               ARRAY_SIZE(mx27ads_i2c_devices));
+       mxc_register_device(&mxc_i2c_device1, &mx27ads_i2c_data);
+       mxc_register_device(&mxc_fb_device, &mx27ads_fb_data);
+       mxc_register_device(&mxc_sdhc_device0, &sdhc1_pdata);
+       mxc_register_device(&mxc_sdhc_device1, &sdhc2_pdata);
 
        platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 }
@@ -277,7 +320,7 @@ static struct map_desc mx27ads_io_desc[] __initdata = {
 
 static void __init mx27ads_map_io(void)
 {
-       mxc_map_io();
+       mx27_map_io();
        iotable_init(mx27ads_io_desc, ARRAY_SIZE(mx27ads_io_desc));
 }
 
diff --git a/arch/arm/mach-mx2/mx27lite.c b/arch/arm/mach-mx2/mx27lite.c
new file mode 100644 (file)
index 0000000..3ae11cb
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2007 Robert Schwebel <r.schwebel@pengutronix.de>, Pengutronix
+ * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
+ * Copyright 2009 Daniel Schaeffer (daniel.schaeffer@timesys.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/platform_device.h>
+#include <linux/gpio.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/mach/map.h>
+#include <mach/hardware.h>
+#include <mach/common.h>
+#include <mach/imx-uart.h>
+#include <mach/iomux.h>
+#include <mach/board-mx27lite.h>
+
+#include "devices.h"
+
+static unsigned int mx27lite_pins[] = {
+       /* UART1 */
+       PE12_PF_UART1_TXD,
+       PE13_PF_UART1_RXD,
+       PE14_PF_UART1_CTS,
+       PE15_PF_UART1_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,
+};
+
+static struct imxuart_platform_data uart_pdata = {
+       .flags = IMXUART_HAVE_RTSCTS,
+};
+
+static struct platform_device *platform_devices[] __initdata = {
+       &mxc_fec_device,
+};
+
+static void __init mx27lite_init(void)
+{
+       mxc_gpio_setup_multiple_pins(mx27lite_pins, ARRAY_SIZE(mx27lite_pins),
+               "imx27lite");
+       mxc_register_device(&mxc_uart_device0, &uart_pdata);
+       platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+}
+
+static void __init mx27lite_timer_init(void)
+{
+       mx27_clocks_init(26000000);
+}
+
+static struct sys_timer mx27lite_timer = {
+       .init   = mx27lite_timer_init,
+};
+
+MACHINE_START(IMX27LITE, "LogicPD i.MX27LITE")
+       .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       = mxc_init_irq,
+       .init_machine   = mx27lite_init,
+       .timer          = &mx27lite_timer,
+MACHINE_END
diff --git a/arch/arm/mach-mx2/mx27pdk.c b/arch/arm/mach-mx2/mx27pdk.c
new file mode 100644 (file)
index 0000000..1d9238c
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Author: Fabio Estevam <fabio.estevam@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/hardware.h>
+#include <mach/common.h>
+#include <mach/imx-uart.h>
+#include <mach/iomux.h>
+#include <mach/board-mx27pdk.h>
+
+#include "devices.h"
+
+static unsigned int mx27pdk_pins[] = {
+       /* UART1 */
+       PE12_PF_UART1_TXD,
+       PE13_PF_UART1_RXD,
+       PE14_PF_UART1_CTS,
+       PE15_PF_UART1_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,
+};
+
+static struct imxuart_platform_data uart_pdata = {
+       .flags = IMXUART_HAVE_RTSCTS,
+};
+
+static struct platform_device *platform_devices[] __initdata = {
+       &mxc_fec_device,
+};
+
+static void __init mx27pdk_init(void)
+{
+       mxc_gpio_setup_multiple_pins(mx27pdk_pins, ARRAY_SIZE(mx27pdk_pins),
+               "mx27pdk");
+       mxc_register_device(&mxc_uart_device0, &uart_pdata);
+       platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+}
+
+static void __init mx27pdk_timer_init(void)
+{
+       mx27_clocks_init(26000000);
+}
+
+static struct sys_timer mx27pdk_timer = {
+       .init   = mx27pdk_timer_init,
+};
+
+MACHINE_START(MX27_3DS, "Freescale MX27PDK")
+       /* maintainer: Freescale Semiconductor, Inc. */
+       .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       = mxc_init_irq,
+       .init_machine   = mx27pdk_init,
+       .timer          = &mx27pdk_timer,
+MACHINE_END
index aa4eaa61d1b5852bb58830cfdc6b9121741cc77e..a4628d00434324ae28faa1a35b33261a8e055ab5 100644 (file)
  * MA 02110-1301, USA.
  */
 
-#include <linux/platform_device.h>
-#include <linux/mtd/physmap.h>
-#include <linux/mtd/plat-ram.h>
-#include <linux/io.h>
 #include <linux/i2c.h>
 #include <linux/i2c/at24.h>
+#include <linux/io.h>
+#include <linux/mtd/plat-ram.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
 
-#include <asm/mach/arch.h>
 #include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+#include <mach/board-pcm038.h>
 #include <mach/common.h>
 #include <mach/hardware.h>
-#include <mach/iomux.h>
-#ifdef CONFIG_I2C_IMX
 #include <mach/i2c.h>
-#endif
-#include <asm/mach/time.h>
+#include <mach/iomux.h>
 #include <mach/imx-uart.h>
-#include <mach/board-pcm038.h>
 #include <mach/mxc_nand.h>
 
 #include "devices.h"
 
+static int pcm038_pins[] = {
+       /* UART1 */
+       PE12_PF_UART1_TXD,
+       PE13_PF_UART1_RXD,
+       PE14_PF_UART1_CTS,
+       PE15_PF_UART1_RTS,
+       /* UART2 */
+       PE3_PF_UART2_CTS,
+       PE4_PF_UART2_RTS,
+       PE6_PF_UART2_TXD,
+       PE7_PF_UART2_RXD,
+       /* UART3 */
+       PE8_PF_UART3_TXD,
+       PE9_PF_UART3_RXD,
+       PE10_PF_UART3_CTS,
+       PE11_PF_UART3_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,
+       /* I2C2 */
+       PC5_PF_I2C2_SDA,
+       PC6_PF_I2C2_SCL,
+       /* SPI1 */
+       PD25_PF_CSPI1_RDY,
+       PD27_PF_CSPI1_SS1,
+       PD28_PF_CSPI1_SS0,
+       PD29_PF_CSPI1_SCLK,
+       PD30_PF_CSPI1_MISO,
+       PD31_PF_CSPI1_MOSI,
+       /* SSI1 */
+       PC20_PF_SSI1_FS,
+       PC21_PF_SSI1_RXD,
+       PC22_PF_SSI1_TXD,
+       PC23_PF_SSI1_CLK,
+       /* SSI4 */
+       PC16_PF_SSI4_FS,
+       PC17_PF_SSI4_RXD,
+       PC18_PF_SSI4_TXD,
+       PC19_PF_SSI4_CLK,
+};
+
 /*
  * Phytec's PCM038 comes with 2MiB battery buffered SRAM,
  * 16 bit width
@@ -88,107 +144,16 @@ static struct platform_device pcm038_nor_mtd_device = {
        .resource = &pcm038_flash_resource,
 };
 
-static int mxc_uart0_pins[] = {
-       PE12_PF_UART1_TXD,
-       PE13_PF_UART1_RXD,
-       PE14_PF_UART1_CTS,
-       PE15_PF_UART1_RTS
-};
-
-static int uart_mxc_port0_init(struct platform_device *pdev)
-{
-       return mxc_gpio_setup_multiple_pins(mxc_uart0_pins,
-                       ARRAY_SIZE(mxc_uart0_pins), "UART0");
-}
-
-static int uart_mxc_port0_exit(struct platform_device *pdev)
-{
-       mxc_gpio_release_multiple_pins(mxc_uart0_pins,
-                       ARRAY_SIZE(mxc_uart0_pins));
-       return 0;
-}
-
-static int mxc_uart1_pins[] = {
-       PE3_PF_UART2_CTS,
-       PE4_PF_UART2_RTS,
-       PE6_PF_UART2_TXD,
-       PE7_PF_UART2_RXD
-};
-
-static int uart_mxc_port1_init(struct platform_device *pdev)
-{
-       return mxc_gpio_setup_multiple_pins(mxc_uart1_pins,
-                       ARRAY_SIZE(mxc_uart1_pins), "UART1");
-}
-
-static int uart_mxc_port1_exit(struct platform_device *pdev)
-{
-       mxc_gpio_release_multiple_pins(mxc_uart1_pins,
-                       ARRAY_SIZE(mxc_uart1_pins));
-       return 0;
-}
-
-static int mxc_uart2_pins[] = { PE8_PF_UART3_TXD,
-                               PE9_PF_UART3_RXD,
-                               PE10_PF_UART3_CTS,
-                               PE11_PF_UART3_RTS };
-
-static int uart_mxc_port2_init(struct platform_device *pdev)
-{
-       return mxc_gpio_setup_multiple_pins(mxc_uart2_pins,
-                       ARRAY_SIZE(mxc_uart2_pins), "UART2");
-}
-
-static int uart_mxc_port2_exit(struct platform_device *pdev)
-{
-       mxc_gpio_release_multiple_pins(mxc_uart2_pins,
-                       ARRAY_SIZE(mxc_uart2_pins));
-       return 0;
-}
-
 static struct imxuart_platform_data uart_pdata[] = {
        {
-               .init = uart_mxc_port0_init,
-               .exit = uart_mxc_port0_exit,
                .flags = IMXUART_HAVE_RTSCTS,
        }, {
-               .init = uart_mxc_port1_init,
-               .exit = uart_mxc_port1_exit,
                .flags = IMXUART_HAVE_RTSCTS,
        }, {
-               .init = uart_mxc_port2_init,
-               .exit = uart_mxc_port2_exit,
                .flags = IMXUART_HAVE_RTSCTS,
        },
 };
 
-static int mxc_fec_pins[] = {
-       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
-};
-
-static void gpio_fec_active(void)
-{
-       mxc_gpio_setup_multiple_pins(mxc_fec_pins,
-                       ARRAY_SIZE(mxc_fec_pins), "FEC");
-}
-
 static struct mxc_nand_platform_data pcm038_nand_board_info = {
        .width = 1,
        .hw_ecc = 1,
@@ -210,27 +175,8 @@ static void __init pcm038_init_sram(void)
        __raw_writel(0x22220a00, CSCR_A(1));
 }
 
-#ifdef CONFIG_I2C_IMX
-static int mxc_i2c1_pins[] = {
-       PC5_PF_I2C2_SDA,
-       PC6_PF_I2C2_SCL
-};
-
-static int pcm038_i2c_1_init(struct device *dev)
-{
-       return mxc_gpio_setup_multiple_pins(mxc_i2c1_pins, ARRAY_SIZE(mxc_i2c1_pins),
-                       "I2C1");
-}
-
-static void pcm038_i2c_1_exit(struct device *dev)
-{
-       mxc_gpio_release_multiple_pins(mxc_i2c1_pins, ARRAY_SIZE(mxc_i2c1_pins));
-}
-
 static struct imxi2c_platform_data pcm038_i2c_1_data = {
        .bitrate = 100000,
-       .init = pcm038_i2c_1_init,
-       .exit = pcm038_i2c_1_exit,
 };
 
 static struct at24_platform_data board_eeprom = {
@@ -253,11 +199,12 @@ static struct i2c_board_info pcm038_i2c_devices[] = {
                .type = "lm75"
        }
 };
-#endif
 
 static void __init pcm038_init(void)
 {
-       gpio_fec_active();
+       mxc_gpio_setup_multiple_pins(pcm038_pins, ARRAY_SIZE(pcm038_pins),
+                       "PCM038");
+
        pcm038_init_sram();
 
        mxc_register_device(&mxc_uart_device0, &uart_pdata[0]);
@@ -267,13 +214,11 @@ static void __init pcm038_init(void)
        mxc_gpio_mode(PE16_AF_OWIRE);
        mxc_register_device(&mxc_nand_device, &pcm038_nand_board_info);
 
-#ifdef CONFIG_I2C_IMX
        /* only the i2c master 1 is used on this CPU card */
        i2c_register_board_info(1, pcm038_i2c_devices,
                                ARRAY_SIZE(pcm038_i2c_devices));
 
        mxc_register_device(&mxc_i2c_device1, &pcm038_i2c_1_data);
-#endif
 
        platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 
@@ -295,7 +240,7 @@ MACHINE_START(PCM038, "phyCORE-i.MX27")
        .phys_io        = AIPI_BASE_ADDR,
        .io_pg_offst    = ((AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
        .boot_params    = PHYS_OFFSET + 0x100,
-       .map_io         = mxc_map_io,
+       .map_io         = mx27_map_io,
        .init_irq       = mxc_init_irq,
        .init_machine   = pcm038_init,
        .timer          = &pcm038_timer,
index bf4e520bc1bc604e424fa549ffe6f70eb1ab825e..6a3acaf57dd44ba9e06e8907aa3a990115fe197a 100644 (file)
  * MA 02110-1301, USA.
  */
 
-#include <linux/platform_device.h>
 #include <linux/gpio.h>
 #include <linux/irq.h>
+#include <linux/platform_device.h>
 
 #include <asm/mach/arch.h>
 
-#include <mach/hardware.h>
 #include <mach/common.h>
-#include <mach/mmc.h>
-#include <mach/imxfb.h>
 #include <mach/iomux.h>
+#include <mach/imxfb.h>
+#include <mach/hardware.h>
+#include <mach/mmc.h>
 
 #include "devices.h"
 
-static int pcm970_sdhc2_get_ro(struct device *dev)
-{
-       return gpio_get_value(GPIO_PORTC + 28);
-}
-
-static int pcm970_sdhc2_pins[] = {
+static int pcm970_pins[] = {
+       /* SDHC */
        PB4_PF_SD2_D0,
        PB5_PF_SD2_D1,
        PB6_PF_SD2_D2,
        PB7_PF_SD2_D3,
        PB8_PF_SD2_CMD,
        PB9_PF_SD2_CLK,
+       GPIO_PORTC | 28 | GPIO_GPIO | GPIO_IN, /* card detect */
+       /* display */
+       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,
+       PA24_PF_REV,
+       PA25_PF_CLS,
+       PA26_PF_PS,
+       PA27_PF_SPL_SPR,
+       PA28_PF_HSYNC,
+       PA29_PF_VSYNC,
+       PA30_PF_CONTRAST,
+       PA31_PF_OE_ACD,
+       /*
+        * it seems the data line misses a pullup, so we must enable
+        * the internal pullup as a local workaround
+        */
+       PD17_PF_I2C_DATA | GPIO_PUEN,
+       PD18_PF_I2C_CLK,
+       /* Camera */
+       PB10_PF_CSI_D0,
+       PB11_PF_CSI_D1,
+       PB12_PF_CSI_D2,
+       PB13_PF_CSI_D3,
+       PB14_PF_CSI_D4,
+       PB15_PF_CSI_MCLK,
+       PB16_PF_CSI_PIXCLK,
+       PB17_PF_CSI_D5,
+       PB18_PF_CSI_D6,
+       PB19_PF_CSI_D7,
+       PB20_PF_CSI_VSYNC,
+       PB21_PF_CSI_HSYNC,
 };
 
+static int pcm970_sdhc2_get_ro(struct device *dev)
+{
+       return gpio_get_value(GPIO_PORTC + 28);
+}
+
 static int pcm970_sdhc2_init(struct device *dev, irq_handler_t detect_irq, void *data)
 {
        int ret;
 
-       ret = mxc_gpio_setup_multiple_pins(pcm970_sdhc2_pins,
-               ARRAY_SIZE(pcm970_sdhc2_pins), "sdhc2");
-       if(ret)
-               return ret;
-
-       ret = request_irq(IRQ_GPIOC(29), detect_irq, 0,
+       ret = request_irq(IRQ_GPIOC(29), detect_irq, IRQF_TRIGGER_FALLING,
                                "imx-mmc-detect", data);
        if (ret)
-               goto out_release_gpio;
-
-       set_irq_type(IRQ_GPIOC(29), IRQF_TRIGGER_FALLING);
+               return ret;
 
        ret = gpio_request(GPIO_PORTC + 28, "imx-mmc-ro");
-       if (ret)
-               goto out_release_gpio;
+       if (ret) {
+               free_irq(IRQ_GPIOC(29), data);
+               return ret;
+       }
 
-       mxc_gpio_mode((GPIO_PORTC | 28) | GPIO_GPIO | GPIO_IN);
        gpio_direction_input(GPIO_PORTC + 28);
 
        return 0;
-
-out_release_gpio:
-       mxc_gpio_release_multiple_pins(pcm970_sdhc2_pins,
-                       ARRAY_SIZE(pcm970_sdhc2_pins));
-       return ret;
 }
 
 static void pcm970_sdhc2_exit(struct device *dev, void *data)
 {
        free_irq(IRQ_GPIOC(29), data);
        gpio_free(GPIO_PORTC + 28);
-       mxc_gpio_release_multiple_pins(pcm970_sdhc2_pins,
-                       ARRAY_SIZE(pcm970_sdhc2_pins));
 }
 
 static struct imxmmc_platform_data sdhc_pdata = {
@@ -89,29 +125,6 @@ static struct imxmmc_platform_data sdhc_pdata = {
        .exit = pcm970_sdhc2_exit,
 };
 
-static int mxc_fb_pins[] = {
-       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,   PA24_PF_REV,
-       PA25_PF_CLS,    PA26_PF_PS,     PA27_PF_SPL_SPR, PA28_PF_HSYNC,
-       PA29_PF_VSYNC,  PA30_PF_CONTRAST, PA31_PF_OE_ACD
-};
-
-static int pcm038_fb_init(struct platform_device *pdev)
-{
-       return mxc_gpio_setup_multiple_pins(mxc_fb_pins,
-                       ARRAY_SIZE(mxc_fb_pins), "FB");
-}
-
-static int pcm038_fb_exit(struct platform_device *pdev)
-{
-       mxc_gpio_release_multiple_pins(mxc_fb_pins, ARRAY_SIZE(mxc_fb_pins));
-
-       return 0;
-}
-
 /*
  * Connected is a portrait Sharp-QVGA display
  * of type: LQ035Q7DH06
@@ -144,9 +157,6 @@ static struct imx_fb_platform_data pcm038_fb_data = {
        .pwmr           = 0x00A903FF,
        .lscr1          = 0x00120300,
        .dmacr          = 0x00020010,
-
-       .init = pcm038_fb_init,
-       .exit = pcm038_fb_exit,
 };
 
 /*
@@ -157,6 +167,9 @@ static struct imx_fb_platform_data pcm038_fb_data = {
  */
 void __init pcm970_baseboard_init(void)
 {
+       mxc_gpio_setup_multiple_pins(pcm970_pins, ARRAY_SIZE(pcm970_pins),
+                       "PCM970");
+
        mxc_register_device(&mxc_fb_device, &pcm038_fb_data);
        mxc_register_device(&mxc_sdhc_device1, &sdhc_pdata);
 }
index 194b8428bba48ba327e88a4327381d6a062d5a5d..17a21a291e2f6eb7d9bdb7593e76f2c2ecac2cc4 100644 (file)
@@ -1,10 +1,12 @@
 if ARCH_MX3
 
 config ARCH_MX31
+       select ARCH_HAS_RNGA
        bool
 
 config ARCH_MX35
        bool
+       select ARCH_MXC_IOMUX_V3
 
 comment "MX3 platforms:"
 
@@ -37,7 +39,6 @@ config MACH_PCM037
 config MACH_MX31LITE
        bool "Support MX31 LITEKIT (LogicPD)"
        select ARCH_MX31
-       default n
        help
          Include support for MX31 LITEKIT platform. This includes specific
          configurations for the board and its peripherals.
@@ -45,7 +46,6 @@ config MACH_MX31LITE
 config MACH_MX31_3DS
        bool "Support MX31PDK (3DS)"
        select ARCH_MX31
-       default n
        help
          Include support for MX31PDK (3DS) platform. This includes specific
          configurations for the board and its peripherals.
@@ -53,17 +53,43 @@ config MACH_MX31_3DS
 config MACH_MX31MOBOARD
        bool "Support mx31moboard platforms (EPFL Mobots group)"
        select ARCH_MX31
-       default n
        help
          Include support for mx31moboard platform. This includes specific
          configurations for the board and its peripherals.
 
+config MACH_MX31LILLY
+       bool "Support MX31 LILLY-1131 platforms (INCO startec)"
+       select ARCH_MX31
+       help
+         Include support for mx31 based LILLY1131 modules. This includes
+         specific configurations for the board and its peripherals.
+
 config MACH_QONG
        bool "Support Dave/DENX QongEVB-LITE platform"
        select ARCH_MX31
-       default n
        help
          Include support for Dave/DENX QongEVB-LITE platform. This includes
          specific configurations for the board and its peripherals.
 
+config MACH_PCM043
+       bool "Support Phytec pcm043 (i.MX35) platforms"
+       select ARCH_MX35
+       help
+         Include support for Phytec pcm043 platform. This includes
+         specific configurations for the board and its peripherals.
+
+config MACH_ARMADILLO5X0
+       bool "Support Atmark Armadillo-500 Development Base Board"
+       select ARCH_MX31
+       help
+         Include support for Atmark Armadillo-500 platform. This includes
+         specific configurations for the board and its peripherals.
+
+config MACH_MX35_3DS
+       bool "Support MX35PDK platform"
+       select ARCH_MX35
+       default n
+       help
+         Include support for MX35PDK platform. This includes specific
+         configurations for the board and its peripherals.
 endif
index 272c8a953b30cd5f5302e5284d74c6171b2d99fe..0322696bd11a19ad0402852b8858efe3750c6303 100644 (file)
@@ -8,9 +8,13 @@ obj-y                          := mm.o devices.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_PCM037)      += pcm037.o
 obj-$(CONFIG_MACH_MX31_3DS)    += mx31pdk.o
 obj-$(CONFIG_MACH_MX31MOBOARD) += mx31moboard.o mx31moboard-devboard.o \
                                   mx31moboard-marxbot.o
 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
diff --git a/arch/arm/mach-mx3/armadillo5x0.c b/arch/arm/mach-mx3/armadillo5x0.c
new file mode 100644 (file)
index 0000000..5411810
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * armadillo5x0.c
+ *
+ * Copyright 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com>
+ * updates in http://alberdroid.blogspot.com/
+ *
+ * Based on Atmark Techno, Inc. armadillo 500 BSP 2008
+ * Based on mx31ads.c and pcm037.c Great Work!
+ *
+ * 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/types.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/smsc911x.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/memory.h>
+#include <asm/mach/map.h>
+
+#include <mach/common.h>
+#include <mach/imx-uart.h>
+#include <mach/iomux-mx3.h>
+#include <mach/board-armadillo5x0.h>
+#include <mach/mmc.h>
+#include <mach/ipu.h>
+#include <mach/mx3fb.h>
+
+#include "devices.h"
+
+static int armadillo5x0_pins[] = {
+       /* UART1 */
+       MX31_PIN_CTS1__CTS1,
+       MX31_PIN_RTS1__RTS1,
+       MX31_PIN_TXD1__TXD1,
+       MX31_PIN_RXD1__RXD1,
+       /* UART2 */
+       MX31_PIN_CTS2__CTS2,
+       MX31_PIN_RTS2__RTS2,
+       MX31_PIN_TXD2__TXD2,
+       MX31_PIN_RXD2__RXD2,
+       /* LAN9118_IRQ */
+       IOMUX_MODE(MX31_PIN_GPIO1_0, IOMUX_CONFIG_GPIO),
+       /* SDHC1 */
+       MX31_PIN_SD1_DATA3__SD1_DATA3,
+       MX31_PIN_SD1_DATA2__SD1_DATA2,
+       MX31_PIN_SD1_DATA1__SD1_DATA1,
+       MX31_PIN_SD1_DATA0__SD1_DATA0,
+       MX31_PIN_SD1_CLK__SD1_CLK,
+       MX31_PIN_SD1_CMD__SD1_CMD,
+       /* Framebuffer */
+       MX31_PIN_LD0__LD0,
+       MX31_PIN_LD1__LD1,
+       MX31_PIN_LD2__LD2,
+       MX31_PIN_LD3__LD3,
+       MX31_PIN_LD4__LD4,
+       MX31_PIN_LD5__LD5,
+       MX31_PIN_LD6__LD6,
+       MX31_PIN_LD7__LD7,
+       MX31_PIN_LD8__LD8,
+       MX31_PIN_LD9__LD9,
+       MX31_PIN_LD10__LD10,
+       MX31_PIN_LD11__LD11,
+       MX31_PIN_LD12__LD12,
+       MX31_PIN_LD13__LD13,
+       MX31_PIN_LD14__LD14,
+       MX31_PIN_LD15__LD15,
+       MX31_PIN_LD16__LD16,
+       MX31_PIN_LD17__LD17,
+       MX31_PIN_VSYNC3__VSYNC3,
+       MX31_PIN_HSYNC__HSYNC,
+       MX31_PIN_FPSHIFT__FPSHIFT,
+       MX31_PIN_DRDY0__DRDY0,
+       IOMUX_MODE(MX31_PIN_LCS1, IOMUX_CONFIG_GPIO), /*ADV7125_PSAVE*/
+
+};
+
+/*
+ * FB support
+ */
+static const struct fb_videomode fb_modedb[] = {
+       {       /* 640x480 @ 60 Hz */
+               .name           = "CRT-VGA",
+               .refresh        = 60,
+               .xres           = 640,
+               .yres           = 480,
+               .pixclock       = 39721,
+               .left_margin    = 35,
+               .right_margin   = 115,
+               .upper_margin   = 43,
+               .lower_margin   = 1,
+               .hsync_len      = 10,
+               .vsync_len      = 1,
+               .sync           = FB_SYNC_OE_ACT_HIGH,
+               .vmode          = FB_VMODE_NONINTERLACED,
+               .flag           = 0,
+       }, {/* 800x600 @ 56 Hz */
+               .name           = "CRT-SVGA",
+               .refresh        = 56,
+               .xres           = 800,
+               .yres           = 600,
+               .pixclock       = 30000,
+               .left_margin    = 30,
+               .right_margin   = 108,
+               .upper_margin   = 13,
+               .lower_margin   = 10,
+               .hsync_len      = 10,
+               .vsync_len      = 1,
+               .sync           = FB_SYNC_OE_ACT_HIGH | FB_SYNC_HOR_HIGH_ACT |
+                                 FB_SYNC_VERT_HIGH_ACT,
+               .vmode          = FB_VMODE_NONINTERLACED,
+               .flag           = 0,
+       },
+};
+
+static struct ipu_platform_data mx3_ipu_data = {
+       .irq_base = MXC_IPU_IRQ_START,
+};
+
+static struct mx3fb_platform_data mx3fb_pdata = {
+       .dma_dev        = &mx3_ipu.dev,
+       .name           = "CRT-VGA",
+       .mode           = fb_modedb,
+       .num_modes      = ARRAY_SIZE(fb_modedb),
+};
+
+/*
+ * SDHC 1
+ * MMC support
+ */
+static int armadillo5x0_sdhc1_get_ro(struct device *dev)
+{
+       return gpio_get_value(IOMUX_TO_GPIO(MX31_PIN_ATA_RESET_B));
+}
+
+static int armadillo5x0_sdhc1_init(struct device *dev,
+                                  irq_handler_t detect_irq, void *data)
+{
+       int ret;
+       int gpio_det, gpio_wp;
+
+       gpio_det = IOMUX_TO_GPIO(MX31_PIN_ATA_DMACK);
+       gpio_wp = IOMUX_TO_GPIO(MX31_PIN_ATA_RESET_B);
+
+       ret = gpio_request(gpio_det, "sdhc-card-detect");
+       if (ret)
+               return ret;
+
+       gpio_direction_input(gpio_det);
+
+       ret = gpio_request(gpio_wp, "sdhc-write-protect");
+       if (ret)
+               goto err_gpio_free;
+
+       gpio_direction_input(gpio_wp);
+
+       /* When supported the trigger type have to be BOTH */
+       ret = request_irq(IOMUX_TO_IRQ(MX31_PIN_ATA_DMACK), detect_irq,
+                         IRQF_DISABLED | IRQF_TRIGGER_FALLING,
+                         "sdhc-detect", data);
+
+       if (ret)
+               goto err_gpio_free_2;
+
+       return 0;
+
+err_gpio_free_2:
+       gpio_free(gpio_wp);
+
+err_gpio_free:
+       gpio_free(gpio_det);
+
+       return ret;
+
+}
+
+static void armadillo5x0_sdhc1_exit(struct device *dev, void *data)
+{
+       free_irq(IOMUX_TO_IRQ(MX31_PIN_ATA_DMACK), data);
+       gpio_free(IOMUX_TO_GPIO(MX31_PIN_ATA_DMACK));
+       gpio_free(IOMUX_TO_GPIO(MX31_PIN_ATA_RESET_B));
+}
+
+static struct imxmmc_platform_data sdhc_pdata = {
+       .get_ro = armadillo5x0_sdhc1_get_ro,
+       .init = armadillo5x0_sdhc1_init,
+       .exit = armadillo5x0_sdhc1_exit,
+};
+
+/*
+ * SMSC 9118
+ * Network support
+ */
+static struct resource armadillo5x0_smc911x_resources[] = {
+       {
+               .start  = CS3_BASE_ADDR,
+               .end    = CS3_BASE_ADDR + SZ_32M - 1,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = IOMUX_TO_IRQ(MX31_PIN_GPIO1_0),
+               .end    = IOMUX_TO_IRQ(MX31_PIN_GPIO1_0),
+               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+       },
+};
+
+static struct smsc911x_platform_config smsc911x_info = {
+       .flags          = SMSC911X_USE_32BIT,
+       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+       .irq_type       = SMSC911X_IRQ_TYPE_PUSH_PULL,
+};
+
+static struct platform_device armadillo5x0_smc911x_device = {
+       .name           = "smsc911x",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(armadillo5x0_smc911x_resources),
+       .resource       = armadillo5x0_smc911x_resources,
+       .dev            = {
+               .platform_data = &smsc911x_info,
+       },
+};
+
+/* UART device data */
+static struct imxuart_platform_data uart_pdata = {
+       .flags = IMXUART_HAVE_RTSCTS,
+};
+
+static struct platform_device *devices[] __initdata = {
+       &armadillo5x0_smc911x_device,
+};
+
+/*
+ * Perform board specific initializations
+ */
+static void __init armadillo5x0_init(void)
+{
+       mxc_iomux_setup_multiple_pins(armadillo5x0_pins,
+                       ARRAY_SIZE(armadillo5x0_pins), "armadillo5x0");
+
+       platform_add_devices(devices, ARRAY_SIZE(devices));
+
+       /* Register UART */
+       mxc_register_device(&mxc_uart_device0, &uart_pdata);
+       mxc_register_device(&mxc_uart_device1, &uart_pdata);
+
+       /* SMSC9118 IRQ pin */
+       gpio_direction_input(MX31_PIN_GPIO1_0);
+
+       /* Register SDHC */
+       mxc_register_device(&mxcsdhc_device0, &sdhc_pdata);
+
+       /* Register FB */
+       mxc_register_device(&mx3_ipu, &mx3_ipu_data);
+       mxc_register_device(&mx3_fb, &mx3fb_pdata);
+}
+
+static void __init armadillo5x0_timer_init(void)
+{
+       mx31_clocks_init(26000000);
+}
+
+static struct sys_timer armadillo5x0_timer = {
+       .init   = armadillo5x0_timer_init,
+};
+
+MACHINE_START(ARMADILLO5X0, "Armadillo-500")
+       /* Maintainer: Alberto Panizzo  */
+       .phys_io        = AIPS1_BASE_ADDR,
+       .io_pg_offst    = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
+       .boot_params    = PHYS_OFFSET + 0x00000100,
+       .map_io         = mx31_map_io,
+       .init_irq       = mxc_init_irq,
+       .timer          = &armadillo5x0_timer,
+       .init_machine   = armadillo5x0_init,
+MACHINE_END
index 3c1e06f56dd6ca60764d3f9ec349f1e1e926c8f3..577ee83d1f605eb748ea2921032b5901942f8529 100644 (file)
@@ -147,34 +147,16 @@ static struct arm_ahb_div clk_consumer[] = {
        { .arm = 0, .ahb = 0, .sel = 0},
 };
 
-static struct arm_ahb_div clk_automotive[] = {
-       { .arm = 1, .ahb = 3, .sel = 0},
-       { .arm = 1, .ahb = 2, .sel = 1},
-       { .arm = 2, .ahb = 1, .sel = 1},
-       { .arm = 0, .ahb = 0, .sel = 0},
-       { .arm = 1, .ahb = 6, .sel = 0},
-       { .arm = 1, .ahb = 4, .sel = 1},
-       { .arm = 2, .ahb = 2, .sel = 1},
-       { .arm = 0, .ahb = 0, .sel = 0},
-};
-
 static unsigned long get_rate_arm(void)
 {
        unsigned long pdr0 = __raw_readl(CCM_BASE + CCM_PDR0);
        struct arm_ahb_div *aad;
        unsigned long fref = get_rate_mpll();
 
-       if (pdr0 & 1) {
-               /* consumer path */
-               aad = &clk_consumer[(pdr0 >> 16) & 0xf];
-               if (aad->sel)
-                       fref = fref * 2 / 3;
-       } else {
-               /* auto path */
-               aad = &clk_automotive[(pdr0 >> 9) & 0x7];
-               if (aad->sel)
-                       fref = fref * 3 / 4;
-       }
+       aad = &clk_consumer[(pdr0 >> 16) & 0xf];
+       if (aad->sel)
+               fref = fref * 2 / 3;
+
        return fref / aad->arm;
 }
 
@@ -184,12 +166,7 @@ static unsigned long get_rate_ahb(struct clk *clk)
        struct arm_ahb_div *aad;
        unsigned long fref = get_rate_mpll();
 
-       if (pdr0 & 1)
-               /* consumer path */
-               aad = &clk_consumer[(pdr0 >> 16) & 0xf];
-       else
-               /* auto path */
-               aad = &clk_automotive[(pdr0 >> 9) & 0x7];
+       aad = &clk_consumer[(pdr0 >> 16) & 0xf];
 
        return fref / aad->ahb;
 }
@@ -430,7 +407,8 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk)
        _REGISTER_CLOCK("imx-i2c.2", NULL, i2c3_clk)
        _REGISTER_CLOCK(NULL, "iomuxc", iomuxc_clk)
-       _REGISTER_CLOCK(NULL, "ipu", ipu_clk)
+       _REGISTER_CLOCK("ipu-core", NULL, ipu_clk)
+       _REGISTER_CLOCK("mx3_sdc_fb", NULL, ipu_clk)
        _REGISTER_CLOCK(NULL, "kpp", kpp_clk)
        _REGISTER_CLOCK(NULL, "mlb", mlb_clk)
        _REGISTER_CLOCK(NULL, "mshc", mshc_clk)
@@ -462,8 +440,6 @@ int __init mx35_clocks_init()
        int i;
        unsigned int ll = 0;
 
-       mxc_set_cpu_type(MXC_CPU_MX35);
-
 #ifdef CONFIG_DEBUG_LL_CONSOLE
        ll = (3 << 16);
 #endif
index a68fcf981edf124678efa99695cf7efe6cd2cbc4..8b14239724c97fe90746878f6c3727f62bdf7066 100644 (file)
@@ -483,7 +483,7 @@ DEFINE_CLOCK(i2c3_clk,    2, MXC_CCM_CGR0, 30, NULL, NULL, &perclk_clk);
 DEFINE_CLOCK(mpeg4_clk,   0, MXC_CCM_CGR1,  0, NULL, NULL, &ahb_clk);
 DEFINE_CLOCK(mstick1_clk, 0, MXC_CCM_CGR1,  2, mstick1_get_rate, NULL, &usb_pll_clk);
 DEFINE_CLOCK(mstick2_clk, 1, MXC_CCM_CGR1,  4, mstick2_get_rate, NULL, &usb_pll_clk);
-DEFINE_CLOCK1(csi_clk,    0, MXC_CCM_CGR1,  6, csi, NULL, &ahb_clk);
+DEFINE_CLOCK1(csi_clk,    0, MXC_CCM_CGR1,  6, csi, NULL, &serial_pll_clk);
 DEFINE_CLOCK(rtc_clk,     0, MXC_CCM_CGR1,  8, NULL, NULL, &ipg_clk);
 DEFINE_CLOCK(wdog_clk,    0, MXC_CCM_CGR1, 10, NULL, NULL, &ipg_clk);
 DEFINE_CLOCK(pwm_clk,     0, MXC_CCM_CGR1, 12, NULL, NULL, &perclk_clk);
@@ -566,13 +566,18 @@ int __init mx31_clocks_init(unsigned long fref)
        u32 reg;
        int i;
 
-       mxc_set_cpu_type(MXC_CPU_MX31);
-
        ckih_rate = fref;
 
        for (i = 0; i < ARRAY_SIZE(lookups); i++)
                clkdev_add(&lookups[i]);
 
+       /* change the csi_clk parent if necessary */
+       reg = __raw_readl(MXC_CCM_CCMR);
+       if (!(reg & MXC_CCM_CCMR_CSCS))
+               if (clk_set_parent(&csi_clk, &usb_pll_clk))
+                       pr_err("%s: error changing csi_clk parent\n", __func__);
+
+
        /* Turn off all possible clocks */
        __raw_writel((3 << 4), MXC_CCM_CGR0);
        __raw_writel(0, MXC_CCM_CGR1);
@@ -581,6 +586,12 @@ int __init mx31_clocks_init(unsigned long fref)
                                           MX32, but still required to be set */
                     MXC_CCM_CGR2);
 
+       /*
+        * Before turning off usb_pll make sure ipg_per_clk is generated
+        * by ipg_clk and not usb_pll.
+        */
+       __raw_writel(__raw_readl(MXC_CCM_CCMR) | (1 << 24), MXC_CCM_CCMR);
+
        usb_pll_disable(&usb_pll_clk);
 
        pr_info("Clock input source is %ld\n", clk_get_rate(&ckih_clk));
index 380be0c9b213f2e7904e418067f83cbec1518b60..d927eddcad460432200db70adf10ae4a5263f55e 100644 (file)
  * Boston, MA  02110-1301, USA.
  */
 
+#include <linux/dma-mapping.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/serial.h>
 #include <linux/gpio.h>
+#include <linux/dma-mapping.h>
 #include <mach/hardware.h>
 #include <mach/irqs.h>
+#include <mach/common.h>
 #include <mach/imx-uart.h>
+#include <mach/mx3_camera.h>
 
 #include "devices.h"
 
@@ -283,6 +287,21 @@ struct platform_device mxcsdhc_device1 = {
        .num_resources = ARRAY_SIZE(mxcsdhc1_resources),
        .resource = mxcsdhc1_resources,
 };
+
+static struct resource rnga_resources[] = {
+       {
+               .start = RNGA_BASE_ADDR,
+               .end = RNGA_BASE_ADDR + 0x28,
+               .flags = IORESOURCE_MEM,
+       },
+};
+
+struct platform_device mxc_rnga_device = {
+       .name = "mxc_rnga",
+       .id = -1,
+       .num_resources = 1,
+       .resource = rnga_resources,
+};
 #endif /* CONFIG_ARCH_MX31 */
 
 /* i.MX31 Image Processing Unit */
@@ -329,10 +348,54 @@ struct platform_device mx3_fb = {
        .num_resources  = ARRAY_SIZE(fb_resources),
        .resource       = fb_resources,
        .dev            = {
-               .coherent_dma_mask = 0xffffffff,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
        },
 };
 
+static struct resource camera_resources[] = {
+       {
+               .start  = IPU_CTRL_BASE_ADDR + 0x60,
+               .end    = IPU_CTRL_BASE_ADDR + 0x87,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+struct platform_device mx3_camera = {
+       .name           = "mx3-camera",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(camera_resources),
+       .resource       = camera_resources,
+       .dev            = {
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+       },
+};
+
+static struct resource otg_resources[] = {
+       {
+               .start  = OTG_BASE_ADDR,
+               .end    = OTG_BASE_ADDR + 0x1ff,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = MXC_INT_USB3,
+               .end    = MXC_INT_USB3,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static u64 otg_dmamask = DMA_BIT_MASK(32);
+
+/* OTG gadget device */
+struct platform_device mxc_otg_udc_device = {
+       .name           = "fsl-usb2-udc",
+       .id             = -1,
+       .dev            = {
+               .dma_mask               = &otg_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+       .resource       = otg_resources,
+       .num_resources  = ARRAY_SIZE(otg_resources),
+};
+
 #ifdef CONFIG_ARCH_MX35
 static struct resource mxc_fec_resources[] = {
        {
@@ -359,6 +422,7 @@ static int mx3_devices_init(void)
        if (cpu_is_mx31()) {
                mxc_nand_resources[0].start = MX31_NFC_BASE_ADDR;
                mxc_nand_resources[0].end = MX31_NFC_BASE_ADDR + 0xfff;
+               mxc_register_device(&mxc_rnga_device, NULL);
        }
        if (cpu_is_mx35()) {
                mxc_nand_resources[0].start = MX35_NFC_BASE_ADDR;
index 88c04b296fabc3ce2ee6ad3669e7d0bcc9c0edd6..ffd494ddd4ace8ffb5613f0e43c94fe75f59a730 100644 (file)
@@ -11,6 +11,10 @@ extern struct platform_device mxc_i2c_device1;
 extern struct platform_device mxc_i2c_device2;
 extern struct platform_device mx3_ipu;
 extern struct platform_device mx3_fb;
+extern struct platform_device mx3_camera;
 extern struct platform_device mxc_fec_device;
 extern struct platform_device mxcsdhc_device0;
 extern struct platform_device mxcsdhc_device1;
+extern struct platform_device mxc_otg_udc_device;
+extern struct platform_device mxc_rnga_device;
+
index 40ffc5a664d93231c176956f0a3c927a6631a787..c66ccbcdc11b820a3b1d7bf57b53452c4d00f648 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/io.h>
-#include <linux/gpio.h>
 #include <linux/kernel.h>
 #include <mach/hardware.h>
 #include <mach/gpio.h>
@@ -94,15 +93,13 @@ void mxc_iomux_set_pad(enum iomux_pins pin, u32 config)
 EXPORT_SYMBOL(mxc_iomux_set_pad);
 
 /*
- * setups a single pin:
+ * allocs a single pin:
  *     - reserves the pin so that it is not claimed by another driver
  *     - setups the iomux according to the configuration
- *     - if the pin is configured as a GPIO, we claim it through kernel gpiolib
  */
-int mxc_iomux_setup_pin(const unsigned int pin, const char *label)
+int mxc_iomux_alloc_pin(const unsigned int pin, const char *label)
 {
        unsigned pad = pin & IOMUX_PADNUM_MASK;
-       unsigned gpio;
 
        if (pad >= (PIN_MAX + 1)) {
                printk(KERN_ERR "mxc_iomux: Attempt to request nonexistant pin %u for \"%s\"\n",
@@ -113,19 +110,13 @@ int mxc_iomux_setup_pin(const unsigned int pin, const char *label)
        if (test_and_set_bit(pad, mxc_pin_alloc_map)) {
                printk(KERN_ERR "mxc_iomux: pin %u already used. Allocation for \"%s\" failed\n",
                        pad, label ? label : "?");
-               return -EINVAL;
+               return -EBUSY;
        }
        mxc_iomux_mode(pin);
 
-       /* if we have a gpio, we can allocate it */
-       gpio = (pin & IOMUX_GPIONUM_MASK) >> IOMUX_GPIONUM_SHIFT;
-       if (gpio < (GPIO_PORT_MAX + 1) * 32)
-               if (gpio_request(gpio, label))
-                       return -EINVAL;
-
        return 0;
 }
-EXPORT_SYMBOL(mxc_iomux_setup_pin);
+EXPORT_SYMBOL(mxc_iomux_alloc_pin);
 
 int mxc_iomux_setup_multiple_pins(unsigned int *pin_list, unsigned count,
                const char *label)
@@ -135,7 +126,8 @@ int mxc_iomux_setup_multiple_pins(unsigned int *pin_list, unsigned count,
        int ret = -EINVAL;
 
        for (i = 0; i < count; i++) {
-               if (mxc_iomux_setup_pin(*p, label))
+               ret = mxc_iomux_alloc_pin(*p, label);
+               if (ret)
                        goto setup_error;
                p++;
        }
@@ -150,14 +142,9 @@ EXPORT_SYMBOL(mxc_iomux_setup_multiple_pins);
 void mxc_iomux_release_pin(const unsigned int pin)
 {
        unsigned pad = pin & IOMUX_PADNUM_MASK;
-       unsigned gpio;
 
        if (pad < (PIN_MAX + 1))
                clear_bit(pad, mxc_pin_alloc_map);
-
-       gpio = (pin & IOMUX_GPIONUM_MASK) >> IOMUX_GPIONUM_SHIFT;
-       if (gpio < (GPIO_PORT_MAX + 1) * 32)
-               gpio_free(gpio);
 }
 EXPORT_SYMBOL(mxc_iomux_release_pin);
 
index 9e1459cb4b74891d960baff040476f9d322e6449..1f5fdd456cb987eed24908cc97b6e00b71f13819 100644 (file)
@@ -72,8 +72,17 @@ static struct map_desc mxc_io_desc[] __initdata = {
  * system startup to create static physical to virtual memory mappings
  * for the IO modules.
  */
-void __init mxc_map_io(void)
+void __init mx31_map_io(void)
 {
+       mxc_set_cpu_type(MXC_CPU_MX31);
+
+       iotable_init(mxc_io_desc, ARRAY_SIZE(mxc_io_desc));
+}
+
+void __init mx35_map_io(void)
+{
+       mxc_set_cpu_type(MXC_CPU_MX35);
+
        iotable_init(mxc_io_desc, ARRAY_SIZE(mxc_io_desc));
 }
 
index a6d6efefa6aa6ea468d08978ad45025e272bb308..30e2767a78ae4771b59ac1a1648374d5d7bc0622 100644 (file)
@@ -187,7 +187,7 @@ static void __init mx31ads_init_expio(void)
        /*
         * Configure INT line as GPIO input
         */
-       mxc_iomux_setup_pin(IOMUX_MODE(MX31_PIN_GPIO1_4, IOMUX_CONFIG_GPIO), "expio");
+       mxc_iomux_alloc_pin(IOMUX_MODE(MX31_PIN_GPIO1_4, IOMUX_CONFIG_GPIO), "expio");
 
        /* disable the interrupt and clear the status */
        __raw_writew(0xFFFF, PBC_INTMASK_CLEAR_REG);
@@ -511,7 +511,7 @@ static struct map_desc mx31ads_io_desc[] __initdata = {
  */
 static void __init mx31ads_map_io(void)
 {
-       mxc_map_io();
+       mx31_map_io();
        iotable_init(mx31ads_io_desc, ARRAY_SIZE(mx31ads_io_desc));
 }
 
diff --git a/arch/arm/mach-mx3/mx31lilly-db.c b/arch/arm/mach-mx3/mx31lilly-db.c
new file mode 100644 (file)
index 0000000..3b3a78f
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ *  LILLY-1131 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 <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-mx31lilly.h>
+#include <mach/mmc.h>
+#include <mach/mx3fb.h>
+#include <mach/ipu.h>
+
+#include "devices.h"
+
+/*
+ * This file contains board-specific initialization routines for the
+ * LILLY-1131 development board. If you design an own baseboard for the
+ * module, use this file as base for support code.
+ */
+
+static unsigned int lilly_db_board_pins[] __initdata = {
+       MX31_PIN_CTS1__CTS1,
+       MX31_PIN_RTS1__RTS1,
+       MX31_PIN_TXD1__TXD1,
+       MX31_PIN_RXD1__RXD1,
+       MX31_PIN_CTS2__CTS2,
+       MX31_PIN_RTS2__RTS2,
+       MX31_PIN_TXD2__TXD2,
+       MX31_PIN_RXD2__RXD2,
+       MX31_PIN_CSPI3_MOSI__RXD3,
+       MX31_PIN_CSPI3_MISO__TXD3,
+       MX31_PIN_CSPI3_SCLK__RTS3,
+       MX31_PIN_CSPI3_SPI_RDY__CTS3,
+       MX31_PIN_SD1_DATA3__SD1_DATA3,
+       MX31_PIN_SD1_DATA2__SD1_DATA2,
+       MX31_PIN_SD1_DATA1__SD1_DATA1,
+       MX31_PIN_SD1_DATA0__SD1_DATA0,
+       MX31_PIN_SD1_CLK__SD1_CLK,
+       MX31_PIN_SD1_CMD__SD1_CMD,
+       MX31_PIN_LD0__LD0,
+       MX31_PIN_LD1__LD1,
+       MX31_PIN_LD2__LD2,
+       MX31_PIN_LD3__LD3,
+       MX31_PIN_LD4__LD4,
+       MX31_PIN_LD5__LD5,
+       MX31_PIN_LD6__LD6,
+       MX31_PIN_LD7__LD7,
+       MX31_PIN_LD8__LD8,
+       MX31_PIN_LD9__LD9,
+       MX31_PIN_LD10__LD10,
+       MX31_PIN_LD11__LD11,
+       MX31_PIN_LD12__LD12,
+       MX31_PIN_LD13__LD13,
+       MX31_PIN_LD14__LD14,
+       MX31_PIN_LD15__LD15,
+       MX31_PIN_LD16__LD16,
+       MX31_PIN_LD17__LD17,
+       MX31_PIN_VSYNC3__VSYNC3,
+       MX31_PIN_HSYNC__HSYNC,
+       MX31_PIN_FPSHIFT__FPSHIFT,
+       MX31_PIN_DRDY0__DRDY0,
+       MX31_PIN_CONTRAST__CONTRAST,
+};
+
+/* UART */
+static struct imxuart_platform_data uart_pdata __initdata = {
+       .flags = IMXUART_HAVE_RTSCTS,
+};
+
+/* MMC support */
+
+static int mxc_mmc1_get_ro(struct device *dev)
+{
+       return gpio_get_value(IOMUX_TO_GPIO(MX31_PIN_LCS0));
+}
+
+static int gpio_det, gpio_wp;
+
+static int mxc_mmc1_init(struct device *dev,
+                        irq_handler_t detect_irq, void *data)
+{
+       int ret;
+
+       gpio_det = IOMUX_TO_GPIO(MX31_PIN_GPIO1_1);
+       gpio_wp = IOMUX_TO_GPIO(MX31_PIN_LCS0);
+
+       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_GPIO1_1), 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,
+};
+
+/* Framebuffer support */
+static struct ipu_platform_data ipu_data __initdata = {
+       .irq_base = MXC_IPU_IRQ_START,
+};
+
+static const struct fb_videomode fb_modedb = {
+       /* 640x480 TFT panel (IPS-056T) */
+       .name           = "CRT-VGA",
+       .refresh        = 64,
+       .xres           = 640,
+       .yres           = 480,
+       .pixclock       = 30000,
+       .left_margin    = 200,
+       .right_margin   = 2,
+       .upper_margin   = 2,
+       .lower_margin   = 2,
+       .hsync_len      = 3,
+       .vsync_len      = 1,
+       .sync           = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_OE_ACT_HIGH,
+       .vmode          = FB_VMODE_NONINTERLACED,
+       .flag           = 0,
+};
+
+static struct mx3fb_platform_data fb_pdata __initdata = {
+       .dma_dev        = &mx3_ipu.dev,
+       .name           = "CRT-VGA",
+       .mode           = &fb_modedb,
+       .num_modes      = 1,
+};
+
+#define LCD_VCC_EN_GPIO         (7)
+
+static void __init mx31lilly_init_fb(void)
+{
+       if (gpio_request(LCD_VCC_EN_GPIO, "LCD enable") != 0) {
+               printk(KERN_WARNING "unable to request LCD_VCC_EN pin.\n");
+               return;
+       }
+
+       mxc_register_device(&mx3_ipu, &ipu_data);
+       mxc_register_device(&mx3_fb, &fb_pdata);
+       gpio_direction_output(LCD_VCC_EN_GPIO, 1);
+}
+
+void __init mx31lilly_db_init(void)
+{
+       mxc_iomux_setup_multiple_pins(lilly_db_board_pins,
+                                       ARRAY_SIZE(lilly_db_board_pins),
+                                       "development board pins");
+       mxc_register_device(&mxc_uart_device0, &uart_pdata);
+       mxc_register_device(&mxc_uart_device1, &uart_pdata);
+       mxc_register_device(&mxc_uart_device2, &uart_pdata);
+       mxc_register_device(&mxcsdhc_device0, &mmc_pdata);
+       mx31lilly_init_fb();
+}
+
diff --git a/arch/arm/mach-mx3/mx31lilly.c b/arch/arm/mach-mx3/mx31lilly.c
new file mode 100644 (file)
index 0000000..6ab2f16
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ *  LILLY-1131 module 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/types.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/smsc911x.h>
+#include <linux/mtd/physmap.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/mach/map.h>
+
+#include <mach/hardware.h>
+#include <mach/common.h>
+#include <mach/iomux-mx3.h>
+#include <mach/board-mx31lilly.h>
+
+#include "devices.h"
+
+/*
+ * This file contains module-specific initialization routines for LILLY-1131.
+ * Initialization of peripherals found on the baseboard is implemented in the
+ * appropriate baseboard support code.
+ */
+
+/* SMSC ethernet support */
+
+static struct resource smsc91x_resources[] = {
+       {
+               .start  = CS4_BASE_ADDR,
+               .end    = CS4_BASE_ADDR + 0xffff,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = IOMUX_TO_IRQ(MX31_PIN_GPIO1_0),
+               .end    = IOMUX_TO_IRQ(MX31_PIN_GPIO1_0),
+               .flags  = IORESOURCE_IRQ | IRQF_TRIGGER_FALLING,
+       }
+};
+
+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 |
+                         SMSC911X_FORCE_INTERNAL_PHY,
+};
+
+static struct platform_device smsc91x_device = {
+       .name           = "smsc911x",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(smsc91x_resources),
+       .resource       = smsc91x_resources,
+       .dev            = {
+               .platform_data = &smsc911x_config,
+       }
+};
+
+/* 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,
+};
+
+static struct platform_device *devices[] __initdata = {
+       &smsc91x_device,
+       &physmap_flash_device,
+       &mxc_i2c_device1,
+};
+
+static int mx31lilly_baseboard;
+core_param(mx31lilly_baseboard, mx31lilly_baseboard, int, 0444);
+
+static void __init mx31lilly_board_init(void)
+{
+       switch (mx31lilly_baseboard) {
+       case MX31LILLY_NOBOARD:
+               break;
+       case MX31LILLY_DB:
+               mx31lilly_db_init();
+               break;
+       default:
+               printk(KERN_ERR "Illegal mx31lilly_baseboard type %d\n",
+                       mx31lilly_baseboard);
+       }
+
+       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");
+
+       platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
+static void __init mx31lilly_timer_init(void)
+{
+       mx31_clocks_init(26000000);
+}
+
+static struct sys_timer mx31lilly_timer = {
+       .init   = mx31lilly_timer_init,
+};
+
+MACHINE_START(LILLY1131, "INCO startec LILLY-1131")
+       .phys_io        = AIPS1_BASE_ADDR,
+       .io_pg_offst    = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
+       .boot_params    = PHYS_OFFSET + 0x100,
+       .map_io         = mx31_map_io,
+       .init_irq       = mxc_init_irq,
+       .init_machine   = mx31lilly_board_init,
+       .timer          = &mx31lilly_timer,
+MACHINE_END
+
index 894d98cd9941a108ee6dde70d5dc00ec00f083f6..86fe70fa3e136ae989cec1cf24f20b3b33d7be78 100644 (file)
@@ -22,6 +22,9 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/memory.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/smsc911x.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/page.h>
 #include <asm/setup.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 "devices.h"
 
 /*
  * This file contains the board-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,
+};
+
+static struct mxc_nand_platform_data mx31lite_nand_board_info = {
+       .width = 1,
+       .hw_ecc = 1,
+};
+
+static struct smsc911x_platform_config smsc911x_config = {
+       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+       .irq_type       = SMSC911X_IRQ_TYPE_PUSH_PULL,
+       .flags          = SMSC911X_USE_16BIT,
+};
+
+static struct resource smsc911x_resources[] = {
+       [0] = {
+               .start          = CS4_BASE_ADDR,
+               .end            = CS4_BASE_ADDR + 0x100,
+               .flags          = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start          = IOMUX_TO_IRQ(MX31_PIN_SFS6),
+               .end            = IOMUX_TO_IRQ(MX31_PIN_SFS6),
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device smsc911x_device = {
+       .name           = "smsc911x",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(smsc911x_resources),
+       .resource       = smsc911x_resources,
+       .dev            = {
+               .platform_data = &smsc911x_config,
+       },
+};
+
 /*
  * This structure defines the MX31 memory map.
  */
@@ -59,7 +115,7 @@ static struct map_desc mx31lite_io_desc[] __initdata = {
  */
 void __init mx31lite_map_io(void)
 {
-       mxc_map_io();
+       mx31_map_io();
        iotable_init(mx31lite_io_desc, ARRAY_SIZE(mx31lite_io_desc));
 }
 
@@ -68,6 +124,22 @@ void __init mx31lite_map_io(void)
  */
 static void __init mxc_board_init(void)
 {
+       int ret;
+
+       mxc_iomux_setup_multiple_pins(mx31lite_pins, ARRAY_SIZE(mx31lite_pins),
+                                     "mx31lite");
+
+       mxc_register_device(&mxc_uart_device0, &uart_pdata);
+       mxc_register_device(&mxc_nand_device, &mx31lite_nand_board_info);
+
+       /* SMSC9117 IRQ pin */
+       ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_SFS6), "sms9117-irq");
+       if (ret)
+               pr_warning("could not get LAN irq gpio\n");
+       else {
+               gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_SFS6));
+               platform_device_register(&smsc911x_device);
+       }
 }
 
 static void __init mx31lite_timer_init(void)
index d080b4add79c05737982dcaf07b5235aa0c88d02..4704405165a16e75b90f40846453566a8a8a959a 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <linux/types.h>
+#include <linux/fsl_devices.h>
+#include <linux/gpio.h>
 #include <linux/init.h>
-
+#include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/types.h>
 
-#include <mach/hardware.h>
 #include <mach/common.h>
 #include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
+#include <mach/hardware.h>
+#include <mach/mmc.h>
 
 #include "devices.h"
 
+static unsigned int devboard_pins[] = {
+       /* UART1 */
+       MX31_PIN_CTS2__CTS2, MX31_PIN_RTS2__RTS2,
+       MX31_PIN_TXD2__TXD2, MX31_PIN_RXD2__RXD2,
+       /* SDHC2 */
+       MX31_PIN_PC_PWRON__SD2_DATA3, MX31_PIN_PC_VS1__SD2_DATA2,
+       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 OTG */
+       MX31_PIN_USBOTG_DATA0__USBOTG_DATA0,
+       MX31_PIN_USBOTG_DATA1__USBOTG_DATA1,
+       MX31_PIN_USBOTG_DATA2__USBOTG_DATA2,
+       MX31_PIN_USBOTG_DATA3__USBOTG_DATA3,
+       MX31_PIN_USBOTG_DATA4__USBOTG_DATA4,
+       MX31_PIN_USBOTG_DATA5__USBOTG_DATA5,
+       MX31_PIN_USBOTG_DATA6__USBOTG_DATA6,
+       MX31_PIN_USBOTG_DATA7__USBOTG_DATA7,
+       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,
+};
+
 static struct imxuart_platform_data uart_pdata = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
-static int mxc_uart1_pins[] = {
-       MX31_PIN_CTS2__CTS2, MX31_PIN_RTS2__RTS2,
-       MX31_PIN_TXD2__TXD2, MX31_PIN_RXD2__RXD2,
+#define SDHC2_CD IOMUX_TO_GPIO(MX31_PIN_ATA_DIOR)
+#define SDHC2_WP IOMUX_TO_GPIO(MX31_PIN_ATA_DIOW)
+
+static int devboard_sdhc2_get_ro(struct device *dev)
+{
+       return gpio_get_value(SDHC2_WP);
+}
+
+static int devboard_sdhc2_init(struct device *dev, irq_handler_t detect_irq,
+               void *data)
+{
+       int ret;
+
+       ret = gpio_request(SDHC2_CD, "sdhc-detect");
+       if (ret)
+               return ret;
+
+       gpio_direction_input(SDHC2_CD);
+
+       ret = gpio_request(SDHC2_WP, "sdhc-wp");
+       if (ret)
+               goto err_gpio_free;
+       gpio_direction_input(SDHC2_WP);
+
+       ret = request_irq(gpio_to_irq(SDHC2_CD), detect_irq,
+               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+               "sdhc2-card-detect", data);
+       if (ret)
+               goto err_gpio_free_2;
+
+       return 0;
+
+err_gpio_free_2:
+       gpio_free(SDHC2_WP);
+err_gpio_free:
+       gpio_free(SDHC2_CD);
+
+       return ret;
+}
+
+static void devboard_sdhc2_exit(struct device *dev, void *data)
+{
+       free_irq(gpio_to_irq(SDHC2_CD), data);
+       gpio_free(SDHC2_WP);
+       gpio_free(SDHC2_CD);
+}
+
+static struct imxmmc_platform_data sdhc2_pdata = {
+       .get_ro = devboard_sdhc2_get_ro,
+       .init   = devboard_sdhc2_init,
+       .exit   = devboard_sdhc2_exit,
+};
+
+static struct fsl_usb2_platform_data usb_pdata = {
+       .operating_mode = FSL_USB2_DR_DEVICE,
+       .phy_mode       = FSL_USB2_PHY_ULPI,
 };
 
+#define OTG_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST)
+#define OTG_EN_B IOMUX_TO_GPIO(MX31_PIN_USB_OC)
+
+static void devboard_usbotg_init(void)
+{
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA0, OTG_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA1, OTG_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA2, OTG_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA3, OTG_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA4, OTG_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA5, OTG_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA6, OTG_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA7, OTG_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_CLK, OTG_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DIR, OTG_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_NXT, OTG_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_STP, OTG_PAD_CFG);
+
+       gpio_request(OTG_EN_B, "usb-udc-en");
+       gpio_direction_output(OTG_EN_B, 0);
+}
+
 /*
  * system init for baseboard usage. Will be called by mx31moboard init.
  */
 void __init mx31moboard_devboard_init(void)
 {
        printk(KERN_INFO "Initializing mx31devboard peripherals\n");
-       mxc_iomux_setup_multiple_pins(mxc_uart1_pins, ARRAY_SIZE(mxc_uart1_pins), "uart1");
+
+       mxc_iomux_setup_multiple_pins(devboard_pins, ARRAY_SIZE(devboard_pins),
+               "devboard");
+
        mxc_register_device(&mxc_uart_device1, &uart_pdata);
+
+       mxc_register_device(&mxcsdhc_device1, &sdhc2_pdata);
+
+       devboard_usbotg_init();
+       mxc_register_device(&mxc_otg_udc_device, &usb_pdata);
 }
index 9ef9566823fb8dec7c8ee15bc7a47a63a0e50c84..641c3d6153aee66566e552e1400375d6390d3dfb 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <linux/types.h>
+#include <linux/fsl_devices.h>
+#include <linux/gpio.h>
 #include <linux/init.h>
-
+#include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/types.h>
 
-#include <mach/hardware.h>
 #include <mach/common.h>
+#include <mach/hardware.h>
 #include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
+#include <mach/mmc.h>
 
 #include "devices.h"
 
+static unsigned int marxbot_pins[] = {
+       /* SDHC2 */
+       MX31_PIN_PC_PWRON__SD2_DATA3, MX31_PIN_PC_VS1__SD2_DATA2,
+       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,
+       /* 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,
+       MX31_PIN_CSI_D12__CSI_D12, MX31_PIN_CSI_D13__CSI_D13,
+       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_GPIO3_0__GPIO3_0, MX31_PIN_GPIO3_1__GPIO3_1,
+       MX31_PIN_TXD2__GPIO1_28,
+       /* USB OTG */
+       MX31_PIN_USBOTG_DATA0__USBOTG_DATA0,
+       MX31_PIN_USBOTG_DATA1__USBOTG_DATA1,
+       MX31_PIN_USBOTG_DATA2__USBOTG_DATA2,
+       MX31_PIN_USBOTG_DATA3__USBOTG_DATA3,
+       MX31_PIN_USBOTG_DATA4__USBOTG_DATA4,
+       MX31_PIN_USBOTG_DATA5__USBOTG_DATA5,
+       MX31_PIN_USBOTG_DATA6__USBOTG_DATA6,
+       MX31_PIN_USBOTG_DATA7__USBOTG_DATA7,
+       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,
+};
+
+#define SDHC2_CD IOMUX_TO_GPIO(MX31_PIN_ATA_DIOR)
+#define SDHC2_WP IOMUX_TO_GPIO(MX31_PIN_ATA_DIOW)
+
+static int marxbot_sdhc2_get_ro(struct device *dev)
+{
+       return gpio_get_value(SDHC2_WP);
+}
+
+static int marxbot_sdhc2_init(struct device *dev, irq_handler_t detect_irq,
+               void *data)
+{
+       int ret;
+
+       ret = gpio_request(SDHC2_CD, "sdhc-detect");
+       if (ret)
+               return ret;
+
+       gpio_direction_input(SDHC2_CD);
+
+       ret = gpio_request(SDHC2_WP, "sdhc-wp");
+       if (ret)
+               goto err_gpio_free;
+       gpio_direction_input(SDHC2_WP);
+
+       ret = request_irq(gpio_to_irq(SDHC2_CD), detect_irq,
+               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+               "sdhc2-card-detect", data);
+       if (ret)
+               goto err_gpio_free_2;
+
+       return 0;
+
+err_gpio_free_2:
+       gpio_free(SDHC2_WP);
+err_gpio_free:
+       gpio_free(SDHC2_CD);
+
+       return ret;
+}
+
+static void marxbot_sdhc2_exit(struct device *dev, void *data)
+{
+       free_irq(gpio_to_irq(SDHC2_CD), data);
+       gpio_free(SDHC2_WP);
+       gpio_free(SDHC2_CD);
+}
+
+static struct imxmmc_platform_data sdhc2_pdata = {
+       .get_ro = marxbot_sdhc2_get_ro,
+       .init   = marxbot_sdhc2_init,
+       .exit   = marxbot_sdhc2_exit,
+};
+
+static struct fsl_usb2_platform_data usb_pdata = {
+       .operating_mode = FSL_USB2_DR_DEVICE,
+       .phy_mode       = FSL_USB2_PHY_ULPI,
+};
+
+#define OTG_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST)
+#define OTG_EN_B IOMUX_TO_GPIO(MX31_PIN_USB_OC)
+
+static void marxbot_usbotg_init(void)
+{
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA0, OTG_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA1, OTG_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA2, OTG_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA3, OTG_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA4, OTG_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA5, OTG_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA6, OTG_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA7, OTG_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_CLK, OTG_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DIR, OTG_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_NXT, OTG_PAD_CFG);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_STP, OTG_PAD_CFG);
+
+       gpio_request(OTG_EN_B, "usb-udc-en");
+       gpio_direction_output(OTG_EN_B, 0);
+}
+
 /*
  * system init for baseboard usage. Will be called by mx31moboard init.
  */
 void __init mx31moboard_marxbot_init(void)
 {
        printk(KERN_INFO "Initializing mx31marxbot peripherals\n");
+
+       mxc_iomux_setup_multiple_pins(marxbot_pins, ARRAY_SIZE(marxbot_pins),
+               "marxbot");
+
+       mxc_register_device(&mxcsdhc_device1, &sdhc2_pdata);
+
+       marxbot_usbotg_init();
+       mxc_register_device(&mxc_otg_udc_device, &usb_pdata);
 }
index 34c2a1b99d4fdfbb31eafba6e4653513c9d0fef8..a17f2e4116097c2a792f8f38454fb901a96efbd7 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <linux/types.h>
+#include <linux/gpio.h>
 #include <linux/init.h>
-
-#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/memory.h>
 #include <linux/mtd/physmap.h>
 #include <linux/mtd/partitions.h>
-#include <linux/memory.h>
+#include <linux/platform_device.h>
+#include <linux/types.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/board-mx31moboard.h>
 #include <mach/common.h>
+#include <mach/hardware.h>
 #include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
-#include <mach/board-mx31moboard.h>
+#include <mach/i2c.h>
+#include <mach/mmc.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,
+       /* UART4 */
+       MX31_PIN_PC_RST__CTS5, MX31_PIN_PC_VS2__RTS5,
+       MX31_PIN_PC_BVD2__TXD5, MX31_PIN_PC_BVD1__RXD5,
+       /* I2C0 */
+       MX31_PIN_I2C_DAT__I2C1_SDA, MX31_PIN_I2C_CLK__I2C1_SCL,
+       /* I2C1 */
+       MX31_PIN_DCD_DTE1__I2C2_SDA, MX31_PIN_RI_DTE1__I2C2_SCL,
+       /* SDHC1 */
+       MX31_PIN_SD1_DATA3__SD1_DATA3, MX31_PIN_SD1_DATA2__SD1_DATA2,
+       MX31_PIN_SD1_DATA1__SD1_DATA1, MX31_PIN_SD1_DATA0__SD1_DATA0,
+       MX31_PIN_SD1_CLK__SD1_CLK, MX31_PIN_SD1_CMD__SD1_CMD,
+       MX31_PIN_ATA_CS0__GPIO3_26, MX31_PIN_ATA_CS1__GPIO3_27,
+};
+
 static struct physmap_flash_data mx31moboard_flash_data = {
        .width          = 2,
 };
@@ -60,17 +81,69 @@ static struct imxuart_platform_data uart_pdata = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
-static struct platform_device *devices[] __initdata = {
-       &mx31moboard_flash,
+static struct imxi2c_platform_data moboard_i2c0_pdata = {
+       .bitrate = 400000,
 };
 
-static int mxc_uart0_pins[] = {
-       MX31_PIN_CTS1__CTS1, MX31_PIN_RTS1__RTS1,
-       MX31_PIN_TXD1__TXD1, MX31_PIN_RXD1__RXD1,
+static struct imxi2c_platform_data moboard_i2c1_pdata = {
+       .bitrate = 100000,
 };
-static int mxc_uart4_pins[] = {
-       MX31_PIN_PC_RST__CTS5, MX31_PIN_PC_VS2__RTS5,
-       MX31_PIN_PC_BVD2__TXD5, MX31_PIN_PC_BVD1__RXD5,
+
+#define SDHC1_CD IOMUX_TO_GPIO(MX31_PIN_ATA_CS0)
+#define SDHC1_WP IOMUX_TO_GPIO(MX31_PIN_ATA_CS1)
+
+static int moboard_sdhc1_get_ro(struct device *dev)
+{
+       return gpio_get_value(SDHC1_WP);
+}
+
+static int moboard_sdhc1_init(struct device *dev, irq_handler_t detect_irq,
+               void *data)
+{
+       int ret;
+
+       ret = gpio_request(SDHC1_CD, "sdhc-detect");
+       if (ret)
+               return ret;
+
+       gpio_direction_input(SDHC1_CD);
+
+       ret = gpio_request(SDHC1_WP, "sdhc-wp");
+       if (ret)
+               goto err_gpio_free;
+       gpio_direction_input(SDHC1_WP);
+
+       ret = request_irq(gpio_to_irq(SDHC1_CD), detect_irq,
+               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+               "sdhc1-card-detect", data);
+       if (ret)
+               goto err_gpio_free_2;
+
+       return 0;
+
+err_gpio_free_2:
+       gpio_free(SDHC1_WP);
+err_gpio_free:
+       gpio_free(SDHC1_CD);
+
+       return ret;
+}
+
+static void moboard_sdhc1_exit(struct device *dev, void *data)
+{
+       free_irq(gpio_to_irq(SDHC1_CD), data);
+       gpio_free(SDHC1_WP);
+       gpio_free(SDHC1_CD);
+}
+
+static struct imxmmc_platform_data sdhc1_pdata = {
+       .get_ro = moboard_sdhc1_get_ro,
+       .init   = moboard_sdhc1_init,
+       .exit   = moboard_sdhc1_exit,
+};
+
+static struct platform_device *devices[] __initdata = {
+       &mx31moboard_flash,
 };
 
 static int mx31moboard_baseboard;
@@ -81,14 +154,19 @@ core_param(mx31moboard_baseboard, mx31moboard_baseboard, int, 0444);
  */
 static void __init mxc_board_init(void)
 {
+       mxc_iomux_setup_multiple_pins(moboard_pins, ARRAY_SIZE(moboard_pins),
+               "moboard");
+
        platform_add_devices(devices, ARRAY_SIZE(devices));
 
-       mxc_iomux_setup_multiple_pins(mxc_uart0_pins, ARRAY_SIZE(mxc_uart0_pins), "uart0");
        mxc_register_device(&mxc_uart_device0, &uart_pdata);
-
-       mxc_iomux_setup_multiple_pins(mxc_uart4_pins, ARRAY_SIZE(mxc_uart4_pins), "uart4");
        mxc_register_device(&mxc_uart_device4, &uart_pdata);
 
+       mxc_register_device(&mxc_i2c_device0, &moboard_i2c0_pdata);
+       mxc_register_device(&mxc_i2c_device1, &moboard_i2c1_pdata);
+
+       mxc_register_device(&mxcsdhc_device0, &sdhc1_pdata);
+
        switch (mx31moboard_baseboard) {
        case MX31NOBOARD:
                break;
@@ -99,7 +177,8 @@ static void __init mxc_board_init(void)
                mx31moboard_marxbot_init();
                break;
        default:
-               printk(KERN_ERR "Illegal mx31moboard_baseboard type %d\n", mx31moboard_baseboard);
+               printk(KERN_ERR "Illegal mx31moboard_baseboard type %d\n",
+                       mx31moboard_baseboard);
        }
 }
 
@@ -117,7 +196,7 @@ MACHINE_START(MX31MOBOARD, "EPFL Mobots mx31moboard")
        .phys_io        = AIPS1_BASE_ADDR,
        .io_pg_offst    = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
        .boot_params    = PHYS_OFFSET + 0x100,
-       .map_io         = mxc_map_io,
+       .map_io         = mx31_map_io,
        .init_irq       = mxc_init_irq,
        .init_machine   = mxc_board_init,
        .timer          = &mx31moboard_timer,
index bc63f17856913205cb644ba8cffd0f72cfaa19fd..c19838d2e369695f3d3121dc0aeeb48d465fb64e 100644 (file)
@@ -20,6 +20,9 @@
 #include <linux/init.h>
 #include <linux/clk.h>
 #include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/smsc911x.h>
+#include <linux/platform_device.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
  * @ingroup System
  */
 
+static int mx31pdk_pins[] = {
+       /* UART1 */
+       MX31_PIN_CTS1__CTS1,
+       MX31_PIN_RTS1__RTS1,
+       MX31_PIN_TXD1__TXD1,
+       MX31_PIN_RXD1__RXD1,
+       IOMUX_MODE(MX31_PIN_GPIO1_1, IOMUX_CONFIG_GPIO),
+};
+
 static struct imxuart_platform_data uart_pdata = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
-static int uart_pins[] = {
-       MX31_PIN_CTS1__CTS1,
-       MX31_PIN_RTS1__RTS1,
-       MX31_PIN_TXD1__TXD1,
-       MX31_PIN_RXD1__RXD1
+/*
+ * Support for the SMSC9217 on the Debug board.
+ */
+
+static struct smsc911x_platform_config smsc911x_config = {
+       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+       .irq_type       = SMSC911X_IRQ_TYPE_PUSH_PULL,
+       .flags          = SMSC911X_USE_16BIT | SMSC911X_FORCE_INTERNAL_PHY,
+       .phy_interface  = PHY_INTERFACE_MODE_MII,
+};
+
+static struct resource smsc911x_resources[] = {
+       {
+               .start          = LAN9217_BASE_ADDR,
+               .end            = LAN9217_BASE_ADDR + 0xff,
+               .flags          = IORESOURCE_MEM,
+       }, {
+               .start          = EXPIO_INT_ENET,
+               .end            = EXPIO_INT_ENET,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device smsc911x_device = {
+       .name           = "smsc911x",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(smsc911x_resources),
+       .resource       = smsc911x_resources,
+       .dev            = {
+               .platform_data = &smsc911x_config,
+       },
 };
 
-static inline void mxc_init_imx_uart(void)
+/*
+ * Routines for the CPLD on the debug board. It contains a CPLD handling
+ * LEDs, switches, interrupts for Ethernet.
+ */
+
+static void mx31pdk_expio_irq_handler(uint32_t irq, struct irq_desc *desc)
 {
-       mxc_iomux_setup_multiple_pins(uart_pins, ARRAY_SIZE(uart_pins), "uart-0");
-       mxc_register_device(&mxc_uart_device0, &uart_pdata);
+       uint32_t imr_val;
+       uint32_t int_valid;
+       uint32_t expio_irq;
+
+       imr_val = __raw_readw(CPLD_INT_MASK_REG);
+       int_valid = __raw_readw(CPLD_INT_STATUS_REG) & ~imr_val;
+
+       expio_irq = MXC_EXP_IO_BASE;
+       for (; int_valid != 0; int_valid >>= 1, expio_irq++) {
+               if ((int_valid & 1) == 0)
+                       continue;
+               generic_handle_irq(expio_irq);
+       }
+}
+
+/*
+ * Disable an expio pin's interrupt by setting the bit in the imr.
+ * @param irq           an expio virtual irq number
+ */
+static void expio_mask_irq(uint32_t irq)
+{
+       uint16_t reg;
+       uint32_t expio = MXC_IRQ_TO_EXPIO(irq);
+
+       /* mask the interrupt */
+       reg = __raw_readw(CPLD_INT_MASK_REG);
+       reg |= 1 << expio;
+       __raw_writew(reg, CPLD_INT_MASK_REG);
+}
+
+/*
+ * Acknowledge an expanded io pin's interrupt by clearing the bit in the isr.
+ * @param irq           an expanded io virtual irq number
+ */
+static void expio_ack_irq(uint32_t irq)
+{
+       uint32_t expio = MXC_IRQ_TO_EXPIO(irq);
+
+       /* clear the interrupt status */
+       __raw_writew(1 << expio, CPLD_INT_RESET_REG);
+       __raw_writew(0, CPLD_INT_RESET_REG);
+       /* mask the interrupt */
+       expio_mask_irq(irq);
+}
+
+/*
+ * Enable a expio pin's interrupt by clearing the bit in the imr.
+ * @param irq           a expio virtual irq number
+ */
+static void expio_unmask_irq(uint32_t irq)
+{
+       uint16_t reg;
+       uint32_t expio = MXC_IRQ_TO_EXPIO(irq);
+
+       /* unmask the interrupt */
+       reg = __raw_readw(CPLD_INT_MASK_REG);
+       reg &= ~(1 << expio);
+       __raw_writew(reg, CPLD_INT_MASK_REG);
+}
+
+static struct irq_chip expio_irq_chip = {
+       .ack = expio_ack_irq,
+       .mask = expio_mask_irq,
+       .unmask = expio_unmask_irq,
+};
+
+static int __init mx31pdk_init_expio(void)
+{
+       int i;
+       int ret;
+
+       /* Check if there's a debug board connected */
+       if ((__raw_readw(CPLD_MAGIC_NUMBER1_REG) != 0xAAAA) ||
+           (__raw_readw(CPLD_MAGIC_NUMBER2_REG) != 0x5555) ||
+           (__raw_readw(CPLD_MAGIC_NUMBER3_REG) != 0xCAFE)) {
+               /* No Debug board found */
+               return -ENODEV;
+       }
+
+       pr_info("i.MX31PDK Debug board detected, rev = 0x%04X\n",
+               __raw_readw(CPLD_CODE_VER_REG));
+
+       /*
+        * Configure INT line as GPIO input
+        */
+       ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_GPIO1_1), "sms9217-irq");
+       if (ret)
+               pr_warning("could not get LAN irq gpio\n");
+       else
+               gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_GPIO1_1));
+
+       /* Disable the interrupts and clear the status */
+       __raw_writew(0, CPLD_INT_MASK_REG);
+       __raw_writew(0xFFFF, CPLD_INT_RESET_REG);
+       __raw_writew(0, CPLD_INT_RESET_REG);
+       __raw_writew(0x1F, CPLD_INT_MASK_REG);
+       for (i = MXC_EXP_IO_BASE;
+            i < (MXC_EXP_IO_BASE + MXC_MAX_EXP_IO_LINES);
+            i++) {
+               set_irq_chip(i, &expio_irq_chip);
+               set_irq_handler(i, handle_level_irq);
+               set_irq_flags(i, IRQF_VALID);
+       }
+       set_irq_type(EXPIO_PARENT_INT, IRQ_TYPE_LEVEL_LOW);
+       set_irq_chained_handler(EXPIO_PARENT_INT, mx31pdk_expio_irq_handler);
+
+       return 0;
+}
+
+/*
+ * This structure defines the MX31 memory map.
+ */
+static struct map_desc mx31pdk_io_desc[] __initdata = {
+       {
+               .virtual = SPBA0_BASE_ADDR_VIRT,
+               .pfn = __phys_to_pfn(SPBA0_BASE_ADDR),
+               .length = SPBA0_SIZE,
+               .type = MT_DEVICE_NONSHARED,
+       }, {
+               .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 mx31pdk_map_io(void)
+{
+       mx31_map_io();
+       iotable_init(mx31pdk_io_desc, ARRAY_SIZE(mx31pdk_io_desc));
 }
 
 /*!
@@ -63,7 +237,13 @@ static inline void mxc_init_imx_uart(void)
  */
 static void __init mxc_board_init(void)
 {
-       mxc_init_imx_uart();
+       mxc_iomux_setup_multiple_pins(mx31pdk_pins, ARRAY_SIZE(mx31pdk_pins),
+                                     "mx31pdk");
+
+       mxc_register_device(&mxc_uart_device0, &uart_pdata);
+
+       if (!mx31pdk_init_expio())
+               platform_device_register(&smsc911x_device);
 }
 
 static void __init mx31pdk_timer_init(void)
@@ -84,7 +264,7 @@ MACHINE_START(MX31_3DS, "Freescale MX31PDK (3DS)")
        .phys_io        = AIPS1_BASE_ADDR,
        .io_pg_offst    = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
        .boot_params    = PHYS_OFFSET + 0x100,
-       .map_io         = mxc_map_io,
+       .map_io         = mx31pdk_map_io,
        .init_irq       = mxc_init_irq,
        .init_machine   = mxc_board_init,
        .timer          = &mx31pdk_timer,
diff --git a/arch/arm/mach-mx3/mx35pdk.c b/arch/arm/mach-mx3/mx35pdk.c
new file mode 100644 (file)
index 0000000..6d15374
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Author: Fabio Estevam <fabio.estevam@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/memory.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/mach/map.h>
+
+#include <mach/hardware.h>
+#include <mach/common.h>
+#include <mach/imx-uart.h>
+#include <mach/iomux-mx35.h>
+
+#include "devices.h"
+
+static struct imxuart_platform_data uart_pdata = {
+       .flags = IMXUART_HAVE_RTSCTS,
+};
+
+static struct platform_device *devices[] __initdata = {
+       &mxc_fec_device,
+};
+
+static struct pad_desc mx35pdk_pads[] = {
+       /* UART1 */
+       MX35_PAD_CTS1__UART1_CTS,
+       MX35_PAD_RTS1__UART1_RTS,
+       MX35_PAD_TXD1__UART1_TXD_MUX,
+       MX35_PAD_RXD1__UART1_RXD_MUX,
+       /* FEC */
+       MX35_PAD_FEC_TX_CLK__FEC_TX_CLK,
+       MX35_PAD_FEC_RX_CLK__FEC_RX_CLK,
+       MX35_PAD_FEC_RX_DV__FEC_RX_DV,
+       MX35_PAD_FEC_COL__FEC_COL,
+       MX35_PAD_FEC_RDATA0__FEC_RDATA_0,
+       MX35_PAD_FEC_TDATA0__FEC_TDATA_0,
+       MX35_PAD_FEC_TX_EN__FEC_TX_EN,
+       MX35_PAD_FEC_MDC__FEC_MDC,
+       MX35_PAD_FEC_MDIO__FEC_MDIO,
+       MX35_PAD_FEC_TX_ERR__FEC_TX_ERR,
+       MX35_PAD_FEC_RX_ERR__FEC_RX_ERR,
+       MX35_PAD_FEC_CRS__FEC_CRS,
+       MX35_PAD_FEC_RDATA1__FEC_RDATA_1,
+       MX35_PAD_FEC_TDATA1__FEC_TDATA_1,
+       MX35_PAD_FEC_RDATA2__FEC_RDATA_2,
+       MX35_PAD_FEC_TDATA2__FEC_TDATA_2,
+       MX35_PAD_FEC_RDATA3__FEC_RDATA_3,
+       MX35_PAD_FEC_TDATA3__FEC_TDATA_3,
+};
+
+/*
+ * Board specific initialization.
+ */
+static void __init mxc_board_init(void)
+{
+       mxc_iomux_v3_setup_multiple_pads(mx35pdk_pads, ARRAY_SIZE(mx35pdk_pads));
+
+       platform_add_devices(devices, ARRAY_SIZE(devices));
+
+       mxc_register_device(&mxc_uart_device0, &uart_pdata);
+}
+
+static void __init mx35pdk_timer_init(void)
+{
+       mx35_clocks_init();
+}
+
+struct sys_timer mx35pdk_timer = {
+       .init   = mx35pdk_timer_init,
+};
+
+MACHINE_START(MX35_3DS, "Freescale MX35PDK")
+       /* Maintainer: Freescale Semiconductor, Inc */
+       .phys_io        = AIPS1_BASE_ADDR,
+       .io_pg_offst    = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
+       .boot_params    = PHYS_OFFSET + 0x100,
+       .map_io         = mx35_map_io,
+       .init_irq       = mxc_init_irq,
+       .init_machine   = mxc_board_init,
+       .timer          = &mx35pdk_timer,
+MACHINE_END
index b5227d837b2fc87012b0aa6536df4910ef3d2c6f..c6f61a1f06c8a2477bbc74e5111433abadbb0c6f 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/i2c.h>
 #include <linux/i2c/at24.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/irq.h>
+#include <linux/fsl_devices.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -37,7 +41,9 @@
 #include <mach/common.h>
 #include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
+#include <mach/ipu.h>
 #include <mach/board-pcm037.h>
+#include <mach/mx3fb.h>
 #include <mach/mxc_nand.h>
 #include <mach/mmc.h>
 #ifdef CONFIG_I2C_IMX
 
 #include "devices.h"
 
+static unsigned int pcm037_pins[] = {
+       /* I2C */
+       MX31_PIN_CSPI2_MOSI__SCL,
+       MX31_PIN_CSPI2_MISO__SDA,
+       /* SDHC1 */
+       MX31_PIN_SD1_DATA3__SD1_DATA3,
+       MX31_PIN_SD1_DATA2__SD1_DATA2,
+       MX31_PIN_SD1_DATA1__SD1_DATA1,
+       MX31_PIN_SD1_DATA0__SD1_DATA0,
+       MX31_PIN_SD1_CLK__SD1_CLK,
+       MX31_PIN_SD1_CMD__SD1_CMD,
+       IOMUX_MODE(MX31_PIN_SCK6, IOMUX_CONFIG_GPIO), /* card detect */
+       IOMUX_MODE(MX31_PIN_SFS6, IOMUX_CONFIG_GPIO), /* write protect */
+       /* SPI1 */
+       MX31_PIN_CSPI1_MOSI__MOSI,
+       MX31_PIN_CSPI1_MISO__MISO,
+       MX31_PIN_CSPI1_SCLK__SCLK,
+       MX31_PIN_CSPI1_SPI_RDY__SPI_RDY,
+       MX31_PIN_CSPI1_SS0__SS0,
+       MX31_PIN_CSPI1_SS1__SS1,
+       MX31_PIN_CSPI1_SS2__SS2,
+       /* UART1 */
+       MX31_PIN_CTS1__CTS1,
+       MX31_PIN_RTS1__RTS1,
+       MX31_PIN_TXD1__TXD1,
+       MX31_PIN_RXD1__RXD1,
+       /* UART2 */
+       MX31_PIN_TXD2__TXD2,
+       MX31_PIN_RXD2__RXD2,
+       MX31_PIN_CTS2__CTS2,
+       MX31_PIN_RTS2__RTS2,
+       /* UART3 */
+       MX31_PIN_CSPI3_MOSI__RXD3,
+       MX31_PIN_CSPI3_MISO__TXD3,
+       MX31_PIN_CSPI3_SCLK__RTS3,
+       MX31_PIN_CSPI3_SPI_RDY__CTS3,
+       /* LAN9217 irq pin */
+       IOMUX_MODE(MX31_PIN_GPIO3_1, IOMUX_CONFIG_GPIO),
+       /* Onewire */
+       MX31_PIN_BATT_LINE__OWIRE,
+       /* Framebuffer */
+       MX31_PIN_LD0__LD0,
+       MX31_PIN_LD1__LD1,
+       MX31_PIN_LD2__LD2,
+       MX31_PIN_LD3__LD3,
+       MX31_PIN_LD4__LD4,
+       MX31_PIN_LD5__LD5,
+       MX31_PIN_LD6__LD6,
+       MX31_PIN_LD7__LD7,
+       MX31_PIN_LD8__LD8,
+       MX31_PIN_LD9__LD9,
+       MX31_PIN_LD10__LD10,
+       MX31_PIN_LD11__LD11,
+       MX31_PIN_LD12__LD12,
+       MX31_PIN_LD13__LD13,
+       MX31_PIN_LD14__LD14,
+       MX31_PIN_LD15__LD15,
+       MX31_PIN_LD16__LD16,
+       MX31_PIN_LD17__LD17,
+       MX31_PIN_VSYNC3__VSYNC3,
+       MX31_PIN_HSYNC__HSYNC,
+       MX31_PIN_FPSHIFT__FPSHIFT,
+       MX31_PIN_DRDY0__DRDY0,
+       MX31_PIN_D3_REV__D3_REV,
+       MX31_PIN_CONTRAST__CONTRAST,
+       MX31_PIN_D3_SPL__D3_SPL,
+       MX31_PIN_D3_CLS__D3_CLS,
+       MX31_PIN_LCS0__GPI03_23,
+};
+
 static struct physmap_flash_data pcm037_flash_data = {
        .width  = 2,
 };
@@ -56,6 +132,54 @@ static struct resource pcm037_flash_resource = {
        .flags  = IORESOURCE_MEM,
 };
 
+static int usbotg_pins[] = {
+       MX31_PIN_USBOTG_DATA0__USBOTG_DATA0,
+       MX31_PIN_USBOTG_DATA1__USBOTG_DATA1,
+       MX31_PIN_USBOTG_DATA2__USBOTG_DATA2,
+       MX31_PIN_USBOTG_DATA3__USBOTG_DATA3,
+       MX31_PIN_USBOTG_DATA4__USBOTG_DATA4,
+       MX31_PIN_USBOTG_DATA5__USBOTG_DATA5,
+       MX31_PIN_USBOTG_DATA6__USBOTG_DATA6,
+       MX31_PIN_USBOTG_DATA7__USBOTG_DATA7,
+       MX31_PIN_USBOTG_CLK__USBOTG_CLK,
+       MX31_PIN_USBOTG_DIR__USBOTG_DIR,
+       MX31_PIN_USBOTG_NXT__USBOTG_NXT,
+       MX31_PIN_USBOTG_STP__USBOTG_STP,
+};
+
+/* USB OTG HS port */
+static int __init gpio_usbotg_hs_activate(void)
+{
+       int ret = mxc_iomux_setup_multiple_pins(usbotg_pins,
+                                       ARRAY_SIZE(usbotg_pins), "usbotg");
+
+       if (ret < 0) {
+               printk(KERN_ERR "Cannot set up OTG pins\n");
+               return ret;
+       }
+
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA0, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA1, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA2, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA3, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA4, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA5, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA6, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA7, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_CLK,   PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_DIR,   PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_NXT,   PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST);
+       mxc_iomux_set_pad(MX31_PIN_USBOTG_STP,   PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST);
+
+       return 0;
+}
+
+/* OTG config */
+static struct fsl_usb2_platform_data usb_pdata = {
+       .operating_mode = FSL_USB2_DR_DEVICE,
+       .phy_mode       = FSL_USB2_PHY_ULPI,
+};
+
 static struct platform_device pcm037_flash = {
        .name   = "physmap-flash",
        .id     = 0,
@@ -127,26 +251,8 @@ static struct mxc_nand_platform_data pcm037_nand_board_info = {
 };
 
 #ifdef CONFIG_I2C_IMX
-static int i2c_1_pins[] = {
-       MX31_PIN_CSPI2_MOSI__SCL,
-       MX31_PIN_CSPI2_MISO__SDA,
-};
-
-static int pcm037_i2c_1_init(struct device *dev)
-{
-       return mxc_iomux_setup_multiple_pins(i2c_1_pins, ARRAY_SIZE(i2c_1_pins),
-                       "i2c-1");
-}
-
-static void pcm037_i2c_1_exit(struct device *dev)
-{
-       mxc_iomux_release_multiple_pins(i2c_1_pins, ARRAY_SIZE(i2c_1_pins));
-}
-
 static struct imxi2c_platform_data pcm037_i2c_1_data = {
        .bitrate = 100000,
-       .init = pcm037_i2c_1_init,
-       .exit = pcm037_i2c_1_exit,
 };
 
 static struct at24_platform_data board_eeprom = {
@@ -166,48 +272,119 @@ static struct i2c_board_info pcm037_i2c_devices[] = {
 };
 #endif
 
-static int sdhc1_pins[] = {
-       MX31_PIN_SD1_DATA3__SD1_DATA3,
-       MX31_PIN_SD1_DATA2__SD1_DATA2,
-       MX31_PIN_SD1_DATA1__SD1_DATA1,
-       MX31_PIN_SD1_DATA0__SD1_DATA0,
-       MX31_PIN_SD1_CLK__SD1_CLK,
-       MX31_PIN_SD1_CMD__SD1_CMD,
-};
+/* Not connected by default */
+#ifdef PCM970_SDHC_RW_SWITCH
+static int pcm970_sdhc1_get_ro(struct device *dev)
+{
+       return gpio_get_value(IOMUX_TO_GPIO(MX31_PIN_SFS6));
+}
+#endif
+
+#define SDHC1_GPIO_WP  IOMUX_TO_GPIO(MX31_PIN_SFS6)
+#define SDHC1_GPIO_DET IOMUX_TO_GPIO(MX31_PIN_SCK6)
 
-static int pcm970_sdhc1_init(struct device *dev, irq_handler_t h, void *data)
+static int pcm970_sdhc1_init(struct device *dev, irq_handler_t detect_irq,
+               void *data)
 {
-       return mxc_iomux_setup_multiple_pins(sdhc1_pins, ARRAY_SIZE(sdhc1_pins),
-                               "sdhc-1");
+       int ret;
+
+       ret = gpio_request(SDHC1_GPIO_DET, "sdhc-detect");
+       if (ret)
+               return ret;
+
+       gpio_direction_input(SDHC1_GPIO_DET);
+
+#ifdef PCM970_SDHC_RW_SWITCH
+       ret = gpio_request(SDHC1_GPIO_WP, "sdhc-wp");
+       if (ret)
+               goto err_gpio_free;
+       gpio_direction_input(SDHC1_GPIO_WP);
+#endif
+
+       ret = request_irq(IOMUX_TO_IRQ(MX31_PIN_SCK6), detect_irq,
+                       IRQF_DISABLED | IRQF_TRIGGER_FALLING,
+                               "sdhc-detect", data);
+       if (ret)
+               goto err_gpio_free_2;
+
+       return 0;
+
+err_gpio_free_2:
+#ifdef PCM970_SDHC_RW_SWITCH
+       gpio_free(SDHC1_GPIO_WP);
+err_gpio_free:
+#endif
+       gpio_free(SDHC1_GPIO_DET);
+
+       return ret;
 }
 
 static void pcm970_sdhc1_exit(struct device *dev, void *data)
 {
-       mxc_iomux_release_multiple_pins(sdhc1_pins, ARRAY_SIZE(sdhc1_pins));
+       free_irq(IOMUX_TO_IRQ(MX31_PIN_SCK6), data);
+       gpio_free(SDHC1_GPIO_DET);
+       gpio_free(SDHC1_GPIO_WP);
 }
 
-/* No card and rw detection at the moment */
 static struct imxmmc_platform_data sdhc_pdata = {
+#ifdef PCM970_SDHC_RW_SWITCH
+       .get_ro = pcm970_sdhc1_get_ro,
+#endif
        .init = pcm970_sdhc1_init,
        .exit = pcm970_sdhc1_exit,
 };
 
 static struct platform_device *devices[] __initdata = {
        &pcm037_flash,
-       &pcm037_eth,
        &pcm037_sram_device,
 };
 
-static int uart0_pins[] = {
-       MX31_PIN_CTS1__CTS1,
-       MX31_PIN_RTS1__RTS1,
-       MX31_PIN_TXD1__TXD1,
-       MX31_PIN_RXD1__RXD1
+static struct ipu_platform_data mx3_ipu_data = {
+       .irq_base = MXC_IPU_IRQ_START,
 };
 
-static int uart2_pins[] = {
-       MX31_PIN_CSPI3_MOSI__RXD3,
-       MX31_PIN_CSPI3_MISO__TXD3
+static const struct fb_videomode fb_modedb[] = {
+       {
+               /* 240x320 @ 60 Hz Sharp */
+               .name           = "Sharp-LQ035Q7DH06-QVGA",
+               .refresh        = 60,
+               .xres           = 240,
+               .yres           = 320,
+               .pixclock       = 185925,
+               .left_margin    = 9,
+               .right_margin   = 16,
+               .upper_margin   = 7,
+               .lower_margin   = 9,
+               .hsync_len      = 1,
+               .vsync_len      = 1,
+               .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_SHARP_MODE |
+                                 FB_SYNC_CLK_INVERT | FB_SYNC_CLK_IDLE_EN,
+               .vmode          = FB_VMODE_NONINTERLACED,
+               .flag           = 0,
+       }, {
+               /* 240x320 @ 60 Hz */
+               .name           = "TX090",
+               .refresh        = 60,
+               .xres           = 240,
+               .yres           = 320,
+               .pixclock       = 38255,
+               .left_margin    = 144,
+               .right_margin   = 0,
+               .upper_margin   = 7,
+               .lower_margin   = 40,
+               .hsync_len      = 96,
+               .vsync_len      = 1,
+               .sync           = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_OE_ACT_HIGH,
+               .vmode          = FB_VMODE_NONINTERLACED,
+               .flag           = 0,
+       },
+};
+
+static struct mx3fb_platform_data mx3fb_pdata = {
+       .dma_dev        = &mx3_ipu.dev,
+       .name           = "Sharp-LQ035Q7DH06-QVGA",
+       .mode           = fb_modedb,
+       .num_modes      = ARRAY_SIZE(fb_modedb),
 };
 
 /*
@@ -215,21 +392,28 @@ static int uart2_pins[] = {
  */
 static void __init mxc_board_init(void)
 {
+       int ret;
+
+       mxc_iomux_setup_multiple_pins(pcm037_pins, ARRAY_SIZE(pcm037_pins),
+                       "pcm037");
+
        platform_add_devices(devices, ARRAY_SIZE(devices));
 
-       mxc_iomux_setup_multiple_pins(uart0_pins, ARRAY_SIZE(uart0_pins), "uart-0");
        mxc_register_device(&mxc_uart_device0, &uart_pdata);
-
-       mxc_iomux_setup_multiple_pins(uart2_pins, ARRAY_SIZE(uart2_pins), "uart-2");
+       mxc_register_device(&mxc_uart_device1, &uart_pdata);
        mxc_register_device(&mxc_uart_device2, &uart_pdata);
 
-       mxc_iomux_setup_pin(MX31_PIN_BATT_LINE__OWIRE, "batt-0wire");
        mxc_register_device(&mxc_w1_master_device, NULL);
 
        /* LAN9217 IRQ pin */
-       if (!mxc_iomux_setup_pin(IOMUX_MODE(MX31_PIN_GPIO3_1, IOMUX_CONFIG_GPIO),
-                               "pcm037-eth"))
+       ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_GPIO3_1), "lan9217-irq");
+       if (ret)
+               pr_warning("could not get LAN irq gpio\n");
+       else {
                gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_GPIO3_1));
+               platform_device_register(&pcm037_eth);
+       }
+
 
 #ifdef CONFIG_I2C_IMX
        i2c_register_board_info(1, pcm037_i2c_devices,
@@ -239,6 +423,10 @@ static void __init mxc_board_init(void)
 #endif
        mxc_register_device(&mxc_nand_device, &pcm037_nand_board_info);
        mxc_register_device(&mxcsdhc_device0, &sdhc_pdata);
+       mxc_register_device(&mx3_ipu, &mx3_ipu_data);
+       mxc_register_device(&mx3_fb, &mx3fb_pdata);
+       if (!gpio_usbotg_hs_activate())
+               mxc_register_device(&mxc_otg_udc_device, &usb_pdata);
 }
 
 static void __init pcm037_timer_init(void)
@@ -255,7 +443,7 @@ MACHINE_START(PCM037, "Phytec Phycore pcm037")
        .phys_io        = AIPS1_BASE_ADDR,
        .io_pg_offst    = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
        .boot_params    = PHYS_OFFSET + 0x100,
-       .map_io         = mxc_map_io,
+       .map_io         = mx31_map_io,
        .init_irq       = mxc_init_irq,
        .init_machine   = mxc_board_init,
        .timer          = &pcm037_timer,
diff --git a/arch/arm/mach-mx3/pcm043.c b/arch/arm/mach-mx3/pcm043.c
new file mode 100644 (file)
index 0000000..8d27c32
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ *  Copyright (C) 2009 Sascha Hauer, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/types.h>
+#include <linux/init.h>
+
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mtd/plat-ram.h>
+#include <linux/memory.h>
+#include <linux/gpio.h>
+#include <linux/smc911x.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/i2c/at24.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/mach/map.h>
+
+#include <mach/hardware.h>
+#include <mach/common.h>
+#include <mach/imx-uart.h>
+#if defined CONFIG_I2C_IMX || defined CONFIG_I2C_IMX_MODULE
+#include <mach/i2c.h>
+#endif
+#include <mach/iomux-mx35.h>
+#include <mach/ipu.h>
+#include <mach/mx3fb.h>
+
+#include "devices.h"
+
+static const struct fb_videomode fb_modedb[] = {
+       {
+               /* 240x320 @ 60 Hz */
+               .name           = "Sharp-LQ035Q7",
+               .refresh        = 60,
+               .xres           = 240,
+               .yres           = 320,
+               .pixclock       = 185925,
+               .left_margin    = 9,
+               .right_margin   = 16,
+               .upper_margin   = 7,
+               .lower_margin   = 9,
+               .hsync_len      = 1,
+               .vsync_len      = 1,
+               .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_SHARP_MODE | FB_SYNC_CLK_INVERT | FB_SYNC_CLK_IDLE_EN,
+               .vmode          = FB_VMODE_NONINTERLACED,
+               .flag           = 0,
+       }, {
+               /* 240x320 @ 60 Hz */
+               .name           = "TX090",
+               .refresh        = 60,
+               .xres           = 240,
+               .yres           = 320,
+               .pixclock       = 38255,
+               .left_margin    = 144,
+               .right_margin   = 0,
+               .upper_margin   = 7,
+               .lower_margin   = 40,
+               .hsync_len      = 96,
+               .vsync_len      = 1,
+               .sync           = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_OE_ACT_HIGH,
+               .vmode          = FB_VMODE_NONINTERLACED,
+               .flag           = 0,
+       },
+};
+
+static struct ipu_platform_data mx3_ipu_data = {
+       .irq_base = MXC_IPU_IRQ_START,
+};
+
+static struct mx3fb_platform_data mx3fb_pdata = {
+       .dma_dev        = &mx3_ipu.dev,
+       .name           = "Sharp-LQ035Q7",
+       .mode           = fb_modedb,
+       .num_modes      = ARRAY_SIZE(fb_modedb),
+};
+
+static struct physmap_flash_data pcm043_flash_data = {
+       .width  = 2,
+};
+
+static struct resource pcm043_flash_resource = {
+       .start  = 0xa0000000,
+       .end    = 0xa1ffffff,
+       .flags  = IORESOURCE_MEM,
+};
+
+static struct platform_device pcm043_flash = {
+       .name   = "physmap-flash",
+       .id     = 0,
+       .dev    = {
+               .platform_data  = &pcm043_flash_data,
+       },
+       .resource = &pcm043_flash_resource,
+       .num_resources = 1,
+};
+
+static struct imxuart_platform_data uart_pdata = {
+       .flags = IMXUART_HAVE_RTSCTS,
+};
+
+#if defined CONFIG_I2C_IMX || defined CONFIG_I2C_IMX_MODULE
+static struct imxi2c_platform_data pcm043_i2c_1_data = {
+       .bitrate = 50000,
+};
+
+static struct at24_platform_data board_eeprom = {
+       .byte_len = 4096,
+       .page_size = 32,
+       .flags = AT24_FLAG_ADDR16,
+};
+
+static struct i2c_board_info pcm043_i2c_devices[] = {
+       {
+               I2C_BOARD_INFO("at24", 0x52), /* E0=0, E1=1, E2=0 */
+               .platform_data = &board_eeprom,
+       }, {
+               I2C_BOARD_INFO("rtc-pcf8563", 0x51),
+               .type = "pcf8563",
+       }
+};
+#endif
+
+static struct platform_device *devices[] __initdata = {
+       &pcm043_flash,
+       &mxc_fec_device,
+};
+
+static struct pad_desc pcm043_pads[] = {
+       /* UART1 */
+       MX35_PAD_CTS1__UART1_CTS,
+       MX35_PAD_RTS1__UART1_RTS,
+       MX35_PAD_TXD1__UART1_TXD_MUX,
+       MX35_PAD_RXD1__UART1_RXD_MUX,
+       /* UART2 */
+       MX35_PAD_CTS2__UART2_CTS,
+       MX35_PAD_RTS2__UART2_RTS,
+       MX35_PAD_TXD2__UART2_TXD_MUX,
+       MX35_PAD_RXD2__UART2_RXD_MUX,
+       /* FEC */
+       MX35_PAD_FEC_TX_CLK__FEC_TX_CLK,
+       MX35_PAD_FEC_RX_CLK__FEC_RX_CLK,
+       MX35_PAD_FEC_RX_DV__FEC_RX_DV,
+       MX35_PAD_FEC_COL__FEC_COL,
+       MX35_PAD_FEC_RDATA0__FEC_RDATA_0,
+       MX35_PAD_FEC_TDATA0__FEC_TDATA_0,
+       MX35_PAD_FEC_TX_EN__FEC_TX_EN,
+       MX35_PAD_FEC_MDC__FEC_MDC,
+       MX35_PAD_FEC_MDIO__FEC_MDIO,
+       MX35_PAD_FEC_TX_ERR__FEC_TX_ERR,
+       MX35_PAD_FEC_RX_ERR__FEC_RX_ERR,
+       MX35_PAD_FEC_CRS__FEC_CRS,
+       MX35_PAD_FEC_RDATA1__FEC_RDATA_1,
+       MX35_PAD_FEC_TDATA1__FEC_TDATA_1,
+       MX35_PAD_FEC_RDATA2__FEC_RDATA_2,
+       MX35_PAD_FEC_TDATA2__FEC_TDATA_2,
+       MX35_PAD_FEC_RDATA3__FEC_RDATA_3,
+       MX35_PAD_FEC_TDATA3__FEC_TDATA_3,
+       /* I2C1 */
+       MX35_PAD_I2C1_CLK__I2C1_SCL,
+       MX35_PAD_I2C1_DAT__I2C1_SDA,
+       /* Display */
+       MX35_PAD_LD0__IPU_DISPB_DAT_0,
+       MX35_PAD_LD1__IPU_DISPB_DAT_1,
+       MX35_PAD_LD2__IPU_DISPB_DAT_2,
+       MX35_PAD_LD3__IPU_DISPB_DAT_3,
+       MX35_PAD_LD4__IPU_DISPB_DAT_4,
+       MX35_PAD_LD5__IPU_DISPB_DAT_5,
+       MX35_PAD_LD6__IPU_DISPB_DAT_6,
+       MX35_PAD_LD7__IPU_DISPB_DAT_7,
+       MX35_PAD_LD8__IPU_DISPB_DAT_8,
+       MX35_PAD_LD9__IPU_DISPB_DAT_9,
+       MX35_PAD_LD10__IPU_DISPB_DAT_10,
+       MX35_PAD_LD11__IPU_DISPB_DAT_11,
+       MX35_PAD_LD12__IPU_DISPB_DAT_12,
+       MX35_PAD_LD13__IPU_DISPB_DAT_13,
+       MX35_PAD_LD14__IPU_DISPB_DAT_14,
+       MX35_PAD_LD15__IPU_DISPB_DAT_15,
+       MX35_PAD_LD16__IPU_DISPB_DAT_16,
+       MX35_PAD_LD17__IPU_DISPB_DAT_17,
+       MX35_PAD_D3_HSYNC__IPU_DISPB_D3_HSYNC,
+       MX35_PAD_D3_FPSHIFT__IPU_DISPB_D3_CLK,
+       MX35_PAD_D3_DRDY__IPU_DISPB_D3_DRDY,
+       MX35_PAD_CONTRAST__IPU_DISPB_CONTR,
+       MX35_PAD_D3_VSYNC__IPU_DISPB_D3_VSYNC,
+       MX35_PAD_D3_REV__IPU_DISPB_D3_REV,
+       MX35_PAD_D3_CLS__IPU_DISPB_D3_CLS,
+       MX35_PAD_D3_SPL__IPU_DISPB_D3_SPL
+};
+
+/*
+ * Board specific initialization.
+ */
+static void __init mxc_board_init(void)
+{
+       mxc_iomux_v3_setup_multiple_pads(pcm043_pads, ARRAY_SIZE(pcm043_pads));
+
+       platform_add_devices(devices, ARRAY_SIZE(devices));
+
+       mxc_register_device(&mxc_uart_device0, &uart_pdata);
+
+       mxc_register_device(&mxc_uart_device1, &uart_pdata);
+
+#if defined CONFIG_I2C_IMX || defined CONFIG_I2C_IMX_MODULE
+       i2c_register_board_info(0, pcm043_i2c_devices,
+                       ARRAY_SIZE(pcm043_i2c_devices));
+
+       mxc_register_device(&mxc_i2c_device0, &pcm043_i2c_1_data);
+#endif
+
+       mxc_register_device(&mx3_ipu, &mx3_ipu_data);
+       mxc_register_device(&mx3_fb, &mx3fb_pdata);
+}
+
+static void __init pcm043_timer_init(void)
+{
+       mx35_clocks_init();
+}
+
+struct sys_timer pcm043_timer = {
+       .init   = pcm043_timer_init,
+};
+
+MACHINE_START(PCM043, "Phytec Phycore pcm043")
+       /* Maintainer: Pengutronix */
+       .phys_io        = AIPS1_BASE_ADDR,
+       .io_pg_offst    = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
+       .boot_params    = PHYS_OFFSET + 0x100,
+       .map_io         = mx35_map_io,
+       .init_irq       = mxc_init_irq,
+       .init_machine   = mxc_board_init,
+       .timer          = &pcm043_timer,
+MACHINE_END
+
index 5a01e48fd8f17e9b44e56bd0cd1160141c5c4a21..82b31c4ab11fc620fd28ea41e2065ed1ce197dba 100644 (file)
@@ -279,7 +279,7 @@ MACHINE_START(QONG, "Dave/DENX QongEVB-LITE")
        .phys_io        = AIPS1_BASE_ADDR,
        .io_pg_offst    = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
        .boot_params    = PHYS_OFFSET + 0x100,
-       .map_io         = mxc_map_io,
+       .map_io         = mx31_map_io,
        .init_irq       = mxc_init_irq,
        .init_machine   = mxc_board_init,
        .timer          = &qong_timer,
index 79df60c20e709cb82472589448b8554d20031e13..43da8bb4926b163c192286dd5a0fc4ba2ab5745c 100644 (file)
@@ -168,7 +168,7 @@ void __init netx_init_irq(void)
 {
        int irq;
 
-       vic_init(__io(io_p2v(NETX_PA_VIC)), 0, ~0);
+       vic_init(__io(io_p2v(NETX_PA_VIC)), 0, ~0, 0);
 
        for (irq = NETX_IRQ_HIF_CHAINED(0); irq <= NETX_IRQ_HIF_LAST; irq++) {
                set_irq_chip(irq, &netx_hif_chip);
index cd8de89c5fadca3f92e8a95099bd38272a025cf5..55ecc01ea206b2dd0d286f7e0879f9a24695bf1b 100644 (file)
@@ -46,7 +46,6 @@ config MACH_OMAP_H2
 config MACH_OMAP_H3
        bool "TI H3 Support"
        depends on ARCH_OMAP1 && ARCH_OMAP16XX
-#      select GPIOEXPANDER_OMAP
        help
          TI OMAP 1710 H3 board support. Say Y here if you have such
          a board.
index 1bda8f5d754666550c24d3881cf0b7c59185848e..6867cd3ad0b4a7c9c391256afe760328541ccc0e 100644 (file)
@@ -13,6 +13,10 @@ obj-$(CONFIG_OMAP_32K_TIMER) += timer32k.o
 # Power Management
 obj-$(CONFIG_PM) += pm.o sleep.o
 
+# DSP
+obj-$(CONFIG_OMAP_MBOX_FWK)    += mailbox_mach.o
+mailbox_mach-objs              := mailbox.o
+
 led-y := leds.o
 
 # Specific board support
index d1ed1365319e6abfe6397952bcb08a8c47090797..e70fc7c66bbb63d0b8b28d59d3e404ac9263a5f7 100644 (file)
 #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/usb.h>
+#include <mach/clock.h>
 
 #define ADS7846_PENDOWN_GPIO   15
 
@@ -162,6 +165,15 @@ static struct spi_board_info nokia770_spi_board_info[] __initdata = {
        },
 };
 
+static struct hwa742_platform_data nokia770_hwa742_platform_data = {
+       .te_connected           = 1,
+};
+
+static void hwa742_dev_init(void)
+{
+       clk_add_alias("hwa_sys_ck", NULL, "bclk", NULL);
+       omapfb_set_ctrl_platform_data(&nokia770_hwa742_platform_data);
+}
 
 /* assume no Mini-AB port */
 
@@ -370,6 +382,7 @@ static void __init omap_nokia770_init(void)
        omap_serial_init();
        omap_register_i2c_bus(1, 100, NULL, 0);
        omap_dsp_init();
+       hwa742_dev_init();
        ads7846_dev_init();
        mipid_dev_init();
        omap_usb_init(&nokia770_usb_config);
index 336e51dc612725588b802ef9b0e4da53f3d70d63..436eed22801beb51ebaac7fcdf4a59159cc40831 100644 (file)
@@ -776,7 +776,7 @@ int __init omap1_clk_init(void)
        arm_idlect1_mask = ~0;
 
        for (c = omap_clks; c < omap_clks + ARRAY_SIZE(omap_clks); c++)
-               clk_init_one(c->lk.clk);
+               clk_preinit(c->lk.clk);
 
        cpu_mask = 0;
        if (cpu_is_omap16xx())
index 9774c1f5311e075e34cae1bd12ebb05999688a30..5218943c91c05b9aab7dba4036ba57c3f196d74e 100644 (file)
 #include <mach/clock.h>
 #include <mach/sram.h>
 #include <mach/tc.h>
-#include <mach/pm.h>
 #include <mach/mux.h>
 #include <mach/dma.h>
 #include <mach/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];
@@ -101,7 +102,7 @@ static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL;
  * going idle we continue to do idle even if we get
  * a clock tick interrupt . .
  */
-void omap_pm_idle(void)
+void omap1_pm_idle(void)
 {
        extern __u32 arm_idlect1_mask;
        __u32 use_idlect1 = arm_idlect1_mask;
@@ -222,7 +223,7 @@ static void omap_pm_wakeup_setup(void)
 #define EN_APICK       6       /* ARM_IDLECT2 */
 #define DSP_EN         1       /* ARM_RSTCT1 */
 
-void omap_pm_suspend(void)
+void omap1_pm_suspend(void)
 {
        unsigned long arg0 = 0, arg1 = 0;
 
@@ -610,7 +611,7 @@ static int omap_pm_enter(suspend_state_t state)
        {
        case PM_SUSPEND_STANDBY:
        case PM_SUSPEND_MEM:
-               omap_pm_suspend();
+               omap1_pm_suspend();
                break;
        default:
                return -EINVAL;
@@ -683,7 +684,7 @@ static int __init omap_pm_init(void)
                return -ENODEV;
        }
 
-       pm_idle = omap_pm_idle;
+       pm_idle = omap1_pm_idle;
 
        if (cpu_is_omap730())
                setup_irq(INT_730_WAKE_UP_REQ, &omap_wakeup_irq);
diff --git a/arch/arm/mach-omap1/pm.h b/arch/arm/mach-omap1/pm.h
new file mode 100644 (file)
index 0000000..9ed5e2c
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * arch/arm/mach-omap1/pm.h
+ *
+ * Header file for OMAP1 Power Management Routines
+ *
+ * Author: MontaVista Software, Inc.
+ *        support@mvista.com
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ * Cleanup 2004 for Linux 2.6 by Dirk Behme <dirk.behme@de.bosch.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP1_PM_H
+#define __ARCH_ARM_MACH_OMAP1_PM_H
+
+/*
+ * ----------------------------------------------------------------------------
+ * Register and offset definitions to be used in PM assembler code
+ * ----------------------------------------------------------------------------
+ */
+#define CLKGEN_REG_ASM_BASE            IO_ADDRESS(0xfffece00)
+#define ARM_IDLECT1_ASM_OFFSET         0x04
+#define ARM_IDLECT2_ASM_OFFSET         0x08
+
+#define TCMIF_ASM_BASE                 IO_ADDRESS(0xfffecc00)
+#define EMIFS_CONFIG_ASM_OFFSET                0x0c
+#define EMIFF_SDRAM_CONFIG_ASM_OFFSET  0x20
+
+/*
+ * ----------------------------------------------------------------------------
+ * Power management bitmasks
+ * ----------------------------------------------------------------------------
+ */
+#define IDLE_WAIT_CYCLES               0x00000fff
+#define PERIPHERAL_ENABLE              0x2
+
+#define SELF_REFRESH_MODE              0x0c000001
+#define IDLE_EMIFS_REQUEST             0xc
+#define MODEM_32K_EN                   0x1
+#define PER_EN                         0x1
+
+#define CPU_SUSPEND_SIZE               200
+#define ULPD_LOW_PWR_EN                        0x0001
+#define ULPD_DEEP_SLEEP_TRANSITION_EN  0x0010
+#define ULPD_SETUP_ANALOG_CELL_3_VAL   0
+#define ULPD_POWER_CTRL_REG_VAL                0x0219
+
+#define DSP_IDLE_DELAY                 10
+#define DSP_IDLE                       0x0040
+#define DSP_RST                                0x0004
+#define DSP_ENABLE                     0x0002
+#define SUFFICIENT_DSP_RESET_TIME      1000
+#define DEFAULT_MPUI_CONFIG            0x05cf
+#define ENABLE_XORCLK                  0x2
+#define DSP_CLOCK_ENABLE               0x2000
+#define DSP_IDLE_MODE                  0x2
+#define TC_IDLE_REQUEST                        (0x0000000c)
+
+#define IRQ_LEVEL2                     (1<<0)
+#define IRQ_KEYBOARD                   (1<<1)
+#define IRQ_UART2                      (1<<15)
+
+#define PDE_BIT                                0x08
+#define PWD_EN_BIT                     0x04
+#define EN_PERCK_BIT                   0x04
+
+#define OMAP1510_DEEP_SLEEP_REQUEST    0x0ec7
+#define OMAP1510_BIG_SLEEP_REQUEST     0x0cc5
+#define OMAP1510_IDLE_LOOP_REQUEST     0x0c00
+#define OMAP1510_IDLE_CLOCK_DOMAINS    0x2
+
+/* Both big sleep and deep sleep use same values. Difference is in ULPD. */
+#define OMAP1610_IDLECT1_SLEEP_VAL     0x13c7
+#define OMAP1610_IDLECT2_SLEEP_VAL     0x09c7
+#define OMAP1610_IDLECT3_VAL           0x3f
+#define OMAP1610_IDLECT3_SLEEP_ORMASK  0x2c
+#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
+
+#if     !defined(CONFIG_ARCH_OMAP730) && \
+       !defined(CONFIG_ARCH_OMAP15XX) && \
+       !defined(CONFIG_ARCH_OMAP16XX)
+#warning "Power management for this processor not implemented yet"
+#endif
+
+#ifndef __ASSEMBLER__
+
+#include <linux/clk.h>
+
+extern struct kset power_subsys;
+
+extern void prevent_idle_sleep(void);
+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 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 omap1510_idle_loop_suspend(void);
+extern void omap1610_idle_loop_suspend(void);
+
+extern unsigned int omap730_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 omap1510_idle_loop_suspend_sz;
+extern unsigned int omap1610_idle_loop_suspend_sz;
+
+#ifdef CONFIG_OMAP_SERIAL_WAKE
+extern void omap_serial_wake_trigger(int enable);
+#else
+#define omap_serial_wakeup_init()      {}
+#define omap_serial_wake_trigger(x)    {}
+#endif /* CONFIG_OMAP_SERIAL_WAKE */
+
+#define ARM_SAVE(x) arm_sleep_save[ARM_SLEEP_SAVE_##x] = omap_readl(x)
+#define ARM_RESTORE(x) omap_writel((arm_sleep_save[ARM_SLEEP_SAVE_##x]), (x))
+#define ARM_SHOW(x) arm_sleep_save[ARM_SLEEP_SAVE_##x]
+
+#define DSP_SAVE(x) dsp_sleep_save[DSP_SLEEP_SAVE_##x] = __raw_readw(x)
+#define DSP_RESTORE(x) __raw_writew((dsp_sleep_save[DSP_SLEEP_SAVE_##x]), (x))
+#define DSP_SHOW(x) dsp_sleep_save[DSP_SLEEP_SAVE_##x]
+
+#define ULPD_SAVE(x) ulpd_sleep_save[ULPD_SLEEP_SAVE_##x] = omap_readw(x)
+#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 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))
+#define MPUI1510_SHOW(x) mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x]
+
+#define MPUI1610_SAVE(x) mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x] = omap_readl(x)
+#define MPUI1610_RESTORE(x) omap_writel((mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x]), (x))
+#define MPUI1610_SHOW(x) mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x]
+
+/*
+ * List of global OMAP registers to preserve.
+ * More ones like CP and general purpose register values are preserved
+ * with the stack pointer in sleep.S.
+ */
+
+enum arm_save_state {
+       ARM_SLEEP_SAVE_START = 0,
+       /*
+        * MPU control registers 32 bits
+        */
+       ARM_SLEEP_SAVE_ARM_CKCTL,
+       ARM_SLEEP_SAVE_ARM_IDLECT1,
+       ARM_SLEEP_SAVE_ARM_IDLECT2,
+       ARM_SLEEP_SAVE_ARM_IDLECT3,
+       ARM_SLEEP_SAVE_ARM_EWUPCT,
+       ARM_SLEEP_SAVE_ARM_RSTCT1,
+       ARM_SLEEP_SAVE_ARM_RSTCT2,
+       ARM_SLEEP_SAVE_ARM_SYSST,
+       ARM_SLEEP_SAVE_SIZE
+};
+
+enum dsp_save_state {
+       DSP_SLEEP_SAVE_START = 0,
+       /*
+        * DSP registers 16 bits
+        */
+       DSP_SLEEP_SAVE_DSP_IDLECT2,
+       DSP_SLEEP_SAVE_SIZE
+};
+
+enum ulpd_save_state {
+       ULPD_SLEEP_SAVE_START = 0,
+       /*
+        * ULPD registers 16 bits
+        */
+       ULPD_SLEEP_SAVE_ULPD_IT_STATUS,
+       ULPD_SLEEP_SAVE_ULPD_CLOCK_CTRL,
+       ULPD_SLEEP_SAVE_ULPD_SOFT_REQ,
+       ULPD_SLEEP_SAVE_ULPD_STATUS_REQ,
+       ULPD_SLEEP_SAVE_ULPD_DPLL_CTRL,
+       ULPD_SLEEP_SAVE_ULPD_POWER_CTRL,
+       ULPD_SLEEP_SAVE_SIZE
+};
+
+enum mpui1510_save_state {
+       MPUI1510_SLEEP_SAVE_START = 0,
+       /*
+        * MPUI registers 32 bits
+        */
+       MPUI1510_SLEEP_SAVE_MPUI_CTRL,
+       MPUI1510_SLEEP_SAVE_MPUI_DSP_BOOT_CONFIG,
+       MPUI1510_SLEEP_SAVE_MPUI_DSP_API_CONFIG,
+       MPUI1510_SLEEP_SAVE_MPUI_DSP_STATUS,
+       MPUI1510_SLEEP_SAVE_EMIFF_SDRAM_CONFIG,
+       MPUI1510_SLEEP_SAVE_EMIFS_CONFIG,
+       MPUI1510_SLEEP_SAVE_OMAP_IH1_MIR,
+       MPUI1510_SLEEP_SAVE_OMAP_IH2_MIR,
+#if defined(CONFIG_ARCH_OMAP15XX)
+       MPUI1510_SLEEP_SAVE_SIZE
+#else
+       MPUI1510_SLEEP_SAVE_SIZE = 0
+#endif
+};
+
+enum mpui730_save_state {
+       MPUI730_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
+#else
+       MPUI730_SLEEP_SAVE_SIZE = 0
+#endif
+};
+
+enum mpui1610_save_state {
+       MPUI1610_SLEEP_SAVE_START = 0,
+       /*
+        * MPUI registers 32 bits
+        */
+       MPUI1610_SLEEP_SAVE_MPUI_CTRL,
+       MPUI1610_SLEEP_SAVE_MPUI_DSP_BOOT_CONFIG,
+       MPUI1610_SLEEP_SAVE_MPUI_DSP_API_CONFIG,
+       MPUI1610_SLEEP_SAVE_MPUI_DSP_STATUS,
+       MPUI1610_SLEEP_SAVE_EMIFF_SDRAM_CONFIG,
+       MPUI1610_SLEEP_SAVE_EMIFS_CONFIG,
+       MPUI1610_SLEEP_SAVE_OMAP_IH1_MIR,
+       MPUI1610_SLEEP_SAVE_OMAP_IH2_0_MIR,
+       MPUI1610_SLEEP_SAVE_OMAP_IH2_1_MIR,
+       MPUI1610_SLEEP_SAVE_OMAP_IH2_2_MIR,
+       MPUI1610_SLEEP_SAVE_OMAP_IH2_3_MIR,
+#if defined(CONFIG_ARCH_OMAP16XX)
+       MPUI1610_SLEEP_SAVE_SIZE
+#else
+       MPUI1610_SLEEP_SAVE_SIZE = 0
+#endif
+};
+
+#endif /* ASSEMBLER */
+#endif /* __ASM_ARCH_OMAP_PM_H */
index 842090b148f16157d23e103cb49add2f61b9b3f3..f754cee4f3c3269779087bc7b56b900538012473 100644 (file)
@@ -26,9 +26,6 @@
 #include <mach/mux.h>
 #include <mach/gpio.h>
 #include <mach/fpga.h>
-#ifdef CONFIG_PM
-#include <mach/pm.h>
-#endif
 
 static struct clk * uart1_ck;
 static struct clk * uart2_ck;
index f3eac932092da1068acdb6bbf7e3e7da86ac122d..22e8568339b0c7f7016e01a438717db5a6bf6479 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <mach/io.h>
-#include <mach/pm.h>
+#include "pm.h"
 
                .text
 
index 64ab386a65c775ff7553d24b65ab8c4928d64210..a755eb5e236190c791c22c99f86f32f62ebad8db 100644 (file)
@@ -25,7 +25,7 @@ config ARCH_OMAP3430
        select ARCH_OMAP_OTG
 
 comment "OMAP Board Type"
-       depends on ARCH_OMAP2 || ARCH_OMAP3
+       depends on ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4
 
 config MACH_OMAP_GENERIC
        bool "Generic OMAP board"
@@ -56,6 +56,10 @@ config MACH_OVERO
        bool "Gumstix Overo board"
        depends on ARCH_OMAP3 && ARCH_OMAP34XX
 
+config MACH_OMAP3EVM
+       bool "OMAP 3530 EVM board"
+       depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
 config MACH_OMAP3_PANDORA
        bool "OMAP3 Pandora"
        depends on ARCH_OMAP3 && ARCH_OMAP34XX
@@ -67,3 +71,11 @@ config MACH_OMAP_3430SDP
 config MACH_NOKIA_RX51
        bool "Nokia RX-51 board"
        depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
+config MACH_OMAP_ZOOM2
+       bool "OMAP3 Zoom2 board"
+       depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
+config MACH_OMAP_4430SDP
+       bool "OMAP 4430 SDP board"
+       depends on ARCH_OMAP4
index c49d9bfa3abde7694e261115e40424f586f1152f..735bae5b0dec01203e4419e4186461688417cfdf 100644 (file)
@@ -3,12 +3,21 @@
 #
 
 # Common support
-obj-y := irq.o id.o io.o sdrc.o control.o prcm.o clock.o mux.o \
-               devices.o serial.o gpmc.o timer-gp.o powerdomain.o \
-               clockdomain.o
+obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer-gp.o
+
+omap-2-3-common                                = irq.o sdrc.o
+prcm-common                            = prcm.o powerdomain.o
+clock-common                           = clock.o clockdomain.o
+
+obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(prcm-common) $(clock-common)
+obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(prcm-common) $(clock-common)
 
 obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
 
+# SMP support ONLY available for OMAP4
+obj-$(CONFIG_SMP)                      += omap-smp.o omap-headsmp.o
+obj-$(CONFIG_LOCAL_TIMERS)             += timer-mpu.o
+
 # Functions loaded to SRAM
 obj-$(CONFIG_ARCH_OMAP2420)            += sram242x.o
 obj-$(CONFIG_ARCH_OMAP2430)            += sram243x.o
@@ -20,14 +29,21 @@ obj-$(CONFIG_ARCH_OMAP2)            += sdrc2xxx.o
 
 # Power Management
 ifeq ($(CONFIG_PM),y)
-obj-y                                  += pm.o
+obj-$(CONFIG_ARCH_OMAP2)               += pm24xx.o
 obj-$(CONFIG_ARCH_OMAP24XX)            += sleep24xx.o
+obj-$(CONFIG_ARCH_OMAP3)               += pm34xx.o sleep34xx.o
+obj-$(CONFIG_PM_DEBUG)                 += pm-debug.o
 endif
 
 # Clock framework
 obj-$(CONFIG_ARCH_OMAP2)               += clock24xx.o
 obj-$(CONFIG_ARCH_OMAP3)               += clock34xx.o
 
+iommu-y                                        += iommu2.o
+iommu-$(CONFIG_ARCH_OMAP3)             += omap3-iommu.o
+
+obj-$(CONFIG_OMAP_IOMMU)               += $(iommu-y)
+
 # Specific board support
 obj-$(CONFIG_MACH_OMAP_GENERIC)                += board-generic.o
 obj-$(CONFIG_MACH_OMAP_H4)             += board-h4.o
@@ -40,6 +56,8 @@ obj-$(CONFIG_MACH_OMAP_LDP)           += board-ldp.o \
                                           mmc-twl4030.o
 obj-$(CONFIG_MACH_OVERO)               += board-overo.o \
                                           mmc-twl4030.o
+obj-$(CONFIG_MACH_OMAP3EVM)            += board-omap3evm.o \
+                                          mmc-twl4030.o
 obj-$(CONFIG_MACH_OMAP3_PANDORA)       += board-omap3pandora.o \
                                           mmc-twl4030.o
 obj-$(CONFIG_MACH_OMAP_3430SDP)                += board-3430sdp.o \
@@ -48,8 +66,17 @@ obj-$(CONFIG_MACH_OMAP_3430SDP)              += board-3430sdp.o \
 obj-$(CONFIG_MACH_NOKIA_RX51)          += board-rx51.o \
                                           board-rx51-peripherals.o \
                                           mmc-twl4030.o
+obj-$(CONFIG_MACH_OMAP_ZOOM2)          += board-zoom2.o \
+                                          mmc-twl4030.o \
+                                          board-zoom-debugboard.o
+
+obj-$(CONFIG_MACH_OMAP_4430SDP)                += board-4430sdp.o
 
 # Platform specific device init code
-ifeq ($(CONFIG_USB_MUSB_SOC),y)
 obj-y                                  += usb-musb.o
-endif
+
+onenand-$(CONFIG_MTD_ONENAND_OMAP2)    := gpmc-onenand.o
+obj-y                                  += $(onenand-m) $(onenand-y)
+
+smc91x-$(CONFIG_SMC91X)                        := gpmc-smc91x.o
+obj-y                                  += $(smc91x-m) $(smc91x-y)
index 22143651037e3b62c526f128c282e1132deac9fd..9c3fdcdf76c324306702d07974e912fb59246d09 100644 (file)
 #include <mach/common.h>
 #include <mach/gpmc.h>
 #include <mach/usb.h>
+#include <mach/gpmc-smc91x.h>
 
 #include "mmc-twl4030.h"
 
 #define SDP2430_CS0_BASE       0x04000000
-#define        SDP2430_FLASH_CS        0
-#define        SDP2430_SMC91X_CS       5
-
-#define SDP2430_ETHR_GPIO_IRQ          149
+#define SECONDARY_LCD_GPIO             147
 
 static struct mtd_partition sdp2430_partitions[] = {
        /* bootloader (U-Boot, etc) in first sector */
@@ -99,100 +97,53 @@ static struct platform_device sdp2430_flash_device = {
        .resource       = &sdp2430_flash_resource,
 };
 
-static struct resource sdp2430_smc91x_resources[] = {
-       [0] = {
-               .start  = SDP2430_CS0_BASE,
-               .end    = SDP2430_CS0_BASE + SZ_64M - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = OMAP_GPIO_IRQ(SDP2430_ETHR_GPIO_IRQ),
-               .end    = OMAP_GPIO_IRQ(SDP2430_ETHR_GPIO_IRQ),
-               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
-       },
-};
-
-static struct platform_device sdp2430_smc91x_device = {
-       .name           = "smc91x",
+static struct platform_device sdp2430_lcd_device = {
+       .name           = "sdp2430_lcd",
        .id             = -1,
-       .num_resources  = ARRAY_SIZE(sdp2430_smc91x_resources),
-       .resource       = sdp2430_smc91x_resources,
 };
 
 static struct platform_device *sdp2430_devices[] __initdata = {
-       &sdp2430_smc91x_device,
        &sdp2430_flash_device,
+       &sdp2430_lcd_device,
 };
 
-static inline void __init sdp2430_init_smc91x(void)
-{
-       int eth_cs;
-       unsigned long cs_mem_base;
-       unsigned int rate;
-       struct clk *gpmc_fck;
+static struct omap_lcd_config sdp2430_lcd_config __initdata = {
+       .ctrl_name      = "internal",
+};
 
-       eth_cs = SDP2430_SMC91X_CS;
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91x_MODULE)
 
-       gpmc_fck = clk_get(NULL, "gpmc_fck");   /* Always on ENABLE_ON_INIT */
-       if (IS_ERR(gpmc_fck)) {
-               WARN_ON(1);
-               return;
-       }
+static struct omap_smc91x_platform_data board_smc91x_data = {
+       .cs             = 5,
+       .gpio_irq       = 149,
+       .flags          = GPMC_MUX_ADD_DATA | GPMC_TIMINGS_SMC91C96 |
+                               IORESOURCE_IRQ_LOWLEVEL,
 
-       clk_enable(gpmc_fck);
-       rate = clk_get_rate(gpmc_fck);
-
-       /* Make sure CS1 timings are correct, for 2430 always muxed */
-       gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG1, 0x00011200);
-
-       if (rate >= 160000000) {
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f01);
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080803);
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1c0b1c0a);
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F);
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4);
-       } else if (rate >= 130000000) {
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00);
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802);
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09);
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F);
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4);
-       } else { /* rate = 100000000 */
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00);
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802);
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09);
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x031A1F1F);
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000003C2);
-       }
+};
 
-       if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) {
-               printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
-               goto out;
-       }
+static void __init board_smc91x_init(void)
+{
+       if (omap_rev() > OMAP3430_REV_ES1_0)
+               board_smc91x_data.gpio_irq = 6;
+       else
+               board_smc91x_data.gpio_irq = 29;
 
-       sdp2430_smc91x_resources[0].start = cs_mem_base + 0x300;
-       sdp2430_smc91x_resources[0].end = cs_mem_base + 0x30f;
-       udelay(100);
+       gpmc_smc91x_init(&board_smc91x_data);
+}
 
-       if (gpio_request(SDP2430_ETHR_GPIO_IRQ, "SMC91x irq") < 0) {
-               printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n",
-                       SDP2430_ETHR_GPIO_IRQ);
-               gpmc_cs_free(eth_cs);
-               goto out;
-       }
-       gpio_direction_input(SDP2430_ETHR_GPIO_IRQ);
+#else
 
-out:
-       clk_disable(gpmc_fck);
-       clk_put(gpmc_fck);
+static inline void board_smc91x_init(void)
+{
 }
 
+#endif
+
 static void __init omap_2430sdp_init_irq(void)
 {
        omap2_init_common_hw(NULL);
        omap_init_irq();
        omap_gpio_init();
-       sdp2430_init_smc91x();
 }
 
 static struct omap_uart_config sdp2430_uart_config __initdata = {
@@ -201,6 +152,7 @@ static struct omap_uart_config sdp2430_uart_config __initdata = {
 
 static struct omap_board_config_kernel sdp2430_config[] = {
        {OMAP_TAG_UART, &sdp2430_uart_config},
+       {OMAP_TAG_LCD, &sdp2430_lcd_config},
 };
 
 
@@ -248,6 +200,8 @@ static struct twl4030_hsmmc_info mmc[] __initdata = {
 
 static void __init omap_2430sdp_init(void)
 {
+       int ret;
+
        omap2430_i2c_init();
 
        platform_add_devices(sdp2430_devices, ARRAY_SIZE(sdp2430_devices));
@@ -256,6 +210,12 @@ static void __init omap_2430sdp_init(void)
        omap_serial_init();
        twl4030_mmc_init(mmc);
        usb_musb_init();
+       board_smc91x_init();
+
+       /* Turn off secondary LCD backlight */
+       ret = gpio_request(SECONDARY_LCD_GPIO, "Secondary LCD backlight");
+       if (ret == 0)
+               gpio_direction_output(SECONDARY_LCD_GPIO, 0);
 }
 
 static void __init omap_2430sdp_map_io(void)
index ed9274972122e782fcc1d94b2570f82f2b0733fb..496a90e4ea7ac16d2983759a1b62dd007160c010 100644 (file)
 
 #include <mach/control.h>
 #include <mach/keypad.h>
+#include <mach/gpmc-smc91x.h>
 
+#include "sdram-qimonda-hyb18m512160af-6.h"
 #include "mmc-twl4030.h"
 
 #define CONFIG_DISABLE_HFCLK 1
 
-#define SDP3430_ETHR_GPIO_IRQ_SDPV1    29
-#define SDP3430_ETHR_GPIO_IRQ_SDPV2    6
-#define SDP3430_SMC91X_CS              3
-
 #define SDP3430_TS_GPIO_IRQ_SDPV1      3
 #define SDP3430_TS_GPIO_IRQ_SDPV2      2
 
 
 #define TWL4030_MSECURE_GPIO 22
 
-static struct resource sdp3430_smc91x_resources[] = {
-       [0] = {
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = 0,
-               .end    = 0,
-               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
-       },
-};
-
-static struct platform_device sdp3430_smc91x_device = {
-       .name           = "smc91x",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(sdp3430_smc91x_resources),
-       .resource       = sdp3430_smc91x_resources,
-};
-
 static int sdp3430_keymap[] = {
        KEY(0, 0, KEY_LEFT),
        KEY(0, 1, KEY_RIGHT),
@@ -184,48 +164,14 @@ static struct regulator_consumer_supply sdp3430_vdvi_supply = {
 };
 
 static struct platform_device *sdp3430_devices[] __initdata = {
-       &sdp3430_smc91x_device,
        &sdp3430_lcd_device,
 };
 
-static inline void __init sdp3430_init_smc91x(void)
-{
-       int eth_cs;
-       unsigned long cs_mem_base;
-       int eth_gpio = 0;
-
-       eth_cs = SDP3430_SMC91X_CS;
-
-       if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) {
-               printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
-               return;
-       }
-
-       sdp3430_smc91x_resources[0].start = cs_mem_base + 0x300;
-       sdp3430_smc91x_resources[0].end = cs_mem_base + 0x30f;
-       udelay(100);
-
-       if (omap_rev() > OMAP3430_REV_ES1_0)
-               eth_gpio = SDP3430_ETHR_GPIO_IRQ_SDPV2;
-       else
-               eth_gpio = SDP3430_ETHR_GPIO_IRQ_SDPV1;
-
-       sdp3430_smc91x_resources[1].start = gpio_to_irq(eth_gpio);
-
-       if (gpio_request(eth_gpio, "SMC91x irq") < 0) {
-               printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n",
-                       eth_gpio);
-               return;
-       }
-       gpio_direction_input(eth_gpio);
-}
-
 static void __init omap_3430sdp_init_irq(void)
 {
-       omap2_init_common_hw(NULL);
+       omap2_init_common_hw(hyb18m512160af6_sdrc_params);
        omap_init_irq();
        omap_gpio_init();
-       sdp3430_init_smc91x();
 }
 
 static struct omap_uart_config sdp3430_uart_config __initdata = {
@@ -506,6 +452,32 @@ static int __init omap3430_i2c_init(void)
        return 0;
 }
 
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+
+static struct omap_smc91x_platform_data board_smc91x_data = {
+       .cs             = 3,
+       .flags          = GPMC_MUX_ADD_DATA | GPMC_TIMINGS_SMC91C96 |
+                               IORESOURCE_IRQ_LOWLEVEL,
+};
+
+static void __init board_smc91x_init(void)
+{
+       if (omap_rev() > OMAP3430_REV_ES1_0)
+               board_smc91x_data.gpio_irq = 6;
+       else
+               board_smc91x_data.gpio_irq = 29;
+
+       gpmc_smc91x_init(&board_smc91x_data);
+}
+
+#else
+
+static inline void board_smc91x_init(void)
+{
+}
+
+#endif
+
 static void __init omap_3430sdp_init(void)
 {
        omap3430_i2c_init();
@@ -522,6 +494,7 @@ static void __init omap_3430sdp_init(void)
        ads7846_dev_init();
        omap_serial_init();
        usb_musb_init();
+       board_smc91x_init();
 }
 
 static void __init omap_3430sdp_map_io(void)
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c
new file mode 100644 (file)
index 0000000..57e477b
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Board support file for OMAP4430 SDP.
+ *
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * Author: Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * Based on mach-omap2/board-3430sdp.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/io.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 <mach/board.h>
+#include <mach/common.h>
+#include <mach/control.h>
+#include <mach/timer-gp.h>
+#include <asm/hardware/gic.h>
+
+static struct platform_device sdp4430_lcd_device = {
+       .name           = "sdp4430_lcd",
+       .id             = -1,
+};
+
+static struct platform_device *sdp4430_devices[] __initdata = {
+       &sdp4430_lcd_device,
+};
+
+static struct omap_uart_config sdp4430_uart_config __initdata = {
+       .enabled_uarts  = (1 << 0) | (1 << 1) | (1 << 2),
+};
+
+static struct omap_lcd_config sdp4430_lcd_config __initdata = {
+       .ctrl_name      = "internal",
+};
+
+static struct omap_board_config_kernel sdp4430_config[] __initdata = {
+       { OMAP_TAG_UART,        &sdp4430_uart_config },
+       { OMAP_TAG_LCD,         &sdp4430_lcd_config },
+};
+
+static void __init gic_init_irq(void)
+{
+       gic_dist_init(0, IO_ADDRESS(OMAP44XX_GIC_DIST_BASE), 29);
+       gic_cpu_init(0, IO_ADDRESS(OMAP44XX_GIC_CPU_BASE));
+}
+
+static void __init omap_4430sdp_init_irq(void)
+{
+       omap2_init_common_hw(NULL);
+#ifdef CONFIG_OMAP_32K_TIMER
+       omap2_gp_clockevent_set_gptimer(1);
+#endif
+       gic_init_irq();
+       omap_gpio_init();
+}
+
+
+static void __init omap_4430sdp_init(void)
+{
+       platform_add_devices(sdp4430_devices, ARRAY_SIZE(sdp4430_devices));
+       omap_board_config = sdp4430_config;
+       omap_board_config_size = ARRAY_SIZE(sdp4430_config);
+       omap_serial_init();
+}
+
+static void __init omap_4430sdp_map_io(void)
+{
+       omap2_set_globals_443x();
+       omap2_map_common_io();
+}
+
+MACHINE_START(OMAP_4430SDP, "OMAP4430 4430SDP board")
+       /* Maintainer: Santosh Shilimkar - Texas Instruments Inc */
+       .phys_io        = 0x48000000,
+       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .boot_params    = 0x80000100,
+       .map_io         = omap_4430sdp_map_io,
+       .init_irq       = omap_4430sdp_init_irq,
+       .init_machine   = omap_4430sdp_init,
+       .timer          = &omap_timer,
+MACHINE_END
index da57b0fcda14c5c2ca0ac92e1da076f7176763ee..d8bc0a7dcb8df64463b3653de1f9a1626bc37619 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/input.h>
+#include <linux/gpio_keys.h>
 #include <linux/workqueue.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
+#include <linux/regulator/machine.h>
 #include <linux/i2c/twl4030.h>
 #include <linux/io.h>
 #include <linux/smsc911x.h>
@@ -39,6 +41,7 @@
 #include <asm/delay.h>
 #include <mach/control.h>
 #include <mach/usb.h>
+#include <mach/keypad.h>
 
 #include "mmc-twl4030.h"
 
@@ -77,8 +80,163 @@ static struct platform_device ldp_smsc911x_device = {
        },
 };
 
-static struct platform_device *ldp_devices[] __initdata = {
-       &ldp_smsc911x_device,
+static int ldp_twl4030_keymap[] = {
+       KEY(0, 0, KEY_1),
+       KEY(1, 0, KEY_2),
+       KEY(2, 0, KEY_3),
+       KEY(0, 1, KEY_4),
+       KEY(1, 1, KEY_5),
+       KEY(2, 1, KEY_6),
+       KEY(3, 1, KEY_F5),
+       KEY(0, 2, KEY_7),
+       KEY(1, 2, KEY_8),
+       KEY(2, 2, KEY_9),
+       KEY(3, 2, KEY_F6),
+       KEY(0, 3, KEY_F7),
+       KEY(1, 3, KEY_0),
+       KEY(2, 3, KEY_F8),
+       PERSISTENT_KEY(4, 5),
+       KEY(4, 4, KEY_VOLUMEUP),
+       KEY(5, 5, KEY_VOLUMEDOWN),
+       0
+};
+
+static struct twl4030_keypad_data ldp_kp_twl4030_data = {
+       .rows           = 6,
+       .cols           = 6,
+       .keymap         = ldp_twl4030_keymap,
+       .keymapsize     = ARRAY_SIZE(ldp_twl4030_keymap),
+       .rep            = 1,
+};
+
+static struct gpio_keys_button ldp_gpio_keys_buttons[] = {
+       [0] = {
+               .code                   = KEY_ENTER,
+               .gpio                   = 101,
+               .desc                   = "enter sw",
+               .active_low             = 1,
+               .debounce_interval      = 30,
+       },
+       [1] = {
+               .code                   = KEY_F1,
+               .gpio                   = 102,
+               .desc                   = "func 1",
+               .active_low             = 1,
+               .debounce_interval      = 30,
+       },
+       [2] = {
+               .code                   = KEY_F2,
+               .gpio                   = 103,
+               .desc                   = "func 2",
+               .active_low             = 1,
+               .debounce_interval      = 30,
+       },
+       [3] = {
+               .code                   = KEY_F3,
+               .gpio                   = 104,
+               .desc                   = "func 3",
+               .active_low             = 1,
+               .debounce_interval      = 30,
+       },
+       [4] = {
+               .code                   = KEY_F4,
+               .gpio                   = 105,
+               .desc                   = "func 4",
+               .active_low             = 1,
+               .debounce_interval      = 30,
+       },
+       [5] = {
+               .code                   = KEY_LEFT,
+               .gpio                   = 106,
+               .desc                   = "left sw",
+               .active_low             = 1,
+               .debounce_interval      = 30,
+       },
+       [6] = {
+               .code                   = KEY_RIGHT,
+               .gpio                   = 107,
+               .desc                   = "right sw",
+               .active_low             = 1,
+               .debounce_interval      = 30,
+       },
+       [7] = {
+               .code                   = KEY_UP,
+               .gpio                   = 108,
+               .desc                   = "up sw",
+               .active_low             = 1,
+               .debounce_interval      = 30,
+       },
+       [8] = {
+               .code                   = KEY_DOWN,
+               .gpio                   = 109,
+               .desc                   = "down sw",
+               .active_low             = 1,
+               .debounce_interval      = 30,
+       },
+};
+
+static struct gpio_keys_platform_data ldp_gpio_keys = {
+       .buttons                = ldp_gpio_keys_buttons,
+       .nbuttons               = ARRAY_SIZE(ldp_gpio_keys_buttons),
+       .rep                    = 1,
+};
+
+static struct platform_device ldp_gpio_keys_device = {
+       .name           = "gpio-keys",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &ldp_gpio_keys,
+       },
+};
+
+static int ts_gpio;
+
+/**
+ * @brief ads7846_dev_init : Requests & sets GPIO line for pen-irq
+ *
+ * @return - void. If request gpio fails then Flag KERN_ERR.
+ */
+static void ads7846_dev_init(void)
+{
+       if (gpio_request(ts_gpio, "ads7846 irq") < 0) {
+               printk(KERN_ERR "can't get ads746 pen down GPIO\n");
+               return;
+       }
+
+       gpio_direction_input(ts_gpio);
+       omap_set_gpio_debounce(ts_gpio, 1);
+       omap_set_gpio_debounce_time(ts_gpio, 0xa);
+}
+
+static int ads7846_get_pendown_state(void)
+{
+       return !gpio_get_value(ts_gpio);
+}
+
+static struct ads7846_platform_data tsc2046_config __initdata = {
+       .get_pendown_state      = ads7846_get_pendown_state,
+       .keep_vref_on           = 1,
+};
+
+static struct omap2_mcspi_device_config tsc2046_mcspi_config = {
+       .turbo_mode     = 0,
+       .single_channel = 1,    /* 0: slave, 1: master */
+};
+
+static struct spi_board_info ldp_spi_board_info[] __initdata = {
+       [0] = {
+               /*
+                * TSC2046 operates at a max freqency of 2MHz, so
+                * operate slightly below at 1.5MHz
+                */
+               .modalias               = "ads7846",
+               .bus_num                = 1,
+               .chip_select            = 0,
+               .max_speed_hz           = 1500000,
+               .controller_data        = &tsc2046_mcspi_config,
+               .irq                    = 0,
+               .platform_data          = &tsc2046_config,
+       },
 };
 
 static inline void __init ldp_init_smsc911x(void)
@@ -122,8 +280,22 @@ static struct omap_uart_config ldp_uart_config __initdata = {
        .enabled_uarts  = ((1 << 0) | (1 << 1) | (1 << 2)),
 };
 
+static struct platform_device ldp_lcd_device = {
+       .name           = "ldp_lcd",
+       .id             = -1,
+};
+
+static struct omap_lcd_config ldp_lcd_config __initdata = {
+       .ctrl_name      = "internal",
+};
+
 static struct omap_board_config_kernel ldp_config[] __initdata = {
        { OMAP_TAG_UART,        &ldp_uart_config },
+       { OMAP_TAG_LCD,         &ldp_lcd_config },
+};
+
+static struct twl4030_usb_data ldp_usb_data = {
+       .usb_mode       = T2_USB_MODE_ULPI,
 };
 
 static struct twl4030_gpio_platform_data ldp_gpio_data = {
@@ -132,12 +304,39 @@ static struct twl4030_gpio_platform_data ldp_gpio_data = {
        .irq_end        = TWL4030_GPIO_IRQ_END,
 };
 
+static struct twl4030_madc_platform_data ldp_madc_data = {
+       .irq_line       = 1,
+};
+
+static struct regulator_consumer_supply ldp_vmmc1_supply = {
+       .supply                 = "vmmc",
+};
+
+/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
+static struct regulator_init_data ldp_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      = &ldp_vmmc1_supply,
+};
+
 static struct twl4030_platform_data ldp_twldata = {
        .irq_base       = TWL4030_IRQ_BASE,
        .irq_end        = TWL4030_IRQ_END,
 
        /* platform_data for children goes here */
+       .madc           = &ldp_madc_data,
+       .usb            = &ldp_usb_data,
+       .vmmc1          = &ldp_vmmc1,
        .gpio           = &ldp_gpio_data,
+       .keypad         = &ldp_kp_twl4030_data,
 };
 
 static struct i2c_board_info __initdata ldp_i2c_boardinfo[] = {
@@ -168,15 +367,29 @@ static struct twl4030_hsmmc_info mmc[] __initdata = {
        {}      /* Terminator */
 };
 
+static struct platform_device *ldp_devices[] __initdata = {
+       &ldp_smsc911x_device,
+       &ldp_lcd_device,
+       &ldp_gpio_keys_device,
+};
+
 static void __init omap_ldp_init(void)
 {
        omap_i2c_init();
        platform_add_devices(ldp_devices, ARRAY_SIZE(ldp_devices));
        omap_board_config = ldp_config;
        omap_board_config_size = ARRAY_SIZE(ldp_config);
+       ts_gpio = 54;
+       ldp_spi_board_info[0].irq = gpio_to_irq(ts_gpio);
+       spi_register_board_info(ldp_spi_board_info,
+                               ARRAY_SIZE(ldp_spi_board_info));
+       ads7846_dev_init();
        omap_serial_init();
-       twl4030_mmc_init(mmc);
        usb_musb_init();
+
+       twl4030_mmc_init(mmc);
+       /* link regulators to MMC adapters */
+       ldp_vmmc1_supply.dev = mmc[0].dev;
 }
 
 static void __init omap_ldp_map_io(void)
index 3a7a29d1f9a74c72137a6bda6b69b4694161f93b..991ac9c38032832dbed51e533f10b2ef7099ce81 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand.h>
 
+#include <linux/regulator/machine.h>
 #include <linux/i2c/twl4030.h>
 
 #include <mach/hardware.h>
@@ -105,6 +106,8 @@ static struct platform_device omap3beagle_nand_device = {
        .resource       = &omap3beagle_nand_resource,
 };
 
+#include "sdram-micron-mt46h32m32lf-6.h"
+
 static struct omap_uart_config omap3_beagle_uart_config __initdata = {
        .enabled_uarts  = ((1 << 0) | (1 << 1) | (1 << 2)),
 };
@@ -118,6 +121,23 @@ static struct twl4030_hsmmc_info mmc[] = {
        {}      /* Terminator */
 };
 
+static struct platform_device omap3_beagle_lcd_device = {
+       .name           = "omap3beagle_lcd",
+       .id             = -1,
+};
+
+static struct omap_lcd_config omap3_beagle_lcd_config __initdata = {
+       .ctrl_name      = "internal",
+};
+
+static struct regulator_consumer_supply beagle_vmmc1_supply = {
+       .supply                 = "vmmc",
+};
+
+static struct regulator_consumer_supply beagle_vsim_supply = {
+       .supply                 = "vmmc_aux",
+};
+
 static struct gpio_led gpio_leds[];
 
 static int beagle_twl_gpio_setup(struct device *dev,
@@ -128,6 +148,10 @@ static int beagle_twl_gpio_setup(struct device *dev,
        mmc[0].gpio_cd = gpio + 0;
        twl4030_mmc_init(mmc);
 
+       /* link regulators to MMC adapters */
+       beagle_vmmc1_supply.dev = mmc[0].dev;
+       beagle_vsim_supply.dev = mmc[0].dev;
+
        /* REVISIT: need ehci-omap hooks for external VBUS
         * power switch and overcurrent detect
         */
@@ -156,12 +180,85 @@ static struct twl4030_gpio_platform_data beagle_gpio_data = {
        .setup          = beagle_twl_gpio_setup,
 };
 
+static struct regulator_consumer_supply beagle_vdac_supply = {
+       .supply         = "vdac",
+       .dev            = &omap3_beagle_lcd_device.dev,
+};
+
+static struct regulator_consumer_supply beagle_vdvi_supply = {
+       .supply         = "vdvi",
+       .dev            = &omap3_beagle_lcd_device.dev,
+};
+
+/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
+static struct regulator_init_data beagle_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      = &beagle_vmmc1_supply,
+};
+
+/* VSIM for MMC1 pins DAT4..DAT7 (2 mA, plus card == max 50 mA) */
+static struct regulator_init_data beagle_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      = &beagle_vsim_supply,
+};
+
+/* VDAC for DSS driving S-Video (8 mA unloaded, max 65 mA) */
+static struct regulator_init_data beagle_vdac = {
+       .constraints = {
+               .min_uV                 = 1800000,
+               .max_uV                 = 1800000,
+               .valid_modes_mask       = REGULATOR_MODE_NORMAL
+                                       | REGULATOR_MODE_STANDBY,
+               .valid_ops_mask         = REGULATOR_CHANGE_MODE
+                                       | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies  = 1,
+       .consumer_supplies      = &beagle_vdac_supply,
+};
+
+/* VPLL2 for digital video outputs */
+static struct regulator_init_data beagle_vpll2 = {
+       .constraints = {
+               .name                   = "VDVI",
+               .min_uV                 = 1800000,
+               .max_uV                 = 1800000,
+               .valid_modes_mask       = REGULATOR_MODE_NORMAL
+                                       | REGULATOR_MODE_STANDBY,
+               .valid_ops_mask         = REGULATOR_CHANGE_MODE
+                                       | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies  = 1,
+       .consumer_supplies      = &beagle_vdvi_supply,
+};
+
 static struct twl4030_platform_data beagle_twldata = {
        .irq_base       = TWL4030_IRQ_BASE,
        .irq_end        = TWL4030_IRQ_END,
 
        /* platform_data for children goes here */
        .gpio           = &beagle_gpio_data,
+       .vmmc1          = &beagle_vmmc1,
+       .vsim           = &beagle_vsim,
+       .vdac           = &beagle_vdac,
+       .vpll2          = &beagle_vpll2,
 };
 
 static struct i2c_board_info __initdata beagle_i2c_boardinfo[] = {
@@ -185,7 +282,7 @@ static int __init omap3_beagle_i2c_init(void)
 
 static void __init omap3_beagle_init_irq(void)
 {
-       omap2_init_common_hw(NULL);
+       omap2_init_common_hw(mt46h32m32lf6_sdrc_params);
        omap_init_irq();
 #ifdef CONFIG_OMAP_32K_TIMER
        omap2_gp_clockevent_set_gptimer(12);
@@ -193,15 +290,6 @@ static void __init omap3_beagle_init_irq(void)
        omap_gpio_init();
 }
 
-static struct platform_device omap3_beagle_lcd_device = {
-       .name           = "omap3beagle_lcd",
-       .id             = -1,
-};
-
-static struct omap_lcd_config omap3_beagle_lcd_config __initdata = {
-       .ctrl_name      = "internal",
-};
-
 static struct gpio_led gpio_leds[] = {
        {
                .name                   = "beagleboard::usr0",
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
new file mode 100644 (file)
index 0000000..d3cc145
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+ * linux/arch/arm/mach-omap2/board-omap3evm.c
+ *
+ * Copyright (C) 2008 Texas Instruments
+ *
+ * Modified from mach-omap2/board-3430sdp.c
+ *
+ * Initial code: Syed Mohammed Khasim
+ *
+ * This 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/gpio.h>
+#include <linux/input.h>
+#include <linux/leds.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+#include <linux/i2c/twl4030.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 <mach/keypad.h>
+
+#include "sdram-micron-mt46h32m32lf-6.h"
+#include "mmc-twl4030.h"
+
+#define OMAP3_EVM_TS_GPIO      175
+
+#define OMAP3EVM_ETHR_START    0x2c000000
+#define OMAP3EVM_ETHR_SIZE     1024
+#define OMAP3EVM_ETHR_GPIO_IRQ 176
+#define OMAP3EVM_SMC911X_CS    5
+
+static struct resource omap3evm_smc911x_resources[] = {
+       [0] =   {
+               .start  = OMAP3EVM_ETHR_START,
+               .end    = (OMAP3EVM_ETHR_START + OMAP3EVM_ETHR_SIZE - 1),
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] =   {
+               .start  = OMAP_GPIO_IRQ(OMAP3EVM_ETHR_GPIO_IRQ),
+               .end    = OMAP_GPIO_IRQ(OMAP3EVM_ETHR_GPIO_IRQ),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device omap3evm_smc911x_device = {
+       .name           = "smc911x",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(omap3evm_smc911x_resources),
+       .resource       = &omap3evm_smc911x_resources[0],
+};
+
+static inline void __init omap3evm_init_smc911x(void)
+{
+       int eth_cs;
+       struct clk *l3ck;
+       unsigned int rate;
+
+       eth_cs = OMAP3EVM_SMC911X_CS;
+
+       l3ck = clk_get(NULL, "l3_ck");
+       if (IS_ERR(l3ck))
+               rate = 100000000;
+       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",
+                       OMAP3EVM_ETHR_GPIO_IRQ);
+               return;
+       }
+
+       gpio_direction_input(OMAP3EVM_ETHR_GPIO_IRQ);
+}
+
+static struct omap_uart_config omap3_evm_uart_config __initdata = {
+       .enabled_uarts  = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
+static struct twl4030_hsmmc_info mmc[] = {
+       {
+               .mmc            = 1,
+               .wires          = 4,
+               .gpio_cd        = -EINVAL,
+               .gpio_wp        = 63,
+       },
+       {}      /* Terminator */
+};
+
+static struct gpio_led gpio_leds[] = {
+       {
+               .name                   = "omap3evm::ledb",
+               /* normally not visible (board underside) */
+               .default_trigger        = "default-on",
+               .gpio                   = -EINVAL,      /* gets replaced */
+               .active_low             = true,
+       },
+};
+
+static struct gpio_led_platform_data gpio_led_info = {
+       .leds           = gpio_leds,
+       .num_leds       = ARRAY_SIZE(gpio_leds),
+};
+
+static struct platform_device leds_gpio = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &gpio_led_info,
+       },
+};
+
+
+static int omap3evm_twl_gpio_setup(struct device *dev,
+               unsigned gpio, unsigned ngpio)
+{
+       /* gpio + 0 is "mmc0_cd" (input/IRQ) */
+       omap_cfg_reg(L8_34XX_GPIO63);
+       mmc[0].gpio_cd = gpio + 0;
+       twl4030_mmc_init(mmc);
+
+       /*
+        * Most GPIOs are for USB OTG.  Some are mostly sent to
+        * the P2 connector; notably LEDA for the LCD backlight.
+        */
+
+       /* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */
+       gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
+
+       platform_device_register(&leds_gpio);
+
+       return 0;
+}
+
+static struct twl4030_gpio_platform_data omap3evm_gpio_data = {
+       .gpio_base      = OMAP_MAX_GPIO_LINES,
+       .irq_base       = TWL4030_GPIO_IRQ_BASE,
+       .irq_end        = TWL4030_GPIO_IRQ_END,
+       .use_leds       = true,
+       .setup          = omap3evm_twl_gpio_setup,
+};
+
+static struct twl4030_usb_data omap3evm_usb_data = {
+       .usb_mode       = T2_USB_MODE_ULPI,
+};
+
+static int omap3evm_keymap[] = {
+       KEY(0, 0, KEY_LEFT),
+       KEY(0, 1, KEY_RIGHT),
+       KEY(0, 2, KEY_A),
+       KEY(0, 3, KEY_B),
+       KEY(1, 0, KEY_DOWN),
+       KEY(1, 1, KEY_UP),
+       KEY(1, 2, KEY_E),
+       KEY(1, 3, KEY_F),
+       KEY(2, 0, KEY_ENTER),
+       KEY(2, 1, KEY_I),
+       KEY(2, 2, KEY_J),
+       KEY(2, 3, KEY_K),
+       KEY(3, 0, KEY_M),
+       KEY(3, 1, KEY_N),
+       KEY(3, 2, KEY_O),
+       KEY(3, 3, KEY_P)
+};
+
+static struct twl4030_keypad_data omap3evm_kp_data = {
+       .rows           = 4,
+       .cols           = 4,
+       .keymap         = omap3evm_keymap,
+       .keymapsize     = ARRAY_SIZE(omap3evm_keymap),
+       .rep            = 1,
+};
+
+static struct twl4030_madc_platform_data omap3evm_madc_data = {
+       .irq_line       = 1,
+};
+
+static struct twl4030_platform_data omap3evm_twldata = {
+       .irq_base       = TWL4030_IRQ_BASE,
+       .irq_end        = TWL4030_IRQ_END,
+
+       /* platform_data for children goes here */
+       .keypad         = &omap3evm_kp_data,
+       .madc           = &omap3evm_madc_data,
+       .usb            = &omap3evm_usb_data,
+       .gpio           = &omap3evm_gpio_data,
+};
+
+static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = {
+       {
+               I2C_BOARD_INFO("twl4030", 0x48),
+               .flags = I2C_CLIENT_WAKE,
+               .irq = INT_34XX_SYS_NIRQ,
+               .platform_data = &omap3evm_twldata,
+       },
+};
+
+static int __init omap3_evm_i2c_init(void)
+{
+       omap_register_i2c_bus(1, 2600, omap3evm_i2c_boardinfo,
+                       ARRAY_SIZE(omap3evm_i2c_boardinfo));
+       omap_register_i2c_bus(2, 400, NULL, 0);
+       omap_register_i2c_bus(3, 400, NULL, 0);
+       return 0;
+}
+
+static struct platform_device omap3_evm_lcd_device = {
+       .name           = "omap3evm_lcd",
+       .id             = -1,
+};
+
+static struct omap_lcd_config omap3_evm_lcd_config __initdata = {
+       .ctrl_name      = "internal",
+};
+
+static void ads7846_dev_init(void)
+{
+       if (gpio_request(OMAP3_EVM_TS_GPIO, "ADS7846 pendown") < 0)
+               printk(KERN_ERR "can't get ads7846 pen down GPIO\n");
+
+       gpio_direction_input(OMAP3_EVM_TS_GPIO);
+
+       omap_set_gpio_debounce(OMAP3_EVM_TS_GPIO, 1);
+       omap_set_gpio_debounce_time(OMAP3_EVM_TS_GPIO, 0xa);
+}
+
+static int ads7846_get_pendown_state(void)
+{
+       return !gpio_get_value(OMAP3_EVM_TS_GPIO);
+}
+
+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,
+       .settle_delay_usecs     = 150,
+};
+
+static struct omap2_mcspi_device_config ads7846_mcspi_config = {
+       .turbo_mode     = 0,
+       .single_channel = 1,    /* 0: slave, 1: master */
+};
+
+struct spi_board_info omap3evm_spi_board_info[] = {
+       [0] = {
+               .modalias               = "ads7846",
+               .bus_num                = 1,
+               .chip_select            = 0,
+               .max_speed_hz           = 1500000,
+               .controller_data        = &ads7846_mcspi_config,
+               .irq                    = OMAP_GPIO_IRQ(OMAP3_EVM_TS_GPIO),
+               .platform_data          = &ads7846_config,
+       },
+};
+
+static void __init omap3_evm_init_irq(void)
+{
+       omap2_init_common_hw(mt46h32m32lf6_sdrc_params);
+       omap_init_irq();
+       omap_gpio_init();
+       omap3evm_init_smc911x();
+}
+
+static struct omap_board_config_kernel omap3_evm_config[] __initdata = {
+       { OMAP_TAG_UART,        &omap3_evm_uart_config },
+       { OMAP_TAG_LCD,         &omap3_evm_lcd_config },
+};
+
+static struct platform_device *omap3_evm_devices[] __initdata = {
+       &omap3_evm_lcd_device,
+       &omap3evm_smc911x_device,
+};
+
+static void __init omap3_evm_init(void)
+{
+       omap3_evm_i2c_init();
+
+       platform_add_devices(omap3_evm_devices, ARRAY_SIZE(omap3_evm_devices));
+       omap_board_config = omap3_evm_config;
+       omap_board_config_size = ARRAY_SIZE(omap3_evm_config);
+
+       spi_register_board_info(omap3evm_spi_board_info,
+                               ARRAY_SIZE(omap3evm_spi_board_info));
+
+       omap_serial_init();
+       usb_musb_init();
+       ads7846_dev_init();
+}
+
+static void __init omap3_evm_map_io(void)
+{
+       omap2_set_globals_343x();
+       omap2_map_common_io();
+}
+
+MACHINE_START(OMAP3EVM, "OMAP3 EVM")
+       /* Maintainer: Syed Mohammed Khasim - Texas Instruments */
+       .phys_io        = 0x48000000,
+       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .boot_params    = 0x80000100,
+       .map_io         = omap3_evm_map_io,
+       .init_irq       = omap3_evm_init_irq,
+       .init_machine   = omap3_evm_init,
+       .timer          = &omap_timer,
+MACHINE_END
index 402f09c6cf1011da8ccd291b62decf5606b6f402..e32aa23ce9629942d9d03befd1e3ee37a9b5c78f 100644 (file)
 
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
+#include <linux/regulator/machine.h>
 #include <linux/i2c/twl4030.h>
+#include <linux/leds.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <mach/hardware.h>
 #include <mach/mcspi.h>
 #include <mach/usb.h>
+#include <mach/keypad.h>
 
+#include "sdram-micron-mt46h32m32lf-6.h"
 #include "mmc-twl4030.h"
 
 #define OMAP3_PANDORA_TS_GPIO          94
 
+/* hardware debounce: (value + 1) * 31us */
+#define GPIO_DEBOUNCE_TIME             127
+
+static struct gpio_led pandora_gpio_leds[] = {
+       {
+               .name                   = "pandora::sd1",
+               .default_trigger        = "mmc0",
+               .gpio                   = 128,
+       }, {
+               .name                   = "pandora::sd2",
+               .default_trigger        = "mmc1",
+               .gpio                   = 129,
+       }, {
+               .name                   = "pandora::bluetooth",
+               .gpio                   = 158,
+       }, {
+               .name                   = "pandora::wifi",
+               .gpio                   = 159,
+       },
+};
+
+static struct gpio_led_platform_data pandora_gpio_led_data = {
+       .leds           = pandora_gpio_leds,
+       .num_leds       = ARRAY_SIZE(pandora_gpio_leds),
+};
+
+static struct platform_device pandora_leds_gpio = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &pandora_gpio_led_data,
+       },
+};
+
+#define GPIO_BUTTON(gpio_num, ev_type, ev_code, act_low, descr)        \
+{                                                              \
+       .gpio           = gpio_num,                             \
+       .type           = ev_type,                              \
+       .code           = ev_code,                              \
+       .active_low     = act_low,                              \
+       .desc           = "btn " descr,                         \
+}
+
+#define GPIO_BUTTON_LOW(gpio_num, event_code, description)     \
+       GPIO_BUTTON(gpio_num, EV_KEY, event_code, 1, description)
+
+static struct gpio_keys_button pandora_gpio_keys[] = {
+       GPIO_BUTTON_LOW(110,    KEY_UP,         "up"),
+       GPIO_BUTTON_LOW(103,    KEY_DOWN,       "down"),
+       GPIO_BUTTON_LOW(96,     KEY_LEFT,       "left"),
+       GPIO_BUTTON_LOW(98,     KEY_RIGHT,      "right"),
+       GPIO_BUTTON_LOW(111,    BTN_A,          "a"),
+       GPIO_BUTTON_LOW(106,    BTN_B,          "b"),
+       GPIO_BUTTON_LOW(109,    BTN_X,          "x"),
+       GPIO_BUTTON_LOW(101,    BTN_Y,          "y"),
+       GPIO_BUTTON_LOW(102,    BTN_TL,         "l"),
+       GPIO_BUTTON_LOW(97,     BTN_TL2,        "l2"),
+       GPIO_BUTTON_LOW(105,    BTN_TR,         "r"),
+       GPIO_BUTTON_LOW(107,    BTN_TR2,        "r2"),
+       GPIO_BUTTON_LOW(104,    KEY_LEFTCTRL,   "ctrl"),
+       GPIO_BUTTON_LOW(99,     KEY_MENU,       "menu"),
+       GPIO_BUTTON_LOW(176,    KEY_COFFEE,     "hold"),
+       GPIO_BUTTON(100, EV_KEY, KEY_LEFTALT, 0, "alt"),
+       GPIO_BUTTON(108, EV_SW, SW_LID, 1, "lid"),
+};
+
+static struct gpio_keys_platform_data pandora_gpio_key_info = {
+       .buttons        = pandora_gpio_keys,
+       .nbuttons       = ARRAY_SIZE(pandora_gpio_keys),
+};
+
+static struct platform_device pandora_keys_gpio = {
+       .name   = "gpio-keys",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &pandora_gpio_key_info,
+       },
+};
+
+static void __init pandora_keys_gpio_init(void)
+{
+       /* set debounce time for GPIO banks 4 and 6 */
+       omap_set_gpio_debounce_time(32 * 3, GPIO_DEBOUNCE_TIME);
+       omap_set_gpio_debounce_time(32 * 5, GPIO_DEBOUNCE_TIME);
+}
+
+static int pandora_keypad_map[] = {
+       /* col, row, code */
+       KEY(0, 0, KEY_9),
+       KEY(0, 1, KEY_0),
+       KEY(0, 2, KEY_BACKSPACE),
+       KEY(0, 3, KEY_O),
+       KEY(0, 4, KEY_P),
+       KEY(0, 5, KEY_K),
+       KEY(0, 6, KEY_L),
+       KEY(0, 7, KEY_ENTER),
+       KEY(1, 0, KEY_8),
+       KEY(1, 1, KEY_7),
+       KEY(1, 2, KEY_6),
+       KEY(1, 3, KEY_5),
+       KEY(1, 4, KEY_4),
+       KEY(1, 5, KEY_3),
+       KEY(1, 6, KEY_2),
+       KEY(1, 7, KEY_1),
+       KEY(2, 0, KEY_I),
+       KEY(2, 1, KEY_U),
+       KEY(2, 2, KEY_Y),
+       KEY(2, 3, KEY_T),
+       KEY(2, 4, KEY_R),
+       KEY(2, 5, KEY_E),
+       KEY(2, 6, KEY_W),
+       KEY(2, 7, KEY_Q),
+       KEY(3, 0, KEY_J),
+       KEY(3, 1, KEY_H),
+       KEY(3, 2, KEY_G),
+       KEY(3, 3, KEY_F),
+       KEY(3, 4, KEY_D),
+       KEY(3, 5, KEY_S),
+       KEY(3, 6, KEY_A),
+       KEY(3, 7, KEY_LEFTSHIFT),
+       KEY(4, 0, KEY_N),
+       KEY(4, 1, KEY_B),
+       KEY(4, 2, KEY_V),
+       KEY(4, 3, KEY_C),
+       KEY(4, 4, KEY_X),
+       KEY(4, 5, KEY_Z),
+       KEY(4, 6, KEY_DOT),
+       KEY(4, 7, KEY_COMMA),
+       KEY(5, 0, KEY_M),
+       KEY(5, 1, KEY_SPACE),
+       KEY(5, 2, KEY_FN),
+};
+
+static struct twl4030_keypad_data pandora_kp_data = {
+       .rows           = 8,
+       .cols           = 6,
+       .keymap         = pandora_keypad_map,
+       .keymapsize     = ARRAY_SIZE(pandora_keypad_map),
+       .rep            = 1,
+};
+
 static struct twl4030_hsmmc_info omap3pandora_mmc[] = {
        {
                .mmc            = 1,
@@ -69,6 +216,14 @@ static struct omap_uart_config omap3pandora_uart_config __initdata = {
        .enabled_uarts  = (1 << 2), /* UART3 */
 };
 
+static struct regulator_consumer_supply pandora_vmmc1_supply = {
+       .supply                 = "vmmc",
+};
+
+static struct regulator_consumer_supply pandora_vmmc2_supply = {
+       .supply                 = "vmmc",
+};
+
 static int omap3pandora_twl_gpio_setup(struct device *dev,
                unsigned gpio, unsigned ngpio)
 {
@@ -77,6 +232,10 @@ static int omap3pandora_twl_gpio_setup(struct device *dev,
        omap3pandora_mmc[1].gpio_cd = gpio + 1;
        twl4030_mmc_init(omap3pandora_mmc);
 
+       /* link regulators to MMC adapters */
+       pandora_vmmc1_supply.dev = omap3pandora_mmc[0].dev;
+       pandora_vmmc2_supply.dev = omap3pandora_mmc[1].dev;
+
        return 0;
 }
 
@@ -87,6 +246,36 @@ static struct twl4030_gpio_platform_data omap3pandora_gpio_data = {
        .setup          = omap3pandora_twl_gpio_setup,
 };
 
+/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
+static struct regulator_init_data pandora_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      = &pandora_vmmc1_supply,
+};
+
+/* VMMC2 for MMC2 pins CMD, CLK, DAT0..DAT3 (max 100 mA) */
+static struct regulator_init_data pandora_vmmc2 = {
+       .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      = &pandora_vmmc2_supply,
+};
+
 static struct twl4030_usb_data omap3pandora_usb_data = {
        .usb_mode       = T2_USB_MODE_ULPI,
 };
@@ -96,6 +285,9 @@ static struct twl4030_platform_data omap3pandora_twldata = {
        .irq_end        = TWL4030_IRQ_END,
        .gpio           = &omap3pandora_gpio_data,
        .usb            = &omap3pandora_usb_data,
+       .vmmc1          = &pandora_vmmc1,
+       .vmmc2          = &pandora_vmmc2,
+       .keypad         = &pandora_kp_data,
 };
 
 static struct i2c_board_info __initdata omap3pandora_i2c_boardinfo[] = {
@@ -118,7 +310,7 @@ static int __init omap3pandora_i2c_init(void)
 
 static void __init omap3pandora_init_irq(void)
 {
-       omap2_init_common_hw(NULL);
+       omap2_init_common_hw(mt46h32m32lf6_sdrc_params);
        omap_init_irq();
        omap_gpio_init();
 }
@@ -188,6 +380,8 @@ static struct omap_board_config_kernel omap3pandora_config[] __initdata = {
 
 static struct platform_device *omap3pandora_devices[] __initdata = {
        &omap3pandora_lcd_device,
+       &pandora_leds_gpio,
+       &pandora_keys_gpio,
 };
 
 static void __init omap3pandora_init(void)
@@ -201,6 +395,7 @@ static void __init omap3pandora_init(void)
        spi_register_board_info(omap3pandora_spi_board_info,
                        ARRAY_SIZE(omap3pandora_spi_board_info));
        omap3pandora_ads7846_init();
+       pandora_keys_gpio_init();
        usb_musb_init();
 }
 
index b1f23bea863fec71ff972b5c9aec8952222f9fc4..dff5528fbfb567fbdd661d1546c5a8cc83e09cd7 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/i2c/twl4030.h>
+#include <linux/regulator/machine.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
@@ -45,6 +46,7 @@
 #include <mach/nand.h>
 #include <mach/usb.h>
 
+#include "sdram-micron-mt46h32m32lf-6.h"
 #include "mmc-twl4030.h"
 
 #define OVERO_GPIO_BT_XGATE    15
@@ -271,21 +273,76 @@ static struct omap_uart_config overo_uart_config __initdata = {
        .enabled_uarts  = ((1 << 0) | (1 << 1) | (1 << 2)),
 };
 
+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,
+               .transceiver    = true,
+               .ocr_mask       = 0x00100000,   /* 3.3V */
+       },
+       {}      /* Terminator */
+};
+
+static struct regulator_consumer_supply overo_vmmc1_supply = {
+       .supply                 = "vmmc",
+};
+
+static int overo_twl_gpio_setup(struct device *dev,
+               unsigned gpio, unsigned ngpio)
+{
+       twl4030_mmc_init(mmc);
+
+       overo_vmmc1_supply.dev = mmc[0].dev;
+
+       return 0;
+}
+
 static struct twl4030_gpio_platform_data overo_gpio_data = {
        .gpio_base      = OMAP_MAX_GPIO_LINES,
        .irq_base       = TWL4030_GPIO_IRQ_BASE,
        .irq_end        = TWL4030_GPIO_IRQ_END,
+       .setup          = overo_twl_gpio_setup,
+};
+
+static struct twl4030_usb_data overo_usb_data = {
+       .usb_mode       = T2_USB_MODE_ULPI,
+};
+
+static struct regulator_init_data overo_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      = &overo_vmmc1_supply,
 };
 
+/* mmc2 (WLAN) and Bluetooth don't use twl4030 regulators */
+
 static struct twl4030_platform_data overo_twldata = {
        .irq_base       = TWL4030_IRQ_BASE,
        .irq_end        = TWL4030_IRQ_END,
        .gpio           = &overo_gpio_data,
+       .usb            = &overo_usb_data,
+       .vmmc1          = &overo_vmmc1,
 };
 
 static struct i2c_board_info __initdata overo_i2c_boardinfo[] = {
        {
-               I2C_BOARD_INFO("twl4030", 0x48),
+               I2C_BOARD_INFO("tps65950", 0x48),
                .flags = I2C_CLIENT_WAKE,
                .irq = INT_34XX_SYS_NIRQ,
                .platform_data = &overo_twldata,
@@ -303,7 +360,7 @@ static int __init overo_i2c_init(void)
 
 static void __init overo_init_irq(void)
 {
-       omap2_init_common_hw(NULL);
+       omap2_init_common_hw(mt46h32m32lf6_sdrc_params);
        omap_init_irq();
        omap_gpio_init();
 }
@@ -326,23 +383,6 @@ static struct platform_device *overo_devices[] __initdata = {
        &overo_lcd_device,
 };
 
-static struct twl4030_hsmmc_info mmc[] __initdata = {
-       {
-               .mmc            = 1,
-               .wires          = 4,
-               .gpio_cd        = -EINVAL,
-               .gpio_wp        = -EINVAL,
-       },
-       {
-               .mmc            = 2,
-               .wires          = 4,
-               .gpio_cd        = -EINVAL,
-               .gpio_wp        = -EINVAL,
-               .transceiver    = true,
-       },
-       {}      /* Terminator */
-};
-
 static void __init overo_init(void)
 {
        overo_i2c_init();
@@ -350,7 +390,6 @@ static void __init overo_init(void)
        omap_board_config = overo_config;
        omap_board_config_size = ARRAY_SIZE(overo_config);
        omap_serial_init();
-       twl4030_mmc_init(mmc);
        overo_flash_init();
        usb_musb_init();
        overo_ads7846_init();
index a7381729645cf5c4deeaf23e895c21ee1306b613..da93b86234ed47d7ef1546d55e98072c0abc913d 100644 (file)
 #include <mach/dma.h>
 #include <mach/gpmc.h>
 #include <mach/keypad.h>
+#include <mach/onenand.h>
+#include <mach/gpmc-smc91x.h>
 
 #include "mmc-twl4030.h"
 
-
-#define SMC91X_CS                      1
-#define SMC91X_GPIO_IRQ                        54
-#define SMC91X_GPIO_RESET              164
-#define SMC91X_GPIO_PWRDWN             86
-
-static struct resource rx51_smc91x_resources[] = {
-       [0] = {
-               .flags          = IORESOURCE_MEM,
-       },
-       [1] = {
-               .flags          = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
-       },
-};
-
-static struct platform_device rx51_smc91x_device = {
-       .name           = "smc91x",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(rx51_smc91x_resources),
-       .resource       = rx51_smc91x_resources,
-};
+#define SYSTEM_REV_B_USES_VAUX3        0x1699
+#define SYSTEM_REV_S_USES_VAUX3 0x8
 
 static int rx51_keymap[] = {
        KEY(0, 0, KEY_Q),
@@ -107,98 +90,6 @@ static struct twl4030_keypad_data rx51_kp_data = {
        .rep            = 1,
 };
 
-static struct platform_device *rx51_peripherals_devices[] = {
-       &rx51_smc91x_device,
-};
-
-/*
- * Timings are taken from smsc-lan91c96-ms.pdf
- */
-static int smc91x_init_gpmc(int cs)
-{
-       struct gpmc_timings t;
-       const int t2_r = 45;            /* t2 in Figure 12.10 */
-       const int t2_w = 30;            /* t2 in Figure 12.11 */
-       const int t3 = 15;              /* t3 in Figure 12.10 */
-       const int t5_r = 0;             /* t5 in Figure 12.10 */
-       const int t6_r = 45;            /* t6 in Figure 12.10 */
-       const int t6_w = 0;             /* t6 in Figure 12.11 */
-       const int t7_w = 15;            /* t7 in Figure 12.11 */
-       const int t15 = 12;             /* t15 in Figure 12.2 */
-       const int t20 = 185;            /* t20 in Figure 12.2 */
-
-       memset(&t, 0, sizeof(t));
-
-       t.cs_on = t15;
-       t.cs_rd_off = t3 + t2_r + t5_r; /* Figure 12.10 */
-       t.cs_wr_off = t3 + t2_w + t6_w; /* Figure 12.11 */
-       t.adv_on = t3;                  /* Figure 12.10 */
-       t.adv_rd_off = t3 + t2_r;       /* Figure 12.10 */
-       t.adv_wr_off = t3 + t2_w;       /* Figure 12.11 */
-       t.oe_off = t3 + t2_r + t5_r;    /* Figure 12.10 */
-       t.oe_on = t.oe_off - t6_r;      /* Figure 12.10 */
-       t.we_off = t3 + t2_w + t6_w;    /* Figure 12.11 */
-       t.we_on = t.we_off - t7_w;      /* Figure 12.11 */
-       t.rd_cycle = t20;               /* Figure 12.2 */
-       t.wr_cycle = t20;               /* Figure 12.4 */
-       t.access = t3 + t2_r + t5_r;    /* Figure 12.10 */
-       t.wr_access = t3 + t2_w + t6_w; /* Figure 12.11 */
-
-       gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, GPMC_CONFIG1_DEVICESIZE_16);
-
-       return gpmc_cs_set_timings(cs, &t);
-}
-
-static void __init rx51_init_smc91x(void)
-{
-       unsigned long cs_mem_base;
-       int ret;
-
-       omap_cfg_reg(U8_34XX_GPIO54_DOWN);
-       omap_cfg_reg(G25_34XX_GPIO86_OUT);
-       omap_cfg_reg(H19_34XX_GPIO164_OUT);
-
-       if (gpmc_cs_request(SMC91X_CS, SZ_16M, &cs_mem_base) < 0) {
-               printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
-               return;
-       }
-
-       rx51_smc91x_resources[0].start = cs_mem_base + 0x300;
-       rx51_smc91x_resources[0].end = cs_mem_base + 0x30f;
-
-       smc91x_init_gpmc(SMC91X_CS);
-
-       if (gpio_request(SMC91X_GPIO_IRQ, "SMC91X irq") < 0)
-               goto free1;
-
-       gpio_direction_input(SMC91X_GPIO_IRQ);
-       rx51_smc91x_resources[1].start = gpio_to_irq(SMC91X_GPIO_IRQ);
-
-       ret = gpio_request(SMC91X_GPIO_PWRDWN, "SMC91X powerdown");
-       if (ret)
-               goto free2;
-       gpio_direction_output(SMC91X_GPIO_PWRDWN, 0);
-
-       ret = gpio_request(SMC91X_GPIO_RESET, "SMC91X reset");
-       if (ret)
-               goto free3;
-       gpio_direction_output(SMC91X_GPIO_RESET, 0);
-       gpio_set_value(SMC91X_GPIO_RESET, 1);
-       msleep(100);
-       gpio_set_value(SMC91X_GPIO_RESET, 0);
-
-       return;
-
-free3:
-       gpio_free(SMC91X_GPIO_PWRDWN);
-free2:
-       gpio_free(SMC91X_GPIO_IRQ);
-free1:
-       gpmc_cs_free(SMC91X_CS);
-
-       printk(KERN_ERR "Could not initialize smc91x\n");
-}
-
 static struct twl4030_madc_platform_data rx51_madc_data = {
        .irq_line               = 1,
 };
@@ -259,7 +150,7 @@ static struct regulator_init_data rx51_vaux2 = {
 };
 
 /* VAUX3 - adds more power to VIO_18 rail */
-static struct regulator_init_data rx51_vaux3 = {
+static struct regulator_init_data rx51_vaux3_cam = {
        .constraints = {
                .name                   = "VCAM_DIG_18",
                .min_uV                 = 1800000,
@@ -272,6 +163,22 @@ static struct regulator_init_data rx51_vaux3 = {
        },
 };
 
+static struct regulator_init_data rx51_vaux3_mmc = {
+       .constraints = {
+               .name                   = "VMMC2_30",
+               .min_uV                 = 2800000,
+               .max_uV                 = 3000000,
+               .apply_uV               = true,
+               .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      = &rx51_vmmc2_supply,
+};
+
 static struct regulator_init_data rx51_vaux4 = {
        .constraints = {
                .name                   = "VCAM_ANA_28",
@@ -382,10 +289,8 @@ static struct twl4030_platform_data rx51_twldata = {
 
        .vaux1                  = &rx51_vaux1,
        .vaux2                  = &rx51_vaux2,
-       .vaux3                  = &rx51_vaux3,
        .vaux4                  = &rx51_vaux4,
        .vmmc1                  = &rx51_vmmc1,
-       .vmmc2                  = &rx51_vmmc2,
        .vsim                   = &rx51_vsim,
        .vdac                   = &rx51_vdac,
 };
@@ -401,6 +306,13 @@ static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_1[] = {
 
 static int __init rx51_i2c_init(void)
 {
+       if ((system_rev >= SYSTEM_REV_S_USES_VAUX3 && system_rev < 0x100) ||
+           system_rev >= SYSTEM_REV_B_USES_VAUX3)
+               rx51_twldata.vaux3 = &rx51_vaux3_mmc;
+       else {
+               rx51_twldata.vaux3 = &rx51_vaux3_cam;
+               rx51_twldata.vmmc2 = &rx51_vmmc2;
+       }
        omap_register_i2c_bus(1, 2600, rx51_peripherals_i2c_board_info_1,
                        ARRAY_SIZE(rx51_peripherals_i2c_board_info_1));
        omap_register_i2c_bus(2, 100, NULL, 0);
@@ -408,12 +320,94 @@ static int __init rx51_i2c_init(void)
        return 0;
 }
 
+#if defined(CONFIG_MTD_ONENAND_OMAP2) || \
+       defined(CONFIG_MTD_ONENAND_OMAP2_MODULE)
+
+static struct mtd_partition onenand_partitions[] = {
+       {
+               .name           = "bootloader",
+               .offset         = 0,
+               .size           = 0x20000,
+               .mask_flags     = MTD_WRITEABLE,        /* Force read-only */
+       },
+       {
+               .name           = "config",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 0x60000,
+       },
+       {
+               .name           = "log",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 0x40000,
+       },
+       {
+               .name           = "kernel",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 0x200000,
+       },
+       {
+               .name           = "initfs",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 0x200000,
+       },
+       {
+               .name           = "rootfs",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct omap_onenand_platform_data board_onenand_data = {
+       .cs             = 0,
+       .gpio_irq       = 65,
+       .parts          = onenand_partitions,
+       .nr_parts       = ARRAY_SIZE(onenand_partitions),
+};
+
+static void __init board_onenand_init(void)
+{
+       gpmc_onenand_init(&board_onenand_data);
+}
+
+#else
+
+static inline void board_onenand_init(void)
+{
+}
+
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+
+static struct omap_smc91x_platform_data board_smc91x_data = {
+       .cs             = 1,
+       .gpio_irq       = 54,
+       .gpio_pwrdwn    = 86,
+       .gpio_reset     = 164,
+       .flags          = GPMC_TIMINGS_SMC91C96 | IORESOURCE_IRQ_HIGHLEVEL,
+};
+
+static void __init board_smc91x_init(void)
+{
+       omap_cfg_reg(U8_34XX_GPIO54_DOWN);
+       omap_cfg_reg(G25_34XX_GPIO86_OUT);
+       omap_cfg_reg(H19_34XX_GPIO164_OUT);
+
+       gpmc_smc91x_init(&board_smc91x_data);
+}
+
+#else
+
+static inline void board_smc91x_init(void)
+{
+}
+
+#endif
 
 void __init rx51_peripherals_init(void)
 {
-       platform_add_devices(rx51_peripherals_devices,
-                               ARRAY_SIZE(rx51_peripherals_devices));
        rx51_i2c_init();
-       rx51_init_smc91x();
+       board_onenand_init();
+       board_smc91x_init();
 }
 
diff --git a/arch/arm/mach-omap2/board-zoom-debugboard.c b/arch/arm/mach-omap2/board-zoom-debugboard.c
new file mode 100644 (file)
index 0000000..bac5c43
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2009 Texas Instruments Inc.
+ * Mikkel Christensen <mlc@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/serial_8250.h>
+#include <linux/smsc911x.h>
+
+#include <mach/gpmc.h>
+
+#define ZOOM2_SMSC911X_CS      7
+#define ZOOM2_SMSC911X_GPIO    158
+#define ZOOM2_QUADUART_CS      3
+#define ZOOM2_QUADUART_GPIO    102
+#define QUART_CLK              1843200
+#define DEBUG_BASE             0x08000000
+#define ZOOM2_ETHR_START       DEBUG_BASE
+
+static struct resource zoom2_smsc911x_resources[] = {
+       [0] = {
+               .start  = ZOOM2_ETHR_START,
+               .end    = ZOOM2_ETHR_START + SZ_4K,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+       },
+};
+
+static struct smsc911x_platform_config zoom2_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 = {
+       .name           = "smsc911x",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(zoom2_smsc911x_resources),
+       .resource       = zoom2_smsc911x_resources,
+       .dev            = {
+               .platform_data = &zoom2_smsc911x_config,
+       },
+};
+
+static inline void __init zoom2_init_smsc911x(void)
+{
+       int eth_cs;
+       unsigned long cs_mem_base;
+       int eth_gpio = 0;
+
+       eth_cs = ZOOM2_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;
+
+       eth_gpio = ZOOM2_SMSC911X_GPIO;
+
+       zoom2_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",
+                               eth_gpio);
+               return;
+       }
+       gpio_direction_input(eth_gpio);
+}
+
+static struct plat_serial8250_port serial_platform_data[] = {
+       {
+               .mapbase        = 0x10000000,
+               .irq            = OMAP_GPIO_IRQ(102),
+               .flags          = UPF_BOOT_AUTOCONF|UPF_IOREMAP|UPF_SHARE_IRQ,
+               .iotype         = UPIO_MEM,
+               .regshift       = 1,
+               .uartclk        = QUART_CLK,
+       }, {
+               .flags          = 0
+       }
+};
+
+static struct platform_device zoom2_debugboard_serial_device = {
+       .name                   = "serial8250",
+       .id                     = PLAT8250_DEV_PLATFORM1,
+       .dev                    = {
+               .platform_data  = serial_platform_data,
+       },
+};
+
+static inline void __init zoom2_init_quaduart(void)
+{
+       int quart_cs;
+       unsigned long cs_mem_base;
+       int quart_gpio = 0;
+
+       quart_cs = ZOOM2_QUADUART_CS;
+
+       if (gpmc_cs_request(quart_cs, SZ_1M, &cs_mem_base) < 0) {
+               printk(KERN_ERR "Failed to request GPMC mem"
+                               "for Quad UART(TL16CP754C)\n");
+               return;
+       }
+
+       quart_gpio = ZOOM2_QUADUART_GPIO;
+
+       if (gpio_request(quart_gpio, "TL16CP754C GPIO") < 0) {
+               printk(KERN_ERR "Failed to request GPIO%d for TL16CP754C\n",
+                                                               quart_gpio);
+               return;
+       }
+       gpio_direction_input(quart_gpio);
+}
+
+static inline int omap_zoom2_debugboard_detect(void)
+{
+       int debug_board_detect = 0;
+
+       debug_board_detect = ZOOM2_SMSC911X_GPIO;
+
+       if (gpio_request(debug_board_detect, "Zoom2 debug board detect") < 0) {
+               printk(KERN_ERR "Failed to request GPIO%d for Zoom2 debug"
+               "board detect\n", debug_board_detect);
+               return 0;
+       }
+       gpio_direction_input(debug_board_detect);
+
+       if (!gpio_get_value(debug_board_detect)) {
+               gpio_free(debug_board_detect);
+               return 0;
+       }
+       return 1;
+}
+
+static struct platform_device *zoom2_devices[] __initdata = {
+       &zoom2_smsc911x_device,
+       &zoom2_debugboard_serial_device,
+};
+
+int __init omap_zoom2_debugboard_init(void)
+{
+       if (!omap_zoom2_debugboard_detect())
+               return 0;
+
+       zoom2_init_smsc911x();
+       zoom2_init_quaduart();
+       return platform_add_devices(zoom2_devices, ARRAY_SIZE(zoom2_devices));
+}
diff --git a/arch/arm/mach-omap2/board-zoom2.c b/arch/arm/mach-omap2/board-zoom2.c
new file mode 100644 (file)
index 0000000..bcc0f76
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2009 Texas Instruments Inc.
+ * Mikkel Christensen <mlc@ti.com>
+ *
+ * Modified from mach-omap2/board-ldp.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/gpio.h>
+#include <linux/i2c/twl4030.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/common.h>
+#include <mach/usb.h>
+
+#include "mmc-twl4030.h"
+
+static void __init omap_zoom2_init_irq(void)
+{
+       omap2_init_common_hw(NULL);
+       omap_init_irq();
+       omap_gpio_init();
+}
+
+static struct omap_uart_config zoom2_uart_config __initdata = {
+       .enabled_uarts  = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
+static struct omap_board_config_kernel zoom2_config[] __initdata = {
+       { OMAP_TAG_UART,        &zoom2_uart_config },
+};
+
+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,
+};
+
+static struct twl4030_platform_data zoom2_twldata = {
+       .irq_base       = TWL4030_IRQ_BASE,
+       .irq_end        = TWL4030_IRQ_END,
+
+       /* platform_data for children goes here */
+       .gpio           = &zoom2_gpio_data,
+};
+
+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;
+}
+
+static struct twl4030_hsmmc_info mmc[] __initdata = {
+       {
+               .mmc            = 1,
+               .wires          = 4,
+               .gpio_cd        = -EINVAL,
+               .gpio_wp        = -EINVAL,
+       },
+       {}      /* Terminator */
+};
+
+extern int __init omap_zoom2_debugboard_init(void);
+
+static void __init omap_zoom2_init(void)
+{
+       omap_i2c_init();
+       omap_board_config = zoom2_config;
+       omap_board_config_size = ARRAY_SIZE(zoom2_config);
+       omap_serial_init();
+       omap_zoom2_debugboard_init();
+       twl4030_mmc_init(mmc);
+       usb_musb_init();
+}
+
+static void __init omap_zoom2_map_io(void)
+{
+       omap2_set_globals_343x();
+       omap2_map_common_io();
+}
+
+MACHINE_START(OMAP_ZOOM2, "OMAP Zoom2 board")
+       .phys_io        = 0x48000000,
+       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .boot_params    = 0x80000100,
+       .map_io         = omap_zoom2_map_io,
+       .init_irq       = omap_zoom2_init_irq,
+       .init_machine   = omap_zoom2_init,
+       .timer          = &omap_timer,
+MACHINE_END
index 4247a1534411ba9f9cf5bfd23c9abf94bcd799c0..ba528f85749c68d63cd3b360699130c340865e6e 100644 (file)
@@ -91,9 +91,9 @@ static void _omap2xxx_clk_commit(struct clk *clk)
                return;
 
        prm_write_mod_reg(OMAP24XX_VALID_CONFIG, OMAP24XX_GR_MOD,
-               OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET);
+               OMAP2_PRCM_CLKCFG_CTRL_OFFSET);
        /* OCP barrier */
-       prm_read_mod_reg(OMAP24XX_GR_MOD, OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET);
+       prm_read_mod_reg(OMAP24XX_GR_MOD, OMAP2_PRCM_CLKCFG_CTRL_OFFSET);
 }
 
 /*
@@ -547,8 +547,8 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
        const struct clksel_rate *clkr;
        u32 last_div = 0;
 
-       printk(KERN_INFO "clock: clksel_round_rate_div: %s target_rate %ld\n",
-              clk->name, target_rate);
+       pr_debug("clock: clksel_round_rate_div: %s target_rate %ld\n",
+                clk->name, target_rate);
 
        *new_div = 1;
 
@@ -562,7 +562,7 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
 
                /* Sanity check */
                if (clkr->div <= last_div)
-                       printk(KERN_ERR "clock: clksel_rate table not sorted "
+                       pr_err("clock: clksel_rate table not sorted "
                               "for clock %s", clk->name);
 
                last_div = clkr->div;
@@ -574,7 +574,7 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
        }
 
        if (!clkr->div) {
-               printk(KERN_ERR "clock: Could not find divisor for target "
+               pr_err("clock: Could not find divisor for target "
                       "rate %ld for clock %s parent %s\n", target_rate,
                       clk->name, clk->parent->name);
                return ~0;
@@ -582,8 +582,8 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
 
        *new_div = clkr->div;
 
-       printk(KERN_INFO "clock: new_div = %d, new_rate = %ld\n", *new_div,
-              (clk->parent->rate / clkr->div));
+       pr_debug("clock: new_div = %d, new_rate = %ld\n", *new_div,
+                (clk->parent->rate / clkr->div));
 
        return (clk->parent->rate / clkr->div);
 }
@@ -1035,7 +1035,7 @@ void omap2_clk_disable_unused(struct clk *clk)
        if ((regval32 & (1 << clk->enable_bit)) == v)
                return;
 
-       printk(KERN_INFO "Disabling unused clock \"%s\"\n", clk->name);
+       printk(KERN_DEBUG "Disabling unused clock \"%s\"\n", clk->name);
        if (cpu_is_omap34xx()) {
                omap2_clk_enable(clk);
                omap2_clk_disable(clk);
index e4cef333e291077d46e9d5d9dde3947c6a516f50..44de0271fc2f23a434e888176e9f34e6f0eba3dc 100644 (file)
@@ -233,6 +233,8 @@ static struct prcm_config *curr_prcm_set;
 static struct clk *vclk;
 static struct clk *sclk;
 
+static void __iomem *prcm_clksrc_ctrl;
+
 /*-------------------------------------------------------------------------
  * Omap24xx specific clock functions
  *-------------------------------------------------------------------------*/
@@ -269,10 +271,9 @@ static int omap2_enable_osc_ck(struct clk *clk)
 {
        u32 pcc;
 
-       pcc = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL);
+       pcc = __raw_readl(prcm_clksrc_ctrl);
 
-       __raw_writel(pcc & ~OMAP_AUTOEXTCLKMODE_MASK,
-                     OMAP24XX_PRCM_CLKSRC_CTRL);
+       __raw_writel(pcc & ~OMAP_AUTOEXTCLKMODE_MASK, prcm_clksrc_ctrl);
 
        return 0;
 }
@@ -281,10 +282,9 @@ static void omap2_disable_osc_ck(struct clk *clk)
 {
        u32 pcc;
 
-       pcc = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL);
+       pcc = __raw_readl(prcm_clksrc_ctrl);
 
-       __raw_writel(pcc | OMAP_AUTOEXTCLKMODE_MASK,
-                     OMAP24XX_PRCM_CLKSRC_CTRL);
+       __raw_writel(pcc | OMAP_AUTOEXTCLKMODE_MASK, prcm_clksrc_ctrl);
 }
 
 static const struct clkops clkops_oscck = {
@@ -654,7 +654,7 @@ static u32 omap2_get_sysclkdiv(void)
 {
        u32 div;
 
-       div = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL);
+       div = __raw_readl(prcm_clksrc_ctrl);
        div &= OMAP_SYSCLKDIV_MASK;
        div >>= OMAP_SYSCLKDIV_SHIFT;
 
@@ -714,15 +714,18 @@ int __init omap2_clk_init(void)
        struct omap_clk *c;
        u32 clkrate;
 
-       if (cpu_is_omap242x())
+       if (cpu_is_omap242x()) {
+               prcm_clksrc_ctrl = OMAP2420_PRCM_CLKSRC_CTRL;
                cpu_mask = RATE_IN_242X;
-       else if (cpu_is_omap2430())
+       } else if (cpu_is_omap2430()) {
+               prcm_clksrc_ctrl = OMAP2430_PRCM_CLKSRC_CTRL;
                cpu_mask = RATE_IN_243X;
+       }
 
        clk_init(&omap2_clk_functions);
 
        for (c = omap24xx_clks; c < omap24xx_clks + ARRAY_SIZE(omap24xx_clks); c++)
-               clk_init_one(c->lk.clk);
+               clk_preinit(c->lk.clk);
 
        osc_ck.rate = omap2_osc_clk_recalc(&osc_ck);
        propagate_rate(&osc_ck);
index 88c5acb40fcf578e97bc769cdc369ff31d3053f2..458f00cdcbea3a354658f2b2fe7b23c25cf3ec55 100644 (file)
 #include "cm-regbits-24xx.h"
 #include "sdrc.h"
 
+/* REVISIT: These should be set dynamically for CONFIG_MULTI_OMAP2 */
+#ifdef CONFIG_ARCH_OMAP2420
+#define OMAP_CM_REGADDR                        OMAP2420_CM_REGADDR
+#define OMAP24XX_PRCM_CLKOUT_CTRL      OMAP2420_PRCM_CLKOUT_CTRL
+#define OMAP24XX_PRCM_CLKEMUL_CTRL     OMAP2420_PRCM_CLKEMUL_CTRL
+#else
+#define OMAP_CM_REGADDR                        OMAP2430_CM_REGADDR
+#define OMAP24XX_PRCM_CLKOUT_CTRL      OMAP2430_PRCM_CLKOUT_CTRL
+#define OMAP24XX_PRCM_CLKEMUL_CTRL     OMAP2430_PRCM_CLKEMUL_CTRL
+#endif
+
 static unsigned long omap2_table_mpu_recalc(struct clk *clk);
 static int omap2_select_table_rate(struct clk *clk, unsigned long rate);
 static long omap2_round_to_table_rate(struct clk *clk, unsigned long rate);
index ba05aa42bd8ed961b3015d0608557abc97fc07db..9e43fe5209d337b7f149099d469339d670b572e6 100644 (file)
@@ -129,6 +129,9 @@ static struct omap_clk omap34xx_clks[] = {
        CLK(NULL,       "sgx_fck",      &sgx_fck,       CK_3430ES2),
        CLK(NULL,       "sgx_ick",      &sgx_ick,       CK_3430ES2),
        CLK(NULL,       "d2d_26m_fck",  &d2d_26m_fck,   CK_3430ES1),
+       CLK(NULL,       "modem_fck",    &modem_fck,     CK_343X),
+       CLK(NULL,       "sad2d_ick",    &sad2d_ick,     CK_343X),
+       CLK(NULL,       "mad2d_ick",    &mad2d_ick,     CK_343X),
        CLK(NULL,       "gpt10_fck",    &gpt10_fck,     CK_343X),
        CLK(NULL,       "gpt11_fck",    &gpt11_fck,     CK_343X),
        CLK(NULL,       "cpefuse_fck",  &cpefuse_fck,   CK_3430ES2),
@@ -281,6 +284,8 @@ static struct omap_clk omap34xx_clks[] = {
 
 #define MAX_DPLL_WAIT_TRIES            1000000
 
+#define MIN_SDRC_DLL_LOCK_FREQ         83000000
+
 /**
  * omap3_dpll_recalc - recalculate DPLL rate
  * @clk: DPLL struct clk
@@ -703,6 +708,7 @@ static int omap3_dpll4_set_rate(struct clk *clk, unsigned long rate)
 static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate)
 {
        u32 new_div = 0;
+       u32 unlock_dll = 0;
        unsigned long validrate, sdrcrate;
        struct omap_sdrc_params *sp;
 
@@ -729,17 +735,22 @@ static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate)
        if (!sp)
                return -EINVAL;
 
-       pr_info("clock: changing CORE DPLL rate from %lu to %lu\n", clk->rate,
-               validrate);
-       pr_info("clock: SDRC timing params used: %08x %08x %08x\n",
-               sp->rfr_ctrl, sp->actim_ctrla, sp->actim_ctrlb);
+       if (sdrcrate < MIN_SDRC_DLL_LOCK_FREQ) {
+               pr_debug("clock: will unlock SDRC DLL\n");
+               unlock_dll = 1;
+       }
+
+       pr_debug("clock: changing CORE DPLL rate from %lu to %lu\n", clk->rate,
+                validrate);
+       pr_debug("clock: SDRC timing params used: %08x %08x %08x\n",
+                sp->rfr_ctrl, sp->actim_ctrla, sp->actim_ctrlb);
 
        /* REVISIT: SRAM code doesn't support other M2 divisors yet */
        WARN_ON(new_div != 1 && new_div != 2);
 
        /* REVISIT: Add SDRC_MR changing to this code also */
        omap3_configure_core_dpll(sp->rfr_ctrl, sp->actim_ctrla,
-                                 sp->actim_ctrlb, new_div);
+                                 sp->actim_ctrlb, new_div, unlock_dll);
 
        return 0;
 }
@@ -956,7 +967,7 @@ int __init omap2_clk_init(void)
        clk_init(&omap2_clk_functions);
 
        for (c = omap34xx_clks; c < omap34xx_clks + ARRAY_SIZE(omap34xx_clks); c++)
-               clk_init_one(c->lk.clk);
+               clk_preinit(c->lk.clk);
 
        for (c = omap34xx_clks; c < omap34xx_clks + ARRAY_SIZE(omap34xx_clks); c++)
                if (c->cpu & cpu_clkflg) {
index 017a30e9aa1de28740c740c0c7b5fa286c0b6763..e433aec4efdd2c65587556702df13001c9aaffe6 100644 (file)
@@ -27,6 +27,8 @@
 #include "prm.h"
 #include "prm-regbits-34xx.h"
 
+#define OMAP_CM_REGADDR                OMAP34XX_CM_REGADDR
+
 static unsigned long omap3_dpll_recalc(struct clk *clk);
 static unsigned long omap3_clkoutx2_recalc(struct clk *clk);
 static void omap3_dpll_allow_idle(struct clk *clk);
@@ -1228,6 +1230,37 @@ static struct clk d2d_26m_fck = {
        .recalc         = &followparent_recalc,
 };
 
+static struct clk modem_fck = {
+       .name           = "modem_fck",
+       .ops            = &clkops_omap2_dflt_wait,
+       .parent         = &sys_ck,
+       .init           = &omap2_init_clk_clkdm,
+       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .enable_bit     = OMAP3430_EN_MODEM_SHIFT,
+       .clkdm_name     = "d2d_clkdm",
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk sad2d_ick = {
+       .name           = "sad2d_ick",
+       .ops            = &clkops_omap2_dflt_wait,
+       .parent         = &l3_ick,
+       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .enable_bit     = OMAP3430_EN_SAD2D_SHIFT,
+       .clkdm_name     = "d2d_clkdm",
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk mad2d_ick = {
+       .name           = "mad2d_ick",
+       .ops            = &clkops_omap2_dflt_wait,
+       .parent         = &l3_ick,
+       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN3),
+       .enable_bit     = OMAP3430_EN_MAD2D_SHIFT,
+       .clkdm_name     = "d2d_clkdm",
+       .recalc         = &followparent_recalc,
+};
+
 static const struct clksel omap343x_gpt_clksel[] = {
        { .parent = &omap_32k_fck, .rates = gpt_32k_rates },
        { .parent = &sys_ck,       .rates = gpt_sys_rates },
@@ -1945,8 +1978,6 @@ static struct clk usb_l4_ick = {
        .recalc         = &omap2_clksel_recalc,
 };
 
-/* XXX MDM_INTC_ICK, SAD2D_ICK ?? */
-
 /* SECURITY_L4_ICK2 based clocks */
 
 static struct clk security_l4_ick2 = {
index 281d5da1918879a2ca927ee4616cbfb495a4fdbc..fe319ae4ca0a4c5a544bdc6652c2d0c1e488317e 100644 (file)
@@ -195,7 +195,7 @@ static struct clockdomain sgx_clkdm = {
 static struct clockdomain d2d_clkdm = {
        .name           = "d2d_clkdm",
        .pwrdm          = { .name = "core_pwrdm" },
-       .flags          = CLKDM_CAN_HWSUP,
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
        .clktrctrl_mask = OMAP3430ES1_CLKTRCTRL_D2D_MASK,
        .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
 };
index 6f3f5a36aae664960e037d59200dba8fe025feab..6923deb98a2884e1c870514581515a30bd670687 100644 (file)
 #define OMAP3430_CLKACTIVITY_MPU_MASK                  (1 << 0)
 
 /* CM_FCLKEN1_CORE specific bits */
+#define OMAP3430_EN_MODEM                              (1 << 31)
+#define OMAP3430_EN_MODEM_SHIFT                                31
 
 /* CM_ICLKEN1_CORE specific bits */
 #define OMAP3430_EN_ICR                                        (1 << 29)
 #define OMAP3430_EN_MAILBOXES_SHIFT                    7
 #define OMAP3430_EN_OMAPCTRL                           (1 << 6)
 #define OMAP3430_EN_OMAPCTRL_SHIFT                     6
+#define OMAP3430_EN_SAD2D                              (1 << 3)
+#define OMAP3430_EN_SAD2D_SHIFT                                3
 #define OMAP3430_EN_SDRC                               (1 << 1)
 #define OMAP3430_EN_SDRC_SHIFT                         1
 
 #define OMAP3430_EN_DES1                               (1 << 0)
 #define OMAP3430_EN_DES1_SHIFT                         0
 
+/* CM_ICLKEN3_CORE */
+#define OMAP3430_EN_MAD2D_SHIFT                                3
+#define OMAP3430_EN_MAD2D                              (1 << 3)
+
 /* CM_FCLKEN3_CORE specific bits */
 #define OMAP3430ES2_EN_TS_SHIFT                                1
 #define OMAP3430ES2_EN_TS_MASK                         (1 << 1)
 #define OMAP3430ES2_ST_CPEFUSE_MASK                    (1 << 0)
 
 /* CM_AUTOIDLE1_CORE */
+#define OMAP3430_AUTO_MODEM                            (1 << 31)
+#define OMAP3430_AUTO_MODEM_SHIFT                      31
 #define OMAP3430ES2_AUTO_MMC3                          (1 << 30)
 #define OMAP3430ES2_AUTO_MMC3_SHIFT                    30
 #define OMAP3430ES2_AUTO_ICR                           (1 << 29)
 #define OMAP3430_AUTO_HSOTGUSB_SHIFT                   4
 #define OMAP3430ES1_AUTO_D2D                           (1 << 3)
 #define OMAP3430ES1_AUTO_D2D_SHIFT                     3
+#define OMAP3430_AUTO_SAD2D                            (1 << 3)
+#define OMAP3430_AUTO_SAD2D_SHIFT                      3
 #define OMAP3430_AUTO_SSI                              (1 << 0)
 #define OMAP3430_AUTO_SSI_SHIFT                                0
 
 #define        OMAP3430ES2_AUTO_USBTLL                         (1 << 2)
 #define OMAP3430ES2_AUTO_USBTLL_SHIFT                  2
 #define OMAP3430ES2_AUTO_USBTLL_MASK                   (1 << 2)
+#define OMAP3430_AUTO_MAD2D_SHIFT                      3
+#define OMAP3430_AUTO_MAD2D                            (1 << 3)
 
 /* CM_CLKSEL_CORE */
 #define OMAP3430_CLKSEL_SSI_SHIFT                      8
index 65fdf78c91e1b1d03c62f006d0937e35b16f3d28..1d3c93bf86d32a69c9d9d5a258bce6a51078c6fb 100644 (file)
 
 #include "prcm-common.h"
 
-#ifndef __ASSEMBLER__
-#define OMAP_CM_REGADDR(module, reg)                                   \
-                       IO_ADDRESS(OMAP2_CM_BASE + (module) + (reg))
-#else
 #define OMAP2420_CM_REGADDR(module, reg)                               \
                        IO_ADDRESS(OMAP2420_CM_BASE + (module) + (reg))
 #define OMAP2430_CM_REGADDR(module, reg)                               \
                        IO_ADDRESS(OMAP2430_CM_BASE + (module) + (reg))
 #define OMAP34XX_CM_REGADDR(module, reg)                               \
                        IO_ADDRESS(OMAP3430_CM_BASE + (module) + (reg))
-#endif
 
 /*
  * Architecture-specific global CM registers
@@ -38,6 +33,7 @@
 #define OMAP3430_CM_SYSCONFIG          OMAP_CM_REGADDR(OCP_MOD, 0x0010)
 #define OMAP3430_CM_POLCTRL            OMAP_CM_REGADDR(OCP_MOD, 0x009c)
 
+#define OMAP3_CM_CLKOUT_CTRL_OFFSET    0x0070
 #define OMAP3430_CM_CLKOUT_CTRL                OMAP_CM_REGADDR(OMAP3430_CCR_MOD, 0x0070)
 
 /*
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
new file mode 100644 (file)
index 0000000..2fd22f9
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * linux/arch/arm/mach-omap2/gpmc-onenand.c
+ *
+ * Copyright (C) 2006 - 2009 Nokia Corporation
+ * Contacts:   Juha Yrjola
+ *             Tony Lindgren
+ *
+ * This 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/mtd/onenand_regs.h>
+#include <linux/io.h>
+
+#include <asm/mach/flash.h>
+
+#include <mach/onenand.h>
+#include <mach/board.h>
+#include <mach/gpmc.h>
+
+static struct omap_onenand_platform_data *gpmc_onenand_data;
+
+static struct platform_device gpmc_onenand_device = {
+       .name           = "omap2-onenand",
+       .id             = -1,
+};
+
+static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base)
+{
+       struct gpmc_timings t;
+
+       const int t_cer = 15;
+       const int t_avdp = 12;
+       const int t_aavdh = 7;
+       const int t_ce = 76;
+       const int t_aa = 76;
+       const int t_oe = 20;
+       const int t_cez = 20; /* max of t_cez, t_oez */
+       const int t_ds = 30;
+       const int t_wpl = 40;
+       const int t_wph = 30;
+
+       memset(&t, 0, sizeof(t));
+       t.sync_clk = 0;
+       t.cs_on = 0;
+       t.adv_on = 0;
+
+       /* Read */
+       t.adv_rd_off = gpmc_round_ns_to_ticks(max_t(int, t_avdp, t_cer));
+       t.oe_on  = t.adv_rd_off + gpmc_round_ns_to_ticks(t_aavdh);
+       t.access = t.adv_on + gpmc_round_ns_to_ticks(t_aa);
+       t.access = max_t(int, t.access, t.cs_on + gpmc_round_ns_to_ticks(t_ce));
+       t.access = max_t(int, t.access, t.oe_on + gpmc_round_ns_to_ticks(t_oe));
+       t.oe_off = t.access + gpmc_round_ns_to_ticks(1);
+       t.cs_rd_off = t.oe_off;
+       t.rd_cycle  = t.cs_rd_off + gpmc_round_ns_to_ticks(t_cez);
+
+       /* Write */
+       t.adv_wr_off = t.adv_rd_off;
+       t.we_on  = t.oe_on;
+       if (cpu_is_omap34xx()) {
+               t.wr_data_mux_bus = t.we_on;
+               t.wr_access = t.we_on + gpmc_round_ns_to_ticks(t_ds);
+       }
+       t.we_off = t.we_on + gpmc_round_ns_to_ticks(t_wpl);
+       t.cs_wr_off = t.we_off + gpmc_round_ns_to_ticks(t_wph);
+       t.wr_cycle  = t.cs_wr_off + gpmc_round_ns_to_ticks(t_cez);
+
+       /* Configure GPMC for asynchronous read */
+       gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1,
+                         GPMC_CONFIG1_DEVICESIZE_16 |
+                         GPMC_CONFIG1_MUXADDDATA);
+
+       return gpmc_cs_set_timings(cs, &t);
+}
+
+static void set_onenand_cfg(void __iomem *onenand_base, int latency,
+                               int sync_read, int sync_write, int hf)
+{
+       u32 reg;
+
+       reg = readw(onenand_base + ONENAND_REG_SYS_CFG1);
+       reg &= ~((0x7 << ONENAND_SYS_CFG1_BRL_SHIFT) | (0x7 << 9));
+       reg |=  (latency << ONENAND_SYS_CFG1_BRL_SHIFT) |
+               ONENAND_SYS_CFG1_BL_16;
+       if (sync_read)
+               reg |= ONENAND_SYS_CFG1_SYNC_READ;
+       else
+               reg &= ~ONENAND_SYS_CFG1_SYNC_READ;
+       if (sync_write)
+               reg |= ONENAND_SYS_CFG1_SYNC_WRITE;
+       else
+               reg &= ~ONENAND_SYS_CFG1_SYNC_WRITE;
+       if (hf)
+               reg |= ONENAND_SYS_CFG1_HF;
+       else
+               reg &= ~ONENAND_SYS_CFG1_HF;
+       writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
+}
+
+static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
+                                       void __iomem *onenand_base,
+                                       int freq)
+{
+       struct gpmc_timings t;
+       const int t_cer  = 15;
+       const int t_avdp = 12;
+       const int t_cez  = 20; /* max of t_cez, t_oez */
+       const int t_ds   = 30;
+       const int t_wpl  = 40;
+       const int t_wph  = 30;
+       int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo;
+       int tick_ns, div, fclk_offset_ns, fclk_offset, gpmc_clk_ns, latency;
+       int first_time = 0, hf = 0, sync_read = 0, sync_write = 0;
+       int err, ticks_cez;
+       int cs = cfg->cs;
+       u32 reg;
+
+       if (cfg->flags & ONENAND_SYNC_READ) {
+               sync_read = 1;
+       } else if (cfg->flags & ONENAND_SYNC_READWRITE) {
+               sync_read = 1;
+               sync_write = 1;
+       }
+
+       if (!freq) {
+               /* Very first call freq is not known */
+               err = omap2_onenand_set_async_mode(cs, onenand_base);
+               if (err)
+                       return err;
+               reg = readw(onenand_base + ONENAND_REG_VERSION_ID);
+               switch ((reg >> 4) & 0xf) {
+               case 0:
+                       freq = 40;
+                       break;
+               case 1:
+                       freq = 54;
+                       break;
+               case 2:
+                       freq = 66;
+                       break;
+               case 3:
+                       freq = 83;
+                       break;
+               case 4:
+                       freq = 104;
+                       break;
+               default:
+                       freq = 54;
+                       break;
+               }
+               first_time = 1;
+       }
+
+       switch (freq) {
+       case 83:
+               min_gpmc_clk_period = 12; /* 83 MHz */
+               t_ces   = 5;
+               t_avds  = 4;
+               t_avdh  = 2;
+               t_ach   = 6;
+               t_aavdh = 6;
+               t_rdyo  = 9;
+               break;
+       case 66:
+               min_gpmc_clk_period = 15; /* 66 MHz */
+               t_ces   = 6;
+               t_avds  = 5;
+               t_avdh  = 2;
+               t_ach   = 6;
+               t_aavdh = 6;
+               t_rdyo  = 11;
+               break;
+       default:
+               min_gpmc_clk_period = 18; /* 54 MHz */
+               t_ces   = 7;
+               t_avds  = 7;
+               t_avdh  = 7;
+               t_ach   = 9;
+               t_aavdh = 7;
+               t_rdyo  = 15;
+               sync_write = 0;
+               break;
+       }
+
+       tick_ns = gpmc_ticks_to_ns(1);
+       div = gpmc_cs_calc_divider(cs, min_gpmc_clk_period);
+       gpmc_clk_ns = gpmc_ticks_to_ns(div);
+       if (gpmc_clk_ns < 15) /* >66Mhz */
+               hf = 1;
+       if (hf)
+               latency = 6;
+       else if (gpmc_clk_ns >= 25) /* 40 MHz*/
+               latency = 3;
+       else
+               latency = 4;
+
+       if (first_time)
+               set_onenand_cfg(onenand_base, latency,
+                                       sync_read, sync_write, hf);
+
+       if (div == 1) {
+               reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2);
+               reg |= (1 << 7);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, reg);
+               reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG3);
+               reg |= (1 << 7);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, reg);
+               reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG4);
+               reg |= (1 << 7);
+               reg |= (1 << 23);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, reg);
+       } else {
+               reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2);
+               reg &= ~(1 << 7);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, reg);
+               reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG3);
+               reg &= ~(1 << 7);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, reg);
+               reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG4);
+               reg &= ~(1 << 7);
+               reg &= ~(1 << 23);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, reg);
+       }
+
+       /* Set synchronous read timings */
+       memset(&t, 0, sizeof(t));
+       t.sync_clk = min_gpmc_clk_period;
+       t.cs_on = 0;
+       t.adv_on = 0;
+       fclk_offset_ns = gpmc_round_ns_to_ticks(max_t(int, t_ces, t_avds));
+       fclk_offset = gpmc_ns_to_ticks(fclk_offset_ns);
+       t.page_burst_access = gpmc_clk_ns;
+
+       /* Read */
+       t.adv_rd_off = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_avdh));
+       t.oe_on = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_ach));
+       t.access = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div);
+       t.oe_off = t.access + gpmc_round_ns_to_ticks(1);
+       t.cs_rd_off = t.oe_off;
+       ticks_cez = ((gpmc_ns_to_ticks(t_cez) + div - 1) / div) * div;
+       t.rd_cycle = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div +
+                    ticks_cez);
+
+       /* Write */
+       if (sync_write) {
+               t.adv_wr_off = t.adv_rd_off;
+               t.we_on  = 0;
+               t.we_off = t.cs_rd_off;
+               t.cs_wr_off = t.cs_rd_off;
+               t.wr_cycle  = t.rd_cycle;
+               if (cpu_is_omap34xx()) {
+                       t.wr_data_mux_bus = gpmc_ticks_to_ns(fclk_offset +
+                                       gpmc_ns_to_ticks(min_gpmc_clk_period +
+                                       t_rdyo));
+                       t.wr_access = t.access;
+               }
+       } else {
+               t.adv_wr_off = gpmc_round_ns_to_ticks(max_t(int,
+                                                       t_avdp, t_cer));
+               t.we_on  = t.adv_wr_off + gpmc_round_ns_to_ticks(t_aavdh);
+               t.we_off = t.we_on + gpmc_round_ns_to_ticks(t_wpl);
+               t.cs_wr_off = t.we_off + gpmc_round_ns_to_ticks(t_wph);
+               t.wr_cycle  = t.cs_wr_off + gpmc_round_ns_to_ticks(t_cez);
+               if (cpu_is_omap34xx()) {
+                       t.wr_data_mux_bus = t.we_on;
+                       t.wr_access = t.we_on + gpmc_round_ns_to_ticks(t_ds);
+               }
+       }
+
+       /* Configure GPMC for synchronous read */
+       gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1,
+                         GPMC_CONFIG1_WRAPBURST_SUPP |
+                         GPMC_CONFIG1_READMULTIPLE_SUPP |
+                         (sync_read ? GPMC_CONFIG1_READTYPE_SYNC : 0) |
+                         (sync_write ? GPMC_CONFIG1_WRITEMULTIPLE_SUPP : 0) |
+                         (sync_write ? GPMC_CONFIG1_WRITETYPE_SYNC : 0) |
+                         GPMC_CONFIG1_CLKACTIVATIONTIME(fclk_offset) |
+                         GPMC_CONFIG1_PAGE_LEN(2) |
+                         (cpu_is_omap34xx() ? 0 :
+                               (GPMC_CONFIG1_WAIT_READ_MON |
+                                GPMC_CONFIG1_WAIT_PIN_SEL(0))) |
+                         GPMC_CONFIG1_DEVICESIZE_16 |
+                         GPMC_CONFIG1_DEVICETYPE_NOR |
+                         GPMC_CONFIG1_MUXADDDATA);
+
+       err = gpmc_cs_set_timings(cs, &t);
+       if (err)
+               return err;
+
+       set_onenand_cfg(onenand_base, latency, sync_read, sync_write, hf);
+
+       return 0;
+}
+
+static int gpmc_onenand_setup(void __iomem *onenand_base, int freq)
+{
+       struct device *dev = &gpmc_onenand_device.dev;
+
+       /* Set sync timings in GPMC */
+       if (omap2_onenand_set_sync_mode(gpmc_onenand_data, onenand_base,
+                       freq) < 0) {
+               dev_err(dev, "Unable to set synchronous mode\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+void __init gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
+{
+       gpmc_onenand_data = _onenand_data;
+       gpmc_onenand_data->onenand_setup = gpmc_onenand_setup;
+       gpmc_onenand_device.dev.platform_data = gpmc_onenand_data;
+
+       if (cpu_is_omap24xx() &&
+                       (gpmc_onenand_data->flags & ONENAND_SYNC_READWRITE)) {
+               printk(KERN_ERR "Onenand using only SYNC_READ on 24xx\n");
+               gpmc_onenand_data->flags &= ~ONENAND_SYNC_READWRITE;
+               gpmc_onenand_data->flags |= ONENAND_SYNC_READ;
+       }
+
+       if (platform_device_register(&gpmc_onenand_device) < 0) {
+               printk(KERN_ERR "Unable to register OneNAND device\n");
+               return;
+       }
+}
diff --git a/arch/arm/mach-omap2/gpmc-smc91x.c b/arch/arm/mach-omap2/gpmc-smc91x.c
new file mode 100644 (file)
index 0000000..df99d31
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * linux/arch/arm/mach-omap2/gpmc-smc91x.c
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Contact:    Tony Lindgren
+ *
+ * This 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/gpio.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/smc91x.h>
+
+#include <mach/board.h>
+#include <mach/gpmc.h>
+#include <mach/gpmc-smc91x.h>
+
+static struct omap_smc91x_platform_data *gpmc_cfg;
+
+static struct resource gpmc_smc91x_resources[] = {
+       [0] = {
+               .flags          = IORESOURCE_MEM,
+       },
+       [1] = {
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct smc91x_platdata gpmc_smc91x_info = {
+       .flags  = SMC91X_USE_16BIT | SMC91X_NOWAIT | SMC91X_IO_SHIFT_0,
+};
+
+static struct platform_device gpmc_smc91x_device = {
+       .name           = "smc91x",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(gpmc_smc91x_resources),
+       .resource       = gpmc_smc91x_resources,
+       .dev            = {
+               .platform_data = &gpmc_smc91x_info,
+       },
+};
+
+/*
+ * Set the gpmc timings for smc91c96. The timings are taken
+ * from the data sheet available at:
+ * http://www.smsc.com/main/catalog/lan91c96.html
+ * REVISIT: Level shifters can add at least to the access latency.
+ */
+static int smc91c96_gpmc_retime(void)
+{
+       struct gpmc_timings t;
+       const int t3 = 10;      /* Figure 12.2 read and 12.4 write */
+       const int t4_r = 20;    /* Figure 12.2 read */
+       const int t4_w = 5;     /* Figure 12.4 write */
+       const int t5 = 25;      /* Figure 12.2 read */
+       const int t6 = 15;      /* Figure 12.2 read */
+       const int t7 = 5;       /* Figure 12.4 write */
+       const int t8 = 5;       /* Figure 12.4 write */
+       const int t20 = 185;    /* Figure 12.2 read and 12.4 write */
+       u32 l;
+
+       memset(&t, 0, sizeof(t));
+
+       /* Read timings */
+       t.cs_on = 0;
+       t.adv_on = t.cs_on;
+       t.oe_on = t.adv_on + t3;
+       t.access = t.oe_on + t5;
+       t.oe_off = t.access;
+       t.adv_rd_off = t.oe_off + max(t4_r, t6);
+       t.cs_rd_off = t.oe_off;
+       t.rd_cycle = t20 - t.oe_on;
+
+       /* Write timings */
+       t.we_on = t.adv_on + t3;
+
+       if (cpu_is_omap34xx() && (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)) {
+               t.wr_data_mux_bus = t.we_on;
+               t.we_off = t.wr_data_mux_bus + t7;
+       } else
+               t.we_off = t.we_on + t7;
+       if (cpu_is_omap34xx())
+               t.wr_access = t.we_off;
+       t.adv_wr_off = t.we_off + max(t4_w, t8);
+       t.cs_wr_off = t.we_off + t4_w;
+       t.wr_cycle = t20 - t.we_on;
+
+       l = GPMC_CONFIG1_DEVICESIZE_16;
+       if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)
+               l |= GPMC_CONFIG1_MUXADDDATA;
+       if (gpmc_cfg->flags & GPMC_READ_MON)
+               l |= GPMC_CONFIG1_WAIT_READ_MON;
+       if (gpmc_cfg->flags & GPMC_WRITE_MON)
+               l |= GPMC_CONFIG1_WAIT_WRITE_MON;
+       if (gpmc_cfg->wait_pin)
+               l |= GPMC_CONFIG1_WAIT_PIN_SEL(gpmc_cfg->wait_pin);
+       gpmc_cs_write_reg(gpmc_cfg->cs, GPMC_CS_CONFIG1, l);
+
+       /*
+        * FIXME: Calculate the address and data bus muxed timings.
+        * Note that at least adv_rd_off needs to be changed according
+        * to omap3430 TRM Figure 11-11. Are the sdp boards using the
+        * FPGA in between smc91x and omap as the timings are different
+        * from above?
+        */
+       if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)
+               return 0;
+
+       return gpmc_cs_set_timings(gpmc_cfg->cs, &t);
+}
+
+/*
+ * Initialize smc91x device connected to the GPMC. Note that we
+ * assume that pin multiplexing is done in the board-*.c file,
+ * or in the bootloader.
+ */
+void __init gpmc_smc91x_init(struct omap_smc91x_platform_data *board_data)
+{
+       unsigned long cs_mem_base;
+       int ret;
+
+       gpmc_cfg = board_data;
+
+       if (gpmc_cfg->flags & GPMC_TIMINGS_SMC91C96)
+               gpmc_cfg->retime = smc91c96_gpmc_retime;
+
+       if (gpmc_cs_request(gpmc_cfg->cs, SZ_16M, &cs_mem_base) < 0) {
+               printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
+               return;
+       }
+
+       gpmc_smc91x_resources[0].start = cs_mem_base + 0x300;
+       gpmc_smc91x_resources[0].end = cs_mem_base + 0x30f;
+       gpmc_smc91x_resources[1].flags |= (gpmc_cfg->flags & IRQF_TRIGGER_MASK);
+
+       if (gpmc_cfg->retime) {
+               ret = gpmc_cfg->retime();
+               if (ret != 0)
+                       goto free1;
+       }
+
+       if (gpio_request(gpmc_cfg->gpio_irq, "SMC91X irq") < 0)
+               goto free1;
+
+       gpio_direction_input(gpmc_cfg->gpio_irq);
+       gpmc_smc91x_resources[1].start = gpio_to_irq(gpmc_cfg->gpio_irq);
+
+       if (gpmc_cfg->gpio_pwrdwn) {
+               ret = gpio_request(gpmc_cfg->gpio_pwrdwn, "SMC91X powerdown");
+               if (ret)
+                       goto free2;
+               gpio_direction_output(gpmc_cfg->gpio_pwrdwn, 0);
+       }
+
+       if (gpmc_cfg->gpio_reset) {
+               ret = gpio_request(gpmc_cfg->gpio_reset, "SMC91X reset");
+               if (ret)
+                       goto free3;
+
+               gpio_direction_output(gpmc_cfg->gpio_reset, 0);
+               gpio_set_value(gpmc_cfg->gpio_reset, 1);
+               msleep(100);
+               gpio_set_value(gpmc_cfg->gpio_reset, 0);
+       }
+
+       if (platform_device_register(&gpmc_smc91x_device) < 0) {
+               printk(KERN_ERR "Unable to register smc91x device\n");
+               gpio_free(gpmc_cfg->gpio_reset);
+               goto free3;
+       }
+
+       return;
+
+free3:
+       if (gpmc_cfg->gpio_pwrdwn)
+               gpio_free(gpmc_cfg->gpio_pwrdwn);
+free2:
+       gpio_free(gpmc_cfg->gpio_irq);
+free1:
+       gpmc_cs_free(gpmc_cfg->cs);
+
+       printk(KERN_ERR "Could not initialize smc91x\n");
+}
index 2249049c1d5a3f4020528fa7a4350532fac34c13..f91934b2b092dc7ca199f853de520637baa32d08 100644 (file)
@@ -5,6 +5,9 @@
  *
  * Author: Juha Yrjola
  *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
@@ -424,6 +427,9 @@ void __init gpmc_init(void)
        } else if (cpu_is_omap34xx()) {
                ck = "gpmc_fck";
                l = OMAP34XX_GPMC_BASE;
+       } else if (cpu_is_omap44xx()) {
+               ck = "gpmc_fck";
+               l = OMAP44XX_GPMC_BASE;
        }
 
        gpmc_l3_clk = clk_get(NULL, ck);
index 34b5914e0f8b18d094d45a31e9ce166af215b410..458990e20c60db3a7f97d5b74ee33cee71496c78 100644 (file)
@@ -6,6 +6,9 @@
  * Copyright (C) 2005 Nokia Corporation
  * Written by Tony Lindgren <tony@atomide.com>
  *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
@@ -200,7 +203,10 @@ void __init omap2_check_revision(void)
                omap24xx_check_revision();
        else if (cpu_is_omap34xx())
                omap34xx_check_revision();
-       else
+       else if (cpu_is_omap44xx()) {
+               printk(KERN_INFO "FIXME: CPU revision = OMAP4430\n");
+               return;
+       } else
                pr_err("OMAP revision unknown, please fix!\n");
 
        /*
index 916fcd3a2328f470671da827fba0d05ee7d9cbfc..32afd944821625b4d49b9654573a9b72719c0430 100644 (file)
@@ -4,12 +4,14 @@
  * OMAP2 I/O mapping code
  *
  * Copyright (C) 2005 Nokia Corporation
- * Copyright (C) 2007 Texas Instruments
+ * Copyright (C) 2007-2009 Texas Instruments
  *
  * Author:
  *     Juha Yrjola <juha.yrjola@nokia.com>
  *     Syed Khasim <x0khasim@ti.com>
  *
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
@@ -30,6 +32,7 @@
 #include <mach/sdrc.h>
 #include <mach/gpmc.h>
 
+#ifndef CONFIG_ARCH_OMAP4      /* FIXME: Remove this once clkdev is ready */
 #include "clock.h"
 
 #include <mach/powerdomain.h>
@@ -38,7 +41,7 @@
 
 #include <mach/clockdomain.h>
 #include "clockdomains.h"
-
+#endif
 /*
  * The machine specific code may provide the extra mapping besides the
  * default mapping provided here.
@@ -166,6 +169,46 @@ static struct map_desc omap34xx_io_desc[] __initdata = {
        },
 };
 #endif
+#ifdef CONFIG_ARCH_OMAP4
+static struct map_desc omap44xx_io_desc[] __initdata = {
+       {
+               .virtual        = L3_44XX_VIRT,
+               .pfn            = __phys_to_pfn(L3_44XX_PHYS),
+               .length         = L3_44XX_SIZE,
+               .type           = MT_DEVICE,
+       },
+       {
+               .virtual        = L4_44XX_VIRT,
+               .pfn            = __phys_to_pfn(L4_44XX_PHYS),
+               .length         = L4_44XX_SIZE,
+               .type           = MT_DEVICE,
+       },
+       {
+               .virtual        = L4_WK_44XX_VIRT,
+               .pfn            = __phys_to_pfn(L4_WK_44XX_PHYS),
+               .length         = L4_WK_44XX_SIZE,
+               .type           = MT_DEVICE,
+       },
+       {
+               .virtual        = OMAP44XX_GPMC_VIRT,
+               .pfn            = __phys_to_pfn(OMAP44XX_GPMC_PHYS),
+               .length         = OMAP44XX_GPMC_SIZE,
+               .type           = MT_DEVICE,
+       },
+       {
+               .virtual        = L4_PER_44XX_VIRT,
+               .pfn            = __phys_to_pfn(L4_PER_44XX_PHYS),
+               .length         = L4_PER_44XX_SIZE,
+               .type           = MT_DEVICE,
+       },
+       {
+               .virtual        = L4_EMU_44XX_VIRT,
+               .pfn            = __phys_to_pfn(L4_EMU_44XX_PHYS),
+               .length         = L4_EMU_44XX_SIZE,
+               .type           = MT_DEVICE,
+       },
+};
+#endif
 
 void __init omap2_map_common_io(void)
 {
@@ -183,6 +226,9 @@ void __init omap2_map_common_io(void)
        iotable_init(omap34xx_io_desc, ARRAY_SIZE(omap34xx_io_desc));
 #endif
 
+#if defined(CONFIG_ARCH_OMAP4)
+       iotable_init(omap44xx_io_desc, ARRAY_SIZE(omap44xx_io_desc));
+#endif
        /* Normally devicemaps_init() would flush caches and tlb after
         * mdesc->map_io(), but we must also do it here because of the CPU
         * revision check below.
@@ -198,9 +244,11 @@ void __init omap2_map_common_io(void)
 void __init omap2_init_common_hw(struct omap_sdrc_params *sp)
 {
        omap2_mux_init();
+#ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once the clkdev is ready */
        pwrdm_init(powerdomains_omap);
        clkdm_init(clockdomains_omap, clkdm_pwrdm_autodeps);
        omap2_clk_init();
        omap2_sdrc_init(sp);
+#endif
        gpmc_init();
 }
diff --git a/arch/arm/mach-omap2/iommu2.c b/arch/arm/mach-omap2/iommu2.c
new file mode 100644 (file)
index 0000000..015f22a
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * omap iommu: omap2/3 architecture specific functions
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>,
+ *             Paul Mundt and Toshihiro Kobayashi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/stringify.h>
+
+#include <mach/iommu.h>
+
+/*
+ * omap2 architecture specific register bit definitions
+ */
+#define IOMMU_ARCH_VERSION     0x00000011
+
+/* SYSCONF */
+#define MMU_SYS_IDLE_SHIFT     3
+#define MMU_SYS_IDLE_FORCE     (0 << MMU_SYS_IDLE_SHIFT)
+#define MMU_SYS_IDLE_NONE      (1 << MMU_SYS_IDLE_SHIFT)
+#define MMU_SYS_IDLE_SMART     (2 << MMU_SYS_IDLE_SHIFT)
+#define MMU_SYS_IDLE_MASK      (3 << MMU_SYS_IDLE_SHIFT)
+
+#define MMU_SYS_SOFTRESET      (1 << 1)
+#define MMU_SYS_AUTOIDLE       1
+
+/* SYSSTATUS */
+#define MMU_SYS_RESETDONE      1
+
+/* IRQSTATUS & IRQENABLE */
+#define MMU_IRQ_MULTIHITFAULT  (1 << 4)
+#define MMU_IRQ_TABLEWALKFAULT (1 << 3)
+#define MMU_IRQ_EMUMISS                (1 << 2)
+#define MMU_IRQ_TRANSLATIONFAULT       (1 << 1)
+#define MMU_IRQ_TLBMISS                (1 << 0)
+#define MMU_IRQ_MASK   \
+       (MMU_IRQ_MULTIHITFAULT | MMU_IRQ_TABLEWALKFAULT | MMU_IRQ_EMUMISS | \
+        MMU_IRQ_TRANSLATIONFAULT)
+
+/* MMU_CNTL */
+#define MMU_CNTL_SHIFT         1
+#define MMU_CNTL_MASK          (7 << MMU_CNTL_SHIFT)
+#define MMU_CNTL_EML_TLB       (1 << 3)
+#define MMU_CNTL_TWL_EN                (1 << 2)
+#define MMU_CNTL_MMU_EN                (1 << 1)
+
+#define get_cam_va_mask(pgsz)                          \
+       (((pgsz) == MMU_CAM_PGSZ_16M) ? 0xff000000 :    \
+        ((pgsz) == MMU_CAM_PGSZ_1M)  ? 0xfff00000 :    \
+        ((pgsz) == MMU_CAM_PGSZ_64K) ? 0xffff0000 :    \
+        ((pgsz) == MMU_CAM_PGSZ_4K)  ? 0xfffff000 : 0)
+
+static int omap2_iommu_enable(struct iommu *obj)
+{
+       u32 l, pa;
+       unsigned long timeout;
+
+       if (!obj->iopgd || !IS_ALIGNED((u32)obj->iopgd,  SZ_16K))
+               return -EINVAL;
+
+       pa = virt_to_phys(obj->iopgd);
+       if (!IS_ALIGNED(pa, SZ_16K))
+               return -EINVAL;
+
+       iommu_write_reg(obj, MMU_SYS_SOFTRESET, MMU_SYSCONFIG);
+
+       timeout = jiffies + msecs_to_jiffies(20);
+       do {
+               l = iommu_read_reg(obj, MMU_SYSSTATUS);
+               if (l & MMU_SYS_RESETDONE)
+                       break;
+       } while (time_after(jiffies, timeout));
+
+       if (!(l & MMU_SYS_RESETDONE)) {
+               dev_err(obj->dev, "can't take mmu out of reset\n");
+               return -ENODEV;
+       }
+
+       l = iommu_read_reg(obj, MMU_REVISION);
+       dev_info(obj->dev, "%s: version %d.%d\n", obj->name,
+                (l >> 4) & 0xf, l & 0xf);
+
+       l = iommu_read_reg(obj, MMU_SYSCONFIG);
+       l &= ~MMU_SYS_IDLE_MASK;
+       l |= (MMU_SYS_IDLE_SMART | MMU_SYS_AUTOIDLE);
+       iommu_write_reg(obj, l, MMU_SYSCONFIG);
+
+       iommu_write_reg(obj, MMU_IRQ_MASK, MMU_IRQENABLE);
+       iommu_write_reg(obj, pa, MMU_TTB);
+
+       l = iommu_read_reg(obj, MMU_CNTL);
+       l &= ~MMU_CNTL_MASK;
+       l |= (MMU_CNTL_MMU_EN | MMU_CNTL_TWL_EN);
+       iommu_write_reg(obj, l, MMU_CNTL);
+
+       return 0;
+}
+
+static void omap2_iommu_disable(struct iommu *obj)
+{
+       u32 l = iommu_read_reg(obj, MMU_CNTL);
+
+       l &= ~MMU_CNTL_MASK;
+       iommu_write_reg(obj, l, MMU_CNTL);
+       iommu_write_reg(obj, MMU_SYS_IDLE_FORCE, MMU_SYSCONFIG);
+
+       dev_dbg(obj->dev, "%s is shutting down\n", obj->name);
+}
+
+static u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra)
+{
+       int i;
+       u32 stat, da;
+       const char *err_msg[] = {
+               "tlb miss",
+               "translation fault",
+               "emulation miss",
+               "table walk fault",
+               "multi hit fault",
+       };
+
+       stat = iommu_read_reg(obj, MMU_IRQSTATUS);
+       stat &= MMU_IRQ_MASK;
+       if (!stat)
+               return 0;
+
+       da = iommu_read_reg(obj, MMU_FAULT_AD);
+       *ra = da;
+
+       dev_err(obj->dev, "%s:\tda:%08x ", __func__, da);
+
+       for (i = 0; i < ARRAY_SIZE(err_msg); i++) {
+               if (stat & (1 << i))
+                       printk("%s ", err_msg[i]);
+       }
+       printk("\n");
+
+       iommu_write_reg(obj, stat, MMU_IRQSTATUS);
+       return stat;
+}
+
+static void omap2_tlb_read_cr(struct iommu *obj, struct cr_regs *cr)
+{
+       cr->cam = iommu_read_reg(obj, MMU_READ_CAM);
+       cr->ram = iommu_read_reg(obj, MMU_READ_RAM);
+}
+
+static void omap2_tlb_load_cr(struct iommu *obj, struct cr_regs *cr)
+{
+       iommu_write_reg(obj, cr->cam | MMU_CAM_V, MMU_CAM);
+       iommu_write_reg(obj, cr->ram, MMU_RAM);
+}
+
+static u32 omap2_cr_to_virt(struct cr_regs *cr)
+{
+       u32 page_size = cr->cam & MMU_CAM_PGSZ_MASK;
+       u32 mask = get_cam_va_mask(cr->cam & page_size);
+
+       return cr->cam & mask;
+}
+
+static struct cr_regs *omap2_alloc_cr(struct iommu *obj, struct iotlb_entry *e)
+{
+       struct cr_regs *cr;
+
+       if (e->da & ~(get_cam_va_mask(e->pgsz))) {
+               dev_err(obj->dev, "%s:\twrong alignment: %08x\n", __func__,
+                       e->da);
+               return ERR_PTR(-EINVAL);
+       }
+
+       cr = kmalloc(sizeof(*cr), GFP_KERNEL);
+       if (!cr)
+               return ERR_PTR(-ENOMEM);
+
+       cr->cam = (e->da & MMU_CAM_VATAG_MASK) | e->prsvd | e->pgsz;
+       cr->ram = e->pa | e->endian | e->elsz | e->mixed;
+
+       return cr;
+}
+
+static inline int omap2_cr_valid(struct cr_regs *cr)
+{
+       return cr->cam & MMU_CAM_V;
+}
+
+static u32 omap2_get_pte_attr(struct iotlb_entry *e)
+{
+       u32 attr;
+
+       attr = e->mixed << 5;
+       attr |= e->endian;
+       attr |= e->elsz >> 3;
+       attr <<= ((e->pgsz & MMU_CAM_PGSZ_4K) ? 0 : 6);
+
+       return attr;
+}
+
+static ssize_t omap2_dump_cr(struct iommu *obj, struct cr_regs *cr, char *buf)
+{
+       char *p = buf;
+
+       /* FIXME: Need more detail analysis of cam/ram */
+       p += sprintf(p, "%08x %08x\n", cr->cam, cr->ram);
+
+       return p - buf;
+}
+
+#define pr_reg(name)                                                   \
+       p += sprintf(p, "%20s: %08x\n",                                 \
+                    __stringify(name), iommu_read_reg(obj, MMU_##name));
+
+static ssize_t omap2_iommu_dump_ctx(struct iommu *obj, char *buf)
+{
+       char *p = buf;
+
+       pr_reg(REVISION);
+       pr_reg(SYSCONFIG);
+       pr_reg(SYSSTATUS);
+       pr_reg(IRQSTATUS);
+       pr_reg(IRQENABLE);
+       pr_reg(WALKING_ST);
+       pr_reg(CNTL);
+       pr_reg(FAULT_AD);
+       pr_reg(TTB);
+       pr_reg(LOCK);
+       pr_reg(LD_TLB);
+       pr_reg(CAM);
+       pr_reg(RAM);
+       pr_reg(GFLUSH);
+       pr_reg(FLUSH_ENTRY);
+       pr_reg(READ_CAM);
+       pr_reg(READ_RAM);
+       pr_reg(EMU_FAULT_AD);
+
+       return p - buf;
+}
+
+static void omap2_iommu_save_ctx(struct iommu *obj)
+{
+       int i;
+       u32 *p = obj->ctx;
+
+       for (i = 0; i < (MMU_REG_SIZE / sizeof(u32)); i++) {
+               p[i] = iommu_read_reg(obj, i * sizeof(u32));
+               dev_dbg(obj->dev, "%s\t[%02d] %08x\n", __func__, i, p[i]);
+       }
+
+       BUG_ON(p[0] != IOMMU_ARCH_VERSION);
+}
+
+static void omap2_iommu_restore_ctx(struct iommu *obj)
+{
+       int i;
+       u32 *p = obj->ctx;
+
+       for (i = 0; i < (MMU_REG_SIZE / sizeof(u32)); i++) {
+               iommu_write_reg(obj, p[i], i * sizeof(u32));
+               dev_dbg(obj->dev, "%s\t[%02d] %08x\n", __func__, i, p[i]);
+       }
+
+       BUG_ON(p[0] != IOMMU_ARCH_VERSION);
+}
+
+static void omap2_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e)
+{
+       e->da           = cr->cam & MMU_CAM_VATAG_MASK;
+       e->pa           = cr->ram & MMU_RAM_PADDR_MASK;
+       e->valid        = cr->cam & MMU_CAM_V;
+       e->pgsz         = cr->cam & MMU_CAM_PGSZ_MASK;
+       e->endian       = cr->ram & MMU_RAM_ENDIAN_MASK;
+       e->elsz         = cr->ram & MMU_RAM_ELSZ_MASK;
+       e->mixed        = cr->ram & MMU_RAM_MIXED;
+}
+
+static const struct iommu_functions omap2_iommu_ops = {
+       .version        = IOMMU_ARCH_VERSION,
+
+       .enable         = omap2_iommu_enable,
+       .disable        = omap2_iommu_disable,
+       .fault_isr      = omap2_iommu_fault_isr,
+
+       .tlb_read_cr    = omap2_tlb_read_cr,
+       .tlb_load_cr    = omap2_tlb_load_cr,
+
+       .cr_to_e        = omap2_cr_to_e,
+       .cr_to_virt     = omap2_cr_to_virt,
+       .alloc_cr       = omap2_alloc_cr,
+       .cr_valid       = omap2_cr_valid,
+       .dump_cr        = omap2_dump_cr,
+
+       .get_pte_attr   = omap2_get_pte_attr,
+
+       .save_ctx       = omap2_iommu_save_ctx,
+       .restore_ctx    = omap2_iommu_restore_ctx,
+       .dump_ctx       = omap2_iommu_dump_ctx,
+};
+
+static int __init omap2_iommu_init(void)
+{
+       return install_iommu_arch(&omap2_iommu_ops);
+}
+module_init(omap2_iommu_init);
+
+static void __exit omap2_iommu_exit(void)
+{
+       uninstall_iommu_arch(&omap2_iommu_ops);
+}
+module_exit(omap2_iommu_exit);
+
+MODULE_AUTHOR("Hiroshi DOYU, Paul Mundt and Toshihiro Kobayashi");
+MODULE_DESCRIPTION("omap iommu: omap2/3 architecture specific functions");
+MODULE_LICENSE("GPL v2");
index 998c5c45587ea31ac1c527aaff399c717907c3a4..b82863887f10ebe96a3d8db573d99d0c7ae6d9a3 100644 (file)
@@ -28,7 +28,6 @@
 #define INTC_MIR_CLEAR0                0x0088
 #define INTC_MIR_SET0          0x008c
 #define INTC_PENDING_IRQ0      0x0098
-
 /* Number of IRQ state bits in each MIR register */
 #define IRQ_BITS_PER_REG       32
 
@@ -134,7 +133,6 @@ static struct irq_chip omap_irq_chip = {
        .ack    = omap_mask_ack_irq,
        .mask   = omap_mask_irq,
        .unmask = omap_unmask_irq,
-       .disable = omap_mask_irq,
 };
 
 static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank)
@@ -157,6 +155,22 @@ static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank)
        intc_bank_write_reg(1 << 0, bank, INTC_SYSCONFIG);
 }
 
+int omap_irq_pending(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
+               struct omap_irq_bank *bank = irq_banks + i;
+               int irq;
+
+               for (irq = 0; irq < bank->nr_irqs; irq += 32)
+                       if (intc_bank_read_reg(bank, INTC_PENDING_IRQ0 +
+                                              ((irq >> 5) << 5)))
+                               return 1;
+       }
+       return 0;
+}
+
 void __init omap_init_irq(void)
 {
        unsigned long nr_of_irqs = 0;
index dc40b3e72206080164b1c1f5b17def1f4d211688..9756a878fd90263c5ddd4fcfd7a1d6dc60228c77 100644 (file)
@@ -16,8 +16,8 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
-#include <linux/i2c/twl4030.h>
-#include <linux/regulator/machine.h>
+#include <linux/mmc/host.h>
+#include <linux/regulator/consumer.h>
 
 #include <mach/hardware.h>
 #include <mach/control.h>
 
 #include "mmc-twl4030.h"
 
-#if defined(CONFIG_TWL4030_CORE) && \
-       (defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE))
 
-#define LDO_CLR                        0x00
-#define VSEL_S2_CLR            0x40
-
-#define VMMC1_DEV_GRP          0x27
-#define VMMC1_CLR              0x00
-#define VMMC1_315V             0x03
-#define VMMC1_300V             0x02
-#define VMMC1_285V             0x01
-#define VMMC1_185V             0x00
-#define VMMC1_DEDICATED                0x2A
-
-#define VMMC2_DEV_GRP          0x2B
-#define VMMC2_CLR              0x40
-#define VMMC2_315V             0x0c
-#define VMMC2_300V             0x0b
-#define VMMC2_285V             0x0a
-#define VMMC2_280V             0x09
-#define VMMC2_260V             0x08
-#define VMMC2_185V             0x06
-#define VMMC2_DEDICATED                0x2E
-
-#define VMMC_DEV_GRP_P1                0x20
+#if defined(CONFIG_REGULATOR) && \
+       (defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE))
 
 static u16 control_pbias_offset;
 static u16 control_devconf1_offset;
@@ -59,19 +37,16 @@ static u16 control_devconf1_offset;
 
 static struct twl_mmc_controller {
        struct omap_mmc_platform_data   *mmc;
-       u8              twl_vmmc_dev_grp;
-       u8              twl_mmc_dedicated;
-       char            name[HSMMC_NAME_LEN + 1];
-} hsmmc[OMAP34XX_NR_MMC] = {
-       {
-               .twl_vmmc_dev_grp               = VMMC1_DEV_GRP,
-               .twl_mmc_dedicated              = VMMC1_DEDICATED,
-       },
-       {
-               .twl_vmmc_dev_grp               = VMMC2_DEV_GRP,
-               .twl_mmc_dedicated              = VMMC2_DEDICATED,
-       },
-};
+       /* Vcc == configured supply
+        * Vcc_alt == optional
+        *   -  MMC1, supply for DAT4..DAT7
+        *   -  MMC2/MMC2, external level shifter voltage supply, for
+        *      chip (SDIO, eMMC, etc) or transceiver (MMC2 only)
+        */
+       struct regulator                *vcc;
+       struct regulator                *vcc_aux;
+       char                            name[HSMMC_NAME_LEN + 1];
+} hsmmc[OMAP34XX_NR_MMC];
 
 static int twl_mmc_card_detect(int irq)
 {
@@ -117,16 +92,60 @@ static int twl_mmc_late_init(struct device *dev)
        int ret = 0;
        int i;
 
-       ret = gpio_request(mmc->slots[0].switch_pin, "mmc_cd");
-       if (ret)
-               goto done;
-       ret = gpio_direction_input(mmc->slots[0].switch_pin);
-       if (ret)
-               goto err;
+       /* MMC/SD/SDIO doesn't require a card detect switch */
+       if (gpio_is_valid(mmc->slots[0].switch_pin)) {
+               ret = gpio_request(mmc->slots[0].switch_pin, "mmc_cd");
+               if (ret)
+                       goto done;
+               ret = gpio_direction_input(mmc->slots[0].switch_pin);
+               if (ret)
+                       goto err;
+       }
 
+       /* require at least main regulator */
        for (i = 0; i < ARRAY_SIZE(hsmmc); i++) {
                if (hsmmc[i].name == mmc->slots[0].name) {
+                       struct regulator *reg;
+
                        hsmmc[i].mmc = mmc;
+
+                       reg = regulator_get(dev, "vmmc");
+                       if (IS_ERR(reg)) {
+                               dev_dbg(dev, "vmmc regulator missing\n");
+                               /* HACK: until fixed.c regulator is usable,
+                                * we don't require a main regulator
+                                * for MMC2 or MMC3
+                                */
+                               if (i != 0)
+                                       break;
+                               ret = PTR_ERR(reg);
+                               goto err;
+                       }
+                       hsmmc[i].vcc = reg;
+                       mmc->slots[0].ocr_mask = mmc_regulator_get_ocrmask(reg);
+
+                       /* allow an aux regulator */
+                       reg = regulator_get(dev, "vmmc_aux");
+                       hsmmc[i].vcc_aux = IS_ERR(reg) ? NULL : reg;
+
+                       /* UGLY HACK:  workaround regulator framework bugs.
+                        * When the bootloader leaves a supply active, it's
+                        * initialized with zero usecount ... and we can't
+                        * disable it without first enabling it.  Until the
+                        * framework is fixed, we need a workaround like this
+                        * (which is safe for MMC, but not in general).
+                        */
+                       if (regulator_is_enabled(hsmmc[i].vcc) > 0) {
+                               regulator_enable(hsmmc[i].vcc);
+                               regulator_disable(hsmmc[i].vcc);
+                       }
+                       if (hsmmc[i].vcc_aux) {
+                               if (regulator_is_enabled(reg) > 0) {
+                                       regulator_enable(reg);
+                                       regulator_disable(reg);
+                               }
+                       }
+
                        break;
                }
        }
@@ -173,96 +192,6 @@ static int twl_mmc_resume(struct device *dev, int slot)
 #define twl_mmc_resume NULL
 #endif
 
-/*
- * Sets the MMC voltage in twl4030
- */
-
-#define MMC1_OCR       (MMC_VDD_165_195 \
-               |MMC_VDD_28_29|MMC_VDD_29_30|MMC_VDD_30_31|MMC_VDD_31_32)
-#define MMC2_OCR       (MMC_VDD_165_195 \
-               |MMC_VDD_25_26|MMC_VDD_26_27|MMC_VDD_27_28 \
-               |MMC_VDD_28_29|MMC_VDD_29_30|MMC_VDD_30_31|MMC_VDD_31_32)
-
-static int twl_mmc_set_voltage(struct twl_mmc_controller *c, int vdd)
-{
-       int ret;
-       u8 vmmc = 0, dev_grp_val;
-
-       if (!vdd)
-               goto doit;
-
-       if (c->twl_vmmc_dev_grp == VMMC1_DEV_GRP) {
-               /* VMMC1:  max 220 mA.  And for 8-bit mode,
-                * VSIM:  max 50 mA
-                */
-               switch (1 << vdd) {
-               case MMC_VDD_165_195:
-                       vmmc = VMMC1_185V;
-                       /* and VSIM_180V */
-                       break;
-               case MMC_VDD_28_29:
-                       vmmc = VMMC1_285V;
-                       /* and VSIM_280V */
-                       break;
-               case MMC_VDD_29_30:
-               case MMC_VDD_30_31:
-                       vmmc = VMMC1_300V;
-                       /* and VSIM_300V */
-                       break;
-               case MMC_VDD_31_32:
-                       vmmc = VMMC1_315V;
-                       /* error if VSIM needed */
-                       break;
-               default:
-                       return -EINVAL;
-               }
-       } else if (c->twl_vmmc_dev_grp == VMMC2_DEV_GRP) {
-               /* VMMC2:  max 100 mA */
-               switch (1 << vdd) {
-               case MMC_VDD_165_195:
-                       vmmc = VMMC2_185V;
-                       break;
-               case MMC_VDD_25_26:
-               case MMC_VDD_26_27:
-                       vmmc = VMMC2_260V;
-                       break;
-               case MMC_VDD_27_28:
-                       vmmc = VMMC2_280V;
-                       break;
-               case MMC_VDD_28_29:
-                       vmmc = VMMC2_285V;
-                       break;
-               case MMC_VDD_29_30:
-               case MMC_VDD_30_31:
-                       vmmc = VMMC2_300V;
-                       break;
-               case MMC_VDD_31_32:
-                       vmmc = VMMC2_315V;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-       } else {
-               return -EINVAL;
-       }
-
-doit:
-       if (vdd)
-               dev_grp_val = VMMC_DEV_GRP_P1;  /* Power up */
-       else
-               dev_grp_val = LDO_CLR;          /* Power down */
-
-       ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
-                                       dev_grp_val, c->twl_vmmc_dev_grp);
-       if (ret || !vdd)
-               return ret;
-
-       ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
-                                       vmmc, c->twl_mmc_dedicated);
-
-       return ret;
-}
-
 static int twl_mmc1_set_power(struct device *dev, int slot, int power_on,
                                int vdd)
 {
@@ -273,11 +202,13 @@ static int twl_mmc1_set_power(struct device *dev, int slot, int power_on,
 
        /*
         * Assume we power both OMAP VMMC1 (for CMD, CLK, DAT0..3) and the
-        * card using the same TWL VMMC1 supply (hsmmc[0]); OMAP has both
+        * card with Vcc regulator (from twl4030 or whatever).  OMAP has both
         * 1.8V and 3.0V modes, controlled by the PBIAS register.
         *
         * In 8-bit modes, OMAP VMMC1A (for DAT4..7) needs a supply, which
         * is most naturally TWL VSIM; those pins also use PBIAS.
+        *
+        * FIXME handle VMMC1A as needed ...
         */
        if (power_on) {
                if (cpu_is_omap2430()) {
@@ -300,7 +231,7 @@ static int twl_mmc1_set_power(struct device *dev, int slot, int power_on,
                reg &= ~OMAP2_PBIASLITEPWRDNZ0;
                omap_ctrl_writel(reg, control_pbias_offset);
 
-               ret = twl_mmc_set_voltage(c, vdd);
+               ret = mmc_regulator_set_ocr(c->vcc, vdd);
 
                /* 100ms delay required for PBIAS configuration */
                msleep(100);
@@ -316,7 +247,7 @@ static int twl_mmc1_set_power(struct device *dev, int slot, int power_on,
                reg &= ~OMAP2_PBIASLITEPWRDNZ0;
                omap_ctrl_writel(reg, control_pbias_offset);
 
-               ret = twl_mmc_set_voltage(c, 0);
+               ret = mmc_regulator_set_ocr(c->vcc, 0);
 
                /* 100ms delay required for PBIAS configuration */
                msleep(100);
@@ -329,19 +260,33 @@ static int twl_mmc1_set_power(struct device *dev, int slot, int power_on,
        return ret;
 }
 
-static int twl_mmc2_set_power(struct device *dev, int slot, int power_on, int vdd)
+static int twl_mmc23_set_power(struct device *dev, int slot, int power_on, int vdd)
 {
-       int ret;
+       int ret = 0;
        struct twl_mmc_controller *c = &hsmmc[1];
        struct omap_mmc_platform_data *mmc = dev->platform_data;
 
+       /* If we don't see a Vcc regulator, assume it's a fixed
+        * voltage always-on regulator.
+        */
+       if (!c->vcc)
+               return 0;
+
        /*
-        * Assume TWL VMMC2 (hsmmc[1]) is used only to power the card ... OMAP
+        * Assume Vcc regulator is used only to power the card ... OMAP
         * VDDS is used to power the pins, optionally with a transceiver to
         * support cards using voltages other than VDDS (1.8V nominal).  When a
         * transceiver is used, DAT3..7 are muxed as transceiver control pins.
+        *
+        * In some cases this regulator won't support enable/disable;
+        * e.g. it's a fixed rail for a WLAN chip.
+        *
+        * In other cases vcc_aux switches interface power.  Example, for
+        * eMMC cards it represents VccQ.  Sometimes transceivers or SDIO
+        * chips/cards need an interface voltage rail too.
         */
        if (power_on) {
+               /* only MMC2 supports a CLKIN */
                if (mmc->slots[0].internal_clock) {
                        u32 reg;
 
@@ -349,24 +294,23 @@ static int twl_mmc2_set_power(struct device *dev, int slot, int power_on, int vd
                        reg |= OMAP2_MMCSDIO2ADPCLKISEL;
                        omap_ctrl_writel(reg, control_devconf1_offset);
                }
-               ret = twl_mmc_set_voltage(c, vdd);
+               ret = mmc_regulator_set_ocr(c->vcc, vdd);
+               /* enable interface voltage rail, if needed */
+               if (ret == 0 && c->vcc_aux) {
+                       ret = regulator_enable(c->vcc_aux);
+                       if (ret < 0)
+                               ret = mmc_regulator_set_ocr(c->vcc, 0);
+               }
        } else {
-               ret = twl_mmc_set_voltage(c, 0);
+               if (c->vcc_aux && (ret = regulator_is_enabled(c->vcc_aux)) > 0)
+                       ret = regulator_disable(c->vcc_aux);
+               if (ret == 0)
+                       ret = mmc_regulator_set_ocr(c->vcc, 0);
        }
 
        return ret;
 }
 
-static int twl_mmc3_set_power(struct device *dev, int slot, int power_on,
-               int vdd)
-{
-       /*
-        * Assume MMC3 has self-powered device connected, for example on-board
-        * chip with external power source.
-        */
-       return 0;
-}
-
 static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC] __initdata;
 
 void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers)
@@ -412,10 +356,10 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers)
                mmc->slots[0].wires = c->wires;
                mmc->slots[0].internal_clock = !c->ext_clock;
                mmc->dma_mask = 0xffffffff;
+               mmc->init = twl_mmc_late_init;
 
-               /* note: twl4030 card detect GPIOs normally switch VMMCx ... */
+               /* note: twl4030 card detect GPIOs can disable VMMCx ... */
                if (gpio_is_valid(c->gpio_cd)) {
-                       mmc->init = twl_mmc_late_init;
                        mmc->cleanup = twl_mmc_cleanup;
                        mmc->suspend = twl_mmc_suspend;
                        mmc->resume = twl_mmc_resume;
@@ -439,26 +383,28 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers)
                } else
                        mmc->slots[0].gpio_wp = -EINVAL;
 
-               /* NOTE:  we assume OMAP's MMC1 and MMC2 use
-                * the TWL4030's VMMC1 and VMMC2, respectively;
-                * and that MMC3 device has it's own power source.
+               /* NOTE:  MMC slots should have a Vcc regulator set up.
+                * This may be from a TWL4030-family chip, another
+                * controllable regulator, or a fixed supply.
+                *
+                * temporary HACK: ocr_mask instead of fixed supply
                 */
+               mmc->slots[0].ocr_mask = c->ocr_mask;
 
                switch (c->mmc) {
                case 1:
+                       /* on-chip level shifting via PBIAS0/PBIAS1 */
                        mmc->slots[0].set_power = twl_mmc1_set_power;
-                       mmc->slots[0].ocr_mask = MMC1_OCR;
                        break;
                case 2:
-                       mmc->slots[0].set_power = twl_mmc2_set_power;
-                       if (c->transceiver)
-                               mmc->slots[0].ocr_mask = MMC2_OCR;
-                       else
-                               mmc->slots[0].ocr_mask = MMC_VDD_165_195;
-                       break;
+                       if (c->ext_clock)
+                               c->transceiver = 1;
+                       if (c->transceiver && c->wires > 4)
+                               c->wires = 4;
+                       /* FALLTHROUGH */
                case 3:
-                       mmc->slots[0].set_power = twl_mmc3_set_power;
-                       mmc->slots[0].ocr_mask = MMC_VDD_165_195;
+                       /* off-chip level shifting, or none */
+                       mmc->slots[0].set_power = twl_mmc23_set_power;
                        break;
                default:
                        pr_err("MMC%d configuration not supported!\n", c->mmc);
index ea59e8624290a1d8c1fb5b2f002a69beebd0cd2b..3807c45c9a6ca4d8dc0a4534da1276af8a069ce3 100644 (file)
@@ -16,9 +16,10 @@ struct twl4030_hsmmc_info {
        int     gpio_wp;        /* or -EINVAL */
        char    *name;          /* or NULL for default */
        struct device *dev;     /* returned: pointer to mmc adapter */
+       int     ocr_mask;       /* temporary HACK */
 };
 
-#if    defined(CONFIG_TWL4030_CORE) && \
+#if defined(CONFIG_REGULATOR) && \
        (defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \
         defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE))
 
diff --git a/arch/arm/mach-omap2/omap-headsmp.S b/arch/arm/mach-omap2/omap-headsmp.S
new file mode 100644 (file)
index 0000000..4afadba
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Secondary CPU startup routine source file.
+ *
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Author:
+ *      Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * Interface functions needed for the SMP. This file is based on arm
+ * realview smp platform.
+ * Copyright (c) 2003 ARM Limited.
+ *
+ * This program is free software,you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+/* Physical address needed since MMU not enabled yet on secondary core */
+#define OMAP4_AUX_CORE_BOOT1_PA                        0x48281804
+
+       __INIT
+
+/*
+ * OMAP4 specific entry point for secondary CPU to jump from ROM
+ * code.  This routine also provides a holding flag into which
+ * secondary core is held until we're ready for it to initialise.
+ * The primary core will update the this flag using a hardware
+ * register AuxCoreBoot1.
+ */
+ENTRY(omap_secondary_startup)
+       mrc     p15, 0, r0, c0, c0, 5
+       and     r0, r0, #0x0f
+hold:  ldr     r1, =OMAP4_AUX_CORE_BOOT1_PA    @ read from AuxCoreBoot1
+       ldr     r2, [r1]
+       cmp     r2, r0
+       bne     hold
+
+       /*
+        * we've been released from the cpu_release,secondary_stack
+        * should now contain the SVC stack for this core
+        */
+       b       secondary_startup
+
diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c
new file mode 100644 (file)
index 0000000..8fe8d23
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * OMAP4 SMP source file. It contains platform specific fucntions
+ * needed for the linux smp kernel.
+ *
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Author:
+ *      Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * Platform file needed for the OMAP4 SMP. This file is based on arm
+ * realview smp platform.
+ * * Copyright (c) 2002 ARM Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/jiffies.h>
+#include <linux/smp.h>
+#include <linux/io.h>
+
+#include <asm/localtimer.h>
+#include <asm/smp_scu.h>
+#include <mach/hardware.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)
+
+/* SCU base address */
+static void __iomem *scu_base = OMAP44XX_VA_SCU_BASE;
+
+/*
+ * Use SCU config register to count number of cores
+ */
+static inline unsigned int get_core_count(void)
+{
+       if (scu_base)
+               return scu_get_core_count(scu_base);
+       return 1;
+}
+
+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(OMAP44XX_GIC_CPU_BASE));
+
+       /*
+        * 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);
+
+       /*
+        * Update the AuxCoreBoot1 with boot state for secondary core.
+        * omap_secondary_startup() routine will hold the secondary core till
+        * 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);
+       smp_wmb();
+
+       timeout = jiffies + (1 * HZ);
+       while (time_before(jiffies, timeout))
+               ;
+
+       /*
+        * Now the secondary core is starting up let it run its
+        * calibrations, then wait for it to finish
+        */
+       spin_unlock(&boot_lock);
+
+       return 0;
+}
+
+static void __init wakeup_secondary(void)
+{
+       /*
+        * Write the address of secondary startup routine into the
+        * AuxCoreBoot0 where ROM code will jump and start executing
+        * on secondary core once out of WFE
+        * A barrier is added to ensure that write buffer is drained
+        */
+       __raw_writel(virt_to_phys(omap_secondary_startup),         \
+                                       OMAP4_AUXCOREBOOT_REG0);
+       smp_wmb();
+
+       /*
+        * Send a 'sev' to wake the secondary core from WFE.
+        */
+       set_event();
+       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
+                      "OMAP4: strange core count of 0? Default to 1\n");
+               ncores = 1;
+       }
+
+       if (ncores > NR_CPUS) {
+               printk(KERN_WARNING
+                      "OMAP4: no. of cores (%d) greater than configured "
+                      "maximum of %d - clipping\n",
+                      ncores, NR_CPUS);
+               ncores = NR_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();
+
+               /*
+                * Initialise the SCU and wake up the secondary core using
+                * wakeup_secondary().
+                */
+               scu_enable(scu_base);
+               wakeup_secondary();
+       }
+}
diff --git a/arch/arm/mach-omap2/omap3-iommu.c b/arch/arm/mach-omap2/omap3-iommu.c
new file mode 100644 (file)
index 0000000..194189c
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * omap iommu: omap3 device registration
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Written by Hiroshi DOYU <Hiroshi.DOYU@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/platform_device.h>
+
+#include <mach/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,
+};
+
+static const struct iommu_platform_data omap3_iommu_pdata[] __initconst = {
+       {
+               .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",
+       },
+#endif
+};
+#define NR_IOMMU_DEVICES ARRAY_SIZE(omap3_iommu_pdata)
+
+static struct platform_device *omap3_iommu_pdev[NR_IOMMU_DEVICES];
+
+static int __init omap3_iommu_init(void)
+{
+       int i, err;
+
+       for (i = 0; i < NR_IOMMU_DEVICES; i++) {
+               struct platform_device *pdev;
+               struct resource res[2];
+
+               pdev = platform_device_alloc("omap-iommu", i);
+               if (!pdev) {
+                       err = -ENOMEM;
+                       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;
+
+               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]));
+               if (err)
+                       goto err_out;
+               err = platform_device_add(pdev);
+               if (err)
+                       goto err_out;
+               omap3_iommu_pdev[i] = pdev;
+       }
+       return 0;
+
+err_out:
+       while (i--)
+               platform_device_put(omap3_iommu_pdev[i]);
+       return err;
+}
+module_init(omap3_iommu_init);
+
+static void __exit omap3_iommu_exit(void)
+{
+       int i;
+
+       for (i = 0; i < NR_IOMMU_DEVICES; i++)
+               platform_device_unregister(omap3_iommu_pdev[i]);
+}
+module_exit(omap3_iommu_exit);
+
+MODULE_AUTHOR("Hiroshi DOYU");
+MODULE_DESCRIPTION("omap iommu: omap3 device registration");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c
new file mode 100644 (file)
index 0000000..6cc375a
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * OMAP Power Management debug routines
+ *
+ * Copyright (C) 2005 Texas Instruments, Inc.
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * Written by:
+ * Richard Woodruff <r-woodruff2@ti.com>
+ * Tony Lindgren
+ * Juha Yrjola
+ * Amit Kucheria <amit.kucheria@nokia.com>
+ * Igor Stoppa <igor.stoppa@nokia.com>
+ * Jouni Hogander
+ *
+ * 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/kernel.h>
+#include <linux/timer.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <mach/clock.h>
+#include <mach/board.h>
+
+#include "prm.h"
+#include "cm.h"
+#include "pm.h"
+
+int omap2_pm_debug;
+
+#define DUMP_PRM_MOD_REG(mod, reg)    \
+       regs[reg_count].name = #mod "." #reg; \
+       regs[reg_count++].val = prm_read_mod_reg(mod, reg)
+#define DUMP_CM_MOD_REG(mod, reg)     \
+       regs[reg_count].name = #mod "." #reg; \
+       regs[reg_count++].val = cm_read_mod_reg(mod, reg)
+#define DUMP_PRM_REG(reg) \
+       regs[reg_count].name = #reg; \
+       regs[reg_count++].val = __raw_readl(reg)
+#define DUMP_CM_REG(reg) \
+       regs[reg_count].name = #reg; \
+       regs[reg_count++].val = __raw_readl(reg)
+#define DUMP_INTC_REG(reg, off) \
+       regs[reg_count].name = #reg; \
+       regs[reg_count++].val = __raw_readl(IO_ADDRESS(0x480fe000 + (off)))
+
+void omap2_pm_dump(int mode, int resume, unsigned int us)
+{
+       struct reg {
+               const char *name;
+               u32 val;
+       } regs[32];
+       int reg_count = 0, i;
+       const char *s1 = NULL, *s2 = NULL;
+
+       if (!resume) {
+#if 0
+               /* MPU */
+               DUMP_PRM_MOD_REG(OCP_MOD, OMAP2_PRM_IRQENABLE_MPU_OFFSET);
+               DUMP_CM_MOD_REG(MPU_MOD, CM_CLKSTCTRL);
+               DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTCTRL);
+               DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTST);
+               DUMP_PRM_MOD_REG(MPU_MOD, PM_WKDEP);
+#endif
+#if 0
+               /* INTC */
+               DUMP_INTC_REG(INTC_MIR0, 0x0084);
+               DUMP_INTC_REG(INTC_MIR1, 0x00a4);
+               DUMP_INTC_REG(INTC_MIR2, 0x00c4);
+#endif
+#if 0
+               DUMP_CM_MOD_REG(CORE_MOD, CM_FCLKEN1);
+               if (cpu_is_omap24xx()) {
+                       DUMP_CM_MOD_REG(CORE_MOD, OMAP24XX_CM_FCLKEN2);
+                       DUMP_PRM_MOD_REG(OMAP24XX_GR_MOD,
+                                       OMAP2_PRCM_CLKEMUL_CTRL_OFFSET);
+                       DUMP_PRM_MOD_REG(OMAP24XX_GR_MOD,
+                                       OMAP2_PRCM_CLKSRC_CTRL_OFFSET);
+               }
+               DUMP_CM_MOD_REG(WKUP_MOD, CM_FCLKEN);
+               DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN1);
+               DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN2);
+               DUMP_CM_MOD_REG(WKUP_MOD, CM_ICLKEN);
+               DUMP_CM_MOD_REG(PLL_MOD, CM_CLKEN);
+               DUMP_CM_MOD_REG(PLL_MOD, CM_AUTOIDLE);
+               DUMP_PRM_MOD_REG(CORE_MOD, PM_PWSTST);
+#endif
+#if 0
+               /* DSP */
+               if (cpu_is_omap24xx()) {
+                       DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_FCLKEN);
+                       DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_ICLKEN);
+                       DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_IDLEST);
+                       DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_AUTOIDLE);
+                       DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSEL);
+                       DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSTCTRL);
+                       DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTCTRL);
+                       DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTST);
+                       DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTCTRL);
+                       DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTST);
+               }
+#endif
+       } else {
+               DUMP_PRM_MOD_REG(CORE_MOD, PM_WKST1);
+               if (cpu_is_omap24xx())
+                       DUMP_PRM_MOD_REG(CORE_MOD, OMAP24XX_PM_WKST2);
+               DUMP_PRM_MOD_REG(WKUP_MOD, PM_WKST);
+               DUMP_PRM_MOD_REG(OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
+#if 1
+               DUMP_INTC_REG(INTC_PENDING_IRQ0, 0x0098);
+               DUMP_INTC_REG(INTC_PENDING_IRQ1, 0x00b8);
+               DUMP_INTC_REG(INTC_PENDING_IRQ2, 0x00d8);
+#endif
+       }
+
+       switch (mode) {
+       case 0:
+               s1 = "full";
+               s2 = "retention";
+               break;
+       case 1:
+               s1 = "MPU";
+               s2 = "retention";
+               break;
+       case 2:
+               s1 = "MPU";
+               s2 = "idle";
+               break;
+       }
+
+       if (!resume)
+#ifdef CONFIG_NO_HZ
+               printk(KERN_INFO
+                      "--- Going to %s %s (next timer after %u ms)\n", s1, s2,
+                      jiffies_to_msecs(get_next_timer_interrupt(jiffies) -
+                                       jiffies));
+#else
+               printk(KERN_INFO "--- Going to %s %s\n", s1, s2);
+#endif
+       else
+               printk(KERN_INFO "--- Woke up (slept for %u.%03u ms)\n",
+                       us / 1000, us % 1000);
+
+       for (i = 0; i < reg_count; i++)
+               printk(KERN_INFO "%-20s: 0x%08x\n", regs[i].name, regs[i].val);
+}
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
deleted file mode 100644 (file)
index ea8ceae..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * linux/arch/arm/mach-omap2/pm.c
- *
- * OMAP2 Power Management Routines
- *
- * 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 omap1
- *
- * This 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/suspend.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
-#include <linux/interrupt.h>
-#include <linux/sysfs.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <asm/atomic.h>
-#include <asm/mach/time.h>
-#include <asm/mach/irq.h>
-
-#include <mach/irqs.h>
-#include <mach/clock.h>
-#include <mach/sram.h>
-#include <mach/pm.h>
-
-static struct clk *vclk;
-static void (*omap2_sram_idle)(void);
-static void (*omap2_sram_suspend)(int dllctrl, int cpu_rev);
-static void (*saved_idle)(void);
-
-extern void __init pmdomain_init(void);
-extern void pmdomain_set_autoidle(void);
-
-static unsigned int omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_SIZE];
-
-void omap2_pm_idle(void)
-{
-       local_irq_disable();
-       local_fiq_disable();
-       if (need_resched()) {
-               local_fiq_enable();
-               local_irq_enable();
-               return;
-       }
-
-       omap2_sram_idle();
-       local_fiq_enable();
-       local_irq_enable();
-}
-
-static int omap2_pm_prepare(void)
-{
-       /* We cannot sleep in idle until we have resumed */
-       saved_idle = pm_idle;
-       pm_idle = NULL;
-       return 0;
-}
-
-static int omap2_pm_suspend(void)
-{
-       return 0;
-}
-
-static int omap2_pm_enter(suspend_state_t state)
-{
-       int ret = 0;
-
-       switch (state)
-       {
-       case PM_SUSPEND_STANDBY:
-       case PM_SUSPEND_MEM:
-               ret = omap2_pm_suspend();
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-static void omap2_pm_finish(void)
-{
-       pm_idle = saved_idle;
-}
-
-static struct platform_suspend_ops omap_pm_ops = {
-       .prepare        = omap2_pm_prepare,
-       .enter          = omap2_pm_enter,
-       .finish         = omap2_pm_finish,
-       .valid          = suspend_valid_only_mem,
-};
-
-static int __init omap2_pm_init(void)
-{
-       return 0;
-}
-
-__initcall(omap2_pm_init);
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
new file mode 100644 (file)
index 0000000..f7b3baf
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * OMAP2/3 Power Management Routines
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Jouni Hogander
+ *
+ * This 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_PM_H
+#define __ARCH_ARM_MACH_OMAP2_PM_H
+
+extern int omap2_pm_init(void);
+extern int omap3_pm_init(void);
+
+#ifdef CONFIG_PM_DEBUG
+extern void omap2_pm_dump(int mode, int resume, unsigned int us);
+extern int omap2_pm_debug;
+#else
+#define omap2_pm_dump(mode, resume, us)                do {} while (0);
+#define omap2_pm_debug                         0
+#endif /* CONFIG_PM_DEBUG */
+
+extern void omap24xx_idle_loop_suspend(void);
+
+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 unsigned int omap24xx_idle_loop_suspend_sz;
+extern unsigned int omap34xx_suspend_sz;
+extern unsigned int save_secure_ram_context_sz;
+extern unsigned int omap24xx_cpu_suspend_sz;
+extern unsigned int omap34xx_cpu_suspend_sz;
+
+#endif
diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
new file mode 100644 (file)
index 0000000..db10255
--- /dev/null
@@ -0,0 +1,549 @@
+/*
+ * OMAP2 Power Management Routines
+ *
+ * Copyright (C) 2005 Texas Instruments, Inc.
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * Written by:
+ * Richard Woodruff <r-woodruff2@ti.com>
+ * Tony Lindgren
+ * Juha Yrjola
+ * Amit Kucheria <amit.kucheria@nokia.com>
+ * Igor Stoppa <igor.stoppa@nokia.com>
+ *
+ * Based on pm.c for omap1
+ *
+ * This 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/suspend.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/interrupt.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/time.h>
+#include <linux/gpio.h>
+
+#include <asm/mach/time.h>
+#include <asm/mach/irq.h>
+#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 "prm.h"
+#include "prm-regbits-24xx.h"
+#include "cm.h"
+#include "cm-regbits-24xx.h"
+#include "sdrc.h"
+#include "pm.h"
+
+#include <mach/powerdomain.h>
+#include <mach/clockdomain.h>
+
+static void (*omap2_sram_idle)(void);
+static void (*omap2_sram_suspend)(u32 dllctrl, void __iomem *sdrc_dlla_ctrl,
+                                 void __iomem *sdrc_power);
+
+static struct powerdomain *mpu_pwrdm;
+static struct powerdomain *core_pwrdm;
+
+static struct clockdomain *dsp_clkdm;
+static struct clockdomain *gfx_clkdm;
+
+static struct clk *osc_ck, *emul_ck;
+
+static int omap2_fclks_active(void)
+{
+       u32 f1, f2;
+
+       f1 = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
+       f2 = cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2);
+
+       /* Ignore UART clocks.  These are handled by UART core (serial.c) */
+       f1 &= ~(OMAP24XX_EN_UART1 | OMAP24XX_EN_UART2);
+       f2 &= ~OMAP24XX_EN_UART3;
+
+       if (f1 | f2)
+               return 1;
+       return 0;
+}
+
+static void omap2_enter_full_retention(void)
+{
+       u32 l;
+       struct timespec ts_preidle, ts_postidle, ts_idle;
+
+       /* There is 1 reference hold for all children of the oscillator
+        * clock, the following will remove it. If no one else uses the
+        * oscillator itself it will be disabled if/when we enter retention
+        * mode.
+        */
+       clk_disable(osc_ck);
+
+       /* Clear old wake-up events */
+       /* REVISIT: These write to reserved bits? */
+       prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
+       prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
+       prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST);
+
+       /*
+        * Set MPU powerdomain's next power state to RETENTION;
+        * preserve logic state during retention
+        */
+       pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
+       pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
+
+       /* Workaround to kill USB */
+       l = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0) | OMAP24XX_USBSTANDBYCTRL;
+       omap_ctrl_writel(l, OMAP2_CONTROL_DEVCONF0);
+
+       omap2_gpio_prepare_for_retention();
+
+       if (omap2_pm_debug) {
+               omap2_pm_dump(0, 0, 0);
+               getnstimeofday(&ts_preidle);
+       }
+
+       /* One last check for pending IRQs to avoid extra latency due
+        * to sleeping unnecessarily. */
+       if (omap_irq_pending())
+               goto no_sleep;
+
+       omap_uart_prepare_idle(0);
+       omap_uart_prepare_idle(1);
+       omap_uart_prepare_idle(2);
+
+       /* Jump to SRAM suspend code */
+       omap2_sram_suspend(sdrc_read_reg(SDRC_DLLA_CTRL),
+                          OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL),
+                          OMAP_SDRC_REGADDR(SDRC_POWER));
+
+       omap_uart_resume_idle(2);
+       omap_uart_resume_idle(1);
+       omap_uart_resume_idle(0);
+
+no_sleep:
+       if (omap2_pm_debug) {
+               unsigned long long tmp;
+
+               getnstimeofday(&ts_postidle);
+               ts_idle = timespec_sub(ts_postidle, ts_preidle);
+               tmp = timespec_to_ns(&ts_idle) * NSEC_PER_USEC;
+               omap2_pm_dump(0, 1, tmp);
+       }
+       omap2_gpio_resume_after_retention();
+
+       clk_enable(osc_ck);
+
+       /* clear CORE wake-up events */
+       prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
+       prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
+
+       /* wakeup domain events - bit 1: GPT1, bit5 GPIO */
+       prm_clear_mod_reg_bits(0x4 | 0x1, WKUP_MOD, PM_WKST);
+
+       /* MPU domain wake events */
+       l = prm_read_mod_reg(OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
+       if (l & 0x01)
+               prm_write_mod_reg(0x01, OCP_MOD,
+                                 OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
+       if (l & 0x20)
+               prm_write_mod_reg(0x20, OCP_MOD,
+                                 OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
+
+       /* Mask future PRCM-to-MPU interrupts */
+       prm_write_mod_reg(0x0, OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
+}
+
+static int omap2_i2c_active(void)
+{
+       u32 l;
+
+       l = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
+       return l & (OMAP2420_EN_I2C2 | OMAP2420_EN_I2C1);
+}
+
+static int sti_console_enabled;
+
+static int omap2_allow_mpu_retention(void)
+{
+       u32 l;
+
+       /* Check for MMC, UART2, UART1, McSPI2, McSPI1 and DSS1. */
+       l = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
+       if (l & (OMAP2420_EN_MMC | OMAP24XX_EN_UART2 |
+                OMAP24XX_EN_UART1 | OMAP24XX_EN_MCSPI2 |
+                OMAP24XX_EN_MCSPI1 | OMAP24XX_EN_DSS1))
+               return 0;
+       /* Check for UART3. */
+       l = cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2);
+       if (l & OMAP24XX_EN_UART3)
+               return 0;
+       if (sti_console_enabled)
+               return 0;
+
+       return 1;
+}
+
+static void omap2_enter_mpu_retention(void)
+{
+       int only_idle = 0;
+       struct timespec ts_preidle, ts_postidle, ts_idle;
+
+       /* Putting MPU into the WFI state while a transfer is active
+        * seems to cause the I2C block to timeout. Why? Good question. */
+       if (omap2_i2c_active())
+               return;
+
+       /* The peripherals seem not to be able to wake up the MPU when
+        * it is in retention mode. */
+       if (omap2_allow_mpu_retention()) {
+               /* REVISIT: These write to reserved bits? */
+               prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
+               prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
+               prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST);
+
+               /* Try to enter MPU retention */
+               prm_write_mod_reg((0x01 << OMAP_POWERSTATE_SHIFT) |
+                                 OMAP_LOGICRETSTATE,
+                                 MPU_MOD, PM_PWSTCTRL);
+       } else {
+               /* Block MPU retention */
+
+               prm_write_mod_reg(OMAP_LOGICRETSTATE, MPU_MOD, PM_PWSTCTRL);
+               only_idle = 1;
+       }
+
+       if (omap2_pm_debug) {
+               omap2_pm_dump(only_idle ? 2 : 1, 0, 0);
+               getnstimeofday(&ts_preidle);
+       }
+
+       omap2_sram_idle();
+
+       if (omap2_pm_debug) {
+               unsigned long long tmp;
+
+               getnstimeofday(&ts_postidle);
+               ts_idle = timespec_sub(ts_postidle, ts_preidle);
+               tmp = timespec_to_ns(&ts_idle) * NSEC_PER_USEC;
+               omap2_pm_dump(only_idle ? 2 : 1, 1, tmp);
+       }
+}
+
+static int omap2_can_sleep(void)
+{
+       if (omap2_fclks_active())
+               return 0;
+       if (osc_ck->usecount > 1)
+               return 0;
+       if (omap_dma_running())
+               return 0;
+
+       return 1;
+}
+
+static void omap2_pm_idle(void)
+{
+       local_irq_disable();
+       local_fiq_disable();
+
+       if (!omap2_can_sleep()) {
+               if (omap_irq_pending())
+                       goto out;
+               omap2_enter_mpu_retention();
+               goto out;
+       }
+
+       if (omap_irq_pending())
+               goto out;
+
+       omap2_enter_full_retention();
+
+out:
+       local_fiq_enable();
+       local_irq_enable();
+}
+
+static int omap2_pm_prepare(void)
+{
+       /* We cannot sleep in idle until we have resumed */
+       disable_hlt();
+       return 0;
+}
+
+static int omap2_pm_suspend(void)
+{
+       u32 wken_wkup, mir1;
+
+       wken_wkup = prm_read_mod_reg(WKUP_MOD, PM_WKEN);
+       prm_write_mod_reg(wken_wkup & ~OMAP24XX_EN_GPT1, WKUP_MOD, PM_WKEN);
+
+       /* Mask GPT1 */
+       mir1 = omap_readl(0x480fe0a4);
+       omap_writel(1 << 5, 0x480fe0ac);
+
+       omap_uart_prepare_suspend();
+       omap2_enter_full_retention();
+
+       omap_writel(mir1, 0x480fe0a4);
+       prm_write_mod_reg(wken_wkup, WKUP_MOD, PM_WKEN);
+
+       return 0;
+}
+
+static int omap2_pm_enter(suspend_state_t state)
+{
+       int ret = 0;
+
+       switch (state) {
+       case PM_SUSPEND_STANDBY:
+       case PM_SUSPEND_MEM:
+               ret = omap2_pm_suspend();
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static void omap2_pm_finish(void)
+{
+       enable_hlt();
+}
+
+static struct platform_suspend_ops omap_pm_ops = {
+       .prepare        = omap2_pm_prepare,
+       .enter          = omap2_pm_enter,
+       .finish         = omap2_pm_finish,
+       .valid          = suspend_valid_only_mem,
+};
+
+static int _pm_clkdm_enable_hwsup(struct clockdomain *clkdm)
+{
+       omap2_clkdm_allow_idle(clkdm);
+       return 0;
+}
+
+static void __init prcm_setup_regs(void)
+{
+       int i, num_mem_banks;
+       struct powerdomain *pwrdm;
+
+       /* Enable autoidle */
+       prm_write_mod_reg(OMAP24XX_AUTOIDLE, OCP_MOD,
+                         OMAP2_PRCM_SYSCONFIG_OFFSET);
+
+       /* Set all domain wakeup dependencies */
+       prm_write_mod_reg(OMAP_EN_WKUP_MASK, MPU_MOD, PM_WKDEP);
+       prm_write_mod_reg(0, OMAP24XX_DSP_MOD, PM_WKDEP);
+       prm_write_mod_reg(0, GFX_MOD, PM_WKDEP);
+       prm_write_mod_reg(0, CORE_MOD, PM_WKDEP);
+       if (cpu_is_omap2430())
+               prm_write_mod_reg(0, OMAP2430_MDM_MOD, PM_WKDEP);
+
+       /*
+        * Set CORE powerdomain memory banks to retain their contents
+        * during RETENTION
+        */
+       num_mem_banks = pwrdm_get_mem_bank_count(core_pwrdm);
+       for (i = 0; i < num_mem_banks; i++)
+               pwrdm_set_mem_retst(core_pwrdm, i, PWRDM_POWER_RET);
+
+       /* Set CORE powerdomain's next power state to RETENTION */
+       pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_RET);
+
+       /*
+        * Set MPU powerdomain's next power state to RETENTION;
+        * preserve logic state during retention
+        */
+       pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
+       pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
+
+       /* Force-power down DSP, GFX powerdomains */
+
+       pwrdm = clkdm_get_pwrdm(dsp_clkdm);
+       pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
+       omap2_clkdm_sleep(dsp_clkdm);
+
+       pwrdm = clkdm_get_pwrdm(gfx_clkdm);
+       pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
+       omap2_clkdm_sleep(gfx_clkdm);
+
+       /* Enable clockdomain hardware-supervised control for all clkdms */
+       clkdm_for_each(_pm_clkdm_enable_hwsup);
+
+       /* Enable clock autoidle for all domains */
+       cm_write_mod_reg(OMAP24XX_AUTO_CAM |
+                        OMAP24XX_AUTO_MAILBOXES |
+                        OMAP24XX_AUTO_WDT4 |
+                        OMAP2420_AUTO_WDT3 |
+                        OMAP24XX_AUTO_MSPRO |
+                        OMAP2420_AUTO_MMC |
+                        OMAP24XX_AUTO_FAC |
+                        OMAP2420_AUTO_EAC |
+                        OMAP24XX_AUTO_HDQ |
+                        OMAP24XX_AUTO_UART2 |
+                        OMAP24XX_AUTO_UART1 |
+                        OMAP24XX_AUTO_I2C2 |
+                        OMAP24XX_AUTO_I2C1 |
+                        OMAP24XX_AUTO_MCSPI2 |
+                        OMAP24XX_AUTO_MCSPI1 |
+                        OMAP24XX_AUTO_MCBSP2 |
+                        OMAP24XX_AUTO_MCBSP1 |
+                        OMAP24XX_AUTO_GPT12 |
+                        OMAP24XX_AUTO_GPT11 |
+                        OMAP24XX_AUTO_GPT10 |
+                        OMAP24XX_AUTO_GPT9 |
+                        OMAP24XX_AUTO_GPT8 |
+                        OMAP24XX_AUTO_GPT7 |
+                        OMAP24XX_AUTO_GPT6 |
+                        OMAP24XX_AUTO_GPT5 |
+                        OMAP24XX_AUTO_GPT4 |
+                        OMAP24XX_AUTO_GPT3 |
+                        OMAP24XX_AUTO_GPT2 |
+                        OMAP2420_AUTO_VLYNQ |
+                        OMAP24XX_AUTO_DSS,
+                        CORE_MOD, CM_AUTOIDLE1);
+       cm_write_mod_reg(OMAP24XX_AUTO_UART3 |
+                        OMAP24XX_AUTO_SSI |
+                        OMAP24XX_AUTO_USB,
+                        CORE_MOD, CM_AUTOIDLE2);
+       cm_write_mod_reg(OMAP24XX_AUTO_SDRC |
+                        OMAP24XX_AUTO_GPMC |
+                        OMAP24XX_AUTO_SDMA,
+                        CORE_MOD, CM_AUTOIDLE3);
+       cm_write_mod_reg(OMAP24XX_AUTO_PKA |
+                        OMAP24XX_AUTO_AES |
+                        OMAP24XX_AUTO_RNG |
+                        OMAP24XX_AUTO_SHA |
+                        OMAP24XX_AUTO_DES,
+                        CORE_MOD, OMAP24XX_CM_AUTOIDLE4);
+
+       cm_write_mod_reg(OMAP2420_AUTO_DSP_IPI, OMAP24XX_DSP_MOD, CM_AUTOIDLE);
+
+       /* Put DPLL and both APLLs into autoidle mode */
+       cm_write_mod_reg((0x03 << OMAP24XX_AUTO_DPLL_SHIFT) |
+                        (0x03 << OMAP24XX_AUTO_96M_SHIFT) |
+                        (0x03 << OMAP24XX_AUTO_54M_SHIFT),
+                        PLL_MOD, CM_AUTOIDLE);
+
+       cm_write_mod_reg(OMAP24XX_AUTO_OMAPCTRL |
+                        OMAP24XX_AUTO_WDT1 |
+                        OMAP24XX_AUTO_MPU_WDT |
+                        OMAP24XX_AUTO_GPIOS |
+                        OMAP24XX_AUTO_32KSYNC |
+                        OMAP24XX_AUTO_GPT1,
+                        WKUP_MOD, CM_AUTOIDLE);
+
+       /* REVISIT: Configure number of 32 kHz clock cycles for sys_clk
+        * stabilisation */
+       prm_write_mod_reg(15 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD,
+                         OMAP2_PRCM_CLKSSETUP_OFFSET);
+
+       /* Configure automatic voltage transition */
+       prm_write_mod_reg(2 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD,
+                         OMAP2_PRCM_VOLTSETUP_OFFSET);
+       prm_write_mod_reg(OMAP24XX_AUTO_EXTVOLT |
+                         (0x1 << OMAP24XX_SETOFF_LEVEL_SHIFT) |
+                         OMAP24XX_MEMRETCTRL |
+                         (0x1 << OMAP24XX_SETRET_LEVEL_SHIFT) |
+                         (0x0 << OMAP24XX_VOLT_LEVEL_SHIFT),
+                         OMAP24XX_GR_MOD, OMAP2_PRCM_VOLTCTRL_OFFSET);
+
+       /* Enable wake-up events */
+       prm_write_mod_reg(OMAP24XX_EN_GPIOS | OMAP24XX_EN_GPT1,
+                         WKUP_MOD, PM_WKEN);
+}
+
+int __init omap2_pm_init(void)
+{
+       u32 l;
+
+       if (!cpu_is_omap24xx())
+               return -ENODEV;
+
+       printk(KERN_INFO "Power Management for OMAP2 initializing\n");
+       l = prm_read_mod_reg(OCP_MOD, OMAP2_PRCM_REVISION_OFFSET);
+       printk(KERN_INFO "PRCM revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
+
+       /* Look up important powerdomains, clockdomains */
+
+       mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
+       if (!mpu_pwrdm)
+               pr_err("PM: mpu_pwrdm not found\n");
+
+       core_pwrdm = pwrdm_lookup("core_pwrdm");
+       if (!core_pwrdm)
+               pr_err("PM: core_pwrdm not found\n");
+
+       dsp_clkdm = clkdm_lookup("dsp_clkdm");
+       if (!dsp_clkdm)
+               pr_err("PM: mpu_clkdm not found\n");
+
+       gfx_clkdm = clkdm_lookup("gfx_clkdm");
+       if (!gfx_clkdm)
+               pr_err("PM: gfx_clkdm not found\n");
+
+
+       osc_ck = clk_get(NULL, "osc_ck");
+       if (IS_ERR(osc_ck)) {
+               printk(KERN_ERR "could not get osc_ck\n");
+               return -ENODEV;
+       }
+
+       if (cpu_is_omap242x()) {
+               emul_ck = clk_get(NULL, "emul_ck");
+               if (IS_ERR(emul_ck)) {
+                       printk(KERN_ERR "could not get emul_ck\n");
+                       clk_put(osc_ck);
+                       return -ENODEV;
+               }
+       }
+
+       prcm_setup_regs();
+
+       /* Hack to prevent MPU retention when STI console is enabled. */
+       {
+               const struct omap_sti_console_config *sti;
+
+               sti = omap_get_config(OMAP_TAG_STI_CONSOLE,
+                                     struct omap_sti_console_config);
+               if (sti != NULL && sti->enable)
+                       sti_console_enabled = 1;
+       }
+
+       /*
+        * We copy the assembler sleep/wakeup routines to SRAM.
+        * These routines need to be in SRAM as that's the only
+        * memory the MPU can see when it wakes up.
+        */
+       if (cpu_is_omap24xx()) {
+               omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend,
+                                                omap24xx_idle_loop_suspend_sz);
+
+               omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend,
+                                                   omap24xx_cpu_suspend_sz);
+       }
+
+       suspend_set_ops(&omap_pm_ops);
+       pm_idle = omap2_pm_idle;
+
+       return 0;
+}
+
+late_initcall(omap2_pm_init);
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
new file mode 100644 (file)
index 0000000..841d4c5
--- /dev/null
@@ -0,0 +1,710 @@
+/*
+ * OMAP3 Power Management Routines
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation
+ * Tony Lindgren <tony@atomide.com>
+ * Jouni Hogander
+ *
+ * Copyright (C) 2005 Texas Instruments, Inc.
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * Based on pm.c for omap1
+ *
+ * This 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/pm.h>
+#include <linux/suspend.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+
+#include <mach/sram.h>
+#include <mach/clockdomain.h>
+#include <mach/powerdomain.h>
+#include <mach/control.h>
+#include <mach/serial.h>
+
+#include "cm.h"
+#include "cm-regbits-34xx.h"
+#include "prm-regbits-34xx.h"
+
+#include "prm.h"
+#include "pm.h"
+
+struct power_state {
+       struct powerdomain *pwrdm;
+       u32 next_state;
+       u32 saved_state;
+       struct list_head node;
+};
+
+static LIST_HEAD(pwrst_list);
+
+static void (*_omap_sram_idle)(u32 *addr, int save_state);
+
+static struct powerdomain *mpu_pwrdm;
+
+/* PRCM Interrupt Handler for wakeups */
+static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
+{
+       u32 wkst, irqstatus_mpu;
+       u32 fclk, iclk;
+
+       /* WKUP */
+       wkst = prm_read_mod_reg(WKUP_MOD, PM_WKST);
+       if (wkst) {
+               iclk = cm_read_mod_reg(WKUP_MOD, CM_ICLKEN);
+               fclk = cm_read_mod_reg(WKUP_MOD, CM_FCLKEN);
+               cm_set_mod_reg_bits(wkst, WKUP_MOD, CM_ICLKEN);
+               cm_set_mod_reg_bits(wkst, WKUP_MOD, CM_FCLKEN);
+               prm_write_mod_reg(wkst, WKUP_MOD, PM_WKST);
+               while (prm_read_mod_reg(WKUP_MOD, PM_WKST))
+                       cpu_relax();
+               cm_write_mod_reg(iclk, WKUP_MOD, CM_ICLKEN);
+               cm_write_mod_reg(fclk, WKUP_MOD, CM_FCLKEN);
+       }
+
+       /* CORE */
+       wkst = prm_read_mod_reg(CORE_MOD, PM_WKST1);
+       if (wkst) {
+               iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN1);
+               fclk = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
+               cm_set_mod_reg_bits(wkst, CORE_MOD, CM_ICLKEN1);
+               cm_set_mod_reg_bits(wkst, CORE_MOD, CM_FCLKEN1);
+               prm_write_mod_reg(wkst, CORE_MOD, PM_WKST1);
+               while (prm_read_mod_reg(CORE_MOD, PM_WKST1))
+                       cpu_relax();
+               cm_write_mod_reg(iclk, CORE_MOD, CM_ICLKEN1);
+               cm_write_mod_reg(fclk, CORE_MOD, CM_FCLKEN1);
+       }
+       wkst = prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3);
+       if (wkst) {
+               iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN3);
+               fclk = cm_read_mod_reg(CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
+               cm_set_mod_reg_bits(wkst, CORE_MOD, CM_ICLKEN3);
+               cm_set_mod_reg_bits(wkst, CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
+               prm_write_mod_reg(wkst, CORE_MOD, OMAP3430ES2_PM_WKST3);
+               while (prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3))
+                       cpu_relax();
+               cm_write_mod_reg(iclk, CORE_MOD, CM_ICLKEN3);
+               cm_write_mod_reg(fclk, CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
+       }
+
+       /* PER */
+       wkst = prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST);
+       if (wkst) {
+               iclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_ICLKEN);
+               fclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_FCLKEN);
+               cm_set_mod_reg_bits(wkst, OMAP3430_PER_MOD, CM_ICLKEN);
+               cm_set_mod_reg_bits(wkst, OMAP3430_PER_MOD, CM_FCLKEN);
+               prm_write_mod_reg(wkst, OMAP3430_PER_MOD, PM_WKST);
+               while (prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST))
+                       cpu_relax();
+               cm_write_mod_reg(iclk, OMAP3430_PER_MOD, CM_ICLKEN);
+               cm_write_mod_reg(fclk, OMAP3430_PER_MOD, CM_FCLKEN);
+       }
+
+       if (omap_rev() > OMAP3430_REV_ES1_0) {
+               /* USBHOST */
+               wkst = prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, PM_WKST);
+               if (wkst) {
+                       iclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
+                                              CM_ICLKEN);
+                       fclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
+                                              CM_FCLKEN);
+                       cm_set_mod_reg_bits(wkst, OMAP3430ES2_USBHOST_MOD,
+                                           CM_ICLKEN);
+                       cm_set_mod_reg_bits(wkst, OMAP3430ES2_USBHOST_MOD,
+                                           CM_FCLKEN);
+                       prm_write_mod_reg(wkst, OMAP3430ES2_USBHOST_MOD,
+                                         PM_WKST);
+                       while (prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
+                                               PM_WKST))
+                               cpu_relax();
+                       cm_write_mod_reg(iclk, OMAP3430ES2_USBHOST_MOD,
+                                        CM_ICLKEN);
+                       cm_write_mod_reg(fclk, OMAP3430ES2_USBHOST_MOD,
+                                        CM_FCLKEN);
+               }
+       }
+
+       irqstatus_mpu = prm_read_mod_reg(OCP_MOD,
+                                        OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
+       prm_write_mod_reg(irqstatus_mpu, OCP_MOD,
+                         OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
+
+       while (prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET))
+               cpu_relax();
+
+       return IRQ_HANDLED;
+}
+
+static void omap_sram_idle(void)
+{
+       /* Variable to tell what needs to be saved and restored
+        * in omap_sram_idle*/
+       /* save_state = 0 => Nothing to save and restored */
+       /* 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;
+
+       if (!_omap_sram_idle)
+               return;
+
+       mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
+       switch (mpu_next_state) {
+       case PWRDM_POWER_RET:
+               /* No need to save context */
+               save_state = 0;
+               break;
+       default:
+               /* Invalid state */
+               printk(KERN_ERR "Invalid mpu state in sram_idle\n");
+               return;
+       }
+       omap2_gpio_prepare_for_retention();
+       omap_uart_prepare_idle(0);
+       omap_uart_prepare_idle(1);
+       omap_uart_prepare_idle(2);
+
+       _omap_sram_idle(NULL, save_state);
+       cpu_init();
+
+       omap_uart_resume_idle(2);
+       omap_uart_resume_idle(1);
+       omap_uart_resume_idle(0);
+       omap2_gpio_resume_after_retention();
+}
+
+/*
+ * 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;
+
+       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;
+}
+
+static int omap3_can_sleep(void)
+{
+       if (!omap_uart_can_sleep())
+               return 0;
+       if (omap3_fclks_active())
+               return 0;
+       return 1;
+}
+
+/* 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)
+{
+       u32 cur_state;
+       int sleep_switch = 0;
+       int ret = 0;
+
+       if (pwrdm == NULL || IS_ERR(pwrdm))
+               return -EINVAL;
+
+       while (!(pwrdm->pwrsts & (1 << state))) {
+               if (state == PWRDM_POWER_OFF)
+                       return ret;
+               state--;
+       }
+
+       cur_state = pwrdm_read_next_pwrst(pwrdm);
+       if (cur_state == state)
+               return ret;
+
+       if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) {
+               omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
+               sleep_switch = 1;
+               pwrdm_wait_transition(pwrdm);
+       }
+
+       ret = pwrdm_set_next_pwrst(pwrdm, state);
+       if (ret) {
+               printk(KERN_ERR "Unable to set state of powerdomain: %s\n",
+                      pwrdm->name);
+               goto err;
+       }
+
+       if (sleep_switch) {
+               omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
+               pwrdm_wait_transition(pwrdm);
+       }
+
+err:
+       return ret;
+}
+
+static void omap3_pm_idle(void)
+{
+       local_irq_disable();
+       local_fiq_disable();
+
+       if (!omap3_can_sleep())
+               goto out;
+
+       if (omap_irq_pending())
+               goto out;
+
+       omap_sram_idle();
+
+out:
+       local_fiq_enable();
+       local_irq_enable();
+}
+
+static int omap3_pm_prepare(void)
+{
+       disable_hlt();
+       return 0;
+}
+
+static int omap3_pm_suspend(void)
+{
+       struct power_state *pwrst;
+       int state, ret = 0;
+
+       /* Read current next_pwrsts */
+       list_for_each_entry(pwrst, &pwrst_list, node)
+               pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
+       /* Set ones wanted by suspend */
+       list_for_each_entry(pwrst, &pwrst_list, node) {
+               if (set_pwrdm_state(pwrst->pwrdm, pwrst->next_state))
+                       goto restore;
+               if (pwrdm_clear_all_prev_pwrst(pwrst->pwrdm))
+                       goto restore;
+       }
+
+       omap_uart_prepare_suspend();
+       omap_sram_idle();
+
+restore:
+       /* Restore next_pwrsts */
+       list_for_each_entry(pwrst, &pwrst_list, node) {
+               set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
+               state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
+               if (state > pwrst->next_state) {
+                       printk(KERN_INFO "Powerdomain (%s) didn't enter "
+                              "target state %d\n",
+                              pwrst->pwrdm->name, pwrst->next_state);
+                       ret = -1;
+               }
+       }
+       if (ret)
+               printk(KERN_ERR "Could not enter target state in pm_suspend\n");
+       else
+               printk(KERN_INFO "Successfully put all powerdomains "
+                      "to target state\n");
+
+       return ret;
+}
+
+static int omap3_pm_enter(suspend_state_t state)
+{
+       int ret = 0;
+
+       switch (state) {
+       case PM_SUSPEND_STANDBY:
+       case PM_SUSPEND_MEM:
+               ret = omap3_pm_suspend();
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static void omap3_pm_finish(void)
+{
+       enable_hlt();
+}
+
+static struct platform_suspend_ops omap_pm_ops = {
+       .prepare        = omap3_pm_prepare,
+       .enter          = omap3_pm_enter,
+       .finish         = omap3_pm_finish,
+       .valid          = suspend_valid_only_mem,
+};
+
+
+/**
+ * omap3_iva_idle(): ensure IVA is in idle so it can be put into
+ *                   retention
+ *
+ * In cases where IVA2 is activated by bootcode, it may prevent
+ * full-chip retention or off-mode because it is not idle.  This
+ * function forces the IVA2 into idle state so it can go
+ * into retention/off and thus allow full-chip retention/off.
+ *
+ **/
+static void __init omap3_iva_idle(void)
+{
+       /* ensure IVA2 clock is disabled */
+       cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
+
+       /* if no clock activity, nothing else to do */
+       if (!(cm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSTST) &
+             OMAP3430_CLKACTIVITY_IVA2_MASK))
+               return;
+
+       /* Reset IVA2 */
+       prm_write_mod_reg(OMAP3430_RST1_IVA2 |
+                         OMAP3430_RST2_IVA2 |
+                         OMAP3430_RST3_IVA2,
+                         OMAP3430_IVA2_MOD, RM_RSTCTRL);
+
+       /* Enable IVA2 clock */
+       cm_write_mod_reg(OMAP3430_CM_FCLKEN_IVA2_EN_IVA2,
+                        OMAP3430_IVA2_MOD, CM_FCLKEN);
+
+       /* Set IVA2 boot mode to 'idle' */
+       omap_ctrl_writel(OMAP3_IVA2_BOOTMOD_IDLE,
+                        OMAP343X_CONTROL_IVA2_BOOTMOD);
+
+       /* Un-reset IVA2 */
+       prm_write_mod_reg(0, OMAP3430_IVA2_MOD, RM_RSTCTRL);
+
+       /* Disable IVA2 clock */
+       cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
+
+       /* Reset IVA2 */
+       prm_write_mod_reg(OMAP3430_RST1_IVA2 |
+                         OMAP3430_RST2_IVA2 |
+                         OMAP3430_RST3_IVA2,
+                         OMAP3430_IVA2_MOD, RM_RSTCTRL);
+}
+
+static void __init omap3_d2d_idle(void)
+{
+       u16 mask, padconf;
+
+       /* In a stand alone OMAP3430 where there is not a stacked
+        * modem for the D2D Idle Ack and D2D MStandby must be pulled
+        * high. S CONTROL_PADCONF_SAD2D_IDLEACK and
+        * CONTROL_PADCONF_SAD2D_MSTDBY to have a pull up. */
+       mask = (1 << 4) | (1 << 3); /* pull-up, enabled */
+       padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_MSTANDBY);
+       padconf |= mask;
+       omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_MSTANDBY);
+
+       padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_IDLEACK);
+       padconf |= mask;
+       omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_IDLEACK);
+
+       /* reset modem */
+       prm_write_mod_reg(OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON |
+                         OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RST,
+                         CORE_MOD, RM_RSTCTRL);
+       prm_write_mod_reg(0, CORE_MOD, RM_RSTCTRL);
+}
+
+static void __init prcm_setup_regs(void)
+{
+       /* XXX Reset all wkdeps. This should be done when initializing
+        * powerdomains */
+       prm_write_mod_reg(0, OMAP3430_IVA2_MOD, PM_WKDEP);
+       prm_write_mod_reg(0, MPU_MOD, PM_WKDEP);
+       prm_write_mod_reg(0, OMAP3430_DSS_MOD, PM_WKDEP);
+       prm_write_mod_reg(0, OMAP3430_NEON_MOD, PM_WKDEP);
+       prm_write_mod_reg(0, OMAP3430_CAM_MOD, PM_WKDEP);
+       prm_write_mod_reg(0, OMAP3430_PER_MOD, PM_WKDEP);
+       if (omap_rev() > OMAP3430_REV_ES1_0) {
+               prm_write_mod_reg(0, OMAP3430ES2_SGX_MOD, PM_WKDEP);
+               prm_write_mod_reg(0, OMAP3430ES2_USBHOST_MOD, PM_WKDEP);
+       } else
+               prm_write_mod_reg(0, GFX_MOD, PM_WKDEP);
+
+       /*
+        * Enable interface clock autoidle for all modules.
+        * Note that in the long run this should be done by clockfw
+        */
+       cm_write_mod_reg(
+               OMAP3430_AUTO_MODEM |
+               OMAP3430ES2_AUTO_MMC3 |
+               OMAP3430ES2_AUTO_ICR |
+               OMAP3430_AUTO_AES2 |
+               OMAP3430_AUTO_SHA12 |
+               OMAP3430_AUTO_DES2 |
+               OMAP3430_AUTO_MMC2 |
+               OMAP3430_AUTO_MMC1 |
+               OMAP3430_AUTO_MSPRO |
+               OMAP3430_AUTO_HDQ |
+               OMAP3430_AUTO_MCSPI4 |
+               OMAP3430_AUTO_MCSPI3 |
+               OMAP3430_AUTO_MCSPI2 |
+               OMAP3430_AUTO_MCSPI1 |
+               OMAP3430_AUTO_I2C3 |
+               OMAP3430_AUTO_I2C2 |
+               OMAP3430_AUTO_I2C1 |
+               OMAP3430_AUTO_UART2 |
+               OMAP3430_AUTO_UART1 |
+               OMAP3430_AUTO_GPT11 |
+               OMAP3430_AUTO_GPT10 |
+               OMAP3430_AUTO_MCBSP5 |
+               OMAP3430_AUTO_MCBSP1 |
+               OMAP3430ES1_AUTO_FAC | /* This is es1 only */
+               OMAP3430_AUTO_MAILBOXES |
+               OMAP3430_AUTO_OMAPCTRL |
+               OMAP3430ES1_AUTO_FSHOSTUSB |
+               OMAP3430_AUTO_HSOTGUSB |
+               OMAP3430_AUTO_SAD2D |
+               OMAP3430_AUTO_SSI,
+               CORE_MOD, CM_AUTOIDLE1);
+
+       cm_write_mod_reg(
+               OMAP3430_AUTO_PKA |
+               OMAP3430_AUTO_AES1 |
+               OMAP3430_AUTO_RNG |
+               OMAP3430_AUTO_SHA11 |
+               OMAP3430_AUTO_DES1,
+               CORE_MOD, CM_AUTOIDLE2);
+
+       if (omap_rev() > OMAP3430_REV_ES1_0) {
+               cm_write_mod_reg(
+                       OMAP3430_AUTO_MAD2D |
+                       OMAP3430ES2_AUTO_USBTLL,
+                       CORE_MOD, CM_AUTOIDLE3);
+       }
+
+       cm_write_mod_reg(
+               OMAP3430_AUTO_WDT2 |
+               OMAP3430_AUTO_WDT1 |
+               OMAP3430_AUTO_GPIO1 |
+               OMAP3430_AUTO_32KSYNC |
+               OMAP3430_AUTO_GPT12 |
+               OMAP3430_AUTO_GPT1 ,
+               WKUP_MOD, CM_AUTOIDLE);
+
+       cm_write_mod_reg(
+               OMAP3430_AUTO_DSS,
+               OMAP3430_DSS_MOD,
+               CM_AUTOIDLE);
+
+       cm_write_mod_reg(
+               OMAP3430_AUTO_CAM,
+               OMAP3430_CAM_MOD,
+               CM_AUTOIDLE);
+
+       cm_write_mod_reg(
+               OMAP3430_AUTO_GPIO6 |
+               OMAP3430_AUTO_GPIO5 |
+               OMAP3430_AUTO_GPIO4 |
+               OMAP3430_AUTO_GPIO3 |
+               OMAP3430_AUTO_GPIO2 |
+               OMAP3430_AUTO_WDT3 |
+               OMAP3430_AUTO_UART3 |
+               OMAP3430_AUTO_GPT9 |
+               OMAP3430_AUTO_GPT8 |
+               OMAP3430_AUTO_GPT7 |
+               OMAP3430_AUTO_GPT6 |
+               OMAP3430_AUTO_GPT5 |
+               OMAP3430_AUTO_GPT4 |
+               OMAP3430_AUTO_GPT3 |
+               OMAP3430_AUTO_GPT2 |
+               OMAP3430_AUTO_MCBSP4 |
+               OMAP3430_AUTO_MCBSP3 |
+               OMAP3430_AUTO_MCBSP2,
+               OMAP3430_PER_MOD,
+               CM_AUTOIDLE);
+
+       if (omap_rev() > OMAP3430_REV_ES1_0) {
+               cm_write_mod_reg(
+                       OMAP3430ES2_AUTO_USBHOST,
+                       OMAP3430ES2_USBHOST_MOD,
+                       CM_AUTOIDLE);
+       }
+
+       /*
+        * Set all plls to autoidle. This is needed until autoidle is
+        * enabled by clockfw
+        */
+       cm_write_mod_reg(1 << OMAP3430_AUTO_IVA2_DPLL_SHIFT,
+                        OMAP3430_IVA2_MOD, CM_AUTOIDLE2);
+       cm_write_mod_reg(1 << OMAP3430_AUTO_MPU_DPLL_SHIFT,
+                        MPU_MOD,
+                        CM_AUTOIDLE2);
+       cm_write_mod_reg((1 << OMAP3430_AUTO_PERIPH_DPLL_SHIFT) |
+                        (1 << OMAP3430_AUTO_CORE_DPLL_SHIFT),
+                        PLL_MOD,
+                        CM_AUTOIDLE);
+       cm_write_mod_reg(1 << OMAP3430ES2_AUTO_PERIPH2_DPLL_SHIFT,
+                        PLL_MOD,
+                        CM_AUTOIDLE2);
+
+       /*
+        * Enable control of expternal oscillator through
+        * sys_clkreq. In the long run clock framework should
+        * take care of this.
+        */
+       prm_rmw_mod_reg_bits(OMAP_AUTOEXTCLKMODE_MASK,
+                            1 << OMAP_AUTOEXTCLKMODE_SHIFT,
+                            OMAP3430_GR_MOD,
+                            OMAP3_PRM_CLKSRC_CTRL_OFFSET);
+
+       /* setup wakup source */
+       prm_write_mod_reg(OMAP3430_EN_IO | OMAP3430_EN_GPIO1 |
+                         OMAP3430_EN_GPT1 | OMAP3430_EN_GPT12,
+                         WKUP_MOD, PM_WKEN);
+       /* No need to write EN_IO, that is always enabled */
+       prm_write_mod_reg(OMAP3430_EN_GPIO1 | OMAP3430_EN_GPT1 |
+                         OMAP3430_EN_GPT12,
+                         WKUP_MOD, OMAP3430_PM_MPUGRPSEL);
+       /* For some reason IO doesn't generate wakeup event even if
+        * it is selected to mpu wakeup goup */
+       prm_write_mod_reg(OMAP3430_IO_EN | OMAP3430_WKUP_EN,
+                         OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET);
+
+       /* Don't attach IVA interrupts */
+       prm_write_mod_reg(0, WKUP_MOD, OMAP3430_PM_IVAGRPSEL);
+       prm_write_mod_reg(0, CORE_MOD, OMAP3430_PM_IVAGRPSEL1);
+       prm_write_mod_reg(0, CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3);
+       prm_write_mod_reg(0, OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL);
+
+       /* Clear any pending 'reset' flags */
+       prm_write_mod_reg(0xffffffff, MPU_MOD, RM_RSTST);
+       prm_write_mod_reg(0xffffffff, CORE_MOD, RM_RSTST);
+       prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, RM_RSTST);
+       prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, RM_RSTST);
+       prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, RM_RSTST);
+       prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, RM_RSTST);
+       prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, RM_RSTST);
+
+       /* Clear any pending PRCM interrupts */
+       prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
+
+       omap3_iva_idle();
+       omap3_d2d_idle();
+}
+
+static int __init pwrdms_setup(struct powerdomain *pwrdm)
+{
+       struct power_state *pwrst;
+
+       if (!pwrdm->pwrsts)
+               return 0;
+
+       pwrst = kmalloc(sizeof(struct power_state), GFP_KERNEL);
+       if (!pwrst)
+               return -ENOMEM;
+       pwrst->pwrdm = pwrdm;
+       pwrst->next_state = PWRDM_POWER_RET;
+       list_add(&pwrst->node, &pwrst_list);
+
+       if (pwrdm_has_hdwr_sar(pwrdm))
+               pwrdm_enable_hdwr_sar(pwrdm);
+
+       return set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
+}
+
+/*
+ * Enable hw supervised mode for all clockdomains if it's
+ * supported. Initiate sleep transition for other clockdomains, if
+ * they are not used
+ */
+static int __init clkdms_setup(struct clockdomain *clkdm)
+{
+       if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
+               omap2_clkdm_allow_idle(clkdm);
+       else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
+                atomic_read(&clkdm->usecount) == 0)
+               omap2_clkdm_sleep(clkdm);
+       return 0;
+}
+
+int __init omap3_pm_init(void)
+{
+       struct power_state *pwrst, *tmp;
+       int ret;
+
+       if (!cpu_is_omap34xx())
+               return -ENODEV;
+
+       printk(KERN_ERR "Power Management for TI OMAP3.\n");
+
+       /* XXX prcm_setup_regs needs to be before enabling hw
+        * supervised mode for powerdomains */
+       prcm_setup_regs();
+
+       ret = request_irq(INT_34XX_PRCM_MPU_IRQ,
+                         (irq_handler_t)prcm_interrupt_handler,
+                         IRQF_DISABLED, "prcm", NULL);
+       if (ret) {
+               printk(KERN_ERR "request_irq failed to register for 0x%x\n",
+                      INT_34XX_PRCM_MPU_IRQ);
+               goto err1;
+       }
+
+       ret = pwrdm_for_each(pwrdms_setup);
+       if (ret) {
+               printk(KERN_ERR "Failed to setup powerdomains\n");
+               goto err2;
+       }
+
+       (void) clkdm_for_each(clkdms_setup);
+
+       mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
+       if (mpu_pwrdm == NULL) {
+               printk(KERN_ERR "Failed to get mpu_pwrdm\n");
+               goto err2;
+       }
+
+       _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend,
+                                        omap34xx_cpu_suspend_sz);
+
+       suspend_set_ops(&omap_pm_ops);
+
+       pm_idle = omap3_pm_idle;
+
+err1:
+       return ret;
+err2:
+       free_irq(INT_34XX_PRCM_MPU_IRQ, NULL);
+       list_for_each_entry_safe(pwrst, tmp, &pwrst_list, node) {
+               list_del(&pwrst->node);
+               kfree(pwrst);
+       }
+       return ret;
+}
+
+late_initcall(omap3_pm_init);
index 812d50ee495d5d3201d718373612a593ecc1fdcf..cb1ae84e0925a597a31bb6385c82d686a887bff3 100644 (file)
 /* CM_FCLKEN_WKUP, CM_ICLKEN_WKUP, PM_WKEN_WKUP shared bits */
 #define OMAP3430_EN_GPIO1                              (1 << 3)
 #define OMAP3430_EN_GPIO1_SHIFT                                3
+#define OMAP3430_EN_GPT12                              (1 << 1)
+#define OMAP3430_EN_GPT12_SHIFT                                1
 #define OMAP3430_EN_GPT1                               (1 << 0)
 #define OMAP3430_EN_GPT1_SHIFT                         0
 
index 826d326b8062d2e2177f0fbfdb3c72e25a88c324..9937e2814696899f4d3f9928c79fcbaeec88682c 100644 (file)
 
 #include "prcm-common.h"
 
-#ifndef __ASSEMBLER__
-#define OMAP_PRM_REGADDR(module, reg)                                  \
-                       IO_ADDRESS(OMAP2_PRM_BASE + (module) + (reg))
-#else
 #define OMAP2420_PRM_REGADDR(module, reg)                              \
                        IO_ADDRESS(OMAP2420_PRM_BASE + (module) + (reg))
 #define OMAP2430_PRM_REGADDR(module, reg)                              \
                        IO_ADDRESS(OMAP2430_PRM_BASE + (module) + (reg))
 #define OMAP34XX_PRM_REGADDR(module, reg)                              \
                        IO_ADDRESS(OMAP3430_PRM_BASE + (module) + (reg))
-#endif
 
 /*
  * Architecture-specific global PRM registers
  *
  */
 
-/* Global 24xx registers in GR_MOD (Same as OCP_MOD for 24xx) */
-#define OMAP24XX_PRCM_VOLTCTRL_OFFSET          0x0050
-#define OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET       0x0080
-
-/* 242x GR_MOD registers, use these only for assembly code */
-#define OMAP242X_PRCM_VOLTCTRL         OMAP2420_PRM_REGADDR(OMAP24XX_GR_MOD,   \
-                                               OMAP24XX_PRCM_VOLTCTRL_OFFSET)
-#define OMAP242X_PRCM_CLKCFG_CTRL      OMAP2420_PRM_REGADDR(OMAP24XX_GR_MOD,   \
-                                               OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET)
-
-/* 243x GR_MOD registers, use these only for assembly code */
-#define OMAP243X_PRCM_VOLTCTRL         OMAP2430_PRM_REGADDR(OMAP24XX_GR_MOD,   \
-                                               OMAP24XX_PRCM_VOLTCTRL_OFFSET)
-#define OMAP243X_PRCM_CLKCFG_CTRL      OMAP2430_PRM_REGADDR(OMAP24XX_GR_MOD,   \
-                                               OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET)
-
-/* These will disappear */
-#define OMAP24XX_PRCM_REVISION         OMAP_PRM_REGADDR(OCP_MOD, 0x0000)
-#define OMAP24XX_PRCM_SYSCONFIG                OMAP_PRM_REGADDR(OCP_MOD, 0x0010)
-
-#define OMAP24XX_PRCM_IRQSTATUS_MPU    OMAP_PRM_REGADDR(OCP_MOD, 0x0018)
-#define OMAP24XX_PRCM_IRQENABLE_MPU    OMAP_PRM_REGADDR(OCP_MOD, 0x001c)
-
-#define OMAP24XX_PRCM_VOLTST           OMAP_PRM_REGADDR(OCP_MOD, 0x0054)
-#define OMAP24XX_PRCM_CLKSRC_CTRL      OMAP_PRM_REGADDR(OCP_MOD, 0x0060)
-#define OMAP24XX_PRCM_CLKOUT_CTRL      OMAP_PRM_REGADDR(OCP_MOD, 0x0070)
-#define OMAP24XX_PRCM_CLKEMUL_CTRL     OMAP_PRM_REGADDR(OCP_MOD, 0x0078)
-#define OMAP24XX_PRCM_CLKCFG_CTRL      OMAP_PRM_REGADDR(OCP_MOD, 0x0080)
-#define OMAP24XX_PRCM_CLKCFG_STATUS    OMAP_PRM_REGADDR(OCP_MOD, 0x0084)
-#define OMAP24XX_PRCM_VOLTSETUP                OMAP_PRM_REGADDR(OCP_MOD, 0x0090)
-#define OMAP24XX_PRCM_CLKSSETUP                OMAP_PRM_REGADDR(OCP_MOD, 0x0094)
-#define OMAP24XX_PRCM_POLCTRL          OMAP_PRM_REGADDR(OCP_MOD, 0x0098)
-
-#define OMAP3430_PRM_REVISION          OMAP_PRM_REGADDR(OCP_MOD, 0x0004)
-#define OMAP3430_PRM_SYSCONFIG         OMAP_PRM_REGADDR(OCP_MOD, 0x0014)
-
-#define OMAP3430_PRM_IRQSTATUS_MPU     OMAP_PRM_REGADDR(OCP_MOD, 0x0018)
-#define OMAP3430_PRM_IRQENABLE_MPU     OMAP_PRM_REGADDR(OCP_MOD, 0x001c)
-
-
-#define OMAP3430_PRM_VC_SMPS_SA                OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0020)
-#define OMAP3430_PRM_VC_SMPS_VOL_RA    OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0024)
-#define OMAP3430_PRM_VC_SMPS_CMD_RA    OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0028)
-#define OMAP3430_PRM_VC_CMD_VAL_0      OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x002c)
-#define OMAP3430_PRM_VC_CMD_VAL_1      OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0030)
-#define OMAP3430_PRM_VC_CH_CONF                OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0034)
-#define OMAP3430_PRM_VC_I2C_CFG                OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0038)
-#define OMAP3430_PRM_VC_BYPASS_VAL     OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x003c)
-#define OMAP3430_PRM_RSTCTRL           OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0050)
-#define OMAP3430_PRM_RSTTIME           OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0054)
-#define OMAP3430_PRM_RSTST             OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0058)
-#define OMAP3430_PRM_VOLTCTRL          OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0060)
-#define OMAP3430_PRM_SRAM_PCHARGE      OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0064)
-#define OMAP3430_PRM_CLKSRC_CTRL       OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0070)
-#define OMAP3430_PRM_VOLTSETUP1                OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0090)
-#define OMAP3430_PRM_VOLTOFFSET                OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0094)
-#define OMAP3430_PRM_CLKSETUP          OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0098)
-#define OMAP3430_PRM_POLCTRL           OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x009c)
-#define OMAP3430_PRM_VOLTSETUP2                OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00a0)
-#define OMAP3430_PRM_VP1_CONFIG                OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b0)
-#define OMAP3430_PRM_VP1_VSTEPMIN      OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b4)
-#define OMAP3430_PRM_VP1_VSTEPMAX      OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b8)
-#define OMAP3430_PRM_VP1_VLIMITTO      OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00bc)
-#define OMAP3430_PRM_VP1_VOLTAGE       OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00c0)
-#define OMAP3430_PRM_VP1_STATUS                OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00c4)
-#define OMAP3430_PRM_VP2_CONFIG                OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d0)
-#define OMAP3430_PRM_VP2_VSTEPMIN      OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d4)
-#define OMAP3430_PRM_VP2_VSTEPMAX      OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d8)
-#define OMAP3430_PRM_VP2_VLIMITTO      OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00dc)
-#define OMAP3430_PRM_VP2_VOLTAGE       OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00e0)
-#define OMAP3430_PRM_VP2_STATUS                OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00e4)
-
-#define OMAP3430_PRM_CLKSEL            OMAP_PRM_REGADDR(OMAP3430_CCR_MOD, 0x0040)
-#define OMAP3430_PRM_CLKOUT_CTRL       OMAP_PRM_REGADDR(OMAP3430_CCR_MOD, 0x0070)
+#define OMAP2_PRCM_REVISION_OFFSET     0x0000
+#define OMAP2420_PRCM_REVISION         OMAP2420_PRM_REGADDR(OCP_MOD, 0x0000)
+#define OMAP2_PRCM_SYSCONFIG_OFFSET    0x0010
+#define OMAP2420_PRCM_SYSCONFIG                OMAP2420_PRM_REGADDR(OCP_MOD, 0x0010)
+
+#define OMAP2_PRCM_IRQSTATUS_MPU_OFFSET        0x0018
+#define OMAP2420_PRCM_IRQSTATUS_MPU    OMAP2420_PRM_REGADDR(OCP_MOD, 0x0018)
+#define OMAP2_PRCM_IRQENABLE_MPU_OFFSET        0x001c
+#define OMAP2420_PRCM_IRQENABLE_MPU    OMAP2420_PRM_REGADDR(OCP_MOD, 0x001c)
+
+#define OMAP2_PRCM_VOLTCTRL_OFFSET     0x0050
+#define OMAP2420_PRCM_VOLTCTRL         OMAP2420_PRM_REGADDR(OCP_MOD, 0x0050)
+#define OMAP2_PRCM_VOLTST_OFFSET       0x0054
+#define OMAP2420_PRCM_VOLTST           OMAP2420_PRM_REGADDR(OCP_MOD, 0x0054)
+#define OMAP2_PRCM_CLKSRC_CTRL_OFFSET  0x0060
+#define OMAP2420_PRCM_CLKSRC_CTRL      OMAP2420_PRM_REGADDR(OCP_MOD, 0x0060)
+#define OMAP2_PRCM_CLKOUT_CTRL_OFFSET  0x0070
+#define OMAP2420_PRCM_CLKOUT_CTRL      OMAP2420_PRM_REGADDR(OCP_MOD, 0x0070)
+#define OMAP2_PRCM_CLKEMUL_CTRL_OFFSET 0x0078
+#define OMAP2420_PRCM_CLKEMUL_CTRL     OMAP2420_PRM_REGADDR(OCP_MOD, 0x0078)
+#define OMAP2_PRCM_CLKCFG_CTRL_OFFSET  0x0080
+#define OMAP2420_PRCM_CLKCFG_CTRL      OMAP2420_PRM_REGADDR(OCP_MOD, 0x0080)
+#define OMAP2_PRCM_CLKCFG_STATUS_OFFSET        0x0084
+#define OMAP2420_PRCM_CLKCFG_STATUS    OMAP2420_PRM_REGADDR(OCP_MOD, 0x0084)
+#define OMAP2_PRCM_VOLTSETUP_OFFSET    0x0090
+#define OMAP2420_PRCM_VOLTSETUP                OMAP2420_PRM_REGADDR(OCP_MOD, 0x0090)
+#define OMAP2_PRCM_CLKSSETUP_OFFSET    0x0094
+#define OMAP2420_PRCM_CLKSSETUP                OMAP2420_PRM_REGADDR(OCP_MOD, 0x0094)
+#define OMAP2_PRCM_POLCTRL_OFFSET      0x0098
+#define OMAP2420_PRCM_POLCTRL          OMAP2420_PRM_REGADDR(OCP_MOD, 0x0098)
+
+#define OMAP2430_PRCM_REVISION         OMAP2430_PRM_REGADDR(OCP_MOD, 0x0000)
+#define OMAP2430_PRCM_SYSCONFIG                OMAP2430_PRM_REGADDR(OCP_MOD, 0x0010)
+
+#define OMAP2430_PRCM_IRQSTATUS_MPU    OMAP2430_PRM_REGADDR(OCP_MOD, 0x0018)
+#define OMAP2430_PRCM_IRQENABLE_MPU    OMAP2430_PRM_REGADDR(OCP_MOD, 0x001c)
+
+#define OMAP2430_PRCM_VOLTCTRL         OMAP2430_PRM_REGADDR(OCP_MOD, 0x0050)
+#define OMAP2430_PRCM_VOLTST           OMAP2430_PRM_REGADDR(OCP_MOD, 0x0054)
+#define OMAP2430_PRCM_CLKSRC_CTRL      OMAP2430_PRM_REGADDR(OCP_MOD, 0x0060)
+#define OMAP2430_PRCM_CLKOUT_CTRL      OMAP2430_PRM_REGADDR(OCP_MOD, 0x0070)
+#define OMAP2430_PRCM_CLKEMUL_CTRL     OMAP2430_PRM_REGADDR(OCP_MOD, 0x0078)
+#define OMAP2430_PRCM_CLKCFG_CTRL      OMAP2430_PRM_REGADDR(OCP_MOD, 0x0080)
+#define OMAP2430_PRCM_CLKCFG_STATUS    OMAP2430_PRM_REGADDR(OCP_MOD, 0x0084)
+#define OMAP2430_PRCM_VOLTSETUP                OMAP2430_PRM_REGADDR(OCP_MOD, 0x0090)
+#define OMAP2430_PRCM_CLKSSETUP                OMAP2430_PRM_REGADDR(OCP_MOD, 0x0094)
+#define OMAP2430_PRCM_POLCTRL          OMAP2430_PRM_REGADDR(OCP_MOD, 0x0098)
+
+#define OMAP3_PRM_REVISION_OFFSET      0x0004
+#define OMAP3430_PRM_REVISION          OMAP34XX_PRM_REGADDR(OCP_MOD, 0x0004)
+#define OMAP3_PRM_SYSCONFIG_OFFSET     0x0014
+#define OMAP3430_PRM_SYSCONFIG         OMAP34XX_PRM_REGADDR(OCP_MOD, 0x0014)
+
+#define OMAP3_PRM_IRQSTATUS_MPU_OFFSET 0x0018
+#define OMAP3430_PRM_IRQSTATUS_MPU     OMAP34XX_PRM_REGADDR(OCP_MOD, 0x0018)
+#define OMAP3_PRM_IRQENABLE_MPU_OFFSET 0x001c
+#define OMAP3430_PRM_IRQENABLE_MPU     OMAP34XX_PRM_REGADDR(OCP_MOD, 0x001c)
+
+
+#define OMAP3_PRM_VC_SMPS_SA_OFFSET    0x0020
+#define OMAP3430_PRM_VC_SMPS_SA                OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0020)
+#define OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET        0x0024
+#define OMAP3430_PRM_VC_SMPS_VOL_RA    OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0024)
+#define OMAP3_PRM_VC_SMPS_CMD_RA_OFFSET        0x0028
+#define OMAP3430_PRM_VC_SMPS_CMD_RA    OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0028)
+#define OMAP3_PRM_VC_CMD_VAL_0_OFFSET  0x002c
+#define OMAP3430_PRM_VC_CMD_VAL_0      OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x002c)
+#define OMAP3_PRM_VC_CMD_VAL_1_OFFSET  0x0030
+#define OMAP3430_PRM_VC_CMD_VAL_1      OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0030)
+#define OMAP3_PRM_VC_CH_CONF_OFFSET    0x0034
+#define OMAP3430_PRM_VC_CH_CONF                OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0034)
+#define OMAP3_PRM_VC_I2C_CFG_OFFSET    0x0038
+#define OMAP3430_PRM_VC_I2C_CFG                OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0038)
+#define OMAP3_PRM_VC_BYPASS_VAL_OFFSET 0x003c
+#define OMAP3430_PRM_VC_BYPASS_VAL     OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x003c)
+#define OMAP3_PRM_RSTCTRL_OFFSET       0x0050
+#define OMAP3430_PRM_RSTCTRL           OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0050)
+#define OMAP3_PRM_RSTTIME_OFFSET       0x0054
+#define OMAP3430_PRM_RSTTIME           OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0054)
+#define OMAP3_PRM_RSTST_OFFSET 0x0058
+#define OMAP3430_PRM_RSTST             OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0058)
+#define OMAP3_PRM_VOLTCTRL_OFFSET      0x0060
+#define OMAP3430_PRM_VOLTCTRL          OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0060)
+#define OMAP3_PRM_SRAM_PCHARGE_OFFSET  0x0064
+#define OMAP3430_PRM_SRAM_PCHARGE      OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0064)
+#define OMAP3_PRM_CLKSRC_CTRL_OFFSET   0x0070
+#define OMAP3430_PRM_CLKSRC_CTRL       OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0070)
+#define OMAP3_PRM_VOLTSETUP1_OFFSET    0x0090
+#define OMAP3430_PRM_VOLTSETUP1                OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0090)
+#define OMAP3_PRM_VOLTOFFSET_OFFSET    0x0094
+#define OMAP3430_PRM_VOLTOFFSET                OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0094)
+#define OMAP3_PRM_CLKSETUP_OFFSET      0x0098
+#define OMAP3430_PRM_CLKSETUP          OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0098)
+#define OMAP3_PRM_POLCTRL_OFFSET       0x009c
+#define OMAP3430_PRM_POLCTRL           OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x009c)
+#define OMAP3_PRM_VOLTSETUP2_OFFSET    0x00a0
+#define OMAP3430_PRM_VOLTSETUP2                OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00a0)
+#define OMAP3_PRM_VP1_CONFIG_OFFSET    0x00b0
+#define OMAP3430_PRM_VP1_CONFIG                OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b0)
+#define OMAP3_PRM_VP1_VSTEPMIN_OFFSET  0x00b4
+#define OMAP3430_PRM_VP1_VSTEPMIN      OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b4)
+#define OMAP3_PRM_VP1_VSTEPMAX_OFFSET  0x00b8
+#define OMAP3430_PRM_VP1_VSTEPMAX      OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b8)
+#define OMAP3_PRM_VP1_VLIMITTO_OFFSET  0x00bc
+#define OMAP3430_PRM_VP1_VLIMITTO      OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00bc)
+#define OMAP3_PRM_VP1_VOLTAGE_OFFSET   0x00c0
+#define OMAP3430_PRM_VP1_VOLTAGE       OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00c0)
+#define OMAP3_PRM_VP1_STATUS_OFFSET    0x00c4
+#define OMAP3430_PRM_VP1_STATUS                OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00c4)
+#define OMAP3_PRM_VP2_CONFIG_OFFSET    0x00d0
+#define OMAP3430_PRM_VP2_CONFIG                OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d0)
+#define OMAP3_PRM_VP2_VSTEPMIN_OFFSET  0x00d4
+#define OMAP3430_PRM_VP2_VSTEPMIN      OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d4)
+#define OMAP3_PRM_VP2_VSTEPMAX_OFFSET  0x00d8
+#define OMAP3430_PRM_VP2_VSTEPMAX      OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d8)
+#define OMAP3_PRM_VP2_VLIMITTO_OFFSET  0x00dc
+#define OMAP3430_PRM_VP2_VLIMITTO      OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00dc)
+#define OMAP3_PRM_VP2_VOLTAGE_OFFSET   0x00e0
+#define OMAP3430_PRM_VP2_VOLTAGE       OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00e0)
+#define OMAP3_PRM_VP2_STATUS_OFFSET    0x00e4
+#define OMAP3430_PRM_VP2_STATUS                OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00e4)
+
+#define OMAP3_PRM_CLKSEL_OFFSET        0x0040
+#define OMAP3430_PRM_CLKSEL            OMAP34XX_PRM_REGADDR(OMAP3430_CCR_MOD, 0x0040)
+#define OMAP3_PRM_CLKOUT_CTRL_OFFSET   0x0070
+#define OMAP3430_PRM_CLKOUT_CTRL       OMAP34XX_PRM_REGADDR(OMAP3430_CCR_MOD, 0x0070)
 
 /*
  * Module specific PRM registers from PRM_BASE + domain offset
 
 #define OMAP3430_PM_MPUGRPSEL                          0x00a4
 #define OMAP3430_PM_MPUGRPSEL1                         OMAP3430_PM_MPUGRPSEL
+#define OMAP3430ES2_PM_MPUGRPSEL3                      0x00f8
 
 #define OMAP3430_PM_IVAGRPSEL                          0x00a8
 #define OMAP3430_PM_IVAGRPSEL1                         OMAP3430_PM_IVAGRPSEL
+#define OMAP3430ES2_PM_IVAGRPSEL3                      0x00f4
 
 #define OMAP3430_PM_PREPWSTST                          0x00e8
 
diff --git a/arch/arm/mach-omap2/sdram-micron-mt46h32m32lf-6.h b/arch/arm/mach-omap2/sdram-micron-mt46h32m32lf-6.h
new file mode 100644 (file)
index 0000000..02e1c2d
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * SDRC register values for the Micron MT46H32M32LF-6
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Paul Walmsley
+ *
+ * This 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_MICRON_MT46H32M32LF
+#define ARCH_ARM_MACH_OMAP2_SDRAM_MICRON_MT46H32M32LF
+
+#include <mach/sdrc.h>
+
+/* Micron MT46H32M32LF-6 */
+/* XXX Using ARE = 0x1 (no autorefresh burst) -- can this be changed? */
+static struct omap_sdrc_params mt46h32m32lf6_sdrc_params[] = {
+       [0] = {
+               .rate        = 166000000,
+               .actim_ctrla = 0x9a9db4c6,
+               .actim_ctrlb = 0x00011217,
+               .rfr_ctrl    = 0x0004dc01,
+               .mr          = 0x00000032,
+       },
+       [1] = {
+               .rate        = 165941176,
+               .actim_ctrla = 0x9a9db4c6,
+               .actim_ctrlb = 0x00011217,
+               .rfr_ctrl    = 0x0004dc01,
+               .mr          = 0x00000032,
+       },
+       [2] = {
+               .rate        = 83000000,
+               .actim_ctrla = 0x51512283,
+               .actim_ctrlb = 0x0001120c,
+               .rfr_ctrl    = 0x00025501,
+               .mr          = 0x00000032,
+       },
+       [3] = {
+               .rate        = 82970588,
+               .actim_ctrla = 0x51512283,
+               .actim_ctrlb = 0x0001120c,
+               .rfr_ctrl    = 0x00025501,
+               .mr          = 0x00000032,
+       },
+       [4] = {
+               .rate        = 0
+       },
+};
+
+#endif
diff --git a/arch/arm/mach-omap2/sdram-qimonda-hyb18m512160af-6.h b/arch/arm/mach-omap2/sdram-qimonda-hyb18m512160af-6.h
new file mode 100644 (file)
index 0000000..3751d29
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * SDRC register values for the Qimonda HYB18M512160AF-6
+ *
+ * Copyright (C) 2008-2009 Texas Instruments, Inc.
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Paul Walmsley
+ *
+ * This 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_QIMONDA_HYB18M512160AF6
+#define ARCH_ARM_MACH_OMAP2_SDRAM_QIMONDA_HYB18M512160AF6
+
+#include <mach/sdrc.h>
+
+/* Qimonda HYB18M512160AF-6 */
+static struct omap_sdrc_params hyb18m512160af6_sdrc_params[] = {
+       [0] = {
+               .rate        = 166000000,
+               .actim_ctrla = 0x629db4c6,
+               .actim_ctrlb = 0x00012214,
+               .rfr_ctrl    = 0x0004dc01,
+               .mr          = 0x00000032,
+       },
+       [1] = {
+               .rate        = 165941176,
+               .actim_ctrla = 0x629db4c6,
+               .actim_ctrlb = 0x00012214,
+               .rfr_ctrl    = 0x0004dc01,
+               .mr          = 0x00000032,
+       },
+       [2] = {
+               .rate        = 83000000,
+               .actim_ctrla = 0x31512283,
+               .actim_ctrlb = 0x0001220a,
+               .rfr_ctrl    = 0x00025501,
+               .mr          = 0x00000022,
+       },
+       [3] = {
+               .rate        = 82970588,
+               .actim_ctrla = 0x31512283,
+               .actim_ctrlb = 0x0001220a,
+               .rfr_ctrl    = 0x00025501,
+               .mr          = 0x00000022,
+       },
+       [4] = {
+               .rate        = 0
+       },
+};
+
+#endif
index 2a30060cb4b78ec897bb668b31c665c26c160827..2045441e8385987967eb02b7f6045c503dc94b1d 100644 (file)
@@ -37,6 +37,10 @@ static struct omap_sdrc_params *sdrc_init_params;
 void __iomem *omap2_sdrc_base;
 void __iomem *omap2_sms_base;
 
+/* SDRC_POWER register bits */
+#define SDRC_POWER_EXTCLKDIS_SHIFT             3
+#define SDRC_POWER_PWDENA_SHIFT                        2
+#define SDRC_POWER_PAGEPOLICY_SHIFT            0
 
 /**
  * omap2_sdrc_get_params - return SDRC register values for a given clock rate
@@ -56,9 +60,12 @@ struct omap_sdrc_params *omap2_sdrc_get_params(unsigned long r)
 {
        struct omap_sdrc_params *sp;
 
+       if (!sdrc_init_params)
+               return NULL;
+
        sp = sdrc_init_params;
 
-       while (sp->rate != r)
+       while (sp->rate && sp->rate != r)
                sp++;
 
        if (!sp->rate)
@@ -74,7 +81,14 @@ void __init omap2_set_globals_sdrc(struct omap_globals *omap2_globals)
        omap2_sms_base = omap2_globals->sms;
 }
 
-/* turn on smart idle modes for SDRAM scheduler and controller */
+/**
+ * omap2_sdrc_init - initialize SMS, SDRC devices on boot
+ * @sp: pointer to a null-terminated list of struct omap_sdrc_params
+ *
+ * Turn on smart idle modes for SDRAM scheduler and controller.
+ * Program a known-good configuration for the SDRC to deal with buggy
+ * bootloaders.
+ */
 void __init omap2_sdrc_init(struct omap_sdrc_params *sp)
 {
        u32 l;
@@ -90,4 +104,10 @@ void __init omap2_sdrc_init(struct omap_sdrc_params *sp)
        sdrc_write_reg(l, SDRC_SYSCONFIG);
 
        sdrc_init_params = sp;
+
+       /* XXX Enable SRFRONIDLEREQ here also? */
+       l = (1 << SDRC_POWER_EXTCLKDIS_SHIFT) |
+               (1 << SDRC_POWER_PWDENA_SHIFT) |
+               (1 << SDRC_POWER_PAGEPOLICY_SHIFT);
+       sdrc_write_reg(l, SDRC_POWER);
 }
index 0afdad5ae9fb3c689f2365aa1ce90297031873eb..feaec7eaf6bd9fd204f443053a3eb3360701d413 100644 (file)
@@ -99,7 +99,10 @@ u32 omap2xxx_sdrc_reprogram(u32 level, u32 force)
        m_type = omap2xxx_sdrc_get_type();
 
        local_irq_save(flags);
-       __raw_writel(0xffff, OMAP24XX_PRCM_VOLTSETUP);
+       if (cpu_is_omap2420())
+               __raw_writel(0xffff, OMAP2420_PRCM_VOLTSETUP);
+       else
+               __raw_writel(0xffff, OMAP2430_PRCM_VOLTSETUP);
        omap2_sram_reprogram_sdrc(level, dll_ctrl, m_type);
        curr_perf_level = level;
        local_irq_restore(flags);
index 4dcf39c285b94bac5e1e6292469299c633fcd0bf..b094c15bfe471d6ccc47073d891bd4459b432c1a 100644 (file)
@@ -6,8 +6,13 @@
  * Copyright (C) 2005-2008 Nokia Corporation
  * Author: Paul Mundt <paul.mundt@nokia.com>
  *
+ * Major rework for PM support by Kevin Hilman
+ *
  * Based off of arch/arm/mach-omap/omap1/serial.c
  *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com
+ *
  * This file is subject to the terms and conditions of the GNU General Public
  * License. See the file "COPYING" in the main directory of this archive
  * for more details.
 
 #include <mach/common.h>
 #include <mach/board.h>
+#include <mach/clock.h>
+#include <mach/control.h>
+
+#include "prm.h"
+#include "pm.h"
+#include "prm-regbits-34xx.h"
+
+#define UART_OMAP_WER          0x17    /* Wake-up enable register */
+
+#define DEFAULT_TIMEOUT (5 * HZ)
 
-static struct clk *uart_ick[OMAP_MAX_NR_PORTS];
-static struct clk *uart_fck[OMAP_MAX_NR_PORTS];
+struct omap_uart_state {
+       int num;
+       int can_sleep;
+       struct timer_list timer;
+       u32 timeout;
+
+       void __iomem *wk_st;
+       void __iomem *wk_en;
+       u32 wk_mask;
+       u32 padconf;
+
+       struct clk *ick;
+       struct clk *fck;
+       int clocked;
+
+       struct plat_serial8250_port *p;
+       struct list_head node;
+
+#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
+       int context_valid;
+
+       /* Registers to be saved/restored for OFF-mode */
+       u16 dll;
+       u16 dlh;
+       u16 ier;
+       u16 sysc;
+       u16 scr;
+       u16 wer;
+#endif
+};
+
+static struct omap_uart_state omap_uart[OMAP_MAX_NR_PORTS];
+static LIST_HEAD(uart_list);
 
 static struct plat_serial8250_port serial_platform_data[] = {
        {
@@ -74,33 +120,369 @@ static inline void serial_write_reg(struct plat_serial8250_port *p, int offset,
  * properly. Note that the TX watermark initialization may not be needed
  * once the 8250.c watermark handling code is merged.
  */
-static inline void __init omap_serial_reset(struct plat_serial8250_port *p)
+static inline void __init omap_uart_reset(struct omap_uart_state *uart)
 {
+       struct plat_serial8250_port *p = uart->p;
+
        serial_write_reg(p, UART_OMAP_MDR1, 0x07);
        serial_write_reg(p, UART_OMAP_SCR, 0x08);
        serial_write_reg(p, UART_OMAP_MDR1, 0x00);
        serial_write_reg(p, UART_OMAP_SYSC, (0x02 << 3) | (1 << 2) | (1 << 0));
 }
 
-void omap_serial_enable_clocks(int enable)
+#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)
 {
-       int i;
-       for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
-               if (uart_ick[i] && uart_fck[i]) {
-                       if (enable) {
-                               clk_enable(uart_ick[i]);
-                               clk_enable(uart_fck[i]);
-                       } else {
-                               clk_disable(uart_ick[i]);
-                               clk_disable(uart_fck[i]);
+       u16 lcr = 0;
+       struct plat_serial8250_port *p = uart->p;
+
+       if (!enable_off_mode)
+               return;
+
+       lcr = serial_read_reg(p, UART_LCR);
+       serial_write_reg(p, UART_LCR, 0xBF);
+       uart->dll = serial_read_reg(p, UART_DLL);
+       uart->dlh = serial_read_reg(p, UART_DLM);
+       serial_write_reg(p, UART_LCR, lcr);
+       uart->ier = serial_read_reg(p, UART_IER);
+       uart->sysc = serial_read_reg(p, UART_OMAP_SYSC);
+       uart->scr = serial_read_reg(p, UART_OMAP_SCR);
+       uart->wer = serial_read_reg(p, UART_OMAP_WER);
+
+       uart->context_valid = 1;
+}
+
+static void omap_uart_restore_context(struct omap_uart_state *uart)
+{
+       u16 efr = 0;
+       struct plat_serial8250_port *p = uart->p;
+
+       if (!enable_off_mode)
+               return;
+
+       if (!uart->context_valid)
+               return;
+
+       uart->context_valid = 0;
+
+       serial_write_reg(p, UART_OMAP_MDR1, 0x7);
+       serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
+       efr = serial_read_reg(p, UART_EFR);
+       serial_write_reg(p, UART_EFR, UART_EFR_ECB);
+       serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */
+       serial_write_reg(p, UART_IER, 0x0);
+       serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
+       serial_write_reg(p, UART_DLL, uart->dll);
+       serial_write_reg(p, UART_DLM, uart->dlh);
+       serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */
+       serial_write_reg(p, UART_IER, uart->ier);
+       serial_write_reg(p, UART_FCR, 0xA1);
+       serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
+       serial_write_reg(p, UART_EFR, efr);
+       serial_write_reg(p, UART_LCR, UART_LCR_WLEN8);
+       serial_write_reg(p, UART_OMAP_SCR, uart->scr);
+       serial_write_reg(p, UART_OMAP_WER, uart->wer);
+       serial_write_reg(p, UART_OMAP_SYSC, uart->sysc);
+       serial_write_reg(p, UART_OMAP_MDR1, 0x00); /* UART 16x mode */
+}
+#else
+static inline void omap_uart_save_context(struct omap_uart_state *uart) {}
+static inline void omap_uart_restore_context(struct omap_uart_state *uart) {}
+#endif /* CONFIG_PM && CONFIG_ARCH_OMAP3 */
+
+static inline void omap_uart_enable_clocks(struct omap_uart_state *uart)
+{
+       if (uart->clocked)
+               return;
+
+       clk_enable(uart->ick);
+       clk_enable(uart->fck);
+       uart->clocked = 1;
+       omap_uart_restore_context(uart);
+}
+
+#ifdef CONFIG_PM
+
+static inline void omap_uart_disable_clocks(struct omap_uart_state *uart)
+{
+       if (!uart->clocked)
+               return;
+
+       omap_uart_save_context(uart);
+       uart->clocked = 0;
+       clk_disable(uart->ick);
+       clk_disable(uart->fck);
+}
+
+static void omap_uart_smart_idle_enable(struct omap_uart_state *uart,
+                                         int enable)
+{
+       struct plat_serial8250_port *p = uart->p;
+       u16 sysc;
+
+       sysc = serial_read_reg(p, UART_OMAP_SYSC) & 0x7;
+       if (enable)
+               sysc |= 0x2 << 3;
+       else
+               sysc |= 0x1 << 3;
+
+       serial_write_reg(p, UART_OMAP_SYSC, sysc);
+}
+
+static void omap_uart_block_sleep(struct omap_uart_state *uart)
+{
+       omap_uart_enable_clocks(uart);
+
+       omap_uart_smart_idle_enable(uart, 0);
+       uart->can_sleep = 0;
+       if (uart->timeout)
+               mod_timer(&uart->timer, jiffies + uart->timeout);
+       else
+               del_timer(&uart->timer);
+}
+
+static void omap_uart_allow_sleep(struct omap_uart_state *uart)
+{
+       if (!uart->clocked)
+               return;
+
+       omap_uart_smart_idle_enable(uart, 1);
+       uart->can_sleep = 1;
+       del_timer(&uart->timer);
+}
+
+static void omap_uart_idle_timer(unsigned long data)
+{
+       struct omap_uart_state *uart = (struct omap_uart_state *)data;
+
+       omap_uart_allow_sleep(uart);
+}
+
+void omap_uart_prepare_idle(int num)
+{
+       struct omap_uart_state *uart;
+
+       list_for_each_entry(uart, &uart_list, node) {
+               if (num == uart->num && uart->can_sleep) {
+                       omap_uart_disable_clocks(uart);
+                       return;
+               }
+       }
+}
+
+void omap_uart_resume_idle(int num)
+{
+       struct omap_uart_state *uart;
+
+       list_for_each_entry(uart, &uart_list, node) {
+               if (num == uart->num) {
+                       omap_uart_enable_clocks(uart);
+
+                       /* Check for IO pad wakeup */
+                       if (cpu_is_omap34xx() && uart->padconf) {
+                               u16 p = omap_ctrl_readw(uart->padconf);
+
+                               if (p & OMAP3_PADCONF_WAKEUPEVENT0)
+                                       omap_uart_block_sleep(uart);
                        }
+
+                       /* Check for normal UART wakeup */
+                       if (__raw_readl(uart->wk_st) & uart->wk_mask)
+                               omap_uart_block_sleep(uart);
+
+                       return;
                }
        }
 }
 
+void omap_uart_prepare_suspend(void)
+{
+       struct omap_uart_state *uart;
+
+       list_for_each_entry(uart, &uart_list, node) {
+               omap_uart_allow_sleep(uart);
+       }
+}
+
+int omap_uart_can_sleep(void)
+{
+       struct omap_uart_state *uart;
+       int can_sleep = 1;
+
+       list_for_each_entry(uart, &uart_list, node) {
+               if (!uart->clocked)
+                       continue;
+
+               if (!uart->can_sleep) {
+                       can_sleep = 0;
+                       continue;
+               }
+
+               /* This UART can now safely sleep. */
+               omap_uart_allow_sleep(uart);
+       }
+
+       return can_sleep;
+}
+
+/**
+ * omap_uart_interrupt()
+ *
+ * This handler is used only to detect that *any* UART interrupt has
+ * occurred.  It does _nothing_ to handle the interrupt.  Rather,
+ * any UART interrupt will trigger the inactivity timer so the
+ * UART will not idle or sleep for its timeout period.
+ *
+ **/
+static irqreturn_t omap_uart_interrupt(int irq, void *dev_id)
+{
+       struct omap_uart_state *uart = dev_id;
+
+       omap_uart_block_sleep(uart);
+
+       return IRQ_NONE;
+}
+
+static u32 sleep_timeout = DEFAULT_TIMEOUT;
+
+static void omap_uart_idle_init(struct omap_uart_state *uart)
+{
+       u32 v;
+       struct plat_serial8250_port *p = uart->p;
+       int ret;
+
+       uart->can_sleep = 0;
+       uart->timeout = sleep_timeout;
+       setup_timer(&uart->timer, omap_uart_idle_timer,
+                   (unsigned long) uart);
+       mod_timer(&uart->timer, jiffies + uart->timeout);
+       omap_uart_smart_idle_enable(uart, 0);
+
+       if (cpu_is_omap34xx()) {
+               u32 mod = (uart->num == 2) ? OMAP3430_PER_MOD : CORE_MOD;
+               u32 wk_mask = 0;
+               u32 padconf = 0;
+
+               uart->wk_en = OMAP34XX_PRM_REGADDR(mod, PM_WKEN1);
+               uart->wk_st = OMAP34XX_PRM_REGADDR(mod, PM_WKST1);
+               switch (uart->num) {
+               case 0:
+                       wk_mask = OMAP3430_ST_UART1_MASK;
+                       padconf = 0x182;
+                       break;
+               case 1:
+                       wk_mask = OMAP3430_ST_UART2_MASK;
+                       padconf = 0x17a;
+                       break;
+               case 2:
+                       wk_mask = OMAP3430_ST_UART3_MASK;
+                       padconf = 0x19e;
+                       break;
+               }
+               uart->wk_mask = wk_mask;
+               uart->padconf = padconf;
+       } else if (cpu_is_omap24xx()) {
+               u32 wk_mask = 0;
+
+               if (cpu_is_omap2430()) {
+                       uart->wk_en = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKEN1);
+                       uart->wk_st = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKST1);
+               } else if (cpu_is_omap2420()) {
+                       uart->wk_en = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKEN1);
+                       uart->wk_st = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKST1);
+               }
+               switch (uart->num) {
+               case 0:
+                       wk_mask = OMAP24XX_ST_UART1_MASK;
+                       break;
+               case 1:
+                       wk_mask = OMAP24XX_ST_UART2_MASK;
+                       break;
+               case 2:
+                       wk_mask = OMAP24XX_ST_UART3_MASK;
+                       break;
+               }
+               uart->wk_mask = wk_mask;
+       } else {
+               uart->wk_en = 0;
+               uart->wk_st = 0;
+               uart->wk_mask = 0;
+               uart->padconf = 0;
+       }
+
+       /* Set wake-enable bit */
+       if (uart->wk_en && uart->wk_mask) {
+               v = __raw_readl(uart->wk_en);
+               v |= uart->wk_mask;
+               __raw_writel(v, uart->wk_en);
+       }
+
+       /* Ensure IOPAD wake-enables are set */
+       if (cpu_is_omap34xx() && uart->padconf) {
+               u16 v;
+
+               v = omap_ctrl_readw(uart->padconf);
+               v |= OMAP3_PADCONF_WAKEUPENABLE0;
+               omap_ctrl_writew(v, uart->padconf);
+       }
+
+       p->flags |= UPF_SHARE_IRQ;
+       ret = request_irq(p->irq, omap_uart_interrupt, IRQF_SHARED,
+                         "serial idle", (void *)uart);
+       WARN_ON(ret);
+}
+
+static ssize_t sleep_timeout_show(struct kobject *kobj,
+                                 struct kobj_attribute *attr,
+                                 char *buf)
+{
+       return sprintf(buf, "%u\n", sleep_timeout / HZ);
+}
+
+static ssize_t sleep_timeout_store(struct kobject *kobj,
+                                  struct kobj_attribute *attr,
+                                  const char *buf, size_t n)
+{
+       struct omap_uart_state *uart;
+       unsigned int value;
+
+       if (sscanf(buf, "%u", &value) != 1) {
+               printk(KERN_ERR "sleep_timeout_store: Invalid value\n");
+               return -EINVAL;
+       }
+       sleep_timeout = value * HZ;
+       list_for_each_entry(uart, &uart_list, node) {
+               uart->timeout = sleep_timeout;
+               if (uart->timeout)
+                       mod_timer(&uart->timer, jiffies + uart->timeout);
+               else
+                       /* A zero value means disable timeout feature */
+                       omap_uart_block_sleep(uart);
+       }
+       return n;
+}
+
+static struct kobj_attribute sleep_timeout_attr =
+       __ATTR(sleep_timeout, 0644, sleep_timeout_show, sleep_timeout_store);
+
+#else
+static inline void omap_uart_idle_init(struct omap_uart_state *uart) {}
+#endif /* CONFIG_PM */
+
+static struct platform_device serial_device = {
+       .name                   = "serial8250",
+       .id                     = PLAT8250_DEV_PLATFORM,
+       .dev                    = {
+               .platform_data  = serial_platform_data,
+       },
+};
+
 void __init omap_serial_init(void)
 {
-       int i;
+       int i, err;
        const struct omap_uart_config *info;
        char name[16];
 
@@ -114,9 +496,14 @@ void __init omap_serial_init(void)
 
        if (info == NULL)
                return;
+       if (cpu_is_omap44xx()) {
+               for (i = 0; i < OMAP_MAX_NR_PORTS; i++)
+                       serial_platform_data[i].irq += 32;
+       }
 
        for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
                struct plat_serial8250_port *p = serial_platform_data + i;
+               struct omap_uart_state *uart = &omap_uart[i];
 
                if (!(info->enabled_uarts & (1 << i))) {
                        p->membase = NULL;
@@ -125,35 +512,39 @@ void __init omap_serial_init(void)
                }
 
                sprintf(name, "uart%d_ick", i+1);
-               uart_ick[i] = clk_get(NULL, name);
-               if (IS_ERR(uart_ick[i])) {
+               uart->ick = clk_get(NULL, name);
+               if (IS_ERR(uart->ick)) {
                        printk(KERN_ERR "Could not get uart%d_ick\n", i+1);
-                       uart_ick[i] = NULL;
-               } else
-                       clk_enable(uart_ick[i]);
+                       uart->ick = NULL;
+               }
 
                sprintf(name, "uart%d_fck", i+1);
-               uart_fck[i] = clk_get(NULL, name);
-               if (IS_ERR(uart_fck[i])) {
+               uart->fck = clk_get(NULL, name);
+               if (IS_ERR(uart->fck)) {
                        printk(KERN_ERR "Could not get uart%d_fck\n", i+1);
-                       uart_fck[i] = NULL;
-               } else
-                       clk_enable(uart_fck[i]);
+                       uart->fck = NULL;
+               }
 
-               omap_serial_reset(p);
+               if (!uart->ick || !uart->fck)
+                       continue;
+
+               uart->num = i;
+               p->private_data = uart;
+               uart->p = p;
+               list_add(&uart->node, &uart_list);
+
+               omap_uart_enable_clocks(uart);
+               omap_uart_reset(uart);
+               omap_uart_idle_init(uart);
        }
-}
 
-static struct platform_device serial_device = {
-       .name                   = "serial8250",
-       .id                     = PLAT8250_DEV_PLATFORM,
-       .dev                    = {
-               .platform_data  = serial_platform_data,
-       },
-};
+       err = platform_device_register(&serial_device);
+
+#ifdef CONFIG_PM
+       if (!err)
+               err = sysfs_create_file(&serial_device.dev.kobj,
+                                       &sleep_timeout_attr.attr);
+#endif
 
-static int __init omap_init(void)
-{
-       return platform_device_register(&serial_device);
 }
-arch_initcall(omap_init);
+
index bf9e96105e111edb4705bdc1d8d342bd05bd6b52..130aadbfa083a7a6f41db2f1ffc5c430ea7000b7 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <mach/io.h>
-#include <mach/pm.h>
 
 #include <mach/omap24xx.h>
 
diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S
new file mode 100644 (file)
index 0000000..e5e2553
--- /dev/null
@@ -0,0 +1,436 @@
+/*
+ * linux/arch/arm/mach-omap2/sleep.S
+ *
+ * (C) Copyright 2007
+ * Texas Instruments
+ * Karthik Dasu <karthik-dp@ti.com>
+ *
+ * (C) Copyright 2004
+ * Texas Instruments, <www.ti.com>
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; 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/linkage.h>
+#include <asm/assembler.h>
+#include <mach/io.h>
+#include <mach/control.h>
+
+#include "prm.h"
+#include "sdrc.h"
+
+#define PM_PREPWSTST_CORE_V    OMAP34XX_PRM_REGADDR(CORE_MOD, \
+                               OMAP3430_PM_PREPWSTST)
+#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 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 SDRC_POWER_V           OMAP34XX_SDRC_REGADDR(SDRC_POWER)
+
+       .text
+/* Function call to get the restore pointer for resume from OFF */
+ENTRY(get_restore_pointer)
+        stmfd   sp!, {lr}     @ save registers on stack
+       adr     r0, restore
+        ldmfd   sp!, {pc}     @ restore regs and return
+ENTRY(get_restore_pointer_sz)
+        .word   . - get_restore_pointer_sz
+/*
+ * Forces OMAP into idle state
+ *
+ * omap34xx_suspend() - This bit of code just executes the WFI
+ * for normal idles.
+ *
+ * Note: This code get's copied to internal SRAM at boot. When the OMAP
+ *      wakes up it continues execution at the point it went to sleep.
+ */
+ENTRY(omap34xx_cpu_suspend)
+       stmfd   sp!, {r0-r12, lr}               @ save registers on stack
+loop:
+       /*b     loop*/  @Enable to debug by stepping through code
+       /* r0 contains restore pointer in sdram */
+       /* r1 contains information about saving context */
+       ldr     r4, sdrc_power          @ read the SDRC_POWER register
+       ldr     r5, [r4]                @ read the contents of SDRC_POWER
+       orr     r5, r5, #0x40           @ enable self refresh on idle req
+       str     r5, [r4]                @ write back to SDRC_POWER register
+
+       cmp     r1, #0x0
+       /* If context save is required, do that and execute wfi */
+       bne     save_context_wfi
+       /* Data memory barrier and Data sync barrier */
+       mov     r1, #0
+       mcr     p15, 0, r1, c7, c10, 4
+       mcr     p15, 0, r1, c7, c10, 5
+
+       wfi                             @ wait for interrupt
+
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       bl i_dll_wait
+
+       ldmfd   sp!, {r0-r12, pc}               @ restore regs and return
+restore:
+       /* 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 */
+        /* 3 - Both L1 and L2 lost */
+       ldr     r1, pm_pwstctrl_mpu
+       ldr     r2, [r1]
+       and     r2, r2, #0x3
+       cmp     r2, #0x0        @ Check if target power state was OFF or RET
+        moveq   r9, #0x3        @ MPU OFF => L1 and L2 lost
+       movne   r9, #0x1        @ Only L1 and L2 lost => avoid L2 invalidation
+       bne     logic_l1_restore
+       /* Execute smi to invalidate L2 cache */
+       mov r12, #0x1                         @ set up to invalide L2
+smi:    .word 0xE1600070                @ Call SMI monitor (smieq)
+logic_l1_restore:
+       mov     r1, #0
+       /* Invalidate all instruction caches to PoU
+        * and flush branch target cache */
+       mcr     p15, 0, r1, c7, c5, 0
+
+       ldr     r4, scratchpad_base
+       ldr     r3, [r4,#0xBC]
+       ldmia   r3!, {r4-r6}
+       mov     sp, r4
+       msr     spsr_cxsf, r5
+       mov     lr, r6
+
+       ldmia   r3!, {r4-r9}
+       /* Coprocessor access Control Register */
+       mcr p15, 0, r4, c1, c0, 2
+
+       /* TTBR0 */
+       MCR p15, 0, r5, c2, c0, 0
+       /* TTBR1 */
+       MCR p15, 0, r6, c2, c0, 1
+       /* Translation table base control register */
+       MCR p15, 0, r7, c2, c0, 2
+       /*domain access Control Register */
+       MCR p15, 0, r8, c3, c0, 0
+       /* data fault status Register */
+       MCR p15, 0, r9, c5, c0, 0
+
+       ldmia  r3!,{r4-r8}
+       /* instruction fault status Register */
+       MCR p15, 0, r4, c5, c0, 1
+       /*Data Auxiliary Fault Status Register */
+       MCR p15, 0, r5, c5, c1, 0
+       /*Instruction Auxiliary Fault Status Register*/
+       MCR p15, 0, r6, c5, c1, 1
+       /*Data Fault Address Register */
+       MCR p15, 0, r7, c6, c0, 0
+       /*Instruction Fault Address Register*/
+       MCR p15, 0, r8, c6, c0, 2
+       ldmia  r3!,{r4-r7}
+
+       /* user r/w thread and process ID */
+       MCR p15, 0, r4, c13, c0, 2
+       /* user ro thread and process ID */
+       MCR p15, 0, r5, c13, c0, 3
+       /*Privileged only thread and process ID */
+       MCR p15, 0, r6, c13, c0, 4
+       /* cache size selection */
+       MCR p15, 2, r7, c0, c0, 0
+       ldmia  r3!,{r4-r8}
+       /* Data TLB lockdown registers */
+       MCR p15, 0, r4, c10, c0, 0
+       /* Instruction TLB lockdown registers */
+       MCR p15, 0, r5, c10, c0, 1
+       /* Secure or Nonsecure Vector Base Address */
+       MCR p15, 0, r6, c12, c0, 0
+       /* FCSE PID */
+       MCR p15, 0, r7, c13, c0, 0
+       /* Context PID */
+       MCR p15, 0, r8, c13, c0, 1
+
+       ldmia  r3!,{r4-r5}
+       /* primary memory remap register */
+       MCR p15, 0, r4, c10, c2, 0
+       /*normal memory remap register */
+       MCR p15, 0, r5, c10, c2, 1
+
+       /* Restore cpsr */
+       ldmia   r3!,{r4}        /*load CPSR from SDRAM*/
+       msr     cpsr, r4        /*store cpsr */
+
+       /* Enabling MMU here */
+       mrc     p15, 0, r7, c2, c0, 2 /* Read TTBRControl */
+       /* Extract N (0:2) bits and decide whether to use TTBR0 or TTBR1*/
+       and     r7, #0x7
+       cmp     r7, #0x0
+       beq     usettbr0
+ttbr_error:
+       /* More work needs to be done to support N[0:2] value other than 0
+       * So looping here so that the error can be detected
+       */
+       b       ttbr_error
+usettbr0:
+       mrc     p15, 0, r2, c2, c0, 0
+       ldr     r5, ttbrbit_mask
+       and     r2, r5
+       mov     r4, pc
+       ldr     r5, table_index_mask
+       and     r4, r5 /* r4 = 31 to 20 bits of pc */
+       /* Extract the value to be written to table entry */
+       ldr     r1, table_entry
+       add     r1, r1, r4 /* r1 has value to be written to table entry*/
+       /* Getting the address of table entry to modify */
+       lsr     r4, #18
+       add     r2, r4 /* r2 has the location which needs to be modified */
+       /* Storing previous entry of location being modified */
+       ldr     r5, scratchpad_base
+       ldr     r4, [r2]
+       str     r4, [r5, #0xC0]
+       /* Modify the table entry */
+       str     r1, [r2]
+       /* Storing address of entry being modified
+        * - will be restored after enabling MMU */
+       ldr     r5, scratchpad_base
+       str     r2, [r5, #0xC4]
+
+       mov     r0, #0
+       mcr     p15, 0, r0, c7, c5, 4   @ Flush prefetch buffer
+       mcr     p15, 0, r0, c7, c5, 6   @ Invalidate branch predictor array
+       mcr     p15, 0, r0, c8, c5, 0   @ Invalidate instruction TLB
+       mcr     p15, 0, r0, c8, c6, 0   @ Invalidate data TLB
+       /* Restore control register  but dont enable caches here*/
+       /* Caches will be enabled after restoring MMU table entry */
+       ldmia   r3!, {r4}
+       /* Store previous value of control register in scratchpad */
+       str     r4, [r5, #0xC8]
+       ldr     r2, cache_pred_disable_mask
+       and     r4, r2
+       mcr     p15, 0, r4, c1, c0, 0
+
+       ldmfd   sp!, {r0-r12, pc}               @ restore regs and return
+save_context_wfi:
+       /*b     save_context_wfi*/      @ enable to debug save code
+       mov     r8, r0 /* Store SDRAM address in r8 */
+        /* Check what that target sleep state is:stored in r1*/
+        /* 1 - Only L1 and logic lost */
+        /* 2 - Only L2 lost */
+        /* 3 - Both L1 and L2 lost */
+       cmp     r1, #0x2 /* Only L2 lost */
+       beq     clean_l2
+       cmp     r1, #0x1 /* L2 retained */
+       /* r9 stores whether to clean L2 or not*/
+       moveq   r9, #0x0 /* Dont Clean L2 */
+       movne   r9, #0x1 /* Clean L2 */
+l1_logic_lost:
+       /* Store sp and spsr to SDRAM */
+       mov     r4, sp
+       mrs     r5, spsr
+       mov     r6, lr
+       stmia   r8!, {r4-r6}
+       /* Save all ARM registers */
+       /* Coprocessor access control register */
+       mrc     p15, 0, r6, c1, c0, 2
+       stmia   r8!, {r6}
+       /* TTBR0, TTBR1 and Translation table base control */
+       mrc     p15, 0, r4, c2, c0, 0
+       mrc     p15, 0, r5, c2, c0, 1
+       mrc     p15, 0, r6, c2, c0, 2
+       stmia   r8!, {r4-r6}
+       /* Domain access control register, data fault status register,
+       and instruction fault status register */
+       mrc     p15, 0, r4, c3, c0, 0
+       mrc     p15, 0, r5, c5, c0, 0
+       mrc     p15, 0, r6, c5, c0, 1
+       stmia   r8!, {r4-r6}
+       /* Data aux fault status register, instruction aux fault status,
+       datat fault address register and instruction fault address register*/
+       mrc     p15, 0, r4, c5, c1, 0
+       mrc     p15, 0, r5, c5, c1, 1
+       mrc     p15, 0, r6, c6, c0, 0
+       mrc     p15, 0, r7, c6, c0, 2
+       stmia   r8!, {r4-r7}
+       /* user r/w thread and process ID, user r/o thread and process ID,
+       priv only thread and process ID, cache size selection */
+       mrc     p15, 0, r4, c13, c0, 2
+       mrc     p15, 0, r5, c13, c0, 3
+       mrc     p15, 0, r6, c13, c0, 4
+       mrc     p15, 2, r7, c0, c0, 0
+       stmia   r8!, {r4-r7}
+       /* Data TLB lockdown, instruction TLB lockdown registers */
+       mrc     p15, 0, r5, c10, c0, 0
+       mrc     p15, 0, r6, c10, c0, 1
+       stmia   r8!, {r5-r6}
+       /* Secure or non secure vector base address, FCSE PID, Context PID*/
+       mrc     p15, 0, r4, c12, c0, 0
+       mrc     p15, 0, r5, c13, c0, 0
+       mrc     p15, 0, r6, c13, c0, 1
+       stmia   r8!, {r4-r6}
+       /* Primary remap, normal remap registers */
+       mrc     p15, 0, r4, c10, c2, 0
+       mrc     p15, 0, r5, c10, c2, 1
+       stmia   r8!,{r4-r5}
+
+       /* Store current cpsr*/
+       mrs     r2, cpsr
+       stmia   r8!, {r2}
+
+       mrc     p15, 0, r4, c1, c0, 0
+       /* save control register */
+       stmia   r8!, {r4}
+clean_caches:
+       /* Clean Data or unified cache to POU*/
+       /* How to invalidate only L1 cache???? - #FIX_ME# */
+       /* mcr  p15, 0, r11, c7, c11, 1 */
+       cmp     r9, #1 /* Check whether L2 inval is required or not*/
+       bne     skip_l2_inval
+clean_l2:
+       /* read clidr */
+       mrc     p15, 1, r0, c0, c0, 1
+       /* extract loc from clidr */
+       ands    r3, r0, #0x7000000
+       /* left align loc bit field */
+       mov     r3, r3, lsr #23
+       /* if loc is 0, then no need to clean */
+       beq     finished
+       /* start clean at cache level 0 */
+       mov     r10, #0
+loop1:
+       /* work out 3x current cache level */
+       add     r2, r10, r10, lsr #1
+       /* extract cache type bits from clidr*/
+       mov     r1, r0, lsr r2
+       /* mask of the bits for current cache only */
+       and     r1, r1, #7
+       /* see what cache we have at this level */
+       cmp     r1, #2
+       /* skip if no cache, or just i-cache */
+       blt     skip
+       /* select current cache level in cssr */
+       mcr     p15, 2, r10, c0, c0, 0
+       /* isb to sych the new cssr&csidr */
+       isb
+       /* read the new csidr */
+       mrc     p15, 1, r1, c0, c0, 0
+       /* extract the length of the cache lines */
+       and     r2, r1, #7
+       /* add 4 (line length offset) */
+       add     r2, r2, #4
+       ldr     r4, assoc_mask
+       /* find maximum number on the way size */
+       ands    r4, r4, r1, lsr #3
+       /* find bit position of way size increment */
+       clz     r5, r4
+       ldr     r7, numset_mask
+       /* extract max number of the index size*/
+       ands    r7, r7, r1, lsr #13
+loop2:
+       mov     r9, r4
+       /* create working copy of max way size*/
+loop3:
+       /* factor way and cache number into r11 */
+       orr     r11, r10, r9, lsl r5
+       /* factor index number into r11 */
+       orr     r11, r11, r7, lsl r2
+       /*clean & invalidate by set/way */
+       mcr     p15, 0, r11, c7, c10, 2
+       /* decrement the way*/
+       subs    r9, r9, #1
+       bge     loop3
+       /*decrement the index */
+       subs    r7, r7, #1
+       bge     loop2
+skip:
+       add     r10, r10, #2
+       /* increment cache number */
+       cmp     r3, r10
+       bgt     loop1
+finished:
+       /*swith back to cache level 0 */
+       mov     r10, #0
+       /* select current cache level in cssr */
+       mcr     p15, 2, r10, c0, c0, 0
+       isb
+skip_l2_inval:
+       /* Data memory barrier and Data sync barrier */
+       mov     r1, #0
+       mcr     p15, 0, r1, c7, c10, 4
+       mcr     p15, 0, r1, c7, c10, 5
+
+       wfi                             @ wait for interrupt
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       bl i_dll_wait
+       /* restore regs and return */
+       ldmfd   sp!, {r0-r12, pc}
+
+i_dll_wait:
+       ldr     r4, clk_stabilize_delay
+
+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
+pm_prepwstst_core:
+       .word   PM_PREPWSTST_CORE_V
+pm_prepwstst_mpu:
+       .word   PM_PREPWSTST_MPU_V
+pm_pwstctrl_mpu:
+       .word   PM_PWSTCTRL_MPU_P
+scratchpad_base:
+       .word   SCRATCHPAD_BASE_P
+sdrc_power:
+       .word SDRC_POWER_V
+context_mem:
+       .word   0x803E3E14
+clk_stabilize_delay:
+       .word 0x000001FF
+assoc_mask:
+       .word   0x3ff
+numset_mask:
+       .word   0x7fff
+ttbrbit_mask:
+       .word   0xFFFFC000
+table_index_mask:
+       .word   0xFFF00000
+table_entry:
+       .word   0x00000C02
+cache_pred_disable_mask:
+       .word   0xFFFFE7FB
+ENTRY(omap34xx_cpu_suspend_sz)
+       .word   . - omap34xx_cpu_suspend
index af4bd3490227feddda1cca44702bc32eb03caf6b..bb299851116de4330229b9901ca3afe9f40291fe 100644 (file)
@@ -124,11 +124,11 @@ omap242x_sdi_cm_clksel2_pll:
 omap242x_sdi_sdrc_dlla_ctrl:
        .word OMAP242X_SDRC_REGADDR(SDRC_DLLA_CTRL)
 omap242x_sdi_prcm_voltctrl:
-       .word OMAP242X_PRCM_VOLTCTRL
+       .word OMAP2420_PRCM_VOLTCTRL
 prcm_mask_val:
        .word 0xFFFF3FFC
 omap242x_sdi_timer_32ksynct_cr:
-       .word IO_ADDRESS(OMAP2_32KSYNCT_BASE + 0x010)
+       .word IO_ADDRESS(OMAP2420_32KSYNCT_BASE + 0x010)
 ENTRY(omap242x_sram_ddr_init_sz)
        .word   . - omap242x_sram_ddr_init
 
@@ -220,11 +220,11 @@ omap242x_srs_sdrc_dlla_ctrl:
 omap242x_srs_sdrc_rfr_ctrl:
        .word OMAP242X_SDRC_REGADDR(SDRC_RFR_CTRL_0)
 omap242x_srs_prcm_voltctrl:
-       .word OMAP242X_PRCM_VOLTCTRL
+       .word OMAP2420_PRCM_VOLTCTRL
 ddr_prcm_mask_val:
        .word 0xFFFF3FFC
 omap242x_srs_timer_32ksynct:
-       .word IO_ADDRESS(OMAP2_32KSYNCT_BASE + 0x010)
+       .word IO_ADDRESS(OMAP2420_32KSYNCT_BASE + 0x010)
 
 ENTRY(omap242x_sram_reprogram_sdrc_sz)
        .word   . - omap242x_sram_reprogram_sdrc
@@ -305,7 +305,7 @@ wait_dll_lock:
        ldmfd   sp!, {r0-r12, pc}       @ restore regs and return
 
 omap242x_ssp_set_config:
-       .word OMAP242X_PRCM_CLKCFG_CTRL
+       .word OMAP2420_PRCM_CLKCFG_CTRL
 omap242x_ssp_pll_ctl:
        .word OMAP2420_CM_REGADDR(PLL_MOD, CM_CLKEN)
 omap242x_ssp_pll_stat:
index 84363e269e8cd7fca6418765786074e4db5e2967..9955abcaeb316b83bbd2549c74ffe287ac9263d0 100644 (file)
@@ -124,11 +124,11 @@ omap243x_sdi_cm_clksel2_pll:
 omap243x_sdi_sdrc_dlla_ctrl:
        .word OMAP243X_SDRC_REGADDR(SDRC_DLLA_CTRL)
 omap243x_sdi_prcm_voltctrl:
-       .word OMAP243X_PRCM_VOLTCTRL
+       .word OMAP2430_PRCM_VOLTCTRL
 prcm_mask_val:
        .word 0xFFFF3FFC
 omap243x_sdi_timer_32ksynct_cr:
-       .word IO_ADDRESS(OMAP2_32KSYNCT_BASE + 0x010)
+       .word IO_ADDRESS(OMAP2430_32KSYNCT_BASE + 0x010)
 ENTRY(omap243x_sram_ddr_init_sz)
        .word   . - omap243x_sram_ddr_init
 
@@ -220,11 +220,11 @@ omap243x_srs_sdrc_dlla_ctrl:
 omap243x_srs_sdrc_rfr_ctrl:
        .word OMAP243X_SDRC_REGADDR(SDRC_RFR_CTRL_0)
 omap243x_srs_prcm_voltctrl:
-       .word OMAP243X_PRCM_VOLTCTRL
+       .word OMAP2430_PRCM_VOLTCTRL
 ddr_prcm_mask_val:
        .word 0xFFFF3FFC
 omap243x_srs_timer_32ksynct:
-       .word IO_ADDRESS(OMAP2_32KSYNCT_BASE + 0x010)
+       .word IO_ADDRESS(OMAP2430_32KSYNCT_BASE + 0x010)
 
 ENTRY(omap243x_sram_reprogram_sdrc_sz)
        .word   . - omap243x_sram_reprogram_sdrc
@@ -305,7 +305,7 @@ wait_dll_lock:
        ldmfd   sp!, {r0-r12, pc}       @ restore regs and return
 
 omap243x_ssp_set_config:
-       .word OMAP243X_PRCM_CLKCFG_CTRL
+       .word OMAP2430_PRCM_CLKCFG_CTRL
 omap243x_ssp_pll_ctl:
        .word OMAP2430_CM_REGADDR(PLL_MOD, CM_CLKEN)
 omap243x_ssp_pll_stat:
index 2c71461363424faabef6145e559ab9d711c88709..c080c82521e187ddde80f936c6c02cb92eeb214a 100644 (file)
 /*
  * Change frequency of core dpll
  * r0 = sdrc_rfr_ctrl r1 = sdrc_actim_ctrla r2 = sdrc_actim_ctrlb r3 = M2
+ * r4 = Unlock SDRC DLL? (1 = yes, 0 = no) -- only unlock DLL for
+ *      SDRC rates < 83MHz
  */
 ENTRY(omap3_sram_configure_core_dpll)
        stmfd   sp!, {r1-r12, lr}       @ store regs to stack
+       ldr     r4, [sp, #52]           @ pull extra args off the stack
+       dsb                             @ flush buffered writes to interconnect
        cmp     r3, #0x2
        blne    configure_sdrc
-       cmp     r3, #0x2
+       cmp     r4, #0x1
+       bleq    unlock_dll
        blne    lock_dll
-       cmp     r3, #0x1
-       blne    unlock_dll
        bl      sdram_in_selfrefresh    @ put the SDRAM in self refresh
        bl      configure_core_dpll
        bl      enable_sdrc
-       cmp     r3, #0x1
-       blne    wait_dll_unlock
-       cmp     r3, #0x2
+       cmp     r4, #0x1
+       bleq    wait_dll_unlock
        blne    wait_dll_lock
        cmp     r3, #0x1
        blne    configure_sdrc
+       isb                             @ prevent speculative exec past here
        mov     r0, #0                  @ return value
        ldmfd   sp!, {r1-r12, pc}       @ restore regs and return
 unlock_dll:
-       ldr     r4, omap3_sdrc_dlla_ctrl
-       ldr     r5, [r4]
-       orr     r5, r5, #0x4
-       str     r5, [r4]
+       ldr     r11, omap3_sdrc_dlla_ctrl
+       ldr     r12, [r11]
+       orr     r12, r12, #0x4
+       str     r12, [r11]              @ (no OCP barrier needed)
        bx      lr
 lock_dll:
-       ldr     r4, omap3_sdrc_dlla_ctrl
-       ldr     r5, [r4]
-       bic     r5, r5, #0x4
-       str     r5, [r4]
+       ldr     r11, omap3_sdrc_dlla_ctrl
+       ldr     r12, [r11]
+       bic     r12, r12, #0x4
+       str     r12, [r11]              @ (no OCP barrier needed)
        bx      lr
 sdram_in_selfrefresh:
-       mov     r5, #0x0                @ Move 0 to R5
-       mcr     p15, 0, r5, c7, c10, 5  @ memory barrier
-       ldr     r4, omap3_sdrc_power    @ read the SDRC_POWER register
-       ldr     r5, [r4]                @ read the contents of SDRC_POWER
-       orr     r5, r5, #0x40           @ enable self refresh on idle req
-       str     r5, [r4]                @ write back to SDRC_POWER register
-       ldr     r4, omap3_cm_iclken1_core       @ read the CM_ICLKEN1_CORE reg
-       ldr     r5, [r4]
-       bic     r5, r5, #0x2            @ disable iclk bit for SRDC
-       str     r5, [r4]
+       ldr     r11, omap3_sdrc_power   @ read the SDRC_POWER register
+       ldr     r12, [r11]              @ read the contents of SDRC_POWER
+       mov     r9, r12                 @ keep a copy of SDRC_POWER bits
+       orr     r12, r12, #0x40         @ enable self refresh on idle req
+       bic     r12, r12, #0x4          @ clear PWDENA
+       str     r12, [r11]              @ write back to SDRC_POWER register
+       ldr     r12, [r11]              @ posted-write barrier for SDRC
+       ldr     r11, omap3_cm_iclken1_core      @ read the CM_ICLKEN1_CORE reg
+       ldr     r12, [r11]
+       bic     r12, r12, #0x2          @ disable iclk bit for SDRC
+       str     r12, [r11]
 wait_sdrc_idle:
-       ldr     r4, omap3_cm_idlest1_core
-       ldr     r5, [r4]
-       and     r5, r5, #0x2            @ check for SDRC idle
-       cmp     r5, #2
+       ldr     r11, omap3_cm_idlest1_core
+       ldr     r12, [r11]
+       and     r12, r12, #0x2          @ check for SDRC idle
+       cmp     r12, #2
        bne     wait_sdrc_idle
        bx      lr
 configure_core_dpll:
-       ldr     r4, omap3_cm_clksel1_pll
-       ldr     r5, [r4]
-       ldr     r6, core_m2_mask_val    @ modify m2 for core dpll
-       and     r5, r5, r6
-       orr     r5, r5, r3, lsl #0x1B   @ r3 contains the M2 val
-       str     r5, [r4]
-       mov     r5, #0x800              @ wait for the clock to stabilise
+       ldr     r11, omap3_cm_clksel1_pll
+       ldr     r12, [r11]
+       ldr     r10, core_m2_mask_val   @ modify m2 for core dpll
+       and     r12, r12, r10
+       orr     r12, r12, r3, lsl #0x1B @ r3 contains the M2 val
+       str     r12, [r11]
+       ldr     r12, [r11]              @ posted-write barrier for CM
+       mov     r12, #0x800             @ wait for the clock to stabilise
        cmp     r3, #2
        bne     wait_clk_stable
        bx      lr
 wait_clk_stable:
-       subs    r5, r5, #1
+       subs    r12, r12, #1
        bne     wait_clk_stable
        nop
        nop
@@ -116,42 +121,42 @@ wait_clk_stable:
        nop
        bx      lr
 enable_sdrc:
-       ldr     r4, omap3_cm_iclken1_core
-       ldr     r5, [r4]
-       orr     r5, r5, #0x2            @ enable iclk bit for SDRC
-       str     r5, [r4]
+       ldr     r11, omap3_cm_iclken1_core
+       ldr     r12, [r11]
+       orr     r12, r12, #0x2          @ enable iclk bit for SDRC
+       str     r12, [r11]
 wait_sdrc_idle1:
-       ldr     r4, omap3_cm_idlest1_core
-       ldr     r5, [r4]
-       and     r5, r5, #0x2
-       cmp     r5, #0
+       ldr     r11, omap3_cm_idlest1_core
+       ldr     r12, [r11]
+       and     r12, r12, #0x2
+       cmp     r12, #0
        bne     wait_sdrc_idle1
-       ldr     r4, omap3_sdrc_power
-       ldr     r5, [r4]
-       bic     r5, r5, #0x40
-       str     r5, [r4]
+restore_sdrc_power_val:
+       ldr     r11, omap3_sdrc_power
+       str     r9, [r11]               @ restore SDRC_POWER, no barrier needed
        bx      lr
 wait_dll_lock:
-       ldr     r4, omap3_sdrc_dlla_status
-       ldr     r5, [r4]
-       and     r5, r5, #0x4
-       cmp     r5, #0x4
+       ldr     r11, omap3_sdrc_dlla_status
+       ldr     r12, [r11]
+       and     r12, r12, #0x4
+       cmp     r12, #0x4
        bne     wait_dll_lock
        bx      lr
 wait_dll_unlock:
-       ldr     r4, omap3_sdrc_dlla_status
-       ldr     r5, [r4]
-       and     r5, r5, #0x4
-       cmp     r5, #0x0
+       ldr     r11, omap3_sdrc_dlla_status
+       ldr     r12, [r11]
+       and     r12, r12, #0x4
+       cmp     r12, #0x0
        bne     wait_dll_unlock
        bx      lr
 configure_sdrc:
-       ldr     r4, omap3_sdrc_rfr_ctrl
-       str     r0, [r4]
-       ldr     r4, omap3_sdrc_actim_ctrla
-       str     r1, [r4]
-       ldr     r4, omap3_sdrc_actim_ctrlb
-       str     r2, [r4]
+       ldr     r11, omap3_sdrc_rfr_ctrl
+       str     r0, [r11]
+       ldr     r11, omap3_sdrc_actim_ctrla
+       str     r1, [r11]
+       ldr     r11, omap3_sdrc_actim_ctrlb
+       str     r2, [r11]
+       ldr     r2, [r11]               @ posted-write barrier for SDRC
        bx      lr
 
 omap3_sdrc_power:
index f36aba12090eb7b8300464dc88bc7499c28790f2..97eeeebcb066110d90c5166200218f162e73be81 100644 (file)
  *
  * Some parts based off of TI's 24xx code:
  *
- *   Copyright (C) 2004 Texas Instruments, Inc.
+ * Copyright (C) 2004-2009 Texas Instruments, Inc.
  *
  * Roughly modelled after the OMAP1 MPU timer code.
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License. See the file "COPYING" in the main directory of this archive
@@ -37,6 +38,7 @@
 
 #include <asm/mach/time.h>
 #include <mach/dmtimer.h>
+#include <asm/localtimer.h>
 
 /* MAX_GPTIMER_ID: number of GPTIMERs on the chip */
 #define MAX_GPTIMER_ID         12
@@ -82,7 +84,8 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
        case CLOCK_EVT_MODE_PERIODIC:
                period = clk_get_rate(omap_dm_timer_get_fclk(gptimer)) / HZ;
                period -= 1;
-
+               if (cpu_is_omap44xx())
+                       period = 0xff;  /* FIXME: */
                omap_dm_timer_set_load_start(gptimer, 1, 0xffffffff - period);
                break;
        case CLOCK_EVT_MODE_ONESHOT:
@@ -145,6 +148,9 @@ static void __init omap2_gp_clockevent_init(void)
                     "timer-gp: omap_dm_timer_set_source() failed\n");
 
        tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer));
+       if (cpu_is_omap44xx())
+               /* Assuming 32kHz clk is driving GPT1 */
+               tick_rate = 32768;      /* FIXME: */
 
        pr_info("OMAP clockevent source: GPTIMER%d at %u Hz\n",
                gptimer_id, tick_rate);
@@ -224,6 +230,9 @@ static void __init omap2_gp_clocksource_init(void)
 
 static void __init omap2_gp_timer_init(void)
 {
+#ifdef CONFIG_LOCAL_TIMERS
+       twd_base = IO_ADDRESS(OMAP44XX_LOCAL_TWD_BASE);
+#endif
        omap_dm_timer_init();
 
        omap2_gp_clockevent_init();
diff --git a/arch/arm/mach-omap2/timer-mpu.c b/arch/arm/mach-omap2/timer-mpu.c
new file mode 100644 (file)
index 0000000..c1a650a
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * The MPU local timer source file. In OMAP4, both cortex-a9 cores have
+ * own timer in it's MPU domain. These timers will be driving the
+ * linux kernel SMP tick framework when active. These timers are not
+ * part of the wake up domain.
+ *
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Author:
+ *      Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * This file is based on arm realview smp platform file.
+ * 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 = INT_44XX_LOCALTIMER_IRQ;
+       twd_timer_setup(evt);
+}
+
index 34a56a136efd3deaa8feabe139f5f0b689b553c8..d85296dc896c2090136652997a2d401c5e60e576 100644 (file)
 
 #include <mach/hardware.h>
 #include <mach/irqs.h>
-#include <mach/pm.h>
 #include <mach/mux.h>
 #include <mach/usb.h>
 
+#define OTG_SYSCONFIG  (OMAP34XX_HSUSB_OTG_BASE + 0x404)
+
+static void __init usb_musb_pm_init(void)
+{
+       /* Ensure force-idle mode for OTG controller */
+       if (cpu_is_omap34xx())
+               omap_writel(0, OTG_SYSCONFIG);
+}
+
+#ifdef CONFIG_USB_MUSB_SOC
+
 static struct resource musb_resources[] = {
        [0] = { /* start and end set dynamically */
                .flags  = IORESOURCE_MEM,
@@ -184,4 +194,13 @@ void __init usb_musb_init(void)
                printk(KERN_ERR "Unable to register HS-USB (MUSB) device\n");
                return;
        }
+
+       usb_musb_pm_init();
+}
+
+#else
+void __init usb_musb_init(void)
+{
+       usb_musb_pm_init();
 }
+#endif /* CONFIG_USB_MUSB_SOC */
index c14d12137276a3a5c6960a01e3c1ea5d51b0d9d8..6f3f77d031d0e5ed8db6f4558dbdee1b05b5a73f 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/init.h>
 #include <linux/mbus.h>
 #include <linux/io.h>
+#include <linux/errno.h>
 #include <mach/hardware.h>
 #include "common.h"
 
@@ -44,6 +45,7 @@
 #define TARGET_DEV_BUS         1
 #define TARGET_PCI             3
 #define TARGET_PCIE            4
+#define TARGET_SRAM            9
 #define ATTR_PCIE_MEM          0x59
 #define ATTR_PCIE_IO           0x51
 #define ATTR_PCIE_WA           0x79
@@ -53,6 +55,7 @@
 #define ATTR_DEV_CS1           0x1d
 #define ATTR_DEV_CS2           0x1b
 #define ATTR_DEV_BOOT          0xf
+#define ATTR_SRAM              0x0
 
 /*
  * Helpers to get DDR bank info
@@ -87,13 +90,13 @@ static int __init orion5x_cpu_win_can_remap(int win)
        return 0;
 }
 
-static void __init setup_cpu_win(int win, u32 base, u32 size,
+static int __init setup_cpu_win(int win, u32 base, u32 size,
                                 u8 target, u8 attr, int remap)
 {
        if (win >= 8) {
                printk(KERN_ERR "setup_cpu_win: trying to allocate "
                                "window %d\n", win);
-               return;
+               return -ENOSPC;
        }
 
        writel(base & 0xffff0000, CPU_WIN_BASE(win));
@@ -107,6 +110,7 @@ static void __init setup_cpu_win(int win, u32 base, u32 size,
                writel(remap & 0xffff0000, CPU_WIN_REMAP_LO(win));
                writel(0, CPU_WIN_REMAP_HI(win));
        }
+       return 0;
 }
 
 void __init orion5x_setup_cpu_mbus_bridge(void)
@@ -193,3 +197,9 @@ void __init orion5x_setup_pcie_wa_win(u32 base, u32 size)
        setup_cpu_win(win_alloc_count++, base, size,
                      TARGET_PCIE, ATTR_PCIE_WA, -1);
 }
+
+int __init orion5x_setup_sram_win(void)
+{
+       return setup_cpu_win(win_alloc_count, ORION5X_SRAM_PHYS_BASE,
+                       ORION5X_SRAM_SIZE, TARGET_SRAM, ATTR_SRAM, -1);
+}
index b1c7778d9f96ebef4700e3887138802edc625282..eafcc49009ead6134192a3ef207f230515ca3cbe 100644 (file)
@@ -31,7 +31,7 @@
 #include <plat/ehci-orion.h>
 #include <plat/mv_xor.h>
 #include <plat/orion_nand.h>
-#include <plat/orion5x_wdt.h>
+#include <plat/orion_wdt.h>
 #include <plat/time.h>
 #include "common.h"
 
@@ -536,16 +536,52 @@ void __init orion5x_xor_init(void)
        platform_device_register(&orion5x_xor1_channel);
 }
 
+static struct resource orion5x_crypto_res[] = {
+       {
+               .name   = "regs",
+               .start  = ORION5X_CRYPTO_PHYS_BASE,
+               .end    = ORION5X_CRYPTO_PHYS_BASE + 0xffff,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .name   = "sram",
+               .start  = ORION5X_SRAM_PHYS_BASE,
+               .end    = ORION5X_SRAM_PHYS_BASE + SZ_8K - 1,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .name   = "crypto interrupt",
+               .start  = IRQ_ORION5X_CESA,
+               .end    = IRQ_ORION5X_CESA,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device orion5x_crypto_device = {
+       .name           = "mv_crypto",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(orion5x_crypto_res),
+       .resource       = orion5x_crypto_res,
+};
+
+int __init orion5x_crypto_init(void)
+{
+       int ret;
+
+       ret = orion5x_setup_sram_win();
+       if (ret)
+               return ret;
+
+       return platform_device_register(&orion5x_crypto_device);
+}
 
 /*****************************************************************************
  * Watchdog
  ****************************************************************************/
-static struct orion5x_wdt_platform_data orion5x_wdt_data = {
+static struct orion_wdt_platform_data orion5x_wdt_data = {
        .tclk                   = 0,
 };
 
 static struct platform_device orion5x_wdt_device = {
-       .name           = "orion5x_wdt",
+       .name           = "orion_wdt",
        .id             = -1,
        .dev            = {
                .platform_data  = &orion5x_wdt_data,
index 798b9a5e3da919852265ad8266615f7fe6a50cf7..de483e83edd7fe29ae34a03c55dae3eb69214a56 100644 (file)
@@ -26,6 +26,7 @@ void orion5x_setup_dev0_win(u32 base, u32 size);
 void orion5x_setup_dev1_win(u32 base, u32 size);
 void orion5x_setup_dev2_win(u32 base, u32 size);
 void orion5x_setup_pcie_wa_win(u32 base, u32 size);
+int orion5x_setup_sram_win(void);
 
 void orion5x_ehci0_init(void);
 void orion5x_ehci1_init(void);
@@ -37,6 +38,7 @@ void orion5x_spi_init(void);
 void orion5x_uart0_init(void);
 void orion5x_uart1_init(void);
 void orion5x_xor_init(void);
+int orion5x_crypto_init(void);
 
 /*
  * PCIe/PCI functions.
index be896e59d3e7089fa0189ae74a539d6ebd24b35d..5c9744cd8ef6e213d465d1e76bc50509474ae82c 100644 (file)
@@ -17,8 +17,8 @@
 
 #define CPU_CTRL               (ORION5X_BRIDGE_VIRT_BASE | 0x104)
 
-#define CPU_RESET_MASK         (ORION5X_BRIDGE_VIRT_BASE | 0x108)
-#define WDT_RESET              0x0002
+#define RSTOUTn_MASK           (ORION5X_BRIDGE_VIRT_BASE | 0x108)
+#define WDT_RESET_OUT_EN       0x0002
 
 #define CPU_SOFT_RESET         (ORION5X_BRIDGE_VIRT_BASE | 0x10c)
 
index 377a773ae53f9808a1caa96865a93c20367b77b4..2d87665705312b8b3bf8bba6bf6158fd600ae212 100644 (file)
@@ -24,6 +24,7 @@
  * f1000000    on-chip peripheral registers
  * f2000000    PCIe I/O space
  * f2100000    PCI I/O space
+ * f2200000    SRAM dedicated for the crypto unit
  * f4000000    device bus mappings (boot)
  * fa000000    device bus mappings (cs0)
  * fa800000    device bus mappings (cs2)
@@ -49,6 +50,9 @@
 #define ORION5X_PCI_IO_BUS_BASE                0x00100000
 #define ORION5X_PCI_IO_SIZE            SZ_1M
 
+#define ORION5X_SRAM_PHYS_BASE         (0xf2200000)
+#define ORION5X_SRAM_SIZE              SZ_8K
+
 /* Relevant only for Orion-1/Orion-NAS */
 #define ORION5X_PCIE_WA_PHYS_BASE      0xf0000000
 #define ORION5X_PCIE_WA_VIRT_BASE      0xfe000000
@@ -94,6 +98,8 @@
 #define ORION5X_SATA_PHYS_BASE         (ORION5X_REGS_PHYS_BASE | 0x80000)
 #define ORION5X_SATA_VIRT_BASE         (ORION5X_REGS_VIRT_BASE | 0x80000)
 
+#define ORION5X_CRYPTO_PHYS_BASE       (ORION5X_REGS_PHYS_BASE | 0x90000)
+
 #define ORION5X_USB1_PHYS_BASE         (ORION5X_REGS_PHYS_BASE | 0xa0000)
 #define ORION5X_USB1_VIRT_BASE         (ORION5X_REGS_VIRT_BASE | 0xa0000)
 
index e912490fff23ad3c78b9820997eed313bd19034d..60e734c104584c3765268b310c18e6df37b84937 100644 (file)
@@ -23,7 +23,7 @@ static inline void arch_reset(char mode, const char *cmd)
        /*
         * Enable and issue soft reset
         */
-       orion5x_setbits(CPU_RESET_MASK, (1 << 2));
+       orion5x_setbits(RSTOUTn_MASK, (1 << 2));
        orion5x_setbits(CPU_SOFT_RESET, 1);
 }
 
index e23a3f91d6c61b777356187df9aceddfc1dae160..bc4c3b9aaf83346fc054b5cb23eb19287b3e2fc0 100644 (file)
@@ -124,6 +124,9 @@ void __init orion5x_mpp_conf(struct orion5x_mpp_mode *mode)
        u32 mpp_8_15_ctrl = readl(MPP_8_15_CTRL);
        u32 mpp_16_19_ctrl = readl(MPP_16_19_CTRL);
 
+       /* Initialize gpiolib. */
+       orion_gpio_init();
+
        while (mode->mpp >= 0) {
                u32 *reg;
                int num_type;
index 41e6d5033d544e22c2a691365da1d2d578c83f22..61c086b66723d96296a51d38363f8d3584523cea 100644 (file)
@@ -181,9 +181,9 @@ static void mss2_power_off(void)
        /*
         * Enable and issue soft reset
         */
-       reg = readl(CPU_RESET_MASK);
+       reg = readl(RSTOUTn_MASK);
        reg |= 1 << 2;
-       writel(reg, CPU_RESET_MASK);
+       writel(reg, RSTOUTn_MASK);
 
        reg = readl(CPU_SOFT_RESET);
        reg |= 1;
index 0f9cdf458952f0da68c0450e35f9c1875d7239da..37b3d4875291af1a076dd4c77f4455f2a8827fc8 100644 (file)
@@ -25,6 +25,7 @@ struct fpga_devices {
        /* Technologic Systems */
        struct fpga_device      ts_rtc;
        struct fpga_device      ts_nand;
+       struct fpga_device      ts_rng;
 };
 
 struct ts78xx_fpga_data {
index 9a6b397f972d533908c096468958bdf6629c997c..5041d1bc26b132e1f0aa7629d6b6be5184d3fcea 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/m48t86.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
+#include <linux/timeriomem-rng.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -269,6 +270,50 @@ static void ts78xx_ts_nand_unload(void)
        platform_device_del(&ts78xx_ts_nand_device);
 }
 
+/*****************************************************************************
+ * HW RNG
+ ****************************************************************************/
+#define TS_RNG_DATA    (TS78XX_FPGA_REGS_PHYS_BASE | 0x044)
+
+static struct resource ts78xx_ts_rng_resource = {
+       .flags          = IORESOURCE_MEM,
+       .start          = TS_RNG_DATA,
+       .end            = TS_RNG_DATA + 4 - 1,
+};
+
+static struct timeriomem_rng_data ts78xx_ts_rng_data = {
+       .period         = 1000000, /* one second */
+};
+
+static struct platform_device ts78xx_ts_rng_device = {
+       .name           = "timeriomem_rng",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &ts78xx_ts_rng_data,
+       },
+       .resource       = &ts78xx_ts_rng_resource,
+       .num_resources  = 1,
+};
+
+static int ts78xx_ts_rng_load(void)
+{
+       int rc;
+
+       if (ts78xx_fpga.supports.ts_rng.init == 0) {
+               rc = platform_device_register(&ts78xx_ts_rng_device);
+               if (!rc)
+                       ts78xx_fpga.supports.ts_rng.init = 1;
+       } else
+               rc = platform_device_add(&ts78xx_ts_rng_device);
+
+       return rc;
+};
+
+static void ts78xx_ts_rng_unload(void)
+{
+       platform_device_del(&ts78xx_ts_rng_device);
+}
+
 /*****************************************************************************
  * FPGA 'hotplug' support code
  ****************************************************************************/
@@ -276,6 +321,7 @@ static void ts78xx_fpga_devices_zero_init(void)
 {
        ts78xx_fpga.supports.ts_rtc.init = 0;
        ts78xx_fpga.supports.ts_nand.init = 0;
+       ts78xx_fpga.supports.ts_rng.init = 0;
 }
 
 static void ts78xx_fpga_supports(void)
@@ -289,10 +335,12 @@ static void ts78xx_fpga_supports(void)
        case TS7800_REV_5:
                ts78xx_fpga.supports.ts_rtc.present = 1;
                ts78xx_fpga.supports.ts_nand.present = 1;
+               ts78xx_fpga.supports.ts_rng.present = 1;
                break;
        default:
                ts78xx_fpga.supports.ts_rtc.present = 0;
                ts78xx_fpga.supports.ts_nand.present = 0;
+               ts78xx_fpga.supports.ts_rng.present = 0;
        }
 }
 
@@ -316,6 +364,14 @@ static int ts78xx_fpga_load_devices(void)
                }
                ret |= tmp;
        }
+       if (ts78xx_fpga.supports.ts_rng.present == 1) {
+               tmp = ts78xx_ts_rng_load();
+               if (tmp) {
+                       printk(KERN_INFO "TS-78xx: RNG not registered\n");
+                       ts78xx_fpga.supports.ts_rng.present = 0;
+               }
+               ret |= tmp;
+       }
 
        return ret;
 }
@@ -328,6 +384,8 @@ static int ts78xx_fpga_unload_devices(void)
                ts78xx_ts_rtc_unload();
        if (ts78xx_fpga.supports.ts_nand.present == 1)
                ts78xx_ts_nand_unload();
+       if (ts78xx_fpga.supports.ts_rng.present == 1)
+               ts78xx_ts_rng_unload();
 
        return ret;
 }
index 7ddc22c2bb5480d17455fe533023ddd36d66a58f..69208217b22037096e4c467c2cc4508fb75dd9e5 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/mtd/physmap.h>
 #include <linux/mv643xx_eth.h>
 #include <linux/ethtool.h>
+#include <net/dsa.h>
 #include <asm/mach-types.h>
 #include <asm/gpio.h>
 #include <asm/mach/arch.h>
@@ -97,6 +98,20 @@ static struct mv643xx_eth_platform_data wnr854t_eth_data = {
        .duplex         = DUPLEX_FULL,
 };
 
+static struct dsa_chip_data wnr854t_switch_chip_data = {
+       .port_names[0] = "lan3",
+       .port_names[1] = "lan4",
+       .port_names[2] = "wan",
+       .port_names[3] = "cpu",
+       .port_names[5] = "lan1",
+       .port_names[7] = "lan2",
+};
+
+static struct dsa_platform_data wnr854t_switch_plat_data = {
+       .nr_chips       = 1,
+       .chip           = &wnr854t_switch_chip_data,
+};
+
 static void __init wnr854t_init(void)
 {
        /*
@@ -110,6 +125,7 @@ static void __init wnr854t_init(void)
         * Configure peripherals.
         */
        orion5x_eth_init(&wnr854t_eth_data);
+       orion5x_eth_switch_init(&wnr854t_switch_plat_data, NO_IRQ);
        orion5x_uart0_init();
 
        orion5x_setup_dev_boot_win(WNR854T_NOR_BOOT_BASE,
index 17d3fbd368a342dd39b4b7f25313740fb8ac86a6..f4533f8ff4e891680f1e49a2169ea6f427b0e574 100644 (file)
@@ -51,6 +51,12 @@ config MACH_INTELMOTE2
        select IWMMXT
        select PXA_HAVE_BOARD_IRQS
 
+config MACH_STARGATE2
+       bool "Intel Stargate 2 Platform"
+       select PXA27x
+       select IWMMXT
+       select PXA_HAVE_BOARD_IRQS
+
 config ARCH_LUBBOCK
        bool "Intel DBPXA250 Development Platform"
        select PXA25x
@@ -88,6 +94,10 @@ config PXA_SHARPSL
          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
@@ -280,6 +290,7 @@ config MACH_ZYLONITE
        select PXA3xx
        select PXA_SSP
        select HAVE_PWM
+       select PXA_HAVE_BOARD_IRQS
 
 config MACH_LITTLETON
        bool "PXA3xx Form Factor Platform (aka Littleton)"
@@ -308,6 +319,14 @@ config MACH_CM_X300
        select PXA3xx
        select CPU_PXA300
 
+config MACH_H4700
+       bool "HP iPAQ hx4700"
+       select PXA27x
+       select IWMMXT
+       select PXA_SSP
+       select HAVE_PWM
+       select PXA_HAVE_BOARD_IRQS
+
 config MACH_MAGICIAN
        bool "Enable HTC Magician Support"
        select PXA27x
@@ -505,12 +524,6 @@ config PXA_SSP
        help
          Enable support for PXA2xx SSP ports
 
-config PXA_PWM
-       tristate
-       default BACKLIGHT_PWM
-       help
-         Enable support for PXA2xx/PXA3xx PWM controllers
-
 config TOSA_BT
        tristate "Control the state of built-in bluetooth chip on Sharp SL-6000"
        depends on MACH_TOSA
index 682dbf4e14b06e25bac7ade81d38ac117d9079ef..d18ffef44b8cb47d4d864689d1008e739a615fe0 100644 (file)
@@ -15,7 +15,6 @@ endif
 
 # Generic drivers that other drivers may depend upon
 obj-$(CONFIG_PXA_SSP)          += ssp.o
-obj-$(CONFIG_PXA_PWM)          += pwm.o
 
 # SoC-specific code
 obj-$(CONFIG_PXA25x)           += mfp-pxa2xx.o pxa2xx.o pxa25x.o
@@ -47,6 +46,7 @@ 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
@@ -78,6 +78,7 @@ obj-$(CONFIG_MACH_CM_X300)      += cm-x300.o
 obj-$(CONFIG_PXA_EZX)           += ezx.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
 
index db52d2c4791da521ab5fffe61056046746e9e658..49ae38292310c2b1058c433f7e2a16fbe378756f 100644 (file)
@@ -86,20 +86,3 @@ void clks_register(struct clk_lookup *clks, size_t num)
        for (i = 0; i < num; i++)
                clkdev_add(&clks[i]);
 }
-
-int clk_add_alias(const char *alias, const char *alias_dev_name, char *id,
-       struct device *dev)
-{
-       struct clk *r = clk_get(dev, id);
-       struct clk_lookup *l;
-
-       if (!r)
-               return -ENODEV;
-
-       l = clkdev_alloc(r, alias, alias_dev_name);
-       clk_put(r);
-       if (!l)
-               return -ENODEV;
-       clkdev_add(l);
-       return 0;
-}
index 34576ba5f5fd0a8d9e059fed35534f139a463335..1d2cec25391de4320819a0bc04a988072f085aaa 100644 (file)
@@ -335,6 +335,10 @@ void __init cmx270_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(cmx270_pin_config));
 
+#ifdef CONFIG_PM
+       pxa27x_set_pwrmode(PWRMODE_DEEPSLEEP);
+#endif
+
        cmx270_init_rtc();
        cmx270_init_mmc();
        cmx270_init_ohci();
index a9f48b1cb54a2aa726831b899827a59fa81e85ca..465da26591bd3e863bbce2a2bd8f8f47e1c321f7 100644 (file)
 #include <linux/gpio.h>
 #include <linux/dm9000.h>
 #include <linux/leds.h>
+#include <linux/rtc-v3020.h>
 
 #include <linux/i2c.h>
 #include <linux/i2c/pca953x.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
+#include <asm/setup.h>
 
 #include <mach/pxa300.h>
 #include <mach/pxafb.h>
 #include <mach/mmc.h>
 #include <mach/ohci.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/pxa3xx_nand.h>
 
 #include <asm/mach/map.h>
 
 #define        CM_X300_MMC2_IRQ        IRQ_GPIO(GPIO82_MMC2_IRQ)
 
+#define GPIO95_RTC_CS          (95)
+#define GPIO96_RTC_WR          (96)
+#define GPIO97_RTC_RD          (97)
+#define GPIO98_RTC_IO          (98)
+
 static mfp_cfg_t cm_x300_mfp_cfg[] __initdata = {
        /* LCD */
        GPIO54_LCD_LDD_0,
@@ -135,6 +142,12 @@ static mfp_cfg_t cm_x300_mfp_cfg[] __initdata = {
        GPIO85_GPIO,                    /* MMC WP */
        GPIO99_GPIO,                    /* Ethernet IRQ */
 
+       /* RTC GPIOs */
+       GPIO95_GPIO,                    /* RTC CS */
+       GPIO96_GPIO,                    /* RTC WR */
+       GPIO97_GPIO,                    /* RTC RD */
+       GPIO98_GPIO,                    /* RTC IO */
+
        /* Standard I2C */
        GPIO21_I2C_SCL,
        GPIO22_I2C_SDA,
@@ -265,6 +278,7 @@ static struct mtd_partition cm_x300_nand_partitions[] = {
 
 static struct pxa3xx_nand_platform_data cm_x300_nand_info = {
        .enable_arbiter = 1,
+       .keep_config    = 1,
        .parts          = cm_x300_nand_partitions,
        .nr_parts       = ARRAY_SIZE(cm_x300_nand_partitions),
 };
@@ -441,6 +455,31 @@ static void __init cm_x300_init_i2c(void)
 static inline void cm_x300_init_i2c(void) {}
 #endif
 
+#if defined(CONFIG_RTC_DRV_V3020) || defined(CONFIG_RTC_DRV_V3020_MODULE)
+struct v3020_platform_data cm_x300_v3020_pdata = {
+       .use_gpio       = 1,
+       .gpio_cs        = GPIO95_RTC_CS,
+       .gpio_wr        = GPIO96_RTC_WR,
+       .gpio_rd        = GPIO97_RTC_RD,
+       .gpio_io        = GPIO98_RTC_IO,
+};
+
+static struct platform_device cm_x300_rtc_device = {
+       .name           = "v3020",
+       .id             = -1,
+       .dev            = {
+               .platform_data = &cm_x300_v3020_pdata,
+       }
+};
+
+static void __init cm_x300_init_rtc(void)
+{
+       platform_device_register(&cm_x300_rtc_device);
+}
+#else
+static inline void cm_x300_init_rtc(void) {}
+#endif
+
 static void __init cm_x300_init(void)
 {
        /* board-processor specific GPIO initialization */
@@ -453,6 +492,19 @@ static void __init cm_x300_init(void)
        cm_x300_init_nand();
        cm_x300_init_leds();
        cm_x300_init_i2c();
+       cm_x300_init_rtc();
+}
+
+static void __init cm_x300_fixup(struct machine_desc *mdesc, struct tag *tags,
+                                char **cmdline, struct meminfo *mi)
+{
+       mi->nr_banks = 2;
+       mi->bank[0].start = 0xa0000000;
+       mi->bank[0].node = 0;
+       mi->bank[0].size = (64*1024*1024);
+       mi->bank[1].start = 0xc0000000;
+       mi->bank[1].node = 0;
+       mi->bank[1].size = (64*1024*1024);
 }
 
 MACHINE_START(CM_X300, "CM-X300 module")
@@ -463,4 +515,5 @@ MACHINE_START(CM_X300, "CM-X300 module")
        .init_irq       = pxa3xx_init_irq,
        .timer          = &pxa_timer,
        .init_machine   = cm_x300_init,
+       .fixup          = cm_x300_fixup,
 MACHINE_END
index 930e364ccde92d6ce8f03c498eec7903bd3222e7..962dda2e154a7e598410732acf493f673a4040fe 100644 (file)
@@ -42,7 +42,7 @@
 #include <asm/mach/irq.h>
 
 #include <mach/pxa25x.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/irda.h>
 #include <mach/mmc.h>
 #include <mach/udc.h>
@@ -445,13 +445,8 @@ static struct ads7846_platform_data corgi_ads7846_info = {
        .wait_for_sync          = corgi_wait_for_hsync,
 };
 
-static void corgi_ads7846_cs(u32 command)
-{
-       gpio_set_value(CORGI_GPIO_ADS7846_CS, !(command == PXA2XX_CS_ASSERT));
-}
-
 static struct pxa2xx_spi_chip corgi_ads7846_chip = {
-       .cs_control     = corgi_ads7846_cs,
+       .gpio_cs        = CORGI_GPIO_ADS7846_CS,
 };
 
 static void corgi_bl_kick_battery(void)
@@ -475,22 +470,12 @@ static struct corgi_lcd_platform_data corgi_lcdcon_info = {
        .kick_battery           = corgi_bl_kick_battery,
 };
 
-static void corgi_lcdcon_cs(u32 command)
-{
-       gpio_set_value(CORGI_GPIO_LCDCON_CS, !(command == PXA2XX_CS_ASSERT));
-}
-
 static struct pxa2xx_spi_chip corgi_lcdcon_chip = {
-       .cs_control     = corgi_lcdcon_cs,
+       .gpio_cs        = CORGI_GPIO_LCDCON_CS,
 };
 
-static void corgi_max1111_cs(u32 command)
-{
-       gpio_set_value(CORGI_GPIO_MAX1111_CS, !(command == PXA2XX_CS_ASSERT));
-}
-
 static struct pxa2xx_spi_chip corgi_max1111_chip = {
-       .cs_control     = corgi_max1111_cs,
+       .gpio_cs        = CORGI_GPIO_MAX1111_CS,
 };
 
 static struct spi_board_info corgi_spi_devices[] = {
@@ -520,32 +505,8 @@ static struct spi_board_info corgi_spi_devices[] = {
 
 static void __init corgi_init_spi(void)
 {
-       int err;
-
-       err = gpio_request(CORGI_GPIO_ADS7846_CS, "ADS7846_CS");
-       if (err)
-               return;
-
-       err = gpio_request(CORGI_GPIO_LCDCON_CS, "LCDCON_CS");
-       if (err)
-               goto err_free_1;
-
-       err = gpio_request(CORGI_GPIO_MAX1111_CS, "MAX1111_CS");
-       if (err)
-               goto err_free_2;
-
-       gpio_direction_output(CORGI_GPIO_ADS7846_CS, 1);
-       gpio_direction_output(CORGI_GPIO_LCDCON_CS, 1);
-       gpio_direction_output(CORGI_GPIO_MAX1111_CS, 1);
-
        pxa2xx_set_spi_info(1, &corgi_spi_info);
        spi_register_board_info(ARRAY_AND_SIZE(corgi_spi_devices));
-       return;
-
-err_free_2:
-       gpio_free(CORGI_GPIO_LCDCON_CS);
-err_free_1:
-       gpio_free(CORGI_GPIO_ADS7846_CS);
 }
 #else
 static inline void corgi_init_spi(void) {}
index 7f04b3a761d12d2bda0af50d07b85ae889f68a78..a093282fe4db99c0cfbbc3de562bed42043c28b7 100644 (file)
@@ -41,7 +41,6 @@ static void corgi_charger_init(void)
        pxa_gpio_mode(CORGI_GPIO_CHRG_ON | GPIO_OUT);
        pxa_gpio_mode(CORGI_GPIO_CHRG_UKN | GPIO_OUT);
        pxa_gpio_mode(CORGI_GPIO_KEY_INT | GPIO_IN);
-       sharpsl_pm_pxa_init();
 }
 
 static void corgi_measure_temp(int on)
@@ -191,7 +190,7 @@ unsigned long corgipm_read_devdata(int type)
 
 static struct sharpsl_charger_machinfo corgi_pm_machinfo = {
        .init            = corgi_charger_init,
-       .exit            = sharpsl_pm_pxa_remove,
+       .exit            = NULL,
        .gpio_batlock    = CORGI_GPIO_BAT_COVER,
        .gpio_acin       = CORGI_GPIO_AC_IN,
        .gpio_batfull    = CORGI_GPIO_CHRG_FULL,
index 083a1d851d494f82f7ddbddc765338b5af220f08..3a8ee2272add9d3f062d6239070e49680044316d 100644 (file)
@@ -36,6 +36,8 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
 
 #include <mach/pxa2xx-regs.h>
 
@@ -47,6 +49,8 @@ MODULE_PARM_DESC(freq_debug, "Set the debug messages to on=1/off=0");
 #define freq_debug  0
 #endif
 
+static struct regulator *vcc_core;
+
 static unsigned int pxa27x_maxfreq;
 module_param(pxa27x_maxfreq, uint, 0);
 MODULE_PARM_DESC(pxa27x_maxfreq, "Set the pxa27x maxfreq in MHz"
@@ -58,6 +62,8 @@ typedef struct {
        unsigned int cccr;
        unsigned int div2;
        unsigned int cclkcfg;
+       int vmin;
+       int vmax;
 } pxa_freqs_t;
 
 /* Define the refresh period in mSec for the SDRAM and the number of rows */
@@ -82,24 +88,24 @@ static unsigned int sdram_rows;
 
 static pxa_freqs_t pxa255_run_freqs[] =
 {
-       /* CPU   MEMBUS  CCCR  DIV2 CCLKCFG        run  turbo PXbus SDRAM */
-       { 99500,  99500, 0x121, 1,  CCLKCFG},   /*  99,   99,   50,   50  */
-       {132700, 132700, 0x123, 1,  CCLKCFG},   /* 133,  133,   66,   66  */
-       {199100,  99500, 0x141, 0,  CCLKCFG},   /* 199,  199,   99,   99  */
-       {265400, 132700, 0x143, 1,  CCLKCFG},   /* 265,  265,  133,   66  */
-       {331800, 165900, 0x145, 1,  CCLKCFG},   /* 331,  331,  166,   83  */
-       {398100,  99500, 0x161, 0,  CCLKCFG},   /* 398,  398,  196,   99  */
+       /* CPU   MEMBUS  CCCR  DIV2 CCLKCFG                run  turbo PXbus SDRAM */
+       { 99500,  99500, 0x121, 1,  CCLKCFG, -1, -1},   /*  99,   99,   50,   50  */
+       {132700, 132700, 0x123, 1,  CCLKCFG, -1, -1},   /* 133,  133,   66,   66  */
+       {199100,  99500, 0x141, 0,  CCLKCFG, -1, -1},   /* 199,  199,   99,   99  */
+       {265400, 132700, 0x143, 1,  CCLKCFG, -1, -1},   /* 265,  265,  133,   66  */
+       {331800, 165900, 0x145, 1,  CCLKCFG, -1, -1},   /* 331,  331,  166,   83  */
+       {398100,  99500, 0x161, 0,  CCLKCFG, -1, -1},   /* 398,  398,  196,   99  */
 };
 
 /* Use the turbo mode frequencies for the CPUFREQ_POLICY_POWERSAVE policy */
 static pxa_freqs_t pxa255_turbo_freqs[] =
 {
        /* CPU   MEMBUS  CCCR  DIV2 CCLKCFG        run  turbo PXbus SDRAM */
-       { 99500, 99500,  0x121, 1,  CCLKCFG},   /*  99,   99,   50,   50  */
-       {199100, 99500,  0x221, 0,  CCLKCFG},   /*  99,  199,   50,   99  */
-       {298500, 99500,  0x321, 0,  CCLKCFG},   /*  99,  287,   50,   99  */
-       {298600, 99500,  0x1c1, 0,  CCLKCFG},   /* 199,  287,   99,   99  */
-       {398100, 99500,  0x241, 0,  CCLKCFG},   /* 199,  398,   99,   99  */
+       { 99500, 99500,  0x121, 1,  CCLKCFG, -1, -1},   /*  99,   99,   50,   50  */
+       {199100, 99500,  0x221, 0,  CCLKCFG, -1, -1},   /*  99,  199,   50,   99  */
+       {298500, 99500,  0x321, 0,  CCLKCFG, -1, -1},   /*  99,  287,   50,   99  */
+       {298600, 99500,  0x1c1, 0,  CCLKCFG, -1, -1},   /* 199,  287,   99,   99  */
+       {398100, 99500,  0x241, 0,  CCLKCFG, -1, -1},   /* 199,  398,   99,   99  */
 };
 
 #define NUM_PXA25x_RUN_FREQS ARRAY_SIZE(pxa255_run_freqs)
@@ -148,13 +154,13 @@ MODULE_PARM_DESC(pxa255_turbo_table, "Selects the frequency table (0 = run table
    ((T)  ? CCLKCFG_TURBO : 0))
 
 static pxa_freqs_t pxa27x_freqs[] = {
-       {104000, 104000, PXA27x_CCCR(1,  8, 2), 0, CCLKCFG2(1, 0, 1)},
-       {156000, 104000, PXA27x_CCCR(1,  8, 6), 0, CCLKCFG2(1, 1, 1)},
-       {208000, 208000, PXA27x_CCCR(0, 16, 2), 1, CCLKCFG2(0, 0, 1)},
-       {312000, 208000, PXA27x_CCCR(1, 16, 3), 1, CCLKCFG2(1, 0, 1)},
-       {416000, 208000, PXA27x_CCCR(1, 16, 4), 1, CCLKCFG2(1, 0, 1)},
-       {520000, 208000, PXA27x_CCCR(1, 16, 5), 1, CCLKCFG2(1, 0, 1)},
-       {624000, 208000, PXA27x_CCCR(1, 16, 6), 1, CCLKCFG2(1, 0, 1)}
+       {104000, 104000, PXA27x_CCCR(1,  8, 2), 0, CCLKCFG2(1, 0, 1),  900000, 1705000 },
+       {156000, 104000, PXA27x_CCCR(1,  8, 6), 0, CCLKCFG2(1, 1, 1), 1000000, 1705000 },
+       {208000, 208000, PXA27x_CCCR(0, 16, 2), 1, CCLKCFG2(0, 0, 1), 1180000, 1705000 },
+       {312000, 208000, PXA27x_CCCR(1, 16, 3), 1, CCLKCFG2(1, 0, 1), 1250000, 1705000 },
+       {416000, 208000, PXA27x_CCCR(1, 16, 4), 1, CCLKCFG2(1, 0, 1), 1350000, 1705000 },
+       {520000, 208000, PXA27x_CCCR(1, 16, 5), 1, CCLKCFG2(1, 0, 1), 1450000, 1705000 },
+       {624000, 208000, PXA27x_CCCR(1, 16, 6), 1, CCLKCFG2(1, 0, 1), 1550000, 1705000 }
 };
 
 #define NUM_PXA27x_FREQS ARRAY_SIZE(pxa27x_freqs)
@@ -163,6 +169,47 @@ static struct cpufreq_frequency_table
 
 extern unsigned get_clk_frequency_khz(int info);
 
+#ifdef CONFIG_REGULATOR
+
+static int pxa_cpufreq_change_voltage(pxa_freqs_t *pxa_freq)
+{
+       int ret = 0;
+       int vmin, vmax;
+
+       if (!cpu_is_pxa27x())
+               return 0;
+
+       vmin = pxa_freq->vmin;
+       vmax = pxa_freq->vmax;
+       if ((vmin == -1) || (vmax == -1))
+               return 0;
+
+       ret = regulator_set_voltage(vcc_core, vmin, vmax);
+       if (ret)
+               pr_err("cpufreq: Failed to set vcc_core in [%dmV..%dmV]\n",
+                      vmin, vmax);
+       return ret;
+}
+
+static __init void pxa_cpufreq_init_voltages(void)
+{
+       vcc_core = regulator_get(NULL, "vcc_core");
+       if (IS_ERR(vcc_core)) {
+               pr_info("cpufreq: Didn't find vcc_core regulator\n");
+               vcc_core = NULL;
+       } else {
+               pr_info("cpufreq: Found vcc_core regulator\n");
+       }
+}
+#else
+static int pxa_cpufreq_change_voltage(pxa_freqs_t *pxa_freq)
+{
+       return 0;
+}
+
+static __init void pxa_cpufreq_init_voltages(void) { }
+#endif
+
 static void find_freq_tables(struct cpufreq_frequency_table **freq_table,
                             pxa_freqs_t **pxa_freqs)
 {
@@ -251,6 +298,7 @@ static int pxa_set_target(struct cpufreq_policy *policy,
        unsigned long flags;
        unsigned int new_freq_cpu, new_freq_mem;
        unsigned int unused, preset_mdrefr, postset_mdrefr, cclkcfg;
+       int ret = 0;
 
        /* Get the current policy */
        find_freq_tables(&pxa_freqs_table, &pxa_freq_settings);
@@ -273,6 +321,10 @@ static int pxa_set_target(struct cpufreq_policy *policy,
                         freqs.new / 1000, (pxa_freq_settings[idx].div2) ?
                         (new_freq_mem / 2000) : (new_freq_mem / 1000));
 
+       if (vcc_core && freqs.new > freqs.old)
+               ret = pxa_cpufreq_change_voltage(&pxa_freq_settings[idx]);
+       if (ret)
+               return ret;
        /*
         * Tell everyone what we're about to do...
         * you should add a notify client with any platform specific
@@ -335,6 +387,18 @@ static int pxa_set_target(struct cpufreq_policy *policy,
         */
        cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 
+       /*
+        * Even if voltage setting fails, we don't report it, as the frequency
+        * change succeeded. The voltage reduction is not a critical failure,
+        * only power savings will suffer from this.
+        *
+        * Note: if the voltage change fails, and a return value is returned, a
+        * bug is triggered (seems a deadlock). Should anybody find out where,
+        * the "return 0" should become a "return ret".
+        */
+       if (vcc_core && freqs.new < freqs.old)
+               ret = pxa_cpufreq_change_voltage(&pxa_freq_settings[idx]);
+
        return 0;
 }
 
@@ -349,6 +413,8 @@ static __init int pxa_cpufreq_init(struct cpufreq_policy *policy)
        if (cpu_is_pxa27x())
                pxa27x_guess_max_freq();
 
+       pxa_cpufreq_init_voltages();
+
        init_sdram_rows();
 
        /* set default policy and cpuinfo */
index 2b289f83a61a6df57592fe87ebbe356980c27154..7d3e1b46e550f3469adb2da0697e561bab69c28a 100644 (file)
 #include <linux/mtd/physmap.h>
 #include <linux/mtd/partitions.h>
 #include <linux/sm501.h>
+#include <linux/smsc911x.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <mach/csb726.h>
 #include <mach/mfp-pxa27x.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/mmc.h>
 #include <mach/ohci.h>
 #include <mach/pxa2xx-regs.h>
+#include <mach/audio.h>
 
 #include "generic.h"
 #include "devices.h"
@@ -275,15 +277,26 @@ static struct resource csb726_lan_resources[] = {
        {
                .start  = CSB726_IRQ_LAN,
                .end    = CSB726_IRQ_LAN,
-               .flags  = IORESOURCE_IRQ,
+               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
        },
 };
 
+struct smsc911x_platform_config csb726_lan_config = {
+       .irq_type       = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+       .irq_type       = SMSC911X_IRQ_TYPE_PUSH_PULL,
+       .flags          = SMSC911X_USE_32BIT,
+       .phy_interface  = PHY_INTERFACE_MODE_MII,
+};
+
+
 static struct platform_device csb726_lan = {
-       .name           = "smc911x",
+       .name           = "smsc911x",
        .id             = -1,
        .num_resources  = ARRAY_SIZE(csb726_lan_resources),
        .resource       = csb726_lan_resources,
+       .dev            = {
+               .platform_data  = &csb726_lan_config,
+       },
 };
 
 static struct platform_device *devices[] __initdata = {
@@ -303,6 +316,7 @@ static void __init csb726_init(void)
        pxa27x_set_i2c_power_info(NULL);
        pxa_set_mci_info(&csb726_mci);
        pxa_set_ohci_info(&csb726_ohci_platform_data);
+       pxa_set_ac97_info(NULL);
 
        platform_add_devices(devices, ARRAY_SIZE(devices));
 }
index 29970f703f3cc6d33ddc19635f1b56a6df3d9777..ecc08f360b68a28df3da71c1d98040a9a760b511 100644 (file)
@@ -8,7 +8,7 @@
 #include <mach/pxafb.h>
 #include <mach/mmc.h>
 #include <mach/irda.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/ohci.h>
 #include <mach/pxa27x_keypad.h>
 #include <mach/pxa2xx_spi.h>
@@ -290,7 +290,7 @@ static struct resource pxa3xx_resources_i2c_power[] = {
 };
 
 struct platform_device pxa3xx_device_i2c_power = {
-       .name           = "pxa2xx-i2c",
+       .name           = "pxa3xx-pwri2c",
        .id             = 1,
        .resource       = pxa3xx_resources_i2c_power,
        .num_resources  = ARRAY_SIZE(pxa3xx_resources_i2c_power),
index bc0f73fbd4ca0ef0c26f56d760005b0c9bf85a0b..243e0802b5f4259aa48f429a185c1b3412dfc28e 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/spi/libertas_spi.h>
 #include <linux/power_supply.h>
 #include <linux/apm-emulation.h>
+#include <linux/i2c.h>
+#include <linux/i2c/pca953x.h>
 
 #include <media/soc_camera.h>
 
@@ -41,7 +43,7 @@
 #include <mach/ohci.h>
 #include <mach/mmc.h>
 #include <mach/pxa27x_keypad.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/camera.h>
 #include <mach/pxa2xx_spi.h>
 
 #define GPIO13_MMC_CD          (13)
 #define GPIO95_MMC_WP          (95)
 #define GPIO56_NAND_RB         (56)
+#define GPIO93_CAM_RESET       (93)
+#define GPIO16_USB_HUB_RESET   (16)
 
 /* eXeda specific GPIOs */
 #define GPIO114_MMC_CD         (114)
 #define GPIO20_NAND_RB         (20)
 #define GPIO38_SD_PWEN         (38)
+#define GPIO37_WLAN_RST                (37)
+#define GPIO95_TOUCHPAD_INT    (95)
+#define GPIO130_CAM_RESET      (130)
+#define GPIO10_USB_HUB_RESET   (10)
 
 /* common  GPIOs */
 #define GPIO11_NAND_CS         (11)
-#define GPIO93_CAM_RESET       (93)
 #define GPIO41_ETHIRQ          (41)
 #define EM_X270_ETHIRQ         IRQ_GPIO(GPIO41_ETHIRQ)
 #define GPIO115_WLAN_PWEN      (115)
 #define GPIO19_WLAN_STRAP      (19)
+#define GPIO9_USB_VBUS_EN      (9)
 
 static int mmc_cd;
 static int nand_rb;
 static int dm9000_flags;
+static int cam_reset;
+static int usb_hub_reset;
 
 static unsigned long common_pin_config[] = {
        /* AC'97 */
@@ -180,7 +190,6 @@ static unsigned long common_pin_config[] = {
 
        /* power controls */
        GPIO20_GPIO     | MFP_LPM_DRIVE_LOW,    /* GPRS_PWEN */
-       GPIO93_GPIO     | MFP_LPM_DRIVE_LOW,    /* Camera reset */
        GPIO115_GPIO    | MFP_LPM_DRIVE_LOW,    /* WLAN_PWEN */
 
        /* NAND controls */
@@ -191,14 +200,18 @@ static unsigned long common_pin_config[] = {
 };
 
 static unsigned long em_x270_pin_config[] = {
-       GPIO13_GPIO,    /* MMC card detect */
-       GPIO56_GPIO,    /* NAND Ready/Busy */
-       GPIO95_GPIO,    /* MMC Write protect */
+       GPIO13_GPIO,                            /* MMC card detect */
+       GPIO16_GPIO,                            /* USB hub reset */
+       GPIO56_GPIO,                            /* NAND Ready/Busy */
+       GPIO93_GPIO     | MFP_LPM_DRIVE_LOW,    /* Camera reset */
+       GPIO95_GPIO,                            /* MMC Write protect */
 };
 
 static unsigned long exeda_pin_config[] = {
+       GPIO10_GPIO,                            /* USB hub reset */
        GPIO20_GPIO,                            /* NAND Ready/Busy */
        GPIO38_GPIO     | MFP_LPM_DRIVE_LOW,    /* SD slot power */
+       GPIO95_GPIO,                            /* touchpad IRQ */
        GPIO114_GPIO,                           /* MMC card detect */
 };
 
@@ -464,18 +477,79 @@ static inline void em_x270_init_nor(void) {}
 
 /* PXA27x OHCI controller setup */
 #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+static struct regulator *em_x270_usb_ldo;
+
+static int em_x270_usb_hub_init(void)
+{
+       int err;
+
+       em_x270_usb_ldo = regulator_get(NULL, "vcc usb");
+       if (IS_ERR(em_x270_usb_ldo))
+               return PTR_ERR(em_x270_usb_ldo);
+
+       err = gpio_request(GPIO9_USB_VBUS_EN, "vbus en");
+       if (err)
+               goto err_free_usb_ldo;
+
+       err = gpio_request(usb_hub_reset, "hub rst");
+       if (err)
+               goto err_free_vbus_gpio;
+
+       /* USB Hub power-on and reset */
+       gpio_direction_output(usb_hub_reset, 0);
+       regulator_enable(em_x270_usb_ldo);
+       gpio_set_value(usb_hub_reset, 1);
+       gpio_set_value(usb_hub_reset, 0);
+       regulator_disable(em_x270_usb_ldo);
+       regulator_enable(em_x270_usb_ldo);
+       gpio_set_value(usb_hub_reset, 1);
+
+       /* enable VBUS */
+       gpio_direction_output(GPIO9_USB_VBUS_EN, 1);
+
+       return 0;
+
+err_free_vbus_gpio:
+       gpio_free(GPIO9_USB_VBUS_EN);
+err_free_usb_ldo:
+       regulator_put(em_x270_usb_ldo);
+
+       return err;
+}
+
 static int em_x270_ohci_init(struct device *dev)
 {
+       int err;
+
+       /* we don't want to entirely disable USB if the HUB init failed */
+       err = em_x270_usb_hub_init();
+       if (err)
+               pr_err("USB Hub initialization failed: %d\n", err);
+
        /* enable port 2 transiever */
        UP2OCR = UP2OCR_HXS | UP2OCR_HXOE;
 
        return 0;
 }
 
+static void em_x270_ohci_exit(struct device *dev)
+{
+       gpio_free(usb_hub_reset);
+       gpio_free(GPIO9_USB_VBUS_EN);
+
+       if (!IS_ERR(em_x270_usb_ldo)) {
+               if (regulator_is_enabled(em_x270_usb_ldo))
+                       regulator_disable(em_x270_usb_ldo);
+
+               regulator_put(em_x270_usb_ldo);
+       }
+}
+
 static struct pxaohci_platform_data em_x270_ohci_platform_data = {
        .port_mode      = PMM_PERPORT_MODE,
        .flags          = ENABLE_PORT1 | ENABLE_PORT2 | POWER_CONTROL_LOW,
        .init           = em_x270_ohci_init,
+       .exit           = em_x270_ohci_exit,
 };
 
 static void __init em_x270_init_ohci(void)
@@ -677,26 +751,52 @@ static int em_x270_libertas_setup(struct spi_device *spi)
        if (err)
                return err;
 
+       err = gpio_request(GPIO19_WLAN_STRAP, "WLAN STRAP");
+       if (err)
+               goto err_free_pwen;
+
+       if (machine_is_exeda()) {
+               err = gpio_request(GPIO37_WLAN_RST, "WLAN RST");
+               if (err)
+                       goto err_free_strap;
+
+               gpio_direction_output(GPIO37_WLAN_RST, 1);
+               msleep(100);
+       }
+
        gpio_direction_output(GPIO19_WLAN_STRAP, 1);
-       mdelay(100);
+       msleep(100);
 
        pxa2xx_mfp_config(ARRAY_AND_SIZE(em_x270_libertas_pin_config));
 
        gpio_direction_output(GPIO115_WLAN_PWEN, 0);
-       mdelay(100);
+       msleep(100);
        gpio_set_value(GPIO115_WLAN_PWEN, 1);
-       mdelay(100);
+       msleep(100);
 
        spi->bits_per_word = 16;
        spi_setup(spi);
 
        return 0;
+
+err_free_strap:
+       gpio_free(GPIO19_WLAN_STRAP);
+err_free_pwen:
+       gpio_free(GPIO115_WLAN_PWEN);
+
+       return err;
 }
 
 static int em_x270_libertas_teardown(struct spi_device *spi)
 {
        gpio_set_value(GPIO115_WLAN_PWEN, 0);
        gpio_free(GPIO115_WLAN_PWEN);
+       gpio_free(GPIO19_WLAN_STRAP);
+
+       if (machine_is_exeda()) {
+               gpio_set_value(GPIO37_WLAN_RST, 0);
+               gpio_free(GPIO37_WLAN_RST);
+       }
 
        return 0;
 }
@@ -863,26 +963,26 @@ static int em_x270_sensor_init(struct device *dev)
 {
        int ret;
 
-       ret = gpio_request(GPIO93_CAM_RESET, "camera reset");
+       ret = gpio_request(cam_reset, "camera reset");
        if (ret)
                return ret;
 
-       gpio_direction_output(GPIO93_CAM_RESET, 0);
+       gpio_direction_output(cam_reset, 0);
 
        em_x270_camera_ldo = regulator_get(NULL, "vcc cam");
        if (em_x270_camera_ldo == NULL) {
-               gpio_free(GPIO93_CAM_RESET);
+               gpio_free(cam_reset);
                return -ENODEV;
        }
 
        ret = regulator_enable(em_x270_camera_ldo);
        if (ret) {
                regulator_put(em_x270_camera_ldo);
-               gpio_free(GPIO93_CAM_RESET);
+               gpio_free(cam_reset);
                return ret;
        }
 
-       gpio_set_value(GPIO93_CAM_RESET, 1);
+       gpio_set_value(cam_reset, 1);
 
        return 0;
 }
@@ -902,7 +1002,7 @@ static int em_x270_sensor_power(struct device *dev, int on)
        if (on == is_on)
                return 0;
 
-       gpio_set_value(GPIO93_CAM_RESET, !on);
+       gpio_set_value(cam_reset, !on);
 
        if (on)
                ret = regulator_enable(em_x270_camera_ldo);
@@ -912,7 +1012,7 @@ static int em_x270_sensor_power(struct device *dev, int on)
        if (ret)
                return ret;
 
-       gpio_set_value(GPIO93_CAM_RESET, on);
+       gpio_set_value(cam_reset, on);
 
        return 0;
 }
@@ -929,13 +1029,8 @@ static struct i2c_board_info em_x270_i2c_cam_info[] = {
        },
 };
 
-static struct i2c_pxa_platform_data em_x270_i2c_info = {
-       .fast_mode = 1,
-};
-
 static void  __init em_x270_init_camera(void)
 {
-       pxa_set_i2c_info(&em_x270_i2c_info);
        i2c_register_board_info(0, ARRAY_AND_SIZE(em_x270_i2c_cam_info));
        pxa_set_camera_info(&em_x270_camera_platform_data);
 }
@@ -985,7 +1080,7 @@ struct led_info em_x270_led_info = {
 };
 
 struct power_supply_info em_x270_psy_info = {
-       .name = "LP555597P6H-FPS",
+       .name = "battery",
        .technology = POWER_SUPPLY_TECHNOLOGY_LIPO,
        .voltage_max_design = 4200000,
        .voltage_min_design = 3000000,
@@ -1069,6 +1164,29 @@ static void __init em_x270_init_da9030(void)
        i2c_register_board_info(1, &em_x270_i2c_pmic_info, 1);
 }
 
+static struct pca953x_platform_data exeda_gpio_ext_pdata = {
+       .gpio_base = 128,
+};
+
+static struct i2c_board_info exeda_i2c_info[] = {
+       {
+               I2C_BOARD_INFO("pca9555", 0x21),
+               .platform_data = &exeda_gpio_ext_pdata,
+       },
+};
+
+static struct i2c_pxa_platform_data em_x270_i2c_info = {
+       .fast_mode = 1,
+};
+
+static void __init em_x270_init_i2c(void)
+{
+       pxa_set_i2c_info(&em_x270_i2c_info);
+
+       if (machine_is_exeda())
+               i2c_register_board_info(0, ARRAY_AND_SIZE(exeda_i2c_info));
+}
+
 static void __init em_x270_module_init(void)
 {
        pr_info("%s\n", __func__);
@@ -1077,6 +1195,8 @@ static void __init em_x270_module_init(void)
        mmc_cd = GPIO13_MMC_CD;
        nand_rb = GPIO56_NAND_RB;
        dm9000_flags = DM9000_PLATF_32BITONLY;
+       cam_reset = GPIO93_CAM_RESET;
+       usb_hub_reset = GPIO16_USB_HUB_RESET;
 }
 
 static void __init em_x270_exeda_init(void)
@@ -1087,12 +1207,18 @@ static void __init em_x270_exeda_init(void)
        mmc_cd = GPIO114_MMC_CD;
        nand_rb = GPIO20_NAND_RB;
        dm9000_flags = DM9000_PLATF_16BITONLY;
+       cam_reset = GPIO130_CAM_RESET;
+       usb_hub_reset = GPIO10_USB_HUB_RESET;
 }
 
 static void __init em_x270_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(common_pin_config));
 
+#ifdef CONFIG_PM
+       pxa27x_set_pwrmode(PWRMODE_DEEPSLEEP);
+#endif
+
        if (machine_is_em_x270())
                em_x270_module_init();
        else if (machine_is_exeda())
@@ -1111,8 +1237,9 @@ static void __init em_x270_init(void)
        em_x270_init_keypad();
        em_x270_init_gpio_keys();
        em_x270_init_ac97();
-       em_x270_init_camera();
        em_x270_init_spi();
+       em_x270_init_i2c();
+       em_x270_init_camera();
 }
 
 MACHINE_START(EM_X270, "Compulab EM-X270")
index 7db966dc29ce50f2e7815e26723794c8e1da639c..588b265e5755e150dad5bb049fec275867515d20 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/delay.h>
 #include <linux/pwm_backlight.h>
 #include <linux/input.h>
+#include <linux/gpio_keys.h>
 
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <mach/pxa27x.h>
 #include <mach/pxafb.h>
 #include <mach/ohci.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/hardware.h>
 #include <mach/pxa27x_keypad.h>
 
 #include "devices.h"
 #include "generic.h"
 
+#define GPIO12_A780_FLIP_LID           12
+#define GPIO15_A1200_FLIP_LID          15
+#define GPIO15_A910_FLIP_LID           15
+#define GPIO12_E680_LOCK_SWITCH        12
+#define GPIO15_E6_LOCK_SWITCH          15
+
 static struct platform_pwm_backlight_data ezx_backlight_data = {
        .pwm_id         = 0,
        .max_brightness = 1023,
@@ -88,7 +95,7 @@ static struct pxafb_mach_info ezx_fb_info_2 = {
        .lcd_conn       = LCD_COLOR_TFT_18BPP,
 };
 
-static struct platform_device *devices[] __initdata = {
+static struct platform_device *ezx_devices[] __initdata = {
        &ezx_backlight_device,
 };
 
@@ -651,6 +658,35 @@ static struct pxa27x_keypad_platform_data e2_keypad_platform_data = {
 #endif /* CONFIG_MACH_EZX_E2 */
 
 #ifdef CONFIG_MACH_EZX_A780
+/* gpio_keys */
+static struct gpio_keys_button a780_buttons[] = {
+       [0] = {
+               .code       = SW_LID,
+               .gpio       = GPIO12_A780_FLIP_LID,
+               .active_low = 0,
+               .desc       = "A780 flip lid",
+               .type       = EV_SW,
+               .wakeup     = 1,
+       },
+};
+
+static struct gpio_keys_platform_data a780_gpio_keys_platform_data = {
+       .buttons  = a780_buttons,
+       .nbuttons = ARRAY_SIZE(a780_buttons),
+};
+
+static struct platform_device a780_gpio_keys = {
+       .name = "gpio-keys",
+       .id   = -1,
+       .dev  = {
+               .platform_data = &a780_gpio_keys_platform_data,
+       },
+};
+
+static struct platform_device *a780_devices[] __initdata = {
+       &a780_gpio_keys,
+};
+
 static void __init a780_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(ezx_pin_config));
@@ -663,7 +699,8 @@ static void __init a780_init(void)
 
        pxa_set_keypad_info(&a780_keypad_platform_data);
 
-       platform_add_devices(devices, ARRAY_SIZE(devices));
+       platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
+       platform_add_devices(ARRAY_AND_SIZE(a780_devices));
 }
 
 MACHINE_START(EZX_A780, "Motorola EZX A780")
@@ -678,10 +715,39 @@ MACHINE_END
 #endif
 
 #ifdef CONFIG_MACH_EZX_E680
+/* gpio_keys */
+static struct gpio_keys_button e680_buttons[] = {
+       [0] = {
+               .code       = KEY_SCREENLOCK,
+               .gpio       = GPIO12_E680_LOCK_SWITCH,
+               .active_low = 0,
+               .desc       = "E680 lock switch",
+               .type       = EV_KEY,
+               .wakeup     = 1,
+       },
+};
+
+static struct gpio_keys_platform_data e680_gpio_keys_platform_data = {
+       .buttons  = e680_buttons,
+       .nbuttons = ARRAY_SIZE(e680_buttons),
+};
+
+static struct platform_device e680_gpio_keys = {
+       .name = "gpio-keys",
+       .id   = -1,
+       .dev  = {
+               .platform_data = &e680_gpio_keys_platform_data,
+       },
+};
+
 static struct i2c_board_info __initdata e680_i2c_board_info[] = {
        { I2C_BOARD_INFO("tea5767", 0x81) },
 };
 
+static struct platform_device *e680_devices[] __initdata = {
+       &e680_gpio_keys,
+};
+
 static void __init e680_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(ezx_pin_config));
@@ -695,7 +761,8 @@ static void __init e680_init(void)
 
        pxa_set_keypad_info(&e680_keypad_platform_data);
 
-       platform_add_devices(devices, ARRAY_SIZE(devices));
+       platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
+       platform_add_devices(ARRAY_AND_SIZE(e680_devices));
 }
 
 MACHINE_START(EZX_E680, "Motorola EZX E680")
@@ -710,10 +777,39 @@ MACHINE_END
 #endif
 
 #ifdef CONFIG_MACH_EZX_A1200
+/* gpio_keys */
+static struct gpio_keys_button a1200_buttons[] = {
+       [0] = {
+               .code       = SW_LID,
+               .gpio       = GPIO15_A1200_FLIP_LID,
+               .active_low = 0,
+               .desc       = "A1200 flip lid",
+               .type       = EV_SW,
+               .wakeup     = 1,
+       },
+};
+
+static struct gpio_keys_platform_data a1200_gpio_keys_platform_data = {
+       .buttons  = a1200_buttons,
+       .nbuttons = ARRAY_SIZE(a1200_buttons),
+};
+
+static struct platform_device a1200_gpio_keys = {
+       .name = "gpio-keys",
+       .id   = -1,
+       .dev  = {
+               .platform_data = &a1200_gpio_keys_platform_data,
+       },
+};
+
 static struct i2c_board_info __initdata a1200_i2c_board_info[] = {
        { I2C_BOARD_INFO("tea5767", 0x81) },
 };
 
+static struct platform_device *a1200_devices[] __initdata = {
+       &a1200_gpio_keys,
+};
+
 static void __init a1200_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(ezx_pin_config));
@@ -727,7 +823,8 @@ static void __init a1200_init(void)
 
        pxa_set_keypad_info(&a1200_keypad_platform_data);
 
-       platform_add_devices(devices, ARRAY_SIZE(devices));
+       platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
+       platform_add_devices(ARRAY_AND_SIZE(a1200_devices));
 }
 
 MACHINE_START(EZX_A1200, "Motorola EZX A1200")
@@ -742,6 +839,35 @@ MACHINE_END
 #endif
 
 #ifdef CONFIG_MACH_EZX_A910
+/* gpio_keys */
+static struct gpio_keys_button a910_buttons[] = {
+       [0] = {
+               .code       = SW_LID,
+               .gpio       = GPIO15_A910_FLIP_LID,
+               .active_low = 0,
+               .desc       = "A910 flip lid",
+               .type       = EV_SW,
+               .wakeup     = 1,
+       },
+};
+
+static struct gpio_keys_platform_data a910_gpio_keys_platform_data = {
+       .buttons  = a910_buttons,
+       .nbuttons = ARRAY_SIZE(a910_buttons),
+};
+
+static struct platform_device a910_gpio_keys = {
+       .name = "gpio-keys",
+       .id   = -1,
+       .dev  = {
+               .platform_data = &a910_gpio_keys_platform_data,
+       },
+};
+
+static struct platform_device *a910_devices[] __initdata = {
+       &a910_gpio_keys,
+};
+
 static void __init a910_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(ezx_pin_config));
@@ -754,7 +880,8 @@ static void __init a910_init(void)
 
        pxa_set_keypad_info(&a910_keypad_platform_data);
 
-       platform_add_devices(devices, ARRAY_SIZE(devices));
+       platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
+       platform_add_devices(ARRAY_AND_SIZE(a910_devices));
 }
 
 MACHINE_START(EZX_A910, "Motorola EZX A910")
@@ -769,10 +896,39 @@ MACHINE_END
 #endif
 
 #ifdef CONFIG_MACH_EZX_E6
+/* gpio_keys */
+static struct gpio_keys_button e6_buttons[] = {
+       [0] = {
+               .code       = KEY_SCREENLOCK,
+               .gpio       = GPIO15_E6_LOCK_SWITCH,
+               .active_low = 0,
+               .desc       = "E6 lock switch",
+               .type       = EV_KEY,
+               .wakeup     = 1,
+       },
+};
+
+static struct gpio_keys_platform_data e6_gpio_keys_platform_data = {
+       .buttons  = e6_buttons,
+       .nbuttons = ARRAY_SIZE(e6_buttons),
+};
+
+static struct platform_device e6_gpio_keys = {
+       .name = "gpio-keys",
+       .id   = -1,
+       .dev  = {
+               .platform_data = &e6_gpio_keys_platform_data,
+       },
+};
+
 static struct i2c_board_info __initdata e6_i2c_board_info[] = {
        { I2C_BOARD_INFO("tea5767", 0x81) },
 };
 
+static struct platform_device *e6_devices[] __initdata = {
+       &e6_gpio_keys,
+};
+
 static void __init e6_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(ezx_pin_config));
@@ -786,7 +942,8 @@ static void __init e6_init(void)
 
        pxa_set_keypad_info(&e6_keypad_platform_data);
 
-       platform_add_devices(devices, ARRAY_SIZE(devices));
+       platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
+       platform_add_devices(ARRAY_AND_SIZE(e6_devices));
 }
 
 MACHINE_START(EZX_E6, "Motorola EZX E6")
@@ -805,6 +962,9 @@ static struct i2c_board_info __initdata e2_i2c_board_info[] = {
        { I2C_BOARD_INFO("tea5767", 0x81) },
 };
 
+static struct platform_device *e2_devices[] __initdata = {
+};
+
 static void __init e2_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(ezx_pin_config));
@@ -818,7 +978,8 @@ static void __init e2_init(void)
 
        pxa_set_keypad_info(&e2_keypad_platform_data);
 
-       platform_add_devices(devices, ARRAY_SIZE(devices));
+       platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
+       platform_add_devices(ARRAY_AND_SIZE(e2_devices));
 }
 
 MACHINE_START(EZX_E2, "Motorola EZX E2")
diff --git a/arch/arm/mach-pxa/hx4700.c b/arch/arm/mach-pxa/hx4700.c
new file mode 100644 (file)
index 0000000..7fff467
--- /dev/null
@@ -0,0 +1,851 @@
+/*
+ * Support for HP iPAQ hx4700 PDAs.
+ *
+ * Copyright (c) 2008-2009 Philipp Zabel
+ *
+ * Based on code:
+ *    Copyright (c) 2004 Hewlett-Packard Company.
+ *    Copyright (c) 2005 SDG Systems, LLC
+ *    Copyright (c) 2006 Anton Vorontsov <cbou@mail.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/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <linux/lcd.h>
+#include <linux/mfd/htc-egpio.h>
+#include <linux/mfd/asic3.h>
+#include <linux/mtd/physmap.h>
+#include <linux/pda_power.h>
+#include <linux/pwm_backlight.h>
+#include <linux/regulator/bq24022.h>
+#include <linux/regulator/machine.h>
+#include <linux/spi/ads7846.h>
+#include <linux/spi/spi.h>
+#include <linux/usb/gpio_vbus.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/pxa27x.h>
+#include <mach/hx4700.h>
+#include <plat/i2c.h>
+#include <mach/irda.h>
+#include <mach/pxa2xx_spi.h>
+
+#include <video/w100fb.h>
+
+#include "devices.h"
+#include "generic.h"
+
+/* Physical address space information */
+
+#define ATI_W3220_PHYS  PXA_CS2_PHYS /* ATI Imageon 3220 Graphics */
+#define ASIC3_PHYS      PXA_CS3_PHYS
+#define ASIC3_SD_PHYS   (PXA_CS3_PHYS + 0x02000000)
+
+static unsigned long hx4700_pin_config[] __initdata = {
+
+       /* SDRAM and Static Memory I/O Signals */
+       GPIO20_nSDCS_2,
+       GPIO21_nSDCS_3,
+       GPIO15_nCS_1,
+       GPIO78_nCS_2,   /* W3220 */
+       GPIO79_nCS_3,   /* ASIC3 */
+       GPIO80_nCS_4,
+       GPIO33_nCS_5,   /* EGPIO, WLAN */
+
+       /* PC CARD */
+       GPIO48_nPOE,
+       GPIO49_nPWE,
+       GPIO50_nPIOR,
+       GPIO51_nPIOW,
+       GPIO54_nPCE_2,
+       GPIO55_nPREG,
+       GPIO56_nPWAIT,
+       GPIO57_nIOIS16,
+       GPIO85_nPCE_1,
+       GPIO104_PSKTSEL,
+
+       /* I2C */
+       GPIO117_I2C_SCL,
+       GPIO118_I2C_SDA,
+
+       /* FFUART (RS-232) */
+       GPIO34_FFUART_RXD,
+       GPIO35_FFUART_CTS,
+       GPIO36_FFUART_DCD,
+       GPIO37_FFUART_DSR,
+       GPIO38_FFUART_RI,
+       GPIO39_FFUART_TXD,
+       GPIO40_FFUART_DTR,
+       GPIO41_FFUART_RTS,
+
+       /* BTUART */
+       GPIO42_BTUART_RXD,
+       GPIO43_BTUART_TXD,
+       GPIO44_BTUART_CTS,
+       GPIO45_BTUART_RTS,
+
+       /* PWM 1 (Backlight) */
+       GPIO17_PWM1_OUT,
+
+       /* I2S */
+       GPIO28_I2S_BITCLK_OUT,
+       GPIO29_I2S_SDATA_IN,
+       GPIO30_I2S_SDATA_OUT,
+       GPIO31_I2S_SYNC,
+       GPIO113_I2S_SYSCLK,
+
+       /* SSP 1 (NavPoint) */
+       GPIO23_SSP1_SCLK,
+       GPIO24_SSP1_SFRM,
+       GPIO25_SSP1_TXD,
+       GPIO26_SSP1_RXD,
+
+       /* SSP 2 (TSC2046) */
+       GPIO19_SSP2_SCLK,
+       GPIO86_SSP2_RXD,
+       GPIO87_SSP2_TXD,
+       GPIO88_GPIO,
+
+       /* HX4700 specific input GPIOs */
+       GPIO12_GPIO,    /* ASIC3_IRQ */
+       GPIO13_GPIO,    /* W3220_IRQ */
+       GPIO14_GPIO,    /* nWLAN_IRQ */
+
+       GPIO10_GPIO,    /* GSM_IRQ */
+       GPIO13_GPIO,    /* CPLD_IRQ */
+       GPIO107_GPIO,   /* DS1WM_IRQ */
+       GPIO108_GPIO,   /* GSM_READY */
+       GPIO58_GPIO,    /* TSC2046_nPENIRQ */
+       GPIO66_GPIO,    /* nSDIO_IRQ */
+};
+
+#define HX4700_GPIO_IN(num, _desc) \
+       { .gpio = (num), .dir = 0, .desc = (_desc) }
+#define HX4700_GPIO_OUT(num, _init, _desc) \
+       { .gpio = (num), .dir = 1, .init = (_init), .desc = (_desc) }
+struct gpio_ress {
+       unsigned gpio : 8;
+       unsigned dir : 1;
+       unsigned init : 1;
+       char *desc;
+};
+
+static int hx4700_gpio_request(struct gpio_ress *gpios, int size)
+{
+       int i, rc = 0;
+       int gpio;
+       int dir;
+
+       for (i = 0; (!rc) && (i < size); i++) {
+               gpio = gpios[i].gpio;
+               dir = gpios[i].dir;
+               rc = gpio_request(gpio, gpios[i].desc);
+               if (rc) {
+                       pr_err("Error requesting GPIO %d(%s) : %d\n",
+                              gpio, gpios[i].desc, rc);
+                       continue;
+               }
+               if (dir)
+                       gpio_direction_output(gpio, gpios[i].init);
+               else
+                       gpio_direction_input(gpio);
+       }
+       while ((rc) && (--i >= 0))
+               gpio_free(gpios[i].gpio);
+       return rc;
+}
+
+/*
+ * IRDA
+ */
+
+static void irda_transceiver_mode(struct device *dev, int mode)
+{
+       gpio_set_value(GPIO105_HX4700_nIR_ON, mode & IR_OFF);
+}
+
+static struct pxaficp_platform_data ficp_info = {
+       .transceiver_cap  = IR_SIRMODE | IR_OFF,
+       .transceiver_mode = irda_transceiver_mode,
+};
+
+/*
+ * GPIO Keys
+ */
+
+#define INIT_KEY(_code, _gpio, _active_low, _desc)     \
+       {                                               \
+               .code       = KEY_##_code,              \
+               .gpio       = _gpio,                    \
+               .active_low = _active_low,              \
+               .desc       = _desc,                    \
+               .type       = EV_KEY,                   \
+               .wakeup     = 1,                        \
+       }
+
+static struct gpio_keys_button gpio_keys_buttons[] = {
+       INIT_KEY(POWER,       GPIO0_HX4700_nKEY_POWER,   1, "Power button"),
+       INIT_KEY(MAIL,        GPIO94_HX4700_KEY_MAIL,    0, "Mail button"),
+       INIT_KEY(ADDRESSBOOK, GPIO99_HX4700_KEY_CONTACTS,0, "Contacts button"),
+       INIT_KEY(RECORD,      GPIOD6_nKEY_RECORD,        1, "Record button"),
+       INIT_KEY(CALENDAR,    GPIOD1_nKEY_CALENDAR,      1, "Calendar button"),
+       INIT_KEY(HOMEPAGE,    GPIOD3_nKEY_HOME,          1, "Home button"),
+};
+
+static struct gpio_keys_platform_data gpio_keys_data = {
+       .buttons = gpio_keys_buttons,
+       .nbuttons = ARRAY_SIZE(gpio_keys_buttons),
+};
+
+static struct platform_device gpio_keys = {
+       .name = "gpio-keys",
+       .dev  = {
+               .platform_data = &gpio_keys_data,
+       },
+       .id   = -1,
+};
+
+/*
+ * ASIC3
+ */
+
+static u16 asic3_gpio_config[] = {
+       /* ASIC3 GPIO banks A and B along with some of C and D
+          implement the buffering for the CF slot. */
+       ASIC3_CONFIG_GPIO(0, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(1, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(2, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(3, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(4, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(5, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(6, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(7, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(8, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(9, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(10, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(11, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(12, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(13, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(14, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(15, 1, 1, 0),
+
+       ASIC3_CONFIG_GPIO(16, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(17, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(18, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(19, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(20, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(21, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(22, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(23, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(24, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(25, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(26, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(27, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(28, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(29, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(30, 1, 1, 0),
+       ASIC3_CONFIG_GPIO(31, 1, 1, 0),
+
+       /* GPIOC - CF, LEDs, SD */
+       ASIC3_GPIOC0_LED0,              /* red */
+       ASIC3_GPIOC1_LED1,              /* green */
+       ASIC3_GPIOC2_LED2,              /* blue */
+       ASIC3_GPIOC4_CF_nCD,
+       ASIC3_GPIOC5_nCIOW,
+       ASIC3_GPIOC6_nCIOR,
+       ASIC3_GPIOC7_nPCE_1,
+       ASIC3_GPIOC8_nPCE_2,
+       ASIC3_GPIOC9_nPOE,
+       ASIC3_GPIOC10_nPWE,
+       ASIC3_GPIOC11_PSKTSEL,
+       ASIC3_GPIOC12_nPREG,
+       ASIC3_GPIOC13_nPWAIT,
+       ASIC3_GPIOC14_nPIOIS16,
+       ASIC3_GPIOC15_nPIOR,
+
+       /* GPIOD: input GPIOs, CF */
+       ASIC3_GPIOD11_nCIOIS16,
+       ASIC3_GPIOD12_nCWAIT,
+       ASIC3_GPIOD15_nPIOW,
+};
+
+static struct resource asic3_resources[] = {
+       /* GPIO part */
+       [0] = {
+               .start  = ASIC3_PHYS,
+               .end    = ASIC3_PHYS + ASIC3_MAP_SIZE_16BIT - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = gpio_to_irq(GPIO12_HX4700_ASIC3_IRQ),
+               .end    = gpio_to_irq(GPIO12_HX4700_ASIC3_IRQ),
+               .flags  = IORESOURCE_IRQ,
+       },
+       /* SD part */
+       [2] = {
+               .start  = ASIC3_SD_PHYS,
+               .end    = ASIC3_SD_PHYS + ASIC3_MAP_SIZE_16BIT - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [3] = {
+               .start  = gpio_to_irq(GPIO66_HX4700_ASIC3_nSDIO_IRQ),
+               .end    = gpio_to_irq(GPIO66_HX4700_ASIC3_nSDIO_IRQ),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct asic3_platform_data asic3_platform_data = {
+       .gpio_config     = asic3_gpio_config,
+       .gpio_config_num = ARRAY_SIZE(asic3_gpio_config),
+       .irq_base        = IRQ_BOARD_START,
+       .gpio_base       = HX4700_ASIC3_GPIO_BASE,
+};
+
+static struct platform_device asic3 = {
+       .name          = "asic3",
+       .id            = -1,
+       .resource      = asic3_resources,
+       .num_resources = ARRAY_SIZE(asic3_resources),
+       .dev = {
+               .platform_data = &asic3_platform_data,
+       },
+};
+
+/*
+ * EGPIO
+ */
+
+static struct resource egpio_resources[] = {
+       [0] = {
+               .start = PXA_CS5_PHYS,
+               .end   = PXA_CS5_PHYS + 0x4 - 1,
+               .flags = IORESOURCE_MEM,
+       },
+};
+
+static struct htc_egpio_chip egpio_chips[] = {
+       [0] = {
+               .reg_start = 0,
+               .gpio_base = HX4700_EGPIO_BASE,
+               .num_gpios = 8,
+               .direction = HTC_EGPIO_OUTPUT,
+       },
+};
+
+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 egpio = {
+       .name          = "htc-egpio",
+       .id            = -1,
+       .resource      = egpio_resources,
+       .num_resources = ARRAY_SIZE(egpio_resources),
+       .dev = {
+               .platform_data = &egpio_info,
+       },
+};
+
+/*
+ * LCD - Sony display connected to ATI Imageon w3220
+ */
+
+static int lcd_power;
+
+static void sony_lcd_init(void)
+{
+       gpio_set_value(GPIO84_HX4700_LCD_SQN, 1);
+       gpio_set_value(GPIO110_HX4700_LCD_LVDD_3V3_ON, 0);
+       gpio_set_value(GPIO111_HX4700_LCD_AVDD_3V3_ON, 0);
+       gpio_set_value(GPIO70_HX4700_LCD_SLIN1, 0);
+       gpio_set_value(GPIO62_HX4700_LCD_nRESET, 0);
+       mdelay(10);
+       gpio_set_value(GPIO59_HX4700_LCD_PC1, 0);
+       gpio_set_value(GPIO110_HX4700_LCD_LVDD_3V3_ON, 0);
+       mdelay(20);
+
+       gpio_set_value(GPIO110_HX4700_LCD_LVDD_3V3_ON, 1);
+       mdelay(5);
+       gpio_set_value(GPIO111_HX4700_LCD_AVDD_3V3_ON, 1);
+
+       /* FIXME: init w3220 registers here */
+
+       mdelay(5);
+       gpio_set_value(GPIO70_HX4700_LCD_SLIN1, 1);
+       mdelay(10);
+       gpio_set_value(GPIO62_HX4700_LCD_nRESET, 1);
+       mdelay(10);
+       gpio_set_value(GPIO59_HX4700_LCD_PC1, 1);
+       mdelay(10);
+       gpio_set_value(GPIO112_HX4700_LCD_N2V7_7V3_ON, 1);
+}
+
+static void sony_lcd_off(void)
+{
+       gpio_set_value(GPIO59_HX4700_LCD_PC1, 0);
+       gpio_set_value(GPIO62_HX4700_LCD_nRESET, 0);
+       mdelay(10);
+       gpio_set_value(GPIO112_HX4700_LCD_N2V7_7V3_ON, 0);
+       mdelay(10);
+       gpio_set_value(GPIO111_HX4700_LCD_AVDD_3V3_ON, 0);
+       mdelay(10);
+       gpio_set_value(GPIO110_HX4700_LCD_LVDD_3V3_ON, 0);
+}
+
+static int hx4700_lcd_set_power(struct lcd_device *ldev, int level)
+{
+       switch (level) {
+       case FB_BLANK_UNBLANK:
+               sony_lcd_init();
+               break;
+       case FB_BLANK_NORMAL:
+       case FB_BLANK_VSYNC_SUSPEND:
+       case FB_BLANK_HSYNC_SUSPEND:
+       case FB_BLANK_POWERDOWN:
+               sony_lcd_off();
+               break;
+       }
+       lcd_power = level;
+       return 0;
+}
+
+static int hx4700_lcd_get_power(struct lcd_device *lm)
+{
+       return lcd_power;
+}
+
+static struct lcd_ops hx4700_lcd_ops = {
+       .get_power = hx4700_lcd_get_power,
+       .set_power = hx4700_lcd_set_power,
+};
+
+static struct lcd_device *hx4700_lcd_device;
+
+#ifdef CONFIG_PM
+static void w3220_lcd_suspend(struct w100fb_par *wfb)
+{
+       sony_lcd_off();
+}
+
+static void w3220_lcd_resume(struct w100fb_par *wfb)
+{
+       sony_lcd_init();
+}
+#else
+#define w3220_lcd_resume       NULL
+#define w3220_lcd_suspend      NULL
+#endif
+
+static struct w100_tg_info w3220_tg_info = {
+       .suspend        = w3220_lcd_suspend,
+       .resume         = w3220_lcd_resume,
+};
+
+/*                              W3220_VGA              QVGA */
+static struct w100_gen_regs w3220_regs = {
+       .lcd_format =        0x00000003,
+       .lcdd_cntl1 =        0x00000000,
+       .lcdd_cntl2 =        0x0003ffff,
+       .genlcd_cntl1 =      0x00abf003,        /* 0x00fff003 */
+       .genlcd_cntl2 =      0x00000003,
+       .genlcd_cntl3 =      0x000102aa,
+};
+
+static struct w100_mode w3220_modes[] = {
+{
+       .xres           = 480,
+       .yres           = 640,
+       .left_margin    = 15,
+       .right_margin   = 16,
+       .upper_margin   = 8,
+       .lower_margin   = 7,
+       .crtc_ss        = 0x00000000,
+       .crtc_ls        = 0xa1ff01f9,   /* 0x21ff01f9 */
+       .crtc_gs        = 0xc0000000,   /* 0x40000000 */
+       .crtc_vpos_gs   = 0x0000028f,
+       .crtc_ps1_active = 0x00000000,  /* 0x41060010 */
+       .crtc_rev       = 0,
+       .crtc_dclk      = 0x80000000,
+       .crtc_gclk      = 0x040a0104,
+       .crtc_goe       = 0,
+       .pll_freq       = 95,
+       .pixclk_divider = 4,
+       .pixclk_divider_rotated = 4,
+       .pixclk_src     = CLK_SRC_PLL,
+       .sysclk_divider = 0,
+       .sysclk_src     = CLK_SRC_PLL,
+},
+{
+       .xres           = 240,
+       .yres           = 320,
+       .left_margin    = 9,
+       .right_margin   = 8,
+       .upper_margin   = 5,
+       .lower_margin   = 4,
+       .crtc_ss        = 0x80150014,
+       .crtc_ls        = 0xa0fb00f7,
+       .crtc_gs        = 0xc0080007,
+       .crtc_vpos_gs   = 0x00080007,
+       .crtc_rev       = 0x0000000a,
+       .crtc_dclk      = 0x81700030,
+       .crtc_gclk      = 0x8015010f,
+       .crtc_goe       = 0x00000000,
+       .pll_freq       = 95,
+       .pixclk_divider = 4,
+       .pixclk_divider_rotated = 4,
+       .pixclk_src     = CLK_SRC_PLL,
+       .sysclk_divider = 0,
+       .sysclk_src     = CLK_SRC_PLL,
+},
+};
+
+struct w100_mem_info w3220_mem_info = {
+       .ext_cntl        = 0x09640011,
+       .sdram_mode_reg  = 0x00600021,
+       .ext_timing_cntl = 0x1a001545,  /* 0x15001545 */
+       .io_cntl         = 0x7ddd7333,
+       .size            = 0x1fffff,
+};
+
+struct w100_bm_mem_info w3220_bm_mem_info = {
+       .ext_mem_bw = 0x50413e01,
+       .offset = 0,
+       .ext_timing_ctl = 0x00043f7f,
+       .ext_cntl = 0x00000010,
+       .mode_reg = 0x00250000,
+       .io_cntl = 0x0fff0000,
+       .config = 0x08301480,
+};
+
+static struct w100_gpio_regs w3220_gpio_info = {
+       .init_data1 = 0xdfe00100,       /* GPIO_DATA */
+       .gpio_dir1  = 0xffff0000,       /* GPIO_CNTL1 */
+       .gpio_oe1   = 0x00000000,       /* GPIO_CNTL2 */
+       .init_data2 = 0x00000000,       /* GPIO_DATA2 */
+       .gpio_dir2  = 0x00000000,       /* GPIO_CNTL3 */
+       .gpio_oe2   = 0x00000000,       /* GPIO_CNTL4 */
+};
+
+static struct w100fb_mach_info w3220_info = {
+       .tg        = &w3220_tg_info,
+       .mem       = &w3220_mem_info,
+       .bm_mem    = &w3220_bm_mem_info,
+       .gpio      = &w3220_gpio_info,
+       .regs      = &w3220_regs,
+       .modelist  = w3220_modes,
+       .num_modes = 2,
+       .xtal_freq = 16000000,
+};
+
+static struct resource w3220_resources[] = {
+       [0] = {
+               .start  = ATI_W3220_PHYS,
+               .end    = ATI_W3220_PHYS + 0x00ffffff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device w3220 = {
+       .name   = "w100fb",
+       .id     = -1,
+       .dev    = {
+               .platform_data = &w3220_info,
+       },
+       .num_resources = ARRAY_SIZE(w3220_resources),
+       .resource      = w3220_resources,
+};
+
+/*
+ * Backlight
+ */
+
+static struct platform_pwm_backlight_data backlight_data = {
+       .pwm_id         = 1,
+       .max_brightness = 200,
+       .dft_brightness = 100,
+       .pwm_period_ns  = 30923,
+};
+
+static struct platform_device backlight = {
+       .name = "pwm-backlight",
+       .id   = -1,
+       .dev  = {
+               .parent        = &pxa27x_device_pwm1.dev,
+               .platform_data = &backlight_data,
+       },
+};
+
+/*
+ * USB "Transceiver"
+ */
+
+static struct gpio_vbus_mach_info gpio_vbus_info = {
+       .gpio_pullup        = GPIO76_HX4700_USBC_PUEN,
+       .gpio_vbus          = GPIOD14_nUSBC_DETECT,
+       .gpio_vbus_inverted = 1,
+};
+
+static struct platform_device gpio_vbus = {
+       .name          = "gpio-vbus",
+       .id            = -1,
+       .dev = {
+               .platform_data = &gpio_vbus_info,
+       },
+};
+
+/*
+ * Touchscreen - TSC2046 connected to SSP2
+ */
+
+static const struct ads7846_platform_data tsc2046_info = {
+       .model            = 7846,
+       .vref_delay_usecs = 100,
+       .pressure_max     = 512,
+       .debounce_max     = 10,
+       .debounce_tol     = 3,
+       .debounce_rep     = 1,
+       .gpio_pendown     = GPIO58_HX4700_TSC2046_nPENIRQ,
+};
+
+static struct pxa2xx_spi_chip tsc2046_chip = {
+       .tx_threshold = 1,
+       .rx_threshold = 2,
+       .timeout      = 64,
+       .gpio_cs      = GPIO88_HX4700_TSC2046_CS,
+};
+
+static struct spi_board_info tsc2046_board_info[] __initdata = {
+       {
+               .modalias        = "ads7846",
+               .bus_num         = 2,
+               .max_speed_hz    = 2600000, /* 100 kHz sample rate */
+               .irq             = gpio_to_irq(GPIO58_HX4700_TSC2046_nPENIRQ),
+               .platform_data   = &tsc2046_info,
+               .controller_data = &tsc2046_chip,
+       },
+};
+
+static struct pxa2xx_spi_master pxa_ssp2_master_info = {
+       .num_chipselect = 1,
+       .clock_enable   = CKEN_SSP2,
+       .enable_dma     = 1,
+};
+
+/*
+ * External power
+ */
+
+static int power_supply_init(struct device *dev)
+{
+       return gpio_request(GPIOD9_nAC_IN, "AC charger detect");
+}
+
+static int hx4700_is_ac_online(void)
+{
+       return !gpio_get_value(GPIOD9_nAC_IN);
+}
+
+static void power_supply_exit(struct device *dev)
+{
+       gpio_free(GPIOD9_nAC_IN);
+}
+
+static char *hx4700_supplicants[] = {
+       "ds2760-battery.0", "backup-battery"
+};
+
+static struct pda_power_pdata power_supply_info = {
+       .init            = power_supply_init,
+       .is_ac_online    = hx4700_is_ac_online,
+       .exit            = power_supply_exit,
+       .supplied_to     = hx4700_supplicants,
+       .num_supplicants = ARRAY_SIZE(hx4700_supplicants),
+};
+
+static struct resource power_supply_resources[] = {
+       [0] = {
+               .name  = "ac",
+               .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE |
+                        IORESOURCE_IRQ_LOWEDGE,
+               .start = gpio_to_irq(GPIOD9_nAC_IN),
+               .end   = gpio_to_irq(GPIOD9_nAC_IN),
+       },
+       [1] = {
+               .name  = "usb",
+               .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE |
+                        IORESOURCE_IRQ_LOWEDGE,
+               .start = gpio_to_irq(GPIOD14_nUSBC_DETECT),
+               .end   = gpio_to_irq(GPIOD14_nUSBC_DETECT),
+       },
+};
+
+static struct platform_device power_supply = {
+       .name = "pda-power",
+       .id   = -1,
+       .dev  = {
+               .platform_data = &power_supply_info,
+       },
+       .resource      = power_supply_resources,
+       .num_resources = ARRAY_SIZE(power_supply_resources),
+};
+
+/*
+ * Battery charger
+ */
+
+static struct regulator_consumer_supply bq24022_consumers[] = {
+       {
+               .dev = &gpio_vbus.dev,
+               .supply = "vbus_draw",
+       },
+       {
+               .dev = &power_supply.dev,
+               .supply = "ac_draw",
+       },
+};
+
+static struct regulator_init_data bq24022_init_data = {
+       .constraints = {
+               .max_uA         = 500000,
+               .valid_ops_mask = REGULATOR_CHANGE_CURRENT,
+       },
+       .num_consumer_supplies  = ARRAY_SIZE(bq24022_consumers),
+       .consumer_supplies      = bq24022_consumers,
+};
+
+static struct bq24022_mach_info bq24022_info = {
+       .gpio_nce   = GPIO72_HX4700_BQ24022_nCHARGE_EN,
+       .gpio_iset2 = GPIO96_HX4700_BQ24022_ISET2,
+       .init_data  = &bq24022_init_data,
+};
+
+static struct platform_device bq24022 = {
+       .name = "bq24022",
+       .id   = -1,
+       .dev  = {
+               .platform_data = &bq24022_info,
+       },
+};
+
+/*
+ * StrataFlash
+ */
+
+static void hx4700_set_vpp(struct map_info *map, int vpp)
+{
+       gpio_set_value(GPIO91_HX4700_FLASH_VPEN, vpp);
+}
+
+static struct resource strataflash_resource = {
+       .start = PXA_CS0_PHYS,
+       .end   = PXA_CS0_PHYS + SZ_128M - 1,
+       .flags = IORESOURCE_MEM,
+};
+
+static struct physmap_flash_data strataflash_data = {
+       .width = 4,
+       .set_vpp = hx4700_set_vpp,
+};
+
+static struct platform_device strataflash = {
+       .name          = "physmap-flash",
+       .id            = -1,
+       .resource      = &strataflash_resource,
+       .num_resources = 1,
+       .dev = {
+               .platform_data = &strataflash_data,
+       },
+};
+
+/*
+ * PCMCIA
+ */
+
+static struct platform_device pcmcia = {
+       .name = "hx4700-pcmcia",
+       .dev  = {
+               .parent = &asic3.dev,
+       },
+};
+
+/*
+ * Platform devices
+ */
+
+static struct platform_device *devices[] __initdata = {
+       &asic3,
+       &gpio_keys,
+       &backlight,
+       &w3220,
+       &egpio,
+       &bq24022,
+       &gpio_vbus,
+       &power_supply,
+       &strataflash,
+       &pcmcia,
+};
+
+static struct gpio_ress global_gpios[] = {
+       HX4700_GPIO_IN(GPIO12_HX4700_ASIC3_IRQ, "ASIC3_IRQ"),
+       HX4700_GPIO_IN(GPIO13_HX4700_W3220_IRQ, "W3220_IRQ"),
+       HX4700_GPIO_IN(GPIO14_HX4700_nWLAN_IRQ, "WLAN_IRQ"),
+       HX4700_GPIO_OUT(GPIO59_HX4700_LCD_PC1,          1, "LCD_PC1"),
+       HX4700_GPIO_OUT(GPIO62_HX4700_LCD_nRESET,       1, "LCD_RESET"),
+       HX4700_GPIO_OUT(GPIO70_HX4700_LCD_SLIN1,        1, "LCD_SLIN1"),
+       HX4700_GPIO_OUT(GPIO84_HX4700_LCD_SQN,          1, "LCD_SQN"),
+       HX4700_GPIO_OUT(GPIO110_HX4700_LCD_LVDD_3V3_ON, 1, "LCD_LVDD"),
+       HX4700_GPIO_OUT(GPIO111_HX4700_LCD_AVDD_3V3_ON, 1, "LCD_AVDD"),
+       HX4700_GPIO_OUT(GPIO32_HX4700_RS232_ON,         1, "RS232_ON"),
+       HX4700_GPIO_OUT(GPIO71_HX4700_ASIC3_nRESET,     1, "ASIC3_nRESET"),
+       HX4700_GPIO_OUT(GPIO82_HX4700_EUART_RESET,      1, "EUART_RESET"),
+       HX4700_GPIO_OUT(GPIO105_HX4700_nIR_ON,          1, "nIR_EN"),
+};
+
+static void __init hx4700_init(void)
+{
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(hx4700_pin_config));
+       hx4700_gpio_request(ARRAY_AND_SIZE(global_gpios));
+
+       platform_add_devices(devices, ARRAY_SIZE(devices));
+
+       pxa_set_ficp_info(&ficp_info);
+       pxa27x_set_i2c_power_info(NULL);
+       pxa_set_i2c_info(NULL);
+       pxa2xx_set_spi_info(2, &pxa_ssp2_master_info);
+       spi_register_board_info(ARRAY_AND_SIZE(tsc2046_board_info));
+
+       hx4700_lcd_device = lcd_device_register("w100fb", NULL,
+                                       (void *)&w3220_info, &hx4700_lcd_ops);
+
+       gpio_set_value(GPIO71_HX4700_ASIC3_nRESET, 0);
+       mdelay(10);
+       gpio_set_value(GPIO71_HX4700_ASIC3_nRESET, 1);
+       mdelay(10);
+}
+
+MACHINE_START(H4700, "HP iPAQ HX4700")
+       .phys_io      = 0x40000000,
+       .io_pg_offst  = (io_p2v(0x40000000) >> 18) & 0xfffc,
+       .boot_params  = 0xa0000100,
+       .map_io       = pxa_map_io,
+       .init_irq     = pxa27x_init_irq,
+       .init_machine = hx4700_init,
+       .timer        = &pxa_timer,
+MACHINE_END
index 2b27336c29f1b6ec517a63fd0881f8e964ff507d..961807dc64670781eec4b282ff1fe6b18aea2b22 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/spi/spi.h>
 #include <linux/i2c.h>
 #include <linux/mfd/da903x.h>
+#include <linux/sht15.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -29,7 +30,7 @@
 #include <asm/mach/flash.h>
 
 #include <mach/pxa27x.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/udc.h>
 #include <mach/mmc.h>
 #include <mach/pxa2xx_spi.h>
@@ -102,6 +103,10 @@ static unsigned long imote2_pin_config[] __initdata = {
        GPIO96_GPIO,    /* accelerometer interrupt */
        GPIO99_GPIO,    /* ADC interrupt */
 
+       /* SHT15 */
+       GPIO100_GPIO,
+       GPIO98_GPIO,
+
        /* Connector pins specified as gpios */
        GPIO94_GPIO, /* large basic connector pin 14 */
        GPIO10_GPIO, /* large basic connector pin 23 */
@@ -112,6 +117,26 @@ static unsigned long imote2_pin_config[] __initdata = {
        GPIO105_GPIO, /* blue led */
 };
 
+static struct sht15_platform_data platform_data_sht15 = {
+       .gpio_data =  100,
+       .gpio_sck  =  98,
+};
+
+static struct platform_device sht15 = {
+       .name = "sht15",
+       .id = -1,
+       .dev = {
+               .platform_data = &platform_data_sht15,
+       },
+};
+
+static struct regulator_consumer_supply imote2_sensor_3_con[] = {
+       {
+               .dev = &sht15.dev,
+               .supply = "vcc",
+       },
+};
+
 static struct gpio_led imote2_led_pins[] = {
        {
                .name       =  "imote2:red",
@@ -257,6 +282,8 @@ static struct regulator_init_data imote2_ldo_init_data[] = {
                        .min_uV = 2800000,
                        .max_uV = 3000000,
                },
+               .num_consumer_supplies = ARRAY_SIZE(imote2_sensor_3_con),
+               .consumer_supplies = imote2_sensor_3_con,
        },
        [vcc_pxa_pll] = { /* 1.17V - 1.43V, default 1.3V*/
                .constraints = {
@@ -432,6 +459,9 @@ static struct i2c_board_info __initdata imote2_i2c_board_info[] = {
                .type = "tmp175",
                .addr = 0x4A,
                .irq = IRQ_GPIO(96),
+       }, { /* IMB400 Multimedia board */
+               .type = "wm8940",
+               .addr = 0x1A,
        },
 };
 
@@ -456,25 +486,12 @@ static struct pxa2xx_spi_master pxa_ssp_master_2_info = {
        .num_chipselect = 1,
 };
 
-/* Patch posted by Eric Miao <eric.miao@marvell.com> will remove
- * the need for these functions.
- */
-static void spi1control(u32 command)
-{
-       gpio_set_value(24, command & PXA2XX_CS_ASSERT ? 0 : 1);
-};
-
-static void spi3control(u32 command)
-{
-       gpio_set_value(39, command & PXA2XX_CS_ASSERT ? 0 : 1);
-};
-
 static struct pxa2xx_spi_chip staccel_chip_info = {
        .tx_threshold = 8,
        .rx_threshold = 8,
        .dma_burst_size = 8,
        .timeout = 235,
-       .cs_control = spi1control,
+       .gpio_cs = 24,
 };
 
 static struct pxa2xx_spi_chip cc2420_info = {
@@ -482,7 +499,7 @@ static struct pxa2xx_spi_chip cc2420_info = {
        .rx_threshold = 8,
        .dma_burst_size = 8,
        .timeout = 235,
-       .cs_control = spi3control,
+       .gpio_cs = 39,
 };
 
 static struct spi_board_info spi_board_info[] __initdata = {
@@ -521,6 +538,7 @@ static struct pxa2xx_udc_mach_info imote2_udc_info __initdata = {
 static struct platform_device *imote2_devices[] = {
        &imote2_flash_device,
        &imote2_leds,
+       &sht15,
 };
 
 static struct i2c_pxa_platform_data i2c_pwr_pdata = {
@@ -538,8 +556,6 @@ static void __init imote2_init(void)
        /* SPI chip select directions - all other directions should
         * be handled by drivers.*/
        gpio_direction_output(37, 0);
-       gpio_direction_output(24, 0);
-       gpio_direction_output(39, 0);
 
        platform_add_devices(imote2_devices, ARRAY_SIZE(imote2_devices));
 
diff --git a/arch/arm/mach-pxa/include/mach/hx4700.h b/arch/arm/mach-pxa/include/mach/hx4700.h
new file mode 100644 (file)
index 0000000..9eaeed1
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * GPIO and IRQ definitions for HP iPAQ hx4700
+ *
+ * Copyright (c) 2008 Philipp Zabel
+ *
+ * This 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 _HX4700_H_
+#define _HX4700_H_
+
+#include <linux/gpio.h>
+#include <linux/mfd/asic3.h>
+
+#define HX4700_ASIC3_GPIO_BASE NR_BUILTIN_GPIO
+#define HX4700_EGPIO_BASE      (HX4700_ASIC3_GPIO_BASE + ASIC3_NUM_GPIOS)
+
+/*
+ * PXA GPIOs
+ */
+
+#define GPIO0_HX4700_nKEY_POWER                        0
+#define GPIO12_HX4700_ASIC3_IRQ                        12
+#define GPIO13_HX4700_W3220_IRQ                        13
+#define GPIO14_HX4700_nWLAN_IRQ                        14
+#define GPIO18_HX4700_RDY                      18
+#define GPIO22_HX4700_LCD_RL                   22
+#define GPIO27_HX4700_CODEC_ON                 27
+#define GPIO32_HX4700_RS232_ON                 32
+#define GPIO52_HX4700_CPU_nBATT_FAULT          52
+#define GPIO58_HX4700_TSC2046_nPENIRQ          58
+#define GPIO59_HX4700_LCD_PC1                  59
+#define GPIO60_HX4700_CF_RNB                   60
+#define GPIO61_HX4700_W3220_nRESET             61
+#define GPIO62_HX4700_LCD_nRESET               62
+#define GPIO63_HX4700_CPU_SS_nRESET            63
+#define GPIO65_HX4700_TSC2046_PEN_PU           65
+#define GPIO66_HX4700_ASIC3_nSDIO_IRQ          66
+#define GPIO67_HX4700_EUART_PS                 67
+#define GPIO70_HX4700_LCD_SLIN1                        70
+#define GPIO71_HX4700_ASIC3_nRESET             71
+#define GPIO72_HX4700_BQ24022_nCHARGE_EN       72
+#define GPIO73_HX4700_LCD_UD_1                 73
+#define GPIO75_HX4700_EARPHONE_nDET            75
+#define GPIO76_HX4700_USBC_PUEN                        76
+#define GPIO81_HX4700_CPU_GP_nRESET            81
+#define GPIO82_HX4700_EUART_RESET              82
+#define GPIO83_HX4700_WLAN_nRESET              83
+#define GPIO84_HX4700_LCD_SQN                  84
+#define GPIO85_HX4700_nPCE1                    85
+#define GPIO88_HX4700_TSC2046_CS               88
+#define GPIO91_HX4700_FLASH_VPEN               91
+#define GPIO92_HX4700_HP_DRIVER                        92
+#define GPIO93_HX4700_EUART_INT                        93
+#define GPIO94_HX4700_KEY_MAIL                 94
+#define GPIO95_HX4700_BATT_OFF                 95
+#define GPIO96_HX4700_BQ24022_ISET2            96
+#define GPIO97_HX4700_nBL_DETECT               97
+#define GPIO99_HX4700_KEY_CONTACTS             99
+#define GPIO100_HX4700_AUTO_SENSE              100 /* BL auto brightness */
+#define GPIO102_HX4700_SYNAPTICS_POWER_ON      102
+#define GPIO103_HX4700_SYNAPTICS_INT           103
+#define GPIO105_HX4700_nIR_ON                  105
+#define GPIO106_HX4700_CPU_BT_nRESET           106
+#define GPIO107_HX4700_SPK_nSD                 107
+#define GPIO109_HX4700_CODEC_nPDN              109
+#define GPIO110_HX4700_LCD_LVDD_3V3_ON         110
+#define GPIO111_HX4700_LCD_AVDD_3V3_ON         111
+#define GPIO112_HX4700_LCD_N2V7_7V3_ON         112
+#define GPIO114_HX4700_CF_RESET                        114
+#define GPIO116_HX4700_CPU_HW_nRESET           116
+
+/*
+ * ASIC3 GPIOs
+ */
+
+#define GPIOC_BASE             (HX4700_ASIC3_GPIO_BASE + 32)
+#define GPIOD_BASE             (HX4700_ASIC3_GPIO_BASE + 48)
+
+#define GPIOC0_LED_RED         (GPIOC_BASE + 0)
+#define GPIOC1_LED_GREEN       (GPIOC_BASE + 1)
+#define GPIOC2_LED_BLUE                (GPIOC_BASE + 2)
+#define GPIOC3_nSD_CS          (GPIOC_BASE + 3)
+#define GPIOC4_CF_nCD          (GPIOC_BASE + 4)        /* Input */
+#define GPIOC5_nCIOW           (GPIOC_BASE + 5)        /* Output, to CF */
+#define GPIOC6_nCIOR           (GPIOC_BASE + 6)        /* Output, to CF */
+#define GPIOC7_nPCE1           (GPIOC_BASE + 7)        /* Input, from CPU */
+#define GPIOC8_nPCE2           (GPIOC_BASE + 8)        /* Input, from CPU */
+#define GPIOC9_nPOE            (GPIOC_BASE + 9)        /* Input, from CPU */
+#define GPIOC10_CF_nPWE                (GPIOC_BASE + 10)       /* Input */
+#define GPIOC11_PSKTSEL                (GPIOC_BASE + 11)       /* Input, from CPU */
+#define GPIOC12_nPREG          (GPIOC_BASE + 12)       /* Input, from CPU */
+#define GPIOC13_nPWAIT         (GPIOC_BASE + 13)       /* Output, to CPU */
+#define GPIOC14_nPIOIS16       (GPIOC_BASE + 14)       /* Output, to CPU */
+#define GPIOC15_nPIOR          (GPIOC_BASE + 15)       /* Input, from CPU */
+
+#define GPIOD0_CPU_SS_INT      (GPIOD_BASE + 0)        /* Input */
+#define GPIOD1_nKEY_CALENDAR   (GPIOD_BASE + 1)
+#define GPIOD2_BLUETOOTH_WAKEUP        (GPIOD_BASE + 2)
+#define GPIOD3_nKEY_HOME       (GPIOD_BASE + 3)
+#define GPIOD4_CF_nCD          (GPIOD_BASE + 4)        /* Input, from CF */
+#define GPIOD5_nPIO            (GPIOD_BASE + 5)        /* Input */
+#define GPIOD6_nKEY_RECORD     (GPIOD_BASE + 6)
+#define GPIOD7_nSDIO_DETECT    (GPIOD_BASE + 7)
+#define GPIOD8_COM_DCD         (GPIOD_BASE + 8)        /* Input */
+#define GPIOD9_nAC_IN          (GPIOD_BASE + 9)
+#define GPIOD10_nSDIO_IRQ      (GPIOD_BASE + 10)       /* Input */
+#define GPIOD11_nCIOIS16       (GPIOD_BASE + 11)       /* Input, from CF */
+#define GPIOD12_nCWAIT         (GPIOD_BASE + 12)       /* Input, from CF */
+#define GPIOD13_CF_RNB         (GPIOD_BASE + 13)       /* Input */
+#define GPIOD14_nUSBC_DETECT   (GPIOD_BASE + 14)
+#define GPIOD15_nPIOW          (GPIOD_BASE + 15)       /* Input, from CPU */
+
+/*
+ * EGPIOs
+ */
+
+#define EGPIO0_VCC_3V3_EN      (HX4700_EGPIO_BASE + 0) /* WLAN support chip */
+#define EGPIO1_WL_VREG_EN      (HX4700_EGPIO_BASE + 1) /* WLAN power */
+#define EGPIO2_VCC_2V1_WL_EN   (HX4700_EGPIO_BASE + 2) /* unused */
+#define EGPIO3_SS_PWR_ON       (HX4700_EGPIO_BASE + 3) /* smart slot power */
+#define EGPIO4_CF_3V3_ON       (HX4700_EGPIO_BASE + 4) /* CF 3.3V enable */
+#define EGPIO5_BT_3V3_ON       (HX4700_EGPIO_BASE + 5) /* BT 3.3V enable */
+#define EGPIO6_WL1V8_EN                (HX4700_EGPIO_BASE + 6) /* WLAN 1.8V enable */
+#define EGPIO7_VCC_3V3_WL_EN   (HX4700_EGPIO_BASE + 7) /* WLAN 3.3V enable */
+#define EGPIO8_USB_3V3_ON      (HX4700_EGPIO_BASE + 8) /* unused */
+
+#endif /* _HX4700_H_ */
diff --git a/arch/arm/mach-pxa/include/mach/i2c.h b/arch/arm/mach-pxa/include/mach/i2c.h
deleted file mode 100644 (file)
index 1a9f65e..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- *  i2c_pxa.h
- *
- *  Copyright (C) 2002 Intrinsyc Software 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 _I2C_PXA_H_
-#define _I2C_PXA_H_
-
-#if 0
-#define DEF_TIMEOUT             3
-#else
-/* need a longer timeout if we're dealing with the fact we may well be
- * looking at a multi-master environment
-*/
-#define DEF_TIMEOUT             32
-#endif
-
-#define BUS_ERROR               (-EREMOTEIO)
-#define XFER_NAKED              (-ECONNREFUSED)
-#define I2C_RETRY               (-2000) /* an error has occurred retry transmit */
-
-/* ICR initialize bit values
-*
-*  15. FM       0 (100 Khz operation)
-*  14. UR       0 (No unit reset)
-*  13. SADIE    0 (Disables the unit from interrupting on slave addresses
-*                                       matching its slave address)
-*  12. ALDIE    0 (Disables the unit from interrupt when it loses arbitration
-*                                       in master mode)
-*  11. SSDIE    0 (Disables interrupts from a slave stop detected, in slave mode)
-*  10. BEIE     1 (Enable interrupts from detected bus errors, no ACK sent)
-*  9.  IRFIE    1 (Enable interrupts from full buffer received)
-*  8.  ITEIE    1 (Enables the I2C unit to interrupt when transmit buffer empty)
-*  7.  GCD      1 (Disables i2c unit response to general call messages as a slave)
-*  6.  IUE      0 (Disable unit until we change settings)
-*  5.  SCLE     1 (Enables the i2c clock output for master mode (drives SCL)
-*  4.  MA       0 (Only send stop with the ICR stop bit)
-*  3.  TB       0 (We are not transmitting a byte initially)
-*  2.  ACKNAK   0 (Send an ACK after the unit receives a byte)
-*  1.  STOP     0 (Do not send a STOP)
-*  0.  START    0 (Do not send a START)
-*
-*/
-#define I2C_ICR_INIT   (ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE)
-
-/* I2C status register init values
- *
- * 10. BED      1 (Clear bus error detected)
- * 9.  SAD      1 (Clear slave address detected)
- * 7.  IRF      1 (Clear IDBR Receive Full)
- * 6.  ITE      1 (Clear IDBR Transmit Empty)
- * 5.  ALD      1 (Clear Arbitration Loss Detected)
- * 4.  SSD      1 (Clear Slave Stop Detected)
- */
-#define I2C_ISR_INIT   0x7FF  /* status register init */
-
-struct i2c_slave_client;
-
-struct i2c_pxa_platform_data {
-       unsigned int            slave_addr;
-       struct i2c_slave_client *slave;
-       unsigned int            class;
-       unsigned int            use_pio :1;
-       unsigned int            fast_mode :1;
-};
-
-extern void pxa_set_i2c_info(struct i2c_pxa_platform_data *info);
-
-#ifdef CONFIG_PXA27x
-extern void pxa27x_set_i2c_power_info(struct i2c_pxa_platform_data *info);
-#endif
-
-#ifdef CONFIG_PXA3xx
-extern void pxa3xx_set_i2c_power_info(struct i2c_pxa_platform_data *info);
-#endif
-
-#endif
index 32bb4a2eb7f13660f43889d5aec7cdcdec07c97e..6a1d95993342438cd320f8e3b1bdc527f951fb37 100644 (file)
 #define IRQ_TO_GPIO(i) (((i) < IRQ_GPIO(2)) ? ((i) - IRQ_GPIO0) : IRQ_TO_GPIO_2_x(i))
 
 /*
- * The next 16 interrupts are for board specific purposes.  Since
+ * The following interrupts are for board specific purposes. Since
  * the kernel can only run on one machine at a time, we can re-use
- * these.  If you need more, increase IRQ_BOARD_END, but keep it
- * within sensible limits.
+ * these.  There will be 16 IRQs by default.  If it is not enough,
+ * IRQ_BOARD_END is allowed be customized for each board, but keep
+ * the numbers within sensible limits and in descending order, so
+ * when multiple config options are selected, the maximum will be
+ * used.
  */
 #define IRQ_BOARD_START                (PXA_GPIO_IRQ_BASE + PXA_GPIO_IRQ_NUM)
+
+#if defined(CONFIG_MACH_H4700)
+#define IRQ_BOARD_END          (IRQ_BOARD_START + 70)
+#elif defined(CONFIG_MACH_ZYLONITE)
+#define IRQ_BOARD_END          (IRQ_BOARD_START + 32)
+#else
 #define IRQ_BOARD_END          (IRQ_BOARD_START + 16)
+#endif
 
 #define IRQ_SA1111_START       (IRQ_BOARD_END)
 #define IRQ_GPAIN0             (IRQ_BOARD_END + 0)
 #define NR_IRQS                        (IRQ_LOCOMO_SPI_TEND + 1)
 #elif defined(CONFIG_PXA_HAVE_BOARD_IRQS)
 #define NR_IRQS                        (IRQ_BOARD_END)
-#elif defined(CONFIG_MACH_ZYLONITE)
-#define NR_IRQS                        (IRQ_BOARD_START + 32)
 #else
 #define NR_IRQS                        (IRQ_BOARD_START)
 #endif
index 07897e61d05afa7ec4af40c6744d83ea8575758c..3ce4682eabb6a1fd582c6a97963a5c8b945bcd09 100644 (file)
 #define GPIO41_UART1_TXD       MFP_CFG_LPM(GPIO41, AF4, FLOAT)
 #define GPIO42_UART1_RXD       MFP_CFG_LPM(GPIO42, AF4, FLOAT)
 #define GPIO42_UART1_TXD       MFP_CFG_LPM(GPIO42, AF2, FLOAT)
+#define GPIO75_UART1_RXD       MFP_CFG_LPM(GPIO75, AF1, FLOAT)
+#define GPIO76_UART1_RXD       MFP_CFG_LPM(GPIO76, AF3, FLOAT)
+#define GPIO76_UART1_TXD       MFP_CFG_LPM(GPIO76, AF1, FLOAT)
 #define GPIO97_UART1_RXD       MFP_CFG_LPM(GPIO97, AF1, FLOAT)
 #define GPIO97_UART1_TXD       MFP_CFG_LPM(GPIO97, AF6, FLOAT)
 #define GPIO98_UART1_RXD       MFP_CFG_LPM(GPIO98, AF6, FLOAT)
 #define GPIO43_UART1_RTS       MFP_CFG_LPM(GPIO43, AF4, FLOAT)
 #define GPIO48_UART1_CTS       MFP_CFG_LPM(GPIO48, AF4, FLOAT)
 #define GPIO48_UART1_RTS       MFP_CFG_LPM(GPIO48, AF2, FLOAT)
+#define GPIO77_UART1_CTS       MFP_CFG_LPM(GPIO77, AF1, FLOAT)
+#define GPIO82_UART1_RTS       MFP_CFG_LPM(GPIO82, AF1, FLOAT)
+#define GPIO82_UART1_CTS       MFP_CFG_LPM(GPIO82, AF3, FLOAT)
 #define GPIO99_UART1_CTS       MFP_CFG_LPM(GPIO99, AF1, FLOAT)
 #define GPIO99_UART1_RTS       MFP_CFG_LPM(GPIO99, AF6, FLOAT)
 #define GPIO104_UART1_CTS      MFP_CFG_LPM(GPIO104, AF6, FLOAT)
 #define GPIO45_UART1_DSR       MFP_CFG_LPM(GPIO45, AF2, FLOAT)
 #define GPIO47_UART1_DTR       MFP_CFG_LPM(GPIO47, AF2, FLOAT)
 #define GPIO47_UART1_DSR       MFP_CFG_LPM(GPIO47, AF4, FLOAT)
+#define GPIO79_UART1_DSR       MFP_CFG_LPM(GPIO79, AF1, FLOAT)
+#define GPIO81_UART1_DTR       MFP_CFG_LPM(GPIO81, AF1, FLOAT)
+#define GPIO81_UART1_DSR       MFP_CFG_LPM(GPIO81, AF3, FLOAT)
 #define GPIO101_UART1_DTR      MFP_CFG_LPM(GPIO101, AF6, FLOAT)
 #define GPIO101_UART1_DSR      MFP_CFG_LPM(GPIO101, AF1, FLOAT)
 #define GPIO103_UART1_DTR      MFP_CFG_LPM(GPIO103, AF1, FLOAT)
 #define GPIO103_UART1_DSR      MFP_CFG_LPM(GPIO103, AF6, FLOAT)
 #define GPIO44_UART1_DCD       MFP_CFG_LPM(GPIO44, AF2, FLOAT)
+#define GPIO78_UART1_DCD       MFP_CFG_LPM(GPIO78, AF1, FLOAT)
 #define GPIO100_UART1_DCD      MFP_CFG_LPM(GPIO100, AF1, FLOAT)
 #define GPIO46_UART1_RI                MFP_CFG_LPM(GPIO46, AF2, FLOAT)
+#define GPIO80_UART1_RI                MFP_CFG_LPM(GPIO80, AF1, FLOAT)
 #define GPIO102_UART1_RI       MFP_CFG_LPM(GPIO102, AF1, FLOAT)
 
 /* UART2 */
 
 #define GPIO2_RDY              MFP_CFG(GPIO2, AF1)
 #define GPIO5_NPIOR            MFP_CFG(GPIO5, AF3)
+#define GPIO6_NPIOW            MFP_CFG(GPIO6, AF3)
+#define GPIO7_NPIOS16          MFP_CFG(GPIO7, AF3)
+#define GPIO8_NPWAIT           MFP_CFG(GPIO8, AF3)
 
 #define GPIO11_PWM0_OUT                MFP_CFG(GPIO11, AF1)
 #define GPIO12_PWM1_OUT                MFP_CFG(GPIO12, AF1)
index fb13c82ad6dcdbe5f1c148b67e1705e55347d203..8721b80102211f3d6607702f8efd03a14db20666 100644 (file)
@@ -56,7 +56,6 @@
 #define GPIO_NR_PALMLD_LED_AMBER       94
 
 /* IDE */
-#define GPIO_NR_PALMLD_IDE_IRQ         95
 #define GPIO_NR_PALMLD_IDE_RESET       98
 #define GPIO_NR_PALMLD_IDE_PWEN                115
 
index a6eeef8a075f4f1918e4f8b8a7137d834209f64e..fd8360c6839d5a69d9faa44fa3bb77c3edb0dc06 100644 (file)
@@ -27,6 +27,8 @@ extern void pxa27x_cpu_suspend(unsigned int);
 extern void pxa_cpu_resume(void);
 
 extern int pxa_pm_enter(suspend_state_t state);
+extern int pxa_pm_prepare(void);
+extern void pxa_pm_finish(void);
 
 /* NOTE: this is for PM debugging on Lubbock,  it's really a big
  * ugly, but let's keep the crap minimum here, instead of direct
index 6876e16c2970dc541c079227adf8127d27947c93..0b702693f4583eef6088febcc96d50f986f6873e 100644 (file)
@@ -16,4 +16,7 @@
 #define ARB_DMA_PARK           (1<<25)    /* Be parked with DMA when idle */
 #define ARB_CORE_PARK          (1<<24)    /* Be parked with core when idle */
 #define ARB_LOCK_FLAG          (1<<23)    /* Only Locking masters gain access to the bus */
+
+extern int __init pxa27x_set_pwrmode(unsigned int mode);
+
 #endif /* __MACH_PXA27x_H */
diff --git a/arch/arm/mach-pxa/include/mach/sharpsl_pm.h b/arch/arm/mach-pxa/include/mach/sharpsl_pm.h
new file mode 100644 (file)
index 0000000..1920dc6
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * SharpSL Battery/PM Driver
+ *
+ * Copyright (c) 2004-2005 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.
+ *
+ */
+#ifndef _MACH_SHARPSL_PM
+#define _MACH_SHARPSL_PM
+
+struct sharpsl_charger_machinfo {
+       void (*init)(void);
+       void (*exit)(void);
+       int gpio_acin;
+       int gpio_batfull;
+       int batfull_irq;
+       int gpio_batlock;
+       int gpio_fatal;
+       void (*discharge)(int);
+       void (*discharge1)(int);
+       void (*charge)(int);
+       void (*measure_temp)(int);
+       void (*presuspend)(void);
+       void (*postsuspend)(void);
+       void (*earlyresume)(void);
+       unsigned long (*read_devdata)(int);
+#define SHARPSL_BATT_VOLT       1
+#define SHARPSL_BATT_TEMP       2
+#define SHARPSL_ACIN_VOLT       3
+#define SHARPSL_STATUS_ACIN     4
+#define SHARPSL_STATUS_LOCK     5
+#define SHARPSL_STATUS_CHRGFULL 6
+#define SHARPSL_STATUS_FATAL    7
+       unsigned long (*charger_wakeup)(void);
+       int (*should_wakeup)(unsigned int resume_on_alarm);
+       void (*backlight_limit)(int);
+       int (*backlight_get_status) (void);
+       int charge_on_volt;
+       int charge_on_temp;
+       int charge_acin_high;
+       int charge_acin_low;
+       int fatal_acin_volt;
+       int fatal_noacin_volt;
+       int bat_levels;
+       struct battery_thresh *bat_levels_noac;
+       struct battery_thresh *bat_levels_acin;
+       struct battery_thresh *bat_levels_noac_bl;
+       struct battery_thresh *bat_levels_acin_bl;
+       int status_high_acin;
+       int status_low_acin;
+       int status_high_noac;
+       int status_low_noac;
+};
+
+struct battery_thresh {
+       int voltage;
+       int percentage;
+};
+
+struct battery_stat {
+       int ac_status;         /* APM AC Present/Not Present */
+       int mainbat_status;    /* APM Main Battery Status */
+       int mainbat_percent;   /* Main Battery Percentage Charge */
+       int mainbat_voltage;   /* Main Battery Voltage */
+};
+
+struct sharpsl_pm_status {
+       struct device *dev;
+       struct timer_list ac_timer;
+       struct timer_list chrg_full_timer;
+
+       int charge_mode;
+#define CHRG_ERROR    (-1)
+#define CHRG_OFF      (0)
+#define CHRG_ON       (1)
+#define CHRG_DONE     (2)
+
+       unsigned int flags;
+#define SHARPSL_SUSPENDED       (1 << 0)  /* Device is Suspended */
+#define SHARPSL_ALARM_ACTIVE    (1 << 1)  /* Alarm is for charging event (not user) */
+#define SHARPSL_BL_LIMIT        (1 << 2)  /* Backlight Intensity Limited */
+#define SHARPSL_APM_QUEUED      (1 << 3)  /* APM Event Queued */
+#define SHARPSL_DO_OFFLINE_CHRG (1 << 4)  /* Trigger the offline charger */
+
+       int full_count;
+       unsigned long charge_start_time;
+       struct sharpsl_charger_machinfo *machinfo;
+       struct battery_stat battstat;
+};
+
+extern struct sharpsl_pm_status sharpsl_pm;
+
+
+#define SHARPSL_LED_ERROR  2
+#define SHARPSL_LED_ON     1
+#define SHARPSL_LED_OFF    0
+
+void sharpsl_battery_kick(void);
+void sharpsl_pm_led(int val);
+
+#endif
index 5706cea95d1188e69a1788cb92c5422a7375badd..b54749413e96faaea2dca232580b79409fc2e4a9 100644 (file)
@@ -36,7 +36,8 @@ static inline void flush(void)
 static inline void arch_decomp_setup(void)
 {
        if (machine_is_littleton() || machine_is_intelmote2()
-                       || machine_is_csb726())
+           || machine_is_csb726() || machine_is_stargate2()
+           || machine_is_cm_x300())
                UART = STUART;
 }
 
index c872b9feb4d404506396687e7bc52f7b71b5e3d4..55b3788fd1ae9c8aa4cc8ec8d47e9ab1ad48a8e6 100644 (file)
 #include <mach/pxa300.h>
 #include <mach/pxafb.h>
 #include <mach/ssp.h>
+#include <mach/mmc.h>
 #include <mach/pxa2xx_spi.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/pxa27x_keypad.h>
 #include <mach/pxa3xx_nand.h>
 #include <mach/littleton.h>
 
 #include "generic.h"
 
+#define GPIO_MMC1_CARD_DETECT  mfp_to_gpio(MFP_PIN_GPIO15)
+
 /* Littleton MFP configurations */
 static mfp_cfg_t littleton_mfp_cfg[] __initdata = {
        /* LCD */
@@ -98,6 +101,15 @@ static mfp_cfg_t littleton_mfp_cfg[] __initdata = {
        GPIO123_KP_MKOUT_2,
        GPIO124_KP_MKOUT_3,
        GPIO125_KP_MKOUT_4,
+
+       /* MMC1 */
+       GPIO3_MMC1_DAT0,
+       GPIO4_MMC1_DAT1,
+       GPIO5_MMC1_DAT2,
+       GPIO6_MMC1_DAT3,
+       GPIO7_MMC1_CLK,
+       GPIO8_MMC1_CMD,
+       GPIO15_GPIO, /* card detect */
 };
 
 static struct resource smc91x_resources[] = {
@@ -179,15 +191,10 @@ static struct pxa2xx_spi_master littleton_spi_info = {
        .num_chipselect         = 1,
 };
 
-static void littleton_tdo24m_cs(u32 cmd)
-{
-       gpio_set_value(LITTLETON_GPIO_LCD_CS, !(cmd == PXA2XX_CS_ASSERT));
-}
-
 static struct pxa2xx_spi_chip littleton_tdo24m_chip = {
        .rx_threshold   = 1,
        .tx_threshold   = 1,
-       .cs_control     = littleton_tdo24m_cs,
+       .gpio_cs        = LITTLETON_GPIO_LCD_CS,
 };
 
 static struct spi_board_info littleton_spi_devices[] __initdata = {
@@ -202,16 +209,6 @@ static struct spi_board_info littleton_spi_devices[] __initdata = {
 
 static void __init littleton_init_spi(void)
 {
-       int err;
-
-       err = gpio_request(LITTLETON_GPIO_LCD_CS, "LCD_CS");
-       if (err) {
-               pr_warning("failed to request GPIO for LCS CS\n");
-               return;
-       }
-
-       gpio_direction_output(LITTLETON_GPIO_LCD_CS, 1);
-
        pxa2xx_set_spi_info(2, &littleton_spi_info);
        spi_register_board_info(ARRAY_AND_SIZE(littleton_spi_devices));
 }
@@ -267,6 +264,56 @@ static void __init littleton_init_keypad(void)
 static inline void littleton_init_keypad(void) {}
 #endif
 
+#if defined(CONFIG_MMC_PXA) || defined(CONFIG_MMC_PXA_MODULE)
+static int littleton_mci_init(struct device *dev,
+                             irq_handler_t littleton_detect_int, void *data)
+{
+       int err, gpio_cd = GPIO_MMC1_CARD_DETECT;
+
+       err = gpio_request(gpio_cd, "mmc card detect");
+       if (err)
+               goto err_request_cd;
+
+       gpio_direction_input(gpio_cd);
+
+       err = request_irq(gpio_to_irq(gpio_cd), littleton_detect_int,
+                         IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+                         "mmc card detect", data);
+       if (err) {
+               dev_err(dev, "failed to request card detect IRQ\n");
+               goto err_request_irq;
+       }
+       return 0;
+
+err_request_irq:
+       gpio_free(gpio_cd);
+err_request_cd:
+       return err;
+}
+
+static void littleton_mci_exit(struct device *dev, void *data)
+{
+       int gpio_cd = GPIO_MMC1_CARD_DETECT;
+
+       free_irq(gpio_to_irq(gpio_cd), data);
+       gpio_free(gpio_cd);
+}
+
+static struct pxamci_platform_data littleton_mci_platform_data = {
+       .detect_delay   = 20,
+       .ocr_mask       = MMC_VDD_32_33 | MMC_VDD_33_34,
+       .init           = littleton_mci_init,
+       .exit           = littleton_mci_exit,
+};
+
+static void __init littleton_init_mmc(void)
+{
+       pxa_set_mci_info(&littleton_mci_platform_data);
+}
+#else
+static inline void littleton_init_mmc(void) {}
+#endif
+
 #if defined(CONFIG_MTD_NAND_PXA3xx) || defined(CONFIG_MTD_NAND_PXA3xx_MODULE)
 static struct mtd_partition littleton_nand_partitions[] = {
        [0] = {
@@ -407,6 +454,7 @@ static void __init littleton_init(void)
 
        littleton_init_spi();
        littleton_init_i2c();
+       littleton_init_mmc();
        littleton_init_lcd();
        littleton_init_keypad();
        littleton_init_nand();
index c899bbd94dc06bad6fbbcb9d57133281667fe509..ca39669cffc508adc980e35774951d9aeabbc855 100644 (file)
@@ -36,7 +36,7 @@
 #include <mach/pxa27x.h>
 #include <mach/magician.h>
 #include <mach/pxafb.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/mmc.h>
 #include <mach/irda.h>
 #include <mach/ohci.h>
@@ -744,6 +744,14 @@ static struct platform_device strataflash = {
        },
 };
 
+/*
+ * I2C
+ */
+
+static struct i2c_pxa_platform_data i2c_info = {
+       .fast_mode = 1,
+};
+
 /*
  * Platform devices
  */
@@ -771,7 +779,7 @@ static void __init magician_init(void)
 
        pxa2xx_mfp_config(ARRAY_AND_SIZE(magician_pin_config));
 
-       platform_add_devices(devices, ARRAY_SIZE(devices));
+       platform_add_devices(ARRAY_AND_SIZE(devices));
 
        err = gpio_request(GPIO83_MAGICIAN_nIR_EN, "nIR_EN");
        if (!err) {
@@ -779,7 +787,7 @@ static void __init magician_init(void)
                pxa_set_ficp_info(&magician_ficp_info);
        }
        pxa27x_set_i2c_power_info(NULL);
-       pxa_set_i2c_info(NULL);
+       pxa_set_i2c_info(&i2c_info);
        pxa_set_mci_info(&magician_mci_info);
        pxa_set_ohci_info(&magician_ohci_info);
 
index a6c8429e975f53b3aa720b7619498700bd6e3afa..f4dabf0273ca2d6beb4030c4cd23d112ffe25f50 100644 (file)
@@ -46,7 +46,7 @@
 #include <mach/mainstone.h>
 #include <mach/audio.h>
 #include <mach/pxafb.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/mmc.h>
 #include <mach/irda.h>
 #include <mach/ohci.h>
index ff8052ce0a0567785535a8d3b79bb3aeefb6ec96..4dc8c2ec40a912cffbab11e676f5f53bd046049d 100644 (file)
@@ -48,7 +48,7 @@
 #include <mach/mmc.h>
 #include <mach/udc.h>
 #include <mach/pxa27x-udc.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/camera.h>
 #include <mach/audio.h>
 #include <media/soc_camera.h>
@@ -798,7 +798,7 @@ static void mioa701_restart(char c, const char *cmd)
        arm_machine_restart('s', cmd);
 }
 
-struct gpio_ress global_gpios[] = {
+static struct gpio_ress global_gpios[] = {
        MIO_GPIO_OUT(GPIO9_CHARGE_EN, 1, "Charger enable"),
        MIO_GPIO_OUT(GPIO18_POWEROFF, 0, "Power Off"),
        MIO_GPIO_OUT(GPIO87_LCD_POWER, 0, "LCD Power")
index 471a853e548b9bd861280b4a9ede88c4d1156be5..ed70f281dd090812f71dac139aaa795660b7b0dd 100644 (file)
@@ -129,7 +129,7 @@ static unsigned long palmld_pin_config[] __initdata = {
        GPIO81_GPIO,    /* wifi reset */
 
        /* HDD */
-       GPIO95_GPIO,    /* HDD irq */
+       GPIO98_GPIO,    /* HDD reset */
        GPIO115_GPIO,   /* HDD power */
 
        /* MISC */
@@ -495,6 +495,14 @@ static struct platform_device palmld_asoc = {
        },
 };
 
+/******************************************************************************
+ * HDD
+ ******************************************************************************/
+static struct platform_device palmld_hdd = {
+       .name   = "pata_palmld",
+       .id     = -1,
+};
+
 /******************************************************************************
  * Framebuffer
  ******************************************************************************/
@@ -524,30 +532,18 @@ static struct pxafb_mach_info palmld_lcd_screen = {
 /******************************************************************************
  * Power management - standby
  ******************************************************************************/
-#ifdef CONFIG_PM
-static u32 *addr __initdata;
-static u32 resume[3] __initdata = {
-       0xe3a00101,     /* mov  r0,     #0x40000000 */
-       0xe380060f,     /* orr  r0, r0, #0x00f00000 */
-       0xe590f008,     /* ldr  pc, [r0, #0x08] */
-};
-
-static int __init palmld_pm_init(void)
+static void __init palmld_pm_init(void)
 {
-       int i;
-
-       /* this is where the bootloader jumps */
-       addr = phys_to_virt(PALMLD_STR_BASE);
-
-       for (i = 0; i < 3; i++)
-               addr[i] = resume[i];
-
-       return 0;
+       static u32 resume[] = {
+               0xe3a00101,     /* mov  r0,     #0x40000000 */
+               0xe380060f,     /* orr  r0, r0, #0x00f00000 */
+               0xe590f008,     /* ldr  pc, [r0, #0x08] */
+       };
+
+       /* copy the bootloader */
+       memcpy(phys_to_virt(PALMLD_STR_BASE), resume, sizeof(resume));
 }
 
-device_initcall(palmld_pm_init);
-#endif
-
 /******************************************************************************
  * Machine init
  ******************************************************************************/
@@ -559,6 +555,7 @@ static struct platform_device *devices[] __initdata = {
        &palmld_leds,
        &power_supply,
        &palmld_asoc,
+       &palmld_hdd,
 };
 
 static struct map_desc palmld_io_desc[] __initdata = {
@@ -586,6 +583,7 @@ static void __init palmld_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(palmld_pin_config));
 
+       palmld_pm_init();
        set_pxa_fb_info(&palmld_lcd_screen);
        pxa_set_mci_info(&palmld_mci_platform_data);
        pxa_set_ac97_info(&palmld_ac97_pdata);
index 05bf979b78a668d3a4a9c256944bdbaeb7dc1de3..aae64a12a734e2ce82d2e91cca54d27d0b1cd345 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/gpio.h>
 #include <linux/wm97xx_batt.h>
 #include <linux/power_supply.h>
+#include <linux/usb/gpio_vbus.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -343,11 +344,18 @@ static struct pxaficp_platform_data palmt5_ficp_platform_data = {
 /******************************************************************************
  * UDC
  ******************************************************************************/
-static struct pxa2xx_udc_mach_info palmt5_udc_info __initdata = {
+static struct gpio_vbus_mach_info palmt5_udc_info = {
        .gpio_vbus              = GPIO_NR_PALMT5_USB_DETECT_N,
        .gpio_vbus_inverted     = 1,
        .gpio_pullup            = GPIO_NR_PALMT5_USB_PULLUP,
-       .gpio_pullup_inverted   = 0,
+};
+
+static struct platform_device palmt5_gpio_vbus = {
+       .name   = "gpio-vbus",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &palmt5_udc_info,
+       },
 };
 
 /******************************************************************************
@@ -466,30 +474,18 @@ static struct pxafb_mach_info palmt5_lcd_screen = {
 /******************************************************************************
  * Power management - standby
  ******************************************************************************/
-#ifdef CONFIG_PM
-static u32 *addr __initdata;
-static u32 resume[3] __initdata = {
-       0xe3a00101,     /* mov  r0,     #0x40000000 */
-       0xe380060f,     /* orr  r0, r0, #0x00f00000 */
-       0xe590f008,     /* ldr  pc, [r0, #0x08] */
-};
-
-static int __init palmt5_pm_init(void)
+static void __init palmt5_pm_init(void)
 {
-       int i;
-
-       /* this is where the bootloader jumps */
-       addr = phys_to_virt(PALMT5_STR_BASE);
-
-       for (i = 0; i < 3; i++)
-               addr[i] = resume[i];
-
-       return 0;
+       static u32 resume[] = {
+               0xe3a00101,     /* mov  r0,     #0x40000000 */
+               0xe380060f,     /* orr  r0, r0, #0x00f00000 */
+               0xe590f008,     /* ldr  pc, [r0, #0x08] */
+       };
+
+       /* copy the bootloader */
+       memcpy(phys_to_virt(PALMT5_STR_BASE), resume, sizeof(resume));
 }
 
-device_initcall(palmt5_pm_init);
-#endif
-
 /******************************************************************************
  * Machine init
  ******************************************************************************/
@@ -500,6 +496,7 @@ static struct platform_device *devices[] __initdata = {
        &palmt5_backlight,
        &power_supply,
        &palmt5_asoc,
+       &palmt5_gpio_vbus,
 };
 
 /* setup udc GPIOs initial state */
@@ -515,14 +512,15 @@ static void __init palmt5_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(palmt5_pin_config));
 
+       palmt5_pm_init();
        set_pxa_fb_info(&palmt5_lcd_screen);
        pxa_set_mci_info(&palmt5_mci_platform_data);
        palmt5_udc_init();
        pxa_set_ac97_info(&palmt5_ac97_pdata);
-       pxa_set_udc_info(&palmt5_udc_info);
        pxa_set_ficp_info(&palmt5_ficp_platform_data);
        pxa_set_keypad_info(&palmt5_keypad_platform_data);
        wm97xx_bat_set_pdata(&wm97xx_batt_pdata);
+
        platform_add_devices(devices, ARRAY_SIZE(devices));
 }
 
index 43fcf2e868875cd17bb738f1df1ca0a6a6ea9813..d823b09801df5865c1b279233fc2d04a0ee49b43 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/gpio.h>
 #include <linux/wm97xx_batt.h>
 #include <linux/power_supply.h>
+#include <linux/usb/gpio_vbus.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -37,6 +38,7 @@
 #include <mach/mfp-pxa25x.h>
 #include <mach/irda.h>
 #include <mach/udc.h>
+#include <mach/palmasoc.h>
 
 #include "generic.h"
 #include "devices.h"
@@ -107,6 +109,7 @@ static unsigned long palmte2_pin_config[] __initdata = {
        GPIO1_RST,      /* reset */
        GPIO4_GPIO,     /* Hotsync button */
        GPIO9_GPIO,     /* power detect */
+       GPIO15_GPIO,    /* earphone detect */
        GPIO37_GPIO,    /* LCD power */
        GPIO56_GPIO,    /* Backlight power */
 };
@@ -318,11 +321,18 @@ static struct pxaficp_platform_data palmte2_ficp_platform_data = {
 /******************************************************************************
  * UDC
  ******************************************************************************/
-static struct pxa2xx_udc_mach_info palmte2_udc_info __initdata = {
+static struct gpio_vbus_mach_info palmte2_udc_info = {
        .gpio_vbus              = GPIO_NR_PALMTE2_USB_DETECT_N,
        .gpio_vbus_inverted     = 1,
        .gpio_pullup            = GPIO_NR_PALMTE2_USB_PULLUP,
-       .gpio_pullup_inverted   = 0,
+};
+
+static struct platform_device palmte2_gpio_vbus = {
+       .name   = "gpio-vbus",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &palmte2_udc_info,
+       },
 };
 
 /******************************************************************************
@@ -394,6 +404,21 @@ static struct wm97xx_batt_info wm97xx_batt_pdata = {
        .batt_name      = "main-batt",
 };
 
+/******************************************************************************
+ * aSoC audio
+ ******************************************************************************/
+static struct palm27x_asoc_info palmte2_asoc_pdata = {
+       .jack_gpio      = GPIO_NR_PALMTE2_EARPHONE_DETECT,
+};
+
+static struct platform_device palmte2_asoc = {
+       .name = "palm27x-asoc",
+       .id   = -1,
+       .dev  = {
+               .platform_data = &palmte2_asoc_pdata,
+       },
+};
+
 /******************************************************************************
  * Framebuffer
  ******************************************************************************/
@@ -429,6 +454,8 @@ static struct platform_device *devices[] __initdata = {
 #endif
        &palmte2_backlight,
        &power_supply,
+       &palmte2_asoc,
+       &palmte2_gpio_vbus,
 };
 
 /* setup udc GPIOs initial state */
@@ -447,7 +474,6 @@ static void __init palmte2_init(void)
        set_pxa_fb_info(&palmte2_lcd_screen);
        pxa_set_mci_info(&palmte2_mci_platform_data);
        palmte2_udc_init();
-       pxa_set_udc_info(&palmte2_udc_info);
        pxa_set_ac97_info(NULL);
        pxa_set_ficp_info(&palmte2_ficp_platform_data);
        wm97xx_bat_set_pdata(&wm97xx_batt_pdata);
index e99a893c58a78b2589fefae2345b019cab98b92f..6c15d84bde53a4853d1ac8e8aa8c119e47ca421e 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/gpio.h>
 #include <linux/wm97xx_batt.h>
 #include <linux/power_supply.h>
+#include <linux/usb/gpio_vbus.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -359,11 +360,18 @@ static struct pxaficp_platform_data palmtx_ficp_platform_data = {
 /******************************************************************************
  * UDC
  ******************************************************************************/
-static struct pxa2xx_udc_mach_info palmtx_udc_info __initdata = {
+static struct gpio_vbus_mach_info palmtx_udc_info = {
        .gpio_vbus              = GPIO_NR_PALMTX_USB_DETECT_N,
        .gpio_vbus_inverted     = 1,
        .gpio_pullup            = GPIO_NR_PALMTX_USB_PULLUP,
-       .gpio_pullup_inverted   = 0,
+};
+
+static struct platform_device palmtx_gpio_vbus = {
+       .name   = "gpio-vbus",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &palmtx_udc_info,
+       },
 };
 
 /******************************************************************************
@@ -483,30 +491,18 @@ static struct pxafb_mach_info palmtx_lcd_screen = {
 /******************************************************************************
  * Power management - standby
  ******************************************************************************/
-#ifdef CONFIG_PM
-static u32 *addr __initdata;
-static u32 resume[3] __initdata = {
-       0xe3a00101,     /* mov  r0,     #0x40000000 */
-       0xe380060f,     /* orr  r0, r0, #0x00f00000 */
-       0xe590f008,     /* ldr  pc, [r0, #0x08] */
-};
-
-static int __init palmtx_pm_init(void)
+static void __init palmtx_pm_init(void)
 {
-       int i;
-
-       /* this is where the bootloader jumps */
-       addr = phys_to_virt(PALMTX_STR_BASE);
-
-       for (i = 0; i < 3; i++)
-               addr[i] = resume[i];
-
-       return 0;
+       static u32 resume[] = {
+               0xe3a00101,     /* mov  r0,     #0x40000000 */
+               0xe380060f,     /* orr  r0, r0, #0x00f00000 */
+               0xe590f008,     /* ldr  pc, [r0, #0x08] */
+       };
+
+       /* copy the bootloader */
+       memcpy(phys_to_virt(PALMTX_STR_BASE), resume, sizeof(resume));
 }
 
-device_initcall(palmtx_pm_init);
-#endif
-
 /******************************************************************************
  * Machine init
  ******************************************************************************/
@@ -517,6 +513,7 @@ static struct platform_device *devices[] __initdata = {
        &palmtx_backlight,
        &power_supply,
        &palmtx_asoc,
+       &palmtx_gpio_vbus,
 };
 
 static struct map_desc palmtx_io_desc[] __initdata = {
@@ -548,11 +545,11 @@ static void __init palmtx_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(palmtx_pin_config));
 
+       palmtx_pm_init();
        set_pxa_fb_info(&palmtx_lcd_screen);
        pxa_set_mci_info(&palmtx_mci_platform_data);
        palmtx_udc_init();
        pxa_set_ac97_info(&palmtx_ac97_pdata);
-       pxa_set_udc_info(&palmtx_udc_info);
        pxa_set_ficp_info(&palmtx_ficp_platform_data);
        pxa_set_keypad_info(&palmtx_keypad_platform_data);
        wm97xx_bat_set_pdata(&wm97xx_batt_pdata);
index 6c12b5a3132f1fc5ddcde76ed241b525464e01a8..095521e9ee246755980af5a59f76986f89ecb59c 100644 (file)
@@ -28,7 +28,7 @@
 #include <media/soc_camera.h>
 
 #include <asm/gpio.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/camera.h>
 #include <asm/mach/map.h>
 #include <mach/pxa27x.h>
index 884b174c8ead93d42c4f9966b84e09ea583e25a5..7693355ee637a60a5496bd980580380c0d19df39 100644 (file)
@@ -79,7 +79,7 @@ static int pxa_pm_valid(suspend_state_t state)
        return -EINVAL;
 }
 
-static int pxa_pm_prepare(void)
+int pxa_pm_prepare(void)
 {
        int ret = 0;
 
@@ -89,7 +89,7 @@ static int pxa_pm_prepare(void)
        return ret;
 }
 
-static void pxa_pm_finish(void)
+void pxa_pm_finish(void)
 {
        if (pxa_cpu_pm_fns && pxa_cpu_pm_fns->finish)
                pxa_cpu_pm_fns->finish();
index 036bbde4d22133fd6bfe7390ddc357259fdc01da..ac431ed10399b3dc017efd3590ce6556ecd2d150 100644 (file)
@@ -39,7 +39,7 @@
 #include <mach/pxa25x.h>
 #include <mach/mmc.h>
 #include <mach/udc.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/irda.h>
 #include <mach/poodle.h>
 #include <mach/pxafb.h>
@@ -214,13 +214,8 @@ static struct ads7846_platform_data poodle_ads7846_info = {
        .gpio_pendown           = POODLE_GPIO_TP_INT,
 };
 
-static void ads7846_cs(u32 command)
-{
-       gpio_set_value(POODLE_GPIO_TP_CS, !(command == PXA2XX_CS_ASSERT));
-}
-
 static struct pxa2xx_spi_chip poodle_ads7846_chip = {
-       .cs_control             = ads7846_cs,
+       .gpio_cs                = POODLE_GPIO_TP_CS,
 };
 
 static struct spi_board_info poodle_spi_devices[] = {
@@ -236,14 +231,6 @@ static struct spi_board_info poodle_spi_devices[] = {
 
 static void __init poodle_init_spi(void)
 {
-       int err;
-
-       err = gpio_request(POODLE_GPIO_TP_CS, "ADS7846_CS");
-       if (err)
-               return;
-
-       gpio_direction_output(POODLE_GPIO_TP_CS, 1);
-
        pxa2xx_set_spi_info(1, &poodle_spi_info);
        spi_register_board_info(ARRAY_AND_SIZE(poodle_spi_devices));
 }
diff --git a/arch/arm/mach-pxa/pwm.c b/arch/arm/mach-pxa/pwm.c
deleted file mode 100644 (file)
index fcdd374..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * linux/arch/arm/mach-pxa/pwm.c
- *
- * simple driver for PWM (Pulse Width Modulator) controller
- *
- * This 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.
- *
- * 2008-02-13  initial version
- *             eric miao <eric.miao@marvell.com>
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/pwm.h>
-
-#include <asm/div64.h>
-
-/* PWM registers and bits definitions */
-#define PWMCR          (0x00)
-#define PWMDCR         (0x04)
-#define PWMPCR         (0x08)
-
-#define PWMCR_SD       (1 << 6)
-#define PWMDCR_FD      (1 << 10)
-
-struct pwm_device {
-       struct list_head        node;
-       struct platform_device *pdev;
-
-       const char      *label;
-       struct clk      *clk;
-       int             clk_enabled;
-       void __iomem    *mmio_base;
-
-       unsigned int    use_count;
-       unsigned int    pwm_id;
-};
-
-/*
- * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE
- * duty_ns   = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
- */
-int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
-{
-       unsigned long long c;
-       unsigned long period_cycles, prescale, pv, dc;
-
-       if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
-               return -EINVAL;
-
-       c = clk_get_rate(pwm->clk);
-       c = c * period_ns;
-       do_div(c, 1000000000);
-       period_cycles = c;
-
-       if (period_cycles < 1)
-               period_cycles = 1;
-       prescale = (period_cycles - 1) / 1024;
-       pv = period_cycles / (prescale + 1) - 1;
-
-       if (prescale > 63)
-               return -EINVAL;
-
-       if (duty_ns == period_ns)
-               dc = PWMDCR_FD;
-       else
-               dc = (pv + 1) * duty_ns / period_ns;
-
-       /* NOTE: the clock to PWM has to be enabled first
-        * before writing to the registers
-        */
-       clk_enable(pwm->clk);
-       __raw_writel(prescale, pwm->mmio_base + PWMCR);
-       __raw_writel(dc, pwm->mmio_base + PWMDCR);
-       __raw_writel(pv, pwm->mmio_base + PWMPCR);
-       clk_disable(pwm->clk);
-
-       return 0;
-}
-EXPORT_SYMBOL(pwm_config);
-
-int pwm_enable(struct pwm_device *pwm)
-{
-       int rc = 0;
-
-       if (!pwm->clk_enabled) {
-               rc = clk_enable(pwm->clk);
-               if (!rc)
-                       pwm->clk_enabled = 1;
-       }
-       return rc;
-}
-EXPORT_SYMBOL(pwm_enable);
-
-void pwm_disable(struct pwm_device *pwm)
-{
-       if (pwm->clk_enabled) {
-               clk_disable(pwm->clk);
-               pwm->clk_enabled = 0;
-       }
-}
-EXPORT_SYMBOL(pwm_disable);
-
-static DEFINE_MUTEX(pwm_lock);
-static LIST_HEAD(pwm_list);
-
-struct pwm_device *pwm_request(int pwm_id, const char *label)
-{
-       struct pwm_device *pwm;
-       int found = 0;
-
-       mutex_lock(&pwm_lock);
-
-       list_for_each_entry(pwm, &pwm_list, node) {
-               if (pwm->pwm_id == pwm_id) {
-                       found = 1;
-                       break;
-               }
-       }
-
-       if (found) {
-               if (pwm->use_count == 0) {
-                       pwm->use_count++;
-                       pwm->label = label;
-               } else
-                       pwm = ERR_PTR(-EBUSY);
-       } else
-               pwm = ERR_PTR(-ENOENT);
-
-       mutex_unlock(&pwm_lock);
-       return pwm;
-}
-EXPORT_SYMBOL(pwm_request);
-
-void pwm_free(struct pwm_device *pwm)
-{
-       mutex_lock(&pwm_lock);
-
-       if (pwm->use_count) {
-               pwm->use_count--;
-               pwm->label = NULL;
-       } else
-               pr_warning("PWM device already freed\n");
-
-       mutex_unlock(&pwm_lock);
-}
-EXPORT_SYMBOL(pwm_free);
-
-static inline void __add_pwm(struct pwm_device *pwm)
-{
-       mutex_lock(&pwm_lock);
-       list_add_tail(&pwm->node, &pwm_list);
-       mutex_unlock(&pwm_lock);
-}
-
-static struct pwm_device *pwm_probe(struct platform_device *pdev,
-               unsigned int pwm_id, struct pwm_device *parent_pwm)
-{
-       struct pwm_device *pwm;
-       struct resource *r;
-       int ret = 0;
-
-       pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
-       if (pwm == NULL) {
-               dev_err(&pdev->dev, "failed to allocate memory\n");
-               return ERR_PTR(-ENOMEM);
-       }
-
-       pwm->clk = clk_get(&pdev->dev, NULL);
-       if (IS_ERR(pwm->clk)) {
-               ret = PTR_ERR(pwm->clk);
-               goto err_free;
-       }
-       pwm->clk_enabled = 0;
-
-       pwm->use_count = 0;
-       pwm->pwm_id = pwm_id;
-       pwm->pdev = pdev;
-
-       if (parent_pwm != NULL) {
-               /* registers for the second PWM has offset of 0x10 */
-               pwm->mmio_base = parent_pwm->mmio_base + 0x10;
-               __add_pwm(pwm);
-               return pwm;
-       }
-
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (r == NULL) {
-               dev_err(&pdev->dev, "no memory resource defined\n");
-               ret = -ENODEV;
-               goto err_free_clk;
-       }
-
-       r = request_mem_region(r->start, r->end - r->start + 1, pdev->name);
-       if (r == NULL) {
-               dev_err(&pdev->dev, "failed to request memory resource\n");
-               ret = -EBUSY;
-               goto err_free_clk;
-       }
-
-       pwm->mmio_base = ioremap(r->start, r->end - r->start + 1);
-       if (pwm->mmio_base == NULL) {
-               dev_err(&pdev->dev, "failed to ioremap() registers\n");
-               ret = -ENODEV;
-               goto err_free_mem;
-       }
-
-       __add_pwm(pwm);
-       platform_set_drvdata(pdev, pwm);
-       return pwm;
-
-err_free_mem:
-       release_mem_region(r->start, r->end - r->start + 1);
-err_free_clk:
-       clk_put(pwm->clk);
-err_free:
-       kfree(pwm);
-       return ERR_PTR(ret);
-}
-
-static int __devinit pxa25x_pwm_probe(struct platform_device *pdev)
-{
-       struct pwm_device *pwm = pwm_probe(pdev, pdev->id, NULL);
-
-       if (IS_ERR(pwm))
-               return PTR_ERR(pwm);
-
-       return 0;
-}
-
-static int __devinit pxa27x_pwm_probe(struct platform_device *pdev)
-{
-       struct pwm_device *pwm;
-
-       pwm = pwm_probe(pdev, pdev->id, NULL);
-       if (IS_ERR(pwm))
-               return PTR_ERR(pwm);
-
-       pwm = pwm_probe(pdev, pdev->id + 2, pwm);
-       if (IS_ERR(pwm))
-               return PTR_ERR(pwm);
-
-       return 0;
-}
-
-static int __devexit pwm_remove(struct platform_device *pdev)
-{
-       struct pwm_device *pwm;
-       struct resource *r;
-
-       pwm = platform_get_drvdata(pdev);
-       if (pwm == NULL)
-               return -ENODEV;
-
-       mutex_lock(&pwm_lock);
-       list_del(&pwm->node);
-       mutex_unlock(&pwm_lock);
-
-       iounmap(pwm->mmio_base);
-
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(r->start, r->end - r->start + 1);
-
-       clk_put(pwm->clk);
-       kfree(pwm);
-       return 0;
-}
-
-static struct platform_driver pxa25x_pwm_driver = {
-       .driver         = {
-               .name   = "pxa25x-pwm",
-       },
-       .probe          = pxa25x_pwm_probe,
-       .remove         = __devexit_p(pwm_remove),
-};
-
-static struct platform_driver pxa27x_pwm_driver = {
-       .driver         = {
-               .name   = "pxa27x-pwm",
-       },
-       .probe          = pxa27x_pwm_probe,
-       .remove         = __devexit_p(pwm_remove),
-};
-
-static int __init pwm_init(void)
-{
-       int ret = 0;
-
-       ret = platform_driver_register(&pxa25x_pwm_driver);
-       if (ret) {
-               printk(KERN_ERR "failed to register pxa25x_pwm_driver\n");
-               return ret;
-       }
-
-       ret = platform_driver_register(&pxa27x_pwm_driver);
-       if (ret) {
-               printk(KERN_ERR "failed to register pxa27x_pwm_driver\n");
-               return ret;
-       }
-
-       return ret;
-}
-arch_initcall(pwm_init);
-
-static void __exit pwm_exit(void)
-{
-       platform_driver_unregister(&pxa25x_pwm_driver);
-       platform_driver_unregister(&pxa27x_pwm_driver);
-}
-module_exit(pwm_exit);
-
-MODULE_LICENSE("GPL v2");
index a425ec71e657cb5bd9ed55beb228bf2523b2b653..ec68cc16b4e3347631ee427854b99d505e551692 100644 (file)
@@ -27,7 +27,7 @@
 #include <mach/ohci.h>
 #include <mach/pm.h>
 #include <mach/dma.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 
 #include "generic.h"
 #include "devices.h"
@@ -203,6 +203,23 @@ static struct clk_lookup pxa27x_clkregs[] = {
 #define SAVE(x)                sleep_save[SLEEP_SAVE_##x] = x
 #define RESTORE(x)     x = sleep_save[SLEEP_SAVE_##x]
 
+/*
+ * allow platforms to override default PWRMODE setting used for PM_SUSPEND_MEM
+ */
+static unsigned int pwrmode = PWRMODE_SLEEP;
+
+int __init pxa27x_set_pwrmode(unsigned int mode)
+{
+       switch (mode) {
+       case PWRMODE_SLEEP:
+       case PWRMODE_DEEPSLEEP:
+               pwrmode = mode;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
 /*
  * List of global PXA peripheral registers to preserve.
  * More ones like CP and general purpose register values are preserved
@@ -254,7 +271,7 @@ void pxa27x_cpu_pm_enter(suspend_state_t state)
                pxa_cpu_standby();
                break;
        case PM_SUSPEND_MEM:
-               pxa27x_cpu_suspend(PWRMODE_SLEEP);
+               pxa27x_cpu_suspend(pwrmode);
                break;
        }
 }
index b02d4544dc956d98b065760dbd6975208bc527b8..6f678d93bf4eb2f0da4b1a142c39945d127503be 100644 (file)
@@ -30,7 +30,7 @@
 #include <mach/pm.h>
 #include <mach/dma.h>
 #include <mach/ssp.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 
 #include "generic.h"
 #include "devices.h"
@@ -552,7 +552,7 @@ void __init pxa3xx_set_i2c_power_info(struct i2c_pxa_platform_data *info)
 }
 
 static struct platform_device *devices[] __initdata = {
-/*     &pxa_device_udc,        The UDC driver is PXA25x only */
+       &pxa27x_device_udc,
        &pxa_device_ffuart,
        &pxa_device_btuart,
        &pxa_device_stuart,
index ff82399914305a69318dce021eab022bb5164396..8241a63ea589bc1b56ae429af465c0c5c0cd032c 100644 (file)
@@ -27,7 +27,7 @@
 #include <asm/mach/arch.h>
 
 #include <mach/pxa930.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/pxafb.h>
 
 #include "devices.h"
index 047909a76651fb377aca1a5e0677e4ca5a21f771..55259f4756c8993e0b5c7bd5e9aa0beb1f77a13b 100644 (file)
@@ -7,7 +7,7 @@
  *
  */
 
-#include <asm/hardware/sharpsl_pm.h>
+#include <mach/sharpsl_pm.h>
 
 /*
  * SharpSL SSP Driver
@@ -44,8 +44,6 @@ void corgi_lcdtg_hw_init(int mode);
 
 extern struct battery_thresh spitz_battery_levels_acin[];
 extern struct battery_thresh spitz_battery_levels_noac[];
-void sharpsl_pm_pxa_init(void);
-void sharpsl_pm_pxa_remove(void);
 int sharpsl_pm_pxa_read_max1111(int channel);
 
 
index 16b4ec67e3b6c03c41ff2b6316dc6613a27738fc..2546c066cd6e9b2c1fdbf932e3793797ea5b8898 100644 (file)
 #undef DEBUG
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
-#include <linux/irq.h>
 #include <linux/platform_device.h>
 #include <linux/apm-emulation.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/leds.h>
+#include <linux/suspend.h>
+#include <linux/gpio.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <mach/pm.h>
+#include <mach/pxa2xx-regs.h>
 #include <mach/pxa2xx-gpio.h>
+#include <mach/regs-rtc.h>
 #include <mach/sharpsl.h>
+#include <mach/sharpsl_pm.h>
+
 #include "sharpsl.h"
 
+/*
+ * Constants
+ */
+#define SHARPSL_CHARGE_ON_TIME_INTERVAL        (msecs_to_jiffies(1*60*1000))  /* 1 min */
+#define SHARPSL_CHARGE_FINISH_TIME             (msecs_to_jiffies(10*60*1000)) /* 10 min */
+#define SHARPSL_BATCHK_TIME                    (msecs_to_jiffies(15*1000))    /* 15 sec */
+#define SHARPSL_BATCHK_TIME_SUSPEND            (60*10)                        /* 10 min */
+
+#define SHARPSL_WAIT_CO_TIME                   15  /* 15 sec */
+#define SHARPSL_WAIT_DISCHARGE_ON              100 /* 100 msec */
+#define SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP   10  /* 10 msec */
+#define SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT   10  /* 10 msec */
+#define SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN   10  /* 10 msec */
+#define SHARPSL_CHARGE_WAIT_TIME               15  /* 15 msec */
+#define SHARPSL_CHARGE_CO_CHECK_TIME           5   /* 5 msec */
+#define SHARPSL_CHARGE_RETRY_CNT               1   /* eqv. 10 min */
+
+/*
+ * Prototypes
+ */
+#ifdef CONFIG_PM
+static int sharpsl_off_charge_battery(void);
+static int sharpsl_check_battery_voltage(void);
+static int sharpsl_fatal_check(void);
+#endif
+static int sharpsl_check_battery_temp(void);
+static int sharpsl_ac_check(void);
+static int sharpsl_average_value(int ad);
+static void sharpsl_average_clear(void);
+static void sharpsl_charge_toggle(struct work_struct *private_);
+static void sharpsl_battery_thread(struct work_struct *private_);
+
+
+/*
+ * Variables
+ */
+struct sharpsl_pm_status sharpsl_pm;
+static DECLARE_DELAYED_WORK(toggle_charger, sharpsl_charge_toggle);
+static DECLARE_DELAYED_WORK(sharpsl_bat, sharpsl_battery_thread);
+DEFINE_LED_TRIGGER(sharpsl_charge_led_trigger);
+
+
+
 struct battery_thresh spitz_battery_levels_acin[] = {
        { 213, 100},
        { 212,  98},
@@ -144,42 +193,789 @@ int sharpsl_pm_pxa_read_max1111(int channel)
 #endif
 }
 
-void sharpsl_pm_pxa_init(void)
+static int get_percentage(int voltage)
+{
+       int i = sharpsl_pm.machinfo->bat_levels - 1;
+       int bl_status = sharpsl_pm.machinfo->backlight_get_status ? sharpsl_pm.machinfo->backlight_get_status() : 0;
+       struct battery_thresh *thresh;
+
+       if (sharpsl_pm.charge_mode == CHRG_ON)
+               thresh = bl_status ? sharpsl_pm.machinfo->bat_levels_acin_bl : sharpsl_pm.machinfo->bat_levels_acin;
+       else
+               thresh = bl_status ? sharpsl_pm.machinfo->bat_levels_noac_bl : sharpsl_pm.machinfo->bat_levels_noac;
+
+       while (i > 0 && (voltage > thresh[i].voltage))
+               i--;
+
+       return thresh[i].percentage;
+}
+
+static int get_apm_status(int voltage)
+{
+       int low_thresh, high_thresh;
+
+       if (sharpsl_pm.charge_mode == CHRG_ON) {
+               high_thresh = sharpsl_pm.machinfo->status_high_acin;
+               low_thresh = sharpsl_pm.machinfo->status_low_acin;
+       } else {
+               high_thresh = sharpsl_pm.machinfo->status_high_noac;
+               low_thresh = sharpsl_pm.machinfo->status_low_noac;
+       }
+
+       if (voltage >= high_thresh)
+               return APM_BATTERY_STATUS_HIGH;
+       if (voltage >= low_thresh)
+               return APM_BATTERY_STATUS_LOW;
+       return APM_BATTERY_STATUS_CRITICAL;
+}
+
+void sharpsl_battery_kick(void)
+{
+       schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(125));
+}
+EXPORT_SYMBOL(sharpsl_battery_kick);
+
+
+static void sharpsl_battery_thread(struct work_struct *private_)
+{
+       int voltage, percent, apm_status, i = 0;
+
+       if (!sharpsl_pm.machinfo)
+               return;
+
+       sharpsl_pm.battstat.ac_status = (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN) ? APM_AC_ONLINE : APM_AC_OFFLINE);
+
+       /* Corgi cannot confirm when battery fully charged so periodically kick! */
+       if (!sharpsl_pm.machinfo->batfull_irq && (sharpsl_pm.charge_mode == CHRG_ON)
+                       && time_after(jiffies, sharpsl_pm.charge_start_time +  SHARPSL_CHARGE_ON_TIME_INTERVAL))
+               schedule_delayed_work(&toggle_charger, 0);
+
+       while(1) {
+               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");
+                       break;
+               }
+       }
+
+       voltage = sharpsl_average_value(voltage);
+       apm_status = get_apm_status(voltage);
+       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) {
+               sharpsl_pm.battstat.mainbat_voltage = voltage;
+               sharpsl_pm.battstat.mainbat_status = apm_status;
+               sharpsl_pm.battstat.mainbat_percent = percent;
+       }
+
+       dev_dbg(sharpsl_pm.dev, "Battery: voltage: %d, status: %d, percentage: %d, time: %ld\n", voltage,
+                       sharpsl_pm.battstat.mainbat_status, sharpsl_pm.battstat.mainbat_percent, jiffies);
+
+#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))) {
+               if (!(sharpsl_pm.flags & SHARPSL_BL_LIMIT)) {
+                       sharpsl_pm.machinfo->backlight_limit(1);
+                       sharpsl_pm.flags |= SHARPSL_BL_LIMIT;
+               }
+       } else if (sharpsl_pm.flags & SHARPSL_BL_LIMIT) {
+               sharpsl_pm.machinfo->backlight_limit(0);
+               sharpsl_pm.flags &= ~SHARPSL_BL_LIMIT;
+       }
+#endif
+
+       /* 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.flags |= SHARPSL_APM_QUEUED;
+               dev_err(sharpsl_pm.dev, "Fatal Off\n");
+               apm_queue_event(APM_CRITICAL_SUSPEND);
+       }
+
+       schedule_delayed_work(&sharpsl_bat, SHARPSL_BATCHK_TIME);
+}
+
+void sharpsl_pm_led(int val)
+{
+       if (val == SHARPSL_LED_ERROR) {
+               dev_err(sharpsl_pm.dev, "Charging Error!\n");
+       } else if (val == SHARPSL_LED_ON) {
+               dev_dbg(sharpsl_pm.dev, "Charge LED On\n");
+               led_trigger_event(sharpsl_charge_led_trigger, LED_FULL);
+       } else {
+               dev_dbg(sharpsl_pm.dev, "Charge LED Off\n");
+               led_trigger_event(sharpsl_charge_led_trigger, LED_OFF);
+       }
+}
+
+static void sharpsl_charge_on(void)
+{
+       dev_dbg(sharpsl_pm.dev, "Turning Charger On\n");
+
+       sharpsl_pm.full_count = 0;
+       sharpsl_pm.charge_mode = CHRG_ON;
+       schedule_delayed_work(&toggle_charger, msecs_to_jiffies(250));
+       schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(500));
+}
+
+static void sharpsl_charge_off(void)
+{
+       dev_dbg(sharpsl_pm.dev, "Turning Charger Off\n");
+
+       sharpsl_pm.machinfo->charge(0);
+       sharpsl_pm_led(SHARPSL_LED_OFF);
+       sharpsl_pm.charge_mode = CHRG_OFF;
+
+       schedule_delayed_work(&sharpsl_bat, 0);
+}
+
+static void sharpsl_charge_error(void)
 {
-       pxa_gpio_mode(sharpsl_pm.machinfo->gpio_acin | GPIO_IN);
-       pxa_gpio_mode(sharpsl_pm.machinfo->gpio_batfull | GPIO_IN);
-       pxa_gpio_mode(sharpsl_pm.machinfo->gpio_batlock | GPIO_IN);
+       sharpsl_pm_led(SHARPSL_LED_ERROR);
+       sharpsl_pm.machinfo->charge(0);
+       sharpsl_pm.charge_mode = CHRG_ERROR;
+}
+
+static void sharpsl_charge_toggle(struct work_struct *private_)
+{
+       dev_dbg(sharpsl_pm.dev, "Toogling Charger at time: %lx\n", jiffies);
+
+       if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) {
+               sharpsl_charge_off();
+               return;
+       } else if ((sharpsl_check_battery_temp() < 0) || (sharpsl_ac_check() < 0)) {
+               sharpsl_charge_error();
+               return;
+       }
+
+       sharpsl_pm_led(SHARPSL_LED_ON);
+       sharpsl_pm.machinfo->charge(0);
+       mdelay(SHARPSL_CHARGE_WAIT_TIME);
+       sharpsl_pm.machinfo->charge(1);
+
+       sharpsl_pm.charge_start_time = jiffies;
+}
+
+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);
+
+       sharpsl_average_clear();
+       if (acin && (sharpsl_pm.charge_mode != CHRG_ON))
+               sharpsl_charge_on();
+       else if (sharpsl_pm.charge_mode == CHRG_ON)
+               sharpsl_charge_off();
+
+       schedule_delayed_work(&sharpsl_bat, 0);
+}
+
+
+static irqreturn_t sharpsl_ac_isr(int irq, void *dev_id)
+{
+       /* Delay the event slightly to debounce */
+       /* Must be a smaller delay than the chrg_full_isr below */
+       mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250));
+
+       return IRQ_HANDLED;
+}
+
+static void sharpsl_chrg_full_timer(unsigned long data)
+{
+       dev_dbg(sharpsl_pm.dev, "Charge Full at time: %lx\n", jiffies);
+
+       sharpsl_pm.full_count++;
+
+       if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) {
+               dev_dbg(sharpsl_pm.dev, "Charge Full: AC removed - stop charging!\n");
+               if (sharpsl_pm.charge_mode == CHRG_ON)
+                       sharpsl_charge_off();
+       } else if (sharpsl_pm.full_count < 2) {
+               dev_dbg(sharpsl_pm.dev, "Charge Full: Count too low\n");
+               schedule_delayed_work(&toggle_charger, 0);
+       } else if (time_after(jiffies, sharpsl_pm.charge_start_time + SHARPSL_CHARGE_FINISH_TIME)) {
+               dev_dbg(sharpsl_pm.dev, "Charge Full: Interrupt generated too slowly - retry.\n");
+               schedule_delayed_work(&toggle_charger, 0);
+       } else {
+               sharpsl_charge_off();
+               sharpsl_pm.charge_mode = CHRG_DONE;
+               dev_dbg(sharpsl_pm.dev, "Charge Full: Charging Finished\n");
+       }
+}
+
+/* Charging Finished Interrupt (Not present on Corgi) */
+/* Can trigger at the same time as an AC status change so
+   delay until after that has been processed */
+static irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id)
+{
+       if (sharpsl_pm.flags & SHARPSL_SUSPENDED)
+               return IRQ_HANDLED;
+
+       /* delay until after any ac interrupt */
+       mod_timer(&sharpsl_pm.chrg_full_timer, jiffies + msecs_to_jiffies(500));
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id)
+{
+       int is_fatal = 0;
+
+       if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_LOCK)) {
+               dev_err(sharpsl_pm.dev, "Battery now Unlocked! Suspending.\n");
+               is_fatal = 1;
+       }
+
+       if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_FATAL)) {
+               dev_err(sharpsl_pm.dev, "Fatal Batt Error! Suspending.\n");
+               is_fatal = 1;
+       }
+
+       if (!(sharpsl_pm.flags & SHARPSL_APM_QUEUED) && is_fatal) {
+               sharpsl_pm.flags |= SHARPSL_APM_QUEUED;
+               apm_queue_event(APM_CRITICAL_SUSPEND);
+       }
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * Maintain an average of the last 10 readings
+ */
+#define SHARPSL_CNV_VALUE_NUM    10
+static int sharpsl_ad_index;
+
+static void sharpsl_average_clear(void)
+{
+       sharpsl_ad_index = 0;
+}
+
+static int sharpsl_average_value(int ad)
+{
+       int i, ad_val = 0;
+       static int sharpsl_ad[SHARPSL_CNV_VALUE_NUM+1];
+
+       if (sharpsl_pm.battstat.mainbat_status != APM_BATTERY_STATUS_HIGH) {
+               sharpsl_ad_index = 0;
+               return 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++)
+                       sharpsl_ad[i] = sharpsl_ad[i+1];
+               sharpsl_ad_index = SHARPSL_CNV_VALUE_NUM - 1;
+       }
+       for (i=0; i < sharpsl_ad_index; i++)
+               ad_val += sharpsl_ad[i];
+
+       return (ad_val / sharpsl_ad_index);
+}
+
+/*
+ * Take an array of 5 integers, remove the maximum and minimum values
+ * and return the average.
+ */
+static int get_select_val(int *val)
+{
+       int i, j, k, temp, sum = 0;
+
+       /* Find MAX val */
+       temp = val[0];
+       j=0;
+       for (i=1; i<5; i++) {
+               if (temp < val[i]) {
+                       temp = val[i];
+                       j = i;
+               }
+       }
+
+       /* Find MIN val */
+       temp = val[4];
+       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 )
+                       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);
+}
+
+static int sharpsl_check_battery_temp(void)
+{
+       int val, i, buff[5];
+
+       /* Check battery temperature */
+       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);
+               buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_TEMP);
+               sharpsl_pm.machinfo->measure_temp(0);
+       }
+
+       val = get_select_val(buff);
+
+       dev_dbg(sharpsl_pm.dev, "Temperature: %d\n", val);
+       if (val > sharpsl_pm.machinfo->charge_on_temp) {
+               printk(KERN_WARNING "Not charging: temperature out of limits.\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int sharpsl_check_battery_voltage(void)
+{
+       int val, i, buff[5];
+
+       /* disable charge, enable discharge */
+       sharpsl_pm.machinfo->charge(0);
+       sharpsl_pm.machinfo->discharge(1);
+       mdelay(SHARPSL_WAIT_DISCHARGE_ON);
+
+       if (sharpsl_pm.machinfo->discharge1)
+               sharpsl_pm.machinfo->discharge1(1);
+
+       /* Check battery voltage */
+       for (i=0; i<5; i++) {
+               buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT);
+               mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT);
+       }
+
+       if (sharpsl_pm.machinfo->discharge1)
+               sharpsl_pm.machinfo->discharge1(0);
+
+       sharpsl_pm.machinfo->discharge(0);
+
+       val = get_select_val(buff);
+       dev_dbg(sharpsl_pm.dev, "Battery Voltage: %d\n", val);
+
+       if (val < sharpsl_pm.machinfo->charge_on_volt)
+               return -1;
+
+       return 0;
+}
+#endif
+
+static int sharpsl_ac_check(void)
+{
+       int temp, i, buff[5];
+
+       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);
+
+       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");
+               return -1;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int sharpsl_pm_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       sharpsl_pm.flags |= SHARPSL_SUSPENDED;
+       flush_scheduled_work();
+
+       if (sharpsl_pm.charge_mode == CHRG_ON)
+               sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG;
+       else
+               sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG;
+
+       return 0;
+}
+
+static int sharpsl_pm_resume(struct platform_device *pdev)
+{
+       /* Clear the reset source indicators as they break the bootloader upon reboot */
+       RCSR = 0x0f;
+       sharpsl_average_clear();
+       sharpsl_pm.flags &= ~SHARPSL_APM_QUEUED;
+       sharpsl_pm.flags &= ~SHARPSL_SUSPENDED;
+
+       return 0;
+}
+
+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, "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))) {
+               dev_dbg(sharpsl_pm.dev, "Activating Offline Charger...\n");
+               sharpsl_pm.charge_mode = CHRG_OFF;
+               sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG;
+               sharpsl_off_charge_battery();
+       }
+
+       sharpsl_pm.machinfo->presuspend();
+
+       PEDR = 0xffffffff; /* clear it */
+
+       sharpsl_pm.flags &= ~SHARPSL_ALARM_ACTIVE;
+       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);
+               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);
+       } else {
+               dev_dbg(sharpsl_pm.dev, "No alarms set.\n");
+       }
+
+       pxa_pm_enter(state);
+
+       sharpsl_pm.machinfo->postsuspend();
+
+       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.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()) {
+                       dev_dbg(sharpsl_pm.dev, "Charging. Suspend...\n");
+                       corgi_goto_sleep(alarm_time, alarm_enable, state);
+                       return 1;
+               }
+               dev_dbg(sharpsl_pm.dev, "User triggered wakeup in offline charger.\n");
+       }
+
+       if ((!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_LOCK)) || (sharpsl_fatal_check() < 0) )
+       {
+               dev_err(sharpsl_pm.dev, "Fatal condition. Suspend.\n");
+               corgi_goto_sleep(alarm_time, alarm_enable, state);
+               return 1;
+       }
+
+       return 0;
+}
+
+static int corgi_pxa_pm_enter(suspend_state_t state)
+{
+       unsigned long alarm_time = RTAR;
+       unsigned int alarm_status = ((RTSR & RTSR_ALE) != 0);
+
+       dev_dbg(sharpsl_pm.dev, "SharpSL suspending for first time.\n");
+
+       corgi_goto_sleep(alarm_time, alarm_status, state);
+
+       while (corgi_enter_suspend(alarm_time,alarm_status,state))
+               {}
+
+       if (sharpsl_pm.machinfo->earlyresume)
+               sharpsl_pm.machinfo->earlyresume();
+
+       dev_dbg(sharpsl_pm.dev, "SharpSL resuming...\n");
+
+       return 0;
+}
+
+/*
+ * Check for fatal battery errors
+ * Fatal returns -1
+ */
+static int sharpsl_fatal_check(void)
+{
+       int buff[5], temp, i, acin;
+
+       dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check entered\n");
+
+       /* Check AC-Adapter */
+       acin = sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN);
+
+       if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) {
+               sharpsl_pm.machinfo->charge(0);
+               udelay(100);
+               sharpsl_pm.machinfo->discharge(1);      /* enable discharge */
+               mdelay(SHARPSL_WAIT_DISCHARGE_ON);
+       }
+
+       if (sharpsl_pm.machinfo->discharge1)
+               sharpsl_pm.machinfo->discharge1(1);
+
+       /* Check battery : check inserting battery ? */
+       for (i=0; i<5; i++) {
+               buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT);
+               mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT);
+       }
+
+       if (sharpsl_pm.machinfo->discharge1)
+               sharpsl_pm.machinfo->discharge1(0);
+
+       if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) {
+               udelay(100);
+               sharpsl_pm.machinfo->charge(1);
+               sharpsl_pm.machinfo->discharge(0);
+       }
+
+       temp = get_select_val(buff);
+       dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check: acin: %d, discharge voltage: %d, no discharge: %ld\n", acin, temp, sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT));
+
+       if ((acin && (temp < sharpsl_pm.machinfo->fatal_acin_volt)) ||
+                       (!acin && (temp < sharpsl_pm.machinfo->fatal_noacin_volt)))
+               return -1;
+       return 0;
+}
+
+static int sharpsl_off_charge_error(void)
+{
+       dev_err(sharpsl_pm.dev, "Offline Charger: Error occurred.\n");
+       sharpsl_pm.machinfo->charge(0);
+       sharpsl_pm_led(SHARPSL_LED_ERROR);
+       sharpsl_pm.charge_mode = CHRG_ERROR;
+       return 1;
+}
+
+/*
+ * Charging Control while suspended
+ * Return 1 - go straight to sleep
+ * Return 0 - sleep or wakeup depending on other factors
+ */
+static int sharpsl_off_charge_battery(void)
+{
+       int time;
+
+       dev_dbg(sharpsl_pm.dev, "Charge Mode: %d\n", sharpsl_pm.charge_mode);
+
+       if (sharpsl_pm.charge_mode == CHRG_OFF) {
+               dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 1\n");
+
+               /* AC Check */
+               if ((sharpsl_ac_check() < 0) || (sharpsl_check_battery_temp() < 0))
+                       return sharpsl_off_charge_error();
+
+               /* Start Charging */
+               sharpsl_pm_led(SHARPSL_LED_ON);
+               sharpsl_pm.machinfo->charge(0);
+               mdelay(SHARPSL_CHARGE_WAIT_TIME);
+               sharpsl_pm.machinfo->charge(1);
+
+               sharpsl_pm.charge_mode = CHRG_ON;
+               sharpsl_pm.full_count = 0;
+
+               return 1;
+       } else if (sharpsl_pm.charge_mode != CHRG_ON) {
+               return 1;
+       }
+
+       if (sharpsl_pm.full_count == 0) {
+               int time;
+
+               dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 2\n");
+
+               if ((sharpsl_check_battery_temp() < 0) || (sharpsl_check_battery_voltage() < 0))
+                       return sharpsl_off_charge_error();
+
+               sharpsl_pm.machinfo->charge(0);
+               mdelay(SHARPSL_CHARGE_WAIT_TIME);
+               sharpsl_pm.machinfo->charge(1);
+               sharpsl_pm.charge_mode = CHRG_ON;
+
+               mdelay(SHARPSL_CHARGE_CO_CHECK_TIME);
+
+               time = RCNR;
+               while(1) {
+                       /* Check if any wakeup event had occurred */
+                       if (sharpsl_pm.machinfo->charger_wakeup() != 0)
+                               return 0;
+                       /* Check for timeout */
+                       if ((RCNR - time) > SHARPSL_WAIT_CO_TIME)
+                               return 1;
+                       if (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_CHRGFULL)) {
+                               dev_dbg(sharpsl_pm.dev, "Offline Charger: Charge full occurred. Retrying to check\n");
+                               sharpsl_pm.full_count++;
+                               sharpsl_pm.machinfo->charge(0);
+                               mdelay(SHARPSL_CHARGE_WAIT_TIME);
+                               sharpsl_pm.machinfo->charge(1);
+                               return 1;
+                       }
+               }
+       }
+
+       dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 3\n");
+
+       mdelay(SHARPSL_CHARGE_CO_CHECK_TIME);
+
+       time = RCNR;
+       while(1) {
+               /* Check if any wakeup event had occurred */
+               if (sharpsl_pm.machinfo->charger_wakeup() != 0)
+                       return 0;
+               /* Check for timeout */
+               if ((RCNR-time) > SHARPSL_WAIT_CO_TIME) {
+                       if (sharpsl_pm.full_count > SHARPSL_CHARGE_RETRY_CNT) {
+                               dev_dbg(sharpsl_pm.dev, "Offline Charger: Not charged sufficiently. Retrying.\n");
+                               sharpsl_pm.full_count = 0;
+                       }
+                       sharpsl_pm.full_count++;
+                       return 1;
+               }
+               if (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_CHRGFULL)) {
+                       dev_dbg(sharpsl_pm.dev, "Offline Charger: Charging complete.\n");
+                       sharpsl_pm_led(SHARPSL_LED_OFF);
+                       sharpsl_pm.machinfo->charge(0);
+                       sharpsl_pm.charge_mode = CHRG_DONE;
+                       return 1;
+               }
+       }
+}
+#else
+#define sharpsl_pm_suspend     NULL
+#define sharpsl_pm_resume      NULL
+#endif
+
+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);
+}
+
+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);
+}
+
+static DEVICE_ATTR(battery_percentage, 0444, battery_percentage_show, NULL);
+static DEVICE_ATTR(battery_voltage, 0444, battery_voltage_show, NULL);
+
+extern void (*apm_get_power_status)(struct apm_power_info *);
+
+static void sharpsl_apm_get_power_status(struct apm_power_info *info)
+{
+       info->ac_line_status = sharpsl_pm.battstat.ac_status;
+
+       if (sharpsl_pm.charge_mode == CHRG_ON)
+               info->battery_status = APM_BATTERY_STATUS_CHARGING;
+       else
+               info->battery_status = sharpsl_pm.battstat.mainbat_status;
+
+       info->battery_flag = (1 << info->battery_status);
+       info->battery_life = sharpsl_pm.battstat.mainbat_percent;
+}
+
+#ifdef CONFIG_PM
+static struct platform_suspend_ops sharpsl_pm_ops = {
+       .prepare        = pxa_pm_prepare,
+       .finish         = pxa_pm_finish,
+       .enter          = corgi_pxa_pm_enter,
+       .valid          = suspend_valid_only_mem,
+};
+#endif
+
+static int __init sharpsl_pm_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       if (!pdev->dev.platform_data)
+               return -EINVAL;
+
+       sharpsl_pm.dev = &pdev->dev;
+       sharpsl_pm.machinfo = pdev->dev.platform_data;
+       sharpsl_pm.charge_mode = CHRG_OFF;
+       sharpsl_pm.flags = 0;
+
+       init_timer(&sharpsl_pm.ac_timer);
+       sharpsl_pm.ac_timer.function = sharpsl_ac_timer;
+
+       init_timer(&sharpsl_pm.chrg_full_timer);
+       sharpsl_pm.chrg_full_timer.function = sharpsl_chrg_full_timer;
+
+       led_trigger_register_simple("sharpsl-charge", &sharpsl_charge_led_trigger);
+
+       sharpsl_pm.machinfo->init();
+
+       gpio_request(sharpsl_pm.machinfo->gpio_acin, "AC IN");
+       gpio_direction_input(sharpsl_pm.machinfo->gpio_acin);
+       gpio_request(sharpsl_pm.machinfo->gpio_batfull, "Battery Full");
+       gpio_direction_input(sharpsl_pm.machinfo->gpio_batfull);
+       gpio_request(sharpsl_pm.machinfo->gpio_batlock, "Battery Lock");
+       gpio_direction_input(sharpsl_pm.machinfo->gpio_batlock);
 
        /* Register interrupt handlers */
-       if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin), sharpsl_ac_isr, IRQF_DISABLED, "AC Input Detect", sharpsl_ac_isr)) {
+       if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin), sharpsl_ac_isr, IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "AC Input Detect", sharpsl_ac_isr)) {
                dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin));
        }
-       else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin),IRQ_TYPE_EDGE_BOTH);
 
-       if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock), sharpsl_fatal_isr, IRQF_DISABLED, "Battery Cover", sharpsl_fatal_isr)) {
+       if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock), sharpsl_fatal_isr, IRQF_DISABLED | IRQF_TRIGGER_FALLING, "Battery Cover", sharpsl_fatal_isr)) {
                dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock));
        }
-       else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock),IRQ_TYPE_EDGE_FALLING);
 
        if (sharpsl_pm.machinfo->gpio_fatal) {
-               if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal), sharpsl_fatal_isr, IRQF_DISABLED, "Fatal Battery", sharpsl_fatal_isr)) {
+               if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal), sharpsl_fatal_isr, IRQF_DISABLED | IRQF_TRIGGER_FALLING, "Fatal Battery", sharpsl_fatal_isr)) {
                        dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal));
                }
-               else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal),IRQ_TYPE_EDGE_FALLING);
        }
 
        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, "CO", sharpsl_chrg_full_isr)) {
+               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));
                }
-               else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull),IRQ_TYPE_EDGE_RISING);
        }
+
+       ret = device_create_file(&pdev->dev, &dev_attr_battery_percentage);
+       ret |= device_create_file(&pdev->dev, &dev_attr_battery_voltage);
+       if (ret != 0)
+               dev_warn(&pdev->dev, "Failed to register attributes (%d)\n", ret);
+
+       apm_get_power_status = sharpsl_apm_get_power_status;
+
+#ifdef CONFIG_PM
+       suspend_set_ops(&sharpsl_pm_ops);
+#endif
+
+       mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250));
+
+       return 0;
 }
 
-void sharpsl_pm_pxa_remove(void)
+static int sharpsl_pm_remove(struct platform_device *pdev)
 {
+       suspend_set_ops(NULL);
+
+       device_remove_file(&pdev->dev, &dev_attr_battery_percentage);
+       device_remove_file(&pdev->dev, &dev_attr_battery_voltage);
+
+       led_trigger_unregister_simple(sharpsl_charge_led_trigger);
+
        free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin), sharpsl_ac_isr);
        free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock), sharpsl_fatal_isr);
 
@@ -188,4 +984,39 @@ void sharpsl_pm_pxa_remove(void)
 
        if (sharpsl_pm.machinfo->batfull_irq)
                free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull), sharpsl_chrg_full_isr);
+
+       gpio_free(sharpsl_pm.machinfo->gpio_batlock);
+       gpio_free(sharpsl_pm.machinfo->gpio_batfull);
+       gpio_free(sharpsl_pm.machinfo->gpio_acin);
+
+       if (sharpsl_pm.machinfo->exit)
+               sharpsl_pm.machinfo->exit();
+
+       del_timer_sync(&sharpsl_pm.chrg_full_timer);
+       del_timer_sync(&sharpsl_pm.ac_timer);
+
+       return 0;
 }
+
+static struct platform_driver sharpsl_pm_driver = {
+       .probe          = sharpsl_pm_probe,
+       .remove         = sharpsl_pm_remove,
+       .suspend        = sharpsl_pm_suspend,
+       .resume         = sharpsl_pm_resume,
+       .driver         = {
+               .name           = "sharpsl-pm",
+       },
+};
+
+static int __devinit sharpsl_pm_init(void)
+{
+       return platform_driver_register(&sharpsl_pm_driver);
+}
+
+static void sharpsl_pm_exit(void)
+{
+       platform_driver_unregister(&sharpsl_pm_driver);
+}
+
+late_initcall(sharpsl_pm_init);
+module_exit(sharpsl_pm_exit);
index 5a45fe340a1057729a7e7a31442af85da9426595..dda310fe71c87bfcd61c5bf6c514c2b614fec8d3 100644 (file)
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
-#include <linux/major.h>
-#include <linux/fs.h>
-#include <linux/interrupt.h>
 #include <linux/gpio.h>
 #include <linux/leds.h>
-#include <linux/mmc/host.h>
 #include <linux/mtd/physmap.h>
-#include <linux/pm.h>
-#include <linux/backlight.h>
-#include <linux/io.h>
 #include <linux/i2c.h>
 #include <linux/i2c/pca953x.h>
 #include <linux/spi/spi.h>
 #include <linux/mtd/sharpsl.h>
 
 #include <asm/setup.h>
-#include <asm/memory.h>
 #include <asm/mach-types.h>
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
 #include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
+#include <asm/mach/sharpsl_param.h>
+#include <asm/hardware/scoop.h>
+
 
 #include <mach/pxa27x.h>
 #include <mach/pxa27x-udc.h>
 #include <mach/reset.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/irda.h>
 #include <mach/mmc.h>
 #include <mach/ohci.h>
-#include <mach/udc.h>
 #include <mach/pxafb.h>
 #include <mach/pxa2xx_spi.h>
 #include <mach/spitz.h>
-#include <mach/sharpsl.h>
-
-#include <asm/mach/sharpsl_param.h>
-#include <asm/hardware/scoop.h>
 
 #include "generic.h"
 #include "devices.h"
@@ -317,13 +300,8 @@ static struct ads7846_platform_data spitz_ads7846_info = {
        .wait_for_sync          = spitz_wait_for_hsync,
 };
 
-static void spitz_ads7846_cs(u32 command)
-{
-       gpio_set_value(SPITZ_GPIO_ADS7846_CS, !(command == PXA2XX_CS_ASSERT));
-}
-
 static struct pxa2xx_spi_chip spitz_ads7846_chip = {
-       .cs_control             = spitz_ads7846_cs,
+       .gpio_cs                = SPITZ_GPIO_ADS7846_CS,
 };
 
 static void spitz_bl_kick_battery(void)
@@ -347,22 +325,12 @@ static struct corgi_lcd_platform_data spitz_lcdcon_info = {
        .kick_battery           = spitz_bl_kick_battery,
 };
 
-static void spitz_lcdcon_cs(u32 command)
-{
-       gpio_set_value(SPITZ_GPIO_LCDCON_CS, !(command == PXA2XX_CS_ASSERT));
-}
-
 static struct pxa2xx_spi_chip spitz_lcdcon_chip = {
-       .cs_control     = spitz_lcdcon_cs,
+       .gpio_cs        = SPITZ_GPIO_LCDCON_CS,
 };
 
-static void spitz_max1111_cs(u32 command)
-{
-       gpio_set_value(SPITZ_GPIO_MAX1111_CS, !(command == PXA2XX_CS_ASSERT));
-}
-
 static struct pxa2xx_spi_chip spitz_max1111_chip = {
-       .cs_control     = spitz_max1111_cs,
+       .gpio_cs        = SPITZ_GPIO_MAX1111_CS,
 };
 
 static struct spi_board_info spitz_spi_devices[] = {
@@ -392,30 +360,6 @@ static struct spi_board_info spitz_spi_devices[] = {
 
 static void __init spitz_init_spi(void)
 {
-       int err;
-
-       err = gpio_request(SPITZ_GPIO_ADS7846_CS, "ADS7846_CS");
-       if (err)
-               return;
-
-       err = gpio_request(SPITZ_GPIO_LCDCON_CS, "LCDCON_CS");
-       if (err)
-               goto err_free_1;
-
-       err = gpio_request(SPITZ_GPIO_MAX1111_CS, "MAX1111_CS");
-       if (err)
-               goto err_free_2;
-
-       err = gpio_direction_output(SPITZ_GPIO_ADS7846_CS, 1);
-       if (err)
-               goto err_free_3;
-       err = gpio_direction_output(SPITZ_GPIO_LCDCON_CS, 1);
-       if (err)
-               goto err_free_3;
-       err = gpio_direction_output(SPITZ_GPIO_MAX1111_CS, 1);
-       if (err)
-               goto err_free_3;
-
        if (machine_is_akita()) {
                spitz_lcdcon_info.gpio_backlight_cont = AKITA_GPIO_BACKLIGHT_CONT;
                spitz_lcdcon_info.gpio_backlight_on = AKITA_GPIO_BACKLIGHT_ON;
@@ -423,14 +367,6 @@ static void __init spitz_init_spi(void)
 
        pxa2xx_set_spi_info(2, &spitz_spi_info);
        spi_register_board_info(ARRAY_AND_SIZE(spitz_spi_devices));
-       return;
-
-err_free_3:
-       gpio_free(SPITZ_GPIO_MAX1111_CS);
-err_free_2:
-       gpio_free(SPITZ_GPIO_LCDCON_CS);
-err_free_1:
-       gpio_free(SPITZ_GPIO_ADS7846_CS);
 }
 #else
 static inline void spitz_init_spi(void) {}
index 2e4490562c9e85d5a4891c823a9e17d83a78923a..724ffb0303176f3fa4fd3256fbe17ad0df416786 100644 (file)
@@ -41,7 +41,6 @@ static void spitz_charger_init(void)
 {
        pxa_gpio_mode(SPITZ_GPIO_KEY_INT | GPIO_IN);
        pxa_gpio_mode(SPITZ_GPIO_SYNC | GPIO_IN);
-       sharpsl_pm_pxa_init();
 }
 
 static void spitz_measure_temp(int on)
@@ -182,7 +181,7 @@ unsigned long spitzpm_read_devdata(int type)
 
 struct sharpsl_charger_machinfo spitz_pm_machinfo = {
        .init             = spitz_charger_init,
-       .exit             = sharpsl_pm_pxa_remove,
+       .exit             = NULL,
        .gpio_batlock     = SPITZ_GPIO_BAT_COVER,
        .gpio_acin        = SPITZ_GPIO_AC_IN,
        .gpio_batfull     = SPITZ_GPIO_CHRG_FULL,
diff --git a/arch/arm/mach-pxa/stargate2.c b/arch/arm/mach-pxa/stargate2.c
new file mode 100644 (file)
index 0000000..3b205b6
--- /dev/null
@@ -0,0 +1,796 @@
+/*
+ *  linux/arch/arm/mach-pxa/stargate2.c
+ *
+ *  Author:    Ed C. Epp
+ *  Created:   Nov 05, 2002
+ *  Copyright: Intel Corp.
+ *
+ *  Modified 2009:  Jonathan Cameron <jic23@cam.ac.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
+ *  published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/bitops.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/machine.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/plat-ram.h>
+#include <linux/mtd/partitions.h>
+
+#include <linux/i2c/pcf857x.h>
+#include <linux/i2c/at24.h>
+#include <linux/smc91x.h>
+#include <linux/gpio.h>
+
+#include <asm/types.h>
+#include <asm/setup.h>
+#include <asm/memory.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/flash.h>
+
+#include <mach/pxa27x.h>
+#include <plat/i2c.h>
+#include <mach/mmc.h>
+#include <mach/udc.h>
+#include <mach/pxa2xx_spi.h>
+#include <mach/pxa27x-udc.h>
+
+#include <linux/spi/spi.h>
+#include <linux/mfd/da903x.h>
+#include <linux/sht15.h>
+
+#include "devices.h"
+#include "generic.h"
+
+/* Bluetooth */
+#define SG2_BT_RESET           81
+
+/* SD */
+#define SG2_GPIO_nSD_DETECT    90
+#define SG2_SD_POWER_ENABLE    89
+
+static unsigned long stargate2_pin_config[] __initdata = {
+
+       GPIO15_nCS_1, /* SRAM */
+       /* SMC91x */
+       GPIO80_nCS_4,
+       GPIO40_GPIO, /*cable detect?*/
+       /* Device Identification for wakeup*/
+       GPIO102_GPIO,
+
+       /* Button */
+       GPIO91_GPIO | WAKEUP_ON_LEVEL_HIGH,
+
+       /* DA9030 */
+       GPIO1_GPIO,
+
+       /* Compact Flash */
+       GPIO79_PSKTSEL,
+       GPIO48_nPOE,
+       GPIO49_nPWE,
+       GPIO50_nPIOR,
+       GPIO51_nPIOW,
+       GPIO85_nPCE_1,
+       GPIO54_nPCE_2,
+       GPIO55_nPREG,
+       GPIO56_nPWAIT,
+       GPIO57_nIOIS16,
+       GPIO120_GPIO, /* Buff ctrl */
+       GPIO108_GPIO, /* Power ctrl */
+       GPIO82_GPIO, /* Reset */
+       GPIO53_GPIO, /* SG2_S0_GPIO_DETECT */
+
+       /* MMC */
+       GPIO32_MMC_CLK,
+       GPIO112_MMC_CMD,
+       GPIO92_MMC_DAT_0,
+       GPIO109_MMC_DAT_1,
+       GPIO110_MMC_DAT_2,
+       GPIO111_MMC_DAT_3,
+       GPIO90_GPIO, /* nSD detect */
+       GPIO89_GPIO, /* SD_POWER_ENABLE */
+
+       /* Bluetooth */
+       GPIO81_GPIO, /* reset */
+
+       /* cc2420 802.15.4 radio */
+       GPIO22_GPIO,            /* CC_RSTN  (out)*/
+       GPIO114_GPIO,           /* CC_FIFO (in) */
+       GPIO116_GPIO,           /* CC_CCA (in) */
+       GPIO0_GPIO,             /* CC_FIFOP (in) */
+       GPIO16_GPIO,            /* CCSFD (in) */
+       GPIO39_GPIO,            /* CSn (out) */
+
+       /* I2C */
+       GPIO117_I2C_SCL,
+       GPIO118_I2C_SDA,
+
+       /* SSP 3 - 802.15.4 radio */
+       GPIO39_GPIO, /* chip select */
+       GPIO34_SSP3_SCLK,
+       GPIO35_SSP3_TXD,
+       GPIO41_SSP3_RXD,
+
+       /* SSP 2 */
+       GPIO11_SSP2_RXD,
+       GPIO38_SSP2_TXD,
+       GPIO36_SSP2_SCLK,
+       GPIO37_GPIO, /* chip select */
+
+       /* SSP 1 */
+       GPIO26_SSP1_RXD,
+       GPIO25_SSP1_TXD,
+       GPIO23_SSP1_SCLK,
+       GPIO24_GPIO, /* chip select */
+
+       /* BTUART */
+       GPIO42_BTUART_RXD,
+       GPIO43_BTUART_TXD,
+       GPIO44_BTUART_CTS,
+       GPIO45_BTUART_RTS,
+
+       /* STUART */
+       GPIO46_STUART_RXD,
+       GPIO47_STUART_TXD,
+
+       /* Basic sensor board */
+       GPIO96_GPIO,    /* accelerometer interrupt */
+       GPIO99_GPIO,    /* ADC interrupt */
+
+       /* Connector pins specified as gpios */
+       GPIO94_GPIO, /* large basic connector pin 14 */
+       GPIO10_GPIO, /* large basic connector pin 23 */
+
+       /* SHT15 */
+       GPIO100_GPIO,
+       GPIO98_GPIO,
+};
+
+/**
+ * stargate2_reset_bluetooth() reset the bluecore to ensure consistent state
+ **/
+static int stargate2_reset_bluetooth(void)
+{
+       int err;
+       err = gpio_request(SG2_BT_RESET, "SG2_BT_RESET");
+       if (err) {
+               printk(KERN_ERR "Could not get gpio for bluetooth reset \n");
+               return err;
+       }
+       gpio_direction_output(SG2_BT_RESET, 1);
+       mdelay(5);
+       /* now reset it - 5 msec minimum */
+       gpio_set_value(SG2_BT_RESET, 0);
+       mdelay(10);
+       gpio_set_value(SG2_BT_RESET, 1);
+       gpio_free(SG2_BT_RESET);
+       return 0;
+}
+
+static struct led_info stargate2_leds[] = {
+       {
+               .name = "sg2:red",
+               .flags = DA9030_LED_RATE_ON,
+       }, {
+               .name = "sg2:blue",
+               .flags = DA9030_LED_RATE_ON,
+       }, {
+               .name = "sg2:green",
+               .flags = DA9030_LED_RATE_ON,
+       },
+};
+
+static struct sht15_platform_data platform_data_sht15 = {
+       .gpio_data =  100,
+       .gpio_sck  =  98,
+};
+
+static struct platform_device sht15 = {
+       .name = "sht15",
+       .id = -1,
+       .dev = {
+               .platform_data = &platform_data_sht15,
+       },
+};
+
+static struct regulator_consumer_supply stargate2_sensor_3_con[] = {
+       {
+               .dev = &sht15.dev,
+               .supply = "vcc",
+       },
+};
+
+enum stargate2_ldos{
+       vcc_vref,
+       vcc_cc2420,
+       /* a mote connector? */
+       vcc_mica,
+       /* the CSR bluecore chip */
+       vcc_bt,
+       /* The two voltages available to sensor boards */
+       vcc_sensor_1_8,
+       vcc_sensor_3,
+       /* directly connected to the pxa27x */
+       vcc_sram_ext,
+       vcc_pxa_pll,
+       vcc_pxa_usim, /* Reference voltage for certain gpios */
+       vcc_pxa_mem,
+       vcc_pxa_flash,
+       vcc_pxa_core, /*Dc-Dc buck not yet supported */
+       vcc_lcd,
+       vcc_bb,
+       vcc_bbio, /*not sure!*/
+       vcc_io, /* cc2420 802.15.4 radio and pxa vcc_io ?*/
+};
+
+/* The values of the various regulator constraints are obviously dependent
+ * on exactly what is wired to each ldo.  Unfortunately this information is
+ * not generally available.  More information has been requested from Xbow.
+ */
+static struct regulator_init_data stargate2_ldo_init_data[] = {
+       [vcc_bbio] = {
+               .constraints = { /* board default 1.8V */
+                       .name = "vcc_bbio",
+                       .min_uV = 1800000,
+                       .max_uV = 1800000,
+               },
+       },
+       [vcc_bb] = {
+               .constraints = { /* board default 2.8V */
+                       .name = "vcc_bb",
+                       .min_uV = 2700000,
+                       .max_uV = 3000000,
+               },
+       },
+       [vcc_pxa_flash] = {
+               .constraints = {/* default is 1.8V */
+                       .name = "vcc_pxa_flash",
+                       .min_uV = 1800000,
+                       .max_uV = 1800000,
+               },
+       },
+       [vcc_cc2420] = { /* also vcc_io */
+               .constraints = {
+                       /* board default is 2.8V */
+                       .name = "vcc_cc2420",
+                       .min_uV = 2700000,
+                       .max_uV = 3300000,
+               },
+       },
+       [vcc_vref] = { /* Reference for what? */
+               .constraints = { /* default 1.8V */
+                       .name = "vcc_vref",
+                       .min_uV = 1800000,
+                       .max_uV = 1800000,
+               },
+       },
+       [vcc_sram_ext] = {
+               .constraints = { /* default 2.8V */
+                       .name = "vcc_sram_ext",
+                       .min_uV = 2800000,
+                       .max_uV = 2800000,
+               },
+       },
+       [vcc_mica] = {
+               .constraints = { /* default 2.8V */
+                       .name = "vcc_mica",
+                       .min_uV = 2800000,
+                       .max_uV = 2800000,
+               },
+       },
+       [vcc_bt] = {
+               .constraints = { /* default 2.8V */
+                       .name = "vcc_bt",
+                       .min_uV = 2800000,
+                       .max_uV = 2800000,
+               },
+       },
+       [vcc_lcd] = {
+               .constraints = { /* default 2.8V */
+                       .name = "vcc_lcd",
+                       .min_uV = 2700000,
+                       .max_uV = 3300000,
+               },
+       },
+       [vcc_io] = { /* Same or higher than everything
+                         * bar vccbat and vccusb */
+               .constraints = { /* default 2.8V */
+                       .name = "vcc_io",
+                       .min_uV = 2692000,
+                       .max_uV = 3300000,
+               },
+       },
+       [vcc_sensor_1_8] = {
+               .constraints = { /* default 1.8V */
+                       .name = "vcc_sensor_1_8",
+                       .min_uV = 1800000,
+                       .max_uV = 1800000,
+               },
+       },
+       [vcc_sensor_3] = { /* curiously default 2.8V */
+               .constraints = {
+                       .name = "vcc_sensor_3",
+                       .min_uV = 2800000,
+                       .max_uV = 3000000,
+               },
+               .num_consumer_supplies = ARRAY_SIZE(stargate2_sensor_3_con),
+               .consumer_supplies = stargate2_sensor_3_con,
+       },
+       [vcc_pxa_pll] = { /* 1.17V - 1.43V, default 1.3V*/
+               .constraints = {
+                       .name = "vcc_pxa_pll",
+                       .min_uV = 1170000,
+                       .max_uV = 1430000,
+               },
+       },
+       [vcc_pxa_usim] = {
+               .constraints = { /* default 1.8V */
+                       .name = "vcc_pxa_usim",
+                       .min_uV = 1710000,
+                       .max_uV = 2160000,
+               },
+       },
+       [vcc_pxa_mem] = {
+               .constraints = { /* default 1.8V */
+                       .name = "vcc_pxa_mem",
+                       .min_uV = 1800000,
+                       .max_uV = 1800000,
+               },
+       },
+};
+
+static struct da903x_subdev_info stargate2_da9030_subdevs[] = {
+       {
+               .name = "da903x-led",
+               .id = DA9030_ID_LED_2,
+               .platform_data = &stargate2_leds[0],
+       }, {
+               .name = "da903x-led",
+               .id = DA9030_ID_LED_3,
+               .platform_data = &stargate2_leds[2],
+       }, {
+               .name = "da903x-led",
+               .id = DA9030_ID_LED_4,
+               .platform_data = &stargate2_leds[1],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO2,
+               .platform_data = &stargate2_ldo_init_data[vcc_bbio],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO3,
+               .platform_data = &stargate2_ldo_init_data[vcc_bb],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO4,
+               .platform_data = &stargate2_ldo_init_data[vcc_pxa_flash],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO5,
+               .platform_data = &stargate2_ldo_init_data[vcc_cc2420],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO6,
+               .platform_data = &stargate2_ldo_init_data[vcc_vref],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO7,
+               .platform_data = &stargate2_ldo_init_data[vcc_sram_ext],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO8,
+               .platform_data = &stargate2_ldo_init_data[vcc_mica],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO9,
+               .platform_data = &stargate2_ldo_init_data[vcc_bt],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO10,
+               .platform_data = &stargate2_ldo_init_data[vcc_sensor_1_8],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO11,
+               .platform_data = &stargate2_ldo_init_data[vcc_sensor_3],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO12,
+               .platform_data = &stargate2_ldo_init_data[vcc_lcd],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO15,
+               .platform_data = &stargate2_ldo_init_data[vcc_pxa_pll],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO17,
+               .platform_data = &stargate2_ldo_init_data[vcc_pxa_usim],
+       }, {
+               .name = "da903x-regulator", /*pxa vcc i/o and cc2420 vcc i/o */
+               .id = DA9030_ID_LDO18,
+               .platform_data = &stargate2_ldo_init_data[vcc_io],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO19,
+               .platform_data = &stargate2_ldo_init_data[vcc_pxa_mem],
+       },
+};
+
+static struct da903x_platform_data stargate2_da9030_pdata = {
+       .num_subdevs = ARRAY_SIZE(stargate2_da9030_subdevs),
+       .subdevs = stargate2_da9030_subdevs,
+};
+
+static struct resource smc91x_resources[] = {
+       [0] = {
+               .name = "smc91x-regs",
+               .start = (PXA_CS4_PHYS + 0x300),
+               .end = (PXA_CS4_PHYS + 0xfffff),
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_GPIO(40),
+               .end = IRQ_GPIO(40),
+               .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+       }
+};
+
+static struct smc91x_platdata stargate2_smc91x_info = {
+       .flags = SMC91X_USE_8BIT | SMC91X_USE_16BIT | SMC91X_USE_32BIT
+       | SMC91X_NOWAIT | SMC91X_USE_DMA,
+};
+
+static struct platform_device smc91x_device = {
+       .name = "smc91x",
+       .id = -1,
+       .num_resources = ARRAY_SIZE(smc91x_resources),
+       .resource = smc91x_resources,
+       .dev = {
+               .platform_data = &stargate2_smc91x_info,
+       },
+};
+
+
+
+static struct pxamci_platform_data stargate2_mci_platform_data;
+
+/*
+ * The card detect interrupt isn't debounced so we delay it by 250ms
+ * to give the card a chance to fully insert / eject.
+ */
+static int stargate2_mci_init(struct device *dev,
+                             irq_handler_t stargate2_detect_int,
+                             void *data)
+{
+       int err;
+
+       err = gpio_request(SG2_SD_POWER_ENABLE, "SG2_sd_power_enable");
+       if (err) {
+               printk(KERN_ERR "Can't get the gpio for SD power control");
+               goto return_err;
+       }
+       gpio_direction_output(SG2_SD_POWER_ENABLE, 0);
+
+       err = gpio_request(SG2_GPIO_nSD_DETECT, "SG2_sd_detect");
+       if (err) {
+               printk(KERN_ERR "Can't get the sd detect gpio");
+               goto free_power_en;
+       }
+       gpio_direction_input(SG2_GPIO_nSD_DETECT);
+       /* Delay to allow for full insertion */
+       stargate2_mci_platform_data.detect_delay = msecs_to_jiffies(250);
+
+       err = request_irq(IRQ_GPIO(SG2_GPIO_nSD_DETECT),
+                         stargate2_detect_int,
+                         IRQ_TYPE_EDGE_BOTH,
+                         "MMC card detect",
+                         data);
+       if (err) {
+               printk(KERN_ERR "can't request MMC card detect IRQ\n");
+               goto free_nsd_detect;
+       }
+       return 0;
+
+ free_nsd_detect:
+       gpio_free(SG2_GPIO_nSD_DETECT);
+ free_power_en:
+       gpio_free(SG2_SD_POWER_ENABLE);
+ return_err:
+       return err;
+}
+
+/**
+ * stargate2_mci_setpower() - set state of mmc power supply
+ *
+ * Very simple control. Either it is on or off and is controlled by
+ * a gpio pin */
+static void stargate2_mci_setpower(struct device *dev, unsigned int vdd)
+{
+       gpio_set_value(SG2_SD_POWER_ENABLE, !!vdd);
+}
+
+static void stargate2_mci_exit(struct device *dev, void *data)
+{
+       free_irq(IRQ_GPIO(SG2_GPIO_nSD_DETECT), data);
+       gpio_free(SG2_SD_POWER_ENABLE);
+       gpio_free(SG2_GPIO_nSD_DETECT);
+}
+
+static struct pxamci_platform_data stargate2_mci_platform_data = {
+       .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
+       .init = stargate2_mci_init,
+       .setpower = stargate2_mci_setpower,
+       .exit = stargate2_mci_exit,
+};
+
+static struct mtd_partition stargate2flash_partitions[] = {
+       {
+               .name = "Bootloader",
+               .size = 0x00040000,
+               .offset = 0,
+               .mask_flags = 0,
+       }, {
+               .name = "Kernel",
+               .size = 0x00200000,
+               .offset = 0x00040000,
+               .mask_flags = 0
+       }, {
+               .name = "Filesystem",
+               .size = 0x01DC0000,
+               .offset = 0x00240000,
+               .mask_flags = 0
+       },
+};
+
+static struct resource flash_resources = {
+       .start = PXA_CS0_PHYS,
+       .end = PXA_CS0_PHYS + SZ_32M - 1,
+       .flags = IORESOURCE_MEM,
+};
+
+static struct flash_platform_data stargate2_flash_data = {
+       .map_name = "cfi_probe",
+       .parts = stargate2flash_partitions,
+       .nr_parts = ARRAY_SIZE(stargate2flash_partitions),
+       .name = "PXA27xOnChipROM",
+       .width = 2,
+};
+
+static struct platform_device stargate2_flash_device = {
+       .name = "pxa2xx-flash",
+       .id = 0,
+       .dev = {
+               .platform_data = &stargate2_flash_data,
+       },
+       .resource = &flash_resources,
+       .num_resources = 1,
+};
+
+/*
+ * SRAM - The Stargate 2 has 32MB of SRAM.
+ *
+ * Here it is made available as an MTD. This will then
+ * typically have a cifs filesystem created on it to provide
+ * fast temporary storage.
+ */
+static struct resource sram_resources = {
+       .start = PXA_CS1_PHYS,
+       .end = PXA_CS1_PHYS + SZ_32M-1,
+       .flags = IORESOURCE_MEM,
+};
+
+static struct platdata_mtd_ram stargate2_sram_pdata = {
+       .mapname = "Stargate2 SRAM",
+       .bankwidth = 2,
+};
+
+static struct platform_device stargate2_sram = {
+       .name = "mtd-ram",
+       .id = 0,
+       .resource = &sram_resources,
+       .num_resources = 1,
+       .dev = {
+               .platform_data = &stargate2_sram_pdata,
+       },
+};
+
+static struct pcf857x_platform_data platform_data_pcf857x = {
+       .gpio_base = 128,
+       .n_latch = 0,
+       .setup = NULL,
+       .teardown = NULL,
+       .context = NULL,
+};
+
+static struct at24_platform_data pca9500_eeprom_pdata = {
+       .byte_len = 256,
+       .page_size = 4,
+};
+
+
+static struct i2c_board_info __initdata stargate2_i2c_board_info[] = {
+       /* Techically this a pca9500 - but it's compatible with the 8574
+        * for gpio expansion and the 24c02 for eeprom access.
+        */
+       {
+               .type = "pcf8574",
+               .addr =  0x27,
+               .platform_data = &platform_data_pcf857x,
+       }, {
+               .type = "24c02",
+               .addr = 0x57,
+               .platform_data = &pca9500_eeprom_pdata,
+       }, {
+               .type = "max1238",
+               .addr = 0x35,
+       }, { /* ITS400 Sensor board only */
+               .type = "max1363",
+               .addr = 0x34,
+               /* Through a nand gate - Also beware, on V2 sensor board the
+                * pull up resistors are missing.
+                */
+               .irq = IRQ_GPIO(99),
+       }, { /* ITS400 Sensor board only */
+               .type = "tsl2561",
+               .addr = 0x49,
+               /* Through a nand gate - Also beware, on V2 sensor board the
+                * pull up resistors are missing.
+                */
+               .irq = IRQ_GPIO(99),
+       }, { /* ITS400 Sensor board only */
+               .type = "tmp175",
+               .addr = 0x4A,
+               .irq = IRQ_GPIO(96),
+       },
+};
+
+static struct i2c_board_info __initdata stargate2_pwr_i2c_board_info[] = {
+       {
+               .type = "da9030",
+               .addr = 0x49,
+               .platform_data = &stargate2_da9030_pdata,
+               .irq = gpio_to_irq(1),
+       },
+};
+
+static struct pxa2xx_spi_master pxa_ssp_master_0_info = {
+       .num_chipselect = 1,
+};
+
+static struct pxa2xx_spi_master pxa_ssp_master_1_info = {
+       .num_chipselect = 1,
+};
+
+static struct pxa2xx_spi_master pxa_ssp_master_2_info = {
+       .num_chipselect = 1,
+};
+
+/* An upcoming kernel change will scrap SFRM usage so these
+ * drivers have been moved to use gpio's via cs_control */
+static struct pxa2xx_spi_chip staccel_chip_info = {
+       .tx_threshold = 8,
+       .rx_threshold = 8,
+       .dma_burst_size = 8,
+       .timeout = 235,
+       .gpio_cs = 24,
+};
+
+static struct pxa2xx_spi_chip cc2420_info = {
+       .tx_threshold = 8,
+       .rx_threshold = 8,
+       .dma_burst_size = 8,
+       .timeout = 235,
+       .gpio_cs = 39,
+};
+
+static struct spi_board_info spi_board_info[] __initdata = {
+       {
+               .modalias = "lis3l02dq",
+               .max_speed_hz = 8000000,/* 8MHz max spi frequency at 3V */
+               .bus_num = 1,
+               .chip_select = 0,
+               .controller_data = &staccel_chip_info,
+               .irq = IRQ_GPIO(96),
+       }, {
+               .modalias = "cc2420",
+               .max_speed_hz = 6500000,
+               .bus_num = 3,
+               .chip_select = 0,
+               .controller_data = &cc2420_info,
+       },
+};
+
+static void sg2_udc_command(int cmd)
+{
+       switch (cmd) {
+       case PXA2XX_UDC_CMD_CONNECT:
+               UP2OCR |=  UP2OCR_HXOE  | UP2OCR_DPPUE | UP2OCR_DPPUBE;
+               break;
+       case PXA2XX_UDC_CMD_DISCONNECT:
+               UP2OCR &= ~(UP2OCR_HXOE  | UP2OCR_DPPUE | UP2OCR_DPPUBE);
+               break;
+       }
+}
+
+/* Board doesn't support cable detection - so always lie and say
+ * something is there.
+ */
+static int sg2_udc_detect(void)
+{
+       return 1;
+}
+
+static struct pxa2xx_udc_mach_info stargate2_udc_info __initdata = {
+       .udc_is_connected       = sg2_udc_detect,
+       .udc_command            = sg2_udc_command,
+};
+
+static struct platform_device *stargate2_devices[] = {
+       &stargate2_flash_device,
+       &stargate2_sram,
+       &smc91x_device,
+       &sht15,
+};
+
+static struct i2c_pxa_platform_data i2c_pwr_pdata = {
+       .fast_mode = 1,
+};
+
+static struct i2c_pxa_platform_data i2c_pdata = {
+       .fast_mode = 1,
+};
+
+static void __init stargate2_init(void)
+{
+       /* This is probably a board specific hack as this must be set
+          prior to connecting the MFP stuff up. */
+       MECR &= ~MECR_NOS;
+
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(stargate2_pin_config));
+
+       /* spi chip selects */
+       gpio_direction_output(37, 0);
+       gpio_direction_output(24, 0);
+       gpio_direction_output(39, 0);
+
+       platform_add_devices(ARRAY_AND_SIZE(stargate2_devices));
+
+       pxa2xx_set_spi_info(1, &pxa_ssp_master_0_info);
+       pxa2xx_set_spi_info(2, &pxa_ssp_master_1_info);
+       pxa2xx_set_spi_info(3, &pxa_ssp_master_2_info);
+       spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+
+       i2c_register_board_info(0, ARRAY_AND_SIZE(stargate2_i2c_board_info));
+       i2c_register_board_info(1,
+                               ARRAY_AND_SIZE(stargate2_pwr_i2c_board_info));
+       pxa27x_set_i2c_power_info(&i2c_pwr_pdata);
+       pxa_set_i2c_info(&i2c_pdata);
+
+       pxa_set_mci_info(&stargate2_mci_platform_data);
+
+       pxa_set_udc_info(&stargate2_udc_info);
+
+       stargate2_reset_bluetooth();
+}
+
+MACHINE_START(STARGATE2, "Stargate 2")
+       .phys_io = 0x40000000,
+       .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
+       .map_io = pxa_map_io,
+       .init_irq = pxa27x_init_irq,
+       .timer = &pxa_timer,
+       .init_machine = stargate2_init,
+       .boot_params = 0xA0000100,
+MACHINE_END
index a0bd46ef5d30de6fb09cda7fc96371a344c95207..168267a5dfb3e3f80775599990c5d54bba81acc3 100644 (file)
@@ -40,7 +40,7 @@
 #include <mach/pxa25x.h>
 #include <mach/reset.h>
 #include <mach/irda.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/mmc.h>
 #include <mach/udc.h>
 #include <mach/tosa_bt.h>
index f79c9cb70ae48c0ce4acc6eb3add778ce4901800..825f540176d25f06b0525a82b115433c7f765c90 100644 (file)
@@ -47,7 +47,7 @@
 #include <mach/mmc.h>
 #include <mach/irda.h>
 #include <mach/ohci.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 
 #include "generic.h"
 #include "devices.h"
index dd031cc418478301458edbafa01fd93f0abde4c5..d33c232b686cae8e06726f8b134148d5935499ab 100644 (file)
@@ -45,7 +45,7 @@
 #include <mach/pxa25x.h>
 #include <mach/audio.h>
 #include <mach/pxafb.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/regs-uart.h>
 #include <mach/viper.h>
 
index c256c57642c06a36a0f72870124068aa252fa7cd..cefd1c0a854aa920df0fdd5704dee5550a07123f 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/gpio.h>
 
 #include <mach/pxa300.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
 #include <mach/zylonite.h>
 
 #include "generic.h"
index b6ec106277762dbf71fdccc95d943750e4a5792f..d4cfa214538649cde7e389e281cbf634aced1e13 100644 (file)
@@ -24,7 +24,6 @@ config REALVIEW_EB_ARM11MP
 config REALVIEW_EB_ARM11MP_REVB
        bool "Support ARM11MPCore RevB tile"
        depends on REALVIEW_EB_ARM11MP
-       default n
        help
          Enable support for the ARM11MPCore RevB tile on the Realview
          platform. Since there are device address differences, a
@@ -48,6 +47,15 @@ config MACH_REALVIEW_PB1176
        help
          Include support for the ARM(R) RealView ARM1176 Platform Baseboard.
 
+config REALVIEW_PB1176_SECURE_FLASH
+       bool "Allow access to the secure flash memory block"
+       depends on MACH_REALVIEW_PB1176
+       default n
+       help
+         Select this option if Linux will only run in secure mode on the
+         RealView PB1176 platform and access to the secure flash memory
+         block (64MB @ 0x3c000000) is required.
+
 config MACH_REALVIEW_PBA8
        bool "Support RealView/PB-A8 platform"
        select CPU_V7
@@ -58,6 +66,13 @@ config MACH_REALVIEW_PBA8
          PB-A8 is a platform with an on-board Cortex-A8 and has support for
          PCI-E and Compact Flash.
 
+config MACH_REALVIEW_PBX
+       bool "Support RealView/PBX platform"
+       select ARM_GIC
+       select HAVE_PATA_PLATFORM
+       help
+         Include support for the ARM(R) RealView PBX platform.
+
 config REALVIEW_HIGH_PHYS_OFFSET
        bool "High physical base address for the RealView platform"
        depends on !MACH_REALVIEW_PB1176
index 7bea8ffc4b5922cc05bff5000356aa8069aa9663..e704edb733c0ee0e0eee26f5ba2a2db02e10df1b 100644 (file)
@@ -7,5 +7,7 @@ obj-$(CONFIG_MACH_REALVIEW_EB)          += realview_eb.o
 obj-$(CONFIG_MACH_REALVIEW_PB11MP)     += realview_pb11mp.o
 obj-$(CONFIG_MACH_REALVIEW_PB1176)     += realview_pb1176.o
 obj-$(CONFIG_MACH_REALVIEW_PBA8)       += realview_pba8.o
-obj-$(CONFIG_SMP)                      += platsmp.o headsmp.o localtimer.o
+obj-$(CONFIG_MACH_REALVIEW_PBX)                += realview_pbx.o
+obj-$(CONFIG_SMP)                      += platsmp.o headsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)              += hotplug.o
+obj-$(CONFIG_LOCAL_TIMERS)             += localtimer.o
index 076acbc50706272d9ab0713b3801be20bc6e067e..9ea9c05093cd47afed1d6798d5a2eeb9d9333f43 100644 (file)
@@ -48,6 +48,9 @@
 
 #include <asm/hardware/gic.h>
 
+#include <mach/platform.h>
+#include <mach/irqs.h>
+
 #include "core.h"
 #include "clock.h"
 
@@ -578,21 +581,22 @@ void realview_leds_event(led_event_t ledevt)
 {
        unsigned long flags;
        u32 val;
+       u32 led = 1 << smp_processor_id();
 
        local_irq_save(flags);
        val = readl(VA_LEDS_BASE);
 
        switch (ledevt) {
        case led_idle_start:
-               val = val & ~REALVIEW_SYS_LED0;
+               val = val & ~led;
                break;
 
        case led_idle_end:
-               val = val | REALVIEW_SYS_LED0;
+               val = val | led;
                break;
 
        case led_timer:
-               val = val ^ REALVIEW_SYS_LED1;
+               val = val ^ REALVIEW_SYS_LED7;
                break;
 
        case led_halted:
index 21c08637683b72ca1105e469e582b8c8230bd9c2..59a337ba4be78c48e710d4650c2eca16d7c085c2 100644 (file)
@@ -51,9 +51,6 @@ extern struct mmc_platform_data realview_mmc0_plat_data;
 extern struct mmc_platform_data realview_mmc1_plat_data;
 extern struct clcd_board clcd_plat_data;
 extern void __iomem *gic_cpu_base_addr;
-#ifdef CONFIG_LOCAL_TIMERS
-extern void __iomem *twd_base;
-#endif
 extern void __iomem *timer0_va_base;
 extern void __iomem *timer1_va_base;
 extern void __iomem *timer2_va_base;
index 268d7701fa9bbc5409a89dc3876d832c94669cb1..794a8d91a6a62110872c1a989f167b10a90f595c 100644 (file)
 #define REALVIEW_EB11MP_SYS_PLD_CTRL1  0x74            /* Register offset for MPCore sysctl */
 #endif
 
-#define IRQ_EB_GIC_START       32
-
-/*
- * RealView EB interrupt sources
- */
-#define IRQ_EB_WDOG            (IRQ_EB_GIC_START + 0)          /* Watchdog timer */
-#define IRQ_EB_SOFT            (IRQ_EB_GIC_START + 1)          /* Software interrupt */
-#define IRQ_EB_COMMRx          (IRQ_EB_GIC_START + 2)          /* Debug Comm Rx interrupt */
-#define IRQ_EB_COMMTx          (IRQ_EB_GIC_START + 3)          /* Debug Comm Tx interrupt */
-#define IRQ_EB_TIMER0_1                (IRQ_EB_GIC_START + 4)          /* Timer 0 and 1 */
-#define IRQ_EB_TIMER2_3                (IRQ_EB_GIC_START + 5)          /* Timer 2 and 3 */
-#define IRQ_EB_GPIO0           (IRQ_EB_GIC_START + 6)          /* GPIO 0 */
-#define IRQ_EB_GPIO1           (IRQ_EB_GIC_START + 7)          /* GPIO 1 */
-#define IRQ_EB_GPIO2           (IRQ_EB_GIC_START + 8)          /* GPIO 2 */
-                                                               /* 9 reserved */
-#define IRQ_EB_RTC             (IRQ_EB_GIC_START + 10)         /* Real Time Clock */
-#define IRQ_EB_SSP             (IRQ_EB_GIC_START + 11)         /* Synchronous Serial Port */
-#define IRQ_EB_UART0           (IRQ_EB_GIC_START + 12)         /* UART 0 on development chip */
-#define IRQ_EB_UART1           (IRQ_EB_GIC_START + 13)         /* UART 1 on development chip */
-#define IRQ_EB_UART2           (IRQ_EB_GIC_START + 14)         /* UART 2 on development chip */
-#define IRQ_EB_UART3           (IRQ_EB_GIC_START + 15)         /* UART 3 on development chip */
-#define IRQ_EB_SCI             (IRQ_EB_GIC_START + 16)         /* Smart Card Interface */
-#define IRQ_EB_MMCI0A          (IRQ_EB_GIC_START + 17)         /* Multimedia Card 0A */
-#define IRQ_EB_MMCI0B          (IRQ_EB_GIC_START + 18)         /* Multimedia Card 0B */
-#define IRQ_EB_AACI            (IRQ_EB_GIC_START + 19)         /* Audio Codec */
-#define IRQ_EB_KMI0            (IRQ_EB_GIC_START + 20)         /* Keyboard/Mouse port 0 */
-#define IRQ_EB_KMI1            (IRQ_EB_GIC_START + 21)         /* Keyboard/Mouse port 1 */
-#define IRQ_EB_CHARLCD         (IRQ_EB_GIC_START + 22)         /* Character LCD */
-#define IRQ_EB_CLCD            (IRQ_EB_GIC_START + 23)         /* CLCD controller */
-#define IRQ_EB_DMA             (IRQ_EB_GIC_START + 24)         /* DMA controller */
-#define IRQ_EB_PWRFAIL         (IRQ_EB_GIC_START + 25)         /* Power failure */
-#define IRQ_EB_PISMO           (IRQ_EB_GIC_START + 26)         /* PISMO interface */
-#define IRQ_EB_DoC             (IRQ_EB_GIC_START + 27)         /* Disk on Chip memory controller */
-#define IRQ_EB_ETH             (IRQ_EB_GIC_START + 28)         /* Ethernet controller */
-#define IRQ_EB_USB             (IRQ_EB_GIC_START + 29)         /* USB controller */
-#define IRQ_EB_TSPEN           (IRQ_EB_GIC_START + 30)         /* Touchscreen pen */
-#define IRQ_EB_TSKPAD          (IRQ_EB_GIC_START + 31)         /* Touchscreen keypad */
-
-/*
- * RealView EB + ARM11MPCore interrupt sources (primary GIC on the core tile)
- */
-#define IRQ_EB11MP_AACI                (IRQ_EB_GIC_START + 0)
-#define IRQ_EB11MP_TIMER0_1    (IRQ_EB_GIC_START + 1)
-#define IRQ_EB11MP_TIMER2_3    (IRQ_EB_GIC_START + 2)
-#define IRQ_EB11MP_USB         (IRQ_EB_GIC_START + 3)
-#define IRQ_EB11MP_UART0       (IRQ_EB_GIC_START + 4)
-#define IRQ_EB11MP_UART1       (IRQ_EB_GIC_START + 5)
-#define IRQ_EB11MP_RTC         (IRQ_EB_GIC_START + 6)
-#define IRQ_EB11MP_KMI0                (IRQ_EB_GIC_START + 7)
-#define IRQ_EB11MP_KMI1                (IRQ_EB_GIC_START + 8)
-#define IRQ_EB11MP_ETH         (IRQ_EB_GIC_START + 9)
-#define IRQ_EB11MP_EB_IRQ1     (IRQ_EB_GIC_START + 10)         /* main GIC */
-#define IRQ_EB11MP_EB_IRQ2     (IRQ_EB_GIC_START + 11)         /* tile GIC */
-#define IRQ_EB11MP_EB_FIQ1     (IRQ_EB_GIC_START + 12)         /* main GIC */
-#define IRQ_EB11MP_EB_FIQ2     (IRQ_EB_GIC_START + 13)         /* tile GIC */
-#define IRQ_EB11MP_MMCI0A      (IRQ_EB_GIC_START + 14)
-#define IRQ_EB11MP_MMCI0B      (IRQ_EB_GIC_START + 15)
-
-#define IRQ_EB11MP_PMU_CPU0    (IRQ_EB_GIC_START + 17)
-#define IRQ_EB11MP_PMU_CPU1    (IRQ_EB_GIC_START + 18)
-#define IRQ_EB11MP_PMU_CPU2    (IRQ_EB_GIC_START + 19)
-#define IRQ_EB11MP_PMU_CPU3    (IRQ_EB_GIC_START + 20)
-#define IRQ_EB11MP_PMU_SCU0    (IRQ_EB_GIC_START + 21)
-#define IRQ_EB11MP_PMU_SCU1    (IRQ_EB_GIC_START + 22)
-#define IRQ_EB11MP_PMU_SCU2    (IRQ_EB_GIC_START + 23)
-#define IRQ_EB11MP_PMU_SCU3    (IRQ_EB_GIC_START + 24)
-#define IRQ_EB11MP_PMU_SCU4    (IRQ_EB_GIC_START + 25)
-#define IRQ_EB11MP_PMU_SCU5    (IRQ_EB_GIC_START + 26)
-#define IRQ_EB11MP_PMU_SCU6    (IRQ_EB_GIC_START + 27)
-#define IRQ_EB11MP_PMU_SCU7    (IRQ_EB_GIC_START + 28)
-
-#define IRQ_EB11MP_L220_EVENT  (IRQ_EB_GIC_START + 29)
-#define IRQ_EB11MP_L220_SLAVE  (IRQ_EB_GIC_START + 30)
-#define IRQ_EB11MP_L220_DECODE (IRQ_EB_GIC_START + 31)
-
-#define IRQ_EB11MP_UART2       -1
-#define IRQ_EB11MP_UART3       -1
-#define IRQ_EB11MP_CLCD                -1
-#define IRQ_EB11MP_DMA         -1
-#define IRQ_EB11MP_WDOG                -1
-#define IRQ_EB11MP_GPIO0       -1
-#define IRQ_EB11MP_GPIO1       -1
-#define IRQ_EB11MP_GPIO2       -1
-#define IRQ_EB11MP_SCI         -1
-#define IRQ_EB11MP_SSP         -1
-
-#define NR_GIC_EB11MP          2
-
-/*
- * Only define NR_IRQS if less than NR_IRQS_EB
- */
-#define NR_IRQS_EB             (IRQ_EB_GIC_START + 96)
-
-#if defined(CONFIG_MACH_REALVIEW_EB) \
-       && (!defined(NR_IRQS) || (NR_IRQS < NR_IRQS_EB))
-#undef NR_IRQS
-#define NR_IRQS                        NR_IRQS_EB
-#endif
-
-#if defined(CONFIG_REALVIEW_EB_ARM11MP) || defined(CONFIG_REALVIEW_EB_A9MP) \
-       && (!defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_EB11MP))
-#undef MAX_GIC_NR
-#define MAX_GIC_NR             NR_GIC_EB11MP
-#endif
-
 /*
  * Core tile identification (REALVIEW_SYS_PROCID)
  */
index 858eea7b1adce12139d6d5d0bb58c75c40159c58..98f8e7eeacc28a1dabc753bc6ed7e643c25f31c6 100644 (file)
@@ -32,6 +32,8 @@
 #define REALVIEW_PB1176_SDRAM67_BASE           0x70000000 /* SDRAM banks 6 and 7 */
 #define REALVIEW_PB1176_FLASH_BASE             0x30000000
 #define REALVIEW_PB1176_FLASH_SIZE             SZ_64M
+#define REALVIEW_PB1176_SEC_FLASH_BASE         0x3C000000 /* Secure flash */
+#define REALVIEW_PB1176_SEC_FLASH_SIZE         SZ_64M
 
 #define REALVIEW_PB1176_TIMER0_1_BASE          0x10104000 /* Timer 0 and 1 */
 #define REALVIEW_PB1176_TIMER2_3_BASE          0x10105000 /* Timer 2 and 3 */
 #define REALVIEW_PB1176_GIC_DIST_BASE          0x10041000 /* GIC distributor, on FPGA */
 #define REALVIEW_PB1176_L220_BASE              0x10110000 /* L220 registers */
 
-/*
- * Irqs
- */
-#define IRQ_DC1176_GIC_START                   32
-#define IRQ_PB1176_GIC_START                   64
-
-/*
- * ARM1176 DevChip interrupt sources (primary GIC)
- */
-#define IRQ_DC1176_WATCHDOG    (IRQ_DC1176_GIC_START + 0)      /* Watchdog timer */
-#define IRQ_DC1176_SOFTINT     (IRQ_DC1176_GIC_START + 1)      /* Software interrupt */
-#define IRQ_DC1176_COMMRx      (IRQ_DC1176_GIC_START + 2)      /* Debug Comm Rx interrupt */
-#define IRQ_DC1176_COMMTx      (IRQ_DC1176_GIC_START + 3)      /* Debug Comm Tx interrupt */
-#define IRQ_DC1176_TIMER0      (IRQ_DC1176_GIC_START + 8)      /* Timer 0 */
-#define IRQ_DC1176_TIMER1      (IRQ_DC1176_GIC_START + 9)      /* Timer 1 */
-#define IRQ_DC1176_TIMER2      (IRQ_DC1176_GIC_START + 10)     /* Timer 2 */
-#define IRQ_DC1176_APC         (IRQ_DC1176_GIC_START + 11)
-#define IRQ_DC1176_IEC         (IRQ_DC1176_GIC_START + 12)
-#define IRQ_DC1176_L2CC                (IRQ_DC1176_GIC_START + 13)
-#define IRQ_DC1176_RTC         (IRQ_DC1176_GIC_START + 14)
-#define IRQ_DC1176_CLCD                (IRQ_DC1176_GIC_START + 15)     /* CLCD controller */
-#define IRQ_DC1176_UART0       (IRQ_DC1176_GIC_START + 18)     /* UART 0 on development chip */
-#define IRQ_DC1176_UART1       (IRQ_DC1176_GIC_START + 19)     /* UART 1 on development chip */
-#define IRQ_DC1176_UART2       (IRQ_DC1176_GIC_START + 20)     /* UART 2 on development chip */
-#define IRQ_DC1176_UART3       (IRQ_DC1176_GIC_START + 21)     /* UART 3 on development chip */
-
-#define IRQ_DC1176_PB_IRQ2     (IRQ_DC1176_GIC_START + 30)     /* tile GIC */
-#define IRQ_DC1176_PB_IRQ1     (IRQ_DC1176_GIC_START + 31)     /* main GIC */
-
-/*
- * RealView PB1176 interrupt sources (secondary GIC)
- */
-#define IRQ_PB1176_MMCI0A      (IRQ_PB1176_GIC_START + 1)      /* Multimedia Card 0A */
-#define IRQ_PB1176_MMCI0B      (IRQ_PB1176_GIC_START + 2)      /* Multimedia Card 0A */
-#define IRQ_PB1176_KMI0                (IRQ_PB1176_GIC_START + 3)      /* Keyboard/Mouse port 0 */
-#define IRQ_PB1176_KMI1                (IRQ_PB1176_GIC_START + 4)      /* Keyboard/Mouse port 1 */
-#define IRQ_PB1176_SCI         (IRQ_PB1176_GIC_START + 5)
-#define IRQ_PB1176_UART4       (IRQ_PB1176_GIC_START + 6)      /* UART 4 on baseboard */
-#define IRQ_PB1176_CHARLCD     (IRQ_PB1176_GIC_START + 7)      /* Character LCD */
-#define IRQ_PB1176_GPIO1       (IRQ_PB1176_GIC_START + 8)
-#define IRQ_PB1176_GPIO2       (IRQ_PB1176_GIC_START + 9)
-#define IRQ_PB1176_ETH         (IRQ_PB1176_GIC_START + 10)     /* Ethernet controller */
-#define IRQ_PB1176_USB         (IRQ_PB1176_GIC_START + 11)     /* USB controller */
-
-#define IRQ_PB1176_PISMO       (IRQ_PB1176_GIC_START + 16)
-
-#define IRQ_PB1176_AACI                (IRQ_PB1176_GIC_START + 19)     /* Audio Codec */
-
-#define IRQ_PB1176_TIMER0_1    (IRQ_PB1176_GIC_START + 22)
-#define IRQ_PB1176_TIMER2_3    (IRQ_PB1176_GIC_START + 23)
-#define IRQ_PB1176_DMAC                (IRQ_PB1176_GIC_START + 24)     /* DMA controller */
-#define IRQ_PB1176_RTC         (IRQ_PB1176_GIC_START + 25)     /* Real Time Clock */
-
-#define IRQ_PB1176_GPIO0       -1
-#define IRQ_PB1176_SSP         -1
-#define IRQ_PB1176_SCTL                -1
-
-#define NR_GIC_PB1176          2
-
-/*
- * Only define NR_IRQS if less than NR_IRQS_PB1176
- */
-#define NR_IRQS_PB1176         (IRQ_DC1176_GIC_START + 96)
-
-#if defined(CONFIG_MACH_REALVIEW_PB1176)
-
-#if !defined(NR_IRQS) || (NR_IRQS < NR_IRQS_PB1176)
-#undef NR_IRQS
-#define NR_IRQS                        NR_IRQS_PB1176
-#endif
-
-#if !defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_PB1176)
-#undef MAX_GIC_NR
-#define MAX_GIC_NR             NR_GIC_PB1176
-#endif
-
-#endif /* CONFIG_MACH_REALVIEW_PB1176 */
-
 #endif /* __ASM_ARCH_BOARD_PB1176_H */
index 53ea0e7a1267b9957a231530e9bf3e645c161061..f0d68e0fea01dc91f31a3cc7c81473978ebeba83 100644 (file)
 #define REALVIEW_TC11MP_GIC_DIST_BASE          0x1F001000      /* Test chip interrupt controller distributor */
 #define REALVIEW_TC11MP_L220_BASE              0x1F002000      /* L220 registers */
 
-/*
- * Irqs
- */
-#define IRQ_TC11MP_GIC_START                   32
-#define IRQ_PB11MP_GIC_START                   64
-
-/*
- * ARM11MPCore test chip interrupt sources (primary GIC on the test chip)
- */
-#define IRQ_TC11MP_AACI                (IRQ_TC11MP_GIC_START + 0)
-#define IRQ_TC11MP_TIMER0_1    (IRQ_TC11MP_GIC_START + 1)
-#define IRQ_TC11MP_TIMER2_3    (IRQ_TC11MP_GIC_START + 2)
-#define IRQ_TC11MP_USB         (IRQ_TC11MP_GIC_START + 3)
-#define IRQ_TC11MP_UART0       (IRQ_TC11MP_GIC_START + 4)
-#define IRQ_TC11MP_UART1       (IRQ_TC11MP_GIC_START + 5)
-#define IRQ_TC11MP_RTC         (IRQ_TC11MP_GIC_START + 6)
-#define IRQ_TC11MP_KMI0                (IRQ_TC11MP_GIC_START + 7)
-#define IRQ_TC11MP_KMI1                (IRQ_TC11MP_GIC_START + 8)
-#define IRQ_TC11MP_ETH         (IRQ_TC11MP_GIC_START + 9)
-#define IRQ_TC11MP_PB_IRQ1     (IRQ_TC11MP_GIC_START + 10)             /* main GIC */
-#define IRQ_TC11MP_PB_IRQ2     (IRQ_TC11MP_GIC_START + 11)             /* tile GIC */
-#define IRQ_TC11MP_PB_FIQ1     (IRQ_TC11MP_GIC_START + 12)             /* main GIC */
-#define IRQ_TC11MP_PB_FIQ2     (IRQ_TC11MP_GIC_START + 13)             /* tile GIC */
-#define IRQ_TC11MP_MMCI0A      (IRQ_TC11MP_GIC_START + 14)
-#define IRQ_TC11MP_MMCI0B      (IRQ_TC11MP_GIC_START + 15)
-
-#define IRQ_TC11MP_PMU_CPU0    (IRQ_TC11MP_GIC_START + 17)
-#define IRQ_TC11MP_PMU_CPU1    (IRQ_TC11MP_GIC_START + 18)
-#define IRQ_TC11MP_PMU_CPU2    (IRQ_TC11MP_GIC_START + 19)
-#define IRQ_TC11MP_PMU_CPU3    (IRQ_TC11MP_GIC_START + 20)
-#define IRQ_TC11MP_PMU_SCU0    (IRQ_TC11MP_GIC_START + 21)
-#define IRQ_TC11MP_PMU_SCU1    (IRQ_TC11MP_GIC_START + 22)
-#define IRQ_TC11MP_PMU_SCU2    (IRQ_TC11MP_GIC_START + 23)
-#define IRQ_TC11MP_PMU_SCU3    (IRQ_TC11MP_GIC_START + 24)
-#define IRQ_TC11MP_PMU_SCU4    (IRQ_TC11MP_GIC_START + 25)
-#define IRQ_TC11MP_PMU_SCU5    (IRQ_TC11MP_GIC_START + 26)
-#define IRQ_TC11MP_PMU_SCU6    (IRQ_TC11MP_GIC_START + 27)
-#define IRQ_TC11MP_PMU_SCU7    (IRQ_TC11MP_GIC_START + 28)
-
-#define IRQ_TC11MP_L220_EVENT  (IRQ_TC11MP_GIC_START + 29)
-#define IRQ_TC11MP_L220_SLAVE  (IRQ_TC11MP_GIC_START + 30)
-#define IRQ_TC11MP_L220_DECODE (IRQ_TC11MP_GIC_START + 31)
-
-/*
- * RealView PB11MPCore GIC interrupt sources (secondary GIC on the board)
- */
-#define IRQ_PB11MP_WATCHDOG    (IRQ_PB11MP_GIC_START + 0)      /* Watchdog timer */
-#define IRQ_PB11MP_SOFT                (IRQ_PB11MP_GIC_START + 1)      /* Software interrupt */
-#define IRQ_PB11MP_COMMRx      (IRQ_PB11MP_GIC_START + 2)      /* Debug Comm Rx interrupt */
-#define IRQ_PB11MP_COMMTx      (IRQ_PB11MP_GIC_START + 3)      /* Debug Comm Tx interrupt */
-#define IRQ_PB11MP_GPIO0       (IRQ_PB11MP_GIC_START + 6)      /* GPIO 0 */
-#define IRQ_PB11MP_GPIO1       (IRQ_PB11MP_GIC_START + 7)      /* GPIO 1 */
-#define IRQ_PB11MP_GPIO2       (IRQ_PB11MP_GIC_START + 8)      /* GPIO 2 */
-                                                               /* 9 reserved */
-#define IRQ_PB11MP_RTC_GIC1    (IRQ_PB11MP_GIC_START + 10)     /* Real Time Clock */
-#define IRQ_PB11MP_SSP         (IRQ_PB11MP_GIC_START + 11)     /* Synchronous Serial Port */
-#define IRQ_PB11MP_UART0_GIC1  (IRQ_PB11MP_GIC_START + 12)     /* UART 0 on development chip */
-#define IRQ_PB11MP_UART1_GIC1  (IRQ_PB11MP_GIC_START + 13)     /* UART 1 on development chip */
-#define IRQ_PB11MP_UART2       (IRQ_PB11MP_GIC_START + 14)     /* UART 2 on development chip */
-#define IRQ_PB11MP_UART3       (IRQ_PB11MP_GIC_START + 15)     /* UART 3 on development chip */
-#define IRQ_PB11MP_SCI         (IRQ_PB11MP_GIC_START + 16)     /* Smart Card Interface */
-#define IRQ_PB11MP_MMCI0A_GIC1 (IRQ_PB11MP_GIC_START + 17)     /* Multimedia Card 0A */
-#define IRQ_PB11MP_MMCI0B_GIC1 (IRQ_PB11MP_GIC_START + 18)     /* Multimedia Card 0B */
-#define IRQ_PB11MP_AACI_GIC1   (IRQ_PB11MP_GIC_START + 19)     /* Audio Codec */
-#define IRQ_PB11MP_KMI0_GIC1   (IRQ_PB11MP_GIC_START + 20)     /* Keyboard/Mouse port 0 */
-#define IRQ_PB11MP_KMI1_GIC1   (IRQ_PB11MP_GIC_START + 21)     /* Keyboard/Mouse port 1 */
-#define IRQ_PB11MP_CHARLCD     (IRQ_PB11MP_GIC_START + 22)     /* Character LCD */
-#define IRQ_PB11MP_CLCD                (IRQ_PB11MP_GIC_START + 23)     /* CLCD controller */
-#define IRQ_PB11MP_DMAC                (IRQ_PB11MP_GIC_START + 24)     /* DMA controller */
-#define IRQ_PB11MP_PWRFAIL     (IRQ_PB11MP_GIC_START + 25)     /* Power failure */
-#define IRQ_PB11MP_PISMO       (IRQ_PB11MP_GIC_START + 26)     /* PISMO interface */
-#define IRQ_PB11MP_DoC         (IRQ_PB11MP_GIC_START + 27)     /* Disk on Chip memory controller */
-#define IRQ_PB11MP_ETH_GIC1    (IRQ_PB11MP_GIC_START + 28)     /* Ethernet controller */
-#define IRQ_PB11MP_USB_GIC1    (IRQ_PB11MP_GIC_START + 29)     /* USB controller */
-#define IRQ_PB11MP_TSPEN       (IRQ_PB11MP_GIC_START + 30)     /* Touchscreen pen */
-#define IRQ_PB11MP_TSKPAD      (IRQ_PB11MP_GIC_START + 31)     /* Touchscreen keypad */
-
-#define IRQ_PB11MP_SMC         -1
-#define IRQ_PB11MP_SCTL                -1
-
-#define NR_GIC_PB11MP          2
-
-/*
- * Only define NR_IRQS if less than NR_IRQS_PB11MP
- */
-#define NR_IRQS_PB11MP         (IRQ_TC11MP_GIC_START + 96)
-
-#if defined(CONFIG_MACH_REALVIEW_PB11MP)
-
-#if !defined(NR_IRQS) || (NR_IRQS < NR_IRQS_PB11MP)
-#undef NR_IRQS
-#define NR_IRQS                        NR_IRQS_PB11MP
-#endif
-
-#if !defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_PB11MP)
-#undef MAX_GIC_NR
-#define MAX_GIC_NR             NR_GIC_PB11MP
-#endif
-
-#endif /* CONFIG_MACH_REALVIEW_PB11MP */
-
 #endif /* __ASM_ARCH_BOARD_PB11MP_H */
index 307f97b16e5b85425c9cd6a300200537035a3973..4dfc67a4f45ffed201e29a6c5fdfec72495c5c30 100644 (file)
 #define REALVIEW_PBA8_PCI_IO_SIZE              0x1000          /* 4 Kb */
 #define REALVIEW_PBA8_PCI_MEM_SIZE             0x20000000      /* 512 MB */
 
-/*
- * Irqs
- */
-#define IRQ_PBA8_GIC_START                     32
-
-/* L220
-#define IRQ_PBA8_L220_EVENT    (IRQ_PBA8_GIC_START + 29)
-#define IRQ_PBA8_L220_SLAVE    (IRQ_PBA8_GIC_START + 30)
-#define IRQ_PBA8_L220_DECODE   (IRQ_PBA8_GIC_START + 31)
-*/
-
-/*
- * PB-A8 on-board gic irq sources
- */
-#define IRQ_PBA8_WATCHDOG      (IRQ_PBA8_GIC_START + 0)        /* Watchdog timer */
-#define IRQ_PBA8_SOFT          (IRQ_PBA8_GIC_START + 1)        /* Software interrupt */
-#define IRQ_PBA8_COMMRx                (IRQ_PBA8_GIC_START + 2)        /* Debug Comm Rx interrupt */
-#define IRQ_PBA8_COMMTx                (IRQ_PBA8_GIC_START + 3)        /* Debug Comm Tx interrupt */
-#define IRQ_PBA8_TIMER0_1      (IRQ_PBA8_GIC_START + 4)        /* Timer 0/1 (default timer) */
-#define IRQ_PBA8_TIMER2_3      (IRQ_PBA8_GIC_START + 5)        /* Timer 2/3 */
-#define IRQ_PBA8_GPIO0         (IRQ_PBA8_GIC_START + 6)        /* GPIO 0 */
-#define IRQ_PBA8_GPIO1         (IRQ_PBA8_GIC_START + 7)        /* GPIO 1 */
-#define IRQ_PBA8_GPIO2         (IRQ_PBA8_GIC_START + 8)        /* GPIO 2 */
-                                                               /* 9 reserved */
-#define IRQ_PBA8_RTC           (IRQ_PBA8_GIC_START + 10)       /* Real Time Clock */
-#define IRQ_PBA8_SSP           (IRQ_PBA8_GIC_START + 11)       /* Synchronous Serial Port */
-#define IRQ_PBA8_UART0         (IRQ_PBA8_GIC_START + 12)       /* UART 0 on development chip */
-#define IRQ_PBA8_UART1         (IRQ_PBA8_GIC_START + 13)       /* UART 1 on development chip */
-#define IRQ_PBA8_UART2         (IRQ_PBA8_GIC_START + 14)       /* UART 2 on development chip */
-#define IRQ_PBA8_UART3         (IRQ_PBA8_GIC_START + 15)       /* UART 3 on development chip */
-#define IRQ_PBA8_SCI           (IRQ_PBA8_GIC_START + 16)       /* Smart Card Interface */
-#define IRQ_PBA8_MMCI0A                (IRQ_PBA8_GIC_START + 17)       /* Multimedia Card 0A */
-#define IRQ_PBA8_MMCI0B                (IRQ_PBA8_GIC_START + 18)       /* Multimedia Card 0B */
-#define IRQ_PBA8_AACI          (IRQ_PBA8_GIC_START + 19)       /* Audio Codec */
-#define IRQ_PBA8_KMI0          (IRQ_PBA8_GIC_START + 20)       /* Keyboard/Mouse port 0 */
-#define IRQ_PBA8_KMI1          (IRQ_PBA8_GIC_START + 21)       /* Keyboard/Mouse port 1 */
-#define IRQ_PBA8_CHARLCD       (IRQ_PBA8_GIC_START + 22)       /* Character LCD */
-#define IRQ_PBA8_CLCD          (IRQ_PBA8_GIC_START + 23)       /* CLCD controller */
-#define IRQ_PBA8_DMAC          (IRQ_PBA8_GIC_START + 24)       /* DMA controller */
-#define IRQ_PBA8_PWRFAIL       (IRQ_PBA8_GIC_START + 25)       /* Power failure */
-#define IRQ_PBA8_PISMO         (IRQ_PBA8_GIC_START + 26)       /* PISMO interface */
-#define IRQ_PBA8_DoC           (IRQ_PBA8_GIC_START + 27)       /* Disk on Chip memory controller */
-#define IRQ_PBA8_ETH           (IRQ_PBA8_GIC_START + 28)       /* Ethernet controller */
-#define IRQ_PBA8_USB           (IRQ_PBA8_GIC_START + 29)       /* USB controller */
-#define IRQ_PBA8_TSPEN         (IRQ_PBA8_GIC_START + 30)       /* Touchscreen pen */
-#define IRQ_PBA8_TSKPAD                (IRQ_PBA8_GIC_START + 31)       /* Touchscreen keypad */
-
-/* ... */
-#define IRQ_PBA8_PCI0          (IRQ_PBA8_GIC_START + 50)
-#define IRQ_PBA8_PCI1          (IRQ_PBA8_GIC_START + 51)
-#define IRQ_PBA8_PCI2          (IRQ_PBA8_GIC_START + 52)
-#define IRQ_PBA8_PCI3          (IRQ_PBA8_GIC_START + 53)
-
-#define IRQ_PBA8_SMC           -1
-#define IRQ_PBA8_SCTL          -1
-
-#define NR_GIC_PBA8            1
-
-/*
- * Only define NR_IRQS if less than NR_IRQS_PBA8
- */
-#define NR_IRQS_PBA8           (IRQ_PBA8_GIC_START + 64)
-
-#if defined(CONFIG_MACH_REALVIEW_PBA8)
-
-#if !defined(NR_IRQS) || (NR_IRQS < NR_IRQS_PBA8)
-#undef NR_IRQS
-#define NR_IRQS                        NR_IRQS_PBA8
-#endif
-
-#if !defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_PBA8)
-#undef MAX_GIC_NR
-#define MAX_GIC_NR             NR_GIC_PBA8
-#endif
-
-#endif /* CONFIG_MACH_REALVIEW_PBA8 */
-
 #endif /* __ASM_ARCH_BOARD_PBA8_H */
diff --git a/arch/arm/mach-realview/include/mach/board-pbx.h b/arch/arm/mach-realview/include/mach/board-pbx.h
new file mode 100644 (file)
index 0000000..848bfff
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * arch/arm/mach-realview/include/mach/board-pbx.h
+ *
+ * Copyright (C) 2009 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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_BOARD_PBX_H
+#define __ASM_ARCH_BOARD_PBX_H
+
+#include <mach/platform.h>
+
+/*
+ * Peripheral addresses
+ */
+#define REALVIEW_PBX_UART0_BASE                        0x10009000      /* UART 0 */
+#define REALVIEW_PBX_UART1_BASE                        0x1000A000      /* UART 1 */
+#define REALVIEW_PBX_UART2_BASE                        0x1000B000      /* UART 2 */
+#define REALVIEW_PBX_UART3_BASE                        0x1000C000      /* UART 3 */
+#define REALVIEW_PBX_SSP_BASE                  0x1000D000      /* Synchronous Serial Port */
+#define REALVIEW_PBX_WATCHDOG0_BASE            0x1000F000      /* Watchdog 0 */
+#define REALVIEW_PBX_WATCHDOG_BASE             0x10010000      /* watchdog interface */
+#define REALVIEW_PBX_TIMER0_1_BASE             0x10011000      /* Timer 0 and 1 */
+#define REALVIEW_PBX_TIMER2_3_BASE             0x10012000      /* Timer 2 and 3 */
+#define REALVIEW_PBX_GPIO0_BASE                        0x10013000      /* GPIO port 0 */
+#define REALVIEW_PBX_RTC_BASE                  0x10017000      /* Real Time Clock */
+#define REALVIEW_PBX_TIMER4_5_BASE             0x10018000      /* Timer 4/5 */
+#define REALVIEW_PBX_TIMER6_7_BASE             0x10019000      /* Timer 6/7 */
+#define REALVIEW_PBX_SCTL_BASE                 0x1001A000      /* System Controller */
+#define REALVIEW_PBX_CLCD_BASE                 0x10020000      /* CLCD */
+#define REALVIEW_PBX_ONB_SRAM_BASE             0x10060000      /* On-board SRAM */
+#define REALVIEW_PBX_DMC_BASE                  0x100E0000      /* DMC configuration */
+#define REALVIEW_PBX_SMC_BASE                  0x100E1000      /* SMC configuration */
+#define REALVIEW_PBX_CAN_BASE                  0x100E2000      /* CAN bus */
+#define REALVIEW_PBX_GIC_CPU_BASE              0x1E000000      /* Generic interrupt controller CPU interface */
+#define REALVIEW_PBX_FLASH0_BASE               0x40000000
+#define REALVIEW_PBX_FLASH0_SIZE               SZ_64M
+#define REALVIEW_PBX_FLASH1_BASE               0x44000000
+#define REALVIEW_PBX_FLASH1_SIZE               SZ_64M
+#define REALVIEW_PBX_ETH_BASE                  0x4E000000      /* Ethernet */
+#define REALVIEW_PBX_USB_BASE                  0x4F000000      /* USB */
+#define REALVIEW_PBX_GIC_DIST_BASE             0x1E001000      /* Generic interrupt controller distributor */
+#define REALVIEW_PBX_LT_BASE                   0xC0000000      /* Logic Tile expansion */
+#define REALVIEW_PBX_SDRAM6_BASE               0x70000000      /* SDRAM bank 6 256MB */
+#define REALVIEW_PBX_SDRAM7_BASE               0x80000000      /* SDRAM bank 7 256MB */
+
+/*
+ * Tile-specific addresses
+ */
+#define REALVIEW_PBX_TILE_SCU_BASE             0x1F000000      /* SCU registers */
+#define REALVIEW_PBX_TILE_GIC_CPU_BASE         0x1F000100      /* Private Generic interrupt controller CPU interface */
+#define REALVIEW_PBX_TILE_TWD_BASE             0x1F000600
+#define REALVIEW_PBX_TILE_TWD_PERCPU_BASE      0x1F000700
+#define REALVIEW_PBX_TILE_TWD_SIZE             0x00000100
+#define REALVIEW_PBX_TILE_GIC_DIST_BASE                0x1F001000      /* Private Generic interrupt controller distributor */
+#define REALVIEW_PBX_TILE_L220_BASE            0x1F002000      /* L220 registers */
+
+#define REALVIEW_PBX_SYS_PLD_CTRL1             0x74
+
+/*
+ * PBX PCI regions
+ */
+#define REALVIEW_PBX_PCI_BASE                  0x90040000      /* PCI-X Unit base */
+#define REALVIEW_PBX_PCI_IO_BASE               0x90050000      /* IO Region on AHB */
+#define REALVIEW_PBX_PCI_MEM_BASE              0xA0000000      /* MEM Region on AHB */
+
+#define REALVIEW_PBX_PCI_BASE_SIZE             0x10000         /* 16 Kb */
+#define REALVIEW_PBX_PCI_IO_SIZE               0x1000          /* 4 Kb */
+#define REALVIEW_PBX_PCI_MEM_SIZE              0x20000000      /* 512 MB */
+
+/*
+ * Core tile identification (REALVIEW_SYS_PROCID)
+ */
+#define REALVIEW_PBX_PROC_MASK          0xFF000000
+#define REALVIEW_PBX_PROC_ARM7TDMI      0x00000000
+#define REALVIEW_PBX_PROC_ARM9          0x02000000
+#define REALVIEW_PBX_PROC_ARM11         0x04000000
+#define REALVIEW_PBX_PROC_ARM11MP       0x06000000
+#define REALVIEW_PBX_PROC_A9MP          0x0C000000
+#define REALVIEW_PBX_PROC_A8            0x0E000000
+
+#define check_pbx_proc(proc_type)                                            \
+       ((readl(__io_address(REALVIEW_SYS_PROCID)) & REALVIEW_PBX_PROC_MASK) \
+       == proc_type)
+
+#ifdef CONFIG_MACH_REALVIEW_PBX
+#define core_tile_pbx11mp()     check_pbx_proc(REALVIEW_PBX_PROC_ARM11MP)
+#define core_tile_pbxa9mp()     check_pbx_proc(REALVIEW_PBX_PROC_A9MP)
+#define core_tile_pbxa8()       check_pbx_proc(REALVIEW_PBX_PROC_A8)
+#else
+#define core_tile_pbx11mp()     0
+#define core_tile_pbxa9mp()     0
+#define core_tile_pbxa8()       0
+#endif
+
+#endif /* __ASM_ARCH_BOARD_PBX_H */
index 92dbcb9e17923f7f26551f690c74a4d975e1a8e5..932d8af180624a7415bdb5a09aafcb4b3235adb0 100644 (file)
@@ -12,7 +12,8 @@
 
 #if defined(CONFIG_MACH_REALVIEW_EB) || \
     defined(CONFIG_MACH_REALVIEW_PB11MP) || \
-    defined(CONFIG_MACH_REALVIEW_PBA8)
+    defined(CONFIG_MACH_REALVIEW_PBA8) || \
+    defined(CONFIG_MACH_REALVIEW_PBX)
 #ifndef DEBUG_LL_UART_OFFSET
 #define DEBUG_LL_UART_OFFSET   0x00009000
 #elif DEBUG_LL_UART_OFFSET != 0x00009000
diff --git a/arch/arm/mach-realview/include/mach/irqs-eb.h b/arch/arm/mach-realview/include/mach/irqs-eb.h
new file mode 100644 (file)
index 0000000..204d537
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * arch/arm/mach-realview/include/mach/irqs-eb.h
+ *
+ * Copyright (C) 2007 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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 __MACH_IRQS_EB_H
+#define __MACH_IRQS_EB_H
+
+#define IRQ_EB_GIC_START       32
+
+/*
+ * RealView EB interrupt sources
+ */
+#define IRQ_EB_WDOG            (IRQ_EB_GIC_START + 0)          /* Watchdog timer */
+#define IRQ_EB_SOFT            (IRQ_EB_GIC_START + 1)          /* Software interrupt */
+#define IRQ_EB_COMMRx          (IRQ_EB_GIC_START + 2)          /* Debug Comm Rx interrupt */
+#define IRQ_EB_COMMTx          (IRQ_EB_GIC_START + 3)          /* Debug Comm Tx interrupt */
+#define IRQ_EB_TIMER0_1                (IRQ_EB_GIC_START + 4)          /* Timer 0 and 1 */
+#define IRQ_EB_TIMER2_3                (IRQ_EB_GIC_START + 5)          /* Timer 2 and 3 */
+#define IRQ_EB_GPIO0           (IRQ_EB_GIC_START + 6)          /* GPIO 0 */
+#define IRQ_EB_GPIO1           (IRQ_EB_GIC_START + 7)          /* GPIO 1 */
+#define IRQ_EB_GPIO2           (IRQ_EB_GIC_START + 8)          /* GPIO 2 */
+                                                               /* 9 reserved */
+#define IRQ_EB_RTC             (IRQ_EB_GIC_START + 10)         /* Real Time Clock */
+#define IRQ_EB_SSP             (IRQ_EB_GIC_START + 11)         /* Synchronous Serial Port */
+#define IRQ_EB_UART0           (IRQ_EB_GIC_START + 12)         /* UART 0 on development chip */
+#define IRQ_EB_UART1           (IRQ_EB_GIC_START + 13)         /* UART 1 on development chip */
+#define IRQ_EB_UART2           (IRQ_EB_GIC_START + 14)         /* UART 2 on development chip */
+#define IRQ_EB_UART3           (IRQ_EB_GIC_START + 15)         /* UART 3 on development chip */
+#define IRQ_EB_SCI             (IRQ_EB_GIC_START + 16)         /* Smart Card Interface */
+#define IRQ_EB_MMCI0A          (IRQ_EB_GIC_START + 17)         /* Multimedia Card 0A */
+#define IRQ_EB_MMCI0B          (IRQ_EB_GIC_START + 18)         /* Multimedia Card 0B */
+#define IRQ_EB_AACI            (IRQ_EB_GIC_START + 19)         /* Audio Codec */
+#define IRQ_EB_KMI0            (IRQ_EB_GIC_START + 20)         /* Keyboard/Mouse port 0 */
+#define IRQ_EB_KMI1            (IRQ_EB_GIC_START + 21)         /* Keyboard/Mouse port 1 */
+#define IRQ_EB_CHARLCD         (IRQ_EB_GIC_START + 22)         /* Character LCD */
+#define IRQ_EB_CLCD            (IRQ_EB_GIC_START + 23)         /* CLCD controller */
+#define IRQ_EB_DMA             (IRQ_EB_GIC_START + 24)         /* DMA controller */
+#define IRQ_EB_PWRFAIL         (IRQ_EB_GIC_START + 25)         /* Power failure */
+#define IRQ_EB_PISMO           (IRQ_EB_GIC_START + 26)         /* PISMO interface */
+#define IRQ_EB_DoC             (IRQ_EB_GIC_START + 27)         /* Disk on Chip memory controller */
+#define IRQ_EB_ETH             (IRQ_EB_GIC_START + 28)         /* Ethernet controller */
+#define IRQ_EB_USB             (IRQ_EB_GIC_START + 29)         /* USB controller */
+#define IRQ_EB_TSPEN           (IRQ_EB_GIC_START + 30)         /* Touchscreen pen */
+#define IRQ_EB_TSKPAD          (IRQ_EB_GIC_START + 31)         /* Touchscreen keypad */
+
+/*
+ * RealView EB + ARM11MPCore interrupt sources (primary GIC on the core tile)
+ */
+#define IRQ_EB11MP_AACI                (IRQ_EB_GIC_START + 0)
+#define IRQ_EB11MP_TIMER0_1    (IRQ_EB_GIC_START + 1)
+#define IRQ_EB11MP_TIMER2_3    (IRQ_EB_GIC_START + 2)
+#define IRQ_EB11MP_USB         (IRQ_EB_GIC_START + 3)
+#define IRQ_EB11MP_UART0       (IRQ_EB_GIC_START + 4)
+#define IRQ_EB11MP_UART1       (IRQ_EB_GIC_START + 5)
+#define IRQ_EB11MP_RTC         (IRQ_EB_GIC_START + 6)
+#define IRQ_EB11MP_KMI0                (IRQ_EB_GIC_START + 7)
+#define IRQ_EB11MP_KMI1                (IRQ_EB_GIC_START + 8)
+#define IRQ_EB11MP_ETH         (IRQ_EB_GIC_START + 9)
+#define IRQ_EB11MP_EB_IRQ1     (IRQ_EB_GIC_START + 10)         /* main GIC */
+#define IRQ_EB11MP_EB_IRQ2     (IRQ_EB_GIC_START + 11)         /* tile GIC */
+#define IRQ_EB11MP_EB_FIQ1     (IRQ_EB_GIC_START + 12)         /* main GIC */
+#define IRQ_EB11MP_EB_FIQ2     (IRQ_EB_GIC_START + 13)         /* tile GIC */
+#define IRQ_EB11MP_MMCI0A      (IRQ_EB_GIC_START + 14)
+#define IRQ_EB11MP_MMCI0B      (IRQ_EB_GIC_START + 15)
+
+#define IRQ_EB11MP_PMU_CPU0    (IRQ_EB_GIC_START + 17)
+#define IRQ_EB11MP_PMU_CPU1    (IRQ_EB_GIC_START + 18)
+#define IRQ_EB11MP_PMU_CPU2    (IRQ_EB_GIC_START + 19)
+#define IRQ_EB11MP_PMU_CPU3    (IRQ_EB_GIC_START + 20)
+#define IRQ_EB11MP_PMU_SCU0    (IRQ_EB_GIC_START + 21)
+#define IRQ_EB11MP_PMU_SCU1    (IRQ_EB_GIC_START + 22)
+#define IRQ_EB11MP_PMU_SCU2    (IRQ_EB_GIC_START + 23)
+#define IRQ_EB11MP_PMU_SCU3    (IRQ_EB_GIC_START + 24)
+#define IRQ_EB11MP_PMU_SCU4    (IRQ_EB_GIC_START + 25)
+#define IRQ_EB11MP_PMU_SCU5    (IRQ_EB_GIC_START + 26)
+#define IRQ_EB11MP_PMU_SCU6    (IRQ_EB_GIC_START + 27)
+#define IRQ_EB11MP_PMU_SCU7    (IRQ_EB_GIC_START + 28)
+
+#define IRQ_EB11MP_L220_EVENT  (IRQ_EB_GIC_START + 29)
+#define IRQ_EB11MP_L220_SLAVE  (IRQ_EB_GIC_START + 30)
+#define IRQ_EB11MP_L220_DECODE (IRQ_EB_GIC_START + 31)
+
+#define IRQ_EB11MP_UART2       -1
+#define IRQ_EB11MP_UART3       -1
+#define IRQ_EB11MP_CLCD                -1
+#define IRQ_EB11MP_DMA         -1
+#define IRQ_EB11MP_WDOG                -1
+#define IRQ_EB11MP_GPIO0       -1
+#define IRQ_EB11MP_GPIO1       -1
+#define IRQ_EB11MP_GPIO2       -1
+#define IRQ_EB11MP_SCI         -1
+#define IRQ_EB11MP_SSP         -1
+
+#define NR_GIC_EB11MP          2
+
+/*
+ * Only define NR_IRQS if less than NR_IRQS_EB
+ */
+#define NR_IRQS_EB             (IRQ_EB_GIC_START + 96)
+
+#if defined(CONFIG_MACH_REALVIEW_EB) \
+       && (!defined(NR_IRQS) || (NR_IRQS < NR_IRQS_EB))
+#undef NR_IRQS
+#define NR_IRQS                        NR_IRQS_EB
+#endif
+
+#if defined(CONFIG_REALVIEW_EB_ARM11MP) || defined(CONFIG_REALVIEW_EB_A9MP) \
+       && (!defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_EB11MP))
+#undef MAX_GIC_NR
+#define MAX_GIC_NR             NR_GIC_EB11MP
+#endif
+
+#endif /* __MACH_IRQS_EB_H */
diff --git a/arch/arm/mach-realview/include/mach/irqs-pb1176.h b/arch/arm/mach-realview/include/mach/irqs-pb1176.h
new file mode 100644 (file)
index 0000000..2410d4f
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * arch/arm/mach-realview/include/mach/irqs-pb1176.h
+ *
+ * Copyright (C) 2008 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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 __MACH_IRQS_PB1176_H
+#define __MACH_IRQS_PB1176_H
+
+#define IRQ_DC1176_GIC_START                   32
+#define IRQ_PB1176_GIC_START                   64
+
+/*
+ * ARM1176 DevChip interrupt sources (primary GIC)
+ */
+#define IRQ_DC1176_WATCHDOG    (IRQ_DC1176_GIC_START + 0)      /* Watchdog timer */
+#define IRQ_DC1176_SOFTINT     (IRQ_DC1176_GIC_START + 1)      /* Software interrupt */
+#define IRQ_DC1176_COMMRx      (IRQ_DC1176_GIC_START + 2)      /* Debug Comm Rx interrupt */
+#define IRQ_DC1176_COMMTx      (IRQ_DC1176_GIC_START + 3)      /* Debug Comm Tx interrupt */
+#define IRQ_DC1176_TIMER0      (IRQ_DC1176_GIC_START + 8)      /* Timer 0 */
+#define IRQ_DC1176_TIMER1      (IRQ_DC1176_GIC_START + 9)      /* Timer 1 */
+#define IRQ_DC1176_TIMER2      (IRQ_DC1176_GIC_START + 10)     /* Timer 2 */
+#define IRQ_DC1176_APC         (IRQ_DC1176_GIC_START + 11)
+#define IRQ_DC1176_IEC         (IRQ_DC1176_GIC_START + 12)
+#define IRQ_DC1176_L2CC                (IRQ_DC1176_GIC_START + 13)
+#define IRQ_DC1176_RTC         (IRQ_DC1176_GIC_START + 14)
+#define IRQ_DC1176_CLCD                (IRQ_DC1176_GIC_START + 15)     /* CLCD controller */
+#define IRQ_DC1176_UART0       (IRQ_DC1176_GIC_START + 18)     /* UART 0 on development chip */
+#define IRQ_DC1176_UART1       (IRQ_DC1176_GIC_START + 19)     /* UART 1 on development chip */
+#define IRQ_DC1176_UART2       (IRQ_DC1176_GIC_START + 20)     /* UART 2 on development chip */
+#define IRQ_DC1176_UART3       (IRQ_DC1176_GIC_START + 21)     /* UART 3 on development chip */
+
+#define IRQ_DC1176_PB_IRQ2     (IRQ_DC1176_GIC_START + 30)     /* tile GIC */
+#define IRQ_DC1176_PB_IRQ1     (IRQ_DC1176_GIC_START + 31)     /* main GIC */
+
+/*
+ * RealView PB1176 interrupt sources (secondary GIC)
+ */
+#define IRQ_PB1176_MMCI0A      (IRQ_PB1176_GIC_START + 1)      /* Multimedia Card 0A */
+#define IRQ_PB1176_MMCI0B      (IRQ_PB1176_GIC_START + 2)      /* Multimedia Card 0A */
+#define IRQ_PB1176_KMI0                (IRQ_PB1176_GIC_START + 3)      /* Keyboard/Mouse port 0 */
+#define IRQ_PB1176_KMI1                (IRQ_PB1176_GIC_START + 4)      /* Keyboard/Mouse port 1 */
+#define IRQ_PB1176_SCI         (IRQ_PB1176_GIC_START + 5)
+#define IRQ_PB1176_UART4       (IRQ_PB1176_GIC_START + 6)      /* UART 4 on baseboard */
+#define IRQ_PB1176_CHARLCD     (IRQ_PB1176_GIC_START + 7)      /* Character LCD */
+#define IRQ_PB1176_GPIO1       (IRQ_PB1176_GIC_START + 8)
+#define IRQ_PB1176_GPIO2       (IRQ_PB1176_GIC_START + 9)
+#define IRQ_PB1176_ETH         (IRQ_PB1176_GIC_START + 10)     /* Ethernet controller */
+#define IRQ_PB1176_USB         (IRQ_PB1176_GIC_START + 11)     /* USB controller */
+
+#define IRQ_PB1176_PISMO       (IRQ_PB1176_GIC_START + 16)
+
+#define IRQ_PB1176_AACI                (IRQ_PB1176_GIC_START + 19)     /* Audio Codec */
+
+#define IRQ_PB1176_TIMER0_1    (IRQ_PB1176_GIC_START + 22)
+#define IRQ_PB1176_TIMER2_3    (IRQ_PB1176_GIC_START + 23)
+#define IRQ_PB1176_DMAC                (IRQ_PB1176_GIC_START + 24)     /* DMA controller */
+#define IRQ_PB1176_RTC         (IRQ_PB1176_GIC_START + 25)     /* Real Time Clock */
+
+#define IRQ_PB1176_GPIO0       -1
+#define IRQ_PB1176_SSP         -1
+#define IRQ_PB1176_SCTL                -1
+
+#define NR_GIC_PB1176          2
+
+/*
+ * Only define NR_IRQS if less than NR_IRQS_PB1176
+ */
+#define NR_IRQS_PB1176         (IRQ_DC1176_GIC_START + 96)
+
+#if defined(CONFIG_MACH_REALVIEW_PB1176)
+
+#if !defined(NR_IRQS) || (NR_IRQS < NR_IRQS_PB1176)
+#undef NR_IRQS
+#define NR_IRQS                        NR_IRQS_PB1176
+#endif
+
+#if !defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_PB1176)
+#undef MAX_GIC_NR
+#define MAX_GIC_NR             NR_GIC_PB1176
+#endif
+
+#endif /* CONFIG_MACH_REALVIEW_PB1176 */
+
+#endif /* __MACH_IRQS_PB1176_H */
diff --git a/arch/arm/mach-realview/include/mach/irqs-pb11mp.h b/arch/arm/mach-realview/include/mach/irqs-pb11mp.h
new file mode 100644 (file)
index 0000000..34e255a
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * arch/arm/mach-realview/include/mach/irqs-pb11mp.h
+ *
+ * Copyright (C) 2008 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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 __MACH_IRQS_PB11MP_H
+#define __MACH_IRQS_PB11MP_H
+
+#define IRQ_TC11MP_GIC_START                   32
+#define IRQ_PB11MP_GIC_START                   64
+
+/*
+ * ARM11MPCore test chip interrupt sources (primary GIC on the test chip)
+ */
+#define IRQ_TC11MP_AACI                (IRQ_TC11MP_GIC_START + 0)
+#define IRQ_TC11MP_TIMER0_1    (IRQ_TC11MP_GIC_START + 1)
+#define IRQ_TC11MP_TIMER2_3    (IRQ_TC11MP_GIC_START + 2)
+#define IRQ_TC11MP_USB         (IRQ_TC11MP_GIC_START + 3)
+#define IRQ_TC11MP_UART0       (IRQ_TC11MP_GIC_START + 4)
+#define IRQ_TC11MP_UART1       (IRQ_TC11MP_GIC_START + 5)
+#define IRQ_TC11MP_RTC         (IRQ_TC11MP_GIC_START + 6)
+#define IRQ_TC11MP_KMI0                (IRQ_TC11MP_GIC_START + 7)
+#define IRQ_TC11MP_KMI1                (IRQ_TC11MP_GIC_START + 8)
+#define IRQ_TC11MP_ETH         (IRQ_TC11MP_GIC_START + 9)
+#define IRQ_TC11MP_PB_IRQ1     (IRQ_TC11MP_GIC_START + 10)             /* main GIC */
+#define IRQ_TC11MP_PB_IRQ2     (IRQ_TC11MP_GIC_START + 11)             /* tile GIC */
+#define IRQ_TC11MP_PB_FIQ1     (IRQ_TC11MP_GIC_START + 12)             /* main GIC */
+#define IRQ_TC11MP_PB_FIQ2     (IRQ_TC11MP_GIC_START + 13)             /* tile GIC */
+#define IRQ_TC11MP_MMCI0A      (IRQ_TC11MP_GIC_START + 14)
+#define IRQ_TC11MP_MMCI0B      (IRQ_TC11MP_GIC_START + 15)
+
+#define IRQ_TC11MP_PMU_CPU0    (IRQ_TC11MP_GIC_START + 17)
+#define IRQ_TC11MP_PMU_CPU1    (IRQ_TC11MP_GIC_START + 18)
+#define IRQ_TC11MP_PMU_CPU2    (IRQ_TC11MP_GIC_START + 19)
+#define IRQ_TC11MP_PMU_CPU3    (IRQ_TC11MP_GIC_START + 20)
+#define IRQ_TC11MP_PMU_SCU0    (IRQ_TC11MP_GIC_START + 21)
+#define IRQ_TC11MP_PMU_SCU1    (IRQ_TC11MP_GIC_START + 22)
+#define IRQ_TC11MP_PMU_SCU2    (IRQ_TC11MP_GIC_START + 23)
+#define IRQ_TC11MP_PMU_SCU3    (IRQ_TC11MP_GIC_START + 24)
+#define IRQ_TC11MP_PMU_SCU4    (IRQ_TC11MP_GIC_START + 25)
+#define IRQ_TC11MP_PMU_SCU5    (IRQ_TC11MP_GIC_START + 26)
+#define IRQ_TC11MP_PMU_SCU6    (IRQ_TC11MP_GIC_START + 27)
+#define IRQ_TC11MP_PMU_SCU7    (IRQ_TC11MP_GIC_START + 28)
+
+#define IRQ_TC11MP_L220_EVENT  (IRQ_TC11MP_GIC_START + 29)
+#define IRQ_TC11MP_L220_SLAVE  (IRQ_TC11MP_GIC_START + 30)
+#define IRQ_TC11MP_L220_DECODE (IRQ_TC11MP_GIC_START + 31)
+
+/*
+ * RealView PB11MPCore GIC interrupt sources (secondary GIC on the board)
+ */
+#define IRQ_PB11MP_WATCHDOG    (IRQ_PB11MP_GIC_START + 0)      /* Watchdog timer */
+#define IRQ_PB11MP_SOFT                (IRQ_PB11MP_GIC_START + 1)      /* Software interrupt */
+#define IRQ_PB11MP_COMMRx      (IRQ_PB11MP_GIC_START + 2)      /* Debug Comm Rx interrupt */
+#define IRQ_PB11MP_COMMTx      (IRQ_PB11MP_GIC_START + 3)      /* Debug Comm Tx interrupt */
+#define IRQ_PB11MP_GPIO0       (IRQ_PB11MP_GIC_START + 6)      /* GPIO 0 */
+#define IRQ_PB11MP_GPIO1       (IRQ_PB11MP_GIC_START + 7)      /* GPIO 1 */
+#define IRQ_PB11MP_GPIO2       (IRQ_PB11MP_GIC_START + 8)      /* GPIO 2 */
+                                                               /* 9 reserved */
+#define IRQ_PB11MP_RTC_GIC1    (IRQ_PB11MP_GIC_START + 10)     /* Real Time Clock */
+#define IRQ_PB11MP_SSP         (IRQ_PB11MP_GIC_START + 11)     /* Synchronous Serial Port */
+#define IRQ_PB11MP_UART0_GIC1  (IRQ_PB11MP_GIC_START + 12)     /* UART 0 on development chip */
+#define IRQ_PB11MP_UART1_GIC1  (IRQ_PB11MP_GIC_START + 13)     /* UART 1 on development chip */
+#define IRQ_PB11MP_UART2       (IRQ_PB11MP_GIC_START + 14)     /* UART 2 on development chip */
+#define IRQ_PB11MP_UART3       (IRQ_PB11MP_GIC_START + 15)     /* UART 3 on development chip */
+#define IRQ_PB11MP_SCI         (IRQ_PB11MP_GIC_START + 16)     /* Smart Card Interface */
+#define IRQ_PB11MP_MMCI0A_GIC1 (IRQ_PB11MP_GIC_START + 17)     /* Multimedia Card 0A */
+#define IRQ_PB11MP_MMCI0B_GIC1 (IRQ_PB11MP_GIC_START + 18)     /* Multimedia Card 0B */
+#define IRQ_PB11MP_AACI_GIC1   (IRQ_PB11MP_GIC_START + 19)     /* Audio Codec */
+#define IRQ_PB11MP_KMI0_GIC1   (IRQ_PB11MP_GIC_START + 20)     /* Keyboard/Mouse port 0 */
+#define IRQ_PB11MP_KMI1_GIC1   (IRQ_PB11MP_GIC_START + 21)     /* Keyboard/Mouse port 1 */
+#define IRQ_PB11MP_CHARLCD     (IRQ_PB11MP_GIC_START + 22)     /* Character LCD */
+#define IRQ_PB11MP_CLCD                (IRQ_PB11MP_GIC_START + 23)     /* CLCD controller */
+#define IRQ_PB11MP_DMAC                (IRQ_PB11MP_GIC_START + 24)     /* DMA controller */
+#define IRQ_PB11MP_PWRFAIL     (IRQ_PB11MP_GIC_START + 25)     /* Power failure */
+#define IRQ_PB11MP_PISMO       (IRQ_PB11MP_GIC_START + 26)     /* PISMO interface */
+#define IRQ_PB11MP_DoC         (IRQ_PB11MP_GIC_START + 27)     /* Disk on Chip memory controller */
+#define IRQ_PB11MP_ETH_GIC1    (IRQ_PB11MP_GIC_START + 28)     /* Ethernet controller */
+#define IRQ_PB11MP_USB_GIC1    (IRQ_PB11MP_GIC_START + 29)     /* USB controller */
+#define IRQ_PB11MP_TSPEN       (IRQ_PB11MP_GIC_START + 30)     /* Touchscreen pen */
+#define IRQ_PB11MP_TSKPAD      (IRQ_PB11MP_GIC_START + 31)     /* Touchscreen keypad */
+
+#define IRQ_PB11MP_SMC         -1
+#define IRQ_PB11MP_SCTL                -1
+
+#define NR_GIC_PB11MP          2
+
+/*
+ * Only define NR_IRQS if less than NR_IRQS_PB11MP
+ */
+#define NR_IRQS_PB11MP         (IRQ_TC11MP_GIC_START + 96)
+
+#if defined(CONFIG_MACH_REALVIEW_PB11MP)
+
+#if !defined(NR_IRQS) || (NR_IRQS < NR_IRQS_PB11MP)
+#undef NR_IRQS
+#define NR_IRQS                        NR_IRQS_PB11MP
+#endif
+
+#if !defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_PB11MP)
+#undef MAX_GIC_NR
+#define MAX_GIC_NR             NR_GIC_PB11MP
+#endif
+
+#endif /* CONFIG_MACH_REALVIEW_PB11MP */
+
+#endif /* __MACH_IRQS_PB11MP_H */
diff --git a/arch/arm/mach-realview/include/mach/irqs-pba8.h b/arch/arm/mach-realview/include/mach/irqs-pba8.h
new file mode 100644 (file)
index 0000000..86792a9
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * arch/arm/mach-realview/include/mach/irqs-pba8.h
+ *
+ * Copyright (C) 2008 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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 __MACH_IRQS_PBA8_H
+#define __MACH_IRQS_PBA8_H
+
+#define IRQ_PBA8_GIC_START                     32
+
+/* L220
+#define IRQ_PBA8_L220_EVENT    (IRQ_PBA8_GIC_START + 29)
+#define IRQ_PBA8_L220_SLAVE    (IRQ_PBA8_GIC_START + 30)
+#define IRQ_PBA8_L220_DECODE   (IRQ_PBA8_GIC_START + 31)
+*/
+
+/*
+ * PB-A8 on-board gic irq sources
+ */
+#define IRQ_PBA8_WATCHDOG      (IRQ_PBA8_GIC_START + 0)        /* Watchdog timer */
+#define IRQ_PBA8_SOFT          (IRQ_PBA8_GIC_START + 1)        /* Software interrupt */
+#define IRQ_PBA8_COMMRx                (IRQ_PBA8_GIC_START + 2)        /* Debug Comm Rx interrupt */
+#define IRQ_PBA8_COMMTx                (IRQ_PBA8_GIC_START + 3)        /* Debug Comm Tx interrupt */
+#define IRQ_PBA8_TIMER0_1      (IRQ_PBA8_GIC_START + 4)        /* Timer 0/1 (default timer) */
+#define IRQ_PBA8_TIMER2_3      (IRQ_PBA8_GIC_START + 5)        /* Timer 2/3 */
+#define IRQ_PBA8_GPIO0         (IRQ_PBA8_GIC_START + 6)        /* GPIO 0 */
+#define IRQ_PBA8_GPIO1         (IRQ_PBA8_GIC_START + 7)        /* GPIO 1 */
+#define IRQ_PBA8_GPIO2         (IRQ_PBA8_GIC_START + 8)        /* GPIO 2 */
+                                                               /* 9 reserved */
+#define IRQ_PBA8_RTC           (IRQ_PBA8_GIC_START + 10)       /* Real Time Clock */
+#define IRQ_PBA8_SSP           (IRQ_PBA8_GIC_START + 11)       /* Synchronous Serial Port */
+#define IRQ_PBA8_UART0         (IRQ_PBA8_GIC_START + 12)       /* UART 0 on development chip */
+#define IRQ_PBA8_UART1         (IRQ_PBA8_GIC_START + 13)       /* UART 1 on development chip */
+#define IRQ_PBA8_UART2         (IRQ_PBA8_GIC_START + 14)       /* UART 2 on development chip */
+#define IRQ_PBA8_UART3         (IRQ_PBA8_GIC_START + 15)       /* UART 3 on development chip */
+#define IRQ_PBA8_SCI           (IRQ_PBA8_GIC_START + 16)       /* Smart Card Interface */
+#define IRQ_PBA8_MMCI0A                (IRQ_PBA8_GIC_START + 17)       /* Multimedia Card 0A */
+#define IRQ_PBA8_MMCI0B                (IRQ_PBA8_GIC_START + 18)       /* Multimedia Card 0B */
+#define IRQ_PBA8_AACI          (IRQ_PBA8_GIC_START + 19)       /* Audio Codec */
+#define IRQ_PBA8_KMI0          (IRQ_PBA8_GIC_START + 20)       /* Keyboard/Mouse port 0 */
+#define IRQ_PBA8_KMI1          (IRQ_PBA8_GIC_START + 21)       /* Keyboard/Mouse port 1 */
+#define IRQ_PBA8_CHARLCD       (IRQ_PBA8_GIC_START + 22)       /* Character LCD */
+#define IRQ_PBA8_CLCD          (IRQ_PBA8_GIC_START + 23)       /* CLCD controller */
+#define IRQ_PBA8_DMAC          (IRQ_PBA8_GIC_START + 24)       /* DMA controller */
+#define IRQ_PBA8_PWRFAIL       (IRQ_PBA8_GIC_START + 25)       /* Power failure */
+#define IRQ_PBA8_PISMO         (IRQ_PBA8_GIC_START + 26)       /* PISMO interface */
+#define IRQ_PBA8_DoC           (IRQ_PBA8_GIC_START + 27)       /* Disk on Chip memory controller */
+#define IRQ_PBA8_ETH           (IRQ_PBA8_GIC_START + 28)       /* Ethernet controller */
+#define IRQ_PBA8_USB           (IRQ_PBA8_GIC_START + 29)       /* USB controller */
+#define IRQ_PBA8_TSPEN         (IRQ_PBA8_GIC_START + 30)       /* Touchscreen pen */
+#define IRQ_PBA8_TSKPAD                (IRQ_PBA8_GIC_START + 31)       /* Touchscreen keypad */
+
+/* ... */
+#define IRQ_PBA8_PCI0          (IRQ_PBA8_GIC_START + 50)
+#define IRQ_PBA8_PCI1          (IRQ_PBA8_GIC_START + 51)
+#define IRQ_PBA8_PCI2          (IRQ_PBA8_GIC_START + 52)
+#define IRQ_PBA8_PCI3          (IRQ_PBA8_GIC_START + 53)
+
+#define IRQ_PBA8_SMC           -1
+#define IRQ_PBA8_SCTL          -1
+
+#define NR_GIC_PBA8            1
+
+/*
+ * Only define NR_IRQS if less than NR_IRQS_PBA8
+ */
+#define NR_IRQS_PBA8           (IRQ_PBA8_GIC_START + 64)
+
+#if defined(CONFIG_MACH_REALVIEW_PBA8)
+
+#if !defined(NR_IRQS) || (NR_IRQS < NR_IRQS_PBA8)
+#undef NR_IRQS
+#define NR_IRQS                        NR_IRQS_PBA8
+#endif
+
+#if !defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_PBA8)
+#undef MAX_GIC_NR
+#define MAX_GIC_NR             NR_GIC_PBA8
+#endif
+
+#endif /* CONFIG_MACH_REALVIEW_PBA8 */
+
+#endif /* __MACH_IRQS_PBA8_H */
diff --git a/arch/arm/mach-realview/include/mach/irqs-pbx.h b/arch/arm/mach-realview/include/mach/irqs-pbx.h
new file mode 100644 (file)
index 0000000..deaad43
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * arch/arm/mach-realview/include/mach/irqs-pbx.h
+ *
+ * Copyright (C) 2009 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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 __MACH_IRQS_PBX_H
+#define __MACH_IRQS_PBX_H
+
+#define IRQ_PBX_GIC_START                      32
+
+/* L220
+#define IRQ_PBX_L220_EVENT     (IRQ_PBX_GIC_START + 29)
+#define IRQ_PBX_L220_SLAVE     (IRQ_PBX_GIC_START + 30)
+#define IRQ_PBX_L220_DECODE    (IRQ_PBX_GIC_START + 31)
+*/
+
+/*
+ * PBX on-board gic irq sources
+ */
+#define IRQ_PBX_WATCHDOG       (IRQ_PBX_GIC_START + 0) /* Watchdog timer */
+#define IRQ_PBX_SOFT           (IRQ_PBX_GIC_START + 1) /* Software interrupt */
+#define IRQ_PBX_COMMRx         (IRQ_PBX_GIC_START + 2) /* Debug Comm Rx interrupt */
+#define IRQ_PBX_COMMTx         (IRQ_PBX_GIC_START + 3) /* Debug Comm Tx interrupt */
+#define IRQ_PBX_TIMER0_1       (IRQ_PBX_GIC_START + 4) /* Timer 0/1 (default timer) */
+#define IRQ_PBX_TIMER2_3       (IRQ_PBX_GIC_START + 5) /* Timer 2/3 */
+#define IRQ_PBX_GPIO0          (IRQ_PBX_GIC_START + 6) /* GPIO 0 */
+#define IRQ_PBX_GPIO1          (IRQ_PBX_GIC_START + 7) /* GPIO 1 */
+#define IRQ_PBX_GPIO2          (IRQ_PBX_GIC_START + 8) /* GPIO 2 */
+                                                               /* 9 reserved */
+#define IRQ_PBX_RTC            (IRQ_PBX_GIC_START + 10)        /* Real Time Clock */
+#define IRQ_PBX_SSP            (IRQ_PBX_GIC_START + 11)        /* Synchronous Serial Port */
+#define IRQ_PBX_UART0          (IRQ_PBX_GIC_START + 12)        /* UART 0 on development chip */
+#define IRQ_PBX_UART1          (IRQ_PBX_GIC_START + 13)        /* UART 1 on development chip */
+#define IRQ_PBX_UART2          (IRQ_PBX_GIC_START + 14)        /* UART 2 on development chip */
+#define IRQ_PBX_UART3          (IRQ_PBX_GIC_START + 15)        /* UART 3 on development chip */
+#define IRQ_PBX_SCI            (IRQ_PBX_GIC_START + 16)        /* Smart Card Interface */
+#define IRQ_PBX_MMCI0A         (IRQ_PBX_GIC_START + 17)        /* Multimedia Card 0A */
+#define IRQ_PBX_MMCI0B         (IRQ_PBX_GIC_START + 18)        /* Multimedia Card 0B */
+#define IRQ_PBX_AACI           (IRQ_PBX_GIC_START + 19)        /* Audio Codec */
+#define IRQ_PBX_KMI0           (IRQ_PBX_GIC_START + 20)        /* Keyboard/Mouse port 0 */
+#define IRQ_PBX_KMI1           (IRQ_PBX_GIC_START + 21)        /* Keyboard/Mouse port 1 */
+#define IRQ_PBX_CHARLCD                (IRQ_PBX_GIC_START + 22)        /* Character LCD */
+#define IRQ_PBX_CLCD           (IRQ_PBX_GIC_START + 23)        /* CLCD controller */
+#define IRQ_PBX_DMAC           (IRQ_PBX_GIC_START + 24)        /* DMA controller */
+#define IRQ_PBX_PWRFAIL                (IRQ_PBX_GIC_START + 25)        /* Power failure */
+#define IRQ_PBX_PISMO          (IRQ_PBX_GIC_START + 26)        /* PISMO interface */
+#define IRQ_PBX_DoC            (IRQ_PBX_GIC_START + 27)        /* Disk on Chip memory controller */
+#define IRQ_PBX_ETH            (IRQ_PBX_GIC_START + 28)        /* Ethernet controller */
+#define IRQ_PBX_USB            (IRQ_PBX_GIC_START + 29)        /* USB controller */
+#define IRQ_PBX_TSPEN          (IRQ_PBX_GIC_START + 30)        /* Touchscreen pen */
+#define IRQ_PBX_TSKPAD         (IRQ_PBX_GIC_START + 31)        /* Touchscreen keypad */
+
+#define IRQ_PBX_PMU_SCU0        (IRQ_PBX_GIC_START + 32)        /* SCU PMU Interrupts (11mp) */
+#define IRQ_PBX_PMU_SCU1        (IRQ_PBX_GIC_START + 33)
+#define IRQ_PBX_PMU_SCU2        (IRQ_PBX_GIC_START + 34)
+#define IRQ_PBX_PMU_SCU3        (IRQ_PBX_GIC_START + 35)
+#define IRQ_PBX_PMU_SCU4        (IRQ_PBX_GIC_START + 36)
+#define IRQ_PBX_PMU_SCU5        (IRQ_PBX_GIC_START + 37)
+#define IRQ_PBX_PMU_SCU6        (IRQ_PBX_GIC_START + 38)
+#define IRQ_PBX_PMU_SCU7        (IRQ_PBX_GIC_START + 39)
+
+#define IRQ_PBX_WATCHDOG1       (IRQ_PBX_GIC_START + 40)        /* Watchdog1 timer */
+#define IRQ_PBX_TIMER4_5        (IRQ_PBX_GIC_START + 41)        /* Timer 0/1 (default timer) */
+#define IRQ_PBX_TIMER6_7        (IRQ_PBX_GIC_START + 42)        /* Timer 2/3 */
+/* ... */
+#define IRQ_PBX_PMU_CPU3        (IRQ_PBX_GIC_START + 44)        /* CPU PMU Interrupts */
+#define IRQ_PBX_PMU_CPU2        (IRQ_PBX_GIC_START + 45)
+#define IRQ_PBX_PMU_CPU1        (IRQ_PBX_GIC_START + 46)
+#define IRQ_PBX_PMU_CPU0        (IRQ_PBX_GIC_START + 47)
+
+/* ... */
+#define IRQ_PBX_PCI0           (IRQ_PBX_GIC_START + 50)
+#define IRQ_PBX_PCI1           (IRQ_PBX_GIC_START + 51)
+#define IRQ_PBX_PCI2           (IRQ_PBX_GIC_START + 52)
+#define IRQ_PBX_PCI3           (IRQ_PBX_GIC_START + 53)
+
+#define IRQ_PBX_SMC            -1
+#define IRQ_PBX_SCTL           -1
+
+#define NR_GIC_PBX             1
+
+/*
+ * Only define NR_IRQS if less than NR_IRQS_PBX
+ */
+#define NR_IRQS_PBX            (IRQ_PBX_GIC_START + 96)
+
+#if defined(CONFIG_MACH_REALVIEW_PBX)
+
+#if !defined(NR_IRQS) || (NR_IRQS < NR_IRQS_PBX)
+#undef NR_IRQS
+#define NR_IRQS                        NR_IRQS_PBX
+#endif
+
+#if !defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_PBX)
+#undef MAX_GIC_NR
+#define MAX_GIC_NR             NR_GIC_PBX
+#endif
+
+#endif /* CONFIG_MACH_REALVIEW_PBX */
+
+#endif /* __MACH_IRQS_PBX_H */
index fe5cb987aa215d7d4f7a1e1fc0be2bf5a501e439..78854f2fa323905f11eee810f107a0b2c0cfefde 100644 (file)
 #ifndef __ASM_ARCH_IRQS_H
 #define __ASM_ARCH_IRQS_H
 
-#include <mach/board-eb.h>
-#include <mach/board-pb11mp.h>
-#include <mach/board-pb1176.h>
-#include <mach/board-pba8.h>
+#include <mach/irqs-eb.h>
+#include <mach/irqs-pb11mp.h>
+#include <mach/irqs-pb1176.h>
+#include <mach/irqs-pba8.h>
+#include <mach/irqs-pbx.h>
 
 #define IRQ_LOCALTIMER         29
 #define IRQ_LOCALWDOG          30
diff --git a/arch/arm/mach-realview/include/mach/scu.h b/arch/arm/mach-realview/include/mach/scu.h
deleted file mode 100644 (file)
index d55802d..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef __ASMARM_ARCH_SCU_H
-#define __ASMARM_ARCH_SCU_H
-
-/*
- * SCU registers
- */
-#define SCU_CTRL               0x00
-#define SCU_CONFIG             0x04
-#define SCU_CPU_STATUS         0x08
-#define SCU_INVALIDATE         0x0c
-#define SCU_FPGA_REVISION      0x10
-
-#endif
index 415d634d52ab2b8153a24de774e5159357c01a02..83050378ffd2b2cb0d51d0eacbe3d27e13b3a0c9 100644 (file)
@@ -24,6 +24,7 @@
 #include <mach/board-pb11mp.h>
 #include <mach/board-pb1176.h>
 #include <mach/board-pba8.h>
+#include <mach/board-pbx.h>
 
 #define AMBA_UART_DR(base)     (*(volatile unsigned char *)((base) + 0x00))
 #define AMBA_UART_LCRH(base)   (*(volatile unsigned char *)((base) + 0x2c))
@@ -43,6 +44,8 @@ static inline unsigned long get_uart_base(void)
                return REALVIEW_PB1176_UART0_BASE;
        else if (machine_is_realview_pba8())
                return REALVIEW_PBA8_UART0_BASE;
+       else if (machine_is_realview_pbx())
+               return REALVIEW_PBX_UART0_BASE;
        else
                return 0;
 }
index 1c01d13460f01f13495e3b0cdf9757fe58ac513f..60b4e111f4596afbd6b1882ad0387f6fad7de45c 100644 (file)
  * published by the Free Software Foundation.
  */
 #include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/device.h>
 #include <linux/smp.h>
-#include <linux/jiffies.h>
-#include <linux/percpu.h>
 #include <linux/clockchips.h>
-#include <linux/irq.h>
-#include <linux/io.h>
 
-#include <asm/hardware/arm_twd.h>
-#include <asm/hardware/gic.h>
-#include <mach/hardware.h>
 #include <asm/irq.h>
-
-static DEFINE_PER_CPU(struct clock_event_device, local_clockevent);
-
-/*
- * Used on SMP for either the local timer or IPI_TIMER
- */
-void local_timer_interrupt(void)
-{
-       struct clock_event_device *clk = &__get_cpu_var(local_clockevent);
-
-       clk->event_handler(clk);
-}
-
-#ifdef CONFIG_LOCAL_TIMERS
-
-/* set up by the platform code */
-void __iomem *twd_base;
-
-static unsigned long mpcore_timer_rate;
-
-static void local_timer_set_mode(enum clock_event_mode mode,
-                                struct clock_event_device *clk)
-{
-       unsigned long ctrl;
-
-       switch(mode) {
-       case CLOCK_EVT_MODE_PERIODIC:
-               /* timer load already set up */
-               ctrl = TWD_TIMER_CONTROL_ENABLE | TWD_TIMER_CONTROL_IT_ENABLE
-                       | TWD_TIMER_CONTROL_PERIODIC;
-               break;
-       case CLOCK_EVT_MODE_ONESHOT:
-               /* period set, and timer enabled in 'next_event' hook */
-               ctrl = TWD_TIMER_CONTROL_IT_ENABLE | TWD_TIMER_CONTROL_ONESHOT;
-               break;
-       case CLOCK_EVT_MODE_UNUSED:
-       case CLOCK_EVT_MODE_SHUTDOWN:
-       default:
-               ctrl = 0;
-       }
-
-       __raw_writel(ctrl, twd_base + TWD_TIMER_CONTROL);
-}
-
-static int local_timer_set_next_event(unsigned long evt,
-                                     struct clock_event_device *unused)
-{
-       unsigned long ctrl = __raw_readl(twd_base + TWD_TIMER_CONTROL);
-
-       __raw_writel(evt, twd_base + TWD_TIMER_COUNTER);
-       __raw_writel(ctrl | TWD_TIMER_CONTROL_ENABLE, twd_base + TWD_TIMER_CONTROL);
-
-       return 0;
-}
-
-/*
- * local_timer_ack: checks for a local timer interrupt.
- *
- * If a local timer interrupt has occurred, acknowledge and return 1.
- * Otherwise, return 0.
- */
-int local_timer_ack(void)
-{
-       if (__raw_readl(twd_base + TWD_TIMER_INTSTAT)) {
-               __raw_writel(1, twd_base + TWD_TIMER_INTSTAT);
-               return 1;
-       }
-
-       return 0;
-}
-
-static void __cpuinit twd_calibrate_rate(void)
-{
-       unsigned long load, count;
-       u64 waitjiffies;
-
-       /*
-        * If this is the first time round, we need to work out how fast
-        * the timer ticks
-        */
-       if (mpcore_timer_rate == 0) {
-               printk("Calibrating local timer... ");
-
-               /* Wait for a tick to start */
-               waitjiffies = get_jiffies_64() + 1;
-
-               while (get_jiffies_64() < waitjiffies)
-                       udelay(10);
-
-               /* OK, now the tick has started, let's get the timer going */
-               waitjiffies += 5;
-
-                                /* enable, no interrupt or reload */
-               __raw_writel(0x1, twd_base + TWD_TIMER_CONTROL);
-
-                                /* maximum value */
-               __raw_writel(0xFFFFFFFFU, twd_base + TWD_TIMER_COUNTER);
-
-               while (get_jiffies_64() < waitjiffies)
-                       udelay(10);
-
-               count = __raw_readl(twd_base + TWD_TIMER_COUNTER);
-
-               mpcore_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5);
-
-               printk("%lu.%02luMHz.\n", mpcore_timer_rate / 1000000,
-                       (mpcore_timer_rate / 100000) % 100);
-       }
-
-       load = mpcore_timer_rate / HZ;
-
-       __raw_writel(load, twd_base + TWD_TIMER_LOAD);
-}
+#include <asm/smp_twd.h>
+#include <asm/localtimer.h>
 
 /*
  * Setup the local clock events for a CPU.
  */
-void __cpuinit local_timer_setup(void)
-{
-       unsigned int cpu = smp_processor_id();
-       struct clock_event_device *clk = &per_cpu(local_clockevent, cpu);
-       unsigned long flags;
-
-       twd_calibrate_rate();
-
-       clk->name               = "local_timer";
-       clk->features           = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
-       clk->rating             = 350;
-       clk->set_mode           = local_timer_set_mode;
-       clk->set_next_event     = local_timer_set_next_event;
-       clk->irq                = IRQ_LOCALTIMER;
-       clk->cpumask            = cpumask_of(cpu);
-       clk->shift              = 20;
-       clk->mult               = div_sc(mpcore_timer_rate, NSEC_PER_SEC, clk->shift);
-       clk->max_delta_ns       = clockevent_delta2ns(0xffffffff, clk);
-       clk->min_delta_ns       = clockevent_delta2ns(0xf, clk);
-
-       /* Make sure our local interrupt controller has this enabled */
-       local_irq_save(flags);
-       get_irq_chip(IRQ_LOCALTIMER)->unmask(IRQ_LOCALTIMER);
-       local_irq_restore(flags);
-
-       clockevents_register_device(clk);
-}
-
-/*
- * take a local timer down
- */
-void __cpuexit local_timer_stop(void)
+void __cpuinit local_timer_setup(struct clock_event_device *evt)
 {
-       __raw_writel(0, twd_base + TWD_TIMER_CONTROL);
+       evt->irq = IRQ_LOCALTIMER;
+       twd_timer_setup(evt);
 }
-
-#else  /* CONFIG_LOCAL_TIMERS */
-
-static void dummy_timer_set_mode(enum clock_event_mode mode,
-                                struct clock_event_device *clk)
-{
-}
-
-void __cpuinit local_timer_setup(void)
-{
-       unsigned int cpu = smp_processor_id();
-       struct clock_event_device *clk = &per_cpu(local_clockevent, cpu);
-
-       clk->name               = "dummy_timer";
-       clk->features           = CLOCK_EVT_FEAT_ONESHOT |
-                                 CLOCK_EVT_FEAT_PERIODIC |
-                                 CLOCK_EVT_FEAT_DUMMY;
-       clk->rating             = 400;
-       clk->mult               = 1;
-       clk->set_mode           = dummy_timer_set_mode;
-       clk->broadcast          = smp_timer_broadcast;
-       clk->cpumask            = cpumask_of(cpu);
-
-       clockevents_register_device(clk);
-}
-
-#endif /* !CONFIG_LOCAL_TIMERS */
index 30a9c68591f661ddd2f11492a02630d0a5f6b357..ac0e83f1cc3a784a80daa5fe58c8d9e283a941b0 100644 (file)
 #include <asm/cacheflush.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
+#include <asm/localtimer.h>
 
 #include <mach/board-eb.h>
 #include <mach/board-pb11mp.h>
-#include <mach/scu.h>
+#include <mach/board-pbx.h>
+#include <asm/smp_scu.h>
 
 #include "core.h"
 
@@ -40,35 +42,19 @@ static void __iomem *scu_base_addr(void)
                return __io_address(REALVIEW_EB11MP_SCU_BASE);
        else if (machine_is_realview_pb11mp())
                return __io_address(REALVIEW_TC11MP_SCU_BASE);
+       else if (machine_is_realview_pbx() &&
+                (core_tile_pbx11mp() || core_tile_pbxa9mp()))
+               return __io_address(REALVIEW_PBX_TILE_SCU_BASE);
        else
                return (void __iomem *)0;
 }
 
-static unsigned int __init get_core_count(void)
+static inline unsigned int get_core_count(void)
 {
-       unsigned int ncores;
        void __iomem *scu_base = scu_base_addr();
-
-       if (scu_base) {
-               ncores = __raw_readl(scu_base + SCU_CONFIG);
-               ncores = (ncores & 0x03) + 1;
-       } else
-               ncores = 1;
-
-       return ncores;
-}
-
-/*
- * Setup the SCU
- */
-static void scu_enable(void)
-{
-       u32 scu_ctrl;
-       void __iomem *scu_base = scu_base_addr();
-
-       scu_ctrl = __raw_readl(scu_base + SCU_CTRL);
-       scu_ctrl |= 1;
-       __raw_writel(scu_ctrl, scu_base + SCU_CTRL);
+       if (scu_base)
+               return scu_get_core_count(scu_base);
+       return 1;
 }
 
 static DEFINE_SPINLOCK(boot_lock);
@@ -184,7 +170,7 @@ void __init smp_init_cpus(void)
        unsigned int i, ncores = get_core_count();
 
        for (i = 0; i < ncores; i++)
-               cpu_set(i, cpu_possible_map);
+               set_cpu_possible(i, true);
 }
 
 void __init smp_prepare_cpus(unsigned int max_cpus)
@@ -217,19 +203,12 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
        if (max_cpus > ncores)
                max_cpus = ncores;
 
-#if defined(CONFIG_LOCAL_TIMERS) || defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
-       /*
-        * Enable the local timer or broadcast device for the boot CPU.
-        */
-       local_timer_setup();
-#endif
-
        /*
         * Initialise the present map, which describes the set of CPUs
         * actually populated at the present time.
         */
        for (i = 0; i < max_cpus; i++)
-               cpu_set(i, cpu_present_map);
+               set_cpu_present(i, true);
 
        /*
         * Initialise the SCU if there are more than one CPU and let
@@ -239,7 +218,13 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
         * WFI
         */
        if (max_cpus > 1) {
-               scu_enable();
+               /*
+                * 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(scu_base_addr());
                poke_milo();
        }
 }
index c20fbef122b38af693f2f56e9f82aadba87de8b7..8dfa44e08a94e87181ca26c1724b9eaed15b615d 100644 (file)
@@ -32,6 +32,7 @@
 #include <asm/hardware/gic.h>
 #include <asm/hardware/icst307.h>
 #include <asm/hardware/cache-l2x0.h>
+#include <asm/localtimer.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
index a64b84a7a3df96b65a237a9566dbbf78bbf46610..25efe71a67c7a19d19229953a933776f719efc4f 100644 (file)
@@ -203,11 +203,23 @@ static struct amba_device *amba_devs[] __initdata = {
 /*
  * RealView PB1176 platform devices
  */
-static struct resource realview_pb1176_flash_resource = {
-       .start                  = REALVIEW_PB1176_FLASH_BASE,
-       .end                    = REALVIEW_PB1176_FLASH_BASE + REALVIEW_PB1176_FLASH_SIZE - 1,
-       .flags                  = IORESOURCE_MEM,
+static struct resource realview_pb1176_flash_resources[] = {
+       [0] = {
+               .start          = REALVIEW_PB1176_FLASH_BASE,
+               .end            = REALVIEW_PB1176_FLASH_BASE + REALVIEW_PB1176_FLASH_SIZE - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start          = REALVIEW_PB1176_SEC_FLASH_BASE,
+               .end            = REALVIEW_PB1176_SEC_FLASH_BASE + REALVIEW_PB1176_SEC_FLASH_SIZE - 1,
+               .flags          = IORESOURCE_MEM,
+       },
 };
+#ifdef CONFIG_REALVIEW_PB1176_SECURE_FLASH
+#define PB1176_FLASH_BLOCKS    2
+#else
+#define PB1176_FLASH_BLOCKS    1
+#endif
 
 static struct resource realview_pb1176_smsc911x_resources[] = {
        [0] = {
@@ -271,7 +283,8 @@ static void __init realview_pb1176_init(void)
        l2x0_init(__io_address(REALVIEW_PB1176_L220_BASE), 0x00730000, 0xfe000fff);
 #endif
 
-       realview_flash_register(&realview_pb1176_flash_resource, 1);
+       realview_flash_register(realview_pb1176_flash_resources,
+                               PB1176_FLASH_BLOCKS);
        realview_eth_register(NULL, realview_pb1176_smsc911x_resources);
        platform_device_register(&realview_i2c_device);
        realview_usb_register(realview_pb1176_isp1761_resources);
index ea1e60eca359efa14baf707502487b5df8e371c6..dc4b16943907d7f3778cf4d50b05a362ddc10281 100644 (file)
@@ -32,6 +32,7 @@
 #include <asm/hardware/gic.h>
 #include <asm/hardware/icst307.h>
 #include <asm/hardware/cache-l2x0.h>
+#include <asm/localtimer.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c
new file mode 100644 (file)
index 0000000..1fe294d
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ *  arch/arm/mach-realview/realview_pbx.c
+ *
+ *  Copyright (C) 2009 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/sysdev.h>
+#include <linux/amba/bus.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+#include <asm/leds.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/gic.h>
+#include <asm/hardware/cache-l2x0.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/mmc.h>
+#include <asm/mach/time.h>
+
+#include <mach/hardware.h>
+#include <mach/board-pbx.h>
+#include <mach/irqs.h>
+
+#include "core.h"
+
+static struct map_desc realview_pbx_io_desc[] __initdata = {
+       {
+               .virtual        = IO_ADDRESS(REALVIEW_SYS_BASE),
+               .pfn            = __phys_to_pfn(REALVIEW_SYS_BASE),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = IO_ADDRESS(REALVIEW_PBX_GIC_CPU_BASE),
+               .pfn            = __phys_to_pfn(REALVIEW_PBX_GIC_CPU_BASE),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = IO_ADDRESS(REALVIEW_PBX_GIC_DIST_BASE),
+               .pfn            = __phys_to_pfn(REALVIEW_PBX_GIC_DIST_BASE),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = IO_ADDRESS(REALVIEW_SCTL_BASE),
+               .pfn            = __phys_to_pfn(REALVIEW_SCTL_BASE),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = IO_ADDRESS(REALVIEW_PBX_TIMER0_1_BASE),
+               .pfn            = __phys_to_pfn(REALVIEW_PBX_TIMER0_1_BASE),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = IO_ADDRESS(REALVIEW_PBX_TIMER2_3_BASE),
+               .pfn            = __phys_to_pfn(REALVIEW_PBX_TIMER2_3_BASE),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       },
+#ifdef CONFIG_PCI
+       {
+               .virtual        = PCIX_UNIT_BASE,
+               .pfn            = __phys_to_pfn(REALVIEW_PBX_PCI_BASE),
+               .length         = REALVIEW_PBX_PCI_BASE_SIZE,
+               .type           = MT_DEVICE,
+       },
+#endif
+#ifdef CONFIG_DEBUG_LL
+       {
+               .virtual        = IO_ADDRESS(REALVIEW_PBX_UART0_BASE),
+               .pfn            = __phys_to_pfn(REALVIEW_PBX_UART0_BASE),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       },
+#endif
+};
+
+static struct map_desc realview_local_io_desc[] __initdata = {
+       {
+               .virtual        = IO_ADDRESS(REALVIEW_PBX_TILE_GIC_CPU_BASE),
+               .pfn            = __phys_to_pfn(REALVIEW_PBX_TILE_GIC_CPU_BASE),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = IO_ADDRESS(REALVIEW_PBX_TILE_GIC_DIST_BASE),
+               .pfn            = __phys_to_pfn(REALVIEW_PBX_TILE_GIC_DIST_BASE),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = IO_ADDRESS(REALVIEW_PBX_TILE_L220_BASE),
+               .pfn            = __phys_to_pfn(REALVIEW_PBX_TILE_L220_BASE),
+               .length         = SZ_8K,
+               .type           = MT_DEVICE,
+       }
+};
+
+static void __init realview_pbx_map_io(void)
+{
+       iotable_init(realview_pbx_io_desc, ARRAY_SIZE(realview_pbx_io_desc));
+       if (core_tile_pbx11mp() || core_tile_pbxa9mp())
+               iotable_init(realview_local_io_desc, ARRAY_SIZE(realview_local_io_desc));
+}
+
+/*
+ * RealView PBXCore AMBA devices
+ */
+
+#define GPIO2_IRQ              { IRQ_PBX_GPIO2, NO_IRQ }
+#define GPIO2_DMA              { 0, 0 }
+#define GPIO3_IRQ              { IRQ_PBX_GPIO3, NO_IRQ }
+#define GPIO3_DMA              { 0, 0 }
+#define AACI_IRQ               { IRQ_PBX_AACI, NO_IRQ }
+#define AACI_DMA               { 0x80, 0x81 }
+#define MMCI0_IRQ              { IRQ_PBX_MMCI0A, IRQ_PBX_MMCI0B }
+#define MMCI0_DMA              { 0x84, 0 }
+#define KMI0_IRQ               { IRQ_PBX_KMI0, NO_IRQ }
+#define KMI0_DMA               { 0, 0 }
+#define KMI1_IRQ               { IRQ_PBX_KMI1, NO_IRQ }
+#define KMI1_DMA               { 0, 0 }
+#define PBX_SMC_IRQ            { NO_IRQ, NO_IRQ }
+#define PBX_SMC_DMA            { 0, 0 }
+#define MPMC_IRQ               { NO_IRQ, NO_IRQ }
+#define MPMC_DMA               { 0, 0 }
+#define PBX_CLCD_IRQ           { IRQ_PBX_CLCD, NO_IRQ }
+#define PBX_CLCD_DMA           { 0, 0 }
+#define DMAC_IRQ               { IRQ_PBX_DMAC, NO_IRQ }
+#define DMAC_DMA               { 0, 0 }
+#define SCTL_IRQ               { NO_IRQ, NO_IRQ }
+#define SCTL_DMA               { 0, 0 }
+#define PBX_WATCHDOG_IRQ       { IRQ_PBX_WATCHDOG, NO_IRQ }
+#define PBX_WATCHDOG_DMA       { 0, 0 }
+#define PBX_GPIO0_IRQ          { IRQ_PBX_GPIO0, NO_IRQ }
+#define PBX_GPIO0_DMA          { 0, 0 }
+#define GPIO1_IRQ              { IRQ_PBX_GPIO1, NO_IRQ }
+#define GPIO1_DMA              { 0, 0 }
+#define PBX_RTC_IRQ            { IRQ_PBX_RTC, NO_IRQ }
+#define PBX_RTC_DMA            { 0, 0 }
+#define SCI_IRQ                        { IRQ_PBX_SCI, NO_IRQ }
+#define SCI_DMA                        { 7, 6 }
+#define PBX_UART0_IRQ          { IRQ_PBX_UART0, NO_IRQ }
+#define PBX_UART0_DMA          { 15, 14 }
+#define PBX_UART1_IRQ          { IRQ_PBX_UART1, NO_IRQ }
+#define PBX_UART1_DMA          { 13, 12 }
+#define PBX_UART2_IRQ          { IRQ_PBX_UART2, NO_IRQ }
+#define PBX_UART2_DMA          { 11, 10 }
+#define PBX_UART3_IRQ          { IRQ_PBX_UART3, NO_IRQ }
+#define PBX_UART3_DMA          { 0x86, 0x87 }
+#define PBX_SSP_IRQ            { IRQ_PBX_SSP, NO_IRQ }
+#define PBX_SSP_DMA            { 9, 8 }
+
+/* FPGA Primecells */
+AMBA_DEVICE(aaci,      "fpga:04",      AACI,           NULL);
+AMBA_DEVICE(mmc0,      "fpga:05",      MMCI0,          &realview_mmc0_plat_data);
+AMBA_DEVICE(kmi0,      "fpga:06",      KMI0,           NULL);
+AMBA_DEVICE(kmi1,      "fpga:07",      KMI1,           NULL);
+AMBA_DEVICE(uart3,     "fpga:09",      PBX_UART3,      NULL);
+
+/* DevChip Primecells */
+AMBA_DEVICE(smc,       "dev:00",       PBX_SMC,        NULL);
+AMBA_DEVICE(sctl,      "dev:e0",       SCTL,           NULL);
+AMBA_DEVICE(wdog,      "dev:e1",       PBX_WATCHDOG,   NULL);
+AMBA_DEVICE(gpio0,     "dev:e4",       PBX_GPIO0,      NULL);
+AMBA_DEVICE(gpio1,     "dev:e5",       GPIO1,          NULL);
+AMBA_DEVICE(gpio2,     "dev:e6",       GPIO2,          NULL);
+AMBA_DEVICE(rtc,       "dev:e8",       PBX_RTC,        NULL);
+AMBA_DEVICE(sci0,      "dev:f0",       SCI,            NULL);
+AMBA_DEVICE(uart0,     "dev:f1",       PBX_UART0,      NULL);
+AMBA_DEVICE(uart1,     "dev:f2",       PBX_UART1,      NULL);
+AMBA_DEVICE(uart2,     "dev:f3",       PBX_UART2,      NULL);
+AMBA_DEVICE(ssp0,      "dev:f4",       PBX_SSP,        NULL);
+
+/* Primecells on the NEC ISSP chip */
+AMBA_DEVICE(clcd,      "issp:20",      PBX_CLCD,       &clcd_plat_data);
+AMBA_DEVICE(dmac,      "issp:30",      DMAC,           NULL);
+
+static struct amba_device *amba_devs[] __initdata = {
+       &dmac_device,
+       &uart0_device,
+       &uart1_device,
+       &uart2_device,
+       &uart3_device,
+       &smc_device,
+       &clcd_device,
+       &sctl_device,
+       &wdog_device,
+       &gpio0_device,
+       &gpio1_device,
+       &gpio2_device,
+       &rtc_device,
+       &sci0_device,
+       &ssp0_device,
+       &aaci_device,
+       &mmc0_device,
+       &kmi0_device,
+       &kmi1_device,
+};
+
+/*
+ * RealView PB-X platform devices
+ */
+static struct resource realview_pbx_flash_resources[] = {
+       [0] = {
+               .start          = REALVIEW_PBX_FLASH0_BASE,
+               .end            = REALVIEW_PBX_FLASH0_BASE + REALVIEW_PBX_FLASH0_SIZE - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start          = REALVIEW_PBX_FLASH1_BASE,
+               .end            = REALVIEW_PBX_FLASH1_BASE + REALVIEW_PBX_FLASH1_SIZE - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+};
+
+static struct resource realview_pbx_smsc911x_resources[] = {
+       [0] = {
+               .start          = REALVIEW_PBX_ETH_BASE,
+               .end            = REALVIEW_PBX_ETH_BASE + SZ_64K - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start          = IRQ_PBX_ETH,
+               .end            = IRQ_PBX_ETH,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource realview_pbx_isp1761_resources[] = {
+       [0] = {
+               .start          = REALVIEW_PBX_USB_BASE,
+               .end            = REALVIEW_PBX_USB_BASE + SZ_128K - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start          = IRQ_PBX_USB,
+               .end            = IRQ_PBX_USB,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static void __init gic_init_irq(void)
+{
+       /* ARM PBX on-board GIC */
+       if (core_tile_pbx11mp() || core_tile_pbxa9mp()) {
+               gic_cpu_base_addr = __io_address(REALVIEW_PBX_TILE_GIC_CPU_BASE);
+               gic_dist_init(0, __io_address(REALVIEW_PBX_TILE_GIC_DIST_BASE),
+                             29);
+               gic_cpu_init(0, __io_address(REALVIEW_PBX_TILE_GIC_CPU_BASE));
+       } else {
+               gic_cpu_base_addr = __io_address(REALVIEW_PBX_GIC_CPU_BASE);
+               gic_dist_init(0, __io_address(REALVIEW_PBX_GIC_DIST_BASE),
+                             IRQ_PBX_GIC_START);
+               gic_cpu_init(0, __io_address(REALVIEW_PBX_GIC_CPU_BASE));
+       }
+}
+
+static void __init realview_pbx_timer_init(void)
+{
+       timer0_va_base = __io_address(REALVIEW_PBX_TIMER0_1_BASE);
+       timer1_va_base = __io_address(REALVIEW_PBX_TIMER0_1_BASE) + 0x20;
+       timer2_va_base = __io_address(REALVIEW_PBX_TIMER2_3_BASE);
+       timer3_va_base = __io_address(REALVIEW_PBX_TIMER2_3_BASE) + 0x20;
+
+#ifdef CONFIG_LOCAL_TIMERS
+       if (core_tile_pbx11mp() || core_tile_pbxa9mp())
+               twd_base = __io_address(REALVIEW_PBX_TILE_TWD_BASE);
+#endif
+       realview_timer_init(IRQ_PBX_TIMER0_1);
+}
+
+static struct sys_timer realview_pbx_timer = {
+       .init           = realview_pbx_timer_init,
+};
+
+static void __init realview_pbx_init(void)
+{
+       int i;
+
+#ifdef CONFIG_CACHE_L2X0
+       if (core_tile_pbxa9mp()) {
+               void __iomem *l2x0_base =
+                       __io_address(REALVIEW_PBX_TILE_L220_BASE);
+
+               /* set RAM latencies to 1 cycle for eASIC */
+               writel(0, l2x0_base + L2X0_TAG_LATENCY_CTRL);
+               writel(0, l2x0_base + L2X0_DATA_LATENCY_CTRL);
+
+               /* 16KB way size, 8-way associativity, parity disabled
+                * Bits:  .. 0 0 0 0 1 00 1 0 1 001 0 000 0 .... .... .... */
+               l2x0_init(l2x0_base, 0x02520000, 0xc0000fff);
+       }
+#endif
+
+       realview_flash_register(realview_pbx_flash_resources,
+                               ARRAY_SIZE(realview_pbx_flash_resources));
+       realview_eth_register(NULL, realview_pbx_smsc911x_resources);
+       platform_device_register(&realview_i2c_device);
+       platform_device_register(&realview_cf_device);
+       realview_usb_register(realview_pbx_isp1761_resources);
+
+       for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
+               struct amba_device *d = amba_devs[i];
+               amba_device_register(d, &iomem_resource);
+       }
+
+#ifdef CONFIG_LEDS
+       leds_event = realview_leds_event;
+#endif
+}
+
+MACHINE_START(REALVIEW_PBX, "ARM-RealView PBX")
+       /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
+       .phys_io        = REALVIEW_PBX_UART0_BASE,
+       .io_pg_offst    = (IO_ADDRESS(REALVIEW_PBX_UART0_BASE) >> 18) & 0xfffc,
+       .boot_params    = PHYS_OFFSET + 0x00000100,
+       .map_io         = realview_pbx_map_io,
+       .init_irq       = gic_init_irq,
+       .timer          = &realview_pbx_timer,
+       .init_machine   = realview_pbx_init,
+MACHINE_END
index 7a7ed4174c8c8c3f65608c206b37974a4c87dbe4..6c68e78f359579055b60ef63140eb63d322d4114 100644 (file)
 
 int s3c2400_gpio_getirq(unsigned int pin)
 {
-       if (pin < S3C2410_GPE0 || pin > S3C2400_GPE7_EINT7)
-               return -1;  /* not valid interrupts */
+       if (pin < S3C2410_GPE(0) || pin > S3C2400_GPE(7))
+               return -EINVAL;  /* not valid interrupts */
 
-       return (pin - S3C2410_GPE0) + IRQ_EINT0;
+       return (pin - S3C2410_GPE(0)) + IRQ_EINT0;
 }
 
 EXPORT_SYMBOL(s3c2400_gpio_getirq);
index 63a30d1dd4250e6c838d3e5c63242a3fa1959116..41bb65d5b91f18c5dd964e87524a1aef40a7a5d7 100644 (file)
@@ -59,6 +59,7 @@ config ARCH_H1940
        bool "IPAQ H1940"
        select CPU_S3C2410
        select PM_H1940 if PM
+       select S3C_DEV_USB_HOST
        help
          Say Y here if you are using the HP IPAQ H1940
 
@@ -70,6 +71,7 @@ config PM_H1940
 config MACH_N30
        bool "Acer N30 family"
        select CPU_S3C2410
+       select S3C_DEV_USB_HOST
        help
          Say Y here if you want suppt for the Acer N30, Acer N35,
          Navman PiN570, Yakumo AlphaX or Airis NC05 PDAs.
@@ -82,6 +84,7 @@ config ARCH_BAST
        select MACH_BAST_IDE
        select S3C24XX_DCLK
        select ISA
+       select S3C_DEV_USB_HOST
        help
          Say Y here if you are using the Simtec Electronics EB2410ITX
          development board (also known as BAST)
@@ -89,6 +92,7 @@ config ARCH_BAST
 config MACH_OTOM
        bool "NexVision OTOM Board"
        select CPU_S3C2410
+       select S3C_DEV_USB_HOST
        help
          Say Y here if you are using the Nex Vision OTOM board
 
@@ -96,6 +100,7 @@ config MACH_AML_M5900
        bool "AML M5900 Series"
        select CPU_S3C2410
        select PM_SIMTEC if PM
+       select S3C_DEV_USB_HOST
        help
           Say Y here if you are using the American Microsystems M5900 Series
            <http://www.amltd.com>
@@ -111,6 +116,7 @@ config BAST_PC104_IRQ
 config MACH_TCT_HAMMER
        bool "TCT Hammer Board"
        select CPU_S3C2410
+       select S3C_DEV_USB_HOST
        help
           Say Y here if you are using the TinCanTools Hammer Board
            <http://www.tincantools.com>
@@ -122,12 +128,14 @@ config MACH_VR1000
        select SIMTEC_NOR
        select MACH_BAST_IDE
        select CPU_S3C2410
+       select S3C_DEV_USB_HOST
        help
          Say Y here if you are using the Thorcom VR1000 board.
 
 config MACH_QT2410
        bool "QT2410"
        select CPU_S3C2410
+       select S3C_DEV_USB_HOST
        help
           Say Y here if you are using the Armzone QT2410
 
index 440c014e24b31bf9b00b536bcd8e7900d836850a..dbf96e60d99263dacc501094705aa1fe12caaa90 100644 (file)
 #include <linux/sysdev.h>
 #include <linux/serial_core.h>
 
+#include <mach/map.h>
 #include <mach/dma.h>
 
 #include <plat/cpu.h>
-#include <plat/dma.h>
+#include <plat/dma-plat.h>
 
 #include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
 #include <plat/regs-ac97.h>
+#include <plat/regs-dma.h>
 #include <mach/regs-mem.h>
 #include <mach/regs-lcd.h>
 #include <mach/regs-sdi.h>
index 36a3132f39e72367d7a372c0c11d642bc57b4e3f..7974afca297ce2282a276ed51063b5d28e3e738e 100644 (file)
@@ -39,12 +39,12 @@ int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
        unsigned long flags;
        unsigned long val;
 
-       if (pin < S3C2410_GPG8 || pin > S3C2410_GPG15)
-               return -1;
+       if (pin < S3C2410_GPG(8) || pin > S3C2410_GPG(15))
+               return -EINVAL;
 
        config &= 0xff;
 
-       pin -= S3C2410_GPG8;
+       pin -= S3C2410_GPG(8);
        reg += pin & ~3;
 
        local_irq_save(flags);
index 5a6bc56f186b2c1a9aa3259c7a81f2960aa8bc66..5aabf117cbb01742fac3e340374c471e2fb60755 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/string.h>
 #include <linux/ctype.h>
 #include <linux/leds.h>
+#include <linux/gpio.h>
+
 #include <mach/regs-gpio.h>
 #include <mach/hardware.h>
 #include <mach/h1940-latch.h>
@@ -41,9 +43,9 @@ static void h1940bt_enable(int on)
                h1940_latch_control(0, H1940_LATCH_BLUETOOTH_POWER);
                /* Reset the chip */
                mdelay(10);
-               s3c2410_gpio_setpin(S3C2410_GPH1, 1);
+               s3c2410_gpio_setpin(S3C2410_GPH(1), 1);
                mdelay(10);
-               s3c2410_gpio_setpin(S3C2410_GPH1, 0);
+               s3c2410_gpio_setpin(S3C2410_GPH(1), 0);
 
                state = 1;
        }
@@ -52,9 +54,9 @@ static void h1940bt_enable(int on)
                led_trigger_event(bt_led_trigger, 0);
 #endif
 
-               s3c2410_gpio_setpin(S3C2410_GPH1, 1);
+               s3c2410_gpio_setpin(S3C2410_GPH(1), 1);
                mdelay(10);
-               s3c2410_gpio_setpin(S3C2410_GPH1, 0);
+               s3c2410_gpio_setpin(S3C2410_GPH(1), 0);
                mdelay(10);
                h1940_latch_control(H1940_LATCH_BLUETOOTH_POWER, 0);
 
@@ -87,14 +89,14 @@ static DEVICE_ATTR(enable, 0644,
 static int __init h1940bt_probe(struct platform_device *pdev)
 {
        /* Configures BT serial port GPIOs */
-       s3c2410_gpio_cfgpin(S3C2410_GPH0, S3C2410_GPH0_nCTS0);
-       s3c2410_gpio_pullup(S3C2410_GPH0, 1);
-       s3c2410_gpio_cfgpin(S3C2410_GPH1, S3C2410_GPH1_OUTP);
-       s3c2410_gpio_pullup(S3C2410_GPH1, 1);
-       s3c2410_gpio_cfgpin(S3C2410_GPH2, S3C2410_GPH2_TXD0);
-       s3c2410_gpio_pullup(S3C2410_GPH2, 1);
-       s3c2410_gpio_cfgpin(S3C2410_GPH3, S3C2410_GPH3_RXD0);
-       s3c2410_gpio_pullup(S3C2410_GPH3, 1);
+       s3c2410_gpio_cfgpin(S3C2410_GPH(0), S3C2410_GPH0_nCTS0);
+       s3c2410_gpio_pullup(S3C2410_GPH(0), 1);
+       s3c2410_gpio_cfgpin(S3C2410_GPH(1), S3C2410_GPIO_OUTPUT);
+       s3c2410_gpio_pullup(S3C2410_GPH(1), 1);
+       s3c2410_gpio_cfgpin(S3C2410_GPH(2), S3C2410_GPH2_TXD0);
+       s3c2410_gpio_pullup(S3C2410_GPH(2), 1);
+       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);
index 13358ce2128c7c16346d4d65932c13dbf3630cdf..c3a2629e0ded67443455dcb3508fb3842845e473 100644 (file)
@@ -3,7 +3,7 @@
  * Copyright (C) 2003,2004,2006 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *
- * Samsung S3C241XX DMA support
+ * Samsung S3C24XX DMA 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
@@ -13,8 +13,8 @@
 #ifndef __ASM_ARCH_DMA_H
 #define __ASM_ARCH_DMA_H __FILE__
 
+#include <plat/dma.h>
 #include <linux/sysdev.h>
-#include <mach/hardware.h>
 
 #define MAX_DMA_TRANSFER_SIZE   0x100000 /* Data Unit is half word  */
 
@@ -55,9 +55,9 @@ enum dma_ch {
 
 /* we have 4 dma channels */
 #ifndef CONFIG_CPU_S3C2443
-#define S3C2410_DMA_CHANNELS           (4)
+#define S3C_DMA_CHANNELS               (4)
 #else
-#define S3C2410_DMA_CHANNELS           (6)
+#define S3C_DMA_CHANNELS               (6)
 #endif
 
 /* types */
@@ -68,7 +68,6 @@ enum s3c2410_dma_state {
        S3C2410_DMA_PAUSED
 };
 
-
 /* enum s3c2410_dma_loadst
  *
  * This represents the state of the DMA engine, wrt to the loaded / running
@@ -104,32 +103,6 @@ enum s3c2410_dma_loadst {
        S3C2410_DMALOAD_1LOADED_1RUNNING,
 };
 
-enum s3c2410_dma_buffresult {
-       S3C2410_RES_OK,
-       S3C2410_RES_ERR,
-       S3C2410_RES_ABORT
-};
-
-enum s3c2410_dmasrc {
-       S3C2410_DMASRC_HW,              /* source is memory */
-       S3C2410_DMASRC_MEM              /* source is hardware */
-};
-
-/* enum s3c2410_chan_op
- *
- * operation codes passed to the DMA code by the user, and also used
- * to inform the current channel owner of any changes to the system state
-*/
-
-enum s3c2410_chan_op {
-       S3C2410_DMAOP_START,
-       S3C2410_DMAOP_STOP,
-       S3C2410_DMAOP_PAUSE,
-       S3C2410_DMAOP_RESUME,
-       S3C2410_DMAOP_FLUSH,
-       S3C2410_DMAOP_TIMEOUT,          /* internal signal to handler */
-       S3C2410_DMAOP_STARTED,          /* indicate channel started */
-};
 
 /* flags */
 
@@ -139,17 +112,14 @@ enum s3c2410_chan_op {
 
 /* dma buffer */
 
-struct s3c2410_dma_client {
-       char                *name;
-};
+struct s3c2410_dma_buf;
 
-/* s3c2410_dma_buf_s
+/* s3c2410_dma_buf
  *
  * internally used buffer structure to describe a queued or running
  * buffer.
 */
 
-struct s3c2410_dma_buf;
 struct s3c2410_dma_buf {
        struct s3c2410_dma_buf  *next;
        int                      magic;         /* magic */
@@ -161,20 +131,6 @@ struct s3c2410_dma_buf {
 
 /* [1] is this updated for both recv/send modes? */
 
-struct s3c2410_dma_chan;
-
-/* s3c2410_dma_cbfn_t
- *
- * buffer callback routine type
-*/
-
-typedef void (*s3c2410_dma_cbfn_t)(struct s3c2410_dma_chan *,
-                                  void *buf, int size,
-                                  enum s3c2410_dma_buffresult result);
-
-typedef int  (*s3c2410_dma_opfn_t)(struct s3c2410_dma_chan *,
-                                  enum s3c2410_chan_op );
-
 struct s3c2410_dma_stats {
        unsigned long           loads;
        unsigned long           timeout_longest;
@@ -206,10 +162,10 @@ struct s3c2410_dma_chan {
 
        /* channel configuration */
        enum s3c2410_dmasrc      source;
+       enum dma_ch              req_ch;
        unsigned long            dev_addr;
        unsigned long            load_timeout;
        unsigned int             flags;         /* channel flags */
-       unsigned int             hw_cfg;        /* last hw config */
 
        struct s3c24xx_dma_map  *map;           /* channel hw maps */
 
@@ -236,213 +192,6 @@ struct s3c2410_dma_chan {
        struct sys_device       dev;
 };
 
-/* the currently allocated channel information */
-extern struct s3c2410_dma_chan s3c2410_chans[];
-
-/* note, we don't really use dma_device_t at the moment */
 typedef unsigned long dma_device_t;
 
-/* functions --------------------------------------------------------------- */
-
-/* s3c2410_dma_request
- *
- * request a dma channel exclusivley
-*/
-
-extern int s3c2410_dma_request(unsigned int channel,
-                              struct s3c2410_dma_client *, void *dev);
-
-
-/* s3c2410_dma_ctrl
- *
- * change the state of the dma channel
-*/
-
-extern int s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op);
-
-/* s3c2410_dma_setflags
- *
- * set the channel's flags to a given state
-*/
-
-extern int s3c2410_dma_setflags(unsigned int channel,
-                               unsigned int flags);
-
-/* s3c2410_dma_free
- *
- * free the dma channel (will also abort any outstanding operations)
-*/
-
-extern int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *);
-
-/* s3c2410_dma_enqueue
- *
- * place the given buffer onto the queue of operations for the channel.
- * The buffer must be allocated from dma coherent memory, or the Dcache/WB
- * drained before the buffer is given to the DMA system.
-*/
-
-extern int s3c2410_dma_enqueue(unsigned int channel, void *id,
-                              dma_addr_t data, int size);
-
-/* s3c2410_dma_config
- *
- * configure the dma channel
-*/
-
-extern int s3c2410_dma_config(unsigned int channel, int xferunit, int dcon);
-
-/* s3c2410_dma_devconfig
- *
- * configure the device we're talking to
-*/
-
-extern int s3c2410_dma_devconfig(int channel, enum s3c2410_dmasrc source,
-                                int hwcfg, unsigned long devaddr);
-
-/* s3c2410_dma_getposition
- *
- * get the position that the dma transfer is currently at
-*/
-
-extern int s3c2410_dma_getposition(unsigned int channel,
-                                  dma_addr_t *src, dma_addr_t *dest);
-
-extern int s3c2410_dma_set_opfn(unsigned int, s3c2410_dma_opfn_t rtn);
-extern int s3c2410_dma_set_buffdone_fn(unsigned int, s3c2410_dma_cbfn_t rtn);
-
-/* DMA Register definitions */
-
-#define S3C2410_DMA_DISRC       (0x00)
-#define S3C2410_DMA_DISRCC      (0x04)
-#define S3C2410_DMA_DIDST       (0x08)
-#define S3C2410_DMA_DIDSTC      (0x0C)
-#define S3C2410_DMA_DCON        (0x10)
-#define S3C2410_DMA_DSTAT       (0x14)
-#define S3C2410_DMA_DCSRC       (0x18)
-#define S3C2410_DMA_DCDST       (0x1C)
-#define S3C2410_DMA_DMASKTRIG   (0x20)
-#define S3C2412_DMA_DMAREQSEL  (0x24)
-#define S3C2443_DMA_DMAREQSEL  (0x24)
-
-#define S3C2410_DISRCC_INC     (1<<0)
-#define S3C2410_DISRCC_APB     (1<<1)
-
-#define S3C2410_DMASKTRIG_STOP   (1<<2)
-#define S3C2410_DMASKTRIG_ON     (1<<1)
-#define S3C2410_DMASKTRIG_SWTRIG (1<<0)
-
-#define S3C2410_DCON_DEMAND     (0<<31)
-#define S3C2410_DCON_HANDSHAKE  (1<<31)
-#define S3C2410_DCON_SYNC_PCLK  (0<<30)
-#define S3C2410_DCON_SYNC_HCLK  (1<<30)
-
-#define S3C2410_DCON_INTREQ     (1<<29)
-
-#define S3C2410_DCON_CH0_XDREQ0        (0<<24)
-#define S3C2410_DCON_CH0_UART0 (1<<24)
-#define S3C2410_DCON_CH0_SDI   (2<<24)
-#define S3C2410_DCON_CH0_TIMER (3<<24)
-#define S3C2410_DCON_CH0_USBEP1        (4<<24)
-
-#define S3C2410_DCON_CH1_XDREQ1        (0<<24)
-#define S3C2410_DCON_CH1_UART1 (1<<24)
-#define S3C2410_DCON_CH1_I2SSDI        (2<<24)
-#define S3C2410_DCON_CH1_SPI   (3<<24)
-#define S3C2410_DCON_CH1_USBEP2        (4<<24)
-
-#define S3C2410_DCON_CH2_I2SSDO        (0<<24)
-#define S3C2410_DCON_CH2_I2SSDI        (1<<24)
-#define S3C2410_DCON_CH2_SDI   (2<<24)
-#define S3C2410_DCON_CH2_TIMER (3<<24)
-#define S3C2410_DCON_CH2_USBEP3        (4<<24)
-
-#define S3C2410_DCON_CH3_UART2 (0<<24)
-#define S3C2410_DCON_CH3_SDI   (1<<24)
-#define S3C2410_DCON_CH3_SPI   (2<<24)
-#define S3C2410_DCON_CH3_TIMER (3<<24)
-#define S3C2410_DCON_CH3_USBEP4        (4<<24)
-
-#define S3C2410_DCON_SRCSHIFT   (24)
-#define S3C2410_DCON_SRCMASK   (7<<24)
-
-#define S3C2410_DCON_BYTE       (0<<20)
-#define S3C2410_DCON_HALFWORD   (1<<20)
-#define S3C2410_DCON_WORD       (2<<20)
-
-#define S3C2410_DCON_AUTORELOAD (0<<22)
-#define S3C2410_DCON_NORELOAD   (1<<22)
-#define S3C2410_DCON_HWTRIG     (1<<23)
-
-#ifdef CONFIG_CPU_S3C2440
-#define S3C2440_DIDSTC_CHKINT  (1<<2)
-
-#define S3C2440_DCON_CH0_I2SSDO        (5<<24)
-#define S3C2440_DCON_CH0_PCMIN (6<<24)
-
-#define S3C2440_DCON_CH1_PCMOUT        (5<<24)
-#define S3C2440_DCON_CH1_SDI   (6<<24)
-
-#define S3C2440_DCON_CH2_PCMIN (5<<24)
-#define S3C2440_DCON_CH2_MICIN (6<<24)
-
-#define S3C2440_DCON_CH3_MICIN (5<<24)
-#define S3C2440_DCON_CH3_PCMOUT        (6<<24)
-#endif
-
-#ifdef CONFIG_CPU_S3C2412
-
-#define S3C2412_DMAREQSEL_SRC(x)       ((x)<<1)
-
-#define S3C2412_DMAREQSEL_HW           (1)
-
-#define S3C2412_DMAREQSEL_SPI0TX       S3C2412_DMAREQSEL_SRC(0)
-#define S3C2412_DMAREQSEL_SPI0RX       S3C2412_DMAREQSEL_SRC(1)
-#define S3C2412_DMAREQSEL_SPI1TX       S3C2412_DMAREQSEL_SRC(2)
-#define S3C2412_DMAREQSEL_SPI1RX       S3C2412_DMAREQSEL_SRC(3)
-#define S3C2412_DMAREQSEL_I2STX                S3C2412_DMAREQSEL_SRC(4)
-#define S3C2412_DMAREQSEL_I2SRX                S3C2412_DMAREQSEL_SRC(5)
-#define S3C2412_DMAREQSEL_TIMER                S3C2412_DMAREQSEL_SRC(9)
-#define S3C2412_DMAREQSEL_SDI          S3C2412_DMAREQSEL_SRC(10)
-#define S3C2412_DMAREQSEL_USBEP1       S3C2412_DMAREQSEL_SRC(13)
-#define S3C2412_DMAREQSEL_USBEP2       S3C2412_DMAREQSEL_SRC(14)
-#define S3C2412_DMAREQSEL_USBEP3       S3C2412_DMAREQSEL_SRC(15)
-#define S3C2412_DMAREQSEL_USBEP4       S3C2412_DMAREQSEL_SRC(16)
-#define S3C2412_DMAREQSEL_XDREQ0       S3C2412_DMAREQSEL_SRC(17)
-#define S3C2412_DMAREQSEL_XDREQ1       S3C2412_DMAREQSEL_SRC(18)
-#define S3C2412_DMAREQSEL_UART0_0      S3C2412_DMAREQSEL_SRC(19)
-#define S3C2412_DMAREQSEL_UART0_1      S3C2412_DMAREQSEL_SRC(20)
-#define S3C2412_DMAREQSEL_UART1_0      S3C2412_DMAREQSEL_SRC(21)
-#define S3C2412_DMAREQSEL_UART1_1      S3C2412_DMAREQSEL_SRC(22)
-#define S3C2412_DMAREQSEL_UART2_0      S3C2412_DMAREQSEL_SRC(23)
-#define S3C2412_DMAREQSEL_UART2_1      S3C2412_DMAREQSEL_SRC(24)
-
-#endif
-
-#define S3C2443_DMAREQSEL_SRC(x)       ((x)<<1)
-
-#define S3C2443_DMAREQSEL_HW           (1)
-
-#define S3C2443_DMAREQSEL_SPI0TX       S3C2443_DMAREQSEL_SRC(0)
-#define S3C2443_DMAREQSEL_SPI0RX       S3C2443_DMAREQSEL_SRC(1)
-#define S3C2443_DMAREQSEL_SPI1TX       S3C2443_DMAREQSEL_SRC(2)
-#define S3C2443_DMAREQSEL_SPI1RX       S3C2443_DMAREQSEL_SRC(3)
-#define S3C2443_DMAREQSEL_I2STX                S3C2443_DMAREQSEL_SRC(4)
-#define S3C2443_DMAREQSEL_I2SRX                S3C2443_DMAREQSEL_SRC(5)
-#define S3C2443_DMAREQSEL_TIMER                S3C2443_DMAREQSEL_SRC(9)
-#define S3C2443_DMAREQSEL_SDI          S3C2443_DMAREQSEL_SRC(10)
-#define S3C2443_DMAREQSEL_XDREQ0       S3C2443_DMAREQSEL_SRC(17)
-#define S3C2443_DMAREQSEL_XDREQ1       S3C2443_DMAREQSEL_SRC(18)
-#define S3C2443_DMAREQSEL_UART0_0      S3C2443_DMAREQSEL_SRC(19)
-#define S3C2443_DMAREQSEL_UART0_1      S3C2443_DMAREQSEL_SRC(20)
-#define S3C2443_DMAREQSEL_UART1_0      S3C2443_DMAREQSEL_SRC(21)
-#define S3C2443_DMAREQSEL_UART1_1      S3C2443_DMAREQSEL_SRC(22)
-#define S3C2443_DMAREQSEL_UART2_0      S3C2443_DMAREQSEL_SRC(23)
-#define S3C2443_DMAREQSEL_UART2_1      S3C2443_DMAREQSEL_SRC(24)
-#define S3C2443_DMAREQSEL_UART3_0      S3C2443_DMAREQSEL_SRC(25)
-#define S3C2443_DMAREQSEL_UART3_1      S3C2443_DMAREQSEL_SRC(26)
-#define S3C2443_DMAREQSEL_PCMOUT       S3C2443_DMAREQSEL_SRC(27)
-#define S3C2443_DMAREQSEL_PCMIN        S3C2443_DMAREQSEL_SRC(28)
-#define S3C2443_DMAREQSEL_MICIN                S3C2443_DMAREQSEL_SRC(29)
-
 #endif /* __ASM_ARCH_DMA_H */
index 6c9fbb99ef14428d9d4e7231fdacdbdbf9ae7f65..8fe192081d3a7f7720189ab81f397fa2a12b8b0b 100644 (file)
@@ -24,7 +24,7 @@ static inline struct s3c_gpio_chip *s3c_gpiolib_getchip(unsigned int pin)
 {
        struct s3c_gpio_chip *chip;
 
-       if (pin > S3C2410_GPG10)
+       if (pin > S3C2410_GPG(10))
                return NULL;
 
        chip = &s3c24xx_gpios[pin/32];
diff --git a/arch/arm/mach-s3c2410/include/mach/gpio-fns.h b/arch/arm/mach-s3c2410/include/mach/gpio-fns.h
new file mode 100644 (file)
index 0000000..801dff1
--- /dev/null
@@ -0,0 +1,103 @@
+/* arch/arm/mach-s3c2410/include/mach/gpio-fns.h
+ *
+ * Copyright (c) 2003,2009 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 - hardware
+ *
+ * This 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 functions are in the to-be-removed category and it is strongly
+ * encouraged not to use these in new code. They will be marked deprecated
+ * very soon.
+ *
+ * Most of the functionality can be either replaced by the gpiocfg calls
+ * for the s3c platform or by the generic GPIOlib API.
+*/
+
+/* external functions for GPIO support
+ *
+ * These allow various different clients to access the same GPIO
+ * registers without conflicting. If your driver only owns the entire
+ * GPIO register, then it is safe to ioremap/__raw_{read|write} to it.
+*/
+
+/* s3c2410_gpio_cfgpin
+ *
+ * set the configuration of the given pin to the value passed.
+ *
+ * eg:
+ *    s3c2410_gpio_cfgpin(S3C2410_GPA(0), S3C2410_GPA0_ADDR0);
+ *    s3c2410_gpio_cfgpin(S3C2410_GPE(8), S3C2410_GPE8_SDDAT1);
+*/
+
+extern void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function);
+
+extern unsigned int s3c2410_gpio_getcfg(unsigned int pin);
+
+/* s3c2410_gpio_getirq
+ *
+ * turn the given pin number into the corresponding IRQ number
+ *
+ * returns:
+ *     < 0 = no interrupt for this pin
+ *     >=0 = interrupt number for the pin
+*/
+
+extern int s3c2410_gpio_getirq(unsigned int pin);
+
+#ifdef CONFIG_CPU_S3C2400
+
+extern int s3c2400_gpio_getirq(unsigned int pin);
+
+#endif /* CONFIG_CPU_S3C2400 */
+
+/* s3c2410_gpio_irqfilter
+ *
+ * set the irq filtering on the given pin
+ *
+ * on = 0 => disable filtering
+ *      1 => enable filtering
+ *
+ * config = S3C2410_EINTFLT_PCLK or S3C2410_EINTFLT_EXTCLK orred with
+ *          width of filter (0 through 63)
+ *
+ *
+*/
+
+extern int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
+                                 unsigned int config);
+
+/* s3c2410_gpio_pullup
+ *
+ * configure the pull-up control on the given pin
+ *
+ * to = 1 => disable the pull-up
+ *      0 => enable the pull-up
+ *
+ * eg;
+ *
+ *   s3c2410_gpio_pullup(S3C2410_GPB(0), 0);
+ *   s3c2410_gpio_pullup(S3C2410_GPE(8), 0);
+*/
+
+extern void s3c2410_gpio_pullup(unsigned int pin, unsigned int to);
+
+/* s3c2410_gpio_getpull
+ *
+ * Read the state of the pull-up on a given pin
+ *
+ * return:
+ *     < 0 => error code
+ *       0 => enabled
+ *       1 => disabled
+*/
+
+extern int s3c2410_gpio_getpull(unsigned int pin);
+
+extern void s3c2410_gpio_setpin(unsigned int pin, unsigned int to);
+
+extern unsigned int s3c2410_gpio_getpin(unsigned int pin);
index ce1ec69806a1a9a2e878f043bd9c189a476839cd..2edbb9c88ab324d612134e3f228a1752034cbcd8 100644 (file)
@@ -11,6 +11,9 @@
  * published by the Free Software Foundation.
 */
 
+#ifndef __MACH_GPIONRS_H
+#define __MACH_GPIONRS_H
+
 #define S3C2410_GPIONO(bank,offset) ((bank) + (offset))
 
 #define S3C2410_GPIO_BANKA   (32*0)
 #define S3C2410_GPIO_BANKF   (32*5)
 #define S3C2410_GPIO_BANKG   (32*6)
 #define S3C2410_GPIO_BANKH   (32*7)
+
+/* GPIO bank sizes */
+#define S3C2410_GPIO_A_NR      (32)
+#define S3C2410_GPIO_B_NR      (32)
+#define S3C2410_GPIO_C_NR      (32)
+#define S3C2410_GPIO_D_NR      (32)
+#define S3C2410_GPIO_E_NR      (32)
+#define S3C2410_GPIO_F_NR      (32)
+#define S3C2410_GPIO_G_NR      (32)
+#define S3C2410_GPIO_H_NR      (32)
+
+#if CONFIG_S3C_GPIO_SPACE != 0
+#error CONFIG_S3C_GPIO_SPACE cannot be zero at the moment
+#endif
+
+#define S3C2410_GPIO_NEXT(__gpio) \
+       ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 0)
+
+#ifndef __ASSEMBLY__
+
+enum s3c_gpio_number {
+       S3C2410_GPIO_A_START = 0,
+       S3C2410_GPIO_B_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_A),
+       S3C2410_GPIO_C_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_B),
+       S3C2410_GPIO_D_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_C),
+       S3C2410_GPIO_E_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_D),
+       S3C2410_GPIO_F_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_E),
+       S3C2410_GPIO_G_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_F),
+       S3C2410_GPIO_H_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_G),
+};
+
+#endif /* __ASSEMBLY__ */
+
+/* S3C2410 GPIO number definitions. */
+
+#define S3C2410_GPA(_nr)       (S3C2410_GPIO_A_START + (_nr))
+#define S3C2410_GPB(_nr)       (S3C2410_GPIO_B_START + (_nr))
+#define S3C2410_GPC(_nr)       (S3C2410_GPIO_C_START + (_nr))
+#define S3C2410_GPD(_nr)       (S3C2410_GPIO_D_START + (_nr))
+#define S3C2410_GPE(_nr)       (S3C2410_GPIO_E_START + (_nr))
+#define S3C2410_GPF(_nr)       (S3C2410_GPIO_F_START + (_nr))
+#define S3C2410_GPG(_nr)       (S3C2410_GPIO_G_START + (_nr))
+#define S3C2410_GPH(_nr)       (S3C2410_GPIO_H_START + (_nr))
+
+/* compatibility until drivers can be modified */
+
+#define S3C2410_GPA0   S3C2410_GPA(0)
+#define S3C2410_GPA1   S3C2410_GPA(1)
+#define S3C2410_GPA3   S3C2410_GPA(3)
+#define S3C2410_GPA7   S3C2410_GPA(7)
+
+#define S3C2410_GPE0   S3C2410_GPE(0)
+#define S3C2410_GPE1   S3C2410_GPE(1)
+#define S3C2410_GPE2   S3C2410_GPE(2)
+#define S3C2410_GPE3   S3C2410_GPE(3)
+#define S3C2410_GPE4   S3C2410_GPE(4)
+#define S3C2410_GPE5   S3C2410_GPE(5)
+#define S3C2410_GPE6   S3C2410_GPE(6)
+#define S3C2410_GPE7   S3C2410_GPE(7)
+#define S3C2410_GPE8   S3C2410_GPE(8)
+#define S3C2410_GPE9   S3C2410_GPE(9)
+#define S3C2410_GPE10  S3C2410_GPE(10)
+
+#define S3C2410_GPH10  S3C2410_GPH(10)
+
+#endif /* __MACH_GPIONRS_H */
+
index 51a88cf9526b3caaad25d9e96ca2952553cae77f..15f0b3e7ce699a373d75ca50a4ed52cef9d1b95e 100644 (file)
@@ -24,5 +24,6 @@
 
 #include <asm-generic/gpio.h>
 #include <mach/gpio-nrs.h>
+#include <mach/gpio-fns.h>
 
 #define S3C_GPIO_END   (S3C2410_GPIO_BANKH + 32)
index 74d5a1a4024cece53810ef96e25236de0b64a883..aef5631eac58107cb56952399c0612611b5a5e7b 100644 (file)
 
 #ifndef __ASSEMBLY__
 
-/* external functions for GPIO support
- *
- * These allow various different clients to access the same GPIO
- * registers without conflicting. If your driver only owns the entire
- * GPIO register, then it is safe to ioremap/__raw_{read|write} to it.
-*/
-
-/* s3c2410_gpio_cfgpin
- *
- * set the configuration of the given pin to the value passed.
- *
- * eg:
- *    s3c2410_gpio_cfgpin(S3C2410_GPA0, S3C2410_GPA0_ADDR0);
- *    s3c2410_gpio_cfgpin(S3C2410_GPE8, S3C2410_GPE8_SDDAT1);
-*/
-
-extern void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function);
-
-extern unsigned int s3c2410_gpio_getcfg(unsigned int pin);
-
-/* s3c2410_gpio_getirq
- *
- * turn the given pin number into the corresponding IRQ number
- *
- * returns:
- *     < 0 = no interrupt for this pin
- *     >=0 = interrupt number for the pin
-*/
-
-extern int s3c2410_gpio_getirq(unsigned int pin);
-
-/* s3c2410_gpio_irq2pin
- *
- * turn the given irq number into the corresponding GPIO number
- *
- * returns:
- *     < 0 = no pin
- *     >=0 = gpio pin number
-*/
-
-extern int s3c2410_gpio_irq2pin(unsigned int irq);
-
-#ifdef CONFIG_CPU_S3C2400
-
-extern int s3c2400_gpio_getirq(unsigned int pin);
-
-#endif /* CONFIG_CPU_S3C2400 */
-
-/* s3c2410_gpio_irqfilter
- *
- * set the irq filtering on the given pin
- *
- * on = 0 => disable filtering
- *      1 => enable filtering
- *
- * config = S3C2410_EINTFLT_PCLK or S3C2410_EINTFLT_EXTCLK orred with
- *          width of filter (0 through 63)
- *
- *
-*/
-
-extern int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
-                                 unsigned int config);
-
-/* s3c2410_gpio_pullup
- *
- * configure the pull-up control on the given pin
- *
- * to = 1 => disable the pull-up
- *      0 => enable the pull-up
- *
- * eg;
- *
- *   s3c2410_gpio_pullup(S3C2410_GPB0, 0);
- *   s3c2410_gpio_pullup(S3C2410_GPE8, 0);
-*/
-
-extern void s3c2410_gpio_pullup(unsigned int pin, unsigned int to);
-
-/* s3c2410_gpio_getpull
- *
- * Read the state of the pull-up on a given pin
- *
- * return:
- *     < 0 => error code
- *       0 => enabled
- *       1 => disabled
-*/
-
-extern int s3c2410_gpio_getpull(unsigned int pin);
-
-extern void s3c2410_gpio_setpin(unsigned int pin, unsigned int to);
-
-extern unsigned int s3c2410_gpio_getpin(unsigned int pin);
-
 extern unsigned int s3c2410_modify_misccr(unsigned int clr, unsigned int chg);
 
 #ifdef CONFIG_CPU_S3C2440
index 255fdfeaf957a6d80e692cd24430dca7ec409c58..e99b212cb1ca6b6bec947a96529ccd3d2e4e8a5c 100644 (file)
@@ -84,7 +84,6 @@
 
 #define S3C24XX_PA_IRQ      S3C2410_PA_IRQ
 #define S3C24XX_PA_MEMCTRL  S3C2410_PA_MEMCTRL
-#define S3C24XX_PA_USBHOST  S3C2410_PA_USBHOST
 #define S3C24XX_PA_DMA      S3C2410_PA_DMA
 #define S3C24XX_PA_CLKPWR   S3C2410_PA_CLKPWR
 #define S3C24XX_PA_LCD      S3C2410_PA_LCD
 
 #define S3C_PA_IIC          S3C2410_PA_IIC
 #define S3C_PA_UART        S3C24XX_PA_UART
+#define S3C_PA_USBHOST S3C2410_PA_USBHOST
 #define S3C_PA_HSMMC0      S3C2443_PA_HSMMC
 
 #endif /* __ASM_ARCH_MAP_H */
index 35a03df473fcfd13f17c7d78a7cb9a1ca89a8926..b278d0c45ccf359e5a8aec6a7ac852740ef52c88 100644 (file)
 #define S3C2400_GPACON    S3C2410_GPIOREG(0x00)
 #define S3C2400_GPADAT    S3C2410_GPIOREG(0x04)
 
-#define S3C2410_GPA0         S3C2410_GPIONO(S3C2410_GPIO_BANKA, 0)
-#define S3C2410_GPA0_OUT     (0<<0)
 #define S3C2410_GPA0_ADDR0   (1<<0)
 
-#define S3C2410_GPA1         S3C2410_GPIONO(S3C2410_GPIO_BANKA, 1)
-#define S3C2410_GPA1_OUT     (0<<1)
 #define S3C2410_GPA1_ADDR16  (1<<1)
 
-#define S3C2410_GPA2         S3C2410_GPIONO(S3C2410_GPIO_BANKA, 2)
-#define S3C2410_GPA2_OUT     (0<<2)
 #define S3C2410_GPA2_ADDR17  (1<<2)
 
-#define S3C2410_GPA3         S3C2410_GPIONO(S3C2410_GPIO_BANKA, 3)
-#define S3C2410_GPA3_OUT     (0<<3)
 #define S3C2410_GPA3_ADDR18  (1<<3)
 
-#define S3C2410_GPA4         S3C2410_GPIONO(S3C2410_GPIO_BANKA, 4)
-#define S3C2410_GPA4_OUT     (0<<4)
 #define S3C2410_GPA4_ADDR19  (1<<4)
 
-#define S3C2410_GPA5         S3C2410_GPIONO(S3C2410_GPIO_BANKA, 5)
-#define S3C2410_GPA5_OUT     (0<<5)
 #define S3C2410_GPA5_ADDR20  (1<<5)
 
-#define S3C2410_GPA6         S3C2410_GPIONO(S3C2410_GPIO_BANKA, 6)
-#define S3C2410_GPA6_OUT     (0<<6)
 #define S3C2410_GPA6_ADDR21  (1<<6)
 
-#define S3C2410_GPA7         S3C2410_GPIONO(S3C2410_GPIO_BANKA, 7)
-#define S3C2410_GPA7_OUT     (0<<7)
 #define S3C2410_GPA7_ADDR22  (1<<7)
 
-#define S3C2410_GPA8         S3C2410_GPIONO(S3C2410_GPIO_BANKA, 8)
-#define S3C2410_GPA8_OUT     (0<<8)
 #define S3C2410_GPA8_ADDR23  (1<<8)
 
-#define S3C2410_GPA9         S3C2410_GPIONO(S3C2410_GPIO_BANKA, 9)
-#define S3C2410_GPA9_OUT     (0<<9)
 #define S3C2410_GPA9_ADDR24  (1<<9)
 
-#define S3C2410_GPA10        S3C2410_GPIONO(S3C2410_GPIO_BANKA, 10)
-#define S3C2410_GPA10_OUT    (0<<10)
 #define S3C2410_GPA10_ADDR25 (1<<10)
 #define S3C2400_GPA10_SCKE   (1<<10)
 
-#define S3C2410_GPA11        S3C2410_GPIONO(S3C2410_GPIO_BANKA, 11)
-#define S3C2410_GPA11_OUT    (0<<11)
 #define S3C2410_GPA11_ADDR26 (1<<11)
 #define S3C2400_GPA11_nCAS0  (1<<11)
 
-#define S3C2410_GPA12        S3C2410_GPIONO(S3C2410_GPIO_BANKA, 12)
-#define S3C2410_GPA12_OUT    (0<<12)
 #define S3C2410_GPA12_nGCS1  (1<<12)
 #define S3C2400_GPA12_nCAS1  (1<<12)
 
-#define S3C2410_GPA13        S3C2410_GPIONO(S3C2410_GPIO_BANKA, 13)
-#define S3C2410_GPA13_OUT    (0<<13)
 #define S3C2410_GPA13_nGCS2  (1<<13)
 #define S3C2400_GPA13_nGCS1  (1<<13)
 
-#define S3C2410_GPA14        S3C2410_GPIONO(S3C2410_GPIO_BANKA, 14)
-#define S3C2410_GPA14_OUT    (0<<14)
 #define S3C2410_GPA14_nGCS3  (1<<14)
 #define S3C2400_GPA14_nGCS2  (1<<14)
 
-#define S3C2410_GPA15        S3C2410_GPIONO(S3C2410_GPIO_BANKA, 15)
-#define S3C2410_GPA15_OUT    (0<<15)
 #define S3C2410_GPA15_nGCS4  (1<<15)
 #define S3C2400_GPA15_nGCS3  (1<<15)
 
-#define S3C2410_GPA16        S3C2410_GPIONO(S3C2410_GPIO_BANKA, 16)
-#define S3C2410_GPA16_OUT    (0<<16)
 #define S3C2410_GPA16_nGCS5  (1<<16)
 #define S3C2400_GPA16_nGCS4  (1<<16)
 
-#define S3C2410_GPA17        S3C2410_GPIONO(S3C2410_GPIO_BANKA, 17)
-#define S3C2410_GPA17_OUT    (0<<17)
 #define S3C2410_GPA17_CLE    (1<<17)
 #define S3C2400_GPA17_nGCS5  (1<<17)
 
-#define S3C2410_GPA18        S3C2410_GPIONO(S3C2410_GPIO_BANKA, 18)
-#define S3C2410_GPA18_OUT    (0<<18)
 #define S3C2410_GPA18_ALE    (1<<18)
 
-#define S3C2410_GPA19        S3C2410_GPIONO(S3C2410_GPIO_BANKA, 19)
-#define S3C2410_GPA19_OUT    (0<<19)
 #define S3C2410_GPA19_nFWE   (1<<19)
 
-#define S3C2410_GPA20        S3C2410_GPIONO(S3C2410_GPIO_BANKA, 20)
-#define S3C2410_GPA20_OUT    (0<<20)
 #define S3C2410_GPA20_nFRE   (1<<20)
 
-#define S3C2410_GPA21        S3C2410_GPIONO(S3C2410_GPIO_BANKA, 21)
-#define S3C2410_GPA21_OUT    (0<<21)
 #define S3C2410_GPA21_nRSTOUT (1<<21)
 
-#define S3C2410_GPA22        S3C2410_GPIONO(S3C2410_GPIO_BANKA, 22)
-#define S3C2410_GPA22_OUT    (0<<22)
 #define S3C2410_GPA22_nFCE   (1<<22)
 
 /* 0x08 and 0x0c are reserved on S3C2410 */
 
 /* no i/o pin in port b can have value 3 (unless it is a s3c2443) ! */
 
-#define S3C2410_GPB0         S3C2410_GPIONO(S3C2410_GPIO_BANKB, 0)
-#define S3C2410_GPB0_INP     (0x00 << 0)
-#define S3C2410_GPB0_OUTP    (0x01 << 0)
 #define S3C2410_GPB0_TOUT0   (0x02 << 0)
 #define S3C2400_GPB0_DATA16  (0x02 << 0)
 
-#define S3C2410_GPB1         S3C2410_GPIONO(S3C2410_GPIO_BANKB, 1)
-#define S3C2410_GPB1_INP     (0x00 << 2)
-#define S3C2410_GPB1_OUTP    (0x01 << 2)
 #define S3C2410_GPB1_TOUT1   (0x02 << 2)
 #define S3C2400_GPB1_DATA17  (0x02 << 2)
 
-#define S3C2410_GPB2         S3C2410_GPIONO(S3C2410_GPIO_BANKB, 2)
-#define S3C2410_GPB2_INP     (0x00 << 4)
-#define S3C2410_GPB2_OUTP    (0x01 << 4)
 #define S3C2410_GPB2_TOUT2   (0x02 << 4)
 #define S3C2400_GPB2_DATA18  (0x02 << 4)
 #define S3C2400_GPB2_TCLK1   (0x03 << 4)
 
-#define S3C2410_GPB3         S3C2410_GPIONO(S3C2410_GPIO_BANKB, 3)
-#define S3C2410_GPB3_INP     (0x00 << 6)
-#define S3C2410_GPB3_OUTP    (0x01 << 6)
 #define S3C2410_GPB3_TOUT3   (0x02 << 6)
 #define S3C2400_GPB3_DATA19  (0x02 << 6)
 #define S3C2400_GPB3_TXD1    (0x03 << 6)
 
-#define S3C2410_GPB4         S3C2410_GPIONO(S3C2410_GPIO_BANKB, 4)
-#define S3C2410_GPB4_INP     (0x00 << 8)
-#define S3C2410_GPB4_OUTP    (0x01 << 8)
 #define S3C2410_GPB4_TCLK0   (0x02 << 8)
 #define S3C2400_GPB4_DATA20  (0x02 << 8)
 #define S3C2410_GPB4_MASK    (0x03 << 8)
 #define S3C2400_GPB4_RXD1    (0x03 << 8)
 #define S3C2400_GPB4_MASK    (0x03 << 8)
 
-#define S3C2410_GPB5         S3C2410_GPIONO(S3C2410_GPIO_BANKB, 5)
-#define S3C2410_GPB5_INP     (0x00 << 10)
-#define S3C2410_GPB5_OUTP    (0x01 << 10)
 #define S3C2410_GPB5_nXBACK  (0x02 << 10)
 #define S3C2443_GPB5_XBACK   (0x03 << 10)
 #define S3C2400_GPB5_DATA21  (0x02 << 10)
 #define S3C2400_GPB5_nCTS1   (0x03 << 10)
 
-#define S3C2410_GPB6         S3C2410_GPIONO(S3C2410_GPIO_BANKB, 6)
-#define S3C2410_GPB6_INP     (0x00 << 12)
-#define S3C2410_GPB6_OUTP    (0x01 << 12)
 #define S3C2410_GPB6_nXBREQ  (0x02 << 12)
 #define S3C2443_GPB6_XBREQ   (0x03 << 12)
 #define S3C2400_GPB6_DATA22  (0x02 << 12)
 #define S3C2400_GPB6_nRTS1   (0x03 << 12)
 
-#define S3C2410_GPB7         S3C2410_GPIONO(S3C2410_GPIO_BANKB, 7)
-#define S3C2410_GPB7_INP     (0x00 << 14)
-#define S3C2410_GPB7_OUTP    (0x01 << 14)
 #define S3C2410_GPB7_nXDACK1 (0x02 << 14)
 #define S3C2443_GPB7_XDACK1  (0x03 << 14)
 #define S3C2400_GPB7_DATA23  (0x02 << 14)
 
-#define S3C2410_GPB8         S3C2410_GPIONO(S3C2410_GPIO_BANKB, 8)
-#define S3C2410_GPB8_INP     (0x00 << 16)
-#define S3C2410_GPB8_OUTP    (0x01 << 16)
 #define S3C2410_GPB8_nXDREQ1 (0x02 << 16)
 #define S3C2400_GPB8_DATA24  (0x02 << 16)
 
-#define S3C2410_GPB9         S3C2410_GPIONO(S3C2410_GPIO_BANKB, 9)
-#define S3C2410_GPB9_INP     (0x00 << 18)
-#define S3C2410_GPB9_OUTP    (0x01 << 18)
 #define S3C2410_GPB9_nXDACK0 (0x02 << 18)
 #define S3C2443_GPB9_XDACK0  (0x03 << 18)
 #define S3C2400_GPB9_DATA25  (0x02 << 18)
 #define S3C2400_GPB9_I2SSDI  (0x03 << 18)
 
-#define S3C2410_GPB10        S3C2410_GPIONO(S3C2410_GPIO_BANKB, 10)
-#define S3C2410_GPB10_INP    (0x00 << 20)
-#define S3C2410_GPB10_OUTP   (0x01 << 20)
 #define S3C2410_GPB10_nXDRE0 (0x02 << 20)
 #define S3C2443_GPB10_XDREQ0 (0x03 << 20)
 #define S3C2400_GPB10_DATA26 (0x02 << 20)
 #define S3C2400_GPB10_nSS    (0x03 << 20)
 
-#define S3C2400_GPB11        S3C2410_GPIONO(S3C2410_GPIO_BANKB, 11)
 #define S3C2400_GPB11_INP    (0x00 << 22)
 #define S3C2400_GPB11_OUTP   (0x01 << 22)
 #define S3C2400_GPB11_DATA27 (0x02 << 22)
 
-#define S3C2400_GPB12        S3C2410_GPIONO(S3C2410_GPIO_BANKB, 12)
 #define S3C2400_GPB12_INP    (0x00 << 24)
 #define S3C2400_GPB12_OUTP   (0x01 << 24)
 #define S3C2400_GPB12_DATA28 (0x02 << 24)
 
-#define S3C2400_GPB13        S3C2410_GPIONO(S3C2410_GPIO_BANKB, 13)
 #define S3C2400_GPB13_INP    (0x00 << 26)
 #define S3C2400_GPB13_OUTP   (0x01 << 26)
 #define S3C2400_GPB13_DATA29 (0x02 << 26)
 
-#define S3C2400_GPB14        S3C2410_GPIONO(S3C2410_GPIO_BANKB, 14)
 #define S3C2400_GPB14_INP    (0x00 << 28)
 #define S3C2400_GPB14_OUTP   (0x01 << 28)
 #define S3C2400_GPB14_DATA30 (0x02 << 28)
 
-#define S3C2400_GPB15        S3C2410_GPIONO(S3C2410_GPIO_BANKB, 15)
 #define S3C2400_GPB15_INP    (0x00 << 30)
 #define S3C2400_GPB15_OUTP   (0x01 << 30)
 #define S3C2400_GPB15_DATA31 (0x02 << 30)
 #define S3C2400_GPCDAT    S3C2410_GPIOREG(0x18)
 #define S3C2400_GPCUP     S3C2410_GPIOREG(0x1C)
 
-#define S3C2410_GPC0            S3C2410_GPIONO(S3C2410_GPIO_BANKC, 0)
-#define S3C2410_GPC0_INP       (0x00 << 0)
-#define S3C2410_GPC0_OUTP      (0x01 << 0)
 #define S3C2410_GPC0_LEND      (0x02 << 0)
 #define S3C2400_GPC0_VD0       (0x02 << 0)
 
-#define S3C2410_GPC1            S3C2410_GPIONO(S3C2410_GPIO_BANKC, 1)
-#define S3C2410_GPC1_INP       (0x00 << 2)
-#define S3C2410_GPC1_OUTP      (0x01 << 2)
 #define S3C2410_GPC1_VCLK      (0x02 << 2)
 #define S3C2400_GPC1_VD1       (0x02 << 2)
 
-#define S3C2410_GPC2            S3C2410_GPIONO(S3C2410_GPIO_BANKC, 2)
-#define S3C2410_GPC2_INP       (0x00 << 4)
-#define S3C2410_GPC2_OUTP      (0x01 << 4)
 #define S3C2410_GPC2_VLINE     (0x02 << 4)
 #define S3C2400_GPC2_VD2       (0x02 << 4)
 
-#define S3C2410_GPC3            S3C2410_GPIONO(S3C2410_GPIO_BANKC, 3)
-#define S3C2410_GPC3_INP       (0x00 << 6)
-#define S3C2410_GPC3_OUTP      (0x01 << 6)
 #define S3C2410_GPC3_VFRAME    (0x02 << 6)
 #define S3C2400_GPC3_VD3       (0x02 << 6)
 
-#define S3C2410_GPC4            S3C2410_GPIONO(S3C2410_GPIO_BANKC, 4)
-#define S3C2410_GPC4_INP       (0x00 << 8)
-#define S3C2410_GPC4_OUTP      (0x01 << 8)
 #define S3C2410_GPC4_VM                (0x02 << 8)
 #define S3C2400_GPC4_VD4       (0x02 << 8)
 
-#define S3C2410_GPC5            S3C2410_GPIONO(S3C2410_GPIO_BANKC, 5)
-#define S3C2410_GPC5_INP       (0x00 << 10)
-#define S3C2410_GPC5_OUTP      (0x01 << 10)
 #define S3C2410_GPC5_LCDVF0    (0x02 << 10)
 #define S3C2400_GPC5_VD5       (0x02 << 10)
 
-#define S3C2410_GPC6            S3C2410_GPIONO(S3C2410_GPIO_BANKC, 6)
-#define S3C2410_GPC6_INP       (0x00 << 12)
-#define S3C2410_GPC6_OUTP      (0x01 << 12)
 #define S3C2410_GPC6_LCDVF1    (0x02 << 12)
 #define S3C2400_GPC6_VD6       (0x02 << 12)
 
-#define S3C2410_GPC7            S3C2410_GPIONO(S3C2410_GPIO_BANKC, 7)
-#define S3C2410_GPC7_INP       (0x00 << 14)
-#define S3C2410_GPC7_OUTP      (0x01 << 14)
 #define S3C2410_GPC7_LCDVF2    (0x02 << 14)
 #define S3C2400_GPC7_VD7       (0x02 << 14)
 
-#define S3C2410_GPC8            S3C2410_GPIONO(S3C2410_GPIO_BANKC, 8)
-#define S3C2410_GPC8_INP       (0x00 << 16)
-#define S3C2410_GPC8_OUTP      (0x01 << 16)
 #define S3C2410_GPC8_VD0       (0x02 << 16)
 #define S3C2400_GPC8_VD8       (0x02 << 16)
 
-#define S3C2410_GPC9            S3C2410_GPIONO(S3C2410_GPIO_BANKC, 9)
-#define S3C2410_GPC9_INP       (0x00 << 18)
-#define S3C2410_GPC9_OUTP      (0x01 << 18)
 #define S3C2410_GPC9_VD1       (0x02 << 18)
 #define S3C2400_GPC9_VD9       (0x02 << 18)
 
-#define S3C2410_GPC10           S3C2410_GPIONO(S3C2410_GPIO_BANKC, 10)
-#define S3C2410_GPC10_INP      (0x00 << 20)
-#define S3C2410_GPC10_OUTP     (0x01 << 20)
 #define S3C2410_GPC10_VD2      (0x02 << 20)
 #define S3C2400_GPC10_VD10     (0x02 << 20)
 
-#define S3C2410_GPC11           S3C2410_GPIONO(S3C2410_GPIO_BANKC, 11)
-#define S3C2410_GPC11_INP      (0x00 << 22)
-#define S3C2410_GPC11_OUTP     (0x01 << 22)
 #define S3C2410_GPC11_VD3      (0x02 << 22)
 #define S3C2400_GPC11_VD11     (0x02 << 22)
 
-#define S3C2410_GPC12           S3C2410_GPIONO(S3C2410_GPIO_BANKC, 12)
-#define S3C2410_GPC12_INP      (0x00 << 24)
-#define S3C2410_GPC12_OUTP     (0x01 << 24)
 #define S3C2410_GPC12_VD4      (0x02 << 24)
 #define S3C2400_GPC12_VD12     (0x02 << 24)
 
-#define S3C2410_GPC13           S3C2410_GPIONO(S3C2410_GPIO_BANKC, 13)
-#define S3C2410_GPC13_INP      (0x00 << 26)
-#define S3C2410_GPC13_OUTP     (0x01 << 26)
 #define S3C2410_GPC13_VD5      (0x02 << 26)
 #define S3C2400_GPC13_VD13     (0x02 << 26)
 
-#define S3C2410_GPC14           S3C2410_GPIONO(S3C2410_GPIO_BANKC, 14)
-#define S3C2410_GPC14_INP      (0x00 << 28)
-#define S3C2410_GPC14_OUTP     (0x01 << 28)
 #define S3C2410_GPC14_VD6      (0x02 << 28)
 #define S3C2400_GPC14_VD14     (0x02 << 28)
 
-#define S3C2410_GPC15           S3C2410_GPIONO(S3C2410_GPIO_BANKC, 15)
-#define S3C2410_GPC15_INP      (0x00 << 30)
-#define S3C2410_GPC15_OUTP     (0x01 << 30)
 #define S3C2410_GPC15_VD7      (0x02 << 30)
 #define S3C2400_GPC15_VD15     (0x02 << 30)
 
 #define S3C2400_GPDDAT    S3C2410_GPIOREG(0x24)
 #define S3C2400_GPDUP     S3C2410_GPIOREG(0x28)
 
-#define S3C2410_GPD0            S3C2410_GPIONO(S3C2410_GPIO_BANKD, 0)
-#define S3C2410_GPD0_INP       (0x00 << 0)
-#define S3C2410_GPD0_OUTP      (0x01 << 0)
 #define S3C2410_GPD0_VD8       (0x02 << 0)
 #define S3C2400_GPD0_VFRAME    (0x02 << 0)
 #define S3C2442_GPD0_nSPICS1   (0x03 << 0)
 
-#define S3C2410_GPD1            S3C2410_GPIONO(S3C2410_GPIO_BANKD, 1)
-#define S3C2410_GPD1_INP       (0x00 << 2)
-#define S3C2410_GPD1_OUTP      (0x01 << 2)
 #define S3C2410_GPD1_VD9       (0x02 << 2)
 #define S3C2400_GPD1_VM                (0x02 << 2)
 #define S3C2442_GPD1_SPICLK1   (0x03 << 2)
 
-#define S3C2410_GPD2            S3C2410_GPIONO(S3C2410_GPIO_BANKD, 2)
-#define S3C2410_GPD2_INP       (0x00 << 4)
-#define S3C2410_GPD2_OUTP      (0x01 << 4)
 #define S3C2410_GPD2_VD10      (0x02 << 4)
 #define S3C2400_GPD2_VLINE     (0x02 << 4)
 
-#define S3C2410_GPD3            S3C2410_GPIONO(S3C2410_GPIO_BANKD, 3)
-#define S3C2410_GPD3_INP       (0x00 << 6)
-#define S3C2410_GPD3_OUTP      (0x01 << 6)
 #define S3C2410_GPD3_VD11      (0x02 << 6)
 #define S3C2400_GPD3_VCLK      (0x02 << 6)
 
-#define S3C2410_GPD4            S3C2410_GPIONO(S3C2410_GPIO_BANKD, 4)
-#define S3C2410_GPD4_INP       (0x00 << 8)
-#define S3C2410_GPD4_OUTP      (0x01 << 8)
 #define S3C2410_GPD4_VD12      (0x02 << 8)
 #define S3C2400_GPD4_LEND      (0x02 << 8)
 
-#define S3C2410_GPD5            S3C2410_GPIONO(S3C2410_GPIO_BANKD, 5)
-#define S3C2410_GPD5_INP       (0x00 << 10)
-#define S3C2410_GPD5_OUTP      (0x01 << 10)
 #define S3C2410_GPD5_VD13      (0x02 << 10)
 #define S3C2400_GPD5_TOUT0     (0x02 << 10)
 
-#define S3C2410_GPD6            S3C2410_GPIONO(S3C2410_GPIO_BANKD, 6)
-#define S3C2410_GPD6_INP       (0x00 << 12)
-#define S3C2410_GPD6_OUTP      (0x01 << 12)
 #define S3C2410_GPD6_VD14      (0x02 << 12)
 #define S3C2400_GPD6_TOUT1     (0x02 << 12)
 
-#define S3C2410_GPD7            S3C2410_GPIONO(S3C2410_GPIO_BANKD, 7)
-#define S3C2410_GPD7_INP       (0x00 << 14)
-#define S3C2410_GPD7_OUTP      (0x01 << 14)
 #define S3C2410_GPD7_VD15      (0x02 << 14)
 #define S3C2400_GPD7_TOUT2     (0x02 << 14)
 
-#define S3C2410_GPD8            S3C2410_GPIONO(S3C2410_GPIO_BANKD, 8)
-#define S3C2410_GPD8_INP       (0x00 << 16)
-#define S3C2410_GPD8_OUTP      (0x01 << 16)
 #define S3C2410_GPD8_VD16      (0x02 << 16)
 #define S3C2400_GPD8_TOUT3     (0x02 << 16)
 
-#define S3C2410_GPD9            S3C2410_GPIONO(S3C2410_GPIO_BANKD, 9)
-#define S3C2410_GPD9_INP       (0x00 << 18)
-#define S3C2410_GPD9_OUTP      (0x01 << 18)
 #define S3C2410_GPD9_VD17      (0x02 << 18)
 #define S3C2400_GPD9_TCLK0     (0x02 << 18)
 #define S3C2410_GPD9_MASK       (0x03 << 18)
 
-#define S3C2410_GPD10           S3C2410_GPIONO(S3C2410_GPIO_BANKD, 10)
-#define S3C2410_GPD10_INP      (0x00 << 20)
-#define S3C2410_GPD10_OUTP     (0x01 << 20)
 #define S3C2410_GPD10_VD18     (0x02 << 20)
 #define S3C2400_GPD10_nWAIT    (0x02 << 20)
 
-#define S3C2410_GPD11           S3C2410_GPIONO(S3C2410_GPIO_BANKD, 11)
-#define S3C2410_GPD11_INP      (0x00 << 22)
-#define S3C2410_GPD11_OUTP     (0x01 << 22)
 #define S3C2410_GPD11_VD19     (0x02 << 22)
 
-#define S3C2410_GPD12           S3C2410_GPIONO(S3C2410_GPIO_BANKD, 12)
-#define S3C2410_GPD12_INP      (0x00 << 24)
-#define S3C2410_GPD12_OUTP     (0x01 << 24)
 #define S3C2410_GPD12_VD20     (0x02 << 24)
 
-#define S3C2410_GPD13           S3C2410_GPIONO(S3C2410_GPIO_BANKD, 13)
-#define S3C2410_GPD13_INP      (0x00 << 26)
-#define S3C2410_GPD13_OUTP     (0x01 << 26)
 #define S3C2410_GPD13_VD21     (0x02 << 26)
 
-#define S3C2410_GPD14           S3C2410_GPIONO(S3C2410_GPIO_BANKD, 14)
-#define S3C2410_GPD14_INP      (0x00 << 28)
-#define S3C2410_GPD14_OUTP     (0x01 << 28)
 #define S3C2410_GPD14_VD22     (0x02 << 28)
 #define S3C2410_GPD14_nSS1     (0x03 << 28)
 
-#define S3C2410_GPD15           S3C2410_GPIONO(S3C2410_GPIO_BANKD, 15)
-#define S3C2410_GPD15_INP      (0x00 << 30)
-#define S3C2410_GPD15_OUTP     (0x01 << 30)
 #define S3C2410_GPD15_VD23     (0x02 << 30)
 #define S3C2410_GPD15_nSS0     (0x03 << 30)
 
 #define S3C2400_GPEDAT    S3C2410_GPIOREG(0x30)
 #define S3C2400_GPEUP     S3C2410_GPIOREG(0x34)
 
-#define S3C2410_GPE0           S3C2410_GPIONO(S3C2410_GPIO_BANKE, 0)
-#define S3C2410_GPE0_INP       (0x00 << 0)
-#define S3C2410_GPE0_OUTP      (0x01 << 0)
 #define S3C2410_GPE0_I2SLRCK   (0x02 << 0)
 #define S3C2443_GPE0_AC_nRESET (0x03 << 0)
 #define S3C2400_GPE0_EINT0     (0x02 << 0)
 #define S3C2410_GPE0_MASK      (0x03 << 0)
 
-#define S3C2410_GPE1           S3C2410_GPIONO(S3C2410_GPIO_BANKE, 1)
-#define S3C2410_GPE1_INP       (0x00 << 2)
-#define S3C2410_GPE1_OUTP      (0x01 << 2)
 #define S3C2410_GPE1_I2SSCLK   (0x02 << 2)
 #define S3C2443_GPE1_AC_SYNC   (0x03 << 2)
 #define S3C2400_GPE1_EINT1     (0x02 << 2)
 #define S3C2400_GPE1_nSS       (0x03 << 2)
 #define S3C2410_GPE1_MASK      (0x03 << 2)
 
-#define S3C2410_GPE2           S3C2410_GPIONO(S3C2410_GPIO_BANKE, 2)
-#define S3C2410_GPE2_INP       (0x00 << 4)
-#define S3C2410_GPE2_OUTP      (0x01 << 4)
 #define S3C2410_GPE2_CDCLK     (0x02 << 4)
 #define S3C2443_GPE2_AC_BITCLK (0x03 << 4)
 #define S3C2400_GPE2_EINT2     (0x02 << 4)
 #define S3C2400_GPE2_I2SSDI    (0x03 << 4)
 
-#define S3C2410_GPE3           S3C2410_GPIONO(S3C2410_GPIO_BANKE, 3)
-#define S3C2410_GPE3_INP       (0x00 << 6)
-#define S3C2410_GPE3_OUTP      (0x01 << 6)
 #define S3C2410_GPE3_I2SSDI    (0x02 << 6)
 #define S3C2443_GPE3_AC_SDI    (0x03 << 6)
 #define S3C2400_GPE3_EINT3     (0x02 << 6)
 #define S3C2410_GPE3_nSS0      (0x03 << 6)
 #define S3C2410_GPE3_MASK      (0x03 << 6)
 
-#define S3C2410_GPE4           S3C2410_GPIONO(S3C2410_GPIO_BANKE, 4)
-#define S3C2410_GPE4_INP       (0x00 << 8)
-#define S3C2410_GPE4_OUTP      (0x01 << 8)
 #define S3C2410_GPE4_I2SSDO    (0x02 << 8)
 #define S3C2443_GPE4_AC_SDO    (0x03 << 8)
 #define S3C2400_GPE4_EINT4     (0x02 << 8)
 #define S3C2410_GPE4_I2SSDI    (0x03 << 8)
 #define S3C2410_GPE4_MASK      (0x03 << 8)
 
-#define S3C2410_GPE5           S3C2410_GPIONO(S3C2410_GPIO_BANKE, 5)
-#define S3C2410_GPE5_INP       (0x00 << 10)
-#define S3C2410_GPE5_OUTP      (0x01 << 10)
 #define S3C2410_GPE5_SDCLK     (0x02 << 10)
 #define S3C2443_GPE5_SD1_CLK   (0x02 << 10)
 #define S3C2400_GPE5_EINT5     (0x02 << 10)
 #define S3C2400_GPE5_TCLK1     (0x03 << 10)
 
-#define S3C2410_GPE6           S3C2410_GPIONO(S3C2410_GPIO_BANKE, 6)
-#define S3C2410_GPE6_INP       (0x00 << 12)
-#define S3C2410_GPE6_OUTP      (0x01 << 12)
 #define S3C2410_GPE6_SDCMD     (0x02 << 12)
 #define S3C2443_GPE6_SD1_CMD   (0x02 << 12)
 #define S3C2443_GPE6_AC_BITCLK (0x03 << 12)
 #define S3C2400_GPE6_EINT6     (0x02 << 12)
 
-#define S3C2410_GPE7           S3C2410_GPIONO(S3C2410_GPIO_BANKE, 7)
-#define S3C2410_GPE7_INP       (0x00 << 14)
-#define S3C2410_GPE7_OUTP      (0x01 << 14)
 #define S3C2410_GPE7_SDDAT0    (0x02 << 14)
 #define S3C2443_GPE5_SD1_DAT0  (0x02 << 14)
 #define S3C2443_GPE7_AC_SDI    (0x03 << 14)
 #define S3C2400_GPE7_EINT7     (0x02 << 14)
 
-#define S3C2410_GPE8           S3C2410_GPIONO(S3C2410_GPIO_BANKE, 8)
-#define S3C2410_GPE8_INP       (0x00 << 16)
-#define S3C2410_GPE8_OUTP      (0x01 << 16)
 #define S3C2410_GPE8_SDDAT1    (0x02 << 16)
 #define S3C2443_GPE8_SD1_DAT1  (0x02 << 16)
 #define S3C2443_GPE8_AC_SDO    (0x03 << 16)
 #define S3C2400_GPE8_nXDACK0   (0x02 << 16)
 
-#define S3C2410_GPE9           S3C2410_GPIONO(S3C2410_GPIO_BANKE, 9)
-#define S3C2410_GPE9_INP       (0x00 << 18)
-#define S3C2410_GPE9_OUTP      (0x01 << 18)
 #define S3C2410_GPE9_SDDAT2    (0x02 << 18)
 #define S3C2443_GPE9_SD1_DAT2  (0x02 << 18)
 #define S3C2443_GPE9_AC_SYNC   (0x03 << 18)
 #define S3C2400_GPE9_nXDACK1   (0x02 << 18)
 #define S3C2400_GPE9_nXBACK    (0x03 << 18)
 
-#define S3C2410_GPE10          S3C2410_GPIONO(S3C2410_GPIO_BANKE, 10)
-#define S3C2410_GPE10_INP      (0x00 << 20)
-#define S3C2410_GPE10_OUTP     (0x01 << 20)
 #define S3C2410_GPE10_SDDAT3   (0x02 << 20)
 #define S3C2443_GPE10_SD1_DAT3 (0x02 << 20)
 #define S3C2443_GPE10_AC_nRESET (0x03 << 20)
 #define S3C2400_GPE10_nXDREQ0  (0x02 << 20)
 
-#define S3C2410_GPE11          S3C2410_GPIONO(S3C2410_GPIO_BANKE, 11)
-#define S3C2410_GPE11_INP      (0x00 << 22)
-#define S3C2410_GPE11_OUTP     (0x01 << 22)
 #define S3C2410_GPE11_SPIMISO0 (0x02 << 22)
 #define S3C2400_GPE11_nXDREQ1  (0x02 << 22)
 #define S3C2400_GPE11_nXBREQ   (0x03 << 22)
 
-#define S3C2410_GPE12          S3C2410_GPIONO(S3C2410_GPIO_BANKE, 12)
-#define S3C2410_GPE12_INP      (0x00 << 24)
-#define S3C2410_GPE12_OUTP     (0x01 << 24)
 #define S3C2410_GPE12_SPIMOSI0 (0x02 << 24)
 
-#define S3C2410_GPE13          S3C2410_GPIONO(S3C2410_GPIO_BANKE, 13)
-#define S3C2410_GPE13_INP      (0x00 << 26)
-#define S3C2410_GPE13_OUTP     (0x01 << 26)
 #define S3C2410_GPE13_SPICLK0  (0x02 << 26)
 
-#define S3C2410_GPE14          S3C2410_GPIONO(S3C2410_GPIO_BANKE, 14)
-#define S3C2410_GPE14_INP      (0x00 << 28)
-#define S3C2410_GPE14_OUTP     (0x01 << 28)
 #define S3C2410_GPE14_IICSCL   (0x02 << 28)
 #define S3C2410_GPE14_MASK     (0x03 << 28)
 
-#define S3C2410_GPE15          S3C2410_GPIONO(S3C2410_GPIO_BANKE, 15)
-#define S3C2410_GPE15_INP      (0x00 << 30)
-#define S3C2410_GPE15_OUTP     (0x01 << 30)
 #define S3C2410_GPE15_IICSDA   (0x02 << 30)
 #define S3C2410_GPE15_MASK     (0x03 << 30)
 
 #define S3C2400_GPFDAT    S3C2410_GPIOREG(0x3C)
 #define S3C2400_GPFUP     S3C2410_GPIOREG(0x40)
 
-#define S3C2410_GPF0        S3C2410_GPIONO(S3C2410_GPIO_BANKF, 0)
-#define S3C2410_GPF0_INP    (0x00 << 0)
-#define S3C2410_GPF0_OUTP   (0x01 << 0)
 #define S3C2410_GPF0_EINT0  (0x02 << 0)
 #define S3C2400_GPF0_RXD0   (0x02 << 0)
 
-#define S3C2410_GPF1        S3C2410_GPIONO(S3C2410_GPIO_BANKF, 1)
-#define S3C2410_GPF1_INP    (0x00 << 2)
-#define S3C2410_GPF1_OUTP   (0x01 << 2)
 #define S3C2410_GPF1_EINT1  (0x02 << 2)
 #define S3C2400_GPF1_RXD1   (0x02 << 2)
 #define S3C2400_GPF1_IICSDA (0x03 << 2)
 
-#define S3C2410_GPF2        S3C2410_GPIONO(S3C2410_GPIO_BANKF, 2)
-#define S3C2410_GPF2_INP    (0x00 << 4)
-#define S3C2410_GPF2_OUTP   (0x01 << 4)
 #define S3C2410_GPF2_EINT2  (0x02 << 4)
 #define S3C2400_GPF2_TXD0   (0x02 << 4)
 
-#define S3C2410_GPF3        S3C2410_GPIONO(S3C2410_GPIO_BANKF, 3)
-#define S3C2410_GPF3_INP    (0x00 << 6)
-#define S3C2410_GPF3_OUTP   (0x01 << 6)
 #define S3C2410_GPF3_EINT3  (0x02 << 6)
 #define S3C2400_GPF3_TXD1   (0x02 << 6)
 #define S3C2400_GPF3_IICSCL (0x03 << 6)
 
-#define S3C2410_GPF4        S3C2410_GPIONO(S3C2410_GPIO_BANKF, 4)
-#define S3C2410_GPF4_INP    (0x00 << 8)
-#define S3C2410_GPF4_OUTP   (0x01 << 8)
 #define S3C2410_GPF4_EINT4  (0x02 << 8)
 #define S3C2400_GPF4_nRTS0  (0x02 << 8)
 #define S3C2400_GPF4_nXBACK (0x03 << 8)
 
-#define S3C2410_GPF5        S3C2410_GPIONO(S3C2410_GPIO_BANKF, 5)
-#define S3C2410_GPF5_INP    (0x00 << 10)
-#define S3C2410_GPF5_OUTP   (0x01 << 10)
 #define S3C2410_GPF5_EINT5  (0x02 << 10)
 #define S3C2400_GPF5_nCTS0  (0x02 << 10)
 #define S3C2400_GPF5_nXBREQ (0x03 << 10)
 
-#define S3C2410_GPF6        S3C2410_GPIONO(S3C2410_GPIO_BANKF, 6)
-#define S3C2410_GPF6_INP    (0x00 << 12)
-#define S3C2410_GPF6_OUTP   (0x01 << 12)
 #define S3C2410_GPF6_EINT6  (0x02 << 12)
 #define S3C2400_GPF6_CLKOUT (0x02 << 12)
 
-#define S3C2410_GPF7        S3C2410_GPIONO(S3C2410_GPIO_BANKF, 7)
-#define S3C2410_GPF7_INP    (0x00 << 14)
-#define S3C2410_GPF7_OUTP   (0x01 << 14)
 #define S3C2410_GPF7_EINT7  (0x02 << 14)
 
 #define S3C2410_GPF_PUPDIS(x)  (1<<(x))
 #define S3C2400_GPGDAT    S3C2410_GPIOREG(0x48)
 #define S3C2400_GPGUP     S3C2410_GPIOREG(0x4C)
 
-#define S3C2410_GPG0          S3C2410_GPIONO(S3C2410_GPIO_BANKG, 0)
-#define S3C2410_GPG0_INP      (0x00 << 0)
-#define S3C2410_GPG0_OUTP     (0x01 << 0)
 #define S3C2410_GPG0_EINT8    (0x02 << 0)
 #define S3C2400_GPG0_I2SLRCK  (0x02 << 0)
 
-#define S3C2410_GPG1          S3C2410_GPIONO(S3C2410_GPIO_BANKG, 1)
-#define S3C2410_GPG1_INP      (0x00 << 2)
-#define S3C2410_GPG1_OUTP     (0x01 << 2)
 #define S3C2410_GPG1_EINT9    (0x02 << 2)
 #define S3C2400_GPG1_I2SSCLK  (0x02 << 2)
 
-#define S3C2410_GPG2          S3C2410_GPIONO(S3C2410_GPIO_BANKG, 2)
-#define S3C2410_GPG2_INP      (0x00 << 4)
-#define S3C2410_GPG2_OUTP     (0x01 << 4)
 #define S3C2410_GPG2_EINT10   (0x02 << 4)
 #define S3C2410_GPG2_nSS0     (0x03 << 4)
 #define S3C2400_GPG2_CDCLK    (0x02 << 4)
 
-#define S3C2410_GPG3          S3C2410_GPIONO(S3C2410_GPIO_BANKG, 3)
-#define S3C2410_GPG3_INP      (0x00 << 6)
-#define S3C2410_GPG3_OUTP     (0x01 << 6)
 #define S3C2410_GPG3_EINT11   (0x02 << 6)
 #define S3C2410_GPG3_nSS1     (0x03 << 6)
 #define S3C2400_GPG3_I2SSDO   (0x02 << 6)
 #define S3C2400_GPG3_I2SSDI   (0x03 << 6)
 
-#define S3C2410_GPG4          S3C2410_GPIONO(S3C2410_GPIO_BANKG, 4)
-#define S3C2410_GPG4_INP      (0x00 << 8)
-#define S3C2410_GPG4_OUTP     (0x01 << 8)
 #define S3C2410_GPG4_EINT12   (0x02 << 8)
 #define S3C2400_GPG4_MMCCLK   (0x02 << 8)
 #define S3C2400_GPG4_I2SSDI   (0x03 << 8)
 #define S3C2410_GPG4_LCDPWREN (0x03 << 8)
 #define S3C2443_GPG4_LCDPWRDN (0x03 << 8)
 
-#define S3C2410_GPG5          S3C2410_GPIONO(S3C2410_GPIO_BANKG, 5)
-#define S3C2410_GPG5_INP      (0x00 << 10)
-#define S3C2410_GPG5_OUTP     (0x01 << 10)
 #define S3C2410_GPG5_EINT13   (0x02 << 10)
 #define S3C2400_GPG5_MMCCMD   (0x02 << 10)
 #define S3C2400_GPG5_IICSDA   (0x03 << 10)
 #define S3C2410_GPG5_SPIMISO1 (0x03 << 10)     /* not s3c2443 */
 
-#define S3C2410_GPG6          S3C2410_GPIONO(S3C2410_GPIO_BANKG, 6)
-#define S3C2410_GPG6_INP      (0x00 << 12)
-#define S3C2410_GPG6_OUTP     (0x01 << 12)
 #define S3C2410_GPG6_EINT14   (0x02 << 12)
 #define S3C2400_GPG6_MMCDAT   (0x02 << 12)
 #define S3C2400_GPG6_IICSCL   (0x03 << 12)
 #define S3C2410_GPG6_SPIMOSI1 (0x03 << 12)
 
-#define S3C2410_GPG7          S3C2410_GPIONO(S3C2410_GPIO_BANKG, 7)
-#define S3C2410_GPG7_INP      (0x00 << 14)
-#define S3C2410_GPG7_OUTP     (0x01 << 14)
 #define S3C2410_GPG7_EINT15   (0x02 << 14)
 #define S3C2410_GPG7_SPICLK1  (0x03 << 14)
 #define S3C2400_GPG7_SPIMISO  (0x02 << 14)
 #define S3C2400_GPG7_IICSDA   (0x03 << 14)
 
-#define S3C2410_GPG8          S3C2410_GPIONO(S3C2410_GPIO_BANKG, 8)
-#define S3C2410_GPG8_INP      (0x00 << 16)
-#define S3C2410_GPG8_OUTP     (0x01 << 16)
 #define S3C2410_GPG8_EINT16   (0x02 << 16)
 #define S3C2400_GPG8_SPIMOSI  (0x02 << 16)
 #define S3C2400_GPG8_IICSCL   (0x03 << 16)
 
-#define S3C2410_GPG9          S3C2410_GPIONO(S3C2410_GPIO_BANKG, 9)
-#define S3C2410_GPG9_INP      (0x00 << 18)
-#define S3C2410_GPG9_OUTP     (0x01 << 18)
 #define S3C2410_GPG9_EINT17   (0x02 << 18)
 #define S3C2400_GPG9_SPICLK   (0x02 << 18)
 #define S3C2400_GPG9_MMCCLK   (0x03 << 18)
 
-#define S3C2410_GPG10         S3C2410_GPIONO(S3C2410_GPIO_BANKG, 10)
-#define S3C2410_GPG10_INP     (0x00 << 20)
-#define S3C2410_GPG10_OUTP    (0x01 << 20)
 #define S3C2410_GPG10_EINT18  (0x02 << 20)
 
-#define S3C2410_GPG11         S3C2410_GPIONO(S3C2410_GPIO_BANKG, 11)
-#define S3C2410_GPG11_INP     (0x00 << 22)
-#define S3C2410_GPG11_OUTP    (0x01 << 22)
 #define S3C2410_GPG11_EINT19  (0x02 << 22)
 #define S3C2410_GPG11_TCLK1   (0x03 << 22)
 #define S3C2443_GPG11_CF_nIREQ (0x03 << 22)
 
-#define S3C2410_GPG12         S3C2410_GPIONO(S3C2410_GPIO_BANKG, 12)
-#define S3C2410_GPG12_INP     (0x00 << 24)
-#define S3C2410_GPG12_OUTP    (0x01 << 24)
 #define S3C2410_GPG12_EINT20  (0x02 << 24)
 #define S3C2410_GPG12_XMON    (0x03 << 24)
 #define S3C2442_GPG12_nSPICS0 (0x03 << 24)
 #define S3C2443_GPG12_nINPACK (0x03 << 24)
 
-#define S3C2410_GPG13         S3C2410_GPIONO(S3C2410_GPIO_BANKG, 13)
-#define S3C2410_GPG13_INP     (0x00 << 26)
-#define S3C2410_GPG13_OUTP    (0x01 << 26)
 #define S3C2410_GPG13_EINT21  (0x02 << 26)
 #define S3C2410_GPG13_nXPON   (0x03 << 26)
 #define S3C2443_GPG13_CF_nREG (0x03 << 26)
 
-#define S3C2410_GPG14         S3C2410_GPIONO(S3C2410_GPIO_BANKG, 14)
-#define S3C2410_GPG14_INP     (0x00 << 28)
-#define S3C2410_GPG14_OUTP    (0x01 << 28)
 #define S3C2410_GPG14_EINT22  (0x02 << 28)
 #define S3C2410_GPG14_YMON    (0x03 << 28)
 #define S3C2443_GPG14_CF_RESET (0x03 << 28)
 
-#define S3C2410_GPG15         S3C2410_GPIONO(S3C2410_GPIO_BANKG, 15)
-#define S3C2410_GPG15_INP     (0x00 << 30)
-#define S3C2410_GPG15_OUTP    (0x01 << 30)
 #define S3C2410_GPG15_EINT23  (0x02 << 30)
 #define S3C2410_GPG15_nYPON   (0x03 << 30)
 #define S3C2443_GPG15_CF_PWR  (0x03 << 30)
 #define S3C2410_GPHDAT    S3C2410_GPIOREG(0x74)
 #define S3C2410_GPHUP     S3C2410_GPIOREG(0x78)
 
-#define S3C2410_GPH0        S3C2410_GPIONO(S3C2410_GPIO_BANKH, 0)
-#define S3C2410_GPH0_INP    (0x00 << 0)
-#define S3C2410_GPH0_OUTP   (0x01 << 0)
 #define S3C2410_GPH0_nCTS0  (0x02 << 0)
 
-#define S3C2410_GPH1        S3C2410_GPIONO(S3C2410_GPIO_BANKH, 1)
-#define S3C2410_GPH1_INP    (0x00 << 2)
-#define S3C2410_GPH1_OUTP   (0x01 << 2)
 #define S3C2410_GPH1_nRTS0  (0x02 << 2)
 
-#define S3C2410_GPH2        S3C2410_GPIONO(S3C2410_GPIO_BANKH, 2)
-#define S3C2410_GPH2_INP    (0x00 << 4)
-#define S3C2410_GPH2_OUTP   (0x01 << 4)
 #define S3C2410_GPH2_TXD0   (0x02 << 4)
 
-#define S3C2410_GPH3        S3C2410_GPIONO(S3C2410_GPIO_BANKH, 3)
-#define S3C2410_GPH3_INP    (0x00 << 6)
-#define S3C2410_GPH3_OUTP   (0x01 << 6)
 #define S3C2410_GPH3_RXD0   (0x02 << 6)
 
-#define S3C2410_GPH4        S3C2410_GPIONO(S3C2410_GPIO_BANKH, 4)
-#define S3C2410_GPH4_INP    (0x00 << 8)
-#define S3C2410_GPH4_OUTP   (0x01 << 8)
 #define S3C2410_GPH4_TXD1   (0x02 << 8)
 
-#define S3C2410_GPH5        S3C2410_GPIONO(S3C2410_GPIO_BANKH, 5)
-#define S3C2410_GPH5_INP    (0x00 << 10)
-#define S3C2410_GPH5_OUTP   (0x01 << 10)
 #define S3C2410_GPH5_RXD1   (0x02 << 10)
 
-#define S3C2410_GPH6        S3C2410_GPIONO(S3C2410_GPIO_BANKH, 6)
-#define S3C2410_GPH6_INP    (0x00 << 12)
-#define S3C2410_GPH6_OUTP   (0x01 << 12)
 #define S3C2410_GPH6_TXD2   (0x02 << 12)
 #define S3C2410_GPH6_nRTS1  (0x03 << 12)
 
-#define S3C2410_GPH7        S3C2410_GPIONO(S3C2410_GPIO_BANKH, 7)
-#define S3C2410_GPH7_INP    (0x00 << 14)
-#define S3C2410_GPH7_OUTP   (0x01 << 14)
 #define S3C2410_GPH7_RXD2   (0x02 << 14)
 #define S3C2410_GPH7_nCTS1  (0x03 << 14)
 
-#define S3C2410_GPH8        S3C2410_GPIONO(S3C2410_GPIO_BANKH, 8)
-#define S3C2410_GPH8_INP    (0x00 << 16)
-#define S3C2410_GPH8_OUTP   (0x01 << 16)
 #define S3C2410_GPH8_UCLK   (0x02 << 16)
 
-#define S3C2410_GPH9          S3C2410_GPIONO(S3C2410_GPIO_BANKH, 9)
-#define S3C2410_GPH9_INP      (0x00 << 18)
-#define S3C2410_GPH9_OUTP     (0x01 << 18)
 #define S3C2410_GPH9_CLKOUT0  (0x02 << 18)
 #define S3C2442_GPH9_nSPICS0  (0x03 << 18)
 
-#define S3C2410_GPH10         S3C2410_GPIONO(S3C2410_GPIO_BANKH, 10)
-#define S3C2410_GPH10_INP     (0x00 << 20)
-#define S3C2410_GPH10_OUTP    (0x01 << 20)
 #define S3C2410_GPH10_CLKOUT1 (0x02 << 20)
 
 /* The S3C2412 and S3C2413 move the GPJ register set to after
index b8687f71c30479c90400e2a36a4c51086c591007..6faadcee7729bd525553bad354738fb66d87d94b 100644 (file)
 */
 
 #include <mach/hardware.h>
-#include <linux/io.h>
-
-#include <plat/regs-watchdog.h>
-#include <mach/regs-clock.h>
-
-#include <linux/clk.h>
-#include <linux/err.h>
+#include <plat/watchdog-reset.h>
 
 extern void (*s3c24xx_reset_hook)(void);
 
 static void
 arch_reset(char mode, const char *cmd)
 {
-       struct clk *wdtclk;
-
        if (mode == 's') {
                cpu_reset(0);
        }
@@ -33,31 +25,7 @@ arch_reset(char mode, const char *cmd)
        if (s3c24xx_reset_hook)
                s3c24xx_reset_hook();
 
-       printk("arch_reset: attempting watchdog reset\n");
-
-       __raw_writel(0, S3C2410_WTCON);   /* disable watchdog, to be safe  */
-
-       wdtclk = clk_get(NULL, "watchdog");
-       if (!IS_ERR(wdtclk)) {
-               clk_enable(wdtclk);
-       } else
-               printk(KERN_WARNING "%s: warning: cannot get watchdog clock\n", __func__);
-
-       /* put initial values into count and data */
-       __raw_writel(0x80, S3C2410_WTCNT);
-       __raw_writel(0x80, S3C2410_WTDAT);
-
-       /* set the watchdog to go and reset... */
-       __raw_writel(S3C2410_WTCON_ENABLE|S3C2410_WTCON_DIV16|S3C2410_WTCON_RSTEN |
-                    S3C2410_WTCON_PRESCALE(0x20), S3C2410_WTCON);
-
-       /* wait for reset to assert... */
-       mdelay(500);
-
-       printk(KERN_ERR "Watchdog reset failed to assert reset\n");
-
-       /* delay to allow the serial port to show the message */
-       mdelay(50);
+       arch_wdt_reset();
 
        /* we'll take a jump through zero as a poor second */
        cpu_reset(0);
index 6d6995afeb439013d19833cc1f360c986a270b32..06a84adfb13fedf936c73e8297ad34715d3df02b 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/proc_fs.h>
@@ -224,8 +225,8 @@ static void amlm5900_init_pm(void)
        } else {
                enable_irq_wake(IRQ_EINT9);
                /* configure the suspend/resume status pin */
-               s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_OUTP);
-               s3c2410_gpio_pullup(S3C2410_GPF2, 0);
+               s3c2410_gpio_cfgpin(S3C2410_GPF(2), S3C2410_GPIO_OUTPUT);
+               s3c2410_gpio_pullup(S3C2410_GPF(2), 0);
        }
 }
 static void __init amlm5900_init(void)
index 8637dea5e1500a11ac6899bca74769d6db008664..ce3baba2cd7fddcbd273d62854de18b1f909c150 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
 #include <linux/sysdev.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
@@ -212,15 +213,15 @@ static struct s3c2410_uartcfg bast_uartcfgs[] __initdata = {
 static int bast_pm_suspend(struct sys_device *sd, pm_message_t state)
 {
        /* ensure that an nRESET is not generated on resume. */
-       s3c2410_gpio_setpin(S3C2410_GPA21, 1);
-       s3c2410_gpio_cfgpin(S3C2410_GPA21, S3C2410_GPA21_OUT);
+       s3c2410_gpio_setpin(S3C2410_GPA(21), 1);
+       s3c2410_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPIO_OUTPUT);
 
        return 0;
 }
 
 static int bast_pm_resume(struct sys_device *sd)
 {
-       s3c2410_gpio_cfgpin(S3C2410_GPA21, S3C2410_GPA21_nRSTOUT);
+       s3c2410_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPA21_nRSTOUT);
        return 0;
 }
 
@@ -591,8 +592,6 @@ static void __init bast_map_io(void)
        s3c24xx_init_io(bast_iodesc, ARRAY_SIZE(bast_iodesc));
        s3c24xx_init_clocks(0);
        s3c24xx_init_uarts(bast_uartcfgs, ARRAY_SIZE(bast_uartcfgs));
-
-       usb_simtec_init();
 }
 
 static void __init bast_init(void)
@@ -607,6 +606,7 @@ static void __init bast_init(void)
        i2c_register_board_info(0, bast_i2c_devs,
                                ARRAY_SIZE(bast_i2c_devs));
 
+       usb_simtec_init();
        nor_simtec_init();
 }
 
index 7a7c4da4c25660f29f5be02c88b86ff7e7241216..d9cd5ddecf4a7fda05bbd275828647982adfcdd5 100644 (file)
@@ -127,7 +127,7 @@ static void h1940_udc_pullup(enum s3c2410_udc_cmd_e cmd)
 
 static struct s3c2410_udc_mach_info h1940_udc_cfg __initdata = {
        .udc_command            = h1940_udc_pullup,
-       .vbus_pin               = S3C2410_GPG5,
+       .vbus_pin               = S3C2410_GPG(5),
        .vbus_pin_inverted      = 1,
 };
 
index 2b83f87077100b310f8a9502663c75451bacaca0..0f6ed61af41513c754f6237b590c8962dc57250c 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <linux/gpio_keys.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
@@ -85,10 +86,10 @@ static void n30_udc_pullup(enum s3c2410_udc_cmd_e cmd)
 {
        switch (cmd) {
        case S3C2410_UDC_P_ENABLE :
-               s3c2410_gpio_setpin(S3C2410_GPB3, 1);
+               s3c2410_gpio_setpin(S3C2410_GPB(3), 1);
                break;
        case S3C2410_UDC_P_DISABLE :
-               s3c2410_gpio_setpin(S3C2410_GPB3, 0);
+               s3c2410_gpio_setpin(S3C2410_GPB(3), 0);
                break;
        case S3C2410_UDC_P_RESET :
                break;
@@ -99,55 +100,55 @@ static void n30_udc_pullup(enum s3c2410_udc_cmd_e cmd)
 
 static struct s3c2410_udc_mach_info n30_udc_cfg __initdata = {
        .udc_command            = n30_udc_pullup,
-       .vbus_pin               = S3C2410_GPG1,
+       .vbus_pin               = S3C2410_GPG(1),
        .vbus_pin_inverted      = 0,
 };
 
 static struct gpio_keys_button n30_buttons[] = {
        {
-               .gpio           = S3C2410_GPF0,
+               .gpio           = S3C2410_GPF(0),
                .code           = KEY_POWER,
                .desc           = "Power",
                .active_low     = 0,
        },
        {
-               .gpio           = S3C2410_GPG9,
+               .gpio           = S3C2410_GPG(9),
                .code           = KEY_UP,
                .desc           = "Thumbwheel Up",
                .active_low     = 0,
        },
        {
-               .gpio           = S3C2410_GPG8,
+               .gpio           = S3C2410_GPG(8),
                .code           = KEY_DOWN,
                .desc           = "Thumbwheel Down",
                .active_low     = 0,
        },
        {
-               .gpio           = S3C2410_GPG7,
+               .gpio           = S3C2410_GPG(7),
                .code           = KEY_ENTER,
                .desc           = "Thumbwheel Press",
                .active_low     = 0,
        },
        {
-               .gpio           = S3C2410_GPF7,
+               .gpio           = S3C2410_GPF(7),
                .code           = KEY_HOMEPAGE,
                .desc           = "Home",
                .active_low     = 0,
        },
        {
-               .gpio           = S3C2410_GPF6,
+               .gpio           = S3C2410_GPF(6),
                .code           = KEY_CALENDAR,
                .desc           = "Calendar",
                .active_low     = 0,
        },
        {
-               .gpio           = S3C2410_GPF5,
+               .gpio           = S3C2410_GPF(5),
                .code           = KEY_ADDRESSBOOK,
                .desc           = "Contacts",
                .active_low     = 0,
        },
        {
-               .gpio           = S3C2410_GPF4,
+               .gpio           = S3C2410_GPF(4),
                .code           = KEY_MAIL,
                .desc           = "Mail",
                .active_low     = 0,
@@ -169,73 +170,73 @@ static struct platform_device n30_button_device = {
 
 static struct gpio_keys_button n35_buttons[] = {
        {
-               .gpio           = S3C2410_GPF0,
+               .gpio           = S3C2410_GPF(0),
                .code           = KEY_POWER,
                .desc           = "Power",
                .active_low     = 0,
        },
        {
-               .gpio           = S3C2410_GPG9,
+               .gpio           = S3C2410_GPG(9),
                .code           = KEY_UP,
                .desc           = "Joystick Up",
                .active_low     = 0,
        },
        {
-               .gpio           = S3C2410_GPG8,
+               .gpio           = S3C2410_GPG(8),
                .code           = KEY_DOWN,
                .desc           = "Joystick Down",
                .active_low     = 0,
        },
        {
-               .gpio           = S3C2410_GPG6,
+               .gpio           = S3C2410_GPG(6),
                .code           = KEY_DOWN,
                .desc           = "Joystick Left",
                .active_low     = 0,
        },
        {
-               .gpio           = S3C2410_GPG5,
+               .gpio           = S3C2410_GPG(5),
                .code           = KEY_DOWN,
                .desc           = "Joystick Right",
                .active_low     = 0,
        },
        {
-               .gpio           = S3C2410_GPG7,
+               .gpio           = S3C2410_GPG(7),
                .code           = KEY_ENTER,
                .desc           = "Joystick Press",
                .active_low     = 0,
        },
        {
-               .gpio           = S3C2410_GPF7,
+               .gpio           = S3C2410_GPF(7),
                .code           = KEY_HOMEPAGE,
                .desc           = "Home",
                .active_low     = 0,
        },
        {
-               .gpio           = S3C2410_GPF6,
+               .gpio           = S3C2410_GPF(6),
                .code           = KEY_CALENDAR,
                .desc           = "Calendar",
                .active_low     = 0,
        },
        {
-               .gpio           = S3C2410_GPF5,
+               .gpio           = S3C2410_GPF(5),
                .code           = KEY_ADDRESSBOOK,
                .desc           = "Contacts",
                .active_low     = 0,
        },
        {
-               .gpio           = S3C2410_GPF4,
+               .gpio           = S3C2410_GPF(4),
                .code           = KEY_MAIL,
                .desc           = "Mail",
                .active_low     = 0,
        },
        {
-               .gpio           = S3C2410_GPF3,
+               .gpio           = S3C2410_GPF(3),
                .code           = SW_RADIO,
                .desc           = "GPS Antenna",
                .active_low     = 0,
        },
        {
-               .gpio           = S3C2410_GPG2,
+               .gpio           = S3C2410_GPG(2),
                .code           = SW_HEADPHONE_INSERT,
                .desc           = "Headphone",
                .active_low     = 0,
@@ -259,7 +260,7 @@ static struct platform_device n35_button_device = {
 /* This is the bluetooth LED on the device. */
 static struct s3c24xx_led_platdata n30_blue_led_pdata = {
        .name           = "blue_led",
-       .gpio           = S3C2410_GPG6,
+       .gpio           = S3C2410_GPG(6),
        .def_trigger    = "",
 };
 
@@ -270,7 +271,7 @@ static struct s3c24xx_led_platdata n30_blue_led_pdata = {
 static struct s3c24xx_led_platdata n30_warning_led_pdata = {
        .name           = "warning_led",
        .flags          = S3C24XX_LEDF_ACTLOW,
-       .gpio           = S3C2410_GPD9,
+       .gpio           = S3C2410_GPD(9),
        .def_trigger    = "",
 };
 
index 9f1ba9b63f702eefaa32ab7ebd321be1709af8b4..2cc9849eb448696b26b83008b8b236f2d6c9eec7 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
 #include <linux/sysdev.h>
 #include <linux/platform_device.h>
 #include <linux/serial_core.h>
@@ -198,7 +199,7 @@ static struct platform_device qt2410_cs89x0 = {
 /* LED */
 
 static struct s3c24xx_led_platdata qt2410_pdata_led = {
-       .gpio           = S3C2410_GPB0,
+       .gpio           = S3C2410_GPB(0),
        .flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
        .name           = "led",
        .def_trigger    = "timer",
@@ -218,18 +219,18 @@ static void spi_gpio_cs(struct s3c2410_spigpio_info *spi, int cs)
 {
        switch (cs) {
        case BITBANG_CS_ACTIVE:
-               s3c2410_gpio_setpin(S3C2410_GPB5, 0);
+               s3c2410_gpio_setpin(S3C2410_GPB(5), 0);
                break;
        case BITBANG_CS_INACTIVE:
-               s3c2410_gpio_setpin(S3C2410_GPB5, 1);
+               s3c2410_gpio_setpin(S3C2410_GPB(5), 1);
                break;
        }
 }
 
 static struct s3c2410_spigpio_info spi_gpio_cfg = {
-       .pin_clk        = S3C2410_GPG7,
-       .pin_mosi       = S3C2410_GPG6,
-       .pin_miso       = S3C2410_GPG5,
+       .pin_clk        = S3C2410_GPG(7),
+       .pin_mosi       = S3C2410_GPG(6),
+       .pin_miso       = S3C2410_GPG(5),
        .chip_select    = &spi_gpio_cs,
 };
 
@@ -346,13 +347,13 @@ static void __init qt2410_machine_init(void)
        }
        s3c24xx_fb_set_platdata(&qt2410_fb_info);
 
-       s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPIO_OUTPUT);
-       s3c2410_gpio_setpin(S3C2410_GPB0, 1);
+       s3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPIO_OUTPUT);
+       s3c2410_gpio_setpin(S3C2410_GPB(0), 1);
 
        s3c24xx_udc_set_platdata(&qt2410_udc_cfg);
        s3c_i2c0_set_platdata(NULL);
 
-       s3c2410_gpio_cfgpin(S3C2410_GPB5, S3C2410_GPIO_OUTPUT);
+       s3c2410_gpio_cfgpin(S3C2410_GPB(5), S3C2410_GPIO_OUTPUT);
 
        platform_add_devices(qt2410_devices, ARRAY_SIZE(qt2410_devices));
        s3c_pm_init();
index 61a1ea9c5c5cd46bf58ed1d78a3deda89003b0d3..1628cc773a2c89f9a04657503681d588bd4547d7 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
 #include <linux/dm9000.h>
 #include <linux/i2c.h>
 
@@ -277,19 +278,19 @@ static struct platform_device vr1000_dm9k1 = {
 
 static struct s3c24xx_led_platdata vr1000_led1_pdata = {
        .name           = "led1",
-       .gpio           = S3C2410_GPB0,
+       .gpio           = S3C2410_GPB(0),
        .def_trigger    = "",
 };
 
 static struct s3c24xx_led_platdata vr1000_led2_pdata = {
        .name           = "led2",
-       .gpio           = S3C2410_GPB1,
+       .gpio           = S3C2410_GPB(1),
        .def_trigger    = "",
 };
 
 static struct s3c24xx_led_platdata vr1000_led3_pdata = {
        .name           = "led3",
-       .gpio           = S3C2410_GPB2,
+       .gpio           = S3C2410_GPB(2),
        .def_trigger    = "",
 };
 
@@ -355,8 +356,8 @@ static struct clk *vr1000_clocks[] __initdata = {
 
 static void vr1000_power_off(void)
 {
-       s3c2410_gpio_cfgpin(S3C2410_GPB9, S3C2410_GPB9_OUTP);
-       s3c2410_gpio_setpin(S3C2410_GPB9, 1);
+       s3c2410_gpio_cfgpin(S3C2410_GPB(9), S3C2410_GPIO_OUTPUT);
+       s3c2410_gpio_setpin(S3C2410_GPB(9), 1);
 }
 
 static void __init vr1000_map_io(void)
index 87fc481d92d4949f0a22a0f10d49a8f1051c2b36..143e08a599d4097e0e47ea243ed7d34f3e2cf085 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/errno.h>
 #include <linux/time.h>
 #include <linux/sysdev.h>
+#include <linux/gpio.h>
 #include <linux/io.h>
 
 #include <mach/hardware.h>
@@ -76,7 +77,7 @@ static void s3c2410_pm_prepare(void)
        }
 
        if ( machine_is_aml_m5900() )
-               s3c2410_gpio_setpin(S3C2410_GPF2, 1);
+               s3c2410_gpio_setpin(S3C2410_GPF(2), 1);
 
 }
 
@@ -91,7 +92,7 @@ static int s3c2410_pm_resume(struct sys_device *dev)
        __raw_writel(tmp, S3C2410_GSTATUS2);
 
        if ( machine_is_aml_m5900() )
-               s3c2410_gpio_setpin(S3C2410_GPF2, 0);
+               s3c2410_gpio_setpin(S3C2410_GPF(2), 0);
 
        return 0;
 }
index 8331e8d97e20511e8926225df9fa1c5e7439718b..6cd9377ddb826d3e4758ca8ce8c0cd7892f7974c 100644 (file)
 #include <linux/types.h>
 #include <linux/interrupt.h>
 #include <linux/list.h>
+#include <linux/gpio.h>
 #include <linux/timer.h>
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/gpio.h>
 #include <linux/io.h>
 
 #include <asm/mach/arch.h>
@@ -29,7 +31,6 @@
 
 #include <mach/bast-map.h>
 #include <mach/bast-irq.h>
-#include <mach/regs-gpio.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
@@ -53,9 +54,9 @@ usb_simtec_powercontrol(int port, int to)
        power_state[port] = to;
 
        if (power_state[0] && power_state[1])
-               s3c2410_gpio_setpin(S3C2410_GPB4, 0);
+               gpio_set_value(S3C2410_GPB(4), 0);
        else
-               s3c2410_gpio_setpin(S3C2410_GPB4, 1);
+               gpio_set_value(S3C2410_GPB(4), 1);
 }
 
 static irqreturn_t
@@ -63,7 +64,7 @@ usb_simtec_ocirq(int irq, void *pw)
 {
        struct s3c2410_hcd_info *info = pw;
 
-       if (s3c2410_gpio_getpin(S3C2410_GPG10) == 0) {
+       if (gpio_get_value(S3C2410_GPG(10)) == 0) {
                pr_debug("usb_simtec: over-current irq (oc detected)\n");
                s3c2410_usb_report_oc(info, 3);
        } else {
@@ -106,10 +107,27 @@ static struct s3c2410_hcd_info usb_simtec_info = {
 
 int usb_simtec_init(void)
 {
+       int ret;
+
        printk("USB Power Control, (c) 2004 Simtec Electronics\n");
-       s3c_device_usb.dev.platform_data = &usb_simtec_info;
 
-       s3c2410_gpio_cfgpin(S3C2410_GPB4, S3C2410_GPB4_OUTP);
-       s3c2410_gpio_setpin(S3C2410_GPB4, 1);
+       ret = gpio_request(S3C2410_GPB(4), "USB power control");
+       if (ret < 0) {
+               pr_err("%s: failed to get GPB4\n", __func__);
+               return ret;
+       }
+
+       ret = gpio_request(S3C2410_GPG(10), "USB overcurrent");
+       if (ret < 0) {
+               pr_err("%s: failed to get GPG10\n", __func__);
+               gpio_free(S3C2410_GPB(4));
+               return ret;
+       }
+
+       /* turn power on */
+       gpio_direction_output(S3C2410_GPB(4), 1);
+       gpio_direction_input(S3C2410_GPG(10));
+
+       s3c_device_usb.dev.platform_data = &usb_simtec_info;
        return 0;
 }
index ca99564ae4b56c917a73a48dd357244c2d3fe654..63586ffd0ae722228f97187bc899bc3a3711e7eb 100644 (file)
@@ -38,6 +38,7 @@ menu "S3C2412 Machines"
 config MACH_JIVE
        bool "Logitech Jive"
        select CPU_S3C2412
+       select S3C_DEV_USB_HOST
        help
          Say Y here if you are using the Logitech Jive.
 
@@ -50,6 +51,7 @@ config MACH_SMDK2413
        select CPU_S3C2412
        select MACH_S3C2413
        select MACH_SMDK
+       select S3C_DEV_USB_HOST
        help
          Say Y here if you are using an SMDK2413
 
@@ -72,6 +74,7 @@ config MACH_SMDK2412
 config MACH_VSTMS
        bool "VMSTMS"
        select CPU_S3C2412
+       select S3C_DEV_USB_HOST
        help
          Say Y here if you are using an VSTMS board
 
index 9e3478506c6f67ef1dd307971b2d7786b32f1104..f8d16fc10bc6ad4ba4c5bc6867bfdc9b93a814ce 100644 (file)
 
 #include <mach/dma.h>
 
-#include <plat/dma.h>
+#include <plat/dma-plat.h>
 #include <plat/cpu.h>
 
 #include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
 #include <plat/regs-ac97.h>
+#include <plat/regs-dma.h>
 #include <mach/regs-mem.h>
 #include <mach/regs-lcd.h>
 #include <mach/regs-sdi.h>
index 8f0d37d43b436f0440d0d6a405a4e5abda3414b9..8df506eac9037aa25f15624e84d96c2644f772f2 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
 #include <linux/sysdev.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
@@ -356,8 +357,8 @@ static void jive_lcm_reset(unsigned int set)
 {
        printk(KERN_DEBUG "%s(%d)\n", __func__, set);
 
-       s3c2410_gpio_setpin(S3C2410_GPG13, set);
-       s3c2410_gpio_cfgpin(S3C2410_GPG13, S3C2410_GPIO_OUTPUT);
+       s3c2410_gpio_setpin(S3C2410_GPG(13), set);
+       s3c2410_gpio_cfgpin(S3C2410_GPG(13), S3C2410_GPIO_OUTPUT);
 }
 
 #undef LCD_UPPER_MARGIN
@@ -390,13 +391,13 @@ static struct ili9320_platdata jive_lcm_config = {
 
 static void jive_lcd_spi_chipselect(struct s3c2410_spigpio_info *spi, int cs)
 {
-       s3c2410_gpio_setpin(S3C2410_GPB7, cs ? 0 : 1);
+       s3c2410_gpio_setpin(S3C2410_GPB(7), cs ? 0 : 1);
 }
 
 static struct s3c2410_spigpio_info jive_lcd_spi = {
        .bus_num        = 1,
-       .pin_clk        = S3C2410_GPG8,
-       .pin_mosi       = S3C2410_GPB8,
+       .pin_clk        = S3C2410_GPG(8),
+       .pin_mosi       = S3C2410_GPB(8),
        .num_chipselect = 1,
        .chip_select    = jive_lcd_spi_chipselect,
 };
@@ -412,13 +413,13 @@ static struct platform_device jive_device_lcdspi = {
 
 static void jive_wm8750_chipselect(struct s3c2410_spigpio_info *spi, int cs)
 {
-       s3c2410_gpio_setpin(S3C2410_GPH10, cs ? 0 : 1);
+       s3c2410_gpio_setpin(S3C2410_GPH(10), cs ? 0 : 1);
 }
 
 static struct s3c2410_spigpio_info jive_wm8750_spi = {
        .bus_num        = 2,
-       .pin_clk        = S3C2410_GPB4,
-       .pin_mosi       = S3C2410_GPB9,
+       .pin_clk        = S3C2410_GPB(4),
+       .pin_mosi       = S3C2410_GPB(9),
        .num_chipselect = 1,
        .chip_select    = jive_wm8750_chipselect,
 };
@@ -479,7 +480,7 @@ static struct platform_device *jive_devices[] __initdata = {
 };
 
 static struct s3c2410_udc_mach_info jive_udc_cfg __initdata = {
-       .vbus_pin       = S3C2410_GPG1,         /* detect is on GPG1 */
+       .vbus_pin       = S3C2410_GPG(1),               /* detect is on GPG1 */
 };
 
 /* Jive power management device */
@@ -529,8 +530,8 @@ static void jive_power_off(void)
 {
        printk(KERN_INFO "powering system down...\n");
 
-       s3c2410_gpio_setpin(S3C2410_GPC5, 1);
-       s3c2410_gpio_cfgpin(S3C2410_GPC5, S3C2410_GPIO_OUTPUT);
+       s3c2410_gpio_setpin(S3C2410_GPC(5), 1);
+       s3c2410_gpio_cfgpin(S3C2410_GPC(5), S3C2410_GPIO_OUTPUT);
 }
 
 static void __init jive_machine_init(void)
@@ -634,22 +635,22 @@ static void __init jive_machine_init(void)
 
        /* initialise the spi */
 
-       s3c2410_gpio_setpin(S3C2410_GPG13, 0);
-       s3c2410_gpio_cfgpin(S3C2410_GPG13, S3C2410_GPIO_OUTPUT);
+       s3c2410_gpio_setpin(S3C2410_GPG(13), 0);
+       s3c2410_gpio_cfgpin(S3C2410_GPG(13), S3C2410_GPIO_OUTPUT);
 
-       s3c2410_gpio_setpin(S3C2410_GPB7, 1);
-       s3c2410_gpio_cfgpin(S3C2410_GPB7, S3C2410_GPIO_OUTPUT);
+       s3c2410_gpio_setpin(S3C2410_GPB(7), 1);
+       s3c2410_gpio_cfgpin(S3C2410_GPB(7), S3C2410_GPIO_OUTPUT);
 
-       s3c2410_gpio_setpin(S3C2410_GPB6, 0);
-       s3c2410_gpio_cfgpin(S3C2410_GPB6, S3C2410_GPIO_OUTPUT);
+       s3c2410_gpio_setpin(S3C2410_GPB(6), 0);
+       s3c2410_gpio_cfgpin(S3C2410_GPB(6), S3C2410_GPIO_OUTPUT);
 
-       s3c2410_gpio_setpin(S3C2410_GPG8, 1);
-       s3c2410_gpio_cfgpin(S3C2410_GPG8, S3C2410_GPIO_OUTPUT);
+       s3c2410_gpio_setpin(S3C2410_GPG(8), 1);
+       s3c2410_gpio_cfgpin(S3C2410_GPG(8), S3C2410_GPIO_OUTPUT);
 
        /* initialise the WM8750 spi */
 
-       s3c2410_gpio_setpin(S3C2410_GPH10, 1);
-       s3c2410_gpio_cfgpin(S3C2410_GPH10, S3C2410_GPIO_OUTPUT);
+       s3c2410_gpio_setpin(S3C2410_GPH(10), 1);
+       s3c2410_gpio_cfgpin(S3C2410_GPH(10), S3C2410_GPIO_OUTPUT);
 
        /* Turn off suspend on both USB ports, and switch the
         * selectable USB port to USB device mode. */
index eba66aa6bd209da9d3fbd920e110b9f09eaace16..9a5e43419722ed941c48c125b78ef7283f7c347f 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
@@ -84,10 +85,10 @@ static void smdk2413_udc_pullup(enum s3c2410_udc_cmd_e cmd)
        switch (cmd)
        {
                case S3C2410_UDC_P_ENABLE :
-                       s3c2410_gpio_setpin(S3C2410_GPF2, 1);
+                       s3c2410_gpio_setpin(S3C2410_GPF(2), 1);
                        break;
                case S3C2410_UDC_P_DISABLE :
-                       s3c2410_gpio_setpin(S3C2410_GPF2, 0);
+                       s3c2410_gpio_setpin(S3C2410_GPF(2), 0);
                        break;
                case S3C2410_UDC_P_RESET :
                        break;
@@ -134,8 +135,8 @@ static void __init smdk2413_machine_init(void)
 {      /* Turn off suspend on both USB ports, and switch the
         * selectable USB port to USB device mode. */
 
-       s3c2410_gpio_setpin(S3C2410_GPF2, 0);
-       s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPIO_OUTPUT);
+       s3c2410_gpio_setpin(S3C2410_GPF(2), 0);
+       s3c2410_gpio_cfgpin(S3C2410_GPF(2), S3C2410_GPIO_OUTPUT);
 
        s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
                              S3C2410_MISCCR_USBSUSPND0 |
index cde5ae9a43400e650f280641019a9bf4c3c7973e..5df73cbf2b40d17e8000601e3888cf34e6ef6650 100644 (file)
@@ -33,6 +33,7 @@ config MACH_ANUBIS
        select PM_SIMTEC if PM
        select HAVE_PATA_PLATFORM
        select S3C24XX_GPIO_EXTRA64
+       select S3C_DEV_USB_HOST
        help
          Say Y here if you are using the Simtec Electronics ANUBIS
          development system
@@ -43,6 +44,7 @@ config MACH_OSIRIS
        select S3C24XX_DCLK
        select PM_SIMTEC if PM
        select S3C24XX_GPIO_EXTRA128
+       select S3C_DEV_USB_HOST
        help
          Say Y here if you are using the Simtec IM2440D20 module, also
          known as the Osiris.
@@ -58,12 +60,14 @@ config ARCH_S3C2440
        bool "SMDK2440"
        select CPU_S3C2440
        select MACH_SMDK
+       select S3C_DEV_USB_HOST
        help
          Say Y here if you are using the SMDK2440.
 
 config MACH_NEXCODER_2440
        bool "NexVision NEXCODER 2440 Light Board"
        select CPU_S3C2440
+       select S3C_DEV_USB_HOST
        help
          Say Y here if you are using the Nex Vision NEXCODER 2440 Light Board
 
@@ -76,6 +80,7 @@ config SMDK2440_CPU2440
 config MACH_AT2440EVB
        bool "Avantech AT2440EVB development board"
        select CPU_S3C2440
+       select S3C_DEV_USB_HOST
        help
          Say Y here if you are using the AT2440EVB development board
 
index 69b6cf34df4728907e5d9dbba631c8d3fbb90a2d..e08e081430f04e4397da0d0fa501789fb9d9b8be 100644 (file)
 #include <linux/sysdev.h>
 #include <linux/serial_core.h>
 
+#include <mach/map.h>
 #include <mach/dma.h>
 
-#include <plat/dma.h>
+#include <plat/dma-plat.h>
 #include <plat/cpu.h>
 
 #include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
 #include <plat/regs-ac97.h>
+#include <plat/regs-dma.h>
 #include <mach/regs-mem.h>
 #include <mach/regs-lcd.h>
 #include <mach/regs-sdi.h>
index 9c6abf9fb540b9727aebfa96c84701953e64683c..68f3870991bfa1fd8e0dcbae9a3095a2e239c63b 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
 #include <linux/ata_platform.h>
@@ -468,7 +469,7 @@ static void __init anubis_map_io(void)
                anubis_nand_sets[0].nr_partitions = ARRAY_SIZE(anubis_default_nand_part_large);
        } else {
                /* ensure that the GPIO is setup */
-               s3c2410_gpio_setpin(S3C2410_GPA0, 1);
+               s3c2410_gpio_setpin(S3C2410_GPA(0), 1);
        }
 }
 
index 315c42e312784993a19c3be53604a0b646071b6e..dfc7010935da451c8615831515889582d5ad6217 100644 (file)
@@ -166,7 +166,7 @@ static struct platform_device at2440evb_device_eth = {
 };
 
 static struct s3c24xx_mci_pdata at2440evb_mci_pdata = {
-       .gpio_detect    = S3C2410_GPG10,
+       .gpio_detect    = S3C2410_GPG(10),
 };
 
 /* 7" LCD panel */
index 7aeaa972d7f5856bb46e9a6156190dd6f065c693..d43edede590e95c99b305488530be4594e2df5c3 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
 #include <linux/string.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
@@ -120,16 +121,16 @@ static struct platform_device *nexcoder_devices[] __initdata = {
 static void __init nexcoder_sensorboard_init(void)
 {
        // Initialize SCCB bus
-       s3c2410_gpio_setpin(S3C2410_GPE14, 1); // IICSCL
-       s3c2410_gpio_cfgpin(S3C2410_GPE14, S3C2410_GPE14_OUTP);
-       s3c2410_gpio_setpin(S3C2410_GPE15, 1); // IICSDA
-       s3c2410_gpio_cfgpin(S3C2410_GPE15, S3C2410_GPE15_OUTP);
+       s3c2410_gpio_setpin(S3C2410_GPE(14), 1); // IICSCL
+       s3c2410_gpio_cfgpin(S3C2410_GPE(14), S3C2410_GPIO_OUTPUT);
+       s3c2410_gpio_setpin(S3C2410_GPE(15), 1); // IICSDA
+       s3c2410_gpio_cfgpin(S3C2410_GPE(15), S3C2410_GPIO_OUTPUT);
 
        // Power up the sensor board
-       s3c2410_gpio_setpin(S3C2410_GPF1, 1);
-       s3c2410_gpio_cfgpin(S3C2410_GPF1, S3C2410_GPF1_OUTP); // CAM_GPIO7 => nLDO_PWRDN
-       s3c2410_gpio_setpin(S3C2410_GPF2, 0);
-       s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_OUTP); // CAM_GPIO6 => CAM_PWRDN
+       s3c2410_gpio_setpin(S3C2410_GPF(1), 1);
+       s3c2410_gpio_cfgpin(S3C2410_GPF(1), S3C2410_GPIO_OUTPUT); // CAM_GPIO7 => nLDO_PWRDN
+       s3c2410_gpio_setpin(S3C2410_GPF(2), 0);
+       s3c2410_gpio_cfgpin(S3C2410_GPF(2), S3C2410_GPIO_OUTPUT); // CAM_GPIO6 => CAM_PWRDN
 }
 
 static void __init nexcoder_map_io(void)
index c8a46685ce381611430e50d7069293667b3914a1..cba064b49a64cd55e364dc1e4e2cc0ff698d66fb 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
 #include <linux/device.h>
 #include <linux/sysdev.h>
 #include <linux/serial_core.h>
@@ -291,8 +292,8 @@ static int osiris_pm_suspend(struct sys_device *sd, pm_message_t state)
        __raw_writeb(tmp, OSIRIS_VA_CTRL0);
 
        /* ensure that an nRESET is not generated on resume. */
-       s3c2410_gpio_setpin(S3C2410_GPA21, 1);
-       s3c2410_gpio_cfgpin(S3C2410_GPA21, S3C2410_GPA21_OUT);
+       s3c2410_gpio_setpin(S3C2410_GPA(21), 1);
+       s3c2410_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPIO_OUTPUT);
 
        return 0;
 }
@@ -304,7 +305,7 @@ static int osiris_pm_resume(struct sys_device *sd)
 
        __raw_writeb(pm_osiris_ctrl0, OSIRIS_VA_CTRL0);
 
-       s3c2410_gpio_cfgpin(S3C2410_GPA21, S3C2410_GPA21_nRSTOUT);
+       s3c2410_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPA21_nRSTOUT);
 
        return 0;
 }
@@ -384,7 +385,7 @@ static void __init osiris_map_io(void)
                osiris_nand_sets[0].nr_partitions = ARRAY_SIZE(osiris_default_nand_part_large);
        } else {
                /* write-protect line to the NAND */
-               s3c2410_gpio_setpin(S3C2410_GPA0, 1);
+               s3c2410_gpio_setpin(S3C2410_GPA(0), 1);
        }
 
        /* fix bus configuration (nBE settings wrong on ABLE pre v2.20) */
index 8430e5829186da2d56f39d3069c6b99e0d708ffa..397f3b5c0b47421941dd4de82336a7fb37ef1541 100644 (file)
 
 #include <mach/dma.h>
 
-#include <plat/dma.h>
+#include <plat/dma-plat.h>
 #include <plat/cpu.h>
 
 #include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
 #include <plat/regs-ac97.h>
+#include <plat/regs-dma.h>
 #include <mach/regs-mem.h>
 #include <mach/regs-lcd.h>
 #include <mach/regs-sdi.h>
index 6da82b5c09ba93f0116dac3610b864ef01556b39..f5af212066c3b0a4b4eb36d5aec6a84ddfc53013 100644 (file)
@@ -5,4 +5,27 @@
 #
 # Licensed under GPLv2
 
-# Currently nothing here, this will be added later
+# Configuration options for the S3C6410 CPU
+
+config CPU_S3C6400
+       bool
+       select CPU_S3C6400_INIT
+       select CPU_S3C6400_CLOCK
+       help
+         Enable S3C6400 CPU support
+
+config S3C6400_SETUP_SDHCI
+       bool
+       help
+         Internal configuration for default SDHCI
+         setup for S3C6400.
+
+# S36400 Macchine support
+
+config MACH_SMDK6400
+       bool "SMDK6400"
+       select CPU_S3C6400
+       select S3C_DEV_HSMMC
+       select S3C6400_SETUP_SDHCI
+       help
+         Machine support for the Samsung SMDK6400
index 8f397db25b87ff5ff1d371169c30846edfcb849d..df1ce4aa03e5ec6def63c2b1c22fd6b095f81469 100644 (file)
@@ -12,4 +12,12 @@ obj-                         :=
 
 # Core support for S3C6400 system
 
-obj-n                          += blank.o
+obj-$(CONFIG_CPU_S3C6400)      += s3c6400.o
+
+# setup support
+
+obj-$(CONFIG_S3C6400_SETUP_SDHCI) += setup-sdhci.o
+
+# Machine support
+
+obj-$(CONFIG_MACH_SMDK6400)    += mach-smdk6400.o
index 9771ac2cb07e346a79944743a43600901dfb4c94..1067619f0ba07a5a2b12ebc0838e941d8d3d745b 100644 (file)
 #ifndef __ASM_ARCH_DMA_H
 #define __ASM_ARCH_DMA_H __FILE__
 
-/* currently nothing here, placeholder */
+#define S3C_DMA_CHANNELS       (16)
+
+/* see mach-s3c2410/dma.h for notes on dma channel numbers */
+
+/* Note, for the S3C64XX architecture we keep the DMACH_
+ * defines in the order they are allocated to [S]DMA0/[S]DMA1
+ * so that is easy to do DHACH_ -> DMA controller conversion
+ */
+enum dma_ch {
+       /* DMA0/SDMA0 */
+       DMACH_UART0 = 0,
+       DMACH_UART0_SRC2,
+       DMACH_UART1,
+       DMACH_UART1_SRC2,
+       DMACH_UART2,
+       DMACH_UART2_SRC2,
+       DMACH_UART3,
+       DMACH_UART3_SRC2,
+       DMACH_PCM0_TX,
+       DMACH_PCM0_RX,
+       DMACH_I2S0_OUT,
+       DMACH_I2S0_IN,
+       DMACH_SPI0_TX,
+       DMACH_SPI0_RX,
+       DMACH_HSI_I2SV40_TX,
+       DMACH_HSI_I2SV40_RX,
+
+       /* DMA1/SDMA1 */
+       DMACH_PCM1_TX = 16,
+       DMACH_PCM1_RX,
+       DMACH_I2S1_OUT,
+       DMACH_I2S1_IN,
+       DMACH_SPI1_TX,
+       DMACH_SPI1_RX,
+       DMACH_AC97_PCMOUT,
+       DMACH_AC97_PCMIN,
+       DMACH_AC97_MICIN,
+       DMACH_PWM,
+       DMACH_IRDA,
+       DMACH_EXTERNAL,
+       DMACH_RES1,
+       DMACH_RES2,
+       DMACH_SECURITY_RX,      /* SDMA1 only */
+       DMACH_SECURITY_TX,      /* SDMA1 only */
+       DMACH_MAX               /* the end */
+};
+
+static __inline__ int s3c_dma_has_circular(void)
+{
+       /* we will be supporting ciruclar buffers as soon as we have DMA
+        * engine support.
+        */
+       return 1;
+}
+
+#define S3C2410_DMAF_CIRCULAR          (1 << 0)
+
+#include <plat/dma.h>
 
 #endif /* __ASM_ARCH_IRQ_H */
index 8199972ed5bd4046cefb0b4f7a2d4ee9d5c1818e..5057d9948d3588ceb784b179bbfad3ed3cdae6d9 100644 (file)
@@ -39,6 +39,8 @@
 #define S3C_VA_UART3           S3C_VA_UARTx(3)
 
 #define S3C64XX_PA_FB          (0x77100000)
+#define S3C64XX_PA_USB_HSOTG   (0x7C000000)
+#define S3C64XX_PA_WATCHDOG    (0x7E004000)
 #define S3C64XX_PA_SYSCON      (0x7E00F000)
 #define S3C64XX_PA_IIS0                (0x7F002000)
 #define S3C64XX_PA_IIS1                (0x7F003000)
@@ -57,6 +59,8 @@
 #define S3C64XX_PA_MODEM       (0x74108000)
 #define S3C64XX_VA_MODEM       S3C_ADDR(0x00600000)
 
+#define S3C64XX_PA_USBHOST     (0x74300000)
+
 /* place VICs close together */
 #define S3C_VA_VIC0            (S3C_VA_IRQ + 0x00)
 #define S3C_VA_VIC1            (S3C_VA_IRQ + 0x10000)
@@ -69,5 +73,7 @@
 #define S3C_PA_IIC             S3C64XX_PA_IIC0
 #define S3C_PA_IIC1            S3C64XX_PA_IIC1
 #define S3C_PA_FB              S3C64XX_PA_FB
+#define S3C_PA_USBHOST         S3C64XX_PA_USBHOST
+#define S3C_PA_USB_HSOTG       S3C64XX_PA_USB_HSOTG
 
 #endif /* __ASM_ARCH_6400_MAP_H */
diff --git a/arch/arm/mach-s3c6400/include/mach/regs-clock.h b/arch/arm/mach-s3c6400/include/mach/regs-clock.h
new file mode 100644 (file)
index 0000000..a6c7f4e
--- /dev/null
@@ -0,0 +1,16 @@
+/* linux/arch/arm/mach-s3c6400/include/mach/regs-clock.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C64XX - clock register compatibility with s3c24xx
+ *
+ * This 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 <plat/regs-clock.h>
+
index 090cfd969bc7f4b572e54a722064d83baa9fd2fa..2e58cb7a71479d79181416714990cc6fb3a4509a 100644 (file)
@@ -11,6 +11,8 @@
 #ifndef __ASM_ARCH_SYSTEM_H
 #define __ASM_ARCH_SYSTEM_H __FILE__
 
+#include <plat/watchdog-reset.h>
+
 static void arch_idle(void)
 {
        /* nothing here yet */
@@ -18,7 +20,11 @@ static void arch_idle(void)
 
 static void arch_reset(char mode, const char *cmd)
 {
-       /* nothing here yet */
+       if (mode != 's')
+               arch_wdt_reset();
+
+       /* if all else fails, or mode was for soft, jump to 0 */
+       cpu_reset(0);
 }
 
 #endif /* __ASM_ARCH_IRQ_H */
diff --git a/arch/arm/mach-s3c6400/mach-smdk6400.c b/arch/arm/mach-s3c6400/mach-smdk6400.c
new file mode 100644 (file)
index 0000000..ab19285
--- /dev/null
@@ -0,0 +1,96 @@
+/* linux/arch/arm/mach-s3c6400/mach-smdk6400.c
+ *
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@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
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/map.h>
+
+#include <plat/regs-serial.h>
+
+#include <plat/s3c6400.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/iic.h>
+
+#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg smdk6400_uartcfgs[] __initdata = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x03,
+               .ufcon       = 0x51,
+       },
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x03,
+               .ufcon       = 0x51,
+       },
+};
+
+static struct map_desc smdk6400_iodesc[] = {};
+
+static void __init smdk6400_map_io(void)
+{
+       s3c64xx_init_io(smdk6400_iodesc, ARRAY_SIZE(smdk6400_iodesc));
+       s3c24xx_init_clocks(12000000);
+       s3c24xx_init_uarts(smdk6400_uartcfgs, ARRAY_SIZE(smdk6400_uartcfgs));
+}
+
+static struct platform_device *smdk6400_devices[] __initdata = {
+       &s3c_device_hsmmc1,
+       &s3c_device_i2c0,
+};
+
+static struct i2c_board_info i2c_devs[] __initdata = {
+       { I2C_BOARD_INFO("wm8753", 0x1A), },
+       { I2C_BOARD_INFO("24c08", 0x50), },
+};
+
+static void __init smdk6400_machine_init(void)
+{
+       i2c_register_board_info(0, i2c_devs, ARRAY_SIZE(i2c_devs));
+       platform_add_devices(smdk6400_devices, ARRAY_SIZE(smdk6400_devices));
+}
+
+MACHINE_START(SMDK6400, "SMDK6400")
+       /* Maintainer: Ben Dooks <ben@fluff.org> */
+       .phys_io        = S3C_PA_UART & 0xfff00000,
+       .io_pg_offst    = (((u32)S3C_VA_UART) >> 18) & 0xfffc,
+       .boot_params    = S3C64XX_PA_SDRAM + 0x100,
+
+       .init_irq       = s3c6400_init_irq,
+       .map_io         = smdk6400_map_io,
+       .init_machine   = smdk6400_machine_init,
+       .timer          = &s3c24xx_timer,
+MACHINE_END
diff --git a/arch/arm/mach-s3c6400/s3c6400.c b/arch/arm/mach-s3c6400/s3c6400.c
new file mode 100644 (file)
index 0000000..1ece887
--- /dev/null
@@ -0,0 +1,89 @@
+/* linux/arch/arm/mach-s3c6410/cpu.c
+ *
+ * Copyright 2009 Simtec Electronics
+ *     Ben Dooks <ben@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
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/sysdev.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+
+#include <plat/cpu-freq.h>
+#include <plat/regs-serial.h>
+#include <plat/regs-clock.h>
+
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/clock.h>
+#include <plat/sdhci.h>
+#include <plat/iic-core.h>
+#include <plat/s3c6400.h>
+
+void __init s3c6400_map_io(void)
+{
+       /* setup SDHCI */
+
+       s3c6400_default_sdhci0();
+       s3c6400_default_sdhci1();
+
+       /* the i2c devices are directly compatible with s3c2440 */
+       s3c_i2c0_setname("s3c2440-i2c");
+}
+
+void __init s3c6400_init_clocks(int xtal)
+{
+       printk(KERN_DEBUG "%s: initialising clocks\n", __func__);
+       s3c24xx_register_baseclocks(xtal);
+       s3c64xx_register_clocks();
+       s3c6400_register_clocks(S3C6400_CLKDIV0_ARM_MASK);
+       s3c6400_setup_clocks();
+}
+
+void __init s3c6400_init_irq(void)
+{
+       /* VIC0 does not have IRQS 5..7,
+        * VIC1 is fully populated. */
+       s3c64xx_init_irq(~0 & ~(0xf << 5), ~0);
+}
+
+struct sysdev_class s3c6400_sysclass = {
+       .name   = "s3c6400-core",
+};
+
+static struct sys_device s3c6400_sysdev = {
+       .cls    = &s3c6400_sysclass,
+};
+
+static int __init s3c6400_core_init(void)
+{
+       return sysdev_class_register(&s3c6400_sysclass);
+}
+
+core_initcall(s3c6400_core_init);
+
+int __init s3c6400_init(void)
+{
+       printk("S3C6400: Initialising architecture\n");
+
+       return sysdev_register(&s3c6400_sysdev);
+}
diff --git a/arch/arm/mach-s3c6400/setup-sdhci.c b/arch/arm/mach-s3c6400/setup-sdhci.c
new file mode 100644 (file)
index 0000000..b93dafb
--- /dev/null
@@ -0,0 +1,63 @@
+/* linux/arch/arm/mach-s3c6410/setup-sdhci.c
+ *
+ * Copyright 2008 Simtec Electronics
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * S3C6410 - Helper functions for settign up SDHCI device(s) (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/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 *s3c6400_hsmmc_clksrcs[4] = {
+       [0] = "hsmmc",
+       [1] = "hsmmc",
+       [2] = "mmc_bus",
+       /* [3] = "48m", - note not succesfully used yet */
+};
+
+void s3c6400_setup_sdhci_cfg_card(struct platform_device *dev,
+                                 void __iomem *r,
+                                 struct mmc_ios *ios,
+                                 struct mmc_card *card)
+{
+       u32 ctrl2, ctrl3;
+
+       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);
+
+       printk(KERN_INFO "%s: CTRL 2=%08x, 3=%08x\n", __func__, ctrl2, ctrl3);
+       writel(ctrl2, r + S3C_SDHCI_CONTROL2);
+       writel(ctrl3, r + S3C_SDHCI_CONTROL3);
+}
+
index 1d50100700273685182d9f987a48ff794b6ebc57..e63aac7f4e5a54c5516eadd457a94531758dbfb4 100644 (file)
@@ -16,9 +16,18 @@ config CPU_S3C6410
 
 config S3C6410_SETUP_SDHCI
        bool
+       select S3C64XX_SETUP_SDHCI_GPIO
        help
          Internal helper functions for S3C6410 based SDHCI systems
 
+config MACH_ANW6410
+       bool "A&W6410"
+       select CPU_S3C6410
+       select S3C_DEV_FB
+       select S3C64XX_SETUP_FB_24BPP
+       help
+         Machine support for the A&W6410
+
 config MACH_SMDK6410
        bool "SMDK6410"
        select CPU_S3C6410
@@ -26,6 +35,8 @@ config MACH_SMDK6410
        select S3C_DEV_HSMMC1
        select S3C_DEV_I2C1
        select S3C_DEV_FB
+       select S3C_DEV_USB_HOST
+       select S3C_DEV_USB_HSOTG
        select S3C6410_SETUP_SDHCI
        select S3C64XX_SETUP_I2C1
        select S3C64XX_SETUP_FB_24BPP
@@ -60,3 +71,29 @@ config SMDK6410_SD_CH1
          channels 0 and 1 are the same.
 
 endchoice
+
+config SMDK6410_WM1190_EV1
+       bool "Support Wolfson Microelectronics 1190-EV1 PMIC card"
+       depends on MACH_SMDK6410
+       select REGULATOR
+       select REGULATOR_WM8350
+       select MFD_WM8350_I2C
+       select MFD_WM8350_CONFIG_MODE_0
+       select MFD_WM8350_CONFIG_MODE_3
+       select MFD_WM8352_CONFIG_MODE_0
+       help
+         The Wolfson Microelectronics 1190-EV1 is a WM835x based PMIC
+         and audio daughtercard for the Samsung SMDK6410 reference
+         platform.  Enabling this option will build support for this
+         module into the kernel.  The presence of the module will be
+         detected at runtime so the the resulting kernel can be used
+         with or without the 1190-EV1 fitted.
+
+config MACH_NCP
+       bool "NCP"
+       select CPU_S3C6410
+       select S3C_DEV_I2C1
+       select S3C_DEV_HSMMC1
+       select S3C64XX_SETUP_I2C1
+       help
+          Machine support for the Samsung NCP
index 2cd4f189036bc77c89117682a25cfccc467d4951..6f9deac8861247ec38ffd9c5944f264a03505e9f 100644 (file)
@@ -20,4 +20,8 @@ obj-$(CONFIG_S3C6410_SETUP_SDHCI)     += setup-sdhci.o
 
 # machine support
 
+obj-$(CONFIG_MACH_ANW6410)     += mach-anw6410.o
 obj-$(CONFIG_MACH_SMDK6410)    += mach-smdk6410.o
+obj-$(CONFIG_MACH_NCP)         += mach-ncp.o
+
+
index 6a73ca6b7a3a81dfd48d878d49871a5c0dbd47bf..ade904de88953f8db6299601b07cdd7433d5b54c 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <plat/cpu-freq.h>
 #include <plat/regs-serial.h>
+#include <plat/regs-clock.h>
 
 #include <plat/cpu.h>
 #include <plat/devs.h>
@@ -68,7 +69,7 @@ void __init s3c6410_init_clocks(int xtal)
        printk(KERN_DEBUG "%s: initialising clocks\n", __func__);
        s3c24xx_register_baseclocks(xtal);
        s3c64xx_register_clocks();
-       s3c6400_register_clocks();
+       s3c6400_register_clocks(S3C6410_CLKDIV0_ARM_MASK);
        s3c6400_setup_clocks();
 }
 
diff --git a/arch/arm/mach-s3c6410/mach-anw6410.c b/arch/arm/mach-s3c6410/mach-anw6410.c
new file mode 100644 (file)
index 0000000..661cca6
--- /dev/null
@@ -0,0 +1,245 @@
+/* linux/arch/arm/mach-s3c6410/mach-anw6410.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ * Copyright 2009 Kwangwoo Lee
+ *     Kwangwoo Lee <kwangwoo.lee@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/dm9000.h>
+
+#include <video/platform_lcd.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/regs-fb.h>
+#include <mach/map.h>
+
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <plat/regs-serial.h>
+#include <plat/iic.h>
+#include <plat/fb.h>
+
+#include <plat/s3c6410.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/regs-gpio.h>
+#include <plat/regs-modem.h>
+
+/* DM9000 */
+#define ANW6410_PA_DM9000      (0x18000000)
+
+/* A hardware buffer to control external devices is mapped at 0x30000000.
+ * It can not be read. So current status must be kept in anw6410_extdev_status.
+ */
+#define ANW6410_VA_EXTDEV      S3C_ADDR(0x02000000)
+#define ANW6410_PA_EXTDEV      (0x30000000)
+
+#define ANW6410_EN_DM9000      (1<<11)
+#define ANW6410_EN_LCD         (1<<14)
+
+static __u32 anw6410_extdev_status;
+
+static struct s3c2410_uartcfg anw6410_uartcfgs[] __initdata = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x03,
+               .ufcon       = 0x51,
+       },
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x03,
+               .ufcon       = 0x51,
+       },
+};
+
+/* framebuffer and LCD setup. */
+static void __init anw6410_lcd_mode_set(void)
+{
+       u32 tmp;
+
+       /* set the LCD type */
+       tmp = __raw_readl(S3C64XX_SPCON);
+       tmp &= ~S3C64XX_SPCON_LCD_SEL_MASK;
+       tmp |= S3C64XX_SPCON_LCD_SEL_RGB;
+       __raw_writel(tmp, S3C64XX_SPCON);
+
+       /* remove the LCD bypass */
+       tmp = __raw_readl(S3C64XX_MODEM_MIFPCON);
+       tmp &= ~MIFPCON_LCD_BYPASS;
+       __raw_writel(tmp, S3C64XX_MODEM_MIFPCON);
+}
+
+/* GPF1 = LCD panel power
+ * GPF4 = LCD backlight control
+ */
+static void anw6410_lcd_power_set(struct plat_lcd_data *pd,
+                                  unsigned int power)
+{
+       if (power) {
+               anw6410_extdev_status |= (ANW6410_EN_LCD << 16);
+               __raw_writel(anw6410_extdev_status, ANW6410_VA_EXTDEV);
+
+               gpio_direction_output(S3C64XX_GPF(1), 1);
+               gpio_direction_output(S3C64XX_GPF(4), 1);
+       } else {
+               anw6410_extdev_status &= ~(ANW6410_EN_LCD << 16);
+               __raw_writel(anw6410_extdev_status, ANW6410_VA_EXTDEV);
+
+               gpio_direction_output(S3C64XX_GPF(1), 0);
+               gpio_direction_output(S3C64XX_GPF(4), 0);
+       }
+}
+
+static struct plat_lcd_data anw6410_lcd_power_data = {
+       .set_power      = anw6410_lcd_power_set,
+};
+
+static struct platform_device anw6410_lcd_powerdev = {
+       .name                   = "platform-lcd",
+       .dev.parent             = &s3c_device_fb.dev,
+       .dev.platform_data      = &anw6410_lcd_power_data,
+};
+
+static struct s3c_fb_pd_win anw6410_fb_win0 = {
+       /* this is to ensure we use win0 */
+       .win_mode       = {
+               .pixclock       = 41094,
+               .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,
+};
+
+/* 405566 clocks per frame => 60Hz refresh requires 24333960Hz clock */
+static struct s3c_fb_platdata anw6410_lcd_pdata __initdata = {
+       .setup_gpio     = s3c64xx_fb_gpio_setup_24bpp,
+       .win[0]         = &anw6410_fb_win0,
+       .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
+       .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
+};
+
+/* DM9000AEP 10/100 ethernet controller */
+static void __init anw6410_dm9000_enable(void)
+{
+       anw6410_extdev_status |= (ANW6410_EN_DM9000 << 16);
+       __raw_writel(anw6410_extdev_status, ANW6410_VA_EXTDEV);
+}
+
+static struct resource anw6410_dm9000_resource[] = {
+       [0] = {
+               .start = ANW6410_PA_DM9000,
+               .end   = ANW6410_PA_DM9000 + 3,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = ANW6410_PA_DM9000 + 4,
+               .end   = ANW6410_PA_DM9000 + 4 + 500,
+               .flags = IORESOURCE_MEM,
+       },
+       [2] = {
+               .start = IRQ_EINT(15),
+               .end   = IRQ_EINT(15),
+               .flags = IORESOURCE_IRQ | IRQF_TRIGGER_HIGH,
+       },
+};
+
+static struct dm9000_plat_data anw6410_dm9000_pdata = {
+       .flags    = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM),
+       /* dev_addr can be set to provide hwaddr. */
+};
+
+static struct platform_device anw6410_device_eth = {
+       .name   = "dm9000",
+       .id     = -1,
+       .num_resources  = ARRAY_SIZE(anw6410_dm9000_resource),
+       .resource       = anw6410_dm9000_resource,
+       .dev    = {
+               .platform_data  = &anw6410_dm9000_pdata,
+       },
+};
+
+static struct map_desc anw6410_iodesc[] __initdata = {
+       {
+               .virtual        = (unsigned long)ANW6410_VA_EXTDEV,
+               .pfn            = __phys_to_pfn(ANW6410_PA_EXTDEV),
+               .length         = SZ_64K,
+               .type           = MT_DEVICE,
+       },
+};
+
+static struct platform_device *anw6410_devices[] __initdata = {
+       &s3c_device_fb,
+       &anw6410_lcd_powerdev,
+       &anw6410_device_eth,
+};
+
+static void __init anw6410_map_io(void)
+{
+       s3c64xx_init_io(anw6410_iodesc, ARRAY_SIZE(anw6410_iodesc));
+       s3c24xx_init_clocks(12000000);
+       s3c24xx_init_uarts(anw6410_uartcfgs, ARRAY_SIZE(anw6410_uartcfgs));
+
+       anw6410_lcd_mode_set();
+}
+
+static void __init anw6410_machine_init(void)
+{
+       s3c_fb_set_platdata(&anw6410_lcd_pdata);
+
+       gpio_request(S3C64XX_GPF(1), "panel power");
+       gpio_request(S3C64XX_GPF(4), "LCD backlight");
+
+       anw6410_dm9000_enable();
+
+       platform_add_devices(anw6410_devices, ARRAY_SIZE(anw6410_devices));
+}
+
+MACHINE_START(ANW6410, "A&W6410")
+       /* Maintainer: Kwangwoo Lee <kwangwoo.lee@gmail.com> */
+       .phys_io        = S3C_PA_UART & 0xfff00000,
+       .io_pg_offst    = (((u32)S3C_VA_UART) >> 18) & 0xfffc,
+       .boot_params    = S3C64XX_PA_SDRAM + 0x100,
+
+       .init_irq       = s3c6410_init_irq,
+       .map_io         = anw6410_map_io,
+       .init_machine   = anw6410_machine_init,
+       .timer          = &s3c24xx_timer,
+MACHINE_END
diff --git a/arch/arm/mach-s3c6410/mach-ncp.c b/arch/arm/mach-s3c6410/mach-ncp.c
new file mode 100644 (file)
index 0000000..6030636
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * linux/arch/arm/mach-s3c6410/mach-ncp.c
+ *
+ * Copyright (C) 2008-2009 Samsung Electronics
+ *
+ * This 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/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include <video/platform_lcd.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/regs-fb.h>
+#include <mach/map.h>
+
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <plat/regs-serial.h>
+#include <plat/iic.h>
+#include <plat/fb.h>
+
+#include <plat/s3c6410.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+
+#define UCON S3C2410_UCON_DEFAULT
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg ncp_uartcfgs[] __initdata = {
+       /* REVISIT: NCP uses only serial 1, 2 */
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       [2] = {
+               .hwport      = 2,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+};
+
+static struct platform_device *ncp_devices[] __initdata = {
+       &s3c_device_hsmmc1,
+       &s3c_device_i2c0,
+};
+
+struct map_desc ncp_iodesc[] = {};
+
+static void __init ncp_map_io(void)
+{
+       s3c64xx_init_io(ncp_iodesc, ARRAY_SIZE(ncp_iodesc));
+       s3c24xx_init_clocks(12000000);
+       s3c24xx_init_uarts(ncp_uartcfgs, ARRAY_SIZE(ncp_uartcfgs));
+}
+
+static void __init ncp_machine_init(void)
+{
+       s3c_i2c0_set_platdata(NULL);
+
+       platform_add_devices(ncp_devices, ARRAY_SIZE(ncp_devices));
+}
+
+MACHINE_START(NCP, "NCP")
+       /* Maintainer: Samsung Electronics */
+       .phys_io        = S3C_PA_UART & 0xfff00000,
+       .io_pg_offst    = (((u32)S3C_VA_UART) >> 18) & 0xfffc,
+       .boot_params    = S3C64XX_PA_SDRAM + 0x100,
+       .init_irq       = s3c6410_init_irq,
+       .map_io         = ncp_map_io,
+       .init_machine   = ncp_machine_init,
+       .timer          = &s3c24xx_timer,
+MACHINE_END
index 7f473e47e4f13cb735b4ccec3b41175e86787be6..bc9a7dea567ff0e90e6dbc29711c3a639a4d99ef 100644 (file)
 #include <linux/fb.h>
 #include <linux/gpio.h>
 #include <linux/delay.h>
+#include <linux/smsc911x.h>
+
+#ifdef CONFIG_SMDK6410_WM1190_EV1
+#include <linux/mfd/wm8350/core.h>
+#include <linux/mfd/wm8350/pmic.h>
+#endif
 
 #include <video/platform_lcd.h>
 
 #include <asm/mach-types.h>
 
 #include <plat/regs-serial.h>
+#include <plat/regs-modem.h>
+#include <plat/regs-gpio.h>
+#include <plat/regs-sys.h>
 #include <plat/iic.h>
 #include <plat/fb.h>
+#include <plat/gpio-cfg.h>
 
 #include <plat/s3c6410.h>
 #include <plat/clock.h>
@@ -129,6 +139,37 @@ static struct s3c_fb_platdata smdk6410_lcd_pdata __initdata = {
        .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
 };
 
+static struct resource smdk6410_smsc911x_resources[] = {
+       [0] = {
+               .start = 0x18000000,
+               .end   = 0x18000000 + SZ_64K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = S3C_EINT(10),
+               .end   = S3C_EINT(10),
+               .flags = IORESOURCE_IRQ | IRQ_TYPE_LEVEL_LOW,
+       },
+};
+
+static struct smsc911x_platform_config smdk6410_smsc911x_pdata = {
+       .irq_polarity  = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+       .irq_type      = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+       .flags         = SMSC911X_USE_32BIT | SMSC911X_FORCE_INTERNAL_PHY,
+       .phy_interface = PHY_INTERFACE_MODE_MII,
+};
+
+
+static struct platform_device smdk6410_smsc911x = {
+       .name          = "smsc911x",
+       .id            = -1,
+       .num_resources = ARRAY_SIZE(smdk6410_smsc911x_resources),
+       .resource      = &smdk6410_smsc911x_resources[0],
+       .dev = {
+               .platform_data = &smdk6410_smsc911x_pdata,
+       },
+};
+
 static struct map_desc smdk6410_iodesc[] = {};
 
 static struct platform_device *smdk6410_devices[] __initdata = {
@@ -141,12 +182,155 @@ static struct platform_device *smdk6410_devices[] __initdata = {
        &s3c_device_i2c0,
        &s3c_device_i2c1,
        &s3c_device_fb,
+       &s3c_device_usb,
+       &s3c_device_usb_hsotg,
        &smdk6410_lcd_powerdev,
+
+       &smdk6410_smsc911x,
+};
+
+#ifdef CONFIG_SMDK6410_WM1190_EV1
+/* S3C64xx internal logic & PLL */
+static struct regulator_init_data wm8350_dcdc1_data = {
+       .constraints = {
+               .name = "PVDD_INT/PVDD_PLL",
+               .min_uV = 1200000,
+               .max_uV = 1200000,
+               .always_on = 1,
+               .apply_uV = 1,
+       },
+};
+
+/* Memory */
+static struct regulator_init_data wm8350_dcdc3_data = {
+       .constraints = {
+               .name = "PVDD_MEM",
+               .min_uV = 1800000,
+               .max_uV = 1800000,
+               .always_on = 1,
+               .state_mem = {
+                        .uV = 1800000,
+                        .mode = REGULATOR_MODE_NORMAL,
+                        .enabled = 1,
+                },
+               .initial_state = PM_SUSPEND_MEM,
+       },
+};
+
+/* USB, EXT, PCM, ADC/DAC, USB, MMC */
+static struct regulator_init_data wm8350_dcdc4_data = {
+       .constraints = {
+               .name = "PVDD_HI/PVDD_EXT/PVDD_SYS/PVCCM2MTV",
+               .min_uV = 3000000,
+               .max_uV = 3000000,
+               .always_on = 1,
+       },
+};
+
+/* ARM core */
+static struct regulator_consumer_supply dcdc6_consumers[] = {
+       {
+               .supply = "vddarm",
+       }
+};
+
+static struct regulator_init_data wm8350_dcdc6_data = {
+       .constraints = {
+               .name = "PVDD_ARM",
+               .min_uV = 1000000,
+               .max_uV = 1300000,
+               .always_on = 1,
+               .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+       },
+       .num_consumer_supplies = ARRAY_SIZE(dcdc6_consumers),
+       .consumer_supplies = dcdc6_consumers,
 };
 
+/* Alive */
+static struct regulator_init_data wm8350_ldo1_data = {
+       .constraints = {
+               .name = "PVDD_ALIVE",
+               .min_uV = 1200000,
+               .max_uV = 1200000,
+               .always_on = 1,
+               .apply_uV = 1,
+       },
+};
+
+/* OTG */
+static struct regulator_init_data wm8350_ldo2_data = {
+       .constraints = {
+               .name = "PVDD_OTG",
+               .min_uV = 3300000,
+               .max_uV = 3300000,
+               .always_on = 1,
+       },
+};
+
+/* LCD */
+static struct regulator_init_data wm8350_ldo3_data = {
+       .constraints = {
+               .name = "PVDD_LCD",
+               .min_uV = 3000000,
+               .max_uV = 3000000,
+               .always_on = 1,
+       },
+};
+
+/* OTGi/1190-EV1 HPVDD & AVDD */
+static struct regulator_init_data wm8350_ldo4_data = {
+       .constraints = {
+               .name = "PVDD_OTGI/HPVDD/AVDD",
+               .min_uV = 1200000,
+               .max_uV = 1200000,
+               .apply_uV = 1,
+               .always_on = 1,
+       },
+};
+
+static struct {
+       int regulator;
+       struct regulator_init_data *initdata;
+} wm1190_regulators[] = {
+       { WM8350_DCDC_1, &wm8350_dcdc1_data },
+       { WM8350_DCDC_3, &wm8350_dcdc3_data },
+       { WM8350_DCDC_4, &wm8350_dcdc4_data },
+       { WM8350_DCDC_6, &wm8350_dcdc6_data },
+       { WM8350_LDO_1, &wm8350_ldo1_data },
+       { WM8350_LDO_2, &wm8350_ldo2_data },
+       { WM8350_LDO_3, &wm8350_ldo3_data },
+       { WM8350_LDO_4, &wm8350_ldo4_data },
+};
+
+static int __init smdk6410_wm8350_init(struct wm8350 *wm8350)
+{
+       int i;
+
+       /* Instantiate the regulators */
+       for (i = 0; i < ARRAY_SIZE(wm1190_regulators); i++)
+               wm8350_register_regulator(wm8350,
+                                         wm1190_regulators[i].regulator,
+                                         wm1190_regulators[i].initdata);
+
+       return 0;
+}
+
+static struct wm8350_platform_data __initdata smdk6410_wm8350_pdata = {
+       .init = smdk6410_wm8350_init,
+       .irq_high = 1,
+};
+#endif
+
 static struct i2c_board_info i2c_devs0[] __initdata = {
        { I2C_BOARD_INFO("24c08", 0x50), },
        { I2C_BOARD_INFO("wm8580", 0x1b), },
+
+#ifdef CONFIG_SMDK6410_WM1190_EV1
+       { I2C_BOARD_INFO("wm8350", 0x1a),
+         .platform_data = &smdk6410_wm8350_pdata,
+         .irq = S3C_EINT(12),
+       },
+#endif
 };
 
 static struct i2c_board_info i2c_devs1[] __initdata = {
@@ -155,9 +339,23 @@ static struct i2c_board_info i2c_devs1[] __initdata = {
 
 static void __init smdk6410_map_io(void)
 {
+       u32 tmp;
+
        s3c64xx_init_io(smdk6410_iodesc, ARRAY_SIZE(smdk6410_iodesc));
        s3c24xx_init_clocks(12000000);
        s3c24xx_init_uarts(smdk6410_uartcfgs, ARRAY_SIZE(smdk6410_uartcfgs));
+
+       /* set the LCD type */
+
+       tmp = __raw_readl(S3C64XX_SPCON);
+       tmp &= ~S3C64XX_SPCON_LCD_SEL_MASK;
+       tmp |= S3C64XX_SPCON_LCD_SEL_RGB;
+       __raw_writel(tmp, S3C64XX_SPCON);
+
+       /* remove the lcd bypass */
+       tmp = __raw_readl(S3C64XX_MODEM_MIFPCON);
+       tmp &= ~MIFPCON_LCD_BYPASS;
+       __raw_writel(tmp, S3C64XX_MODEM_MIFPCON);
 }
 
 static void __init smdk6410_machine_init(void)
index 0b5788bd59859a3cc0f10f5bef0d44d781f6794a..20666f3bd4785b4ce786952958601ec075a41fb9 100644 (file)
@@ -21,8 +21,6 @@
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
 
-#include <mach/gpio.h>
-#include <plat/gpio-cfg.h>
 #include <plat/regs-sdhci.h>
 #include <plat/sdhci.h>
 
@@ -35,22 +33,6 @@ char *s3c6410_hsmmc_clksrcs[4] = {
        /* [3] = "48m", - note not succesfully used yet */
 };
 
-void s3c6410_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width)
-{
-       unsigned int gpio;
-       unsigned int end;
-
-       end = S3C64XX_GPG(2 + width);
-
-       /* Set all the necessary GPG pins to special-function 0 */
-       for (gpio = S3C64XX_GPG(0); gpio < end; gpio++) {
-               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-       }
-
-       s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP);
-       s3c_gpio_cfgpin(S3C64XX_GPG(6), S3C_GPIO_SFN(2));
-}
 
 void s3c6410_setup_sdhci0_cfg_card(struct platform_device *dev,
                                    void __iomem *r,
@@ -84,19 +66,3 @@ void s3c6410_setup_sdhci0_cfg_card(struct platform_device *dev,
        writel(ctrl3, r + S3C_SDHCI_CONTROL3);
 }
 
-void s3c6410_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width)
-{
-       unsigned int gpio;
-       unsigned int end;
-
-       end = S3C64XX_GPH(2 + width);
-
-       /* Set all the necessary GPG pins to special-function 0 */
-       for (gpio = S3C64XX_GPH(0); gpio < end; gpio++) {
-               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-       }
-
-       s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP);
-       s3c_gpio_cfgpin(S3C64XX_GPG(6), S3C_GPIO_SFN(3));
-}
diff --git a/arch/arm/mach-sa1100/collie_pm.c b/arch/arm/mach-sa1100/collie_pm.c
deleted file mode 100644 (file)
index 444f266..0000000
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * Based on spitz_pm.c and sharp code.
- *
- * Copyright (C) 2001  SHARP
- * Copyright 2005 Pavel Machek <pavel@suse.cz>
- *
- * Distribute under GPLv2.
- *
- * Li-ion batteries are angry beasts, and they like to explode. This driver is not finished,
- * and sometimes charges them when it should not. If it makes angry lithium to come your way...
- * ...well, you have been warned.
- *
- * Actually, this should be quite safe, it seems sharp leaves charger enabled by default,
- * and my collie did not explode (yet).
- */
-
-#include <linux/module.h>
-#include <linux/stat.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-
-#include <asm/irq.h>
-#include <mach/hardware.h>
-#include <asm/hardware/scoop.h>
-#include <mach/dma.h>
-#include <mach/collie.h>
-#include <asm/mach/sharpsl_param.h>
-#include <asm/hardware/sharpsl_pm.h>
-
-#include "../drivers/mfd/ucb1x00.h"
-
-static struct ucb1x00 *ucb;
-static int ad_revise;
-
-#define ADCtoPower(x)         ((330 * x * 2) / 1024)
-
-static void collie_charger_init(void)
-{
-       int err;
-
-       if (sharpsl_param.adadj != -1)
-               ad_revise = sharpsl_param.adadj;
-
-       /* Register interrupt handler. */
-       if ((err = request_irq(COLLIE_IRQ_GPIO_AC_IN, sharpsl_ac_isr, IRQF_DISABLED,
-                              "ACIN", sharpsl_ac_isr))) {
-               printk("Could not get irq %d.\n", COLLIE_IRQ_GPIO_AC_IN);
-               return;
-       }
-       if ((err = request_irq(COLLIE_IRQ_GPIO_CO, sharpsl_chrg_full_isr, IRQF_DISABLED,
-                              "CO", sharpsl_chrg_full_isr))) {
-               free_irq(COLLIE_IRQ_GPIO_AC_IN, sharpsl_ac_isr);
-               printk("Could not get irq %d.\n", COLLIE_IRQ_GPIO_CO);
-               return;
-       }
-
-       gpio_request(COLLIE_GPIO_CHARGE_ON, "charge on");
-       gpio_direction_output(COLLIE_GPIO_CHARGE_ON, 1);
-
-       ucb1x00_io_set_dir(ucb, 0, COLLIE_TC35143_GPIO_MBAT_ON | COLLIE_TC35143_GPIO_TMP_ON |
-                                  COLLIE_TC35143_GPIO_BBAT_ON);
-       return;
-}
-
-static void collie_measure_temp(int on)
-{
-       if (on)
-               ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_TMP_ON, 0);
-       else
-               ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_TMP_ON);
-}
-
-static void collie_charge(int on)
-{
-       /* Zaurus seems to contain LTC1731; it should know when to
-        * stop charging itself, so setting charge on should be
-        * relatively harmless (as long as it is not done too often).
-        */
-       gpio_set_value(COLLIE_GPIO_CHARGE_ON, on);
-}
-
-static void collie_discharge(int on)
-{
-}
-
-static void collie_discharge1(int on)
-{
-}
-
-static void collie_presuspend(void)
-{
-}
-
-static void collie_postsuspend(void)
-{
-}
-
-static int collie_should_wakeup(unsigned int resume_on_alarm)
-{
-       return 0;
-}
-
-static unsigned long collie_charger_wakeup(void)
-{
-       return 0;
-}
-
-int collie_read_backup_battery(void)
-{
-       int voltage;
-
-       ucb1x00_adc_enable(ucb);
-
-       ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_BBAT_ON, 0);
-       voltage = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD1, UCB_SYNC);
-
-       ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_BBAT_ON);
-       ucb1x00_adc_disable(ucb);
-
-       printk("Backup battery = %d(%d)\n", ADCtoPower(voltage), voltage);
-
-       return ADCtoPower(voltage);
-}
-
-int collie_read_main_battery(void)
-{
-       int voltage, voltage_rev, voltage_volts;
-
-       ucb1x00_adc_enable(ucb);
-       ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_BBAT_ON);
-       ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_MBAT_ON, 0);
-
-       mdelay(1);
-       voltage = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD1, UCB_SYNC);
-
-       ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_MBAT_ON);
-       ucb1x00_adc_disable(ucb);
-
-       voltage_rev = voltage + ((ad_revise * voltage) / 652);
-       voltage_volts = ADCtoPower(voltage_rev);
-
-       printk("Main battery = %d(%d)\n", voltage_volts, voltage);
-
-       if (voltage != -1)
-               return voltage_volts;
-       else
-               return voltage;
-}
-
-int collie_read_temp(void)
-{
-       int voltage;
-
-       /* According to Sharp, temp must be > 973, main battery must be < 465,
-          FIXME: sharpsl_pm.c has both conditions negated? FIXME: values
-          are way out of range? */
-
-       ucb1x00_adc_enable(ucb);
-       ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_TMP_ON, 0);
-       /* >1010 = battery removed, 460 = 22C ?, higher = lower temp ? */
-       voltage = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD0, UCB_SYNC);
-       ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_TMP_ON);
-       ucb1x00_adc_disable(ucb);
-
-       printk("Battery temp = %d\n", voltage);
-       return voltage;
-}
-
-static unsigned long read_devdata(int which)
-{
-       switch (which) {
-       case SHARPSL_BATT_VOLT:
-               return collie_read_main_battery();
-       case SHARPSL_BATT_TEMP:
-               return collie_read_temp();
-       case SHARPSL_ACIN_VOLT:
-               return 500;
-       case SHARPSL_STATUS_ACIN: {
-               int ret = GPLR & COLLIE_GPIO_AC_IN;
-               printk("AC status = %d\n", ret);
-               return ret;
-       }
-       case SHARPSL_STATUS_FATAL: {
-               int ret = GPLR & COLLIE_GPIO_MAIN_BAT_LOW;
-               printk("Fatal bat = %d\n", ret);
-               return ret;
-       }
-       default:
-               return ~0;
-       }
-}
-
-struct battery_thresh collie_battery_levels_acin[] = {
-       { 420, 100},
-       { 417,  95},
-       { 415,  90},
-       { 413,  80},
-       { 411,  75},
-       { 408,  70},
-       { 406,  60},
-       { 403,  50},
-       { 398,  40},
-       { 391,  25},
-       {  10,   5},
-       {   0,   0},
-};
-
-struct battery_thresh collie_battery_levels[] = {
-       { 394, 100},
-       { 390,  95},
-       { 380,  90},
-       { 370,  80},
-       { 368,  75},    /* From sharp code: battery high with frontlight */
-       { 366,  70},    /* 60..90 -- fake values invented by me for testing */
-       { 364,  60},
-       { 362,  50},
-       { 360,  40},
-       { 358,  25},    /* From sharp code: battery low with frontlight */
-       { 356,   5},    /* From sharp code: battery verylow with frontlight */
-       {   0,   0},
-};
-
-struct sharpsl_charger_machinfo collie_pm_machinfo = {
-       .init             = collie_charger_init,
-       .read_devdata     = read_devdata,
-       .discharge        = collie_discharge,
-       .discharge1       = collie_discharge1,
-       .charge           = collie_charge,
-       .measure_temp     = collie_measure_temp,
-       .presuspend       = collie_presuspend,
-       .postsuspend      = collie_postsuspend,
-       .charger_wakeup   = collie_charger_wakeup,
-       .should_wakeup    = collie_should_wakeup,
-       .bat_levels       = 12,
-       .bat_levels_noac  = collie_battery_levels,
-       .bat_levels_acin  = collie_battery_levels_acin,
-       .status_high_acin = 368,
-       .status_low_acin  = 358,
-       .status_high_noac = 368,
-       .status_low_noac  = 358,
-       .charge_on_volt   = 350,        /* spitz uses 2.90V, but lets play it safe. */
-       .charge_on_temp   = 550,
-       .charge_acin_high = 550,        /* collie does not seem to have sensor for this, anyway */
-       .charge_acin_low  = 450,        /* ignored, too */
-       .fatal_acin_volt  = 356,
-       .fatal_noacin_volt = 356,
-
-       .batfull_irq = 1,               /* We do not want periodical charge restarts */
-};
-
-static int __init collie_pm_ucb_add(struct ucb1x00_dev *pdev)
-{
-       sharpsl_pm.machinfo = &collie_pm_machinfo;
-       ucb = pdev->ucb;
-       return 0;
-}
-
-static struct ucb1x00_driver collie_pm_ucb_driver = {
-       .add    = collie_pm_ucb_add,
-};
-
-static struct platform_device *collie_pm_device;
-
-static int __init collie_pm_init(void)
-{
-       int ret;
-
-       collie_pm_device = platform_device_alloc("sharpsl-pm", -1);
-       if (!collie_pm_device)
-               return -ENOMEM;
-
-       collie_pm_device->dev.platform_data = &collie_pm_machinfo;
-       ret = platform_device_add(collie_pm_device);
-
-       if (ret)
-               platform_device_put(collie_pm_device);
-
-       if (!ret)
-               ret = ucb1x00_register_driver(&collie_pm_ucb_driver);
-
-       return ret;
-}
-
-static void __exit collie_pm_exit(void)
-{
-       ucb1x00_unregister_driver(&collie_pm_ucb_driver);
-       platform_device_unregister(collie_pm_device);
-}
-
-module_init(collie_pm_init);
-module_exit(collie_pm_exit);
index 28cf3696797705a3b263f14854675498d279f068..506a5e5a9ad5b3f5e784fd0aec199fb639133cef 100644 (file)
@@ -54,7 +54,7 @@ EXPORT_SYMBOL(jornada_ssp_reverse);
  * timeout after <timeout> rounds. Needs mcu running before its called.
  *
  * returns : %mcu output on success
- *        : %-ETIMEOUT on timeout
+ *        : %-ETIMEDOUT on timeout
  */
 int jornada_ssp_byte(u8 byte)
 {
@@ -82,7 +82,7 @@ EXPORT_SYMBOL(jornada_ssp_byte);
  * jornada_ssp_inout - decide if input is command or trading byte
  *
  * returns : (jornada_ssp_byte(byte)) on success
- *         : %-ETIMEOUT on timeout failure
+ *         : %-ETIMEDOUT on timeout failure
  */
 int jornada_ssp_inout(u8 byte)
 {
diff --git a/arch/arm/mach-stmp378x/Makefile b/arch/arm/mach-stmp378x/Makefile
new file mode 100644 (file)
index 0000000..d156f76
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_ARCH_STMP378X) += stmp378x.o
+obj-$(CONFIG_MACH_STMP378X) += stmp378x_devb.o
diff --git a/arch/arm/mach-stmp378x/Makefile.boot b/arch/arm/mach-stmp378x/Makefile.boot
new file mode 100644 (file)
index 0000000..1568ad4
--- /dev/null
@@ -0,0 +1,3 @@
+   zreladdr-y  := 0x40008000
+params_phys-y  := 0x40000100
+initrd_phys-y  := 0x40800000
diff --git a/arch/arm/mach-stmp378x/include/mach/entry-macro.S b/arch/arm/mach-stmp378x/include/mach/entry-macro.S
new file mode 100644 (file)
index 0000000..731a922
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Low-level IRQ helper macros for Freescale STMP378X
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+               .macro  disable_fiq
+               .endm
+
+               .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
+
+               mov     \base, #0xf0000000      @ vm address of IRQ controller
+               ldr     \irqnr, [\base, #0x70]  @ HW_ICOLL_STAT
+               cmp     \irqnr, #0x7f
+               moveqs  \irqnr, #0              @ Zero flag set for no IRQ
+
+               .endm
+
+                .macro  get_irqnr_preamble, base, tmp
+                .endm
+
+                .macro  arch_ret_to_user, tmp1, tmp2
+                .endm
diff --git a/arch/arm/mach-stmp378x/include/mach/irqs.h b/arch/arm/mach-stmp378x/include/mach/irqs.h
new file mode 100644 (file)
index 0000000..cc59673
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Freescale STMP378X interrupts
+ *
+ * Copyright (C) 2005 Sigmatel Inc
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#define IRQ_DEBUG_UART                 0
+#define IRQ_COMMS_RX                   1
+#define IRQ_COMMS_TX                   1
+#define IRQ_SSP2_ERROR                 2
+#define IRQ_VDD5V                      3
+#define IRQ_HEADPHONE_SHORT            4
+#define IRQ_DAC_DMA                    5
+#define IRQ_DAC_ERROR                  6
+#define IRQ_ADC_DMA                    7
+#define IRQ_ADC_ERROR                  8
+#define IRQ_SPDIF_DMA                  9
+#define IRQ_SAIF2_DMA                  9
+#define IRQ_SPDIF_ERROR                        10
+#define IRQ_SAIF1_IRQ                  10
+#define IRQ_SAIF2_IRQ                  10
+#define IRQ_USB_CTRL                   11
+#define IRQ_USB_WAKEUP                 12
+#define IRQ_GPMI_DMA                   13
+#define IRQ_SSP1_DMA                   14
+#define IRQ_SSP_ERROR                  15
+#define IRQ_GPIO0                      16
+#define IRQ_GPIO1                      17
+#define IRQ_GPIO2                      18
+#define IRQ_SAIF1_DMA                  19
+#define IRQ_SSP2_DMA                   20
+#define IRQ_ECC8_IRQ                   21
+#define IRQ_RTC_ALARM                  22
+#define IRQ_UARTAPP_TX_DMA             23
+#define IRQ_UARTAPP_INTERNAL           24
+#define IRQ_UARTAPP_RX_DMA             25
+#define IRQ_I2C_DMA                    26
+#define IRQ_I2C_ERROR                  27
+#define IRQ_TIMER0                     28
+#define IRQ_TIMER1                     29
+#define IRQ_TIMER2                     30
+#define IRQ_TIMER3                     31
+#define IRQ_BATT_BRNOUT                        32
+#define IRQ_VDDD_BRNOUT                        33
+#define IRQ_VDDIO_BRNOUT               34
+#define IRQ_VDD18_BRNOUT               35
+#define IRQ_TOUCH_DETECT               36
+#define IRQ_LRADC_CH0                  37
+#define IRQ_LRADC_CH1                  38
+#define IRQ_LRADC_CH2                  39
+#define IRQ_LRADC_CH3                  40
+#define IRQ_LRADC_CH4                  41
+#define IRQ_LRADC_CH5                  42
+#define IRQ_LRADC_CH6                  43
+#define IRQ_LRADC_CH7                  44
+#define IRQ_LCDIF_DMA                  45
+#define IRQ_LCDIF_ERROR                        46
+#define IRQ_DIGCTL_DEBUG_TRAP          47
+#define IRQ_RTC_1MSEC                  48
+#define IRQ_DRI_DMA                    49
+#define IRQ_DRI_ATTENTION              50
+#define IRQ_GPMI_ATTENTION             51
+#define IRQ_IR                         52
+#define IRQ_DCP_VMI                    53
+#define IRQ_DCP                                54
+#define IRQ_BCH                                56
+#define IRQ_PXP                                57
+#define IRQ_UARTAPP2_TX_DMA            58
+#define IRQ_UARTAPP2_INTERNAL          59
+#define IRQ_UARTAPP2_RX_DMA            60
+#define IRQ_VDAC_DETECT                        61
+#define IRQ_VDD5V_DROOP                        64
+#define IRQ_DCDC4P2_BO                 65
+
+
+#define NR_REAL_IRQS   128
+#define NR_IRQS                (NR_REAL_IRQS + 32 * 3)
+
+/* All interrupts are FIQ capable */
+#define FIQ_START              IRQ_DEBUG_UART
+
+/* Hard disk IRQ is a GPMI attention IRQ */
+#define IRQ_HARDDISK           IRQ_GPMI_ATTENTION
diff --git a/arch/arm/mach-stmp378x/include/mach/pins.h b/arch/arm/mach-stmp378x/include/mach/pins.h
new file mode 100644 (file)
index 0000000..93f952d
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Freescale STMP378X SoC pin multiplexing
+ *
+ * Author: Vladislav Buzov <vbuzov@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __ASM_ARCH_PINS_H
+#define __ASM_ARCH_PINS_H
+
+/*
+ * Define all STMP378x pins, a pin name corresponds to a STMP378x hardware
+ * interface  this pin belongs to.
+ */
+
+/* Bank 0 */
+#define PINID_GPMI_D00         STMP3XXX_PINID(0, 0)
+#define PINID_GPMI_D01         STMP3XXX_PINID(0, 1)
+#define PINID_GPMI_D02         STMP3XXX_PINID(0, 2)
+#define PINID_GPMI_D03         STMP3XXX_PINID(0, 3)
+#define PINID_GPMI_D04         STMP3XXX_PINID(0, 4)
+#define PINID_GPMI_D05         STMP3XXX_PINID(0, 5)
+#define PINID_GPMI_D06         STMP3XXX_PINID(0, 6)
+#define PINID_GPMI_D07         STMP3XXX_PINID(0, 7)
+#define PINID_GPMI_D08         STMP3XXX_PINID(0, 8)
+#define PINID_GPMI_D09         STMP3XXX_PINID(0, 9)
+#define PINID_GPMI_D10         STMP3XXX_PINID(0, 10)
+#define PINID_GPMI_D11         STMP3XXX_PINID(0, 11)
+#define PINID_GPMI_D12         STMP3XXX_PINID(0, 12)
+#define PINID_GPMI_D13         STMP3XXX_PINID(0, 13)
+#define PINID_GPMI_D14         STMP3XXX_PINID(0, 14)
+#define PINID_GPMI_D15         STMP3XXX_PINID(0, 15)
+#define PINID_GPMI_CLE         STMP3XXX_PINID(0, 16)
+#define PINID_GPMI_ALE         STMP3XXX_PINID(0, 17)
+#define PINID_GMPI_CE2N                STMP3XXX_PINID(0, 18)
+#define PINID_GPMI_RDY0                STMP3XXX_PINID(0, 19)
+#define PINID_GPMI_RDY1                STMP3XXX_PINID(0, 20)
+#define PINID_GPMI_RDY2                STMP3XXX_PINID(0, 21)
+#define PINID_GPMI_RDY3                STMP3XXX_PINID(0, 22)
+#define PINID_GPMI_WPN         STMP3XXX_PINID(0, 23)
+#define PINID_GPMI_WRN         STMP3XXX_PINID(0, 24)
+#define PINID_GPMI_RDN         STMP3XXX_PINID(0, 25)
+#define PINID_AUART1_CTS       STMP3XXX_PINID(0, 26)
+#define PINID_AUART1_RTS       STMP3XXX_PINID(0, 27)
+#define PINID_AUART1_RX                STMP3XXX_PINID(0, 28)
+#define PINID_AUART1_TX                STMP3XXX_PINID(0, 29)
+#define PINID_I2C_SCL          STMP3XXX_PINID(0, 30)
+#define PINID_I2C_SDA          STMP3XXX_PINID(0, 31)
+
+/* Bank 1 */
+#define PINID_LCD_D00          STMP3XXX_PINID(1, 0)
+#define PINID_LCD_D01          STMP3XXX_PINID(1, 1)
+#define PINID_LCD_D02          STMP3XXX_PINID(1, 2)
+#define PINID_LCD_D03          STMP3XXX_PINID(1, 3)
+#define PINID_LCD_D04          STMP3XXX_PINID(1, 4)
+#define PINID_LCD_D05          STMP3XXX_PINID(1, 5)
+#define PINID_LCD_D06          STMP3XXX_PINID(1, 6)
+#define PINID_LCD_D07          STMP3XXX_PINID(1, 7)
+#define PINID_LCD_D08          STMP3XXX_PINID(1, 8)
+#define PINID_LCD_D09          STMP3XXX_PINID(1, 9)
+#define PINID_LCD_D10          STMP3XXX_PINID(1, 10)
+#define PINID_LCD_D11          STMP3XXX_PINID(1, 11)
+#define PINID_LCD_D12          STMP3XXX_PINID(1, 12)
+#define PINID_LCD_D13          STMP3XXX_PINID(1, 13)
+#define PINID_LCD_D14          STMP3XXX_PINID(1, 14)
+#define PINID_LCD_D15          STMP3XXX_PINID(1, 15)
+#define PINID_LCD_D16          STMP3XXX_PINID(1, 16)
+#define PINID_LCD_D17          STMP3XXX_PINID(1, 17)
+#define PINID_LCD_RESET                STMP3XXX_PINID(1, 18)
+#define PINID_LCD_RS           STMP3XXX_PINID(1, 19)
+#define PINID_LCD_WR           STMP3XXX_PINID(1, 20)
+#define PINID_LCD_CS           STMP3XXX_PINID(1, 21)
+#define PINID_LCD_DOTCK                STMP3XXX_PINID(1, 22)
+#define PINID_LCD_ENABLE       STMP3XXX_PINID(1, 23)
+#define PINID_LCD_HSYNC                STMP3XXX_PINID(1, 24)
+#define PINID_LCD_VSYNC                STMP3XXX_PINID(1, 25)
+#define PINID_PWM0             STMP3XXX_PINID(1, 26)
+#define PINID_PWM1             STMP3XXX_PINID(1, 27)
+#define PINID_PWM2             STMP3XXX_PINID(1, 28)
+#define PINID_PWM3             STMP3XXX_PINID(1, 29)
+#define PINID_PWM4             STMP3XXX_PINID(1, 30)
+
+/* Bank 2 */
+#define PINID_SSP1_CMD         STMP3XXX_PINID(2, 0)
+#define PINID_SSP1_DETECT      STMP3XXX_PINID(2, 1)
+#define PINID_SSP1_DATA0       STMP3XXX_PINID(2, 2)
+#define PINID_SSP1_DATA1       STMP3XXX_PINID(2, 3)
+#define PINID_SSP1_DATA2       STMP3XXX_PINID(2, 4)
+#define PINID_SSP1_DATA3       STMP3XXX_PINID(2, 5)
+#define PINID_SSP1_SCK         STMP3XXX_PINID(2, 6)
+#define PINID_ROTARYA          STMP3XXX_PINID(2, 7)
+#define PINID_ROTARYB          STMP3XXX_PINID(2, 8)
+#define PINID_EMI_A00          STMP3XXX_PINID(2, 9)
+#define PINID_EMI_A01          STMP3XXX_PINID(2, 10)
+#define PINID_EMI_A02          STMP3XXX_PINID(2, 11)
+#define PINID_EMI_A03          STMP3XXX_PINID(2, 12)
+#define PINID_EMI_A04          STMP3XXX_PINID(2, 13)
+#define PINID_EMI_A05          STMP3XXX_PINID(2, 14)
+#define PINID_EMI_A06          STMP3XXX_PINID(2, 15)
+#define PINID_EMI_A07          STMP3XXX_PINID(2, 16)
+#define PINID_EMI_A08          STMP3XXX_PINID(2, 17)
+#define PINID_EMI_A09          STMP3XXX_PINID(2, 18)
+#define PINID_EMI_A10          STMP3XXX_PINID(2, 19)
+#define PINID_EMI_A11          STMP3XXX_PINID(2, 20)
+#define PINID_EMI_A12          STMP3XXX_PINID(2, 21)
+#define PINID_EMI_BA0          STMP3XXX_PINID(2, 22)
+#define PINID_EMI_BA1          STMP3XXX_PINID(2, 23)
+#define PINID_EMI_CASN         STMP3XXX_PINID(2, 24)
+#define PINID_EMI_CE0N         STMP3XXX_PINID(2, 25)
+#define PINID_EMI_CE1N         STMP3XXX_PINID(2, 26)
+#define PINID_GPMI_CE1N                STMP3XXX_PINID(2, 27)
+#define PINID_GPMI_CE0N                STMP3XXX_PINID(2, 28)
+#define PINID_EMI_CKE          STMP3XXX_PINID(2, 29)
+#define PINID_EMI_RASN         STMP3XXX_PINID(2, 30)
+#define PINID_EMI_WEN          STMP3XXX_PINID(2, 31)
+
+/* Bank 3 */
+#define PINID_EMI_D00          STMP3XXX_PINID(3, 0)
+#define PINID_EMI_D01          STMP3XXX_PINID(3, 1)
+#define PINID_EMI_D02          STMP3XXX_PINID(3, 2)
+#define PINID_EMI_D03          STMP3XXX_PINID(3, 3)
+#define PINID_EMI_D04          STMP3XXX_PINID(3, 4)
+#define PINID_EMI_D05          STMP3XXX_PINID(3, 5)
+#define PINID_EMI_D06          STMP3XXX_PINID(3, 6)
+#define PINID_EMI_D07          STMP3XXX_PINID(3, 7)
+#define PINID_EMI_D08          STMP3XXX_PINID(3, 8)
+#define PINID_EMI_D09          STMP3XXX_PINID(3, 9)
+#define PINID_EMI_D10          STMP3XXX_PINID(3, 10)
+#define PINID_EMI_D11          STMP3XXX_PINID(3, 11)
+#define PINID_EMI_D12          STMP3XXX_PINID(3, 12)
+#define PINID_EMI_D13          STMP3XXX_PINID(3, 13)
+#define PINID_EMI_D14          STMP3XXX_PINID(3, 14)
+#define PINID_EMI_D15          STMP3XXX_PINID(3, 15)
+#define PINID_EMI_DQM0         STMP3XXX_PINID(3, 16)
+#define PINID_EMI_DQM1         STMP3XXX_PINID(3, 17)
+#define PINID_EMI_DQS0         STMP3XXX_PINID(3, 18)
+#define PINID_EMI_DQS1         STMP3XXX_PINID(3, 19)
+#define PINID_EMI_CLK          STMP3XXX_PINID(3, 20)
+#define PINID_EMI_CLKN         STMP3XXX_PINID(3, 21)
+
+#endif /* __ASM_ARCH_PINS_H */
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-apbh.h b/arch/arm/mach-stmp378x/include/mach/regs-apbh.h
new file mode 100644 (file)
index 0000000..dbcf85b
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * stmp378x: APBH register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef _MACH_REGS_APBH
+#define _MACH_REGS_APBH
+
+#define REGS_APBH_BASE (STMP3XXX_REGS_BASE + 0x4000)
+#define REGS_APBH_PHYS 0x80004000
+#define REGS_APBH_SIZE 0x2000
+
+#define HW_APBH_CTRL0          0x0
+#define BM_APBH_CTRL0_RESET_CHANNEL    0x00FF0000
+#define BP_APBH_CTRL0_RESET_CHANNEL    16
+#define BM_APBH_CTRL0_CLKGATE  0x40000000
+#define BM_APBH_CTRL0_SFTRST   0x80000000
+
+#define HW_APBH_CTRL1          0x10
+#define BM_APBH_CTRL1_CH0_CMDCMPLT_IRQ 0x00000001
+#define BP_APBH_CTRL1_CH0_CMDCMPLT_IRQ 0
+
+#define HW_APBH_CTRL2          0x20
+
+#define HW_APBH_DEVSEL         0x30
+
+#define HW_APBH_CH0_NXTCMDAR   (0x50 + 0 * 0x70)
+#define HW_APBH_CH1_NXTCMDAR   (0x50 + 1 * 0x70)
+#define HW_APBH_CH2_NXTCMDAR   (0x50 + 2 * 0x70)
+#define HW_APBH_CH3_NXTCMDAR   (0x50 + 3 * 0x70)
+#define HW_APBH_CH4_NXTCMDAR   (0x50 + 4 * 0x70)
+#define HW_APBH_CH5_NXTCMDAR   (0x50 + 5 * 0x70)
+#define HW_APBH_CH6_NXTCMDAR   (0x50 + 6 * 0x70)
+#define HW_APBH_CH7_NXTCMDAR   (0x50 + 7 * 0x70)
+#define HW_APBH_CH8_NXTCMDAR   (0x50 + 8 * 0x70)
+#define HW_APBH_CH9_NXTCMDAR   (0x50 + 9 * 0x70)
+#define HW_APBH_CH10_NXTCMDAR  (0x50 + 10 * 0x70)
+#define HW_APBH_CH11_NXTCMDAR  (0x50 + 11 * 0x70)
+#define HW_APBH_CH12_NXTCMDAR  (0x50 + 12 * 0x70)
+#define HW_APBH_CH13_NXTCMDAR  (0x50 + 13 * 0x70)
+#define HW_APBH_CH14_NXTCMDAR  (0x50 + 14 * 0x70)
+#define HW_APBH_CH15_NXTCMDAR  (0x50 + 15 * 0x70)
+
+#define HW_APBH_CHn_NXTCMDAR   0x50
+
+#define BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER    0
+#define BV_APBH_CHn_CMD_COMMAND__DMA_WRITE      1
+#define BV_APBH_CHn_CMD_COMMAND__DMA_READ       2
+#define BV_APBH_CHn_CMD_COMMAND__DMA_SENSE      3
+#define BM_APBH_CHn_CMD_COMMAND        0x00000003
+#define BP_APBH_CHn_CMD_COMMAND        0
+#define BM_APBH_CHn_CMD_CHAIN  0x00000004
+#define BM_APBH_CHn_CMD_IRQONCMPLT     0x00000008
+#define BM_APBH_CHn_CMD_NANDLOCK       0x00000010
+#define BM_APBH_CHn_CMD_NANDWAIT4READY 0x00000020
+#define BM_APBH_CHn_CMD_SEMAPHORE      0x00000040
+#define BM_APBH_CHn_CMD_WAIT4ENDCMD    0x00000080
+#define BM_APBH_CHn_CMD_CMDWORDS       0x0000F000
+#define BP_APBH_CHn_CMD_CMDWORDS       12
+#define BM_APBH_CHn_CMD_XFER_COUNT     0xFFFF0000
+#define BP_APBH_CHn_CMD_XFER_COUNT     16
+
+#define HW_APBH_CH0_SEMA       (0x80 + 0 * 0x70)
+#define HW_APBH_CH1_SEMA       (0x80 + 1 * 0x70)
+#define HW_APBH_CH2_SEMA       (0x80 + 2 * 0x70)
+#define HW_APBH_CH3_SEMA       (0x80 + 3 * 0x70)
+#define HW_APBH_CH4_SEMA       (0x80 + 4 * 0x70)
+#define HW_APBH_CH5_SEMA       (0x80 + 5 * 0x70)
+#define HW_APBH_CH6_SEMA       (0x80 + 6 * 0x70)
+#define HW_APBH_CH7_SEMA       (0x80 + 7 * 0x70)
+#define HW_APBH_CH8_SEMA       (0x80 + 8 * 0x70)
+#define HW_APBH_CH9_SEMA       (0x80 + 9 * 0x70)
+#define HW_APBH_CH10_SEMA      (0x80 + 10 * 0x70)
+#define HW_APBH_CH11_SEMA      (0x80 + 11 * 0x70)
+#define HW_APBH_CH12_SEMA      (0x80 + 12 * 0x70)
+#define HW_APBH_CH13_SEMA      (0x80 + 13 * 0x70)
+#define HW_APBH_CH14_SEMA      (0x80 + 14 * 0x70)
+#define HW_APBH_CH15_SEMA      (0x80 + 15 * 0x70)
+
+#define HW_APBH_CHn_SEMA       0x80
+#define BM_APBH_CHn_SEMA_INCREMENT_SEMA        0x000000FF
+#define BP_APBH_CHn_SEMA_INCREMENT_SEMA        0
+#define BM_APBH_CHn_SEMA_PHORE 0x00FF0000
+#define BP_APBH_CHn_SEMA_PHORE 16
+
+#endif
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-apbx.h b/arch/arm/mach-stmp378x/include/mach/regs-apbx.h
new file mode 100644 (file)
index 0000000..3b934a4
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * stmp378x: APBX register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef _MACH_REGS_APBX
+#define _MACH_REGS_APBX
+
+#define REGS_APBX_BASE (STMP3XXX_REGS_BASE + 0x24000)
+#define REGS_APBX_PHYS 0x80024000
+#define REGS_APBX_SIZE 0x2000
+
+#define HW_APBX_CTRL0          0x0
+#define BM_APBX_CTRL0_CLKGATE  0x40000000
+#define BM_APBX_CTRL0_SFTRST   0x80000000
+
+#define HW_APBX_CTRL1          0x10
+
+#define HW_APBX_CTRL2          0x20
+
+#define HW_APBX_CHANNEL_CTRL   0x30
+#define BM_APBX_CHANNEL_CTRL_RESET_CHANNEL     0xFFFF0000
+#define BP_APBX_CHANNEL_CTRL_RESET_CHANNEL     16
+
+#define HW_APBX_DEVSEL         0x40
+
+#define HW_APBX_CH0_NXTCMDAR   (0x110 + 0 * 0x70)
+#define HW_APBX_CH1_NXTCMDAR   (0x110 + 1 * 0x70)
+#define HW_APBX_CH2_NXTCMDAR   (0x110 + 2 * 0x70)
+#define HW_APBX_CH3_NXTCMDAR   (0x110 + 3 * 0x70)
+#define HW_APBX_CH4_NXTCMDAR   (0x110 + 4 * 0x70)
+#define HW_APBX_CH5_NXTCMDAR   (0x110 + 5 * 0x70)
+#define HW_APBX_CH6_NXTCMDAR   (0x110 + 6 * 0x70)
+#define HW_APBX_CH7_NXTCMDAR   (0x110 + 7 * 0x70)
+#define HW_APBX_CH8_NXTCMDAR   (0x110 + 8 * 0x70)
+#define HW_APBX_CH9_NXTCMDAR   (0x110 + 9 * 0x70)
+#define HW_APBX_CH10_NXTCMDAR  (0x110 + 10 * 0x70)
+#define HW_APBX_CH11_NXTCMDAR  (0x110 + 11 * 0x70)
+#define HW_APBX_CH12_NXTCMDAR  (0x110 + 12 * 0x70)
+#define HW_APBX_CH13_NXTCMDAR  (0x110 + 13 * 0x70)
+#define HW_APBX_CH14_NXTCMDAR  (0x110 + 14 * 0x70)
+#define HW_APBX_CH15_NXTCMDAR  (0x110 + 15 * 0x70)
+
+#define HW_APBX_CHn_NXTCMDAR   0x110
+#define BM_APBX_CHn_CMD_COMMAND        0x00000003
+#define BP_APBX_CHn_CMD_COMMAND        0
+#define BV_APBX_CHn_CMD_COMMAND__NO_DMA_XFER    0
+#define BV_APBX_CHn_CMD_COMMAND__DMA_WRITE      1
+#define BV_APBX_CHn_CMD_COMMAND__DMA_READ       2
+#define BV_APBX_CHn_CMD_COMMAND__DMA_SENSE      3
+#define BM_APBX_CHn_CMD_CHAIN  0x00000004
+#define BM_APBX_CHn_CMD_IRQONCMPLT     0x00000008
+#define BM_APBX_CHn_CMD_SEMAPHORE      0x00000040
+#define BM_APBX_CHn_CMD_WAIT4ENDCMD    0x00000080
+#define BM_APBX_CHn_CMD_HALTONTERMINATE        0x00000100
+#define BM_APBX_CHn_CMD_CMDWORDS       0x0000F000
+#define BP_APBX_CHn_CMD_CMDWORDS       12
+#define BM_APBX_CHn_CMD_XFER_COUNT     0xFFFF0000
+#define BP_APBX_CHn_CMD_XFER_COUNT     16
+
+#define HW_APBX_CH0_BAR                (0x130 + 0 * 0x70)
+#define HW_APBX_CH1_BAR                (0x130 + 1 * 0x70)
+#define HW_APBX_CH2_BAR                (0x130 + 2 * 0x70)
+#define HW_APBX_CH3_BAR                (0x130 + 3 * 0x70)
+#define HW_APBX_CH4_BAR                (0x130 + 4 * 0x70)
+#define HW_APBX_CH5_BAR                (0x130 + 5 * 0x70)
+#define HW_APBX_CH6_BAR                (0x130 + 6 * 0x70)
+#define HW_APBX_CH7_BAR                (0x130 + 7 * 0x70)
+#define HW_APBX_CH8_BAR                (0x130 + 8 * 0x70)
+#define HW_APBX_CH9_BAR                (0x130 + 9 * 0x70)
+#define HW_APBX_CH10_BAR               (0x130 + 10 * 0x70)
+#define HW_APBX_CH11_BAR               (0x130 + 11 * 0x70)
+#define HW_APBX_CH12_BAR               (0x130 + 12 * 0x70)
+#define HW_APBX_CH13_BAR               (0x130 + 13 * 0x70)
+#define HW_APBX_CH14_BAR               (0x130 + 14 * 0x70)
+#define HW_APBX_CH15_BAR               (0x130 + 15 * 0x70)
+
+#define HW_APBX_CHn_BAR                0x130
+
+#define HW_APBX_CH0_SEMA       (0x140 + 0 * 0x70)
+#define HW_APBX_CH1_SEMA       (0x140 + 1 * 0x70)
+#define HW_APBX_CH2_SEMA       (0x140 + 2 * 0x70)
+#define HW_APBX_CH3_SEMA       (0x140 + 3 * 0x70)
+#define HW_APBX_CH4_SEMA       (0x140 + 4 * 0x70)
+#define HW_APBX_CH5_SEMA       (0x140 + 5 * 0x70)
+#define HW_APBX_CH6_SEMA       (0x140 + 6 * 0x70)
+#define HW_APBX_CH7_SEMA       (0x140 + 7 * 0x70)
+#define HW_APBX_CH8_SEMA       (0x140 + 8 * 0x70)
+#define HW_APBX_CH9_SEMA       (0x140 + 9 * 0x70)
+#define HW_APBX_CH10_SEMA      (0x140 + 10 * 0x70)
+#define HW_APBX_CH11_SEMA      (0x140 + 11 * 0x70)
+#define HW_APBX_CH12_SEMA      (0x140 + 12 * 0x70)
+#define HW_APBX_CH13_SEMA      (0x140 + 13 * 0x70)
+#define HW_APBX_CH14_SEMA      (0x140 + 14 * 0x70)
+#define HW_APBX_CH15_SEMA      (0x140 + 15 * 0x70)
+
+#define HW_APBX_CHn_SEMA       0x140
+#define BM_APBX_CHn_SEMA_INCREMENT_SEMA        0x000000FF
+#define BP_APBX_CHn_SEMA_INCREMENT_SEMA        0
+#define BM_APBX_CHn_SEMA_PHORE 0x00FF0000
+#define BP_APBX_CHn_SEMA_PHORE 16
+
+#endif
+
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-audioin.h b/arch/arm/mach-stmp378x/include/mach/regs-audioin.h
new file mode 100644 (file)
index 0000000..641ac61
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * stmp378x: AUDIOIN register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_AUDIOIN_BASE      (STMP3XXX_REGS_BASE + 0x4C000)
+#define REGS_AUDIOIN_PHYS      0x8004C000
+#define REGS_AUDIOIN_SIZE      0x2000
+
+#define HW_AUDIOIN_CTRL                0x0
+#define BM_AUDIOIN_CTRL_RUN    0x00000001
+#define BP_AUDIOIN_CTRL_RUN    0
+#define BM_AUDIOIN_CTRL_FIFO_ERROR_IRQ_EN      0x00000002
+#define BM_AUDIOIN_CTRL_FIFO_OVERFLOW_IRQ      0x00000004
+#define BM_AUDIOIN_CTRL_FIFO_UNDERFLOW_IRQ     0x00000008
+#define BM_AUDIOIN_CTRL_WORD_LENGTH    0x00000020
+#define BM_AUDIOIN_CTRL_CLKGATE        0x40000000
+#define BM_AUDIOIN_CTRL_SFTRST 0x80000000
+
+#define HW_AUDIOIN_STAT                0x10
+
+#define HW_AUDIOIN_ADCSRR      0x20
+
+#define HW_AUDIOIN_ADCVOLUME   0x30
+#define BM_AUDIOIN_ADCVOLUME_VOLUME_RIGHT      0x000000FF
+#define BP_AUDIOIN_ADCVOLUME_VOLUME_RIGHT      0
+#define BM_AUDIOIN_ADCVOLUME_VOLUME_LEFT       0x00FF0000
+#define BP_AUDIOIN_ADCVOLUME_VOLUME_LEFT       16
+
+#define HW_AUDIOIN_ADCDEBUG    0x40
+
+#define HW_AUDIOIN_ADCVOL      0x50
+#define BM_AUDIOIN_ADCVOL_GAIN_RIGHT   0x0000000F
+#define BP_AUDIOIN_ADCVOL_GAIN_RIGHT   0
+#define BM_AUDIOIN_ADCVOL_SELECT_RIGHT 0x00000030
+#define BP_AUDIOIN_ADCVOL_SELECT_RIGHT 4
+#define BM_AUDIOIN_ADCVOL_GAIN_LEFT    0x00000F00
+#define BP_AUDIOIN_ADCVOL_GAIN_LEFT    8
+#define BM_AUDIOIN_ADCVOL_SELECT_LEFT  0x00003000
+#define BP_AUDIOIN_ADCVOL_SELECT_LEFT  12
+#define BM_AUDIOIN_ADCVOL_MUTE 0x01000000
+
+#define HW_AUDIOIN_MICLINE     0x60
+
+#define HW_AUDIOIN_ANACLKCTRL  0x70
+#define BM_AUDIOIN_ANACLKCTRL_CLKGATE  0x80000000
+
+#define HW_AUDIOIN_DATA                0x80
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-audioout.h b/arch/arm/mach-stmp378x/include/mach/regs-audioout.h
new file mode 100644 (file)
index 0000000..f533e23
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * stmp378x: AUDIOOUT register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_AUDIOOUT_BASE     (STMP3XXX_REGS_BASE + 0x48000)
+#define REGS_AUDIOOUT_PHYS     0x80048000
+#define REGS_AUDIOOUT_SIZE     0x2000
+
+#define HW_AUDIOOUT_CTRL       0x0
+#define BM_AUDIOOUT_CTRL_RUN   0x00000001
+#define BP_AUDIOOUT_CTRL_RUN   0
+#define BM_AUDIOOUT_CTRL_FIFO_ERROR_IRQ_EN     0x00000002
+#define BM_AUDIOOUT_CTRL_FIFO_OVERFLOW_IRQ     0x00000004
+#define BM_AUDIOOUT_CTRL_FIFO_UNDERFLOW_IRQ    0x00000008
+#define BM_AUDIOOUT_CTRL_WORD_LENGTH   0x00000040
+#define BM_AUDIOOUT_CTRL_CLKGATE       0x40000000
+#define BM_AUDIOOUT_CTRL_SFTRST        0x80000000
+
+#define HW_AUDIOOUT_STAT       0x10
+
+#define HW_AUDIOOUT_DACSRR     0x20
+#define BM_AUDIOOUT_DACSRR_SRC_FRAC    0x00001FFF
+#define BP_AUDIOOUT_DACSRR_SRC_FRAC    0
+#define BM_AUDIOOUT_DACSRR_SRC_INT     0x001F0000
+#define BP_AUDIOOUT_DACSRR_SRC_INT     16
+#define BM_AUDIOOUT_DACSRR_SRC_HOLD    0x07000000
+#define BP_AUDIOOUT_DACSRR_SRC_HOLD    24
+#define BM_AUDIOOUT_DACSRR_BASEMULT    0x70000000
+#define BP_AUDIOOUT_DACSRR_BASEMULT    28
+
+#define HW_AUDIOOUT_DACVOLUME  0x30
+#define BM_AUDIOOUT_DACVOLUME_MUTE_RIGHT       0x00000100
+#define BM_AUDIOOUT_DACVOLUME_MUTE_LEFT        0x01000000
+#define BM_AUDIOOUT_DACVOLUME_EN_ZCD   0x02000000
+
+#define HW_AUDIOOUT_DACDEBUG   0x40
+
+#define HW_AUDIOOUT_HPVOL      0x50
+#define BM_AUDIOOUT_HPVOL_MUTE 0x01000000
+#define BM_AUDIOOUT_HPVOL_EN_MSTR_ZCD  0x02000000
+
+#define HW_AUDIOOUT_PWRDN      0x70
+#define BM_AUDIOOUT_PWRDN_HEADPHONE    0x00000001
+#define BP_AUDIOOUT_PWRDN_HEADPHONE    0
+#define BM_AUDIOOUT_PWRDN_CAPLESS      0x00000010
+#define BM_AUDIOOUT_PWRDN_ADC  0x00000100
+#define BM_AUDIOOUT_PWRDN_DAC  0x00001000
+#define BM_AUDIOOUT_PWRDN_RIGHT_ADC    0x00010000
+#define BM_AUDIOOUT_PWRDN_SPEAKER      0x01000000
+
+#define HW_AUDIOOUT_REFCTRL    0x80
+#define BM_AUDIOOUT_REFCTRL_VAG_VAL    0x000000F0
+#define BP_AUDIOOUT_REFCTRL_VAG_VAL    4
+#define BM_AUDIOOUT_REFCTRL_ADC_REFVAL 0x00000F00
+#define BP_AUDIOOUT_REFCTRL_ADC_REFVAL 8
+#define BM_AUDIOOUT_REFCTRL_ADJ_VAG    0x00001000
+#define BM_AUDIOOUT_REFCTRL_ADJ_ADC    0x00002000
+#define BM_AUDIOOUT_REFCTRL_BIAS_CTRL  0x00030000
+#define BP_AUDIOOUT_REFCTRL_BIAS_CTRL  16
+#define BM_AUDIOOUT_REFCTRL_LOW_PWR    0x00080000
+#define BM_AUDIOOUT_REFCTRL_VBG_ADJ    0x00700000
+#define BP_AUDIOOUT_REFCTRL_VBG_ADJ    20
+#define BM_AUDIOOUT_REFCTRL_XTAL_BGR_BIAS      0x01000000
+#define BM_AUDIOOUT_REFCTRL_RAISE_REF  0x02000000
+
+#define HW_AUDIOOUT_ANACTRL    0x90
+#define BM_AUDIOOUT_ANACTRL_HP_CLASSAB 0x00000010
+#define BM_AUDIOOUT_ANACTRL_HP_HOLD_GND        0x00000020
+
+#define HW_AUDIOOUT_TEST       0xA0
+#define BM_AUDIOOUT_TEST_HP_I1_ADJ     0x00C00000
+#define BP_AUDIOOUT_TEST_HP_I1_ADJ     22
+
+#define HW_AUDIOOUT_BISTCTRL   0xB0
+
+#define HW_AUDIOOUT_BISTSTAT0  0xC0
+
+#define HW_AUDIOOUT_BISTSTAT1  0xD0
+
+#define HW_AUDIOOUT_ANACLKCTRL 0xE0
+#define BM_AUDIOOUT_ANACLKCTRL_CLKGATE 0x80000000
+
+#define HW_AUDIOOUT_DATA       0xF0
+
+#define HW_AUDIOOUT_SPEAKERCTRL        0x100
+#define BM_AUDIOOUT_SPEAKERCTRL_MUTE   0x01000000
+
+#define HW_AUDIOOUT_VERSION    0x200
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-bch.h b/arch/arm/mach-stmp378x/include/mach/regs-bch.h
new file mode 100644 (file)
index 0000000..532d246
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * stmp378x: BCH register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_BCH_BASE  (STMP3XXX_REGS_BASE + 0xA000)
+#define REGS_BCH_PHYS  0x8000A000
+#define REGS_BCH_SIZE  0x2000
+
+#define HW_BCH_CTRL            0x0
+#define BM_BCH_CTRL_COMPLETE_IRQ       0x00000001
+#define BP_BCH_CTRL_COMPLETE_IRQ       0
+#define BM_BCH_CTRL_COMPLETE_IRQ_EN    0x00000100
+
+#define HW_BCH_STATUS0         0x10
+#define BM_BCH_STATUS0_UNCORRECTABLE   0x00000004
+#define BM_BCH_STATUS0_CORRECTED       0x00000008
+#define BM_BCH_STATUS0_STATUS_BLK0     0x0000FF00
+#define BP_BCH_STATUS0_STATUS_BLK0     8
+#define BM_BCH_STATUS0_COMPLETED_CE    0x000F0000
+#define BP_BCH_STATUS0_COMPLETED_CE    16
+
+#define HW_BCH_LAYOUTSELECT    0x70
+
+#define HW_BCH_FLASH0LAYOUT0   0x80
+#define BM_BCH_FLASH0LAYOUT0_DATA0_SIZE        0x00000FFF
+#define BP_BCH_FLASH0LAYOUT0_DATA0_SIZE        0
+#define BM_BCH_FLASH0LAYOUT0_ECC0      0x0000F000
+#define BP_BCH_FLASH0LAYOUT0_ECC0      12
+#define BM_BCH_FLASH0LAYOUT0_META_SIZE 0x00FF0000
+#define BP_BCH_FLASH0LAYOUT0_META_SIZE 16
+#define BM_BCH_FLASH0LAYOUT0_NBLOCKS   0xFF000000
+#define BP_BCH_FLASH0LAYOUT0_NBLOCKS   24
+#define BM_BCH_FLASH0LAYOUT1_DATAN_SIZE        0x00000FFF
+#define BP_BCH_FLASH0LAYOUT1_DATAN_SIZE        0
+#define BM_BCH_FLASH0LAYOUT1_ECCN      0x0000F000
+#define BP_BCH_FLASH0LAYOUT1_ECCN      12
+#define BM_BCH_FLASH0LAYOUT1_PAGE_SIZE 0xFFFF0000
+#define BP_BCH_FLASH0LAYOUT1_PAGE_SIZE 16
+
+#define HW_BCH_BLOCKNAME       0x150
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-clkctrl.h b/arch/arm/mach-stmp378x/include/mach/regs-clkctrl.h
new file mode 100644 (file)
index 0000000..7c546af
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * stmp378x: CLKCTRL register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef _MACH_REGS_CLKCTRL
+#define _MACH_REGS_CLKCTRL
+
+#define REGS_CLKCTRL_BASE      (STMP3XXX_REGS_BASE + 0x40000)
+#define REGS_CLKCTRL_PHYS      0x80040000
+#define REGS_CLKCTRL_SIZE      0x2000
+
+#define HW_CLKCTRL_PLLCTRL0    0x0
+#define BM_CLKCTRL_PLLCTRL0_EN_USB_CLKS        0x00040000
+
+#define HW_CLKCTRL_CPU         0x20
+#define BM_CLKCTRL_CPU_DIV_CPU 0x0000003F
+#define BP_CLKCTRL_CPU_DIV_CPU 0
+
+#define HW_CLKCTRL_HBUS                0x30
+#define BM_CLKCTRL_HBUS_DIV    0x0000001F
+#define BP_CLKCTRL_HBUS_DIV    0
+#define BM_CLKCTRL_HBUS_DIV_FRAC_EN    0x00000020
+
+#define HW_CLKCTRL_XBUS                0x40
+
+#define HW_CLKCTRL_XTAL                0x50
+#define BM_CLKCTRL_XTAL_DRI_CLK24M_GATE        0x10000000
+
+#define HW_CLKCTRL_PIX         0x60
+#define BM_CLKCTRL_PIX_DIV     0x00000FFF
+#define BP_CLKCTRL_PIX_DIV     0
+#define BM_CLKCTRL_PIX_CLKGATE 0x80000000
+
+#define HW_CLKCTRL_SSP         0x70
+
+#define HW_CLKCTRL_GPMI                0x80
+
+#define HW_CLKCTRL_SPDIF       0x90
+
+#define HW_CLKCTRL_EMI         0xA0
+#define BM_CLKCTRL_EMI_DIV_EMI 0x0000003F
+#define BP_CLKCTRL_EMI_DIV_EMI 0
+#define BM_CLKCTRL_EMI_DCC_RESYNC_ENABLE       0x00010000
+#define BM_CLKCTRL_EMI_BUSY_DCC_RESYNC 0x00020000
+#define BM_CLKCTRL_EMI_BUSY_REF_EMI    0x10000000
+#define BM_CLKCTRL_EMI_BUSY_REF_XTAL   0x20000000
+
+#define HW_CLKCTRL_IR          0xB0
+
+#define HW_CLKCTRL_SAIF                0xC0
+
+#define HW_CLKCTRL_TV          0xD0
+
+#define HW_CLKCTRL_ETM         0xE0
+
+#define HW_CLKCTRL_FRAC                0xF0
+#define BM_CLKCTRL_FRAC_EMIFRAC        0x00003F00
+#define BP_CLKCTRL_FRAC_EMIFRAC        8
+#define BM_CLKCTRL_FRAC_PIXFRAC        0x003F0000
+#define BP_CLKCTRL_FRAC_PIXFRAC        16
+#define BM_CLKCTRL_FRAC_CLKGATEPIX     0x00800000
+
+#define HW_CLKCTRL_FRAC1       0x100
+
+#define HW_CLKCTRL_CLKSEQ      0x110
+#define BM_CLKCTRL_CLKSEQ_BYPASS_PIX   0x00000002
+
+#define HW_CLKCTRL_RESET       0x120
+#define BM_CLKCTRL_RESET_DIG   0x00000001
+#define BP_CLKCTRL_RESET_DIG   0
+
+#endif
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-dcp.h b/arch/arm/mach-stmp378x/include/mach/regs-dcp.h
new file mode 100644 (file)
index 0000000..fdedd00
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * stmp378x: DCP register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_DCP_BASE  (STMP3XXX_REGS_BASE + 0x28000)
+#define REGS_DCP_PHYS  0x80028000
+#define REGS_DCP_SIZE  0x2000
+
+#define HW_DCP_CTRL            0x0
+#define BM_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE   0x000000FF
+#define BP_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE   0
+#define BM_DCP_CTRL_ENABLE_CONTEXT_CACHING     0x00400000
+#define BM_DCP_CTRL_GATHER_RESIDUAL_WRITES     0x00800000
+#define BM_DCP_CTRL_CLKGATE    0x40000000
+#define BM_DCP_CTRL_SFTRST     0x80000000
+
+#define HW_DCP_STAT            0x10
+#define BM_DCP_STAT_IRQ                0x0000000F
+#define BP_DCP_STAT_IRQ                0
+
+#define HW_DCP_CHANNELCTRL     0x20
+#define BM_DCP_CHANNELCTRL_ENABLE_CHANNEL      0x000000FF
+#define BP_DCP_CHANNELCTRL_ENABLE_CHANNEL      0
+
+#define HW_DCP_CONTEXT         0x50
+#define BM_DCP_PACKET1_INTERRUPT       0x00000001
+#define BP_DCP_PACKET1_INTERRUPT       0
+#define BM_DCP_PACKET1_DECR_SEMAPHORE  0x00000002
+#define BM_DCP_PACKET1_CHAIN   0x00000004
+#define BM_DCP_PACKET1_CHAIN_CONTIGUOUS        0x00000008
+#define BM_DCP_PACKET1_ENABLE_CIPHER   0x00000020
+#define BM_DCP_PACKET1_ENABLE_HASH     0x00000040
+#define BM_DCP_PACKET1_CIPHER_ENCRYPT  0x00000100
+#define BM_DCP_PACKET1_CIPHER_INIT     0x00000200
+#define BM_DCP_PACKET1_OTP_KEY 0x00000400
+#define BM_DCP_PACKET1_PAYLOAD_KEY     0x00000800
+#define BM_DCP_PACKET1_HASH_INIT       0x00001000
+#define BM_DCP_PACKET1_HASH_TERM       0x00002000
+#define BM_DCP_PACKET2_CIPHER_SELECT   0x0000000F
+#define BP_DCP_PACKET2_CIPHER_SELECT   0
+#define BM_DCP_PACKET2_CIPHER_MODE     0x000000F0
+#define BP_DCP_PACKET2_CIPHER_MODE     4
+#define BM_DCP_PACKET2_KEY_SELECT      0x0000FF00
+#define BP_DCP_PACKET2_KEY_SELECT      8
+#define BM_DCP_PACKET2_HASH_SELECT     0x000F0000
+#define BP_DCP_PACKET2_HASH_SELECT     16
+#define BM_DCP_PACKET2_CIPHER_CFG      0xFF000000
+#define BP_DCP_PACKET2_CIPHER_CFG      24
+
+#define HW_DCP_CH0CMDPTR       (0x100 + 0 * 0x40)
+#define HW_DCP_CH1CMDPTR       (0x100 + 1 * 0x40)
+#define HW_DCP_CH2CMDPTR       (0x100 + 2 * 0x40)
+#define HW_DCP_CH3CMDPTR       (0x100 + 3 * 0x40)
+
+#define HW_DCP_CHnCMDPTR       0x100
+
+#define HW_DCP_CH0SEMA         (0x110 + 0 * 0x40)
+#define HW_DCP_CH1SEMA         (0x110 + 1 * 0x40)
+#define HW_DCP_CH2SEMA         (0x110 + 2 * 0x40)
+#define HW_DCP_CH3SEMA         (0x110 + 3 * 0x40)
+
+#define HW_DCP_CHnSEMA         0x110
+#define BM_DCP_CHnSEMA_INCREMENT       0x000000FF
+#define BP_DCP_CHnSEMA_INCREMENT       0
+
+#define HW_DCP_CH0STAT         (0x120 + 0 * 0x40)
+#define HW_DCP_CH1STAT         (0x120 + 1 * 0x40)
+#define HW_DCP_CH2STAT         (0x120 + 2 * 0x40)
+#define HW_DCP_CH3STAT         (0x120 + 3 * 0x40)
+
+#define HW_DCP_CHnSTAT         0x120
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-digctl.h b/arch/arm/mach-stmp378x/include/mach/regs-digctl.h
new file mode 100644 (file)
index 0000000..5293005
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * stmp378x: DIGCTL register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_DIGCTL_BASE       (STMP3XXX_REGS_BASE + 0x1C000)
+#define REGS_DIGCTL_PHYS       0x8001C000
+#define REGS_DIGCTL_SIZE       0x2000
+
+#define HW_DIGCTL_CTRL         0x0
+#define BM_DIGCTL_CTRL_USB_CLKGATE     0x00000004
+
+#define HW_DIGCTL_ARMCACHE     0x2B0
+#define BM_DIGCTL_ARMCACHE_ITAG_SS     0x00000003
+#define BP_DIGCTL_ARMCACHE_ITAG_SS     0
+#define BM_DIGCTL_ARMCACHE_DTAG_SS     0x00000030
+#define BP_DIGCTL_ARMCACHE_DTAG_SS     4
+#define BM_DIGCTL_ARMCACHE_CACHE_SS    0x00000300
+#define BP_DIGCTL_ARMCACHE_CACHE_SS    8
+#define BM_DIGCTL_ARMCACHE_DRTY_SS     0x00003000
+#define BP_DIGCTL_ARMCACHE_DRTY_SS     12
+#define BM_DIGCTL_ARMCACHE_VALID_SS    0x00030000
+#define BP_DIGCTL_ARMCACHE_VALID_SS    16
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-dram.h b/arch/arm/mach-stmp378x/include/mach/regs-dram.h
new file mode 100644 (file)
index 0000000..0285143
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * stmp378x: DRAM register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_DRAM_BASE (STMP3XXX_REGS_BASE + 0xE0000)
+#define REGS_DRAM_PHYS 0x800E0000
+#define REGS_DRAM_SIZE 0x2000
+
+#define HW_DRAM_CTL06          0x18
+
+#define HW_DRAM_CTL08          0x20
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-dri.h b/arch/arm/mach-stmp378x/include/mach/regs-dri.h
new file mode 100644 (file)
index 0000000..da25f7e
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * stmp378x: DRI register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_DRI_BASE  (STMP3XXX_REGS_BASE + 0x74000)
+#define REGS_DRI_PHYS  0x80074000
+#define REGS_DRI_SIZE  0x2000
+
+#define HW_DRI_CTRL            0x0
+#define BM_DRI_CTRL_RUN                0x00000001
+#define BP_DRI_CTRL_RUN                0
+#define BM_DRI_CTRL_ATTENTION_IRQ      0x00000002
+#define BM_DRI_CTRL_PILOT_SYNC_LOSS_IRQ        0x00000004
+#define BM_DRI_CTRL_OVERFLOW_IRQ       0x00000008
+#define BM_DRI_CTRL_ATTENTION_IRQ_EN   0x00000200
+#define BM_DRI_CTRL_PILOT_SYNC_LOSS_IRQ_EN     0x00000400
+#define BM_DRI_CTRL_OVERFLOW_IRQ_EN    0x00000800
+#define BM_DRI_CTRL_REACQUIRE_PHASE    0x00008000
+#define BM_DRI_CTRL_STOP_ON_PILOT_ERROR        0x02000000
+#define BM_DRI_CTRL_STOP_ON_OFLOW_ERROR        0x04000000
+#define BM_DRI_CTRL_ENABLE_INPUTS      0x20000000
+#define BM_DRI_CTRL_CLKGATE    0x40000000
+#define BM_DRI_CTRL_SFTRST     0x80000000
+
+#define HW_DRI_TIMING          0x10
+#define BM_DRI_TIMING_GAP_DETECTION_INTERVAL   0x000000FF
+#define BP_DRI_TIMING_GAP_DETECTION_INTERVAL   0
+#define BM_DRI_TIMING_PILOT_REP_RATE   0x000F0000
+#define BP_DRI_TIMING_PILOT_REP_RATE   16
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-ecc8.h b/arch/arm/mach-stmp378x/include/mach/regs-ecc8.h
new file mode 100644 (file)
index 0000000..cc353be
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * stmp378x: ECC8 register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_ECC8_BASE (STMP3XXX_REGS_BASE + 0x8000)
+#define REGS_ECC8_PHYS 0x80008000
+#define REGS_ECC8_SIZE 0x2000
+
+#define HW_ECC8_CTRL           0x0
+#define BM_ECC8_CTRL_COMPLETE_IRQ      0x00000001
+#define BP_ECC8_CTRL_COMPLETE_IRQ      0
+#define BM_ECC8_CTRL_COMPLETE_IRQ_EN   0x00000100
+#define BM_ECC8_CTRL_AHBM_SFTRST       0x20000000
+
+#define HW_ECC8_STATUS0                0x10
+#define BM_ECC8_STATUS0_UNCORRECTABLE  0x00000004
+#define BM_ECC8_STATUS0_CORRECTED      0x00000008
+#define BM_ECC8_STATUS0_STATUS_AUX     0x00000F00
+#define BP_ECC8_STATUS0_STATUS_AUX     8
+#define BM_ECC8_STATUS0_COMPLETED_CE   0x000F0000
+#define BP_ECC8_STATUS0_COMPLETED_CE   16
+
+#define HW_ECC8_STATUS1                0x20
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-emi.h b/arch/arm/mach-stmp378x/include/mach/regs-emi.h
new file mode 100644 (file)
index 0000000..98773fc
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * stmp378x: EMI register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_EMI_BASE  (STMP3XXX_REGS_BASE + 0x20000)
+#define REGS_EMI_PHYS  0x80020000
+#define REGS_EMI_SIZE  0x2000
+
+#define HW_EMI_STAT            0x10
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-gpmi.h b/arch/arm/mach-stmp378x/include/mach/regs-gpmi.h
new file mode 100644 (file)
index 0000000..2cc8bbe
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * stmp378x: GPMI register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_GPMI_BASE (STMP3XXX_REGS_BASE + 0xC000)
+#define REGS_GPMI_PHYS 0x8000C000
+#define REGS_GPMI_SIZE 0x2000
+
+#define HW_GPMI_CTRL0          0x0
+#define BM_GPMI_CTRL0_XFER_COUNT       0x0000FFFF
+#define BP_GPMI_CTRL0_XFER_COUNT       0
+#define BM_GPMI_CTRL0_CS       0x00300000
+#define BP_GPMI_CTRL0_CS       20
+#define BM_GPMI_CTRL0_LOCK_CS  0x00400000
+#define BM_GPMI_CTRL0_WORD_LENGTH      0x00800000
+#define BM_GPMI_CTRL0_ADDRESS      0x000E0000
+#define BP_GPMI_CTRL0_ADDRESS      17
+#define BV_GPMI_CTRL0_ADDRESS__NAND_DATA  0x0
+#define BV_GPMI_CTRL0_ADDRESS__NAND_CLE   0x1
+#define BV_GPMI_CTRL0_ADDRESS__NAND_ALE   0x2
+#define BM_GPMI_CTRL0_ADDRESS_INCREMENT      0x00010000
+#define BM_GPMI_CTRL0_COMMAND_MODE     0x03000000
+#define BP_GPMI_CTRL0_COMMAND_MODE     24
+#define BV_GPMI_CTRL0_COMMAND_MODE__WRITE          0x0
+#define BV_GPMI_CTRL0_COMMAND_MODE__READ            0x1
+#define BV_GPMI_CTRL0_COMMAND_MODE__READ_AND_COMPARE 0x2
+#define BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY   0x3
+#define BM_GPMI_CTRL0_RUN      0x20000000
+#define BM_GPMI_CTRL0_CLKGATE  0x40000000
+#define BM_GPMI_CTRL0_SFTRST   0x80000000
+#define BM_GPMI_ECCCTRL_BUFFER_MASK    0x000001FF
+#define BP_GPMI_ECCCTRL_BUFFER_MASK    0
+#define BM_GPMI_ECCCTRL_ENABLE_ECC     0x00001000
+#define BM_GPMI_ECCCTRL_ECC_CMD        0x00006000
+#define BP_GPMI_ECCCTRL_ECC_CMD        13
+#define BV_GPMI_ECCCTRL_ECC_CMD__DECODE_4_BIT                  0
+#define BV_GPMI_ECCCTRL_ECC_CMD__ENCODE_4_BIT                  1
+#define BV_GPMI_ECCCTRL_ECC_CMD__DECODE_8_BIT                  2
+#define BV_GPMI_ECCCTRL_ECC_CMD__ENCODE_8_BIT                  3
+
+#define HW_GPMI_CTRL1          0x60
+#define BM_GPMI_CTRL1_GPMI_MODE        0x00000001
+#define BP_GPMI_CTRL1_GPMI_MODE        0
+#define BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY      0x00000004
+#define BM_GPMI_CTRL1_DEV_RESET        0x00000008
+#define BM_GPMI_CTRL1_TIMEOUT_IRQ      0x00000200
+#define BM_GPMI_CTRL1_DEV_IRQ  0x00000400
+#define BM_GPMI_CTRL1_RDN_DELAY        0x0000F000
+#define BP_GPMI_CTRL1_RDN_DELAY        12
+#define BM_GPMI_CTRL1_BCH_MODE 0x00040000
+
+#define HW_GPMI_TIMING0                0x70
+#define BM_GPMI_TIMING0_DATA_SETUP     0x000000FF
+#define BP_GPMI_TIMING0_DATA_SETUP     0
+#define BM_GPMI_TIMING0_DATA_HOLD      0x0000FF00
+#define BP_GPMI_TIMING0_DATA_HOLD      8
+#define BM_GPMI_TIMING0_ADDRESS_SETUP  0x00FF0000
+#define BP_GPMI_TIMING0_ADDRESS_SETUP  16
+
+#define HW_GPMI_TIMING1                0x80
+#define BM_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT    0xFFFF0000
+#define BP_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT    16
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-i2c.h b/arch/arm/mach-stmp378x/include/mach/regs-i2c.h
new file mode 100644 (file)
index 0000000..13a234c
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * stmp378x: I2C register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_I2C_BASE  (STMP3XXX_REGS_BASE + 0x58000)
+#define REGS_I2C_PHYS  0x80058000
+#define REGS_I2C_SIZE  0x2000
+
+#define HW_I2C_CTRL0           0x0
+#define BM_I2C_CTRL0_XFER_COUNT        0x0000FFFF
+#define BP_I2C_CTRL0_XFER_COUNT        0
+#define BM_I2C_CTRL0_DIRECTION 0x00010000
+#define BM_I2C_CTRL0_MASTER_MODE       0x00020000
+#define BM_I2C_CTRL0_PRE_SEND_START    0x00080000
+#define BM_I2C_CTRL0_POST_SEND_STOP    0x00100000
+#define BM_I2C_CTRL0_RETAIN_CLOCK      0x00200000
+#define BM_I2C_CTRL0_SEND_NAK_ON_LAST  0x02000000
+#define BM_I2C_CTRL0_CLKGATE   0x40000000
+#define BM_I2C_CTRL0_SFTRST    0x80000000
+
+#define HW_I2C_TIMING0         0x10
+
+#define HW_I2C_TIMING1         0x20
+
+#define HW_I2C_TIMING2         0x30
+
+#define HW_I2C_CTRL1           0x40
+#define BM_I2C_CTRL1_SLAVE_IRQ 0x00000001
+#define BP_I2C_CTRL1_SLAVE_IRQ 0
+#define BM_I2C_CTRL1_SLAVE_STOP_IRQ    0x00000002
+#define BM_I2C_CTRL1_MASTER_LOSS_IRQ   0x00000004
+#define BM_I2C_CTRL1_EARLY_TERM_IRQ    0x00000008
+#define BM_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ    0x00000010
+#define BM_I2C_CTRL1_NO_SLAVE_ACK_IRQ  0x00000020
+#define BM_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ     0x00000040
+#define BM_I2C_CTRL1_BUS_FREE_IRQ      0x00000080
+#define BM_I2C_CTRL1_CLR_GOT_A_NAK     0x10000000
+
+#define HW_I2C_VERSION         0x90
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-icoll.h b/arch/arm/mach-stmp378x/include/mach/regs-icoll.h
new file mode 100644 (file)
index 0000000..f996e80
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * stmp378x: ICOLL register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef _MACH_REGS_ICOLL
+#define _MACH_REGS_ICOLL
+
+#define REGS_ICOLL_BASE        (STMP3XXX_REGS_BASE + 0x0)
+#define REGS_ICOLL_PHYS        0x80000000
+#define REGS_ICOLL_SIZE        0x2000
+
+#define HW_ICOLL_VECTOR                0x0
+
+#define HW_ICOLL_LEVELACK      0x10
+#define BM_ICOLL_LEVELACK_IRQLEVELACK  0x0000000F
+#define BP_ICOLL_LEVELACK_IRQLEVELACK  0
+
+#define HW_ICOLL_CTRL          0x20
+#define BM_ICOLL_CTRL_CLKGATE  0x40000000
+#define BM_ICOLL_CTRL_SFTRST   0x80000000
+
+#define HW_ICOLL_STAT          0x70
+
+#define HW_ICOLL_INTERRUPTn    0x120
+
+#define HW_ICOLL_INTERRUPTn    0x120
+#define BM_ICOLL_INTERRUPTn_ENABLE     0x00000004
+
+#endif
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-ir.h b/arch/arm/mach-stmp378x/include/mach/regs-ir.h
new file mode 100644 (file)
index 0000000..a5b4ef1
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * stmp378x: IR register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_IR_BASE   (STMP3XXX_REGS_BASE + 0x78000)
+#define REGS_IR_PHYS   0x80078000
+#define REGS_IR_SIZE   0x2000
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-lcdif.h b/arch/arm/mach-stmp378x/include/mach/regs-lcdif.h
new file mode 100644 (file)
index 0000000..9cdbef4
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * stmp378x: LCDIF register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_LCDIF_BASE        (STMP3XXX_REGS_BASE + 0x30000)
+#define REGS_LCDIF_PHYS        0x80030000
+#define REGS_LCDIF_SIZE        0x2000
+
+#define HW_LCDIF_CTRL          0x0
+#define BM_LCDIF_CTRL_RUN      0x00000001
+#define BP_LCDIF_CTRL_RUN      0
+#define BM_LCDIF_CTRL_LCDIF_MASTER     0x00000020
+#define BM_LCDIF_CTRL_RGB_TO_YCBCR422_CSC      0x00000080
+#define BM_LCDIF_CTRL_WORD_LENGTH      0x00000300
+#define BP_LCDIF_CTRL_WORD_LENGTH      8
+#define BM_LCDIF_CTRL_LCD_DATABUS_WIDTH        0x00000C00
+#define BP_LCDIF_CTRL_LCD_DATABUS_WIDTH        10
+#define BM_LCDIF_CTRL_INPUT_DATA_SWIZZLE       0x0000C000
+#define BP_LCDIF_CTRL_INPUT_DATA_SWIZZLE       14
+#define BM_LCDIF_CTRL_DATA_SELECT      0x00010000
+#define BM_LCDIF_CTRL_DOTCLK_MODE      0x00020000
+#define BM_LCDIF_CTRL_VSYNC_MODE       0x00040000
+#define BM_LCDIF_CTRL_BYPASS_COUNT     0x00080000
+#define BM_LCDIF_CTRL_DVI_MODE 0x00100000
+#define BM_LCDIF_CTRL_SHIFT_NUM_BITS   0x03E00000
+#define BP_LCDIF_CTRL_SHIFT_NUM_BITS   21
+#define BM_LCDIF_CTRL_DATA_SHIFT_DIR   0x04000000
+#define BM_LCDIF_CTRL_WAIT_FOR_VSYNC_EDGE      0x08000000
+#define BM_LCDIF_CTRL_CLKGATE  0x40000000
+#define BM_LCDIF_CTRL_SFTRST   0x80000000
+
+#define HW_LCDIF_CTRL1         0x10
+#define BM_LCDIF_CTRL1_RESET   0x00000001
+#define BP_LCDIF_CTRL1_RESET   0
+#define BM_LCDIF_CTRL1_MODE86  0x00000002
+#define BM_LCDIF_CTRL1_BUSY_ENABLE     0x00000004
+#define BM_LCDIF_CTRL1_VSYNC_EDGE_IRQ  0x00000100
+#define BM_LCDIF_CTRL1_CUR_FRAME_DONE_IRQ      0x00000200
+#define BM_LCDIF_CTRL1_UNDERFLOW_IRQ   0x00000400
+#define BM_LCDIF_CTRL1_OVERFLOW_IRQ    0x00000800
+#define BM_LCDIF_CTRL1_VSYNC_EDGE_IRQ_EN       0x00001000
+#define BM_LCDIF_CTRL1_BYTE_PACKING_FORMAT     0x000F0000
+#define BP_LCDIF_CTRL1_BYTE_PACKING_FORMAT     16
+#define BM_LCDIF_CTRL1_INTERLACE_FIELDS        0x00800000
+#define BM_LCDIF_CTRL1_RECOVER_ON_UNDERFLOW    0x01000000
+
+#define HW_LCDIF_TRANSFER_COUNT        0x20
+#define BM_LCDIF_TRANSFER_COUNT_H_COUNT        0x0000FFFF
+#define BP_LCDIF_TRANSFER_COUNT_H_COUNT        0
+#define BM_LCDIF_TRANSFER_COUNT_V_COUNT        0xFFFF0000
+#define BP_LCDIF_TRANSFER_COUNT_V_COUNT        16
+
+#define HW_LCDIF_CUR_BUF       0x30
+
+#define HW_LCDIF_NEXT_BUF      0x40
+
+#define HW_LCDIF_TIMING                0x60
+
+#define HW_LCDIF_VDCTRL0       0x70
+#define BM_LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH     0x0003FFFF
+#define BP_LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH     0
+#define BM_LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT        0x00100000
+#define BM_LCDIF_VDCTRL0_VSYNC_PERIOD_UNIT     0x00200000
+#define BM_LCDIF_VDCTRL0_ENABLE_POL    0x01000000
+#define BM_LCDIF_VDCTRL0_DOTCLK_POL    0x02000000
+#define BM_LCDIF_VDCTRL0_HSYNC_POL     0x04000000
+#define BM_LCDIF_VDCTRL0_VSYNC_POL     0x08000000
+#define BM_LCDIF_VDCTRL0_ENABLE_PRESENT        0x10000000
+#define BM_LCDIF_VDCTRL0_VSYNC_OEB     0x20000000
+
+#define HW_LCDIF_VDCTRL1       0x80
+#define BM_LCDIF_VDCTRL1_VSYNC_PERIOD  0xFFFFFFFF
+#define BP_LCDIF_VDCTRL1_VSYNC_PERIOD  0
+
+#define HW_LCDIF_VDCTRL2       0x90
+#define BM_LCDIF_VDCTRL2_HSYNC_PERIOD  0x0003FFFF
+#define BP_LCDIF_VDCTRL2_HSYNC_PERIOD  0
+#define BM_LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH     0xFF000000
+#define BP_LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH     24
+
+#define HW_LCDIF_VDCTRL3       0xA0
+#define BM_LCDIF_VDCTRL3_VERTICAL_WAIT_CNT     0x0000FFFF
+#define BP_LCDIF_VDCTRL3_VERTICAL_WAIT_CNT     0
+#define BM_LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT   0x0FFF0000
+#define BP_LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT   16
+
+#define HW_LCDIF_VDCTRL4       0xB0
+#define BM_LCDIF_VDCTRL4_DOTCLK_H_VALID_DATA_CNT       0x0003FFFF
+#define BP_LCDIF_VDCTRL4_DOTCLK_H_VALID_DATA_CNT       0
+#define BM_LCDIF_VDCTRL4_SYNC_SIGNALS_ON       0x00040000
+
+#define HW_LCDIF_DVICTRL0      0xC0
+#define BM_LCDIF_DVICTRL0_V_LINES_CNT  0x000003FF
+#define BP_LCDIF_DVICTRL0_V_LINES_CNT  0
+#define BM_LCDIF_DVICTRL0_H_BLANKING_CNT       0x000FFC00
+#define BP_LCDIF_DVICTRL0_H_BLANKING_CNT       10
+#define BM_LCDIF_DVICTRL0_H_ACTIVE_CNT 0x7FF00000
+#define BP_LCDIF_DVICTRL0_H_ACTIVE_CNT 20
+
+#define HW_LCDIF_DVICTRL1      0xD0
+#define BM_LCDIF_DVICTRL1_F2_START_LINE        0x000003FF
+#define BP_LCDIF_DVICTRL1_F2_START_LINE        0
+#define BM_LCDIF_DVICTRL1_F1_END_LINE  0x000FFC00
+#define BP_LCDIF_DVICTRL1_F1_END_LINE  10
+#define BM_LCDIF_DVICTRL1_F1_START_LINE        0x3FF00000
+#define BP_LCDIF_DVICTRL1_F1_START_LINE        20
+
+#define HW_LCDIF_DVICTRL2      0xE0
+#define BM_LCDIF_DVICTRL2_V1_BLANK_END_LINE    0x000003FF
+#define BP_LCDIF_DVICTRL2_V1_BLANK_END_LINE    0
+#define BM_LCDIF_DVICTRL2_V1_BLANK_START_LINE  0x000FFC00
+#define BP_LCDIF_DVICTRL2_V1_BLANK_START_LINE  10
+#define BM_LCDIF_DVICTRL2_F2_END_LINE  0x3FF00000
+#define BP_LCDIF_DVICTRL2_F2_END_LINE  20
+
+#define HW_LCDIF_DVICTRL3      0xF0
+#define BM_LCDIF_DVICTRL3_V2_BLANK_END_LINE    0x000003FF
+#define BP_LCDIF_DVICTRL3_V2_BLANK_END_LINE    0
+#define BM_LCDIF_DVICTRL3_V2_BLANK_START_LINE  0x03FF0000
+#define BP_LCDIF_DVICTRL3_V2_BLANK_START_LINE  16
+
+#define HW_LCDIF_DVICTRL4      0x100
+#define BM_LCDIF_DVICTRL4_H_FILL_CNT   0x000000FF
+#define BP_LCDIF_DVICTRL4_H_FILL_CNT   0
+#define BM_LCDIF_DVICTRL4_CR_FILL_VALUE        0x0000FF00
+#define BP_LCDIF_DVICTRL4_CR_FILL_VALUE        8
+#define BM_LCDIF_DVICTRL4_CB_FILL_VALUE        0x00FF0000
+#define BP_LCDIF_DVICTRL4_CB_FILL_VALUE        16
+#define BM_LCDIF_DVICTRL4_Y_FILL_VALUE 0xFF000000
+#define BP_LCDIF_DVICTRL4_Y_FILL_VALUE 24
+
+#define HW_LCDIF_CSC_COEFF0    0x110
+#define BM_LCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER       0x00000003
+#define BP_LCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER       0
+#define BM_LCDIF_CSC_COEFF0_C0 0x03FF0000
+#define BP_LCDIF_CSC_COEFF0_C0 16
+
+#define HW_LCDIF_CSC_COEFF1    0x120
+#define BM_LCDIF_CSC_COEFF1_C1 0x000003FF
+#define BP_LCDIF_CSC_COEFF1_C1 0
+#define BM_LCDIF_CSC_COEFF1_C2 0x03FF0000
+#define BP_LCDIF_CSC_COEFF1_C2 16
+
+#define HW_LCDIF_CSC_COEFF2    0x130
+#define BM_LCDIF_CSC_COEFF2_C3 0x000003FF
+#define BP_LCDIF_CSC_COEFF2_C3 0
+#define BM_LCDIF_CSC_COEFF2_C4 0x03FF0000
+#define BP_LCDIF_CSC_COEFF2_C4 16
+
+#define HW_LCDIF_CSC_COEFF3    0x140
+#define BM_LCDIF_CSC_COEFF3_C5 0x000003FF
+#define BP_LCDIF_CSC_COEFF3_C5 0
+#define BM_LCDIF_CSC_COEFF3_C6 0x03FF0000
+#define BP_LCDIF_CSC_COEFF3_C6 16
+
+#define HW_LCDIF_CSC_COEFF4    0x150
+#define BM_LCDIF_CSC_COEFF4_C7 0x000003FF
+#define BP_LCDIF_CSC_COEFF4_C7 0
+#define BM_LCDIF_CSC_COEFF4_C8 0x03FF0000
+#define BP_LCDIF_CSC_COEFF4_C8 16
+
+#define HW_LCDIF_CSC_OFFSET    0x160
+#define BM_LCDIF_CSC_OFFSET_Y_OFFSET   0x000001FF
+#define BP_LCDIF_CSC_OFFSET_Y_OFFSET   0
+#define BM_LCDIF_CSC_OFFSET_CBCR_OFFSET        0x01FF0000
+#define BP_LCDIF_CSC_OFFSET_CBCR_OFFSET        16
+
+#define HW_LCDIF_CSC_LIMIT     0x170
+#define BM_LCDIF_CSC_LIMIT_Y_MAX       0x000000FF
+#define BP_LCDIF_CSC_LIMIT_Y_MAX       0
+#define BM_LCDIF_CSC_LIMIT_Y_MIN       0x0000FF00
+#define BP_LCDIF_CSC_LIMIT_Y_MIN       8
+#define BM_LCDIF_CSC_LIMIT_CBCR_MAX    0x00FF0000
+#define BP_LCDIF_CSC_LIMIT_CBCR_MAX    16
+#define BM_LCDIF_CSC_LIMIT_CBCR_MIN    0xFF000000
+#define BP_LCDIF_CSC_LIMIT_CBCR_MIN    24
+
+#define HW_LCDIF_STAT          0x1D0
+#define BM_LCDIF_STAT_TXFIFO_EMPTY     0x04000000
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-lradc.h b/arch/arm/mach-stmp378x/include/mach/regs-lradc.h
new file mode 100644 (file)
index 0000000..cb8cb06
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * stmp378x: LRADC register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_LRADC_BASE        (STMP3XXX_REGS_BASE + 0x50000)
+#define REGS_LRADC_PHYS        0x80050000
+#define REGS_LRADC_SIZE        0x2000
+
+#define HW_LRADC_CTRL0         0x0
+#define BM_LRADC_CTRL0_SCHEDULE        0x000000FF
+#define BP_LRADC_CTRL0_SCHEDULE        0
+#define BM_LRADC_CTRL0_XPLUS_ENABLE    0x00010000
+#define BM_LRADC_CTRL0_YPLUS_ENABLE    0x00020000
+#define BM_LRADC_CTRL0_XMINUS_ENABLE   0x00040000
+#define BM_LRADC_CTRL0_YMINUS_ENABLE   0x00080000
+#define BM_LRADC_CTRL0_TOUCH_DETECT_ENABLE     0x00100000
+#define BM_LRADC_CTRL0_ONCHIP_GROUNDREF        0x00200000
+#define BM_LRADC_CTRL0_CLKGATE 0x40000000
+#define BM_LRADC_CTRL0_SFTRST  0x80000000
+
+#define HW_LRADC_CTRL1         0x10
+#define BM_LRADC_CTRL1_LRADC0_IRQ      0x00000001
+#define BP_LRADC_CTRL1_LRADC0_IRQ      0
+#define BM_LRADC_CTRL1_LRADC5_IRQ      0x00000020
+#define BM_LRADC_CTRL1_LRADC6_IRQ      0x00000040
+#define BM_LRADC_CTRL1_TOUCH_DETECT_IRQ        0x00000100
+#define BM_LRADC_CTRL1_LRADC0_IRQ_EN   0x00010000
+#define BM_LRADC_CTRL1_LRADC5_IRQ_EN   0x00200000
+#define BM_LRADC_CTRL1_TOUCH_DETECT_IRQ_EN     0x01000000
+
+#define HW_LRADC_CTRL2         0x20
+#define BM_LRADC_CTRL2_BL_BRIGHTNESS   0x001F0000
+#define BP_LRADC_CTRL2_BL_BRIGHTNESS   16
+#define BM_LRADC_CTRL2_BL_MUX_SELECT   0x00200000
+#define BM_LRADC_CTRL2_BL_ENABLE       0x00400000
+#define BM_LRADC_CTRL2_DIVIDE_BY_TWO   0xFF000000
+#define BP_LRADC_CTRL2_DIVIDE_BY_TWO   24
+
+#define HW_LRADC_CTRL3         0x30
+#define BM_LRADC_CTRL3_CYCLE_TIME      0x00000300
+#define BP_LRADC_CTRL3_CYCLE_TIME      8
+
+#define HW_LRADC_STATUS                0x40
+#define BM_LRADC_STATUS_TOUCH_DETECT_RAW       0x00000001
+#define BP_LRADC_STATUS_TOUCH_DETECT_RAW       0
+
+#define HW_LRADC_CH0           (0x50 + 0 * 0x10)
+#define HW_LRADC_CH1           (0x50 + 1 * 0x10)
+#define HW_LRADC_CH2           (0x50 + 2 * 0x10)
+#define HW_LRADC_CH3           (0x50 + 3 * 0x10)
+#define HW_LRADC_CH4           (0x50 + 4 * 0x10)
+#define HW_LRADC_CH5           (0x50 + 5 * 0x10)
+#define HW_LRADC_CH6           (0x50 + 6 * 0x10)
+#define HW_LRADC_CH7           (0x50 + 7 * 0x10)
+
+#define HW_LRADC_CHn           0x50
+#define BM_LRADC_CHn_VALUE     0x0003FFFF
+#define BP_LRADC_CHn_VALUE     0
+#define BM_LRADC_CHn_NUM_SAMPLES       0x1F000000
+#define BP_LRADC_CHn_NUM_SAMPLES       24
+#define BM_LRADC_CHn_ACCUMULATE        0x20000000
+
+#define HW_LRADC_DELAY0                (0xD0 + 0 * 0x10)
+#define HW_LRADC_DELAY1                (0xD0 + 1 * 0x10)
+#define HW_LRADC_DELAY2                (0xD0 + 2 * 0x10)
+#define HW_LRADC_DELAY3                (0xD0 + 3 * 0x10)
+
+#define HW_LRADC_DELAYn                0xD0
+#define BM_LRADC_DELAYn_DELAY  0x000007FF
+#define BP_LRADC_DELAYn_DELAY  0
+#define BM_LRADC_DELAYn_LOOP_COUNT     0x0000F800
+#define BP_LRADC_DELAYn_LOOP_COUNT     11
+#define BM_LRADC_DELAYn_TRIGGER_DELAYS 0x000F0000
+#define BP_LRADC_DELAYn_TRIGGER_DELAYS 16
+#define BM_LRADC_DELAYn_KICK   0x00100000
+#define BM_LRADC_DELAYn_TRIGGER_LRADCS 0xFF000000
+#define BP_LRADC_DELAYn_TRIGGER_LRADCS 24
+
+#define HW_LRADC_CTRL4         0x140
+#define BM_LRADC_CTRL4_LRADC6SELECT    0x0F000000
+#define BP_LRADC_CTRL4_LRADC6SELECT    24
+#define BM_LRADC_CTRL4_LRADC7SELECT    0xF0000000
+#define BP_LRADC_CTRL4_LRADC7SELECT    28
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-ocotp.h b/arch/arm/mach-stmp378x/include/mach/regs-ocotp.h
new file mode 100644 (file)
index 0000000..f0af64d
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * stmp378x: OCOTP register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_OCOTP_BASE        (STMP3XXX_REGS_BASE + 0x2C000)
+#define REGS_OCOTP_PHYS        0x8002C000
+#define REGS_OCOTP_SIZE        0x2000
+
+#define HW_OCOTP_CTRL          0x0
+#define BM_OCOTP_CTRL_BUSY     0x00000100
+#define BM_OCOTP_CTRL_ERROR    0x00000200
+#define BM_OCOTP_CTRL_RD_BANK_OPEN     0x00001000
+#define BM_OCOTP_CTRL_RELOAD_SHADOWS   0x00002000
+#define BM_OCOTP_CTRL_WR_UNLOCK        0xFFFF0000
+#define BP_OCOTP_CTRL_WR_UNLOCK        16
+
+#define HW_OCOTP_DATA          0x10
+
+#define HW_OCOTP_CUST0         (0x20 + 0 * 0x10)
+#define HW_OCOTP_CUST1         (0x20 + 1 * 0x10)
+#define HW_OCOTP_CUST2         (0x20 + 2 * 0x10)
+#define HW_OCOTP_CUST3         (0x20 + 3 * 0x10)
+
+#define HW_OCOTP_CUSTn         0x20
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-pinctrl.h b/arch/arm/mach-stmp378x/include/mach/regs-pinctrl.h
new file mode 100644 (file)
index 0000000..50d90ea
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * stmp378x: PINCTRL register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef _MACH_REGS_PINCTRL
+#define _MACH_REGS_PINCTRL
+
+#define REGS_PINCTRL_BASE      (STMP3XXX_REGS_BASE + 0x18000)
+#define REGS_PINCTRL_PHYS      0x80018000
+#define REGS_PINCTRL_SIZE      0x2000
+
+#define HW_PINCTRL_MUXSEL0     0x100
+#define HW_PINCTRL_MUXSEL1     0x110
+#define HW_PINCTRL_MUXSEL2     0x120
+#define HW_PINCTRL_MUXSEL3     0x130
+#define HW_PINCTRL_MUXSEL4     0x140
+#define HW_PINCTRL_MUXSEL5     0x150
+#define HW_PINCTRL_MUXSEL6     0x160
+#define HW_PINCTRL_MUXSEL7     0x170
+
+#define HW_PINCTRL_DRIVE0      0x200
+#define HW_PINCTRL_DRIVE1      0x210
+#define HW_PINCTRL_DRIVE2      0x220
+#define HW_PINCTRL_DRIVE3      0x230
+#define HW_PINCTRL_DRIVE4      0x240
+#define HW_PINCTRL_DRIVE5      0x250
+#define HW_PINCTRL_DRIVE6      0x260
+#define HW_PINCTRL_DRIVE7      0x270
+#define HW_PINCTRL_DRIVE8      0x280
+#define HW_PINCTRL_DRIVE9      0x290
+#define HW_PINCTRL_DRIVE10     0x2A0
+#define HW_PINCTRL_DRIVE11     0x2B0
+#define HW_PINCTRL_DRIVE12     0x2C0
+#define HW_PINCTRL_DRIVE13     0x2D0
+#define HW_PINCTRL_DRIVE14     0x2E0
+
+#define HW_PINCTRL_PULL0       0x400
+#define HW_PINCTRL_PULL1       0x410
+#define HW_PINCTRL_PULL2       0x420
+#define HW_PINCTRL_PULL3       0x430
+
+#define HW_PINCTRL_DOUT0       0x500
+#define HW_PINCTRL_DOUT1       0x510
+#define HW_PINCTRL_DOUT2       0x520
+
+#define HW_PINCTRL_DIN0                0x600
+#define HW_PINCTRL_DIN1                0x610
+#define HW_PINCTRL_DIN2                0x620
+
+#define HW_PINCTRL_DOE0                0x700
+#define HW_PINCTRL_DOE1                0x710
+#define HW_PINCTRL_DOE2                0x720
+
+#define HW_PINCTRL_PIN2IRQ0    0x800
+#define HW_PINCTRL_PIN2IRQ1    0x810
+#define HW_PINCTRL_PIN2IRQ2    0x820
+
+#define HW_PINCTRL_IRQEN0      0x900
+#define HW_PINCTRL_IRQEN1      0x910
+#define HW_PINCTRL_IRQEN2      0x920
+
+#define HW_PINCTRL_IRQLEVEL0   0xA00
+#define HW_PINCTRL_IRQLEVEL1   0xA10
+#define HW_PINCTRL_IRQLEVEL2   0xA20
+
+#define HW_PINCTRL_IRQPOL0     0xB00
+#define HW_PINCTRL_IRQPOL1     0xB10
+#define HW_PINCTRL_IRQPOL2     0xB20
+
+#define HW_PINCTRL_IRQSTAT0    0xC00
+#define HW_PINCTRL_IRQSTAT1    0xC10
+#define HW_PINCTRL_IRQSTAT2    0xC20
+
+#endif
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-power.h b/arch/arm/mach-stmp378x/include/mach/regs-power.h
new file mode 100644 (file)
index 0000000..e454c83
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * stmp378x: POWER register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef _MACH_REGS_POWER
+#define _MACH_REGS_POWER
+
+#define REGS_POWER_BASE        (STMP3XXX_REGS_BASE + 0x44000)
+#define REGS_POWER_PHYS        0x80044000
+#define REGS_POWER_SIZE        0x2000
+
+#define HW_POWER_CTRL          0x0
+#define BM_POWER_CTRL_ENIRQ_VDD5V_GT_VDDIO     0x00000001
+#define BP_POWER_CTRL_ENIRQ_VDD5V_GT_VDDIO     0
+#define BM_POWER_CTRL_ENIRQ_PSWITCH    0x00020000
+#define BM_POWER_CTRL_PSWITCH_IRQ      0x00100000
+#define BM_POWER_CTRL_CLKGATE  0x40000000
+
+#define HW_POWER_5VCTRL                0x10
+#define BM_POWER_5VCTRL_ENABLE_LINREG_ILIMIT   0x00000040
+
+#define HW_POWER_MINPWR                0x20
+
+#define HW_POWER_CHARGE                0x30
+
+#define HW_POWER_VDDDCTRL      0x40
+
+#define HW_POWER_VDDACTRL      0x50
+
+#define HW_POWER_VDDIOCTRL     0x60
+#define BM_POWER_VDDIOCTRL_TRG 0x0000001F
+#define BP_POWER_VDDIOCTRL_TRG 0
+
+#define HW_POWER_STS           0xC0
+#define BM_POWER_STS_VBUSVALID 0x00000002
+#define BM_POWER_STS_BVALID    0x00000004
+#define BM_POWER_STS_AVALID    0x00000008
+#define BM_POWER_STS_DC_OK     0x00000200
+
+#define HW_POWER_RESET         0x100
+
+#define HW_POWER_DEBUG         0x110
+#define BM_POWER_DEBUG_BVALIDPIOLOCK   0x00000002
+#define BM_POWER_DEBUG_AVALIDPIOLOCK   0x00000004
+#define BM_POWER_DEBUG_VBUSVALIDPIOLOCK        0x00000008
+
+#endif
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-pwm.h b/arch/arm/mach-stmp378x/include/mach/regs-pwm.h
new file mode 100644 (file)
index 0000000..0d0f9e5
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * stmp378x: PWM register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_PWM_BASE  (STMP3XXX_REGS_BASE + 0x64000)
+#define REGS_PWM_PHYS  0x80064000
+#define REGS_PWM_SIZE  0x2000
+
+#define HW_PWM_CTRL            0x0
+#define BM_PWM_CTRL_PWM2_ENABLE        0x00000004
+#define BM_PWM_CTRL_PWM2_ANA_CTRL_ENABLE       0x00000020
+
+#define HW_PWM_ACTIVE0         (0x10 + 0 * 0x20)
+#define HW_PWM_ACTIVE1         (0x10 + 1 * 0x20)
+#define HW_PWM_ACTIVE2         (0x10 + 2 * 0x20)
+#define HW_PWM_ACTIVE3         (0x10 + 3 * 0x20)
+
+#define HW_PWM_ACTIVEn         0x10
+#define BM_PWM_ACTIVEn_ACTIVE  0x0000FFFF
+#define BP_PWM_ACTIVEn_ACTIVE  0
+#define BM_PWM_ACTIVEn_INACTIVE        0xFFFF0000
+#define BP_PWM_ACTIVEn_INACTIVE        16
+
+#define HW_PWM_PERIOD0         (0x20 + 0 * 0x20)
+#define HW_PWM_PERIOD1         (0x20 + 1 * 0x20)
+#define HW_PWM_PERIOD2         (0x20 + 2 * 0x20)
+#define HW_PWM_PERIOD3         (0x20 + 3 * 0x20)
+
+#define HW_PWM_PERIODn         0x20
+#define BM_PWM_PERIODn_PERIOD  0x0000FFFF
+#define BP_PWM_PERIODn_PERIOD  0
+#define BM_PWM_PERIODn_ACTIVE_STATE    0x00030000
+#define BP_PWM_PERIODn_ACTIVE_STATE    16
+#define BM_PWM_PERIODn_INACTIVE_STATE  0x000C0000
+#define BP_PWM_PERIODn_INACTIVE_STATE  18
+#define BM_PWM_PERIODn_CDIV    0x00700000
+#define BP_PWM_PERIODn_CDIV    20
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-pxp.h b/arch/arm/mach-stmp378x/include/mach/regs-pxp.h
new file mode 100644 (file)
index 0000000..54d2978
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * stmp378x: PXP register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_PXP_BASE  (STMP3XXX_REGS_BASE + 0x2A000)
+#define REGS_PXP_PHYS  0x8002A000
+#define REGS_PXP_SIZE  0x2000
+
+#define HW_PXP_CTRL            0x0
+#define BM_PXP_CTRL_ENABLE     0x00000001
+#define BP_PXP_CTRL_ENABLE     0
+#define BM_PXP_CTRL_IRQ_ENABLE 0x00000002
+#define BM_PXP_CTRL_OUTPUT_RGB_FORMAT  0x000000F0
+#define BP_PXP_CTRL_OUTPUT_RGB_FORMAT  4
+#define BM_PXP_CTRL_ROTATE     0x00000300
+#define BP_PXP_CTRL_ROTATE     8
+#define BM_PXP_CTRL_HFLIP      0x00000400
+#define BM_PXP_CTRL_VFLIP      0x00000800
+#define BM_PXP_CTRL_S0_FORMAT  0x0000F000
+#define BP_PXP_CTRL_S0_FORMAT  12
+#define BM_PXP_CTRL_SCALE      0x00040000
+#define BM_PXP_CTRL_CROP       0x00080000
+
+#define HW_PXP_STAT            0x10
+#define BM_PXP_STAT_IRQ                0x00000001
+#define BP_PXP_STAT_IRQ                0
+
+#define HW_PXP_RGBBUF          0x20
+
+#define HW_PXP_RGBSIZE         0x40
+#define BM_PXP_RGBSIZE_HEIGHT  0x00000FFF
+#define BP_PXP_RGBSIZE_HEIGHT  0
+#define BM_PXP_RGBSIZE_WIDTH   0x00FFF000
+#define BP_PXP_RGBSIZE_WIDTH   12
+
+#define HW_PXP_S0BUF           0x50
+
+#define HW_PXP_S0UBUF          0x60
+
+#define HW_PXP_S0VBUF          0x70
+
+#define HW_PXP_S0PARAM         0x80
+#define BM_PXP_S0PARAM_HEIGHT  0x000000FF
+#define BP_PXP_S0PARAM_HEIGHT  0
+#define BM_PXP_S0PARAM_WIDTH   0x0000FF00
+#define BP_PXP_S0PARAM_WIDTH   8
+#define BM_PXP_S0PARAM_YBASE   0x00FF0000
+#define BP_PXP_S0PARAM_YBASE   16
+#define BM_PXP_S0PARAM_XBASE   0xFF000000
+#define BP_PXP_S0PARAM_XBASE   24
+
+#define HW_PXP_S0BACKGROUND    0x90
+
+#define HW_PXP_S0CROP          0xA0
+#define BM_PXP_S0CROP_HEIGHT   0x000000FF
+#define BP_PXP_S0CROP_HEIGHT   0
+#define BM_PXP_S0CROP_WIDTH    0x0000FF00
+#define BP_PXP_S0CROP_WIDTH    8
+#define BM_PXP_S0CROP_YBASE    0x00FF0000
+#define BP_PXP_S0CROP_YBASE    16
+#define BM_PXP_S0CROP_XBASE    0xFF000000
+#define BP_PXP_S0CROP_XBASE    24
+
+#define HW_PXP_S0SCALE         0xB0
+#define BM_PXP_S0SCALE_XSCALE  0x00003FFF
+#define BP_PXP_S0SCALE_XSCALE  0
+#define BM_PXP_S0SCALE_YSCALE  0x3FFF0000
+#define BP_PXP_S0SCALE_YSCALE  16
+
+#define HW_PXP_CSCCOEFF0       0xD0
+
+#define HW_PXP_CSCCOEFF1       0xE0
+
+#define HW_PXP_CSCCOEFF2       0xF0
+
+#define HW_PXP_S0COLORKEYLOW   0x180
+
+#define HW_PXP_S0COLORKEYHIGH  0x190
+
+#define HW_PXP_OL0             (0x200 + 0 * 0x40)
+#define HW_PXP_OL1             (0x200 + 1 * 0x40)
+#define HW_PXP_OL2             (0x200 + 2 * 0x40)
+#define HW_PXP_OL3             (0x200 + 3 * 0x40)
+#define HW_PXP_OL4             (0x200 + 4 * 0x40)
+#define HW_PXP_OL5             (0x200 + 5 * 0x40)
+#define HW_PXP_OL6             (0x200 + 6 * 0x40)
+#define HW_PXP_OL7             (0x200 + 7 * 0x40)
+
+#define HW_PXP_OLn             0x200
+
+#define HW_PXP_OL0SIZE         (0x210 + 0 * 0x40)
+#define HW_PXP_OL1SIZE         (0x210 + 1 * 0x40)
+#define HW_PXP_OL2SIZE         (0x210 + 2 * 0x40)
+#define HW_PXP_OL3SIZE         (0x210 + 3 * 0x40)
+#define HW_PXP_OL4SIZE         (0x210 + 4 * 0x40)
+#define HW_PXP_OL5SIZE         (0x210 + 5 * 0x40)
+#define HW_PXP_OL6SIZE         (0x210 + 6 * 0x40)
+#define HW_PXP_OL7SIZE         (0x210 + 7 * 0x40)
+
+#define HW_PXP_OLnSIZE         0x210
+#define BM_PXP_OLnSIZE_HEIGHT  0x000000FF
+#define BP_PXP_OLnSIZE_HEIGHT  0
+#define BM_PXP_OLnSIZE_WIDTH   0x0000FF00
+#define BP_PXP_OLnSIZE_WIDTH   8
+
+#define HW_PXP_OL0PARAM                (0x220 + 0 * 0x40)
+#define HW_PXP_OL1PARAM                (0x220 + 1 * 0x40)
+#define HW_PXP_OL2PARAM                (0x220 + 2 * 0x40)
+#define HW_PXP_OL3PARAM                (0x220 + 3 * 0x40)
+#define HW_PXP_OL4PARAM                (0x220 + 4 * 0x40)
+#define HW_PXP_OL5PARAM                (0x220 + 5 * 0x40)
+#define HW_PXP_OL6PARAM                (0x220 + 6 * 0x40)
+#define HW_PXP_OL7PARAM                (0x220 + 7 * 0x40)
+
+#define HW_PXP_OLnPARAM                0x220
+#define BM_PXP_OLnPARAM_ENABLE 0x00000001
+#define BP_PXP_OLnPARAM_ENABLE 0
+#define BM_PXP_OLnPARAM_ALPHA_CNTL     0x00000006
+#define BP_PXP_OLnPARAM_ALPHA_CNTL     1
+#define BM_PXP_OLnPARAM_ENABLE_COLORKEY        0x00000008
+#define BM_PXP_OLnPARAM_FORMAT 0x000000F0
+#define BP_PXP_OLnPARAM_FORMAT 4
+#define BM_PXP_OLnPARAM_ALPHA  0x0000FF00
+#define BP_PXP_OLnPARAM_ALPHA  8
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-rtc.h b/arch/arm/mach-stmp378x/include/mach/regs-rtc.h
new file mode 100644 (file)
index 0000000..b8dbd67
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * stmp378x: RTC register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_RTC_BASE  (STMP3XXX_REGS_BASE + 0x5C000)
+#define REGS_RTC_PHYS  0x8005C000
+#define REGS_RTC_SIZE  0x2000
+
+#define HW_RTC_CTRL            0x0
+#define BM_RTC_CTRL_ALARM_IRQ_EN       0x00000001
+#define BP_RTC_CTRL_ALARM_IRQ_EN       0
+#define BM_RTC_CTRL_ONEMSEC_IRQ_EN     0x00000002
+#define BM_RTC_CTRL_ALARM_IRQ  0x00000004
+#define BM_RTC_CTRL_ONEMSEC_IRQ        0x00000008
+#define BM_RTC_CTRL_WATCHDOGEN 0x00000010
+
+#define HW_RTC_STAT            0x10
+#define BM_RTC_STAT_NEW_REGS   0x0000FF00
+#define BP_RTC_STAT_NEW_REGS   8
+#define BM_RTC_STAT_STALE_REGS 0x00FF0000
+#define BP_RTC_STAT_STALE_REGS 16
+#define BM_RTC_STAT_RTC_PRESENT        0x80000000
+
+#define HW_RTC_SECONDS         0x30
+
+#define HW_RTC_ALARM           0x40
+
+#define HW_RTC_WATCHDOG                0x50
+
+#define HW_RTC_PERSISTENT0     0x60
+#define BM_RTC_PERSISTENT0_ALARM_WAKE_EN       0x00000002
+#define BM_RTC_PERSISTENT0_ALARM_EN    0x00000004
+#define BM_RTC_PERSISTENT0_XTAL24MHZ_PWRUP     0x00000010
+#define BM_RTC_PERSISTENT0_XTAL32KHZ_PWRUP     0x00000020
+#define BM_RTC_PERSISTENT0_ALARM_WAKE  0x00000080
+#define BM_RTC_PERSISTENT0_SPARE_ANALOG        0xFFFC0000
+#define BP_RTC_PERSISTENT0_SPARE_ANALOG        18
+
+#define HW_RTC_PERSISTENT1     0x70
+#define BM_RTC_PERSISTENT1_GENERAL     0xFFFFFFFF
+#define BP_RTC_PERSISTENT1_GENERAL     0
+
+#define HW_RTC_VERSION         0xD0
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-saif.h b/arch/arm/mach-stmp378x/include/mach/regs-saif.h
new file mode 100644 (file)
index 0000000..6df4176
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * stmp378x: SAIF register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_SAIF_SIZE 0x2000
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-spdif.h b/arch/arm/mach-stmp378x/include/mach/regs-spdif.h
new file mode 100644 (file)
index 0000000..8015398
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * stmp378x: SPDIF register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_SPDIF_BASE        (STMP3XXX_REGS_BASE + 0x54000)
+#define REGS_SPDIF_PHYS        0x80054000
+#define REGS_SPDIF_SIZE        0x2000
+
+#define HW_SPDIF_CTRL          0x0
+#define BM_SPDIF_CTRL_RUN      0x00000001
+#define BP_SPDIF_CTRL_RUN      0
+#define BM_SPDIF_CTRL_FIFO_ERROR_IRQ_EN        0x00000002
+#define BM_SPDIF_CTRL_FIFO_OVERFLOW_IRQ        0x00000004
+#define BM_SPDIF_CTRL_FIFO_UNDERFLOW_IRQ       0x00000008
+#define BM_SPDIF_CTRL_WORD_LENGTH      0x00000010
+#define BM_SPDIF_CTRL_CLKGATE  0x40000000
+#define BM_SPDIF_CTRL_SFTRST   0x80000000
+
+#define HW_SPDIF_STAT          0x10
+
+#define HW_SPDIF_FRAMECTRL     0x20
+
+#define HW_SPDIF_SRR           0x30
+#define BM_SPDIF_SRR_RATE      0x000FFFFF
+#define BP_SPDIF_SRR_RATE      0
+#define BM_SPDIF_SRR_BASEMULT  0x70000000
+#define BP_SPDIF_SRR_BASEMULT  28
+
+#define HW_SPDIF_DEBUG         0x40
+
+#define HW_SPDIF_DATA          0x50
+
+#define HW_SPDIF_VERSION       0x60
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-ssp.h b/arch/arm/mach-stmp378x/include/mach/regs-ssp.h
new file mode 100644 (file)
index 0000000..28aacf0
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * stmp378x: SSP register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_SSP1_BASE (STMP3XXX_REGS_BASE + 0x10000)
+#define REGS_SSP1_PHYS 0x80010000
+#define REGS_SSP2_BASE (STMP3XXX_REGS_BASE + 0x34000)
+#define REGS_SSP2_PHYS 0x80034000
+#define REGS_SSP_SIZE  0x2000
+
+#define HW_SSP_CTRL0           0x0
+#define BM_SSP_CTRL0_XFER_COUNT        0x0000FFFF
+#define BP_SSP_CTRL0_XFER_COUNT        0
+#define BM_SSP_CTRL0_ENABLE    0x00010000
+#define BM_SSP_CTRL0_GET_RESP  0x00020000
+#define BM_SSP_CTRL0_LONG_RESP 0x00080000
+#define BM_SSP_CTRL0_WAIT_FOR_CMD      0x00100000
+#define BM_SSP_CTRL0_WAIT_FOR_IRQ      0x00200000
+#define BM_SSP_CTRL0_BUS_WIDTH 0x00C00000
+#define BP_SSP_CTRL0_BUS_WIDTH 22
+#define BM_SSP_CTRL0_DATA_XFER 0x01000000
+#define BM_SSP_CTRL0_READ      0x02000000
+#define BM_SSP_CTRL0_IGNORE_CRC        0x04000000
+#define BM_SSP_CTRL0_LOCK_CS   0x08000000
+#define BM_SSP_CTRL0_RUN       0x20000000
+#define BM_SSP_CTRL0_CLKGATE   0x40000000
+#define BM_SSP_CTRL0_SFTRST    0x80000000
+
+#define HW_SSP_CMD0            0x10
+#define BM_SSP_CMD0_CMD                0x000000FF
+#define BP_SSP_CMD0_CMD                0
+#define BM_SSP_CMD0_BLOCK_COUNT        0x0000FF00
+#define BP_SSP_CMD0_BLOCK_COUNT        8
+#define BM_SSP_CMD0_BLOCK_SIZE 0x000F0000
+#define BP_SSP_CMD0_BLOCK_SIZE 16
+#define BM_SSP_CMD0_APPEND_8CYC        0x00100000
+#define BM_SSP_CMD1_CMD_ARG    0xFFFFFFFF
+#define BP_SSP_CMD1_CMD_ARG    0
+
+#define HW_SSP_TIMING          0x50
+#define BM_SSP_TIMING_CLOCK_RATE       0x000000FF
+#define BP_SSP_TIMING_CLOCK_RATE       0
+#define BM_SSP_TIMING_CLOCK_DIVIDE     0x0000FF00
+#define BP_SSP_TIMING_CLOCK_DIVIDE     8
+#define BM_SSP_TIMING_TIMEOUT  0xFFFF0000
+#define BP_SSP_TIMING_TIMEOUT  16
+
+#define HW_SSP_CTRL1           0x60
+#define BM_SSP_CTRL1_SSP_MODE  0x0000000F
+#define BP_SSP_CTRL1_SSP_MODE  0
+#define BM_SSP_CTRL1_WORD_LENGTH       0x000000F0
+#define BP_SSP_CTRL1_WORD_LENGTH       4
+#define BM_SSP_CTRL1_POLARITY  0x00000200
+#define BM_SSP_CTRL1_PHASE     0x00000400
+#define BM_SSP_CTRL1_DMA_ENABLE        0x00002000
+#define BM_SSP_CTRL1_FIFO_OVERRUN_IRQ  0x00008000
+#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN       0x00010000
+#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ  0x00020000
+#define BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ 0x00200000
+#define BM_SSP_CTRL1_DATA_CRC_IRQ_EN   0x00400000
+#define BM_SSP_CTRL1_DATA_CRC_IRQ      0x00800000
+#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN       0x01000000
+#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ  0x02000000
+#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN       0x04000000
+#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ  0x08000000
+#define BM_SSP_CTRL1_RESP_ERR_IRQ_EN   0x10000000
+#define BM_SSP_CTRL1_RESP_ERR_IRQ      0x20000000
+#define BM_SSP_CTRL1_SDIO_IRQ  0x80000000
+
+#define HW_SSP_DATA            0x70
+
+#define HW_SSP_SDRESP0         0x80
+
+#define HW_SSP_SDRESP1         0x90
+
+#define HW_SSP_SDRESP2         0xA0
+
+#define HW_SSP_SDRESP3         0xB0
+
+#define HW_SSP_STATUS          0xC0
+#define BM_SSP_STATUS_FIFO_EMPTY       0x00000020
+#define BM_SSP_STATUS_TIMEOUT  0x00001000
+#define BM_SSP_STATUS_RESP_TIMEOUT     0x00004000
+#define BM_SSP_STATUS_RESP_ERR 0x00008000
+#define BM_SSP_STATUS_RESP_CRC_ERR     0x00010000
+#define BM_SSP_STATUS_CARD_DETECT      0x10000000
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-sydma.h b/arch/arm/mach-stmp378x/include/mach/regs-sydma.h
new file mode 100644 (file)
index 0000000..08343a8
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * stmp378x: SYDMA register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_SYDMA_BASE        (STMP3XXX_REGS_BASE + 0x26000)
+#define REGS_SYDMA_PHYS        0x80026000
+#define REGS_SYDMA_SIZE        0x2000
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-timrot.h b/arch/arm/mach-stmp378x/include/mach/regs-timrot.h
new file mode 100644 (file)
index 0000000..b552795
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * stmp378x: TIMROT register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef _MACH_REGS_TIMROT
+#define _MACH_REGS_TIMROT
+
+#define REGS_TIMROT_BASE       (STMP3XXX_REGS_BASE + 0x68000)
+#define REGS_TIMROT_PHYS       0x80068000
+#define REGS_TIMROT_SIZE       0x2000
+
+#define HW_TIMROT_ROTCTRL      0x0
+#define BM_TIMROT_ROTCTRL_SELECT_A     0x00000007
+#define BP_TIMROT_ROTCTRL_SELECT_A     0
+#define BM_TIMROT_ROTCTRL_SELECT_B     0x00000070
+#define BP_TIMROT_ROTCTRL_SELECT_B     4
+#define BM_TIMROT_ROTCTRL_POLARITY_A   0x00000100
+#define BM_TIMROT_ROTCTRL_POLARITY_B   0x00000200
+#define BM_TIMROT_ROTCTRL_OVERSAMPLE   0x00000C00
+#define BP_TIMROT_ROTCTRL_OVERSAMPLE   10
+#define BM_TIMROT_ROTCTRL_RELATIVE     0x00001000
+#define BM_TIMROT_ROTCTRL_DIVIDER      0x003F0000
+#define BP_TIMROT_ROTCTRL_DIVIDER      16
+#define BM_TIMROT_ROTCTRL_ROTARY_PRESENT       0x20000000
+#define BM_TIMROT_ROTCTRL_CLKGATE      0x40000000
+#define BM_TIMROT_ROTCTRL_SFTRST       0x80000000
+
+#define HW_TIMROT_ROTCOUNT     0x10
+#define BM_TIMROT_ROTCOUNT_UPDOWN      0x0000FFFF
+#define BP_TIMROT_ROTCOUNT_UPDOWN      0
+
+#define HW_TIMROT_TIMCTRL0     (0x20 + 0 * 0x20)
+#define HW_TIMROT_TIMCTRL1     (0x20 + 1 * 0x20)
+#define HW_TIMROT_TIMCTRL2     (0x20 + 2 * 0x20)
+
+#define HW_TIMROT_TIMCTRLn     0x20
+#define BM_TIMROT_TIMCTRLn_SELECT      0x0000000F
+#define BP_TIMROT_TIMCTRLn_SELECT      0
+#define BM_TIMROT_TIMCTRLn_PRESCALE    0x00000030
+#define BP_TIMROT_TIMCTRLn_PRESCALE    4
+#define BM_TIMROT_TIMCTRLn_RELOAD      0x00000040
+#define BM_TIMROT_TIMCTRLn_UPDATE      0x00000080
+#define BM_TIMROT_TIMCTRLn_IRQ_EN      0x00004000
+#define BM_TIMROT_TIMCTRLn_IRQ 0x00008000
+
+#define HW_TIMROT_TIMCOUNT0    (0x30 + 0 * 0x20)
+#define HW_TIMROT_TIMCOUNT1    (0x30 + 1 * 0x20)
+#define HW_TIMROT_TIMCOUNT2    (0x30 + 2 * 0x20)
+
+#define HW_TIMROT_TIMCOUNTn    0x30
+
+#endif
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-tvenc.h b/arch/arm/mach-stmp378x/include/mach/regs-tvenc.h
new file mode 100644 (file)
index 0000000..7f895cb
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * stmp378x: TVENC register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_TVENC_BASE        (STMP3XXX_REGS_BASE + 0x38000)
+#define REGS_TVENC_PHYS        0x80038000
+#define REGS_TVENC_SIZE        0x2000
+
+#define HW_TVENC_CTRL          0x0
+#define BM_TVENC_CTRL_CLKGATE  0x40000000
+#define BM_TVENC_CTRL_SFTRST   0x80000000
+
+#define HW_TVENC_CONFIG                0x10
+#define BM_TVENC_CONFIG_ENCD_MODE      0x00000007
+#define BP_TVENC_CONFIG_ENCD_MODE      0
+#define BM_TVENC_CONFIG_SYNC_MODE      0x00000070
+#define BP_TVENC_CONFIG_SYNC_MODE      4
+#define BM_TVENC_CONFIG_FSYNC_PHS      0x00000200
+#define BM_TVENC_CONFIG_CGAIN  0x0000C000
+#define BP_TVENC_CONFIG_CGAIN  14
+#define BM_TVENC_CONFIG_YGAIN_SEL      0x00030000
+#define BP_TVENC_CONFIG_YGAIN_SEL      16
+#define BM_TVENC_CONFIG_PAL_SHAPE      0x00100000
+
+#define HW_TVENC_SYNCOFFSET    0x30
+
+#define HW_TVENC_COLORSUB0     0xC0
+
+#define HW_TVENC_COLORBURST    0x140
+#define BM_TVENC_COLORBURST_PBA        0x00FF0000
+#define BP_TVENC_COLORBURST_PBA        16
+#define BM_TVENC_COLORBURST_NBA        0xFF000000
+#define BP_TVENC_COLORBURST_NBA        24
+
+#define HW_TVENC_MACROVISION0  0x150
+
+#define HW_TVENC_MACROVISION1  0x160
+
+#define HW_TVENC_MACROVISION2  0x170
+
+#define HW_TVENC_MACROVISION3  0x180
+
+#define HW_TVENC_MACROVISION4  0x190
+
+#define HW_TVENC_DACCTRL       0x1A0
+#define BM_TVENC_DACCTRL_RVAL  0x00000070
+#define BP_TVENC_DACCTRL_RVAL  4
+#define BM_TVENC_DACCTRL_DUMP_TOVDD1   0x00000100
+#define BM_TVENC_DACCTRL_PWRUP1        0x00001000
+#define BM_TVENC_DACCTRL_GAINUP        0x00040000
+#define BM_TVENC_DACCTRL_GAINDN        0x00080000
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-uartapp.h b/arch/arm/mach-stmp378x/include/mach/regs-uartapp.h
new file mode 100644 (file)
index 0000000..a251e68
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * stmp378x: UARTAPP register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_UARTAPP1_BASE     (STMP3XXX_REGS_BASE + 0x6C000)
+#define REGS_UARTAPP1_PHYS     0x8006C000
+#define REGS_UARTAPP2_BASE     (STMP3XXX_REGS_BASE + 0x6E000)
+#define REGS_UARTAPP2_PHYS     0x8006E000
+#define REGS_UARTAPP_SIZE      0x2000
+
+#define HW_UARTAPP_CTRL0       0x0
+#define BM_UARTAPP_CTRL0_XFER_COUNT    0x0000FFFF
+#define BP_UARTAPP_CTRL0_XFER_COUNT    0
+#define BM_UARTAPP_CTRL0_RXTIMEOUT     0x07FF0000
+#define BP_UARTAPP_CTRL0_RXTIMEOUT     16
+#define BM_UARTAPP_CTRL0_RXTO_ENABLE   0x08000000
+#define BM_UARTAPP_CTRL0_RUN   0x20000000
+#define BM_UARTAPP_CTRL0_SFTRST        0x80000000
+#define BM_UARTAPP_CTRL1_XFER_COUNT    0x0000FFFF
+#define BP_UARTAPP_CTRL1_XFER_COUNT    0
+#define BM_UARTAPP_CTRL1_RUN   0x10000000
+
+#define HW_UARTAPP_CTRL2       0x20
+#define BM_UARTAPP_CTRL2_UARTEN        0x00000001
+#define BP_UARTAPP_CTRL2_UARTEN        0
+#define BM_UARTAPP_CTRL2_TXE   0x00000100
+#define BM_UARTAPP_CTRL2_RXE   0x00000200
+#define BM_UARTAPP_CTRL2_RTS   0x00000800
+#define BM_UARTAPP_CTRL2_RTSEN 0x00004000
+#define BM_UARTAPP_CTRL2_CTSEN 0x00008000
+#define BM_UARTAPP_CTRL2_RXDMAE        0x01000000
+#define BM_UARTAPP_CTRL2_TXDMAE        0x02000000
+#define BM_UARTAPP_CTRL2_DMAONERR      0x04000000
+
+#define HW_UARTAPP_LINECTRL    0x30
+#define BM_UARTAPP_LINECTRL_BRK        0x00000001
+#define BP_UARTAPP_LINECTRL_BRK        0
+#define BM_UARTAPP_LINECTRL_PEN        0x00000002
+#define BM_UARTAPP_LINECTRL_EPS        0x00000004
+#define BM_UARTAPP_LINECTRL_STP2       0x00000008
+#define BM_UARTAPP_LINECTRL_FEN        0x00000010
+#define BM_UARTAPP_LINECTRL_WLEN       0x00000060
+#define BP_UARTAPP_LINECTRL_WLEN       5
+#define BM_UARTAPP_LINECTRL_SPS        0x00000080
+#define BM_UARTAPP_LINECTRL_BAUD_DIVFRAC       0x00003F00
+#define BP_UARTAPP_LINECTRL_BAUD_DIVFRAC       8
+#define BM_UARTAPP_LINECTRL_BAUD_DIVINT        0xFFFF0000
+#define BP_UARTAPP_LINECTRL_BAUD_DIVINT        16
+
+#define HW_UARTAPP_INTR                0x50
+#define BM_UARTAPP_INTR_CTSMIS 0x00000002
+#define BM_UARTAPP_INTR_RTIS   0x00000040
+#define BM_UARTAPP_INTR_CTSMIEN        0x00020000
+#define BM_UARTAPP_INTR_RXIEN  0x00100000
+#define BM_UARTAPP_INTR_RTIEN  0x00400000
+
+#define HW_UARTAPP_DATA                0x60
+
+#define HW_UARTAPP_STAT                0x70
+#define BM_UARTAPP_STAT_RXCOUNT        0x0000FFFF
+#define BP_UARTAPP_STAT_RXCOUNT        0
+#define BM_UARTAPP_STAT_FERR   0x00010000
+#define BM_UARTAPP_STAT_PERR   0x00020000
+#define BM_UARTAPP_STAT_BERR   0x00040000
+#define BM_UARTAPP_STAT_OERR   0x00080000
+#define BM_UARTAPP_STAT_RXFE   0x01000000
+#define BM_UARTAPP_STAT_TXFF   0x02000000
+#define BM_UARTAPP_STAT_TXFE   0x08000000
+#define BM_UARTAPP_STAT_CTS    0x10000000
+
+#define HW_UARTAPP_VERSION     0x90
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-uartdbg.h b/arch/arm/mach-stmp378x/include/mach/regs-uartdbg.h
new file mode 100644 (file)
index 0000000..b810deb
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * stmp378x: UARTDBG register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_UARTDBG_BASE      (STMP3XXX_REGS_BASE + 0x70000)
+#define REGS_UARTDBG_PHYS      0x80070000
+#define REGS_UARTDBG_SIZE      0x2000
+
+#define HW_UARTDBGDR 0x00000000
+#define BP_UARTDBGDR_UNAVAILABLE      16
+#define BM_UARTDBGDR_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGDR_UNAVAILABLE(v) \
+       (((v) << 16) & BM_UARTDBGDR_UNAVAILABLE)
+#define BP_UARTDBGDR_RESERVED      12
+#define BM_UARTDBGDR_RESERVED 0x0000F000
+#define BF_UARTDBGDR_RESERVED(v)  \
+       (((v) << 12) & BM_UARTDBGDR_RESERVED)
+#define BM_UARTDBGDR_OE 0x00000800
+#define BM_UARTDBGDR_BE 0x00000400
+#define BM_UARTDBGDR_PE 0x00000200
+#define BM_UARTDBGDR_FE 0x00000100
+#define BP_UARTDBGDR_DATA      0
+#define BM_UARTDBGDR_DATA 0x000000FF
+#define BF_UARTDBGDR_DATA(v)  \
+       (((v) << 0) & BM_UARTDBGDR_DATA)
+#define HW_UARTDBGRSR_ECR 0x00000004
+#define BP_UARTDBGRSR_ECR_UNAVAILABLE      8
+#define BM_UARTDBGRSR_ECR_UNAVAILABLE 0xFFFFFF00
+#define BF_UARTDBGRSR_ECR_UNAVAILABLE(v) \
+       (((v) << 8) & BM_UARTDBGRSR_ECR_UNAVAILABLE)
+#define BP_UARTDBGRSR_ECR_EC      4
+#define BM_UARTDBGRSR_ECR_EC 0x000000F0
+#define BF_UARTDBGRSR_ECR_EC(v)  \
+       (((v) << 4) & BM_UARTDBGRSR_ECR_EC)
+#define BM_UARTDBGRSR_ECR_OE 0x00000008
+#define BM_UARTDBGRSR_ECR_BE 0x00000004
+#define BM_UARTDBGRSR_ECR_PE 0x00000002
+#define BM_UARTDBGRSR_ECR_FE 0x00000001
+#define HW_UARTDBGFR 0x00000018
+#define BP_UARTDBGFR_UNAVAILABLE      16
+#define BM_UARTDBGFR_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGFR_UNAVAILABLE(v) \
+       (((v) << 16) & BM_UARTDBGFR_UNAVAILABLE)
+#define BP_UARTDBGFR_RESERVED      9
+#define BM_UARTDBGFR_RESERVED 0x0000FE00
+#define BF_UARTDBGFR_RESERVED(v)  \
+       (((v) << 9) & BM_UARTDBGFR_RESERVED)
+#define BM_UARTDBGFR_RI 0x00000100
+#define BM_UARTDBGFR_TXFE 0x00000080
+#define BM_UARTDBGFR_RXFF 0x00000040
+#define BM_UARTDBGFR_TXFF 0x00000020
+#define BM_UARTDBGFR_RXFE 0x00000010
+#define BM_UARTDBGFR_BUSY 0x00000008
+#define BM_UARTDBGFR_DCD 0x00000004
+#define BM_UARTDBGFR_DSR 0x00000002
+#define BM_UARTDBGFR_CTS 0x00000001
+#define HW_UARTDBGILPR 0x00000020
+#define BP_UARTDBGILPR_UNAVAILABLE      8
+#define BM_UARTDBGILPR_UNAVAILABLE 0xFFFFFF00
+#define BF_UARTDBGILPR_UNAVAILABLE(v) \
+       (((v) << 8) & BM_UARTDBGILPR_UNAVAILABLE)
+#define BP_UARTDBGILPR_ILPDVSR      0
+#define BM_UARTDBGILPR_ILPDVSR 0x000000FF
+#define BF_UARTDBGILPR_ILPDVSR(v)  \
+       (((v) << 0) & BM_UARTDBGILPR_ILPDVSR)
+#define HW_UARTDBGIBRD 0x00000024
+#define BP_UARTDBGIBRD_UNAVAILABLE      16
+#define BM_UARTDBGIBRD_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGIBRD_UNAVAILABLE(v) \
+       (((v) << 16) & BM_UARTDBGIBRD_UNAVAILABLE)
+#define BP_UARTDBGIBRD_BAUD_DIVINT      0
+#define BM_UARTDBGIBRD_BAUD_DIVINT 0x0000FFFF
+#define BF_UARTDBGIBRD_BAUD_DIVINT(v)  \
+       (((v) << 0) & BM_UARTDBGIBRD_BAUD_DIVINT)
+#define HW_UARTDBGFBRD 0x00000028
+#define BP_UARTDBGFBRD_UNAVAILABLE      8
+#define BM_UARTDBGFBRD_UNAVAILABLE 0xFFFFFF00
+#define BF_UARTDBGFBRD_UNAVAILABLE(v) \
+       (((v) << 8) & BM_UARTDBGFBRD_UNAVAILABLE)
+#define BP_UARTDBGFBRD_RESERVED      6
+#define BM_UARTDBGFBRD_RESERVED 0x000000C0
+#define BF_UARTDBGFBRD_RESERVED(v)  \
+       (((v) << 6) & BM_UARTDBGFBRD_RESERVED)
+#define BP_UARTDBGFBRD_BAUD_DIVFRAC      0
+#define BM_UARTDBGFBRD_BAUD_DIVFRAC 0x0000003F
+#define BF_UARTDBGFBRD_BAUD_DIVFRAC(v)  \
+       (((v) << 0) & BM_UARTDBGFBRD_BAUD_DIVFRAC)
+#define HW_UARTDBGLCR_H 0x0000002c
+#define BP_UARTDBGLCR_H_UNAVAILABLE      16
+#define BM_UARTDBGLCR_H_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGLCR_H_UNAVAILABLE(v) \
+       (((v) << 16) & BM_UARTDBGLCR_H_UNAVAILABLE)
+#define BP_UARTDBGLCR_H_RESERVED      8
+#define BM_UARTDBGLCR_H_RESERVED 0x0000FF00
+#define BF_UARTDBGLCR_H_RESERVED(v)  \
+       (((v) << 8) & BM_UARTDBGLCR_H_RESERVED)
+#define BM_UARTDBGLCR_H_SPS 0x00000080
+#define BP_UARTDBGLCR_H_WLEN      5
+#define BM_UARTDBGLCR_H_WLEN 0x00000060
+#define BF_UARTDBGLCR_H_WLEN(v)  \
+       (((v) << 5) & BM_UARTDBGLCR_H_WLEN)
+#define BM_UARTDBGLCR_H_FEN 0x00000010
+#define BM_UARTDBGLCR_H_STP2 0x00000008
+#define BM_UARTDBGLCR_H_EPS 0x00000004
+#define BM_UARTDBGLCR_H_PEN 0x00000002
+#define BM_UARTDBGLCR_H_BRK 0x00000001
+#define HW_UARTDBGCR 0x00000030
+#define BP_UARTDBGCR_UNAVAILABLE      16
+#define BM_UARTDBGCR_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGCR_UNAVAILABLE(v) \
+       (((v) << 16) & BM_UARTDBGCR_UNAVAILABLE)
+#define BM_UARTDBGCR_CTSEN 0x00008000
+#define BM_UARTDBGCR_RTSEN 0x00004000
+#define BM_UARTDBGCR_OUT2 0x00002000
+#define BM_UARTDBGCR_OUT1 0x00001000
+#define BM_UARTDBGCR_RTS 0x00000800
+#define BM_UARTDBGCR_DTR 0x00000400
+#define BM_UARTDBGCR_RXE 0x00000200
+#define BM_UARTDBGCR_TXE 0x00000100
+#define BM_UARTDBGCR_LBE 0x00000080
+#define BP_UARTDBGCR_RESERVED      3
+#define BM_UARTDBGCR_RESERVED 0x00000078
+#define BF_UARTDBGCR_RESERVED(v)  \
+       (((v) << 3) & BM_UARTDBGCR_RESERVED)
+#define BM_UARTDBGCR_SIRLP 0x00000004
+#define BM_UARTDBGCR_SIREN 0x00000002
+#define BM_UARTDBGCR_UARTEN 0x00000001
+#define HW_UARTDBGIFLS 0x00000034
+#define BP_UARTDBGIFLS_UNAVAILABLE      16
+#define BM_UARTDBGIFLS_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGIFLS_UNAVAILABLE(v) \
+       (((v) << 16) & BM_UARTDBGIFLS_UNAVAILABLE)
+#define BP_UARTDBGIFLS_RESERVED      6
+#define BM_UARTDBGIFLS_RESERVED 0x0000FFC0
+#define BF_UARTDBGIFLS_RESERVED(v)  \
+       (((v) << 6) & BM_UARTDBGIFLS_RESERVED)
+#define BP_UARTDBGIFLS_RXIFLSEL      3
+#define BM_UARTDBGIFLS_RXIFLSEL 0x00000038
+#define BF_UARTDBGIFLS_RXIFLSEL(v)  \
+       (((v) << 3) & BM_UARTDBGIFLS_RXIFLSEL)
+#define BV_UARTDBGIFLS_RXIFLSEL__NOT_EMPTY      0x0
+#define BV_UARTDBGIFLS_RXIFLSEL__ONE_QUARTER    0x1
+#define BV_UARTDBGIFLS_RXIFLSEL__ONE_HALF       0x2
+#define BV_UARTDBGIFLS_RXIFLSEL__THREE_QUARTERS 0x3
+#define BV_UARTDBGIFLS_RXIFLSEL__SEVEN_EIGHTHS  0x4
+#define BV_UARTDBGIFLS_RXIFLSEL__INVALID5       0x5
+#define BV_UARTDBGIFLS_RXIFLSEL__INVALID6       0x6
+#define BV_UARTDBGIFLS_RXIFLSEL__INVALID7       0x7
+#define BP_UARTDBGIFLS_TXIFLSEL      0
+#define BM_UARTDBGIFLS_TXIFLSEL 0x00000007
+#define BF_UARTDBGIFLS_TXIFLSEL(v)  \
+       (((v) << 0) & BM_UARTDBGIFLS_TXIFLSEL)
+#define BV_UARTDBGIFLS_TXIFLSEL__EMPTY   0x0
+#define BV_UARTDBGIFLS_TXIFLSEL__ONE_QUARTER    0x1
+#define BV_UARTDBGIFLS_TXIFLSEL__ONE_HALF       0x2
+#define BV_UARTDBGIFLS_TXIFLSEL__THREE_QUARTERS 0x3
+#define BV_UARTDBGIFLS_TXIFLSEL__SEVEN_EIGHTHS  0x4
+#define BV_UARTDBGIFLS_TXIFLSEL__INVALID5       0x5
+#define BV_UARTDBGIFLS_TXIFLSEL__INVALID6       0x6
+#define BV_UARTDBGIFLS_TXIFLSEL__INVALID7       0x7
+#define HW_UARTDBGIMSC 0x00000038
+#define BP_UARTDBGIMSC_UNAVAILABLE      16
+#define BM_UARTDBGIMSC_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGIMSC_UNAVAILABLE(v) \
+       (((v) << 16) & BM_UARTDBGIMSC_UNAVAILABLE)
+#define BP_UARTDBGIMSC_RESERVED      11
+#define BM_UARTDBGIMSC_RESERVED 0x0000F800
+#define BF_UARTDBGIMSC_RESERVED(v)  \
+       (((v) << 11) & BM_UARTDBGIMSC_RESERVED)
+#define BM_UARTDBGIMSC_OEIM 0x00000400
+#define BM_UARTDBGIMSC_BEIM 0x00000200
+#define BM_UARTDBGIMSC_PEIM 0x00000100
+#define BM_UARTDBGIMSC_FEIM 0x00000080
+#define BM_UARTDBGIMSC_RTIM 0x00000040
+#define BM_UARTDBGIMSC_TXIM 0x00000020
+#define BM_UARTDBGIMSC_RXIM 0x00000010
+#define BM_UARTDBGIMSC_DSRMIM 0x00000008
+#define BM_UARTDBGIMSC_DCDMIM 0x00000004
+#define BM_UARTDBGIMSC_CTSMIM 0x00000002
+#define BM_UARTDBGIMSC_RIMIM 0x00000001
+#define HW_UARTDBGRIS 0x0000003c
+#define BP_UARTDBGRIS_UNAVAILABLE      16
+#define BM_UARTDBGRIS_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGRIS_UNAVAILABLE(v) \
+       (((v) << 16) & BM_UARTDBGRIS_UNAVAILABLE)
+#define BP_UARTDBGRIS_RESERVED      11
+#define BM_UARTDBGRIS_RESERVED 0x0000F800
+#define BF_UARTDBGRIS_RESERVED(v)  \
+       (((v) << 11) & BM_UARTDBGRIS_RESERVED)
+#define BM_UARTDBGRIS_OERIS 0x00000400
+#define BM_UARTDBGRIS_BERIS 0x00000200
+#define BM_UARTDBGRIS_PERIS 0x00000100
+#define BM_UARTDBGRIS_FERIS 0x00000080
+#define BM_UARTDBGRIS_RTRIS 0x00000040
+#define BM_UARTDBGRIS_TXRIS 0x00000020
+#define BM_UARTDBGRIS_RXRIS 0x00000010
+#define BM_UARTDBGRIS_DSRRMIS 0x00000008
+#define BM_UARTDBGRIS_DCDRMIS 0x00000004
+#define BM_UARTDBGRIS_CTSRMIS 0x00000002
+#define BM_UARTDBGRIS_RIRMIS 0x00000001
+#define HW_UARTDBGMIS 0x00000040
+#define BP_UARTDBGMIS_UNAVAILABLE      16
+#define BM_UARTDBGMIS_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGMIS_UNAVAILABLE(v) \
+       (((v) << 16) & BM_UARTDBGMIS_UNAVAILABLE)
+#define BP_UARTDBGMIS_RESERVED      11
+#define BM_UARTDBGMIS_RESERVED 0x0000F800
+#define BF_UARTDBGMIS_RESERVED(v)  \
+       (((v) << 11) & BM_UARTDBGMIS_RESERVED)
+#define BM_UARTDBGMIS_OEMIS 0x00000400
+#define BM_UARTDBGMIS_BEMIS 0x00000200
+#define BM_UARTDBGMIS_PEMIS 0x00000100
+#define BM_UARTDBGMIS_FEMIS 0x00000080
+#define BM_UARTDBGMIS_RTMIS 0x00000040
+#define BM_UARTDBGMIS_TXMIS 0x00000020
+#define BM_UARTDBGMIS_RXMIS 0x00000010
+#define BM_UARTDBGMIS_DSRMMIS 0x00000008
+#define BM_UARTDBGMIS_DCDMMIS 0x00000004
+#define BM_UARTDBGMIS_CTSMMIS 0x00000002
+#define BM_UARTDBGMIS_RIMMIS 0x00000001
+#define HW_UARTDBGICR 0x00000044
+#define BP_UARTDBGICR_UNAVAILABLE      16
+#define BM_UARTDBGICR_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGICR_UNAVAILABLE(v) \
+       (((v) << 16) & BM_UARTDBGICR_UNAVAILABLE)
+#define BP_UARTDBGICR_RESERVED      11
+#define BM_UARTDBGICR_RESERVED 0x0000F800
+#define BF_UARTDBGICR_RESERVED(v)  \
+       (((v) << 11) & BM_UARTDBGICR_RESERVED)
+#define BM_UARTDBGICR_OEIC 0x00000400
+#define BM_UARTDBGICR_BEIC 0x00000200
+#define BM_UARTDBGICR_PEIC 0x00000100
+#define BM_UARTDBGICR_FEIC 0x00000080
+#define BM_UARTDBGICR_RTIC 0x00000040
+#define BM_UARTDBGICR_TXIC 0x00000020
+#define BM_UARTDBGICR_RXIC 0x00000010
+#define BM_UARTDBGICR_DSRMIC 0x00000008
+#define BM_UARTDBGICR_DCDMIC 0x00000004
+#define BM_UARTDBGICR_CTSMIC 0x00000002
+#define BM_UARTDBGICR_RIMIC 0x00000001
+#define HW_UARTDBGDMACR 0x00000048
+#define BP_UARTDBGDMACR_UNAVAILABLE      16
+#define BM_UARTDBGDMACR_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGDMACR_UNAVAILABLE(v) \
+       (((v) << 16) & BM_UARTDBGDMACR_UNAVAILABLE)
+#define BP_UARTDBGDMACR_RESERVED      3
+#define BM_UARTDBGDMACR_RESERVED 0x0000FFF8
+#define BF_UARTDBGDMACR_RESERVED(v)  \
+       (((v) << 3) & BM_UARTDBGDMACR_RESERVED)
+#define BM_UARTDBGDMACR_DMAONERR 0x00000004
+#define BM_UARTDBGDMACR_TXDMAE 0x00000002
+#define BM_UARTDBGDMACR_RXDMAE 0x00000001
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-usbctrl.h b/arch/arm/mach-stmp378x/include/mach/regs-usbctrl.h
new file mode 100644 (file)
index 0000000..25112c1
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * stmp378x: USBCTRL register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_USBCTRL_BASE      (STMP3XXX_REGS_BASE + 0x80000)
+#define REGS_USBCTRL_PHYS      0x80080000
+#define REGS_USBCTRL_SIZE      0x2000
+
+#define HW_USBCTRL_USBCMD      0x140
+#define BM_USBCTRL_USBCMD_RS   0x00000001
+#define BP_USBCTRL_USBCMD_RS   0
+#define BM_USBCTRL_USBCMD_RST  0x00000002
+
+#define HW_USBCTRL_USBINTR     0x148
+#define BM_USBCTRL_USBINTR_UE  0x00000001
+#define BP_USBCTRL_USBINTR_UE  0
+
+#define HW_USBCTRL_PORTSC1     0x184
+#define BM_USBCTRL_PORTSC1_PHCD        0x00800000
+
+#define HW_USBCTRL_OTGSC       0x1A4
+#define BM_USBCTRL_OTGSC_ID    0x00000100
+#define BM_USBCTRL_OTGSC_IDIS  0x00010000
+#define BM_USBCTRL_OTGSC_IDIE  0x01000000
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-usbphy.h b/arch/arm/mach-stmp378x/include/mach/regs-usbphy.h
new file mode 100644 (file)
index 0000000..11f3b73
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * stmp378x: USBPHY register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_USBPHY_BASE       (STMP3XXX_REGS_BASE + 0x7C000)
+#define REGS_USBPHY_PHYS       0x8007C000
+#define REGS_USBPHY_SIZE       0x2000
+
+#define HW_USBPHY_PWD          0x0
+
+#define HW_USBPHY_CTRL         0x30
+#define BM_USBPHY_CTRL_ENHOSTDISCONDETECT      0x00000002
+#define BM_USBPHY_CTRL_ENDEVPLUGINDETECT       0x00000010
+#define BM_USBPHY_CTRL_ENOTGIDDETECT   0x00000080
+#define BM_USBPHY_CTRL_ENIRQDEVPLUGIN  0x00000800
+#define BM_USBPHY_CTRL_CLKGATE 0x40000000
+#define BM_USBPHY_CTRL_SFTRST  0x80000000
+
+#define HW_USBPHY_STATUS       0x40
+#define BM_USBPHY_STATUS_DEVPLUGIN_STATUS      0x00000040
+#define BM_USBPHY_STATUS_OTGID_STATUS  0x00000100
diff --git a/arch/arm/mach-stmp378x/stmp378x.c b/arch/arm/mach-stmp378x/stmp378x.c
new file mode 100644 (file)
index 0000000..ddd49a7
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * Freescale STMP378X platform support
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/dma.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+
+#include <mach/pins.h>
+#include <mach/pinmux.h>
+#include <mach/dma.h>
+#include <mach/hardware.h>
+#include <mach/system.h>
+#include <mach/platform.h>
+#include <mach/stmp3xxx.h>
+#include <mach/regs-icoll.h>
+#include <mach/regs-apbh.h>
+#include <mach/regs-apbx.h>
+#include <mach/regs-pxp.h>
+#include <mach/regs-i2c.h>
+
+#include "stmp378x.h"
+/*
+ * IRQ handling
+ */
+static void stmp378x_ack_irq(unsigned int irq)
+{
+       /* Tell ICOLL to release IRQ line */
+       __raw_writel(0, REGS_ICOLL_BASE + HW_ICOLL_VECTOR);
+
+       /* ACK current interrupt */
+       __raw_writel(0x01 /* BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0 */,
+                       REGS_ICOLL_BASE + HW_ICOLL_LEVELACK);
+
+       /* Barrier */
+       (void)__raw_readl(REGS_ICOLL_BASE + HW_ICOLL_STAT);
+}
+
+static void stmp378x_mask_irq(unsigned int irq)
+{
+       /* IRQ disable */
+       stmp3xxx_clearl(BM_ICOLL_INTERRUPTn_ENABLE,
+                       REGS_ICOLL_BASE + HW_ICOLL_INTERRUPTn + irq * 0x10);
+}
+
+static void stmp378x_unmask_irq(unsigned int irq)
+{
+       /* IRQ enable */
+       stmp3xxx_setl(BM_ICOLL_INTERRUPTn_ENABLE,
+                     REGS_ICOLL_BASE + HW_ICOLL_INTERRUPTn + irq * 0x10);
+}
+
+static struct irq_chip stmp378x_chip = {
+       .ack    = stmp378x_ack_irq,
+       .mask   = stmp378x_mask_irq,
+       .unmask = stmp378x_unmask_irq,
+};
+
+void __init stmp378x_init_irq(void)
+{
+       stmp3xxx_init_irq(&stmp378x_chip);
+}
+
+/*
+ * DMA interrupt handling
+ */
+void stmp3xxx_arch_dma_enable_interrupt(int channel)
+{
+       void __iomem *c1, *c2;
+
+       switch (STMP3XXX_DMA_BUS(channel)) {
+       case STMP3XXX_BUS_APBH:
+               c1 = REGS_APBH_BASE + HW_APBH_CTRL1;
+               c2 = REGS_APBH_BASE + HW_APBH_CTRL2;
+               break;
+
+       case STMP3XXX_BUS_APBX:
+               c1 = REGS_APBX_BASE + HW_APBX_CTRL1;
+               c2 = REGS_APBX_BASE + HW_APBX_CTRL2;
+               break;
+
+       default:
+               return;
+       }
+       stmp3xxx_setl(1 << (16 + STMP3XXX_DMA_CHANNEL(channel)), c1);
+       stmp3xxx_setl(1 << (16 + STMP3XXX_DMA_CHANNEL(channel)), c2);
+}
+EXPORT_SYMBOL(stmp3xxx_arch_dma_enable_interrupt);
+
+void stmp3xxx_arch_dma_clear_interrupt(int channel)
+{
+       void __iomem *c1, *c2;
+
+       switch (STMP3XXX_DMA_BUS(channel)) {
+       case STMP3XXX_BUS_APBH:
+               c1 = REGS_APBH_BASE + HW_APBH_CTRL1;
+               c2 = REGS_APBH_BASE + HW_APBH_CTRL2;
+               break;
+
+       case STMP3XXX_BUS_APBX:
+               c1 = REGS_APBX_BASE + HW_APBX_CTRL1;
+               c2 = REGS_APBX_BASE + HW_APBX_CTRL2;
+               break;
+
+       default:
+               return;
+       }
+       stmp3xxx_clearl(1 << STMP3XXX_DMA_CHANNEL(channel), c1);
+       stmp3xxx_clearl(1 << STMP3XXX_DMA_CHANNEL(channel), c2);
+}
+EXPORT_SYMBOL(stmp3xxx_arch_dma_clear_interrupt);
+
+int stmp3xxx_arch_dma_is_interrupt(int channel)
+{
+       int r = 0;
+
+       switch (STMP3XXX_DMA_BUS(channel)) {
+       case STMP3XXX_BUS_APBH:
+               r = __raw_readl(REGS_APBH_BASE + HW_APBH_CTRL1) &
+                       (1 << STMP3XXX_DMA_CHANNEL(channel));
+               break;
+
+       case STMP3XXX_BUS_APBX:
+               r = __raw_readl(REGS_APBX_BASE + HW_APBX_CTRL1) &
+                       (1 << STMP3XXX_DMA_CHANNEL(channel));
+               break;
+       }
+       return r;
+}
+EXPORT_SYMBOL(stmp3xxx_arch_dma_is_interrupt);
+
+void stmp3xxx_arch_dma_reset_channel(int channel)
+{
+       unsigned chbit = 1 << STMP3XXX_DMA_CHANNEL(channel);
+       void __iomem *c0;
+       u32 mask;
+
+       switch (STMP3XXX_DMA_BUS(channel)) {
+       case STMP3XXX_BUS_APBH:
+               c0 = REGS_APBH_BASE + HW_APBH_CTRL0;
+               mask = chbit << BP_APBH_CTRL0_RESET_CHANNEL;
+               break;
+       case STMP3XXX_BUS_APBX:
+               c0 = REGS_APBX_BASE + HW_APBX_CHANNEL_CTRL;
+               mask = chbit << BP_APBX_CHANNEL_CTRL_RESET_CHANNEL;
+               break;
+       default:
+               return;
+       }
+
+       /* Reset channel and wait for it to complete */
+       stmp3xxx_setl(mask, c0);
+       while (__raw_readl(c0) & mask)
+               cpu_relax();
+}
+EXPORT_SYMBOL(stmp3xxx_arch_dma_reset_channel);
+
+void stmp3xxx_arch_dma_freeze(int channel)
+{
+       unsigned chbit = 1 << STMP3XXX_DMA_CHANNEL(channel);
+       u32 mask = 1 << chbit;
+
+       switch (STMP3XXX_DMA_BUS(channel)) {
+       case STMP3XXX_BUS_APBH:
+               stmp3xxx_setl(mask, REGS_APBH_BASE + HW_APBH_CTRL0);
+               break;
+       case STMP3XXX_BUS_APBX:
+               stmp3xxx_setl(mask, REGS_APBX_BASE + HW_APBX_CHANNEL_CTRL);
+               break;
+       }
+}
+EXPORT_SYMBOL(stmp3xxx_arch_dma_freeze);
+
+void stmp3xxx_arch_dma_unfreeze(int channel)
+{
+       unsigned chbit = 1 << STMP3XXX_DMA_CHANNEL(channel);
+       u32 mask = 1 << chbit;
+
+       switch (STMP3XXX_DMA_BUS(channel)) {
+       case STMP3XXX_BUS_APBH:
+               stmp3xxx_clearl(mask, REGS_APBH_BASE + HW_APBH_CTRL0);
+               break;
+       case STMP3XXX_BUS_APBX:
+               stmp3xxx_clearl(mask, REGS_APBX_BASE + HW_APBX_CHANNEL_CTRL);
+               break;
+       }
+}
+EXPORT_SYMBOL(stmp3xxx_arch_dma_unfreeze);
+
+/*
+ * The registers are all very closely mapped, so we might as well map them all
+ * with a single mapping
+ *
+ * Logical      Physical
+ * f0000000    80000000        On-chip registers
+ * f1000000    00000000        32k on-chip SRAM
+ */
+
+static struct map_desc stmp378x_io_desc[] __initdata = {
+       {
+               .virtual        = (u32)STMP3XXX_REGS_BASE,
+               .pfn            = __phys_to_pfn(STMP3XXX_REGS_PHBASE),
+               .length         = STMP3XXX_REGS_SIZE,
+               .type           = MT_DEVICE,
+       },
+       {
+               .virtual        = (u32)STMP3XXX_OCRAM_BASE,
+               .pfn            = __phys_to_pfn(STMP3XXX_OCRAM_PHBASE),
+               .length         = STMP3XXX_OCRAM_SIZE,
+               .type           = MT_DEVICE,
+       },
+};
+
+
+static u64 common_dmamask = DMA_BIT_MASK(32);
+
+/*
+ * devices that are present only on stmp378x, not on all 3xxx boards:
+ *     PxP
+ *     I2C
+ */
+static struct resource pxp_resource[] = {
+       {
+               .flags  = IORESOURCE_MEM,
+               .start  = REGS_PXP_PHYS,
+               .end    = REGS_PXP_PHYS + REGS_PXP_SIZE,
+       }, {
+               .flags  = IORESOURCE_IRQ,
+               .start  = IRQ_PXP,
+               .end    = IRQ_PXP,
+       },
+};
+
+struct platform_device stmp378x_pxp = {
+       .name           = "stmp3xxx-pxp",
+       .id             = -1,
+       .dev            = {
+               .dma_mask               = &common_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+       .num_resources  = ARRAY_SIZE(pxp_resource),
+       .resource       = pxp_resource,
+};
+
+static struct resource i2c_resources[] = {
+       {
+               .flags = IORESOURCE_IRQ,
+               .start = IRQ_I2C_ERROR,
+               .end = IRQ_I2C_ERROR,
+       }, {
+               .flags = IORESOURCE_MEM,
+               .start = REGS_I2C_PHYS,
+               .end = REGS_I2C_PHYS + REGS_I2C_SIZE,
+       }, {
+               .flags = IORESOURCE_DMA,
+               .start = STMP3XXX_DMA(3, STMP3XXX_BUS_APBX),
+               .end = STMP3XXX_DMA(3, STMP3XXX_BUS_APBX),
+       },
+};
+
+struct platform_device stmp378x_i2c = {
+       .name = "i2c_stmp3xxx",
+       .id = 0,
+       .dev    = {
+               .dma_mask       = &common_dmamask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+       },
+       .resource = i2c_resources,
+       .num_resources = ARRAY_SIZE(i2c_resources),
+};
+
+void __init stmp378x_map_io(void)
+{
+       iotable_init(stmp378x_io_desc, ARRAY_SIZE(stmp378x_io_desc));
+}
diff --git a/arch/arm/mach-stmp378x/stmp378x.h b/arch/arm/mach-stmp378x/stmp378x.h
new file mode 100644 (file)
index 0000000..0dc15b3
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Freescale STMP37XX/STMP378X internal functions and data declarations
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __MACH_STMP378X_H
+#define __MACH_STMP378X_H
+
+void stmp378x_map_io(void);
+void stmp378x_init_irq(void);
+
+extern struct platform_device stmp378x_pxp, stmp378x_i2c;
+#endif /* __MACH_STMP378X_COMMON_H */
diff --git a/arch/arm/mach-stmp378x/stmp378x_devb.c b/arch/arm/mach-stmp378x/stmp378x_devb.c
new file mode 100644 (file)
index 0000000..90d8fe6
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * Freescale STMP378X development board support
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/spi/spi.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/pins.h>
+#include <mach/pinmux.h>
+#include <mach/platform.h>
+#include <mach/stmp3xxx.h>
+#include <mach/mmc.h>
+#include <mach/gpmi.h>
+
+#include "stmp378x.h"
+
+static struct platform_device *devices[] = {
+       &stmp3xxx_dbguart,
+       &stmp3xxx_appuart,
+       &stmp3xxx_watchdog,
+       &stmp3xxx_touchscreen,
+       &stmp3xxx_rtc,
+       &stmp3xxx_keyboard,
+       &stmp3xxx_framebuffer,
+       &stmp3xxx_backlight,
+       &stmp3xxx_rotdec,
+       &stmp3xxx_persistent,
+       &stmp3xxx_dcp_bootstream,
+       &stmp3xxx_dcp,
+       &stmp3xxx_battery,
+       &stmp378x_pxp,
+       &stmp378x_i2c,
+};
+
+static struct pin_desc i2c_pins_desc[] = {
+       { PINID_I2C_SCL, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+       { PINID_I2C_SDA, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+};
+
+static struct pin_group i2c_pins = {
+       .pins           = i2c_pins_desc,
+       .nr_pins        = ARRAY_SIZE(i2c_pins_desc),
+};
+
+static struct pin_desc dbguart_pins_0[] = {
+       { PINID_PWM0, PIN_FUN3, },
+       { PINID_PWM1, PIN_FUN3, },
+};
+
+static struct pin_group dbguart_pins[] = {
+       [0] = {
+               .pins           = dbguart_pins_0,
+               .nr_pins        = ARRAY_SIZE(dbguart_pins_0),
+       },
+};
+
+static int dbguart_pins_control(int id, int request)
+{
+       int r = 0;
+
+       if (request)
+               r = stmp3xxx_request_pin_group(&dbguart_pins[id], "debug uart");
+       else
+               stmp3xxx_release_pin_group(&dbguart_pins[id], "debug uart");
+       return r;
+}
+
+static struct pin_desc appuart_pins_0[] = {
+       { PINID_AUART1_CTS, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
+       { PINID_AUART1_RTS, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
+       { PINID_AUART1_RX, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
+       { PINID_AUART1_TX, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
+};
+
+static struct pin_desc appuart_pins_1[] = {
+#if 0 /* enable these when second appuart will be connected */
+       { PINID_AUART2_CTS, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
+       { PINID_AUART2_RTS, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
+       { PINID_AUART2_RX, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
+       { PINID_AUART2_TX, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
+#endif
+};
+
+static struct pin_desc mmc_pins_desc[] = {
+       { PINID_SSP1_DATA0, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 },
+       { PINID_SSP1_DATA1, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 },
+       { PINID_SSP1_DATA2, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 },
+       { PINID_SSP1_DATA3, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 },
+       { PINID_SSP1_CMD, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 },
+       { PINID_SSP1_SCK, PIN_FUN1, PIN_8MA, PIN_3_3V, 0 },
+       { PINID_SSP1_DETECT, PIN_FUN1, PIN_8MA, PIN_3_3V, 0 },
+};
+
+static struct pin_group mmc_pins = {
+       .pins           = mmc_pins_desc,
+       .nr_pins        = ARRAY_SIZE(mmc_pins_desc),
+};
+
+static int stmp3xxxmmc_get_wp(void)
+{
+       return gpio_get_value(PINID_PWM4);
+}
+
+static int stmp3xxxmmc_hw_init_ssp1(void)
+{
+       int ret;
+
+       ret = stmp3xxx_request_pin_group(&mmc_pins, "mmc");
+       if (ret)
+               goto out;
+
+       /* Configure write protect GPIO pin */
+       ret = gpio_request(PINID_PWM4, "mmc wp");
+       if (ret)
+               goto out_wp;
+
+       gpio_direction_input(PINID_PWM4);
+
+       /* Configure POWER pin as gpio to drive power to MMC slot */
+       ret = gpio_request(PINID_PWM3, "mmc power");
+       if (ret)
+               goto out_power;
+
+       gpio_direction_output(PINID_PWM3, 0);
+       mdelay(100);
+
+       return 0;
+
+out_power:
+       gpio_free(PINID_PWM4);
+out_wp:
+       stmp3xxx_release_pin_group(&mmc_pins, "mmc");
+out:
+       return ret;
+}
+
+static void stmp3xxxmmc_hw_release_ssp1(void)
+{
+       gpio_free(PINID_PWM3);
+       gpio_free(PINID_PWM4);
+       stmp3xxx_release_pin_group(&mmc_pins, "mmc");
+}
+
+static void stmp3xxxmmc_cmd_pullup_ssp1(int enable)
+{
+       stmp3xxx_pin_pullup(PINID_SSP1_CMD, enable, "mmc");
+}
+
+static unsigned long
+stmp3xxxmmc_setclock_ssp1(void __iomem *base, unsigned long hz)
+{
+       struct clk *ssp, *parent;
+       char *p;
+       long r;
+
+       ssp = clk_get(NULL, "ssp");
+
+       /* using SSP1, no timeout, clock rate 1 */
+       writel(BF(2, SSP_TIMING_CLOCK_DIVIDE) |
+              BF(0xFFFF, SSP_TIMING_TIMEOUT),
+              base + HW_SSP_TIMING);
+
+       p = (hz > 1000000) ? "io" : "osc_24M";
+       parent = clk_get(NULL, p);
+       clk_set_parent(ssp, parent);
+       r = clk_set_rate(ssp, 2 * hz / 1000);
+       clk_put(parent);
+       clk_put(ssp);
+
+       return hz;
+}
+
+static struct stmp3xxxmmc_platform_data mmc_data = {
+       .hw_init        = stmp3xxxmmc_hw_init_ssp1,
+       .hw_release     = stmp3xxxmmc_hw_release_ssp1,
+       .get_wp         = stmp3xxxmmc_get_wp,
+       .cmd_pullup     = stmp3xxxmmc_cmd_pullup_ssp1,
+       .setclock       = stmp3xxxmmc_setclock_ssp1,
+};
+
+
+static struct pin_group appuart_pins[] = {
+       [0] = {
+               .pins           = appuart_pins_0,
+               .nr_pins        = ARRAY_SIZE(appuart_pins_0),
+       },
+       [1] = {
+               .pins           = appuart_pins_1,
+               .nr_pins        = ARRAY_SIZE(appuart_pins_1),
+       },
+};
+
+static struct pin_desc ssp1_pins_desc[] = {
+       { PINID_SSP1_SCK,       PIN_FUN1, PIN_8MA, PIN_3_3V, 0, },
+       { PINID_SSP1_CMD,       PIN_FUN1, PIN_4MA, PIN_3_3V, 0, },
+       { PINID_SSP1_DATA0,     PIN_FUN1, PIN_4MA, PIN_3_3V, 0, },
+       { PINID_SSP1_DATA3,     PIN_FUN1, PIN_4MA, PIN_3_3V, 0, },
+};
+
+static struct pin_desc ssp2_pins_desc[] = {
+       { PINID_GPMI_WRN,       PIN_FUN3, PIN_8MA, PIN_3_3V, 0, },
+       { PINID_GPMI_RDY1,      PIN_FUN3, PIN_4MA, PIN_3_3V, 0, },
+       { PINID_GPMI_D00,       PIN_FUN3, PIN_4MA, PIN_3_3V, 0, },
+       { PINID_GPMI_D03,       PIN_FUN3, PIN_4MA, PIN_3_3V, 0, },
+};
+
+static struct pin_group ssp1_pins = {
+       .pins = ssp1_pins_desc,
+       .nr_pins = ARRAY_SIZE(ssp1_pins_desc),
+};
+
+static struct pin_group ssp2_pins = {
+       .pins = ssp1_pins_desc,
+       .nr_pins = ARRAY_SIZE(ssp2_pins_desc),
+};
+
+static struct pin_desc gpmi_pins_desc[] = {
+       { PINID_GPMI_CE0N, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+       { PINID_GPMI_CE1N, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+       { PINID_GMPI_CE2N, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+       { PINID_GPMI_CLE, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+       { PINID_GPMI_ALE, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+       { PINID_GPMI_WPN, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 },
+       { PINID_GPMI_RDY1, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+       { PINID_GPMI_D00, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+       { PINID_GPMI_D01, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+       { PINID_GPMI_D02, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+       { PINID_GPMI_D03, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+       { PINID_GPMI_D04, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+       { PINID_GPMI_D05, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+       { PINID_GPMI_D06, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+       { PINID_GPMI_D07, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+       { PINID_GPMI_RDY0, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+       { PINID_GPMI_RDY2, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+       { PINID_GPMI_RDY3, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
+       { PINID_GPMI_WRN, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 },
+       { PINID_GPMI_RDN, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 },
+};
+
+static struct pin_group gpmi_pins = {
+       .pins           = gpmi_pins_desc,
+       .nr_pins        = ARRAY_SIZE(gpmi_pins_desc),
+};
+
+static struct mtd_partition gpmi_partitions[] = {
+       [0] = {
+               .name   = "boot",
+               .size   = 10 * SZ_1M,
+               .offset = 0,
+       },
+       [1] = {
+               .name   = "data",
+               .size   = MTDPART_SIZ_FULL,
+               .offset = MTDPART_OFS_APPEND,
+       },
+};
+
+static struct gpmi_platform_data gpmi_data = {
+       .pins = &gpmi_pins,
+       .nr_parts = ARRAY_SIZE(gpmi_partitions),
+       .parts = gpmi_partitions,
+       .part_types = { "cmdline", NULL },
+};
+
+static struct spi_board_info spi_board_info[] __initdata = {
+#if defined(CONFIG_ENC28J60) || defined(CONFIG_ENC28J60_MODULE)
+       {
+               .modalias       = "enc28j60",
+               .max_speed_hz   = 6 * 1000 * 1000,
+               .bus_num        = 1,
+               .chip_select    = 0,
+               .platform_data  = NULL,
+       },
+#endif
+};
+
+static void __init stmp378x_devb_init(void)
+{
+       stmp3xxx_pinmux_init(NR_REAL_IRQS);
+
+       /* init stmp3xxx platform */
+       stmp3xxx_init();
+
+       stmp3xxx_dbguart.dev.platform_data = dbguart_pins_control;
+       stmp3xxx_appuart.dev.platform_data = appuart_pins;
+       stmp3xxx_mmc.dev.platform_data = &mmc_data;
+       stmp3xxx_gpmi.dev.platform_data = &gpmi_data;
+       stmp3xxx_spi1.dev.platform_data = &ssp1_pins;
+       stmp3xxx_spi2.dev.platform_data = &ssp2_pins;
+       stmp378x_i2c.dev.platform_data = &i2c_pins;
+
+       /* register spi devices */
+       spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+
+       /* add board's devices */
+       platform_add_devices(devices, ARRAY_SIZE(devices));
+
+       /* add devices selected by command line ssp1= and ssp2= options */
+       stmp3xxx_ssp1_device_register();
+       stmp3xxx_ssp2_device_register();
+}
+
+MACHINE_START(STMP378X, "STMP378X")
+       .phys_io        = 0x80000000,
+       .io_pg_offst    = ((0xf0000000) >> 18) & 0xfffc,
+       .boot_params    = 0x40000100,
+       .map_io         = stmp378x_map_io,
+       .init_irq       = stmp378x_init_irq,
+       .timer          = &stmp3xxx_timer,
+       .init_machine   = stmp378x_devb_init,
+MACHINE_END
diff --git a/arch/arm/mach-stmp37xx/Makefile b/arch/arm/mach-stmp37xx/Makefile
new file mode 100644 (file)
index 0000000..57deffd
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_ARCH_STMP37XX) += stmp37xx.o
+obj-$(CONFIG_MACH_STMP37XX) += stmp37xx_devb.o
diff --git a/arch/arm/mach-stmp37xx/Makefile.boot b/arch/arm/mach-stmp37xx/Makefile.boot
new file mode 100644 (file)
index 0000000..1568ad4
--- /dev/null
@@ -0,0 +1,3 @@
+   zreladdr-y  := 0x40008000
+params_phys-y  := 0x40000100
+initrd_phys-y  := 0x40800000
diff --git a/arch/arm/mach-stmp37xx/include/mach/entry-macro.S b/arch/arm/mach-stmp37xx/include/mach/entry-macro.S
new file mode 100644 (file)
index 0000000..fed2787
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Low-level IRQ helper macros for Freescale STMP37XX
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+               .macro  disable_fiq
+               .endm
+
+               .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
+
+               mov     \base, #0xf0000000      @ vm address of IRQ controller
+               ldr     \irqnr, [\base, #0x30]  @ HW_ICOLL_STAT
+               cmp     \irqnr, #0x3f
+               movne   \irqstat, #0            @ Ack this IRQ
+               strne   \irqstat, [\base, #0x00]@ HW_ICOLL_VECTOR
+               moveqs  \irqnr, #0              @ Zero flag set for no IRQ
+
+               .endm
+
+                .macro  get_irqnr_preamble, base, tmp
+                .endm
+
+                .macro  arch_ret_to_user, tmp1, tmp2
+                .endm
diff --git a/arch/arm/mach-stmp37xx/include/mach/irqs.h b/arch/arm/mach-stmp37xx/include/mach/irqs.h
new file mode 100644 (file)
index 0000000..98f1293
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Freescale STMP37XX interrupts
+ *
+ * Copyright (C) 2005 Sigmatel Inc
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef _ASM_ARCH_IRQS_H
+#define _ASM_ARCH_IRQS_H
+
+#define IRQ_DEBUG_UART          0
+#define IRQ_COMMS_RX              1
+#define IRQ_COMMS_TX              1
+#define IRQ_SSP2_ERROR          2
+#define IRQ_VDD5V                    3
+#define IRQ_HEADPHONE_SHORT        4
+#define IRQ_DAC_DMA                5
+#define IRQ_DAC_ERROR            6
+#define IRQ_ADC_DMA                7
+#define IRQ_ADC_ERROR            8
+#define IRQ_SPDIF_DMA            9
+#define IRQ_SAIF2_DMA            9
+#define IRQ_SPDIF_ERROR                10
+#define IRQ_SAIF1_IRQ            10
+#define IRQ_SAIF2_IRQ            10
+#define IRQ_USB_CTRL              11
+#define IRQ_USB_WAKEUP          12
+#define IRQ_GPMI_DMA              13
+#define IRQ_SSP1_DMA              14
+#define IRQ_SSP_ERROR            15
+#define IRQ_GPIO0                    16
+#define IRQ_GPIO1                    17
+#define IRQ_GPIO2                    18
+#define IRQ_SAIF1_DMA            19
+#define IRQ_SSP2_DMA              20
+#define IRQ_ECC8_IRQ              21
+#define IRQ_RTC_ALARM            22
+#define IRQ_UARTAPP_TX_DMA          23
+#define IRQ_UARTAPP_INTERNAL      24
+#define IRQ_UARTAPP_RX_DMA          25
+#define IRQ_I2C_DMA                26
+#define IRQ_I2C_ERROR            27
+#define IRQ_TIMER0                  28
+#define IRQ_TIMER1                  29
+#define IRQ_TIMER2                  30
+#define IRQ_TIMER3                  31
+#define IRQ_BATT_BRNOUT                32
+#define IRQ_VDDD_BRNOUT                33
+#define IRQ_VDDIO_BRNOUT              34
+#define IRQ_VDD18_BRNOUT              35
+#define IRQ_TOUCH_DETECT              36
+#define IRQ_LRADC_CH0            37
+#define IRQ_LRADC_CH1            38
+#define IRQ_LRADC_CH2            39
+#define IRQ_LRADC_CH3            40
+#define IRQ_LRADC_CH4            41
+#define IRQ_LRADC_CH5            42
+#define IRQ_LRADC_CH6            43
+#define IRQ_LRADC_CH7            44
+#define IRQ_LCDIF_DMA            45
+#define IRQ_LCDIF_ERROR                46
+#define IRQ_DIGCTL_DEBUG_TRAP    47
+#define IRQ_RTC_1MSEC            48
+#define IRQ_DRI_DMA                49
+#define IRQ_DRI_ATTENTION            50
+#define IRQ_GPMI_ATTENTION          51
+#define IRQ_IR                  52
+#define IRQ_DCP_VMI                53
+#define IRQ_DCP                        54
+#define IRQ_RESERVED_55                55
+#define IRQ_RESERVED_56                56
+#define IRQ_RESERVED_57                57
+#define IRQ_RESERVED_58                58
+#define IRQ_RESERVED_59                59
+#define SW_IRQ_60                    60
+#define SW_IRQ_61                    61
+#define SW_IRQ_62                    62
+#define SW_IRQ_63                    63
+
+#define NR_REAL_IRQS           64
+#define NR_IRQS                        (NR_REAL_IRQS + 32 * 3)
+
+/* TIMER and BRNOUT are FIQ capable */
+#define FIQ_START                      IRQ_TIMER0
+
+/* Hard disk IRQ is a GPMI attention IRQ */
+#define IRQ_HARDDISK           IRQ_GPMI_ATTENTION
+
+#endif /* _ASM_ARCH_IRQS_H */
diff --git a/arch/arm/mach-stmp37xx/include/mach/pins.h b/arch/arm/mach-stmp37xx/include/mach/pins.h
new file mode 100644 (file)
index 0000000..d56de0c
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Freescale STMP37XX SoC pin multiplexing
+ *
+ * Author: Vladislav Buzov <vbuzov@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __ASM_ARCH_PINS_H
+#define __ASM_ARCH_PINS_H
+
+/*
+ * Define all STMP37XX pins, a pin name corresponds to a STMP37xx hardware
+ * interface  this pin belongs to.
+ */
+
+/* Bank 0 */
+#define PINID_GPMI_D00         STMP3XXX_PINID(0, 0)
+#define PINID_GPMI_D01         STMP3XXX_PINID(0, 1)
+#define PINID_GPMI_D02         STMP3XXX_PINID(0, 2)
+#define PINID_GPMI_D03         STMP3XXX_PINID(0, 3)
+#define PINID_GPMI_D04         STMP3XXX_PINID(0, 4)
+#define PINID_GPMI_D05         STMP3XXX_PINID(0, 5)
+#define PINID_GPMI_D06         STMP3XXX_PINID(0, 6)
+#define PINID_GPMI_D07         STMP3XXX_PINID(0, 7)
+#define PINID_GPMI_D08         STMP3XXX_PINID(0, 8)
+#define PINID_GPMI_D09         STMP3XXX_PINID(0, 9)
+#define PINID_GPMI_D10         STMP3XXX_PINID(0, 10)
+#define PINID_GPMI_D11         STMP3XXX_PINID(0, 11)
+#define PINID_GPMI_D12         STMP3XXX_PINID(0, 12)
+#define PINID_GPMI_D13         STMP3XXX_PINID(0, 13)
+#define PINID_GPMI_D14         STMP3XXX_PINID(0, 14)
+#define PINID_GPMI_D15         STMP3XXX_PINID(0, 15)
+#define PINID_GPMI_A0          STMP3XXX_PINID(0, 16)
+#define PINID_GPMI_A1          STMP3XXX_PINID(0, 17)
+#define PINID_GPMI_A2          STMP3XXX_PINID(0, 18)
+#define PINID_GPMI_RDY0                STMP3XXX_PINID(0, 19)
+#define PINID_GPMI_RDY2                STMP3XXX_PINID(0, 20)
+#define PINID_GPMI_RDY3                STMP3XXX_PINID(0, 21)
+#define PINID_GPMI_RESETN      STMP3XXX_PINID(0, 22)
+#define PINID_GPMI_IRQ         STMP3XXX_PINID(0, 23)
+#define PINID_GPMI_WRN         STMP3XXX_PINID(0, 24)
+#define PINID_GPMI_RDN         STMP3XXX_PINID(0, 25)
+#define PINID_UART2_CTS                STMP3XXX_PINID(0, 26)
+#define PINID_UART2_RTS                STMP3XXX_PINID(0, 27)
+#define PINID_UART2_RX         STMP3XXX_PINID(0, 28)
+#define PINID_UART2_TX         STMP3XXX_PINID(0, 29)
+
+/* Bank 1 */
+#define PINID_LCD_D00          STMP3XXX_PINID(1, 0)
+#define PINID_LCD_D01          STMP3XXX_PINID(1, 1)
+#define PINID_LCD_D02          STMP3XXX_PINID(1, 2)
+#define PINID_LCD_D03          STMP3XXX_PINID(1, 3)
+#define PINID_LCD_D04          STMP3XXX_PINID(1, 4)
+#define PINID_LCD_D05          STMP3XXX_PINID(1, 5)
+#define PINID_LCD_D06          STMP3XXX_PINID(1, 6)
+#define PINID_LCD_D07          STMP3XXX_PINID(1, 7)
+#define PINID_LCD_D08          STMP3XXX_PINID(1, 8)
+#define PINID_LCD_D09          STMP3XXX_PINID(1, 9)
+#define PINID_LCD_D10          STMP3XXX_PINID(1, 10)
+#define PINID_LCD_D11          STMP3XXX_PINID(1, 11)
+#define PINID_LCD_D12          STMP3XXX_PINID(1, 12)
+#define PINID_LCD_D13          STMP3XXX_PINID(1, 13)
+#define PINID_LCD_D14          STMP3XXX_PINID(1, 14)
+#define PINID_LCD_D15          STMP3XXX_PINID(1, 15)
+#define PINID_LCD_RESET        STMP3XXX_PINID(1, 16)
+#define PINID_LCD_RS           STMP3XXX_PINID(1, 17)
+#define PINID_LCD_WR_RWN       STMP3XXX_PINID(1, 18)
+#define PINID_LCD_RD_E         STMP3XXX_PINID(1, 19)
+#define PINID_LCD_CS           STMP3XXX_PINID(1, 20)
+#define PINID_LCD_BUSY         STMP3XXX_PINID(1, 21)
+#define PINID_SSP1_CMD         STMP3XXX_PINID(1, 22)
+#define PINID_SSP1_SCK         STMP3XXX_PINID(1, 23)
+#define PINID_SSP1_DATA0       STMP3XXX_PINID(1, 24)
+#define PINID_SSP1_DATA1       STMP3XXX_PINID(1, 25)
+#define PINID_SSP1_DATA2       STMP3XXX_PINID(1, 26)
+#define PINID_SSP1_DATA3       STMP3XXX_PINID(1, 27)
+#define PINID_SSP1_DETECT      STMP3XXX_PINID(1, 28)
+
+/* Bank 2 */
+#define PINID_PWM0             STMP3XXX_PINID(2, 0)
+#define PINID_PWM1             STMP3XXX_PINID(2, 1)
+#define PINID_PWM2             STMP3XXX_PINID(2, 2)
+#define PINID_PWM3             STMP3XXX_PINID(2, 3)
+#define PINID_PWM4             STMP3XXX_PINID(2, 4)
+#define PINID_I2C_SCL          STMP3XXX_PINID(2, 5)
+#define PINID_I2C_SDA          STMP3XXX_PINID(2, 6)
+#define PINID_ROTTARYA         STMP3XXX_PINID(2, 7)
+#define PINID_ROTTARYB         STMP3XXX_PINID(2, 8)
+#define PINID_EMI_CKE          STMP3XXX_PINID(2, 9)
+#define PINID_EMI_RASN         STMP3XXX_PINID(2, 10)
+#define PINID_EMI_CASN         STMP3XXX_PINID(2, 11)
+#define PINID_EMI_CE0N         STMP3XXX_PINID(2, 12)
+#define PINID_EMI_CE1N         STMP3XXX_PINID(2, 13)
+#define PINID_EMI_CE2N         STMP3XXX_PINID(2, 14)
+#define PINID_EMI_CE3N         STMP3XXX_PINID(2, 15)
+#define PINID_EMI_A00          STMP3XXX_PINID(2, 16)
+#define PINID_EMI_A01          STMP3XXX_PINID(2, 17)
+#define PINID_EMI_A02          STMP3XXX_PINID(2, 18)
+#define PINID_EMI_A03          STMP3XXX_PINID(2, 19)
+#define PINID_EMI_A04          STMP3XXX_PINID(2, 20)
+#define PINID_EMI_A05          STMP3XXX_PINID(2, 21)
+#define PINID_EMI_A06          STMP3XXX_PINID(2, 22)
+#define PINID_EMI_A07          STMP3XXX_PINID(2, 23)
+#define PINID_EMI_A08          STMP3XXX_PINID(2, 24)
+#define PINID_EMI_A09          STMP3XXX_PINID(2, 25)
+#define PINID_EMI_A10          STMP3XXX_PINID(2, 26)
+#define PINID_EMI_A11          STMP3XXX_PINID(2, 27)
+#define PINID_EMI_A12          STMP3XXX_PINID(2, 28)
+#define PINID_EMI_A13          STMP3XXX_PINID(2, 29)
+#define PINID_EMI_A14          STMP3XXX_PINID(2, 30)
+#define PINID_EMI_WEN          STMP3XXX_PINID(2, 31)
+
+/* Bank 3 */
+#define PINID_EMI_D00          STMP3XXX_PINID(3, 0)
+#define PINID_EMI_D01          STMP3XXX_PINID(3, 1)
+#define PINID_EMI_D02          STMP3XXX_PINID(3, 2)
+#define PINID_EMI_D03          STMP3XXX_PINID(3, 3)
+#define PINID_EMI_D04          STMP3XXX_PINID(3, 4)
+#define PINID_EMI_D05          STMP3XXX_PINID(3, 5)
+#define PINID_EMI_D06          STMP3XXX_PINID(3, 6)
+#define PINID_EMI_D07          STMP3XXX_PINID(3, 7)
+#define PINID_EMI_D08          STMP3XXX_PINID(3, 8)
+#define PINID_EMI_D09          STMP3XXX_PINID(3, 9)
+#define PINID_EMI_D10          STMP3XXX_PINID(3, 10)
+#define PINID_EMI_D11          STMP3XXX_PINID(3, 11)
+#define PINID_EMI_D12          STMP3XXX_PINID(3, 12)
+#define PINID_EMI_D13          STMP3XXX_PINID(3, 13)
+#define PINID_EMI_D14          STMP3XXX_PINID(3, 14)
+#define PINID_EMI_D15          STMP3XXX_PINID(3, 15)
+#define PINID_EMI_DQS0         STMP3XXX_PINID(3, 16)
+#define PINID_EMI_DQS1         STMP3XXX_PINID(3, 17)
+#define PINID_EMI_DQM0         STMP3XXX_PINID(3, 18)
+#define PINID_EMI_DQM1         STMP3XXX_PINID(3, 19)
+#define PINID_EMI_CLK          STMP3XXX_PINID(3, 20)
+#define PINID_EMI_CLKN         STMP3XXX_PINID(3, 21)
+
+#endif /* __ASM_ARCH_PINS_H */
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-apbh.h b/arch/arm/mach-stmp37xx/include/mach/regs-apbh.h
new file mode 100644 (file)
index 0000000..a323aa9
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * stmp37xx: APBH register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef _MACH_REGS_APBH
+#define _MACH_REGS_APBH
+
+#define REGS_APBH_BASE (STMP3XXX_REGS_BASE + 0x4000)
+
+#define HW_APBH_CTRL0          0x0
+#define BM_APBH_CTRL0_RESET_CHANNEL    0x00FF0000
+#define BP_APBH_CTRL0_RESET_CHANNEL    16
+#define BM_APBH_CTRL0_CLKGATE  0x40000000
+#define BM_APBH_CTRL0_SFTRST   0x80000000
+
+#define HW_APBH_CTRL1          0x10
+#define BM_APBH_CTRL1_CH0_CMDCMPLT_IRQ 0x00000001
+#define BP_APBH_CTRL1_CH0_CMDCMPLT_IRQ 0
+
+#define HW_APBH_DEVSEL         0x20
+
+#define HW_APBH_CH0_NXTCMDAR   (0x50 + 0 * 0x70)
+#define HW_APBH_CH1_NXTCMDAR   (0x50 + 1 * 0x70)
+#define HW_APBH_CH2_NXTCMDAR   (0x50 + 2 * 0x70)
+#define HW_APBH_CH3_NXTCMDAR   (0x50 + 3 * 0x70)
+#define HW_APBH_CH4_NXTCMDAR   (0x50 + 4 * 0x70)
+#define HW_APBH_CH5_NXTCMDAR   (0x50 + 5 * 0x70)
+#define HW_APBH_CH6_NXTCMDAR   (0x50 + 6 * 0x70)
+#define HW_APBH_CH7_NXTCMDAR   (0x50 + 7 * 0x70)
+#define HW_APBH_CH8_NXTCMDAR   (0x50 + 8 * 0x70)
+#define HW_APBH_CH9_NXTCMDAR   (0x50 + 9 * 0x70)
+#define HW_APBH_CH10_NXTCMDAR  (0x50 + 10 * 0x70)
+#define HW_APBH_CH11_NXTCMDAR  (0x50 + 11 * 0x70)
+#define HW_APBH_CH12_NXTCMDAR  (0x50 + 12 * 0x70)
+#define HW_APBH_CH13_NXTCMDAR  (0x50 + 13 * 0x70)
+#define HW_APBH_CH14_NXTCMDAR  (0x50 + 14 * 0x70)
+#define HW_APBH_CH15_NXTCMDAR  (0x50 + 15 * 0x70)
+
+#define HW_APBH_CHn_NXTCMDAR   0x50
+
+#define BM_APBH_CHn_CMD_MODE           0x00000003
+#define BP_APBH_CHn_CMD_MODE           0x00000001
+#define BV_APBH_CHn_CMD_MODE_NOOP               0
+#define BV_APBH_CHn_CMD_MODE_WRITE              1
+#define BV_APBH_CHn_CMD_MODE_READ               2
+#define BV_APBH_CHn_CMD_MODE_SENSE              3
+#define BM_APBH_CHn_CMD_CHAIN          0x00000004
+#define BM_APBH_CHn_CMD_IRQONCMPLT     0x00000008
+#define BM_APBH_CHn_CMD_NANDLOCK       0x00000010
+#define BM_APBH_CHn_CMD_NANDWAIT4READY 0x00000020
+#define BM_APBH_CHn_CMD_SEMAPHORE      0x00000040
+#define BM_APBH_CHn_CMD_WAIT4ENDCMD    0x00000080
+#define BM_APBH_CHn_CMD_CMDWORDS       0x0000F000
+#define BP_APBH_CHn_CMD_CMDWORDS       12
+#define BM_APBH_CHn_CMD_XFER_COUNT     0xFFFF0000
+#define BP_APBH_CHn_CMD_XFER_COUNT     16
+
+#define HW_APBH_CH0_SEMA       (0x80 + 0 * 0x70)
+#define HW_APBH_CH1_SEMA       (0x80 + 1 * 0x70)
+#define HW_APBH_CH2_SEMA       (0x80 + 2 * 0x70)
+#define HW_APBH_CH3_SEMA       (0x80 + 3 * 0x70)
+#define HW_APBH_CH4_SEMA       (0x80 + 4 * 0x70)
+#define HW_APBH_CH5_SEMA       (0x80 + 5 * 0x70)
+#define HW_APBH_CH6_SEMA       (0x80 + 6 * 0x70)
+#define HW_APBH_CH7_SEMA       (0x80 + 7 * 0x70)
+#define HW_APBH_CH8_SEMA       (0x80 + 8 * 0x70)
+#define HW_APBH_CH9_SEMA       (0x80 + 9 * 0x70)
+#define HW_APBH_CH10_SEMA      (0x80 + 10 * 0x70)
+#define HW_APBH_CH11_SEMA      (0x80 + 11 * 0x70)
+#define HW_APBH_CH12_SEMA      (0x80 + 12 * 0x70)
+#define HW_APBH_CH13_SEMA      (0x80 + 13 * 0x70)
+#define HW_APBH_CH14_SEMA      (0x80 + 14 * 0x70)
+#define HW_APBH_CH15_SEMA      (0x80 + 15 * 0x70)
+
+#define HW_APBH_CHn_SEMA       0x80
+#define BM_APBH_CHn_SEMA_INCREMENT_SEMA        0x000000FF
+#define BP_APBH_CHn_SEMA_INCREMENT_SEMA        0
+#define BM_APBH_CHn_SEMA_PHORE 0x00FF0000
+#define BP_APBH_CHn_SEMA_PHORE 16
+
+#endif
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-apbx.h b/arch/arm/mach-stmp37xx/include/mach/regs-apbx.h
new file mode 100644 (file)
index 0000000..6d080cd
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * stmp37xx: APBX register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef _MACH_REGS_APBX
+#define _MACH_REGS_APBX
+
+#define REGS_APBX_BASE (STMP3XXX_REGS_BASE + 0x24000)
+
+#define HW_APBX_CTRL0          0x0
+#define BM_APBX_CTRL0_RESET_CHANNEL    0x00FF0000
+#define BP_APBX_CTRL0_RESET_CHANNEL    16
+#define BM_APBX_CTRL0_CLKGATE  0x40000000
+#define BM_APBX_CTRL0_SFTRST   0x80000000
+
+#define HW_APBX_CTRL1          0x10
+
+#define HW_APBX_DEVSEL         0x20
+
+#define HW_APBX_CH0_NXTCMDAR   (0x50 + 0 * 0x70)
+#define HW_APBX_CH1_NXTCMDAR   (0x50 + 1 * 0x70)
+#define HW_APBX_CH2_NXTCMDAR   (0x50 + 2 * 0x70)
+#define HW_APBX_CH3_NXTCMDAR   (0x50 + 3 * 0x70)
+#define HW_APBX_CH4_NXTCMDAR   (0x50 + 4 * 0x70)
+#define HW_APBX_CH5_NXTCMDAR   (0x50 + 5 * 0x70)
+#define HW_APBX_CH6_NXTCMDAR   (0x50 + 6 * 0x70)
+#define HW_APBX_CH7_NXTCMDAR   (0x50 + 7 * 0x70)
+#define HW_APBX_CH8_NXTCMDAR   (0x50 + 8 * 0x70)
+#define HW_APBX_CH9_NXTCMDAR   (0x50 + 9 * 0x70)
+#define HW_APBX_CH10_NXTCMDAR  (0x50 + 10 * 0x70)
+#define HW_APBX_CH11_NXTCMDAR  (0x50 + 11 * 0x70)
+#define HW_APBX_CH12_NXTCMDAR  (0x50 + 12 * 0x70)
+#define HW_APBX_CH13_NXTCMDAR  (0x50 + 13 * 0x70)
+#define HW_APBX_CH14_NXTCMDAR  (0x50 + 14 * 0x70)
+#define HW_APBX_CH15_NXTCMDAR  (0x50 + 15 * 0x70)
+
+#define HW_APBX_CHn_NXTCMDAR   0x50
+#define BM_APBX_CHn_CMD_MODE           0x00000003
+#define BP_APBX_CHn_CMD_MODE           0x00000001
+#define BV_APBX_CHn_CMD_MODE_NOOP               0
+#define BV_APBX_CHn_CMD_MODE_WRITE              1
+#define BV_APBX_CHn_CMD_MODE_READ               2
+#define BV_APBX_CHn_CMD_MODE_SENSE              3
+#define BM_APBX_CHn_CMD_COMMAND        0x00000003
+#define BP_APBX_CHn_CMD_COMMAND        0
+#define BM_APBX_CHn_CMD_CHAIN  0x00000004
+#define BM_APBX_CHn_CMD_IRQONCMPLT     0x00000008
+#define BM_APBX_CHn_CMD_SEMAPHORE      0x00000040
+#define BM_APBX_CHn_CMD_WAIT4ENDCMD    0x00000080
+#define BM_APBX_CHn_CMD_CMDWORDS       0x0000F000
+#define BP_APBX_CHn_CMD_CMDWORDS       12
+#define BM_APBX_CHn_CMD_XFER_COUNT     0xFFFF0000
+#define BP_APBX_CHn_CMD_XFER_COUNT     16
+
+#define HW_APBX_CH0_BAR                (0x70 + 0 * 0x70)
+#define HW_APBX_CH1_BAR                (0x70 + 1 * 0x70)
+#define HW_APBX_CH2_BAR                (0x70 + 2 * 0x70)
+#define HW_APBX_CH3_BAR                (0x70 + 3 * 0x70)
+#define HW_APBX_CH4_BAR                (0x70 + 4 * 0x70)
+#define HW_APBX_CH5_BAR                (0x70 + 5 * 0x70)
+#define HW_APBX_CH6_BAR                (0x70 + 6 * 0x70)
+#define HW_APBX_CH7_BAR                (0x70 + 7 * 0x70)
+#define HW_APBX_CH8_BAR                (0x70 + 8 * 0x70)
+#define HW_APBX_CH9_BAR                (0x70 + 9 * 0x70)
+#define HW_APBX_CH10_BAR               (0x70 + 10 * 0x70)
+#define HW_APBX_CH11_BAR               (0x70 + 11 * 0x70)
+#define HW_APBX_CH12_BAR               (0x70 + 12 * 0x70)
+#define HW_APBX_CH13_BAR               (0x70 + 13 * 0x70)
+#define HW_APBX_CH14_BAR               (0x70 + 14 * 0x70)
+#define HW_APBX_CH15_BAR               (0x70 + 15 * 0x70)
+
+#define HW_APBX_CHn_BAR                0x70
+
+#define HW_APBX_CH0_SEMA       (0x80 + 0 * 0x70)
+#define HW_APBX_CH1_SEMA       (0x80 + 1 * 0x70)
+#define HW_APBX_CH2_SEMA       (0x80 + 2 * 0x70)
+#define HW_APBX_CH3_SEMA       (0x80 + 3 * 0x70)
+#define HW_APBX_CH4_SEMA       (0x80 + 4 * 0x70)
+#define HW_APBX_CH5_SEMA       (0x80 + 5 * 0x70)
+#define HW_APBX_CH6_SEMA       (0x80 + 6 * 0x70)
+#define HW_APBX_CH7_SEMA       (0x80 + 7 * 0x70)
+#define HW_APBX_CH8_SEMA       (0x80 + 8 * 0x70)
+#define HW_APBX_CH9_SEMA       (0x80 + 9 * 0x70)
+#define HW_APBX_CH10_SEMA      (0x80 + 10 * 0x70)
+#define HW_APBX_CH11_SEMA      (0x80 + 11 * 0x70)
+#define HW_APBX_CH12_SEMA      (0x80 + 12 * 0x70)
+#define HW_APBX_CH13_SEMA      (0x80 + 13 * 0x70)
+#define HW_APBX_CH14_SEMA      (0x80 + 14 * 0x70)
+#define HW_APBX_CH15_SEMA      (0x80 + 15 * 0x70)
+
+#define HW_APBX_CHn_SEMA       0x80
+#define BM_APBX_CHn_SEMA_INCREMENT_SEMA        0x000000FF
+#define BP_APBX_CHn_SEMA_INCREMENT_SEMA        0
+#define BM_APBX_CHn_SEMA_PHORE 0x00FF0000
+#define BP_APBX_CHn_SEMA_PHORE 16
+
+#endif
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-audioin.h b/arch/arm/mach-stmp37xx/include/mach/regs-audioin.h
new file mode 100644 (file)
index 0000000..3b511f9
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * stmp37xx: AUDIOIN register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_AUDIOIN_BASE      (STMP3XXX_REGS_BASE + 0x4C000)
+
+#define HW_AUDIOIN_CTRL                0x0
+#define BM_AUDIOIN_CTRL_RUN    0x00000001
+#define BP_AUDIOIN_CTRL_RUN    0
+#define BM_AUDIOIN_CTRL_FIFO_ERROR_IRQ_EN      0x00000002
+#define BM_AUDIOIN_CTRL_FIFO_OVERFLOW_IRQ      0x00000004
+#define BM_AUDIOIN_CTRL_FIFO_UNDERFLOW_IRQ     0x00000008
+#define BM_AUDIOIN_CTRL_WORD_LENGTH    0x00000020
+#define BM_AUDIOIN_CTRL_CLKGATE        0x40000000
+#define BM_AUDIOIN_CTRL_SFTRST 0x80000000
+
+#define HW_AUDIOIN_STAT                0x10
+
+#define HW_AUDIOIN_ADCSRR      0x20
+
+#define HW_AUDIOIN_ADCVOLUME   0x30
+#define BM_AUDIOIN_ADCVOLUME_VOLUME_RIGHT      0x000000FF
+#define BP_AUDIOIN_ADCVOLUME_VOLUME_RIGHT      0
+#define BM_AUDIOIN_ADCVOLUME_VOLUME_LEFT       0x00FF0000
+#define BP_AUDIOIN_ADCVOLUME_VOLUME_LEFT       16
+
+#define HW_AUDIOIN_ADCDEBUG    0x40
+
+#define HW_AUDIOIN_ADCVOL      0x50
+#define BM_AUDIOIN_ADCVOL_GAIN_RIGHT   0x0000000F
+#define BP_AUDIOIN_ADCVOL_GAIN_RIGHT   0
+#define BM_AUDIOIN_ADCVOL_SELECT_RIGHT 0x00000030
+#define BP_AUDIOIN_ADCVOL_SELECT_RIGHT 4
+#define BM_AUDIOIN_ADCVOL_GAIN_LEFT    0x00000F00
+#define BP_AUDIOIN_ADCVOL_GAIN_LEFT    8
+#define BM_AUDIOIN_ADCVOL_SELECT_LEFT  0x00003000
+#define BP_AUDIOIN_ADCVOL_SELECT_LEFT  12
+#define BM_AUDIOIN_ADCVOL_MUTE 0x01000000
+
+#define HW_AUDIOIN_MICLINE     0x60
+
+#define HW_AUDIOIN_ANACLKCTRL  0x70
+#define BM_AUDIOIN_ANACLKCTRL_CLKGATE  0x80000000
+
+#define HW_AUDIOIN_DATA                0x80
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-audioout.h b/arch/arm/mach-stmp37xx/include/mach/regs-audioout.h
new file mode 100644 (file)
index 0000000..ca1942b
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * stmp37xx: AUDIOOUT register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_AUDIOOUT_BASE     (STMP3XXX_REGS_BASE + 0x48000)
+
+#define HW_AUDIOOUT_CTRL       0x0
+#define BM_AUDIOOUT_CTRL_RUN   0x00000001
+#define BP_AUDIOOUT_CTRL_RUN   0
+#define BM_AUDIOOUT_CTRL_FIFO_ERROR_IRQ_EN     0x00000002
+#define BM_AUDIOOUT_CTRL_FIFO_OVERFLOW_IRQ     0x00000004
+#define BM_AUDIOOUT_CTRL_FIFO_UNDERFLOW_IRQ    0x00000008
+#define BM_AUDIOOUT_CTRL_WORD_LENGTH   0x00000040
+#define BM_AUDIOOUT_CTRL_CLKGATE       0x40000000
+#define BM_AUDIOOUT_CTRL_SFTRST        0x80000000
+
+#define HW_AUDIOOUT_STAT       0x10
+
+#define HW_AUDIOOUT_DACSRR     0x20
+#define BM_AUDIOOUT_DACSRR_SRC_FRAC    0x00001FFF
+#define BP_AUDIOOUT_DACSRR_SRC_FRAC    0
+#define BM_AUDIOOUT_DACSRR_SRC_INT     0x001F0000
+#define BP_AUDIOOUT_DACSRR_SRC_INT     16
+#define BM_AUDIOOUT_DACSRR_SRC_HOLD    0x07000000
+#define BP_AUDIOOUT_DACSRR_SRC_HOLD    24
+#define BM_AUDIOOUT_DACSRR_BASEMULT    0x70000000
+#define BP_AUDIOOUT_DACSRR_BASEMULT    28
+
+#define HW_AUDIOOUT_DACVOLUME  0x30
+#define BM_AUDIOOUT_DACVOLUME_MUTE_RIGHT       0x00000100
+#define BM_AUDIOOUT_DACVOLUME_MUTE_LEFT        0x01000000
+#define BM_AUDIOOUT_DACVOLUME_EN_ZCD   0x02000000
+
+#define HW_AUDIOOUT_DACDEBUG   0x40
+
+#define HW_AUDIOOUT_HPVOL      0x50
+#define BM_AUDIOOUT_HPVOL_MUTE 0x01000000
+#define BM_AUDIOOUT_HPVOL_EN_MSTR_ZCD  0x02000000
+
+#define HW_AUDIOOUT_PWRDN      0x70
+#define BM_AUDIOOUT_PWRDN_HEADPHONE    0x00000001
+#define BP_AUDIOOUT_PWRDN_HEADPHONE    0
+#define BM_AUDIOOUT_PWRDN_CAPLESS      0x00000010
+#define BM_AUDIOOUT_PWRDN_ADC  0x00000100
+#define BM_AUDIOOUT_PWRDN_DAC  0x00001000
+#define BM_AUDIOOUT_PWRDN_RIGHT_ADC    0x00010000
+#define BM_AUDIOOUT_PWRDN_LINEOUT      0x01000000
+
+#define HW_AUDIOOUT_REFCTRL    0x80
+#define BM_AUDIOOUT_REFCTRL_VAG_VAL    0x000000F0
+#define BP_AUDIOOUT_REFCTRL_VAG_VAL    4
+#define BM_AUDIOOUT_REFCTRL_ADC_REFVAL 0x00000F00
+#define BP_AUDIOOUT_REFCTRL_ADC_REFVAL 8
+#define BM_AUDIOOUT_REFCTRL_ADJ_VAG    0x00001000
+#define BM_AUDIOOUT_REFCTRL_ADJ_ADC    0x00002000
+#define BM_AUDIOOUT_REFCTRL_BIAS_CTRL  0x00030000
+#define BP_AUDIOOUT_REFCTRL_BIAS_CTRL  16
+#define BM_AUDIOOUT_REFCTRL_LOW_PWR    0x00080000
+#define BM_AUDIOOUT_REFCTRL_VBG_ADJ    0x00700000
+#define BP_AUDIOOUT_REFCTRL_VBG_ADJ    20
+#define BM_AUDIOOUT_REFCTRL_XTAL_BGR_BIAS      0x01000000
+#define BM_AUDIOOUT_REFCTRL_RAISE_REF  0x02000000
+
+#define HW_AUDIOOUT_ANACTRL    0x90
+#define BM_AUDIOOUT_ANACTRL_HP_CLASSAB 0x00000010
+#define BM_AUDIOOUT_ANACTRL_HP_HOLD_GND        0x00000020
+
+#define HW_AUDIOOUT_TEST       0xA0
+#define BM_AUDIOOUT_TEST_HP_I1_ADJ     0x00C00000
+#define BP_AUDIOOUT_TEST_HP_I1_ADJ     22
+
+#define HW_AUDIOOUT_BISTCTRL   0xB0
+
+#define HW_AUDIOOUT_BISTSTAT0  0xC0
+
+#define HW_AUDIOOUT_BISTSTAT1  0xD0
+
+#define HW_AUDIOOUT_ANACLKCTRL 0xE0
+#define BM_AUDIOOUT_ANACLKCTRL_CLKGATE 0x80000000
+
+#define HW_AUDIOOUT_DATA       0xF0
+
+#define HW_AUDIOOUT_LINEOUTCTRL        0x100
+#define BM_AUDIOOUT_LINEOUTCTRL_VOL_RIGHT      0x0000001F
+#define BP_AUDIOOUT_LINEOUTCTRL_VOL_RIGHT      0
+#define BM_AUDIOOUT_LINEOUTCTRL_VOL_LEFT       0x00001F00
+#define BP_AUDIOOUT_LINEOUTCTRL_VOL_LEFT       8
+#define BM_AUDIOOUT_LINEOUTCTRL_CHARGE_CAP     0x00007000
+#define BP_AUDIOOUT_LINEOUTCTRL_CHARGE_CAP     12
+#define BM_AUDIOOUT_LINEOUTCTRL_VAG_CTRL       0x00F00000
+#define BP_AUDIOOUT_LINEOUTCTRL_VAG_CTRL       20
+#define BM_AUDIOOUT_LINEOUTCTRL_MUTE   0x01000000
+#define BM_AUDIOOUT_LINEOUTCTRL_EN_ZCD 0x02000000
+
+#define HW_AUDIOOUT_VERSION    0x200
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-clkctrl.h b/arch/arm/mach-stmp37xx/include/mach/regs-clkctrl.h
new file mode 100644 (file)
index 0000000..47f5c92
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * stmp37xx: CLKCTRL register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef _MACH_REGS_CLKCTRL
+#define _MACH_REGS_CLKCTRL
+
+#define REGS_CLKCTRL_BASE      (STMP3XXX_REGS_BASE + 0x40000)
+
+#define HW_CLKCTRL_PLLCTRL0    0x0
+#define BM_CLKCTRL_PLLCTRL0_EN_USB_CLKS        0x00040000
+
+#define HW_CLKCTRL_CPU         0x20
+#define BM_CLKCTRL_CPU_DIV_CPU 0x0000003F
+#define BP_CLKCTRL_CPU_DIV_CPU 0
+
+#define HW_CLKCTRL_HBUS                0x30
+#define BM_CLKCTRL_HBUS_DIV    0x0000001F
+#define BP_CLKCTRL_HBUS_DIV    0
+
+#define HW_CLKCTRL_XBUS                0x40
+
+#define HW_CLKCTRL_XTAL                0x50
+
+#define HW_CLKCTRL_PIX         0x60
+#define BM_CLKCTRL_PIX_DIV     0x00007FFF
+#define BP_CLKCTRL_PIX_DIV     0
+#define BM_CLKCTRL_PIX_CLKGATE 0x80000000
+
+#define HW_CLKCTRL_SSP         0x70
+
+#define HW_CLKCTRL_GPMI                0x80
+
+#define HW_CLKCTRL_SPDIF       0x90
+
+#define HW_CLKCTRL_EMI         0xA0
+
+#define HW_CLKCTRL_IR          0xB0
+
+#define HW_CLKCTRL_SAIF                0xC0
+
+#define HW_CLKCTRL_FRAC                0xD0
+#define BM_CLKCTRL_FRAC_EMIFRAC        0x00003F00
+#define BP_CLKCTRL_FRAC_EMIFRAC        8
+#define BM_CLKCTRL_FRAC_PIXFRAC        0x003F0000
+#define BP_CLKCTRL_FRAC_PIXFRAC        16
+#define BM_CLKCTRL_FRAC_CLKGATEPIX     0x00800000
+
+#define HW_CLKCTRL_CLKSEQ      0xE0
+#define BM_CLKCTRL_CLKSEQ_BYPASS_PIX   0x00000002
+
+#define HW_CLKCTRL_RESET       0xF0
+#define BM_CLKCTRL_RESET_DIG   0x00000001
+#define BP_CLKCTRL_RESET_DIG   0
+
+#endif
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-digctl.h b/arch/arm/mach-stmp37xx/include/mach/regs-digctl.h
new file mode 100644 (file)
index 0000000..ba1bbe2
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * stmp37xx: DIGCTL register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_DIGCTL_BASE       (STMP3XXX_REGS_BASE + 0x1C000)
+
+#define HW_DIGCTL_CTRL         0x0
+#define BM_DIGCTL_CTRL_USB_CLKGATE     0x00000004
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-ecc8.h b/arch/arm/mach-stmp37xx/include/mach/regs-ecc8.h
new file mode 100644 (file)
index 0000000..3b6d990
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * stmp37xx: ECC8 register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_ECC8_BASE (STMP3XXX_REGS_BASE + 0x8000)
+
+#define HW_ECC8_CTRL           0x0
+#define BM_ECC8_CTRL_COMPLETE_IRQ      0x00000001
+#define BP_ECC8_CTRL_COMPLETE_IRQ      0
+#define BM_ECC8_CTRL_COMPLETE_IRQ_EN   0x00000100
+#define BM_ECC8_CTRL_AHBM_SFTRST       0x20000000
+
+#define HW_ECC8_STATUS0                0x10
+#define BM_ECC8_STATUS0_UNCORRECTABLE  0x00000004
+#define BM_ECC8_STATUS0_CORRECTED      0x00000008
+#define BM_ECC8_STATUS0_STATUS_AUX     0x00000F00
+#define BP_ECC8_STATUS0_STATUS_AUX     8
+#define BM_ECC8_STATUS0_COMPLETED_CE   0x000F0000
+#define BP_ECC8_STATUS0_COMPLETED_CE   16
+
+#define HW_ECC8_STATUS1                0x20
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-gpmi.h b/arch/arm/mach-stmp37xx/include/mach/regs-gpmi.h
new file mode 100644 (file)
index 0000000..f2b304f
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * stmp37xx: GPMI register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_GPMI_BASE (STMP3XXX_REGS_BASE + 0xC000)
+#define REGS_GPMI_PHYS 0x8000C000
+#define REGS_GPMI_SIZE 0x2000
+
+#define HW_GPMI_CTRL0          0x0
+#define BM_GPMI_CTRL0_XFER_COUNT       0x0000FFFF
+#define BP_GPMI_CTRL0_XFER_COUNT       0
+#define BM_GPMI_CTRL0_CS       0x00300000
+#define BP_GPMI_CTRL0_CS       20
+#define BM_GPMI_CTRL0_LOCK_CS  0x00400000
+#define BM_GPMI_CTRL0_WORD_LENGTH      0x00800000
+#define BM_GPMI_CTRL0_COMMAND_MODE     0x03000000
+#define BP_GPMI_CTRL0_COMMAND_MODE     24
+#define BV_GPMI_CTRL0_COMMAND_MODE__WRITE          0x0
+#define BV_GPMI_CTRL0_COMMAND_MODE__READ            0x1
+#define BV_GPMI_CTRL0_COMMAND_MODE__READ_AND_COMPARE 0x2
+#define BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY   0x3
+#define BM_GPMI_CTRL0_RUN      0x20000000
+#define BM_GPMI_CTRL0_CLKGATE  0x40000000
+#define BM_GPMI_CTRL0_SFTRST   0x80000000
+#define BM_GPMI_ECCCTRL_ENABLE_ECC     0x00001000
+#define BM_GPMI_ECCCTRL_ECC_CMD        0x00006000
+#define BP_GPMI_ECCCTRL_ECC_CMD        13
+
+#define HW_GPMI_CTRL1          0x60
+#define BM_GPMI_CTRL1_GPMI_MODE        0x00000003
+#define BP_GPMI_CTRL1_GPMI_MODE        0
+#define BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY      0x00000004
+#define BM_GPMI_CTRL1_DEV_RESET        0x00000008
+#define BM_GPMI_CTRL1_TIMEOUT_IRQ      0x00000200
+#define BM_GPMI_CTRL1_DEV_IRQ  0x00000400
+#define BM_GPMI_CTRL1_DSAMPLE_TIME     0x00007000
+#define BP_GPMI_CTRL1_DSAMPLE_TIME     12
+
+#define HW_GPMI_TIMING0                0x70
+#define BM_GPMI_TIMING0_DATA_SETUP     0x000000FF
+#define BP_GPMI_TIMING0_DATA_SETUP     0
+#define BM_GPMI_TIMING0_DATA_HOLD      0x0000FF00
+#define BP_GPMI_TIMING0_DATA_HOLD      8
+
+#define HW_GPMI_TIMING1                0x80
+#define BM_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT    0xFFFF0000
+#define BP_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT    16
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-i2c.h b/arch/arm/mach-stmp37xx/include/mach/regs-i2c.h
new file mode 100644 (file)
index 0000000..35882a9
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * stmp37xx: I2C register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_I2C_BASE  (STMP3XXX_REGS_BASE + 0x58000)
+#define REGS_I2C_PHYS  0x80058000
+#define REGS_I2C_SIZE  0x2000
+
+#define HW_I2C_CTRL0           0x0
+#define BM_I2C_CTRL0_XFER_COUNT        0x0000FFFF
+#define BP_I2C_CTRL0_XFER_COUNT        0
+#define BM_I2C_CTRL0_DIRECTION 0x00010000
+#define BM_I2C_CTRL0_MASTER_MODE       0x00020000
+#define BM_I2C_CTRL0_PRE_SEND_START    0x00080000
+#define BM_I2C_CTRL0_POST_SEND_STOP    0x00100000
+#define BM_I2C_CTRL0_RETAIN_CLOCK      0x00200000
+#define BM_I2C_CTRL0_SEND_NAK_ON_LAST  0x02000000
+#define BM_I2C_CTRL0_CLKGATE   0x40000000
+#define BM_I2C_CTRL0_SFTRST    0x80000000
+
+#define HW_I2C_TIMING0         0x10
+
+#define HW_I2C_TIMING1         0x20
+
+#define HW_I2C_TIMING2         0x30
+
+#define HW_I2C_CTRL1           0x40
+#define BM_I2C_CTRL1_SLAVE_IRQ 0x00000001
+#define BP_I2C_CTRL1_SLAVE_IRQ 0
+#define BM_I2C_CTRL1_SLAVE_STOP_IRQ    0x00000002
+#define BM_I2C_CTRL1_MASTER_LOSS_IRQ   0x00000004
+#define BM_I2C_CTRL1_EARLY_TERM_IRQ    0x00000008
+#define BM_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ    0x00000010
+#define BM_I2C_CTRL1_NO_SLAVE_ACK_IRQ  0x00000020
+#define BM_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ     0x00000040
+#define BM_I2C_CTRL1_BUS_FREE_IRQ      0x00000080
+#define BM_I2C_CTRL1_CLR_GOT_A_NAK     0x10000000
+
+#define HW_I2C_VERSION         0x90
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-icoll.h b/arch/arm/mach-stmp37xx/include/mach/regs-icoll.h
new file mode 100644 (file)
index 0000000..3b7c922
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * stmp37xx: ICOLL register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef _MACH_REGS_ICOLL
+#define _MACH_REGS_ICOLL
+
+#define REGS_ICOLL_BASE        (STMP3XXX_REGS_BASE + 0x0)
+
+#define HW_ICOLL_VECTOR                0x0
+
+#define HW_ICOLL_LEVELACK      0x10
+
+#define HW_ICOLL_CTRL          0x20
+#define BM_ICOLL_CTRL_CLKGATE  0x40000000
+#define BM_ICOLL_CTRL_SFTRST   0x80000000
+
+#define HW_ICOLL_STAT          0x30
+
+#define HW_ICOLL_PRIORITY0     (0x60 + 0 * 0x10)
+#define HW_ICOLL_PRIORITY1     (0x60 + 1 * 0x10)
+#define HW_ICOLL_PRIORITY2     (0x60 + 2 * 0x10)
+#define HW_ICOLL_PRIORITY3     (0x60 + 3 * 0x10)
+
+#define HW_ICOLL_PRIORITYn     0x60
+
+#endif
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-lcdif.h b/arch/arm/mach-stmp37xx/include/mach/regs-lcdif.h
new file mode 100644 (file)
index 0000000..72514e8
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * stmp37xx: LCDIF register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_LCDIF_BASE        (STMP3XXX_REGS_BASE + 0x30000)
+#define REGS_LCDIF_PHYS        0x80030000
+#define REGS_LCDIF_SIZE        0x2000
+
+#define HW_LCDIF_CTRL          0x0
+#define BM_LCDIF_CTRL_COUNT    0x0000FFFF
+#define BP_LCDIF_CTRL_COUNT    0
+#define BM_LCDIF_CTRL_RUN      0x00010000
+#define BM_LCDIF_CTRL_WORD_LENGTH      0x00020000
+#define BM_LCDIF_CTRL_DATA_SELECT      0x00040000
+#define BM_LCDIF_CTRL_DOTCLK_MODE      0x00080000
+#define BM_LCDIF_CTRL_VSYNC_MODE       0x00100000
+#define BM_LCDIF_CTRL_DATA_SWIZZLE     0x00600000
+#define BP_LCDIF_CTRL_DATA_SWIZZLE     21
+#define BM_LCDIF_CTRL_BYPASS_COUNT     0x00800000
+#define BM_LCDIF_CTRL_SHIFT_NUM_BITS   0x06000000
+#define BP_LCDIF_CTRL_SHIFT_NUM_BITS   25
+#define BM_LCDIF_CTRL_DATA_SHIFT_DIR   0x08000000
+#define BM_LCDIF_CTRL_WAIT_FOR_VSYNC_EDGE      0x10000000
+#define BM_LCDIF_CTRL_CLKGATE  0x40000000
+#define BM_LCDIF_CTRL_SFTRST   0x80000000
+
+#define HW_LCDIF_CTRL1         0x10
+#define BM_LCDIF_CTRL1_RESET   0x00000001
+#define BP_LCDIF_CTRL1_RESET   0
+#define BM_LCDIF_CTRL1_MODE86  0x00000002
+#define BM_LCDIF_CTRL1_BUSY_ENABLE     0x00000004
+#define BM_LCDIF_CTRL1_VSYNC_EDGE_IRQ  0x00000100
+#define BM_LCDIF_CTRL1_CUR_FRAME_DONE_IRQ      0x00000200
+#define BM_LCDIF_CTRL1_UNDERFLOW_IRQ   0x00000400
+#define BM_LCDIF_CTRL1_OVERFLOW_IRQ    0x00000800
+#define BM_LCDIF_CTRL1_VSYNC_EDGE_IRQ_EN       0x00001000
+#define BM_LCDIF_CTRL1_BYTE_PACKING_FORMAT     0x000F0000
+#define BP_LCDIF_CTRL1_BYTE_PACKING_FORMAT     16
+
+#define HW_LCDIF_TIMING                0x20
+
+#define HW_LCDIF_VDCTRL0       0x30
+#define BM_LCDIF_VDCTRL0_VALID_DATA_CNT        0x000003FF
+#define BP_LCDIF_VDCTRL0_VALID_DATA_CNT        0
+#define BM_LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT        0x00100000
+#define BM_LCDIF_VDCTRL0_VSYNC_PERIOD_UNIT     0x00200000
+#define BM_LCDIF_VDCTRL0_ENABLE_POL    0x01000000
+#define BM_LCDIF_VDCTRL0_DOTCLK_POL    0x02000000
+#define BM_LCDIF_VDCTRL0_HSYNC_POL     0x04000000
+#define BM_LCDIF_VDCTRL0_VSYNC_POL     0x08000000
+#define BM_LCDIF_VDCTRL0_ENABLE_PRESENT        0x10000000
+#define BM_LCDIF_VDCTRL0_VSYNC_OEB     0x20000000
+
+#define HW_LCDIF_VDCTRL1       0x40
+#define BM_LCDIF_VDCTRL1_VSYNC_PERIOD  0x000FFFFF
+#define BP_LCDIF_VDCTRL1_VSYNC_PERIOD  0
+#define BM_LCDIF_VDCTRL1_VSYNC_PULSE_WIDTH     0xFFF00000
+#define BP_LCDIF_VDCTRL1_VSYNC_PULSE_WIDTH     20
+
+#define HW_LCDIF_VDCTRL2       0x50
+#define BM_LCDIF_VDCTRL2_VALID_DATA_CNT        0x000007FF
+#define BP_LCDIF_VDCTRL2_VALID_DATA_CNT        0
+#define BM_LCDIF_VDCTRL2_HSYNC_PERIOD  0x007FF800
+#define BP_LCDIF_VDCTRL2_HSYNC_PERIOD  11
+#define BM_LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH     0xFF800000
+#define BP_LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH     23
+
+#define HW_LCDIF_VDCTRL3       0x60
+#define BM_LCDIF_VDCTRL3_VERTICAL_WAIT_CNT     0x000001FF
+#define BP_LCDIF_VDCTRL3_VERTICAL_WAIT_CNT     0
+#define BM_LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT   0x00FFF000
+#define BP_LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT   12
+#define BM_LCDIF_VDCTRL3_SYNC_SIGNALS_ON       0x01000000
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-lradc.h b/arch/arm/mach-stmp37xx/include/mach/regs-lradc.h
new file mode 100644 (file)
index 0000000..cc7b470
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * stmp37xx: LRADC register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_LRADC_BASE        (STMP3XXX_REGS_BASE + 0x50000)
+
+#define HW_LRADC_CTRL0         0x0
+#define BM_LRADC_CTRL0_SCHEDULE        0x000000FF
+#define BP_LRADC_CTRL0_SCHEDULE        0
+#define BM_LRADC_CTRL0_XPLUS_ENABLE    0x00010000
+#define BM_LRADC_CTRL0_YPLUS_ENABLE    0x00020000
+#define BM_LRADC_CTRL0_XMINUS_ENABLE   0x00040000
+#define BM_LRADC_CTRL0_YMINUS_ENABLE   0x00080000
+#define BM_LRADC_CTRL0_TOUCH_DETECT_ENABLE     0x00100000
+#define BM_LRADC_CTRL0_ONCHIP_GROUNDREF        0x00200000
+#define BM_LRADC_CTRL0_CLKGATE 0x40000000
+#define BM_LRADC_CTRL0_SFTRST  0x80000000
+
+#define HW_LRADC_CTRL1         0x10
+#define BM_LRADC_CTRL1_LRADC0_IRQ      0x00000001
+#define BP_LRADC_CTRL1_LRADC0_IRQ      0
+#define BM_LRADC_CTRL1_LRADC5_IRQ      0x00000020
+#define BM_LRADC_CTRL1_LRADC6_IRQ      0x00000040
+#define BM_LRADC_CTRL1_TOUCH_DETECT_IRQ        0x00000100
+#define BM_LRADC_CTRL1_LRADC0_IRQ_EN   0x00010000
+#define BM_LRADC_CTRL1_LRADC5_IRQ_EN   0x00200000
+#define BM_LRADC_CTRL1_TOUCH_DETECT_IRQ_EN     0x01000000
+
+#define HW_LRADC_CTRL2         0x20
+#define BM_LRADC_CTRL2_BL_BRIGHTNESS   0x001F0000
+#define BP_LRADC_CTRL2_BL_BRIGHTNESS   16
+#define BM_LRADC_CTRL2_BL_MUX_SELECT   0x00200000
+#define BM_LRADC_CTRL2_BL_ENABLE       0x00400000
+#define BM_LRADC_CTRL2_DIVIDE_BY_TWO   0xFF000000
+#define BP_LRADC_CTRL2_DIVIDE_BY_TWO   24
+
+#define HW_LRADC_CTRL3         0x30
+#define BM_LRADC_CTRL3_CYCLE_TIME      0x00000300
+#define BP_LRADC_CTRL3_CYCLE_TIME      8
+
+#define HW_LRADC_STATUS                0x40
+#define BM_LRADC_STATUS_TOUCH_DETECT_RAW       0x00000001
+#define BP_LRADC_STATUS_TOUCH_DETECT_RAW       0
+
+#define HW_LRADC_CH0           (0x50 + 0 * 0x10)
+#define HW_LRADC_CH1           (0x50 + 1 * 0x10)
+#define HW_LRADC_CH2           (0x50 + 2 * 0x10)
+#define HW_LRADC_CH3           (0x50 + 3 * 0x10)
+#define HW_LRADC_CH4           (0x50 + 4 * 0x10)
+#define HW_LRADC_CH5           (0x50 + 5 * 0x10)
+#define HW_LRADC_CH6           (0x50 + 6 * 0x10)
+#define HW_LRADC_CH7           (0x50 + 7 * 0x10)
+
+#define HW_LRADC_CHn           0x50
+#define BM_LRADC_CHn_VALUE     0x0003FFFF
+#define BP_LRADC_CHn_VALUE     0
+#define BM_LRADC_CHn_NUM_SAMPLES       0x1F000000
+#define BP_LRADC_CHn_NUM_SAMPLES       24
+#define BM_LRADC_CHn_ACCUMULATE        0x20000000
+
+#define HW_LRADC_DELAY0                (0xD0 + 0 * 0x10)
+#define HW_LRADC_DELAY1                (0xD0 + 1 * 0x10)
+#define HW_LRADC_DELAY2                (0xD0 + 2 * 0x10)
+#define HW_LRADC_DELAY3                (0xD0 + 3 * 0x10)
+
+#define HW_LRADC_DELAYn                0xD0
+#define BM_LRADC_DELAYn_DELAY  0x000007FF
+#define BP_LRADC_DELAYn_DELAY  0
+#define BM_LRADC_DELAYn_LOOP_COUNT     0x0000F800
+#define BP_LRADC_DELAYn_LOOP_COUNT     11
+#define BM_LRADC_DELAYn_TRIGGER_DELAYS 0x000F0000
+#define BP_LRADC_DELAYn_TRIGGER_DELAYS 16
+#define BM_LRADC_DELAYn_KICK   0x00100000
+#define BM_LRADC_DELAYn_TRIGGER_LRADCS 0xFF000000
+#define BP_LRADC_DELAYn_TRIGGER_LRADCS 24
+
+#define HW_LRADC_CTRL4         0x140
+#define BM_LRADC_CTRL4_LRADC6SELECT    0x0F000000
+#define BP_LRADC_CTRL4_LRADC6SELECT    24
+#define BM_LRADC_CTRL4_LRADC7SELECT    0xF0000000
+#define BP_LRADC_CTRL4_LRADC7SELECT    28
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-pinctrl.h b/arch/arm/mach-stmp37xx/include/mach/regs-pinctrl.h
new file mode 100644 (file)
index 0000000..d5efce2
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * stmp37xx: PINCTRL register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef _MACH_REGS_PINCTRL
+#define _MACH_REGS_PINCTRL
+
+#define REGS_PINCTRL_BASE      (STMP3XXX_REGS_BASE + 0x18000)
+
+#define HW_PINCTRL_MUXSEL0     0x100
+#define HW_PINCTRL_MUXSEL1     0x110
+#define HW_PINCTRL_MUXSEL2     0x120
+#define HW_PINCTRL_MUXSEL3     0x130
+#define HW_PINCTRL_MUXSEL4     0x140
+#define HW_PINCTRL_MUXSEL5     0x150
+#define HW_PINCTRL_MUXSEL6     0x160
+#define HW_PINCTRL_MUXSEL7     0x170
+
+#define HW_PINCTRL_DRIVE0      0x200
+#define HW_PINCTRL_DRIVE1      0x210
+#define HW_PINCTRL_DRIVE2      0x220
+#define HW_PINCTRL_DRIVE3      0x230
+#define HW_PINCTRL_DRIVE4      0x240
+#define HW_PINCTRL_DRIVE5      0x250
+#define HW_PINCTRL_DRIVE6      0x260
+#define HW_PINCTRL_DRIVE7      0x270
+#define HW_PINCTRL_DRIVE8      0x280
+#define HW_PINCTRL_DRIVE9      0x290
+#define HW_PINCTRL_DRIVE10     0x2A0
+#define HW_PINCTRL_DRIVE11     0x2B0
+#define HW_PINCTRL_DRIVE12     0x2C0
+#define HW_PINCTRL_DRIVE13     0x2D0
+#define HW_PINCTRL_DRIVE14     0x2E0
+
+#define HW_PINCTRL_PULL0       0x300
+#define HW_PINCTRL_PULL1       0x310
+#define HW_PINCTRL_PULL2       0x320
+#define HW_PINCTRL_PULL3       0x330
+
+#define HW_PINCTRL_DOUT0       0x400
+#define HW_PINCTRL_DOUT1       0x410
+#define HW_PINCTRL_DOUT2       0x420
+
+#define HW_PINCTRL_DIN0                0x500
+#define HW_PINCTRL_DIN1                0x510
+#define HW_PINCTRL_DIN2                0x520
+
+#define HW_PINCTRL_DOE0                0x600
+#define HW_PINCTRL_DOE1                0x610
+#define HW_PINCTRL_DOE2                0x620
+
+#define HW_PINCTRL_PIN2IRQ0    0x700
+#define HW_PINCTRL_PIN2IRQ1    0x710
+#define HW_PINCTRL_PIN2IRQ2    0x720
+
+#define HW_PINCTRL_IRQEN0      0x800
+#define HW_PINCTRL_IRQEN1      0x810
+#define HW_PINCTRL_IRQEN2      0x820
+
+#define HW_PINCTRL_IRQLEVEL0   0x900
+#define HW_PINCTRL_IRQLEVEL1   0x910
+#define HW_PINCTRL_IRQLEVEL2   0x920
+
+#define HW_PINCTRL_IRQPOL0     0xA00
+#define HW_PINCTRL_IRQPOL1     0xA10
+#define HW_PINCTRL_IRQPOL2     0xA20
+
+#define HW_PINCTRL_IRQSTAT0    0xB00
+#define HW_PINCTRL_IRQSTAT1    0xB10
+#define HW_PINCTRL_IRQSTAT2    0xB20
+
+#endif
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-power.h b/arch/arm/mach-stmp37xx/include/mach/regs-power.h
new file mode 100644 (file)
index 0000000..0e733d7
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * stmp37xx: POWER register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef _MACH_REGS_POWER
+#define _MACH_REGS_POWER
+
+#define REGS_POWER_BASE        (STMP3XXX_REGS_BASE + 0x44000)
+
+#define HW_POWER_CTRL          0x0
+#define BM_POWER_CTRL_CLKGATE  0x40000000
+
+#define HW_POWER_5VCTRL                0x10
+
+#define HW_POWER_MINPWR                0x20
+
+#define HW_POWER_CHARGE                0x30
+
+#define HW_POWER_VDDDCTRL      0x40
+
+#define HW_POWER_VDDACTRL      0x50
+
+#define HW_POWER_VDDIOCTRL     0x60
+#define BM_POWER_VDDIOCTRL_TRG 0x0000001F
+#define BP_POWER_VDDIOCTRL_TRG 0
+
+#define HW_POWER_STS           0xB0
+#define BM_POWER_STS_VBUSVALID 0x00000002
+#define BM_POWER_STS_BVALID    0x00000004
+#define BM_POWER_STS_AVALID    0x00000008
+#define BM_POWER_STS_DC_OK     0x00000100
+
+#define HW_POWER_RESET         0xE0
+
+#define HW_POWER_DEBUG         0xF0
+#define BM_POWER_DEBUG_BVALIDPIOLOCK   0x00000002
+#define BM_POWER_DEBUG_AVALIDPIOLOCK   0x00000004
+#define BM_POWER_DEBUG_VBUSVALIDPIOLOCK        0x00000008
+
+#endif
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-pwm.h b/arch/arm/mach-stmp37xx/include/mach/regs-pwm.h
new file mode 100644 (file)
index 0000000..15966a1
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * stmp37xx: PWM register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_PWM_BASE  (STMP3XXX_REGS_BASE + 0x64000)
+
+#define HW_PWM_CTRL            0x0
+#define BM_PWM_CTRL_PWM2_ENABLE        0x00000004
+#define BM_PWM_CTRL_PWM2_ANA_CTRL_ENABLE       0x00000020
+
+#define HW_PWM_ACTIVE0         (0x10 + 0 * 0x20)
+#define HW_PWM_ACTIVE1         (0x10 + 1 * 0x20)
+#define HW_PWM_ACTIVE2         (0x10 + 2 * 0x20)
+#define HW_PWM_ACTIVE3         (0x10 + 3 * 0x20)
+
+#define HW_PWM_ACTIVEn         0x10
+#define BM_PWM_ACTIVEn_ACTIVE  0x0000FFFF
+#define BP_PWM_ACTIVEn_ACTIVE  0
+#define BM_PWM_ACTIVEn_INACTIVE        0xFFFF0000
+#define BP_PWM_ACTIVEn_INACTIVE        16
+
+#define HW_PWM_PERIOD0         (0x20 + 0 * 0x20)
+#define HW_PWM_PERIOD1         (0x20 + 1 * 0x20)
+#define HW_PWM_PERIOD2         (0x20 + 2 * 0x20)
+#define HW_PWM_PERIOD3         (0x20 + 3 * 0x20)
+
+#define HW_PWM_PERIODn         0x20
+#define BM_PWM_PERIODn_PERIOD  0x0000FFFF
+#define BP_PWM_PERIODn_PERIOD  0
+#define BM_PWM_PERIODn_ACTIVE_STATE    0x00030000
+#define BP_PWM_PERIODn_ACTIVE_STATE    16
+#define BM_PWM_PERIODn_INACTIVE_STATE  0x000C0000
+#define BP_PWM_PERIODn_INACTIVE_STATE  18
+#define BM_PWM_PERIODn_CDIV    0x00700000
+#define BP_PWM_PERIODn_CDIV    20
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-rtc.h b/arch/arm/mach-stmp37xx/include/mach/regs-rtc.h
new file mode 100644 (file)
index 0000000..fac40ed
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * stmp37xx: RTC register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_RTC_BASE  (STMP3XXX_REGS_BASE + 0x5C000)
+#define REGS_RTC_PHYS   0x8005C000
+#define REGS_RTC_SIZE   0x2000
+
+#define HW_RTC_CTRL            0x0
+#define BM_RTC_CTRL_ALARM_IRQ_EN       0x00000001
+#define BP_RTC_CTRL_ALARM_IRQ_EN       0
+#define BM_RTC_CTRL_ONEMSEC_IRQ_EN     0x00000002
+#define BM_RTC_CTRL_ALARM_IRQ  0x00000004
+#define BM_RTC_CTRL_ONEMSEC_IRQ        0x00000008
+#define BM_RTC_CTRL_WATCHDOGEN 0x00000010
+
+#define HW_RTC_STAT            0x10
+#define BM_RTC_STAT_NEW_REGS   0x0000FF00
+#define BP_RTC_STAT_NEW_REGS   8
+#define BM_RTC_STAT_STALE_REGS 0x00FF0000
+#define BP_RTC_STAT_STALE_REGS 16
+#define BM_RTC_STAT_RTC_PRESENT        0x80000000
+
+#define HW_RTC_SECONDS         0x30
+
+#define HW_RTC_ALARM           0x40
+
+#define HW_RTC_WATCHDOG                0x50
+
+#define HW_RTC_PERSISTENT0     0x60
+#define BM_RTC_PERSISTENT0_ALARM_WAKE_EN       0x00000002
+#define BM_RTC_PERSISTENT0_ALARM_EN    0x00000004
+#define BM_RTC_PERSISTENT0_XTAL24MHZ_PWRUP     0x00000010
+#define BM_RTC_PERSISTENT0_XTAL32KHZ_PWRUP     0x00000020
+#define BM_RTC_PERSISTENT0_ALARM_WAKE  0x00000080
+#define BM_RTC_PERSISTENT0_SPARE_ANALOG        0xFFFC0000
+#define BP_RTC_PERSISTENT0_SPARE_ANALOG        18
+
+#define HW_RTC_PERSISTENT1     0x70
+
+#define HW_RTC_VERSION         0xD0
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-ssp.h b/arch/arm/mach-stmp37xx/include/mach/regs-ssp.h
new file mode 100644 (file)
index 0000000..cbde891
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * stmp37xx: SSP register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_SSP_BASE  (STMP3XXX_REGS_BASE + 0x10000)
+#define REGS_SSP1_PHYS 0x80010000
+#define REGS_SSP2_PHYS 0x80034000
+#define REGS_SSP_SIZE  0x2000
+
+#define HW_SSP_CTRL0           0x0
+#define BM_SSP_CTRL0_XFER_COUNT        0x0000FFFF
+#define BP_SSP_CTRL0_XFER_COUNT        0
+#define BM_SSP_CTRL0_ENABLE    0x00010000
+#define BM_SSP_CTRL0_GET_RESP  0x00020000
+#define BM_SSP_CTRL0_LONG_RESP 0x00080000
+#define BM_SSP_CTRL0_WAIT_FOR_CMD      0x00100000
+#define BM_SSP_CTRL0_WAIT_FOR_IRQ      0x00200000
+#define BM_SSP_CTRL0_BUS_WIDTH 0x00C00000
+#define BP_SSP_CTRL0_BUS_WIDTH 22
+#define BM_SSP_CTRL0_DATA_XFER 0x01000000
+#define BM_SSP_CTRL0_READ      0x02000000
+#define BM_SSP_CTRL0_IGNORE_CRC        0x04000000
+#define BM_SSP_CTRL0_LOCK_CS   0x08000000
+#define BM_SSP_CTRL0_RUN       0x20000000
+#define BM_SSP_CTRL0_CLKGATE   0x40000000
+#define BM_SSP_CTRL0_SFTRST    0x80000000
+
+#define HW_SSP_CMD0            0x10
+#define BM_SSP_CMD0_CMD                0x000000FF
+#define BP_SSP_CMD0_CMD                0
+#define BM_SSP_CMD0_BLOCK_COUNT        0x0000FF00
+#define BP_SSP_CMD0_BLOCK_COUNT        8
+#define BM_SSP_CMD0_BLOCK_SIZE 0x000F0000
+#define BP_SSP_CMD0_BLOCK_SIZE 16
+#define BM_SSP_CMD0_APPEND_8CYC        0x00100000
+#define BM_SSP_CMD1_CMD_ARG    0xFFFFFFFF
+#define BP_SSP_CMD1_CMD_ARG    0
+
+#define HW_SSP_TIMING          0x50
+#define BM_SSP_TIMING_CLOCK_RATE       0x000000FF
+#define BP_SSP_TIMING_CLOCK_RATE       0
+#define BM_SSP_TIMING_CLOCK_DIVIDE     0x0000FF00
+#define BP_SSP_TIMING_CLOCK_DIVIDE     8
+#define BM_SSP_TIMING_TIMEOUT  0xFFFF0000
+#define BP_SSP_TIMING_TIMEOUT  16
+
+#define HW_SSP_CTRL1           0x60
+#define BM_SSP_CTRL1_SSP_MODE  0x0000000F
+#define BP_SSP_CTRL1_SSP_MODE  0
+#define BM_SSP_CTRL1_WORD_LENGTH       0x000000F0
+#define BP_SSP_CTRL1_WORD_LENGTH       4
+#define BM_SSP_CTRL1_POLARITY  0x00000200
+#define BM_SSP_CTRL1_PHASE     0x00000400
+#define BM_SSP_CTRL1_DMA_ENABLE        0x00002000
+#define BM_SSP_CTRL1_FIFO_OVERRUN_IRQ  0x00008000
+#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN       0x00010000
+#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ  0x00020000
+#define BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ 0x00200000
+#define BM_SSP_CTRL1_DATA_CRC_IRQ_EN   0x00400000
+#define BM_SSP_CTRL1_DATA_CRC_IRQ      0x00800000
+#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN       0x01000000
+#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ  0x02000000
+#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN       0x04000000
+#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ  0x08000000
+#define BM_SSP_CTRL1_RESP_ERR_IRQ_EN   0x10000000
+#define BM_SSP_CTRL1_RESP_ERR_IRQ      0x20000000
+#define BM_SSP_CTRL1_SDIO_IRQ  0x80000000
+
+#define HW_SSP_DATA            0x70
+
+#define HW_SSP_SDRESP0         0x80
+
+#define HW_SSP_SDRESP1         0x90
+
+#define HW_SSP_SDRESP2         0xA0
+
+#define HW_SSP_SDRESP3         0xB0
+
+#define HW_SSP_STATUS          0xC0
+#define BM_SSP_STATUS_FIFO_EMPTY       0x00000020
+#define BM_SSP_STATUS_TIMEOUT  0x00001000
+#define BM_SSP_STATUS_RESP_TIMEOUT     0x00004000
+#define BM_SSP_STATUS_RESP_ERR 0x00008000
+#define BM_SSP_STATUS_RESP_CRC_ERR     0x00010000
+#define BM_SSP_STATUS_CARD_DETECT      0x10000000
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-timrot.h b/arch/arm/mach-stmp37xx/include/mach/regs-timrot.h
new file mode 100644 (file)
index 0000000..4af0f6e
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * stmp37xx: TIMROT register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#ifndef _MACH_REGS_TIMROT
+#define _MACH_REGS_TIMROT
+
+#define REGS_TIMROT_BASE       (STMP3XXX_REGS_BASE + 0x68000)
+
+#define HW_TIMROT_ROTCTRL      0x0
+#define BM_TIMROT_ROTCTRL_CLKGATE      0x40000000
+#define BM_TIMROT_ROTCTRL_SFTRST       0x80000000
+
+#define HW_TIMROT_TIMCTRL0     (0x20 + 0 * 0x20)
+#define HW_TIMROT_TIMCTRL1     (0x20 + 1 * 0x20)
+#define HW_TIMROT_TIMCTRL2     (0x20 + 2 * 0x20)
+
+#define HW_TIMROT_TIMCTRLn     0x20
+#define BM_TIMROT_TIMCTRLn_SELECT      0x0000000F
+#define BP_TIMROT_TIMCTRLn_SELECT      0
+#define BM_TIMROT_TIMCTRLn_PRESCALE    0x00000030
+#define BP_TIMROT_TIMCTRLn_PRESCALE    4
+#define BM_TIMROT_TIMCTRLn_RELOAD      0x00000040
+#define BM_TIMROT_TIMCTRLn_UPDATE      0x00000080
+#define BM_TIMROT_TIMCTRLn_IRQ_EN      0x00004000
+#define BM_TIMROT_TIMCTRLn_IRQ 0x00008000
+
+#define HW_TIMROT_TIMCOUNT0    (0x30 + 0 * 0x20)
+#define HW_TIMROT_TIMCOUNT1    (0x30 + 1 * 0x20)
+#define HW_TIMROT_TIMCOUNT2    (0x30 + 2 * 0x20)
+
+#define HW_TIMROT_TIMCOUNTn    0x30
+#endif
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-uartapp.h b/arch/arm/mach-stmp37xx/include/mach/regs-uartapp.h
new file mode 100644 (file)
index 0000000..0594275
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * stmp37xx: UARTAPP register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_UARTAPP_BASE      (STMP3XXX_REGS_BASE + 0x6C000)
+#define REGS_UARTAPP1_PHYS     0x8006C000
+#define REGS_UARTAPP_SIZE      0x2000
+
+#define HW_UARTAPP_CTRL0       0x0
+#define BM_UARTAPP_CTRL0_XFER_COUNT    0x0000FFFF
+#define BP_UARTAPP_CTRL0_XFER_COUNT    0
+#define BM_UARTAPP_CTRL0_RXTIMEOUT     0x07FF0000
+#define BP_UARTAPP_CTRL0_RXTIMEOUT     16
+#define BM_UARTAPP_CTRL0_RXTO_ENABLE   0x08000000
+#define BM_UARTAPP_CTRL0_RUN   0x20000000
+#define BM_UARTAPP_CTRL0_SFTRST        0x80000000
+#define BM_UARTAPP_CTRL1_XFER_COUNT    0x0000FFFF
+#define BP_UARTAPP_CTRL1_XFER_COUNT    0
+#define BM_UARTAPP_CTRL1_RUN   0x10000000
+
+#define HW_UARTAPP_CTRL2       0x20
+#define BM_UARTAPP_CTRL2_UARTEN        0x00000001
+#define BP_UARTAPP_CTRL2_UARTEN        0
+#define BM_UARTAPP_CTRL2_TXE   0x00000100
+#define BM_UARTAPP_CTRL2_RXE   0x00000200
+#define BM_UARTAPP_CTRL2_RTS   0x00000800
+#define BM_UARTAPP_CTRL2_RTSEN 0x00004000
+#define BM_UARTAPP_CTRL2_CTSEN 0x00008000
+#define BM_UARTAPP_CTRL2_RXDMAE        0x01000000
+#define BM_UARTAPP_CTRL2_TXDMAE        0x02000000
+#define BM_UARTAPP_CTRL2_DMAONERR      0x04000000
+
+#define HW_UARTAPP_LINECTRL    0x30
+#define BM_UARTAPP_LINECTRL_BRK        0x00000001
+#define BP_UARTAPP_LINECTRL_BRK        0
+#define BM_UARTAPP_LINECTRL_PEN        0x00000002
+#define BM_UARTAPP_LINECTRL_EPS        0x00000004
+#define BM_UARTAPP_LINECTRL_STP2       0x00000008
+#define BM_UARTAPP_LINECTRL_FEN        0x00000010
+#define BM_UARTAPP_LINECTRL_WLEN       0x00000060
+#define BP_UARTAPP_LINECTRL_WLEN       5
+#define BM_UARTAPP_LINECTRL_SPS        0x00000080
+#define BM_UARTAPP_LINECTRL_BAUD_DIVFRAC       0x00003F00
+#define BP_UARTAPP_LINECTRL_BAUD_DIVFRAC       8
+#define BM_UARTAPP_LINECTRL_BAUD_DIVINT        0xFFFF0000
+#define BP_UARTAPP_LINECTRL_BAUD_DIVINT        16
+
+#define HW_UARTAPP_INTR                0x50
+#define BM_UARTAPP_INTR_CTSMIS 0x00000002
+#define BM_UARTAPP_INTR_RTIS   0x00000040
+#define BM_UARTAPP_INTR_CTSMIEN        0x00020000
+#define BM_UARTAPP_INTR_RXIEN  0x00100000
+#define BM_UARTAPP_INTR_RTIEN  0x00400000
+
+#define HW_UARTAPP_DATA                0x60
+
+#define HW_UARTAPP_STAT                0x70
+#define BM_UARTAPP_STAT_RXCOUNT        0x0000FFFF
+#define BP_UARTAPP_STAT_RXCOUNT        0
+#define BM_UARTAPP_STAT_FERR   0x00010000
+#define BM_UARTAPP_STAT_PERR   0x00020000
+#define BM_UARTAPP_STAT_BERR   0x00040000
+#define BM_UARTAPP_STAT_OERR   0x00080000
+#define BM_UARTAPP_STAT_RXFE   0x01000000
+#define BM_UARTAPP_STAT_TXFF   0x02000000
+#define BM_UARTAPP_STAT_TXFE   0x08000000
+#define BM_UARTAPP_STAT_CTS    0x10000000
+
+#define HW_UARTAPP_VERSION     0x90
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-uartdbg.h b/arch/arm/mach-stmp37xx/include/mach/regs-uartdbg.h
new file mode 100644 (file)
index 0000000..b810deb
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * stmp378x: UARTDBG register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_UARTDBG_BASE      (STMP3XXX_REGS_BASE + 0x70000)
+#define REGS_UARTDBG_PHYS      0x80070000
+#define REGS_UARTDBG_SIZE      0x2000
+
+#define HW_UARTDBGDR 0x00000000
+#define BP_UARTDBGDR_UNAVAILABLE      16
+#define BM_UARTDBGDR_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGDR_UNAVAILABLE(v) \
+       (((v) << 16) & BM_UARTDBGDR_UNAVAILABLE)
+#define BP_UARTDBGDR_RESERVED      12
+#define BM_UARTDBGDR_RESERVED 0x0000F000
+#define BF_UARTDBGDR_RESERVED(v)  \
+       (((v) << 12) & BM_UARTDBGDR_RESERVED)
+#define BM_UARTDBGDR_OE 0x00000800
+#define BM_UARTDBGDR_BE 0x00000400
+#define BM_UARTDBGDR_PE 0x00000200
+#define BM_UARTDBGDR_FE 0x00000100
+#define BP_UARTDBGDR_DATA      0
+#define BM_UARTDBGDR_DATA 0x000000FF
+#define BF_UARTDBGDR_DATA(v)  \
+       (((v) << 0) & BM_UARTDBGDR_DATA)
+#define HW_UARTDBGRSR_ECR 0x00000004
+#define BP_UARTDBGRSR_ECR_UNAVAILABLE      8
+#define BM_UARTDBGRSR_ECR_UNAVAILABLE 0xFFFFFF00
+#define BF_UARTDBGRSR_ECR_UNAVAILABLE(v) \
+       (((v) << 8) & BM_UARTDBGRSR_ECR_UNAVAILABLE)
+#define BP_UARTDBGRSR_ECR_EC      4
+#define BM_UARTDBGRSR_ECR_EC 0x000000F0
+#define BF_UARTDBGRSR_ECR_EC(v)  \
+       (((v) << 4) & BM_UARTDBGRSR_ECR_EC)
+#define BM_UARTDBGRSR_ECR_OE 0x00000008
+#define BM_UARTDBGRSR_ECR_BE 0x00000004
+#define BM_UARTDBGRSR_ECR_PE 0x00000002
+#define BM_UARTDBGRSR_ECR_FE 0x00000001
+#define HW_UARTDBGFR 0x00000018
+#define BP_UARTDBGFR_UNAVAILABLE      16
+#define BM_UARTDBGFR_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGFR_UNAVAILABLE(v) \
+       (((v) << 16) & BM_UARTDBGFR_UNAVAILABLE)
+#define BP_UARTDBGFR_RESERVED      9
+#define BM_UARTDBGFR_RESERVED 0x0000FE00
+#define BF_UARTDBGFR_RESERVED(v)  \
+       (((v) << 9) & BM_UARTDBGFR_RESERVED)
+#define BM_UARTDBGFR_RI 0x00000100
+#define BM_UARTDBGFR_TXFE 0x00000080
+#define BM_UARTDBGFR_RXFF 0x00000040
+#define BM_UARTDBGFR_TXFF 0x00000020
+#define BM_UARTDBGFR_RXFE 0x00000010
+#define BM_UARTDBGFR_BUSY 0x00000008
+#define BM_UARTDBGFR_DCD 0x00000004
+#define BM_UARTDBGFR_DSR 0x00000002
+#define BM_UARTDBGFR_CTS 0x00000001
+#define HW_UARTDBGILPR 0x00000020
+#define BP_UARTDBGILPR_UNAVAILABLE      8
+#define BM_UARTDBGILPR_UNAVAILABLE 0xFFFFFF00
+#define BF_UARTDBGILPR_UNAVAILABLE(v) \
+       (((v) << 8) & BM_UARTDBGILPR_UNAVAILABLE)
+#define BP_UARTDBGILPR_ILPDVSR      0
+#define BM_UARTDBGILPR_ILPDVSR 0x000000FF
+#define BF_UARTDBGILPR_ILPDVSR(v)  \
+       (((v) << 0) & BM_UARTDBGILPR_ILPDVSR)
+#define HW_UARTDBGIBRD 0x00000024
+#define BP_UARTDBGIBRD_UNAVAILABLE      16
+#define BM_UARTDBGIBRD_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGIBRD_UNAVAILABLE(v) \
+       (((v) << 16) & BM_UARTDBGIBRD_UNAVAILABLE)
+#define BP_UARTDBGIBRD_BAUD_DIVINT      0
+#define BM_UARTDBGIBRD_BAUD_DIVINT 0x0000FFFF
+#define BF_UARTDBGIBRD_BAUD_DIVINT(v)  \
+       (((v) << 0) & BM_UARTDBGIBRD_BAUD_DIVINT)
+#define HW_UARTDBGFBRD 0x00000028
+#define BP_UARTDBGFBRD_UNAVAILABLE      8
+#define BM_UARTDBGFBRD_UNAVAILABLE 0xFFFFFF00
+#define BF_UARTDBGFBRD_UNAVAILABLE(v) \
+       (((v) << 8) & BM_UARTDBGFBRD_UNAVAILABLE)
+#define BP_UARTDBGFBRD_RESERVED      6
+#define BM_UARTDBGFBRD_RESERVED 0x000000C0
+#define BF_UARTDBGFBRD_RESERVED(v)  \
+       (((v) << 6) & BM_UARTDBGFBRD_RESERVED)
+#define BP_UARTDBGFBRD_BAUD_DIVFRAC      0
+#define BM_UARTDBGFBRD_BAUD_DIVFRAC 0x0000003F
+#define BF_UARTDBGFBRD_BAUD_DIVFRAC(v)  \
+       (((v) << 0) & BM_UARTDBGFBRD_BAUD_DIVFRAC)
+#define HW_UARTDBGLCR_H 0x0000002c
+#define BP_UARTDBGLCR_H_UNAVAILABLE      16
+#define BM_UARTDBGLCR_H_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGLCR_H_UNAVAILABLE(v) \
+       (((v) << 16) & BM_UARTDBGLCR_H_UNAVAILABLE)
+#define BP_UARTDBGLCR_H_RESERVED      8
+#define BM_UARTDBGLCR_H_RESERVED 0x0000FF00
+#define BF_UARTDBGLCR_H_RESERVED(v)  \
+       (((v) << 8) & BM_UARTDBGLCR_H_RESERVED)
+#define BM_UARTDBGLCR_H_SPS 0x00000080
+#define BP_UARTDBGLCR_H_WLEN      5
+#define BM_UARTDBGLCR_H_WLEN 0x00000060
+#define BF_UARTDBGLCR_H_WLEN(v)  \
+       (((v) << 5) & BM_UARTDBGLCR_H_WLEN)
+#define BM_UARTDBGLCR_H_FEN 0x00000010
+#define BM_UARTDBGLCR_H_STP2 0x00000008
+#define BM_UARTDBGLCR_H_EPS 0x00000004
+#define BM_UARTDBGLCR_H_PEN 0x00000002
+#define BM_UARTDBGLCR_H_BRK 0x00000001
+#define HW_UARTDBGCR 0x00000030
+#define BP_UARTDBGCR_UNAVAILABLE      16
+#define BM_UARTDBGCR_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGCR_UNAVAILABLE(v) \
+       (((v) << 16) & BM_UARTDBGCR_UNAVAILABLE)
+#define BM_UARTDBGCR_CTSEN 0x00008000
+#define BM_UARTDBGCR_RTSEN 0x00004000
+#define BM_UARTDBGCR_OUT2 0x00002000
+#define BM_UARTDBGCR_OUT1 0x00001000
+#define BM_UARTDBGCR_RTS 0x00000800
+#define BM_UARTDBGCR_DTR 0x00000400
+#define BM_UARTDBGCR_RXE 0x00000200
+#define BM_UARTDBGCR_TXE 0x00000100
+#define BM_UARTDBGCR_LBE 0x00000080
+#define BP_UARTDBGCR_RESERVED      3
+#define BM_UARTDBGCR_RESERVED 0x00000078
+#define BF_UARTDBGCR_RESERVED(v)  \
+       (((v) << 3) & BM_UARTDBGCR_RESERVED)
+#define BM_UARTDBGCR_SIRLP 0x00000004
+#define BM_UARTDBGCR_SIREN 0x00000002
+#define BM_UARTDBGCR_UARTEN 0x00000001
+#define HW_UARTDBGIFLS 0x00000034
+#define BP_UARTDBGIFLS_UNAVAILABLE      16
+#define BM_UARTDBGIFLS_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGIFLS_UNAVAILABLE(v) \
+       (((v) << 16) & BM_UARTDBGIFLS_UNAVAILABLE)
+#define BP_UARTDBGIFLS_RESERVED      6
+#define BM_UARTDBGIFLS_RESERVED 0x0000FFC0
+#define BF_UARTDBGIFLS_RESERVED(v)  \
+       (((v) << 6) & BM_UARTDBGIFLS_RESERVED)
+#define BP_UARTDBGIFLS_RXIFLSEL      3
+#define BM_UARTDBGIFLS_RXIFLSEL 0x00000038
+#define BF_UARTDBGIFLS_RXIFLSEL(v)  \
+       (((v) << 3) & BM_UARTDBGIFLS_RXIFLSEL)
+#define BV_UARTDBGIFLS_RXIFLSEL__NOT_EMPTY      0x0
+#define BV_UARTDBGIFLS_RXIFLSEL__ONE_QUARTER    0x1
+#define BV_UARTDBGIFLS_RXIFLSEL__ONE_HALF       0x2
+#define BV_UARTDBGIFLS_RXIFLSEL__THREE_QUARTERS 0x3
+#define BV_UARTDBGIFLS_RXIFLSEL__SEVEN_EIGHTHS  0x4
+#define BV_UARTDBGIFLS_RXIFLSEL__INVALID5       0x5
+#define BV_UARTDBGIFLS_RXIFLSEL__INVALID6       0x6
+#define BV_UARTDBGIFLS_RXIFLSEL__INVALID7       0x7
+#define BP_UARTDBGIFLS_TXIFLSEL      0
+#define BM_UARTDBGIFLS_TXIFLSEL 0x00000007
+#define BF_UARTDBGIFLS_TXIFLSEL(v)  \
+       (((v) << 0) & BM_UARTDBGIFLS_TXIFLSEL)
+#define BV_UARTDBGIFLS_TXIFLSEL__EMPTY   0x0
+#define BV_UARTDBGIFLS_TXIFLSEL__ONE_QUARTER    0x1
+#define BV_UARTDBGIFLS_TXIFLSEL__ONE_HALF       0x2
+#define BV_UARTDBGIFLS_TXIFLSEL__THREE_QUARTERS 0x3
+#define BV_UARTDBGIFLS_TXIFLSEL__SEVEN_EIGHTHS  0x4
+#define BV_UARTDBGIFLS_TXIFLSEL__INVALID5       0x5
+#define BV_UARTDBGIFLS_TXIFLSEL__INVALID6       0x6
+#define BV_UARTDBGIFLS_TXIFLSEL__INVALID7       0x7
+#define HW_UARTDBGIMSC 0x00000038
+#define BP_UARTDBGIMSC_UNAVAILABLE      16
+#define BM_UARTDBGIMSC_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGIMSC_UNAVAILABLE(v) \
+       (((v) << 16) & BM_UARTDBGIMSC_UNAVAILABLE)
+#define BP_UARTDBGIMSC_RESERVED      11
+#define BM_UARTDBGIMSC_RESERVED 0x0000F800
+#define BF_UARTDBGIMSC_RESERVED(v)  \
+       (((v) << 11) & BM_UARTDBGIMSC_RESERVED)
+#define BM_UARTDBGIMSC_OEIM 0x00000400
+#define BM_UARTDBGIMSC_BEIM 0x00000200
+#define BM_UARTDBGIMSC_PEIM 0x00000100
+#define BM_UARTDBGIMSC_FEIM 0x00000080
+#define BM_UARTDBGIMSC_RTIM 0x00000040
+#define BM_UARTDBGIMSC_TXIM 0x00000020
+#define BM_UARTDBGIMSC_RXIM 0x00000010
+#define BM_UARTDBGIMSC_DSRMIM 0x00000008
+#define BM_UARTDBGIMSC_DCDMIM 0x00000004
+#define BM_UARTDBGIMSC_CTSMIM 0x00000002
+#define BM_UARTDBGIMSC_RIMIM 0x00000001
+#define HW_UARTDBGRIS 0x0000003c
+#define BP_UARTDBGRIS_UNAVAILABLE      16
+#define BM_UARTDBGRIS_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGRIS_UNAVAILABLE(v) \
+       (((v) << 16) & BM_UARTDBGRIS_UNAVAILABLE)
+#define BP_UARTDBGRIS_RESERVED      11
+#define BM_UARTDBGRIS_RESERVED 0x0000F800
+#define BF_UARTDBGRIS_RESERVED(v)  \
+       (((v) << 11) & BM_UARTDBGRIS_RESERVED)
+#define BM_UARTDBGRIS_OERIS 0x00000400
+#define BM_UARTDBGRIS_BERIS 0x00000200
+#define BM_UARTDBGRIS_PERIS 0x00000100
+#define BM_UARTDBGRIS_FERIS 0x00000080
+#define BM_UARTDBGRIS_RTRIS 0x00000040
+#define BM_UARTDBGRIS_TXRIS 0x00000020
+#define BM_UARTDBGRIS_RXRIS 0x00000010
+#define BM_UARTDBGRIS_DSRRMIS 0x00000008
+#define BM_UARTDBGRIS_DCDRMIS 0x00000004
+#define BM_UARTDBGRIS_CTSRMIS 0x00000002
+#define BM_UARTDBGRIS_RIRMIS 0x00000001
+#define HW_UARTDBGMIS 0x00000040
+#define BP_UARTDBGMIS_UNAVAILABLE      16
+#define BM_UARTDBGMIS_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGMIS_UNAVAILABLE(v) \
+       (((v) << 16) & BM_UARTDBGMIS_UNAVAILABLE)
+#define BP_UARTDBGMIS_RESERVED      11
+#define BM_UARTDBGMIS_RESERVED 0x0000F800
+#define BF_UARTDBGMIS_RESERVED(v)  \
+       (((v) << 11) & BM_UARTDBGMIS_RESERVED)
+#define BM_UARTDBGMIS_OEMIS 0x00000400
+#define BM_UARTDBGMIS_BEMIS 0x00000200
+#define BM_UARTDBGMIS_PEMIS 0x00000100
+#define BM_UARTDBGMIS_FEMIS 0x00000080
+#define BM_UARTDBGMIS_RTMIS 0x00000040
+#define BM_UARTDBGMIS_TXMIS 0x00000020
+#define BM_UARTDBGMIS_RXMIS 0x00000010
+#define BM_UARTDBGMIS_DSRMMIS 0x00000008
+#define BM_UARTDBGMIS_DCDMMIS 0x00000004
+#define BM_UARTDBGMIS_CTSMMIS 0x00000002
+#define BM_UARTDBGMIS_RIMMIS 0x00000001
+#define HW_UARTDBGICR 0x00000044
+#define BP_UARTDBGICR_UNAVAILABLE      16
+#define BM_UARTDBGICR_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGICR_UNAVAILABLE(v) \
+       (((v) << 16) & BM_UARTDBGICR_UNAVAILABLE)
+#define BP_UARTDBGICR_RESERVED      11
+#define BM_UARTDBGICR_RESERVED 0x0000F800
+#define BF_UARTDBGICR_RESERVED(v)  \
+       (((v) << 11) & BM_UARTDBGICR_RESERVED)
+#define BM_UARTDBGICR_OEIC 0x00000400
+#define BM_UARTDBGICR_BEIC 0x00000200
+#define BM_UARTDBGICR_PEIC 0x00000100
+#define BM_UARTDBGICR_FEIC 0x00000080
+#define BM_UARTDBGICR_RTIC 0x00000040
+#define BM_UARTDBGICR_TXIC 0x00000020
+#define BM_UARTDBGICR_RXIC 0x00000010
+#define BM_UARTDBGICR_DSRMIC 0x00000008
+#define BM_UARTDBGICR_DCDMIC 0x00000004
+#define BM_UARTDBGICR_CTSMIC 0x00000002
+#define BM_UARTDBGICR_RIMIC 0x00000001
+#define HW_UARTDBGDMACR 0x00000048
+#define BP_UARTDBGDMACR_UNAVAILABLE      16
+#define BM_UARTDBGDMACR_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGDMACR_UNAVAILABLE(v) \
+       (((v) << 16) & BM_UARTDBGDMACR_UNAVAILABLE)
+#define BP_UARTDBGDMACR_RESERVED      3
+#define BM_UARTDBGDMACR_RESERVED 0x0000FFF8
+#define BF_UARTDBGDMACR_RESERVED(v)  \
+       (((v) << 3) & BM_UARTDBGDMACR_RESERVED)
+#define BM_UARTDBGDMACR_DMAONERR 0x00000004
+#define BM_UARTDBGDMACR_TXDMAE 0x00000002
+#define BM_UARTDBGDMACR_RXDMAE 0x00000001
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-usbctl.h b/arch/arm/mach-stmp37xx/include/mach/regs-usbctl.h
new file mode 100644 (file)
index 0000000..9145e22
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * stmp37xx: USBCTL register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_USBCTL_BASE       (STMP3XXX_REGS_BASE + 0x80000)
+#define REGS_USBCTL_PHYS       0x80000
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-usbctrl.h b/arch/arm/mach-stmp37xx/include/mach/regs-usbctrl.h
new file mode 100644 (file)
index 0000000..1a2ae9c
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * stmp37xx: USBCTRL register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_USBCTRL_BASE      (STMP3XXX_REGS_BASE + 0x80000)
+#define REGS_USBCTRL_PHYS      0x80080000
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-usbphy.h b/arch/arm/mach-stmp37xx/include/mach/regs-usbphy.h
new file mode 100644 (file)
index 0000000..b7fce0f
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * stmp37xx: USBPHY register definitions
+ *
+ * Copyright (c) 2008 Freescale Semiconductor
+ * Copyright 2008 Embedded Alley Solutions, 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
+ */
+#define REGS_USBPHY_BASE       (STMP3XXX_REGS_BASE + 0x7C000)
+
+#define HW_USBPHY_PWD          0x0
+
+#define HW_USBPHY_CTRL         0x30
+#define BM_USBPHY_CTRL_ENHSPRECHARGEXMIT       0x00000001
+#define BP_USBPHY_CTRL_ENHSPRECHARGEXMIT       0
+#define BM_USBPHY_CTRL_ENHOSTDISCONDETECT      0x00000002
+#define BM_USBPHY_CTRL_ENDEVPLUGINDETECT       0x00000010
+#define BM_USBPHY_CTRL_ENOTGIDDETECT   0x00000080
+#define BM_USBPHY_CTRL_ENIRQDEVPLUGIN  0x00000800
+#define BM_USBPHY_CTRL_CLKGATE 0x40000000
+#define BM_USBPHY_CTRL_SFTRST  0x80000000
+
+#define HW_USBPHY_STATUS       0x40
+#define BM_USBPHY_STATUS_DEVPLUGIN_STATUS      0x00000040
+#define BM_USBPHY_STATUS_OTGID_STATUS  0x00000100
diff --git a/arch/arm/mach-stmp37xx/stmp37xx.c b/arch/arm/mach-stmp37xx/stmp37xx.c
new file mode 100644 (file)
index 0000000..8c7d6fb
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * Freescale STMP37XX platform support
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+
+#include <mach/stmp3xxx.h>
+#include <mach/dma.h>
+
+#include <mach/platform.h>
+#include <mach/regs-icoll.h>
+#include <mach/regs-apbh.h>
+#include <mach/regs-apbx.h>
+#include "stmp37xx.h"
+
+/*
+ * IRQ handling
+ */
+static void stmp37xx_ack_irq(unsigned int irq)
+{
+       /* Disable IRQ */
+       stmp3xxx_clearl(0x04 << ((irq % 4) * 8),
+               REGS_ICOLL_BASE + HW_ICOLL_PRIORITYn + irq / 4 * 0x10);
+
+       /* ACK current interrupt */
+       __raw_writel(1, REGS_ICOLL_BASE + HW_ICOLL_LEVELACK);
+
+       /* Barrier */
+       (void)__raw_readl(REGS_ICOLL_BASE + HW_ICOLL_STAT);
+}
+
+static void stmp37xx_mask_irq(unsigned int irq)
+{
+       /* IRQ disable */
+       stmp3xxx_clearl(0x04 << ((irq % 4) * 8),
+               REGS_ICOLL_BASE + HW_ICOLL_PRIORITYn + irq / 4 * 0x10);
+}
+
+static void stmp37xx_unmask_irq(unsigned int irq)
+{
+       /* IRQ enable */
+       stmp3xxx_setl(0x04 << ((irq % 4) * 8),
+               REGS_ICOLL_BASE + HW_ICOLL_PRIORITYn + irq / 4 * 0x10);
+}
+
+static struct irq_chip stmp37xx_chip = {
+       .ack    = stmp37xx_ack_irq,
+       .mask   = stmp37xx_mask_irq,
+       .unmask = stmp37xx_unmask_irq,
+};
+
+void __init stmp37xx_init_irq(void)
+{
+       stmp3xxx_init_irq(&stmp37xx_chip);
+}
+
+/*
+ * DMA interrupt handling
+ */
+void stmp3xxx_arch_dma_enable_interrupt(int channel)
+{
+       switch (STMP3XXX_DMA_BUS(channel)) {
+       case STMP3XXX_BUS_APBH:
+               stmp3xxx_setl(1 << (8 + STMP3XXX_DMA_CHANNEL(channel)),
+                       REGS_APBH_BASE + HW_APBH_CTRL1);
+               break;
+
+       case STMP3XXX_BUS_APBX:
+               stmp3xxx_setl(1 << (8 + STMP3XXX_DMA_CHANNEL(channel)),
+                       REGS_APBX_BASE + HW_APBX_CTRL1);
+               break;
+       }
+}
+EXPORT_SYMBOL(stmp3xxx_arch_dma_enable_interrupt);
+
+void stmp3xxx_arch_dma_clear_interrupt(int channel)
+{
+       switch (STMP3XXX_DMA_BUS(channel)) {
+       case STMP3XXX_BUS_APBH:
+               stmp3xxx_clearl(1 << STMP3XXX_DMA_CHANNEL(channel),
+                               REGS_APBH_BASE + HW_APBH_CTRL1);
+               break;
+
+       case STMP3XXX_BUS_APBX:
+               stmp3xxx_clearl(1 << STMP3XXX_DMA_CHANNEL(channel),
+                               REGS_APBX_BASE + HW_APBX_CTRL1);
+               break;
+       }
+}
+EXPORT_SYMBOL(stmp3xxx_arch_dma_clear_interrupt);
+
+int stmp3xxx_arch_dma_is_interrupt(int channel)
+{
+       int r = 0;
+
+       switch (STMP3XXX_DMA_BUS(channel)) {
+       case STMP3XXX_BUS_APBH:
+               r = __raw_readl(REGS_APBH_BASE + HW_APBH_CTRL1) &
+                       (1 << STMP3XXX_DMA_CHANNEL(channel));
+               break;
+
+       case STMP3XXX_BUS_APBX:
+               r = __raw_readl(REGS_APBH_BASE + HW_APBH_CTRL1) &
+                       (1 << STMP3XXX_DMA_CHANNEL(channel));
+               break;
+       }
+       return r;
+}
+EXPORT_SYMBOL(stmp3xxx_arch_dma_is_interrupt);
+
+void stmp3xxx_arch_dma_reset_channel(int channel)
+{
+       unsigned chbit = 1 << STMP3XXX_DMA_CHANNEL(channel);
+
+       switch (STMP3XXX_DMA_BUS(channel)) {
+       case STMP3XXX_BUS_APBH:
+               /* Reset channel and wait for it to complete */
+               stmp3xxx_setl(chbit << BP_APBH_CTRL0_RESET_CHANNEL,
+                       REGS_APBH_BASE + HW_APBH_CTRL0);
+               while (__raw_readl(REGS_APBH_BASE + HW_APBH_CTRL0) &
+                      (chbit << BP_APBH_CTRL0_RESET_CHANNEL))
+                               cpu_relax();
+               break;
+
+       case STMP3XXX_BUS_APBX:
+               stmp3xxx_setl(chbit << BP_APBX_CTRL0_RESET_CHANNEL,
+                       REGS_APBX_BASE + HW_APBX_CTRL0);
+               while (__raw_readl(REGS_APBX_BASE + HW_APBX_CTRL0) &
+                      (chbit << BP_APBX_CTRL0_RESET_CHANNEL))
+                               cpu_relax();
+               break;
+       }
+}
+EXPORT_SYMBOL(stmp3xxx_arch_dma_reset_channel);
+
+void stmp3xxx_arch_dma_freeze(int channel)
+{
+       unsigned chbit = 1 << STMP3XXX_DMA_CHANNEL(channel);
+
+       switch (STMP3XXX_DMA_BUS(channel)) {
+       case STMP3XXX_BUS_APBH:
+               stmp3xxx_setl(1 << chbit, REGS_APBH_BASE + HW_APBH_CTRL0);
+               break;
+       case STMP3XXX_BUS_APBX:
+               stmp3xxx_setl(1 << chbit, REGS_APBH_BASE + HW_APBH_CTRL0);
+               break;
+       }
+}
+EXPORT_SYMBOL(stmp3xxx_arch_dma_freeze);
+
+void stmp3xxx_arch_dma_unfreeze(int channel)
+{
+       unsigned chbit = 1 << STMP3XXX_DMA_CHANNEL(channel);
+
+       switch (STMP3XXX_DMA_BUS(channel)) {
+       case STMP3XXX_BUS_APBH:
+               stmp3xxx_clearl(1 << chbit, REGS_APBH_BASE + HW_APBH_CTRL0);
+               break;
+       case STMP3XXX_BUS_APBX:
+               stmp3xxx_clearl(1 << chbit, REGS_APBH_BASE + HW_APBH_CTRL0);
+               break;
+       }
+}
+EXPORT_SYMBOL(stmp3xxx_arch_dma_unfreeze);
+
+/*
+ * The registers are all very closely mapped, so we might as well map them all
+ * with a single mapping
+ *
+ * Logical      Physical
+ * f0000000    80000000        On-chip registers
+ * f1000000    00000000        32k on-chip SRAM
+ */
+static struct map_desc stmp37xx_io_desc[] __initdata = {
+       {
+               .virtual        = (u32)STMP3XXX_REGS_BASE,
+               .pfn            = __phys_to_pfn(STMP3XXX_REGS_PHBASE),
+               .length         = SZ_1M,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = (u32)STMP3XXX_OCRAM_BASE,
+               .pfn            = __phys_to_pfn(STMP3XXX_OCRAM_PHBASE),
+               .length         = STMP3XXX_OCRAM_SIZE,
+               .type           = MT_DEVICE,
+       },
+};
+
+void __init stmp37xx_map_io(void)
+{
+       iotable_init(stmp37xx_io_desc, ARRAY_SIZE(stmp37xx_io_desc));
+}
diff --git a/arch/arm/mach-stmp37xx/stmp37xx.h b/arch/arm/mach-stmp37xx/stmp37xx.h
new file mode 100644 (file)
index 0000000..0b75fb7
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Freescale STMP37XX/STMP378X internal functions and data declarations
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __MACH_STMP37XX_H
+#define __MACH_STMP37XX_H
+
+void stmp37xx_map_io(void);
+void stmp37xx_init_irq(void);
+
+#endif /* __MACH_STMP37XX_H */
diff --git a/arch/arm/mach-stmp37xx/stmp37xx_devb.c b/arch/arm/mach-stmp37xx/stmp37xx_devb.c
new file mode 100644 (file)
index 0000000..394f21a
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Freescale STMP37XX development board support
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/stmp3xxx.h>
+#include <mach/pins.h>
+#include <mach/pinmux.h>
+#include "stmp37xx.h"
+
+/*
+ * List of STMP37xx development board specific devices
+ */
+static struct platform_device *stmp37xx_devb_devices[] = {
+       &stmp3xxx_dbguart,
+       &stmp3xxx_appuart,
+};
+
+static struct pin_desc dbguart_pins_0[] = {
+       { PINID_PWM0, PIN_FUN3, },
+       { PINID_PWM1, PIN_FUN3, },
+};
+
+struct pin_desc appuart_pins_0[] = {
+       { PINID_UART2_CTS, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
+       { PINID_UART2_RTS, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
+       { PINID_UART2_RX, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
+       { PINID_UART2_TX, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
+};
+
+static struct pin_group appuart_pins[] = {
+       [0] = {
+               .pins           = appuart_pins_0,
+               .nr_pins        = ARRAY_SIZE(appuart_pins_0),
+       },
+       /* 37xx has the only app uart */
+};
+
+static struct pin_group dbguart_pins[] = {
+       [0] = {
+               .pins           = dbguart_pins_0,
+               .nr_pins        = ARRAY_SIZE(dbguart_pins_0),
+       },
+};
+
+static int dbguart_pins_control(int id, int request)
+{
+       int r = 0;
+
+       if (request)
+               r = stmp3xxx_request_pin_group(&dbguart_pins[id], "debug uart");
+       else
+               stmp3xxx_release_pin_group(&dbguart_pins[id], "debug uart");
+       return r;
+}
+
+
+static void __init stmp37xx_devb_init(void)
+{
+       stmp3xxx_pinmux_init(NR_REAL_IRQS);
+
+       /* Init STMP3xxx platform */
+       stmp3xxx_init();
+
+       stmp3xxx_dbguart.dev.platform_data = dbguart_pins_control;
+       stmp3xxx_appuart.dev.platform_data = appuart_pins;
+
+       /* Add STMP37xx development board devices */
+       platform_add_devices(stmp37xx_devb_devices,
+                       ARRAY_SIZE(stmp37xx_devb_devices));
+}
+
+MACHINE_START(STMP37XX, "STMP37XX")
+       .phys_io        = 0x80000000,
+       .io_pg_offst    = ((0xf0000000) >> 18) & 0xfffc,
+       .boot_params    = 0x40000100,
+       .map_io         = stmp37xx_map_io,
+       .init_irq       = stmp37xx_init_irq,
+       .timer          = &stmp3xxx_timer,
+       .init_machine   = stmp37xx_devb_init,
+MACHINE_END
diff --git a/arch/arm/mach-u300/Kconfig b/arch/arm/mach-u300/Kconfig
new file mode 100644 (file)
index 0000000..337b9aa
--- /dev/null
@@ -0,0 +1,105 @@
+if ARCH_U300
+
+menu "ST-Ericsson AB U300/U330/U335/U365 Platform"
+
+comment "ST-Ericsson Mobile Platform Products"
+
+config MACH_U300
+       bool "U300"
+
+comment "ST-Ericsson U300/U330/U335/U365 Feature Selections"
+
+choice
+       prompt "U300/U330/U335/U365 system type"
+       default MACH_U300_BS2X
+       ---help---
+       You need to select the target system, i.e. the
+       U300/U330/U335/U365 board that you want to compile your kernel
+       for.
+
+config MACH_U300_BS2X
+       bool "S26/S26/B25/B26 Test Products"
+       depends on MACH_U300
+       help
+               Select this if you're developing on the
+               S26/S25 test products. (Also works on
+               B26/B25 big boards.)
+
+config MACH_U300_BS330
+       bool "S330/B330 Test Products"
+       depends on MACH_U300
+       help
+               Select this if you're developing on the
+               S330/B330 test products.
+
+config MACH_U300_BS335
+       bool "S335/B335 Test Products"
+       depends on MACH_U300
+       help
+               Select this if you're developing on the
+               S335/B335 test products.
+
+config MACH_U300_BS365
+       bool "S365/B365 Test Products"
+       depends on MACH_U300
+       help
+               Select this if you're developing on the
+               S365/B365 test products.
+
+endchoice
+
+choice
+       prompt "Memory configuration"
+       default MACH_U300_SINGLE_RAM
+       ---help---
+       You have to config the kernel according to the physical memory
+       configuration.
+
+config MACH_U300_SINGLE_RAM
+       bool "Single RAM"
+       help
+               Select this if you want support for Single RAM phones.
+
+config MACH_U300_DUAL_RAM
+       bool "Dual RAM"
+       help
+               Select this if you want support for Dual RAM phones.
+               This is two RAM memorys on different EMIFs.
+endchoice
+
+config U300_DEBUG
+       bool "Debug support for U300"
+       depends on PM
+       help
+               Debug support for U300 in sysfs, procfs etc.
+
+config MACH_U300_SEMI_IS_SHARED
+       bool "The SEMI is used by both the access and application side"
+       depends on MACH_U300
+       help
+               This makes it possible to use the SEMI (Shared External
+               Memory Interface) from both from access and application
+               side.
+
+comment "All the settings below must match the bootloader's settings"
+
+config MACH_U300_ACCESS_MEM_SIZE
+       int "Access CPU memory allocation"
+       range 7 25
+       depends on MACH_U300_SINGLE_RAM
+       default 13
+       help
+               How much memory in MiB that the Access side CPU has allocated
+
+config MACH_U300_2MB_ALIGNMENT_FIX
+       bool "2MiB alignment fix"
+       depends on MACH_U300_SINGLE_RAM
+       default y
+       help
+               If yes and the Access side CPU has allocated an odd size in
+               MiB, this fix gives you one MiB extra that would otherwise be
+               lost due to Linux 2 MiB alignment policy.
+
+endmenu
+
+endif
diff --git a/arch/arm/mach-u300/Makefile b/arch/arm/mach-u300/Makefile
new file mode 100644 (file)
index 0000000..24950e0
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# Makefile for the linux kernel, U300 machine.
+#
+
+obj-y          := core.o clock.o timer.o gpio.o padmux.o
+obj-m          :=
+obj-n          :=
+obj-           :=
+
+obj-$(CONFIG_ARCH_U300)                  += u300.o
+obj-$(CONFIG_MMC)                 += mmc.o
diff --git a/arch/arm/mach-u300/Makefile.boot b/arch/arm/mach-u300/Makefile.boot
new file mode 100644 (file)
index 0000000..6fbfc6e
--- /dev/null
@@ -0,0 +1,15 @@
+# Note: the following conditions must always be true:
+#   ZRELADDR == virt_to_phys(TEXTADDR)
+#   PARAMS_PHYS must be within 4MB of ZRELADDR
+#   INITRD_PHYS must be in RAM
+
+ifdef CONFIG_MACH_U300_SINGLE_RAM
+     zreladdr-y        := 0x28E08000
+  params_phys-y        := 0x28E00100
+else
+     zreladdr-y        := 0x48008000
+  params_phys-y        := 0x48000100
+endif
+
+# This isn't used.
+#initrd_phys-y := 0x29800000
diff --git a/arch/arm/mach-u300/clock.c b/arch/arm/mach-u300/clock.c
new file mode 100644 (file)
index 0000000..5cd04d6
--- /dev/null
@@ -0,0 +1,1487 @@
+/*
+ *
+ * arch/arm/mach-u300/clock.c
+ *
+ *
+ * Copyright (C) 2007-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Define clocks in the app platform.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/io.h>
+
+#include <asm/clkdev.h>
+#include <mach/hardware.h>
+#include <mach/syscon.h>
+
+#include "clock.h"
+
+/*
+ * TODO:
+ * - move all handling of the CCR register into this file and create
+ *   a spinlock for the CCR register
+ * - switch to the clkdevice lookup mechanism that maps clocks to
+ *   device ID:s instead when it becomes available in kernel 2.6.29.
+ * - implement rate get/set for all clocks that need it.
+ */
+
+/*
+ * Syscon clock I/O registers lock so clock requests don't collide
+ * NOTE: this is a local lock only used to lock access to clock and
+ * reset registers in syscon.
+ */
+static DEFINE_SPINLOCK(syscon_clkreg_lock);
+static DEFINE_SPINLOCK(syscon_resetreg_lock);
+
+/*
+ * The clocking hierarchy currently looks like this.
+ * NOTE: the idea is NOT to show how the clocks are routed on the chip!
+ * The ideas is to show dependencies, so a clock higher up in the
+ * hierarchy has to be on in order for another clock to be on. Now,
+ * both CPU and DMA can actually be on top of the hierarchy, and that
+ * is not modeled currently. Instead we have the backbone AMBA bus on
+ * top. This bus cannot be programmed in any way but conceptually it
+ * needs to be active for the bridges and devices to transport data.
+ *
+ * Please be aware that a few clocks are hw controlled, which mean that
+ * the hw itself can turn on/off or change the rate of the clock when
+ * needed!
+ *
+ *  AMBA bus
+ *  |
+ *  +- CPU
+ *  +- NANDIF NAND Flash interface
+ *  +- SEMI Shared Memory interface
+ *  +- ISP Image Signal Processor (U335 only)
+ *  +- CDS (U335 only)
+ *  +- DMA Direct Memory Access Controller
+ *  +- AAIF APP/ACC Inteface (Mobile Scalable Link, MSL)
+ *  +- APEX
+ *  +- VIDEO_ENC AVE2/3 Video Encoder
+ *  +- XGAM Graphics Accelerator Controller
+ *  +- AHB
+ *  |
+ *  +- ahb:0 AHB Bridge
+ *  |  |
+ *  |  +- ahb:1 INTCON Interrupt controller
+ *  |  +- ahb:3 MSPRO  Memory Stick Pro controller
+ *  |  +- ahb:4 EMIF   External Memory interface
+ *  |
+ *  +- fast:0 FAST bridge
+ *  |  |
+ *  |  +- fast:1 MMCSD MMC/SD card reader controller
+ *  |  +- fast:2 I2S0  PCM I2S channel 0 controller
+ *  |  +- fast:3 I2S1  PCM I2S channel 1 controller
+ *  |  +- fast:4 I2C0  I2C channel 0 controller
+ *  |  +- fast:5 I2C1  I2C channel 1 controller
+ *  |  +- fast:6 SPI   SPI controller
+ *  |  +- fast:7 UART1 Secondary UART (U335 only)
+ *  |
+ *  +- slow:0 SLOW bridge
+ *     |
+ *     +- slow:1 SYSCON (not possible to control)
+ *     +- slow:2 WDOG Watchdog
+ *     +- slow:3 UART0 primary UART
+ *     +- slow:4 TIMER_APP Application timer - used in Linux
+ *     +- slow:5 KEYPAD controller
+ *     +- slow:6 GPIO controller
+ *     +- slow:7 RTC controller
+ *     +- slow:8 BT Bus Tracer (not used currently)
+ *     +- slow:9 EH Event Handler (not used currently)
+ *     +- slow:a TIMER_ACC Access style timer (not used currently)
+ *     +- slow:b PPM (U335 only, what is that?)
+ */
+
+/*
+ * Reset control functions. We remember if a block has been
+ * taken out of reset and don't remove the reset assertion again
+ * and vice versa. Currently we only remove resets so the
+ * enablement function is defined out.
+ */
+static void syscon_block_reset_enable(struct clk *clk)
+{
+       u16 val;
+       unsigned long iflags;
+
+       /* Not all blocks support resetting */
+       if (!clk->res_reg || !clk->res_mask)
+               return;
+       spin_lock_irqsave(&syscon_resetreg_lock, iflags);
+       val = readw(clk->res_reg);
+       val |= clk->res_mask;
+       writew(val, clk->res_reg);
+       spin_unlock_irqrestore(&syscon_resetreg_lock, iflags);
+       clk->reset = true;
+}
+
+static void syscon_block_reset_disable(struct clk *clk)
+{
+       u16 val;
+       unsigned long iflags;
+
+       /* Not all blocks support resetting */
+       if (!clk->res_reg || !clk->res_mask)
+               return;
+       spin_lock_irqsave(&syscon_resetreg_lock, iflags);
+       val = readw(clk->res_reg);
+       val &= ~clk->res_mask;
+       writew(val, clk->res_reg);
+       spin_unlock_irqrestore(&syscon_resetreg_lock, iflags);
+       clk->reset = false;
+}
+
+int __clk_get(struct clk *clk)
+{
+       u16 val;
+
+       /* The MMC and MSPRO clocks need some special set-up */
+       if (!strcmp(clk->name, "MCLK")) {
+               /* Set default MMC clock divisor to 18.9 MHz */
+               writew(0x0054U, U300_SYSCON_VBASE + U300_SYSCON_MMF0R);
+               val = readw(U300_SYSCON_VBASE + U300_SYSCON_MMCR);
+               /* Disable the MMC feedback clock */
+               val &= ~U300_SYSCON_MMCR_MMC_FB_CLK_SEL_ENABLE;
+               /* Disable MSPRO frequency */
+               val &= ~U300_SYSCON_MMCR_MSPRO_FREQSEL_ENABLE;
+               writew(val, U300_SYSCON_VBASE + U300_SYSCON_MMCR);
+       }
+       if (!strcmp(clk->name, "MSPRO")) {
+               val = readw(U300_SYSCON_VBASE + U300_SYSCON_MMCR);
+               /* Disable the MMC feedback clock */
+               val &= ~U300_SYSCON_MMCR_MMC_FB_CLK_SEL_ENABLE;
+               /* Enable MSPRO frequency */
+               val |= U300_SYSCON_MMCR_MSPRO_FREQSEL_ENABLE;
+               writew(val, U300_SYSCON_VBASE + U300_SYSCON_MMCR);
+       }
+       return 1;
+}
+EXPORT_SYMBOL(__clk_get);
+
+void __clk_put(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(__clk_put);
+
+static void syscon_clk_disable(struct clk *clk)
+{
+       unsigned long iflags;
+
+       /* Don't touch the hardware controlled clocks */
+       if (clk->hw_ctrld)
+               return;
+
+       spin_lock_irqsave(&syscon_clkreg_lock, iflags);
+       writew(clk->clk_val, U300_SYSCON_VBASE + U300_SYSCON_SBCDR);
+       spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
+}
+
+static void syscon_clk_enable(struct clk *clk)
+{
+       unsigned long iflags;
+
+       /* Don't touch the hardware controlled clocks */
+       if (clk->hw_ctrld)
+               return;
+
+       spin_lock_irqsave(&syscon_clkreg_lock, iflags);
+       writew(clk->clk_val, U300_SYSCON_VBASE + U300_SYSCON_SBCER);
+       spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
+}
+
+static u16 syscon_clk_get_rate(void)
+{
+       u16 val;
+       unsigned long iflags;
+
+       spin_lock_irqsave(&syscon_clkreg_lock, iflags);
+       val = readw(U300_SYSCON_VBASE + U300_SYSCON_CCR);
+       val &= U300_SYSCON_CCR_CLKING_PERFORMANCE_MASK;
+       spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
+       return val;
+}
+
+#ifdef CONFIG_MACH_U300_USE_I2S_AS_MASTER
+static void enable_i2s0_vcxo(void)
+{
+       u16 val;
+       unsigned long iflags;
+
+       spin_lock_irqsave(&syscon_clkreg_lock, iflags);
+       /* Set I2S0 to use the VCXO 26 MHz clock */
+       val = readw(U300_SYSCON_VBASE + U300_SYSCON_CCR);
+       val |= U300_SYSCON_CCR_TURN_VCXO_ON;
+       writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
+       val |= U300_SYSCON_CCR_I2S0_USE_VCXO;
+       writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
+       val = readw(U300_SYSCON_VBASE + U300_SYSCON_CEFR);
+       val |= U300_SYSCON_CEFR_I2S0_CLK_EN;
+       writew(val, U300_SYSCON_VBASE + U300_SYSCON_CEFR);
+       spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
+}
+
+static void enable_i2s1_vcxo(void)
+{
+       u16 val;
+       unsigned long iflags;
+
+       spin_lock_irqsave(&syscon_clkreg_lock, iflags);
+       /* Set I2S1 to use the VCXO 26 MHz clock */
+       val = readw(U300_SYSCON_VBASE + U300_SYSCON_CCR);
+       val |= U300_SYSCON_CCR_TURN_VCXO_ON;
+       writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
+       val |= U300_SYSCON_CCR_I2S1_USE_VCXO;
+       writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
+       val = readw(U300_SYSCON_VBASE + U300_SYSCON_CEFR);
+       val |= U300_SYSCON_CEFR_I2S1_CLK_EN;
+       writew(val, U300_SYSCON_VBASE + U300_SYSCON_CEFR);
+       spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
+}
+
+static void disable_i2s0_vcxo(void)
+{
+       u16 val;
+       unsigned long iflags;
+
+       spin_lock_irqsave(&syscon_clkreg_lock, iflags);
+       /* Disable I2S0 use of the VCXO 26 MHz clock */
+       val = readw(U300_SYSCON_VBASE + U300_SYSCON_CCR);
+       val &= ~U300_SYSCON_CCR_I2S0_USE_VCXO;
+       writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
+       /* Deactivate VCXO if noone else is using VCXO */
+       if (!(val & U300_SYSCON_CCR_I2S1_USE_VCXO))
+               val &= ~U300_SYSCON_CCR_TURN_VCXO_ON;
+       writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
+       val = readw(U300_SYSCON_VBASE + U300_SYSCON_CEFR);
+       val &= ~U300_SYSCON_CEFR_I2S0_CLK_EN;
+       writew(val, U300_SYSCON_VBASE + U300_SYSCON_CEFR);
+       spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
+}
+
+static void disable_i2s1_vcxo(void)
+{
+       u16 val;
+       unsigned long iflags;
+
+       spin_lock_irqsave(&syscon_clkreg_lock, iflags);
+       /* Disable I2S1 use of the VCXO 26 MHz clock */
+       val = readw(U300_SYSCON_VBASE + U300_SYSCON_CCR);
+       val &= ~U300_SYSCON_CCR_I2S1_USE_VCXO;
+       writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
+       /* Deactivate VCXO if noone else is using VCXO */
+       if (!(val & U300_SYSCON_CCR_I2S0_USE_VCXO))
+               val &= ~U300_SYSCON_CCR_TURN_VCXO_ON;
+       writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
+       val = readw(U300_SYSCON_VBASE + U300_SYSCON_CEFR);
+       val &= ~U300_SYSCON_CEFR_I2S0_CLK_EN;
+       writew(val, U300_SYSCON_VBASE + U300_SYSCON_CEFR);
+       spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
+}
+#endif /* CONFIG_MACH_U300_USE_I2S_AS_MASTER */
+
+
+static void syscon_clk_rate_set_mclk(unsigned long rate)
+{
+       u16 val;
+       u32 reg;
+       unsigned long iflags;
+
+       switch (rate) {
+       case 18900000:
+               val = 0x0054;
+               break;
+       case 20800000:
+               val = 0x0044;
+               break;
+       case 23100000:
+               val = 0x0043;
+               break;
+       case 26000000:
+               val = 0x0033;
+               break;
+       case 29700000:
+               val = 0x0032;
+               break;
+       case 34700000:
+               val = 0x0022;
+               break;
+       case 41600000:
+               val = 0x0021;
+               break;
+       case 52000000:
+               val = 0x0011;
+               break;
+       case 104000000:
+               val = 0x0000;
+               break;
+       default:
+               printk(KERN_ERR "Trying to set MCLK to unknown speed! %ld\n",
+                      rate);
+               return;
+       }
+
+       spin_lock_irqsave(&syscon_clkreg_lock, iflags);
+       reg = readw(U300_SYSCON_VBASE + U300_SYSCON_MMF0R) &
+               ~U300_SYSCON_MMF0R_MASK;
+       writew(reg | val, U300_SYSCON_VBASE + U300_SYSCON_MMF0R);
+       spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
+}
+
+void syscon_clk_rate_set_cpuclk(unsigned long rate)
+{
+       u16 val;
+       unsigned long iflags;
+
+       switch (rate) {
+       case 13000000:
+               val = U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER;
+               break;
+       case 52000000:
+               val = U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE;
+               break;
+       case 104000000:
+               val = U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH;
+               break;
+       case 208000000:
+               val = U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST;
+               break;
+       default:
+               return;
+       }
+       spin_lock_irqsave(&syscon_clkreg_lock, iflags);
+       val |= readw(U300_SYSCON_VBASE + U300_SYSCON_CCR) &
+               ~U300_SYSCON_CCR_CLKING_PERFORMANCE_MASK ;
+       writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
+       spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
+}
+EXPORT_SYMBOL(syscon_clk_rate_set_cpuclk);
+
+void clk_disable(struct clk *clk)
+{
+       unsigned long iflags;
+
+       spin_lock_irqsave(&clk->lock, iflags);
+       if (clk->usecount > 0 && !(--clk->usecount)) {
+               /* some blocks lack clocking registers and cannot be disabled */
+               if (clk->disable)
+                       clk->disable(clk);
+               if (likely((u32)clk->parent))
+                       clk_disable(clk->parent);
+       }
+#ifdef CONFIG_MACH_U300_USE_I2S_AS_MASTER
+       if (unlikely(!strcmp(clk->name, "I2S0")))
+               disable_i2s0_vcxo();
+       if (unlikely(!strcmp(clk->name, "I2S1")))
+               disable_i2s1_vcxo();
+#endif
+       spin_unlock_irqrestore(&clk->lock, iflags);
+}
+EXPORT_SYMBOL(clk_disable);
+
+int clk_enable(struct clk *clk)
+{
+       int ret = 0;
+       unsigned long iflags;
+
+       spin_lock_irqsave(&clk->lock, iflags);
+       if (clk->usecount++ == 0) {
+               if (likely((u32)clk->parent))
+                       ret = clk_enable(clk->parent);
+
+               if (unlikely(ret != 0))
+                       clk->usecount--;
+               else {
+                       /* remove reset line (we never enable reset again) */
+                       syscon_block_reset_disable(clk);
+                       /* clocks without enable function are always on */
+                       if (clk->enable)
+                               clk->enable(clk);
+#ifdef CONFIG_MACH_U300_USE_I2S_AS_MASTER
+                       if (unlikely(!strcmp(clk->name, "I2S0")))
+                               enable_i2s0_vcxo();
+                       if (unlikely(!strcmp(clk->name, "I2S1")))
+                               enable_i2s1_vcxo();
+#endif
+               }
+       }
+       spin_unlock_irqrestore(&clk->lock, iflags);
+       return ret;
+
+}
+EXPORT_SYMBOL(clk_enable);
+
+/* Returns the clock rate in Hz */
+static unsigned long clk_get_rate_cpuclk(struct clk *clk)
+{
+       u16 val;
+
+       val = syscon_clk_get_rate();
+
+       switch (val) {
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER:
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW:
+               return 13000000;
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE:
+               return 52000000;
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH:
+               return 104000000;
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST:
+               return 208000000;
+       default:
+               break;
+       }
+       return clk->rate;
+}
+
+static unsigned long clk_get_rate_ahb_clk(struct clk *clk)
+{
+       u16 val;
+
+       val = syscon_clk_get_rate();
+
+       switch (val) {
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER:
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW:
+               return 6500000;
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE:
+               return 26000000;
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH:
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST:
+               return 52000000;
+       default:
+               break;
+       }
+       return clk->rate;
+
+}
+
+static unsigned long clk_get_rate_emif_clk(struct clk *clk)
+{
+       u16 val;
+
+       val = syscon_clk_get_rate();
+
+       switch (val) {
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER:
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW:
+               return 13000000;
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE:
+               return 52000000;
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH:
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST:
+               return 104000000;
+       default:
+               break;
+       }
+       return clk->rate;
+
+}
+
+static unsigned long clk_get_rate_xgamclk(struct clk *clk)
+{
+       u16 val;
+
+       val = syscon_clk_get_rate();
+
+       switch (val) {
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER:
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW:
+               return 6500000;
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE:
+               return 26000000;
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH:
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST:
+               return 52000000;
+       default:
+               break;
+       }
+
+       return clk->rate;
+}
+
+static unsigned long clk_get_rate_mclk(struct clk *clk)
+{
+       u16 val;
+
+       val = syscon_clk_get_rate();
+
+       switch (val) {
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER:
+               /*
+                * Here, the 208 MHz PLL gets shut down and the always
+                * on 13 MHz PLL used for RTC etc kicks into use
+                * instead.
+                */
+               return 13000000;
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW:
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE:
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH:
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST:
+       {
+               /*
+                * This clock is under program control. The register is
+                * divided in two nybbles, bit 7-4 gives cycles-1 to count
+                * high, bit 3-0 gives cycles-1 to count low. Distribute
+                * these with no more than 1 cycle difference between
+                * low and high and add low and high to get the actual
+                * divisor. The base PLL is 208 MHz. Writing 0x00 will
+                * divide by 1 and 1 so the highest frequency possible
+                * is 104 MHz.
+                *
+                * e.g. 0x54 =>
+                * f = 208 / ((5+1) + (4+1)) = 208 / 11 = 18.9 MHz
+                */
+               u16 val = readw(U300_SYSCON_VBASE + U300_SYSCON_MMF0R) &
+                       U300_SYSCON_MMF0R_MASK;
+               switch (val) {
+               case 0x0054:
+                       return 18900000;
+               case 0x0044:
+                       return 20800000;
+               case 0x0043:
+                       return 23100000;
+               case 0x0033:
+                       return 26000000;
+               case 0x0032:
+                       return 29700000;
+               case 0x0022:
+                       return 34700000;
+               case 0x0021:
+                       return 41600000;
+               case 0x0011:
+                       return 52000000;
+               case 0x0000:
+                       return 104000000;
+               default:
+                       break;
+               }
+       }
+       default:
+               break;
+       }
+
+       return clk->rate;
+}
+
+static unsigned long clk_get_rate_i2s_i2c_spi(struct clk *clk)
+{
+       u16 val;
+
+       val = syscon_clk_get_rate();
+
+       switch (val) {
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER:
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW:
+               return 13000000;
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE:
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH:
+       case U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST:
+               return 26000000;
+       default:
+               break;
+       }
+
+       return clk->rate;
+}
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+       if (clk->get_rate)
+               return clk->get_rate(clk);
+       else
+               return clk->rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+static unsigned long clk_round_rate_mclk(struct clk *clk, unsigned long rate)
+{
+       if (rate >= 18900000)
+               return 18900000;
+       if (rate >= 20800000)
+               return 20800000;
+       if (rate >= 23100000)
+               return 23100000;
+       if (rate >= 26000000)
+               return 26000000;
+       if (rate >= 29700000)
+               return 29700000;
+       if (rate >= 34700000)
+               return 34700000;
+       if (rate >= 41600000)
+               return 41600000;
+       if (rate >= 52000000)
+               return 52000000;
+       return -EINVAL;
+}
+
+static unsigned long clk_round_rate_cpuclk(struct clk *clk, unsigned long rate)
+{
+       if (rate >= 13000000)
+               return 13000000;
+       if (rate >= 52000000)
+               return 52000000;
+       if (rate >= 104000000)
+               return 104000000;
+       if (rate >= 208000000)
+               return 208000000;
+       return -EINVAL;
+}
+
+/*
+ * This adjusts a requested rate to the closest exact rate
+ * a certain clock can provide. For a fixed clock it's
+ * mostly clk->rate.
+ */
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+       /* TODO: get apropriate switches for EMIFCLK, AHBCLK and MCLK */
+       /* Else default to fixed value */
+
+       if (clk->round_rate) {
+               return (long) clk->round_rate(clk, rate);
+       } else {
+               printk(KERN_ERR "clock: Failed to round rate of %s\n",
+                      clk->name);
+       }
+       return (long) clk->rate;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+static int clk_set_rate_mclk(struct clk *clk, unsigned long rate)
+{
+       syscon_clk_rate_set_mclk(clk_round_rate(clk, rate));
+       return 0;
+}
+
+static int clk_set_rate_cpuclk(struct clk *clk, unsigned long rate)
+{
+       syscon_clk_rate_set_cpuclk(clk_round_rate(clk, rate));
+       return 0;
+}
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       /* TODO: set for EMIFCLK and AHBCLK */
+       /* Else assume the clock is fixed and fail */
+       if (clk->set_rate) {
+               return clk->set_rate(clk, rate);
+       } else {
+               printk(KERN_ERR "clock: Failed to set %s to %ld hz\n",
+                      clk->name, rate);
+               return -EINVAL;
+       }
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+/*
+ * Clock definitions. The clock parents are set to respective
+ * bridge and the clock framework makes sure that the clocks have
+ * parents activated and are brought out of reset when in use.
+ *
+ * Clocks that have hw_ctrld = true are hw controlled, and the hw
+ * can by itself turn these clocks on and off.
+ * So in other words, we don't really have to care about them.
+ */
+
+static struct clk amba_clk = {
+       .name       = "AMBA",
+       .rate       = 52000000, /* this varies! */
+       .hw_ctrld   = true,
+       .reset      = false,
+};
+
+/*
+ * These blocks are connected directly to the AMBA bus
+ * with no bridge.
+ */
+
+static struct clk cpu_clk = {
+       .name       = "CPU",
+       .parent     = &amba_clk,
+       .rate       = 208000000, /* this varies! */
+       .hw_ctrld   = true,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
+       .res_mask   = U300_SYSCON_RRR_CPU_RESET_EN,
+       .set_rate   = clk_set_rate_cpuclk,
+       .get_rate   = clk_get_rate_cpuclk,
+       .round_rate = clk_round_rate_cpuclk,
+};
+
+static struct clk nandif_clk = {
+       .name       = "NANDIF",
+       .parent     = &amba_clk,
+       .hw_ctrld   = false,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
+       .res_mask   = U300_SYSCON_RRR_NANDIF_RESET_EN,
+       .clk_val    = U300_SYSCON_SBCER_NANDIF_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+};
+
+static struct clk semi_clk = {
+       .name       = "SEMI",
+       .parent     = &amba_clk,
+       .rate       = 0, /* FIXME */
+       /* It is not possible to reset SEMI */
+       .hw_ctrld   = false,
+       .reset      = false,
+       .clk_val    = U300_SYSCON_SBCER_SEMI_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+};
+
+#ifdef CONFIG_MACH_U300_BS335
+static struct clk isp_clk = {
+       .name       = "ISP",
+       .parent     = &amba_clk,
+       .rate       = 0, /* FIXME */
+       .hw_ctrld   = false,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
+       .res_mask   = U300_SYSCON_RRR_ISP_RESET_EN,
+       .clk_val    = U300_SYSCON_SBCER_ISP_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+};
+
+static struct clk cds_clk = {
+       .name       = "CDS",
+       .parent     = &amba_clk,
+       .rate       = 0, /* FIXME */
+       .hw_ctrld   = false,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
+       .res_mask   = U300_SYSCON_RRR_CDS_RESET_EN,
+       .clk_val    = U300_SYSCON_SBCER_CDS_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+};
+#endif
+
+static struct clk dma_clk = {
+       .name       = "DMA",
+       .parent     = &amba_clk,
+       .rate       = 52000000, /* this varies! */
+       .hw_ctrld   = true,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
+       .res_mask   = U300_SYSCON_RRR_DMAC_RESET_EN,
+       .clk_val    = U300_SYSCON_SBCER_DMAC_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+};
+
+static struct clk aaif_clk = {
+       .name       = "AAIF",
+       .parent     = &amba_clk,
+       .rate       = 52000000, /* this varies! */
+       .hw_ctrld   = true,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
+       .res_mask   = U300_SYSCON_RRR_AAIF_RESET_EN,
+       .clk_val    = U300_SYSCON_SBCER_AAIF_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+};
+
+static struct clk apex_clk = {
+       .name       = "APEX",
+       .parent     = &amba_clk,
+       .rate       = 0, /* FIXME */
+       .hw_ctrld   = true,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
+       .res_mask   = U300_SYSCON_RRR_APEX_RESET_EN,
+       .clk_val    = U300_SYSCON_SBCER_APEX_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+};
+
+static struct clk video_enc_clk = {
+       .name       = "VIDEO_ENC",
+       .parent     = &amba_clk,
+       .rate       = 208000000, /* this varies! */
+       .hw_ctrld   = false,
+       .reset      = false,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
+       /* This has XGAM in the name but refers to the video encoder */
+       .res_mask   = U300_SYSCON_RRR_XGAM_VC_SYNC_RESET_EN,
+       .clk_val    = U300_SYSCON_SBCER_VIDEO_ENC_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+};
+
+static struct clk xgam_clk = {
+       .name       = "XGAMCLK",
+       .parent     = &amba_clk,
+       .rate       = 52000000, /* this varies! */
+       .hw_ctrld   = false,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
+       .res_mask   = U300_SYSCON_RRR_XGAM_RESET_EN,
+       .clk_val    = U300_SYSCON_SBCER_XGAM_CLK_EN,
+       .get_rate   = clk_get_rate_xgamclk,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+};
+
+/* This clock is used to activate the video encoder */
+static struct clk ahb_clk = {
+       .name       = "AHB",
+       .parent     = &amba_clk,
+       .rate       = 52000000, /* this varies! */
+       .hw_ctrld   = false, /* This one is set to false due to HW bug */
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
+       .res_mask   = U300_SYSCON_RRR_AHB_RESET_EN,
+       .clk_val    = U300_SYSCON_SBCER_AHB_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+       .get_rate   = clk_get_rate_ahb_clk,
+};
+
+
+/*
+ * Clocks on the AHB bridge
+ */
+
+static struct clk ahb_subsys_clk = {
+       .name       = "AHB_SUBSYS",
+       .parent     = &amba_clk,
+       .rate       = 52000000, /* this varies! */
+       .hw_ctrld   = true,
+       .reset      = false,
+       .clk_val    = U300_SYSCON_SBCER_AHB_SUBSYS_BRIDGE_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+       .get_rate   = clk_get_rate_ahb_clk,
+};
+
+static struct clk intcon_clk = {
+       .name       = "INTCON",
+       .parent     = &ahb_subsys_clk,
+       .rate       = 52000000, /* this varies! */
+       .hw_ctrld   = false,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
+       .res_mask   = U300_SYSCON_RRR_INTCON_RESET_EN,
+       /* INTCON can be reset but not clock-gated */
+};
+
+static struct clk mspro_clk = {
+       .name       = "MSPRO",
+       .parent     = &ahb_subsys_clk,
+       .rate       = 0, /* FIXME */
+       .hw_ctrld   = false,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
+       .res_mask   = U300_SYSCON_RRR_MSPRO_RESET_EN,
+       .clk_val    = U300_SYSCON_SBCER_MSPRO_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+};
+
+static struct clk emif_clk = {
+       .name       = "EMIF",
+       .parent     = &ahb_subsys_clk,
+       .rate       = 104000000, /* this varies! */
+       .hw_ctrld   = false,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RRR,
+       .res_mask   = U300_SYSCON_RRR_EMIF_RESET_EN,
+       .clk_val    = U300_SYSCON_SBCER_EMIF_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+       .get_rate   = clk_get_rate_emif_clk,
+};
+
+
+/*
+ * Clocks on the FAST bridge
+ */
+static struct clk fast_clk = {
+       .name       = "FAST_BRIDGE",
+       .parent     = &amba_clk,
+       .rate       = 13000000, /* this varies! */
+       .hw_ctrld   = true,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RFR,
+       .res_mask   = U300_SYSCON_RFR_FAST_BRIDGE_RESET_ENABLE,
+       .clk_val    = U300_SYSCON_SBCER_FAST_BRIDGE_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+};
+
+static struct clk mmcsd_clk = {
+       .name       = "MCLK",
+       .parent     = &fast_clk,
+       .rate       = 18900000, /* this varies! */
+       .hw_ctrld   = false,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RFR,
+       .res_mask   = U300_SYSCON_RFR_MMC_RESET_ENABLE,
+       .clk_val    = U300_SYSCON_SBCER_MMC_CLK_EN,
+       .get_rate   = clk_get_rate_mclk,
+       .set_rate   = clk_set_rate_mclk,
+       .round_rate = clk_round_rate_mclk,
+       .disable    = syscon_clk_disable,
+       .enable     = syscon_clk_enable,
+};
+
+static struct clk i2s0_clk = {
+       .name       = "i2s0",
+       .parent     = &fast_clk,
+       .rate       = 26000000, /* this varies! */
+       .hw_ctrld   = true,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RFR,
+       .res_mask   = U300_SYSCON_RFR_PCM_I2S0_RESET_ENABLE,
+       .clk_val    = U300_SYSCON_SBCER_I2S0_CORE_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+       .get_rate   = clk_get_rate_i2s_i2c_spi,
+};
+
+static struct clk i2s1_clk = {
+       .name       = "i2s1",
+       .parent     = &fast_clk,
+       .rate       = 26000000, /* this varies! */
+       .hw_ctrld   = true,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RFR,
+       .res_mask   = U300_SYSCON_RFR_PCM_I2S1_RESET_ENABLE,
+       .clk_val    = U300_SYSCON_SBCER_I2S1_CORE_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+       .get_rate   = clk_get_rate_i2s_i2c_spi,
+};
+
+static struct clk i2c0_clk = {
+       .name       = "I2C0",
+       .parent     = &fast_clk,
+       .rate       = 26000000, /* this varies! */
+       .hw_ctrld   = false,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RFR,
+       .res_mask   = U300_SYSCON_RFR_I2C0_RESET_ENABLE,
+       .clk_val    = U300_SYSCON_SBCER_I2C0_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+       .get_rate   = clk_get_rate_i2s_i2c_spi,
+};
+
+static struct clk i2c1_clk = {
+       .name       = "I2C1",
+       .parent     = &fast_clk,
+       .rate       = 26000000, /* this varies! */
+       .hw_ctrld   = false,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RFR,
+       .res_mask   = U300_SYSCON_RFR_I2C1_RESET_ENABLE,
+       .clk_val    = U300_SYSCON_SBCER_I2C1_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+       .get_rate   = clk_get_rate_i2s_i2c_spi,
+};
+
+static struct clk spi_clk = {
+       .name       = "SPI",
+       .parent     = &fast_clk,
+       .rate       = 26000000, /* this varies! */
+       .hw_ctrld   = false,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RFR,
+       .res_mask   = U300_SYSCON_RFR_SPI_RESET_ENABLE,
+       .clk_val    = U300_SYSCON_SBCER_SPI_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+       .get_rate   = clk_get_rate_i2s_i2c_spi,
+};
+
+#ifdef CONFIG_MACH_U300_BS335
+static struct clk uart1_clk = {
+       .name       = "UART1",
+       .parent     = &fast_clk,
+       .rate       = 13000000,
+       .hw_ctrld   = false,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RFR,
+       .res_mask   = U300_SYSCON_RFR_UART1_RESET_ENABLE,
+       .clk_val    = U300_SYSCON_SBCER_UART1_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+};
+#endif
+
+
+/*
+ * Clocks on the SLOW bridge
+ */
+static struct clk slow_clk = {
+       .name       = "SLOW_BRIDGE",
+       .parent     = &amba_clk,
+       .rate       = 13000000,
+       .hw_ctrld   = true,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RSR,
+       .res_mask   = U300_SYSCON_RSR_SLOW_BRIDGE_RESET_EN,
+       .clk_val    = U300_SYSCON_SBCER_SLOW_BRIDGE_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+};
+
+/* TODO: implement SYSCON clock? */
+
+static struct clk wdog_clk = {
+       .name       = "WDOG",
+       .parent     = &slow_clk,
+       .hw_ctrld   = false,
+       .rate       = 32768,
+       .reset      = false,
+       /* This is always on, cannot be enabled/disabled or reset */
+};
+
+/* This one is hardwired to PLL13 */
+static struct clk uart_clk = {
+       .name       = "UARTCLK",
+       .parent     = &slow_clk,
+       .rate       = 13000000,
+       .hw_ctrld   = false,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RSR,
+       .res_mask   = U300_SYSCON_RSR_UART_RESET_EN,
+       .clk_val    = U300_SYSCON_SBCER_UART_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+};
+
+static struct clk keypad_clk = {
+       .name       = "KEYPAD",
+       .parent     = &slow_clk,
+       .rate       = 32768,
+       .hw_ctrld   = false,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RSR,
+       .res_mask   = U300_SYSCON_RSR_KEYPAD_RESET_EN,
+       .clk_val    = U300_SYSCON_SBCER_KEYPAD_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+};
+
+static struct clk gpio_clk = {
+       .name       = "GPIO",
+       .parent     = &slow_clk,
+       .rate       = 13000000,
+       .hw_ctrld   = true,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RSR,
+       .res_mask   = U300_SYSCON_RSR_GPIO_RESET_EN,
+       .clk_val    = U300_SYSCON_SBCER_GPIO_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+};
+
+static struct clk rtc_clk = {
+       .name       = "RTC",
+       .parent     = &slow_clk,
+       .rate       = 32768,
+       .hw_ctrld   = true,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RSR,
+       .res_mask   = U300_SYSCON_RSR_RTC_RESET_EN,
+       /* This clock is always on, cannot be enabled/disabled */
+};
+
+static struct clk bustr_clk = {
+       .name       = "BUSTR",
+       .parent     = &slow_clk,
+       .rate       = 13000000,
+       .hw_ctrld   = true,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RSR,
+       .res_mask   = U300_SYSCON_RSR_BTR_RESET_EN,
+       .clk_val    = U300_SYSCON_SBCER_BTR_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+};
+
+static struct clk evhist_clk = {
+       .name       = "EVHIST",
+       .parent     = &slow_clk,
+       .rate       = 13000000,
+       .hw_ctrld   = true,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RSR,
+       .res_mask   = U300_SYSCON_RSR_EH_RESET_EN,
+       .clk_val    = U300_SYSCON_SBCER_EH_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+};
+
+static struct clk timer_clk = {
+       .name       = "TIMER",
+       .parent     = &slow_clk,
+       .rate       = 13000000,
+       .hw_ctrld   = true,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RSR,
+       .res_mask   = U300_SYSCON_RSR_ACC_TMR_RESET_EN,
+       .clk_val    = U300_SYSCON_SBCER_ACC_TMR_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+};
+
+static struct clk app_timer_clk = {
+       .name       = "TIMER_APP",
+       .parent     = &slow_clk,
+       .rate       = 13000000,
+       .hw_ctrld   = true,
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RSR,
+       .res_mask   = U300_SYSCON_RSR_APP_TMR_RESET_EN,
+       .clk_val    = U300_SYSCON_SBCER_APP_TMR_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+};
+
+#ifdef CONFIG_MACH_U300_BS335
+static struct clk ppm_clk = {
+       .name       = "PPM",
+       .parent     = &slow_clk,
+       .rate       = 0, /* FIXME */
+       .hw_ctrld   = true, /* TODO: Look up if it is hw ctrld or not */
+       .reset      = true,
+       .res_reg    = U300_SYSCON_VBASE + U300_SYSCON_RSR,
+       .res_mask   = U300_SYSCON_RSR_PPM_RESET_EN,
+       .clk_val    = U300_SYSCON_SBCER_PPM_CLK_EN,
+       .enable     = syscon_clk_enable,
+       .disable    = syscon_clk_disable,
+};
+#endif
+
+#define DEF_LOOKUP(devid, clkref)              \
+       {                                       \
+       .dev_id = devid,                        \
+       .clk = clkref,                          \
+       }
+
+/*
+ * Here we only define clocks that are meaningful to
+ * look up through clockdevice.
+ */
+static struct clk_lookup lookups[] = {
+       /* Connected directly to the AMBA bus */
+       DEF_LOOKUP("amba", &amba_clk),
+       DEF_LOOKUP("cpu", &cpu_clk),
+       DEF_LOOKUP("nandif", &nandif_clk),
+       DEF_LOOKUP("semi", &semi_clk),
+#ifdef CONFIG_MACH_U300_BS335
+       DEF_LOOKUP("isp", &isp_clk),
+       DEF_LOOKUP("cds", &cds_clk),
+#endif
+       DEF_LOOKUP("dma", &dma_clk),
+       DEF_LOOKUP("aaif", &aaif_clk),
+       DEF_LOOKUP("apex", &apex_clk),
+       DEF_LOOKUP("video_enc", &video_enc_clk),
+       DEF_LOOKUP("xgam", &xgam_clk),
+       DEF_LOOKUP("ahb", &ahb_clk),
+       /* AHB bridge clocks */
+       DEF_LOOKUP("ahb", &ahb_subsys_clk),
+       DEF_LOOKUP("intcon", &intcon_clk),
+       DEF_LOOKUP("mspro", &mspro_clk),
+       DEF_LOOKUP("pl172", &emif_clk),
+       /* FAST bridge clocks */
+       DEF_LOOKUP("fast", &fast_clk),
+       DEF_LOOKUP("mmci", &mmcsd_clk),
+       /*
+        * The .0 and .1 identifiers on these comes from the platform device
+        * .id field and are assigned when the platform devices are registered.
+        */
+       DEF_LOOKUP("i2s.0", &i2s0_clk),
+       DEF_LOOKUP("i2s.1", &i2s1_clk),
+       DEF_LOOKUP("stddci2c.0", &i2c0_clk),
+       DEF_LOOKUP("stddci2c.1", &i2c1_clk),
+       DEF_LOOKUP("pl022", &spi_clk),
+#ifdef CONFIG_MACH_U300_BS335
+       DEF_LOOKUP("uart1", &uart1_clk),
+#endif
+       /* SLOW bridge clocks */
+       DEF_LOOKUP("slow", &slow_clk),
+       DEF_LOOKUP("wdog", &wdog_clk),
+       DEF_LOOKUP("uart0", &uart_clk),
+       DEF_LOOKUP("apptimer", &app_timer_clk),
+       DEF_LOOKUP("keypad", &keypad_clk),
+       DEF_LOOKUP("u300-gpio", &gpio_clk),
+       DEF_LOOKUP("rtc0", &rtc_clk),
+       DEF_LOOKUP("bustr", &bustr_clk),
+       DEF_LOOKUP("evhist", &evhist_clk),
+       DEF_LOOKUP("timer", &timer_clk),
+#ifdef CONFIG_MACH_U300_BS335
+       DEF_LOOKUP("ppm", &ppm_clk),
+#endif
+};
+
+static void __init clk_register(void)
+{
+       int i;
+
+       /* Register the lookups */
+       for (i = 0; i < ARRAY_SIZE(lookups); i++)
+               clkdev_add(&lookups[i]);
+}
+
+/*
+ * These are the clocks for cells registered as primecell drivers
+ * on the AMBA bus. These must be on during AMBA device registration
+ * since the bus probe will attempt to read magic configuration
+ * registers for these devices. If they are deactivated these probes
+ * will fail.
+ *
+ *
+ * Please note that on emif, both RAM and NAND is connected in dual
+ * RAM phones. On single RAM phones, ram is on semi and NAND on emif.
+ *
+ */
+void u300_clock_primecells(void)
+{
+       clk_enable(&intcon_clk);
+       clk_enable(&uart_clk);
+#ifdef CONFIG_MACH_U300_BS335
+       clk_enable(&uart1_clk);
+#endif
+       clk_enable(&spi_clk);
+
+       clk_enable(&mmcsd_clk);
+
+}
+EXPORT_SYMBOL(u300_clock_primecells);
+
+void u300_unclock_primecells(void)
+{
+
+       clk_disable(&intcon_clk);
+       clk_disable(&uart_clk);
+#ifdef CONFIG_MACH_U300_BS335
+       clk_disable(&uart1_clk);
+#endif
+       clk_disable(&spi_clk);
+       clk_disable(&mmcsd_clk);
+
+}
+EXPORT_SYMBOL(u300_unclock_primecells);
+
+/*
+ * The interrupt controller is enabled before the clock API is registered.
+ */
+void u300_enable_intcon_clock(void)
+{
+       clk_enable(&intcon_clk);
+}
+EXPORT_SYMBOL(u300_enable_intcon_clock);
+
+/*
+ * The timer is enabled before the clock API is registered.
+ */
+void u300_enable_timer_clock(void)
+{
+       clk_enable(&app_timer_clk);
+}
+EXPORT_SYMBOL(u300_enable_timer_clock);
+
+#if (defined(CONFIG_DEBUG_FS) && defined(CONFIG_U300_DEBUG))
+/*
+ * The following makes it possible to view the status (especially
+ * reference count and reset status) for the clocks in the platform
+ * by looking into the special file <debugfs>/u300_clocks
+ */
+
+/* A list of all clocks in the platform */
+static struct clk *clks[] = {
+       /* Top node clock for the AMBA bus */
+       &amba_clk,
+       /* Connected directly to the AMBA bus */
+       &cpu_clk,
+       &nandif_clk,
+       &semi_clk,
+#ifdef CONFIG_MACH_U300_BS335
+       &isp_clk,
+       &cds_clk,
+#endif
+       &dma_clk,
+       &aaif_clk,
+       &apex_clk,
+       &video_enc_clk,
+       &xgam_clk,
+       &ahb_clk,
+
+       /* AHB bridge clocks */
+       &ahb_subsys_clk,
+       &intcon_clk,
+       &mspro_clk,
+       &emif_clk,
+       /* FAST bridge clocks */
+       &fast_clk,
+       &mmcsd_clk,
+       &i2s0_clk,
+       &i2s1_clk,
+       &i2c0_clk,
+       &i2c1_clk,
+       &spi_clk,
+#ifdef CONFIG_MACH_U300_BS335
+       &uart1_clk,
+#endif
+       /* SLOW bridge clocks */
+       &slow_clk,
+       &wdog_clk,
+       &uart_clk,
+       &app_timer_clk,
+       &keypad_clk,
+       &gpio_clk,
+       &rtc_clk,
+       &bustr_clk,
+       &evhist_clk,
+       &timer_clk,
+#ifdef CONFIG_MACH_U300_BS335
+       &ppm_clk,
+#endif
+};
+
+static int u300_clocks_show(struct seq_file *s, void *data)
+{
+       struct clk *clk;
+       int i;
+
+       seq_printf(s, "CLOCK           DEVICE          RESET STATE\t" \
+                  "ACTIVE\tUSERS\tHW CTRL FREQ\n");
+       seq_printf(s, "---------------------------------------------" \
+                  "-----------------------------------------\n");
+       for (i = 0; i < ARRAY_SIZE(clks); i++) {
+               clk = clks[i];
+               if (clk != ERR_PTR(-ENOENT)) {
+                       /* Format clock and device name nicely */
+                       char cdp[33];
+                       int chars;
+
+                       chars = snprintf(&cdp[0], 17, "%s", clk->name);
+                       while (chars < 16) {
+                               cdp[chars] = ' ';
+                               chars++;
+                       }
+                       chars = snprintf(&cdp[16], 17, "%s", clk->dev ?
+                                        dev_name(clk->dev) : "N/A");
+                       while (chars < 16) {
+                               cdp[chars+16] = ' ';
+                               chars++;
+                       }
+                       cdp[32] = '\0';
+                       if (clk->get_rate)
+                               seq_printf(s,
+                                          "%s%s\t%s\t%d\t%s\t%lu Hz\n",
+                                          &cdp[0],
+                                          clk->reset ?
+                                          "ASSERTED" : "RELEASED",
+                                          clk->usecount ? "ON" : "OFF",
+                                          clk->usecount,
+                                          clk->hw_ctrld  ? "YES" : "NO ",
+                                          clk->get_rate(clk));
+                       else
+                               seq_printf(s,
+                                          "%s%s\t%s\t%d\t%s\t" \
+                                          "(unknown rate)\n",
+                                          &cdp[0],
+                                          clk->reset ?
+                                          "ASSERTED" : "RELEASED",
+                                          clk->usecount ? "ON" : "OFF",
+                                          clk->usecount,
+                                          clk->hw_ctrld  ? "YES" : "NO ");
+               }
+       }
+       return 0;
+}
+
+static int u300_clocks_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, u300_clocks_show, NULL);
+}
+
+static const struct file_operations u300_clocks_operations = {
+       .open           = u300_clocks_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static void init_clk_read_procfs(void)
+{
+       /* Expose a simple debugfs interface to view all clocks */
+       (void) debugfs_create_file("u300_clocks", S_IFREG | S_IRUGO,
+                                  NULL, NULL, &u300_clocks_operations);
+}
+#else
+static inline void init_clk_read_procfs(void)
+{
+}
+#endif
+
+static int __init u300_clock_init(void)
+{
+       u16 val;
+
+       /*
+        * FIXME: shall all this powermanagement stuff really live here???
+        */
+
+       /* Set system to run at PLL208, max performance, a known state. */
+       val = readw(U300_SYSCON_VBASE + U300_SYSCON_CCR);
+       val &= ~U300_SYSCON_CCR_CLKING_PERFORMANCE_MASK;
+       writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
+       /* Wait for the PLL208 to lock if not locked in yet */
+       while (!(readw(U300_SYSCON_VBASE + U300_SYSCON_CSR) &
+                U300_SYSCON_CSR_PLL208_LOCK_IND));
+
+       /* Power management enable */
+       val = readw(U300_SYSCON_VBASE + U300_SYSCON_PMCR);
+       val |= U300_SYSCON_PMCR_PWR_MGNT_ENABLE;
+       writew(val, U300_SYSCON_VBASE + U300_SYSCON_PMCR);
+
+       clk_register();
+
+       init_clk_read_procfs();
+
+       /*
+        * Some of these may be on when we boot the system so make sure they
+        * are turned OFF.
+        */
+       syscon_block_reset_enable(&timer_clk);
+       timer_clk.disable(&timer_clk);
+
+       /*
+        * These shall be turned on by default when we boot the system
+        * so make sure they are ON. (Adding CPU here is a bit too much.)
+        * These clocks will be claimed by drivers later.
+        */
+       syscon_block_reset_disable(&semi_clk);
+       syscon_block_reset_disable(&emif_clk);
+       semi_clk.enable(&semi_clk);
+       emif_clk.enable(&emif_clk);
+
+       return 0;
+}
+/* initialize clocking early to be available later in the boot */
+core_initcall(u300_clock_init);
diff --git a/arch/arm/mach-u300/clock.h b/arch/arm/mach-u300/clock.h
new file mode 100644 (file)
index 0000000..fc6d9cc
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * arch/arm/mach-u300/include/mach/clock.h
+ *
+ * Copyright (C) 2004 - 2005 Nokia corporation
+ * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ * Based on clocks.h by Tony Lindgren, Gordon McNutt and RidgeRun, Inc
+ * Copyright (C) 2007-2009 ST-Ericsson AB
+ * Adopted to ST-Ericsson U300 platforms by
+ * Jonas Aaberg <jonas.aberg@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.
+ *
+ */
+
+#ifndef __MACH_CLOCK_H
+#define __MACH_CLOCK_H
+
+#include <linux/clk.h>
+
+struct clk {
+       struct list_head node;
+       struct module *owner;
+       struct device *dev;
+       const char *name;
+       struct clk *parent;
+
+       spinlock_t lock;
+       unsigned long rate;
+       bool reset;
+       __u16 clk_val;
+       __s8 usecount;
+       __u32 res_reg;
+       __u16 res_mask;
+
+       bool hw_ctrld;
+
+       void (*recalc) (struct clk *);
+       int (*set_rate) (struct clk *, unsigned long);
+       unsigned long (*get_rate) (struct clk *);
+       unsigned long (*round_rate) (struct clk *, unsigned long);
+       void (*init) (struct clk *);
+       void (*enable) (struct clk *);
+       void (*disable) (struct clk *);
+};
+
+void u300_clock_primecells(void);
+void u300_unclock_primecells(void);
+void u300_enable_intcon_clock(void);
+void u300_enable_timer_clock(void);
+
+#endif
diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c
new file mode 100644 (file)
index 0000000..89b3ccf
--- /dev/null
@@ -0,0 +1,649 @@
+/*
+ *
+ * arch/arm/mach-u300/core.c
+ *
+ *
+ * Copyright (C) 2007-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Core platform support, IRQ handling and device definitions.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/termios.h>
+#include <linux/amba/bus.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <asm/types.h>
+#include <asm/setup.h>
+#include <asm/memory.h>
+#include <asm/hardware/vic.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/syscon.h>
+
+#include "clock.h"
+#include "mmc.h"
+
+/*
+ * Static I/O mappings that are needed for booting the U300 platforms. The
+ * only things we need are the areas where we find the timer, syscon and
+ * intcon, since the remaining device drivers will map their own memory
+ * physical to virtual as the need arise.
+ */
+static struct map_desc u300_io_desc[] __initdata = {
+       {
+               .virtual        = U300_SLOW_PER_VIRT_BASE,
+               .pfn            = __phys_to_pfn(U300_SLOW_PER_PHYS_BASE),
+               .length         = SZ_64K,
+               .type           = MT_DEVICE,
+       },
+       {
+               .virtual        = U300_AHB_PER_VIRT_BASE,
+               .pfn            = __phys_to_pfn(U300_AHB_PER_PHYS_BASE),
+               .length         = SZ_32K,
+               .type           = MT_DEVICE,
+       },
+       {
+               .virtual        = U300_FAST_PER_VIRT_BASE,
+               .pfn            = __phys_to_pfn(U300_FAST_PER_PHYS_BASE),
+               .length         = SZ_32K,
+               .type           = MT_DEVICE,
+       },
+       {
+               .virtual        = 0xffff2000, /* TCM memory */
+               .pfn            = __phys_to_pfn(0xffff2000),
+               .length         = SZ_16K,
+               .type           = MT_DEVICE,
+       },
+
+       /*
+        * This overlaps with the IRQ vectors etc at 0xffff0000, so these
+        * may have to be moved to 0x00000000 in order to use the ROM.
+        */
+       /*
+       {
+               .virtual        = U300_BOOTROM_VIRT_BASE,
+               .pfn            = __phys_to_pfn(U300_BOOTROM_PHYS_BASE),
+               .length         = SZ_64K,
+               .type           = MT_ROM,
+       },
+       */
+};
+
+void __init u300_map_io(void)
+{
+       iotable_init(u300_io_desc, ARRAY_SIZE(u300_io_desc));
+}
+
+/*
+ * Declaration of devices found on the U300 board and
+ * their respective memory locations.
+ */
+static struct amba_device uart0_device = {
+       .dev = {
+               .init_name = "uart0", /* Slow device at 0x3000 offset */
+               .platform_data = NULL,
+       },
+       .res = {
+               .start = U300_UART0_BASE,
+               .end   = U300_UART0_BASE + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       .irq = { IRQ_U300_UART0, NO_IRQ },
+};
+
+/* The U335 have an additional UART1 on the APP CPU */
+#ifdef CONFIG_MACH_U300_BS335
+static struct amba_device uart1_device = {
+       .dev = {
+               .init_name = "uart1", /* Fast device at 0x7000 offset */
+               .platform_data = NULL,
+       },
+       .res = {
+               .start = U300_UART1_BASE,
+               .end   = U300_UART1_BASE + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       .irq = { IRQ_U300_UART1, NO_IRQ },
+};
+#endif
+
+static struct amba_device pl172_device = {
+       .dev = {
+               .init_name = "pl172", /* AHB device at 0x4000 offset */
+               .platform_data = NULL,
+       },
+       .res = {
+               .start = U300_EMIF_CFG_BASE,
+               .end   = U300_EMIF_CFG_BASE + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+};
+
+
+/*
+ * Everything within this next ifdef deals with external devices connected to
+ * the APP SPI bus.
+ */
+static struct amba_device pl022_device = {
+       .dev = {
+               .coherent_dma_mask = ~0,
+               .init_name = "pl022", /* Fast device at 0x6000 offset */
+       },
+       .res = {
+               .start = U300_SPI_BASE,
+               .end   = U300_SPI_BASE + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       .irq = {IRQ_U300_SPI, NO_IRQ },
+       /*
+        * This device has a DMA channel but the Linux driver does not use
+        * it currently.
+        */
+};
+
+static struct amba_device mmcsd_device = {
+       .dev = {
+               .init_name = "mmci", /* Fast device at 0x1000 offset */
+               .platform_data = NULL, /* Added later */
+       },
+       .res = {
+               .start = U300_MMCSD_BASE,
+               .end   = U300_MMCSD_BASE + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       .irq = {IRQ_U300_MMCSD_MCIINTR0, IRQ_U300_MMCSD_MCIINTR1 },
+       /*
+        * This device has a DMA channel but the Linux driver does not use
+        * it currently.
+        */
+};
+
+/*
+ * The order of device declaration may be important, since some devices
+ * have dependencies on other devices being initialized first.
+ */
+static struct amba_device *amba_devs[] __initdata = {
+       &uart0_device,
+#ifdef CONFIG_MACH_U300_BS335
+       &uart1_device,
+#endif
+       &pl022_device,
+       &pl172_device,
+       &mmcsd_device,
+};
+
+/* Here follows a list of all hw resources that the platform devices
+ * allocate. Note, clock dependencies are not included
+ */
+
+static struct resource gpio_resources[] = {
+       {
+               .start = U300_GPIO_BASE,
+               .end   = (U300_GPIO_BASE + SZ_4K - 1),
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name  = "gpio0",
+               .start = IRQ_U300_GPIO_PORT0,
+               .end   = IRQ_U300_GPIO_PORT0,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name  = "gpio1",
+               .start = IRQ_U300_GPIO_PORT1,
+               .end   = IRQ_U300_GPIO_PORT1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name  = "gpio2",
+               .start = IRQ_U300_GPIO_PORT2,
+               .end   = IRQ_U300_GPIO_PORT2,
+               .flags = IORESOURCE_IRQ,
+       },
+#ifdef U300_COH901571_3
+       {
+               .name  = "gpio3",
+               .start = IRQ_U300_GPIO_PORT3,
+               .end   = IRQ_U300_GPIO_PORT3,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name  = "gpio4",
+               .start = IRQ_U300_GPIO_PORT4,
+               .end   = IRQ_U300_GPIO_PORT4,
+               .flags = IORESOURCE_IRQ,
+       },
+#ifdef CONFIG_MACH_U300_BS335
+       {
+               .name  = "gpio5",
+               .start = IRQ_U300_GPIO_PORT5,
+               .end   = IRQ_U300_GPIO_PORT5,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name  = "gpio6",
+               .start = IRQ_U300_GPIO_PORT6,
+               .end   = IRQ_U300_GPIO_PORT6,
+               .flags = IORESOURCE_IRQ,
+       },
+#endif /* CONFIG_MACH_U300_BS335 */
+#endif /* U300_COH901571_3 */
+};
+
+static struct resource keypad_resources[] = {
+       {
+               .start = U300_KEYPAD_BASE,
+               .end   = U300_KEYPAD_BASE + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name  = "coh901461-press",
+               .start = IRQ_U300_KEYPAD_KEYBF,
+               .end   = IRQ_U300_KEYPAD_KEYBF,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name  = "coh901461-release",
+               .start = IRQ_U300_KEYPAD_KEYBR,
+               .end   = IRQ_U300_KEYPAD_KEYBR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource rtc_resources[] = {
+       {
+               .start = U300_RTC_BASE,
+               .end   = U300_RTC_BASE + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_U300_RTC,
+               .end   = IRQ_U300_RTC,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+/*
+ * Fsmc does have IRQs: #43 and #44 (NFIF and NFIF2)
+ * but these are not yet used by the driver.
+ */
+static struct resource fsmc_resources[] = {
+       {
+               .start = U300_NAND_IF_PHYS_BASE,
+               .end   = U300_NAND_IF_PHYS_BASE + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+};
+
+static struct resource i2c0_resources[] = {
+       {
+               .start = U300_I2C0_BASE,
+               .end   = U300_I2C0_BASE + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_U300_I2C0,
+               .end   = IRQ_U300_I2C0,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource i2c1_resources[] = {
+       {
+               .start = U300_I2C1_BASE,
+               .end   = U300_I2C1_BASE + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_U300_I2C1,
+               .end   = IRQ_U300_I2C1,
+               .flags = IORESOURCE_IRQ,
+       },
+
+};
+
+static struct resource wdog_resources[] = {
+       {
+               .start = U300_WDOG_BASE,
+               .end   = U300_WDOG_BASE + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_U300_WDOG,
+               .end   = IRQ_U300_WDOG,
+               .flags = IORESOURCE_IRQ,
+       }
+};
+
+/* TODO: These should be protected by suitable #ifdef's */
+static struct resource ave_resources[] = {
+       {
+               .name  = "AVE3e I/O Area",
+               .start = U300_VIDEOENC_BASE,
+               .end   = U300_VIDEOENC_BASE + SZ_512K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name  = "AVE3e IRQ0",
+               .start = IRQ_U300_VIDEO_ENC_0,
+               .end   = IRQ_U300_VIDEO_ENC_0,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name  = "AVE3e IRQ1",
+               .start = IRQ_U300_VIDEO_ENC_1,
+               .end   = IRQ_U300_VIDEO_ENC_1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name  = "AVE3e Physmem Area",
+               .start = 0, /* 0 will be remapped to reserved memory */
+               .end   = SZ_1M - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       /*
+        * The AVE3e requires two regions of 256MB that it considers
+        * "invisible". The hardware will not be able to access these
+        * adresses, so they should never point to system RAM.
+        */
+       {
+               .name  = "AVE3e Reserved 0",
+               .start = 0xd0000000,
+               .end   = 0xd0000000 + SZ_256M - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name  = "AVE3e Reserved 1",
+               .start = 0xe0000000,
+               .end   = 0xe0000000 + SZ_256M - 1,
+               .flags = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device wdog_device = {
+       .name = "wdog",
+       .id = -1,
+       .num_resources = ARRAY_SIZE(wdog_resources),
+       .resource = wdog_resources,
+};
+
+static struct platform_device i2c0_device = {
+       .name = "stddci2c",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(i2c0_resources),
+       .resource = i2c0_resources,
+};
+
+static struct platform_device i2c1_device = {
+       .name = "stddci2c",
+       .id = 1,
+       .num_resources = ARRAY_SIZE(i2c1_resources),
+       .resource = i2c1_resources,
+};
+
+static struct platform_device gpio_device = {
+       .name = "u300-gpio",
+       .id = -1,
+       .num_resources = ARRAY_SIZE(gpio_resources),
+       .resource = gpio_resources,
+};
+
+static struct platform_device keypad_device = {
+       .name = "keypad",
+       .id = -1,
+       .num_resources = ARRAY_SIZE(keypad_resources),
+       .resource = keypad_resources,
+};
+
+static struct platform_device rtc_device = {
+       .name = "rtc0",
+       .id = -1,
+       .num_resources = ARRAY_SIZE(rtc_resources),
+       .resource = rtc_resources,
+};
+
+static struct platform_device fsmc_device = {
+       .name = "nandif",
+       .id = -1,
+       .num_resources = ARRAY_SIZE(fsmc_resources),
+       .resource = fsmc_resources,
+};
+
+static struct platform_device ave_device = {
+       .name = "video_enc",
+       .id = -1,
+       .num_resources = ARRAY_SIZE(ave_resources),
+       .resource = ave_resources,
+};
+
+/*
+ * Notice that AMBA devices are initialized before platform devices.
+ *
+ */
+static struct platform_device *platform_devs[] __initdata = {
+       &i2c0_device,
+       &i2c1_device,
+       &keypad_device,
+       &rtc_device,
+       &gpio_device,
+       &fsmc_device,
+       &wdog_device,
+       &ave_device
+};
+
+
+/*
+ * Interrupts: the U300 platforms have two pl190 ARM PrimeCells connected
+ * together so some interrupts are connected to the first one and some
+ * to the second one.
+ */
+void __init u300_init_irq(void)
+{
+       u32 mask[2] = {0, 0};
+       int i;
+
+       for (i = 0; i < NR_IRQS; i++)
+               set_bit(i, (unsigned long *) &mask[0]);
+       u300_enable_intcon_clock();
+       vic_init((void __iomem *) U300_INTCON0_VBASE, 0, mask[0], 0);
+       vic_init((void __iomem *) U300_INTCON1_VBASE, 32, mask[1], 0);
+}
+
+
+/*
+ * U300 platforms peripheral handling
+ */
+struct db_chip {
+       u16 chipid;
+       const char *name;
+};
+
+/*
+ * This is a list of the Digital Baseband chips used in the U300 platform.
+ */
+static struct db_chip db_chips[] __initdata = {
+       {
+               .chipid = 0xb800,
+               .name = "DB3000",
+       },
+       {
+               .chipid = 0xc000,
+               .name = "DB3100",
+       },
+       {
+               .chipid = 0xc800,
+               .name = "DB3150",
+       },
+       {
+               .chipid = 0xd800,
+               .name = "DB3200",
+       },
+       {
+               .chipid = 0xe000,
+               .name = "DB3250",
+       },
+       {
+               .chipid = 0xe800,
+               .name = "DB3210",
+       },
+       {
+               .chipid = 0xf000,
+               .name = "DB3350 P1x",
+       },
+       {
+               .chipid = 0xf100,
+               .name = "DB3350 P2x",
+       },
+       {
+               .chipid = 0x0000, /* List terminator */
+               .name = NULL,
+       }
+};
+
+static void u300_init_check_chip(void)
+{
+
+       u16 val;
+       struct db_chip *chip;
+       const char *chipname;
+       const char unknown[] = "UNKNOWN";
+
+       /* Read out and print chip ID */
+       val = readw(U300_SYSCON_VBASE + U300_SYSCON_CIDR);
+       /* This is in funky bigendian order... */
+       val = (val & 0xFFU) << 8 | (val >> 8);
+       chip = db_chips;
+       chipname = unknown;
+
+       for ( ; chip->chipid; chip++) {
+               if (chip->chipid == (val & 0xFF00U)) {
+                       chipname = chip->name;
+                       break;
+               }
+       }
+       printk(KERN_INFO "Initializing U300 system on %s baseband chip " \
+              "(chip ID 0x%04x)\n", chipname, val);
+
+#ifdef CONFIG_MACH_U300_BS26
+       if ((val & 0xFF00U) != 0xc800) {
+               printk(KERN_ERR "Platform configured for BS25/BS26 " \
+                      "with DB3150 but %s detected, expect problems!",
+                      chipname);
+       }
+#endif
+#ifdef CONFIG_MACH_U300_BS330
+       if ((val & 0xFF00U) != 0xd800) {
+               printk(KERN_ERR "Platform configured for BS330 " \
+                      "with DB3200 but %s detected, expect problems!",
+                      chipname);
+       }
+#endif
+#ifdef CONFIG_MACH_U300_BS335
+       if ((val & 0xFF00U) != 0xf000 && (val & 0xFF00U) != 0xf100) {
+               printk(KERN_ERR "Platform configured for BS365 " \
+                      " with DB3350 but %s detected, expect problems!",
+                      chipname);
+       }
+#endif
+#ifdef CONFIG_MACH_U300_BS365
+       if ((val & 0xFF00U) != 0xe800) {
+               printk(KERN_ERR "Platform configured for BS365 " \
+                      "with DB3210 but %s detected, expect problems!",
+                      chipname);
+       }
+#endif
+
+
+}
+
+/*
+ * Some devices and their resources require reserved physical memory from
+ * the end of the available RAM. This function traverses the list of devices
+ * and assigns actual adresses to these.
+ */
+static void __init u300_assign_physmem(void)
+{
+       unsigned long curr_start = __pa(high_memory);
+       int i, j;
+
+       for (i = 0; i < ARRAY_SIZE(platform_devs); i++) {
+               for (j = 0; j < platform_devs[i]->num_resources; j++) {
+                       struct resource *const res =
+                         &platform_devs[i]->resource[j];
+
+                       if (IORESOURCE_MEM == res->flags &&
+                                    0 == res->start) {
+                               res->start  = curr_start;
+                               res->end   += curr_start;
+                               curr_start += (res->end - res->start + 1);
+
+                               printk(KERN_INFO "core.c: Mapping RAM " \
+                                      "%#x-%#x to device %s:%s\n",
+                                       res->start, res->end,
+                                      platform_devs[i]->name, res->name);
+                       }
+               }
+       }
+}
+
+void __init u300_init_devices(void)
+{
+       int i;
+       u16 val;
+
+       /* Check what platform we run and print some status information */
+       u300_init_check_chip();
+
+       /* Set system to run at PLL208, max performance, a known state. */
+       val = readw(U300_SYSCON_VBASE + U300_SYSCON_CCR);
+       val &= ~U300_SYSCON_CCR_CLKING_PERFORMANCE_MASK;
+       writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
+       /* Wait for the PLL208 to lock if not locked in yet */
+       while (!(readw(U300_SYSCON_VBASE + U300_SYSCON_CSR) &
+                U300_SYSCON_CSR_PLL208_LOCK_IND));
+
+       /* Register the AMBA devices in the AMBA bus abstraction layer */
+       u300_clock_primecells();
+       for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
+               struct amba_device *d = amba_devs[i];
+               amba_device_register(d, &iomem_resource);
+       }
+       u300_unclock_primecells();
+
+       u300_assign_physmem();
+
+       /* Register the platform devices */
+       platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
+
+#ifndef CONFIG_MACH_U300_SEMI_IS_SHARED
+       /*
+        * Enable SEMI self refresh. Self-refresh of the SDRAM is entered when
+        * both subsystems are requesting this mode.
+        * If we not share the Acc SDRAM, this is never the case. Therefore
+        * enable it here from the App side.
+        */
+       val = readw(U300_SYSCON_VBASE + U300_SYSCON_SMCR) |
+               U300_SYSCON_SMCR_SEMI_SREFREQ_ENABLE;
+       writew(val, U300_SYSCON_VBASE + U300_SYSCON_SMCR);
+#endif /* CONFIG_MACH_U300_SEMI_IS_SHARED */
+}
+
+static int core_module_init(void)
+{
+       /*
+        * This needs to be initialized later: it needs the input framework
+        * to be initialized first.
+        */
+       return mmc_init(&mmcsd_device);
+}
+module_init(core_module_init);
diff --git a/arch/arm/mach-u300/gpio.c b/arch/arm/mach-u300/gpio.c
new file mode 100644 (file)
index 0000000..308cdb1
--- /dev/null
@@ -0,0 +1,703 @@
+/*
+ *
+ * arch/arm/mach-u300/gpio.c
+ *
+ *
+ * Copyright (C) 2007-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * U300 GPIO module.
+ * This can driver either of the two basic GPIO cores
+ * available in the U300 platforms:
+ * COH 901 335   - Used in DB3150 (U300 1.0) and DB3200 (U330 1.0)
+ * COH 901 571/3 - Used in DB3210 (U365 2.0) and DB3350 (U335 1.0)
+ * Notice that you also have inline macros in <asm-arch/gpio.h>
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
+ *
+ */
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+/* Need access to SYSCON registers for PADmuxing */
+#include <mach/syscon.h>
+
+#include "padmux.h"
+
+/* Reference to GPIO block clock */
+static struct clk *clk;
+
+/* Memory resource */
+static struct resource *memres;
+static void __iomem *virtbase;
+static struct device *gpiodev;
+
+struct u300_gpio_port {
+       const char *name;
+       int irq;
+       int number;
+};
+
+
+static struct u300_gpio_port gpio_ports[] = {
+       {
+               .name = "gpio0",
+               .number = 0,
+       },
+       {
+               .name = "gpio1",
+               .number = 1,
+       },
+       {
+               .name = "gpio2",
+               .number = 2,
+       },
+#ifdef U300_COH901571_3
+       {
+               .name = "gpio3",
+               .number = 3,
+       },
+       {
+               .name = "gpio4",
+               .number = 4,
+       },
+#ifdef CONFIG_MACH_U300_BS335
+       {
+               .name = "gpio5",
+               .number = 5,
+       },
+       {
+               .name = "gpio6",
+               .number = 6,
+       },
+#endif
+#endif
+
+};
+
+
+#ifdef U300_COH901571_3
+
+/* Default input value */
+#define DEFAULT_OUTPUT_LOW   0
+#define DEFAULT_OUTPUT_HIGH  1
+
+/* GPIO Pull-Up status */
+#define DISABLE_PULL_UP  0
+#define ENABLE_PULL_UP  1
+
+#define GPIO_NOT_USED 0
+#define GPIO_IN       1
+#define GPIO_OUT      2
+
+struct u300_gpio_configuration_data {
+       unsigned char pin_usage;
+       unsigned char default_output_value;
+       unsigned char pull_up;
+};
+
+/* Initial configuration */
+const struct u300_gpio_configuration_data
+u300_gpio_config[U300_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = {
+#ifdef CONFIG_MACH_U300_BS335
+       /* Port 0, pins 0-7 */
+       {
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_HIGH,  DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP}
+       },
+       /* Port 1, pins 0-7 */
+       {
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_HIGH,  DISABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP}
+       },
+       /* Port 2, pins 0-7 */
+       {
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP}
+       },
+       /* Port 3, pins 0-7 */
+       {
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP}
+       },
+       /* Port 4, pins 0-7 */
+       {
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP}
+       },
+       /* Port 5, pins 0-7 */
+       {
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP}
+       },
+       /* Port 6, pind 0-7 */
+       {
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP}
+       }
+#endif
+
+#ifdef CONFIG_MACH_U300_BS365
+       /* Port 0, pins 0-7 */
+       {
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP}
+       },
+       /* Port 1, pins 0-7 */
+       {
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_HIGH,  DISABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP}
+       },
+       /* Port 2, pins 0-7 */
+       {
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,   DISABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP}
+       },
+       /* Port 3, pins 0-7 */
+       {
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP}
+       },
+       /* Port 4, pins 0-7 */
+       {
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+               {GPIO_IN,  DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+               /* These 4 pins doesn't exist on DB3210 */
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP},
+               {GPIO_OUT, DEFAULT_OUTPUT_LOW,    ENABLE_PULL_UP}
+       }
+#endif
+};
+#endif
+
+
+/* No users == we can power down GPIO */
+static int gpio_users;
+
+struct gpio_struct {
+       int (*callback)(void *);
+       void *data;
+       int users;
+};
+
+static struct gpio_struct gpio_pin[U300_GPIO_MAX];
+
+/*
+ * Let drivers register callback in order to get notified when there is
+ * an interrupt on the gpio pin
+ */
+int gpio_register_callback(unsigned gpio, int (*func)(void *arg), void *data)
+{
+       if (gpio_pin[gpio].callback)
+               dev_warn(gpiodev, "%s: WARNING: callback already "
+                        "registered for gpio pin#%d\n", __func__, gpio);
+       gpio_pin[gpio].callback = func;
+       gpio_pin[gpio].data = data;
+
+       return 0;
+}
+EXPORT_SYMBOL(gpio_register_callback);
+
+int gpio_unregister_callback(unsigned gpio)
+{
+       if (!gpio_pin[gpio].callback)
+               dev_warn(gpiodev, "%s: WARNING: callback already "
+                        "unregistered for gpio pin#%d\n", __func__, gpio);
+       gpio_pin[gpio].callback = NULL;
+       gpio_pin[gpio].data = NULL;
+
+       return 0;
+}
+EXPORT_SYMBOL(gpio_unregister_callback);
+
+int gpio_request(unsigned gpio, const char *label)
+{
+       if (gpio_pin[gpio].users)
+               return -EINVAL;
+       else
+               gpio_pin[gpio].users++;
+
+       gpio_users++;
+
+       return 0;
+}
+EXPORT_SYMBOL(gpio_request);
+
+void gpio_free(unsigned gpio)
+{
+       gpio_users--;
+       gpio_pin[gpio].users--;
+       if (unlikely(gpio_pin[gpio].users < 0)) {
+               dev_warn(gpiodev, "warning: gpio#%d release mismatch\n",
+                        gpio);
+               gpio_pin[gpio].users = 0;
+       }
+
+       return;
+}
+EXPORT_SYMBOL(gpio_free);
+
+/* This returns zero or nonzero */
+int gpio_get_value(unsigned gpio)
+{
+       return readl(virtbase + U300_GPIO_PXPDIR +
+         PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING) & (1 << (gpio & 0x07));
+}
+EXPORT_SYMBOL(gpio_get_value);
+
+/*
+ * We hope that the compiler will optimize away the unused branch
+ * in case "value" is a constant
+ */
+void gpio_set_value(unsigned gpio, int value)
+{
+       u32 val;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       if (value) {
+               /* set */
+               val = readl(virtbase + U300_GPIO_PXPDOR +
+                 PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING)
+                 & (1 << (gpio & 0x07));
+               writel(val | (1 << (gpio & 0x07)), virtbase +
+                 U300_GPIO_PXPDOR +
+                 PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING);
+       } else {
+               /* clear */
+               val = readl(virtbase + U300_GPIO_PXPDOR +
+                 PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING)
+                 & (1 << (gpio & 0x07));
+               writel(val & ~(1 << (gpio & 0x07)), virtbase +
+                 U300_GPIO_PXPDOR +
+                 PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING);
+       }
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL(gpio_set_value);
+
+int gpio_direction_input(unsigned gpio)
+{
+       unsigned long flags;
+       u32 val;
+
+       if (gpio > U300_GPIO_MAX)
+               return -EINVAL;
+
+       local_irq_save(flags);
+       val = readl(virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) *
+                               U300_GPIO_PORTX_SPACING);
+       /* Mask out this pin*/
+       val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << ((gpio & 0x07) << 1));
+       /* This is not needed since it sets the bits to zero.*/
+       /* val |= (U300_GPIO_PXPCR_PIN_MODE_INPUT << (gpio*2)); */
+       writel(val, virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) *
+                               U300_GPIO_PORTX_SPACING);
+       local_irq_restore(flags);
+       return 0;
+}
+EXPORT_SYMBOL(gpio_direction_input);
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+       unsigned long flags;
+       u32 val;
+
+       if (gpio > U300_GPIO_MAX)
+               return -EINVAL;
+
+       local_irq_save(flags);
+       val = readl(virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) *
+                               U300_GPIO_PORTX_SPACING);
+       /* Mask out this pin */
+       val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << ((gpio & 0x07) << 1));
+       /*
+        * FIXME: configure for push/pull, open drain or open source per pin
+        * in setup. The current driver will only support push/pull.
+        */
+       val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL
+                       << ((gpio & 0x07) << 1));
+       writel(val, virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) *
+                               U300_GPIO_PORTX_SPACING);
+       gpio_set_value(gpio, value);
+       local_irq_restore(flags);
+       return 0;
+}
+EXPORT_SYMBOL(gpio_direction_output);
+
+/*
+ * Enable an IRQ, edge is rising edge (!= 0) or falling edge (==0).
+ */
+void enable_irq_on_gpio_pin(unsigned gpio, int edge)
+{
+       u32 val;
+       unsigned long flags;
+       local_irq_save(flags);
+
+       val = readl(virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) *
+                               U300_GPIO_PORTX_SPACING);
+       val |= (1 << (gpio & 0x07));
+       writel(val, virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) *
+                               U300_GPIO_PORTX_SPACING);
+       val = readl(virtbase + U300_GPIO_PXICR + PIN_TO_PORT(gpio) *
+                               U300_GPIO_PORTX_SPACING);
+       if (edge)
+               val |= (1 << (gpio & 0x07));
+       else
+               val &= ~(1 << (gpio & 0x07));
+       writel(val, virtbase + U300_GPIO_PXICR + PIN_TO_PORT(gpio) *
+                               U300_GPIO_PORTX_SPACING);
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL(enable_irq_on_gpio_pin);
+
+void disable_irq_on_gpio_pin(unsigned gpio)
+{
+       u32 val;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       val = readl(virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) *
+                               U300_GPIO_PORTX_SPACING);
+       val &= ~(1 << (gpio & 0x07));
+       writel(val, virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) *
+                               U300_GPIO_PORTX_SPACING);
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL(disable_irq_on_gpio_pin);
+
+/* Enable (value == 0) or disable (value == 1) internal pullup */
+void gpio_pullup(unsigned gpio, int value)
+{
+       u32 val;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       if (value) {
+               val = readl(virtbase + U300_GPIO_PXPER + PIN_TO_PORT(gpio) *
+                                       U300_GPIO_PORTX_SPACING);
+               writel(val | (1 << (gpio & 0x07)), virtbase + U300_GPIO_PXPER +
+                               PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING);
+       } else {
+               val = readl(virtbase + U300_GPIO_PXPER + PIN_TO_PORT(gpio) *
+                                       U300_GPIO_PORTX_SPACING);
+               writel(val & ~(1 << (gpio & 0x07)), virtbase + U300_GPIO_PXPER +
+                               PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING);
+       }
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL(gpio_pullup);
+
+static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
+{
+       struct u300_gpio_port *port = dev_id;
+       u32 val;
+       int pin;
+
+       /* Read event register */
+       val = readl(virtbase + U300_GPIO_PXIEV + port->number *
+                               U300_GPIO_PORTX_SPACING);
+       /* Mask with enable register */
+       val &= readl(virtbase + U300_GPIO_PXIEV + port->number *
+                               U300_GPIO_PORTX_SPACING);
+       /* Mask relevant bits */
+       val &= U300_GPIO_PXIEV_ALL_IRQ_EVENT_MASK;
+       /* ACK IRQ (clear event) */
+       writel(val, virtbase + U300_GPIO_PXIEV + port->number *
+                               U300_GPIO_PORTX_SPACING);
+       /* Print message */
+       while (val != 0) {
+               unsigned gpio;
+
+               pin = __ffs(val);
+               /* mask off this pin */
+               val &= ~(1 << pin);
+               gpio = (port->number << 3) + pin;
+
+               if (gpio_pin[gpio].callback)
+                       (void)gpio_pin[gpio].callback(gpio_pin[gpio].data);
+               else
+                       dev_dbg(gpiodev, "stray GPIO IRQ on line %d\n",
+                              gpio);
+       }
+       return IRQ_HANDLED;
+}
+
+static void gpio_set_initial_values(void)
+{
+#ifdef U300_COH901571_3
+       int i, j;
+       unsigned long flags;
+       u32 val;
+
+       /* Write default values to all pins */
+       for (i = 0; i < U300_GPIO_NUM_PORTS; i++) {
+               val = 0;
+               for (j = 0; j < 8; j++)
+                       val |= (u32) (u300_gpio_config[i][j].default_output_value != DEFAULT_OUTPUT_LOW) << j;
+               local_irq_save(flags);
+               writel(val, virtbase + U300_GPIO_PXPDOR + i * U300_GPIO_PORTX_SPACING);
+               local_irq_restore(flags);
+       }
+
+       /*
+        * Put all pins that are set to either 'GPIO_OUT' or 'GPIO_NOT_USED'
+        * to output and 'GPIO_IN' to input for each port. And initalize
+        * default value on outputs.
+        */
+       for (i = 0; i < U300_GPIO_NUM_PORTS; i++) {
+               for (j = 0; j < U300_GPIO_PINS_PER_PORT; j++) {
+                       local_irq_save(flags);
+                       val = readl(virtbase + U300_GPIO_PXPCR +
+                                        i * U300_GPIO_PORTX_SPACING);
+                       /* Mask out this pin */
+                       val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << (j << 1));
+
+                       if (u300_gpio_config[i][j].pin_usage != GPIO_IN)
+                               val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL << (j << 1));
+                       writel(val, virtbase + U300_GPIO_PXPCR +
+                                        i * U300_GPIO_PORTX_SPACING);
+                       local_irq_restore(flags);
+               }
+       }
+
+       /* Enable or disable the internal pull-ups in the GPIO ASIC block */
+       for (i = 0; i < U300_GPIO_MAX; i++) {
+               val = 0;
+               for (j = 0; j < 8; j++)
+                       val |= (u32)((u300_gpio_config[i][j].pull_up == DISABLE_PULL_UP)) << j;
+               local_irq_save(flags);
+               writel(val, virtbase + U300_GPIO_PXPER + i * U300_GPIO_PORTX_SPACING);
+               local_irq_restore(flags);
+       }
+#endif
+}
+
+static int __init gpio_probe(struct platform_device *pdev)
+{
+       u32 val;
+       int err = 0;
+       int i;
+       int num_irqs;
+
+       gpiodev = &pdev->dev;
+       memset(gpio_pin, 0, sizeof(gpio_pin));
+
+       /* Get GPIO clock */
+       clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(clk)) {
+               err = PTR_ERR(clk);
+               dev_err(gpiodev, "could not get GPIO clock\n");
+               goto err_no_clk;
+       }
+       err = clk_enable(clk);
+       if (err) {
+               dev_err(gpiodev, "could not enable GPIO clock\n");
+               goto err_no_clk_enable;
+       }
+
+       memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!memres)
+               goto err_no_resource;
+
+       if (request_mem_region(memres->start, memres->end - memres->start, "GPIO Controller")
+           == NULL) {
+               err = -ENODEV;
+               goto err_no_ioregion;
+       }
+
+       virtbase = ioremap(memres->start, resource_size(memres));
+       if (!virtbase) {
+               err = -ENOMEM;
+               goto err_no_ioremap;
+       }
+       dev_info(gpiodev, "remapped 0x%08x to %p\n",
+                memres->start, virtbase);
+
+#ifdef U300_COH901335
+       dev_info(gpiodev, "initializing GPIO Controller COH 901 335\n");
+       /* Turn on the GPIO block */
+       writel(U300_GPIO_CR_BLOCK_CLOCK_ENABLE, virtbase + U300_GPIO_CR);
+#endif
+
+#ifdef U300_COH901571_3
+       dev_info(gpiodev, "initializing GPIO Controller COH 901 571/3\n");
+       val = readl(virtbase + U300_GPIO_CR);
+       dev_info(gpiodev, "COH901571/3 block version: %d, " \
+              "number of cores: %d\n",
+              ((val & 0x0000FE00) >> 9),
+              ((val & 0x000001FC) >> 2));
+       writel(U300_GPIO_CR_BLOCK_CLKRQ_ENABLE, virtbase + U300_GPIO_CR);
+#endif
+
+       /* Set up some padmuxing here */
+#ifdef CONFIG_MMC
+       pmx_set_mission_mode_mmc();
+#endif
+#ifdef CONFIG_SPI_PL022
+       pmx_set_mission_mode_spi();
+#endif
+
+       gpio_set_initial_values();
+
+       for (num_irqs = 0 ; num_irqs < U300_GPIO_NUM_PORTS; num_irqs++) {
+
+               gpio_ports[num_irqs].irq =
+                       platform_get_irq_byname(pdev,
+                                               gpio_ports[num_irqs].name);
+
+               err = request_irq(gpio_ports[num_irqs].irq,
+                                 gpio_irq_handler, IRQF_DISABLED,
+                                 gpio_ports[num_irqs].name,
+                                 &gpio_ports[num_irqs]);
+               if (err) {
+                       dev_err(gpiodev, "cannot allocate IRQ for %s!\n",
+                               gpio_ports[num_irqs].name);
+                       goto err_no_irq;
+               }
+               /* Turns off PortX_irq_force */
+               writel(0x0, virtbase + U300_GPIO_PXIFR +
+                                num_irqs * U300_GPIO_PORTX_SPACING);
+       }
+
+       return 0;
+
+ err_no_irq:
+       for (i = 0; i < num_irqs; i++)
+               free_irq(gpio_ports[i].irq, &gpio_ports[i]);
+       iounmap(virtbase);
+ err_no_ioremap:
+       release_mem_region(memres->start, memres->end - memres->start);
+ err_no_ioregion:
+ err_no_resource:
+       clk_disable(clk);
+ err_no_clk_enable:
+       clk_put(clk);
+ err_no_clk:
+       dev_info(gpiodev, "module ERROR:%d\n", err);
+       return err;
+}
+
+static int __exit gpio_remove(struct platform_device *pdev)
+{
+       int i;
+
+       /* Turn off the GPIO block */
+       writel(0x00000000U, virtbase + U300_GPIO_CR);
+       for (i = 0 ; i < U300_GPIO_NUM_PORTS; i++)
+               free_irq(gpio_ports[i].irq, &gpio_ports[i]);
+       iounmap(virtbase);
+       release_mem_region(memres->start, memres->end - memres->start);
+       clk_disable(clk);
+       clk_put(clk);
+       return 0;
+}
+
+static struct platform_driver gpio_driver = {
+       .driver         = {
+               .name   = "u300-gpio",
+       },
+       .remove         = __exit_p(gpio_remove),
+};
+
+
+static int __init u300_gpio_init(void)
+{
+       return platform_driver_probe(&gpio_driver, gpio_probe);
+}
+
+static void __exit u300_gpio_exit(void)
+{
+       platform_driver_unregister(&gpio_driver);
+}
+
+arch_initcall(u300_gpio_init);
+module_exit(u300_gpio_exit);
+
+MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
+
+#ifdef U300_COH901571_3
+MODULE_DESCRIPTION("ST-Ericsson AB COH 901 571/3 GPIO driver");
+#endif
+
+#ifdef U300_COH901335
+MODULE_DESCRIPTION("ST-Ericsson AB COH 901 335 GPIO driver");
+#endif
+
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-u300/include/mach/clkdev.h b/arch/arm/mach-u300/include/mach/clkdev.h
new file mode 100644 (file)
index 0000000..92e3cc8
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __MACH_CLKDEV_H
+#define __MACH_CLKDEV_H
+
+int __clk_get(struct clk *clk);
+void __clk_put(struct clk *clk);
+
+#endif
diff --git a/arch/arm/mach-u300/include/mach/debug-macro.S b/arch/arm/mach-u300/include/mach/debug-macro.S
new file mode 100644 (file)
index 0000000..f3a1cbb
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ *
+ * arch-arm/mach-u300/include/mach/debug-macro.S
+ *
+ *
+ * Copyright (C) 2006-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Debugging macro include header.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+#include <mach/hardware.h>
+
+       .macro  addruart,rx
+       /* If we move the adress using MMU, use this. */
+       mrc     p15, 0, \rx, c1, c0
+       tst     \rx, #1                 @ MMU enabled?
+       ldreq   \rx,      = U300_SLOW_PER_PHYS_BASE @ MMU off, physical address
+       ldrne   \rx,      = U300_SLOW_PER_VIRT_BASE @ MMU on, virtual address
+       orr     \rx, \rx, #0x00003000
+       .endm
+
+#include <asm/hardware/debug-pl01x.S>
diff --git a/arch/arm/mach-u300/include/mach/entry-macro.S b/arch/arm/mach-u300/include/mach/entry-macro.S
new file mode 100644 (file)
index 0000000..20731ae
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *
+ * arch-arm/mach-u300/include/mach/entry-macro.S
+ *
+ *
+ * Copyright (C) 2006-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Low-level IRQ helper macros for ST-Ericsson U300
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+#include <mach/hardware.h>
+#include <asm/hardware/vic.h>
+
+       .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, = U300_AHB_PER_VIRT_BASE-U300_AHB_PER_PHYS_BASE+U300_INTCON0_BASE
+       ldr     \irqstat, [\base, #VIC_IRQ_STATUS] @ get masked status
+       mov     \irqnr, #0
+       teq     \irqstat, #0
+       bne     1002f
+1001:  ldr     \base, = U300_AHB_PER_VIRT_BASE-U300_AHB_PER_PHYS_BASE+U300_INTCON1_BASE
+       ldr     \irqstat, [\base, #VIC_IRQ_STATUS] @ get masked status
+       mov     \irqnr, #32
+       teq     \irqstat, #0
+       beq     1003f
+1002:  tst     \irqstat, #1
+       bne     1003f
+       add     \irqnr, \irqnr, #1
+       movs    \irqstat, \irqstat, lsr #1
+       bne     1002b
+1003:          /* EQ will be set if no irqs pending */
+       .endm
diff --git a/arch/arm/mach-u300/include/mach/gpio.h b/arch/arm/mach-u300/include/mach/gpio.h
new file mode 100644 (file)
index 0000000..c817412
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ *
+ * arch/arm/mach-u300/include/mach/gpio.h
+ *
+ *
+ * Copyright (C) 2007-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * GPIO block resgister definitions and inline macros for
+ * U300 GPIO COH 901 335 or COH 901 571/3
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+
+#ifndef __MACH_U300_GPIO_H
+#define __MACH_U300_GPIO_H
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <mach/hardware.h>
+#include <asm/irq.h>
+
+/* Switch type depending on platform/chip variant */
+#if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330)
+#define U300_COH901335
+#endif
+#if defined(CONFIG_MACH_U300_BS365) || defined(CONFIG_MACH_U300_BS335)
+#define U300_COH901571_3
+#endif
+
+/* Get base address for regs here */
+#include "u300-regs.h"
+/* IRQ numbers */
+#include "irqs.h"
+
+/*
+ * This is the GPIO block definitions. GPIO (General Purpose I/O) can be
+ * used for anything, and often is. The event/enable etc figures are for
+ * the lowermost pin (pin 0 on each port), shift this left to match your
+ * pin if you're gonna use these values.
+ */
+#ifdef U300_COH901335
+#define U300_GPIO_PORTX_SPACING                                (0x1C)
+/* Port X Pin Data Register 32bit, this is both input and output (R/W) */
+#define U300_GPIO_PXPDIR                               (0x00)
+#define U300_GPIO_PXPDOR                               (0x00)
+/* Port X Pin Config Register 32bit (R/W) */
+#define U300_GPIO_PXPCR                                        (0x04)
+#define U300_GPIO_PXPCR_ALL_PINS_MODE_MASK             (0x0000FFFFUL)
+#define U300_GPIO_PXPCR_PIN_MODE_MASK                  (0x00000003UL)
+#define U300_GPIO_PXPCR_PIN_MODE_SHIFT                 (0x00000002UL)
+#define U300_GPIO_PXPCR_PIN_MODE_INPUT                 (0x00000000UL)
+#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL      (0x00000001UL)
+#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_DRAIN     (0x00000002UL)
+#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_SOURCE    (0x00000003UL)
+/* Port X Interrupt Event Register 32bit (R/W) */
+#define U300_GPIO_PXIEV                                        (0x08)
+#define U300_GPIO_PXIEV_ALL_IRQ_EVENT_MASK             (0x000000FFUL)
+#define U300_GPIO_PXIEV_IRQ_EVENT                      (0x00000001UL)
+/* Port X Interrupt Enable Register 32bit (R/W) */
+#define U300_GPIO_PXIEN                                        (0x0C)
+#define U300_GPIO_PXIEN_ALL_IRQ_ENABLE_MASK            (0x000000FFUL)
+#define U300_GPIO_PXIEN_IRQ_ENABLE                     (0x00000001UL)
+/* Port X Interrupt Force Register 32bit (R/W) */
+#define U300_GPIO_PXIFR                                        (0x10)
+#define U300_GPIO_PXIFR_ALL_IRQ_FORCE_MASK             (0x000000FFUL)
+#define U300_GPIO_PXIFR_IRQ_FORCE                      (0x00000001UL)
+/* Port X Interrupt Config Register 32bit (R/W) */
+#define U300_GPIO_PXICR                                        (0x14)
+#define U300_GPIO_PXICR_ALL_IRQ_CONFIG_MASK            (0x000000FFUL)
+#define U300_GPIO_PXICR_IRQ_CONFIG_MASK                        (0x00000001UL)
+#define U300_GPIO_PXICR_IRQ_CONFIG_FALLING_EDGE                (0x00000000UL)
+#define U300_GPIO_PXICR_IRQ_CONFIG_RISING_EDGE         (0x00000001UL)
+/* Port X Pull-up Enable Register 32bit (R/W) */
+#define U300_GPIO_PXPER                                        (0x18)
+#define U300_GPIO_PXPER_ALL_PULL_UP_DISABLE_MASK       (0x000000FFUL)
+#define U300_GPIO_PXPER_PULL_UP_DISABLE                        (0x00000001UL)
+/* Control Register 32bit (R/W) */
+#define U300_GPIO_CR                                   (0x54)
+#define U300_GPIO_CR_BLOCK_CLOCK_ENABLE                        (0x00000001UL)
+/* three ports of 8 bits each = GPIO pins 0..23 */
+#define U300_GPIO_NUM_PORTS 3
+#define U300_GPIO_PINS_PER_PORT 8
+#define U300_GPIO_MAX  (U300_GPIO_PINS_PER_PORT * U300_GPIO_NUM_PORTS - 1)
+#endif
+
+#ifdef U300_COH901571_3
+/*
+ * Control Register 32bit (R/W)
+ * bit 15-9 (mask 0x0000FE00) contains the number of cores. 8*cores
+ * gives the number of GPIO pins.
+ * bit 8-2  (mask 0x000001FC) contains the core version ID.
+ */
+#define U300_GPIO_CR                                   (0x00)
+#define U300_GPIO_CR_SYNC_SEL_ENABLE                   (0x00000002UL)
+#define U300_GPIO_CR_BLOCK_CLKRQ_ENABLE                        (0x00000001UL)
+#define U300_GPIO_PORTX_SPACING                                (0x30)
+/* Port X Pin Data INPUT Register 32bit (R/W) */
+#define U300_GPIO_PXPDIR                               (0x04)
+/* Port X Pin Data OUTPUT Register 32bit (R/W) */
+#define U300_GPIO_PXPDOR                               (0x08)
+/* Port X Pin Config Register 32bit (R/W) */
+#define U300_GPIO_PXPCR                                        (0x0C)
+#define U300_GPIO_PXPCR_ALL_PINS_MODE_MASK             (0x0000FFFFUL)
+#define U300_GPIO_PXPCR_PIN_MODE_MASK                  (0x00000003UL)
+#define U300_GPIO_PXPCR_PIN_MODE_SHIFT                 (0x00000002UL)
+#define U300_GPIO_PXPCR_PIN_MODE_INPUT                 (0x00000000UL)
+#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL      (0x00000001UL)
+#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_DRAIN     (0x00000002UL)
+#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_SOURCE    (0x00000003UL)
+/* Port X Pull-up Enable Register 32bit (R/W) */
+#define U300_GPIO_PXPER                                        (0x10)
+#define U300_GPIO_PXPER_ALL_PULL_UP_DISABLE_MASK       (0x000000FFUL)
+#define U300_GPIO_PXPER_PULL_UP_DISABLE                        (0x00000001UL)
+/* Port X Interrupt Event Register 32bit (R/W) */
+#define U300_GPIO_PXIEV                                        (0x14)
+#define U300_GPIO_PXIEV_ALL_IRQ_EVENT_MASK             (0x000000FFUL)
+#define U300_GPIO_PXIEV_IRQ_EVENT                      (0x00000001UL)
+/* Port X Interrupt Enable Register 32bit (R/W) */
+#define U300_GPIO_PXIEN                                        (0x18)
+#define U300_GPIO_PXIEN_ALL_IRQ_ENABLE_MASK            (0x000000FFUL)
+#define U300_GPIO_PXIEN_IRQ_ENABLE                     (0x00000001UL)
+/* Port X Interrupt Force Register 32bit (R/W) */
+#define U300_GPIO_PXIFR                                        (0x1C)
+#define U300_GPIO_PXIFR_ALL_IRQ_FORCE_MASK             (0x000000FFUL)
+#define U300_GPIO_PXIFR_IRQ_FORCE                      (0x00000001UL)
+/* Port X Interrupt Config Register 32bit (R/W) */
+#define U300_GPIO_PXICR                                        (0x20)
+#define U300_GPIO_PXICR_ALL_IRQ_CONFIG_MASK            (0x000000FFUL)
+#define U300_GPIO_PXICR_IRQ_CONFIG_MASK                        (0x00000001UL)
+#define U300_GPIO_PXICR_IRQ_CONFIG_FALLING_EDGE                (0x00000000UL)
+#define U300_GPIO_PXICR_IRQ_CONFIG_RISING_EDGE         (0x00000001UL)
+#ifdef CONFIG_MACH_U300_BS335
+/* seven ports of 8 bits each = GPIO pins 0..55 */
+#define U300_GPIO_NUM_PORTS 7
+#else
+/* five ports of 8 bits each = GPIO pins 0..39 */
+#define U300_GPIO_NUM_PORTS 5
+#endif
+#define U300_GPIO_PINS_PER_PORT 8
+#define U300_GPIO_MAX (U300_GPIO_PINS_PER_PORT * U300_GPIO_NUM_PORTS - 1)
+#endif
+
+/*
+ * Individual pin assignments for the B26/S26. Notice that the
+ * actual usage of these pins depends on the PAD MUX settings, that
+ * is why the same number can potentially appear several times.
+ * In the reference design each pin is only used for one purpose.
+ * These were determined by inspecting the B26/S26 schematic:
+ * 2/1911-ROA 128 1603
+ */
+#ifdef CONFIG_MACH_U300_BS2X
+#define U300_GPIO_PIN_UART_RX          0
+#define U300_GPIO_PIN_UART_TX          1
+#define U300_GPIO_PIN_GPIO02           2  /* Unrouted */
+#define U300_GPIO_PIN_GPIO03           3  /* Unrouted */
+#define U300_GPIO_PIN_CAM_SLEEP                4
+#define U300_GPIO_PIN_CAM_REG_EN       5
+#define U300_GPIO_PIN_GPIO06           6  /* Unrouted */
+#define U300_GPIO_PIN_GPIO07           7  /* Unrouted */
+
+#define U300_GPIO_PIN_GPIO08           8  /* Service point SP2321 */
+#define U300_GPIO_PIN_GPIO09           9  /* Service point SP2322 */
+#define U300_GPIO_PIN_PHFSENSE         10 /* Headphone jack sensing */
+#define U300_GPIO_PIN_MMC_CLKRET       11 /* Clock return from MMC/SD card */
+#define U300_GPIO_PIN_MMC_CD           12 /* MMC Card insertion detection */
+#define U300_GPIO_PIN_FLIPSENSE                13 /* Mechanical flip sensing */
+#define U300_GPIO_PIN_GPIO14           14 /* DSP JTAG Port RTCK */
+#define U300_GPIO_PIN_GPIO15           15 /* Unrouted */
+
+#define U300_GPIO_PIN_GPIO16           16 /* Unrouted */
+#define U300_GPIO_PIN_GPIO17           17 /* Unrouted */
+#define U300_GPIO_PIN_GPIO18           18 /* Unrouted */
+#define U300_GPIO_PIN_GPIO19           19 /* Unrouted */
+#define U300_GPIO_PIN_GPIO20           20 /* Unrouted */
+#define U300_GPIO_PIN_GPIO21           21 /* Unrouted */
+#define U300_GPIO_PIN_GPIO22           22 /* Unrouted */
+#define U300_GPIO_PIN_GPIO23           23 /* Unrouted */
+#endif
+
+/*
+ * Individual pin assignments for the B330/S330 and B365/S365.
+ * Notice that the actual usage of these pins depends on the
+ * PAD MUX settings, that is why the same number can potentially
+ * appear several times. In the reference design each pin is only
+ * used for one purpose. These were determined by inspecting the
+ * S365 schematic.
+ */
+#if defined(CONFIG_MACH_U300_BS330) || defined(CONFIG_MACH_U300_BS365) || \
+    defined(CONFIG_MACH_U300_BS335)
+#define U300_GPIO_PIN_UART_RX          0
+#define U300_GPIO_PIN_UART_TX          1
+#define U300_GPIO_PIN_UART_CTS         2
+#define U300_GPIO_PIN_UART_RTS         3
+#define U300_GPIO_PIN_CAM_MAIN_STANDBY 4 /* Camera MAIN standby */
+#define U300_GPIO_PIN_GPIO05           5 /* Unrouted */
+#define U300_GPIO_PIN_MS_CD            6 /* Memory Stick Card insertion */
+#define U300_GPIO_PIN_GPIO07           7 /* Test point TP2430 */
+
+#define U300_GPIO_PIN_GPIO08           8 /* Test point TP2437 */
+#define U300_GPIO_PIN_GPIO09           9 /* Test point TP2431 */
+#define U300_GPIO_PIN_GPIO10           10 /* Test point TP2432 */
+#define U300_GPIO_PIN_MMC_CLKRET       11 /* Clock return from MMC/SD card */
+#define U300_GPIO_PIN_MMC_CD           12 /* MMC Card insertion detection */
+#define U300_GPIO_PIN_CAM_SUB_STANDBY  13 /* Camera SUB standby */
+#define U300_GPIO_PIN_GPIO14           14 /* Test point TP2436 */
+#define U300_GPIO_PIN_GPIO15           15 /* Unrouted */
+
+#define U300_GPIO_PIN_GPIO16           16 /* Test point TP2438 */
+#define U300_GPIO_PIN_PHFSENSE         17 /* Headphone jack sensing */
+#define U300_GPIO_PIN_GPIO18           18 /* Test point TP2439 */
+#define U300_GPIO_PIN_GPIO19           19 /* Routed somewhere */
+#define U300_GPIO_PIN_GPIO20           20 /* Unrouted */
+#define U300_GPIO_PIN_GPIO21           21 /* Unrouted */
+#define U300_GPIO_PIN_GPIO22           22 /* Unrouted */
+#define U300_GPIO_PIN_GPIO23           23 /* Unrouted */
+
+#define U300_GPIO_PIN_GPIO24           24 /* Unrouted */
+#define U300_GPIO_PIN_GPIO25           25 /* Unrouted */
+#define U300_GPIO_PIN_GPIO26           26 /* Unrouted */
+#define U300_GPIO_PIN_GPIO27           27 /* Unrouted */
+#define U300_GPIO_PIN_GPIO28           28 /* Unrouted */
+#define U300_GPIO_PIN_GPIO29           29 /* Unrouted */
+#define U300_GPIO_PIN_GPIO30           30 /* Unrouted */
+#define U300_GPIO_PIN_GPIO31           31 /* Unrouted */
+
+#define U300_GPIO_PIN_GPIO32           32 /* Unrouted */
+#define U300_GPIO_PIN_GPIO33           33 /* Unrouted */
+#define U300_GPIO_PIN_GPIO34           34 /* Unrouted */
+#define U300_GPIO_PIN_GPIO35           35 /* Unrouted */
+#define U300_GPIO_PIN_GPIO36           36 /* Unrouted */
+#define U300_GPIO_PIN_GPIO37           37 /* Unrouted */
+#define U300_GPIO_PIN_GPIO38           38 /* Unrouted */
+#define U300_GPIO_PIN_GPIO39           39 /* Unrouted */
+
+#ifdef CONFIG_MACH_U300_BS335
+
+#define U300_GPIO_PIN_GPIO40           40 /* Unrouted */
+#define U300_GPIO_PIN_GPIO41           41 /* Unrouted */
+#define U300_GPIO_PIN_GPIO42           42 /* Unrouted */
+#define U300_GPIO_PIN_GPIO43           43 /* Unrouted */
+#define U300_GPIO_PIN_GPIO44           44 /* Unrouted */
+#define U300_GPIO_PIN_GPIO45           45 /* Unrouted */
+#define U300_GPIO_PIN_GPIO46           46 /* Unrouted */
+#define U300_GPIO_PIN_GPIO47           47 /* Unrouted */
+
+#define U300_GPIO_PIN_GPIO48           48 /* Unrouted */
+#define U300_GPIO_PIN_GPIO49           49 /* Unrouted */
+#define U300_GPIO_PIN_GPIO50           50 /* Unrouted */
+#define U300_GPIO_PIN_GPIO51           51 /* Unrouted */
+#define U300_GPIO_PIN_GPIO52           52 /* Unrouted */
+#define U300_GPIO_PIN_GPIO53           53 /* Unrouted */
+#define U300_GPIO_PIN_GPIO54           54 /* Unrouted */
+#define U300_GPIO_PIN_GPIO55           55 /* Unrouted */
+#endif
+
+#endif
+
+/* translates a pin number to a port number */
+#define PIN_TO_PORT(val) (val >> 3)
+
+/* These can be found in arch/arm/mach-u300/gpio.c */
+extern int gpio_request(unsigned gpio, const char *label);
+extern void gpio_free(unsigned gpio);
+extern int gpio_direction_input(unsigned gpio);
+extern int gpio_direction_output(unsigned gpio, int value);
+extern int gpio_register_callback(unsigned gpio,
+                                 int (*func)(void *arg),
+                                 void *);
+extern int gpio_unregister_callback(unsigned gpio);
+extern void enable_irq_on_gpio_pin(unsigned gpio, int edge);
+extern void disable_irq_on_gpio_pin(unsigned gpio);
+extern void gpio_pullup(unsigned gpio, int value);
+extern int gpio_get_value(unsigned gpio);
+extern void gpio_set_value(unsigned gpio, int value);
+
+/* wrappers to sleep-enable the previous two functions */
+static inline unsigned gpio_to_irq(unsigned gpio)
+{
+       return PIN_TO_PORT(gpio) + IRQ_U300_GPIO_PORT0;
+}
+
+static inline unsigned irq_to_gpio(unsigned irq)
+{
+       /*
+        * FIXME: This is no 1-1 mapping at all, it points to the
+        * whole block of 8 pins.
+        */
+       return (irq - IRQ_U300_GPIO_PORT0) << 3;
+}
+
+#endif
diff --git a/arch/arm/mach-u300/include/mach/hardware.h b/arch/arm/mach-u300/include/mach/hardware.h
new file mode 100644 (file)
index 0000000..b99d4ce
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-u300/include/mach/hardware.h
+ */
+#include <asm/sizes.h>
+#include <mach/u300-regs.h>
diff --git a/arch/arm/mach-u300/include/mach/io.h b/arch/arm/mach-u300/include/mach/io.h
new file mode 100644 (file)
index 0000000..5d6b4c1
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ *
+ * arch/arm/mach-u300/include/mach/io.h
+ *
+ *
+ * Copyright (C) 2006-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Dummy IO map for being able to use writew()/readw(),
+ * writel()/readw() and similar accessor functions.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+#ifndef __MACH_IO_H
+#define __MACH_IO_H
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+#define __io(a)                __typesafe_io(a)
+#define __mem_pci(a)   (a)
+
+#endif
diff --git a/arch/arm/mach-u300/include/mach/irqs.h b/arch/arm/mach-u300/include/mach/irqs.h
new file mode 100644 (file)
index 0000000..a6867b1
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ *
+ * arch/arm/mach-u300/include/mach/irqs.h
+ *
+ *
+ * Copyright (C) 2006-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * IRQ channel definitions for the U300 platforms.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+
+#ifndef __MACH_IRQS_H
+#define __MACH_IRQS_H
+
+#define IRQ_U300_INTCON0_START         0
+#define IRQ_U300_INTCON1_START         32
+/* These are on INTCON0 - 30 lines */
+#define IRQ_U300_IRQ0_EXT              0
+#define IRQ_U300_IRQ1_EXT              1
+#define IRQ_U300_DMA                   2
+#define IRQ_U300_VIDEO_ENC_0           3
+#define IRQ_U300_VIDEO_ENC_1           4
+#define IRQ_U300_AAIF_RX               5
+#define IRQ_U300_AAIF_TX               6
+#define IRQ_U300_AAIF_VGPIO            7
+#define IRQ_U300_AAIF_WAKEUP           8
+#define IRQ_U300_PCM_I2S0_FRAME                9
+#define IRQ_U300_PCM_I2S0_FIFO         10
+#define IRQ_U300_PCM_I2S1_FRAME                11
+#define IRQ_U300_PCM_I2S1_FIFO         12
+#define IRQ_U300_XGAM_GAMCON           13
+#define IRQ_U300_XGAM_CDI              14
+#define IRQ_U300_XGAM_CDICON           15
+#if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330)
+/* MMIACC not used on the DB3210 or DB3350 chips */
+#define IRQ_U300_XGAM_MMIACC           16
+#endif
+#define IRQ_U300_XGAM_PDI              17
+#define IRQ_U300_XGAM_PDICON           18
+#define IRQ_U300_XGAM_GAMEACC          19
+#define IRQ_U300_XGAM_MCIDCT           20
+#define IRQ_U300_APEX                  21
+#define IRQ_U300_UART0                 22
+#define IRQ_U300_SPI                   23
+#define IRQ_U300_TIMER_APP_OS          24
+#define IRQ_U300_TIMER_APP_DD          25
+#define IRQ_U300_TIMER_APP_GP1         26
+#define IRQ_U300_TIMER_APP_GP2         27
+#define IRQ_U300_TIMER_OS              28
+#define IRQ_U300_TIMER_MS              29
+#define IRQ_U300_KEYPAD_KEYBF          30
+#define IRQ_U300_KEYPAD_KEYBR          31
+/* These are on INTCON1 - 32 lines */
+#define IRQ_U300_GPIO_PORT0            32
+#define IRQ_U300_GPIO_PORT1            33
+#define IRQ_U300_GPIO_PORT2            34
+
+#if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330) || \
+    defined(CONFIG_MACH_U300_BS335)
+/* These are for DB3150, DB3200 and DB3350 */
+#define IRQ_U300_WDOG                  35
+#define IRQ_U300_EVHIST                        36
+#define IRQ_U300_MSPRO                 37
+#define IRQ_U300_MMCSD_MCIINTR0                38
+#define IRQ_U300_MMCSD_MCIINTR1                39
+#define IRQ_U300_I2C0                  40
+#define IRQ_U300_I2C1                  41
+#define IRQ_U300_RTC                   42
+#define IRQ_U300_NFIF                  43
+#define IRQ_U300_NFIF2                 44
+#endif
+
+/* DB3150 and DB3200 have only 45 IRQs */
+#if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330)
+#define U300_NR_IRQS                   45
+#endif
+
+/* The DB3350-specific interrupt lines */
+#ifdef CONFIG_MACH_U300_BS335
+#define IRQ_U300_ISP_F0                        45
+#define IRQ_U300_ISP_F1                        46
+#define IRQ_U300_ISP_F2                        47
+#define IRQ_U300_ISP_F3                        48
+#define IRQ_U300_ISP_F4                        49
+#define IRQ_U300_GPIO_PORT3            50
+#define IRQ_U300_SYSCON_PLL_LOCK       51
+#define IRQ_U300_UART1                 52
+#define IRQ_U300_GPIO_PORT4            53
+#define IRQ_U300_GPIO_PORT5            54
+#define IRQ_U300_GPIO_PORT6            55
+#define U300_NR_IRQS                   56
+#endif
+
+/* The DB3210-specific interrupt lines */
+#ifdef CONFIG_MACH_U300_BS365
+#define IRQ_U300_GPIO_PORT3            35
+#define IRQ_U300_GPIO_PORT4            36
+#define IRQ_U300_WDOG                  37
+#define IRQ_U300_EVHIST                        38
+#define IRQ_U300_MSPRO                 39
+#define IRQ_U300_MMCSD_MCIINTR0                40
+#define IRQ_U300_MMCSD_MCIINTR1                41
+#define IRQ_U300_I2C0                  42
+#define IRQ_U300_I2C1                  43
+#define IRQ_U300_RTC                   44
+#define IRQ_U300_NFIF                  45
+#define IRQ_U300_NFIF2                 46
+#define IRQ_U300_SYSCON_PLL_LOCK       47
+#define U300_NR_IRQS                   48
+#endif
+
+#define NR_IRQS U300_NR_IRQS
+
+#endif
diff --git a/arch/arm/mach-u300/include/mach/memory.h b/arch/arm/mach-u300/include/mach/memory.h
new file mode 100644 (file)
index 0000000..bf134bc
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *
+ * arch/arm/mach-u300/include/mach/memory.h
+ *
+ *
+ * Copyright (C) 2007-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Memory virtual/physical mapping constants.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
+ */
+
+#ifndef __MACH_MEMORY_H
+#define __MACH_MEMORY_H
+
+#ifdef CONFIG_MACH_U300_DUAL_RAM
+
+#define PHYS_OFFSET            UL(0x48000000)
+#define BOOT_PARAMS_OFFSET     (PHYS_OFFSET + 0x100)
+
+#else
+
+#ifdef CONFIG_MACH_U300_2MB_ALIGNMENT_FIX
+#define PHYS_OFFSET (0x28000000 + \
+            (CONFIG_MACH_U300_ACCESS_MEM_SIZE - \
+            (CONFIG_MACH_U300_ACCESS_MEM_SIZE & 1))*1024*1024)
+#else
+#define PHYS_OFFSET (0x28000000 + \
+            (CONFIG_MACH_U300_ACCESS_MEM_SIZE +        \
+            (CONFIG_MACH_U300_ACCESS_MEM_SIZE & 1))*1024*1024)
+#endif
+#define BOOT_PARAMS_OFFSET (0x28000000 + \
+           (CONFIG_MACH_U300_ACCESS_MEM_SIZE +         \
+           (CONFIG_MACH_U300_ACCESS_MEM_SIZE & 1))*1024*1024 + 0x100)
+#endif
+
+/*
+ * We enable a real big DMA buffer if need be.
+ */
+#define CONSISTENT_DMA_SIZE SZ_4M
+
+#endif
diff --git a/arch/arm/mach-u300/include/mach/platform.h b/arch/arm/mach-u300/include/mach/platform.h
new file mode 100644 (file)
index 0000000..77d9210
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ *
+ * arch/arm/mach-u300/include/mach/platform.h
+ *
+ *
+ * Copyright (C) 2006-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Basic platform init and mapping functions.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+
+#ifndef __ASSEMBLY__
+
+void u300_map_io(void);
+void u300_init_irq(void);
+void u300_init_devices(void);
+extern struct sys_timer u300_timer;
+
+#endif
diff --git a/arch/arm/mach-u300/include/mach/syscon.h b/arch/arm/mach-u300/include/mach/syscon.h
new file mode 100644 (file)
index 0000000..1c90d1b
--- /dev/null
@@ -0,0 +1,644 @@
+/*
+ *
+ * arch/arm/mach-u300/include/mach/syscon.h
+ *
+ *
+ * Copyright (C) 2008 ST-Ericsson AB
+ *
+ * Author: Rickard Andersson <rickard.andersson@stericsson.com>
+ */
+
+#ifndef __MACH_SYSCON_H
+#define __MACH_SYSCON_H
+
+/*
+ * All register defines for SYSCON registers that concerns individual
+ * block clocks and reset lines are registered here. This is because
+ * we don't want any other file to try to fool around with this stuff.
+ */
+
+/* APP side SYSCON registers */
+/* TODO: this is incomplete. Add all from asic_syscon_map.h eventually. */
+/* CLK Control Register 16bit (R/W) */
+#define U300_SYSCON_CCR                                                (0x0000)
+#define U300_SYSCON_CCR_I2S1_USE_VCXO                          (0x0040)
+#define U300_SYSCON_CCR_I2S0_USE_VCXO                          (0x0020)
+#define U300_SYSCON_CCR_TURN_VCXO_ON                           (0x0008)
+#define U300_SYSCON_CCR_CLKING_PERFORMANCE_MASK                        (0x0007)
+#define U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER           (0x04)
+#define U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW                 (0x03)
+#define U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE                (0x02)
+#define U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH                        (0x01)
+#define U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST                        (0x00)
+/* CLK Status Register 16bit (R/W) */
+#define U300_SYSCON_CSR                                                (0x0004)
+#define U300_SYSCON_CSR_PLL208_LOCK_IND                                (0x0002)
+#define U300_SYSCON_CSR_PLL13_LOCK_IND                         (0x0001)
+/* Reset lines for SLOW devices 16bit (R/W) */
+#define U300_SYSCON_RSR                                                (0x0014)
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_SYSCON_RSR_PPM_RESET_EN                           (0x0200)
+#endif
+#define U300_SYSCON_RSR_ACC_TMR_RESET_EN                       (0x0100)
+#define U300_SYSCON_RSR_APP_TMR_RESET_EN                       (0x0080)
+#define U300_SYSCON_RSR_RTC_RESET_EN                           (0x0040)
+#define U300_SYSCON_RSR_KEYPAD_RESET_EN                                (0x0020)
+#define U300_SYSCON_RSR_GPIO_RESET_EN                          (0x0010)
+#define U300_SYSCON_RSR_EH_RESET_EN                            (0x0008)
+#define U300_SYSCON_RSR_BTR_RESET_EN                           (0x0004)
+#define U300_SYSCON_RSR_UART_RESET_EN                          (0x0002)
+#define U300_SYSCON_RSR_SLOW_BRIDGE_RESET_EN                   (0x0001)
+/* Reset lines for FAST devices 16bit (R/W) */
+#define U300_SYSCON_RFR                                                (0x0018)
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_SYSCON_RFR_UART1_RESET_ENABLE                     (0x0080)
+#endif
+#define U300_SYSCON_RFR_SPI_RESET_ENABLE                       (0x0040)
+#define U300_SYSCON_RFR_MMC_RESET_ENABLE                       (0x0020)
+#define U300_SYSCON_RFR_PCM_I2S1_RESET_ENABLE                  (0x0010)
+#define U300_SYSCON_RFR_PCM_I2S0_RESET_ENABLE                  (0x0008)
+#define U300_SYSCON_RFR_I2C1_RESET_ENABLE                      (0x0004)
+#define U300_SYSCON_RFR_I2C0_RESET_ENABLE                      (0x0002)
+#define U300_SYSCON_RFR_FAST_BRIDGE_RESET_ENABLE               (0x0001)
+/* Reset lines for the rest of the peripherals 16bit (R/W) */
+#define U300_SYSCON_RRR                                                (0x001c)
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_SYSCON_RRR_CDS_RESET_EN                           (0x4000)
+#define U300_SYSCON_RRR_ISP_RESET_EN                           (0x2000)
+#endif
+#define U300_SYSCON_RRR_INTCON_RESET_EN                                (0x1000)
+#define U300_SYSCON_RRR_MSPRO_RESET_EN                         (0x0800)
+#define U300_SYSCON_RRR_XGAM_RESET_EN                          (0x0100)
+#define U300_SYSCON_RRR_XGAM_VC_SYNC_RESET_EN                  (0x0080)
+#define U300_SYSCON_RRR_NANDIF_RESET_EN                                (0x0040)
+#define U300_SYSCON_RRR_EMIF_RESET_EN                          (0x0020)
+#define U300_SYSCON_RRR_DMAC_RESET_EN                          (0x0010)
+#define U300_SYSCON_RRR_CPU_RESET_EN                           (0x0008)
+#define U300_SYSCON_RRR_APEX_RESET_EN                          (0x0004)
+#define U300_SYSCON_RRR_AHB_RESET_EN                           (0x0002)
+#define U300_SYSCON_RRR_AAIF_RESET_EN                          (0x0001)
+/* Clock enable for SLOW peripherals 16bit (R/W) */
+#define U300_SYSCON_CESR                                       (0x0020)
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_SYSCON_CESR_PPM_CLK_EN                            (0x0200)
+#endif
+#define U300_SYSCON_CESR_ACC_TMR_CLK_EN                                (0x0100)
+#define U300_SYSCON_CESR_APP_TMR_CLK_EN                                (0x0080)
+#define U300_SYSCON_CESR_KEYPAD_CLK_EN                         (0x0040)
+#define U300_SYSCON_CESR_GPIO_CLK_EN                           (0x0010)
+#define U300_SYSCON_CESR_EH_CLK_EN                             (0x0008)
+#define U300_SYSCON_CESR_BTR_CLK_EN                            (0x0004)
+#define U300_SYSCON_CESR_UART_CLK_EN                           (0x0002)
+#define U300_SYSCON_CESR_SLOW_BRIDGE_CLK_EN                    (0x0001)
+/* Clock enable for FAST peripherals 16bit (R/W) */
+#define U300_SYSCON_CEFR                                       (0x0024)
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_SYSCON_CEFR_UART1_CLK_EN                          (0x0200)
+#endif
+#define U300_SYSCON_CEFR_I2S1_CORE_CLK_EN                      (0x0100)
+#define U300_SYSCON_CEFR_I2S0_CORE_CLK_EN                      (0x0080)
+#define U300_SYSCON_CEFR_SPI_CLK_EN                            (0x0040)
+#define U300_SYSCON_CEFR_MMC_CLK_EN                            (0x0020)
+#define U300_SYSCON_CEFR_I2S1_CLK_EN                           (0x0010)
+#define U300_SYSCON_CEFR_I2S0_CLK_EN                           (0x0008)
+#define U300_SYSCON_CEFR_I2C1_CLK_EN                           (0x0004)
+#define U300_SYSCON_CEFR_I2C0_CLK_EN                           (0x0002)
+#define U300_SYSCON_CEFR_FAST_BRIDGE_CLK_EN                    (0x0001)
+/* Clock enable for the rest of the peripherals 16bit (R/W) */
+#define U300_SYSCON_CERR                                       (0x0028)
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_SYSCON_CERR_CDS_CLK_EN                            (0x2000)
+#define U300_SYSCON_CERR_ISP_CLK_EN                            (0x1000)
+#endif
+#define U300_SYSCON_CERR_MSPRO_CLK_EN                          (0x0800)
+#define U300_SYSCON_CERR_AHB_SUBSYS_BRIDGE_CLK_EN              (0x0400)
+#define U300_SYSCON_CERR_SEMI_CLK_EN                           (0x0200)
+#define U300_SYSCON_CERR_XGAM_CLK_EN                           (0x0100)
+#define U300_SYSCON_CERR_VIDEO_ENC_CLK_EN                      (0x0080)
+#define U300_SYSCON_CERR_NANDIF_CLK_EN                         (0x0040)
+#define U300_SYSCON_CERR_EMIF_CLK_EN                           (0x0020)
+#define U300_SYSCON_CERR_DMAC_CLK_EN                           (0x0010)
+#define U300_SYSCON_CERR_CPU_CLK_EN                            (0x0008)
+#define U300_SYSCON_CERR_APEX_CLK_EN                           (0x0004)
+#define U300_SYSCON_CERR_AHB_CLK_EN                            (0x0002)
+#define U300_SYSCON_CERR_AAIF_CLK_EN                           (0x0001)
+/* Single block clock enable 16bit (-/W) */
+#define U300_SYSCON_SBCER                                      (0x002c)
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_SYSCON_SBCER_PPM_CLK_EN                           (0x0009)
+#endif
+#define U300_SYSCON_SBCER_ACC_TMR_CLK_EN                       (0x0008)
+#define U300_SYSCON_SBCER_APP_TMR_CLK_EN                       (0x0007)
+#define U300_SYSCON_SBCER_KEYPAD_CLK_EN                                (0x0006)
+#define U300_SYSCON_SBCER_GPIO_CLK_EN                          (0x0004)
+#define U300_SYSCON_SBCER_EH_CLK_EN                            (0x0003)
+#define U300_SYSCON_SBCER_BTR_CLK_EN                           (0x0002)
+#define U300_SYSCON_SBCER_UART_CLK_EN                          (0x0001)
+#define U300_SYSCON_SBCER_SLOW_BRIDGE_CLK_EN                   (0x0000)
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_SYSCON_SBCER_UART1_CLK_EN                         (0x0019)
+#endif
+#define U300_SYSCON_SBCER_I2S1_CORE_CLK_EN                     (0x0018)
+#define U300_SYSCON_SBCER_I2S0_CORE_CLK_EN                     (0x0017)
+#define U300_SYSCON_SBCER_SPI_CLK_EN                           (0x0016)
+#define U300_SYSCON_SBCER_MMC_CLK_EN                           (0x0015)
+#define U300_SYSCON_SBCER_I2S1_CLK_EN                          (0x0014)
+#define U300_SYSCON_SBCER_I2S0_CLK_EN                          (0x0013)
+#define U300_SYSCON_SBCER_I2C1_CLK_EN                          (0x0012)
+#define U300_SYSCON_SBCER_I2C0_CLK_EN                          (0x0011)
+#define U300_SYSCON_SBCER_FAST_BRIDGE_CLK_EN                   (0x0010)
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_SYSCON_SBCER_CDS_CLK_EN                           (0x002D)
+#define U300_SYSCON_SBCER_ISP_CLK_EN                           (0x002C)
+#endif
+#define U300_SYSCON_SBCER_MSPRO_CLK_EN                         (0x002B)
+#define U300_SYSCON_SBCER_AHB_SUBSYS_BRIDGE_CLK_EN             (0x002A)
+#define U300_SYSCON_SBCER_SEMI_CLK_EN                          (0x0029)
+#define U300_SYSCON_SBCER_XGAM_CLK_EN                          (0x0028)
+#define U300_SYSCON_SBCER_VIDEO_ENC_CLK_EN                     (0x0027)
+#define U300_SYSCON_SBCER_NANDIF_CLK_EN                                (0x0026)
+#define U300_SYSCON_SBCER_EMIF_CLK_EN                          (0x0025)
+#define U300_SYSCON_SBCER_DMAC_CLK_EN                          (0x0024)
+#define U300_SYSCON_SBCER_CPU_CLK_EN                           (0x0023)
+#define U300_SYSCON_SBCER_APEX_CLK_EN                          (0x0022)
+#define U300_SYSCON_SBCER_AHB_CLK_EN                           (0x0021)
+#define U300_SYSCON_SBCER_AAIF_CLK_EN                          (0x0020)
+/* Single block clock disable 16bit (-/W) */
+#define U300_SYSCON_SBCDR                                      (0x0030)
+/* Same values as above for SBCER */
+/* Clock force SLOW peripherals 16bit (R/W) */
+#define U300_SYSCON_CFSR                                       (0x003c)
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_SYSCON_CFSR_PPM_CLK_FORCE_EN                      (0x0200)
+#endif
+#define U300_SYSCON_CFSR_ACC_TMR_CLK_FORCE_EN                  (0x0100)
+#define U300_SYSCON_CFSR_APP_TMR_CLK_FORCE_EN                  (0x0080)
+#define U300_SYSCON_CFSR_KEYPAD_CLK_FORCE_EN                   (0x0020)
+#define U300_SYSCON_CFSR_GPIO_CLK_FORCE_EN                     (0x0010)
+#define U300_SYSCON_CFSR_EH_CLK_FORCE_EN                       (0x0008)
+#define U300_SYSCON_CFSR_BTR_CLK_FORCE_EN                      (0x0004)
+#define U300_SYSCON_CFSR_UART_CLK_FORCE_EN                     (0x0002)
+#define U300_SYSCON_CFSR_SLOW_BRIDGE_CLK_FORCE_EN              (0x0001)
+/* Clock force FAST peripherals 16bit (R/W) */
+#define U300_SYSCON_CFFR                                       (0x40)
+/* Values not defined. Define if you want to use them. */
+/* Clock force the rest of the peripherals 16bit (R/W) */
+#define U300_SYSCON_CFRR                                       (0x44)
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_SYSCON_CFRR_CDS_CLK_FORCE_EN                      (0x2000)
+#define U300_SYSCON_CFRR_ISP_CLK_FORCE_EN                      (0x1000)
+#endif
+#define U300_SYSCON_CFRR_MSPRO_CLK_FORCE_EN                    (0x0800)
+#define U300_SYSCON_CFRR_AHB_SUBSYS_BRIDGE_CLK_FORCE_EN                (0x0400)
+#define U300_SYSCON_CFRR_SEMI_CLK_FORCE_EN                     (0x0200)
+#define U300_SYSCON_CFRR_XGAM_CLK_FORCE_EN                     (0x0100)
+#define U300_SYSCON_CFRR_VIDEO_ENC_CLK_FORCE_EN                        (0x0080)
+#define U300_SYSCON_CFRR_NANDIF_CLK_FORCE_EN                   (0x0040)
+#define U300_SYSCON_CFRR_EMIF_CLK_FORCE_EN                     (0x0020)
+#define U300_SYSCON_CFRR_DMAC_CLK_FORCE_EN                     (0x0010)
+#define U300_SYSCON_CFRR_CPU_CLK_FORCE_EN                      (0x0008)
+#define U300_SYSCON_CFRR_APEX_CLK_FORCE_EN                     (0x0004)
+#define U300_SYSCON_CFRR_AHB_CLK_FORCE_EN                      (0x0002)
+#define U300_SYSCON_CFRR_AAIF_CLK_FORCE_EN                     (0x0001)
+/* PLL208 Frequency Control 16bit (R/W) */
+#define U300_SYSCON_PFCR                                       (0x48)
+#define U300_SYSCON_PFCR_DPLL_MULT_NUM                         (0x000F)
+/* Power Management Control 16bit (R/W) */
+#define U300_SYSCON_PMCR                                       (0x50)
+#define U300_SYSCON_PMCR_DCON_ENABLE                           (0x0002)
+#define U300_SYSCON_PMCR_PWR_MGNT_ENABLE                       (0x0001)
+/*
+ * All other clocking registers moved to clock.c!
+ */
+/* Reset Out 16bit (R/W) */
+#define U300_SYSCON_RCR                                                (0x6c)
+#define U300_SYSCON_RCR_RESOUT0_RST_N_DISABLE                  (0x0001)
+/* EMIF Slew Rate Control 16bit (R/W) */
+#define U300_SYSCON_SRCLR                                      (0x70)
+#define U300_SYSCON_SRCLR_MASK                                 (0x03FF)
+#define U300_SYSCON_SRCLR_VALUE                                        (0x03FF)
+#define U300_SYSCON_SRCLR_EMIF_1_SLRC_5_B                      (0x0200)
+#define U300_SYSCON_SRCLR_EMIF_1_SLRC_5_A                      (0x0100)
+#define U300_SYSCON_SRCLR_EMIF_1_SLRC_4_B                      (0x0080)
+#define U300_SYSCON_SRCLR_EMIF_1_SLRC_4_A                      (0x0040)
+#define U300_SYSCON_SRCLR_EMIF_1_SLRC_3_B                      (0x0020)
+#define U300_SYSCON_SRCLR_EMIF_1_SLRC_3_A                      (0x0010)
+#define U300_SYSCON_SRCLR_EMIF_1_SLRC_2_B                      (0x0008)
+#define U300_SYSCON_SRCLR_EMIF_1_SLRC_2_A                      (0x0004)
+#define U300_SYSCON_SRCLR_EMIF_1_SLRC_1_B                      (0x0002)
+#define U300_SYSCON_SRCLR_EMIF_1_SLRC_1_A                      (0x0001)
+/* EMIF Clock Control Register 16bit (R/W) */
+#define U300_SYSCON_ECCR                                       (0x0078)
+#define U300_SYSCON_ECCR_MASK                                  (0x000F)
+#define U300_SYSCON_ECCR_EMIF_1_STATIC_CLK_EN_N_DISABLE                (0x0008)
+#define U300_SYSCON_ECCR_EMIF_1_RET_OUT_CLK_EN_N_DISABLE       (0x0004)
+#define U300_SYSCON_ECCR_EMIF_MEMCLK_RET_EN_N_DISABLE          (0x0002)
+#define U300_SYSCON_ECCR_EMIF_SDRCLK_RET_EN_N_DISABLE          (0x0001)
+/* PAD MUX Control register 1 (LOW) 16bit (R/W) */
+#define U300_SYSCON_PMC1LR                                     (0x007C)
+#define U300_SYSCON_PMC1LR_MASK                                        (0xFFFF)
+#define U300_SYSCON_PMC1LR_CDI_MASK                            (0xC000)
+#define U300_SYSCON_PMC1LR_CDI_CDI                             (0x0000)
+#define U300_SYSCON_PMC1LR_CDI_EMIF                            (0x4000)
+#define U300_SYSCON_PMC1LR_CDI_GPIO                            (0x8000)
+#define U300_SYSCON_PMC1LR_CDI_WCDMA                           (0xC000)
+#define U300_SYSCON_PMC1LR_PDI_MASK                            (0x3000)
+#define U300_SYSCON_PMC1LR_PDI_PDI                             (0x0000)
+#define U300_SYSCON_PMC1LR_PDI_EGG                             (0x1000)
+#define U300_SYSCON_PMC1LR_PDI_WCDMA                           (0x3000)
+#define U300_SYSCON_PMC1LR_MMCSD_MASK                          (0x0C00)
+#define U300_SYSCON_PMC1LR_MMCSD_MMCSD                         (0x0000)
+#define U300_SYSCON_PMC1LR_MMCSD_MSPRO                         (0x0400)
+#define U300_SYSCON_PMC1LR_MMCSD_DSP                           (0x0800)
+#define U300_SYSCON_PMC1LR_MMCSD_WCDMA                         (0x0C00)
+#define U300_SYSCON_PMC1LR_ETM_MASK                            (0x0300)
+#define U300_SYSCON_PMC1LR_ETM_ACC                             (0x0000)
+#define U300_SYSCON_PMC1LR_ETM_APP                             (0x0100)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS2_MASK                     (0x00C0)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS2_STATIC                   (0x0000)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS2_NFIF                     (0x0040)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS2_SDRAM                    (0x0080)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS2_STATIC_2GB               (0x00C0)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS1_MASK                     (0x0030)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS1_STATIC                   (0x0000)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS1_NFIF                     (0x0010)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS1_SDRAM                    (0x0020)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS1_SEMI                     (0x0030)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS0_MASK                     (0x000C)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS0_STATIC                   (0x0000)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS0_NFIF                     (0x0004)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS0_SDRAM                    (0x0008)
+#define U300_SYSCON_PMC1LR_EMIF_1_CS0_SEMI                     (0x000C)
+#define U300_SYSCON_PMC1LR_EMIF_1_MASK                         (0x0003)
+#define U300_SYSCON_PMC1LR_EMIF_1_STATIC                       (0x0000)
+#define U300_SYSCON_PMC1LR_EMIF_1_SDRAM0                       (0x0001)
+#define U300_SYSCON_PMC1LR_EMIF_1_SDRAM1                       (0x0002)
+#define U300_SYSCON_PMC1LR_EMIF_1                              (0x0003)
+/* PAD MUX Control register 2 (HIGH) 16bit (R/W) */
+#define U300_SYSCON_PMC1HR                                     (0x007E)
+#define U300_SYSCON_PMC1HR_MASK                                        (0xFFFF)
+#define U300_SYSCON_PMC1HR_MISC_2_MASK                         (0xC000)
+#define U300_SYSCON_PMC1HR_MISC_2_APP_GPIO                     (0x0000)
+#define U300_SYSCON_PMC1HR_MISC_2_MSPRO                                (0x4000)
+#define U300_SYSCON_PMC1HR_MISC_2_DSP                          (0x8000)
+#define U300_SYSCON_PMC1HR_MISC_2_AAIF                         (0xC000)
+#define U300_SYSCON_PMC1HR_APP_GPIO_2_MASK                     (0x3000)
+#define U300_SYSCON_PMC1HR_APP_GPIO_2_APP_GPIO                 (0x0000)
+#define U300_SYSCON_PMC1HR_APP_GPIO_2_NFIF                     (0x1000)
+#define U300_SYSCON_PMC1HR_APP_GPIO_2_DSP                      (0x2000)
+#define U300_SYSCON_PMC1HR_APP_GPIO_2_AAIF                     (0x3000)
+#define U300_SYSCON_PMC1HR_APP_GPIO_1_MASK                     (0x0C00)
+#define U300_SYSCON_PMC1HR_APP_GPIO_1_APP_GPIO                 (0x0000)
+#define U300_SYSCON_PMC1HR_APP_GPIO_1_MMC                      (0x0400)
+#define U300_SYSCON_PMC1HR_APP_GPIO_1_DSP                      (0x0800)
+#define U300_SYSCON_PMC1HR_APP_GPIO_1_AAIF                     (0x0C00)
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_2_MASK                   (0x0300)
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_2_APP_GPIO               (0x0000)
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_2_SPI                    (0x0100)
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_2_AAIF                   (0x0300)
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_1_MASK                   (0x00C0)
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_1_APP_GPIO               (0x0000)
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_1_SPI                    (0x0040)
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_1_AAIF                   (0x00C0)
+#define U300_SYSCON_PMC1HR_APP_SPI_2_MASK                      (0x0030)
+#define U300_SYSCON_PMC1HR_APP_SPI_2_APP_GPIO                  (0x0000)
+#define U300_SYSCON_PMC1HR_APP_SPI_2_SPI                       (0x0010)
+#define U300_SYSCON_PMC1HR_APP_SPI_2_DSP                       (0x0020)
+#define U300_SYSCON_PMC1HR_APP_SPI_2_AAIF                      (0x0030)
+#define U300_SYSCON_PMC1HR_APP_UART0_2_MASK                    (0x000C)
+#define U300_SYSCON_PMC1HR_APP_UART0_2_APP_GPIO                        (0x0000)
+#define U300_SYSCON_PMC1HR_APP_UART0_2_UART0                   (0x0004)
+#define U300_SYSCON_PMC1HR_APP_UART0_2_NFIF_CS                 (0x0008)
+#define U300_SYSCON_PMC1HR_APP_UART0_2_AAIF                    (0x000C)
+#define U300_SYSCON_PMC1HR_APP_UART0_1_MASK                    (0x0003)
+#define U300_SYSCON_PMC1HR_APP_UART0_1_APP_GPIO                        (0x0000)
+#define U300_SYSCON_PMC1HR_APP_UART0_1_UART0                   (0x0001)
+#define U300_SYSCON_PMC1HR_APP_UART0_1_AAIF                    (0x0003)
+/* Step one for killing the applications system 16bit (-/W) */
+#define U300_SYSCON_KA1R                                       (0x0080)
+#define U300_SYSCON_KA1R_MASK                                  (0xFFFF)
+#define U300_SYSCON_KA1R_VALUE                                 (0xFFFF)
+/* Step two for killing the application system 16bit (-/W) */
+#define U300_SYSCON_KA2R                                       (0x0084)
+#define U300_SYSCON_KA2R_MASK                                  (0xFFFF)
+#define U300_SYSCON_KA2R_VALUE                                 (0xFFFF)
+/* MMC/MSPRO frequency divider register 0 16bit (R/W) */
+#define U300_SYSCON_MMF0R                                      (0x90)
+#define U300_SYSCON_MMF0R_MASK                                 (0x00FF)
+#define U300_SYSCON_MMF0R_FREQ_0_HIGH_MASK                     (0x00F0)
+#define U300_SYSCON_MMF0R_FREQ_0_LOW_MASK                      (0x000F)
+/* MMC/MSPRO frequency divider register 1 16bit (R/W) */
+#define U300_SYSCON_MMF1R                                      (0x94)
+#define U300_SYSCON_MMF1R_MASK                                 (0x00FF)
+#define U300_SYSCON_MMF1R_FREQ_1_HIGH_MASK                     (0x00F0)
+#define U300_SYSCON_MMF1R_FREQ_1_LOW_MASK                      (0x000F)
+/* AAIF control register 16 bit (R/W) */
+#define U300_SYSCON_AAIFCR                                     (0x98)
+#define U300_SYSCON_AAIFCR_MASK                                        (0x0003)
+#define U300_SYSCON_AAIFCR_AASW_CTRL_MASK                      (0x0003)
+#define U300_SYSCON_AAIFCR_AASW_CTRL_FUNCTIONAL                        (0x0000)
+#define U300_SYSCON_AAIFCR_AASW_CTRL_MONITORING                        (0x0001)
+#define U300_SYSCON_AAIFCR_AASW_CTRL_ACC_TO_EXT                        (0x0002)
+#define U300_SYSCON_AAIFCR_AASW_CTRL_APP_TO_EXT                        (0x0003)
+/* Clock control for the MMC and MSPRO blocks 16bit (R/W) */
+#define U300_SYSCON_MMCR                                       (0x9C)
+#define U300_SYSCON_MMCR_MASK                                  (0x0003)
+#define U300_SYSCON_MMCR_MMC_FB_CLK_SEL_ENABLE                 (0x0002)
+#define U300_SYSCON_MMCR_MSPRO_FREQSEL_ENABLE                  (0x0001)
+
+/* TODO: More SYSCON registers missing */
+#define U300_SYSCON_PMC3R                                      (0x10c)
+#define U300_SYSCON_PMC3R_APP_MISC_11_MASK                     (0xc000)
+#define U300_SYSCON_PMC3R_APP_MISC_11_SPI                      (0x4000)
+#define U300_SYSCON_PMC3R_APP_MISC_10_MASK                     (0x3000)
+#define U300_SYSCON_PMC3R_APP_MISC_10_SPI                      (0x1000)
+/* TODO: Missing other configs, I just added the SPI stuff */
+
+/* SYS_0_CLK_CONTROL first clock control 16bit (R/W) */
+#define U300_SYSCON_S0CCR                                      (0x120)
+#define U300_SYSCON_S0CCR_FIELD_MASK                           (0x43FF)
+#define U300_SYSCON_S0CCR_CLOCK_REQ                            (0x4000)
+#define U300_SYSCON_S0CCR_CLOCK_INV                            (0x0200)
+#define U300_SYSCON_S0CCR_CLOCK_FREQ_MASK                      (0x01E0)
+#define U300_SYSCON_S0CCR_CLOCK_SELECT_MASK                    (0x001E)
+#define U300_SYSCON_S0CCR_CLOCK_ENABLE                         (0x0001)
+#define U300_SYSCON_S0CCR_SEL_MCLK                             (0x8<<1)
+#define U300_SYSCON_S0CCR_SEL_ACC_FSM_CLK                      (0xA<<1)
+#define U300_SYSCON_S0CCR_SEL_PLL60_48_CLK                     (0xC<<1)
+#define U300_SYSCON_S0CCR_SEL_PLL60_60_CLK                     (0xD<<1)
+#define U300_SYSCON_S0CCR_SEL_ACC_PLL208_CLK                   (0xE<<1)
+#define U300_SYSCON_S0CCR_SEL_APP_PLL13_CLK                    (0x0<<1)
+#define U300_SYSCON_S0CCR_SEL_APP_FSM_CLK                      (0x2<<1)
+#define U300_SYSCON_S0CCR_SEL_RTC_CLK                          (0x4<<1)
+#define U300_SYSCON_S0CCR_SEL_APP_PLL208_CLK                   (0x6<<1)
+/* SYS_1_CLK_CONTROL second clock control 16 bit (R/W) */
+#define U300_SYSCON_S1CCR                                      (0x124)
+#define U300_SYSCON_S1CCR_FIELD_MASK                           (0x43FF)
+#define U300_SYSCON_S1CCR_CLOCK_REQ                            (0x4000)
+#define U300_SYSCON_S1CCR_CLOCK_INV                            (0x0200)
+#define U300_SYSCON_S1CCR_CLOCK_FREQ_MASK                      (0x01E0)
+#define U300_SYSCON_S1CCR_CLOCK_SELECT_MASK                    (0x001E)
+#define U300_SYSCON_S1CCR_CLOCK_ENABLE                         (0x0001)
+#define U300_SYSCON_S1CCR_SEL_MCLK                             (0x8<<1)
+#define U300_SYSCON_S1CCR_SEL_ACC_FSM_CLK                      (0xA<<1)
+#define U300_SYSCON_S1CCR_SEL_PLL60_48_CLK                     (0xC<<1)
+#define U300_SYSCON_S1CCR_SEL_PLL60_60_CLK                     (0xD<<1)
+#define U300_SYSCON_S1CCR_SEL_ACC_PLL208_CLK                   (0xE<<1)
+#define U300_SYSCON_S1CCR_SEL_ACC_PLL13_CLK                    (0x0<<1)
+#define U300_SYSCON_S1CCR_SEL_APP_FSM_CLK                      (0x2<<1)
+#define U300_SYSCON_S1CCR_SEL_RTC_CLK                          (0x4<<1)
+#define U300_SYSCON_S1CCR_SEL_APP_PLL208_CLK                   (0x6<<1)
+/* SYS_2_CLK_CONTROL third clock contol 16 bit (R/W) */
+#define U300_SYSCON_S2CCR                                      (0x128)
+#define U300_SYSCON_S2CCR_FIELD_MASK                           (0xC3FF)
+#define U300_SYSCON_S2CCR_CLK_STEAL                            (0x8000)
+#define U300_SYSCON_S2CCR_CLOCK_REQ                            (0x4000)
+#define U300_SYSCON_S2CCR_CLOCK_INV                            (0x0200)
+#define U300_SYSCON_S2CCR_CLOCK_FREQ_MASK                      (0x01E0)
+#define U300_SYSCON_S2CCR_CLOCK_SELECT_MASK                    (0x001E)
+#define U300_SYSCON_S2CCR_CLOCK_ENABLE                         (0x0001)
+#define U300_SYSCON_S2CCR_SEL_MCLK                             (0x8<<1)
+#define U300_SYSCON_S2CCR_SEL_ACC_FSM_CLK                      (0xA<<1)
+#define U300_SYSCON_S2CCR_SEL_PLL60_48_CLK                     (0xC<<1)
+#define U300_SYSCON_S2CCR_SEL_PLL60_60_CLK                     (0xD<<1)
+#define U300_SYSCON_S2CCR_SEL_ACC_PLL208_CLK                   (0xE<<1)
+#define U300_SYSCON_S2CCR_SEL_ACC_PLL13_CLK                    (0x0<<1)
+#define U300_SYSCON_S2CCR_SEL_APP_FSM_CLK                      (0x2<<1)
+#define U300_SYSCON_S2CCR_SEL_RTC_CLK                          (0x4<<1)
+#define U300_SYSCON_S2CCR_SEL_APP_PLL208_CLK                   (0x6<<1)
+/* SYS_MISC_CONTROL, miscellaneous 16bit (R/W) */
+#define U300_SYSCON_MCR                                                (0x12c)
+#define U300_SYSCON_MCR_FIELD_MASK                             (0x00FF)
+#define U300_SYSCON_MCR_PMGEN_CR_4_MASK                                (0x00C0)
+#define U300_SYSCON_MCR_PMGEN_CR_4_GPIO                                (0x0000)
+#define U300_SYSCON_MCR_PMGEN_CR_4_SPI                         (0x0040)
+#define U300_SYSCON_MCR_PMGEN_CR_4_AAIF                                (0x00C0)
+#define U300_SYSCON_MCR_PMGEN_CR_2_MASK                                (0x0030)
+#define U300_SYSCON_MCR_PMGEN_CR_2_GPIO                                (0x0000)
+#define U300_SYSCON_MCR_PMGEN_CR_2_EMIF_1_STATIC               (0x0010)
+#define U300_SYSCON_MCR_PMGEN_CR_2_DSP                         (0x0020)
+#define U300_SYSCON_MCR_PMGEN_CR_2_AAIF                                (0x0030)
+#define U300_SYSCON_MCR_PMGEN_CR_0_MASK                                (0x000C)
+#define U300_SYSCON_MCR_PMGEN_CR_0_EMIF_1_SDRAM_M1             (0x0000)
+#define U300_SYSCON_MCR_PMGEN_CR_0_EMIF_1_SDRAM_M2             (0x0004)
+#define U300_SYSCON_MCR_PMGEN_CR_0_EMIF_1_SDRAM_M3             (0x0008)
+#define U300_SYSCON_MCR_PMGEN_CR_0_EMIF_0_SDRAM                        (0x000C)
+#define U300_SYSCON_MCR_PM1G_MODE_ENABLE                       (0x0002)
+#define U300_SYSCON_MCR_PMTG5_MODE_ENABLE                      (0x0001)
+/* Clock activity observability register 0 */
+#define U300_SYSCON_C0OAR                                      (0x140)
+#define U300_SYSCON_C0OAR_MASK                                 (0xFFFF)
+#define U300_SYSCON_C0OAR_VALUE                                        (0xFFFF)
+#define U300_SYSCON_C0OAR_BT_H_CLK                             (0x8000)
+#define U300_SYSCON_C0OAR_ASPB_P_CLK                           (0x4000)
+#define U300_SYSCON_C0OAR_APP_SEMI_H_CLK                       (0x2000)
+#define U300_SYSCON_C0OAR_APP_SEMI_CLK                         (0x1000)
+#define U300_SYSCON_C0OAR_APP_MMC_MSPRO_CLK                    (0x0800)
+#define U300_SYSCON_C0OAR_APP_I2S1_CLK                         (0x0400)
+#define U300_SYSCON_C0OAR_APP_I2S0_CLK                         (0x0200)
+#define U300_SYSCON_C0OAR_APP_CPU_CLK                          (0x0100)
+#define U300_SYSCON_C0OAR_APP_52_CLK                           (0x0080)
+#define U300_SYSCON_C0OAR_APP_208_CLK                          (0x0040)
+#define U300_SYSCON_C0OAR_APP_104_CLK                          (0x0020)
+#define U300_SYSCON_C0OAR_APEX_CLK                             (0x0010)
+#define U300_SYSCON_C0OAR_AHPB_M_H_CLK                         (0x0008)
+#define U300_SYSCON_C0OAR_AHB_CLK                              (0x0004)
+#define U300_SYSCON_C0OAR_AFPB_P_CLK                           (0x0002)
+#define U300_SYSCON_C0OAR_AAIF_CLK                             (0x0001)
+/* Clock activity observability register 1 */
+#define U300_SYSCON_C1OAR                                      (0x144)
+#define U300_SYSCON_C1OAR_MASK                                 (0x3FFE)
+#define U300_SYSCON_C1OAR_VALUE                                        (0x3FFE)
+#define U300_SYSCON_C1OAR_NFIF_F_CLK                           (0x2000)
+#define U300_SYSCON_C1OAR_MSPRO_CLK                            (0x1000)
+#define U300_SYSCON_C1OAR_MMC_P_CLK                            (0x0800)
+#define U300_SYSCON_C1OAR_MMC_CLK                              (0x0400)
+#define U300_SYSCON_C1OAR_KP_P_CLK                             (0x0200)
+#define U300_SYSCON_C1OAR_I2C1_P_CLK                           (0x0100)
+#define U300_SYSCON_C1OAR_I2C0_P_CLK                           (0x0080)
+#define U300_SYSCON_C1OAR_GPIO_CLK                             (0x0040)
+#define U300_SYSCON_C1OAR_EMIF_MPMC_CLK                                (0x0020)
+#define U300_SYSCON_C1OAR_EMIF_H_CLK                           (0x0010)
+#define U300_SYSCON_C1OAR_EVHIST_CLK                           (0x0008)
+#define U300_SYSCON_C1OAR_PPM_CLK                              (0x0004)
+#define U300_SYSCON_C1OAR_DMA_CLK                              (0x0002)
+/* Clock activity observability register 2 */
+#define U300_SYSCON_C2OAR                                      (0x148)
+#define U300_SYSCON_C2OAR_MASK                                 (0x0FFF)
+#define U300_SYSCON_C2OAR_VALUE                                        (0x0FFF)
+#define U300_SYSCON_C2OAR_XGAM_CDI_CLK                         (0x0800)
+#define U300_SYSCON_C2OAR_XGAM_CLK                             (0x0400)
+#define U300_SYSCON_C2OAR_VC_H_CLK                             (0x0200)
+#define U300_SYSCON_C2OAR_VC_CLK                               (0x0100)
+#define U300_SYSCON_C2OAR_UA_P_CLK                             (0x0080)
+#define U300_SYSCON_C2OAR_TMR1_CLK                             (0x0040)
+#define U300_SYSCON_C2OAR_TMR0_CLK                             (0x0020)
+#define U300_SYSCON_C2OAR_SPI_P_CLK                            (0x0010)
+#define U300_SYSCON_C2OAR_PCM_I2S1_CORE_CLK                    (0x0008)
+#define U300_SYSCON_C2OAR_PCM_I2S1_CLK                         (0x0004)
+#define U300_SYSCON_C2OAR_PCM_I2S0_CORE_CLK                    (0x0002)
+#define U300_SYSCON_C2OAR_PCM_I2S0_CLK                         (0x0001)
+
+/* Chip ID register 16bit (R/-) */
+#define U300_SYSCON_CIDR                                       (0x400)
+/* Video IRQ clear 16bit (R/W) */
+#define U300_SYSCON_VICR                                       (0x404)
+#define U300_SYSCON_VICR_VIDEO1_IRQ_CLEAR_ENABLE               (0x0002)
+#define U300_SYSCON_VICR_VIDEO0_IRQ_CLEAR_ENABLE               (0x0001)
+/* SMCR */
+#define U300_SYSCON_SMCR                                       (0x4d0)
+#define U300_SYSCON_SMCR_FIELD_MASK                            (0x000e)
+#define U300_SYSCON_SMCR_SEMI_SREFACK_IND                      (0x0008)
+#define U300_SYSCON_SMCR_SEMI_SREFREQ_ENABLE                   (0x0004)
+#define U300_SYSCON_SMCR_SEMI_EXT_BOOT_MODE_ENABLE             (0x0002)
+/* CPU_SW_DBGEN Software Debug Enable 16bit (R/W) */
+#define U300_SYSCON_CSDR                                       (0x4f0)
+#define U300_SYSCON_CSDR_SW_DEBUG_ENABLE                       (0x0001)
+/* PRINT_CONTROL Print Control 16bit (R/-) */
+#define U300_SYSCON_PCR                                                (0x4f8)
+#define U300_SYSCON_PCR_SERV_IND                               (0x0001)
+/* BOOT_CONTROL 16bit (R/-) */
+#define U300_SYSCON_BCR                                                (0x4fc)
+#define U300_SYSCON_BCR_ACC_CPU_SUBSYS_VINITHI_IND             (0x0400)
+#define U300_SYSCON_BCR_APP_CPU_SUBSYS_VINITHI_IND             (0x0200)
+#define U300_SYSCON_BCR_EXTRA_BOOT_OPTION_MASK                 (0x01FC)
+#define U300_SYSCON_BCR_APP_BOOT_SERV_MASK                     (0x0003)
+
+
+/* CPU clock defines */
+/**
+ * CPU high frequency in MHz
+ */
+#define SYSCON_CPU_CLOCK_HIGH    208
+/**
+ * CPU medium frequency in MHz
+ */
+#define SYSCON_CPU_CLOCK_MEDIUM  104
+/**
+ * CPU low frequency in MHz
+ */
+#define SYSCON_CPU_CLOCK_LOW      13
+
+/* EMIF clock defines */
+/**
+ * EMIF high frequency in MHz
+ */
+#define SYSCON_EMIF_CLOCK_HIGH   104
+/**
+ * EMIF medium frequency in MHz
+ */
+#define SYSCON_EMIF_CLOCK_MEDIUM 104
+/**
+ * EMIF low frequency in MHz
+ */
+#define SYSCON_EMIF_CLOCK_LOW     13
+
+/* AHB clock defines */
+/**
+ * AHB high frequency in MHz
+ */
+#define SYSCON_AHB_CLOCK_HIGH     52
+/**
+ * AHB medium frequency in MHz
+ */
+#define SYSCON_AHB_CLOCK_MEDIUM   52
+/**
+ * AHB low frequency in MHz
+ */
+#define SYSCON_AHB_CLOCK_LOW       7  /* i.e 13/2=6.5MHz */
+
+enum syscon_busmaster {
+  SYSCON_BM_DMAC,
+  SYSCON_BM_XGAM,
+  SYSCON_BM_VIDEO_ENC
+};
+
+/*
+ * Note that this array must match the order of the array "clk_reg"
+ * in syscon.c
+ */
+enum syscon_clk {
+  SYSCON_CLKCONTROL_SLOW_BRIDGE,
+  SYSCON_CLKCONTROL_UART,
+  SYSCON_CLKCONTROL_BTR,
+  SYSCON_CLKCONTROL_EH,
+  SYSCON_CLKCONTROL_GPIO,
+  SYSCON_CLKCONTROL_KEYPAD,
+  SYSCON_CLKCONTROL_APP_TIMER,
+  SYSCON_CLKCONTROL_ACC_TIMER,
+  SYSCON_CLKCONTROL_FAST_BRIDGE,
+  SYSCON_CLKCONTROL_I2C0,
+  SYSCON_CLKCONTROL_I2C1,
+  SYSCON_CLKCONTROL_I2S0,
+  SYSCON_CLKCONTROL_I2S1,
+  SYSCON_CLKCONTROL_MMC,
+  SYSCON_CLKCONTROL_SPI,
+  SYSCON_CLKCONTROL_I2S0_CORE,
+  SYSCON_CLKCONTROL_I2S1_CORE,
+  SYSCON_CLKCONTROL_AAIF,
+  SYSCON_CLKCONTROL_AHB,
+  SYSCON_CLKCONTROL_APEX,
+  SYSCON_CLKCONTROL_CPU,
+  SYSCON_CLKCONTROL_DMA,
+  SYSCON_CLKCONTROL_EMIF,
+  SYSCON_CLKCONTROL_NAND_IF,
+  SYSCON_CLKCONTROL_VIDEO_ENC,
+  SYSCON_CLKCONTROL_XGAM,
+  SYSCON_CLKCONTROL_SEMI,
+  SYSCON_CLKCONTROL_AHB_SUBSYS,
+  SYSCON_CLKCONTROL_MSPRO
+};
+
+enum syscon_sysclk_mode {
+  SYSCON_SYSCLK_DISABLED,
+  SYSCON_SYSCLK_M_CLK,
+  SYSCON_SYSCLK_ACC_FSM,
+  SYSCON_SYSCLK_PLL60_48,
+  SYSCON_SYSCLK_PLL60_60,
+  SYSCON_SYSCLK_ACC_PLL208,
+  SYSCON_SYSCLK_APP_PLL13,
+  SYSCON_SYSCLK_APP_FSM,
+  SYSCON_SYSCLK_RTC,
+  SYSCON_SYSCLK_APP_PLL208
+};
+
+enum syscon_sysclk_req {
+  SYSCON_SYSCLKREQ_DISABLED,
+  SYSCON_SYSCLKREQ_ACTIVE_LOW
+};
+
+enum syscon_clk_mode {
+  SYSCON_CLKMODE_OFF,
+  SYSCON_CLKMODE_DEFAULT,
+  SYSCON_CLKMODE_LOW,
+  SYSCON_CLKMODE_MEDIUM,
+  SYSCON_CLKMODE_HIGH,
+  SYSCON_CLKMODE_PERMANENT,
+  SYSCON_CLKMODE_ON,
+};
+
+enum syscon_call_mode {
+  SYSCON_CLKCALL_NOWAIT,
+  SYSCON_CLKCALL_WAIT,
+};
+
+int syscon_dc_on(bool keep_power_on);
+int syscon_set_busmaster_active_state(enum syscon_busmaster busmaster,
+                                     bool active);
+bool syscon_get_busmaster_active_state(void);
+int syscon_set_sleep_mask(enum syscon_clk,
+                         bool sleep_ctrl);
+int syscon_config_sysclk(u32 sysclk,
+                        enum syscon_sysclk_mode sysclkmode,
+                        bool inverse,
+                        u32 divisor,
+                        enum syscon_sysclk_req sysclkreq);
+bool syscon_can_turn_off_semi_clock(void);
+
+/* This function is restricted to core.c */
+int syscon_request_normal_power(bool req);
+
+/* This function is restricted to be used by platform_speed.c */
+int syscon_speed_request(enum syscon_call_mode wait_mode,
+                        enum syscon_clk_mode req_clk_mode);
+#endif /* __MACH_SYSCON_H */
diff --git a/arch/arm/mach-u300/include/mach/system.h b/arch/arm/mach-u300/include/mach/system.h
new file mode 100644 (file)
index 0000000..8daf136
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *
+ * arch/arm/mach-u300/include/mach/system.h
+ *
+ *
+ * Copyright (C) 2007-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * System shutdown and reset functions.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+#include <mach/hardware.h>
+#include <asm/io.h>
+#include <asm/hardware/vic.h>
+#include <asm/irq.h>
+
+/* Forward declare this function from the watchdog */
+void coh901327_watchdog_reset(void);
+
+static inline void arch_idle(void)
+{
+       cpu_do_idle();
+}
+
+static void arch_reset(char mode, const char *cmd)
+{
+       switch (mode) {
+       case 's':
+       case 'h':
+               printk(KERN_CRIT "RESET: shutting down/rebooting system\n");
+               /* Disable interrupts */
+               local_irq_disable();
+#ifdef CONFIG_COH901327_WATCHDOG
+               coh901327_watchdog_reset();
+#endif
+               break;
+       default:
+               /* Do nothing */
+               break;
+       }
+       /* Wait for system do die/reset. */
+       while (1);
+}
diff --git a/arch/arm/mach-u300/include/mach/timex.h b/arch/arm/mach-u300/include/mach/timex.h
new file mode 100644 (file)
index 0000000..f233b72
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ *
+ * arch/arm/mach-u300/include/mach/timex.h
+ *
+ *
+ * Copyright (C) 2006-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Platform tick rate definition.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+#ifndef __MACH_TIMEX_H
+#define __MACH_TIMEX_H
+
+/* This is for the APP OS GP1 (General Purpose 1) timer */
+#define CLOCK_TICK_RATE                1000000
+
+#endif
diff --git a/arch/arm/mach-u300/include/mach/u300-regs.h b/arch/arm/mach-u300/include/mach/u300-regs.h
new file mode 100644 (file)
index 0000000..88333df
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ *
+ * arch/arm/mach-u300/include/mach/u300-regs.h
+ *
+ *
+ * Copyright (C) 2006-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Basic register address definitions in physical memory and
+ * some block defintions for core devices like the timer.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+
+#ifndef __MACH_U300_REGS_H
+#define __MACH_U300_REGS_H
+
+/*
+ * These are the large blocks of memory allocated for I/O.
+ * the defines are used for setting up the I/O memory mapping.
+ */
+
+/* NAND Flash CS0 */
+#define U300_NAND_CS0_PHYS_BASE                0x80000000
+#define U300_NAND_CS0_VIRT_BASE                0xff040000
+
+/* NFIF */
+#define U300_NAND_IF_PHYS_BASE         0x9f800000
+#define U300_NAND_IF_VIRT_BASE         0xff030000
+
+/* AHB Peripherals */
+#define U300_AHB_PER_PHYS_BASE         0xa0000000
+#define U300_AHB_PER_VIRT_BASE         0xff010000
+
+/* FAST Peripherals */
+#define U300_FAST_PER_PHYS_BASE                0xc0000000
+#define U300_FAST_PER_VIRT_BASE                0xff020000
+
+/* SLOW Peripherals */
+#define U300_SLOW_PER_PHYS_BASE                0xc0010000
+#define U300_SLOW_PER_VIRT_BASE                0xff000000
+
+/* Boot ROM */
+#define U300_BOOTROM_PHYS_BASE         0xffff0000
+#define U300_BOOTROM_VIRT_BASE         0xffff0000
+
+/* SEMI config base */
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_SEMI_CONFIG_BASE          0x2FFE0000
+#else
+#define U300_SEMI_CONFIG_BASE          0x30000000
+#endif
+
+/*
+ * All the following peripherals are specified at their PHYSICAL address,
+ * so if you need to access them (in the kernel), you MUST use the macros
+ * defined in <asm/io.h> to map to the IO_ADDRESS_AHB() IO_ADDRESS_FAST()
+ * etc.
+ */
+
+/*
+ * AHB peripherals
+ */
+
+/* AHB Peripherals Bridge Controller */
+#define U300_AHB_BRIDGE_BASE           (U300_AHB_PER_PHYS_BASE+0x0000)
+
+/* Vectored Interrupt Controller 0, servicing 32 interrupts */
+#define U300_INTCON0_BASE              (U300_AHB_PER_PHYS_BASE+0x1000)
+#define U300_INTCON0_VBASE             (U300_AHB_PER_VIRT_BASE+0x1000)
+
+/* Vectored Interrupt Controller 1, servicing 32 interrupts */
+#define U300_INTCON1_BASE              (U300_AHB_PER_PHYS_BASE+0x2000)
+#define U300_INTCON1_VBASE             (U300_AHB_PER_VIRT_BASE+0x2000)
+
+/* Memory Stick Pro (MSPRO) controller */
+#define U300_MSPRO_BASE                        (U300_AHB_PER_PHYS_BASE+0x3000)
+
+/* EMIF Configuration Area */
+#define U300_EMIF_CFG_BASE             (U300_AHB_PER_PHYS_BASE+0x4000)
+
+
+/*
+ * FAST peripherals
+ */
+
+/* FAST bridge control */
+#define U300_FAST_BRIDGE_BASE          (U300_FAST_PER_PHYS_BASE+0x0000)
+
+/* MMC/SD controller */
+#define U300_MMCSD_BASE                        (U300_FAST_PER_PHYS_BASE+0x1000)
+
+/* PCM I2S0 controller */
+#define U300_PCM_I2S0_BASE             (U300_FAST_PER_PHYS_BASE+0x2000)
+
+/* PCM I2S1 controller */
+#define U300_PCM_I2S1_BASE             (U300_FAST_PER_PHYS_BASE+0x3000)
+
+/* I2C0 controller */
+#define U300_I2C0_BASE                 (U300_FAST_PER_PHYS_BASE+0x4000)
+
+/* I2C1 controller */
+#define U300_I2C1_BASE                 (U300_FAST_PER_PHYS_BASE+0x5000)
+
+/* SPI controller */
+#define U300_SPI_BASE                  (U300_FAST_PER_PHYS_BASE+0x6000)
+
+#ifdef CONFIG_MACH_U300_BS335
+/* Fast UART1 on U335 only */
+#define U300_UART1_BASE                        (U300_SLOW_PER_PHYS_BASE+0x7000)
+#endif
+
+/*
+ * SLOW peripherals
+ */
+
+/* SLOW bridge control */
+#define U300_SLOW_BRIDGE_BASE          (U300_SLOW_PER_PHYS_BASE)
+
+/* SYSCON */
+#define U300_SYSCON_BASE               (U300_SLOW_PER_PHYS_BASE+0x1000)
+#define U300_SYSCON_VBASE              (U300_SLOW_PER_VIRT_BASE+0x1000)
+
+/* Watchdog */
+#define U300_WDOG_BASE                 (U300_SLOW_PER_PHYS_BASE+0x2000)
+
+/* UART0 */
+#define U300_UART0_BASE                        (U300_SLOW_PER_PHYS_BASE+0x3000)
+
+/* APP side special timer */
+#define U300_TIMER_APP_BASE            (U300_SLOW_PER_PHYS_BASE+0x4000)
+#define U300_TIMER_APP_VBASE           (U300_SLOW_PER_VIRT_BASE+0x4000)
+
+/* Keypad */
+#define U300_KEYPAD_BASE               (U300_SLOW_PER_PHYS_BASE+0x5000)
+
+/* GPIO */
+#define U300_GPIO_BASE                 (U300_SLOW_PER_PHYS_BASE+0x6000)
+
+/* RTC */
+#define U300_RTC_BASE                  (U300_SLOW_PER_PHYS_BASE+0x7000)
+
+/* Bus tracer */
+#define U300_BUSTR_BASE                        (U300_SLOW_PER_PHYS_BASE+0x8000)
+
+/* Event handler (hardware queue) */
+#define U300_EVHIST_BASE               (U300_SLOW_PER_PHYS_BASE+0x9000)
+
+/* Genric Timer */
+#define U300_TIMER_BASE                        (U300_SLOW_PER_PHYS_BASE+0xa000)
+
+/* PPM */
+#define U300_PPM_BASE                  (U300_SLOW_PER_PHYS_BASE+0xb000)
+
+
+/*
+ * REST peripherals
+ */
+
+/* ISP (image signal processor) is only available in U335 */
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_ISP_BASE                  (0xA0008000)
+#endif
+
+/* DMA Controller base */
+#define U300_DMAC_BASE                 (0xC0020000)
+
+/* MSL Base */
+#define U300_MSL_BASE                  (0xc0022000)
+
+/* APEX Base */
+#define U300_APEX_BASE                 (0xc0030000)
+
+/* Video Encoder Base */
+#ifdef CONFIG_MACH_U300_BS335
+#define U300_VIDEOENC_BASE             (0xc0080000)
+#else
+#define U300_VIDEOENC_BASE             (0xc0040000)
+#endif
+
+/* XGAM Base */
+#define U300_XGAM_BASE                 (0xd0000000)
+
+/*
+ * Virtual accessor macros for static devices
+ */
+
+
+#endif
diff --git a/arch/arm/mach-u300/include/mach/uncompress.h b/arch/arm/mach-u300/include/mach/uncompress.h
new file mode 100644 (file)
index 0000000..29acb71
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * arch/arm/mach-u300/include/mach/uncompress.h
+ *
+ * Copyright (C) 2003 ARM Limited
+ *
+ * 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 AMBA_UART_DR   (*(volatile unsigned char *)0xc0013000)
+#define AMBA_UART_LCRH (*(volatile unsigned char *)0xc001302C)
+#define AMBA_UART_CR   (*(volatile unsigned char *)0xc0013030)
+#define AMBA_UART_FR   (*(volatile unsigned char *)0xc0013018)
+
+/*
+ * This does not append a newline
+ */
+static inline void putc(int c)
+{
+       while (AMBA_UART_FR & (1 << 5))
+               barrier();
+
+       AMBA_UART_DR = c;
+}
+
+static inline void flush(void)
+{
+       while (AMBA_UART_FR & (1 << 3))
+               barrier();
+}
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_setup()
+#define arch_decomp_wdog()
diff --git a/arch/arm/mach-u300/include/mach/vmalloc.h b/arch/arm/mach-u300/include/mach/vmalloc.h
new file mode 100644 (file)
index 0000000..b00c51a
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ *
+ * arch/arm/mach-u300/include/mach/vmalloc.h
+ *
+ *
+ * Copyright (C) 2006-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Virtual memory allocations
+ * End must be above the I/O registers and on an even 2MiB boundary.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+#define VMALLOC_END    0xfe800000
diff --git a/arch/arm/mach-u300/mmc.c b/arch/arm/mach-u300/mmc.c
new file mode 100644 (file)
index 0000000..3138d39
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ *
+ * arch/arm/mach-u300/mmc.c
+ *
+ *
+ * Copyright (C) 2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ * Author: Johan Lundin <johan.lundin@stericsson.com>
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
+ */
+#include <linux/device.h>
+#include <linux/amba/bus.h>
+#include <linux/mmc/host.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/machine.h>
+#include <linux/gpio.h>
+
+#include <asm/mach/mmc.h>
+#include "mmc.h"
+
+struct mmci_card_event {
+       struct input_dev *mmc_input;
+       int mmc_inserted;
+       struct work_struct workq;
+       struct mmc_platform_data mmc0_plat_data;
+};
+
+static unsigned int mmc_status(struct device *dev)
+{
+       struct mmci_card_event *mmci_card = container_of(
+               dev->platform_data,
+               struct mmci_card_event, mmc0_plat_data);
+
+       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;
+
+       disable_irq_on_gpio_pin(U300_GPIO_PIN_MMC_CD);
+       schedule_work(&mmci_card->workq);
+
+       return 0;
+}
+
+
+static ssize_t gpio_show(struct device *dev, struct device_attribute *attr,
+                 char *buf)
+{
+       struct mmci_card_event *mmci_card = container_of(
+               dev->platform_data,
+               struct mmci_card_event, mmc0_plat_data);
+
+
+       return sprintf(buf, "%d\n", !mmci_card->mmc_inserted);
+}
+
+static DEVICE_ATTR(mmc_inserted, S_IRUGO, gpio_show, NULL);
+
+static void _mmci_callback(struct work_struct *ws)
+{
+
+       struct mmci_card_event *mmci_card = container_of(
+               ws,
+               struct mmci_card_event, workq);
+
+       mdelay(20);
+
+       mmci_card->mmc_inserted = !!gpio_get_value(U300_GPIO_PIN_MMC_CD);
+
+       input_report_switch(mmci_card->mmc_input, KEY_INSERT,
+                           !mmci_card->mmc_inserted);
+       input_sync(mmci_card->mmc_input);
+
+       pr_debug("MMC/SD card was %s\n",
+                mmci_card->mmc_inserted ? "removed" : "inserted");
+
+       enable_irq_on_gpio_pin(U300_GPIO_PIN_MMC_CD, !mmci_card->mmc_inserted);
+}
+
+int __devinit mmc_init(struct amba_device *adev)
+{
+       struct mmci_card_event *mmci_card;
+       struct device *mmcsd_device = &adev->dev;
+       int ret = 0;
+
+       mmci_card = kzalloc(sizeof(struct mmci_card_event), GFP_KERNEL);
+       if (!mmci_card)
+               return -ENOMEM;
+
+       /* 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;
+
+       mmcsd_device->platform_data = (void *) &mmci_card->mmc0_plat_data;
+
+       INIT_WORK(&mmci_card->workq, _mmci_callback);
+
+       ret = gpio_request(U300_GPIO_PIN_MMC_CD, "MMC card detection");
+       if (ret) {
+               printk(KERN_CRIT "Could not allocate MMC card detection " \
+                      "GPIO pin\n");
+               goto out;
+       }
+
+       ret = gpio_direction_input(U300_GPIO_PIN_MMC_CD);
+       if (ret) {
+               printk(KERN_CRIT "Invalid GPIO pin requested\n");
+               goto out;
+       }
+
+       ret = sysfs_create_file(&mmcsd_device->kobj,
+                              &dev_attr_mmc_inserted.attr);
+       if (ret)
+               goto out;
+
+       mmci_card->mmc_input = input_allocate_device();
+       if (!mmci_card->mmc_input) {
+               printk(KERN_CRIT "Could not allocate MMC input device\n");
+               return -ENOMEM;
+       }
+
+       mmci_card->mmc_input->name = "MMC insert notification";
+       mmci_card->mmc_input->id.bustype = BUS_HOST;
+       mmci_card->mmc_input->id.vendor = 0;
+       mmci_card->mmc_input->id.product = 0;
+       mmci_card->mmc_input->id.version = 0x0100;
+       mmci_card->mmc_input->dev.parent = mmcsd_device;
+       input_set_capability(mmci_card->mmc_input, EV_SW, KEY_INSERT);
+
+       /*
+        * Since this must always be compiled into the kernel, this input
+        * is never unregistered or free:ed.
+        */
+       ret = input_register_device(mmci_card->mmc_input);
+       if (ret) {
+               input_free_device(mmci_card->mmc_input);
+               goto out;
+       }
+
+       input_set_drvdata(mmci_card->mmc_input, mmci_card);
+
+       ret = gpio_register_callback(U300_GPIO_PIN_MMC_CD, mmci_callback,
+                                    mmci_card);
+
+       schedule_work(&mmci_card->workq);
+
+       printk(KERN_INFO "Registered MMC insert/remove notification\n");
+out:
+       return ret;
+}
diff --git a/arch/arm/mach-u300/mmc.h b/arch/arm/mach-u300/mmc.h
new file mode 100644 (file)
index 0000000..92b8512
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ *
+ * arch/arm/mach-u300/mmc.h
+ *
+ *
+ * Copyright (C) 2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
+ */
+#ifndef MMC_H
+#define MMC_H
+
+#include <linux/amba/bus.h>
+
+int __devinit mmc_init(struct amba_device *adev);
+
+#endif
diff --git a/arch/arm/mach-u300/padmux.c b/arch/arm/mach-u300/padmux.c
new file mode 100644 (file)
index 0000000..f366456
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ *
+ * arch/arm/mach-u300/padmux.c
+ *
+ *
+ * Copyright (C) 2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * U300 PADMUX functions
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ *
+ */
+#include <linux/io.h>
+#include <linux/err.h>
+#include <mach/u300-regs.h>
+#include <mach/syscon.h>
+
+#include "padmux.h"
+
+/* Set the PAD MUX to route the MMC reader correctly to GPIO0. */
+void pmx_set_mission_mode_mmc(void)
+{
+       u16 val;
+
+       val = readw(U300_SYSCON_VBASE + U300_SYSCON_PMC1LR);
+       val &= ~U300_SYSCON_PMC1LR_MMCSD_MASK;
+       writew(val, U300_SYSCON_VBASE + U300_SYSCON_PMC1LR);
+       val = readw(U300_SYSCON_VBASE + U300_SYSCON_PMC1HR);
+       val &= ~U300_SYSCON_PMC1HR_APP_GPIO_1_MASK;
+       val |= U300_SYSCON_PMC1HR_APP_GPIO_1_MMC;
+       writew(val, U300_SYSCON_VBASE + U300_SYSCON_PMC1HR);
+}
+
+void pmx_set_mission_mode_spi(void)
+{
+       u16 val;
+
+       /* Set up padmuxing so the SPI port and its chipselects are active */
+       val = readw(U300_SYSCON_VBASE + U300_SYSCON_PMC1HR);
+       /*
+        * Activate the SPI port (disable the use of these pins for generic
+        * GPIO, DSP, AAIF
+        */
+       val &= ~U300_SYSCON_PMC1HR_APP_SPI_2_MASK;
+       val |= U300_SYSCON_PMC1HR_APP_SPI_2_SPI;
+       /*
+        * Use GPIO pin SPI CS1 for CS1 actually (it can be used for other
+        * things also)
+        */
+       val &= ~U300_SYSCON_PMC1HR_APP_SPI_CS_1_MASK;
+       val |= U300_SYSCON_PMC1HR_APP_SPI_CS_1_SPI;
+       /*
+        * Use GPIO pin SPI CS2 for CS2 actually (it can be used for other
+        * things also)
+        */
+       val &= ~U300_SYSCON_PMC1HR_APP_SPI_CS_2_MASK;
+       val |= U300_SYSCON_PMC1HR_APP_SPI_CS_2_SPI;
+       writew(val, U300_SYSCON_VBASE + U300_SYSCON_PMC1HR);
+}
diff --git a/arch/arm/mach-u300/padmux.h b/arch/arm/mach-u300/padmux.h
new file mode 100644 (file)
index 0000000..8c2099a
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ *
+ * arch/arm/mach-u300/padmux.h
+ *
+ *
+ * Copyright (C) 2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * U300 PADMUX API
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ *
+ */
+
+#ifndef __MACH_U300_PADMUX_H
+#define __MACH_U300_PADMUX_H
+
+void pmx_set_mission_mode_mmc(void);
+void pmx_set_mission_mode_spi(void);
+
+#endif
diff --git a/arch/arm/mach-u300/timer.c b/arch/arm/mach-u300/timer.c
new file mode 100644 (file)
index 0000000..cce5320
--- /dev/null
@@ -0,0 +1,422 @@
+/*
+ *
+ * arch/arm/mach-u300/timer.c
+ *
+ *
+ * Copyright (C) 2007-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Timer COH 901 328, runs the OS timer interrupt.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/types.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+
+/* Generic stuff */
+#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+#include <asm/mach/irq.h>
+
+#include "clock.h"
+
+/*
+ * APP side special timer registers
+ * This timer contains four timers which can fire an interrupt each.
+ * OS (operating system) timer @ 32768 Hz
+ * DD (device driver) timer @ 1 kHz
+ * GP1 (general purpose 1) timer @ 1MHz
+ * GP2 (general purpose 2) timer @ 1MHz
+ */
+
+/* Reset OS Timer 32bit (-/W) */
+#define U300_TIMER_APP_ROST                                    (0x0000)
+#define U300_TIMER_APP_ROST_TIMER_RESET                                (0x00000000)
+/* Enable OS Timer 32bit (-/W) */
+#define U300_TIMER_APP_EOST                                    (0x0004)
+#define U300_TIMER_APP_EOST_TIMER_ENABLE                       (0x00000000)
+/* Disable OS Timer 32bit (-/W) */
+#define U300_TIMER_APP_DOST                                    (0x0008)
+#define U300_TIMER_APP_DOST_TIMER_DISABLE                      (0x00000000)
+/* OS Timer Mode Register 32bit (-/W) */
+#define U300_TIMER_APP_SOSTM                                   (0x000c)
+#define U300_TIMER_APP_SOSTM_MODE_CONTINUOUS                   (0x00000000)
+#define U300_TIMER_APP_SOSTM_MODE_ONE_SHOT                     (0x00000001)
+/* OS Timer Status Register 32bit (R/-) */
+#define U300_TIMER_APP_OSTS                                    (0x0010)
+#define U300_TIMER_APP_OSTS_TIMER_STATE_MASK                   (0x0000000F)
+#define U300_TIMER_APP_OSTS_TIMER_STATE_IDLE                   (0x00000001)
+#define U300_TIMER_APP_OSTS_TIMER_STATE_ACTIVE                 (0x00000002)
+#define U300_TIMER_APP_OSTS_ENABLE_IND                         (0x00000010)
+#define U300_TIMER_APP_OSTS_MODE_MASK                          (0x00000020)
+#define U300_TIMER_APP_OSTS_MODE_CONTINUOUS                    (0x00000000)
+#define U300_TIMER_APP_OSTS_MODE_ONE_SHOT                      (0x00000020)
+#define U300_TIMER_APP_OSTS_IRQ_ENABLED_IND                    (0x00000040)
+#define U300_TIMER_APP_OSTS_IRQ_PENDING_IND                    (0x00000080)
+/* OS Timer Current Count Register 32bit (R/-) */
+#define U300_TIMER_APP_OSTCC                                   (0x0014)
+/* OS Timer Terminal Count Register 32bit (R/W) */
+#define U300_TIMER_APP_OSTTC                                   (0x0018)
+/* OS Timer Interrupt Enable Register 32bit (-/W) */
+#define U300_TIMER_APP_OSTIE                                   (0x001c)
+#define U300_TIMER_APP_OSTIE_IRQ_DISABLE                       (0x00000000)
+#define U300_TIMER_APP_OSTIE_IRQ_ENABLE                                (0x00000001)
+/* OS Timer Interrupt Acknowledge Register 32bit (-/W) */
+#define U300_TIMER_APP_OSTIA                                   (0x0020)
+#define U300_TIMER_APP_OSTIA_IRQ_ACK                           (0x00000080)
+
+/* Reset DD Timer 32bit (-/W) */
+#define U300_TIMER_APP_RDDT                                    (0x0040)
+#define U300_TIMER_APP_RDDT_TIMER_RESET                                (0x00000000)
+/* Enable DD Timer 32bit (-/W) */
+#define U300_TIMER_APP_EDDT                                    (0x0044)
+#define U300_TIMER_APP_EDDT_TIMER_ENABLE                       (0x00000000)
+/* Disable DD Timer 32bit (-/W) */
+#define U300_TIMER_APP_DDDT                                    (0x0048)
+#define U300_TIMER_APP_DDDT_TIMER_DISABLE                      (0x00000000)
+/* DD Timer Mode Register 32bit (-/W) */
+#define U300_TIMER_APP_SDDTM                                   (0x004c)
+#define U300_TIMER_APP_SDDTM_MODE_CONTINUOUS                   (0x00000000)
+#define U300_TIMER_APP_SDDTM_MODE_ONE_SHOT                     (0x00000001)
+/* DD Timer Status Register 32bit (R/-) */
+#define U300_TIMER_APP_DDTS                                    (0x0050)
+#define U300_TIMER_APP_DDTS_TIMER_STATE_MASK                   (0x0000000F)
+#define U300_TIMER_APP_DDTS_TIMER_STATE_IDLE                   (0x00000001)
+#define U300_TIMER_APP_DDTS_TIMER_STATE_ACTIVE                 (0x00000002)
+#define U300_TIMER_APP_DDTS_ENABLE_IND                         (0x00000010)
+#define U300_TIMER_APP_DDTS_MODE_MASK                          (0x00000020)
+#define U300_TIMER_APP_DDTS_MODE_CONTINUOUS                    (0x00000000)
+#define U300_TIMER_APP_DDTS_MODE_ONE_SHOT                      (0x00000020)
+#define U300_TIMER_APP_DDTS_IRQ_ENABLED_IND                    (0x00000040)
+#define U300_TIMER_APP_DDTS_IRQ_PENDING_IND                    (0x00000080)
+/* DD Timer Current Count Register 32bit (R/-) */
+#define U300_TIMER_APP_DDTCC                                   (0x0054)
+/* DD Timer Terminal Count Register 32bit (R/W) */
+#define U300_TIMER_APP_DDTTC                                   (0x0058)
+/* DD Timer Interrupt Enable Register 32bit (-/W) */
+#define U300_TIMER_APP_DDTIE                                   (0x005c)
+#define U300_TIMER_APP_DDTIE_IRQ_DISABLE                       (0x00000000)
+#define U300_TIMER_APP_DDTIE_IRQ_ENABLE                                (0x00000001)
+/* DD Timer Interrupt Acknowledge Register 32bit (-/W) */
+#define U300_TIMER_APP_DDTIA                                   (0x0060)
+#define U300_TIMER_APP_DDTIA_IRQ_ACK                           (0x00000080)
+
+/* Reset GP1 Timer 32bit (-/W) */
+#define U300_TIMER_APP_RGPT1                                   (0x0080)
+#define U300_TIMER_APP_RGPT1_TIMER_RESET                       (0x00000000)
+/* Enable GP1 Timer 32bit (-/W) */
+#define U300_TIMER_APP_EGPT1                                   (0x0084)
+#define U300_TIMER_APP_EGPT1_TIMER_ENABLE                      (0x00000000)
+/* Disable GP1 Timer 32bit (-/W) */
+#define U300_TIMER_APP_DGPT1                                   (0x0088)
+#define U300_TIMER_APP_DGPT1_TIMER_DISABLE                     (0x00000000)
+/* GP1 Timer Mode Register 32bit (-/W) */
+#define U300_TIMER_APP_SGPT1M                                  (0x008c)
+#define U300_TIMER_APP_SGPT1M_MODE_CONTINUOUS                  (0x00000000)
+#define U300_TIMER_APP_SGPT1M_MODE_ONE_SHOT                    (0x00000001)
+/* GP1 Timer Status Register 32bit (R/-) */
+#define U300_TIMER_APP_GPT1S                                   (0x0090)
+#define U300_TIMER_APP_GPT1S_TIMER_STATE_MASK                  (0x0000000F)
+#define U300_TIMER_APP_GPT1S_TIMER_STATE_IDLE                  (0x00000001)
+#define U300_TIMER_APP_GPT1S_TIMER_STATE_ACTIVE                        (0x00000002)
+#define U300_TIMER_APP_GPT1S_ENABLE_IND                                (0x00000010)
+#define U300_TIMER_APP_GPT1S_MODE_MASK                         (0x00000020)
+#define U300_TIMER_APP_GPT1S_MODE_CONTINUOUS                   (0x00000000)
+#define U300_TIMER_APP_GPT1S_MODE_ONE_SHOT                     (0x00000020)
+#define U300_TIMER_APP_GPT1S_IRQ_ENABLED_IND                   (0x00000040)
+#define U300_TIMER_APP_GPT1S_IRQ_PENDING_IND                   (0x00000080)
+/* GP1 Timer Current Count Register 32bit (R/-) */
+#define U300_TIMER_APP_GPT1CC                                  (0x0094)
+/* GP1 Timer Terminal Count Register 32bit (R/W) */
+#define U300_TIMER_APP_GPT1TC                                  (0x0098)
+/* GP1 Timer Interrupt Enable Register 32bit (-/W) */
+#define U300_TIMER_APP_GPT1IE                                  (0x009c)
+#define U300_TIMER_APP_GPT1IE_IRQ_DISABLE                      (0x00000000)
+#define U300_TIMER_APP_GPT1IE_IRQ_ENABLE                       (0x00000001)
+/* GP1 Timer Interrupt Acknowledge Register 32bit (-/W) */
+#define U300_TIMER_APP_GPT1IA                                  (0x00a0)
+#define U300_TIMER_APP_GPT1IA_IRQ_ACK                          (0x00000080)
+
+/* Reset GP2 Timer 32bit (-/W) */
+#define U300_TIMER_APP_RGPT2                                   (0x00c0)
+#define U300_TIMER_APP_RGPT2_TIMER_RESET                       (0x00000000)
+/* Enable GP2 Timer 32bit (-/W) */
+#define U300_TIMER_APP_EGPT2                                   (0x00c4)
+#define U300_TIMER_APP_EGPT2_TIMER_ENABLE                      (0x00000000)
+/* Disable GP2 Timer 32bit (-/W) */
+#define U300_TIMER_APP_DGPT2                                   (0x00c8)
+#define U300_TIMER_APP_DGPT2_TIMER_DISABLE                     (0x00000000)
+/* GP2 Timer Mode Register 32bit (-/W) */
+#define U300_TIMER_APP_SGPT2M                                  (0x00cc)
+#define U300_TIMER_APP_SGPT2M_MODE_CONTINUOUS                  (0x00000000)
+#define U300_TIMER_APP_SGPT2M_MODE_ONE_SHOT                    (0x00000001)
+/* GP2 Timer Status Register 32bit (R/-) */
+#define U300_TIMER_APP_GPT2S                                   (0x00d0)
+#define U300_TIMER_APP_GPT2S_TIMER_STATE_MASK                  (0x0000000F)
+#define U300_TIMER_APP_GPT2S_TIMER_STATE_IDLE                  (0x00000001)
+#define U300_TIMER_APP_GPT2S_TIMER_STATE_ACTIVE                        (0x00000002)
+#define U300_TIMER_APP_GPT2S_ENABLE_IND                                (0x00000010)
+#define U300_TIMER_APP_GPT2S_MODE_MASK                         (0x00000020)
+#define U300_TIMER_APP_GPT2S_MODE_CONTINUOUS                   (0x00000000)
+#define U300_TIMER_APP_GPT2S_MODE_ONE_SHOT                     (0x00000020)
+#define U300_TIMER_APP_GPT2S_IRQ_ENABLED_IND                   (0x00000040)
+#define U300_TIMER_APP_GPT2S_IRQ_PENDING_IND                   (0x00000080)
+/* GP2 Timer Current Count Register 32bit (R/-) */
+#define U300_TIMER_APP_GPT2CC                                  (0x00d4)
+/* GP2 Timer Terminal Count Register 32bit (R/W) */
+#define U300_TIMER_APP_GPT2TC                                  (0x00d8)
+/* GP2 Timer Interrupt Enable Register 32bit (-/W) */
+#define U300_TIMER_APP_GPT2IE                                  (0x00dc)
+#define U300_TIMER_APP_GPT2IE_IRQ_DISABLE                      (0x00000000)
+#define U300_TIMER_APP_GPT2IE_IRQ_ENABLE                       (0x00000001)
+/* GP2 Timer Interrupt Acknowledge Register 32bit (-/W) */
+#define U300_TIMER_APP_GPT2IA                                  (0x00e0)
+#define U300_TIMER_APP_GPT2IA_IRQ_ACK                          (0x00000080)
+
+/* Clock request control register - all four timers */
+#define U300_TIMER_APP_CRC                                     (0x100)
+#define U300_TIMER_APP_CRC_CLOCK_REQUEST_ENABLE                        (0x00000001)
+
+#define TICKS_PER_JIFFY ((CLOCK_TICK_RATE + (HZ/2)) / HZ)
+#define US_PER_TICK ((1000000 + (HZ/2)) / HZ)
+
+/*
+ * The u300_set_mode() function is always called first, if we
+ * have oneshot timer active, the oneshot scheduling function
+ * u300_set_next_event() is called immediately after.
+ */
+static void u300_set_mode(enum clock_event_mode mode,
+                         struct clock_event_device *evt)
+{
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               /* Disable interrupts on GPT1 */
+               writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
+                      U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE);
+               /* Disable GP1 while we're reprogramming it. */
+               writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
+                      U300_TIMER_APP_VBASE + U300_TIMER_APP_DGPT1);
+               /*
+                * Set the periodic mode to a certain number of ticks per
+                * jiffy.
+                */
+               writel(TICKS_PER_JIFFY,
+                      U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1TC);
+               /*
+                * Set continuous mode, so the timer keeps triggering
+                * interrupts.
+                */
+               writel(U300_TIMER_APP_SGPT1M_MODE_CONTINUOUS,
+                      U300_TIMER_APP_VBASE + U300_TIMER_APP_SGPT1M);
+               /* Enable timer interrupts */
+               writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE,
+                      U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE);
+               /* Then enable the OS timer again */
+               writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE,
+                      U300_TIMER_APP_VBASE + U300_TIMER_APP_EGPT1);
+               break;
+       case CLOCK_EVT_MODE_ONESHOT:
+               /* Just break; here? */
+               /*
+                * The actual event will be programmed by the next event hook,
+                * so we just set a dummy value somewhere at the end of the
+                * universe here.
+                */
+               /* Disable interrupts on GPT1 */
+               writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
+                      U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE);
+               /* Disable GP1 while we're reprogramming it. */
+               writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
+                      U300_TIMER_APP_VBASE + U300_TIMER_APP_DGPT1);
+               /*
+                * Expire far in the future, u300_set_next_event() will be
+                * called soon...
+                */
+               writel(0xFFFFFFFF, U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1TC);
+               /* We run one shot per tick here! */
+               writel(U300_TIMER_APP_SGPT1M_MODE_ONE_SHOT,
+                      U300_TIMER_APP_VBASE + U300_TIMER_APP_SGPT1M);
+               /* Enable interrupts for this timer */
+               writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE,
+                      U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE);
+               /* Enable timer */
+               writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE,
+                      U300_TIMER_APP_VBASE + U300_TIMER_APP_EGPT1);
+               break;
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+               /* Disable interrupts on GP1 */
+               writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
+                      U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE);
+               /* Disable GP1 */
+               writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
+                      U300_TIMER_APP_VBASE + U300_TIMER_APP_DGPT1);
+               break;
+       case CLOCK_EVT_MODE_RESUME:
+               /* Ignore this call */
+               break;
+       }
+}
+
+/*
+ * The app timer in one shot mode obviously has to be reprogrammed
+ * in EXACTLY this sequence to work properly. Do NOT try to e.g. replace
+ * the interrupt disable + timer disable commands with a reset command,
+ * it will fail miserably. Apparently (and I found this the hard way)
+ * the timer is very sensitive to the instruction order, though you don't
+ * get that impression from the data sheet.
+ */
+static int u300_set_next_event(unsigned long cycles,
+                              struct clock_event_device *evt)
+
+{
+       /* Disable interrupts on GPT1 */
+       writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
+              U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE);
+       /* Disable GP1 while we're reprogramming it. */
+       writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
+              U300_TIMER_APP_VBASE + U300_TIMER_APP_DGPT1);
+       /* Reset the General Purpose timer 1. */
+       writel(U300_TIMER_APP_RGPT1_TIMER_RESET,
+              U300_TIMER_APP_VBASE + U300_TIMER_APP_RGPT1);
+       /* IRQ in n * cycles */
+       writel(cycles, U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1TC);
+       /*
+        * We run one shot per tick here! (This is necessary to reconfigure,
+        * the timer will tilt if you don't!)
+        */
+       writel(U300_TIMER_APP_SGPT1M_MODE_ONE_SHOT,
+              U300_TIMER_APP_VBASE + U300_TIMER_APP_SGPT1M);
+       /* Enable timer interrupts */
+       writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE,
+              U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE);
+       /* Then enable the OS timer again */
+       writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE,
+              U300_TIMER_APP_VBASE + U300_TIMER_APP_EGPT1);
+       return 0;
+}
+
+
+/* Use general purpose timer 1 as clock event */
+static struct clock_event_device clockevent_u300_1mhz = {
+       .name           = "GPT1",
+       .rating         = 300, /* Reasonably fast and accurate clock event */
+       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+       /* 22 calculated using the algorithm in arch/mips/kernel/time.c */
+       .shift          = 22,
+       .set_next_event = u300_set_next_event,
+       .set_mode       = u300_set_mode,
+};
+
+/* Clock event timer interrupt handler */
+static irqreturn_t u300_timer_interrupt(int irq, void *dev_id)
+{
+       struct clock_event_device *evt = &clockevent_u300_1mhz;
+       /* ACK/Clear timer IRQ for the APP GPT1 Timer */
+       writel(U300_TIMER_APP_GPT1IA_IRQ_ACK,
+               U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IA);
+       evt->event_handler(evt);
+       return IRQ_HANDLED;
+}
+
+static struct irqaction u300_timer_irq = {
+       .name           = "U300 Timer Tick",
+       .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+       .handler        = u300_timer_interrupt,
+};
+
+/* Use general purpose timer 2 as clock source */
+static cycle_t u300_get_cycles(struct clocksource *cs)
+{
+       return (cycles_t) readl(U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT2CC);
+}
+
+static struct clocksource clocksource_u300_1mhz = {
+       .name           = "GPT2",
+       .rating         = 300, /* Reasonably fast and accurate clock source */
+       .read           = u300_get_cycles,
+       .mask           = CLOCKSOURCE_MASK(32), /* 32 bits */
+       /* 22 calculated using the algorithm in arch/mips/kernel/time.c */
+       .shift          = 22,
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+
+/*
+ * This sets up the system timers, clock source and clock event.
+ */
+static void __init u300_timer_init(void)
+{
+       u300_enable_timer_clock();
+       /*
+        * Disable the "OS" and "DD" timers - these are designed for Symbian!
+        * Example usage in cnh1601578 cpu subsystem pd_timer_app.c
+        */
+       writel(U300_TIMER_APP_CRC_CLOCK_REQUEST_ENABLE,
+               U300_TIMER_APP_VBASE + U300_TIMER_APP_CRC);
+       writel(U300_TIMER_APP_ROST_TIMER_RESET,
+               U300_TIMER_APP_VBASE + U300_TIMER_APP_ROST);
+       writel(U300_TIMER_APP_DOST_TIMER_DISABLE,
+               U300_TIMER_APP_VBASE + U300_TIMER_APP_DOST);
+       writel(U300_TIMER_APP_RDDT_TIMER_RESET,
+               U300_TIMER_APP_VBASE + U300_TIMER_APP_RDDT);
+       writel(U300_TIMER_APP_DDDT_TIMER_DISABLE,
+               U300_TIMER_APP_VBASE + U300_TIMER_APP_DDDT);
+
+       /* Reset the General Purpose timer 1. */
+       writel(U300_TIMER_APP_RGPT1_TIMER_RESET,
+               U300_TIMER_APP_VBASE + U300_TIMER_APP_RGPT1);
+
+       /* Set up the IRQ handler */
+       setup_irq(IRQ_U300_TIMER_APP_GP1, &u300_timer_irq);
+
+       /* Reset the General Purpose timer 2 */
+       writel(U300_TIMER_APP_RGPT2_TIMER_RESET,
+               U300_TIMER_APP_VBASE + U300_TIMER_APP_RGPT2);
+       /* Set this timer to run around forever */
+       writel(0xFFFFFFFFU, U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT2TC);
+       /* Set continuous mode so it wraps around */
+       writel(U300_TIMER_APP_SGPT2M_MODE_CONTINUOUS,
+              U300_TIMER_APP_VBASE + U300_TIMER_APP_SGPT2M);
+       /* Disable timer interrupts */
+       writel(U300_TIMER_APP_GPT2IE_IRQ_DISABLE,
+               U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT2IE);
+       /* Then enable the GP2 timer to use as a free running us counter */
+       writel(U300_TIMER_APP_EGPT2_TIMER_ENABLE,
+               U300_TIMER_APP_VBASE + U300_TIMER_APP_EGPT2);
+
+       /* This is a pure microsecond clock source */
+       clocksource_u300_1mhz.mult =
+               clocksource_khz2mult(1000, clocksource_u300_1mhz.shift);
+       if (clocksource_register(&clocksource_u300_1mhz))
+               printk(KERN_ERR "timer: failed to initialize clock "
+                      "source %s\n", clocksource_u300_1mhz.name);
+
+       clockevent_u300_1mhz.mult =
+               div_sc(1000000, NSEC_PER_SEC, clockevent_u300_1mhz.shift);
+       /* 32bit counter, so 32bits delta is max */
+       clockevent_u300_1mhz.max_delta_ns =
+               clockevent_delta2ns(0xffffffff, &clockevent_u300_1mhz);
+       /* This timer is slow enough to set for 1 cycle == 1 MHz */
+       clockevent_u300_1mhz.min_delta_ns =
+               clockevent_delta2ns(1, &clockevent_u300_1mhz);
+       clockevent_u300_1mhz.cpumask = cpumask_of(0);
+       clockevents_register_device(&clockevent_u300_1mhz);
+       /*
+        * TODO: init and register the rest of the timers too, they can be
+        * used by hrtimers!
+        */
+}
+
+/*
+ * Very simple system timer that only register the clock event and
+ * clock source.
+ */
+struct sys_timer u300_timer = {
+       .init           = u300_timer_init,
+};
diff --git a/arch/arm/mach-u300/u300.c b/arch/arm/mach-u300/u300.c
new file mode 100644 (file)
index 0000000..d2a0b88
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ *
+ * arch/arm/mach-u300/u300.c
+ *
+ *
+ * Copyright (C) 2006-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Platform machine definition.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <mach/hardware.h>
+#include <mach/platform.h>
+#include <mach/memory.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+static void __init u300_init_machine(void)
+{
+       u300_init_devices();
+}
+
+#ifdef CONFIG_MACH_U300_BS2X
+#define MACH_U300_STRING "Ericsson AB U300 S25/S26/B25/B26 Prototype Board"
+#endif
+
+#ifdef CONFIG_MACH_U300_BS330
+#define MACH_U300_STRING "Ericsson AB U330 S330/B330 Prototype Board"
+#endif
+
+#ifdef CONFIG_MACH_U300_BS335
+#define MACH_U300_STRING "Ericsson AB U335 S335/B335 Prototype Board"
+#endif
+
+#ifdef CONFIG_MACH_U300_BS365
+#define MACH_U300_STRING "Ericsson AB U365 S365/B365 Prototype Board"
+#endif
+
+MACHINE_START(U300, MACH_U300_STRING)
+       /* Maintainer: Linus Walleij <linus.walleij@stericsson.com> */
+       .phys_io        = U300_AHB_PER_PHYS_BASE,
+       .io_pg_offst    = ((U300_AHB_PER_VIRT_BASE) >> 18) & 0xfffc,
+       .boot_params    = BOOT_PARAMS_OFFSET,
+       .map_io         = u300_map_io,
+       .init_irq       = u300_init_irq,
+       .timer          = &u300_timer,
+       .init_machine   = u300_init_machine,
+MACHINE_END
index b3bebcc5623bf23ff2a78ce44ca532fbf13d6eea..69214fc8bd19576093accb6904549ecc2e12fa0c 100644 (file)
@@ -116,7 +116,7 @@ void __init versatile_init_irq(void)
 {
        unsigned int i;
 
-       vic_init(VA_VIC_BASE, IRQ_VIC_START, ~0);
+       vic_init(VA_VIC_BASE, IRQ_VIC_START, ~0, 0);
 
        set_irq_chained_handler(IRQ_VICSOURCE31, sic_handle_irq);
 
index 0c0c1d63f1c72089de8e8e87ff83a6e4209ce06b..d50c94f4dbdfd27f45ea92e58c69cbffa25c45ce 100644 (file)
@@ -4,7 +4,7 @@
 
 # Object file lists.
 
-obj-y                          := irq.o time.o
+obj-y                          := irq.o time.o mfp-w90p910.o gpio.o clock.o
 
 # W90X900 CPU support files
 
diff --git a/arch/arm/mach-w90x900/clock.c b/arch/arm/mach-w90x900/clock.c
new file mode 100644 (file)
index 0000000..f420613
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * linux/arch/arm/mach-w90x900/clock.c
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ *
+ * Wan ZongShun <mcuos.com@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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/clk.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+
+#include "clock.h"
+
+static DEFINE_SPINLOCK(clocks_lock);
+
+int clk_enable(struct clk *clk)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&clocks_lock, flags);
+       if (clk->enabled++ == 0)
+               (clk->enable)(clk, 1);
+       spin_unlock_irqrestore(&clocks_lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+       unsigned long flags;
+
+       WARN_ON(clk->enabled == 0);
+
+       spin_lock_irqsave(&clocks_lock, flags);
+       if (--clk->enabled == 0)
+               (clk->enable)(clk, 0);
+       spin_unlock_irqrestore(&clocks_lock, flags);
+}
+EXPORT_SYMBOL(clk_disable);
+
+void w90x900_clk_enable(struct clk *clk, int enable)
+{
+       unsigned int clocks = clk->cken;
+       unsigned long clken;
+
+       clken = __raw_readl(W90X900_VA_CLKPWR);
+
+       if (enable)
+               clken |= clocks;
+       else
+               clken &= ~clocks;
+
+       __raw_writel(clken, W90X900_VA_CLKPWR);
+}
+
+void clks_register(struct clk_lookup *clks, size_t num)
+{
+       int i;
+
+       for (i = 0; i < num; i++)
+               clkdev_add(&clks[i]);
+}
diff --git a/arch/arm/mach-w90x900/clock.h b/arch/arm/mach-w90x900/clock.h
new file mode 100644 (file)
index 0000000..4f27bda
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * linux/arch/arm/mach-w90x900/clock.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ *
+ * Wan ZongShun <mcuos.com@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.
+ */
+
+#include <asm/clkdev.h>
+
+void w90x900_clk_enable(struct clk *clk, int enable);
+void clks_register(struct clk_lookup *clks, size_t num);
+
+struct clk {
+       unsigned long           cken;
+       unsigned int            enabled;
+       void                    (*enable)(struct clk *, int enable);
+};
+
+#define DEFINE_CLK(_name, _ctrlbit)                    \
+struct clk clk_##_name = {                             \
+               .enable = w90x900_clk_enable,           \
+               .cken   = (1 << _ctrlbit),              \
+       }
+
+#define DEF_CLKLOOK(_clk, _devname, _conname)          \
+       {                                               \
+               .clk            = _clk,                 \
+               .dev_id         = _devname,             \
+               .con_id         = _conname,             \
+       }
+
index de29ddcb9459ba03f1d805f7c32f8a67ee0db078..57b5dbabeb41a50b65c242038765bf2dc0faf65e 100644 (file)
@@ -41,7 +41,7 @@ struct sys_timer;
 extern void w90x900_init_irq(void);
 extern void w90p910_init_io(struct map_desc *mach_desc, int size);
 extern void w90p910_init_uarts(struct w90x900_uartcfg *cfg, int no);
-extern void w90p910_init_clocks(int xtal);
+extern void w90p910_init_clocks(void);
 extern void w90p910_map_io(struct map_desc *mach_desc, int size);
 extern struct platform_device w90p910_serial_device;
 extern struct sys_timer w90x900_timer;
diff --git a/arch/arm/mach-w90x900/gpio.c b/arch/arm/mach-w90x900/gpio.c
new file mode 100644 (file)
index 0000000..c72e0df
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * linux/arch/arm/mach-w90p910/gpio.c
+ *
+ * Generic w90p910 GPIO handling
+ *
+ *  Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <mach/hardware.h>
+
+#define GPIO_BASE              (W90X900_VA_GPIO)
+#define GPIO_DIR               (0x04)
+#define GPIO_OUT               (0x08)
+#define GPIO_IN                        (0x0C)
+#define GROUPINERV             (0x10)
+#define GPIO_GPIO(Nb)          (0x00000001 << (Nb))
+#define to_w90p910_gpio_chip(c) container_of(c, struct w90p910_gpio_chip, chip)
+
+#define W90P910_GPIO_CHIP(name, base_gpio, nr_gpio)                    \
+       {                                                               \
+               .chip = {                                               \
+                       .label            = name,                       \
+                       .direction_input  = w90p910_dir_input,          \
+                       .direction_output = w90p910_dir_output,         \
+                       .get              = w90p910_gpio_get,           \
+                       .set              = w90p910_gpio_set,           \
+                       .base             = base_gpio,                  \
+                       .ngpio            = nr_gpio,                    \
+               }                                                       \
+       }
+
+struct w90p910_gpio_chip {
+       struct gpio_chip        chip;
+       void __iomem            *regbase;       /* Base of group register*/
+       spinlock_t              gpio_lock;
+};
+
+static int w90p910_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       struct w90p910_gpio_chip *w90p910_gpio = to_w90p910_gpio_chip(chip);
+       void __iomem *pio = w90p910_gpio->regbase + GPIO_IN;
+       unsigned int regval;
+
+       regval = __raw_readl(pio);
+       regval &= GPIO_GPIO(offset);
+
+       return (regval != 0);
+}
+
+static void w90p910_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
+{
+       struct w90p910_gpio_chip *w90p910_gpio = to_w90p910_gpio_chip(chip);
+       void __iomem *pio = w90p910_gpio->regbase + GPIO_OUT;
+       unsigned int regval;
+       unsigned long flags;
+
+       spin_lock_irqsave(&w90p910_gpio->gpio_lock, flags);
+
+       regval = __raw_readl(pio);
+
+       if (val)
+               regval |= GPIO_GPIO(offset);
+       else
+               regval &= ~GPIO_GPIO(offset);
+
+       __raw_writel(regval, pio);
+
+       spin_unlock_irqrestore(&w90p910_gpio->gpio_lock, flags);
+}
+
+static int w90p910_dir_input(struct gpio_chip *chip, unsigned offset)
+{
+       struct w90p910_gpio_chip *w90p910_gpio = to_w90p910_gpio_chip(chip);
+       void __iomem *pio = w90p910_gpio->regbase + GPIO_DIR;
+       unsigned int regval;
+       unsigned long flags;
+
+       spin_lock_irqsave(&w90p910_gpio->gpio_lock, flags);
+
+       regval = __raw_readl(pio);
+       regval &= ~GPIO_GPIO(offset);
+       __raw_writel(regval, pio);
+
+       spin_unlock_irqrestore(&w90p910_gpio->gpio_lock, flags);
+
+       return 0;
+}
+
+static int w90p910_dir_output(struct gpio_chip *chip, unsigned offset, int val)
+{
+       struct w90p910_gpio_chip *w90p910_gpio = to_w90p910_gpio_chip(chip);
+       void __iomem *outreg = w90p910_gpio->regbase + GPIO_OUT;
+       void __iomem *pio = w90p910_gpio->regbase + GPIO_DIR;
+       unsigned int regval;
+       unsigned long flags;
+
+       spin_lock_irqsave(&w90p910_gpio->gpio_lock, flags);
+
+       regval = __raw_readl(pio);
+       regval |= GPIO_GPIO(offset);
+       __raw_writel(regval, pio);
+
+       regval = __raw_readl(outreg);
+
+       if (val)
+               regval |= GPIO_GPIO(offset);
+       else
+               regval &= ~GPIO_GPIO(offset);
+
+       __raw_writel(regval, outreg);
+
+       spin_unlock_irqrestore(&w90p910_gpio->gpio_lock, flags);
+
+       return 0;
+}
+
+static struct w90p910_gpio_chip w90p910_gpio[] = {
+       W90P910_GPIO_CHIP("GROUPC", 0, 16),
+       W90P910_GPIO_CHIP("GROUPD", 16, 10),
+       W90P910_GPIO_CHIP("GROUPE", 26, 14),
+       W90P910_GPIO_CHIP("GROUPF", 40, 10),
+       W90P910_GPIO_CHIP("GROUPG", 50, 17),
+       W90P910_GPIO_CHIP("GROUPH", 67, 8),
+       W90P910_GPIO_CHIP("GROUPI", 75, 17),
+};
+
+void __init w90p910_init_gpio(int nr_group)
+{
+       unsigned        i;
+       struct w90p910_gpio_chip *gpio_chip;
+
+       for (i = 0; i < nr_group; i++) {
+               gpio_chip = &w90p910_gpio[i];
+               spin_lock_init(&gpio_chip->gpio_lock);
+               gpio_chip->regbase = GPIO_BASE + i * GROUPINERV;
+               gpiochip_add(&gpio_chip->chip);
+       }
+}
diff --git a/arch/arm/mach-w90x900/include/mach/clkdev.h b/arch/arm/mach-w90x900/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-w90x900/include/mach/gpio.h b/arch/arm/mach-w90x900/include/mach/gpio.h
new file mode 100644 (file)
index 0000000..034da3e
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * linux/arch/arm/mach-w90p910/include/mach/gpio.h
+ *
+ * Generic w90p910 GPIO handling
+ *
+ *  Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_W90P910_GPIO_H
+#define __ASM_ARCH_W90P910_GPIO_H
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm-generic/gpio.h>
+
+#define gpio_get_value __gpio_get_value
+#define gpio_set_value __gpio_set_value
+#define gpio_cansleep  __gpio_cansleep
+
+static inline int gpio_to_irq(unsigned gpio)
+{
+       return gpio;
+}
+
+static inline int irq_to_gpio(unsigned irq)
+{
+       return irq;
+}
+
+#endif
index 1c583f9cbcde93a27acaef66eb0645e63513d125..9d5cba3a509fa3a0c1fe01f55e4fa4718bd2455c 100644 (file)
@@ -1,8 +1,7 @@
 /*
  * arch/arm/mach-w90x900/include/mach/irqs.h
  *
- * Copyright (c) 2008 Nuvoton technology corporation
- * All rights reserved.
+ * Copyright (c) 2008 Nuvoton technology corporation.
  *
  * Wan ZongShun <mcuos.com@gmail.com>
  *
@@ -10,8 +9,7 @@
  *
  * 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.
+ * the Free Software Foundation;version 2 of the License.
  *
  */
 
 /* Main cpu interrupts */
 
 #define IRQ_WDT                W90X900_IRQ(1)
+#define IRQ_GROUP0     W90X900_IRQ(2)
+#define IRQ_GROUP1     W90X900_IRQ(3)
+#define IRQ_ACTL       W90X900_IRQ(4)
+#define IRQ_LCD                W90X900_IRQ(5)
+#define IRQ_RTC                W90X900_IRQ(6)
 #define IRQ_UART0      W90X900_IRQ(7)
 #define IRQ_UART1      W90X900_IRQ(8)
 #define IRQ_UART2      W90X900_IRQ(9)
 #define IRQ_TIMER0     W90X900_IRQ(12)
 #define IRQ_TIMER1     W90X900_IRQ(13)
 #define IRQ_T_INT_GROUP        W90X900_IRQ(14)
+#define IRQ_USBH       W90X900_IRQ(15)
+#define IRQ_EMCTX      W90X900_IRQ(16)
+#define IRQ_EMCRX      W90X900_IRQ(17)
+#define IRQ_GDMAGROUP  W90X900_IRQ(18)
+#define IRQ_DMAC       W90X900_IRQ(19)
+#define IRQ_FMI                W90X900_IRQ(20)
+#define IRQ_USBD       W90X900_IRQ(21)
+#define IRQ_ATAPI      W90X900_IRQ(22)
+#define IRQ_G2D                W90X900_IRQ(23)
+#define IRQ_PCI                W90X900_IRQ(24)
+#define IRQ_SCGROUP    W90X900_IRQ(25)
+#define IRQ_I2CGROUP   W90X900_IRQ(26)
+#define IRQ_SSP                W90X900_IRQ(27)
+#define IRQ_PWM                W90X900_IRQ(28)
+#define IRQ_KPI                W90X900_IRQ(29)
+#define IRQ_P2SGROUP   W90X900_IRQ(30)
 #define IRQ_ADC                W90X900_IRQ(31)
 #define NR_IRQS                (IRQ_ADC+1)
 
+/*for irq group*/
+
+#define        IRQ_PS2_PORT0   0x10000000
+#define        IRQ_PS2_PORT1   0x20000000
+#define        IRQ_I2C_LINE0   0x04000000
+#define        IRQ_I2C_LINE1   0x08000000
+#define        IRQ_SC_CARD0    0x01000000
+#define        IRQ_SC_CARD1    0x02000000
+#define        IRQ_GDMA_CH0    0x00100000
+#define        IRQ_GDMA_CH1    0x00200000
+#define        IRQ_TIMER2      0x00010000
+#define        IRQ_TIMER3      0x00020000
+#define        IRQ_TIMER4      0x00040000
+#define        IRQ_GROUP0_IRQ0 0x00000001
+#define        IRQ_GROUP0_IRQ1 0x00000002
+#define        IRQ_GROUP0_IRQ2 0x00000004
+#define        IRQ_GROUP0_IRQ3 0x00000008
+#define        IRQ_GROUP1_IRQ4 0x00000010
+#define        IRQ_GROUP1_IRQ5 0x00000020
+#define        IRQ_GROUP1_IRQ6 0x00000040
+#define        IRQ_GROUP1_IRQ7 0x00000080
+
 #endif /* __ASM_ARCH_IRQ_H */
index 79320ebe614b044799217463838a63affa3d570f..1a209530411776e916f176fc539877b649992895 100644 (file)
@@ -1,8 +1,7 @@
 /*
  * arch/arm/mach-w90x900/include/mach/map.h
  *
- * Copyright (c) 2008 Nuvoton technology corporation
- * All rights reserved.
+ * Copyright (c) 2008 Nuvoton technology corporation.
  *
  * Wan ZongShun <mcuos.com@gmail.com>
  *
@@ -10,8 +9,7 @@
  *
  * 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.
+ * the Free Software Foundation;version 2 of the License.
  *
  */
 
@@ -34,7 +32,6 @@
  * interrupt controller is the first thing we put in, to make
  * the assembly code for the irq detection easier
  */
-
 #define W90X900_VA_IRQ         W90X900_ADDR(0x00000000)
 #define W90X900_PA_IRQ         (0xB8002000)
 #define W90X900_SZ_IRQ         SZ_4K
 #define W90X900_SZ_GCR         SZ_4K
 
 /* Clock and Power management */
-
 #define W90X900_VA_CLKPWR      (W90X900_VA_GCR+0x200)
 #define W90X900_PA_CLKPWR      (0xB0000200)
 #define W90X900_SZ_CLKPWR      SZ_4K
 
 /* EBI management */
-
 #define W90X900_VA_EBI         W90X900_ADDR(0x00001000)
 #define W90X900_PA_EBI         (0xB0001000)
 #define W90X900_SZ_EBI         SZ_4K
 
 /* UARTs */
-
 #define W90X900_VA_UART                W90X900_ADDR(0x08000000)
 #define W90X900_PA_UART                (0xB8000000)
 #define W90X900_SZ_UART                SZ_4K
 
 /* Timers */
-
 #define W90X900_VA_TIMER       W90X900_ADDR(0x08001000)
 #define W90X900_PA_TIMER       (0xB8001000)
 #define W90X900_SZ_TIMER       SZ_4K
 
 /* GPIO ports */
-
 #define W90X900_VA_GPIO                W90X900_ADDR(0x08003000)
 #define W90X900_PA_GPIO                (0xB8003000)
 #define W90X900_SZ_GPIO                SZ_4K
 
+/* GDMA control */
+#define W90X900_VA_GDMA                W90X900_ADDR(0x00004000)
+#define W90X900_PA_GDMA                (0xB0004000)
+#define W90X900_SZ_GDMA                SZ_4K
+
+/* USB host controller*/
+#define W90X900_VA_USBEHCIHOST W90X900_ADDR(0x00005000)
+#define W90X900_PA_USBEHCIHOST (0xB0005000)
+#define W90X900_SZ_USBEHCIHOST SZ_4K
+
+#define W90X900_VA_USBOHCIHOST W90X900_ADDR(0x00007000)
+#define W90X900_PA_USBOHCIHOST (0xB0007000)
+#define W90X900_SZ_USBOHCIHOST SZ_4K
+
+/* I2C hardware controller */
+#define W90X900_VA_I2C         W90X900_ADDR(0x08006000)
+#define W90X900_PA_I2C         (0xB8006000)
+#define W90X900_SZ_I2C         SZ_4K
+
+/* Keypad Interface*/
+#define W90X900_VA_KPI         W90X900_ADDR(0x08008000)
+#define W90X900_PA_KPI         (0xB8008000)
+#define W90X900_SZ_KPI         SZ_4K
+
+/* Smart card host*/
+#define W90X900_VA_SC          W90X900_ADDR(0x08005000)
+#define W90X900_PA_SC          (0xB8005000)
+#define W90X900_SZ_SC          SZ_4K
+
+/* LCD controller*/
+#define W90X900_VA_LCD         W90X900_ADDR(0x00008000)
+#define W90X900_PA_LCD         (0xB0008000)
+#define W90X900_SZ_LCD         SZ_4K
+
+/* 2D controller*/
+#define W90X900_VA_GE          W90X900_ADDR(0x0000B000)
+#define W90X900_PA_GE          (0xB000B000)
+#define W90X900_SZ_GE          SZ_4K
+
+/* ATAPI */
+#define W90X900_VA_ATAPI       W90X900_ADDR(0x0000A000)
+#define W90X900_PA_ATAPI       (0xB000A000)
+#define W90X900_SZ_ATAPI       SZ_4K
+
+/* ADC */
+#define W90X900_VA_ADC         W90X900_ADDR(0x0800A000)
+#define W90X900_PA_ADC         (0xB800A000)
+#define W90X900_SZ_ADC         SZ_4K
+
+/* PS2 Interface*/
+#define W90X900_VA_PS2         W90X900_ADDR(0x08009000)
+#define W90X900_PA_PS2         (0xB8009000)
+#define W90X900_SZ_PS2         SZ_4K
+
+/* RTC */
+#define W90X900_VA_RTC         W90X900_ADDR(0x08004000)
+#define W90X900_PA_RTC         (0xB8004000)
+#define W90X900_SZ_RTC         SZ_4K
+
+/* Pulse Width Modulation(PWM) Registers */
+#define W90X900_VA_PWM         W90X900_ADDR(0x08007000)
+#define W90X900_PA_PWM         (0xB8007000)
+#define W90X900_SZ_PWM         SZ_4K
+
+/* Audio Controller controller */
+#define W90X900_VA_ACTL                W90X900_ADDR(0x00009000)
+#define W90X900_PA_ACTL                (0xB0009000)
+#define W90X900_SZ_ACTL                SZ_4K
+
+/* DMA controller */
+#define W90X900_VA_DMA         W90X900_ADDR(0x0000c000)
+#define W90X900_PA_DMA         (0xB000c000)
+#define W90X900_SZ_DMA         SZ_4K
+
+/* FMI controller */
+#define W90X900_VA_FMI         W90X900_ADDR(0x0000d000)
+#define W90X900_PA_FMI         (0xB000d000)
+#define W90X900_SZ_FMI         SZ_4K
+
+/* USB Device port */
+#define W90X900_VA_USBDEV      W90X900_ADDR(0x00006000)
+#define W90X900_PA_USBDEV      (0xB0006000)
+#define W90X900_SZ_USBDEV      SZ_4K
+
+/* External MAC control*/
+#define W90X900_VA_EMC         W90X900_ADDR(0x00003000)
+#define W90X900_PA_EMC         (0xB0003000)
+#define W90X900_SZ_EMC         SZ_4K
+
 #endif /* __ASM_ARCH_MAP_H */
diff --git a/arch/arm/mach-w90x900/include/mach/regs-clock.h b/arch/arm/mach-w90x900/include/mach/regs-clock.h
new file mode 100644 (file)
index 0000000..f10b6a8
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * arch/arm/mach-w90x900/include/mach/regs-clock.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation;version 2 of the License.
+ *
+ */
+
+#ifndef __ASM_ARCH_REGS_CLOCK_H
+#define __ASM_ARCH_REGS_CLOCK_H
+
+/* Clock Control Registers  */
+#define CLK_BA         W90X900_VA_CLKPWR
+#define REG_CLKEN      (CLK_BA + 0x00)
+#define REG_CLKSEL     (CLK_BA + 0x04)
+#define REG_CLKDIV     (CLK_BA + 0x08)
+#define REG_PLLCON0    (CLK_BA + 0x0C)
+#define REG_PLLCON1    (CLK_BA + 0x10)
+#define REG_PMCON      (CLK_BA + 0x14)
+#define REG_IRQWAKECON (CLK_BA + 0x18)
+#define REG_IRQWAKEFLAG        (CLK_BA + 0x1C)
+#define REG_IPSRST     (CLK_BA + 0x20)
+#define REG_CLKEN1     (CLK_BA + 0x24)
+#define REG_CLKDIV1    (CLK_BA + 0x28)
+
+#endif /*  __ASM_ARCH_REGS_CLOCK_H */
diff --git a/arch/arm/mach-w90x900/include/mach/regs-usb.h b/arch/arm/mach-w90x900/include/mach/regs-usb.h
new file mode 100644 (file)
index 0000000..ab74b0c
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * arch/arm/mach-w90x900/include/mach/regs-usb.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation;version 2 of the License.
+ *
+ */
+
+#ifndef __ASM_ARCH_REGS_USB_H
+#define __ASM_ARCH_REGS_USB_H
+
+/* usb Control Registers  */
+#define USBH_BA                W90X900_VA_USBEHCIHOST
+#define USBD_BA                W90X900_VA_USBDEV
+#define USBO_BA                W90X900_VA_USBOHCIHOST
+
+/* USB Host Control Registers */
+#define REG_UPSCR0     (USBH_BA+0x064)
+#define REG_UPSCR1     (USBH_BA+0x068)
+#define REG_USBPCR0    (USBH_BA+0x0C4)
+#define REG_USBPCR1    (USBH_BA+0x0C8)
+
+/* USBH OHCI Control Registers */
+#define REG_OpModEn    (USBO_BA+0x204)
+/*This bit controls the polarity of over
+*current flag from external power IC.
+*/
+#define OCALow         0x08
+
+#endif /*  __ASM_ARCH_REGS_USB_H */
index 726ff6798a5630cee92197bab18bfde4202ee737..7a62bd348e80ddb39b0e0ee75b368813284eb16f 100644 (file)
@@ -3,15 +3,13 @@
  *
  * Based on mach-s3c2410/mach-smdk2410.c by Jonas Dietsche
  *
- * Copyright (C) 2008 Nuvoton technology corporation
- * All rights reserved.
+ * Copyright (C) 2008 Nuvoton technology corporation.
  *
  * Wan ZongShun <mcuos.com@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.
+ * published by the Free Software Foundation;version 2 of the License.
  *
  */
 
@@ -80,6 +78,156 @@ static struct platform_device w90p910_flash_device = {
        .num_resources  =       ARRAY_SIZE(w90p910_flash_resources),
 };
 
+/* USB EHCI Host Controller */
+
+static struct resource w90x900_usb_ehci_resource[] = {
+       [0] = {
+               .start = W90X900_PA_USBEHCIHOST,
+               .end   = W90X900_PA_USBEHCIHOST + W90X900_SZ_USBEHCIHOST - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_USBH,
+               .end   = IRQ_USBH,
+               .flags = IORESOURCE_IRQ,
+       }
+};
+
+static u64 w90x900_device_usb_ehci_dmamask = 0xffffffffUL;
+
+struct platform_device w90x900_device_usb_ehci = {
+       .name             = "w90x900-ehci",
+       .id               = -1,
+       .num_resources    = ARRAY_SIZE(w90x900_usb_ehci_resource),
+       .resource         = w90x900_usb_ehci_resource,
+       .dev              = {
+               .dma_mask = &w90x900_device_usb_ehci_dmamask,
+               .coherent_dma_mask = 0xffffffffUL
+       }
+};
+EXPORT_SYMBOL(w90x900_device_usb_ehci);
+
+/* USB OHCI Host Controller */
+
+static struct resource w90x900_usb_ohci_resource[] = {
+       [0] = {
+               .start = W90X900_PA_USBOHCIHOST,
+               .end   = W90X900_PA_USBOHCIHOST + W90X900_SZ_USBOHCIHOST - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_USBH,
+               .end   = IRQ_USBH,
+               .flags = IORESOURCE_IRQ,
+       }
+};
+
+static u64 w90x900_device_usb_ohci_dmamask = 0xffffffffUL;
+struct platform_device w90x900_device_usb_ohci = {
+       .name             = "w90x900-ohci",
+       .id               = -1,
+       .num_resources    = ARRAY_SIZE(w90x900_usb_ohci_resource),
+       .resource         = w90x900_usb_ohci_resource,
+       .dev              = {
+               .dma_mask = &w90x900_device_usb_ohci_dmamask,
+               .coherent_dma_mask = 0xffffffffUL
+       }
+};
+EXPORT_SYMBOL(w90x900_device_usb_ohci);
+
+/*TouchScreen controller*/
+
+static struct resource w90x900_ts_resource[] = {
+       [0] = {
+               .start = W90X900_PA_ADC,
+               .end   = W90X900_PA_ADC + W90X900_SZ_ADC-1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_ADC,
+               .end   = IRQ_ADC,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device w90x900_device_ts = {
+       .name           = "w90x900-ts",
+       .id             = -1,
+       .resource       = w90x900_ts_resource,
+       .num_resources  = ARRAY_SIZE(w90x900_ts_resource),
+};
+EXPORT_SYMBOL(w90x900_device_ts);
+
+/* RTC controller*/
+
+static struct resource w90x900_rtc_resource[] = {
+       [0] = {
+               .start = W90X900_PA_RTC,
+               .end   = W90X900_PA_RTC + 0xff,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_RTC,
+               .end   = IRQ_RTC,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device w90x900_device_rtc = {
+       .name           = "w90x900-rtc",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(w90x900_rtc_resource),
+       .resource       = w90x900_rtc_resource,
+};
+EXPORT_SYMBOL(w90x900_device_rtc);
+
+/* KPI controller*/
+
+static struct resource w90x900_kpi_resource[] = {
+       [0] = {
+               .start = W90X900_PA_KPI,
+               .end   = W90X900_PA_KPI + W90X900_SZ_KPI - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_KPI,
+               .end   = IRQ_KPI,
+               .flags = IORESOURCE_IRQ,
+       }
+
+};
+
+struct platform_device w90x900_device_kpi = {
+       .name           = "w90x900-kpi",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(w90x900_kpi_resource),
+       .resource       = w90x900_kpi_resource,
+};
+EXPORT_SYMBOL(w90x900_device_kpi);
+
+/* USB Device (Gadget)*/
+
+static struct resource w90x900_usbgadget_resource[] = {
+       [0] = {
+               .start = W90X900_PA_USBDEV,
+               .end   = W90X900_PA_USBDEV + W90X900_SZ_USBDEV - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_USBD,
+               .end   = IRQ_USBD,
+               .flags = IORESOURCE_IRQ,
+       }
+};
+
+struct platform_device w90x900_device_usbgadget = {
+       .name           = "w90x900-usbgadget",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(w90x900_usbgadget_resource),
+       .resource       = w90x900_usbgadget_resource,
+};
+EXPORT_SYMBOL(w90x900_device_usbgadget);
+
 static struct map_desc w90p910_iodesc[] __initdata = {
 };
 
@@ -88,12 +236,18 @@ static struct map_desc w90p910_iodesc[] __initdata = {
 static struct platform_device *w90p910evb_dev[] __initdata = {
        &w90p910_serial_device,
        &w90p910_flash_device,
+       &w90x900_device_usb_ehci,
+       &w90x900_device_usb_ohci,
+       &w90x900_device_ts,
+       &w90x900_device_rtc,
+       &w90x900_device_kpi,
+       &w90x900_device_usbgadget,
 };
 
 static void __init w90p910evb_map_io(void)
 {
        w90p910_map_io(w90p910_iodesc, ARRAY_SIZE(w90p910_iodesc));
-       w90p910_init_clocks(0);
+       w90p910_init_clocks();
 }
 
 static void __init w90p910evb_init(void)
diff --git a/arch/arm/mach-w90x900/mfp-w90p910.c b/arch/arm/mach-w90x900/mfp-w90p910.c
new file mode 100644 (file)
index 0000000..a3520fe
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * linux/arch/arm/mach-w90x900/mfp-w90p910.c
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation;version 2 of the License.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+
+#define REG_MFSEL      (W90X900_VA_GCR + 0xC)
+
+#define GPSELF         (0x01 << 1)
+
+#define GPSELC         (0x03 << 2)
+#define ENKPI          (0x02 << 2)
+#define ENNAND         (0x01 << 2)
+
+#define GPSELEI0       (0x01 << 26)
+#define GPSELEI1       (0x01 << 27)
+
+static DECLARE_MUTEX(mfp_sem);
+
+void mfp_set_groupf(struct device *dev)
+{
+       unsigned long mfpen;
+       const char *dev_id;
+
+       BUG_ON(!dev);
+
+       down(&mfp_sem);
+
+       dev_id = dev_name(dev);
+
+       mfpen = __raw_readl(REG_MFSEL);
+
+       if (strcmp(dev_id, "w90p910-emc") == 0)
+               mfpen |= GPSELF;/*enable mac*/
+       else
+               mfpen &= ~GPSELF;/*GPIOF[9:0]*/
+
+       __raw_writel(mfpen, REG_MFSEL);
+
+       up(&mfp_sem);
+}
+EXPORT_SYMBOL(mfp_set_groupf);
+
+void mfp_set_groupc(struct device *dev)
+{
+       unsigned long mfpen;
+       const char *dev_id;
+
+       BUG_ON(!dev);
+
+       down(&mfp_sem);
+
+       dev_id = dev_name(dev);
+
+       mfpen = __raw_readl(REG_MFSEL);
+
+       if (strcmp(dev_id, "w90p910-lcd") == 0)
+               mfpen |= GPSELC;/*enable lcd*/
+       else if (strcmp(dev_id, "w90p910-kpi") == 0) {
+                       mfpen &= (~GPSELC);/*enable kpi*/
+                       mfpen |= ENKPI;
+               } else if (strcmp(dev_id, "w90p910-nand") == 0) {
+                               mfpen &= (~GPSELC);/*enable nand*/
+                               mfpen |= ENNAND;
+                       } else
+                               mfpen &= (~GPSELC);/*GPIOC[14:0]*/
+
+       __raw_writel(mfpen, REG_MFSEL);
+
+       up(&mfp_sem);
+}
+EXPORT_SYMBOL(mfp_set_groupc);
+
+void mfp_set_groupi(struct device *dev, int gpio)
+{
+       unsigned long mfpen;
+       const char *dev_id;
+
+       BUG_ON(!dev);
+
+       down(&mfp_sem);
+
+       dev_id = dev_name(dev);
+
+       mfpen = __raw_readl(REG_MFSEL);
+
+       if (strcmp(dev_id, "w90p910-wdog") == 0)
+               mfpen |= GPSELEI1;/*enable wdog*/
+               else if (strcmp(dev_id, "w90p910-atapi") == 0)
+                       mfpen |= GPSELEI0;/*enable atapi*/
+
+       __raw_writel(mfpen, REG_MFSEL);
+
+       up(&mfp_sem);
+}
+EXPORT_SYMBOL(mfp_set_groupi);
+
index 2bcbaa681b9925ba8ba15e885d4a08eb44dab64f..1c97e4930b7ab0a6e7f6da6a7261cbc9c3de0371 100644 (file)
@@ -3,8 +3,7 @@
  *
  * Based on linux/arch/arm/plat-s3c24xx/s3c244x.c by Ben Dooks
  *
- * Copyright (c) 2008 Nuvoton technology corporation
- * All rights reserved.
+ * Copyright (c) 2008 Nuvoton technology corporation.
  *
  * Wan ZongShun <mcuos.com@gmail.com>
  *
@@ -12,8 +11,7 @@
  *
  * 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.
+ * the Free Software Foundation;version 2 of the License.
  *
  */
 
@@ -36,6 +34,7 @@
 #include <mach/regs-serial.h>
 
 #include "cpu.h"
+#include "clock.h"
 
 /* Initial IO mappings */
 
@@ -45,9 +44,52 @@ static struct map_desc w90p910_iodesc[] __initdata = {
        IODESC_ENT(UART),
        IODESC_ENT(TIMER),
        IODESC_ENT(EBI),
+       IODESC_ENT(USBEHCIHOST),
+       IODESC_ENT(USBOHCIHOST),
+       IODESC_ENT(ADC),
+       IODESC_ENT(RTC),
+       IODESC_ENT(KPI),
+       IODESC_ENT(USBDEV),
        /*IODESC_ENT(LCD),*/
 };
 
+/* Initial clock declarations. */
+static DEFINE_CLK(lcd, 0);
+static DEFINE_CLK(audio, 1);
+static DEFINE_CLK(fmi, 4);
+static DEFINE_CLK(dmac, 5);
+static DEFINE_CLK(atapi, 6);
+static DEFINE_CLK(emc, 7);
+static DEFINE_CLK(usbd, 8);
+static DEFINE_CLK(usbh, 9);
+static DEFINE_CLK(g2d, 10);;
+static DEFINE_CLK(pwm, 18);
+static DEFINE_CLK(ps2, 24);
+static DEFINE_CLK(kpi, 25);
+static DEFINE_CLK(wdt, 26);
+static DEFINE_CLK(gdma, 27);
+static DEFINE_CLK(adc, 28);
+static DEFINE_CLK(usi, 29);
+
+static struct clk_lookup w90p910_clkregs[] = {
+       DEF_CLKLOOK(&clk_lcd, "w90p910-lcd", NULL),
+       DEF_CLKLOOK(&clk_audio, "w90p910-audio", NULL),
+       DEF_CLKLOOK(&clk_fmi, "w90p910-fmi", NULL),
+       DEF_CLKLOOK(&clk_dmac, "w90p910-dmac", NULL),
+       DEF_CLKLOOK(&clk_atapi, "w90p910-atapi", NULL),
+       DEF_CLKLOOK(&clk_emc, "w90p910-emc", NULL),
+       DEF_CLKLOOK(&clk_usbd, "w90p910-usbd", NULL),
+       DEF_CLKLOOK(&clk_usbh, "w90p910-usbh", NULL),
+       DEF_CLKLOOK(&clk_g2d, "w90p910-g2d", NULL),
+       DEF_CLKLOOK(&clk_pwm, "w90p910-pwm", NULL),
+       DEF_CLKLOOK(&clk_ps2, "w90p910-ps2", NULL),
+       DEF_CLKLOOK(&clk_kpi, "w90p910-kpi", NULL),
+       DEF_CLKLOOK(&clk_wdt, "w90p910-wdt", NULL),
+       DEF_CLKLOOK(&clk_gdma, "w90p910-gdma", NULL),
+       DEF_CLKLOOK(&clk_adc, "w90p910-adc", NULL),
+       DEF_CLKLOOK(&clk_usi, "w90p910-usi", NULL),
+};
+
 /* Initial serial platform data */
 
 struct plat_serial8250_port w90p910_uart_data[] = {
@@ -77,8 +119,9 @@ void __init w90p910_map_io(struct map_desc *mach_desc, int mach_size)
 
 /*Init W90P910 clock*/
 
-void __init w90p910_init_clocks(int xtal)
+void __init w90p910_init_clocks(void)
 {
+       clks_register(w90p910_clkregs, ARRAY_SIZE(w90p910_clkregs));
 }
 
 static int __init w90p910_init_cpu(void)
index 20979564e7ee3cc04825e43f4b4af42bc7fc65be..83c025e72ceb6877c7a5994875832ab8f16c8462 100644 (file)
@@ -391,7 +391,7 @@ config CPU_FEROCEON_OLD_ID
 
 # ARMv6
 config CPU_V6
-       bool "Support ARM V6 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB
+       bool "Support ARM V6 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX
        select CPU_32v6
        select CPU_ABRT_EV6
        select CPU_PABRT_NOIFAR
@@ -416,7 +416,7 @@ config CPU_32v6K
 
 # ARMv7
 config CPU_V7
-       bool "Support ARM V7 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB
+       bool "Support ARM V7 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX
        select CPU_32v6K
        select CPU_32v7
        select CPU_ABRT_EV7
@@ -639,10 +639,23 @@ config CPU_BIG_ENDIAN
          port must properly enable any big-endian related features
          of your chipset/board/processor.
 
+config CPU_ENDIAN_BE8
+       bool
+       depends on CPU_BIG_ENDIAN
+       default CPU_V6 || CPU_V7
+       help
+         Support for the BE-8 (big-endian) mode on ARMv6 and ARMv7 processors.
+
+config CPU_ENDIAN_BE32
+       bool
+       depends on CPU_BIG_ENDIAN
+       default !CPU_ENDIAN_BE8
+       help
+         Support for the BE-32 (big-endian) mode on pre-ARMv6 processors.
+
 config CPU_HIGH_VECTOR
        depends on !MMU && CPU_CP15 && !CPU_ARM740T
        bool "Select the High exception vector"
-       default n
        help
          Say Y here to select high exception vector(0xFFFF0000~).
          The exception vector can be vary depending on the platform
@@ -726,7 +739,6 @@ config NEEDS_SYSCALL_FOR_CMPXCHG
 
 config OUTER_CACHE
        bool
-       default n
 
 config CACHE_FEROCEON_L2
        bool "Enable the Feroceon L2 cache controller"
@@ -739,7 +751,6 @@ config CACHE_FEROCEON_L2
 config CACHE_FEROCEON_L2_WRITETHROUGH
        bool "Force Feroceon L2 cache write through"
        depends on CACHE_FEROCEON_L2
-       default n
        help
          Say Y here to use the Feroceon L2 cache in writethrough mode.
          Unless you specifically require this, say N for writeback mode.
@@ -747,7 +758,7 @@ config CACHE_FEROCEON_L2_WRITETHROUGH
 config CACHE_L2X0
        bool "Enable the L2x0 outer cache controller"
        depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || \
-                  REALVIEW_EB_A9MP || ARCH_MX35 || ARCH_MX31
+                  REALVIEW_EB_A9MP || ARCH_MX35 || ARCH_MX31 || MACH_REALVIEW_PBX
        default y
        select OUTER_CACHE
        help
index 6f7e70907e443c708b6cd67e59df07ba86f56302..f332df7f0d37be504eb1d2af35efae5edc4a579c 100644 (file)
@@ -37,6 +37,9 @@ ENTRY(v6_early_abort)
        movne   pc, lr
        do_thumb_abort
        ldreq   r3, [r2]                        @ read aborted ARM instruction
+#ifdef CONFIG_CPU_ENDIAN_BE8
+       reveq   r3, r3
+#endif
        do_ldrd_abort
        tst     r3, #1 << 20                    @ L = 0 -> write
        orreq   r1, r1, #1 << 11                @ yes.
index 9f88dd3be6019ec850e4d5a789ceaf623bb91a92..0ab75c60f7cfdf4745cc1f9c48d87db61cb93918 100644 (file)
@@ -110,6 +110,12 @@ static int remap_area_pages(unsigned long start, unsigned long pfn,
        return err;
 }
 
+int ioremap_page(unsigned long virt, unsigned long phys,
+                const struct mem_type *mtype)
+{
+       return remap_area_pages(virt, __phys_to_pfn(phys), PAGE_SIZE, mtype);
+}
+EXPORT_SYMBOL(ioremap_page);
 
 void __check_kvm_seq(struct mm_struct *mm)
 {
index e6344ece00cee9c6e026bbe3b443e203745534e9..fdaa9bb87c163b89b19d8daa40f15352a1c06447 100644 (file)
@@ -255,6 +255,7 @@ const struct mem_type *get_mem_type(unsigned int type)
 {
        return type < ARRAY_SIZE(mem_types) ? &mem_types[type] : NULL;
 }
+EXPORT_SYMBOL(get_mem_type);
 
 /*
  * Adjust the PMD section entries according to the CPU in use.
@@ -839,6 +840,20 @@ void __init reserve_node_zero(pg_data_t *pgdat)
                reserve_bootmem_node(pgdat, 0xa0200000, 0x1000,
                                BOOTMEM_EXCLUSIVE);
 
+       /*
+        * U300 - This platform family can share physical memory
+        * between two ARM cpus, one running Linux and the other
+        * running another OS.
+        */
+       if (machine_is_u300()) {
+#ifdef CONFIG_MACH_U300_SINGLE_RAM
+#if ((CONFIG_MACH_U300_ACCESS_MEM_SIZE & 1) == 1) &&   \
+       CONFIG_MACH_U300_2MB_ALIGNMENT_FIX
+               res_size = 0x00100000;
+#endif
+#endif
+       }
+
 #ifdef CONFIG_SA1111
        /*
         * Because of the SA1111 DMA bug, we want to preserve our
index 087e239704df197baf2102cbca52dc2ccfb780d6..524ddae92595052c19ef0e015ab9ed09b24d4026 100644 (file)
@@ -170,6 +170,9 @@ __v6_setup:
 #endif /* CONFIG_MMU */
        adr     r5, v6_crval
        ldmia   r5, {r5, r6}
+#ifdef CONFIG_CPU_ENDIAN_BE8
+       orr     r6, r6, #1 << 25                @ big-endian page tables
+#endif
        mrc     p15, 0, r0, c1, c0, 0           @ read control register
        bic     r0, r0, r5                      @ clear bits them
        orr     r0, r0, r6                      @ set them
index a08d9d2380d3e357dedbf743111e0eac45721b09..180a08d03a03b60a46433017782c4586286fd735 100644 (file)
 
 #include "proc-macros.S"
 
-#define TTB_C          (1 << 0)
 #define TTB_S          (1 << 1)
 #define TTB_RGN_NC     (0 << 3)
 #define TTB_RGN_OC_WBWA        (1 << 3)
 #define TTB_RGN_OC_WT  (2 << 3)
 #define TTB_RGN_OC_WB  (3 << 3)
+#define TTB_NOS                (1 << 5)
+#define TTB_IRGN_NC    ((0 << 0) | (0 << 6))
+#define TTB_IRGN_WBWA  ((0 << 0) | (1 << 6))
+#define TTB_IRGN_WT    ((1 << 0) | (0 << 6))
+#define TTB_IRGN_WB    ((1 << 0) | (1 << 6))
 
 #ifndef CONFIG_SMP
-#define TTB_FLAGS      TTB_C|TTB_RGN_OC_WB             @ mark PTWs cacheable, outer WB
+/* PTWs cacheable, inner WB not shareable, outer WB not shareable */
+#define TTB_FLAGS      TTB_IRGN_WB|TTB_RGN_OC_WB
 #else
-#define TTB_FLAGS      TTB_C|TTB_S|TTB_RGN_OC_WBWA     @ mark PTWs cacheable and shared, outer WBWA
+/* PTWs cacheable, inner WBWA shareable, outer WBWA not shareable */
+#define TTB_FLAGS      TTB_IRGN_WBWA|TTB_S|TTB_NOS|TTB_RGN_OC_WBWA
 #endif
 
 ENTRY(cpu_v7_proc_init)
@@ -176,8 +182,8 @@ cpu_v7_name:
  */
 __v7_setup:
 #ifdef CONFIG_SMP
-       mrc     p15, 0, r0, c1, c0, 1           @ Enable SMP/nAMP mode
-       orr     r0, r0, #(0x1 << 6)
+       mrc     p15, 0, r0, c1, c0, 1           @ Enable SMP/nAMP mode and
+       orr     r0, r0, #(1 << 6) | (1 << 0)    @ TLB ops broadcasting
        mcr     p15, 0, r0, c1, c0, 1
 #endif
        adr     r12, __v7_setup_stack           @ the local stack
@@ -227,12 +233,43 @@ __v7_setup:
        mov     r10, #0x1f                      @ domains 0, 1 = manager
        mcr     p15, 0, r10, c3, c0, 0          @ load domain access register
 #endif
-       ldr     r5, =0xff0aa1a8
-       ldr     r6, =0x40e040e0
+       /*
+        * Memory region attributes with SCTLR.TRE=1
+        *
+        *   n = TEX[0],C,B
+        *   TR = PRRR[2n+1:2n]         - memory type
+        *   IR = NMRR[2n+1:2n]         - inner cacheable property
+        *   OR = NMRR[2n+17:2n+16]     - outer cacheable property
+        *
+        *                      n       TR      IR      OR
+        *   UNCACHED           000     00
+        *   BUFFERABLE         001     10      00      00
+        *   WRITETHROUGH       010     10      10      10
+        *   WRITEBACK          011     10      11      11
+        *   reserved           110
+        *   WRITEALLOC         111     10      01      01
+        *   DEV_SHARED         100     01
+        *   DEV_NONSHARED      100     01
+        *   DEV_WC             001     10
+        *   DEV_CACHED         011     10
+        *
+        * Other attributes:
+        *
+        *   DS0 = PRRR[16] = 0         - device shareable property
+        *   DS1 = PRRR[17] = 1         - device shareable property
+        *   NS0 = PRRR[18] = 0         - normal shareable property
+        *   NS1 = PRRR[19] = 1         - normal shareable property
+        *   NOS = PRRR[24+n] = 1       - not outer shareable
+        */
+       ldr     r5, =0xff0a81a8                 @ PRRR
+       ldr     r6, =0x40e040e0                 @ NMRR
        mcr     p15, 0, r5, c10, c2, 0          @ write PRRR
        mcr     p15, 0, r6, c10, c2, 1          @ write NMRR
        adr     r5, v7_crval
        ldmia   r5, {r5, r6}
+#ifdef CONFIG_CPU_ENDIAN_BE8
+       orr     r6, r6, #1 << 25                @ big-endian page tables
+#endif
        mrc     p15, 0, r0, c1, c0, 0           @ read control register
        bic     r0, r0, r5                      @ clear bits them
        orr     r0, r0, r6                      @ set them
@@ -240,14 +277,14 @@ __v7_setup:
 ENDPROC(__v7_setup)
 
        /*   AT
-        *  TFR   EV X F   I D LR
-        * .EEE ..EE PUI. .T.T 4RVI ZFRS BLDP WCAM
+        *  TFR   EV X F   I D LR    S
+        * .EEE ..EE PUI. .T.T 4RVI ZWRS BLDP WCAM
         * rxxx rrxx xxx0 0101 xxxx xxxx x111 xxxx < forced
-        *    1    0 110       0011 1.00 .111 1101 < we want
+        *    1    0 110       0011 1100 .111 1101 < we want
         */
        .type   v7_crval, #object
 v7_crval:
-       crval   clear=0x0120c302, mmuset=0x10c0387d, ucset=0x00c0187c
+       crval   clear=0x0120c302, mmuset=0x10c03c7d, ucset=0x00c01c7c
 
 __v7_setup_stack:
        .space  4 * 11                          @ 11 registers
index b637e7380ab7ed100f74ad1db3e9d31aaf15c0e5..a26a605b73bd91688417dddc00378f286bfc6a33 100644 (file)
@@ -42,9 +42,11 @@ ENTRY(v7wbi_flush_user_tlb_range)
        mov     r1, r1, lsl #PAGE_SHIFT
        vma_vm_flags r2, r2                     @ get vma->vm_flags
 1:
-       mcr     p15, 0, r0, c8, c6, 1           @ TLB invalidate D MVA (was 1)
-       tst     r2, #VM_EXEC                    @ Executable area ?
-       mcrne   p15, 0, r0, c8, c5, 1           @ TLB invalidate I MVA (was 1)
+#ifdef CONFIG_SMP
+       mcr     p15, 0, r0, c8, c3, 1           @ TLB invalidate U MVA (shareable) 
+#else
+       mcr     p15, 0, r0, c8, c7, 1           @ TLB invalidate U MVA
+#endif
        add     r0, r0, #PAGE_SZ
        cmp     r0, r1
        blo     1b
@@ -69,8 +71,11 @@ ENTRY(v7wbi_flush_kern_tlb_range)
        mov     r0, r0, lsl #PAGE_SHIFT
        mov     r1, r1, lsl #PAGE_SHIFT
 1:
-       mcr     p15, 0, r0, c8, c6, 1           @ TLB invalidate D MVA
-       mcr     p15, 0, r0, c8, c5, 1           @ TLB invalidate I MVA
+#ifdef CONFIG_SMP
+       mcr     p15, 0, r0, c8, c3, 1           @ TLB invalidate U MVA (shareable)
+#else
+       mcr     p15, 0, r0, c8, c7, 1           @ TLB invalidate U MVA
+#endif
        add     r0, r0, #PAGE_SZ
        cmp     r0, r1
        blo     1b
@@ -87,5 +92,5 @@ ENDPROC(v7wbi_flush_kern_tlb_range)
 ENTRY(v7wbi_tlb_fns)
        .long   v7wbi_flush_user_tlb_range
        .long   v7wbi_flush_kern_tlb_range
-       .long   v6wbi_tlb_flags
+       .long   v7wbi_tlb_flags
        .size   v7wbi_tlb_fns, . - v7wbi_tlb_fns
index 853d42bb8682c83b517bf656ae922d4ce5cd3b63..4ce0f9801e2ef2c5ea9d92e29ec1c680b8335aec 100644 (file)
@@ -41,6 +41,7 @@
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
 #include <mach/hardware.h>
+#include <mach/board-eb.h>
 #include <asm/system.h>
 
 #include "op_counter.h"
index 17d0e9906d5f6ac9fc2ed64af14feef4727115c5..8986b7412235c7b6e51ebcd7c061a727e0599d3f 100644 (file)
@@ -48,7 +48,14 @@ config MXC_IRQ_PRIOR
 config MXC_PWM
        tristate "Enable PWM driver"
        depends on ARCH_MXC
+       select HAVE_PWM
        help
          Enable support for the i.MX PWM controller(s).
 
+config ARCH_HAS_RNGA
+       bool
+       depends on ARCH_MXC
+
+config ARCH_MXC_IOMUX_V3
+       bool
 endif
index 055406312b6947698e41a53f5de6d548be3a492d..e3212c8ff4215e46c5f98e37a6972f0584557ac5 100644 (file)
@@ -7,4 +7,5 @@ obj-y := irq.o clock.o gpio.o time.o devices.o cpu.o system.o
 
 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
index 89e95798cc3ba096aa09f1bf0e0a7bf8b42ff82e..7506d963be4b41ba746f543f7ba10b6b5b818c5c 100644 (file)
@@ -64,6 +64,8 @@ static void gpio_unmask_irq(u32 irq)
        _set_gpio_irqenable(&mxc_gpio_ports[gpio / 32], gpio & 0x1f, 1);
 }
 
+static int mxc_gpio_get(struct gpio_chip *chip, unsigned offset);
+
 static int gpio_set_irq_type(u32 irq, u32 type)
 {
        u32 gpio = irq_to_gpio(irq);
@@ -72,6 +74,7 @@ static int gpio_set_irq_type(u32 irq, u32 type)
        int edge;
        void __iomem *reg = port->base;
 
+       port->both_edges &= ~(1 << (gpio & 31));
        switch (type) {
        case IRQ_TYPE_EDGE_RISING:
                edge = GPIO_INT_RISE_EDGE;
@@ -79,13 +82,24 @@ static int gpio_set_irq_type(u32 irq, u32 type)
        case IRQ_TYPE_EDGE_FALLING:
                edge = GPIO_INT_FALL_EDGE;
                break;
+       case IRQ_TYPE_EDGE_BOTH:
+               val = mxc_gpio_get(&port->chip, gpio & 31);
+               if (val) {
+                       edge = GPIO_INT_LOW_LEV;
+                       pr_debug("mxc: set GPIO %d to low trigger\n", gpio);
+               } else {
+                       edge = GPIO_INT_HIGH_LEV;
+                       pr_debug("mxc: set GPIO %d to high trigger\n", gpio);
+               }
+               port->both_edges |= 1 << (gpio & 31);
+               break;
        case IRQ_TYPE_LEVEL_LOW:
                edge = GPIO_INT_LOW_LEV;
                break;
        case IRQ_TYPE_LEVEL_HIGH:
                edge = GPIO_INT_HIGH_LEV;
                break;
-       default:        /* this includes IRQ_TYPE_EDGE_BOTH */
+       default:
                return -EINVAL;
        }
 
@@ -98,6 +112,34 @@ static int gpio_set_irq_type(u32 irq, u32 type)
        return 0;
 }
 
+static void mxc_flip_edge(struct mxc_gpio_port *port, u32 gpio)
+{
+       void __iomem *reg = port->base;
+       u32 bit, val;
+       int edge;
+
+       reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */
+       bit = gpio & 0xf;
+       val = __raw_readl(reg);
+       edge = (val >> (bit << 1)) & 3;
+       val &= ~(0x3 << (bit << 1));
+       switch (edge) {
+       case GPIO_INT_HIGH_LEV:
+               edge = GPIO_INT_LOW_LEV;
+               pr_debug("mxc: switch GPIO %d to low trigger\n", gpio);
+               break;
+       case GPIO_INT_LOW_LEV:
+               edge = GPIO_INT_HIGH_LEV;
+               pr_debug("mxc: switch GPIO %d to high trigger\n", gpio);
+               break;
+       default:
+               pr_err("mxc: invalid configuration for GPIO %d: %x\n",
+                      gpio, edge);
+               return;
+       }
+       __raw_writel(val | (edge << (bit << 1)), reg);
+}
+
 /* handle n interrupts in one status register */
 static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat)
 {
@@ -105,11 +147,16 @@ static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat)
 
        gpio_irq_no = port->virtual_irq_start;
        for (; irq_stat != 0; irq_stat >>= 1, gpio_irq_no++) {
+               u32 gpio = irq_to_gpio(gpio_irq_no);
 
                if ((irq_stat & 1) == 0)
                        continue;
 
                BUG_ON(!(irq_desc[gpio_irq_no].handle_irq));
+
+               if (port->both_edges & (1 << (gpio & 31)))
+                       mxc_flip_edge(port, gpio);
+
                irq_desc[gpio_irq_no].handle_irq(gpio_irq_no,
                                &irq_desc[gpio_irq_no]);
        }
diff --git a/arch/arm/plat-mxc/include/mach/board-armadillo5x0.h b/arch/arm/plat-mxc/include/mach/board-armadillo5x0.h
new file mode 100644 (file)
index 0000000..8769e91
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com>.
+ * 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.
+ */
+
+#ifndef __ASM_ARCH_MXC_BOARD_ARMADILLO5X0_H__
+#define __ASM_ARCH_MXC_BOARD_ARMADILLO5X0_H__
+
+#include <mach/hardware.h>
+
+/* mandatory for CONFIG_DEBUG_LL */
+
+#define MXC_LL_UART_PADDR      UART1_BASE_ADDR
+#define MXC_LL_UART_VADDR      AIPS1_IO_ADDRESS(UART1_BASE_ADDR)
+
+#endif
diff --git a/arch/arm/plat-mxc/include/mach/board-mx21ads.h b/arch/arm/plat-mxc/include/mach/board-mx21ads.h
new file mode 100644 (file)
index 0000000..06701df
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __ASM_ARCH_MXC_BOARD_MX21ADS_H__
+#define __ASM_ARCH_MXC_BOARD_MX21ADS_H__
+
+/*
+ * MXC UART EVB board level configurations
+ */
+#define MXC_LL_UART_PADDR       UART1_BASE_ADDR
+#define MXC_LL_UART_VADDR       AIPI_IO_ADDRESS(UART1_BASE_ADDR)
+
+/*
+ * Memory-mapped I/O on MX21ADS base board
+ */
+#define MX21ADS_MMIO_BASE_ADDR   0xF5000000
+#define MX21ADS_MMIO_SIZE        SZ_16M
+
+#define MX21ADS_REG_ADDR(offset)    (void __force __iomem *) \
+               (MX21ADS_MMIO_BASE_ADDR + (offset))
+
+#define MX21ADS_CS8900A_IRQ         IRQ_GPIOE(11)
+#define MX21ADS_CS8900A_IOBASE_REG  MX21ADS_REG_ADDR(0x000000)
+#define MX21ADS_ST16C255_IOBASE_REG MX21ADS_REG_ADDR(0x200000)
+#define MX21ADS_VERSION_REG         MX21ADS_REG_ADDR(0x400000)
+#define MX21ADS_IO_REG              MX21ADS_REG_ADDR(0x800000)
+
+/* MX21ADS_IO_REG bit definitions */
+#define MX21ADS_IO_SD_WP        0x0001 /* read */
+#define MX21ADS_IO_TP6          0x0001 /* write */
+#define MX21ADS_IO_SW_SEL       0x0002 /* read */
+#define MX21ADS_IO_TP7          0x0002 /* write */
+#define MX21ADS_IO_RESET_E_UART 0x0004
+#define MX21ADS_IO_RESET_BASE   0x0008
+#define MX21ADS_IO_CSI_CTL2     0x0010
+#define MX21ADS_IO_CSI_CTL1     0x0020
+#define MX21ADS_IO_CSI_CTL0     0x0040
+#define MX21ADS_IO_UART1_EN     0x0080
+#define MX21ADS_IO_UART4_EN     0x0100
+#define MX21ADS_IO_LCDON        0x0200
+#define MX21ADS_IO_IRDA_EN      0x0400
+#define MX21ADS_IO_IRDA_FIR_SEL 0x0800
+#define MX21ADS_IO_IRDA_MD0_B   0x1000
+#define MX21ADS_IO_IRDA_MD1     0x2000
+#define MX21ADS_IO_LED4_ON      0x4000
+#define MX21ADS_IO_LED3_ON      0x8000
+
+#endif                         /* __ASM_ARCH_MXC_BOARD_MX21ADS_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/board-mx27lite.h b/arch/arm/plat-mxc/include/mach/board-mx27lite.h
new file mode 100644 (file)
index 0000000..a870f8e
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2009 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_MXC_BOARD_MX27LITE_H__
+#define __ASM_ARCH_MXC_BOARD_MX27LITE_H__
+
+/* mandatory for CONFIG_DEBUG_LL */
+
+#define MXC_LL_UART_PADDR      UART1_BASE_ADDR
+#define MXC_LL_UART_VADDR      AIPS1_IO_ADDRESS(UART1_BASE_ADDR)
+
+#endif /* __ASM_ARCH_MXC_BOARD_MX27LITE_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/board-mx27pdk.h b/arch/arm/plat-mxc/include/mach/board-mx27pdk.h
new file mode 100644 (file)
index 0000000..552b55d
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2009 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_MXC_BOARD_MX27PDK_H__
+#define __ASM_ARCH_MXC_BOARD_MX27PDK_H__
+
+/* mandatory for CONFIG_DEBUG_LL */
+
+#define MXC_LL_UART_PADDR      UART1_BASE_ADDR
+#define MXC_LL_UART_VADDR      AIPS1_IO_ADDRESS(UART1_BASE_ADDR)
+
+#endif /* __ASM_ARCH_MXC_BOARD_MX27PDK_H__ */
index 318c72ada13db892043e5aaf694a826cf7ba0ed9..06e6895f7f6527a9a837a56895fc01d57b135516 100644 (file)
 
 #define MXC_MAX_EXP_IO_LINES   16
 
-/* mandatory for CONFIG_LL_DEBUG */
+/* mandatory for CONFIG_DEBUG_LL */
 
 #define MXC_LL_UART_PADDR      UART1_BASE_ADDR
 #define MXC_LL_UART_VADDR      AIPS1_IO_ADDRESS(UART1_BASE_ADDR)
diff --git a/arch/arm/plat-mxc/include/mach/board-mx31lilly.h b/arch/arm/plat-mxc/include/mach/board-mx31lilly.h
new file mode 100644 (file)
index 0000000..78cf31e
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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_MX31LILLY_H__
+#define __ASM_ARCH_MXC_BOARD_MX31LILLY_H__
+
+/* mandatory for CONFIG_LL_DEBUG */
+
+#define MXC_LL_UART_PADDR      UART1_BASE_ADDR
+#define MXC_LL_UART_VADDR      (AIPI_BASE_ADDR_VIRT + 0x0A000)
+
+#ifndef __ASSEMBLY__
+
+enum mx31lilly_boards {
+       MX31LILLY_NOBOARD       = 0,
+       MX31LILLY_DB            = 1,
+};
+
+/*
+ * This CPU module needs a baseboard to work. After basic initializing
+ * its own devices, it calls baseboard's init function.
+ */
+
+extern void mx31lilly_db_init(void);
+
+#endif
+
+#endif /* __ASM_ARCH_MXC_BOARD_MX31LILLY_H__ */
index e4e5cf5ad7db52554240a37dac874d18c490de2a..52fbdf2d6f26814cd0bbea2d70e8e6a54ce811c6 100644 (file)
 #ifndef __ASM_ARCH_MXC_BOARD_MX31LITE_H__
 #define __ASM_ARCH_MXC_BOARD_MX31LITE_H__
 
-#define MXC_MAX_EXP_IO_LINES   16
-
-
-/*
- * Memory Size parameters
- */
-
-/*
- * Size of SDRAM memory
- */
-#define SDRAM_MEM_SIZE         SZ_128M
-/*
- * Size of MBX buffer memory
- */
-#define MXC_MBX_MEM_SIZE       SZ_16M
-/*
- * Size of memory available to kernel
- */
-#define MEM_SIZE               (SDRAM_MEM_SIZE - MXC_MBX_MEM_SIZE)
-
 #define MXC_LL_UART_PADDR      UART1_BASE_ADDR
 #define MXC_LL_UART_VADDR      AIPS1_IO_ADDRESS(UART1_BASE_ADDR)
 
-#endif /* __ASM_ARCH_MXC_BOARD_MX31ADS_H__ */
+#endif /* __ASM_ARCH_MXC_BOARD_MX31LITE_H__ */
 
index f8aef1babb758971602121c9c68209adba51a5f6..303fd2434a2149ebb9ee3a9c143f7b84f458dd36 100644 (file)
@@ -19,7 +19,7 @@
 #ifndef __ASM_ARCH_MXC_BOARD_MX31MOBOARD_H__
 #define __ASM_ARCH_MXC_BOARD_MX31MOBOARD_H__
 
-/* mandatory for CONFIG_LL_DEBUG */
+/* mandatory for CONFIG_DEBUG_LL */
 
 #define MXC_LL_UART_PADDR      UART1_BASE_ADDR
 #define MXC_LL_UART_VADDR      (AIPI_BASE_ADDR_VIRT + 0x0A000)
index 2b6b316d0f51305b9cf4ae85af601ab03564bc66..519bab3eb28bf02b4e89995a04d63ceb803df27c 100644 (file)
 #ifndef __ASM_ARCH_MXC_BOARD_MX31PDK_H__
 #define __ASM_ARCH_MXC_BOARD_MX31PDK_H__
 
-/* mandatory for CONFIG_LL_DEBUG */
+/* mandatory for CONFIG_DEBUG_LL */
 
 #define MXC_LL_UART_PADDR      UART1_BASE_ADDR
 #define MXC_LL_UART_VADDR      AIPS1_IO_ADDRESS(UART1_BASE_ADDR)
 
+/* Definitions for components on the Debug board */
+
+/* Base address of CPLD controller on the Debug board */
+#define DEBUG_BASE_ADDRESS             CS5_IO_ADDRESS(CS5_BASE_ADDR)
+
+/* LAN9217 ethernet base address */
+#define LAN9217_BASE_ADDR              CS5_BASE_ADDR
+
+/* CPLD config and interrupt base address */
+#define CPLD_ADDR                      (DEBUG_BASE_ADDRESS + 0x20000)
+
+/* LED switchs */
+#define CPLD_LED_REG                   (CPLD_ADDR + 0x00)
+/* buttons */
+#define CPLD_SWITCH_BUTTONS_REG        (EXPIO_ADDR + 0x08)
+/* status, interrupt */
+#define CPLD_INT_STATUS_REG            (CPLD_ADDR + 0x10)
+#define CPLD_INT_MASK_REG              (CPLD_ADDR + 0x38)
+#define CPLD_INT_RESET_REG             (CPLD_ADDR + 0x20)
+/* magic word for debug CPLD */
+#define CPLD_MAGIC_NUMBER1_REG         (CPLD_ADDR + 0x40)
+#define CPLD_MAGIC_NUMBER2_REG         (CPLD_ADDR + 0x48)
+/* CPLD code version */
+#define CPLD_CODE_VER_REG              (CPLD_ADDR + 0x50)
+/* magic word for debug CPLD */
+#define CPLD_MAGIC_NUMBER3_REG         (CPLD_ADDR + 0x58)
+/* module reset register */
+#define CPLD_MODULE_RESET_REG          (CPLD_ADDR + 0x60)
+/* CPU ID and Personality ID */
+#define CPLD_MCU_BOARD_ID_REG          (CPLD_ADDR + 0x68)
+
+/* CPLD IRQ line for external uart, external ethernet etc */
+#define EXPIO_PARENT_INT       IOMUX_TO_IRQ(MX31_PIN_GPIO1_1)
+
+#define MXC_EXP_IO_BASE                (MXC_BOARD_IRQ_START)
+#define MXC_IRQ_TO_EXPIO(irq)  ((irq) - MXC_EXP_IO_BASE)
+
+#define EXPIO_INT_ENET         (MXC_EXP_IO_BASE + 0)
+#define EXPIO_INT_XUART_A      (MXC_EXP_IO_BASE + 1)
+#define EXPIO_INT_XUART_B      (MXC_EXP_IO_BASE + 2)
+#define EXPIO_INT_BUTTON_A     (MXC_EXP_IO_BASE + 3)
+#define EXPIO_INT_BUTTON_B     (MXC_EXP_IO_BASE + 4)
+
+#define MXC_MAX_EXP_IO_LINES   16
+
 #endif /* __ASM_ARCH_MXC_BOARD_MX31PDK_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/board-mx35pdk.h b/arch/arm/plat-mxc/include/mach/board-mx35pdk.h
new file mode 100644 (file)
index 0000000..1111037
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ *  Copyright 2009 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
+ */
+
+#ifndef __ASM_ARCH_MXC_BOARD_MX35PDK_H__
+#define __ASM_ARCH_MXC_BOARD_MX35PDK_H__
+
+/* mandatory for CONFIG_DEBUG_LL */
+
+#define MXC_LL_UART_PADDR      UART1_BASE_ADDR
+#define MXC_LL_UART_VADDR      AIPS1_IO_ADDRESS(UART1_BASE_ADDR)
+
+#endif /* __ASM_ARCH_MXC_BOARD_MX35PDK_H__ */
index 82232ba3c8fcd79c7e80a684a67f33114484993f..f0a1fa1938a2be208fd193b99c8a4b064c3a13b7 100644 (file)
@@ -19,7 +19,7 @@
 #ifndef __ASM_ARCH_MXC_BOARD_PCM037_H__
 #define __ASM_ARCH_MXC_BOARD_PCM037_H__
 
-/* mandatory for CONFIG_LL_DEBUG */
+/* mandatory for CONFIG_DEBUG_LL */
 
 #define MXC_LL_UART_PADDR      UART1_BASE_ADDR
 #define MXC_LL_UART_VADDR      AIPS1_IO_ADDRESS(UART1_BASE_ADDR)
index 750c62afd90fc4d00bb358ac9730f19575ba9652..4fcd7499e092e13a953f8b0c22bf7cd596162df1 100644 (file)
@@ -19,7 +19,7 @@
 #ifndef __ASM_ARCH_MXC_BOARD_PCM038_H__
 #define __ASM_ARCH_MXC_BOARD_PCM038_H__
 
-/* mandatory for CONFIG_LL_DEBUG */
+/* mandatory for CONFIG_DEBUG_LL */
 
 #define MXC_LL_UART_PADDR      UART1_BASE_ADDR
 #define MXC_LL_UART_VADDR      (AIPI_BASE_ADDR_VIRT + 0x0A000)
diff --git a/arch/arm/plat-mxc/include/mach/board-pcm043.h b/arch/arm/plat-mxc/include/mach/board-pcm043.h
new file mode 100644 (file)
index 0000000..15fbdf1
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ *  Copyright (C) 2008 Sascha Hauer, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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_MXC_BOARD_PCM043_H__
+#define __ASM_ARCH_MXC_BOARD_PCM043_H__
+
+/* mandatory for CONFIG_LL_DEBUG */
+
+#define MXC_LL_UART_PADDR      UART1_BASE_ADDR
+#define MXC_LL_UART_VADDR      AIPS1_IO_ADDRESS(UART1_BASE_ADDR)
+
+#endif /* __ASM_ARCH_MXC_BOARD_PCM043_H__ */
index 4ff762dd45cfc3d447e74ac608fc04b81d6b5bea..04033ec637d21c55189008314ceade9bc890b607 100644 (file)
@@ -11,7 +11,7 @@
 #ifndef __ASM_ARCH_MXC_BOARD_QONG_H__
 #define __ASM_ARCH_MXC_BOARD_QONG_H__
 
-/* mandatory for CONFIG_LL_DEBUG */
+/* mandatory for CONFIG_DEBUG_LL */
 
 #define MXC_LL_UART_PADDR      UART1_BASE_ADDR
 #define MXC_LL_UART_VADDR      AIPS1_IO_ADDRESS(UART1_BASE_ADDR)
index b2f9b72644db4a019f9cfb054008e7338d37e524..02c3cd004db3b7a52f045be026a75d3f26eaab04 100644 (file)
 struct platform_device;
 struct clk;
 
-extern void mxc_map_io(void);
+extern void mx1_map_io(void);
+extern void mx21_map_io(void);
+extern void mx27_map_io(void);
+extern void mx31_map_io(void);
+extern void mx35_map_io(void);
 extern void mxc_init_irq(void);
 extern void mxc_timer_init(struct clk *timer_clk);
 extern int mx1_clocks_init(unsigned long fref);
index 4f773148bc2061bfa9913cf970eb836ea43abf37..bbc5f6753cfb1948de8391cdd0c4e9ab9331a139 100644 (file)
@@ -25,6 +25,9 @@
 #ifdef CONFIG_MACH_MX27ADS
 #include <mach/board-mx27ads.h>
 #endif
+#ifdef CONFIG_MACH_MX21ADS
+#include <mach/board-mx21ads.h>
+#endif
 #ifdef CONFIG_MACH_PCM038
 #include <mach/board-pcm038.h>
 #endif
 #endif
 #ifdef CONFIG_MACH_QONG
 #include <mach/board-qong.h>
+#endif
+#ifdef CONFIG_MACH_PCM043
+#include <mach/board-pcm043.h>
+#endif
+#ifdef CONFIG_MACH_MX27_3DS
+#include <mach/board-mx27pdk.h>
+#endif
+#ifdef CONFIG_MACH_ARMADILLO5X0
+#include <mach/board-armadillo5x0.h>
+#endif
+#ifdef CONFIG_MACH_MX35_3DS
+#include <mach/board-mx35pdk.h>
+#endif
+#ifdef CONFIG_MACH_MX27LITE
+#include <mach/board-mx27lite.h>
 #endif
                .macro  addruart,rx
                mrc     p15, 0, \rx, c1, c0
index ea509f1090fb80a608477f4992d238c1b1b0bb84..894d2f87c85600c495d117a6d0f524060ee15aaa 100644 (file)
@@ -35,6 +35,7 @@ struct mxc_gpio_port {
        int irq;
        int virtual_irq_start;
        struct gpio_chip chip;
+       u32 both_edges;
 };
 
 int mxc_gpio_init(struct mxc_gpio_port*, int);
index f9bd17dd8dd71af1fd6d6c05f7c7781b51daea26..4adec9b154dd6b91904aad2f542aef1730c22f72 100644 (file)
@@ -24,7 +24,7 @@
 
 struct imxuart_platform_data {
        int (*init)(struct platform_device *pdev);
-       int (*exit)(struct platform_device *pdev);
+       void (*exit)(struct platform_device *pdev);
        unsigned int flags;
        void (*irda_enable)(int enable);
        unsigned int irda_inv_rx:1;
index 762a7b0430e2786c6e77582f43afd68c0dbdbb88..9f0101157ec1093068140f68c2624cf04a452315 100644 (file)
@@ -76,8 +76,8 @@ struct imx_fb_platform_data {
        u_char * fixed_screen_cpu;
        dma_addr_t fixed_screen_dma;
 
-       int (*init)(struct platform_device*);
-       int (*exit)(struct platform_device*);
+       int (*init)(struct platform_device *);
+       void (*exit)(struct platform_device *);
 
        void (*lcd_power)(int);
        void (*backlight_power)(int);
index 57e927a1fd3a5767e4ac389dd694d3d8681df599..27f8d1b2bc6ba611bc0759b1900f81a39182c9d9 100644 (file)
@@ -114,7 +114,7 @@ enum iomux_gp_func {
  *     - setups the iomux according to the configuration
  *     - if the pin is configured as a GPIO, we claim it throug kernel gpiolib
  */
-int mxc_iomux_setup_pin(const unsigned int pin, const char *label);
+int mxc_iomux_alloc_pin(const unsigned int pin, const char *label);
 /*
  * setups mutliple pins
  * convenient way to call the above function with tables
@@ -633,6 +633,40 @@ enum iomux_pins {
 #define MX31_PIN_USBOTG_DIR__USBOTG_DIR        IOMUX_MODE(MX31_PIN_USBOTG_DIR, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_USBOTG_NXT__USBOTG_NXT        IOMUX_MODE(MX31_PIN_USBOTG_NXT, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_USBOTG_STP__USBOTG_STP        IOMUX_MODE(MX31_PIN_USBOTG_STP, IOMUX_CONFIG_FUNC)
+#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)
+#define MX31_PIN_DCD_DTE1__I2C2_SDA    IOMUX_MODE(MX31_PIN_DCD_DTE1, IOMUX_CONFIG_ALT2)
+#define MX31_PIN_RI_DTE1__I2C2_SCL     IOMUX_MODE(MX31_PIN_RI_DTE1, IOMUX_CONFIG_ALT2)
+#define MX31_PIN_ATA_CS0__GPIO3_26     IOMUX_MODE(MX31_PIN_ATA_CS0, IOMUX_CONFIG_GPIO)
+#define MX31_PIN_ATA_CS1__GPIO3_27     IOMUX_MODE(MX31_PIN_ATA_CS1, IOMUX_CONFIG_GPIO)
+#define MX31_PIN_PC_PWRON__SD2_DATA3   IOMUX_MODE(MX31_PIN_PC_PWRON, IOMUX_CONFIG_ALT1)
+#define MX31_PIN_PC_VS1__SD2_DATA2     IOMUX_MODE(MX31_PIN_PC_VS1, IOMUX_CONFIG_ALT1)
+#define MX31_PIN_PC_READY__SD2_DATA1   IOMUX_MODE(MX31_PIN_PC_READY, IOMUX_CONFIG_ALT1)
+#define MX31_PIN_PC_WAIT_B__SD2_DATA0  IOMUX_MODE(MX31_PIN_PC_WAIT_B, IOMUX_CONFIG_ALT1)
+#define MX31_PIN_PC_CD2_B__SD2_CLK     IOMUX_MODE(MX31_PIN_PC_CD2_B, IOMUX_CONFIG_ALT1)
+#define MX31_PIN_PC_CD1_B__SD2_CMD     IOMUX_MODE(MX31_PIN_PC_CD1_B, IOMUX_CONFIG_ALT1)
+#define MX31_PIN_ATA_DIOR__GPIO3_28    IOMUX_MODE(MX31_PIN_ATA_DIOR, IOMUX_CONFIG_GPIO)
+#define MX31_PIN_ATA_DIOW__GPIO3_29    IOMUX_MODE(MX31_PIN_ATA_DIOW, IOMUX_CONFIG_GPIO)
+#define MX31_PIN_CSI_D4__CSI_D4                IOMUX_MODE(MX31_PIN_CSI_D4, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_D5__CSI_D5                IOMUX_MODE(MX31_PIN_CSI_D5, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_D6__CSI_D6                IOMUX_MODE(MX31_PIN_CSI_D6, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_D7__CSI_D7                IOMUX_MODE(MX31_PIN_CSI_D7, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_D8__CSI_D8                IOMUX_MODE(MX31_PIN_CSI_D8, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_D9__CSI_D9                IOMUX_MODE(MX31_PIN_CSI_D9, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_D10__CSI_D10      IOMUX_MODE(MX31_PIN_CSI_D10, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_D11__CSI_D11      IOMUX_MODE(MX31_PIN_CSI_D11, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_D12__CSI_D12      IOMUX_MODE(MX31_PIN_CSI_D12, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_D13__CSI_D13      IOMUX_MODE(MX31_PIN_CSI_D13, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_D14__CSI_D14      IOMUX_MODE(MX31_PIN_CSI_D14, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_D15__CSI_D15      IOMUX_MODE(MX31_PIN_CSI_D15, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_HSYNC__CSI_HSYNC  IOMUX_MODE(MX31_PIN_CSI_HSYNC, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_MCLK__CSI_MCLK    IOMUX_MODE(MX31_PIN_CSI_MCLK, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_PIXCLK__CSI_PIXCLK        IOMUX_MODE(MX31_PIN_CSI_PIXCLK, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CSI_VSYNC__CSI_VSYNC  IOMUX_MODE(MX31_PIN_CSI_VSYNC, IOMUX_CONFIG_FUNC)
+#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)
 
 /*XXX: The SS0, SS1, SS2, SS3 lines of spi3 are multiplexed by cspi2_ss0, cspi2_ss1, cspi1_ss0
  * cspi1_ss1*/
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx35.h b/arch/arm/plat-mxc/include/mach/iomux-mx35.h
new file mode 100644 (file)
index 0000000..00b0ac1
--- /dev/null
@@ -0,0 +1,1267 @@
+/*
+ * Copyright (C, NO_PAD_CTRL) 2009 by Jan Weitzel Phytec Messtechnik GmbH <armlinux@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, NO_PAD_CTRL) 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 __MACH_IOMUX_MX35_H__
+#define __MACH_IOMUX_MX35_H__
+
+#include <mach/iomux-v3.h>
+
+/*
+ * The naming convention for the pad modes is MX35_PAD_<padname>__<padmode>
+ * If <padname> or <padmode> refers to a GPIO, it is named
+ * GPIO_<unit>_<num> see also iomux-v3.h
+ */
+
+/*                                                                       PAD    MUX   ALT INPSE PATH */
+#define MX35_PAD_CAPTURE__GPT_CAPIN1                           IOMUX_PAD(0x328, 0x004, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CAPTURE__GPT_CMPOUT2                          IOMUX_PAD(0x328, 0x004, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CAPTURE__CSPI2_SS1                            IOMUX_PAD(0x328, 0x004, 2, 0x7f4, 0, NO_PAD_CTRL)
+#define MX35_PAD_CAPTURE__EPIT1_EPITO                          IOMUX_PAD(0x328, 0x004, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CAPTURE__CCM_CLK32K                           IOMUX_PAD(0x328, 0x004, 4, 0x7d0, 0, NO_PAD_CTRL)
+#define MX35_PAD_CAPTURE__GPIO1_4                              IOMUX_PAD(0x328, 0x004, 5, 0x850, 0, NO_PAD_CTRL)
+
+#define MX35_PAD_COMPARE__GPT_CMPOUT1                          IOMUX_PAD(0x32c, 0x008, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_COMPARE__GPT_CAPIN2                           IOMUX_PAD(0x32c, 0x008, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_COMPARE__GPT_CMPOUT3                          IOMUX_PAD(0x32c, 0x008, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_COMPARE__EPIT2_EPITO                          IOMUX_PAD(0x32c, 0x008, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_COMPARE__GPIO1_5                              IOMUX_PAD(0x32c, 0x008, 5, 0x854, 0, NO_PAD_CTRL)
+#define MX35_PAD_COMPARE__SDMA_EXTDMA_2                                IOMUX_PAD(0x32c, 0x008, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_WDOG_RST__WDOG_WDOG_B                         IOMUX_PAD(0x330, 0x00c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_WDOG_RST__IPU_FLASH_STROBE                    IOMUX_PAD(0x330, 0x00c, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_WDOG_RST__GPIO1_6                             IOMUX_PAD(0x330, 0x00c, 5, 0x858, 0, NO_PAD_CTRL)
+
+#define MX35_PAD_GPIO1_0__GPIO1_0                              IOMUX_PAD(0x334, 0x010, 0, 0x82c, 0, NO_PAD_CTRL)
+#define MX35_PAD_GPIO1_0__CCM_PMIC_RDY                         IOMUX_PAD(0x334, 0x010, 1, 0x7d4, 0, NO_PAD_CTRL)
+#define MX35_PAD_GPIO1_0__OWIRE_LINE                           IOMUX_PAD(0x334, 0x010, 2, 0x990, 0, NO_PAD_CTRL)
+#define MX35_PAD_GPIO1_0__SDMA_EXTDMA_0                                IOMUX_PAD(0x334, 0x010, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_GPIO1_1__GPIO1_1                              IOMUX_PAD(0x338, 0x014, 0, 0x838, 0, NO_PAD_CTRL)
+#define MX35_PAD_GPIO1_1__PWM_PWMO                             IOMUX_PAD(0x338, 0x014, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_GPIO1_1__CSPI1_SS2                            IOMUX_PAD(0x338, 0x014, 3, 0x7d8, 0, NO_PAD_CTRL)
+#define MX35_PAD_GPIO1_1__SCC_TAMPER_DETECT                    IOMUX_PAD(0x338, 0x014, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_GPIO1_1__SDMA_EXTDMA_1                                IOMUX_PAD(0x338, 0x014, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_GPIO2_0__GPIO2_0                              IOMUX_PAD(0x33c, 0x018, 0, 0x868, 0, NO_PAD_CTRL)
+#define MX35_PAD_GPIO2_0__USB_TOP_USBOTG_CLK                   IOMUX_PAD(0x33c, 0x018, 1, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_GPIO3_0__GPIO3_0                              IOMUX_PAD(0x340, 0x01c, 0, 0x8e8, 0, NO_PAD_CTRL)
+#define MX35_PAD_GPIO3_0__USB_TOP_USBH2_CLK                    IOMUX_PAD(0x340, 0x01c, 1, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_RESET_IN_B__CCM_RESET_IN_B                    IOMUX_PAD(0x344, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_POR_B__CCM_POR_B                              IOMUX_PAD(0x348, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CLKO__CCM_CLKO                                        IOMUX_PAD(0x34c, 0x020, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CLKO__GPIO1_8                                 IOMUX_PAD(0x34c, 0x020, 5, 0x860, 0, NO_PAD_CTRL)
+
+#define MX35_PAD_BOOT_MODE0__CCM_BOOT_MODE_0                   IOMUX_PAD(0x350, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_BOOT_MODE1__CCM_BOOT_MODE_1                   IOMUX_PAD(0x354, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CLK_MODE0__CCM_CLK_MODE_0                     IOMUX_PAD(0x358, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CLK_MODE1__CCM_CLK_MODE_1                     IOMUX_PAD(0x35c, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_POWER_FAIL__CCM_DSM_WAKEUP_INT_26             IOMUX_PAD(0x360, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_VSTBY__CCM_VSTBY                              IOMUX_PAD(0x364, 0x024, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_VSTBY__GPIO1_7                                        IOMUX_PAD(0x364, 0x024, 5, 0x85c, 0, NO_PAD_CTRL)
+
+#define MX35_PAD_A0__EMI_EIM_DA_L_0                            IOMUX_PAD(0x368, 0x028, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A1__EMI_EIM_DA_L_1                            IOMUX_PAD(0x36c, 0x02c, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A2__EMI_EIM_DA_L_2                            IOMUX_PAD(0x370, 0x030, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A3__EMI_EIM_DA_L_3                            IOMUX_PAD(0x374, 0x034, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A4__EMI_EIM_DA_L_4                            IOMUX_PAD(0x378, 0x038, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A5__EMI_EIM_DA_L_5                            IOMUX_PAD(0x37c, 0x03c, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A6__EMI_EIM_DA_L_6                            IOMUX_PAD(0x380, 0x040, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A7__EMI_EIM_DA_L_7                            IOMUX_PAD(0x384, 0x044, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A8__EMI_EIM_DA_H_8                            IOMUX_PAD(0x388, 0x048, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A9__EMI_EIM_DA_H_9                            IOMUX_PAD(0x38c, 0x04c, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A10__EMI_EIM_DA_H_10                          IOMUX_PAD(0x390, 0x050, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_MA10__EMI_MA10                                        IOMUX_PAD(0x394, 0x054, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A11__EMI_EIM_DA_H_11                          IOMUX_PAD(0x398, 0x058, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A12__EMI_EIM_DA_H_12                          IOMUX_PAD(0x39c, 0x05c, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A13__EMI_EIM_DA_H_13                          IOMUX_PAD(0x3a0, 0x060, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A14__EMI_EIM_DA_H2_14                         IOMUX_PAD(0x3a4, 0x064, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A15__EMI_EIM_DA_H2_15                         IOMUX_PAD(0x3a8, 0x068, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A16__EMI_EIM_A_16                             IOMUX_PAD(0x3ac, 0x06c, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A17__EMI_EIM_A_17                             IOMUX_PAD(0x3b0, 0x070, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A18__EMI_EIM_A_18                             IOMUX_PAD(0x3b4, 0x074, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A19__EMI_EIM_A_19                             IOMUX_PAD(0x3b8, 0x078, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A20__EMI_EIM_A_20                             IOMUX_PAD(0x3bc, 0x07c, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A21__EMI_EIM_A_21                             IOMUX_PAD(0x3c0, 0x080, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A22__EMI_EIM_A_22                             IOMUX_PAD(0x3c4, 0x084, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A23__EMI_EIM_A_23                             IOMUX_PAD(0x3c8, 0x088, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A24__EMI_EIM_A_24                             IOMUX_PAD(0x3cc, 0x08c, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_A25__EMI_EIM_A_25                             IOMUX_PAD(0x3d0, 0x090, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SDBA1__EMI_EIM_SDBA1                          IOMUX_PAD(0x3d4, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SDBA0__EMI_EIM_SDBA0                          IOMUX_PAD(0x3d8, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD0__EMI_DRAM_D_0                             IOMUX_PAD(0x3dc, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD1__EMI_DRAM_D_1                             IOMUX_PAD(0x3e0, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD2__EMI_DRAM_D_2                             IOMUX_PAD(0x3e4, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD3__EMI_DRAM_D_3                             IOMUX_PAD(0x3e8, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD4__EMI_DRAM_D_4                             IOMUX_PAD(0x3ec, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD5__EMI_DRAM_D_5                             IOMUX_PAD(0x3f0, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD6__EMI_DRAM_D_6                             IOMUX_PAD(0x3f4, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD7__EMI_DRAM_D_7                             IOMUX_PAD(0x3f8, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD8__EMI_DRAM_D_8                             IOMUX_PAD(0x3fc, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD9__EMI_DRAM_D_9                             IOMUX_PAD(0x400, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD10__EMI_DRAM_D_10                           IOMUX_PAD(0x404, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD11__EMI_DRAM_D_11                           IOMUX_PAD(0x408, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD12__EMI_DRAM_D_12                           IOMUX_PAD(0x40c, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD13__EMI_DRAM_D_13                           IOMUX_PAD(0x410, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD14__EMI_DRAM_D_14                           IOMUX_PAD(0x414, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD15__EMI_DRAM_D_15                           IOMUX_PAD(0x418, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD16__EMI_DRAM_D_16                           IOMUX_PAD(0x41c, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD17__EMI_DRAM_D_17                           IOMUX_PAD(0x420, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD18__EMI_DRAM_D_18                           IOMUX_PAD(0x424, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD19__EMI_DRAM_D_19                           IOMUX_PAD(0x428, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD20__EMI_DRAM_D_20                           IOMUX_PAD(0x42c, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD21__EMI_DRAM_D_21                           IOMUX_PAD(0x430, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD22__EMI_DRAM_D_22                           IOMUX_PAD(0x434, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD23__EMI_DRAM_D_23                           IOMUX_PAD(0x438, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD24__EMI_DRAM_D_24                           IOMUX_PAD(0x43c, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD25__EMI_DRAM_D_25                           IOMUX_PAD(0x440, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD26__EMI_DRAM_D_26                           IOMUX_PAD(0x444, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD27__EMI_DRAM_D_27                           IOMUX_PAD(0x448, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD28__EMI_DRAM_D_28                           IOMUX_PAD(0x44c, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD29__EMI_DRAM_D_29                           IOMUX_PAD(0x450, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD30__EMI_DRAM_D_30                           IOMUX_PAD(0x454, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD31__EMI_DRAM_D_31                           IOMUX_PAD(0x458, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_DQM0__EMI_DRAM_DQM_0                          IOMUX_PAD(0x45c, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_DQM1__EMI_DRAM_DQM_1                          IOMUX_PAD(0x460, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_DQM2__EMI_DRAM_DQM_2                          IOMUX_PAD(0x464, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_DQM3__EMI_DRAM_DQM_3                          IOMUX_PAD(0x468, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_EB0__EMI_EIM_EB0_B                            IOMUX_PAD(0x46c, 0x094, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_EB1__EMI_EIM_EB1_B                            IOMUX_PAD(0x470, 0x098, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_OE__EMI_EIM_OE                                        IOMUX_PAD(0x474, 0x09c, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CS0__EMI_EIM_CS0                              IOMUX_PAD(0x478, 0x0a0, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CS1__EMI_EIM_CS1                              IOMUX_PAD(0x47c, 0x0a4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CS1__EMI_NANDF_CE3                            IOMUX_PAD(0x47c, 0x0a4, 3, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CS2__EMI_EIM_CS2                              IOMUX_PAD(0x480, 0x0a8, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CS3__EMI_EIM_CS3                              IOMUX_PAD(0x484, 0x0ac, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CS4__EMI_EIM_CS4                              IOMUX_PAD(0x488, 0x0b0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CS4__EMI_DTACK_B                              IOMUX_PAD(0x488, 0x0b0, 1, 0x800, 0, NO_PAD_CTRL)
+#define MX35_PAD_CS4__EMI_NANDF_CE1                            IOMUX_PAD(0x488, 0x0b0, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CS4__GPIO1_20                                 IOMUX_PAD(0x488, 0x0b0, 5, 0x83c, 0, NO_PAD_CTRL)
+
+#define MX35_PAD_CS5__EMI_EIM_CS5                              IOMUX_PAD(0x48c, 0x0b4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CS5__CSPI2_SS2                                        IOMUX_PAD(0x48c, 0x0b4, 1, 0x7f8, 0, NO_PAD_CTRL)
+#define MX35_PAD_CS5__CSPI1_SS2                                        IOMUX_PAD(0x48c, 0x0b4, 2, 0x7d8, 1, NO_PAD_CTRL)
+#define MX35_PAD_CS5__EMI_NANDF_CE2                            IOMUX_PAD(0x48c, 0x0b4, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CS5__GPIO1_21                                 IOMUX_PAD(0x48c, 0x0b4, 5, 0x840, 0, NO_PAD_CTRL)
+
+#define MX35_PAD_NF_CE0__EMI_NANDF_CE0                         IOMUX_PAD(0x490, 0x0b8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_NF_CE0__GPIO1_22                              IOMUX_PAD(0x490, 0x0b8, 5, 0x844, 0, NO_PAD_CTRL)
+
+#define MX35_PAD_ECB__EMI_EIM_ECB                              IOMUX_PAD(0x494, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LBA__EMI_EIM_LBA                              IOMUX_PAD(0x498, 0x0bc, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_BCLK__EMI_EIM_BCLK                            IOMUX_PAD(0x49c, 0x0c0, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_RW__EMI_EIM_RW                                        IOMUX_PAD(0x4a0, 0x0c4, 0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_RAS__EMI_DRAM_RAS                             IOMUX_PAD(0x4a4, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CAS__EMI_DRAM_CAS                             IOMUX_PAD(0x4a8, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SDWE__EMI_DRAM_SDWE                           IOMUX_PAD(0x4ac, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SDCKE0__EMI_DRAM_SDCKE_0                      IOMUX_PAD(0x4b0, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SDCKE1__EMI_DRAM_SDCKE_1                      IOMUX_PAD(0x4b4, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SDCLK__EMI_DRAM_SDCLK                         IOMUX_PAD(0x4b8, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SDQS0__EMI_DRAM_SDQS_0                                IOMUX_PAD(0x4bc, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SDQS1__EMI_DRAM_SDQS_1                                IOMUX_PAD(0x4c0, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SDQS2__EMI_DRAM_SDQS_2                                IOMUX_PAD(0x4c4, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SDQS3__EMI_DRAM_SDQS_3                                IOMUX_PAD(0x4c8, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_NFWE_B__EMI_NANDF_WE_B                                IOMUX_PAD(0x4cc, 0x0c8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_NFWE_B__USB_TOP_USBH2_DATA_3                  IOMUX_PAD(0x4cc, 0x0c8, 1, 0x9d8, 0, NO_PAD_CTRL)
+#define MX35_PAD_NFWE_B__IPU_DISPB_D0_VSYNC                    IOMUX_PAD(0x4cc, 0x0c8, 2, 0x924, 0, NO_PAD_CTRL)
+#define MX35_PAD_NFWE_B__GPIO2_18                              IOMUX_PAD(0x4cc, 0x0c8, 5, 0x88c, 0, NO_PAD_CTRL)
+#define MX35_PAD_NFWE_B__ARM11P_TOP_TRACE_0                    IOMUX_PAD(0x4cc, 0x0c8, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_NFRE_B__EMI_NANDF_RE_B                                IOMUX_PAD(0x4d0, 0x0cc, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_NFRE_B__USB_TOP_USBH2_DIR                     IOMUX_PAD(0x4d0, 0x0cc, 1, 0x9ec, 0, NO_PAD_CTRL)
+#define MX35_PAD_NFRE_B__IPU_DISPB_BCLK                                IOMUX_PAD(0x4d0, 0x0cc, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_NFRE_B__GPIO2_19                              IOMUX_PAD(0x4d0, 0x0cc, 5, 0x890, 0, NO_PAD_CTRL)
+#define MX35_PAD_NFRE_B__ARM11P_TOP_TRACE_1                    IOMUX_PAD(0x4d0, 0x0cc, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_NFALE__EMI_NANDF_ALE                          IOMUX_PAD(0x4d4, 0x0d0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_NFALE__USB_TOP_USBH2_STP                      IOMUX_PAD(0x4d4, 0x0d0, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_NFALE__IPU_DISPB_CS0                          IOMUX_PAD(0x4d4, 0x0d0, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_NFALE__GPIO2_20                               IOMUX_PAD(0x4d4, 0x0d0, 5, 0x898, 0, NO_PAD_CTRL)
+#define MX35_PAD_NFALE__ARM11P_TOP_TRACE_2                     IOMUX_PAD(0x4d4, 0x0d0, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_NFCLE__EMI_NANDF_CLE                          IOMUX_PAD(0x4d8, 0x0d4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_NFCLE__USB_TOP_USBH2_NXT                      IOMUX_PAD(0x4d8, 0x0d4, 1, 0x9f0, 0, NO_PAD_CTRL)
+#define MX35_PAD_NFCLE__IPU_DISPB_PAR_RS                       IOMUX_PAD(0x4d8, 0x0d4, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_NFCLE__GPIO2_21                               IOMUX_PAD(0x4d8, 0x0d4, 5, 0x89c, 0, NO_PAD_CTRL)
+#define MX35_PAD_NFCLE__ARM11P_TOP_TRACE_3                     IOMUX_PAD(0x4d8, 0x0d4, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_NFWP_B__EMI_NANDF_WP_B                                IOMUX_PAD(0x4dc, 0x0d8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_NFWP_B__USB_TOP_USBH2_DATA_7                  IOMUX_PAD(0x4dc, 0x0d8, 1, 0x9e8, 0, NO_PAD_CTRL)
+#define MX35_PAD_NFWP_B__IPU_DISPB_WR                          IOMUX_PAD(0x4dc, 0x0d8, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_NFWP_B__GPIO2_22                              IOMUX_PAD(0x4dc, 0x0d8, 5, 0x8a0, 0, NO_PAD_CTRL)
+#define MX35_PAD_NFWP_B__ARM11P_TOP_TRCTL                      IOMUX_PAD(0x4dc, 0x0d8, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_NFRB__EMI_NANDF_RB                            IOMUX_PAD(0x4e0, 0x0dc, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_NFRB__IPU_DISPB_RD                            IOMUX_PAD(0x4e0, 0x0dc, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_NFRB__GPIO2_23                                        IOMUX_PAD(0x4e0, 0x0dc, 5, 0x8a4, 0, NO_PAD_CTRL)
+#define MX35_PAD_NFRB__ARM11P_TOP_TRCLK                                IOMUX_PAD(0x4e0, 0x0dc, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D15__EMI_EIM_D_15                             IOMUX_PAD(0x4e4, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D14__EMI_EIM_D_14                             IOMUX_PAD(0x4e8, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D13__EMI_EIM_D_13                             IOMUX_PAD(0x4ec, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D12__EMI_EIM_D_12                             IOMUX_PAD(0x4f0, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D11__EMI_EIM_D_11                             IOMUX_PAD(0x4f4, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D10__EMI_EIM_D_10                             IOMUX_PAD(0x4f8, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D9__EMI_EIM_D_9                               IOMUX_PAD(0x4fc, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D8__EMI_EIM_D_8                               IOMUX_PAD(0x500, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D7__EMI_EIM_D_7                               IOMUX_PAD(0x504, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D6__EMI_EIM_D_6                               IOMUX_PAD(0x508, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D5__EMI_EIM_D_5                               IOMUX_PAD(0x50c, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D4__EMI_EIM_D_4                               IOMUX_PAD(0x510, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D3__EMI_EIM_D_3                               IOMUX_PAD(0x514, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D2__EMI_EIM_D_2                               IOMUX_PAD(0x518, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D1__EMI_EIM_D_1                               IOMUX_PAD(0x51c, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D0__EMI_EIM_D_0                               IOMUX_PAD(0x520, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSI_D8__IPU_CSI_D_8                           IOMUX_PAD(0x524, 0x0e0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D8__KPP_COL_0                             IOMUX_PAD(0x524, 0x0e0, 1, 0x950, 0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D8__GPIO1_20                              IOMUX_PAD(0x524, 0x0e0, 5, 0x83c, 1, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D8__ARM11P_TOP_EVNTBUS_13                 IOMUX_PAD(0x524, 0x0e0, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSI_D9__IPU_CSI_D_9                           IOMUX_PAD(0x528, 0x0e4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D9__KPP_COL_1                             IOMUX_PAD(0x528, 0x0e4, 1, 0x954, 0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D9__GPIO1_21                              IOMUX_PAD(0x528, 0x0e4, 5, 0x840, 1, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D9__ARM11P_TOP_EVNTBUS_14                 IOMUX_PAD(0x528, 0x0e4, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSI_D10__IPU_CSI_D_10                         IOMUX_PAD(0x52c, 0x0e8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D10__KPP_COL_2                            IOMUX_PAD(0x52c, 0x0e8, 1, 0x958, 0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D10__GPIO1_22                             IOMUX_PAD(0x52c, 0x0e8, 5, 0x844, 1, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D10__ARM11P_TOP_EVNTBUS_15                        IOMUX_PAD(0x52c, 0x0e8, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSI_D11__IPU_CSI_D_11                         IOMUX_PAD(0x530, 0x0ec, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D11__KPP_COL_3                            IOMUX_PAD(0x530, 0x0ec, 1, 0x95c, 0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D11__GPIO1_23                             IOMUX_PAD(0x530, 0x0ec, 5, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSI_D12__IPU_CSI_D_12                         IOMUX_PAD(0x534, 0x0f0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D12__KPP_ROW_0                            IOMUX_PAD(0x534, 0x0f0, 1, 0x970, 0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D12__GPIO1_24                             IOMUX_PAD(0x534, 0x0f0, 5, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSI_D13__IPU_CSI_D_13                         IOMUX_PAD(0x538, 0x0f4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D13__KPP_ROW_1                            IOMUX_PAD(0x538, 0x0f4, 1, 0x974, 0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D13__GPIO1_25                             IOMUX_PAD(0x538, 0x0f4, 5, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSI_D14__IPU_CSI_D_14                         IOMUX_PAD(0x53c, 0x0f8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D14__KPP_ROW_2                            IOMUX_PAD(0x53c, 0x0f8, 1, 0x978, 0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D14__GPIO1_26                             IOMUX_PAD(0x53c, 0x0f8, 5, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSI_D15__IPU_CSI_D_15                         IOMUX_PAD(0x540, 0x0fc, 0, 0x97c, 0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D15__KPP_ROW_3                            IOMUX_PAD(0x540, 0x0fc, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_D15__GPIO1_27                             IOMUX_PAD(0x540, 0x0fc, 5, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSI_MCLK__IPU_CSI_MCLK                                IOMUX_PAD(0x544, 0x100, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_MCLK__GPIO1_28                            IOMUX_PAD(0x544, 0x100, 5, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSI_VSYNC__IPU_CSI_VSYNC                      IOMUX_PAD(0x548, 0x104, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_VSYNC__GPIO1_29                           IOMUX_PAD(0x548, 0x104, 5, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSI_HSYNC__IPU_CSI_HSYNC                      IOMUX_PAD(0x54c, 0x108, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_HSYNC__GPIO1_30                           IOMUX_PAD(0x54c, 0x108, 5, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSI_PIXCLK__IPU_CSI_PIXCLK                    IOMUX_PAD(0x550, 0x10c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSI_PIXCLK__GPIO1_31                          IOMUX_PAD(0x550, 0x10c, 5, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_I2C1_CLK__I2C1_SCL                            IOMUX_PAD(0x554, 0x110, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_I2C1_CLK__GPIO2_24                            IOMUX_PAD(0x554, 0x110, 5, 0x8a8, 0, NO_PAD_CTRL)
+#define MX35_PAD_I2C1_CLK__CCM_USB_BYP_CLK                     IOMUX_PAD(0x554, 0x110, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_I2C1_DAT__I2C1_SDA                            IOMUX_PAD(0x558, 0x114, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_I2C1_DAT__GPIO2_25                            IOMUX_PAD(0x558, 0x114, 5, 0x8ac, 0, NO_PAD_CTRL)
+
+#define MX35_PAD_I2C2_CLK__I2C2_SCL                            IOMUX_PAD(0x55c, 0x118, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_I2C2_CLK__CAN1_TXCAN                          IOMUX_PAD(0x55c, 0x118, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_I2C2_CLK__USB_TOP_USBH2_PWR                   IOMUX_PAD(0x55c, 0x118, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_I2C2_CLK__GPIO2_26                            IOMUX_PAD(0x55c, 0x118, 5, 0x8b0, 0, NO_PAD_CTRL)
+#define MX35_PAD_I2C2_CLK__SDMA_DEBUG_BUS_DEVICE_2             IOMUX_PAD(0x55c, 0x118, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_I2C2_DAT__I2C2_SDA                            IOMUX_PAD(0x560, 0x11c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_I2C2_DAT__CAN1_RXCAN                          IOMUX_PAD(0x560, 0x11c, 1, 0x7c8, 0, NO_PAD_CTRL)
+#define MX35_PAD_I2C2_DAT__USB_TOP_USBH2_OC                    IOMUX_PAD(0x560, 0x11c, 2, 0x9f4, 0, NO_PAD_CTRL)
+#define MX35_PAD_I2C2_DAT__GPIO2_27                            IOMUX_PAD(0x560, 0x11c, 5, 0x8b4, 0, NO_PAD_CTRL)
+#define MX35_PAD_I2C2_DAT__SDMA_DEBUG_BUS_DEVICE_3             IOMUX_PAD(0x560, 0x11c, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_STXD4__AUDMUX_AUD4_TXD                                IOMUX_PAD(0x564, 0x120, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_STXD4__GPIO2_28                               IOMUX_PAD(0x564, 0x120, 5, 0x8b8, 0, NO_PAD_CTRL)
+#define MX35_PAD_STXD4__ARM11P_TOP_ARM_COREASID0               IOMUX_PAD(0x564, 0x120, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SRXD4__AUDMUX_AUD4_RXD                                IOMUX_PAD(0x568, 0x124, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SRXD4__GPIO2_29                               IOMUX_PAD(0x568, 0x124, 5, 0x8bc, 0, NO_PAD_CTRL)
+#define MX35_PAD_SRXD4__ARM11P_TOP_ARM_COREASID1               IOMUX_PAD(0x568, 0x124, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SCK4__AUDMUX_AUD4_TXC                         IOMUX_PAD(0x56c, 0x128, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SCK4__GPIO2_30                                        IOMUX_PAD(0x56c, 0x128, 5, 0x8c4, 0, NO_PAD_CTRL)
+#define MX35_PAD_SCK4__ARM11P_TOP_ARM_COREASID2                        IOMUX_PAD(0x56c, 0x128, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_STXFS4__AUDMUX_AUD4_TXFS                      IOMUX_PAD(0x570, 0x12c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_STXFS4__GPIO2_31                              IOMUX_PAD(0x570, 0x12c, 5, 0x8c8, 0, NO_PAD_CTRL)
+#define MX35_PAD_STXFS4__ARM11P_TOP_ARM_COREASID3              IOMUX_PAD(0x570, 0x12c, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_STXD5__AUDMUX_AUD5_TXD                                IOMUX_PAD(0x574, 0x130, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_STXD5__SPDIF_SPDIF_OUT1                       IOMUX_PAD(0x574, 0x130, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_STXD5__CSPI2_MOSI                             IOMUX_PAD(0x574, 0x130, 2, 0x7ec, 0, NO_PAD_CTRL)
+#define MX35_PAD_STXD5__GPIO1_0                                        IOMUX_PAD(0x574, 0x130, 5, 0x82c, 1, NO_PAD_CTRL)
+#define MX35_PAD_STXD5__ARM11P_TOP_ARM_COREASID4               IOMUX_PAD(0x574, 0x130, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SRXD5__AUDMUX_AUD5_RXD                                IOMUX_PAD(0x578, 0x134, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SRXD5__SPDIF_SPDIF_IN1                                IOMUX_PAD(0x578, 0x134, 1, 0x998, 0, NO_PAD_CTRL)
+#define MX35_PAD_SRXD5__CSPI2_MISO                             IOMUX_PAD(0x578, 0x134, 2, 0x7e8, 0, NO_PAD_CTRL)
+#define MX35_PAD_SRXD5__GPIO1_1                                        IOMUX_PAD(0x578, 0x134, 5, 0x838, 1, NO_PAD_CTRL)
+#define MX35_PAD_SRXD5__ARM11P_TOP_ARM_COREASID5               IOMUX_PAD(0x578, 0x134, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SCK5__AUDMUX_AUD5_TXC                         IOMUX_PAD(0x57c, 0x138, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SCK5__SPDIF_SPDIF_EXTCLK                      IOMUX_PAD(0x57c, 0x138, 1, 0x994, 0, NO_PAD_CTRL)
+#define MX35_PAD_SCK5__CSPI2_SCLK                              IOMUX_PAD(0x57c, 0x138, 2, 0x7e0, 0, NO_PAD_CTRL)
+#define MX35_PAD_SCK5__GPIO1_2                                 IOMUX_PAD(0x57c, 0x138, 5, 0x848, 0, NO_PAD_CTRL)
+#define MX35_PAD_SCK5__ARM11P_TOP_ARM_COREASID6                        IOMUX_PAD(0x57c, 0x138, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_STXFS5__AUDMUX_AUD5_TXFS                      IOMUX_PAD(0x580, 0x13c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_STXFS5__CSPI2_RDY                             IOMUX_PAD(0x580, 0x13c, 2, 0x7e4, 0, NO_PAD_CTRL)
+#define MX35_PAD_STXFS5__GPIO1_3                               IOMUX_PAD(0x580, 0x13c, 5, 0x84c, 0, NO_PAD_CTRL)
+#define MX35_PAD_STXFS5__ARM11P_TOP_ARM_COREASID7              IOMUX_PAD(0x580, 0x13c, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SCKR__ESAI_SCKR                               IOMUX_PAD(0x584, 0x140, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SCKR__GPIO1_4                                 IOMUX_PAD(0x584, 0x140, 5, 0x850, 1, NO_PAD_CTRL)
+#define MX35_PAD_SCKR__ARM11P_TOP_EVNTBUS_10                   IOMUX_PAD(0x584, 0x140, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FSR__ESAI_FSR                                 IOMUX_PAD(0x588, 0x144, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FSR__GPIO1_5                                  IOMUX_PAD(0x588, 0x144, 5, 0x854, 1, NO_PAD_CTRL)
+#define MX35_PAD_FSR__ARM11P_TOP_EVNTBUS_11                    IOMUX_PAD(0x588, 0x144, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_HCKR__ESAI_HCKR                               IOMUX_PAD(0x58c, 0x148, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_HCKR__AUDMUX_AUD5_RXFS                                IOMUX_PAD(0x58c, 0x148, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_HCKR__CSPI2_SS0                               IOMUX_PAD(0x58c, 0x148, 2, 0x7f0, 0, NO_PAD_CTRL)
+#define MX35_PAD_HCKR__IPU_FLASH_STROBE                                IOMUX_PAD(0x58c, 0x148, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_HCKR__GPIO1_6                                 IOMUX_PAD(0x58c, 0x148, 5, 0x858, 1, NO_PAD_CTRL)
+#define MX35_PAD_HCKR__ARM11P_TOP_EVNTBUS_12                   IOMUX_PAD(0x58c, 0x148, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SCKT__ESAI_SCKT                               IOMUX_PAD(0x590, 0x14c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SCKT__GPIO1_7                                 IOMUX_PAD(0x590, 0x14c, 5, 0x85c, 1, NO_PAD_CTRL)
+#define MX35_PAD_SCKT__IPU_CSI_D_0                             IOMUX_PAD(0x590, 0x14c, 6, 0x930, 0, NO_PAD_CTRL)
+#define MX35_PAD_SCKT__KPP_ROW_2                               IOMUX_PAD(0x590, 0x14c, 7, 0x978, 1, NO_PAD_CTRL)
+
+#define MX35_PAD_FST__ESAI_FST                                 IOMUX_PAD(0x594, 0x150, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FST__GPIO1_8                                  IOMUX_PAD(0x594, 0x150, 5, 0x860, 1, NO_PAD_CTRL)
+#define MX35_PAD_FST__IPU_CSI_D_1                              IOMUX_PAD(0x594, 0x150, 6, 0x934, 0, NO_PAD_CTRL)
+#define MX35_PAD_FST__KPP_ROW_3                                        IOMUX_PAD(0x594, 0x150, 7, 0x97c, 1, NO_PAD_CTRL)
+
+#define MX35_PAD_HCKT__ESAI_HCKT                               IOMUX_PAD(0x598, 0x154, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_HCKT__AUDMUX_AUD5_RXC                         IOMUX_PAD(0x598, 0x154, 1, 0x7a8, 0, NO_PAD_CTRL)
+#define MX35_PAD_HCKT__GPIO1_9                                 IOMUX_PAD(0x598, 0x154, 5, 0x864, 0, NO_PAD_CTRL)
+#define MX35_PAD_HCKT__IPU_CSI_D_2                             IOMUX_PAD(0x598, 0x154, 6, 0x938, 0, NO_PAD_CTRL)
+#define MX35_PAD_HCKT__KPP_COL_3                               IOMUX_PAD(0x598, 0x154, 7, 0x95c, 1, NO_PAD_CTRL)
+
+#define MX35_PAD_TX5_RX0__ESAI_TX5_RX0                         IOMUX_PAD(0x59c, 0x158, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX5_RX0__AUDMUX_AUD4_RXC                      IOMUX_PAD(0x59c, 0x158, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX5_RX0__CSPI2_SS2                            IOMUX_PAD(0x59c, 0x158, 2, 0x7f8, 1, NO_PAD_CTRL)
+#define MX35_PAD_TX5_RX0__CAN2_TXCAN                           IOMUX_PAD(0x59c, 0x158, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX5_RX0__UART2_DTR                            IOMUX_PAD(0x59c, 0x158, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX5_RX0__GPIO1_10                             IOMUX_PAD(0x59c, 0x158, 5, 0x830, 0, NO_PAD_CTRL)
+#define MX35_PAD_TX5_RX0__EMI_M3IF_CHOSEN_MASTER_0             IOMUX_PAD(0x59c, 0x158, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_TX4_RX1__ESAI_TX4_RX1                         IOMUX_PAD(0x5a0, 0x15c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX4_RX1__AUDMUX_AUD4_RXFS                     IOMUX_PAD(0x5a0, 0x15c, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX4_RX1__CSPI2_SS3                            IOMUX_PAD(0x5a0, 0x15c, 2, 0x7fc, 0, NO_PAD_CTRL)
+#define MX35_PAD_TX4_RX1__CAN2_RXCAN                           IOMUX_PAD(0x5a0, 0x15c, 3, 0x7cc, 0, NO_PAD_CTRL)
+#define MX35_PAD_TX4_RX1__UART2_DSR                            IOMUX_PAD(0x5a0, 0x15c, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX4_RX1__GPIO1_11                             IOMUX_PAD(0x5a0, 0x15c, 5, 0x834, 0, NO_PAD_CTRL)
+#define MX35_PAD_TX4_RX1__IPU_CSI_D_3                          IOMUX_PAD(0x5a0, 0x15c, 6, 0x93c, 0, NO_PAD_CTRL)
+#define MX35_PAD_TX4_RX1__KPP_ROW_0                            IOMUX_PAD(0x5a0, 0x15c, 7, 0x970, 1, NO_PAD_CTRL)
+
+#define MX35_PAD_TX3_RX2__ESAI_TX3_RX2                         IOMUX_PAD(0x5a4, 0x160, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX3_RX2__I2C3_SCL                             IOMUX_PAD(0x5a4, 0x160, 1, 0x91c, 0, NO_PAD_CTRL)
+#define MX35_PAD_TX3_RX2__EMI_NANDF_CE1                                IOMUX_PAD(0x5a4, 0x160, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX3_RX2__GPIO1_12                             IOMUX_PAD(0x5a4, 0x160, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX3_RX2__IPU_CSI_D_4                          IOMUX_PAD(0x5a4, 0x160, 6, 0x940, 0, NO_PAD_CTRL)
+#define MX35_PAD_TX3_RX2__KPP_ROW_1                            IOMUX_PAD(0x5a4, 0x160, 7, 0x974, 1, NO_PAD_CTRL)
+
+#define MX35_PAD_TX2_RX3__ESAI_TX2_RX3                         IOMUX_PAD(0x5a8, 0x164, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX2_RX3__I2C3_SDA                             IOMUX_PAD(0x5a8, 0x164, 1, 0x920, 0, NO_PAD_CTRL)
+#define MX35_PAD_TX2_RX3__EMI_NANDF_CE2                                IOMUX_PAD(0x5a8, 0x164, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX2_RX3__GPIO1_13                             IOMUX_PAD(0x5a8, 0x164, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX2_RX3__IPU_CSI_D_5                          IOMUX_PAD(0x5a8, 0x164, 6, 0x944, 0, NO_PAD_CTRL)
+#define MX35_PAD_TX2_RX3__KPP_COL_0                            IOMUX_PAD(0x5a8, 0x164, 7, 0x950, 1, NO_PAD_CTRL)
+
+#define MX35_PAD_TX1__ESAI_TX1                                 IOMUX_PAD(0x5ac, 0x168, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX1__CCM_PMIC_RDY                             IOMUX_PAD(0x5ac, 0x168, 1, 0x7d4, 1, NO_PAD_CTRL)
+#define MX35_PAD_TX1__CSPI1_SS2                                        IOMUX_PAD(0x5ac, 0x168, 2, 0x7d8, 2, NO_PAD_CTRL)
+#define MX35_PAD_TX1__EMI_NANDF_CE3                            IOMUX_PAD(0x5ac, 0x168, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX1__UART2_RI                                 IOMUX_PAD(0x5ac, 0x168, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX1__GPIO1_14                                 IOMUX_PAD(0x5ac, 0x168, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX1__IPU_CSI_D_6                              IOMUX_PAD(0x5ac, 0x168, 6, 0x948, 0, NO_PAD_CTRL)
+#define MX35_PAD_TX1__KPP_COL_1                                        IOMUX_PAD(0x5ac, 0x168, 7, 0x954, 1, NO_PAD_CTRL)
+
+#define MX35_PAD_TX0__ESAI_TX0                                 IOMUX_PAD(0x5b0, 0x16c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX0__SPDIF_SPDIF_EXTCLK                       IOMUX_PAD(0x5b0, 0x16c, 1, 0x994, 1, NO_PAD_CTRL)
+#define MX35_PAD_TX0__CSPI1_SS3                                        IOMUX_PAD(0x5b0, 0x16c, 2, 0x7dc, 0, NO_PAD_CTRL)
+#define MX35_PAD_TX0__EMI_DTACK_B                              IOMUX_PAD(0x5b0, 0x16c, 3, 0x800, 1, NO_PAD_CTRL)
+#define MX35_PAD_TX0__UART2_DCD                                        IOMUX_PAD(0x5b0, 0x16c, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX0__GPIO1_15                                 IOMUX_PAD(0x5b0, 0x16c, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TX0__IPU_CSI_D_7                              IOMUX_PAD(0x5b0, 0x16c, 6, 0x94c, 0, NO_PAD_CTRL)
+#define MX35_PAD_TX0__KPP_COL_2                                        IOMUX_PAD(0x5b0, 0x16c, 7, 0x958, 1, NO_PAD_CTRL)
+
+#define MX35_PAD_CSPI1_MOSI__CSPI1_MOSI                                IOMUX_PAD(0x5b4, 0x170, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_MOSI__GPIO1_16                          IOMUX_PAD(0x5b4, 0x170, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_MOSI__ECT_CTI_TRIG_OUT1_2               IOMUX_PAD(0x5b4, 0x170, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSPI1_MISO__CSPI1_MISO                                IOMUX_PAD(0x5b8, 0x174, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_MISO__GPIO1_17                          IOMUX_PAD(0x5b8, 0x174, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_MISO__ECT_CTI_TRIG_OUT1_3               IOMUX_PAD(0x5b8, 0x174, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSPI1_SS0__CSPI1_SS0                          IOMUX_PAD(0x5bc, 0x178, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SS0__OWIRE_LINE                         IOMUX_PAD(0x5bc, 0x178, 1, 0x990, 1, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SS0__CSPI2_SS3                          IOMUX_PAD(0x5bc, 0x178, 2, 0x7fc, 1, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SS0__GPIO1_18                           IOMUX_PAD(0x5bc, 0x178, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SS0__ECT_CTI_TRIG_OUT1_4                        IOMUX_PAD(0x5bc, 0x178, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSPI1_SS1__CSPI1_SS1                          IOMUX_PAD(0x5c0, 0x17c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SS1__PWM_PWMO                           IOMUX_PAD(0x5c0, 0x17c, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SS1__CCM_CLK32K                         IOMUX_PAD(0x5c0, 0x17c, 2, 0x7d0, 1, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SS1__GPIO1_19                           IOMUX_PAD(0x5c0, 0x17c, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SS1__IPU_DIAGB_29                       IOMUX_PAD(0x5c0, 0x17c, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SS1__ECT_CTI_TRIG_OUT1_5                        IOMUX_PAD(0x5c0, 0x17c, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSPI1_SCLK__CSPI1_SCLK                                IOMUX_PAD(0x5c4, 0x180, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SCLK__GPIO3_4                           IOMUX_PAD(0x5c4, 0x180, 5, 0x904, 0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SCLK__IPU_DIAGB_30                      IOMUX_PAD(0x5c4, 0x180, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SCLK__EMI_M3IF_CHOSEN_MASTER_1          IOMUX_PAD(0x5c4, 0x180, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CSPI1_SPI_RDY__CSPI1_RDY                      IOMUX_PAD(0x5c8, 0x184, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SPI_RDY__GPIO3_5                                IOMUX_PAD(0x5c8, 0x184, 5, 0x908, 0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SPI_RDY__IPU_DIAGB_31                   IOMUX_PAD(0x5c8, 0x184, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CSPI1_SPI_RDY__EMI_M3IF_CHOSEN_MASTER_2       IOMUX_PAD(0x5c8, 0x184, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_RXD1__UART1_RXD_MUX                           IOMUX_PAD(0x5cc, 0x188, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_RXD1__CSPI2_MOSI                              IOMUX_PAD(0x5cc, 0x188, 1, 0x7ec, 1, NO_PAD_CTRL)
+#define MX35_PAD_RXD1__KPP_COL_4                               IOMUX_PAD(0x5cc, 0x188, 4, 0x960, 0, NO_PAD_CTRL)
+#define MX35_PAD_RXD1__GPIO3_6                                 IOMUX_PAD(0x5cc, 0x188, 5, 0x90c, 0, NO_PAD_CTRL)
+#define MX35_PAD_RXD1__ARM11P_TOP_EVNTBUS_16                   IOMUX_PAD(0x5cc, 0x188, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_TXD1__UART1_TXD_MUX                           IOMUX_PAD(0x5d0, 0x18c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TXD1__CSPI2_MISO                              IOMUX_PAD(0x5d0, 0x18c, 1, 0x7e8, 1, NO_PAD_CTRL)
+#define MX35_PAD_TXD1__KPP_COL_5                               IOMUX_PAD(0x5d0, 0x18c, 4, 0x964, 0, NO_PAD_CTRL)
+#define MX35_PAD_TXD1__GPIO3_7                                 IOMUX_PAD(0x5d0, 0x18c, 5, 0x910, 0, NO_PAD_CTRL)
+#define MX35_PAD_TXD1__ARM11P_TOP_EVNTBUS_17                   IOMUX_PAD(0x5d0, 0x18c, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_RTS1__UART1_RTS                               IOMUX_PAD(0x5d4, 0x190, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_RTS1__CSPI2_SCLK                              IOMUX_PAD(0x5d4, 0x190, 1, 0x7e0, 1, NO_PAD_CTRL)
+#define MX35_PAD_RTS1__I2C3_SCL                                        IOMUX_PAD(0x5d4, 0x190, 2, 0x91c, 1, NO_PAD_CTRL)
+#define MX35_PAD_RTS1__IPU_CSI_D_0                             IOMUX_PAD(0x5d4, 0x190, 3, 0x930, 1, NO_PAD_CTRL)
+#define MX35_PAD_RTS1__KPP_COL_6                               IOMUX_PAD(0x5d4, 0x190, 4, 0x968, 0, NO_PAD_CTRL)
+#define MX35_PAD_RTS1__GPIO3_8                                 IOMUX_PAD(0x5d4, 0x190, 5, 0x914, 0, NO_PAD_CTRL)
+#define MX35_PAD_RTS1__EMI_NANDF_CE1                           IOMUX_PAD(0x5d4, 0x190, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_RTS1__ARM11P_TOP_EVNTBUS_18                   IOMUX_PAD(0x5d4, 0x190, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CTS1__UART1_CTS                               IOMUX_PAD(0x5d8, 0x194, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CTS1__CSPI2_RDY                               IOMUX_PAD(0x5d8, 0x194, 1, 0x7e4, 1, NO_PAD_CTRL)
+#define MX35_PAD_CTS1__I2C3_SDA                                        IOMUX_PAD(0x5d8, 0x194, 2, 0x920, 1, NO_PAD_CTRL)
+#define MX35_PAD_CTS1__IPU_CSI_D_1                             IOMUX_PAD(0x5d8, 0x194, 3, 0x934, 1, NO_PAD_CTRL)
+#define MX35_PAD_CTS1__KPP_COL_7                               IOMUX_PAD(0x5d8, 0x194, 4, 0x96c, 0, NO_PAD_CTRL)
+#define MX35_PAD_CTS1__GPIO3_9                                 IOMUX_PAD(0x5d8, 0x194, 5, 0x918, 0, NO_PAD_CTRL)
+#define MX35_PAD_CTS1__EMI_NANDF_CE2                           IOMUX_PAD(0x5d8, 0x194, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CTS1__ARM11P_TOP_EVNTBUS_19                   IOMUX_PAD(0x5d8, 0x194, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_RXD2__UART2_RXD_MUX                           IOMUX_PAD(0x5dc, 0x198, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_RXD2__KPP_ROW_4                               IOMUX_PAD(0x5dc, 0x198, 4, 0x980, 0, NO_PAD_CTRL)
+#define MX35_PAD_RXD2__GPIO3_10                                        IOMUX_PAD(0x5dc, 0x198, 5, 0x8ec, 0, NO_PAD_CTRL)
+
+#define MX35_PAD_TXD2__UART2_TXD_MUX                           IOMUX_PAD(0x5e0, 0x19c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_TXD2__SPDIF_SPDIF_EXTCLK                      IOMUX_PAD(0x5e0, 0x19c, 1, 0x994, 2, NO_PAD_CTRL)
+#define MX35_PAD_TXD2__KPP_ROW_5                               IOMUX_PAD(0x5e0, 0x19c, 4, 0x984, 0, NO_PAD_CTRL)
+#define MX35_PAD_TXD2__GPIO3_11                                        IOMUX_PAD(0x5e0, 0x19c, 5, 0x8f0, 0, NO_PAD_CTRL)
+
+#define MX35_PAD_RTS2__UART2_RTS                               IOMUX_PAD(0x5e4, 0x1a0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_RTS2__SPDIF_SPDIF_IN1                         IOMUX_PAD(0x5e4, 0x1a0, 1, 0x998, 1, NO_PAD_CTRL)
+#define MX35_PAD_RTS2__CAN2_RXCAN                              IOMUX_PAD(0x5e4, 0x1a0, 2, 0x7cc, 1, NO_PAD_CTRL)
+#define MX35_PAD_RTS2__IPU_CSI_D_2                             IOMUX_PAD(0x5e4, 0x1a0, 3, 0x938, 1, NO_PAD_CTRL)
+#define MX35_PAD_RTS2__KPP_ROW_6                               IOMUX_PAD(0x5e4, 0x1a0, 4, 0x988, 0, NO_PAD_CTRL)
+#define MX35_PAD_RTS2__GPIO3_12                                        IOMUX_PAD(0x5e4, 0x1a0, 5, 0x8f4, 0, NO_PAD_CTRL)
+#define MX35_PAD_RTS2__AUDMUX_AUD5_RXC                         IOMUX_PAD(0x5e4, 0x1a0, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_RTS2__UART3_RXD_MUX                           IOMUX_PAD(0x5e4, 0x1a0, 7, 0x9a0, 0, NO_PAD_CTRL)
+
+#define MX35_PAD_CTS2__UART2_CTS                               IOMUX_PAD(0x5e8, 0x1a4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CTS2__SPDIF_SPDIF_OUT1                                IOMUX_PAD(0x5e8, 0x1a4, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CTS2__CAN2_TXCAN                              IOMUX_PAD(0x5e8, 0x1a4, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CTS2__IPU_CSI_D_3                             IOMUX_PAD(0x5e8, 0x1a4, 3, 0x93c, 1, NO_PAD_CTRL)
+#define MX35_PAD_CTS2__KPP_ROW_7                               IOMUX_PAD(0x5e8, 0x1a4, 4, 0x98c, 0, NO_PAD_CTRL)
+#define MX35_PAD_CTS2__GPIO3_13                                        IOMUX_PAD(0x5e8, 0x1a4, 5, 0x8f8, 0, NO_PAD_CTRL)
+#define MX35_PAD_CTS2__AUDMUX_AUD5_RXFS                                IOMUX_PAD(0x5e8, 0x1a4, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CTS2__UART3_TXD_MUX                           IOMUX_PAD(0x5e8, 0x1a4, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_RTCK__ARM11P_TOP_RTCK                         IOMUX_PAD(0x5ec, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_TCK__SJC_TCK                                  IOMUX_PAD(0x5f0, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_TMS__SJC_TMS                                  IOMUX_PAD(0x5f4, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_TDI__SJC_TDI                                  IOMUX_PAD(0x5f8, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_TDO__SJC_TDO                                  IOMUX_PAD(0x5fc, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_TRSTB__SJC_TRSTB                              IOMUX_PAD(0x600, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_DE_B__SJC_DE_B                                        IOMUX_PAD(0x604, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SJC_MOD__SJC_MOD                              IOMUX_PAD(0x608, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_USBOTG_PWR__USB_TOP_USBOTG_PWR                        IOMUX_PAD(0x60c, 0x1a8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_USBOTG_PWR__USB_TOP_USBH2_PWR                 IOMUX_PAD(0x60c, 0x1a8, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_USBOTG_PWR__GPIO3_14                          IOMUX_PAD(0x60c, 0x1a8, 5, 0x8fc, 0, NO_PAD_CTRL)
+
+#define MX35_PAD_USBOTG_OC__USB_TOP_USBOTG_OC                  IOMUX_PAD(0x610, 0x1ac, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_USBOTG_OC__USB_TOP_USBH2_OC                   IOMUX_PAD(0x610, 0x1ac, 1, 0x9f4, 1, NO_PAD_CTRL)
+#define MX35_PAD_USBOTG_OC__GPIO3_15                           IOMUX_PAD(0x610, 0x1ac, 5, 0x900, 0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD0__IPU_DISPB_DAT_0                          IOMUX_PAD(0x614, 0x1b0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD0__GPIO2_0                                  IOMUX_PAD(0x614, 0x1b0, 5, 0x868, 1, NO_PAD_CTRL)
+#define MX35_PAD_LD0__SDMA_SDMA_DEBUG_PC_0                     IOMUX_PAD(0x614, 0x1b0, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD1__IPU_DISPB_DAT_1                          IOMUX_PAD(0x618, 0x1b4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD1__GPIO2_1                                  IOMUX_PAD(0x618, 0x1b4, 5, 0x894, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD1__SDMA_SDMA_DEBUG_PC_1                     IOMUX_PAD(0x618, 0x1b4, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD2__IPU_DISPB_DAT_2                          IOMUX_PAD(0x61c, 0x1b8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD2__GPIO2_2                                  IOMUX_PAD(0x61c, 0x1b8, 5, 0x8c0, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD2__SDMA_SDMA_DEBUG_PC_2                     IOMUX_PAD(0x61c, 0x1b8, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD3__IPU_DISPB_DAT_3                          IOMUX_PAD(0x620, 0x1bc, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD3__GPIO2_3                                  IOMUX_PAD(0x620, 0x1bc, 5, 0x8cc, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD3__SDMA_SDMA_DEBUG_PC_3                     IOMUX_PAD(0x620, 0x1bc, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD4__IPU_DISPB_DAT_4                          IOMUX_PAD(0x624, 0x1c0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD4__GPIO2_4                                  IOMUX_PAD(0x624, 0x1c0, 5, 0x8d0, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD4__SDMA_SDMA_DEBUG_PC_4                     IOMUX_PAD(0x624, 0x1c0, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD5__IPU_DISPB_DAT_5                          IOMUX_PAD(0x628, 0x1c4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD5__GPIO2_5                                  IOMUX_PAD(0x628, 0x1c4, 5, 0x8d4, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD5__SDMA_SDMA_DEBUG_PC_5                     IOMUX_PAD(0x628, 0x1c4, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD6__IPU_DISPB_DAT_6                          IOMUX_PAD(0x62c, 0x1c8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD6__GPIO2_6                                  IOMUX_PAD(0x62c, 0x1c8, 5, 0x8d8, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD6__SDMA_SDMA_DEBUG_PC_6                     IOMUX_PAD(0x62c, 0x1c8, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD7__IPU_DISPB_DAT_7                          IOMUX_PAD(0x630, 0x1cc, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD7__GPIO2_7                                  IOMUX_PAD(0x630, 0x1cc, 5, 0x8dc, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD7__SDMA_SDMA_DEBUG_PC_7                     IOMUX_PAD(0x630, 0x1cc, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD8__IPU_DISPB_DAT_8                          IOMUX_PAD(0x634, 0x1d0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD8__GPIO2_8                                  IOMUX_PAD(0x634, 0x1d0, 5, 0x8e0, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD8__SDMA_SDMA_DEBUG_PC_8                     IOMUX_PAD(0x634, 0x1d0, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD9__IPU_DISPB_DAT_9                          IOMUX_PAD(0x638, 0x1d4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD9__GPIO2_9                                  IOMUX_PAD(0x638, 0x1d4, 5, 0x8e4  0, NO_PAD_CTRL)
+#define MX35_PAD_LD9__SDMA_SDMA_DEBUG_PC_9                     IOMUX_PAD(0x638, 0x1d4, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD10__IPU_DISPB_DAT_10                                IOMUX_PAD(0x63c, 0x1d8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD10__GPIO2_10                                        IOMUX_PAD(0x63c, 0x1d8, 5, 0x86c, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD10__SDMA_SDMA_DEBUG_PC_10                   IOMUX_PAD(0x63c, 0x1d8, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD11__IPU_DISPB_DAT_11                                IOMUX_PAD(0x640, 0x1dc, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD11__GPIO2_11                                        IOMUX_PAD(0x640, 0x1dc, 5, 0x870, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD11__SDMA_SDMA_DEBUG_PC_11                   IOMUX_PAD(0x640, 0x1dc, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD11__ARM11P_TOP_TRACE_4                      IOMUX_PAD(0x640, 0x1dc, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD12__IPU_DISPB_DAT_12                                IOMUX_PAD(0x644, 0x1e0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD12__GPIO2_12                                        IOMUX_PAD(0x644, 0x1e0, 5, 0x874, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD12__SDMA_SDMA_DEBUG_PC_12                   IOMUX_PAD(0x644, 0x1e0, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD12__ARM11P_TOP_TRACE_5                      IOMUX_PAD(0x644, 0x1e0, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD13__IPU_DISPB_DAT_13                                IOMUX_PAD(0x648, 0x1e4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD13__GPIO2_13                                        IOMUX_PAD(0x648, 0x1e4, 5, 0x878, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD13__SDMA_SDMA_DEBUG_PC_13                   IOMUX_PAD(0x648, 0x1e4, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD13__ARM11P_TOP_TRACE_6                      IOMUX_PAD(0x648, 0x1e4, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD14__IPU_DISPB_DAT_14                                IOMUX_PAD(0x64c, 0x1e8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD14__GPIO2_14                                        IOMUX_PAD(0x64c, 0x1e8, 5, 0x87c, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD14__SDMA_SDMA_DEBUG_EVENT_CHANNEL_0         IOMUX_PAD(0x64c, 0x1e8, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD14__ARM11P_TOP_TRACE_7                      IOMUX_PAD(0x64c, 0x1e8, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD15__IPU_DISPB_DAT_15                                IOMUX_PAD(0x650, 0x1ec, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD15__GPIO2_15                                        IOMUX_PAD(0x650, 0x1ec, 5, 0x880, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD15__SDMA_SDMA_DEBUG_EVENT_CHANNEL_1         IOMUX_PAD(0x650, 0x1ec, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD15__ARM11P_TOP_TRACE_8                      IOMUX_PAD(0x650, 0x1ec, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD16__IPU_DISPB_DAT_16                                IOMUX_PAD(0x654, 0x1f0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD16__IPU_DISPB_D12_VSYNC                     IOMUX_PAD(0x654, 0x1f0, 2, 0x928, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD16__GPIO2_16                                        IOMUX_PAD(0x654, 0x1f0, 5, 0x884, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD16__SDMA_SDMA_DEBUG_EVENT_CHANNEL_2         IOMUX_PAD(0x654, 0x1f0, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD16__ARM11P_TOP_TRACE_9                      IOMUX_PAD(0x654, 0x1f0, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD17__IPU_DISPB_DAT_17                                IOMUX_PAD(0x658, 0x1f4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD17__IPU_DISPB_CS2                           IOMUX_PAD(0x658, 0x1f4, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD17__GPIO2_17                                        IOMUX_PAD(0x658, 0x1f4, 5, 0x888, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD17__SDMA_SDMA_DEBUG_EVENT_CHANNEL_3         IOMUX_PAD(0x658, 0x1f4, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD17__ARM11P_TOP_TRACE_10                     IOMUX_PAD(0x658, 0x1f4, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD18__IPU_DISPB_DAT_18                                IOMUX_PAD(0x65c, 0x1f8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD18__IPU_DISPB_D0_VSYNC                      IOMUX_PAD(0x65c, 0x1f8, 1, 0x924, 1, NO_PAD_CTRL)
+#define MX35_PAD_LD18__IPU_DISPB_D12_VSYNC                     IOMUX_PAD(0x65c, 0x1f8, 2, 0x928, 1, NO_PAD_CTRL)
+#define MX35_PAD_LD18__ESDHC3_CMD                              IOMUX_PAD(0x65c, 0x1f8, 3, 0x818, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD18__USB_TOP_USBOTG_DATA_3                   IOMUX_PAD(0x65c, 0x1f8, 4, 0x9b0, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD18__GPIO3_24                                        IOMUX_PAD(0x65c, 0x1f8, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD18__SDMA_SDMA_DEBUG_EVENT_CHANNEL_4         IOMUX_PAD(0x65c, 0x1f8, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD18__ARM11P_TOP_TRACE_11                     IOMUX_PAD(0x65c, 0x1f8, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD19__IPU_DISPB_DAT_19                                IOMUX_PAD(0x660, 0x1fc, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD19__IPU_DISPB_BCLK                          IOMUX_PAD(0x660, 0x1fc, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD19__IPU_DISPB_CS1                           IOMUX_PAD(0x660, 0x1fc, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD19__ESDHC3_CLK                              IOMUX_PAD(0x660, 0x1fc, 3, 0x814, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD19__USB_TOP_USBOTG_DIR                      IOMUX_PAD(0x660, 0x1fc, 4, 0x9c4, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD19__GPIO3_25                                        IOMUX_PAD(0x660, 0x1fc, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD19__SDMA_SDMA_DEBUG_EVENT_CHANNEL_5         IOMUX_PAD(0x660, 0x1fc, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD19__ARM11P_TOP_TRACE_12                     IOMUX_PAD(0x660, 0x1fc, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD20__IPU_DISPB_DAT_20                                IOMUX_PAD(0x664, 0x200, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD20__IPU_DISPB_CS0                           IOMUX_PAD(0x664, 0x200, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD20__IPU_DISPB_SD_CLK                                IOMUX_PAD(0x664, 0x200, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD20__ESDHC3_DAT0                             IOMUX_PAD(0x664, 0x200, 3, 0x81c, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD20__GPIO3_26                                        IOMUX_PAD(0x664, 0x200, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD20__SDMA_SDMA_DEBUG_CORE_STATUS_3           IOMUX_PAD(0x664, 0x200, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD20__ARM11P_TOP_TRACE_13                     IOMUX_PAD(0x664, 0x200, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD21__IPU_DISPB_DAT_21                                IOMUX_PAD(0x668, 0x204, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD21__IPU_DISPB_PAR_RS                                IOMUX_PAD(0x668, 0x204, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD21__IPU_DISPB_SER_RS                                IOMUX_PAD(0x668, 0x204, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD21__ESDHC3_DAT1                             IOMUX_PAD(0x668, 0x204, 3, 0x820, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD21__USB_TOP_USBOTG_STP                      IOMUX_PAD(0x668, 0x204, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD21__GPIO3_27                                        IOMUX_PAD(0x668, 0x204, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD21__SDMA_DEBUG_EVENT_CHANNEL_SEL            IOMUX_PAD(0x668, 0x204, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD21__ARM11P_TOP_TRACE_14                     IOMUX_PAD(0x668, 0x204, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD22__IPU_DISPB_DAT_22                                IOMUX_PAD(0x66c, 0x208, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD22__IPU_DISPB_WR                            IOMUX_PAD(0x66c, 0x208, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD22__IPU_DISPB_SD_D_I                                IOMUX_PAD(0x66c, 0x208, 2, 0x92c, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD22__ESDHC3_DAT2                             IOMUX_PAD(0x66c, 0x208, 3, 0x824, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD22__USB_TOP_USBOTG_NXT                      IOMUX_PAD(0x66c, 0x208, 4, 0x9c8, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD22__GPIO3_28                                        IOMUX_PAD(0x66c, 0x208, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD22__SDMA_DEBUG_BUS_ERROR                    IOMUX_PAD(0x66c, 0x208, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD22__ARM11P_TOP_TRCTL                                IOMUX_PAD(0x66c, 0x208, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_LD23__IPU_DISPB_DAT_23                                IOMUX_PAD(0x670, 0x20c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD23__IPU_DISPB_RD                            IOMUX_PAD(0x670, 0x20c, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD23__IPU_DISPB_SD_D_IO                       IOMUX_PAD(0x670, 0x20c, 2, 0x92c, 1, NO_PAD_CTRL)
+#define MX35_PAD_LD23__ESDHC3_DAT3                             IOMUX_PAD(0x670, 0x20c, 3, 0x828, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD23__USB_TOP_USBOTG_DATA_7                   IOMUX_PAD(0x670, 0x20c, 4, 0x9c0, 0, NO_PAD_CTRL)
+#define MX35_PAD_LD23__GPIO3_29                                        IOMUX_PAD(0x670, 0x20c, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD23__SDMA_DEBUG_MATCHED_DMBUS                        IOMUX_PAD(0x670, 0x20c, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_LD23__ARM11P_TOP_TRCLK                                IOMUX_PAD(0x670, 0x20c, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D3_HSYNC__IPU_DISPB_D3_HSYNC                  IOMUX_PAD(0x674, 0x210, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_HSYNC__IPU_DISPB_SD_D_IO                   IOMUX_PAD(0x674, 0x210, 2, 0x92c, 2, NO_PAD_CTRL)
+#define MX35_PAD_D3_HSYNC__GPIO3_30                            IOMUX_PAD(0x674, 0x210, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_HSYNC__SDMA_DEBUG_RTBUFFER_WRITE           IOMUX_PAD(0x674, 0x210, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_HSYNC__ARM11P_TOP_TRACE_15                 IOMUX_PAD(0x674, 0x210, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D3_FPSHIFT__IPU_DISPB_D3_CLK                  IOMUX_PAD(0x678, 0x214, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_FPSHIFT__IPU_DISPB_SD_CLK                  IOMUX_PAD(0x678, 0x214, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_FPSHIFT__GPIO3_31                          IOMUX_PAD(0x678, 0x214, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_FPSHIFT__SDMA_SDMA_DEBUG_CORE_STATUS_0     IOMUX_PAD(0x678, 0x214, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_FPSHIFT__ARM11P_TOP_TRACE_16               IOMUX_PAD(0x678, 0x214, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D3_DRDY__IPU_DISPB_D3_DRDY                    IOMUX_PAD(0x67c, 0x218, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_DRDY__IPU_DISPB_SD_D_O                     IOMUX_PAD(0x67c, 0x218, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_DRDY__GPIO1_0                              IOMUX_PAD(0x67c, 0x218, 5, 0x82c, 2, NO_PAD_CTRL)
+#define MX35_PAD_D3_DRDY__SDMA_SDMA_DEBUG_CORE_STATUS_1                IOMUX_PAD(0x67c, 0x218, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_DRDY__ARM11P_TOP_TRACE_17                  IOMUX_PAD(0x67c, 0x218, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_CONTRAST__IPU_DISPB_CONTR                     IOMUX_PAD(0x680, 0x21c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CONTRAST__GPIO1_1                             IOMUX_PAD(0x680, 0x21c, 5, 0x838, 2, NO_PAD_CTRL)
+#define MX35_PAD_CONTRAST__SDMA_SDMA_DEBUG_CORE_STATUS_2       IOMUX_PAD(0x680, 0x21c, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_CONTRAST__ARM11P_TOP_TRACE_18                 IOMUX_PAD(0x680, 0x21c, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D3_VSYNC__IPU_DISPB_D3_VSYNC                  IOMUX_PAD(0x684, 0x220, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_VSYNC__IPU_DISPB_CS1                       IOMUX_PAD(0x684, 0x220, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_VSYNC__GPIO1_2                             IOMUX_PAD(0x684, 0x220, 5, 0x848, 1, NO_PAD_CTRL)
+#define MX35_PAD_D3_VSYNC__SDMA_DEBUG_YIELD                    IOMUX_PAD(0x684, 0x220, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_VSYNC__ARM11P_TOP_TRACE_19                 IOMUX_PAD(0x684, 0x220, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D3_REV__IPU_DISPB_D3_REV                      IOMUX_PAD(0x688, 0x224, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_REV__IPU_DISPB_SER_RS                      IOMUX_PAD(0x688, 0x224, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_REV__GPIO1_3                               IOMUX_PAD(0x688, 0x224, 5, 0x84c, 1, NO_PAD_CTRL)
+#define MX35_PAD_D3_REV__SDMA_DEBUG_BUS_RWB                    IOMUX_PAD(0x688, 0x224, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_REV__ARM11P_TOP_TRACE_20                   IOMUX_PAD(0x688, 0x224, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D3_CLS__IPU_DISPB_D3_CLS                      IOMUX_PAD(0x68c, 0x228, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_CLS__IPU_DISPB_CS2                         IOMUX_PAD(0x68c, 0x228, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_CLS__GPIO1_4                               IOMUX_PAD(0x68c, 0x228, 5, 0x850, 2, NO_PAD_CTRL)
+#define MX35_PAD_D3_CLS__SDMA_DEBUG_BUS_DEVICE_0               IOMUX_PAD(0x68c, 0x228, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_CLS__ARM11P_TOP_TRACE_21                   IOMUX_PAD(0x68c, 0x228, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_D3_SPL__IPU_DISPB_D3_SPL                      IOMUX_PAD(0x690, 0x22c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_SPL__IPU_DISPB_D12_VSYNC                   IOMUX_PAD(0x690, 0x22c, 2, 0x928, 2, NO_PAD_CTRL)
+#define MX35_PAD_D3_SPL__GPIO1_5                               IOMUX_PAD(0x690, 0x22c, 5, 0x854, 2, NO_PAD_CTRL)
+#define MX35_PAD_D3_SPL__SDMA_DEBUG_BUS_DEVICE_1               IOMUX_PAD(0x690, 0x22c, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_D3_SPL__ARM11P_TOP_TRACE_22                   IOMUX_PAD(0x690, 0x22c, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD1_CMD__ESDHC1_CMD                           IOMUX_PAD(0x694, 0x230, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_CMD__MSHC_SCLK                            IOMUX_PAD(0x694, 0x230, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_CMD__IPU_DISPB_D0_VSYNC                   IOMUX_PAD(0x694, 0x230, 3, 0x924, 2, NO_PAD_CTRL)
+#define MX35_PAD_SD1_CMD__USB_TOP_USBOTG_DATA_4                        IOMUX_PAD(0x694, 0x230, 4, 0x9b4, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_CMD__GPIO1_6                              IOMUX_PAD(0x694, 0x230, 5, 0x858, 2, NO_PAD_CTRL)
+#define MX35_PAD_SD1_CMD__ARM11P_TOP_TRCTL                     IOMUX_PAD(0x694, 0x230, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD1_CLK__ESDHC1_CLK                           IOMUX_PAD(0x698, 0x234, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_CLK__MSHC_BS                              IOMUX_PAD(0x698, 0x234, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_CLK__IPU_DISPB_BCLK                       IOMUX_PAD(0x698, 0x234, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_CLK__USB_TOP_USBOTG_DATA_5                        IOMUX_PAD(0x698, 0x234, 4, 0x9b8, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_CLK__GPIO1_7                              IOMUX_PAD(0x698, 0x234, 5, 0x85c, 2, NO_PAD_CTRL)
+#define MX35_PAD_SD1_CLK__ARM11P_TOP_TRCLK                     IOMUX_PAD(0x698, 0x234, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD1_DATA0__ESDHC1_DAT0                                IOMUX_PAD(0x69c, 0x238, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA0__MSHC_DATA_0                                IOMUX_PAD(0x69c, 0x238, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA0__IPU_DISPB_CS0                      IOMUX_PAD(0x69c, 0x238, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA0__USB_TOP_USBOTG_DATA_6              IOMUX_PAD(0x69c, 0x238, 4, 0x9bc, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA0__GPIO1_8                            IOMUX_PAD(0x69c, 0x238, 5, 0x860, 2, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA0__ARM11P_TOP_TRACE_23                        IOMUX_PAD(0x69c, 0x238, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD1_DATA1__ESDHC1_DAT1                                IOMUX_PAD(0x6a0, 0x23c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA1__MSHC_DATA_1                                IOMUX_PAD(0x6a0, 0x23c, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA1__IPU_DISPB_PAR_RS                   IOMUX_PAD(0x6a0, 0x23c, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA1__USB_TOP_USBOTG_DATA_0              IOMUX_PAD(0x6a0, 0x23c, 4, 0x9a4, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA1__GPIO1_9                            IOMUX_PAD(0x6a0, 0x23c, 5, 0x864, 1, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA1__ARM11P_TOP_TRACE_24                        IOMUX_PAD(0x6a0, 0x23c, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD1_DATA2__ESDHC1_DAT2                                IOMUX_PAD(0x6a4, 0x240, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA2__MSHC_DATA_2                                IOMUX_PAD(0x6a4, 0x240, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA2__IPU_DISPB_WR                       IOMUX_PAD(0x6a4, 0x240, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA2__USB_TOP_USBOTG_DATA_1              IOMUX_PAD(0x6a4, 0x240, 4, 0x9a8, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA2__GPIO1_10                           IOMUX_PAD(0x6a4, 0x240, 5, 0x830, 1, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA2__ARM11P_TOP_TRACE_25                        IOMUX_PAD(0x6a4, 0x240, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD1_DATA3__ESDHC1_DAT3                                IOMUX_PAD(0x6a8, 0x244, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA3__MSHC_DATA_3                                IOMUX_PAD(0x6a8, 0x244, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA3__IPU_DISPB_RD                       IOMUX_PAD(0x6a8, 0x244, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA3__USB_TOP_USBOTG_DATA_2              IOMUX_PAD(0x6a8, 0x244, 4, 0x9ac, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA3__GPIO1_11                           IOMUX_PAD(0x6a8, 0x244, 5, 0x834, 1, NO_PAD_CTRL)
+#define MX35_PAD_SD1_DATA3__ARM11P_TOP_TRACE_26                        IOMUX_PAD(0x6a8, 0x244, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD2_CMD__ESDHC2_CMD                           IOMUX_PAD(0x6ac, 0x248, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CMD__I2C3_SCL                             IOMUX_PAD(0x6ac, 0x248, 1, 0x91c, 2, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CMD__ESDHC1_DAT4                          IOMUX_PAD(0x6ac, 0x248, 2, 0x804, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CMD__IPU_CSI_D_2                          IOMUX_PAD(0x6ac, 0x248, 3, 0x938, 2, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CMD__USB_TOP_USBH2_DATA_4                 IOMUX_PAD(0x6ac, 0x248, 4, 0x9dc, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CMD__GPIO2_0                              IOMUX_PAD(0x6ac, 0x248, 5, 0x868, 2, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CMD__SPDIF_SPDIF_OUT1                     IOMUX_PAD(0x6ac, 0x248, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CMD__IPU_DISPB_D12_VSYNC                  IOMUX_PAD(0x6ac, 0x248, 7, 0x928, 3, NO_PAD_CTRL)
+
+#define MX35_PAD_SD2_CLK__ESDHC2_CLK                           IOMUX_PAD(0x6b0, 0x24c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CLK__I2C3_SDA                             IOMUX_PAD(0x6b0, 0x24c, 1, 0x920, 2, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CLK__ESDHC1_DAT5                          IOMUX_PAD(0x6b0, 0x24c, 2, 0x808, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CLK__IPU_CSI_D_3                          IOMUX_PAD(0x6b0, 0x24c, 3, 0x93c, 2, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CLK__USB_TOP_USBH2_DATA_5                 IOMUX_PAD(0x6b0, 0x24c, 4, 0x9e0, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CLK__GPIO2_1                              IOMUX_PAD(0x6b0, 0x24c, 5, 0x894, 1, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CLK__SPDIF_SPDIF_IN1                      IOMUX_PAD(0x6b0, 0x24c, 6, 0x998, 2, NO_PAD_CTRL)
+#define MX35_PAD_SD2_CLK__IPU_DISPB_CS2                                IOMUX_PAD(0x6b0, 0x24c, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_SD2_DATA0__ESDHC2_DAT0                                IOMUX_PAD(0x6b4, 0x250, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA0__UART3_RXD_MUX                      IOMUX_PAD(0x6b4, 0x250, 1, 0x9a0, 1, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA0__ESDHC1_DAT6                                IOMUX_PAD(0x6b4, 0x250, 2, 0x80c, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA0__IPU_CSI_D_4                                IOMUX_PAD(0x6b4, 0x250, 3, 0x940, 1, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA0__USB_TOP_USBH2_DATA_6               IOMUX_PAD(0x6b4, 0x250, 4, 0x9e4, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA0__GPIO2_2                            IOMUX_PAD(0x6b4, 0x250, 5, 0x8c0, 1, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA0__SPDIF_SPDIF_EXTCLK                 IOMUX_PAD(0x6b4, 0x250, 6, 0x994, 3, NO_PAD_CTRL)
+
+#define MX35_PAD_SD2_DATA1__ESDHC2_DAT1                                IOMUX_PAD(0x6b8, 0x254, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA1__UART3_TXD_MUX                      IOMUX_PAD(0x6b8, 0x254, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA1__ESDHC1_DAT7                                IOMUX_PAD(0x6b8, 0x254, 2, 0x810, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA1__IPU_CSI_D_5                                IOMUX_PAD(0x6b8, 0x254, 3, 0x944, 1, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA1__USB_TOP_USBH2_DATA_0               IOMUX_PAD(0x6b8, 0x254, 4, 0x9cc, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA1__GPIO2_3                            IOMUX_PAD(0x6b8, 0x254, 5, 0x8cc, 1, NO_PAD_CTRL)
+
+#define MX35_PAD_SD2_DATA2__ESDHC2_DAT2                                IOMUX_PAD(0x6bc, 0x258, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA2__UART3_RTS                          IOMUX_PAD(0x6bc, 0x258, 1, 0x99c, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA2__CAN1_RXCAN                         IOMUX_PAD(0x6bc, 0x258, 2, 0x7c8, 1, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA2__IPU_CSI_D_6                                IOMUX_PAD(0x6bc, 0x258, 3, 0x948, 1, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA2__USB_TOP_USBH2_DATA_1               IOMUX_PAD(0x6bc, 0x258, 4, 0x9d0, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA2__GPIO2_4                            IOMUX_PAD(0x6bc, 0x258, 5, 0x8d0, 1, NO_PAD_CTRL)
+
+#define MX35_PAD_SD2_DATA3__ESDHC2_DAT3                                IOMUX_PAD(0x6c0, 0x25c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA3__UART3_CTS                          IOMUX_PAD(0x6c0, 0x25c, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA3__CAN1_TXCAN                         IOMUX_PAD(0x6c0, 0x25c, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA3__IPU_CSI_D_7                                IOMUX_PAD(0x6c0, 0x25c, 3, 0x94c, 1, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA3__USB_TOP_USBH2_DATA_2               IOMUX_PAD(0x6c0, 0x25c, 4, 0x9d4, 0, NO_PAD_CTRL)
+#define MX35_PAD_SD2_DATA3__GPIO2_5                            IOMUX_PAD(0x6c0, 0x25c, 5, 0x8d4, 1, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_CS0__ATA_CS0                              IOMUX_PAD(0x6c4, 0x260, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_CS0__CSPI1_SS3                            IOMUX_PAD(0x6c4, 0x260, 1, 0x7dc, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_CS0__IPU_DISPB_CS1                                IOMUX_PAD(0x6c4, 0x260, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_CS0__GPIO2_6                              IOMUX_PAD(0x6c4, 0x260, 5, 0x8d8, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_CS0__IPU_DIAGB_0                          IOMUX_PAD(0x6c4, 0x260, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_CS0__ARM11P_TOP_MAX1_HMASTER_0            IOMUX_PAD(0x6c4, 0x260, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_CS1__ATA_CS1                              IOMUX_PAD(0x6c8, 0x264, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_CS1__IPU_DISPB_CS2                                IOMUX_PAD(0x6c8, 0x264, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_CS1__CSPI2_SS0                            IOMUX_PAD(0x6c8, 0x264, 4, 0x7f0, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_CS1__GPIO2_7                              IOMUX_PAD(0x6c8, 0x264, 5, 0x8dc, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_CS1__IPU_DIAGB_1                          IOMUX_PAD(0x6c8, 0x264, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_CS1__ARM11P_TOP_MAX1_HMASTER_1            IOMUX_PAD(0x6c8, 0x264, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DIOR__ATA_DIOR                            IOMUX_PAD(0x6cc, 0x268, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOR__ESDHC3_DAT0                         IOMUX_PAD(0x6cc, 0x268, 1, 0x81c, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOR__USB_TOP_USBOTG_DIR                  IOMUX_PAD(0x6cc, 0x268, 2, 0x9c4, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOR__IPU_DISPB_BE0                       IOMUX_PAD(0x6cc, 0x268, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOR__CSPI2_SS1                           IOMUX_PAD(0x6cc, 0x268, 4, 0x7f4, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOR__GPIO2_8                             IOMUX_PAD(0x6cc, 0x268, 5, 0x8e0, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOR__IPU_DIAGB_2                         IOMUX_PAD(0x6cc, 0x268, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOR__ARM11P_TOP_MAX1_HMASTER_2           IOMUX_PAD(0x6cc, 0x268, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DIOW__ATA_DIOW                            IOMUX_PAD(0x6d0, 0x26c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOW__ESDHC3_DAT1                         IOMUX_PAD(0x6d0, 0x26c, 1, 0x820, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOW__USB_TOP_USBOTG_STP                  IOMUX_PAD(0x6d0, 0x26c, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOW__IPU_DISPB_BE1                       IOMUX_PAD(0x6d0, 0x26c, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOW__CSPI2_MOSI                          IOMUX_PAD(0x6d0, 0x26c, 4, 0x7ec, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOW__GPIO2_9                             IOMUX_PAD(0x6d0, 0x26c, 5, 0x8e4, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOW__IPU_DIAGB_3                         IOMUX_PAD(0x6d0, 0x26c, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DIOW__ARM11P_TOP_MAX1_HMASTER_3           IOMUX_PAD(0x6d0, 0x26c, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DMACK__ATA_DMACK                          IOMUX_PAD(0x6d4, 0x270, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DMACK__ESDHC3_DAT2                                IOMUX_PAD(0x6d4, 0x270, 1, 0x824, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DMACK__USB_TOP_USBOTG_NXT                 IOMUX_PAD(0x6d4, 0x270, 2, 0x9c8, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DMACK__CSPI2_MISO                         IOMUX_PAD(0x6d4, 0x270, 4, 0x7e8, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DMACK__GPIO2_10                           IOMUX_PAD(0x6d4, 0x270, 5, 0x86c, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DMACK__IPU_DIAGB_4                                IOMUX_PAD(0x6d4, 0x270, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DMACK__ARM11P_TOP_MAX0_HMASTER_0          IOMUX_PAD(0x6d4, 0x270, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_RESET_B__ATA_RESET_B                      IOMUX_PAD(0x6d8, 0x274, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_RESET_B__ESDHC3_DAT3                      IOMUX_PAD(0x6d8, 0x274, 1, 0x828, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_RESET_B__USB_TOP_USBOTG_DATA_0            IOMUX_PAD(0x6d8, 0x274, 2, 0x9a4, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_RESET_B__IPU_DISPB_SD_D_O                 IOMUX_PAD(0x6d8, 0x274, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_RESET_B__CSPI2_RDY                                IOMUX_PAD(0x6d8, 0x274, 4, 0x7e4, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_RESET_B__GPIO2_11                         IOMUX_PAD(0x6d8, 0x274, 5, 0x870, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_RESET_B__IPU_DIAGB_5                      IOMUX_PAD(0x6d8, 0x274, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_RESET_B__ARM11P_TOP_MAX0_HMASTER_1                IOMUX_PAD(0x6d8, 0x274, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_IORDY__ATA_IORDY                          IOMUX_PAD(0x6dc, 0x278, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_IORDY__ESDHC3_DAT4                                IOMUX_PAD(0x6dc, 0x278, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_IORDY__USB_TOP_USBOTG_DATA_1              IOMUX_PAD(0x6dc, 0x278, 2, 0x9a8, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_IORDY__IPU_DISPB_SD_D_IO                  IOMUX_PAD(0x6dc, 0x278, 3, 0x92c, 3, NO_PAD_CTRL)
+#define MX35_PAD_ATA_IORDY__ESDHC2_DAT4                                IOMUX_PAD(0x6dc, 0x278, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_IORDY__GPIO2_12                           IOMUX_PAD(0x6dc, 0x278, 5, 0x874, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_IORDY__IPU_DIAGB_6                                IOMUX_PAD(0x6dc, 0x278, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_IORDY__ARM11P_TOP_MAX0_HMASTER_2          IOMUX_PAD(0x6dc, 0x278, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA0__ATA_DATA_0                         IOMUX_PAD(0x6e0, 0x27c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA0__ESDHC3_DAT5                                IOMUX_PAD(0x6e0, 0x27c, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA0__USB_TOP_USBOTG_DATA_2              IOMUX_PAD(0x6e0, 0x27c, 2, 0x9ac, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA0__IPU_DISPB_D12_VSYNC                        IOMUX_PAD(0x6e0, 0x27c, 3, 0x928, 4, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA0__ESDHC2_DAT5                                IOMUX_PAD(0x6e0, 0x27c, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA0__GPIO2_13                           IOMUX_PAD(0x6e0, 0x27c, 5, 0x878, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA0__IPU_DIAGB_7                                IOMUX_PAD(0x6e0, 0x27c, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA0__ARM11P_TOP_MAX0_HMASTER_3          IOMUX_PAD(0x6e0, 0x27c, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA1__ATA_DATA_1                         IOMUX_PAD(0x6e4, 0x280, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA1__ESDHC3_DAT6                                IOMUX_PAD(0x6e4, 0x280, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA1__USB_TOP_USBOTG_DATA_3              IOMUX_PAD(0x6e4, 0x280, 2, 0x9b0, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA1__IPU_DISPB_SD_CLK                   IOMUX_PAD(0x6e4, 0x280, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA1__ESDHC2_DAT6                                IOMUX_PAD(0x6e4, 0x280, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA1__GPIO2_14                           IOMUX_PAD(0x6e4, 0x280, 5, 0x87c, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA1__IPU_DIAGB_8                                IOMUX_PAD(0x6e4, 0x280, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA1__ARM11P_TOP_TRACE_27                        IOMUX_PAD(0x6e4, 0x280, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA2__ATA_DATA_2                         IOMUX_PAD(0x6e8, 0x284, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA2__ESDHC3_DAT7                                IOMUX_PAD(0x6e8, 0x284, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA2__USB_TOP_USBOTG_DATA_4              IOMUX_PAD(0x6e8, 0x284, 2, 0x9b4, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA2__IPU_DISPB_SER_RS                   IOMUX_PAD(0x6e8, 0x284, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA2__ESDHC2_DAT7                                IOMUX_PAD(0x6e8, 0x284, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA2__GPIO2_15                           IOMUX_PAD(0x6e8, 0x284, 5, 0x880, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA2__IPU_DIAGB_9                                IOMUX_PAD(0x6e8, 0x284, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA2__ARM11P_TOP_TRACE_28                        IOMUX_PAD(0x6e8, 0x284, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA3__ATA_DATA_3                         IOMUX_PAD(0x6e8, 0x288, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA3__ESDHC3_CLK                         IOMUX_PAD(0x6e8, 0x288, 1, 0x814, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA3__USB_TOP_USBOTG_DATA_5              IOMUX_PAD(0x6e8, 0x288, 2, 0x9b8, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA3__CSPI2_SCLK                         IOMUX_PAD(0x6e8, 0x288, 4, 0x7e0, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA3__GPIO2_16                           IOMUX_PAD(0x6e8, 0x288, 5, 0x884, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA3__IPU_DIAGB_10                       IOMUX_PAD(0x6e8, 0x288, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA3__ARM11P_TOP_TRACE_29                        IOMUX_PAD(0x6e8, 0x288, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA4__ATA_DATA_4                         IOMUX_PAD(0x6f0, 0x28c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA4__ESDHC3_CMD                         IOMUX_PAD(0x6f0, 0x28c, 1, 0x818, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA4__USB_TOP_USBOTG_DATA_6              IOMUX_PAD(0x6f0, 0x28c, 2, 0x9bc, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA4__GPIO2_17                           IOMUX_PAD(0x6f0, 0x28c, 5, 0x888, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA4__IPU_DIAGB_11                       IOMUX_PAD(0x6f0, 0x28c, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA4__ARM11P_TOP_TRACE_30                        IOMUX_PAD(0x6f0, 0x28c, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA5__ATA_DATA_5                         IOMUX_PAD(0x6f4, 0x290, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA5__USB_TOP_USBOTG_DATA_7              IOMUX_PAD(0x6f4, 0x290, 2, 0x9c0, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA5__GPIO2_18                           IOMUX_PAD(0x6f4, 0x290, 5, 0x88c, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA5__IPU_DIAGB_12                       IOMUX_PAD(0x6f4, 0x290, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA5__ARM11P_TOP_TRACE_31                        IOMUX_PAD(0x6f4, 0x290, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA6__ATA_DATA_6                         IOMUX_PAD(0x6f8, 0x294, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA6__CAN1_TXCAN                         IOMUX_PAD(0x6f8, 0x294, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA6__UART1_DTR                          IOMUX_PAD(0x6f8, 0x294, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA6__AUDMUX_AUD6_TXD                    IOMUX_PAD(0x6f8, 0x294, 3, 0x7b4, 0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA6__GPIO2_19                           IOMUX_PAD(0x6f8, 0x294, 5, 0x890, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA6__IPU_DIAGB_13                       IOMUX_PAD(0x6f8, 0x294, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA7__ATA_DATA_7                         IOMUX_PAD(0x6fc, 0x298, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA7__CAN1_RXCAN                         IOMUX_PAD(0x6fc, 0x298, 1, 0x7c8, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA7__UART1_DSR                          IOMUX_PAD(0x6fc, 0x298, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA7__AUDMUX_AUD6_RXD                    IOMUX_PAD(0x6fc, 0x298, 3, 0x7b0, 0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA7__GPIO2_20                           IOMUX_PAD(0x6fc, 0x298, 5, 0x898, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA7__IPU_DIAGB_14                       IOMUX_PAD(0x6fc, 0x298, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA8__ATA_DATA_8                         IOMUX_PAD(0x700, 0x29c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA8__UART3_RTS                          IOMUX_PAD(0x700, 0x29c, 1, 0x99c, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA8__UART1_RI                           IOMUX_PAD(0x700, 0x29c, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA8__AUDMUX_AUD6_TXC                    IOMUX_PAD(0x700, 0x29c, 3, 0x7c0, 0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA8__GPIO2_21                           IOMUX_PAD(0x700, 0x29c, 5, 0x89c, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA8__IPU_DIAGB_15                       IOMUX_PAD(0x700, 0x29c, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA9__ATA_DATA_9                         IOMUX_PAD(0x704, 0x2a0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA9__UART3_CTS                          IOMUX_PAD(0x704, 0x2a0, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA9__UART1_DCD                          IOMUX_PAD(0x704, 0x2a0, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA9__AUDMUX_AUD6_TXFS                   IOMUX_PAD(0x704, 0x2a0, 3, 0x7c4, 0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA9__GPIO2_22                           IOMUX_PAD(0x704, 0x2a0, 5, 0x8a0, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA9__IPU_DIAGB_16                       IOMUX_PAD(0x704, 0x2a0, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA10__ATA_DATA_10                       IOMUX_PAD(0x708, 0x2a4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA10__UART3_RXD_MUX                     IOMUX_PAD(0x708, 0x2a4, 1, 0x9a0, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA10__AUDMUX_AUD6_RXC                   IOMUX_PAD(0x708, 0x2a4, 3, 0x7b8, 0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA10__GPIO2_23                          IOMUX_PAD(0x708, 0x2a4, 5, 0x8a4, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA10__IPU_DIAGB_17                      IOMUX_PAD(0x708, 0x2a4, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA11__ATA_DATA_11                       IOMUX_PAD(0x70c, 0x2a8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA11__UART3_TXD_MUX                     IOMUX_PAD(0x70c, 0x2a8, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA11__AUDMUX_AUD6_RXFS                  IOMUX_PAD(0x70c, 0x2a8, 3, 0x7bc, 0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA11__GPIO2_24                          IOMUX_PAD(0x70c, 0x2a8, 5, 0x8a8, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA11__IPU_DIAGB_18                      IOMUX_PAD(0x70c, 0x2a8, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA12__ATA_DATA_12                       IOMUX_PAD(0x710, 0x2ac, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA12__I2C3_SCL                          IOMUX_PAD(0x710, 0x2ac, 1, 0x91c, 3, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA12__GPIO2_25                          IOMUX_PAD(0x710, 0x2ac, 5, 0x8ac, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA12__IPU_DIAGB_19                      IOMUX_PAD(0x710, 0x2ac, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA13__ATA_DATA_13                       IOMUX_PAD(0x714, 0x2b0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA13__I2C3_SDA                          IOMUX_PAD(0x714, 0x2b0, 1, 0x920, 3, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA13__GPIO2_26                          IOMUX_PAD(0x714, 0x2b0, 5, 0x8b0, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA13__IPU_DIAGB_20                      IOMUX_PAD(0x714, 0x2b0, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA14__ATA_DATA_14                       IOMUX_PAD(0x718, 0x2b4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA14__IPU_CSI_D_0                       IOMUX_PAD(0x718, 0x2b4, 1, 0x930, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA14__KPP_ROW_0                         IOMUX_PAD(0x718, 0x2b4, 3, 0x970, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA14__GPIO2_27                          IOMUX_PAD(0x718, 0x2b4, 5, 0x8b4, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA14__IPU_DIAGB_21                      IOMUX_PAD(0x718, 0x2b4, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DATA15__ATA_DATA_15                       IOMUX_PAD(0x71c, 0x2b8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA15__IPU_CSI_D_1                       IOMUX_PAD(0x71c, 0x2b8, 1, 0x934, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA15__KPP_ROW_1                         IOMUX_PAD(0x71c, 0x2b8, 3, 0x974, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA15__GPIO2_28                          IOMUX_PAD(0x71c, 0x2b8, 5, 0x8b8, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA15__IPU_DIAGB_22                      IOMUX_PAD(0x71c, 0x2b8, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_INTRQ__ATA_INTRQ                          IOMUX_PAD(0x720, 0x2bc, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_INTRQ__IPU_CSI_D_2                                IOMUX_PAD(0x720, 0x2bc, 1, 0x938, 3, NO_PAD_CTRL)
+#define MX35_PAD_ATA_INTRQ__KPP_ROW_2                          IOMUX_PAD(0x720, 0x2bc, 3, 0x978, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_INTRQ__GPIO2_29                           IOMUX_PAD(0x720, 0x2bc, 5, 0x8bc, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_INTRQ__IPU_DIAGB_23                       IOMUX_PAD(0x720, 0x2bc, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_BUFF_EN__ATA_BUFFER_EN                    IOMUX_PAD(0x724, 0x2c0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_BUFF_EN__IPU_CSI_D_3                      IOMUX_PAD(0x724, 0x2c0, 1, 0x93c, 3, NO_PAD_CTRL)
+#define MX35_PAD_ATA_BUFF_EN__KPP_ROW_3                                IOMUX_PAD(0x724, 0x2c0, 3, 0x97c, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_BUFF_EN__GPIO2_30                         IOMUX_PAD(0x724, 0x2c0, 5, 0x8c4, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_BUFF_EN__IPU_DIAGB_24                     IOMUX_PAD(0x724, 0x2c0, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DMARQ__ATA_DMARQ                          IOMUX_PAD(0x728, 0x2c4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DMARQ__IPU_CSI_D_4                                IOMUX_PAD(0x728, 0x2c4, 1, 0x940, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DMARQ__KPP_COL_0                          IOMUX_PAD(0x728, 0x2c4, 3, 0x950, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DMARQ__GPIO2_31                           IOMUX_PAD(0x728, 0x2c4, 5, 0x8c8, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DMARQ__IPU_DIAGB_25                       IOMUX_PAD(0x728, 0x2c4, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DMARQ__ECT_CTI_TRIG_IN1_4                 IOMUX_PAD(0x728, 0x2c4, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DA0__ATA_DA_0                             IOMUX_PAD(0x72c, 0x2c8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA0__IPU_CSI_D_5                          IOMUX_PAD(0x72c, 0x2c8, 1, 0x944, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA0__KPP_COL_1                            IOMUX_PAD(0x72c, 0x2c8, 3, 0x954, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA0__GPIO3_0                              IOMUX_PAD(0x72c, 0x2c8, 5, 0x8e8, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA0__IPU_DIAGB_26                         IOMUX_PAD(0x72c, 0x2c8, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA0__ECT_CTI_TRIG_IN1_5                   IOMUX_PAD(0x72c, 0x2c8, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DA1__ATA_DA_1                             IOMUX_PAD(0x730, 0x2cc, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA1__IPU_CSI_D_6                          IOMUX_PAD(0x730, 0x2cc, 1, 0x948, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA1__KPP_COL_2                            IOMUX_PAD(0x730, 0x2cc, 3, 0x958, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA1__GPIO3_1                              IOMUX_PAD(0x730, 0x2cc, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA1__IPU_DIAGB_27                         IOMUX_PAD(0x730, 0x2cc, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA1__ECT_CTI_TRIG_IN1_6                   IOMUX_PAD(0x730, 0x2cc, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_ATA_DA2__ATA_DA_2                             IOMUX_PAD(0x734, 0x2d0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA2__IPU_CSI_D_7                          IOMUX_PAD(0x734, 0x2d0, 1, 0x94c, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA2__KPP_COL_3                            IOMUX_PAD(0x734, 0x2d0, 3, 0x95c, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA2__GPIO3_2                              IOMUX_PAD(0x734, 0x2d0, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA2__IPU_DIAGB_28                         IOMUX_PAD(0x734, 0x2d0, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DA2__ECT_CTI_TRIG_IN1_7                   IOMUX_PAD(0x734, 0x2d0, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_MLB_CLK__MLB_MLBCLK                           IOMUX_PAD(0x738, 0x2d4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_MLB_CLK__GPIO3_3                              IOMUX_PAD(0x738, 0x2d4, 5, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_MLB_DAT__MLB_MLBDAT                           IOMUX_PAD(0x73c, 0x2d8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_MLB_DAT__GPIO3_4                              IOMUX_PAD(0x73c, 0x2d8, 5, 0x904, 1, NO_PAD_CTRL)
+
+#define MX35_PAD_MLB_SIG__MLB_MLBSIG                           IOMUX_PAD(0x740, 0x2dc, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_MLB_SIG__GPIO3_5                              IOMUX_PAD(0x740, 0x2dc, 5, 0x908, 1, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_TX_CLK__FEC_TX_CLK                                IOMUX_PAD(0x744, 0x2e0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_CLK__ESDHC1_DAT4                       IOMUX_PAD(0x744, 0x2e0, 1, 0x804, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_CLK__UART3_RXD_MUX                     IOMUX_PAD(0x744, 0x2e0, 2, 0x9a0, 3, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_CLK__USB_TOP_USBH2_DIR                 IOMUX_PAD(0x744, 0x2e0, 3, 0x9ec, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_CLK__CSPI2_MOSI                                IOMUX_PAD(0x744, 0x2e0, 4, 0x7ec, 3, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_CLK__GPIO3_6                           IOMUX_PAD(0x744, 0x2e0, 5, 0x90c, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_CLK__IPU_DISPB_D12_VSYNC               IOMUX_PAD(0x744, 0x2e0, 6, 0x928, 5, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_CLK__ARM11P_TOP_EVNTBUS_0              IOMUX_PAD(0x744, 0x2e0, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_RX_CLK__FEC_RX_CLK                                IOMUX_PAD(0x748, 0x2e4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_CLK__ESDHC1_DAT5                       IOMUX_PAD(0x748, 0x2e4, 1, 0x808, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_CLK__UART3_TXD_MUX                     IOMUX_PAD(0x748, 0x2e4, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_CLK__USB_TOP_USBH2_STP                 IOMUX_PAD(0x748, 0x2e4, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_CLK__CSPI2_MISO                                IOMUX_PAD(0x748, 0x2e4, 4, 0x7e8, 3, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_CLK__GPIO3_7                           IOMUX_PAD(0x748, 0x2e4, 5, 0x910, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_CLK__IPU_DISPB_SD_D_I                  IOMUX_PAD(0x748, 0x2e4, 6, 0x92c, 4, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_CLK__ARM11P_TOP_EVNTBUS_1              IOMUX_PAD(0x748, 0x2e4, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_RX_DV__FEC_RX_DV                          IOMUX_PAD(0x74c, 0x2e8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_DV__ESDHC1_DAT6                                IOMUX_PAD(0x74c, 0x2e8, 1, 0x80c, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_DV__UART3_RTS                          IOMUX_PAD(0x74c, 0x2e8, 2, 0x99c, 2, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_DV__USB_TOP_USBH2_NXT                  IOMUX_PAD(0x74c, 0x2e8, 3, 0x9f0, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_DV__CSPI2_SCLK                         IOMUX_PAD(0x74c, 0x2e8, 4, 0x7e0, 3, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_DV__GPIO3_8                            IOMUX_PAD(0x74c, 0x2e8, 5, 0x914, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_DV__IPU_DISPB_SD_CLK                   IOMUX_PAD(0x74c, 0x2e8, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_DV__ARM11P_TOP_EVNTBUS_2               IOMUX_PAD(0x74c, 0x2e8, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_COL__FEC_COL                              IOMUX_PAD(0x750, 0x2ec, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_COL__ESDHC1_DAT7                          IOMUX_PAD(0x750, 0x2ec, 1, 0x810, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_COL__UART3_CTS                            IOMUX_PAD(0x750, 0x2ec, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_COL__USB_TOP_USBH2_DATA_0                 IOMUX_PAD(0x750, 0x2ec, 3, 0x9cc, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_COL__CSPI2_RDY                            IOMUX_PAD(0x750, 0x2ec, 4, 0x7e4, 3, NO_PAD_CTRL)
+#define MX35_PAD_FEC_COL__GPIO3_9                              IOMUX_PAD(0x750, 0x2ec, 5, 0x918, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_COL__IPU_DISPB_SER_RS                     IOMUX_PAD(0x750, 0x2ec, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_COL__ARM11P_TOP_EVNTBUS_3                 IOMUX_PAD(0x750, 0x2ec, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_RDATA0__FEC_RDATA_0                       IOMUX_PAD(0x754, 0x2f0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA0__PWM_PWMO                          IOMUX_PAD(0x754, 0x2f0, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA0__UART3_DTR                         IOMUX_PAD(0x754, 0x2f0, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA0__USB_TOP_USBH2_DATA_1              IOMUX_PAD(0x754, 0x2f0, 3, 0x9d0, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA0__CSPI2_SS0                         IOMUX_PAD(0x754, 0x2f0, 4, 0x7f0, 2, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA0__GPIO3_10                          IOMUX_PAD(0x754, 0x2f0, 5, 0x8ec, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA0__IPU_DISPB_CS1                     IOMUX_PAD(0x754, 0x2f0, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA0__ARM11P_TOP_EVNTBUS_4              IOMUX_PAD(0x754, 0x2f0, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_TDATA0__FEC_TDATA_0                       IOMUX_PAD(0x758, 0x2f4, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA0__SPDIF_SPDIF_OUT1                  IOMUX_PAD(0x758, 0x2f4, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA0__UART3_DSR                         IOMUX_PAD(0x758, 0x2f4, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA0__USB_TOP_USBH2_DATA_2              IOMUX_PAD(0x758, 0x2f4, 3, 0x9d4, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA0__CSPI2_SS1                         IOMUX_PAD(0x758, 0x2f4, 4, 0x7f4, 2, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA0__GPIO3_11                          IOMUX_PAD(0x758, 0x2f4, 5, 0x8f0, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA0__IPU_DISPB_CS0                     IOMUX_PAD(0x758, 0x2f4, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA0__ARM11P_TOP_EVNTBUS_5              IOMUX_PAD(0x758, 0x2f4, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_TX_EN__FEC_TX_EN                          IOMUX_PAD(0x75c, 0x2f8, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_EN__SPDIF_SPDIF_IN1                    IOMUX_PAD(0x75c, 0x2f8, 1, 0x998, 3, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_EN__UART3_RI                           IOMUX_PAD(0x75c, 0x2f8, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_EN__USB_TOP_USBH2_DATA_3               IOMUX_PAD(0x75c, 0x2f8, 3, 0x9d8, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_EN__GPIO3_12                           IOMUX_PAD(0x75c, 0x2f8, 5, 0x8f4, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_EN__IPU_DISPB_PAR_RS                   IOMUX_PAD(0x75c, 0x2f8, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_EN__ARM11P_TOP_EVNTBUS_6               IOMUX_PAD(0x75c, 0x2f8, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_MDC__FEC_MDC                              IOMUX_PAD(0x760, 0x2fc, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_MDC__CAN2_TXCAN                           IOMUX_PAD(0x760, 0x2fc, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_MDC__UART3_DCD                            IOMUX_PAD(0x760, 0x2fc, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_MDC__USB_TOP_USBH2_DATA_4                 IOMUX_PAD(0x760, 0x2fc, 3, 0x9dc, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_MDC__GPIO3_13                             IOMUX_PAD(0x760, 0x2fc, 5, 0x8f8, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_MDC__IPU_DISPB_WR                         IOMUX_PAD(0x760, 0x2fc, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_MDC__ARM11P_TOP_EVNTBUS_7                 IOMUX_PAD(0x760, 0x2fc, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_MDIO__FEC_MDIO                            IOMUX_PAD(0x764, 0x300, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_MDIO__CAN2_RXCAN                          IOMUX_PAD(0x764, 0x300, 1, 0x7cc, 2, NO_PAD_CTRL)
+#define MX35_PAD_FEC_MDIO__USB_TOP_USBH2_DATA_5                        IOMUX_PAD(0x764, 0x300, 3, 0x9e0, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_MDIO__GPIO3_14                            IOMUX_PAD(0x764, 0x300, 5, 0x8fc, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_MDIO__IPU_DISPB_RD                                IOMUX_PAD(0x764, 0x300, 6, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_MDIO__ARM11P_TOP_EVNTBUS_8                        IOMUX_PAD(0x764, 0x300, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_TX_ERR__FEC_TX_ERR                                IOMUX_PAD(0x768, 0x304, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_ERR__OWIRE_LINE                                IOMUX_PAD(0x768, 0x304, 1, 0x990, 2, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_ERR__SPDIF_SPDIF_EXTCLK                        IOMUX_PAD(0x768, 0x304, 2, 0x994, 4, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_ERR__USB_TOP_USBH2_DATA_6              IOMUX_PAD(0x768, 0x304, 3, 0x9e4, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_ERR__GPIO3_15                          IOMUX_PAD(0x768, 0x304, 5, 0x900, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_ERR__IPU_DISPB_D0_VSYNC                        IOMUX_PAD(0x768, 0x304, 6, 0x924, 3, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TX_ERR__ARM11P_TOP_EVNTBUS_9              IOMUX_PAD(0x768, 0x304, 7, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_RX_ERR__FEC_RX_ERR                                IOMUX_PAD(0x76c, 0x308, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_ERR__IPU_CSI_D_0                       IOMUX_PAD(0x76c, 0x308, 1, 0x930, 3, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_ERR__USB_TOP_USBH2_DATA_7              IOMUX_PAD(0x76c, 0x308, 3, 0x9e8, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_ERR__KPP_COL_4                         IOMUX_PAD(0x76c, 0x308, 4, 0x960, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_ERR__GPIO3_16                          IOMUX_PAD(0x76c, 0x308, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RX_ERR__IPU_DISPB_SD_D_IO                 IOMUX_PAD(0x76c, 0x308, 6, 0x92c, 5, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_CRS__FEC_CRS                              IOMUX_PAD(0x770, 0x30c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_CRS__IPU_CSI_D_1                          IOMUX_PAD(0x770, 0x30c, 1, 0x934, 3, NO_PAD_CTRL)
+#define MX35_PAD_FEC_CRS__USB_TOP_USBH2_PWR                    IOMUX_PAD(0x770, 0x30c, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_CRS__KPP_COL_5                            IOMUX_PAD(0x770, 0x30c, 4, 0x964, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_CRS__GPIO3_17                             IOMUX_PAD(0x770, 0x30c, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_CRS__IPU_FLASH_STROBE                     IOMUX_PAD(0x770, 0x30c, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_RDATA1__FEC_RDATA_1                       IOMUX_PAD(0x774, 0x310, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA1__IPU_CSI_D_2                       IOMUX_PAD(0x774, 0x310, 1, 0x938, 4, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA1__AUDMUX_AUD6_RXC                   IOMUX_PAD(0x774, 0x310, 2, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA1__USB_TOP_USBH2_OC                  IOMUX_PAD(0x774, 0x310, 3, 0x9f4, 2, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA1__KPP_COL_6                         IOMUX_PAD(0x774, 0x310, 4, 0x968, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA1__GPIO3_18                          IOMUX_PAD(0x774, 0x310, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA1__IPU_DISPB_BE0                     IOMUX_PAD(0x774, 0x310, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_TDATA1__FEC_TDATA_1                       IOMUX_PAD(0x778, 0x314, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA1__IPU_CSI_D_3                       IOMUX_PAD(0x778, 0x314, 1, 0x93c, 4, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA1__AUDMUX_AUD6_RXFS                  IOMUX_PAD(0x778, 0x314, 2, 0x7bc, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA1__KPP_COL_7                         IOMUX_PAD(0x778, 0x314, 4, 0x96c, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA1__GPIO3_19                          IOMUX_PAD(0x778, 0x314, 5, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA1__IPU_DISPB_BE1                     IOMUX_PAD(0x778, 0x314, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_RDATA2__FEC_RDATA_2                       IOMUX_PAD(0x77c, 0x318, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA2__IPU_CSI_D_4                       IOMUX_PAD(0x77c, 0x318, 1, 0x940, 3, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA2__AUDMUX_AUD6_TXD                   IOMUX_PAD(0x77c, 0x318, 2, 0x7b4, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA2__KPP_ROW_4                         IOMUX_PAD(0x77c, 0x318, 4, 0x980, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA2__GPIO3_20                          IOMUX_PAD(0x77c, 0x318, 5, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_TDATA2__FEC_TDATA_2                       IOMUX_PAD(0x780, 0x31c, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA2__IPU_CSI_D_5                       IOMUX_PAD(0x780, 0x31c, 1, 0x944, 3, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA2__AUDMUX_AUD6_RXD                   IOMUX_PAD(0x780, 0x31c, 2, 0x7b0, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA2__KPP_ROW_5                         IOMUX_PAD(0x780, 0x31c, 4, 0x984, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA2__GPIO3_21                          IOMUX_PAD(0x780, 0x31c, 5, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_RDATA3__FEC_RDATA_3                       IOMUX_PAD(0x784, 0x320, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA3__IPU_CSI_D_6                       IOMUX_PAD(0x784, 0x320, 1, 0x948, 3, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA3__AUDMUX_AUD6_TXC                   IOMUX_PAD(0x784, 0x320, 2, 0x7c0, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA3__KPP_ROW_6                         IOMUX_PAD(0x784, 0x320, 4, 0x988, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_RDATA3__GPIO3_22                          IOMUX_PAD(0x784, 0x320, 6, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_FEC_TDATA3__FEC_TDATA_3                       IOMUX_PAD(0x788, 0x324, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA3__IPU_CSI_D_7                       IOMUX_PAD(0x788, 0x324, 1, 0x94c, 3, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA3__AUDMUX_AUD6_TXFS                  IOMUX_PAD(0x788, 0x324, 2, 0x7c4, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA3__KPP_ROW_7                         IOMUX_PAD(0x788, 0x324, 4, 0x98c, 1, NO_PAD_CTRL)
+#define MX35_PAD_FEC_TDATA3__GPIO3_23                          IOMUX_PAD(0x788, 0x324, 5, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_EXT_ARMCLK__CCM_EXT_ARMCLK                    IOMUX_PAD(0x78c, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+#define MX35_PAD_TEST_MODE__TCU_TEST_MODE                      IOMUX_PAD(0x790, 0x0,   0, 0x0,   0, NO_PAD_CTRL)
+
+
+#endif /* __MACH_IOMUX_MX35_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/iomux-v3.h b/arch/arm/plat-mxc/include/mach/iomux-v3.h
new file mode 100644 (file)
index 0000000..7cd8454
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2009 by Jan Weitzel Phytec Messtechnik GmbH,
+ *                     <armlinux@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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifndef __MACH_IOMUX_V3_H__
+#define __MACH_IOMUX_V3_H__
+
+/*
+ *     build IOMUX_PAD structure
+ *
+ * This iomux scheme is based around pads, which are the physical balls
+ * on the processor.
+ *
+ * - Each pad has a pad control register (IOMUXC_SW_PAD_CTRL_x) which controls
+ *   things like driving strength and pullup/pulldown.
+ * - Each pad can have but not necessarily does have an output routing register
+ *   (IOMUXC_SW_MUX_CTL_PAD_x).
+ * - Each pad can have but not necessarily does have an input routing register
+ *   (IOMUXC_x_SELECT_INPUT)
+ *
+ * The three register sets do not have a fixed offset to each other,
+ * hence we order this table by pad control registers (which all pads
+ * have) and put the optional i/o routing registers into additional
+ * fields.
+ *
+ * The naming convention for the pad modes is MX35_PAD_<padname>__<padmode>
+ * If <padname> or <padmode> refers to a GPIO, it is named
+ * GPIO_<unit>_<num>
+ *
+ */
+
+struct pad_desc {
+       unsigned mux_ctrl_ofs:12; /* IOMUXC_SW_MUX_CTL_PAD offset */
+       unsigned mux_mode:8;
+       unsigned pad_ctrl_ofs:12; /* IOMUXC_SW_PAD_CTRL offset */
+#define        NO_PAD_CTRL     (1 << 16)
+       unsigned pad_ctrl:17;
+       unsigned select_input_ofs:12; /* IOMUXC_SELECT_INPUT offset */
+       unsigned select_input:3;
+};
+
+#define IOMUX_PAD(_pad_ctrl_ofs, _mux_ctrl_ofs, _mux_mode, _select_input_ofs, \
+               _select_input, _pad_ctrl)                               \
+               {                                                       \
+                       .mux_ctrl_ofs     = _mux_ctrl_ofs,              \
+                       .mux_mode         = _mux_mode,                  \
+                       .pad_ctrl_ofs     = _pad_ctrl_ofs,              \
+                       .pad_ctrl         = _pad_ctrl,                  \
+                       .select_input_ofs = _select_input_ofs,          \
+                       .select_input     = _select_input,              \
+               }
+
+/*
+ * Use to set PAD control
+ */
+#define PAD_CTL_DRIVE_VOLTAGE_3_3_V    0
+#define PAD_CTL_DRIVE_VOLTAGE_1_8_V    1
+
+#define PAD_CTL_NO_HYSTERESIS          0
+#define PAD_CTL_HYSTERESIS             1
+
+#define PAD_CTL_PULL_DISABLED          0x0
+#define PAD_CTL_PULL_KEEPER            0xa
+#define PAD_CTL_PULL_DOWN_100K         0xc
+#define PAD_CTL_PULL_UP_47K            0xd
+#define PAD_CTL_PULL_UP_100K           0xe
+#define PAD_CTL_PULL_UP_22K            0xf
+
+#define PAD_CTL_OUTPUT_CMOS            0
+#define PAD_CTL_OUTPUT_OPEN_DRAIN      1
+
+#define PAD_CTL_DRIVE_STRENGTH_NORM    0
+#define PAD_CTL_DRIVE_STRENGTH_HIGH    1
+#define PAD_CTL_DRIVE_STRENGTH_MAX     2
+
+#define PAD_CTL_SLEW_RATE_SLOW         0
+#define PAD_CTL_SLEW_RATE_FAST         1
+
+/*
+ * setups a single pad:
+ *     - reserves the pad so that it is not claimed by another driver
+ *     - setups the iomux according to the configuration
+ */
+int mxc_iomux_v3_setup_pad(struct pad_desc *pad);
+
+/*
+ * setups mutliple pads
+ * convenient way to call the above function with tables
+ */
+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);
+
+#endif /* __MACH_IOMUX_V3_H__*/
+
index eca37d09f3f8cee771db68b8d32dbb2a6ef5cfc1..6065e00176edd2b910789b5b9d404006ca0e78cb 100644 (file)
 #define CONSISTENT_DMA_SIZE SZ_4M
 #endif /* CONFIG_MX1_VIDEO */
 
+#if defined(CONFIG_MX3_VIDEO)
+/*
+ * Increase size of DMA-consistent memory region.
+ * This is required for mx3 camera driver to capture at least two QXGA frames.
+ */
+#define CONSISTENT_DMA_SIZE SZ_8M
+#endif /* CONFIG_MX3_VIDEO */
+
 #endif /* __ASM_ARCH_MXC_MEMORY_H__ */
index b92e02324d8e02cb410ddb37db3c3fc4bcb3b2f4..1000bf330bcdbdaa8e514de8c83da3d6196a41de 100644 (file)
 #define DMA_REQ_UART1_T                30
 #define DMA_REQ_UART1_R                31
 
-/* mandatory for CONFIG_LL_DEBUG */
+/* mandatory for CONFIG_DEBUG_LL */
 #define MXC_LL_UART_PADDR      UART1_BASE_ADDR
 #define MXC_LL_UART_VADDR      IO_ADDRESS(UART1_BASE_ADDR)
 
index 3878c6085d5c2675f2c693644adb465b2e9a0dba..b559a4bb576987ed51d66a372236d719fe952378 100644 (file)
@@ -48,6 +48,9 @@
 #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
 
 /*
 #define CS4_IO_ADDRESS(x)  \
        (((x) - CS4_BASE_ADDR) + CS4_BASE_ADDR_VIRT)
 
+#define CS5_IO_ADDRESS(x)  \
+       (((x) - CS5_BASE_ADDR) + CS5_BASE_ADDR_VIRT)
+
 #define X_MEMC_IO_ADDRESS(x)  \
        (((x) - X_MEMC_BASE_ADDR) + X_MEMC_BASE_ADDR_VIRT)
 
diff --git a/arch/arm/plat-mxc/include/mach/mxc_timer.h b/arch/arm/plat-mxc/include/mach/mxc_timer.h
deleted file mode 100644 (file)
index 6c19a13..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * mxc_timer.h
- *
- * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
- *
- * Platform independent (i.MX1, i.MX2, i.MX3) definition for timer handling.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the 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 __PLAT_MXC_TIMER_H
-#define __PLAT_MXC_TIMER_H
-
-#include <linux/clk.h>
-#include <mach/hardware.h>
-
-#ifdef CONFIG_ARCH_MX1
-#define TIMER_BASE             IO_ADDRESS(TIM1_BASE_ADDR)
-#define TIMER_INTERRUPT                TIM1_INT
-
-#define TCTL_VAL               TCTL_CLK_PCLK1
-#define TCTL_IRQEN             (1<<4)
-#define TCTL_FRR               (1<<8)
-#define TCTL_CLK_PCLK1         (1<<1)
-#define TCTL_CLK_PCLK1_4       (2<<1)
-#define TCTL_CLK_TIN           (3<<1)
-#define TCTL_CLK_32            (4<<1)
-
-#define MXC_TCTL   0x00
-#define MXC_TPRER  0x04
-#define MXC_TCMP   0x08
-#define MXC_TCR    0x0c
-#define MXC_TCN    0x10
-#define MXC_TSTAT  0x14
-#define TSTAT_CAPT             (1<<1)
-#define TSTAT_COMP             (1<<0)
-
-static inline void gpt_irq_disable(void)
-{
-       unsigned int tmp;
-
-       tmp = __raw_readl(TIMER_BASE + MXC_TCTL);
-       __raw_writel(tmp & ~TCTL_IRQEN, TIMER_BASE + MXC_TCTL);
-}
-
-static inline void gpt_irq_enable(void)
-{
-       __raw_writel(__raw_readl(TIMER_BASE + MXC_TCTL) | TCTL_IRQEN,
-                               TIMER_BASE + MXC_TCTL);
-}
-
-static void gpt_irq_acknowledge(void)
-{
-       __raw_writel(0, TIMER_BASE + MXC_TSTAT);
-}
-#endif /* CONFIG_ARCH_MX1 */
-
-#ifdef CONFIG_ARCH_MX2
-#define TIMER_BASE             IO_ADDRESS(GPT1_BASE_ADDR)
-#define TIMER_INTERRUPT                MXC_INT_GPT1
-
-#define MXC_TCTL   0x00
-#define TCTL_VAL               TCTL_CLK_PCLK1
-#define TCTL_CLK_PCLK1         (1<<1)
-#define TCTL_CLK_PCLK1_4       (2<<1)
-#define TCTL_IRQEN             (1<<4)
-#define TCTL_FRR               (1<<8)
-#define MXC_TPRER  0x04
-#define MXC_TCMP   0x08
-#define MXC_TCR    0x0c
-#define MXC_TCN    0x10
-#define MXC_TSTAT  0x14
-#define TSTAT_CAPT             (1<<1)
-#define TSTAT_COMP             (1<<0)
-
-static inline void gpt_irq_disable(void)
-{
-       unsigned int tmp;
-
-       tmp = __raw_readl(TIMER_BASE + MXC_TCTL);
-       __raw_writel(tmp & ~TCTL_IRQEN, TIMER_BASE + MXC_TCTL);
-}
-
-static inline void gpt_irq_enable(void)
-{
-       __raw_writel(__raw_readl(TIMER_BASE + MXC_TCTL) | TCTL_IRQEN,
-                               TIMER_BASE + MXC_TCTL);
-}
-
-static void gpt_irq_acknowledge(void)
-{
-       __raw_writel(TSTAT_CAPT | TSTAT_COMP, TIMER_BASE + MXC_TSTAT);
-}
-#endif /* CONFIG_ARCH_MX2 */
-
-#ifdef CONFIG_ARCH_MX3
-#define TIMER_BASE             IO_ADDRESS(GPT1_BASE_ADDR)
-#define TIMER_INTERRUPT                MXC_INT_GPT
-
-#define MXC_TCTL   0x00
-#define TCTL_VAL               (TCTL_CLK_IPG | TCTL_WAITEN)
-#define TCTL_CLK_IPG           (1<<6)
-#define TCTL_FRR               (1<<9)
-#define TCTL_WAITEN            (1<<3)
-
-#define MXC_TPRER  0x04
-#define MXC_TSTAT  0x08
-#define TSTAT_OF1              (1<<0)
-#define TSTAT_OF2              (1<<1)
-#define TSTAT_OF3              (1<<2)
-#define TSTAT_IF1              (1<<3)
-#define TSTAT_IF2              (1<<4)
-#define TSTAT_ROV              (1<<5)
-#define MXC_IR     0x0c
-#define MXC_TCMP   0x10
-#define MXC_TCMP2  0x14
-#define MXC_TCMP3  0x18
-#define MXC_TCR    0x1c
-#define MXC_TCN    0x24
-
-static inline void gpt_irq_disable(void)
-{
-       __raw_writel(0, TIMER_BASE + MXC_IR);
-}
-
-static inline void gpt_irq_enable(void)
-{
-       __raw_writel(1<<0, TIMER_BASE + MXC_IR);
-}
-
-static inline void gpt_irq_acknowledge(void)
-{
-       __raw_writel(TSTAT_OF1, TIMER_BASE + MXC_TSTAT);
-}
-#endif /* CONFIG_ARCH_MX3 */
-
-#define TCTL_SWR               (1<<15)
-#define TCTL_CC                        (1<<10)
-#define TCTL_OM                        (1<<9)
-#define TCTL_CAP_RIS           (1<<6)
-#define TCTL_CAP_FAL           (2<<6)
-#define TCTL_CAP_RIS_FAL       (3<<6)
-#define TCTL_CAP_ENA           (1<<5)
-#define TCTL_TEN               (1<<0)
-
-#endif
index 2dacb3086f1c06ae9b0bc48b74692effe0a6cf44..be273371f34ac82d8b919a305864cfe50e13da36 100644 (file)
@@ -17,7 +17,7 @@
 
 struct imxusb_platform_data {
        int (*init)(struct device *);
-       int (*exit)(struct device *);
+       void (*exit)(struct device *);
 };
 
 #endif /* __ASM_ARCH_MXC_USB */
diff --git a/arch/arm/plat-mxc/iomux-v3.c b/arch/arm/plat-mxc/iomux-v3.c
new file mode 100644 (file)
index 0000000..77a078f
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2008 by Sascha Hauer <kernel@pengutronix.de>
+ * Copyright (C) 2009 by Jan Weitzel Phytec Messtechnik GmbH,
+ *                       <armlinux@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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/gpio.h>
+
+#include <mach/hardware.h>
+#include <asm/mach/map.h>
+#include <mach/iomux-v3.h>
+
+#define IOMUX_BASE     IO_ADDRESS(IOMUXC_BASE_ADDR)
+
+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
+ */
+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, IOMUX_BASE + pad->mux_ctrl_ofs);
+
+       if (pad->select_input_ofs)
+               __raw_writel(pad->select_input,
+                               IOMUX_BASE + pad->select_input_ofs);
+
+       if (!(pad->pad_ctrl & NO_PAD_CTRL))
+               __raw_writel(pad->pad_ctrl, IOMUX_BASE + pad->pad_ctrl_ofs);
+       return 0;
+}
+EXPORT_SYMBOL(mxc_iomux_v3_setup_pad);
+
+int mxc_iomux_v3_setup_multiple_pads(struct pad_desc *pad_list, unsigned count)
+{
+       struct pad_desc *p = pad_list;
+       int i;
+       int ret;
+
+       for (i = 0; i < count; i++) {
+               ret = mxc_iomux_v3_setup_pad(p);
+               if (ret)
+                       goto setup_error;
+               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);
index 0fb68a531f5536e231286829598bab832349d038..8aee76304f8f770b1a0836f3add9864900f8d201 100644 (file)
 #include <asm/mach/irq.h>
 #include <mach/hardware.h>
 
-#define AVIC_BASE              IO_ADDRESS(AVIC_BASE_ADDR)
-#define AVIC_INTCNTL           (AVIC_BASE + 0x00)      /* int control reg */
-#define AVIC_NIMASK            (AVIC_BASE + 0x04)      /* int mask reg */
-#define AVIC_INTENNUM          (AVIC_BASE + 0x08)      /* int enable number reg */
-#define AVIC_INTDISNUM         (AVIC_BASE + 0x0C)      /* int disable number reg */
-#define AVIC_INTENABLEH                (AVIC_BASE + 0x10)      /* int enable reg high */
-#define AVIC_INTENABLEL                (AVIC_BASE + 0x14)      /* int enable reg low */
-#define AVIC_INTTYPEH          (AVIC_BASE + 0x18)      /* int type reg high */
-#define AVIC_INTTYPEL          (AVIC_BASE + 0x1C)      /* int type reg low */
-#define AVIC_NIPRIORITY(x)     (AVIC_BASE + (0x20 + 4 * (7 - (x)))) /* int priority */
-#define AVIC_NIVECSR           (AVIC_BASE + 0x40)      /* norm int vector/status */
-#define AVIC_FIVECSR           (AVIC_BASE + 0x44)      /* fast int vector/status */
-#define AVIC_INTSRCH           (AVIC_BASE + 0x48)      /* int source reg high */
-#define AVIC_INTSRCL           (AVIC_BASE + 0x4C)      /* int source reg low */
-#define AVIC_INTFRCH           (AVIC_BASE + 0x50)      /* int force reg high */
-#define AVIC_INTFRCL           (AVIC_BASE + 0x54)      /* int force reg low */
-#define AVIC_NIPNDH            (AVIC_BASE + 0x58)      /* norm int pending high */
-#define AVIC_NIPNDL            (AVIC_BASE + 0x5C)      /* norm int pending low */
-#define AVIC_FIPNDH            (AVIC_BASE + 0x60)      /* fast int pending high */
-#define AVIC_FIPNDL            (AVIC_BASE + 0x64)      /* fast int pending low */
-
-#define SYSTEM_PREV_REG                IO_ADDRESS(IIM_BASE_ADDR + 0x20)
-#define SYSTEM_SREV_REG                IO_ADDRESS(IIM_BASE_ADDR + 0x24)
-#define IIM_PROD_REV_SH                3
-#define IIM_PROD_REV_LEN       5
+#define AVIC_INTCNTL           0x00    /* int control reg */
+#define AVIC_NIMASK            0x04    /* int mask reg */
+#define AVIC_INTENNUM          0x08    /* int enable number reg */
+#define AVIC_INTDISNUM         0x0C    /* int disable number reg */
+#define AVIC_INTENABLEH                0x10    /* int enable reg high */
+#define AVIC_INTENABLEL                0x14    /* int enable reg low */
+#define AVIC_INTTYPEH          0x18    /* int type reg high */
+#define AVIC_INTTYPEL          0x1C    /* int type reg low */
+#define AVIC_NIPRIORITY(x)     (0x20 + 4 * (7 - (x))) /* int priority */
+#define AVIC_NIVECSR           0x40    /* norm int vector/status */
+#define AVIC_FIVECSR           0x44    /* fast int vector/status */
+#define AVIC_INTSRCH           0x48    /* int source reg high */
+#define AVIC_INTSRCL           0x4C    /* int source reg low */
+#define AVIC_INTFRCH           0x50    /* int force reg high */
+#define AVIC_INTFRCL           0x54    /* int force reg low */
+#define AVIC_NIPNDH            0x58    /* norm int pending high */
+#define AVIC_NIPNDL            0x5C    /* norm int pending low */
+#define AVIC_FIPNDH            0x60    /* fast int pending high */
+#define AVIC_FIPNDL            0x64    /* fast int pending low */
+
+static void __iomem *avic_base;
 
 int imx_irq_set_priority(unsigned char irq, unsigned char prio)
 {
@@ -59,11 +55,11 @@ int imx_irq_set_priority(unsigned char irq, unsigned char prio)
        if (irq >= MXC_INTERNAL_IRQS)
                return -EINVAL;;
 
-       temp = __raw_readl(AVIC_NIPRIORITY(irq / 8));
+       temp = __raw_readl(avic_base + AVIC_NIPRIORITY(irq / 8));
        temp &= ~mask;
        temp |= prio & mask;
 
-       __raw_writel(temp, AVIC_NIPRIORITY(irq / 8));
+       __raw_writel(temp, avic_base + AVIC_NIPRIORITY(irq / 8));
 
        return 0;
 #else
@@ -81,12 +77,12 @@ int mxc_set_irq_fiq(unsigned int irq, unsigned int type)
                return -EINVAL;
 
        if (irq < MXC_INTERNAL_IRQS / 2) {
-               irqt = __raw_readl(AVIC_INTTYPEL) & ~(1 << irq);
-               __raw_writel(irqt | (!!type << irq), AVIC_INTTYPEL);
+               irqt = __raw_readl(avic_base + AVIC_INTTYPEL) & ~(1 << irq);
+               __raw_writel(irqt | (!!type << irq), avic_base + AVIC_INTTYPEL);
        } else {
                irq -= MXC_INTERNAL_IRQS / 2;
-               irqt = __raw_readl(AVIC_INTTYPEH) & ~(1 << irq);
-               __raw_writel(irqt | (!!type << irq), AVIC_INTTYPEH);
+               irqt = __raw_readl(avic_base + AVIC_INTTYPEH) & ~(1 << irq);
+               __raw_writel(irqt | (!!type << irq), avic_base + AVIC_INTTYPEH);
        }
 
        return 0;
@@ -97,13 +93,13 @@ EXPORT_SYMBOL(mxc_set_irq_fiq);
 /* Disable interrupt number "irq" in the AVIC */
 static void mxc_mask_irq(unsigned int irq)
 {
-       __raw_writel(irq, AVIC_INTDISNUM);
+       __raw_writel(irq, avic_base + AVIC_INTDISNUM);
 }
 
 /* Enable interrupt number "irq" in the AVIC */
 static void mxc_unmask_irq(unsigned int irq)
 {
-       __raw_writel(irq, AVIC_INTENNUM);
+       __raw_writel(irq, avic_base + AVIC_INTENNUM);
 }
 
 static struct irq_chip mxc_avic_chip = {
@@ -121,19 +117,21 @@ void __init mxc_init_irq(void)
 {
        int i;
 
+       avic_base = IO_ADDRESS(AVIC_BASE_ADDR);
+
        /* put the AVIC into the reset value with
         * all interrupts disabled
         */
-       __raw_writel(0, AVIC_INTCNTL);
-       __raw_writel(0x1f, AVIC_NIMASK);
+       __raw_writel(0, avic_base + AVIC_INTCNTL);
+       __raw_writel(0x1f, avic_base + AVIC_NIMASK);
 
        /* disable all interrupts */
-       __raw_writel(0, AVIC_INTENABLEH);
-       __raw_writel(0, AVIC_INTENABLEL);
+       __raw_writel(0, avic_base + AVIC_INTENABLEH);
+       __raw_writel(0, avic_base + AVIC_INTENABLEL);
 
        /* all IRQ no FIQ */
-       __raw_writel(0, AVIC_INTTYPEH);
-       __raw_writel(0, AVIC_INTTYPEL);
+       __raw_writel(0, avic_base + AVIC_INTTYPEH);
+       __raw_writel(0, avic_base + AVIC_INTTYPEL);
        for (i = 0; i < MXC_INTERNAL_IRQS; i++) {
                set_irq_chip(i, &mxc_avic_chip);
                set_irq_handler(i, handle_level_irq);
@@ -142,7 +140,7 @@ void __init mxc_init_irq(void)
 
        /* Set default priority value (0) for all IRQ's */
        for (i = 0; i < 8; i++)
-               __raw_writel(0, AVIC_NIPRIORITY(i));
+               __raw_writel(0, avic_base + AVIC_NIPRIORITY(i));
 
        /* init architectures chained interrupt handler */
        mxc_register_gpios();
@@ -154,3 +152,4 @@ void __init mxc_init_irq(void)
 
        printk(KERN_INFO "MXC IRQ initialized\n");
 }
+
index 9bffbc507cc2804e79dcdde527e9ad55ef67ba2c..ae34198a79dd279b86c4a51060cbfe154e4c64c1 100644 (file)
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/pwm.h>
+#include <mach/hardware.h>
+
+
+/* i.MX1 and i.MX21 share the same PWM function block: */
+
+#define MX1_PWMC    0x00   /* PWM Control Register */
+#define MX1_PWMS    0x04   /* PWM Sample Register */
+#define MX1_PWMP    0x08   /* PWM Period Register */
+
+
+/* i.MX27, i.MX31, i.MX35 share the same PWM function block: */
+
+#define MX3_PWMCR                 0x00    /* PWM Control Register */
+#define MX3_PWMSAR                0x0C    /* PWM Sample Register */
+#define MX3_PWMPR                 0x10    /* PWM Period Register */
+#define MX3_PWMCR_PRESCALER(x)    (((x - 1) & 0xFFF) << 4)
+#define MX3_PWMCR_CLKSRC_IPG_HIGH (2 << 16)
+#define MX3_PWMCR_EN              (1 << 0)
+
 
-#if defined CONFIG_ARCH_MX1 || defined CONFIG_ARCH_MX21
-#define PWM_VER_1
-
-#define PWMCR  0x00    /* PWM Control Register         */
-#define PWMSR  0x04    /* PWM Sample Register          */
-#define PWMPR  0x08    /* PWM Period Register          */
-#define PWMCNR 0x0C    /* PWM Counter Register         */
-
-#define PWMCR_HCTR             (1 << 18)               /* Halfword FIFO Data Swapping  */
-#define PWMCR_BCTR             (1 << 17)               /* Byte FIFO Data Swapping      */
-#define PWMCR_SWR              (1 << 16)               /* Software Reset               */
-#define PWMCR_CLKSRC_PERCLK    (0 << 15)               /* PERCLK Clock Source          */
-#define PWMCR_CLKSRC_CLK32     (1 << 15)               /* 32KHz Clock Source           */
-#define PWMCR_PRESCALER(x)     (((x - 1) & 0x7F) << 8) /* PRESCALER                    */
-#define PWMCR_IRQ              (1 << 7)                /* Interrupt Request            */
-#define PWMCR_IRQEN            (1 << 6)                /* Interrupt Request Enable     */
-#define PWMCR_FIFOAV           (1 << 5)                /* FIFO Available               */
-#define PWMCR_EN               (1 << 4)                /* Enables/Disables the PWM     */
-#define PWMCR_REPEAT(x)                (((x) & 0x03) << 2)     /* Sample Repeats               */
-#define PWMCR_DIV(x)           (((x) & 0x03) << 0)     /* Clock divider 2/4/8/16       */
-
-#define MAX_DIV                        (128 * 16)
-#endif
-
-#if defined CONFIG_MACH_MX27 || defined CONFIG_ARCH_MX31
-#define PWM_VER_2
-
-#define PWMCR  0x00    /* PWM Control Register         */
-#define PWMSR  0x04    /* PWM Status Register          */
-#define PWMIR  0x08    /* PWM Interrupt Register       */
-#define PWMSAR 0x0C    /* PWM Sample Register          */
-#define PWMPR  0x10    /* PWM Period Register          */
-#define PWMCNR 0x14    /* PWM Counter Register         */
-
-#define PWMCR_EN               (1 << 0)                /* Enables/Disables the PWM     */
-#define PWMCR_REPEAT(x)                (((x) & 0x03) << 1)     /* Sample Repeats               */
-#define PWMCR_SWR              (1 << 3)                /* Software Reset               */
-#define PWMCR_PRESCALER(x)     (((x - 1) & 0xFFF) << 4)/* PRESCALER                    */
-#define PWMCR_CLKSRC(x)                (((x) & 0x3) << 16)
-#define PWMCR_CLKSRC_OFF       (0 << 16)
-#define PWMCR_CLKSRC_IPG       (1 << 16)
-#define PWMCR_CLKSRC_IPG_HIGH  (2 << 16)
-#define PWMCR_CLKSRC_CLK32     (3 << 16)
-#define PWMCR_POUTC
-#define PWMCR_HCTR             (1 << 20)               /* Halfword FIFO Data Swapping  */
-#define PWMCR_BCTR             (1 << 21)               /* Byte FIFO Data Swapping      */
-#define PWMCR_DBGEN            (1 << 22)               /* Debug Mode                   */
-#define PWMCR_WAITEN           (1 << 23)               /* Wait Mode                    */
-#define PWMCR_DOZEN            (1 << 24)               /* Doze Mode                    */
-#define PWMCR_STOPEN           (1 << 25)               /* Stop Mode                    */
-#define PWMCR_FWM(x)           (((x) & 0x3) << 26)     /* FIFO Water Mark              */
-
-#define MAX_DIV 4096
-#endif
-
-#define PWMS_SAMPLE(x)         ((x) & 0xFFFF)          /* Contains a two-sample word   */
-#define PWMP_PERIOD(x)         ((x) & 0xFFFF)          /* Represents the PWM's period  */
-#define PWMC_COUNTER(x)                ((x) & 0xFFFF)          /* Represents the current count value   */
 
 struct pwm_device {
        struct list_head        node;
@@ -91,32 +52,52 @@ struct pwm_device {
 
 int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
 {
-       unsigned long long c;
-       unsigned long period_cycles, duty_cycles, prescale;
-
        if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
                return -EINVAL;
 
-       c = clk_get_rate(pwm->clk);
-       c = c * period_ns;
-       do_div(c, 1000000000);
-       period_cycles = c;
-
-       prescale = period_cycles / 0x10000 + 1;
-
-       period_cycles /= prescale;
-       c = (unsigned long long)period_cycles * duty_ns;
-       do_div(c, period_ns);
-       duty_cycles = c;
-
-#ifdef PWM_VER_2
-       writel(duty_cycles, pwm->mmio_base + PWMSAR);
-       writel(period_cycles, pwm->mmio_base + PWMPR);
-       writel(PWMCR_PRESCALER(prescale - 1) | PWMCR_CLKSRC_IPG_HIGH | PWMCR_EN,
-                       pwm->mmio_base + PWMCR);
-#elif defined PWM_VER_1
-#error PWM not yet working on MX1 / MX21
-#endif
+       if (cpu_is_mx27() || cpu_is_mx3()) {
+               unsigned long long c;
+               unsigned long period_cycles, duty_cycles, prescale;
+               c = clk_get_rate(pwm->clk);
+               c = c * period_ns;
+               do_div(c, 1000000000);
+               period_cycles = c;
+
+               prescale = period_cycles / 0x10000 + 1;
+
+               period_cycles /= prescale;
+               c = (unsigned long long)period_cycles * duty_ns;
+               do_div(c, period_ns);
+               duty_cycles = c;
+
+               writel(duty_cycles, pwm->mmio_base + MX3_PWMSAR);
+               writel(period_cycles, pwm->mmio_base + MX3_PWMPR);
+               writel(MX3_PWMCR_PRESCALER(prescale - 1) |
+                       MX3_PWMCR_CLKSRC_IPG_HIGH | MX3_PWMCR_EN,
+                       pwm->mmio_base + MX3_PWMCR);
+       } else if (cpu_is_mx1() || cpu_is_mx21()) {
+               /* The PWM subsystem allows for exact frequencies. However,
+                * I cannot connect a scope on my device to the PWM line and
+                * thus cannot provide the program the PWM controller
+                * exactly. Instead, I'm relying on the fact that the
+                * Bootloader (u-boot or WinCE+haret) has programmed the PWM
+                * function group already. So I'll just modify the PWM sample
+                * register to follow the ratio of duty_ns vs. period_ns
+                * accordingly.
+                *
+                * This is good enought for programming the brightness of
+                * the LCD backlight.
+                *
+                * The real implementation would divide PERCLK[0] first by
+                * both the prescaler (/1 .. /128) and then by CLKSEL
+                * (/2 .. /16).
+                */
+               u32 max = readl(pwm->mmio_base + MX1_PWMP);
+               u32 p = max * duty_ns / period_ns;
+               writel(max - p, pwm->mmio_base + MX1_PWMS);
+       } else {
+               BUG();
+       }
 
        return 0;
 }
@@ -297,4 +278,3 @@ module_exit(mxc_pwm_exit);
 
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
-
index dab3357196fb8a6b6c51f71329b0cb15ce1f4932..88fb3a57e0299fcf25c61f4ea054f09601b64efd 100644 (file)
 #include <mach/hardware.h>
 #include <asm/mach/time.h>
 #include <mach/common.h>
-#include <mach/mxc_timer.h>
+
+/* defines common for all i.MX */
+#define MXC_TCTL               0x00
+#define MXC_TCTL_TEN           (1 << 0)
+#define MXC_TPRER              0x04
+
+/* MX1, MX21, MX27 */
+#define MX1_2_TCTL_CLK_PCLK1   (1 << 1)
+#define MX1_2_TCTL_IRQEN       (1 << 4)
+#define MX1_2_TCTL_FRR         (1 << 8)
+#define MX1_2_TCMP             0x08
+#define MX1_2_TCN              0x10
+#define MX1_2_TSTAT            0x14
+
+/* MX21, MX27 */
+#define MX2_TSTAT_CAPT         (1 << 1)
+#define MX2_TSTAT_COMP         (1 << 0)
+
+/* MX31, MX35 */
+#define MX3_TCTL_WAITEN                (1 << 3)
+#define MX3_TCTL_CLK_IPG       (1 << 6)
+#define MX3_TCTL_FRR           (1 << 9)
+#define MX3_IR                 0x0c
+#define MX3_TSTAT              0x08
+#define MX3_TSTAT_OF1          (1 << 0)
+#define MX3_TCN                        0x24
+#define MX3_TCMP               0x10
 
 static struct clock_event_device clockevent_mxc;
 static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
 
-/* clock source */
+static void __iomem *timer_base;
 
-static cycle_t mxc_get_cycles(struct clocksource *cs)
+static inline void gpt_irq_disable(void)
 {
-       return __raw_readl(TIMER_BASE + MXC_TCN);
+       unsigned int tmp;
+
+       if (cpu_is_mx3())
+               __raw_writel(0, timer_base + MX3_IR);
+       else {
+               tmp = __raw_readl(timer_base + MXC_TCTL);
+               __raw_writel(tmp & ~MX1_2_TCTL_IRQEN, timer_base + MXC_TCTL);
+       }
+}
+
+static inline void gpt_irq_enable(void)
+{
+       if (cpu_is_mx3())
+               __raw_writel(1<<0, timer_base + MX3_IR);
+       else {
+               __raw_writel(__raw_readl(timer_base + MXC_TCTL) | MX1_2_TCTL_IRQEN,
+                       timer_base + MXC_TCTL);
+       }
+}
+
+static void gpt_irq_acknowledge(void)
+{
+       if (cpu_is_mx1())
+               __raw_writel(0, timer_base + MX1_2_TSTAT);
+       if (cpu_is_mx2())
+               __raw_writel(MX2_TSTAT_CAPT | MX2_TSTAT_COMP, timer_base + MX1_2_TSTAT);
+       if (cpu_is_mx3())
+               __raw_writel(MX3_TSTAT_OF1, timer_base + MX3_TSTAT);
+}
+
+static cycle_t mx1_2_get_cycles(struct clocksource *cs)
+{
+       return __raw_readl(timer_base + MX1_2_TCN);
+}
+
+static cycle_t mx3_get_cycles(struct clocksource *cs)
+{
+       return __raw_readl(timer_base + MX3_TCN);
 }
 
 static struct clocksource clocksource_mxc = {
        .name           = "mxc_timer1",
        .rating         = 200,
-       .read           = mxc_get_cycles,
+       .read           = mx1_2_get_cycles,
        .mask           = CLOCKSOURCE_MASK(32),
        .shift          = 20,
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
@@ -54,6 +117,9 @@ static int __init mxc_clocksource_init(struct clk *timer_clk)
 {
        unsigned int c = clk_get_rate(timer_clk);
 
+       if (cpu_is_mx3())
+               clocksource_mxc.read = mx3_get_cycles;
+
        clocksource_mxc.mult = clocksource_hz2mult(c,
                                        clocksource_mxc.shift);
        clocksource_register(&clocksource_mxc);
@@ -63,15 +129,29 @@ static int __init mxc_clocksource_init(struct clk *timer_clk)
 
 /* clock event */
 
-static int mxc_set_next_event(unsigned long evt,
+static int mx1_2_set_next_event(unsigned long evt,
                              struct clock_event_device *unused)
 {
        unsigned long tcmp;
 
-       tcmp = __raw_readl(TIMER_BASE + MXC_TCN) + evt;
-       __raw_writel(tcmp, TIMER_BASE + MXC_TCMP);
+       tcmp = __raw_readl(timer_base + MX1_2_TCN) + evt;
 
-       return (int)(tcmp - __raw_readl(TIMER_BASE + MXC_TCN)) < 0 ?
+       __raw_writel(tcmp, timer_base + MX1_2_TCMP);
+
+       return (int)(tcmp - __raw_readl(timer_base + MX1_2_TCN)) < 0 ?
+                               -ETIME : 0;
+}
+
+static int mx3_set_next_event(unsigned long evt,
+                             struct clock_event_device *unused)
+{
+       unsigned long tcmp;
+
+       tcmp = __raw_readl(timer_base + MX3_TCN) + evt;
+
+       __raw_writel(tcmp, timer_base + MX3_TCMP);
+
+       return (int)(tcmp - __raw_readl(timer_base + MX3_TCN)) < 0 ?
                                -ETIME : 0;
 }
 
@@ -100,8 +180,13 @@ static void mxc_set_mode(enum clock_event_mode mode,
 
        if (mode != clockevent_mode) {
                /* Set event time into far-far future */
-               __raw_writel(__raw_readl(TIMER_BASE + MXC_TCN) - 3,
-                               TIMER_BASE + MXC_TCMP);
+               if (cpu_is_mx3())
+                       __raw_writel(__raw_readl(timer_base + MX3_TCN) - 3,
+                                       timer_base + MX3_TCMP);
+               else
+                       __raw_writel(__raw_readl(timer_base + MX1_2_TCN) - 3,
+                                       timer_base + MX1_2_TCMP);
+
                /* Clear pending interrupt */
                gpt_irq_acknowledge();
        }
@@ -148,7 +233,10 @@ static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
        struct clock_event_device *evt = &clockevent_mxc;
        uint32_t tstat;
 
-       tstat = __raw_readl(TIMER_BASE + MXC_TSTAT);
+       if (cpu_is_mx3())
+               tstat = __raw_readl(timer_base + MX3_TSTAT);
+       else
+               tstat = __raw_readl(timer_base + MX1_2_TSTAT);
 
        gpt_irq_acknowledge();
 
@@ -168,7 +256,7 @@ static struct clock_event_device clockevent_mxc = {
        .features       = CLOCK_EVT_FEAT_ONESHOT,
        .shift          = 32,
        .set_mode       = mxc_set_mode,
-       .set_next_event = mxc_set_next_event,
+       .set_next_event = mx1_2_set_next_event,
        .rating         = 200,
 };
 
@@ -176,6 +264,9 @@ static int __init mxc_clockevent_init(struct clk *timer_clk)
 {
        unsigned int c = clk_get_rate(timer_clk);
 
+       if (cpu_is_mx3())
+               clockevent_mxc.set_next_event = mx3_set_next_event;
+
        clockevent_mxc.mult = div_sc(c, NSEC_PER_SEC,
                                        clockevent_mxc.shift);
        clockevent_mxc.max_delta_ns =
@@ -192,23 +283,47 @@ static int __init mxc_clockevent_init(struct clk *timer_clk)
 
 void __init mxc_timer_init(struct clk *timer_clk)
 {
+       uint32_t tctl_val;
+       int irq;
+
        clk_enable(timer_clk);
 
+       if (cpu_is_mx1()) {
+#ifdef CONFIG_ARCH_MX1
+               timer_base = IO_ADDRESS(TIM1_BASE_ADDR);
+               irq = TIM1_INT;
+#endif
+       } else if (cpu_is_mx2()) {
+#ifdef CONFIG_ARCH_MX2
+               timer_base = IO_ADDRESS(GPT1_BASE_ADDR);
+               irq = MXC_INT_GPT1;
+#endif
+       } else if (cpu_is_mx3()) {
+#ifdef CONFIG_ARCH_MX3
+               timer_base = IO_ADDRESS(GPT1_BASE_ADDR);
+               irq = MXC_INT_GPT;
+#endif
+       } else
+               BUG();
+
        /*
         * Initialise to a known state (all timers off, and timing reset)
         */
-       __raw_writel(0, TIMER_BASE + MXC_TCTL);
-       __raw_writel(0, TIMER_BASE + MXC_TPRER); /* see datasheet note */
 
-       __raw_writel(TCTL_FRR | /* free running */
-                    TCTL_VAL | /* set clocksource and arch specific bits */
-                    TCTL_TEN,  /* start the timer */
-                    TIMER_BASE + MXC_TCTL);
+       __raw_writel(0, timer_base + MXC_TCTL);
+       __raw_writel(0, timer_base + MXC_TPRER); /* see datasheet note */
+
+       if (cpu_is_mx3())
+               tctl_val = MX3_TCTL_CLK_IPG | MX3_TCTL_FRR | MX3_TCTL_WAITEN | MXC_TCTL_TEN;
+       else
+               tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN;
+
+       __raw_writel(tctl_val, timer_base + MXC_TCTL);
 
        /* init and register the timer to the framework */
        mxc_clocksource_init(timer_clk);
        mxc_clockevent_init(timer_clk);
 
        /* Make irqs happen */
-       setup_irq(TIMER_INTERRUPT, &mxc_timer_irq);
+       setup_irq(irq, &mxc_timer_irq);
 }
index 9dd68fafb374b54c273ebe2e7034be042e993563..efe85d0951901cd3773b436a096da87da80e5dfe 100644 (file)
@@ -23,6 +23,11 @@ config ARCH_OMAP3
        select CPU_V7
        select COMMON_CLKDEV
 
+config ARCH_OMAP4
+       bool "TI OMAP4"
+       select CPU_V7
+       select ARM_GIC
+
 endchoice
 
 comment "OMAP Feature Selections"
@@ -40,7 +45,6 @@ config OMAP_DEBUG_LEDS
 config OMAP_DEBUG_POWERDOMAIN
        bool "Emit debug messages from powerdomain layer"
        depends on ARCH_OMAP2 || ARCH_OMAP3
-       default n
        help
          Say Y here if you want to compile in powerdomain layer
          debugging messages for OMAP2/3.   These messages can
@@ -52,7 +56,6 @@ config OMAP_DEBUG_POWERDOMAIN
 config OMAP_DEBUG_CLOCKDOMAIN
        bool "Emit debug messages from clockdomain layer"
        depends on ARCH_OMAP2 || ARCH_OMAP3
-       default n
        help
          Say Y here if you want to compile in clockdomain layer
          debugging messages for OMAP2/3.   These messages can
@@ -110,11 +113,13 @@ config OMAP_MCBSP
 config OMAP_MBOX_FWK
        tristate "Mailbox framework support"
        depends on ARCH_OMAP
-       default n
        help
          Say Y here if you want to use OMAP Mailbox framework support for
          DSP, IVA1.0 and IVA2 in OMAP1/2/3.
 
+config OMAP_IOMMU
+       tristate
+
 choice
         prompt "System timer"
        default OMAP_MPU_TIMER
@@ -128,13 +133,13 @@ config OMAP_MPU_TIMER
 
 config OMAP_32K_TIMER
        bool "Use 32KHz timer"
-       depends on ARCH_OMAP16XX || ARCH_OMAP24XX || ARCH_OMAP34XX
+       depends on ARCH_OMAP16XX || ARCH_OMAP24XX || ARCH_OMAP34XX || ARCH_OMAP4
        help
          Select this option if you want to enable the OMAP 32KHz timer.
          This timer saves power compared to the OMAP_MPU_TIMER, and has
          support for no tick during idle. The 32KHz timer provides less
          intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is
-         currently only available for OMAP16XX, 24XX and 34XX.
+         currently only available for OMAP16XX, 24XX, 34XX and OMAP4.
 
 endchoice
 
@@ -149,7 +154,7 @@ config OMAP_32K_TIMER_HZ
 
 config OMAP_DM_TIMER
        bool "Use dual-mode timer"
-       depends on ARCH_OMAP16XX || ARCH_OMAP24XX || ARCH_OMAP34XX
+       depends on ARCH_OMAP16XX || ARCH_OMAP24XX || ARCH_OMAP34XX || ARCH_OMAP4
        help
         Select this option if you want to use OMAP Dual-Mode timers.
 
@@ -171,7 +176,7 @@ endchoice
 
 config OMAP_SERIAL_WAKE
        bool "Enable wake-up events for serial ports"
-       depends on OMAP_MUX
+       depends on ARCH_OMAP1 && OMAP_MUX
        default y
        help
          Select this option if you want to have your system wake up
index 04a100cfb8e5fcfe67057938f7472114150c04b1..a83279523958a97231f2405b5af8b859ef58dfe9 100644 (file)
@@ -13,6 +13,7 @@ obj-  :=
 obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
 
 obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
+obj-$(CONFIG_OMAP_IOMMU) += iommu.o iovmm.o
 
 obj-$(CONFIG_CPU_FREQ) += cpu-omap.o
 obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o
index 29efc279287acb0dd286883d29707cb2ac4e2315..e8c327a45a55d120ce3df941703e22455676974c 100644 (file)
@@ -36,10 +36,40 @@ static struct clk_functions *arch_clock;
  * Standard clock functions defined in include/linux/clk.h
  *-------------------------------------------------------------------------*/
 
+/* This functions is moved to arch/arm/common/clkdev.c. For OMAP4 since
+ * clock framework is not up , it is defined here to avoid rework in
+ * every driver. Also dummy prcm reset function is added */
+
+/* Dummy hooks only for OMAP4.For rest OMAPs, common clkdev is used */
+#if defined(CONFIG_ARCH_OMAP4)
+struct clk *clk_get(struct device *dev, const char *id)
+{
+       return NULL;
+}
+EXPORT_SYMBOL(clk_get);
+
+void clk_put(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_put);
+
+void omap2_clk_prepare_for_reboot(void)
+{
+}
+EXPORT_SYMBOL(omap2_clk_prepare_for_reboot);
+
+void omap_prcm_arch_reset(char mode)
+{
+}
+EXPORT_SYMBOL(omap_prcm_arch_reset);
+#endif
 int clk_enable(struct clk *clk)
 {
        unsigned long flags;
        int ret = 0;
+       if (cpu_is_omap44xx())
+               /* OMAP4 clk framework not supported yet */
+               return 0;
 
        if (clk == NULL || IS_ERR(clk))
                return -EINVAL;
@@ -140,6 +170,9 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
        unsigned long flags;
        int ret = -EINVAL;
 
+       if (cpu_is_omap44xx())
+       /* OMAP4 clk framework not supported yet */
+               return 0;
        if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent))
                return ret;
 
@@ -240,13 +273,13 @@ void recalculate_root_clocks(void)
 }
 
 /**
- * clk_init_one - initialize any fields in the struct clk before clk init
+ * clk_preinit - initialize any fields in the struct clk before clk init
  * @clk: struct clk * to initialize
  *
  * Initialize any struct clk fields needed before normal clk initialization
  * can run.  No return value.
  */
-void clk_init_one(struct clk *clk)
+void clk_preinit(struct clk *clk)
 {
        INIT_LIST_HEAD(&clk->children);
 }
index 433021f3d7cc9a3bab39065fc2d229d7805881b9..ebcf006406f96568ecc809afd158f169bb6e5147 100644 (file)
@@ -2,6 +2,10 @@
  * linux/arch/arm/plat-omap/common.c
  *
  * Code common to all OMAP machines.
+ * The file is created by Tony Lindgren <tony@atomide.com>
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -11,7 +15,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
-#include <linux/pm.h>
 #include <linux/console.h>
 #include <linux/serial.h>
 #include <linux/tty.h>
@@ -175,25 +178,70 @@ console_initcall(omap_add_serial_console);
  * but systems won't necessarily want to spend resources that way.
  */
 
-#if defined(CONFIG_ARCH_OMAP16XX)
-#define TIMER_32K_SYNCHRONIZED         0xfffbc410
-#elif defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
-#define TIMER_32K_SYNCHRONIZED         (OMAP2_32KSYNCT_BASE + 0x10)
-#endif
+#define OMAP16XX_TIMER_32K_SYNCHRONIZED                0xfffbc410
 
-#ifdef TIMER_32K_SYNCHRONIZED
+#if !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX))
 
 #include <linux/clocksource.h>
 
-static cycle_t omap_32k_read(struct clocksource *cs)
+#ifdef CONFIG_ARCH_OMAP16XX
+static cycle_t omap16xx_32k_read(struct clocksource *cs)
+{
+       return omap_readl(OMAP16XX_TIMER_32K_SYNCHRONIZED);
+}
+#else
+#define omap16xx_32k_read      NULL
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2420
+static cycle_t omap2420_32k_read(struct clocksource *cs)
+{
+       return omap_readl(OMAP2420_32KSYNCT_BASE + 0x10);
+}
+#else
+#define omap2420_32k_read      NULL
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2430
+static cycle_t omap2430_32k_read(struct clocksource *cs)
+{
+       return omap_readl(OMAP2430_32KSYNCT_BASE + 0x10);
+}
+#else
+#define omap2430_32k_read      NULL
+#endif
+
+#ifdef CONFIG_ARCH_OMAP34XX
+static cycle_t omap34xx_32k_read(struct clocksource *cs)
+{
+       return omap_readl(OMAP3430_32KSYNCT_BASE + 0x10);
+}
+#else
+#define omap34xx_32k_read      NULL
+#endif
+
+#ifdef CONFIG_ARCH_OMAP4
+static cycle_t omap44xx_32k_read(struct clocksource *cs)
 {
-       return omap_readl(TIMER_32K_SYNCHRONIZED);
+       return omap_readl(OMAP4430_32KSYNCT_BASE + 0x10);
+}
+#else
+#define omap44xx_32k_read      NULL
+#endif
+
+/*
+ * Kernel assumes that sched_clock can be called early but may not have
+ * things ready yet.
+ */
+static cycle_t omap_32k_read_dummy(struct clocksource *cs)
+{
+       return 0;
 }
 
 static struct clocksource clocksource_32k = {
        .name           = "32k_counter",
        .rating         = 250,
-       .read           = omap_32k_read,
+       .read           = omap_32k_read_dummy,
        .mask           = CLOCKSOURCE_MASK(32),
        .shift          = 10,
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
@@ -207,7 +255,7 @@ unsigned long long sched_clock(void)
 {
        unsigned long long ret;
 
-       ret = (unsigned long long)omap_32k_read(&clocksource_32k);
+       ret = (unsigned long long)clocksource_32k.read(&clocksource_32k);
        ret = (ret * clocksource_32k.mult_orig) >> clocksource_32k.shift;
        return ret;
 }
@@ -220,6 +268,19 @@ static int __init omap_init_clocksource_32k(void)
        if (cpu_is_omap16xx() || cpu_class_is_omap2()) {
                struct clk *sync_32k_ick;
 
+               if (cpu_is_omap16xx())
+                       clocksource_32k.read = omap16xx_32k_read;
+               else if (cpu_is_omap2420())
+                       clocksource_32k.read = omap2420_32k_read;
+               else if (cpu_is_omap2430())
+                       clocksource_32k.read = omap2430_32k_read;
+               else if (cpu_is_omap34xx())
+                       clocksource_32k.read = omap34xx_32k_read;
+               else if (cpu_is_omap44xx())
+                       clocksource_32k.read = omap44xx_32k_read;
+               else
+                       return -ENODEV;
+
                sync_32k_ick = clk_get(NULL, "omap_32ksync_ick");
                if (sync_32k_ick)
                        clk_enable(sync_32k_ick);
@@ -234,15 +295,13 @@ static int __init omap_init_clocksource_32k(void)
 }
 arch_initcall(omap_init_clocksource_32k);
 
-#endif /* TIMER_32K_SYNCHRONIZED */
+#endif /* !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX)) */
 
 /* Global address base setup code */
 
 #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
 
-static struct omap_globals *omap2_globals;
-
-static void __init __omap2_set_globals(void)
+static void __init __omap2_set_globals(struct omap_globals *omap2_globals)
 {
        omap2_set_globals_tap(omap2_globals);
        omap2_set_globals_sdrc(omap2_globals);
@@ -266,8 +325,7 @@ static struct omap_globals omap242x_globals = {
 
 void __init omap2_set_globals_242x(void)
 {
-       omap2_globals = &omap242x_globals;
-       __omap2_set_globals();
+       __omap2_set_globals(&omap242x_globals);
 }
 #endif
 
@@ -285,8 +343,7 @@ static struct omap_globals omap243x_globals = {
 
 void __init omap2_set_globals_243x(void)
 {
-       omap2_globals = &omap243x_globals;
-       __omap2_set_globals();
+       __omap2_set_globals(&omap243x_globals);
 }
 #endif
 
@@ -304,8 +361,23 @@ static struct omap_globals omap343x_globals = {
 
 void __init omap2_set_globals_343x(void)
 {
-       omap2_globals = &omap343x_globals;
-       __omap2_set_globals();
+       __omap2_set_globals(&omap343x_globals);
+}
+#endif
+
+#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),
+};
+
+void __init omap2_set_globals_443x(void)
+{
+       omap2_set_globals_tap(&omap4_globals);
+       omap2_set_globals_control(&omap4_globals);
 }
 #endif
 
index 87fb7ff4179489728874278092b176b14886ac3c..a64b692a1bfeb0466892de5bf75b61769bbebd31 100644 (file)
@@ -311,6 +311,8 @@ static void omap_init_wdt(void)
                wdt_resources[0].start = 0x49016000; /* WDT2 */
        else if (cpu_is_omap343x())
                wdt_resources[0].start = 0x48314000; /* WDT2 */
+       else if (cpu_is_omap44xx())
+               wdt_resources[0].start = 0x4a314000;
        else
                return;
 
index 7fc8c045ad5d79de26dda4fbba92f6b9bf132abe..def14ec265b369f7929ea5bd841f4e97a6ac5b38 100644 (file)
@@ -10,6 +10,9 @@
  * Merged to support both OMAP1 and OMAP2 by Tony Lindgren <tony@atomide.com>
  * Some functions based on earlier dma-omap.c Copyright (C) 2001 RidgeRun, Inc.
  *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
  * Support functions for the OMAP internal DMA channels.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -310,41 +313,62 @@ EXPORT_SYMBOL(omap_set_dma_transfer_params);
 
 void omap_set_dma_color_mode(int lch, enum omap_dma_color_mode mode, u32 color)
 {
-       u16 w;
-
        BUG_ON(omap_dma_in_1510_mode());
 
-       if (cpu_class_is_omap2()) {
-               REVISIT_24XX();
-               return;
-       }
+       if (cpu_class_is_omap1()) {
+               u16 w;
 
-       w = dma_read(CCR2(lch));
-       w &= ~0x03;
+               w = dma_read(CCR2(lch));
+               w &= ~0x03;
 
-       switch (mode) {
-       case OMAP_DMA_CONSTANT_FILL:
-               w |= 0x01;
-               break;
-       case OMAP_DMA_TRANSPARENT_COPY:
-               w |= 0x02;
-               break;
-       case OMAP_DMA_COLOR_DIS:
-               break;
-       default:
-               BUG();
+               switch (mode) {
+               case OMAP_DMA_CONSTANT_FILL:
+                       w |= 0x01;
+                       break;
+               case OMAP_DMA_TRANSPARENT_COPY:
+                       w |= 0x02;
+                       break;
+               case OMAP_DMA_COLOR_DIS:
+                       break;
+               default:
+                       BUG();
+               }
+               dma_write(w, CCR2(lch));
+
+               w = dma_read(LCH_CTRL(lch));
+               w &= ~0x0f;
+               /* Default is channel type 2D */
+               if (mode) {
+                       dma_write((u16)color, COLOR_L(lch));
+                       dma_write((u16)(color >> 16), COLOR_U(lch));
+                       w |= 1;         /* Channel type G */
+               }
+               dma_write(w, LCH_CTRL(lch));
        }
-       dma_write(w, CCR2(lch));
 
-       w = dma_read(LCH_CTRL(lch));
-       w &= ~0x0f;
-       /* Default is channel type 2D */
-       if (mode) {
-               dma_write((u16)color, COLOR_L(lch));
-               dma_write((u16)(color >> 16), COLOR_U(lch));
-               w |= 1;         /* Channel type G */
+       if (cpu_class_is_omap2()) {
+               u32 val;
+
+               val = dma_read(CCR(lch));
+               val &= ~((1 << 17) | (1 << 16));
+
+               switch (mode) {
+               case OMAP_DMA_CONSTANT_FILL:
+                       val |= 1 << 16;
+                       break;
+               case OMAP_DMA_TRANSPARENT_COPY:
+                       val |= 1 << 17;
+                       break;
+               case OMAP_DMA_COLOR_DIS:
+                       break;
+               default:
+                       BUG();
+               }
+               dma_write(val, CCR(lch));
+
+               color &= 0xffffff;
+               dma_write(color, COLOR(lch));
        }
-       dma_write(w, LCH_CTRL(lch));
 }
 EXPORT_SYMBOL(omap_set_dma_color_mode);
 
@@ -851,7 +875,7 @@ omap_dma_set_prio_lch(int lch, unsigned char read_prio,
        }
        l = dma_read(CCR(lch));
        l &= ~((1 << 6) | (1 << 26));
-       if (cpu_is_omap2430() || cpu_is_omap34xx())
+       if (cpu_is_omap2430() || cpu_is_omap34xx() ||  cpu_is_omap44xx())
                l |= ((read_prio & 0x1) << 6) | ((write_prio & 0x1) << 26);
        else
                l |= ((read_prio & 0x1) << 6);
@@ -1199,7 +1223,7 @@ static void create_dma_lch_chain(int lch_head, int lch_queue)
  *          Failure: -EINVAL/-ENOMEM
  */
 int omap_request_dma_chain(int dev_id, const char *dev_name,
-                          void (*callback) (int chain_id, u16 ch_status,
+                          void (*callback) (int lch, u16 ch_status,
                                             void *data),
                           int *chain_id, int no_of_chans, int chain_mode,
                           struct omap_dma_channel_params params)
@@ -1823,7 +1847,8 @@ static irqreturn_t omap1_dma_irq_handler(int irq, void *dev_id)
 #define omap1_dma_irq_handler  NULL
 #endif
 
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \
+                       defined(CONFIG_ARCH_OMAP4)
 
 static int omap2_dma_handle_ch(int ch)
 {
@@ -2318,6 +2343,9 @@ static int __init omap_init_dma(void)
        } else if (cpu_is_omap34xx()) {
                omap_dma_base = IO_ADDRESS(OMAP34XX_DMA4_BASE);
                dma_lch_count = OMAP_DMA4_LOGICAL_DMA_CH_COUNT;
+       } else if (cpu_is_omap44xx()) {
+               omap_dma_base = IO_ADDRESS(OMAP44XX_DMA4_BASE);
+               dma_lch_count = OMAP_DMA4_LOGICAL_DMA_CH_COUNT;
        } else {
                pr_err("DMA init failed for unsupported omap\n");
                return -ENODEV;
@@ -2416,12 +2444,18 @@ static int __init omap_init_dma(void)
                }
        }
 
-       if (cpu_is_omap2430() || cpu_is_omap34xx())
+       if (cpu_is_omap2430() || cpu_is_omap34xx() || cpu_is_omap44xx())
                omap_dma_set_global_params(DMA_DEFAULT_ARB_RATE,
                                DMA_DEFAULT_FIFO_DEPTH, 0);
 
-       if (cpu_class_is_omap2())
-               setup_irq(INT_24XX_SDMA_IRQ0, &omap24xx_dma_irq);
+       if (cpu_class_is_omap2()) {
+               int irq;
+               if (cpu_is_omap44xx())
+                       irq = INT_44XX_SDMA_IRQ0;
+               else
+                       irq = INT_24XX_SDMA_IRQ0;
+               setup_irq(irq, &omap24xx_dma_irq);
+       }
 
        /* FIXME: Update LCD DMA to work on 24xx */
        if (cpu_class_is_omap1()) {
index 55bb9963129248cf96cd0ddcc3276c2772d10710..7f50b6103dee5ca0dcd5b85ff16bdc81932ee3fb 100644 (file)
@@ -7,6 +7,9 @@
  * OMAP2 support by Juha Yrjola
  * API improvements and OMAP2 clock framework support by Timo Teras
  *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
  * Free Software Foundation; either version 2 of the License, or (at your
 struct omap_dm_timer {
        unsigned long phys_base;
        int irq;
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \
+                       defined(CONFIG_ARCH_OMAP4)
        struct clk *iclk, *fclk;
 #endif
        void __iomem *io_base;
@@ -169,6 +173,9 @@ struct omap_dm_timer {
 #define omap3_dm_timers                        NULL
 #define omap3_dm_source_names          NULL
 #define omap3_dm_source_clocks         NULL
+#define omap4_dm_timers                        NULL
+#define omap4_dm_source_names          NULL
+#define omap4_dm_source_clocks         NULL
 
 static struct omap_dm_timer omap1_dm_timers[] = {
        { .phys_base = 0xfffb1400, .irq = INT_1610_GPTIMER1 },
@@ -191,6 +198,9 @@ static const int dm_timer_count = ARRAY_SIZE(omap1_dm_timers);
 #define omap3_dm_timers                        NULL
 #define omap3_dm_source_names          NULL
 #define omap3_dm_source_clocks         NULL
+#define omap4_dm_timers                        NULL
+#define omap4_dm_source_names          NULL
+#define omap4_dm_source_clocks         NULL
 
 static struct omap_dm_timer omap2_dm_timers[] = {
        { .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 },
@@ -214,7 +224,7 @@ static const char *omap2_dm_source_names[] __initdata = {
        NULL
 };
 
-static struct clk **omap2_dm_source_clocks[3];
+static struct clk *omap2_dm_source_clocks[3];
 static const int dm_timer_count = ARRAY_SIZE(omap2_dm_timers);
 
 #elif defined(CONFIG_ARCH_OMAP3)
@@ -225,6 +235,9 @@ static const int dm_timer_count = ARRAY_SIZE(omap2_dm_timers);
 #define omap2_dm_timers                        NULL
 #define omap2_dm_source_names          NULL
 #define omap2_dm_source_clocks         NULL
+#define omap4_dm_timers                        NULL
+#define omap4_dm_source_names          NULL
+#define omap4_dm_source_clocks         NULL
 
 static struct omap_dm_timer omap3_dm_timers[] = {
        { .phys_base = 0x48318000, .irq = INT_24XX_GPTIMER1 },
@@ -247,9 +260,43 @@ static const char *omap3_dm_source_names[] __initdata = {
        NULL
 };
 
-static struct clk **omap3_dm_source_clocks[2];
+static struct clk *omap3_dm_source_clocks[2];
 static const int dm_timer_count = ARRAY_SIZE(omap3_dm_timers);
 
+#elif defined(CONFIG_ARCH_OMAP4)
+
+#define omap_dm_clk_enable(x)          clk_enable(x)
+#define omap_dm_clk_disable(x)         clk_disable(x)
+#define omap1_dm_timers                        NULL
+#define omap2_dm_timers                        NULL
+#define omap2_dm_source_names          NULL
+#define omap2_dm_source_clocks         NULL
+#define omap3_dm_timers                        NULL
+#define omap3_dm_source_names          NULL
+#define omap3_dm_source_clocks         NULL
+
+static struct omap_dm_timer omap4_dm_timers[] = {
+       { .phys_base = 0x4a318000, .irq = INT_44XX_GPTIMER1 },
+       { .phys_base = 0x48032000, .irq = INT_44XX_GPTIMER2 },
+       { .phys_base = 0x48034000, .irq = INT_44XX_GPTIMER3 },
+       { .phys_base = 0x48036000, .irq = INT_44XX_GPTIMER4 },
+       { .phys_base = 0x40138000, .irq = INT_44XX_GPTIMER5 },
+       { .phys_base = 0x4013a000, .irq = INT_44XX_GPTIMER6 },
+       { .phys_base = 0x4013a000, .irq = INT_44XX_GPTIMER7 },
+       { .phys_base = 0x4013e000, .irq = INT_44XX_GPTIMER8 },
+       { .phys_base = 0x4803e000, .irq = INT_44XX_GPTIMER9 },
+       { .phys_base = 0x48086000, .irq = INT_44XX_GPTIMER10 },
+       { .phys_base = 0x48088000, .irq = INT_44XX_GPTIMER11 },
+       { .phys_base = 0x4a320000, .irq = INT_44XX_GPTIMER12 },
+};
+static const char *omap4_dm_source_names[] __initdata = {
+       "sys_ck",
+       "omap_32k_fck",
+       NULL
+};
+static struct clk *omap4_dm_source_clocks[2];
+static const int dm_timer_count = ARRAY_SIZE(omap4_dm_timers);
+
 #else
 
 #error OMAP architecture not supported!
@@ -257,7 +304,7 @@ static const int dm_timer_count = ARRAY_SIZE(omap3_dm_timers);
 #endif
 
 static struct omap_dm_timer *dm_timers;
-static char **dm_source_names;
+static const char **dm_source_names;
 static struct clk **dm_source_clocks;
 
 static spinlock_t dm_timer_lock;
@@ -459,7 +506,8 @@ __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
 
-#elif defined(CONFIG_ARCH_OMAP2) || defined (CONFIG_ARCH_OMAP3)
+#elif defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \
+                               defined(CONFIG_ARCH_OMAP4)
 
 struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
 {
@@ -705,12 +753,16 @@ int __init omap_dm_timer_init(void)
                dm_timers = omap1_dm_timers;
        else if (cpu_is_omap24xx()) {
                dm_timers = omap2_dm_timers;
-               dm_source_names = (char **)omap2_dm_source_names;
-               dm_source_clocks = (struct clk **)omap2_dm_source_clocks;
+               dm_source_names = omap2_dm_source_names;
+               dm_source_clocks = omap2_dm_source_clocks;
        } else if (cpu_is_omap34xx()) {
                dm_timers = omap3_dm_timers;
-               dm_source_names = (char **)omap3_dm_source_names;
-               dm_source_clocks = (struct clk **)omap3_dm_source_clocks;
+               dm_source_names = omap3_dm_source_names;
+               dm_source_clocks = omap3_dm_source_clocks;
+       } else if (cpu_is_omap44xx()) {
+               dm_timers = omap4_dm_timers;
+               dm_source_names = omap4_dm_source_names;
+               dm_source_clocks = omap4_dm_source_clocks;
        }
 
        if (cpu_class_is_omap2())
@@ -723,7 +775,8 @@ int __init omap_dm_timer_init(void)
        for (i = 0; i < dm_timer_count; i++) {
                timer = &dm_timers[i];
                timer->io_base = IO_ADDRESS(timer->phys_base);
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \
+                                       defined(CONFIG_ARCH_OMAP4)
                if (cpu_class_is_omap2()) {
                        char clk_name[16];
                        sprintf(clk_name, "gpt%d_ick", i + 1);
index ee0b21f5b094f64e70e95caffb7eda66b6c8d930..7fd89ba8d3b5939684ab6999a12fc19c5430b31e 100644 (file)
@@ -6,6 +6,9 @@
  * Copyright (C) 2003-2005 Nokia Corporation
  * Written by Juha Yrjölä <juha.yrjola@nokia.com>
  *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
 #define OMAP34XX_GPIO5_BASE            IO_ADDRESS(0x49056000)
 #define OMAP34XX_GPIO6_BASE            IO_ADDRESS(0x49058000)
 
+/*
+ * OMAP44XX  specific GPIO registers
+ */
+#define OMAP44XX_GPIO1_BASE             IO_ADDRESS(0x4a310000)
+#define OMAP44XX_GPIO2_BASE             IO_ADDRESS(0x48055000)
+#define OMAP44XX_GPIO3_BASE             IO_ADDRESS(0x48057000)
+#define OMAP44XX_GPIO4_BASE             IO_ADDRESS(0x48059000)
+#define OMAP44XX_GPIO5_BASE             IO_ADDRESS(0x4805B000)
+#define OMAP44XX_GPIO6_BASE             IO_ADDRESS(0x4805D000)
+
 #define OMAP_MPUIO_VBASE               IO_ADDRESS(OMAP_MPUIO_BASE)
 
 struct gpio_bank {
@@ -153,11 +166,13 @@ struct gpio_bank {
        u16 irq;
        u16 virtual_irq_start;
        int method;
-#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX) ||  \
+               defined(CONFIG_ARCH_OMAP34XX) || defined(CONFIG_ARCH_OMAP4)
        u32 suspend_wakeup;
        u32 saved_wakeup;
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+                       defined(CONFIG_ARCH_OMAP4)
        u32 non_wakeup_gpios;
        u32 enabled_non_wakeup_gpios;
 
@@ -251,6 +266,24 @@ static struct gpio_bank gpio_bank_34xx[6] = {
 
 #endif
 
+#ifdef CONFIG_ARCH_OMAP4
+static struct gpio_bank gpio_bank_44xx[6] = {
+       { OMAP44XX_GPIO1_BASE, INT_44XX_GPIO_BANK1, IH_GPIO_BASE,       \
+               METHOD_GPIO_24XX },
+       { OMAP44XX_GPIO2_BASE, INT_44XX_GPIO_BANK2, IH_GPIO_BASE + 32,  \
+               METHOD_GPIO_24XX },
+       { OMAP44XX_GPIO3_BASE, INT_44XX_GPIO_BANK3, IH_GPIO_BASE + 64,  \
+               METHOD_GPIO_24XX },
+       { OMAP44XX_GPIO4_BASE, INT_44XX_GPIO_BANK4, IH_GPIO_BASE + 96,  \
+               METHOD_GPIO_24XX },
+       { OMAP44XX_GPIO5_BASE, INT_44XX_GPIO_BANK5, IH_GPIO_BASE + 128, \
+               METHOD_GPIO_24XX },
+       { OMAP44XX_GPIO6_BASE, INT_44XX_GPIO_BANK6, IH_GPIO_BASE + 160, \
+               METHOD_GPIO_24XX },
+};
+
+#endif
+
 static struct gpio_bank *gpio_bank;
 static int gpio_bank_count;
 
@@ -273,7 +306,7 @@ static inline struct gpio_bank *get_gpio_bank(int gpio)
        }
        if (cpu_is_omap24xx())
                return &gpio_bank[gpio >> 5];
-       if (cpu_is_omap34xx())
+       if (cpu_is_omap34xx() || cpu_is_omap44xx())
                return &gpio_bank[gpio >> 5];
        BUG();
        return NULL;
@@ -285,7 +318,7 @@ static inline int get_gpio_index(int gpio)
                return gpio & 0x1f;
        if (cpu_is_omap24xx())
                return gpio & 0x1f;
-       if (cpu_is_omap34xx())
+       if (cpu_is_omap34xx() || cpu_is_omap44xx())
                return gpio & 0x1f;
        return gpio & 0x0f;
 }
@@ -307,7 +340,7 @@ static inline int gpio_valid(int gpio)
                return 0;
        if (cpu_is_omap24xx() && gpio < 128)
                return 0;
-       if (cpu_is_omap34xx() && gpio < 192)
+       if ((cpu_is_omap34xx() || cpu_is_omap44xx()) && gpio < 192)
                return 0;
        return -1;
 }
@@ -353,7 +386,8 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
                reg += OMAP850_GPIO_DIR_CONTROL;
                break;
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+                       defined(CONFIG_ARCH_OMAP4)
        case METHOD_GPIO_24XX:
                reg += OMAP24XX_GPIO_OE;
                break;
@@ -425,7 +459,8 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable)
                        l &= ~(1 << gpio);
                break;
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+                       defined(CONFIG_ARCH_OMAP4)
        case METHOD_GPIO_24XX:
                if (enable)
                        reg += OMAP24XX_GPIO_SETDATAOUT;
@@ -476,7 +511,8 @@ static int __omap_get_gpio_datain(int gpio)
                reg += OMAP850_GPIO_DATA_INPUT;
                break;
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+                       defined(CONFIG_ARCH_OMAP4)
        case METHOD_GPIO_24XX:
                reg += OMAP24XX_GPIO_DATAIN;
                break;
@@ -520,7 +556,7 @@ void omap_set_gpio_debounce(int gpio, int enable)
        else
                goto done;
 
-       if (cpu_is_omap34xx()) {
+       if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
                if (enable)
                        clk_enable(bank->dbck);
                else
@@ -550,7 +586,8 @@ void omap_set_gpio_debounce_time(int gpio, int enc_time)
 }
 EXPORT_SYMBOL(omap_set_gpio_debounce_time);
 
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+                               defined(CONFIG_ARCH_OMAP4)
 static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio,
                                                int trigger)
 {
@@ -660,7 +697,8 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
                        goto bad;
                break;
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+                               defined(CONFIG_ARCH_OMAP4)
        case METHOD_GPIO_24XX:
                set_24xx_gpio_triggering(bank, gpio, trigger);
                break;
@@ -745,7 +783,8 @@ static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
                reg += OMAP850_GPIO_INT_STATUS;
                break;
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+                               defined(CONFIG_ARCH_OMAP4)
        case METHOD_GPIO_24XX:
                reg += OMAP24XX_GPIO_IRQSTATUS1;
                break;
@@ -814,7 +853,8 @@ static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank)
                inv = 1;
                break;
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+                               defined(CONFIG_ARCH_OMAP4)
        case METHOD_GPIO_24XX:
                reg += OMAP24XX_GPIO_IRQENABLE1;
                mask = 0xffffffff;
@@ -887,7 +927,8 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab
                        l |= gpio_mask;
                break;
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+               defined(CONFIG_ARCH_OMAP4)
        case METHOD_GPIO_24XX:
                if (enable)
                        reg += OMAP24XX_GPIO_SETIRQENABLE1;
@@ -932,7 +973,8 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
                spin_unlock_irqrestore(&bank->lock, flags);
                return 0;
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+                               defined(CONFIG_ARCH_OMAP4)
        case METHOD_GPIO_24XX:
                if (bank->non_wakeup_gpios & (1 << gpio)) {
                        printk(KERN_ERR "Unable to modify wakeup on "
@@ -1017,7 +1059,8 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
                __raw_writel(1 << offset, reg);
        }
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+                               defined(CONFIG_ARCH_OMAP4)
        if (bank->method == METHOD_GPIO_24XX) {
                /* Disable wake-up during idle for dynamic tick */
                void __iomem *reg = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
@@ -1069,7 +1112,8 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
        if (bank->method == METHOD_GPIO_850)
                isr_reg = bank->base + OMAP850_GPIO_INT_STATUS;
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+                               defined(CONFIG_ARCH_OMAP4)
        if (bank->method == METHOD_GPIO_24XX)
                isr_reg = bank->base + OMAP24XX_GPIO_IRQSTATUS1;
 #endif
@@ -1346,7 +1390,7 @@ static int gpio_2irq(struct gpio_chip *chip, unsigned offset)
 /*---------------------------------------------------------------------*/
 
 static int initialized;
-#if !defined(CONFIG_ARCH_OMAP3)
+#if !(defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4))
 static struct clk * gpio_ick;
 #endif
 
@@ -1359,7 +1403,7 @@ static struct clk * gpio5_ick;
 static struct clk * gpio5_fck;
 #endif
 
-#if defined(CONFIG_ARCH_OMAP3)
+#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
 static struct clk *gpio_iclks[OMAP34XX_NR_GPIOS];
 #endif
 
@@ -1419,8 +1463,8 @@ static int __init _omap_gpio_init(void)
        }
 #endif
 
-#if defined(CONFIG_ARCH_OMAP3)
-       if (cpu_is_omap34xx()) {
+#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
+       if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
                for (i = 0; i < OMAP34XX_NR_GPIOS; i++) {
                        sprintf(clk_name, "gpio%d_ick", i + 1);
                        gpio_iclks[i] = clk_get(NULL, clk_name);
@@ -1496,6 +1540,17 @@ static int __init _omap_gpio_init(void)
                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 + OMAP24XX_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++) {
                int j, gpio_count = 16;
@@ -1520,7 +1575,8 @@ static int __init _omap_gpio_init(void)
                        gpio_count = 32; /* 730 has 32-bit GPIOs */
                }
 
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+                               defined(CONFIG_ARCH_OMAP4)
                if (bank->method == METHOD_GPIO_24XX) {
                        static const u32 non_wakeup_gpios[] = {
                                0xe203ffc0, 0x08700040
@@ -1577,7 +1633,7 @@ static int __init _omap_gpio_init(void)
                set_irq_chained_handler(bank->irq, gpio_irq_handler);
                set_irq_data(bank->irq, bank);
 
-               if (cpu_is_omap34xx()) {
+               if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
                        sprintf(clk_name, "gpio%d_dbck", i + 1);
                        bank->dbck = clk_get(NULL, clk_name);
                        if (IS_ERR(bank->dbck))
@@ -1599,7 +1655,8 @@ static int __init _omap_gpio_init(void)
        return 0;
 }
 
-#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX) || \
+               defined(CONFIG_ARCH_OMAP34XX) || defined(CONFIG_ARCH_OMAP4)
 static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg)
 {
        int i;
@@ -1622,7 +1679,8 @@ static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg)
                        wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
                        break;
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+                               defined(CONFIG_ARCH_OMAP4)
                case METHOD_GPIO_24XX:
                        wake_status = bank->base + OMAP24XX_GPIO_WAKE_EN;
                        wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
@@ -1663,7 +1721,8 @@ static int omap_gpio_resume(struct sys_device *dev)
                        wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
                        break;
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+                       defined(CONFIG_ARCH_OMAP4)
                case METHOD_GPIO_24XX:
                        wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
                        wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA;
@@ -1695,7 +1754,8 @@ static struct sys_device omap_gpio_device = {
 
 #endif
 
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+                               defined(CONFIG_ARCH_OMAP4)
 
 static int workaround_enabled;
 
@@ -1711,7 +1771,8 @@ void omap2_gpio_prepare_for_retention(void)
 
                if (!(bank->enabled_non_wakeup_gpios))
                        continue;
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+                               defined(CONFIG_ARCH_OMAP4)
                bank->saved_datain = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN);
                l1 = __raw_readl(bank->base + OMAP24XX_GPIO_FALLINGDETECT);
                l2 = __raw_readl(bank->base + OMAP24XX_GPIO_RISINGDETECT);
@@ -1720,7 +1781,8 @@ void omap2_gpio_prepare_for_retention(void)
                bank->saved_risingdetect = l2;
                l1 &= ~bank->enabled_non_wakeup_gpios;
                l2 &= ~bank->enabled_non_wakeup_gpios;
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+                       defined(CONFIG_ARCH_OMAP4)
                __raw_writel(l1, bank->base + OMAP24XX_GPIO_FALLINGDETECT);
                __raw_writel(l2, bank->base + OMAP24XX_GPIO_RISINGDETECT);
 #endif
@@ -1745,7 +1807,8 @@ void omap2_gpio_resume_after_retention(void)
 
                if (!(bank->enabled_non_wakeup_gpios))
                        continue;
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+                       defined(CONFIG_ARCH_OMAP4)
                __raw_writel(bank->saved_fallingdetect,
                                 bank->base + OMAP24XX_GPIO_FALLINGDETECT);
                __raw_writel(bank->saved_risingdetect,
@@ -1755,14 +1818,16 @@ void omap2_gpio_resume_after_retention(void)
                 * state.  If so, generate an IRQ by software.  This is
                 * horribly racy, but it's the best we can do to work around
                 * this silicon bug. */
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+                       defined(CONFIG_ARCH_OMAP4)
                l = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN);
 #endif
                l ^= bank->saved_datain;
                l &= bank->non_wakeup_gpios;
                if (l) {
                        u32 old0, old1;
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+                       defined(CONFIG_ARCH_OMAP4)
                        old0 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0);
                        old1 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1);
                        __raw_writel(old0 | l, bank->base + OMAP24XX_GPIO_LEVELDETECT0);
@@ -1798,7 +1863,8 @@ static int __init omap_gpio_sysinit(void)
 
        mpuio_init();
 
-#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX) || \
+               defined(CONFIG_ARCH_OMAP34XX) || defined(CONFIG_ARCH_OMAP4)
        if (cpu_is_omap16xx() || cpu_class_is_omap2()) {
                if (ret == 0) {
                        ret = sysdev_class_register(&omap_gpio_sysclass);
@@ -1887,7 +1953,7 @@ static int dbg_gpio_show(struct seq_file *s, void *unused)
 
                        irqstat = irq_desc[irq].status;
 #if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX) ||  \
-               defined(CONFIG_ARCH_OMAP34XX)
+               defined(CONFIG_ARCH_OMAP34XX) || defined(CONFIG_ARCH_OMAP4)
                        if (is_in && ((bank->suspend_wakeup & mask)
                                        || irqstat & IRQ_TYPE_SENSE_MASK)) {
                                char    *trigger = NULL;
index a303071d5e36bb7459aef8a59c0923efdb824e77..8b848391f0c8b7939d8a22b929a0710831cd95a3 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 2007 Nokia Corporation.
  *
- * Contact: Jarkko Nikula <jarkko.nikula@nokia.com>
+ * Contact: Jarkko Nikula <jhnikula@gmail.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 073a2c5569f02c16969d95ce72451fa072692055..f9f65e1ba3f13abe11d7c06d514b6581e6697016 100644 (file)
@@ -22,7 +22,8 @@ struct clkops {
        void                    (*disable)(struct clk *);
 };
 
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \
+               defined(CONFIG_ARCH_OMAP4)
 
 struct clksel_rate {
        u32                     val;
@@ -51,7 +52,7 @@ struct dpll_data {
        u8                      max_divider;
        u32                     max_tolerance;
        u16                     max_multiplier;
-#  if defined(CONFIG_ARCH_OMAP3)
+#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
        u8                      modes;
        void __iomem            *autoidle_reg;
        void __iomem            *idlest_reg;
@@ -83,7 +84,8 @@ struct clk {
        void                    (*init)(struct clk *);
        __u8                    enable_bit;
        __s8                    usecount;
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \
+               defined(CONFIG_ARCH_OMAP4)
        u8                      fixed_div;
        void __iomem            *clksel_reg;
        u32                     clksel_mask;
@@ -119,7 +121,7 @@ struct clk_functions {
 extern unsigned int mpurate;
 
 extern int clk_init(struct clk_functions *custom_clocks);
-extern void clk_init_one(struct clk *clk);
+extern void clk_preinit(struct clk *clk);
 extern int clk_register(struct clk *clk);
 extern void clk_reparent(struct clk *child, struct clk *parent);
 extern void clk_unregister(struct clk *clk);
index 0ecf36deb17b36e1477e2aa7b04139ae09a0f1ad..fdeab421b4dcd9c787925d3ede2251ac99a98abc 100644 (file)
@@ -33,8 +33,6 @@ struct sys_timer;
 
 extern void omap_map_common_io(void);
 extern struct sys_timer omap_timer;
-extern void omap_serial_init(void);
-extern void omap_serial_enable_clocks(int enable);
 #if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
 extern int omap_register_i2c_bus(int bus_id, u32 clkrate,
                                 struct i2c_board_info const *info,
@@ -62,6 +60,7 @@ struct omap_globals {
 void omap2_set_globals_242x(void);
 void omap2_set_globals_243x(void);
 void omap2_set_globals_343x(void);
+void omap2_set_globals_443x(void);
 
 /* These get called from omap2_set_globals_xxxx(), do not call these */
 void omap2_set_globals_tap(struct omap_globals *);
index 269147f3836f50985809c3ab5b9a3f81a944e2f4..8140dbccb7bc64f3dda2716ebda424666481ecc0 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * arch/arm/plat-omap/include/mach/control.h
  *
- * OMAP2/3 System Control Module definitions
+ * OMAP2/3/4 System Control Module definitions
  *
- * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ * Copyright (C) 2007-2009 Texas Instruments, Inc.
  * Copyright (C) 2007-2008 Nokia Corporation
  *
  * Written by Paul Walmsley
 #define OMAP343X_CONTROL_PBIAS_LITE    (OMAP2_CONTROL_GENERAL + 0x02b0)
 #define OMAP343X_CONTROL_TEMP_SENSOR   (OMAP2_CONTROL_GENERAL + 0x02b4)
 
+/* 34xx D2D idle-related pins, handled by PM core */
+#define OMAP3_PADCONF_SAD2D_MSTANDBY   0x250
+#define OMAP3_PADCONF_SAD2D_IDLEACK    0x254
+
 /*
  * REVISIT: This list of registers is not comprehensive - there are more
  * that should be added.
 #define OMAP2_PBIASLITEPWRDNZ0         (1 << 1)
 #define OMAP2_PBIASLITEVMODE0          (1 << 0)
 
+/* CONTROL_IVA2_BOOTMOD bits */
+#define OMAP3_IVA2_BOOTMOD_SHIFT       0
+#define OMAP3_IVA2_BOOTMOD_MASK                (0xf << 0)
+#define OMAP3_IVA2_BOOTMOD_IDLE                (0x1 << 0)
+
+/* CONTROL_PADCONF_X bits */
+#define OMAP3_PADCONF_WAKEUPEVENT0     (1 << 15)
+#define OMAP3_PADCONF_WAKEUPENABLE0    (1 << 14)
+
 #ifndef __ASSEMBLY__
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \
+               defined(CONFIG_ARCH_OMAP4)
 extern void __iomem *omap_ctrl_base_get(void);
 extern u8 omap_ctrl_readb(u16 offset);
 extern u16 omap_ctrl_readw(u16 offset);
index 98b1442523649f6998d4686039e6467c7866ad34..fc60c4ebcc28af1d0d1fa80d583b7f35cf00feaf 100644 (file)
@@ -5,8 +5,12 @@
  *
  * Copyright (C) 2004, 2008 Nokia Corporation
  *
+ * Copyright (C) 2009 Texas Instruments.
+ *
  * Written by Tony Lindgren <tony.lindgren@nokia.com>
  *
+ * Added OMAP4 specific defines - Santosh Shilimkar<santosh.shilimkar@ti.com>
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -155,6 +159,8 @@ IS_OMAP_SUBCLASS(343x, 0x343)
 #define cpu_is_omap243x()              0
 #define cpu_is_omap34xx()              0
 #define cpu_is_omap343x()              0
+#define cpu_is_omap44xx()              0
+#define cpu_is_omap443x()              0
 
 #if defined(MULTI_OMAP1)
 # if defined(CONFIG_ARCH_OMAP730)
@@ -348,12 +354,21 @@ IS_OMAP_TYPE(3430, 0x3430)
 # define cpu_is_omap3430()             is_omap3430()
 #endif
 
+# if defined(CONFIG_ARCH_OMAP4)
+# undef cpu_is_omap44xx
+# undef cpu_is_omap443x
+# define cpu_is_omap44xx()             1
+# define cpu_is_omap443x()             1
+# endif
+
 /* Macros to detect if we have OMAP1 or OMAP2 */
 #define cpu_class_is_omap1()   (cpu_is_omap7xx() || cpu_is_omap15xx() || \
                                cpu_is_omap16xx())
-#define cpu_class_is_omap2()   (cpu_is_omap24xx() || cpu_is_omap34xx())
+#define cpu_class_is_omap2()   (cpu_is_omap24xx() || cpu_is_omap34xx() || \
+                               cpu_is_omap44xx())
 
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \
+                       defined(CONFIG_ARCH_OMAP4)
 
 /* Various silicon revisions for omap2 */
 #define OMAP242X_CLASS         0x24200024
@@ -370,6 +385,8 @@ IS_OMAP_TYPE(3430, 0x3430)
 #define OMAP3430_REV_ES3_0     0x34303034
 #define OMAP3430_REV_ES3_1     0x34304034
 
+#define OMAP443X_CLASS         0x44300034
+
 /*
  * omap_chip bits
  *
index 1b11f5c6a2d9769d4acdc543a5fba4bd1a03636d..ac24050e3416cf90670839db233f4fda566f1b00 100644 (file)
@@ -36,7 +36,7 @@
                add     \rx, \rx, #0x00004000   @ UART 3
 #endif
 
-#elif  CONFIG_ARCH_OMAP3
+#elif defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
                moveq   \rx, #0x48000000        @ physical base address
                movne   \rx, #0xd8000000        @ virtual base
                orr     \rx, \rx, #0x0006a000
index 54fe9665b1826f674b761685d443f54c48567864..8c1eae88737e9e6a0ca24d85a5b51c63050c156a 100644 (file)
@@ -48,6 +48,7 @@
 /* Hardware registers for omap2 and omap3 */
 #define OMAP24XX_DMA4_BASE             (L4_24XX_BASE + 0x56000)
 #define OMAP34XX_DMA4_BASE             (L4_34XX_BASE + 0x56000)
+#define OMAP44XX_DMA4_BASE             (L4_44XX_BASE + 0x56000)
 
 #define OMAP_DMA4_REVISION             0x00
 #define OMAP_DMA4_GCR                  0x78
 #define OMAP_DMA4_CSSA_U(n)            0
 #define OMAP_DMA4_CDSA_L(n)            0
 #define OMAP_DMA4_CDSA_U(n)            0
+#define OMAP1_DMA_COLOR(n)             0
 
 /*----------------------------------------------------------------------------*/
 
@@ -531,7 +533,7 @@ extern int omap_get_dma_index(int lch, int *ei, int *fi);
 /* Chaining APIs */
 #ifndef CONFIG_ARCH_OMAP1
 extern int omap_request_dma_chain(int dev_id, const char *dev_name,
-                                 void (*callback) (int chain_id, u16 ch_status,
+                                 void (*callback) (int lch, u16 ch_status,
                                                    void *data),
                                  int *chain_id, int no_of_chans,
                                  int chain_mode,
index 2276f89671d83dafbce62954f58e41e8b3721fe4..56426ed45ef4800b862199b7ab4869710ddac7c3 100644 (file)
@@ -3,6 +3,9 @@
  *
  * Low-level IRQ helper macros for OMAP-based platforms
  *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
  * This file is licensed under  the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
  * warranty of any kind, whether express or implied.
@@ -10,6 +13,7 @@
 #include <mach/hardware.h>
 #include <mach/io.h>
 #include <mach/irqs.h>
+#include <asm/hardware/gic.h>
 
 #if defined(CONFIG_ARCH_OMAP1)
 
                .endm
 
 #endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+                       defined(CONFIG_ARCH_OMAP4)
 
-#if defined(CONFIG_ARCH_OMAP24XX)
 #include <mach/omap24xx.h>
-#endif
-#if defined(CONFIG_ARCH_OMAP34XX)
 #include <mach/omap34xx.h>
-#endif
 
+/* 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               IO_ADDRESS(OMAP24XX_IC_BASE)
+#elif defined(CONFIG_ARCH_OMAP34XX)
+#define OMAP2_VA_IC_BASE               IO_ADDRESS(OMAP34XX_IC_BASE)
+#endif
+#if defined(CONFIG_ARCH_OMAP4)
+#include <mach/omap44xx.h>
+#endif
 #define INTCPS_SIR_IRQ_OFFSET  0x0040          /* Active interrupt offset */
 #define        ACTIVEIRQ_MASK          0x7f            /* Active interrupt bits */
 
@@ -77,6 +87,7 @@
                .macro  arch_ret_to_user, tmp1, tmp2
                .endm
 
+#ifndef CONFIG_ARCH_OMAP4
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
                ldr     \base, =OMAP2_VA_IC_BASE
                ldr     \irqnr, [\base, #0x98] /* IRQ pending reg 1 */
                and     \irqnr, \irqnr, #ACTIVEIRQ_MASK /* Clear spurious bits */
 
                .endm
+#else
+               /*
+                * 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
+               ldr     \base, =OMAP44XX_VA_GIC_CPU_BASE
+               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
+               it      cc
+               strcc   \irqstat, [\base, #GIC_CPU_EOI]
+               it      cs
+               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
+               itt     eq
+               moveq   \tmp, #1
+               streq   \irqstat, [\base, #GIC_CPU_EOI]
+               cmp     \tmp, #0
+               .endm
+#endif
 
                .macro  irq_prio_table
                .endm
diff --git a/arch/arm/plat-omap/include/mach/gpmc-smc91x.h b/arch/arm/plat-omap/include/mach/gpmc-smc91x.h
new file mode 100644 (file)
index 0000000..b64fbee
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * arch/arm/plat-omap/include/mach/gpmc-smc91x.h
+ *
+ * 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 __ASM_ARCH_OMAP_GPMC_SMC91X_H__
+
+#define GPMC_TIMINGS_SMC91C96  (1 << 4)
+#define GPMC_MUX_ADD_DATA      (1 << 5) /* GPMC_CONFIG1_MUXADDDATA */
+#define GPMC_READ_MON          (1 << 6) /* GPMC_CONFIG1_WAIT_READ_MON */
+#define GPMC_WRITE_MON         (1 << 7) /* GPMC_CONFIG1_WAIT_WRITE_MON */
+
+struct omap_smc91x_platform_data {
+       int     cs;
+       int     gpio_irq;
+       int     gpio_pwrdwn;
+       int     gpio_reset;
+       int     wait_pin;       /* Optional GPMC_CONFIG1_WAITPINSELECT */
+       u32     flags;
+       int     (*retime)(void);
+};
+
+#if defined(CONFIG_SMC91X) || \
+       defined(CONFIG_SMC91X_MODULE)
+
+extern void gpmc_smc91x_init(struct omap_smc91x_platform_data *d);
+
+#else
+
+#define board_smc91x_data      NULL
+
+static inline void gpmc_smc91x_init(struct omap_smc91x_platform_data *d)
+{
+}
+
+#endif
+#endif
index 3dc423ed3e802d355fd964f5ce6e2076587b6d6a..26c1fbff08aaa544880e4eb9caaee3464b78c62f 100644 (file)
 #include "omap16xx.h"
 #include "omap24xx.h"
 #include "omap34xx.h"
+#include "omap44xx.h"
 
 #endif /* __ASM_ARCH_OMAP_HARDWARE_H */
index 577f492f2d3c713a7228aa6f260e66a483743835..886248d32b499c6594605061e8a352ba4191f8db 100644 (file)
@@ -2,10 +2,6 @@
 #define _HWA742_H
 
 struct hwa742_platform_data {
-       void            (*power_up)(struct device *dev);
-       void            (*power_down)(struct device *dev);
-       unsigned long   (*get_clock_rate)(struct device *dev);
-
        unsigned        te_connected:1;
 };
 
index 0610d7e2b3d736cb5a0bc37a18b416162005055f..3b28147205691a05df715d71a31d5e33fef858eb 100644 (file)
@@ -6,6 +6,9 @@
  * Copied from arch/arm/mach-sa1100/include/mach/io.h
  * Copyright (C) 1997-1999 Russell King
  *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
  * Free Software Foundation; either version 2 of the License, or (at your
 #define DSP_MMU_34XX_VIRT      0xe2000000
 #define DSP_MMU_34XX_SIZE      SZ_4K
 
+
+#elif defined(CONFIG_ARCH_OMAP4)
+/* We map both L3 and L4 on OMAP4 */
+#define L3_44XX_PHYS           L3_44XX_BASE
+#define L3_44XX_VIRT           0xd4000000
+#define L3_44XX_SIZE           SZ_1M
+
+#define L4_44XX_PHYS           L4_44XX_BASE
+#define L4_44XX_VIRT           0xda000000
+#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_SIZE                SZ_1M
+
+#define L4_PER_44XX_PHYS       L4_PER_44XX_BASE
+#define L4_PER_44XX_VIRT       0xd8000000
+#define L4_PER_44XX_SIZE       SZ_4M
+
+#define L4_EMU_44XX_PHYS       L4_EMU_44XX_BASE
+#define L4_EMU_44XX_VIRT       0xe4000000
+#define L4_EMU_44XX_SIZE       SZ_64M
+
+#define OMAP44XX_GPMC_PHYS     OMAP44XX_GPMC_BASE
+#define OMAP44XX_GPMC_VIRT     0xe0000000
+#define OMAP44XX_GPMC_SIZE     SZ_1M
+
+
+#define IO_OFFSET              0x90000000
+#define __IO_ADDRESS(pa)       ((pa) + IO_OFFSET)/* Works for L3 and L4 */
+#define __OMAP2_IO_ADDRESS(pa) ((pa) + IO_OFFSET)/* Works for L3 and L4 */
+#define io_v2p(va)             ((va) - IO_OFFSET)/* Works for L3 and L4 */
+
 #endif
 
 #define IO_ADDRESS(pa)         IOMEM(__IO_ADDRESS(pa))
diff --git a/arch/arm/plat-omap/include/mach/iommu.h b/arch/arm/plat-omap/include/mach/iommu.h
new file mode 100644 (file)
index 0000000..769b00b
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * omap iommu: main structures
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Written by Hiroshi DOYU <Hiroshi.DOYU@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.
+ */
+
+#ifndef __MACH_IOMMU_H
+#define __MACH_IOMMU_H
+
+struct iotlb_entry {
+       u32 da;
+       u32 pa;
+       u32 pgsz, prsvd, valid;
+       union {
+               u16 ap;
+               struct {
+                       u32 endian, elsz, mixed;
+               };
+       };
+};
+
+struct iommu {
+       const char      *name;
+       struct module   *owner;
+       struct clk      *clk;
+       void __iomem    *regbase;
+       struct device   *dev;
+
+       unsigned int    refcount;
+       struct mutex    iommu_lock;     /* global for this whole object */
+
+       /*
+        * We don't change iopgd for a situation like pgd for a task,
+        * but share it globally for each iommu.
+        */
+       u32             *iopgd;
+       spinlock_t      page_table_lock; /* protect iopgd */
+
+       int             nr_tlb_entries;
+
+       struct list_head        mmap;
+       struct mutex            mmap_lock; /* protect mmap */
+
+       int (*isr)(struct iommu *obj);
+
+       void *ctx; /* iommu context: registres saved area */
+};
+
+struct cr_regs {
+       union {
+               struct {
+                       u16 cam_l;
+                       u16 cam_h;
+               };
+               u32 cam;
+       };
+       union {
+               struct {
+                       u16 ram_l;
+                       u16 ram_h;
+               };
+               u32 ram;
+       };
+};
+
+struct iotlb_lock {
+       short base;
+       short vict;
+};
+
+/* architecture specific functions */
+struct iommu_functions {
+       unsigned long   version;
+
+       int (*enable)(struct iommu *obj);
+       void (*disable)(struct iommu *obj);
+       u32 (*fault_isr)(struct iommu *obj, u32 *ra);
+
+       void (*tlb_read_cr)(struct iommu *obj, struct cr_regs *cr);
+       void (*tlb_load_cr)(struct iommu *obj, struct cr_regs *cr);
+
+       struct cr_regs *(*alloc_cr)(struct iommu *obj, struct iotlb_entry *e);
+       int (*cr_valid)(struct cr_regs *cr);
+       u32 (*cr_to_virt)(struct cr_regs *cr);
+       void (*cr_to_e)(struct cr_regs *cr, struct iotlb_entry *e);
+       ssize_t (*dump_cr)(struct iommu *obj, struct cr_regs *cr, char *buf);
+
+       u32 (*get_pte_attr)(struct iotlb_entry *e);
+
+       void (*save_ctx)(struct iommu *obj);
+       void (*restore_ctx)(struct iommu *obj);
+       ssize_t (*dump_ctx)(struct iommu *obj, char *buf);
+};
+
+struct iommu_platform_data {
+       const char *name;
+       const char *clk_name;
+       const int nr_tlb_entries;
+};
+
+#if defined(CONFIG_ARCH_OMAP1)
+#error "iommu for this processor not implemented yet"
+#else
+#include <mach/iommu2.h>
+#endif
+
+/*
+ * utilities for super page(16MB, 1MB, 64KB and 4KB)
+ */
+
+#define iopgsz_max(bytes)                      \
+       (((bytes) >= SZ_16M) ? SZ_16M :         \
+        ((bytes) >= SZ_1M)  ? SZ_1M  :         \
+        ((bytes) >= SZ_64K) ? SZ_64K :         \
+        ((bytes) >= SZ_4K)  ? SZ_4K  : 0)
+
+#define bytes_to_iopgsz(bytes)                         \
+       (((bytes) == SZ_16M) ? MMU_CAM_PGSZ_16M :       \
+        ((bytes) == SZ_1M)  ? MMU_CAM_PGSZ_1M  :       \
+        ((bytes) == SZ_64K) ? MMU_CAM_PGSZ_64K :       \
+        ((bytes) == SZ_4K)  ? MMU_CAM_PGSZ_4K  : -1)
+
+#define iopgsz_to_bytes(iopgsz)                                \
+       (((iopgsz) == MMU_CAM_PGSZ_16M) ? SZ_16M :      \
+        ((iopgsz) == MMU_CAM_PGSZ_1M)  ? SZ_1M  :      \
+        ((iopgsz) == MMU_CAM_PGSZ_64K) ? SZ_64K :      \
+        ((iopgsz) == MMU_CAM_PGSZ_4K)  ? SZ_4K  : 0)
+
+#define iopgsz_ok(bytes) (bytes_to_iopgsz(bytes) >= 0)
+
+/*
+ * global functions
+ */
+extern u32 iommu_arch_version(void);
+
+extern void iotlb_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e);
+extern u32 iotlb_cr_to_virt(struct cr_regs *cr);
+
+extern int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e);
+extern void flush_iotlb_page(struct iommu *obj, u32 da);
+extern void flush_iotlb_range(struct iommu *obj, u32 start, u32 end);
+extern void flush_iotlb_all(struct iommu *obj);
+
+extern int iopgtable_store_entry(struct iommu *obj, struct iotlb_entry *e);
+extern size_t iopgtable_clear_entry(struct iommu *obj, u32 iova);
+
+extern struct iommu *iommu_get(const char *name);
+extern void iommu_put(struct iommu *obj);
+
+extern void iommu_save_ctx(struct iommu *obj);
+extern void iommu_restore_ctx(struct iommu *obj);
+
+extern int install_iommu_arch(const struct iommu_functions *ops);
+extern void uninstall_iommu_arch(const struct iommu_functions *ops);
+
+extern int foreach_iommu_device(void *data,
+                               int (*fn)(struct device *, void *));
+
+extern ssize_t iommu_dump_ctx(struct iommu *obj, char *buf);
+extern size_t dump_tlb_entries(struct iommu *obj, char *buf);
+
+#endif /* __MACH_IOMMU_H */
diff --git a/arch/arm/plat-omap/include/mach/iommu2.h b/arch/arm/plat-omap/include/mach/iommu2.h
new file mode 100644 (file)
index 0000000..10ad05f
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * omap iommu: omap2 architecture specific definitions
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Written by Hiroshi DOYU <Hiroshi.DOYU@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.
+ */
+
+#ifndef __MACH_IOMMU2_H
+#define __MACH_IOMMU2_H
+
+#include <linux/io.h>
+
+/*
+ * MMU Register offsets
+ */
+#define MMU_REVISION           0x00
+#define MMU_SYSCONFIG          0x10
+#define MMU_SYSSTATUS          0x14
+#define MMU_IRQSTATUS          0x18
+#define MMU_IRQENABLE          0x1c
+#define MMU_WALKING_ST         0x40
+#define MMU_CNTL               0x44
+#define MMU_FAULT_AD           0x48
+#define MMU_TTB                        0x4c
+#define MMU_LOCK               0x50
+#define MMU_LD_TLB             0x54
+#define MMU_CAM                        0x58
+#define MMU_RAM                        0x5c
+#define MMU_GFLUSH             0x60
+#define MMU_FLUSH_ENTRY                0x64
+#define MMU_READ_CAM           0x68
+#define MMU_READ_RAM           0x6c
+#define MMU_EMU_FAULT_AD       0x70
+
+#define MMU_REG_SIZE           256
+
+/*
+ * MMU Register bit definitions
+ */
+#define MMU_LOCK_BASE_SHIFT    10
+#define MMU_LOCK_BASE_MASK     (0x1f << MMU_LOCK_BASE_SHIFT)
+#define MMU_LOCK_BASE(x)       \
+       ((x & MMU_LOCK_BASE_MASK) >> MMU_LOCK_BASE_SHIFT)
+
+#define MMU_LOCK_VICT_SHIFT    4
+#define MMU_LOCK_VICT_MASK     (0x1f << MMU_LOCK_VICT_SHIFT)
+#define MMU_LOCK_VICT(x)       \
+       ((x & MMU_LOCK_VICT_MASK) >> MMU_LOCK_VICT_SHIFT)
+
+#define MMU_CAM_VATAG_SHIFT    12
+#define MMU_CAM_VATAG_MASK \
+       ((~0UL >> MMU_CAM_VATAG_SHIFT) << MMU_CAM_VATAG_SHIFT)
+#define MMU_CAM_P              (1 << 3)
+#define MMU_CAM_V              (1 << 2)
+#define MMU_CAM_PGSZ_MASK      3
+#define MMU_CAM_PGSZ_1M                (0 << 0)
+#define MMU_CAM_PGSZ_64K       (1 << 0)
+#define MMU_CAM_PGSZ_4K                (2 << 0)
+#define MMU_CAM_PGSZ_16M       (3 << 0)
+
+#define MMU_RAM_PADDR_SHIFT    12
+#define MMU_RAM_PADDR_MASK \
+       ((~0UL >> MMU_RAM_PADDR_SHIFT) << MMU_RAM_PADDR_SHIFT)
+#define MMU_RAM_ENDIAN_SHIFT   9
+#define MMU_RAM_ENDIAN_MASK    (1 << MMU_RAM_ENDIAN_SHIFT)
+#define MMU_RAM_ENDIAN_BIG     (1 << MMU_RAM_ENDIAN_SHIFT)
+#define MMU_RAM_ENDIAN_LITTLE  (0 << MMU_RAM_ENDIAN_SHIFT)
+#define MMU_RAM_ELSZ_SHIFT     7
+#define MMU_RAM_ELSZ_MASK      (3 << MMU_RAM_ELSZ_SHIFT)
+#define MMU_RAM_ELSZ_8         (0 << MMU_RAM_ELSZ_SHIFT)
+#define MMU_RAM_ELSZ_16                (1 << MMU_RAM_ELSZ_SHIFT)
+#define MMU_RAM_ELSZ_32                (2 << MMU_RAM_ELSZ_SHIFT)
+#define MMU_RAM_ELSZ_NONE      (3 << MMU_RAM_ELSZ_SHIFT)
+#define MMU_RAM_MIXED_SHIFT    6
+#define MMU_RAM_MIXED_MASK     (1 << MMU_RAM_MIXED_SHIFT)
+#define MMU_RAM_MIXED          MMU_RAM_MIXED_MASK
+
+/*
+ * register accessors
+ */
+static inline u32 iommu_read_reg(struct iommu *obj, size_t offs)
+{
+       return __raw_readl(obj->regbase + offs);
+}
+
+static inline void iommu_write_reg(struct iommu *obj, u32 val, size_t offs)
+{
+       __raw_writel(val, obj->regbase + offs);
+}
+
+#endif /* __MACH_IOMMU2_H */
diff --git a/arch/arm/plat-omap/include/mach/iovmm.h b/arch/arm/plat-omap/include/mach/iovmm.h
new file mode 100644 (file)
index 0000000..bdc7ce5
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * omap iommu: simple virtual address space management
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Written by Hiroshi DOYU <Hiroshi.DOYU@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.
+ */
+
+#ifndef __IOMMU_MMAP_H
+#define __IOMMU_MMAP_H
+
+struct iovm_struct {
+       struct iommu            *iommu; /* iommu object which this belongs to */
+       u32                     da_start; /* area definition */
+       u32                     da_end;
+       u32                     flags; /* IOVMF_: see below */
+       struct list_head        list; /* linked in ascending order */
+       const struct sg_table   *sgt; /* keep 'page' <-> 'da' mapping */
+       void                    *va; /* mpu side mapped address */
+};
+
+/*
+ * IOVMF_FLAGS: attribute for iommu virtual memory area(iovma)
+ *
+ * lower 16 bit is used for h/w and upper 16 bit is for s/w.
+ */
+#define IOVMF_SW_SHIFT         16
+#define IOVMF_HW_SIZE          (1 << IOVMF_SW_SHIFT)
+#define IOVMF_HW_MASK          (IOVMF_HW_SIZE - 1)
+#define IOVMF_SW_MASK          (~IOVMF_HW_MASK)UL
+
+/*
+ * iovma: h/w flags derived from cam and ram attribute
+ */
+#define IOVMF_CAM_MASK         (~((1 << 10) - 1))
+#define IOVMF_RAM_MASK         (~IOVMF_CAM_MASK)
+
+#define IOVMF_PGSZ_MASK                (3 << 0)
+#define IOVMF_PGSZ_1M          MMU_CAM_PGSZ_1M
+#define IOVMF_PGSZ_64K         MMU_CAM_PGSZ_64K
+#define IOVMF_PGSZ_4K          MMU_CAM_PGSZ_4K
+#define IOVMF_PGSZ_16M         MMU_CAM_PGSZ_16M
+
+#define IOVMF_ENDIAN_MASK      (1 << 9)
+#define IOVMF_ENDIAN_BIG       MMU_RAM_ENDIAN_BIG
+#define IOVMF_ENDIAN_LITTLE    MMU_RAM_ENDIAN_LITTLE
+
+#define IOVMF_ELSZ_MASK                (3 << 7)
+#define IOVMF_ELSZ_8           MMU_RAM_ELSZ_8
+#define IOVMF_ELSZ_16          MMU_RAM_ELSZ_16
+#define IOVMF_ELSZ_32          MMU_RAM_ELSZ_32
+#define IOVMF_ELSZ_NONE                MMU_RAM_ELSZ_NONE
+
+#define IOVMF_MIXED_MASK       (1 << 6)
+#define IOVMF_MIXED            MMU_RAM_MIXED
+
+/*
+ * iovma: s/w flags, used for mapping and umapping internally.
+ */
+#define IOVMF_MMIO             (1 << IOVMF_SW_SHIFT)
+#define IOVMF_ALLOC            (2 << IOVMF_SW_SHIFT)
+#define IOVMF_ALLOC_MASK       (3 << IOVMF_SW_SHIFT)
+
+/* "superpages" is supported just with physically linear pages */
+#define IOVMF_DISCONT          (1 << (2 + IOVMF_SW_SHIFT))
+#define IOVMF_LINEAR           (2 << (2 + IOVMF_SW_SHIFT))
+#define IOVMF_LINEAR_MASK      (3 << (2 + IOVMF_SW_SHIFT))
+
+#define IOVMF_DA_FIXED         (1 << (4 + IOVMF_SW_SHIFT))
+#define IOVMF_DA_ANON          (2 << (4 + IOVMF_SW_SHIFT))
+#define IOVMF_DA_MASK          (3 << (4 + IOVMF_SW_SHIFT))
+
+
+extern struct iovm_struct *find_iovm_area(struct iommu *obj, u32 da);
+extern u32 iommu_vmap(struct iommu *obj, u32 da,
+                       const struct sg_table *sgt, u32 flags);
+extern struct sg_table *iommu_vunmap(struct iommu *obj, u32 da);
+extern u32 iommu_vmalloc(struct iommu *obj, u32 da, size_t bytes,
+                          u32 flags);
+extern void iommu_vfree(struct iommu *obj, const u32 da);
+extern u32 iommu_kmap(struct iommu *obj, u32 da, u32 pa, size_t bytes,
+                       u32 flags);
+extern void iommu_kunmap(struct iommu *obj, u32 da);
+extern u32 iommu_kmalloc(struct iommu *obj, u32 da, size_t bytes,
+                          u32 flags);
+extern void iommu_kfree(struct iommu *obj, u32 da);
+
+extern void *da_to_va(struct iommu *obj, u32 da);
+
+#endif /* __IOMMU_MMAP_H */
index 7f57ee66f364dd0ad65092f58d62066c95a3604d..fb7cb7723990082141de476990b7619741ec65d1 100644 (file)
@@ -4,6 +4,9 @@
  *  Copyright (C) Greg Lonnon 2001
  *  Updated for OMAP-1610 by Tony Lindgren <tony@atomide.com>
  *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
 
 #define        INT_34XX_BENCH_MPU_EMUL 3
 
+
+#define IRQ_GIC_START          32
+#define INT_44XX_LOCALTIMER_IRQ        29
+#define INT_44XX_LOCALWDT_IRQ  30
+
+#define INT_44XX_BENCH_MPU_EMUL        (3 + IRQ_GIC_START)
+#define INT_44XX_SSM_ABORT_IRQ (6 + IRQ_GIC_START)
+#define INT_44XX_SYS_NIRQ      (7 + IRQ_GIC_START)
+#define INT_44XX_D2D_FW_IRQ    (8 + IRQ_GIC_START)
+#define INT_44XX_PRCM_MPU_IRQ  (11 + IRQ_GIC_START)
+#define INT_44XX_SDMA_IRQ0     (12 + IRQ_GIC_START)
+#define INT_44XX_SDMA_IRQ1     (13 + IRQ_GIC_START)
+#define INT_44XX_SDMA_IRQ2     (14 + IRQ_GIC_START)
+#define INT_44XX_SDMA_IRQ3     (15 + IRQ_GIC_START)
+#define INT_44XX_ISS_IRQ       (24 + IRQ_GIC_START)
+#define INT_44XX_DSS_IRQ       (25 + IRQ_GIC_START)
+#define INT_44XX_MAIL_U0_MPU   (26 + IRQ_GIC_START)
+#define INT_44XX_DSP_MMU       (28 + IRQ_GIC_START)
+#define INT_44XX_GPTIMER1      (37 + IRQ_GIC_START)
+#define INT_44XX_GPTIMER2      (38 + IRQ_GIC_START)
+#define INT_44XX_GPTIMER3      (39 + IRQ_GIC_START)
+#define INT_44XX_GPTIMER4      (40 + IRQ_GIC_START)
+#define INT_44XX_GPTIMER5      (41 + IRQ_GIC_START)
+#define INT_44XX_GPTIMER6      (42 + IRQ_GIC_START)
+#define INT_44XX_GPTIMER7      (43 + IRQ_GIC_START)
+#define INT_44XX_GPTIMER8      (44 + IRQ_GIC_START)
+#define INT_44XX_GPTIMER9      (45 + IRQ_GIC_START)
+#define INT_44XX_GPTIMER10     (46 + IRQ_GIC_START)
+#define INT_44XX_GPTIMER11     (47 + IRQ_GIC_START)
+#define INT_44XX_GPTIMER12     (95 + IRQ_GIC_START)
+#define INT_44XX_SHA1MD5       (51 + IRQ_GIC_START)
+#define INT_44XX_I2C1_IRQ      (56 + IRQ_GIC_START)
+#define INT_44XX_I2C2_IRQ      (57 + IRQ_GIC_START)
+#define INT_44XX_HDQ_IRQ       (58 + IRQ_GIC_START)
+#define INT_44XX_SPI1_IRQ      (65 + IRQ_GIC_START)
+#define INT_44XX_SPI2_IRQ      (66 + IRQ_GIC_START)
+#define INT_44XX_HSI_1_IRQ0    (67 + IRQ_GIC_START)
+#define INT_44XX_HSI_2_IRQ1    (68 + IRQ_GIC_START)
+#define INT_44XX_HSI_1_DMAIRQ  (71 + IRQ_GIC_START)
+#define INT_44XX_UART1_IRQ     (72 + IRQ_GIC_START)
+#define INT_44XX_UART2_IRQ     (73 + IRQ_GIC_START)
+#define INT_44XX_UART3_IRQ     (74 + IRQ_GIC_START)
+#define INT_44XX_UART4_IRQ     (70 + IRQ_GIC_START)
+#define INT_44XX_USB_IRQ_NISO  (76 + IRQ_GIC_START)
+#define INT_44XX_USB_IRQ_ISO   (77 + IRQ_GIC_START)
+#define INT_44XX_USB_IRQ_HGEN  (78 + IRQ_GIC_START)
+#define INT_44XX_USB_IRQ_HSOF  (79 + IRQ_GIC_START)
+#define INT_44XX_USB_IRQ_OTG   (80 + IRQ_GIC_START)
+#define INT_44XX_MCBSP4_IRQ_TX (81 + IRQ_GIC_START)
+#define INT_44XX_MCBSP4_IRQ_RX (82 + IRQ_GIC_START)
+#define INT_44XX_MMC_IRQ       (83 + IRQ_GIC_START)
+#define INT_44XX_MMC2_IRQ      (86 + IRQ_GIC_START)
+#define INT_44XX_MCBSP2_IRQ_TX (89 + IRQ_GIC_START)
+#define INT_44XX_MCBSP2_IRQ_RX (90 + IRQ_GIC_START)
+#define INT_44XX_SPI3_IRQ      (91 + IRQ_GIC_START)
+#define INT_44XX_SPI5_IRQ      (69 + IRQ_GIC_START)
+
+#define INT_44XX_MCBSP5_IRQ    (16 + IRQ_GIC_START)
+#define INT_44xX_MCBSP1_IRQ    (17 + IRQ_GIC_START)
+#define INT_44XX_MCBSP2_IRQ    (22 + IRQ_GIC_START)
+#define INT_44XX_MCBSP3_IRQ    (23 + IRQ_GIC_START)
+#define INT_44XX_MCBSP4_IRQ    (27 + IRQ_GIC_START)
+#define INT_44XX_HS_USB_MC     (92 + IRQ_GIC_START)
+#define INT_44XX_HS_USB_DMA    (93 + IRQ_GIC_START)
+
+#define INT_44XX_GPIO_BANK1    (29 + IRQ_GIC_START)
+#define INT_44XX_GPIO_BANK2    (30 + IRQ_GIC_START)
+#define INT_44XX_GPIO_BANK3    (31 + IRQ_GIC_START)
+#define INT_44XX_GPIO_BANK4    (32 + IRQ_GIC_START)
+#define INT_44XX_GPIO_BANK5    (33 + IRQ_GIC_START)
+#define INT_44XX_GPIO_BANK6    (34 + IRQ_GIC_START)
+#define INT_44XX_USIM_IRQ      (35 + IRQ_GIC_START)
+#define INT_44XX_WDT3_IRQ      (36 + IRQ_GIC_START)
+#define INT_44XX_SPI4_IRQ      (48 + IRQ_GIC_START)
+#define INT_44XX_SHA1MD52_IRQ  (49 + IRQ_GIC_START)
+#define INT_44XX_FPKA_READY_IRQ        (50 + IRQ_GIC_START)
+#define INT_44XX_SHA1MD51_IRQ  (51 + IRQ_GIC_START)
+#define INT_44XX_RNG_IRQ       (52 + IRQ_GIC_START)
+#define INT_44XX_I2C3_IRQ      (61 + IRQ_GIC_START)
+#define INT_44XX_FPKA_ERROR_IRQ        (64 + IRQ_GIC_START)
+#define INT_44XX_PBIAS_IRQ     (75 + IRQ_GIC_START)
+#define INT_44XX_OHCI_IRQ      (76 + IRQ_GIC_START)
+#define INT_44XX_EHCI_IRQ      (77 + IRQ_GIC_START)
+#define INT_44XX_TLL_IRQ       (78 + IRQ_GIC_START)
+#define INT_44XX_PARTHASH_IRQ  (79 + IRQ_GIC_START)
+#define INT_44XX_MMC3_IRQ      (94 + IRQ_GIC_START)
+
+
 /* Max. 128 level 2 IRQs (OMAP1610), 192 GPIOs (OMAP730/850) and
  * 16 MPUIO lines */
 #define OMAP_MAX_GPIO_LINES    192
 
 #ifndef __ASSEMBLY__
 extern void omap_init_irq(void);
+extern int omap_irq_pending(void);
 #endif
 
 #include <mach/hardware.h>
index 232923aaf61d34ed0f66daf5af54d1fad7c73a13..45ea3ae3c995ab7f0ad51386ad3282836c46419e 100644 (file)
@@ -33,7 +33,11 @@ struct omap_kp_platform_data {
 #define GROUP_3                (3 << 16)
 #define GROUP_MASK     GROUP_3
 
+#define KEY_PERSISTENT         0x00800000
+#define KEYNUM_MASK            0x00EFFFFF
 #define KEY(col, row, val) (((col) << 28) | ((row) << 24) | (val))
+#define PERSISTENT_KEY(col, row) (((col) << 28) | ((row) << 24) | \
+                                               KEY_PERSISTENT)
 
 #endif
 
index 99ed564d92774fe3d91e67f43a479ef6a21198d8..9ad41dc484c17ff2da3449d71df2ad7a925b4701 100644 (file)
@@ -38,7 +38,8 @@
  */
 #if defined(CONFIG_ARCH_OMAP1)
 #define PHYS_OFFSET            UL(0x10000000)
-#elif defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+#elif defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \
+                       defined(CONFIG_ARCH_OMAP4)
 #define PHYS_OFFSET            UL(0x80000000)
 #endif
 
index 24335d4932f5c725a13583197633bcd08fced549..696edfc145a6fa138183d3b678895ff1a73ba1a1 100644 (file)
 #define OMAP24XX_SEC_AES_BASE  (OMAP24XX_SEC_BASE + 0x6000)
 #define OMAP24XX_SEC_PKA_BASE  (OMAP24XX_SEC_BASE + 0x8000)
 
-#if defined(CONFIG_ARCH_OMAP2420)
-
-#define OMAP2_32KSYNCT_BASE    OMAP2420_32KSYNCT_BASE
-#define OMAP2_PRCM_BASE                OMAP2420_PRCM_BASE
-#define OMAP2_CM_BASE          OMAP2420_CM_BASE
-#define OMAP2_PRM_BASE         OMAP2420_PRM_BASE
-#define OMAP2_VA_IC_BASE       IO_ADDRESS(OMAP24XX_IC_BASE)
-
-#elif defined(CONFIG_ARCH_OMAP2430)
-
-#define OMAP2_32KSYNCT_BASE    OMAP2430_32KSYNCT_BASE
-#define OMAP2_PRCM_BASE                OMAP2430_PRCM_BASE
-#define OMAP2_CM_BASE          OMAP2430_CM_BASE
-#define OMAP2_PRM_BASE         OMAP2430_PRM_BASE
-#define OMAP2_VA_IC_BASE       IO_ADDRESS(OMAP24XX_IC_BASE)
-
-#endif
-
 #endif /* __ASM_ARCH_OMAP24XX_H */
 
index ab640151d3ec3ef38d90389978802254f14e21be..f8d186a737126109f56d53e3155167183ac577e2 100644 (file)
 
 #define L4_34XX_BASE           0x48000000
 #define L4_WK_34XX_BASE                0x48300000
-#define L4_WK_OMAP_BASE                L4_WK_34XX_BASE
 #define L4_PER_34XX_BASE       0x49000000
-#define L4_PER_OMAP_BASE       L4_PER_34XX_BASE
 #define L4_EMU_34XX_BASE       0x54000000
-#define L4_EMU_BASE            L4_EMU_34XX_BASE
 #define L3_34XX_BASE           0x68000000
-#define L3_OMAP_BASE           L3_34XX_BASE
 
 #define OMAP3430_32KSYNCT_BASE 0x48320000
 #define OMAP3430_CM_BASE       0x48004800
 
 #define OMAP34XX_MAILBOX_BASE          (L4_34XX_BASE + 0x94000)
 
-#if defined(CONFIG_ARCH_OMAP3430)
-
-#define OMAP2_32KSYNCT_BASE            OMAP3430_32KSYNCT_BASE
-#define OMAP2_CM_BASE                  OMAP3430_CM_BASE
-#define OMAP2_PRM_BASE                 OMAP3430_PRM_BASE
-#define OMAP2_VA_IC_BASE               IO_ADDRESS(OMAP34XX_IC_BASE)
-
-#endif
-
 #define OMAP34XX_DSP_BASE      0x58000000
 #define OMAP34XX_DSP_MEM_BASE  (OMAP34XX_DSP_BASE + 0x0)
 #define OMAP34XX_DSP_IPI_BASE  (OMAP34XX_DSP_BASE + 0x1000000)
diff --git a/arch/arm/plat-omap/include/mach/omap44xx.h b/arch/arm/plat-omap/include/mach/omap44xx.h
new file mode 100644 (file)
index 0000000..15dec7f
--- /dev/null
@@ -0,0 +1,46 @@
+/*:
+ * Address mappings and base address for OMAP4 interconnects
+ * and peripherals.
+ *
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * Author: Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __ASM_ARCH_OMAP44XX_H
+#define __ASM_ARCH_OMAP44XX_H
+
+/*
+ * Please place only base defines here and put the rest in device
+ * specific headers.
+ */
+#define L4_44XX_BASE                   0x4a000000
+#define L4_WK_44XX_BASE                        0x4a300000
+#define L4_PER_44XX_BASE               0x48000000
+#define L4_EMU_44XX_BASE               0x54000000
+#define L3_44XX_BASE                   0x44000000
+#define OMAP4430_32KSYNCT_BASE         0x4a304000
+#define OMAP4430_CM_BASE               0x4a004000
+#define OMAP4430_PRM_BASE              0x48306000
+#define OMAP44XX_GPMC_BASE             0x50000000
+#define OMAP443X_SCM_BASE              0x4a002000
+#define OMAP443X_CTRL_BASE             OMAP443X_SCM_BASE
+#define OMAP44XX_IC_BASE               0x48200000
+#define OMAP44XX_IVA_INTC_BASE         0x40000000
+#define IRQ_SIR_IRQ                    0x0040
+#define OMAP44XX_GIC_DIST_BASE         0x48241000
+#define OMAP44XX_GIC_CPU_BASE          0x48240100
+#define OMAP44XX_VA_GIC_CPU_BASE       IO_ADDRESS(OMAP44XX_GIC_CPU_BASE)
+#define OMAP44XX_SCU_BASE              0x48240000
+#define OMAP44XX_VA_SCU_BASE           IO_ADDRESS(OMAP44XX_SCU_BASE)
+#define OMAP44XX_LOCAL_TWD_BASE                0x48240600
+#define OMAP44XX_VA_LOCAL_TWD_BASE     IO_ADDRESS(OMAP44XX_LOCAL_TWD_BASE)
+#define OMAP44XX_LOCAL_TWD_SIZE                0x00000100
+#define OMAP44XX_WKUPGEN_BASE          0x48281000
+#define OMAP44XX_VA_WKUPGEN_BASE       IO_ADDRESS(OMAP44XX_WKUPGEN_BASE)
+
+#endif /* __ASM_ARCH_OMAP44XX_H */
+
index 4649d302c263723abb48c6c33579d39f96813e4f..72f433d7d827883250cfc1a034cb38e42d5d94a1 100644 (file)
@@ -9,8 +9,12 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 
+#define ONENAND_SYNC_READ      (1 << 0)
+#define ONENAND_SYNC_READWRITE (1 << 1)
+
 struct omap_onenand_platform_data {
        int                     cs;
        int                     gpio_irq;
@@ -18,8 +22,22 @@ struct omap_onenand_platform_data {
        int                     nr_parts;
        int                     (*onenand_setup)(void __iomem *, int freq);
        int                     dma_channel;
+       u8                      flags;
 };
 
-int omap2_onenand_rephase(void);
-
 #define ONENAND_MAX_PARTITIONS 8
+
+#if defined(CONFIG_MTD_ONENAND_OMAP2) || \
+       defined(CONFIG_MTD_ONENAND_OMAP2_MODULE)
+
+extern void gpmc_onenand_init(struct omap_onenand_platform_data *d);
+
+#else
+
+#define board_onenand_data     NULL
+
+static inline void gpmc_onenand_init(struct omap_onenand_platform_data *d)
+{
+}
+
+#endif
diff --git a/arch/arm/plat-omap/include/mach/pm.h b/arch/arm/plat-omap/include/mach/pm.h
deleted file mode 100644 (file)
index ce6ee79..0000000
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * arch/arm/plat-omap/include/mach/pm.h
- *
- * Header file for OMAP Power Management Routines
- *
- * Author: MontaVista Software, Inc.
- *        support@mvista.com
- *
- * Copyright 2002 MontaVista Software Inc.
- *
- * Cleanup 2004 for Linux 2.6 by Dirk Behme <dirk.behme@de.bosch.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __ASM_ARCH_OMAP_PM_H
-#define __ASM_ARCH_OMAP_PM_H
-
-/*
- * ----------------------------------------------------------------------------
- * Register and offset definitions to be used in PM assembler code
- * ----------------------------------------------------------------------------
- */
-#define CLKGEN_REG_ASM_BASE            IO_ADDRESS(0xfffece00)
-#define ARM_IDLECT1_ASM_OFFSET         0x04
-#define ARM_IDLECT2_ASM_OFFSET         0x08
-
-#define TCMIF_ASM_BASE                 IO_ADDRESS(0xfffecc00)
-#define EMIFS_CONFIG_ASM_OFFSET                0x0c
-#define EMIFF_SDRAM_CONFIG_ASM_OFFSET  0x20
-
-/*
- * ----------------------------------------------------------------------------
- * Power management bitmasks
- * ----------------------------------------------------------------------------
- */
-#define IDLE_WAIT_CYCLES               0x00000fff
-#define PERIPHERAL_ENABLE              0x2
-
-#define SELF_REFRESH_MODE              0x0c000001
-#define IDLE_EMIFS_REQUEST             0xc
-#define MODEM_32K_EN                   0x1
-#define PER_EN                         0x1
-
-#define CPU_SUSPEND_SIZE               200
-#define ULPD_LOW_PWR_EN                        0x0001
-#define ULPD_DEEP_SLEEP_TRANSITION_EN  0x0010
-#define ULPD_SETUP_ANALOG_CELL_3_VAL   0
-#define ULPD_POWER_CTRL_REG_VAL                0x0219
-
-#define DSP_IDLE_DELAY                 10
-#define DSP_IDLE                       0x0040
-#define DSP_RST                                0x0004
-#define DSP_ENABLE                     0x0002
-#define SUFFICIENT_DSP_RESET_TIME      1000
-#define DEFAULT_MPUI_CONFIG            0x05cf
-#define ENABLE_XORCLK                  0x2
-#define DSP_CLOCK_ENABLE               0x2000
-#define DSP_IDLE_MODE                  0x2
-#define TC_IDLE_REQUEST                        (0x0000000c)
-
-#define IRQ_LEVEL2                     (1<<0)
-#define IRQ_KEYBOARD                   (1<<1)
-#define IRQ_UART2                      (1<<15)
-
-#define PDE_BIT                                0x08
-#define PWD_EN_BIT                     0x04
-#define EN_PERCK_BIT                   0x04
-
-#define OMAP1510_DEEP_SLEEP_REQUEST    0x0ec7
-#define OMAP1510_BIG_SLEEP_REQUEST     0x0cc5
-#define OMAP1510_IDLE_LOOP_REQUEST     0x0c00
-#define OMAP1510_IDLE_CLOCK_DOMAINS    0x2
-
-/* Both big sleep and deep sleep use same values. Difference is in ULPD. */
-#define OMAP1610_IDLECT1_SLEEP_VAL     0x13c7
-#define OMAP1610_IDLECT2_SLEEP_VAL     0x09c7
-#define OMAP1610_IDLECT3_VAL           0x3f
-#define OMAP1610_IDLECT3_SLEEP_ORMASK  0x2c
-#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
-
-#if     !defined(CONFIG_ARCH_OMAP730) && \
-       !defined(CONFIG_ARCH_OMAP15XX) && \
-       !defined(CONFIG_ARCH_OMAP16XX) && \
-       !defined(CONFIG_ARCH_OMAP24XX)
-#warning "Power management for this processor not implemented yet"
-#endif
-
-#ifndef __ASSEMBLER__
-
-#include <linux/clk.h>
-
-extern void prevent_idle_sleep(void);
-extern void allow_idle_sleep(void);
-
-extern void omap_pm_idle(void);
-extern void omap_pm_suspend(void);
-extern void omap730_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 omap24xx_cpu_suspend(u32 dll_ctrl, void __iomem *sdrc_dlla_ctrl,
-                                       void __iomem *sdrc_power);
-extern void omap730_idle_loop_suspend(void);
-extern void omap1510_idle_loop_suspend(void);
-extern void omap1610_idle_loop_suspend(void);
-extern void omap24xx_idle_loop_suspend(void);
-
-extern unsigned int omap730_cpu_suspend_sz;
-extern unsigned int omap1510_cpu_suspend_sz;
-extern unsigned int omap1610_cpu_suspend_sz;
-extern unsigned int omap24xx_cpu_suspend_sz;
-extern unsigned int omap730_idle_loop_suspend_sz;
-extern unsigned int omap1510_idle_loop_suspend_sz;
-extern unsigned int omap1610_idle_loop_suspend_sz;
-extern unsigned int omap24xx_idle_loop_suspend_sz;
-
-#ifdef CONFIG_OMAP_SERIAL_WAKE
-extern void omap_serial_wake_trigger(int enable);
-#else
-#define omap_serial_wakeup_init()      {}
-#define omap_serial_wake_trigger(x)    {}
-#endif /* CONFIG_OMAP_SERIAL_WAKE */
-
-#define ARM_SAVE(x) arm_sleep_save[ARM_SLEEP_SAVE_##x] = omap_readl(x)
-#define ARM_RESTORE(x) omap_writel((arm_sleep_save[ARM_SLEEP_SAVE_##x]), (x))
-#define ARM_SHOW(x) arm_sleep_save[ARM_SLEEP_SAVE_##x]
-
-#define DSP_SAVE(x) dsp_sleep_save[DSP_SLEEP_SAVE_##x] = __raw_readw(x)
-#define DSP_RESTORE(x) __raw_writew((dsp_sleep_save[DSP_SLEEP_SAVE_##x]), (x))
-#define DSP_SHOW(x) dsp_sleep_save[DSP_SLEEP_SAVE_##x]
-
-#define ULPD_SAVE(x) ulpd_sleep_save[ULPD_SLEEP_SAVE_##x] = omap_readw(x)
-#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 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))
-#define MPUI1510_SHOW(x) mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x]
-
-#define MPUI1610_SAVE(x) mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x] = omap_readl(x)
-#define MPUI1610_RESTORE(x) omap_writel((mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x]), (x))
-#define MPUI1610_SHOW(x) mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x]
-
-#define OMAP24XX_SAVE(x) omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x] = x
-#define OMAP24XX_RESTORE(x) x = omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x]
-#define OMAP24XX_SHOW(x) omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x]
-
-/*
- * List of global OMAP registers to preserve.
- * More ones like CP and general purpose register values are preserved
- * with the stack pointer in sleep.S.
- */
-
-enum arm_save_state {
-       ARM_SLEEP_SAVE_START = 0,
-       /*
-        * MPU control registers 32 bits
-        */
-       ARM_SLEEP_SAVE_ARM_CKCTL,
-       ARM_SLEEP_SAVE_ARM_IDLECT1,
-       ARM_SLEEP_SAVE_ARM_IDLECT2,
-       ARM_SLEEP_SAVE_ARM_IDLECT3,
-       ARM_SLEEP_SAVE_ARM_EWUPCT,
-       ARM_SLEEP_SAVE_ARM_RSTCT1,
-       ARM_SLEEP_SAVE_ARM_RSTCT2,
-       ARM_SLEEP_SAVE_ARM_SYSST,
-       ARM_SLEEP_SAVE_SIZE
-};
-
-enum dsp_save_state {
-       DSP_SLEEP_SAVE_START = 0,
-       /*
-        * DSP registers 16 bits
-        */
-       DSP_SLEEP_SAVE_DSP_IDLECT2,
-       DSP_SLEEP_SAVE_SIZE
-};
-
-enum ulpd_save_state {
-       ULPD_SLEEP_SAVE_START = 0,
-       /*
-        * ULPD registers 16 bits
-        */
-       ULPD_SLEEP_SAVE_ULPD_IT_STATUS,
-       ULPD_SLEEP_SAVE_ULPD_CLOCK_CTRL,
-       ULPD_SLEEP_SAVE_ULPD_SOFT_REQ,
-       ULPD_SLEEP_SAVE_ULPD_STATUS_REQ,
-       ULPD_SLEEP_SAVE_ULPD_DPLL_CTRL,
-       ULPD_SLEEP_SAVE_ULPD_POWER_CTRL,
-       ULPD_SLEEP_SAVE_SIZE
-};
-
-enum mpui1510_save_state {
-       MPUI1510_SLEEP_SAVE_START = 0,
-       /*
-        * MPUI registers 32 bits
-        */
-       MPUI1510_SLEEP_SAVE_MPUI_CTRL,
-       MPUI1510_SLEEP_SAVE_MPUI_DSP_BOOT_CONFIG,
-       MPUI1510_SLEEP_SAVE_MPUI_DSP_API_CONFIG,
-       MPUI1510_SLEEP_SAVE_MPUI_DSP_STATUS,
-       MPUI1510_SLEEP_SAVE_EMIFF_SDRAM_CONFIG,
-       MPUI1510_SLEEP_SAVE_EMIFS_CONFIG,
-       MPUI1510_SLEEP_SAVE_OMAP_IH1_MIR,
-       MPUI1510_SLEEP_SAVE_OMAP_IH2_MIR,
-#if defined(CONFIG_ARCH_OMAP15XX)
-       MPUI1510_SLEEP_SAVE_SIZE
-#else
-       MPUI1510_SLEEP_SAVE_SIZE = 0
-#endif
-};
-
-enum mpui730_save_state {
-       MPUI730_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
-#else
-       MPUI730_SLEEP_SAVE_SIZE = 0
-#endif
-};
-
-enum mpui1610_save_state {
-       MPUI1610_SLEEP_SAVE_START = 0,
-       /*
-        * MPUI registers 32 bits
-        */
-       MPUI1610_SLEEP_SAVE_MPUI_CTRL,
-       MPUI1610_SLEEP_SAVE_MPUI_DSP_BOOT_CONFIG,
-       MPUI1610_SLEEP_SAVE_MPUI_DSP_API_CONFIG,
-       MPUI1610_SLEEP_SAVE_MPUI_DSP_STATUS,
-       MPUI1610_SLEEP_SAVE_EMIFF_SDRAM_CONFIG,
-       MPUI1610_SLEEP_SAVE_EMIFS_CONFIG,
-       MPUI1610_SLEEP_SAVE_OMAP_IH1_MIR,
-       MPUI1610_SLEEP_SAVE_OMAP_IH2_0_MIR,
-       MPUI1610_SLEEP_SAVE_OMAP_IH2_1_MIR,
-       MPUI1610_SLEEP_SAVE_OMAP_IH2_2_MIR,
-       MPUI1610_SLEEP_SAVE_OMAP_IH2_3_MIR,
-#if defined(CONFIG_ARCH_OMAP16XX)
-       MPUI1610_SLEEP_SAVE_SIZE
-#else
-       MPUI1610_SLEEP_SAVE_SIZE = 0
-#endif
-};
-
-enum omap24xx_save_state {
-       OMAP24XX_SLEEP_SAVE_START = 0,
-       OMAP24XX_SLEEP_SAVE_INTC_MIR0,
-       OMAP24XX_SLEEP_SAVE_INTC_MIR1,
-       OMAP24XX_SLEEP_SAVE_INTC_MIR2,
-
-       OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_MPU,
-       OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_CORE,
-       OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_GFX,
-       OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_DSP,
-       OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_MDM,
-
-       OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_MPU,
-       OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_CORE,
-       OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_GFX,
-       OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_DSP,
-       OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_MDM,
-
-       OMAP24XX_SLEEP_SAVE_CM_IDLEST1_CORE,
-       OMAP24XX_SLEEP_SAVE_CM_IDLEST2_CORE,
-       OMAP24XX_SLEEP_SAVE_CM_IDLEST3_CORE,
-       OMAP24XX_SLEEP_SAVE_CM_IDLEST4_CORE,
-       OMAP24XX_SLEEP_SAVE_CM_IDLEST_GFX,
-       OMAP24XX_SLEEP_SAVE_CM_IDLEST_WKUP,
-       OMAP24XX_SLEEP_SAVE_CM_IDLEST_CKGEN,
-       OMAP24XX_SLEEP_SAVE_CM_IDLEST_DSP,
-       OMAP24XX_SLEEP_SAVE_CM_IDLEST_MDM,
-
-       OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE1_CORE,
-       OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE2_CORE,
-       OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE3_CORE,
-       OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE4_CORE,
-       OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE_WKUP,
-       OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE_PLL,
-       OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE_DSP,
-       OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE_MDM,
-
-       OMAP24XX_SLEEP_SAVE_CM_FCLKEN1_CORE,
-       OMAP24XX_SLEEP_SAVE_CM_FCLKEN2_CORE,
-       OMAP24XX_SLEEP_SAVE_CM_ICLKEN1_CORE,
-       OMAP24XX_SLEEP_SAVE_CM_ICLKEN2_CORE,
-       OMAP24XX_SLEEP_SAVE_CM_ICLKEN3_CORE,
-       OMAP24XX_SLEEP_SAVE_CM_ICLKEN4_CORE,
-       OMAP24XX_SLEEP_SAVE_GPIO1_IRQENABLE1,
-       OMAP24XX_SLEEP_SAVE_GPIO2_IRQENABLE1,
-       OMAP24XX_SLEEP_SAVE_GPIO3_IRQENABLE1,
-       OMAP24XX_SLEEP_SAVE_GPIO4_IRQENABLE1,
-       OMAP24XX_SLEEP_SAVE_GPIO3_OE,
-       OMAP24XX_SLEEP_SAVE_GPIO4_OE,
-       OMAP24XX_SLEEP_SAVE_GPIO3_RISINGDETECT,
-       OMAP24XX_SLEEP_SAVE_GPIO3_FALLINGDETECT,
-       OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SPI1_NCS2,
-       OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_MCBSP1_DX,
-       OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SSI1_FLAG_TX,
-       OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SYS_NIRQW0,
-       OMAP24XX_SLEEP_SAVE_SIZE
-};
-
-#endif /* ASSEMBLER */
-#endif /* __ASM_ARCH_OMAP_PM_H */
index 8a676a04be481b1630cb7d0fa61cc87b00498aa4..13abd02d15279163291772ff129a71012d8a257e 100644 (file)
@@ -1,5 +1,8 @@
 /*
- *  arch/arm/plat-omap/include/mach/serial.h
+ * arch/arm/plat-omap/include/mach/serial.h
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Addded OMAP4 support- Santosh Shilimkar <santosh.shilimkar@ti.com>
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 #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 OMAP_MAX_NR_PORTS      3
 #define OMAP1510_BASE_BAUD     (12000000/16)
 #define OMAP16XX_BASE_BAUD     (48000000/16)
 #define OMAP24XX_BASE_BAUD     (48000000/16)
                        __ret;                                          \
                        })
 
+#ifndef __ASSEMBLER__
+extern void omap_serial_init(void);
+extern int omap_uart_can_sleep(void);
+extern void omap_uart_check_wakeup(void);
+extern void omap_uart_prepare_suspend(void);
+extern void omap_uart_prepare_idle(int num);
+extern void omap_uart_resume_idle(int num);
+#endif
+
 #endif
diff --git a/arch/arm/plat-omap/include/mach/smp.h b/arch/arm/plat-omap/include/mach/smp.h
new file mode 100644 (file)
index 0000000..dcaa8fd
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * OMAP4 machine specific smp.h
+ *
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Author:
+ *     Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * Interface functions needed for the SMP. This file is based on arm
+ * realview smp platform.
+ * Copyright (c) 2003 ARM Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef OMAP_ARCH_SMP_H
+#define OMAP_ARCH_SMP_H
+
+#include <asm/hardware/gic.h>
+
+/*
+ * set_event() is used to wake up secondary core from wfe using sev. ROM
+ * code puts the second core into wfe(standby).
+ *
+ */
+#define set_event()    __asm__ __volatile__ ("sev" : : : "memory")
+
+/* Needed for secondary core boot */
+extern void omap_secondary_startup(void);
+
+/*
+ * We use Soft IRQ1 as the IPI
+ */
+static inline void smp_cross_call(const struct cpumask *mask)
+{
+       gic_raise_softirq(mask, 1);
+}
+
+/*
+ * Read MPIDR: Multiprocessor affinity register
+ */
+#define hard_smp_processor_id()                        \
+       ({                                              \
+               unsigned int cpunum;                    \
+               __asm__("mrc p15, 0, %0, c0, c0, 5"     \
+                       : "=r" (cpunum));               \
+               cpunum &= 0x0F;                         \
+       })
+
+#endif
index ab35d622dcf5c4553c6340da777146c89f3b974b..dca7c16ae903726a6937ca6a79d7e5d8791fddaa 100644 (file)
@@ -23,7 +23,8 @@ extern u32 omap2_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass);
 
 extern u32 omap3_configure_core_dpll(u32 sdrc_rfr_ctrl,
                                     u32 sdrc_actim_ctrla,
-                                    u32 sdrc_actim_ctrlb, u32 m2);
+                                    u32 sdrc_actim_ctrlb, u32 m2,
+                                    u32 unlock_dll);
 
 /* Do not use these */
 extern void omap1_sram_reprogram_clock(u32 ckctl, u32 dpllctl);
@@ -60,7 +61,8 @@ extern unsigned long omap243x_sram_reprogram_sdrc_sz;
 
 extern u32 omap3_sram_configure_core_dpll(u32 sdrc_rfr_ctrl,
                                          u32 sdrc_actim_ctrla,
-                                         u32 sdrc_actim_ctrlb, u32 m2);
+                                         u32 sdrc_actim_ctrlb, u32 m2,
+                                         u32 unlock_dll);
 extern unsigned long omap3_sram_configure_core_dpll_sz;
 
 #endif
index 69f0ceed500bd174467e3b1cd7e579d160c9cc9e..f337e1761e2c0db8c56fd3c712c1317aa4293e09 100644 (file)
 #define UDC_BASE                       OMAP2_UDC_BASE
 #define OMAP_OHCI_BASE                 OMAP2_OHCI_BASE
 
-#ifdef CONFIG_USB_MUSB_SOC
 extern void usb_musb_init(void);
-#else
-static inline void usb_musb_init(void)
-{
-}
-#endif
 
 #endif
 
index dc104cd96197ce63e983cbd4139830bbe36ce29b..b97dfafeebda6179a5ef652fb0e8070a2ef4b3ae 100644 (file)
@@ -17,5 +17,5 @@
  * 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 + 0x10000000)
+#define VMALLOC_END      (PAGE_OFFSET + 0x18000000)
 
index af326efc1ad3b807f9cd1e09763181436dfb757d..9b42d72d96cf9b3b822bb1e8ee29d57357839d66 100644 (file)
@@ -1,3 +1,14 @@
+/*
+ * Common io.c file
+ * This file is created by Russell King <rmk+kernel@arm.linux.org.uk>
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
 #include <linux/module.h>
 #include <linux/io.h>
 #include <linux/mm.h>
@@ -7,6 +18,7 @@
 #include <mach/omap16xx.h>
 #include <mach/omap24xx.h>
 #include <mach/omap34xx.h>
+#include <mach/omap44xx.h>
 
 #define BETWEEN(p,st,sz)       ((p) >= (st) && (p) < ((st) + (sz)))
 #define XLATE(p,pst,vst)       ((void __iomem *)((p) - (pst) + (vst)))
@@ -92,7 +104,22 @@ void __iomem *omap_ioremap(unsigned long p, size_t size, unsigned int type)
                        return XLATE(p, L4_EMU_34XX_PHYS, L4_EMU_34XX_VIRT);
        }
 #endif
-
+#ifdef CONFIG_ARCH_OMAP4
+       if (cpu_is_omap44xx()) {
+               if (BETWEEN(p, L3_44XX_PHYS, L3_44XX_SIZE))
+                       return XLATE(p, L3_44XX_PHYS, L3_44XX_VIRT);
+               if (BETWEEN(p, L4_44XX_PHYS, L4_44XX_SIZE))
+                       return XLATE(p, L4_44XX_PHYS, L4_44XX_VIRT);
+               if (BETWEEN(p, L4_WK_44XX_PHYS, L4_WK_44XX_SIZE))
+                       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, 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))
+                       return XLATE(p, L4_EMU_44XX_PHYS, L4_EMU_44XX_VIRT);
+       }
+#endif
        return __arm_ioremap(p, size, type);
 }
 EXPORT_SYMBOL(omap_ioremap);
diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c
new file mode 100644 (file)
index 0000000..4cf449f
--- /dev/null
@@ -0,0 +1,996 @@
+/*
+ * omap iommu: tlb and pagetable primitives
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>,
+ *             Paul Mundt and Toshihiro Kobayashi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include <asm/cacheflush.h>
+
+#include <mach/iommu.h>
+
+#include "iopgtable.h"
+
+/* accommodate the difference between omap1 and omap2/3 */
+static const struct iommu_functions *arch_iommu;
+
+static struct platform_driver omap_iommu_driver;
+static struct kmem_cache *iopte_cachep;
+
+/**
+ * install_iommu_arch - Install archtecure specific iommu functions
+ * @ops:       a pointer to architecture specific iommu functions
+ *
+ * There are several kind of iommu algorithm(tlb, pagetable) among
+ * omap series. This interface installs such an iommu algorighm.
+ **/
+int install_iommu_arch(const struct iommu_functions *ops)
+{
+       if (arch_iommu)
+               return -EBUSY;
+
+       arch_iommu = ops;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(install_iommu_arch);
+
+/**
+ * uninstall_iommu_arch - Uninstall archtecure specific iommu functions
+ * @ops:       a pointer to architecture specific iommu functions
+ *
+ * This interface uninstalls the iommu algorighm installed previously.
+ **/
+void uninstall_iommu_arch(const struct iommu_functions *ops)
+{
+       if (arch_iommu != ops)
+               pr_err("%s: not your arch\n", __func__);
+
+       arch_iommu = NULL;
+}
+EXPORT_SYMBOL_GPL(uninstall_iommu_arch);
+
+/**
+ * iommu_save_ctx - Save registers for pm off-mode support
+ * @obj:       target iommu
+ **/
+void iommu_save_ctx(struct iommu *obj)
+{
+       arch_iommu->save_ctx(obj);
+}
+EXPORT_SYMBOL_GPL(iommu_save_ctx);
+
+/**
+ * iommu_restore_ctx - Restore registers for pm off-mode support
+ * @obj:       target iommu
+ **/
+void iommu_restore_ctx(struct iommu *obj)
+{
+       arch_iommu->restore_ctx(obj);
+}
+EXPORT_SYMBOL_GPL(iommu_restore_ctx);
+
+/**
+ * iommu_arch_version - Return running iommu arch version
+ **/
+u32 iommu_arch_version(void)
+{
+       return arch_iommu->version;
+}
+EXPORT_SYMBOL_GPL(iommu_arch_version);
+
+static int iommu_enable(struct iommu *obj)
+{
+       int err;
+
+       if (!obj)
+               return -EINVAL;
+
+       clk_enable(obj->clk);
+
+       err = arch_iommu->enable(obj);
+
+       clk_disable(obj->clk);
+       return err;
+}
+
+static void iommu_disable(struct iommu *obj)
+{
+       if (!obj)
+               return;
+
+       clk_enable(obj->clk);
+
+       arch_iommu->disable(obj);
+
+       clk_disable(obj->clk);
+}
+
+/*
+ *     TLB operations
+ */
+void iotlb_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e)
+{
+       BUG_ON(!cr || !e);
+
+       arch_iommu->cr_to_e(cr, e);
+}
+EXPORT_SYMBOL_GPL(iotlb_cr_to_e);
+
+static inline int iotlb_cr_valid(struct cr_regs *cr)
+{
+       if (!cr)
+               return -EINVAL;
+
+       return arch_iommu->cr_valid(cr);
+}
+
+static inline struct cr_regs *iotlb_alloc_cr(struct iommu *obj,
+                                            struct iotlb_entry *e)
+{
+       if (!e)
+               return NULL;
+
+       return arch_iommu->alloc_cr(obj, e);
+}
+
+u32 iotlb_cr_to_virt(struct cr_regs *cr)
+{
+       return arch_iommu->cr_to_virt(cr);
+}
+EXPORT_SYMBOL_GPL(iotlb_cr_to_virt);
+
+static u32 get_iopte_attr(struct iotlb_entry *e)
+{
+       return arch_iommu->get_pte_attr(e);
+}
+
+static u32 iommu_report_fault(struct iommu *obj, u32 *da)
+{
+       return arch_iommu->fault_isr(obj, da);
+}
+
+static void iotlb_lock_get(struct iommu *obj, struct iotlb_lock *l)
+{
+       u32 val;
+
+       val = iommu_read_reg(obj, MMU_LOCK);
+
+       l->base = MMU_LOCK_BASE(val);
+       l->vict = MMU_LOCK_VICT(val);
+
+       BUG_ON(l->base != 0); /* Currently no preservation is used */
+}
+
+static void iotlb_lock_set(struct iommu *obj, struct iotlb_lock *l)
+{
+       u32 val;
+
+       BUG_ON(l->base != 0); /* Currently no preservation is used */
+
+       val = (l->base << MMU_LOCK_BASE_SHIFT);
+       val |= (l->vict << MMU_LOCK_VICT_SHIFT);
+
+       iommu_write_reg(obj, val, MMU_LOCK);
+}
+
+static void iotlb_read_cr(struct iommu *obj, struct cr_regs *cr)
+{
+       arch_iommu->tlb_read_cr(obj, cr);
+}
+
+static void iotlb_load_cr(struct iommu *obj, struct cr_regs *cr)
+{
+       arch_iommu->tlb_load_cr(obj, cr);
+
+       iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY);
+       iommu_write_reg(obj, 1, MMU_LD_TLB);
+}
+
+/**
+ * iotlb_dump_cr - Dump an iommu tlb entry into buf
+ * @obj:       target iommu
+ * @cr:                contents of cam and ram register
+ * @buf:       output buffer
+ **/
+static inline ssize_t iotlb_dump_cr(struct iommu *obj, struct cr_regs *cr,
+                                   char *buf)
+{
+       BUG_ON(!cr || !buf);
+
+       return arch_iommu->dump_cr(obj, cr, buf);
+}
+
+/**
+ * load_iotlb_entry - Set an iommu tlb entry
+ * @obj:       target iommu
+ * @e:         an iommu tlb entry info
+ **/
+int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e)
+{
+       int i;
+       int err = 0;
+       struct iotlb_lock l;
+       struct cr_regs *cr;
+
+       if (!obj || !obj->nr_tlb_entries || !e)
+               return -EINVAL;
+
+       clk_enable(obj->clk);
+
+       for (i = 0; i < obj->nr_tlb_entries; i++) {
+               struct cr_regs tmp;
+
+               iotlb_lock_get(obj, &l);
+               l.vict = i;
+               iotlb_lock_set(obj, &l);
+               iotlb_read_cr(obj, &tmp);
+               if (!iotlb_cr_valid(&tmp))
+                       break;
+       }
+
+       if (i == obj->nr_tlb_entries) {
+               dev_dbg(obj->dev, "%s: full: no entry\n", __func__);
+               err = -EBUSY;
+               goto out;
+       }
+
+       cr = iotlb_alloc_cr(obj, e);
+       if (IS_ERR(cr)) {
+               clk_disable(obj->clk);
+               return PTR_ERR(cr);
+       }
+
+       iotlb_load_cr(obj, cr);
+       kfree(cr);
+
+       /* increment victim for next tlb load */
+       if (++l.vict == obj->nr_tlb_entries)
+               l.vict = 0;
+       iotlb_lock_set(obj, &l);
+out:
+       clk_disable(obj->clk);
+       return err;
+}
+EXPORT_SYMBOL_GPL(load_iotlb_entry);
+
+/**
+ * flush_iotlb_page - Clear an iommu tlb entry
+ * @obj:       target iommu
+ * @da:                iommu device virtual address
+ *
+ * Clear an iommu tlb entry which includes 'da' address.
+ **/
+void flush_iotlb_page(struct iommu *obj, u32 da)
+{
+       struct iotlb_lock l;
+       int i;
+
+       clk_enable(obj->clk);
+
+       for (i = 0; i < obj->nr_tlb_entries; i++) {
+               struct cr_regs cr;
+               u32 start;
+               size_t bytes;
+
+               iotlb_lock_get(obj, &l);
+               l.vict = i;
+               iotlb_lock_set(obj, &l);
+               iotlb_read_cr(obj, &cr);
+               if (!iotlb_cr_valid(&cr))
+                       continue;
+
+               start = iotlb_cr_to_virt(&cr);
+               bytes = iopgsz_to_bytes(cr.cam & 3);
+
+               if ((start <= da) && (da < start + bytes)) {
+                       dev_dbg(obj->dev, "%s: %08x<=%08x(%x)\n",
+                               __func__, start, da, bytes);
+
+                       iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY);
+               }
+       }
+       clk_disable(obj->clk);
+
+       if (i == obj->nr_tlb_entries)
+               dev_dbg(obj->dev, "%s: no page for %08x\n", __func__, da);
+}
+EXPORT_SYMBOL_GPL(flush_iotlb_page);
+
+/**
+ * flush_iotlb_range - Clear an iommu tlb entries
+ * @obj:       target iommu
+ * @start:     iommu device virtual address(start)
+ * @end:       iommu device virtual address(end)
+ *
+ * Clear an iommu tlb entry which includes 'da' address.
+ **/
+void flush_iotlb_range(struct iommu *obj, u32 start, u32 end)
+{
+       u32 da = start;
+
+       while (da < end) {
+               flush_iotlb_page(obj, da);
+               /* FIXME: Optimize for multiple page size */
+               da += IOPTE_SIZE;
+       }
+}
+EXPORT_SYMBOL_GPL(flush_iotlb_range);
+
+/**
+ * flush_iotlb_all - Clear all iommu tlb entries
+ * @obj:       target iommu
+ **/
+void flush_iotlb_all(struct iommu *obj)
+{
+       struct iotlb_lock l;
+
+       clk_enable(obj->clk);
+
+       l.base = 0;
+       l.vict = 0;
+       iotlb_lock_set(obj, &l);
+
+       iommu_write_reg(obj, 1, MMU_GFLUSH);
+
+       clk_disable(obj->clk);
+}
+EXPORT_SYMBOL_GPL(flush_iotlb_all);
+
+#if defined(CONFIG_OMAP_IOMMU_DEBUG_MODULE)
+
+ssize_t iommu_dump_ctx(struct iommu *obj, char *buf)
+{
+       ssize_t bytes;
+
+       if (!obj || !buf)
+               return -EINVAL;
+
+       clk_enable(obj->clk);
+
+       bytes = arch_iommu->dump_ctx(obj, buf);
+
+       clk_disable(obj->clk);
+
+       return bytes;
+}
+EXPORT_SYMBOL_GPL(iommu_dump_ctx);
+
+static int __dump_tlb_entries(struct iommu *obj, struct cr_regs *crs)
+{
+       int i;
+       struct iotlb_lock saved, l;
+       struct cr_regs *p = crs;
+
+       clk_enable(obj->clk);
+
+       iotlb_lock_get(obj, &saved);
+       memcpy(&l, &saved, sizeof(saved));
+
+       for (i = 0; i < obj->nr_tlb_entries; i++) {
+               struct cr_regs tmp;
+
+               iotlb_lock_get(obj, &l);
+               l.vict = i;
+               iotlb_lock_set(obj, &l);
+               iotlb_read_cr(obj, &tmp);
+               if (!iotlb_cr_valid(&tmp))
+                       continue;
+
+               *p++ = tmp;
+       }
+       iotlb_lock_set(obj, &saved);
+       clk_disable(obj->clk);
+
+       return  p - crs;
+}
+
+/**
+ * dump_tlb_entries - dump cr arrays to given buffer
+ * @obj:       target iommu
+ * @buf:       output buffer
+ **/
+size_t dump_tlb_entries(struct iommu *obj, char *buf)
+{
+       int i, n;
+       struct cr_regs *cr;
+       char *p = buf;
+
+       cr = kcalloc(obj->nr_tlb_entries, sizeof(*cr), GFP_KERNEL);
+       if (!cr)
+               return 0;
+
+       n = __dump_tlb_entries(obj, cr);
+       for (i = 0; i < n; i++)
+               p += iotlb_dump_cr(obj, cr + i, p);
+       kfree(cr);
+
+       return p - buf;
+}
+EXPORT_SYMBOL_GPL(dump_tlb_entries);
+
+int foreach_iommu_device(void *data, int (*fn)(struct device *, void *))
+{
+       return driver_for_each_device(&omap_iommu_driver.driver,
+                                     NULL, data, fn);
+}
+EXPORT_SYMBOL_GPL(foreach_iommu_device);
+
+#endif /* CONFIG_OMAP_IOMMU_DEBUG_MODULE */
+
+/*
+ *     H/W pagetable operations
+ */
+static void flush_iopgd_range(u32 *first, u32 *last)
+{
+       /* FIXME: L2 cache should be taken care of if it exists */
+       do {
+               asm("mcr        p15, 0, %0, c7, c10, 1 @ flush_pgd"
+                   : : "r" (first));
+               first += L1_CACHE_BYTES / sizeof(*first);
+       } while (first <= last);
+}
+
+static void flush_iopte_range(u32 *first, u32 *last)
+{
+       /* FIXME: L2 cache should be taken care of if it exists */
+       do {
+               asm("mcr        p15, 0, %0, c7, c10, 1 @ flush_pte"
+                   : : "r" (first));
+               first += L1_CACHE_BYTES / sizeof(*first);
+       } while (first <= last);
+}
+
+static void iopte_free(u32 *iopte)
+{
+       /* Note: freed iopte's must be clean ready for re-use */
+       kmem_cache_free(iopte_cachep, iopte);
+}
+
+static u32 *iopte_alloc(struct iommu *obj, u32 *iopgd, u32 da)
+{
+       u32 *iopte;
+
+       /* a table has already existed */
+       if (*iopgd)
+               goto pte_ready;
+
+       /*
+        * do the allocation outside the page table lock
+        */
+       spin_unlock(&obj->page_table_lock);
+       iopte = kmem_cache_zalloc(iopte_cachep, GFP_KERNEL);
+       spin_lock(&obj->page_table_lock);
+
+       if (!*iopgd) {
+               if (!iopte)
+                       return ERR_PTR(-ENOMEM);
+
+               *iopgd = virt_to_phys(iopte) | IOPGD_TABLE;
+               flush_iopgd_range(iopgd, iopgd);
+
+               dev_vdbg(obj->dev, "%s: a new pte:%p\n", __func__, iopte);
+       } else {
+               /* We raced, free the reduniovant table */
+               iopte_free(iopte);
+       }
+
+pte_ready:
+       iopte = iopte_offset(iopgd, da);
+
+       dev_vdbg(obj->dev,
+                "%s: da:%08x pgd:%p *pgd:%08x pte:%p *pte:%08x\n",
+                __func__, da, iopgd, *iopgd, iopte, *iopte);
+
+       return iopte;
+}
+
+static int iopgd_alloc_section(struct iommu *obj, u32 da, u32 pa, u32 prot)
+{
+       u32 *iopgd = iopgd_offset(obj, da);
+
+       *iopgd = (pa & IOSECTION_MASK) | prot | IOPGD_SECTION;
+       flush_iopgd_range(iopgd, iopgd);
+       return 0;
+}
+
+static int iopgd_alloc_super(struct iommu *obj, u32 da, u32 pa, u32 prot)
+{
+       u32 *iopgd = iopgd_offset(obj, da);
+       int i;
+
+       for (i = 0; i < 16; i++)
+               *(iopgd + i) = (pa & IOSUPER_MASK) | prot | IOPGD_SUPER;
+       flush_iopgd_range(iopgd, iopgd + 15);
+       return 0;
+}
+
+static int iopte_alloc_page(struct iommu *obj, u32 da, u32 pa, u32 prot)
+{
+       u32 *iopgd = iopgd_offset(obj, da);
+       u32 *iopte = iopte_alloc(obj, iopgd, da);
+
+       if (IS_ERR(iopte))
+               return PTR_ERR(iopte);
+
+       *iopte = (pa & IOPAGE_MASK) | prot | IOPTE_SMALL;
+       flush_iopte_range(iopte, iopte);
+
+       dev_vdbg(obj->dev, "%s: da:%08x pa:%08x pte:%p *pte:%08x\n",
+                __func__, da, pa, iopte, *iopte);
+
+       return 0;
+}
+
+static int iopte_alloc_large(struct iommu *obj, u32 da, u32 pa, u32 prot)
+{
+       u32 *iopgd = iopgd_offset(obj, da);
+       u32 *iopte = iopte_alloc(obj, iopgd, da);
+       int i;
+
+       if (IS_ERR(iopte))
+               return PTR_ERR(iopte);
+
+       for (i = 0; i < 16; i++)
+               *(iopte + i) = (pa & IOLARGE_MASK) | prot | IOPTE_LARGE;
+       flush_iopte_range(iopte, iopte + 15);
+       return 0;
+}
+
+static int iopgtable_store_entry_core(struct iommu *obj, struct iotlb_entry *e)
+{
+       int (*fn)(struct iommu *, u32, u32, u32);
+       u32 prot;
+       int err;
+
+       if (!obj || !e)
+               return -EINVAL;
+
+       switch (e->pgsz) {
+       case MMU_CAM_PGSZ_16M:
+               fn = iopgd_alloc_super;
+               break;
+       case MMU_CAM_PGSZ_1M:
+               fn = iopgd_alloc_section;
+               break;
+       case MMU_CAM_PGSZ_64K:
+               fn = iopte_alloc_large;
+               break;
+       case MMU_CAM_PGSZ_4K:
+               fn = iopte_alloc_page;
+               break;
+       default:
+               fn = NULL;
+               BUG();
+               break;
+       }
+
+       prot = get_iopte_attr(e);
+
+       spin_lock(&obj->page_table_lock);
+       err = fn(obj, e->da, e->pa, prot);
+       spin_unlock(&obj->page_table_lock);
+
+       return err;
+}
+
+/**
+ * iopgtable_store_entry - Make an iommu pte entry
+ * @obj:       target iommu
+ * @e:         an iommu tlb entry info
+ **/
+int iopgtable_store_entry(struct iommu *obj, struct iotlb_entry *e)
+{
+       int err;
+
+       flush_iotlb_page(obj, e->da);
+       err = iopgtable_store_entry_core(obj, e);
+#ifdef PREFETCH_IOTLB
+       if (!err)
+               load_iotlb_entry(obj, e);
+#endif
+       return err;
+}
+EXPORT_SYMBOL_GPL(iopgtable_store_entry);
+
+/**
+ * iopgtable_lookup_entry - Lookup an iommu pte entry
+ * @obj:       target iommu
+ * @da:                iommu device virtual address
+ * @ppgd:      iommu pgd entry pointer to be returned
+ * @ppte:      iommu pte entry pointer to be returned
+ **/
+void iopgtable_lookup_entry(struct iommu *obj, u32 da, u32 **ppgd, u32 **ppte)
+{
+       u32 *iopgd, *iopte = NULL;
+
+       iopgd = iopgd_offset(obj, da);
+       if (!*iopgd)
+               goto out;
+
+       if (*iopgd & IOPGD_TABLE)
+               iopte = iopte_offset(iopgd, da);
+out:
+       *ppgd = iopgd;
+       *ppte = iopte;
+}
+EXPORT_SYMBOL_GPL(iopgtable_lookup_entry);
+
+static size_t iopgtable_clear_entry_core(struct iommu *obj, u32 da)
+{
+       size_t bytes;
+       u32 *iopgd = iopgd_offset(obj, da);
+       int nent = 1;
+
+       if (!*iopgd)
+               return 0;
+
+       if (*iopgd & IOPGD_TABLE) {
+               int i;
+               u32 *iopte = iopte_offset(iopgd, da);
+
+               bytes = IOPTE_SIZE;
+               if (*iopte & IOPTE_LARGE) {
+                       nent *= 16;
+                       /* rewind to the 1st entry */
+                       iopte = (u32 *)((u32)iopte & IOLARGE_MASK);
+               }
+               bytes *= nent;
+               memset(iopte, 0, nent * sizeof(*iopte));
+               flush_iopte_range(iopte, iopte + (nent - 1) * sizeof(*iopte));
+
+               /*
+                * do table walk to check if this table is necessary or not
+                */
+               iopte = iopte_offset(iopgd, 0);
+               for (i = 0; i < PTRS_PER_IOPTE; i++)
+                       if (iopte[i])
+                               goto out;
+
+               iopte_free(iopte);
+               nent = 1; /* for the next L1 entry */
+       } else {
+               bytes = IOPGD_SIZE;
+               if (*iopgd & IOPGD_SUPER) {
+                       nent *= 16;
+                       /* rewind to the 1st entry */
+                       iopgd = (u32 *)((u32)iopgd & IOSUPER_MASK);
+               }
+               bytes *= nent;
+       }
+       memset(iopgd, 0, nent * sizeof(*iopgd));
+       flush_iopgd_range(iopgd, iopgd + (nent - 1) * sizeof(*iopgd));
+out:
+       return bytes;
+}
+
+/**
+ * iopgtable_clear_entry - Remove an iommu pte entry
+ * @obj:       target iommu
+ * @da:                iommu device virtual address
+ **/
+size_t iopgtable_clear_entry(struct iommu *obj, u32 da)
+{
+       size_t bytes;
+
+       spin_lock(&obj->page_table_lock);
+
+       bytes = iopgtable_clear_entry_core(obj, da);
+       flush_iotlb_page(obj, da);
+
+       spin_unlock(&obj->page_table_lock);
+
+       return bytes;
+}
+EXPORT_SYMBOL_GPL(iopgtable_clear_entry);
+
+static void iopgtable_clear_entry_all(struct iommu *obj)
+{
+       int i;
+
+       spin_lock(&obj->page_table_lock);
+
+       for (i = 0; i < PTRS_PER_IOPGD; i++) {
+               u32 da;
+               u32 *iopgd;
+
+               da = i << IOPGD_SHIFT;
+               iopgd = iopgd_offset(obj, da);
+
+               if (!*iopgd)
+                       continue;
+
+               if (*iopgd & IOPGD_TABLE)
+                       iopte_free(iopte_offset(iopgd, 0));
+
+               *iopgd = 0;
+               flush_iopgd_range(iopgd, iopgd);
+       }
+
+       flush_iotlb_all(obj);
+
+       spin_unlock(&obj->page_table_lock);
+}
+
+/*
+ *     Device IOMMU generic operations
+ */
+static irqreturn_t iommu_fault_handler(int irq, void *data)
+{
+       u32 stat, da;
+       u32 *iopgd, *iopte;
+       int err = -EIO;
+       struct iommu *obj = data;
+
+       if (!obj->refcount)
+               return IRQ_NONE;
+
+       /* Dynamic loading TLB or PTE */
+       if (obj->isr)
+               err = obj->isr(obj);
+
+       if (!err)
+               return IRQ_HANDLED;
+
+       clk_enable(obj->clk);
+       stat = iommu_report_fault(obj, &da);
+       clk_disable(obj->clk);
+       if (!stat)
+               return IRQ_HANDLED;
+
+       iopgd = iopgd_offset(obj, da);
+
+       if (!(*iopgd & IOPGD_TABLE)) {
+               dev_err(obj->dev, "%s: da:%08x pgd:%p *pgd:%08x\n", __func__,
+                       da, iopgd, *iopgd);
+               return IRQ_NONE;
+       }
+
+       iopte = iopte_offset(iopgd, da);
+
+       dev_err(obj->dev, "%s: da:%08x pgd:%p *pgd:%08x pte:%p *pte:%08x\n",
+               __func__, da, iopgd, *iopgd, iopte, *iopte);
+
+       return IRQ_NONE;
+}
+
+static int device_match_by_alias(struct device *dev, void *data)
+{
+       struct iommu *obj = to_iommu(dev);
+       const char *name = data;
+
+       pr_debug("%s: %s %s\n", __func__, obj->name, name);
+
+       return strcmp(obj->name, name) == 0;
+}
+
+/**
+ * iommu_get - Get iommu handler
+ * @name:      target iommu name
+ **/
+struct iommu *iommu_get(const char *name)
+{
+       int err = -ENOMEM;
+       struct device *dev;
+       struct iommu *obj;
+
+       dev = driver_find_device(&omap_iommu_driver.driver, NULL, (void *)name,
+                                device_match_by_alias);
+       if (!dev)
+               return ERR_PTR(-ENODEV);
+
+       obj = to_iommu(dev);
+
+       mutex_lock(&obj->iommu_lock);
+
+       if (obj->refcount++ == 0) {
+               err = iommu_enable(obj);
+               if (err)
+                       goto err_enable;
+               flush_iotlb_all(obj);
+       }
+
+       if (!try_module_get(obj->owner))
+               goto err_module;
+
+       mutex_unlock(&obj->iommu_lock);
+
+       dev_dbg(obj->dev, "%s: %s\n", __func__, obj->name);
+       return obj;
+
+err_module:
+       if (obj->refcount == 1)
+               iommu_disable(obj);
+err_enable:
+       obj->refcount--;
+       mutex_unlock(&obj->iommu_lock);
+       return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(iommu_get);
+
+/**
+ * iommu_put - Put back iommu handler
+ * @obj:       target iommu
+ **/
+void iommu_put(struct iommu *obj)
+{
+       if (!obj && IS_ERR(obj))
+               return;
+
+       mutex_lock(&obj->iommu_lock);
+
+       if (--obj->refcount == 0)
+               iommu_disable(obj);
+
+       module_put(obj->owner);
+
+       mutex_unlock(&obj->iommu_lock);
+
+       dev_dbg(obj->dev, "%s: %s\n", __func__, obj->name);
+}
+EXPORT_SYMBOL_GPL(iommu_put);
+
+/*
+ *     OMAP Device MMU(IOMMU) detection
+ */
+static int __devinit omap_iommu_probe(struct platform_device *pdev)
+{
+       int err = -ENODEV;
+       void *p;
+       int irq;
+       struct iommu *obj;
+       struct resource *res;
+       struct iommu_platform_data *pdata = pdev->dev.platform_data;
+
+       if (pdev->num_resources != 2)
+               return -EINVAL;
+
+       obj = kzalloc(sizeof(*obj) + MMU_REG_SIZE, GFP_KERNEL);
+       if (!obj)
+               return -ENOMEM;
+
+       obj->clk = clk_get(&pdev->dev, pdata->clk_name);
+       if (IS_ERR(obj->clk))
+               goto err_clk;
+
+       obj->nr_tlb_entries = pdata->nr_tlb_entries;
+       obj->name = pdata->name;
+       obj->dev = &pdev->dev;
+       obj->ctx = (void *)obj + sizeof(*obj);
+
+       mutex_init(&obj->iommu_lock);
+       mutex_init(&obj->mmap_lock);
+       spin_lock_init(&obj->page_table_lock);
+       INIT_LIST_HEAD(&obj->mmap);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               err = -ENODEV;
+               goto err_mem;
+       }
+       obj->regbase = ioremap(res->start, resource_size(res));
+       if (!obj->regbase) {
+               err = -ENOMEM;
+               goto err_mem;
+       }
+
+       res = request_mem_region(res->start, resource_size(res),
+                                dev_name(&pdev->dev));
+       if (!res) {
+               err = -EIO;
+               goto err_mem;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               err = -ENODEV;
+               goto err_irq;
+       }
+       err = request_irq(irq, iommu_fault_handler, IRQF_SHARED,
+                         dev_name(&pdev->dev), obj);
+       if (err < 0)
+               goto err_irq;
+       platform_set_drvdata(pdev, obj);
+
+       p = (void *)__get_free_pages(GFP_KERNEL, get_order(IOPGD_TABLE_SIZE));
+       if (!p) {
+               err = -ENOMEM;
+               goto err_pgd;
+       }
+       memset(p, 0, IOPGD_TABLE_SIZE);
+       clean_dcache_area(p, IOPGD_TABLE_SIZE);
+       obj->iopgd = p;
+
+       BUG_ON(!IS_ALIGNED((unsigned long)obj->iopgd, IOPGD_TABLE_SIZE));
+
+       dev_info(&pdev->dev, "%s registered\n", obj->name);
+       return 0;
+
+err_pgd:
+       free_irq(irq, obj);
+err_irq:
+       release_mem_region(res->start, resource_size(res));
+       iounmap(obj->regbase);
+err_mem:
+       clk_put(obj->clk);
+err_clk:
+       kfree(obj);
+       return err;
+}
+
+static int __devexit omap_iommu_remove(struct platform_device *pdev)
+{
+       int irq;
+       struct resource *res;
+       struct iommu *obj = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+
+       iopgtable_clear_entry_all(obj);
+       free_pages((unsigned long)obj->iopgd, get_order(IOPGD_TABLE_SIZE));
+
+       irq = platform_get_irq(pdev, 0);
+       free_irq(irq, obj);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(res->start, resource_size(res));
+       iounmap(obj->regbase);
+
+       clk_put(obj->clk);
+       dev_info(&pdev->dev, "%s removed\n", obj->name);
+       kfree(obj);
+       return 0;
+}
+
+static struct platform_driver omap_iommu_driver = {
+       .probe  = omap_iommu_probe,
+       .remove = __devexit_p(omap_iommu_remove),
+       .driver = {
+               .name   = "omap-iommu",
+       },
+};
+
+static void iopte_cachep_ctor(void *iopte)
+{
+       clean_dcache_area(iopte, IOPTE_TABLE_SIZE);
+}
+
+static int __init omap_iommu_init(void)
+{
+       struct kmem_cache *p;
+       const unsigned long flags = SLAB_HWCACHE_ALIGN;
+       size_t align = 1 << 10; /* L2 pagetable alignement */
+
+       p = kmem_cache_create("iopte_cache", IOPTE_TABLE_SIZE, align, flags,
+                             iopte_cachep_ctor);
+       if (!p)
+               return -ENOMEM;
+       iopte_cachep = p;
+
+       return platform_driver_register(&omap_iommu_driver);
+}
+module_init(omap_iommu_init);
+
+static void __exit omap_iommu_exit(void)
+{
+       kmem_cache_destroy(iopte_cachep);
+
+       platform_driver_unregister(&omap_iommu_driver);
+}
+module_exit(omap_iommu_exit);
+
+MODULE_DESCRIPTION("omap iommu: tlb and pagetable primitives");
+MODULE_ALIAS("platform:omap-iommu");
+MODULE_AUTHOR("Hiroshi DOYU, Paul Mundt and Toshihiro Kobayashi");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/plat-omap/iopgtable.h b/arch/arm/plat-omap/iopgtable.h
new file mode 100644 (file)
index 0000000..37dac43
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * omap iommu: pagetable definitions
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Written by Hiroshi DOYU <Hiroshi.DOYU@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.
+ */
+
+#ifndef __PLAT_OMAP_IOMMU_H
+#define __PLAT_OMAP_IOMMU_H
+
+#define IOPGD_SHIFT            20
+#define IOPGD_SIZE             (1 << IOPGD_SHIFT)
+#define IOPGD_MASK             (~(IOPGD_SIZE - 1))
+#define IOSECTION_MASK         IOPGD_MASK
+#define PTRS_PER_IOPGD         (1 << (32 - IOPGD_SHIFT))
+#define IOPGD_TABLE_SIZE       (PTRS_PER_IOPGD * sizeof(u32))
+
+#define IOSUPER_SIZE           (IOPGD_SIZE << 4)
+#define IOSUPER_MASK           (~(IOSUPER_SIZE - 1))
+
+#define IOPTE_SHIFT            12
+#define IOPTE_SIZE             (1 << IOPTE_SHIFT)
+#define IOPTE_MASK             (~(IOPTE_SIZE - 1))
+#define IOPAGE_MASK            IOPTE_MASK
+#define PTRS_PER_IOPTE         (1 << (IOPGD_SHIFT - IOPTE_SHIFT))
+#define IOPTE_TABLE_SIZE       (PTRS_PER_IOPTE * sizeof(u32))
+
+#define IOLARGE_SIZE           (IOPTE_SIZE << 4)
+#define IOLARGE_MASK           (~(IOLARGE_SIZE - 1))
+
+#define IOPGD_TABLE            (1 << 0)
+#define IOPGD_SECTION          (2 << 0)
+#define IOPGD_SUPER            (1 << 18 | 2 << 0)
+
+#define IOPTE_SMALL            (2 << 0)
+#define IOPTE_LARGE            (1 << 0)
+
+#define iopgd_index(da)                (((da) >> IOPGD_SHIFT) & (PTRS_PER_IOPGD - 1))
+#define iopgd_offset(obj, da)  ((obj)->iopgd + iopgd_index(da))
+
+#define iopte_paddr(iopgd)     (*iopgd & ~((1 << 10) - 1))
+#define iopte_vaddr(iopgd)     ((u32 *)phys_to_virt(iopte_paddr(iopgd)))
+
+#define iopte_index(da)                (((da) >> IOPTE_SHIFT) & (PTRS_PER_IOPTE - 1))
+#define iopte_offset(iopgd, da)        (iopte_vaddr(iopgd) + iopte_index(da))
+
+static inline u32 iotlb_init_entry(struct iotlb_entry *e, u32 da, u32 pa,
+                                  u32 flags)
+{
+       memset(e, 0, sizeof(*e));
+
+       e->da           = da;
+       e->pa           = pa;
+       e->valid        = 1;
+       /* FIXME: add OMAP1 support */
+       e->pgsz         = flags & MMU_CAM_PGSZ_MASK;
+       e->endian       = flags & MMU_RAM_ENDIAN_MASK;
+       e->elsz         = flags & MMU_RAM_ELSZ_MASK;
+       e->mixed        = flags & MMU_RAM_MIXED_MASK;
+
+       return iopgsz_to_bytes(e->pgsz);
+}
+
+#define to_iommu(dev)                                                  \
+       (struct iommu *)platform_get_drvdata(to_platform_device(dev))
+
+#endif /* __PLAT_OMAP_IOMMU_H */
diff --git a/arch/arm/plat-omap/iovmm.c b/arch/arm/plat-omap/iovmm.c
new file mode 100644 (file)
index 0000000..2fce2c1
--- /dev/null
@@ -0,0 +1,896 @@
+/*
+ * omap iommu: simple virtual address space management
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Written by Hiroshi DOYU <Hiroshi.DOYU@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/err.h>
+#include <linux/vmalloc.h>
+#include <linux/device.h>
+#include <linux/scatterlist.h>
+
+#include <asm/cacheflush.h>
+#include <asm/mach/map.h>
+
+#include <mach/iommu.h>
+#include <mach/iovmm.h>
+
+#include "iopgtable.h"
+
+/*
+ * A device driver needs to create address mappings between:
+ *
+ * - iommu/device address
+ * - physical address
+ * - mpu virtual address
+ *
+ * There are 4 possible patterns for them:
+ *
+ *    |iova/                     mapping               iommu_          page
+ *    | da     pa      va      (d)-(p)-(v)             function        type
+ *  ---------------------------------------------------------------------------
+ *  1 | c      c       c        1 - 1 - 1        _kmap() / _kunmap()   s
+ *  2 | c      c,a     c        1 - 1 - 1      _kmalloc()/ _kfree()    s
+ *  3 | c      d       c        1 - n - 1        _vmap() / _vunmap()   s
+ *  4 | c      d,a     c        1 - n - 1      _vmalloc()/ _vfree()    n*
+ *
+ *
+ *     'iova': device iommu virtual address
+ *     'da':   alias of 'iova'
+ *     'pa':   physical address
+ *     'va':   mpu virtual address
+ *
+ *     'c':    contiguous memory area
+ *     'd':    dicontiguous memory area
+ *     'a':    anonymous memory allocation
+ *     '()':   optional feature
+ *
+ *     'n':    a normal page(4KB) size is used.
+ *     's':    multiple iommu superpage(16MB, 1MB, 64KB, 4KB) size is used.
+ *
+ *     '*':    not yet, but feasible.
+ */
+
+static struct kmem_cache *iovm_area_cachep;
+
+/* return total bytes of sg buffers */
+static size_t sgtable_len(const struct sg_table *sgt)
+{
+       unsigned int i, total = 0;
+       struct scatterlist *sg;
+
+       if (!sgt)
+               return 0;
+
+       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+               size_t bytes;
+
+               bytes = sg_dma_len(sg);
+
+               if (!iopgsz_ok(bytes)) {
+                       pr_err("%s: sg[%d] not iommu pagesize(%x)\n",
+                              __func__, i, bytes);
+                       return 0;
+               }
+
+               total += bytes;
+       }
+
+       return total;
+}
+#define sgtable_ok(x)  (!!sgtable_len(x))
+
+/*
+ * calculate the optimal number sg elements from total bytes based on
+ * iommu superpages
+ */
+static unsigned int sgtable_nents(size_t bytes)
+{
+       int i;
+       unsigned int nr_entries;
+       const unsigned long pagesize[] = { SZ_16M, SZ_1M, SZ_64K, SZ_4K, };
+
+       if (!IS_ALIGNED(bytes, PAGE_SIZE)) {
+               pr_err("%s: wrong size %08x\n", __func__, bytes);
+               return 0;
+       }
+
+       nr_entries = 0;
+       for (i = 0; i < ARRAY_SIZE(pagesize); i++) {
+               if (bytes >= pagesize[i]) {
+                       nr_entries += (bytes / pagesize[i]);
+                       bytes %= pagesize[i];
+               }
+       }
+       BUG_ON(bytes);
+
+       return nr_entries;
+}
+
+/* allocate and initialize sg_table header(a kind of 'superblock') */
+static struct sg_table *sgtable_alloc(const size_t bytes, u32 flags)
+{
+       unsigned int nr_entries;
+       int err;
+       struct sg_table *sgt;
+
+       if (!bytes)
+               return ERR_PTR(-EINVAL);
+
+       if (!IS_ALIGNED(bytes, PAGE_SIZE))
+               return ERR_PTR(-EINVAL);
+
+       /* FIXME: IOVMF_DA_FIXED should support 'superpages' */
+       if ((flags & IOVMF_LINEAR) && (flags & IOVMF_DA_ANON)) {
+               nr_entries = sgtable_nents(bytes);
+               if (!nr_entries)
+                       return ERR_PTR(-EINVAL);
+       } else
+               nr_entries =  bytes / PAGE_SIZE;
+
+       sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
+       if (!sgt)
+               return ERR_PTR(-ENOMEM);
+
+       err = sg_alloc_table(sgt, nr_entries, GFP_KERNEL);
+       if (err)
+               return ERR_PTR(err);
+
+       pr_debug("%s: sgt:%p(%d entries)\n", __func__, sgt, nr_entries);
+
+       return sgt;
+}
+
+/* free sg_table header(a kind of superblock) */
+static void sgtable_free(struct sg_table *sgt)
+{
+       if (!sgt)
+               return;
+
+       sg_free_table(sgt);
+       kfree(sgt);
+
+       pr_debug("%s: sgt:%p\n", __func__, sgt);
+}
+
+/* map 'sglist' to a contiguous mpu virtual area and return 'va' */
+static void *vmap_sg(const struct sg_table *sgt)
+{
+       u32 va;
+       size_t total;
+       unsigned int i;
+       struct scatterlist *sg;
+       struct vm_struct *new;
+       const struct mem_type *mtype;
+
+       mtype = get_mem_type(MT_DEVICE);
+       if (!mtype)
+               return ERR_PTR(-EINVAL);
+
+       total = sgtable_len(sgt);
+       if (!total)
+               return ERR_PTR(-EINVAL);
+
+       new = __get_vm_area(total, VM_IOREMAP, VMALLOC_START, VMALLOC_END);
+       if (!new)
+               return ERR_PTR(-ENOMEM);
+       va = (u32)new->addr;
+
+       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+               size_t bytes;
+               u32 pa;
+               int err;
+
+               pa = sg_phys(sg);
+               bytes = sg_dma_len(sg);
+
+               BUG_ON(bytes != PAGE_SIZE);
+
+               err = ioremap_page(va,  pa, mtype);
+               if (err)
+                       goto err_out;
+
+               va += bytes;
+       }
+
+       flush_cache_vmap(new->addr, total);
+       return new->addr;
+
+err_out:
+       WARN_ON(1); /* FIXME: cleanup some mpu mappings */
+       vunmap(new->addr);
+       return ERR_PTR(-EAGAIN);
+}
+
+static inline void vunmap_sg(const void *va)
+{
+       vunmap(va);
+}
+
+static struct iovm_struct *__find_iovm_area(struct iommu *obj, const u32 da)
+{
+       struct iovm_struct *tmp;
+
+       list_for_each_entry(tmp, &obj->mmap, list) {
+               if ((da >= tmp->da_start) && (da < tmp->da_end)) {
+                       size_t len;
+
+                       len = tmp->da_end - tmp->da_start;
+
+                       dev_dbg(obj->dev, "%s: %08x-%08x-%08x(%x) %08x\n",
+                               __func__, tmp->da_start, da, tmp->da_end, len,
+                               tmp->flags);
+
+                       return tmp;
+               }
+       }
+
+       return NULL;
+}
+
+/**
+ * find_iovm_area  -  find iovma which includes @da
+ * @da:                iommu device virtual address
+ *
+ * Find the existing iovma starting at @da
+ */
+struct iovm_struct *find_iovm_area(struct iommu *obj, u32 da)
+{
+       struct iovm_struct *area;
+
+       mutex_lock(&obj->mmap_lock);
+       area = __find_iovm_area(obj, da);
+       mutex_unlock(&obj->mmap_lock);
+
+       return area;
+}
+EXPORT_SYMBOL_GPL(find_iovm_area);
+
+/*
+ * This finds the hole(area) which fits the requested address and len
+ * in iovmas mmap, and returns the new allocated iovma.
+ */
+static struct iovm_struct *alloc_iovm_area(struct iommu *obj, u32 da,
+                                          size_t bytes, u32 flags)
+{
+       struct iovm_struct *new, *tmp;
+       u32 start, prev_end, alignement;
+
+       if (!obj || !bytes)
+               return ERR_PTR(-EINVAL);
+
+       start = da;
+       alignement = PAGE_SIZE;
+
+       if (flags & IOVMF_DA_ANON) {
+               /*
+                * Reserve the first page for NULL
+                */
+               start = PAGE_SIZE;
+               if (flags & IOVMF_LINEAR)
+                       alignement = iopgsz_max(bytes);
+               start = roundup(start, alignement);
+       }
+
+       tmp = NULL;
+       if (list_empty(&obj->mmap))
+               goto found;
+
+       prev_end = 0;
+       list_for_each_entry(tmp, &obj->mmap, list) {
+
+               if ((prev_end <= start) && (start + bytes < tmp->da_start))
+                       goto found;
+
+               if (flags & IOVMF_DA_ANON)
+                       start = roundup(tmp->da_end, alignement);
+
+               prev_end = tmp->da_end;
+       }
+
+       if ((start >= prev_end) && (ULONG_MAX - start >= bytes))
+               goto found;
+
+       dev_dbg(obj->dev, "%s: no space to fit %08x(%x) flags: %08x\n",
+               __func__, da, bytes, flags);
+
+       return ERR_PTR(-EINVAL);
+
+found:
+       new = kmem_cache_zalloc(iovm_area_cachep, GFP_KERNEL);
+       if (!new)
+               return ERR_PTR(-ENOMEM);
+
+       new->iommu = obj;
+       new->da_start = start;
+       new->da_end = start + bytes;
+       new->flags = flags;
+
+       /*
+        * keep ascending order of iovmas
+        */
+       if (tmp)
+               list_add_tail(&new->list, &tmp->list);
+       else
+               list_add(&new->list, &obj->mmap);
+
+       dev_dbg(obj->dev, "%s: found %08x-%08x-%08x(%x) %08x\n",
+               __func__, new->da_start, start, new->da_end, bytes, flags);
+
+       return new;
+}
+
+static void free_iovm_area(struct iommu *obj, struct iovm_struct *area)
+{
+       size_t bytes;
+
+       BUG_ON(!obj || !area);
+
+       bytes = area->da_end - area->da_start;
+
+       dev_dbg(obj->dev, "%s: %08x-%08x(%x) %08x\n",
+               __func__, area->da_start, area->da_end, bytes, area->flags);
+
+       list_del(&area->list);
+       kmem_cache_free(iovm_area_cachep, area);
+}
+
+/**
+ * da_to_va - convert (d) to (v)
+ * @obj:       objective iommu
+ * @da:                iommu device virtual address
+ * @va:                mpu virtual address
+ *
+ * Returns mpu virtual addr which corresponds to a given device virtual addr
+ */
+void *da_to_va(struct iommu *obj, u32 da)
+{
+       void *va = NULL;
+       struct iovm_struct *area;
+
+       mutex_lock(&obj->mmap_lock);
+
+       area = __find_iovm_area(obj, da);
+       if (!area) {
+               dev_dbg(obj->dev, "%s: no da area(%08x)\n", __func__, da);
+               goto out;
+       }
+       va = area->va;
+       mutex_unlock(&obj->mmap_lock);
+out:
+       return va;
+}
+EXPORT_SYMBOL_GPL(da_to_va);
+
+static void sgtable_fill_vmalloc(struct sg_table *sgt, void *_va)
+{
+       unsigned int i;
+       struct scatterlist *sg;
+       void *va = _va;
+       void *va_end;
+
+       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+               struct page *pg;
+               const size_t bytes = PAGE_SIZE;
+
+               /*
+                * iommu 'superpage' isn't supported with 'iommu_vmalloc()'
+                */
+               pg = vmalloc_to_page(va);
+               BUG_ON(!pg);
+               sg_set_page(sg, pg, bytes, 0);
+
+               va += bytes;
+       }
+
+       va_end = _va + PAGE_SIZE * i;
+       flush_cache_vmap(_va, va_end);
+}
+
+static inline void sgtable_drain_vmalloc(struct sg_table *sgt)
+{
+       /*
+        * Actually this is not necessary at all, just exists for
+        * consistency of the code readibility.
+        */
+       BUG_ON(!sgt);
+}
+
+static void sgtable_fill_kmalloc(struct sg_table *sgt, u32 pa, size_t len)
+{
+       unsigned int i;
+       struct scatterlist *sg;
+       void *va;
+
+       va = phys_to_virt(pa);
+
+       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+               size_t bytes;
+
+               bytes = iopgsz_max(len);
+
+               BUG_ON(!iopgsz_ok(bytes));
+
+               sg_set_buf(sg, phys_to_virt(pa), bytes);
+               /*
+                * 'pa' is cotinuous(linear).
+                */
+               pa += bytes;
+               len -= bytes;
+       }
+       BUG_ON(len);
+
+       clean_dcache_area(va, len);
+}
+
+static inline void sgtable_drain_kmalloc(struct sg_table *sgt)
+{
+       /*
+        * Actually this is not necessary at all, just exists for
+        * consistency of the code readibility
+        */
+       BUG_ON(!sgt);
+}
+
+/* create 'da' <-> 'pa' mapping from 'sgt' */
+static int map_iovm_area(struct iommu *obj, struct iovm_struct *new,
+                        const struct sg_table *sgt, u32 flags)
+{
+       int err;
+       unsigned int i, j;
+       struct scatterlist *sg;
+       u32 da = new->da_start;
+
+       if (!obj || !new || !sgt)
+               return -EINVAL;
+
+       BUG_ON(!sgtable_ok(sgt));
+
+       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+               u32 pa;
+               int pgsz;
+               size_t bytes;
+               struct iotlb_entry e;
+
+               pa = sg_phys(sg);
+               bytes = sg_dma_len(sg);
+
+               flags &= ~IOVMF_PGSZ_MASK;
+               pgsz = bytes_to_iopgsz(bytes);
+               if (pgsz < 0)
+                       goto err_out;
+               flags |= pgsz;
+
+               pr_debug("%s: [%d] %08x %08x(%x)\n", __func__,
+                        i, da, pa, bytes);
+
+               iotlb_init_entry(&e, da, pa, flags);
+               err = iopgtable_store_entry(obj, &e);
+               if (err)
+                       goto err_out;
+
+               da += bytes;
+       }
+       return 0;
+
+err_out:
+       da = new->da_start;
+
+       for_each_sg(sgt->sgl, sg, i, j) {
+               size_t bytes;
+
+               bytes = iopgtable_clear_entry(obj, da);
+
+               BUG_ON(!iopgsz_ok(bytes));
+
+               da += bytes;
+       }
+       return err;
+}
+
+/* release 'da' <-> 'pa' mapping */
+static void unmap_iovm_area(struct iommu *obj, struct iovm_struct *area)
+{
+       u32 start;
+       size_t total = area->da_end - area->da_start;
+
+       BUG_ON((!total) || !IS_ALIGNED(total, PAGE_SIZE));
+
+       start = area->da_start;
+       while (total > 0) {
+               size_t bytes;
+
+               bytes = iopgtable_clear_entry(obj, start);
+               if (bytes == 0)
+                       bytes = PAGE_SIZE;
+               else
+                       dev_dbg(obj->dev, "%s: unmap %08x(%x) %08x\n",
+                               __func__, start, bytes, area->flags);
+
+               BUG_ON(!IS_ALIGNED(bytes, PAGE_SIZE));
+
+               total -= bytes;
+               start += bytes;
+       }
+       BUG_ON(total);
+}
+
+/* template function for all unmapping */
+static struct sg_table *unmap_vm_area(struct iommu *obj, const u32 da,
+                                     void (*fn)(const void *), u32 flags)
+{
+       struct sg_table *sgt = NULL;
+       struct iovm_struct *area;
+
+       if (!IS_ALIGNED(da, PAGE_SIZE)) {
+               dev_err(obj->dev, "%s: alignment err(%08x)\n", __func__, da);
+               return NULL;
+       }
+
+       mutex_lock(&obj->mmap_lock);
+
+       area = __find_iovm_area(obj, da);
+       if (!area) {
+               dev_dbg(obj->dev, "%s: no da area(%08x)\n", __func__, da);
+               goto out;
+       }
+
+       if ((area->flags & flags) != flags) {
+               dev_err(obj->dev, "%s: wrong flags(%08x)\n", __func__,
+                       area->flags);
+               goto out;
+       }
+       sgt = (struct sg_table *)area->sgt;
+
+       unmap_iovm_area(obj, area);
+
+       fn(area->va);
+
+       dev_dbg(obj->dev, "%s: %08x-%08x-%08x(%x) %08x\n", __func__,
+               area->da_start, da, area->da_end,
+               area->da_end - area->da_start, area->flags);
+
+       free_iovm_area(obj, area);
+out:
+       mutex_unlock(&obj->mmap_lock);
+
+       return sgt;
+}
+
+static u32 map_iommu_region(struct iommu *obj, u32 da,
+             const struct sg_table *sgt, void *va, size_t bytes, u32 flags)
+{
+       int err = -ENOMEM;
+       struct iovm_struct *new;
+
+       mutex_lock(&obj->mmap_lock);
+
+       new = alloc_iovm_area(obj, da, bytes, flags);
+       if (IS_ERR(new)) {
+               err = PTR_ERR(new);
+               goto err_alloc_iovma;
+       }
+       new->va = va;
+       new->sgt = sgt;
+
+       if (map_iovm_area(obj, new, sgt, new->flags))
+               goto err_map;
+
+       mutex_unlock(&obj->mmap_lock);
+
+       dev_dbg(obj->dev, "%s: da:%08x(%x) flags:%08x va:%p\n",
+               __func__, new->da_start, bytes, new->flags, va);
+
+       return new->da_start;
+
+err_map:
+       free_iovm_area(obj, new);
+err_alloc_iovma:
+       mutex_unlock(&obj->mmap_lock);
+       return err;
+}
+
+static inline u32 __iommu_vmap(struct iommu *obj, u32 da,
+                const struct sg_table *sgt, void *va, size_t bytes, u32 flags)
+{
+       return map_iommu_region(obj, da, sgt, va, bytes, flags);
+}
+
+/**
+ * iommu_vmap  -  (d)-(p)-(v) address mapper
+ * @obj:       objective iommu
+ * @sgt:       address of scatter gather table
+ * @flags:     iovma and page property
+ *
+ * Creates 1-n-1 mapping with given @sgt and returns @da.
+ * All @sgt element must be io page size aligned.
+ */
+u32 iommu_vmap(struct iommu *obj, u32 da, const struct sg_table *sgt,
+                u32 flags)
+{
+       size_t bytes;
+       void *va;
+
+       if (!obj || !obj->dev || !sgt)
+               return -EINVAL;
+
+       bytes = sgtable_len(sgt);
+       if (!bytes)
+               return -EINVAL;
+       bytes = PAGE_ALIGN(bytes);
+
+       va = vmap_sg(sgt);
+       if (IS_ERR(va))
+               return PTR_ERR(va);
+
+       flags &= IOVMF_HW_MASK;
+       flags |= IOVMF_DISCONT;
+       flags |= IOVMF_MMIO;
+       flags |= (da ? IOVMF_DA_FIXED : IOVMF_DA_ANON);
+
+       da = __iommu_vmap(obj, da, sgt, va, bytes, flags);
+       if (IS_ERR_VALUE(da))
+               vunmap_sg(va);
+
+       return da;
+}
+EXPORT_SYMBOL_GPL(iommu_vmap);
+
+/**
+ * iommu_vunmap  -  release virtual mapping obtained by 'iommu_vmap()'
+ * @obj:       objective iommu
+ * @da:                iommu device virtual address
+ *
+ * Free the iommu virtually contiguous memory area starting at
+ * @da, which was returned by 'iommu_vmap()'.
+ */
+struct sg_table *iommu_vunmap(struct iommu *obj, u32 da)
+{
+       struct sg_table *sgt;
+       /*
+        * 'sgt' is allocated before 'iommu_vmalloc()' is called.
+        * Just returns 'sgt' to the caller to free
+        */
+       sgt = unmap_vm_area(obj, da, vunmap_sg, IOVMF_DISCONT | IOVMF_MMIO);
+       if (!sgt)
+               dev_dbg(obj->dev, "%s: No sgt\n", __func__);
+       return sgt;
+}
+EXPORT_SYMBOL_GPL(iommu_vunmap);
+
+/**
+ * iommu_vmalloc  -  (d)-(p)-(v) address allocator and mapper
+ * @obj:       objective iommu
+ * @da:                contiguous iommu virtual memory
+ * @bytes:     allocation size
+ * @flags:     iovma and page property
+ *
+ * Allocate @bytes linearly and creates 1-n-1 mapping and returns
+ * @da again, which might be adjusted if 'IOVMF_DA_ANON' is set.
+ */
+u32 iommu_vmalloc(struct iommu *obj, u32 da, size_t bytes, u32 flags)
+{
+       void *va;
+       struct sg_table *sgt;
+
+       if (!obj || !obj->dev || !bytes)
+               return -EINVAL;
+
+       bytes = PAGE_ALIGN(bytes);
+
+       va = vmalloc(bytes);
+       if (!va)
+               return -ENOMEM;
+
+       sgt = sgtable_alloc(bytes, flags);
+       if (IS_ERR(sgt)) {
+               da = PTR_ERR(sgt);
+               goto err_sgt_alloc;
+       }
+       sgtable_fill_vmalloc(sgt, va);
+
+       flags &= IOVMF_HW_MASK;
+       flags |= IOVMF_DISCONT;
+       flags |= IOVMF_ALLOC;
+       flags |= (da ? IOVMF_DA_FIXED : IOVMF_DA_ANON);
+
+       da = __iommu_vmap(obj, da, sgt, va, bytes, flags);
+       if (IS_ERR_VALUE(da))
+               goto err_iommu_vmap;
+
+       return da;
+
+err_iommu_vmap:
+       sgtable_drain_vmalloc(sgt);
+       sgtable_free(sgt);
+err_sgt_alloc:
+       vfree(va);
+       return da;
+}
+EXPORT_SYMBOL_GPL(iommu_vmalloc);
+
+/**
+ * iommu_vfree  -  release memory allocated by 'iommu_vmalloc()'
+ * @obj:       objective iommu
+ * @da:                iommu device virtual address
+ *
+ * Frees the iommu virtually continuous memory area starting at
+ * @da, as obtained from 'iommu_vmalloc()'.
+ */
+void iommu_vfree(struct iommu *obj, const u32 da)
+{
+       struct sg_table *sgt;
+
+       sgt = unmap_vm_area(obj, da, vfree, IOVMF_DISCONT | IOVMF_ALLOC);
+       if (!sgt)
+               dev_dbg(obj->dev, "%s: No sgt\n", __func__);
+       sgtable_free(sgt);
+}
+EXPORT_SYMBOL_GPL(iommu_vfree);
+
+static u32 __iommu_kmap(struct iommu *obj, u32 da, u32 pa, void *va,
+                         size_t bytes, u32 flags)
+{
+       struct sg_table *sgt;
+
+       sgt = sgtable_alloc(bytes, flags);
+       if (IS_ERR(sgt))
+               return PTR_ERR(sgt);
+
+       sgtable_fill_kmalloc(sgt, pa, bytes);
+
+       da = map_iommu_region(obj, da, sgt, va, bytes, flags);
+       if (IS_ERR_VALUE(da)) {
+               sgtable_drain_kmalloc(sgt);
+               sgtable_free(sgt);
+       }
+
+       return da;
+}
+
+/**
+ * iommu_kmap  -  (d)-(p)-(v) address mapper
+ * @obj:       objective iommu
+ * @da:                contiguous iommu virtual memory
+ * @pa:                contiguous physical memory
+ * @flags:     iovma and page property
+ *
+ * Creates 1-1-1 mapping and returns @da again, which can be
+ * adjusted if 'IOVMF_DA_ANON' is set.
+ */
+u32 iommu_kmap(struct iommu *obj, u32 da, u32 pa, size_t bytes,
+                u32 flags)
+{
+       void *va;
+
+       if (!obj || !obj->dev || !bytes)
+               return -EINVAL;
+
+       bytes = PAGE_ALIGN(bytes);
+
+       va = ioremap(pa, bytes);
+       if (!va)
+               return -ENOMEM;
+
+       flags &= IOVMF_HW_MASK;
+       flags |= IOVMF_LINEAR;
+       flags |= IOVMF_MMIO;
+       flags |= (da ? IOVMF_DA_FIXED : IOVMF_DA_ANON);
+
+       da = __iommu_kmap(obj, da, pa, va, bytes, flags);
+       if (IS_ERR_VALUE(da))
+               iounmap(va);
+
+       return da;
+}
+EXPORT_SYMBOL_GPL(iommu_kmap);
+
+/**
+ * iommu_kunmap  -  release virtual mapping obtained by 'iommu_kmap()'
+ * @obj:       objective iommu
+ * @da:                iommu device virtual address
+ *
+ * Frees the iommu virtually contiguous memory area starting at
+ * @da, which was passed to and was returned by'iommu_kmap()'.
+ */
+void iommu_kunmap(struct iommu *obj, u32 da)
+{
+       struct sg_table *sgt;
+       typedef void (*func_t)(const void *);
+
+       sgt = unmap_vm_area(obj, da, (func_t)__iounmap,
+                           IOVMF_LINEAR | IOVMF_MMIO);
+       if (!sgt)
+               dev_dbg(obj->dev, "%s: No sgt\n", __func__);
+       sgtable_free(sgt);
+}
+EXPORT_SYMBOL_GPL(iommu_kunmap);
+
+/**
+ * iommu_kmalloc  -  (d)-(p)-(v) address allocator and mapper
+ * @obj:       objective iommu
+ * @da:                contiguous iommu virtual memory
+ * @bytes:     bytes for allocation
+ * @flags:     iovma and page property
+ *
+ * Allocate @bytes linearly and creates 1-1-1 mapping and returns
+ * @da again, which might be adjusted if 'IOVMF_DA_ANON' is set.
+ */
+u32 iommu_kmalloc(struct iommu *obj, u32 da, size_t bytes, u32 flags)
+{
+       void *va;
+       u32 pa;
+
+       if (!obj || !obj->dev || !bytes)
+               return -EINVAL;
+
+       bytes = PAGE_ALIGN(bytes);
+
+       va = kmalloc(bytes, GFP_KERNEL | GFP_DMA);
+       if (!va)
+               return -ENOMEM;
+       pa = virt_to_phys(va);
+
+       flags &= IOVMF_HW_MASK;
+       flags |= IOVMF_LINEAR;
+       flags |= IOVMF_ALLOC;
+       flags |= (da ? IOVMF_DA_FIXED : IOVMF_DA_ANON);
+
+       da = __iommu_kmap(obj, da, pa, va, bytes, flags);
+       if (IS_ERR_VALUE(da))
+               kfree(va);
+
+       return da;
+}
+EXPORT_SYMBOL_GPL(iommu_kmalloc);
+
+/**
+ * iommu_kfree  -  release virtual mapping obtained by 'iommu_kmalloc()'
+ * @obj:       objective iommu
+ * @da:                iommu device virtual address
+ *
+ * Frees the iommu virtually contiguous memory area starting at
+ * @da, which was passed to and was returned by'iommu_kmalloc()'.
+ */
+void iommu_kfree(struct iommu *obj, u32 da)
+{
+       struct sg_table *sgt;
+
+       sgt = unmap_vm_area(obj, da, kfree, IOVMF_LINEAR | IOVMF_ALLOC);
+       if (!sgt)
+               dev_dbg(obj->dev, "%s: No sgt\n", __func__);
+       sgtable_free(sgt);
+}
+EXPORT_SYMBOL_GPL(iommu_kfree);
+
+
+static int __init iovmm_init(void)
+{
+       const unsigned long flags = SLAB_HWCACHE_ALIGN;
+       struct kmem_cache *p;
+
+       p = kmem_cache_create("iovm_area_cache", sizeof(struct iovm_struct), 0,
+                             flags, NULL);
+       if (!p)
+               return -ENOMEM;
+       iovm_area_cachep = p;
+
+       return 0;
+}
+module_init(iovmm_init);
+
+static void __exit iovmm_exit(void)
+{
+       kmem_cache_destroy(iovm_area_cachep);
+}
+module_exit(iovmm_exit);
+
+MODULE_DESCRIPTION("omap iommu: simple virtual address space management");
+MODULE_AUTHOR("Hiroshi DOYU <Hiroshi.DOYU@nokia.com>");
+MODULE_LICENSE("GPL v2");
index 28b0a824b8cfa1bff4f7d2b4ea27cd494bd1bfbe..efa0e0111f38815f4416634bc31427d786e8fced 100644 (file)
@@ -91,11 +91,20 @@ static void omap_mcbsp_dump_reg(u8 id)
 static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id)
 {
        struct omap_mcbsp *mcbsp_tx = dev_id;
+       u16 irqst_spcr2;
 
-       dev_dbg(mcbsp_tx->dev, "TX IRQ callback : 0x%x\n",
-               OMAP_MCBSP_READ(mcbsp_tx->io_base, SPCR2));
+       irqst_spcr2 = OMAP_MCBSP_READ(mcbsp_tx->io_base, SPCR2);
+       dev_dbg(mcbsp_tx->dev, "TX IRQ callback : 0x%x\n", irqst_spcr2);
 
-       complete(&mcbsp_tx->tx_irq_completion);
+       if (irqst_spcr2 & XSYNC_ERR) {
+               dev_err(mcbsp_tx->dev, "TX Frame Sync Error! : 0x%x\n",
+                       irqst_spcr2);
+               /* Writing zero to XSYNC_ERR clears the IRQ */
+               OMAP_MCBSP_WRITE(mcbsp_tx->io_base, SPCR2,
+                       irqst_spcr2 & ~(XSYNC_ERR));
+       } else {
+               complete(&mcbsp_tx->tx_irq_completion);
+       }
 
        return IRQ_HANDLED;
 }
@@ -103,11 +112,20 @@ static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id)
 static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id)
 {
        struct omap_mcbsp *mcbsp_rx = dev_id;
+       u16 irqst_spcr1;
 
-       dev_dbg(mcbsp_rx->dev, "RX IRQ callback : 0x%x\n",
-               OMAP_MCBSP_READ(mcbsp_rx->io_base, SPCR2));
+       irqst_spcr1 = OMAP_MCBSP_READ(mcbsp_rx->io_base, SPCR1);
+       dev_dbg(mcbsp_rx->dev, "RX IRQ callback : 0x%x\n", irqst_spcr1);
 
-       complete(&mcbsp_rx->rx_irq_completion);
+       if (irqst_spcr1 & RSYNC_ERR) {
+               dev_err(mcbsp_rx->dev, "RX Frame Sync Error! : 0x%x\n",
+                       irqst_spcr1);
+               /* Writing zero to RSYNC_ERR clears the IRQ */
+               OMAP_MCBSP_WRITE(mcbsp_rx->io_base, SPCR1,
+                       irqst_spcr1 & ~(RSYNC_ERR));
+       } else {
+               complete(&mcbsp_rx->tx_irq_completion);
+       }
 
        return IRQ_HANDLED;
 }
index 80b040fd5ca79fc55cb8ba42111596be48ce10bc..8d329fb20740886493c6402c35b6f8db290f1eab 100644 (file)
@@ -54,6 +54,9 @@ int __init_or_module omap_cfg_reg(const unsigned long index)
 {
        struct pin_config *reg;
 
+       if (cpu_is_omap44xx())
+               return 0;
+
        if (mux_cfg == NULL) {
                printk(KERN_ERR "Pin mux table not initialized\n");
                return -ENODEV;
index fa5297d643d3f545d181551bdee853a2a0938251..a5b9bcd6b10821c5ad38166e0600c5ceba924fb5 100644 (file)
@@ -6,6 +6,9 @@
  * Copyright (C) 2005 Nokia Corporation
  * Written by Tony Lindgren <tony@atomide.com>
  *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
 #define OMAP1_SRAM_VA          VMALLOC_END
 #define OMAP2_SRAM_PA          0x40200000
 #define OMAP2_SRAM_PUB_PA      0x4020f800
-#define OMAP2_SRAM_VA          VMALLOC_END
-#define OMAP2_SRAM_PUB_VA      (VMALLOC_END + 0x800)
+#define OMAP2_SRAM_VA          0xe3000000
+#define OMAP2_SRAM_PUB_VA      (OMAP2_SRAM_VA + 0x800)
 #define OMAP3_SRAM_PA           0x40200000
 #define OMAP3_SRAM_VA           0xd7000000
 #define OMAP3_SRAM_PUB_PA       0x40208000
 #define OMAP3_SRAM_PUB_VA       0xd7008000
+#define OMAP4_SRAM_PA          0x40200000              /*0x402f0000*/
+#define OMAP4_SRAM_VA          0xd7000000              /*0xd70f0000*/
 
 #if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
 #define SRAM_BOOTLOADER_SZ     0x00
@@ -87,6 +92,10 @@ static int is_sram_locked(void)
 {
        int type = 0;
 
+       if (cpu_is_omap44xx())
+               /* Not yet supported */
+               return 0;
+
        if (cpu_is_omap242x())
                type = omap_rev() & OMAP2_DEVICETYPE_MASK;
 
@@ -135,6 +144,10 @@ void __init omap_detect_sram(void)
                                omap_sram_base = OMAP3_SRAM_VA;
                                omap_sram_start = OMAP3_SRAM_PA;
                                omap_sram_size = 0x10000; /* 64K */
+                       } else if (cpu_is_omap44xx()) {
+                               omap_sram_base = OMAP4_SRAM_VA;
+                               omap_sram_start = OMAP4_SRAM_PA;
+                               omap_sram_size = 0x8000; /* 32K */
                        } else {
                                omap_sram_base = OMAP2_SRAM_VA;
                                omap_sram_start = OMAP2_SRAM_PA;
@@ -201,8 +214,23 @@ void __init omap_map_sram(void)
                base = OMAP3_SRAM_PA;
                base = ROUND_DOWN(base, PAGE_SIZE);
                omap_sram_io_desc[0].pfn = __phys_to_pfn(base);
+
+               /*
+                * SRAM must be marked as non-cached on OMAP3 since the
+                * CORE DPLL M2 divider change code (in SRAM) runs with the
+                * SDRAM controller disabled, and if it is marked cached,
+                * the ARM may attempt to write cache lines back to SDRAM
+                * which will cause the system to hang.
+                */
+               omap_sram_io_desc[0].type = MT_MEMORY_NONCACHED;
        }
 
+       if (cpu_is_omap44xx()) {
+               omap_sram_io_desc[0].virtual = OMAP4_SRAM_VA;
+               base = OMAP4_SRAM_PA;
+               base = ROUND_DOWN(base, PAGE_SIZE);
+               omap_sram_io_desc[0].pfn = __phys_to_pfn(base);
+       }
        omap_sram_io_desc[0].length = 1024 * 1024;      /* Use section desc */
        iotable_init(omap_sram_io_desc, ARRAY_SIZE(omap_sram_io_desc));
 
@@ -242,20 +270,13 @@ void * omap_sram_push(void * start, unsigned long size)
        return (void *)omap_sram_ceil;
 }
 
-static void omap_sram_error(void)
-{
-       panic("Uninitialized SRAM function\n");
-}
-
 #ifdef CONFIG_ARCH_OMAP1
 
 static void (*_omap_sram_reprogram_clock)(u32 dpllctl, u32 ckctl);
 
 void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl)
 {
-       if (!_omap_sram_reprogram_clock)
-               omap_sram_error();
-
+       BUG_ON(!_omap_sram_reprogram_clock);
        _omap_sram_reprogram_clock(dpllctl, ckctl);
 }
 
@@ -280,9 +301,7 @@ static void (*_omap2_sram_ddr_init)(u32 *slow_dll_ctrl, u32 fast_dll_ctrl,
 void omap2_sram_ddr_init(u32 *slow_dll_ctrl, u32 fast_dll_ctrl,
                   u32 base_cs, u32 force_unlock)
 {
-       if (!_omap2_sram_ddr_init)
-               omap_sram_error();
-
+       BUG_ON(!_omap2_sram_ddr_init);
        _omap2_sram_ddr_init(slow_dll_ctrl, fast_dll_ctrl,
                             base_cs, force_unlock);
 }
@@ -292,9 +311,7 @@ static void (*_omap2_sram_reprogram_sdrc)(u32 perf_level, u32 dll_val,
 
 void omap2_sram_reprogram_sdrc(u32 perf_level, u32 dll_val, u32 mem_type)
 {
-       if (!_omap2_sram_reprogram_sdrc)
-               omap_sram_error();
-
+       BUG_ON(!_omap2_sram_reprogram_sdrc);
        _omap2_sram_reprogram_sdrc(perf_level, dll_val, mem_type);
 }
 
@@ -302,9 +319,7 @@ static u32 (*_omap2_set_prcm)(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass);
 
 u32 omap2_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass)
 {
-       if (!_omap2_set_prcm)
-               omap_sram_error();
-
+       BUG_ON(!_omap2_set_prcm);
        return _omap2_set_prcm(dpll_ctrl_val, sdrc_rfr_val, bypass);
 }
 #endif
@@ -356,16 +371,15 @@ static inline int omap243x_sram_init(void)
 static u32 (*_omap3_sram_configure_core_dpll)(u32 sdrc_rfr_ctrl,
                                              u32 sdrc_actim_ctrla,
                                              u32 sdrc_actim_ctrlb,
-                                             u32 m2);
+                                             u32 m2, u32 unlock_dll);
 u32 omap3_configure_core_dpll(u32 sdrc_rfr_ctrl, u32 sdrc_actim_ctrla,
-                             u32 sdrc_actim_ctrlb, u32 m2)
+                             u32 sdrc_actim_ctrlb, u32 m2, u32 unlock_dll)
 {
-       if (!_omap3_sram_configure_core_dpll)
-               omap_sram_error();
-
+       BUG_ON(!_omap3_sram_configure_core_dpll);
        return _omap3_sram_configure_core_dpll(sdrc_rfr_ctrl,
                                               sdrc_actim_ctrla,
-                                              sdrc_actim_ctrlb, m2);
+                                              sdrc_actim_ctrlb, m2,
+                                              unlock_dll);
 }
 
 /* REVISIT: Should this be same as omap34xx_sram_init() after off-idle? */
@@ -406,6 +420,8 @@ int __init omap_sram_init(void)
                omap243x_sram_init();
        else if (cpu_is_omap34xx())
                omap34xx_sram_init();
+       else if (cpu_is_omap44xx())
+               omap34xx_sram_init(); /* FIXME: */
 
        return 0;
 }
index 32eb9e33bebbe448d47d7500b53e79dfe81d46a8..e814803d474187e384e893c62f5d229fe50f32bb 100644 (file)
 #include <linux/spinlock.h>
 #include <linux/bitops.h>
 #include <linux/io.h>
-#include <asm/gpio.h>
+#include <linux/gpio.h>
 
 static DEFINE_SPINLOCK(gpio_lock);
-static const char *gpio_label[GPIO_MAX];  /* non null for allocated GPIOs */
 static unsigned long gpio_valid_input[BITS_TO_LONGS(GPIO_MAX)];
 static unsigned long gpio_valid_output[BITS_TO_LONGS(GPIO_MAX)];
 
@@ -46,82 +45,54 @@ static void __set_level(unsigned pin, int high)
        writel(u, GPIO_OUT(pin));
 }
 
-
-/*
- * GENERIC_GPIO primitives.
- */
-int gpio_direction_input(unsigned pin)
+static inline void __set_blinking(unsigned pin, int blink)
 {
-       unsigned long flags;
-
-       if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid_input)) {
-               pr_debug("%s: invalid GPIO %d\n", __func__, pin);
-               return -EINVAL;
-       }
-
-       spin_lock_irqsave(&gpio_lock, flags);
-
-       /*
-        * Some callers might not have used gpio_request(),
-        * so flag this pin as requested now.
-        */
-       if (gpio_label[pin] == NULL)
-               gpio_label[pin] = "?";
+       u32 u;
 
-       /*
-        * Configure GPIO direction.
-        */
-       __set_direction(pin, 1);
+       u = readl(GPIO_BLINK_EN(pin));
+       if (blink)
+               u |= 1 << (pin & 31);
+       else
+               u &= ~(1 << (pin & 31));
+       writel(u, GPIO_BLINK_EN(pin));
+}
 
-       spin_unlock_irqrestore(&gpio_lock, flags);
+static inline int orion_gpio_is_valid(unsigned pin, int mode)
+{
+       if (pin < GPIO_MAX) {
+               if ((mode & GPIO_INPUT_OK) && !test_bit(pin, gpio_valid_input))
+                       goto err_out;
+               if ((mode & GPIO_OUTPUT_OK) && !test_bit(pin, gpio_valid_output))
+                       goto err_out;
+               return true;
+       }
 
-       return 0;
+err_out:
+       pr_debug("%s: invalid GPIO %d\n", __func__, pin);
+       return false;
 }
-EXPORT_SYMBOL(gpio_direction_input);
 
-int gpio_direction_output(unsigned pin, int value)
+/*
+ * GENERIC_GPIO primitives.
+ */
+static int orion_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
 {
        unsigned long flags;
-       u32 u;
 
-       if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid_output)) {
-               pr_debug("%s: invalid GPIO %d\n", __func__, pin);
+       if (!orion_gpio_is_valid(pin, GPIO_INPUT_OK))
                return -EINVAL;
-       }
 
        spin_lock_irqsave(&gpio_lock, flags);
 
-       /*
-        * Some callers might not have used gpio_request(),
-        * so flag this pin as requested now.
-        */
-       if (gpio_label[pin] == NULL)
-               gpio_label[pin] = "?";
-
-       /*
-        * Disable blinking.
-        */
-       u = readl(GPIO_BLINK_EN(pin));
-       u &= ~(1 << (pin & 31));
-       writel(u, GPIO_BLINK_EN(pin));
-
-       /*
-        * Configure GPIO output value.
-        */
-       __set_level(pin, value);
-
-       /*
-        * Configure GPIO direction.
-        */
-       __set_direction(pin, 0);
+       /* Configure GPIO direction. */
+       __set_direction(pin, 1);
 
        spin_unlock_irqrestore(&gpio_lock, flags);
 
        return 0;
 }
-EXPORT_SYMBOL(gpio_direction_output);
 
-int gpio_get_value(unsigned pin)
+static int orion_gpio_get_value(struct gpio_chip *chip, unsigned pin)
 {
        int val;
 
@@ -132,83 +103,75 @@ int gpio_get_value(unsigned pin)
 
        return (val >> (pin & 31)) & 1;
 }
-EXPORT_SYMBOL(gpio_get_value);
 
-void gpio_set_value(unsigned pin, int value)
+static int orion_gpio_direction_output(struct gpio_chip *chip, unsigned pin,
+       int value)
 {
        unsigned long flags;
-       u32 u;
+
+       if (!orion_gpio_is_valid(pin, GPIO_OUTPUT_OK))
+               return -EINVAL;
 
        spin_lock_irqsave(&gpio_lock, flags);
 
-       /*
-        * Disable blinking.
-        */
-       u = readl(GPIO_BLINK_EN(pin));
-       u &= ~(1 << (pin & 31));
-       writel(u, GPIO_BLINK_EN(pin));
+       /* Disable blinking. */
+       __set_blinking(pin, 0);
 
-       /*
-        * Configure GPIO output value.
-        */
+       /* Configure GPIO output value. */
        __set_level(pin, value);
 
+       /* Configure GPIO direction. */
+       __set_direction(pin, 0);
+
        spin_unlock_irqrestore(&gpio_lock, flags);
+
+       return 0;
 }
-EXPORT_SYMBOL(gpio_set_value);
 
-int gpio_request(unsigned pin, const char *label)
+static void orion_gpio_set_value(struct gpio_chip *chip, unsigned pin,
+       int value)
 {
        unsigned long flags;
-       int ret;
-
-       if (pin >= GPIO_MAX ||
-           !(test_bit(pin, gpio_valid_input) ||
-             test_bit(pin, gpio_valid_output))) {
-               pr_debug("%s: invalid GPIO %d\n", __func__, pin);
-               return -EINVAL;
-       }
 
        spin_lock_irqsave(&gpio_lock, flags);
-       if (gpio_label[pin] == NULL) {
-               gpio_label[pin] = label ? label : "?";
-               ret = 0;
-       } else {
-               pr_debug("%s: GPIO %d already used as %s\n",
-                        __func__, pin, gpio_label[pin]);
-               ret = -EBUSY;
-       }
-       spin_unlock_irqrestore(&gpio_lock, flags);
 
-       return ret;
+       /* Configure GPIO output value. */
+       __set_level(pin, value);
+
+       spin_unlock_irqrestore(&gpio_lock, flags);
 }
-EXPORT_SYMBOL(gpio_request);
 
-void gpio_free(unsigned pin)
+static int orion_gpio_request(struct gpio_chip *chip, unsigned pin)
 {
-       if (pin >= GPIO_MAX ||
-           !(test_bit(pin, gpio_valid_input) ||
-             test_bit(pin, gpio_valid_output))) {
-               pr_debug("%s: invalid GPIO %d\n", __func__, pin);
-               return;
-       }
-
-       if (gpio_label[pin] == NULL)
-               pr_warning("%s: GPIO %d already freed\n", __func__, pin);
-       else
-               gpio_label[pin] = NULL;
+       if (orion_gpio_is_valid(pin, GPIO_INPUT_OK) ||
+           orion_gpio_is_valid(pin, GPIO_OUTPUT_OK))
+               return 0;
+       return -EINVAL;
 }
-EXPORT_SYMBOL(gpio_free);
 
+static struct gpio_chip orion_gpiochip = {
+       .label                  = "orion_gpio",
+       .direction_input        = orion_gpio_direction_input,
+       .get                    = orion_gpio_get_value,
+       .direction_output       = orion_gpio_direction_output,
+       .set                    = orion_gpio_set_value,
+       .request                = orion_gpio_request,
+       .base                   = 0,
+       .ngpio                  = GPIO_MAX,
+       .can_sleep              = 0,
+};
+
+void __init orion_gpio_init(void)
+{
+       gpiochip_add(&orion_gpiochip);
+}
 
 /*
  * Orion-specific GPIO API extensions.
  */
 void __init orion_gpio_set_unused(unsigned pin)
 {
-       /*
-        * Configure as output, drive low.
-        */
+       /* Configure as output, drive low. */
        __set_level(pin, 0);
        __set_direction(pin, 0);
 }
@@ -230,21 +193,14 @@ void __init orion_gpio_set_valid(unsigned pin, int mode)
 void orion_gpio_set_blink(unsigned pin, int blink)
 {
        unsigned long flags;
-       u32 u;
 
        spin_lock_irqsave(&gpio_lock, flags);
 
-       /*
-        * Set output value to zero.
-        */
+       /* Set output value to zero. */
        __set_level(pin, 0);
 
-       u = readl(GPIO_BLINK_EN(pin));
-       if (blink)
-               u |= 1 << (pin & 31);
-       else
-               u &= ~(1 << (pin & 31));
-       writel(u, GPIO_BLINK_EN(pin));
+       /* Set blinking. */
+       __set_blinking(pin, blink);
 
        spin_unlock_irqrestore(&gpio_lock, flags);
 }
@@ -368,7 +324,7 @@ static int gpio_irq_set_type(u32 irq, u32 type)
 }
 
 struct irq_chip orion_gpio_irq_chip = {
-       .name           = "orion_gpio",
+       .name           = "orion_gpio_irq",
        .ack            = gpio_irq_ack,
        .mask           = gpio_irq_mask,
        .unmask         = gpio_irq_unmask,
index 33f6c6aec1858374e967a88f19fd1461b7a08a39..9646a94ed3d06aa1937f8d9889d11248777ebec3 100644 (file)
 /*
  * GENERIC_GPIO primitives.
  */
-int gpio_request(unsigned pin, const char *label);
-void gpio_free(unsigned pin);
-int gpio_direction_input(unsigned pin);
-int gpio_direction_output(unsigned pin, int value);
-int gpio_get_value(unsigned pin);
-void gpio_set_value(unsigned pin, int value);
+#define gpio_get_value  __gpio_get_value
+#define gpio_set_value  __gpio_set_value
+#define gpio_cansleep   __gpio_cansleep
 
 /*
  * Orion-specific GPIO API extensions.
@@ -27,11 +24,13 @@ void gpio_set_value(unsigned pin, int value);
 void orion_gpio_set_unused(unsigned pin);
 void orion_gpio_set_blink(unsigned pin, int blink);
 
-#define GPIO_BIDI_OK           (1 << 0)
-#define GPIO_INPUT_OK          (1 << 1)
-#define GPIO_OUTPUT_OK         (1 << 2)
+#define GPIO_INPUT_OK          (1 << 0)
+#define GPIO_OUTPUT_OK         (1 << 1)
 void orion_gpio_set_valid(unsigned pin, int mode);
 
+/* Initialize gpiolib. */
+void __init orion_gpio_init(void);
+
 /*
  * GPIO interrupt handling.
  */
diff --git a/arch/arm/plat-orion/include/plat/orion5x_wdt.h b/arch/arm/plat-orion/include/plat/orion5x_wdt.h
deleted file mode 100644 (file)
index 3c9cf6a..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * arch/arm/plat-orion/include/plat/orion5x_wdt.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 __PLAT_ORION5X_WDT_H
-#define __PLAT_ORION5X_WDT_H
-
-struct orion5x_wdt_platform_data {
-       u32     tclk;           /* no <linux/clk.h> support yet */
-};
-
-
-#endif
-
diff --git a/arch/arm/plat-orion/include/plat/orion_wdt.h b/arch/arm/plat-orion/include/plat/orion_wdt.h
new file mode 100644 (file)
index 0000000..665c362
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * arch/arm/plat-orion/include/plat/orion_wdt.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 __PLAT_ORION_WDT_H
+#define __PLAT_ORION_WDT_H
+
+struct orion_wdt_platform_data {
+       u32     tclk;           /* no <linux/clk.h> support yet */
+};
+
+
+#endif
+
index de8a001fc3a9d0a4fbb6622005ba596c645d7fd0..715a30177f2857c02ed227e74240359be58dbb1a 100644 (file)
  */
 
 #include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/cnt32_to_63.h>
+#include <linux/timer.h>
 #include <linux/clockchips.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <asm/mach/time.h>
 #include <mach/bridge-regs.h>
+#include <mach/hardware.h>
 
 /*
  * Number of timer ticks per jiffy.
@@ -38,6 +42,56 @@ static u32 ticks_per_jiffy;
 #define TIMER1_VAL             (TIMER_VIRT_BASE + 0x001c)
 
 
+/*
+ * Orion's sched_clock implementation. It has a resolution of
+ * at least 7.5ns (133MHz TCLK) and a maximum value of 834 days.
+ *
+ * Because the hardware timer period is quite short (21 secs if
+ * 200MHz TCLK) and because cnt32_to_63() needs to be called at
+ * least once per half period to work properly, a kernel timer is
+ * set up to ensure this requirement is always met.
+ */
+#define TCLK2NS_SCALE_FACTOR 8
+
+static unsigned long tclk2ns_scale;
+
+unsigned long long sched_clock(void)
+{
+       unsigned long long v = cnt32_to_63(0xffffffff - readl(TIMER0_VAL));
+       return (v * tclk2ns_scale) >> TCLK2NS_SCALE_FACTOR;
+}
+
+static struct timer_list cnt32_to_63_keepwarm_timer;
+
+static void cnt32_to_63_keepwarm(unsigned long data)
+{
+       mod_timer(&cnt32_to_63_keepwarm_timer, round_jiffies(jiffies + data));
+       (void) sched_clock();
+}
+
+static void __init setup_sched_clock(unsigned long tclk)
+{
+       unsigned long long v;
+       unsigned long data;
+
+       v = NSEC_PER_SEC;
+       v <<= TCLK2NS_SCALE_FACTOR;
+       v += tclk/2;
+       do_div(v, tclk);
+       /*
+        * We want an even value to automatically clear the top bit
+        * returned by cnt32_to_63() without an additional run time
+        * instruction. So if the LSB is 1 then round it up.
+        */
+       if (v & 1)
+               v++;
+       tclk2ns_scale = v;
+
+       data = (0xffffffffUL / tclk / 2 - 2) * HZ;
+       setup_timer(&cnt32_to_63_keepwarm_timer, cnt32_to_63_keepwarm, data);
+       mod_timer(&cnt32_to_63_keepwarm_timer, round_jiffies(jiffies + data));
+}
+
 /*
  * Clocksource handling.
  */
@@ -176,6 +230,10 @@ void __init orion_time_init(unsigned int irq, unsigned int tclk)
 
        ticks_per_jiffy = (tclk + HZ/2) / HZ;
 
+       /*
+        * Set scale and timer for sched_clock
+        */
+       setup_sched_clock(tclk);
 
        /*
         * Setup free-running clocksource timer (interrupts
@@ -190,7 +248,6 @@ void __init orion_time_init(unsigned int irq, unsigned int tclk)
        orion_clksrc.mult = clocksource_hz2mult(tclk, orion_clksrc.shift);
        clocksource_register(&orion_clksrc);
 
-
        /*
         * Setup clockevent timer (interrupt-driven.)
         */
index 8f2c4c7fbd480ffc2318b4df7a6dc6c6cc710497..0264bfb0ca4f24254d59bc9cf5ff5e1a0f9bbdae 100644 (file)
@@ -7,3 +7,5 @@ obj-y   := dma.o
 obj-$(CONFIG_GENERIC_GPIO)     += gpio.o
 obj-$(CONFIG_PXA3xx)           += mfp.o
 obj-$(CONFIG_ARCH_MMP)         += mfp.o
+
+obj-$(CONFIG_HAVE_PWM)         += pwm.o
diff --git a/arch/arm/plat-pxa/include/plat/i2c.h b/arch/arm/plat-pxa/include/plat/i2c.h
new file mode 100644 (file)
index 0000000..1a9f65e
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ *  i2c_pxa.h
+ *
+ *  Copyright (C) 2002 Intrinsyc Software 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 _I2C_PXA_H_
+#define _I2C_PXA_H_
+
+#if 0
+#define DEF_TIMEOUT             3
+#else
+/* need a longer timeout if we're dealing with the fact we may well be
+ * looking at a multi-master environment
+*/
+#define DEF_TIMEOUT             32
+#endif
+
+#define BUS_ERROR               (-EREMOTEIO)
+#define XFER_NAKED              (-ECONNREFUSED)
+#define I2C_RETRY               (-2000) /* an error has occurred retry transmit */
+
+/* ICR initialize bit values
+*
+*  15. FM       0 (100 Khz operation)
+*  14. UR       0 (No unit reset)
+*  13. SADIE    0 (Disables the unit from interrupting on slave addresses
+*                                       matching its slave address)
+*  12. ALDIE    0 (Disables the unit from interrupt when it loses arbitration
+*                                       in master mode)
+*  11. SSDIE    0 (Disables interrupts from a slave stop detected, in slave mode)
+*  10. BEIE     1 (Enable interrupts from detected bus errors, no ACK sent)
+*  9.  IRFIE    1 (Enable interrupts from full buffer received)
+*  8.  ITEIE    1 (Enables the I2C unit to interrupt when transmit buffer empty)
+*  7.  GCD      1 (Disables i2c unit response to general call messages as a slave)
+*  6.  IUE      0 (Disable unit until we change settings)
+*  5.  SCLE     1 (Enables the i2c clock output for master mode (drives SCL)
+*  4.  MA       0 (Only send stop with the ICR stop bit)
+*  3.  TB       0 (We are not transmitting a byte initially)
+*  2.  ACKNAK   0 (Send an ACK after the unit receives a byte)
+*  1.  STOP     0 (Do not send a STOP)
+*  0.  START    0 (Do not send a START)
+*
+*/
+#define I2C_ICR_INIT   (ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE)
+
+/* I2C status register init values
+ *
+ * 10. BED      1 (Clear bus error detected)
+ * 9.  SAD      1 (Clear slave address detected)
+ * 7.  IRF      1 (Clear IDBR Receive Full)
+ * 6.  ITE      1 (Clear IDBR Transmit Empty)
+ * 5.  ALD      1 (Clear Arbitration Loss Detected)
+ * 4.  SSD      1 (Clear Slave Stop Detected)
+ */
+#define I2C_ISR_INIT   0x7FF  /* status register init */
+
+struct i2c_slave_client;
+
+struct i2c_pxa_platform_data {
+       unsigned int            slave_addr;
+       struct i2c_slave_client *slave;
+       unsigned int            class;
+       unsigned int            use_pio :1;
+       unsigned int            fast_mode :1;
+};
+
+extern void pxa_set_i2c_info(struct i2c_pxa_platform_data *info);
+
+#ifdef CONFIG_PXA27x
+extern void pxa27x_set_i2c_power_info(struct i2c_pxa_platform_data *info);
+#endif
+
+#ifdef CONFIG_PXA3xx
+extern void pxa3xx_set_i2c_power_info(struct i2c_pxa_platform_data *info);
+#endif
+
+#endif
diff --git a/arch/arm/plat-pxa/pwm.c b/arch/arm/plat-pxa/pwm.c
new file mode 100644 (file)
index 0000000..a9eabdc
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ * linux/arch/arm/mach-pxa/pwm.c
+ *
+ * simple driver for PWM (Pulse Width Modulator) controller
+ *
+ * This 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.
+ *
+ * 2008-02-13  initial version
+ *             eric miao <eric.miao@marvell.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/pwm.h>
+
+#include <asm/div64.h>
+
+#define HAS_SECONDARY_PWM      0x10
+#define PWM_ID_BASE(d)         ((d) & 0xf)
+
+static const struct platform_device_id pwm_id_table[] = {
+       /*   PWM    has_secondary_pwm? */
+       { "pxa25x-pwm", 0 },
+       { "pxa27x-pwm", 0 | HAS_SECONDARY_PWM },
+       { "pxa168-pwm", 1 },
+       { "pxa910-pwm", 1 },
+       { },
+};
+MODULE_DEVICE_TABLE(platform, pwm_id_table);
+
+/* PWM registers and bits definitions */
+#define PWMCR          (0x00)
+#define PWMDCR         (0x04)
+#define PWMPCR         (0x08)
+
+#define PWMCR_SD       (1 << 6)
+#define PWMDCR_FD      (1 << 10)
+
+struct pwm_device {
+       struct list_head        node;
+       struct pwm_device       *secondary;
+       struct platform_device  *pdev;
+
+       const char      *label;
+       struct clk      *clk;
+       int             clk_enabled;
+       void __iomem    *mmio_base;
+
+       unsigned int    use_count;
+       unsigned int    pwm_id;
+};
+
+/*
+ * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE
+ * duty_ns   = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
+ */
+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+       unsigned long long c;
+       unsigned long period_cycles, prescale, pv, dc;
+
+       if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
+               return -EINVAL;
+
+       c = clk_get_rate(pwm->clk);
+       c = c * period_ns;
+       do_div(c, 1000000000);
+       period_cycles = c;
+
+       if (period_cycles < 1)
+               period_cycles = 1;
+       prescale = (period_cycles - 1) / 1024;
+       pv = period_cycles / (prescale + 1) - 1;
+
+       if (prescale > 63)
+               return -EINVAL;
+
+       if (duty_ns == period_ns)
+               dc = PWMDCR_FD;
+       else
+               dc = (pv + 1) * duty_ns / period_ns;
+
+       /* NOTE: the clock to PWM has to be enabled first
+        * before writing to the registers
+        */
+       clk_enable(pwm->clk);
+       __raw_writel(prescale, pwm->mmio_base + PWMCR);
+       __raw_writel(dc, pwm->mmio_base + PWMDCR);
+       __raw_writel(pv, pwm->mmio_base + PWMPCR);
+       clk_disable(pwm->clk);
+
+       return 0;
+}
+EXPORT_SYMBOL(pwm_config);
+
+int pwm_enable(struct pwm_device *pwm)
+{
+       int rc = 0;
+
+       if (!pwm->clk_enabled) {
+               rc = clk_enable(pwm->clk);
+               if (!rc)
+                       pwm->clk_enabled = 1;
+       }
+       return rc;
+}
+EXPORT_SYMBOL(pwm_enable);
+
+void pwm_disable(struct pwm_device *pwm)
+{
+       if (pwm->clk_enabled) {
+               clk_disable(pwm->clk);
+               pwm->clk_enabled = 0;
+       }
+}
+EXPORT_SYMBOL(pwm_disable);
+
+static DEFINE_MUTEX(pwm_lock);
+static LIST_HEAD(pwm_list);
+
+struct pwm_device *pwm_request(int pwm_id, const char *label)
+{
+       struct pwm_device *pwm;
+       int found = 0;
+
+       mutex_lock(&pwm_lock);
+
+       list_for_each_entry(pwm, &pwm_list, node) {
+               if (pwm->pwm_id == pwm_id) {
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (found) {
+               if (pwm->use_count == 0) {
+                       pwm->use_count++;
+                       pwm->label = label;
+               } else
+                       pwm = ERR_PTR(-EBUSY);
+       } else
+               pwm = ERR_PTR(-ENOENT);
+
+       mutex_unlock(&pwm_lock);
+       return pwm;
+}
+EXPORT_SYMBOL(pwm_request);
+
+void pwm_free(struct pwm_device *pwm)
+{
+       mutex_lock(&pwm_lock);
+
+       if (pwm->use_count) {
+               pwm->use_count--;
+               pwm->label = NULL;
+       } else
+               pr_warning("PWM device already freed\n");
+
+       mutex_unlock(&pwm_lock);
+}
+EXPORT_SYMBOL(pwm_free);
+
+static inline void __add_pwm(struct pwm_device *pwm)
+{
+       mutex_lock(&pwm_lock);
+       list_add_tail(&pwm->node, &pwm_list);
+       mutex_unlock(&pwm_lock);
+}
+
+static int __devinit pwm_probe(struct platform_device *pdev)
+{
+       struct platform_device_id *id = platform_get_device_id(pdev);
+       struct pwm_device *pwm, *secondary = NULL;
+       struct resource *r;
+       int ret = 0;
+
+       pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
+       if (pwm == NULL) {
+               dev_err(&pdev->dev, "failed to allocate memory\n");
+               return -ENOMEM;
+       }
+
+       pwm->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(pwm->clk)) {
+               ret = PTR_ERR(pwm->clk);
+               goto err_free;
+       }
+       pwm->clk_enabled = 0;
+
+       pwm->use_count = 0;
+       pwm->pwm_id = PWM_ID_BASE(id->driver_data) + pdev->id;
+       pwm->pdev = pdev;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (r == NULL) {
+               dev_err(&pdev->dev, "no memory resource defined\n");
+               ret = -ENODEV;
+               goto err_free_clk;
+       }
+
+       r = request_mem_region(r->start, r->end - r->start + 1, pdev->name);
+       if (r == NULL) {
+               dev_err(&pdev->dev, "failed to request memory resource\n");
+               ret = -EBUSY;
+               goto err_free_clk;
+       }
+
+       pwm->mmio_base = ioremap(r->start, r->end - r->start + 1);
+       if (pwm->mmio_base == NULL) {
+               dev_err(&pdev->dev, "failed to ioremap() registers\n");
+               ret = -ENODEV;
+               goto err_free_mem;
+       }
+
+       if (id->driver_data & HAS_SECONDARY_PWM) {
+               secondary = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
+               if (secondary == NULL) {
+                       ret = -ENOMEM;
+                       goto err_free_mem;
+               }
+
+               *secondary = *pwm;
+               pwm->secondary = secondary;
+
+               /* registers for the second PWM has offset of 0x10 */
+               secondary->mmio_base = pwm->mmio_base + 0x10;
+               secondary->pwm_id = pdev->id + 2;
+       }
+
+       __add_pwm(pwm);
+       if (secondary)
+               __add_pwm(secondary);
+
+       platform_set_drvdata(pdev, pwm);
+       return 0;
+
+err_free_mem:
+       release_mem_region(r->start, r->end - r->start + 1);
+err_free_clk:
+       clk_put(pwm->clk);
+err_free:
+       kfree(pwm);
+       return ret;
+}
+
+static int __devexit pwm_remove(struct platform_device *pdev)
+{
+       struct pwm_device *pwm;
+       struct resource *r;
+
+       pwm = platform_get_drvdata(pdev);
+       if (pwm == NULL)
+               return -ENODEV;
+
+       mutex_lock(&pwm_lock);
+
+       if (pwm->secondary) {
+               list_del(&pwm->secondary->node);
+               kfree(pwm->secondary);
+       }
+
+       list_del(&pwm->node);
+       mutex_unlock(&pwm_lock);
+
+       iounmap(pwm->mmio_base);
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(r->start, r->end - r->start + 1);
+
+       clk_put(pwm->clk);
+       kfree(pwm);
+       return 0;
+}
+
+static struct platform_driver pwm_driver = {
+       .driver         = {
+               .name   = "pxa25x-pwm",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = pwm_probe,
+       .remove         = __devexit_p(pwm_remove),
+       .id_table       = pwm_id_table,
+};
+
+static int __init pwm_init(void)
+{
+       return platform_driver_register(&pwm_driver);
+}
+arch_initcall(pwm_init);
+
+static void __exit pwm_exit(void)
+{
+       platform_driver_unregister(&pwm_driver);
+}
+module_exit(pwm_exit);
+
+MODULE_LICENSE("GPL v2");
index de9383814e5ef15db9cc36b20ee7e84cf49819b2..935c7558469bab7b1f524420ccd63b4467abc0d0 100644 (file)
@@ -71,6 +71,15 @@ config S3C2410_PM_DEBUG
          Resume code. See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
          for more information.
 
+config S3C_PM_DEBUG_LED_SMDK
+       bool "SMDK LED suspend/resume debugging"
+       depends on PM && (MACH_SMDK6410)
+       help
+         Say Y here to enable the use of the SMDK LEDs on the baseboard
+        for debugging of the state of the suspend and resume process.
+
+        Note, this currently only works for S3C64XX based SMDK boards.
+
 config S3C2410_PM_CHECK
        bool "S3C2410 PM Suspend Memory CRC"
        depends on PM && CRC32
@@ -150,6 +159,13 @@ config S3C_GPIO_CFG_S3C64XX
          Internal configuration to enable S3C64XX style GPIO configuration
          functions.
 
+# DMA
+
+config S3C_DMA
+       bool
+       help
+         Internal configuration for S3C DMA core
+
 # device definitions to compile in
 
 config S3C_DEV_HSMMC
@@ -172,4 +188,14 @@ config S3C_DEV_FB
        help
          Compile in platform device definition for framebuffer
 
+config S3C_DEV_USB_HOST
+       bool
+       help
+         Compile in platform device definition for USB host.
+
+config S3C_DEV_USB_HSOTG
+       bool
+       help
+         Compile in platform device definition for USB high-speed OtG
+
 endif
index 8d7815d25a51d3b3b2f3e2bab6afddee6f50986b..610651455a78615bbd74415cbcdf7802c0b44407 100644 (file)
@@ -18,9 +18,14 @@ obj-y                                += pwm-clock.o
 obj-y                          += gpio.o
 obj-y                          += gpio-config.o
 
+# DMA support
+
+obj-$(CONFIG_S3C_DMA)          += dma.o
+
 # PM support
 
 obj-$(CONFIG_PM)               += pm.o
+obj-$(CONFIG_PM)               += pm-gpio.o
 obj-$(CONFIG_S3C2410_PM_CHECK) += pm-check.o
 
 # devices
@@ -30,3 +35,5 @@ obj-$(CONFIG_S3C_DEV_HSMMC1)  += dev-hsmmc1.o
 obj-y                          += dev-i2c0.o
 obj-$(CONFIG_S3C_DEV_I2C1)     += dev-i2c1.o
 obj-$(CONFIG_S3C_DEV_FB)       += dev-fb.o
+obj-$(CONFIG_S3C_DEV_USB_HOST) += dev-usb.o
+obj-$(CONFIG_S3C_DEV_USB_HSOTG)        += dev-usb-hsotg.o
diff --git a/arch/arm/plat-s3c/dev-usb-hsotg.c b/arch/arm/plat-s3c/dev-usb-hsotg.c
new file mode 100644 (file)
index 0000000..e2f604b
--- /dev/null
@@ -0,0 +1,41 @@
+/* linux/arch/arm/plat-s3c/dev-usb-hsotg.c
+ *
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * S3C series device definition for USB high-speed UDC/OtG block
+ *
+ * This 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/string.h>
+#include <linux/platform_device.h>
+
+#include <mach/irqs.h>
+#include <mach/map.h>
+
+#include <plat/devs.h>
+
+static struct resource s3c_usb_hsotg_resources[] = {
+       [0] = {
+               .start  = S3C_PA_USB_HSOTG,
+               .end    = S3C_PA_USB_HSOTG + 0x10000 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ_OTG,
+               .end    = IRQ_OTG,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device s3c_device_usb_hsotg = {
+       .name           = "s3c-hsotg",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(s3c_usb_hsotg_resources),
+       .resource       = s3c_usb_hsotg_resources,
+};
diff --git a/arch/arm/plat-s3c/dev-usb.c b/arch/arm/plat-s3c/dev-usb.c
new file mode 100644 (file)
index 0000000..2ee85ab
--- /dev/null
@@ -0,0 +1,50 @@
+/* linux/arch/arm/plat-s3c/dev-usb.c
+ *
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * S3C series device definition for USB host
+ *
+ * This 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/string.h>
+#include <linux/platform_device.h>
+
+#include <mach/irqs.h>
+#include <mach/map.h>
+
+#include <plat/devs.h>
+
+
+static struct resource s3c_usb_resource[] = {
+       [0] = {
+               .start = S3C_PA_USBHOST,
+               .end   = S3C_PA_USBHOST + 0x100 - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_USBH,
+               .end   = IRQ_USBH,
+               .flags = IORESOURCE_IRQ,
+       }
+};
+
+static u64 s3c_device_usb_dmamask = 0xffffffffUL;
+
+struct platform_device s3c_device_usb = {
+       .name             = "s3c2410-ohci",
+       .id               = -1,
+       .num_resources    = ARRAY_SIZE(s3c_usb_resource),
+       .resource         = s3c_usb_resource,
+       .dev              = {
+               .dma_mask = &s3c_device_usb_dmamask,
+               .coherent_dma_mask = 0xffffffffUL
+       }
+};
+
+EXPORT_SYMBOL(s3c_device_usb);
diff --git a/arch/arm/plat-s3c/dma.c b/arch/arm/plat-s3c/dma.c
new file mode 100644 (file)
index 0000000..c9db75c
--- /dev/null
@@ -0,0 +1,86 @@
+/* linux/arch/arm/plat-s3c/dma.c
+ *
+ * Copyright (c) 2003-2005,2006,2009 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * S3C DMA core
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+struct s3c2410_dma_buf;
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+
+#include <mach/dma.h>
+#include <mach/irqs.h>
+
+#include <plat/dma-plat.h>
+
+/* dma channel state information */
+struct s3c2410_dma_chan s3c2410_chans[S3C_DMA_CHANNELS];
+struct s3c2410_dma_chan *s3c_dma_chan_map[DMACH_MAX];
+
+/* s3c_dma_lookup_channel
+ *
+ * change the dma channel number given into a real dma channel id
+*/
+
+struct s3c2410_dma_chan *s3c_dma_lookup_channel(unsigned int channel)
+{
+       if (channel & DMACH_LOW_LEVEL)
+               return &s3c2410_chans[channel & ~DMACH_LOW_LEVEL];
+       else
+               return s3c_dma_chan_map[channel];
+}
+
+/* do we need to protect the settings of the fields from
+ * irq?
+*/
+
+int s3c2410_dma_set_opfn(unsigned int channel, s3c2410_dma_opfn_t rtn)
+{
+       struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+
+       if (chan == NULL)
+               return -EINVAL;
+
+       pr_debug("%s: chan=%p, op rtn=%p\n", __func__, chan, rtn);
+
+       chan->op_fn = rtn;
+
+       return 0;
+}
+EXPORT_SYMBOL(s3c2410_dma_set_opfn);
+
+int s3c2410_dma_set_buffdone_fn(unsigned int channel, s3c2410_dma_cbfn_t rtn)
+{
+       struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+
+       if (chan == NULL)
+               return -EINVAL;
+
+       pr_debug("%s: chan=%p, callback rtn=%p\n", __func__, chan, rtn);
+
+       chan->callback_fn = rtn;
+
+       return 0;
+}
+EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn);
+
+int s3c2410_dma_setflags(unsigned int channel, unsigned int flags)
+{
+       struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+
+       if (chan == NULL)
+               return -EINVAL;
+
+       chan->flags = flags;
+       return 0;
+}
+EXPORT_SYMBOL(s3c2410_dma_setflags);
index d71dd6d9ce5ca4585bbc944d99ecbcebba6e6859..260fdc6ad685e4035ee3d494564f5dc06d5f479c 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/io.h>
 #include <linux/gpio.h>
 
-#include <plat/gpio-core.h>
+#include <mach/gpio-core.h>
 
 #ifdef CONFIG_S3C_GPIO_TRACK
 struct s3c_gpio_chip *s3c_gpios[S3C_GPIO_END];
@@ -140,6 +140,15 @@ __init void s3c_gpiolib_add(struct s3c_gpio_chip *chip)
        if (!gc->get)
                gc->get = s3c_gpiolib_get;
 
+#ifdef CONFIG_PM
+       if (chip->pm != NULL) {
+               if (!chip->pm->save || !chip->pm->resume)
+                       printk(KERN_ERR "gpio: %s has missing PM functions\n",
+                              gc->label);
+       } else
+               printk(KERN_ERR "gpio: %s has no PM function\n", gc->label);
+#endif
+
        /* gpiochip_add() prints own failure message on error. */
        ret = gpiochip_add(gc);
        if (ret >= 0)
index 43df2a404b0be5539e662503250a921b16501b64..d847bd476b6c29ffab98369250dc63b09a43025f 100644 (file)
@@ -19,10 +19,12 @@ struct s3c_adc_client;
 extern int s3c_adc_start(struct s3c_adc_client *client,
                         unsigned int channel, unsigned int nr_samples);
 
-extern struct s3c_adc_client *s3c_adc_register(struct platform_device *pdev,
-                                              void (*select)(unsigned selected),
-                                              void (*conv)(unsigned d0, unsigned d1),
-                                              unsigned int is_ts);
+extern struct s3c_adc_client *
+       s3c_adc_register(struct platform_device *pdev,
+                        void (*select)(unsigned selected),
+                        void (*conv)(unsigned d0, unsigned d1,
+                                     unsigned *samples_left),
+                        unsigned int is_ts);
 
 extern void s3c_adc_release(struct s3c_adc_client *client);
 
index a10622eed43ab10ab2b5fd13474d6f7a27af71fe..d86af84b5b8cdcf63bd617e180a7e3a418018646 100644 (file)
@@ -50,6 +50,7 @@ extern struct clk clk_xtal;
 extern struct clk clk_ext;
 
 /* S3C64XX specific clocks */
+extern struct clk clk_h2;
 extern struct clk clk_27m;
 extern struct clk clk_48m;
 
index e62ae0fcfe56ad0833764a4cd9a4fdfe7a98dffe..be541cbba0708d0e152233013a6ab2fa27428424 100644 (file)
@@ -69,3 +69,6 @@ extern struct sysdev_class s3c2412_sysclass;
 extern struct sysdev_class s3c2440_sysclass;
 extern struct sysdev_class s3c2442_sysclass;
 extern struct sysdev_class s3c2443_sysclass;
+extern struct sysdev_class s3c6410_sysclass;
+extern struct sysdev_class s3c64xx_sysclass;
+
index 26f0cec3ac04160d1f3111eec4f66621548cd064..a0b6768fddcffda46ddd905cbc413975bc8196b5 100644 (file)
@@ -45,6 +45,7 @@ extern struct platform_device s3c_device_spi1;
 extern struct platform_device s3c_device_nand;
 
 extern struct platform_device s3c_device_usbgadget;
+extern struct platform_device s3c_device_usb_hsotg;
 
 /* s3c2440 specific devices */
 
diff --git a/arch/arm/plat-s3c/include/plat/dma-core.h b/arch/arm/plat-s3c/include/plat/dma-core.h
new file mode 100644 (file)
index 0000000..32ff2a9
--- /dev/null
@@ -0,0 +1,22 @@
+/* arch/arm/plat-s3c/include/plat/dma.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * Samsung S3C DMA core 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.
+*/
+
+extern struct s3c2410_dma_chan *s3c_dma_lookup_channel(unsigned int channel);
+
+extern struct s3c2410_dma_chan *s3c_dma_chan_map[];
+
+/* the currently allocated channel information */
+extern struct s3c2410_dma_chan s3c2410_chans[];
+
+
diff --git a/arch/arm/plat-s3c/include/plat/dma.h b/arch/arm/plat-s3c/include/plat/dma.h
new file mode 100644 (file)
index 0000000..34dba98
--- /dev/null
@@ -0,0 +1,127 @@
+/* arch/arm/plat-s3c/include/plat/dma.h
+ *
+ * Copyright (C) 2003,2004,2006 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Samsung S3C DMA 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.
+*/
+
+enum s3c2410_dma_buffresult {
+       S3C2410_RES_OK,
+       S3C2410_RES_ERR,
+       S3C2410_RES_ABORT
+};
+
+enum s3c2410_dmasrc {
+       S3C2410_DMASRC_HW,              /* source is memory */
+       S3C2410_DMASRC_MEM              /* source is hardware */
+};
+
+/* enum s3c2410_chan_op
+ *
+ * operation codes passed to the DMA code by the user, and also used
+ * to inform the current channel owner of any changes to the system state
+*/
+
+enum s3c2410_chan_op {
+       S3C2410_DMAOP_START,
+       S3C2410_DMAOP_STOP,
+       S3C2410_DMAOP_PAUSE,
+       S3C2410_DMAOP_RESUME,
+       S3C2410_DMAOP_FLUSH,
+       S3C2410_DMAOP_TIMEOUT,          /* internal signal to handler */
+       S3C2410_DMAOP_STARTED,          /* indicate channel started */
+};
+
+struct s3c2410_dma_client {
+       char                *name;
+};
+
+struct s3c2410_dma_chan;
+
+/* s3c2410_dma_cbfn_t
+ *
+ * buffer callback routine type
+*/
+
+typedef void (*s3c2410_dma_cbfn_t)(struct s3c2410_dma_chan *,
+                                  void *buf, int size,
+                                  enum s3c2410_dma_buffresult result);
+
+typedef int  (*s3c2410_dma_opfn_t)(struct s3c2410_dma_chan *,
+                                  enum s3c2410_chan_op );
+
+
+
+/* s3c2410_dma_request
+ *
+ * request a dma channel exclusivley
+*/
+
+extern int s3c2410_dma_request(unsigned int channel,
+                              struct s3c2410_dma_client *, void *dev);
+
+
+/* s3c2410_dma_ctrl
+ *
+ * change the state of the dma channel
+*/
+
+extern int s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op);
+
+/* s3c2410_dma_setflags
+ *
+ * set the channel's flags to a given state
+*/
+
+extern int s3c2410_dma_setflags(unsigned int channel,
+                               unsigned int flags);
+
+/* s3c2410_dma_free
+ *
+ * free the dma channel (will also abort any outstanding operations)
+*/
+
+extern int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *);
+
+/* s3c2410_dma_enqueue
+ *
+ * place the given buffer onto the queue of operations for the channel.
+ * The buffer must be allocated from dma coherent memory, or the Dcache/WB
+ * drained before the buffer is given to the DMA system.
+*/
+
+extern int s3c2410_dma_enqueue(unsigned int channel, void *id,
+                              dma_addr_t data, int size);
+
+/* s3c2410_dma_config
+ *
+ * configure the dma channel
+*/
+
+extern int s3c2410_dma_config(unsigned int channel, int xferunit);
+
+/* s3c2410_dma_devconfig
+ *
+ * configure the device we're talking to
+*/
+
+extern int s3c2410_dma_devconfig(int channel, enum s3c2410_dmasrc source,
+                                unsigned long devaddr);
+
+/* s3c2410_dma_getposition
+ *
+ * get the position that the dma transfer is currently at
+*/
+
+extern int s3c2410_dma_getposition(unsigned int channel,
+                                  dma_addr_t *src, dma_addr_t *dest);
+
+extern int s3c2410_dma_set_opfn(unsigned int, s3c2410_dma_opfn_t rtn);
+extern int s3c2410_dma_set_buffdone_fn(unsigned int, s3c2410_dma_cbfn_t rtn);
+
+
index 2fc60a580ac89241428678f9e8dbdea57c4a4fa6..32af612767aa2bea25cd81f850e6d86e4eefb008 100644 (file)
  * specific code.
 */
 
+struct s3c_gpio_chip;
+
+/**
+ * struct s3c_gpio_pm - power management (suspend/resume) information
+ * @save: Routine to save the state of the GPIO block
+ * @resume: Routine to resume the GPIO block.
+ */
+struct s3c_gpio_pm {
+       void (*save)(struct s3c_gpio_chip *chip);
+       void (*resume)(struct s3c_gpio_chip *chip);
+};
+
 struct s3c_gpio_cfg;
 
 /**
@@ -27,6 +39,7 @@ struct s3c_gpio_cfg;
  * @chip: The chip structure to be exported via gpiolib.
  * @base: The base pointer to the gpio configuration registers.
  * @config: special function and pull-resistor control information.
+ * @pm_save: Save information for suspend/resume support.
  *
  * This wrapper provides the necessary information for the Samsung
  * specific gpios being registered with gpiolib.
@@ -34,7 +47,11 @@ struct s3c_gpio_cfg;
 struct s3c_gpio_chip {
        struct gpio_chip        chip;
        struct s3c_gpio_cfg     *config;
+       struct s3c_gpio_pm      *pm;
        void __iomem            *base;
+#ifdef CONFIG_PM
+       u32                     pm_save[4];
+#endif
 };
 
 static inline struct s3c_gpio_chip *to_s3c_gpio(struct gpio_chip *gpc)
@@ -75,3 +92,16 @@ static inline struct s3c_gpio_chip *s3c_gpiolib_getchip(unsigned int chip)
 
 static inline void s3c_gpiolib_track(struct s3c_gpio_chip *chip) { }
 #endif
+
+#ifdef CONFIG_PM
+extern struct s3c_gpio_pm s3c_gpio_pm_1bit;
+extern struct s3c_gpio_pm s3c_gpio_pm_2bit;
+extern struct s3c_gpio_pm s3c_gpio_pm_4bit;
+#define __gpio_pm(x) x
+#else
+#define s3c_gpio_pm_1bit NULL
+#define s3c_gpio_pm_2bit NULL
+#define s3c_gpio_pm_4bit NULL
+#define __gpio_pm(x) NULL
+
+#endif /* CONFIG_PM */
index 3779775133a9b487105b80fc86259b5d87204434..7a797192fcf35a245b570146e1c7ca16ef4887a0 100644 (file)
@@ -44,6 +44,8 @@ extern void (*pm_cpu_sleep)(void);
 
 extern unsigned long s3c_pm_flags;
 
+extern unsigned char pm_uart_udivslot;  /* true to save UART UDIVSLOT */
+
 /* from sleep.S */
 
 extern int  s3c_cpu_save(unsigned long *saveblk);
@@ -88,6 +90,7 @@ struct pm_uart_save {
        u32     ufcon;
        u32     umcon;
        u32     ubrdiv;
+       u32     udivslot;
 };
 
 /* helper functions to save/restore lists of registers. */
@@ -124,6 +127,18 @@ extern void s3c_pm_dbg(const char *msg, ...);
 #define S3C_PMDBG(fmt...) printk(KERN_DEBUG fmt)
 #endif
 
+#ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK
+/**
+ * s3c_pm_debug_smdkled() - Debug PM suspend/resume via SMDK Board LEDs
+ * @set: set bits for the state of the LEDs
+ * @clear: clear bits for the state of the LEDs.
+ */
+extern void s3c_pm_debug_smdkled(u32 set, u32 clear);
+
+#else
+static inline void s3c_pm_debug_smdkled(u32 set, u32 clear) { }
+#endif /* CONFIG_S3C_PM_DEBUG_LED_SMDK */
+
 /* suspend memory checking */
 
 #ifdef CONFIG_S3C2410_PM_CHECK
index 487d7d2a7e1d1a315fdd7f3f8f6687882203833a..66af75a5cdd1f54cc564f660b0da23611481793f 100644 (file)
 
 #define S3C2443_DIVSLOT                  (0x2C)
 
+/* S3C64XX interrupt registers. */
+#define S3C64XX_UINTP          0x30
+#define S3C64XX_UINTSP         0x34
+#define S3C64XX_UINTM          0x38
+
 #ifndef __ASSEMBLY__
 
 /* struct s3c24xx_uart_clksrc
index c4ca3920ca4bde8abdd3b33a6d5ad8678246148f..f615308ccdfb9eaa3a35daf0830d4182a6bae036 100644 (file)
@@ -67,12 +67,52 @@ extern struct s3c_sdhci_platdata s3c_hsmmc1_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);
+
+/* S3C6400 SDHCI setup */
+
+#ifdef CONFIG_S3C6400_SETUP_SDHCI
+extern char *s3c6400_hsmmc_clksrcs[4];
+
+#ifdef CONFIG_S3C_DEV_HSMMC
+extern void s3c6400_setup_sdhci_cfg_card(struct platform_device *dev,
+                                        void __iomem *r,
+                                        struct mmc_ios *ios,
+                                        struct mmc_card *card);
+
+static inline void s3c6400_default_sdhci0(void)
+{
+       s3c_hsmmc0_def_platdata.clocks = s3c6400_hsmmc_clksrcs;
+       s3c_hsmmc0_def_platdata.cfg_gpio = s3c64xx_setup_sdhci0_cfg_gpio;
+       s3c_hsmmc0_def_platdata.cfg_card = s3c6400_setup_sdhci_cfg_card;
+}
+
+#else
+static inline void s3c6400_default_sdhci0(void) { }
+#endif  /* CONFIG_S3C_DEV_HSMMC */
+
+#ifdef CONFIG_S3C_DEV_HSMMC1
+static inline void s3c6400_default_sdhci1(void)
+{
+       s3c_hsmmc1_def_platdata.clocks = s3c6400_hsmmc_clksrcs;
+       s3c_hsmmc1_def_platdata.cfg_gpio = s3c64xx_setup_sdhci1_cfg_gpio;
+       s3c_hsmmc1_def_platdata.cfg_card = s3c6400_setup_sdhci_cfg_card;
+}
+#else
+static inline void s3c6400_default_sdhci1(void) { }
+#endif /* CONFIG_S3C_DEV_HSMMC1 */
+
+#else
+static inline void s3c6400_default_sdhci0(void) { }
+static inline void s3c6400_default_sdhci1(void) { }
+#endif /* CONFIG_S3C6400_SETUP_SDHCI */
+
+/* S3C6410 SDHCI setup */
+
 #ifdef CONFIG_S3C6410_SETUP_SDHCI
 extern char *s3c6410_hsmmc_clksrcs[4];
 
-extern void s3c6410_setup_sdhci0_cfg_gpio(struct platform_device *, int w);
-extern void s3c6410_setup_sdhci1_cfg_gpio(struct platform_device *, int w);
-
 extern void s3c6410_setup_sdhci0_cfg_card(struct platform_device *dev,
                                           void __iomem *r,
                                           struct mmc_ios *ios,
@@ -82,7 +122,7 @@ extern void s3c6410_setup_sdhci0_cfg_card(struct platform_device *dev,
 static inline void s3c6410_default_sdhci0(void)
 {
        s3c_hsmmc0_def_platdata.clocks = s3c6410_hsmmc_clksrcs;
-       s3c_hsmmc0_def_platdata.cfg_gpio = s3c6410_setup_sdhci0_cfg_gpio;
+       s3c_hsmmc0_def_platdata.cfg_gpio = s3c64xx_setup_sdhci0_cfg_gpio;
        s3c_hsmmc0_def_platdata.cfg_card = s3c6410_setup_sdhci0_cfg_card;
 }
 #else
@@ -93,7 +133,7 @@ static inline void s3c6410_default_sdhci0(void) { }
 static inline void s3c6410_default_sdhci1(void)
 {
        s3c_hsmmc1_def_platdata.clocks = s3c6410_hsmmc_clksrcs;
-       s3c_hsmmc1_def_platdata.cfg_gpio = s3c6410_setup_sdhci1_cfg_gpio;
+       s3c_hsmmc1_def_platdata.cfg_gpio = s3c64xx_setup_sdhci1_cfg_gpio;
        s3c_hsmmc1_def_platdata.cfg_card = s3c6410_setup_sdhci0_cfg_card;
 }
 #else
diff --git a/arch/arm/plat-s3c/include/plat/udc-hs.h b/arch/arm/plat-s3c/include/plat/udc-hs.h
new file mode 100644 (file)
index 0000000..dd04db0
--- /dev/null
@@ -0,0 +1,29 @@
+/* arch/arm/plat-s3c/include/plat/udc-hs.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C USB2.0 High-speed / OtG platform information
+ *
+ * This 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.
+*/
+
+enum s3c_hostg_dmamode {
+       S3C_HSOTG_DMA_NONE,     /* do not use DMA at-all */
+       S3C_HSOTG_DMA_ONLY,     /* always use DMA */
+       S3C_HSOTG_DMA_DRV,      /* DMA is chosen by driver */
+};
+
+/**
+ * struct s3c_hsotg_plat - platform data for high-speed otg/udc
+ * @dma: Whether to use DMA or not.
+ * @is_osc: The clock source is an oscillator, not a crystal
+ */
+struct s3c_hsotg_plat {
+       enum s3c_hostg_dmamode  dma;
+       unsigned int            is_osc : 1;
+};
diff --git a/arch/arm/plat-s3c/include/plat/watchdog-reset.h b/arch/arm/plat-s3c/include/plat/watchdog-reset.h
new file mode 100644 (file)
index 0000000..54b762a
--- /dev/null
@@ -0,0 +1,49 @@
+/* arch/arm/plat-s3c/include/plat/watchdog-reset.h
+ *
+ * Copyright (c) 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 - System define for arch_reset() function
+ *
+ * This 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 <plat/regs-watchdog.h>
+#include <mach/map.h>
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+static inline void arch_wdt_reset(void)
+{
+       struct clk *wdtclk;
+
+       printk("arch_reset: attempting watchdog reset\n");
+
+       __raw_writel(0, S3C2410_WTCON);   /* disable watchdog, to be safe  */
+
+       wdtclk = clk_get(NULL, "watchdog");
+       if (!IS_ERR(wdtclk)) {
+               clk_enable(wdtclk);
+       } else
+               printk(KERN_WARNING "%s: warning: cannot get watchdog clock\n", __func__);
+
+       /* put initial values into count and data */
+       __raw_writel(0x80, S3C2410_WTCNT);
+       __raw_writel(0x80, S3C2410_WTDAT);
+
+       /* set the watchdog to go and reset... */
+       __raw_writel(S3C2410_WTCON_ENABLE|S3C2410_WTCON_DIV16|S3C2410_WTCON_RSTEN |
+                    S3C2410_WTCON_PRESCALE(0x20), S3C2410_WTCON);
+
+       /* wait for reset to assert... */
+       mdelay(500);
+
+       printk(KERN_ERR "Watchdog reset failed to assert reset\n");
+
+       /* delay to allow the serial port to show the message */
+       mdelay(50);
+}
diff --git a/arch/arm/plat-s3c/pm-gpio.c b/arch/arm/plat-s3c/pm-gpio.c
new file mode 100644 (file)
index 0000000..cfd326a
--- /dev/null
@@ -0,0 +1,380 @@
+
+/* linux/arch/arm/plat-s3c/pm-gpio.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * S3C series GPIO PM code
+ *
+ * This 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/sysdev.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <mach/gpio-core.h>
+#include <plat/pm.h>
+
+/* PM GPIO helpers */
+
+#define OFFS_CON       (0x00)
+#define OFFS_DAT       (0x04)
+#define OFFS_UP                (0x08)
+
+static void s3c_gpio_pm_1bit_save(struct s3c_gpio_chip *chip)
+{
+       chip->pm_save[0] = __raw_readl(chip->base + OFFS_CON);
+       chip->pm_save[1] = __raw_readl(chip->base + OFFS_DAT);
+}
+
+static void s3c_gpio_pm_1bit_resume(struct s3c_gpio_chip *chip)
+{
+       void __iomem *base = chip->base;
+       u32 old_gpcon = __raw_readl(base + OFFS_CON);
+       u32 old_gpdat = __raw_readl(base + OFFS_DAT);
+       u32 gps_gpcon = chip->pm_save[0];
+       u32 gps_gpdat = chip->pm_save[1];
+       u32 gpcon;
+
+       /* GPACON only has one bit per control / data and no PULLUPs.
+        * GPACON[x] = 0 => Output, 1 => SFN */
+
+       /* first set all SFN bits to SFN */
+
+       gpcon = old_gpcon | gps_gpcon;
+       __raw_writel(gpcon, base + OFFS_CON);
+
+       /* now set all the other bits */
+
+       __raw_writel(gps_gpdat, base + OFFS_DAT);
+       __raw_writel(gps_gpcon, base + OFFS_CON);
+
+       S3C_PMDBG("%s: CON %08x => %08x, DAT %08x => %08x\n",
+                 chip->chip.label, old_gpcon, gps_gpcon, old_gpdat, gps_gpdat);
+}
+
+struct s3c_gpio_pm s3c_gpio_pm_1bit = {
+       .save   = s3c_gpio_pm_1bit_save,
+       .resume = s3c_gpio_pm_1bit_resume,
+};
+
+static void s3c_gpio_pm_2bit_save(struct s3c_gpio_chip *chip)
+{
+       chip->pm_save[0] = __raw_readl(chip->base + OFFS_CON);
+       chip->pm_save[1] = __raw_readl(chip->base + OFFS_DAT);
+       chip->pm_save[2] = __raw_readl(chip->base + OFFS_UP);
+}
+
+/* Test whether the given masked+shifted bits of an GPIO configuration
+ * are one of the SFN (special function) modes. */
+
+static inline int is_sfn(unsigned long con)
+{
+       return con >= 2;
+}
+
+/* Test if the given masked+shifted GPIO configuration is an input */
+
+static inline int is_in(unsigned long con)
+{
+       return con == 0;
+}
+
+/* Test if the given masked+shifted GPIO configuration is an output */
+
+static inline int is_out(unsigned long con)
+{
+       return con == 1;
+}
+
+/**
+ * s3c_gpio_pm_2bit_resume() - restore the given GPIO bank
+ * @chip: The chip information to resume.
+ *
+ * Restore one of the GPIO banks that was saved during suspend. This is
+ * not as simple as once thought, due to the possibility of glitches
+ * from the order that the CON and DAT registers are set in.
+ *
+ * The three states the pin can be are {IN,OUT,SFN} which gives us 9
+ * combinations of changes to check. Three of these, if the pin stays
+ * in the same configuration can be discounted. This leaves us with
+ * the following:
+ *
+ * { IN => OUT }  Change DAT first
+ * { IN => SFN }  Change CON first
+ * { OUT => SFN } Change CON first, so new data will not glitch
+ * { OUT => IN }  Change CON first, so new data will not glitch
+ * { SFN => IN }  Change CON first
+ * { SFN => OUT } Change DAT first, so new data will not glitch [1]
+ *
+ * We do not currently deal with the UP registers as these control
+ * weak resistors, so a small delay in change should not need to bring
+ * these into the calculations.
+ *
+ * [1] this assumes that writing to a pin DAT whilst in SFN will set the
+ *     state for when it is next output.
+ */
+static void s3c_gpio_pm_2bit_resume(struct s3c_gpio_chip *chip)
+{
+       void __iomem *base = chip->base;
+       u32 old_gpcon = __raw_readl(base + OFFS_CON);
+       u32 old_gpdat = __raw_readl(base + OFFS_DAT);
+       u32 gps_gpcon = chip->pm_save[0];
+       u32 gps_gpdat = chip->pm_save[1];
+       u32 gpcon, old, new, mask;
+       u32 change_mask = 0x0;
+       int nr;
+
+       /* restore GPIO pull-up settings */
+       __raw_writel(chip->pm_save[2], base + OFFS_UP);
+
+       /* Create a change_mask of all the items that need to have
+        * their CON value changed before their DAT value, so that
+        * we minimise the work between the two settings.
+        */
+
+       for (nr = 0, mask = 0x03; nr < 32; nr += 2, mask <<= 2) {
+               old = (old_gpcon & mask) >> nr;
+               new = (gps_gpcon & mask) >> nr;
+
+               /* If there is no change, then skip */
+
+               if (old == new)
+                       continue;
+
+               /* If both are special function, then skip */
+
+               if (is_sfn(old) && is_sfn(new))
+                       continue;
+
+               /* Change is IN => OUT, do not change now */
+
+               if (is_in(old) && is_out(new))
+                       continue;
+
+               /* Change is SFN => OUT, do not change now */
+
+               if (is_sfn(old) && is_out(new))
+                       continue;
+
+               /* We should now be at the case of IN=>SFN,
+                * OUT=>SFN, OUT=>IN, SFN=>IN. */
+
+               change_mask |= mask;
+       }
+
+
+       /* Write the new CON settings */
+
+       gpcon = old_gpcon & ~change_mask;
+       gpcon |= gps_gpcon & change_mask;
+
+       __raw_writel(gpcon, base + OFFS_CON);
+
+       /* Now change any items that require DAT,CON */
+
+       __raw_writel(gps_gpdat, base + OFFS_DAT);
+       __raw_writel(gps_gpcon, base + OFFS_CON);
+
+       S3C_PMDBG("%s: CON %08x => %08x, DAT %08x => %08x\n",
+                 chip->chip.label, old_gpcon, gps_gpcon, old_gpdat, gps_gpdat);
+}
+
+struct s3c_gpio_pm s3c_gpio_pm_2bit = {
+       .save   = s3c_gpio_pm_2bit_save,
+       .resume = s3c_gpio_pm_2bit_resume,
+};
+
+#ifdef CONFIG_ARCH_S3C64XX
+static void s3c_gpio_pm_4bit_save(struct s3c_gpio_chip *chip)
+{
+       chip->pm_save[1] = __raw_readl(chip->base + OFFS_CON);
+       chip->pm_save[2] = __raw_readl(chip->base + OFFS_DAT);
+       chip->pm_save[3] = __raw_readl(chip->base + OFFS_UP);
+
+       if (chip->chip.ngpio > 8)
+               chip->pm_save[0] = __raw_readl(chip->base - 4);
+}
+
+static u32 s3c_gpio_pm_4bit_mask(u32 old_gpcon, u32 gps_gpcon)
+{
+       u32 old, new, mask;
+       u32 change_mask = 0x0;
+       int nr;
+
+       for (nr = 0, mask = 0x0f; nr < 16; nr += 4, mask <<= 4) {
+               old = (old_gpcon & mask) >> nr;
+               new = (gps_gpcon & mask) >> nr;
+
+               /* If there is no change, then skip */
+
+               if (old == new)
+                       continue;
+
+               /* If both are special function, then skip */
+
+               if (is_sfn(old) && is_sfn(new))
+                       continue;
+
+               /* Change is IN => OUT, do not change now */
+
+               if (is_in(old) && is_out(new))
+                       continue;
+
+               /* Change is SFN => OUT, do not change now */
+
+               if (is_sfn(old) && is_out(new))
+                       continue;
+
+               /* We should now be at the case of IN=>SFN,
+                * OUT=>SFN, OUT=>IN, SFN=>IN. */
+
+               change_mask |= mask;
+       }
+
+       return change_mask;
+}
+
+static void s3c_gpio_pm_4bit_con(struct s3c_gpio_chip *chip, int index)
+{
+       void __iomem *con = chip->base + (index * 4);
+       u32 old_gpcon = __raw_readl(con);
+       u32 gps_gpcon = chip->pm_save[index + 1];
+       u32 gpcon, mask;
+
+       mask = s3c_gpio_pm_4bit_mask(old_gpcon, gps_gpcon);
+
+       gpcon = old_gpcon & ~mask;
+       gpcon |= gps_gpcon & mask;
+
+       __raw_writel(gpcon, con);
+}
+
+static void s3c_gpio_pm_4bit_resume(struct s3c_gpio_chip *chip)
+{
+       void __iomem *base = chip->base;
+       u32 old_gpcon[2];
+       u32 old_gpdat = __raw_readl(base + OFFS_DAT);
+       u32 gps_gpdat = chip->pm_save[2];
+
+       /* First, modify the CON settings */
+
+       old_gpcon[0] = 0;
+       old_gpcon[1] = __raw_readl(base + OFFS_CON);
+
+       s3c_gpio_pm_4bit_con(chip, 0);
+       if (chip->chip.ngpio > 8) {
+               old_gpcon[0] = __raw_readl(base - 4);
+               s3c_gpio_pm_4bit_con(chip, -1);
+       }
+
+       /* Now change the configurations that require DAT,CON */
+
+       __raw_writel(chip->pm_save[2], base + OFFS_DAT);
+       __raw_writel(chip->pm_save[1], base + OFFS_CON);
+       if (chip->chip.ngpio > 8)
+               __raw_writel(chip->pm_save[0], base - 4);
+
+       __raw_writel(chip->pm_save[2], base + OFFS_DAT);
+       __raw_writel(chip->pm_save[3], base + OFFS_UP);
+
+       if (chip->chip.ngpio > 8) {
+               S3C_PMDBG("%s: CON4 %08x,%08x => %08x,%08x, DAT %08x => %08x\n",
+                         chip->chip.label, old_gpcon[0], old_gpcon[1],
+                         __raw_readl(base - 4),
+                         __raw_readl(base + OFFS_CON),
+                         old_gpdat, gps_gpdat);
+       } else
+               S3C_PMDBG("%s: CON4 %08x => %08x, DAT %08x => %08x\n",
+                         chip->chip.label, old_gpcon[1],
+                         __raw_readl(base + OFFS_CON),
+                         old_gpdat, gps_gpdat);
+}
+
+struct s3c_gpio_pm s3c_gpio_pm_4bit = {
+       .save   = s3c_gpio_pm_4bit_save,
+       .resume = s3c_gpio_pm_4bit_resume,
+};
+#endif /* CONFIG_ARCH_S3C64XX */
+
+/**
+ * s3c_pm_save_gpio() - save gpio chip data for suspend
+ * @ourchip: The chip for suspend.
+ */
+static void s3c_pm_save_gpio(struct s3c_gpio_chip *ourchip)
+{
+       struct s3c_gpio_pm *pm = ourchip->pm;
+
+       if (pm == NULL || pm->save == NULL)
+               S3C_PMDBG("%s: no pm for %s\n", __func__, ourchip->chip.label);
+       else
+               pm->save(ourchip);
+}
+
+/**
+ * s3c_pm_save_gpios() - Save the state of the GPIO banks.
+ *
+ * For all the GPIO banks, save the state of each one ready for going
+ * into a suspend mode.
+ */
+void s3c_pm_save_gpios(void)
+{
+       struct s3c_gpio_chip *ourchip;
+       unsigned int gpio_nr;
+
+       for (gpio_nr = 0; gpio_nr < S3C_GPIO_END; gpio_nr++) {
+               ourchip = s3c_gpiolib_getchip(gpio_nr);
+               if (!ourchip)
+                       continue;
+
+               s3c_pm_save_gpio(ourchip);
+
+               S3C_PMDBG("%s: save %08x,%08x,%08x,%08x\n",
+                         ourchip->chip.label,
+                         ourchip->pm_save[0],
+                         ourchip->pm_save[1],
+                         ourchip->pm_save[2],
+                         ourchip->pm_save[3]);
+
+               gpio_nr += ourchip->chip.ngpio;
+               gpio_nr += CONFIG_S3C_GPIO_SPACE;
+       }
+}
+
+/**
+ * s3c_pm_resume_gpio() - restore gpio chip data after suspend
+ * @ourchip: The suspended chip.
+ */
+static void s3c_pm_resume_gpio(struct s3c_gpio_chip *ourchip)
+{
+       struct s3c_gpio_pm *pm = ourchip->pm;
+
+       if (pm == NULL || pm->resume == NULL)
+               S3C_PMDBG("%s: no pm for %s\n", __func__, ourchip->chip.label);
+       else
+               pm->resume(ourchip);
+}
+
+void s3c_pm_restore_gpios(void)
+{
+       struct s3c_gpio_chip *ourchip;
+       unsigned int gpio_nr;
+
+       for (gpio_nr = 0; gpio_nr < S3C_GPIO_END; gpio_nr++) {
+               ourchip = s3c_gpiolib_getchip(gpio_nr);
+               if (!ourchip)
+                       continue;
+
+               s3c_pm_resume_gpio(ourchip);
+
+               gpio_nr += ourchip->chip.ngpio;
+               gpio_nr += CONFIG_S3C_GPIO_SPACE;
+       }
+}
index 061182ca66e392246beae1abb29411339b338a8d..8d97db2c7a0d37ce743a699fe02dc0be7b8e955a 100644 (file)
 
 #include <asm/cacheflush.h>
 #include <mach/hardware.h>
+#include <mach/map.h>
 
 #include <plat/regs-serial.h>
 #include <mach/regs-clock.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-mem.h>
 #include <mach/regs-irq.h>
 #include <asm/irq.h>
 
@@ -70,6 +69,8 @@ static inline void s3c_pm_debug_init(void)
 
 /* Save the UART configurations if we are configured for debug. */
 
+unsigned char pm_uart_udivslot;
+
 #ifdef CONFIG_S3C2410_PM_DEBUG
 
 struct pm_uart_save uart_save[CONFIG_SERIAL_SAMSUNG_UARTS];
@@ -83,6 +84,12 @@ static void s3c_pm_save_uart(unsigned int uart, struct pm_uart_save *save)
        save->ufcon = __raw_readl(regs + S3C2410_UFCON);
        save->umcon = __raw_readl(regs + S3C2410_UMCON);
        save->ubrdiv = __raw_readl(regs + S3C2410_UBRDIV);
+
+       if (pm_uart_udivslot)
+               save->udivslot = __raw_readl(regs + S3C2443_DIVSLOT);
+
+       S3C_PMDBG("UART[%d]: ULCON=%04x, UCON=%04x, UFCON=%04x, UBRDIV=%04x\n",
+                 uart, save->ulcon, save->ucon, save->ufcon, save->ubrdiv);
 }
 
 static void s3c_pm_save_uarts(void)
@@ -98,11 +105,16 @@ static void s3c_pm_restore_uart(unsigned int uart, struct pm_uart_save *save)
 {
        void __iomem *regs = S3C_VA_UARTx(uart);
 
+       s3c_pm_arch_update_uart(regs, save);
+
        __raw_writel(save->ulcon, regs + S3C2410_ULCON);
        __raw_writel(save->ucon,  regs + S3C2410_UCON);
        __raw_writel(save->ufcon, regs + S3C2410_UFCON);
        __raw_writel(save->umcon, regs + S3C2410_UMCON);
        __raw_writel(save->ubrdiv, regs + S3C2410_UBRDIV);
+
+       if (pm_uart_udivslot)
+               __raw_writel(save->udivslot, regs + S3C2443_DIVSLOT);
 }
 
 static void s3c_pm_restore_uarts(void)
@@ -313,6 +325,9 @@ static int s3c_pm_enter(suspend_state_t state)
 
        S3C_PMDBG("%s: post sleep, preparing to return\n", __func__);
 
+       /* LEDs should now be 1110 */
+       s3c_pm_debug_smdkled(1 << 1, 0);
+
        s3c_pm_check_restore();
 
        /* ok, let's return from sleep */
index 2c8a2f5d75ffb5a40553047f30c4ea28d7ccd52b..5b0bc914f58ed02494bfaf2b0562e2bcf8ab4216 100644 (file)
@@ -71,6 +71,7 @@ config PM_SIMTEC
 config S3C2410_DMA
        bool "S3C2410 DMA support"
        depends on ARCH_S3C2410
+       select S3C_DMA
        help
          S3C2410 DMA support. This is needed for drivers like sound which
          use the S3C2410's DMA system to move data to and from the
index 91adfa71c1724f30b55a5d72c5e8bd25f32321bf..ee1baf11ad9e9851754a3514d1c6eb359f7de4ca 100644 (file)
@@ -45,7 +45,8 @@ struct s3c_adc_client {
        unsigned char            channel;
 
        void    (*select_cb)(unsigned selected);
-       void    (*convert_cb)(unsigned val1, unsigned val2);
+       void    (*convert_cb)(unsigned val1, unsigned val2,
+                             unsigned *samples_left);
 };
 
 struct adc_device {
@@ -158,7 +159,8 @@ static void s3c_adc_default_select(unsigned select)
 
 struct s3c_adc_client *s3c_adc_register(struct platform_device *pdev,
                                        void (*select)(unsigned int selected),
-                                       void (*conv)(unsigned d0, unsigned d1),
+                                       void (*conv)(unsigned d0, unsigned d1,
+                                                    unsigned *samples_left),
                                        unsigned int is_ts)
 {
        struct s3c_adc_client *client;
@@ -227,9 +229,10 @@ static irqreturn_t s3c_adc_irq(int irq, void *pw)
        data1 = readl(adc->regs + S3C2410_ADCDAT1);
        adc_dbg(adc, "read %d: 0x%04x, 0x%04x\n", client->nr_samples, data0, data1);
 
-       (client->convert_cb)(data0 & 0x3ff, data1 & 0x3ff);
+       client->nr_samples--;
+       (client->convert_cb)(data0 & 0x3ff, data1 & 0x3ff, &client->nr_samples);
 
-       if (--client->nr_samples > 0) {
+       if (client->nr_samples > 0) {
                /* fire another conversion for this */
 
                client->select_cb(1);
index 1a8347cec20a3da803ecaf5c7f8dba269a2270ee..aa119863c5cec428691353b4869dfc93d5df1af4 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
 #include <linux/sysdev.h>
 #include <linux/platform_device.h>
 
 /* LED devices */
 
 static struct s3c24xx_led_platdata smdk_pdata_led4 = {
-       .gpio           = S3C2410_GPF4,
+       .gpio           = S3C2410_GPF(4),
        .flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
        .name           = "led4",
        .def_trigger    = "timer",
 };
 
 static struct s3c24xx_led_platdata smdk_pdata_led5 = {
-       .gpio           = S3C2410_GPF5,
+       .gpio           = S3C2410_GPF(5),
        .flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
        .name           = "led5",
        .def_trigger    = "nand-disk",
 };
 
 static struct s3c24xx_led_platdata smdk_pdata_led6 = {
-       .gpio           = S3C2410_GPF6,
+       .gpio           = S3C2410_GPF(6),
        .flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
        .name           = "led6",
 };
 
 static struct s3c24xx_led_platdata smdk_pdata_led7 = {
-       .gpio           = S3C2410_GPF7,
+       .gpio           = S3C2410_GPF(7),
        .flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
        .name           = "led7",
 };
@@ -184,15 +185,15 @@ void __init smdk_machine_init(void)
 {
        /* Configure the LEDs (even if we have no LED support)*/
 
-       s3c2410_gpio_cfgpin(S3C2410_GPF4, S3C2410_GPF4_OUTP);
-       s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);
-       s3c2410_gpio_cfgpin(S3C2410_GPF6, S3C2410_GPF6_OUTP);
-       s3c2410_gpio_cfgpin(S3C2410_GPF7, S3C2410_GPF7_OUTP);
+       s3c2410_gpio_cfgpin(S3C2410_GPF(4), S3C2410_GPIO_OUTPUT);
+       s3c2410_gpio_cfgpin(S3C2410_GPF(5), S3C2410_GPIO_OUTPUT);
+       s3c2410_gpio_cfgpin(S3C2410_GPF(6), S3C2410_GPIO_OUTPUT);
+       s3c2410_gpio_cfgpin(S3C2410_GPF(7), S3C2410_GPIO_OUTPUT);
 
-       s3c2410_gpio_setpin(S3C2410_GPF4, 1);
-       s3c2410_gpio_setpin(S3C2410_GPF5, 1);
-       s3c2410_gpio_setpin(S3C2410_GPF6, 1);
-       s3c2410_gpio_setpin(S3C2410_GPF7, 1);
+       s3c2410_gpio_setpin(S3C2410_GPF(4), 1);
+       s3c2410_gpio_setpin(S3C2410_GPF(5), 1);
+       s3c2410_gpio_setpin(S3C2410_GPF(6), 1);
+       s3c2410_gpio_setpin(S3C2410_GPF(7), 1);
 
        if (machine_is_smdk2443())
                smdk_nand_info.twrph0 = 50;
index 16ac01d9b8ab631c023bc309d30e45f9289e1835..4eb378c89a390541ca3e17bbd3d4eefaf866031b 100644 (file)
@@ -136,36 +136,6 @@ struct platform_device *s3c24xx_uart_src[4] = {
 struct platform_device *s3c24xx_uart_devs[4] = {
 };
 
-/* USB Host Controller */
-
-static struct resource s3c_usb_resource[] = {
-       [0] = {
-               .start = S3C24XX_PA_USBHOST,
-               .end   = S3C24XX_PA_USBHOST + S3C24XX_SZ_USBHOST - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start = IRQ_USBH,
-               .end   = IRQ_USBH,
-               .flags = IORESOURCE_IRQ,
-       }
-};
-
-static u64 s3c_device_usb_dmamask = 0xffffffffUL;
-
-struct platform_device s3c_device_usb = {
-       .name             = "s3c2410-ohci",
-       .id               = -1,
-       .num_resources    = ARRAY_SIZE(s3c_usb_resource),
-       .resource         = s3c_usb_resource,
-       .dev              = {
-               .dma_mask = &s3c_device_usb_dmamask,
-               .coherent_dma_mask = 0xffffffffUL
-       }
-};
-
-EXPORT_SYMBOL(s3c_device_usb);
-
 /* LCD Controller */
 
 static struct resource s3c_lcd_resource[] = {
index 07326f632361dbd4e6cfe3656780f172b550ddc5..196b19123653a244bc9da318a25c8b6fc5977d01 100644 (file)
 #include <asm/irq.h>
 #include <mach/hardware.h>
 #include <mach/dma.h>
-
 #include <mach/map.h>
 
-#include <plat/dma.h>
+#include <plat/dma-plat.h>
+#include <plat/regs-dma.h>
 
 /* io map for dma */
 static void __iomem *dma_base;
@@ -44,8 +44,6 @@ static int dma_channels;
 
 static struct s3c24xx_dma_selection dma_sel;
 
-/* dma channel state information */
-struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS];
 
 /* debugging functions */
 
@@ -135,21 +133,6 @@ dmadbg_showregs(const char *fname, int line, struct s3c2410_dma_chan *chan)
 #define dbg_showchan(chan) do { } while(0)
 #endif /* CONFIG_S3C2410_DMA_DEBUG */
 
-static struct s3c2410_dma_chan *dma_chan_map[DMACH_MAX];
-
-/* lookup_dma_channel
- *
- * change the dma channel number given into a real dma channel id
-*/
-
-static struct s3c2410_dma_chan *lookup_dma_channel(unsigned int channel)
-{
-       if (channel & DMACH_LOW_LEVEL)
-               return &s3c2410_chans[channel & ~DMACH_LOW_LEVEL];
-       else
-               return dma_chan_map[channel];
-}
-
 /* s3c2410_dma_stats_timeout
  *
  * Update DMA stats from timeout info
@@ -214,8 +197,6 @@ s3c2410_dma_waitforload(struct s3c2410_dma_chan *chan, int line)
        return 0;
 }
 
-
-
 /* s3c2410_dma_loadbuffer
  *
  * load a buffer, and update the channel state
@@ -453,7 +434,7 @@ s3c2410_dma_canload(struct s3c2410_dma_chan *chan)
 int s3c2410_dma_enqueue(unsigned int channel, void *id,
                        dma_addr_t data, int size)
 {
-       struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+       struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
        struct s3c2410_dma_buf *buf;
        unsigned long flags;
 
@@ -804,7 +785,7 @@ EXPORT_SYMBOL(s3c2410_dma_request);
 
 int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *client)
 {
-       struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+       struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
        unsigned long flags;
 
        if (chan == NULL)
@@ -836,7 +817,7 @@ int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *client)
        chan->irq_claimed = 0;
 
        if (!(channel & DMACH_LOW_LEVEL))
-               dma_chan_map[channel] = NULL;
+               s3c_dma_chan_map[channel] = NULL;
 
        local_irq_restore(flags);
 
@@ -995,7 +976,7 @@ static int s3c2410_dma_started(struct s3c2410_dma_chan *chan)
 int
 s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op)
 {
-       struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+       struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
 
        if (chan == NULL)
                return -EINVAL;
@@ -1038,14 +1019,13 @@ EXPORT_SYMBOL(s3c2410_dma_ctrl);
 /* s3c2410_dma_config
  *
  * xfersize:     size of unit in bytes (1,2,4)
- * dcon:         base value of the DCONx register
 */
 
 int s3c2410_dma_config(unsigned int channel,
-                      int xferunit,
-                      int dcon)
+                      int xferunit)
 {
-       struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+       struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+       unsigned int dcon;
 
        pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n",
                 __func__, channel, xferunit, dcon);
@@ -1055,10 +1035,33 @@ int s3c2410_dma_config(unsigned int channel,
 
        pr_debug("%s: Initial dcon is %08x\n", __func__, dcon);
 
-       dcon |= chan->dcon & dma_sel.dcon_mask;
+       dcon = chan->dcon & dma_sel.dcon_mask;
 
        pr_debug("%s: New dcon is %08x\n", __func__, dcon);
 
+       switch (chan->req_ch) {
+       case DMACH_I2S_IN:
+       case DMACH_I2S_OUT:
+       case DMACH_PCM_IN:
+       case DMACH_PCM_OUT:
+       case DMACH_MIC_IN:
+       default:
+               dcon |= S3C2410_DCON_HANDSHAKE;
+               dcon |= S3C2410_DCON_SYNC_PCLK;
+               break;
+
+       case DMACH_SDI:
+               /* note, ensure if need HANDSHAKE or not */
+               dcon |= S3C2410_DCON_SYNC_PCLK;
+               break;
+
+       case DMACH_XD0:
+       case DMACH_XD1:
+               dcon |= S3C2410_DCON_HANDSHAKE;
+               dcon |= S3C2410_DCON_SYNC_HCLK;
+               break;
+       }
+
        switch (xferunit) {
        case 1:
                dcon |= S3C2410_DCON_BYTE;
@@ -1090,58 +1093,6 @@ int s3c2410_dma_config(unsigned int channel,
 
 EXPORT_SYMBOL(s3c2410_dma_config);
 
-int s3c2410_dma_setflags(unsigned int channel, unsigned int flags)
-{
-       struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
-
-       if (chan == NULL)
-               return -EINVAL;
-
-       pr_debug("%s: chan=%p, flags=%08x\n", __func__, chan, flags);
-
-       chan->flags = flags;
-
-       return 0;
-}
-
-EXPORT_SYMBOL(s3c2410_dma_setflags);
-
-
-/* do we need to protect the settings of the fields from
- * irq?
-*/
-
-int s3c2410_dma_set_opfn(unsigned int channel, s3c2410_dma_opfn_t rtn)
-{
-       struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
-
-       if (chan == NULL)
-               return -EINVAL;
-
-       pr_debug("%s: chan=%p, op rtn=%p\n", __func__, chan, rtn);
-
-       chan->op_fn = rtn;
-
-       return 0;
-}
-
-EXPORT_SYMBOL(s3c2410_dma_set_opfn);
-
-int s3c2410_dma_set_buffdone_fn(unsigned int channel, s3c2410_dma_cbfn_t rtn)
-{
-       struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
-
-       if (chan == NULL)
-               return -EINVAL;
-
-       pr_debug("%s: chan=%p, callback rtn=%p\n", __func__, chan, rtn);
-
-       chan->callback_fn = rtn;
-
-       return 0;
-}
-
-EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn);
 
 /* s3c2410_dma_devconfig
  *
@@ -1150,29 +1101,38 @@ EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn);
  * source:    S3C2410_DMASRC_HW: source is hardware
  *            S3C2410_DMASRC_MEM: source is memory
  *
- * hwcfg:     the value for xxxSTCn register,
- *            bit 0: 0=increment pointer, 1=leave pointer
- *            bit 1: 0=source is AHB, 1=source is APB
- *
  * devaddr:   physical address of the source
 */
 
 int s3c2410_dma_devconfig(int channel,
                          enum s3c2410_dmasrc source,
-                         int hwcfg,
                          unsigned long devaddr)
 {
-       struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+       struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+       unsigned int hwcfg;
 
        if (chan == NULL)
                return -EINVAL;
 
-       pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n",
-                __func__, (int)source, hwcfg, devaddr);
+       pr_debug("%s: source=%d, devaddr=%08lx\n",
+                __func__, (int)source, devaddr);
 
        chan->source = source;
        chan->dev_addr = devaddr;
-       chan->hw_cfg = hwcfg;
+
+       switch (chan->req_ch) {
+       case DMACH_XD0:
+       case DMACH_XD1:
+               hwcfg = 0; /* AHB */
+               break;
+
+       default:
+               hwcfg = S3C2410_DISRCC_APB;
+       }
+
+       /* always assume our peripheral desintation is a fixed
+        * address in memory. */
+        hwcfg |= S3C2410_DISRCC_INC;
 
        switch (source) {
        case S3C2410_DMASRC_HW:
@@ -1219,7 +1179,7 @@ EXPORT_SYMBOL(s3c2410_dma_devconfig);
 
 int s3c2410_dma_getposition(unsigned int channel, dma_addr_t *src, dma_addr_t *dst)
 {
-       struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+       struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
 
        if (chan == NULL)
                return -EINVAL;
@@ -1278,8 +1238,8 @@ static int s3c2410_dma_resume(struct sys_device *dev)
 
        printk(KERN_INFO "dma%d: restoring configuration\n", cp->number);
 
-       s3c2410_dma_config(no, cp->xfer_unit, cp->dcon);
-       s3c2410_dma_devconfig(no, cp->source, cp->hw_cfg, cp->dev_addr);
+       s3c2410_dma_config(no, cp->xfer_unit);
+       s3c2410_dma_devconfig(no, cp->source, cp->dev_addr);
 
        /* re-select the dma source for this channel */
 
@@ -1476,7 +1436,8 @@ static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
  found:
        dmach = &s3c2410_chans[ch];
        dmach->map = ch_map;
-       dma_chan_map[channel] = dmach;
+       dmach->req_ch = channel;
+       s3c_dma_chan_map[channel] = dmach;
 
        /* select the channel */
 
index 4a899c279eb547ca5578936b95df5b9ae5d5d910..95df059b5a1db2b7430ee52972b83034e6b3f6de 100644 (file)
@@ -183,35 +183,19 @@ EXPORT_SYMBOL(s3c2410_modify_misccr);
 
 int s3c2410_gpio_getirq(unsigned int pin)
 {
-       if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15)
-               return -1;      /* not valid interrupts */
+       if (pin < S3C2410_GPF(0) || pin > S3C2410_GPG(15))
+               return -EINVAL; /* not valid interrupts */
 
-       if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7)
-               return -1;      /* not valid pin */
+       if (pin < S3C2410_GPG(0) && pin > S3C2410_GPF(7))
+               return -EINVAL; /* not valid pin */
 
-       if (pin < S3C2410_GPF4)
-               return (pin - S3C2410_GPF0) + IRQ_EINT0;
+       if (pin < S3C2410_GPF(4))
+               return (pin - S3C2410_GPF(0)) + IRQ_EINT0;
 
-       if (pin < S3C2410_GPG0)
-               return (pin - S3C2410_GPF4) + IRQ_EINT4;
+       if (pin < S3C2410_GPG(0))
+               return (pin - S3C2410_GPF(4)) + IRQ_EINT4;
 
-       return (pin - S3C2410_GPG0) + IRQ_EINT8;
+       return (pin - S3C2410_GPG(0)) + IRQ_EINT8;
 }
 
 EXPORT_SYMBOL(s3c2410_gpio_getirq);
-
-int s3c2410_gpio_irq2pin(unsigned int irq)
-{
-       if (irq >= IRQ_EINT0 && irq <= IRQ_EINT3)
-               return S3C2410_GPF0 + (irq - IRQ_EINT0);
-
-       if (irq >= IRQ_EINT4 && irq <= IRQ_EINT7)
-               return S3C2410_GPF4 + (irq - IRQ_EINT4);
-
-       if (irq >= IRQ_EINT8 && irq <= IRQ_EINT23)
-               return S3C2410_GPG0 + (irq - IRQ_EINT8);
-
-       return -EINVAL;
-}
-
-EXPORT_SYMBOL(s3c2410_gpio_irq2pin);
index 5c0491bf738bf551adb98c74dc719ae3a10f1b0d..6d7a961d3269eb3c34a8e9b9e0a41b874c92a484 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/sysdev.h>
 #include <linux/ioport.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
@@ -22,6 +23,7 @@
 #include <mach/gpio-core.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
+#include <plat/pm.h>
 
 #include <mach/regs-gpio.h>
 
@@ -77,9 +79,10 @@ static int s3c24xx_gpiolib_bankg_toirq(struct gpio_chip *chip, unsigned offset)
 
 struct s3c_gpio_chip s3c24xx_gpios[] = {
        [0] = {
-               .base   = S3C24XX_GPIO_BASE(S3C2410_GPA0),
+               .base   = S3C2410_GPACON,
+               .pm     = __gpio_pm(&s3c_gpio_pm_1bit),
                .chip   = {
-                       .base                   = S3C2410_GPA0,
+                       .base                   = S3C2410_GPA(0),
                        .owner                  = THIS_MODULE,
                        .label                  = "GPIOA",
                        .ngpio                  = 24,
@@ -88,45 +91,50 @@ struct s3c_gpio_chip s3c24xx_gpios[] = {
                },
        },
        [1] = {
-               .base   = S3C24XX_GPIO_BASE(S3C2410_GPB0),
+               .base   = S3C2410_GPBCON,
+               .pm     = __gpio_pm(&s3c_gpio_pm_2bit),
                .chip   = {
-                       .base                   = S3C2410_GPB0,
+                       .base                   = S3C2410_GPB(0),
                        .owner                  = THIS_MODULE,
                        .label                  = "GPIOB",
                        .ngpio                  = 16,
                },
        },
        [2] = {
-               .base   = S3C24XX_GPIO_BASE(S3C2410_GPC0),
+               .base   = S3C2410_GPCCON,
+               .pm     = __gpio_pm(&s3c_gpio_pm_2bit),
                .chip   = {
-                       .base                   = S3C2410_GPC0,
+                       .base                   = S3C2410_GPC(0),
                        .owner                  = THIS_MODULE,
                        .label                  = "GPIOC",
                        .ngpio                  = 16,
                },
        },
        [3] = {
-               .base   = S3C24XX_GPIO_BASE(S3C2410_GPD0),
+               .base   = S3C2410_GPDCON,
+               .pm     = __gpio_pm(&s3c_gpio_pm_2bit),
                .chip   = {
-                       .base                   = S3C2410_GPD0,
+                       .base                   = S3C2410_GPD(0),
                        .owner                  = THIS_MODULE,
                        .label                  = "GPIOD",
                        .ngpio                  = 16,
                },
        },
        [4] = {
-               .base   = S3C24XX_GPIO_BASE(S3C2410_GPE0),
+               .base   = S3C2410_GPECON,
+               .pm     = __gpio_pm(&s3c_gpio_pm_2bit),
                .chip   = {
-                       .base                   = S3C2410_GPE0,
+                       .base                   = S3C2410_GPE(0),
                        .label                  = "GPIOE",
                        .owner                  = THIS_MODULE,
                        .ngpio                  = 16,
                },
        },
        [5] = {
-               .base   = S3C24XX_GPIO_BASE(S3C2410_GPF0),
+               .base   = S3C2410_GPFCON,
+               .pm     = __gpio_pm(&s3c_gpio_pm_2bit),
                .chip   = {
-                       .base                   = S3C2410_GPF0,
+                       .base                   = S3C2410_GPF(0),
                        .owner                  = THIS_MODULE,
                        .label                  = "GPIOF",
                        .ngpio                  = 8,
@@ -134,14 +142,24 @@ struct s3c_gpio_chip s3c24xx_gpios[] = {
                },
        },
        [6] = {
-               .base   = S3C24XX_GPIO_BASE(S3C2410_GPG0),
+               .base   = S3C2410_GPGCON,
+               .pm     = __gpio_pm(&s3c_gpio_pm_2bit),
                .chip   = {
-                       .base                   = S3C2410_GPG0,
+                       .base                   = S3C2410_GPG(0),
                        .owner                  = THIS_MODULE,
                        .label                  = "GPIOG",
-                       .ngpio                  = 10,
+                       .ngpio                  = 16,
                        .to_irq                 = s3c24xx_gpiolib_bankg_toirq,
                },
+       }, {
+               .base   = S3C2410_GPHCON,
+               .pm     = __gpio_pm(&s3c_gpio_pm_2bit),
+               .chip   = {
+                       .base                   = S3C2410_GPH(0),
+                       .owner                  = THIS_MODULE,
+                       .label                  = "GPIOH",
+                       .ngpio                  = 11,
+               },
        },
 };
 
@@ -156,4 +174,4 @@ static __init int s3c24xx_gpiolib_init(void)
        return 0;
 }
 
-arch_initcall(s3c24xx_gpiolib_init);
+core_initcall(s3c24xx_gpiolib_init);
diff --git a/arch/arm/plat-s3c24xx/include/plat/dma-plat.h b/arch/arm/plat-s3c24xx/include/plat/dma-plat.h
new file mode 100644 (file)
index 0000000..9565ead
--- /dev/null
@@ -0,0 +1,84 @@
+/* linux/arch/arm/plat-s3c24xx/include/plat/dma-plat.h
+ *
+ * Copyright (C) 2006 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Samsung S3C24XX DMA 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 <plat/dma-core.h>
+
+extern struct sysdev_class dma_sysclass;
+extern struct s3c2410_dma_chan s3c2410_chans[S3C_DMA_CHANNELS];
+
+#define DMA_CH_VALID           (1<<31)
+#define DMA_CH_NEVER           (1<<30)
+
+struct s3c24xx_dma_addr {
+       unsigned long           from;
+       unsigned long           to;
+};
+
+/* struct s3c24xx_dma_map
+ *
+ * this holds the mapping information for the channel selected
+ * to be connected to the specified device
+*/
+
+struct s3c24xx_dma_map {
+       const char              *name;
+       struct s3c24xx_dma_addr  hw_addr;
+
+       unsigned long            channels[S3C_DMA_CHANNELS];
+       unsigned long            channels_rx[S3C_DMA_CHANNELS];
+};
+
+struct s3c24xx_dma_selection {
+       struct s3c24xx_dma_map  *map;
+       unsigned long            map_size;
+       unsigned long            dcon_mask;
+
+       void    (*select)(struct s3c2410_dma_chan *chan,
+                         struct s3c24xx_dma_map *map);
+
+       void    (*direction)(struct s3c2410_dma_chan *chan,
+                            struct s3c24xx_dma_map *map,
+                            enum s3c2410_dmasrc dir);
+};
+
+extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel);
+
+/* struct s3c24xx_dma_order_ch
+ *
+ * channel map for one of the `enum dma_ch` dma channels. the list
+ * entry contains a set of low-level channel numbers, orred with
+ * DMA_CH_VALID, which are checked in the order in the array.
+*/
+
+struct s3c24xx_dma_order_ch {
+       unsigned int    list[S3C_DMA_CHANNELS]; /* list of channels */
+       unsigned int    flags;                          /* flags */
+};
+
+/* struct s3c24xx_dma_order
+ *
+ * information provided by either the core or the board to give the
+ * dma system a hint on how to allocate channels
+*/
+
+struct s3c24xx_dma_order {
+       struct s3c24xx_dma_order_ch     channels[DMACH_MAX];
+};
+
+extern int s3c24xx_dma_order_set(struct s3c24xx_dma_order *map);
+
+/* DMA init code, called from the cpu support code */
+
+extern int s3c2410_dma_init(void);
+
+extern int s3c24xx_dma_init(unsigned int channels, unsigned int irq,
+                           unsigned int stride);
diff --git a/arch/arm/plat-s3c24xx/include/plat/dma.h b/arch/arm/plat-s3c24xx/include/plat/dma.h
deleted file mode 100644 (file)
index c78efe3..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/* linux/include/asm-arm/plat-s3c24xx/dma.h
- *
- * Copyright (C) 2006 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * Samsung S3C24XX DMA 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.
-*/
-
-extern struct sysdev_class dma_sysclass;
-extern struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS];
-
-#define DMA_CH_VALID           (1<<31)
-#define DMA_CH_NEVER           (1<<30)
-
-struct s3c24xx_dma_addr {
-       unsigned long           from;
-       unsigned long           to;
-};
-
-/* struct s3c24xx_dma_map
- *
- * this holds the mapping information for the channel selected
- * to be connected to the specified device
-*/
-
-struct s3c24xx_dma_map {
-       const char              *name;
-       struct s3c24xx_dma_addr  hw_addr;
-
-       unsigned long            channels[S3C2410_DMA_CHANNELS];
-       unsigned long            channels_rx[S3C2410_DMA_CHANNELS];
-};
-
-struct s3c24xx_dma_selection {
-       struct s3c24xx_dma_map  *map;
-       unsigned long            map_size;
-       unsigned long            dcon_mask;
-
-       void    (*select)(struct s3c2410_dma_chan *chan,
-                         struct s3c24xx_dma_map *map);
-
-       void    (*direction)(struct s3c2410_dma_chan *chan,
-                            struct s3c24xx_dma_map *map,
-                            enum s3c2410_dmasrc dir);
-};
-
-extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel);
-
-/* struct s3c24xx_dma_order_ch
- *
- * channel map for one of the `enum dma_ch` dma channels. the list
- * entry contains a set of low-level channel numbers, orred with
- * DMA_CH_VALID, which are checked in the order in the array.
-*/
-
-struct s3c24xx_dma_order_ch {
-       unsigned int    list[S3C2410_DMA_CHANNELS];     /* list of channels */
-       unsigned int    flags;                          /* flags */
-};
-
-/* struct s3c24xx_dma_order
- *
- * information provided by either the core or the board to give the
- * dma system a hint on how to allocate channels
-*/
-
-struct s3c24xx_dma_order {
-       struct s3c24xx_dma_order_ch     channels[DMACH_MAX];
-};
-
-extern int s3c24xx_dma_order_set(struct s3c24xx_dma_order *map);
-
-/* DMA init code, called from the cpu support code */
-
-extern int s3c2410_dma_init(void);
-
-extern int s3c24xx_dma_init(unsigned int channels, unsigned int irq,
-                           unsigned int stride);
index eed8f78e75930d76580391bcf6f0a6f51a89add0..c4d133436fc79af2844817797fe3ab79d49b88cd 100644 (file)
@@ -58,7 +58,6 @@
 #define S3C24XX_SZ_SPI         SZ_1M
 #define S3C24XX_SZ_SDI         SZ_1M
 #define S3C24XX_SZ_NAND                SZ_1M
-#define S3C24XX_SZ_USBHOST     SZ_1M
 
 /* GPIO ports */
 
index c75882113e049bf36233ce3e1c84f381643668d4..fb45dd9adca5689e575f3aa8a295b62108762b16 100644 (file)
@@ -57,3 +57,8 @@ static inline void s3c_pm_arch_show_resume_irqs(void)
        s3c_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND),
                                s3c_irqwake_eintmask);
 }
+
+static inline void s3c_pm_arch_update_uart(void __iomem *regs,
+                                          struct pm_uart_save *save)
+{
+}
diff --git a/arch/arm/plat-s3c24xx/include/plat/regs-dma.h b/arch/arm/plat-s3c24xx/include/plat/regs-dma.h
new file mode 100644 (file)
index 0000000..3bc0a21
--- /dev/null
@@ -0,0 +1,145 @@
+/* arch/arm/mach-s3c2410/include/mach/dma.h
+ *
+ * Copyright (C) 2003,2004,2006 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Samsung S3C24XX DMA 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.
+*/
+
+/* DMA Register definitions */
+
+#define S3C2410_DMA_DISRC              (0x00)
+#define S3C2410_DMA_DISRCC             (0x04)
+#define S3C2410_DMA_DIDST              (0x08)
+#define S3C2410_DMA_DIDSTC             (0x0C)
+#define S3C2410_DMA_DCON               (0x10)
+#define S3C2410_DMA_DSTAT              (0x14)
+#define S3C2410_DMA_DCSRC              (0x18)
+#define S3C2410_DMA_DCDST              (0x1C)
+#define S3C2410_DMA_DMASKTRIG          (0x20)
+#define S3C2412_DMA_DMAREQSEL          (0x24)
+#define S3C2443_DMA_DMAREQSEL          (0x24)
+
+#define S3C2410_DISRCC_INC             (1<<0)
+#define S3C2410_DISRCC_APB             (1<<1)
+
+#define S3C2410_DMASKTRIG_STOP         (1<<2)
+#define S3C2410_DMASKTRIG_ON           (1<<1)
+#define S3C2410_DMASKTRIG_SWTRIG       (1<<0)
+
+#define S3C2410_DCON_DEMAND            (0<<31)
+#define S3C2410_DCON_HANDSHAKE         (1<<31)
+#define S3C2410_DCON_SYNC_PCLK         (0<<30)
+#define S3C2410_DCON_SYNC_HCLK         (1<<30)
+
+#define S3C2410_DCON_INTREQ            (1<<29)
+
+#define S3C2410_DCON_CH0_XDREQ0                (0<<24)
+#define S3C2410_DCON_CH0_UART0         (1<<24)
+#define S3C2410_DCON_CH0_SDI           (2<<24)
+#define S3C2410_DCON_CH0_TIMER         (3<<24)
+#define S3C2410_DCON_CH0_USBEP1                (4<<24)
+
+#define S3C2410_DCON_CH1_XDREQ1                (0<<24)
+#define S3C2410_DCON_CH1_UART1         (1<<24)
+#define S3C2410_DCON_CH1_I2SSDI                (2<<24)
+#define S3C2410_DCON_CH1_SPI           (3<<24)
+#define S3C2410_DCON_CH1_USBEP2                (4<<24)
+
+#define S3C2410_DCON_CH2_I2SSDO                (0<<24)
+#define S3C2410_DCON_CH2_I2SSDI                (1<<24)
+#define S3C2410_DCON_CH2_SDI           (2<<24)
+#define S3C2410_DCON_CH2_TIMER         (3<<24)
+#define S3C2410_DCON_CH2_USBEP3                (4<<24)
+
+#define S3C2410_DCON_CH3_UART2         (0<<24)
+#define S3C2410_DCON_CH3_SDI           (1<<24)
+#define S3C2410_DCON_CH3_SPI           (2<<24)
+#define S3C2410_DCON_CH3_TIMER         (3<<24)
+#define S3C2410_DCON_CH3_USBEP4                (4<<24)
+
+#define S3C2410_DCON_SRCSHIFT          (24)
+#define S3C2410_DCON_SRCMASK           (7<<24)
+
+#define S3C2410_DCON_BYTE              (0<<20)
+#define S3C2410_DCON_HALFWORD          (1<<20)
+#define S3C2410_DCON_WORD              (2<<20)
+
+#define S3C2410_DCON_AUTORELOAD                (0<<22)
+#define S3C2410_DCON_NORELOAD          (1<<22)
+#define S3C2410_DCON_HWTRIG            (1<<23)
+
+#ifdef CONFIG_CPU_S3C2440
+#define S3C2440_DIDSTC_CHKINT          (1<<2)
+
+#define S3C2440_DCON_CH0_I2SSDO                (5<<24)
+#define S3C2440_DCON_CH0_PCMIN         (6<<24)
+
+#define S3C2440_DCON_CH1_PCMOUT                (5<<24)
+#define S3C2440_DCON_CH1_SDI           (6<<24)
+
+#define S3C2440_DCON_CH2_PCMIN         (5<<24)
+#define S3C2440_DCON_CH2_MICIN         (6<<24)
+
+#define S3C2440_DCON_CH3_MICIN         (5<<24)
+#define S3C2440_DCON_CH3_PCMOUT                (6<<24)
+#endif
+
+#ifdef CONFIG_CPU_S3C2412
+
+#define S3C2412_DMAREQSEL_SRC(x)       ((x)<<1)
+
+#define S3C2412_DMAREQSEL_HW           (1)
+
+#define S3C2412_DMAREQSEL_SPI0TX       S3C2412_DMAREQSEL_SRC(0)
+#define S3C2412_DMAREQSEL_SPI0RX       S3C2412_DMAREQSEL_SRC(1)
+#define S3C2412_DMAREQSEL_SPI1TX       S3C2412_DMAREQSEL_SRC(2)
+#define S3C2412_DMAREQSEL_SPI1RX       S3C2412_DMAREQSEL_SRC(3)
+#define S3C2412_DMAREQSEL_I2STX                S3C2412_DMAREQSEL_SRC(4)
+#define S3C2412_DMAREQSEL_I2SRX                S3C2412_DMAREQSEL_SRC(5)
+#define S3C2412_DMAREQSEL_TIMER                S3C2412_DMAREQSEL_SRC(9)
+#define S3C2412_DMAREQSEL_SDI          S3C2412_DMAREQSEL_SRC(10)
+#define S3C2412_DMAREQSEL_USBEP1       S3C2412_DMAREQSEL_SRC(13)
+#define S3C2412_DMAREQSEL_USBEP2       S3C2412_DMAREQSEL_SRC(14)
+#define S3C2412_DMAREQSEL_USBEP3       S3C2412_DMAREQSEL_SRC(15)
+#define S3C2412_DMAREQSEL_USBEP4       S3C2412_DMAREQSEL_SRC(16)
+#define S3C2412_DMAREQSEL_XDREQ0       S3C2412_DMAREQSEL_SRC(17)
+#define S3C2412_DMAREQSEL_XDREQ1       S3C2412_DMAREQSEL_SRC(18)
+#define S3C2412_DMAREQSEL_UART0_0      S3C2412_DMAREQSEL_SRC(19)
+#define S3C2412_DMAREQSEL_UART0_1      S3C2412_DMAREQSEL_SRC(20)
+#define S3C2412_DMAREQSEL_UART1_0      S3C2412_DMAREQSEL_SRC(21)
+#define S3C2412_DMAREQSEL_UART1_1      S3C2412_DMAREQSEL_SRC(22)
+#define S3C2412_DMAREQSEL_UART2_0      S3C2412_DMAREQSEL_SRC(23)
+#define S3C2412_DMAREQSEL_UART2_1      S3C2412_DMAREQSEL_SRC(24)
+
+#endif
+
+#define S3C2443_DMAREQSEL_SRC(x)       ((x)<<1)
+
+#define S3C2443_DMAREQSEL_HW           (1)
+
+#define S3C2443_DMAREQSEL_SPI0TX       S3C2443_DMAREQSEL_SRC(0)
+#define S3C2443_DMAREQSEL_SPI0RX       S3C2443_DMAREQSEL_SRC(1)
+#define S3C2443_DMAREQSEL_SPI1TX       S3C2443_DMAREQSEL_SRC(2)
+#define S3C2443_DMAREQSEL_SPI1RX       S3C2443_DMAREQSEL_SRC(3)
+#define S3C2443_DMAREQSEL_I2STX                S3C2443_DMAREQSEL_SRC(4)
+#define S3C2443_DMAREQSEL_I2SRX                S3C2443_DMAREQSEL_SRC(5)
+#define S3C2443_DMAREQSEL_TIMER                S3C2443_DMAREQSEL_SRC(9)
+#define S3C2443_DMAREQSEL_SDI          S3C2443_DMAREQSEL_SRC(10)
+#define S3C2443_DMAREQSEL_XDREQ0       S3C2443_DMAREQSEL_SRC(17)
+#define S3C2443_DMAREQSEL_XDREQ1       S3C2443_DMAREQSEL_SRC(18)
+#define S3C2443_DMAREQSEL_UART0_0      S3C2443_DMAREQSEL_SRC(19)
+#define S3C2443_DMAREQSEL_UART0_1      S3C2443_DMAREQSEL_SRC(20)
+#define S3C2443_DMAREQSEL_UART1_0      S3C2443_DMAREQSEL_SRC(21)
+#define S3C2443_DMAREQSEL_UART1_1      S3C2443_DMAREQSEL_SRC(22)
+#define S3C2443_DMAREQSEL_UART2_0      S3C2443_DMAREQSEL_SRC(23)
+#define S3C2443_DMAREQSEL_UART2_1      S3C2443_DMAREQSEL_SRC(24)
+#define S3C2443_DMAREQSEL_UART3_0      S3C2443_DMAREQSEL_SRC(25)
+#define S3C2443_DMAREQSEL_UART3_1      S3C2443_DMAREQSEL_SRC(26)
+#define S3C2443_DMAREQSEL_PCMOUT       S3C2443_DMAREQSEL_SRC(27)
+#define S3C2443_DMAREQSEL_PCMIN        S3C2443_DMAREQSEL_SRC(28)
+#define S3C2443_DMAREQSEL_MICIN                S3C2443_DMAREQSEL_SRC(29)
index 062a29339a9189447795bf32e0385a6da881a170..56e5253ca02cc15f7523331984991b9198b81de4 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/suspend.h>
 #include <linux/errno.h>
 #include <linux/time.h>
+#include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/serial_core.h>
 #include <linux/io.h>
@@ -75,43 +76,10 @@ static struct sleep_save core_save[] = {
        SAVE_ITEM(S3C2410_CLKSLOW),
 };
 
-static struct gpio_sleep {
-       void __iomem    *base;
-       unsigned int     gpcon;
-       unsigned int     gpdat;
-       unsigned int     gpup;
-} gpio_save[] = {
-       [0] = {
-               .base   = S3C2410_GPACON,
-       },
-       [1] = {
-               .base   = S3C2410_GPBCON,
-       },
-       [2] = {
-               .base   = S3C2410_GPCCON,
-       },
-       [3] = {
-               .base   = S3C2410_GPDCON,
-       },
-       [4] = {
-               .base   = S3C2410_GPECON,
-       },
-       [5] = {
-               .base   = S3C2410_GPFCON,
-       },
-       [6] = {
-               .base   = S3C2410_GPGCON,
-       },
-       [7] = {
-               .base   = S3C2410_GPHCON,
-       },
-};
-
 static struct sleep_save misc_save[] = {
        SAVE_ITEM(S3C2410_DCLKCON),
 };
 
-
 /* s3c_pm_check_resume_pin
  *
  * check to see if the pin is configured correctly for sleep mode, and
@@ -156,195 +124,15 @@ void s3c_pm_configure_extint(void)
         * and then configure it as an input if it is not
        */
 
-       for (pin = S3C2410_GPF0; pin <= S3C2410_GPF7; pin++) {
-               s3c_pm_check_resume_pin(pin, pin - S3C2410_GPF0);
-       }
-
-       for (pin = S3C2410_GPG0; pin <= S3C2410_GPG7; pin++) {
-               s3c_pm_check_resume_pin(pin, (pin - S3C2410_GPG0)+8);
+       for (pin = S3C2410_GPF(0); pin <= S3C2410_GPF(7); pin++) {
+               s3c_pm_check_resume_pin(pin, pin - S3C2410_GPF(0));
        }
-}
-
-/* offsets for CON/DAT/UP registers */
-
-#define OFFS_CON       (S3C2410_GPACON - S3C2410_GPACON)
-#define OFFS_DAT       (S3C2410_GPADAT - S3C2410_GPACON)
-#define OFFS_UP                (S3C2410_GPBUP  - S3C2410_GPBCON)
-
-/* s3c_pm_save_gpios()
- *
- * Save the state of the GPIOs
- */
-
-void s3c_pm_save_gpios(void)
-{
-       struct gpio_sleep *gps = gpio_save;
-       unsigned int gpio;
-
-       for (gpio = 0; gpio < ARRAY_SIZE(gpio_save); gpio++, gps++) {
-               void __iomem *base = gps->base;
-
-               gps->gpcon = __raw_readl(base + OFFS_CON);
-               gps->gpdat = __raw_readl(base + OFFS_DAT);
-
-               if (gpio > 0)
-                       gps->gpup = __raw_readl(base + OFFS_UP);
 
+       for (pin = S3C2410_GPG(0); pin <= S3C2410_GPG(7); pin++) {
+               s3c_pm_check_resume_pin(pin, (pin - S3C2410_GPG(0))+8);
        }
 }
 
-/* Test whether the given masked+shifted bits of an GPIO configuration
- * are one of the SFN (special function) modes. */
-
-static inline int is_sfn(unsigned long con)
-{
-       return (con == 2 || con == 3);
-}
-
-/* Test if the given masked+shifted GPIO configuration is an input */
-
-static inline int is_in(unsigned long con)
-{
-       return con == 0;
-}
-
-/* Test if the given masked+shifted GPIO configuration is an output */
-
-static inline int is_out(unsigned long con)
-{
-       return con == 1;
-}
-
-/**
- * s3c2410_pm_restore_gpio() - restore the given GPIO bank
- * @index: The number of the GPIO bank being resumed.
- * @gps: The sleep confgiuration for the bank.
- *
- * Restore one of the GPIO banks that was saved during suspend. This is
- * not as simple as once thought, due to the possibility of glitches
- * from the order that the CON and DAT registers are set in.
- *
- * The three states the pin can be are {IN,OUT,SFN} which gives us 9
- * combinations of changes to check. Three of these, if the pin stays
- * in the same configuration can be discounted. This leaves us with
- * the following:
- *
- * { IN => OUT }  Change DAT first
- * { IN => SFN }  Change CON first
- * { OUT => SFN } Change CON first, so new data will not glitch
- * { OUT => IN }  Change CON first, so new data will not glitch
- * { SFN => IN }  Change CON first
- * { SFN => OUT } Change DAT first, so new data will not glitch [1]
- *
- * We do not currently deal with the UP registers as these control
- * weak resistors, so a small delay in change should not need to bring
- * these into the calculations.
- *
- * [1] this assumes that writing to a pin DAT whilst in SFN will set the
- *     state for when it is next output.
- */
-
-static void s3c2410_pm_restore_gpio(int index, struct gpio_sleep *gps)
-{
-       void __iomem *base = gps->base;
-       unsigned long gps_gpcon = gps->gpcon;
-       unsigned long gps_gpdat = gps->gpdat;
-       unsigned long old_gpcon;
-       unsigned long old_gpdat;
-       unsigned long old_gpup = 0x0;
-       unsigned long gpcon;
-       int nr;
-
-       old_gpcon = __raw_readl(base + OFFS_CON);
-       old_gpdat = __raw_readl(base + OFFS_DAT);
-
-       if (base == S3C2410_GPACON) {
-               /* GPACON only has one bit per control / data and no PULLUPs.
-                * GPACON[x] = 0 => Output, 1 => SFN */
-
-               /* first set all SFN bits to SFN */
-
-               gpcon = old_gpcon | gps->gpcon;
-               __raw_writel(gpcon, base + OFFS_CON);
-
-               /* now set all the other bits */
-
-               __raw_writel(gps_gpdat, base + OFFS_DAT);
-               __raw_writel(gps_gpcon, base + OFFS_CON);
-       } else {
-               unsigned long old, new, mask;
-               unsigned long change_mask = 0x0;
-
-               old_gpup = __raw_readl(base + OFFS_UP);
-
-               /* Create a change_mask of all the items that need to have
-                * their CON value changed before their DAT value, so that
-                * we minimise the work between the two settings.
-                */
-
-               for (nr = 0, mask = 0x03; nr < 32; nr += 2, mask <<= 2) {
-                       old = (old_gpcon & mask) >> nr;
-                       new = (gps_gpcon & mask) >> nr;
-
-                       /* If there is no change, then skip */
-
-                       if (old == new)
-                               continue;
-
-                       /* If both are special function, then skip */
-
-                       if (is_sfn(old) && is_sfn(new))
-                               continue;
-
-                       /* Change is IN => OUT, do not change now */
-
-                       if (is_in(old) && is_out(new))
-                               continue;
-
-                       /* Change is SFN => OUT, do not change now */
-
-                       if (is_sfn(old) && is_out(new))
-                               continue;
-
-                       /* We should now be at the case of IN=>SFN,
-                        * OUT=>SFN, OUT=>IN, SFN=>IN. */
-
-                       change_mask |= mask;
-               }
-
-               /* Write the new CON settings */
-
-               gpcon = old_gpcon & ~change_mask;
-               gpcon |= gps_gpcon & change_mask;
-
-               __raw_writel(gpcon, base + OFFS_CON);
-
-               /* Now change any items that require DAT,CON */
-
-               __raw_writel(gps_gpdat, base + OFFS_DAT);
-               __raw_writel(gps_gpcon, base + OFFS_CON);
-               __raw_writel(gps->gpup, base + OFFS_UP);
-       }
-
-       S3C_PMDBG("GPIO[%d] CON %08lx => %08lx, DAT %08lx => %08lx\n",
-                 index, old_gpcon, gps_gpcon, old_gpdat, gps_gpdat);
-}
-
-
-/** s3c2410_pm_restore_gpios()
- *
- * Restore the state of the GPIOs
- */
-
-void s3c_pm_restore_gpios(void)
-{
-       struct gpio_sleep *gps = gpio_save;
-       int gpio;
-
-       for (gpio = 0; gpio < ARRAY_SIZE(gpio_save); gpio++, gps++) {
-               s3c2410_pm_restore_gpio(gpio, gps);
-       }
-}
 
 void s3c_pm_restore_core(void)
 {
index d62b7e7fb3556c72bb32731d7588b2be31fccda0..71a6accf114eaf47d49a5cb03b28bfe40299a67d 100644 (file)
@@ -11,6 +11,7 @@
 */
 
 #include <linux/kernel.h>
+#include <linux/gpio.h>
 
 struct platform_device;
 
@@ -20,6 +21,6 @@ struct platform_device;
 
 void s3c_i2c0_cfg_gpio(struct platform_device *dev)
 {
-       s3c2410_gpio_cfgpin(S3C2410_GPE15, S3C2410_GPE15_IICSDA);
-       s3c2410_gpio_cfgpin(S3C2410_GPE14, S3C2410_GPE14_IICSCL);
+       s3c2410_gpio_cfgpin(S3C2410_GPE(15), S3C2410_GPE15_IICSDA);
+       s3c2410_gpio_cfgpin(S3C2410_GPE(14), S3C2410_GPE14_IICSCL);
 }
index 8b403cbb53d2323f7504484015af160881c6895e..9edf7894eedd663fd5a2ad652515ce08c437f09d 100644 (file)
@@ -22,16 +22,16 @@ void s3c24xx_spi_gpiocfg_bus0_gpe11_12_13(struct s3c2410_spi_info *spi,
                                          int enable)
 {
        if (enable) {
-               s3c2410_gpio_cfgpin(S3C2410_GPE13, S3C2410_GPE13_SPICLK0);
-               s3c2410_gpio_cfgpin(S3C2410_GPE12, S3C2410_GPE12_SPIMOSI0);
-               s3c2410_gpio_cfgpin(S3C2410_GPE11, S3C2410_GPE11_SPIMISO0);
-               s3c2410_gpio_pullup(S3C2410_GPE11, 0);
-               s3c2410_gpio_pullup(S3C2410_GPE13, 0);
+               s3c2410_gpio_cfgpin(S3C2410_GPE(13), S3C2410_GPE13_SPICLK0);
+               s3c2410_gpio_cfgpin(S3C2410_GPE(12), S3C2410_GPE12_SPIMOSI0);
+               s3c2410_gpio_cfgpin(S3C2410_GPE(11), S3C2410_GPE11_SPIMISO0);
+               s3c2410_gpio_pullup(S3C2410_GPE(11), 0);
+               s3c2410_gpio_pullup(S3C2410_GPE(13), 0);
        } else {
-               s3c2410_gpio_cfgpin(S3C2410_GPE13, S3C2410_GPIO_INPUT);
-               s3c2410_gpio_cfgpin(S3C2410_GPE11, S3C2410_GPIO_INPUT);
-               s3c2410_gpio_pullup(S3C2410_GPE11, 1);
-               s3c2410_gpio_pullup(S3C2410_GPE12, 1);
-               s3c2410_gpio_pullup(S3C2410_GPE13, 1);
+               s3c2410_gpio_cfgpin(S3C2410_GPE(13), S3C2410_GPIO_INPUT);
+               s3c2410_gpio_cfgpin(S3C2410_GPE(11), S3C2410_GPIO_INPUT);
+               s3c2410_gpio_pullup(S3C2410_GPE(11), 1);
+               s3c2410_gpio_pullup(S3C2410_GPE(12), 1);
+               s3c2410_gpio_pullup(S3C2410_GPE(13), 1);
        }
 }
index 8fccd4e549f056f1bef0269a3bf7c20388c6546c..f34d0fc69ad81228add93dcd4db889aa4c44230c 100644 (file)
@@ -22,16 +22,16 @@ void s3c24xx_spi_gpiocfg_bus1_gpg5_6_7(struct s3c2410_spi_info *spi,
                                       int enable)
 {
        if (enable) {
-               s3c2410_gpio_cfgpin(S3C2410_GPG7, S3C2410_GPG7_SPICLK1);
-               s3c2410_gpio_cfgpin(S3C2410_GPG6, S3C2410_GPG6_SPIMOSI1);
-               s3c2410_gpio_cfgpin(S3C2410_GPG5, S3C2410_GPG5_SPIMISO1);
-               s3c2410_gpio_pullup(S3C2410_GPG5, 0);
-               s3c2410_gpio_pullup(S3C2410_GPG6, 0);
+               s3c2410_gpio_cfgpin(S3C2410_GPG(7), S3C2410_GPG7_SPICLK1);
+               s3c2410_gpio_cfgpin(S3C2410_GPG(6), S3C2410_GPG6_SPIMOSI1);
+               s3c2410_gpio_cfgpin(S3C2410_GPG(5), S3C2410_GPG5_SPIMISO1);
+               s3c2410_gpio_pullup(S3C2410_GPG(5), 0);
+               s3c2410_gpio_pullup(S3C2410_GPG(6), 0);
        } else {
-               s3c2410_gpio_cfgpin(S3C2410_GPG7, S3C2410_GPIO_INPUT);
-               s3c2410_gpio_cfgpin(S3C2410_GPG5, S3C2410_GPIO_INPUT);
-               s3c2410_gpio_pullup(S3C2410_GPG5, 1);
-               s3c2410_gpio_pullup(S3C2410_GPG6, 1);
-               s3c2410_gpio_pullup(S3C2410_GPG7, 1);
+               s3c2410_gpio_cfgpin(S3C2410_GPG(7), S3C2410_GPIO_INPUT);
+               s3c2410_gpio_cfgpin(S3C2410_GPG(5), S3C2410_GPIO_INPUT);
+               s3c2410_gpio_pullup(S3C2410_GPG(5), 1);
+               s3c2410_gpio_pullup(S3C2410_GPG(6), 1);
+               s3c2410_gpio_pullup(S3C2410_GPG(7), 1);
        }
 }
index 54375a00a7d25d685216c47fa423a52a59141dc7..5ebd8b425a54c329df34e09ab2a8a32a637df3e7 100644 (file)
@@ -19,6 +19,7 @@ config PLAT_S3C64XX
        select S3C_GPIO_PULL_UPDOWN
        select S3C_GPIO_CFG_S3C24XX
        select S3C_GPIO_CFG_S3C64XX
+       select USB_ARCH_HAS_OHCI
        help
          Base platform code for any Samsung S3C64XX device
 
@@ -38,6 +39,10 @@ config CPU_S3C6400_CLOCK
          Common clock support code for the S3C6400 that is shared
          by other CPUs in the series, such as the S3C6410.
 
+config S3C64XX_DMA
+       bool "S3C64XX DMA"
+       select S3C_DMA
+
 # platform specific device setup
 
 config S3C64XX_SETUP_I2C0
@@ -59,4 +64,9 @@ config S3C64XX_SETUP_FB_24BPP
        help
          Common setup code for S3C64XX with an 24bpp RGB display helper.
 
+config S3C64XX_SETUP_SDHCI_GPIO
+       bool
+       help
+         Common setup code for S3C64XX SDHCI GPIO configurations
+
 endif
index 2e6d79bf8f33537061a9751eea9f482745958309..2ed5df34f9ea9abafc63afa3a709c16b21ca424b 100644 (file)
@@ -24,8 +24,19 @@ obj-y                                += gpiolib.o
 obj-$(CONFIG_CPU_S3C6400_INIT) += s3c6400-init.o
 obj-$(CONFIG_CPU_S3C6400_CLOCK)        += s3c6400-clock.o
 
+# PM support
+
+obj-$(CONFIG_PM)               += pm.o
+obj-$(CONFIG_PM)               += sleep.o
+obj-$(CONFIG_PM)               += irq-pm.o
+
+# DMA support
+
+obj-$(CONFIG_S3C64XX_DMA)      += dma.o
+
 # Device setup
 
 obj-$(CONFIG_S3C64XX_SETUP_I2C0) += setup-i2c0.o
 obj-$(CONFIG_S3C64XX_SETUP_I2C1) += setup-i2c1.o
 obj-$(CONFIG_S3C64XX_SETUP_FB_24BPP) += setup-fb-24bpp.o
+obj-$(CONFIG_S3C64XX_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
\ No newline at end of file
index ad1b9682c9c3457b32470f3f1bcfd23da1de0811..0bc2fa1dfc40e0f334508a0ce2896271dd6f06a5 100644 (file)
 #include <plat/devs.h>
 #include <plat/clock.h>
 
+struct clk clk_h2 = {
+       .name           = "hclk2",
+       .id             = -1,
+       .rate           = 0,
+};
+
 struct clk clk_27m = {
        .name           = "clk_27m",
        .id             = -1,
@@ -152,6 +158,18 @@ static struct clk init_clocks_disable[] = {
                .parent         = &clk_48m,
                .enable         = s3c64xx_sclk_ctrl,
                .ctrlbit        = S3C_CLKCON_SCLK_MMC2_48,
+       }, {
+               .name           = "dma0",
+               .id             = -1,
+               .parent         = &clk_h,
+               .enable         = s3c64xx_hclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_HCLK_DMA0,
+       }, {
+               .name           = "dma1",
+               .id             = -1,
+               .parent         = &clk_h,
+               .enable         = s3c64xx_hclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_HCLK_DMA1,
        },
 };
 
@@ -246,6 +264,7 @@ static struct clk *clks[] __initdata = {
        &clk_epll,
        &clk_27m,
        &clk_48m,
+       &clk_h2,
 };
 
 void __init s3c64xx_register_clocks(void)
index 91f49a3a665d094f6ed77e2257e8964d58c865f3..b1fdd83940a623558c6e46bc407f882d073f70c4 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
+#include <linux/sysdev.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
@@ -101,9 +102,24 @@ static struct map_desc s3c_iodesc[] __initdata = {
                .pfn            = __phys_to_pfn(S3C64XX_PA_MODEM),
                .length         = SZ_4K,
                .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S3C_VA_WATCHDOG,
+               .pfn            = __phys_to_pfn(S3C64XX_PA_WATCHDOG),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
        },
 };
 
+
+struct sysdev_class s3c64xx_sysclass = {
+       .name   = "s3c64xx-core",
+};
+
+static struct sys_device s3c64xx_sysdev = {
+       .cls    = &s3c64xx_sysclass,
+};
+
+
 /* read cpu identification code */
 
 void __init s3c64xx_init_io(struct map_desc *mach_desc, int size)
@@ -115,5 +131,21 @@ void __init s3c64xx_init_io(struct map_desc *mach_desc, int size)
        iotable_init(mach_desc, size);
 
        idcode = __raw_readl(S3C_VA_SYS + 0x118);
+       if (!idcode) {
+               /* S3C6400 has the ID register in a different place,
+                * and needs a write before it can be read. */
+
+               __raw_writel(0x0, S3C_VA_SYS + 0xA1C);
+               idcode = __raw_readl(S3C_VA_SYS + 0xA1C);
+       }
+
        s3c_init_cpu(idcode, cpu_ids, ARRAY_SIZE(cpu_ids));
 }
+
+static __init int s3c64xx_sysdev_init(void)
+{
+       sysdev_class_register(&s3c64xx_sysclass);
+       return sysdev_register(&s3c64xx_sysdev);
+}
+
+core_initcall(s3c64xx_sysdev_init);
diff --git a/arch/arm/plat-s3c64xx/dma.c b/arch/arm/plat-s3c64xx/dma.c
new file mode 100644 (file)
index 0000000..67aa93d
--- /dev/null
@@ -0,0 +1,722 @@
+/* linux/arch/arm/plat-s3c64xx/dma.c
+ *
+ * Copyright 2009 Openmoko, Inc.
+ * Copyright 2009 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX DMA core
+ *
+ * This 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/interrupt.h>
+#include <linux/dmapool.h>
+#include <linux/sysdev.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <mach/dma.h>
+#include <mach/map.h>
+#include <mach/irqs.h>
+
+#include <plat/dma-plat.h>
+#include <plat/regs-sys.h>
+
+#include <asm/hardware/pl080.h>
+
+/* dma channel state information */
+
+struct s3c64xx_dmac {
+       struct sys_device        sysdev;
+       struct clk              *clk;
+       void __iomem            *regs;
+       struct s3c2410_dma_chan *channels;
+       enum dma_ch              chanbase;
+};
+
+/* pool to provide LLI buffers */
+static struct dma_pool *dma_pool;
+
+/* Debug configuration and code */
+
+static unsigned char debug_show_buffs = 0;
+
+static void dbg_showchan(struct s3c2410_dma_chan *chan)
+{
+       pr_debug("DMA%d: %08x->%08x L %08x C %08x,%08x S %08x\n",
+                chan->number,
+                readl(chan->regs + PL080_CH_SRC_ADDR),
+                readl(chan->regs + PL080_CH_DST_ADDR),
+                readl(chan->regs + PL080_CH_LLI),
+                readl(chan->regs + PL080_CH_CONTROL),
+                readl(chan->regs + PL080S_CH_CONTROL2),
+                readl(chan->regs + PL080S_CH_CONFIG));
+}
+
+static void show_lli(struct pl080s_lli *lli)
+{
+       pr_debug("LLI[%p] %08x->%08x, NL %08x C %08x,%08x\n",
+                lli, lli->src_addr, lli->dst_addr, lli->next_lli,
+                lli->control0, lli->control1);
+}
+
+static void dbg_showbuffs(struct s3c2410_dma_chan *chan)
+{
+       struct s3c64xx_dma_buff *ptr;
+       struct s3c64xx_dma_buff *end;
+
+       pr_debug("DMA%d: buffs next %p, curr %p, end %p\n",
+                chan->number, chan->next, chan->curr, chan->end);
+
+       ptr = chan->next;
+       end = chan->end;
+
+       if (debug_show_buffs) {
+               for (; ptr != NULL; ptr = ptr->next) {
+                       pr_debug("DMA%d: %08x ",
+                                chan->number, ptr->lli_dma);
+                       show_lli(ptr->lli);
+               }
+       }
+}
+
+/* End of Debug */
+
+static struct s3c2410_dma_chan *s3c64xx_dma_map_channel(unsigned int channel)
+{
+       struct s3c2410_dma_chan *chan;
+       unsigned int start, offs;
+
+       start = 0;
+
+       if (channel >= DMACH_PCM1_TX)
+               start = 8;
+
+       for (offs = 0; offs < 8; offs++) {
+               chan = &s3c2410_chans[start + offs];
+               if (!chan->in_use)
+                       goto found;
+       }
+
+       return NULL;
+
+found:
+       s3c_dma_chan_map[channel] = chan;
+       return chan;
+}
+
+int s3c2410_dma_config(unsigned int channel, int xferunit)
+{
+       struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+
+       if (chan == NULL)
+               return -EINVAL;
+
+       switch (xferunit) {
+       case 1:
+               chan->hw_width = 0;
+               break;
+       case 2:
+               chan->hw_width = 1;
+               break;
+       case 4:
+               chan->hw_width = 2;
+               break;
+       default:
+               printk(KERN_ERR "%s: illegal width %d\n", __func__, xferunit);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(s3c2410_dma_config);
+
+static void s3c64xx_dma_fill_lli(struct s3c2410_dma_chan *chan,
+                                struct pl080s_lli *lli,
+                                dma_addr_t data, int size)
+{
+       dma_addr_t src, dst;
+       u32 control0, control1;
+
+       switch (chan->source) {
+       case S3C2410_DMASRC_HW:
+               src = chan->dev_addr;
+               dst = data;
+               control0 = PL080_CONTROL_SRC_AHB2;
+               control0 |= (u32)chan->hw_width << PL080_CONTROL_SWIDTH_SHIFT;
+               control0 |= 2 << PL080_CONTROL_DWIDTH_SHIFT;
+               control0 |= PL080_CONTROL_DST_INCR;
+               break;
+
+       case S3C2410_DMASRC_MEM:
+               src = data;
+               dst = chan->dev_addr;
+               control0 = PL080_CONTROL_DST_AHB2;
+               control0 |= (u32)chan->hw_width << PL080_CONTROL_DWIDTH_SHIFT;
+               control0 |= 2 << PL080_CONTROL_SWIDTH_SHIFT;
+               control0 |= PL080_CONTROL_SRC_INCR;
+               break;
+       default:
+               BUG();
+       }
+
+       /* note, we do not currently setup any of the burst controls */
+
+       control1 = size >> chan->hw_width;      /* size in no of xfers */
+       control0 |= PL080_CONTROL_PROT_SYS;     /* always in priv. mode */
+       control0 |= PL080_CONTROL_TC_IRQ_EN;    /* always fire IRQ */
+
+       lli->src_addr = src;
+       lli->dst_addr = dst;
+       lli->next_lli = 0;
+       lli->control0 = control0;
+       lli->control1 = control1;
+}
+
+static void s3c64xx_lli_to_regs(struct s3c2410_dma_chan *chan,
+                               struct pl080s_lli *lli)
+{
+       void __iomem *regs = chan->regs;
+
+       pr_debug("%s: LLI %p => regs\n", __func__, lli);
+       show_lli(lli);
+
+       writel(lli->src_addr, regs + PL080_CH_SRC_ADDR);
+       writel(lli->dst_addr, regs + PL080_CH_DST_ADDR);
+       writel(lli->next_lli, regs + PL080_CH_LLI);
+       writel(lli->control0, regs + PL080_CH_CONTROL);
+       writel(lli->control1, regs + PL080S_CH_CONTROL2);
+}
+
+static int s3c64xx_dma_start(struct s3c2410_dma_chan *chan)
+{
+       struct s3c64xx_dmac *dmac = chan->dmac;
+       u32 config;
+       u32 bit = chan->bit;
+
+       dbg_showchan(chan);
+
+       pr_debug("%s: clearing interrupts\n", __func__);
+
+       /* clear interrupts */
+       writel(bit, dmac->regs + PL080_TC_CLEAR);
+       writel(bit, dmac->regs + PL080_ERR_CLEAR);
+
+       pr_debug("%s: starting channel\n", __func__);
+
+       config = readl(chan->regs + PL080S_CH_CONFIG);
+       config |= PL080_CONFIG_ENABLE;
+
+       pr_debug("%s: writing config %08x\n", __func__, config);
+       writel(config, chan->regs + PL080S_CH_CONFIG);
+
+       return 0;
+}
+
+static int s3c64xx_dma_stop(struct s3c2410_dma_chan *chan)
+{
+       u32 config;
+       int timeout;
+
+       pr_debug("%s: stopping channel\n", __func__);
+
+       dbg_showchan(chan);
+
+       config = readl(chan->regs + PL080S_CH_CONFIG);
+       config |= PL080_CONFIG_HALT;
+       writel(config, chan->regs + PL080S_CH_CONFIG);
+
+       timeout = 1000;
+       do {
+               config = readl(chan->regs + PL080S_CH_CONFIG);
+               pr_debug("%s: %d - config %08x\n", __func__, timeout, config);
+               if (config & PL080_CONFIG_ACTIVE)
+                       udelay(10);
+               else
+                       break;
+               } while (--timeout > 0);
+
+       if (config & PL080_CONFIG_ACTIVE) {
+               printk(KERN_ERR "%s: channel still active\n", __func__);
+               return -EFAULT;
+       }
+
+       config = readl(chan->regs + PL080S_CH_CONFIG);
+       config &= ~PL080_CONFIG_ENABLE;
+       writel(config, chan->regs + PL080S_CH_CONFIG);
+
+       return 0;
+}
+
+static inline void s3c64xx_dma_bufffdone(struct s3c2410_dma_chan *chan,
+                                        struct s3c64xx_dma_buff *buf,
+                                        enum s3c2410_dma_buffresult result)
+{
+       if (chan->callback_fn != NULL)
+               (chan->callback_fn)(chan, buf->pw, 0, result);
+}
+
+static void s3c64xx_dma_freebuff(struct s3c64xx_dma_buff *buff)
+{
+       dma_pool_free(dma_pool, buff->lli, buff->lli_dma);
+       kfree(buff);
+}
+
+static int s3c64xx_dma_flush(struct s3c2410_dma_chan *chan)
+{
+       struct s3c64xx_dma_buff *buff, *next;
+       u32 config;
+
+       dbg_showchan(chan);
+
+       pr_debug("%s: flushing channel\n", __func__);
+
+       config = readl(chan->regs + PL080S_CH_CONFIG);
+       config &= ~PL080_CONFIG_ENABLE;
+       writel(config, chan->regs + PL080S_CH_CONFIG);
+
+       /* dump all the buffers associated with this channel */
+
+       for (buff = chan->curr; buff != NULL; buff = next) {
+               next = buff->next;
+               pr_debug("%s: buff %p (next %p)\n", __func__, buff, buff->next);
+
+               s3c64xx_dma_bufffdone(chan, buff, S3C2410_RES_ABORT);
+               s3c64xx_dma_freebuff(buff);
+       }
+
+       chan->curr = chan->next = chan->end = NULL;
+
+       return 0;
+}
+
+int s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op)
+{
+       struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+
+       WARN_ON(!chan);
+       if (!chan)
+               return -EINVAL;
+
+       switch (op) {
+       case S3C2410_DMAOP_START:
+               return s3c64xx_dma_start(chan);
+
+       case S3C2410_DMAOP_STOP:
+               return s3c64xx_dma_stop(chan);
+
+       case S3C2410_DMAOP_FLUSH:
+               return s3c64xx_dma_flush(chan);
+
+       /* belive PAUSE/RESUME are no-ops */
+       case S3C2410_DMAOP_PAUSE:
+       case S3C2410_DMAOP_RESUME:
+       case S3C2410_DMAOP_STARTED:
+       case S3C2410_DMAOP_TIMEOUT:
+               return 0;
+       }
+
+       return -ENOENT;
+}
+EXPORT_SYMBOL(s3c2410_dma_ctrl);
+
+/* s3c2410_dma_enque
+ *
+ */
+
+int s3c2410_dma_enqueue(unsigned int channel, void *id,
+                       dma_addr_t data, int size)
+{
+       struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+       struct s3c64xx_dma_buff *next;
+       struct s3c64xx_dma_buff *buff;
+       struct pl080s_lli *lli;
+       int ret;
+
+       WARN_ON(!chan);
+       if (!chan)
+               return -EINVAL;
+
+       buff = kzalloc(sizeof(struct s3c64xx_dma_buff), GFP_KERNEL);
+       if (!buff) {
+               printk(KERN_ERR "%s: no memory for buffer\n", __func__);
+               return -ENOMEM;
+       }
+
+       lli = dma_pool_alloc(dma_pool, GFP_KERNEL, &buff->lli_dma);
+       if (!lli) {
+               printk(KERN_ERR "%s: no memory for lli\n", __func__);
+               ret = -ENOMEM;
+               goto err_buff;
+       }
+
+       pr_debug("%s: buff %p, dp %08x lli (%p, %08x) %d\n",
+                __func__, buff, data, lli, (u32)buff->lli_dma, size);
+
+       buff->lli = lli;
+       buff->pw = id;
+
+       s3c64xx_dma_fill_lli(chan, lli, data, size);
+
+       if ((next = chan->next) != NULL) {
+               struct s3c64xx_dma_buff *end = chan->end;
+               struct pl080s_lli *endlli = end->lli;
+
+               pr_debug("enquing onto channel\n");
+
+               end->next = buff;
+               endlli->next_lli = buff->lli_dma;
+
+               if (chan->flags & S3C2410_DMAF_CIRCULAR) {
+                       struct s3c64xx_dma_buff *curr = chan->curr;
+                       lli->next_lli = curr->lli_dma;
+               }
+
+               if (next == chan->curr) {
+                       writel(buff->lli_dma, chan->regs + PL080_CH_LLI);
+                       chan->next = buff;
+               }
+
+               show_lli(endlli);
+               chan->end = buff;
+       } else {
+               pr_debug("enquing onto empty channel\n");
+
+               chan->curr = buff;
+               chan->next = buff;
+               chan->end = buff;
+
+               s3c64xx_lli_to_regs(chan, lli);
+       }
+
+       show_lli(lli);
+
+       dbg_showchan(chan);
+       dbg_showbuffs(chan);
+       return 0;
+
+err_buff:
+       kfree(buff);
+       return ret;
+}
+
+EXPORT_SYMBOL(s3c2410_dma_enqueue);
+
+
+int s3c2410_dma_devconfig(int channel,
+                         enum s3c2410_dmasrc source,
+                         unsigned long devaddr)
+{
+       struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+       u32 peripheral;
+       u32 config = 0;
+
+       pr_debug("%s: channel %d, source %d, dev %08lx, chan %p\n",
+                __func__, channel, source, devaddr, chan);
+
+       WARN_ON(!chan);
+       if (!chan)
+               return -EINVAL;
+
+       peripheral = (chan->peripheral & 0xf);
+       chan->source = source;
+       chan->dev_addr = devaddr;
+
+       pr_debug("%s: peripheral %d\n", __func__, peripheral);
+
+       switch (source) {
+       case S3C2410_DMASRC_HW:
+               config = 2 << PL080_CONFIG_FLOW_CONTROL_SHIFT;
+               config |= peripheral << PL080_CONFIG_SRC_SEL_SHIFT;
+               break;
+       case S3C2410_DMASRC_MEM:
+               config = 1 << PL080_CONFIG_FLOW_CONTROL_SHIFT;
+               config |= peripheral << PL080_CONFIG_DST_SEL_SHIFT;
+               break;
+       default:
+               printk(KERN_ERR "%s: bad source\n", __func__);
+               return -EINVAL;
+       }
+
+       /* allow TC and ERR interrupts */
+       config |= PL080_CONFIG_TC_IRQ_MASK;
+       config |= PL080_CONFIG_ERR_IRQ_MASK;
+
+       pr_debug("%s: config %08x\n", __func__, config);
+
+       writel(config, chan->regs + PL080S_CH_CONFIG);
+
+       return 0;
+}
+EXPORT_SYMBOL(s3c2410_dma_devconfig);
+
+
+int s3c2410_dma_getposition(unsigned int channel,
+                           dma_addr_t *src, dma_addr_t *dst)
+{
+       struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+
+       WARN_ON(!chan);
+       if (!chan)
+               return -EINVAL;
+
+       if (src != NULL)
+               *src = readl(chan->regs + PL080_CH_SRC_ADDR);
+
+       if (dst != NULL)
+               *dst = readl(chan->regs + PL080_CH_DST_ADDR);
+
+       return 0;
+}
+EXPORT_SYMBOL(s3c2410_dma_getposition);
+
+/* s3c2410_request_dma
+ *
+ * get control of an dma channel
+*/
+
+int s3c2410_dma_request(unsigned int channel,
+                       struct s3c2410_dma_client *client,
+                       void *dev)
+{
+       struct s3c2410_dma_chan *chan;
+       unsigned long flags;
+
+       pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n",
+                channel, client->name, dev);
+
+       local_irq_save(flags);
+
+       chan = s3c64xx_dma_map_channel(channel);
+       if (chan == NULL) {
+               local_irq_restore(flags);
+               return -EBUSY;
+       }
+
+       dbg_showchan(chan);
+
+       chan->client = client;
+       chan->in_use = 1;
+       chan->peripheral = channel;
+
+       local_irq_restore(flags);
+
+       /* need to setup */
+
+       pr_debug("%s: channel initialised, %p\n", __func__, chan);
+
+       return chan->number | DMACH_LOW_LEVEL;
+}
+
+EXPORT_SYMBOL(s3c2410_dma_request);
+
+/* s3c2410_dma_free
+ *
+ * release the given channel back to the system, will stop and flush
+ * any outstanding transfers, and ensure the channel is ready for the
+ * next claimant.
+ *
+ * Note, although a warning is currently printed if the freeing client
+ * info is not the same as the registrant's client info, the free is still
+ * allowed to go through.
+*/
+
+int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *client)
+{
+       struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+       unsigned long flags;
+
+       if (chan == NULL)
+               return -EINVAL;
+
+       local_irq_save(flags);
+
+       if (chan->client != client) {
+               printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n",
+                      channel, chan->client, client);
+       }
+
+       /* sort out stopping and freeing the channel */
+
+
+       chan->client = NULL;
+       chan->in_use = 0;
+
+       if (!(channel & DMACH_LOW_LEVEL))
+               s3c_dma_chan_map[channel] = NULL;
+
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+EXPORT_SYMBOL(s3c2410_dma_free);
+
+
+static void s3c64xx_dma_tcirq(struct s3c64xx_dmac *dmac, int offs)
+{
+       struct s3c2410_dma_chan *chan = dmac->channels + offs;
+
+       /* note, we currently do not bother to work out which buffer
+        * or buffers have been completed since the last tc-irq. */
+
+       if (chan->callback_fn)
+               (chan->callback_fn)(chan, chan->curr->pw, 0, S3C2410_RES_OK);
+}
+
+static void s3c64xx_dma_errirq(struct s3c64xx_dmac *dmac, int offs)
+{
+       printk(KERN_DEBUG "%s: offs %d\n", __func__, offs);
+}
+
+static irqreturn_t s3c64xx_dma_irq(int irq, void *pw)
+{
+       struct s3c64xx_dmac *dmac = pw;
+       u32 tcstat, errstat;
+       u32 bit;
+       int offs;
+
+       tcstat = readl(dmac->regs + PL080_TC_STATUS);
+       errstat = readl(dmac->regs + PL080_ERR_STATUS);
+
+       for (offs = 0, bit = 1; offs < 8; offs++, bit <<= 1) {
+               if (tcstat & bit) {
+                       writel(bit, dmac->regs + PL080_TC_CLEAR);
+                       s3c64xx_dma_tcirq(dmac, offs);
+               }
+
+               if (errstat & bit) {
+                       s3c64xx_dma_errirq(dmac, offs);
+                       writel(bit, dmac->regs + PL080_ERR_CLEAR);
+               }
+       }
+
+       return IRQ_HANDLED;
+}
+
+static struct sysdev_class dma_sysclass = {
+       .name           = "s3c64xx-dma",
+};
+
+static int s3c64xx_dma_init1(int chno, enum dma_ch chbase,
+                            int irq, unsigned int base)
+{
+       struct s3c2410_dma_chan *chptr = &s3c2410_chans[chno];
+       struct s3c64xx_dmac *dmac;
+       char clkname[16];
+       void __iomem *regs;
+       void __iomem *regptr;
+       int err, ch;
+
+       dmac = kzalloc(sizeof(struct s3c64xx_dmac), GFP_KERNEL);
+       if (!dmac) {
+               printk(KERN_ERR "%s: failed to alloc mem\n", __func__);
+               return -ENOMEM;
+       }
+
+       dmac->sysdev.id = chno / 8;
+       dmac->sysdev.cls = &dma_sysclass;
+
+       err = sysdev_register(&dmac->sysdev);
+       if (err) {
+               printk(KERN_ERR "%s: failed to register sysdevice\n", __func__);
+               goto err_alloc;
+       }
+
+       regs = ioremap(base, 0x200);
+       if (!regs) {
+               printk(KERN_ERR "%s: failed to ioremap()\n", __func__);
+               err = -ENXIO;
+               goto err_dev;
+       }
+
+       snprintf(clkname, sizeof(clkname), "dma%d", dmac->sysdev.id);
+
+       dmac->clk = clk_get(NULL, clkname);
+       if (IS_ERR(dmac->clk)) {
+               printk(KERN_ERR "%s: failed to get clock %s\n", __func__, clkname);
+               err = PTR_ERR(dmac->clk);
+               goto err_map;
+       }
+
+       clk_enable(dmac->clk);
+
+       dmac->regs = regs;
+       dmac->chanbase = chbase;
+       dmac->channels = chptr;
+
+       err = request_irq(irq, s3c64xx_dma_irq, 0, "DMA", dmac);
+       if (err < 0) {
+               printk(KERN_ERR "%s: failed to get irq\n", __func__);
+               goto err_clk;
+       }
+
+       regptr = regs + PL080_Cx_BASE(0);
+
+       for (ch = 0; ch < 8; ch++, chno++, chptr++) {
+               printk(KERN_INFO "%s: registering DMA %d (%p)\n",
+                      __func__, chno, regptr);
+
+               chptr->bit = 1 << ch;
+               chptr->number = chno;
+               chptr->dmac = dmac;
+               chptr->regs = regptr;
+               regptr += PL008_Cx_STRIDE;
+       }
+
+       /* for the moment, permanently enable the controller */
+       writel(PL080_CONFIG_ENABLE, regs + PL080_CONFIG);
+
+       printk(KERN_INFO "PL080: IRQ %d, at %p\n", irq, regs);
+
+       return 0;
+
+err_clk:
+       clk_disable(dmac->clk);
+       clk_put(dmac->clk);
+err_map:
+       iounmap(regs);
+err_dev:
+       sysdev_unregister(&dmac->sysdev);
+err_alloc:
+       kfree(dmac);
+       return err;
+}
+
+static int __init s3c64xx_dma_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "%s: Registering DMA channels\n", __func__);
+
+       dma_pool = dma_pool_create("DMA-LLI", NULL, 32, 16, 0);
+       if (!dma_pool) {
+               printk(KERN_ERR "%s: failed to create pool\n", __func__);
+               return -ENOMEM;
+       }
+
+       ret = sysdev_class_register(&dma_sysclass);
+       if (ret) {
+               printk(KERN_ERR "%s: failed to create sysclass\n", __func__);
+               return -ENOMEM;
+       }
+
+       /* Set all DMA configuration to be DMA, not SDMA */
+       writel(0xffffff, S3C_SYSREG(0x110));
+
+       /* Register standard DMA controlers */
+       s3c64xx_dma_init1(0, DMACH_UART0, IRQ_DMA0, 0x75000000);
+       s3c64xx_dma_init1(8, DMACH_PCM1_TX, IRQ_DMA1, 0x75100000);
+
+       return 0;
+}
+
+arch_initcall(s3c64xx_dma_init);
index 78ee52cffc9e936ced05d5092a3e9dee4559b166..da7b60ee5e677fc32d1639fec1b48377af9a53a2 100644 (file)
@@ -385,12 +385,19 @@ static __init void s3c64xx_gpiolib_add_4bit(struct s3c_gpio_chip *chip)
 {
        chip->chip.direction_input = s3c64xx_gpiolib_4bit_input;
        chip->chip.direction_output = s3c64xx_gpiolib_4bit_output;
+       chip->pm = __gpio_pm(&s3c_gpio_pm_4bit);
 }
 
 static __init void s3c64xx_gpiolib_add_4bit2(struct s3c_gpio_chip *chip)
 {
        chip->chip.direction_input = s3c64xx_gpiolib_4bit2_input;
        chip->chip.direction_output = s3c64xx_gpiolib_4bit2_output;
+       chip->pm = __gpio_pm(&s3c_gpio_pm_4bit);
+}
+
+static __init void s3c64xx_gpiolib_add_2bit(struct s3c_gpio_chip *chip)
+{
+       chip->pm = __gpio_pm(&s3c_gpio_pm_2bit);
 }
 
 static __init void s3c64xx_gpiolib_add(struct s3c_gpio_chip *chips,
@@ -412,7 +419,8 @@ static __init int s3c64xx_gpiolib_init(void)
        s3c64xx_gpiolib_add(gpio_4bit2, ARRAY_SIZE(gpio_4bit2),
                            s3c64xx_gpiolib_add_4bit2);
 
-       s3c64xx_gpiolib_add(gpio_2bit, ARRAY_SIZE(gpio_2bit), NULL);
+       s3c64xx_gpiolib_add(gpio_2bit, ARRAY_SIZE(gpio_2bit),
+                           s3c64xx_gpiolib_add_2bit);
 
        return 0;
 }
diff --git a/arch/arm/plat-s3c64xx/include/plat/dma-plat.h b/arch/arm/plat-s3c64xx/include/plat/dma-plat.h
new file mode 100644 (file)
index 0000000..0c30dd9
--- /dev/null
@@ -0,0 +1,70 @@
+/* linux/arch/arm/plat-s3c64xx/include/plat/dma-plat.h
+ *
+ * Copyright 2009 Openmoko, Inc.
+ * Copyright 2009 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX DMA core
+ *
+ * This 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 DMACH_LOW_LEVEL (1<<28) /* use this to specifiy hardware ch no */
+
+struct s3c64xx_dma_buff;
+
+/** s3c64xx_dma_buff - S3C64XX DMA buffer descriptor
+ * @next: Pointer to next buffer in queue or ring.
+ * @pw: Client provided identifier
+ * @lli: Pointer to hardware descriptor this buffer is associated with.
+ * @lli_dma: Hardare address of the descriptor.
+ */
+struct s3c64xx_dma_buff {
+       struct s3c64xx_dma_buff *next;
+
+       void                    *pw;
+       struct pl080_lli        *lli;
+       dma_addr_t               lli_dma;
+};
+
+struct s3c64xx_dmac;
+
+struct s3c2410_dma_chan {
+       unsigned char            number;      /* number of this dma channel */
+       unsigned char            in_use;      /* channel allocated */
+       unsigned char            bit;         /* bit for enable/disable/etc */
+       unsigned char            hw_width;
+       unsigned char            peripheral;
+
+       unsigned int             flags;
+       enum s3c2410_dmasrc      source;
+
+
+       dma_addr_t              dev_addr;
+
+       struct s3c2410_dma_client *client;
+       struct s3c64xx_dmac     *dmac;          /* pointer to controller */
+
+       void __iomem            *regs;
+
+       /* cdriver callbacks */
+       s3c2410_dma_cbfn_t       callback_fn;   /* buffer done callback */
+       s3c2410_dma_opfn_t       op_fn;         /* channel op callback */
+
+       /* buffer list and information */
+       struct s3c64xx_dma_buff *curr;          /* current dma buffer */
+       struct s3c64xx_dma_buff *next;          /* next buffer to load */
+       struct s3c64xx_dma_buff *end;           /* end of queue */
+
+       /* note, when channel is running in circular mode, curr is the
+        * first buffer enqueued, end is the last and curr is where the
+        * last buffer-done event is set-at. The buffers are not freed
+        * and the last buffer hardware descriptor points back to the
+        * first.
+        */
+};
+
+#include <plat/dma-core.h>
index f865bf4d709eaea2299f93c85de83b59c5b7457e..743a70094d0411cc421e3b32bccfdc7dce7c5fe3 100644 (file)
 
 #define S3C_EINT(x)            ((x) + S3C_IRQ_EINT_BASE)
 #define IRQ_EINT(x)            S3C_EINT(x)
+#define IRQ_EINT_BIT(x)                ((x) - S3C_EINT(0))
 
 /* Next the external interrupt groups. These are similar to the IRQ_EINT(x)
  * that they are sourced from the GPIO pins but with a different scheme for
diff --git a/arch/arm/plat-s3c64xx/include/plat/pm-core.h b/arch/arm/plat-s3c64xx/include/plat/pm-core.h
new file mode 100644 (file)
index 0000000..d347de3
--- /dev/null
@@ -0,0 +1,98 @@
+/* linux/arch/arm/plat-s3c64xx/include/plat/pm-core.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX - PM core support for arch/arm/plat-s3c/pm.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 <plat/regs-gpio.h>
+
+static inline void s3c_pm_debug_init_uart(void)
+{
+       u32 tmp = __raw_readl(S3C_PCLK_GATE);
+
+       /* As a note, since the S3C64XX UARTs generally have multiple
+        * clock sources, we simply enable PCLK at the moment and hope
+        * that the resume settings for the UART are suitable for the
+        * use with PCLK.
+        */
+
+       tmp |= S3C_CLKCON_PCLK_UART0;
+       tmp |= S3C_CLKCON_PCLK_UART1;
+       tmp |= S3C_CLKCON_PCLK_UART2;
+       tmp |= S3C_CLKCON_PCLK_UART3;
+
+       __raw_writel(tmp, S3C_PCLK_GATE);
+       udelay(10);
+}
+
+static inline void s3c_pm_arch_prepare_irqs(void)
+{
+       /* VIC should have already been taken care of */
+
+       /* clear any pending EINT0 interrupts */
+       __raw_writel(__raw_readl(S3C64XX_EINT0PEND), S3C64XX_EINT0PEND);
+}
+
+static inline void s3c_pm_arch_stop_clocks(void)
+{
+}
+
+static inline void s3c_pm_arch_show_resume_irqs(void)
+{
+}
+
+/* make these defines, we currently do not have any need to change
+ * the IRQ wake controls depending on the CPU we are running on */
+
+#define s3c_irqwake_eintallow  ((1 << 28) - 1)
+#define s3c_irqwake_intallow   (0)
+
+static inline void s3c_pm_arch_update_uart(void __iomem *regs,
+                                          struct pm_uart_save *save)
+{
+       u32 ucon = __raw_readl(regs + S3C2410_UCON);
+       u32 ucon_clk = ucon & S3C6400_UCON_CLKMASK;
+       u32 save_clk = save->ucon & S3C6400_UCON_CLKMASK;
+       u32 new_ucon;
+       u32 delta;
+
+       /* S3C64XX UART blocks only support level interrupts, so ensure that
+        * when we restore unused UART blocks we force the level interrupt
+        * settigs. */
+       save->ucon |= S3C2410_UCON_TXILEVEL | S3C2410_UCON_RXILEVEL;
+
+       /* We have a constraint on changing the clock type of the UART
+        * between UCLKx and PCLK, so ensure that when we restore UCON
+        * that the CLK field is correctly modified if the bootloader
+        * has changed anything.
+        */
+       if (ucon_clk != save_clk) {
+               new_ucon = save->ucon;
+               delta = ucon_clk ^ save_clk;
+
+               /* change from UCLKx => wrong PCLK,
+                * either UCLK can be tested for by a bit-test
+                * with UCLK0 */
+               if (ucon_clk & S3C6400_UCON_UCLK0 &&
+                   !(save_clk & S3C6400_UCON_UCLK0) &&
+                   delta & S3C6400_UCON_PCLK2) {
+                       new_ucon &= ~S3C6400_UCON_UCLK0;
+               } else if (delta == S3C6400_UCON_PCLK2) {
+                       /* as an precaution, don't change from
+                        * PCLK2 => PCLK or vice-versa */
+                       new_ucon ^= S3C6400_UCON_PCLK2;
+               }
+
+               S3C_PMDBG("ucon change %04x => %04x (save=%04x)\n",
+                         ucon, new_ucon, save->ucon);
+               save->ucon = new_ucon;
+       }
+}
index b1082c163247678621614889f9d5bacd893a0f26..52836d41e333f9a552ac6fac8f9b6316a0749a68 100644 (file)
@@ -32,6 +32,7 @@
 #define S3C_HCLK_GATE          S3C_CLKREG(0x30)
 #define S3C_PCLK_GATE          S3C_CLKREG(0x34)
 #define S3C_SCLK_GATE          S3C_CLKREG(0x38)
+#define S3C_MEM0_GATE          S3C_CLKREG(0x3C)
 
 /* CLKDIV0 */
 #define S3C6400_CLKDIV0_MFC_MASK       (0xf << 28)
index 571eaa2e54f1433dc098b0b7e634e30017db941d..11f2e1e119b0946803c59dcedaa6216a80027ee6 100644 (file)
 /* Common init code for S3C6400 related SoCs */
 
 extern void s3c6400_common_init_uarts(struct s3c2410_uartcfg *cfg, int no);
-extern void s3c6400_register_clocks(void);
+extern void s3c6400_register_clocks(unsigned armclk_divlimit);
 extern void s3c6400_setup_clocks(void);
 
 #ifdef CONFIG_CPU_S3C6400
 
 extern  int s3c6400_init(void);
+extern void s3c6400_init_irq(void);
 extern void s3c6400_map_io(void);
 extern void s3c6400_init_clocks(int xtal);
 
index 47e5155bb13ed897420dca2cdfabbffd3d4d489b..f81b7b818ba0f92a7013e153e00cd206c622ef6f 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
+#include <linux/sysdev.h>
 #include <linux/gpio.h>
 #include <linux/irq.h>
 #include <linux/io.h>
@@ -26,6 +27,7 @@
 
 #include <mach/map.h>
 #include <plat/cpu.h>
+#include <plat/pm.h>
 
 #define eint_offset(irq)       ((irq) - IRQ_EINT(0))
 #define eint_irq_to_bit(irq)   (1 << eint_offset(irq))
@@ -134,6 +136,7 @@ static struct irq_chip s3c_irq_eint = {
        .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
diff --git a/arch/arm/plat-s3c64xx/irq-pm.c b/arch/arm/plat-s3c64xx/irq-pm.c
new file mode 100644 (file)
index 0000000..ca523b5
--- /dev/null
@@ -0,0 +1,111 @@
+/* arch/arm/plat-s3c64xx/irq-pm.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX - Interrupt handling Power Management
+ *
+ * This 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/sysdev.h>
+#include <linux/interrupt.h>
+#include <linux/serial_core.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <mach/map.h>
+
+#include <plat/regs-serial.h>
+#include <plat/regs-timer.h>
+#include <plat/regs-gpio.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
+
+/* We handled all the IRQ types in this code, to save having to make several
+ * small files to handle each different type separately. Having the EINT_GRP
+ * code here shouldn't be as much bloat as the IRQ table space needed when
+ * they are enabled. The added benefit is we ensure that these registers are
+ * in the same state as we suspended.
+ */
+
+static struct sleep_save irq_save[] = {
+       SAVE_ITEM(S3C64XX_PRIORITY),
+       SAVE_ITEM(S3C64XX_EINT0CON0),
+       SAVE_ITEM(S3C64XX_EINT0CON1),
+       SAVE_ITEM(S3C64XX_EINT0FLTCON0),
+       SAVE_ITEM(S3C64XX_EINT0FLTCON1),
+       SAVE_ITEM(S3C64XX_EINT0FLTCON2),
+       SAVE_ITEM(S3C64XX_EINT0FLTCON3),
+       SAVE_ITEM(S3C64XX_EINT0MASK),
+       SAVE_ITEM(S3C64XX_TINT_CSTAT),
+};
+
+static struct irq_grp_save {
+       u32     fltcon;
+       u32     con;
+       u32     mask;
+} eint_grp_save[5];
+
+static u32 irq_uart_mask[CONFIG_SERIAL_SAMSUNG_UARTS];
+
+static int s3c64xx_irq_pm_suspend(struct sys_device *dev, pm_message_t state)
+{
+       struct irq_grp_save *grp = eint_grp_save;
+       int i;
+
+       S3C_PMDBG("%s: suspending IRQs\n", __func__);
+
+       s3c_pm_do_save(irq_save, ARRAY_SIZE(irq_save));
+
+       for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++)
+               irq_uart_mask[i] = __raw_readl(S3C_VA_UARTx(i) + S3C64XX_UINTM);
+
+       for (i = 0; i < ARRAY_SIZE(eint_grp_save); i++, grp++) {
+               grp->con = __raw_readl(S3C64XX_EINT12CON + (i * 4));
+               grp->mask = __raw_readl(S3C64XX_EINT12MASK + (i * 4));
+               grp->fltcon = __raw_readl(S3C64XX_EINT12FLTCON + (i * 4));
+       }
+
+       return 0;
+}
+
+static int s3c64xx_irq_pm_resume(struct sys_device *dev)
+{
+       struct irq_grp_save *grp = eint_grp_save;
+       int i;
+
+       S3C_PMDBG("%s: resuming IRQs\n", __func__);
+
+       s3c_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
+
+       for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++)
+               __raw_writel(irq_uart_mask[i], S3C_VA_UARTx(i) + S3C64XX_UINTM);
+
+       for (i = 0; i < ARRAY_SIZE(eint_grp_save); i++, grp++) {
+               __raw_writel(grp->con, S3C64XX_EINT12CON + (i * 4));
+               __raw_writel(grp->mask, S3C64XX_EINT12MASK + (i * 4));
+               __raw_writel(grp->fltcon, S3C64XX_EINT12FLTCON + (i * 4));
+       }
+
+       S3C_PMDBG("%s: IRQ configuration restored\n", __func__);
+       return 0;
+}
+
+static struct sysdev_driver s3c64xx_irq_driver = {
+       .suspend = s3c64xx_irq_pm_suspend,
+       .resume  = s3c64xx_irq_pm_resume,
+};
+
+static int __init s3c64xx_irq_pm_init(void)
+{
+       return sysdev_driver_register(&s3c64xx_sysclass, &s3c64xx_irq_driver);
+}
+
+arch_initcall(s3c64xx_irq_pm_init);
+
index f22edf7c2d2de65b8fee6ba955468d8b9feb7bcf..8dc5b6da978951d49e79305631368360624527dd 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
+#include <linux/serial_core.h>
 #include <linux/irq.h>
 #include <linux/io.h>
 
 #include <asm/hardware/vic.h>
 
 #include <mach/map.h>
+#include <plat/regs-serial.h>
 #include <plat/regs-timer.h>
 #include <plat/cpu.h>
 
@@ -135,9 +137,6 @@ static inline unsigned int s3c_irq_uart_bit(unsigned int irq)
 }
 
 /* UART interrupt registers, not worth adding to seperate include header */
-#define S3C64XX_UINTP  0x30
-#define S3C64XX_UINTSP 0x34
-#define S3C64XX_UINTM  0x38
 
 static void s3c_irq_uart_mask(unsigned int irq)
 {
@@ -233,8 +232,8 @@ void __init s3c64xx_init_irq(u32 vic0_valid, u32 vic1_valid)
        printk(KERN_DEBUG "%s: initialising interrupts\n", __func__);
 
        /* initialise the pair of VICs */
-       vic_init(S3C_VA_VIC0, S3C_VIC0_BASE, vic0_valid);
-       vic_init(S3C_VA_VIC1, S3C_VIC1_BASE, vic1_valid);
+       vic_init(S3C_VA_VIC0, S3C_VIC0_BASE, vic0_valid, 0);
+       vic_init(S3C_VA_VIC1, S3C_VIC1_BASE, vic1_valid, 0);
 
        /* add the timer sub-irqs */
 
diff --git a/arch/arm/plat-s3c64xx/pm.c b/arch/arm/plat-s3c64xx/pm.c
new file mode 100644 (file)
index 0000000..07a6516
--- /dev/null
@@ -0,0 +1,175 @@
+/* linux/arch/arm/plat-s3c64xx/pm.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX CPU PM support.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/init.h>
+#include <linux/suspend.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+
+#include <mach/map.h>
+
+#include <plat/pm.h>
+#include <plat/regs-sys.h>
+#include <plat/regs-gpio.h>
+#include <plat/regs-clock.h>
+#include <plat/regs-syscon-power.h>
+#include <plat/regs-gpio-memport.h>
+
+#ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK
+#include <plat/gpio-bank-n.h>
+
+void s3c_pm_debug_smdkled(u32 set, u32 clear)
+{
+       unsigned long flags;
+       u32 reg;
+
+       local_irq_save(flags);
+       reg = __raw_readl(S3C64XX_GPNCON);
+       reg &= ~(S3C64XX_GPN_CONMASK(12) | S3C64XX_GPN_CONMASK(13) |
+                S3C64XX_GPN_CONMASK(14) | S3C64XX_GPN_CONMASK(15));
+       reg |= S3C64XX_GPN_OUTPUT(12) | S3C64XX_GPN_OUTPUT(13) |
+              S3C64XX_GPN_OUTPUT(14) | S3C64XX_GPN_OUTPUT(15);
+       __raw_writel(reg, S3C64XX_GPNCON);
+
+       reg = __raw_readl(S3C64XX_GPNDAT);
+       reg &= ~(clear << 12);
+       reg |= set << 12;
+       __raw_writel(reg, S3C64XX_GPNDAT);
+
+       local_irq_restore(flags);
+}
+#endif
+
+static struct sleep_save core_save[] = {
+       SAVE_ITEM(S3C_APLL_LOCK),
+       SAVE_ITEM(S3C_MPLL_LOCK),
+       SAVE_ITEM(S3C_EPLL_LOCK),
+       SAVE_ITEM(S3C_CLK_SRC),
+       SAVE_ITEM(S3C_CLK_DIV0),
+       SAVE_ITEM(S3C_CLK_DIV1),
+       SAVE_ITEM(S3C_CLK_DIV2),
+       SAVE_ITEM(S3C_CLK_OUT),
+       SAVE_ITEM(S3C_HCLK_GATE),
+       SAVE_ITEM(S3C_PCLK_GATE),
+       SAVE_ITEM(S3C_SCLK_GATE),
+       SAVE_ITEM(S3C_MEM0_GATE),
+
+       SAVE_ITEM(S3C_EPLL_CON1),
+       SAVE_ITEM(S3C_EPLL_CON0),
+
+       SAVE_ITEM(S3C64XX_MEM0DRVCON),
+       SAVE_ITEM(S3C64XX_MEM1DRVCON),
+
+#ifndef CONFIG_CPU_FREQ
+       SAVE_ITEM(S3C_APLL_CON),
+       SAVE_ITEM(S3C_MPLL_CON),
+#endif
+};
+
+static struct sleep_save misc_save[] = {
+       SAVE_ITEM(S3C64XX_AHB_CON0),
+       SAVE_ITEM(S3C64XX_AHB_CON1),
+       SAVE_ITEM(S3C64XX_AHB_CON2),
+       
+       SAVE_ITEM(S3C64XX_SPCON),
+
+       SAVE_ITEM(S3C64XX_MEM0CONSTOP),
+       SAVE_ITEM(S3C64XX_MEM1CONSTOP),
+       SAVE_ITEM(S3C64XX_MEM0CONSLP0),
+       SAVE_ITEM(S3C64XX_MEM0CONSLP1),
+       SAVE_ITEM(S3C64XX_MEM1CONSLP),
+};
+
+void s3c_pm_configure_extint(void)
+{
+       __raw_writel(s3c_irqwake_eintmask, S3C64XX_EINT_MASK);
+}
+
+void s3c_pm_restore_core(void)
+{
+       __raw_writel(0, S3C64XX_EINT_MASK);
+
+       s3c_pm_debug_smdkled(1 << 2, 0);
+
+       s3c_pm_do_restore_core(core_save, ARRAY_SIZE(core_save));
+       s3c_pm_do_restore(misc_save, ARRAY_SIZE(misc_save));
+}
+
+void s3c_pm_save_core(void)
+{
+       s3c_pm_do_save(misc_save, ARRAY_SIZE(misc_save));
+       s3c_pm_do_save(core_save, ARRAY_SIZE(core_save));
+}
+
+/* since both s3c6400 and s3c6410 share the same sleep pm calls, we
+ * put the per-cpu code in here until any new cpu comes along and changes
+ * this.
+ */
+
+#include <plat/regs-gpio.h>
+
+static void s3c64xx_cpu_suspend(void)
+{
+       unsigned long tmp;
+
+       /* set our standby method to sleep */
+
+       tmp = __raw_readl(S3C64XX_PWR_CFG);
+       tmp &= ~S3C64XX_PWRCFG_CFG_WFI_MASK;
+       tmp |= S3C64XX_PWRCFG_CFG_WFI_SLEEP;
+       __raw_writel(tmp, S3C64XX_PWR_CFG);
+
+       /* clear any old wakeup */
+
+       __raw_writel(__raw_readl(S3C64XX_WAKEUP_STAT),
+                    S3C64XX_WAKEUP_STAT);
+
+       /* set the LED state to 0110 over sleep */
+       s3c_pm_debug_smdkled(3 << 1, 0xf);
+
+       /* issue the standby signal into the pm unit. Note, we
+        * issue a write-buffer drain just in case */
+
+       tmp = 0;
+
+       asm("b 1f\n\t"
+           ".align 5\n\t"
+           "1:\n\t"
+           "mcr p15, 0, %0, c7, c10, 5\n\t"
+           "mcr p15, 0, %0, c7, c10, 4\n\t"
+           "mcr p15, 0, %0, c7, c0, 4" :: "r" (tmp));
+
+       /* we should never get past here */
+
+       panic("sleep resumed to originator?");
+}
+
+static void s3c64xx_pm_prepare(void)
+{
+       /* store address of resume. */
+       __raw_writel(virt_to_phys(s3c_cpu_resume), S3C64XX_INFORM0);
+
+       /* ensure previous wakeup state is cleared before sleeping */
+       __raw_writel(__raw_readl(S3C64XX_WAKEUP_STAT), S3C64XX_WAKEUP_STAT);
+}
+
+static int s3c64xx_pm_init(void)
+{
+       pm_cpu_prep = s3c64xx_pm_prepare;
+       pm_cpu_sleep = s3c64xx_cpu_suspend;
+       pm_uart_udivslot = 1;
+       return 0;
+}
+
+arch_initcall(s3c64xx_pm_init);
index 05b17528041e36f451e4bc5f0e30b8d33ab316ea..1debc1f9f987bd09cc96d0d2574493bd5adb9e73 100644 (file)
@@ -133,6 +133,65 @@ static struct clksrc_clk clk_mout_mpll = {
        .sources        = &clk_src_mpll,
 };
 
+static unsigned int armclk_mask;
+
+static unsigned long s3c64xx_clk_arm_get_rate(struct clk *clk)
+{
+       unsigned long rate = clk_get_rate(clk->parent);
+       u32 clkdiv;
+
+       /* divisor mask starts at bit0, so no need to shift */
+       clkdiv = __raw_readl(S3C_CLK_DIV0) & armclk_mask;
+
+       return rate / (clkdiv + 1);
+}
+
+static unsigned long s3c64xx_clk_arm_round_rate(struct clk *clk,
+                                               unsigned long rate)
+{
+       unsigned long parent = clk_get_rate(clk->parent);
+       u32 div;
+
+       if (parent < rate)
+               return rate;
+
+       div = (parent / rate) - 1;
+       if (div > armclk_mask)
+               div = armclk_mask;
+
+       return parent / (div + 1);
+}
+
+static int s3c64xx_clk_arm_set_rate(struct clk *clk, unsigned long rate)
+{
+       unsigned long parent = clk_get_rate(clk->parent);
+       u32 div;
+       u32 val;
+
+       if (rate < parent / (armclk_mask + 1))
+               return -EINVAL;
+
+       rate = clk_round_rate(clk, rate);
+       div = clk_get_rate(clk->parent) / rate;
+
+       val = __raw_readl(S3C_CLK_DIV0);
+       val &= armclk_mask;
+       val |= (div - 1);
+       __raw_writel(val, S3C_CLK_DIV0);
+
+       return 0;
+
+}
+
+static struct clk clk_arm = {
+       .name           = "armclk",
+       .id             = -1,
+       .parent         = &clk_mout_apll.clk,
+       .get_rate       = s3c64xx_clk_arm_get_rate,
+       .set_rate       = s3c64xx_clk_arm_set_rate,
+       .round_rate     = s3c64xx_clk_arm_round_rate,
+};
+
 static unsigned long s3c64xx_clk_doutmpll_get_rate(struct clk *clk)
 {
        unsigned long rate = clk_get_rate(clk->parent);
@@ -520,6 +579,33 @@ static struct clksrc_clk clk_irda = {
        .reg_divider    = S3C_CLK_DIV2,
 };
 
+static struct clk *clkset_camif_list[] = {
+       &clk_h2,
+};
+
+static struct clk_sources clkset_camif = {
+       .sources        = clkset_camif_list,
+       .nr_sources     = ARRAY_SIZE(clkset_camif_list),
+};
+
+static struct clksrc_clk clk_camif = {
+       .clk    = {
+               .name           = "camera",
+               .id             = -1,
+               .ctrlbit        = S3C_CLKCON_SCLK_CAM,
+               .enable         = s3c64xx_sclk_ctrl,
+               .set_parent     = s3c64xx_setparent_clksrc,
+               .get_rate       = s3c64xx_getrate_clksrc,
+               .set_rate       = s3c64xx_setrate_clksrc,
+               .round_rate     = s3c64xx_roundrate_clksrc,
+       },
+       .shift          = 0,
+       .mask           = 0,
+       .sources        = &clkset_camif,
+       .divider_shift  = S3C6400_CLKDIV0_CAM_SHIFT,
+       .reg_divider    = S3C_CLK_DIV0,
+};
+
 /* Clock initialisation code */
 
 static struct clksrc_clk *init_parents[] = {
@@ -536,6 +622,7 @@ static struct clksrc_clk *init_parents[] = {
        &clk_audio0,
        &clk_audio1,
        &clk_irda,
+       &clk_camif,
 };
 
 static void __init_or_cpufreq s3c6400_set_clksrc(struct clksrc_clk *clk)
@@ -608,6 +695,7 @@ void __init_or_cpufreq s3c6400_setup_clocks(void)
        clk_fout_epll.rate = epll;
        clk_fout_apll.rate = apll;
 
+       clk_h2.rate = hclk2;
        clk_h.rate = hclk;
        clk_p.rate = pclk;
        clk_f.rate = fclk;
@@ -635,14 +723,30 @@ static struct clk *clks[] __initdata = {
        &clk_audio0.clk,
        &clk_audio1.clk,
        &clk_irda.clk,
+       &clk_camif.clk,
+       &clk_arm,
 };
 
-void __init s3c6400_register_clocks(void)
+/**
+ * s3c6400_register_clocks - register clocks for s3c6400 and above
+ * @armclk_divlimit: Divisor mask for ARMCLK
+ *
+ * Register the clocks for the S3C6400 and above SoC range, such
+ * as ARMCLK and the clocks which have divider chains attached.
+ *
+ * This call does not setup the clocks, which is left to the
+ * s3c6400_setup_clocks() call which may be needed by the cpufreq
+ * or resume code to re-set the clocks if the bootloader has changed
+ * them.
+ */
+void __init s3c6400_register_clocks(unsigned armclk_divlimit)
 {
        struct clk *clkp;
        int ret;
        int ptr;
 
+       armclk_mask = armclk_divlimit;
+
        for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
                clkp = clks[ptr];
                ret = s3c24xx_register_clock(clkp);
diff --git a/arch/arm/plat-s3c64xx/setup-sdhci-gpio.c b/arch/arm/plat-s3c64xx/setup-sdhci-gpio.c
new file mode 100644 (file)
index 0000000..5417123
--- /dev/null
@@ -0,0 +1,55 @@
+/* linux/arch/arm/plat-s3c64xx/setup-sdhci-gpio.c
+ *
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX - 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 <mach/gpio.h>
+#include <plat/gpio-cfg.h>
+
+void s3c64xx_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width)
+{
+       unsigned int gpio;
+       unsigned int end;
+
+       end = S3C64XX_GPG(2 + width);
+
+       /* Set all the necessary GPG pins to special-function 0 */
+       for (gpio = S3C64XX_GPG(0); gpio < end; gpio++) {
+               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+       }
+
+       s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP);
+       s3c_gpio_cfgpin(S3C64XX_GPG(6), S3C_GPIO_SFN(2));
+}
+
+void s3c64xx_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width)
+{
+       unsigned int gpio;
+       unsigned int end;
+
+       end = S3C64XX_GPH(2 + width);
+
+       /* Set all the necessary GPG pins to special-function 0 */
+       for (gpio = S3C64XX_GPH(0); gpio < end; gpio++) {
+               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+       }
+
+       s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP);
+       s3c_gpio_cfgpin(S3C64XX_GPG(6), S3C_GPIO_SFN(3));
+}
diff --git a/arch/arm/plat-s3c64xx/sleep.S b/arch/arm/plat-s3c64xx/sleep.S
new file mode 100644 (file)
index 0000000..8e71fe9
--- /dev/null
@@ -0,0 +1,144 @@
+/* linux/0arch/arm/plat-s3c64xx/sleep.S
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX CPU sleep code
+ *
+ * This 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 <asm/assembler.h>
+#include <mach/map.h>
+
+#undef S3C64XX_VA_GPIO
+#define S3C64XX_VA_GPIO (0x0)
+
+#include <plat/regs-gpio.h>
+#include <plat/gpio-bank-n.h>
+
+#define LL_UART (S3C_PA_UART + (0x400 * CONFIG_S3C_LOWLEVEL_UART_PORT))
+
+       .text
+
+       /* s3c_cpu_save
+        *
+        * Save enough processor state to allow the restart of the pm.c
+        * code after resume.
+        *
+        * entry:
+        *      r0 = pointer to the save block
+       */
+
+ENTRY(s3c_cpu_save)
+       stmfd   sp!, { r4 - r12, lr }
+
+       mrc     p15, 0, r4, c13, c0, 0  @ FCSE/PID
+       mrc     p15, 0, r5, c3, c0, 0   @ Domain ID
+       mrc     p15, 0, r6, c2, c0, 0   @ Translation Table BASE0
+       mrc     p15, 0, r7, c2, c0, 1   @ Translation Table BASE1
+       mrc     p15, 0, r8, c2, c0, 2   @ Translation Table Control
+       mrc     p15, 0, r9, c1, c0, 0   @ Control register
+       mrc     p15, 0, r10, c1, c0, 1  @ Auxiliary control register
+       mrc     p15, 0, r11, c1, c0, 2  @ Co-processor access controls
+
+       stmia   r0, { r4 - r13 }        @ Save CP registers and SP
+
+       @@ save our state to ram
+       bl      s3c_pm_cb_flushcache
+
+       @@ call final suspend code
+       ldr     r0, =pm_cpu_sleep
+       ldr     pc, [r0]
+       
+       @@ return to the caller, after the MMU is turned on.
+       @@ restore the last bits of the stack and return.
+resume_with_mmu:
+       ldmfd   sp!, { r4 - r12, pc }   @ return, from sp from s3c_cpu_save
+
+       .data
+
+       /* the next bit is code, but it requires easy access to the
+        * s3c_sleep_save_phys data before the MMU is switched on, so
+        * we store the code that needs this variable in the .data where
+        * the value can be written to (the .text segment is RO).
+       */
+
+       .global s3c_sleep_save_phys
+s3c_sleep_save_phys:
+       .word   0
+
+       /* Sleep magic, the word before the resume entry point so that the
+        * bootloader can check for a resumeable image. */
+
+       .word   0x2bedf00d
+
+       /* s3c_cpu_reusme
+        *
+        * This is the entry point, stored by whatever method the bootloader
+        * requires to get the kernel runnign again. This code expects to be
+        * entered with no caches live and the MMU disabled. It will then
+        * restore the MMU and other basic CP registers saved and restart
+        * the kernel C code to finish the resume code.
+       */
+
+ENTRY(s3c_cpu_resume)
+       msr     cpsr_c, #PSR_I_BIT | PSR_F_BIT | SVC_MODE
+       ldr     r2, =LL_UART            /* for debug */
+
+#ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK
+       /* Initialise the GPIO state if we are debugging via the SMDK LEDs,
+        * as the uboot version supplied resets these to inputs during the
+        * resume checks.
+       */
+
+       ldr     r3, =S3C64XX_PA_GPIO
+       ldr     r0, [ r3, #S3C64XX_GPNCON ]
+       bic     r0, r0, #(S3C64XX_GPN_CONMASK(12) | S3C64XX_GPN_CONMASK(13) | \
+                         S3C64XX_GPN_CONMASK(14) | S3C64XX_GPN_CONMASK(15))
+       orr     r0, r0, #(S3C64XX_GPN_OUTPUT(12) | S3C64XX_GPN_OUTPUT(13) | \
+                         S3C64XX_GPN_OUTPUT(14) | S3C64XX_GPN_OUTPUT(15))
+       str     r0, [ r3, #S3C64XX_GPNCON ]
+
+       ldr     r0, [ r3, #S3C64XX_GPNDAT ]
+       bic     r0, r0, #0xf << 12                      @ GPN12..15
+       orr     r0, r0, #1 << 15                        @ GPN15
+       str     r0, [ r3, #S3C64XX_GPNDAT ]
+#endif
+
+       /* __v6_setup from arch/arm/mm/proc-v6.S, ensure that the caches
+        * are thoroughly cleaned just in case the bootloader didn't do it
+        * for us. */
+       mov     r0, #0
+       mcr     p15, 0, r0, c7, c14, 0          @ clean+invalidate D cache
+       mcr     p15, 0, r0, c7, c5, 0           @ invalidate I cache
+       mcr     p15, 0, r0, c7, c15, 0          @ clean+invalidate cache
+       mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer
+       @@mcr   p15, 0, r0, c8, c7, 0           @ invalidate I + D TLBs
+       @@mcr   p15, 0, r0, c7, c7, 0           @ Invalidate I + D caches
+
+       ldr     r0, s3c_sleep_save_phys
+       ldmia   r0, { r4 - r13 }
+
+       mcr     p15, 0, r4, c13, c0, 0  @ FCSE/PID
+       mcr     p15, 0, r5, c3, c0, 0   @ Domain ID
+       mcr     p15, 0, r6, c2, c0, 0   @ Translation Table BASE0
+       mcr     p15, 0, r7, c2, c0, 1   @ Translation Table BASE1
+       mcr     p15, 0, r8, c2, c0, 2   @ Translation Table Control
+       mcr     p15, 0, r10, c1, c0, 1  @ Auxiliary control register
+
+       mov     r0, #0                  @ restore copro access controls
+       mcr     p15, 0, r11, c1, c0, 2  @ Co-processor access controls
+       mcr     p15, 0, r0, c7, c5, 4
+
+       ldr     r2, =resume_with_mmu
+       mcr     p15, 0, r9, c1, c0, 0           /* turn mmu back on */
+       nop
+       mov     pc, r2                          /* jump back */
+
+       .end
diff --git a/arch/arm/plat-stmp3xxx/Kconfig b/arch/arm/plat-stmp3xxx/Kconfig
new file mode 100644 (file)
index 0000000..2cf37c3
--- /dev/null
@@ -0,0 +1,37 @@
+if ARCH_STMP3XXX
+
+menu "Freescale STMP3xxx implementations"
+
+choice
+       prompt "Select STMP3xxx chip family"
+
+config ARCH_STMP37XX
+       bool "Freescale SMTP37xx"
+       select CPU_ARM926T
+       ---help---
+        STMP37xx refers to 3700 through 3769 chips
+
+config ARCH_STMP378X
+       bool "Freescale STMP378x"
+       select CPU_ARM926T
+       ---help---
+        STMP378x refers to 3780 through 3789 chips
+
+endchoice
+
+choice
+       prompt "Select STMP3xxx board type"
+
+config MACH_STMP37XX
+       depends on ARCH_STMP37XX
+       bool "Freescale STMP37xx development board"
+
+config MACH_STMP378X
+       depends on ARCH_STMP378X
+       bool "Freescale STMP378x development board"
+
+endchoice
+
+endmenu
+
+endif
diff --git a/arch/arm/plat-stmp3xxx/Makefile b/arch/arm/plat-stmp3xxx/Makefile
new file mode 100644 (file)
index 0000000..31dd518
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# Makefile for the linux kernel.
+#
+# Object file lists.
+obj-y += core.o timer.o irq.o dma.o clock.o pinmux.o devices.o
diff --git a/arch/arm/plat-stmp3xxx/clock.c b/arch/arm/plat-stmp3xxx/clock.c
new file mode 100644 (file)
index 0000000..5d2f19a
--- /dev/null
@@ -0,0 +1,1135 @@
+/*
+ * Clock manipulation routines for Freescale STMP37XX/STMP378X
+ *
+ * Author: Vitaly Wool <vital@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#define DEBUG
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include <asm/mach-types.h>
+#include <asm/clkdev.h>
+#include <mach/platform.h>
+#include <mach/regs-clkctrl.h>
+
+#include "clock.h"
+
+static DEFINE_SPINLOCK(clocks_lock);
+
+static struct clk osc_24M;
+static struct clk pll_clk;
+static struct clk cpu_clk;
+static struct clk hclk;
+
+static int propagate_rate(struct clk *);
+
+static inline int clk_is_busy(struct clk *clk)
+{
+       return __raw_readl(clk->busy_reg) & (1 << clk->busy_bit);
+}
+
+static inline int clk_good(struct clk *clk)
+{
+       return clk && !IS_ERR(clk) && clk->ops;
+}
+
+static int std_clk_enable(struct clk *clk)
+{
+       if (clk->enable_reg) {
+               u32 clk_reg = __raw_readl(clk->enable_reg);
+               if (clk->enable_negate)
+                       clk_reg &= ~(1 << clk->enable_shift);
+               else
+                       clk_reg |= (1 << clk->enable_shift);
+               __raw_writel(clk_reg, clk->enable_reg);
+               if (clk->enable_wait)
+                       udelay(clk->enable_wait);
+               return 0;
+       } else
+               return -EINVAL;
+}
+
+static int std_clk_disable(struct clk *clk)
+{
+       if (clk->enable_reg) {
+               u32 clk_reg = __raw_readl(clk->enable_reg);
+               if (clk->enable_negate)
+                       clk_reg |= (1 << clk->enable_shift);
+               else
+                       clk_reg &= ~(1 << clk->enable_shift);
+               __raw_writel(clk_reg, clk->enable_reg);
+               return 0;
+       } else
+               return -EINVAL;
+}
+
+static int io_set_rate(struct clk *clk, u32 rate)
+{
+       u32 reg_frac, clkctrl_frac;
+       int i, ret = 0, mask = 0x1f;
+
+       clkctrl_frac = (clk->parent->rate * 18 + rate - 1) / rate;
+
+       if (clkctrl_frac < 18 || clkctrl_frac > 35) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       reg_frac = __raw_readl(clk->scale_reg);
+       reg_frac &= ~(mask << clk->scale_shift);
+       __raw_writel(reg_frac | (clkctrl_frac << clk->scale_shift),
+                               clk->scale_reg);
+       if (clk->busy_reg) {
+               for (i = 10000; i; i--)
+                       if (!clk_is_busy(clk))
+                               break;
+               if (!i)
+                       ret = -ETIMEDOUT;
+               else
+                       ret = 0;
+       }
+out:
+       return ret;
+}
+
+static long io_get_rate(struct clk *clk)
+{
+       long rate = clk->parent->rate * 18;
+       int mask = 0x1f;
+
+       rate /= (__raw_readl(clk->scale_reg) >> clk->scale_shift) & mask;
+       clk->rate = rate;
+
+       return rate;
+}
+
+static long per_get_rate(struct clk *clk)
+{
+       long rate = clk->parent->rate;
+       long div;
+       const int mask = 0xff;
+
+       if (clk->enable_reg &&
+                       !(__raw_readl(clk->enable_reg) & clk->enable_shift))
+               clk->rate = 0;
+       else {
+               div = (__raw_readl(clk->scale_reg) >> clk->scale_shift) & mask;
+               if (div)
+                       rate /= div;
+               clk->rate = rate;
+       }
+
+       return clk->rate;
+}
+
+static int per_set_rate(struct clk *clk, u32 rate)
+{
+       int ret = -EINVAL;
+       int div = (clk->parent->rate + rate - 1) / rate;
+       u32 reg_frac;
+       const int mask = 0xff;
+       int try = 10;
+       int i = -1;
+
+       if (div == 0 || div > mask)
+               goto out;
+
+       reg_frac = __raw_readl(clk->scale_reg);
+       reg_frac &= ~(mask << clk->scale_shift);
+
+       while (try--) {
+               __raw_writel(reg_frac | (div << clk->scale_shift),
+                               clk->scale_reg);
+
+               if (clk->busy_reg) {
+                       for (i = 10000; i; i--)
+                               if (!clk_is_busy(clk))
+                                       break;
+               }
+               if (i)
+                       break;
+       }
+
+       if (!i)
+               ret = -ETIMEDOUT;
+       else
+               ret = 0;
+
+out:
+       if (ret != 0)
+               printk(KERN_ERR "%s: error %d\n", __func__, ret);
+       return ret;
+}
+
+static long lcdif_get_rate(struct clk *clk)
+{
+       long rate = clk->parent->rate;
+       long div;
+       const int mask = 0xff;
+
+       div = (__raw_readl(clk->scale_reg) >> clk->scale_shift) & mask;
+       if (div) {
+               rate /= div;
+               div = (__raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC) &
+                       BM_CLKCTRL_FRAC_PIXFRAC) >> BP_CLKCTRL_FRAC_PIXFRAC;
+               rate /= div;
+       }
+       clk->rate = rate;
+
+       return rate;
+}
+
+static int lcdif_set_rate(struct clk *clk, u32 rate)
+{
+       int ret = 0;
+       /*
+        * On 3700, we can get most timings exact by modifying ref_pix
+        * and the divider, but keeping the phase timings at 1 (2
+        * phases per cycle).
+        *
+        * ref_pix can be between 480e6*18/35=246.9MHz and 480e6*18/18=480MHz,
+        * which is between 18/(18*480e6)=2.084ns and 35/(18*480e6)=4.050ns.
+        *
+        * ns_cycle >= 2*18e3/(18*480) = 25/6
+        * ns_cycle <= 2*35e3/(18*480) = 875/108
+        *
+        * Multiply the ns_cycle by 'div' to lengthen it until it fits the
+        * bounds. This is the divider we'll use after ref_pix.
+        *
+        * 6 * ns_cycle >= 25 * div
+        * 108 * ns_cycle <= 875 * div
+        */
+       u32 ns_cycle = 1000000 / rate;
+       u32 div, reg_val;
+       u32 lowest_result = (u32) -1;
+       u32 lowest_div = 0, lowest_fracdiv = 0;
+
+       for (div = 1; div < 256; ++div) {
+               u32 fracdiv;
+               u32 ps_result;
+               int lower_bound = 6 * ns_cycle >= 25 * div;
+               int upper_bound = 108 * ns_cycle <= 875 * div;
+               if (!lower_bound)
+                       break;
+               if (!upper_bound)
+                       continue;
+               /*
+                * Found a matching div. Calculate fractional divider needed,
+                * rounded up.
+                */
+               fracdiv = ((clk->parent->rate / 1000 * 18 / 2) *
+                               ns_cycle + 1000 * div - 1) /
+                               (1000 * div);
+               if (fracdiv < 18 || fracdiv > 35) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+               /* Calculate the actual cycle time this results in */
+               ps_result = 6250 * div * fracdiv / 27;
+
+               /* Use the fastest result that doesn't break ns_cycle */
+               if (ps_result <= lowest_result) {
+                       lowest_result = ps_result;
+                       lowest_div = div;
+                       lowest_fracdiv = fracdiv;
+               }
+       }
+
+       if (div >= 256 || lowest_result == (u32) -1) {
+               ret = -EINVAL;
+               goto out;
+       }
+       pr_debug("Programming PFD=%u,DIV=%u ref_pix=%uMHz "
+                       "PIXCLK=%uMHz cycle=%u.%03uns\n",
+                       lowest_fracdiv, lowest_div,
+                       480*18/lowest_fracdiv, 480*18/lowest_fracdiv/lowest_div,
+                       lowest_result / 1000, lowest_result % 1000);
+
+       /* Program ref_pix phase fractional divider */
+       reg_val = __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC);
+       reg_val &= ~BM_CLKCTRL_FRAC_PIXFRAC;
+       reg_val |= BF(lowest_fracdiv, CLKCTRL_FRAC_PIXFRAC);
+       __raw_writel(reg_val, REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC);
+
+       /* Ungate PFD */
+       stmp3xxx_clearl(BM_CLKCTRL_FRAC_CLKGATEPIX,
+                       REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC);
+
+       /* Program pix divider */
+       reg_val = __raw_readl(clk->scale_reg);
+       reg_val &= ~(BM_CLKCTRL_PIX_DIV | BM_CLKCTRL_PIX_CLKGATE);
+       reg_val |= BF(lowest_div, CLKCTRL_PIX_DIV);
+       __raw_writel(reg_val, clk->scale_reg);
+
+       /* Wait for divider update */
+       if (clk->busy_reg) {
+               int i;
+               for (i = 10000; i; i--)
+                       if (!clk_is_busy(clk))
+                               break;
+               if (!i) {
+                       ret = -ETIMEDOUT;
+                       goto out;
+               }
+       }
+
+       /* Switch to ref_pix source */
+       reg_val = __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ);
+       reg_val &= ~BM_CLKCTRL_CLKSEQ_BYPASS_PIX;
+       __raw_writel(reg_val, REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ);
+
+out:
+       return ret;
+}
+
+
+static int cpu_set_rate(struct clk *clk, u32 rate)
+{
+       u32 reg_val;
+
+       if (rate < 24000)
+               return -EINVAL;
+       else if (rate == 24000) {
+               /* switch to the 24M source */
+               clk_set_parent(clk, &osc_24M);
+       } else {
+               int i;
+               u32 clkctrl_cpu = 1;
+               u32 c = clkctrl_cpu;
+               u32 clkctrl_frac = 1;
+               u32 val;
+               for ( ; c < 0x40; c++) {
+                       u32 f = (pll_clk.rate*18/c + rate/2) / rate;
+                       int s1, s2;
+
+                       if (f < 18 || f > 35)
+                               continue;
+                       s1 = pll_clk.rate*18/clkctrl_frac/clkctrl_cpu - rate;
+                       s2 = pll_clk.rate*18/c/f - rate;
+                       pr_debug("%s: s1 %d, s2 %d\n", __func__, s1, s2);
+                       if (abs(s1) > abs(s2)) {
+                               clkctrl_cpu = c;
+                               clkctrl_frac = f;
+                       }
+                       if (s2 == 0)
+                               break;
+               };
+               pr_debug("%s: clkctrl_cpu %d, clkctrl_frac %d\n", __func__,
+                               clkctrl_cpu, clkctrl_frac);
+               if (c == 0x40) {
+                       int  d = pll_clk.rate*18/clkctrl_frac/clkctrl_cpu -
+                               rate;
+                       if (abs(d) > 100 ||
+                           clkctrl_frac < 18 || clkctrl_frac > 35)
+                               return -EINVAL;
+               }
+
+               /* 4.6.2 */
+               val = __raw_readl(clk->scale_reg);
+               val &= ~(0x3f << clk->scale_shift);
+               val |= clkctrl_frac;
+               clk_set_parent(clk, &osc_24M);
+               udelay(10);
+               __raw_writel(val, clk->scale_reg);
+               /* ungate */
+               __raw_writel(1<<7, clk->scale_reg + 8);
+               /* write clkctrl_cpu */
+               clk->saved_div = clkctrl_cpu;
+
+               reg_val = __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU);
+               reg_val &= ~0x3F;
+               reg_val |= clkctrl_cpu;
+               __raw_writel(reg_val, REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU);
+
+               for (i = 10000; i; i--)
+                       if (!clk_is_busy(clk))
+                               break;
+               if (!i) {
+                       printk(KERN_ERR "couldn't set up CPU divisor\n");
+                       return -ETIMEDOUT;
+               }
+               clk_set_parent(clk, &pll_clk);
+               clk->saved_div = 0;
+               udelay(10);
+       }
+       return 0;
+}
+
+static long cpu_get_rate(struct clk *clk)
+{
+       long rate = clk->parent->rate * 18;
+
+       rate /= (__raw_readl(clk->scale_reg) >> clk->scale_shift) & 0x3f;
+       rate /= __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU) & 0x3f;
+       rate = ((rate + 9) / 10) * 10;
+       clk->rate = rate;
+
+       return rate;
+}
+
+static long cpu_round_rate(struct clk *clk, u32 rate)
+{
+       unsigned long r = 0;
+
+       if (rate <= 24000)
+               r = 24000;
+       else {
+               u32 clkctrl_cpu = 1;
+               u32 clkctrl_frac;
+               do {
+                       clkctrl_frac =
+                               (pll_clk.rate*18 / clkctrl_cpu + rate/2) / rate;
+                       if (clkctrl_frac > 35)
+                               continue;
+                       if (pll_clk.rate*18 / clkctrl_frac / clkctrl_cpu/10 ==
+                           rate / 10)
+                               break;
+               } while (pll_clk.rate / 2  >= clkctrl_cpu++ * rate);
+               if (pll_clk.rate / 2 < (clkctrl_cpu - 1) * rate)
+                       clkctrl_cpu--;
+               pr_debug("%s: clkctrl_cpu %d, clkctrl_frac %d\n", __func__,
+                               clkctrl_cpu, clkctrl_frac);
+               if (clkctrl_frac < 18)
+                       clkctrl_frac = 18;
+               if (clkctrl_frac > 35)
+                       clkctrl_frac = 35;
+
+               r = pll_clk.rate * 18;
+               r /= clkctrl_frac;
+               r /= clkctrl_cpu;
+               r = 10 * ((r + 9) / 10);
+       }
+       return r;
+}
+
+static long emi_get_rate(struct clk *clk)
+{
+       long rate = clk->parent->rate * 18;
+
+       rate /= (__raw_readl(clk->scale_reg) >> clk->scale_shift) & 0x3f;
+       rate /= __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_EMI) & 0x3f;
+       clk->rate = rate;
+
+       return rate;
+}
+
+static int clkseq_set_parent(struct clk *clk, struct clk *parent)
+{
+       int ret = -EINVAL;
+       int shift = 8;
+
+       /* bypass? */
+       if (parent == &osc_24M)
+               shift = 4;
+
+       if (clk->bypass_reg) {
+#ifdef CONFIG_ARCH_STMP378X
+               u32 hbus_val, cpu_val;
+
+               if (clk == &cpu_clk && shift == 4) {
+                       hbus_val = __raw_readl(REGS_CLKCTRL_BASE +
+                                       HW_CLKCTRL_HBUS);
+                       cpu_val = __raw_readl(REGS_CLKCTRL_BASE +
+                                       HW_CLKCTRL_CPU);
+
+                       hbus_val &= ~(BM_CLKCTRL_HBUS_DIV_FRAC_EN |
+                                     BM_CLKCTRL_HBUS_DIV);
+                       clk->saved_div = cpu_val & BM_CLKCTRL_CPU_DIV_CPU;
+                       cpu_val &= ~BM_CLKCTRL_CPU_DIV_CPU;
+                       cpu_val |= 1;
+
+                       if (machine_is_stmp378x()) {
+                               __raw_writel(hbus_val,
+                                       REGS_CLKCTRL_BASE + HW_CLKCTRL_HBUS);
+                               __raw_writel(cpu_val,
+                                       REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU);
+                               hclk.rate = 0;
+                       }
+               } else if (clk == &cpu_clk && shift == 8) {
+                       hbus_val = __raw_readl(REGS_CLKCTRL_BASE +
+                                                       HW_CLKCTRL_HBUS);
+                       cpu_val = __raw_readl(REGS_CLKCTRL_BASE +
+                                                       HW_CLKCTRL_CPU);
+                       hbus_val &= ~(BM_CLKCTRL_HBUS_DIV_FRAC_EN |
+                                     BM_CLKCTRL_HBUS_DIV);
+                       hbus_val |= 2;
+                       cpu_val &= ~BM_CLKCTRL_CPU_DIV_CPU;
+                       if (clk->saved_div)
+                               cpu_val |= clk->saved_div;
+                       else
+                               cpu_val |= 2;
+
+                       if (machine_is_stmp378x()) {
+                               __raw_writel(hbus_val,
+                                       REGS_CLKCTRL_BASE + HW_CLKCTRL_HBUS);
+                               __raw_writel(cpu_val,
+                                       REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU);
+                               hclk.rate = 0;
+                       }
+               }
+#endif
+               __raw_writel(1 << clk->bypass_shift, clk->bypass_reg + shift);
+
+               ret = 0;
+       }
+
+       return ret;
+}
+
+static int hbus_set_rate(struct clk *clk, u32 rate)
+{
+       u8 div = 0;
+       int is_frac = 0;
+       u32 clkctrl_hbus;
+       struct clk *parent = clk->parent;
+
+       pr_debug("%s: rate %d, parent rate %d\n", __func__, rate,
+                       parent->rate);
+
+       if (rate > parent->rate)
+               return -EINVAL;
+
+       if (((parent->rate + rate/2) / rate) * rate != parent->rate &&
+           parent->rate / rate < 32) {
+               pr_debug("%s: switching to fractional mode\n", __func__);
+               is_frac = 1;
+       }
+
+       if (is_frac)
+               div = (32 * rate + parent->rate / 2) / parent->rate;
+       else
+               div = (parent->rate + rate - 1) / rate;
+       pr_debug("%s: div calculated is %d\n", __func__, div);
+       if (!div || div > 0x1f)
+               return -EINVAL;
+
+       clk_set_parent(&cpu_clk, &osc_24M);
+       udelay(10);
+       clkctrl_hbus = __raw_readl(clk->scale_reg);
+       clkctrl_hbus &= ~0x3f;
+       clkctrl_hbus |= div;
+       clkctrl_hbus |= (is_frac << 5);
+
+       __raw_writel(clkctrl_hbus, clk->scale_reg);
+       if (clk->busy_reg) {
+               int i;
+               for (i = 10000; i; i--)
+                       if (!clk_is_busy(clk))
+                               break;
+               if (!i) {
+                       printk(KERN_ERR "couldn't set up CPU divisor\n");
+                       return -ETIMEDOUT;
+               }
+       }
+       clk_set_parent(&cpu_clk, &pll_clk);
+       __raw_writel(clkctrl_hbus, clk->scale_reg);
+       udelay(10);
+       return 0;
+}
+
+static long hbus_get_rate(struct clk *clk)
+{
+       long rate = clk->parent->rate;
+
+       if (__raw_readl(clk->scale_reg) & 0x20) {
+               rate *= __raw_readl(clk->scale_reg) & 0x1f;
+               rate /= 32;
+       } else
+               rate /= __raw_readl(clk->scale_reg) & 0x1f;
+       clk->rate = rate;
+
+       return rate;
+}
+
+static int xbus_set_rate(struct clk *clk, u32 rate)
+{
+       u16 div = 0;
+       u32 clkctrl_xbus;
+
+       pr_debug("%s: rate %d, parent rate %d\n", __func__, rate,
+                       clk->parent->rate);
+
+       div = (clk->parent->rate + rate - 1) / rate;
+       pr_debug("%s: div calculated is %d\n", __func__, div);
+       if (!div || div > 0x3ff)
+               return -EINVAL;
+
+       clkctrl_xbus = __raw_readl(clk->scale_reg);
+       clkctrl_xbus &= ~0x3ff;
+       clkctrl_xbus |= div;
+       __raw_writel(clkctrl_xbus, clk->scale_reg);
+       if (clk->busy_reg) {
+               int i;
+               for (i = 10000; i; i--)
+                       if (!clk_is_busy(clk))
+                               break;
+               if (!i) {
+                       printk(KERN_ERR "couldn't set up xbus divisor\n");
+                       return -ETIMEDOUT;
+               }
+       }
+       return 0;
+}
+
+static long xbus_get_rate(struct clk *clk)
+{
+       long rate = clk->parent->rate;
+
+       rate /= __raw_readl(clk->scale_reg) & 0x3ff;
+       clk->rate = rate;
+
+       return rate;
+}
+
+
+/* Clock ops */
+
+static struct clk_ops std_ops = {
+       .enable         = std_clk_enable,
+       .disable        = std_clk_disable,
+       .get_rate       = per_get_rate,
+       .set_rate       = per_set_rate,
+       .set_parent     = clkseq_set_parent,
+};
+
+static struct clk_ops min_ops = {
+       .enable         = std_clk_enable,
+       .disable        = std_clk_disable,
+};
+
+static struct clk_ops cpu_ops = {
+       .enable         = std_clk_enable,
+       .disable        = std_clk_disable,
+       .get_rate       = cpu_get_rate,
+       .set_rate       = cpu_set_rate,
+       .round_rate     = cpu_round_rate,
+       .set_parent     = clkseq_set_parent,
+};
+
+static struct clk_ops io_ops = {
+       .enable         = std_clk_enable,
+       .disable        = std_clk_disable,
+       .get_rate       = io_get_rate,
+       .set_rate       = io_set_rate,
+};
+
+static struct clk_ops hbus_ops = {
+       .get_rate       = hbus_get_rate,
+       .set_rate       = hbus_set_rate,
+};
+
+static struct clk_ops xbus_ops = {
+       .get_rate       = xbus_get_rate,
+       .set_rate       = xbus_set_rate,
+};
+
+static struct clk_ops lcdif_ops = {
+       .enable         = std_clk_enable,
+       .disable        = std_clk_disable,
+       .get_rate       = lcdif_get_rate,
+       .set_rate       = lcdif_set_rate,
+       .set_parent     = clkseq_set_parent,
+};
+
+static struct clk_ops emi_ops = {
+       .get_rate       = emi_get_rate,
+};
+
+/* List of on-chip clocks */
+
+static struct clk osc_24M = {
+       .flags          = FIXED_RATE | ENABLED,
+       .rate           = 24000,
+};
+
+static struct clk pll_clk = {
+       .parent         = &osc_24M,
+       .enable_reg     = REGS_CLKCTRL_BASE + HW_CLKCTRL_PLLCTRL0,
+       .enable_shift   = 16,
+       .enable_wait    = 10,
+       .flags          = FIXED_RATE | ENABLED,
+       .rate           = 480000,
+       .ops            = &min_ops,
+};
+
+static struct clk cpu_clk = {
+       .parent         = &pll_clk,
+       .scale_reg      = REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC,
+       .scale_shift    = 0,
+       .bypass_reg     = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
+       .bypass_shift   = 7,
+       .busy_reg       = REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU,
+       .busy_bit       = 28,
+       .flags          = RATE_PROPAGATES | ENABLED,
+       .ops            = &cpu_ops,
+};
+
+static struct clk io_clk = {
+       .parent         = &pll_clk,
+       .enable_reg     = REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC,
+       .enable_shift   = 31,
+       .enable_negate  = 1,
+       .scale_reg      = REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC,
+       .scale_shift    = 24,
+       .flags          = RATE_PROPAGATES | ENABLED,
+       .ops            = &io_ops,
+};
+
+static struct clk hclk = {
+       .parent         = &cpu_clk,
+       .scale_reg      = REGS_CLKCTRL_BASE + HW_CLKCTRL_HBUS,
+       .bypass_reg     = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
+       .bypass_shift   = 7,
+       .busy_reg       = REGS_CLKCTRL_BASE + HW_CLKCTRL_HBUS,
+       .busy_bit       = 29,
+       .flags          = RATE_PROPAGATES | ENABLED,
+       .ops            = &hbus_ops,
+};
+
+static struct clk xclk = {
+       .parent         = &osc_24M,
+       .scale_reg      = REGS_CLKCTRL_BASE + HW_CLKCTRL_XBUS,
+       .busy_reg       = REGS_CLKCTRL_BASE + HW_CLKCTRL_XBUS,
+       .busy_bit       = 31,
+       .flags          = RATE_PROPAGATES | ENABLED,
+       .ops            = &xbus_ops,
+};
+
+static struct clk uart_clk = {
+       .parent         = &xclk,
+       .enable_reg     = REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL,
+       .enable_shift   = 31,
+       .enable_negate  = 1,
+       .flags          = ENABLED,
+       .ops            = &min_ops,
+};
+
+static struct clk audio_clk = {
+       .parent         = &xclk,
+       .enable_reg     = REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL,
+       .enable_shift   = 30,
+       .enable_negate  = 1,
+       .ops            = &min_ops,
+};
+
+static struct clk pwm_clk = {
+       .parent         = &xclk,
+       .enable_reg     = REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL,
+       .enable_shift   = 29,
+       .enable_negate  = 1,
+       .ops            = &min_ops,
+};
+
+static struct clk dri_clk = {
+       .parent         = &xclk,
+       .enable_reg     = REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL,
+       .enable_shift   = 28,
+       .enable_negate  = 1,
+       .ops            = &min_ops,
+};
+
+static struct clk digctl_clk = {
+       .parent         = &xclk,
+       .enable_reg     = REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL,
+       .enable_shift   = 27,
+       .enable_negate  = 1,
+       .ops            = &min_ops,
+};
+
+static struct clk timer_clk = {
+       .parent         = &xclk,
+       .enable_reg     = REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL,
+       .enable_shift   = 26,
+       .enable_negate  = 1,
+       .flags          = ENABLED,
+       .ops            = &min_ops,
+};
+
+static struct clk lcdif_clk = {
+       .parent         = &pll_clk,
+       .scale_reg      = REGS_CLKCTRL_BASE + HW_CLKCTRL_PIX,
+       .busy_reg       = REGS_CLKCTRL_BASE + HW_CLKCTRL_PIX,
+       .busy_bit       = 29,
+       .enable_reg     = REGS_CLKCTRL_BASE + HW_CLKCTRL_PIX,
+       .enable_shift   = 31,
+       .enable_negate  = 1,
+       .bypass_reg     = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
+       .bypass_shift   = 1,
+       .flags          = NEEDS_SET_PARENT,
+       .ops            = &lcdif_ops,
+};
+
+static struct clk ssp_clk = {
+       .parent         = &io_clk,
+       .scale_reg      = REGS_CLKCTRL_BASE + HW_CLKCTRL_SSP,
+       .busy_reg       = REGS_CLKCTRL_BASE + HW_CLKCTRL_SSP,
+       .busy_bit       = 29,
+       .enable_reg     = REGS_CLKCTRL_BASE + HW_CLKCTRL_SSP,
+       .enable_shift   = 31,
+       .bypass_reg     = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
+       .bypass_shift   = 5,
+       .enable_negate  = 1,
+       .flags          = NEEDS_SET_PARENT,
+       .ops            = &std_ops,
+};
+
+static struct clk gpmi_clk = {
+       .parent         = &io_clk,
+       .scale_reg      = REGS_CLKCTRL_BASE + HW_CLKCTRL_GPMI,
+       .busy_reg       = REGS_CLKCTRL_BASE + HW_CLKCTRL_GPMI,
+       .busy_bit       = 29,
+       .enable_reg     = REGS_CLKCTRL_BASE + HW_CLKCTRL_GPMI,
+       .enable_shift   = 31,
+       .enable_negate  = 1,
+       .bypass_reg     = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
+       .bypass_shift   = 4,
+       .flags          = NEEDS_SET_PARENT,
+       .ops            = &std_ops,
+};
+
+static struct clk spdif_clk = {
+       .parent         = &pll_clk,
+       .enable_reg     = REGS_CLKCTRL_BASE + HW_CLKCTRL_SPDIF,
+       .enable_shift   = 31,
+       .enable_negate  = 1,
+       .ops            = &min_ops,
+};
+
+static struct clk emi_clk = {
+       .parent         = &pll_clk,
+       .enable_reg     = REGS_CLKCTRL_BASE + HW_CLKCTRL_EMI,
+       .enable_shift   = 31,
+       .enable_negate  = 1,
+       .scale_reg      = REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC,
+       .scale_shift    = 8,
+       .busy_reg       = REGS_CLKCTRL_BASE + HW_CLKCTRL_EMI,
+       .busy_bit       = 28,
+       .bypass_reg     = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
+       .bypass_shift   = 6,
+       .flags          = ENABLED,
+       .ops            = &emi_ops,
+};
+
+static struct clk ir_clk = {
+       .parent         = &io_clk,
+       .enable_reg     = REGS_CLKCTRL_BASE + HW_CLKCTRL_IR,
+       .enable_shift   = 31,
+       .enable_negate  = 1,
+       .bypass_reg     = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
+       .bypass_shift   = 3,
+       .ops            = &min_ops,
+};
+
+static struct clk saif_clk = {
+       .parent         = &pll_clk,
+       .scale_reg      = REGS_CLKCTRL_BASE + HW_CLKCTRL_SAIF,
+       .busy_reg       = REGS_CLKCTRL_BASE + HW_CLKCTRL_SAIF,
+       .busy_bit       = 29,
+       .enable_reg     = REGS_CLKCTRL_BASE + HW_CLKCTRL_SAIF,
+       .enable_shift   = 31,
+       .enable_negate  = 1,
+       .bypass_reg     = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
+       .bypass_shift   = 0,
+       .ops            = &std_ops,
+};
+
+static struct clk usb_clk = {
+       .parent         = &pll_clk,
+       .enable_reg     = REGS_CLKCTRL_BASE + HW_CLKCTRL_PLLCTRL0,
+       .enable_shift   = 18,
+       .enable_negate  = 1,
+       .ops            = &min_ops,
+};
+
+/* list of all the clocks */
+static struct clk_lookup onchip_clks[] = {
+       {
+               .con_id = "osc_24M",
+               .clk = &osc_24M,
+       }, {
+               .con_id = "pll",
+               .clk = &pll_clk,
+       }, {
+               .con_id = "cpu",
+               .clk = &cpu_clk,
+       }, {
+               .con_id = "hclk",
+               .clk = &hclk,
+       }, {
+               .con_id = "xclk",
+               .clk = &xclk,
+       }, {
+               .con_id = "io",
+               .clk = &io_clk,
+       }, {
+               .con_id = "uart",
+               .clk = &uart_clk,
+       }, {
+               .con_id = "audio",
+               .clk = &audio_clk,
+       }, {
+               .con_id = "pwm",
+               .clk = &pwm_clk,
+       }, {
+               .con_id = "dri",
+               .clk = &dri_clk,
+       }, {
+               .con_id = "digctl",
+               .clk = &digctl_clk,
+       }, {
+               .con_id = "timer",
+               .clk = &timer_clk,
+       }, {
+               .con_id = "lcdif",
+               .clk = &lcdif_clk,
+       }, {
+               .con_id = "ssp",
+               .clk = &ssp_clk,
+       }, {
+               .con_id = "gpmi",
+               .clk = &gpmi_clk,
+       }, {
+               .con_id = "spdif",
+               .clk = &spdif_clk,
+       }, {
+               .con_id = "emi",
+               .clk = &emi_clk,
+       }, {
+               .con_id = "ir",
+               .clk = &ir_clk,
+       }, {
+               .con_id = "saif",
+               .clk = &saif_clk,
+       }, {
+               .con_id = "usb",
+               .clk = &usb_clk,
+       },
+};
+
+static int __init propagate_rate(struct clk *clk)
+{
+       struct clk_lookup *cl;
+
+       for (cl = onchip_clks; cl < onchip_clks + ARRAY_SIZE(onchip_clks);
+            cl++) {
+               if (unlikely(!clk_good(cl->clk)))
+                       continue;
+               if (cl->clk->parent == clk && cl->clk->ops->get_rate) {
+                       cl->clk->ops->get_rate(cl->clk);
+                       if (cl->clk->flags & RATE_PROPAGATES)
+                               propagate_rate(cl->clk);
+               }
+       }
+
+       return 0;
+}
+
+/* Exported API */
+unsigned long clk_get_rate(struct clk *clk)
+{
+       if (unlikely(!clk_good(clk)))
+               return 0;
+
+       if (clk->rate != 0)
+               return clk->rate;
+
+       if (clk->ops->get_rate != NULL)
+               return clk->ops->get_rate(clk);
+
+       return clk_get_rate(clk->parent);
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+       if (unlikely(!clk_good(clk)))
+               return 0;
+
+       if (clk->ops->round_rate)
+               return clk->ops->round_rate(clk, rate);
+
+       return 0;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+static inline int close_enough(long rate1, long rate2)
+{
+       return rate1 && !((rate2 - rate1) * 1000 / rate1);
+}
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       int ret = -EINVAL;
+
+       if (unlikely(!clk_good(clk)))
+               goto out;
+
+       if (clk->flags & FIXED_RATE || !clk->ops->set_rate)
+               goto out;
+
+       else if (!close_enough(clk->rate, rate)) {
+               ret = clk->ops->set_rate(clk, rate);
+               if (ret < 0)
+                       goto out;
+               clk->rate = rate;
+               if (clk->flags & RATE_PROPAGATES)
+                       propagate_rate(clk);
+       } else
+               ret = 0;
+
+out:
+       return ret;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+int clk_enable(struct clk *clk)
+{
+       unsigned long clocks_flags;
+
+       if (unlikely(!clk_good(clk)))
+               return -EINVAL;
+
+       if (clk->parent)
+               clk_enable(clk->parent);
+
+       spin_lock_irqsave(&clocks_lock, clocks_flags);
+
+       clk->usage++;
+       if (clk->ops && clk->ops->enable)
+               clk->ops->enable(clk);
+
+       spin_unlock_irqrestore(&clocks_lock, clocks_flags);
+       return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+static void local_clk_disable(struct clk *clk)
+{
+       if (unlikely(!clk_good(clk)))
+               return;
+
+       if (clk->usage == 0 && clk->ops->disable)
+               clk->ops->disable(clk);
+
+       if (clk->parent)
+               local_clk_disable(clk->parent);
+}
+
+void clk_disable(struct clk *clk)
+{
+       unsigned long clocks_flags;
+
+       if (unlikely(!clk_good(clk)))
+               return;
+
+       spin_lock_irqsave(&clocks_lock, clocks_flags);
+
+       if ((--clk->usage) == 0 && clk->ops->disable)
+               clk->ops->disable(clk);
+
+       spin_unlock_irqrestore(&clocks_lock, clocks_flags);
+       if (clk->parent)
+               clk_disable(clk->parent);
+}
+EXPORT_SYMBOL(clk_disable);
+
+/* Some additional API */
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+       int ret = -ENODEV;
+       unsigned long clocks_flags;
+
+       if (unlikely(!clk_good(clk)))
+               goto out;
+
+       if (!clk->ops->set_parent)
+               goto out;
+
+       spin_lock_irqsave(&clocks_lock, clocks_flags);
+
+       ret = clk->ops->set_parent(clk, parent);
+       if (!ret) {
+               /* disable if usage count is 0 */
+               local_clk_disable(parent);
+
+               parent->usage += clk->usage;
+               clk->parent->usage -= clk->usage;
+
+               /* disable if new usage count is 0 */
+               local_clk_disable(clk->parent);
+
+               clk->parent = parent;
+       }
+       spin_unlock_irqrestore(&clocks_lock, clocks_flags);
+
+out:
+       return ret;
+}
+EXPORT_SYMBOL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+       if (unlikely(!clk_good(clk)))
+               return NULL;
+       return clk->parent;
+}
+EXPORT_SYMBOL(clk_get_parent);
+
+static int __init clk_init(void)
+{
+       struct clk_lookup *cl;
+       struct clk_ops *ops;
+
+       spin_lock_init(&clocks_lock);
+
+       for (cl = onchip_clks; cl < onchip_clks + ARRAY_SIZE(onchip_clks);
+            cl++) {
+               if (cl->clk->flags & ENABLED)
+                       clk_enable(cl->clk);
+               else
+                       local_clk_disable(cl->clk);
+
+               ops = cl->clk->ops;
+
+               if ((cl->clk->flags & NEEDS_INITIALIZATION) &&
+                               ops && ops->set_rate)
+                       ops->set_rate(cl->clk, cl->clk->rate);
+
+               if (cl->clk->flags & FIXED_RATE) {
+                       if (cl->clk->flags & RATE_PROPAGATES)
+                               propagate_rate(cl->clk);
+               } else {
+                       if (ops && ops->get_rate)
+                               ops->get_rate(cl->clk);
+               }
+
+               if (cl->clk->flags & NEEDS_SET_PARENT) {
+                       if (ops && ops->set_parent)
+                               ops->set_parent(cl->clk, cl->clk->parent);
+               }
+
+               clkdev_add(cl);
+       }
+       return 0;
+}
+
+arch_initcall(clk_init);
diff --git a/arch/arm/plat-stmp3xxx/clock.h b/arch/arm/plat-stmp3xxx/clock.h
new file mode 100644 (file)
index 0000000..a6611e1
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Clock control driver for Freescale STMP37XX/STMP378X - internal header file
+ *
+ * Author: Vitaly Wool <vital@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __ARCH_ARM_STMX3XXX_CLOCK_H__
+#define __ARCH_ARM_STMX3XXX_CLOCK_H__
+
+#ifndef __ASSEMBLER__
+
+struct clk_ops {
+       int (*enable) (struct clk *);
+       int (*disable) (struct clk *);
+       long (*get_rate) (struct clk *);
+       long (*round_rate) (struct clk *, u32);
+       int (*set_rate) (struct clk *, u32);
+       int (*set_parent) (struct clk *, struct clk *);
+};
+
+struct clk {
+       struct clk *parent;
+       u32 rate;
+       u32 flags;
+       u8 scale_shift;
+       u8 enable_shift;
+       u8 bypass_shift;
+       u8 busy_bit;
+       s8 usage;
+       int enable_wait;
+       int enable_negate;
+       u32 saved_div;
+       void __iomem *enable_reg;
+       void __iomem *scale_reg;
+       void __iomem *bypass_reg;
+       void __iomem *busy_reg;
+       struct clk_ops *ops;
+};
+
+#endif /* __ASSEMBLER__ */
+
+/* Flags */
+#define RATE_PROPAGATES      (1<<0)
+#define NEEDS_INITIALIZATION (1<<1)
+#define PARENT_SET_RATE      (1<<2)
+#define FIXED_RATE           (1<<3)
+#define ENABLED                     (1<<4)
+#define NEEDS_SET_PARENT     (1<<5)
+
+#endif
diff --git a/arch/arm/plat-stmp3xxx/core.c b/arch/arm/plat-stmp3xxx/core.c
new file mode 100644 (file)
index 0000000..37b8a09
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Freescale STMP37XX/STMP378X core routines
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+
+#include <mach/stmp3xxx.h>
+#include <mach/platform.h>
+#include <mach/dma.h>
+#include <mach/regs-clkctrl.h>
+
+static int __stmp3xxx_reset_block(void __iomem *hwreg, int just_enable)
+{
+       u32 c;
+       int timeout;
+
+       /* the process of software reset of IP block is done
+          in several steps:
+
+          - clear SFTRST and wait for block is enabled;
+          - clear clock gating (CLKGATE bit);
+          - set the SFTRST again and wait for block is in reset;
+          - clear SFTRST and wait for reset completion.
+       */
+       c = __raw_readl(hwreg);
+       c &= ~(1<<31);          /* clear SFTRST */
+       __raw_writel(c, hwreg);
+       for (timeout = 1000000; timeout > 0; timeout--)
+               /* still in SFTRST state ? */
+               if ((__raw_readl(hwreg) & (1<<31)) == 0)
+                       break;
+       if (timeout <= 0) {
+               printk(KERN_ERR"%s(%p): timeout when enabling\n",
+                               __func__, hwreg);
+               return -ETIME;
+       }
+
+       c = __raw_readl(hwreg);
+       c &= ~(1<<30);          /* clear CLKGATE */
+       __raw_writel(c, hwreg);
+
+       if (!just_enable) {
+               c = __raw_readl(hwreg);
+               c |= (1<<31);           /* now again set SFTRST */
+               __raw_writel(c, hwreg);
+               for (timeout = 1000000; timeout > 0; timeout--)
+                       /* poll until CLKGATE set */
+                       if (__raw_readl(hwreg) & (1<<30))
+                               break;
+               if (timeout <= 0) {
+                       printk(KERN_ERR"%s(%p): timeout when resetting\n",
+                                       __func__, hwreg);
+                       return -ETIME;
+               }
+
+               c = __raw_readl(hwreg);
+               c &= ~(1<<31);          /* clear SFTRST */
+               __raw_writel(c, hwreg);
+               for (timeout = 1000000; timeout > 0; timeout--)
+                       /* still in SFTRST state ? */
+                       if ((__raw_readl(hwreg) & (1<<31)) == 0)
+                               break;
+               if (timeout <= 0) {
+                       printk(KERN_ERR"%s(%p): timeout when enabling "
+                                       "after reset\n", __func__, hwreg);
+                       return -ETIME;
+               }
+
+               c = __raw_readl(hwreg);
+               c &= ~(1<<30);          /* clear CLKGATE */
+               __raw_writel(c, hwreg);
+       }
+       for (timeout = 1000000; timeout > 0; timeout--)
+               /* still in SFTRST state ? */
+               if ((__raw_readl(hwreg) & (1<<30)) == 0)
+                       break;
+
+       if (timeout <= 0) {
+               printk(KERN_ERR"%s(%p): timeout when unclockgating\n",
+                               __func__, hwreg);
+               return -ETIME;
+       }
+
+       return 0;
+}
+
+int stmp3xxx_reset_block(void __iomem *hwreg, int just_enable)
+{
+       int try = 10;
+       int r;
+
+       while (try--) {
+               r = __stmp3xxx_reset_block(hwreg, just_enable);
+               if (!r)
+                       break;
+               pr_debug("%s: try %d failed\n", __func__, 10 - try);
+       }
+       return r;
+}
+EXPORT_SYMBOL(stmp3xxx_reset_block);
+
+struct platform_device stmp3xxx_dbguart = {
+       .name = "stmp3xxx-dbguart",
+       .id = -1,
+};
+
+void __init stmp3xxx_init(void)
+{
+       /* Turn off auto-slow and other tricks */
+       stmp3xxx_clearl(0x7f00000, REGS_CLKCTRL_BASE + HW_CLKCTRL_HBUS);
+
+       stmp3xxx_dma_init();
+}
diff --git a/arch/arm/plat-stmp3xxx/devices.c b/arch/arm/plat-stmp3xxx/devices.c
new file mode 100644 (file)
index 0000000..68fed4b
--- /dev/null
@@ -0,0 +1,389 @@
+/*
+* Freescale STMP37XX/STMP378X platform devices
+*
+* Embedded Alley Solutions, Inc <source@embeddedalley.com>
+*
+* Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+* Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+*/
+
+/*
+* The code contained herein is licensed under the GNU General Public
+* License. You may obtain a copy of the GNU General Public License
+* Version 2 or later at the following locations:
+*
+* http://www.opensource.org/licenses/gpl-license.html
+* http://www.gnu.org/copyleft/gpl.html
+*/
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+
+#include <mach/dma.h>
+#include <mach/platform.h>
+#include <mach/stmp3xxx.h>
+#include <mach/regs-lcdif.h>
+#include <mach/regs-uartapp.h>
+#include <mach/regs-gpmi.h>
+#include <mach/regs-usbctrl.h>
+#include <mach/regs-ssp.h>
+#include <mach/regs-rtc.h>
+
+static u64 common_dmamask = DMA_BIT_MASK(32);
+
+static struct resource appuart_resources[] = {
+       {
+               .start = IRQ_UARTAPP_INTERNAL,
+               .end = IRQ_UARTAPP_INTERNAL,
+               .flags = IORESOURCE_IRQ,
+       }, {
+               .start = IRQ_UARTAPP_RX_DMA,
+               .end = IRQ_UARTAPP_RX_DMA,
+               .flags = IORESOURCE_IRQ,
+       }, {
+               .start = IRQ_UARTAPP_TX_DMA,
+               .end = IRQ_UARTAPP_TX_DMA,
+               .flags = IORESOURCE_IRQ,
+       }, {
+               .start = REGS_UARTAPP1_PHYS,
+               .end = REGS_UARTAPP1_PHYS + REGS_UARTAPP_SIZE,
+               .flags = IORESOURCE_MEM,
+       }, {
+               /* Rx DMA channel */
+               .start = STMP3XXX_DMA(6, STMP3XXX_BUS_APBX),
+               .end = STMP3XXX_DMA(6, STMP3XXX_BUS_APBX),
+               .flags = IORESOURCE_DMA,
+       }, {
+               /* Tx DMA channel */
+               .start = STMP3XXX_DMA(7, STMP3XXX_BUS_APBX),
+               .end = STMP3XXX_DMA(7, STMP3XXX_BUS_APBX),
+               .flags = IORESOURCE_DMA,
+       },
+};
+
+struct platform_device stmp3xxx_appuart = {
+       .name = "stmp3xxx-appuart",
+       .id = 0,
+       .resource = appuart_resources,
+       .num_resources = ARRAY_SIZE(appuart_resources),
+       .dev = {
+               .dma_mask       = &common_dmamask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+       },
+};
+
+struct platform_device stmp3xxx_watchdog = {
+      .name   = "stmp3xxx_wdt",
+      .id     = -1,
+};
+
+static struct resource ts_resource[] = {
+       {
+               .flags  = IORESOURCE_IRQ,
+               .start  = IRQ_TOUCH_DETECT,
+               .end    = IRQ_TOUCH_DETECT,
+       }, {
+               .flags  = IORESOURCE_IRQ,
+               .start  = IRQ_LRADC_CH5,
+               .end    = IRQ_LRADC_CH5,
+       },
+};
+
+struct platform_device stmp3xxx_touchscreen = {
+       .name           = "stmp3xxx_ts",
+       .id             = -1,
+       .resource       = ts_resource,
+       .num_resources  = ARRAY_SIZE(ts_resource),
+};
+
+/*
+* Keypad device
+*/
+struct platform_device stmp3xxx_keyboard = {
+       .name           = "stmp3xxx-keyboard",
+       .id             = -1,
+};
+
+static struct resource gpmi_resources[] = {
+       {
+               .flags = IORESOURCE_MEM,
+               .start = REGS_GPMI_PHYS,
+               .end = REGS_GPMI_PHYS + REGS_GPMI_SIZE,
+       }, {
+               .flags = IORESOURCE_IRQ,
+               .start = IRQ_GPMI_DMA,
+               .end = IRQ_GPMI_DMA,
+       }, {
+               .flags = IORESOURCE_DMA,
+               .start = STMP3XXX_DMA(4, STMP3XXX_BUS_APBH),
+               .end = STMP3XXX_DMA(8, STMP3XXX_BUS_APBH),
+       },
+};
+
+struct platform_device stmp3xxx_gpmi = {
+       .name = "gpmi",
+       .id = -1,
+       .dev    = {
+               .dma_mask       = &common_dmamask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+       },
+       .resource = gpmi_resources,
+       .num_resources = ARRAY_SIZE(gpmi_resources),
+};
+
+static struct resource mmc1_resource[] = {
+       {
+               .flags  = IORESOURCE_MEM,
+               .start  = REGS_SSP1_PHYS,
+               .end    = REGS_SSP1_PHYS + REGS_SSP_SIZE,
+       }, {
+               .flags  = IORESOURCE_DMA,
+               .start  = STMP3XXX_DMA(1, STMP3XXX_BUS_APBH),
+               .end    = STMP3XXX_DMA(1, STMP3XXX_BUS_APBH),
+       }, {
+               .flags  = IORESOURCE_IRQ,
+               .start  = IRQ_SSP1_DMA,
+               .end    = IRQ_SSP1_DMA,
+       }, {
+               .flags  = IORESOURCE_IRQ,
+               .start  = IRQ_SSP_ERROR,
+               .end    = IRQ_SSP_ERROR,
+       },
+};
+
+struct platform_device stmp3xxx_mmc = {
+       .name   = "stmp3xxx-mmc",
+       .id     = 1,
+       .dev    = {
+               .dma_mask       = &common_dmamask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+       },
+       .resource = mmc1_resource,
+       .num_resources = ARRAY_SIZE(mmc1_resource),
+};
+
+static struct resource usb_resources[] = {
+       {
+               .start  = REGS_USBCTRL_PHYS,
+               .end    = REGS_USBCTRL_PHYS + SZ_4K,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = IRQ_USB_CTRL,
+               .end    = IRQ_USB_CTRL,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device stmp3xxx_udc = {
+       .name           = "fsl-usb2-udc",
+       .id             = -1,
+       .dev            = {
+               .dma_mask               = &common_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+       .resource = usb_resources,
+       .num_resources = ARRAY_SIZE(usb_resources),
+};
+
+struct platform_device stmp3xxx_ehci = {
+       .name           = "fsl-ehci",
+       .id             = -1,
+       .dev            = {
+               .dma_mask               = &common_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+       .resource       = usb_resources,
+       .num_resources  = ARRAY_SIZE(usb_resources),
+};
+
+static struct resource rtc_resources[] = {
+       {
+               .start  = REGS_RTC_PHYS,
+               .end    = REGS_RTC_PHYS + REGS_RTC_SIZE,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = IRQ_RTC_ALARM,
+               .end    = IRQ_RTC_ALARM,
+               .flags  = IORESOURCE_IRQ,
+       }, {
+               .start  = IRQ_RTC_1MSEC,
+               .end    = IRQ_RTC_1MSEC,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device stmp3xxx_rtc = {
+       .name           = "stmp3xxx-rtc",
+       .id             = -1,
+       .resource       = rtc_resources,
+       .num_resources  = ARRAY_SIZE(rtc_resources),
+};
+
+static struct resource ssp1_resources[] = {
+       {
+               .start  = REGS_SSP1_PHYS,
+               .end    = REGS_SSP1_PHYS + REGS_SSP_SIZE,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = IRQ_SSP1_DMA,
+               .end    = IRQ_SSP1_DMA,
+               .flags  = IORESOURCE_IRQ,
+       }, {
+               .start  = STMP3XXX_DMA(1, STMP3XXX_BUS_APBH),
+               .end    = STMP3XXX_DMA(1, STMP3XXX_BUS_APBH),
+               .flags  = IORESOURCE_DMA,
+       },
+};
+
+static struct resource ssp2_resources[] = {
+       {
+               .start  = REGS_SSP2_PHYS,
+               .end    = REGS_SSP2_PHYS + REGS_SSP_SIZE,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = IRQ_SSP2_DMA,
+               .end    = IRQ_SSP2_DMA,
+               .flags  = IORESOURCE_IRQ,
+       }, {
+               .start  = STMP3XXX_DMA(2, STMP3XXX_BUS_APBH),
+               .end    = STMP3XXX_DMA(2, STMP3XXX_BUS_APBH),
+               .flags  = IORESOURCE_DMA,
+       },
+};
+
+struct platform_device stmp3xxx_spi1 = {
+       .name   = "stmp3xxx_ssp",
+       .id     = 1,
+       .dev    = {
+               .dma_mask       = &common_dmamask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+       },
+       .resource = ssp1_resources,
+       .num_resources = ARRAY_SIZE(ssp1_resources),
+};
+
+struct platform_device stmp3xxx_spi2 = {
+       .name   = "stmp3xxx_ssp",
+       .id     = 2,
+       .dev    = {
+               .dma_mask       = &common_dmamask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+       },
+       .resource = ssp2_resources,
+       .num_resources = ARRAY_SIZE(ssp2_resources),
+};
+
+static struct resource fb_resource[] = {
+       {
+               .flags  = IORESOURCE_IRQ,
+               .start  = IRQ_LCDIF_DMA,
+               .end    = IRQ_LCDIF_DMA,
+       }, {
+               .flags  = IORESOURCE_IRQ,
+               .start  = IRQ_LCDIF_ERROR,
+               .end    = IRQ_LCDIF_ERROR,
+       }, {
+               .flags  = IORESOURCE_MEM,
+               .start  = REGS_LCDIF_PHYS,
+               .end    = REGS_LCDIF_PHYS + REGS_LCDIF_SIZE,
+       },
+};
+
+struct platform_device stmp3xxx_framebuffer = {
+       .name           = "stmp3xxx-fb",
+       .id             = -1,
+       .dev            = {
+               .dma_mask               = &common_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+       .num_resources  = ARRAY_SIZE(fb_resource),
+       .resource       = fb_resource,
+};
+
+#define CMDLINE_DEVICE_CHOOSE(name, dev1, dev2)                        \
+       static char *cmdline_device_##name;                     \
+       static int cmdline_device_##name##_setup(char *dev)     \
+       {                                                       \
+               cmdline_device_##name = dev + 1;                \
+               return 0;                                       \
+       }                                                       \
+       __setup(#name, cmdline_device_##name##_setup);          \
+       int stmp3xxx_##name##_device_register(void)             \
+       {                                                       \
+               struct platform_device *d = NULL;               \
+               if (!cmdline_device_##name ||                   \
+                       !strcmp(cmdline_device_##name, #dev1))  \
+                               d = &stmp3xxx_##dev1;           \
+               else if (!strcmp(cmdline_device_##name, #dev2)) \
+                               d = &stmp3xxx_##dev2;           \
+               else                                            \
+                       printk(KERN_ERR"Unknown %s assignment '%s'.\n", \
+                               #name, cmdline_device_##name);  \
+               return d ? platform_device_register(d) : -ENOENT;       \
+       }
+
+CMDLINE_DEVICE_CHOOSE(ssp1, mmc, spi1)
+CMDLINE_DEVICE_CHOOSE(ssp2, gpmi, spi2)
+
+struct platform_device stmp3xxx_backlight = {
+       .name           = "stmp3xxx-bl",
+       .id             = -1,
+};
+
+struct platform_device stmp3xxx_rotdec = {
+       .name   = "stmp3xxx-rotdec",
+       .id     = -1,
+};
+
+struct platform_device stmp3xxx_persistent = {
+       .name                   = "stmp3xxx-persistent",
+       .id                     = -1,
+};
+
+struct platform_device stmp3xxx_dcp_bootstream = {
+       .name                   = "stmp3xxx-dcpboot",
+       .id                     = -1,
+       .dev    = {
+               .dma_mask       = &common_dmamask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+       },
+};
+
+static struct resource dcp_resources[] = {
+       {
+               .start = IRQ_DCP_VMI,
+               .end = IRQ_DCP_VMI,
+               .flags = IORESOURCE_IRQ,
+       }, {
+               .start = IRQ_DCP,
+               .end = IRQ_DCP,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device stmp3xxx_dcp = {
+       .name                   = "stmp3xxx-dcp",
+       .id                     = -1,
+       .resource               = dcp_resources,
+       .num_resources          = ARRAY_SIZE(dcp_resources),
+       .dev    = {
+               .dma_mask       = &common_dmamask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+       },
+};
+
+static struct resource battery_resource[] = {
+       {
+               .flags  = IORESOURCE_IRQ,
+               .start  = IRQ_VDD5V,
+               .end    = IRQ_VDD5V,
+       },
+};
+
+struct platform_device stmp3xxx_battery = {
+       .name   = "stmp3xxx-battery",
+       .resource = battery_resource,
+       .num_resources = ARRAY_SIZE(battery_resource),
+};
diff --git a/arch/arm/plat-stmp3xxx/dma.c b/arch/arm/plat-stmp3xxx/dma.c
new file mode 100644 (file)
index 0000000..d2f4977
--- /dev/null
@@ -0,0 +1,463 @@
+/*
+ * DMA helper routines for Freescale STMP37XX/STMP378X
+ *
+ * Author: dmitry pervushin <dpervushin@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/dmapool.h>
+#include <linux/sysdev.h>
+#include <linux/cpufreq.h>
+
+#include <asm/page.h>
+
+#include <mach/platform.h>
+#include <mach/dma.h>
+#include <mach/regs-apbx.h>
+#include <mach/regs-apbh.h>
+
+static const size_t pool_item_size = sizeof(struct stmp3xxx_dma_command);
+static const size_t pool_alignment = 8;
+static struct stmp3xxx_dma_user {
+       void *pool;
+       int inuse;
+       const char *name;
+} channels[MAX_DMA_CHANNELS];
+
+#define IS_VALID_CHANNEL(ch) ((ch) >= 0 && (ch) < MAX_DMA_CHANNELS)
+#define IS_USED(ch) (channels[ch].inuse)
+
+int stmp3xxx_dma_request(int ch, struct device *dev, const char *name)
+{
+       struct stmp3xxx_dma_user *user;
+       int err = 0;
+
+       user = channels + ch;
+       if (!IS_VALID_CHANNEL(ch)) {
+               err = -ENODEV;
+               goto out;
+       }
+       if (IS_USED(ch)) {
+               err = -EBUSY;
+               goto out;
+       }
+       /* Create a pool to allocate dma commands from */
+       user->pool = dma_pool_create(name, dev, pool_item_size,
+                                    pool_alignment, PAGE_SIZE);
+       if (user->pool == NULL) {
+               err = -ENOMEM;
+               goto out;
+       }
+       user->name = name;
+       user->inuse++;
+out:
+       return err;
+}
+EXPORT_SYMBOL(stmp3xxx_dma_request);
+
+int stmp3xxx_dma_release(int ch)
+{
+       struct stmp3xxx_dma_user *user = channels + ch;
+       int err = 0;
+
+       if (!IS_VALID_CHANNEL(ch)) {
+               err = -ENODEV;
+               goto out;
+       }
+       if (!IS_USED(ch)) {
+               err = -EBUSY;
+               goto out;
+       }
+       BUG_ON(user->pool == NULL);
+       dma_pool_destroy(user->pool);
+       user->inuse--;
+out:
+       return err;
+}
+EXPORT_SYMBOL(stmp3xxx_dma_release);
+
+int stmp3xxx_dma_read_semaphore(int channel)
+{
+       int sem = -1;
+
+       switch (STMP3XXX_DMA_BUS(channel)) {
+       case STMP3XXX_BUS_APBH:
+               sem = __raw_readl(REGS_APBH_BASE + HW_APBH_CHn_SEMA +
+                               STMP3XXX_DMA_CHANNEL(channel) * 0x70);
+               sem &= BM_APBH_CHn_SEMA_PHORE;
+               sem >>= BP_APBH_CHn_SEMA_PHORE;
+               break;
+
+       case STMP3XXX_BUS_APBX:
+               sem = __raw_readl(REGS_APBX_BASE + HW_APBX_CHn_SEMA +
+                               STMP3XXX_DMA_CHANNEL(channel) * 0x70);
+               sem &= BM_APBX_CHn_SEMA_PHORE;
+               sem >>= BP_APBX_CHn_SEMA_PHORE;
+               break;
+       default:
+               BUG();
+       }
+       return sem;
+}
+EXPORT_SYMBOL(stmp3xxx_dma_read_semaphore);
+
+int stmp3xxx_dma_allocate_command(int channel,
+                                 struct stmp3xxx_dma_descriptor *descriptor)
+{
+       struct stmp3xxx_dma_user *user = channels + channel;
+       int err = 0;
+
+       if (!IS_VALID_CHANNEL(channel)) {
+               err = -ENODEV;
+               goto out;
+       }
+       if (!IS_USED(channel)) {
+               err = -EBUSY;
+               goto out;
+       }
+       if (descriptor == NULL) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       /* Allocate memory for a command from the buffer */
+       descriptor->command =
+           dma_pool_alloc(user->pool, GFP_KERNEL, &descriptor->handle);
+
+       /* Check it worked */
+       if (!descriptor->command) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       memset(descriptor->command, 0, pool_item_size);
+out:
+       WARN_ON(err);
+       return err;
+}
+EXPORT_SYMBOL(stmp3xxx_dma_allocate_command);
+
+int stmp3xxx_dma_free_command(int channel,
+                             struct stmp3xxx_dma_descriptor *descriptor)
+{
+       int err = 0;
+
+       if (!IS_VALID_CHANNEL(channel)) {
+               err = -ENODEV;
+               goto out;
+       }
+       if (!IS_USED(channel)) {
+               err = -EBUSY;
+               goto out;
+       }
+
+       /* Return the command memory to the pool */
+       dma_pool_free(channels[channel].pool, descriptor->command,
+                     descriptor->handle);
+
+       /* Initialise descriptor so we're not tempted to use it */
+       descriptor->command = NULL;
+       descriptor->handle = 0;
+       descriptor->virtual_buf_ptr = NULL;
+       descriptor->next_descr = NULL;
+
+       WARN_ON(err);
+out:
+       return err;
+}
+EXPORT_SYMBOL(stmp3xxx_dma_free_command);
+
+void stmp3xxx_dma_go(int channel,
+                    struct stmp3xxx_dma_descriptor *head, u32 semaphore)
+{
+       int ch = STMP3XXX_DMA_CHANNEL(channel);
+       void __iomem *c, *s;
+
+       switch (STMP3XXX_DMA_BUS(channel)) {
+       case STMP3XXX_BUS_APBH:
+               c = REGS_APBH_BASE + HW_APBH_CHn_NXTCMDAR + 0x70 * ch;
+               s = REGS_APBH_BASE + HW_APBH_CHn_SEMA + 0x70 * ch;
+               break;
+
+       case STMP3XXX_BUS_APBX:
+               c = REGS_APBX_BASE + HW_APBX_CHn_NXTCMDAR + 0x70 * ch;
+               s = REGS_APBX_BASE + HW_APBX_CHn_SEMA + 0x70 * ch;
+               break;
+
+       default:
+               return;
+       }
+
+       /* Set next command */
+       __raw_writel(head->handle, c);
+       /* Set counting semaphore (kicks off transfer). Assumes
+          peripheral has been set up correctly */
+       __raw_writel(semaphore, s);
+}
+EXPORT_SYMBOL(stmp3xxx_dma_go);
+
+int stmp3xxx_dma_running(int channel)
+{
+       switch (STMP3XXX_DMA_BUS(channel)) {
+       case STMP3XXX_BUS_APBH:
+               return (__raw_readl(REGS_APBH_BASE + HW_APBH_CHn_SEMA +
+                       0x70 * STMP3XXX_DMA_CHANNEL(channel))) &
+                           BM_APBH_CHn_SEMA_PHORE;
+
+       case STMP3XXX_BUS_APBX:
+               return (__raw_readl(REGS_APBX_BASE + HW_APBX_CHn_SEMA +
+                       0x70 * STMP3XXX_DMA_CHANNEL(channel))) &
+                           BM_APBX_CHn_SEMA_PHORE;
+       default:
+               BUG();
+               return 0;
+       }
+}
+EXPORT_SYMBOL(stmp3xxx_dma_running);
+
+/*
+ * Circular dma chain management
+ */
+void stmp3xxx_dma_free_chain(struct stmp37xx_circ_dma_chain *chain)
+{
+       int i;
+
+       for (i = 0; i < chain->total_count; i++)
+               stmp3xxx_dma_free_command(
+                       STMP3XXX_DMA(chain->channel, chain->bus),
+                       &chain->chain[i]);
+}
+EXPORT_SYMBOL(stmp3xxx_dma_free_chain);
+
+int stmp3xxx_dma_make_chain(int ch, struct stmp37xx_circ_dma_chain *chain,
+                           struct stmp3xxx_dma_descriptor descriptors[],
+                           unsigned items)
+{
+       int i;
+       int err = 0;
+
+       if (items == 0)
+               return err;
+
+       for (i = 0; i < items; i++) {
+               err = stmp3xxx_dma_allocate_command(ch, &descriptors[i]);
+               if (err) {
+                       WARN_ON(err);
+                       /*
+                        * Couldn't allocate the whole chain.
+                        * deallocate what has been allocated
+                        */
+                       if (i) {
+                               do {
+                                       stmp3xxx_dma_free_command(ch,
+                                                                 &descriptors
+                                                                 [i]);
+                               } while (i-- >= 0);
+                       }
+                       return err;
+               }
+
+               /* link them! */
+               if (i > 0) {
+                       descriptors[i - 1].next_descr = &descriptors[i];
+                       descriptors[i - 1].command->next =
+                                               descriptors[i].handle;
+               }
+       }
+
+       /* make list circular */
+       descriptors[items - 1].next_descr = &descriptors[0];
+       descriptors[items - 1].command->next = descriptors[0].handle;
+
+       chain->total_count = items;
+       chain->chain = descriptors;
+       chain->free_index = 0;
+       chain->active_index = 0;
+       chain->cooked_index = 0;
+       chain->free_count = items;
+       chain->active_count = 0;
+       chain->cooked_count = 0;
+       chain->bus = STMP3XXX_DMA_BUS(ch);
+       chain->channel = STMP3XXX_DMA_CHANNEL(ch);
+       return err;
+}
+EXPORT_SYMBOL(stmp3xxx_dma_make_chain);
+
+void stmp37xx_circ_clear_chain(struct stmp37xx_circ_dma_chain *chain)
+{
+       BUG_ON(stmp3xxx_dma_running(STMP3XXX_DMA(chain->channel, chain->bus)));
+       chain->free_index = 0;
+       chain->active_index = 0;
+       chain->cooked_index = 0;
+       chain->free_count = chain->total_count;
+       chain->active_count = 0;
+       chain->cooked_count = 0;
+}
+EXPORT_SYMBOL(stmp37xx_circ_clear_chain);
+
+void stmp37xx_circ_advance_free(struct stmp37xx_circ_dma_chain *chain,
+               unsigned count)
+{
+       BUG_ON(chain->cooked_count < count);
+
+       chain->cooked_count -= count;
+       chain->cooked_index += count;
+       chain->cooked_index %= chain->total_count;
+       chain->free_count += count;
+}
+EXPORT_SYMBOL(stmp37xx_circ_advance_free);
+
+void stmp37xx_circ_advance_active(struct stmp37xx_circ_dma_chain *chain,
+               unsigned count)
+{
+       void __iomem *c;
+       u32 mask_clr, mask;
+       BUG_ON(chain->free_count < count);
+
+       chain->free_count -= count;
+       chain->free_index += count;
+       chain->free_index %= chain->total_count;
+       chain->active_count += count;
+
+       switch (chain->bus) {
+       case STMP3XXX_BUS_APBH:
+               c = REGS_APBH_BASE + HW_APBH_CHn_SEMA + 0x70 * chain->channel;
+               mask_clr = BM_APBH_CHn_SEMA_INCREMENT_SEMA;
+               mask = BF(count, APBH_CHn_SEMA_INCREMENT_SEMA);
+               break;
+       case STMP3XXX_BUS_APBX:
+               c = REGS_APBX_BASE + HW_APBX_CHn_SEMA + 0x70 * chain->channel;
+               mask_clr = BM_APBX_CHn_SEMA_INCREMENT_SEMA;
+               mask = BF(count, APBX_CHn_SEMA_INCREMENT_SEMA);
+               break;
+       default:
+               BUG();
+               return;
+       }
+
+       /* Set counting semaphore (kicks off transfer). Assumes
+          peripheral has been set up correctly */
+       stmp3xxx_clearl(mask_clr, c);
+       stmp3xxx_setl(mask, c);
+}
+EXPORT_SYMBOL(stmp37xx_circ_advance_active);
+
+unsigned stmp37xx_circ_advance_cooked(struct stmp37xx_circ_dma_chain *chain)
+{
+       unsigned cooked;
+
+       cooked = chain->active_count -
+         stmp3xxx_dma_read_semaphore(STMP3XXX_DMA(chain->channel, chain->bus));
+
+       chain->active_count -= cooked;
+       chain->active_index += cooked;
+       chain->active_index %= chain->total_count;
+
+       chain->cooked_count += cooked;
+
+       return cooked;
+}
+EXPORT_SYMBOL(stmp37xx_circ_advance_cooked);
+
+void stmp3xxx_dma_set_alt_target(int channel, int function)
+{
+#if defined(CONFIG_ARCH_STMP37XX)
+       unsigned bits = 4;
+#elif defined(CONFIG_ARCH_STMP378X)
+       unsigned bits = 2;
+#else
+#error wrong arch
+#endif
+       int shift = STMP3XXX_DMA_CHANNEL(channel) * bits;
+       unsigned mask = (1<<bits) - 1;
+       void __iomem *c;
+
+       BUG_ON(function < 0 || function >= (1<<bits));
+       pr_debug("%s: channel = %d, using mask %x, "
+                "shift = %d\n", __func__, channel, mask, shift);
+
+       switch (STMP3XXX_DMA_BUS(channel)) {
+       case STMP3XXX_BUS_APBH:
+               c = REGS_APBH_BASE + HW_APBH_DEVSEL;
+               break;
+       case STMP3XXX_BUS_APBX:
+               c = REGS_APBX_BASE + HW_APBX_DEVSEL;
+               break;
+       default:
+               BUG();
+       }
+       stmp3xxx_clearl(mask << shift, c);
+       stmp3xxx_setl(mask << shift, c);
+}
+EXPORT_SYMBOL(stmp3xxx_dma_set_alt_target);
+
+void stmp3xxx_dma_suspend(void)
+{
+       stmp3xxx_setl(BM_APBH_CTRL0_CLKGATE, REGS_APBH_BASE + HW_APBH_CTRL0);
+       stmp3xxx_setl(BM_APBX_CTRL0_CLKGATE, REGS_APBX_BASE + HW_APBX_CTRL0);
+}
+
+void stmp3xxx_dma_resume(void)
+{
+       stmp3xxx_clearl(BM_APBH_CTRL0_CLKGATE | BM_APBH_CTRL0_SFTRST,
+                       REGS_APBH_BASE + HW_APBH_CTRL0);
+       stmp3xxx_clearl(BM_APBX_CTRL0_CLKGATE | BM_APBX_CTRL0_SFTRST,
+                       REGS_APBX_BASE + HW_APBX_CTRL0);
+}
+
+#ifdef CONFIG_CPU_FREQ
+
+struct dma_notifier_block {
+       struct notifier_block nb;
+       void *data;
+};
+
+static int dma_cpufreq_notifier(struct notifier_block *self,
+                               unsigned long phase, void *p)
+{
+       switch (phase) {
+       case CPUFREQ_POSTCHANGE:
+               stmp3xxx_dma_resume();
+               break;
+
+       case CPUFREQ_PRECHANGE:
+               stmp3xxx_dma_suspend();
+               break;
+
+       default:
+               break;
+       }
+
+       return NOTIFY_DONE;
+}
+
+static struct dma_notifier_block dma_cpufreq_nb = {
+       .nb = {
+               .notifier_call = dma_cpufreq_notifier,
+       },
+};
+#endif /* CONFIG_CPU_FREQ */
+
+void __init stmp3xxx_dma_init(void)
+{
+       stmp3xxx_clearl(BM_APBH_CTRL0_CLKGATE | BM_APBH_CTRL0_SFTRST,
+                       REGS_APBH_BASE + HW_APBH_CTRL0);
+       stmp3xxx_clearl(BM_APBX_CTRL0_CLKGATE | BM_APBX_CTRL0_SFTRST,
+                       REGS_APBX_BASE + HW_APBX_CTRL0);
+#ifdef CONFIG_CPU_FREQ
+       cpufreq_register_notifier(&dma_cpufreq_nb.nb,
+                               CPUFREQ_TRANSITION_NOTIFIER);
+#endif /* CONFIG_CPU_FREQ */
+}
diff --git a/arch/arm/plat-stmp3xxx/include/mach/clkdev.h b/arch/arm/plat-stmp3xxx/include/mach/clkdev.h
new file mode 100644 (file)
index 0000000..f9c3977
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#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/plat-stmp3xxx/include/mach/cputype.h b/arch/arm/plat-stmp3xxx/include/mach/cputype.h
new file mode 100644 (file)
index 0000000..b4e205b
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Freescale STMP37XX/STMP378X CPU type detection
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __ASM_PLAT_CPU_H
+#define __ASM_PLAT_CPU_H
+
+#ifdef CONFIG_ARCH_STMP37XX
+#define cpu_is_stmp37xx()      (1)
+#else
+#define cpu_is_stmp37xx()      (0)
+#endif
+
+#ifdef CONFIG_ARCH_STMP378X
+#define cpu_is_stmp378x()      (1)
+#else
+#define cpu_is_stmp378x()      (0)
+#endif
+
+#endif /* __ASM_PLAT_CPU_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/debug-macro.S b/arch/arm/plat-stmp3xxx/include/mach/debug-macro.S
new file mode 100644 (file)
index 0000000..fb3b969
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Debugging macro include header
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+               .macro  addruart,rx
+               mrc     p15, 0, \rx, c1, c0
+               tst     \rx, #1                 @ MMU enabled?
+               moveq   \rx, #0x80000000        @ physical base address
+               addeq   \rx, \rx, #0x00070000
+               movne   \rx, #0xf0000000        @ virtual base
+               addne   \rx, \rx, #0x00070000
+               .endm
+
+               .macro  senduart,rd,rx
+               strb    \rd, [\rx, #0]          @ data register at 0
+               .endm
+
+               .macro  waituart,rd,rx
+1001:          ldr     \rd, [\rx, #0x18]       @ UARTFLG
+               tst     \rd, #1 << 5            @ UARTFLGUTXFF - 1 when full
+               bne     1001b
+               .endm
+
+               .macro  busyuart,rd,rx
+1001:          ldr     \rd, [\rx, #0x18]       @ UARTFLG
+               tst     \rd, #1 << 3            @ UARTFLGUBUSY - 1 when busy
+               bne     1001b
+               .endm
diff --git a/arch/arm/plat-stmp3xxx/include/mach/dma.h b/arch/arm/plat-stmp3xxx/include/mach/dma.h
new file mode 100644 (file)
index 0000000..7c58557
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Freescale STMP37XX/STMP378X DMA helper interface
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __ASM_PLAT_STMP3XXX_DMA_H
+#define __ASM_PLAT_STMP3XXX_DMA_H
+
+#include <linux/platform_device.h>
+#include <linux/dmapool.h>
+
+#if !defined(MAX_PIO_WORDS)
+#define MAX_PIO_WORDS   (15)
+#endif
+
+#define STMP3XXX_BUS_APBH              0
+#define STMP3XXX_BUS_APBX              1
+#define STMP3XXX_DMA_MAX_CHANNEL       16
+#define STMP3XXX_DMA_BUS(dma)          ((dma) / 16)
+#define STMP3XXX_DMA_CHANNEL(dma)      ((dma) % 16)
+#define STMP3XXX_DMA(channel, bus)     ((bus) * 16 + (channel))
+#define MAX_DMA_ADDRESS                        0xffffffff
+#define MAX_DMA_CHANNELS               32
+
+struct stmp3xxx_dma_command {
+       u32 next;
+       u32 cmd;
+       union {
+               u32 buf_ptr;
+               u32 alternate;
+       };
+       u32 pio_words[MAX_PIO_WORDS];
+};
+
+struct stmp3xxx_dma_descriptor {
+       struct stmp3xxx_dma_command *command;
+       dma_addr_t handle;
+
+       /* The virtual address of the buffer pointer */
+       void *virtual_buf_ptr;
+       /* The next descriptor in a the DMA chain (optional) */
+       struct stmp3xxx_dma_descriptor *next_descr;
+};
+
+struct stmp37xx_circ_dma_chain {
+       unsigned total_count;
+       struct stmp3xxx_dma_descriptor *chain;
+
+       unsigned free_index;
+       unsigned free_count;
+       unsigned active_index;
+       unsigned active_count;
+       unsigned cooked_index;
+       unsigned cooked_count;
+
+       int bus;
+       unsigned channel;
+};
+
+static inline struct stmp3xxx_dma_descriptor
+    *stmp3xxx_dma_circ_get_free_head(struct stmp37xx_circ_dma_chain *chain)
+{
+       return &(chain->chain[chain->free_index]);
+}
+
+static inline struct stmp3xxx_dma_descriptor
+    *stmp3xxx_dma_circ_get_cooked_head(struct stmp37xx_circ_dma_chain *chain)
+{
+       return &(chain->chain[chain->cooked_index]);
+}
+
+int stmp3xxx_dma_request(int ch, struct device *dev, const char *name);
+int stmp3xxx_dma_release(int ch);
+int stmp3xxx_dma_allocate_command(int ch,
+                                 struct stmp3xxx_dma_descriptor *descriptor);
+int stmp3xxx_dma_free_command(int ch,
+                             struct stmp3xxx_dma_descriptor *descriptor);
+void stmp3xxx_dma_continue(int channel, u32 semaphore);
+void stmp3xxx_dma_go(int ch, struct stmp3xxx_dma_descriptor *head,
+                    u32 semaphore);
+int stmp3xxx_dma_running(int ch);
+int stmp3xxx_dma_make_chain(int ch, struct stmp37xx_circ_dma_chain *chain,
+                           struct stmp3xxx_dma_descriptor descriptors[],
+                           unsigned items);
+void stmp3xxx_dma_free_chain(struct stmp37xx_circ_dma_chain *chain);
+void stmp37xx_circ_clear_chain(struct stmp37xx_circ_dma_chain *chain);
+void stmp37xx_circ_advance_free(struct stmp37xx_circ_dma_chain *chain,
+               unsigned count);
+void stmp37xx_circ_advance_active(struct stmp37xx_circ_dma_chain *chain,
+               unsigned count);
+unsigned stmp37xx_circ_advance_cooked(struct stmp37xx_circ_dma_chain *chain);
+int stmp3xxx_dma_read_semaphore(int ch);
+void stmp3xxx_dma_init(void);
+void stmp3xxx_dma_set_alt_target(int ch, int target);
+void stmp3xxx_dma_suspend(void);
+void stmp3xxx_dma_resume(void);
+
+/*
+ * STMP37xx and STMP378x have different DMA control
+ * registers layout
+ */
+
+void stmp3xxx_arch_dma_freeze(int ch);
+void stmp3xxx_arch_dma_unfreeze(int ch);
+void stmp3xxx_arch_dma_reset_channel(int ch);
+void stmp3xxx_arch_dma_enable_interrupt(int ch);
+void stmp3xxx_arch_dma_clear_interrupt(int ch);
+int stmp3xxx_arch_dma_is_interrupt(int ch);
+
+static inline void stmp3xxx_dma_reset_channel(int ch)
+{
+       stmp3xxx_arch_dma_reset_channel(ch);
+}
+
+
+static inline void stmp3xxx_dma_freeze(int ch)
+{
+       stmp3xxx_arch_dma_freeze(ch);
+}
+
+static inline void stmp3xxx_dma_unfreeze(int ch)
+{
+       stmp3xxx_arch_dma_unfreeze(ch);
+}
+
+static inline void stmp3xxx_dma_enable_interrupt(int ch)
+{
+       stmp3xxx_arch_dma_enable_interrupt(ch);
+}
+
+static inline void stmp3xxx_dma_clear_interrupt(int ch)
+{
+       stmp3xxx_arch_dma_clear_interrupt(ch);
+}
+
+static inline int stmp3xxx_dma_is_interrupt(int ch)
+{
+       return stmp3xxx_arch_dma_is_interrupt(ch);
+}
+
+#endif /* __ASM_PLAT_STMP3XXX_DMA_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/gpio.h b/arch/arm/plat-stmp3xxx/include/mach/gpio.h
new file mode 100644 (file)
index 0000000..a8b5792
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Freescale STMP37XX/STMP378X GPIO interface
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __ASM_PLAT_GPIO_H
+#define __ASM_PLAT_GPIO_H
+
+#define ARCH_NR_GPIOS  (32 * 3)
+#define gpio_to_irq(gpio) __gpio_to_irq(gpio)
+#define gpio_get_value(gpio) __gpio_get_value(gpio)
+#define gpio_set_value(gpio, value) __gpio_set_value(gpio, value)
+
+#include <asm-generic/gpio.h>
+
+#endif /* __ASM_PLAT_GPIO_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/gpmi.h b/arch/arm/plat-stmp3xxx/include/mach/gpmi.h
new file mode 100644 (file)
index 0000000..e166432
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef __MACH_GPMI_H
+
+#include <linux/mtd/partitions.h>
+#include <mach/regs-gpmi.h>
+
+struct gpmi_platform_data {
+       void *pins;
+       int nr_parts;
+       struct mtd_partition *parts;
+       const char *part_types[];
+};
+#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/hardware.h b/arch/arm/plat-stmp3xxx/include/mach/hardware.h
new file mode 100644 (file)
index 0000000..47b8978
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * This file contains the hardware definitions of the Freescale STMP3XXX
+ *
+ * Copyright (C) 2005 Sigmatel Inc
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+/*
+ * Where in virtual memory the IO devices (timers, system controllers
+ * and so on)
+ */
+#define IO_BASE                        0xF0000000                 /* VA of IO  */
+#define IO_SIZE                        0x00100000                 /* How much? */
+#define IO_START               0x80000000                 /* PA of IO  */
+
+/* macro to get at IO space when running virtually */
+#define IO_ADDRESS(x) (((x) & 0x000fffff) | IO_BASE)
+
+#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/io.h b/arch/arm/plat-stmp3xxx/include/mach/io.h
new file mode 100644 (file)
index 0000000..d08b1b7
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2005 Sigmatel Inc
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+#define __io(a)        __typesafe_io(a)
+#define __mem_pci(a)   (a)
+#define __mem_isa(a)   (a)
+
+#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/memory.h b/arch/arm/plat-stmp3xxx/include/mach/memory.h
new file mode 100644 (file)
index 0000000..7b875a0
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+/*
+ * Physical DRAM offset.
+ */
+#define PHYS_OFFSET    UL(0x40000000)
+
+#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/mmc.h b/arch/arm/plat-stmp3xxx/include/mach/mmc.h
new file mode 100644 (file)
index 0000000..ba81e15
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef _MACH_MMC_H
+#define _MACH_MMC_H
+
+#include <mach/regs-ssp.h>
+
+struct stmp3xxxmmc_platform_data {
+       int (*get_wp)(void);
+       unsigned long (*setclock)(void __iomem *base, unsigned long);
+       void (*cmd_pullup)(int);
+       int  (*hw_init)(void);
+       void (*hw_release)(void);
+};
+
+#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/pinmux.h b/arch/arm/plat-stmp3xxx/include/mach/pinmux.h
new file mode 100644 (file)
index 0000000..cc5af82
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Freescale STMP37XX/STMP378X Pin Multiplexing
+ *
+ * Author: Vladislav Buzov <vbuzov@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __PINMUX_H
+#define __PINMUX_H
+
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/gpio.h>
+#include <asm-generic/gpio.h>
+
+/* Pin definitions */
+#include "pins.h"
+#include <mach/pins.h>
+
+/*
+ * Each pin may be routed up to four different HW interfaces
+ * including GPIO
+ */
+enum pin_fun {
+       PIN_FUN1 = 0,
+       PIN_FUN2,
+       PIN_FUN3,
+       PIN_GPIO,
+};
+
+/*
+ * Each pin may have different output drive strength in range from
+ * 4mA to 20mA. The most common case is 4, 8 and 12 mA strengths.
+ */
+enum pin_strength {
+       PIN_4MA = 0,
+       PIN_8MA,
+       PIN_12MA,
+       PIN_16MA,
+       PIN_20MA,
+};
+
+/*
+ * Each pin can be programmed for 1.8V or 3.3V
+ */
+enum pin_voltage {
+       PIN_1_8V = 0,
+       PIN_3_3V,
+};
+
+/*
+ * Structure to define a group of pins and their parameters
+ */
+struct pin_desc {
+       unsigned id;
+       enum pin_fun fun;
+       enum pin_strength strength;
+       enum pin_voltage voltage;
+       unsigned pullup:1;
+};
+
+struct pin_group {
+       struct pin_desc *pins;
+       int nr_pins;
+};
+
+/* Set pin drive strength */
+void stmp3xxx_pin_strength(unsigned id, enum pin_strength strength,
+                          const char *label);
+
+/* Set pin voltage */
+void stmp3xxx_pin_voltage(unsigned id, enum pin_voltage voltage,
+                          const char *label);
+
+/* Enable pull-up resistor for a pin */
+void stmp3xxx_pin_pullup(unsigned id, int enable, const char *label);
+
+/*
+ * Request a pin ownership, only one module (identified by @label)
+ * may own a pin.
+ */
+int stmp3xxx_request_pin(unsigned id, enum pin_fun fun, const char *label);
+
+/* Release pin */
+void stmp3xxx_release_pin(unsigned id, const char *label);
+
+void stmp3xxx_set_pin_type(unsigned id, enum pin_fun fun);
+
+/*
+ * Each bank is associated with a number of registers to control
+ * pin function, drive strength, voltage and pull-up reigster. The
+ * number of registers of a given type depends on the number of bits
+ * describin particular pin.
+ */
+#define HW_MUXSEL_NUM          2       /* registers per bank */
+#define HW_MUXSEL_PIN_LEN      2       /* bits per pin */
+#define HW_MUXSEL_PIN_NUM      16      /* pins per register */
+#define HW_MUXSEL_PINFUN_MASK  0x3     /* pin function mask */
+#define HW_MUXSEL_PINFUN_NUM   4       /* four options for a pin */
+
+#define HW_DRIVE_NUM           4       /* registers per bank */
+#define HW_DRIVE_PIN_LEN       4       /* bits per pin */
+#define HW_DRIVE_PIN_NUM       8       /* pins per register */
+#define HW_DRIVE_PINDRV_MASK   0x3     /* pin strength mask - 2 bits */
+#define HW_DRIVE_PINDRV_NUM    5       /* five possible strength values */
+#define HW_DRIVE_PINV_MASK     0x4     /* pin voltage mask - 1 bit */
+
+
+struct stmp3xxx_pinmux_bank {
+       struct gpio_chip chip;
+
+       /* Pins allocation map */
+       unsigned long pin_map;
+
+       /* Pin owner names */
+       const char *pin_labels[32];
+
+       /* Bank registers */
+       void __iomem *hw_muxsel[HW_MUXSEL_NUM];
+       void __iomem *hw_drive[HW_DRIVE_NUM];
+       void __iomem *hw_pull;
+
+       void __iomem *pin2irq,
+               *irqlevel,
+               *irqpolarity,
+               *irqen,
+               *irqstat;
+
+       /* HW MUXSEL register function bit values */
+       u8 functions[HW_MUXSEL_PINFUN_NUM];
+
+       /*
+        * HW DRIVE register strength bit values:
+        * 0xff - requested strength is not supported for this bank
+        */
+       u8 strengths[HW_DRIVE_PINDRV_NUM];
+
+       /* GPIO things */
+       void __iomem *hw_gpio_in,
+                    *hw_gpio_out,
+                    *hw_gpio_doe;
+       int irq, virq;
+};
+
+int __init stmp3xxx_pinmux_init(int virtual_irq_start);
+
+#endif /* __PINMUX_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/pins.h b/arch/arm/plat-stmp3xxx/include/mach/pins.h
new file mode 100644 (file)
index 0000000..c573318
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Freescale STMP37XX/STMP378X Pin multiplexing interface definitions
+ *
+ * Author: Vladislav Buzov <vbuzov@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __ASM_PLAT_PINS_H
+#define __ASM_PLAT_PINS_H
+
+#define STMP3XXX_PINID(bank, pin)      (bank * 32 + pin)
+#define STMP3XXX_PINID_TO_BANK(pinid)  (pinid / 32)
+#define STMP3XXX_PINID_TO_PINNUM(pinid)        (pinid % 32)
+
+/*
+ * Special invalid pin identificator to show a pin doesn't exist
+ */
+#define PINID_NO_PIN   STMP3XXX_PINID(0xFF, 0xFF)
+
+#endif /* __ASM_PLAT_PINS_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/platform.h b/arch/arm/plat-stmp3xxx/include/mach/platform.h
new file mode 100644 (file)
index 0000000..7007dda
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __ASM_PLAT_PLATFORM_H
+#define __ASM_PLAT_PLATFORM_H
+
+#ifndef __ASSEMBLER__
+#include <linux/io.h>
+#endif
+#include <asm/sizes.h>
+
+/* Virtual address where registers are mapped */
+#define STMP3XXX_REGS_PHBASE   0x80000000
+#ifdef __ASSEMBLER__
+#define STMP3XXX_REGS_BASE     0xF0000000
+#else
+#define STMP3XXX_REGS_BASE     (void __iomem *)0xF0000000
+#endif
+#define STMP3XXX_REGS_SIZE     SZ_1M
+
+/* Virtual address where OCRAM is mapped */
+#define STMP3XXX_OCRAM_PHBASE  0x00000000
+#ifdef __ASSEMBLER__
+#define STMP3XXX_OCRAM_BASE    0xf1000000
+#else
+#define STMP3XXX_OCRAM_BASE    (void __iomem *)0xf1000000
+#endif
+#define STMP3XXX_OCRAM_SIZE    (32 * SZ_1K)
+
+#ifdef CONFIG_ARCH_STMP37XX
+#define IRQ_PRIORITY_REG_RD    HW_ICOLL_PRIORITYn_RD
+#define IRQ_PRIORITY_REG_WR    HW_ICOLL_PRIORITYn_WR
+#endif
+
+#ifdef CONFIG_ARCH_STMP378X
+#define IRQ_PRIORITY_REG_RD    HW_ICOLL_INTERRUPTn_RD
+#define IRQ_PRIORITY_REG_WR    HW_ICOLL_INTERRUPTn_WR
+#endif
+
+#define HW_STMP3XXX_SET                0x04
+#define HW_STMP3XXX_CLR                0x08
+#define HW_STMP3XXX_TOG                0x0c
+
+#ifndef __ASSEMBLER__
+static inline void stmp3xxx_clearl(u32 v, void __iomem *r)
+{
+       __raw_writel(v, r + HW_STMP3XXX_CLR);
+}
+
+static inline void stmp3xxx_setl(u32 v, void __iomem *r)
+{
+       __raw_writel(v, r + HW_STMP3XXX_SET);
+}
+#endif
+
+#define BF(value, field) (((value) << BP_##field) & BM_##field)
+
+#endif /* __ASM_ARCH_PLATFORM_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/stmp3xxx.h b/arch/arm/plat-stmp3xxx/include/mach/stmp3xxx.h
new file mode 100644 (file)
index 0000000..2e300fe
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Freescale STMP37XX/STMP378X core structure and function declarations
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __ASM_PLAT_STMP3XXX_H
+#define __ASM_PLAT_STMP3XXX_H
+
+#include <linux/irq.h>
+
+extern struct sys_timer stmp3xxx_timer;
+
+void stmp3xxx_init_irq(struct irq_chip *chip);
+void stmp3xxx_init(void);
+int stmp3xxx_reset_block(void __iomem *hwreg, int just_enable);
+extern struct platform_device stmp3xxx_dbguart,
+                             stmp3xxx_appuart,
+                             stmp3xxx_watchdog,
+                             stmp3xxx_touchscreen,
+                             stmp3xxx_keyboard,
+                             stmp3xxx_gpmi,
+                             stmp3xxx_mmc,
+                             stmp3xxx_udc,
+                             stmp3xxx_ehci,
+                             stmp3xxx_rtc,
+                             stmp3xxx_spi1,
+                             stmp3xxx_spi2,
+                             stmp3xxx_backlight,
+                             stmp3xxx_rotdec,
+                             stmp3xxx_dcp,
+                             stmp3xxx_dcp_bootstream,
+                             stmp3xxx_persistent,
+                             stmp3xxx_framebuffer,
+                             stmp3xxx_battery;
+int stmp3xxx_ssp1_device_register(void);
+int stmp3xxx_ssp2_device_register(void);
+
+struct pin_group;
+void stmp3xxx_release_pin_group(struct pin_group *pin_group, const char *label);
+int stmp3xxx_request_pin_group(struct pin_group *pin_group, const char *label);
+
+#endif /* __ASM_PLAT_STMP3XXX_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/system.h b/arch/arm/plat-stmp3xxx/include/mach/system.h
new file mode 100644 (file)
index 0000000..28a9888
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2005 Sigmatel Inc
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __ASM_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H
+
+#include <asm/proc-fns.h>
+#include <mach/platform.h>
+#include <mach/regs-clkctrl.h>
+#include <mach/regs-power.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)
+{
+       /* Set BATTCHRG to default value */
+       __raw_writel(0x00010000, REGS_POWER_BASE + HW_POWER_CHARGE);
+
+       /* Set MINPWR to default value   */
+       __raw_writel(0, REGS_POWER_BASE + HW_POWER_MINPWR);
+
+       /* Reset digital side of chip (but not power or RTC) */
+       __raw_writel(BM_CLKCTRL_RESET_DIG,
+                       REGS_CLKCTRL_BASE + HW_CLKCTRL_RESET);
+
+       /* Should not return */
+}
+
+#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/timex.h b/arch/arm/plat-stmp3xxx/include/mach/timex.h
new file mode 100644 (file)
index 0000000..3373985
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 1999 ARM Limited
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ * System time clock is sourced from the 32k clock
+ */
+#define CLOCK_TICK_RATE                (32768)
diff --git a/arch/arm/plat-stmp3xxx/include/mach/uncompress.h b/arch/arm/plat-stmp3xxx/include/mach/uncompress.h
new file mode 100644 (file)
index 0000000..f79f5ee
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __ASM_PLAT_UNCOMPRESS_H
+#define __ASM_PLAT_UNCOMPRESS_H
+
+/*
+ * Register includes are for when the MMU enabled; we need to define our
+ * own stuff here for pre-MMU use
+ */
+#define UARTDBG_BASE           0x80070000
+#define UART(c)                        (((volatile unsigned *)UARTDBG_BASE)[c])
+
+/*
+ * This does not append a newline
+ */
+static void putc(char c)
+{
+       /* Wait for TX fifo empty */
+       while ((UART(6) & (1<<7)) == 0)
+               continue;
+
+       /* Write byte */
+       UART(0) = c;
+
+       /* Wait for last bit to exit the UART */
+       while (UART(6) & (1<<3))
+               continue;
+}
+
+static void flush(void)
+{
+}
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_setup()
+
+#define arch_decomp_wdog()
+
+#endif /* __ASM_PLAT_UNCOMPRESS_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/vmalloc.h b/arch/arm/plat-stmp3xxx/include/mach/vmalloc.h
new file mode 100644 (file)
index 0000000..541b880
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#define VMALLOC_END       (0xF0000000)
diff --git a/arch/arm/plat-stmp3xxx/irq.c b/arch/arm/plat-stmp3xxx/irq.c
new file mode 100644 (file)
index 0000000..20de4e0
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Freescale STMP37XX/STMP378X common interrupt handling code
+ *
+ * Author: Vladislav Buzov <vbuzov@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/sysdev.h>
+
+#include <mach/stmp3xxx.h>
+#include <mach/platform.h>
+#include <mach/regs-icoll.h>
+
+void __init stmp3xxx_init_irq(struct irq_chip *chip)
+{
+       unsigned int i, lv;
+
+       /* Reset the interrupt controller */
+       stmp3xxx_reset_block(REGS_ICOLL_BASE + HW_ICOLL_CTRL, true);
+
+       /* Disable all interrupts initially */
+       for (i = 0; i < NR_REAL_IRQS; i++) {
+               chip->mask(i);
+               set_irq_chip(i, chip);
+               set_irq_handler(i, handle_level_irq);
+               set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+       }
+
+       /* Ensure vector is cleared */
+       for (lv = 0; lv < 4; lv++)
+               __raw_writel(1 << lv, REGS_ICOLL_BASE + HW_ICOLL_LEVELACK);
+       __raw_writel(0, REGS_ICOLL_BASE + HW_ICOLL_VECTOR);
+
+       /* Barrier */
+       (void)__raw_readl(REGS_ICOLL_BASE + HW_ICOLL_STAT);
+}
+
diff --git a/arch/arm/plat-stmp3xxx/pinmux.c b/arch/arm/plat-stmp3xxx/pinmux.c
new file mode 100644 (file)
index 0000000..d412003
--- /dev/null
@@ -0,0 +1,552 @@
+/*
+ * Freescale STMP378X/STMP378X Pin Multiplexing
+ *
+ * Author: Vladislav Buzov <vbuzov@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#define DEBUG
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/sysdev.h>
+#include <linux/string.h>
+#include <linux/bitops.h>
+#include <linux/sysdev.h>
+#include <linux/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+#include <mach/regs-pinctrl.h>
+#include <mach/pins.h>
+#include <mach/pinmux.h>
+
+#define NR_BANKS ARRAY_SIZE(pinmux_banks)
+static struct stmp3xxx_pinmux_bank pinmux_banks[] = {
+       [0] = {
+               .hw_muxsel = {
+                       REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL0,
+                       REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL1,
+               },
+               .hw_drive = {
+                       REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE0,
+                       REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE1,
+                       REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE2,
+                       REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE3,
+               },
+               .hw_pull = REGS_PINCTRL_BASE + HW_PINCTRL_PULL0,
+               .functions = { 0x0, 0x1, 0x2, 0x3 },
+               .strengths = { 0x0, 0x1, 0x2, 0x3, 0xff },
+
+               .hw_gpio_in = REGS_PINCTRL_BASE + HW_PINCTRL_DIN0,
+               .hw_gpio_out = REGS_PINCTRL_BASE + HW_PINCTRL_DOUT0,
+               .hw_gpio_doe = REGS_PINCTRL_BASE + HW_PINCTRL_DOE0,
+               .irq = IRQ_GPIO0,
+
+               .pin2irq = REGS_PINCTRL_BASE + HW_PINCTRL_PIN2IRQ0,
+               .irqstat = REGS_PINCTRL_BASE + HW_PINCTRL_IRQSTAT0,
+               .irqlevel = REGS_PINCTRL_BASE + HW_PINCTRL_IRQLEVEL0,
+               .irqpolarity = REGS_PINCTRL_BASE + HW_PINCTRL_IRQPOL0,
+               .irqen = REGS_PINCTRL_BASE + HW_PINCTRL_IRQEN0,
+       },
+       [1] = {
+               .hw_muxsel = {
+                       REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL2,
+                       REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL3,
+               },
+               .hw_drive = {
+                       REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE4,
+                       REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE5,
+                       REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE6,
+                       REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE7,
+               },
+               .hw_pull = REGS_PINCTRL_BASE + HW_PINCTRL_PULL1,
+               .functions = { 0x0, 0x1, 0x2, 0x3 },
+               .strengths = { 0x0, 0x1, 0x2, 0x3, 0xff },
+
+               .hw_gpio_in = REGS_PINCTRL_BASE + HW_PINCTRL_DIN1,
+               .hw_gpio_out = REGS_PINCTRL_BASE + HW_PINCTRL_DOUT1,
+               .hw_gpio_doe = REGS_PINCTRL_BASE + HW_PINCTRL_DOE1,
+               .irq = IRQ_GPIO1,
+
+               .pin2irq = REGS_PINCTRL_BASE + HW_PINCTRL_PIN2IRQ1,
+               .irqstat = REGS_PINCTRL_BASE + HW_PINCTRL_IRQSTAT1,
+               .irqlevel = REGS_PINCTRL_BASE + HW_PINCTRL_IRQLEVEL1,
+               .irqpolarity = REGS_PINCTRL_BASE + HW_PINCTRL_IRQPOL1,
+               .irqen = REGS_PINCTRL_BASE + HW_PINCTRL_IRQEN1,
+       },
+       [2] = {
+              .hw_muxsel = {
+                       REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL4,
+                       REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL5,
+               },
+               .hw_drive = {
+                       REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE8,
+                       REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE9,
+                       REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE10,
+                       REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE11,
+               },
+               .hw_pull = REGS_PINCTRL_BASE + HW_PINCTRL_PULL2,
+               .functions = { 0x0, 0x1, 0x2, 0x3 },
+               .strengths = { 0x0, 0x1, 0x2, 0x1, 0x2 },
+
+               .hw_gpio_in = REGS_PINCTRL_BASE + HW_PINCTRL_DIN2,
+               .hw_gpio_out = REGS_PINCTRL_BASE + HW_PINCTRL_DOUT2,
+               .hw_gpio_doe = REGS_PINCTRL_BASE + HW_PINCTRL_DOE2,
+               .irq = IRQ_GPIO2,
+
+               .pin2irq = REGS_PINCTRL_BASE + HW_PINCTRL_PIN2IRQ2,
+               .irqstat = REGS_PINCTRL_BASE + HW_PINCTRL_IRQSTAT2,
+               .irqlevel = REGS_PINCTRL_BASE + HW_PINCTRL_IRQLEVEL2,
+               .irqpolarity = REGS_PINCTRL_BASE + HW_PINCTRL_IRQPOL2,
+               .irqen = REGS_PINCTRL_BASE + HW_PINCTRL_IRQEN2,
+       },
+       [3] = {
+              .hw_muxsel = {
+                      REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL6,
+                      REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL7,
+              },
+              .hw_drive = {
+                       REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE12,
+                       REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE13,
+                       REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE14,
+                       NULL,
+              },
+              .hw_pull = REGS_PINCTRL_BASE + HW_PINCTRL_PULL3,
+              .functions = {0x0, 0x1, 0x2, 0x3},
+              .strengths = {0x0, 0x1, 0x2, 0x3, 0xff},
+       },
+};
+
+static inline struct stmp3xxx_pinmux_bank *
+stmp3xxx_pinmux_bank(unsigned id, unsigned *bank, unsigned *pin)
+{
+       unsigned b, p;
+
+       b = STMP3XXX_PINID_TO_BANK(id);
+       p = STMP3XXX_PINID_TO_PINNUM(id);
+       BUG_ON(b >= NR_BANKS);
+       if (bank)
+               *bank = b;
+       if (pin)
+               *pin = p;
+       return &pinmux_banks[b];
+}
+
+/* Check if requested pin is owned by caller */
+static int stmp3xxx_check_pin(unsigned id, const char *label)
+{
+       unsigned pin;
+       struct stmp3xxx_pinmux_bank *pm = stmp3xxx_pinmux_bank(id, NULL, &pin);
+
+       if (!test_bit(pin, &pm->pin_map)) {
+               printk(KERN_WARNING
+                      "%s: Accessing free pin %x, caller %s\n",
+                      __func__, id, label);
+
+               return -EINVAL;
+       }
+
+       if (label && pm->pin_labels[pin] &&
+           strcmp(label, pm->pin_labels[pin])) {
+               printk(KERN_WARNING
+                      "%s: Wrong pin owner %x, caller %s owner %s\n",
+                      __func__, id, label, pm->pin_labels[pin]);
+
+               return -EINVAL;
+       }
+       return 0;
+}
+
+void stmp3xxx_pin_strength(unsigned id, enum pin_strength strength,
+               const char *label)
+{
+       struct stmp3xxx_pinmux_bank *pbank;
+       void __iomem *hwdrive;
+       u32 shift, val;
+       u32 bank, pin;
+
+       pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
+       pr_debug("%s: label %s bank %d pin %d strength %d\n", __func__, label,
+                bank, pin, strength);
+
+       hwdrive = pbank->hw_drive[pin / HW_DRIVE_PIN_NUM];
+       shift = (pin % HW_DRIVE_PIN_NUM) * HW_DRIVE_PIN_LEN;
+       val = pbank->strengths[strength];
+       if (val == 0xff) {
+               printk(KERN_WARNING
+                      "%s: strength is not supported for bank %d, caller %s",
+                      __func__, bank, label);
+               return;
+       }
+
+       if (stmp3xxx_check_pin(id, label))
+               return;
+
+       pr_debug("%s: writing 0x%x to 0x%p register\n", __func__,
+                       val << shift, hwdrive);
+       stmp3xxx_clearl(HW_DRIVE_PINDRV_MASK << shift, hwdrive);
+       stmp3xxx_setl(val << shift, hwdrive);
+}
+
+void stmp3xxx_pin_voltage(unsigned id, enum pin_voltage voltage,
+                         const char *label)
+{
+       struct stmp3xxx_pinmux_bank *pbank;
+       void __iomem *hwdrive;
+       u32 shift;
+       u32 bank, pin;
+
+       pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
+       pr_debug("%s: label %s bank %d pin %d voltage %d\n", __func__, label,
+                bank, pin, voltage);
+
+       hwdrive = pbank->hw_drive[pin / HW_DRIVE_PIN_NUM];
+       shift = (pin % HW_DRIVE_PIN_NUM) * HW_DRIVE_PIN_LEN;
+
+       if (stmp3xxx_check_pin(id, label))
+               return;
+
+       pr_debug("%s: changing 0x%x bit in 0x%p register\n",
+                       __func__, HW_DRIVE_PINV_MASK << shift, hwdrive);
+       if (voltage == PIN_1_8V)
+               stmp3xxx_clearl(HW_DRIVE_PINV_MASK << shift, hwdrive);
+       else
+               stmp3xxx_setl(HW_DRIVE_PINV_MASK << shift, hwdrive);
+}
+
+void stmp3xxx_pin_pullup(unsigned id, int enable, const char *label)
+{
+       struct stmp3xxx_pinmux_bank *pbank;
+       void __iomem *hwpull;
+       u32 bank, pin;
+
+       pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
+       pr_debug("%s: label %s bank %d pin %d enable %d\n", __func__, label,
+                bank, pin, enable);
+
+       hwpull = pbank->hw_pull;
+
+       if (stmp3xxx_check_pin(id, label))
+               return;
+
+       pr_debug("%s: changing 0x%x bit in 0x%p register\n",
+                       __func__, 1 << pin, hwpull);
+       if (enable)
+               stmp3xxx_setl(1 << pin, hwpull);
+       else
+               stmp3xxx_clearl(1 << pin, hwpull);
+}
+
+int stmp3xxx_request_pin(unsigned id, enum pin_fun fun, const char *label)
+{
+       struct stmp3xxx_pinmux_bank *pbank;
+       u32 bank, pin;
+       int ret = 0;
+
+       pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
+       pr_debug("%s: label %s bank %d pin %d fun %d\n", __func__, label,
+                bank, pin, fun);
+
+       if (test_bit(pin, &pbank->pin_map)) {
+               printk(KERN_WARNING
+                      "%s: CONFLICT DETECTED pin %d:%d caller %s owner %s\n",
+                      __func__, bank, pin, label, pbank->pin_labels[pin]);
+               return -EBUSY;
+       }
+
+       set_bit(pin, &pbank->pin_map);
+       pbank->pin_labels[pin] = label;
+
+       stmp3xxx_set_pin_type(id, fun);
+
+       return ret;
+}
+
+void stmp3xxx_set_pin_type(unsigned id, enum pin_fun fun)
+{
+       struct stmp3xxx_pinmux_bank *pbank;
+       void __iomem *hwmux;
+       u32 shift, val;
+       u32 bank, pin;
+
+       pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
+
+       hwmux = pbank->hw_muxsel[pin / HW_MUXSEL_PIN_NUM];
+       shift = (pin % HW_MUXSEL_PIN_NUM) * HW_MUXSEL_PIN_LEN;
+
+       val = pbank->functions[fun];
+       shift = (pin % HW_MUXSEL_PIN_NUM) * HW_MUXSEL_PIN_LEN;
+       pr_debug("%s: writing 0x%x to 0x%p register\n",
+                       __func__, val << shift, hwmux);
+       stmp3xxx_clearl(HW_MUXSEL_PINFUN_MASK << shift, hwmux);
+       stmp3xxx_setl(val << shift, hwmux);
+}
+
+void stmp3xxx_release_pin(unsigned id, const char *label)
+{
+       struct stmp3xxx_pinmux_bank *pbank;
+       u32 bank, pin;
+
+       pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
+       pr_debug("%s: label %s bank %d pin %d\n", __func__, label, bank, pin);
+
+       if (stmp3xxx_check_pin(id, label))
+               return;
+
+       clear_bit(pin, &pbank->pin_map);
+       pbank->pin_labels[pin] = NULL;
+}
+
+int stmp3xxx_request_pin_group(struct pin_group *pin_group, const char *label)
+{
+       struct pin_desc *pin;
+       int p;
+       int err = 0;
+
+       /* Allocate and configure pins */
+       for (p = 0; p < pin_group->nr_pins; p++) {
+               pr_debug("%s: #%d\n", __func__, p);
+               pin = &pin_group->pins[p];
+
+               err = stmp3xxx_request_pin(pin->id, pin->fun, label);
+               if (err)
+                       goto out_err;
+
+               stmp3xxx_pin_strength(pin->id, pin->strength, label);
+               stmp3xxx_pin_voltage(pin->id, pin->voltage, label);
+               stmp3xxx_pin_pullup(pin->id, pin->pullup, label);
+       }
+
+       return 0;
+
+out_err:
+       /* Release allocated pins in case of error */
+       while (--p >= 0) {
+               pr_debug("%s: releasing #%d\n", __func__, p);
+               stmp3xxx_release_pin(pin_group->pins[p].id, label);
+       }
+       return err;
+}
+EXPORT_SYMBOL(stmp3xxx_request_pin_group);
+
+void stmp3xxx_release_pin_group(struct pin_group *pin_group, const char *label)
+{
+       struct pin_desc *pin;
+       int p;
+
+       for (p = 0; p < pin_group->nr_pins; p++) {
+               pin = &pin_group->pins[p];
+               stmp3xxx_release_pin(pin->id, label);
+       }
+}
+EXPORT_SYMBOL(stmp3xxx_release_pin_group);
+
+static int stmp3xxx_irq_to_gpio(int irq,
+       struct stmp3xxx_pinmux_bank **bank, unsigned *gpio)
+{
+       struct stmp3xxx_pinmux_bank *pm;
+
+       for (pm = pinmux_banks; pm < pinmux_banks + NR_BANKS; pm++)
+               if (pm->virq <= irq && irq < pm->virq + 32) {
+                       *bank = pm;
+                       *gpio = irq - pm->virq;
+                       return 0;
+               }
+       return -ENOENT;
+}
+
+static int stmp3xxx_set_irqtype(unsigned irq, unsigned type)
+{
+       struct stmp3xxx_pinmux_bank *pm;
+       unsigned gpio;
+       int l, p;
+
+       stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+               l = 0; p = 1; break;
+       case IRQ_TYPE_EDGE_FALLING:
+               l = 0; p = 0; break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               l = 1; p = 1; break;
+       case IRQ_TYPE_LEVEL_LOW:
+               l = 1; p = 0; break;
+       default:
+               pr_debug("%s: Incorrect GPIO interrupt type 0x%x\n",
+                               __func__, type);
+               return -ENXIO;
+       }
+
+       if (l)
+               stmp3xxx_setl(1 << gpio, pm->irqlevel);
+       else
+               stmp3xxx_clearl(1 << gpio, pm->irqlevel);
+       if (p)
+               stmp3xxx_setl(1 << gpio, pm->irqpolarity);
+       else
+               stmp3xxx_clearl(1 << gpio, pm->irqpolarity);
+       return 0;
+}
+
+static void stmp3xxx_pin_ack_irq(unsigned irq)
+{
+       u32 stat;
+       struct stmp3xxx_pinmux_bank *pm;
+       unsigned gpio;
+
+       stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
+       stat = __raw_readl(pm->irqstat) & (1 << gpio);
+       stmp3xxx_clearl(stat, pm->irqstat);
+}
+
+static void stmp3xxx_pin_mask_irq(unsigned irq)
+{
+       struct stmp3xxx_pinmux_bank *pm;
+       unsigned gpio;
+
+       stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
+       stmp3xxx_clearl(1 << gpio, pm->irqen);
+       stmp3xxx_clearl(1 << gpio, pm->pin2irq);
+}
+
+static void stmp3xxx_pin_unmask_irq(unsigned irq)
+{
+       struct stmp3xxx_pinmux_bank *pm;
+       unsigned gpio;
+
+       stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
+       stmp3xxx_setl(1 << gpio, pm->irqen);
+       stmp3xxx_setl(1 << gpio, pm->pin2irq);
+}
+
+static inline
+struct stmp3xxx_pinmux_bank *to_pinmux_bank(struct gpio_chip *chip)
+{
+       return container_of(chip, struct stmp3xxx_pinmux_bank, chip);
+}
+
+static int stmp3xxx_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
+       return pm->virq + offset;
+}
+
+static int stmp3xxx_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
+       unsigned v;
+
+       v = __raw_readl(pm->hw_gpio_in) & (1 << offset);
+       return v ? 1 : 0;
+}
+
+static void stmp3xxx_gpio_set(struct gpio_chip *chip, unsigned offset, int v)
+{
+       struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
+
+       if (v)
+               stmp3xxx_setl(1 << offset, pm->hw_gpio_out);
+       else
+               stmp3xxx_clearl(1 << offset, pm->hw_gpio_out);
+}
+
+static int stmp3xxx_gpio_output(struct gpio_chip *chip, unsigned offset, int v)
+{
+       struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
+
+       stmp3xxx_setl(1 << offset, pm->hw_gpio_doe);
+       stmp3xxx_gpio_set(chip, offset, v);
+       return 0;
+}
+
+static int stmp3xxx_gpio_input(struct gpio_chip *chip, unsigned offset)
+{
+       struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
+
+       stmp3xxx_clearl(1 << offset, pm->hw_gpio_doe);
+       return 0;
+}
+
+static int stmp3xxx_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+       return stmp3xxx_request_pin(chip->base + offset, PIN_GPIO, "gpio");
+}
+
+static void stmp3xxx_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+       stmp3xxx_release_pin(chip->base + offset, "gpio");
+}
+
+static void stmp3xxx_gpio_irq(u32 irq, struct irq_desc *desc)
+{
+       struct stmp3xxx_pinmux_bank *pm = get_irq_data(irq);
+       int gpio_irq = pm->virq;
+       u32 stat = __raw_readl(pm->irqstat);
+
+       while (stat) {
+               if (stat & 1)
+                       irq_desc[gpio_irq].handle_irq(gpio_irq,
+                               &irq_desc[gpio_irq]);
+               gpio_irq++;
+               stat >>= 1;
+       }
+}
+
+static struct irq_chip gpio_irq_chip = {
+       .ack    = stmp3xxx_pin_ack_irq,
+       .mask   = stmp3xxx_pin_mask_irq,
+       .unmask = stmp3xxx_pin_unmask_irq,
+       .set_type = stmp3xxx_set_irqtype,
+};
+
+int __init stmp3xxx_pinmux_init(int virtual_irq_start)
+{
+       int b, r = 0;
+       struct stmp3xxx_pinmux_bank *pm;
+       int virq;
+
+       for (b = 0; b < 3; b++) {
+               /* only banks 0,1,2 are allowed to GPIO */
+               pm = pinmux_banks + b;
+               pm->chip.base = 32 * b;
+               pm->chip.ngpio = 32;
+               pm->chip.owner = THIS_MODULE;
+               pm->chip.can_sleep = 1;
+               pm->chip.exported = 1;
+               pm->chip.to_irq = stmp3xxx_gpio_to_irq;
+               pm->chip.direction_input = stmp3xxx_gpio_input;
+               pm->chip.direction_output = stmp3xxx_gpio_output;
+               pm->chip.get = stmp3xxx_gpio_get;
+               pm->chip.set = stmp3xxx_gpio_set;
+               pm->chip.request = stmp3xxx_gpio_request;
+               pm->chip.free = stmp3xxx_gpio_free;
+               pm->virq = virtual_irq_start + b * 32;
+
+               for (virq = pm->virq; virq < pm->virq; virq++) {
+                       gpio_irq_chip.mask(virq);
+                       set_irq_chip(virq, &gpio_irq_chip);
+                       set_irq_handler(virq, handle_level_irq);
+                       set_irq_flags(virq, IRQF_VALID);
+               }
+               r = gpiochip_add(&pm->chip);
+               if (r < 0)
+                       break;
+               set_irq_chained_handler(pm->irq, stmp3xxx_gpio_irq);
+               set_irq_data(pm->irq, pm);
+       }
+       return r;
+}
+
+MODULE_AUTHOR("Vladislav Buzov");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/plat-stmp3xxx/timer.c b/arch/arm/plat-stmp3xxx/timer.c
new file mode 100644 (file)
index 0000000..063c7bc
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * System timer for Freescale STMP37XX/STMP378X
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+
+#include <asm/mach/time.h>
+#include <mach/stmp3xxx.h>
+#include <mach/platform.h>
+#include <mach/regs-timrot.h>
+
+static irqreturn_t
+stmp3xxx_timer_interrupt(int irq, void *dev_id)
+{
+       struct clock_event_device *c = dev_id;
+
+       /* timer 0 */
+       if (__raw_readl(REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0) &
+                       BM_TIMROT_TIMCTRLn_IRQ) {
+               stmp3xxx_clearl(BM_TIMROT_TIMCTRLn_IRQ,
+                               REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0);
+               c->event_handler(c);
+       }
+
+       /* timer 1 */
+       else if (__raw_readl(REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1)
+                       & BM_TIMROT_TIMCTRLn_IRQ) {
+               stmp3xxx_clearl(BM_TIMROT_TIMCTRLn_IRQ,
+                               REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1);
+               stmp3xxx_clearl(BM_TIMROT_TIMCTRLn_IRQ_EN,
+                               REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1);
+               __raw_writel(0xFFFF, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static cycle_t stmp3xxx_clock_read(struct clocksource *cs)
+{
+       return ~((__raw_readl(REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1)
+                               & 0xFFFF0000) >> 16);
+}
+
+static int
+stmp3xxx_timrot_set_next_event(unsigned long delta,
+               struct clock_event_device *dev)
+{
+       /* reload the timer */
+       __raw_writel(delta, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0);
+       return 0;
+}
+
+static void
+stmp3xxx_timrot_set_mode(enum clock_event_mode mode,
+               struct clock_event_device *dev)
+{
+}
+
+static struct clock_event_device ckevt_timrot = {
+       .name           = "timrot",
+       .features       = CLOCK_EVT_FEAT_ONESHOT,
+       .shift          = 32,
+       .set_next_event = stmp3xxx_timrot_set_next_event,
+       .set_mode       = stmp3xxx_timrot_set_mode,
+};
+
+static struct clocksource cksrc_stmp3xxx = {
+       .name           = "cksrc_stmp3xxx",
+       .rating         = 250,
+       .read           = stmp3xxx_clock_read,
+       .mask           = CLOCKSOURCE_MASK(16),
+       .shift          = 10,
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static struct irqaction stmp3xxx_timer_irq = {
+       .name           = "stmp3xxx_timer",
+       .flags          = IRQF_DISABLED | IRQF_TIMER,
+       .handler        = stmp3xxx_timer_interrupt,
+       .dev_id         = &ckevt_timrot,
+};
+
+
+/*
+ * Set up timer interrupt, and return the current time in seconds.
+ */
+static void __init stmp3xxx_init_timer(void)
+{
+       cksrc_stmp3xxx.mult = clocksource_hz2mult(CLOCK_TICK_RATE,
+                               cksrc_stmp3xxx.shift);
+       ckevt_timrot.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC,
+                               ckevt_timrot.shift);
+       ckevt_timrot.min_delta_ns = clockevent_delta2ns(2, &ckevt_timrot);
+       ckevt_timrot.max_delta_ns = clockevent_delta2ns(0xFFF, &ckevt_timrot);
+       ckevt_timrot.cpumask = cpumask_of(0);
+
+       stmp3xxx_reset_block(REGS_TIMROT_BASE, false);
+
+       /* clear two timers */
+       __raw_writel(0, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0);
+       __raw_writel(0, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1);
+
+       /* configure them */
+       __raw_writel(
+               (8 << BP_TIMROT_TIMCTRLn_SELECT) |  /* 32 kHz */
+               BM_TIMROT_TIMCTRLn_RELOAD |
+               BM_TIMROT_TIMCTRLn_UPDATE |
+               BM_TIMROT_TIMCTRLn_IRQ_EN,
+                       REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0);
+       __raw_writel(
+               (8 << BP_TIMROT_TIMCTRLn_SELECT) |  /* 32 kHz */
+               BM_TIMROT_TIMCTRLn_RELOAD |
+               BM_TIMROT_TIMCTRLn_UPDATE |
+               BM_TIMROT_TIMCTRLn_IRQ_EN,
+                       REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1);
+
+       __raw_writel(CLOCK_TICK_RATE / HZ - 1,
+                       REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0);
+       __raw_writel(0xFFFF, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1);
+
+       setup_irq(IRQ_TIMER0, &stmp3xxx_timer_irq);
+
+       clocksource_register(&cksrc_stmp3xxx);
+       clockevents_register_device(&ckevt_timrot);
+}
+
+#ifdef CONFIG_PM
+
+void stmp3xxx_suspend_timer(void)
+{
+       stmp3xxx_clearl(BM_TIMROT_TIMCTRLn_IRQ_EN | BM_TIMROT_TIMCTRLn_IRQ,
+                       REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0);
+       stmp3xxx_setl(BM_TIMROT_ROTCTRL_CLKGATE,
+                       REGS_TIMROT_BASE + HW_TIMROT_ROTCTRL);
+}
+
+void stmp3xxx_resume_timer(void)
+{
+       stmp3xxx_clearl(BM_TIMROT_ROTCTRL_SFTRST | BM_TIMROT_ROTCTRL_CLKGATE,
+                       REGS_TIMROT_BASE + HW_TIMROT_ROTCTRL);
+       __raw_writel(
+               8 << BP_TIMROT_TIMCTRLn_SELECT |  /* 32 kHz */
+               BM_TIMROT_TIMCTRLn_RELOAD |
+               BM_TIMROT_TIMCTRLn_UPDATE |
+               BM_TIMROT_TIMCTRLn_IRQ_EN,
+                       REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0);
+       __raw_writel(
+               8 << BP_TIMROT_TIMCTRLn_SELECT |  /* 32 kHz */
+               BM_TIMROT_TIMCTRLn_RELOAD |
+               BM_TIMROT_TIMCTRLn_UPDATE |
+               BM_TIMROT_TIMCTRLn_IRQ_EN,
+                       REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1);
+       __raw_writel(CLOCK_TICK_RATE / HZ - 1,
+                       REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0);
+       __raw_writel(0xFFFF, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1);
+}
+
+#else
+
+#define stmp3xxx_suspend_timer NULL
+#define        stmp3xxx_resume_timer   NULL
+
+#endif /* CONFIG_PM */
+
+struct sys_timer stmp3xxx_timer = {
+       .init           = stmp3xxx_init_timer,
+       .suspend        = stmp3xxx_suspend_timer,
+       .resume         = stmp3xxx_resume_timer,
+};
index 83c4e384b16d07efa738e293ae05ef79ea61be1f..1aeae38725dd664b034b8163e409e9fc9f5c065d 100644 (file)
@@ -100,6 +100,7 @@ ENTRY(vfp_support_entry)
        beq     no_old_VFP_process
        VFPFSTMIA r4, r5                @ save the working registers
        VFPFMRX r5, FPSCR               @ current status
+#ifndef CONFIG_CPU_FEROCEON
        tst     r1, #FPEXC_EX           @ is there additional state to save?
        beq     1f
        VFPFMRX r6, FPINST              @ FPINST (only if FPEXC.EX is set)
@@ -107,6 +108,7 @@ ENTRY(vfp_support_entry)
        beq     1f
        VFPFMRX r8, FPINST2             @ FPINST2 if needed (and present)
 1:
+#endif
        stmia   r4, {r1, r5, r6, r8}    @ save FPEXC, FPSCR, FPINST, FPINST2
                                        @ and point r4 at the word at the
                                        @ start of the register dump
@@ -119,6 +121,7 @@ no_old_VFP_process:
        VFPFLDMIA r10, r5               @ reload the working registers while
                                        @ FPEXC is in a safe state
        ldmia   r10, {r1, r5, r6, r8}   @ load FPEXC, FPSCR, FPINST, FPINST2
+#ifndef CONFIG_CPU_FEROCEON
        tst     r1, #FPEXC_EX           @ is there additional state to restore?
        beq     1f
        VFPFMXR FPINST, r6              @ restore FPINST (only if FPEXC.EX is set)
@@ -126,6 +129,7 @@ no_old_VFP_process:
        beq     1f
        VFPFMXR FPINST2, r8             @ FPINST2 if needed (and present)
 1:
+#endif
        VFPFMXR FPSCR, r5               @ restore status
 
 check_for_exception:
index 01599c4ef7266f9f3eb27b56bbe0cdd3f3931121..2d7423af1197a3418f1b7bb84222f04f77954884 100644 (file)
@@ -253,12 +253,14 @@ void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
        }
 
        if (fpexc & FPEXC_EX) {
+#ifndef CONFIG_CPU_FEROCEON
                /*
                 * Asynchronous exception. The instruction is read from FPINST
                 * and the interrupted instruction has to be restarted.
                 */
                trigger = fmrx(FPINST);
                regs->ARM_pc -= 4;
+#endif
        } else if (!(fpexc & FPEXC_DEX)) {
                /*
                 * Illegal combination of bits. It can be caused by an
index b3f99477bbeb02dc47d4203893eb12bb98868933..be27a0218ab4e050a2f5637f12fd88c3e698b966 100644 (file)
@@ -2,8 +2,15 @@
 
 if BOARD_ATNGW100
 
+choice
+       prompt "Select an NGW100 add-on board to support"
+       default BOARD_ATNGW100_ADDON_NONE
+
+config BOARD_ATNGW100_ADDON_NONE
+       bool "None"
+
 config BOARD_ATNGW100_EVKLCD10X
-       bool "Add support for EVKLCD10X addon board"
+       bool "EVKLCD10X addon board"
        help
          This enables support for the EVKLCD100 (QVGA) or EVKLCD101 (VGA)
          addon board for the NGW100. By enabling this the LCD controller and
@@ -14,7 +21,19 @@ config BOARD_ATNGW100_EVKLCD10X
          The MCI pins can be reenabled by editing the "add device function" but
          this may break the setup for other displays that use these pins.
 
-         Choose 'Y' here if you have a EVKLCD100/101 connected to the NGW100.
+config BOARD_ATNGW100_MRMT
+       bool "Mediama RMT1/2 add-on board"
+       help
+         This enables support for the Mediama RMT1 or RMT2 board.
+         RMT provides LCD support, AC97 codec and other
+         optional peripherals to the Atmel NGW100.
+
+         This choice disables the detect pin and the write-protect pin for the
+         MCI platform device, since it conflicts with the LCD platform device.
+         The MCI pins can be reenabled by editing the "add device function" but
+         this may break the setup for other displays that use these pins.
+
+endchoice
 
 choice
        prompt "LCD panel resolution on EVKLCD10X"
@@ -32,4 +51,8 @@ config BOARD_ATNGW100_EVKLCD10X_POW_QVGA
 
 endchoice
 
+if BOARD_ATNGW100_MRMT
+source "arch/avr32/boards/atngw100/Kconfig_mrmt"
+endif
+
 endif  # BOARD_ATNGW100
diff --git a/arch/avr32/boards/atngw100/Kconfig_mrmt b/arch/avr32/boards/atngw100/Kconfig_mrmt
new file mode 100644 (file)
index 0000000..9a199a2
--- /dev/null
@@ -0,0 +1,80 @@
+# RMT for NGW100 customization
+
+choice
+       prompt "RMT Version"
+       help
+         Select the RMTx board version.
+
+config BOARD_MRMT_REV1
+       bool "RMT1"
+config BOARD_MRMT_REV2
+       bool "RMT2"
+
+endchoice
+
+config BOARD_MRMT_AC97
+       bool "Enable AC97 CODEC"
+       help
+         Enable the UCB1400 AC97 CODEC driver.
+
+choice
+       prompt "Touchscreen Driver"
+       default BOARD_MRMT_ADS7846_TS
+
+config BOARD_MRMT_UCB1400_TS
+       bool "Use UCB1400 Touchscreen"
+
+config BOARD_MRMT_ADS7846_TS
+       bool "Use ADS7846 Touchscreen"
+
+endchoice
+
+choice
+       prompt "RMTx LCD Selection"
+       default BOARD_MRMT_LCD_DISABLE
+
+config BOARD_MRMT_LCD_DISABLE
+       bool "LCD Disabled"
+
+config BOARD_MRMT_LCD_LQ043T3DX0X
+       bool "Sharp LQ043T3DX0x or compatible"
+       help
+         If using RMT2, be sure to load the resistor pack selectors accordingly
+
+if BOARD_MRMT_REV2
+config BOARD_MRMT_LCD_KWH043GM08
+       bool "Formike KWH043GM08 or compatible"
+       help
+         Be sure to load the RMT2 resistor pack selectors accordingly
+endif
+
+endchoice
+
+if !BOARD_MRMT_LCD_DISABLE
+config BOARD_MRMT_BL_PWM
+       bool "Use PWM control for LCD Backlight"
+       help
+               Use PWM driver for controlling LCD Backlight.
+               Otherwise, LCD Backlight is always on.
+endif
+
+config BOARD_MRMT_RTC_I2C
+       bool "Use External RTC on I2C Bus"
+       help
+               RMT1 has an optional RTC device on the I2C bus.
+               It is a SII S35390A.  Be sure to select the
+               matching RTC driver.
+
+choice
+       prompt "Wireless Module on ttyS2"
+       default BOARD_MRMT_WIRELESS_ZB
+
+config BOARD_MRMT_WIRELESS_ZB
+       bool "Use ZigBee/802.15.4 Module"
+
+config BOARD_MRMT_WIRELESS_BT
+       bool "Use Bluetooth (HCI) Module"
+
+config BOARD_MRMT_WIRELESS_NONE
+       bool "Not Installed"
+endchoice
index 6376f5322e4d2c8537494821cfe55ac50eaed11c..f4ebe42a8254d22b59e83084ba4d4d38d397cb0f 100644 (file)
@@ -1,2 +1,3 @@
 obj-y                                  += setup.o flash.o
 obj-$(CONFIG_BOARD_ATNGW100_EVKLCD10X) += evklcd10x.o
+obj-$(CONFIG_BOARD_ATNGW100_MRMT)      += mrmt.o
diff --git a/arch/avr32/boards/atngw100/mrmt.c b/arch/avr32/boards/atngw100/mrmt.c
new file mode 100644 (file)
index 0000000..bf78e51
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * Board-specific setup code for Remote Media Terminal 1 (RMT1)
+ * add-on board for the ATNGW100 Network Gateway
+ *
+ * Copyright (C) 2008 Mediama Technologies
+ * Based on ATNGW100 Network Gateway (Copyright (C) Atmel)
+ *
+ * This 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/gpio.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/linkage.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/fb.h>
+#include <linux/leds.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+#include <linux/atmel_serial.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+
+#include <video/atmel_lcdc.h>
+#include <sound/atmel-ac97c.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <asm/setup.h>
+
+#include <mach/at32ap700x.h>
+#include <mach/board.h>
+#include <mach/init.h>
+#include <mach/portmux.h>
+
+/* Define board-specifoic GPIO assignments */
+#define PIN_LCD_BL     GPIO_PIN_PA(28)
+#define PWM_CH_BL      0       /* Must match with GPIO pin definition */
+#define PIN_LCD_DISP   GPIO_PIN_PA(31)
+#define        PIN_AC97_RST_N  GPIO_PIN_PA(30)
+#define PB_EXTINT_BASE 25
+#define TS_IRQ         0
+#define PIN_TS_EXTINT  GPIO_PIN_PB(PB_EXTINT_BASE+TS_IRQ)
+#define PIN_PB_LEFT    GPIO_PIN_PB(11)
+#define PIN_PB_RIGHT   GPIO_PIN_PB(12)
+#define PIN_PWR_SW_N   GPIO_PIN_PB(14)
+#define PIN_PWR_ON     GPIO_PIN_PB(13)
+#define PIN_ZB_RST_N   GPIO_PIN_PA(21)
+#define PIN_BT_RST     GPIO_PIN_PA(22)
+#define PIN_LED_SYS    GPIO_PIN_PA(16)
+#define PIN_LED_A      GPIO_PIN_PA(19)
+#define PIN_LED_B      GPIO_PIN_PE(19)
+
+#ifdef CONFIG_BOARD_MRMT_LCD_LQ043T3DX0X
+/* Sharp LQ043T3DX0x (or compatible) panel */
+static struct fb_videomode __initdata lcd_fb_modes[] = {
+       {
+               .name           = "480x272 @ 59.94Hz",
+               .refresh        = 59.94,
+               .xres           = 480,          .yres           = 272,
+               .pixclock       = KHZ2PICOS(9000),
+
+               .left_margin    = 2,            .right_margin   = 2,
+               .upper_margin   = 3,            .lower_margin   = 9,
+               .hsync_len      = 41,           .vsync_len      = 1,
+
+               .sync           = 0,
+               .vmode          = FB_VMODE_NONINTERLACED,
+       },
+};
+
+static struct fb_monspecs __initdata lcd_fb_default_monspecs = {
+       .manufacturer           = "SHA",
+       .monitor                = "LQ043T3DX02",
+       .modedb                 = lcd_fb_modes,
+       .modedb_len             = ARRAY_SIZE(lcd_fb_modes),
+       .hfmin                  = 14915,
+       .hfmax                  = 17638,
+       .vfmin                  = 53,
+       .vfmax                  = 61,
+       .dclkmax                = 9260000,
+};
+
+static struct atmel_lcdfb_info __initdata rmt_lcdc_data = {
+       .default_bpp            = 24,
+       .default_dmacon         = ATMEL_LCDC_DMAEN | ATMEL_LCDC_DMA2DEN,
+       .default_lcdcon2        = (ATMEL_LCDC_DISTYPE_TFT
+                                  | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE
+                                  | ATMEL_LCDC_INVCLK_NORMAL
+                                  | ATMEL_LCDC_MEMOR_BIG),
+       .lcd_wiring_mode        = ATMEL_LCDC_WIRING_RGB,
+       .default_monspecs       = &lcd_fb_default_monspecs,
+       .guard_time             = 2,
+};
+#endif
+
+#ifdef CONFIG_BOARD_MRMT_LCD_KWH043GM08
+/* Sharp KWH043GM08-Fxx (or compatible) panel */
+static struct fb_videomode __initdata lcd_fb_modes[] = {
+       {
+               .name           = "480x272 @ 59.94Hz",
+               .refresh        = 59.94,
+               .xres           = 480,          .yres           = 272,
+               .pixclock       = KHZ2PICOS(9000),
+
+               .left_margin    = 2,            .right_margin   = 2,
+               .upper_margin   = 3,            .lower_margin   = 9,
+               .hsync_len      = 41,           .vsync_len      = 1,
+
+               .sync           = 0,
+               .vmode          = FB_VMODE_NONINTERLACED,
+       },
+};
+
+static struct fb_monspecs __initdata lcd_fb_default_monspecs = {
+       .manufacturer           = "FOR",
+       .monitor                = "KWH043GM08",
+       .modedb                 = lcd_fb_modes,
+       .modedb_len             = ARRAY_SIZE(lcd_fb_modes),
+       .hfmin                  = 14915,
+       .hfmax                  = 17638,
+       .vfmin                  = 53,
+       .vfmax                  = 61,
+       .dclkmax                = 9260000,
+};
+
+static struct atmel_lcdfb_info __initdata rmt_lcdc_data = {
+       .default_bpp            = 24,
+       .default_dmacon         = ATMEL_LCDC_DMAEN | ATMEL_LCDC_DMA2DEN,
+       .default_lcdcon2        = (ATMEL_LCDC_DISTYPE_TFT
+                                  | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE
+                                  | ATMEL_LCDC_INVCLK_INVERTED
+                                  | ATMEL_LCDC_MEMOR_BIG),
+       .lcd_wiring_mode        = ATMEL_LCDC_WIRING_RGB,
+       .default_monspecs       = &lcd_fb_default_monspecs,
+       .guard_time             = 2,
+};
+#endif
+
+#ifdef CONFIG_BOARD_MRMT_AC97
+static struct ac97c_platform_data __initdata ac97c0_data = {
+       .reset_pin              = PIN_AC97_RST_N,
+};
+#endif
+
+#ifdef CONFIG_BOARD_MRMT_UCB1400_TS
+/* NOTE: IRQ assignment relies on kernel module parameter */
+static struct platform_device rmt_ts_device = {
+       .name   = "ucb1400_ts",
+       .id     = -1,
+       }
+};
+#endif
+
+#ifdef CONFIG_BOARD_MRMT_BL_PWM
+/* PWM LEDs: LCD Backlight, etc */
+static struct gpio_led rmt_pwm_led[] = {
+       /* here the "gpio" is actually a PWM channel */
+       { .name = "backlight",  .gpio = PWM_CH_BL, },
+};
+
+static struct gpio_led_platform_data rmt_pwm_led_data = {
+       .num_leds       = ARRAY_SIZE(rmt_pwm_led),
+       .leds           = rmt_pwm_led,
+};
+
+static struct platform_device rmt_pwm_led_dev = {
+       .name           = "leds-atmel-pwm",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &rmt_pwm_led_data,
+       },
+};
+#endif
+
+#ifdef CONFIG_BOARD_MRMT_ADS7846_TS
+static int ads7846_pendown_state(void)
+{
+       return !gpio_get_value( PIN_TS_EXTINT );        /* PENIRQ.*/
+}
+
+static struct ads7846_platform_data ads_info = {
+       .model                          = 7846,
+       .keep_vref_on                   = 0,    /* Use external VREF pin */
+       .vref_delay_usecs               = 0,
+       .vref_mv                        = 3300, /* VREF = 3.3V */
+       .settle_delay_usecs             = 800,
+       .penirq_recheck_delay_usecs     = 800,
+       .x_plate_ohms                   = 750,
+       .y_plate_ohms                   = 300,
+       .pressure_max                   = 4096,
+       .debounce_max                   = 1,
+       .debounce_rep                   = 0,
+       .debounce_tol                   = (~0),
+       .get_pendown_state              = ads7846_pendown_state,
+       .filter                         = NULL,
+       .filter_init                    = NULL,
+};
+
+static struct spi_board_info spi01_board_info[] __initdata = {
+       {
+               .modalias       = "ads7846",
+               .max_speed_hz   = 31250*26,
+               .bus_num        = 0,
+               .chip_select    = 1,
+               .platform_data  = &ads_info,
+               .irq            = AT32_EXTINT(TS_IRQ),
+       },
+};
+#endif
+
+/* GPIO Keys: left, right, power, etc */
+static const struct gpio_keys_button rmt_gpio_keys_buttons[] = {
+       [0] = {
+               .type           = EV_KEY,
+               .code           = KEY_POWER,
+               .gpio           = PIN_PWR_SW_N,
+               .active_low     = 1,
+               .desc           = "power button",
+       },
+       [1] = {
+               .type           = EV_KEY,
+               .code           = KEY_LEFT,
+               .gpio           = PIN_PB_LEFT,
+               .active_low     = 1,
+               .desc           = "left button",
+       },
+       [2] = {
+               .type           = EV_KEY,
+               .code           = KEY_RIGHT,
+               .gpio           = PIN_PB_RIGHT,
+               .active_low     = 1,
+               .desc           = "right button",
+       },
+};
+
+static const struct gpio_keys_platform_data rmt_gpio_keys_data = {
+       .nbuttons =     ARRAY_SIZE(rmt_gpio_keys_buttons),
+       .buttons =      (void *) rmt_gpio_keys_buttons,
+};
+
+static struct platform_device rmt_gpio_keys = {
+       .name =         "gpio-keys",
+       .id =           -1,
+       .dev = {
+               .platform_data = (void *) &rmt_gpio_keys_data,
+       }
+};
+
+#ifdef CONFIG_BOARD_MRMT_RTC_I2C
+static struct i2c_board_info __initdata mrmt1_i2c_rtc = {
+       I2C_BOARD_INFO("s35390a", 0x30),
+       .irq            = 0,
+};
+#endif
+
+static void mrmt_power_off(void)
+{
+       /* PWR_ON=0 will force power off */
+       gpio_set_value( PIN_PWR_ON, 0 );
+}
+
+static int __init mrmt1_init(void)
+{
+       gpio_set_value( PIN_PWR_ON, 1 );        /* Ensure PWR_ON is enabled */
+
+       pm_power_off = mrmt_power_off;
+
+       /* Setup USARTS (other than console) */
+       at32_map_usart(2, 1, 0);        /* USART 2: /dev/ttyS1, RMT1:DB9M */
+       at32_map_usart(3, 2, ATMEL_USART_RTS | ATMEL_USART_CTS);
+                       /* USART 3: /dev/ttyS2, RMT1:Wireless, w/ RTS/CTS */
+       at32_add_device_usart(1);
+       at32_add_device_usart(2);
+
+       /* Select GPIO Key pins */
+       at32_select_gpio( PIN_PWR_SW_N, AT32_GPIOF_DEGLITCH);
+       at32_select_gpio( PIN_PB_LEFT, AT32_GPIOF_DEGLITCH);
+       at32_select_gpio( PIN_PB_RIGHT, AT32_GPIOF_DEGLITCH);
+       platform_device_register(&rmt_gpio_keys);
+
+#ifdef CONFIG_BOARD_MRMT_RTC_I2C
+       i2c_register_board_info(0, &mrmt1_i2c_rtc, 1);
+#endif
+
+#ifndef CONFIG_BOARD_MRMT_LCD_DISABLE
+       /* User "alternate" LCDC inferface on Port E & D */
+       /* NB: exclude LCDC_CC pin, as NGW100 reserves it for other use */
+       at32_add_device_lcdc(0, &rmt_lcdc_data,
+               fbmem_start, fbmem_size,
+               (ATMEL_LCDC_ALT_24BIT | ATMEL_LCDC_PE_DVAL ) );
+#endif
+
+#ifdef CONFIG_BOARD_MRMT_AC97
+       at32_add_device_ac97c(0, &ac97c0_data, AC97C_BOTH);
+#endif
+
+#ifdef CONFIG_BOARD_MRMT_ADS7846_TS
+       /* Select the Touchscreen interrupt pin mode */
+       at32_select_periph( GPIO_PIOB_BASE, 1 << (PB_EXTINT_BASE+TS_IRQ),
+                       GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH);
+       set_irq_type( AT32_EXTINT(TS_IRQ), IRQ_TYPE_EDGE_FALLING );
+       spi_register_board_info(spi01_board_info,ARRAY_SIZE(spi01_board_info));
+#endif
+
+#ifdef CONFIG_BOARD_MRMT_UCB1400_TS
+       /* Select the Touchscreen interrupt pin mode */
+       at32_select_periph( GPIO_PIOB_BASE, 1 << (PB_EXTINT_BASE+TS_IRQ),
+                       GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH);
+       platform_device_register(&rmt_ts_device);
+#endif
+
+       at32_select_gpio( PIN_LCD_DISP, AT32_GPIOF_OUTPUT );
+       gpio_request( PIN_LCD_DISP, "LCD_DISP" );
+       gpio_direction_output( PIN_LCD_DISP, 0 );       /* LCD DISP */
+#ifdef CONFIG_BOARD_MRMT_LCD_DISABLE
+       /* Keep Backlight and DISP off */
+       at32_select_gpio( PIN_LCD_BL, AT32_GPIOF_OUTPUT );
+       gpio_request( PIN_LCD_BL, "LCD_BL" );
+       gpio_direction_output( PIN_LCD_BL, 0 );         /* Backlight */
+#else
+       gpio_set_value( PIN_LCD_DISP, 1 );      /* DISP asserted first */
+#ifdef CONFIG_BOARD_MRMT_BL_PWM
+       /* Use PWM for Backlight controls */
+       at32_add_device_pwm(1 << PWM_CH_BL);
+       platform_device_register(&rmt_pwm_led_dev);
+#else
+       /* Backlight always on */
+       udelay( 1 );
+       at32_select_gpio( PIN_LCD_BL, AT32_GPIOF_OUTPUT );
+       gpio_request( PIN_LCD_BL, "LCD_BL" );
+       gpio_direction_output( PIN_LCD_BL, 1 );
+#endif
+#endif
+
+       /* Make sure BT and Zigbee modules in reset */
+       at32_select_gpio( PIN_BT_RST, AT32_GPIOF_OUTPUT );
+       gpio_request( PIN_BT_RST, "BT_RST" );
+       gpio_direction_output( PIN_BT_RST, 1 );
+       /* BT Module in Reset */
+
+       at32_select_gpio( PIN_ZB_RST_N, AT32_GPIOF_OUTPUT );
+       gpio_request( PIN_ZB_RST_N, "ZB_RST_N" );
+       gpio_direction_output( PIN_ZB_RST_N, 0 );
+       /* XBee Module in Reset */
+
+#ifdef CONFIG_BOARD_MRMT_WIRELESS_ZB
+       udelay( 1000 );
+       /* Unreset the XBee Module */
+       gpio_set_value( PIN_ZB_RST_N, 1 );
+#endif
+#ifdef CONFIG_BOARD_MRMT_WIRELESS_BT
+       udelay( 1000 );
+       /* Unreset the BT Module */
+       gpio_set_value( PIN_BT_RST, 0 );
+#endif
+
+       return 0;
+}
+arch_initcall(mrmt1_init);
+
+static int __init mrmt1_early_init(void)
+{
+       /* To maintain power-on signal in case boot loader did not already */
+       at32_select_gpio( PIN_PWR_ON, AT32_GPIOF_OUTPUT );
+       gpio_request( PIN_PWR_ON, "PIN_PWR_ON" );
+       gpio_direction_output( PIN_PWR_ON, 1 );
+
+       return 0;
+}
+core_initcall(mrmt1_early_init);
index 5b022aad4bd95b5c086801a04cf6114cc81cde10..bc299fbbeb4e3f94a65f8747ac3e9f6b2e8c4cdd 100644 (file)
@@ -56,8 +56,13 @@ static struct spi_board_info spi0_board_info[] __initdata = {
 static struct mci_platform_data __initdata mci0_data = {
        .slot[0] = {
                .bus_width      = 4,
+#if defined(CONFIG_BOARD_ATNGW100_EVKLCD10X) || defined(CONFIG_BOARD_ATNGW100_MRMT1)
+               .detect_pin     = GPIO_PIN_NONE,
+               .wp_pin         = GPIO_PIN_NONE,
+#else
                .detect_pin     = GPIO_PIN_PC(25),
                .wp_pin         = GPIO_PIN_PE(0),
+#endif
        },
 };
 
index 20b300cf105ade80ed74f2a0f94fc4aa100a9098..623b077594fc65238ae04f26eb1633816a666f96 100644 (file)
@@ -94,9 +94,10 @@ static struct spi_board_info __initdata spi0_board_info[] = {
 
 static struct mci_platform_data __initdata mci0_data = {
        .slot[0] = {
-               .bus_width      = 4,
-               .detect_pin     = GPIO_PIN_PE(19),
-               .wp_pin         = GPIO_PIN_PE(20),
+               .bus_width              = 4,
+               .detect_pin             = GPIO_PIN_PE(19),
+               .wp_pin                 = GPIO_PIN_PE(20),
+               .detect_is_active_high  = true,
        },
 };
 
index c1b2175b4fea6300c8d7c654e85ca2fa9a99cca2..523d8e183bef79a5b30ad3660ea8efd5909e7fb9 100644 (file)
@@ -43,16 +43,16 @@ unsigned long at32_board_osc_rates[3] = {
 /* Initialized by bootloader-specific startup code. */
 struct tag *bootloader_tags __initdata;
 
-static struct fb_videomode __initdata tx14d14_modes[] = {
+static struct fb_videomode __initdata pt0434827_modes[] = {
        {
-               .name           = "640x480 @ 60",
-               .refresh        = 60,
-               .xres           = 640,          .yres           = 480,
-               .pixclock       = KHZ2PICOS(11666),
+               .name           = "480x272 @ 72",
+               .refresh        = 72,
+               .xres           = 480,          .yres           = 272,
+               .pixclock       = KHZ2PICOS(10000),
 
-               .left_margin    = 80,           .right_margin   = 1,
-               .upper_margin   = 13,           .lower_margin   = 2,
-               .hsync_len      = 64,           .vsync_len      = 1,
+               .left_margin    = 1,            .right_margin   = 1,
+               .upper_margin   = 12,           .lower_margin   = 1,
+               .hsync_len      = 42,           .vsync_len      = 1,
 
                .sync           = 0,
                .vmode          = FB_VMODE_NONINTERLACED,
@@ -60,14 +60,14 @@ static struct fb_videomode __initdata tx14d14_modes[] = {
 };
 
 static struct fb_monspecs __initdata mimc200_default_monspecs = {
-       .manufacturer           = "HIT",
-       .monitor                = "TX14D14VM1BAB",
-       .modedb                 = tx14d14_modes,
-       .modedb_len             = ARRAY_SIZE(tx14d14_modes),
+       .manufacturer           = "PT",
+       .monitor                = "PT0434827-A401",
+       .modedb                 = pt0434827_modes,
+       .modedb_len             = ARRAY_SIZE(pt0434827_modes),
        .hfmin                  = 14820,
        .hfmax                  = 22230,
        .vfmin                  = 60,
-       .vfmax                  = 73.3,
+       .vfmax                  = 85,
        .dclkmax                = 25200000,
 };
 
@@ -228,7 +228,8 @@ static int __init mimc200_init(void)
        i2c_register_board_info(0, i2c_info, ARRAY_SIZE(i2c_info));
 
        at32_add_device_lcdc(0, &mimc200_lcdc_data,
-                            fbmem_start, fbmem_size, 1);
+                            fbmem_start, fbmem_size,
+                            ATMEL_LCDC_CONTROL | ATMEL_LCDC_ALT_CONTROL | ATMEL_LCDC_ALT_24B_DATA);
 
        return 0;
 }
diff --git a/arch/avr32/configs/atngw100_mrmt_defconfig b/arch/avr32/configs/atngw100_mrmt_defconfig
new file mode 100644 (file)
index 0000000..17b0307
--- /dev/null
@@ -0,0 +1,1363 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.30-rc1
+# Wed Jun  3 00:24:53 2009
+#
+CONFIG_AVR32=y
+CONFIG_GENERIC_GPIO=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_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# 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_BUG=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# 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=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_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_SYSCTL_SYSCALL is not set
+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 is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_SLUB_DEBUG is not set
+CONFIG_COMPAT_BRK=y
+# CONFIG_SLAB is not set
+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_CLK=y
+# CONFIG_SLOW_WORK is not set
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=1
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+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_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=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 and features
+#
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_SUBARCH_AVR32B=y
+CONFIG_MMU=y
+CONFIG_PERFORMANCE_COUNTERS=y
+CONFIG_PLATFORM_AT32AP=y
+CONFIG_CPU_AT32AP700X=y
+CONFIG_CPU_AT32AP7000=y
+# CONFIG_BOARD_ATSTK1000 is not set
+CONFIG_BOARD_ATNGW100=y
+# CONFIG_BOARD_HAMMERHEAD is not set
+# CONFIG_BOARD_FAVR_32 is not set
+# CONFIG_BOARD_MERISC is not set
+# CONFIG_BOARD_MIMC200 is not set
+# CONFIG_BOARD_ATNGW100_ADDON_NONE is not set
+# CONFIG_BOARD_ATNGW100_EVKLCD10X is not set
+CONFIG_BOARD_ATNGW100_MRMT=y
+CONFIG_BOARD_MRMT_REV1=y
+# CONFIG_BOARD_MRMT_REV2 is not set
+CONFIG_BOARD_MRMT_AC97=y
+# CONFIG_BOARD_MRMT_UCB1400_TS is not set
+CONFIG_BOARD_MRMT_ADS7846_TS=y
+# CONFIG_BOARD_MRMT_LCD_DISABLE is not set
+CONFIG_BOARD_MRMT_LCD_LQ043T3DX0X=y
+# CONFIG_BOARD_MRMT_LCD_KWH043GM08 is not set
+CONFIG_BOARD_MRMT_BL_PWM=y
+CONFIG_BOARD_MRMT_RTC_I2C=y
+CONFIG_BOARD_MRMT_WIRELESS_ZB=y
+# CONFIG_BOARD_MRMT_WIRELESS_BT is not set
+# CONFIG_BOARD_MRMT_WIRELESS_NONE is not set
+CONFIG_LOADER_U_BOOT=y
+
+#
+# Atmel AVR32 AP options
+#
+# CONFIG_AP700X_32_BIT_SMC is not set
+CONFIG_AP700X_16_BIT_SMC=y
+# CONFIG_AP700X_8_BIT_SMC is not set
+CONFIG_LOAD_ADDRESS=0x10000000
+CONFIG_ENTRY_ADDRESS=0x90000000
+CONFIG_PHYS_OFFSET=0x10000000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_QUICKLIST=y
+# CONFIG_HAVE_ARCH_BOOTMEM is not set
+# CONFIG_ARCH_HAVE_MEMORY_PRESENT is not set
+# CONFIG_NEED_NODE_MEMMAP_SIZE is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+# CONFIG_ARCH_SPARSEMEM_ENABLE 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_NR_QUICK=2
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_OWNERSHIP_TRACE is not set
+# CONFIG_NMI_DEBUGGING is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_SCHED_HRTICK is not set
+CONFIG_CMDLINE=""
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+# CONFIG_SUSPEND is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+
+#
+# CPU Frequency scaling
+#
+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_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=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_AT32AP=y
+
+#
+# Bus options
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+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_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# 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 is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# 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_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_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 is not set
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+# CONFIG_BT_BNEP is not set
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BT_HCIBTSDIO is not set
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+# CONFIG_BT_HCIUART_LL is not set
+# CONFIG_BT_HCIVHCI 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_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# 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=y
+# CONFIG_MTD_DEBUG 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_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_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+CONFIG_MTD_DATAFLASH=y
+# CONFIG_MTD_DATAFLASH_WRITE_VERIFY is not set
+# CONFIG_MTD_DATAFLASH_OTP is not set
+# CONFIG_MTD_M25P80 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 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 is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+CONFIG_ATMEL_PWM=y
+# CONFIG_ATMEL_TCLIB is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ATMEL_SSC 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_93CX6 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_COMPAT_NET_DEV_OPS=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 is not set
+CONFIG_MACB=y
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC 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_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# 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 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_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_GPIO=y
+# 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_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_WM97XX is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 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_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+CONFIG_SERIAL_ATMEL_PDC=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
+# 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=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_ALGOBIT=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_GPIO=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
+
+#
+# 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_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 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_ATMEL=y
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+
+#
+# SPI Protocol Masters
+#
+CONFIG_SPI_SPIDEV=y
+# CONFIG_SPI_TLE62X0 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:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY 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_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_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_SENSORS_LIS3_SPI is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_AT32AP700X_WDT=y
+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_UCB1400_CORE is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_REGULATOR 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
+
+#
+# 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_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_S1D13XXX is not set
+CONFIG_FB_ATMEL=y
+# 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=y
+# 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 is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_ATMEL_LCDC is not set
+# CONFIG_BACKLIGHT_ATMEL_PWM is not set
+CONFIG_BACKLIGHT_GENERIC=y
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+# CONFIG_LOGO is not set
+CONFIG_SOUND=m
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+# CONFIG_SND_SEQUENCER 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 is not set
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_VMASTER=y
+CONFIG_SND_AC97_CODEC=m
+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_AC97_POWER_SAVE is not set
+
+#
+# Atmel devices (AVR32 and AT91)
+#
+# CONFIG_SND_ATMEL_ABDAC is not set
+CONFIG_SND_ATMEL_AC97C=m
+# CONFIG_SND_SPI is not set
+# CONFIG_SND_SOC is not set
+# CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=m
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+# CONFIG_HID_PID is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_APPLE is not set
+CONFIG_USB_SUPPORT=y
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB 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=m
+# CONFIG_USB_GADGET_DEBUG is not set
+CONFIG_USB_GADGET_DEBUG_FILES=y
+# 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=y
+CONFIG_USB_ATMEL_USBA=m
+# 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_PXA27X is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_IMX 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_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+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
+
+#
+# OTG and related infrastructure
+#
+# 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 is not set
+CONFIG_MMC_ATMELMCI=y
+# CONFIG_MMC_ATMELMCI_DMA 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_ATMEL_PWM=y
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_GPIO_PLATFORM=y
+# CONFIG_LEDS_LP5521 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 is not set
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=m
+CONFIG_RTC_CLASS=m
+
+#
+# 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=m
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 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
+
+#
+# Platform RTC drivers
+#
+# 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_AT32AP700X=m
+CONFIG_DMADEVICES=y
+
+#
+# DMA Devices
+#
+CONFIG_DW_DMAC=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=y
+# CONFIG_UIO_PDRV is not set
+# CONFIG_UIO_PDRV_GENIRQ is not set
+# CONFIG_UIO_SMX is not set
+# CONFIG_UIO_SERCOS3 is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY 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_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+# 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_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=850
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+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=y
+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_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_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 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=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+CONFIG_CIFS=m
+CONFIG_CIFS_STATS=y
+# CONFIG_CIFS_STATS2 is not set
+CONFIG_CIFS_WEAK_PW_HASH=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_EXPERIMENTAL 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=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 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=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_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 is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS 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 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_FRAME_POINTER=y
+# 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_FAULT_INJECTION is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_TRACING_SUPPORT=y
+
+#
+# Tracers
+#
+# 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_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
+
+#
+# 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_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 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
index 318815107748dc8ee335e8fc7d2fc47fab8b10c0..b131c27ddf5785883a1c28a3078cf6f1bd5a5c0e 100644 (file)
@@ -196,6 +196,6 @@ static inline int atomic_sub_if_positive(int i, atomic_t *v)
 #define smp_mb__before_atomic_inc()    barrier()
 #define smp_mb__after_atomic_inc()     barrier()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 
 #endif /*  __ASM_AVR32_ATOMIC_H */
diff --git a/arch/avr32/include/asm/bitsperlong.h b/arch/avr32/include/asm/bitsperlong.h
new file mode 100644 (file)
index 0000000..6dc0bb0
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/bitsperlong.h>
index 218b0a6bfd1bdc220a3217e9574a107d999a2304..a36f9fcb8fcdd5758d31869cea2491082c2eda15 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __ASM_AVR32_HW_IRQ_H
 #define __ASM_AVR32_HW_IRQ_H
 
-static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i)
+static inline void hw_resend_irq(struct irq_chip *h, unsigned int i)
 {
        /* Nothing to do */
 }
index 648f91e7187a089a670ed5ba057524ff2439a334..9a92b15f6a66c19eeae0c9c42ecc964447608268 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __ASM_AVR32_MMAN_H__
 #define __ASM_AVR32_MMAN_H__
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 #define MAP_GROWSDOWN  0x0100          /* stack-like segment */
 #define MAP_DENYWRITE  0x0800          /* ETXTBSY */
index caffefeeba1fed9deccd9e7c51685e4bb69a8068..8790dfc10d5ba25353398a94cd93916ea1fe50a0 100644 (file)
@@ -112,7 +112,7 @@ typedef unsigned long sigset_t;
 #define MINSIGSTKSZ    2048
 #define SIGSTKSZ       8192
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
index 0152aba35154b5a8b53644e1466f30cd3748296e..dd7e9da2548894e8a749bb05196898efd629fe6a 100644 (file)
@@ -55,7 +55,7 @@ struct termio {
 */
 #define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
 
-#include <asm-generic/termios.h>
+#include <asm-generic/termios-base.h>
 
 #endif /* __KERNEL__ */
 
index 1167fe9cf6c4884c3448c01c1fbf037ce282af65..98f94d041d9c1dd212a0519efac60def8034b7db 100644 (file)
@@ -32,8 +32,6 @@ void module_free(struct module *mod, void *module_region)
        mod->arch.syminfo = NULL;
 
        vfree(module_region);
-       /* FIXME: if module_region == mod->init_region, trim exception
-        * table entries. */
 }
 
 static inline int check_rela(Elf32_Rela *rela, struct module *module,
index d547c8df157da7f31c5459e2fd4f2395faf1bc34..6e3d491184eab1d079b83a6cdaf33139f1365c1f 100644 (file)
@@ -75,8 +75,17 @@ void _exception(long signr, struct pt_regs *regs, int code,
 {
        siginfo_t info;
 
-       if (!user_mode(regs))
+       if (!user_mode(regs)) {
+               const struct exception_table_entry *fixup;
+
+               /* Are we prepared to handle this kernel fault? */
+               fixup = search_exception_tables(regs->pc);
+               if (fixup) {
+                       regs->pc = fixup->fixup;
+                       return;
+               }
                die("Unhandled exception in kernel mode", regs, signr);
+       }
 
        memset(&info, 0, sizeof(info));
        info.si_signo = signr;
index 0b81642818999d2161e7c9a0f72cdd05d21064f7..ddedb471f33eb34fa3e902a1a3b98f08dd58da08 100644 (file)
@@ -29,7 +29,7 @@ extern struct platform_device *atmel_default_console_device;
 /* Flags for selecting USART extra pins */
 #define        ATMEL_USART_RTS         0x01
 #define        ATMEL_USART_CTS         0x02
-#define        ATMEL_USART_CLK         0x03
+#define        ATMEL_USART_CLK         0x04
 
 struct atmel_uart_data {
        short           use_dma_tx;     /* use transmit DMA? */
index 3640cdc38aace3db670bbd703eb31959bd76cf05..a60cfe757914afb4d4be86494848574cf01b56b6 100644 (file)
@@ -223,6 +223,7 @@ endchoice
 
 config SMP
        depends on BF561
+       select GENERIC_TIME
        bool "Symmetric multi-processing support"
        ---help---
          This enables support for systems with more than one CPU,
@@ -241,12 +242,6 @@ config IRQ_PER_CPU
        depends on SMP
        default y
 
-config TICK_SOURCE_SYSTMR0
-       bool
-       select BFIN_GPTIMERS
-       depends on SMP
-       default y
-
 config BF_REV_MIN
        int
        default 0 if (BF51x || BF52x || (BF54x && !BF54xM))
@@ -263,8 +258,8 @@ config BF_REV_MAX
 
 choice
        prompt "Silicon Rev"
-       default BF_REV_0_1 if (BF51x || BF52x || (BF54x && !BF54xM))
-       default BF_REV_0_2 if (BF534 || BF536 || BF537)
+       default BF_REV_0_0 if (BF51x || BF52x)
+       default BF_REV_0_2 if (BF534 || BF536 || BF537 || (BF54x && !BF54xM))
        default BF_REV_0_3 if (BF531 || BF532 || BF533 || BF54xM || BF561)
 
 config BF_REV_0_0
@@ -607,7 +602,6 @@ source kernel/Kconfig.hz
 
 config GENERIC_TIME
        bool "Generic time"
-       depends on !SMP
        default y
 
 config GENERIC_CLOCKEVENTS
@@ -615,12 +609,26 @@ config GENERIC_CLOCKEVENTS
        depends on GENERIC_TIME
        default y
 
+choice
+       prompt "Kernel Tick Source"
+       depends on GENERIC_CLOCKEVENTS
+       default TICKSOURCE_CORETMR
+
+config TICKSOURCE_GPTMR0
+       bool "Gptimer0 (SCLK domain)"
+       select BFIN_GPTIMERS
+       depends on !IPIPE
+
+config TICKSOURCE_CORETMR
+       bool "Core timer (CCLK domain)"
+
+endchoice
+
 config CYCLES_CLOCKSOURCE
-       bool "Use 'CYCLES' as a clocksource (EXPERIMENTAL)"
-       depends on EXPERIMENTAL
+       bool "Use 'CYCLES' as a clocksource"
        depends on GENERIC_CLOCKEVENTS
        depends on !BFIN_SCRATCH_REG_CYCLES
-       default n
+       depends on !SMP
        help
          If you say Y here, you will enable support for using the 'cycles'
          registers as a clock source.  Doing so means you will be unable to
@@ -628,6 +636,11 @@ config CYCLES_CLOCKSOURCE
          still be able to read it (such as for performance monitoring), but
          writing the registers will most likely crash the kernel.
 
+config GPTMR0_CLOCKSOURCE
+       bool "Use GPTimer0 as a clocksource (higher rating)"
+       depends on GENERIC_CLOCKEVENTS
+       depends on !TICKSOURCE_GPTMR0
+
 source kernel/time/Kconfig
 
 comment "Misc"
@@ -808,7 +821,7 @@ config APP_STACK_L1
 config EXCEPTION_L1_SCRATCH
        bool "Locate exception stack in L1 Scratch Memory"
        default n
-       depends on !APP_STACK_L1 && !SYSCALL_TAB_L1
+       depends on !APP_STACK_L1
        help
          Whenever an exception occurs, use the L1 Scratch memory for
          stack storage.  You cannot place the stacks of FLAT binaries
@@ -872,7 +885,7 @@ config BFIN_GPTIMERS
          are unsure, say N.
 
          To compile this driver as a module, choose M here: the module
-         will be called gptimers.ko.
+         will be called gptimers.
 
 choice
        prompt "Uncached DMA region"
@@ -901,7 +914,7 @@ config BFIN_ICACHE_LOCK
        bool "Enable Instruction Cache Locking"
 
 choice
-       prompt "Policy"
+       prompt "External memory cache policy"
        depends on BFIN_DCACHE
        default BFIN_WB if !SMP
        default BFIN_WT if SMP
@@ -942,12 +955,22 @@ config BFIN_WT
 
 endchoice
 
-config BFIN_L2_CACHEABLE
-       bool "Cache L2 SRAM"
-       depends on (BFIN_DCACHE || BFIN_ICACHE) && (BF54x || (BF561 && !SMP))
-       default n
-       help
-         Select to make L2 SRAM cacheable in L1 data and instruction cache.
+choice
+       prompt "L2 SRAM cache policy"
+       depends on (BF54x || BF561)
+       default BFIN_L2_WT
+config BFIN_L2_WB
+       bool "Write back"
+       depends on !SMP
+
+config BFIN_L2_WT
+       bool "Write through"
+       depends on !SMP
+
+config BFIN_L2_NOT_CACHED
+       bool "Not cached"
+
+endchoice
 
 config MPU
        bool "Enable the memory protection unit (EXPERIMENTAL)"
@@ -1011,21 +1034,34 @@ endmenu
 
 menu "EBIU_AMBCTL Control"
 config BANK_0
-       hex "Bank 0"
+       hex "Bank 0 (AMBCTL0.L)"
        default 0x7BB0
+       help
+         These are the low 16 bits of the EBIU_AMBCTL0 MMR which are
+         used to control the Asynchronous Memory Bank 0 settings.
 
 config BANK_1
-       hex "Bank 1"
+       hex "Bank 1 (AMBCTL0.H)"
        default 0x7BB0
        default 0x5558 if BF54x
+       help
+         These are the high 16 bits of the EBIU_AMBCTL0 MMR which are
+         used to control the Asynchronous Memory Bank 1 settings.
 
 config BANK_2
-       hex "Bank 2"
+       hex "Bank 2 (AMBCTL1.L)"
        default 0x7BB0
+       help
+         These are the low 16 bits of the EBIU_AMBCTL1 MMR which are
+         used to control the Asynchronous Memory Bank 2 settings.
 
 config BANK_3
-       hex "Bank 3"
+       hex "Bank 3 (AMBCTL1.H)"
        default 0x99B3
+       help
+         These are the high 16 bits of the EBIU_AMBCTL1 MMR which are
+         used to control the Asynchronous Memory Bank 3 settings.
+
 endmenu
 
 config EBIU_MBSCTLVAL
index 79e7e63ab70985ddea291a2656052dcd6f8a2c5c..1fc4981d486f1371ebbf230ead0eeafaba6fe6b2 100644 (file)
@@ -54,6 +54,19 @@ config DEBUG_HWERR
          hardware error interrupts and need to know where they are coming
          from.
 
+config EXACT_HWERR
+       bool "Try to make Hardware errors exact"
+       depends on DEBUG_HWERR
+       help
+         By default, the Blackfin hardware errors are not exact - the error
+          be reported multiple cycles after the error happens. This delay
+         can cause the wrong application, or even the kernel to receive a
+         signal to be killed. If you are getting HW errors in your system,
+         try turning this on to ensure they are at least comming from the
+         proper thread.
+
+         On production systems, it is safe (and a small optimization) to say N.
+
 config DEBUG_DOUBLEFAULT
        bool "Debug Double Faults"
        default n
index c121d6e6e2b8d0bbe98860ef50e092b4d5492bf0..baec1337f2823c15223a92df63602024f64114c4 100644 (file)
@@ -1,6 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.7
+# Linux kernel version: 2.6.28.10
+# Thu May 21 05:50:01 2009
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -42,10 +43,11 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -53,16 +55,15 @@ CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 # CONFIG_ELF_CORE is not set
-CONFIG_COMPAT_BRK=y
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
@@ -71,7 +72,6 @@ CONFIG_SLAB=y
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
 CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
@@ -259,7 +259,10 @@ CONFIG_HZ=250
 # CONFIG_SCHED_HRTICK is not set
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_TICKSOURCE_GPTMR0 is not set
+CONFIG_TICKSOURCE_CORETMR=y
 # CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_GPTMR0_CLOCKSOURCE is not set
 # CONFIG_NO_HZ is not set
 # CONFIG_HIGH_RES_TIMERS is not set
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
@@ -404,7 +407,7 @@ CONFIG_IP_PNP=y
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -688,14 +691,14 @@ CONFIG_INPUT_MISC=y
 # Character devices
 #
 # CONFIG_AD9960 is not set
-# CONFIG_SPI_ADC_BF533 is not set
-# CONFIG_BF5xx_PPIFCD is not set
+CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_PPI is not set
+# CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
-# CONFIG_BF5xx_PPI is not set
+# CONFIG_BFIN_SPI_ADC is not set
 # CONFIG_BFIN_SPORT is not set
 # CONFIG_BFIN_TIMER_LATENCY is not set
-# CONFIG_TWI_LCD is not set
-CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_TWI_LCD is not set
 CONFIG_SIMPLE_GPIO=m
 CONFIG_VT=y
 CONFIG_CONSOLE_TRANSLATIONS=y
@@ -802,7 +805,30 @@ CONFIG_SPI_BFIN=y
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-# CONFIG_GPIOLIB is not set
+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_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
@@ -831,6 +857,7 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_HTC_PASIC3 is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
 # CONFIG_MFD_WM8400 is not set
 # CONFIG_MFD_WM8350_I2C is not set
 # CONFIG_REGULATOR is not set
@@ -962,7 +989,8 @@ CONFIG_RTC_DRV_BFIN=y
 #
 # File systems
 #
-# CONFIG_EXT2_FS is not set
+CONFIG_EXT2_FS=m
+# CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT3_FS is not set
 # CONFIG_EXT4_FS is not set
 # CONFIG_REISERFS_FS is not set
@@ -988,8 +1016,11 @@ CONFIG_INOTIFY_USER=y
 #
 # DOS/FAT/NT Filesystems
 #
+CONFIG_FAT_FS=m
 # CONFIG_MSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # CONFIG_NTFS_FS is not set
 
 #
@@ -1012,8 +1043,8 @@ CONFIG_SYSFS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-# CONFIG_YAFFS_FS is not set
 # CONFIG_JFFS2_FS is not set
+# CONFIG_YAFFS_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
@@ -1048,9 +1079,9 @@ CONFIG_SMB_FS=m
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-CONFIG_NLS=y
+CONFIG_NLS=m
 CONFIG_NLS_DEFAULT="iso8859-1"
-CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_437=m
 # CONFIG_NLS_CODEPAGE_737 is not set
 # CONFIG_NLS_CODEPAGE_775 is not set
 # CONFIG_NLS_CODEPAGE_850 is not set
@@ -1065,7 +1096,7 @@ CONFIG_NLS_CODEPAGE_437=y
 # 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_936=m
 # CONFIG_NLS_CODEPAGE_950 is not set
 # CONFIG_NLS_CODEPAGE_932 is not set
 # CONFIG_NLS_CODEPAGE_949 is not set
@@ -1074,7 +1105,7 @@ CONFIG_NLS_CODEPAGE_437=y
 # 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_1=m
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
 # CONFIG_NLS_ISO8859_4 is not set
@@ -1087,7 +1118,7 @@ CONFIG_NLS_ISO8859_1=y
 # 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_NLS_UTF8=m
 # CONFIG_DLM is not set
 
 #
@@ -1102,7 +1133,7 @@ CONFIG_FRAME_WARN=1024
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
@@ -1111,8 +1142,6 @@ CONFIG_SCHED_DEBUG=y
 # CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_OBJECTS is not set
 # CONFIG_DEBUG_SLAB 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_SPINLOCK_SLEEP is not set
@@ -1132,7 +1161,6 @@ CONFIG_DEBUG_INFO=y
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_FAULT_INJECTION is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 
 #
 # Tracers
@@ -1148,16 +1176,20 @@ CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_VERBOSE=y
 CONFIG_DEBUG_MMRS=y
-# CONFIG_DEBUG_HWERR is not set
-# CONFIG_DEBUG_DOUBLEFAULT is not set
+CONFIG_DEBUG_HWERR=y
+CONFIG_EXACT_HWERR=y
+CONFIG_DEBUG_DOUBLEFAULT=y
+CONFIG_DEBUG_DOUBLEFAULT_PRINT=y
+# CONFIG_DEBUG_DOUBLEFAULT_RESET is not set
+# CONFIG_DEBUG_ICACHE_CHECK is not set
 CONFIG_DEBUG_HUNT_FOR_ZERO=y
 CONFIG_DEBUG_BFIN_HWTRACE_ON=y
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
-# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 # CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=1
 # CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
-# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
 CONFIG_ACCESS_CHECK=y
@@ -1269,7 +1301,6 @@ CONFIG_CRC32=y
 # CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
-CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
index 3e562b2775d4b5221b839cca0629bd933f4b21ca..c06262e41f7c9058b8a61a8cf2dff01ae215d3f2 100644 (file)
@@ -1,6 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.7
+# Linux kernel version: 2.6.28.10
+# Thu May 21 05:50:01 2009
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -42,10 +43,11 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -53,16 +55,15 @@ CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 # CONFIG_ELF_CORE is not set
-CONFIG_COMPAT_BRK=y
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
@@ -71,7 +72,6 @@ CONFIG_SLAB=y
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
 CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
@@ -144,8 +144,8 @@ CONFIG_BF526=y
 # CONFIG_BF561 is not set
 CONFIG_BF_REV_MIN=0
 CONFIG_BF_REV_MAX=2
-# CONFIG_BF_REV_0_0 is not set
-CONFIG_BF_REV_0_1=y
+CONFIG_BF_REV_0_0=y
+# CONFIG_BF_REV_0_1 is not set
 # CONFIG_BF_REV_0_2 is not set
 # CONFIG_BF_REV_0_3 is not set
 # CONFIG_BF_REV_0_4 is not set
@@ -264,7 +264,10 @@ CONFIG_HZ=250
 # CONFIG_SCHED_HRTICK is not set
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_TICKSOURCE_GPTMR0 is not set
+CONFIG_TICKSOURCE_CORETMR=y
 # CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_GPTMR0_CLOCKSOURCE is not set
 # CONFIG_NO_HZ is not set
 # CONFIG_HIGH_RES_TIMERS is not set
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
@@ -409,7 +412,7 @@ CONFIG_IP_PNP=y
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -491,7 +494,7 @@ CONFIG_MTD_PARTITIONS=y
 #
 # User Modules And Translation Layers
 #
-CONFIG_MTD_CHAR=m
+CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLKDEVS=y
 CONFIG_MTD_BLOCK=y
 # CONFIG_FTL is not set
@@ -504,9 +507,9 @@ CONFIG_MTD_BLOCK=y
 #
 # RAM/ROM/Flash chip drivers
 #
-# CONFIG_MTD_CFI is not set
-CONFIG_MTD_JEDECPROBE=m
-CONFIG_MTD_GEN_PROBE=m
+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
@@ -518,9 +521,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 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=y
 CONFIG_MTD_ROM=m
 # CONFIG_MTD_ABSENT is not set
@@ -529,7 +533,8 @@ CONFIG_MTD_ROM=m
 # Mapping drivers for chip access
 #
 CONFIG_MTD_COMPLEX_MAPPINGS=y
-# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
 # CONFIG_MTD_GPIO_ADDR is not set
 # CONFIG_MTD_UCLINUX is not set
 # CONFIG_MTD_PLATRAM is not set
@@ -597,9 +602,42 @@ CONFIG_HAVE_IDE=y
 # SCSI device support
 #
 # CONFIG_RAID_ATTRS is not set
-# CONFIG_SCSI is not set
-# CONFIG_SCSI_DMA 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=m
+# CONFIG_BLK_DEV_SR_VENDOR 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
+# 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_ATA is not set
 # CONFIG_MD is not set
 CONFIG_NETDEVICES=y
@@ -644,9 +682,8 @@ CONFIG_BFIN_MAC_RMII=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_NETDEV_1000=y
-# CONFIG_AX88180 is not set
-CONFIG_NETDEV_10000=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
@@ -715,14 +752,14 @@ CONFIG_INPUT_MISC=y
 # Character devices
 #
 # CONFIG_AD9960 is not set
-# CONFIG_SPI_ADC_BF533 is not set
-# CONFIG_BF5xx_PPIFCD is not set
+CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_PPI is not set
+# CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
-# CONFIG_BF5xx_PPI is not set
+# CONFIG_BFIN_SPI_ADC is not set
 # CONFIG_BFIN_SPORT is not set
 # CONFIG_BFIN_TIMER_LATENCY is not set
-# CONFIG_TWI_LCD is not set
-CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_TWI_LCD is not set
 CONFIG_SIMPLE_GPIO=m
 CONFIG_VT=y
 CONFIG_CONSOLE_TRANSLATIONS=y
@@ -832,11 +869,35 @@ CONFIG_SPI_BFIN=y
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-# CONFIG_GPIOLIB is not set
+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_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD5252 is not set
 # CONFIG_SENSORS_AD7414 is not set
 # CONFIG_SENSORS_AD7418 is not set
 # CONFIG_SENSORS_ADCXX is not set
@@ -920,6 +981,7 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_HTC_PASIC3 is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
 # CONFIG_MFD_WM8400 is not set
 # CONFIG_MFD_WM8350_I2C is not set
 # CONFIG_REGULATOR is not set
@@ -1008,8 +1070,8 @@ CONFIG_USB=y
 #
 # Miscellaneous USB options
 #
-# CONFIG_USB_DEVICEFS is not set
-CONFIG_USB_DEVICE_CLASS=y
+CONFIG_USB_DEVICEFS=y
+# 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
@@ -1037,10 +1099,10 @@ CONFIG_USB_MUSB_SOC=y
 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=y
-CONFIG_MUSB_DMA_POLL=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
 
 #
@@ -1058,7 +1120,7 @@ CONFIG_MUSB_DMA_POLL=y
 #
 # see USB_STORAGE Help for more information
 #
-CONFIG_USB_STORAGE=m
+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
@@ -1107,33 +1169,10 @@ CONFIG_USB_STORAGE=m
 # 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
-# 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_PXA27X 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_NET2272 is not set
-# CONFIG_USB_GADGET_NET2280 is not set
-# CONFIG_USB_GADGET_GOKU is not set
-# CONFIG_USB_GADGET_DUMMY_HCD is not set
-# CONFIG_USB_ZERO 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
 # CONFIG_MMC is not set
 # CONFIG_MEMSTICK is not set
 # CONFIG_NEW_LEDS is not set
@@ -1206,7 +1245,8 @@ CONFIG_RTC_DRV_BFIN=y
 #
 # File systems
 #
-# CONFIG_EXT2_FS is not set
+CONFIG_EXT2_FS=m
+# CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT3_FS is not set
 # CONFIG_EXT4_FS is not set
 # CONFIG_REISERFS_FS is not set
@@ -1226,14 +1266,19 @@ CONFIG_INOTIFY_USER=y
 #
 # CD-ROM/DVD Filesystems
 #
-# CONFIG_ISO9660_FS is not set
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
 # CONFIG_UDF_FS is not set
 
 #
 # DOS/FAT/NT Filesystems
 #
+CONFIG_FAT_FS=m
 # CONFIG_MSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # CONFIG_NTFS_FS is not set
 
 #
@@ -1256,16 +1301,6 @@ CONFIG_SYSFS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-CONFIG_YAFFS_FS=m
-CONFIG_YAFFS_YAFFS1=y
-# CONFIG_YAFFS_9BYTE_TAGS is not set
-# CONFIG_YAFFS_DOES_ECC is not set
-CONFIG_YAFFS_YAFFS2=y
-CONFIG_YAFFS_AUTO_YAFFS2=y
-# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
-# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
-# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
-CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 CONFIG_JFFS2_FS=m
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -1277,6 +1312,16 @@ CONFIG_JFFS2_ZLIB=y
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
+CONFIG_YAFFS_FS=m
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
@@ -1313,7 +1358,7 @@ CONFIG_SMB_FS=m
 CONFIG_MSDOS_PARTITION=y
 CONFIG_NLS=m
 CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
+CONFIG_NLS_CODEPAGE_437=m
 # CONFIG_NLS_CODEPAGE_737 is not set
 # CONFIG_NLS_CODEPAGE_775 is not set
 # CONFIG_NLS_CODEPAGE_850 is not set
@@ -1328,7 +1373,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # 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_936=m
 # CONFIG_NLS_CODEPAGE_950 is not set
 # CONFIG_NLS_CODEPAGE_932 is not set
 # CONFIG_NLS_CODEPAGE_949 is not set
@@ -1337,7 +1382,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
 # CONFIG_NLS_ASCII is not set
-# CONFIG_NLS_ISO8859_1 is not set
+CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
 # CONFIG_NLS_ISO8859_4 is not set
@@ -1350,7 +1395,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # 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_NLS_UTF8=m
 # CONFIG_DLM is not set
 
 #
@@ -1365,7 +1410,7 @@ CONFIG_FRAME_WARN=1024
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
@@ -1374,8 +1419,6 @@ CONFIG_SCHED_DEBUG=y
 # CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_OBJECTS is not set
 # CONFIG_DEBUG_SLAB 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_SPINLOCK_SLEEP is not set
@@ -1395,7 +1438,6 @@ CONFIG_DEBUG_INFO=y
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_FAULT_INJECTION is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 
 #
 # Tracers
@@ -1411,16 +1453,20 @@ CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_VERBOSE=y
 CONFIG_DEBUG_MMRS=y
-# CONFIG_DEBUG_HWERR is not set
-# CONFIG_DEBUG_DOUBLEFAULT is not set
+CONFIG_DEBUG_HWERR=y
+CONFIG_EXACT_HWERR=y
+CONFIG_DEBUG_DOUBLEFAULT=y
+CONFIG_DEBUG_DOUBLEFAULT_PRINT=y
+# CONFIG_DEBUG_DOUBLEFAULT_RESET is not set
+# CONFIG_DEBUG_ICACHE_CHECK is not set
 CONFIG_DEBUG_HUNT_FOR_ZERO=y
 CONFIG_DEBUG_BFIN_HWTRACE_ON=y
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
-# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 # CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=1
 # CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
-# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
 CONFIG_ACCESS_CHECK=y
@@ -1534,7 +1580,6 @@ CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
-CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
index 911b5dba1dbc5022e9fd1b37301f4be13e136a9b..e9175c608aa7175c9ef8f8b72ec423200cdf55a7 100644 (file)
@@ -1,6 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.7
+# Linux kernel version: 2.6.28.10
+# Thu May 21 05:50:01 2009
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -42,10 +43,11 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -53,16 +55,15 @@ CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 # CONFIG_ELF_CORE is not set
-CONFIG_COMPAT_BRK=y
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
@@ -71,7 +72,6 @@ CONFIG_SLAB=y
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
 CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
@@ -145,8 +145,8 @@ CONFIG_BF527=y
 CONFIG_BF_REV_MIN=0
 CONFIG_BF_REV_MAX=2
 # CONFIG_BF_REV_0_0 is not set
-CONFIG_BF_REV_0_1=y
-# CONFIG_BF_REV_0_2 is not set
+# CONFIG_BF_REV_0_1 is not set
+CONFIG_BF_REV_0_2=y
 # CONFIG_BF_REV_0_3 is not set
 # CONFIG_BF_REV_0_4 is not set
 # CONFIG_BF_REV_0_5 is not set
@@ -264,7 +264,10 @@ CONFIG_HZ=250
 # CONFIG_SCHED_HRTICK is not set
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_TICKSOURCE_GPTMR0 is not set
+CONFIG_TICKSOURCE_CORETMR=y
 # CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_GPTMR0_CLOCKSOURCE is not set
 # CONFIG_NO_HZ is not set
 # CONFIG_HIGH_RES_TIMERS is not set
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
@@ -318,7 +321,7 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
 # CONFIG_PHYS_ADDR_T_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=1
 CONFIG_VIRT_TO_BUS=y
-CONFIG_BFIN_GPTIMERS=m
+CONFIG_BFIN_GPTIMERS=y
 # CONFIG_DMA_UNCACHED_4M is not set
 # CONFIG_DMA_UNCACHED_2M is not set
 CONFIG_DMA_UNCACHED_1M=y
@@ -409,7 +412,7 @@ CONFIG_IP_PNP=y
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -639,9 +642,42 @@ CONFIG_HAVE_IDE=y
 # SCSI device support
 #
 # CONFIG_RAID_ATTRS is not set
-# CONFIG_SCSI is not set
-# CONFIG_SCSI_DMA 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=m
+# CONFIG_BLK_DEV_SR_VENDOR 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
+# 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_ATA is not set
 # CONFIG_MD is not set
 CONFIG_NETDEVICES=y
@@ -687,9 +723,8 @@ CONFIG_BFIN_MAC_RMII=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_NETDEV_1000=y
-# CONFIG_AX88180 is not set
-CONFIG_NETDEV_10000=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
@@ -758,14 +793,14 @@ CONFIG_INPUT_MISC=y
 # Character devices
 #
 # CONFIG_AD9960 is not set
-# CONFIG_SPI_ADC_BF533 is not set
-# CONFIG_BF5xx_PPIFCD is not set
+CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_PPI is not set
+# CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
-CONFIG_BF5xx_PPI=m
+# CONFIG_BFIN_SPI_ADC is not set
 CONFIG_BFIN_SPORT=m
 # CONFIG_BFIN_TIMER_LATENCY is not set
-# CONFIG_TWI_LCD is not set
-CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_TWI_LCD is not set
 CONFIG_SIMPLE_GPIO=m
 CONFIG_VT=y
 CONFIG_CONSOLE_TRANSLATIONS=y
@@ -875,7 +910,30 @@ CONFIG_SPI_BFIN=y
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-# CONFIG_GPIOLIB is not set
+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_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
@@ -909,6 +967,7 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_HTC_PASIC3 is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
 # CONFIG_MFD_WM8400 is not set
 # CONFIG_MFD_WM8350_I2C is not set
 # CONFIG_REGULATOR is not set
@@ -1091,8 +1150,8 @@ CONFIG_USB=y
 #
 # Miscellaneous USB options
 #
-# CONFIG_USB_DEVICEFS is not set
-CONFIG_USB_DEVICE_CLASS=y
+CONFIG_USB_DEVICEFS=y
+# 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
@@ -1120,10 +1179,10 @@ CONFIG_USB_MUSB_SOC=y
 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=y
-CONFIG_MUSB_DMA_POLL=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
 
 #
@@ -1141,7 +1200,7 @@ CONFIG_MUSB_DMA_POLL=y
 #
 # see USB_STORAGE Help for more information
 #
-CONFIG_USB_STORAGE=m
+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
@@ -1190,33 +1249,10 @@ CONFIG_USB_STORAGE=m
 # 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
-# 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_PXA27X 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_NET2272 is not set
-# CONFIG_USB_GADGET_NET2280 is not set
-# CONFIG_USB_GADGET_GOKU is not set
-# CONFIG_USB_GADGET_DUMMY_HCD is not set
-# CONFIG_USB_ZERO 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
 # CONFIG_MMC is not set
 # CONFIG_MEMSTICK is not set
 # CONFIG_NEW_LEDS is not set
@@ -1289,7 +1325,8 @@ CONFIG_RTC_DRV_BFIN=y
 #
 # File systems
 #
-# CONFIG_EXT2_FS is not set
+CONFIG_EXT2_FS=m
+# CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT3_FS is not set
 # CONFIG_EXT4_FS is not set
 # CONFIG_REISERFS_FS is not set
@@ -1309,14 +1346,20 @@ CONFIG_INOTIFY_USER=y
 #
 # CD-ROM/DVD Filesystems
 #
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
 
 #
 # DOS/FAT/NT Filesystems
 #
+CONFIG_FAT_FS=m
 # CONFIG_MSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # CONFIG_NTFS_FS is not set
 
 #
@@ -1339,16 +1382,6 @@ CONFIG_SYSFS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-CONFIG_YAFFS_FS=m
-CONFIG_YAFFS_YAFFS1=y
-# CONFIG_YAFFS_9BYTE_TAGS is not set
-# CONFIG_YAFFS_DOES_ECC is not set
-CONFIG_YAFFS_YAFFS2=y
-CONFIG_YAFFS_AUTO_YAFFS2=y
-# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
-# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
-# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
-CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 CONFIG_JFFS2_FS=m
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -1360,6 +1393,16 @@ CONFIG_JFFS2_ZLIB=y
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
+CONFIG_YAFFS_FS=m
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
@@ -1396,7 +1439,7 @@ CONFIG_SMB_FS=m
 CONFIG_MSDOS_PARTITION=y
 CONFIG_NLS=m
 CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
+CONFIG_NLS_CODEPAGE_437=m
 # CONFIG_NLS_CODEPAGE_737 is not set
 # CONFIG_NLS_CODEPAGE_775 is not set
 # CONFIG_NLS_CODEPAGE_850 is not set
@@ -1411,7 +1454,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # 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_936=m
 # CONFIG_NLS_CODEPAGE_950 is not set
 # CONFIG_NLS_CODEPAGE_932 is not set
 # CONFIG_NLS_CODEPAGE_949 is not set
@@ -1420,7 +1463,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
 # CONFIG_NLS_ASCII is not set
-# CONFIG_NLS_ISO8859_1 is not set
+CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
 # CONFIG_NLS_ISO8859_4 is not set
@@ -1433,7 +1476,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # 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_NLS_UTF8=m
 # CONFIG_DLM is not set
 
 #
@@ -1448,7 +1491,7 @@ CONFIG_FRAME_WARN=1024
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
@@ -1457,8 +1500,6 @@ CONFIG_SCHED_DEBUG=y
 # CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_OBJECTS is not set
 # CONFIG_DEBUG_SLAB 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_SPINLOCK_SLEEP is not set
@@ -1478,7 +1519,6 @@ CONFIG_DEBUG_INFO=y
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_FAULT_INJECTION is not set
-# CONFIG_SYSCTL_SYSCALL_CHECK is not set
 
 #
 # Tracers
@@ -1494,16 +1534,20 @@ CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_VERBOSE=y
 CONFIG_DEBUG_MMRS=y
-# CONFIG_DEBUG_HWERR is not set
-# CONFIG_DEBUG_DOUBLEFAULT is not set
+CONFIG_DEBUG_HWERR=y
+CONFIG_EXACT_HWERR=y
+CONFIG_DEBUG_DOUBLEFAULT=y
+CONFIG_DEBUG_DOUBLEFAULT_PRINT=y
+# CONFIG_DEBUG_DOUBLEFAULT_RESET is not set
+# CONFIG_DEBUG_ICACHE_CHECK is not set
 CONFIG_DEBUG_HUNT_FOR_ZERO=y
 CONFIG_DEBUG_BFIN_HWTRACE_ON=y
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
-# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 # CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=1
 # CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
-# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
 CONFIG_ACCESS_CHECK=y
@@ -1611,13 +1655,12 @@ CONFIG_BITREVERSE=y
 CONFIG_CRC_CCITT=m
 # CONFIG_CRC16 is not set
 # CONFIG_CRC_T10DIF is not set
-# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC_ITU_T=m
 CONFIG_CRC32=y
 # CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
-CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
index 4c41e03efe0f943e3e6d4cbd6a35ce757ba2ecd4..5aa63bafdd624ea1ff4f998e042d777a98c93f2e 100644 (file)
@@ -1,6 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.7
+# Linux kernel version: 2.6.28.10
+# Thu May 21 05:50:01 2009
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -42,10 +43,11 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -53,16 +55,15 @@ CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 # CONFIG_ELF_CORE is not set
-CONFIG_COMPAT_BRK=y
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
@@ -71,7 +72,6 @@ CONFIG_SLAB=y
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
 CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
@@ -225,7 +225,10 @@ CONFIG_HZ=250
 CONFIG_SCHED_HRTICK=y
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_TICKSOURCE_GPTMR0 is not set
+CONFIG_TICKSOURCE_CORETMR=y
 # CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_GPTMR0_CLOCKSOURCE is not set
 CONFIG_TICK_ONESHOT=y
 # CONFIG_NO_HZ is not set
 CONFIG_HIGH_RES_TIMERS=y
@@ -382,7 +385,7 @@ CONFIG_IP_PNP=y
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -613,9 +616,8 @@ CONFIG_SMC91X=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_NETDEV_1000=y
-# CONFIG_AX88180 is not set
-CONFIG_NETDEV_10000=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
@@ -667,13 +669,13 @@ CONFIG_INPUT_EVDEV=m
 # Character devices
 #
 # CONFIG_AD9960 is not set
-# CONFIG_SPI_ADC_BF533 is not set
-# CONFIG_BF5xx_PPIFCD is not set
+CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_PPI is not set
+# CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
-# CONFIG_BF5xx_PPI is not set
+# CONFIG_BFIN_SPI_ADC is not set
 CONFIG_BFIN_SPORT=y
 # CONFIG_BFIN_TIMER_LATENCY is not set
-CONFIG_BFIN_DMA_INTERFACE=m
 CONFIG_SIMPLE_GPIO=m
 # CONFIG_VT is not set
 # CONFIG_DEVKMEM is not set
@@ -729,7 +731,30 @@ CONFIG_SPI_BFIN=y
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-# CONFIG_GPIOLIB is not set
+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_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
@@ -904,16 +929,6 @@ CONFIG_SYSFS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-CONFIG_YAFFS_FS=m
-CONFIG_YAFFS_YAFFS1=y
-# CONFIG_YAFFS_9BYTE_TAGS is not set
-# CONFIG_YAFFS_DOES_ECC is not set
-CONFIG_YAFFS_YAFFS2=y
-CONFIG_YAFFS_AUTO_YAFFS2=y
-# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
-# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
-# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
-CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 CONFIG_JFFS2_FS=m
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -925,6 +940,16 @@ CONFIG_JFFS2_ZLIB=y
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
+CONFIG_YAFFS_FS=m
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
@@ -1013,7 +1038,7 @@ CONFIG_FRAME_WARN=1024
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
@@ -1022,8 +1047,6 @@ CONFIG_SCHED_DEBUG=y
 # CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_OBJECTS is not set
 # CONFIG_DEBUG_SLAB 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_SPINLOCK_SLEEP is not set
@@ -1043,7 +1066,6 @@ CONFIG_DEBUG_INFO=y
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_FAULT_INJECTION is not set
-# CONFIG_SYSCTL_SYSCALL_CHECK is not set
 
 #
 # Tracers
@@ -1059,16 +1081,20 @@ CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_VERBOSE=y
 CONFIG_DEBUG_MMRS=y
-# CONFIG_DEBUG_HWERR is not set
-# CONFIG_DEBUG_DOUBLEFAULT is not set
+CONFIG_DEBUG_HWERR=y
+CONFIG_EXACT_HWERR=y
+CONFIG_DEBUG_DOUBLEFAULT=y
+CONFIG_DEBUG_DOUBLEFAULT_PRINT=y
+# CONFIG_DEBUG_DOUBLEFAULT_RESET is not set
+# CONFIG_DEBUG_ICACHE_CHECK is not set
 CONFIG_DEBUG_HUNT_FOR_ZERO=y
 CONFIG_DEBUG_BFIN_HWTRACE_ON=y
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
-# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 # CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=1
 # CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
-# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
 CONFIG_ACCESS_CHECK=y
@@ -1181,7 +1207,6 @@ CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
-CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
index 9c482cd1b34393ce8f05e724608b34636f97ddc1..fed25329e13ced60cb37c4e75be9e06a5d054b42 100644 (file)
@@ -1,6 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.7
+# Linux kernel version: 2.6.28.10
+# Thu May 21 05:50:01 2009
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -42,10 +43,11 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -53,16 +55,15 @@ CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 # CONFIG_ELF_CORE is not set
-CONFIG_COMPAT_BRK=y
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
@@ -71,7 +72,6 @@ CONFIG_SLAB=y
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
 CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
@@ -225,7 +225,10 @@ CONFIG_HZ=250
 CONFIG_SCHED_HRTICK=y
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_TICKSOURCE_GPTMR0 is not set
+CONFIG_TICKSOURCE_CORETMR=y
 # CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_GPTMR0_CLOCKSOURCE is not set
 CONFIG_TICK_ONESHOT=y
 # CONFIG_NO_HZ is not set
 CONFIG_HIGH_RES_TIMERS=y
@@ -382,7 +385,7 @@ CONFIG_IP_PNP=y
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -618,9 +621,8 @@ CONFIG_SMC91X=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_NETDEV_1000=y
-# CONFIG_AX88180 is not set
-CONFIG_NETDEV_10000=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
@@ -674,14 +676,14 @@ CONFIG_CONFIG_INPUT_PCF8574=m
 # Character devices
 #
 # CONFIG_AD9960 is not set
-# CONFIG_SPI_ADC_BF533 is not set
-# CONFIG_BF5xx_PPIFCD is not set
+CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_PPI is not set
+# CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
-CONFIG_BF5xx_PPI=m
+# CONFIG_BFIN_SPI_ADC is not set
 CONFIG_BFIN_SPORT=m
 # CONFIG_BFIN_TIMER_LATENCY is not set
-# CONFIG_TWI_LCD is not set
-CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_TWI_LCD is not set
 CONFIG_SIMPLE_GPIO=m
 # CONFIG_VT is not set
 # CONFIG_DEVKMEM is not set
@@ -781,7 +783,30 @@ CONFIG_SPI_BFIN=y
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-# CONFIG_GPIOLIB is not set
+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_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
@@ -1068,16 +1093,6 @@ CONFIG_SYSFS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-CONFIG_YAFFS_FS=m
-CONFIG_YAFFS_YAFFS1=y
-# CONFIG_YAFFS_9BYTE_TAGS is not set
-# CONFIG_YAFFS_DOES_ECC is not set
-CONFIG_YAFFS_YAFFS2=y
-CONFIG_YAFFS_AUTO_YAFFS2=y
-# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
-# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
-# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
-CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 CONFIG_JFFS2_FS=m
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -1089,6 +1104,16 @@ CONFIG_JFFS2_ZLIB=y
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
+CONFIG_YAFFS_FS=m
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
@@ -1177,7 +1202,7 @@ CONFIG_FRAME_WARN=1024
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
@@ -1186,8 +1211,6 @@ CONFIG_SCHED_DEBUG=y
 # CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_OBJECTS is not set
 # CONFIG_DEBUG_SLAB 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_SPINLOCK_SLEEP is not set
@@ -1207,7 +1230,6 @@ CONFIG_DEBUG_INFO=y
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_FAULT_INJECTION is not set
-# CONFIG_SYSCTL_SYSCALL_CHECK is not set
 
 #
 # Tracers
@@ -1223,16 +1245,20 @@ CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_VERBOSE=y
 CONFIG_DEBUG_MMRS=y
-# CONFIG_DEBUG_HWERR is not set
-# CONFIG_DEBUG_DOUBLEFAULT is not set
+CONFIG_DEBUG_HWERR=y
+CONFIG_EXACT_HWERR=y
+CONFIG_DEBUG_DOUBLEFAULT=y
+CONFIG_DEBUG_DOUBLEFAULT_PRINT=y
+# CONFIG_DEBUG_DOUBLEFAULT_RESET is not set
+# CONFIG_DEBUG_ICACHE_CHECK is not set
 CONFIG_DEBUG_HUNT_FOR_ZERO=y
 CONFIG_DEBUG_BFIN_HWTRACE_ON=y
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
-# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 # CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=1
 # CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
-# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
 CONFIG_ACCESS_CHECK=y
@@ -1345,7 +1371,6 @@ CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
-CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
index 591f6edda4f791dedc3011c3042e09e5c460c3ed..f9ac20d55799e81a213f6baa9f76f43bd0589f06 100644 (file)
@@ -1,6 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.7
+# Linux kernel version: 2.6.28.10
+# Thu May 21 05:50:01 2009
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -42,10 +43,11 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -53,16 +55,15 @@ CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 # CONFIG_ELF_CORE is not set
-CONFIG_COMPAT_BRK=y
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
@@ -71,7 +72,6 @@ CONFIG_SLAB=y
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
 CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
@@ -232,7 +232,10 @@ CONFIG_HZ=250
 CONFIG_SCHED_HRTICK=y
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_TICKSOURCE_GPTMR0 is not set
+CONFIG_TICKSOURCE_CORETMR=y
 # CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_GPTMR0_CLOCKSOURCE is not set
 CONFIG_TICK_ONESHOT=y
 # CONFIG_NO_HZ is not set
 CONFIG_HIGH_RES_TIMERS=y
@@ -390,7 +393,7 @@ CONFIG_IP_PNP=y
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -548,9 +551,7 @@ CONFIG_MTD_ROM=m
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
 CONFIG_MTD_PHYSMAP=m
-CONFIG_MTD_PHYSMAP_START=0x20000000
-CONFIG_MTD_PHYSMAP_LEN=0x0
-CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
 # CONFIG_MTD_UCLINUX is not set
 # CONFIG_MTD_PLATRAM is not set
 
@@ -649,9 +650,8 @@ CONFIG_BFIN_RX_DESC_NUM=20
 # 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=y
-# CONFIG_AX88180 is not set
-CONFIG_NETDEV_10000=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
@@ -708,14 +708,14 @@ CONFIG_SERIO_LIBPS2=y
 # Character devices
 #
 # CONFIG_AD9960 is not set
-# CONFIG_SPI_ADC_BF533 is not set
-# CONFIG_BF5xx_PPIFCD is not set
+CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_PPI is not set
+# CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
-CONFIG_BF5xx_PPI=m
+# CONFIG_BFIN_SPI_ADC is not set
 CONFIG_BFIN_SPORT=m
 # CONFIG_BFIN_TIMER_LATENCY is not set
-# CONFIG_TWI_LCD is not set
-CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_TWI_LCD is not set
 CONFIG_SIMPLE_GPIO=m
 # CONFIG_VT is not set
 # CONFIG_DEVKMEM is not set
@@ -823,7 +823,30 @@ CONFIG_SPI_BFIN=y
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-# CONFIG_GPIOLIB is not set
+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_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
@@ -1123,16 +1146,6 @@ CONFIG_SYSFS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-CONFIG_YAFFS_FS=m
-CONFIG_YAFFS_YAFFS1=y
-# CONFIG_YAFFS_9BYTE_TAGS is not set
-# CONFIG_YAFFS_DOES_ECC is not set
-CONFIG_YAFFS_YAFFS2=y
-CONFIG_YAFFS_AUTO_YAFFS2=y
-# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
-# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
-# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
-CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 CONFIG_JFFS2_FS=m
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -1144,6 +1157,16 @@ CONFIG_JFFS2_ZLIB=y
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
+CONFIG_YAFFS_FS=m
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
@@ -1232,7 +1255,7 @@ CONFIG_FRAME_WARN=1024
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
@@ -1241,8 +1264,6 @@ CONFIG_SCHED_DEBUG=y
 # CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_OBJECTS is not set
 # CONFIG_DEBUG_SLAB 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_SPINLOCK_SLEEP is not set
@@ -1262,7 +1283,6 @@ CONFIG_DEBUG_INFO=y
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_FAULT_INJECTION is not set
-# CONFIG_SYSCTL_SYSCALL_CHECK is not set
 
 #
 # Tracers
@@ -1278,16 +1298,20 @@ CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_VERBOSE=y
 CONFIG_DEBUG_MMRS=y
-# CONFIG_DEBUG_HWERR is not set
-# CONFIG_DEBUG_DOUBLEFAULT is not set
+CONFIG_DEBUG_HWERR=y
+CONFIG_EXACT_HWERR=y
+CONFIG_DEBUG_DOUBLEFAULT=y
+CONFIG_DEBUG_DOUBLEFAULT_PRINT=y
+# CONFIG_DEBUG_DOUBLEFAULT_RESET is not set
+# CONFIG_DEBUG_ICACHE_CHECK is not set
 CONFIG_DEBUG_HUNT_FOR_ZERO=y
 CONFIG_DEBUG_BFIN_HWTRACE_ON=y
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
-# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 # CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=1
 # CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
-# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
 CONFIG_ACCESS_CHECK=y
@@ -1400,7 +1424,6 @@ CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
-CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
index 1a8e8c3adf980a0a7fcf4dcb2c9e71d319d7d7a3..ee98e227b887a47435275bb57148be95abcabbad 100644 (file)
@@ -1,6 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.7
+# Linux kernel version: 2.6.28.10
+# Thu May 21 05:50:01 2009
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -42,10 +43,11 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -53,16 +55,15 @@ CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 # CONFIG_ELF_CORE is not set
-CONFIG_COMPAT_BRK=y
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
@@ -71,7 +72,6 @@ CONFIG_SLAB=y
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
 CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
@@ -243,7 +243,10 @@ CONFIG_HZ=250
 CONFIG_SCHED_HRTICK=y
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_TICKSOURCE_GPTMR0 is not set
+CONFIG_TICKSOURCE_CORETMR=y
 # CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_GPTMR0_CLOCKSOURCE is not set
 CONFIG_TICK_ONESHOT=y
 # CONFIG_NO_HZ is not set
 CONFIG_HIGH_RES_TIMERS=y
@@ -389,7 +392,7 @@ CONFIG_IP_PNP=y
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -546,9 +549,7 @@ CONFIG_MTD_ROM=m
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
 CONFIG_MTD_PHYSMAP=m
-CONFIG_MTD_PHYSMAP_START=0x20000000
-CONFIG_MTD_PHYSMAP_LEN=0x0
-CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
 # CONFIG_MTD_UCLINUX is not set
 # CONFIG_MTD_PLATRAM is not set
 
@@ -691,11 +692,11 @@ CONFIG_INPUT_EVDEV=m
 # 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=y
 CONFIG_TOUCHSCREEN_AD7879=y
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
 # CONFIG_TOUCHSCREEN_FUJITSU is not set
 # CONFIG_TOUCHSCREEN_GUNZE is not set
 # CONFIG_TOUCHSCREEN_ELO is not set
@@ -720,14 +721,14 @@ CONFIG_INPUT_MISC=y
 # Character devices
 #
 # CONFIG_AD9960 is not set
-# CONFIG_SPI_ADC_BF533 is not set
-# CONFIG_BF5xx_PPIFCD is not set
+CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_PPI is not set
+# CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
-CONFIG_BF5xx_PPI=m
+# CONFIG_BFIN_SPI_ADC is not set
 CONFIG_BFIN_SPORT=m
 # CONFIG_BFIN_TIMER_LATENCY is not set
-# CONFIG_TWI_LCD is not set
-CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_TWI_LCD is not set
 CONFIG_SIMPLE_GPIO=m
 # CONFIG_VT is not set
 # CONFIG_DEVKMEM is not set
@@ -833,7 +834,30 @@ CONFIG_SPI_BFIN=y
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-# CONFIG_GPIOLIB is not set
+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_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
@@ -1056,16 +1080,6 @@ CONFIG_SYSFS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-CONFIG_YAFFS_FS=m
-CONFIG_YAFFS_YAFFS1=y
-# CONFIG_YAFFS_9BYTE_TAGS is not set
-# CONFIG_YAFFS_DOES_ECC is not set
-CONFIG_YAFFS_YAFFS2=y
-CONFIG_YAFFS_AUTO_YAFFS2=y
-# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
-# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
-# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
-CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 CONFIG_JFFS2_FS=m
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -1077,6 +1091,16 @@ CONFIG_JFFS2_ZLIB=y
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
+CONFIG_YAFFS_FS=m
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
@@ -1165,7 +1189,7 @@ CONFIG_FRAME_WARN=1024
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
@@ -1174,8 +1198,6 @@ CONFIG_SCHED_DEBUG=y
 # CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_OBJECTS is not set
 # CONFIG_DEBUG_SLAB 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_SPINLOCK_SLEEP is not set
@@ -1195,7 +1217,6 @@ CONFIG_DEBUG_INFO=y
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_FAULT_INJECTION is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 
 #
 # Tracers
@@ -1211,16 +1232,20 @@ CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_VERBOSE=y
 CONFIG_DEBUG_MMRS=y
-# CONFIG_DEBUG_HWERR is not set
-# CONFIG_DEBUG_DOUBLEFAULT is not set
+CONFIG_DEBUG_HWERR=y
+CONFIG_EXACT_HWERR=y
+CONFIG_DEBUG_DOUBLEFAULT=y
+CONFIG_DEBUG_DOUBLEFAULT_PRINT=y
+# CONFIG_DEBUG_DOUBLEFAULT_RESET is not set
+# CONFIG_DEBUG_ICACHE_CHECK is not set
 CONFIG_DEBUG_HUNT_FOR_ZERO=y
 CONFIG_DEBUG_BFIN_HWTRACE_ON=y
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
-# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 # CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=1
 # CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
-# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
 CONFIG_ACCESS_CHECK=y
@@ -1333,7 +1358,6 @@ CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
-CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
index 2cd1c2b218d7ce63a6cd64ec449af55262a79c7f..deeabef8ab805a04e0be4cf39b6998b6b7333a65 100644 (file)
@@ -1,6 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.7
+# Linux kernel version: 2.6.28.10
+# Thu May 21 05:50:01 2009
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -42,10 +43,11 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -53,16 +55,15 @@ CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 # CONFIG_ELF_CORE is not set
-CONFIG_COMPAT_BRK=y
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
@@ -71,7 +72,6 @@ CONFIG_SLAB=y
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
 CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
@@ -196,6 +196,7 @@ CONFIG_BFIN548_EZKIT=y
 # BF548 Specific Configuration
 #
 # CONFIG_DEB_DMA_URGENT is not set
+# CONFIG_BF548_ATAPI_ALTERNATIVE_PORT is not set
 
 #
 # Interrupt Priority Assignment
@@ -298,7 +299,10 @@ CONFIG_HZ=250
 # CONFIG_SCHED_HRTICK is not set
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_TICKSOURCE_GPTMR0 is not set
+CONFIG_TICKSOURCE_CORETMR=y
 # CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_GPTMR0_CLOCKSOURCE is not set
 # CONFIG_NO_HZ is not set
 # CONFIG_HIGH_RES_TIMERS is not set
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
@@ -367,7 +371,9 @@ CONFIG_BFIN_DCACHE=y
 # CONFIG_BFIN_ICACHE_LOCK is not set
 CONFIG_BFIN_WB=y
 # CONFIG_BFIN_WT is not set
-# CONFIG_BFIN_L2_CACHEABLE is not set
+# CONFIG_BFIN_L2_WB is not set
+CONFIG_BFIN_L2_WT=y
+# CONFIG_BFIN_L2_NOT_CACHED is not set
 # CONFIG_MPU is not set
 
 #
@@ -447,7 +453,7 @@ CONFIG_IP_PNP=y
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -616,9 +622,7 @@ CONFIG_MTD_RAM=y
 #
 CONFIG_MTD_COMPLEX_MAPPINGS=y
 CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_PHYSMAP_START=0x20000000
-CONFIG_MTD_PHYSMAP_LEN=0
-CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
 # CONFIG_MTD_GPIO_ADDR is not set
 # CONFIG_MTD_UCLINUX is not set
 # CONFIG_MTD_PLATRAM is not set
@@ -696,7 +700,7 @@ CONFIG_SCSI_DMA=y
 CONFIG_BLK_DEV_SD=y
 # CONFIG_CHR_DEV_ST is not set
 # CONFIG_CHR_DEV_OSST is not set
-CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR=m
 # CONFIG_BLK_DEV_SR_VENDOR is not set
 # CONFIG_CHR_DEV_SG is not set
 # CONFIG_CHR_DEV_SCH is not set
@@ -718,9 +722,7 @@ CONFIG_SCSI_WAIT_SCAN=m
 # 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_SCSI_DEBUG is not set
+# CONFIG_SCSI_LOWLEVEL is not set
 # CONFIG_SCSI_DH is not set
 CONFIG_ATA=y
 # CONFIG_ATA_NONSTANDARD is not set
@@ -752,9 +754,8 @@ CONFIG_SMSC911X=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_NETDEV_1000=y
-# CONFIG_AX88180 is not set
-CONFIG_NETDEV_10000=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
@@ -821,11 +822,11 @@ CONFIG_KEYBOARD_BFIN=y
 # 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=m
 # CONFIG_TOUCHSCREEN_AD7879_I2C is not set
 # CONFIG_TOUCHSCREEN_AD7879_SPI is not set
 # CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
 # CONFIG_TOUCHSCREEN_FUJITSU is not set
 # CONFIG_TOUCHSCREEN_GUNZE is not set
 # CONFIG_TOUCHSCREEN_ELO is not set
@@ -858,14 +859,14 @@ CONFIG_INPUT_MISC=y
 # Character devices
 #
 # CONFIG_AD9960 is not set
-# CONFIG_SPI_ADC_BF533 is not set
-# CONFIG_BF5xx_PPIFCD is not set
+CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_PPI is not set
+# CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
-CONFIG_BF5xx_PPI=m
+# CONFIG_BFIN_SPI_ADC is not set
 CONFIG_BFIN_SPORT=m
 # CONFIG_BFIN_TIMER_LATENCY is not set
-# CONFIG_TWI_LCD is not set
-CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_TWI_LCD is not set
 CONFIG_SIMPLE_GPIO=m
 CONFIG_VT=y
 CONFIG_CONSOLE_TRANSLATIONS=y
@@ -977,7 +978,30 @@ CONFIG_SPI_BFIN=y
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-# CONFIG_GPIOLIB is not set
+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_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
@@ -1011,6 +1035,7 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_HTC_PASIC3 is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
 # CONFIG_MFD_WM8400 is not set
 # CONFIG_MFD_WM8350_I2C is not set
 # CONFIG_REGULATOR is not set
@@ -1193,8 +1218,8 @@ CONFIG_USB=y
 #
 # Miscellaneous USB options
 #
-# CONFIG_USB_DEVICEFS is not set
-CONFIG_USB_DEVICE_CLASS=y
+CONFIG_USB_DEVICEFS=y
+# 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
@@ -1222,10 +1247,10 @@ CONFIG_USB_MUSB_SOC=y
 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=y
-CONFIG_MUSB_DMA_POLL=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
 
 #
@@ -1243,7 +1268,7 @@ CONFIG_MUSB_DMA_POLL=y
 #
 # see USB_STORAGE Help for more information
 #
-CONFIG_USB_STORAGE=m
+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
@@ -1292,33 +1317,10 @@ CONFIG_USB_STORAGE=m
 # 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
-# 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_PXA27X 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_NET2272 is not set
-# CONFIG_USB_GADGET_NET2280 is not set
-# CONFIG_USB_GADGET_GOKU is not set
-# CONFIG_USB_GADGET_DUMMY_HCD is not set
-# CONFIG_USB_ZERO 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
 CONFIG_MMC=y
 # CONFIG_MMC_DEBUG is not set
 # CONFIG_MMC_UNSAFE_RESUME is not set
@@ -1414,13 +1416,8 @@ CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 # CONFIG_EXT2_FS_POSIX_ACL is not set
 # CONFIG_EXT2_FS_SECURITY is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT3_FS is not set
 # CONFIG_EXT4_FS is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
@@ -1476,16 +1473,6 @@ CONFIG_SYSFS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-CONFIG_YAFFS_FS=m
-CONFIG_YAFFS_YAFFS1=y
-# CONFIG_YAFFS_9BYTE_TAGS is not set
-# CONFIG_YAFFS_DOES_ECC is not set
-CONFIG_YAFFS_YAFFS2=y
-CONFIG_YAFFS_AUTO_YAFFS2=y
-# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
-# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
-# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
-CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 CONFIG_JFFS2_FS=m
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -1497,6 +1484,16 @@ CONFIG_JFFS2_ZLIB=y
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
+CONFIG_YAFFS_FS=m
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
@@ -1539,63 +1536,47 @@ CONFIG_CIFS=y
 #
 # 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_PARTITION_ADVANCED 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=m
-CONFIG_NLS_CODEPAGE_737=m
-CONFIG_NLS_CODEPAGE_775=m
-CONFIG_NLS_CODEPAGE_850=m
-CONFIG_NLS_CODEPAGE_852=m
-CONFIG_NLS_CODEPAGE_855=m
-CONFIG_NLS_CODEPAGE_857=m
-CONFIG_NLS_CODEPAGE_860=m
-CONFIG_NLS_CODEPAGE_861=m
-CONFIG_NLS_CODEPAGE_862=m
-CONFIG_NLS_CODEPAGE_863=m
-CONFIG_NLS_CODEPAGE_864=m
-CONFIG_NLS_CODEPAGE_865=m
-CONFIG_NLS_CODEPAGE_866=m
-CONFIG_NLS_CODEPAGE_869=m
+# 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=m
-CONFIG_NLS_CODEPAGE_950=m
-CONFIG_NLS_CODEPAGE_932=m
-CONFIG_NLS_CODEPAGE_949=m
-CONFIG_NLS_CODEPAGE_874=m
-CONFIG_NLS_ISO8859_8=m
-CONFIG_NLS_CODEPAGE_1250=m
-CONFIG_NLS_CODEPAGE_1251=m
-CONFIG_NLS_ASCII=m
+# 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=m
-CONFIG_NLS_ISO8859_2=m
-CONFIG_NLS_ISO8859_3=m
-CONFIG_NLS_ISO8859_4=m
-CONFIG_NLS_ISO8859_5=m
-CONFIG_NLS_ISO8859_6=m
-CONFIG_NLS_ISO8859_7=m
-CONFIG_NLS_ISO8859_9=m
-CONFIG_NLS_ISO8859_13=m
-CONFIG_NLS_ISO8859_14=m
-CONFIG_NLS_ISO8859_15=m
-CONFIG_NLS_KOI8_R=m
-CONFIG_NLS_KOI8_U=m
+# 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
 
@@ -1611,7 +1592,7 @@ CONFIG_FRAME_WARN=1024
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
@@ -1620,8 +1601,6 @@ CONFIG_SCHED_DEBUG=y
 # CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_OBJECTS is not set
 # CONFIG_DEBUG_SLAB 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_SPINLOCK_SLEEP is not set
@@ -1641,7 +1620,6 @@ CONFIG_DEBUG_INFO=y
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_FAULT_INJECTION is not set
-# CONFIG_SYSCTL_SYSCALL_CHECK is not set
 
 #
 # Tracers
@@ -1657,16 +1635,20 @@ CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_VERBOSE=y
 CONFIG_DEBUG_MMRS=y
-# CONFIG_DEBUG_HWERR is not set
-# CONFIG_DEBUG_DOUBLEFAULT is not set
+CONFIG_DEBUG_HWERR=y
+CONFIG_EXACT_HWERR=y
+CONFIG_DEBUG_DOUBLEFAULT=y
+CONFIG_DEBUG_DOUBLEFAULT_PRINT=y
+# CONFIG_DEBUG_DOUBLEFAULT_RESET is not set
+# CONFIG_DEBUG_ICACHE_CHECK is not set
 CONFIG_DEBUG_HUNT_FOR_ZERO=y
 CONFIG_DEBUG_BFIN_HWTRACE_ON=y
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
-# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 # CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=1
 # CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
-# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
 CONFIG_ACCESS_CHECK=y
@@ -1780,7 +1762,6 @@ CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
-CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
index 4a6ea8e31df7443e4fdebd0a8cff92aadce18edf..dcfbe2e2931e57105a29a45314d436310360dbe6 100644 (file)
@@ -1,6 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.7
+# Linux kernel version: 2.6.28.10
+# Thu May 21 05:50:01 2009
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -42,10 +43,11 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -53,16 +55,15 @@ CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 # CONFIG_ELF_CORE is not set
-CONFIG_COMPAT_BRK=y
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
@@ -71,7 +72,6 @@ CONFIG_SLAB=y
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
 CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
@@ -148,9 +148,9 @@ CONFIG_BF_REV_MAX=5
 # CONFIG_BF_REV_0_0 is not set
 # CONFIG_BF_REV_0_1 is not set
 # CONFIG_BF_REV_0_2 is not set
-CONFIG_BF_REV_0_3=y
+# CONFIG_BF_REV_0_3 is not set
 # CONFIG_BF_REV_0_4 is not set
-# CONFIG_BF_REV_0_5 is not set
+CONFIG_BF_REV_0_5=y
 # CONFIG_BF_REV_0_6 is not set
 # CONFIG_BF_REV_ANY is not set
 # CONFIG_BF_REV_NONE is not set
@@ -179,7 +179,6 @@ CONFIG_BFIN561_EZKIT=y
 # Core B Support
 #
 CONFIG_BF561_COREB=y
-CONFIG_BF561_COREB_RESET=y
 
 #
 # Interrupt Priority Assignment
@@ -264,7 +263,10 @@ CONFIG_HZ=250
 CONFIG_SCHED_HRTICK=y
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_TICKSOURCE_GPTMR0 is not set
+CONFIG_TICKSOURCE_CORETMR=y
 # CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_GPTMR0_CLOCKSOURCE is not set
 CONFIG_TICK_ONESHOT=y
 # CONFIG_NO_HZ is not set
 CONFIG_HIGH_RES_TIMERS=y
@@ -334,7 +336,9 @@ CONFIG_BFIN_DCACHE=y
 # CONFIG_BFIN_ICACHE_LOCK is not set
 CONFIG_BFIN_WB=y
 # CONFIG_BFIN_WT is not set
-# CONFIG_BFIN_L2_CACHEABLE is not set
+# CONFIG_BFIN_L2_WB is not set
+CONFIG_BFIN_L2_WT=y
+# CONFIG_BFIN_L2_NOT_CACHED is not set
 # CONFIG_MPU is not set
 
 #
@@ -415,7 +419,7 @@ CONFIG_IP_PNP=y
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -570,9 +574,7 @@ CONFIG_MTD_ROM=m
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
 CONFIG_MTD_PHYSMAP=m
-CONFIG_MTD_PHYSMAP_START=0x20000000
-CONFIG_MTD_PHYSMAP_LEN=0x0
-CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
 # CONFIG_MTD_UCLINUX is not set
 # CONFIG_MTD_PLATRAM is not set
 
@@ -649,9 +651,8 @@ CONFIG_SMC91X=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_NETDEV_1000=y
-# CONFIG_AX88180 is not set
-CONFIG_NETDEV_10000=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
@@ -703,13 +704,13 @@ CONFIG_INPUT_EVDEV=m
 # Character devices
 #
 # CONFIG_AD9960 is not set
-# CONFIG_SPI_ADC_BF533 is not set
-# CONFIG_BF5xx_PPIFCD is not set
+CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_PPI is not set
+# CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
-# CONFIG_BF5xx_PPI is not set
+# CONFIG_BFIN_SPI_ADC is not set
 # CONFIG_BFIN_SPORT is not set
 # CONFIG_BFIN_TIMER_LATENCY is not set
-CONFIG_BFIN_DMA_INTERFACE=m
 CONFIG_SIMPLE_GPIO=m
 # CONFIG_VT is not set
 # CONFIG_DEVKMEM is not set
@@ -765,7 +766,30 @@ CONFIG_SPI_BFIN=y
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-# CONFIG_GPIOLIB is not set
+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_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
@@ -897,16 +921,6 @@ CONFIG_SYSFS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-CONFIG_YAFFS_FS=m
-CONFIG_YAFFS_YAFFS1=y
-# CONFIG_YAFFS_9BYTE_TAGS is not set
-# CONFIG_YAFFS_DOES_ECC is not set
-CONFIG_YAFFS_YAFFS2=y
-CONFIG_YAFFS_AUTO_YAFFS2=y
-# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
-# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
-# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
-CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 CONFIG_JFFS2_FS=m
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -918,6 +932,16 @@ CONFIG_JFFS2_ZLIB=y
 # CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
+CONFIG_YAFFS_FS=m
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
@@ -1006,7 +1030,7 @@ CONFIG_FRAME_WARN=1024
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
@@ -1015,8 +1039,6 @@ CONFIG_SCHED_DEBUG=y
 # CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_OBJECTS is not set
 # CONFIG_DEBUG_SLAB 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_SPINLOCK_SLEEP is not set
@@ -1036,7 +1058,6 @@ CONFIG_DEBUG_INFO=y
 # CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_FAULT_INJECTION is not set
-# CONFIG_SYSCTL_SYSCALL_CHECK is not set
 
 #
 # Tracers
@@ -1052,16 +1073,20 @@ CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_VERBOSE=y
 CONFIG_DEBUG_MMRS=y
-# CONFIG_DEBUG_HWERR is not set
-# CONFIG_DEBUG_DOUBLEFAULT is not set
+CONFIG_DEBUG_HWERR=y
+CONFIG_EXACT_HWERR=y
+CONFIG_DEBUG_DOUBLEFAULT=y
+CONFIG_DEBUG_DOUBLEFAULT_PRINT=y
+# CONFIG_DEBUG_DOUBLEFAULT_RESET is not set
+# CONFIG_DEBUG_ICACHE_CHECK is not set
 CONFIG_DEBUG_HUNT_FOR_ZERO=y
 CONFIG_DEBUG_BFIN_HWTRACE_ON=y
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
-# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 # CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
-CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=1
 # CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
-# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
 CONFIG_ACCESS_CHECK=y
@@ -1174,7 +1199,6 @@ CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
-CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
index ef1a2c84ace1614c6f56443baf0cfeac3b024794..174c578b8ec4ffb5165a80fa5660cce933e20d50 100644 (file)
@@ -46,7 +46,7 @@ CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_SYSCTL is not set
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -381,7 +381,7 @@ CONFIG_IP_PNP=y
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
index e2fc588e43364702d3099a043d785c3bc11597cd..e17875e8abe8ff9df259717a015bd3e8a6c35cb7 100644 (file)
@@ -46,7 +46,7 @@ CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_SYSCTL is not set
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -411,7 +411,7 @@ CONFIG_IP_PNP=y
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -783,7 +783,30 @@ CONFIG_SPI_BFIN=y
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-# CONFIG_GPIOLIB is not set
+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_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
index 65a8bbb8d647dc8128ce733dbd24ad05dd90118e..fafd95e84b28c78f95bfa732f04211302972c7ae 100644 (file)
@@ -49,7 +49,7 @@ CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_SYSCTL is not set
 CONFIG_EMBEDDED=y
 # CONFIG_UID16 is not set
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 # CONFIG_HOTPLUG is not set
@@ -347,7 +347,7 @@ CONFIG_IP_FIB_HASH=y
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -547,9 +547,9 @@ CONFIG_MII=y
 CONFIG_SMC91X=y
 # CONFIG_SMSC911X is not set
 # CONFIG_DM9000 is not set
-CONFIG_NETDEV_1000=y
+# CONFIG_NETDEV_1000 is not set
 # CONFIG_AX88180 is not set
-CONFIG_NETDEV_10000=y
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
@@ -641,6 +641,10 @@ CONFIG_UNIX98_PTYS=y
 # CONFIG_TCG_TPM is not set
 # CONFIG_I2C is not set
 
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+
 #
 # SPI support
 #
index 9b7e9d781145a2aef42acdd202dd7a6e99acb5fe..e73aa5af58b9e50285e094cd97f0878c3cd84d51 100644 (file)
@@ -1,6 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22.16
+# Linux kernel version: 2.6.28.10
+# Wed Jun  3 06:27:41 2009
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -8,48 +9,44 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_BLACKFIN=y
 CONFIG_ZONE_DMA=y
-CONFIG_SEMAPHORE_SLEEPERS=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_GPIO=y
 CONFIG_FORCE_MAX_ZONEORDER=14
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
 CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
 # CONFIG_AUDIT is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_CGROUPS is not set
+# CONFIG_GROUP_SCHED 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 is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 # CONFIG_UID16 is not set
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 # CONFIG_HOTPLUG is not set
@@ -58,37 +55,36 @@ CONFIG_BUG=y
 # CONFIG_ELF_CORE is not set
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_EVENTFD=y
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
 CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_BIG_ORDER_ALLOC_NOFAIL_MAGIC=3
-# CONFIG_NP2 is not set
+CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
-CONFIG_RT_MUTEXES=y
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
 CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
 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_KMOD=y
-
-#
-# Block layer
-#
 CONFIG_BLOCK=y
 # CONFIG_LBD is not set
 # CONFIG_BLK_DEV_IO_TRACE is not set
 # CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
 
 #
 # IO Schedulers
@@ -102,9 +98,11 @@ CONFIG_IOSCHED_CFQ=y
 # CONFIG_DEFAULT_CFQ is not set
 CONFIG_DEFAULT_NOOP=y
 CONFIG_DEFAULT_IOSCHED="noop"
+CONFIG_CLASSIC_RCU=y
 CONFIG_PREEMPT_NONE=y
 # CONFIG_PREEMPT_VOLUNTARY is not set
 # CONFIG_PREEMPT is not set
+# CONFIG_FREEZER is not set
 
 #
 # Blackfin Processor Options
@@ -113,6 +111,10 @@ CONFIG_PREEMPT_NONE=y
 #
 # Processor and Board Settings
 #
+# CONFIG_BF512 is not set
+# CONFIG_BF514 is not set
+# CONFIG_BF516 is not set
+# CONFIG_BF518 is not set
 # CONFIG_BF522 is not set
 # CONFIG_BF523 is not set
 # CONFIG_BF524 is not set
@@ -125,22 +127,31 @@ CONFIG_PREEMPT_NONE=y
 # CONFIG_BF534 is not set
 # CONFIG_BF536 is not set
 CONFIG_BF537=y
+# CONFIG_BF538 is not set
+# CONFIG_BF539 is not set
 # CONFIG_BF542 is not set
+# CONFIG_BF542M is not set
 # CONFIG_BF544 is not set
+# CONFIG_BF544M is not set
 # CONFIG_BF547 is not set
+# CONFIG_BF547M is not set
 # CONFIG_BF548 is not set
+# CONFIG_BF548M is not set
 # CONFIG_BF549 is not set
+# CONFIG_BF549M is not set
 # CONFIG_BF561 is not set
+CONFIG_BF_REV_MIN=2
+CONFIG_BF_REV_MAX=3
 # CONFIG_BF_REV_0_0 is not set
 # CONFIG_BF_REV_0_1 is not set
 CONFIG_BF_REV_0_2=y
 # CONFIG_BF_REV_0_3 is not set
 # CONFIG_BF_REV_0_4 is not set
 # CONFIG_BF_REV_0_5 is not set
+# CONFIG_BF_REV_0_6 is not set
 # CONFIG_BF_REV_ANY is not set
 # CONFIG_BF_REV_NONE is not set
 CONFIG_BF53x=y
-CONFIG_BFIN_SINGLE_CORE=y
 CONFIG_MEM_MT48LC16M16A2TG_75=y
 CONFIG_IRQ_PLL_WAKEUP=7
 CONFIG_IRQ_RTC=8
@@ -150,7 +161,6 @@ CONFIG_IRQ_SPORT0_TX=9
 CONFIG_IRQ_SPORT1_RX=9
 CONFIG_IRQ_SPORT1_TX=9
 CONFIG_IRQ_TWI=10
-CONFIG_IRQ_SPI=10
 CONFIG_IRQ_UART0_RX=10
 CONFIG_IRQ_UART0_TX=10
 CONFIG_IRQ_UART1_RX=10
@@ -169,11 +179,12 @@ CONFIG_IRQ_PORTG_INTB=12
 CONFIG_IRQ_MEM_DMA0=13
 CONFIG_IRQ_MEM_DMA1=13
 CONFIG_IRQ_WATCH=13
+CONFIG_IRQ_SPI=10
 # CONFIG_BFIN537_STAMP is not set
 CONFIG_BFIN537_BLUETECHNIX_CM=y
+# CONFIG_BFIN537_BLUETECHNIX_TCM is not set
 # CONFIG_PNAV10 is not set
 # CONFIG_CAMSIG_MINOTAUR is not set
-# CONFIG_GENERIC_BF537_BOARD is not set
 
 #
 # BF537 Specific Configuration
@@ -196,6 +207,7 @@ CONFIG_IRQ_PROG_INTA=12
 # Board customizations
 #
 # CONFIG_CMDLINE_BOOL is not set
+CONFIG_BOOT_LOAD=0x1000
 
 #
 # Clock/PLL Setup
@@ -215,13 +227,20 @@ CONFIG_HZ_250=y
 # CONFIG_HZ_300 is not set
 # CONFIG_HZ_1000 is not set
 CONFIG_HZ=250
+# CONFIG_SCHED_HRTICK is not set
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_TICKSOURCE_GPTMR0 is not set
+CONFIG_TICKSOURCE_CORETMR=y
+# CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_GPTMR0_CLOCKSOURCE is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
 
 #
-# Memory Setup
+# Misc
 #
-CONFIG_MAX_MEM_SIZE=32
-CONFIG_MEM_ADD_WIDTH=9
-CONFIG_BOOT_LOAD=0x1000
 CONFIG_BFIN_SCRATCH_REG_RETN=y
 # CONFIG_BFIN_SCRATCH_REG_RETE is not set
 # CONFIG_BFIN_SCRATCH_REG_CYCLES is not set
@@ -248,6 +267,12 @@ CONFIG_IP_CHECKSUM_L1=y
 CONFIG_CACHELINE_ALIGNED_L1=y
 CONFIG_SYSCALL_TAB_L1=y
 CONFIG_CPLB_SWITCH_TAB_L1=y
+CONFIG_APP_STACK_L1=y
+
+#
+# Speed Optimizations
+#
+CONFIG_BFIN_INS_LOWOVERHEAD=y
 CONFIG_RAMKERNEL=y
 # CONFIG_ROMKERNEL is not set
 CONFIG_SELECT_MEMORY_MODEL=y
@@ -256,12 +281,14 @@ CONFIG_FLATMEM_MANUAL=y
 # CONFIG_SPARSEMEM_MANUAL is not set
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
 # CONFIG_RESOURCES_64BIT is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=1
-CONFIG_LARGE_ALLOCS=y
+CONFIG_VIRT_TO_BUS=y
 # CONFIG_BFIN_GPTIMERS is not set
+# CONFIG_DMA_UNCACHED_4M is not set
 # CONFIG_DMA_UNCACHED_2M is not set
 CONFIG_DMA_UNCACHED_1M=y
 # CONFIG_DMA_UNCACHED_NONE is not set
@@ -275,7 +302,6 @@ CONFIG_BFIN_DCACHE=y
 # CONFIG_BFIN_ICACHE_LOCK is not set
 CONFIG_BFIN_WB=y
 # CONFIG_BFIN_WT is not set
-CONFIG_L1_MAX_PIECE=16
 # CONFIG_MPU is not set
 
 #
@@ -304,13 +330,8 @@ CONFIG_BANK_3=0xFFC2
 #
 # Bus options (PCI, PCMCIA, EISA, MCA, ISA)
 #
-# CONFIG_PCI is not set
 # CONFIG_ARCH_SUPPORTS_MSI is not set
 
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-
 #
 # Executable file formats
 #
@@ -318,22 +339,19 @@ CONFIG_BINFMT_ELF_FDPIC=y
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
 CONFIG_BINFMT_SHARED_FLAT=y
+# CONFIG_HAVE_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
 
 #
 # Power management options
 #
 # CONFIG_PM is not set
-# CONFIG_PM_WAKEUP_BY_GPIO is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
 
 #
 # CPU Frequency scaling
 #
 # CONFIG_CPU_FREQ is not set
-
-#
-# Networking
-#
 CONFIG_NET=y
 
 #
@@ -346,6 +364,7 @@ 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
@@ -358,7 +377,7 @@ CONFIG_IP_PNP=y
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -367,6 +386,7 @@ CONFIG_SYN_COOKIES=y
 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
@@ -374,8 +394,6 @@ CONFIG_TCP_CONG_CUBIC=y
 CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_TCP_MD5SIG is not set
 # CONFIG_IPV6 is not set
-# CONFIG_INET6_XFRM_TUNNEL is not set
-# CONFIG_INET6_TUNNEL is not set
 # CONFIG_NETLABEL is not set
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
@@ -384,6 +402,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # 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
@@ -393,10 +412,6 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_LAPB 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
 
 #
@@ -404,18 +419,14 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 #
 # 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
-
-#
-# Wireless
-#
-# CONFIG_CFG80211 is not set
-# CONFIG_WIRELESS_EXT is not set
-# CONFIG_MAC80211 is not set
-# CONFIG_IEEE80211 is not set
+# CONFIG_PHONET is not set
+# CONFIG_WIRELESS is not set
 # CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -427,10 +438,6 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
 # CONFIG_CONNECTOR is not set
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
@@ -438,6 +445,7 @@ CONFIG_MTD=y
 CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
 # CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
 
 #
 # User Modules And Translation Layers
@@ -450,12 +458,15 @@ CONFIG_MTD_BLOCK=y
 # 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 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
@@ -466,6 +477,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=y
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
@@ -473,7 +488,8 @@ CONFIG_MTD_RAM=y
 #
 # Mapping drivers for chip access
 #
-# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_GPIO_ADDR=y
 CONFIG_MTD_UCLINUX=y
 # CONFIG_MTD_PLATRAM is not set
 
@@ -498,33 +514,23 @@ CONFIG_MTD_UCLINUX=y
 # UBI - Unsorted block images
 #
 # CONFIG_MTD_UBI is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNPACPI is not set
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP 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=4096
-CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_BLK_DEV_XIP is not set
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_C2PORT is not set
+CONFIG_HAVE_IDE=y
 # CONFIG_IDE is not set
 
 #
@@ -532,22 +538,17 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 #
 # 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
-
-#
-# Multi-device support (RAID and LVM)
-#
 # CONFIG_MD is not set
-
-#
-# Network device support
-#
 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
 
 #
@@ -561,46 +562,44 @@ CONFIG_PHYLIB=y
 # 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_FIXED_PHY is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
+# CONFIG_MDIO_BITBANG is not set
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
-# CONFIG_SMC91X is not set
 CONFIG_BFIN_MAC=y
 CONFIG_BFIN_MAC_USE_L1=y
 CONFIG_BFIN_TX_DESC_NUM=10
 CONFIG_BFIN_RX_DESC_NUM=20
 # CONFIG_BFIN_MAC_RMII is not set
+# CONFIG_SMC91X is not set
 # CONFIG_SMSC911X is not set
 # CONFIG_DM9000 is not set
-CONFIG_NETDEV_1000=y
-# CONFIG_AX88180 is not set
-CONFIG_NETDEV_10000=y
+# 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_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
 #
 # CONFIG_WLAN_PRE80211 is not set
 # CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
 # CONFIG_WAN is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
-# CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
@@ -618,15 +617,17 @@ CONFIG_NETDEV_10000=y
 # Character devices
 #
 # CONFIG_AD9960 is not set
-# CONFIG_SPI_ADC_BF533 is not set
-# CONFIG_BF5xx_PFLAGS is not set
-# CONFIG_BF5xx_PPIFCD is not set
+CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_PPI is not set
+# CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
-# CONFIG_BF5xx_PPI is not set
+# CONFIG_BFIN_SPI_ADC is not set
 CONFIG_BFIN_SPORT=y
 # CONFIG_BFIN_TIMER_LATENCY is not set
+# CONFIG_SIMPLE_GPIO is not set
 # CONFIG_VT is not set
 # CONFIG_DEVKMEM is not set
+# CONFIG_BFIN_JTAG_COMM is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
@@ -655,138 +656,119 @@ CONFIG_UNIX98_PTYS=y
 # CAN, the car bus and industrial fieldbus
 #
 # CONFIG_CAN4LINUX is not set
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
-# CONFIG_WATCHDOG is not set
 # CONFIG_HW_RANDOM is not set
-# CONFIG_GEN_RTC 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
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
 
 #
-# TPM devices
+# Memory mapped GPIO expanders:
 #
-# CONFIG_TCG_TPM is not set
-# CONFIG_I2C is not set
 
 #
-# SPI support
+# I2C GPIO expanders:
+#
+
+#
+# PCI GPIO expanders:
 #
-# CONFIG_SPI is not set
-# CONFIG_SPI_MASTER is not set
 
 #
-# Dallas's 1-wire bus
+# SPI GPIO expanders:
 #
 # CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
-# CONFIG_SENSORS_ABITUGURU is not set
 # 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_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_HWMON_DEBUG_CHIP is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON 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_REGULATOR is not set
 
 #
 # Multimedia devices
 #
+
+#
+# Multimedia core support
+#
 # CONFIG_VIDEO_DEV is not set
 # CONFIG_DVB_CORE is not set
-# CONFIG_DAB is not set
+# CONFIG_VIDEO_MEDIA is not set
 
 #
-# Graphics support
+# Multimedia drivers
 #
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_DAB is not set
 
 #
-# Display device support
+# Graphics support
 #
-# CONFIG_DISPLAY_SUPPORT 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
 
 #
-# Sound
+# Display device support
 #
+# CONFIG_DISPLAY_SUPPORT is not set
 # CONFIG_SOUND is not set
-
-#
-# USB support
-#
+CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 # CONFIG_USB_ARCH_HAS_OHCI is not set
 # CONFIG_USB_ARCH_HAS_EHCI is not set
 # CONFIG_USB is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
 
 #
 # Enable Host or Gadget support to see Inventra options
 #
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
-#
-
-#
-# USB Gadget Support
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
 #
 # CONFIG_USB_GADGET is not set
 # CONFIG_MMC is not set
-
-#
-# LED devices
-#
+# CONFIG_MEMSTICK is not set
 # CONFIG_NEW_LEDS is not set
-
-#
-# LED drivers
-#
-
-#
-# LED Triggers
-#
-
-#
-# InfiniBand support
-#
-
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
-#
-# Real Time Clock
-#
+# CONFIG_ACCESSIBILITY is not set
 # CONFIG_RTC_CLASS is not set
-
-#
-# DMA Engine support
-#
-# CONFIG_DMA_ENGINE is not set
-
-#
-# DMA Clients
-#
-
-#
-# DMA Devices
-#
-
-#
-# PBX support
-#
-# CONFIG_PBX is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
 
 #
 # File systems
@@ -796,20 +778,18 @@ CONFIG_EXT2_FS_XATTR=y
 # CONFIG_EXT2_FS_POSIX_ACL is not set
 # CONFIG_EXT2_FS_SECURITY is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_EXT4DEV_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 is not set
+CONFIG_FILE_LOCKING=y
 # CONFIG_XFS_FS is not set
-# CONFIG_GFS2_FS is not set
 # CONFIG_OCFS2_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
+# CONFIG_DNOTIFY is not set
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY_USER=y
 # CONFIG_QUOTA is not set
-# CONFIG_DNOTIFY is not set
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
@@ -835,7 +815,6 @@ CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
 # CONFIG_TMPFS is not set
 # CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
 # CONFIG_CONFIGFS_FS is not set
 
 #
@@ -848,60 +827,53 @@ CONFIG_RAMFS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-# CONFIG_YAFFS_FS is not set
 # CONFIG_JFFS2_FS is not set
+# CONFIG_YAFFS_FS is not set
 # CONFIG_CRAMFS 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_NFS_FS is not set
-# CONFIG_NFSD 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
-# CONFIG_9P_FS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
 
 #
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
 # CONFIG_NLS is not set
-
-#
-# Distributed Lock Manager
-#
 # CONFIG_DLM is not set
 
-#
-# Profiling support
-#
-# CONFIG_PROFILING 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_UNUSED_SYMBOLS is not set
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_SECTION_MISMATCH=y
 # CONFIG_DEBUG_KERNEL is not set
 # CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+
+#
+# Tracers
+#
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_DEBUG_VERBOSE=y
 CONFIG_DEBUG_MMRS=y
+# CONFIG_DEBUG_DOUBLEFAULT is not set
 CONFIG_DEBUG_HUNT_FOR_ZERO=y
 CONFIG_DEBUG_BFIN_HWTRACE_ON=y
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
@@ -919,13 +891,95 @@ CONFIG_ACCESS_CHECK=y
 #
 # CONFIG_KEYS is not set
 CONFIG_SECURITY=y
+# CONFIG_SECURITYFS is not set
 # CONFIG_SECURITY_NETWORK is not set
-CONFIG_SECURITY_CAPABILITIES=y
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+# 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
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C 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 is not set
+# CONFIG_CRYPTO_LZO is not set
 
 #
-# Cryptographic options
+# Random Number Generation
 #
-# CONFIG_CRYPTO is not set
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
 
 #
 # Library routines
@@ -933,11 +987,12 @@ CONFIG_SECURITY_CAPABILITIES=y
 CONFIG_BITREVERSE=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_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
index 569523c1c034113f2c1991403e3d76e2a291f876..80211303f6b9572908aa423d36e11c8523ef0a5a 100644 (file)
@@ -49,7 +49,7 @@ CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_SYSCTL is not set
 CONFIG_EMBEDDED=y
 # CONFIG_UID16 is not set
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 # CONFIG_HOTPLUG is not set
@@ -355,7 +355,7 @@ CONFIG_IP_FIB_HASH=y
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -556,9 +556,9 @@ CONFIG_SMC91X=y
 # CONFIG_BFIN_MAC is not set
 # CONFIG_SMSC911X is not set
 # CONFIG_DM9000 is not set
-CONFIG_NETDEV_1000=y
+# CONFIG_NETDEV_1000 is not set
 # CONFIG_AX88180 is not set
-CONFIG_NETDEV_10000=y
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
@@ -652,6 +652,10 @@ CONFIG_UNIX98_PTYS=y
 # CONFIG_TCG_TPM is not set
 # CONFIG_I2C is not set
 
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+
 #
 # SPI support
 #
index 035b635e599cbd69083ee67ddf94fddfb0c3ac32..dd815f0d15175e13c652b9efb20cb27690d4e949 100644 (file)
@@ -49,7 +49,7 @@ CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_SYSCTL is not set
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_HOTPLUG=y
@@ -125,9 +125,9 @@ CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_BF548=y
 # CONFIG_BF549 is not set
 # CONFIG_BF561 is not set
-CONFIG_BF_REV_0_0=y
+# CONFIG_BF_REV_0_0 is not set
 # CONFIG_BF_REV_0_1 is not set
-# CONFIG_BF_REV_0_2 is not set
+CONFIG_BF_REV_0_2=y
 # CONFIG_BF_REV_0_3 is not set
 # CONFIG_BF_REV_0_4 is not set
 # CONFIG_BF_REV_0_5 is not set
@@ -422,7 +422,7 @@ CONFIG_IP_PNP=y
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -811,6 +811,10 @@ CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=100
 # CONFIG_I2C_DEBUG_BUS is not set
 # CONFIG_I2C_DEBUG_CHIP is not set
 
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+
 #
 # SPI support
 #
index 7015e42ccce5baa5b2d0c7fc5798d2fb06a03ddc..16c198bd40c5347d443f570af4c2ac3bd22d3a11 100644 (file)
@@ -49,7 +49,7 @@ CONFIG_FAIR_USER_SCHED=y
 # CONFIG_SYSCTL is not set
 CONFIG_EMBEDDED=y
 # CONFIG_UID16 is not set
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 # CONFIG_HOTPLUG is not set
@@ -389,7 +389,7 @@ CONFIG_IP_FIB_HASH=y
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -569,9 +569,9 @@ CONFIG_SMC91X=y
 # CONFIG_IBM_NEW_EMAC_TAH is not set
 # CONFIG_IBM_NEW_EMAC_EMAC4 is not set
 # CONFIG_B44 is not set
-CONFIG_NETDEV_1000=y
+# CONFIG_NETDEV_1000 is not set
 # CONFIG_AX88180 is not set
-CONFIG_NETDEV_10000=y
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
@@ -646,6 +646,10 @@ CONFIG_UNIX98_PTYS=y
 # CONFIG_TCG_TPM is not set
 # CONFIG_I2C is not set
 
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+
 #
 # SPI support
 #
index dfc8e1ddd77a63a0aaccdf8d3dcb4ab66ee0fbe2..6b4c1a982383a8f6b0b83ceceabd5c652a05b612 100644 (file)
@@ -48,7 +48,7 @@ CONFIG_SYSFS_DEPRECATED=y
 # CONFIG_SYSCTL is not set
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_HOTPLUG=y
@@ -347,7 +347,7 @@ CONFIG_IP_PNP=y
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -594,8 +594,8 @@ CONFIG_MII=y
 # CONFIG_SMC91X is not set
 # CONFIG_SMSC911X is not set
 CONFIG_DM9000=y
-CONFIG_NETDEV_1000=y
-CONFIG_NETDEV_10000=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
 # CONFIG_AX88180 is not set
 
 #
index 95a5f91aebaa1b3d544b96e50e73bcd21fd1c9f4..1ec9ae2e964b816f17905cac2e70512e6a31aa4f 100644 (file)
@@ -49,7 +49,7 @@ CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_SYSCTL is not set
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 # CONFIG_HOTPLUG is not set
@@ -355,7 +355,7 @@ CONFIG_IP_PNP=y
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -672,9 +672,9 @@ CONFIG_MII=y
 # CONFIG_SMC91X is not set
 # CONFIG_SMSC911X is not set
 CONFIG_DM9000=y
-CONFIG_NETDEV_1000=y
+# CONFIG_NETDEV_1000 is not set
 # CONFIG_AX88180 is not set
-CONFIG_NETDEV_10000=y
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
index 78e24080e7f1821cc96b7a8c254db4b901236690..09701f907e9bafe519eb214af72246738db22fb0 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28.7
+# Linux kernel version: 2.6.28.10
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -40,26 +40,26 @@ CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_NAMESPACES is not set
 # CONFIG_BLK_DEV_INITRD is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 # CONFIG_ELF_CORE is not set
-CONFIG_COMPAT_BRK=y
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
 CONFIG_SIGNALFD=y
 CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 # CONFIG_AIO is not set
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
@@ -68,7 +68,6 @@ CONFIG_SLAB=y
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
 CONFIG_TINY_SHMEM=y
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
@@ -229,7 +228,10 @@ CONFIG_HZ=250
 # CONFIG_SCHED_HRTICK is not set
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_TICKSOURCE_GPTMR0 is not set
+CONFIG_TICKSOURCE_CORETMR=y
 # CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_GPTMR0_CLOCKSOURCE is not set
 # CONFIG_NO_HZ is not set
 # CONFIG_HIGH_RES_TIMERS is not set
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
@@ -374,7 +376,7 @@ CONFIG_IP_PNP=y
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -598,9 +600,8 @@ CONFIG_BFIN_MAC_RMII=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_NETDEV_1000=y
-# CONFIG_AX88180 is not set
-CONFIG_NETDEV_10000=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
@@ -640,11 +641,11 @@ CONFIG_INPUT_EVDEV=y
 # 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=y
 # CONFIG_TOUCHSCREEN_AD7879_I2C is not set
 # CONFIG_TOUCHSCREEN_AD7879_SPI is not set
 # CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
 # CONFIG_TOUCHSCREEN_FUJITSU is not set
 # CONFIG_TOUCHSCREEN_GUNZE is not set
 # CONFIG_TOUCHSCREEN_ELO is not set
@@ -676,14 +677,14 @@ CONFIG_INPUT_UINPUT=y
 # Character devices
 #
 # CONFIG_AD9960 is not set
-# CONFIG_SPI_ADC_BF533 is not set
-# CONFIG_BF5xx_PPIFCD is not set
+CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_PPI is not set
+# CONFIG_BFIN_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
-# CONFIG_BF5xx_PPI is not set
+# CONFIG_BFIN_SPI_ADC is not set
 CONFIG_BFIN_SPORT=y
 # CONFIG_BFIN_TIMER_LATENCY is not set
-CONFIG_TWI_LCD=m
-CONFIG_BFIN_DMA_INTERFACE=m
+# CONFIG_BFIN_TWI_LCD is not set
 # CONFIG_SIMPLE_GPIO is not set
 # CONFIG_VT is not set
 CONFIG_DEVKMEM=y
@@ -796,6 +797,7 @@ CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
 # CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD5252 is not set
 # CONFIG_SENSORS_AD7414 is not set
 # CONFIG_SENSORS_AD7418 is not set
 # CONFIG_SENSORS_ADCXX is not set
@@ -867,6 +869,7 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_HTC_PASIC3 is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
 # CONFIG_MFD_WM8400 is not set
 # CONFIG_MFD_WM8350_I2C is not set
 # CONFIG_REGULATOR is not set
@@ -1111,6 +1114,7 @@ CONFIG_SYSFS=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_YAFFS_FS=y
 CONFIG_YAFFS_YAFFS1=y
 # CONFIG_YAFFS_9BYTE_TAGS is not set
@@ -1121,7 +1125,6 @@ CONFIG_YAFFS_AUTO_YAFFS2=y
 # CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
 # CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
 CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
-# CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
@@ -1213,7 +1216,6 @@ CONFIG_FRAME_WARN=1024
 # CONFIG_DEBUG_BUGVERBOSE is not set
 # CONFIG_DEBUG_MEMORY_INIT is not set
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
-# CONFIG_SYSCTL_SYSCALL_CHECK is not set
 
 #
 # Tracers
@@ -1343,7 +1345,6 @@ CONFIG_CRC32=y
 # CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
-CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
index 2bc0779d22ea49eb48a3f65eb24d55690d17c52f..ec84a53daae928db75b2eab32f341151332e814a 100644 (file)
@@ -52,7 +52,7 @@ CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_SYSCTL is not set
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -373,7 +373,7 @@ CONFIG_IP_PNP=y
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
index e65b3a49214f9ab7d54b40181e6df9899ff99e3b..6e2796240fdc50907d201fb03cf59f9af5d969e0 100644 (file)
@@ -42,7 +42,7 @@ CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_SYSCTL is not set
 CONFIG_EMBEDDED=y
 # CONFIG_UID16 is not set
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 # CONFIG_HOTPLUG is not set
@@ -537,7 +537,30 @@ CONFIG_SPI_BFIN=y
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-# CONFIG_GPIOLIB is not set
+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_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
index 94b2a9b194519a9fb16c50abd761c78de3db85dd..7bbf44e4ddf9642a264396d26eba88e7ce08f842 100644 (file)
@@ -208,6 +208,6 @@ static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
 #define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
 #define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 
 #endif                         /* __ARCH_BLACKFIN_ATOMIC __ */
diff --git a/arch/blackfin/include/asm/bitsperlong.h b/arch/blackfin/include/asm/bitsperlong.h
new file mode 100644 (file)
index 0000000..6dc0bb0
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/bitsperlong.h>
index 1b040f5b4feb10e8fd0a07a5de8933a0bb1e7bf2..94697f0f6f402fc2bf772ca778b96dddf750344d 100644 (file)
@@ -30,7 +30,8 @@
 #ifndef _BLACKFIN_CACHEFLUSH_H
 #define _BLACKFIN_CACHEFLUSH_H
 
-extern void blackfin_icache_dcache_flush_range(unsigned long start_address, unsigned long end_address);
+#include <asm/blackfin.h>      /* for SSYNC() */
+
 extern void blackfin_icache_flush_range(unsigned long start_address, unsigned long end_address);
 extern void blackfin_dcache_flush_range(unsigned long start_address, unsigned long end_address);
 extern void blackfin_dcache_invalidate_range(unsigned long start_address, unsigned long end_address);
@@ -54,32 +55,28 @@ extern void blackfin_invalidate_entire_dcache(void);
 
 static inline void flush_icache_range(unsigned start, unsigned end)
 {
-#if defined(CONFIG_BFIN_DCACHE) && defined(CONFIG_BFIN_ICACHE)
-
-# if defined(CONFIG_BFIN_WT)
-       blackfin_icache_flush_range((start), (end));
-       flush_icache_range_others(start, end);
-# else
-       blackfin_icache_dcache_flush_range((start), (end));
-# endif
-
-#else
+#if defined(CONFIG_BFIN_WB)
+       blackfin_dcache_flush_range(start, end);
+#endif
 
-# if defined(CONFIG_BFIN_ICACHE)
-       blackfin_icache_flush_range((start), (end));
+       /* Make sure all write buffers in the data side of the core
+        * are flushed before trying to invalidate the icache.  This
+        * needs to be after the data flush and before the icache
+        * flush so that the SSYNC does the right thing in preventing
+        * the instruction prefetcher from hitting things in cached
+        * memory at the wrong time -- it runs much further ahead than
+        * the pipeline.
+        */
+       SSYNC();
+#if defined(CONFIG_BFIN_ICACHE)
+       blackfin_icache_flush_range(start, end);
        flush_icache_range_others(start, end);
-# endif
-# if defined(CONFIG_BFIN_DCACHE)
-       blackfin_dcache_flush_range((start), (end));
-# endif
-
 #endif
 }
 
 #define copy_to_user_page(vma, page, vaddr, dst, src, len)             \
 do { memcpy(dst, src, len);                                            \
      flush_icache_range((unsigned) (dst), (unsigned) (dst) + (len));   \
-     flush_icache_range_others((unsigned long) (dst), (unsigned long) (dst) + (len));\
 } while (0)
 
 #define copy_from_user_page(vma, page, vaddr, dst, src, len)   memcpy(dst, src, len)
@@ -111,6 +108,11 @@ static inline int bfin_addr_dcachable(unsigned long addr)
                addr >= _ramend && addr < physical_mem_end)
                return 1;
 
+#ifndef CONFIG_BFIN_L2_NOT_CACHED
+       if (addr >= L2_START && addr < L2_START + L2_LENGTH)
+               return 1;
+#endif
+
        return 0;
 }
 
index ad566ff9ad16fdcf13c9fc84be53a6f040346957..a75a6a9f0949d42e0d3eaf028a5d8f026708a321 100644 (file)
 #define SDRAM_DGENERIC   (CPLB_L1_CHBL | CPLB_WT | CPLB_L1_AOW  | CPLB_COMMON)
 #endif
 
+#define SDRAM_DNON_CHBL  (CPLB_COMMON)
+#define SDRAM_EBIU       (CPLB_COMMON)
+#define SDRAM_OOPS       (CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY)
+
 #define L1_DMEMORY       (CPLB_LOCK | CPLB_COMMON)
 
 #ifdef CONFIG_SMP
-#define L2_ATTR           (INITIAL_T | I_CPLB | D_CPLB)
-#define L2_IMEMORY         (CPLB_COMMON | CPLB_LOCK)
-#define L2_DMEMORY         (CPLB_COMMON | CPLB_LOCK)
+#define L2_ATTR          (INITIAL_T | I_CPLB | D_CPLB)
+#define L2_IMEMORY       (CPLB_COMMON)
+#define L2_DMEMORY       (CPLB_LOCK | CPLB_COMMON)
 
 #else
-#ifdef CONFIG_BFIN_L2_CACHEABLE
-#define L2_IMEMORY        (SDRAM_IGENERIC)
-#define L2_DMEMORY        (SDRAM_DGENERIC)
-#else
-#define L2_IMEMORY        (CPLB_COMMON)
-#define L2_DMEMORY        (CPLB_COMMON)
-#endif /* CONFIG_BFIN_L2_CACHEABLE */
-
-#define L2_ATTR           (INITIAL_T | SWITCH_T | I_CPLB | D_CPLB)
+#define L2_ATTR          (INITIAL_T | SWITCH_T | I_CPLB | D_CPLB)
+#define L2_IMEMORY       (SDRAM_IGENERIC)
+
+# if defined(CONFIG_BFIN_L2_WB)
+# define L2_DMEMORY      (CPLB_L1_CHBL | CPLB_COMMON)
+# elif defined(CONFIG_BFIN_L2_WT)
+# define L2_DMEMORY      (CPLB_L1_CHBL | CPLB_WT | CPLB_L1_AOW  | CPLB_COMMON)
+# elif defined(CONFIG_BFIN_L2_NOT_CACHED)
+# define L2_DMEMORY      (CPLB_COMMON)
+# else
+# define L2_DMEMORY      (0)
+# endif
 #endif /* CONFIG_SMP */
 
-#define SDRAM_DNON_CHBL  (CPLB_COMMON)
-#define SDRAM_EBIU       (CPLB_COMMON)
-#define SDRAM_OOPS       (CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY)
-
 #define SIZE_1K 0x00000400      /* 1K */
 #define SIZE_4K 0x00001000      /* 4K */
 #define SIZE_1M 0x00100000      /* 1M */
index e4f7b8043f025335d4acf2f2dc95c37e58d16ca4..c9a59622e23f65d490087c64f26921ddaf545313 100644 (file)
@@ -206,10 +206,16 @@ static inline unsigned long get_dma_curr_addr(unsigned int channel)
 
 static inline void set_dma_sg(unsigned int channel, struct dmasg *sg, int ndsize)
 {
+       /* Make sure the internal data buffers in the core are drained
+        * so that the DMA descriptors are completely written when the
+        * DMA engine goes to fetch them below.
+        */
+       SSYNC();
+
+       dma_ch[channel].regs->next_desc_ptr = sg;
        dma_ch[channel].regs->cfg =
                (dma_ch[channel].regs->cfg & ~(0xf << 8)) |
                ((ndsize & 0xf) << 8);
-       dma_ch[channel].regs->next_desc_ptr = sg;
 }
 
 static inline int dma_channel_active(unsigned int channel)
@@ -253,5 +259,7 @@ static inline void clear_dma_irqstat(unsigned int channel)
 void *dma_memcpy(void *dest, const void *src, size_t count);
 void *safe_dma_memcpy(void *dest, const void *src, size_t count);
 void blackfin_dma_early_init(void);
+void early_dma_memcpy(void *dest, const void *src, size_t count);
+void early_dma_memcpy_done(void);
 
 #endif
index cdbfcfc30f6a693c170d6db57e80a3af04c5cf50..230e1605d3fbcc60d481c19b7b23b0aed59ab71b 100644 (file)
@@ -55,50 +55,50 @@ do {                                                                                        \
 #define ELF_FDPIC_CORE_EFLAGS  EF_BFIN_FDPIC
 #define ELF_EXEC_PAGESIZE      4096
 
-#define        R_unused0       0       /* relocation type 0 is not defined */
-#define R_pcrel5m2     1       /*LSETUP part a */
-#define R_unused1      2       /* relocation type 2 is not defined */
-#define R_pcrel10      3       /* type 3, if cc jump <target>  */
-#define R_pcrel12_jump 4       /* type 4, jump <target> */
-#define R_rimm16       5       /* type 0x5, rN = <target> */
-#define R_luimm16      6       /* # 0x6, preg.l=<target> Load imm 16 to lower half */
-#define R_huimm16      7       /* # 0x7, preg.h=<target> Load imm 16 to upper half */
-#define R_pcrel12_jump_s 8     /* # 0x8 jump.s <target> */
-#define R_pcrel24_jump_x 9     /* # 0x9 jump.x <target> */
-#define R_pcrel24       10     /* # 0xa call <target> , not expandable */
-#define R_unusedb       11     /* # 0xb not generated */
-#define R_unusedc       12     /* # 0xc  not used */
-#define R_pcrel24_jump_l 13    /*0xd jump.l <target> */
-#define R_pcrel24_call_x 14    /* 0xE, call.x <target> if <target> is above 24 bit limit call through P1 */
-#define R_var_eq_symb    15    /* 0xf, linker should treat it same as 0x12 */
-#define R_byte_data      16    /* 0x10, .byte var = symbol */
-#define R_byte2_data     17    /* 0x11, .byte2 var = symbol */
-#define R_byte4_data     18    /* 0x12, .byte4 var = symbol and .var var=symbol */
-#define R_pcrel11        19    /* 0x13, lsetup part b */
-#define R_unused14      20     /* 0x14, undefined */
-#define R_unused15       21    /* not generated by VDSP 3.5 */
+#define R_BFIN_UNUSED0         0   /* relocation type 0 is not defined */
+#define R_BFIN_PCREL5M2        1   /* LSETUP part a */
+#define R_BFIN_UNUSED1         2   /* relocation type 2 is not defined */
+#define R_BFIN_PCREL10         3   /* type 3, if cc jump <target> */
+#define R_BFIN_PCREL12_JUMP    4   /* type 4, jump <target> */
+#define R_BFIN_RIMM16          5   /* type 0x5, rN = <target> */
+#define R_BFIN_LUIMM16         6   /* # 0x6, preg.l=<target> Load imm 16 to lower half */
+#define R_BFIN_HUIMM16         7   /* # 0x7, preg.h=<target> Load imm 16 to upper half */
+#define R_BFIN_PCREL12_JUMP_S  8   /* # 0x8 jump.s <target> */
+#define R_BFIN_PCREL24_JUMP_X  9   /* # 0x9 jump.x <target> */
+#define R_BFIN_PCREL24         10  /* # 0xa call <target> , not expandable */
+#define R_BFIN_UNUSEDB         11  /* # 0xb not generated */
+#define R_BFIN_UNUSEDC         12  /* # 0xc  not used */
+#define R_BFIN_PCREL24_JUMP_L  13  /* 0xd jump.l <target> */
+#define R_BFIN_PCREL24_CALL_X  14  /* 0xE, call.x <target> if <target> is above 24 bit limit call through P1 */
+#define R_BFIN_VAR_EQ_SYMB     15  /* 0xf, linker should treat it same as 0x12 */
+#define R_BFIN_BYTE_DATA       16  /* 0x10, .byte var = symbol */
+#define R_BFIN_BYTE2_DATA      17  /* 0x11, .byte2 var = symbol */
+#define R_BFIN_BYTE4_DATA      18  /* 0x12, .byte4 var = symbol and .var var=symbol */
+#define R_BFIN_PCREL11         19  /* 0x13, lsetup part b */
+#define R_BFIN_UNUSED14        20  /* 0x14, undefined */
+#define R_BFIN_UNUSED15        21  /* not generated by VDSP 3.5 */
 
 /* arithmetic relocations */
-#define R_push          0xE0
-#define R_const                 0xE1
-#define R_add           0xE2
-#define R_sub           0xE3
-#define R_mult          0xE4
-#define R_div           0xE5
-#define R_mod           0xE6
-#define R_lshift        0xE7
-#define R_rshift        0xE8
-#define R_and           0xE9
-#define R_or            0xEA
-#define R_xor           0xEB
-#define R_land          0xEC
-#define R_lor           0xED
-#define R_len           0xEE
-#define R_neg           0xEF
-#define R_comp          0xF0
-#define R_page          0xF1
-#define R_hwpage        0xF2
-#define R_addr          0xF3
+#define R_BFIN_PUSH            0xE0
+#define R_BFIN_CONST           0xE1
+#define R_BFIN_ADD             0xE2
+#define R_BFIN_SUB             0xE3
+#define R_BFIN_MULT            0xE4
+#define R_BFIN_DIV             0xE5
+#define R_BFIN_MOD             0xE6
+#define R_BFIN_LSHIFT          0xE7
+#define R_BFIN_RSHIFT          0xE8
+#define R_BFIN_AND             0xE9
+#define R_BFIN_OR              0xEA
+#define R_BFIN_XOR             0xEB
+#define R_BFIN_LAND            0xEC
+#define R_BFIN_LOR             0xED
+#define R_BFIN_LEN             0xEE
+#define R_BFIN_NEG             0xEF
+#define R_BFIN_COMP            0xF0
+#define R_BFIN_PAGE            0xF1
+#define R_BFIN_HWPAGE          0xF2
+#define R_BFIN_ADDR            0xF3
 
 /* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
    use of this is to invoke "./ld.so someprog" to test out a new version of
index b30a2968e2741ab75356672581129945128e6525..ec58efc130e677cb5b688b691715e0d4d0a5761c 100644 (file)
 #else
 # define LOAD_IPIPE_IPEND
 #endif
+
+#ifndef CONFIG_EXACT_HWERR
+/* As a debugging aid - we save IPEND when DEBUG_KERNEL is on,
+ * otherwise it is a waste of cycles.
+ */
+# ifndef CONFIG_DEBUG_KERNEL
+#define INTERRUPT_ENTRY(N)                                             \
+    [--sp] = SYSCFG;                                                   \
+    [--sp] = P0;       /*orig_p0*/                                     \
+    [--sp] = R0;       /*orig_r0*/                                     \
+    [--sp] = (R7:0,P5:0);                                              \
+    R0 = (N);                                                          \
+    LOAD_IPIPE_IPEND                                                   \
+    jump __common_int_entry;
+# else /* CONFIG_DEBUG_KERNEL */
 #define INTERRUPT_ENTRY(N)                                             \
     [--sp] = SYSCFG;                                                   \
-                                                                       \
     [--sp] = P0;       /*orig_p0*/                                     \
     [--sp] = R0;       /*orig_r0*/                                     \
     [--sp] = (R7:0,P5:0);                                              \
+    p0.l = lo(IPEND);                                                  \
+    p0.h = hi(IPEND);                                                  \
+    r1 = [p0];                                                         \
     R0 = (N);                                                          \
     LOAD_IPIPE_IPEND                                                   \
     jump __common_int_entry;
+# endif /* CONFIG_DEBUG_KERNEL */
 
 /* For timer interrupts, we need to save IPEND, since the user_mode
-          macro accesses it to determine where to account time.  */
+ *macro accesses it to determine where to account time.
+ */
 #define TIMER_INTERRUPT_ENTRY(N)                                       \
     [--sp] = SYSCFG;                                                   \
-                                                                       \
     [--sp] = P0;       /*orig_p0*/                                     \
     [--sp] = R0;       /*orig_r0*/                                     \
     [--sp] = (R7:0,P5:0);                                              \
     r1 = [p0];                                                         \
     R0 = (N);                                                          \
     jump __common_int_entry;
+#else /* CONFIG_EXACT_HWERR is defined */
+
+/* if we want hardware error to be exact, we need to do a SSYNC (which forces
+ * read/writes to complete to the memory controllers), and check to see that
+ * caused a pending HW error condition. If so, we assume it was caused by user
+ * space, by setting the same interrupt that we are in (so it goes off again)
+ * and context restore, and a RTI (without servicing anything). This should
+ * cause the pending HWERR to fire, and when that is done, this interrupt will
+ * be re-serviced properly.
+ * As you can see by the code - we actually need to do two SSYNCS - one to
+ * make sure the read/writes complete, and another to make sure the hardware
+ * error is recognized by the core.
+ */
+#define INTERRUPT_ENTRY(N)                                             \
+    SSYNC;                                                             \
+    SSYNC;                                                             \
+    [--sp] = SYSCFG;                                                   \
+    [--sp] = P0;       /*orig_p0*/                                     \
+    [--sp] = R0;       /*orig_r0*/                                     \
+    [--sp] = (R7:0,P5:0);                                              \
+    R1 = ASTAT;                                                                \
+    P0.L = LO(ILAT);                                                   \
+    P0.H = HI(ILAT);                                                   \
+    R0 = [P0];                                                         \
+    CC = BITTST(R0, EVT_IVHW_P);                                       \
+    IF CC JUMP 1f;                                                     \
+    ASTAT = R1;                                                                \
+    p0.l = lo(IPEND);                                                  \
+    p0.h = hi(IPEND);                                                  \
+    r1 = [p0];                                                         \
+    R0 = (N);                                                          \
+    LOAD_IPIPE_IPEND                                                   \
+    jump __common_int_entry;                                           \
+1:  ASTAT = R1;                                                                \
+    RAISE N;                                                           \
+    (R7:0, P5:0) = [SP++];                                             \
+    SP += 0x8;                                                         \
+    SYSCFG = [SP++];                                                   \
+    CSYNC;                                                             \
+    RTI;
+
+#define TIMER_INTERRUPT_ENTRY(N)                                       \
+    SSYNC;                                                             \
+    SSYNC;                                                             \
+    [--sp] = SYSCFG;                                                   \
+    [--sp] = P0;       /*orig_p0*/                                     \
+    [--sp] = R0;       /*orig_r0*/                                     \
+    [--sp] = (R7:0,P5:0);                                              \
+    R1 = ASTAT;                                                                \
+    P0.L = LO(ILAT);                                                   \
+    P0.H = HI(ILAT);                                                   \
+    R0 = [P0];                                                         \
+    CC = BITTST(R0, EVT_IVHW_P);                                       \
+    IF CC JUMP 1f;                                                     \
+    ASTAT = R1;                                                                \
+    p0.l = lo(IPEND);                                                  \
+    p0.h = hi(IPEND);                                                  \
+    r1 = [p0];                                                         \
+    R0 = (N);                                                          \
+    jump __common_int_entry;                                           \
+1:  ASTAT = R1;                                                                \
+    RAISE N;                                                           \
+    (R7:0, P5:0) = [SP++];                                             \
+    SP += 0x8;                                                         \
+    SYSCFG = [SP++];                                                   \
+    CSYNC;                                                             \
+    RTI;
+#endif /* CONFIG_EXACT_HWERR */
 
 /* This one pushes RETI without using CLI.  Interrupts are enabled.  */
 #define SAVE_CONTEXT_SYSCALL   save_context_syscall
index b0f847ae4bf48b045a881eedd63b7ff4e30bba29..89f08decb8e0fb0b6e5bf62c3d664d36e83e043e 100644 (file)
@@ -30,6 +30,7 @@
 # else
 #  define MAX_BLACKFIN_GPTIMERS 11
 #  define TIMER8_GROUP_REG      TIMER_ENABLE1
+#  define TIMER_GROUP2          1
 # endif
 # define TIMER0_GROUP_REG       TIMER_ENABLE0
 #endif
 # define MAX_BLACKFIN_GPTIMERS 12
 # define TIMER0_GROUP_REG      TMRS8_ENABLE
 # define TIMER8_GROUP_REG      TMRS4_ENABLE
+# define TIMER_GROUP2          1
 #endif
 /*
  * All others: 3 timers:
  */
+#define TIMER_GROUP1           0
 #if !defined(MAX_BLACKFIN_GPTIMERS)
 # define MAX_BLACKFIN_GPTIMERS 3
 # define TIMER0_GROUP_REG      TIMER_ENABLE
 #define TIMER_ERR_PROG_PER  0x8000
 #define TIMER_ERR_PROG_PW   0xC000
 #define TIMER_EMU_RUN       0x0200
-#define        TIMER_TOGGLE_HI     0x0100
-#define        TIMER_CLK_SEL       0x0080
+#define TIMER_TOGGLE_HI     0x0100
+#define TIMER_CLK_SEL       0x0080
 #define TIMER_OUT_DIS       0x0040
 #define TIMER_TIN_SEL       0x0020
 #define TIMER_IRQ_ENA       0x0010
 
 /* The actual gptimer API */
 
-void     set_gptimer_pwidth    (int timer_id, uint32_t width);
-uint32_t get_gptimer_pwidth    (int timer_id);
-void     set_gptimer_period    (int timer_id, uint32_t period);
-uint32_t get_gptimer_period    (int timer_id);
-uint32_t get_gptimer_count     (int timer_id);
-uint16_t get_gptimer_intr      (int timer_id);
-void     clear_gptimer_intr    (int timer_id);
-uint16_t get_gptimer_over      (int timer_id);
-void     clear_gptimer_over    (int timer_id);
-void     set_gptimer_config    (int timer_id, uint16_t config);
-uint16_t get_gptimer_config    (int timer_id);
-void     set_gptimer_pulse_hi  (int timer_id);
+void     set_gptimer_pwidth(int timer_id, uint32_t width);
+uint32_t get_gptimer_pwidth(int timer_id);
+void     set_gptimer_period(int timer_id, uint32_t period);
+uint32_t get_gptimer_period(int timer_id);
+uint32_t get_gptimer_count(int timer_id);
+int      get_gptimer_intr(int timer_id);
+void     clear_gptimer_intr(int timer_id);
+int      get_gptimer_over(int timer_id);
+void     clear_gptimer_over(int timer_id);
+void     set_gptimer_config(int timer_id, uint16_t config);
+uint16_t get_gptimer_config(int timer_id);
+int      get_gptimer_run(int timer_id);
+void     set_gptimer_pulse_hi(int timer_id);
 void     clear_gptimer_pulse_hi(int timer_id);
-void     enable_gptimers       (uint16_t mask);
-void     disable_gptimers      (uint16_t mask);
-uint16_t get_enabled_gptimers  (void);
-uint32_t get_gptimer_status    (int group);
-void     set_gptimer_status    (int group, uint32_t value);
+void     enable_gptimers(uint16_t mask);
+void     disable_gptimers(uint16_t mask);
+void     disable_gptimers_sync(uint16_t mask);
+uint16_t get_enabled_gptimers(void);
+uint32_t get_gptimer_status(int group);
+void     set_gptimer_status(int group, uint32_t value);
 
 #endif
index 63b2d8c78570170eb0ca4bb5984ad92192fd8fd5..3022b5c96b3769841418ac7ef29e6088ff0a04bb 100644 (file)
@@ -80,19 +80,22 @@ static inline unsigned int readl(const volatile void __iomem *addr)
 #define memcpy_fromio(a,b,c)   memcpy((a),(void *)(b),(c))
 #define memcpy_toio(a,b,c)     memcpy((void *)(a),(b),(c))
 
-#define inb(addr)    readb(addr)
-#define inw(addr)    readw(addr)
-#define inl(addr)    readl(addr)
-#define outb(x,addr) ((void) writeb(x,addr))
-#define outw(x,addr) ((void) writew(x,addr))
-#define outl(x,addr) ((void) writel(x,addr))
-
-#define inb_p(addr)    inb(addr)
-#define inw_p(addr)    inw(addr)
-#define inl_p(addr)    inl(addr)
-#define outb_p(x,addr) outb(x,addr)
-#define outw_p(x,addr) outw(x,addr)
-#define outl_p(x,addr) outl(x,addr)
+/* Convert "I/O port addresses" to actual addresses.  i.e. ugly casts. */
+#define __io(port) ((void *)(unsigned long)(port))
+
+#define inb(port)    readb(__io(port))
+#define inw(port)    readw(__io(port))
+#define inl(port)    readl(__io(port))
+#define outb(x,port) writeb(x,__io(port))
+#define outw(x,port) writew(x,__io(port))
+#define outl(x,port) writel(x,__io(port))
+
+#define inb_p(port)    inb(__io(port))
+#define inw_p(port)    inw(__io(port))
+#define inl_p(port)    inl(__io(port))
+#define outb_p(x,port) outb(x,__io(port))
+#define outw_p(x,port) outw(x,__io(port))
+#define outl_p(x,port) outl(x,__io(port))
 
 #define ioread8_rep(a,d,c)     readsb(a,d,c)
 #define ioread16_rep(a,d,c)    readsw(a,d,c)
index 343b56361ec98db86252f75a3e0f01f07bbea7c1..51d0bf5e2899d4543810e344d842591057b210ee 100644 (file)
 #include <asm/atomic.h>
 #include <asm/traps.h>
 
-#define IPIPE_ARCH_STRING     "1.9-00"
+#define IPIPE_ARCH_STRING     "1.9-01"
 #define IPIPE_MAJOR_NUMBER    1
 #define IPIPE_MINOR_NUMBER    9
-#define IPIPE_PATCH_NUMBER    0
+#define IPIPE_PATCH_NUMBER    1
 
 #ifdef CONFIG_SMP
 #error "I-pipe/blackfin: SMP not implemented"
index 344f6a8c1f22a9cebe0a86f38c3955e30c0032a5..3ea2016a1d4a344e475d09c1154594e8007d0e94 100644 (file)
@@ -81,7 +81,7 @@ extern unsigned long memory_end;
 #define        virt_addr_valid(kaddr)  (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \
                                ((void *)(kaddr) < (void *)memory_end))
 
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif                         /* __ASSEMBLY__ */
 
index a67142740df0b4fa9592ec8c95c8df93dd0d5617..b42555c1431cb5683605af10918389d151aeb708 100644 (file)
@@ -64,8 +64,6 @@ struct blackfin_pda {                 /* Per-processor Data Area */
 
 extern struct blackfin_pda cpu_pda[];
 
-void reserve_pda(void);
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_BLACKFIN_PDA_H */
index 0eece23b41c7c1ddaeb2f04908c20b5c9f16cd0f..3040415523b2120a338321beddb66b2cfdc8f3e1 100644 (file)
@@ -131,8 +131,8 @@ unsigned long get_wchan(struct task_struct *p);
 /* Get the Silicon Revision of the chip */
 static inline uint32_t __pure bfin_revid(void)
 {
-       /* stored in the upper 4 bits */
-       uint32_t revid = bfin_read_CHIPID() >> 28;
+       /* Always use CHIPID, to work around ANOMALY_05000234 */
+       uint32_t revid = (bfin_read_CHIPID() & CHIPID_VERSION) >> 28;
 
 #ifdef CONFIG_BF52x
        /* ANOMALY_05000357
index 87951d25145813e183459d03a15bf7000da69408..2eea907944545aad94b54cba586d2eec1c36ac32 100644 (file)
@@ -104,7 +104,7 @@ typedef unsigned long sigset_t;
 #define MINSIGSTKSZ    2048
 #define SIGSTKSZ       8192
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
index ddc43ce385338054a68a1c50a149c01b53185ce7..589e937ed1ebedfd4e7802ff68316fad0255cc9e 100644 (file)
@@ -37,4 +37,5 @@ extern unsigned long long __bfin_cycles_off;
 extern unsigned int __bfin_cycles_mod;
 #endif
 
+extern void __init setup_core_timer(void);
 #endif
index 3248033531e607b98d823351a3c05910aea5bfce..8894e9ffbb575b51d5e4857fa1e467574d0d12ba 100644 (file)
@@ -59,12 +59,8 @@ static inline int is_in_rom(unsigned long addr)
 #ifndef CONFIG_ACCESS_CHECK
 static inline int _access_ok(unsigned long addr, unsigned long size) { return 1; }
 #else
-#ifdef CONFIG_ACCESS_OK_L1
-extern int _access_ok(unsigned long addr, unsigned long size)__attribute__((l1_text));
-#else
 extern int _access_ok(unsigned long addr, unsigned long size);
 #endif
-#endif
 
 /*
  * The exception table consists of pairs of addresses: the first is the
@@ -83,9 +79,6 @@ struct exception_table_entry {
        unsigned long insn, fixup;
 };
 
-/* Returns 0 if exception not found and fixup otherwise.  */
-extern unsigned long search_exception_table(unsigned long);
-
 /*
  * These are the main single-value transfer routines.  They automatically
  * use the right size if we just have the right pointer type.
@@ -233,16 +226,29 @@ strncpy_from_user(char *dst, const char *src, long count)
 }
 
 /*
- * Return the size of a string (including the ending 0)
+ * Get the size of a string in user space.
+ *   src: The string to measure
+ *     n: The maximum valid length
  *
- * Return 0 on exception, a value greater than N if too long
+ * Get the size of a NUL-terminated string in user space.
+ *
+ * Returns the size of the string INCLUDING the terminating NUL.
+ * On exception, returns 0.
+ * If the string is too long, returns a value greater than n.
  */
-static inline long strnlen_user(const char *src, long n)
+static inline long __must_check strnlen_user(const char *src, long n)
 {
-       return (strlen(src) + 1);
+       if (!access_ok(VERIFY_READ, src, 1))
+               return 0;
+       return strnlen(src, n) + 1;
 }
 
-#define strlen_user(str) strnlen_user(str, 32767)
+static inline long __must_check strlen_user(const char *src)
+{
+       if (!access_ok(VERIFY_READ, src, 1))
+               return 0;
+       return strlen(src) + 1;
+}
 
 /*
  * Zero Userspace
@@ -251,6 +257,8 @@ static inline long strnlen_user(const char *src, long n)
 static inline unsigned long __must_check
 __clear_user(void *to, unsigned long n)
 {
+       if (!access_ok(VERIFY_WRITE, to, n))
+               return n;
        memset(to, 0, n);
        return 0;
 }
index 8531693fb48d8b5cddc10e60b13d3fc5f5b56275..763ed84ba459f3236fd7831075cdb002bd610d96 100644 (file)
 #include <asm/dma.h>
 #include <asm/uaccess.h>
 
+/*
+ * To make sure we work around 05000119 - we always check DMA_DONE bit,
+ * never the DMA_RUN bit
+ */
+
 struct dma_channel dma_ch[MAX_DMA_CHANNELS];
 EXPORT_SYMBOL(dma_ch);
 
@@ -232,6 +237,87 @@ void blackfin_dma_resume(void)
 void __init blackfin_dma_early_init(void)
 {
        bfin_write_MDMA_S0_CONFIG(0);
+       bfin_write_MDMA_S1_CONFIG(0);
+}
+
+void __init early_dma_memcpy(void *pdst, const void *psrc, size_t size)
+{
+       unsigned long dst = (unsigned long)pdst;
+       unsigned long src = (unsigned long)psrc;
+       struct dma_register *dst_ch, *src_ch;
+
+       /* We assume that everything is 4 byte aligned, so include
+        * a basic sanity check
+        */
+       BUG_ON(dst % 4);
+       BUG_ON(src % 4);
+       BUG_ON(size % 4);
+
+       /* Force a sync in case a previous config reset on this channel
+        * occurred.  This is needed so subsequent writes to DMA registers
+        * are not spuriously lost/corrupted.
+        */
+       __builtin_bfin_ssync();
+
+       src_ch = 0;
+       /* Find an avalible memDMA channel */
+       while (1) {
+               if (!src_ch || src_ch == (struct dma_register *)MDMA_S1_NEXT_DESC_PTR) {
+                       dst_ch = (struct dma_register *)MDMA_D0_NEXT_DESC_PTR;
+                       src_ch = (struct dma_register *)MDMA_S0_NEXT_DESC_PTR;
+               } else {
+                       dst_ch = (struct dma_register *)MDMA_D1_NEXT_DESC_PTR;
+                       src_ch = (struct dma_register *)MDMA_S1_NEXT_DESC_PTR;
+               }
+
+               if (!bfin_read16(&src_ch->cfg)) {
+                       break;
+               } else {
+                       if (bfin_read16(&src_ch->irq_status) & DMA_DONE)
+                               bfin_write16(&src_ch->cfg, 0);
+               }
+
+       }
+
+       /* Destination */
+       bfin_write32(&dst_ch->start_addr, dst);
+       bfin_write16(&dst_ch->x_count, size >> 2);
+       bfin_write16(&dst_ch->x_modify, 1 << 2);
+       bfin_write16(&dst_ch->irq_status, DMA_DONE | DMA_ERR);
+
+       /* Source */
+       bfin_write32(&src_ch->start_addr, src);
+       bfin_write16(&src_ch->x_count, size >> 2);
+       bfin_write16(&src_ch->x_modify, 1 << 2);
+       bfin_write16(&src_ch->irq_status, DMA_DONE | DMA_ERR);
+
+       /* Enable */
+       bfin_write16(&src_ch->cfg, DMAEN | WDSIZE_32);
+       bfin_write16(&dst_ch->cfg, WNR | DI_EN | DMAEN | WDSIZE_32);
+
+       /* Since we are atomic now, don't use the workaround ssync */
+       __builtin_bfin_ssync();
+}
+
+void __init early_dma_memcpy_done(void)
+{
+       while ((bfin_read_MDMA_S0_CONFIG() && !(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE)) ||
+              (bfin_read_MDMA_S1_CONFIG() && !(bfin_read_MDMA_D1_IRQ_STATUS() & DMA_DONE)))
+               continue;
+
+       bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
+       bfin_write_MDMA_D1_IRQ_STATUS(DMA_DONE | DMA_ERR);
+       /*
+        * Now that DMA is done, we would normally flush cache, but
+        * i/d cache isn't running this early, so we don't bother,
+        * and just clear out the DMA channel for next time
+        */
+       bfin_write_MDMA_S0_CONFIG(0);
+       bfin_write_MDMA_S1_CONFIG(0);
+       bfin_write_MDMA_D0_CONFIG(0);
+       bfin_write_MDMA_D1_CONFIG(0);
+
+       __builtin_bfin_ssync();
 }
 
 /**
index a0678da405328a3cbef29b65a95ac1f00d524f2a..beffa00a93c3a6e2d98f236e82f1653e232c40e8 100644 (file)
@@ -313,15 +313,6 @@ inline void portmux_setup(unsigned short per)
 # define portmux_setup(...)  do { } while (0)
 #endif
 
-static int __init bfin_gpio_init(void)
-{
-       printk(KERN_INFO "Blackfin GPIO Controller\n");
-
-       return 0;
-}
-arch_initcall(bfin_gpio_init);
-
-
 #ifndef CONFIG_BF54x
 /***********************************************************
 *
@@ -1021,15 +1012,6 @@ int bfin_gpio_irq_request(unsigned gpio, const char *label)
 
        local_irq_save_hw(flags);
 
-       if (unlikely(reserved_gpio_irq_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
-               if (system_state == SYSTEM_BOOTING)
-                       dump_stack();
-               printk(KERN_ERR
-                      "bfin-gpio: GPIO %d is already reserved as gpio-irq !\n",
-                      gpio);
-               local_irq_restore_hw(flags);
-               return -EBUSY;
-       }
        if (unlikely(reserved_peri_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
                if (system_state == SYSTEM_BOOTING)
                        dump_stack();
index 01f917d58b5908e65f3feeda75b89ec9c6fec407..53e893ff708aa547674aaab28c0974c54272f37c 100644 (file)
@@ -16,7 +16,6 @@ EXPORT_SYMBOL(bfin_return_from_exception);
 
 /* All the Blackfin cache functions: mach-common/cache.S */
 EXPORT_SYMBOL(blackfin_dcache_invalidate_range);
-EXPORT_SYMBOL(blackfin_icache_dcache_flush_range);
 EXPORT_SYMBOL(blackfin_icache_flush_range);
 EXPORT_SYMBOL(blackfin_dcache_flush_range);
 EXPORT_SYMBOL(blackfin_dflush_page);
index c6ff947f9d377ff30ec60a343deec485bc4390ae..d5a86c3017f7cfa8ca571f507224ac058881dbc7 100644 (file)
@@ -55,7 +55,14 @@ void __cpuinit bfin_dcache_init(struct cplb_entry *dcplb_tbl)
        }
 
        ctrl = bfin_read_DMEM_CONTROL();
-       ctrl |= DMEM_CNTR;
+
+       /*
+        *  Anomaly notes:
+        *  05000287 - We implement workaround #2 - Change the DMEM_CONTROL
+        *  register, so that the port preferences for DAG0 and DAG1 are set
+        *  to port B
+        */
+       ctrl |= DMEM_CNTR | PORT_PREF0 | (ANOMALY_05000287 ? PORT_PREF1 : 0);
        bfin_write_DMEM_CONTROL(ctrl);
        SSYNC();
 }
index 3e329a6ce041ad79e5429d0e0ea557ca98478569..c006a44527bf7a54907e87afe7ba7cea3201f199 100644 (file)
@@ -64,7 +64,7 @@ void __init generate_cplb_tables_cpu(unsigned int cpu)
        dcplb_tbl[cpu][i_d++].data = SDRAM_OOPS | PAGE_SIZE_1KB;
 
        icplb_tbl[cpu][i_i].addr = 0;
-       icplb_tbl[cpu][i_i++].data = i_cache | CPLB_USER_RD | PAGE_SIZE_1KB;
+       icplb_tbl[cpu][i_i++].data = CPLB_VALID | i_cache | CPLB_USER_RD | PAGE_SIZE_1KB;
 
        /* Cover kernel memory with 4M pages.  */
        addr = 0;
index c6ff947f9d377ff30ec60a343deec485bc4390ae..d5a86c3017f7cfa8ca571f507224ac058881dbc7 100644 (file)
@@ -55,7 +55,14 @@ void __cpuinit bfin_dcache_init(struct cplb_entry *dcplb_tbl)
        }
 
        ctrl = bfin_read_DMEM_CONTROL();
-       ctrl |= DMEM_CNTR;
+
+       /*
+        *  Anomaly notes:
+        *  05000287 - We implement workaround #2 - Change the DMEM_CONTROL
+        *  register, so that the port preferences for DAG0 and DAG1 are set
+        *  to port B
+        */
+       ctrl |= DMEM_CNTR | PORT_PREF0 | (ANOMALY_05000287 ? PORT_PREF1 : 0);
        bfin_write_DMEM_CONTROL(ctrl);
        SSYNC();
 }
index c8ad051742e256f8adae84d935b533582e634310..3302719173ca63ba39656ad5d8a5623c74994993 100644 (file)
@@ -178,25 +178,15 @@ int __init setup_early_printk(char *buf)
 
 asmlinkage void __init init_early_exception_vectors(void)
 {
+       u32 evt;
        SSYNC();
 
        /* cannot program in software:
         * evt0 - emulation (jtag)
         * evt1 - reset
         */
-       bfin_write_EVT2(early_trap);
-       bfin_write_EVT3(early_trap);
-       bfin_write_EVT5(early_trap);
-       bfin_write_EVT6(early_trap);
-       bfin_write_EVT7(early_trap);
-       bfin_write_EVT8(early_trap);
-       bfin_write_EVT9(early_trap);
-       bfin_write_EVT10(early_trap);
-       bfin_write_EVT11(early_trap);
-       bfin_write_EVT12(early_trap);
-       bfin_write_EVT13(early_trap);
-       bfin_write_EVT14(early_trap);
-       bfin_write_EVT15(early_trap);
+       for (evt = EVT2; evt <= EVT15; evt += 4)
+               bfin_write32(evt, early_trap);
        CSYNC();
 
        /* Set all the return from interrupt, exception, NMI to a known place
index 3a3e9615b0027a68c2c2d8e3ffc7386cd0c9dcd3..7281a91d26b5cfc2c328eef44ae327ac753bd6b4 100644 (file)
@@ -189,10 +189,10 @@ void set_gptimer_status(int group, uint32_t value)
 }
 EXPORT_SYMBOL(set_gptimer_status);
 
-uint16_t get_gptimer_intr(int timer_id)
+int get_gptimer_intr(int timer_id)
 {
        tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
-       return (group_regs[BFIN_TIMER_OCTET(timer_id)]->status & timil_mask[timer_id]) ? 1 : 0;
+       return !!(group_regs[BFIN_TIMER_OCTET(timer_id)]->status & timil_mask[timer_id]);
 }
 EXPORT_SYMBOL(get_gptimer_intr);
 
@@ -203,10 +203,10 @@ void clear_gptimer_intr(int timer_id)
 }
 EXPORT_SYMBOL(clear_gptimer_intr);
 
-uint16_t get_gptimer_over(int timer_id)
+int get_gptimer_over(int timer_id)
 {
        tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
-       return (group_regs[BFIN_TIMER_OCTET(timer_id)]->status & tovf_mask[timer_id]) ? 1 : 0;
+       return !!(group_regs[BFIN_TIMER_OCTET(timer_id)]->status & tovf_mask[timer_id]);
 }
 EXPORT_SYMBOL(get_gptimer_over);
 
@@ -217,6 +217,13 @@ void clear_gptimer_over(int timer_id)
 }
 EXPORT_SYMBOL(clear_gptimer_over);
 
+int get_gptimer_run(int timer_id)
+{
+       tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
+       return !!(group_regs[BFIN_TIMER_OCTET(timer_id)]->status & trun_mask[timer_id]);
+}
+EXPORT_SYMBOL(get_gptimer_run);
+
 void set_gptimer_config(int timer_id, uint16_t config)
 {
        tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
@@ -244,7 +251,7 @@ void enable_gptimers(uint16_t mask)
 }
 EXPORT_SYMBOL(enable_gptimers);
 
-void disable_gptimers(uint16_t mask)
+static void _disable_gptimers(uint16_t mask)
 {
        int i;
        uint16_t m = mask;
@@ -253,6 +260,12 @@ void disable_gptimers(uint16_t mask)
                group_regs[i]->disable = m & 0xFF;
                m >>= 8;
        }
+}
+
+void disable_gptimers(uint16_t mask)
+{
+       int i;
+       _disable_gptimers(mask);
        for (i = 0; i < MAX_BLACKFIN_GPTIMERS; ++i)
                if (mask & (1 << i))
                        group_regs[BFIN_TIMER_OCTET(i)]->status |= trun_mask[i];
@@ -260,6 +273,13 @@ void disable_gptimers(uint16_t mask)
 }
 EXPORT_SYMBOL(disable_gptimers);
 
+void disable_gptimers_sync(uint16_t mask)
+{
+       _disable_gptimers(mask);
+       SSYNC();
+}
+EXPORT_SYMBOL(disable_gptimers_sync);
+
 void set_gptimer_pulse_hi(int timer_id)
 {
        tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
index a5de8d45424cda8b29f21d338e6224c94892cb1b..5fc424803a1788409a3b51d479c242d9ee16b6ae 100644 (file)
@@ -167,7 +167,7 @@ int __ipipe_check_root(void)
 void __ipipe_enable_irqdesc(struct ipipe_domain *ipd, unsigned irq)
 {
        struct irq_desc *desc = irq_to_desc(irq);
-       int prio = desc->ic_prio;
+       int prio = __ipipe_get_irq_priority(irq);
 
        desc->depth = 0;
        if (ipd != &ipipe_root &&
@@ -178,8 +178,7 @@ EXPORT_SYMBOL(__ipipe_enable_irqdesc);
 
 void __ipipe_disable_irqdesc(struct ipipe_domain *ipd, unsigned irq)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
-       int prio = desc->ic_prio;
+       int prio = __ipipe_get_irq_priority(irq);
 
        if (ipd != &ipipe_root &&
            atomic_dec_and_test(&__ipipe_irq_lvdepth[prio]))
@@ -310,12 +309,16 @@ int ipipe_trigger_irq(unsigned irq)
 
 asmlinkage void __ipipe_sync_root(void)
 {
+       void (*irq_tail_hook)(void) = (void (*)(void))__ipipe_irq_tail_hook;
        unsigned long flags;
 
        BUG_ON(irqs_disabled());
 
        local_irq_save_hw(flags);
 
+       if (irq_tail_hook)
+               irq_tail_hook();
+
        clear_thread_flag(TIF_IRQ_SYNC);
 
        if (ipipe_root_cpudom_var(irqpend_himask) != 0)
index 401bd32aa499f10be2009a4a622b0e1a530994b4..6e31e935bb31a03fe1cadc78fd1787c0e87b1516 100644 (file)
@@ -59,12 +59,14 @@ static struct irq_chip bad_chip = {
        .unmask = dummy_mask_unmask_irq,
 };
 
+static int bad_stats;
 static struct irq_desc bad_irq_desc = {
        .status = IRQ_DISABLED,
        .chip = &bad_chip,
        .handle_irq = handle_bad_irq,
        .depth = 1,
        .lock = __SPIN_LOCK_UNLOCKED(irq_desc->lock),
+       .kstat_irqs = &bad_stats,
 #ifdef CONFIG_SMP
        .affinity = CPU_MASK_ALL
 #endif
index b163f6d3330d4e0a9317ee116171f9718b5fd45d..da28f796ad7889d43483eef8a3bd3c454ffd89d6 100644 (file)
@@ -466,7 +466,7 @@ static int validate_memory_access_address(unsigned long addr, int size)
        int cpu = raw_smp_processor_id();
 
        if (size < 0)
-               return EFAULT;
+               return -EFAULT;
        if (addr >= 0x1000 && (addr + size) <= physical_mem_end)
                return 0;
        if (addr >= SYSMMR_BASE)
@@ -498,7 +498,7 @@ static int validate_memory_access_address(unsigned long addr, int size)
        if (IN_MEM(addr, size, L2_START, L2_LENGTH))
                return 0;
 
-       return EFAULT;
+       return -EFAULT;
 }
 
 /*
@@ -508,14 +508,15 @@ static int validate_memory_access_address(unsigned long addr, int size)
 int kgdb_mem2hex(char *mem, char *buf, int count)
 {
        char *tmp;
-       int err = 0;
+       int err;
        unsigned char *pch;
        unsigned short mmr16;
        unsigned long mmr32;
        int cpu = raw_smp_processor_id();
 
-       if (validate_memory_access_address((unsigned long)mem, count))
-               return EFAULT;
+       err = validate_memory_access_address((unsigned long)mem, count);
+       if (err)
+               return err;
 
        /*
         * We use the upper half of buf as an intermediate buffer for the
@@ -533,7 +534,7 @@ int kgdb_mem2hex(char *mem, char *buf, int count)
                                *tmp++ = *pch++;
                                tmp -= 2;
                        } else
-                               err = EFAULT;
+                               err = -EFAULT;
                        break;
                case 4:
                        if ((unsigned int)mem % 4 == 0) {
@@ -545,10 +546,10 @@ int kgdb_mem2hex(char *mem, char *buf, int count)
                                *tmp++ = *pch++;
                                tmp -= 4;
                        } else
-                               err = EFAULT;
+                               err = -EFAULT;
                        break;
                default:
-                       err = EFAULT;
+                       err = -EFAULT;
                }
        } else if ((cpu == 0 && IN_MEM(mem, count, L1_CODE_START, L1_CODE_LENGTH))
 #ifdef CONFIG_SMP
@@ -557,7 +558,7 @@ int kgdb_mem2hex(char *mem, char *buf, int count)
                ) {
                /* access L1 instruction SRAM*/
                if (dma_memcpy(tmp, mem, count) == NULL)
-                       err = EFAULT;
+                       err = -EFAULT;
        } else
                err = probe_kernel_read(tmp, mem, count);
 
@@ -585,24 +586,24 @@ int kgdb_ebin2mem(char *buf, char *mem, int count)
        char *tmp_new;
        unsigned short *mmr16;
        unsigned long *mmr32;
-       int err = 0;
-       int size = 0;
+       int err;
+       int size;
        int cpu = raw_smp_processor_id();
 
        tmp_old = tmp_new = buf;
 
-       while (count-- > 0) {
+       for (size = 0; size < count; ++size) {
                if (*tmp_old == 0x7d)
                        *tmp_new = *(++tmp_old) ^ 0x20;
                else
                        *tmp_new = *tmp_old;
                tmp_new++;
                tmp_old++;
-               size++;
        }
 
-       if (validate_memory_access_address((unsigned long)mem, size))
-               return EFAULT;
+       err = validate_memory_access_address((unsigned long)mem, size);
+       if (err)
+               return err;
 
        if ((unsigned int)mem >= SYSMMR_BASE) { /*access MMR registers*/
                switch (size) {
@@ -611,17 +612,17 @@ int kgdb_ebin2mem(char *buf, char *mem, int count)
                                mmr16 = (unsigned short *)buf;
                                *(unsigned short *)mem = *mmr16;
                        } else
-                               return EFAULT;
+                               err = -EFAULT;
                        break;
                case 4:
                        if ((unsigned int)mem % 4 == 0) {
                                mmr32 = (unsigned long *)buf;
                                *(unsigned long *)mem = *mmr32;
                        } else
-                               return EFAULT;
+                               err = -EFAULT;
                        break;
                default:
-                       return EFAULT;
+                       err = -EFAULT;
                }
        } else if ((cpu == 0 && IN_MEM(mem, count, L1_CODE_START, L1_CODE_LENGTH))
 #ifdef CONFIG_SMP
@@ -630,7 +631,7 @@ int kgdb_ebin2mem(char *buf, char *mem, int count)
                ) {
                /* access L1 instruction SRAM */
                if (dma_memcpy(mem, buf, size) == NULL)
-                       err = EFAULT;
+                       err = -EFAULT;
        } else
                err = probe_kernel_write(mem, buf, size);
 
@@ -648,10 +649,12 @@ int kgdb_hex2mem(char *buf, char *mem, int count)
        char *tmp_hex;
        unsigned short *mmr16;
        unsigned long *mmr32;
+       int err;
        int cpu = raw_smp_processor_id();
 
-       if (validate_memory_access_address((unsigned long)mem, count))
-               return EFAULT;
+       err = validate_memory_access_address((unsigned long)mem, count);
+       if (err)
+               return err;
 
        /*
         * We use the upper half of buf as an intermediate buffer for the
@@ -673,17 +676,17 @@ int kgdb_hex2mem(char *buf, char *mem, int count)
                                mmr16 = (unsigned short *)tmp_raw;
                                *(unsigned short *)mem = *mmr16;
                        } else
-                               return EFAULT;
+                               err = -EFAULT;
                        break;
                case 4:
                        if ((unsigned int)mem % 4 == 0) {
                                mmr32 = (unsigned long *)tmp_raw;
                                *(unsigned long *)mem = *mmr32;
                        } else
-                               return EFAULT;
+                               err = -EFAULT;
                        break;
                default:
-                       return EFAULT;
+                       err = -EFAULT;
                }
        } else if ((cpu == 0 && IN_MEM(mem, count, L1_CODE_START, L1_CODE_LENGTH))
 #ifdef CONFIG_SMP
@@ -692,10 +695,11 @@ int kgdb_hex2mem(char *buf, char *mem, int count)
                ) {
                /* access L1 instruction SRAM */
                if (dma_memcpy(mem, tmp_raw, count) == NULL)
-                       return EFAULT;
+                       err = -EFAULT;
        } else
-               return probe_kernel_write(mem, tmp_raw, count);
-       return 0;
+               err = probe_kernel_write(mem, tmp_raw, count);
+
+       return err;
 }
 
 int kgdb_validate_break_address(unsigned long addr)
@@ -715,7 +719,7 @@ int kgdb_validate_break_address(unsigned long addr)
        if (IN_MEM(addr, BREAK_INSTR_SIZE, L2_START, L2_LENGTH))
                return 0;
 
-       return EFAULT;
+       return -EFAULT;
 }
 
 int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr)
index 1bd7f2d018a85892c92ebcb8277e7547727c71fe..d5aee362668838f11d2f924ed47b05e34e4bb835 100644 (file)
@@ -201,8 +201,8 @@ apply_relocate(Elf_Shdr * sechdrs, const char *strtab,
 /*            Arithmetic relocations are handled.                        */
 /*            We do not expect LSETUP to be split and hence is not       */
 /*            handled.                                                   */
-/*            R_byte and R_byte2 are also not handled as the gas         */
-/*            does not generate it.                                      */
+/*            R_BFIN_BYTE and R_BFIN_BYTE2 are also not handled as the   */
+/*            gas does not generate it.                                  */
 /*************************************************************************/
 int
 apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab,
@@ -243,8 +243,8 @@ apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab,
 #endif
                switch (ELF32_R_TYPE(rel[i].r_info)) {
 
-               case R_pcrel24:
-               case R_pcrel24_jump_l:
+               case R_BFIN_PCREL24:
+               case R_BFIN_PCREL24_JUMP_L:
                        /* Add the value, subtract its postition */
                        location16 =
                            (uint16_t *) (sechdrs[sechdrs[relsec].sh_info].
@@ -266,18 +266,18 @@ apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab,
                            (*location16 & 0xff00) | (value >> 16 & 0x00ff);
                        *(location16 + 1) = value & 0xffff;
                        break;
-               case R_pcrel12_jump:
-               case R_pcrel12_jump_s:
+               case R_BFIN_PCREL12_JUMP:
+               case R_BFIN_PCREL12_JUMP_S:
                        value -= (uint32_t) location32;
                        value >>= 1;
                        *location16 = (value & 0xfff);
                        break;
-               case R_pcrel10:
+               case R_BFIN_PCREL10:
                        value -= (uint32_t) location32;
                        value >>= 1;
                        *location16 = (value & 0x3ff);
                        break;
-               case R_luimm16:
+               case R_BFIN_LUIMM16:
                        pr_debug("before %x after %x\n", *location16,
                                       (value & 0xffff));
                        tmp = (value & 0xffff);
@@ -286,7 +286,7 @@ apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab,
                        } else
                                *location16 = tmp;
                        break;
-               case R_huimm16:
+               case R_BFIN_HUIMM16:
                        pr_debug("before %x after %x\n", *location16,
                                       ((value >> 16) & 0xffff));
                        tmp = ((value >> 16) & 0xffff);
@@ -295,10 +295,10 @@ apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab,
                        } else
                                *location16 = tmp;
                        break;
-               case R_rimm16:
+               case R_BFIN_RIMM16:
                        *location16 = (value & 0xffff);
                        break;
-               case R_byte4_data:
+               case R_BFIN_BYTE4_DATA:
                        pr_debug("before %x after %x\n", *location32, value);
                        *location32 = value;
                        break;
index e040e03335ea3c54792e44651424bbad51db5728..30d0843ed70192aa70fa49d9a3657260f235299d 100644 (file)
@@ -322,6 +322,9 @@ void finish_atomic_sections (struct pt_regs *regs)
 }
 
 #if defined(CONFIG_ACCESS_CHECK)
+#ifdef CONFIG_ACCESS_OK_L1
+__attribute__((l1_text))
+#endif
 /* Return 1 if access to memory range is OK, 0 otherwise */
 int _access_ok(unsigned long addr, unsigned long size)
 {
index a58687bdee6a6580031d6903526774c3f35e1625..80447f99c2b5f43cb0af2662e8e3717e214ab3e3 100644 (file)
 #include <linux/tty.h>
 #include <linux/pfn.h>
 
+#ifdef CONFIG_MTD_UCLINUX
+#include <linux/mtd/map.h>
 #include <linux/ext2_fs.h>
 #include <linux/cramfs_fs.h>
 #include <linux/romfs_fs.h>
+#endif
 
 #include <asm/cplb.h>
 #include <asm/cacheflush.h>
@@ -45,6 +48,7 @@ EXPORT_SYMBOL(_ramend);
 EXPORT_SYMBOL(reserved_mem_dcache_on);
 
 #ifdef CONFIG_MTD_UCLINUX
+extern struct map_info uclinux_ram_map;
 unsigned long memory_mtd_end, memory_mtd_start, mtd_size;
 unsigned long _ebss;
 EXPORT_SYMBOL(memory_mtd_end);
@@ -150,40 +154,45 @@ void __init bfin_relocate_l1_mem(void)
        unsigned long l1_data_b_length;
        unsigned long l2_length;
 
+       /*
+        * due to the ALIGN(4) in the arch/blackfin/kernel/vmlinux.lds.S
+        * we know that everything about l1 text/data is nice and aligned,
+        * so copy by 4 byte chunks, and don't worry about overlapping
+        * src/dest.
+        *
+        * We can't use the dma_memcpy functions, since they can call
+        * scheduler functions which might be in L1 :( and core writes
+        * into L1 instruction cause bad access errors, so we are stuck,
+        * we are required to use DMA, but can't use the common dma
+        * functions. We can't use memcpy either - since that might be
+        * going to be in the relocated L1
+        */
+
        blackfin_dma_early_init();
 
+       /* if necessary, copy _stext_l1 to _etext_l1 to L1 instruction SRAM */
        l1_code_length = _etext_l1 - _stext_l1;
-       if (l1_code_length > L1_CODE_LENGTH)
-               panic("L1 Instruction SRAM Overflow\n");
-       /* cannot complain as printk is not available as yet.
-        * But we can continue booting and complain later!
-        */
-
-       /* Copy _stext_l1 to _etext_l1 to L1 instruction SRAM */
-       dma_memcpy(_stext_l1, _l1_lma_start, l1_code_length);
+       if (l1_code_length)
+               early_dma_memcpy(_stext_l1, _l1_lma_start, l1_code_length);
 
+       /* if necessary, copy _sdata_l1 to _sbss_l1 to L1 data bank A SRAM */
        l1_data_a_length = _sbss_l1 - _sdata_l1;
-       if (l1_data_a_length > L1_DATA_A_LENGTH)
-               panic("L1 Data SRAM Bank A Overflow\n");
-
-       /* Copy _sdata_l1 to _sbss_l1 to L1 data bank A SRAM */
-       dma_memcpy(_sdata_l1, _l1_lma_start + l1_code_length, l1_data_a_length);
+       if (l1_data_a_length)
+               early_dma_memcpy(_sdata_l1, _l1_lma_start + l1_code_length, l1_data_a_length);
 
+       /* if necessary, copy _sdata_b_l1 to _sbss_b_l1 to L1 data bank B SRAM */
        l1_data_b_length = _sbss_b_l1 - _sdata_b_l1;
-       if (l1_data_b_length > L1_DATA_B_LENGTH)
-               panic("L1 Data SRAM Bank B Overflow\n");
-
-       /* Copy _sdata_b_l1 to _sbss_b_l1 to L1 data bank B SRAM */
-       dma_memcpy(_sdata_b_l1, _l1_lma_start + l1_code_length +
+       if (l1_data_b_length)
+               early_dma_memcpy(_sdata_b_l1, _l1_lma_start + l1_code_length +
                        l1_data_a_length, l1_data_b_length);
 
+       early_dma_memcpy_done();
+
+       /* if necessary, copy _stext_l2 to _edata_l2 to L2 SRAM */
        if (L2_LENGTH != 0) {
                l2_length = _sbss_l2 - _stext_l2;
-               if (l2_length > L2_LENGTH)
-                       panic("L2 SRAM Overflow\n");
-
-               /* Copy _stext_l2 to _edata_l2 to L2 SRAM */
-               dma_memcpy(_stext_l2, _l2_lma_start, l2_length);
+               if (l2_length)
+                       memcpy(_stext_l2, _l2_lma_start, l2_length);
        }
 }
 
@@ -472,7 +481,7 @@ static __init void memory_setup(void)
 
        if (DMA_UNCACHED_REGION > (_ramend - _ramstart)) {
                console_init();
-               panic("DMA region exceeds memory limit: %lu.\n",
+               panic("DMA region exceeds memory limit: %lu.",
                        _ramend - _ramstart);
        }
        memory_end = _ramend - DMA_UNCACHED_REGION;
@@ -526,14 +535,13 @@ static __init void memory_setup(void)
 
        if (mtd_size == 0) {
                console_init();
-               panic("Don't boot kernel without rootfs attached.\n");
+               panic("Don't boot kernel without rootfs attached.");
        }
 
        /* Relocate MTD image to the top of memory after the uncached memory area */
-       dma_memcpy((char *)memory_end, _end, mtd_size);
-
-       memory_mtd_start = memory_end;
-       _ebss = memory_mtd_start;       /* define _ebss for compatible */
+       uclinux_ram_map.phys = memory_mtd_start = memory_end;
+       uclinux_ram_map.size = mtd_size;
+       dma_memcpy((void *)uclinux_ram_map.phys, _end, uclinux_ram_map.size);
 #endif                         /* CONFIG_MTD_UCLINUX */
 
 #if (defined(CONFIG_BFIN_ICACHE) && ANOMALY_05000263)
@@ -796,10 +804,8 @@ void __init setup_arch(char **cmdline_p)
        cclk = get_cclk();
        sclk = get_sclk();
 
-#if !defined(CONFIG_BFIN_KERNEL_CLOCK)
-       if (ANOMALY_05000273 && cclk == sclk)
-               panic("ANOMALY 05000273, SCLK can not be same as CCLK");
-#endif
+       if ((ANOMALY_05000273 || ANOMALY_05000274) && (cclk >> 1) < sclk)
+               panic("ANOMALY 05000273 or 05000274: CCLK must be >= 2*SCLK");
 
 #ifdef BF561_FAMILY
        if (ANOMALY_05000266) {
@@ -881,7 +887,7 @@ void __init setup_arch(char **cmdline_p)
                                printk(KERN_ERR "Warning: Compiled for Rev %d, but running on Rev %d\n",
                                       bfin_compiled_revid(), bfin_revid());
                                if (bfin_compiled_revid() > bfin_revid())
-                                       panic("Error: you are missing anomaly workarounds for this rev\n");
+                                       panic("Error: you are missing anomaly workarounds for this rev");
                        }
                }
                if (bfin_revid() < CONFIG_BF_REV_MIN || bfin_revid() > CONFIG_BF_REV_MAX)
@@ -891,16 +897,13 @@ void __init setup_arch(char **cmdline_p)
 
        /* We can't run on BF548-0.1 due to ANOMALY 05000448 */
        if (bfin_cpuid() == 0x27de && bfin_revid() == 1)
-               panic("You can't run on this processor due to 05000448\n");
+               panic("You can't run on this processor due to 05000448");
 
        printk(KERN_INFO "Blackfin Linux support by http://blackfin.uclinux.org/\n");
 
        printk(KERN_INFO "Processor Speed: %lu MHz core clock and %lu MHz System Clock\n",
               cclk / 1000000, sclk / 1000000);
 
-       if (ANOMALY_05000273 && (cclk >> 1) <= sclk)
-               printk("\n\n\nANOMALY_05000273: CCLK must be >= 2*SCLK !!!\n\n\n");
-
        setup_bootmem_allocator();
 
        paging_init();
index fce49d7cf0017f0014304f8e715477cb29fa8f6b..a8f1329c15a48befeb62f31a7b80603b263dda2d 100644 (file)
@@ -78,11 +78,6 @@ asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
        return do_mmap2(addr, len, prot, flags, fd, pgoff);
 }
 
-asmlinkage int sys_getpagesize(void)
-{
-       return PAGE_SIZE;
-}
-
 asmlinkage void *sys_sram_alloc(size_t size, unsigned long flags)
 {
        return sram_alloc_with_lsl(size, flags);
index 27646121280a3f876295071084129148b1c0f250..0791eba40d9fdc479509682c990099299912f85a 100644 (file)
@@ -20,8 +20,9 @@
 
 #include <asm/blackfin.h>
 #include <asm/time.h>
+#include <asm/gptimers.h>
 
-#ifdef CONFIG_CYCLES_CLOCKSOURCE
+#if defined(CONFIG_CYCLES_CLOCKSOURCE)
 
 /* Accelerators for sched_clock()
  * convert from cycles(64bits) => nanoseconds (64bits)
@@ -58,15 +59,15 @@ static inline unsigned long long cycles_2_ns(cycle_t cyc)
        return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
 }
 
-static cycle_t read_cycles(struct clocksource *cs)
+static cycle_t bfin_read_cycles(struct clocksource *cs)
 {
        return __bfin_cycles_off + (get_cycles() << __bfin_cycles_mod);
 }
 
-static struct clocksource clocksource_bfin = {
-       .name           = "bfin_cycles",
+static struct clocksource bfin_cs_cycles = {
+       .name           = "bfin_cs_cycles",
        .rating         = 350,
-       .read           = read_cycles,
+       .read           = bfin_read_cycles,
        .mask           = CLOCKSOURCE_MASK(64),
        .shift          = 22,
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
@@ -74,53 +75,198 @@ static struct clocksource clocksource_bfin = {
 
 unsigned long long sched_clock(void)
 {
-       return cycles_2_ns(read_cycles(&clocksource_bfin));
+       return cycles_2_ns(bfin_read_cycles(&bfin_cs_cycles));
 }
 
-static int __init bfin_clocksource_init(void)
+static int __init bfin_cs_cycles_init(void)
 {
        set_cyc2ns_scale(get_cclk() / 1000);
 
-       clocksource_bfin.mult = clocksource_hz2mult(get_cclk(), clocksource_bfin.shift);
+       bfin_cs_cycles.mult = \
+               clocksource_hz2mult(get_cclk(), bfin_cs_cycles.shift);
 
-       if (clocksource_register(&clocksource_bfin))
+       if (clocksource_register(&bfin_cs_cycles))
                panic("failed to register clocksource");
 
        return 0;
 }
+#else
+# define bfin_cs_cycles_init()
+#endif
+
+#ifdef CONFIG_GPTMR0_CLOCKSOURCE
+
+void __init setup_gptimer0(void)
+{
+       disable_gptimers(TIMER0bit);
+
+       set_gptimer_config(TIMER0_id, \
+               TIMER_OUT_DIS | TIMER_PERIOD_CNT | TIMER_MODE_PWM);
+       set_gptimer_period(TIMER0_id, -1);
+       set_gptimer_pwidth(TIMER0_id, -2);
+       SSYNC();
+       enable_gptimers(TIMER0bit);
+}
+
+static cycle_t bfin_read_gptimer0(void)
+{
+       return bfin_read_TIMER0_COUNTER();
+}
+
+static struct clocksource bfin_cs_gptimer0 = {
+       .name           = "bfin_cs_gptimer0",
+       .rating         = 400,
+       .read           = bfin_read_gptimer0,
+       .mask           = CLOCKSOURCE_MASK(32),
+       .shift          = 22,
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static int __init bfin_cs_gptimer0_init(void)
+{
+       setup_gptimer0();
 
+       bfin_cs_gptimer0.mult = \
+               clocksource_hz2mult(get_sclk(), bfin_cs_gptimer0.shift);
+
+       if (clocksource_register(&bfin_cs_gptimer0))
+               panic("failed to register clocksource");
+
+       return 0;
+}
 #else
-# define bfin_clocksource_init()
+# define bfin_cs_gptimer0_init()
 #endif
 
+#ifdef CONFIG_CORE_TIMER_IRQ_L1
+__attribute__((l1_text))
+#endif
+irqreturn_t timer_interrupt(int irq, void *dev_id);
+
+static int bfin_timer_set_next_event(unsigned long, \
+               struct clock_event_device *);
+
+static void bfin_timer_set_mode(enum clock_event_mode, \
+               struct clock_event_device *);
+
+static struct clock_event_device clockevent_bfin = {
+#if defined(CONFIG_TICKSOURCE_GPTMR0)
+       .name           = "bfin_gptimer0",
+       .rating         = 300,
+       .irq            = IRQ_TIMER0,
+#else
+       .name           = "bfin_core_timer",
+       .rating         = 350,
+       .irq            = IRQ_CORETMR,
+#endif
+       .shift          = 32,
+       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+       .set_next_event = bfin_timer_set_next_event,
+       .set_mode       = bfin_timer_set_mode,
+};
+
+static struct irqaction bfin_timer_irq = {
+#if defined(CONFIG_TICKSOURCE_GPTMR0)
+       .name           = "Blackfin GPTimer0",
+#else
+       .name           = "Blackfin CoreTimer",
+#endif
+       .flags          = IRQF_DISABLED | IRQF_TIMER | \
+                         IRQF_IRQPOLL | IRQF_PERCPU,
+       .handler        = timer_interrupt,
+       .dev_id         = &clockevent_bfin,
+};
+
+#if defined(CONFIG_TICKSOURCE_GPTMR0)
 static int bfin_timer_set_next_event(unsigned long cycles,
                                      struct clock_event_device *evt)
 {
+       disable_gptimers(TIMER0bit);
+
+       /* it starts counting three SCLK cycles after the TIMENx bit is set */
+       set_gptimer_pwidth(TIMER0_id, cycles - 3);
+       enable_gptimers(TIMER0bit);
+       return 0;
+}
+
+static void bfin_timer_set_mode(enum clock_event_mode mode,
+                               struct clock_event_device *evt)
+{
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC: {
+               set_gptimer_config(TIMER0_id, \
+                       TIMER_OUT_DIS | TIMER_IRQ_ENA | \
+                       TIMER_PERIOD_CNT | TIMER_MODE_PWM);
+               set_gptimer_period(TIMER0_id, get_sclk() / HZ);
+               set_gptimer_pwidth(TIMER0_id, get_sclk() / HZ - 1);
+               enable_gptimers(TIMER0bit);
+               break;
+       }
+       case CLOCK_EVT_MODE_ONESHOT:
+               disable_gptimers(TIMER0bit);
+               set_gptimer_config(TIMER0_id, \
+                       TIMER_OUT_DIS | TIMER_IRQ_ENA | TIMER_MODE_PWM);
+               set_gptimer_period(TIMER0_id, 0);
+               break;
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+               disable_gptimers(TIMER0bit);
+               break;
+       case CLOCK_EVT_MODE_RESUME:
+               break;
+       }
+}
+
+static void bfin_timer_ack(void)
+{
+       set_gptimer_status(TIMER_GROUP1, TIMER_STATUS_TIMIL0);
+}
+
+static void __init bfin_timer_init(void)
+{
+       disable_gptimers(TIMER0bit);
+}
+
+static unsigned long  __init bfin_clockevent_check(void)
+{
+       setup_irq(IRQ_TIMER0, &bfin_timer_irq);
+       return get_sclk();
+}
+
+#else /* CONFIG_TICKSOURCE_CORETMR */
+
+static int bfin_timer_set_next_event(unsigned long cycles,
+                               struct clock_event_device *evt)
+{
+       bfin_write_TCNTL(TMPWR);
+       CSYNC();
        bfin_write_TCOUNT(cycles);
        CSYNC();
+       bfin_write_TCNTL(TMPWR | TMREN);
        return 0;
 }
 
 static void bfin_timer_set_mode(enum clock_event_mode mode,
-                                struct clock_event_device *evt)
+                               struct clock_event_device *evt)
 {
        switch (mode) {
        case CLOCK_EVT_MODE_PERIODIC: {
                unsigned long tcount = ((get_cclk() / (HZ * TIME_SCALE)) - 1);
                bfin_write_TCNTL(TMPWR);
-               bfin_write_TSCALE(TIME_SCALE - 1);
                CSYNC();
+               bfin_write_TSCALE(TIME_SCALE - 1);
                bfin_write_TPERIOD(tcount);
                bfin_write_TCOUNT(tcount);
-               bfin_write_TCNTL(TMPWR | TMREN | TAUTORLD);
                CSYNC();
+               bfin_write_TCNTL(TMPWR | TMREN | TAUTORLD);
                break;
        }
        case CLOCK_EVT_MODE_ONESHOT:
+               bfin_write_TCNTL(TMPWR);
+               CSYNC();
                bfin_write_TSCALE(TIME_SCALE - 1);
+               bfin_write_TPERIOD(0);
                bfin_write_TCOUNT(0);
-               bfin_write_TCNTL(TMPWR | TMREN);
-               CSYNC();
                break;
        case CLOCK_EVT_MODE_UNUSED:
        case CLOCK_EVT_MODE_SHUTDOWN:
@@ -132,6 +278,10 @@ static void bfin_timer_set_mode(enum clock_event_mode mode,
        }
 }
 
+static void bfin_timer_ack(void)
+{
+}
+
 static void __init bfin_timer_init(void)
 {
        /* power up the timer, but don't enable it just yet */
@@ -145,38 +295,32 @@ static void __init bfin_timer_init(void)
        bfin_write_TPERIOD(0);
        bfin_write_TCOUNT(0);
 
-       /* now enable the timer */
        CSYNC();
 }
 
+static unsigned long  __init bfin_clockevent_check(void)
+{
+       setup_irq(IRQ_CORETMR, &bfin_timer_irq);
+       return get_cclk() / TIME_SCALE;
+}
+
+void __init setup_core_timer(void)
+{
+       bfin_timer_init();
+       bfin_timer_set_mode(CLOCK_EVT_MODE_PERIODIC, NULL);
+}
+#endif /* CONFIG_TICKSOURCE_GPTMR0 */
+
 /*
  * timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
  */
-#ifdef CONFIG_CORE_TIMER_IRQ_L1
-__attribute__((l1_text))
-#endif
-irqreturn_t timer_interrupt(int irq, void *dev_id);
-
-static struct clock_event_device clockevent_bfin = {
-       .name           = "bfin_core_timer",
-       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
-       .shift          = 32,
-       .set_next_event = bfin_timer_set_next_event,
-       .set_mode       = bfin_timer_set_mode,
-};
-
-static struct irqaction bfin_timer_irq = {
-       .name           = "Blackfin Core Timer",
-       .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-       .handler        = timer_interrupt,
-       .dev_id         = &clockevent_bfin,
-};
-
 irqreturn_t timer_interrupt(int irq, void *dev_id)
 {
        struct clock_event_device *evt = dev_id;
+       smp_mb();
        evt->event_handler(evt);
+       bfin_timer_ack();
        return IRQ_HANDLED;
 }
 
@@ -184,9 +328,8 @@ static int __init bfin_clockevent_init(void)
 {
        unsigned long timer_clk;
 
-       timer_clk = get_cclk() / TIME_SCALE;
+       timer_clk = bfin_clockevent_check();
 
-       setup_irq(IRQ_CORETMR, &bfin_timer_irq);
        bfin_timer_init();
 
        clockevent_bfin.mult = div_sc(timer_clk, NSEC_PER_SEC, clockevent_bfin.shift);
@@ -218,6 +361,7 @@ void __init time_init(void)
        xtime.tv_nsec = 0;
        set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec);
 
-       bfin_clocksource_init();
+       bfin_cs_cycles_init();
+       bfin_cs_gptimer0_init();
        bfin_clockevent_init();
 }
index 1bbacfbd4c5d7c6198496fa939a7920dc36319d4..adb54aa7d7c81a19eeeeb25f094179224a073a78 100644 (file)
 
 static struct irqaction bfin_timer_irq = {
        .name = "Blackfin Timer Tick",
-#ifdef CONFIG_IRQ_PER_CPU
-       .flags = IRQF_DISABLED | IRQF_PERCPU,
-#else
        .flags = IRQF_DISABLED
-#endif
 };
 
-#if defined(CONFIG_TICK_SOURCE_SYSTMR0) || defined(CONFIG_IPIPE)
+#if defined(CONFIG_IPIPE)
 void __init setup_system_timer0(void)
 {
        /* Power down the core timer, just to play safe. */
@@ -74,7 +70,7 @@ void __init setup_core_timer(void)
 static void __init
 time_sched_init(irqreturn_t(*timer_routine) (int, void *))
 {
-#if defined(CONFIG_TICK_SOURCE_SYSTMR0) || defined(CONFIG_IPIPE)
+#if defined(CONFIG_IPIPE)
        setup_system_timer0();
        bfin_timer_irq.handler = timer_routine;
        setup_irq(IRQ_TIMER0, &bfin_timer_irq);
@@ -94,7 +90,7 @@ static unsigned long gettimeoffset(void)
        unsigned long offset;
        unsigned long clocks_per_jiffy;
 
-#if defined(CONFIG_TICK_SOURCE_SYSTMR0) || defined(CONFIG_IPIPE)
+#if defined(CONFIG_IPIPE)
        clocks_per_jiffy = bfin_read_TIMER0_PERIOD();
        offset = bfin_read_TIMER0_COUNTER() / \
                (((clocks_per_jiffy + 1) * HZ) / USEC_PER_SEC);
@@ -133,36 +129,25 @@ irqreturn_t timer_interrupt(int irq, void *dummy)
        static long last_rtc_update;
 
        write_seqlock(&xtime_lock);
-#if defined(CONFIG_TICK_SOURCE_SYSTMR0) && !defined(CONFIG_IPIPE)
+       do_timer(1);
+
        /*
-        * TIMIL0 is latched in __ipipe_grab_irq() when the I-Pipe is
-        * enabled.
+        * If we have an externally synchronized Linux clock, then update
+        * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+        * called as close as possible to 500 ms before the new second starts.
         */
-       if (get_gptimer_status(0) & TIMER_STATUS_TIMIL0) {
-#endif
-               do_timer(1);
-
-               /*
-                * If we have an externally synchronized Linux clock, then update
-                * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
-                * called as close as possible to 500 ms before the new second starts.
-                */
-               if (ntp_synced() &&
-                   xtime.tv_sec > last_rtc_update + 660 &&
-                   (xtime.tv_nsec / NSEC_PER_USEC) >=
-                   500000 - ((unsigned)TICK_SIZE) / 2
-                   && (xtime.tv_nsec / NSEC_PER_USEC) <=
-                   500000 + ((unsigned)TICK_SIZE) / 2) {
-                       if (set_rtc_mmss(xtime.tv_sec) == 0)
-                               last_rtc_update = xtime.tv_sec;
-                       else
-                               /* Do it again in 60s. */
-                               last_rtc_update = xtime.tv_sec - 600;
-               }
-#if defined(CONFIG_TICK_SOURCE_SYSTMR0) && !defined(CONFIG_IPIPE)
-               set_gptimer_status(0, TIMER_STATUS_TIMIL0);
+       if (ntp_synced() &&
+           xtime.tv_sec > last_rtc_update + 660 &&
+           (xtime.tv_nsec / NSEC_PER_USEC) >=
+           500000 - ((unsigned)TICK_SIZE) / 2
+           && (xtime.tv_nsec / NSEC_PER_USEC) <=
+           500000 + ((unsigned)TICK_SIZE) / 2) {
+               if (set_rtc_mmss(xtime.tv_sec) == 0)
+                       last_rtc_update = xtime.tv_sec;
+               else
+                       /* Do it again in 60s. */
+                       last_rtc_update = xtime.tv_sec - 600;
        }
-#endif
        write_sequnlock(&xtime_lock);
 
 #ifdef CONFIG_IPIPE
index ffe7fb53eccbdaccd344fbe27029fdc5bba12b14..aa76dfb0226ecd6dcf03136c463eb2969ac78f4b 100644 (file)
        ({ if (0) printk(fmt, ##arg); 0; })
 #endif
 
+#if defined(CONFIG_DEBUG_MMRS) || defined(CONFIG_DEBUG_MMRS_MODULE)
+u32 last_seqstat;
+#ifdef CONFIG_DEBUG_MMRS_MODULE
+EXPORT_SYMBOL(last_seqstat);
+#endif
+#endif
+
 /* Initiate the event table handler */
 void __init trap_init(void)
 {
@@ -79,7 +86,6 @@ void __init trap_init(void)
 static void decode_address(char *buf, unsigned long address)
 {
 #ifdef CONFIG_DEBUG_VERBOSE
-       struct vm_list_struct *vml;
        struct task_struct *p;
        struct mm_struct *mm;
        unsigned long flags, offset;
@@ -196,6 +202,11 @@ done:
 
 asmlinkage void double_fault_c(struct pt_regs *fp)
 {
+#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
+       int j;
+       trace_buffer_save(j);
+#endif
+
        console_verbose();
        oops_in_progress = 1;
 #ifdef CONFIG_DEBUG_VERBOSE
@@ -220,9 +231,10 @@ asmlinkage void double_fault_c(struct pt_regs *fp)
                dump_bfin_process(fp);
                dump_bfin_mem(fp);
                show_regs(fp);
+               dump_bfin_trace_buffer();
        }
 #endif
-       panic("Double Fault - unrecoverable event\n");
+       panic("Double Fault - unrecoverable event");
 
 }
 
@@ -239,6 +251,9 @@ asmlinkage void trap_c(struct pt_regs *fp)
        unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE;
 
        trace_buffer_save(j);
+#if defined(CONFIG_DEBUG_MMRS) || defined(CONFIG_DEBUG_MMRS_MODULE)
+       last_seqstat = (u32)fp->seqstat;
+#endif
 
        /* Important - be very careful dereferncing pointers - will lead to
         * double faults if the stack has become corrupt
@@ -588,6 +603,9 @@ asmlinkage void trap_c(struct pt_regs *fp)
                force_sig_info(sig, &info, current);
        }
 
+       if (ANOMALY_05000461 && trapnr == VEC_HWERR && !access_ok(VERIFY_READ, fp->pc, 8))
+               fp->pc = SAFE_USER_INSTRUCTION;
+
        trace_buffer_restore(j);
        return;
 }
@@ -832,6 +850,11 @@ void show_stack(struct task_struct *task, unsigned long *stack)
        decode_address(buf, (unsigned int)stack);
        printk(KERN_NOTICE " SP: [0x%p] %s\n", stack, buf);
 
+       if (!access_ok(VERIFY_READ, stack, (unsigned int)endstack - (unsigned int)stack)) {
+               printk(KERN_NOTICE "Invalid stack pointer\n");
+               return;
+       }
+
        /* First thing is to look for a frame pointer */
        for (addr = (unsigned int *)((unsigned int)stack & ~0xF); addr < endstack; addr++) {
                if (*addr & 0x1)
@@ -1066,6 +1089,29 @@ void show_regs(struct pt_regs *fp)
        unsigned int cpu = smp_processor_id();
        unsigned char in_atomic = (bfin_read_IPEND() & 0x10) || in_atomic();
 
+       verbose_printk(KERN_NOTICE "\n");
+       if (CPUID != bfin_cpuid())
+               verbose_printk(KERN_NOTICE "Compiled for cpu family 0x%04x (Rev %d), "
+                       "but running on:0x%04x (Rev %d)\n",
+                       CPUID, bfin_compiled_revid(), bfin_cpuid(), bfin_revid());
+
+       verbose_printk(KERN_NOTICE "ADSP-%s-0.%d",
+               CPU, bfin_compiled_revid());
+
+       if (bfin_compiled_revid() !=  bfin_revid())
+               verbose_printk("(Detected 0.%d)", bfin_revid());
+
+       verbose_printk(" %lu(MHz CCLK) %lu(MHz SCLK) (%s)\n",
+               get_cclk()/1000000, get_sclk()/1000000,
+#ifdef CONFIG_MPU
+               "mpu on"
+#else
+               "mpu off"
+#endif
+               );
+
+       verbose_printk(KERN_NOTICE "%s", linux_banner);
+
        verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\t\t%s\n", print_tainted());
        verbose_printk(KERN_NOTICE " SEQSTAT: %08lx  IPEND: %04lx  SYSCFG: %04lx\n",
                (long)fp->seqstat, fp->ipend, fp->syscfg);
@@ -1246,5 +1292,5 @@ void panic_cplb_error(int cplb_panic, struct pt_regs *fp)
        dump_bfin_mem(fp);
        show_regs(fp);
        dump_stack();
-       panic("Unrecoverable event\n");
+       panic("Unrecoverable event");
 }
index 27952ae047d883ab80b564eebdbba1e4836e2439..8b67167cb4f4cdeac39c465c0be0a5ba4f52711e 100644 (file)
@@ -50,7 +50,9 @@ SECTIONS
                _text = .;
                __stext = .;
                TEXT_TEXT
+#ifndef CONFIG_SCHEDULE_L1
                SCHED_TEXT
+#endif
                LOCK_TEXT
                KPROBES_TEXT
                *(.text.*)
@@ -180,6 +182,9 @@ SECTIONS
                . = ALIGN(4);
                __stext_l1 = .;
                *(.l1.text)
+#ifdef CONFIG_SCHEDULE_L1
+               SCHED_TEXT
+#endif
                . = ALIGN(4);
                __etext_l1 = .;
        }
index f397ede006bf8a6ebc36721a780a6a2e8d4c3ade..4c76fefb7a3b68c02006358622bffe0a401d6761 100644 (file)
@@ -156,6 +156,7 @@ config IRQ_PORTH_INTB
        default 11
 config IRQ_TIMER0
        int "IRQ_TIMER0"
+       default 7 if TICKSOURCE_GPTMR0
        default 8
 config IRQ_TIMER1
        int "IRQ_TIMER1"
index 41f2eacfef207339d53d7dbf1de90b78e7d3a8f2..62bba09bcce689dfe908b5b702e76fb20877921f 100644 (file)
@@ -82,7 +82,11 @@ static struct physmap_flash_data ezbrd_flash_data = {
 
 static struct resource ezbrd_flash_resource = {
        .start = 0x20000000,
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+       .end   = 0x202fffff,
+#else
        .end   = 0x203fffff,
+#endif
        .flags = IORESOURCE_MEM,
 };
 
@@ -162,8 +166,8 @@ static struct bfin5xx_spi_chip spi_flash_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) \
-       || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) \
+       || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 /* SPI ADC chip */
 static struct bfin5xx_spi_chip spi_adc_chip_info = {
        .enable_dma = 1,         /* use dma transfer with this chip*/
@@ -249,8 +253,8 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) \
-       || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) \
+       || defined(CONFIG_BFIN_SPI_ADC_MODULE)
        {
                .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
                .max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
@@ -514,7 +518,7 @@ static struct platform_device i2c_bfin_twi_device = {
 #endif
 
 static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
-#if defined(CONFIG_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
        {
                I2C_BOARD_INFO("pcf8574_lcd", 0x22),
        },
@@ -678,6 +682,11 @@ static int __init ezbrd_init(void)
                                ARRAY_SIZE(bfin_i2c_board_info));
        platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
        spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
+       /* setup BF518-EZBRD GPIO pin PG11 to AMS2, PG15 to AMS3. */
+       peripheral_request(P_AMS2, "ParaFlash");
+#if !defined(CONFIG_SPI_BFIN) && !defined(CONFIG_SPI_BFIN_MODULE)
+       peripheral_request(P_AMS3, "ParaFlash");
+#endif
        return 0;
 }
 
index c847bb101076399cbb3bc510adf5946e42ddecff..b69bd9af38ddad9a7b218387fedf34704addf5c4 100644 (file)
@@ -6,14 +6,19 @@
  * Licensed under the GPL-2 or later.
  */
 
-/* This file shoule be up to date with:
+/* This file should be up to date with:
  *  - Revision B, 02/03/2009; ADSP-BF512/BF514/BF516/BF518 Blackfin Processor Anomaly List
  */
 
+/* We plan on not supporting 0.0 silicon, but 0.1 isn't out yet - sorry */
+#if __SILICON_REVISION__ < 0
+# error will not work on BF518 silicon version
+#endif
+
 #ifndef _MACH_ANOMALY_H_
 #define _MACH_ANOMALY_H_
 
-/* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot2 Not Supported */
+/* Multi-issue instruction with dsp32shiftimm in slot1 and P-reg store in slot 2 not supported */
 #define ANOMALY_05000074 (1)
 /* Rx.H Cannot Be Used to Access 16-bit System MMR Registers */
 #define ANOMALY_05000122 (1)
@@ -47,7 +52,7 @@
 #define ANOMALY_05000435 (1)
 /* PORTx_DRIVE and PORTx_HYSTERESIS Registers Read Back Incorrect Values */
 #define ANOMALY_05000438 (1)
-/* Preboot Cannot be Used to Program the PLL_DIV Register */
+/* Preboot Cannot be Used to Alter the PLL_DIV Register */
 #define ANOMALY_05000439 (1)
 /* bfrom_SysControl() Cannot be Used to Write the PLL_DIV Register */
 #define ANOMALY_05000440 (1)
 #define ANOMALY_05000453 (1)
 /* PPI_FS3 is Driven One Half Cycle Later Than PPI Data */
 #define ANOMALY_05000455 (1)
+/* False Hardware Error when RETI points to invalid memory */
+#define ANOMALY_05000461 (1)
 
 /* Anomalies that don't exist on this proc */
+#define ANOMALY_05000099 (0)
+#define ANOMALY_05000119 (0)
+#define ANOMALY_05000120 (0)
 #define ANOMALY_05000125 (0)
+#define ANOMALY_05000149 (0)
 #define ANOMALY_05000158 (0)
+#define ANOMALY_05000171 (0)
+#define ANOMALY_05000179 (0)
 #define ANOMALY_05000183 (0)
 #define ANOMALY_05000198 (0)
+#define ANOMALY_05000215 (0)
+#define ANOMALY_05000220 (0)
+#define ANOMALY_05000227 (0)
 #define ANOMALY_05000230 (0)
+#define ANOMALY_05000231 (0)
+#define ANOMALY_05000233 (0)
+#define ANOMALY_05000242 (0)
 #define ANOMALY_05000244 (0)
+#define ANOMALY_05000248 (0)
+#define ANOMALY_05000250 (0)
 #define ANOMALY_05000261 (0)
 #define ANOMALY_05000263 (0)
 #define ANOMALY_05000266 (0)
 #define ANOMALY_05000273 (0)
+#define ANOMALY_05000274 (0)
 #define ANOMALY_05000278 (0)
 #define ANOMALY_05000285 (0)
+#define ANOMALY_05000287 (0)
+#define ANOMALY_05000301 (0)
 #define ANOMALY_05000305 (0)
 #define ANOMALY_05000307 (0)
 #define ANOMALY_05000311 (0)
 #define ANOMALY_05000312 (0)
 #define ANOMALY_05000323 (0)
 #define ANOMALY_05000353 (0)
+#define ANOMALY_05000362 (1)
 #define ANOMALY_05000363 (0)
 #define ANOMALY_05000380 (0)
 #define ANOMALY_05000386 (0)
+#define ANOMALY_05000389 (0)
+#define ANOMALY_05000400 (0)
 #define ANOMALY_05000412 (0)
 #define ANOMALY_05000432 (0)
 #define ANOMALY_05000447 (0)
 #define ANOMALY_05000448 (0)
+#define ANOMALY_05000456 (0)
+#define ANOMALY_05000450 (0)
 
 #endif
index f618b487b2b0eabd96d03e1be423b282122770ca..a0fc77fd331518f48039f76dde51370581883bba 100644 (file)
 #define P_PTP_PPS              (P_DEFINED | P_IDENT(GPIO_PG12) | P_FUNCT(2))
 #define P_PTP_CLKOUT           (P_DEFINED | P_IDENT(GPIO_PG13) | P_FUNCT(2))
 
-#define P_HWAIT                (P_DEFINED | P_IDENT(GPIO_PG000000000) | P_FUNCT(1))
+/* AMS */
+#define P_AMS2                 (P_DEFINED | P_IDENT(GPIO_PG11) | P_FUNCT(1))
+#define P_AMS3                 (P_DEFINED | P_IDENT(GPIO_PG15) | P_FUNCT(2))
+
+#define P_HWAIT                        (P_DEFINED | P_IDENT(GPIO_PG000000000) | P_FUNCT(1))
 
 #endif                         /* _MACH_PORTMUX_H_ */
index 8438ec6d6679007fe115f8dd9fc4f477d9befeda..848ac6f868231d42044209a71c48a46c806d96e0 100644 (file)
@@ -170,6 +170,7 @@ config IRQ_PORTH_INTB
        default 11
 config IRQ_TIMER0
        int "IRQ_TIMER0"
+       default 7 if TICKSOURCE_GPTMR0
        default 8
 config IRQ_TIMER1
        int "IRQ_TIMER1"
index 48e69eecdba42b4e690b146b71866f1127c6d6e8..6d6f9effa0bb8e36f38f99ba9f7a8cfdb6798b16 100644 (file)
@@ -463,8 +463,8 @@ static struct bfin5xx_spi_chip spi_flash_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) \
-       || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) \
+       || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 /* SPI ADC chip */
 static struct bfin5xx_spi_chip spi_adc_chip_info = {
        .enable_dma = 1,         /* use dma transfer with this chip*/
@@ -554,8 +554,8 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) \
-       || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) \
+       || defined(CONFIG_BFIN_SPI_ADC_MODULE)
        {
                .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
                .max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
@@ -789,7 +789,7 @@ static struct platform_device i2c_bfin_twi_device = {
 #endif
 
 static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
-#if defined(CONFIG_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
        {
                I2C_BOARD_INFO("pcf8574_lcd", 0x22),
                .type = "pcf8574_lcd",
index 7fe480e4ebe83c1022e275373cc1d77550091c20..1435c5d38cd515127d5f6b16f60fc084f8c96287 100644 (file)
@@ -247,8 +247,8 @@ static struct bfin5xx_spi_chip spi_flash_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) \
-       || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) \
+       || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 /* SPI ADC chip */
 static struct bfin5xx_spi_chip spi_adc_chip_info = {
        .enable_dma = 1,         /* use dma transfer with this chip*/
@@ -354,8 +354,8 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) \
-       || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) \
+       || defined(CONFIG_BFIN_SPI_ADC_MODULE)
        {
                .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
                .max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
@@ -586,7 +586,7 @@ static struct platform_device i2c_bfin_twi_device = {
 #endif
 
 static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
-#if defined(CONFIG_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
        {
                I2C_BOARD_INFO("pcf8574_lcd", 0x22),
        },
index d0864111ef594f3b05ed613c31d18251c87961c3..147edd1eb1ad44f52850a8d9977a36dbbfd5aab0 100644 (file)
@@ -485,8 +485,8 @@ static struct bfin5xx_spi_chip spi_flash_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) \
-       || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) \
+       || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 /* SPI ADC chip */
 static struct bfin5xx_spi_chip spi_adc_chip_info = {
        .enable_dma = 1,         /* use dma transfer with this chip*/
@@ -509,6 +509,13 @@ static struct bfin5xx_spi_chip ad9960_spi_chip_info = {
 };
 #endif
 
+#if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE)
+static struct bfin5xx_spi_chip  mmc_spi_chip_info = {
+       .enable_dma = 0,
+       .bits_per_word = 8,
+};
+#endif
+
 #if defined(CONFIG_PBX)
 static struct bfin5xx_spi_chip spi_si3xxx_chip_info = {
        .ctl_reg        = 0x4, /* send zero */
@@ -593,8 +600,8 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) \
-       || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) \
+       || defined(CONFIG_BFIN_SPI_ADC_MODULE)
        {
                .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
                .max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
@@ -624,6 +631,17 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
                .controller_data = &ad9960_spi_chip_info,
        },
 #endif
+#if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE)
+       {
+               .modalias = "mmc_spi",
+               .max_speed_hz = 20000000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num = 0,
+               .chip_select = 3,
+               .controller_data = &mmc_spi_chip_info,
+               .mode = SPI_MODE_0,
+       },
+#endif
+
 #if defined(CONFIG_PBX)
        {
                .modalias = "fxs-spi",
@@ -836,7 +854,7 @@ static struct platform_device i2c_bfin_twi_device = {
 #endif
 
 static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
-#if defined(CONFIG_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
        {
                I2C_BOARD_INFO("pcf8574_lcd", 0x22),
        },
index df6808d8a6efce3f5317cfc849c9bbb969e7dcda..c84ddea95749c7c0b2a1be099cd22cb62f5b30cf 100644 (file)
@@ -6,14 +6,19 @@
  * Licensed under the GPL-2 or later.
  */
 
-/* This file shoule be up to date with:
- *  - Revision B, 08/12/2008; ADSP-BF526 Blackfin Processor Anomaly List
- *  - Revision E, 08/18/2008; ADSP-BF527 Blackfin Processor Anomaly List
+/* This file should be up to date with:
+ *  - Revision C, 03/13/2009; ADSP-BF526 Blackfin Processor Anomaly List
+ *  - Revision F, 03/03/2009; ADSP-BF527 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
 #define _MACH_ANOMALY_H_
 
+/* We do not support old silicon - sorry */
+#if __SILICON_REVISION__ < 0
+# error will not work on BF526/BF527 silicon version
+#endif
+
 #if defined(__ADSPBF522__) || defined(__ADSPBF524__) || defined(__ADSPBF526__)
 # define ANOMALY_BF526 1
 #else
 # define ANOMALY_BF527 0
 #endif
 
-/* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot2 Not Supported */
+#define _ANOMALY_BF526(rev526) (ANOMALY_BF526 && __SILICON_REVISION__ rev526)
+#define _ANOMALY_BF527(rev527) (ANOMALY_BF527 && __SILICON_REVISION__ rev527)
+#define _ANOMALY_BF526_BF527(rev526, rev527) (_ANOMALY_BF526(rev526) || _ANOMALY_BF527(rev527))
+
+/* Multi-issue instruction with dsp32shiftimm in slot1 and P-reg store in slot 2 not supported */
 #define ANOMALY_05000074 (1)
 /* DMA_RUN Bit Is Not Valid after a Peripheral Receive Channel DMA Stops */
 #define ANOMALY_05000119 (1)   /* note: brokenness is noted in documentation, not anomaly sheet */
 /* Rx.H Cannot Be Used to Access 16-bit System MMR Registers */
 #define ANOMALY_05000122 (1)
-/* Spurious Hardware Error from an Access in the Shadow of a Conditional Branch */
+/* False Hardware Error from an Access in the Shadow of a Conditional Branch */
 #define ANOMALY_05000245 (1)
+/* Incorrect Timer Pulse Width in Single-Shot PWM_OUT Mode with External Clock */
+#define ANOMALY_05000254 (1)
 /* Sensitivity To Noise with Slow Input Edge Rates on External SPORT TX and RX Clocks */
 #define ANOMALY_05000265 (1)
 /* False Hardware Errors Caused by Fetches at the Boundary of Reserved Memory */
 #define ANOMALY_05000310 (1)
 /* PPI Is Level-Sensitive on First Transfer In Single Frame Sync Modes */
-#define ANOMALY_05000313 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000313 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* Incorrect Access of OTP_STATUS During otp_write() Function */
-#define ANOMALY_05000328 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000328 (_ANOMALY_BF527(< 2))
+/* Host DMA Boot Modes Are Not Functional */
+#define ANOMALY_05000330 (__SILICON_REVISION__ < 2)
 /* Disallowed Configuration Prevents Subsequent Allowed Configuration on Host DMA Port */
-#define ANOMALY_05000337 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000337 (_ANOMALY_BF527(< 2))
 /* Ethernet MAC MDIO Reads Do Not Meet IEEE Specification */
-#define ANOMALY_05000341 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000341 (_ANOMALY_BF527(< 2))
 /* TWI May Not Operate Correctly Under Certain Signal Termination Conditions */
-#define ANOMALY_05000342 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000342 (_ANOMALY_BF527(< 2))
 /* USB Calibration Value Is Not Initialized */
-#define ANOMALY_05000346 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000346 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* USB Calibration Value to use */
 #define ANOMALY_05000346_value 0xE510
 /* Preboot Routine Incorrectly Alters Reset Value of USB Register */
-#define ANOMALY_05000347 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000347 (_ANOMALY_BF527(< 2))
 /* Security Features Are Not Functional */
-#define ANOMALY_05000348 (ANOMALY_BF527 && __SILICON_REVISION__ < 1)
+#define ANOMALY_05000348 (_ANOMALY_BF527(< 1))
 /* bfrom_SysControl() Firmware Function Performs Improper System Reset */
-#define ANOMALY_05000353 (ANOMALY_BF526)
+#define ANOMALY_05000353 (_ANOMALY_BF526(< 1))
 /* Regulator Programming Blocked when Hibernate Wakeup Source Remains Active */
-#define ANOMALY_05000355 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000355 (_ANOMALY_BF527(< 2))
 /* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */
-#define ANOMALY_05000357 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000357 (_ANOMALY_BF527(< 2))
 /* Incorrect Revision Number in DSPID Register */
-#define ANOMALY_05000364 (ANOMALY_BF527 && __SILICON_REVISION__ == 1)
+#define ANOMALY_05000364 (_ANOMALY_BF527(== 1))
 /* PPI Underflow Error Goes Undetected in ITU-R 656 Mode */
 #define ANOMALY_05000366 (1)
 /* Incorrect Default CSEL Value in PLL_DIV */
-#define ANOMALY_05000368 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000368 (_ANOMALY_BF527(< 2))
 /* Possible RETS Register Corruption when Subroutine Is under 5 Cycles in Duration */
-#define ANOMALY_05000371 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000371 (_ANOMALY_BF527(< 2))
 /* Authentication Fails To Initiate */
-#define ANOMALY_05000376 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000376 (_ANOMALY_BF527(< 2))
 /* Data Read From L3 Memory by USB DMA May be Corrupted */
-#define ANOMALY_05000380 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000380 (_ANOMALY_BF527(< 2))
 /* 8-Bit NAND Flash Boot Mode Not Functional */
-#define ANOMALY_05000382 (__SILICON_REVISION__ < 2)
-/* Host Must Not Read Back During Host DMA Boot */
-#define ANOMALY_05000384 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000382 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* Boot from OTP Memory Not Functional */
-#define ANOMALY_05000385 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000385 (_ANOMALY_BF527(< 2))
 /* bfrom_SysControl() Firmware Routine Not Functional */
-#define ANOMALY_05000386 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000386 (_ANOMALY_BF527(< 2))
 /* Programmable Preboot Settings Not Functional */
-#define ANOMALY_05000387 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000387 (_ANOMALY_BF527(< 2))
 /* CRC32 Checksum Support Not Functional */
-#define ANOMALY_05000388 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000388 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* Reset Vector Must Not Be in SDRAM Memory Space */
-#define ANOMALY_05000389 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000389 (_ANOMALY_BF527(< 2))
 /* pTempCurrent Not Present in ADI_BOOT_DATA Structure */
-#define ANOMALY_05000392 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000392 (_ANOMALY_BF527(< 2))
 /* Deprecated Value of dTempByteCount in ADI_BOOT_DATA Structure */
-#define ANOMALY_05000393 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000393 (_ANOMALY_BF527(< 2))
 /* Log Buffer Not Functional */
-#define ANOMALY_05000394 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000394 (_ANOMALY_BF527(< 2))
 /* Hook Routine Not Functional */
-#define ANOMALY_05000395 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000395 (_ANOMALY_BF527(< 2))
 /* Header Indirect Bit Not Functional */
-#define ANOMALY_05000396 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000396 (_ANOMALY_BF527(< 2))
 /* BK_ONES, BK_ZEROS, and BK_DATECODE Constants Not Functional */
-#define ANOMALY_05000397 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000397 (_ANOMALY_BF527(< 2))
 /* SWRESET, DFRESET and WDRESET Bits in the SYSCR Register Not Functional */
-#define ANOMALY_05000398 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000398 (_ANOMALY_BF527(< 2))
 /* BCODE_NOBOOT in BCODE Field of SYSCR Register Not Functional */
-#define ANOMALY_05000399 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000399 (_ANOMALY_BF527(< 2))
 /* PPI Data Signals D0 and D8 do not Tristate After Disabling PPI */
-#define ANOMALY_05000401 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000401 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* Level-Sensitive External GPIO Wakeups May Cause Indefinite Stall */
-#define ANOMALY_05000403 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000403 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* Lockbox SESR Disallows Certain User Interrupts */
-#define ANOMALY_05000404 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000404 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* Lockbox SESR Firmware Does Not Save/Restore Full Context */
 #define ANOMALY_05000405 (1)
 /* Lockbox SESR Firmware Arguments Are Not Retained After First Initialization */
-#define ANOMALY_05000407 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000407 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* Lockbox Firmware Memory Cleanup Routine Does not Clear Registers */
 #define ANOMALY_05000408 (1)
 /* Lockbox firmware leaves MDMA0 channel enabled */
-#define ANOMALY_05000409 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000409 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* Incorrect Default Internal Voltage Regulator Setting */
-#define ANOMALY_05000410 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000410 (_ANOMALY_BF527(< 2))
 /* bfrom_SysControl() Firmware Function Cannot be Used to Enter Power Saving Modes */
-#define ANOMALY_05000411 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000411 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* OTP_CHECK_FOR_PREV_WRITE Bit is Not Functional in bfrom_OtpWrite() API */
-#define ANOMALY_05000414 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000414 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* DEB2_URGENT Bit Not Functional */
-#define ANOMALY_05000415 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000415 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* Speculative Fetches Can Cause Undesired External FIFO Operations */
 #define ANOMALY_05000416 (1)
 /* SPORT0 Ignores External TSCLK0 on PG14 When TMR6 is an Output */
-#define ANOMALY_05000417 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
-/* tSFSPE and tHFSPE Do Not Meet Data Sheet Specifications */
-#define ANOMALY_05000418 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000417 (_ANOMALY_BF527(< 2))
+/* PPI Timing Requirements tSFSPE and tHFSPE Do Not Meet Data Sheet Specifications */
+#define ANOMALY_05000418 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* USB PLL_STABLE Bit May Not Accurately Reflect the USB PLL's Status */
-#define ANOMALY_05000420 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000420 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* TWI Fall Time (Tof) May Violate the Minimum I2C Specification */
 #define ANOMALY_05000421 (1)
 /* TWI Input Capacitance (Ci) May Violate the Maximum I2C Specification */
-#define ANOMALY_05000422 (ANOMALY_BF527 && __SILICON_REVISION__ > 1)
+#define ANOMALY_05000422 (_ANOMALY_BF526_BF527(> 0, > 1))
 /* Certain Ethernet Frames With Errors are Misclassified in RMII Mode */
-#define ANOMALY_05000423 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000423 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* Internal Voltage Regulator Not Trimmed */
-#define ANOMALY_05000424 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+#define ANOMALY_05000424 (_ANOMALY_BF527(< 2))
 /* Multichannel SPORT Channel Misalignment Under Specific Configuration */
-#define ANOMALY_05000425 (__SILICON_REVISION__ < 2)
-/* Speculative Fetches of Indirect-Pointer Instructions Can Cause Spurious Hardware Errors */
+#define ANOMALY_05000425 (_ANOMALY_BF526_BF527(< 1, < 2))
+/* Speculative Fetches of Indirect-Pointer Instructions Can Cause False Hardware Errors */
 #define ANOMALY_05000426 (1)
 /* WB_EDGE Bit in NFC_IRQSTAT Incorrectly Reflects Buffer Status Instead of IRQ Status */
-#define ANOMALY_05000429 (__SILICON_REVISION__ < 2)
+#define ANOMALY_05000429 (_ANOMALY_BF526_BF527(< 1, < 2))
 /* Software System Reset Corrupts PLL_LOCKCNT Register */
-#define ANOMALY_05000430 (ANOMALY_BF527 && __SILICON_REVISION__ > 1)
+#define ANOMALY_05000430 (_ANOMALY_BF527(> 1))
+/* Incorrect Use of Stack in Lockbox Firmware During Authentication */
+#define ANOMALY_05000431 (1)
 /* bfrom_SysControl() Does Not Clear SIC_IWR1 Before Executing PLL Programming Sequence */
-#define ANOMALY_05000432 (ANOMALY_BF526)
+#define ANOMALY_05000432 (_ANOMALY_BF526(< 1))
 /* Certain SIC Registers are not Reset After Soft or Core Double Fault Reset */
-#define ANOMALY_05000435 ((ANOMALY_BF526 && __SILICON_REVISION__ < 1) || ANOMALY_BF527)
+#define ANOMALY_05000435 (_ANOMALY_BF526_BF527(< 1, >= 0))
+/* Preboot Cannot be Used to Alter the PLL_DIV Register */
+#define ANOMALY_05000439 (_ANOMALY_BF526_BF527(< 1, >= 0))
+/* bfrom_SysControl() Cannot be Used to Write the PLL_DIV Register */
+#define ANOMALY_05000440 (_ANOMALY_BF526_BF527(< 1, >= 0))
+/* OTP Write Accesses Not Supported */
+#define ANOMALY_05000442 (_ANOMALY_BF527(< 1))
 /* IFLUSH Instruction at End of Hardware Loop Causes Infinite Stall */
 #define ANOMALY_05000443 (1)
+/* The WURESET Bit in the SYSCR Register is not Functional */
+#define ANOMALY_05000445 (1)
+/* BCODE_QUICKBOOT, BCODE_ALLBOOT, and BCODE_FULLBOOT Settings in SYSCR Register Not Functional */
+#define ANOMALY_05000451 (1)
+/* Incorrect Default Hysteresis Setting for RESET, NMI, and BMODE Signals */
+#define ANOMALY_05000452 (_ANOMALY_BF526_BF527(< 1, >= 0))
+/* USB Receive Interrupt Is Not Generated in DMA Mode 1 */
+#define ANOMALY_05000456 (1)
+/* Host DMA Port Responds to Certain Bus Activity Without HOST_CE Assertion */
+#define ANOMALY_05000457 (1)
+/* False Hardware Error when RETI points to invalid memory */
+#define ANOMALY_05000461 (1)
 
 /* Anomalies that don't exist on this proc */
+#define ANOMALY_05000099 (0)
+#define ANOMALY_05000120 (0)
 #define ANOMALY_05000125 (0)
+#define ANOMALY_05000149 (0)
 #define ANOMALY_05000158 (0)
+#define ANOMALY_05000171 (0)
+#define ANOMALY_05000179 (0)
 #define ANOMALY_05000183 (0)
 #define ANOMALY_05000198 (0)
+#define ANOMALY_05000215 (0)
+#define ANOMALY_05000220 (0)
+#define ANOMALY_05000227 (0)
 #define ANOMALY_05000230 (0)
+#define ANOMALY_05000231 (0)
+#define ANOMALY_05000233 (0)
+#define ANOMALY_05000242 (0)
 #define ANOMALY_05000244 (0)
+#define ANOMALY_05000248 (0)
+#define ANOMALY_05000250 (0)
 #define ANOMALY_05000261 (0)
 #define ANOMALY_05000263 (0)
 #define ANOMALY_05000266 (0)
 #define ANOMALY_05000273 (0)
+#define ANOMALY_05000274 (0)
 #define ANOMALY_05000278 (0)
 #define ANOMALY_05000285 (0)
+#define ANOMALY_05000287 (0)
+#define ANOMALY_05000301 (0)
 #define ANOMALY_05000305 (0)
 #define ANOMALY_05000307 (0)
 #define ANOMALY_05000311 (0)
 #define ANOMALY_05000312 (0)
 #define ANOMALY_05000323 (0)
+#define ANOMALY_05000362 (1)
 #define ANOMALY_05000363 (0)
+#define ANOMALY_05000400 (0)
 #define ANOMALY_05000412 (0)
 #define ANOMALY_05000447 (0)
 #define ANOMALY_05000448 (0)
+#define ANOMALY_05000450 (0)
 
 #endif
index 14427de7d77f6ebf571ca2e9bf3f423778311138..4c572443147e62d0f32b81ca0cc9d1297ccb2625 100644 (file)
@@ -59,6 +59,7 @@ config DMA7_UARTTX
        default 10
 config TIMER0
        int "TIMER0"
+       default 7 if TICKSOURCE_GPTMR0
        default 8
 config TIMER1
        int "TIMER1"
index 0c66bf44cfab81629e22c4d619d294dd87ded2d1..895f213ea454d11038c536a5c0e9645093e6ea51 100644 (file)
@@ -173,7 +173,7 @@ static struct bfin5xx_spi_chip spi_flash_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 /* SPI ADC chip */
 static struct bfin5xx_spi_chip spi_adc_chip_info = {
        .ctl_reg = 0x1000,
@@ -216,7 +216,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
        {
                .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
                .max_speed_hz = 4,     /* actual baudrate is SCLK/(2xspeed_hz) */
index e8974878d8c2807dc34bb2baa4b5822959558a5c..a727e538fa2857e128baa6d9b61a73f0c06b8eb0 100644 (file)
@@ -82,7 +82,7 @@ static struct bfin5xx_spi_chip spi_flash_chip_info = {
 #endif
 
 /* SPI ADC chip */
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 static struct bfin5xx_spi_chip spi_adc_chip_info = {
        .enable_dma = 1,         /* use dma transfer with this chip*/
        .bits_per_word = 16,
@@ -117,7 +117,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
        {
                .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
                .max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
index 08cd0969de475a98b6b82670b80825fab8e0a891..842f1c9c239336e684bc2f7fd7ad0d733a27ffb7 100644 (file)
@@ -118,7 +118,7 @@ static struct bfin5xx_spi_chip spi_flash_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 /* SPI ADC chip */
 static struct bfin5xx_spi_chip spi_adc_chip_info = {
        .enable_dma = 1,         /* use dma transfer with this chip*/
@@ -154,7 +154,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
        {
                .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
                .max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
index db96f33f72e238ee5d4c64178232859a692645cf..e19c565ade160e4639c4f17bddf4c4e13c17c225 100644 (file)
@@ -192,7 +192,7 @@ static struct bfin5xx_spi_chip spi_flash_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 /* SPI ADC chip */
 static struct bfin5xx_spi_chip spi_adc_chip_info = {
        .enable_dma = 1,         /* use dma transfer with this chip*/
@@ -237,7 +237,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
        {
                .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
                .max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
@@ -448,7 +448,7 @@ static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
                .irq = 39,
        },
 #endif
-#if defined(CONFIG_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
        {
                I2C_BOARD_INFO("pcf8574_lcd", 0x22),
        },
index 1cf893e2e55baffa27cf4aa8aa2d2757505f76f1..31145b509e20c1ae2054a1006c9f4a9165a958da 100644 (file)
@@ -6,7 +6,7 @@
  * Licensed under the GPL-2 or later.
  */
 
-/* This file shoule be up to date with:
+/* This file should be up to date with:
  *  - Revision E, 09/18/2008; ADSP-BF531/BF532/BF533 Blackfin Processor Anomaly List
  */
 
 # define ANOMALY_BF533 0
 #endif
 
-/* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot 2 Not Supported */
+/* Multi-issue instruction with dsp32shiftimm in slot1 and P-reg store in slot 2 not supported */
 #define ANOMALY_05000074 (1)
 /* UART Line Status Register (UART_LSR) Bits Are Not Updated at the Same Time */
 #define ANOMALY_05000099 (__SILICON_REVISION__ < 5)
 /* Watchpoint Status Register (WPSTAT) Bits Are Set on Every Corresponding Match */
-#define ANOMALY_05000105 (1)
+#define ANOMALY_05000105 (__SILICON_REVISION__ > 2)
 /* DMA_RUN Bit Is Not Valid after a Peripheral Receive Channel DMA Stops */
 #define ANOMALY_05000119 (1)
 /* Rx.H Cannot Be Used to Access 16-bit System MMR Registers */
@@ -48,7 +48,7 @@
 #define ANOMALY_05000158 (__SILICON_REVISION__ < 5)
 /* PPI Data Lengths Between 8 and 16 Do Not Zero Out Upper Bits */
 #define ANOMALY_05000166 (1)
-/* Turning Serial Ports on with External Frame Syncs */
+/* Turning SPORTs on while External Frame Sync Is Active May Corrupt Data */
 #define ANOMALY_05000167 (1)
 /* PPI_COUNT Cannot Be Programmed to 0 in General Purpose TX or RX Modes */
 #define ANOMALY_05000179 (__SILICON_REVISION__ < 5)
@@ -67,9 +67,9 @@
 /* Current DMA Address Shows Wrong Value During Carry Fix */
 #define ANOMALY_05000199 (__SILICON_REVISION__ < 4)
 /* SPORT TFS and DT Are Incorrectly Driven During Inactive Channels in Certain Conditions */
-#define ANOMALY_05000200 (__SILICON_REVISION__ < 5)
+#define ANOMALY_05000200 (__SILICON_REVISION__ == 3 || __SILICON_REVISION__ == 4)
 /* Receive Frame Sync Not Ignored During Active Frames in SPORT Multi-Channel Mode */
-#define ANOMALY_05000201 (__SILICON_REVISION__ < 4)
+#define ANOMALY_05000201 (__SILICON_REVISION__ == 3)
 /* Possible Infinite Stall with Specific Dual-DAG Situation */
 #define ANOMALY_05000202 (__SILICON_REVISION__ < 5)
 /* Specific Sequence That Can Cause DMA Error or DMA Stopping */
 #define ANOMALY_05000242 (__SILICON_REVISION__ < 5)
 /* If I-Cache Is On, CSYNC/SSYNC/IDLE Around Change of Control Causes Failures */
 #define ANOMALY_05000244 (__SILICON_REVISION__ < 5)
-/* Spurious Hardware Error from an Access in the Shadow of a Conditional Branch */
+/* False Hardware Error from an Access in the Shadow of a Conditional Branch */
 #define ANOMALY_05000245 (1)
 /* Data CPLBs Should Prevent Spurious Hardware Errors */
 #define ANOMALY_05000246 (__SILICON_REVISION__ < 5)
 /* High I/O Activity Causes Output Voltage of Internal Voltage Regulator (Vddint) to Decrease */
 #define ANOMALY_05000270 (__SILICON_REVISION__ < 5)
 /* Spontaneous Reset of Internal Voltage Regulator */
-#define ANOMALY_05000271 (__SILICON_REVISION__ < 4)
+#define ANOMALY_05000271 (__SILICON_REVISION__ == 3)
 /* Certain Data Cache Writethrough Modes Fail for Vddint <= 0.9V */
 #define ANOMALY_05000272 (1)
 /* Writes to Synchronous SDRAM Memory May Be Lost */
 /* New Feature: Additional PPI Frame Sync Sampling Options (Not Available On Older Silicon) */
 #define ANOMALY_05000306 (__SILICON_REVISION__ < 5)
 /* SCKELOW Bit Does Not Maintain State Through Hibernate */
-#define ANOMALY_05000307 (1)
+#define ANOMALY_05000307 (1)   /* note: brokenness is noted in documentation, not anomaly sheet */
 /* False Hardware Errors Caused by Fetches at the Boundary of Reserved Memory */
 #define ANOMALY_05000310 (1)
 /* Erroneous Flag (GPIO) Pin Operations under Specific Sequences */
 #define ANOMALY_05000311 (__SILICON_REVISION__ < 6)
 /* Errors When SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted */
 #define ANOMALY_05000312 (__SILICON_REVISION__ < 6)
-/* PPI Is Level-Sensitive on First Transfer */
+/* PPI Is Level-Sensitive on First Transfer In Single Frame Sync Modes */
 #define ANOMALY_05000313 (__SILICON_REVISION__ < 6)
 /* Killed System MMR Write Completes Erroneously On Next System MMR Access */
 #define ANOMALY_05000315 (__SILICON_REVISION__ < 6)
 #define ANOMALY_05000426 (1)
 /* IFLUSH Instruction at End of Hardware Loop Causes Infinite Stall */
 #define ANOMALY_05000443 (1)
+/* False Hardware Error when RETI points to invalid memory */
+#define ANOMALY_05000461 (1)
 
 /* These anomalies have been "phased" out of analog.com anomaly sheets and are
  * here to show running on older silicon just isn't feasible.
  */
 
+/* Internal voltage regulator can't be modified via register writes */
+#define ANOMALY_05000066 (__SILICON_REVISION__ < 2)
 /* Watchpoints (Hardware Breakpoints) are not supported */
 #define ANOMALY_05000067 (__SILICON_REVISION__ < 3)
+/* SDRAM PSSE bit cannot be set again after SDRAM Powerup */
+#define ANOMALY_05000070 (__SILICON_REVISION__ < 2)
+/* Writing FIO_DIR can corrupt a programmable flag's data */
+#define ANOMALY_05000079 (__SILICON_REVISION__ < 2)
+/* Timer Auto-Baud Mode requires the UART clock to be enabled */
+#define ANOMALY_05000086 (__SILICON_REVISION__ < 2)
+/* Internal Clocking Modes on SPORT0 not supported */
+#define ANOMALY_05000088 (__SILICON_REVISION__ < 2)
+/* Internal voltage regulator does not wake up from an RTC wakeup */
+#define ANOMALY_05000092 (__SILICON_REVISION__ < 2)
+/* The IFLUSH instruction must be preceded by a CSYNC instruction */
+#define ANOMALY_05000093 (__SILICON_REVISION__ < 2)
+/* Vectoring to an instruction that is presently being filled into the instruction cache may cause erroneous behavior */
+#define ANOMALY_05000095 (__SILICON_REVISION__ < 2)
+/* PREFETCH, FLUSH, and FLUSHINV must be followed by a CSYNC */
+#define ANOMALY_05000096 (__SILICON_REVISION__ < 2)
+/* Performance Monitor 0 and 1 are swapped when monitoring memory events */
+#define ANOMALY_05000097 (__SILICON_REVISION__ < 2)
+/* 32-bit SPORT DMA will be word reversed */
+#define ANOMALY_05000098 (__SILICON_REVISION__ < 2)
+/* Incorrect status in the UART_IIR register */
+#define ANOMALY_05000100 (__SILICON_REVISION__ < 2)
+/* Reading X_MODIFY or Y_MODIFY while DMA channel is active */
+#define ANOMALY_05000101 (__SILICON_REVISION__ < 2)
+/* Descriptor-based MemDMA may lock up with 32-bit transfers or if transfers span 64KB buffers */
+#define ANOMALY_05000102 (__SILICON_REVISION__ < 2)
+/* Incorrect value written to the cycle counters */
+#define ANOMALY_05000103 (__SILICON_REVISION__ < 2)
+/* Stores to L1 Data memory incorrect when a specific sequence is followed */
+#define ANOMALY_05000104 (__SILICON_REVISION__ < 2)
+/* Programmable Flag (PF3) functionality not supported in all PPI modes */
+#define ANOMALY_05000106 (__SILICON_REVISION__ < 2)
+/* Data store can be lost when targeting a cache line fill */
+#define ANOMALY_05000107 (__SILICON_REVISION__ < 2)
 /* Reserved bits in SYSCFG register not set at power on */
 #define ANOMALY_05000109 (__SILICON_REVISION__ < 3)
+/* Infinite Core Stall */
+#define ANOMALY_05000114 (__SILICON_REVISION__ < 2)
+/* PPI_FSx may glitch when generated by the on chip Timers */
+#define ANOMALY_05000115 (__SILICON_REVISION__ < 2)
 /* Trace Buffers may record discontinuities into emulation mode and/or exception, NMI, reset handlers */
 #define ANOMALY_05000116 (__SILICON_REVISION__ < 3)
+/* DTEST registers allow access to Data Cache when DTEST_COMMAND< 14 >= 0 */
+#define ANOMALY_05000117 (__SILICON_REVISION__ < 2)
+/* Booting from an 8-bit or 24-bit Addressable SPI device is not supported */
+#define ANOMALY_05000118 (__SILICON_REVISION__ < 2)
 /* DTEST_COMMAND initiated memory access may be incorrect if data cache or DMA is active */
 #define ANOMALY_05000123 (__SILICON_REVISION__ < 3)
 /* DMA Lock-up at CCLK to SCLK ratios of 4:1, 2:1, or 1:1 */
 /* DMEM_CONTROL is not set on Reset */
 #define ANOMALY_05000137 (__SILICON_REVISION__ < 3)
 /* SPI boot will not complete if there is a zero fill block in the loader file */
-#define ANOMALY_05000138 (__SILICON_REVISION__ < 3)
+#define ANOMALY_05000138 (__SILICON_REVISION__ == 2)
+/* Timerx_Config must be set for using the PPI in GP output mode with internal Frame Syncs */
+#define ANOMALY_05000139 (__SILICON_REVISION__ < 2)
 /* Allowing the SPORT RX FIFO to fill will cause an overflow */
 #define ANOMALY_05000140 (__SILICON_REVISION__ < 3)
 /* An Infinite Stall occurs with a particular sequence of consecutive dual dag events */
 #define ANOMALY_05000145 (__SILICON_REVISION__ < 3)
 /* MDMA may lose the first few words of a descriptor chain */
 #define ANOMALY_05000146 (__SILICON_REVISION__ < 3)
-/* The source MDMA descriptor may stop with a DMA Error */
+/* Source MDMA descriptor may stop with a DMA Error near beginning of descriptor fetch */
 #define ANOMALY_05000147 (__SILICON_REVISION__ < 3)
 /* When booting from a 16-bit asynchronous memory device, the upper 8-bits of each word must be 0x00 */
 #define ANOMALY_05000148 (__SILICON_REVISION__ < 3)
 /* Frame Delay in SPORT Multichannel Mode */
 #define ANOMALY_05000153 (__SILICON_REVISION__ < 3)
-/* SPORT TFS signal is active in Multi-channel mode outside of valid channels */
+/* SPORT TFS signal stays active in multichannel mode outside of valid channels */
 #define ANOMALY_05000154 (__SILICON_REVISION__ < 3)
 /* Timer1 can not be used for PWMOUT mode when a certain PPI mode is in use */
 #define ANOMALY_05000155 (__SILICON_REVISION__ < 3)
-/* A killed 32-bit System MMR write will lead to the next system MMR access thinking it should be 32-bit. */
+/* Killed 32-bit MMR write leads to next system MMR access thinking it should be 32-bit */
 #define ANOMALY_05000157 (__SILICON_REVISION__ < 3)
 /* SPORT transmit data is not gated by external frame sync in certain conditions */
 #define ANOMALY_05000163 (__SILICON_REVISION__ < 3)
 #define ANOMALY_05000206 (__SILICON_REVISION__ < 3)
 
 /* Anomalies that don't exist on this proc */
+#define ANOMALY_05000120 (0)
+#define ANOMALY_05000149 (0)
+#define ANOMALY_05000171 (0)
+#define ANOMALY_05000220 (0)
+#define ANOMALY_05000248 (0)
 #define ANOMALY_05000266 (0)
+#define ANOMALY_05000274 (0)
+#define ANOMALY_05000287 (0)
 #define ANOMALY_05000323 (0)
 #define ANOMALY_05000353 (1)
+#define ANOMALY_05000362 (1)
 #define ANOMALY_05000380 (0)
 #define ANOMALY_05000386 (1)
+#define ANOMALY_05000389 (0)
 #define ANOMALY_05000412 (0)
+#define ANOMALY_05000430 (0)
 #define ANOMALY_05000432 (0)
 #define ANOMALY_05000435 (0)
 #define ANOMALY_05000447 (0)
 #define ANOMALY_05000448 (0)
+#define ANOMALY_05000456 (0)
+#define ANOMALY_05000450 (0)
 
 #endif
index bbc08fd4f122ae2ad71cc8ed661c50886703d8b0..d81224f9d723d0f8e3b27ea8d558ec1389e77f1f 100644 (file)
@@ -66,6 +66,7 @@ config IRQ_MAC_TX
        default 11
 config IRQ_TIMER0
        int "IRQ_TIMER0"
+       default 7 if TICKSOURCE_GPTMR0
        default 8
 config IRQ_TIMER1
        int "IRQ_TIMER1"
index 41c75b9bfac03dde78f1269738fd750193efe4a2..4fee196731279f5eb86a794be4894d6eefb114db 100644 (file)
@@ -86,7 +86,7 @@ static struct bfin5xx_spi_chip spi_flash_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 /* SPI ADC chip */
 static struct bfin5xx_spi_chip spi_adc_chip_info = {
        .enable_dma = 1,         /* use dma transfer with this chip*/
@@ -129,7 +129,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
        {
                .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
                .max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
index 4e1de1e53f89f396a38ff5faf71fa04300434381..26707ce39f29b98666593b011deb89c8912e5ede 100644 (file)
@@ -265,8 +265,8 @@ static struct bfin5xx_spi_chip spi_flash_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) \
-       || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) \
+       || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 /* SPI ADC chip */
 static struct bfin5xx_spi_chip spi_adc_chip_info = {
        .enable_dma = 1,         /* use dma transfer with this chip*/
@@ -333,8 +333,8 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) \
-       || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) \
+       || defined(CONFIG_BFIN_SPI_ADC_MODULE)
        {
                .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
                .max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
index 0572926da23f4ef81a2648b70a7f233c1a3b72fb..dfb5036f8a6b2d8dacdb414227f010196b830e39 100644 (file)
@@ -508,8 +508,8 @@ static struct bfin5xx_spi_chip spi_flash_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) \
-       || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) \
+       || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 /* SPI ADC chip */
 static struct bfin5xx_spi_chip spi_adc_chip_info = {
        .enable_dma = 1,         /* use dma transfer with this chip*/
@@ -607,6 +607,43 @@ static const struct ad7879_platform_data bfin_ad7879_ts_info = {
 };
 #endif
 
+#if defined(CONFIG_INPUT_ADXL34X) || defined(CONFIG_INPUT_ADXL34X_MODULE)
+#include <linux/input.h>
+#include <linux/spi/adxl34x.h>
+static const struct adxl34x_platform_data adxl34x_info = {
+       .x_axis_offset = 0,
+       .y_axis_offset = 0,
+       .z_axis_offset = 0,
+       .tap_threshold = 0x31,
+       .tap_duration = 0x10,
+       .tap_latency = 0x60,
+       .tap_window = 0xF0,
+       .tap_axis_control = ADXL_TAP_X_EN | ADXL_TAP_Y_EN | ADXL_TAP_Z_EN,
+       .act_axis_control = 0xFF,
+       .activity_threshold = 5,
+       .inactivity_threshold = 3,
+       .inactivity_time = 4,
+       .free_fall_threshold = 0x7,
+       .free_fall_time = 0x20,
+       .data_rate = 0x8,
+       .data_range = ADXL_FULL_RES,
+
+       .ev_type = EV_ABS,
+       .ev_code_x = ABS_X,             /* EV_REL */
+       .ev_code_y = ABS_Y,             /* EV_REL */
+       .ev_code_z = ABS_Z,             /* EV_REL */
+
+       .ev_code_tap_x = BTN_TOUCH,             /* EV_KEY */
+       .ev_code_tap_y = BTN_TOUCH,             /* EV_KEY */
+       .ev_code_tap_z = BTN_TOUCH,             /* EV_KEY */
+
+/*     .ev_code_ff = KEY_F,*/          /* EV_KEY */
+/*     .ev_code_act_inactivity = KEY_A,*/      /* EV_KEY */
+       .power_mode = ADXL_AUTO_SLEEP | ADXL_LINK,
+       .fifo_mode = ADXL_FIFO_STREAM,
+};
+#endif
+
 #if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
 static struct bfin5xx_spi_chip spi_ad7879_chip_info = {
        .enable_dma = 0,
@@ -695,8 +732,8 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
                .mode = SPI_MODE_3,
        },
 #endif
-#if defined(CONFIG_SPI_ADC_BF533) \
-       || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) \
+       || defined(CONFIG_BFIN_SPI_ADC_MODULE)
        {
                .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
                .max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
@@ -1280,7 +1317,7 @@ static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
                .irq = IRQ_PF5,
        },
 #endif
-#if defined(CONFIG_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
        {
                I2C_BOARD_INFO("pcf8574_lcd", 0x22),
        },
@@ -1312,6 +1349,13 @@ static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
                .platform_data = (void *)&adp5520_pdev_data,
        },
 #endif
+#if defined(CONFIG_INPUT_ADXL34X_I2C) || defined(CONFIG_INPUT_ADXL34X_I2C_MODULE)
+       {
+               I2C_BOARD_INFO("adxl34x", 0x53),
+               .irq = IRQ_PG3,
+               .platform_data = (void *)&adxl34x_info,
+       },
+#endif
 };
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
@@ -1358,16 +1402,18 @@ static struct resource bfin_pata_resources[] = {
 static struct pata_platform_info bfin_pata_platform_data = {
        .ioport_shift = 0,
 };
-
+/* CompactFlash Storage Card Memory Mapped Adressing
+ * /REG = A11 = 1
+ */
 static struct resource bfin_pata_resources[] = {
        {
-               .start = 0x20211820,
-               .end = 0x2021183F,
+               .start = 0x20211800,
+               .end = 0x20211807,
                .flags = IORESOURCE_MEM,
        },
        {
-               .start = 0x2021181C,
-               .end = 0x2021181F,
+               .start = 0x2021180E,    /* Device Ctl */
+               .end = 0x2021180E,
                .flags = IORESOURCE_MEM,
        },
 };
@@ -1527,7 +1573,8 @@ static int __init stamp_init(void)
        platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
        spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
 
-#if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
+#if (defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)) \
+        && defined(PATA_INT)
        irq_desc[PATA_INT].status |= IRQ_NOAUTOEN;
 #endif
 
index 53ad10f3cd76fb5a7fe945f032e80a172dc0f7fd..280574591201e54b98b61d65513d6d92d79098a3 100644 (file)
@@ -86,7 +86,7 @@ static struct bfin5xx_spi_chip spi_flash_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 /* SPI ADC chip */
 static struct bfin5xx_spi_chip spi_adc_chip_info = {
        .enable_dma = 1,         /* use dma transfer with this chip*/
@@ -129,7 +129,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
        {
                .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
                .max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
index 1bfd80c26c90c35fe0921585a177d4e215eb3bdd..fc9663425465cf5f751f31082f6025766c41cd23 100644 (file)
@@ -6,7 +6,7 @@
  * Licensed under the GPL-2 or later.
  */
 
-/* This file shoule be up to date with:
+/* This file should be up to date with:
  *  - Revision D, 09/18/2008; ADSP-BF534/ADSP-BF536/ADSP-BF537 Blackfin Processor Anomaly List
  */
 
 
 /* Multi-issue instruction with dsp32shiftimm in slot1 and P-reg store in slot 2 not supported */
 #define ANOMALY_05000074 (1)
-/* DMA_RUN bit is not valid after a Peripheral Receive Channel DMA stops */
+/* DMA_RUN Bit Is Not Valid after a Peripheral Receive Channel DMA Stops */
 #define ANOMALY_05000119 (1)
-/* Rx.H cannot be used to access 16-bit System MMR registers */
+/* Rx.H Cannot Be Used to Access 16-bit System MMR Registers */
 #define ANOMALY_05000122 (1)
 /* Killed 32-bit MMR write leads to next system MMR access thinking it should be 32-bit */
 #define ANOMALY_05000157 (__SILICON_REVISION__ < 2)
-/* Turning SPORTs on while External Frame Sync Is Active May Corrupt Data */
-#define ANOMALY_05000167 (1)
-/* PPI_DELAY not functional in PPI modes with 0 frame syncs */
+/* PPI_DELAY Not Functional in PPI Modes with 0 Frame Syncs */
 #define ANOMALY_05000180 (1)
 /* Instruction Cache Is Not Functional */
 #define ANOMALY_05000237 (__SILICON_REVISION__ < 2)
-/* If i-cache is on, CSYNC/SSYNC/IDLE around Change of Control causes failures */
+/* If I-Cache Is On, CSYNC/SSYNC/IDLE Around Change of Control Causes Failures */
 #define ANOMALY_05000244 (__SILICON_REVISION__ < 3)
-/* Spurious Hardware Error from an access in the shadow of a conditional branch */
+/* False Hardware Error from an Access in the Shadow of a Conditional Branch */
 #define ANOMALY_05000245 (1)
 /* CLKIN Buffer Output Enable Reset Behavior Is Changed */
 #define ANOMALY_05000247 (1)
-/* Incorrect Bit-Shift of Data Word in Multichannel (TDM) mode in certain conditions */
+/* Incorrect Bit Shift of Data Word in Multichannel (TDM) Mode in Certain Conditions */
 #define ANOMALY_05000250 (__SILICON_REVISION__ < 3)
 /* EMAC Tx DMA error after an early frame abort */
 #define ANOMALY_05000252 (__SILICON_REVISION__ < 3)
-/* Maximum external clock speed for Timers */
+/* Maximum External Clock Speed for Timers */
 #define ANOMALY_05000253 (__SILICON_REVISION__ < 3)
-/* Incorrect Timer Pulse Width in Single-Shot PWM_OUT mode with external clock */
+/* Incorrect Timer Pulse Width in Single-Shot PWM_OUT Mode with External Clock */
 #define ANOMALY_05000254 (__SILICON_REVISION__ > 2)
-/* Entering Hibernate Mode with RTC Seconds event interrupt not functional */
+/* Entering Hibernate State with RTC Seconds Interrupt Not Functional */
 #define ANOMALY_05000255 (__SILICON_REVISION__ < 3)
 /* EMAC MDIO input latched on wrong MDC edge */
 #define ANOMALY_05000256 (__SILICON_REVISION__ < 3)
-/* Interrupt/Exception during short hardware loop may cause bad instruction fetches */
+/* Interrupt/Exception During Short Hardware Loop May Cause Bad Instruction Fetches */
 #define ANOMALY_05000257 (__SILICON_REVISION__ < 3)
-/* Instruction Cache is corrupted when bits 9 and 12 of the ICPLB Data registers differ */
+/* Instruction Cache Is Corrupted When Bits 9 and 12 of the ICPLB Data Registers Differ */
 #define ANOMALY_05000258 (((ANOMALY_BF536 || ANOMALY_BF537) && __SILICON_REVISION__ == 1) || __SILICON_REVISION__ == 2)
-/* ICPLB_STATUS MMR register may be corrupted */
+/* ICPLB_STATUS MMR Register May Be Corrupted */
 #define ANOMALY_05000260 (__SILICON_REVISION__ == 2)
-/* DCPLB_FAULT_ADDR MMR register may be corrupted */
+/* DCPLB_FAULT_ADDR MMR Register May Be Corrupted */
 #define ANOMALY_05000261 (__SILICON_REVISION__ < 3)
-/* Stores to data cache may be lost */
+/* Stores To Data Cache May Be Lost */
 #define ANOMALY_05000262 (__SILICON_REVISION__ < 3)
-/* Hardware loop corrupted when taking an ICPLB exception */
+/* Hardware Loop Corrupted When Taking an ICPLB Exception */
 #define ANOMALY_05000263 (__SILICON_REVISION__ == 2)
-/* CSYNC/SSYNC/IDLE causes infinite stall in second to last instruction in hardware loop */
+/* CSYNC/SSYNC/IDLE Causes Infinite Stall in Penultimate Instruction in Hardware Loop */
 #define ANOMALY_05000264 (__SILICON_REVISION__ < 3)
-/* Sensitivity to noise with slow input edge rates on external SPORT TX and RX clocks */
+/* Sensitivity To Noise with Slow Input Edge Rates on External SPORT TX and RX Clocks */
 #define ANOMALY_05000265 (1)
 /* Memory DMA error when peripheral DMA is running with non-zero DEB_TRAFFIC_PERIOD */
 #define ANOMALY_05000268 (__SILICON_REVISION__ < 3)
-/* High I/O activity causes output voltage of internal voltage regulator (VDDint) to decrease */
+/* High I/O Activity Causes Output Voltage of Internal Voltage Regulator (Vddint) to Decrease */
 #define ANOMALY_05000270 (__SILICON_REVISION__ < 3)
-/* Certain data cache write through modes fail for VDDint <=0.9V */
+/* Certain Data Cache Writethrough Modes Fail for Vddint <= 0.9V */
 #define ANOMALY_05000272 (1)
-/* Writes to Synchronous SDRAM memory may be lost */
+/* Writes to Synchronous SDRAM Memory May Be Lost */
 #define ANOMALY_05000273 (__SILICON_REVISION__ < 3)
-/* Writes to an I/O data register one SCLK cycle after an edge is detected may clear interrupt */
+/* Writes to an I/O Data Register One SCLK Cycle after an Edge Is Detected May Clear Interrupt */
 #define ANOMALY_05000277 (__SILICON_REVISION__ < 3)
-/* Disabling Peripherals with DMA running may cause DMA system instability */
+/* Disabling Peripherals with DMA Running May Cause DMA System Instability */
 #define ANOMALY_05000278 (((ANOMALY_BF536 || ANOMALY_BF537) && __SILICON_REVISION__ < 3) || (ANOMALY_BF534 && __SILICON_REVISION__ < 2))
 /* SPI Master boot mode does not work well with Atmel Data flash devices */
 #define ANOMALY_05000280 (1)
-/* False Hardware Error Exception when ISR context is not restored */
+/* False Hardware Error Exception When ISR Context Is Not Restored */
 #define ANOMALY_05000281 (__SILICON_REVISION__ < 3)
-/* Memory DMA corruption with 32-bit data and traffic control */
+/* Memory DMA Corruption with 32-Bit Data and Traffic Control */
 #define ANOMALY_05000282 (__SILICON_REVISION__ < 3)
 /* System MMR Write Is Stalled Indefinitely When Killed in a Particular Stage */
 #define ANOMALY_05000283 (__SILICON_REVISION__ < 3)
 /* New Feature: EMAC TX DMA Word Alignment (Not Available On Older Silicon) */
 #define ANOMALY_05000285 (__SILICON_REVISION__ < 3)
-/* SPORTs may receive bad data if FIFOs fill up */
+/* SPORTs May Receive Bad Data If FIFOs Fill Up */
 #define ANOMALY_05000288 (__SILICON_REVISION__ < 3)
-/* Memory to memory DMA source/destination descriptors must be in same memory space */
+/* Memory-To-Memory DMA Source/Destination Descriptors Must Be in Same Memory Space */
 #define ANOMALY_05000301 (1)
 /* SSYNCs After Writes To CAN/DMA MMR Registers Are Not Always Handled Correctly */
 #define ANOMALY_05000304 (__SILICON_REVISION__ < 3)
 #define ANOMALY_05000307 (__SILICON_REVISION__ < 3)
 /* Writing UART_THR while UART clock is disabled sends erroneous start bit */
 #define ANOMALY_05000309 (__SILICON_REVISION__ < 3)
-/* False hardware errors caused by fetches at the boundary of reserved memory */
+/* False Hardware Errors Caused by Fetches at the Boundary of Reserved Memory */
 #define ANOMALY_05000310 (1)
-/* Errors when SSYNC, CSYNC, or loads to LT, LB and LC registers are interrupted */
+/* Errors When SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted */
 #define ANOMALY_05000312 (1)
-/* PPI is level sensitive on first transfer */
+/* PPI Is Level-Sensitive on First Transfer In Single Frame Sync Modes */
 #define ANOMALY_05000313 (1)
 /* Killed System MMR Write Completes Erroneously On Next System MMR Access */
 #define ANOMALY_05000315 (__SILICON_REVISION__ < 3)
 #define ANOMALY_05000426 (1)
 /* IFLUSH Instruction at End of Hardware Loop Causes Infinite Stall */
 #define ANOMALY_05000443 (1)
+/* False Hardware Error when RETI points to invalid memory */
+#define ANOMALY_05000461 (1)
 
 /* Anomalies that don't exist on this proc */
+#define ANOMALY_05000099 (0)
+#define ANOMALY_05000120 (0)
 #define ANOMALY_05000125 (0)
+#define ANOMALY_05000149 (0)
 #define ANOMALY_05000158 (0)
+#define ANOMALY_05000171 (0)
+#define ANOMALY_05000179 (0)
 #define ANOMALY_05000183 (0)
 #define ANOMALY_05000198 (0)
+#define ANOMALY_05000215 (0)
+#define ANOMALY_05000220 (0)
+#define ANOMALY_05000227 (0)
 #define ANOMALY_05000230 (0)
+#define ANOMALY_05000231 (0)
+#define ANOMALY_05000233 (0)
+#define ANOMALY_05000242 (0)
+#define ANOMALY_05000248 (0)
 #define ANOMALY_05000266 (0)
+#define ANOMALY_05000274 (0)
+#define ANOMALY_05000287 (0)
 #define ANOMALY_05000311 (0)
 #define ANOMALY_05000323 (0)
 #define ANOMALY_05000353 (1)
+#define ANOMALY_05000362 (1)
 #define ANOMALY_05000363 (0)
 #define ANOMALY_05000380 (0)
 #define ANOMALY_05000386 (1)
+#define ANOMALY_05000389 (0)
+#define ANOMALY_05000400 (0)
 #define ANOMALY_05000412 (0)
+#define ANOMALY_05000430 (0)
 #define ANOMALY_05000432 (0)
 #define ANOMALY_05000435 (0)
 #define ANOMALY_05000447 (0)
 #define ANOMALY_05000448 (0)
+#define ANOMALY_05000456 (0)
+#define ANOMALY_05000450 (0)
 
 #endif
index f068c3523cdc716ab04806f2d2dd4fafbcbd5afc..2d280f504ab0a829178366118cb116b07248e42f 100644 (file)
@@ -57,6 +57,7 @@ config IRQ_UART0_TX
        default 10
 config IRQ_TIMER0
        int "IRQ_TIMER0"
+       default 7 if TICKSOURCE_GPTMR0
        default 8
 config IRQ_TIMER1
        int "IRQ_TIMER1"
index 3a5699827363b9e68c547c2c7628a5852660ab48..175ca9ef7232bca986d412901dbe639b6d4b20e6 100644 (file)
@@ -6,7 +6,7 @@
  * Licensed under the GPL-2 or later.
  */
 
-/* This file shoule be up to date with:
+/* This file should be up to date with:
  *  - Revision G, 09/18/2008; ADSP-BF538/BF538F Blackfin Processor Anomaly List
  *  - Revision L, 09/18/2008; ADSP-BF539/BF539F Blackfin Processor Anomaly List
  */
 #ifndef _MACH_ANOMALY_H_
 #define _MACH_ANOMALY_H_
 
+/* We do not support old silicon - sorry */
 #if __SILICON_REVISION__ < 4
-# error will not work on BF538 silicon version 0.0, 0.1, 0.2, or 0.3
+# error will not work on BF538/BF539 silicon version 0.0, 0.1, 0.2, or 0.3
 #endif
 
-/* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot2 Not Supported */
+#if defined(__ADSPBF538__)
+# define ANOMALY_BF538 1
+#else
+# define ANOMALY_BF538 0
+#endif
+#if defined(__ADSPBF539__)
+# define ANOMALY_BF539 1
+#else
+# define ANOMALY_BF539 0
+#endif
+
+/* Multi-issue instruction with dsp32shiftimm in slot1 and P-reg store in slot 2 not supported */
 #define ANOMALY_05000074 (1)
 /* DMA_RUN Bit Is Not Valid after a Peripheral Receive Channel DMA Stops */
 #define ANOMALY_05000119 (1)
 /* Rx.H Cannot Be Used to Access 16-bit System MMR Registers */
 #define ANOMALY_05000122 (1)
-/* PPI Data Lengths between 8 and 16 Do Not Zero Out Upper Bits */
+/* PPI Data Lengths Between 8 and 16 Do Not Zero Out Upper Bits */
 #define ANOMALY_05000166 (1)
 /* PPI_COUNT Cannot Be Programmed to 0 in General Purpose TX or RX Modes */
 #define ANOMALY_05000179 (1)
 #define ANOMALY_05000229 (1)
 /* PPI_FS3 Is Not Driven in 2 or 3 Internal Frame Sync Transmit Modes */
 #define ANOMALY_05000233 (1)
-/* If i-cache is on, CSYNC/SSYNC/IDLE around Change of Control causes failures */
+/* If I-Cache Is On, CSYNC/SSYNC/IDLE Around Change of Control Causes Failures */
 #define ANOMALY_05000244 (__SILICON_REVISION__ < 3)
-/* Spurious Hardware Error from an Access in the Shadow of a Conditional Branch */
+/* False Hardware Error from an Access in the Shadow of a Conditional Branch */
 #define ANOMALY_05000245 (1)
 /* Maximum External Clock Speed for Timers */
 #define ANOMALY_05000253 (1)
-/* DCPLB_FAULT_ADDR MMR register may be corrupted */
+/* DCPLB_FAULT_ADDR MMR Register May Be Corrupted */
 #define ANOMALY_05000261 (__SILICON_REVISION__ < 3)
 /* High I/O Activity Causes Output Voltage of Internal Voltage Regulator (Vddint) to Decrease */
 #define ANOMALY_05000270 (__SILICON_REVISION__ < 4)
 #define ANOMALY_05000277 (__SILICON_REVISION__ < 4)
 /* Disabling Peripherals with DMA Running May Cause DMA System Instability */
 #define ANOMALY_05000278 (__SILICON_REVISION__ < 4)
-/* False Hardware Error Exception when ISR Context Is Not Restored */
+/* False Hardware Error Exception When ISR Context Is Not Restored */
 #define ANOMALY_05000281 (__SILICON_REVISION__ < 4)
 /* Memory DMA Corruption with 32-Bit Data and Traffic Control */
 #define ANOMALY_05000282 (__SILICON_REVISION__ < 4)
-/* System MMR Write Is Stalled Indefinitely when Killed in a Particular Stage */
+/* System MMR Write Is Stalled Indefinitely When Killed in a Particular Stage */
 #define ANOMALY_05000283 (__SILICON_REVISION__ < 4)
 /* SPORTs May Receive Bad Data If FIFOs Fill Up */
 #define ANOMALY_05000288 (__SILICON_REVISION__ < 4)
 #define ANOMALY_05000307 (__SILICON_REVISION__ < 4)
 /* False Hardware Errors Caused by Fetches at the Boundary of Reserved Memory */
 #define ANOMALY_05000310 (1)
-/* Errors when SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted */
+/* Errors When SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted */
 #define ANOMALY_05000312 (__SILICON_REVISION__ < 5)
-/* PPI Is Level-Sensitive on First Transfer */
+/* PPI Is Level-Sensitive on First Transfer In Single Frame Sync Modes */
 #define ANOMALY_05000313 (__SILICON_REVISION__ < 4)
-/* Killed System MMR Write Completes Erroneously on Next System MMR Access */
+/* Killed System MMR Write Completes Erroneously On Next System MMR Access */
 #define ANOMALY_05000315 (__SILICON_REVISION__ < 4)
 /* PFx Glitch on Write to FIO_FLAG_D or FIO_FLAG_T */
-#define ANOMALY_05000318 (__SILICON_REVISION__ < 4)
+#define ANOMALY_05000318 (ANOMALY_BF539 && __SILICON_REVISION__ < 4)
 /* Regulator Programming Blocked when Hibernate Wakeup Source Remains Active */
 #define ANOMALY_05000355 (__SILICON_REVISION__ < 5)
 /* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */
 #define ANOMALY_05000436 (__SILICON_REVISION__ > 3)
 /* IFLUSH Instruction at End of Hardware Loop Causes Infinite Stall */
 #define ANOMALY_05000443 (1)
+/* False Hardware Error when RETI points to invalid memory */
+#define ANOMALY_05000461 (1)
 
 /* Anomalies that don't exist on this proc */
+#define ANOMALY_05000099 (0)
+#define ANOMALY_05000120 (0)
+#define ANOMALY_05000149 (0)
 #define ANOMALY_05000158 (0)
+#define ANOMALY_05000171 (0)
 #define ANOMALY_05000198 (0)
+#define ANOMALY_05000215 (0)
+#define ANOMALY_05000220 (0)
+#define ANOMALY_05000227 (0)
 #define ANOMALY_05000230 (0)
+#define ANOMALY_05000231 (0)
+#define ANOMALY_05000242 (0)
+#define ANOMALY_05000248 (0)
+#define ANOMALY_05000250 (0)
+#define ANOMALY_05000254 (0)
 #define ANOMALY_05000263 (0)
+#define ANOMALY_05000274 (0)
+#define ANOMALY_05000287 (0)
 #define ANOMALY_05000305 (0)
 #define ANOMALY_05000311 (0)
 #define ANOMALY_05000323 (0)
 #define ANOMALY_05000353 (1)
+#define ANOMALY_05000362 (1)
 #define ANOMALY_05000363 (0)
 #define ANOMALY_05000380 (0)
 #define ANOMALY_05000386 (1)
+#define ANOMALY_05000389 (0)
+#define ANOMALY_05000400 (0)
 #define ANOMALY_05000412 (0)
+#define ANOMALY_05000430 (0)
 #define ANOMALY_05000432 (0)
 #define ANOMALY_05000435 (0)
 #define ANOMALY_05000447 (0)
 #define ANOMALY_05000448 (0)
+#define ANOMALY_05000456 (0)
+#define ANOMALY_05000450 (0)
 
 #endif
index ea25371a922b3a0c92e19b4c6e0072b2a418fff9..6f628353dde30b1f9b98666d640bcf5830635078 100644 (file)
 #define OFFSET_SCR              0x1C   /* SCR Scratch Register                 */
 #define OFFSET_GCTL             0x24   /* Global Control Register              */
 
-
-#define bfin_write_MDMA_D0_IRQ_STATUS  bfin_write_MDMA0_D0_IRQ_STATUS
-#define bfin_write_MDMA_D0_START_ADDR   bfin_write_MDMA0_D0_START_ADDR
-#define bfin_write_MDMA_S0_START_ADDR   bfin_write_MDMA0_S0_START_ADDR
-#define bfin_write_MDMA_D0_X_COUNT      bfin_write_MDMA0_D0_X_COUNT
-#define bfin_write_MDMA_S0_X_COUNT      bfin_write_MDMA0_S0_X_COUNT
-#define bfin_write_MDMA_D0_Y_COUNT      bfin_write_MDMA0_D0_Y_COUNT
-#define bfin_write_MDMA_S0_Y_COUNT      bfin_write_MDMA0_S0_Y_COUNT
-#define bfin_write_MDMA_D0_X_MODIFY     bfin_write_MDMA0_D0_X_MODIFY
-#define bfin_write_MDMA_S0_X_MODIFY     bfin_write_MDMA0_S0_X_MODIFY
-#define bfin_write_MDMA_D0_Y_MODIFY     bfin_write_MDMA0_D0_Y_MODIFY
-#define bfin_write_MDMA_S0_Y_MODIFY     bfin_write_MDMA0_S0_Y_MODIFY
-#define bfin_write_MDMA_S0_CONFIG       bfin_write_MDMA0_S0_CONFIG
-#define bfin_write_MDMA_D0_CONFIG       bfin_write_MDMA0_D0_CONFIG
-#define bfin_read_MDMA_S0_CONFIG        bfin_read_MDMA0_S0_CONFIG
-#define bfin_read_MDMA_D0_IRQ_STATUS    bfin_read_MDMA0_D0_IRQ_STATUS
-#define bfin_write_MDMA_S0_IRQ_STATUS   bfin_write_MDMA0_S0_IRQ_STATUS
-
-
 /* DPMC*/
 #define bfin_read_STOPCK_OFF() bfin_read_STOPCK()
 #define bfin_write_STOPCK_OFF(val) bfin_write_STOPCK(val)
index 241725bc69881c0703549ce16ddac62389a41754..99ca3f4305e2fd233a86a4cf34e5e9a89492d610 100644 (file)
 #define bfin_write_SIC_ISR0(val)       bfin_write32(SIC_ISR0, val)
 #define bfin_read_SIC_ISR1()           bfin_read32(SIC_ISR1)
 #define bfin_write_SIC_ISR1(val)       bfin_write32(SIC_ISR1, val)
-#define bfin_read_SIC_ISR(x)          bfin_read32(SIC_ISR0 + x * (SIC_ISR1 - SIC_ISR0))
+#define bfin_read_SIC_ISR(x)           bfin_read32(SIC_ISR0 + x * (SIC_ISR1 - SIC_ISR0))
 #define bfin_write_SIC_ISR(x, val)     bfin_write32(SIC_ISR0 + x * (SIC_ISR1 - SIC_ISR0), val)
 #define bfin_read_SIC_IWR0()           bfin_read32(SIC_IWR0)
 #define bfin_write_SIC_IWR0(val)       bfin_write32(SIC_IWR0, val)
 #define bfin_read_SIC_IWR1()           bfin_read32(SIC_IWR1)
 #define bfin_write_SIC_IWR1(val)       bfin_write32(SIC_IWR1, val)
-#define bfin_read_SIC_IWR(x)          bfin_read32(SIC_IWR0 + x * (SIC_IWR1 - SIC_IWR0))
-#define bfin_write_SIC_IWR(x, val)     bfin_write32((SIC_IWR0 + x * (SIC_IWR1 - SIC_IWR0), val)
+#define bfin_read_SIC_IWR(x)           bfin_read32(SIC_IWR0 + x * (SIC_IWR1 - SIC_IWR0))
+#define bfin_write_SIC_IWR(x, val)     bfin_write32(SIC_IWR0 + x * (SIC_IWR1 - SIC_IWR0), val)
 #define bfin_read_SIC_IAR0()           bfin_read32(SIC_IAR0)
 #define bfin_write_SIC_IAR0(val)       bfin_write32(SIC_IAR0, val)
 #define bfin_read_SIC_IAR1()           bfin_read32(SIC_IAR1)
 #define bfin_write_MDMA1_S1_CURR_X_COUNT(val) bfin_write16(MDMA1_S1_CURR_X_COUNT, val)
 #define bfin_read_MDMA1_S1_CURR_Y_COUNT() bfin_read16(MDMA1_S1_CURR_Y_COUNT)
 #define bfin_write_MDMA1_S1_CURR_Y_COUNT(val) bfin_write16(MDMA1_S1_CURR_Y_COUNT, val)
+
+#define bfin_read_MDMA_S0_CONFIG()  bfin_read_MDMA0_S0_CONFIG()
+#define bfin_write_MDMA_S0_CONFIG(val) bfin_write_MDMA0_S0_CONFIG(val)
+#define bfin_read_MDMA_S0_IRQ_STATUS()  bfin_read_MDMA0_S0_IRQ_STATUS()
+#define bfin_write_MDMA_S0_IRQ_STATUS(val) bfin_write_MDMA0_S0_IRQ_STATUS(val)
+#define bfin_read_MDMA_S0_X_MODIFY()  bfin_read_MDMA0_S0_X_MODIFY()
+#define bfin_write_MDMA_S0_X_MODIFY(val) bfin_write_MDMA0_S0_X_MODIFY(val)
+#define bfin_read_MDMA_S0_Y_MODIFY()  bfin_read_MDMA0_S0_Y_MODIFY()
+#define bfin_write_MDMA_S0_Y_MODIFY(val) bfin_write_MDMA0_S0_Y_MODIFY(val)
+#define bfin_read_MDMA_S0_X_COUNT()  bfin_read_MDMA0_S0_X_COUNT()
+#define bfin_write_MDMA_S0_X_COUNT(val) bfin_write_MDMA0_S0_X_COUNT(val)
+#define bfin_read_MDMA_S0_Y_COUNT()  bfin_read_MDMA0_S0_Y_COUNT()
+#define bfin_write_MDMA_S0_Y_COUNT(val) bfin_write_MDMA0_S0_Y_COUNT(val)
+#define bfin_read_MDMA_S0_START_ADDR()  bfin_read_MDMA0_S0_START_ADDR()
+#define bfin_write_MDMA_S0_START_ADDR(val) bfin_write_MDMA0_S0_START_ADDR(val)
+#define bfin_read_MDMA_D0_CONFIG()  bfin_read_MDMA0_D0_CONFIG()
+#define bfin_write_MDMA_D0_CONFIG(val) bfin_write_MDMA0_D0_CONFIG(val)
+#define bfin_read_MDMA_D0_IRQ_STATUS()  bfin_read_MDMA0_D0_IRQ_STATUS()
+#define bfin_write_MDMA_D0_IRQ_STATUS(val) bfin_write_MDMA0_D0_IRQ_STATUS(val)
+#define bfin_read_MDMA_D0_X_MODIFY()  bfin_read_MDMA0_D0_X_MODIFY()
+#define bfin_write_MDMA_D0_X_MODIFY(val) bfin_write_MDMA0_D0_X_MODIFY(val)
+#define bfin_read_MDMA_D0_Y_MODIFY()  bfin_read_MDMA0_D0_Y_MODIFY()
+#define bfin_write_MDMA_D0_Y_MODIFY(val) bfin_write_MDMA0_D0_Y_MODIFY(val)
+#define bfin_read_MDMA_D0_X_COUNT()  bfin_read_MDMA0_D0_X_COUNT()
+#define bfin_write_MDMA_D0_X_COUNT(val) bfin_write_MDMA0_D0_X_COUNT(val)
+#define bfin_read_MDMA_D0_Y_COUNT()  bfin_read_MDMA0_D0_Y_COUNT()
+#define bfin_write_MDMA_D0_Y_COUNT(val) bfin_write_MDMA0_D0_Y_COUNT(val)
+#define bfin_read_MDMA_D0_START_ADDR()  bfin_read_MDMA0_D0_START_ADDR()
+#define bfin_write_MDMA_D0_START_ADDR(val) bfin_write_MDMA0_D0_START_ADDR(val)
+
+#define bfin_read_MDMA_S1_CONFIG()  bfin_read_MDMA0_S1_CONFIG()
+#define bfin_write_MDMA_S1_CONFIG(val) bfin_write_MDMA0_S1_CONFIG(val)
+#define bfin_read_MDMA_S1_IRQ_STATUS()  bfin_read_MDMA0_S1_IRQ_STATUS()
+#define bfin_write_MDMA_S1_IRQ_STATUS(val) bfin_write_MDMA0_S1_IRQ_STATUS(val)
+#define bfin_read_MDMA_S1_X_MODIFY()  bfin_read_MDMA0_S1_X_MODIFY()
+#define bfin_write_MDMA_S1_X_MODIFY(val) bfin_write_MDMA0_S1_X_MODIFY(val)
+#define bfin_read_MDMA_S1_Y_MODIFY()  bfin_read_MDMA0_S1_Y_MODIFY()
+#define bfin_write_MDMA_S1_Y_MODIFY(val) bfin_write_MDMA0_S1_Y_MODIFY(val)
+#define bfin_read_MDMA_S1_X_COUNT()  bfin_read_MDMA0_S1_X_COUNT()
+#define bfin_write_MDMA_S1_X_COUNT(val) bfin_write_MDMA0_S1_X_COUNT(val)
+#define bfin_read_MDMA_S1_Y_COUNT()  bfin_read_MDMA0_S1_Y_COUNT()
+#define bfin_write_MDMA_S1_Y_COUNT(val) bfin_write_MDMA0_S1_Y_COUNT(val)
+#define bfin_read_MDMA_S1_START_ADDR()  bfin_read_MDMA0_S1_START_ADDR()
+#define bfin_write_MDMA_S1_START_ADDR(val) bfin_write_MDMA0_S1_START_ADDR(val)
+#define bfin_read_MDMA_D1_CONFIG()  bfin_read_MDMA0_D1_CONFIG()
+#define bfin_write_MDMA_D1_CONFIG(val) bfin_write_MDMA0_D1_CONFIG(val)
+#define bfin_read_MDMA_D1_IRQ_STATUS()  bfin_read_MDMA0_D1_IRQ_STATUS()
+#define bfin_write_MDMA_D1_IRQ_STATUS(val) bfin_write_MDMA0_D1_IRQ_STATUS(val)
+#define bfin_read_MDMA_D1_X_MODIFY()  bfin_read_MDMA0_D1_X_MODIFY()
+#define bfin_write_MDMA_D1_X_MODIFY(val) bfin_write_MDMA0_D1_X_MODIFY(val)
+#define bfin_read_MDMA_D1_Y_MODIFY()  bfin_read_MDMA0_D1_Y_MODIFY()
+#define bfin_write_MDMA_D1_Y_MODIFY(val) bfin_write_MDMA0_D1_Y_MODIFY(val)
+#define bfin_read_MDMA_D1_X_COUNT()  bfin_read_MDMA0_D1_X_COUNT()
+#define bfin_write_MDMA_D1_X_COUNT(val) bfin_write_MDMA0_D1_X_COUNT(val)
+#define bfin_read_MDMA_D1_Y_COUNT()  bfin_read_MDMA0_D1_Y_COUNT()
+#define bfin_write_MDMA_D1_Y_COUNT(val) bfin_write_MDMA0_D1_Y_COUNT(val)
+#define bfin_read_MDMA_D1_START_ADDR()  bfin_read_MDMA0_D1_START_ADDR()
+#define bfin_write_MDMA_D1_START_ADDR(val) bfin_write_MDMA0_D1_START_ADDR(val)
+
 #define bfin_read_PPI_CONTROL()        bfin_read16(PPI_CONTROL)
 #define bfin_write_PPI_CONTROL(val)    bfin_write16(PPI_CONTROL, val)
 #define bfin_read_PPI_STATUS()         bfin_read16(PPI_STATUS)
index 6adbfcc65a3527ebde33be0e3092102c324112f6..bdc330cd0e1c3e41354433f2a556627058e0bceb 100644 (file)
 #define        MDMA0_S1_CURR_X_COUNT   0xFFC00EF0      /* MemDMA0 Stream 1 Source Current X Count Register */
 #define        MDMA0_S1_CURR_Y_COUNT   0xFFC00EF8      /* MemDMA0 Stream 1 Source Current Y Count Register */
 
+#define MDMA_D0_NEXT_DESC_PTR MDMA0_D0_NEXT_DESC_PTR
+#define MDMA_D0_START_ADDR MDMA0_D0_START_ADDR
+#define MDMA_D0_CONFIG MDMA0_D0_CONFIG
+#define MDMA_D0_X_COUNT MDMA0_D0_X_COUNT
+#define MDMA_D0_X_MODIFY MDMA0_D0_X_MODIFY
+#define MDMA_D0_Y_COUNT MDMA0_D0_Y_COUNT
+#define MDMA_D0_Y_MODIFY MDMA0_D0_Y_MODIFY
+#define MDMA_D0_CURR_DESC_PTR MDMA0_D0_CURR_DESC_PTR
+#define MDMA_D0_CURR_ADDR MDMA0_D0_CURR_ADDR
+#define MDMA_D0_IRQ_STATUS MDMA0_D0_IRQ_STATUS
+#define MDMA_D0_PERIPHERAL_MAP MDMA0_D0_PERIPHERAL_MAP
+#define MDMA_D0_CURR_X_COUNT MDMA0_D0_CURR_X_COUNT
+#define MDMA_D0_CURR_Y_COUNT MDMA0_D0_CURR_Y_COUNT
+
+#define MDMA_S0_NEXT_DESC_PTR MDMA0_S0_NEXT_DESC_PTR
+#define MDMA_S0_START_ADDR MDMA0_S0_START_ADDR
+#define MDMA_S0_CONFIG MDMA0_S0_CONFIG
+#define MDMA_S0_X_COUNT MDMA0_S0_X_COUNT
+#define MDMA_S0_X_MODIFY MDMA0_S0_X_MODIFY
+#define MDMA_S0_Y_COUNT MDMA0_S0_Y_COUNT
+#define MDMA_S0_Y_MODIFY MDMA0_S0_Y_MODIFY
+#define MDMA_S0_CURR_DESC_PTR MDMA0_S0_CURR_DESC_PTR
+#define MDMA_S0_CURR_ADDR MDMA0_S0_CURR_ADDR
+#define MDMA_S0_IRQ_STATUS MDMA0_S0_IRQ_STATUS
+#define MDMA_S0_PERIPHERAL_MAP MDMA0_S0_PERIPHERAL_MAP
+#define MDMA_S0_CURR_X_COUNT MDMA0_S0_CURR_X_COUNT
+#define MDMA_S0_CURR_Y_COUNT MDMA0_S0_CURR_Y_COUNT
+
+#define MDMA_D1_NEXT_DESC_PTR MDMA0_D1_NEXT_DESC_PTR
+#define MDMA_D1_START_ADDR MDMA0_D1_START_ADDR
+#define MDMA_D1_CONFIG MDMA0_D1_CONFIG
+#define MDMA_D1_X_COUNT MDMA0_D1_X_COUNT
+#define MDMA_D1_X_MODIFY MDMA0_D1_X_MODIFY
+#define MDMA_D1_Y_COUNT MDMA0_D1_Y_COUNT
+#define MDMA_D1_Y_MODIFY MDMA0_D1_Y_MODIFY
+#define MDMA_D1_CURR_DESC_PTR MDMA0_D1_CURR_DESC_PTR
+#define MDMA_D1_CURR_ADDR MDMA0_D1_CURR_ADDR
+#define MDMA_D1_IRQ_STATUS MDMA0_D1_IRQ_STATUS
+#define MDMA_D1_PERIPHERAL_MAP MDMA0_D1_PERIPHERAL_MAP
+#define MDMA_D1_CURR_X_COUNT MDMA0_D1_CURR_X_COUNT
+#define MDMA_D1_CURR_Y_COUNT MDMA0_D1_CURR_Y_COUNT
+
+#define MDMA_S1_NEXT_DESC_PTR MDMA0_S1_NEXT_DESC_PTR
+#define MDMA_S1_START_ADDR MDMA0_S1_START_ADDR
+#define MDMA_S1_CONFIG MDMA0_S1_CONFIG
+#define MDMA_S1_X_COUNT MDMA0_S1_X_COUNT
+#define MDMA_S1_X_MODIFY MDMA0_S1_X_MODIFY
+#define MDMA_S1_Y_COUNT MDMA0_S1_Y_COUNT
+#define MDMA_S1_Y_MODIFY MDMA0_S1_Y_MODIFY
+#define MDMA_S1_CURR_DESC_PTR MDMA0_S1_CURR_DESC_PTR
+#define MDMA_S1_CURR_ADDR MDMA0_S1_CURR_ADDR
+#define MDMA_S1_IRQ_STATUS MDMA0_S1_IRQ_STATUS
+#define MDMA_S1_PERIPHERAL_MAP MDMA0_S1_PERIPHERAL_MAP
+#define MDMA_S1_CURR_X_COUNT MDMA0_S1_CURR_X_COUNT
+#define MDMA_S1_CURR_Y_COUNT MDMA0_S1_CURR_Y_COUNT
+
 
 /* Parallel Peripheral Interface (PPI) (0xFFC01000 - 0xFFC010FF) */
 #define        PPI_CONTROL                     0xFFC01000      /* PPI Control Register */
index dcf657159051cfd8a1fb34714ea3586ba6bff5c4..a09623dfd5504b063199c72b9f76d4df43ffaee7 100644 (file)
@@ -11,6 +11,13 @@ config DEB_DMA_URGENT
        help
          Treat any DEB1, DEB2 and DEB3 request as Urgent
 
+config BF548_ATAPI_ALTERNATIVE_PORT
+       bool "BF548 ATAPI alternative port via GPIO"
+       help
+         BF548 ATAPI data and address PINs can be routed through
+         async address or GPIO port F and G. Select y to route it
+         to GPIO.
+
 comment "Interrupt Priority Assignment"
 menu "Priority"
 
@@ -250,6 +257,7 @@ config IRQ_OTPSEC
        default 11
 config IRQ_TIMER0
        int "IRQ_TIMER0"
+       default 7 if TICKSOURCE_GPTMR0
        default 8
 config IRQ_TIMER1
        int "IRQ_TIMER1"
index 096e661700a7d666ab4534edbdb847a83975100f..add5a17452cec8010bf3386de428a6d47ce3af1e 100644 (file)
@@ -208,6 +208,43 @@ static struct platform_device bfin_rotary_device = {
 };
 #endif
 
+#if defined(CONFIG_INPUT_ADXL34X) || defined(CONFIG_INPUT_ADXL34X_MODULE)
+#include <linux/input.h>
+#include <linux/spi/adxl34x.h>
+static const struct adxl34x_platform_data adxl34x_info = {
+       .x_axis_offset = 0,
+       .y_axis_offset = 0,
+       .z_axis_offset = 0,
+       .tap_threshold = 0x31,
+       .tap_duration = 0x10,
+       .tap_latency = 0x60,
+       .tap_window = 0xF0,
+       .tap_axis_control = ADXL_TAP_X_EN | ADXL_TAP_Y_EN | ADXL_TAP_Z_EN,
+       .act_axis_control = 0xFF,
+       .activity_threshold = 5,
+       .inactivity_threshold = 3,
+       .inactivity_time = 4,
+       .free_fall_threshold = 0x7,
+       .free_fall_time = 0x20,
+       .data_rate = 0x8,
+       .data_range = ADXL_FULL_RES,
+
+       .ev_type = EV_ABS,
+       .ev_code_x = ABS_X,             /* EV_REL */
+       .ev_code_y = ABS_Y,             /* EV_REL */
+       .ev_code_z = ABS_Z,             /* EV_REL */
+
+       .ev_code_tap_x = BTN_TOUCH,             /* EV_KEY */
+       .ev_code_tap_y = BTN_TOUCH,             /* EV_KEY */
+       .ev_code_tap_z = BTN_TOUCH,             /* EV_KEY */
+
+/*     .ev_code_ff = KEY_F,*/          /* EV_KEY */
+/*     .ev_code_act_inactivity = KEY_A,*/      /* EV_KEY */
+       .power_mode = ADXL_AUTO_SLEEP | ADXL_LINK,
+       .fifo_mode = ADXL_FIFO_STREAM,
+};
+#endif
+
 #if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
 static struct platform_device rtc_device = {
        .name = "rtc-bfin",
@@ -628,6 +665,14 @@ static struct bfin5xx_spi_chip spidev_chip_info = {
 };
 #endif
 
+#if defined(CONFIG_INPUT_ADXL34X_SPI) || defined(CONFIG_INPUT_ADXL34X_SPI_MODULE)
+static struct bfin5xx_spi_chip spi_adxl34x_chip_info = {
+       .enable_dma = 0,         /* use dma transfer with this chip*/
+       .bits_per_word = 8,
+       .cs_change_per_word = 0,
+};
+#endif
+
 static struct spi_board_info bfin_spi_board_info[] __initdata = {
 #if defined(CONFIG_MTD_M25P80) \
        || defined(CONFIG_MTD_M25P80_MODULE)
@@ -653,15 +698,15 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 #if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
-{
-       .modalias               = "ad7877",
-       .platform_data          = &bfin_ad7877_ts_info,
-       .irq                    = IRQ_PB4,      /* old boards (<=Rev 1.3) use IRQ_PJ11 */
-       .max_speed_hz           = 12500000,     /* max spi clock (SCK) speed in HZ */
-       .bus_num                = 0,
-       .chip_select            = 2,
-       .controller_data = &spi_ad7877_chip_info,
-},
+       {
+               .modalias               = "ad7877",
+               .platform_data          = &bfin_ad7877_ts_info,
+               .irq                    = IRQ_PB4,      /* old boards (<=Rev 1.3) use IRQ_PJ11 */
+               .max_speed_hz           = 12500000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num                = 0,
+               .chip_select            = 2,
+               .controller_data = &spi_ad7877_chip_info,
+       },
 #endif
 #if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
        {
@@ -672,8 +717,19 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
                .controller_data = &spidev_chip_info,
        },
 #endif
+#if defined(CONFIG_INPUT_ADXL34X_SPI) || defined(CONFIG_INPUT_ADXL34X_SPI_MODULE)
+       {
+               .modalias               = "adxl34x",
+               .platform_data          = &adxl34x_info,
+               .irq                    = IRQ_PC5,
+               .max_speed_hz           = 5000000,     /* max spi clock (SCK) speed in HZ */
+               .bus_num                = 1,
+               .chip_select            = 2,
+               .controller_data = &spi_adxl34x_chip_info,
+               .mode = SPI_MODE_3,
+       },
+#endif
 };
-
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
 /* SPI (0) */
 static struct resource bfin_spi0_resource[] = {
@@ -786,7 +842,7 @@ static struct i2c_board_info __initdata bfin_i2c_board_info0[] = {
 
 #if !defined(CONFIG_BF542)     /* The BF542 only has 1 TWI */
 static struct i2c_board_info __initdata bfin_i2c_board_info1[] = {
-#if defined(CONFIG_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
        {
                I2C_BOARD_INFO("pcf8574_lcd", 0x22),
        },
@@ -797,6 +853,13 @@ static struct i2c_board_info __initdata bfin_i2c_board_info1[] = {
                .irq = 212,
        },
 #endif
+#if defined(CONFIG_INPUT_ADXL34X_I2C) || defined(CONFIG_INPUT_ADXL34X_I2C_MODULE)
+       {
+               I2C_BOARD_INFO("adxl34x", 0x53),
+               .irq = IRQ_PC5,
+               .platform_data = (void *)&adxl34x_info,
+       },
+#endif
 };
 #endif
 
index 882e40ccf0d16f752563bdffffc46f98f2ed6f99..c510ae688e283a59439e199d6fd3acff7826fc51 100644 (file)
@@ -6,26 +6,31 @@
  * Licensed under the GPL-2 or later.
  */
 
-/* This file shoule be up to date with:
+/* This file should be up to date with:
  *  - Revision H, 01/16/2009; ADSP-BF542/BF544/BF547/BF548/BF549 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
 #define _MACH_ANOMALY_H_
 
-/* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot2 Not Supported */
+/* We do not support 0.0 or 0.1 silicon - sorry */
+#if __SILICON_REVISION__ < 2
+# error will not work on BF548 silicon version 0.0, or 0.1
+#endif
+
+/* Multi-issue instruction with dsp32shiftimm in slot1 and P-reg store in slot 2 not supported */
 #define ANOMALY_05000074 (1)
 /* DMA_RUN Bit Is Not Valid after a Peripheral Receive Channel DMA Stops */
 #define ANOMALY_05000119 (1)
 /* Rx.H Cannot Be Used to Access 16-bit System MMR Registers */
 #define ANOMALY_05000122 (1)
-/* Spurious Hardware Error from an Access in the Shadow of a Conditional Branch */
+/* False Hardware Error from an Access in the Shadow of a Conditional Branch */
 #define ANOMALY_05000245 (1)
 /* Sensitivity To Noise with Slow Input Edge Rates on External SPORT TX and RX Clocks */
 #define ANOMALY_05000265 (1)
 /* Certain Data Cache Writethrough Modes Fail for Vddint <= 0.9V */
 #define ANOMALY_05000272 (1)
-/* False Hardware Error Exception when ISR context is not restored */
+/* False Hardware Error Exception When ISR Context Is Not Restored */
 #define ANOMALY_05000281 (__SILICON_REVISION__ < 1)
 /* SSYNCs After Writes To CAN/DMA MMR Registers Are Not Always Handled Correctly */
 #define ANOMALY_05000304 (__SILICON_REVISION__ < 1)
@@ -59,7 +64,7 @@
 #define ANOMALY_05000340 (__SILICON_REVISION__ < 1)
 /* Boot Host Wait (HWAIT) and Boot Host Wait Alternate (HWAITA) Signals Are Swapped */
 #define ANOMALY_05000344 (__SILICON_REVISION__ < 1)
-/* USB Calibration Value Is Not Intialized */
+/* USB Calibration Value Is Not Initialized */
 #define ANOMALY_05000346 (__SILICON_REVISION__ < 1)
 /* USB Calibration Value to use */
 #define ANOMALY_05000346_value 0x5411
 #define ANOMALY_05000416 (1)
 /* Multichannel SPORT Channel Misalignment Under Specific Configuration */
 #define ANOMALY_05000425 (1)
-/* Speculative Fetches of Indirect-Pointer Instructions Can Cause Spurious Hardware Errors */
+/* Speculative Fetches of Indirect-Pointer Instructions Can Cause False Hardware Errors */
 #define ANOMALY_05000426 (1)
 /* CORE_EPPI_PRIO bit and SYS_EPPI_PRIO bit in the HMDMA1_CONTROL register are not functional */
 #define ANOMALY_05000427 (__SILICON_REVISION__ < 2)
-/* WB_EDGE Bit in NFC_IRQSTAT Incorrectly Behaves as a Buffer Status Bit Instead of an IRQ Status Bit */
+/* WB_EDGE Bit in NFC_IRQSTAT Incorrectly Reflects Buffer Status Instead of IRQ Status */
 #define ANOMALY_05000429 (__SILICON_REVISION__ < 2)
 /* Software System Reset Corrupts PLL_LOCKCNT Register */
 #define ANOMALY_05000430 (__SILICON_REVISION__ >= 2)
 /* Reduced Timing Margins on DDR Output Setup and Hold (tDS and tDH) */
 #define ANOMALY_05000449 (__SILICON_REVISION__ == 1)
 /* USB DMA Mode 1 Short Packet Data Corruption */
-#define ANOMALY_05000450 (1
+#define ANOMALY_05000450 (1)
+/* USB Receive Interrupt Is Not Generated in DMA Mode 1 */
+#define ANOMALY_05000456 (__SILICON_REVISION__ < 3)
+/* False Hardware Error when RETI points to invalid memory */
+#define ANOMALY_05000461 (1)
 
 /* Anomalies that don't exist on this proc */
+#define ANOMALY_05000099 (0)
+#define ANOMALY_05000120 (0)
 #define ANOMALY_05000125 (0)
+#define ANOMALY_05000149 (0)
 #define ANOMALY_05000158 (0)
+#define ANOMALY_05000171 (0)
+#define ANOMALY_05000179 (0)
 #define ANOMALY_05000183 (0)
 #define ANOMALY_05000198 (0)
+#define ANOMALY_05000215 (0)
+#define ANOMALY_05000220 (0)
+#define ANOMALY_05000227 (0)
 #define ANOMALY_05000230 (0)
+#define ANOMALY_05000231 (0)
+#define ANOMALY_05000233 (0)
+#define ANOMALY_05000242 (0)
 #define ANOMALY_05000244 (0)
+#define ANOMALY_05000248 (0)
+#define ANOMALY_05000250 (0)
+#define ANOMALY_05000254 (0)
 #define ANOMALY_05000261 (0)
 #define ANOMALY_05000263 (0)
 #define ANOMALY_05000266 (0)
 #define ANOMALY_05000273 (0)
+#define ANOMALY_05000274 (0)
 #define ANOMALY_05000278 (0)
+#define ANOMALY_05000287 (0)
+#define ANOMALY_05000301 (0)
 #define ANOMALY_05000305 (0)
 #define ANOMALY_05000307 (0)
 #define ANOMALY_05000311 (0)
 #define ANOMALY_05000323 (0)
+#define ANOMALY_05000362 (1)
 #define ANOMALY_05000363 (0)
 #define ANOMALY_05000380 (0)
+#define ANOMALY_05000400 (0)
 #define ANOMALY_05000412 (0)
 #define ANOMALY_05000432 (0)
 #define ANOMALY_05000435 (0)
index ffb1d0a44b4d798e9f83df9a2e5e9b4c02b5d155..ce372ba0f04644ff4c8e7b79060973265608e8be 100644 (file)
 #define P_PPI0_D13     (P_DEFINED | P_IDENT(GPIO_PF13) | P_FUNCT(0))
 #define P_PPI0_D14     (P_DEFINED | P_IDENT(GPIO_PF14) | P_FUNCT(0))
 #define P_PPI0_D15     (P_DEFINED | P_IDENT(GPIO_PF15) | P_FUNCT(0))
-#define P_ATAPI_D0A    (P_DEFINED | P_IDENT(GPIO_PF0) | P_FUNCT(1))
-#define P_ATAPI_D1A    (P_DEFINED | P_IDENT(GPIO_PF1) | P_FUNCT(1))
-#define P_ATAPI_D2A    (P_DEFINED | P_IDENT(GPIO_PF2) | P_FUNCT(1))
-#define P_ATAPI_D3A    (P_DEFINED | P_IDENT(GPIO_PF3) | P_FUNCT(1))
-#define P_ATAPI_D4A    (P_DEFINED | P_IDENT(GPIO_PF4) | P_FUNCT(1))
-#define P_ATAPI_D5A    (P_DEFINED | P_IDENT(GPIO_PF5) | P_FUNCT(1))
-#define P_ATAPI_D6A    (P_DEFINED | P_IDENT(GPIO_PF6) | P_FUNCT(1))
-#define P_ATAPI_D7A    (P_DEFINED | P_IDENT(GPIO_PF7) | P_FUNCT(1))
-#define P_ATAPI_D8A    (P_DEFINED | P_IDENT(GPIO_PF8) | P_FUNCT(1))
-#define P_ATAPI_D9A    (P_DEFINED | P_IDENT(GPIO_PF9) | P_FUNCT(1))
-#define P_ATAPI_D10A   (P_DEFINED | P_IDENT(GPIO_PF10) | P_FUNCT(1))
-#define P_ATAPI_D11A   (P_DEFINED | P_IDENT(GPIO_PF11) | P_FUNCT(1))
-#define P_ATAPI_D12A   (P_DEFINED | P_IDENT(GPIO_PF12) | P_FUNCT(1))
-#define P_ATAPI_D13A   (P_DEFINED | P_IDENT(GPIO_PF13) | P_FUNCT(1))
-#define P_ATAPI_D14A   (P_DEFINED | P_IDENT(GPIO_PF14) | P_FUNCT(1))
-#define P_ATAPI_D15A   (P_DEFINED | P_IDENT(GPIO_PF15) | P_FUNCT(1))
+
+#ifdef CONFIG_BF548_ATAPI_ALTERNATIVE_PORT
+# define P_ATAPI_D0A   (P_DEFINED | P_IDENT(GPIO_PF0) | P_FUNCT(1))
+# define P_ATAPI_D1A   (P_DEFINED | P_IDENT(GPIO_PF1) | P_FUNCT(1))
+# define P_ATAPI_D2A   (P_DEFINED | P_IDENT(GPIO_PF2) | P_FUNCT(1))
+# define P_ATAPI_D3A   (P_DEFINED | P_IDENT(GPIO_PF3) | P_FUNCT(1))
+# define P_ATAPI_D4A   (P_DEFINED | P_IDENT(GPIO_PF4) | P_FUNCT(1))
+# define P_ATAPI_D5A   (P_DEFINED | P_IDENT(GPIO_PF5) | P_FUNCT(1))
+# define P_ATAPI_D6A   (P_DEFINED | P_IDENT(GPIO_PF6) | P_FUNCT(1))
+# define P_ATAPI_D7A   (P_DEFINED | P_IDENT(GPIO_PF7) | P_FUNCT(1))
+# define P_ATAPI_D8A   (P_DEFINED | P_IDENT(GPIO_PF8) | P_FUNCT(1))
+# define P_ATAPI_D9A   (P_DEFINED | P_IDENT(GPIO_PF9) | P_FUNCT(1))
+# define P_ATAPI_D10A  (P_DEFINED | P_IDENT(GPIO_PF10) | P_FUNCT(1))
+# define P_ATAPI_D11A  (P_DEFINED | P_IDENT(GPIO_PF11) | P_FUNCT(1))
+# define P_ATAPI_D12A  (P_DEFINED | P_IDENT(GPIO_PF12) | P_FUNCT(1))
+# define P_ATAPI_D13A  (P_DEFINED | P_IDENT(GPIO_PF13) | P_FUNCT(1))
+# define P_ATAPI_D14A  (P_DEFINED | P_IDENT(GPIO_PF14) | P_FUNCT(1))
+# define P_ATAPI_D15A  (P_DEFINED | P_IDENT(GPIO_PF15) | P_FUNCT(1))
+#else
+# define P_ATAPI_D0A   (P_DONTCARE)
+# define P_ATAPI_D1A   (P_DONTCARE)
+# define P_ATAPI_D2A   (P_DONTCARE)
+# define P_ATAPI_D3A   (P_DONTCARE)
+# define P_ATAPI_D4A   (P_DONTCARE)
+# define P_ATAPI_D5A   (P_DONTCARE)
+# define P_ATAPI_D6A   (P_DONTCARE)
+# define P_ATAPI_D7A   (P_DONTCARE)
+# define P_ATAPI_D8A   (P_DONTCARE)
+# define P_ATAPI_D9A   (P_DONTCARE)
+# define P_ATAPI_D10A  (P_DONTCARE)
+# define P_ATAPI_D11A  (P_DONTCARE)
+# define P_ATAPI_D12A  (P_DONTCARE)
+# define P_ATAPI_D13A  (P_DONTCARE)
+# define P_ATAPI_D14A  (P_DONTCARE)
+# define P_ATAPI_D15A  (P_DONTCARE)
+#endif
 
 #define P_PPI0_CLK     (P_DEFINED | P_IDENT(GPIO_PG0) | P_FUNCT(0))
 #define P_PPI0_FS1     (P_DEFINED | P_IDENT(GPIO_PG1) | P_FUNCT(0))
 #define P_CAN0_RX      (P_DEFINED | P_IDENT(GPIO_PG13) | P_FUNCT(0))
 #define P_CAN1_TX      (P_DEFINED | P_IDENT(GPIO_PG14) | P_FUNCT(0))
 #define P_CAN1_RX      (P_DEFINED | P_IDENT(GPIO_PG15) | P_FUNCT(0))
-#define P_ATAPI_A0A    (P_DEFINED | P_IDENT(GPIO_PG2) | P_FUNCT(1))
-#define P_ATAPI_A1A    (P_DEFINED | P_IDENT(GPIO_PG3) | P_FUNCT(1))
-#define P_ATAPI_A2A    (P_DEFINED | P_IDENT(GPIO_PG4) | P_FUNCT(1))
+#ifdef CONFIG_BF548_ATAPI_ALTERNATIVE_PORT
+# define P_ATAPI_A0A   (P_DEFINED | P_IDENT(GPIO_PG2) | P_FUNCT(1))
+# define P_ATAPI_A1A   (P_DEFINED | P_IDENT(GPIO_PG3) | P_FUNCT(1))
+# define P_ATAPI_A2A   (P_DEFINED | P_IDENT(GPIO_PG4) | P_FUNCT(1))
+#else
+# define P_ATAPI_A0A   (P_DONTCARE)
+# define P_ATAPI_A1A   (P_DONTCARE)
+# define P_ATAPI_A2A   (P_DONTCARE)
+#endif
 #define P_HOST_CE      (P_DEFINED | P_IDENT(GPIO_PG5) | P_FUNCT(1))
 #define P_HOST_RD      (P_DEFINED | P_IDENT(GPIO_PG6) | P_FUNCT(1))
 #define P_HOST_WR      (P_DEFINED | P_IDENT(GPIO_PG7) | P_FUNCT(1))
index 638ec38ca47066ccc8fcfc15a294a00598934c2e..cb97436415113f65725852e125af02d0197bc992 100644 (file)
@@ -9,22 +9,9 @@ if (!SMP)
 comment "Core B Support"
 
 config BF561_COREB
-       bool "Enable Core B support"
+       bool "Enable Core B loader"
        default y
 
-config BF561_COREB_RESET
-       bool "Enable Core B reset support"
-       default n
-       help
-         This requires code in the application that is loaded
-         into Core B. In order to reset, the application needs
-         to install an interrupt handler for Supplemental
-         Interrupt 0, that sets RETI to 0xff600000 and writes
-         bit 11 of SICB_SYSCR when bit 5 of SICA_SYSCR is 0.
-         This causes Core B to stall when Supplemental Interrupt
-         0 is set, and will reset PC to 0xff600000 when
-         COREB_SRAM_INIT is cleared.
-
 endif
 
 comment "Interrupt Priority Assignment"
@@ -138,6 +125,7 @@ config IRQ_DMA2_11
        default 9
 config IRQ_TIMER0
        int "TIMER 0  Interrupt"
+       default 7 if TICKSOURCE_GPTMR0
        default 8
 config IRQ_TIMER1
        int "TIMER 1  Interrupt"
index f623c6b0719fbc2711f1942e19e4a7143f359c4a..0dd9685e5d53f967e9e76a3aea1a317f983c8911 100644 (file)
@@ -83,7 +83,7 @@ static struct bfin5xx_spi_chip spi_flash_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
 /* SPI ADC chip */
 static struct bfin5xx_spi_chip spi_adc_chip_info = {
        .enable_dma = 1,         /* use dma transfer with this chip*/
@@ -126,7 +126,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 
-#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+#if defined(CONFIG_BFIN_SPI_ADC) || defined(CONFIG_BFIN_SPI_ADC_MODULE)
        {
                .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
                .max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
index 8598098c08408e85382bb21960f219a130a71ec5..93635a766f9cded6c93e8cc011e47e35e62da0c1 100644 (file)
-/*
- * File:         arch/blackfin/mach-bf561/coreb.c
- * Based on:
- * Author:
+/* Load firmware into Core B on a BF561
  *
- * Created:
- * Description:  Handle CoreB on a BF561
- *
- * Modified:
- *               Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs:         Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ * Copyright 2004-2009 Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+/* The Core B reset func requires code in the application that is loaded into
+ * Core B.  In order to reset, the application needs to install an interrupt
+ * handler for Supplemental Interrupt 0, that sets RETI to 0xff600000 and
+ * writes bit 11 of SICB_SYSCR when bit 5 of SICA_SYSCR is 0.  This causes Core
+ * B to stall when Supplemental Interrupt 0 is set, and will reset PC to
+ * 0xff600000 when COREB_SRAM_INIT is cleared.
  */
 
-#include <linux/mm.h>
-#include <linux/miscdevice.h>
 #include <linux/device.h>
-#include <linux/ioport.h>
-#include <linux/module.h>
-#include <linux/uaccess.h>
 #include <linux/fs.h>
-#include <asm/dma.h>
-#include <asm/cacheflush.h>
-
-#define MODULE_VER             "v0.1"
-
-static spinlock_t coreb_lock;
-static wait_queue_head_t coreb_dma_wait;
-
-#define COREB_IS_OPEN          0x00000001
-#define COREB_IS_RUNNING       0x00000010
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
 
-#define CMD_COREB_INDEX                1
 #define CMD_COREB_START                2
 #define CMD_COREB_STOP         3
 #define CMD_COREB_RESET                4
 
-#define COREB_MINOR            229
-
-static unsigned long coreb_status = 0;
-static unsigned long coreb_base = 0xff600000;
-static unsigned long coreb_size = 0x4000;
-int coreb_dma_done;
-
-static loff_t coreb_lseek(struct file *file, loff_t offset, int origin);
-static ssize_t coreb_read(struct file *file, char *buf, size_t count,
-                         loff_t * ppos);
-static ssize_t coreb_write(struct file *file, const char *buf, size_t count,
-                          loff_t * ppos);
-static int coreb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-                      unsigned long arg);
-static int coreb_open(struct inode *inode, struct file *file);
-static int coreb_release(struct inode *inode, struct file *file);
-
-static irqreturn_t coreb_dma_interrupt(int irq, void *dev_id)
-{
-       clear_dma_irqstat(CH_MEM_STREAM2_DEST);
-       coreb_dma_done = 1;
-       wake_up_interruptible(&coreb_dma_wait);
-       return IRQ_HANDLED;
-}
-
-static ssize_t coreb_write(struct file *file, const char *buf, size_t count,
-                          loff_t * ppos)
-{
-       unsigned long p = *ppos;
-       ssize_t wrote = 0;
-
-       if (p + count > coreb_size)
-               return -EFAULT;
-
-       while (count > 0) {
-               int len = count;
-
-               if (len > PAGE_SIZE)
-                       len = PAGE_SIZE;
-
-               coreb_dma_done = 0;
-
-               flush_dcache_range((unsigned long)buf, (unsigned long)(buf+len));
-               /* Source Channel */
-               set_dma_start_addr(CH_MEM_STREAM2_SRC, (unsigned long)buf);
-               set_dma_x_count(CH_MEM_STREAM2_SRC, len);
-               set_dma_x_modify(CH_MEM_STREAM2_SRC, sizeof(char));
-               set_dma_config(CH_MEM_STREAM2_SRC, 0);
-               /* Destination Channel */
-               set_dma_start_addr(CH_MEM_STREAM2_DEST, coreb_base + p);
-               set_dma_x_count(CH_MEM_STREAM2_DEST, len);
-               set_dma_x_modify(CH_MEM_STREAM2_DEST, sizeof(char));
-               set_dma_config(CH_MEM_STREAM2_DEST, WNR | RESTART | DI_EN);
-
-               enable_dma(CH_MEM_STREAM2_SRC);
-               enable_dma(CH_MEM_STREAM2_DEST);
-
-               wait_event_interruptible(coreb_dma_wait, coreb_dma_done);
-
-               disable_dma(CH_MEM_STREAM2_SRC);
-               disable_dma(CH_MEM_STREAM2_DEST);
-
-               count -= len;
-               wrote += len;
-               buf += len;
-               p += len;
-       }
-       *ppos = p;
-       return wrote;
-}
-
-static ssize_t coreb_read(struct file *file, char *buf, size_t count,
-                         loff_t * ppos)
-{
-       unsigned long p = *ppos;
-       ssize_t read = 0;
-
-       if ((p + count) > coreb_size)
-               return -EFAULT;
-
-       while (count > 0) {
-               int len = count;
-
-               if (len > PAGE_SIZE)
-                       len = PAGE_SIZE;
-
-               coreb_dma_done = 0;
-
-               invalidate_dcache_range((unsigned long)buf, (unsigned long)(buf+len));
-               /* Source Channel */
-               set_dma_start_addr(CH_MEM_STREAM2_SRC, coreb_base + p);
-               set_dma_x_count(CH_MEM_STREAM2_SRC, len);
-               set_dma_x_modify(CH_MEM_STREAM2_SRC, sizeof(char));
-               set_dma_config(CH_MEM_STREAM2_SRC, 0);
-               /* Destination Channel */
-               set_dma_start_addr(CH_MEM_STREAM2_DEST, (unsigned long)buf);
-               set_dma_x_count(CH_MEM_STREAM2_DEST, len);
-               set_dma_x_modify(CH_MEM_STREAM2_DEST, sizeof(char));
-               set_dma_config(CH_MEM_STREAM2_DEST, WNR | RESTART | DI_EN);
-
-               enable_dma(CH_MEM_STREAM2_SRC);
-               enable_dma(CH_MEM_STREAM2_DEST);
-
-               wait_event_interruptible(coreb_dma_wait, coreb_dma_done);
-
-               disable_dma(CH_MEM_STREAM2_SRC);
-               disable_dma(CH_MEM_STREAM2_DEST);
-
-               count -= len;
-               read += len;
-               buf += len;
-               p += len;
-       }
-
-       return read;
-}
-
-static loff_t coreb_lseek(struct file *file, loff_t offset, int origin)
+static int
+coreb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
-       loff_t ret;
-
-       mutex_lock(&file->f_dentry->d_inode->i_mutex);
-
-       switch (origin) {
-       case 0 /* SEEK_SET */ :
-               if (offset < coreb_size) {
-                       file->f_pos = offset;
-                       ret = file->f_pos;
-               } else
-                       ret = -EINVAL;
-               break;
-       case 1 /* SEEK_CUR */ :
-               if ((offset + file->f_pos) < coreb_size) {
-                       file->f_pos += offset;
-                       ret = file->f_pos;
-               } else
-                       ret = -EINVAL;
-       default:
-               ret = -EINVAL;
-       }
-       mutex_unlock(&file->f_dentry->d_inode->i_mutex);
-       return ret;
-}
-
-/* No BKL needed here */
-static int coreb_open(struct inode *inode, struct file *file)
-{
-       spin_lock_irq(&coreb_lock);
-
-       if (coreb_status & COREB_IS_OPEN)
-               goto out_busy;
-
-       coreb_status |= COREB_IS_OPEN;
-
-       spin_unlock_irq(&coreb_lock);
-       return 0;
-
- out_busy:
-       spin_unlock_irq(&coreb_lock);
-       return -EBUSY;
-}
-
-static int coreb_release(struct inode *inode, struct file *file)
-{
-       spin_lock_irq(&coreb_lock);
-       coreb_status &= ~COREB_IS_OPEN;
-       spin_unlock_irq(&coreb_lock);
-       return 0;
-}
-
-static int coreb_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg)
-{
-       int retval = 0;
-       int coreb_index = 0;
+       int ret = 0;
 
        switch (cmd) {
-       case CMD_COREB_INDEX:
-               if (copy_from_user(&coreb_index, (int *)arg, sizeof(int))) {
-                       retval = -EFAULT;
-                       break;
-               }
-
-               spin_lock_irq(&coreb_lock);
-               switch (coreb_index) {
-               case 0:
-                       coreb_base = 0xff600000;
-                       coreb_size = 0x4000;
-                       break;
-               case 1:
-                       coreb_base = 0xff610000;
-                       coreb_size = 0x4000;
-                       break;
-               case 2:
-                       coreb_base = 0xff500000;
-                       coreb_size = 0x8000;
-                       break;
-               case 3:
-                       coreb_base = 0xff400000;
-                       coreb_size = 0x8000;
-                       break;
-               default:
-                       retval = -EINVAL;
-                       break;
-               }
-               spin_unlock_irq(&coreb_lock);
-
-               mutex_lock(&file->f_dentry->d_inode->i_mutex);
-               file->f_pos = 0;
-               mutex_unlock(&file->f_dentry->d_inode->i_mutex);
-               break;
        case CMD_COREB_START:
-               spin_lock_irq(&coreb_lock);
-               if (coreb_status & COREB_IS_RUNNING) {
-                       retval = -EBUSY;
-                       break;
-               }
-               printk(KERN_INFO "Starting Core B\n");
-               coreb_status |= COREB_IS_RUNNING;
                bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() & ~0x0020);
-               SSYNC();
-               spin_unlock_irq(&coreb_lock);
                break;
-#if defined(CONFIG_BF561_COREB_RESET)
        case CMD_COREB_STOP:
-               spin_lock_irq(&coreb_lock);
-               printk(KERN_INFO "Stopping Core B\n");
                bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() | 0x0020);
                bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | 0x0080);
-               coreb_status &= ~COREB_IS_RUNNING;
-               spin_unlock_irq(&coreb_lock);
                break;
        case CMD_COREB_RESET:
-               printk(KERN_INFO "Resetting Core B\n");
                bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | 0x0080);
                break;
-#endif
+       default:
+               ret = -EINVAL;
+               break;
        }
 
-       return retval;
+       CSYNC();
+
+       return ret;
 }
 
 static struct file_operations coreb_fops = {
-       .owner = THIS_MODULE,
-       .llseek = coreb_lseek,
-       .read = coreb_read,
-       .write = coreb_write,
-       .ioctl = coreb_ioctl,
-       .open = coreb_open,
-       .release = coreb_release
+       .owner   = THIS_MODULE,
+       .ioctl   = coreb_ioctl,
 };
 
 static struct miscdevice coreb_dev = {
-       COREB_MINOR,
-       "coreb",
-       &coreb_fops
+       .minor = MISC_DYNAMIC_MINOR,
+       .name  = "coreb",
+       .fops  = &coreb_fops,
 };
 
-static ssize_t coreb_show_status(struct device *dev, struct device_attribute *attr, char *buf)
+static int __init bf561_coreb_init(void)
 {
-       return sprintf(buf,
-                      "Base Address:\t0x%08lx\n"
-                      "Core B is %s\n"
-                      "SICA_SYSCR:\t%04x\n"
-                      "SICB_SYSCR:\t%04x\n"
-                      "\n"
-                      "IRQ Status:\tCore A\t\tCore B\n"
-                      "ISR0:\t\t%08x\t\t%08x\n"
-                      "ISR1:\t\t%08x\t\t%08x\n"
-                      "IMASK0:\t\t%08x\t\t%08x\n"
-                      "IMASK1:\t\t%08x\t\t%08x\n",
-                      coreb_base,
-                      coreb_status & COREB_IS_RUNNING ? "running" : "stalled",
-                      bfin_read_SICA_SYSCR(), bfin_read_SICB_SYSCR(),
-                      bfin_read_SICA_ISR0(), bfin_read_SICB_ISR0(),
-                      bfin_read_SICA_ISR1(), bfin_read_SICB_ISR0(),
-                      bfin_read_SICA_IMASK0(), bfin_read_SICB_IMASK0(),
-                      bfin_read_SICA_IMASK1(), bfin_read_SICB_IMASK1());
-}
-
-static DEVICE_ATTR(coreb_status, S_IRUGO, coreb_show_status, NULL);
-
-int __init bf561_coreb_init(void)
-{
-       init_waitqueue_head(&coreb_dma_wait);
-
-       spin_lock_init(&coreb_lock);
-       /* Request the core memory regions for Core B */
-       if (request_mem_region(0xff600000, 0x4000,
-                              "Core B - Instruction SRAM") == NULL)
-               goto exit;
-
-       if (request_mem_region(0xFF610000, 0x4000,
-                              "Core B - Instruction SRAM") == NULL)
-               goto release_instruction_a_sram;
-
-       if (request_mem_region(0xFF500000, 0x8000,
-                              "Core B - Data Bank B SRAM") == NULL)
-               goto release_instruction_b_sram;
-
-       if (request_mem_region(0xff400000, 0x8000,
-                              "Core B - Data Bank A SRAM") == NULL)
-               goto release_data_b_sram;
-
-       if (request_dma(CH_MEM_STREAM2_DEST, "Core B - DMA Destination") < 0)
-               goto release_data_a_sram;
-
-       if (request_dma(CH_MEM_STREAM2_SRC, "Core B - DMA Source") < 0)
-               goto release_dma_dest;
-
-       set_dma_callback(CH_MEM_STREAM2_DEST, coreb_dma_interrupt, NULL);
-
-       misc_register(&coreb_dev);
-
-       if (device_create_file(coreb_dev.this_device, &dev_attr_coreb_status))
-               goto release_dma_src;
-
-       printk(KERN_INFO "BF561 Core B driver %s initialized.\n", MODULE_VER);
-       return 0;
-
- release_dma_src:
-       free_dma(CH_MEM_STREAM2_SRC);
- release_dma_dest:
-       free_dma(CH_MEM_STREAM2_DEST);
- release_data_a_sram:
-       release_mem_region(0xff400000, 0x8000);
- release_data_b_sram:
-       release_mem_region(0xff500000, 0x8000);
- release_instruction_b_sram:
-       release_mem_region(0xff610000, 0x4000);
- release_instruction_a_sram:
-       release_mem_region(0xff600000, 0x4000);
- exit:
-       return -ENOMEM;
+       return misc_register(&coreb_dev);
 }
+module_init(bf561_coreb_init);
 
-void __exit bf561_coreb_exit(void)
+static void __exit bf561_coreb_exit(void)
 {
-       device_remove_file(coreb_dev.this_device, &dev_attr_coreb_status);
        misc_deregister(&coreb_dev);
-
-       release_mem_region(0xff610000, 0x4000);
-       release_mem_region(0xff600000, 0x4000);
-       release_mem_region(0xff500000, 0x8000);
-       release_mem_region(0xff400000, 0x8000);
-
-       free_dma(CH_MEM_STREAM2_DEST);
-       free_dma(CH_MEM_STREAM2_SRC);
 }
-
-module_init(bf561_coreb_init);
 module_exit(bf561_coreb_exit);
 
 MODULE_AUTHOR("Bas Vermeulen <bvermeul@blackstar.xs4all.nl>");
index d0b0b3506440fee5373c850b19cf703a94941681..dccd396cd93158e188677f8bf0eaf9961fde3958 100644 (file)
@@ -6,7 +6,7 @@
  * Licensed under the GPL-2 or later.
  */
 
-/* This file shoule be up to date with:
+/* This file should be up to date with:
  *  - Revision Q, 11/07/2008; ADSP-BF561 Blackfin Processor Anomaly List
  */
 
 # error will not work on BF561 silicon version 0.0, 0.1, 0.2, or 0.4
 #endif
 
-/* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot 2 Not Supported */
+/* Multi-issue instruction with dsp32shiftimm in slot1 and P-reg store in slot 2 not supported */
 #define ANOMALY_05000074 (1)
 /* UART Line Status Register (UART_LSR) Bits Are Not Updated at the Same Time */
 #define ANOMALY_05000099 (__SILICON_REVISION__ < 5)
-/* Trace Buffers may contain errors in emulation mode and/or exception, NMI, reset handlers */
+/* Trace Buffers may record discontinuities into emulation mode and/or exception, NMI, reset handlers */
 #define ANOMALY_05000116 (__SILICON_REVISION__ < 3)
 /* Testset instructions restricted to 32-bit aligned memory locations */
 #define ANOMALY_05000120 (1)
@@ -40,7 +40,7 @@
 #define ANOMALY_05000136 (__SILICON_REVISION__ < 3)
 /* Allowing the SPORT RX FIFO to fill will cause an overflow */
 #define ANOMALY_05000140 (__SILICON_REVISION__ < 3)
-/* Infinite Stall may occur with a particular sequence of consecutive dual dag events */
+/* An Infinite Stall occurs with a particular sequence of consecutive dual dag events */
 #define ANOMALY_05000141 (__SILICON_REVISION__ < 3)
 /* Interrupts may be lost when a programmable input flag is configured to be edge sensitive */
 #define ANOMALY_05000142 (__SILICON_REVISION__ < 3)
@@ -80,7 +80,7 @@
 #define ANOMALY_05000163 (__SILICON_REVISION__ < 3)
 /* PPI Data Lengths Between 8 and 16 Do Not Zero Out Upper Bits */
 #define ANOMALY_05000166 (1)
-/* Turning Serial Ports on with External Frame Syncs */
+/* Turning SPORTs on while External Frame Sync Is Active May Corrupt Data */
 #define ANOMALY_05000167 (1)
 /* SDRAM auto-refresh and subsequent Power Ups */
 #define ANOMALY_05000168 (__SILICON_REVISION__ < 5)
 #define ANOMALY_05000242 (__SILICON_REVISION__ < 5)
 /* If I-Cache Is On, CSYNC/SSYNC/IDLE Around Change of Control Causes Failures */
 #define ANOMALY_05000244 (__SILICON_REVISION__ < 5)
-/* Spurious Hardware Error from an Access in the Shadow of a Conditional Branch */
+/* False Hardware Error from an Access in the Shadow of a Conditional Branch */
 #define ANOMALY_05000245 (__SILICON_REVISION__ < 5)
 /* TESTSET operation forces stall on the other core */
 #define ANOMALY_05000248 (__SILICON_REVISION__ < 5)
 #define ANOMALY_05000275 (__SILICON_REVISION__ > 2)
 /* Timing Requirements Change for External Frame Sync PPI Modes with Non-Zero PPI_DELAY */
 #define ANOMALY_05000276 (__SILICON_REVISION__ < 5)
-/* Writes to an I/O data register one SCLK cycle after an edge is detected may clear interrupt */
+/* Writes to an I/O Data Register One SCLK Cycle after an Edge Is Detected May Clear Interrupt */
 #define ANOMALY_05000277 (__SILICON_REVISION__ < 3)
 /* Disabling Peripherals with DMA Running May Cause DMA System Instability */
 #define ANOMALY_05000278 (__SILICON_REVISION__ < 5)
 #define ANOMALY_05000310 (1)
 /* Errors When SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted */
 #define ANOMALY_05000312 (1)
-/* PPI Is Level-Sensitive on First Transfer */
+/* PPI Is Level-Sensitive on First Transfer In Single Frame Sync Modes */
 #define ANOMALY_05000313 (1)
 /* Killed System MMR Write Completes Erroneously On Next System MMR Access */
 #define ANOMALY_05000315 (1)
 #define ANOMALY_05000428 (__SILICON_REVISION__ > 3)
 /* IFLUSH Instruction at End of Hardware Loop Causes Infinite Stall */
 #define ANOMALY_05000443 (1)
+/* False Hardware Error when RETI points to invalid memory */
+#define ANOMALY_05000461 (1)
 
 /* Anomalies that don't exist on this proc */
+#define ANOMALY_05000119 (0)
 #define ANOMALY_05000158 (0)
 #define ANOMALY_05000183 (0)
+#define ANOMALY_05000233 (0)
 #define ANOMALY_05000273 (0)
 #define ANOMALY_05000311 (0)
 #define ANOMALY_05000353 (1)
 #define ANOMALY_05000380 (0)
 #define ANOMALY_05000386 (1)
+#define ANOMALY_05000389 (0)
+#define ANOMALY_05000400 (0)
+#define ANOMALY_05000430 (0)
 #define ANOMALY_05000432 (0)
 #define ANOMALY_05000435 (0)
 #define ANOMALY_05000447 (0)
 #define ANOMALY_05000448 (0)
+#define ANOMALY_05000456 (0)
+#define ANOMALY_05000450 (0)
 
 #endif
index 95d609f11c97d207b43bf05eb5e5a0caac890253..9d9858c2be68bacadf7a5f78ca228c9175639a6d 100644 (file)
 #define bfin_read_MDMA_D0_START_ADDR()  bfin_read_MDMA1_D0_START_ADDR()
 #define bfin_write_MDMA_D0_START_ADDR(val) bfin_write_MDMA1_D0_START_ADDR(val)
 
+#define bfin_read_MDMA_S1_CONFIG()  bfin_read_MDMA1_S1_CONFIG()
+#define bfin_write_MDMA_S1_CONFIG(val) bfin_write_MDMA1_S1_CONFIG(val)
+#define bfin_read_MDMA_S1_IRQ_STATUS()  bfin_read_MDMA1_S1_IRQ_STATUS()
+#define bfin_write_MDMA_S1_IRQ_STATUS(val) bfin_write_MDMA1_S1_IRQ_STATUS(val)
+#define bfin_read_MDMA_S1_X_MODIFY()  bfin_read_MDMA1_S1_X_MODIFY()
+#define bfin_write_MDMA_S1_X_MODIFY(val) bfin_write_MDMA1_S1_X_MODIFY(val)
+#define bfin_read_MDMA_S1_Y_MODIFY()  bfin_read_MDMA1_S1_Y_MODIFY()
+#define bfin_write_MDMA_S1_Y_MODIFY(val) bfin_write_MDMA1_S1_Y_MODIFY(val)
+#define bfin_read_MDMA_S1_X_COUNT()  bfin_read_MDMA1_S1_X_COUNT()
+#define bfin_write_MDMA_S1_X_COUNT(val) bfin_write_MDMA1_S1_X_COUNT(val)
+#define bfin_read_MDMA_S1_Y_COUNT()  bfin_read_MDMA1_S1_Y_COUNT()
+#define bfin_write_MDMA_S1_Y_COUNT(val) bfin_write_MDMA1_S1_Y_COUNT(val)
+#define bfin_read_MDMA_S1_START_ADDR()  bfin_read_MDMA1_S1_START_ADDR()
+#define bfin_write_MDMA_S1_START_ADDR(val) bfin_write_MDMA1_S1_START_ADDR(val)
+#define bfin_read_MDMA_D1_CONFIG()  bfin_read_MDMA1_D1_CONFIG()
+#define bfin_write_MDMA_D1_CONFIG(val) bfin_write_MDMA1_D1_CONFIG(val)
+#define bfin_read_MDMA_D1_IRQ_STATUS()  bfin_read_MDMA1_D1_IRQ_STATUS()
+#define bfin_write_MDMA_D1_IRQ_STATUS(val) bfin_write_MDMA1_D1_IRQ_STATUS(val)
+#define bfin_read_MDMA_D1_X_MODIFY()  bfin_read_MDMA1_D1_X_MODIFY()
+#define bfin_write_MDMA_D1_X_MODIFY(val) bfin_write_MDMA1_D1_X_MODIFY(val)
+#define bfin_read_MDMA_D1_Y_MODIFY()  bfin_read_MDMA1_D1_Y_MODIFY()
+#define bfin_write_MDMA_D1_Y_MODIFY(val) bfin_write_MDMA1_D1_Y_MODIFY(val)
+#define bfin_read_MDMA_D1_X_COUNT()  bfin_read_MDMA1_D1_X_COUNT()
+#define bfin_write_MDMA_D1_X_COUNT(val) bfin_write_MDMA1_D1_X_COUNT(val)
+#define bfin_read_MDMA_D1_Y_COUNT()  bfin_read_MDMA1_D1_Y_COUNT()
+#define bfin_write_MDMA_D1_Y_COUNT(val) bfin_write_MDMA1_D1_Y_COUNT(val)
+#define bfin_read_MDMA_D1_START_ADDR()  bfin_read_MDMA1_D1_START_ADDR()
+#define bfin_write_MDMA_D1_START_ADDR(val) bfin_write_MDMA1_D1_START_ADDR(val)
+
 /* These need to be last due to the cdef/linux inter-dependencies */
 #include <asm/irq.h>
 
index cf922295f4ce61902a1e959c8ae74f5522592121..5fc0f05026e093a7f4cb74fee1b41f6fb206e2c0 100644 (file)
 #define MDMA2_S1_IRQ_STATUS 0xFFC00FE8 /*MemDMA2 Stream 1 Source Interrupt/Status Register */
 #define MDMA2_S1_PERIPHERAL_MAP 0xFFC00FEC     /*MemDMA2 Stream 1 Source Peripheral Map register */
 
+#define MDMA_D0_NEXT_DESC_PTR MDMA1_D0_NEXT_DESC_PTR
+#define MDMA_D0_START_ADDR MDMA1_D0_START_ADDR
+#define MDMA_D0_CONFIG MDMA1_D0_CONFIG
+#define MDMA_D0_X_COUNT MDMA1_D0_X_COUNT
+#define MDMA_D0_X_MODIFY MDMA1_D0_X_MODIFY
+#define MDMA_D0_Y_COUNT MDMA1_D0_Y_COUNT
+#define MDMA_D0_Y_MODIFY MDMA1_D0_Y_MODIFY
+#define MDMA_D0_CURR_DESC_PTR MDMA1_D0_CURR_DESC_PTR
+#define MDMA_D0_CURR_ADDR MDMA1_D0_CURR_ADDR
+#define MDMA_D0_IRQ_STATUS MDMA1_D0_IRQ_STATUS
+#define MDMA_D0_PERIPHERAL_MAP MDMA1_D0_PERIPHERAL_MAP
+#define MDMA_D0_CURR_X_COUNT MDMA1_D0_CURR_X_COUNT
+#define MDMA_D0_CURR_Y_COUNT MDMA1_D0_CURR_Y_COUNT
+
+#define MDMA_S0_NEXT_DESC_PTR MDMA1_S0_NEXT_DESC_PTR
+#define MDMA_S0_START_ADDR MDMA1_S0_START_ADDR
+#define MDMA_S0_CONFIG MDMA1_S0_CONFIG
+#define MDMA_S0_X_COUNT MDMA1_S0_X_COUNT
+#define MDMA_S0_X_MODIFY MDMA1_S0_X_MODIFY
+#define MDMA_S0_Y_COUNT MDMA1_S0_Y_COUNT
+#define MDMA_S0_Y_MODIFY MDMA1_S0_Y_MODIFY
+#define MDMA_S0_CURR_DESC_PTR MDMA1_S0_CURR_DESC_PTR
+#define MDMA_S0_CURR_ADDR MDMA1_S0_CURR_ADDR
+#define MDMA_S0_IRQ_STATUS MDMA1_S0_IRQ_STATUS
+#define MDMA_S0_PERIPHERAL_MAP MDMA1_S0_PERIPHERAL_MAP
+#define MDMA_S0_CURR_X_COUNT MDMA1_S0_CURR_X_COUNT
+#define MDMA_S0_CURR_Y_COUNT MDMA1_S0_CURR_Y_COUNT
+
+#define MDMA_D1_NEXT_DESC_PTR MDMA1_D1_NEXT_DESC_PTR
+#define MDMA_D1_START_ADDR MDMA1_D1_START_ADDR
+#define MDMA_D1_CONFIG MDMA1_D1_CONFIG
+#define MDMA_D1_X_COUNT MDMA1_D1_X_COUNT
+#define MDMA_D1_X_MODIFY MDMA1_D1_X_MODIFY
+#define MDMA_D1_Y_COUNT MDMA1_D1_Y_COUNT
+#define MDMA_D1_Y_MODIFY MDMA1_D1_Y_MODIFY
+#define MDMA_D1_CURR_DESC_PTR MDMA1_D1_CURR_DESC_PTR
+#define MDMA_D1_CURR_ADDR MDMA1_D1_CURR_ADDR
+#define MDMA_D1_IRQ_STATUS MDMA1_D1_IRQ_STATUS
+#define MDMA_D1_PERIPHERAL_MAP MDMA1_D1_PERIPHERAL_MAP
+#define MDMA_D1_CURR_X_COUNT MDMA1_D1_CURR_X_COUNT
+#define MDMA_D1_CURR_Y_COUNT MDMA1_D1_CURR_Y_COUNT
+
+#define MDMA_S1_NEXT_DESC_PTR MDMA1_S1_NEXT_DESC_PTR
+#define MDMA_S1_START_ADDR MDMA1_S1_START_ADDR
+#define MDMA_S1_CONFIG MDMA1_S1_CONFIG
+#define MDMA_S1_X_COUNT MDMA1_S1_X_COUNT
+#define MDMA_S1_X_MODIFY MDMA1_S1_X_MODIFY
+#define MDMA_S1_Y_COUNT MDMA1_S1_Y_COUNT
+#define MDMA_S1_Y_MODIFY MDMA1_S1_Y_MODIFY
+#define MDMA_S1_CURR_DESC_PTR MDMA1_S1_CURR_DESC_PTR
+#define MDMA_S1_CURR_ADDR MDMA1_S1_CURR_ADDR
+#define MDMA_S1_IRQ_STATUS MDMA1_S1_IRQ_STATUS
+#define MDMA_S1_PERIPHERAL_MAP MDMA1_S1_PERIPHERAL_MAP
+#define MDMA_S1_CURR_X_COUNT MDMA1_S1_CURR_X_COUNT
+#define MDMA_S1_CURR_Y_COUNT MDMA1_S1_CURR_Y_COUNT
+
 /* Internal Memory DMA Registers (0xFFC0_1800 - 0xFFC0_19FF) */
 #define IMDMA_D0_CONFIG 0xFFC01808     /*IMDMA Stream 0 Destination Configuration */
 #define IMDMA_D0_NEXT_DESC_PTR 0xFFC01800      /*IMDMA Stream 0 Destination Next Descriptor Ptr Reg */
index 9b27e698c0b2e717bd97ff8033bb630112097750..8c10701c251f4f4ffd4962a2172b323146904465 100644 (file)
@@ -133,9 +133,9 @@ void __init platform_request_ipi(irq_handler_t handler)
        int ret;
 
        ret = request_irq(IRQ_SUPPLE_0, handler, IRQF_DISABLED,
-                         "SMP interrupt", handler);
+                         "Supplemental Interrupt0", handler);
        if (ret)
-               panic("Cannot request supplemental interrupt 0 for IPI service\n");
+               panic("Cannot request supplemental interrupt 0 for IPI service");
 }
 
 void platform_send_ipi(cpumask_t callmap)
index 80d39b2f9db295d2709574664528a9c71b6ac1db..da93d92071659cc6e70ea8be3f17b7587b247733 100644 (file)
 #if ANOMALY_05000448
 # error You are using a part with anomaly 05000448, this issue causes random memory read/write failures - that means random crashes.
 #endif
+
+/* if 220 exists, can not set External Memory WB and L2 not_cached, either External Memory not_cached and L2 WB */
+#if ANOMALY_05000220 && \
+       ((defined(CONFIG_BFIN_WB) && defined(CONFIG_BFIN_L2_NOT_CACHED)) || \
+        (!defined(CONFIG_BFIN_DCACHE) && defined(CONFIG_BFIN_L2_WB)))
+# error You are exposing Anomaly 220 in this config, either config L2 as Write Through, or make External Memory WB.
+#endif
index aa0648c6a9feb19111d2b8e60e96dfef12bc9340..d9666fe6c3d6e4847db784ae6d3f2ab1bb14af01 100644 (file)
 
 .text
 
+/* 05000443 - IFLUSH cannot be last instruction in hardware loop */
+#if ANOMALY_05000443
+# define BROK_FLUSH_INST "IFLUSH"
+#else
+# define BROK_FLUSH_INST "no anomaly! yeah!"
+#endif
+
 /* Since all L1 caches work the same way, we use the same method for flushing
  * them.  Only the actual flush instruction differs.  We write this in asm as
  * GCC can be hard to coax into writing nice hardware loops.
@@ -23,7 +30,7 @@
  * R0 = start address
  * R1 = end address
  */
-.macro do_flush flushins:req optflushins optnopins label
+.macro do_flush flushins:req label
 
        R2 = -L1_CACHE_BYTES;
 
 \label :
 .endif
        P0 = R0;
+
        LSETUP (1f, 2f) LC1 = P1;
 1:
-.ifnb \optflushins
-       \optflushins [P0];
-.endif
-#if ANOMALY_05000443
-.ifb \optnopins
-2:
-.endif
+.ifeqs "\flushins", BROK_FLUSH_INST
        \flushins [P0++];
-.ifnb \optnopins
-2:     \optnopins;
-.endif
-#else
+2:     nop;
+.else
 2:     \flushins [P0++];
-#endif
+.endif
 
        RTS;
 .endm
@@ -77,25 +77,9 @@ ENTRY(_blackfin_icache_flush_range)
  */
        P0 = R0;
        IFLUSH[P0];
-       do_flush IFLUSH, , nop
+       do_flush IFLUSH
 ENDPROC(_blackfin_icache_flush_range)
 
-/* Flush all cache lines assocoiated with this area of memory. */
-ENTRY(_blackfin_icache_dcache_flush_range)
-/*
- * Walkaround to avoid loading wrong instruction after invalidating icache
- * and following sequence is met.
- *
- * 1) One instruction address is cached in the instruction cache.
- * 2) This instruction in SDRAM is changed.
- * 3) IFLASH[P0] is executed only once in blackfin_icache_flush_range().
- * 4) This instruction is executed again, but the old one is loaded.
- */
-       P0 = R0;
-       IFLUSH[P0];
-       do_flush FLUSH, IFLUSH
-ENDPROC(_blackfin_icache_dcache_flush_range)
-
 /* Throw away all D-cached data in specified region without any obligation to
  * write them back.  Since the Blackfin ISA does not have an "invalidate"
  * instruction, we use flush/invalidate.  Perhaps as a speed optimization we
@@ -107,7 +91,7 @@ ENDPROC(_blackfin_dcache_invalidate_range)
 
 /* Flush all data cache lines assocoiated with this memory area */
 ENTRY(_blackfin_dcache_flush_range)
-       do_flush FLUSH, , , .Ldfr
+       do_flush FLUSH, .Ldfr
 ENDPROC(_blackfin_dcache_flush_range)
 
 /* Our headers convert the page structure to an address, so just need to flush
index 35393651359bfc004d996154fb7d8d2497e45b5b..ef6870e9eea6d37c4771cfbd73906d85ffe03dec 100644 (file)
@@ -72,6 +72,7 @@ void init_clocks(void)
 #endif
        bfin_write_PLL_LOCKCNT(0x300);
        do_sync();
+       /* We always write PLL_CTL thus avoiding Anomaly 05000242 */
        bfin_write16(PLL_CTL, PLL_CTL_VAL);
        __asm__ __volatile__("IDLE;");
        bfin_write_PLL_DIV(CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV);
index 72e16605ca09f61f41bb3d8d3302ad6123d08d8b..70e3411f558c189b7f2f28ef67c3a5e706fa8857 100644 (file)
@@ -140,7 +140,8 @@ static int __init __bfin_cpu_init(struct cpufreq_policy *policy)
        cclk = get_cclk() / 1000;
        sclk = get_sclk() / 1000;
 
-#if ANOMALY_05000273 || (!defined(CONFIG_BF54x) && defined(CONFIG_BFIN_DCACHE))
+#if ANOMALY_05000273 || ANOMALY_05000274 || \
+       (!defined(CONFIG_BF54x) && defined(CONFIG_BFIN_DCACHE))
        min_cclk = sclk * 2;
 #else
        min_cclk = sclk;
index a063a434f7e35e5235f343a570a8ef60ded304a1..da0558ad1b1a7495764d2b375de4de409e7df992 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/init.h>
 #include <linux/linkage.h>
 #include <linux/unistd.h>
-#include <linux/threads.h>
 #include <asm/blackfin.h>
 #include <asm/errno.h>
 #include <asm/fixed_code.h>
@@ -201,7 +200,18 @@ ENTRY(_ex_single_step)
        cc = r7 == 0;
        if !cc jump 1f;
 #endif
-
+#ifdef CONFIG_EXACT_HWERR
+       /* Read the ILAT, and to check to see if the process we are
+        * single stepping caused a previous hardware error
+        * If so, do not single step, (which lowers to IRQ5, and makes
+        * us miss the error).
+        */
+       p5.l = lo(ILAT);
+       p5.h = hi(ILAT);
+       r7 = [p5];
+       cc = bittst(r7, EVT_IVHW_P);
+       if cc jump 1f;
+#endif
        /* Single stepping only a single instruction, so clear the trace
         * bit here.  */
        r7 = syscfg;
@@ -263,15 +273,6 @@ ENTRY(_bfin_return_from_exception)
        r6 = 0x25;
        CC = R7 == R6;
        if CC JUMP _double_fault;
-
-       /* Did we cause a HW error? */
-       p5.l = lo(ILAT);
-       p5.h = hi(ILAT);
-       r6 = [p5];
-       r7 = 0x20;              /* Did I just cause anther HW error? */
-       r6 = r7 & r6;
-       CC = R7 == R6;
-       if CC JUMP _double_fault;
 #endif
 
        (R7:6,P5:4) = [sp++];
@@ -473,6 +474,16 @@ ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/
        [--sp] = ASTAT;
        [--sp] = (R7:6,P5:4);
 
+#ifdef CONFIG_EXACT_HWERR
+       /* Make sure all pending read/writes complete. This will ensure any
+        * accesses which could cause hardware errors completes, and signal
+        * the the hardware before we do something silly, like crash the
+        * kernel. We don't need to work around anomaly 05000312, since
+        * we are already atomic
+        */
+       ssync;
+#endif
+
 #if ANOMALY_05000283 || ANOMALY_05000315
        cc = r7 == r7;
        p5.h = HI(CHIPID);
@@ -855,7 +866,7 @@ ENTRY(_ret_from_exception)
        p1.h = _schedule_and_signal;
        [p0] = p1;
        csync;
-       raise 15;               /* raise evt14 to do signal or reschedule */
+       raise 15;               /* raise evt15 to do signal or reschedule */
 4:
        r0 = syscfg;
        bitclr(r0, 0);
@@ -916,7 +927,7 @@ ENTRY(_return_from_int)
        p1.h = _schedule_and_signal_from_int;
        [p0] = p1;
        csync;
-#if ANOMALY_05000281
+#if ANOMALY_05000281 || ANOMALY_05000461
        r0.l = lo(SAFE_USER_INSTRUCTION);
        r0.h = hi(SAFE_USER_INSTRUCTION);
        reti = r0;
@@ -930,18 +941,27 @@ ENTRY(_return_from_int)
 ENDPROC(_return_from_int)
 
 ENTRY(_lower_to_irq14)
-#if ANOMALY_05000281
+#if ANOMALY_05000281 || ANOMALY_05000461
        r0.l = lo(SAFE_USER_INSTRUCTION);
        r0.h = hi(SAFE_USER_INSTRUCTION);
        reti = r0;
 #endif
-       r0 = 0x401f;
+
+#ifdef CONFIG_DEBUG_HWERR
+       /* enable irq14 & hwerr interrupt, until we transition to _evt14_softirq */
+       r0 = (EVT_IVG14 | EVT_IVHW | EVT_IRPTEN | EVT_EVX | EVT_NMI | EVT_RST | EVT_EMU);
+#else
+       /* Only enable irq14 interrupt, until we transition to _evt14_softirq */
+       r0 = (EVT_IVG14 | EVT_IRPTEN | EVT_EVX | EVT_NMI | EVT_RST | EVT_EMU);
+#endif
        sti r0;
        raise 14;
        rti;
+ENDPROC(_lower_to_irq14)
+
 ENTRY(_evt14_softirq)
 #ifdef CONFIG_DEBUG_HWERR
-       r0 = 0x3f;
+       r0 = (EVT_IVHW | EVT_IRPTEN | EVT_EVX | EVT_NMI | EVT_RST | EVT_EMU);
        sti r0;
 #else
        cli r0;
@@ -949,8 +969,9 @@ ENTRY(_evt14_softirq)
        [--sp] = RETI;
        SP += 4;
        rts;
+ENDPROC(_evt14_softirq)
 
-_schedule_and_signal_from_int:
+ENTRY(_schedule_and_signal_from_int)
        /* To end up here, vector 15 was changed - so we have to change it
         * back.
         */
@@ -983,8 +1004,9 @@ _schedule_and_signal_from_int:
        call _finish_atomic_sections;
        sp += 12;
        jump.s .Lresume_userspace;
+ENDPROC(_schedule_and_signal_from_int)
 
-_schedule_and_signal:
+ENTRY(_schedule_and_signal)
        SAVE_CONTEXT_SYSCALL
        /* To end up here, vector 15 was changed - so we have to change it
         * back.
@@ -1002,7 +1024,7 @@ _schedule_and_signal:
 1:
        RESTORE_CONTEXT
        rti;
-ENDPROC(_lower_to_irq14)
+ENDPROC(_schedule_and_signal)
 
 /* We handle this 100% in exception space - to reduce overhead
  * Only potiential problem is if the software buffer gets swapped out of the
@@ -1588,19 +1610,3 @@ ENTRY(_sys_call_table)
        .long _sys_ni_syscall
        .endr
 END(_sys_call_table)
-
-#ifdef CONFIG_EXCEPTION_L1_SCRATCH
-/* .section .l1.bss.scratch */
-.set _exception_stack_top, L1_SCRATCH_START + L1_SCRATCH_LENGTH
-#else
-#ifdef CONFIG_SYSCALL_TAB_L1
-.section .l1.bss
-#else
-.bss
-#endif
-ENTRY(_exception_stack)
-       .rept 1024 * NR_CPUS
-       .long 0
-       .endr
-_exception_stack_top:
-#endif
index 698d4c05947e8ba48a21320344a8fc3f93162c00..f826f6b9f917e168e31ef84604549424745015c7 100644 (file)
@@ -30,8 +30,6 @@ ENTRY(__init_clear_bss)
        rts;
 ENDPROC(__init_clear_bss)
 
-#define INITIAL_STACK  (L1_SCRATCH_START + L1_SCRATCH_LENGTH - 12)
-
 ENTRY(__start)
        /* R0: argument of command line string, passed from uboot, save it */
        R7 = R0;
@@ -126,30 +124,30 @@ ENTRY(__start)
         * below
         */
        GET_PDA(p0, r0);
-       r7 = [p0 + PDA_RETX];
+       r6 = [p0 + PDA_RETX];
        p1.l = _init_saved_retx;
        p1.h = _init_saved_retx;
-       [p1] = r7;
+       [p1] = r6;
 
-       r7 = [p0 + PDA_DCPLB];
+       r6 = [p0 + PDA_DCPLB];
        p1.l = _init_saved_dcplb_fault_addr;
        p1.h = _init_saved_dcplb_fault_addr;
-       [p1] = r7;
+       [p1] = r6;
 
-       r7 = [p0 + PDA_ICPLB];
+       r6 = [p0 + PDA_ICPLB];
        p1.l = _init_saved_icplb_fault_addr;
        p1.h = _init_saved_icplb_fault_addr;
-       [p1] = r7;
+       [p1] = r6;
 
-       r7 = [p0 + PDA_SEQSTAT];
+       r6 = [p0 + PDA_SEQSTAT];
        p1.l = _init_saved_seqstat;
        p1.h = _init_saved_seqstat;
-       [p1] = r7;
+       [p1] = r6;
 #endif
 
        /* Initialize stack pointer */
-       sp.l = lo(INITIAL_STACK);
-       sp.h = hi(INITIAL_STACK);
+       sp.l = _init_thread_union;
+       sp.h = _init_thread_union;
        fp = sp;
        usp = sp;
 
@@ -189,7 +187,15 @@ ENTRY(__start)
        /* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
        call _bfin_relocate_l1_mem;
 #ifdef CONFIG_BFIN_KERNEL_CLOCK
+       /* Only use on-chip scratch space for stack when absolutely required
+        * to avoid Anomaly 05000227 ... we know the init_clocks() func only
+        * uses L1 text and stack space and no other memory region.
+        */
+# define KERNEL_CLOCK_STACK (L1_SCRATCH_START + L1_SCRATCH_LENGTH - 12)
+       sp.l = lo(KERNEL_CLOCK_STACK);
+       sp.h = hi(KERNEL_CLOCK_STACK);
        call _init_clocks;
+       sp = usp;       /* usp hasnt been touched, so restore from there */
 #endif
 
        /* This section keeps the processor in supervisor mode
@@ -243,9 +249,7 @@ ENTRY(_real_start)
        call _cmdline_init;
 
        /* Load the current thread pointer and stack */
-       sp.l = _init_thread_union;
-       sp.h = _init_thread_union;
-       p1 = THREAD_SIZE (z);
+       p1 = THREAD_SIZE + 4 (z);       /* +4 is for reti loading */
        sp = sp + p1;
        usp = sp;
        fp = sp;
index 0069c2dd462520db2a1abb7ad4c54108efcc5203..9c46680186e4de2cab991257451d2f96c50e3dde 100644 (file)
@@ -145,6 +145,14 @@ __common_int_entry:
 
 /* interrupt routine for ivhw - 5 */
 ENTRY(_evt_ivhw)
+       /* In case a single action kicks off multiple memory transactions, (like
+        * a cache line fetch, - this can cause multiple hardware errors, let's
+        * catch them all. First - make sure all the actions are complete, and
+        * the core sees the hardware errors.
+        */
+       SSYNC;
+       SSYNC;
+
        SAVE_ALL_SYS
 #ifdef CONFIG_FRAME_POINTER
        fp = 0;
@@ -159,6 +167,25 @@ ENTRY(_evt_ivhw)
 1:
 #endif
 
+       /* Handle all stacked hardware errors
+        * To make sure we don't hang forever, only do it 10 times
+        */
+       R0 = 0;
+       R2 = 10;
+1:
+       P0.L = LO(ILAT);
+       P0.H = HI(ILAT);
+       R1 = [P0];
+       CC = BITTST(R1, EVT_IVHW_P);
+       IF ! CC JUMP 2f;
+       /* OK a hardware error is pending - clear it */
+       R1 = EVT_IVHW_P;
+       [P0] = R1;
+       R0 += 1;
+       CC = R1 == R2;
+       if CC JUMP 2f;
+       JUMP 1b;
+2:
        # We are going to dump something out, so make sure we print IPEND properly
        p2.l = lo(IPEND);
        p2.h = hi(IPEND);
index a7d7b2dd4059a7f5685cec710bb9409174c31589..351afd0e36d8f8552dc4d2b85f37e0c49d4523a3 100644 (file)
@@ -1052,7 +1052,7 @@ int __init init_arch_irq(void)
                        set_irq_chained_handler(irq, bfin_demux_error_irq);
                        break;
 #endif
-#if defined(CONFIG_TICK_SOURCE_SYSTMR0) || defined(CONFIG_IPIPE)
+#if defined(CONFIG_TICKSOURCE_GPTMR0)
                case IRQ_TIMER0:
                        set_irq_handler(irq, handle_percpu_irq);
                        break;
@@ -1116,6 +1116,9 @@ int __init init_arch_irq(void)
            IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |
            IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW;
 
+       /* This implicitly covers ANOMALY_05000171
+        * Boot-ROM code modifies SICA_IWRx wakeup registers
+        */
 #ifdef SIC_IWR0
        bfin_write_SIC_IWR0(IWR_DISABLE_ALL);
 # ifdef SIC_IWR1
@@ -1136,13 +1139,6 @@ int __init init_arch_irq(void)
        bfin_write_SIC_IWR(IWR_DISABLE_ALL);
 #endif
 
-#ifdef CONFIG_IPIPE
-       for (irq = 0; irq < NR_IRQS; irq++) {
-               struct irq_desc *desc = irq_to_desc(irq);
-               desc->ic_prio = __ipipe_get_irq_priority(irq);
-       }
-#endif /* CONFIG_IPIPE */
-
        return 0;
 }
 
@@ -1156,23 +1152,22 @@ void do_irq(int vec, struct pt_regs *fp)
        } else {
                struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;
                struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;
-#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561) \
-       || defined(BF538_FAMILY) || defined(CONFIG_BF51x)
+#if defined(SIC_ISR0) || defined(SICA_ISR0)
                unsigned long sic_status[3];
 
                if (smp_processor_id()) {
-#ifdef CONFIG_SMP
+# ifdef SICB_ISR0
                        /* This will be optimized out in UP mode. */
                        sic_status[0] = bfin_read_SICB_ISR0() & bfin_read_SICB_IMASK0();
                        sic_status[1] = bfin_read_SICB_ISR1() & bfin_read_SICB_IMASK1();
-#endif
+# endif
                } else {
                        sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
                        sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
                }
-#ifdef CONFIG_BF54x
+# ifdef SIC_ISR2
                sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
-#endif
+# endif
                for (;; ivg++) {
                        if (ivg >= ivg_stop) {
                                atomic_inc(&num_spurious);
@@ -1236,20 +1231,16 @@ asmlinkage int __ipipe_grab_irq(int vec, struct pt_regs *regs)
 
        if (likely(vec == EVT_IVTMR_P)) {
                irq = IRQ_CORETMR;
-               goto core_tick;
-       }
 
-       SSYNC();
-
-#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561)
-       {
+       } else {
+#if defined(SIC_ISR0) || defined(SICA_ISR0)
                unsigned long sic_status[3];
 
                sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
                sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
-#ifdef CONFIG_BF54x
+# ifdef SIC_ISR2
                sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
-#endif
+# endif
                for (;; ivg++) {
                        if (ivg >= ivg_stop) {
                                atomic_inc(&num_spurious);
@@ -1258,9 +1249,7 @@ asmlinkage int __ipipe_grab_irq(int vec, struct pt_regs *regs)
                        if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)
                                break;
                }
-       }
 #else
-       {
                unsigned long sic_status;
 
                sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();
@@ -1272,15 +1261,13 @@ asmlinkage int __ipipe_grab_irq(int vec, struct pt_regs *regs)
                        } else if (sic_status & ivg->isrflag)
                                break;
                }
-       }
 #endif
 
-       irq = ivg->irqno;
+               irq = ivg->irqno;
+       }
 
        if (irq == IRQ_SYSTMR) {
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
-core_tick:
-#else
+#ifndef CONFIG_GENERIC_CLOCKEVENTS
                bfin_write_TIMER_STATUS(1); /* Latch TIMIL0 */
 #endif
                /* This is basically what we need from the register frame. */
@@ -1292,9 +1279,6 @@ core_tick:
                        __raw_get_cpu_var(__ipipe_tick_regs).ipend |= 0x10;
        }
 
-#ifndef CONFIG_GENERIC_CLOCKEVENTS
-core_tick:
-#endif
        if (this_domain == ipipe_root_domain) {
                s = __test_and_set_bit(IPIPE_SYNCDEFER_FLAG, &p->status);
                barrier();
@@ -1312,7 +1296,7 @@ core_tick:
                }
        }
 
-       return 0;
+       return 0;
 }
 
 #endif /* CONFIG_IPIPE */
index 93eab61460792b8a10d08f7ce33ee3d1d9f1d853..3b8ebaee77f2d1dd38adbaa5a2a6f0eac036a5db 100644 (file)
 #include <asm/processor.h>
 #include <asm/ptrace.h>
 #include <asm/cpu.h>
+#include <asm/time.h>
 #include <linux/err.h>
 
+/*
+ * Anomaly notes:
+ * 05000120 - we always define corelock as 32-bit integer in L2
+ */
 struct corelock_slot corelock __attribute__ ((__section__(".l2.bss")));
 
 void __cpuinitdata *init_retx_coreb, *init_saved_retx_coreb,
@@ -352,7 +357,7 @@ int __cpuinit __cpu_up(unsigned int cpu)
 
 static void __cpuinit setup_secondary(unsigned int cpu)
 {
-#if !(defined(CONFIG_TICK_SOURCE_SYSTMR0) || defined(CONFIG_IPIPE))
+#if !defined(CONFIG_TICKSOURCE_GPTMR0)
        struct irq_desc *timer_desc;
 #endif
        unsigned long ilat;
@@ -364,16 +369,13 @@ static void __cpuinit setup_secondary(unsigned int cpu)
        bfin_write_ILAT(ilat);
        CSYNC();
 
-       /* Reserve the PDA space for the secondary CPU. */
-       reserve_pda();
-
        /* Enable interrupt levels IVG7-15. IARs have been already
         * programmed by the boot CPU.  */
        bfin_irq_flags |= IMASK_IVG15 |
            IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |
            IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW;
 
-#if defined(CONFIG_TICK_SOURCE_SYSTMR0) || defined(CONFIG_IPIPE)
+#if defined(CONFIG_TICKSOURCE_GPTMR0)
        /* Power down the core timer, just to play safe. */
        bfin_write_TCNTL(0);
 
index 8cb0945563f9eda946c5ac274af431c58786c921..bc0062884fde3388337a30a0c0bf4b833e04430a 100644 (file)
@@ -30,7 +30,6 @@
 #ifndef __BLACKFIN_SRAM_H__
 #define __BLACKFIN_SRAM_H__
 
-extern void bfin_sram_init(void);
 extern void *l1sram_alloc(size_t);
 
 #endif
index 9c3629b9a689420edb42a34e3d7611c9650fbe57..014a55abd09a4999731871efd6e095ad6951f26c 100644 (file)
@@ -52,9 +52,14 @@ static unsigned long empty_bad_page_table;
 
 static unsigned long empty_bad_page;
 
-unsigned long empty_zero_page;
+static unsigned long empty_zero_page;
 
-extern unsigned long exception_stack[NR_CPUS][1024];
+#ifndef CONFIG_EXCEPTION_L1_SCRATCH
+#if defined CONFIG_SYSCALL_TAB_L1
+__attribute__((l1_data))
+#endif
+static unsigned long exception_stack[NR_CPUS][1024];
+#endif
 
 struct blackfin_pda cpu_pda[NR_CPUS];
 EXPORT_SYMBOL(cpu_pda);
@@ -117,19 +122,18 @@ asmlinkage void __init init_pda(void)
        cpu_pda[0].next = &cpu_pda[1];
        cpu_pda[1].next = &cpu_pda[0];
 
+#ifdef CONFIG_EXCEPTION_L1_SCRATCH
+       cpu_pda[cpu].ex_stack = (unsigned long *)(L1_SCRATCH_START + \
+                                       L1_SCRATCH_LENGTH);
+#else
        cpu_pda[cpu].ex_stack = exception_stack[cpu + 1];
+#endif
 
 #ifdef CONFIG_SMP
        cpu_pda[cpu].imask = 0x1f;
 #endif
 }
 
-void __cpuinit reserve_pda(void)
-{
-       printk(KERN_INFO "PDA for CPU%u reserved at %p\n", smp_processor_id(),
-                                       &cpu_pda[smp_processor_id()]);
-}
-
 void __init mem_init(void)
 {
        unsigned int codek = 0, datak = 0, initk = 0;
@@ -171,19 +175,6 @@ void __init mem_init(void)
                initk, codek, datak, DMA_UNCACHED_REGION >> 10, (reservedpages << (PAGE_SHIFT-10)));
 }
 
-static int __init sram_init(void)
-{
-       /* Initialize the blackfin L1 Memory. */
-       bfin_sram_init();
-
-       /* Reserve the PDA space for the boot CPU right after we
-        * initialized the scratch memory allocator.
-        */
-       reserve_pda();
-       return 0;
-}
-pure_initcall(sram_init);
-
 static void __init free_init_pages(const char *what, unsigned long begin, unsigned long end)
 {
        unsigned long addr;
index 22913e7a1818169a4909c2403da1f185858eae67..c080e70f98b0c579eafbb7d07365daaa2f8d484c 100644 (file)
@@ -125,7 +125,7 @@ static bool isram_check_addr(const void *addr, size_t n)
 {
        if ((addr >= (void *)L1_CODE_START) &&
            (addr < (void *)(L1_CODE_START + L1_CODE_LENGTH))) {
-               if ((addr + n) >= (void *)(L1_CODE_START + L1_CODE_LENGTH)) {
+               if ((addr + n) > (void *)(L1_CODE_START + L1_CODE_LENGTH)) {
                        show_stack(NULL, NULL);
                        printk(KERN_ERR "isram_memcpy: copy involving %p length "
                                        "(%zu) too long\n", addr, n);
index 530d1393a23226926c80ef833dd6b32230405214..0bc3c4ef0aad54664610b7713a7a9f9696845890 100644 (file)
@@ -83,6 +83,14 @@ static struct kmem_cache *sram_piece_cache;
 static void __init l1sram_init(void)
 {
        unsigned int cpu;
+       unsigned long reserve;
+
+#ifdef CONFIG_SMP
+       reserve = 0;
+#else
+       reserve = sizeof(struct l1_scratch_task_info);
+#endif
+
        for (cpu = 0; cpu < num_possible_cpus(); ++cpu) {
                per_cpu(free_l1_ssram_head, cpu).next =
                        kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
@@ -91,8 +99,8 @@ static void __init l1sram_init(void)
                        return;
                }
 
-               per_cpu(free_l1_ssram_head, cpu).next->paddr = (void *)get_l1_scratch_start_cpu(cpu);
-               per_cpu(free_l1_ssram_head, cpu).next->size = L1_SCRATCH_LENGTH;
+               per_cpu(free_l1_ssram_head, cpu).next->paddr = (void *)get_l1_scratch_start_cpu(cpu) + reserve;
+               per_cpu(free_l1_ssram_head, cpu).next->size = L1_SCRATCH_LENGTH - reserve;
                per_cpu(free_l1_ssram_head, cpu).next->pid = 0;
                per_cpu(free_l1_ssram_head, cpu).next->next = NULL;
 
@@ -223,7 +231,7 @@ static void __init l2_sram_init(void)
        spin_lock_init(&l2_sram_lock);
 }
 
-void __init bfin_sram_init(void)
+static int __init bfin_sram_init(void)
 {
        sram_piece_cache = kmem_cache_create("sram_piece_cache",
                                sizeof(struct sram_piece),
@@ -233,7 +241,10 @@ void __init bfin_sram_init(void)
        l1_data_sram_init();
        l1_inst_sram_init();
        l2_sram_init();
+
+       return 0;
 }
+pure_initcall(bfin_sram_init);
 
 /* SRAM allocate function */
 static void *_sram_alloc(size_t size, struct sram_piece *pfree_head,
@@ -732,6 +743,10 @@ found:
 }
 EXPORT_SYMBOL(sram_free_with_lsl);
 
+/* Allocate memory and keep in L1 SRAM List (lsl) so that the resources are
+ * tracked.  These are designed for userspace so that when a process exits,
+ * we can safely reap their resources.
+ */
 void *sram_alloc_with_lsl(size_t size, unsigned long flags)
 {
        void *addr = NULL;
index 5718dd8902a11d0953f77c03d75db4306c861073..a6aca819e9f334050d6927146fa0a2941901c1e6 100644 (file)
@@ -158,5 +158,5 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
 #define smp_mb__before_atomic_inc()    barrier()
 #define smp_mb__after_atomic_inc()     barrier()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif
diff --git a/arch/cris/include/asm/bitsperlong.h b/arch/cris/include/asm/bitsperlong.h
new file mode 100644 (file)
index 0000000..6dc0bb0
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/bitsperlong.h>
index 1c35e1b66b46e206a24d5b99a65a13eedcf44ad3..b7f0afba3ce052c515972d9c28d17ec264057243 100644 (file)
@@ -3,7 +3,7 @@
 
 /* verbatim copy of asm-i386/ version */
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 #define MAP_GROWSDOWN  0x0100          /* stack-like segment */
 #define MAP_DENYWRITE  0x0800          /* ETXTBSY */
index f3fdbd09c34cfe0b7cd62d50487f4460ac668977..be45ee366be922f43dd0a4b6e4e1f8dcc9aa3d25 100644 (file)
@@ -68,7 +68,7 @@ typedef struct page *pgtable_t;
                                 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
 #include <asm-generic/memory_model.h>
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* _CRIS_PAGE_H */
 
index 349ae682b568625083fd2dcbf3f8e157a4251ab6..ea6af9aad76c25c92d255c842ea95f0aeba27fbe 100644 (file)
@@ -106,7 +106,7 @@ typedef unsigned long sigset_t;
 #define MINSIGSTKSZ    2048
 #define SIGSTKSZ       8192
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
index a187833febc8b0cfd582a39b84aaefdabe54a205..abc13e368b909540df0c66206f7e95ad42d07745 100644 (file)
@@ -48,8 +48,6 @@ void *module_alloc(unsigned long size)
 void module_free(struct module *mod, void *module_region)
 {
        FREE_MODULE(module_region);
-       /* FIXME: If module_region == mod->init_region, trim exception
-          table entries. */
 }
 
 /* We don't need anything special. */
index 296c35cfb207a5a9d4342f5bfb9bd7baee7f9519..0409d981fd39501820618036f8667957ef7f205d 100644 (file)
@@ -194,5 +194,5 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
 
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* _ASM_ATOMIC_H */
diff --git a/arch/frv/include/asm/bitsperlong.h b/arch/frv/include/asm/bitsperlong.h
new file mode 100644 (file)
index 0000000..6dc0bb0
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/bitsperlong.h>
index b4371e9286836ff5f3d84da2c6ddf4becc6ce049..58c1d11e2ac71fe225f7e2a05137d80e53dbc32a 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __ASM_MMAN_H__
 #define __ASM_MMAN_H__
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 #define MAP_GROWSDOWN  0x0100          /* stack-like segment */
 #define MAP_DENYWRITE  0x0800          /* ETXTBSY */
index bd9c220094c74b288a03dc958f91e1b977dcb57c..25c6a5002355da190f88b90c5d8954b912453a6f 100644 (file)
@@ -73,6 +73,6 @@ extern unsigned long max_pfn;
 #endif /* __ASSEMBLY__ */
 
 #include <asm-generic/memory_model.h>
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* _ASM_PAGE_H */
index cc685e60b0f9ce92c06372cd695346a3b3ba6b17..492b5c4dfed606d3004faf808b7a7270c3c94d0d 100644 (file)
@@ -10,8 +10,8 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#ifndef ASM_PCI_H
-#define        ASM_PCI_H
+#ifndef _ASM_FRV_PCI_H
+#define _ASM_FRV_PCI_H
 
 #include <linux/mm.h>
 #include <asm/scatterlist.h>
@@ -43,12 +43,6 @@ extern void pci_free_consistent(struct pci_dev *hwdev, size_t size,
 /* Return the index of the PCI controller for device PDEV. */
 #define pci_controller_num(PDEV)       (0)
 
-/* The PCI address space does equal the physical memory
- * address space.  The networking and block device layers use
- * this boolean for bounce buffer decisions.
- */
-#define PCI_DMA_BUS_IS_PHYS    (1)
-
 /* pci_unmap_{page,single} is a nop so... */
 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
 #define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
@@ -111,5 +105,4 @@ static inline void pci_dma_sync_sg(struct pci_dev *hwdev,
                                    sg_dma_address(&sg[i])+sg_dma_len(&sg[i]));
 }
 
-
-#endif
+#endif /* _ASM_FRV_PCI_H */
index 2079197d483d3855e1539f00ef4b650e6b36dc3b..f071e813dcb3c21d5110ecee08d57a2e7fcf26db 100644 (file)
 
 #include <linux/types.h>
 
-/* Avoid too many header ordering problems.  */
-struct siginfo;
-
-#ifdef __KERNEL__
-/* Most things should be clean enough to redefine this at will, if care
-   is taken to make libc match.  */
-
-#define _NSIG          64
-#define _NSIG_BPW      32
-#define _NSIG_WORDS    (_NSIG / _NSIG_BPW)
-
-typedef unsigned long old_sigset_t;            /* at least 32 bits */
-
-typedef struct {
-       unsigned long sig[_NSIG_WORDS];
-} sigset_t;
-
-#else
+#ifndef __KERNEL__
 /* Here we must cater to libcs that poke about in kernel headers.  */
 
 #define NSIG           32
 typedef unsigned long sigset_t;
 
-#endif /* __KERNEL__ */
-
-#define SIGHUP          1
-#define SIGINT          2
-#define SIGQUIT                 3
-#define SIGILL          4
-#define SIGTRAP                 5
-#define SIGABRT                 6
-#define SIGIOT          6
-#define SIGBUS          7
-#define SIGFPE          8
-#define SIGKILL                 9
-#define SIGUSR1                10
-#define SIGSEGV                11
-#define SIGUSR2                12
-#define SIGPIPE                13
-#define SIGALRM                14
-#define SIGTERM                15
-#define SIGSTKFLT      16
-#define SIGCHLD                17
-#define SIGCONT                18
-#define SIGSTOP                19
-#define SIGTSTP                20
-#define SIGTTIN                21
-#define SIGTTOU                22
-#define SIGURG         23
-#define SIGXCPU                24
-#define SIGXFSZ                25
-#define SIGVTALRM      26
-#define SIGPROF                27
-#define SIGWINCH       28
-#define SIGIO          29
-#define SIGPOLL                SIGIO
-/*
-#define SIGLOST                29
-*/
-#define SIGPWR         30
-#define SIGSYS         31
-#define        SIGUNUSED       31
-
-/* These should not be considered constants from userland.  */
-#define SIGRTMIN       32
-#define SIGRTMAX       (_NSIG-1)
-
-/*
- * SA_FLAGS values:
- *
- * SA_ONSTACK indicates that a registered stack_t will be used.
- * SA_RESTART flag to get restarting signals (which were the default long ago)
- * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
- * SA_RESETHAND clears the handler when the signal is delivered.
- * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
- * SA_NODEFER prevents the current signal from being masked in the handler.
- *
- * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
- * Unix names RESETHAND and NODEFER respectively.
- */
-#define SA_NOCLDSTOP   0x00000001
-#define SA_NOCLDWAIT   0x00000002 /* not supported yet */
-#define SA_SIGINFO     0x00000004
-#define SA_ONSTACK     0x08000000
-#define SA_RESTART     0x10000000
-#define SA_NODEFER     0x40000000
-#define SA_RESETHAND   0x80000000
-
-#define SA_NOMASK      SA_NODEFER
-#define SA_ONESHOT     SA_RESETHAND
-
-#define SA_RESTORER    0x04000000
-
-/*
- * sigaltstack controls
- */
-#define SS_ONSTACK     1
-#define SS_DISABLE     2
+#endif /* !__KERNEL__ */
 
-#define MINSIGSTKSZ    2048
-#define SIGSTKSZ       8192
+#define SA_RESTORER    0x04000000 /* to get struct sigaction correct */
 
 #include <asm-generic/signal.h>
 
@@ -115,16 +23,6 @@ struct old_sigaction {
        __sigrestore_t sa_restorer;
 };
 
-struct sigaction {
-       __sighandler_t sa_handler;
-       unsigned long sa_flags;
-       __sigrestore_t sa_restorer;
-       sigset_t sa_mask;               /* mask last for extensibility */
-};
-
-struct k_sigaction {
-       struct sigaction sa;
-};
 #else
 /* Here we must cater to libcs that poke about in kernel headers.  */
 
@@ -143,19 +41,4 @@ struct sigaction {
 
 #endif /* __KERNEL__ */
 
-typedef struct sigaltstack {
-       void __user *ss_sp;
-       int ss_flags;
-       size_t ss_size;
-} stack_t;
-
-#define ptrace_signal_deliver(regs, cookie) do { } while (0)
-
-#ifdef __KERNEL__
-
-#include <asm/sigcontext.h>
-#undef __HAVE_ARCH_SIG_BITOPS
-
-#endif /* __KERNEL__ */
-
 #endif /* _ASM_SIGNAL_H */
index a62fb58723758faeef174533a1e867356f0da697..b4868aafe79c3c99e58254ef21f673e822fcd345 100644 (file)
@@ -52,7 +52,7 @@ struct termio {
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 
 #ifdef __KERNEL__
-#include <asm-generic/termios.h>
+#include <asm-generic/termios-base.h>
 #endif
 
 #endif /* _ASM_TERMIOS_H */
index 850d168f69fc553b9cfc51ae3abe6122067ac8da..711763c8a6f3a76c5901d43f0744e09aa94d6e6c 100644 (file)
@@ -35,8 +35,6 @@ void *module_alloc(unsigned long size)
 void module_free(struct module *mod, void *module_region)
 {
        vfree(module_region);
-       /* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
 }
 
 /* We don't need anything special. */
index 833186c8dc3b9cab79f0e801feb602ee952a098c..33c8c0fa9583e0c2794cf0950006d824da961778 100644 (file)
@@ -141,5 +141,5 @@ static __inline__ void atomic_set_mask(unsigned long mask, unsigned long *v)
 #define smp_mb__before_atomic_inc()    barrier()
 #define smp_mb__after_atomic_inc() barrier()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* __ARCH_H8300_ATOMIC __ */
diff --git a/arch/h8300/include/asm/bitsperlong.h b/arch/h8300/include/asm/bitsperlong.h
new file mode 100644 (file)
index 0000000..6dc0bb0
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/bitsperlong.h>
index b9f104f22a36a96b976758baca4215e47955b9df..cf35f0a6f12eee77729b51551f7a87bb3aeba477 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __H8300_MMAN_H__
 #define __H8300_MMAN_H__
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 #define MAP_GROWSDOWN  0x0100          /* stack-like segment */
 #define MAP_DENYWRITE  0x0800          /* ETXTBSY */
index 0b6acf0b03aa823a884cd8a861666ef9b1a75ecd..837381a2df464d74fb1d156ea65f2215f6835e4f 100644 (file)
@@ -73,6 +73,6 @@ extern unsigned long memory_end;
 #endif /* __ASSEMBLY__ */
 
 #include <asm-generic/memory_model.h>
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* _H8300_PAGE_H */
index 7bc15048a64f810ad4a0fee4475cd31c1ba4c975..fd8b66e40dcaa41c726500c66237e2b4b87cc92a 100644 (file)
@@ -105,7 +105,7 @@ typedef unsigned long sigset_t;
 #define MINSIGSTKSZ    2048
 #define SIGSTKSZ       8192
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
index cfc9127d2cede26312fcaef364a35d6be0c95080..0865e291c20d2948c95edc70f52925121409599d 100644 (file)
@@ -23,8 +23,6 @@ void *module_alloc(unsigned long size)
 void module_free(struct module *mod, void *module_region)
 {
        vfree(module_region);
-       /* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
 }
 
 /* We don't need anything special. */
index d37292bd98757402f2f075689bb0e04cf254cda6..88405cb0832ae88e48f2770e5d8af797d519a346 100644 (file)
@@ -216,5 +216,5 @@ atomic64_add_negative (__s64 i, atomic64_t *v)
 #define smp_mb__before_atomic_inc()    barrier()
 #define smp_mb__after_atomic_inc()     barrier()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* _ASM_IA64_ATOMIC_H */
diff --git a/arch/ia64/include/asm/bitsperlong.h b/arch/ia64/include/asm/bitsperlong.h
new file mode 100644 (file)
index 0000000..ec4db3c
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __ASM_IA64_BITSPERLONG_H
+#define __ASM_IA64_BITSPERLONG_H
+
+#define __BITS_PER_LONG 64
+
+#include <asm-generic/bitsperlong.h>
+
+#endif /* __ASM_IA64_BITSPERLONG_H */
index c73b87832a1e56a3b9cae408ed0d6f2f504e8195..48cf8b98a0b47bbb5eb4ff2c58ea837c6e56e623 100644 (file)
@@ -8,7 +8,7 @@
  *     David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co
  */
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 #define MAP_GROWSDOWN  0x00100         /* stack-like segment */
 #define MAP_GROWSUP    0x00200         /* register stack-like segment */
index 4f5ca5643cb12553430f9b013e0096695567582e..b166248d49a46b884b425dd530b4dd5fd0d96ad9 100644 (file)
 
 #endif /* __KERNEL__ */
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 # ifndef __ASSEMBLY__
 
diff --git a/arch/ia64/include/asm/suspend.h b/arch/ia64/include/asm/suspend.h
deleted file mode 100644 (file)
index b05bbb6..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/* dummy (must be non-empty to prevent prejudicial removal...) */
index e36b3716e71851493137eddc7a04702f4bc578d5..fbf1ed3b44ced9ea3701fd59c38d1b61957adca7 100644 (file)
 # define __IA64_UL(x)          (x)
 # define __IA64_UL_CONST(x)    x
 
-# ifdef __KERNEL__
-#  define BITS_PER_LONG 64
-# endif
-
 #else
 # define __IA64_UL(x)          ((unsigned long)(x))
 # define __IA64_UL_CONST(x)    x##UL
@@ -34,10 +30,7 @@ typedef unsigned int umode_t;
  */
 # ifdef __KERNEL__
 
-#define BITS_PER_LONG 64
-
 /* DMA addresses are 64-bits wide, in general.  */
-
 typedef u64 dma_addr_t;
 
 # endif /* __KERNEL__ */
index 71c50dd8f8706da65a0362dc2ee8e15888c42060..e95d5ad9285dab575aa10f70e398c1c8368e0316 100644 (file)
@@ -53,6 +53,32 @@ void sort_extable (struct exception_table_entry *start,
             cmp_ex, swap_ex);
 }
 
+static inline unsigned long ex_to_addr(const struct exception_table_entry *x)
+{
+       return (unsigned long)&x->insn + x->insn;
+}
+
+#ifdef CONFIG_MODULES
+/*
+ * Any entry referring to the module init will be at the beginning or
+ * the end.
+ */
+void trim_init_extable(struct module *m)
+{
+       /*trim the beginning*/
+       while (m->num_exentries &&
+              within_module_init(ex_to_addr(&m->extable[0]), m)) {
+               m->extable++;
+               m->num_exentries--;
+       }
+       /*trim the end*/
+       while (m->num_exentries &&
+              within_module_init(ex_to_addr(&m->extable[m->num_exentries-1]),
+                                 m))
+               m->num_exentries--;
+}
+#endif /* CONFIG_MODULES */
+
 const struct exception_table_entry *
 search_extable (const struct exception_table_entry *first,
                const struct exception_table_entry *last,
index 2eed30f84080c66d3c102338cbb38bc70461cbc9..63f0cf0f50dde3949725305e42fa6472971c6f45 100644 (file)
@@ -314,5 +314,5 @@ static __inline__ void atomic_set_mask(unsigned long  mask, atomic_t *addr)
 #define smp_mb__before_atomic_inc()    barrier()
 #define smp_mb__after_atomic_inc()     barrier()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* _ASM_M32R_ATOMIC_H */
diff --git a/arch/m32r/include/asm/bitsperlong.h b/arch/m32r/include/asm/bitsperlong.h
new file mode 100644 (file)
index 0000000..6dc0bb0
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/bitsperlong.h>
index 516a8973b1302c177643915c35ee248f5631e987..04a5f40aa401c988b9799e7362c99db07f2189e5 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __M32R_MMAN_H__
 #define __M32R_MMAN_H__
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 #define MAP_GROWSDOWN  0x0100          /* stack-like segment */
 #define MAP_DENYWRITE  0x0800          /* ETXTBSY */
index c9333089fe111e5b0e4878bb4c6cd063d6b9271f..11777f7a5628e7a7324f298ba41cfb01aa10118d 100644 (file)
@@ -82,6 +82,6 @@ typedef struct page *pgtable_t;
 #define devmem_is_allowed(x) 1
 
 #include <asm-generic/memory_model.h>
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* _ASM_M32R_PAGE_H */
index fe785d167db6142d2af839368874bca5665254ec..07d3834c6dec106645851972be2c171917e1694a 100644 (file)
@@ -3,6 +3,4 @@
 
 #include <asm-generic/pci.h>
 
-#define PCI_DMA_BUS_IS_PHYS    (1)
-
 #endif /* _ASM_M32R_PCI_H */
index 1a607066bc645ce0a6767702640438930402ebd3..9c1acb2b1a928984c8f62ce4a5cd91a25329dc21 100644 (file)
@@ -107,7 +107,7 @@ typedef unsigned long sigset_t;
 #define MINSIGSTKSZ    2048
 #define SIGSTKSZ       8192
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
index 8d4205794380f93612f9dc62974e8895427f5912..cb5f37d78d490889c0fc80e747d54d35c97c263a 100644 (file)
@@ -44,8 +44,6 @@ void *module_alloc(unsigned long size)
 void module_free(struct module *mod, void *module_region)
 {
        vfree(module_region);
-       /* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
 }
 
 /* We don't need anything special. */
index eb0ab9d4ee77e8f083a6861c7fdbfa1798f37f0b..88b7af20a9960c59f42258d017fe6b16ef79b5ce 100644 (file)
@@ -192,5 +192,5 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
 #define smp_mb__before_atomic_inc()    barrier()
 #define smp_mb__after_atomic_inc()     barrier()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* __ARCH_M68K_ATOMIC __ */
index 6bb674855a3f57867ddd6d829eb8ca3e953f9bc9..5674cb9449bd81278fa67e319a0b66abca0efd39 100644 (file)
@@ -151,5 +151,5 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
 #define atomic_dec_return(v) atomic_sub_return(1,(v))
 #define atomic_inc_return(v) atomic_add_return(1,(v))
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* __ARCH_M68KNOMMU_ATOMIC __ */
diff --git a/arch/m68k/include/asm/bitsperlong.h b/arch/m68k/include/asm/bitsperlong.h
new file mode 100644 (file)
index 0000000..6dc0bb0
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/bitsperlong.h>
index 1626d37f48980c1fce8179051790323b557c5a70..9f5c4c4b3c7b20d37a4184e6d76a6888358d4510 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __M68K_MMAN_H__
 #define __M68K_MMAN_H__
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 #define MAP_GROWSDOWN  0x0100          /* stack-like segment */
 #define MAP_DENYWRITE  0x0800          /* ETXTBSY */
index a34b8bad784703b1597c5e15e5f655e3a05a7a3e..d009f3ea39abdaf133e06b122a86e4053b44636f 100644 (file)
@@ -223,6 +223,6 @@ static inline __attribute_const__ int __virt_to_node_shift(void)
 #define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
                                 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* _M68K_PAGE_H */
index 3a1ede4544cba4815e357a23daafbb07189f59f1..9aa3f90f4855b85ade95e2977cf9422e397d32f6 100644 (file)
@@ -72,6 +72,6 @@ extern unsigned long memory_end;
 
 #endif /* __ASSEMBLY__ */
 
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* _M68KNOMMU_PAGE_H */
index 08788fdefde0c66cb330145fd95b319131330c4b..5bc09c787a1175a05850bac9fec1d739e192bb3e 100644 (file)
@@ -103,7 +103,7 @@ typedef unsigned long sigset_t;
 #define MINSIGSTKSZ    2048
 #define SIGSTKSZ       8192
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
diff --git a/arch/m68k/include/asm/suspend.h b/arch/m68k/include/asm/suspend.h
deleted file mode 100644 (file)
index 57b3ddb..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _M68K_SUSPEND_H
-#define _M68K_SUSPEND_H
-
-/* Dummy include. */
-
-#endif  /* _M68K_SUSPEND_H */
index 774862bc6977297c0099c4bdfa96980820dcf1df..cd6bcb1c957e925c55583a0249961f09e395b74d 100644 (file)
@@ -31,8 +31,6 @@ void *module_alloc(unsigned long size)
 void module_free(struct module *mod, void *module_region)
 {
        vfree(module_region);
-       /* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
 }
 
 /* We don't need anything special. */
index 3b1a2ff61ddcf18846fc108859e964a6d28110fd..d11ffae7956a5d31fbbc02251aff1fff073f3b0a 100644 (file)
@@ -23,8 +23,6 @@ void *module_alloc(unsigned long size)
 void module_free(struct module *mod, void *module_region)
 {
        vfree(module_region);
-       /* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
 }
 
 /* We don't need anything special. */
index 8cc312b5d4dce12b0f591bb9b1063b7b33827bd0..b50b845fdd506d6f6e914038794a854769301bfc 100644 (file)
@@ -6,6 +6,7 @@ mainmenu "Linux/Microblaze Kernel Configuration"
 config MICROBLAZE
        def_bool y
        select HAVE_LMB
+       select ARCH_WANT_OPTIONAL_GPIOLIB
 
 config SWAP
        def_bool n
@@ -49,13 +50,14 @@ config GENERIC_CLOCKEVENTS
 config GENERIC_HARDIRQS_NO__DO_IRQ
        def_bool y
 
+config GENERIC_GPIO
+       def_bool y
+
 config PCI
-       depends on !MMU
        def_bool n
 
 config NO_DMA
-       depends on !MMU
-       def_bool n
+       def_bool y
 
 source "init/Kconfig"
 
@@ -72,7 +74,8 @@ source "kernel/Kconfig.preempt"
 source "kernel/Kconfig.hz"
 
 config MMU
-       def_bool n
+       bool "MMU support"
+       default n
 
 config NO_MMU
        bool
@@ -105,9 +108,6 @@ config CMDLINE_FORCE
 config OF
        def_bool y
 
-config OF_DEVICE
-       def_bool y
-
 config PROC_DEVICETREE
        bool "Support for device tree in /proc"
        depends on PROC_FS
@@ -118,6 +118,113 @@ config PROC_DEVICETREE
 
 endmenu
 
+menu "Advanced setup"
+
+config ADVANCED_OPTIONS
+       bool "Prompt for advanced kernel configuration options"
+       depends on MMU
+       help
+         This option will enable prompting for a variety of advanced kernel
+         configuration options.  These options can cause the kernel to not
+         work if they are set incorrectly, but can be used to optimize certain
+         aspects of kernel memory management.
+
+         Unless you know what you are doing, say N here.
+
+comment "Default settings for advanced configuration options are used"
+       depends on !ADVANCED_OPTIONS
+
+config HIGHMEM_START_BOOL
+       bool "Set high memory pool address"
+       depends on ADVANCED_OPTIONS && HIGHMEM
+       help
+         This option allows you to set the base address of the kernel virtual
+         area used to map high memory pages.  This can be useful in
+         optimizing the layout of kernel virtual memory.
+
+         Say N here unless you know what you are doing.
+
+config HIGHMEM_START
+       hex "Virtual start address of high memory pool" if HIGHMEM_START_BOOL
+       depends on MMU
+       default "0xfe000000"
+
+config LOWMEM_SIZE_BOOL
+       bool "Set maximum low memory"
+       depends on ADVANCED_OPTIONS
+       help
+         This option allows you to set the maximum amount of memory which
+         will be used as "low memory", that is, memory which the kernel can
+         access directly, without having to set up a kernel virtual mapping.
+         This can be useful in optimizing the layout of kernel virtual
+         memory.
+
+         Say N here unless you know what you are doing.
+
+config LOWMEM_SIZE
+       hex "Maximum low memory size (in bytes)" if LOWMEM_SIZE_BOOL
+       depends on MMU
+       default "0x30000000"
+
+config KERNEL_START_BOOL
+       bool "Set custom kernel base address"
+       depends on ADVANCED_OPTIONS
+       help
+         This option allows you to set the kernel virtual address at which
+         the kernel will map low memory (the kernel image will be linked at
+         this address).  This can be useful in optimizing the virtual memory
+         layout of the system.
+
+         Say N here unless you know what you are doing.
+
+config KERNEL_START
+       hex "Virtual address of kernel base" if KERNEL_START_BOOL
+       default "0xc0000000" if MMU
+       default KERNEL_BASE_ADDR if !MMU
+
+config TASK_SIZE_BOOL
+       bool "Set custom user task size"
+       depends on ADVANCED_OPTIONS
+       help
+         This option allows you to set the amount of virtual address space
+         allocated to user tasks.  This can be useful in optimizing the
+         virtual memory layout of the system.
+
+         Say N here unless you know what you are doing.
+
+config TASK_SIZE
+       hex "Size of user task space" if TASK_SIZE_BOOL
+       depends on MMU
+       default "0x80000000"
+
+config CONSISTENT_START_BOOL
+       bool "Set custom consistent memory pool address"
+       depends on ADVANCED_OPTIONS && NOT_COHERENT_CACHE
+       help
+         This option allows you to set the base virtual address
+         of the the consistent memory pool.  This pool of virtual
+         memory is used to make consistent memory allocations.
+
+config CONSISTENT_START
+       hex "Base virtual address of consistent memory pool" if CONSISTENT_START_BOOL
+       depends on MMU
+       default "0xff100000" if NOT_COHERENT_CACHE
+
+config CONSISTENT_SIZE_BOOL
+       bool "Set custom consistent memory pool size"
+       depends on ADVANCED_OPTIONS && NOT_COHERENT_CACHE
+       help
+         This option allows you to set the size of the the
+         consistent memory pool.  This pool of virtual memory
+         is used to make consistent memory allocations.
+
+config CONSISTENT_SIZE
+       hex "Size of consistent memory pool" if CONSISTENT_SIZE_BOOL
+       depends on MMU
+       default "0x00200000" if NOT_COHERENT_CACHE
+
+endmenu
+
 source "mm/Kconfig"
 
 menu "Exectuable file formats"
index aaadfa701da30b82475583bde4db5c3bea9cc116..d0bcf80a113659d2b3da42e9cd0e7c4c58f701a9 100644 (file)
@@ -1,4 +1,8 @@
+ifeq ($(CONFIG_MMU),y)
+UTS_SYSNAME = -DUTS_SYSNAME=\"Linux\"
+else
 UTS_SYSNAME = -DUTS_SYSNAME=\"uClinux\"
+endif
 
 # What CPU vesion are we building for, and crack it open
 # as major.minor.rev
@@ -36,6 +40,8 @@ CPUFLAGS-1 += $(call cc-option,-mcpu=v$(CPU_VER))
 # r31 holds current when in kernel mode
 CFLAGS_KERNEL += -ffixed-r31 $(CPUFLAGS-1) $(CPUFLAGS-2)
 
+LDFLAGS                :=
+LDFLAGS_vmlinux        :=
 LDFLAGS_BLOB := --format binary --oformat elf32-microblaze
 
 LIBGCC := $(shell $(CC) $(CFLAGS_KERNEL) -print-libgcc-file-name)
index 844edf406d34cb6b901fdc807c02e371bb1148a5..c2bb043a029d2df7891d17ae6e92e46e0360657b 100644 (file)
@@ -7,6 +7,8 @@ targets := linux.bin linux.bin.gz
 OBJCOPYFLAGS_linux.bin  := -O binary
 
 $(obj)/linux.bin: vmlinux FORCE
+       [ -n $(CONFIG_INITRAMFS_SOURCE) ] && [ ! -e $(CONFIG_INITRAMFS_SOURCE) ] && \
+       touch $(CONFIG_INITRAMFS_SOURCE) || echo "No CPIO image"
        $(call if_changed,objcopy)
        @echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
 
diff --git a/arch/microblaze/configs/mmu_defconfig b/arch/microblaze/configs/mmu_defconfig
new file mode 100644 (file)
index 0000000..bd0b85e
--- /dev/null
@@ -0,0 +1,798 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.30-rc6
+# Fri May 22 10:02:33 2009
+#
+CONFIG_MICROBLAZE=y
+# CONFIG_SWAP is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_TIME=y
+# CONFIG_GENERIC_TIME_VSYSCALL is not set
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=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_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU 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=17
+# CONFIG_GROUP_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="rootfs.cpio"
+CONFIG_INITRAMFS_ROOT_UID=0
+CONFIG_INITRAMFS_ROOT_GID=0
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+CONFIG_INITRAMFS_COMPRESSION_NONE=y
+# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
+# CONFIG_INITRAMFS_COMPRESSION_BZIP2 is not set
+# CONFIG_INITRAMFS_COMPRESSION_LZMA is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_KALLSYMS_EXTRA_PASS=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+# CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+# CONFIG_SHMEM is not set
+CONFIG_AIO=y
+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_MARKERS is not set
+# CONFIG_SLOW_WORK is not set
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_BASE_SMALL=1
+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_LBD 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
+
+#
+# Platform options
+#
+CONFIG_PLATFORM_GENERIC=y
+CONFIG_OPT_LIB_FUNCTION=y
+CONFIG_OPT_LIB_ASM=y
+CONFIG_ALLOW_EDIT_AUTO=y
+
+#
+# Automatic platform settings from Kconfig.auto
+#
+
+#
+# Definitions for MICROBLAZE0
+#
+CONFIG_KERNEL_BASE_ADDR=0x90000000
+CONFIG_XILINX_MICROBLAZE0_FAMILY="virtex5"
+CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR=1
+CONFIG_XILINX_MICROBLAZE0_USE_PCMP_INSTR=1
+CONFIG_XILINX_MICROBLAZE0_USE_BARREL=1
+CONFIG_XILINX_MICROBLAZE0_USE_DIV=1
+CONFIG_XILINX_MICROBLAZE0_USE_HW_MUL=2
+CONFIG_XILINX_MICROBLAZE0_USE_FPU=2
+CONFIG_XILINX_MICROBLAZE0_HW_VER="7.10.d"
+
+#
+# Processor type and features
+#
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
+# CONFIG_SCHED_HRTICK is not set
+CONFIG_MMU=y
+
+#
+# Boot options
+#
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyUL0,115200"
+CONFIG_CMDLINE_FORCE=y
+CONFIG_OF=y
+CONFIG_PROC_DEVICETREE=y
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+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_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+
+#
+# Exectuable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+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 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 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_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_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_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# 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_OF_DEVICE=y
+# 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_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_XILINX_SYSACE 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
+
+#
+# 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_COMPAT_NET_DEV_OPS=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 is not set
+# CONFIG_ETHOC 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_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# 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 is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_UARTLITE=y
+CONFIG_SERIAL_UARTLITE_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_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_XILINX_HWICAP 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
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+# CONFIG_GPIOLIB 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_THERMAL_HWMON 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_REGULATOR 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
+
+#
+# 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
+# CONFIG_SOUND 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_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO 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_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+# 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_KCORE is not set
+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_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 is not set
+# 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=y
+CONFIG_CIFS_STATS=y
+CONFIG_CIFS_STATS2=y
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_EXPERIMENTAL 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 is not set
+# 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 is not set
+# 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 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=y
+# CONFIG_DEBUG_SLAB_LEAK is not set
+CONFIG_DEBUG_SPINLOCK=y
+# CONFIG_DEBUG_MUTEXES 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_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_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_FAULT_INJECTION is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+# CONFIG_PAGE_POISONING is not set
+# CONFIG_SAMPLES is not set
+CONFIG_EARLY_PRINTK=y
+CONFIG_HEART_BEAT=y
+CONFIG_DEBUG_BOOTMEM=y
+
+#
+# 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_FIPS is not set
+# 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
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C 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 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 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_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
+CONFIG_NLATTR=y
index 31820dfef56b6a1a69e8b03740f4f2aa59717098..db5294c30cafef1d2cbb8f83b787edb36f812613 100644 (file)
@@ -1,26 +1,3 @@
 include include/asm-generic/Kbuild.asm
 
-header-y += auxvec.h
-header-y += errno.h
-header-y += fcntl.h
-header-y += ioctl.h
-header-y += ioctls.h
-header-y += ipcbuf.h
-header-y += linkage.h
-header-y += msgbuf.h
-header-y += poll.h
-header-y += resource.h
-header-y += sembuf.h
-header-y += shmbuf.h
-header-y += sigcontext.h
-header-y += siginfo.h
-header-y += socket.h
-header-y += sockios.h
-header-y += statfs.h
-header-y += stat.h
-header-y += termbits.h
-header-y += ucontext.h
-
-unifdef-y += cputable.h
-unifdef-y += elf.h
-unifdef-y += termios.h
+header-y  += elf.h
index a448d94ab721802f4d196b72b20fd0b45c52a8df..0de612ad7cb2e5b2ca2ef8f98b4616768ab8d6c2 100644 (file)
@@ -118,6 +118,6 @@ static inline int atomic_dec_if_positive(atomic_t *v)
 #define smp_mb__before_atomic_inc()    barrier()
 #define smp_mb__after_atomic_inc()     barrier()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 
 #endif /* _ASM_MICROBLAZE_ATOMIC_H */
diff --git a/arch/microblaze/include/asm/bitsperlong.h b/arch/microblaze/include/asm/bitsperlong.h
new file mode 100644 (file)
index 0000000..6dc0bb0
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/bitsperlong.h>
index 3300b785049bb8a6bb218ae6496c507c788bdb1e..f989d6aad6482b30f4e8bc3fa33c57a3c67b52b6 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) 2007 PetaLogix
+ * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2007-2009 PetaLogix
  * Copyright (C) 2007 John Williams <john.williams@petalogix.com>
  * based on v850 version which was
  * Copyright (C) 2001,02,03 NEC Electronics Corporation
 #define flush_icache_range(start, len) __invalidate_icache_range(start, len)
 #define flush_icache_page(vma, pg)             do { } while (0)
 
+#ifndef CONFIG_MMU
+# define flush_icache_user_range(start, len)   do { } while (0)
+#else
+# define flush_icache_user_range(vma, pg, adr, len) __invalidate_icache_all()
+
+# define flush_page_to_ram(page)               do { } while (0)
+
+# define flush_icache()                        __invalidate_icache_all()
+# define flush_cache_sigtramp(vaddr) \
+                       __invalidate_icache_range(vaddr, vaddr + 8)
+
+# define flush_dcache_mmap_lock(mapping)       do { } while (0)
+# define flush_dcache_mmap_unlock(mapping)     do { } while (0)
+
+# define flush_cache_dup_mm(mm)                        do { } while (0)
+#endif
+
 #define flush_cache_vmap(start, end)           do { } while (0)
 #define flush_cache_vunmap(start, end)         do { } while (0)
 
index 92b30762ce59a2e4cf115f65bb8816ba1531c4d2..97ea46b5cf80a2a1071b5b89dc9a85cb2e8e3f28 100644 (file)
@@ -51,7 +51,8 @@ extern __wsum csum_partial(const void *buff, int len, __wsum sum);
  * here even more important to align src and dst on a 32-bit (or even
  * better 64-bit) boundary
  */
-extern __wsum csum_partial_copy(const char *src, char *dst, int len, int sum);
+extern __wsum csum_partial_copy(const void *src, void *dst, int len,
+                                                               __wsum sum);
 
 /*
  * the same as csum_partial_copy, but copies from user space.
@@ -59,8 +60,8 @@ extern __wsum csum_partial_copy(const char *src, char *dst, int len, int sum);
  * here even more important to align src and dst on a 32-bit (or even
  * better 64-bit) boundary
  */
-extern __wsum csum_partial_copy_from_user(const char *src, char *dst,
-                                       int len, int sum, int *csum_err);
+extern __wsum csum_partial_copy_from_user(const void __user *src, void *dst,
+                                       int len, __wsum sum, int *csum_err);
 
 #define csum_partial_copy_nocheck(src, dst, len, sum)  \
        csum_partial_copy((src), (dst), (len), (sum))
@@ -75,11 +76,12 @@ extern __sum16 ip_fast_csum(const void *iph, unsigned int ihl);
 /*
  *     Fold a partial checksum
  */
-static inline __sum16 csum_fold(unsigned int sum)
+static inline __sum16 csum_fold(__wsum csum)
 {
+       u32 sum = (__force u32)csum;
        sum = (sum & 0xffff) + (sum >> 16);
        sum = (sum & 0xffff) + (sum >> 16);
-       return ~sum;
+       return (__force __sum16)~sum;
 }
 
 static inline __sum16
@@ -93,6 +95,6 @@ csum_tcpudp_magic(__be32 saddr, __be32 daddr, unsigned short len,
  * this routine is used for miscellaneous IP-like checksums, mainly
  * in icmp.c
  */
-extern __sum16 ip_compute_csum(const unsigned char *buff, int len);
+extern __sum16 ip_compute_csum(const void *buff, int len);
 
 #endif /* _ASM_MICROBLAZE_CHECKSUM_H */
index 8375ea991e2633900c16d3c63094b4eee5249041..29303ed825cce591770d93e6fb9d7912e4022e42 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -9,6 +11,12 @@
 #ifndef _ASM_MICROBLAZE_CURRENT_H
 #define _ASM_MICROBLAZE_CURRENT_H
 
+/*
+ * Register used to hold the current task pointer while in the kernel.
+ * Any `call clobbered' register without a special meaning should be OK,
+ * but check asm/microblaze/kernel/entry.S to be sure.
+ */
+#define CURRENT_TASK   r31
 # ifndef __ASSEMBLY__
 /*
  * Dedicate r31 to keeping the current task pointer
index 17336252a9b827932be864ba051c46603a8f8f7c..d00e40099165b7075ef8efd35df050f06246fce2 100644 (file)
@@ -1,129 +1 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_DMA_MAPPING_H
-#define _ASM_MICROBLAZE_DMA_MAPPING_H
-
-#include <asm/cacheflush.h>
-#include <linux/io.h>
-#include <linux/bug.h>
-
-struct scatterlist;
-
-#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
-#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
-
-/* FIXME */
-static inline int
-dma_supported(struct device *dev, u64 mask)
-{
-       return 1;
-}
-
-static inline dma_addr_t
-dma_map_page(struct device *dev, struct page *page,
-       unsigned long offset, size_t size,
-       enum dma_data_direction direction)
-{
-       BUG();
-       return 0;
-}
-
-static inline void
-dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
-       enum dma_data_direction direction)
-{
-       BUG();
-}
-
-static inline int
-dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-       enum dma_data_direction direction)
-{
-       BUG();
-       return 0;
-}
-
-static inline void
-dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
-       enum dma_data_direction direction)
-{
-       BUG();
-}
-
-static inline void
-dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
-                       enum dma_data_direction direction)
-{
-       BUG();
-}
-
-static inline void
-dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
-               size_t size, enum dma_data_direction direction)
-{
-       BUG();
-}
-
-static inline void
-dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
-               enum dma_data_direction direction)
-{
-       BUG();
-}
-
-static inline void
-dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
-               enum dma_data_direction direction)
-{
-       BUG();
-}
-
-static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
-{
-       return 0;
-}
-
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
-                               dma_addr_t *dma_handle, int flag)
-{
-       return NULL; /* consistent_alloc(flag, size, dma_handle); */
-}
-
-static inline void dma_free_coherent(struct device *dev, size_t size,
-                       void *vaddr, dma_addr_t dma_handle)
-{
-       BUG();
-}
-
-static inline dma_addr_t
-dma_map_single(struct device *dev, void *ptr, size_t size,
-       enum dma_data_direction direction)
-{
-       BUG_ON(direction == DMA_NONE);
-
-       return virt_to_bus(ptr);
-}
-
-static inline void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
-                                   size_t size,
-                                   enum dma_data_direction direction)
-{
-       switch (direction) {
-       case DMA_FROM_DEVICE:
-               flush_dcache_range((unsigned)dma_addr,
-                       (unsigned)dma_addr + size);
-                       /* Fall through */
-       case DMA_TO_DEVICE:
-               break;
-       default:
-               BUG();
-       }
-}
-
-#endif /* _ASM_MICROBLAZE_DMA_MAPPING_H */
+#include <asm-generic/dma-mapping-broken.h>
index 0967fa04fc5eb4e95338bf9e8f2d7a92ab90f8f8..08c073badf198f3296b384742b98a31a1ab9b408 100644 (file)
@@ -9,8 +9,13 @@
 #ifndef _ASM_MICROBLAZE_DMA_H
 #define _ASM_MICROBLAZE_DMA_H
 
+#ifndef CONFIG_MMU
 /* we don't have dma address limit. define it as zero to be
  * unlimited. */
 #define MAX_DMA_ADDRESS                (0)
+#else
+/* Virtual address corresponding to last available physical memory address.  */
+#define MAX_DMA_ADDRESS (CONFIG_KERNEL_START + memory_size - 1)
+#endif
 
 #endif /* _ASM_MICROBLAZE_DMA_H */
index 81337f241347a15ad53f165a95876e0bb2d48054..f92fc0dda006d40b886d36b947bb3891cb83656a 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
  */
 #define ELF_CLASS      ELFCLASS32
 
+#ifndef __uClinux__
+
+/*
+ * ELF register definitions..
+ */
+
+#include <asm/ptrace.h>
+#include <asm/byteorder.h>
+
+#ifndef ELF_GREG_T
+#define ELF_GREG_T
+typedef unsigned long elf_greg_t;
+#endif
+
+#ifndef ELF_NGREG
+#define ELF_NGREG (sizeof(struct pt_regs) / sizeof(elf_greg_t))
+#endif
+
+#ifndef ELF_GREGSET_T
+#define ELF_GREGSET_T
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+#endif
+
+#ifndef ELF_FPREGSET_T
+#define ELF_FPREGSET_T
+
+/* TBD */
+#define ELF_NFPREG     33      /* includes fsr */
+typedef unsigned long elf_fpreg_t;
+typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+
+/* typedef struct user_fpu_struct elf_fpregset_t; */
+#endif
+
+/* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
+ * use of this is to invoke "./ld.so someprog" to test out a new version of
+ * the loader.  We need to make sure that it is out of the way of the program
+ * that it will "exec", and that there is sufficient room for the brk.
+ */
+
+#define ELF_ET_DYN_BASE         (0x08000000)
+
+#ifdef __LITTLE_ENDIAN__
+#define ELF_DATA       ELFDATA2LSB
+#else
+#define ELF_DATA       ELFDATA2MSB
+#endif
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE      4096
+
+
+#define ELF_CORE_COPY_REGS(_dest, _regs)                       \
+       memcpy((char *) &_dest, (char *) _regs,         \
+       sizeof(struct pt_regs));
+
+/* This yields a mask that user programs can use to figure out what
+ * instruction set this CPU supports.  This could be done in user space,
+ * but it's not easy, and we've already done it here.
+ */
+#define ELF_HWCAP      (0)
+
+/* This yields a string that ld.so will use to load implementation
+ * specific libraries for optimization.  This is more specific in
+ * intent than poking at uname or /proc/cpuinfo.
+
+ * For the moment, we have only optimizations for the Intel generations,
+ * but that could change...
+ */
+#define ELF_PLATFORM  (NULL)
+
+/* Added _f parameter. Is this definition correct: TBD */
+#define ELF_PLAT_INIT(_r, _f)                          \
+do {                                                   \
+       _r->r1 =  _r->r1 =  _r->r2 =  _r->r3 =          \
+       _r->r4 =  _r->r5 =  _r->r6 =  _r->r7 =          \
+       _r->r8 =  _r->r9 =  _r->r10 = _r->r11 =         \
+       _r->r12 = _r->r13 = _r->r14 = _r->r15 =         \
+       _r->r16 = _r->r17 = _r->r18 = _r->r19 =         \
+       _r->r20 = _r->r21 = _r->r22 = _r->r23 =         \
+       _r->r24 = _r->r25 = _r->r26 = _r->r27 =         \
+       _r->r28 = _r->r29 = _r->r30 = _r->r31 =         \
+       0;                                              \
+} while (0)
+
+#ifdef __KERNEL__
+#define SET_PERSONALITY(ex) set_personality(PER_LINUX_32BIT)
+#endif
+
+#endif /* __uClinux__ */
+
 #endif /* _ASM_MICROBLAZE_ELF_H */
index e4c3aef884df0dacdba060af7d6d95dd3e122460..61abbd232640ff6b99f8a9110c55e47a8f0edf84 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * Definitions used by low-level trap handlers
  *
- * Copyright (C) 2008 Michal Simek
- * Copyright (C) 2007 - 2008 PetaLogix
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2007-2009 PetaLogix
  * Copyright (C) 2007 John Williams <john.williams@petalogix.com>
  *
  * This file is subject to the terms and conditions of the GNU General
@@ -31,7 +31,40 @@ DECLARE_PER_CPU(unsigned int, R11_SAVE); /* Temp variable for entry */
 DECLARE_PER_CPU(unsigned int, CURRENT_SAVE); /* Saved current pointer */
 # endif /* __ASSEMBLY__ */
 
+#ifndef CONFIG_MMU
+
 /* noMMU hasn't any space for args */
 # define STATE_SAVE_ARG_SPACE  (0)
 
+#else /* CONFIG_MMU */
+
+/* If true, system calls save and restore all registers (except result
+ * registers, of course).  If false, then `call clobbered' registers
+ * will not be preserved, on the theory that system calls are basically
+ * function calls anyway, and the caller should be able to deal with it.
+ * This is a security risk, of course, as `internal' values may leak out
+ * after a system call, but that certainly doesn't matter very much for
+ * a processor with no MMU protection!  For a protected-mode kernel, it
+ * would be faster to just zero those registers before returning.
+ *
+ * I can not rely on the glibc implementation. If you turn it off make
+ * sure that r11/r12 is saved in user-space. --KAA
+ *
+ * These are special variables using by the kernel trap/interrupt code
+ * to save registers in, at a time when there are no spare registers we
+ * can use to do so, and we can't depend on the value of the stack
+ * pointer.  This means that they must be within a signed 16-bit
+ * displacement of 0x00000000.
+ */
+
+/* A `state save frame' is a struct pt_regs preceded by some extra space
+ * suitable for a function call stack frame. */
+
+/* Amount of room on the stack reserved for arguments and to satisfy the
+ * C calling conventions, in addition to the space used by the struct
+ * pt_regs that actually holds saved values. */
+#define STATE_SAVE_ARG_SPACE   (6*4) /* Up to six arguments */
+
+#endif /* CONFIG_MMU */
+
 #endif /* _ASM_MICROBLAZE_ENTRY_H */
index 24ca540e77c043dc45e6dba1d389b18a4a441dfb..90731df9e574c30bd8684272be6f11250147997c 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * Preliminary support for HW exception handing for Microblaze
  *
- * Copyright (C) 2008 Michal Simek
- * Copyright (C) 2008 PetaLogix
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2005 John Williams <jwilliams@itee.uq.edu.au>
  *
  * This file is subject to the terms and conditions of the GNU General
@@ -64,21 +64,13 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
 void die(const char *str, struct pt_regs *fp, long err);
 void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr);
 
-#if defined(CONFIG_XMON)
-extern void xmon(struct pt_regs *regs);
-extern int xmon_bpt(struct pt_regs *regs);
-extern int xmon_sstep(struct pt_regs *regs);
-extern int xmon_iabr_match(struct pt_regs *regs);
-extern int xmon_dabr_match(struct pt_regs *regs);
-extern void (*xmon_fault_handler)(struct pt_regs *regs);
+#ifdef CONFIG_MMU
+void __bug(const char *file, int line, void *data);
+int bad_trap(int trap_num, struct pt_regs *regs);
+int debug_trap(struct pt_regs *regs);
+#endif /* CONFIG_MMU */
 
-void (*debugger)(struct pt_regs *regs) = xmon;
-int (*debugger_bpt)(struct pt_regs *regs) = xmon_bpt;
-int (*debugger_sstep)(struct pt_regs *regs) = xmon_sstep;
-int (*debugger_iabr_match)(struct pt_regs *regs) = xmon_iabr_match;
-int (*debugger_dabr_match)(struct pt_regs *regs) = xmon_dabr_match;
-void (*debugger_fault_handler)(struct pt_regs *regs);
-#elif defined(CONFIG_KGDB)
+#if defined(CONFIG_KGDB)
 void (*debugger)(struct pt_regs *regs);
 int (*debugger_bpt)(struct pt_regs *regs);
 int (*debugger_sstep)(struct pt_regs *regs);
index acf0da543ef140d2dbccc1fe610e8720a48e5939..6847c1512c7baf17f6f58a000566e79631ce3db8 100644 (file)
@@ -13,7 +13,6 @@
 
 #include <asm/unaligned.h>
 
-#define        flat_stack_align(sp) /* nothing needed */
 #define        flat_argvp_envp_on_stack()      0
 #define        flat_old_ram_flag(flags)        (flags)
 #define        flat_reloc_valid(reloc, size)   ((reloc) <= (size))
index ea04632399d8d25f8cf5e4f4720c28bd7dbbaef9..2345ac354d9be3b865e0477c206b46630bca50a1 100644 (file)
@@ -11,8 +11,8 @@
  * (at your option) any later version.
  */
 
-#ifndef __ASM_POWERPC_GPIO_H
-#define __ASM_POWERPC_GPIO_H
+#ifndef _ASM_MICROBLAZE_GPIO_H
+#define _ASM_MICROBLAZE_GPIO_H
 
 #include <linux/errno.h>
 #include <asm-generic/gpio.h>
@@ -53,4 +53,4 @@ static inline int irq_to_gpio(unsigned int irq)
 
 #endif /* CONFIG_GPIOLIB */
 
-#endif /* __ASM_POWERPC_GPIO_H */
+#endif /* _ASM_MICROBLAZE_GPIO_H */
index 8b5853ee6b5c8a9dec3fae1b320a02461e658d27..5c173424d0744bdd6cfdda945e57985adff9060c 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2007-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -12,6 +14,9 @@
 #include <asm/byteorder.h>
 #include <asm/page.h>
 #include <linux/types.h>
+#include <asm/byteorder.h>
+#include <linux/mm.h>          /* Get struct page {...} */
+
 
 #define IO_SPACE_LIMIT (0xFFFFFFFF)
 
@@ -112,6 +117,30 @@ static inline void writel(unsigned int v, volatile void __iomem *addr)
 #define memcpy_fromio(a, b, c) memcpy((a), (void *)(b), (c))
 #define memcpy_toio(a, b, c)   memcpy((void *)(a), (b), (c))
 
+#ifdef CONFIG_MMU
+
+#define mm_ptov(addr)          ((void *)__phys_to_virt(addr))
+#define mm_vtop(addr)          ((unsigned long)__virt_to_phys(addr))
+#define phys_to_virt(addr)     ((void *)__phys_to_virt(addr))
+#define virt_to_phys(addr)     ((unsigned long)__virt_to_phys(addr))
+#define virt_to_bus(addr)      ((unsigned long)__virt_to_phys(addr))
+
+#define __page_address(page) \
+               (PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT))
+#define page_to_phys(page)     virt_to_phys((void *)__page_address(page))
+#define page_to_bus(page)      (page_to_phys(page))
+#define bus_to_virt(addr)      (phys_to_virt(addr))
+
+extern void iounmap(void *addr);
+/*extern void *__ioremap(phys_addr_t address, unsigned long size,
+               unsigned long flags);*/
+extern void __iomem *ioremap(phys_addr_t address, unsigned long size);
+#define ioremap_writethrough(addr, size) ioremap((addr), (size))
+#define ioremap_nocache(addr, size)      ioremap((addr), (size))
+#define ioremap_fullcache(addr, size)    ioremap((addr), (size))
+
+#else /* CONFIG_MMU */
+
 /**
  *     virt_to_phys - map virtual addresses to physical
  *     @address: address to remap
@@ -160,6 +189,8 @@ static inline void __iomem *__ioremap(phys_addr_t address, unsigned long size,
 #define iounmap(addr)          ((void)0)
 #define ioremap_nocache(physaddr, size)        ioremap(physaddr, size)
 
+#endif /* CONFIG_MMU */
+
 /*
  * Convert a physical pointer to a virtual kernel pointer for /dev/mem
  * access
index 0e0431d61635ae2dcbe02c93fe390ea0152eb5bd..66cad6a99d77b41a8c5b50f140de1c3daf356121 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
 #ifndef _ASM_MICROBLAZE_MMU_H
 #define _ASM_MICROBLAZE_MMU_H
 
-#ifndef __ASSEMBLY__
+# ifndef CONFIG_MMU
+#  ifndef __ASSEMBLY__
 typedef struct {
        struct vm_list_struct   *vmlist;
        unsigned long           end_brk;
 } mm_context_t;
-#endif /* __ASSEMBLY__ */
+#  endif /* __ASSEMBLY__ */
+# else /* CONFIG_MMU */
+#  ifdef __KERNEL__
+#   ifndef __ASSEMBLY__
 
+/* Default "unsigned long" context */
+typedef unsigned long mm_context_t;
+
+/* Hardware Page Table Entry */
+typedef struct _PTE {
+       unsigned long    v:1;   /* Entry is valid */
+       unsigned long vsid:24;  /* Virtual segment identifier */
+       unsigned long    h:1;   /* Hash algorithm indicator */
+       unsigned long  api:6;   /* Abbreviated page index */
+       unsigned long  rpn:20;  /* Real (physical) page number */
+       unsigned long     :3;   /* Unused */
+       unsigned long    r:1;   /* Referenced */
+       unsigned long    c:1;   /* Changed */
+       unsigned long    w:1;   /* Write-thru cache mode */
+       unsigned long    i:1;   /* Cache inhibited */
+       unsigned long    m:1;   /* Memory coherence */
+       unsigned long    g:1;   /* Guarded */
+       unsigned long     :1;   /* Unused */
+       unsigned long   pp:2;   /* Page protection */
+} PTE;
+
+/* Values for PP (assumes Ks=0, Kp=1) */
+#  define PP_RWXX      0 /* Supervisor read/write, User none */
+#  define PP_RWRX      1 /* Supervisor read/write, User read */
+#  define PP_RWRW      2 /* Supervisor read/write, User read/write */
+#  define PP_RXRX      3 /* Supervisor read,       User read */
+
+/* Segment Register */
+typedef struct _SEGREG {
+       unsigned long    t:1;   /* Normal or I/O  type */
+       unsigned long   ks:1;   /* Supervisor 'key' (normally 0) */
+       unsigned long   kp:1;   /* User 'key' (normally 1) */
+       unsigned long    n:1;   /* No-execute */
+       unsigned long     :4;   /* Unused */
+       unsigned long vsid:24;  /* Virtual Segment Identifier */
+} SEGREG;
+
+extern void _tlbie(unsigned long va);  /* invalidate a TLB entry */
+extern void _tlbia(void);              /* invalidate all TLB entries */
+#   endif /* __ASSEMBLY__ */
+
+/*
+ * The MicroBlaze processor has a TLB architecture identical to PPC-40x. The
+ * instruction and data sides share a unified, 64-entry, semi-associative
+ * TLB which is maintained totally under software control. In addition, the
+ * instruction side has a hardware-managed, 2,4, or 8-entry, fully-associative
+ * TLB which serves as a first level to the shared TLB. These two TLBs are
+ * known as the UTLB and ITLB, respectively.
+ */
+
+#  define MICROBLAZE_TLB_SIZE 64
+
+/*
+ * TLB entries are defined by a "high" tag portion and a "low" data
+ * portion. The data portion is 32-bits.
+ *
+ * TLB entries are managed entirely under software control by reading,
+ * writing, and searching using the MTS and MFS instructions.
+ */
+
+#  define TLB_LO               1
+#  define TLB_HI               0
+#  define TLB_DATA             TLB_LO
+#  define TLB_TAG              TLB_HI
+
+/* Tag portion */
+#  define TLB_EPN_MASK         0xFFFFFC00 /* Effective Page Number */
+#  define TLB_PAGESZ_MASK      0x00000380
+#  define TLB_PAGESZ(x)                (((x) & 0x7) << 7)
+#  define PAGESZ_1K            0
+#  define PAGESZ_4K            1
+#  define PAGESZ_16K           2
+#  define PAGESZ_64K           3
+#  define PAGESZ_256K          4
+#  define PAGESZ_1M            5
+#  define PAGESZ_4M            6
+#  define PAGESZ_16M           7
+#  define TLB_VALID            0x00000040 /* Entry is valid */
+
+/* Data portion */
+#  define TLB_RPN_MASK         0xFFFFFC00 /* Real Page Number */
+#  define TLB_PERM_MASK                0x00000300
+#  define TLB_EX               0x00000200 /* Instruction execution allowed */
+#  define TLB_WR               0x00000100 /* Writes permitted */
+#  define TLB_ZSEL_MASK                0x000000F0
+#  define TLB_ZSEL(x)          (((x) & 0xF) << 4)
+#  define TLB_ATTR_MASK                0x0000000F
+#  define TLB_W                        0x00000008 /* Caching is write-through */
+#  define TLB_I                        0x00000004 /* Caching is inhibited */
+#  define TLB_M                        0x00000002 /* Memory is coherent */
+#  define TLB_G                        0x00000001 /* Memory is guarded from prefetch */
+
+#  endif /* __KERNEL__ */
+# endif /* CONFIG_MMU */
 #endif /* _ASM_MICROBLAZE_MMU_H */
index 150ca01b74ba160d929dc5214dc700426a388bbc..385fed16bbfb12eb04281c838037c475fb72c8fa 100644 (file)
@@ -1,21 +1,5 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_MMU_CONTEXT_H
-#define _ASM_MICROBLAZE_MMU_CONTEXT_H
-
-# define init_new_context(tsk, mm)             ({ 0; })
-
-# define enter_lazy_tlb(mm, tsk)               do {} while (0)
-# define change_mm_context(old, ctx, _pml4)    do {} while (0)
-# define destroy_context(mm)                   do {} while (0)
-# define deactivate_mm(tsk, mm)                        do {} while (0)
-# define switch_mm(prev, next, tsk)            do {} while (0)
-# define activate_mm(prev, next)               do {} while (0)
-
-#endif /* _ASM_MICROBLAZE_MMU_CONTEXT_H */
+#ifdef CONFIG_MMU
+# include "mmu_context_mm.h"
+#else
+# include "mmu_context_no.h"
+#endif
diff --git a/arch/microblaze/include/asm/mmu_context_mm.h b/arch/microblaze/include/asm/mmu_context_mm.h
new file mode 100644 (file)
index 0000000..3e5c254
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
+ * Copyright (C) 2006 Atmark Techno, Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_MICROBLAZE_MMU_CONTEXT_H
+#define _ASM_MICROBLAZE_MMU_CONTEXT_H
+
+#include <asm/atomic.h>
+#include <asm/bitops.h>
+#include <asm/mmu.h>
+#include <asm-generic/mm_hooks.h>
+
+# ifdef __KERNEL__
+/*
+ * This function defines the mapping from contexts to VSIDs (virtual
+ * segment IDs).  We use a skew on both the context and the high 4 bits
+ * of the 32-bit virtual address (the "effective segment ID") in order
+ * to spread out the entries in the MMU hash table.
+ */
+# define CTX_TO_VSID(ctx, va)  (((ctx) * (897 * 16) + ((va) >> 28) * 0x111) \
+                                & 0xffffff)
+
+/*
+   MicroBlaze has 256 contexts, so we can just rotate through these
+   as a way of "switching" contexts.  If the TID of the TLB is zero,
+   the PID/TID comparison is disabled, so we can use a TID of zero
+   to represent all kernel pages as shared among all contexts.
+ */
+
+static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+{
+}
+
+# define NO_CONTEXT    256
+# define LAST_CONTEXT  255
+# define FIRST_CONTEXT 1
+
+/*
+ * Set the current MMU context.
+ * This is done byloading up the segment registers for the user part of the
+ * address space.
+ *
+ * Since the PGD is immediately available, it is much faster to simply
+ * pass this along as a second parameter, which is required for 8xx and
+ * can be used for debugging on all processors (if you happen to have
+ * an Abatron).
+ */
+extern void set_context(mm_context_t context, pgd_t *pgd);
+
+/*
+ * Bitmap of contexts in use.
+ * The size of this bitmap is LAST_CONTEXT + 1 bits.
+ */
+extern unsigned long context_map[];
+
+/*
+ * This caches the next context number that we expect to be free.
+ * Its use is an optimization only, we can't rely on this context
+ * number to be free, but it usually will be.
+ */
+extern mm_context_t next_mmu_context;
+
+/*
+ * Since we don't have sufficient contexts to give one to every task
+ * that could be in the system, we need to be able to steal contexts.
+ * These variables support that.
+ */
+extern atomic_t nr_free_contexts;
+extern struct mm_struct *context_mm[LAST_CONTEXT+1];
+extern void steal_context(void);
+
+/*
+ * Get a new mmu context for the address space described by `mm'.
+ */
+static inline void get_mmu_context(struct mm_struct *mm)
+{
+       mm_context_t ctx;
+
+       if (mm->context != NO_CONTEXT)
+               return;
+       while (atomic_dec_if_positive(&nr_free_contexts) < 0)
+               steal_context();
+       ctx = next_mmu_context;
+       while (test_and_set_bit(ctx, context_map)) {
+               ctx = find_next_zero_bit(context_map, LAST_CONTEXT+1, ctx);
+               if (ctx > LAST_CONTEXT)
+                       ctx = 0;
+       }
+       next_mmu_context = (ctx + 1) & LAST_CONTEXT;
+       mm->context = ctx;
+       context_mm[ctx] = mm;
+}
+
+/*
+ * Set up the context for a new address space.
+ */
+# define init_new_context(tsk, mm)     (((mm)->context = NO_CONTEXT), 0)
+
+/*
+ * We're finished using the context for an address space.
+ */
+static inline void destroy_context(struct mm_struct *mm)
+{
+       if (mm->context != NO_CONTEXT) {
+               clear_bit(mm->context, context_map);
+               mm->context = NO_CONTEXT;
+               atomic_inc(&nr_free_contexts);
+       }
+}
+
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
+                            struct task_struct *tsk)
+{
+       tsk->thread.pgdir = next->pgd;
+       get_mmu_context(next);
+       set_context(next->context, next->pgd);
+}
+
+/*
+ * After we have set current->mm to a new value, this activates
+ * the context for the new mm so we see the new mappings.
+ */
+static inline void activate_mm(struct mm_struct *active_mm,
+                       struct mm_struct *mm)
+{
+       current->thread.pgdir = mm->pgd;
+       get_mmu_context(mm);
+       set_context(mm->context, mm->pgd);
+}
+
+extern void mmu_context_init(void);
+
+# endif /* __KERNEL__ */
+#endif /* _ASM_MICROBLAZE_MMU_CONTEXT_H */
diff --git a/arch/microblaze/include/asm/mmu_context_no.h b/arch/microblaze/include/asm/mmu_context_no.h
new file mode 100644 (file)
index 0000000..ba55671
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
+ * Copyright (C) 2006 Atmark Techno, Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_MICROBLAZE_MMU_CONTEXT_H
+#define _ASM_MICROBLAZE_MMU_CONTEXT_H
+
+# define init_new_context(tsk, mm)             ({ 0; })
+
+# define enter_lazy_tlb(mm, tsk)               do {} while (0)
+# define change_mm_context(old, ctx, _pml4)    do {} while (0)
+# define destroy_context(mm)                   do {} while (0)
+# define deactivate_mm(tsk, mm)                        do {} while (0)
+# define switch_mm(prev, next, tsk)            do {} while (0)
+# define activate_mm(prev, next)               do {} while (0)
+
+#endif /* _ASM_MICROBLAZE_MMU_CONTEXT_H */
index 7238dcfcc5174af979475f75013608f1f8558158..72aceae88680a2b427253d2941a3f29452f34e26 100644 (file)
@@ -1,6 +1,8 @@
 /*
- * Copyright (C) 2008 Michal Simek
- * Copyright (C) 2008 PetaLogix
+ * VM ops
+ *
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  * Changes for MMU support:
  *    Copyright (C) 2007 Xilinx, Inc.  All rights reserved.
 
 #include <linux/pfn.h>
 #include <asm/setup.h>
+#include <linux/const.h>
+
+#ifdef __KERNEL__
 
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT     (12)
-#define PAGE_SIZE      (1UL << PAGE_SHIFT)
+#define PAGE_SIZE      (_AC(1, UL) << PAGE_SHIFT)
 #define PAGE_MASK      (~(PAGE_SIZE-1))
 
-#ifdef __KERNEL__
-
 #ifndef __ASSEMBLY__
 
 #define PAGE_UP(addr)  (((addr)+((PAGE_SIZE)-1))&(~((PAGE_SIZE)-1)))
@@ -35,6 +38,7 @@
 /* align addr on a size boundary - adjust address up if needed */
 #define _ALIGN(addr, size)     _ALIGN_UP(addr, size)
 
+#ifndef CONFIG_MMU
 /*
  * PAGE_OFFSET -- the first address of the first page of memory. When not
  * using MMU this corresponds to the first free page in physical memory (aligned
 extern unsigned int __page_offset;
 #define PAGE_OFFSET __page_offset
 
-#define copy_page(to, from)                    memcpy((to), (from), PAGE_SIZE)
-#define get_user_page(vaddr)                   __get_free_page(GFP_KERNEL)
-#define free_user_page(page, addr)             free_page(addr)
+#else /* CONFIG_MMU */
 
-#define clear_page(pgaddr)                     memset((pgaddr), 0, PAGE_SIZE)
+/*
+ * PAGE_OFFSET -- the first address of the first page of memory. With MMU
+ * it is set to the kernel start address (aligned on a page boundary).
+ *
+ * CONFIG_KERNEL_START is defined in arch/microblaze/config.in and used
+ * in arch/microblaze/Makefile.
+ */
+#define PAGE_OFFSET    CONFIG_KERNEL_START
 
+/*
+ * MAP_NR -- given an address, calculate the index of the page struct which
+ * points to the address's page.
+ */
+#define MAP_NR(addr) (((unsigned long)(addr) - PAGE_OFFSET) >> PAGE_SHIFT)
 
-#define clear_user_page(pgaddr, vaddr, page)   memset((pgaddr), 0, PAGE_SIZE)
-#define copy_user_page(vto, vfrom, vaddr, topg) \
+/*
+ * The basic type of a PTE - 32 bit physical addressing.
+ */
+typedef unsigned long pte_basic_t;
+#define PTE_SHIFT      (PAGE_SHIFT - 2)        /* 1024 ptes per page */
+#define PTE_FMT                "%.8lx"
+
+#endif /* CONFIG_MMU */
+
+#  ifndef CONFIG_MMU
+#  define copy_page(to, from)                  memcpy((to), (from), PAGE_SIZE)
+#  define get_user_page(vaddr)                 __get_free_page(GFP_KERNEL)
+#  define free_user_page(page, addr)           free_page(addr)
+#  else /* CONFIG_MMU */
+extern void copy_page(void *to, void *from);
+#  endif /* CONFIG_MMU */
+
+# define clear_page(pgaddr)                    memset((pgaddr), 0, PAGE_SIZE)
+
+# define clear_user_page(pgaddr, vaddr, page)  memset((pgaddr), 0, PAGE_SIZE)
+# define copy_user_page(vto, vfrom, vaddr, topg) \
                        memcpy((vto), (vfrom), PAGE_SIZE)
 
 /*
@@ -60,21 +93,32 @@ extern unsigned int __page_offset;
 typedef struct page *pgtable_t;
 typedef struct { unsigned long pte; }          pte_t;
 typedef struct { unsigned long pgprot; }       pgprot_t;
+/* FIXME this can depend on linux kernel version */
+#   ifdef CONFIG_MMU
+typedef struct { unsigned long pmd; } pmd_t;
+typedef struct { unsigned long pgd; } pgd_t;
+#   else /* CONFIG_MMU */
 typedef struct { unsigned long ste[64]; }      pmd_t;
 typedef struct { pmd_t         pue[1]; }       pud_t;
 typedef struct { pud_t         pge[1]; }       pgd_t;
+#   endif /* CONFIG_MMU */
 
+# define pte_val(x)    ((x).pte)
+# define pgprot_val(x) ((x).pgprot)
 
-#define pte_val(x)     ((x).pte)
-#define pgprot_val(x)  ((x).pgprot)
-#define pmd_val(x)     ((x).ste[0])
-#define pud_val(x)     ((x).pue[0])
-#define pgd_val(x)     ((x).pge[0])
+#   ifdef CONFIG_MMU
+#   define pmd_val(x)      ((x).pmd)
+#   define pgd_val(x)      ((x).pgd)
+#   else  /* CONFIG_MMU */
+#   define pmd_val(x)  ((x).ste[0])
+#   define pud_val(x)  ((x).pue[0])
+#   define pgd_val(x)  ((x).pge[0])
+#   endif  /* CONFIG_MMU */
 
-#define __pte(x)       ((pte_t) { (x) })
-#define __pmd(x)       ((pmd_t) { (x) })
-#define __pgd(x)       ((pgd_t) { (x) })
-#define __pgprot(x)    ((pgprot_t) { (x) })
+# define __pte(x)      ((pte_t) { (x) })
+# define __pmd(x)      ((pmd_t) { (x) })
+# define __pgd(x)      ((pgd_t) { (x) })
+# define __pgprot(x)   ((pgprot_t) { (x) })
 
 /**
  * Conversions for virtual address, physical address, pfn, and struct
@@ -94,47 +138,83 @@ extern unsigned long max_low_pfn;
 extern unsigned long min_low_pfn;
 extern unsigned long max_pfn;
 
-#define __pa(vaddr)            ((unsigned long) (vaddr))
-#define __va(paddr)            ((void *) (paddr))
+extern unsigned long memory_start;
+extern unsigned long memory_end;
+extern unsigned long memory_size;
 
-#define phys_to_pfn(phys)      (PFN_DOWN(phys))
-#define pfn_to_phys(pfn)       (PFN_PHYS(pfn))
+extern int page_is_ram(unsigned long pfn);
 
-#define virt_to_pfn(vaddr)     (phys_to_pfn((__pa(vaddr))))
-#define pfn_to_virt(pfn)       __va(pfn_to_phys((pfn)))
+# define phys_to_pfn(phys)     (PFN_DOWN(phys))
+# define pfn_to_phys(pfn)      (PFN_PHYS(pfn))
 
-#define virt_to_page(vaddr)    (pfn_to_page(virt_to_pfn(vaddr)))
-#define page_to_virt(page)     (pfn_to_virt(page_to_pfn(page)))
+# define virt_to_pfn(vaddr)    (phys_to_pfn((__pa(vaddr))))
+# define pfn_to_virt(pfn)      __va(pfn_to_phys((pfn)))
 
-#define page_to_phys(page)     (pfn_to_phys(page_to_pfn(page)))
-#define page_to_bus(page)      (page_to_phys(page))
-#define phys_to_page(paddr)    (pfn_to_page(phys_to_pfn(paddr)))
+#  ifdef CONFIG_MMU
+#  define virt_to_page(kaddr)  (mem_map +  MAP_NR(kaddr))
+#  else /* CONFIG_MMU */
+#  define virt_to_page(vaddr)  (pfn_to_page(virt_to_pfn(vaddr)))
+#  define page_to_virt(page)   (pfn_to_virt(page_to_pfn(page)))
+#  define page_to_phys(page)   (pfn_to_phys(page_to_pfn(page)))
+#  define page_to_bus(page)    (page_to_phys(page))
+#  define phys_to_page(paddr)  (pfn_to_page(phys_to_pfn(paddr)))
+#  endif /* CONFIG_MMU */
 
-extern unsigned int memory_start;
-extern unsigned int memory_end;
-extern unsigned int memory_size;
+#  ifndef CONFIG_MMU
+#  define pfn_valid(pfn)       ((pfn) >= min_low_pfn && (pfn) <= max_mapnr)
+#  define ARCH_PFN_OFFSET      (PAGE_OFFSET >> PAGE_SHIFT)
+#  else /* CONFIG_MMU */
+#  define ARCH_PFN_OFFSET      (memory_start >> PAGE_SHIFT)
+#  define pfn_valid(pfn)       ((pfn) < (max_mapnr + ARCH_PFN_OFFSET))
+#  define VALID_PAGE(page)     ((page - mem_map) < max_mapnr)
+#  endif /* CONFIG_MMU */
 
-#define pfn_valid(pfn)         ((pfn) >= min_low_pfn && (pfn) < max_mapnr)
+# endif /* __ASSEMBLY__ */
 
-#define ARCH_PFN_OFFSET                (PAGE_OFFSET >> PAGE_SHIFT)
+#define        virt_addr_valid(vaddr)  (pfn_valid(virt_to_pfn(vaddr)))
 
-#else
-#define tophys(rd, rs) (addik rd, rs, 0)
-#define tovirt(rd, rs) (addik rd, rs, 0)
-#endif /* __ASSEMBLY__ */
 
-#define virt_addr_valid(vaddr) (pfn_valid(virt_to_pfn(vaddr)))
+#  ifndef CONFIG_MMU
+#  define __pa(vaddr)  ((unsigned long) (vaddr))
+#  define __va(paddr)  ((void *) (paddr))
+#  else /* CONFIG_MMU */
+#  define __pa(x)      __virt_to_phys((unsigned long)(x))
+#  define __va(x)      ((void *)__phys_to_virt((unsigned long)(x)))
+#  endif /* CONFIG_MMU */
+
 
-/* Convert between virtual and physical address for MMU.  */
-/* Handle MicroBlaze processor with virtual memory.  */
+/* Convert between virtual and physical address for MMU. */
+/* Handle MicroBlaze processor with virtual memory. */
+#ifndef CONFIG_MMU
 #define __virt_to_phys(addr)   addr
 #define __phys_to_virt(addr)   addr
+#define tophys(rd, rs) addik rd, rs, 0
+#define tovirt(rd, rs) addik rd, rs, 0
+#else
+#define __virt_to_phys(addr) \
+       ((addr) + CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START)
+#define __phys_to_virt(addr) \
+       ((addr) + CONFIG_KERNEL_START - CONFIG_KERNEL_BASE_ADDR)
+#define tophys(rd, rs) \
+       addik rd, rs, (CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START)
+#define tovirt(rd, rs) \
+       addik rd, rs, (CONFIG_KERNEL_START - CONFIG_KERNEL_BASE_ADDR)
+#endif /* CONFIG_MMU */
 
 #define TOPHYS(addr)  __virt_to_phys(addr)
 
+#ifdef CONFIG_MMU
+#ifdef CONFIG_CONTIGUOUS_PAGE_ALLOC
+#define WANT_PAGE_VIRTUAL 1 /* page alloc 2 relies on this */
+#endif
+
+#define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
+                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+#endif /* CONFIG_MMU */
+
 #endif /* __KERNEL__ */
 
 #include <asm-generic/memory_model.h>
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* _ASM_MICROBLAZE_PAGE_H */
index 2a4b3548401095f98e3111f8422005f008c931fe..59a757e46ba552ad57736103ea42c3378e83af90 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
 #ifndef _ASM_MICROBLAZE_PGALLOC_H
 #define _ASM_MICROBLAZE_PGALLOC_H
 
+#ifdef CONFIG_MMU
+
+#include <linux/kernel.h>      /* For min/max macros */
+#include <linux/highmem.h>
+#include <asm/setup.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/cache.h>
+
+#define PGDIR_ORDER    0
+
+/*
+ * This is handled very differently on MicroBlaze since out page tables
+ * are all 0's and I want to be able to use these zero'd pages elsewhere
+ * as well - it gives us quite a speedup.
+ * -- Cort
+ */
+extern struct pgtable_cache_struct {
+       unsigned long *pgd_cache;
+       unsigned long *pte_cache;
+       unsigned long pgtable_cache_sz;
+} quicklists;
+
+#define pgd_quicklist          (quicklists.pgd_cache)
+#define pmd_quicklist          ((unsigned long *)0)
+#define pte_quicklist          (quicklists.pte_cache)
+#define pgtable_cache_size     (quicklists.pgtable_cache_sz)
+
+extern unsigned long *zero_cache; /* head linked list of pre-zero'd pages */
+extern atomic_t zero_sz; /* # currently pre-zero'd pages */
+extern atomic_t zeropage_hits; /* # zero'd pages request that we've done */
+extern atomic_t zeropage_calls; /* # zero'd pages request that've been made */
+extern atomic_t zerototal; /* # pages zero'd over time */
+
+#define zero_quicklist         (zero_cache)
+#define zero_cache_sz          (zero_sz)
+#define zero_cache_calls       (zeropage_calls)
+#define zero_cache_hits                (zeropage_hits)
+#define zero_cache_total       (zerototal)
+
+/*
+ * return a pre-zero'd page from the list,
+ * return NULL if none available -- Cort
+ */
+extern unsigned long get_zero_page_fast(void);
+
+extern void __bad_pte(pmd_t *pmd);
+
+extern inline pgd_t *get_pgd_slow(void)
+{
+       pgd_t *ret;
+
+       ret = (pgd_t *)__get_free_pages(GFP_KERNEL, PGDIR_ORDER);
+       if (ret != NULL)
+               clear_page(ret);
+       return ret;
+}
+
+extern inline pgd_t *get_pgd_fast(void)
+{
+       unsigned long *ret;
+
+       ret = pgd_quicklist;
+       if (ret != NULL) {
+               pgd_quicklist = (unsigned long *)(*ret);
+               ret[0] = 0;
+               pgtable_cache_size--;
+       } else
+               ret = (unsigned long *)get_pgd_slow();
+       return (pgd_t *)ret;
+}
+
+extern inline void free_pgd_fast(pgd_t *pgd)
+{
+       *(unsigned long **)pgd = pgd_quicklist;
+       pgd_quicklist = (unsigned long *) pgd;
+       pgtable_cache_size++;
+}
+
+extern inline void free_pgd_slow(pgd_t *pgd)
+{
+       free_page((unsigned long)pgd);
+}
+
+#define pgd_free(mm, pgd)        free_pgd_fast(pgd)
+#define pgd_alloc(mm)          get_pgd_fast()
+
+#define pmd_pgtable(pmd)       pmd_page(pmd)
+
+/*
+ * We don't have any real pmd's, and this code never triggers because
+ * the pgd will always be present..
+ */
+#define pmd_alloc_one_fast(mm, address)        ({ BUG(); ((pmd_t *)1); })
+#define pmd_alloc_one(mm, address)     ({ BUG(); ((pmd_t *)2); })
+/* FIXME two definition - look below */
+#define pmd_free(mm, x)                        do { } while (0)
+#define pgd_populate(mm, pmd, pte)     BUG()
+
+static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
+               unsigned long address)
+{
+       pte_t *pte;
+       extern int mem_init_done;
+       extern void *early_get_page(void);
+       if (mem_init_done) {
+               pte = (pte_t *)__get_free_page(GFP_KERNEL |
+                                       __GFP_REPEAT | __GFP_ZERO);
+       } else {
+               pte = (pte_t *)early_get_page();
+               if (pte)
+                       clear_page(pte);
+       }
+       return pte;
+}
+
+static inline struct page *pte_alloc_one(struct mm_struct *mm,
+               unsigned long address)
+{
+       struct page *ptepage;
+
+#ifdef CONFIG_HIGHPTE
+       int flags = GFP_KERNEL | __GFP_HIGHMEM | __GFP_REPEAT;
+#else
+       int flags = GFP_KERNEL | __GFP_REPEAT;
+#endif
+
+       ptepage = alloc_pages(flags, 0);
+       if (ptepage)
+               clear_highpage(ptepage);
+       return ptepage;
+}
+
+static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm,
+               unsigned long address)
+{
+       unsigned long *ret;
+
+       ret = pte_quicklist;
+       if (ret != NULL) {
+               pte_quicklist = (unsigned long *)(*ret);
+               ret[0] = 0;
+               pgtable_cache_size--;
+       }
+       return (pte_t *)ret;
+}
+
+extern inline void pte_free_fast(pte_t *pte)
+{
+       *(unsigned long **)pte = pte_quicklist;
+       pte_quicklist = (unsigned long *) pte;
+       pgtable_cache_size++;
+}
+
+extern inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
+{
+       free_page((unsigned long)pte);
+}
+
+extern inline void pte_free_slow(struct page *ptepage)
+{
+       __free_page(ptepage);
+}
+
+extern inline void pte_free(struct mm_struct *mm, struct page *ptepage)
+{
+       __free_page(ptepage);
+}
+
+#define __pte_free_tlb(tlb, pte)       pte_free((tlb)->mm, (pte))
+
+#define pmd_populate(mm, pmd, pte)     (pmd_val(*(pmd)) = page_address(pte))
+
+#define pmd_populate_kernel(mm, pmd, pte) \
+               (pmd_val(*(pmd)) = (unsigned long) (pte))
+
+/*
+ * We don't have any real pmd's, and this code never triggers because
+ * the pgd will always be present..
+ */
+#define pmd_alloc_one(mm, address)     ({ BUG(); ((pmd_t *)2); })
+/*#define pmd_free(mm, x)                      do { } while (0)*/
+#define __pmd_free_tlb(tlb, x)         do { } while (0)
+#define pgd_populate(mm, pmd, pte)     BUG()
+
+extern int do_check_pgt_cache(int, int);
+
+#endif /* CONFIG_MMU */
+
 #define check_pgt_cache()      do {} while (0)
 
 #endif /* _ASM_MICROBLAZE_PGALLOC_H */
index 4df31e46568e7649e43f69170604f5a28484bfc3..4c57a586a989e6695be8b14a2337d34f87f7f751 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -14,6 +16,8 @@
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)                \
                remap_pfn_range(vma, vaddr, pfn, size, prot)
 
+#ifndef CONFIG_MMU
+
 #define pgd_present(pgd)       (1) /* pages are always present on non MMU */
 #define pgd_none(pgd)          (0)
 #define pgd_bad(pgd)           (0)
@@ -27,6 +31,8 @@
 #define PAGE_READONLY          __pgprot(0) /* these mean nothing to non MMU */
 #define PAGE_KERNEL            __pgprot(0) /* these mean nothing to non MMU */
 
+#define pgprot_noncached(x)    (x)
+
 #define __swp_type(x)          (0)
 #define __swp_offset(x)                (0)
 #define __swp_entry(typ, off)  ((swp_entry_t) { ((typ) | ((off) << 7)) })
@@ -45,6 +51,538 @@ static inline int pte_file(pte_t pte) { return 0; }
 
 #define arch_enter_lazy_cpu_mode()     do {} while (0)
 
+#else /* CONFIG_MMU */
+
+#include <asm-generic/4level-fixup.h>
+
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+
+#include <linux/sched.h>
+#include <linux/threads.h>
+#include <asm/processor.h>             /* For TASK_SIZE */
+#include <asm/mmu.h>
+#include <asm/page.h>
+
+#define FIRST_USER_ADDRESS     0
+
+extern unsigned long va_to_phys(unsigned long address);
+extern pte_t *va_to_pte(unsigned long address);
+extern unsigned long ioremap_bot, ioremap_base;
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+
+static inline int pte_special(pte_t pte)       { return 0; }
+
+static inline pte_t pte_mkspecial(pte_t pte)   { return pte; }
+
+/* Start and end of the vmalloc area. */
+/* Make sure to map the vmalloc area above the pinned kernel memory area
+   of 32Mb.  */
+#define VMALLOC_START  (CONFIG_KERNEL_START + \
+                               max(32 * 1024 * 1024UL, memory_size))
+#define VMALLOC_END    ioremap_bot
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+
+#endif /* __ASSEMBLY__ */
+
+/*
+ * The MicroBlaze MMU is identical to the PPC-40x MMU, and uses a hash
+ * table containing PTEs, together with a set of 16 segment registers, to
+ * define the virtual to physical address mapping.
+ *
+ * We use the hash table as an extended TLB, i.e. a cache of currently
+ * active mappings.  We maintain a two-level page table tree, much
+ * like that used by the i386, for the sake of the Linux memory
+ * management code.  Low-level assembler code in hashtable.S
+ * (procedure hash_page) is responsible for extracting ptes from the
+ * tree and putting them into the hash table when necessary, and
+ * updating the accessed and modified bits in the page table tree.
+ */
+
+/*
+ * The MicroBlaze processor has a TLB architecture identical to PPC-40x. The
+ * instruction and data sides share a unified, 64-entry, semi-associative
+ * TLB which is maintained totally under software control. In addition, the
+ * instruction side has a hardware-managed, 2,4, or 8-entry, fully-associative
+ * TLB which serves as a first level to the shared TLB. These two TLBs are
+ * known as the UTLB and ITLB, respectively (see "mmu.h" for definitions).
+ */
+
+/*
+ * The normal case is that PTEs are 32-bits and we have a 1-page
+ * 1024-entry pgdir pointing to 1-page 1024-entry PTE pages.  -- paulus
+ *
+ */
+
+/* PMD_SHIFT determines the size of the area mapped by the PTE pages */
+#define PMD_SHIFT      (PAGE_SHIFT + PTE_SHIFT)
+#define PMD_SIZE       (1UL << PMD_SHIFT)
+#define PMD_MASK       (~(PMD_SIZE-1))
+
+/* PGDIR_SHIFT determines what a top-level page table entry can map */
+#define PGDIR_SHIFT    PMD_SHIFT
+#define PGDIR_SIZE     (1UL << PGDIR_SHIFT)
+#define PGDIR_MASK     (~(PGDIR_SIZE-1))
+
+/*
+ * entries per page directory level: our page-table tree is two-level, so
+ * we don't really have any PMD directory.
+ */
+#define PTRS_PER_PTE   (1 << PTE_SHIFT)
+#define PTRS_PER_PMD   1
+#define PTRS_PER_PGD   (1 << (32 - PGDIR_SHIFT))
+
+#define USER_PTRS_PER_PGD      (TASK_SIZE / PGDIR_SIZE)
+#define FIRST_USER_PGD_NR      0
+
+#define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
+#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
+
+#define pte_ERROR(e) \
+       printk(KERN_ERR "%s:%d: bad pte "PTE_FMT".\n", \
+               __FILE__, __LINE__, pte_val(e))
+#define pmd_ERROR(e) \
+       printk(KERN_ERR "%s:%d: bad pmd %08lx.\n", \
+               __FILE__, __LINE__, pmd_val(e))
+#define pgd_ERROR(e) \
+       printk(KERN_ERR "%s:%d: bad pgd %08lx.\n", \
+               __FILE__, __LINE__, pgd_val(e))
+
+/*
+ * Bits in a linux-style PTE.  These match the bits in the
+ * (hardware-defined) PTE as closely as possible.
+ */
+
+/* There are several potential gotchas here.  The hardware TLBLO
+ * field looks like this:
+ *
+ * 0  1  2  3  4  ... 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+ * RPN.....................  0  0 EX WR ZSEL.......  W  I  M  G
+ *
+ * Where possible we make the Linux PTE bits match up with this
+ *
+ * - bits 20 and 21 must be cleared, because we use 4k pages (4xx can
+ * support down to 1k pages), this is done in the TLBMiss exception
+ * handler.
+ * - We use only zones 0 (for kernel pages) and 1 (for user pages)
+ * of the 16 available.  Bit 24-26 of the TLB are cleared in the TLB
+ * miss handler.  Bit 27 is PAGE_USER, thus selecting the correct
+ * zone.
+ * - PRESENT *must* be in the bottom two bits because swap cache
+ * entries use the top 30 bits.  Because 4xx doesn't support SMP
+ * anyway, M is irrelevant so we borrow it for PAGE_PRESENT.  Bit 30
+ * is cleared in the TLB miss handler before the TLB entry is loaded.
+ * - All other bits of the PTE are loaded into TLBLO without
+ *  * modification, leaving us only the bits 20, 21, 24, 25, 26, 30 for
+ * software PTE bits.  We actually use use bits 21, 24, 25, and
+ * 30 respectively for the software bits: ACCESSED, DIRTY, RW, and
+ * PRESENT.
+ */
+
+/* Definitions for MicroBlaze. */
+#define        _PAGE_GUARDED   0x001   /* G: page is guarded from prefetch */
+#define _PAGE_PRESENT  0x002   /* software: PTE contains a translation */
+#define        _PAGE_NO_CACHE  0x004   /* I: caching is inhibited */
+#define        _PAGE_WRITETHRU 0x008   /* W: caching is write-through */
+#define        _PAGE_USER      0x010   /* matches one of the zone permission bits */
+#define        _PAGE_RW        0x040   /* software: Writes permitted */
+#define        _PAGE_DIRTY     0x080   /* software: dirty page */
+#define _PAGE_HWWRITE  0x100   /* hardware: Dirty & RW, set in exception */
+#define _PAGE_HWEXEC   0x200   /* hardware: EX permission */
+#define _PAGE_ACCESSED 0x400   /* software: R: page referenced */
+#define _PMD_PRESENT   PAGE_MASK
+
+/*
+ * Some bits are unused...
+ */
+#ifndef _PAGE_HASHPTE
+#define _PAGE_HASHPTE  0
+#endif
+#ifndef _PTE_NONE_MASK
+#define _PTE_NONE_MASK 0
+#endif
+#ifndef _PAGE_SHARED
+#define _PAGE_SHARED   0
+#endif
+#ifndef _PAGE_HWWRITE
+#define _PAGE_HWWRITE  0
+#endif
+#ifndef _PAGE_HWEXEC
+#define _PAGE_HWEXEC   0
+#endif
+#ifndef _PAGE_EXEC
+#define _PAGE_EXEC     0
+#endif
+
+#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
+
+/*
+ * Note: the _PAGE_COHERENT bit automatically gets set in the hardware
+ * PTE if CONFIG_SMP is defined (hash_page does this); there is no need
+ * to have it in the Linux PTE, and in fact the bit could be reused for
+ * another purpose.  -- paulus.
+ */
+#define _PAGE_BASE     (_PAGE_PRESENT | _PAGE_ACCESSED)
+#define _PAGE_WRENABLE (_PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE)
+
+#define _PAGE_KERNEL \
+       (_PAGE_BASE | _PAGE_WRENABLE | _PAGE_SHARED | _PAGE_HWEXEC)
+
+#define _PAGE_IO       (_PAGE_KERNEL | _PAGE_NO_CACHE | _PAGE_GUARDED)
+
+#define PAGE_NONE      __pgprot(_PAGE_BASE)
+#define PAGE_READONLY  __pgprot(_PAGE_BASE | _PAGE_USER)
+#define PAGE_READONLY_X        __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
+#define PAGE_SHARED    __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW)
+#define PAGE_SHARED_X \
+               __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | _PAGE_EXEC)
+#define PAGE_COPY      __pgprot(_PAGE_BASE | _PAGE_USER)
+#define PAGE_COPY_X    __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
+
+#define PAGE_KERNEL    __pgprot(_PAGE_KERNEL)
+#define PAGE_KERNEL_RO __pgprot(_PAGE_BASE | _PAGE_SHARED)
+#define PAGE_KERNEL_CI __pgprot(_PAGE_IO)
+
+/*
+ * We consider execute permission the same as read.
+ * Also, write permissions imply read permissions.
+ */
+#define __P000 PAGE_NONE
+#define __P001 PAGE_READONLY_X
+#define __P010 PAGE_COPY
+#define __P011 PAGE_COPY_X
+#define __P100 PAGE_READONLY
+#define __P101 PAGE_READONLY_X
+#define __P110 PAGE_COPY
+#define __P111 PAGE_COPY_X
+
+#define __S000 PAGE_NONE
+#define __S001 PAGE_READONLY_X
+#define __S010 PAGE_SHARED
+#define __S011 PAGE_SHARED_X
+#define __S100 PAGE_READONLY
+#define __S101 PAGE_READONLY_X
+#define __S110 PAGE_SHARED
+#define __S111 PAGE_SHARED_X
+
+#ifndef __ASSEMBLY__
+/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern unsigned long empty_zero_page[1024];
+#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+
+#endif /* __ASSEMBLY__ */
+
+#define pte_none(pte)          ((pte_val(pte) & ~_PTE_NONE_MASK) == 0)
+#define pte_present(pte)       (pte_val(pte) & _PAGE_PRESENT)
+#define pte_clear(mm, addr, ptep) \
+       do { set_pte_at((mm), (addr), (ptep), __pte(0)); } while (0)
+
+#define pmd_none(pmd)          (!pmd_val(pmd))
+#define        pmd_bad(pmd)            ((pmd_val(pmd) & _PMD_PRESENT) == 0)
+#define        pmd_present(pmd)        ((pmd_val(pmd) & _PMD_PRESENT) != 0)
+#define        pmd_clear(pmdp)         do { pmd_val(*(pmdp)) = 0; } while (0)
+
+#define pte_page(x)            (mem_map + (unsigned long) \
+                               ((pte_val(x) - memory_start) >> PAGE_SHIFT))
+#define PFN_SHIFT_OFFSET       (PAGE_SHIFT)
+
+#define pte_pfn(x)             (pte_val(x) >> PFN_SHIFT_OFFSET)
+
+#define pfn_pte(pfn, prot) \
+       __pte(((pte_basic_t)(pfn) << PFN_SHIFT_OFFSET) | pgprot_val(prot))
+
+#ifndef __ASSEMBLY__
+/*
+ * The "pgd_xxx()" functions here are trivial for a folded two-level
+ * setup: the pgd is never bad, and a pmd always exists (as it's folded
+ * into the pgd entry)
+ */
+static inline int pgd_none(pgd_t pgd)          { return 0; }
+static inline int pgd_bad(pgd_t pgd)           { return 0; }
+static inline int pgd_present(pgd_t pgd)       { return 1; }
+#define pgd_clear(xp)                          do { } while (0)
+#define pgd_page(pgd) \
+       ((unsigned long) __va(pgd_val(pgd) & PAGE_MASK))
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+static inline int pte_read(pte_t pte)  { return pte_val(pte) & _PAGE_USER; }
+static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; }
+static inline int pte_exec(pte_t pte)  { return pte_val(pte) & _PAGE_EXEC; }
+static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
+static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
+/* FIXME */
+static inline int pte_file(pte_t pte)          { return 0; }
+
+static inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; }
+static inline void pte_cache(pte_t pte)   { pte_val(pte) &= ~_PAGE_NO_CACHE; }
+
+static inline pte_t pte_rdprotect(pte_t pte) \
+               { pte_val(pte) &= ~_PAGE_USER; return pte; }
+static inline pte_t pte_wrprotect(pte_t pte) \
+       { pte_val(pte) &= ~(_PAGE_RW | _PAGE_HWWRITE); return pte; }
+static inline pte_t pte_exprotect(pte_t pte) \
+       { pte_val(pte) &= ~_PAGE_EXEC; return pte; }
+static inline pte_t pte_mkclean(pte_t pte) \
+       { pte_val(pte) &= ~(_PAGE_DIRTY | _PAGE_HWWRITE); return pte; }
+static inline pte_t pte_mkold(pte_t pte) \
+       { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
+
+static inline pte_t pte_mkread(pte_t pte) \
+       { pte_val(pte) |= _PAGE_USER; return pte; }
+static inline pte_t pte_mkexec(pte_t pte) \
+       { pte_val(pte) |= _PAGE_USER | _PAGE_EXEC; return pte; }
+static inline pte_t pte_mkwrite(pte_t pte) \
+       { pte_val(pte) |= _PAGE_RW; return pte; }
+static inline pte_t pte_mkdirty(pte_t pte) \
+       { pte_val(pte) |= _PAGE_DIRTY; return pte; }
+static inline pte_t pte_mkyoung(pte_t pte) \
+       { pte_val(pte) |= _PAGE_ACCESSED; return pte; }
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+
+static inline pte_t mk_pte_phys(phys_addr_t physpage, pgprot_t pgprot)
+{
+       pte_t pte;
+       pte_val(pte) = physpage | pgprot_val(pgprot);
+       return pte;
+}
+
+#define mk_pte(page, pgprot) \
+({                                                                        \
+       pte_t pte;                                                         \
+       pte_val(pte) = (((page - mem_map) << PAGE_SHIFT) + memory_start) |  \
+                       pgprot_val(pgprot);                                \
+       pte;                                                               \
+})
+
+static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{
+       pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot);
+       return pte;
+}
+
+/*
+ * Atomic PTE updates.
+ *
+ * pte_update clears and sets bit atomically, and returns
+ * the old pte value.
+ * The ((unsigned long)(p+1) - 4) hack is to get to the least-significant
+ * 32 bits of the PTE regardless of whether PTEs are 32 or 64 bits.
+ */
+static inline unsigned long pte_update(pte_t *p, unsigned long clr,
+                               unsigned long set)
+{
+       unsigned long old, tmp, msr;
+
+       __asm__ __volatile__("\
+       msrclr  %2, 0x2\n\
+       nop\n\
+       lw      %0, %4, r0\n\
+       andn    %1, %0, %5\n\
+       or      %1, %1, %6\n\
+       sw      %1, %4, r0\n\
+       mts     rmsr, %2\n\
+       nop"
+       : "=&r" (old), "=&r" (tmp), "=&r" (msr), "=m" (*p)
+       : "r" ((unsigned long)(p+1) - 4), "r" (clr), "r" (set), "m" (*p)
+       : "cc");
+
+       return old;
+}
+
+/*
+ * set_pte stores a linux PTE into the linux page table.
+ */
+static inline void set_pte(struct mm_struct *mm, unsigned long addr,
+               pte_t *ptep, pte_t pte)
+{
+       *ptep = pte;
+}
+
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+               pte_t *ptep, pte_t pte)
+{
+       *ptep = pte;
+}
+
+static inline int ptep_test_and_clear_young(struct mm_struct *mm,
+               unsigned long addr, pte_t *ptep)
+{
+       return (pte_update(ptep, _PAGE_ACCESSED, 0) & _PAGE_ACCESSED) != 0;
+}
+
+static inline int ptep_test_and_clear_dirty(struct mm_struct *mm,
+               unsigned long addr, pte_t *ptep)
+{
+       return (pte_update(ptep, \
+               (_PAGE_DIRTY | _PAGE_HWWRITE), 0) & _PAGE_DIRTY) != 0;
+}
+
+static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
+               unsigned long addr, pte_t *ptep)
+{
+       return __pte(pte_update(ptep, ~_PAGE_HASHPTE, 0));
+}
+
+/*static inline void ptep_set_wrprotect(struct mm_struct *mm,
+               unsigned long addr, pte_t *ptep)
+{
+       pte_update(ptep, (_PAGE_RW | _PAGE_HWWRITE), 0);
+}*/
+
+static inline void ptep_mkdirty(struct mm_struct *mm,
+               unsigned long addr, pte_t *ptep)
+{
+       pte_update(ptep, 0, _PAGE_DIRTY);
+}
+
+/*#define pte_same(A,B)        (((pte_val(A) ^ pte_val(B)) & ~_PAGE_HASHPTE) == 0)*/
+
+/* Convert pmd entry to page */
+/* our pmd entry is an effective address of pte table*/
+/* returns effective address of the pmd entry*/
+#define pmd_page_kernel(pmd)   ((unsigned long) (pmd_val(pmd) & PAGE_MASK))
+
+/* returns struct *page of the pmd entry*/
+#define pmd_page(pmd)  (pfn_to_page(__pa(pmd_val(pmd)) >> PAGE_SHIFT))
+
+/* to find an entry in a kernel page-table-directory */
+#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+
+/* to find an entry in a page-table-directory */
+#define pgd_index(address)      ((address) >> PGDIR_SHIFT)
+#define pgd_offset(mm, address)         ((mm)->pgd + pgd_index(address))
+
+/* Find an entry in the second-level page table.. */
+static inline pmd_t *pmd_offset(pgd_t *dir, unsigned long address)
+{
+       return (pmd_t *) dir;
+}
+
+/* Find an entry in the third-level page table.. */
+#define pte_index(address)             \
+       (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+#define pte_offset_kernel(dir, addr)   \
+       ((pte_t *) pmd_page_kernel(*(dir)) + pte_index(addr))
+#define pte_offset_map(dir, addr)              \
+       ((pte_t *) kmap_atomic(pmd_page(*(dir)), KM_PTE0) + pte_index(addr))
+#define pte_offset_map_nested(dir, addr)       \
+       ((pte_t *) kmap_atomic(pmd_page(*(dir)), KM_PTE1) + pte_index(addr))
+
+#define pte_unmap(pte)         kunmap_atomic(pte, KM_PTE0)
+#define pte_unmap_nested(pte)  kunmap_atomic(pte, KM_PTE1)
+
+/* Encode and decode a nonlinear file mapping entry */
+#define PTE_FILE_MAX_BITS      29
+#define pte_to_pgoff(pte)      (pte_val(pte) >> 3)
+#define pgoff_to_pte(off)      ((pte_t) { ((off) << 3) })
+
+extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+
+/*
+ * When flushing the tlb entry for a page, we also need to flush the hash
+ * table entry.  flush_hash_page is assembler (for speed) in hashtable.S.
+ */
+extern int flush_hash_page(unsigned context, unsigned long va, pte_t *ptep);
+
+/* Add an HPTE to the hash table */
+extern void add_hash_page(unsigned context, unsigned long va, pte_t *ptep);
+
+/*
+ * Encode and decode a swap entry.
+ * Note that the bits we use in a PTE for representing a swap entry
+ * must not include the _PAGE_PRESENT bit, or the _PAGE_HASHPTE bit
+ * (if used).  -- paulus
+ */
+#define __swp_type(entry)              ((entry).val & 0x3f)
+#define __swp_offset(entry)    ((entry).val >> 6)
+#define __swp_entry(type, offset) \
+               ((swp_entry_t) { (type) | ((offset) << 6) })
+#define __pte_to_swp_entry(pte)        ((swp_entry_t) { pte_val(pte) >> 2 })
+#define __swp_entry_to_pte(x)  ((pte_t) { (x).val << 2 })
+
+
+/* CONFIG_APUS */
+/* For virtual address to physical address conversion */
+extern void cache_clear(__u32 addr, int length);
+extern void cache_push(__u32 addr, int length);
+extern int mm_end_of_chunk(unsigned long addr, int len);
+extern unsigned long iopa(unsigned long addr);
+/* extern unsigned long mm_ptov(unsigned long addr) \
+       __attribute__ ((const)); TBD */
+
+/* Values for nocacheflag and cmode */
+/* These are not used by the APUS kernel_map, but prevents
+ * compilation errors.
+ */
+#define        IOMAP_FULL_CACHING      0
+#define        IOMAP_NOCACHE_SER       1
+#define        IOMAP_NOCACHE_NONSER    2
+#define        IOMAP_NO_COPYBACK       3
+
+/*
+ * Map some physical address range into the kernel address space.
+ */
+extern unsigned long kernel_map(unsigned long paddr, unsigned long size,
+                               int nocacheflag, unsigned long *memavailp);
+
+/*
+ * Set cache mode of (kernel space) address range.
+ */
+extern void kernel_set_cachemode(unsigned long address, unsigned long size,
+                               unsigned int cmode);
+
+/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
+#define kern_addr_valid(addr)  (1)
+
+#define io_remap_page_range remap_page_range
+
+/*
+ * No page table caches to initialise
+ */
+#define pgtable_cache_init()   do { } while (0)
+
+void do_page_fault(struct pt_regs *regs, unsigned long address,
+                  unsigned long error_code);
+
+void __init io_block_mapping(unsigned long virt, phys_addr_t phys,
+                            unsigned int size, int flags);
+
+void __init adjust_total_lowmem(void);
+void mapin_ram(void);
+int map_page(unsigned long va, phys_addr_t pa, int flags);
+
+extern int mem_init_done;
+extern unsigned long ioremap_base;
+extern unsigned long ioremap_bot;
+
+asmlinkage void __init mmu_init(void);
+
+void __init *early_get_page(void);
+
+void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle);
+void consistent_free(void *vaddr);
+void consistent_sync(void *vaddr, size_t size, int direction);
+void consistent_sync_page(struct page *page, unsigned long offset,
+       size_t size, int direction);
+#endif /* __ASSEMBLY__ */
+#endif /* __KERNEL__ */
+
+#endif /* CONFIG_MMU */
+
 #ifndef __ASSEMBLY__
 #include <asm-generic/pgtable.h>
 
index b4df41c5dde23fc2cf2e51bf4ba4dea84a3d7719..8c758b231f376780dad5b30a0ae8b8b29da54b00 100644 (file)
@@ -16,7 +16,7 @@
  */
 
 typedef unsigned long  __kernel_ino_t;
-typedef unsigned int   __kernel_mode_t;
+typedef unsigned short __kernel_mode_t;
 typedef unsigned int   __kernel_nlink_t;
 typedef long           __kernel_off_t;
 typedef int            __kernel_pid_t;
index 9329029d26148c5c04d10df919c308eee099b1a9..563c6b9453f030a34344cf0e9d63f1a5dd994318 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Copyright (C) 2008 Michal Simek
- * Copyright (C) 2008 PetaLogix
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -26,14 +26,15 @@ extern const struct seq_operations cpuinfo_op;
 # define cpu_sleep()           do {} while (0)
 # define prepare_to_copy(tsk)  do {} while (0)
 
-# endif /* __ASSEMBLY__ */
-
 #define task_pt_regs(tsk) \
                (((struct pt_regs *)(THREAD_SIZE + task_stack_page(tsk))) - 1)
 
 /* Do necessary setup to start up a newly executed thread. */
 void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp);
 
+# endif /* __ASSEMBLY__ */
+
+# ifndef CONFIG_MMU
 /*
  * User space process size: memory size
  *
@@ -85,4 +86,90 @@ extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
 # define KSTK_EIP(tsk) (0)
 # define KSTK_ESP(tsk) (0)
 
+# else /* CONFIG_MMU */
+
+/*
+ * This is used to define STACK_TOP, and with MMU it must be below
+ * kernel base to select the correct PGD when handling MMU exceptions.
+ */
+# define TASK_SIZE     (CONFIG_KERNEL_START)
+
+/*
+ * This decides where the kernel will search for a free chunk of vm
+ * space during mmap's.
+ */
+# define TASK_UNMAPPED_BASE    (TASK_SIZE / 8 * 3)
+
+# define THREAD_KSP    0
+
+#  ifndef __ASSEMBLY__
+
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+#  define current_text_addr()  ({ __label__ _l; _l: &&_l; })
+
+/* If you change this, you must change the associated assembly-languages
+ * constants defined below, THREAD_*.
+ */
+struct thread_struct {
+       /* kernel stack pointer (must be first field in structure) */
+       unsigned long   ksp;
+       unsigned long   ksp_limit;      /* if ksp <= ksp_limit stack overflow */
+       void            *pgdir;         /* root of page-table tree */
+       struct pt_regs  *regs;          /* Pointer to saved register state */
+};
+
+#  define INIT_THREAD { \
+       .ksp   = sizeof init_stack + (unsigned long)init_stack, \
+       .pgdir = swapper_pg_dir, \
+}
+
+/* Do necessary setup to start up a newly executed thread.  */
+void start_thread(struct pt_regs *regs,
+               unsigned long pc, unsigned long usp);
+
+/* Free all resources held by a thread. */
+extern inline void release_thread(struct task_struct *dead_task)
+{
+}
+
+extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
+
+/* Free current thread data structures etc.  */
+static inline void exit_thread(void)
+{
+}
+
+/* Return saved (kernel) PC of a blocked thread.  */
+#  define thread_saved_pc(tsk) \
+       ((tsk)->thread.regs ? (tsk)->thread.regs->r15 : 0)
+
+unsigned long get_wchan(struct task_struct *p);
+
+/* The size allocated for kernel stacks. This _must_ be a power of two! */
+# define KERNEL_STACK_SIZE     0x2000
+
+/* Return some info about the user process TASK.  */
+#  define task_tos(task)       ((unsigned long)(task) + KERNEL_STACK_SIZE)
+#  define task_regs(task) ((struct pt_regs *)task_tos(task) - 1)
+
+#  define task_pt_regs_plus_args(tsk) \
+       (((void *)task_pt_regs(tsk)) - STATE_SAVE_ARG_SPACE)
+
+#  define task_sp(task)        (task_regs(task)->r1)
+#  define task_pc(task)        (task_regs(task)->pc)
+/* Grotty old names for some.  */
+#  define KSTK_EIP(task)       (task_pc(task))
+#  define KSTK_ESP(task)       (task_sp(task))
+
+/* FIXME */
+#  define deactivate_mm(tsk, mm)       do { } while (0)
+
+#  define STACK_TOP    TASK_SIZE
+#  define STACK_TOP_MAX        STACK_TOP
+
+#  endif /* __ASSEMBLY__ */
+# endif /* CONFIG_MMU */
 #endif /* _ASM_MICROBLAZE_PROCESSOR_H */
index 55015bce5e47ed0c6ec9bc6fa2eef293ddcfbdbd..a917dc517736dd03715235505606e9be5afdf53e 100644 (file)
@@ -10,7 +10,6 @@
 #define _ASM_MICROBLAZE_PTRACE_H
 
 #ifndef __ASSEMBLY__
-#include <linux/types.h>
 
 typedef unsigned long microblaze_reg_t;
 
index 834142d9356fa810813f1100360177835ed69336..68c3afb738779e389a17ba75b0457233058f8bbb 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Copyright (C) 2008 Michal Simek
- * Copyright (C) 2008 PetaLogix
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
 #define FSR_UF         (1<<1) /* Underflow */
 #define FSR_DO         (1<<0) /* Denormalized operand error */
 
+# ifdef CONFIG_MMU
+/* Machine State Register (MSR) Fields */
+# define MSR_UM                (1<<11) /* User Mode */
+# define MSR_UMS       (1<<12) /* User Mode Save */
+# define MSR_VM                (1<<13) /* Virtual Mode */
+# define MSR_VMS       (1<<14) /* Virtual Mode Save */
+
+# define MSR_KERNEL    (MSR_EE | MSR_VM)
+/* # define MSR_USER   (MSR_KERNEL | MSR_UM | MSR_IE) */
+# define MSR_KERNEL_VMS        (MSR_EE | MSR_VMS)
+/* # define MSR_USER_VMS       (MSR_KERNEL_VMS | MSR_UMS | MSR_IE) */
+
+/* Exception State Register (ESR) Fields */
+# define         ESR_DIZ       (1<<11) /* Zone Protection */
+# define         ESR_S         (1<<10) /* Store instruction */
+
+# endif /* CONFIG_MMU */
 #endif /* _ASM_MICROBLAZE_REGISTERS_H */
index 8434a43e542139e316c5c991dc9fc7da5206037d..4487e150b4555d2815417551cbdafc200234bb5a 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -14,6 +16,7 @@
 # ifndef __ASSEMBLY__
 extern char _ssbss[], _esbss[];
 extern unsigned long __ivt_start[], __ivt_end[];
+extern char _etext[], _stext[];
 
 #  ifdef CONFIG_MTD_UCLINUX
 extern char *_ebss;
index 7f5dcc56eea1b586aa3e0a9357195cd4b217fdef..0e7102c3fb117e2f6ebdef2bad277e5ec2c27eec 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Copyright (C) 2008 Michal Simek
- * Copyright (C) 2008 PetaLogix
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -11,7 +11,7 @@
 #ifndef _ASM_MICROBLAZE_SEGMENT_H
 #define _ASM_MICROBLAZE_SEGMENT_H
 
-#ifndef __ASSEMBLY__
+# ifndef __ASSEMBLY__
 
 typedef struct {
        unsigned long seg;
@@ -29,15 +29,21 @@ typedef struct {
  *
  * For non-MMU arch like Microblaze, KERNEL_DS and USER_DS is equal.
  */
-#  define KERNEL_DS    ((mm_segment_t){0})
+# define MAKE_MM_SEG(s)       ((mm_segment_t) { (s) })
+
+#  ifndef CONFIG_MMU
+#  define KERNEL_DS    MAKE_MM_SEG(0)
 #  define USER_DS      KERNEL_DS
+#  else
+#  define KERNEL_DS    MAKE_MM_SEG(0xFFFFFFFF)
+#  define USER_DS      MAKE_MM_SEG(TASK_SIZE - 1)
+#  endif
 
 # define get_ds()      (KERNEL_DS)
 # define get_fs()      (current_thread_info()->addr_limit)
-# define set_fs(x) \
-               do { current_thread_info()->addr_limit = (x); } while (0)
+# define set_fs(val)   (current_thread_info()->addr_limit = (val))
 
-# define segment_eq(a, b)              ((a).seg == (b).seg)
+# define segment_eq(a, b)      ((a).seg == (b).seg)
 
 # endif /* __ASSEMBLY__ */
 #endif /* _ASM_MICROBLAZE_SEGMENT_H */
index 9b98e8e6abae8e7cb020af7d5755bb2ba957b8ed..27f8dafd8c34b25f9f2b2463a62b025611d8de14 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) 2007-2008 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2007-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -18,7 +19,6 @@
 extern unsigned int boot_cpuid; /* move to smp.h */
 
 extern char cmd_line[COMMAND_LINE_SIZE];
-#  endif/* __KERNEL__ */
 
 void early_printk(const char *fmt, ...);
 
@@ -30,6 +30,11 @@ void setup_heartbeat(void);
 
 unsigned long long sched_clock(void);
 
+#   ifdef CONFIG_MMU
+extern void mmu_reset(void);
+extern void early_console_reg_tlb_alloc(unsigned int addr);
+#   endif /* CONFIG_MMU */
+
 void time_init(void);
 void init_IRQ(void);
 void machine_early_init(const char *cmdline, unsigned int ram,
@@ -40,5 +45,6 @@ void machine_shutdown(void);
 void machine_halt(void);
 void machine_power_off(void);
 
+#  endif/* __KERNEL__ */
 # endif /* __ASSEMBLY__ */
 #endif /* _ASM_MICROBLAZE_SETUP_H */
index 9676fad3486cfcf7c1853217a1c8f17a40948fc9..46bc2267d9497a751de01b75324120b384f4ce5f 100644 (file)
@@ -90,7 +90,7 @@
 
 # ifndef __ASSEMBLY__
 # include <linux/types.h>
-# include <asm-generic/signal.h>
+# include <asm-generic/signal-defs.h>
 
 /* Avoid too many header ordering problems. */
 struct siginfo;
index 5f18b8aed220fcb147c65a2965481640b93f988f..a15f77520bfd74ac2dff80e4780d37c7b3574ed9 100644 (file)
 
 #include <linux/posix_types.h>
 
+#define STAT_HAVE_NSEC 1
+
 struct stat {
-       unsigned int    st_dev;
+       unsigned long   st_dev;
        unsigned long   st_ino;
        unsigned int    st_mode;
        unsigned int    st_nlink;
        unsigned int    st_uid;
        unsigned int    st_gid;
-       unsigned int    st_rdev;
-       unsigned long   st_size;
-       unsigned long   st_blksize;
-       unsigned long   st_blocks;
-       unsigned long   st_atime;
-       unsigned long   __unused1; /* unsigned long  st_atime_nsec */
-       unsigned long   st_mtime;
-       unsigned long   __unused2; /* unsigned long  st_mtime_nsec */
-       unsigned long   st_ctime;
-       unsigned long   __unused3; /* unsigned long  st_ctime_nsec */
+       unsigned long   st_rdev;
+       unsigned long   __pad1;
+       long            st_size;
+       int             st_blksize;
+       int             __pad2;
+       long            st_blocks;
+       int             st_atime;
+       unsigned int    st_atime_nsec;
+       int             st_mtime;
+       unsigned int    st_mtime_nsec;
+       int             st_ctime;
+       unsigned int    st_ctime_nsec;
        unsigned long   __unused4;
        unsigned long   __unused5;
 };
 
 struct stat64 {
-       unsigned long long      st_dev;
-       unsigned long   __unused1;
-
-       unsigned long long      st_ino;
-
-       unsigned int    st_mode;
-       unsigned int    st_nlink;
-
-       unsigned int    st_uid;
-       unsigned int    st_gid;
-
-       unsigned long long      st_rdev;
-       unsigned long   __unused3;
-
-       long long       st_size;
-       unsigned long   st_blksize;
-
-       unsigned long   st_blocks; /* No. of 512-byte blocks allocated */
-       unsigned long   __unused4; /* future possible st_blocks high bits */
-
-       unsigned long   st_atime;
-       unsigned long   st_atime_nsec;
-
-       unsigned long   st_mtime;
-       unsigned long   st_mtime_nsec;
-
-       unsigned long   st_ctime;
-       unsigned long   st_ctime_nsec;
-
-       unsigned long   __unused8;
+       unsigned long long      st_dev;         /* Device.  */
+       unsigned long long      st_ino;         /* File serial number.  */
+       unsigned int            st_mode;        /* File mode.  */
+       unsigned int            st_nlink;       /* Link count.  */
+       unsigned int            st_uid;         /* User ID of the file's owner.  */
+       unsigned int            st_gid;         /* Group ID of the file's group. */
+       unsigned long long      st_rdev;        /* Device number, if device.  */
+       unsigned long long      __pad1;
+       long long               st_size;        /* Size of file, in bytes.  */
+       int                     st_blksize;     /* Optimal block size for I/O.  */
+       int                     __pad2;
+       long long               st_blocks;      /* Number 512-byte blocks allocated. */
+       int                     st_atime;       /* Time of last access.  */
+       unsigned int            st_atime_nsec;
+       int                     st_mtime;       /* Time of last modification.  */
+       unsigned int            st_mtime_nsec;
+       int                     st_ctime;       /* Time of last status change.  */
+       unsigned int            st_ctime_nsec;
+       unsigned int            __unused4;
+       unsigned int            __unused5;
 };
 
 #endif /* _ASM_MICROBLAZE_STAT_H */
+
index f7728c90fc186af92a1005400bf99ed7c9ec2387..aec2f59298b879d063e7f48d04ad20602695143d 100644 (file)
@@ -9,7 +9,7 @@
 #ifndef _ASM_MICROBLAZE_STRING_H
 #define _ASM_MICROBLAZE_STRING_H
 
-#ifndef __KERNEL__
+#ifdef __KERNEL__
 
 #define __HAVE_ARCH_MEMSET
 #define __HAVE_ARCH_MEMCPY
index 9cb4ff0edeb2fdf42a166b5feae54b41a18f51cb..ddea9eb31f8da76aa4a3a820a7ee8a9c0744dae7 100644 (file)
@@ -34,6 +34,9 @@ asmlinkage int sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize,
 asmlinkage int sys_sigaction(int sig, const struct old_sigaction *act,
                struct old_sigaction *oact);
 
+asmlinkage long sys_rt_sigaction(int sig, const struct sigaction __user *act,
+               struct sigaction __user *oact, size_t sigsetsize);
+
 asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
                struct pt_regs *regs);
 
index 102d772586689ff209f342ac3e91d8f9bfb986a6..47a46d1fbe26fa4e1ddd1bf7b66f3290ea1facc8 100644 (file)
@@ -81,7 +81,7 @@ struct termio {
 
 #ifdef __KERNEL__
 
-#include <asm-generic/termios.h>
+#include <asm-generic/termios-base.h>
 
 #endif /* __KERNEL__ */
 
index 4c3943e3f40354809f99767c06f7147da9341522..7fac44498445f82595431e75c28fcf61a6731e21 100644 (file)
@@ -122,6 +122,8 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_SINGLESTEP         4
 #define TIF_IRET               5 /* return with iret */
 #define TIF_MEMDIE             6
+#define TIF_SYSCALL_AUDIT      9       /* syscall auditing active */
+#define TIF_SECCOMP            10      /* secure computing */
 #define TIF_FREEZE             14      /* Freezing for suspend */
 
 /* FIXME change in entry.S */
@@ -138,10 +140,17 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_IRET              (1<<TIF_IRET)
 #define _TIF_POLLING_NRFLAG    (1<<TIF_POLLING_NRFLAG)
 #define _TIF_FREEZE            (1<<TIF_FREEZE)
+#define _TIF_SYSCALL_AUDIT     (1 << TIF_SYSCALL_AUDIT)
+#define _TIF_SECCOMP           (1 << TIF_SECCOMP)
 #define _TIF_KERNEL_TRACE      (1 << TIF_KERNEL_TRACE)
 
+/* work to do in syscall trace */
+#define _TIF_WORK_SYSCALL_MASK  (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | \
+                                _TIF_SYSCALL_AUDIT | _TIF_SECCOMP)
+
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK         0x0000FFFE
+
 /* work to do on any return to u-space */
 #define _TIF_ALLWORK_MASK      0x0000FFFF
 
@@ -154,6 +163,17 @@ static inline struct thread_info *current_thread_info(void)
  */
 /* FPU was used by this task this quantum (SMP) */
 #define TS_USEDFPU             0x0001
+#define TS_RESTORE_SIGMASK     0x0002
+
+#ifndef __ASSEMBLY__
+#define HAVE_SET_RESTORE_SIGMASK 1
+static inline void set_restore_sigmask(void)
+{
+       struct thread_info *ti = current_thread_info();
+       ti->status |= TS_RESTORE_SIGMASK;
+       set_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags);
+}
+#endif
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_MICROBLAZE_THREAD_INFO_H */
index d1dfe3791127ba2223f58941e5d18e2328934209..c472d280113285780afb447948ff543bb6a57fd9 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
 
 #include <asm-generic/tlb.h>
 
+#ifdef CONFIG_MMU
+#define tlb_start_vma(tlb, vma)                do { } while (0)
+#define tlb_end_vma(tlb, vma)          do { } while (0)
+#define __tlb_remove_tlb_entry(tlb, pte, address) do { } while (0)
+#endif
+
 #endif /* _ASM_MICROBLAZE_TLB_H */
index d7fe7629001b12ed8f52161d52f574a07c8d6806..eb31a0e8a7725cc843a3c19a16886fbae8e55ed6 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -9,6 +11,50 @@
 #ifndef _ASM_MICROBLAZE_TLBFLUSH_H
 #define _ASM_MICROBLAZE_TLBFLUSH_H
 
+#ifdef CONFIG_MMU
+
+#include <linux/sched.h>
+#include <linux/threads.h>
+#include <asm/processor.h>     /* For TASK_SIZE */
+#include <asm/mmu.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+
+extern void _tlbie(unsigned long address);
+extern void _tlbia(void);
+
+#define __tlbia()      _tlbia()
+
+static inline void local_flush_tlb_all(void)
+       { __tlbia(); }
+static inline void local_flush_tlb_mm(struct mm_struct *mm)
+       { __tlbia(); }
+static inline void local_flush_tlb_page(struct vm_area_struct *vma,
+                               unsigned long vmaddr)
+       { _tlbie(vmaddr); }
+static inline void local_flush_tlb_range(struct vm_area_struct *vma,
+               unsigned long start, unsigned long end)
+       { __tlbia(); }
+
+#define flush_tlb_kernel_range(start, end)     do { } while (0)
+
+#define update_mmu_cache(vma, addr, pte)       do { } while (0)
+
+#define flush_tlb_all local_flush_tlb_all
+#define flush_tlb_mm local_flush_tlb_mm
+#define flush_tlb_page local_flush_tlb_page
+#define flush_tlb_range local_flush_tlb_range
+
+/*
+ * This is called in munmap when we have freed up some page-table
+ * pages.  We don't need to do anything here, there's nothing special
+ * about our page-table pages.  -- paulus
+ */
+static inline void flush_tlb_pgtables(struct mm_struct *mm,
+       unsigned long start, unsigned long end) { }
+
+#else /* CONFIG_MMU */
+
 #define flush_tlb()                            BUG()
 #define flush_tlb_all()                                BUG()
 #define flush_tlb_mm(mm)                       BUG()
@@ -17,4 +63,6 @@
 #define flush_tlb_pgtables(mm, start, end)     BUG()
 #define flush_tlb_kernel_range(start, end)     BUG()
 
+#endif /* CONFIG_MMU */
+
 #endif /* _ASM_MICROBLAZE_TLBFLUSH_H */
index 5a3ffc308e127cd76fb099c9f410c774095f7436..65adad61e7e90b4bbf05cc161caaf4a6a6757290 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
 #define VERIFY_READ    0
 #define VERIFY_WRITE   1
 
+#define __clear_user(addr, n)  (memset((void *)(addr), 0, (n)), 0)
+
+#ifndef CONFIG_MMU
+
 extern int ___range_ok(unsigned long addr, unsigned long size);
 
 #define __range_ok(addr, size) \
@@ -34,68 +40,68 @@ extern int ___range_ok(unsigned long addr, unsigned long size);
 #define access_ok(type, addr, size) (__range_ok((addr), (size)) == 0)
 #define __access_ok(add, size) (__range_ok((addr), (size)) == 0)
 
-extern inline int bad_user_access_length(void)
-{
-       return 0;
-}
+/* Undefined function to trigger linker error */
+extern int bad_user_access_length(void);
+
 /* FIXME this is function for optimalization -> memcpy */
-#define __get_user(var, ptr)                                   \
-       ({                                                      \
-               int __gu_err = 0;                               \
-               switch (sizeof(*(ptr))) {                       \
-               case 1:                                         \
-               case 2:                                         \
-               case 4:                                         \
-                       (var) = *(ptr);                         \
-                       break;                                  \
-               case 8:                                         \
-                       memcpy((void *) &(var), (ptr), 8);      \
-                       break;                                  \
-               default:                                        \
-                       (var) = 0;                              \
-                       __gu_err = __get_user_bad();            \
-                       break;                                  \
-               }                                               \
-               __gu_err;                                       \
-       })
+#define __get_user(var, ptr)                           \
+({                                                     \
+       int __gu_err = 0;                               \
+       switch (sizeof(*(ptr))) {                       \
+       case 1:                                         \
+       case 2:                                         \
+       case 4:                                         \
+               (var) = *(ptr);                         \
+               break;                                  \
+       case 8:                                         \
+               memcpy((void *) &(var), (ptr), 8);      \
+               break;                                  \
+       default:                                        \
+               (var) = 0;                              \
+               __gu_err = __get_user_bad();            \
+               break;                                  \
+       }                                               \
+       __gu_err;                                       \
+})
 
 #define __get_user_bad()       (bad_user_access_length(), (-EFAULT))
 
+/* FIXME is not there defined __pu_val */
 #define __put_user(var, ptr)                                   \
-       ({                                                      \
-               int __pu_err = 0;                               \
-               switch (sizeof(*(ptr))) {                       \
-               case 1:                                         \
-               case 2:                                         \
-               case 4:                                         \
-                       *(ptr) = (var);                         \
-                       break;                                  \
-               case 8: {                                       \
-                       typeof(*(ptr)) __pu_val = var;          \
-                       memcpy(ptr, &__pu_val, sizeof(__pu_val));\
-                       }                                       \
-                       break;                                  \
-               default:                                        \
-                       __pu_err = __put_user_bad();            \
-                       break;                                  \
-               }                                                       \
-               __pu_err;                                               \
-       })
+({                                                             \
+       int __pu_err = 0;                                       \
+       switch (sizeof(*(ptr))) {                               \
+       case 1:                                                 \
+       case 2:                                                 \
+       case 4:                                                 \
+               *(ptr) = (var);                                 \
+               break;                                          \
+       case 8: {                                               \
+               typeof(*(ptr)) __pu_val = (var);                \
+               memcpy(ptr, &__pu_val, sizeof(__pu_val));       \
+               }                                               \
+               break;                                          \
+       default:                                                \
+               __pu_err = __put_user_bad();                    \
+               break;                                          \
+       }                                                       \
+       __pu_err;                                               \
+})
 
 #define __put_user_bad()       (bad_user_access_length(), (-EFAULT))
 
-#define put_user(x, ptr)       __put_user(x, ptr)
-#define get_user(x, ptr)       __get_user(x, ptr)
+#define put_user(x, ptr)       __put_user((x), (ptr))
+#define get_user(x, ptr)       __get_user((x), (ptr))
 
-#define copy_to_user(to, from, n)              (memcpy(to, from, n), 0)
-#define copy_from_user(to, from, n)            (memcpy(to, from, n), 0)
+#define copy_to_user(to, from, n)      (memcpy((to), (from), (n)), 0)
+#define copy_from_user(to, from, n)    (memcpy((to), (from), (n)), 0)
 
-#define __copy_to_user(to, from, n)            (copy_to_user(to, from, n))
-#define __copy_from_user(to, from, n)          (copy_from_user(to, from, n))
-#define __copy_to_user_inatomic(to, from, n)   (__copy_to_user(to, from, n))
-#define __copy_from_user_inatomic(to, from, n) (__copy_from_user(to, from, n))
-
-#define __clear_user(addr, n)  (memset((void *)addr, 0, n), 0)
+#define __copy_to_user(to, from, n)    (copy_to_user((to), (from), (n)))
+#define __copy_from_user(to, from, n)  (copy_from_user((to), (from), (n)))
+#define __copy_to_user_inatomic(to, from, n) \
+                       (__copy_to_user((to), (from), (n)))
+#define __copy_from_user_inatomic(to, from, n) \
+                       (__copy_from_user((to), (from), (n)))
 
 static inline unsigned long clear_user(void *addr, unsigned long size)
 {
@@ -104,13 +110,200 @@ static inline unsigned long clear_user(void *addr, unsigned long size)
        return size;
 }
 
-/* Returns 0 if exception not found and fixup otherwise. */
+/* Returns 0 if exception not found and fixup otherwise.  */
 extern unsigned long search_exception_table(unsigned long);
 
+extern long strncpy_from_user(char *dst, const char *src, long count);
+extern long strnlen_user(const char *src, long count);
+
+#else /* CONFIG_MMU */
+
+/*
+ * Address is valid if:
+ *  - "addr", "addr + size" and "size" are all below the limit
+ */
+#define access_ok(type, addr, size) \
+       (get_fs().seg > (((unsigned long)(addr)) | \
+               (size) | ((unsigned long)(addr) + (size))))
+
+/* || printk("access_ok failed for %s at 0x%08lx (size %d), seg 0x%08x\n",
+ type?"WRITE":"READ",addr,size,get_fs().seg)) */
+
+/*
+ * All the __XXX versions macros/functions below do not perform
+ * access checking. It is assumed that the necessary checks have been
+ * already performed before the finction (macro) is called.
+ */
+
+#define get_user(x, ptr)                                               \
+({                                                                     \
+       access_ok(VERIFY_READ, (ptr), sizeof(*(ptr)))                   \
+               ? __get_user((x), (ptr)) : -EFAULT;                     \
+})
+
+#define put_user(x, ptr)                                               \
+({                                                                     \
+       access_ok(VERIFY_WRITE, (ptr), sizeof(*(ptr)))                  \
+               ? __put_user((x), (ptr)) : -EFAULT;                     \
+})
+
+#define __get_user(x, ptr)                                             \
+({                                                                     \
+       unsigned long __gu_val;                                         \
+       /*unsigned long __gu_ptr = (unsigned long)(ptr);*/              \
+       long __gu_err;                                                  \
+       switch (sizeof(*(ptr))) {                                       \
+       case 1:                                                         \
+               __get_user_asm("lbu", (ptr), __gu_val, __gu_err);       \
+               break;                                                  \
+       case 2:                                                         \
+               __get_user_asm("lhu", (ptr), __gu_val, __gu_err);       \
+               break;                                                  \
+       case 4:                                                         \
+               __get_user_asm("lw", (ptr), __gu_val, __gu_err);        \
+               break;                                                  \
+       default:                                                        \
+               __gu_val = 0; __gu_err = -EINVAL;                       \
+       }                                                               \
+       x = (__typeof__(*(ptr))) __gu_val;                              \
+       __gu_err;                                                       \
+})
+
+#define __get_user_asm(insn, __gu_ptr, __gu_val, __gu_err)             \
+({                                                                     \
+       __asm__ __volatile__ (                                          \
+                       "1:"    insn    " %1, %2, r0;                   \
+                               addk    %0, r0, r0;                     \
+                       2:                                              \
+                       .section .fixup,\"ax\";                         \
+                       3:      brid    2b;                             \
+                               addik   %0, r0, %3;                     \
+                       .previous;                                      \
+                       .section __ex_table,\"a\";                      \
+                       .word   1b,3b;                                  \
+                       .previous;"                                     \
+               : "=r"(__gu_err), "=r"(__gu_val)                        \
+               : "r"(__gu_ptr), "i"(-EFAULT)                           \
+       );                                                              \
+})
+
+#define __put_user(x, ptr)                                             \
+({                                                                     \
+       __typeof__(*(ptr)) __gu_val = x;                                \
+       long __gu_err = 0;                                              \
+       switch (sizeof(__gu_val)) {                                     \
+       case 1:                                                         \
+               __put_user_asm("sb", (ptr), __gu_val, __gu_err);        \
+               break;                                                  \
+       case 2:                                                         \
+               __put_user_asm("sh", (ptr), __gu_val, __gu_err);        \
+               break;                                                  \
+       case 4:                                                         \
+               __put_user_asm("sw", (ptr), __gu_val, __gu_err);        \
+               break;                                                  \
+       case 8:                                                         \
+               __put_user_asm_8((ptr), __gu_val, __gu_err);            \
+               break;                                                  \
+       default:                                                        \
+               __gu_err = -EINVAL;                                     \
+       }                                                               \
+       __gu_err;                                                       \
+})
+
+#define __put_user_asm_8(__gu_ptr, __gu_val, __gu_err) \
+({                                                     \
+__asm__ __volatile__ ("        lwi     %0, %1, 0;              \
+               1:      swi     %0, %2, 0;              \
+                       lwi     %0, %1, 4;              \
+               2:      swi     %0, %2, 4;              \
+                       addk    %0,r0,r0;               \
+               3:                                      \
+               .section .fixup,\"ax\";                 \
+               4:      brid    3b;                     \
+                       addik   %0, r0, %3;             \
+               .previous;                              \
+               .section __ex_table,\"a\";              \
+               .word   1b,4b,2b,4b;                    \
+               .previous;"                             \
+       : "=&r"(__gu_err)                               \
+       : "r"(&__gu_val),                               \
+       "r"(__gu_ptr), "i"(-EFAULT)                     \
+       );                                              \
+})
+
+#define __put_user_asm(insn, __gu_ptr, __gu_val, __gu_err)     \
+({                                                             \
+       __asm__ __volatile__ (                                  \
+                       "1:"    insn    " %1, %2, r0;           \
+                               addk    %0, r0, r0;             \
+                       2:                                      \
+                       .section .fixup,\"ax\";                 \
+                       3:      brid    2b;                     \
+                               addik   %0, r0, %3;             \
+                       .previous;                              \
+                       .section __ex_table,\"a\";              \
+                       .word   1b,3b;                          \
+                       .previous;"                             \
+               : "=r"(__gu_err)                                \
+               : "r"(__gu_val), "r"(__gu_ptr), "i"(-EFAULT)    \
+       );                                                      \
+})
+
+/*
+ * Return: number of not copied bytes, i.e. 0 if OK or non-zero if fail.
+ */
+static inline int clear_user(char *to, int size)
+{
+       if (size && access_ok(VERIFY_WRITE, to, size)) {
+               __asm__ __volatile__ ("                         \
+                               1:                              \
+                                       sb      r0, %2, r0;     \
+                                       addik   %0, %0, -1;     \
+                                       bneid   %0, 1b;         \
+                                       addik   %2, %2, 1;      \
+                               2:                              \
+                               .section __ex_table,\"a\";      \
+                               .word   1b,2b;                  \
+                               .section .text;"                \
+                       : "=r"(size)                            \
+                       : "0"(size), "r"(to)
+               );
+       }
+       return size;
+}
+
+extern unsigned long __copy_tofrom_user(void __user *to,
+               const void __user *from, unsigned long size);
+
+#define copy_to_user(to, from, n)                                      \
+       (access_ok(VERIFY_WRITE, (to), (n)) ?                           \
+               __copy_tofrom_user((void __user *)(to),                 \
+                       (__force const void __user *)(from), (n))       \
+               : -EFAULT)
+
+#define __copy_to_user(to, from, n)    copy_to_user((to), (from), (n))
+#define __copy_to_user_inatomic(to, from, n)   copy_to_user((to), (from), (n))
+
+#define copy_from_user(to, from, n)                                    \
+       (access_ok(VERIFY_READ, (from), (n)) ?                          \
+               __copy_tofrom_user((__force void __user *)(to),         \
+                       (void __user *)(from), (n))                     \
+               : -EFAULT)
+
+#define __copy_from_user(to, from, n)  copy_from_user((to), (from), (n))
+#define __copy_from_user_inatomic(to, from, n) \
+               copy_from_user((to), (from), (n))
+
+extern int __strncpy_user(char *to, const char __user *from, int len);
+extern int __strnlen_user(const char __user *sstr, int len);
+
+#define strncpy_from_user(to, from, len)       \
+               (access_ok(VERIFY_READ, from, 1) ?      \
+                       __strncpy_user(to, from, len) : -EFAULT)
+#define strnlen_user(str, len) \
+               (access_ok(VERIFY_READ, str, 1) ? __strnlen_user(str, len) : 0)
 
-extern long strncpy_from_user(char *dst, const char __user *src, long count);
-extern long strnlen_user(const char __user *src, long count);
-extern long __strncpy_from_user(char *dst, const char __user *src, long count);
+#endif /* CONFIG_MMU */
 
 /*
  * The exception table consists of pairs of addresses: the first is the
index 9d66b640c910635f5c6baa56ba4e7d2c3ba46d3a..3658d91ac0fb95ead00dbc3bca4fd9e0b8d36457 100644 (file)
@@ -12,7 +12,8 @@
 
 # ifdef __KERNEL__
 
-# include <linux/unaligned/access_ok.h>
+# include <linux/unaligned/be_struct.h>
+# include <linux/unaligned/le_byteshift.h>
 # include <linux/unaligned/generic.h>
 
 # define get_unaligned __get_unaligned_be
index da94bec4ecbaa71b428214b4ad41aa31c7e83371..f4a5e19a20eb98f6848e01f3d2708d8e105446b2 100644 (file)
@@ -15,5 +15,6 @@ obj-$(CONFIG_EARLY_PRINTK)    += early_printk.o
 obj-$(CONFIG_SELFMOD)          += selfmod.o
 obj-$(CONFIG_HEART_BEAT)       += heartbeat.o
 obj-$(CONFIG_MODULES)          += microblaze_ksyms.o module.o
+obj-$(CONFIG_MMU)              += misc.o
 
 obj-y  += entry$(MMUEXT).o
index aabd9e9423a651103c4eb379460446ba82297833..7bc7b68f97db3089952ee59bfe8adcff29c95a0b 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2007-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
@@ -68,16 +69,26 @@ int main(int argc, char *argv[])
 
        /* struct task_struct */
        DEFINE(TS_THREAD_INFO, offsetof(struct task_struct, stack));
+#ifdef CONFIG_MMU
+       DEFINE(TASK_STATE, offsetof(struct task_struct, state));
+       DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
+       DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
+       DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
+       DEFINE(TASK_MM, offsetof(struct task_struct, mm));
+       DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
+       DEFINE(TASK_PID, offsetof(struct task_struct, pid));
+       DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
+       DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
+       BLANK();
+
+       DEFINE(PGDIR, offsetof(struct thread_struct, pgdir));
+       BLANK();
+#endif
 
        /* struct thread_info */
        DEFINE(TI_TASK, offsetof(struct thread_info, task));
-       DEFINE(TI_EXEC_DOMAIN, offsetof(struct thread_info, exec_domain));
        DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
-       DEFINE(TI_STATUS, offsetof(struct thread_info, status));
-       DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
-       DEFINE(TI_PRE_COUNT, offsetof(struct thread_info, preempt_count));
        DEFINE(TI_ADDR_LIMIT, offsetof(struct thread_info, addr_limit));
-       DEFINE(TI_RESTART_BLOCK, offsetof(struct thread_info, restart_block));
        DEFINE(TI_CPU_CONTEXT, offsetof(struct thread_info, cpu_context));
        BLANK();
 
index 4b0f0fdb9ca0ba1649703cc7b1ae76055825d680..7de84923ba07d90b60406c05a777030c1204b5a6 100644 (file)
@@ -87,6 +87,9 @@ int __init setup_early_printk(char *opt)
        base_addr = early_uartlite_console();
        if (base_addr) {
                early_console_initialized = 1;
+#ifdef CONFIG_MMU
+               early_console_reg_tlb_alloc(base_addr);
+#endif
                early_printk("early_printk_console is enabled at 0x%08x\n",
                                                        base_addr);
 
index f24b1268baaf5c08b834f9c5c5052db5e063694b..1fce6b803f54905b69ffadca0162a4db0593ed66 100644 (file)
@@ -10,7 +10,7 @@
 
 #include <linux/linkage.h>
 #include <asm/thread_info.h>
-#include <asm/errno.h>
+#include <linux/errno.h>
 #include <asm/entry.h>
 #include <asm/asm-offsets.h>
 #include <asm/registers.h>
diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S
new file mode 100644 (file)
index 0000000..91a0e7b
--- /dev/null
@@ -0,0 +1,1116 @@
+/*
+ * Low-level system-call handling, trap handlers and context-switching
+ *
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
+ * Copyright (C) 2003          John Williams <jwilliams@itee.uq.edu.au>
+ * Copyright (C) 2001,2002     NEC Corporation
+ * Copyright (C) 2001,2002     Miles Bader <miles@gnu.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ * Heavily modified by John Williams for Microblaze
+ */
+
+#include <linux/sys.h>
+#include <linux/linkage.h>
+
+#include <asm/entry.h>
+#include <asm/current.h>
+#include <asm/processor.h>
+#include <asm/exceptions.h>
+#include <asm/asm-offsets.h>
+#include <asm/thread_info.h>
+
+#include <asm/page.h>
+#include <asm/unistd.h>
+
+#include <linux/errno.h>
+#include <asm/signal.h>
+
+/* The size of a state save frame. */
+#define STATE_SAVE_SIZE                (PT_SIZE + STATE_SAVE_ARG_SPACE)
+
+/* The offset of the struct pt_regs in a `state save frame' on the stack. */
+#define PTO    STATE_SAVE_ARG_SPACE /* 24 the space for args */
+
+#define C_ENTRY(name)  .globl name; .align 4; name
+
+/*
+ * Various ways of setting and clearing BIP in flags reg.
+ * This is mucky, but necessary using microblaze version that
+ * allows msr ops to write to BIP
+ */
+#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
+       .macro  clear_bip
+       msrclr  r11, MSR_BIP
+       nop
+       .endm
+
+       .macro  set_bip
+       msrset  r11, MSR_BIP
+       nop
+       .endm
+
+       .macro  clear_eip
+       msrclr  r11, MSR_EIP
+       nop
+       .endm
+
+       .macro  set_ee
+       msrset  r11, MSR_EE
+       nop
+       .endm
+
+       .macro  disable_irq
+       msrclr  r11, MSR_IE
+       nop
+       .endm
+
+       .macro  enable_irq
+       msrset  r11, MSR_IE
+       nop
+       .endm
+
+       .macro  set_ums
+       msrset  r11, MSR_UMS
+       nop
+       msrclr  r11, MSR_VMS
+       nop
+       .endm
+
+       .macro  set_vms
+       msrclr  r11, MSR_UMS
+       nop
+       msrset  r11, MSR_VMS
+       nop
+       .endm
+
+       .macro  clear_vms_ums
+       msrclr  r11, MSR_VMS
+       nop
+       msrclr  r11, MSR_UMS
+       nop
+       .endm
+#else
+       .macro  clear_bip
+       mfs     r11, rmsr
+       nop
+       andi    r11, r11, ~MSR_BIP
+       mts     rmsr, r11
+       nop
+       .endm
+
+       .macro  set_bip
+       mfs     r11, rmsr
+       nop
+       ori     r11, r11, MSR_BIP
+       mts     rmsr, r11
+       nop
+       .endm
+
+       .macro  clear_eip
+       mfs     r11, rmsr
+       nop
+       andi    r11, r11, ~MSR_EIP
+       mts     rmsr, r11
+       nop
+       .endm
+
+       .macro  set_ee
+       mfs     r11, rmsr
+       nop
+       ori     r11, r11, MSR_EE
+       mts     rmsr, r11
+       nop
+       .endm
+
+       .macro  disable_irq
+       mfs     r11, rmsr
+       nop
+       andi    r11, r11, ~MSR_IE
+       mts     rmsr, r11
+       nop
+       .endm
+
+       .macro  enable_irq
+       mfs     r11, rmsr
+       nop
+       ori     r11, r11, MSR_IE
+       mts     rmsr, r11
+       nop
+       .endm
+
+       .macro set_ums
+       mfs     r11, rmsr
+       nop
+       ori     r11, r11, MSR_VMS
+       andni   r11, r11, MSR_UMS
+       mts     rmsr, r11
+       nop
+       .endm
+
+       .macro  set_vms
+       mfs     r11, rmsr
+       nop
+       ori     r11, r11, MSR_VMS
+       andni   r11, r11, MSR_UMS
+       mts     rmsr, r11
+       nop
+       .endm
+
+       .macro  clear_vms_ums
+       mfs     r11, rmsr
+       nop
+       andni   r11, r11, (MSR_VMS|MSR_UMS)
+       mts     rmsr,r11
+       nop
+       .endm
+#endif
+
+/* Define how to call high-level functions. With MMU, virtual mode must be
+ * enabled when calling the high-level function. Clobbers R11.
+ * VM_ON, VM_OFF, DO_JUMP_BIPCLR, DO_CALL
+ */
+
+/* turn on virtual protected mode save */
+#define VM_ON          \
+       set_ums;                \
+       rted    r0, 2f; \
+2: nop;
+
+/* turn off virtual protected mode save and user mode save*/
+#define VM_OFF                 \
+       clear_vms_ums;                  \
+       rted    r0, TOPHYS(1f); \
+1: nop;
+
+#define SAVE_REGS \
+       swi     r2, r1, PTO+PT_R2;      /* Save SDA */                  \
+       swi     r5, r1, PTO+PT_R5;                                      \
+       swi     r6, r1, PTO+PT_R6;                                      \
+       swi     r7, r1, PTO+PT_R7;                                      \
+       swi     r8, r1, PTO+PT_R8;                                      \
+       swi     r9, r1, PTO+PT_R9;                                      \
+       swi     r10, r1, PTO+PT_R10;                                    \
+       swi     r11, r1, PTO+PT_R11;    /* save clobbered regs after rval */\
+       swi     r12, r1, PTO+PT_R12;                                    \
+       swi     r13, r1, PTO+PT_R13;    /* Save SDA2 */                 \
+       swi     r14, r1, PTO+PT_PC;     /* PC, before IRQ/trap */       \
+       swi     r15, r1, PTO+PT_R15;    /* Save LP */                   \
+       swi     r18, r1, PTO+PT_R18;    /* Save asm scratch reg */      \
+       swi     r19, r1, PTO+PT_R19;                                    \
+       swi     r20, r1, PTO+PT_R20;                                    \
+       swi     r21, r1, PTO+PT_R21;                                    \
+       swi     r22, r1, PTO+PT_R22;                                    \
+       swi     r23, r1, PTO+PT_R23;                                    \
+       swi     r24, r1, PTO+PT_R24;                                    \
+       swi     r25, r1, PTO+PT_R25;                                    \
+       swi     r26, r1, PTO+PT_R26;                                    \
+       swi     r27, r1, PTO+PT_R27;                                    \
+       swi     r28, r1, PTO+PT_R28;                                    \
+       swi     r29, r1, PTO+PT_R29;                                    \
+       swi     r30, r1, PTO+PT_R30;                                    \
+       swi     r31, r1, PTO+PT_R31;    /* Save current task reg */     \
+       mfs     r11, rmsr;              /* save MSR */                  \
+       nop;                                                            \
+       swi     r11, r1, PTO+PT_MSR;
+
+#define RESTORE_REGS \
+       lwi     r11, r1, PTO+PT_MSR;                                    \
+       mts     rmsr , r11;                                             \
+       nop;                                                            \
+       lwi     r2, r1, PTO+PT_R2;      /* restore SDA */               \
+       lwi     r5, r1, PTO+PT_R5;                                      \
+       lwi     r6, r1, PTO+PT_R6;                                      \
+       lwi     r7, r1, PTO+PT_R7;                                      \
+       lwi     r8, r1, PTO+PT_R8;                                      \
+       lwi     r9, r1, PTO+PT_R9;                                      \
+       lwi     r10, r1, PTO+PT_R10;                                    \
+       lwi     r11, r1, PTO+PT_R11;    /* restore clobbered regs after rval */\
+       lwi     r12, r1, PTO+PT_R12;                                    \
+       lwi     r13, r1, PTO+PT_R13;    /* restore SDA2 */              \
+       lwi     r14, r1, PTO+PT_PC;     /* RESTORE_LINK PC, before IRQ/trap */\
+       lwi     r15, r1, PTO+PT_R15;    /* restore LP */                \
+       lwi     r18, r1, PTO+PT_R18;    /* restore asm scratch reg */   \
+       lwi     r19, r1, PTO+PT_R19;                                    \
+       lwi     r20, r1, PTO+PT_R20;                                    \
+       lwi     r21, r1, PTO+PT_R21;                                    \
+       lwi     r22, r1, PTO+PT_R22;                                    \
+       lwi     r23, r1, PTO+PT_R23;                                    \
+       lwi     r24, r1, PTO+PT_R24;                                    \
+       lwi     r25, r1, PTO+PT_R25;                                    \
+       lwi     r26, r1, PTO+PT_R26;                                    \
+       lwi     r27, r1, PTO+PT_R27;                                    \
+       lwi     r28, r1, PTO+PT_R28;                                    \
+       lwi     r29, r1, PTO+PT_R29;                                    \
+       lwi     r30, r1, PTO+PT_R30;                                    \
+       lwi     r31, r1, PTO+PT_R31;    /* Restore cur task reg */
+
+.text
+
+/*
+ * User trap.
+ *
+ * System calls are handled here.
+ *
+ * Syscall protocol:
+ * Syscall number in r12, args in r5-r10
+ * Return value in r3
+ *
+ * Trap entered via brki instruction, so BIP bit is set, and interrupts
+ * are masked. This is nice, means we don't have to CLI before state save
+ */
+C_ENTRY(_user_exception):
+       swi     r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
+       addi    r14, r14, 4     /* return address is 4 byte after call */
+       swi     r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* Save r11 */
+
+       lwi     r11, r0, TOPHYS(PER_CPU(KM));/* See if already in kernel mode.*/
+       beqi    r11, 1f;                /* Jump ahead if coming from user */
+/* Kernel-mode state save. */
+       lwi     r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/
+       tophys(r1,r11);
+       swi     r11, r1, (PT_R1-PT_SIZE); /* Save original SP. */
+       lwi     r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */
+
+       addik   r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */
+       SAVE_REGS
+
+       addi    r11, r0, 1;             /* Was in kernel-mode. */
+       swi     r11, r1, PTO+PT_MODE; /* pt_regs -> kernel mode */
+       brid    2f;
+       nop;                            /* Fill delay slot */
+
+/* User-mode state save.  */
+1:
+       lwi     r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */
+       lwi     r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */
+       tophys(r1,r1);
+       lwi     r1, r1, TS_THREAD_INFO; /* get stack from task_struct */
+/* calculate kernel stack pointer from task struct 8k */
+       addik   r1, r1, THREAD_SIZE;
+       tophys(r1,r1);
+
+       addik   r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack.  */
+       SAVE_REGS
+
+       swi     r0, r1, PTO+PT_MODE;                    /* Was in user-mode. */
+       lwi     r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
+       swi     r11, r1, PTO+PT_R1;             /* Store user SP.  */
+       addi    r11, r0, 1;
+       swi     r11, r0, TOPHYS(PER_CPU(KM));   /* Now we're in kernel-mode.  */
+2:     lwi     r31, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */
+       /* Save away the syscall number.  */
+       swi     r12, r1, PTO+PT_R0;
+       tovirt(r1,r1)
+
+       la      r15, r0, ret_from_trap-8
+/* where the trap should return need -8 to adjust for rtsd r15, 8*/
+/* Jump to the appropriate function for the system call number in r12
+ * (r12 is not preserved), or return an error if r12 is not valid. The LP
+ * register should point to the location where
+ * the called function should return.  [note that MAKE_SYS_CALL uses label 1] */
+       /* See if the system call number is valid.  */
+       addi    r11, r12, -__NR_syscalls;
+       bgei    r11,1f;
+       /* Figure out which function to use for this system call.  */
+       /* Note Microblaze barrel shift is optional, so don't rely on it */
+       add     r12, r12, r12;                  /* convert num -> ptr */
+       add     r12, r12, r12;
+
+       /* Trac syscalls and stored them to r0_ram */
+       lwi     r3, r12, 0x400 + TOPHYS(r0_ram)
+       addi    r3, r3, 1
+       swi     r3, r12, 0x400 + TOPHYS(r0_ram)
+
+       lwi     r12, r12, TOPHYS(sys_call_table); /* Function ptr */
+       /* Make the system call.  to r12*/
+       set_vms;
+       rtid    r12, 0;
+       nop;
+       /* The syscall number is invalid, return an error.  */
+1:     VM_ON;  /* RETURN() expects virtual mode*/
+       addi    r3, r0, -ENOSYS;
+       rtsd    r15,8;          /* looks like a normal subroutine return */
+       or      r0, r0, r0
+
+
+/* Entry point used to return from a syscall/trap.  */
+/* We re-enable BIP bit before state restore */
+C_ENTRY(ret_from_trap):
+       set_bip;                        /*  Ints masked for state restore*/
+       lwi     r11, r1, PTO+PT_MODE;
+/* See if returning to kernel mode, if so, skip resched &c.  */
+       bnei    r11, 2f;
+
+       /* We're returning to user mode, so check for various conditions that
+        * trigger rescheduling. */
+       /* Get current task ptr into r11 */
+       add     r11, r0, CURRENT_TASK;  /* Get current task ptr into r11 */
+       lwi     r11, r11, TS_THREAD_INFO;       /* get thread info */
+       lwi     r11, r11, TI_FLAGS;             /* get flags in thread info */
+       andi    r11, r11, _TIF_NEED_RESCHED;
+       beqi    r11, 5f;
+
+       swi     r3, r1, PTO + PT_R3; /* store syscall result */
+       swi     r4, r1, PTO + PT_R4;
+       bralid  r15, schedule;  /* Call scheduler */
+       nop;                            /* delay slot */
+       lwi     r3, r1, PTO + PT_R3; /* restore syscall result */
+       lwi     r4, r1, PTO + PT_R4;
+
+       /* Maybe handle a signal */
+5:     add     r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */
+       lwi     r11, r11, TS_THREAD_INFO;       /* get thread info */
+       lwi     r11, r11, TI_FLAGS;     /* get flags in thread info */
+       andi    r11, r11, _TIF_SIGPENDING;
+       beqi    r11, 1f;                /* Signals to handle, handle them */
+
+       swi     r3, r1, PTO + PT_R3; /* store syscall result */
+       swi     r4, r1, PTO + PT_R4;
+       la      r5, r1, PTO;            /* Arg 1: struct pt_regs *regs */
+       add     r6, r0, r0;             /* Arg 2: sigset_t *oldset */
+       addi    r7, r0, 1;              /* Arg 3: int in_syscall */
+       bralid  r15, do_signal; /* Handle any signals */
+       nop;
+       lwi     r3, r1, PTO + PT_R3; /* restore syscall result */
+       lwi     r4, r1, PTO + PT_R4;
+
+/* Finally, return to user state.  */
+1:     swi     r0, r0, PER_CPU(KM);    /* Now officially in user state. */
+       add     r11, r0, CURRENT_TASK;  /* Get current task ptr into r11 */
+       swi     r11, r0, PER_CPU(CURRENT_SAVE); /* save current */
+       VM_OFF;
+       tophys(r1,r1);
+       RESTORE_REGS;
+       addik   r1, r1, STATE_SAVE_SIZE         /* Clean up stack space.  */
+       lwi     r1, r1, PT_R1 - PT_SIZE;/* Restore user stack pointer. */
+       bri     6f;
+
+/* Return to kernel state.  */
+2:     VM_OFF;
+       tophys(r1,r1);
+       RESTORE_REGS;
+       addik   r1, r1, STATE_SAVE_SIZE         /* Clean up stack space.  */
+       tovirt(r1,r1);
+6:
+TRAP_return:           /* Make global symbol for debugging */
+       rtbd    r14, 0; /* Instructions to return from an IRQ */
+       nop;
+
+
+/* These syscalls need access to the struct pt_regs on the stack, so we
+   implement them in assembly (they're basically all wrappers anyway).  */
+
+C_ENTRY(sys_fork_wrapper):
+       addi    r5, r0, SIGCHLD                 /* Arg 0: flags */
+       lwi     r6, r1, PTO+PT_R1       /* Arg 1: child SP (use parent's) */
+       la      r7, r1, PTO                     /* Arg 2: parent context */
+       add     r8. r0, r0                      /* Arg 3: (unused) */
+       add     r9, r0, r0;                     /* Arg 4: (unused) */
+       add     r10, r0, r0;                    /* Arg 5: (unused) */
+       brid    do_fork         /* Do real work (tail-call) */
+       nop;
+
+/* This the initial entry point for a new child thread, with an appropriate
+   stack in place that makes it look the the child is in the middle of an
+   syscall.  This function is actually `returned to' from switch_thread
+   (copy_thread makes ret_from_fork the return address in each new thread's
+   saved context).  */
+C_ENTRY(ret_from_fork):
+       bralid  r15, schedule_tail; /* ...which is schedule_tail's arg */
+       add     r3, r5, r0;     /* switch_thread returns the prev task */
+                               /* ( in the delay slot ) */
+       add     r3, r0, r0;     /* Child's fork call should return 0. */
+       brid    ret_from_trap;  /* Do normal trap return */
+       nop;
+
+C_ENTRY(sys_vfork_wrapper):
+       la      r5, r1, PTO
+       brid    sys_vfork       /* Do real work (tail-call) */
+       nop
+
+C_ENTRY(sys_clone_wrapper):
+       bnei    r6, 1f;                 /* See if child SP arg (arg 1) is 0. */
+       lwi     r6, r1, PTO+PT_R1;      /* If so, use paret's stack ptr */
+1:     la      r7, r1, PTO;                    /* Arg 2: parent context */
+       add     r8, r0, r0;                     /* Arg 3: (unused) */
+       add     r9, r0, r0;                     /* Arg 4: (unused) */
+       add     r10, r0, r0;                    /* Arg 5: (unused) */
+       brid    do_fork         /* Do real work (tail-call) */
+       nop;
+
+C_ENTRY(sys_execve_wrapper):
+       la      r8, r1, PTO;            /* add user context as 4th arg */
+       brid    sys_execve;     /* Do real work (tail-call).*/
+       nop;
+
+C_ENTRY(sys_sigsuspend_wrapper):
+       swi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
+       swi     r4, r1, PTO+PT_R4;
+       la      r6, r1, PTO;            /* add user context as 2nd arg */
+       bralid  r15, sys_sigsuspend; /* Do real work.*/
+       nop;
+       lwi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
+       lwi     r4, r1, PTO+PT_R4;
+       bri ret_from_trap /* fall through will not work here due to align */
+       nop;
+
+C_ENTRY(sys_rt_sigsuspend_wrapper):
+       swi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
+       swi     r4, r1, PTO+PT_R4;
+       la      r7, r1, PTO;            /* add user context as 3rd arg */
+       brlid   r15, sys_rt_sigsuspend; /* Do real work.*/
+       nop;
+       lwi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
+       lwi     r4, r1, PTO+PT_R4;
+       bri ret_from_trap /* fall through will not work here due to align */
+       nop;
+
+
+C_ENTRY(sys_sigreturn_wrapper):
+       swi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
+       swi     r4, r1, PTO+PT_R4;
+       la      r5, r1, PTO;            /* add user context as 1st arg */
+       brlid   r15, sys_sigreturn;     /* Do real work.*/
+       nop;
+       lwi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
+       lwi     r4, r1, PTO+PT_R4;
+       bri ret_from_trap /* fall through will not work here due to align */
+       nop;
+
+C_ENTRY(sys_rt_sigreturn_wrapper):
+       swi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
+       swi     r4, r1, PTO+PT_R4;
+       la      r5, r1, PTO;            /* add user context as 1st arg */
+       brlid   r15, sys_rt_sigreturn   /* Do real work */
+       nop;
+       lwi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
+       lwi     r4, r1, PTO+PT_R4;
+       bri ret_from_trap /* fall through will not work here due to align */
+       nop;
+
+/*
+ * HW EXCEPTION rutine start
+ */
+
+#define SAVE_STATE     \
+       swi     r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* Save r11 */  \
+       set_bip;        /*equalize initial state for all possible entries*/\
+       clear_eip;                                                      \
+       enable_irq;                                                     \
+       set_ee;                                                         \
+       /* See if already in kernel mode.*/                             \
+       lwi     r11, r0, TOPHYS(PER_CPU(KM));                           \
+       beqi    r11, 1f;                /* Jump ahead if coming from user */\
+       /* Kernel-mode state save.  */                                  \
+       /* Reload kernel stack-ptr. */                                  \
+       lwi     r11, r0, TOPHYS(PER_CPU(ENTRY_SP));                     \
+       tophys(r1,r11);                                                 \
+       swi     r11, r1, (PT_R1-PT_SIZE); /* Save original SP. */       \
+       lwi     r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */\
+       addik   r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack.  */\
+       /* store return registers separately because                    \
+        * this macros is use for others exceptions */                  \
+       swi     r3, r1, PTO + PT_R3;                                    \
+       swi     r4, r1, PTO + PT_R4;                                    \
+       SAVE_REGS                                                       \
+       /* PC, before IRQ/trap - this is one instruction above */       \
+       swi     r17, r1, PTO+PT_PC;                                     \
+                                                                       \
+       addi    r11, r0, 1;             /* Was in kernel-mode.  */      \
+       swi     r11, r1, PTO+PT_MODE;                                   \
+       brid    2f;                                                     \
+       nop;                            /* Fill delay slot */           \
+1:     /* User-mode state save.  */                                    \
+       lwi     r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */\
+       lwi     r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */\
+       tophys(r1,r1);                                                  \
+       lwi     r1, r1, TS_THREAD_INFO; /* get the thread info */       \
+       addik   r1, r1, THREAD_SIZE;    /* calculate kernel stack pointer */\
+       tophys(r1,r1);                                                  \
+                                                                       \
+       addik   r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack.  */\
+       /* store return registers separately because this macros        \
+        * is use for others exceptions */                              \
+       swi     r3, r1, PTO + PT_R3;                                    \
+       swi     r4, r1, PTO + PT_R4;                                    \
+       SAVE_REGS                                                       \
+       /* PC, before IRQ/trap - this is one instruction above FIXME*/  \
+       swi     r17, r1, PTO+PT_PC;                                     \
+                                                                       \
+       swi     r0, r1, PTO+PT_MODE; /* Was in user-mode.  */           \
+       lwi     r11, r0, TOPHYS(PER_CPU(ENTRY_SP));                     \
+       swi     r11, r1, PTO+PT_R1; /* Store user SP.  */               \
+       addi    r11, r0, 1;                                             \
+       swi     r11, r0, TOPHYS(PER_CPU(KM)); /* Now we're in kernel-mode.*/\
+2:     lwi     r31, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */\
+       /* Save away the syscall number.  */                            \
+       swi     r0, r1, PTO+PT_R0;                                      \
+       tovirt(r1,r1)
+
+C_ENTRY(full_exception_trap):
+       swi     r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
+       /* adjust exception address for privileged instruction
+        * for finding where is it */
+       addik   r17, r17, -4
+       SAVE_STATE /* Save registers */
+       /* FIXME this can be store directly in PT_ESR reg.
+        * I tested it but there is a fault */
+       /* where the trap should return need -8 to adjust for rtsd r15, 8 */
+       la      r15, r0, ret_from_exc - 8
+       la      r5, r1, PTO              /* parameter struct pt_regs * regs */
+       mfs     r6, resr
+       nop
+       mfs     r7, rfsr;               /* save FSR */
+       nop
+       la      r12, r0, full_exception
+       set_vms;
+       rtbd    r12, 0;
+       nop;
+
+/*
+ * Unaligned data trap.
+ *
+ * Unaligned data trap last on 4k page is handled here.
+ *
+ * Trap entered via exception, so EE bit is set, and interrupts
+ * are masked.  This is nice, means we don't have to CLI before state save
+ *
+ * The assembler routine is in "arch/microblaze/kernel/hw_exception_handler.S"
+ */
+C_ENTRY(unaligned_data_trap):
+       swi     r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
+       SAVE_STATE              /* Save registers.*/
+       /* where the trap should return need -8 to adjust for rtsd r15, 8 */
+       la      r15, r0, ret_from_exc-8
+       mfs     r3, resr                /* ESR */
+       nop
+       mfs     r4, rear                /* EAR */
+       nop
+       la      r7, r1, PTO             /* parameter struct pt_regs * regs */
+       la      r12, r0, _unaligned_data_exception
+       set_vms;
+       rtbd    r12, 0; /* interrupts enabled */
+       nop;
+
+/*
+ * Page fault traps.
+ *
+ * If the real exception handler (from hw_exception_handler.S) didn't find
+ * the mapping for the process, then we're thrown here to handle such situation.
+ *
+ * Trap entered via exceptions, so EE bit is set, and interrupts
+ * are masked.  This is nice, means we don't have to CLI before state save
+ *
+ * Build a standard exception frame for TLB Access errors.  All TLB exceptions
+ * will bail out to this point if they can't resolve the lightweight TLB fault.
+ *
+ * The C function called is in "arch/microblaze/mm/fault.c", declared as:
+ * void do_page_fault(struct pt_regs *regs,
+ *                             unsigned long address,
+ *                             unsigned long error_code)
+ */
+/* data and intruction trap - which is choose is resolved int fault.c */
+C_ENTRY(page_fault_data_trap):
+       swi     r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
+       SAVE_STATE              /* Save registers.*/
+       /* where the trap should return need -8 to adjust for rtsd r15, 8 */
+       la      r15, r0, ret_from_exc-8
+       la      r5, r1, PTO             /* parameter struct pt_regs * regs */
+       mfs     r6, rear                /* parameter unsigned long address */
+       nop
+       mfs     r7, resr                /* parameter unsigned long error_code */
+       nop
+       la      r12, r0, do_page_fault
+       set_vms;
+       rtbd    r12, 0; /* interrupts enabled */
+       nop;
+
+C_ENTRY(page_fault_instr_trap):
+       swi     r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
+       SAVE_STATE              /* Save registers.*/
+       /* where the trap should return need -8 to adjust for rtsd r15, 8 */
+       la      r15, r0, ret_from_exc-8
+       la      r5, r1, PTO             /* parameter struct pt_regs * regs */
+       mfs     r6, rear                /* parameter unsigned long address */
+       nop
+       ori     r7, r0, 0               /* parameter unsigned long error_code */
+       la      r12, r0, do_page_fault
+       set_vms;
+       rtbd    r12, 0; /* interrupts enabled */
+       nop;
+
+/* Entry point used to return from an exception.  */
+C_ENTRY(ret_from_exc):
+       set_bip;                        /*  Ints masked for state restore*/
+       lwi     r11, r1, PTO+PT_MODE;
+       bnei    r11, 2f;                /* See if returning to kernel mode, */
+                                       /* ... if so, skip resched &c.  */
+
+       /* We're returning to user mode, so check for various conditions that
+          trigger rescheduling. */
+       /* Get current task ptr into r11 */
+       add     r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */
+       lwi     r11, r11, TS_THREAD_INFO;       /* get thread info */
+       lwi     r11, r11, TI_FLAGS;     /* get flags in thread info */
+       andi    r11, r11, _TIF_NEED_RESCHED;
+       beqi    r11, 5f;
+
+/* Call the scheduler before returning from a syscall/trap. */
+       bralid  r15, schedule;  /* Call scheduler */
+       nop;                            /* delay slot */
+
+       /* Maybe handle a signal */
+5:     add     r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */
+       lwi     r11, r11, TS_THREAD_INFO;       /* get thread info */
+       lwi     r11, r11, TI_FLAGS;     /* get flags in thread info */
+       andi    r11, r11, _TIF_SIGPENDING;
+       beqi    r11, 1f;                /* Signals to handle, handle them */
+
+       /*
+        * Handle a signal return; Pending signals should be in r18.
+        *
+        * Not all registers are saved by the normal trap/interrupt entry
+        * points (for instance, call-saved registers (because the normal
+        * C-compiler calling sequence in the kernel makes sure they're
+        * preserved), and call-clobbered registers in the case of
+        * traps), but signal handlers may want to examine or change the
+        * complete register state.  Here we save anything not saved by
+        * the normal entry sequence, so that it may be safely restored
+        * (in a possibly modified form) after do_signal returns.
+        * store return registers separately because this macros is use
+        * for others exceptions */
+       swi     r3, r1, PTO + PT_R3;
+       swi     r4, r1, PTO + PT_R4;
+       la      r5, r1, PTO;            /* Arg 1: struct pt_regs *regs */
+       add     r6, r0, r0;             /* Arg 2: sigset_t *oldset */
+       addi    r7, r0, 0;              /* Arg 3: int in_syscall */
+       bralid  r15, do_signal; /* Handle any signals */
+       nop;
+       lwi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
+       lwi     r4, r1, PTO+PT_R4;
+
+/* Finally, return to user state.  */
+1:     swi     r0, r0, PER_CPU(KM);    /* Now officially in user state. */
+       add     r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */
+       swi     r11, r0, PER_CPU(CURRENT_SAVE); /* save current */
+       VM_OFF;
+       tophys(r1,r1);
+
+       lwi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
+       lwi     r4, r1, PTO+PT_R4;
+       RESTORE_REGS;
+       addik   r1, r1, STATE_SAVE_SIZE         /* Clean up stack space.  */
+
+       lwi     r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer. */
+       bri     6f;
+/* Return to kernel state.  */
+2:     VM_OFF;
+       tophys(r1,r1);
+       lwi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
+       lwi     r4, r1, PTO+PT_R4;
+       RESTORE_REGS;
+       addik   r1, r1, STATE_SAVE_SIZE         /* Clean up stack space.  */
+
+       tovirt(r1,r1);
+6:
+EXC_return:            /* Make global symbol for debugging */
+       rtbd    r14, 0; /* Instructions to return from an IRQ */
+       nop;
+
+/*
+ * HW EXCEPTION rutine end
+ */
+
+/*
+ * Hardware maskable interrupts.
+ *
+ * The stack-pointer (r1) should have already been saved to the memory
+ * location PER_CPU(ENTRY_SP).
+ */
+C_ENTRY(_interrupt):
+/* MS: we are in physical address */
+/* Save registers, switch to proper stack, convert SP to virtual.*/
+       swi     r1, r0, TOPHYS(PER_CPU(ENTRY_SP))
+       swi     r11, r0, TOPHYS(PER_CPU(R11_SAVE));
+       /* MS: See if already in kernel mode. */
+       lwi     r11, r0, TOPHYS(PER_CPU(KM));
+       beqi    r11, 1f; /* MS: Jump ahead if coming from user */
+
+/* Kernel-mode state save. */
+       or      r11, r1, r0
+       tophys(r1,r11); /* MS: I have in r1 physical address where stack is */
+/* MS: Save original SP - position PT_R1 to next stack frame 4 *1 - 152*/
+       swi     r11, r1, (PT_R1 - PT_SIZE);
+/* MS: restore r11 because of saving in SAVE_REGS */
+       lwi     r11, r0, TOPHYS(PER_CPU(R11_SAVE));
+       /* save registers */
+/* MS: Make room on the stack -> activation record */
+       addik   r1, r1, -STATE_SAVE_SIZE;
+/* MS: store return registers separately because
+ * this macros is use for others exceptions */
+       swi     r3, r1, PTO + PT_R3;
+       swi     r4, r1, PTO + PT_R4;
+       SAVE_REGS
+       /* MS: store mode */
+       addi    r11, r0, 1; /* MS: Was in kernel-mode. */
+       swi     r11, r1, PTO + PT_MODE; /* MS: and save it */
+       brid    2f;
+       nop; /* MS: Fill delay slot */
+
+1:
+/* User-mode state save. */
+/* MS: restore r11 -> FIXME move before SAVE_REG */
+       lwi     r11, r0, TOPHYS(PER_CPU(R11_SAVE));
+ /* MS: get the saved current */
+       lwi     r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
+       tophys(r1,r1);
+       lwi     r1, r1, TS_THREAD_INFO;
+       addik   r1, r1, THREAD_SIZE;
+       tophys(r1,r1);
+       /* save registers */
+       addik   r1, r1, -STATE_SAVE_SIZE;
+       swi     r3, r1, PTO+PT_R3;
+       swi     r4, r1, PTO+PT_R4;
+       SAVE_REGS
+       /* calculate mode */
+       swi     r0, r1, PTO + PT_MODE;
+       lwi     r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
+       swi     r11, r1, PTO+PT_R1;
+       /* setup kernel mode to KM */
+       addi    r11, r0, 1;
+       swi     r11, r0, TOPHYS(PER_CPU(KM));
+
+2:
+       lwi     r31, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
+       swi     r0, r1, PTO + PT_R0;
+       tovirt(r1,r1)
+       la      r5, r1, PTO;
+       set_vms;
+       la      r11, r0, do_IRQ;
+       la      r15, r0, irq_call;
+irq_call:rtbd  r11, 0;
+       nop;
+
+/* MS: we are in virtual mode */
+ret_from_irq:
+       lwi     r11, r1, PTO + PT_MODE;
+       bnei    r11, 2f;
+
+       add     r11, r0, CURRENT_TASK;
+       lwi     r11, r11, TS_THREAD_INFO;
+       lwi     r11, r11, TI_FLAGS; /* MS: get flags from thread info */
+       andi    r11, r11, _TIF_NEED_RESCHED;
+       beqi    r11, 5f
+       bralid  r15, schedule;
+       nop; /* delay slot */
+
+    /* Maybe handle a signal */
+5:     add     r11, r0, CURRENT_TASK;
+       lwi     r11, r11, TS_THREAD_INFO; /* MS: get thread info */
+       lwi     r11, r11, TI_FLAGS; /* get flags in thread info */
+       andi    r11, r11, _TIF_SIGPENDING;
+       beqid   r11, no_intr_resched
+/* Handle a signal return; Pending signals should be in r18. */
+       addi    r7, r0, 0; /* Arg 3: int in_syscall */
+       la      r5, r1, PTO; /* Arg 1: struct pt_regs *regs */
+       bralid  r15, do_signal; /* Handle any signals */
+       add     r6, r0, r0; /* Arg 2: sigset_t *oldset */
+
+/* Finally, return to user state. */
+no_intr_resched:
+    /* Disable interrupts, we are now committed to the state restore */
+       disable_irq
+       swi     r0, r0, PER_CPU(KM); /* MS: Now officially in user state. */
+       add     r11, r0, CURRENT_TASK;
+       swi     r11, r0, PER_CPU(CURRENT_SAVE);
+       VM_OFF;
+       tophys(r1,r1);
+       lwi     r3, r1, PTO + PT_R3; /* MS: restore saved r3, r4 registers */
+       lwi     r4, r1, PTO + PT_R4;
+       RESTORE_REGS
+       addik   r1, r1, STATE_SAVE_SIZE /* MS: Clean up stack space. */
+       lwi     r1, r1, PT_R1 - PT_SIZE;
+       bri     6f;
+/* MS: Return to kernel state. */
+2:     VM_OFF /* MS: turn off MMU */
+       tophys(r1,r1)
+       lwi     r3, r1, PTO + PT_R3; /* MS: restore saved r3, r4 registers */
+       lwi     r4, r1, PTO + PT_R4;
+       RESTORE_REGS
+       addik   r1, r1, STATE_SAVE_SIZE /* MS: Clean up stack space. */
+       tovirt(r1,r1);
+6:
+IRQ_return: /* MS: Make global symbol for debugging */
+       rtid    r14, 0
+       nop
+
+/*
+ * `Debug' trap
+ *  We enter dbtrap in "BIP" (breakpoint) mode.
+ *  So we exit the breakpoint mode with an 'rtbd' and proceed with the
+ *  original dbtrap.
+ *  however, wait to save state first
+ */
+C_ENTRY(_debug_exception):
+       /* BIP bit is set on entry, no interrupts can occur */
+       swi     r1, r0, TOPHYS(PER_CPU(ENTRY_SP))
+
+       swi     r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* Save r11 */
+       set_bip;        /*equalize initial state for all possible entries*/
+       clear_eip;
+       enable_irq;
+       lwi     r11, r0, TOPHYS(PER_CPU(KM));/* See if already in kernel mode.*/
+       beqi    r11, 1f;                /* Jump ahead if coming from user */
+       /* Kernel-mode state save.  */
+       lwi     r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/
+       tophys(r1,r11);
+       swi     r11, r1, (PT_R1-PT_SIZE); /* Save original SP. */
+       lwi     r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */
+
+       addik   r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack.  */
+       swi     r3, r1, PTO + PT_R3;
+       swi     r4, r1, PTO + PT_R4;
+       SAVE_REGS;
+
+       addi    r11, r0, 1;             /* Was in kernel-mode.  */
+       swi     r11, r1, PTO + PT_MODE;
+       brid    2f;
+       nop;                            /* Fill delay slot */
+1:      /* User-mode state save.  */
+       lwi     r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */
+       lwi     r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */
+       tophys(r1,r1);
+       lwi     r1, r1, TS_THREAD_INFO; /* get the thread info */
+       addik   r1, r1, THREAD_SIZE;    /* calculate kernel stack pointer */
+       tophys(r1,r1);
+
+       addik   r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack.  */
+       swi     r3, r1, PTO + PT_R3;
+       swi     r4, r1, PTO + PT_R4;
+       SAVE_REGS;
+
+       swi     r0, r1, PTO+PT_MODE; /* Was in user-mode.  */
+       lwi     r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
+       swi     r11, r1, PTO+PT_R1; /* Store user SP.  */
+       addi    r11, r0, 1;
+       swi     r11, r0, TOPHYS(PER_CPU(KM));   /* Now we're in kernel-mode.  */
+2:     lwi     r31, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */
+       /* Save away the syscall number.  */
+       swi     r0, r1, PTO+PT_R0;
+       tovirt(r1,r1)
+
+       addi    r5, r0, SIGTRAP              /* send the trap signal */
+       add     r6, r0, CURRENT_TASK; /* Get current task ptr into r11 */
+       addk    r7, r0, r0                   /* 3rd param zero */
+
+       set_vms;
+       la      r11, r0, send_sig;
+       la      r15, r0, dbtrap_call;
+dbtrap_call:   rtbd    r11, 0;
+       nop;
+
+       set_bip;                        /*  Ints masked for state restore*/
+       lwi     r11, r1, PTO+PT_MODE;
+       bnei    r11, 2f;
+
+       /* Get current task ptr into r11 */
+       add     r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */
+       lwi     r11, r11, TS_THREAD_INFO;       /* get thread info */
+       lwi     r11, r11, TI_FLAGS;     /* get flags in thread info */
+       andi    r11, r11, _TIF_NEED_RESCHED;
+       beqi    r11, 5f;
+
+/* Call the scheduler before returning from a syscall/trap. */
+
+       bralid  r15, schedule;  /* Call scheduler */
+       nop;                            /* delay slot */
+       /* XXX Is PT_DTRACE handling needed here? */
+       /* XXX m68knommu also checks TASK_STATE & TASK_COUNTER here.  */
+
+       /* Maybe handle a signal */
+5:     add     r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */
+       lwi     r11, r11, TS_THREAD_INFO;       /* get thread info */
+       lwi     r11, r11, TI_FLAGS;     /* get flags in thread info */
+       andi    r11, r11, _TIF_SIGPENDING;
+       beqi    r11, 1f;                /* Signals to handle, handle them */
+
+/* Handle a signal return; Pending signals should be in r18.  */
+       /* Not all registers are saved by the normal trap/interrupt entry
+          points (for instance, call-saved registers (because the normal
+          C-compiler calling sequence in the kernel makes sure they're
+          preserved), and call-clobbered registers in the case of
+          traps), but signal handlers may want to examine or change the
+          complete register state.  Here we save anything not saved by
+          the normal entry sequence, so that it may be safely restored
+          (in a possibly modified form) after do_signal returns.  */
+
+       la      r5, r1, PTO;            /* Arg 1: struct pt_regs *regs */
+       add     r6, r0, r0;             /* Arg 2: sigset_t *oldset */
+       addi  r7, r0, 0;        /* Arg 3: int in_syscall */
+       bralid  r15, do_signal; /* Handle any signals */
+       nop;
+
+
+/* Finally, return to user state.  */
+1:     swi     r0, r0, PER_CPU(KM);    /* Now officially in user state. */
+       add     r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */
+       swi     r11, r0, PER_CPU(CURRENT_SAVE); /* save current */
+       VM_OFF;
+       tophys(r1,r1);
+
+       lwi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
+       lwi     r4, r1, PTO+PT_R4;
+       RESTORE_REGS
+       addik   r1, r1, STATE_SAVE_SIZE         /* Clean up stack space.  */
+
+
+       lwi     r1, r1, PT_R1 - PT_SIZE;
+                                       /* Restore user stack pointer. */
+       bri     6f;
+
+/* Return to kernel state.  */
+2:     VM_OFF;
+       tophys(r1,r1);
+       lwi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
+       lwi     r4, r1, PTO+PT_R4;
+       RESTORE_REGS
+       addik   r1, r1, STATE_SAVE_SIZE         /* Clean up stack space.  */
+
+       tovirt(r1,r1);
+6:
+DBTRAP_return:         /* Make global symbol for debugging */
+       rtbd    r14, 0; /* Instructions to return from an IRQ */
+       nop;
+
+
+
+ENTRY(_switch_to)
+       /* prepare return value */
+       addk    r3, r0, r31
+
+       /* save registers in cpu_context */
+       /* use r11 and r12, volatile registers, as temp register */
+       /* give start of cpu_context for previous process */
+       addik   r11, r5, TI_CPU_CONTEXT
+       swi     r1, r11, CC_R1
+       swi     r2, r11, CC_R2
+       /* skip volatile registers.
+        * they are saved on stack when we jumped to _switch_to() */
+       /* dedicated registers */
+       swi     r13, r11, CC_R13
+       swi     r14, r11, CC_R14
+       swi     r15, r11, CC_R15
+       swi     r16, r11, CC_R16
+       swi     r17, r11, CC_R17
+       swi     r18, r11, CC_R18
+       /* save non-volatile registers */
+       swi     r19, r11, CC_R19
+       swi     r20, r11, CC_R20
+       swi     r21, r11, CC_R21
+       swi     r22, r11, CC_R22
+       swi     r23, r11, CC_R23
+       swi     r24, r11, CC_R24
+       swi     r25, r11, CC_R25
+       swi     r26, r11, CC_R26
+       swi     r27, r11, CC_R27
+       swi     r28, r11, CC_R28
+       swi     r29, r11, CC_R29
+       swi     r30, r11, CC_R30
+       /* special purpose registers */
+       mfs     r12, rmsr
+       nop
+       swi     r12, r11, CC_MSR
+       mfs     r12, rear
+       nop
+       swi     r12, r11, CC_EAR
+       mfs     r12, resr
+       nop
+       swi     r12, r11, CC_ESR
+       mfs     r12, rfsr
+       nop
+       swi     r12, r11, CC_FSR
+
+       /* update r31, the current */
+       lwi     r31, r6, TI_TASK/* give me pointer to task which will be next */
+       /* stored it to current_save too */
+       swi     r31, r0, PER_CPU(CURRENT_SAVE)
+
+       /* get new process' cpu context and restore */
+       /* give me start where start context of next task */
+       addik   r11, r6, TI_CPU_CONTEXT
+
+       /* non-volatile registers */
+       lwi     r30, r11, CC_R30
+       lwi     r29, r11, CC_R29
+       lwi     r28, r11, CC_R28
+       lwi     r27, r11, CC_R27
+       lwi     r26, r11, CC_R26
+       lwi     r25, r11, CC_R25
+       lwi     r24, r11, CC_R24
+       lwi     r23, r11, CC_R23
+       lwi     r22, r11, CC_R22
+       lwi     r21, r11, CC_R21
+       lwi     r20, r11, CC_R20
+       lwi     r19, r11, CC_R19
+       /* dedicated registers */
+       lwi     r18, r11, CC_R18
+       lwi     r17, r11, CC_R17
+       lwi     r16, r11, CC_R16
+       lwi     r15, r11, CC_R15
+       lwi     r14, r11, CC_R14
+       lwi     r13, r11, CC_R13
+       /* skip volatile registers */
+       lwi     r2, r11, CC_R2
+       lwi     r1, r11, CC_R1
+
+       /* special purpose registers */
+       lwi     r12, r11, CC_FSR
+       mts     rfsr, r12
+       nop
+       lwi     r12, r11, CC_MSR
+       mts     rmsr, r12
+       nop
+
+       rtsd    r15, 8
+       nop
+
+ENTRY(_reset)
+       brai    0x70; /* Jump back to FS-boot */
+
+ENTRY(_break)
+       mfs     r5, rmsr
+       nop
+       swi     r5, r0, 0x250 + TOPHYS(r0_ram)
+       mfs     r5, resr
+       nop
+       swi     r5, r0, 0x254 + TOPHYS(r0_ram)
+       bri     0
+
+       /* These are compiled and loaded into high memory, then
+        * copied into place in mach_early_setup */
+       .section        .init.ivt, "ax"
+       .org    0x0
+       /* this is very important - here is the reset vector */
+       /* in current MMU branch you don't care what is here - it is
+        * used from bootloader site - but this is correct for FS-BOOT */
+       brai    0x70
+       nop
+       brai    TOPHYS(_user_exception); /* syscall handler */
+       brai    TOPHYS(_interrupt);     /* Interrupt handler */
+       brai    TOPHYS(_break);         /* nmi trap handler */
+       brai    TOPHYS(_hw_exception_handler);  /* HW exception handler */
+
+       .org    0x60
+       brai    TOPHYS(_debug_exception);       /* debug trap handler*/
+
+.section .rodata,"a"
+#include "syscall_table.S"
+
+syscall_table_size=(.-sys_call_table)
+
index 4a8a4064c7ee8919b0a47d3bc2e69774afcd995a..0cb64a31e89a78870319b3f78ac07ca18d16aa80 100644 (file)
@@ -21,9 +21,9 @@
 
 #include <asm/exceptions.h>
 #include <asm/entry.h>         /* For KM CPU var */
-#include <asm/uaccess.h>
-#include <asm/errno.h>
-#include <asm/ptrace.h>
+#include <linux/uaccess.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
 #include <asm/current.h>
 
 #define MICROBLAZE_ILL_OPCODE_EXCEPTION        0x02
@@ -31,7 +31,7 @@
 #define MICROBLAZE_DBUS_EXCEPTION      0x04
 #define MICROBLAZE_DIV_ZERO_EXCEPTION  0x05
 #define MICROBLAZE_FPU_EXCEPTION       0x06
-#define MICROBLAZE_PRIVILEG_EXCEPTION  0x07
+#define MICROBLAZE_PRIVILEGED_EXCEPTION        0x07
 
 static DEFINE_SPINLOCK(die_lock);
 
@@ -66,6 +66,11 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
 asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
                                                        int fsr, int addr)
 {
+#ifdef CONFIG_MMU
+       int code;
+       addr = regs->pc;
+#endif
+
 #if 0
        printk(KERN_WARNING "Exception %02x in %s mode, FSR=%08x PC=%08x ESR=%08x\n",
                        type, user_mode(regs) ? "user" : "kernel", fsr,
@@ -74,7 +79,13 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
 
        switch (type & 0x1F) {
        case MICROBLAZE_ILL_OPCODE_EXCEPTION:
-               _exception(SIGILL, regs, ILL_ILLOPC, addr);
+               if (user_mode(regs)) {
+                       printk(KERN_WARNING "Illegal opcode exception in user mode.\n");
+                       _exception(SIGILL, regs, ILL_ILLOPC, addr);
+                       return;
+               }
+               printk(KERN_WARNING "Illegal opcode exception in kernel mode.\n");
+               die("opcode exception", regs, SIGBUS);
                break;
        case MICROBLAZE_IBUS_EXCEPTION:
                if (user_mode(regs)) {
@@ -95,11 +106,16 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
                die("bus exception", regs, SIGBUS);
                break;
        case MICROBLAZE_DIV_ZERO_EXCEPTION:
-               printk(KERN_WARNING "Divide by zero exception\n");
-               _exception(SIGILL, regs, ILL_ILLOPC, addr);
+               if (user_mode(regs)) {
+                       printk(KERN_WARNING "Divide by zero exception in user mode\n");
+                       _exception(SIGILL, regs, ILL_ILLOPC, addr);
+                       return;
+               }
+               printk(KERN_WARNING "Divide by zero exception in kernel mode.\n");
+               die("Divide by exception", regs, SIGBUS);
                break;
-
        case MICROBLAZE_FPU_EXCEPTION:
+               printk(KERN_WARNING "FPU exception\n");
                /* IEEE FP exception */
                /* I removed fsr variable and use code var for storing fsr */
                if (fsr & FSR_IO)
@@ -115,7 +131,20 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
                _exception(SIGFPE, regs, fsr, addr);
                break;
 
+#ifdef CONFIG_MMU
+       case MICROBLAZE_PRIVILEGED_EXCEPTION:
+               printk(KERN_WARNING "Privileged exception\n");
+               /* "brk r0,r0" - used as debug breakpoint */
+               if (get_user(code, (unsigned long *)regs->pc) == 0
+                       && code == 0x980c0000) {
+                       _exception(SIGTRAP, regs, TRAP_BRKPT, addr);
+               } else {
+                       _exception(SIGILL, regs, ILL_PRVOPC, addr);
+               }
+               break;
+#endif
        default:
+       /* FIXME what to do in unexpected exception */
                printk(KERN_WARNING "Unexpected exception %02x "
                        "PC=%08x in %s mode\n", type, (unsigned int) addr,
                        kernel_mode(regs) ? "kernel" : "user");
index 319dc35fc922e630b471598142f1a98c3564b5d8..e568d6ec621bfa400bc5b506b9ff6afbe327c002 100644 (file)
@@ -3,6 +3,26 @@
  * Copyright (C) 2007-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
  *
+ * MMU code derived from arch/ppc/kernel/head_4xx.S:
+ *    Copyright (c) 1995-1996 Gary Thomas <gdt@linuxppc.org>
+ *      Initial PowerPC version.
+ *    Copyright (c) 1996 Cort Dougan <cort@cs.nmt.edu>
+ *      Rewritten for PReP
+ *    Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
+ *      Low-level exception handers, MMU support, and rewrite.
+ *    Copyright (c) 1997 Dan Malek <dmalek@jlc.net>
+ *      PowerPC 8xx modifications.
+ *    Copyright (c) 1998-1999 TiVo, Inc.
+ *      PowerPC 403GCX modifications.
+ *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *      PowerPC 403GCX/405GP modifications.
+ *    Copyright 2000 MontaVista Software Inc.
+ *     PPC405 modifications
+ *      PowerPC 403GCX/405GP modifications.
+ *     Author: MontaVista Software, Inc.
+ *             frank_rowand@mvista.com or source@mvista.com
+ *             debbie_chu@mvista.com
+ *
  * This file is subject to the terms and conditions of the GNU General Public
  * License. See the file "COPYING" in the main directory of this archive
  * for more details.
 #include <asm/thread_info.h>
 #include <asm/page.h>
 
+#ifdef CONFIG_MMU
+#include <asm/setup.h> /* COMMAND_LINE_SIZE */
+#include <asm/mmu.h>
+#include <asm/processor.h>
+
+.data
+.global empty_zero_page
+.align 12
+empty_zero_page:
+       .space  4096
+.global swapper_pg_dir
+swapper_pg_dir:
+       .space  4096
+
+#endif /* CONFIG_MMU */
+
        .text
 ENTRY(_start)
        mfs     r1, rmsr
@@ -32,6 +68,123 @@ _copy_fdt:
        addik   r3, r3, -4 /* descrement loop */
 no_fdt_arg:
 
+#ifdef CONFIG_MMU
+
+#ifndef CONFIG_CMDLINE_BOOL
+/*
+ * handling command line
+ * copy command line to __init_end. There is space for storing command line.
+ */
+       or      r6, r0, r0              /* incremment */
+       ori     r4, r0, __init_end      /* load address of command line */
+       tophys(r4,r4)                   /* convert to phys address */
+       ori     r3, r0, COMMAND_LINE_SIZE - 1 /* number of loops */
+_copy_command_line:
+       lbu     r7, r5, r6 /* r7=r5+r6 - r5 contain pointer to command line */
+       sb      r7, r4, r6              /* addr[r4+r6]= r7*/
+       addik   r6, r6, 1               /* increment counting */
+       bgtid   r3, _copy_command_line  /* loop for all entries       */
+       addik   r3, r3, -1              /* descrement loop */
+       addik   r5, r4, 0               /* add new space for command line */
+       tovirt(r5,r5)
+#endif /* CONFIG_CMDLINE_BOOL */
+
+#ifdef NOT_COMPILE
+/* save bram context */
+       or      r6, r0, r0                              /* incremment */
+       ori     r4, r0, TOPHYS(_bram_load_start)        /* save bram context */
+       ori     r3, r0, (LMB_SIZE - 4)
+_copy_bram:
+       lw      r7, r0, r6              /* r7 = r0 + r6 */
+       sw      r7, r4, r6              /* addr[r4 + r6] = r7*/
+       addik   r6, r6, 4               /* increment counting */
+       bgtid   r3, _copy_bram          /* loop for all entries */
+       addik   r3, r3, -4              /* descrement loop */
+#endif
+       /* We have to turn on the MMU right away. */
+
+       /*
+        * Set up the initial MMU state so we can do the first level of
+        * kernel initialization.  This maps the first 16 MBytes of memory 1:1
+        * virtual to physical.
+        */
+       nop
+       addik   r3, r0, 63              /* Invalidate all TLB entries */
+_invalidate:
+       mts     rtlbx, r3
+       mts     rtlbhi, r0                      /* flush: ensure V is clear   */
+       bgtid   r3, _invalidate         /* loop for all entries       */
+       addik   r3, r3, -1
+       /* sync */
+
+       /*
+        * We should still be executing code at physical address area
+        * RAM_BASEADDR at this point. However, kernel code is at
+        * a virtual address. So, set up a TLB mapping to cover this once
+        * translation is enabled.
+        */
+
+       addik   r3,r0, CONFIG_KERNEL_START /* Load the kernel virtual address */
+       tophys(r4,r3)                   /* Load the kernel physical address */
+
+       mts     rpid,r0                 /* Load the kernel PID */
+       nop
+       bri     4
+
+       /*
+        * Configure and load two entries into TLB slots 0 and 1.
+        * In case we are pinning TLBs, these are reserved in by the
+        * other TLB functions.  If not reserving, then it doesn't
+        * matter where they are loaded.
+        */
+       andi    r4,r4,0xfffffc00        /* Mask off the real page number */
+       ori     r4,r4,(TLB_WR | TLB_EX) /* Set the write and execute bits */
+
+       andi    r3,r3,0xfffffc00        /* Mask off the effective page number */
+       ori     r3,r3,(TLB_VALID | TLB_PAGESZ(PAGESZ_16M))
+
+       mts     rtlbx,r0                /* TLB slow 0 */
+
+       mts     rtlblo,r4               /* Load the data portion of the entry */
+       mts     rtlbhi,r3               /* Load the tag portion of the entry */
+
+       addik   r4, r4, 0x01000000      /* Map next 16 M entries */
+       addik   r3, r3, 0x01000000
+
+       ori     r6,r0,1                 /* TLB slot 1 */
+       mts     rtlbx,r6
+
+       mts     rtlblo,r4               /* Load the data portion of the entry */
+       mts     rtlbhi,r3               /* Load the tag portion of the entry */
+
+       /*
+        * Load a TLB entry for LMB, since we need access to
+        * the exception vectors, using a 4k real==virtual mapping.
+        */
+       ori     r6,r0,3                 /* TLB slot 3 */
+       mts     rtlbx,r6
+
+       ori     r4,r0,(TLB_WR | TLB_EX)
+       ori     r3,r0,(TLB_VALID | TLB_PAGESZ(PAGESZ_4K))
+
+       mts     rtlblo,r4               /* Load the data portion of the entry */
+       mts     rtlbhi,r3               /* Load the tag portion of the entry */
+
+       /*
+        * We now have the lower 16 Meg of RAM mapped into TLB entries, and the
+        * caches ready to work.
+        */
+turn_on_mmu:
+       ori     r15,r0,start_here
+       ori     r4,r0,MSR_KERNEL_VMS
+       mts     rmsr,r4
+       nop
+       rted    r15,0                   /* enables MMU */
+       nop
+
+start_here:
+#endif /* CONFIG_MMU */
+
        /* Initialize small data anchors */
        la      r13, r0, _KERNEL_SDA_BASE_
        la      r2, r0, _KERNEL_SDA2_BASE_
@@ -51,6 +204,43 @@ no_fdt_arg:
        brald   r15, r8
        nop
 
+#ifndef CONFIG_MMU
        la      r15, r0, machine_halt
        braid   start_kernel
        nop
+#else
+       /*
+        * Initialize the MMU.
+        */
+       bralid  r15, mmu_init
+       nop
+
+       /* Go back to running unmapped so we can load up new values
+        * and change to using our exception vectors.
+        * On the MicroBlaze, all we invalidate the used TLB entries to clear
+        * the old 16M byte TLB mappings.
+        */
+       ori     r15,r0,TOPHYS(kernel_load_context)
+       ori     r4,r0,MSR_KERNEL
+       mts     rmsr,r4
+       nop
+       bri     4
+       rted    r15,0
+       nop
+
+       /* Load up the kernel context */
+kernel_load_context:
+       # Keep entry 0 and 1 valid. Entry 3 mapped to LMB can go away.
+       ori     r5,r0,3
+       mts     rtlbx,r5
+       nop
+       mts     rtlbhi,r0
+       nop
+       addi    r15, r0, machine_halt
+       ori     r17, r0, start_kernel
+       ori     r4, r0, MSR_KERNEL_VMS
+       mts     rmsr, r4
+       nop
+       rted    r17, 0          /* enable MMU and jump to start_kernel */
+       nop
+#endif /* CONFIG_MMU */
index cf9486d998380df08d95f5e8e413491fd583a92a..9d591cd74fc221293fa1d647f530c0e29120dbe4 100644 (file)
  *   - Illegal instruction opcode
  *   - Divide-by-zero
  *
+ *   - Privileged instruction exception (MMU)
+ *   - Data storage exception (MMU)
+ *   - Instruction storage exception (MMU)
+ *   - Data TLB miss exception (MMU)
+ *   - Instruction TLB miss exception (MMU)
+ *
  * Note we disable interrupts during exception handling, otherwise we will
  * possibly get multiple re-entrancy if interrupt handles themselves cause
  * exceptions. JW
 #include <asm/asm-offsets.h>
 
 /* Helpful Macros */
+#ifndef CONFIG_MMU
 #define EX_HANDLER_STACK_SIZ   (4*19)
+#endif
 #define NUM_TO_REG(num)                r ## num
 
+#ifdef CONFIG_MMU
+/* FIXME you can't change first load of MSR because there is
+ * hardcoded jump bri 4 */
+       #define RESTORE_STATE                   \
+               lwi     r3, r1, PT_R3;          \
+               lwi     r4, r1, PT_R4;          \
+               lwi     r5, r1, PT_R5;          \
+               lwi     r6, r1, PT_R6;          \
+               lwi     r11, r1, PT_R11;        \
+               lwi     r31, r1, PT_R31;        \
+               lwi     r1, r0, TOPHYS(r0_ram + 0);
+#endif /* CONFIG_MMU */
+
 #define LWREG_NOP                      \
        bri     ex_handler_unhandled;   \
        nop;
        or      r3, r0, NUM_TO_REG (regnum);            \
        bri     ex_sw_tail;
 
+#ifdef CONFIG_MMU
+       #define R3_TO_LWREG_VM_V(regnum)                \
+               brid    ex_lw_end_vm;                   \
+               swi     r3, r7, 4 * regnum;
+
+       #define R3_TO_LWREG_VM(regnum)                  \
+               brid    ex_lw_end_vm;                   \
+               or      NUM_TO_REG (regnum), r0, r3;
+
+       #define SWREG_TO_R3_VM_V(regnum)                \
+               brid    ex_sw_tail_vm;                  \
+               lwi     r3, r7, 4 * regnum;
+
+       #define SWREG_TO_R3_VM(regnum)                  \
+               brid    ex_sw_tail_vm;                  \
+               or      r3, r0, NUM_TO_REG (regnum);
+
+       /* Shift right instruction depending on available configuration */
+       #if CONFIG_XILINX_MICROBLAZE0_USE_BARREL > 0
+       #define BSRLI(rD, rA, imm)      \
+               bsrli rD, rA, imm
+       #elif CONFIG_XILINX_MICROBLAZE0_USE_DIV > 0
+       #define BSRLI(rD, rA, imm)      \
+               ori rD, r0, (1 << imm); \
+               idivu rD, rD, rA
+       #else
+       #define BSRLI(rD, rA, imm) BSRLI ## imm (rD, rA)
+       /* Only the used shift constants defined here - add more if needed */
+       #define BSRLI2(rD, rA)                          \
+               srl rD, rA;             /* << 1 */      \
+               srl rD, rD;             /* << 2 */
+       #define BSRLI10(rD, rA)                         \
+               srl rD, rA;             /* << 1 */      \
+               srl rD, rD;             /* << 2 */      \
+               srl rD, rD;             /* << 3 */      \
+               srl rD, rD;             /* << 4 */      \
+               srl rD, rD;             /* << 5 */      \
+               srl rD, rD;             /* << 6 */      \
+               srl rD, rD;             /* << 7 */      \
+               srl rD, rD;             /* << 8 */      \
+               srl rD, rD;             /* << 9 */      \
+               srl rD, rD              /* << 10 */
+       #define BSRLI20(rD, rA)         \
+               BSRLI10(rD, rA);        \
+               BSRLI10(rD, rD)
+       #endif
+#endif /* CONFIG_MMU */
+
 .extern other_exception_handler /* Defined in exception.c */
 
 /*
 
 /* wrappers to restore state before coming to entry.S */
 
+#ifdef CONFIG_MMU
+.section .rodata
+.align 4
+_MB_HW_ExceptionVectorTable:
+/*  0 - Undefined */
+       .long   TOPHYS(ex_handler_unhandled)
+/*  1 - Unaligned data access exception */
+       .long   TOPHYS(handle_unaligned_ex)
+/*  2 - Illegal op-code exception */
+       .long   TOPHYS(full_exception_trapw)
+/*  3 - Instruction bus error exception */
+       .long   TOPHYS(full_exception_trapw)
+/*  4 - Data bus error exception */
+       .long   TOPHYS(full_exception_trapw)
+/*  5 - Divide by zero exception */
+       .long   TOPHYS(full_exception_trapw)
+/*  6 - Floating point unit exception */
+       .long   TOPHYS(full_exception_trapw)
+/*  7 - Privileged instruction exception */
+       .long   TOPHYS(full_exception_trapw)
+/*  8 - 15 - Undefined */
+       .long   TOPHYS(ex_handler_unhandled)
+       .long   TOPHYS(ex_handler_unhandled)
+       .long   TOPHYS(ex_handler_unhandled)
+       .long   TOPHYS(ex_handler_unhandled)
+       .long   TOPHYS(ex_handler_unhandled)
+       .long   TOPHYS(ex_handler_unhandled)
+       .long   TOPHYS(ex_handler_unhandled)
+       .long   TOPHYS(ex_handler_unhandled)
+/* 16 - Data storage exception */
+       .long   TOPHYS(handle_data_storage_exception)
+/* 17 - Instruction storage exception */
+       .long   TOPHYS(handle_instruction_storage_exception)
+/* 18 - Data TLB miss exception */
+       .long   TOPHYS(handle_data_tlb_miss_exception)
+/* 19 - Instruction TLB miss exception */
+       .long   TOPHYS(handle_instruction_tlb_miss_exception)
+/* 20 - 31 - Undefined */
+       .long   TOPHYS(ex_handler_unhandled)
+       .long   TOPHYS(ex_handler_unhandled)
+       .long   TOPHYS(ex_handler_unhandled)
+       .long   TOPHYS(ex_handler_unhandled)
+       .long   TOPHYS(ex_handler_unhandled)
+       .long   TOPHYS(ex_handler_unhandled)
+       .long   TOPHYS(ex_handler_unhandled)
+       .long   TOPHYS(ex_handler_unhandled)
+       .long   TOPHYS(ex_handler_unhandled)
+       .long   TOPHYS(ex_handler_unhandled)
+       .long   TOPHYS(ex_handler_unhandled)
+       .long   TOPHYS(ex_handler_unhandled)
+#endif
+
 .global _hw_exception_handler
 .section .text
 .align 4
 .ent _hw_exception_handler
 _hw_exception_handler:
+#ifndef CONFIG_MMU
        addik   r1, r1, -(EX_HANDLER_STACK_SIZ); /* Create stack frame */
+#else
+       swi     r1, r0, TOPHYS(r0_ram + 0); /* GET_SP */
+       /* Save date to kernel memory. Here is the problem
+        * when you came from user space */
+       ori     r1, r0, TOPHYS(r0_ram + 28);
+#endif
        swi     r3, r1, PT_R3
        swi     r4, r1, PT_R4
        swi     r5, r1, PT_R5
        swi     r6, r1, PT_R6
 
-       mfs     r5, rmsr;
-       nop
-       swi     r5, r1, 0;
-       mfs     r4, rbtr        /* Save BTR before jumping to handler */
-       nop
+#ifdef CONFIG_MMU
+       swi     r11, r1, PT_R11
+       swi     r31, r1, PT_R31
+       lwi     r31, r0, TOPHYS(PER_CPU(CURRENT_SAVE)) /* get saved current */
+#endif
+
        mfs     r3, resr
        nop
+       mfs     r4, rear;
+       nop
 
+#ifndef CONFIG_MMU
        andi    r5, r3, 0x1000;         /* Check ESR[DS] */
        beqi    r5, not_in_delay_slot;  /* Branch if ESR[DS] not set */
        mfs     r17, rbtr;      /* ESR[DS] set - return address in BTR */
        nop
 not_in_delay_slot:
        swi     r17, r1, PT_R17
+#endif
 
        andi    r5, r3, 0x1F;           /* Extract ESR[EXC] */
 
+#ifdef CONFIG_MMU
+       /* Calculate exception vector offset = r5 << 2 */
+       addk    r6, r5, r5; /* << 1 */
+       addk    r6, r6, r6; /* << 2 */
+
+/* counting which exception happen */
+       lwi     r5, r0, 0x200 + TOPHYS(r0_ram)
+       addi    r5, r5, 1
+       swi     r5, r0, 0x200 + TOPHYS(r0_ram)
+       lwi     r5, r6, 0x200 + TOPHYS(r0_ram)
+       addi    r5, r5, 1
+       swi     r5, r6, 0x200 + TOPHYS(r0_ram)
+/* end */
+       /* Load the HW Exception vector */
+       lwi     r6, r6, TOPHYS(_MB_HW_ExceptionVectorTable)
+       bra     r6
+
+full_exception_trapw:
+       RESTORE_STATE
+       bri     full_exception_trap
+#else
        /* Exceptions enabled here. This will allow nested exceptions */
        mfs     r6, rmsr;
        nop
@@ -254,6 +408,7 @@ handle_other_ex: /* Handle Other exceptions here */
        lwi     r18, r1, PT_R18
 
        bri     ex_handler_done; /* Complete exception handling */
+#endif
 
 /* 0x01 - Unaligned data access exception
  * This occurs when a word access is not aligned on a word boundary,
@@ -265,11 +420,28 @@ handle_other_ex: /* Handle Other exceptions here */
 handle_unaligned_ex:
        /* Working registers already saved: R3, R4, R5, R6
         *  R3 = ESR
-        *  R4 = BTR
+        *  R4 = EAR
         */
-       mfs     r4, rear;
+#ifdef CONFIG_MMU
+       andi    r6, r3, 0x1000                  /* Check ESR[DS] */
+       beqi    r6, _no_delayslot               /* Branch if ESR[DS] not set */
+       mfs     r17, rbtr;      /* ESR[DS] set - return address in BTR */
        nop
+_no_delayslot:
+#endif
+
+#ifdef CONFIG_MMU
+       /* Check if unaligned address is last on a 4k page */
+               andi    r5, r4, 0xffc
+               xori    r5, r5, 0xffc
+               bnei    r5, _unaligned_ex2
+       _unaligned_ex1:
+               RESTORE_STATE;
+/* Another page must be accessed or physical address not in page table */
+               bri     unaligned_data_trap
 
+       _unaligned_ex2:
+#endif
        andi    r6, r3, 0x3E0; /* Mask and extract the register operand */
        srl     r6, r6; /* r6 >> 5 */
        srl     r6, r6;
@@ -278,6 +450,45 @@ handle_unaligned_ex:
        srl     r6, r6;
        /* Store the register operand in a temporary location */
        sbi     r6, r0, TOPHYS(ex_reg_op);
+#ifdef CONFIG_MMU
+       /* Get physical address */
+       /* If we are faulting a kernel address, we have to use the
+        * kernel page tables.
+        */
+       ori     r5, r0, CONFIG_KERNEL_START
+       cmpu    r5, r4, r5
+       bgti    r5, _unaligned_ex3
+       ori     r5, r0, swapper_pg_dir
+       bri     _unaligned_ex4
+
+       /* Get the PGD for the current thread. */
+_unaligned_ex3: /* user thread */
+       addi    r5 ,CURRENT_TASK, TOPHYS(0); /* get current task address */
+       lwi     r5, r5, TASK_THREAD + PGDIR
+_unaligned_ex4:
+       tophys(r5,r5)
+       BSRLI(r6,r4,20)                 /* Create L1 (pgdir/pmd) address */
+       andi    r6, r6, 0xffc
+/* Assume pgdir aligned on 4K boundary, no need for "andi r5,r5,0xfffff003" */
+       or      r5, r5, r6
+       lwi     r6, r5, 0               /* Get L1 entry */
+       andi    r5, r6, 0xfffff000      /* Extract L2 (pte) base address. */
+       beqi    r5, _unaligned_ex1      /* Bail if no table */
+
+       tophys(r5,r5)
+       BSRLI(r6,r4,10)                 /* Compute PTE address */
+       andi    r6, r6, 0xffc
+       andi    r5, r5, 0xfffff003
+       or      r5, r5, r6
+       lwi     r5, r5, 0               /* Get Linux PTE */
+
+       andi    r6, r5, _PAGE_PRESENT
+       beqi    r6, _unaligned_ex1      /* Bail if no page */
+
+       andi    r5, r5, 0xfffff000      /* Extract RPN */
+       andi    r4, r4, 0x00000fff      /* Extract offset */
+       or      r4, r4, r5              /* Create physical address */
+#endif /* CONFIG_MMU */
 
        andi    r6, r3, 0x400; /* Extract ESR[S] */
        bnei    r6, ex_sw;
@@ -355,6 +566,7 @@ ex_shw:
 ex_sw_end: /* Exception handling of store word, ends. */
 
 ex_handler_done:
+#ifndef CONFIG_MMU
        lwi     r5, r1, 0 /* RMSR */
        mts     rmsr, r5
        nop
@@ -366,13 +578,455 @@ ex_handler_done:
 
        rted    r17, 0
        addik   r1, r1, (EX_HANDLER_STACK_SIZ); /* Restore stack frame */
+#else
+       RESTORE_STATE;
+       rted    r17, 0
+       nop
+#endif
+
+#ifdef CONFIG_MMU
+       /* Exception vector entry code. This code runs with address translation
+        * turned off (i.e. using physical addresses). */
+
+       /* Exception vectors. */
+
+       /* 0x10 - Data Storage Exception
+        * This happens for just a few reasons. U0 set (but we don't do that),
+        * or zone protection fault (user violation, write to protected page).
+        * If this is just an update of modified status, we do that quickly
+        * and exit. Otherwise, we call heavyweight functions to do the work.
+        */
+       handle_data_storage_exception:
+               /* Working registers already saved: R3, R4, R5, R6
+                * R3 = ESR
+                */
+               mfs     r11, rpid
+               nop
+               bri     4
+               mfs     r3, rear                /* Get faulting address */
+               nop
+               /* If we are faulting a kernel address, we have to use the
+                * kernel page tables.
+                */
+               ori     r4, r0, CONFIG_KERNEL_START
+               cmpu    r4, r3, r4
+               bgti    r4, ex3
+               /* First, check if it was a zone fault (which means a user
+                * tried to access a kernel or read-protected page - always
+                * a SEGV). All other faults here must be stores, so no
+                * need to check ESR_S as well. */
+               mfs     r4, resr
+               nop
+               andi    r4, r4, 0x800           /* ESR_Z - zone protection */
+               bnei    r4, ex2
+
+               ori     r4, r0, swapper_pg_dir
+               mts     rpid, r0                /* TLB will have 0 TID */
+               nop
+               bri     ex4
+
+               /* Get the PGD for the current thread. */
+       ex3:
+               /* First, check if it was a zone fault (which means a user
+                * tried to access a kernel or read-protected page - always
+                * a SEGV). All other faults here must be stores, so no
+                * need to check ESR_S as well. */
+               mfs     r4, resr
+               nop
+               andi    r4, r4, 0x800           /* ESR_Z */
+               bnei    r4, ex2
+               /* get current task address */
+               addi    r4 ,CURRENT_TASK, TOPHYS(0);
+               lwi     r4, r4, TASK_THREAD+PGDIR
+       ex4:
+               tophys(r4,r4)
+               BSRLI(r5,r3,20)         /* Create L1 (pgdir/pmd) address */
+               andi    r5, r5, 0xffc
+/* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */
+               or      r4, r4, r5
+               lwi     r4, r4, 0               /* Get L1 entry */
+               andi    r5, r4, 0xfffff000 /* Extract L2 (pte) base address */
+               beqi    r5, ex2                 /* Bail if no table */
+
+               tophys(r5,r5)
+               BSRLI(r6,r3,10)                 /* Compute PTE address */
+               andi    r6, r6, 0xffc
+               andi    r5, r5, 0xfffff003
+               or      r5, r5, r6
+               lwi     r4, r5, 0               /* Get Linux PTE */
+
+               andi    r6, r4, _PAGE_RW        /* Is it writeable? */
+               beqi    r6, ex2                 /* Bail if not */
+
+               /* Update 'changed' */
+               ori     r4, r4, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE
+               swi     r4, r5, 0               /* Update Linux page table */
+
+               /* Most of the Linux PTE is ready to load into the TLB LO.
+                * We set ZSEL, where only the LS-bit determines user access.
+                * We set execute, because we don't have the granularity to
+                * properly set this at the page level (Linux problem).
+                * If shared is set, we cause a zero PID->TID load.
+                * Many of these bits are software only. Bits we don't set
+                * here we (properly should) assume have the appropriate value.
+                */
+               andni   r4, r4, 0x0ce2          /* Make sure 20, 21 are zero */
+               ori     r4, r4, _PAGE_HWEXEC    /* make it executable */
+
+               /* find the TLB index that caused the fault. It has to be here*/
+               mts     rtlbsx, r3
+               nop
+               mfs     r5, rtlbx               /* DEBUG: TBD */
+               nop
+               mts     rtlblo, r4              /* Load TLB LO */
+               nop
+                                               /* Will sync shadow TLBs */
+
+               /* Done...restore registers and get out of here. */
+               mts     rpid, r11
+               nop
+               bri 4
+
+               RESTORE_STATE;
+               rted    r17, 0
+               nop
+       ex2:
+               /* The bailout. Restore registers to pre-exception conditions
+                * and call the heavyweights to help us out. */
+               mts     rpid, r11
+               nop
+               bri 4
+               RESTORE_STATE;
+               bri     page_fault_data_trap
+
+
+       /* 0x11 - Instruction Storage Exception
+        * This is caused by a fetch from non-execute or guarded pages. */
+       handle_instruction_storage_exception:
+               /* Working registers already saved: R3, R4, R5, R6
+                * R3 = ESR
+                */
+
+               mfs     r3, rear                /* Get faulting address */
+               nop
+               RESTORE_STATE;
+               bri     page_fault_instr_trap
+
+       /* 0x12 - Data TLB Miss Exception
+        * As the name implies, translation is not in the MMU, so search the
+        * page tables and fix it. The only purpose of this function is to
+        * load TLB entries from the page table if they exist.
+        */
+       handle_data_tlb_miss_exception:
+               /* Working registers already saved: R3, R4, R5, R6
+                * R3 = ESR
+                */
+               mfs     r11, rpid
+               nop
+               bri     4
+               mfs     r3, rear                /* Get faulting address */
+               nop
+
+               /* If we are faulting a kernel address, we have to use the
+                * kernel page tables. */
+               ori     r4, r0, CONFIG_KERNEL_START
+               cmpu    r4, r3, r4
+               bgti    r4, ex5
+               ori     r4, r0, swapper_pg_dir
+               mts     rpid, r0                /* TLB will have 0 TID */
+               nop
+               bri     ex6
 
+               /* Get the PGD for the current thread. */
+       ex5:
+               /* get current task address */
+               addi    r4 ,CURRENT_TASK, TOPHYS(0);
+               lwi     r4, r4, TASK_THREAD+PGDIR
+       ex6:
+               tophys(r4,r4)
+               BSRLI(r5,r3,20)         /* Create L1 (pgdir/pmd) address */
+               andi    r5, r5, 0xffc
+/* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */
+               or      r4, r4, r5
+               lwi     r4, r4, 0               /* Get L1 entry */
+               andi    r5, r4, 0xfffff000 /* Extract L2 (pte) base address */
+               beqi    r5, ex7                 /* Bail if no table */
+
+               tophys(r5,r5)
+               BSRLI(r6,r3,10)                 /* Compute PTE address */
+               andi    r6, r6, 0xffc
+               andi    r5, r5, 0xfffff003
+               or      r5, r5, r6
+               lwi     r4, r5, 0               /* Get Linux PTE */
+
+               andi    r6, r4, _PAGE_PRESENT
+               beqi    r6, ex7
+
+               ori     r4, r4, _PAGE_ACCESSED
+               swi     r4, r5, 0
+
+               /* Most of the Linux PTE is ready to load into the TLB LO.
+                * We set ZSEL, where only the LS-bit determines user access.
+                * We set execute, because we don't have the granularity to
+                * properly set this at the page level (Linux problem).
+                * If shared is set, we cause a zero PID->TID load.
+                * Many of these bits are software only. Bits we don't set
+                * here we (properly should) assume have the appropriate value.
+                */
+               andni   r4, r4, 0x0ce2          /* Make sure 20, 21 are zero */
+
+               bri     finish_tlb_load
+       ex7:
+               /* The bailout. Restore registers to pre-exception conditions
+                * and call the heavyweights to help us out.
+                */
+               mts     rpid, r11
+               nop
+               bri     4
+               RESTORE_STATE;
+               bri     page_fault_data_trap
+
+       /* 0x13 - Instruction TLB Miss Exception
+        * Nearly the same as above, except we get our information from
+        * different registers and bailout to a different point.
+        */
+       handle_instruction_tlb_miss_exception:
+               /* Working registers already saved: R3, R4, R5, R6
+                *  R3 = ESR
+                */
+               mfs     r11, rpid
+               nop
+               bri     4
+               mfs     r3, rear                /* Get faulting address */
+               nop
+
+               /* If we are faulting a kernel address, we have to use the
+                * kernel page tables.
+                */
+               ori     r4, r0, CONFIG_KERNEL_START
+               cmpu    r4, r3, r4
+               bgti    r4, ex8
+               ori     r4, r0, swapper_pg_dir
+               mts     rpid, r0                /* TLB will have 0 TID */
+               nop
+               bri     ex9
+
+               /* Get the PGD for the current thread. */
+       ex8:
+               /* get current task address */
+               addi    r4 ,CURRENT_TASK, TOPHYS(0);
+               lwi     r4, r4, TASK_THREAD+PGDIR
+       ex9:
+               tophys(r4,r4)
+               BSRLI(r5,r3,20)         /* Create L1 (pgdir/pmd) address */
+               andi    r5, r5, 0xffc
+/* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */
+               or      r4, r4, r5
+               lwi     r4, r4, 0               /* Get L1 entry */
+               andi    r5, r4, 0xfffff000 /* Extract L2 (pte) base address */
+               beqi    r5, ex10                /* Bail if no table */
+
+               tophys(r5,r5)
+               BSRLI(r6,r3,10)                 /* Compute PTE address */
+               andi    r6, r6, 0xffc
+               andi    r5, r5, 0xfffff003
+               or      r5, r5, r6
+               lwi     r4, r5, 0               /* Get Linux PTE */
+
+               andi    r6, r4, _PAGE_PRESENT
+               beqi    r6, ex7
+
+               ori     r4, r4, _PAGE_ACCESSED
+               swi     r4, r5, 0
+
+               /* Most of the Linux PTE is ready to load into the TLB LO.
+                * We set ZSEL, where only the LS-bit determines user access.
+                * We set execute, because we don't have the granularity to
+                * properly set this at the page level (Linux problem).
+                * If shared is set, we cause a zero PID->TID load.
+                * Many of these bits are software only. Bits we don't set
+                * here we (properly should) assume have the appropriate value.
+                */
+               andni   r4, r4, 0x0ce2          /* Make sure 20, 21 are zero */
+
+               bri     finish_tlb_load
+       ex10:
+               /* The bailout. Restore registers to pre-exception conditions
+                * and call the heavyweights to help us out.
+                */
+               mts     rpid, r11
+               nop
+               bri 4
+               RESTORE_STATE;
+               bri     page_fault_instr_trap
+
+/* Both the instruction and data TLB miss get to this point to load the TLB.
+ *     r3 - EA of fault
+ *     r4 - TLB LO (info from Linux PTE)
+ *     r5, r6 - available to use
+ *     PID - loaded with proper value when we get here
+ *     Upon exit, we reload everything and RFI.
+ * A common place to load the TLB.
+ */
+       tlb_index:
+               .long   1 /* MS: storing last used tlb index */
+       finish_tlb_load:
+               /* MS: load the last used TLB index. */
+               lwi     r5, r0, TOPHYS(tlb_index)
+               addik   r5, r5, 1 /* MS: inc tlb_index -> use next one */
+
+/* MS: FIXME this is potential fault, because this is mask not count */
+               andi    r5, r5, (MICROBLAZE_TLB_SIZE-1)
+               ori     r6, r0, 1
+               cmp     r31, r5, r6
+               blti    r31, sem
+               addik   r5, r6, 1
+       sem:
+               /* MS: save back current TLB index */
+               swi     r5, r0, TOPHYS(tlb_index)
+
+               ori     r4, r4, _PAGE_HWEXEC    /* make it executable */
+               mts     rtlbx, r5               /* MS: save current TLB */
+               nop
+               mts     rtlblo, r4              /* MS: save to TLB LO */
+               nop
+
+               /* Create EPN. This is the faulting address plus a static
+                * set of bits. These are size, valid, E, U0, and ensure
+                * bits 20 and 21 are zero.
+                */
+               andi    r3, r3, 0xfffff000
+               ori     r3, r3, 0x0c0
+               mts     rtlbhi, r3              /* Load TLB HI */
+               nop
+
+               /* Done...restore registers and get out of here. */
+       ex12:
+               mts     rpid, r11
+               nop
+               bri 4
+               RESTORE_STATE;
+               rted    r17, 0
+               nop
+
+       /* extern void giveup_fpu(struct task_struct *prev)
+        *
+        * The MicroBlaze processor may have an FPU, so this should not just
+        * return: TBD.
+        */
+       .globl giveup_fpu;
+       .align 4;
+       giveup_fpu:
+               bralid  r15,0                   /* TBD */
+               nop
+
+       /* At present, this routine just hangs. - extern void abort(void) */
+       .globl abort;
+       .align 4;
+       abort:
+               br      r0
+
+       .globl set_context;
+       .align 4;
+       set_context:
+               mts     rpid, r5        /* Shadow TLBs are automatically */
+               nop
+               bri     4               /* flushed by changing PID */
+               rtsd    r15,8
+               nop
+
+#endif
 .end _hw_exception_handler
 
+#ifdef CONFIG_MMU
+/* Unaligned data access exception last on a 4k page for MMU.
+ * When this is called, we are in virtual mode with exceptions enabled
+ * and registers 1-13,15,17,18 saved.
+ *
+ * R3 = ESR
+ * R4 = EAR
+ * R7 = pointer to saved registers (struct pt_regs *regs)
+ *
+ * This handler perform the access, and returns via ret_from_exc.
+ */
+.global _unaligned_data_exception
+.ent _unaligned_data_exception
+_unaligned_data_exception:
+       andi    r8, r3, 0x3E0;  /* Mask and extract the register operand */
+       BSRLI(r8,r8,2);         /* r8 >> 2 = register operand * 8 */
+       andi    r6, r3, 0x400;  /* Extract ESR[S] */
+       bneid   r6, ex_sw_vm;
+       andi    r6, r3, 0x800;  /* Extract ESR[W] - delay slot */
+ex_lw_vm:
+       beqid   r6, ex_lhw_vm;
+       lbui    r5, r4, 0;      /* Exception address in r4 - delay slot */
+/* Load a word, byte-by-byte from destination address and save it in tmp space*/
+       la      r6, r0, ex_tmp_data_loc_0;
+       sbi     r5, r6, 0;
+       lbui    r5, r4, 1;
+       sbi     r5, r6, 1;
+       lbui    r5, r4, 2;
+       sbi     r5, r6, 2;
+       lbui    r5, r4, 3;
+       sbi     r5, r6, 3;
+       brid    ex_lw_tail_vm;
+/* Get the destination register value into r3 - delay slot */
+       lwi     r3, r6, 0;
+ex_lhw_vm:
+       /* Load a half-word, byte-by-byte from destination address and
+        * save it in tmp space */
+       la      r6, r0, ex_tmp_data_loc_0;
+       sbi     r5, r6, 0;
+       lbui    r5, r4, 1;
+       sbi     r5, r6, 1;
+       lhui    r3, r6, 0;      /* Get the destination register value into r3 */
+ex_lw_tail_vm:
+       /* Form load_word jump table offset (lw_table_vm + (8 * regnum)) */
+       addik   r5, r8, lw_table_vm;
+       bra     r5;
+ex_lw_end_vm:                  /* Exception handling of load word, ends */
+       brai    ret_from_exc;
+ex_sw_vm:
+/* Form store_word jump table offset (sw_table_vm + (8 * regnum)) */
+       addik   r5, r8, sw_table_vm;
+       bra     r5;
+ex_sw_tail_vm:
+       la      r5, r0, ex_tmp_data_loc_0;
+       beqid   r6, ex_shw_vm;
+       swi     r3, r5, 0;      /* Get the word - delay slot */
+       /* Store the word, byte-by-byte into destination address */
+       lbui    r3, r5, 0;
+       sbi     r3, r4, 0;
+       lbui    r3, r5, 1;
+       sbi     r3, r4, 1;
+       lbui    r3, r5, 2;
+       sbi     r3, r4, 2;
+       lbui    r3, r5, 3;
+       brid    ret_from_exc;
+       sbi     r3, r4, 3;      /* Delay slot */
+ex_shw_vm:
+       /* Store the lower half-word, byte-by-byte into destination address */
+       lbui    r3, r5, 2;
+       sbi     r3, r4, 0;
+       lbui    r3, r5, 3;
+       brid    ret_from_exc;
+       sbi     r3, r4, 1;      /* Delay slot */
+ex_sw_end_vm:                  /* Exception handling of store word, ends. */
+.end _unaligned_data_exception
+#endif /* CONFIG_MMU */
+
 ex_handler_unhandled:
 /* FIXME add handle function for unhandled exception - dump register */
        bri 0
 
+/*
+ * hw_exception_handler Jump Table
+ * - Contains code snippets for each register that caused the unalign exception
+ * - Hence exception handler is NOT self-modifying
+ * - Separate table for load exceptions and store exceptions.
+ * - Each table is of size: (8 * 32) = 256 bytes
+ */
+
 .section .text
 .align 4
 lw_table:
@@ -407,7 +1061,11 @@ lw_r27:           R3_TO_LWREG     (27);
 lw_r28:                R3_TO_LWREG     (28);
 lw_r29:                R3_TO_LWREG     (29);
 lw_r30:                R3_TO_LWREG     (30);
+#ifdef CONFIG_MMU
+lw_r31:        R3_TO_LWREG_V   (31);
+#else
 lw_r31:                R3_TO_LWREG     (31);
+#endif
 
 sw_table:
 sw_r0:         SWREG_TO_R3     (0);
@@ -441,7 +1099,81 @@ sw_r27:           SWREG_TO_R3     (27);
 sw_r28:                SWREG_TO_R3     (28);
 sw_r29:                SWREG_TO_R3     (29);
 sw_r30:                SWREG_TO_R3     (30);
+#ifdef CONFIG_MMU
+sw_r31:                SWREG_TO_R3_V   (31);
+#else
 sw_r31:                SWREG_TO_R3     (31);
+#endif
+
+#ifdef CONFIG_MMU
+lw_table_vm:
+lw_r0_vm:      R3_TO_LWREG_VM          (0);
+lw_r1_vm:      R3_TO_LWREG_VM_V        (1);
+lw_r2_vm:      R3_TO_LWREG_VM_V        (2);
+lw_r3_vm:      R3_TO_LWREG_VM_V        (3);
+lw_r4_vm:      R3_TO_LWREG_VM_V        (4);
+lw_r5_vm:      R3_TO_LWREG_VM_V        (5);
+lw_r6_vm:      R3_TO_LWREG_VM_V        (6);
+lw_r7_vm:      R3_TO_LWREG_VM_V        (7);
+lw_r8_vm:      R3_TO_LWREG_VM_V        (8);
+lw_r9_vm:      R3_TO_LWREG_VM_V        (9);
+lw_r10_vm:     R3_TO_LWREG_VM_V        (10);
+lw_r11_vm:     R3_TO_LWREG_VM_V        (11);
+lw_r12_vm:     R3_TO_LWREG_VM_V        (12);
+lw_r13_vm:     R3_TO_LWREG_VM_V        (13);
+lw_r14_vm:     R3_TO_LWREG_VM          (14);
+lw_r15_vm:     R3_TO_LWREG_VM_V        (15);
+lw_r16_vm:     R3_TO_LWREG_VM          (16);
+lw_r17_vm:     R3_TO_LWREG_VM_V        (17);
+lw_r18_vm:     R3_TO_LWREG_VM_V        (18);
+lw_r19_vm:     R3_TO_LWREG_VM          (19);
+lw_r20_vm:     R3_TO_LWREG_VM          (20);
+lw_r21_vm:     R3_TO_LWREG_VM          (21);
+lw_r22_vm:     R3_TO_LWREG_VM          (22);
+lw_r23_vm:     R3_TO_LWREG_VM          (23);
+lw_r24_vm:     R3_TO_LWREG_VM          (24);
+lw_r25_vm:     R3_TO_LWREG_VM          (25);
+lw_r26_vm:     R3_TO_LWREG_VM          (26);
+lw_r27_vm:     R3_TO_LWREG_VM          (27);
+lw_r28_vm:     R3_TO_LWREG_VM          (28);
+lw_r29_vm:     R3_TO_LWREG_VM          (29);
+lw_r30_vm:     R3_TO_LWREG_VM          (30);
+lw_r31_vm:     R3_TO_LWREG_VM_V        (31);
+
+sw_table_vm:
+sw_r0_vm:      SWREG_TO_R3_VM          (0);
+sw_r1_vm:      SWREG_TO_R3_VM_V        (1);
+sw_r2_vm:      SWREG_TO_R3_VM_V        (2);
+sw_r3_vm:      SWREG_TO_R3_VM_V        (3);
+sw_r4_vm:      SWREG_TO_R3_VM_V        (4);
+sw_r5_vm:      SWREG_TO_R3_VM_V        (5);
+sw_r6_vm:      SWREG_TO_R3_VM_V        (6);
+sw_r7_vm:      SWREG_TO_R3_VM_V        (7);
+sw_r8_vm:      SWREG_TO_R3_VM_V        (8);
+sw_r9_vm:      SWREG_TO_R3_VM_V        (9);
+sw_r10_vm:     SWREG_TO_R3_VM_V        (10);
+sw_r11_vm:     SWREG_TO_R3_VM_V        (11);
+sw_r12_vm:     SWREG_TO_R3_VM_V        (12);
+sw_r13_vm:     SWREG_TO_R3_VM_V        (13);
+sw_r14_vm:     SWREG_TO_R3_VM          (14);
+sw_r15_vm:     SWREG_TO_R3_VM_V        (15);
+sw_r16_vm:     SWREG_TO_R3_VM          (16);
+sw_r17_vm:     SWREG_TO_R3_VM_V        (17);
+sw_r18_vm:     SWREG_TO_R3_VM_V        (18);
+sw_r19_vm:     SWREG_TO_R3_VM          (19);
+sw_r20_vm:     SWREG_TO_R3_VM          (20);
+sw_r21_vm:     SWREG_TO_R3_VM          (21);
+sw_r22_vm:     SWREG_TO_R3_VM          (22);
+sw_r23_vm:     SWREG_TO_R3_VM          (23);
+sw_r24_vm:     SWREG_TO_R3_VM          (24);
+sw_r25_vm:     SWREG_TO_R3_VM          (25);
+sw_r26_vm:     SWREG_TO_R3_VM          (26);
+sw_r27_vm:     SWREG_TO_R3_VM          (27);
+sw_r28_vm:     SWREG_TO_R3_VM          (28);
+sw_r29_vm:     SWREG_TO_R3_VM          (29);
+sw_r30_vm:     SWREG_TO_R3_VM          (30);
+sw_r31_vm:     SWREG_TO_R3_VM_V        (31);
+#endif /* CONFIG_MMU */
 
 /* Temporary data structures used in the handler */
 .section .data
index 5f71790e3c3ce68c953c65e33e970a2ff947ef6a..59ff20e33e0cde5b22b7f95fb0517323066c4440 100644 (file)
@@ -45,3 +45,5 @@ extern void __udivsi3(void);
 EXPORT_SYMBOL(__udivsi3);
 extern void __umodsi3(void);
 EXPORT_SYMBOL(__umodsi3);
+extern char *_ebss;
+EXPORT_SYMBOL_GPL(_ebss);
diff --git a/arch/microblaze/kernel/misc.S b/arch/microblaze/kernel/misc.S
new file mode 100644 (file)
index 0000000..df16c62
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Miscellaneous low-level MMU functions.
+ *
+ * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2008-2009 PetaLogix
+ * Copyright (C) 2007 Xilinx, Inc.  All rights reserved.
+ *
+ * Derived from arch/ppc/kernel/misc.S
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ */
+
+#include <linux/linkage.h>
+#include <linux/sys.h>
+#include <asm/unistd.h>
+#include <linux/errno.h>
+#include <asm/mmu.h>
+#include <asm/page.h>
+
+       .text
+/*
+ * Flush MMU TLB
+ *
+ * We avoid flushing the pinned 0, 1 and possibly 2 entries.
+ */
+.globl _tlbia;
+.align 4;
+_tlbia:
+       addik   r12, r0, 63 /* flush all entries (63 - 3) */
+       /* isync */
+_tlbia_1:
+       mts     rtlbx, r12
+       nop
+       mts     rtlbhi, r0 /* flush: ensure V is clear */
+       nop
+       addik   r11, r12, -2
+       bneid   r11, _tlbia_1 /* loop for all entries */
+       addik   r12, r12, -1
+       /* sync */
+       rtsd    r15, 8
+       nop
+
+/*
+ * Flush MMU TLB for a particular address (in r5)
+ */
+.globl _tlbie;
+.align 4;
+_tlbie:
+       mts     rtlbsx, r5 /* look up the address in TLB */
+       nop
+       mfs     r12, rtlbx /* Retrieve index */
+       nop
+       blti    r12, _tlbie_1 /* Check if found */
+       mts     rtlbhi, r0 /* flush: ensure V is clear */
+       nop
+_tlbie_1:
+       rtsd    r15, 8
+       nop
+
+/*
+ * Allocate TLB entry for early console
+ */
+.globl early_console_reg_tlb_alloc;
+.align 4;
+early_console_reg_tlb_alloc:
+       /*
+        * Load a TLB entry for the UART, so that microblaze_progress() can use
+        * the UARTs nice and early.  We use a 4k real==virtual mapping.
+        */
+       ori     r4, r0, 63
+       mts     rtlbx, r4 /* TLB slot 2 */
+
+       or      r4,r5,r0
+       andi    r4,r4,0xfffff000
+       ori     r4,r4,(TLB_WR|TLB_I|TLB_M|TLB_G)
+
+       andi    r5,r5,0xfffff000
+       ori     r5,r5,(TLB_VALID | TLB_PAGESZ(PAGESZ_4K))
+
+       mts     rtlblo,r4 /* Load the data portion of the entry */
+       nop
+       mts     rtlbhi,r5 /* Load the tag portion of the entry */
+       nop
+       rtsd    r15, 8
+       nop
+
+/*
+ * Copy a whole page (4096 bytes).
+ */
+#define COPY_16_BYTES          \
+       lwi     r7, r6, 0;      \
+       lwi     r8, r6, 4;      \
+       lwi     r9, r6, 8;      \
+       lwi     r10, r6, 12;    \
+       swi     r7, r5, 0;      \
+       swi     r8, r5, 4;      \
+       swi     r9, r5, 8;      \
+       swi     r10, r5, 12
+
+
+/* FIXME DCACHE_LINE_BYTES (CONFIG_XILINX_MICROBLAZE0_DCACHE_LINE_LEN * 4)*/
+#define DCACHE_LINE_BYTES (4 * 4)
+
+.globl copy_page;
+.align 4;
+copy_page:
+       ori     r11, r0, (PAGE_SIZE/DCACHE_LINE_BYTES) - 1
+_copy_page_loop:
+       COPY_16_BYTES
+#if DCACHE_LINE_BYTES >= 32
+       COPY_16_BYTES
+#endif
+       addik   r6, r6, DCACHE_LINE_BYTES
+       addik   r5, r5, DCACHE_LINE_BYTES
+       bneid   r11, _copy_page_loop
+       addik   r11, r11, -1
+       rtsd    r15, 8
+       nop
index 07d4fa339eda8c6c0384c1c0b70b8ba09b55781d..00b12c6d5326767fc9260df77801a699050cdee7 100644 (file)
@@ -126,9 +126,54 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
        else
                childregs->r1 = ((unsigned long) ti) + THREAD_SIZE;
 
+#ifndef CONFIG_MMU
        memset(&ti->cpu_context, 0, sizeof(struct cpu_context));
        ti->cpu_context.r1 = (unsigned long)childregs;
        ti->cpu_context.msr = (unsigned long)childregs->msr;
+#else
+
+       /* if creating a kernel thread then update the current reg (we don't
+        * want to use the parent's value when restoring by POP_STATE) */
+       if (kernel_mode(regs))
+               /* save new current on stack to use POP_STATE */
+               childregs->CURRENT_TASK = (unsigned long)p;
+       /* if returning to user then use the parent's value of this register */
+
+       /* if we're creating a new kernel thread then just zeroing all
+        * the registers. That's OK for a brand new thread.*/
+       /* Pls. note that some of them will be restored in POP_STATE */
+       if (kernel_mode(regs))
+               memset(&ti->cpu_context, 0, sizeof(struct cpu_context));
+       /* if this thread is created for fork/vfork/clone, then we want to
+        * restore all the parent's context */
+       /* in addition to the registers which will be restored by POP_STATE */
+       else {
+               ti->cpu_context = *(struct cpu_context *)regs;
+               childregs->msr |= MSR_UMS;
+       }
+
+       /* FIXME STATE_SAVE_PT_OFFSET; */
+       ti->cpu_context.r1  = (unsigned long)childregs - STATE_SAVE_ARG_SPACE;
+       /* we should consider the fact that childregs is a copy of the parent
+        * regs which were saved immediately after entering the kernel state
+        * before enabling VM. This MSR will be restored in switch_to and
+        * RETURN() and we want to have the right machine state there
+        * specifically this state must have INTs disabled before and enabled
+        * after performing rtbd
+        * compose the right MSR for RETURN(). It will work for switch_to also
+        * excepting for VM and UMS
+        * don't touch UMS , CARRY and cache bits
+        * right now MSR is a copy of parent one */
+       childregs->msr |= MSR_BIP;
+       childregs->msr &= ~MSR_EIP;
+       childregs->msr |= MSR_IE;
+       childregs->msr &= ~MSR_VM;
+       childregs->msr |= MSR_VMS;
+       childregs->msr |= MSR_EE; /* exceptions will be enabled*/
+
+       ti->cpu_context.msr = (childregs->msr|MSR_VM);
+       ti->cpu_context.msr &= ~MSR_UMS; /* switch_to to kernel mode */
+#endif
        ti->cpu_context.r15 = (unsigned long)ret_from_fork - 8;
 
        if (clone_flags & CLONE_SETTLS)
@@ -137,6 +182,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
        return 0;
 }
 
+#ifndef CONFIG_MMU
 /*
  * Return saved PC of a blocked thread.
  */
@@ -151,6 +197,7 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
        else
                return ctx->r14;
 }
+#endif
 
 static void kernel_thread_helper(int (*fn)(void *), void *arg)
 {
@@ -173,6 +220,7 @@ int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
        return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
                        &regs, 0, NULL, NULL);
 }
+EXPORT_SYMBOL_GPL(kernel_thread);
 
 unsigned long get_wchan(struct task_struct *p)
 {
@@ -188,3 +236,14 @@ void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp)
        regs->r1 = usp;
        regs->pt_mode = 0;
 }
+
+#ifdef CONFIG_MMU
+#include <linux/elfcore.h>
+/*
+ * Set up a thread for executing a new program
+ */
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
+{
+       return 0; /* MicroBlaze has no separate FPU registers */
+}
+#endif /* CONFIG_MMU */
index 34c48718061afcdd7781e7160dcd998e0c45c025..c005cc6f1aaf7f5703fb58219ddba588dc4127e4 100644 (file)
@@ -509,12 +509,13 @@ static void __init early_init_dt_check_for_initrd(unsigned long node)
 
        prop = of_get_flat_dt_prop(node, "linux,initrd-start", &l);
        if (prop) {
-               initrd_start = (unsigned long)__va(of_read_ulong(prop, l/4));
+               initrd_start = (unsigned long)
+                                       __va((u32)of_read_ulong(prop, l/4));
 
                prop = of_get_flat_dt_prop(node, "linux,initrd-end", &l);
                if (prop) {
                        initrd_end = (unsigned long)
-                                       __va(of_read_ulong(prop, l/4));
+                                       __va((u32)of_read_ulong(prop, 1/4));
                        initrd_below_start_ok = 1;
                } else {
                        initrd_start = 0;
@@ -563,7 +564,9 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
                strlcpy(cmd_line, p, min((int)l, COMMAND_LINE_SIZE));
 
 #ifdef CONFIG_CMDLINE
+#ifndef CONFIG_CMDLINE_FORCE
        if (p == NULL || l == 0 || (l == 1 && (*p) == 0))
+#endif
                strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
 #endif /* CONFIG_CMDLINE */
 
index eb6b41758e2301fd0d24ca4eebcb9d004257bad3..8709bea09604585958cd95d72c107c65d1396855 100644 (file)
@@ -42,10 +42,6 @@ char cmd_line[COMMAND_LINE_SIZE];
 
 void __init setup_arch(char **cmdline_p)
 {
-#ifdef CONFIG_CMDLINE_FORCE
-       strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
-       strlcpy(boot_command_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
-#endif
        *cmdline_p = cmd_line;
 
        console_verbose();
@@ -102,14 +98,34 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,
 {
        unsigned long *src, *dst = (unsigned long *)0x0;
 
+       /* If CONFIG_MTD_UCLINUX is defined, assume ROMFS is at the
+        * end of kernel. There are two position which we want to check.
+        * The first is __init_end and the second __bss_start.
+        */
+#ifdef CONFIG_MTD_UCLINUX
+       int romfs_size;
+       unsigned int romfs_base;
+       char *old_klimit = klimit;
+
+       romfs_base = (ram ? ram : (unsigned int)&__init_end);
+       romfs_size = PAGE_ALIGN(get_romfs_len((unsigned *)romfs_base));
+       if (!romfs_size) {
+               romfs_base = (unsigned int)&__bss_start;
+               romfs_size = PAGE_ALIGN(get_romfs_len((unsigned *)romfs_base));
+       }
+
+       /* Move ROMFS out of BSS before clearing it */
+       if (romfs_size > 0) {
+               memmove(&_ebss, (int *)romfs_base, romfs_size);
+               klimit += romfs_size;
+       }
+#endif
+
 /* clearing bss section */
        memset(__bss_start, 0, __bss_stop-__bss_start);
        memset(_ssbss, 0, _esbss-_ssbss);
 
-       /*
-        * Copy command line passed from bootloader, or use default
-        * if none provided, or forced
-        */
+       /* Copy command line passed from bootloader */
 #ifndef CONFIG_CMDLINE_BOOL
        if (cmdline && cmdline[0] != '\0')
                strlcpy(cmd_line, cmdline, COMMAND_LINE_SIZE);
@@ -126,27 +142,15 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,
        printk(KERN_NOTICE "Found FDT at 0x%08x\n", fdt);
 
 #ifdef CONFIG_MTD_UCLINUX
-       {
-               int size;
-               unsigned int romfs_base;
-               romfs_base = (ram ? ram : (unsigned int)&__init_end);
-               /* if CONFIG_MTD_UCLINUX_EBSS is defined, assume ROMFS is at the
-                * end of kernel, which is ROMFS_LOCATION defined above. */
-               size = PAGE_ALIGN(get_romfs_len((unsigned *)romfs_base));
-               early_printk("Found romfs @ 0x%08x (0x%08x)\n",
-                               romfs_base, size);
-               early_printk("#### klimit %p ####\n", klimit);
-               BUG_ON(size < 0); /* What else can we do? */
-
-               /* Use memmove to handle likely case of memory overlap */
-               early_printk("Moving 0x%08x bytes from 0x%08x to 0x%08x\n",
-                       size, romfs_base, (unsigned)&_ebss);
-               memmove(&_ebss, (int *)romfs_base, size);
-
-               /* update klimit */
-               klimit += PAGE_ALIGN(size);
-               early_printk("New klimit: 0x%08x\n", (unsigned)klimit);
-       }
+       early_printk("Found romfs @ 0x%08x (0x%08x)\n",
+                       romfs_base, romfs_size);
+       early_printk("#### klimit %p ####\n", old_klimit);
+       BUG_ON(romfs_size < 0); /* What else can we do? */
+
+       early_printk("Moved 0x%08x bytes from 0x%08x to 0x%08x\n",
+                       romfs_size, romfs_base, (unsigned)&_ebss);
+
+       early_printk("New klimit: 0x%08x\n", (unsigned)klimit);
 #endif
 
        for (src = __ivt_start; src < __ivt_end; src++, dst++)
index 40d36931e363eccefd2857383e60fb162f6bf492..4c0e6521b1140e6d92183fb165b03076253a889d 100644 (file)
@@ -152,8 +152,8 @@ struct rt_sigframe {
        unsigned long tramp[2]; /* signal trampoline */
 };
 
-static int
-restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *rval_p)
+static int restore_sigcontext(struct pt_regs *regs,
+                               struct sigcontext __user *sc, int *rval_p)
 {
        unsigned int err = 0;
 
@@ -211,11 +211,10 @@ badframe:
 
 asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
 {
-       struct rt_sigframe *frame =
-                       (struct rt_sigframe *)(regs->r1 + STATE_SAVE_ARG_SPACE);
+       struct rt_sigframe __user *frame =
+               (struct rt_sigframe __user *)(regs->r1 + STATE_SAVE_ARG_SPACE);
 
        sigset_t set;
-       stack_t st;
        int rval;
 
        if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
@@ -233,11 +232,10 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
        if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &rval))
                goto badframe;
 
-       if (__copy_from_user((void *)&st, &frame->uc.uc_stack, sizeof(st)))
-               goto badframe;
        /* It is more difficult to avoid calling this function than to
         call it and ignore errors. */
-       do_sigaltstack(&st, NULL, regs->r1);
+       if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->r1))
+               goto badframe;
 
        return rval;
 
@@ -251,7 +249,7 @@ badframe:
  */
 
 static int
-setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
+setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
                unsigned long mask)
 {
        int err = 0;
@@ -278,7 +276,7 @@ setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
 /*
  * Determine which stack to use..
  */
-static inline void *
+static inline void __user *
 get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
 {
        /* Default to using normal stack */
@@ -287,87 +285,13 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
        if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && !on_sig_stack(sp))
                sp = current->sas_ss_sp + current->sas_ss_size;
 
-       return (void *)((sp - frame_size) & -8UL);
-}
-
-static void setup_frame(int sig, struct k_sigaction *ka,
-                       sigset_t *set, struct pt_regs *regs)
-{
-       struct sigframe *frame;
-       int err = 0;
-       int signal;
-
-       frame = get_sigframe(ka, regs, sizeof(*frame));
-
-       if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-               goto give_sigsegv;
-
-       signal = current_thread_info()->exec_domain
-               && current_thread_info()->exec_domain->signal_invmap
-               && sig < 32
-               ? current_thread_info()->exec_domain->signal_invmap[sig]
-               : sig;
-
-       err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
-
-       if (_NSIG_WORDS > 1) {
-               err |= __copy_to_user(frame->extramask, &set->sig[1],
-                                       sizeof(frame->extramask));
-       }
-
-       /* Set up to return from userspace. If provided, use a stub
-        already in userspace. */
-       /* minus 8 is offset to cater for "rtsd r15,8" offset */
-       if (ka->sa.sa_flags & SA_RESTORER) {
-               regs->r15 = ((unsigned long)ka->sa.sa_restorer)-8;
-       } else {
-               /* Note, these encodings are _big endian_! */
-
-               /* addi r12, r0, __NR_sigreturn */
-               err |= __put_user(0x31800000 | __NR_sigreturn ,
-                               frame->tramp + 0);
-               /* brki r14, 0x8 */
-               err |= __put_user(0xb9cc0008, frame->tramp + 1);
-
-               /* Return from sighandler will jump to the tramp.
-                Negative 8 offset because return is rtsd r15, 8 */
-               regs->r15 = ((unsigned long)frame->tramp)-8;
-
-               __invalidate_cache_sigtramp((unsigned long)frame->tramp);
-       }
-
-       if (err)
-               goto give_sigsegv;
-
-       /* Set up registers for signal handler */
-       regs->r1 = (unsigned long) frame - STATE_SAVE_ARG_SPACE;
-
-       /* Signal handler args: */
-       regs->r5 = signal; /* Arg 0: signum */
-       regs->r6 = (unsigned long) &frame->sc; /* arg 1: sigcontext */
-
-       /* Offset of 4 to handle microblaze rtid r14, 0 */
-       regs->pc = (unsigned long)ka->sa.sa_handler;
-
-       set_fs(USER_DS);
-
-#ifdef DEBUG_SIG
-       printk(KERN_INFO "SIG deliver (%s:%d): sp=%p pc=%08lx\n",
-               current->comm, current->pid, frame, regs->pc);
-#endif
-
-       return;
-
-give_sigsegv:
-       if (sig == SIGSEGV)
-               ka->sa.sa_handler = SIG_DFL;
-       force_sig(SIGSEGV, current);
+       return (void __user *)((sp - frame_size) & -8UL);
 }
 
 static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
                        sigset_t *set, struct pt_regs *regs)
 {
-       struct rt_sigframe *frame;
+       struct rt_sigframe __user *frame;
        int err = 0;
        int signal;
 
@@ -382,7 +306,8 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
                ? current_thread_info()->exec_domain->signal_invmap[sig]
                : sig;
 
-       err |= copy_siginfo_to_user(&frame->info, info);
+       if (info)
+               err |= copy_siginfo_to_user(&frame->info, info);
 
        /* Create the ucontext. */
        err |= __put_user(0, &frame->uc.uc_flags);
@@ -463,7 +388,15 @@ handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
        case -ERESTARTNOINTR:
 do_restart:
                /* offset of 4 bytes to re-execute trap (brki) instruction */
+#ifndef CONFIG_MMU
                regs->pc -= 4;
+#else
+               /* offset of 8 bytes required = 4 for rtbd
+                  offset, plus 4 for size of
+                       "brki r14,8"
+                  instruction. */
+               regs->pc -= 8;
+#endif
                break;
        }
 }
@@ -480,7 +413,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
        if (ka->sa.sa_flags & SA_SIGINFO)
                setup_rt_frame(sig, ka, info, oldset, regs);
        else
-               setup_frame(sig, ka, oldset, regs);
+               setup_rt_frame(sig, ka, NULL, oldset, regs);
 
        if (ka->sa.sa_flags & SA_ONESHOT)
                ka->sa.sa_handler = SIG_DFL;
index 3bb42ec924c2ccc299004ab7b525724ab5cd8c9c..376d1789f7c065e436fdf39d7b3e2f8f2318494f 100644 (file)
@@ -2,7 +2,11 @@ ENTRY(sys_call_table)
        .long sys_restart_syscall       /* 0 - old "setup()" system call,
                                         * used for restarting */
        .long sys_exit
-       .long sys_ni_syscall            /* was fork */
+#ifdef CONFIG_MMU
+       .long sys_fork_wrapper
+#else
+       .long sys_ni_syscall
+#endif
        .long sys_read
        .long sys_write
        .long sys_open                  /* 5 */
index 293ef486013aa9fa65b8f2204221615af22ffb38..eaaaf805f31b6d32039376df4f0e9ffdec777b5d 100644 (file)
@@ -22,14 +22,6 @@ void trap_init(void)
        __enable_hw_exceptions();
 }
 
-void __bad_xchg(volatile void *ptr, int size)
-{
-       printk(KERN_INFO "xchg: bad data size: pc 0x%p, ptr 0x%p, size %d\n",
-               __builtin_return_address(0), ptr, size);
-       BUG();
-}
-EXPORT_SYMBOL(__bad_xchg);
-
 static int kstack_depth_to_print = 24;
 
 static int __init kstack_setup(char *s)
@@ -105,3 +97,37 @@ void dump_stack(void)
        show_stack(NULL, NULL);
 }
 EXPORT_SYMBOL(dump_stack);
+
+#ifdef CONFIG_MMU
+void __bug(const char *file, int line, void *data)
+{
+       if (data)
+               printk(KERN_CRIT "kernel BUG at %s:%d (data = %p)!\n",
+                       file, line, data);
+       else
+               printk(KERN_CRIT "kernel BUG at %s:%d!\n", file, line);
+
+       machine_halt();
+}
+
+int bad_trap(int trap_num, struct pt_regs *regs)
+{
+       printk(KERN_CRIT
+               "unimplemented trap %d called at 0x%08lx, pid %d!\n",
+               trap_num, regs->pc, current->pid);
+       return -ENOSYS;
+}
+
+int debug_trap(struct pt_regs *regs)
+{
+       int i;
+       printk(KERN_CRIT "debug trap\n");
+       for (i = 0; i < 32; i++) {
+               /* printk("r%i:%08X\t",i,regs->gpr[i]); */
+               if ((i % 4) == 3)
+                       printk(KERN_CRIT "\n");
+       }
+       printk(KERN_CRIT "pc:%08lX\tmsr:%08lX\n", regs->pc, regs->msr);
+       return -ENOSYS;
+}
+#endif
index 840385e51291f507b9560f1ac36c43585f232870..8ae807ab7a51bd568709c2c57b9b5b189cfeb951 100644 (file)
@@ -17,8 +17,7 @@ ENTRY(_start)
 jiffies = jiffies_64 + 4;
 
 SECTIONS {
-       . = CONFIG_KERNEL_BASE_ADDR;
-
+       . = CONFIG_KERNEL_START;
        .text : {
                _text = . ;
                _stext = . ;
@@ -132,6 +131,8 @@ SECTIONS {
                __con_initcall_end = .;
        }
 
+       SECURITY_INIT
+
        __init_end_before_initramfs = .;
 
        .init.ramfs ALIGN(4096) : {
index d27126bf306a61e08ec9b1664298fcb9d1caab39..71c8cb6c9e43767a4ebd43f9e4c54d3e9820928b 100644 (file)
@@ -10,4 +10,5 @@ else
 lib-y += memcpy.o memmove.o
 endif
 
-lib-y +=  uaccess.o
+lib-$(CONFIG_NO_MMU) += uaccess.o
+lib-$(CONFIG_MMU) += uaccess_old.o
index 809340070a13c1142567ba814384f7632b0d9952..f08e74591418dc4d15563620eaff7bddbc0de95c 100644 (file)
 /* Revised by Kenneth Albanowski for m68knommu. Basic problem: unaligned access
  kills, so most of the assembly has to go. */
 
-#include <net/checksum.h>
-#include <asm/checksum.h>
 #include <linux/module.h>
+#include <net/checksum.h>
+
+#include <asm/byteorder.h>
 
 static inline unsigned short from32to16(unsigned long x)
 {
@@ -102,6 +103,7 @@ __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
 {
        return (__force __sum16)~do_csum(iph, ihl*4);
 }
+EXPORT_SYMBOL(ip_fast_csum);
 
 /*
  * computes the checksum of a memory block at buff, length len,
@@ -115,15 +117,16 @@ __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
  *
  * it's best to have buff aligned on a 32-bit boundary
  */
-__wsum csum_partial(const void *buff, int len, __wsum sum)
+__wsum csum_partial(const void *buff, int len, __wsum wsum)
 {
+       unsigned int sum = (__force unsigned int)wsum;
        unsigned int result = do_csum(buff, len);
 
        /* add in old sum, and carry.. */
        result += sum;
        if (sum > result)
                result += 1;
-       return result;
+       return (__force __wsum)result;
 }
 EXPORT_SYMBOL(csum_partial);
 
@@ -131,9 +134,9 @@ EXPORT_SYMBOL(csum_partial);
  * this routine is used for miscellaneous IP-like checksums, mainly
  * in icmp.c
  */
-__sum16 ip_compute_csum(const unsigned char *buff, int len)
+__sum16 ip_compute_csum(const void *buff, int len)
 {
-       return ~do_csum(buff, len);
+       return (__force __sum16)~do_csum(buff, len);
 }
 EXPORT_SYMBOL(ip_compute_csum);
 
@@ -141,12 +144,18 @@ EXPORT_SYMBOL(ip_compute_csum);
  * copy from fs while checksumming, otherwise like csum_partial
  */
 __wsum
-csum_partial_copy_from_user(const char __user *src, char *dst, int len,
-                                               int sum, int *csum_err)
+csum_partial_copy_from_user(const void __user *src, void *dst, int len,
+                                               __wsum sum, int *csum_err)
 {
-       if (csum_err)
+       int missing;
+
+       missing = __copy_from_user(dst, src, len);
+       if (missing) {
+               memset(dst + len - missing, 0, missing);
+               *csum_err = -EFAULT;
+       } else
                *csum_err = 0;
-       memcpy(dst, src, len);
+
        return csum_partial(dst, len, sum);
 }
 EXPORT_SYMBOL(csum_partial_copy_from_user);
@@ -155,7 +164,7 @@ EXPORT_SYMBOL(csum_partial_copy_from_user);
  * copy from ds while checksumming, otherwise like csum_partial
  */
 __wsum
-csum_partial_copy(const char *src, char *dst, int len, int sum)
+csum_partial_copy(const void *src, void *dst, int len, __wsum sum)
 {
        memcpy(dst, src, len);
        return csum_partial(dst, len, sum);
index 5880119c448721e9064b3a315cba6810907b6d31..6a907c58a4bc075ae84aa91797d34ad7565d9d54 100644 (file)
@@ -154,8 +154,3 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
 }
 EXPORT_SYMBOL(memcpy);
 #endif /* __HAVE_ARCH_MEMCPY */
-
-void *cacheable_memcpy(void *d, const void *s, __kernel_size_t c)
-{
-       return memcpy(d, s, c);
-}
diff --git a/arch/microblaze/lib/uaccess_old.S b/arch/microblaze/lib/uaccess_old.S
new file mode 100644 (file)
index 0000000..67f991c
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2009 PetaLogix
+ * Copyright (C) 2007 LynuxWorks, Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/errno.h>
+#include <linux/linkage.h>
+
+/*
+ * int __strncpy_user(char *to, char *from, int len);
+ *
+ * Returns:
+ *  -EFAULT  for an exception
+ *  len      if we hit the buffer limit
+ *  bytes copied
+ */
+
+       .text
+.globl __strncpy_user;
+.align 4;
+__strncpy_user:
+
+       /*
+        * r5 - to
+        * r6 - from
+        * r7 - len
+        * r3 - temp count
+        * r4 - temp val
+        */
+       addik   r3,r7,0         /* temp_count = len */
+       beqi    r3,3f
+1:
+       lbu     r4,r6,r0
+       sb      r4,r5,r0
+
+       addik   r3,r3,-1
+       beqi    r3,2f           /* break on len */
+
+       addik   r5,r5,1
+       bneid   r4,1b
+       addik   r6,r6,1         /* delay slot */
+       addik   r3,r3,1         /* undo "temp_count--" */
+2:
+       rsubk   r3,r3,r7        /* temp_count = len - temp_count */
+3:
+       rtsd    r15,8
+       nop
+
+
+       .section        .fixup, "ax"
+       .align  2
+4:
+       brid    3b
+       addik   r3,r0, -EFAULT
+
+       .section        __ex_table, "a"
+       .word   1b,4b
+
+/*
+ * int __strnlen_user(char __user *str, int maxlen);
+ *
+ * Returns:
+ *  0 on error
+ *  maxlen + 1  if no NUL byte found within maxlen bytes
+ *  size of the string (including NUL byte)
+ */
+
+       .text
+.globl __strnlen_user;
+.align 4;
+__strnlen_user:
+       addik   r3,r6,0
+       beqi    r3,3f
+1:
+       lbu     r4,r5,r0
+       beqid   r4,2f           /* break on NUL */
+       addik   r3,r3,-1        /* delay slot */
+
+       bneid   r3,1b
+       addik   r5,r5,1         /* delay slot */
+
+       addik   r3,r3,-1        /* for break on len */
+2:
+       rsubk   r3,r3,r6
+3:
+       rtsd    r15,8
+       nop
+
+
+       .section        .fixup,"ax"
+4:
+       brid    3b
+       addk    r3,r0,r0
+
+       .section        __ex_table,"a"
+       .word   1b,4b
+
+/*
+ * int __copy_tofrom_user(char *to, char *from, int len)
+ * Return:
+ *   0 on success
+ *   number of not copied bytes on error
+ */
+       .text
+.globl __copy_tofrom_user;
+.align 4;
+__copy_tofrom_user:
+       /*
+        * r5 - to
+        * r6 - from
+        * r7, r3 - count
+        * r4 - tempval
+        */
+       addik   r3,r7,0
+       beqi    r3,3f
+1:
+       lbu     r4,r6,r0
+       addik   r6,r6,1
+2:
+       sb      r4,r5,r0
+       addik   r3,r3,-1
+       bneid   r3,1b
+       addik   r5,r5,1         /* delay slot */
+3:
+       rtsd    r15,8
+       nop
+
+
+       .section        __ex_table,"a"
+       .word   1b,3b,2b,3b
index bf9e4479a1fdb82fe142043db8072de44b854551..6c8a924d9e266f8313b7107abc844c853968f633 100644 (file)
@@ -3,3 +3,5 @@
 #
 
 obj-y := init.o
+
+obj-$(CONFIG_MMU) += pgtable.o mmu_context.o fault.o
diff --git a/arch/microblaze/mm/fault.c b/arch/microblaze/mm/fault.c
new file mode 100644 (file)
index 0000000..5e67cd1
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ *  arch/microblaze/mm/fault.c
+ *
+ *    Copyright (C) 2007 Xilinx, Inc.  All rights reserved.
+ *
+ *  Derived from "arch/ppc/mm/fault.c"
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Derived from "arch/i386/mm/fault.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  Modified by Cort Dougan and Paul Mackerras.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/mmu.h>
+#include <asm/mmu_context.h>
+#include <asm/system.h>
+#include <linux/uaccess.h>
+#include <asm/exceptions.h>
+
+#if defined(CONFIG_KGDB)
+int debugger_kernel_faults = 1;
+#endif
+
+static unsigned long pte_misses;       /* updated by do_page_fault() */
+static unsigned long pte_errors;       /* updated by do_page_fault() */
+
+/*
+ * Check whether the instruction at regs->pc is a store using
+ * an update addressing form which will update r1.
+ */
+static int store_updates_sp(struct pt_regs *regs)
+{
+       unsigned int inst;
+
+       if (get_user(inst, (unsigned int *)regs->pc))
+               return 0;
+       /* check for 1 in the rD field */
+       if (((inst >> 21) & 0x1f) != 1)
+               return 0;
+       /* check for store opcodes */
+       if ((inst & 0xd0000000) == 0xd0000000)
+               return 1;
+       return 0;
+}
+
+
+/*
+ * bad_page_fault is called when we have a bad access from the kernel.
+ * It is called from do_page_fault above and from some of the procedures
+ * in traps.c.
+ */
+static void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
+{
+       const struct exception_table_entry *fixup;
+/* MS: no context */
+       /* Are we prepared to handle this fault?  */
+       fixup = search_exception_tables(regs->pc);
+       if (fixup) {
+               regs->pc = fixup->fixup;
+               return;
+       }
+
+       /* kernel has accessed a bad area */
+#if defined(CONFIG_KGDB)
+       if (debugger_kernel_faults)
+               debugger(regs);
+#endif
+       die("kernel access of bad area", regs, sig);
+}
+
+/*
+ * The error_code parameter is ESR for a data fault,
+ * 0 for an instruction fault.
+ */
+void do_page_fault(struct pt_regs *regs, unsigned long address,
+                  unsigned long error_code)
+{
+       struct vm_area_struct *vma;
+       struct mm_struct *mm = current->mm;
+       siginfo_t info;
+       int code = SEGV_MAPERR;
+       int is_write = error_code & ESR_S;
+       int fault;
+
+       regs->ear = address;
+       regs->esr = error_code;
+
+       /* On a kernel SLB miss we can only check for a valid exception entry */
+       if (kernel_mode(regs) && (address >= TASK_SIZE)) {
+               printk(KERN_WARNING "kernel task_size exceed");
+               _exception(SIGSEGV, regs, code, address);
+       }
+
+       /* for instr TLB miss and instr storage exception ESR_S is undefined */
+       if ((error_code & 0x13) == 0x13 || (error_code & 0x11) == 0x11)
+               is_write = 0;
+
+#if defined(CONFIG_KGDB)
+       if (debugger_fault_handler && regs->trap == 0x300) {
+               debugger_fault_handler(regs);
+               return;
+       }
+#endif /* CONFIG_KGDB */
+
+       if (in_atomic() || mm == NULL) {
+               /* FIXME */
+               if (kernel_mode(regs)) {
+                       printk(KERN_EMERG
+                               "Page fault in kernel mode - Oooou!!! pid %d\n",
+                               current->pid);
+                       _exception(SIGSEGV, regs, code, address);
+                       return;
+               }
+               /* in_atomic() in user mode is really bad,
+                  as is current->mm == NULL. */
+               printk(KERN_EMERG "Page fault in user mode with "
+                      "in_atomic(), mm = %p\n", mm);
+               printk(KERN_EMERG "r15 = %lx  MSR = %lx\n",
+                      regs->r15, regs->msr);
+               die("Weird page fault", regs, SIGSEGV);
+       }
+
+       /* When running in the kernel we expect faults to occur only to
+        * addresses in user space.  All other faults represent errors in the
+        * kernel and should generate an OOPS.  Unfortunately, in the case of an
+        * erroneous fault occurring in a code path which already holds mmap_sem
+        * we will deadlock attempting to validate the fault against the
+        * address space.  Luckily the kernel only validly references user
+        * space from well defined areas of code, which are listed in the
+        * exceptions table.
+        *
+        * As the vast majority of faults will be valid we will only perform
+        * the source reference check when there is a possibility of a deadlock.
+        * Attempt to lock the address space, if we cannot we then validate the
+        * source.  If this is invalid we can skip the address space check,
+        * thus avoiding the deadlock.
+        */
+       if (!down_read_trylock(&mm->mmap_sem)) {
+               if (kernel_mode(regs) && !search_exception_tables(regs->pc))
+                       goto bad_area_nosemaphore;
+
+               down_read(&mm->mmap_sem);
+       }
+
+       vma = find_vma(mm, address);
+       if (!vma)
+               goto bad_area;
+
+       if (vma->vm_start <= address)
+               goto good_area;
+
+       if (!(vma->vm_flags & VM_GROWSDOWN))
+               goto bad_area;
+
+       if (!is_write)
+               goto bad_area;
+
+       /*
+        * N.B. The ABI allows programs to access up to
+        * a few hundred bytes below the stack pointer (TBD).
+        * The kernel signal delivery code writes up to about 1.5kB
+        * below the stack pointer (r1) before decrementing it.
+        * The exec code can write slightly over 640kB to the stack
+        * before setting the user r1.  Thus we allow the stack to
+        * expand to 1MB without further checks.
+        */
+       if (address + 0x100000 < vma->vm_end) {
+
+               /* get user regs even if this fault is in kernel mode */
+               struct pt_regs *uregs = current->thread.regs;
+               if (uregs == NULL)
+                       goto bad_area;
+
+               /*
+                * A user-mode access to an address a long way below
+                * the stack pointer is only valid if the instruction
+                * is one which would update the stack pointer to the
+                * address accessed if the instruction completed,
+                * i.e. either stwu rs,n(r1) or stwux rs,r1,rb
+                * (or the byte, halfword, float or double forms).
+                *
+                * If we don't check this then any write to the area
+                * between the last mapped region and the stack will
+                * expand the stack rather than segfaulting.
+                */
+               if (address + 2048 < uregs->r1
+                       && (kernel_mode(regs) || !store_updates_sp(regs)))
+                               goto bad_area;
+       }
+       if (expand_stack(vma, address))
+               goto bad_area;
+
+good_area:
+       code = SEGV_ACCERR;
+
+       /* a write */
+       if (is_write) {
+               if (!(vma->vm_flags & VM_WRITE))
+                       goto bad_area;
+       /* a read */
+       } else {
+               /* protection fault */
+               if (error_code & 0x08000000)
+                       goto bad_area;
+               if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+                       goto bad_area;
+       }
+
+       /*
+        * If for any reason at all we couldn't handle the fault,
+        * make sure we exit gracefully rather than endlessly redo
+        * the fault.
+        */
+survive:
+       fault = handle_mm_fault(mm, vma, address, is_write);
+       if (unlikely(fault & VM_FAULT_ERROR)) {
+               if (fault & VM_FAULT_OOM)
+                       goto out_of_memory;
+               else if (fault & VM_FAULT_SIGBUS)
+                       goto do_sigbus;
+               BUG();
+       }
+       if (fault & VM_FAULT_MAJOR)
+               current->maj_flt++;
+       else
+               current->min_flt++;
+       up_read(&mm->mmap_sem);
+       /*
+        * keep track of tlb+htab misses that are good addrs but
+        * just need pte's created via handle_mm_fault()
+        * -- Cort
+        */
+       pte_misses++;
+       return;
+
+bad_area:
+       up_read(&mm->mmap_sem);
+
+bad_area_nosemaphore:
+       pte_errors++;
+
+       /* User mode accesses cause a SIGSEGV */
+       if (user_mode(regs)) {
+               _exception(SIGSEGV, regs, code, address);
+/*             info.si_signo = SIGSEGV;
+               info.si_errno = 0;
+               info.si_code = code;
+               info.si_addr = (void *) address;
+               force_sig_info(SIGSEGV, &info, current);*/
+               return;
+       }
+
+       bad_page_fault(regs, address, SIGSEGV);
+       return;
+
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+out_of_memory:
+       if (current->pid == 1) {
+               yield();
+               down_read(&mm->mmap_sem);
+               goto survive;
+       }
+       up_read(&mm->mmap_sem);
+       printk(KERN_WARNING "VM: killing process %s\n", current->comm);
+       if (user_mode(regs))
+               do_exit(SIGKILL);
+       bad_page_fault(regs, address, SIGKILL);
+       return;
+
+do_sigbus:
+       up_read(&mm->mmap_sem);
+       if (user_mode(regs)) {
+               info.si_signo = SIGBUS;
+               info.si_errno = 0;
+               info.si_code = BUS_ADRERR;
+               info.si_addr = (void __user *)address;
+               force_sig_info(SIGBUS, &info, current);
+               return;
+       }
+       bad_page_fault(regs, address, SIGBUS);
+}
index b0c8213cd6cf3c4322aa261e54f7c29e7b704766..b5a701cd71e08d86ceec067f011c98b4abe0f419 100644 (file)
 #include <asm/sections.h>
 #include <asm/tlb.h>
 
+#ifndef CONFIG_MMU
 unsigned int __page_offset;
-/* EXPORT_SYMBOL(__page_offset); */
+EXPORT_SYMBOL(__page_offset);
+
+#else
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+
+int mem_init_done;
+static int init_bootmem_done;
+#endif /* CONFIG_MMU */
 
 char *klimit = _end;
 
@@ -32,28 +40,26 @@ char *klimit = _end;
  * Initialize the bootmem system and give it all the memory we
  * have available.
  */
-unsigned int memory_start;
-unsigned int memory_end; /* due to mm/nommu.c */
-unsigned int memory_size;
+unsigned long memory_start;
+unsigned long memory_end; /* due to mm/nommu.c */
+unsigned long memory_size;
 
 /*
  * paging_init() sets up the page tables - in fact we've already done this.
  */
 static void __init paging_init(void)
 {
-       int i;
        unsigned long zones_size[MAX_NR_ZONES];
 
+       /* Clean every zones */
+       memset(zones_size, 0, sizeof(zones_size));
+
        /*
         * old: we can DMA to/from any address.put all page into ZONE_DMA
         * We use only ZONE_NORMAL
         */
        zones_size[ZONE_NORMAL] = max_mapnr;
 
-       /* every other zones are empty */
-       for (i = 1; i < MAX_NR_ZONES; i++)
-               zones_size[i] = 0;
-
        free_area_init(zones_size);
 }
 
@@ -61,6 +67,7 @@ void __init setup_memory(void)
 {
        int i;
        unsigned long map_size;
+#ifndef CONFIG_MMU
        u32 kernel_align_start, kernel_align_size;
 
        /* Find main memory where is the kernel */
@@ -93,6 +100,7 @@ void __init setup_memory(void)
                __func__, kernel_align_start, kernel_align_start
                        + kernel_align_size, kernel_align_size);
 
+#endif
        /*
         * Kernel:
         * start: base phys address of kernel - page align
@@ -121,9 +129,13 @@ void __init setup_memory(void)
         * for 4GB of memory, using 4kB pages), plus 1 page
         * (in case the address isn't page-aligned).
         */
+#ifndef CONFIG_MMU
        map_size = init_bootmem_node(NODE_DATA(0), PFN_UP(TOPHYS((u32)_end)),
                                        min_low_pfn, max_low_pfn);
-
+#else
+       map_size = init_bootmem_node(&contig_page_data,
+               PFN_UP(TOPHYS((u32)_end)), min_low_pfn, max_low_pfn);
+#endif
        lmb_reserve(PFN_UP(TOPHYS((u32)_end)) << PAGE_SHIFT, map_size);
 
        /* free bootmem is whole main memory */
@@ -137,6 +149,9 @@ void __init setup_memory(void)
                reserve_bootmem(lmb.reserved.region[i].base,
                        lmb_size_bytes(&lmb.reserved, i) - 1, BOOTMEM_DEFAULT);
        }
+#ifdef CONFIG_MMU
+       init_bootmem_done = 1;
+#endif
        paging_init();
 }
 
@@ -191,11 +206,145 @@ void __init mem_init(void)
        printk(KERN_INFO "Memory: %luk/%luk available\n",
               (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
               num_physpages << (PAGE_SHIFT-10));
+#ifdef CONFIG_MMU
+       mem_init_done = 1;
+#endif
 }
 
+#ifndef CONFIG_MMU
 /* Check against bounds of physical memory */
 int ___range_ok(unsigned long addr, unsigned long size)
 {
        return ((addr < memory_start) ||
                ((addr + size) > memory_end));
 }
+EXPORT_SYMBOL(___range_ok);
+
+#else
+int page_is_ram(unsigned long pfn)
+{
+       return pfn < max_low_pfn;
+}
+
+/*
+ * Check for command-line options that affect what MMU_init will do.
+ */
+static void mm_cmdline_setup(void)
+{
+       unsigned long maxmem = 0;
+       char *p = cmd_line;
+
+       /* Look for mem= option on command line */
+       p = strstr(cmd_line, "mem=");
+       if (p) {
+               p += 4;
+               maxmem = memparse(p, &p);
+               if (maxmem && memory_size > maxmem) {
+                       memory_size = maxmem;
+                       memory_end = memory_start + memory_size;
+                       lmb.memory.region[0].size = memory_size;
+               }
+       }
+}
+
+/*
+ * MMU_init_hw does the chip-specific initialization of the MMU hardware.
+ */
+static void __init mmu_init_hw(void)
+{
+       /*
+        * The Zone Protection Register (ZPR) defines how protection will
+        * be applied to every page which is a member of a given zone. At
+        * present, we utilize only two of the zones.
+        * The zone index bits (of ZSEL) in the PTE are used for software
+        * indicators, except the LSB.  For user access, zone 1 is used,
+        * for kernel access, zone 0 is used.  We set all but zone 1
+        * to zero, allowing only kernel access as indicated in the PTE.
+        * For zone 1, we set a 01 binary (a value of 10 will not work)
+        * to allow user access as indicated in the PTE.  This also allows
+        * kernel access as indicated in the PTE.
+        */
+       __asm__ __volatile__ ("ori r11, r0, 0x10000000;" \
+                       "mts rzpr, r11;"
+                       : : : "r11");
+}
+
+/*
+ * MMU_init sets up the basic memory mappings for the kernel,
+ * including both RAM and possibly some I/O regions,
+ * and sets up the page tables and the MMU hardware ready to go.
+ */
+
+/* called from head.S */
+asmlinkage void __init mmu_init(void)
+{
+       unsigned int kstart, ksize;
+
+       if (!lmb.reserved.cnt) {
+               printk(KERN_EMERG "Error memory count\n");
+               machine_restart(NULL);
+       }
+
+       if ((u32) lmb.memory.region[0].size < 0x1000000) {
+               printk(KERN_EMERG "Memory must be greater than 16MB\n");
+               machine_restart(NULL);
+       }
+       /* Find main memory where the kernel is */
+       memory_start = (u32) lmb.memory.region[0].base;
+       memory_end = (u32) lmb.memory.region[0].base +
+                               (u32) lmb.memory.region[0].size;
+       memory_size = memory_end - memory_start;
+
+       mm_cmdline_setup(); /* FIXME parse args from command line - not used */
+
+       /*
+        * Map out the kernel text/data/bss from the available physical
+        * memory.
+        */
+       kstart = __pa(CONFIG_KERNEL_START); /* kernel start */
+       /* kernel size */
+       ksize = PAGE_ALIGN(((u32)_end - (u32)CONFIG_KERNEL_START));
+       lmb_reserve(kstart, ksize);
+
+#if defined(CONFIG_BLK_DEV_INITRD)
+       /* Remove the init RAM disk from the available memory. */
+/*     if (initrd_start) {
+               mem_pieces_remove(&phys_avail, __pa(initrd_start),
+                                 initrd_end - initrd_start, 1);
+       }*/
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+       /* Initialize the MMU hardware */
+       mmu_init_hw();
+
+       /* Map in all of RAM starting at CONFIG_KERNEL_START */
+       mapin_ram();
+
+#ifdef HIGHMEM_START_BOOL
+       ioremap_base = HIGHMEM_START;
+#else
+       ioremap_base = 0xfe000000UL;    /* for now, could be 0xfffff000 */
+#endif /* CONFIG_HIGHMEM */
+       ioremap_bot = ioremap_base;
+
+       /* Initialize the context management stuff */
+       mmu_context_init();
+}
+
+/* This is only called until mem_init is done. */
+void __init *early_get_page(void)
+{
+       void *p;
+       if (init_bootmem_done) {
+               p = alloc_bootmem_pages(PAGE_SIZE);
+       } else {
+               /*
+                * Mem start + 32MB -> here is limit
+                * because of mem mapping from head.S
+                */
+               p = __va(lmb_alloc_base(PAGE_SIZE, PAGE_SIZE,
+                                       memory_start + 0x2000000));
+       }
+       return p;
+}
+#endif /* CONFIG_MMU */
diff --git a/arch/microblaze/mm/mmu_context.c b/arch/microblaze/mm/mmu_context.c
new file mode 100644 (file)
index 0000000..26ff82f
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * This file contains the routines for handling the MMU.
+ *
+ *    Copyright (C) 2007 Xilinx, Inc.  All rights reserved.
+ *
+ *  Derived from arch/ppc/mm/4xx_mmu.c:
+ *  -- paulus
+ *
+ *  Derived from arch/ppc/mm/init.c:
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
+ *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ *    Copyright (C) 1996 Paul Mackerras
+ *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  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/mm.h>
+#include <linux/init.h>
+
+#include <asm/tlbflush.h>
+#include <asm/mmu_context.h>
+
+mm_context_t next_mmu_context;
+unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1];
+atomic_t nr_free_contexts;
+struct mm_struct *context_mm[LAST_CONTEXT+1];
+
+/*
+ * Initialize the context management stuff.
+ */
+void __init mmu_context_init(void)
+{
+       /*
+        * The use of context zero is reserved for the kernel.
+        * This code assumes FIRST_CONTEXT < 32.
+        */
+       context_map[0] = (1 << FIRST_CONTEXT) - 1;
+       next_mmu_context = FIRST_CONTEXT;
+       atomic_set(&nr_free_contexts, LAST_CONTEXT - FIRST_CONTEXT + 1);
+}
+
+/*
+ * Steal a context from a task that has one at the moment.
+ *
+ * This isn't an LRU system, it just frees up each context in
+ * turn (sort-of pseudo-random replacement :).  This would be the
+ * place to implement an LRU scheme if anyone were motivated to do it.
+ */
+void steal_context(void)
+{
+       struct mm_struct *mm;
+
+       /* free up context `next_mmu_context' */
+       /* if we shouldn't free context 0, don't... */
+       if (next_mmu_context < FIRST_CONTEXT)
+               next_mmu_context = FIRST_CONTEXT;
+       mm = context_mm[next_mmu_context];
+       flush_tlb_mm(mm);
+       destroy_context(mm);
+}
diff --git a/arch/microblaze/mm/pgtable.c b/arch/microblaze/mm/pgtable.c
new file mode 100644 (file)
index 0000000..46c4ca5
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ *  This file contains the routines setting up the linux page tables.
+ *
+ * Copyright (C) 2008 Michal Simek
+ * Copyright (C) 2008 PetaLogix
+ *
+ *    Copyright (C) 2007 Xilinx, Inc.  All rights reserved.
+ *
+ *  Derived from arch/ppc/mm/pgtable.c:
+ *    -- paulus
+ *
+ *  Derived from arch/ppc/mm/init.c:
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
+ *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ *    Copyright (C) 1996 Paul Mackerras
+ *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  This file is subject to the terms and conditions of the GNU General
+ *  Public License.  See the file COPYING in the main directory of this
+ *  archive for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <linux/io.h>
+#include <asm/mmu.h>
+#include <asm/sections.h>
+
+#define flush_HPTE(X, va, pg)  _tlbie(va)
+
+unsigned long ioremap_base;
+unsigned long ioremap_bot;
+
+/* The maximum lowmem defaults to 768Mb, but this can be configured to
+ * another value.
+ */
+#define MAX_LOW_MEM    CONFIG_LOWMEM_SIZE
+
+#ifndef CONFIG_SMP
+struct pgtable_cache_struct quicklists;
+#endif
+
+static void __iomem *__ioremap(phys_addr_t addr, unsigned long size,
+               unsigned long flags)
+{
+       unsigned long v, i;
+       phys_addr_t p;
+       int err;
+
+       /*
+        * Choose an address to map it to.
+        * Once the vmalloc system is running, we use it.
+        * Before then, we use space going down from ioremap_base
+        * (ioremap_bot records where we're up to).
+        */
+       p = addr & PAGE_MASK;
+       size = PAGE_ALIGN(addr + size) - p;
+
+       /*
+        * Don't allow anybody to remap normal RAM that we're using.
+        * mem_init() sets high_memory so only do the check after that.
+        *
+        * However, allow remap of rootfs: TBD
+        */
+       if (mem_init_done &&
+               p >= memory_start && p < virt_to_phys(high_memory) &&
+               !(p >= virt_to_phys((unsigned long)&__bss_stop) &&
+               p < virt_to_phys((unsigned long)__bss_stop))) {
+               printk(KERN_WARNING "__ioremap(): phys addr "PTE_FMT
+                       " is RAM lr %p\n", (unsigned long)p,
+                       __builtin_return_address(0));
+               return NULL;
+       }
+
+       if (size == 0)
+               return NULL;
+
+       /*
+        * Is it already mapped? If the whole area is mapped then we're
+        * done, otherwise remap it since we want to keep the virt addrs for
+        * each request contiguous.
+        *
+        * We make the assumption here that if the bottom and top
+        * of the range we want are mapped then it's mapped to the
+        * same virt address (and this is contiguous).
+        *  -- Cort
+        */
+
+       if (mem_init_done) {
+               struct vm_struct *area;
+               area = get_vm_area(size, VM_IOREMAP);
+               if (area == NULL)
+                       return NULL;
+               v = VMALLOC_VMADDR(area->addr);
+       } else {
+               v = (ioremap_bot -= size);
+       }
+
+       if ((flags & _PAGE_PRESENT) == 0)
+               flags |= _PAGE_KERNEL;
+       if (flags & _PAGE_NO_CACHE)
+               flags |= _PAGE_GUARDED;
+
+       err = 0;
+       for (i = 0; i < size && err == 0; i += PAGE_SIZE)
+               err = map_page(v + i, p + i, flags);
+       if (err) {
+               if (mem_init_done)
+                       vfree((void *)v);
+               return NULL;
+       }
+
+       return (void __iomem *) (v + ((unsigned long)addr & ~PAGE_MASK));
+}
+
+void __iomem *ioremap(phys_addr_t addr, unsigned long size)
+{
+       return __ioremap(addr, size, _PAGE_NO_CACHE);
+}
+EXPORT_SYMBOL(ioremap);
+
+void iounmap(void *addr)
+{
+       if (addr > high_memory && (unsigned long) addr < ioremap_bot)
+               vfree((void *) (PAGE_MASK & (unsigned long) addr));
+}
+EXPORT_SYMBOL(iounmap);
+
+
+int map_page(unsigned long va, phys_addr_t pa, int flags)
+{
+       pmd_t *pd;
+       pte_t *pg;
+       int err = -ENOMEM;
+       /* spin_lock(&init_mm.page_table_lock); */
+       /* Use upper 10 bits of VA to index the first level map */
+       pd = pmd_offset(pgd_offset_k(va), va);
+       /* Use middle 10 bits of VA to index the second-level map */
+       pg = pte_alloc_kernel(pd, va); /* from powerpc - pgtable.c */
+       /* pg = pte_alloc_kernel(&init_mm, pd, va); */
+
+       if (pg != NULL) {
+               err = 0;
+               set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT,
+                               __pgprot(flags)));
+               if (mem_init_done)
+                       flush_HPTE(0, va, pmd_val(*pd));
+                       /* flush_HPTE(0, va, pg); */
+
+       }
+       /* spin_unlock(&init_mm.page_table_lock); */
+       return err;
+}
+
+void __init adjust_total_lowmem(void)
+{
+/* TBD */
+#if 0
+       unsigned long max_low_mem = MAX_LOW_MEM;
+
+       if (total_lowmem > max_low_mem) {
+               total_lowmem = max_low_mem;
+#ifndef CONFIG_HIGHMEM
+               printk(KERN_INFO "Warning, memory limited to %ld Mb, use "
+                               "CONFIG_HIGHMEM to reach %ld Mb\n",
+                               max_low_mem >> 20, total_memory >> 20);
+               total_memory = total_lowmem;
+#endif /* CONFIG_HIGHMEM */
+       }
+#endif
+}
+
+static void show_tmem(unsigned long tmem)
+{
+       volatile unsigned long a;
+       a = a + tmem;
+}
+
+/*
+ * Map in all of physical memory starting at CONFIG_KERNEL_START.
+ */
+void __init mapin_ram(void)
+{
+       unsigned long v, p, s, f;
+
+       v = CONFIG_KERNEL_START;
+       p = memory_start;
+       show_tmem(memory_size);
+       for (s = 0; s < memory_size; s += PAGE_SIZE) {
+               f = _PAGE_PRESENT | _PAGE_ACCESSED |
+                               _PAGE_SHARED | _PAGE_HWEXEC;
+               if ((char *) v < _stext || (char *) v >= _etext)
+                       f |= _PAGE_WRENABLE;
+               else
+                       /* On the MicroBlaze, no user access
+                          forces R/W kernel access */
+                       f |= _PAGE_USER;
+               map_page(v, p, f);
+               v += PAGE_SIZE;
+               p += PAGE_SIZE;
+       }
+}
+
+/* is x a power of 2? */
+#define is_power_of_2(x)       ((x) != 0 && (((x) & ((x) - 1)) == 0))
+
+/*
+ * Set up a mapping for a block of I/O.
+ * virt, phys, size must all be page-aligned.
+ * This should only be called before ioremap is called.
+ */
+void __init io_block_mapping(unsigned long virt, phys_addr_t phys,
+                            unsigned int size, int flags)
+{
+       int i;
+
+       if (virt > CONFIG_KERNEL_START && virt < ioremap_bot)
+               ioremap_bot = ioremap_base = virt;
+
+       /* Put it in the page tables. */
+       for (i = 0; i < size; i += PAGE_SIZE)
+               map_page(virt + i, phys + i, flags);
+}
+
+/* Scan the real Linux page tables and return a PTE pointer for
+ * a virtual address in a context.
+ * Returns true (1) if PTE was found, zero otherwise.  The pointer to
+ * the PTE pointer is unmodified if PTE is not found.
+ */
+static int get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep)
+{
+       pgd_t   *pgd;
+       pmd_t   *pmd;
+       pte_t   *pte;
+       int     retval = 0;
+
+       pgd = pgd_offset(mm, addr & PAGE_MASK);
+       if (pgd) {
+               pmd = pmd_offset(pgd, addr & PAGE_MASK);
+               if (pmd_present(*pmd)) {
+                       pte = pte_offset_kernel(pmd, addr & PAGE_MASK);
+                       if (pte) {
+                               retval = 1;
+                               *ptep = pte;
+                       }
+               }
+       }
+       return retval;
+}
+
+/* Find physical address for this virtual address.  Normally used by
+ * I/O functions, but anyone can call it.
+ */
+unsigned long iopa(unsigned long addr)
+{
+       unsigned long pa;
+
+       pte_t *pte;
+       struct mm_struct *mm;
+
+       /* Allow mapping of user addresses (within the thread)
+        * for DMA if necessary.
+        */
+       if (addr < TASK_SIZE)
+               mm = current->mm;
+       else
+               mm = &init_mm;
+
+       pa = 0;
+       if (get_pteptr(mm, addr, &pte))
+               pa = (pte_val(*pte) & PAGE_MASK) | (addr & ~PAGE_MASK);
+
+       return pa;
+}
index 1b332e15ab528522c19e4769c7691435e843dce1..eb7f01cfd1acb906e2dd1a4ffd02bbd4893bf9f8 100644 (file)
@@ -793,6 +793,6 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
 #define smp_mb__before_atomic_inc()    smp_llsc_mb()
 #define smp_mb__after_atomic_inc()     smp_llsc_mb()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 
 #endif /* _ASM_ATOMIC_H */
diff --git a/arch/mips/include/asm/bitsperlong.h b/arch/mips/include/asm/bitsperlong.h
new file mode 100644 (file)
index 0000000..3e4c10a
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __ASM_MIPS_BITSPERLONG_H
+#define __ASM_MIPS_BITSPERLONG_H
+
+#define __BITS_PER_LONG _MIPS_SZLONG
+
+#include <asm-generic/bitsperlong.h>
+
+#endif /* __ASM_MIPS_BITSPERLONG_H */
index 9f946e4ca0574fbdc3ab376554d7ba7497493fce..72c80d2034c2064022ecfc2136ca8f4931e77d08 100644 (file)
@@ -189,6 +189,6 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 #define CAC_ADDR(addr)         ((addr) - UNCAC_BASE + PAGE_OFFSET)
 
 #include <asm-generic/memory_model.h>
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* _ASM_PAGE_H */
index bee5153aca483b44e03ece34a54a7a51d6795141..c783f364938ccd82ec1c99bc28bac0dfcbce54ef 100644 (file)
@@ -109,7 +109,7 @@ typedef unsigned long old_sigset_t;         /* at least 32 bits */
 #define SIG_UNBLOCK    2       /* for unblocking signals */
 #define SIG_SETMASK    3       /* for setting the signal mask */
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 struct sigaction {
        unsigned int    sa_flags;
diff --git a/arch/mips/include/asm/suspend.h b/arch/mips/include/asm/suspend.h
deleted file mode 100644 (file)
index 2562f8f..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_SUSPEND_H
-#define __ASM_SUSPEND_H
-
-/* Somewhen...  Maybe :-)  */
-
-#endif /* __ASM_SUSPEND_H */
index 7956e69a3bd5cfe6a8b50466f7460996599f9ce5..544a2854598f0d6558269beb298fe839e161ea08 100644 (file)
@@ -31,9 +31,6 @@ typedef unsigned short umode_t;
  * These aren't exported outside the kernel to avoid name space clashes
  */
 #ifdef __KERNEL__
-
-#define BITS_PER_LONG _MIPS_SZLONG
-
 #ifndef __ASSEMBLY__
 
 #if (defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR)) \
index 1f60e27523d9e65ad43289462ee269e4c696ba30..3e9100dcc12db963337da41a7b47e6b8d1faed59 100644 (file)
@@ -68,8 +68,6 @@ void *module_alloc(unsigned long size)
 void module_free(struct module *mod, void *module_region)
 {
        vfree(module_region);
-       /* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
 }
 
 int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
index bc064825f9b1b11380f299c24d98fda795d31c0a..5bf5be9566dece295d8922a8c3c54aa9f5420615 100644 (file)
@@ -151,7 +151,7 @@ static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
 #define smp_mb__before_atomic_inc()    barrier()
 #define smp_mb__after_atomic_inc()     barrier()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_ATOMIC_H */
diff --git a/arch/mn10300/include/asm/bitsperlong.h b/arch/mn10300/include/asm/bitsperlong.h
new file mode 100644 (file)
index 0000000..6dc0bb0
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/bitsperlong.h>
index b7986b65addf81da83bebc77446966373bd155eb..d04fac1da5aa80513f350afc18dd603fc0c0b4dd 100644 (file)
@@ -12,7 +12,7 @@
 #ifndef _ASM_MMAN_H
 #define _ASM_MMAN_H
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 #define MAP_GROWSDOWN  0x0100          /* stack-like segment */
 #define MAP_DENYWRITE  0x0800          /* ETXTBSY */
index 921942ed1b03508a582e6e226ed33acf50c8fa5b..1b0ba5e182b0c5624f18e20adb0764881f7f9606 100644 (file)
@@ -77,8 +77,6 @@ struct pt_regs {
 };
 #endif
 
-extern struct pt_regs *__frame; /* current frame pointer */
-
 /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
 #define PTRACE_GETREGS            12
 #define PTRACE_SETREGS            13
@@ -90,6 +88,8 @@ extern struct pt_regs *__frame; /* current frame pointer */
 
 #if defined(__KERNEL__)
 
+extern struct pt_regs *__frame;                /* current frame pointer */
+
 #if !defined(__ASSEMBLY__)
 struct task_struct;
 
@@ -107,5 +107,4 @@ extern void user_disable_single_step(struct task_struct *);
 #define profile_pc(regs) ((regs)->pc)
 
 #endif  /*  __KERNEL__  */
-
 #endif /* _ASM_PTRACE_H */
index 08356c83228329835a153bd18160af0650bbdb0d..c229d1e3f9990a6ed483e24c9e1d8b5035e4e427 100644 (file)
@@ -11,7 +11,8 @@
 #ifndef _ASM_SETUP_H
 #define _ASM_SETUP_H
 
+#ifdef __KERNEL__
 extern void __init unit_setup(void);
 extern void __init unit_init_IRQ(void);
-
+#endif
 #endif /* _ASM_SETUP_H */
index e98817cec5f7833873ffc24f23515f227da5a594..7e891fce2370028acea4a56497aafa74c443c0be 100644 (file)
@@ -115,7 +115,7 @@ typedef unsigned long sigset_t;
 #define MINSIGSTKSZ    2048
 #define SIGSTKSZ       8192
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
index 6b287f2e8e843f885c9a856df8527f862e9147a1..4fa0e3648d8ee909ada33bc1a4156dcb25b7b9f1 100644 (file)
@@ -48,8 +48,6 @@ void *module_alloc(unsigned long size)
 void module_free(struct module *mod, void *module_region)
 {
        vfree(module_region);
-       /* FIXME: If module_region == mod->init_region, trim exception
-        * table entries. */
 }
 
 /*
index ada3e5364d8254993f85d9586c51abb1278cb6bc..7eeaff944360335c8548b0f25e1828432ea55f9b 100644 (file)
@@ -338,6 +338,6 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
 
 #endif /* CONFIG_64BIT */
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 
 #endif /* _ASM_PARISC_ATOMIC_H_ */
diff --git a/arch/parisc/include/asm/bitsperlong.h b/arch/parisc/include/asm/bitsperlong.h
new file mode 100644 (file)
index 0000000..75196b4
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef __ASM_PARISC_BITSPERLONG_H
+#define __ASM_PARISC_BITSPERLONG_H
+
+/*
+ * using CONFIG_* outside of __KERNEL__ is wrong,
+ * __LP64__ was also removed from headers, so what
+ * is the right approach on parisc?
+ *     -arnd
+ */
+#if (defined(__KERNEL__) && defined(CONFIG_64BIT)) || defined (__LP64__)
+#define __BITS_PER_LONG 64
+#define SHIFT_PER_LONG 6
+#else
+#define __BITS_PER_LONG 32
+#define SHIFT_PER_LONG 5
+#endif
+
+#include <asm-generic/bitsperlong.h>
+
+#endif /* __ASM_PARISC_BITSPERLONG_H */
index 7bc5125d7d4c9f83a1f7bcd6b4bf980d4fdbaea3..a84cc1f925f63ed22a0b18f28debcb760fe4b528 100644 (file)
@@ -159,6 +159,6 @@ extern int npmem_ranges;
                                 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
 #include <asm-generic/memory_model.h>
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* _PARISC_PAGE_H */
index 7f5a39bfb4ce1eabecfed3e1cc88f27d3cee078f..20135cc8003924dc688d1abd52e064fbbf317fd5 100644 (file)
@@ -14,14 +14,6 @@ typedef unsigned short umode_t;
  */
 #ifdef __KERNEL__
 
-#ifdef CONFIG_64BIT
-#define BITS_PER_LONG 64
-#define SHIFT_PER_LONG 6
-#else
-#define BITS_PER_LONG 32
-#define SHIFT_PER_LONG 5
-#endif
-
 #ifndef __ASSEMBLY__
 
 /* Dma addresses are 32-bits wide.  */
index cd4c0b2a8e70bf228a27a47a376afa1aa2ff8d9b..7cf799d70b4c1b5da344895ddc6c055fe8d26686 100644 (file)
@@ -7,7 +7,7 @@
 #include <asm/page.h>
 #include <asm/system.h>
 #include <asm/cache.h>
-#include <asm-generic/uaccess.h>
+#include <asm-generic/uaccess-unaligned.h>
 
 #define VERIFY_READ 0
 #define VERIFY_WRITE 1
index ecd1c50244470db01620f67615e5562b87d2bcec..ef5caf2e6ed0820944c9ea891dd33c49c2a5ceda 100644 (file)
@@ -267,8 +267,6 @@ void module_free(struct module *mod, void *module_region)
        mod->arch.section = NULL;
 
        vfree(module_region);
-       /* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
 }
 
 /* Additional bytes needed in front of individual sections */
index b401950f5259e6a16a7d38a1fa3c0c509d6183ee..b7d2d07b6f965f5a613c92b12ebaf23fd938c141 100644 (file)
@@ -472,6 +472,6 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
 
 #endif /* __powerpc64__ */
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_ATOMIC_H_ */
diff --git a/arch/powerpc/include/asm/bitsperlong.h b/arch/powerpc/include/asm/bitsperlong.h
new file mode 100644 (file)
index 0000000..5f16590
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef __ASM_POWERPC_BITSPERLONG_H
+#define __ASM_POWERPC_BITSPERLONG_H
+
+#if defined(__powerpc64__)
+# define __BITS_PER_LONG 64
+#else
+# define __BITS_PER_LONG 32
+#endif
+
+#include <asm-generic/bitsperlong.h>
+
+#endif /* __ASM_POWERPC_BITSPERLONG_H */
index e7b99bac9f4875312655e1f3b44799b6734f6a16..7b1c49811a2439cb195aa3d311da2e2493b612f9 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef _ASM_POWERPC_MMAN_H
 #define _ASM_POWERPC_MMAN_H
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 /*
  * This program is free software; you can redistribute it and/or
index a218da6bec7c5ea69091196d363b9cb7c51158b0..fb841205745055151c43100d2e15ba33b80f9eed 100644 (file)
 #define MPC52xx_PSC_MAXNUM     6
 
 /* Programmable Serial Controller (PSC) status register bits */
+#define MPC52xx_PSC_SR_UNEX_RX 0x0001
+#define MPC52xx_PSC_SR_DATA_VAL        0x0002
+#define MPC52xx_PSC_SR_DATA_OVR        0x0004
+#define MPC52xx_PSC_SR_CMDSEND 0x0008
 #define MPC52xx_PSC_SR_CDE     0x0080
 #define MPC52xx_PSC_SR_RXRDY   0x0100
 #define MPC52xx_PSC_SR_RXFULL  0x0200
 #define MPC52xx_PSC_RXTX_FIFO_EMPTY    0x0001
 
 /* PSC interrupt status/mask bits */
+#define MPC52xx_PSC_IMR_UNEX_RX_SLOT 0x0001
+#define MPC52xx_PSC_IMR_DATA_VALID     0x0002
+#define MPC52xx_PSC_IMR_DATA_OVR       0x0004
+#define MPC52xx_PSC_IMR_CMD_SEND       0x0008
+#define MPC52xx_PSC_IMR_ERROR          0x0040
+#define MPC52xx_PSC_IMR_DEOF           0x0080
 #define MPC52xx_PSC_IMR_TXRDY          0x0100
 #define MPC52xx_PSC_IMR_RXRDY          0x0200
 #define MPC52xx_PSC_IMR_DB             0x0400
 #define MPC52xx_PSC_SICR_SIM_FIR               (0x6 << 24)
 #define MPC52xx_PSC_SICR_SIM_CODEC_24          (0x7 << 24)
 #define MPC52xx_PSC_SICR_SIM_CODEC_32          (0xf << 24)
+#define MPC52xx_PSC_SICR_AWR                   (1 << 30)
 #define MPC52xx_PSC_SICR_GENCLK                        (1 << 23)
 #define MPC52xx_PSC_SICR_I2S                   (1 << 22)
 #define MPC52xx_PSC_SICR_CLKPOL                        (1 << 21)
index a0e3f6e6b4eeadc2140080843dc35ebeda6c241f..bd0849dbcaaad4c6f87347cf2092a1079581b61e 100644 (file)
@@ -41,7 +41,7 @@ extern void clear_pages(void *page, int order);
 static inline void clear_page(void *page) { clear_pages(page, 0); }
 extern void copy_page(void *to, void *from);
 
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #define PGD_T_LOG2     (__builtin_ffs(sizeof(pgd_t)) - 1)
 #define PTE_T_LOG2     (__builtin_ffs(sizeof(pte_t)) - 1)
index 043bfdfe4f7379ed90edc7bf5119e25950e159a8..5817a3b747e53c12b516fd8229381b40486cd0e2 100644 (file)
@@ -180,6 +180,6 @@ do {                                                \
        (test_thread_flag(TIF_32BIT) ? \
         VM_STACK_DEFAULT_FLAGS32 : VM_STACK_DEFAULT_FLAGS64)
 
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* _ASM_POWERPC_PAGE_64_H */
index 69f709d8e8e750f781c3b7f2a507dd4043ef49d5..3eb13be11d8f6eff81fa251b8ab1c589ed35edce 100644 (file)
@@ -94,7 +94,7 @@ typedef struct {
 #define MINSIGSTKSZ    2048
 #define SIGSTKSZ       8192
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 struct old_sigaction {
        __sighandler_t sa_handler;
index 2c14fea07c8aa92ae9bc320553103dac8d255e67..a24f48704a3405ca468473aafacd961765d5d48d 100644 (file)
@@ -78,7 +78,7 @@ struct termio {
 
 #ifdef __KERNEL__
 
-#include <asm-generic/termios.h>
+#include <asm-generic/termios-base.h>
 
 #endif /* __KERNEL__ */
 
index 7ce27a52bb3450d56ba038000febbb9e555e4572..a5aea0ca34e9a3dc98fdf4b504cc56e472baad87 100644 (file)
@@ -40,15 +40,6 @@ typedef struct {
 #endif /* __ASSEMBLY__ */
 
 #ifdef __KERNEL__
-/*
- * These aren't exported outside the kernel to avoid name space clashes
- */
-#ifdef __powerpc64__
-#define BITS_PER_LONG 64
-#else
-#define BITS_PER_LONG 32
-#endif
-
 #ifndef __ASSEMBLY__
 
 typedef __vector128 vector128;
index 43e7e3a7f130220bdd56122c1560d42484a6db80..477c663e014043a5c08fbaf51e82853005391344 100644 (file)
@@ -43,8 +43,6 @@ void *module_alloc(unsigned long size)
 void module_free(struct module *mod, void *module_region)
 {
        vfree(module_region);
-       /* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
 }
 
 static const Elf_Shdr *find_section(const Elf_Ehdr *hdr,
index b3f7d1216bae8b8299735a8e3b03f267ddafcd5d..b72e7a19d05464982a9864d9f8d011bc335ad6dc 100644 (file)
@@ -294,12 +294,12 @@ static void power7_disable_pmc(unsigned int pmc, u64 mmcr[])
 }
 
 static int power7_generic_events[] = {
-       [PERF_COUNT_CPU_CYCLES] = 0x1e,
-       [PERF_COUNT_INSTRUCTIONS] = 2,
-       [PERF_COUNT_CACHE_REFERENCES] = 0xc880,         /* LD_REF_L1_LSU */
-       [PERF_COUNT_CACHE_MISSES] = 0x400f0,            /* LD_MISS_L1 */
-       [PERF_COUNT_BRANCH_INSTRUCTIONS] = 0x10068,     /* BRU_FIN */
-       [PERF_COUNT_BRANCH_MISSES] = 0x400f6,           /* BR_MPRED */
+       [PERF_COUNT_HW_CPU_CYCLES] = 0x1e,
+       [PERF_COUNT_HW_INSTRUCTIONS] = 2,
+       [PERF_COUNT_HW_CACHE_REFERENCES] = 0xc880,      /* LD_REF_L1_LSU*/
+       [PERF_COUNT_HW_CACHE_MISSES] = 0x400f0,         /* LD_MISS_L1   */
+       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x10068,  /* BRU_FIN      */
+       [PERF_COUNT_HW_BRANCH_MISSES] = 0x400f6,        /* BR_MPRED     */
 };
 
 #define C(x)   PERF_COUNT_HW_CACHE_##x
index 89497fb04280ce6bb63b50af6603c513c942d872..3b52c80e5e33866141630e1e4ddbe587f7dd519d 100644 (file)
@@ -2,7 +2,7 @@
  * PowerPC64 SLB support.
  *
  * Copyright (C) 2004 David Gibson <dwg@au.ibm.com>, IBM
- * Based on earlier code writteh by:
+ * Based on earlier code written by:
  * Dave Engebretsen and Mike Corrigan {engebret|mikejc}@us.ibm.com
  *    Copyright (c) 2001 Dave Engebretsen
  * Copyright (C) 2002 Anton Blanchard <anton@au.ibm.com>, IBM
index 2eca5fe0e75b243a71b3f0450ac756d9dea2a1f9..99dc3ded6b4975dc190d0243b856d539c9a932ce 100644 (file)
@@ -82,6 +82,11 @@ config S390
        select USE_GENERIC_SMP_HELPERS if SMP
        select HAVE_SYSCALL_WRAPPERS
        select HAVE_FUNCTION_TRACER
+       select HAVE_FUNCTION_TRACE_MCOUNT_TEST
+       select HAVE_FTRACE_MCOUNT_RECORD
+       select HAVE_FTRACE_SYSCALLS
+       select HAVE_DYNAMIC_FTRACE
+       select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_DEFAULT_NO_SPIN_MUTEXES
        select HAVE_OPROFILE
        select HAVE_KPROBES
@@ -567,6 +572,24 @@ bool "s390 guest support for KVM (EXPERIMENTAL)"
          the KVM hypervisor. This will add detection for KVM as well  as a
          virtio transport. If KVM is detected, the virtio console will be
          the default console.
+
+config SECCOMP
+       bool "Enable seccomp to safely compute untrusted bytecode"
+       depends on PROC_FS
+       default y
+       help
+         This kernel feature is useful for number crunching applications
+         that may need to compute untrusted bytecode during their
+         execution. By using pipes or other transports made available to
+         the process as file descriptors supporting the read/write
+         syscalls, it's possible to isolate those applications in
+         their own address space using seccomp. Once seccomp is
+         enabled via /proc/<pid>/seccomp, it cannot be disabled
+         and the task is only allowed to execute a few safe syscalls
+         defined by each seccomp mode.
+
+         If unsure, say Y.
+
 endmenu
 
 source "net/Kconfig"
index de432f2de2d22ed3f9f2362023a52caacea1bcb2..fca9dffcc669b186f779785ae8d1ac3a9858c356 100644 (file)
@@ -275,6 +275,6 @@ static __inline__ int atomic64_add_unless(atomic64_t *v,
 #define smp_mb__before_atomic_inc()    smp_mb()
 #define smp_mb__after_atomic_inc()     smp_mb()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* __KERNEL__ */
 #endif /* __ARCH_S390_ATOMIC__  */
diff --git a/arch/s390/include/asm/bitsperlong.h b/arch/s390/include/asm/bitsperlong.h
new file mode 100644 (file)
index 0000000..6b235ae
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __ASM_S390_BITSPERLONG_H
+#define __ASM_S390_BITSPERLONG_H
+
+#ifndef __s390x__
+#define __BITS_PER_LONG 32
+#else
+#define __BITS_PER_LONG 64
+#endif
+
+#include <asm-generic/bitsperlong.h>
+
+#endif /* __ASM_S390_BITSPERLONG_H */
+
index de065b32381a36867eb7bf6bc58f2b0ba8ddeec2..01a08020bc0e2bb3757e783ca51ee35478bbbc52 100644 (file)
@@ -5,6 +5,7 @@
  */
 #include <linux/types.h>
 #include <linux/sched.h>
+#include <linux/thread_info.h>
 
 #define PSW32_MASK_PER         0x40000000UL
 #define PSW32_MASK_DAT         0x04000000UL
@@ -163,12 +164,28 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr)
        return (u32)(unsigned long)uptr;
 }
 
+#ifdef CONFIG_COMPAT
+
+static inline int is_compat_task(void)
+{
+       return test_thread_flag(TIF_31BIT);
+}
+
+#else
+
+static inline int is_compat_task(void)
+{
+       return 0;
+}
+
+#endif
+
 static inline void __user *compat_alloc_user_space(long len)
 {
        unsigned long stack;
 
        stack = KSTK_ESP(current);
-       if (test_thread_flag(TIF_31BIT))
+       if (is_compat_task())
                stack &= 0x7fffffffUL;
        return (void __user *) (stack - len);
 }
diff --git a/arch/s390/include/asm/cpu.h b/arch/s390/include/asm/cpu.h
deleted file mode 100644 (file)
index d60a2ee..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- *  include/asm-s390/cpu.h
- *
- *    Copyright IBM Corp. 2007
- *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
- */
-
-#ifndef _ASM_S390_CPU_H_
-#define _ASM_S390_CPU_H_
-
-#include <linux/types.h>
-#include <linux/percpu.h>
-#include <linux/spinlock.h>
-
-struct s390_idle_data {
-       spinlock_t lock;
-       unsigned long long idle_count;
-       unsigned long long idle_enter;
-       unsigned long long idle_time;
-};
-
-DECLARE_PER_CPU(struct s390_idle_data, s390_idle);
-
-void vtime_start_cpu(void);
-
-static inline void s390_idle_check(void)
-{
-       if ((&__get_cpu_var(s390_idle))->idle_enter != 0ULL)
-               vtime_start_cpu();
-}
-
-#endif /* _ASM_S390_CPU_H_ */
index 941384fbd39c503b79bd9ebdebe3ef35772a6e7e..ec917d42ee6d2b18264e26fe6407d2ced5da17ed 100644 (file)
@@ -9,6 +9,9 @@
 #ifndef _S390_CPUTIME_H
 #define _S390_CPUTIME_H
 
+#include <linux/types.h>
+#include <linux/percpu.h>
+#include <linux/spinlock.h>
 #include <asm/div64.h>
 
 /* We want to use full resolution of the CPU timer: 2**-12 micro-seconds. */
@@ -174,8 +177,24 @@ cputime64_to_clock_t(cputime64_t cputime)
        return __div(cputime, 4096000000ULL / USER_HZ);
 }
 
+struct s390_idle_data {
+       spinlock_t lock;
+       unsigned long long idle_count;
+       unsigned long long idle_enter;
+       unsigned long long idle_time;
+};
+
+DECLARE_PER_CPU(struct s390_idle_data, s390_idle);
+
+void vtime_start_cpu(void);
 cputime64_t s390_get_idle_time(int cpu);
 
 #define arch_idle_time(cpu) s390_get_idle_time(cpu)
 
+static inline void s390_idle_check(void)
+{
+       if ((&__get_cpu_var(s390_idle))->idle_enter != 0ULL)
+               vtime_start_cpu();
+}
+
 #endif /* _S390_CPUTIME_H */
index 5a5bc75e19d4a3f94866a4da9ef31cf13b942356..96c14a9102b8beadc324ae8b50cf8c81806af420 100644 (file)
@@ -2,7 +2,28 @@
 #define _ASM_S390_FTRACE_H
 
 #ifndef __ASSEMBLY__
+
 extern void _mcount(void);
+extern unsigned long ftrace_dyn_func;
+
+struct dyn_arch_ftrace { };
+
+#define MCOUNT_ADDR ((long)_mcount)
+
+#ifdef CONFIG_64BIT
+#define MCOUNT_OFFSET_RET 18
+#define MCOUNT_INSN_SIZE  24
+#define MCOUNT_OFFSET    14
+#else
+#define MCOUNT_OFFSET_RET 26
+#define MCOUNT_INSN_SIZE  30
+#define MCOUNT_OFFSET     8
 #endif
 
+static inline unsigned long ftrace_call_adjust(unsigned long addr)
+{
+       return addr - MCOUNT_OFFSET;
+}
+
+#endif /* __ASSEMBLY__ */
 #endif /* _ASM_S390_FTRACE_H */
index 3aeca492b14763fa6431192a14830eb041e69609..5046ad6b7a63453e8b660acd6d70986f361a1265 100644 (file)
@@ -30,6 +30,7 @@
 #define __LC_SUBCHANNEL_NR             0x00ba
 #define __LC_IO_INT_PARM               0x00bc
 #define __LC_IO_INT_WORD               0x00c0
+#define __LC_STFL_FAC_LIST             0x00c8
 #define __LC_MCCK_CODE                 0x00e8
 
 #define __LC_DUMP_REIPL                        0x0e00
@@ -67,6 +68,7 @@
 #define __LC_CPUID                     0x02b0
 #define __LC_INT_CLOCK                 0x02c8
 #define __LC_MACHINE_FLAGS             0x02d8
+#define __LC_FTRACE_FUNC               0x02dc
 #define __LC_IRB                       0x0300
 #define __LC_PFAULT_INTPARM            0x0080
 #define __LC_CPU_TIMER_SAVE_AREA       0x00d8
 #define __LC_INT_CLOCK                 0x0340
 #define __LC_VDSO_PER_CPU              0x0350
 #define __LC_MACHINE_FLAGS             0x0358
+#define __LC_FTRACE_FUNC               0x0360
 #define __LC_IRB                       0x0380
 #define __LC_PASTE                     0x03c0
 #define __LC_PFAULT_INTPARM            0x11b8
@@ -280,7 +283,8 @@ struct _lowcore
        __u64   int_clock;                      /* 0x02c8 */
        __u64   clock_comparator;               /* 0x02d0 */
        __u32   machine_flags;                  /* 0x02d8 */
-       __u8    pad_0x02dc[0x0300-0x02dc];      /* 0x02dc */
+       __u32   ftrace_func;                    /* 0x02dc */
+       __u8    pad_0x02f0[0x0300-0x02f0];      /* 0x02f0 */
 
        /* Interrupt response block */
        __u8    irb[64];                        /* 0x0300 */
@@ -385,7 +389,8 @@ struct _lowcore
        __u64   clock_comparator;               /* 0x0348 */
        __u64   vdso_per_cpu_data;              /* 0x0350 */
        __u64   machine_flags;                  /* 0x0358 */
-       __u8    pad_0x0360[0x0380-0x0360];      /* 0x0360 */
+       __u64   ftrace_func;                    /* 0x0360 */
+       __u8    pad_0x0368[0x0380-0x0368];      /* 0x0368 */
 
        /* Interrupt response block. */
        __u8    irb[64];                        /* 0x0380 */
index da01432e8f447b057e0989980dbdfd4efb15cd04..f63fe7b431ed4ee8a967305cb129b6b0ad8b0314 100644 (file)
@@ -9,7 +9,7 @@
 #ifndef __S390_MMAN_H__
 #define __S390_MMAN_H__
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 #define MAP_GROWSDOWN  0x0100          /* stack-like segment */
 #define MAP_DENYWRITE  0x0800          /* ETXTBSY */
index 32e8f6aa4384245892a6523943d7819f0c808cb6..3e3594d01f8315f6c5545fd40dbe0d1d521f3de2 100644 (file)
@@ -150,7 +150,7 @@ void arch_alloc_page(struct page *page, int order);
                                 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
 #include <asm-generic/memory_model.h>
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #define __HAVE_ARCH_GATE_AREA 1
 
index 5caddd4f7bedd74ed7fa9078c8cf4d97bdfc2227..60a7b1a1702ff478b60177b2ac161341a2882873 100644 (file)
@@ -112,12 +112,15 @@ extern char empty_zero_page[PAGE_SIZE];
  * effect, this also makes sure that 64 bit module code cannot be used
  * as system call address.
  */
+
+extern unsigned long VMALLOC_START;
+
 #ifndef __s390x__
-#define VMALLOC_START  0x78000000UL
+#define VMALLOC_SIZE   (96UL << 20)
 #define VMALLOC_END    0x7e000000UL
 #define VMEM_MAP_END   0x80000000UL
 #else /* __s390x__ */
-#define VMALLOC_START  0x3e000000000UL
+#define VMALLOC_SIZE   (1UL << 30)
 #define VMALLOC_END    0x3e040000000UL
 #define VMEM_MAP_END   0x40000000000UL
 #endif /* __s390x__ */
diff --git a/arch/s390/include/asm/seccomp.h b/arch/s390/include/asm/seccomp.h
new file mode 100644 (file)
index 0000000..781a9cf
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _ASM_S390_SECCOMP_H
+#define _ASM_S390_SECCOMP_H
+
+#include <linux/unistd.h>
+
+#define __NR_seccomp_read      __NR_read
+#define __NR_seccomp_write     __NR_write
+#define __NR_seccomp_exit      __NR_exit
+#define __NR_seccomp_sigreturn __NR_sigreturn
+
+#define __NR_seccomp_read_32   __NR_read
+#define __NR_seccomp_write_32  __NR_write
+#define __NR_seccomp_exit_32   __NR_exit
+#define __NR_seccomp_sigreturn_32 __NR_sigreturn
+
+#endif /* _ASM_S390_SECCOMP_H */
index f6cfddb278cb95bafc4189a50216915530a74360..cdf5cb2fe03f5aa0c2c45765a54536b78d88dde5 100644 (file)
@@ -115,7 +115,7 @@ typedef unsigned long sigset_t;
 #define MINSIGSTKSZ     2048
 #define SIGSTKSZ        8192
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
index f3861b09ebb08a2ef2a1081f623f59429b1c6049..c9af0d19c7ab7b4fc726528797be910ef7d7c0f3 100644 (file)
@@ -122,8 +122,10 @@ static inline void __raw_spin_unlock(raw_spinlock_t *lp)
 #define __raw_write_can_lock(x) ((x)->lock == 0)
 
 extern void _raw_read_lock_wait(raw_rwlock_t *lp);
+extern void _raw_read_lock_wait_flags(raw_rwlock_t *lp, unsigned long flags);
 extern int _raw_read_trylock_retry(raw_rwlock_t *lp);
 extern void _raw_write_lock_wait(raw_rwlock_t *lp);
+extern void _raw_write_lock_wait_flags(raw_rwlock_t *lp, unsigned long flags);
 extern int _raw_write_trylock_retry(raw_rwlock_t *lp);
 
 static inline void __raw_read_lock(raw_rwlock_t *rw)
@@ -134,6 +136,14 @@ static inline void __raw_read_lock(raw_rwlock_t *rw)
                _raw_read_lock_wait(rw);
 }
 
+static inline void __raw_read_lock_flags(raw_rwlock_t *rw, unsigned long flags)
+{
+       unsigned int old;
+       old = rw->lock & 0x7fffffffU;
+       if (_raw_compare_and_swap(&rw->lock, old, old + 1) != old)
+               _raw_read_lock_wait_flags(rw, flags);
+}
+
 static inline void __raw_read_unlock(raw_rwlock_t *rw)
 {
        unsigned int old, cmp;
@@ -151,6 +161,12 @@ static inline void __raw_write_lock(raw_rwlock_t *rw)
                _raw_write_lock_wait(rw);
 }
 
+static inline void __raw_write_lock_flags(raw_rwlock_t *rw, unsigned long flags)
+{
+       if (unlikely(_raw_compare_and_swap(&rw->lock, 0, 0x80000000) != 0))
+               _raw_write_lock_wait_flags(rw, flags);
+}
+
 static inline void __raw_write_unlock(raw_rwlock_t *rw)
 {
        _raw_compare_and_swap(&rw->lock, 0x80000000, 0);
@@ -172,9 +188,6 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw)
        return _raw_write_trylock_retry(rw);
 }
 
-#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock)
-#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock)
-
 #define _raw_read_relax(lock)  cpu_relax()
 #define _raw_write_relax(lock) cpu_relax()
 
diff --git a/arch/s390/include/asm/suspend.h b/arch/s390/include/asm/suspend.h
deleted file mode 100644 (file)
index 1f34580..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifndef __ASM_S390_SUSPEND_H
-#define __ASM_S390_SUSPEND_H
-
-#endif
-
index 2429b87eb28d92c6fc6adf5a5887f2b29e062d70..e0a73d3eb8371be3bb599413aa09cd65a7f7da56 100644 (file)
@@ -12,6 +12,7 @@
 #ifndef _ASM_SYSCALL_H
 #define _ASM_SYSCALL_H 1
 
+#include <linux/sched.h>
 #include <asm/ptrace.h>
 
 static inline long syscall_get_nr(struct task_struct *task,
index 67f66278f533f8706d5467560530a164c63121cf..bc3a35cefc9629e4ebae31ee601d6a2432b14c5c 100644 (file)
@@ -60,7 +60,7 @@ struct termio {
 #define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios2))
 #define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2))
 
-#include <asm-generic/termios.h>
+#include <asm-generic/termios-base.h>
 
 #endif /* __KERNEL__ */
 
index 461f2abd2e6fd2d9dcc94cf604f4a77e50f3ee18..925bcc6490354c3f2fa2c5dbbca8b37b553b1bd6 100644 (file)
@@ -83,14 +83,16 @@ static inline struct thread_info *current_thread_info(void)
 /*
  * thread information flags bit numbers
  */
-#define TIF_SYSCALL_TRACE      0       /* syscall trace active */
 #define TIF_NOTIFY_RESUME      1       /* callback before returning to user */
 #define TIF_SIGPENDING         2       /* signal pending */
 #define TIF_NEED_RESCHED       3       /* rescheduling necessary */
 #define TIF_RESTART_SVC                4       /* restart svc with new svc number */
-#define TIF_SYSCALL_AUDIT      5       /* syscall auditing active */
 #define TIF_SINGLE_STEP                6       /* deliver sigtrap on return to user */
 #define TIF_MCCK_PENDING       7       /* machine check handling is pending */
+#define TIF_SYSCALL_TRACE      8       /* syscall trace active */
+#define TIF_SYSCALL_AUDIT      9       /* syscall auditing active */
+#define TIF_SECCOMP            10      /* secure computing */
+#define TIF_SYSCALL_FTRACE     11      /* ftrace syscall instrumentation */
 #define TIF_USEDFPU            16      /* FPU was used by this task this quantum (SMP) */
 #define TIF_POLLING_NRFLAG     17      /* true if poll_idle() is polling 
                                           TIF_NEED_RESCHED */
@@ -99,15 +101,17 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_RESTORE_SIGMASK    20      /* restore signal mask in do_signal() */
 #define TIF_FREEZE             21      /* thread is freezing for suspend */
 
-#define _TIF_SYSCALL_TRACE     (1<<TIF_SYSCALL_TRACE)
 #define _TIF_NOTIFY_RESUME     (1<<TIF_NOTIFY_RESUME)
 #define _TIF_RESTORE_SIGMASK   (1<<TIF_RESTORE_SIGMASK)
 #define _TIF_SIGPENDING                (1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED      (1<<TIF_NEED_RESCHED)
 #define _TIF_RESTART_SVC       (1<<TIF_RESTART_SVC)
-#define _TIF_SYSCALL_AUDIT     (1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SINGLE_STEP       (1<<TIF_SINGLE_STEP)
 #define _TIF_MCCK_PENDING      (1<<TIF_MCCK_PENDING)
+#define _TIF_SYSCALL_TRACE     (1<<TIF_SYSCALL_TRACE)
+#define _TIF_SYSCALL_AUDIT     (1<<TIF_SYSCALL_AUDIT)
+#define _TIF_SECCOMP           (1<<TIF_SECCOMP)
+#define _TIF_SYSCALL_FTRACE    (1<<TIF_SYSCALL_FTRACE)
 #define _TIF_USEDFPU           (1<<TIF_USEDFPU)
 #define _TIF_POLLING_NRFLAG    (1<<TIF_POLLING_NRFLAG)
 #define _TIF_31BIT             (1<<TIF_31BIT)
index 3dc3fc228812a3ce22070d8b52705c211b23ea47..04d6b95a89c6b4ce1c5454341d378ea45700e286 100644 (file)
@@ -28,12 +28,6 @@ typedef __signed__ long saddr_t;
  */
 #ifdef __KERNEL__
 
-#ifndef __s390x__
-#define BITS_PER_LONG 32
-#else
-#define BITS_PER_LONG 64
-#endif
-
 #ifndef __ASSEMBLY__
 
 typedef u64 dma64_addr_t;
index 0235970278f0574516ca7638e08737ce58c3ef3c..8377e91533d26434878708fc6e3ecc7245bbb579 100644 (file)
@@ -131,7 +131,7 @@ static inline int __get_user_fn(size_t size, const void __user *ptr, void *x)
 
 #define put_user(x, ptr)                                       \
 ({                                                             \
-       might_sleep();                                          \
+       might_fault();                                          \
        __put_user(x, ptr);                                     \
 })
 
@@ -180,7 +180,7 @@ extern int __put_user_bad(void) __attribute__((noreturn));
 
 #define get_user(x, ptr)                                       \
 ({                                                             \
-       might_sleep();                                          \
+       might_fault();                                          \
        __get_user(x, ptr);                                     \
 })
 
@@ -231,7 +231,7 @@ __copy_to_user(void __user *to, const void *from, unsigned long n)
 static inline unsigned long __must_check
 copy_to_user(void __user *to, const void *from, unsigned long n)
 {
-       might_sleep();
+       might_fault();
        if (access_ok(VERIFY_WRITE, to, n))
                n = __copy_to_user(to, from, n);
        return n;
@@ -282,7 +282,7 @@ __copy_from_user(void *to, const void __user *from, unsigned long n)
 static inline unsigned long __must_check
 copy_from_user(void *to, const void __user *from, unsigned long n)
 {
-       might_sleep();
+       might_fault();
        if (access_ok(VERIFY_READ, from, n))
                n = __copy_from_user(to, from, n);
        else
@@ -299,7 +299,7 @@ __copy_in_user(void __user *to, const void __user *from, unsigned long n)
 static inline unsigned long __must_check
 copy_in_user(void __user *to, const void __user *from, unsigned long n)
 {
-       might_sleep();
+       might_fault();
        if (__access_ok(from,n) && __access_ok(to,n))
                n = __copy_in_user(to, from, n);
        return n;
@@ -312,7 +312,7 @@ static inline long __must_check
 strncpy_from_user(char *dst, const char __user *src, long count)
 {
         long res = -EFAULT;
-        might_sleep();
+       might_fault();
         if (access_ok(VERIFY_READ, src, 1))
                res = uaccess.strncpy_from_user(count, src, dst);
         return res;
@@ -321,7 +321,7 @@ strncpy_from_user(char *dst, const char __user *src, long count)
 static inline unsigned long
 strnlen_user(const char __user * src, unsigned long n)
 {
-       might_sleep();
+       might_fault();
        return uaccess.strnlen_user(n, src);
 }
 
@@ -354,7 +354,7 @@ __clear_user(void __user *to, unsigned long n)
 static inline unsigned long __must_check
 clear_user(void __user *to, unsigned long n)
 {
-       might_sleep();
+       might_fault();
        if (access_ok(VERIFY_WRITE, to, n))
                n = uaccess.clear_user(n, to);
        return n;
index f0f19e6ace6cf550253483a6eddee80b163326ca..c80602d7c88000a9d7e91f5edc10ba7135e2ef3f 100644 (file)
 #define __NR_epoll_create1     327
 #define        __NR_preadv             328
 #define        __NR_pwritev            329
-#define NR_syscalls 330
+#define __NR_rt_tgsigqueueinfo 330
+#define __NR_perf_counter_open 331
+#define NR_syscalls 332
 
 /* 
  * There are some system calls that are not present on 64 bit, some
index 228e3105ded772da7d975faf6afaddb73a4e1e9e..c75ed43b1a181e250695312fae9844e64185f590 100644 (file)
@@ -3,8 +3,9 @@
 #
 
 ifdef CONFIG_FUNCTION_TRACER
-# Do not trace early boot code
+# Don't trace early setup code and tracing code
 CFLAGS_REMOVE_early.o = -pg
+CFLAGS_REMOVE_ftrace.o = -pg
 endif
 
 #
@@ -22,7 +23,7 @@ CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w
 obj-y  :=  bitmap.o traps.o time.o process.o base.o early.o setup.o \
            processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
            s390_ext.o debug.o irq.o ipl.o dis.o diag.o mem_detect.o \
-           vdso.o vtime.o sysinfo.o nmi.o
+           vdso.o vtime.o sysinfo.o nmi.o sclp.o
 
 obj-y  += $(if $(CONFIG_64BIT),entry64.o,entry.o)
 obj-y  += $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
@@ -41,6 +42,8 @@ obj-$(CONFIG_COMPAT)          += compat_linux.o compat_signal.o \
 obj-$(CONFIG_STACKTRACE)       += stacktrace.o
 obj-$(CONFIG_KPROBES)          += kprobes.o
 obj-$(CONFIG_FUNCTION_TRACER)  += mcount.o
+obj-$(CONFIG_DYNAMIC_FTRACE)   += ftrace.o
+obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
 
 # Kexec part
 S390_KEXEC_OBJS := machine_kexec.o crash.o
index fb38af6316bb84f26c5a7f169cc142ef687540e8..88a83366819f6f7bba0dfbc05ff6ac78f221becb 100644 (file)
@@ -1823,3 +1823,20 @@ compat_sys_pwritev_wrapper:
        llgfr   %r5,%r5                 # u32
        llgfr   %r6,%r6                 # u32
        jg      compat_sys_pwritev      # branch to system call
+
+       .globl  compat_sys_rt_tgsigqueueinfo_wrapper
+compat_sys_rt_tgsigqueueinfo_wrapper:
+       lgfr    %r2,%r2                 # compat_pid_t
+       lgfr    %r3,%r3                 # compat_pid_t
+       lgfr    %r4,%r4                 # int
+       llgtr   %r5,%r5                 # struct compat_siginfo *
+       jg      compat_sys_rt_tgsigqueueinfo_wrapper # branch to system call
+
+       .globl  sys_perf_counter_open_wrapper
+sys_perf_counter_open_wrapper:
+       llgtr   %r2,%r2                 # const struct perf_counter_attr *
+       lgfr    %r3,%r3                 # pid_t
+       lgfr    %r4,%r4                 # int
+       lgfr    %r5,%r5                 # int
+       llgfr   %r6,%r6                 # unsigned long
+       jg      sys_perf_counter_open   # branch to system call
index cf09948faad6330aba32a207a88921aac833a307..fb263736826c8d73d0e2f0031afbbd24c88c69a9 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
+#include <linux/ftrace.h>
 #include <linux/lockdep.h>
 #include <linux/module.h>
 #include <linux/pfn.h>
@@ -410,5 +411,8 @@ void __init startup_init(void)
        sclp_facilities_detect();
        detect_memory_layout(memory_chunk);
        S390_lowcore.machine_flags = machine_flags;
+#ifdef CONFIG_DYNAMIC_FTRACE
+       S390_lowcore.ftrace_func = (unsigned long)ftrace_caller;
+#endif
        lockdep_on();
 }
index f3e2759342135c170b5b70e9f75375f9a62efdea..c4c80a22bc1f315215111d240a8756b479e2fe37 100644 (file)
@@ -53,6 +53,8 @@ _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
                 _TIF_MCCK_PENDING | _TIF_RESTART_SVC | _TIF_SINGLE_STEP )
 _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
                 _TIF_MCCK_PENDING)
+_TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \
+               _TIF_SECCOMP>>8 | _TIF_SYSCALL_FTRACE>>8)
 
 STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
 STACK_SIZE  = 1 << STACK_SHIFT
@@ -265,7 +267,7 @@ sysc_do_restart:
        sth     %r7,SP_SVCNR(%r15)
        sll     %r7,2             # svc number *4
        l       %r8,BASED(.Lsysc_table)
-       tm      __TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
+       tm      __TI_flags+2(%r9),_TIF_SYSCALL
        l       %r8,0(%r7,%r8)    # get system call addr.
        bnz     BASED(sysc_tracesys)
        basr    %r14,%r8          # call sys_xxxx
@@ -405,7 +407,7 @@ sysc_tracego:
        basr    %r14,%r8                # call sys_xxx
        st      %r2,SP_R2(%r15)         # store return value
 sysc_tracenogo:
-       tm      __TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
+       tm      __TI_flags+2(%r9),_TIF_SYSCALL
        bz      BASED(sysc_return)
        l       %r1,BASED(.Ltrace_exit)
        la      %r2,SP_PTREGS(%r15)     # load pt_regs
@@ -1107,6 +1109,7 @@ cleanup_io_leave_insn:
 
                .section .rodata, "a"
 #define SYSCALL(esa,esame,emu) .long esa
+       .globl  sys_call_table
 sys_call_table:
 #include "syscalls.S"
 #undef SYSCALL
index 84a105838e03d2765723a3b995d00133e434ea11..f6618e9e15efd85b47ca37e4923685edaca85cb8 100644 (file)
@@ -56,6 +56,8 @@ _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
                 _TIF_MCCK_PENDING | _TIF_RESTART_SVC | _TIF_SINGLE_STEP )
 _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
                 _TIF_MCCK_PENDING)
+_TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \
+               _TIF_SECCOMP>>8 | _TIF_SYSCALL_FTRACE>>8)
 
 #define BASED(name) name-system_call(%r13)
 
@@ -260,7 +262,7 @@ sysc_do_restart:
        larl    %r10,sys_call_table_emu  # use 31 bit emulation system calls
 sysc_noemu:
 #endif
-       tm      __TI_flags+7(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
+       tm      __TI_flags+6(%r9),_TIF_SYSCALL
        lgf     %r8,0(%r7,%r10) # load address of system call routine
        jnz     sysc_tracesys
        basr    %r14,%r8        # call sys_xxxx
@@ -391,7 +393,7 @@ sysc_tracego:
        basr    %r14,%r8                # call sys_xxx
        stg     %r2,SP_R2(%r15)         # store return value
 sysc_tracenogo:
-       tm      __TI_flags+7(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
+       tm      __TI_flags+6(%r9),_TIF_SYSCALL
        jz      sysc_return
        la      %r2,SP_PTREGS(%r15)     # load pt_regs
        larl    %r14,sysc_return        # return point is sysc_return
@@ -1058,6 +1060,7 @@ cleanup_io_leave_insn:
 
                .section .rodata, "a"
 #define SYSCALL(esa,esame,emu) .long esame
+       .globl  sys_call_table
 sys_call_table:
 #include "syscalls.S"
 #undef SYSCALL
diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c
new file mode 100644 (file)
index 0000000..82ddfd3
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * Dynamic function tracer architecture backend.
+ *
+ * Copyright IBM Corp. 2009
+ *
+ *   Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
+ *
+ */
+
+#include <linux/hardirq.h>
+#include <linux/uaccess.h>
+#include <linux/ftrace.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <trace/syscall.h>
+#include <asm/lowcore.h>
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+
+void ftrace_disable_code(void);
+void ftrace_disable_return(void);
+void ftrace_call_code(void);
+void ftrace_nop_code(void);
+
+#define FTRACE_INSN_SIZE 4
+
+#ifdef CONFIG_64BIT
+
+asm(
+       "       .align  4\n"
+       "ftrace_disable_code:\n"
+       "       j       0f\n"
+       "       .word   0x0024\n"
+       "       lg      %r1,"__stringify(__LC_FTRACE_FUNC)"\n"
+       "       basr    %r14,%r1\n"
+       "ftrace_disable_return:\n"
+       "       lg      %r14,8(15)\n"
+       "       lgr     %r0,%r0\n"
+       "0:\n");
+
+asm(
+       "       .align  4\n"
+       "ftrace_nop_code:\n"
+       "       j       .+"__stringify(MCOUNT_INSN_SIZE)"\n");
+
+asm(
+       "       .align  4\n"
+       "ftrace_call_code:\n"
+       "       stg     %r14,8(%r15)\n");
+
+#else /* CONFIG_64BIT */
+
+asm(
+       "       .align  4\n"
+       "ftrace_disable_code:\n"
+       "       j       0f\n"
+       "       l       %r1,"__stringify(__LC_FTRACE_FUNC)"\n"
+       "       basr    %r14,%r1\n"
+       "ftrace_disable_return:\n"
+       "       l       %r14,4(%r15)\n"
+       "       j       0f\n"
+       "       bcr     0,%r7\n"
+       "       bcr     0,%r7\n"
+       "       bcr     0,%r7\n"
+       "       bcr     0,%r7\n"
+       "       bcr     0,%r7\n"
+       "       bcr     0,%r7\n"
+       "0:\n");
+
+asm(
+       "       .align  4\n"
+       "ftrace_nop_code:\n"
+       "       j       .+"__stringify(MCOUNT_INSN_SIZE)"\n");
+
+asm(
+       "       .align  4\n"
+       "ftrace_call_code:\n"
+       "       st      %r14,4(%r15)\n");
+
+#endif /* CONFIG_64BIT */
+
+static int ftrace_modify_code(unsigned long ip,
+                             void *old_code, int old_size,
+                             void *new_code, int new_size)
+{
+       unsigned char replaced[MCOUNT_INSN_SIZE];
+
+       /*
+        * Note: Due to modules code can disappear and change.
+        *  We need to protect against faulting as well as code
+        *  changing. We do this by using the probe_kernel_*
+        *  functions.
+        *  This however is just a simple sanity check.
+        */
+       if (probe_kernel_read(replaced, (void *)ip, old_size))
+               return -EFAULT;
+       if (memcmp(replaced, old_code, old_size) != 0)
+               return -EINVAL;
+       if (probe_kernel_write((void *)ip, new_code, new_size))
+               return -EPERM;
+       return 0;
+}
+
+static int ftrace_make_initial_nop(struct module *mod, struct dyn_ftrace *rec,
+                                  unsigned long addr)
+{
+       return ftrace_modify_code(rec->ip,
+                                 ftrace_call_code, FTRACE_INSN_SIZE,
+                                 ftrace_disable_code, MCOUNT_INSN_SIZE);
+}
+
+int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
+                   unsigned long addr)
+{
+       if (addr == MCOUNT_ADDR)
+               return ftrace_make_initial_nop(mod, rec, addr);
+       return ftrace_modify_code(rec->ip,
+                                 ftrace_call_code, FTRACE_INSN_SIZE,
+                                 ftrace_nop_code, FTRACE_INSN_SIZE);
+}
+
+int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+{
+       return ftrace_modify_code(rec->ip,
+                                 ftrace_nop_code, FTRACE_INSN_SIZE,
+                                 ftrace_call_code, FTRACE_INSN_SIZE);
+}
+
+int ftrace_update_ftrace_func(ftrace_func_t func)
+{
+       ftrace_dyn_func = (unsigned long)func;
+       return 0;
+}
+
+int __init ftrace_dyn_arch_init(void *data)
+{
+       *(unsigned long *)data = 0;
+       return 0;
+}
+
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+#ifdef CONFIG_DYNAMIC_FTRACE
+/*
+ * Patch the kernel code at ftrace_graph_caller location:
+ * The instruction there is branch relative on condition. The condition mask
+ * is either all ones (always branch aka disable ftrace_graph_caller) or all
+ * zeroes (nop aka enable ftrace_graph_caller).
+ * Instruction format for brc is a7m4xxxx where m is the condition mask.
+ */
+int ftrace_enable_ftrace_graph_caller(void)
+{
+       unsigned short opcode = 0xa704;
+
+       return probe_kernel_write(ftrace_graph_caller, &opcode, sizeof(opcode));
+}
+
+int ftrace_disable_ftrace_graph_caller(void)
+{
+       unsigned short opcode = 0xa7f4;
+
+       return probe_kernel_write(ftrace_graph_caller, &opcode, sizeof(opcode));
+}
+
+static inline unsigned long ftrace_mcount_call_adjust(unsigned long addr)
+{
+       return addr - (ftrace_disable_return - ftrace_disable_code);
+}
+
+#else /* CONFIG_DYNAMIC_FTRACE */
+
+static inline unsigned long ftrace_mcount_call_adjust(unsigned long addr)
+{
+       return addr - MCOUNT_OFFSET_RET;
+}
+
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
+/*
+ * Hook the return address and push it in the stack of return addresses
+ * in current thread info.
+ */
+unsigned long prepare_ftrace_return(unsigned long ip, unsigned long parent)
+{
+       struct ftrace_graph_ent trace;
+
+       /* Nmi's are currently unsupported. */
+       if (unlikely(in_nmi()))
+               goto out;
+       if (unlikely(atomic_read(&current->tracing_graph_pause)))
+               goto out;
+       if (ftrace_push_return_trace(parent, ip, &trace.depth) == -EBUSY)
+               goto out;
+       trace.func = ftrace_mcount_call_adjust(ip) & PSW_ADDR_INSN;
+       /* Only trace if the calling function expects to. */
+       if (!ftrace_graph_entry(&trace)) {
+               current->curr_ret_stack--;
+               goto out;
+       }
+       parent = (unsigned long)return_to_handler;
+out:
+       return parent;
+}
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+#ifdef CONFIG_FTRACE_SYSCALLS
+
+extern unsigned long __start_syscalls_metadata[];
+extern unsigned long __stop_syscalls_metadata[];
+extern unsigned int sys_call_table[];
+
+static struct syscall_metadata **syscalls_metadata;
+
+struct syscall_metadata *syscall_nr_to_meta(int nr)
+{
+       if (!syscalls_metadata || nr >= NR_syscalls || nr < 0)
+               return NULL;
+
+       return syscalls_metadata[nr];
+}
+
+static struct syscall_metadata *find_syscall_meta(unsigned long syscall)
+{
+       struct syscall_metadata *start;
+       struct syscall_metadata *stop;
+       char str[KSYM_SYMBOL_LEN];
+
+       start = (struct syscall_metadata *)__start_syscalls_metadata;
+       stop = (struct syscall_metadata *)__stop_syscalls_metadata;
+       kallsyms_lookup(syscall, NULL, NULL, NULL, str);
+
+       for ( ; start < stop; start++) {
+               if (start->name && !strcmp(start->name + 3, str + 3))
+                       return start;
+       }
+       return NULL;
+}
+
+void arch_init_ftrace_syscalls(void)
+{
+       struct syscall_metadata *meta;
+       int i;
+       static atomic_t refs;
+
+       if (atomic_inc_return(&refs) != 1)
+               goto out;
+       syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) * NR_syscalls,
+                                   GFP_KERNEL);
+       if (!syscalls_metadata)
+               goto out;
+       for (i = 0; i < NR_syscalls; i++) {
+               meta = find_syscall_meta((unsigned long)sys_call_table[i]);
+               syscalls_metadata[i] = meta;
+       }
+       return;
+out:
+       atomic_dec(&refs);
+}
+#endif
index 22596d70fc2e8961f1e29dc80305248b20028c79..ec6882348520540ea87d84e58ac921c11a466a0d 100644 (file)
@@ -1,7 +1,5 @@
 /*
- *  arch/s390/kernel/head.S
- *
- * Copyright (C) IBM Corp. 1999,2006
+ * Copyright IBM Corp. 1999,2009
  *
  *    Author(s): Hartmut Penner <hp@de.ibm.com>
  *              Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -64,7 +62,7 @@ __HEAD
        .org   0x100
 #
 # subroutine for loading from tape
-# Paramters:
+# Parameters:
 #  R1 = device number
 #  R2 = load address
 .Lloader:
@@ -479,27 +477,58 @@ startup:basr      %r13,0                  # get base
        mvc     __LC_LAST_UPDATE_TIMER(8),6f-.LPG0(%r13)
        mvc     __LC_EXIT_TIMER(8),5f-.LPG0(%r13)
 #ifndef CONFIG_MARCH_G5
-       # check processor version against MARCH_{G5,Z900,Z990,Z9_109,Z10}
-       stidp   __LC_CPUID              # store cpuid
-       lhi     %r0,(3f-2f) / 2
-       la      %r1,2f-.LPG0(%r13)
-0:     clc     __LC_CPUID+4(2),0(%r1)
-       jne     3f
-       lpsw    1f-.LPG0(13)            # machine type not good enough, crash
+       # check capabilities against MARCH_{G5,Z900,Z990,Z9_109,Z10}
+       xc      __LC_STFL_FAC_LIST(8),__LC_STFL_FAC_LIST
+       stfl    __LC_STFL_FAC_LIST      # store facility list
+       tm      __LC_STFL_FAC_LIST,0x01 # stfle available ?
+       jz      0f
+       la      %r0,0
+       .insn   s,0xb2b00000,__LC_STFL_FAC_LIST # store facility list extended
+0:     l       %r0,__LC_STFL_FAC_LIST
+       n       %r0,2f+8-.LPG0(%r13)
+       cl      %r0,2f+8-.LPG0(%r13)
+       jne     1f
+       l       %r0,__LC_STFL_FAC_LIST+4
+       n       %r0,2f+12-.LPG0(%r13)
+       cl      %r0,2f+12-.LPG0(%r13)
+       je      3f
+1:     l       %r15,.Lstack-.LPG0(%r13)
+       ahi     %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union+THREAD_SIZE
+       ahi     %r15,-96
+       la      %r2,.Lals_string-.LPG0(%r13)
+       l       %r3,.Lsclp_print-.LPG0(%r13)
+       basr    %r14,%r3
+       lpsw    2f-.LPG0(%r13)          # machine type not good enough, crash
+.Lals_string:
+       .asciz  "The Linux kernel requires more recent processor hardware"
+.Lsclp_print:
+       .long   _sclp_print_early
+.Lstack:
+       .long   init_thread_union
        .align 16
-1:     .long   0x000a0000,0x00000000
-2:
+2:     .long   0x000a0000,0x8badcccc
+#if defined(CONFIG_64BIT)
 #if defined(CONFIG_MARCH_Z10)
-       .short 0x9672, 0x2064, 0x2066, 0x2084, 0x2086, 0x2094, 0x2096
+       .long 0xc100efe3, 0xf0680000
 #elif defined(CONFIG_MARCH_Z9_109)
-       .short 0x9672, 0x2064, 0x2066, 0x2084, 0x2086
+       .long 0xc100efc3, 0x00000000
 #elif defined(CONFIG_MARCH_Z990)
-       .short 0x9672, 0x2064, 0x2066
+       .long 0xc0002000, 0x00000000
 #elif defined(CONFIG_MARCH_Z900)
-       .short 0x9672
+       .long 0xc0000000, 0x00000000
+#endif
+#else
+#if defined(CONFIG_MARCH_Z10)
+       .long 0x8100c880, 0x00000000
+#elif defined(CONFIG_MARCH_Z9_109)
+       .long 0x8100c880, 0x00000000
+#elif defined(CONFIG_MARCH_Z990)
+       .long 0x80002000, 0x00000000
+#elif defined(CONFIG_MARCH_Z900)
+       .long 0x80000000, 0x00000000
+#endif
 #endif
-3:     la      %r1,2(%r1)
-       brct    %r0,0b
+3:
 #endif
 
        l       %r13,4f-.LPG0(%r13)
index a01cf0284db2dc20b2ab7b9e6e0d299074410a49..9bb2f6241d9faeaf77c71567569baba703716912 100644 (file)
@@ -25,9 +25,9 @@
 #include <linux/preempt.h>
 #include <linux/stop_machine.h>
 #include <linux/kdebug.h>
+#include <linux/uaccess.h>
 #include <asm/cacheflush.h>
 #include <asm/sections.h>
-#include <asm/uaccess.h>
 #include <linux/module.h>
 
 DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
@@ -155,35 +155,8 @@ void __kprobes get_instruction_type(struct arch_specific_insn *ainsn)
 static int __kprobes swap_instruction(void *aref)
 {
        struct ins_replace_args *args = aref;
-       u32 *addr;
-       u32 instr;
-       int err = -EFAULT;
 
-       /*
-        * Text segment is read-only, hence we use stura to bypass dynamic
-        * address translation to exchange the instruction. Since stura
-        * always operates on four bytes, but we only want to exchange two
-        * bytes do some calculations to get things right. In addition we
-        * shall not cross any page boundaries (vmalloc area!) when writing
-        * the new instruction.
-        */
-       addr = (u32 *)((unsigned long)args->ptr & -4UL);
-       if ((unsigned long)args->ptr & 2)
-               instr = ((*addr) & 0xffff0000) | args->new;
-       else
-               instr = ((*addr) & 0x0000ffff) | args->new << 16;
-
-       asm volatile(
-               "       lra     %1,0(%1)\n"
-               "0:     stura   %2,%1\n"
-               "1:     la      %0,0\n"
-               "2:\n"
-               EX_TABLE(0b,2b)
-               : "+d" (err)
-               : "a" (addr), "d" (instr)
-               : "memory", "cc");
-
-       return err;
+       return probe_kernel_write(args->ptr, &args->new, sizeof(args->new));
 }
 
 void __kprobes arch_arm_kprobe(struct kprobe *p)
index 80641224a0959299dff6ba72c8119378ecd87059..2a0a5e97ba8c2a6f954c2209a1836fe70d92ac0f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008,2009
  *
  *   Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
  *
@@ -7,36 +7,64 @@
 
 #include <asm/asm-offsets.h>
 
-#ifndef CONFIG_64BIT
-.globl _mcount
+       .globl ftrace_stub
+ftrace_stub:
+       br      %r14
+
+#ifdef CONFIG_64BIT
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+
+       .globl _mcount
 _mcount:
-       stm     %r0,%r5,8(%r15)
-       st      %r14,56(%r15)
-       lr      %r1,%r15
-       ahi     %r15,-96
-       l       %r3,100(%r15)
-       la      %r2,0(%r14)
-       st      %r1,__SF_BACKCHAIN(%r15)
-       la      %r3,0(%r3)
-       bras    %r14,0f
-       .long   ftrace_trace_function
-0:     l       %r14,0(%r14)
-       l       %r14,0(%r14)
-       basr    %r14,%r14
-       ahi     %r15,96
-       lm      %r0,%r5,8(%r15)
-       l       %r14,56(%r15)
        br      %r14
 
-.globl ftrace_stub
-ftrace_stub:
+       .globl ftrace_caller
+ftrace_caller:
+       larl    %r1,function_trace_stop
+       icm     %r1,0xf,0(%r1)
+       bnzr    %r14
+       stmg    %r2,%r5,32(%r15)
+       stg     %r14,112(%r15)
+       lgr     %r1,%r15
+       aghi    %r15,-160
+       stg     %r1,__SF_BACKCHAIN(%r15)
+       lgr     %r2,%r14
+       lg      %r3,168(%r15)
+       larl    %r14,ftrace_dyn_func
+       lg      %r14,0(%r14)
+       basr    %r14,%r14
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       .globl  ftrace_graph_caller
+ftrace_graph_caller:
+       # This unconditional branch gets runtime patched. Change only if
+       # you know what you are doing. See ftrace_enable_graph_caller().
+       j       0f
+       lg      %r2,272(%r15)
+       lg      %r3,168(%r15)
+       brasl   %r14,prepare_ftrace_return
+       stg     %r2,168(%r15)
+0:
+#endif
+       aghi    %r15,160
+       lmg     %r2,%r5,32(%r15)
+       lg      %r14,112(%r15)
        br      %r14
 
-#else /* CONFIG_64BIT */
+       .data
+       .globl  ftrace_dyn_func
+ftrace_dyn_func:
+       .quad   ftrace_stub
+       .previous
+
+#else /* CONFIG_DYNAMIC_FTRACE */
 
-.globl _mcount
+       .globl _mcount
 _mcount:
-       stmg    %r0,%r5,16(%r15)
+       larl    %r1,function_trace_stop
+       icm     %r1,0xf,0(%r1)
+       bnzr    %r14
+       stmg    %r2,%r5,32(%r15)
        stg     %r14,112(%r15)
        lgr     %r1,%r15
        aghi    %r15,-160
@@ -46,13 +74,143 @@ _mcount:
        larl    %r14,ftrace_trace_function
        lg      %r14,0(%r14)
        basr    %r14,%r14
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       lg      %r2,272(%r15)
+       lg      %r3,168(%r15)
+       brasl   %r14,prepare_ftrace_return
+       stg     %r2,168(%r15)
+#endif
        aghi    %r15,160
-       lmg     %r0,%r5,16(%r15)
+       lmg     %r2,%r5,32(%r15)
        lg      %r14,112(%r15)
        br      %r14
 
-.globl ftrace_stub
-ftrace_stub:
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+
+       .globl  return_to_handler
+return_to_handler:
+       stmg    %r2,%r5,32(%r15)
+       lgr     %r1,%r15
+       aghi    %r15,-160
+       stg     %r1,__SF_BACKCHAIN(%r15)
+       brasl   %r14,ftrace_return_to_handler
+       aghi    %r15,160
+       lgr     %r14,%r2
+       lmg     %r2,%r5,32(%r15)
+       br      %r14
+
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+#else /* CONFIG_64BIT */
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+
+       .globl _mcount
+_mcount:
+       br      %r14
+
+       .globl ftrace_caller
+ftrace_caller:
+       stm     %r2,%r5,16(%r15)
+       bras    %r1,2f
+0:     .long   ftrace_trace_function
+1:     .long   function_trace_stop
+2:     l       %r2,1b-0b(%r1)
+       icm     %r2,0xf,0(%r2)
+       jnz     3f
+       st      %r14,56(%r15)
+       lr      %r0,%r15
+       ahi     %r15,-96
+       l       %r3,100(%r15)
+       la      %r2,0(%r14)
+       st      %r0,__SF_BACKCHAIN(%r15)
+       la      %r3,0(%r3)
+       l       %r14,0b-0b(%r1)
+       l       %r14,0(%r14)
+       basr    %r14,%r14
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       .globl  ftrace_graph_caller
+ftrace_graph_caller:
+       # This unconditional branch gets runtime patched. Change only if
+       # you know what you are doing. See ftrace_enable_graph_caller().
+       j       1f
+       bras    %r1,0f
+       .long   prepare_ftrace_return
+0:     l       %r2,152(%r15)
+       l       %r4,0(%r1)
+       l       %r3,100(%r15)
+       basr    %r14,%r4
+       st      %r2,100(%r15)
+1:
+#endif
+       ahi     %r15,96
+       l       %r14,56(%r15)
+3:     lm      %r2,%r5,16(%r15)
        br      %r14
 
+       .data
+       .globl  ftrace_dyn_func
+ftrace_dyn_func:
+       .long   ftrace_stub
+       .previous
+
+#else /* CONFIG_DYNAMIC_FTRACE */
+
+       .globl _mcount
+_mcount:
+       stm     %r2,%r5,16(%r15)
+       bras    %r1,2f
+0:     .long   ftrace_trace_function
+1:     .long   function_trace_stop
+2:     l       %r2,1b-0b(%r1)
+       icm     %r2,0xf,0(%r2)
+       jnz     3f
+       st      %r14,56(%r15)
+       lr      %r0,%r15
+       ahi     %r15,-96
+       l       %r3,100(%r15)
+       la      %r2,0(%r14)
+       st      %r0,__SF_BACKCHAIN(%r15)
+       la      %r3,0(%r3)
+       l       %r14,0b-0b(%r1)
+       l       %r14,0(%r14)
+       basr    %r14,%r14
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       bras    %r1,0f
+       .long   prepare_ftrace_return
+0:     l       %r2,152(%r15)
+       l       %r4,0(%r1)
+       l       %r3,100(%r15)
+       basr    %r14,%r4
+       st      %r2,100(%r15)
+#endif
+       ahi     %r15,96
+       l       %r14,56(%r15)
+3:     lm      %r2,%r5,16(%r15)
+       br      %r14
+
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+
+       .globl  return_to_handler
+return_to_handler:
+       stm     %r2,%r5,16(%r15)
+       st      %r14,56(%r15)
+       lr      %r0,%r15
+       ahi     %r15,-96
+       st      %r0,__SF_BACKCHAIN(%r15)
+       bras    %r1,0f
+       .long   ftrace_return_to_handler
+0:     l       %r2,0b-0b(%r1)
+       basr    %r14,%r2
+       lr      %r14,%r2
+       ahi     %r15,96
+       lm      %r2,%r5,16(%r15)
+       br      %r14
+
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
 #endif /* CONFIG_64BIT */
index eed4a00cb676238f7fdbc3b1ccc9dbde7ecb0b98..ab2e3ed28abc89256f7b305ee7ac63dfacfd34e4 100644 (file)
@@ -56,8 +56,6 @@ void *module_alloc(unsigned long size)
 void module_free(struct module *mod, void *module_region)
 {
        vfree(module_region);
-       /* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
 }
 
 static void
index 28cf196ba775e0e956024a123576fa15b5da1021..015e27da40eb100e5375d356c1160d4c3a98c552 100644 (file)
@@ -16,7 +16,7 @@
 #include <asm/lowcore.h>
 #include <asm/smp.h>
 #include <asm/etr.h>
-#include <asm/cpu.h>
+#include <asm/cputime.h>
 #include <asm/nmi.h>
 #include <asm/crw.h>
 
index a3acd8e60aff70886b058afdc8bce0a441b60e62..355f7a30c3f11c7cdc8a1eaddc77c41a42e9808b 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/elfcore.h>
 #include <linux/kernel_stat.h>
 #include <linux/syscalls.h>
+#include <asm/compat.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -204,7 +205,7 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
        save_fp_regs(&p->thread.fp_regs);
        /* Set a new TLS ?  */
        if (clone_flags & CLONE_SETTLS) {
-               if (test_thread_flag(TIF_31BIT)) {
+               if (is_compat_task()) {
                        p->thread.acrs[0] = (unsigned int) regs->gprs[6];
                } else {
                        p->thread.acrs[0] = (unsigned int)(regs->gprs[6] >> 32);
index 75c496f4f16d2c41900fb4db365f49149e52d022..490b39934d65aa8a98cc76f5772b10f3ef9735ea 100644 (file)
@@ -36,7 +36,9 @@
 #include <linux/elf.h>
 #include <linux/regset.h>
 #include <linux/tracehook.h>
-
+#include <linux/seccomp.h>
+#include <trace/syscall.h>
+#include <asm/compat.h>
 #include <asm/segment.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -69,7 +71,7 @@ FixPerRegisters(struct task_struct *task)
        if (per_info->single_step) {
                per_info->control_regs.bits.starting_addr = 0;
 #ifdef CONFIG_COMPAT
-               if (test_thread_flag(TIF_31BIT))
+               if (is_compat_task())
                        per_info->control_regs.bits.ending_addr = 0x7fffffffUL;
                else
 #endif
@@ -482,8 +484,7 @@ static int peek_user_compat(struct task_struct *child,
 {
        __u32 tmp;
 
-       if (!test_thread_flag(TIF_31BIT) ||
-           (addr & 3) || addr > sizeof(struct user) - 3)
+       if (!is_compat_task() || (addr & 3) || addr > sizeof(struct user) - 3)
                return -EIO;
 
        tmp = __peek_user_compat(child, addr);
@@ -584,8 +585,7 @@ static int __poke_user_compat(struct task_struct *child,
 static int poke_user_compat(struct task_struct *child,
                            addr_t addr, addr_t data)
 {
-       if (!test_thread_flag(TIF_31BIT) ||
-           (addr & 3) || addr > sizeof(struct user32) - 3)
+       if (!is_compat_task() || (addr & 3) || addr > sizeof(struct user32) - 3)
                return -EIO;
 
        return __poke_user_compat(child, addr, data);
@@ -642,6 +642,9 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
 {
        long ret;
 
+       /* Do the secure computing check first. */
+       secure_computing(regs->gprs[2]);
+
        /*
         * The sysc_tracesys code in entry.S stored the system
         * call number to gprs[2].
@@ -659,8 +662,11 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
                ret = -1;
        }
 
+       if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE)))
+               ftrace_syscall_enter(regs);
+
        if (unlikely(current->audit_context))
-               audit_syscall_entry(test_thread_flag(TIF_31BIT) ?
+               audit_syscall_entry(is_compat_task() ?
                                        AUDIT_ARCH_S390 : AUDIT_ARCH_S390X,
                                    regs->gprs[2], regs->orig_gpr2,
                                    regs->gprs[3], regs->gprs[4],
@@ -674,6 +680,9 @@ asmlinkage void do_syscall_trace_exit(struct pt_regs *regs)
                audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]),
                                   regs->gprs[2]);
 
+       if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE)))
+               ftrace_syscall_exit(regs);
+
        if (test_thread_flag(TIF_SYSCALL_TRACE))
                tracehook_report_syscall_exit(regs, 0);
 }
index a0d2d55d7fb3996faae1fcaf686b44d1ef353863..0de305b598cee30a1352f67d4ded1eda4f0d3be0 100644 (file)
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/ftrace.h>
 #include <linux/errno.h>
 #include <linux/kernel_stat.h>
 #include <linux/interrupt.h>
-#include <asm/cpu.h>
+#include <asm/cputime.h>
 #include <asm/lowcore.h>
 #include <asm/s390_ext.h>
 #include <asm/irq_regs.h>
@@ -112,7 +113,7 @@ int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
        return 0;
 }
 
-void do_extint(struct pt_regs *regs, unsigned short code)
+void __irq_entry do_extint(struct pt_regs *regs, unsigned short code)
 {
         ext_int_info_t *p;
         int index;
diff --git a/arch/s390/kernel/sclp.S b/arch/s390/kernel/sclp.S
new file mode 100644 (file)
index 0000000..20639df
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * Mini SCLP driver.
+ *
+ * Copyright IBM Corp. 2004,2009
+ *
+ *   Author(s):        Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>,
+ *             Heiko Carstens <heiko.carstens@de.ibm.com>,
+ *
+ */
+
+LC_EXT_NEW_PSW         = 0x58                  # addr of ext int handler
+LC_EXT_INT_PARAM       = 0x80                  # addr of ext int parameter
+LC_EXT_INT_CODE                = 0x86                  # addr of ext int code
+
+#
+# Subroutine which waits synchronously until either an external interruption
+# or a timeout occurs.
+#
+# Parameters:
+#   R2 = 0 for no timeout, non-zero for timeout in (approximated) seconds
+#
+# Returns:
+#   R2 = 0 on interrupt, 2 on timeout
+#   R3 = external interruption parameter if R2=0
+#
+
+.section ".init.text","ax"
+
+_sclp_wait_int:
+       stm     %r6,%r15,24(%r15)               # save registers
+       basr    %r13,0                          # get base register
+.LbaseS1:
+       ahi     %r15,-96                        # create stack frame
+       la      %r8,LC_EXT_NEW_PSW              # register int handler
+       mvc     .LoldpswS1-.LbaseS1(8,%r13),0(%r8)
+       mvc     0(8,%r8),.LextpswS1-.LbaseS1(%r13)
+       lhi     %r6,0x0200                      # cr mask for ext int (cr0.54)
+       ltr     %r2,%r2
+       jz      .LsetctS1
+       ahi     %r6,0x0800                      # cr mask for clock int (cr0.52)
+       stck    .LtimeS1-.LbaseS1(%r13)         # initiate timeout
+       al      %r2,.LtimeS1-.LbaseS1(%r13)
+       st      %r2,.LtimeS1-.LbaseS1(%r13)
+       sckc    .LtimeS1-.LbaseS1(%r13)
+
+.LsetctS1:
+       stctl   %c0,%c0,.LctlS1-.LbaseS1(%r13)  # enable required interrupts
+       l       %r0,.LctlS1-.LbaseS1(%r13)
+       lhi     %r1,~(0x200 | 0x800)            # clear old values
+       nr      %r1,%r0
+       or      %r1,%r6                         # set new value
+       st      %r1,.LctlS1-.LbaseS1(%r13)
+       lctl    %c0,%c0,.LctlS1-.LbaseS1(%r13)
+       st      %r0,.LctlS1-.LbaseS1(%r13)
+       lhi     %r2,2                           # return code for timeout
+.LloopS1:
+       lpsw    .LwaitpswS1-.LbaseS1(%r13)      # wait until interrupt
+.LwaitS1:
+       lh      %r7,LC_EXT_INT_CODE
+       chi     %r7,0x1004                      # timeout?
+       je      .LtimeoutS1
+       chi     %r7,0x2401                      # service int?
+       jne     .LloopS1
+       sr      %r2,%r2
+       l       %r3,LC_EXT_INT_PARAM
+.LtimeoutS1:
+       lctl    %c0,%c0,.LctlS1-.LbaseS1(%r13)  # restore interrupt setting
+       # restore old handler
+       mvc     0(8,%r8),.LoldpswS1-.LbaseS1(%r13)
+       lm      %r6,%r15,120(%r15)              # restore registers
+       br      %r14                            # return to caller
+
+       .align  8
+.LoldpswS1:
+       .long   0, 0                            # old ext int PSW
+.LextpswS1:
+       .long   0x00080000, 0x80000000+.LwaitS1 # PSW to handle ext int
+.LwaitpswS1:
+       .long   0x010a0000, 0x00000000+.LloopS1 # PSW to wait for ext int
+.LtimeS1:
+       .quad   0                               # current time
+.LctlS1:
+       .long   0                               # CT0 contents
+
+#
+# Subroutine to synchronously issue a service call.
+#
+# Parameters:
+#   R2 = command word
+#   R3 = sccb address
+#
+# Returns:
+#   R2 = 0 on success, 1 on failure
+#   R3 = sccb response code if R2 = 0
+#
+
+_sclp_servc:
+       stm     %r6,%r15,24(%r15)               # save registers
+       ahi     %r15,-96                        # create stack frame
+       lr      %r6,%r2                         # save command word
+       lr      %r7,%r3                         # save sccb address
+.LretryS2:
+       lhi     %r2,1                           # error return code
+       .insn   rre,0xb2200000,%r6,%r7          # servc
+       brc     1,.LendS2                       # exit if not operational
+       brc     8,.LnotbusyS2                   # go on if not busy
+       sr      %r2,%r2                         # wait until no longer busy
+       bras    %r14,_sclp_wait_int
+       j       .LretryS2                       # retry
+.LnotbusyS2:
+       sr      %r2,%r2                         # wait until result
+       bras    %r14,_sclp_wait_int
+       sr      %r2,%r2
+       lh      %r3,6(%r7)
+.LendS2:
+       lm      %r6,%r15,120(%r15)              # restore registers
+       br      %r14
+
+#
+# Subroutine to set up the SCLP interface.
+#
+# Parameters:
+#   R2 = 0 to activate, non-zero to deactivate
+#
+# Returns:
+#   R2 = 0 on success, non-zero on failure
+#
+
+_sclp_setup:
+       stm     %r6,%r15,24(%r15)               # save registers
+       ahi     %r15,-96                        # create stack frame
+       basr    %r13,0                          # get base register
+.LbaseS3:
+       l       %r6,.LsccbS0-.LbaseS3(%r13)     # prepare init mask sccb
+       mvc     0(.LinitendS3-.LinitsccbS3,%r6),.LinitsccbS3-.LbaseS3(%r13)
+       ltr     %r2,%r2                         # initialization?
+       jz      .LdoinitS3                      # go ahead
+       # clear masks
+       xc      .LinitmaskS3-.LinitsccbS3(8,%r6),.LinitmaskS3-.LinitsccbS3(%r6)
+.LdoinitS3:
+       l       %r2,.LwritemaskS3-.LbaseS3(%r13)# get command word
+       lr      %r3,%r6                         # get sccb address
+       bras    %r14,_sclp_servc                # issue service call
+       ltr     %r2,%r2                         # servc successful?
+       jnz     .LerrorS3
+       chi     %r3,0x20                        # write mask successful?
+       jne     .LerrorS3
+       # check masks
+       la      %r2,.LinitmaskS3-.LinitsccbS3(%r6)
+       l       %r1,0(%r2)                      # receive mask ok?
+       n       %r1,12(%r2)
+       cl      %r1,0(%r2)
+       jne     .LerrorS3
+       l       %r1,4(%r2)                      # send mask ok?
+       n       %r1,8(%r2)
+       cl      %r1,4(%r2)
+       sr      %r2,%r2
+       je      .LendS3
+.LerrorS3:
+       lhi     %r2,1                           # error return code
+.LendS3:
+       lm      %r6,%r15,120(%r15)              # restore registers
+       br      %r14
+.LwritemaskS3:
+       .long   0x00780005                      # SCLP command for write mask
+.LinitsccbS3:
+       .word   .LinitendS3-.LinitsccbS3
+       .byte   0,0,0,0
+       .word   0
+       .word   0
+       .word   4
+.LinitmaskS3:
+       .long   0x80000000
+       .long   0x40000000
+       .long   0
+       .long   0
+.LinitendS3:
+
+#
+# Subroutine which prints a given text to the SCLP console.
+#
+# Parameters:
+#   R2 = address of nil-terminated ASCII text
+#
+# Returns:
+#   R2 = 0 on success, 1 on failure
+#
+
+_sclp_print:
+       stm     %r6,%r15,24(%r15)               # save registers
+       ahi     %r15,-96                        # create stack frame
+       basr    %r13,0                          # get base register
+.LbaseS4:
+       l       %r8,.LsccbS0-.LbaseS4(%r13)     # prepare write data sccb
+       mvc     0(.LmtoS4-.LwritesccbS4,%r8),.LwritesccbS4-.LbaseS4(%r13)
+       la      %r7,.LmtoS4-.LwritesccbS4(%r8)  # current mto addr
+       sr      %r0,%r0
+       l       %r10,.Lascebc-.LbaseS4(%r13)    # address of translation table
+.LinitmtoS4:
+       # initialize mto
+       mvc     0(.LmtoendS4-.LmtoS4,%r7),.LmtoS4-.LbaseS4(%r13)
+       lhi     %r6,.LmtoendS4-.LmtoS4          # current mto length
+.LloopS4:
+       ic      %r0,0(%r2)                      # get character
+       ahi     %r2,1
+       ltr     %r0,%r0                         # end of string?
+       jz      .LfinalizemtoS4
+       chi     %r0,0x15                        # end of line (NL)?
+       jz      .LfinalizemtoS4
+       stc     %r0,0(%r6,%r7)                  # copy to mto
+       la      %r11,0(%r6,%r7)
+       tr      0(1,%r11),0(%r10)               # translate to EBCDIC
+       ahi     %r6,1
+       j       .LloopS4
+.LfinalizemtoS4:
+       sth     %r6,0(%r7)                      # update mto length
+       lh      %r9,.LmdbS4-.LwritesccbS4(%r8)  # update mdb length
+       ar      %r9,%r6
+       sth     %r9,.LmdbS4-.LwritesccbS4(%r8)
+       lh      %r9,.LevbufS4-.LwritesccbS4(%r8)# update evbuf length
+       ar      %r9,%r6
+       sth     %r9,.LevbufS4-.LwritesccbS4(%r8)
+       lh      %r9,0(%r8)                      # update sccb length
+       ar      %r9,%r6
+       sth     %r9,0(%r8)
+       ar      %r7,%r6                         # update current mto adress
+       ltr     %r0,%r0                         # more characters?
+       jnz     .LinitmtoS4
+       l       %r2,.LwritedataS4-.LbaseS4(%r13)# write data
+       lr      %r3,%r8
+       bras    %r14,_sclp_servc
+       ltr     %r2,%r2                         # servc successful?
+       jnz     .LendS4
+       chi     %r3,0x20                        # write data successful?
+       je      .LendS4
+       lhi     %r2,1                           # error return code
+.LendS4:
+       lm      %r6,%r15,120(%r15)              # restore registers
+       br      %r14
+
+#
+# Function which prints a given text to the SCLP console.
+#
+# Parameters:
+#   R2 = address of nil-terminated ASCII text
+#
+# Returns:
+#   R2 = 0 on success, 1 on failure
+#
+
+       .globl _sclp_print_early
+_sclp_print_early:
+       stm     %r6,%r15,24(%r15)               # save registers
+       ahi     %r15,-96                        # create stack frame
+       lr      %r10,%r2                        # save string pointer
+       lhi     %r2,0
+       bras    %r14,_sclp_setup                # enable console
+       ltr     %r2,%r2
+       jnz     .LendS5
+       lr      %r2,%r10
+       bras    %r14,_sclp_print                # print string
+       ltr     %r2,%r2
+       jnz     .LendS5
+       lhi     %r2,1
+       bras    %r14,_sclp_setup                # disable console
+.LendS5:
+       lm      %r6,%r15,120(%r15)              # restore registers
+       br      %r14
+
+.LwritedataS4:
+       .long   0x00760005                      # SCLP command for write data
+.LwritesccbS4:
+       # sccb
+       .word   .LmtoS4-.LwritesccbS4
+       .byte   0
+       .byte   0,0,0
+       .word   0
+
+       # evbuf
+.LevbufS4:
+       .word   .LmtoS4-.LevbufS4
+       .byte   0x02
+       .byte   0
+       .word   0
+
+.LmdbS4:
+       # mdb
+       .word   .LmtoS4-.LmdbS4
+       .word   1
+       .long   0xd4c4c240
+       .long   1
+
+       # go
+.LgoS4:
+       .word   .LmtoS4-.LgoS4
+       .word   1
+       .long   0
+       .byte   0,0,0,0,0,0,0,0
+       .byte   0,0,0
+       .byte   0
+       .byte   0,0,0,0,0,0,0
+       .byte   0
+       .word   0
+       .byte   0,0,0,0,0,0,0,0,0,0
+       .byte   0,0,0,0,0,0,0,0
+       .byte   0,0,0,0,0,0,0,0
+
+.LmtoS4:
+       .word   .LmtoendS4-.LmtoS4
+       .word   4
+       .word   0x1000
+       .byte   0
+       .byte   0,0,0
+.LmtoendS4:
+
+       # Global constants
+.LsccbS0:
+       .long   _sclp_work_area
+.Lascebc:
+       .long   _ascebc
+.previous
+
+.section ".init.data","a"
+       .balign 4096
+_sclp_work_area:
+       .fill   4096
+.previous
index 7402b6a39ead686232723361a5de31d6ad2e5b95..9717717c6fea5595b364e8b321ee6fa284580396 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/ctype.h>
 #include <linux/reboot.h>
 #include <linux/topology.h>
+#include <linux/ftrace.h>
 
 #include <asm/ipl.h>
 #include <asm/uaccess.h>
@@ -442,6 +443,7 @@ setup_lowcore(void)
        lc->steal_timer = S390_lowcore.steal_timer;
        lc->last_update_timer = S390_lowcore.last_update_timer;
        lc->last_update_clock = S390_lowcore.last_update_clock;
+       lc->ftrace_func = S390_lowcore.ftrace_func;
        set_prefix((u32)(unsigned long) lc);
        lowcore_ptr[0] = lc;
 }
index 3cf74c3ccb699184e7b55e9237103d6cd269b47a..062bd64e65fabe1f09641a4c3e0290ae4ff013ee 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/binfmts.h>
 #include <linux/tracehook.h>
 #include <linux/syscalls.h>
+#include <linux/compat.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/lowcore.h>
@@ -482,7 +483,7 @@ void do_signal(struct pt_regs *regs)
                /* Whee!  Actually deliver the signal.  */
                int ret;
 #ifdef CONFIG_COMPAT
-               if (test_thread_flag(TIF_31BIT)) {
+               if (is_compat_task()) {
                        ret = handle_signal32(signr, &ka, &info, oldset, regs);
                }
                else
index a985a3ba44011c948ef6948ac6631a2d9685a8a2..cc8c484984e33160375b11fd9f147c764b805cde 100644 (file)
@@ -47,7 +47,7 @@
 #include <asm/timer.h>
 #include <asm/lowcore.h>
 #include <asm/sclp.h>
-#include <asm/cpu.h>
+#include <asm/cputime.h>
 #include <asm/vdso.h>
 #include "entry.h"
 
@@ -572,6 +572,7 @@ int __cpuinit __cpu_up(unsigned int cpu)
        cpu_lowcore->cpu_nr = cpu;
        cpu_lowcore->kernel_asce = S390_lowcore.kernel_asce;
        cpu_lowcore->machine_flags = S390_lowcore.machine_flags;
+       cpu_lowcore->ftrace_func = S390_lowcore.ftrace_func;
        eieio();
 
        while (signal_processor(cpu, sigp_restart) == sigp_busy)
index 2c7739fe70b10a632146cb73ec674def95175478..ad1acd20038554ec19a518e8fda56cce7b4d5f17 100644 (file)
@@ -338,3 +338,5 @@ SYSCALL(sys_dup3,sys_dup3,sys_dup3_wrapper)
 SYSCALL(sys_epoll_create1,sys_epoll_create1,sys_epoll_create1_wrapper)
 SYSCALL(sys_preadv,sys_preadv,compat_sys_preadv_wrapper)
 SYSCALL(sys_pwritev,sys_pwritev,compat_sys_pwritev_wrapper)
+SYSCALL(sys_rt_tgsigqueueinfo,sys_rt_tgsigqueueinfo,compat_sys_rt_tgsigqueueinfo_wrapper) /* 330 */
+SYSCALL(sys_perf_counter_open,sys_perf_counter_open,sys_perf_counter_open_wrapper)
index ef596d020573ec0bfef8bc98ef1d4be225e7881f..215330a2c128dfce1bb341fed1bd138ef089c918 100644 (file)
@@ -70,7 +70,7 @@ static DEFINE_PER_CPU(struct clock_event_device, comparators);
 /*
  * Scheduler clock - returns current time in nanosec units.
  */
-unsigned long long sched_clock(void)
+unsigned long long notrace sched_clock(void)
 {
        return ((get_clock_xt() - sched_clock_base_cc) * 125) >> 9;
 }
@@ -95,12 +95,6 @@ void tod_to_timeval(__u64 todval, struct timespec *xtime)
        xtime->tv_nsec = ((todval * 1000) >> 12);
 }
 
-#ifdef CONFIG_PROFILING
-#define s390_do_profile()      profile_tick(CPU_PROFILING)
-#else
-#define s390_do_profile()      do { ; } while(0)
-#endif /* CONFIG_PROFILING */
-
 void clock_comparator_work(void)
 {
        struct clock_event_device *cd;
@@ -109,7 +103,6 @@ void clock_comparator_work(void)
        set_clock_comparator(S390_lowcore.clock_comparator);
        cd = &__get_cpu_var(comparators);
        cd->event_handler(cd);
-       s390_do_profile();
 }
 
 /*
index 89b2e7f1b7a9ca85c207880b54f7c220ac428728..45e1708b70fd028fdd9b6b432f156f886855d0ae 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/elf.h>
 #include <linux/security.h>
 #include <linux/bootmem.h>
-
+#include <linux/compat.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/processor.h>
@@ -53,8 +53,19 @@ unsigned int __read_mostly vdso_enabled = 1;
 
 static int __init vdso_setup(char *s)
 {
-       vdso_enabled = simple_strtoul(s, NULL, 0);
-       return 1;
+       unsigned long val;
+       int rc;
+
+       rc = 0;
+       if (strncmp(s, "on", 3) == 0)
+               vdso_enabled = 1;
+       else if (strncmp(s, "off", 4) == 0)
+               vdso_enabled = 0;
+       else {
+               rc = strict_strtoul(s, 0, &val);
+               vdso_enabled = rc ? 0 : !!val;
+       }
+       return !rc;
 }
 __setup("vdso=", vdso_setup);
 
@@ -203,7 +214,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
        vdso_pagelist = vdso64_pagelist;
        vdso_pages = vdso64_pages;
 #ifdef CONFIG_COMPAT
-       if (test_thread_flag(TIF_31BIT)) {
+       if (is_compat_task()) {
                vdso_pagelist = vdso32_pagelist;
                vdso_pages = vdso32_pages;
        }
index 89399b8756c2bae265601ba314bfb51dd9493f0f..a53db23ee092fcbd37f2fa2e16ca5fbc8a583cd7 100644 (file)
@@ -34,6 +34,7 @@ SECTIONS
                SCHED_TEXT
                LOCK_TEXT
                KPROBES_TEXT
+               IRQENTRY_TEXT
                *(.fixup)
                *(.gnu.warning)
        } :text = 0x0700
index c87f59bd8246a9ecdbe9d9417a58b19975df72f9..c8eb7255332b8bda03f187525087dd47baa535e2 100644 (file)
@@ -23,7 +23,7 @@
 #include <asm/s390_ext.h>
 #include <asm/timer.h>
 #include <asm/irq_regs.h>
-#include <asm/cpu.h>
+#include <asm/cputime.h>
 
 static ext_int_info_t ext_int_info_timer;
 
index 10bccd1f8aee58a33220bfbc07aa3b3452b1b3e7..c18b21d6991cebacdb8dfb4358017db75782eb44 100644 (file)
@@ -512,7 +512,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                BUG();
        }
 
-       might_sleep();
+       might_fault();
 
        do {
                __vcpu_run(vcpu);
index e41f4008afc501927a5c3b08fda18891c1afc887..f7e0d30250b707b1ed46f7878f0f6790e7295e30 100644 (file)
@@ -124,6 +124,27 @@ void _raw_read_lock_wait(raw_rwlock_t *rw)
 }
 EXPORT_SYMBOL(_raw_read_lock_wait);
 
+void _raw_read_lock_wait_flags(raw_rwlock_t *rw, unsigned long flags)
+{
+       unsigned int old;
+       int count = spin_retry;
+
+       local_irq_restore(flags);
+       while (1) {
+               if (count-- <= 0) {
+                       _raw_yield();
+                       count = spin_retry;
+               }
+               if (!__raw_read_can_lock(rw))
+                       continue;
+               old = rw->lock & 0x7fffffffU;
+               local_irq_disable();
+               if (_raw_compare_and_swap(&rw->lock, old, old + 1) == old)
+                       return;
+       }
+}
+EXPORT_SYMBOL(_raw_read_lock_wait_flags);
+
 int _raw_read_trylock_retry(raw_rwlock_t *rw)
 {
        unsigned int old;
@@ -157,6 +178,25 @@ void _raw_write_lock_wait(raw_rwlock_t *rw)
 }
 EXPORT_SYMBOL(_raw_write_lock_wait);
 
+void _raw_write_lock_wait_flags(raw_rwlock_t *rw, unsigned long flags)
+{
+       int count = spin_retry;
+
+       local_irq_restore(flags);
+       while (1) {
+               if (count-- <= 0) {
+                       _raw_yield();
+                       count = spin_retry;
+               }
+               if (!__raw_write_can_lock(rw))
+                       continue;
+               local_irq_disable();
+               if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000) == 0)
+                       return;
+       }
+}
+EXPORT_SYMBOL(_raw_write_lock_wait_flags);
+
 int _raw_write_trylock_retry(raw_rwlock_t *rw)
 {
        int count = spin_retry;
index 2a745813454410cb35ff525e837efc9f29c0dd95..db05661ac8954269a36d796b548e7bb0a40f126c 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the linux s390-specific parts of the memory manager.
 #
 
-obj-y   := init.o fault.o extmem.o mmap.o vmem.o pgtable.o
+obj-y   := init.o fault.o extmem.o mmap.o vmem.o pgtable.o maccess.o
 obj-$(CONFIG_CMM) += cmm.o
 obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
 obj-$(CONFIG_PAGE_STATES) += page-states.o
index 833e8366c351d08238466e21f660c66dc47e0845..220a152c836ccf990c109bed1089d297e4ba76d6 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
+#include <linux/compat.h>
 #include <linux/smp.h>
 #include <linux/kdebug.h>
 #include <linux/smp_lock.h>
@@ -239,7 +240,7 @@ static int signal_return(struct mm_struct *mm, struct pt_regs *regs,
        up_read(&mm->mmap_sem);
        clear_tsk_thread_flag(current, TIF_SINGLE_STEP);
 #ifdef CONFIG_COMPAT
-       compat = test_tsk_thread_flag(current, TIF_31BIT);
+       compat = is_compat_task();
        if (compat && instruction == 0x0a77)
                sys32_sigreturn();
        else if (compat && instruction == 0x0aad)
diff --git a/arch/s390/mm/maccess.c b/arch/s390/mm/maccess.c
new file mode 100644 (file)
index 0000000..8175627
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Access kernel memory without faulting -- s390 specific implementation.
+ *
+ * Copyright IBM Corp. 2009
+ *
+ *   Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
+ *
+ */
+
+#include <linux/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <asm/system.h>
+
+/*
+ * This function writes to kernel memory bypassing DAT and possible
+ * write protection. It copies one to four bytes from src to dst
+ * using the stura instruction.
+ * Returns the number of bytes copied or -EFAULT.
+ */
+static long probe_kernel_write_odd(void *dst, void *src, size_t size)
+{
+       unsigned long count, aligned;
+       int offset, mask;
+       int rc = -EFAULT;
+
+       aligned = (unsigned long) dst & ~3UL;
+       offset = (unsigned long) dst & 3;
+       count = min_t(unsigned long, 4 - offset, size);
+       mask = (0xf << (4 - count)) & 0xf;
+       mask >>= offset;
+       asm volatile(
+               "       bras    1,0f\n"
+               "       icm     0,0,0(%3)\n"
+               "0:     l       0,0(%1)\n"
+               "       lra     %1,0(%1)\n"
+               "1:     ex      %2,0(1)\n"
+               "2:     stura   0,%1\n"
+               "       la      %0,0\n"
+               "3:\n"
+               EX_TABLE(0b,3b) EX_TABLE(1b,3b) EX_TABLE(2b,3b)
+               : "+d" (rc), "+a" (aligned)
+               : "a" (mask), "a" (src) : "cc", "memory", "0", "1");
+       return rc ? rc : count;
+}
+
+long probe_kernel_write(void *dst, void *src, size_t size)
+{
+       long copied = 0;
+
+       while (size) {
+               copied = probe_kernel_write_odd(dst, src, size);
+               if (copied < 0)
+                       break;
+               dst += copied;
+               src += copied;
+               size -= copied;
+       }
+       return copied < 0 ? -EFAULT : 0;
+}
index e008d236cc150666187fc7921df901523fe476ce..f4558ccf02b9cd266ad005cb2925a2dfa5d7ea89 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <asm/pgalloc.h>
+#include <asm/compat.h>
 
 /*
  * Top of mmap area (just below the process stack).
@@ -55,7 +56,7 @@ static inline int mmap_is_legacy(void)
        /*
         * Force standard allocation for 64 bit programs.
         */
-       if (!test_thread_flag(TIF_31BIT))
+       if (!is_compat_task())
                return 1;
 #endif
        return sysctl_legacy_va_layout ||
@@ -91,7 +92,7 @@ EXPORT_SYMBOL_GPL(arch_pick_mmap_layout);
 
 int s390_mmap_check(unsigned long addr, unsigned long len)
 {
-       if (!test_thread_flag(TIF_31BIT) &&
+       if (!is_compat_task() &&
            len >= TASK_SIZE && TASK_SIZE < (1UL << 53))
                return crst_table_upgrade(current->mm, 1UL << 53);
        return 0;
@@ -108,8 +109,7 @@ s390_get_unmapped_area(struct file *filp, unsigned long addr,
        area = arch_get_unmapped_area(filp, addr, len, pgoff, flags);
        if (!(area & ~PAGE_MASK))
                return area;
-       if (area == -ENOMEM &&
-           !test_thread_flag(TIF_31BIT) && TASK_SIZE < (1UL << 53)) {
+       if (area == -ENOMEM && !is_compat_task() && TASK_SIZE < (1UL << 53)) {
                /* Upgrade the page table to 4 levels and retry. */
                rc = crst_table_upgrade(mm, 1UL << 53);
                if (rc)
@@ -131,8 +131,7 @@ s390_get_unmapped_area_topdown(struct file *filp, const unsigned long addr,
        area = arch_get_unmapped_area_topdown(filp, addr, len, pgoff, flags);
        if (!(area & ~PAGE_MASK))
                return area;
-       if (area == -ENOMEM &&
-           !test_thread_flag(TIF_31BIT) && TASK_SIZE < (1UL << 53)) {
+       if (area == -ENOMEM && !is_compat_task() && TASK_SIZE < (1UL << 53)) {
                /* Upgrade the page table to 4 levels and retry. */
                rc = crst_table_upgrade(mm, 1UL << 53);
                if (rc)
index be6c1cf4ad5ae8922f039ab2100b2e50183553f2..4ca8e826bf303b4d8694f0757fe8b471ba52d099 100644 (file)
@@ -1,7 +1,5 @@
 /*
- *  arch/s390/mm/pgtable.c
- *
- *    Copyright IBM Corp. 2007
+ *    Copyright IBM Corp. 2007,2009
  *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
  */
 
@@ -53,6 +51,18 @@ void clear_table_pgstes(unsigned long *table)
 
 #endif
 
+unsigned long VMALLOC_START = VMALLOC_END - VMALLOC_SIZE;
+EXPORT_SYMBOL(VMALLOC_START);
+
+static int __init parse_vmalloc(char *arg)
+{
+       if (!arg)
+               return -EINVAL;
+       VMALLOC_START = (VMALLOC_END - memparse(arg, &arg)) & PAGE_MASK;
+       return 0;
+}
+early_param("vmalloc", parse_vmalloc);
+
 unsigned long *crst_table_alloc(struct mm_struct *mm, int noexec)
 {
        struct page *page = alloc_pages(GFP_KERNEL, ALLOC_ORDER);
index 978b58efb1e92e18464010bfeeeae5a5296de3c0..157c320272cbb256b8e13915534ba80bd66227ac 100644 (file)
@@ -84,5 +84,5 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
 #define smp_mb__before_atomic_inc()    barrier()
 #define smp_mb__after_atomic_inc()     barrier()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* __ASM_SH_ATOMIC_H */
diff --git a/arch/sh/include/asm/bitsperlong.h b/arch/sh/include/asm/bitsperlong.h
new file mode 100644 (file)
index 0000000..6dc0bb0
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/bitsperlong.h>
index 156eb0225cf64d0a49cd4e7ec14e1602467cabb7..7d8b72c91a5f45d25db9dca3d5d88c6cd5454836 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __ASM_SH_MMAN_H
 #define __ASM_SH_MMAN_H
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 #define MAP_GROWSDOWN  0x0100          /* stack-like segment */
 #define MAP_DENYWRITE  0x0800          /* ETXTBSY */
index 9c6d21ec0240981f3bc4da574162caebad1feac6..49592c780a6e8d604df09d9ed45edb9728bcbdfc 100644 (file)
@@ -163,7 +163,7 @@ typedef struct page *pgtable_t;
                                 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
 #include <asm-generic/memory_model.h>
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 /* vDSO support */
 #ifdef CONFIG_VSYSCALL
index 5c5c1e852089f2b4e81f8f07f96a660dbb81afe6..9cc5f014468905a3bef54d80a399391aa2e98c8f 100644 (file)
@@ -106,7 +106,7 @@ typedef unsigned long sigset_t;
 #define MINSIGSTKSZ    2048
 #define SIGSTKSZ       8192
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 #ifdef __KERNEL__
 struct old_sigaction {
index c19b0f7d2cc13a100aaeecd24b420eeaff30c32f..c2efdcde266f7e91f196aaa3a1aa942e86c558f6 100644 (file)
@@ -46,8 +46,6 @@ void *module_alloc(unsigned long size)
 void module_free(struct module *mod, void *module_region)
 {
        vfree(module_region);
-       /* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
 }
 
 /* We don't need anything special. */
index bb91b1248cd1dca941846f80d132206dd4ad6f39..f0d343c3b956580265210d4fb6a059f2bde2ddd4 100644 (file)
@@ -161,5 +161,5 @@ static inline int __atomic24_sub(int i, atomic24_t *v)
 
 #endif /* !(__KERNEL__) */
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* !(__ARCH_SPARC_ATOMIC__) */
index a0a70649269693e199973b190939e48937fc8157..f2e48009989e1e57f552066d8ae9890264590d5c 100644 (file)
@@ -114,5 +114,5 @@ static inline int atomic64_add_unless(atomic64_t *v, long a, long u)
 #define smp_mb__before_atomic_inc()    barrier()
 #define smp_mb__after_atomic_inc()     barrier()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* !(__ARCH_SPARC64_ATOMIC__) */
diff --git a/arch/sparc/include/asm/bitsperlong.h b/arch/sparc/include/asm/bitsperlong.h
new file mode 100644 (file)
index 0000000..40dcaa3
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __ASM_ALPHA_BITSPERLONG_H
+#define __ASM_ALPHA_BITSPERLONG_H
+
+#if defined(__sparc__) && defined(__arch64__)
+#define __BITS_PER_LONG 64
+#else
+#define __BITS_PER_LONG 32
+#endif
+
+#include <asm-generic/bitsperlong.h>
+
+#endif /* __ASM_ALPHA_BITSPERLONG_H */
+
index fdfbbf0a4736ef454287ce2d6c6a9b2da6801fc5..988192e8e95657d366e558a97954dda6cfba027f 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __SPARC_MMAN_H__
 #define __SPARC_MMAN_H__
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 /* SunOS'ified... */
 
index d1806edc0958b7f81c2b9d38d06a2b9ab71b2c3a..f72080bdda947ec81edce5206842d836755f4521 100644 (file)
@@ -152,6 +152,6 @@ extern unsigned long pfn_base;
                                 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
 #include <asm-generic/memory_model.h>
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* _SPARC_PAGE_H */
index 4274ed13ddb2d6209fdc914db7d51f939ad4b06c..f0d09b40103626f7f02d571170935c651f64c470 100644 (file)
@@ -132,6 +132,6 @@ typedef struct page *pgtable_t;
 #define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
                                 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* _SPARC64_PAGE_H */
index cba45206b7f2e6eb975da848a4bbcbe4f190eb4e..e49b828a2471d57cca8e5aa723acc3a011a9d390 100644 (file)
@@ -176,7 +176,7 @@ struct sigstack {
 #define SA_STATIC_ALLOC         0x8000
 #endif
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 struct __new_sigaction {
        __sighandler_t          sa_handler;
index 2237118825d029d260c18b8f46a735c5294899f8..de671d73baed5703b08329378990ca3f2fb9a10b 100644 (file)
@@ -21,8 +21,6 @@ typedef unsigned short umode_t;
 
 #ifdef __KERNEL__
 
-#define BITS_PER_LONG 64
-
 #ifndef __ASSEMBLY__
 
 /* Dma addresses come in generic and 64-bit flavours.  */
@@ -46,8 +44,6 @@ typedef unsigned short umode_t;
 
 #ifdef __KERNEL__
 
-#define BITS_PER_LONG 32
-
 #ifndef __ASSEMBLY__
 
 typedef u32 dma_addr_t;
index 47d5619d43fafbdd15a0798b4357aac3f30cbce3..8303ac48103426542f6681d826c995f8b8375385 100644 (file)
@@ -17,6 +17,9 @@
 
 #ifndef __ASSEMBLY__
 
+#define ARCH_HAS_SORT_EXTABLE
+#define ARCH_HAS_SEARCH_EXTABLE
+
 /* Sparc is not segmented, however we need to be able to fool access_ok()
  * when doing system calls from kernel mode legitimately.
  *
index c64e767a3e4b3821fd906a3132db4cdc579d8f30..a38c03238918ce3659c66e34804398a6a8345786 100644 (file)
@@ -12,7 +12,7 @@
 #include <asm/asi.h>
 #include <asm/system.h>
 #include <asm/spitfire.h>
-#include <asm-generic/uaccess.h>
+#include <asm-generic/uaccess-unaligned.h>
 #endif
 
 #ifndef __ASSEMBLY__
index 90273765e81f95b7d07250fe35dc29cc5d122ecc..0ee642f63234a19ce1d32b5d9feab15e9309cc5a 100644 (file)
@@ -75,8 +75,6 @@ void *module_alloc(unsigned long size)
 void module_free(struct module *mod, void *module_region)
 {
        vfree(module_region);
-       /* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
 }
 
 /* Make generic code ignore STT_REGISTER dummy undefined symbols.  */
index 16cc28935e398ede97a7e86fff652656bd042d21..a61c349448e1e12b28621b3590553593f2d3b799 100644 (file)
@@ -28,6 +28,10 @@ search_extable(const struct exception_table_entry *start,
         *      word 3: last insn address + 4 bytes
         *      word 4: fixup code address
         *
+        * Deleted entries are encoded as:
+        *      word 1: unused
+        *      word 2: -1
+        *
         * See asm/uaccess.h for more details.
         */
 
@@ -39,6 +43,10 @@ search_extable(const struct exception_table_entry *start,
                        continue;
                }
 
+               /* A deleted entry; see trim_init_extable */
+               if (walk->fixup == -1)
+                       continue;
+
                if (walk->insn == value)
                        return walk;
        }
@@ -57,6 +65,27 @@ search_extable(const struct exception_table_entry *start,
         return NULL;
 }
 
+#ifdef CONFIG_MODULES
+/* We could memmove them around; easier to mark the trimmed ones. */
+void trim_init_extable(struct module *m)
+{
+       unsigned int i;
+       bool range;
+
+       for (i = 0; i < m->num_exentries; i += range ? 2 : 1) {
+               range = m->extable[i].fixup == 0;
+
+               if (within_module_init(m->extable[i].insn, m)) {
+                       m->extable[i].fixup = -1;
+                       if (range)
+                               m->extable[i+1].fixup = -1;
+               }
+               if (range)
+                       i++;
+       }
+}
+#endif /* CONFIG_MODULES */
+
 /* Special extable search, which handles ranges.  Returns fixup */
 unsigned long search_extables_range(unsigned long addr, unsigned long *g2)
 {
index 55f28a0bae6d3dd99ee7e23eb01ccb546ba446ef..4cc9b6cf480a299dc201791a189babd4362177d4 100644 (file)
@@ -116,7 +116,7 @@ extern unsigned long uml_physmem;
 #define virt_addr_valid(v) pfn_valid(phys_to_pfn(__pa(v)))
 
 #include <asm-generic/memory_model.h>
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #endif /* __ASSEMBLY__ */
 #endif /* __UM_PAGE_H */
index 58da2480a7f4229fb164ae81947bfc901de8b27d..9ce3f165111a63607fa91f98a99e3b232fb5080a 100644 (file)
@@ -53,16 +53,21 @@ extern unsigned long end_iomem;
 #else
 # define VMALLOC_END   (FIXADDR_START-2*PAGE_SIZE)
 #endif
+#define MODULES_VADDR  VMALLOC_START
+#define MODULES_END    VMALLOC_END
+#define MODULES_LEN    (MODULES_VADDR - MODULES_END)
 
 #define _PAGE_TABLE    (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
 #define _KERNPG_TABLE  (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
 #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
-
+#define __PAGE_KERNEL_EXEC                                              \
+        (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
 #define PAGE_NONE      __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
 #define PAGE_SHARED    __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
 #define PAGE_COPY      __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
 #define PAGE_READONLY  __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
 #define PAGE_KERNEL    __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
+#define PAGE_KERNEL_EXEC       __pgprot(__PAGE_KERNEL_EXEC)
 
 /*
  * The i386 can't do page protection for execute, and considers that the same
diff --git a/arch/um/include/asm/suspend.h b/arch/um/include/asm/suspend.h
deleted file mode 100644 (file)
index f4e8e00..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#ifndef __UM_SUSPEND_H
-#define __UM_SUSPEND_H
-
-#endif
index 598b5c1903af11f10c5c171402b6d283ba9e7565..1b549bca46454c2098974396af7db246dc27a677 100644 (file)
@@ -8,7 +8,7 @@ obj-y = bug.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
 
 subarch-obj-y = lib/semaphore_32.o lib/string_32.o
 subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem_32.o
-subarch-obj-$(CONFIG_MODULES) += kernel/module_32.o
+subarch-obj-$(CONFIG_MODULES) += kernel/module.o
 
 USER_OBJS := bugs.o ptrace_user.o fault.o
 
index c8b4cce9cfe1ce333dd877c8644f5b7d4fab3558..2201e9c20e4a85ec4673939f27e15a3ef3431f94 100644 (file)
@@ -8,10 +8,8 @@ obj-y = bug.o bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \
        setjmp.o signal.o stub.o stub_segv.o syscalls.o syscall_table.o \
        sysrq.o ksyms.o tls.o
 
-obj-$(CONFIG_MODULES) += um_module.o
-
 subarch-obj-y = lib/csum-partial_64.o lib/memcpy_64.o lib/thunk_64.o
-subarch-obj-$(CONFIG_MODULES) += kernel/module_64.o
+subarch-obj-$(CONFIG_MODULES) += kernel/module.o
 
 ldt-y = ../sys-i386/ldt.o
 
diff --git a/arch/um/sys-x86_64/um_module.c b/arch/um/sys-x86_64/um_module.c
deleted file mode 100644 (file)
index 3dead39..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#include <linux/vmalloc.h>
-#include <linux/moduleloader.h>
-
-/* Copied from i386 arch/i386/kernel/module.c */
-void *module_alloc(unsigned long size)
-{
-       if (size == 0)
-               return NULL;
-       return vmalloc_exec(size);
-}
-
-/* Free memory returned from module_alloc */
-void module_free(struct module *mod, void *module_region)
-{
-       vfree(module_region);
-       /*
-        * FIXME: If module_region == mod->init_region, trim exception
-        * table entries.
-        */
-}
-
index 711b214684ef15b3a649ae82f476380285f18cef..cf42fc305419873d2816f2989bb01f23711d74ed 100644 (file)
@@ -790,10 +790,26 @@ config X86_MCE
          to disable it.  MCE support simply ignores non-MCE processors like
          the 386 and 486, so nearly everyone can say Y here.
 
+config X86_OLD_MCE
+       depends on X86_32 && X86_MCE
+       bool "Use legacy machine check code (will go away)"
+       default n
+       select X86_ANCIENT_MCE
+       ---help---
+         Use the old i386 machine check code. This is merely intended for
+         testing in a transition period. Try this if you run into any machine
+         check related software problems, but report the problem to
+         linux-kernel.  When in doubt say no.
+
+config X86_NEW_MCE
+       depends on X86_MCE
+       bool
+       default y if (!X86_OLD_MCE && X86_32) || X86_64
+
 config X86_MCE_INTEL
        def_bool y
        prompt "Intel MCE features"
-       depends on X86_64 && X86_MCE && X86_LOCAL_APIC
+       depends on X86_NEW_MCE && X86_LOCAL_APIC
        ---help---
           Additional support for intel specific MCE features such as
           the thermal monitor.
@@ -801,19 +817,36 @@ config X86_MCE_INTEL
 config X86_MCE_AMD
        def_bool y
        prompt "AMD MCE features"
-       depends on X86_64 && X86_MCE && X86_LOCAL_APIC
+       depends on X86_NEW_MCE && X86_LOCAL_APIC
        ---help---
           Additional support for AMD specific MCE features such as
           the DRAM Error Threshold.
 
+config X86_ANCIENT_MCE
+       def_bool n
+       depends on X86_32
+       prompt "Support for old Pentium 5 / WinChip machine checks"
+       ---help---
+         Include support for machine check handling on old Pentium 5 or WinChip
+         systems. These typically need to be enabled explicitely on the command
+         line.
+
 config X86_MCE_THRESHOLD
        depends on X86_MCE_AMD || X86_MCE_INTEL
        bool
        default y
 
+config X86_MCE_INJECT
+       depends on X86_NEW_MCE
+       tristate "Machine check injector support"
+       ---help---
+         Provide support for injecting machine checks for testing purposes.
+         If you don't know what a machine check is and you don't do kernel
+         QA it is safe to say n.
+
 config X86_MCE_NONFATAL
        tristate "Check for non-fatal errors on AMD Athlon/Duron / Intel Pentium 4"
-       depends on X86_32 && X86_MCE
+       depends on X86_OLD_MCE
        ---help---
          Enabling this feature starts a timer that triggers every 5 seconds which
          will look at the machine check registers to see if anything happened.
@@ -826,11 +859,15 @@ config X86_MCE_NONFATAL
 
 config X86_MCE_P4THERMAL
        bool "check for P4 thermal throttling interrupt."
-       depends on X86_32 && X86_MCE && (X86_UP_APIC || SMP)
+       depends on X86_OLD_MCE && X86_MCE && (X86_UP_APIC || SMP)
        ---help---
          Enabling this feature will cause a message to be printed when the P4
          enters thermal throttling.
 
+config X86_THERMAL_VECTOR
+       def_bool y
+       depends on X86_MCE_P4THERMAL || X86_MCE_INTEL
+
 config VM86
        bool "Enable VM86 support" if EMBEDDED
        default y
index ebe7deedd5b42b27974b1b8884e1b68bdebb82cb..cfb0010fa94001573d73186128a19ec20821b056 100644 (file)
@@ -2,6 +2,8 @@
 # Arch-specific CryptoAPI modules.
 #
 
+obj-$(CONFIG_CRYPTO_FPU) += fpu.o
+
 obj-$(CONFIG_CRYPTO_AES_586) += aes-i586.o
 obj-$(CONFIG_CRYPTO_TWOFISH_586) += twofish-i586.o
 obj-$(CONFIG_CRYPTO_SALSA20_586) += salsa20-i586.o
index 02af0af65497a1d860052b97a25309f4a436dd2a..4e663398f77f8f4353904399f88ff3774036825a 100644 (file)
 #include <asm/i387.h>
 #include <asm/aes.h>
 
+#if defined(CONFIG_CRYPTO_CTR) || defined(CONFIG_CRYPTO_CTR_MODULE)
+#define HAS_CTR
+#endif
+
+#if defined(CONFIG_CRYPTO_LRW) || defined(CONFIG_CRYPTO_LRW_MODULE)
+#define HAS_LRW
+#endif
+
+#if defined(CONFIG_CRYPTO_PCBC) || defined(CONFIG_CRYPTO_PCBC_MODULE)
+#define HAS_PCBC
+#endif
+
+#if defined(CONFIG_CRYPTO_XTS) || defined(CONFIG_CRYPTO_XTS_MODULE)
+#define HAS_XTS
+#endif
+
 struct async_aes_ctx {
        struct cryptd_ablkcipher *cryptd_tfm;
 };
@@ -137,6 +153,41 @@ static struct crypto_alg aesni_alg = {
        }
 };
 
+static void __aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+       struct crypto_aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(tfm));
+
+       aesni_enc(ctx, dst, src);
+}
+
+static void __aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+       struct crypto_aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(tfm));
+
+       aesni_dec(ctx, dst, src);
+}
+
+static struct crypto_alg __aesni_alg = {
+       .cra_name               = "__aes-aesni",
+       .cra_driver_name        = "__driver-aes-aesni",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_CIPHER,
+       .cra_blocksize          = AES_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct crypto_aes_ctx)+AESNI_ALIGN-1,
+       .cra_alignmask          = 0,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(__aesni_alg.cra_list),
+       .cra_u  = {
+               .cipher = {
+                       .cia_min_keysize        = AES_MIN_KEY_SIZE,
+                       .cia_max_keysize        = AES_MAX_KEY_SIZE,
+                       .cia_setkey             = aes_set_key,
+                       .cia_encrypt            = __aes_encrypt,
+                       .cia_decrypt            = __aes_decrypt
+               }
+       }
+};
+
 static int ecb_encrypt(struct blkcipher_desc *desc,
                       struct scatterlist *dst, struct scatterlist *src,
                       unsigned int nbytes)
@@ -277,8 +328,16 @@ static int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key,
                        unsigned int key_len)
 {
        struct async_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+       struct crypto_ablkcipher *child = &ctx->cryptd_tfm->base;
+       int err;
 
-       return crypto_ablkcipher_setkey(&ctx->cryptd_tfm->base, key, key_len);
+       crypto_ablkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+       crypto_ablkcipher_set_flags(child, crypto_ablkcipher_get_flags(tfm)
+                                   & CRYPTO_TFM_REQ_MASK);
+       err = crypto_ablkcipher_setkey(child, key, key_len);
+       crypto_ablkcipher_set_flags(tfm, crypto_ablkcipher_get_flags(child)
+                                   & CRYPTO_TFM_RES_MASK);
+       return err;
 }
 
 static int ablk_encrypt(struct ablkcipher_request *req)
@@ -411,6 +470,163 @@ static struct crypto_alg ablk_cbc_alg = {
        },
 };
 
+#ifdef HAS_CTR
+static int ablk_ctr_init(struct crypto_tfm *tfm)
+{
+       struct cryptd_ablkcipher *cryptd_tfm;
+
+       cryptd_tfm = cryptd_alloc_ablkcipher("fpu(ctr(__driver-aes-aesni))",
+                                            0, 0);
+       if (IS_ERR(cryptd_tfm))
+               return PTR_ERR(cryptd_tfm);
+       ablk_init_common(tfm, cryptd_tfm);
+       return 0;
+}
+
+static struct crypto_alg ablk_ctr_alg = {
+       .cra_name               = "ctr(aes)",
+       .cra_driver_name        = "ctr-aes-aesni",
+       .cra_priority           = 400,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = 1,
+       .cra_ctxsize            = sizeof(struct async_aes_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(ablk_ctr_alg.cra_list),
+       .cra_init               = ablk_ctr_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = AES_MIN_KEY_SIZE,
+                       .max_keysize    = AES_MAX_KEY_SIZE,
+                       .ivsize         = AES_BLOCK_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = ablk_encrypt,
+                       .decrypt        = ablk_decrypt,
+                       .geniv          = "chainiv",
+               },
+       },
+};
+#endif
+
+#ifdef HAS_LRW
+static int ablk_lrw_init(struct crypto_tfm *tfm)
+{
+       struct cryptd_ablkcipher *cryptd_tfm;
+
+       cryptd_tfm = cryptd_alloc_ablkcipher("fpu(lrw(__driver-aes-aesni))",
+                                            0, 0);
+       if (IS_ERR(cryptd_tfm))
+               return PTR_ERR(cryptd_tfm);
+       ablk_init_common(tfm, cryptd_tfm);
+       return 0;
+}
+
+static struct crypto_alg ablk_lrw_alg = {
+       .cra_name               = "lrw(aes)",
+       .cra_driver_name        = "lrw-aes-aesni",
+       .cra_priority           = 400,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = AES_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct async_aes_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(ablk_lrw_alg.cra_list),
+       .cra_init               = ablk_lrw_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = AES_MIN_KEY_SIZE + AES_BLOCK_SIZE,
+                       .max_keysize    = AES_MAX_KEY_SIZE + AES_BLOCK_SIZE,
+                       .ivsize         = AES_BLOCK_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = ablk_encrypt,
+                       .decrypt        = ablk_decrypt,
+               },
+       },
+};
+#endif
+
+#ifdef HAS_PCBC
+static int ablk_pcbc_init(struct crypto_tfm *tfm)
+{
+       struct cryptd_ablkcipher *cryptd_tfm;
+
+       cryptd_tfm = cryptd_alloc_ablkcipher("fpu(pcbc(__driver-aes-aesni))",
+                                            0, 0);
+       if (IS_ERR(cryptd_tfm))
+               return PTR_ERR(cryptd_tfm);
+       ablk_init_common(tfm, cryptd_tfm);
+       return 0;
+}
+
+static struct crypto_alg ablk_pcbc_alg = {
+       .cra_name               = "pcbc(aes)",
+       .cra_driver_name        = "pcbc-aes-aesni",
+       .cra_priority           = 400,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = AES_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct async_aes_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(ablk_pcbc_alg.cra_list),
+       .cra_init               = ablk_pcbc_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = AES_MIN_KEY_SIZE,
+                       .max_keysize    = AES_MAX_KEY_SIZE,
+                       .ivsize         = AES_BLOCK_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = ablk_encrypt,
+                       .decrypt        = ablk_decrypt,
+               },
+       },
+};
+#endif
+
+#ifdef HAS_XTS
+static int ablk_xts_init(struct crypto_tfm *tfm)
+{
+       struct cryptd_ablkcipher *cryptd_tfm;
+
+       cryptd_tfm = cryptd_alloc_ablkcipher("fpu(xts(__driver-aes-aesni))",
+                                            0, 0);
+       if (IS_ERR(cryptd_tfm))
+               return PTR_ERR(cryptd_tfm);
+       ablk_init_common(tfm, cryptd_tfm);
+       return 0;
+}
+
+static struct crypto_alg ablk_xts_alg = {
+       .cra_name               = "xts(aes)",
+       .cra_driver_name        = "xts-aes-aesni",
+       .cra_priority           = 400,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = AES_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct async_aes_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(ablk_xts_alg.cra_list),
+       .cra_init               = ablk_xts_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = 2 * AES_MIN_KEY_SIZE,
+                       .max_keysize    = 2 * AES_MAX_KEY_SIZE,
+                       .ivsize         = AES_BLOCK_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = ablk_encrypt,
+                       .decrypt        = ablk_decrypt,
+               },
+       },
+};
+#endif
+
 static int __init aesni_init(void)
 {
        int err;
@@ -421,6 +637,8 @@ static int __init aesni_init(void)
        }
        if ((err = crypto_register_alg(&aesni_alg)))
                goto aes_err;
+       if ((err = crypto_register_alg(&__aesni_alg)))
+               goto __aes_err;
        if ((err = crypto_register_alg(&blk_ecb_alg)))
                goto blk_ecb_err;
        if ((err = crypto_register_alg(&blk_cbc_alg)))
@@ -429,9 +647,41 @@ static int __init aesni_init(void)
                goto ablk_ecb_err;
        if ((err = crypto_register_alg(&ablk_cbc_alg)))
                goto ablk_cbc_err;
+#ifdef HAS_CTR
+       if ((err = crypto_register_alg(&ablk_ctr_alg)))
+               goto ablk_ctr_err;
+#endif
+#ifdef HAS_LRW
+       if ((err = crypto_register_alg(&ablk_lrw_alg)))
+               goto ablk_lrw_err;
+#endif
+#ifdef HAS_PCBC
+       if ((err = crypto_register_alg(&ablk_pcbc_alg)))
+               goto ablk_pcbc_err;
+#endif
+#ifdef HAS_XTS
+       if ((err = crypto_register_alg(&ablk_xts_alg)))
+               goto ablk_xts_err;
+#endif
 
        return err;
 
+#ifdef HAS_XTS
+ablk_xts_err:
+#endif
+#ifdef HAS_PCBC
+       crypto_unregister_alg(&ablk_pcbc_alg);
+ablk_pcbc_err:
+#endif
+#ifdef HAS_LRW
+       crypto_unregister_alg(&ablk_lrw_alg);
+ablk_lrw_err:
+#endif
+#ifdef HAS_CTR
+       crypto_unregister_alg(&ablk_ctr_alg);
+ablk_ctr_err:
+#endif
+       crypto_unregister_alg(&ablk_cbc_alg);
 ablk_cbc_err:
        crypto_unregister_alg(&ablk_ecb_alg);
 ablk_ecb_err:
@@ -439,6 +689,8 @@ ablk_ecb_err:
 blk_cbc_err:
        crypto_unregister_alg(&blk_ecb_alg);
 blk_ecb_err:
+       crypto_unregister_alg(&__aesni_alg);
+__aes_err:
        crypto_unregister_alg(&aesni_alg);
 aes_err:
        return err;
@@ -446,10 +698,23 @@ aes_err:
 
 static void __exit aesni_exit(void)
 {
+#ifdef HAS_XTS
+       crypto_unregister_alg(&ablk_xts_alg);
+#endif
+#ifdef HAS_PCBC
+       crypto_unregister_alg(&ablk_pcbc_alg);
+#endif
+#ifdef HAS_LRW
+       crypto_unregister_alg(&ablk_lrw_alg);
+#endif
+#ifdef HAS_CTR
+       crypto_unregister_alg(&ablk_ctr_alg);
+#endif
        crypto_unregister_alg(&ablk_cbc_alg);
        crypto_unregister_alg(&ablk_ecb_alg);
        crypto_unregister_alg(&blk_cbc_alg);
        crypto_unregister_alg(&blk_ecb_alg);
+       crypto_unregister_alg(&__aesni_alg);
        crypto_unregister_alg(&aesni_alg);
 }
 
diff --git a/arch/x86/crypto/fpu.c b/arch/x86/crypto/fpu.c
new file mode 100644 (file)
index 0000000..5f9781a
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * FPU: Wrapper for blkcipher touching fpu
+ *
+ * Copyright (c) Intel Corp.
+ *   Author: Huang Ying <ying.huang@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+
+#include <crypto/algapi.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/i387.h>
+
+struct crypto_fpu_ctx {
+       struct crypto_blkcipher *child;
+};
+
+static int crypto_fpu_setkey(struct crypto_tfm *parent, const u8 *key,
+                            unsigned int keylen)
+{
+       struct crypto_fpu_ctx *ctx = crypto_tfm_ctx(parent);
+       struct crypto_blkcipher *child = ctx->child;
+       int err;
+
+       crypto_blkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+       crypto_blkcipher_set_flags(child, crypto_tfm_get_flags(parent) &
+                                  CRYPTO_TFM_REQ_MASK);
+       err = crypto_blkcipher_setkey(child, key, keylen);
+       crypto_tfm_set_flags(parent, crypto_blkcipher_get_flags(child) &
+                                    CRYPTO_TFM_RES_MASK);
+       return err;
+}
+
+static int crypto_fpu_encrypt(struct blkcipher_desc *desc_in,
+                             struct scatterlist *dst, struct scatterlist *src,
+                             unsigned int nbytes)
+{
+       int err;
+       struct crypto_fpu_ctx *ctx = crypto_blkcipher_ctx(desc_in->tfm);
+       struct crypto_blkcipher *child = ctx->child;
+       struct blkcipher_desc desc = {
+               .tfm = child,
+               .info = desc_in->info,
+               .flags = desc_in->flags,
+       };
+
+       kernel_fpu_begin();
+       err = crypto_blkcipher_crt(desc.tfm)->encrypt(&desc, dst, src, nbytes);
+       kernel_fpu_end();
+       return err;
+}
+
+static int crypto_fpu_decrypt(struct blkcipher_desc *desc_in,
+                             struct scatterlist *dst, struct scatterlist *src,
+                             unsigned int nbytes)
+{
+       int err;
+       struct crypto_fpu_ctx *ctx = crypto_blkcipher_ctx(desc_in->tfm);
+       struct crypto_blkcipher *child = ctx->child;
+       struct blkcipher_desc desc = {
+               .tfm = child,
+               .info = desc_in->info,
+               .flags = desc_in->flags,
+       };
+
+       kernel_fpu_begin();
+       err = crypto_blkcipher_crt(desc.tfm)->decrypt(&desc, dst, src, nbytes);
+       kernel_fpu_end();
+       return err;
+}
+
+static int crypto_fpu_init_tfm(struct crypto_tfm *tfm)
+{
+       struct crypto_instance *inst = crypto_tfm_alg_instance(tfm);
+       struct crypto_spawn *spawn = crypto_instance_ctx(inst);
+       struct crypto_fpu_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct crypto_blkcipher *cipher;
+
+       cipher = crypto_spawn_blkcipher(spawn);
+       if (IS_ERR(cipher))
+               return PTR_ERR(cipher);
+
+       ctx->child = cipher;
+       return 0;
+}
+
+static void crypto_fpu_exit_tfm(struct crypto_tfm *tfm)
+{
+       struct crypto_fpu_ctx *ctx = crypto_tfm_ctx(tfm);
+       crypto_free_blkcipher(ctx->child);
+}
+
+static struct crypto_instance *crypto_fpu_alloc(struct rtattr **tb)
+{
+       struct crypto_instance *inst;
+       struct crypto_alg *alg;
+       int err;
+
+       err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER);
+       if (err)
+               return ERR_PTR(err);
+
+       alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_BLKCIPHER,
+                                 CRYPTO_ALG_TYPE_MASK);
+       if (IS_ERR(alg))
+               return ERR_CAST(alg);
+
+       inst = crypto_alloc_instance("fpu", alg);
+       if (IS_ERR(inst))
+               goto out_put_alg;
+
+       inst->alg.cra_flags = alg->cra_flags;
+       inst->alg.cra_priority = alg->cra_priority;
+       inst->alg.cra_blocksize = alg->cra_blocksize;
+       inst->alg.cra_alignmask = alg->cra_alignmask;
+       inst->alg.cra_type = alg->cra_type;
+       inst->alg.cra_blkcipher.ivsize = alg->cra_blkcipher.ivsize;
+       inst->alg.cra_blkcipher.min_keysize = alg->cra_blkcipher.min_keysize;
+       inst->alg.cra_blkcipher.max_keysize = alg->cra_blkcipher.max_keysize;
+       inst->alg.cra_ctxsize = sizeof(struct crypto_fpu_ctx);
+       inst->alg.cra_init = crypto_fpu_init_tfm;
+       inst->alg.cra_exit = crypto_fpu_exit_tfm;
+       inst->alg.cra_blkcipher.setkey = crypto_fpu_setkey;
+       inst->alg.cra_blkcipher.encrypt = crypto_fpu_encrypt;
+       inst->alg.cra_blkcipher.decrypt = crypto_fpu_decrypt;
+
+out_put_alg:
+       crypto_mod_put(alg);
+       return inst;
+}
+
+static void crypto_fpu_free(struct crypto_instance *inst)
+{
+       crypto_drop_spawn(crypto_instance_ctx(inst));
+       kfree(inst);
+}
+
+static struct crypto_template crypto_fpu_tmpl = {
+       .name = "fpu",
+       .alloc = crypto_fpu_alloc,
+       .free = crypto_fpu_free,
+       .module = THIS_MODULE,
+};
+
+static int __init crypto_fpu_module_init(void)
+{
+       return crypto_register_template(&crypto_fpu_tmpl);
+}
+
+static void __exit crypto_fpu_module_exit(void)
+{
+       crypto_unregister_template(&crypto_fpu_tmpl);
+}
+
+module_init(crypto_fpu_module_init);
+module_exit(crypto_fpu_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("FPU block cipher wrapper");
index aff9f1fcdcd7e2be9d86049fc7f9522bafd4b35d..8cb9c814e1203a0b7434018392e2ee01ef3ca199 100644 (file)
@@ -483,5 +483,5 @@ atomic64_add_negative(unsigned long long delta, atomic64_t *ptr)
        return old_val < 0;
 }
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* _ASM_X86_ATOMIC_32_H */
index 8c21731984daacec35c6df87071b3b94b758c4ca..0d6360220007b2bc3a35952a7fa4830c837ad4af 100644 (file)
@@ -455,5 +455,5 @@ static inline void atomic_or_long(unsigned long *v1, unsigned long v2)
 #define smp_mb__before_atomic_inc()    barrier()
 #define smp_mb__after_atomic_inc()     barrier()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* _ASM_X86_ATOMIC_64_H */
diff --git a/arch/x86/include/asm/bitsperlong.h b/arch/x86/include/asm/bitsperlong.h
new file mode 100644 (file)
index 0000000..b0ae1c4
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __ASM_X86_BITSPERLONG_H
+#define __ASM_X86_BITSPERLONG_H
+
+#ifdef __x86_64__
+# define __BITS_PER_LONG 64
+#else
+# define __BITS_PER_LONG 32
+#endif
+
+#include <asm-generic/bitsperlong.h>
+
+#endif /* __ASM_X86_BITSPERLONG_H */
+
index d750a10ccad663fe0e8cd5df1d5e5778e12e0d90..ff8cbfa07851a1b2ce121f70b84e4d4269331dfb 100644 (file)
@@ -14,6 +14,7 @@ BUILD_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR)
 BUILD_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR)
 BUILD_INTERRUPT(call_function_single_interrupt,CALL_FUNCTION_SINGLE_VECTOR)
 BUILD_INTERRUPT(irq_move_cleanup_interrupt,IRQ_MOVE_CLEANUP_VECTOR)
+BUILD_INTERRUPT(reboot_interrupt,REBOOT_VECTOR)
 
 BUILD_INTERRUPT3(invalidate_interrupt0,INVALIDATE_TLB_VECTOR_START+0,
                 smp_invalidate_interrupt)
@@ -52,8 +53,16 @@ BUILD_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR)
 BUILD_INTERRUPT(perf_pending_interrupt, LOCAL_PENDING_VECTOR)
 #endif
 
-#ifdef CONFIG_X86_MCE_P4THERMAL
+#ifdef CONFIG_X86_THERMAL_VECTOR
 BUILD_INTERRUPT(thermal_interrupt,THERMAL_APIC_VECTOR)
 #endif
 
+#ifdef CONFIG_X86_MCE_THRESHOLD
+BUILD_INTERRUPT(threshold_interrupt,THRESHOLD_APIC_VECTOR)
+#endif
+
+#ifdef CONFIG_X86_NEW_MCE
+BUILD_INTERRUPT(mce_self_interrupt,MCE_SELF_VECTOR)
+#endif
+
 #endif
index 9ebc5c2550327ed26ab88e5647fbc09833194d07..82e3e8f010439cde125a3a75c4f0d65a7068b573 100644 (file)
@@ -22,7 +22,7 @@ typedef struct {
 #endif
 #ifdef CONFIG_X86_MCE
        unsigned int irq_thermal_count;
-# ifdef CONFIG_X86_64
+# ifdef CONFIG_X86_MCE_THRESHOLD
        unsigned int irq_threshold_count;
 # endif
 #endif
index 6df45f639666f4be9ccb3792fc893fc48791871b..ba180d93b08c3200a4d2d717dda6fdc5aceef70a 100644 (file)
@@ -34,6 +34,7 @@ extern void perf_pending_interrupt(void);
 extern void spurious_interrupt(void);
 extern void thermal_interrupt(void);
 extern void reschedule_interrupt(void);
+extern void mce_self_interrupt(void);
 
 extern void invalidate_interrupt(void);
 extern void invalidate_interrupt0(void);
@@ -46,6 +47,7 @@ extern void invalidate_interrupt6(void);
 extern void invalidate_interrupt7(void);
 
 extern void irq_move_cleanup_interrupt(void);
+extern void reboot_interrupt(void);
 extern void threshold_interrupt(void);
 
 extern void call_function_interrupt(void);
index e997be98c9b97c166b1b484f5a53b8f171f95b47..5b21f0ec3df258110ce1db5bad0f568577cbb34e 100644 (file)
@@ -25,6 +25,7 @@
  */
 
 #define NMI_VECTOR                     0x02
+#define MCE_VECTOR                     0x12
 
 /*
  * IDT vectors usable for external interrupt sources start
 #define CALL_FUNCTION_VECTOR           0xfc
 #define CALL_FUNCTION_SINGLE_VECTOR    0xfb
 #define THERMAL_APIC_VECTOR            0xfa
-
-#ifdef CONFIG_X86_32
-/* 0xf8 - 0xf9 : free */
-#else
-# define THRESHOLD_APIC_VECTOR         0xf9
-# define UV_BAU_MESSAGE                        0xf8
-#endif
+#define THRESHOLD_APIC_VECTOR          0xf9
+#define REBOOT_VECTOR                  0xf8
 
 /* f0-f7 used for spreading out TLB flushes: */
 #define INVALIDATE_TLB_VECTOR_END      0xf7
  */
 #define LOCAL_PENDING_VECTOR           0xec
 
+#define UV_BAU_MESSAGE                 0xec
+
+/*
+ * Self IPI vector for machine checks
+ */
+#define MCE_SELF_VECTOR                        0xeb
+
 /*
  * First APIC vector available to drivers: (vectors 0x30-0xee) we
  * start at 0x31(0x41) to spread out vectors evenly between priority
index 1caf57628b9c8c750dccbf2e8d60c29a250b39c9..313389cd50d2a3dfe1285152b2d43645e40f7636 100644 (file)
 /* Pages for switcher itself, then two pages per cpu */
 #define TOTAL_SWITCHER_PAGES (SHARED_SWITCHER_PAGES + 2 * nr_cpu_ids)
 
-/* We map at -4M for ease of mapping into the guest (one PTE page). */
+/* We map at -4M (-2M when PAE is activated) for ease of mapping
+ * into the guest (one PTE page). */
+#ifdef CONFIG_X86_PAE
+#define SWITCHER_ADDR 0xFFE00000
+#else
 #define SWITCHER_ADDR 0xFFC00000
+#endif
 
 /* Found in switcher.S */
 extern unsigned long default_idt_entries[];
index faae1996487b7208b6314fd922f5e84a5cf9be4a..d31c4a684078080ebe48fbc4d90ebd7f67dce568 100644 (file)
 #define LHCALL_TS              8
 #define LHCALL_SET_CLOCKEVENT  9
 #define LHCALL_HALT            10
+#define LHCALL_SET_PMD         13
 #define LHCALL_SET_PTE         14
-#define LHCALL_SET_PMD         15
+#define LHCALL_SET_PGD         15
 #define LHCALL_LOAD_TLS                16
 #define LHCALL_NOTIFY          17
 #define LHCALL_LOAD_GDT_ENTRY  18
+#define LHCALL_SEND_INTERRUPTS 19
 
 #define LGUEST_TRAP_ENTRY 0x1F
 
  * operations?  There are two ways: the direct way is to make a "hypercall",
  * to make requests of the Host Itself.
  *
- * We use the KVM hypercall mechanism. Eighteen hypercalls are
+ * We use the KVM hypercall mechanism. Seventeen hypercalls are
  * available: the hypercall number is put in the %eax register, and the
- * arguments (when required) are placed in %ebx, %ecx and %edx.  If a return
- * value makes sense, it's returned in %eax.
+ * arguments (when required) are placed in %ebx, %ecx, %edx and %esi.
+ * If a return value makes sense, it's returned in %eax.
  *
  * Grossly invalid calls result in Sudden Death at the hands of the vengeful
  * Host, rather than returning failure.  This reflects Winston Churchill's
@@ -47,8 +49,9 @@
 
 #define LHCALL_RING_SIZE 64
 struct hcall_args {
-       /* These map directly onto eax, ebx, ecx, edx in struct lguest_regs */
-       unsigned long arg0, arg1, arg2, arg3;
+       /* These map directly onto eax, ebx, ecx, edx and esi
+        * in struct lguest_regs */
+       unsigned long arg0, arg1, arg2, arg3, arg4;
 };
 
 #endif /* !__ASSEMBLY__ */
index 4f8c199584e748c8075a1fd4c344f7af9d33688e..540a466e50f52860f410c831d293f57c63120a2d 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef _ASM_X86_MCE_H
 #define _ASM_X86_MCE_H
 
-#ifdef __x86_64__
-
 #include <linux/types.h>
 #include <asm/ioctls.h>
 
  * Machine Check support for x86
  */
 
-#define MCG_CTL_P       (1UL<<8)   /* MCG_CAP register available */
-#define MCG_EXT_P       (1ULL<<9)   /* Extended registers available */
-#define MCG_CMCI_P      (1ULL<<10)  /* CMCI supported */
-
-#define MCG_STATUS_RIPV  (1UL<<0)   /* restart ip valid */
-#define MCG_STATUS_EIPV  (1UL<<1)   /* ip points to correct instruction */
-#define MCG_STATUS_MCIP  (1UL<<2)   /* machine check in progress */
-
-#define MCI_STATUS_VAL   (1UL<<63)  /* valid error */
-#define MCI_STATUS_OVER  (1UL<<62)  /* previous errors lost */
-#define MCI_STATUS_UC    (1UL<<61)  /* uncorrected error */
-#define MCI_STATUS_EN    (1UL<<60)  /* error enabled */
-#define MCI_STATUS_MISCV (1UL<<59)  /* misc error reg. valid */
-#define MCI_STATUS_ADDRV (1UL<<58)  /* addr reg. valid */
-#define MCI_STATUS_PCC   (1UL<<57)  /* processor context corrupt */
+#define MCG_BANKCNT_MASK       0xff         /* Number of Banks */
+#define MCG_CTL_P              (1ULL<<8)    /* MCG_CAP register available */
+#define MCG_EXT_P              (1ULL<<9)    /* Extended registers available */
+#define MCG_CMCI_P             (1ULL<<10)   /* CMCI supported */
+#define MCG_EXT_CNT_MASK       0xff0000     /* Number of Extended registers */
+#define MCG_EXT_CNT_SHIFT      16
+#define MCG_EXT_CNT(c)         (((c) & MCG_EXT_CNT_MASK) >> MCG_EXT_CNT_SHIFT)
+#define MCG_SER_P              (1ULL<<24)   /* MCA recovery/new status bits */
+
+#define MCG_STATUS_RIPV  (1ULL<<0)   /* restart ip valid */
+#define MCG_STATUS_EIPV  (1ULL<<1)   /* ip points to correct instruction */
+#define MCG_STATUS_MCIP  (1ULL<<2)   /* machine check in progress */
+
+#define MCI_STATUS_VAL   (1ULL<<63)  /* valid error */
+#define MCI_STATUS_OVER  (1ULL<<62)  /* previous errors lost */
+#define MCI_STATUS_UC    (1ULL<<61)  /* uncorrected error */
+#define MCI_STATUS_EN    (1ULL<<60)  /* error enabled */
+#define MCI_STATUS_MISCV (1ULL<<59)  /* misc error reg. valid */
+#define MCI_STATUS_ADDRV (1ULL<<58)  /* addr reg. valid */
+#define MCI_STATUS_PCC   (1ULL<<57)  /* processor context corrupt */
+#define MCI_STATUS_S    (1ULL<<56)  /* Signaled machine check */
+#define MCI_STATUS_AR   (1ULL<<55)  /* Action required */
+
+/* MISC register defines */
+#define MCM_ADDR_SEGOFF  0     /* segment offset */
+#define MCM_ADDR_LINEAR  1     /* linear address */
+#define MCM_ADDR_PHYS   2      /* physical address */
+#define MCM_ADDR_MEM    3      /* memory address */
+#define MCM_ADDR_GENERIC 7     /* generic */
 
 /* Fields are zero when not available */
 struct mce {
@@ -34,13 +46,19 @@ struct mce {
        __u64 mcgstatus;
        __u64 ip;
        __u64 tsc;      /* cpu time stamp counter */
-       __u64 res1;     /* for future extension */
-       __u64 res2;     /* dito. */
+       __u64 time;     /* wall time_t when error was detected */
+       __u8  cpuvendor;        /* cpu vendor as encoded in system.h */
+       __u8  pad1;
+       __u16 pad2;
+       __u32 cpuid;    /* CPUID 1 EAX */
        __u8  cs;               /* code segment */
        __u8  bank;     /* machine check bank */
-       __u8  cpu;      /* cpu that raised the error */
+       __u8  cpu;      /* cpu number; obsolete; use extcpu now */
        __u8  finished;   /* entry is valid */
-       __u32 pad;
+       __u32 extcpu;   /* linux cpu number that detected the error */
+       __u32 socketid; /* CPU socket ID */
+       __u32 apicid;   /* CPU initial apic ID */
+       __u64 mcgcap;   /* MCGCAP MSR: machine check capabilities of CPU */
 };
 
 /*
@@ -57,7 +75,7 @@ struct mce_log {
        unsigned len;       /* = MCE_LOG_LEN */
        unsigned next;
        unsigned flags;
-       unsigned pad0;
+       unsigned recordlen;     /* length of struct mce */
        struct mce entry[MCE_LOG_LEN];
 };
 
@@ -82,19 +100,16 @@ 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)
 
-#endif /* __x86_64__ */
-
 #ifdef __KERNEL__
 
-#ifdef CONFIG_X86_32
 extern int mce_disabled;
-#else /* CONFIG_X86_32 */
 
 #include <asm/atomic.h>
+#include <linux/percpu.h>
 
 void mce_setup(struct mce *m);
 void mce_log(struct mce *m);
-DECLARE_PER_CPU(struct sys_device, device_mce);
+DECLARE_PER_CPU(struct sys_device, mce_dev);
 extern void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu);
 
 /*
@@ -104,6 +119,8 @@ extern void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu);
 #define MAX_NR_BANKS (MCE_EXTENDED_BANK - 1)
 
 #ifdef CONFIG_X86_MCE_INTEL
+extern int mce_cmci_disabled;
+extern int mce_ignore_ce;
 void mce_intel_feature_init(struct cpuinfo_x86 *c);
 void cmci_clear(void);
 void cmci_reenable(void);
@@ -123,13 +140,16 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c);
 static inline void mce_amd_feature_init(struct cpuinfo_x86 *c) { }
 #endif
 
-extern int mce_available(struct cpuinfo_x86 *c);
+int mce_available(struct cpuinfo_x86 *c);
+
+DECLARE_PER_CPU(unsigned, mce_exception_count);
+DECLARE_PER_CPU(unsigned, mce_poll_count);
 
 void mce_log_therm_throt_event(__u64 status);
 
 extern atomic_t mce_entry;
 
-extern void do_machine_check(struct pt_regs *, long);
+void do_machine_check(struct pt_regs *, long);
 
 typedef DECLARE_BITMAP(mce_banks_t, MAX_NR_BANKS);
 DECLARE_PER_CPU(mce_banks_t, mce_poll_banks);
@@ -139,14 +159,16 @@ enum mcp_flags {
        MCP_UC = (1 << 1),              /* log uncorrected errors */
        MCP_DONTLOG = (1 << 2),         /* only clear, don't log */
 };
-extern void machine_check_poll(enum mcp_flags flags, mce_banks_t *b);
+void machine_check_poll(enum mcp_flags flags, mce_banks_t *b);
 
-extern int mce_notify_user(void);
+int mce_notify_irq(void);
+void mce_notify_process(void);
 
-#endif /* !CONFIG_X86_32 */
+DECLARE_PER_CPU(struct mce, injectm);
+extern struct file_operations mce_chrdev_ops;
 
 #ifdef CONFIG_X86_MCE
-extern void mcheck_init(struct cpuinfo_x86 *c);
+void mcheck_init(struct cpuinfo_x86 *c);
 #else
 #define mcheck_init(c) do { } while (0)
 #endif
index 90bc4108a4fdf917fc243502bd7fcf833f482a55..751af2550ed95befecc593c80343f20035f14bb4 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef _ASM_X86_MMAN_H
 #define _ASM_X86_MMAN_H
 
-#include <asm-generic/mman.h>
+#include <asm-generic/mman-common.h>
 
 #define MAP_32BIT      0x40            /* only give out 32bit addresses */
 
index 4d58d04fca830bc56ab8bf62009661ad77a85f3e..1692fb5050e35e010e904c54043576ff83cff746 100644 (file)
 
 #define MSR_IA32_THERM_CONTROL         0x0000019a
 #define MSR_IA32_THERM_INTERRUPT       0x0000019b
+
+#define THERM_INT_LOW_ENABLE           (1 << 0)
+#define THERM_INT_HIGH_ENABLE          (1 << 1)
+
 #define MSR_IA32_THERM_STATUS          0x0000019c
+
+#define THERM_STATUS_PROCHOT           (1 << 0)
+
 #define MSR_IA32_MISC_ENABLE           0x000001a0
 
 /* MISC_ENABLE bits: architectural */
index 89ed9d70b0aa6b65158b22b536677429281ea46b..625c3f0e741aab7bd75d839cadf7084c303baa61 100644 (file)
@@ -56,7 +56,7 @@ extern bool __virt_addr_valid(unsigned long kaddr);
 #endif /* __ASSEMBLY__ */
 
 #include <asm-generic/memory_model.h>
-#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
 
 #define __HAVE_ARCH_GATE_AREA 1
 
index 2733fad45f989bfd5a775c99e5decb35cfe8014a..5e67c15323145753d29894eb43c4c29f0343f38e 100644 (file)
@@ -46,6 +46,10 @@ extern bool __vmalloc_start_set; /* set once high_memory is set */
 # define VMALLOC_END   (FIXADDR_START - 2 * PAGE_SIZE)
 #endif
 
+#define MODULES_VADDR  VMALLOC_START
+#define MODULES_END    VMALLOC_END
+#define MODULES_LEN    (MODULES_VADDR - MODULES_END)
+
 #define MAXMEM (VMALLOC_END - PAGE_OFFSET - __VMALLOC_RESERVE)
 
 #endif /* _ASM_X86_PGTABLE_32_DEFS_H */
index 7761a5d554bb2eb567024375b5bb3c083991946f..598457cbd0f80c47e4cf7759e8d3b6c5de048f06 100644 (file)
@@ -117,7 +117,7 @@ typedef unsigned long sigset_t;
 #define MINSIGSTKSZ    2048
 #define SIGSTKSZ       8192
 
-#include <asm-generic/signal.h>
+#include <asm-generic/signal-defs.h>
 
 #ifndef __ASSEMBLY__
 
index a5ecc9c33e920eda5e50bcfe0313b333b1b2cd31..7f3eba08e7de988dfe85affb84495b59bf0e6a0d 100644 (file)
@@ -172,6 +172,6 @@ static inline void flush_tlb_kernel_range(unsigned long start,
        flush_tlb_all();
 }
 
-extern void zap_low_mappings(void);
+extern void zap_low_mappings(bool early);
 
 #endif /* _ASM_X86_TLBFLUSH_H */
index e6f7363200773e13f94b02ef53a8dab57d974bef..09b97745772f134532d869fd2f9565ec8633b29b 100644 (file)
@@ -14,12 +14,6 @@ typedef unsigned short umode_t;
  */
 #ifdef __KERNEL__
 
-#ifdef CONFIG_X86_32
-# define BITS_PER_LONG 32
-#else
-# define BITS_PER_LONG 64
-#endif
-
 #ifndef __ASSEMBLY__
 
 typedef u64 dma64_addr_t;
index 4f78bd682125067c07fbf9c11a1b1bc1c40a2dd6..f3477bb845660c51e30a5000c5989831529bad17 100644 (file)
@@ -73,7 +73,7 @@ obj-$(CONFIG_KEXEC)           += machine_kexec_$(BITS).o
 obj-$(CONFIG_KEXEC)            += relocate_kernel_$(BITS).o crash.o
 obj-$(CONFIG_CRASH_DUMP)       += crash_dump_$(BITS).o
 obj-$(CONFIG_KPROBES)          += kprobes.o
-obj-$(CONFIG_MODULES)          += module_$(BITS).o
+obj-$(CONFIG_MODULES)          += module.o
 obj-$(CONFIG_EFI)              += efi.o efi_$(BITS).o efi_stub_$(BITS).o
 obj-$(CONFIG_DOUBLEFAULT)      += doublefault_32.o
 obj-$(CONFIG_KGDB)             += kgdb.o
index 7c243a2c5115dfa6653d7a4fec05d6521eb5ef4f..ca93638ba4309b3e90085ee3d49e5ce81568501e 100644 (file)
@@ -104,7 +104,7 @@ int acpi_save_state_mem(void)
        initial_gs = per_cpu_offset(smp_processor_id());
 #endif
        initial_code = (unsigned long)wakeup_long64;
-       saved_magic = 0x123456789abcdef0;
+       saved_magic = 0x123456789abcdef0L;
 #endif /* CONFIG_64BIT */
 
        return 0;
index 076d3881f3da11d5e18f1bcabc079e1192f935c2..8c7c042ecad1eeb406caa0b5fa6605f7d6c7a04a 100644 (file)
@@ -899,7 +899,7 @@ void clear_local_APIC(void)
        }
 
        /* lets not touch this if we didn't frob it */
-#if defined(CONFIG_X86_MCE_P4THERMAL) || defined(CONFIG_X86_MCE_INTEL)
+#ifdef CONFIG_X86_THERMAL_VECTOR
        if (maxlvt >= 5) {
                v = apic_read(APIC_LVTTHMR);
                apic_write(APIC_LVTTHMR, v | APIC_LVT_MASKED);
@@ -2017,7 +2017,7 @@ static int lapic_suspend(struct sys_device *dev, pm_message_t state)
        apic_pm_state.apic_lvterr = apic_read(APIC_LVTERR);
        apic_pm_state.apic_tmict = apic_read(APIC_TMICT);
        apic_pm_state.apic_tdcr = apic_read(APIC_TDCR);
-#if defined(CONFIG_X86_MCE_P4THERMAL) || defined(CONFIG_X86_MCE_INTEL)
+#ifdef CONFIG_X86_THERMAL_VECTOR
        if (maxlvt >= 5)
                apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR);
 #endif
index a691302dc3ffa4e5e4771df1fedf17919d7133c6..b3025b43b63a93053b0318574d06498b685c2607 100644 (file)
@@ -66,7 +66,7 @@ static inline unsigned int get_nmi_count(int cpu)
 
 static inline int mce_in_progress(void)
 {
-#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE)
+#if defined(CONFIG_X86_NEW_MCE)
        return atomic_read(&mce_entry) > 0;
 #endif
        return 0;
index 49e0939bac4211ba35f32240af5e92ed905ec578..79302e9a33a43322eea70cc2f69f019426b69847 100644 (file)
@@ -1233,9 +1233,9 @@ static int suspend(int vetoable)
        int err;
        struct apm_user *as;
 
-       device_suspend(PMSG_SUSPEND);
+       dpm_suspend_start(PMSG_SUSPEND);
 
-       device_power_down(PMSG_SUSPEND);
+       dpm_suspend_noirq(PMSG_SUSPEND);
 
        local_irq_disable();
        sysdev_suspend(PMSG_SUSPEND);
@@ -1259,9 +1259,9 @@ static int suspend(int vetoable)
        sysdev_resume();
        local_irq_enable();
 
-       device_power_up(PMSG_RESUME);
+       dpm_resume_noirq(PMSG_RESUME);
 
-       device_resume(PMSG_RESUME);
+       dpm_resume_end(PMSG_RESUME);
        queue_event(APM_NORMAL_RESUME, NULL);
        spin_lock(&user_list_lock);
        for (as = user_list; as != NULL; as = as->next) {
@@ -1277,7 +1277,7 @@ static void standby(void)
 {
        int err;
 
-       device_power_down(PMSG_SUSPEND);
+       dpm_suspend_noirq(PMSG_SUSPEND);
 
        local_irq_disable();
        sysdev_suspend(PMSG_SUSPEND);
@@ -1291,7 +1291,7 @@ static void standby(void)
        sysdev_resume();
        local_irq_enable();
 
-       device_power_up(PMSG_RESUME);
+       dpm_resume_noirq(PMSG_RESUME);
 }
 
 static apm_event_t get_event(void)
@@ -1376,7 +1376,7 @@ static void check_events(void)
                        ignore_bounce = 1;
                        if ((event != APM_NORMAL_RESUME)
                            || (ignore_normal_resume == 0)) {
-                               device_resume(PMSG_RESUME);
+                               dpm_resume_end(PMSG_RESUME);
                                queue_event(event, NULL);
                        }
                        ignore_normal_resume = 0;
index 1a830cbd70153b8662eddf16a87a5336c6cb0742..dfdbf640389536489f5ac05b3258361d133d76d8 100644 (file)
@@ -126,6 +126,7 @@ void foo(void)
 #if defined(CONFIG_LGUEST) || defined(CONFIG_LGUEST_GUEST) || defined(CONFIG_LGUEST_MODULE)
        BLANK();
        OFFSET(LGUEST_DATA_irq_enabled, lguest_data, irq_enabled);
+       OFFSET(LGUEST_DATA_irq_pending, lguest_data, irq_pending);
        OFFSET(LGUEST_DATA_pgdir, lguest_data, pgdir);
 
        BLANK();
index b2f89829bbe824d2cecfd74d8c09b2923406493b..45004faf67ea700419845d66d90070dd98d645db 100644 (file)
@@ -1,7 +1,11 @@
-obj-y                          =  mce_$(BITS).o therm_throt.o
+obj-y                          =  mce.o therm_throt.o
 
-obj-$(CONFIG_X86_32)           += k7.o p4.o p5.o p6.o winchip.o
-obj-$(CONFIG_X86_MCE_INTEL)    += mce_intel_64.o
+obj-$(CONFIG_X86_NEW_MCE)      += mce-severity.o
+obj-$(CONFIG_X86_OLD_MCE)      += k7.o p4.o p6.o
+obj-$(CONFIG_X86_ANCIENT_MCE)  += winchip.o p5.o
+obj-$(CONFIG_X86_MCE_P4THERMAL)        += mce_intel.o
+obj-$(CONFIG_X86_MCE_INTEL)    += mce_intel_64.o mce_intel.o
 obj-$(CONFIG_X86_MCE_AMD)      += mce_amd_64.o
 obj-$(CONFIG_X86_MCE_NONFATAL) += non-fatal.o
 obj-$(CONFIG_X86_MCE_THRESHOLD) += threshold.o
+obj-$(CONFIG_X86_MCE_INJECT)   += mce-inject.o
index dd3af6e7b39a078835abd589feeaeee0b6184907..89e51042415266bed84f165b5eb74e02575092df 100644 (file)
@@ -2,11 +2,10 @@
  * Athlon specific Machine Check Exception Reporting
  * (C) Copyright 2002 Dave Jones <davej@redhat.com>
  */
-
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
 #include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
 #include <linux/smp.h>
 
 #include <asm/processor.h>
 
 #include "mce.h"
 
-/* Machine Check Handler For AMD Athlon/Duron */
+/* Machine Check Handler For AMD Athlon/Duron: */
 static void k7_machine_check(struct pt_regs *regs, long error_code)
 {
-       int recover = 1;
        u32 alow, ahigh, high, low;
        u32 mcgstl, mcgsth;
+       int recover = 1;
        int i;
 
        rdmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
@@ -32,15 +31,19 @@ static void k7_machine_check(struct pt_regs *regs, long error_code)
 
        for (i = 1; i < nr_mce_banks; i++) {
                rdmsr(MSR_IA32_MC0_STATUS+i*4, low, high);
-               if (high&(1<<31)) {
+               if (high & (1<<31)) {
                        char misc[20];
                        char addr[24];
-                       misc[0] = addr[0] = '\0';
+
+                       misc[0] = '\0';
+                       addr[0] = '\0';
+
                        if (high & (1<<29))
                                recover |= 1;
                        if (high & (1<<25))
                                recover |= 2;
                        high &= ~(1<<31);
+
                        if (high & (1<<27)) {
                                rdmsr(MSR_IA32_MC0_MISC+i*4, alow, ahigh);
                                snprintf(misc, 20, "[%08x%08x]", ahigh, alow);
@@ -49,27 +52,31 @@ static void k7_machine_check(struct pt_regs *regs, long error_code)
                                rdmsr(MSR_IA32_MC0_ADDR+i*4, alow, ahigh);
                                snprintf(addr, 24, " at %08x%08x", ahigh, alow);
                        }
+
                        printk(KERN_EMERG "CPU %d: Bank %d: %08x%08x%s%s\n",
                                smp_processor_id(), i, high, low, misc, addr);
-                       /* Clear it */
+
+                       /* Clear it: */
                        wrmsr(MSR_IA32_MC0_STATUS+i*4, 0UL, 0UL);
-                       /* Serialize */
+                       /* Serialize: */
                        wmb();
                        add_taint(TAINT_MACHINE_CHECK);
                }
        }
 
-       if (recover&2)
+       if (recover & 2)
                panic("CPU context corrupt");
-       if (recover&1)
+       if (recover & 1)
                panic("Unable to continue");
+
        printk(KERN_EMERG "Attempting to continue.\n");
+
        mcgstl &= ~(1<<2);
        wrmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
 }
 
 
-/* AMD K7 machine check is Intel like */
+/* AMD K7 machine check is Intel like: */
 void amd_mcheck_init(struct cpuinfo_x86 *c)
 {
        u32 l, h;
@@ -79,21 +86,26 @@ void amd_mcheck_init(struct cpuinfo_x86 *c)
                return;
 
        machine_check_vector = k7_machine_check;
+       /* Make sure the vector pointer is visible before we enable MCEs: */
        wmb();
 
        printk(KERN_INFO "Intel machine check architecture supported.\n");
+
        rdmsr(MSR_IA32_MCG_CAP, l, h);
        if (l & (1<<8)) /* Control register present ? */
                wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
        nr_mce_banks = l & 0xff;
 
-       /* Clear status for MC index 0 separately, we don't touch CTL,
-        * as some K7 Athlons cause spurious MCEs when its enabled. */
+       /*
+        * Clear status for MC index 0 separately, we don't touch CTL,
+        * as some K7 Athlons cause spurious MCEs when its enabled:
+        */
        if (boot_cpu_data.x86 == 6) {
                wrmsr(MSR_IA32_MC0_STATUS, 0x0, 0x0);
                i = 1;
        } else
                i = 0;
+
        for (; i < nr_mce_banks; i++) {
                wrmsr(MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff);
                wrmsr(MSR_IA32_MC0_STATUS+4*i, 0x0, 0x0);
diff --git a/arch/x86/kernel/cpu/mcheck/mce-inject.c b/arch/x86/kernel/cpu/mcheck/mce-inject.c
new file mode 100644 (file)
index 0000000..a3a235a
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Machine check injection support.
+ * Copyright 2008 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ *
+ * Authors:
+ * Andi Kleen
+ * Ying Huang
+ */
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/smp.h>
+#include <asm/mce.h>
+
+/* Update fake mce registers on current CPU. */
+static void inject_mce(struct mce *m)
+{
+       struct mce *i = &per_cpu(injectm, m->extcpu);
+
+       /* Make sure noone reads partially written injectm */
+       i->finished = 0;
+       mb();
+       m->finished = 0;
+       /* First set the fields after finished */
+       i->extcpu = m->extcpu;
+       mb();
+       /* Now write record in order, finished last (except above) */
+       memcpy(i, m, sizeof(struct mce));
+       /* Finally activate it */
+       mb();
+       i->finished = 1;
+}
+
+struct delayed_mce {
+       struct timer_list timer;
+       struct mce m;
+};
+
+/* Inject mce on current CPU */
+static void raise_mce(unsigned long data)
+{
+       struct delayed_mce *dm = (struct delayed_mce *)data;
+       struct mce *m = &dm->m;
+       int cpu = m->extcpu;
+
+       inject_mce(m);
+       if (m->status & MCI_STATUS_UC) {
+               struct pt_regs regs;
+               memset(&regs, 0, sizeof(struct pt_regs));
+               regs.ip = m->ip;
+               regs.cs = m->cs;
+               printk(KERN_INFO "Triggering MCE exception on CPU %d\n", cpu);
+               do_machine_check(&regs, 0);
+               printk(KERN_INFO "MCE exception done on CPU %d\n", cpu);
+       } else {
+               mce_banks_t b;
+               memset(&b, 0xff, sizeof(mce_banks_t));
+               printk(KERN_INFO "Starting machine check poll CPU %d\n", cpu);
+               machine_check_poll(0, &b);
+               mce_notify_irq();
+               printk(KERN_INFO "Finished machine check poll on CPU %d\n",
+                      cpu);
+       }
+       kfree(dm);
+}
+
+/* Error injection interface */
+static ssize_t mce_write(struct file *filp, const char __user *ubuf,
+                        size_t usize, loff_t *off)
+{
+       struct delayed_mce *dm;
+       struct mce m;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       /*
+        * There are some cases where real MSR reads could slip
+        * through.
+        */
+       if (!boot_cpu_has(X86_FEATURE_MCE) || !boot_cpu_has(X86_FEATURE_MCA))
+               return -EIO;
+
+       if ((unsigned long)usize > sizeof(struct mce))
+               usize = sizeof(struct mce);
+       if (copy_from_user(&m, ubuf, usize))
+               return -EFAULT;
+
+       if (m.extcpu >= num_possible_cpus() || !cpu_online(m.extcpu))
+               return -EINVAL;
+
+       dm = kmalloc(sizeof(struct delayed_mce), GFP_KERNEL);
+       if (!dm)
+               return -ENOMEM;
+
+       /*
+        * Need to give user space some time to set everything up,
+        * so do it a jiffie or two later everywhere.
+        * Should we use a hrtimer here for better synchronization?
+        */
+       memcpy(&dm->m, &m, sizeof(struct mce));
+       setup_timer(&dm->timer, raise_mce, (unsigned long)dm);
+       dm->timer.expires = jiffies + 2;
+       add_timer_on(&dm->timer, m.extcpu);
+       return usize;
+}
+
+static int inject_init(void)
+{
+       printk(KERN_INFO "Machine check injector initialized\n");
+       mce_chrdev_ops.write = mce_write;
+       return 0;
+}
+
+module_init(inject_init);
+/*
+ * Cannot tolerate unloading currently because we cannot
+ * guarantee all openers of mce_chrdev will get a reference to us.
+ */
+MODULE_LICENSE("GPL");
diff --git a/arch/x86/kernel/cpu/mcheck/mce-internal.h b/arch/x86/kernel/cpu/mcheck/mce-internal.h
new file mode 100644 (file)
index 0000000..54dcb8f
--- /dev/null
@@ -0,0 +1,15 @@
+#include <asm/mce.h>
+
+enum severity_level {
+       MCE_NO_SEVERITY,
+       MCE_KEEP_SEVERITY,
+       MCE_SOME_SEVERITY,
+       MCE_AO_SEVERITY,
+       MCE_UC_SEVERITY,
+       MCE_AR_SEVERITY,
+       MCE_PANIC_SEVERITY,
+};
+
+int mce_severity(struct mce *a, int tolerant, char **msg);
+
+extern int mce_ser;
diff --git a/arch/x86/kernel/cpu/mcheck/mce-severity.c b/arch/x86/kernel/cpu/mcheck/mce-severity.c
new file mode 100644 (file)
index 0000000..ff0807f
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * MCE grading rules.
+ * Copyright 2008, 2009 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ *
+ * Author: Andi Kleen
+ */
+#include <linux/kernel.h>
+#include <linux/seq_file.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <asm/mce.h>
+
+#include "mce-internal.h"
+
+/*
+ * Grade an mce by severity. In general the most severe ones are processed
+ * first. Since there are quite a lot of combinations test the bits in a
+ * table-driven way. The rules are simply processed in order, first
+ * match wins.
+ *
+ * Note this is only used for machine check exceptions, the corrected
+ * errors use much simpler rules. The exceptions still check for the corrected
+ * errors, but only to leave them alone for the CMCI handler (except for
+ * panic situations)
+ */
+
+enum context { IN_KERNEL = 1, IN_USER = 2 };
+enum ser { SER_REQUIRED = 1, NO_SER = 2 };
+
+static struct severity {
+       u64 mask;
+       u64 result;
+       unsigned char sev;
+       unsigned char mcgmask;
+       unsigned char mcgres;
+       unsigned char ser;
+       unsigned char context;
+       unsigned char covered;
+       char *msg;
+} severities[] = {
+#define KERNEL .context = IN_KERNEL
+#define USER .context = IN_USER
+#define SER .ser = SER_REQUIRED
+#define NOSER .ser = NO_SER
+#define SEV(s) .sev = MCE_ ## s ## _SEVERITY
+#define BITCLR(x, s, m, r...) { .mask = x, .result = 0, SEV(s), .msg = m, ## r }
+#define BITSET(x, s, m, r...) { .mask = x, .result = x, SEV(s), .msg = m, ## r }
+#define MCGMASK(x, res, s, m, r...) \
+       { .mcgmask = x, .mcgres = res, SEV(s), .msg = m, ## r }
+#define MASK(x, y, s, m, r...) \
+       { .mask = x, .result = y, SEV(s), .msg = m, ## r }
+#define MCI_UC_S (MCI_STATUS_UC|MCI_STATUS_S)
+#define MCI_UC_SAR (MCI_STATUS_UC|MCI_STATUS_S|MCI_STATUS_AR)
+#define MCACOD 0xffff
+
+       BITCLR(MCI_STATUS_VAL, NO, "Invalid"),
+       BITCLR(MCI_STATUS_EN, NO, "Not enabled"),
+       BITSET(MCI_STATUS_PCC, PANIC, "Processor context corrupt"),
+       /* When MCIP is not set something is very confused */
+       MCGMASK(MCG_STATUS_MCIP, 0, PANIC, "MCIP not set in MCA handler"),
+       /* Neither return not error IP -- no chance to recover -> PANIC */
+       MCGMASK(MCG_STATUS_RIPV|MCG_STATUS_EIPV, 0, PANIC,
+               "Neither restart nor error IP"),
+       MCGMASK(MCG_STATUS_RIPV, 0, PANIC, "In kernel and no restart IP",
+               KERNEL),
+       BITCLR(MCI_STATUS_UC, KEEP, "Corrected error", NOSER),
+       MASK(MCI_STATUS_OVER|MCI_STATUS_UC|MCI_STATUS_EN, MCI_STATUS_UC, SOME,
+            "Spurious not enabled", SER),
+
+       /* ignore OVER for UCNA */
+       MASK(MCI_UC_SAR, MCI_STATUS_UC, KEEP,
+            "Uncorrected no action required", SER),
+       MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_STATUS_UC|MCI_STATUS_AR, PANIC,
+            "Illegal combination (UCNA with AR=1)", SER),
+       MASK(MCI_STATUS_S, 0, KEEP, "Non signalled machine check", SER),
+
+       /* AR add known MCACODs here */
+       MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_STATUS_OVER|MCI_UC_SAR, PANIC,
+            "Action required with lost events", SER),
+       MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCACOD, MCI_UC_SAR, PANIC,
+            "Action required; unknown MCACOD", SER),
+
+       /* known AO MCACODs: */
+       MASK(MCI_UC_SAR|MCI_STATUS_OVER|0xfff0, MCI_UC_S|0xc0, AO,
+            "Action optional: memory scrubbing error", SER),
+       MASK(MCI_UC_SAR|MCI_STATUS_OVER|MCACOD, MCI_UC_S|0x17a, AO,
+            "Action optional: last level cache writeback error", SER),
+
+       MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_UC_S, SOME,
+            "Action optional unknown MCACOD", SER),
+       MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_UC_S|MCI_STATUS_OVER, SOME,
+            "Action optional with lost events", SER),
+       BITSET(MCI_STATUS_UC|MCI_STATUS_OVER, PANIC, "Overflowed uncorrected"),
+       BITSET(MCI_STATUS_UC, UC, "Uncorrected"),
+       BITSET(0, SOME, "No match")     /* always matches. keep at end */
+};
+
+/*
+ * If the EIPV bit is set, it means the saved IP is the
+ * instruction which caused the MCE.
+ */
+static int error_context(struct mce *m)
+{
+       if (m->mcgstatus & MCG_STATUS_EIPV)
+               return (m->ip && (m->cs & 3) == 3) ? IN_USER : IN_KERNEL;
+       /* Unknown, assume kernel */
+       return IN_KERNEL;
+}
+
+int mce_severity(struct mce *a, int tolerant, char **msg)
+{
+       enum context ctx = error_context(a);
+       struct severity *s;
+
+       for (s = severities;; s++) {
+               if ((a->status & s->mask) != s->result)
+                       continue;
+               if ((a->mcgstatus & s->mcgmask) != s->mcgres)
+                       continue;
+               if (s->ser == SER_REQUIRED && !mce_ser)
+                       continue;
+               if (s->ser == NO_SER && mce_ser)
+                       continue;
+               if (s->context && ctx != s->context)
+                       continue;
+               if (msg)
+                       *msg = s->msg;
+               s->covered = 1;
+               if (s->sev >= MCE_UC_SEVERITY && ctx == IN_KERNEL) {
+                       if (panic_on_oops || tolerant < 1)
+                               return MCE_PANIC_SEVERITY;
+               }
+               return s->sev;
+       }
+}
+
+static void *s_start(struct seq_file *f, loff_t *pos)
+{
+       if (*pos >= ARRAY_SIZE(severities))
+               return NULL;
+       return &severities[*pos];
+}
+
+static void *s_next(struct seq_file *f, void *data, loff_t *pos)
+{
+       if (++(*pos) >= ARRAY_SIZE(severities))
+               return NULL;
+       return &severities[*pos];
+}
+
+static void s_stop(struct seq_file *f, void *data)
+{
+}
+
+static int s_show(struct seq_file *f, void *data)
+{
+       struct severity *ser = data;
+       seq_printf(f, "%d\t%s\n", ser->covered, ser->msg);
+       return 0;
+}
+
+static const struct seq_operations severities_seq_ops = {
+       .start  = s_start,
+       .next   = s_next,
+       .stop   = s_stop,
+       .show   = s_show,
+};
+
+static int severities_coverage_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &severities_seq_ops);
+}
+
+static ssize_t severities_coverage_write(struct file *file,
+                                        const char __user *ubuf,
+                                        size_t count, loff_t *ppos)
+{
+       int i;
+       for (i = 0; i < ARRAY_SIZE(severities); i++)
+               severities[i].covered = 0;
+       return count;
+}
+
+static const struct file_operations severities_coverage_fops = {
+       .open           = severities_coverage_open,
+       .release        = seq_release,
+       .read           = seq_read,
+       .write          = severities_coverage_write,
+};
+
+static int __init severities_debugfs_init(void)
+{
+       struct dentry *dmce = NULL, *fseverities_coverage = NULL;
+
+       dmce = debugfs_create_dir("mce", NULL);
+       if (dmce == NULL)
+               goto err_out;
+       fseverities_coverage = debugfs_create_file("severities-coverage",
+                                                  0444, dmce, NULL,
+                                                  &severities_coverage_fops);
+       if (fseverities_coverage == NULL)
+               goto err_out;
+
+       return 0;
+
+err_out:
+       if (fseverities_coverage)
+               debugfs_remove(fseverities_coverage);
+       if (dmce)
+               debugfs_remove(dmce);
+       return -ENOMEM;
+}
+late_initcall(severities_debugfs_init);
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
new file mode 100644 (file)
index 0000000..fabba15
--- /dev/null
@@ -0,0 +1,1964 @@
+/*
+ * Machine check handler.
+ *
+ * K8 parts Copyright 2002,2003 Andi Kleen, SuSE Labs.
+ * Rest from unknown author(s).
+ * 2004 Andi Kleen. Rewrote most of it.
+ * Copyright 2008 Intel Corporation
+ * Author: Andi Kleen
+ */
+#include <linux/thread_info.h>
+#include <linux/capability.h>
+#include <linux/miscdevice.h>
+#include <linux/interrupt.h>
+#include <linux/ratelimit.h>
+#include <linux/kallsyms.h>
+#include <linux/rcupdate.h>
+#include <linux/kobject.h>
+#include <linux/uaccess.h>
+#include <linux/kdebug.h>
+#include <linux/kernel.h>
+#include <linux/percpu.h>
+#include <linux/string.h>
+#include <linux/sysdev.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/sched.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/poll.h>
+#include <linux/nmi.h>
+#include <linux/cpu.h>
+#include <linux/smp.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+
+#include <asm/processor.h>
+#include <asm/hw_irq.h>
+#include <asm/apic.h>
+#include <asm/idle.h>
+#include <asm/ipi.h>
+#include <asm/mce.h>
+#include <asm/msr.h>
+
+#include "mce-internal.h"
+#include "mce.h"
+
+/* Handle unconfigured int18 (should never happen) */
+static void unexpected_machine_check(struct pt_regs *regs, long error_code)
+{
+       printk(KERN_ERR "CPU#%d: Unexpected int18 (Machine Check).\n",
+              smp_processor_id());
+}
+
+/* Call the installed machine check handler for this CPU setup. */
+void (*machine_check_vector)(struct pt_regs *, long error_code) =
+                                               unexpected_machine_check;
+
+int                            mce_disabled;
+
+#ifdef CONFIG_X86_NEW_MCE
+
+#define MISC_MCELOG_MINOR      227
+
+#define SPINUNIT 100   /* 100ns */
+
+atomic_t mce_entry;
+
+DEFINE_PER_CPU(unsigned, mce_exception_count);
+
+/*
+ * Tolerant levels:
+ *   0: always panic on uncorrected errors, log corrected errors
+ *   1: panic or SIGBUS on uncorrected errors, log corrected errors
+ *   2: SIGBUS or log uncorrected errors (if possible), log corrected errors
+ *   3: never panic or SIGBUS, log all errors (for testing only)
+ */
+static int                     tolerant = 1;
+static int                     banks;
+static u64                     *bank;
+static unsigned long           notify_user;
+static int                     rip_msr;
+static int                     mce_bootlog = -1;
+static int                     monarch_timeout = -1;
+static int                     mce_panic_timeout;
+static int                     mce_dont_log_ce;
+int                            mce_cmci_disabled;
+int                            mce_ignore_ce;
+int                            mce_ser;
+
+static char                    trigger[128];
+static char                    *trigger_argv[2] = { trigger, NULL };
+
+static unsigned long           dont_init_banks;
+
+static DECLARE_WAIT_QUEUE_HEAD(mce_wait);
+static DEFINE_PER_CPU(struct mce, mces_seen);
+static int                     cpu_missing;
+
+
+/* MCA banks polled by the period polling timer for corrected events */
+DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = {
+       [0 ... BITS_TO_LONGS(MAX_NR_BANKS)-1] = ~0UL
+};
+
+static inline int skip_bank_init(int i)
+{
+       return i < BITS_PER_LONG && test_bit(i, &dont_init_banks);
+}
+
+static DEFINE_PER_CPU(struct work_struct, mce_work);
+
+/* Do initial initialization of a struct mce */
+void mce_setup(struct mce *m)
+{
+       memset(m, 0, sizeof(struct mce));
+       m->cpu = m->extcpu = smp_processor_id();
+       rdtscll(m->tsc);
+       /* We hope get_seconds stays lockless */
+       m->time = get_seconds();
+       m->cpuvendor = boot_cpu_data.x86_vendor;
+       m->cpuid = cpuid_eax(1);
+#ifdef CONFIG_SMP
+       m->socketid = cpu_data(m->extcpu).phys_proc_id;
+#endif
+       m->apicid = cpu_data(m->extcpu).initial_apicid;
+       rdmsrl(MSR_IA32_MCG_CAP, m->mcgcap);
+}
+
+DEFINE_PER_CPU(struct mce, injectm);
+EXPORT_PER_CPU_SYMBOL_GPL(injectm);
+
+/*
+ * Lockless MCE logging infrastructure.
+ * This avoids deadlocks on printk locks without having to break locks. Also
+ * separate MCEs from kernel messages to avoid bogus bug reports.
+ */
+
+static struct mce_log mcelog = {
+       .signature      = MCE_LOG_SIGNATURE,
+       .len            = MCE_LOG_LEN,
+       .recordlen      = sizeof(struct mce),
+};
+
+void mce_log(struct mce *mce)
+{
+       unsigned next, entry;
+
+       mce->finished = 0;
+       wmb();
+       for (;;) {
+               entry = rcu_dereference(mcelog.next);
+               for (;;) {
+                       /*
+                        * When the buffer fills up discard new entries.
+                        * Assume that the earlier errors are the more
+                        * interesting ones:
+                        */
+                       if (entry >= MCE_LOG_LEN) {
+                               set_bit(MCE_OVERFLOW,
+                                       (unsigned long *)&mcelog.flags);
+                               return;
+                       }
+                       /* Old left over entry. Skip: */
+                       if (mcelog.entry[entry].finished) {
+                               entry++;
+                               continue;
+                       }
+                       break;
+               }
+               smp_rmb();
+               next = entry + 1;
+               if (cmpxchg(&mcelog.next, entry, next) == entry)
+                       break;
+       }
+       memcpy(mcelog.entry + entry, mce, sizeof(struct mce));
+       wmb();
+       mcelog.entry[entry].finished = 1;
+       wmb();
+
+       mce->finished = 1;
+       set_bit(0, &notify_user);
+}
+
+static void print_mce(struct mce *m)
+{
+       printk(KERN_EMERG
+              "CPU %d: Machine Check Exception: %16Lx Bank %d: %016Lx\n",
+              m->extcpu, m->mcgstatus, m->bank, m->status);
+       if (m->ip) {
+               printk(KERN_EMERG "RIP%s %02x:<%016Lx> ",
+                      !(m->mcgstatus & MCG_STATUS_EIPV) ? " !INEXACT!" : "",
+                      m->cs, m->ip);
+               if (m->cs == __KERNEL_CS)
+                       print_symbol("{%s}", m->ip);
+               printk("\n");
+       }
+       printk(KERN_EMERG "TSC %llx ", m->tsc);
+       if (m->addr)
+               printk("ADDR %llx ", m->addr);
+       if (m->misc)
+               printk("MISC %llx ", m->misc);
+       printk("\n");
+       printk(KERN_EMERG "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x\n",
+                       m->cpuvendor, m->cpuid, m->time, m->socketid,
+                       m->apicid);
+}
+
+static void print_mce_head(void)
+{
+       printk(KERN_EMERG "\n" KERN_EMERG "HARDWARE ERROR\n");
+}
+
+static void print_mce_tail(void)
+{
+       printk(KERN_EMERG "This is not a software problem!\n"
+              KERN_EMERG "Run through mcelog --ascii to decode and contact your hardware vendor\n");
+}
+
+#define PANIC_TIMEOUT 5 /* 5 seconds */
+
+static atomic_t mce_paniced;
+
+/* Panic in progress. Enable interrupts and wait for final IPI */
+static void wait_for_panic(void)
+{
+       long timeout = PANIC_TIMEOUT*USEC_PER_SEC;
+       preempt_disable();
+       local_irq_enable();
+       while (timeout-- > 0)
+               udelay(1);
+       if (panic_timeout == 0)
+               panic_timeout = mce_panic_timeout;
+       panic("Panicing machine check CPU died");
+}
+
+static void mce_panic(char *msg, struct mce *final, char *exp)
+{
+       int i;
+
+       /*
+        * Make sure only one CPU runs in machine check panic
+        */
+       if (atomic_add_return(1, &mce_paniced) > 1)
+               wait_for_panic();
+       barrier();
+
+       bust_spinlocks(1);
+       console_verbose();
+       print_mce_head();
+       /* First print corrected ones that are still unlogged */
+       for (i = 0; i < MCE_LOG_LEN; i++) {
+               struct mce *m = &mcelog.entry[i];
+               if (!(m->status & MCI_STATUS_VAL))
+                       continue;
+               if (!(m->status & MCI_STATUS_UC))
+                       print_mce(m);
+       }
+       /* Now print uncorrected but with the final one last */
+       for (i = 0; i < MCE_LOG_LEN; i++) {
+               struct mce *m = &mcelog.entry[i];
+               if (!(m->status & MCI_STATUS_VAL))
+                       continue;
+               if (!(m->status & MCI_STATUS_UC))
+                       continue;
+               if (!final || memcmp(m, final, sizeof(struct mce)))
+                       print_mce(m);
+       }
+       if (final)
+               print_mce(final);
+       if (cpu_missing)
+               printk(KERN_EMERG "Some CPUs didn't answer in synchronization\n");
+       print_mce_tail();
+       if (exp)
+               printk(KERN_EMERG "Machine check: %s\n", exp);
+       if (panic_timeout == 0)
+               panic_timeout = mce_panic_timeout;
+       panic(msg);
+}
+
+/* Support code for software error injection */
+
+static int msr_to_offset(u32 msr)
+{
+       unsigned bank = __get_cpu_var(injectm.bank);
+       if (msr == rip_msr)
+               return offsetof(struct mce, ip);
+       if (msr == MSR_IA32_MC0_STATUS + bank*4)
+               return offsetof(struct mce, status);
+       if (msr == MSR_IA32_MC0_ADDR + bank*4)
+               return offsetof(struct mce, addr);
+       if (msr == MSR_IA32_MC0_MISC + bank*4)
+               return offsetof(struct mce, misc);
+       if (msr == MSR_IA32_MCG_STATUS)
+               return offsetof(struct mce, mcgstatus);
+       return -1;
+}
+
+/* MSR access wrappers used for error injection */
+static u64 mce_rdmsrl(u32 msr)
+{
+       u64 v;
+       if (__get_cpu_var(injectm).finished) {
+               int offset = msr_to_offset(msr);
+               if (offset < 0)
+                       return 0;
+               return *(u64 *)((char *)&__get_cpu_var(injectm) + offset);
+       }
+       rdmsrl(msr, v);
+       return v;
+}
+
+static void mce_wrmsrl(u32 msr, u64 v)
+{
+       if (__get_cpu_var(injectm).finished) {
+               int offset = msr_to_offset(msr);
+               if (offset >= 0)
+                       *(u64 *)((char *)&__get_cpu_var(injectm) + offset) = v;
+               return;
+       }
+       wrmsrl(msr, v);
+}
+
+/*
+ * Simple lockless ring to communicate PFNs from the exception handler with the
+ * process context work function. This is vastly simplified because there's
+ * only a single reader and a single writer.
+ */
+#define MCE_RING_SIZE 16       /* we use one entry less */
+
+struct mce_ring {
+       unsigned short start;
+       unsigned short end;
+       unsigned long ring[MCE_RING_SIZE];
+};
+static DEFINE_PER_CPU(struct mce_ring, mce_ring);
+
+/* Runs with CPU affinity in workqueue */
+static int mce_ring_empty(void)
+{
+       struct mce_ring *r = &__get_cpu_var(mce_ring);
+
+       return r->start == r->end;
+}
+
+static int mce_ring_get(unsigned long *pfn)
+{
+       struct mce_ring *r;
+       int ret = 0;
+
+       *pfn = 0;
+       get_cpu();
+       r = &__get_cpu_var(mce_ring);
+       if (r->start == r->end)
+               goto out;
+       *pfn = r->ring[r->start];
+       r->start = (r->start + 1) % MCE_RING_SIZE;
+       ret = 1;
+out:
+       put_cpu();
+       return ret;
+}
+
+/* Always runs in MCE context with preempt off */
+static int mce_ring_add(unsigned long pfn)
+{
+       struct mce_ring *r = &__get_cpu_var(mce_ring);
+       unsigned next;
+
+       next = (r->end + 1) % MCE_RING_SIZE;
+       if (next == r->start)
+               return -1;
+       r->ring[r->end] = pfn;
+       wmb();
+       r->end = next;
+       return 0;
+}
+
+int mce_available(struct cpuinfo_x86 *c)
+{
+       if (mce_disabled)
+               return 0;
+       return cpu_has(c, X86_FEATURE_MCE) && cpu_has(c, X86_FEATURE_MCA);
+}
+
+static void mce_schedule_work(void)
+{
+       if (!mce_ring_empty()) {
+               struct work_struct *work = &__get_cpu_var(mce_work);
+               if (!work_pending(work))
+                       schedule_work(work);
+       }
+}
+
+/*
+ * Get the address of the instruction at the time of the machine check
+ * error.
+ */
+static inline void mce_get_rip(struct mce *m, struct pt_regs *regs)
+{
+
+       if (regs && (m->mcgstatus & (MCG_STATUS_RIPV|MCG_STATUS_EIPV))) {
+               m->ip = regs->ip;
+               m->cs = regs->cs;
+       } else {
+               m->ip = 0;
+               m->cs = 0;
+       }
+       if (rip_msr)
+               m->ip = mce_rdmsrl(rip_msr);
+}
+
+#ifdef CONFIG_X86_LOCAL_APIC 
+/*
+ * Called after interrupts have been reenabled again
+ * when a MCE happened during an interrupts off region
+ * in the kernel.
+ */
+asmlinkage void smp_mce_self_interrupt(struct pt_regs *regs)
+{
+       ack_APIC_irq();
+       exit_idle();
+       irq_enter();
+       mce_notify_irq();
+       mce_schedule_work();
+       irq_exit();
+}
+#endif
+
+static void mce_report_event(struct pt_regs *regs)
+{
+       if (regs->flags & (X86_VM_MASK|X86_EFLAGS_IF)) {
+               mce_notify_irq();
+               /*
+                * Triggering the work queue here is just an insurance
+                * policy in case the syscall exit notify handler
+                * doesn't run soon enough or ends up running on the
+                * wrong CPU (can happen when audit sleeps)
+                */
+               mce_schedule_work();
+               return;
+       }
+
+#ifdef CONFIG_X86_LOCAL_APIC
+       /*
+        * Without APIC do not notify. The event will be picked
+        * up eventually.
+        */
+       if (!cpu_has_apic)
+               return;
+
+       /*
+        * When interrupts are disabled we cannot use
+        * kernel services safely. Trigger an self interrupt
+        * through the APIC to instead do the notification
+        * after interrupts are reenabled again.
+        */
+       apic->send_IPI_self(MCE_SELF_VECTOR);
+
+       /*
+        * Wait for idle afterwards again so that we don't leave the
+        * APIC in a non idle state because the normal APIC writes
+        * cannot exclude us.
+        */
+       apic_wait_icr_idle();
+#endif
+}
+
+DEFINE_PER_CPU(unsigned, mce_poll_count);
+
+/*
+ * Poll for corrected events or events that happened before reset.
+ * Those are just logged through /dev/mcelog.
+ *
+ * This is executed in standard interrupt context.
+ *
+ * Note: spec recommends to panic for fatal unsignalled
+ * errors here. However this would be quite problematic --
+ * we would need to reimplement the Monarch handling and
+ * it would mess up the exclusion between exception handler
+ * and poll hander -- * so we skip this for now.
+ * These cases should not happen anyways, or only when the CPU
+ * is already totally * confused. In this case it's likely it will
+ * not fully execute the machine check handler either.
+ */
+void machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
+{
+       struct mce m;
+       int i;
+
+       __get_cpu_var(mce_poll_count)++;
+
+       mce_setup(&m);
+
+       m.mcgstatus = mce_rdmsrl(MSR_IA32_MCG_STATUS);
+       for (i = 0; i < banks; i++) {
+               if (!bank[i] || !test_bit(i, *b))
+                       continue;
+
+               m.misc = 0;
+               m.addr = 0;
+               m.bank = i;
+               m.tsc = 0;
+
+               barrier();
+               m.status = mce_rdmsrl(MSR_IA32_MC0_STATUS + i*4);
+               if (!(m.status & MCI_STATUS_VAL))
+                       continue;
+
+               /*
+                * Uncorrected or signalled events are handled by the exception
+                * handler when it is enabled, so don't process those here.
+                *
+                * TBD do the same check for MCI_STATUS_EN here?
+                */
+               if (!(flags & MCP_UC) &&
+                   (m.status & (mce_ser ? MCI_STATUS_S : MCI_STATUS_UC)))
+                       continue;
+
+               if (m.status & MCI_STATUS_MISCV)
+                       m.misc = mce_rdmsrl(MSR_IA32_MC0_MISC + i*4);
+               if (m.status & MCI_STATUS_ADDRV)
+                       m.addr = mce_rdmsrl(MSR_IA32_MC0_ADDR + i*4);
+
+               if (!(flags & MCP_TIMESTAMP))
+                       m.tsc = 0;
+               /*
+                * Don't get the IP here because it's unlikely to
+                * have anything to do with the actual error location.
+                */
+               if (!(flags & MCP_DONTLOG) && !mce_dont_log_ce) {
+                       mce_log(&m);
+                       add_taint(TAINT_MACHINE_CHECK);
+               }
+
+               /*
+                * Clear state for this bank.
+                */
+               mce_wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
+       }
+
+       /*
+        * Don't clear MCG_STATUS here because it's only defined for
+        * exceptions.
+        */
+
+       sync_core();
+}
+EXPORT_SYMBOL_GPL(machine_check_poll);
+
+/*
+ * Do a quick check if any of the events requires a panic.
+ * This decides if we keep the events around or clear them.
+ */
+static int mce_no_way_out(struct mce *m, char **msg)
+{
+       int i;
+
+       for (i = 0; i < banks; i++) {
+               m->status = mce_rdmsrl(MSR_IA32_MC0_STATUS + i*4);
+               if (mce_severity(m, tolerant, msg) >= MCE_PANIC_SEVERITY)
+                       return 1;
+       }
+       return 0;
+}
+
+/*
+ * Variable to establish order between CPUs while scanning.
+ * Each CPU spins initially until executing is equal its number.
+ */
+static atomic_t mce_executing;
+
+/*
+ * Defines order of CPUs on entry. First CPU becomes Monarch.
+ */
+static atomic_t mce_callin;
+
+/*
+ * Check if a timeout waiting for other CPUs happened.
+ */
+static int mce_timed_out(u64 *t)
+{
+       /*
+        * The others already did panic for some reason.
+        * Bail out like in a timeout.
+        * rmb() to tell the compiler that system_state
+        * might have been modified by someone else.
+        */
+       rmb();
+       if (atomic_read(&mce_paniced))
+               wait_for_panic();
+       if (!monarch_timeout)
+               goto out;
+       if ((s64)*t < SPINUNIT) {
+               /* CHECKME: Make panic default for 1 too? */
+               if (tolerant < 1)
+                       mce_panic("Timeout synchronizing machine check over CPUs",
+                                 NULL, NULL);
+               cpu_missing = 1;
+               return 1;
+       }
+       *t -= SPINUNIT;
+out:
+       touch_nmi_watchdog();
+       return 0;
+}
+
+/*
+ * The Monarch's reign.  The Monarch is the CPU who entered
+ * the machine check handler first. It waits for the others to
+ * raise the exception too and then grades them. When any
+ * error is fatal panic. Only then let the others continue.
+ *
+ * The other CPUs entering the MCE handler will be controlled by the
+ * Monarch. They are called Subjects.
+ *
+ * This way we prevent any potential data corruption in a unrecoverable case
+ * and also makes sure always all CPU's errors are examined.
+ *
+ * Also this detects the case of an machine check event coming from outer
+ * space (not detected by any CPUs) In this case some external agent wants
+ * us to shut down, so panic too.
+ *
+ * The other CPUs might still decide to panic if the handler happens
+ * in a unrecoverable place, but in this case the system is in a semi-stable
+ * state and won't corrupt anything by itself. It's ok to let the others
+ * continue for a bit first.
+ *
+ * All the spin loops have timeouts; when a timeout happens a CPU
+ * typically elects itself to be Monarch.
+ */
+static void mce_reign(void)
+{
+       int cpu;
+       struct mce *m = NULL;
+       int global_worst = 0;
+       char *msg = NULL;
+       char *nmsg = NULL;
+
+       /*
+        * This CPU is the Monarch and the other CPUs have run
+        * through their handlers.
+        * Grade the severity of the errors of all the CPUs.
+        */
+       for_each_possible_cpu(cpu) {
+               int severity = mce_severity(&per_cpu(mces_seen, cpu), tolerant,
+                                           &nmsg);
+               if (severity > global_worst) {
+                       msg = nmsg;
+                       global_worst = severity;
+                       m = &per_cpu(mces_seen, cpu);
+               }
+       }
+
+       /*
+        * Cannot recover? Panic here then.
+        * This dumps all the mces in the log buffer and stops the
+        * other CPUs.
+        */
+       if (m && global_worst >= MCE_PANIC_SEVERITY && tolerant < 3)
+               mce_panic("Fatal Machine check", m, msg);
+
+       /*
+        * For UC somewhere we let the CPU who detects it handle it.
+        * Also must let continue the others, otherwise the handling
+        * CPU could deadlock on a lock.
+        */
+
+       /*
+        * No machine check event found. Must be some external
+        * source or one CPU is hung. Panic.
+        */
+       if (!m && tolerant < 3)
+               mce_panic("Machine check from unknown source", NULL, NULL);
+
+       /*
+        * Now clear all the mces_seen so that they don't reappear on
+        * the next mce.
+        */
+       for_each_possible_cpu(cpu)
+               memset(&per_cpu(mces_seen, cpu), 0, sizeof(struct mce));
+}
+
+static atomic_t global_nwo;
+
+/*
+ * Start of Monarch synchronization. This waits until all CPUs have
+ * entered the exception handler and then determines if any of them
+ * saw a fatal event that requires panic. Then it executes them
+ * in the entry order.
+ * TBD double check parallel CPU hotunplug
+ */
+static int mce_start(int no_way_out, int *order)
+{
+       int nwo;
+       int cpus = num_online_cpus();
+       u64 timeout = (u64)monarch_timeout * NSEC_PER_USEC;
+
+       if (!timeout) {
+               *order = -1;
+               return no_way_out;
+       }
+
+       atomic_add(no_way_out, &global_nwo);
+
+       /*
+        * Wait for everyone.
+        */
+       while (atomic_read(&mce_callin) != cpus) {
+               if (mce_timed_out(&timeout)) {
+                       atomic_set(&global_nwo, 0);
+                       *order = -1;
+                       return no_way_out;
+               }
+               ndelay(SPINUNIT);
+       }
+
+       /*
+        * Cache the global no_way_out state.
+        */
+       nwo = atomic_read(&global_nwo);
+
+       /*
+        * Monarch starts executing now, the others wait.
+        */
+       if (*order == 1) {
+               atomic_set(&mce_executing, 1);
+               return nwo;
+       }
+
+       /*
+        * Now start the scanning loop one by one
+        * in the original callin order.
+        * This way when there are any shared banks it will
+        * be only seen by one CPU before cleared, avoiding duplicates.
+        */
+       while (atomic_read(&mce_executing) < *order) {
+               if (mce_timed_out(&timeout)) {
+                       atomic_set(&global_nwo, 0);
+                       *order = -1;
+                       return no_way_out;
+               }
+               ndelay(SPINUNIT);
+       }
+       return nwo;
+}
+
+/*
+ * Synchronize between CPUs after main scanning loop.
+ * This invokes the bulk of the Monarch processing.
+ */
+static int mce_end(int order)
+{
+       int ret = -1;
+       u64 timeout = (u64)monarch_timeout * NSEC_PER_USEC;
+
+       if (!timeout)
+               goto reset;
+       if (order < 0)
+               goto reset;
+
+       /*
+        * Allow others to run.
+        */
+       atomic_inc(&mce_executing);
+
+       if (order == 1) {
+               /* CHECKME: Can this race with a parallel hotplug? */
+               int cpus = num_online_cpus();
+
+               /*
+                * Monarch: Wait for everyone to go through their scanning
+                * loops.
+                */
+               while (atomic_read(&mce_executing) <= cpus) {
+                       if (mce_timed_out(&timeout))
+                               goto reset;
+                       ndelay(SPINUNIT);
+               }
+
+               mce_reign();
+               barrier();
+               ret = 0;
+       } else {
+               /*
+                * Subject: Wait for Monarch to finish.
+                */
+               while (atomic_read(&mce_executing) != 0) {
+                       if (mce_timed_out(&timeout))
+                               goto reset;
+                       ndelay(SPINUNIT);
+               }
+
+               /*
+                * Don't reset anything. That's done by the Monarch.
+                */
+               return 0;
+       }
+
+       /*
+        * Reset all global state.
+        */
+reset:
+       atomic_set(&global_nwo, 0);
+       atomic_set(&mce_callin, 0);
+       barrier();
+
+       /*
+        * Let others run again.
+        */
+       atomic_set(&mce_executing, 0);
+       return ret;
+}
+
+/*
+ * Check if the address reported by the CPU is in a format we can parse.
+ * It would be possible to add code for most other cases, but all would
+ * be somewhat complicated (e.g. segment offset would require an instruction
+ * parser). So only support physical addresses upto page granuality for now.
+ */
+static int mce_usable_address(struct mce *m)
+{
+       if (!(m->status & MCI_STATUS_MISCV) || !(m->status & MCI_STATUS_ADDRV))
+               return 0;
+       if ((m->misc & 0x3f) > PAGE_SHIFT)
+               return 0;
+       if (((m->misc >> 6) & 7) != MCM_ADDR_PHYS)
+               return 0;
+       return 1;
+}
+
+static void mce_clear_state(unsigned long *toclear)
+{
+       int i;
+
+       for (i = 0; i < banks; i++) {
+               if (test_bit(i, toclear))
+                       mce_wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
+       }
+}
+
+/*
+ * The actual machine check handler. This only handles real
+ * exceptions when something got corrupted coming in through int 18.
+ *
+ * This is executed in NMI context not subject to normal locking rules. This
+ * implies that most kernel services cannot be safely used. Don't even
+ * think about putting a printk in there!
+ *
+ * On Intel systems this is entered on all CPUs in parallel through
+ * MCE broadcast. However some CPUs might be broken beyond repair,
+ * so be always careful when synchronizing with others.
+ */
+void do_machine_check(struct pt_regs *regs, long error_code)
+{
+       struct mce m, *final;
+       int i;
+       int worst = 0;
+       int severity;
+       /*
+        * Establish sequential order between the CPUs entering the machine
+        * check handler.
+        */
+       int order;
+
+       /*
+        * If no_way_out gets set, there is no safe way to recover from this
+        * MCE.  If tolerant is cranked up, we'll try anyway.
+        */
+       int no_way_out = 0;
+       /*
+        * If kill_it gets set, there might be a way to recover from this
+        * error.
+        */
+       int kill_it = 0;
+       DECLARE_BITMAP(toclear, MAX_NR_BANKS);
+       char *msg = "Unknown";
+
+       atomic_inc(&mce_entry);
+
+       __get_cpu_var(mce_exception_count)++;
+
+       if (notify_die(DIE_NMI, "machine check", regs, error_code,
+                          18, SIGKILL) == NOTIFY_STOP)
+               goto out;
+       if (!banks)
+               goto out;
+
+       order = atomic_add_return(1, &mce_callin);
+       mce_setup(&m);
+
+       m.mcgstatus = mce_rdmsrl(MSR_IA32_MCG_STATUS);
+       no_way_out = mce_no_way_out(&m, &msg);
+
+       final = &__get_cpu_var(mces_seen);
+       *final = m;
+
+       barrier();
+
+       /*
+        * When no restart IP must always kill or panic.
+        */
+       if (!(m.mcgstatus & MCG_STATUS_RIPV))
+               kill_it = 1;
+
+       /*
+        * Go through all the banks in exclusion of the other CPUs.
+        * This way we don't report duplicated events on shared banks
+        * because the first one to see it will clear it.
+        */
+       no_way_out = mce_start(no_way_out, &order);
+       for (i = 0; i < banks; i++) {
+               __clear_bit(i, toclear);
+               if (!bank[i])
+                       continue;
+
+               m.misc = 0;
+               m.addr = 0;
+               m.bank = i;
+
+               m.status = mce_rdmsrl(MSR_IA32_MC0_STATUS + i*4);
+               if ((m.status & MCI_STATUS_VAL) == 0)
+                       continue;
+
+               /*
+                * Non uncorrected or non signaled errors are handled by
+                * machine_check_poll. Leave them alone, unless this panics.
+                */
+               if (!(m.status & (mce_ser ? MCI_STATUS_S : MCI_STATUS_UC)) &&
+                       !no_way_out)
+                       continue;
+
+               /*
+                * Set taint even when machine check was not enabled.
+                */
+               add_taint(TAINT_MACHINE_CHECK);
+
+               severity = mce_severity(&m, tolerant, NULL);
+
+               /*
+                * When machine check was for corrected handler don't touch,
+                * unless we're panicing.
+                */
+               if (severity == MCE_KEEP_SEVERITY && !no_way_out)
+                       continue;
+               __set_bit(i, toclear);
+               if (severity == MCE_NO_SEVERITY) {
+                       /*
+                        * Machine check event was not enabled. Clear, but
+                        * ignore.
+                        */
+                       continue;
+               }
+
+               /*
+                * Kill on action required.
+                */
+               if (severity == MCE_AR_SEVERITY)
+                       kill_it = 1;
+
+               if (m.status & MCI_STATUS_MISCV)
+                       m.misc = mce_rdmsrl(MSR_IA32_MC0_MISC + i*4);
+               if (m.status & MCI_STATUS_ADDRV)
+                       m.addr = mce_rdmsrl(MSR_IA32_MC0_ADDR + i*4);
+
+               /*
+                * Action optional error. Queue address for later processing.
+                * When the ring overflows we just ignore the AO error.
+                * RED-PEN add some logging mechanism when
+                * usable_address or mce_add_ring fails.
+                * RED-PEN don't ignore overflow for tolerant == 0
+                */
+               if (severity == MCE_AO_SEVERITY && mce_usable_address(&m))
+                       mce_ring_add(m.addr >> PAGE_SHIFT);
+
+               mce_get_rip(&m, regs);
+               mce_log(&m);
+
+               if (severity > worst) {
+                       *final = m;
+                       worst = severity;
+               }
+       }
+
+       if (!no_way_out)
+               mce_clear_state(toclear);
+
+       /*
+        * Do most of the synchronization with other CPUs.
+        * When there's any problem use only local no_way_out state.
+        */
+       if (mce_end(order) < 0)
+               no_way_out = worst >= MCE_PANIC_SEVERITY;
+
+       /*
+        * If we have decided that we just CAN'T continue, and the user
+        * has not set tolerant to an insane level, give up and die.
+        *
+        * This is mainly used in the case when the system doesn't
+        * support MCE broadcasting or it has been disabled.
+        */
+       if (no_way_out && tolerant < 3)
+               mce_panic("Fatal machine check on current CPU", final, msg);
+
+       /*
+        * If the error seems to be unrecoverable, something should be
+        * done.  Try to kill as little as possible.  If we can kill just
+        * one task, do that.  If the user has set the tolerance very
+        * high, don't try to do anything at all.
+        */
+
+       if (kill_it && tolerant < 3)
+               force_sig(SIGBUS, current);
+
+       /* notify userspace ASAP */
+       set_thread_flag(TIF_MCE_NOTIFY);
+
+       if (worst > 0)
+               mce_report_event(regs);
+       mce_wrmsrl(MSR_IA32_MCG_STATUS, 0);
+out:
+       atomic_dec(&mce_entry);
+       sync_core();
+}
+EXPORT_SYMBOL_GPL(do_machine_check);
+
+/* dummy to break dependency. actual code is in mm/memory-failure.c */
+void __attribute__((weak)) memory_failure(unsigned long pfn, int vector)
+{
+       printk(KERN_ERR "Action optional memory failure at %lx ignored\n", pfn);
+}
+
+/*
+ * Called after mce notification in process context. This code
+ * is allowed to sleep. Call the high level VM handler to process
+ * any corrupted pages.
+ * Assume that the work queue code only calls this one at a time
+ * per CPU.
+ * Note we don't disable preemption, so this code might run on the wrong
+ * CPU. In this case the event is picked up by the scheduled work queue.
+ * This is merely a fast path to expedite processing in some common
+ * cases.
+ */
+void mce_notify_process(void)
+{
+       unsigned long pfn;
+       mce_notify_irq();
+       while (mce_ring_get(&pfn))
+               memory_failure(pfn, MCE_VECTOR);
+}
+
+static void mce_process_work(struct work_struct *dummy)
+{
+       mce_notify_process();
+}
+
+#ifdef CONFIG_X86_MCE_INTEL
+/***
+ * mce_log_therm_throt_event - Logs the thermal throttling event to mcelog
+ * @cpu: The CPU on which the event occurred.
+ * @status: Event status information
+ *
+ * This function should be called by the thermal interrupt after the
+ * event has been processed and the decision was made to log the event
+ * further.
+ *
+ * The status parameter will be saved to the 'status' field of 'struct mce'
+ * and historically has been the register value of the
+ * MSR_IA32_THERMAL_STATUS (Intel) msr.
+ */
+void mce_log_therm_throt_event(__u64 status)
+{
+       struct mce m;
+
+       mce_setup(&m);
+       m.bank = MCE_THERMAL_BANK;
+       m.status = status;
+       mce_log(&m);
+}
+#endif /* CONFIG_X86_MCE_INTEL */
+
+/*
+ * Periodic polling timer for "silent" machine check errors.  If the
+ * poller finds an MCE, poll 2x faster.  When the poller finds no more
+ * errors, poll 2x slower (up to check_interval seconds).
+ */
+static int check_interval = 5 * 60; /* 5 minutes */
+
+static DEFINE_PER_CPU(int, next_interval); /* in jiffies */
+static DEFINE_PER_CPU(struct timer_list, mce_timer);
+
+static void mcheck_timer(unsigned long data)
+{
+       struct timer_list *t = &per_cpu(mce_timer, data);
+       int *n;
+
+       WARN_ON(smp_processor_id() != data);
+
+       if (mce_available(&current_cpu_data)) {
+               machine_check_poll(MCP_TIMESTAMP,
+                               &__get_cpu_var(mce_poll_banks));
+       }
+
+       /*
+        * Alert userspace if needed.  If we logged an MCE, reduce the
+        * polling interval, otherwise increase the polling interval.
+        */
+       n = &__get_cpu_var(next_interval);
+       if (mce_notify_irq())
+               *n = max(*n/2, HZ/100);
+       else
+               *n = min(*n*2, (int)round_jiffies_relative(check_interval*HZ));
+
+       t->expires = jiffies + *n;
+       add_timer(t);
+}
+
+static void mce_do_trigger(struct work_struct *work)
+{
+       call_usermodehelper(trigger, trigger_argv, NULL, UMH_NO_WAIT);
+}
+
+static DECLARE_WORK(mce_trigger_work, mce_do_trigger);
+
+/*
+ * Notify the user(s) about new machine check events.
+ * Can be called from interrupt context, but not from machine check/NMI
+ * context.
+ */
+int mce_notify_irq(void)
+{
+       /* Not more than two messages every minute */
+       static DEFINE_RATELIMIT_STATE(ratelimit, 60*HZ, 2);
+
+       clear_thread_flag(TIF_MCE_NOTIFY);
+
+       if (test_and_clear_bit(0, &notify_user)) {
+               wake_up_interruptible(&mce_wait);
+
+               /*
+                * There is no risk of missing notifications because
+                * work_pending is always cleared before the function is
+                * executed.
+                */
+               if (trigger[0] && !work_pending(&mce_trigger_work))
+                       schedule_work(&mce_trigger_work);
+
+               if (__ratelimit(&ratelimit))
+                       printk(KERN_INFO "Machine check events logged\n");
+
+               return 1;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mce_notify_irq);
+
+/*
+ * Initialize Machine Checks for a CPU.
+ */
+static int mce_cap_init(void)
+{
+       unsigned b;
+       u64 cap;
+
+       rdmsrl(MSR_IA32_MCG_CAP, cap);
+
+       b = cap & MCG_BANKCNT_MASK;
+       printk(KERN_INFO "mce: CPU supports %d MCE banks\n", b);
+
+       if (b > MAX_NR_BANKS) {
+               printk(KERN_WARNING
+                      "MCE: Using only %u machine check banks out of %u\n",
+                       MAX_NR_BANKS, b);
+               b = MAX_NR_BANKS;
+       }
+
+       /* Don't support asymmetric configurations today */
+       WARN_ON(banks != 0 && b != banks);
+       banks = b;
+       if (!bank) {
+               bank = kmalloc(banks * sizeof(u64), GFP_KERNEL);
+               if (!bank)
+                       return -ENOMEM;
+               memset(bank, 0xff, banks * sizeof(u64));
+       }
+
+       /* Use accurate RIP reporting if available. */
+       if ((cap & MCG_EXT_P) && MCG_EXT_CNT(cap) >= 9)
+               rip_msr = MSR_IA32_MCG_EIP;
+
+       if (cap & MCG_SER_P)
+               mce_ser = 1;
+
+       return 0;
+}
+
+static void mce_init(void)
+{
+       mce_banks_t all_banks;
+       u64 cap;
+       int i;
+
+       /*
+        * Log the machine checks left over from the previous reset.
+        */
+       bitmap_fill(all_banks, MAX_NR_BANKS);
+       machine_check_poll(MCP_UC|(!mce_bootlog ? MCP_DONTLOG : 0), &all_banks);
+
+       set_in_cr4(X86_CR4_MCE);
+
+       rdmsrl(MSR_IA32_MCG_CAP, cap);
+       if (cap & MCG_CTL_P)
+               wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
+
+       for (i = 0; i < banks; i++) {
+               if (skip_bank_init(i))
+                       continue;
+               wrmsrl(MSR_IA32_MC0_CTL+4*i, bank[i]);
+               wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
+       }
+}
+
+/* Add per CPU specific workarounds here */
+static void mce_cpu_quirks(struct cpuinfo_x86 *c)
+{
+       /* This should be disabled by the BIOS, but isn't always */
+       if (c->x86_vendor == X86_VENDOR_AMD) {
+               if (c->x86 == 15 && banks > 4) {
+                       /*
+                        * disable GART TBL walk error reporting, which
+                        * trips off incorrectly with the IOMMU & 3ware
+                        * & Cerberus:
+                        */
+                       clear_bit(10, (unsigned long *)&bank[4]);
+               }
+               if (c->x86 <= 17 && mce_bootlog < 0) {
+                       /*
+                        * Lots of broken BIOS around that don't clear them
+                        * by default and leave crap in there. Don't log:
+                        */
+                       mce_bootlog = 0;
+               }
+               /*
+                * Various K7s with broken bank 0 around. Always disable
+                * by default.
+                */
+                if (c->x86 == 6)
+                       bank[0] = 0;
+       }
+
+       if (c->x86_vendor == X86_VENDOR_INTEL) {
+               /*
+                * SDM documents that on family 6 bank 0 should not be written
+                * because it aliases to another special BIOS controlled
+                * register.
+                * But it's not aliased anymore on model 0x1a+
+                * Don't ignore bank 0 completely because there could be a
+                * valid event later, merely don't write CTL0.
+                */
+
+               if (c->x86 == 6 && c->x86_model < 0x1A)
+                       __set_bit(0, &dont_init_banks);
+
+               /*
+                * All newer Intel systems support MCE broadcasting. Enable
+                * synchronization with a one second timeout.
+                */
+               if ((c->x86 > 6 || (c->x86 == 6 && c->x86_model >= 0xe)) &&
+                       monarch_timeout < 0)
+                       monarch_timeout = USEC_PER_SEC;
+       }
+       if (monarch_timeout < 0)
+               monarch_timeout = 0;
+       if (mce_bootlog != 0)
+               mce_panic_timeout = 30;
+}
+
+static void __cpuinit mce_ancient_init(struct cpuinfo_x86 *c)
+{
+       if (c->x86 != 5)
+               return;
+       switch (c->x86_vendor) {
+       case X86_VENDOR_INTEL:
+               if (mce_p5_enabled())
+                       intel_p5_mcheck_init(c);
+               break;
+       case X86_VENDOR_CENTAUR:
+               winchip_mcheck_init(c);
+               break;
+       }
+}
+
+static void mce_cpu_features(struct cpuinfo_x86 *c)
+{
+       switch (c->x86_vendor) {
+       case X86_VENDOR_INTEL:
+               mce_intel_feature_init(c);
+               break;
+       case X86_VENDOR_AMD:
+               mce_amd_feature_init(c);
+               break;
+       default:
+               break;
+       }
+}
+
+static void mce_init_timer(void)
+{
+       struct timer_list *t = &__get_cpu_var(mce_timer);
+       int *n = &__get_cpu_var(next_interval);
+
+       if (mce_ignore_ce)
+               return;
+
+       *n = check_interval * HZ;
+       if (!*n)
+               return;
+       setup_timer(t, mcheck_timer, smp_processor_id());
+       t->expires = round_jiffies(jiffies + *n);
+       add_timer(t);
+}
+
+/*
+ * Called for each booted CPU to set up machine checks.
+ * Must be called with preempt off:
+ */
+void __cpuinit mcheck_init(struct cpuinfo_x86 *c)
+{
+       if (mce_disabled)
+               return;
+
+       mce_ancient_init(c);
+
+       if (!mce_available(c))
+               return;
+
+       if (mce_cap_init() < 0) {
+               mce_disabled = 1;
+               return;
+       }
+       mce_cpu_quirks(c);
+
+       machine_check_vector = do_machine_check;
+
+       mce_init();
+       mce_cpu_features(c);
+       mce_init_timer();
+       INIT_WORK(&__get_cpu_var(mce_work), mce_process_work);
+}
+
+/*
+ * Character device to read and clear the MCE log.
+ */
+
+static DEFINE_SPINLOCK(mce_state_lock);
+static int             open_count;             /* #times opened */
+static int             open_exclu;             /* already open exclusive? */
+
+static int mce_open(struct inode *inode, struct file *file)
+{
+       spin_lock(&mce_state_lock);
+
+       if (open_exclu || (open_count && (file->f_flags & O_EXCL))) {
+               spin_unlock(&mce_state_lock);
+
+               return -EBUSY;
+       }
+
+       if (file->f_flags & O_EXCL)
+               open_exclu = 1;
+       open_count++;
+
+       spin_unlock(&mce_state_lock);
+
+       return nonseekable_open(inode, file);
+}
+
+static int mce_release(struct inode *inode, struct file *file)
+{
+       spin_lock(&mce_state_lock);
+
+       open_count--;
+       open_exclu = 0;
+
+       spin_unlock(&mce_state_lock);
+
+       return 0;
+}
+
+static void collect_tscs(void *data)
+{
+       unsigned long *cpu_tsc = (unsigned long *)data;
+
+       rdtscll(cpu_tsc[smp_processor_id()]);
+}
+
+static DEFINE_MUTEX(mce_read_mutex);
+
+static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize,
+                       loff_t *off)
+{
+       char __user *buf = ubuf;
+       unsigned long *cpu_tsc;
+       unsigned prev, next;
+       int i, err;
+
+       cpu_tsc = kmalloc(nr_cpu_ids * sizeof(long), GFP_KERNEL);
+       if (!cpu_tsc)
+               return -ENOMEM;
+
+       mutex_lock(&mce_read_mutex);
+       next = rcu_dereference(mcelog.next);
+
+       /* Only supports full reads right now */
+       if (*off != 0 || usize < MCE_LOG_LEN*sizeof(struct mce)) {
+               mutex_unlock(&mce_read_mutex);
+               kfree(cpu_tsc);
+
+               return -EINVAL;
+       }
+
+       err = 0;
+       prev = 0;
+       do {
+               for (i = prev; i < next; i++) {
+                       unsigned long start = jiffies;
+
+                       while (!mcelog.entry[i].finished) {
+                               if (time_after_eq(jiffies, start + 2)) {
+                                       memset(mcelog.entry + i, 0,
+                                              sizeof(struct mce));
+                                       goto timeout;
+                               }
+                               cpu_relax();
+                       }
+                       smp_rmb();
+                       err |= copy_to_user(buf, mcelog.entry + i,
+                                           sizeof(struct mce));
+                       buf += sizeof(struct mce);
+timeout:
+                       ;
+               }
+
+               memset(mcelog.entry + prev, 0,
+                      (next - prev) * sizeof(struct mce));
+               prev = next;
+               next = cmpxchg(&mcelog.next, prev, 0);
+       } while (next != prev);
+
+       synchronize_sched();
+
+       /*
+        * Collect entries that were still getting written before the
+        * synchronize.
+        */
+       on_each_cpu(collect_tscs, cpu_tsc, 1);
+
+       for (i = next; i < MCE_LOG_LEN; i++) {
+               if (mcelog.entry[i].finished &&
+                   mcelog.entry[i].tsc < cpu_tsc[mcelog.entry[i].cpu]) {
+                       err |= copy_to_user(buf, mcelog.entry+i,
+                                           sizeof(struct mce));
+                       smp_rmb();
+                       buf += sizeof(struct mce);
+                       memset(&mcelog.entry[i], 0, sizeof(struct mce));
+               }
+       }
+       mutex_unlock(&mce_read_mutex);
+       kfree(cpu_tsc);
+
+       return err ? -EFAULT : buf - ubuf;
+}
+
+static unsigned int mce_poll(struct file *file, poll_table *wait)
+{
+       poll_wait(file, &mce_wait, wait);
+       if (rcu_dereference(mcelog.next))
+               return POLLIN | POLLRDNORM;
+       return 0;
+}
+
+static long mce_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
+{
+       int __user *p = (int __user *)arg;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       switch (cmd) {
+       case MCE_GET_RECORD_LEN:
+               return put_user(sizeof(struct mce), p);
+       case MCE_GET_LOG_LEN:
+               return put_user(MCE_LOG_LEN, p);
+       case MCE_GETCLEAR_FLAGS: {
+               unsigned flags;
+
+               do {
+                       flags = mcelog.flags;
+               } while (cmpxchg(&mcelog.flags, flags, 0) != flags);
+
+               return put_user(flags, p);
+       }
+       default:
+               return -ENOTTY;
+       }
+}
+
+/* Modified in mce-inject.c, so not static or const */
+struct file_operations mce_chrdev_ops = {
+       .open                   = mce_open,
+       .release                = mce_release,
+       .read                   = mce_read,
+       .poll                   = mce_poll,
+       .unlocked_ioctl         = mce_ioctl,
+};
+EXPORT_SYMBOL_GPL(mce_chrdev_ops);
+
+static struct miscdevice mce_log_device = {
+       MISC_MCELOG_MINOR,
+       "mcelog",
+       &mce_chrdev_ops,
+};
+
+/*
+ * mce=off Disables machine check
+ * mce=no_cmci Disables CMCI
+ * mce=dont_log_ce Clears corrected events silently, no log created for CEs.
+ * mce=ignore_ce Disables polling and CMCI, corrected events are not cleared.
+ * mce=TOLERANCELEVEL[,monarchtimeout] (number, see above)
+ *     monarchtimeout is how long to wait for other CPUs on machine
+ *     check, or 0 to not wait
+ * mce=bootlog Log MCEs from before booting. Disabled by default on AMD.
+ * mce=nobootlog Don't log MCEs from before booting.
+ */
+static int __init mcheck_enable(char *str)
+{
+       if (*str == 0)
+               enable_p5_mce();
+       if (*str == '=')
+               str++;
+       if (!strcmp(str, "off"))
+               mce_disabled = 1;
+       else if (!strcmp(str, "no_cmci"))
+               mce_cmci_disabled = 1;
+       else if (!strcmp(str, "dont_log_ce"))
+               mce_dont_log_ce = 1;
+       else if (!strcmp(str, "ignore_ce"))
+               mce_ignore_ce = 1;
+       else if (!strcmp(str, "bootlog") || !strcmp(str, "nobootlog"))
+               mce_bootlog = (str[0] == 'b');
+       else if (isdigit(str[0])) {
+               get_option(&str, &tolerant);
+               if (*str == ',') {
+                       ++str;
+                       get_option(&str, &monarch_timeout);
+               }
+       } else {
+               printk(KERN_INFO "mce argument %s ignored. Please use /sys\n",
+                      str);
+               return 0;
+       }
+       return 1;
+}
+__setup("mce", mcheck_enable);
+
+/*
+ * Sysfs support
+ */
+
+/*
+ * Disable machine checks on suspend and shutdown. We can't really handle
+ * them later.
+ */
+static int mce_disable(void)
+{
+       int i;
+
+       for (i = 0; i < banks; i++) {
+               if (!skip_bank_init(i))
+                       wrmsrl(MSR_IA32_MC0_CTL + i*4, 0);
+       }
+       return 0;
+}
+
+static int mce_suspend(struct sys_device *dev, pm_message_t state)
+{
+       return mce_disable();
+}
+
+static int mce_shutdown(struct sys_device *dev)
+{
+       return mce_disable();
+}
+
+/*
+ * On resume clear all MCE state. Don't want to see leftovers from the BIOS.
+ * Only one CPU is active at this time, the others get re-added later using
+ * CPU hotplug:
+ */
+static int mce_resume(struct sys_device *dev)
+{
+       mce_init();
+       mce_cpu_features(&current_cpu_data);
+
+       return 0;
+}
+
+static void mce_cpu_restart(void *data)
+{
+       del_timer_sync(&__get_cpu_var(mce_timer));
+       if (mce_available(&current_cpu_data))
+               mce_init();
+       mce_init_timer();
+}
+
+/* Reinit MCEs after user configuration changes */
+static void mce_restart(void)
+{
+       on_each_cpu(mce_cpu_restart, NULL, 1);
+}
+
+static struct sysdev_class mce_sysclass = {
+       .suspend        = mce_suspend,
+       .shutdown       = mce_shutdown,
+       .resume         = mce_resume,
+       .name           = "machinecheck",
+};
+
+DEFINE_PER_CPU(struct sys_device, mce_dev);
+
+__cpuinitdata
+void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu);
+
+static struct sysdev_attribute *bank_attrs;
+
+static ssize_t show_bank(struct sys_device *s, struct sysdev_attribute *attr,
+                        char *buf)
+{
+       u64 b = bank[attr - bank_attrs];
+
+       return sprintf(buf, "%llx\n", b);
+}
+
+static ssize_t set_bank(struct sys_device *s, struct sysdev_attribute *attr,
+                       const char *buf, size_t size)
+{
+       u64 new;
+
+       if (strict_strtoull(buf, 0, &new) < 0)
+               return -EINVAL;
+
+       bank[attr - bank_attrs] = new;
+       mce_restart();
+
+       return size;
+}
+
+static ssize_t
+show_trigger(struct sys_device *s, struct sysdev_attribute *attr, char *buf)
+{
+       strcpy(buf, trigger);
+       strcat(buf, "\n");
+       return strlen(trigger) + 1;
+}
+
+static ssize_t set_trigger(struct sys_device *s, struct sysdev_attribute *attr,
+                               const char *buf, size_t siz)
+{
+       char *p;
+       int len;
+
+       strncpy(trigger, buf, sizeof(trigger));
+       trigger[sizeof(trigger)-1] = 0;
+       len = strlen(trigger);
+       p = strchr(trigger, '\n');
+
+       if (*p)
+               *p = 0;
+
+       return len;
+}
+
+static ssize_t store_int_with_restart(struct sys_device *s,
+                                     struct sysdev_attribute *attr,
+                                     const char *buf, size_t size)
+{
+       ssize_t ret = sysdev_store_int(s, attr, buf, size);
+       mce_restart();
+       return ret;
+}
+
+static SYSDEV_ATTR(trigger, 0644, show_trigger, set_trigger);
+static SYSDEV_INT_ATTR(tolerant, 0644, tolerant);
+static SYSDEV_INT_ATTR(monarch_timeout, 0644, monarch_timeout);
+
+static struct sysdev_ext_attribute attr_check_interval = {
+       _SYSDEV_ATTR(check_interval, 0644, sysdev_show_int,
+                    store_int_with_restart),
+       &check_interval
+};
+
+static struct sysdev_attribute *mce_attrs[] = {
+       &attr_tolerant.attr, &attr_check_interval.attr, &attr_trigger,
+       &attr_monarch_timeout.attr,
+       NULL
+};
+
+static cpumask_var_t mce_dev_initialized;
+
+/* Per cpu sysdev init. All of the cpus still share the same ctrl bank: */
+static __cpuinit int mce_create_device(unsigned int cpu)
+{
+       int err;
+       int i;
+
+       if (!mce_available(&boot_cpu_data))
+               return -EIO;
+
+       memset(&per_cpu(mce_dev, cpu).kobj, 0, sizeof(struct kobject));
+       per_cpu(mce_dev, cpu).id        = cpu;
+       per_cpu(mce_dev, cpu).cls       = &mce_sysclass;
+
+       err = sysdev_register(&per_cpu(mce_dev, cpu));
+       if (err)
+               return err;
+
+       for (i = 0; mce_attrs[i]; i++) {
+               err = sysdev_create_file(&per_cpu(mce_dev, cpu), mce_attrs[i]);
+               if (err)
+                       goto error;
+       }
+       for (i = 0; i < banks; i++) {
+               err = sysdev_create_file(&per_cpu(mce_dev, cpu),
+                                       &bank_attrs[i]);
+               if (err)
+                       goto error2;
+       }
+       cpumask_set_cpu(cpu, mce_dev_initialized);
+
+       return 0;
+error2:
+       while (--i >= 0)
+               sysdev_remove_file(&per_cpu(mce_dev, cpu), &bank_attrs[i]);
+error:
+       while (--i >= 0)
+               sysdev_remove_file(&per_cpu(mce_dev, cpu), mce_attrs[i]);
+
+       sysdev_unregister(&per_cpu(mce_dev, cpu));
+
+       return err;
+}
+
+static __cpuinit void mce_remove_device(unsigned int cpu)
+{
+       int i;
+
+       if (!cpumask_test_cpu(cpu, mce_dev_initialized))
+               return;
+
+       for (i = 0; mce_attrs[i]; i++)
+               sysdev_remove_file(&per_cpu(mce_dev, cpu), mce_attrs[i]);
+
+       for (i = 0; i < banks; i++)
+               sysdev_remove_file(&per_cpu(mce_dev, cpu), &bank_attrs[i]);
+
+       sysdev_unregister(&per_cpu(mce_dev, cpu));
+       cpumask_clear_cpu(cpu, mce_dev_initialized);
+}
+
+/* Make sure there are no machine checks on offlined CPUs. */
+static void 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++) {
+               if (!skip_bank_init(i))
+                       wrmsrl(MSR_IA32_MC0_CTL + i*4, 0);
+       }
+}
+
+static void mce_reenable_cpu(void *h)
+{
+       unsigned long action = *(unsigned long *)h;
+       int i;
+
+       if (!mce_available(&current_cpu_data))
+               return;
+
+       if (!(action & CPU_TASKS_FROZEN))
+               cmci_reenable();
+       for (i = 0; i < banks; i++) {
+               if (!skip_bank_init(i))
+                       wrmsrl(MSR_IA32_MC0_CTL + i*4, bank[i]);
+       }
+}
+
+/* Get notified when a cpu comes on/off. Be hotplug friendly. */
+static int __cpuinit
+mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
+{
+       unsigned int cpu = (unsigned long)hcpu;
+       struct timer_list *t = &per_cpu(mce_timer, cpu);
+
+       switch (action) {
+       case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
+               mce_create_device(cpu);
+               if (threshold_cpu_callback)
+                       threshold_cpu_callback(action, cpu);
+               break;
+       case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
+               if (threshold_cpu_callback)
+                       threshold_cpu_callback(action, cpu);
+               mce_remove_device(cpu);
+               break;
+       case CPU_DOWN_PREPARE:
+       case CPU_DOWN_PREPARE_FROZEN:
+               del_timer_sync(t);
+               smp_call_function_single(cpu, mce_disable_cpu, &action, 1);
+               break;
+       case CPU_DOWN_FAILED:
+       case CPU_DOWN_FAILED_FROZEN:
+               t->expires = round_jiffies(jiffies +
+                                               __get_cpu_var(next_interval));
+               add_timer_on(t, cpu);
+               smp_call_function_single(cpu, mce_reenable_cpu, &action, 1);
+               break;
+       case CPU_POST_DEAD:
+               /* intentionally ignoring frozen here */
+               cmci_rediscover(cpu);
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block mce_cpu_notifier __cpuinitdata = {
+       .notifier_call = mce_cpu_callback,
+};
+
+static __init int mce_init_banks(void)
+{
+       int i;
+
+       bank_attrs = kzalloc(sizeof(struct sysdev_attribute) * banks,
+                               GFP_KERNEL);
+       if (!bank_attrs)
+               return -ENOMEM;
+
+       for (i = 0; i < banks; i++) {
+               struct sysdev_attribute *a = &bank_attrs[i];
+
+               a->attr.name    = kasprintf(GFP_KERNEL, "bank%d", i);
+               if (!a->attr.name)
+                       goto nomem;
+
+               a->attr.mode    = 0644;
+               a->show         = show_bank;
+               a->store        = set_bank;
+       }
+       return 0;
+
+nomem:
+       while (--i >= 0)
+               kfree(bank_attrs[i].attr.name);
+       kfree(bank_attrs);
+       bank_attrs = NULL;
+
+       return -ENOMEM;
+}
+
+static __init int mce_init_device(void)
+{
+       int err;
+       int i = 0;
+
+       if (!mce_available(&boot_cpu_data))
+               return -EIO;
+
+       alloc_cpumask_var(&mce_dev_initialized, GFP_KERNEL);
+
+       err = mce_init_banks();
+       if (err)
+               return err;
+
+       err = sysdev_class_register(&mce_sysclass);
+       if (err)
+               return err;
+
+       for_each_online_cpu(i) {
+               err = mce_create_device(i);
+               if (err)
+                       return err;
+       }
+
+       register_hotcpu_notifier(&mce_cpu_notifier);
+       misc_register(&mce_log_device);
+
+       return err;
+}
+
+device_initcall(mce_init_device);
+
+#else /* CONFIG_X86_OLD_MCE: */
+
+int nr_mce_banks;
+EXPORT_SYMBOL_GPL(nr_mce_banks);       /* non-fatal.o */
+
+/* This has to be run for each processor */
+void mcheck_init(struct cpuinfo_x86 *c)
+{
+       if (mce_disabled == 1)
+               return;
+
+       switch (c->x86_vendor) {
+       case X86_VENDOR_AMD:
+               amd_mcheck_init(c);
+               break;
+
+       case X86_VENDOR_INTEL:
+               if (c->x86 == 5)
+                       intel_p5_mcheck_init(c);
+               if (c->x86 == 6)
+                       intel_p6_mcheck_init(c);
+               if (c->x86 == 15)
+                       intel_p4_mcheck_init(c);
+               break;
+
+       case X86_VENDOR_CENTAUR:
+               if (c->x86 == 5)
+                       winchip_mcheck_init(c);
+               break;
+
+       default:
+               break;
+       }
+       printk(KERN_INFO "mce: CPU supports %d MCE banks\n", nr_mce_banks);
+}
+
+static int __init mcheck_enable(char *str)
+{
+       mce_disabled = -1;
+       return 1;
+}
+
+__setup("mce", mcheck_enable);
+
+#endif /* CONFIG_X86_OLD_MCE */
+
+/*
+ * Old style boot options parsing. Only for compatibility.
+ */
+static int __init mcheck_disable(char *str)
+{
+       mce_disabled = 1;
+       return 1;
+}
+__setup("nomce", mcheck_disable);
index ae9f628838f126863443451d58352f3b158bf464..84a552b458c8368140c5a5a2fc3b96a5db12036c 100644 (file)
@@ -1,14 +1,38 @@
 #include <linux/init.h>
 #include <asm/mce.h>
 
+#ifdef CONFIG_X86_OLD_MCE
 void amd_mcheck_init(struct cpuinfo_x86 *c);
 void intel_p4_mcheck_init(struct cpuinfo_x86 *c);
-void intel_p5_mcheck_init(struct cpuinfo_x86 *c);
 void intel_p6_mcheck_init(struct cpuinfo_x86 *c);
+#endif
+
+#ifdef CONFIG_X86_ANCIENT_MCE
+void intel_p5_mcheck_init(struct cpuinfo_x86 *c);
 void winchip_mcheck_init(struct cpuinfo_x86 *c);
+extern int mce_p5_enable;
+static inline int mce_p5_enabled(void) { return mce_p5_enable; }
+static inline void enable_p5_mce(void) { mce_p5_enable = 1; }
+#else
+static inline void intel_p5_mcheck_init(struct cpuinfo_x86 *c) {}
+static inline void winchip_mcheck_init(struct cpuinfo_x86 *c) {}
+static inline int mce_p5_enabled(void) { return 0; }
+static inline void enable_p5_mce(void) { }
+#endif
 
 /* Call the installed machine check handler for this CPU setup. */
 extern void (*machine_check_vector)(struct pt_regs *, long error_code);
 
+#ifdef CONFIG_X86_OLD_MCE
+
 extern int nr_mce_banks;
 
+void intel_set_thermal_handler(void);
+
+#else
+
+static inline void intel_set_thermal_handler(void) { }
+
+#endif
+
+void intel_init_thermal(struct cpuinfo_x86 *c);
diff --git a/arch/x86/kernel/cpu/mcheck/mce_32.c b/arch/x86/kernel/cpu/mcheck/mce_32.c
deleted file mode 100644 (file)
index 3552119..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * mce.c - x86 Machine Check Exception Reporting
- * (c) 2002 Alan Cox <alan@lxorguk.ukuu.org.uk>, Dave Jones <davej@redhat.com>
- */
-
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/smp.h>
-#include <linux/thread_info.h>
-
-#include <asm/processor.h>
-#include <asm/system.h>
-#include <asm/mce.h>
-
-#include "mce.h"
-
-int mce_disabled;
-int nr_mce_banks;
-
-EXPORT_SYMBOL_GPL(nr_mce_banks);       /* non-fatal.o */
-
-/* Handle unconfigured int18 (should never happen) */
-static void unexpected_machine_check(struct pt_regs *regs, long error_code)
-{
-       printk(KERN_ERR "CPU#%d: Unexpected int18 (Machine Check).\n", smp_processor_id());
-}
-
-/* Call the installed machine check handler for this CPU setup. */
-void (*machine_check_vector)(struct pt_regs *, long error_code) = unexpected_machine_check;
-
-/* This has to be run for each processor */
-void mcheck_init(struct cpuinfo_x86 *c)
-{
-       if (mce_disabled == 1)
-               return;
-
-       switch (c->x86_vendor) {
-       case X86_VENDOR_AMD:
-               amd_mcheck_init(c);
-               break;
-
-       case X86_VENDOR_INTEL:
-               if (c->x86 == 5)
-                       intel_p5_mcheck_init(c);
-               if (c->x86 == 6)
-                       intel_p6_mcheck_init(c);
-               if (c->x86 == 15)
-                       intel_p4_mcheck_init(c);
-               break;
-
-       case X86_VENDOR_CENTAUR:
-               if (c->x86 == 5)
-                       winchip_mcheck_init(c);
-               break;
-
-       default:
-               break;
-       }
-}
-
-static int __init mcheck_disable(char *str)
-{
-       mce_disabled = 1;
-       return 1;
-}
-
-static int __init mcheck_enable(char *str)
-{
-       mce_disabled = -1;
-       return 1;
-}
-
-__setup("nomce", mcheck_disable);
-__setup("mce", mcheck_enable);
diff --git a/arch/x86/kernel/cpu/mcheck/mce_64.c b/arch/x86/kernel/cpu/mcheck/mce_64.c
deleted file mode 100644 (file)
index 289cc48..0000000
+++ /dev/null
@@ -1,1188 +0,0 @@
-/*
- * Machine check handler.
- * K8 parts Copyright 2002,2003 Andi Kleen, SuSE Labs.
- * Rest from unknown author(s).
- * 2004 Andi Kleen. Rewrote most of it.
- * Copyright 2008 Intel Corporation
- * Author: Andi Kleen
- */
-
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/string.h>
-#include <linux/rcupdate.h>
-#include <linux/kallsyms.h>
-#include <linux/sysdev.h>
-#include <linux/miscdevice.h>
-#include <linux/fs.h>
-#include <linux/capability.h>
-#include <linux/cpu.h>
-#include <linux/percpu.h>
-#include <linux/poll.h>
-#include <linux/thread_info.h>
-#include <linux/ctype.h>
-#include <linux/kmod.h>
-#include <linux/kdebug.h>
-#include <linux/kobject.h>
-#include <linux/sysfs.h>
-#include <linux/ratelimit.h>
-#include <asm/processor.h>
-#include <asm/msr.h>
-#include <asm/mce.h>
-#include <asm/uaccess.h>
-#include <asm/smp.h>
-#include <asm/idle.h>
-
-#define MISC_MCELOG_MINOR 227
-
-atomic_t mce_entry;
-
-static int mce_dont_init;
-
-/*
- * Tolerant levels:
- *   0: always panic on uncorrected errors, log corrected errors
- *   1: panic or SIGBUS on uncorrected errors, log corrected errors
- *   2: SIGBUS or log uncorrected errors (if possible), log corrected errors
- *   3: never panic or SIGBUS, log all errors (for testing only)
- */
-static int tolerant = 1;
-static int banks;
-static u64 *bank;
-static unsigned long notify_user;
-static int rip_msr;
-static int mce_bootlog = -1;
-static atomic_t mce_events;
-
-static char trigger[128];
-static char *trigger_argv[2] = { trigger, NULL };
-
-static DECLARE_WAIT_QUEUE_HEAD(mce_wait);
-
-/* MCA banks polled by the period polling timer for corrected events */
-DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = {
-       [0 ... BITS_TO_LONGS(MAX_NR_BANKS)-1] = ~0UL
-};
-
-/* Do initial initialization of a struct mce */
-void mce_setup(struct mce *m)
-{
-       memset(m, 0, sizeof(struct mce));
-       m->cpu = smp_processor_id();
-       rdtscll(m->tsc);
-}
-
-/*
- * Lockless MCE logging infrastructure.
- * This avoids deadlocks on printk locks without having to break locks. Also
- * separate MCEs from kernel messages to avoid bogus bug reports.
- */
-
-static struct mce_log mcelog = {
-       MCE_LOG_SIGNATURE,
-       MCE_LOG_LEN,
-};
-
-void mce_log(struct mce *mce)
-{
-       unsigned next, entry;
-       atomic_inc(&mce_events);
-       mce->finished = 0;
-       wmb();
-       for (;;) {
-               entry = rcu_dereference(mcelog.next);
-               for (;;) {
-                       /* When the buffer fills up discard new entries. Assume
-                          that the earlier errors are the more interesting. */
-                       if (entry >= MCE_LOG_LEN) {
-                               set_bit(MCE_OVERFLOW, (unsigned long *)&mcelog.flags);
-                               return;
-                       }
-                       /* Old left over entry. Skip. */
-                       if (mcelog.entry[entry].finished) {
-                               entry++;
-                               continue;
-                       }
-                       break;
-               }
-               smp_rmb();
-               next = entry + 1;
-               if (cmpxchg(&mcelog.next, entry, next) == entry)
-                       break;
-       }
-       memcpy(mcelog.entry + entry, mce, sizeof(struct mce));
-       wmb();
-       mcelog.entry[entry].finished = 1;
-       wmb();
-
-       set_bit(0, &notify_user);
-}
-
-static void print_mce(struct mce *m)
-{
-       printk(KERN_EMERG "\n"
-              KERN_EMERG "HARDWARE ERROR\n"
-              KERN_EMERG
-              "CPU %d: Machine Check Exception: %16Lx Bank %d: %016Lx\n",
-              m->cpu, m->mcgstatus, m->bank, m->status);
-       if (m->ip) {
-               printk(KERN_EMERG "RIP%s %02x:<%016Lx> ",
-                      !(m->mcgstatus & MCG_STATUS_EIPV) ? " !INEXACT!" : "",
-                      m->cs, m->ip);
-               if (m->cs == __KERNEL_CS)
-                       print_symbol("{%s}", m->ip);
-               printk("\n");
-       }
-       printk(KERN_EMERG "TSC %llx ", m->tsc);
-       if (m->addr)
-               printk("ADDR %llx ", m->addr);
-       if (m->misc)
-               printk("MISC %llx ", m->misc);
-       printk("\n");
-       printk(KERN_EMERG "This is not a software problem!\n");
-       printk(KERN_EMERG "Run through mcelog --ascii to decode "
-              "and contact your hardware vendor\n");
-}
-
-static void mce_panic(char *msg, struct mce *backup, unsigned long start)
-{
-       int i;
-
-       oops_begin();
-       for (i = 0; i < MCE_LOG_LEN; i++) {
-               unsigned long tsc = mcelog.entry[i].tsc;
-
-               if (time_before(tsc, start))
-                       continue;
-               print_mce(&mcelog.entry[i]);
-               if (backup && mcelog.entry[i].tsc == backup->tsc)
-                       backup = NULL;
-       }
-       if (backup)
-               print_mce(backup);
-       panic(msg);
-}
-
-int mce_available(struct cpuinfo_x86 *c)
-{
-       if (mce_dont_init)
-               return 0;
-       return cpu_has(c, X86_FEATURE_MCE) && cpu_has(c, X86_FEATURE_MCA);
-}
-
-static inline void mce_get_rip(struct mce *m, struct pt_regs *regs)
-{
-       if (regs && (m->mcgstatus & MCG_STATUS_RIPV)) {
-               m->ip = regs->ip;
-               m->cs = regs->cs;
-       } else {
-               m->ip = 0;
-               m->cs = 0;
-       }
-       if (rip_msr) {
-               /* Assume the RIP in the MSR is exact. Is this true? */
-               m->mcgstatus |= MCG_STATUS_EIPV;
-               rdmsrl(rip_msr, m->ip);
-               m->cs = 0;
-       }
-}
-
-/*
- * Poll for corrected events or events that happened before reset.
- * Those are just logged through /dev/mcelog.
- *
- * This is executed in standard interrupt context.
- */
-void machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
-{
-       struct mce m;
-       int i;
-
-       mce_setup(&m);
-
-       rdmsrl(MSR_IA32_MCG_STATUS, m.mcgstatus);
-       for (i = 0; i < banks; i++) {
-               if (!bank[i] || !test_bit(i, *b))
-                       continue;
-
-               m.misc = 0;
-               m.addr = 0;
-               m.bank = i;
-               m.tsc = 0;
-
-               barrier();
-               rdmsrl(MSR_IA32_MC0_STATUS + i*4, m.status);
-               if (!(m.status & MCI_STATUS_VAL))
-                       continue;
-
-               /*
-                * Uncorrected events are handled by the exception handler
-                * when it is enabled. But when the exception is disabled log
-                * everything.
-                *
-                * TBD do the same check for MCI_STATUS_EN here?
-                */
-               if ((m.status & MCI_STATUS_UC) && !(flags & MCP_UC))
-                       continue;
-
-               if (m.status & MCI_STATUS_MISCV)
-                       rdmsrl(MSR_IA32_MC0_MISC + i*4, m.misc);
-               if (m.status & MCI_STATUS_ADDRV)
-                       rdmsrl(MSR_IA32_MC0_ADDR + i*4, m.addr);
-
-               if (!(flags & MCP_TIMESTAMP))
-                       m.tsc = 0;
-               /*
-                * Don't get the IP here because it's unlikely to
-                * have anything to do with the actual error location.
-                */
-               if (!(flags & MCP_DONTLOG)) {
-                       mce_log(&m);
-                       add_taint(TAINT_MACHINE_CHECK);
-               }
-
-               /*
-                * Clear state for this bank.
-                */
-               wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
-       }
-
-       /*
-        * Don't clear MCG_STATUS here because it's only defined for
-        * exceptions.
-        */
-}
-
-/*
- * The actual machine check handler. This only handles real
- * exceptions when something got corrupted coming in through int 18.
- *
- * This is executed in NMI context not subject to normal locking rules. This
- * implies that most kernel services cannot be safely used. Don't even
- * think about putting a printk in there!
- */
-void do_machine_check(struct pt_regs * regs, long error_code)
-{
-       struct mce m, panicm;
-       u64 mcestart = 0;
-       int i;
-       int panicm_found = 0;
-       /*
-        * If no_way_out gets set, there is no safe way to recover from this
-        * MCE.  If tolerant is cranked up, we'll try anyway.
-        */
-       int no_way_out = 0;
-       /*
-        * If kill_it gets set, there might be a way to recover from this
-        * error.
-        */
-       int kill_it = 0;
-       DECLARE_BITMAP(toclear, MAX_NR_BANKS);
-
-       atomic_inc(&mce_entry);
-
-       if (notify_die(DIE_NMI, "machine check", regs, error_code,
-                          18, SIGKILL) == NOTIFY_STOP)
-               goto out2;
-       if (!banks)
-               goto out2;
-
-       mce_setup(&m);
-
-       rdmsrl(MSR_IA32_MCG_STATUS, m.mcgstatus);
-       /* if the restart IP is not valid, we're done for */
-       if (!(m.mcgstatus & MCG_STATUS_RIPV))
-               no_way_out = 1;
-
-       rdtscll(mcestart);
-       barrier();
-
-       for (i = 0; i < banks; i++) {
-               __clear_bit(i, toclear);
-               if (!bank[i])
-                       continue;
-
-               m.misc = 0;
-               m.addr = 0;
-               m.bank = i;
-
-               rdmsrl(MSR_IA32_MC0_STATUS + i*4, m.status);
-               if ((m.status & MCI_STATUS_VAL) == 0)
-                       continue;
-
-               /*
-                * Non uncorrected errors are handled by machine_check_poll
-                * Leave them alone.
-                */
-               if ((m.status & MCI_STATUS_UC) == 0)
-                       continue;
-
-               /*
-                * Set taint even when machine check was not enabled.
-                */
-               add_taint(TAINT_MACHINE_CHECK);
-
-               __set_bit(i, toclear);
-
-               if (m.status & MCI_STATUS_EN) {
-                       /* if PCC was set, there's no way out */
-                       no_way_out |= !!(m.status & MCI_STATUS_PCC);
-                       /*
-                        * If this error was uncorrectable and there was
-                        * an overflow, we're in trouble.  If no overflow,
-                        * we might get away with just killing a task.
-                        */
-                       if (m.status & MCI_STATUS_UC) {
-                               if (tolerant < 1 || m.status & MCI_STATUS_OVER)
-                                       no_way_out = 1;
-                               kill_it = 1;
-                       }
-               } else {
-                       /*
-                        * Machine check event was not enabled. Clear, but
-                        * ignore.
-                        */
-                       continue;
-               }
-
-               if (m.status & MCI_STATUS_MISCV)
-                       rdmsrl(MSR_IA32_MC0_MISC + i*4, m.misc);
-               if (m.status & MCI_STATUS_ADDRV)
-                       rdmsrl(MSR_IA32_MC0_ADDR + i*4, m.addr);
-
-               mce_get_rip(&m, regs);
-               mce_log(&m);
-
-               /* Did this bank cause the exception? */
-               /* Assume that the bank with uncorrectable errors did it,
-                  and that there is only a single one. */
-               if ((m.status & MCI_STATUS_UC) && (m.status & MCI_STATUS_EN)) {
-                       panicm = m;
-                       panicm_found = 1;
-               }
-       }
-
-       /* If we didn't find an uncorrectable error, pick
-          the last one (shouldn't happen, just being safe). */
-       if (!panicm_found)
-               panicm = m;
-
-       /*
-        * If we have decided that we just CAN'T continue, and the user
-        *  has not set tolerant to an insane level, give up and die.
-        */
-       if (no_way_out && tolerant < 3)
-               mce_panic("Machine check", &panicm, mcestart);
-
-       /*
-        * If the error seems to be unrecoverable, something should be
-        * done.  Try to kill as little as possible.  If we can kill just
-        * one task, do that.  If the user has set the tolerance very
-        * high, don't try to do anything at all.
-        */
-       if (kill_it && tolerant < 3) {
-               int user_space = 0;
-
-               /*
-                * If the EIPV bit is set, it means the saved IP is the
-                * instruction which caused the MCE.
-                */
-               if (m.mcgstatus & MCG_STATUS_EIPV)
-                       user_space = panicm.ip && (panicm.cs & 3);
-
-               /*
-                * If we know that the error was in user space, send a
-                * SIGBUS.  Otherwise, panic if tolerance is low.
-                *
-                * force_sig() takes an awful lot of locks and has a slight
-                * risk of deadlocking.
-                */
-               if (user_space) {
-                       force_sig(SIGBUS, current);
-               } else if (panic_on_oops || tolerant < 2) {
-                       mce_panic("Uncorrected machine check",
-                               &panicm, mcestart);
-               }
-       }
-
-       /* notify userspace ASAP */
-       set_thread_flag(TIF_MCE_NOTIFY);
-
-       /* the last thing we do is clear state */
-       for (i = 0; i < banks; i++) {
-               if (test_bit(i, toclear))
-                       wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
-       }
-       wrmsrl(MSR_IA32_MCG_STATUS, 0);
- out2:
-       atomic_dec(&mce_entry);
-}
-EXPORT_SYMBOL_GPL(do_machine_check);
-
-#ifdef CONFIG_X86_MCE_INTEL
-/***
- * mce_log_therm_throt_event - Logs the thermal throttling event to mcelog
- * @cpu: The CPU on which the event occurred.
- * @status: Event status information
- *
- * This function should be called by the thermal interrupt after the
- * event has been processed and the decision was made to log the event
- * further.
- *
- * The status parameter will be saved to the 'status' field of 'struct mce'
- * and historically has been the register value of the
- * MSR_IA32_THERMAL_STATUS (Intel) msr.
- */
-void mce_log_therm_throt_event(__u64 status)
-{
-       struct mce m;
-
-       mce_setup(&m);
-       m.bank = MCE_THERMAL_BANK;
-       m.status = status;
-       mce_log(&m);
-}
-#endif /* CONFIG_X86_MCE_INTEL */
-
-/*
- * Periodic polling timer for "silent" machine check errors.  If the
- * poller finds an MCE, poll 2x faster.  When the poller finds no more
- * errors, poll 2x slower (up to check_interval seconds).
- */
-
-static int check_interval = 5 * 60; /* 5 minutes */
-static DEFINE_PER_CPU(int, next_interval); /* in jiffies */
-static void mcheck_timer(unsigned long);
-static DEFINE_PER_CPU(struct timer_list, mce_timer);
-
-static void mcheck_timer(unsigned long data)
-{
-       struct timer_list *t = &per_cpu(mce_timer, data);
-       int *n;
-
-       WARN_ON(smp_processor_id() != data);
-
-       if (mce_available(&current_cpu_data))
-               machine_check_poll(MCP_TIMESTAMP,
-                               &__get_cpu_var(mce_poll_banks));
-
-       /*
-        * Alert userspace if needed.  If we logged an MCE, reduce the
-        * polling interval, otherwise increase the polling interval.
-        */
-       n = &__get_cpu_var(next_interval);
-       if (mce_notify_user()) {
-               *n = max(*n/2, HZ/100);
-       } else {
-               *n = min(*n*2, (int)round_jiffies_relative(check_interval*HZ));
-       }
-
-       t->expires = jiffies + *n;
-       add_timer(t);
-}
-
-static void mce_do_trigger(struct work_struct *work)
-{
-       call_usermodehelper(trigger, trigger_argv, NULL, UMH_NO_WAIT);
-}
-
-static DECLARE_WORK(mce_trigger_work, mce_do_trigger);
-
-/*
- * Notify the user(s) about new machine check events.
- * Can be called from interrupt context, but not from machine check/NMI
- * context.
- */
-int mce_notify_user(void)
-{
-       /* Not more than two messages every minute */
-       static DEFINE_RATELIMIT_STATE(ratelimit, 60*HZ, 2);
-
-       clear_thread_flag(TIF_MCE_NOTIFY);
-       if (test_and_clear_bit(0, &notify_user)) {
-               wake_up_interruptible(&mce_wait);
-
-               /*
-                * There is no risk of missing notifications because
-                * work_pending is always cleared before the function is
-                * executed.
-                */
-               if (trigger[0] && !work_pending(&mce_trigger_work))
-                       schedule_work(&mce_trigger_work);
-
-               if (__ratelimit(&ratelimit))
-                       printk(KERN_INFO "Machine check events logged\n");
-
-               return 1;
-       }
-       return 0;
-}
-
-/* see if the idle task needs to notify userspace */
-static int
-mce_idle_callback(struct notifier_block *nfb, unsigned long action, void *junk)
-{
-       /* IDLE_END should be safe - interrupts are back on */
-       if (action == IDLE_END && test_thread_flag(TIF_MCE_NOTIFY))
-               mce_notify_user();
-
-       return NOTIFY_OK;
-}
-
-static struct notifier_block mce_idle_notifier = {
-       .notifier_call = mce_idle_callback,
-};
-
-static __init int periodic_mcheck_init(void)
-{
-       idle_notifier_register(&mce_idle_notifier);
-       return 0;
-}
-__initcall(periodic_mcheck_init);
-
-/*
- * Initialize Machine Checks for a CPU.
- */
-static int mce_cap_init(void)
-{
-       u64 cap;
-       unsigned b;
-
-       rdmsrl(MSR_IA32_MCG_CAP, cap);
-       b = cap & 0xff;
-       if (b > MAX_NR_BANKS) {
-               printk(KERN_WARNING
-                      "MCE: Using only %u machine check banks out of %u\n",
-                       MAX_NR_BANKS, b);
-               b = MAX_NR_BANKS;
-       }
-
-       /* Don't support asymmetric configurations today */
-       WARN_ON(banks != 0 && b != banks);
-       banks = b;
-       if (!bank) {
-               bank = kmalloc(banks * sizeof(u64), GFP_KERNEL);
-               if (!bank)
-                       return -ENOMEM;
-               memset(bank, 0xff, banks * sizeof(u64));
-       }
-
-       /* Use accurate RIP reporting if available. */
-       if ((cap & (1<<9)) && ((cap >> 16) & 0xff) >= 9)
-               rip_msr = MSR_IA32_MCG_EIP;
-
-       return 0;
-}
-
-static void mce_init(void *dummy)
-{
-       u64 cap;
-       int i;
-       mce_banks_t all_banks;
-
-       /*
-        * Log the machine checks left over from the previous reset.
-        */
-       bitmap_fill(all_banks, MAX_NR_BANKS);
-       machine_check_poll(MCP_UC|(!mce_bootlog ? MCP_DONTLOG : 0), &all_banks);
-
-       set_in_cr4(X86_CR4_MCE);
-
-       rdmsrl(MSR_IA32_MCG_CAP, cap);
-       if (cap & MCG_CTL_P)
-               wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
-
-       for (i = 0; i < banks; i++) {
-               wrmsrl(MSR_IA32_MC0_CTL+4*i, bank[i]);
-               wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
-       }
-}
-
-/* Add per CPU specific workarounds here */
-static void mce_cpu_quirks(struct cpuinfo_x86 *c)
-{
-       /* This should be disabled by the BIOS, but isn't always */
-       if (c->x86_vendor == X86_VENDOR_AMD) {
-               if (c->x86 == 15 && banks > 4)
-                       /* disable GART TBL walk error reporting, which trips off
-                          incorrectly with the IOMMU & 3ware & Cerberus. */
-                       clear_bit(10, (unsigned long *)&bank[4]);
-               if(c->x86 <= 17 && mce_bootlog < 0)
-                       /* Lots of broken BIOS around that don't clear them
-                          by default and leave crap in there. Don't log. */
-                       mce_bootlog = 0;
-       }
-
-}
-
-static void mce_cpu_features(struct cpuinfo_x86 *c)
-{
-       switch (c->x86_vendor) {
-       case X86_VENDOR_INTEL:
-               mce_intel_feature_init(c);
-               break;
-       case X86_VENDOR_AMD:
-               mce_amd_feature_init(c);
-               break;
-       default:
-               break;
-       }
-}
-
-static void mce_init_timer(void)
-{
-       struct timer_list *t = &__get_cpu_var(mce_timer);
-       int *n = &__get_cpu_var(next_interval);
-
-       *n = check_interval * HZ;
-       if (!*n)
-               return;
-       setup_timer(t, mcheck_timer, smp_processor_id());
-       t->expires = round_jiffies(jiffies + *n);
-       add_timer(t);
-}
-
-/*
- * Called for each booted CPU to set up machine checks.
- * Must be called with preempt off.
- */
-void __cpuinit mcheck_init(struct cpuinfo_x86 *c)
-{
-       if (!mce_available(c))
-               return;
-
-       if (mce_cap_init() < 0) {
-               mce_dont_init = 1;
-               return;
-       }
-       mce_cpu_quirks(c);
-
-       mce_init(NULL);
-       mce_cpu_features(c);
-       mce_init_timer();
-}
-
-/*
- * Character device to read and clear the MCE log.
- */
-
-static DEFINE_SPINLOCK(mce_state_lock);
-static int open_count; /* #times opened */
-static int open_exclu; /* already open exclusive? */
-
-static int mce_open(struct inode *inode, struct file *file)
-{
-       lock_kernel();
-       spin_lock(&mce_state_lock);
-
-       if (open_exclu || (open_count && (file->f_flags & O_EXCL))) {
-               spin_unlock(&mce_state_lock);
-               unlock_kernel();
-               return -EBUSY;
-       }
-
-       if (file->f_flags & O_EXCL)
-               open_exclu = 1;
-       open_count++;
-
-       spin_unlock(&mce_state_lock);
-       unlock_kernel();
-
-       return nonseekable_open(inode, file);
-}
-
-static int mce_release(struct inode *inode, struct file *file)
-{
-       spin_lock(&mce_state_lock);
-
-       open_count--;
-       open_exclu = 0;
-
-       spin_unlock(&mce_state_lock);
-
-       return 0;
-}
-
-static void collect_tscs(void *data)
-{
-       unsigned long *cpu_tsc = (unsigned long *)data;
-
-       rdtscll(cpu_tsc[smp_processor_id()]);
-}
-
-static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize,
-                       loff_t *off)
-{
-       unsigned long *cpu_tsc;
-       static DEFINE_MUTEX(mce_read_mutex);
-       unsigned prev, next;
-       char __user *buf = ubuf;
-       int i, err;
-
-       cpu_tsc = kmalloc(nr_cpu_ids * sizeof(long), GFP_KERNEL);
-       if (!cpu_tsc)
-               return -ENOMEM;
-
-       mutex_lock(&mce_read_mutex);
-       next = rcu_dereference(mcelog.next);
-
-       /* Only supports full reads right now */
-       if (*off != 0 || usize < MCE_LOG_LEN*sizeof(struct mce)) {
-               mutex_unlock(&mce_read_mutex);
-               kfree(cpu_tsc);
-               return -EINVAL;
-       }
-
-       err = 0;
-       prev = 0;
-       do {
-               for (i = prev; i < next; i++) {
-                       unsigned long start = jiffies;
-
-                       while (!mcelog.entry[i].finished) {
-                               if (time_after_eq(jiffies, start + 2)) {
-                                       memset(mcelog.entry + i, 0,
-                                              sizeof(struct mce));
-                                       goto timeout;
-                               }
-                               cpu_relax();
-                       }
-                       smp_rmb();
-                       err |= copy_to_user(buf, mcelog.entry + i,
-                                           sizeof(struct mce));
-                       buf += sizeof(struct mce);
-timeout:
-                       ;
-               }
-
-               memset(mcelog.entry + prev, 0,
-                      (next - prev) * sizeof(struct mce));
-               prev = next;
-               next = cmpxchg(&mcelog.next, prev, 0);
-       } while (next != prev);
-
-       synchronize_sched();
-
-       /*
-        * Collect entries that were still getting written before the
-        * synchronize.
-        */
-       on_each_cpu(collect_tscs, cpu_tsc, 1);
-       for (i = next; i < MCE_LOG_LEN; i++) {
-               if (mcelog.entry[i].finished &&
-                   mcelog.entry[i].tsc < cpu_tsc[mcelog.entry[i].cpu]) {
-                       err |= copy_to_user(buf, mcelog.entry+i,
-                                           sizeof(struct mce));
-                       smp_rmb();
-                       buf += sizeof(struct mce);
-                       memset(&mcelog.entry[i], 0, sizeof(struct mce));
-               }
-       }
-       mutex_unlock(&mce_read_mutex);
-       kfree(cpu_tsc);
-       return err ? -EFAULT : buf - ubuf;
-}
-
-static unsigned int mce_poll(struct file *file, poll_table *wait)
-{
-       poll_wait(file, &mce_wait, wait);
-       if (rcu_dereference(mcelog.next))
-               return POLLIN | POLLRDNORM;
-       return 0;
-}
-
-static long mce_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
-{
-       int __user *p = (int __user *)arg;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       switch (cmd) {
-       case MCE_GET_RECORD_LEN:
-               return put_user(sizeof(struct mce), p);
-       case MCE_GET_LOG_LEN:
-               return put_user(MCE_LOG_LEN, p);
-       case MCE_GETCLEAR_FLAGS: {
-               unsigned flags;
-
-               do {
-                       flags = mcelog.flags;
-               } while (cmpxchg(&mcelog.flags, flags, 0) != flags);
-               return put_user(flags, p);
-       }
-       default:
-               return -ENOTTY;
-       }
-}
-
-static const struct file_operations mce_chrdev_ops = {
-       .open = mce_open,
-       .release = mce_release,
-       .read = mce_read,
-       .poll = mce_poll,
-       .unlocked_ioctl = mce_ioctl,
-};
-
-static struct miscdevice mce_log_device = {
-       MISC_MCELOG_MINOR,
-       "mcelog",
-       &mce_chrdev_ops,
-};
-
-/*
- * Old style boot options parsing. Only for compatibility.
- */
-static int __init mcheck_disable(char *str)
-{
-       mce_dont_init = 1;
-       return 1;
-}
-
-/* mce=off disables machine check.
-   mce=TOLERANCELEVEL (number, see above)
-   mce=bootlog Log MCEs from before booting. Disabled by default on AMD.
-   mce=nobootlog Don't log MCEs from before booting. */
-static int __init mcheck_enable(char *str)
-{
-       if (!strcmp(str, "off"))
-               mce_dont_init = 1;
-       else if (!strcmp(str, "bootlog") || !strcmp(str,"nobootlog"))
-               mce_bootlog = str[0] == 'b';
-       else if (isdigit(str[0]))
-               get_option(&str, &tolerant);
-       else
-               printk("mce= argument %s ignored. Please use /sys", str);
-       return 1;
-}
-
-__setup("nomce", mcheck_disable);
-__setup("mce=", mcheck_enable);
-
-/*
- * Sysfs support
- */
-
-/*
- * Disable machine checks on suspend and shutdown. We can't really handle
- * them later.
- */
-static int mce_disable(void)
-{
-       int i;
-
-       for (i = 0; i < banks; i++)
-               wrmsrl(MSR_IA32_MC0_CTL + i*4, 0);
-       return 0;
-}
-
-static int mce_suspend(struct sys_device *dev, pm_message_t state)
-{
-       return mce_disable();
-}
-
-static int mce_shutdown(struct sys_device *dev)
-{
-       return mce_disable();
-}
-
-/* On resume clear all MCE state. Don't want to see leftovers from the BIOS.
-   Only one CPU is active at this time, the others get readded later using
-   CPU hotplug. */
-static int mce_resume(struct sys_device *dev)
-{
-       mce_init(NULL);
-       mce_cpu_features(&current_cpu_data);
-       return 0;
-}
-
-static void mce_cpu_restart(void *data)
-{
-       del_timer_sync(&__get_cpu_var(mce_timer));
-       if (mce_available(&current_cpu_data))
-               mce_init(NULL);
-       mce_init_timer();
-}
-
-/* Reinit MCEs after user configuration changes */
-static void mce_restart(void)
-{
-       on_each_cpu(mce_cpu_restart, NULL, 1);
-}
-
-static struct sysdev_class mce_sysclass = {
-       .suspend = mce_suspend,
-       .shutdown = mce_shutdown,
-       .resume = mce_resume,
-       .name = "machinecheck",
-};
-
-DEFINE_PER_CPU(struct sys_device, device_mce);
-void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu) __cpuinitdata;
-
-/* Why are there no generic functions for this? */
-#define ACCESSOR(name, var, start) \
-       static ssize_t show_ ## name(struct sys_device *s,              \
-                                    struct sysdev_attribute *attr,     \
-                                    char *buf) {                       \
-               return sprintf(buf, "%lx\n", (unsigned long)var);       \
-       }                                                               \
-       static ssize_t set_ ## name(struct sys_device *s,               \
-                                   struct sysdev_attribute *attr,      \
-                                   const char *buf, size_t siz) {      \
-               char *end;                                              \
-               unsigned long new = simple_strtoul(buf, &end, 0);       \
-               if (end == buf) return -EINVAL;                         \
-               var = new;                                              \
-               start;                                                  \
-               return end-buf;                                         \
-       }                                                               \
-       static SYSDEV_ATTR(name, 0644, show_ ## name, set_ ## name);
-
-static struct sysdev_attribute *bank_attrs;
-
-static ssize_t show_bank(struct sys_device *s, struct sysdev_attribute *attr,
-                        char *buf)
-{
-       u64 b = bank[attr - bank_attrs];
-       return sprintf(buf, "%llx\n", b);
-}
-
-static ssize_t set_bank(struct sys_device *s, struct sysdev_attribute *attr,
-                       const char *buf, size_t siz)
-{
-       char *end;
-       u64 new = simple_strtoull(buf, &end, 0);
-       if (end == buf)
-               return -EINVAL;
-       bank[attr - bank_attrs] = new;
-       mce_restart();
-       return end-buf;
-}
-
-static ssize_t show_trigger(struct sys_device *s, struct sysdev_attribute *attr,
-                               char *buf)
-{
-       strcpy(buf, trigger);
-       strcat(buf, "\n");
-       return strlen(trigger) + 1;
-}
-
-static ssize_t set_trigger(struct sys_device *s, struct sysdev_attribute *attr,
-                               const char *buf,size_t siz)
-{
-       char *p;
-       int len;
-       strncpy(trigger, buf, sizeof(trigger));
-       trigger[sizeof(trigger)-1] = 0;
-       len = strlen(trigger);
-       p = strchr(trigger, '\n');
-       if (*p) *p = 0;
-       return len;
-}
-
-static SYSDEV_ATTR(trigger, 0644, show_trigger, set_trigger);
-static SYSDEV_INT_ATTR(tolerant, 0644, tolerant);
-ACCESSOR(check_interval,check_interval,mce_restart())
-static struct sysdev_attribute *mce_attributes[] = {
-       &attr_tolerant.attr, &attr_check_interval, &attr_trigger,
-       NULL
-};
-
-static cpumask_var_t mce_device_initialized;
-
-/* Per cpu sysdev init.  All of the cpus still share the same ctl bank */
-static __cpuinit int mce_create_device(unsigned int cpu)
-{
-       int err;
-       int i;
-
-       if (!mce_available(&boot_cpu_data))
-               return -EIO;
-
-       memset(&per_cpu(device_mce, cpu).kobj, 0, sizeof(struct kobject));
-       per_cpu(device_mce,cpu).id = cpu;
-       per_cpu(device_mce,cpu).cls = &mce_sysclass;
-
-       err = sysdev_register(&per_cpu(device_mce,cpu));
-       if (err)
-               return err;
-
-       for (i = 0; mce_attributes[i]; i++) {
-               err = sysdev_create_file(&per_cpu(device_mce,cpu),
-                                        mce_attributes[i]);
-               if (err)
-                       goto error;
-       }
-       for (i = 0; i < banks; i++) {
-               err = sysdev_create_file(&per_cpu(device_mce, cpu),
-                                       &bank_attrs[i]);
-               if (err)
-                       goto error2;
-       }
-       cpumask_set_cpu(cpu, mce_device_initialized);
-
-       return 0;
-error2:
-       while (--i >= 0) {
-               sysdev_remove_file(&per_cpu(device_mce, cpu),
-                                       &bank_attrs[i]);
-       }
-error:
-       while (--i >= 0) {
-               sysdev_remove_file(&per_cpu(device_mce,cpu),
-                                  mce_attributes[i]);
-       }
-       sysdev_unregister(&per_cpu(device_mce,cpu));
-
-       return err;
-}
-
-static __cpuinit void mce_remove_device(unsigned int cpu)
-{
-       int i;
-
-       if (!cpumask_test_cpu(cpu, mce_device_initialized))
-               return;
-
-       for (i = 0; mce_attributes[i]; i++)
-               sysdev_remove_file(&per_cpu(device_mce,cpu),
-                       mce_attributes[i]);
-       for (i = 0; i < banks; i++)
-               sysdev_remove_file(&per_cpu(device_mce, cpu),
-                       &bank_attrs[i]);
-       sysdev_unregister(&per_cpu(device_mce,cpu));
-       cpumask_clear_cpu(cpu, mce_device_initialized);
-}
-
-/* Make sure there are no machine checks on offlined CPUs. */
-static void mce_disable_cpu(void *h)
-{
-       int i;
-       unsigned long action = *(unsigned long *)h;
-
-       if (!mce_available(&current_cpu_data))
-               return;
-       if (!(action & CPU_TASKS_FROZEN))
-               cmci_clear();
-       for (i = 0; i < banks; i++)
-               wrmsrl(MSR_IA32_MC0_CTL + i*4, 0);
-}
-
-static void mce_reenable_cpu(void *h)
-{
-       int i;
-       unsigned long action = *(unsigned long *)h;
-
-       if (!mce_available(&current_cpu_data))
-               return;
-       if (!(action & CPU_TASKS_FROZEN))
-               cmci_reenable();
-       for (i = 0; i < banks; i++)
-               wrmsrl(MSR_IA32_MC0_CTL + i*4, bank[i]);
-}
-
-/* Get notified when a cpu comes on/off. Be hotplug friendly. */
-static int __cpuinit mce_cpu_callback(struct notifier_block *nfb,
-                                     unsigned long action, void *hcpu)
-{
-       unsigned int cpu = (unsigned long)hcpu;
-       struct timer_list *t = &per_cpu(mce_timer, cpu);
-
-       switch (action) {
-       case CPU_ONLINE:
-       case CPU_ONLINE_FROZEN:
-               mce_create_device(cpu);
-               if (threshold_cpu_callback)
-                       threshold_cpu_callback(action, cpu);
-               break;
-       case CPU_DEAD:
-       case CPU_DEAD_FROZEN:
-               if (threshold_cpu_callback)
-                       threshold_cpu_callback(action, cpu);
-               mce_remove_device(cpu);
-               break;
-       case CPU_DOWN_PREPARE:
-       case CPU_DOWN_PREPARE_FROZEN:
-               del_timer_sync(t);
-               smp_call_function_single(cpu, mce_disable_cpu, &action, 1);
-               break;
-       case CPU_DOWN_FAILED:
-       case CPU_DOWN_FAILED_FROZEN:
-               t->expires = round_jiffies(jiffies +
-                                               __get_cpu_var(next_interval));
-               add_timer_on(t, cpu);
-               smp_call_function_single(cpu, mce_reenable_cpu, &action, 1);
-               break;
-       case CPU_POST_DEAD:
-               /* intentionally ignoring frozen here */
-               cmci_rediscover(cpu);
-               break;
-       }
-       return NOTIFY_OK;
-}
-
-static struct notifier_block mce_cpu_notifier __cpuinitdata = {
-       .notifier_call = mce_cpu_callback,
-};
-
-static __init int mce_init_banks(void)
-{
-       int i;
-
-       bank_attrs = kzalloc(sizeof(struct sysdev_attribute) * banks,
-                               GFP_KERNEL);
-       if (!bank_attrs)
-               return -ENOMEM;
-
-       for (i = 0; i < banks; i++) {
-               struct sysdev_attribute *a = &bank_attrs[i];
-               a->attr.name = kasprintf(GFP_KERNEL, "bank%d", i);
-               if (!a->attr.name)
-                       goto nomem;
-               a->attr.mode = 0644;
-               a->show = show_bank;
-               a->store = set_bank;
-       }
-       return 0;
-
-nomem:
-       while (--i >= 0)
-               kfree(bank_attrs[i].attr.name);
-       kfree(bank_attrs);
-       bank_attrs = NULL;
-       return -ENOMEM;
-}
-
-static __init int mce_init_device(void)
-{
-       int err;
-       int i = 0;
-
-       if (!mce_available(&boot_cpu_data))
-               return -EIO;
-
-       zalloc_cpumask_var(&mce_device_initialized, GFP_KERNEL);
-
-       err = mce_init_banks();
-       if (err)
-               return err;
-
-       err = sysdev_class_register(&mce_sysclass);
-       if (err)
-               return err;
-
-       for_each_online_cpu(i) {
-               err = mce_create_device(i);
-               if (err)
-                       return err;
-       }
-
-       register_hotcpu_notifier(&mce_cpu_notifier);
-       misc_register(&mce_log_device);
-       return err;
-}
-
-device_initcall(mce_init_device);
index 56dde9c4bc96b8fe3202a2051a500efe52853b0f..ddae21620bda67a8c0fecf724bf2456821659c5f 100644 (file)
  *
  *  All MC4_MISCi registers are shared between multi-cores
  */
-
-#include <linux/cpu.h>
-#include <linux/errno.h>
-#include <linux/init.h>
 #include <linux/interrupt.h>
-#include <linux/kobject.h>
 #include <linux/notifier.h>
-#include <linux/sched.h>
-#include <linux/smp.h>
+#include <linux/kobject.h>
+#include <linux/percpu.h>
 #include <linux/sysdev.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
 #include <linux/sysfs.h>
+#include <linux/init.h>
+#include <linux/cpu.h>
+#include <linux/smp.h>
+
 #include <asm/apic.h>
+#include <asm/idle.h>
 #include <asm/mce.h>
 #include <asm/msr.h>
-#include <asm/percpu.h>
-#include <asm/idle.h>
 
 #define PFX               "mce_threshold: "
 #define VERSION           "version 1.1.1"
 #define MCG_XBLK_ADDR     0xC0000400
 
 struct threshold_block {
-       unsigned int block;
-       unsigned int bank;
-       unsigned int cpu;
-       u32 address;
-       u16 interrupt_enable;
-       u16 threshold_limit;
-       struct kobject kobj;
-       struct list_head miscj;
+       unsigned int            block;
+       unsigned int            bank;
+       unsigned int            cpu;
+       u32                     address;
+       u16                     interrupt_enable;
+       u16                     threshold_limit;
+       struct kobject          kobj;
+       struct list_head        miscj;
 };
 
 /* defaults used early on boot */
 static struct threshold_block threshold_defaults = {
-       .interrupt_enable = 0,
-       .threshold_limit = THRESHOLD_MAX,
+       .interrupt_enable       = 0,
+       .threshold_limit        = THRESHOLD_MAX,
 };
 
 struct threshold_bank {
-       struct kobject *kobj;
-       struct threshold_block *blocks;
-       cpumask_var_t cpus;
+       struct kobject          *kobj;
+       struct threshold_block  *blocks;
+       cpumask_var_t           cpus;
 };
 static DEFINE_PER_CPU(struct threshold_bank *, threshold_banks[NR_BANKS]);
 
@@ -86,9 +86,9 @@ static void amd_threshold_interrupt(void);
  */
 
 struct thresh_restart {
-       struct threshold_block *b;
-       int reset;
-       u16 old_limit;
+       struct threshold_block  *b;
+       int                     reset;
+       u16                     old_limit;
 };
 
 /* must be called with correct cpu affinity */
@@ -110,6 +110,7 @@ static void threshold_restart_bank(void *_tr)
        } else if (tr->old_limit) {     /* change limit w/o reset */
                int new_count = (mci_misc_hi & THRESHOLD_MAX) +
                    (tr->old_limit - tr->b->threshold_limit);
+
                mci_misc_hi = (mci_misc_hi & ~MASK_ERR_COUNT_HI) |
                    (new_count & THRESHOLD_MAX);
        }
@@ -125,11 +126,11 @@ static void threshold_restart_bank(void *_tr)
 /* cpu init entry point, called from mce.c with preempt off */
 void mce_amd_feature_init(struct cpuinfo_x86 *c)
 {
-       unsigned int bank, block;
        unsigned int cpu = smp_processor_id();
-       u8 lvt_off;
        u32 low = 0, high = 0, address = 0;
+       unsigned int bank, block;
        struct thresh_restart tr;
+       u8 lvt_off;
 
        for (bank = 0; bank < NR_BANKS; ++bank) {
                for (block = 0; block < NR_BLOCKS; ++block) {
@@ -140,8 +141,7 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)
                                if (!address)
                                        break;
                                address += MCG_XBLK_ADDR;
-                       }
-                       else
+                       } else
                                ++address;
 
                        if (rdmsr_safe(address, &low, &high))
@@ -193,9 +193,9 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)
  */
 static void amd_threshold_interrupt(void)
 {
+       u32 low = 0, high = 0, address = 0;
        unsigned int bank, block;
        struct mce m;
-       u32 low = 0, high = 0, address = 0;
 
        mce_setup(&m);
 
@@ -204,16 +204,16 @@ static void amd_threshold_interrupt(void)
                if (!(per_cpu(bank_map, m.cpu) & (1 << bank)))
                        continue;
                for (block = 0; block < NR_BLOCKS; ++block) {
-                       if (block == 0)
+                       if (block == 0) {
                                address = MSR_IA32_MC0_MISC + bank * 4;
-                       else if (block == 1) {
+                       else if (block == 1) {
                                address = (low & MASK_BLKPTR_LO) >> 21;
                                if (!address)
                                        break;
                                address += MCG_XBLK_ADDR;
-                       }
-                       else
+                       } else {
                                ++address;
+                       }
 
                        if (rdmsr_safe(address, &low, &high))
                                break;
@@ -229,8 +229,10 @@ static void amd_threshold_interrupt(void)
                             (high & MASK_LOCKED_HI))
                                continue;
 
-                       /* Log the machine check that caused the threshold
-                          event. */
+                       /*
+                        * Log the machine check that caused the threshold
+                        * event.
+                        */
                        machine_check_poll(MCP_TIMESTAMP,
                                        &__get_cpu_var(mce_poll_banks));
 
@@ -254,48 +256,52 @@ static void amd_threshold_interrupt(void)
 
 struct threshold_attr {
        struct attribute attr;
-       ssize_t(*show) (struct threshold_block *, char *);
-       ssize_t(*store) (struct threshold_block *, const char *, size_t count);
+       ssize_t (*show) (struct threshold_block *, char *);
+       ssize_t (*store) (struct threshold_block *, const char *, size_t count);
 };
 
-#define SHOW_FIELDS(name)                                           \
-static ssize_t show_ ## name(struct threshold_block * b, char *buf) \
-{                                                                   \
-        return sprintf(buf, "%lx\n", (unsigned long) b->name);      \
+#define SHOW_FIELDS(name)                                              \
+static ssize_t show_ ## name(struct threshold_block *b, char *buf)     \
+{                                                                      \
+       return sprintf(buf, "%lx\n", (unsigned long) b->name);          \
 }
 SHOW_FIELDS(interrupt_enable)
 SHOW_FIELDS(threshold_limit)
 
-static ssize_t store_interrupt_enable(struct threshold_block *b,
-                                     const char *buf, size_t count)
+static ssize_t
+store_interrupt_enable(struct threshold_block *b, const char *buf, size_t size)
 {
-       char *end;
        struct thresh_restart tr;
-       unsigned long new = simple_strtoul(buf, &end, 0);
-       if (end == buf)
+       unsigned long new;
+
+       if (strict_strtoul(buf, 0, &new) < 0)
                return -EINVAL;
+
        b->interrupt_enable = !!new;
 
-       tr.b = b;
-       tr.reset = 0;
-       tr.old_limit = 0;
+       tr.b            = b;
+       tr.reset        = 0;
+       tr.old_limit    = 0;
+
        smp_call_function_single(b->cpu, threshold_restart_bank, &tr, 1);
 
-       return end - buf;
+       return size;
 }
 
-static ssize_t store_threshold_limit(struct threshold_block *b,
-                                    const char *buf, size_t count)
+static ssize_t
+store_threshold_limit(struct threshold_block *b, const char *buf, size_t size)
 {
-       char *end;
        struct thresh_restart tr;
-       unsigned long new = simple_strtoul(buf, &end, 0);
-       if (end == buf)
+       unsigned long new;
+
+       if (strict_strtoul(buf, 0, &new) < 0)
                return -EINVAL;
+
        if (new > THRESHOLD_MAX)
                new = THRESHOLD_MAX;
        if (new < 1)
                new = 1;
+
        tr.old_limit = b->threshold_limit;
        b->threshold_limit = new;
        tr.b = b;
@@ -303,12 +309,12 @@ static ssize_t store_threshold_limit(struct threshold_block *b,
 
        smp_call_function_single(b->cpu, threshold_restart_bank, &tr, 1);
 
-       return end - buf;
+       return size;
 }
 
 struct threshold_block_cross_cpu {
-       struct threshold_block *tb;
-       long retval;
+       struct threshold_block  *tb;
+       long                    retval;
 };
 
 static void local_error_count_handler(void *_tbcc)
@@ -338,16 +344,13 @@ static ssize_t store_error_count(struct threshold_block *b,
        return 1;
 }
 
-#define THRESHOLD_ATTR(_name,_mode,_show,_store) {            \
-        .attr = {.name = __stringify(_name), .mode = _mode }, \
-        .show = _show,                                        \
-        .store = _store,                                      \
+#define RW_ATTR(val)                                                   \
+static struct threshold_attr val = {                                   \
+       .attr   = {.name = __stringify(val), .mode = 0644 },            \
+       .show   = show_## val,                                          \
+       .store  = store_## val,                                         \
 };
 
-#define RW_ATTR(name)                                           \
-static struct threshold_attr name =                             \
-        THRESHOLD_ATTR(name, 0644, show_## name, store_## name)
-
 RW_ATTR(interrupt_enable);
 RW_ATTR(threshold_limit);
 RW_ATTR(error_count);
@@ -359,15 +362,17 @@ static struct attribute *default_attrs[] = {
        NULL
 };
 
-#define to_block(k) container_of(k, struct threshold_block, kobj)
-#define to_attr(a) container_of(a, struct threshold_attr, attr)
+#define to_block(k)    container_of(k, struct threshold_block, kobj)
+#define to_attr(a)     container_of(a, struct threshold_attr, attr)
 
 static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
 {
        struct threshold_block *b = to_block(kobj);
        struct threshold_attr *a = to_attr(attr);
        ssize_t ret;
+
        ret = a->show ? a->show(b, buf) : -EIO;
+
        return ret;
 }
 
@@ -377,18 +382,20 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
        struct threshold_block *b = to_block(kobj);
        struct threshold_attr *a = to_attr(attr);
        ssize_t ret;
+
        ret = a->store ? a->store(b, buf, count) : -EIO;
+
        return ret;
 }
 
 static struct sysfs_ops threshold_ops = {
-       .show = show,
-       .store = store,
+       .show                   = show,
+       .store                  = store,
 };
 
 static struct kobj_type threshold_ktype = {
-       .sysfs_ops = &threshold_ops,
-       .default_attrs = default_attrs,
+       .sysfs_ops              = &threshold_ops,
+       .default_attrs          = default_attrs,
 };
 
 static __cpuinit int allocate_threshold_blocks(unsigned int cpu,
@@ -396,9 +403,9 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu,
                                               unsigned int block,
                                               u32 address)
 {
-       int err;
-       u32 low, high;
        struct threshold_block *b = NULL;
+       u32 low, high;
+       int err;
 
        if ((bank >= NR_BANKS) || (block >= NR_BLOCKS))
                return 0;
@@ -421,20 +428,21 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu,
        if (!b)
                return -ENOMEM;
 
-       b->block = block;
-       b->bank = bank;
-       b->cpu = cpu;
-       b->address = address;
-       b->interrupt_enable = 0;
-       b->threshold_limit = THRESHOLD_MAX;
+       b->block                = block;
+       b->bank                 = bank;
+       b->cpu                  = cpu;
+       b->address              = address;
+       b->interrupt_enable     = 0;
+       b->threshold_limit      = THRESHOLD_MAX;
 
        INIT_LIST_HEAD(&b->miscj);
 
-       if (per_cpu(threshold_banks, cpu)[bank]->blocks)
+       if (per_cpu(threshold_banks, cpu)[bank]->blocks) {
                list_add(&b->miscj,
                         &per_cpu(threshold_banks, cpu)[bank]->blocks->miscj);
-       else
+       } else {
                per_cpu(threshold_banks, cpu)[bank]->blocks = b;
+       }
 
        err = kobject_init_and_add(&b->kobj, &threshold_ktype,
                                   per_cpu(threshold_banks, cpu)[bank]->kobj,
@@ -447,8 +455,9 @@ recurse:
                if (!address)
                        return 0;
                address += MCG_XBLK_ADDR;
-       } else
+       } else {
                ++address;
+       }
 
        err = allocate_threshold_blocks(cpu, bank, ++block, address);
        if (err)
@@ -500,13 +509,14 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
                if (!b)
                        goto out;
 
-               err = sysfs_create_link(&per_cpu(device_mce, cpu).kobj,
+               err = sysfs_create_link(&per_cpu(mce_dev, cpu).kobj,
                                        b->kobj, name);
                if (err)
                        goto out;
 
                cpumask_copy(b->cpus, cpu_core_mask(cpu));
                per_cpu(threshold_banks, cpu)[bank] = b;
+
                goto out;
        }
 #endif
@@ -522,7 +532,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
                goto out;
        }
 
-       b->kobj = kobject_create_and_add(name, &per_cpu(device_mce, cpu).kobj);
+       b->kobj = kobject_create_and_add(name, &per_cpu(mce_dev, cpu).kobj);
        if (!b->kobj)
                goto out_free;
 
@@ -542,7 +552,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
                if (i == cpu)
                        continue;
 
-               err = sysfs_create_link(&per_cpu(device_mce, i).kobj,
+               err = sysfs_create_link(&per_cpu(mce_dev, i).kobj,
                                        b->kobj, name);
                if (err)
                        goto out;
@@ -605,15 +615,13 @@ static void deallocate_threshold_block(unsigned int cpu,
 
 static void threshold_remove_bank(unsigned int cpu, int bank)
 {
-       int i = 0;
        struct threshold_bank *b;
        char name[32];
+       int i = 0;
 
        b = per_cpu(threshold_banks, cpu)[bank];
-
        if (!b)
                return;
-
        if (!b->blocks)
                goto free_out;
 
@@ -622,8 +630,9 @@ static void threshold_remove_bank(unsigned int cpu, int bank)
 #ifdef CONFIG_SMP
        /* sibling symlink */
        if (shared_bank[bank] && b->blocks->cpu != cpu) {
-               sysfs_remove_link(&per_cpu(device_mce, cpu).kobj, name);
+               sysfs_remove_link(&per_cpu(mce_dev, cpu).kobj, name);
                per_cpu(threshold_banks, cpu)[bank] = NULL;
+
                return;
        }
 #endif
@@ -633,7 +642,7 @@ static void threshold_remove_bank(unsigned int cpu, int bank)
                if (i == cpu)
                        continue;
 
-               sysfs_remove_link(&per_cpu(device_mce, i).kobj, name);
+               sysfs_remove_link(&per_cpu(mce_dev, i).kobj, name);
                per_cpu(threshold_banks, i)[bank] = NULL;
        }
 
@@ -659,12 +668,9 @@ static void threshold_remove_device(unsigned int cpu)
 }
 
 /* get notified when a cpu comes on/off */
-static void __cpuinit amd_64_threshold_cpu_callback(unsigned long action,
-                                                    unsigned int cpu)
+static void __cpuinit
+amd_64_threshold_cpu_callback(unsigned long action, unsigned int cpu)
 {
-       if (cpu >= NR_CPUS)
-               return;
-
        switch (action) {
        case CPU_ONLINE:
        case CPU_ONLINE_FROZEN:
@@ -686,11 +692,12 @@ static __init int threshold_init_device(void)
        /* to hit CPUs online before the notifier is up */
        for_each_online_cpu(lcpu) {
                int err = threshold_create_device(lcpu);
+
                if (err)
                        return err;
        }
        threshold_cpu_callback = amd_64_threshold_cpu_callback;
+
        return 0;
 }
-
 device_initcall(threshold_init_device);
diff --git a/arch/x86/kernel/cpu/mcheck/mce_intel.c b/arch/x86/kernel/cpu/mcheck/mce_intel.c
new file mode 100644 (file)
index 0000000..2b011d2
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Common code for Intel machine checks
+ */
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+
+#include <asm/therm_throt.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/apic.h>
+#include <asm/msr.h>
+
+#include "mce.h"
+
+void intel_init_thermal(struct cpuinfo_x86 *c)
+{
+       unsigned int cpu = smp_processor_id();
+       int tm2 = 0;
+       u32 l, h;
+
+       /* Thermal monitoring depends on ACPI and clock modulation*/
+       if (!cpu_has(c, X86_FEATURE_ACPI) || !cpu_has(c, X86_FEATURE_ACC))
+               return;
+
+       /*
+        * First check if its enabled already, in which case there might
+        * be some SMM goo which handles it, so we can't even put a handler
+        * since it might be delivered via SMI already:
+        */
+       rdmsr(MSR_IA32_MISC_ENABLE, l, h);
+       h = apic_read(APIC_LVTTHMR);
+       if ((l & MSR_IA32_MISC_ENABLE_TM1) && (h & APIC_DM_SMI)) {
+               printk(KERN_DEBUG
+                      "CPU%d: Thermal monitoring handled by SMI\n", cpu);
+               return;
+       }
+
+       if (cpu_has(c, X86_FEATURE_TM2) && (l & MSR_IA32_MISC_ENABLE_TM2))
+               tm2 = 1;
+
+       /* Check whether a vector already exists */
+       if (h & APIC_VECTOR_MASK) {
+               printk(KERN_DEBUG
+                      "CPU%d: Thermal LVT vector (%#x) already installed\n",
+                      cpu, (h & APIC_VECTOR_MASK));
+               return;
+       }
+
+       /* We'll mask the thermal vector in the lapic till we're ready: */
+       h = THERMAL_APIC_VECTOR | APIC_DM_FIXED | APIC_LVT_MASKED;
+       apic_write(APIC_LVTTHMR, h);
+
+       rdmsr(MSR_IA32_THERM_INTERRUPT, l, h);
+       wrmsr(MSR_IA32_THERM_INTERRUPT,
+               l | (THERM_INT_LOW_ENABLE | THERM_INT_HIGH_ENABLE), h);
+
+       intel_set_thermal_handler();
+
+       rdmsr(MSR_IA32_MISC_ENABLE, l, h);
+       wrmsr(MSR_IA32_MISC_ENABLE, l | MSR_IA32_MISC_ENABLE_TM1, h);
+
+       /* Unmask the thermal vector: */
+       l = apic_read(APIC_LVTTHMR);
+       apic_write(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
+
+       printk(KERN_INFO "CPU%d: Thermal monitoring enabled (%s)\n",
+              cpu, tm2 ? "TM2" : "TM1");
+
+       /* enable thermal throttle processing */
+       atomic_set(&therm_throt_en, 1);
+}
index 65a0fceedcd77ce7ed0088a5b24b0432caebd990..f2ef6952c4003284c5d0886a299d14ca734ba09c 100644 (file)
@@ -16,6 +16,8 @@
 #include <asm/idle.h>
 #include <asm/therm_throt.h>
 
+#include "mce.h"
+
 asmlinkage void smp_thermal_interrupt(void)
 {
        __u64 msr_val;
@@ -26,67 +28,13 @@ asmlinkage void smp_thermal_interrupt(void)
        irq_enter();
 
        rdmsrl(MSR_IA32_THERM_STATUS, msr_val);
-       if (therm_throt_process(msr_val & 1))
+       if (therm_throt_process(msr_val & THERM_STATUS_PROCHOT))
                mce_log_therm_throt_event(msr_val);
 
        inc_irq_stat(irq_thermal_count);
        irq_exit();
 }
 
-static void intel_init_thermal(struct cpuinfo_x86 *c)
-{
-       u32 l, h;
-       int tm2 = 0;
-       unsigned int cpu = smp_processor_id();
-
-       if (!cpu_has(c, X86_FEATURE_ACPI))
-               return;
-
-       if (!cpu_has(c, X86_FEATURE_ACC))
-               return;
-
-       /* first check if TM1 is already enabled by the BIOS, in which
-        * case there might be some SMM goo which handles it, so we can't even
-        * put a handler since it might be delivered via SMI already.
-        */
-       rdmsr(MSR_IA32_MISC_ENABLE, l, h);
-       h = apic_read(APIC_LVTTHMR);
-       if ((l & MSR_IA32_MISC_ENABLE_TM1) && (h & APIC_DM_SMI)) {
-               printk(KERN_DEBUG
-                      "CPU%d: Thermal monitoring handled by SMI\n", cpu);
-               return;
-       }
-
-       if (cpu_has(c, X86_FEATURE_TM2) && (l & MSR_IA32_MISC_ENABLE_TM2))
-               tm2 = 1;
-
-       if (h & APIC_VECTOR_MASK) {
-               printk(KERN_DEBUG
-                      "CPU%d: Thermal LVT vector (%#x) already "
-                      "installed\n", cpu, (h & APIC_VECTOR_MASK));
-               return;
-       }
-
-       h = THERMAL_APIC_VECTOR;
-       h |= (APIC_DM_FIXED | APIC_LVT_MASKED);
-       apic_write(APIC_LVTTHMR, h);
-
-       rdmsr(MSR_IA32_THERM_INTERRUPT, l, h);
-       wrmsr(MSR_IA32_THERM_INTERRUPT, l | 0x03, h);
-
-       rdmsr(MSR_IA32_MISC_ENABLE, l, h);
-       wrmsr(MSR_IA32_MISC_ENABLE, l | MSR_IA32_MISC_ENABLE_TM1, h);
-
-       l = apic_read(APIC_LVTTHMR);
-       apic_write(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
-       printk(KERN_INFO "CPU%d: Thermal monitoring enabled (%s)\n",
-               cpu, tm2 ? "TM2" : "TM1");
-
-       /* enable thermal throttle processing */
-       atomic_set(&therm_throt_en, 1);
-       return;
-}
-
 /*
  * Support for Intel Correct Machine Check Interrupts. This allows
  * the CPU to raise an interrupt when a corrected machine check happened.
@@ -108,6 +56,9 @@ static int cmci_supported(int *banks)
 {
        u64 cap;
 
+       if (mce_cmci_disabled || mce_ignore_ce)
+               return 0;
+
        /*
         * Vendor check is not strictly needed, but the initial
         * initialization is vendor keyed and this
@@ -131,7 +82,7 @@ static int cmci_supported(int *banks)
 static void intel_threshold_interrupt(void)
 {
        machine_check_poll(MCP_TIMESTAMP, &__get_cpu_var(mce_banks_owned));
-       mce_notify_user();
+       mce_notify_irq();
 }
 
 static void print_update(char *type, int *hdr, int num)
@@ -247,7 +198,7 @@ void cmci_rediscover(int dying)
                return;
        cpumask_copy(old, &current->cpus_allowed);
 
-       for_each_online_cpu (cpu) {
+       for_each_online_cpu(cpu) {
                if (cpu == dying)
                        continue;
                if (set_cpus_allowed_ptr(current, cpumask_of(cpu)))
index a74af128efc917384909d44b51834aaf40282647..70b710420f744ba7566b707da0c71c6dfd7086e5 100644 (file)
@@ -6,15 +6,14 @@
  * This file contains routines to check for non-fatal MCEs every 15s
  *
  */
-
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/jiffies.h>
-#include <linux/workqueue.h>
 #include <linux/interrupt.h>
-#include <linux/smp.h>
+#include <linux/workqueue.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/smp.h>
 
 #include <asm/processor.h>
 #include <asm/system.h>
@@ -22,9 +21,9 @@
 
 #include "mce.h"
 
-static int firstbank;
+static int             firstbank;
 
-#define MCE_RATE       15*HZ   /* timer rate is 15s */
+#define MCE_RATE       (15*HZ) /* timer rate is 15s */
 
 static void mce_checkregs(void *info)
 {
@@ -34,23 +33,24 @@ static void mce_checkregs(void *info)
        for (i = firstbank; i < nr_mce_banks; i++) {
                rdmsr(MSR_IA32_MC0_STATUS+i*4, low, high);
 
-               if (high & (1<<31)) {
-                       printk(KERN_INFO "MCE: The hardware reports a non "
-                               "fatal, correctable incident occurred on "
-                               "CPU %d.\n",
+               if (!(high & (1<<31)))
+                       continue;
+
+               printk(KERN_INFO "MCE: The hardware reports a non fatal, "
+                       "correctable incident occurred on CPU %d.\n",
                                smp_processor_id());
-                       printk(KERN_INFO "Bank %d: %08x%08x\n", i, high, low);
-
-                       /*
-                        * Scrub the error so we don't pick it up in MCE_RATE
-                        * seconds time.
-                        */
-                       wrmsr(MSR_IA32_MC0_STATUS+i*4, 0UL, 0UL);
-
-                       /* Serialize */
-                       wmb();
-                       add_taint(TAINT_MACHINE_CHECK);
-               }
+
+               printk(KERN_INFO "Bank %d: %08x%08x\n", i, high, low);
+
+               /*
+                * Scrub the error so we don't pick it up in MCE_RATE
+                * seconds time:
+                */
+               wrmsr(MSR_IA32_MC0_STATUS+i*4, 0UL, 0UL);
+
+               /* Serialize: */
+               wmb();
+               add_taint(TAINT_MACHINE_CHECK);
        }
 }
 
@@ -77,16 +77,17 @@ static int __init init_nonfatal_mce_checker(void)
 
        /* Some Athlons misbehave when we frob bank 0 */
        if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
-               boot_cpu_data.x86 == 6)
-                       firstbank = 1;
+                                               boot_cpu_data.x86 == 6)
+               firstbank = 1;
        else
-                       firstbank = 0;
+               firstbank = 0;
 
        /*
         * Check for non-fatal errors every MCE_RATE s
         */
        schedule_delayed_work(&mce_work, round_jiffies_relative(MCE_RATE));
        printk(KERN_INFO "Machine check exception polling timer started.\n");
+
        return 0;
 }
 module_init(init_nonfatal_mce_checker);
index f53bdcbaf38255ae95eb936a5127548b09c8dbf2..82cee108a2d3471f8173d939bedaf9662978b843 100644 (file)
@@ -2,18 +2,17 @@
  * P4 specific Machine Check Exception Reporting
  */
 
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
 #include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
 #include <linux/smp.h>
 
+#include <asm/therm_throt.h>
 #include <asm/processor.h>
 #include <asm/system.h>
-#include <asm/msr.h>
 #include <asm/apic.h>
-
-#include <asm/therm_throt.h>
+#include <asm/msr.h>
 
 #include "mce.h"
 
@@ -36,6 +35,7 @@ static int mce_num_extended_msrs;
 
 
 #ifdef CONFIG_X86_MCE_P4THERMAL
+
 static void unexpected_thermal_interrupt(struct pt_regs *regs)
 {
        printk(KERN_ERR "CPU%d: Unexpected LVT TMR interrupt!\n",
@@ -43,7 +43,7 @@ static void unexpected_thermal_interrupt(struct pt_regs *regs)
        add_taint(TAINT_MACHINE_CHECK);
 }
 
-/* P4/Xeon Thermal transition interrupt handler */
+/* P4/Xeon Thermal transition interrupt handler: */
 static void intel_thermal_interrupt(struct pt_regs *regs)
 {
        __u64 msr_val;
@@ -51,11 +51,12 @@ static void intel_thermal_interrupt(struct pt_regs *regs)
        ack_APIC_irq();
 
        rdmsrl(MSR_IA32_THERM_STATUS, msr_val);
-       therm_throt_process(msr_val & 0x1);
+       therm_throt_process(msr_val & THERM_STATUS_PROCHOT);
 }
 
-/* Thermal interrupt handler for this CPU setup */
-static void (*vendor_thermal_interrupt)(struct pt_regs *regs) = unexpected_thermal_interrupt;
+/* Thermal interrupt handler for this CPU setup: */
+static void (*vendor_thermal_interrupt)(struct pt_regs *regs) =
+                                               unexpected_thermal_interrupt;
 
 void smp_thermal_interrupt(struct pt_regs *regs)
 {
@@ -65,67 +66,15 @@ void smp_thermal_interrupt(struct pt_regs *regs)
        irq_exit();
 }
 
-/* P4/Xeon Thermal regulation detect and init */
-static void intel_init_thermal(struct cpuinfo_x86 *c)
+void intel_set_thermal_handler(void)
 {
-       u32 l, h;
-       unsigned int cpu = smp_processor_id();
-
-       /* Thermal monitoring */
-       if (!cpu_has(c, X86_FEATURE_ACPI))
-               return; /* -ENODEV */
-
-       /* Clock modulation */
-       if (!cpu_has(c, X86_FEATURE_ACC))
-               return; /* -ENODEV */
-
-       /* first check if its enabled already, in which case there might
-        * be some SMM goo which handles it, so we can't even put a handler
-        * since it might be delivered via SMI already -zwanem.
-        */
-       rdmsr(MSR_IA32_MISC_ENABLE, l, h);
-       h = apic_read(APIC_LVTTHMR);
-       if ((l & MSR_IA32_MISC_ENABLE_TM1) && (h & APIC_DM_SMI)) {
-               printk(KERN_DEBUG "CPU%d: Thermal monitoring handled by SMI\n",
-                               cpu);
-               return; /* -EBUSY */
-       }
-
-       /* check whether a vector already exists, temporarily masked? */
-       if (h & APIC_VECTOR_MASK) {
-               printk(KERN_DEBUG "CPU%d: Thermal LVT vector (%#x) already "
-                               "installed\n",
-                       cpu, (h & APIC_VECTOR_MASK));
-               return; /* -EBUSY */
-       }
-
-       /* The temperature transition interrupt handler setup */
-       h = THERMAL_APIC_VECTOR;                /* our delivery vector */
-       h |= (APIC_DM_FIXED | APIC_LVT_MASKED); /* we'll mask till we're ready */
-       apic_write(APIC_LVTTHMR, h);
-
-       rdmsr(MSR_IA32_THERM_INTERRUPT, l, h);
-       wrmsr(MSR_IA32_THERM_INTERRUPT, l | 0x03 , h);
-
-       /* ok we're good to go... */
        vendor_thermal_interrupt = intel_thermal_interrupt;
-
-       rdmsr(MSR_IA32_MISC_ENABLE, l, h);
-       wrmsr(MSR_IA32_MISC_ENABLE, l | MSR_IA32_MISC_ENABLE_TM1, h);
-
-       l = apic_read(APIC_LVTTHMR);
-       apic_write(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
-       printk(KERN_INFO "CPU%d: Thermal monitoring enabled\n", cpu);
-
-       /* enable thermal throttle processing */
-       atomic_set(&therm_throt_en, 1);
-       return;
 }
-#endif /* CONFIG_X86_MCE_P4THERMAL */
 
+#endif /* CONFIG_X86_MCE_P4THERMAL */
 
 /* P4/Xeon Extended MCE MSR retrieval, return 0 if unsupported */
-static inline void intel_get_extended_msrs(struct intel_mce_extended_msrs *r)
+static void intel_get_extended_msrs(struct intel_mce_extended_msrs *r)
 {
        u32 h;
 
@@ -143,9 +92,9 @@ static inline void intel_get_extended_msrs(struct intel_mce_extended_msrs *r)
 
 static void intel_machine_check(struct pt_regs *regs, long error_code)
 {
-       int recover = 1;
        u32 alow, ahigh, high, low;
        u32 mcgstl, mcgsth;
+       int recover = 1;
        int i;
 
        rdmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
@@ -157,7 +106,9 @@ static void intel_machine_check(struct pt_regs *regs, long error_code)
 
        if (mce_num_extended_msrs > 0) {
                struct intel_mce_extended_msrs dbg;
+
                intel_get_extended_msrs(&dbg);
+
                printk(KERN_DEBUG "CPU %d: EIP: %08x EFLAGS: %08x\n"
                        "\teax: %08x ebx: %08x ecx: %08x edx: %08x\n"
                        "\tesi: %08x edi: %08x ebp: %08x esp: %08x\n",
@@ -171,6 +122,7 @@ static void intel_machine_check(struct pt_regs *regs, long error_code)
                if (high & (1<<31)) {
                        char misc[20];
                        char addr[24];
+
                        misc[0] = addr[0] = '\0';
                        if (high & (1<<29))
                                recover |= 1;
@@ -196,6 +148,7 @@ static void intel_machine_check(struct pt_regs *regs, long error_code)
                panic("Unable to continue");
 
        printk(KERN_EMERG "Attempting to continue.\n");
+
        /*
         * Do not clear the MSR_IA32_MCi_STATUS if the error is not
         * recoverable/continuable.This will allow BIOS to look at the MSRs
@@ -217,7 +170,6 @@ static void intel_machine_check(struct pt_regs *regs, long error_code)
        wrmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
 }
 
-
 void intel_p4_mcheck_init(struct cpuinfo_x86 *c)
 {
        u32 l, h;
index c9f77ea69edc710fca386f4cbf0d9017d148fd57..015f481ab1b043448d8f10bbe3c0160a480e7e88 100644 (file)
@@ -2,11 +2,10 @@
  * P5 specific Machine Check Exception Reporting
  * (C) Copyright 2002 Alan Cox <alan@lxorguk.ukuu.org.uk>
  */
-
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
 #include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
 #include <linux/smp.h>
 
 #include <asm/processor.h>
 
 #include "mce.h"
 
-/* Machine check handler for Pentium class Intel */
+/* By default disabled */
+int            mce_p5_enable;
+
+/* Machine check handler for Pentium class Intel CPUs: */
 static void pentium_machine_check(struct pt_regs *regs, long error_code)
 {
        u32 loaddr, hi, lotype;
+
        rdmsr(MSR_IA32_P5_MC_ADDR, loaddr, hi);
        rdmsr(MSR_IA32_P5_MC_TYPE, lotype, hi);
-       printk(KERN_EMERG "CPU#%d: Machine Check Exception:  0x%8X (type 0x%8X).\n", smp_processor_id(), loaddr, lotype);
-       if (lotype&(1<<5))
-               printk(KERN_EMERG "CPU#%d: Possible thermal failure (CPU on fire ?).\n", smp_processor_id());
+
+       printk(KERN_EMERG
+               "CPU#%d: Machine Check Exception:  0x%8X (type 0x%8X).\n",
+               smp_processor_id(), loaddr, lotype);
+
+       if (lotype & (1<<5)) {
+               printk(KERN_EMERG
+                       "CPU#%d: Possible thermal failure (CPU on fire ?).\n",
+                       smp_processor_id());
+       }
+
        add_taint(TAINT_MACHINE_CHECK);
 }
 
-/* Set up machine check reporting for processors with Intel style MCE */
+/* Set up machine check reporting for processors with Intel style MCE: */
 void intel_p5_mcheck_init(struct cpuinfo_x86 *c)
 {
        u32 l, h;
 
-       /*Check for MCE support */
+       /* Check for MCE support: */
        if (!cpu_has(c, X86_FEATURE_MCE))
                return;
 
-       /* Default P5 to off as its often misconnected */
+#ifdef CONFIG_X86_OLD_MCE
+       /* Default P5 to off as its often misconnected: */
        if (mce_disabled != -1)
                return;
+#endif
+
        machine_check_vector = pentium_machine_check;
+       /* Make sure the vector pointer is visible before we enable MCEs: */
        wmb();
 
-       /* Read registers before enabling */
+       /* Read registers before enabling: */
        rdmsr(MSR_IA32_P5_MC_ADDR, l, h);
        rdmsr(MSR_IA32_P5_MC_TYPE, l, h);
-       printk(KERN_INFO "Intel old style machine check architecture supported.\n");
+       printk(KERN_INFO
+              "Intel old style machine check architecture supported.\n");
 
-       /* Enable MCE */
+       /* Enable MCE: */
        set_in_cr4(X86_CR4_MCE);
-       printk(KERN_INFO "Intel old style machine check reporting enabled on CPU#%d.\n", smp_processor_id());
+       printk(KERN_INFO
+              "Intel old style machine check reporting enabled on CPU#%d.\n",
+              smp_processor_id());
 }
index 2ac52d7b434bd2b56543295e8bb326faa65493d7..43c24e667457f2b8598da9984bb59cde18aa00c4 100644 (file)
@@ -2,11 +2,10 @@
  * P6 specific Machine Check Exception Reporting
  * (C) Copyright 2002 Alan Cox <alan@lxorguk.ukuu.org.uk>
  */
-
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
 #include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
 #include <linux/smp.h>
 
 #include <asm/processor.h>
@@ -18,9 +17,9 @@
 /* Machine Check Handler For PII/PIII */
 static void intel_machine_check(struct pt_regs *regs, long error_code)
 {
-       int recover = 1;
        u32 alow, ahigh, high, low;
        u32 mcgstl, mcgsth;
+       int recover = 1;
        int i;
 
        rdmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
@@ -35,12 +34,16 @@ static void intel_machine_check(struct pt_regs *regs, long error_code)
                if (high & (1<<31)) {
                        char misc[20];
                        char addr[24];
-                       misc[0] = addr[0] = '\0';
+
+                       misc[0] = '\0';
+                       addr[0] = '\0';
+
                        if (high & (1<<29))
                                recover |= 1;
                        if (high & (1<<25))
                                recover |= 2;
                        high &= ~(1<<31);
+
                        if (high & (1<<27)) {
                                rdmsr(MSR_IA32_MC0_MISC+i*4, alow, ahigh);
                                snprintf(misc, 20, "[%08x%08x]", ahigh, alow);
@@ -49,6 +52,7 @@ static void intel_machine_check(struct pt_regs *regs, long error_code)
                                rdmsr(MSR_IA32_MC0_ADDR+i*4, alow, ahigh);
                                snprintf(addr, 24, " at %08x%08x", ahigh, alow);
                        }
+
                        printk(KERN_EMERG "CPU %d: Bank %d: %08x%08x%s%s\n",
                                smp_processor_id(), i, high, low, misc, addr);
                }
@@ -63,16 +67,17 @@ static void intel_machine_check(struct pt_regs *regs, long error_code)
        /*
         * Do not clear the MSR_IA32_MCi_STATUS if the error is not
         * recoverable/continuable.This will allow BIOS to look at the MSRs
-        * for errors if the OS could not log the error.
+        * for errors if the OS could not log the error:
         */
        for (i = 0; i < nr_mce_banks; i++) {
                unsigned int msr;
+
                msr = MSR_IA32_MC0_STATUS+i*4;
                rdmsr(msr, low, high);
                if (high & (1<<31)) {
-                       /* Clear it */
+                       /* Clear it: */
                        wrmsr(msr, 0UL, 0UL);
-                       /* Serialize */
+                       /* Serialize: */
                        wmb();
                        add_taint(TAINT_MACHINE_CHECK);
                }
@@ -81,7 +86,7 @@ static void intel_machine_check(struct pt_regs *regs, long error_code)
        wrmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
 }
 
-/* Set up machine check reporting for processors with Intel style MCE */
+/* Set up machine check reporting for processors with Intel style MCE: */
 void intel_p6_mcheck_init(struct cpuinfo_x86 *c)
 {
        u32 l, h;
@@ -97,6 +102,7 @@ void intel_p6_mcheck_init(struct cpuinfo_x86 *c)
 
        /* Ok machine check is available */
        machine_check_vector = intel_machine_check;
+       /* Make sure the vector pointer is visible before we enable MCEs: */
        wmb();
 
        printk(KERN_INFO "Intel machine check architecture supported.\n");
index d5ae2243f0b959bf26839c476850faec8a6a4476..7b1ae2e20ba5a6a3d63322ef825994914cb26ec4 100644 (file)
@@ -1,7 +1,7 @@
 /*
- *
  * Thermal throttle event support code (such as syslog messaging and rate
  * limiting) that was factored out from x86_64 (mce_intel.c) and i386 (p4.c).
+ *
  * This allows consistent reporting of CPU thermal throttle events.
  *
  * Maintains a counter in /sys that keeps track of the number of thermal
  * Credits: Adapted from Zwane Mwaikambo's original code in mce_intel.c.
  *          Inspired by Ross Biro's and Al Borchers' counter code.
  */
-
+#include <linux/notifier.h>
+#include <linux/jiffies.h>
 #include <linux/percpu.h>
 #include <linux/sysdev.h>
 #include <linux/cpu.h>
-#include <asm/cpu.h>
-#include <linux/notifier.h>
-#include <linux/jiffies.h>
+
 #include <asm/therm_throt.h>
 
 /* How long to wait between reporting thermal events */
-#define CHECK_INTERVAL              (300 * HZ)
+#define CHECK_INTERVAL         (300 * HZ)
 
 static DEFINE_PER_CPU(__u64, next_check) = INITIAL_JIFFIES;
 static DEFINE_PER_CPU(unsigned long, thermal_throttle_count);
-atomic_t therm_throt_en = ATOMIC_INIT(0);
+
+atomic_t therm_throt_en                = ATOMIC_INIT(0);
 
 #ifdef CONFIG_SYSFS
-#define define_therm_throt_sysdev_one_ro(_name)                              \
-        static SYSDEV_ATTR(_name, 0444, therm_throt_sysdev_show_##_name, NULL)
-
-#define define_therm_throt_sysdev_show_func(name)                            \
-static ssize_t therm_throt_sysdev_show_##name(struct sys_device *dev,        \
-                                       struct sysdev_attribute *attr,       \
-                                              char *buf)                     \
-{                                                                            \
-       unsigned int cpu = dev->id;                                          \
-       ssize_t ret;                                                         \
-                                                                             \
-       preempt_disable();              /* CPU hotplug */                    \
-       if (cpu_online(cpu))                                                 \
-               ret = sprintf(buf, "%lu\n",                                  \
-                             per_cpu(thermal_throttle_##name, cpu));        \
-       else                                                                 \
-               ret = 0;                                                     \
-       preempt_enable();                                                    \
-                                                                             \
-       return ret;                                                          \
+#define define_therm_throt_sysdev_one_ro(_name)                                \
+       static SYSDEV_ATTR(_name, 0444, therm_throt_sysdev_show_##_name, NULL)
+
+#define define_therm_throt_sysdev_show_func(name)                      \
+static ssize_t therm_throt_sysdev_show_##name(struct sys_device *dev,  \
+                                       struct sysdev_attribute *attr,  \
+                                             char *buf)                \
+{                                                                      \
+       unsigned int cpu = dev->id;                                     \
+       ssize_t ret;                                                    \
+                                                                       \
+       preempt_disable();      /* CPU hotplug */                       \
+       if (cpu_online(cpu))                                            \
+               ret = sprintf(buf, "%lu\n",                             \
+                             per_cpu(thermal_throttle_##name, cpu));   \
+       else                                                            \
+               ret = 0;                                                \
+       preempt_enable();                                               \
+                                                                       \
+       return ret;                                                     \
 }
 
 define_therm_throt_sysdev_show_func(count);
@@ -61,8 +61,8 @@ static struct attribute *thermal_throttle_attrs[] = {
 };
 
 static struct attribute_group thermal_throttle_attr_group = {
-       .attrs = thermal_throttle_attrs,
-       .name = "thermal_throttle"
+       .attrs  = thermal_throttle_attrs,
+       .name   = "thermal_throttle"
 };
 #endif /* CONFIG_SYSFS */
 
@@ -110,10 +110,11 @@ int therm_throt_process(int curr)
 }
 
 #ifdef CONFIG_SYSFS
-/* Add/Remove thermal_throttle interface for CPU device */
+/* Add/Remove thermal_throttle interface for CPU device: */
 static __cpuinit int thermal_throttle_add_dev(struct sys_device *sys_dev)
 {
-       return sysfs_create_group(&sys_dev->kobj, &thermal_throttle_attr_group);
+       return sysfs_create_group(&sys_dev->kobj,
+                                 &thermal_throttle_attr_group);
 }
 
 static __cpuinit void thermal_throttle_remove_dev(struct sys_device *sys_dev)
@@ -121,19 +122,21 @@ static __cpuinit void thermal_throttle_remove_dev(struct sys_device *sys_dev)
        sysfs_remove_group(&sys_dev->kobj, &thermal_throttle_attr_group);
 }
 
-/* Mutex protecting device creation against CPU hotplug */
+/* Mutex protecting device creation against CPU hotplug: */
 static DEFINE_MUTEX(therm_cpu_lock);
 
 /* Get notified when a cpu comes on/off. Be hotplug friendly. */
-static __cpuinit int thermal_throttle_cpu_callback(struct notifier_block *nfb,
-                                                  unsigned long action,
-                                                  void *hcpu)
+static __cpuinit int
+thermal_throttle_cpu_callback(struct notifier_block *nfb,
+                             unsigned long action,
+                             void *hcpu)
 {
        unsigned int cpu = (unsigned long)hcpu;
        struct sys_device *sys_dev;
        int err = 0;
 
        sys_dev = get_cpu_sysdev(cpu);
+
        switch (action) {
        case CPU_UP_PREPARE:
        case CPU_UP_PREPARE_FROZEN:
index 23ee9e730f78856c2f9e72687ac82316c463f26c..d746df2909c9fe306d20f1e5288cc476c5777209 100644 (file)
@@ -17,7 +17,7 @@ static void default_threshold_interrupt(void)
 
 void (*mce_threshold_vector)(void) = default_threshold_interrupt;
 
-asmlinkage void mce_threshold_interrupt(void)
+asmlinkage void smp_threshold_interrupt(void)
 {
        exit_idle();
        irq_enter();
index 2a043d89811de67f211ec17964e1862c5df7fd7d..81b02487090be5e85e7092dee5eb01cd785d99cf 100644 (file)
@@ -2,11 +2,10 @@
  * IDT Winchip specific Machine Check Exception Reporting
  * (C) Copyright 2002 Alan Cox <alan@lxorguk.ukuu.org.uk>
  */
-
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
 #include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
 
 #include <asm/processor.h>
 #include <asm/system.h>
@@ -14,7 +13,7 @@
 
 #include "mce.h"
 
-/* Machine check handler for WinChip C6 */
+/* Machine check handler for WinChip C6: */
 static void winchip_machine_check(struct pt_regs *regs, long error_code)
 {
        printk(KERN_EMERG "CPU0: Machine Check Exception.\n");
@@ -25,12 +24,18 @@ static void winchip_machine_check(struct pt_regs *regs, long error_code)
 void winchip_mcheck_init(struct cpuinfo_x86 *c)
 {
        u32 lo, hi;
+
        machine_check_vector = winchip_machine_check;
+       /* Make sure the vector pointer is visible before we enable MCEs: */
        wmb();
+
        rdmsr(MSR_IDT_FCR1, lo, hi);
        lo |= (1<<2);   /* Enable EIERRINT (int 18 MCE) */
        lo &= ~(1<<4);  /* Enable MCE */
        wrmsr(MSR_IDT_FCR1, lo, hi);
+
        set_in_cr4(X86_CR4_MCE);
-       printk(KERN_INFO "Winchip machine check reporting enabled on CPU#0.\n");
+
+       printk(KERN_INFO
+              "Winchip machine check reporting enabled on CPU#0.\n");
 }
index 895c82e78455036810b21302cf2bea49a40466a1..275bc142cd5ddab2d530be5819744fbaafd831d9 100644 (file)
@@ -968,6 +968,13 @@ fixed_mode_idx(struct perf_counter *counter, struct hw_perf_counter *hwc)
        if (!x86_pmu.num_counters_fixed)
                return -1;
 
+       /*
+        * Quirk, IA32_FIXED_CTRs do not work on current Atom processors:
+        */
+       if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
+                                       boot_cpu_data.x86_model == 28)
+               return -1;
+
        event = hwc->config & ARCH_PERFMON_EVENT_MASK;
 
        if (unlikely(event == x86_pmu.event_map(PERF_COUNT_HW_INSTRUCTIONS)))
index a4742a340d8d146e71fe8ee684c462b8215839ab..de74f0a3e0ed38a75563baea16934d530a3e68d2 100644 (file)
@@ -963,6 +963,8 @@ END(\sym)
 #ifdef CONFIG_SMP
 apicinterrupt IRQ_MOVE_CLEANUP_VECTOR \
        irq_move_cleanup_interrupt smp_irq_move_cleanup_interrupt
+apicinterrupt REBOOT_VECTOR \
+       reboot_interrupt smp_reboot_interrupt
 #endif
 
 #ifdef CONFIG_X86_UV
@@ -994,10 +996,15 @@ apicinterrupt INVALIDATE_TLB_VECTOR_START+7 \
 #endif
 
 apicinterrupt THRESHOLD_APIC_VECTOR \
-       threshold_interrupt mce_threshold_interrupt
+       threshold_interrupt smp_threshold_interrupt
 apicinterrupt THERMAL_APIC_VECTOR \
        thermal_interrupt smp_thermal_interrupt
 
+#ifdef CONFIG_X86_MCE
+apicinterrupt MCE_SELF_VECTOR \
+       mce_self_interrupt smp_mce_self_interrupt
+#endif
+
 #ifdef CONFIG_SMP
 apicinterrupt CALL_FUNCTION_SINGLE_VECTOR \
        call_function_single_interrupt smp_call_function_single_interrupt
@@ -1379,7 +1386,7 @@ errorentry xen_stack_segment do_stack_segment
 errorentry general_protection do_general_protection
 errorentry page_fault do_page_fault
 #ifdef CONFIG_X86_MCE
-paranoidzeroentry machine_check do_machine_check
+paranoidzeroentry machine_check *machine_check_vector(%rip)
 #endif
 
        /*
index 38287b5f116e10e4e1bba96cac3d0c30bf842890..b0cdde6932f5ef094d74eae1a80e0e79877a1018 100644 (file)
@@ -12,6 +12,7 @@
 #include <asm/io_apic.h>
 #include <asm/irq.h>
 #include <asm/idle.h>
+#include <asm/mce.h>
 #include <asm/hw_irq.h>
 
 atomic_t irq_err_count;
@@ -96,12 +97,22 @@ static int show_other_interrupts(struct seq_file *p, int prec)
        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_64
+# 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_NEW_MCE
+       seq_printf(p, "%*s: ", prec, "MCE");
+       for_each_online_cpu(j)
+               seq_printf(p, "%10u ", per_cpu(mce_exception_count, j));
+       seq_printf(p, "  Machine check exceptions\n");
+       seq_printf(p, "%*s: ", prec, "MCP");
+       for_each_online_cpu(j)
+               seq_printf(p, "%10u ", per_cpu(mce_poll_count, j));
+       seq_printf(p, "  Machine check polls\n");
 #endif
        seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count));
 #if defined(CONFIG_X86_IO_APIC)
@@ -185,9 +196,13 @@ u64 arch_irq_stat_cpu(unsigned int cpu)
 #endif
 #ifdef CONFIG_X86_MCE
        sum += irq_stats(cpu)->irq_thermal_count;
-# ifdef CONFIG_X86_64
+# ifdef CONFIG_X86_MCE_THRESHOLD
        sum += irq_stats(cpu)->irq_threshold_count;
 # endif
+#endif
+#ifdef CONFIG_X86_NEW_MCE
+       sum += per_cpu(mce_exception_count, cpu);
+       sum += per_cpu(mce_poll_count, cpu);
 #endif
        return sum;
 }
index 267c6624c77f53dab8be37e59fa97ebd2315d1c5..696f0e475c2d6d8b8b5f2eb4a22e4d934a00e561 100644 (file)
@@ -173,6 +173,9 @@ static void __init smp_intr_init(void)
        /* Low priority IPI to cleanup after moving an irq */
        set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt);
        set_bit(IRQ_MOVE_CLEANUP_VECTOR, used_vectors);
+
+       /* IPI used for rebooting/stopping */
+       alloc_intr_gate(REBOOT_VECTOR, reboot_interrupt);
 #endif
 #endif /* CONFIG_SMP */
 }
diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c
new file mode 100644 (file)
index 0000000..89f386f
--- /dev/null
@@ -0,0 +1,248 @@
+/*  Kernel module help for x86.
+    Copyright (C) 2001 Rusty Russell.
+
+    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/moduleloader.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/mm.h>
+
+#include <asm/system.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(fmt...)
+#endif
+
+void *module_alloc(unsigned long size)
+{
+       struct vm_struct *area;
+
+       if (!size)
+               return NULL;
+       size = PAGE_ALIGN(size);
+       if (size > MODULES_LEN)
+               return NULL;
+
+       area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END);
+       if (!area)
+               return NULL;
+
+       return __vmalloc_area(area, GFP_KERNEL | __GFP_HIGHMEM,
+                                       PAGE_KERNEL_EXEC);
+}
+
+/* Free memory returned from module_alloc */
+void module_free(struct module *mod, void *module_region)
+{
+       vfree(module_region);
+}
+
+/* We don't need anything special. */
+int module_frob_arch_sections(Elf_Ehdr *hdr,
+                             Elf_Shdr *sechdrs,
+                             char *secstrings,
+                             struct module *mod)
+{
+       return 0;
+}
+
+#ifdef CONFIG_X86_32
+int apply_relocate(Elf32_Shdr *sechdrs,
+                  const char *strtab,
+                  unsigned int symindex,
+                  unsigned int relsec,
+                  struct module *me)
+{
+       unsigned int i;
+       Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr;
+       Elf32_Sym *sym;
+       uint32_t *location;
+
+       DEBUGP("Applying relocate section %u to %u\n", relsec,
+              sechdrs[relsec].sh_info);
+       for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+               /* This is where to make the change */
+               location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+                       + rel[i].r_offset;
+               /* This is the symbol it is referring to.  Note that all
+                  undefined symbols have been resolved.  */
+               sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+                       + ELF32_R_SYM(rel[i].r_info);
+
+               switch (ELF32_R_TYPE(rel[i].r_info)) {
+               case R_386_32:
+                       /* We add the value into the location given */
+                       *location += sym->st_value;
+                       break;
+               case R_386_PC32:
+                       /* Add the value, subtract its postition */
+                       *location += sym->st_value - (uint32_t)location;
+                       break;
+               default:
+                       printk(KERN_ERR "module %s: Unknown relocation: %u\n",
+                              me->name, ELF32_R_TYPE(rel[i].r_info));
+                       return -ENOEXEC;
+               }
+       }
+       return 0;
+}
+
+int apply_relocate_add(Elf32_Shdr *sechdrs,
+                      const char *strtab,
+                      unsigned int symindex,
+                      unsigned int relsec,
+                      struct module *me)
+{
+       printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n",
+              me->name);
+       return -ENOEXEC;
+}
+#else /*X86_64*/
+int apply_relocate_add(Elf64_Shdr *sechdrs,
+                  const char *strtab,
+                  unsigned int symindex,
+                  unsigned int relsec,
+                  struct module *me)
+{
+       unsigned int i;
+       Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr;
+       Elf64_Sym *sym;
+       void *loc;
+       u64 val;
+
+       DEBUGP("Applying relocate section %u to %u\n", relsec,
+              sechdrs[relsec].sh_info);
+       for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+               /* This is where to make the change */
+               loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+                       + rel[i].r_offset;
+
+               /* This is the symbol it is referring to.  Note that all
+                  undefined symbols have been resolved.  */
+               sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
+                       + ELF64_R_SYM(rel[i].r_info);
+
+               DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n",
+                       (int)ELF64_R_TYPE(rel[i].r_info),
+                       sym->st_value, rel[i].r_addend, (u64)loc);
+
+               val = sym->st_value + rel[i].r_addend;
+
+               switch (ELF64_R_TYPE(rel[i].r_info)) {
+               case R_X86_64_NONE:
+                       break;
+               case R_X86_64_64:
+                       *(u64 *)loc = val;
+                       break;
+               case R_X86_64_32:
+                       *(u32 *)loc = val;
+                       if (val != *(u32 *)loc)
+                               goto overflow;
+                       break;
+               case R_X86_64_32S:
+                       *(s32 *)loc = val;
+                       if ((s64)val != *(s32 *)loc)
+                               goto overflow;
+                       break;
+               case R_X86_64_PC32:
+                       val -= (u64)loc;
+                       *(u32 *)loc = val;
+#if 0
+                       if ((s64)val != *(s32 *)loc)
+                               goto overflow;
+#endif
+                       break;
+               default:
+                       printk(KERN_ERR "module %s: Unknown rela relocation: %llu\n",
+                              me->name, ELF64_R_TYPE(rel[i].r_info));
+                       return -ENOEXEC;
+               }
+       }
+       return 0;
+
+overflow:
+       printk(KERN_ERR "overflow in relocation type %d val %Lx\n",
+              (int)ELF64_R_TYPE(rel[i].r_info), val);
+       printk(KERN_ERR "`%s' likely not compiled with -mcmodel=kernel\n",
+              me->name);
+       return -ENOEXEC;
+}
+
+int apply_relocate(Elf_Shdr *sechdrs,
+                  const char *strtab,
+                  unsigned int symindex,
+                  unsigned int relsec,
+                  struct module *me)
+{
+       printk(KERN_ERR "non add relocation not supported\n");
+       return -ENOSYS;
+}
+
+#endif
+
+int module_finalize(const Elf_Ehdr *hdr,
+                   const Elf_Shdr *sechdrs,
+                   struct module *me)
+{
+       const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL,
+               *para = NULL;
+       char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+
+       for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
+               if (!strcmp(".text", secstrings + s->sh_name))
+                       text = s;
+               if (!strcmp(".altinstructions", secstrings + s->sh_name))
+                       alt = s;
+               if (!strcmp(".smp_locks", secstrings + s->sh_name))
+                       locks = s;
+               if (!strcmp(".parainstructions", secstrings + s->sh_name))
+                       para = s;
+       }
+
+       if (alt) {
+               /* patch .altinstructions */
+               void *aseg = (void *)alt->sh_addr;
+               apply_alternatives(aseg, aseg + alt->sh_size);
+       }
+       if (locks && text) {
+               void *lseg = (void *)locks->sh_addr;
+               void *tseg = (void *)text->sh_addr;
+               alternatives_smp_module_add(me, me->name,
+                                           lseg, lseg + locks->sh_size,
+                                           tseg, tseg + text->sh_size);
+       }
+
+       if (para) {
+               void *pseg = (void *)para->sh_addr;
+               apply_paravirt(pseg, pseg + para->sh_size);
+       }
+
+       return module_bug_finalize(hdr, sechdrs, me);
+}
+
+void module_arch_cleanup(struct module *mod)
+{
+       alternatives_smp_module_del(mod);
+       module_bug_cleanup(mod);
+}
diff --git a/arch/x86/kernel/module_32.c b/arch/x86/kernel/module_32.c
deleted file mode 100644 (file)
index 0edd819..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/*  Kernel module help for i386.
-    Copyright (C) 2001 Rusty Russell.
-
-    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/moduleloader.h>
-#include <linux/elf.h>
-#include <linux/vmalloc.h>
-#include <linux/fs.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/bug.h>
-
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(fmt...)
-#endif
-
-void *module_alloc(unsigned long size)
-{
-       if (size == 0)
-               return NULL;
-       return vmalloc_exec(size);
-}
-
-
-/* Free memory returned from module_alloc */
-void module_free(struct module *mod, void *module_region)
-{
-       vfree(module_region);
-       /* FIXME: If module_region == mod->init_region, trim exception
-          table entries. */
-}
-
-/* We don't need anything special. */
-int module_frob_arch_sections(Elf_Ehdr *hdr,
-                             Elf_Shdr *sechdrs,
-                             char *secstrings,
-                             struct module *mod)
-{
-       return 0;
-}
-
-int apply_relocate(Elf32_Shdr *sechdrs,
-                  const char *strtab,
-                  unsigned int symindex,
-                  unsigned int relsec,
-                  struct module *me)
-{
-       unsigned int i;
-       Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr;
-       Elf32_Sym *sym;
-       uint32_t *location;
-
-       DEBUGP("Applying relocate section %u to %u\n", relsec,
-              sechdrs[relsec].sh_info);
-       for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
-               /* This is where to make the change */
-               location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
-                       + rel[i].r_offset;
-               /* This is the symbol it is referring to.  Note that all
-                  undefined symbols have been resolved.  */
-               sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
-                       + ELF32_R_SYM(rel[i].r_info);
-
-               switch (ELF32_R_TYPE(rel[i].r_info)) {
-               case R_386_32:
-                       /* We add the value into the location given */
-                       *location += sym->st_value;
-                       break;
-               case R_386_PC32:
-                       /* Add the value, subtract its postition */
-                       *location += sym->st_value - (uint32_t)location;
-                       break;
-               default:
-                       printk(KERN_ERR "module %s: Unknown relocation: %u\n",
-                              me->name, ELF32_R_TYPE(rel[i].r_info));
-                       return -ENOEXEC;
-               }
-       }
-       return 0;
-}
-
-int apply_relocate_add(Elf32_Shdr *sechdrs,
-                      const char *strtab,
-                      unsigned int symindex,
-                      unsigned int relsec,
-                      struct module *me)
-{
-       printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n",
-              me->name);
-       return -ENOEXEC;
-}
-
-int module_finalize(const Elf_Ehdr *hdr,
-                   const Elf_Shdr *sechdrs,
-                   struct module *me)
-{
-       const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL,
-               *para = NULL;
-       char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
-
-       for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
-               if (!strcmp(".text", secstrings + s->sh_name))
-                       text = s;
-               if (!strcmp(".altinstructions", secstrings + s->sh_name))
-                       alt = s;
-               if (!strcmp(".smp_locks", secstrings + s->sh_name))
-                       locks = s;
-               if (!strcmp(".parainstructions", secstrings + s->sh_name))
-                       para = s;
-       }
-
-       if (alt) {
-               /* patch .altinstructions */
-               void *aseg = (void *)alt->sh_addr;
-               apply_alternatives(aseg, aseg + alt->sh_size);
-       }
-       if (locks && text) {
-               void *lseg = (void *)locks->sh_addr;
-               void *tseg = (void *)text->sh_addr;
-               alternatives_smp_module_add(me, me->name,
-                                           lseg, lseg + locks->sh_size,
-                                           tseg, tseg + text->sh_size);
-       }
-
-       if (para) {
-               void *pseg = (void *)para->sh_addr;
-               apply_paravirt(pseg, pseg + para->sh_size);
-       }
-
-       return module_bug_finalize(hdr, sechdrs, me);
-}
-
-void module_arch_cleanup(struct module *mod)
-{
-       alternatives_smp_module_del(mod);
-       module_bug_cleanup(mod);
-}
diff --git a/arch/x86/kernel/module_64.c b/arch/x86/kernel/module_64.c
deleted file mode 100644 (file)
index c23880b..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-/*  Kernel module help for x86-64
-    Copyright (C) 2001 Rusty Russell.
-    Copyright (C) 2002,2003 Andi Kleen, SuSE Labs.
-
-    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/moduleloader.h>
-#include <linux/elf.h>
-#include <linux/vmalloc.h>
-#include <linux/fs.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/bug.h>
-
-#include <asm/system.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-
-#define DEBUGP(fmt...)
-
-#ifndef CONFIG_UML
-void module_free(struct module *mod, void *module_region)
-{
-       vfree(module_region);
-       /* FIXME: If module_region == mod->init_region, trim exception
-          table entries. */
-}
-
-void *module_alloc(unsigned long size)
-{
-       struct vm_struct *area;
-
-       if (!size)
-               return NULL;
-       size = PAGE_ALIGN(size);
-       if (size > MODULES_LEN)
-               return NULL;
-
-       area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END);
-       if (!area)
-               return NULL;
-
-       return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL_EXEC);
-}
-#endif
-
-/* We don't need anything special. */
-int module_frob_arch_sections(Elf_Ehdr *hdr,
-                             Elf_Shdr *sechdrs,
-                             char *secstrings,
-                             struct module *mod)
-{
-       return 0;
-}
-
-int apply_relocate_add(Elf64_Shdr *sechdrs,
-                  const char *strtab,
-                  unsigned int symindex,
-                  unsigned int relsec,
-                  struct module *me)
-{
-       unsigned int i;
-       Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr;
-       Elf64_Sym *sym;
-       void *loc;
-       u64 val;
-
-       DEBUGP("Applying relocate section %u to %u\n", relsec,
-              sechdrs[relsec].sh_info);
-       for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
-               /* This is where to make the change */
-               loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
-                       + rel[i].r_offset;
-
-               /* This is the symbol it is referring to.  Note that all
-                  undefined symbols have been resolved.  */
-               sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
-                       + ELF64_R_SYM(rel[i].r_info);
-
-               DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n",
-                       (int)ELF64_R_TYPE(rel[i].r_info),
-                       sym->st_value, rel[i].r_addend, (u64)loc);
-
-               val = sym->st_value + rel[i].r_addend;
-
-               switch (ELF64_R_TYPE(rel[i].r_info)) {
-               case R_X86_64_NONE:
-                       break;
-               case R_X86_64_64:
-                       *(u64 *)loc = val;
-                       break;
-               case R_X86_64_32:
-                       *(u32 *)loc = val;
-                       if (val != *(u32 *)loc)
-                               goto overflow;
-                       break;
-               case R_X86_64_32S:
-                       *(s32 *)loc = val;
-                       if ((s64)val != *(s32 *)loc)
-                               goto overflow;
-                       break;
-               case R_X86_64_PC32:
-                       val -= (u64)loc;
-                       *(u32 *)loc = val;
-#if 0
-                       if ((s64)val != *(s32 *)loc)
-                               goto overflow;
-#endif
-                       break;
-               default:
-                       printk(KERN_ERR "module %s: Unknown rela relocation: %llu\n",
-                              me->name, ELF64_R_TYPE(rel[i].r_info));
-                       return -ENOEXEC;
-               }
-       }
-       return 0;
-
-overflow:
-       printk(KERN_ERR "overflow in relocation type %d val %Lx\n",
-              (int)ELF64_R_TYPE(rel[i].r_info), val);
-       printk(KERN_ERR "`%s' likely not compiled with -mcmodel=kernel\n",
-              me->name);
-       return -ENOEXEC;
-}
-
-int apply_relocate(Elf_Shdr *sechdrs,
-                  const char *strtab,
-                  unsigned int symindex,
-                  unsigned int relsec,
-                  struct module *me)
-{
-       printk(KERN_ERR "non add relocation not supported\n");
-       return -ENOSYS;
-}
-
-int module_finalize(const Elf_Ehdr *hdr,
-                   const Elf_Shdr *sechdrs,
-                   struct module *me)
-{
-       const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL,
-               *para = NULL;
-       char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
-
-       for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
-               if (!strcmp(".text", secstrings + s->sh_name))
-                       text = s;
-               if (!strcmp(".altinstructions", secstrings + s->sh_name))
-                       alt = s;
-               if (!strcmp(".smp_locks", secstrings + s->sh_name))
-                       locks = s;
-               if (!strcmp(".parainstructions", secstrings + s->sh_name))
-                       para = s;
-       }
-
-       if (alt) {
-               /* patch .altinstructions */
-               void *aseg = (void *)alt->sh_addr;
-               apply_alternatives(aseg, aseg + alt->sh_size);
-       }
-       if (locks && text) {
-               void *lseg = (void *)locks->sh_addr;
-               void *tseg = (void *)text->sh_addr;
-               alternatives_smp_module_add(me, me->name,
-                                           lseg, lseg + locks->sh_size,
-                                           tseg, tseg + text->sh_size);
-       }
-
-       if (para) {
-               void *pseg = (void *)para->sh_addr;
-               apply_paravirt(pseg, pseg + para->sh_size);
-       }
-
-       return module_bug_finalize(hdr, sechdrs, me);
-}
-
-void module_arch_cleanup(struct module *mod)
-{
-       alternatives_smp_module_del(mod);
-       module_bug_cleanup(mod);
-}
index d1c636bf31a71018d73f7e36616d2c7d533707ea..be5ae80f897fb58f68f353fcd65c9346b3834d39 100644 (file)
@@ -301,15 +301,13 @@ static void __init reserve_brk(void)
 
 #ifdef CONFIG_BLK_DEV_INITRD
 
-#ifdef CONFIG_X86_32
-
 #define MAX_MAP_CHUNK  (NR_FIX_BTMAPS << PAGE_SHIFT)
 static void __init relocate_initrd(void)
 {
 
        u64 ramdisk_image = boot_params.hdr.ramdisk_image;
        u64 ramdisk_size  = boot_params.hdr.ramdisk_size;
-       u64 end_of_lowmem = max_low_pfn << PAGE_SHIFT;
+       u64 end_of_lowmem = max_low_pfn_mapped << PAGE_SHIFT;
        u64 ramdisk_here;
        unsigned long slop, clen, mapaddr;
        char *p, *q;
@@ -365,14 +363,13 @@ static void __init relocate_initrd(void)
                ramdisk_image, ramdisk_image + ramdisk_size - 1,
                ramdisk_here, ramdisk_here + ramdisk_size - 1);
 }
-#endif
 
 static void __init reserve_initrd(void)
 {
        u64 ramdisk_image = boot_params.hdr.ramdisk_image;
        u64 ramdisk_size  = boot_params.hdr.ramdisk_size;
        u64 ramdisk_end   = ramdisk_image + ramdisk_size;
-       u64 end_of_lowmem = max_low_pfn << PAGE_SHIFT;
+       u64 end_of_lowmem = max_low_pfn_mapped << PAGE_SHIFT;
 
        if (!boot_params.hdr.type_of_loader ||
            !ramdisk_image || !ramdisk_size)
@@ -402,14 +399,8 @@ static void __init reserve_initrd(void)
                return;
        }
 
-#ifdef CONFIG_X86_32
        relocate_initrd();
-#else
-       printk(KERN_ERR "initrd extends beyond end of memory "
-              "(0x%08llx > 0x%08llx)\ndisabling initrd\n",
-              ramdisk_end, end_of_lowmem);
-       initrd_start = 0;
-#endif
+
        free_early(ramdisk_image, ramdisk_end);
 }
 #else
index 0a813b17b172437760b6d8beae71104f6fc878ba..4c578751e94ec08dc4e6ed69338947105e444654 100644 (file)
 #include <asm/ucontext.h>
 #include <asm/i387.h>
 #include <asm/vdso.h>
+#include <asm/mce.h>
 
 #ifdef CONFIG_X86_64
 #include <asm/proto.h>
 #include <asm/ia32_unistd.h>
-#include <asm/mce.h>
 #endif /* CONFIG_X86_64 */
 
 #include <asm/syscall.h>
@@ -856,10 +856,10 @@ static void do_signal(struct pt_regs *regs)
 void
 do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
 {
-#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE)
+#ifdef CONFIG_X86_NEW_MCE
        /* notify userspace of pending MCEs */
        if (thread_info_flags & _TIF_MCE_NOTIFY)
-               mce_notify_user();
+               mce_notify_process();
 #endif /* CONFIG_X86_64 && CONFIG_X86_MCE */
 
        /* deal with pending signal delivery */
index 28f5fb495a669e9b6843daf33a37baaac512fad7..ec1de97600e70638bcfdcb53da52a83bc1288829 100644 (file)
@@ -150,14 +150,40 @@ void native_send_call_func_ipi(const struct cpumask *mask)
  * this function calls the 'stop' function on all other CPUs in the system.
  */
 
+asmlinkage void smp_reboot_interrupt(void)
+{
+       ack_APIC_irq();
+       irq_enter();
+       stop_this_cpu(NULL);
+       irq_exit();
+}
+
 static void native_smp_send_stop(void)
 {
        unsigned long flags;
+       unsigned long wait;
 
        if (reboot_force)
                return;
 
-       smp_call_function(stop_this_cpu, NULL, 0);
+       /*
+        * Use an own vector here because smp_call_function
+        * does lots of things not suitable in a panic situation.
+        * On most systems we could also use an NMI here,
+        * but there are a few systems around where NMI
+        * is problematic so stay with an non NMI for now
+        * (this implies we cannot stop CPUs spinning with irq off
+        * currently)
+        */
+       if (num_online_cpus() > 1) {
+               apic->send_IPI_allbutself(REBOOT_VECTOR);
+
+               /* Don't wait longer than a second */
+               wait = USEC_PER_SEC;
+               while (num_online_cpus() > 1 && wait--)
+                       udelay(1);
+       }
+
        local_irq_save(flags);
        disable_local_APIC();
        local_irq_restore(flags);
index 7c80007ea5f7fb28ce9e61c4569f3c3432981b1d..2fecda69ee646a78402cc6a1d9e3d86a29ca06d6 100644 (file)
@@ -873,7 +873,7 @@ int __cpuinit native_cpu_up(unsigned int cpu)
 
        err = do_boot_cpu(apicid, cpu);
 
-       zap_low_mappings();
+       zap_low_mappings(false);
        low_mappings = 0;
 #else
        err = do_boot_cpu(apicid, cpu);
index e7a28e6aa4bcc047f2a2dd3b9988a95b3c12986b..5f935f0d5861c625b3ffa6811846e4a480c91282 100644 (file)
@@ -803,15 +803,15 @@ unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp)
 
        return new_kesp;
 }
-#else
+#endif
+
 asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void)
 {
 }
 
-asmlinkage void __attribute__((weak)) mce_threshold_interrupt(void)
+asmlinkage void __attribute__((weak)) smp_threshold_interrupt(void)
 {
 }
-#endif
 
 /*
  * 'math_state_restore()' saves the current math information in the
index 4c85b2e2bb652873da1ee5367549e070b363bf8a..367e878820418789055a6a2da48aa27350ada443 100644 (file)
@@ -108,6 +108,8 @@ SECTIONS
        /* Data */
        . = ALIGN(PAGE_SIZE);
        .data : AT(ADDR(.data) - LOAD_OFFSET) {
+               /* Start of data section */
+               _sdata = .;
                DATA_DATA
                CONSTRUCTORS
 
index 8dab8f7844d3e2ac62371e413ce71a07eb280d51..38718041efc34fbf6d8f120fe90e26b6d37abbaa 100644 (file)
@@ -2,7 +2,6 @@ config LGUEST_GUEST
        bool "Lguest guest support"
        select PARAVIRT
        depends on X86_32
-       depends on !X86_PAE
        select VIRTIO
        select VIRTIO_RING
        select VIRTIO_CONSOLE
index 4e0c265593958fcb70a8588d942a27a7d0ac3da6..7bc65f0f62c4fc51607dd443641d1273cb4ebb03 100644 (file)
@@ -87,7 +87,7 @@ struct lguest_data lguest_data = {
 
 /*G:037 async_hcall() is pretty simple: I'm quite proud of it really.  We have a
  * ring buffer of stored hypercalls which the Host will run though next time we
- * do a normal hypercall.  Each entry in the ring has 4 slots for the hypercall
+ * do a normal hypercall.  Each entry in the ring has 5 slots for the hypercall
  * arguments, and a "hcall_status" word which is 0 if the call is ready to go,
  * and 255 once the Host has finished with it.
  *
@@ -96,7 +96,8 @@ struct lguest_data lguest_data = {
  * effect of causing the Host to run all the stored calls in the ring buffer
  * which empties it for next time! */
 static void async_hcall(unsigned long call, unsigned long arg1,
-                       unsigned long arg2, unsigned long arg3)
+                       unsigned long arg2, unsigned long arg3,
+                       unsigned long arg4)
 {
        /* Note: This code assumes we're uniprocessor. */
        static unsigned int next_call;
@@ -108,12 +109,13 @@ static void async_hcall(unsigned long call, unsigned long arg1,
        local_irq_save(flags);
        if (lguest_data.hcall_status[next_call] != 0xFF) {
                /* Table full, so do normal hcall which will flush table. */
-               kvm_hypercall3(call, arg1, arg2, arg3);
+               kvm_hypercall4(call, arg1, arg2, arg3, arg4);
        } else {
                lguest_data.hcalls[next_call].arg0 = call;
                lguest_data.hcalls[next_call].arg1 = arg1;
                lguest_data.hcalls[next_call].arg2 = arg2;
                lguest_data.hcalls[next_call].arg3 = arg3;
+               lguest_data.hcalls[next_call].arg4 = arg4;
                /* Arguments must all be written before we mark it to go */
                wmb();
                lguest_data.hcall_status[next_call] = 0;
@@ -141,7 +143,7 @@ static void lazy_hcall1(unsigned long call,
        if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE)
                kvm_hypercall1(call, arg1);
        else
-               async_hcall(call, arg1, 0, 0);
+               async_hcall(call, arg1, 0, 0, 0);
 }
 
 static void lazy_hcall2(unsigned long call,
@@ -151,7 +153,7 @@ static void lazy_hcall2(unsigned long call,
        if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE)
                kvm_hypercall2(call, arg1, arg2);
        else
-               async_hcall(call, arg1, arg2, 0);
+               async_hcall(call, arg1, arg2, 0, 0);
 }
 
 static void lazy_hcall3(unsigned long call,
@@ -162,9 +164,23 @@ static void lazy_hcall3(unsigned long call,
        if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE)
                kvm_hypercall3(call, arg1, arg2, arg3);
        else
-               async_hcall(call, arg1, arg2, arg3);
+               async_hcall(call, arg1, arg2, arg3, 0);
 }
 
+#ifdef CONFIG_X86_PAE
+static void lazy_hcall4(unsigned long call,
+                      unsigned long arg1,
+                      unsigned long arg2,
+                      unsigned long arg3,
+                      unsigned long arg4)
+{
+       if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE)
+               kvm_hypercall4(call, arg1, arg2, arg3, arg4);
+       else
+               async_hcall(call, arg1, arg2, arg3, arg4);
+}
+#endif
+
 /* When lazy mode is turned off reset the per-cpu lazy mode variable and then
  * issue the do-nothing hypercall to flush any stored calls. */
 static void lguest_leave_lazy_mmu_mode(void)
@@ -179,7 +195,7 @@ static void lguest_end_context_switch(struct task_struct *next)
        paravirt_end_context_switch(next);
 }
 
-/*G:033
+/*G:032
  * After that diversion we return to our first native-instruction
  * replacements: four functions for interrupt control.
  *
@@ -199,30 +215,28 @@ static unsigned long save_fl(void)
 {
        return lguest_data.irq_enabled;
 }
-PV_CALLEE_SAVE_REGS_THUNK(save_fl);
-
-/* restore_flags() just sets the flags back to the value given. */
-static void restore_fl(unsigned long flags)
-{
-       lguest_data.irq_enabled = flags;
-}
-PV_CALLEE_SAVE_REGS_THUNK(restore_fl);
 
 /* Interrupts go off... */
 static void irq_disable(void)
 {
        lguest_data.irq_enabled = 0;
 }
+
+/* Let's pause a moment.  Remember how I said these are called so often?
+ * Jeremy Fitzhardinge optimized them so hard early in 2009 that he had to
+ * break some rules.  In particular, these functions are assumed to save their
+ * own registers if they need to: normal C functions assume they can trash the
+ * eax register.  To use normal C functions, we use
+ * PV_CALLEE_SAVE_REGS_THUNK(), which pushes %eax onto the stack, calls the
+ * C function, then restores it. */
+PV_CALLEE_SAVE_REGS_THUNK(save_fl);
 PV_CALLEE_SAVE_REGS_THUNK(irq_disable);
+/*:*/
 
-/* Interrupts go on... */
-static void irq_enable(void)
-{
-       lguest_data.irq_enabled = X86_EFLAGS_IF;
-}
-PV_CALLEE_SAVE_REGS_THUNK(irq_enable);
+/* These are in i386_head.S */
+extern void lg_irq_enable(void);
+extern void lg_restore_fl(unsigned long flags);
 
-/*:*/
 /*M:003 Note that we don't check for outstanding interrupts when we re-enable
  * them (or when we unmask an interrupt).  This seems to work for the moment,
  * since interrupts are rare and we'll just get the interrupt on the next timer
@@ -368,8 +382,8 @@ static void lguest_cpuid(unsigned int *ax, unsigned int *bx,
        case 1: /* Basic feature request. */
                /* We only allow kernel to see SSE3, CMPXCHG16B and SSSE3 */
                *cx &= 0x00002201;
-               /* SSE, SSE2, FXSR, MMX, CMOV, CMPXCHG8B, TSC, FPU. */
-               *dx &= 0x07808111;
+               /* SSE, SSE2, FXSR, MMX, CMOV, CMPXCHG8B, TSC, FPU, PAE. */
+               *dx &= 0x07808151;
                /* The Host can do a nice optimization if it knows that the
                 * kernel mappings (addresses above 0xC0000000 or whatever
                 * PAGE_OFFSET is set to) haven't changed.  But Linux calls
@@ -388,6 +402,11 @@ static void lguest_cpuid(unsigned int *ax, unsigned int *bx,
                if (*ax > 0x80000008)
                        *ax = 0x80000008;
                break;
+       case 0x80000001:
+               /* Here we should fix nx cap depending on host. */
+               /* For this version of PAE, we just clear NX bit. */
+               *dx &= ~(1 << 20);
+               break;
        }
 }
 
@@ -521,25 +540,52 @@ static void lguest_write_cr4(unsigned long val)
 static void lguest_pte_update(struct mm_struct *mm, unsigned long addr,
                               pte_t *ptep)
 {
+#ifdef CONFIG_X86_PAE
+       lazy_hcall4(LHCALL_SET_PTE, __pa(mm->pgd), addr,
+                   ptep->pte_low, ptep->pte_high);
+#else
        lazy_hcall3(LHCALL_SET_PTE, __pa(mm->pgd), addr, ptep->pte_low);
+#endif
 }
 
 static void lguest_set_pte_at(struct mm_struct *mm, unsigned long addr,
                              pte_t *ptep, pte_t pteval)
 {
-       *ptep = pteval;
+       native_set_pte(ptep, pteval);
        lguest_pte_update(mm, addr, ptep);
 }
 
-/* The Guest calls this to set a top-level entry.  Again, we set the entry then
- * tell the Host which top-level page we changed, and the index of the entry we
- * changed. */
+/* The Guest calls lguest_set_pud to set a top-level entry and lguest_set_pmd
+ * to set a middle-level entry when PAE is activated.
+ * Again, we set the entry then tell the Host which page we changed,
+ * and the index of the entry we changed. */
+#ifdef CONFIG_X86_PAE
+static void lguest_set_pud(pud_t *pudp, pud_t pudval)
+{
+       native_set_pud(pudp, pudval);
+
+       /* 32 bytes aligned pdpt address and the index. */
+       lazy_hcall2(LHCALL_SET_PGD, __pa(pudp) & 0xFFFFFFE0,
+                  (__pa(pudp) & 0x1F) / sizeof(pud_t));
+}
+
 static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval)
 {
-       *pmdp = pmdval;
+       native_set_pmd(pmdp, pmdval);
        lazy_hcall2(LHCALL_SET_PMD, __pa(pmdp) & PAGE_MASK,
-                  (__pa(pmdp) & (PAGE_SIZE - 1)) / 4);
+                  (__pa(pmdp) & (PAGE_SIZE - 1)) / sizeof(pmd_t));
 }
+#else
+
+/* The Guest calls lguest_set_pmd to set a top-level entry when PAE is not
+ * activated. */
+static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval)
+{
+       native_set_pmd(pmdp, pmdval);
+       lazy_hcall2(LHCALL_SET_PGD, __pa(pmdp) & PAGE_MASK,
+                  (__pa(pmdp) & (PAGE_SIZE - 1)) / sizeof(pmd_t));
+}
+#endif
 
 /* There are a couple of legacy places where the kernel sets a PTE, but we
  * don't know the top level any more.  This is useless for us, since we don't
@@ -552,11 +598,31 @@ static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval)
  * which brings boot back to 0.25 seconds. */
 static void lguest_set_pte(pte_t *ptep, pte_t pteval)
 {
-       *ptep = pteval;
+       native_set_pte(ptep, pteval);
+       if (cr3_changed)
+               lazy_hcall1(LHCALL_FLUSH_TLB, 1);
+}
+
+#ifdef CONFIG_X86_PAE
+static void lguest_set_pte_atomic(pte_t *ptep, pte_t pte)
+{
+       native_set_pte_atomic(ptep, pte);
        if (cr3_changed)
                lazy_hcall1(LHCALL_FLUSH_TLB, 1);
 }
 
+void lguest_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+{
+       native_pte_clear(mm, addr, ptep);
+       lguest_pte_update(mm, addr, ptep);
+}
+
+void lguest_pmd_clear(pmd_t *pmdp)
+{
+       lguest_set_pmd(pmdp, __pmd(0));
+}
+#endif
+
 /* Unfortunately for Lguest, the pv_mmu_ops for page tables were based on
  * native page table operations.  On native hardware you can set a new page
  * table entry whenever you want, but if you want to remove one you have to do
@@ -628,13 +694,12 @@ static void __init lguest_init_IRQ(void)
 {
        unsigned int i;
 
-       for (i = 0; i < LGUEST_IRQS; i++) {
-               int vector = FIRST_EXTERNAL_VECTOR + i;
+       for (i = FIRST_EXTERNAL_VECTOR; i < NR_VECTORS; i++) {
                /* Some systems map "vectors" to interrupts weirdly.  Lguest has
                 * a straightforward 1 to 1 mapping, so force that here. */
-               __get_cpu_var(vector_irq)[vector] = i;
-               if (vector != SYSCALL_VECTOR)
-                       set_intr_gate(vector, interrupt[i]);
+               __get_cpu_var(vector_irq)[i] = i - FIRST_EXTERNAL_VECTOR;
+               if (i != SYSCALL_VECTOR)
+                       set_intr_gate(i, interrupt[i - FIRST_EXTERNAL_VECTOR]);
        }
        /* This call is required to set up for 4k stacks, where we have
         * separate stacks for hard and soft interrupts. */
@@ -973,10 +1038,10 @@ static void lguest_restart(char *reason)
  *
  * Our current solution is to allow the paravirt back end to optionally patch
  * over the indirect calls to replace them with something more efficient.  We
- * patch the four most commonly called functions: disable interrupts, enable
- * interrupts, restore interrupts and save interrupts.  We usually have 6 or 10
- * bytes to patch into: the Guest versions of these operations are small enough
- * that we can fit comfortably.
+ * patch two of the simplest of the most commonly called functions: disable
+ * interrupts and save interrupts.  We usually have 6 or 10 bytes to patch
+ * into: the Guest versions of these operations are small enough that we can
+ * fit comfortably.
  *
  * First we need assembly templates of each of the patchable Guest operations,
  * and these are in i386_head.S. */
@@ -987,8 +1052,6 @@ static const struct lguest_insns
        const char *start, *end;
 } lguest_insns[] = {
        [PARAVIRT_PATCH(pv_irq_ops.irq_disable)] = { lgstart_cli, lgend_cli },
-       [PARAVIRT_PATCH(pv_irq_ops.irq_enable)] = { lgstart_sti, lgend_sti },
-       [PARAVIRT_PATCH(pv_irq_ops.restore_fl)] = { lgstart_popf, lgend_popf },
        [PARAVIRT_PATCH(pv_irq_ops.save_fl)] = { lgstart_pushf, lgend_pushf },
 };
 
@@ -1026,6 +1089,7 @@ __init void lguest_init(void)
        pv_info.name = "lguest";
        pv_info.paravirt_enabled = 1;
        pv_info.kernel_rpl = 1;
+       pv_info.shared_kernel_pmd = 1;
 
        /* We set up all the lguest overrides for sensitive operations.  These
         * are detailed with the operations themselves. */
@@ -1033,9 +1097,9 @@ __init void lguest_init(void)
        /* interrupt-related operations */
        pv_irq_ops.init_IRQ = lguest_init_IRQ;
        pv_irq_ops.save_fl = PV_CALLEE_SAVE(save_fl);
-       pv_irq_ops.restore_fl = PV_CALLEE_SAVE(restore_fl);
+       pv_irq_ops.restore_fl = __PV_IS_CALLEE_SAVE(lg_restore_fl);
        pv_irq_ops.irq_disable = PV_CALLEE_SAVE(irq_disable);
-       pv_irq_ops.irq_enable = PV_CALLEE_SAVE(irq_enable);
+       pv_irq_ops.irq_enable = __PV_IS_CALLEE_SAVE(lg_irq_enable);
        pv_irq_ops.safe_halt = lguest_safe_halt;
 
        /* init-time operations */
@@ -1071,6 +1135,12 @@ __init void lguest_init(void)
        pv_mmu_ops.set_pte = lguest_set_pte;
        pv_mmu_ops.set_pte_at = lguest_set_pte_at;
        pv_mmu_ops.set_pmd = lguest_set_pmd;
+#ifdef CONFIG_X86_PAE
+       pv_mmu_ops.set_pte_atomic = lguest_set_pte_atomic;
+       pv_mmu_ops.pte_clear = lguest_pte_clear;
+       pv_mmu_ops.pmd_clear = lguest_pmd_clear;
+       pv_mmu_ops.set_pud = lguest_set_pud;
+#endif
        pv_mmu_ops.read_cr2 = lguest_read_cr2;
        pv_mmu_ops.read_cr3 = lguest_read_cr3;
        pv_mmu_ops.lazy_mode.enter = paravirt_enter_lazy_mmu;
index f795419894718796d48050f80a6b279a6a875dff..a9c8cfe61cd4d48497a648538ce5b1c7d04e7cde 100644 (file)
@@ -46,10 +46,64 @@ ENTRY(lguest_entry)
        .globl lgstart_##name; .globl lgend_##name
 
 LGUEST_PATCH(cli, movl $0, lguest_data+LGUEST_DATA_irq_enabled)
-LGUEST_PATCH(sti, movl $X86_EFLAGS_IF, lguest_data+LGUEST_DATA_irq_enabled)
-LGUEST_PATCH(popf, movl %eax, lguest_data+LGUEST_DATA_irq_enabled)
 LGUEST_PATCH(pushf, movl lguest_data+LGUEST_DATA_irq_enabled, %eax)
-/*:*/
+
+/*G:033 But using those wrappers is inefficient (we'll see why that doesn't
+ * matter for save_fl and irq_disable later).  If we write our routines
+ * carefully in assembler, we can avoid clobbering any registers and avoid
+ * jumping through the wrapper functions.
+ *
+ * I skipped over our first piece of assembler, but this one is worth studying
+ * in a bit more detail so I'll describe in easy stages.  First, the routine
+ * to enable interrupts: */
+ENTRY(lg_irq_enable)
+       /* The reverse of irq_disable, this sets lguest_data.irq_enabled to
+        * X86_EFLAGS_IF (ie. "Interrupts enabled"). */
+       movl $X86_EFLAGS_IF, lguest_data+LGUEST_DATA_irq_enabled
+       /* But now we need to check if the Host wants to know: there might have
+        * been interrupts waiting to be delivered, in which case it will have
+        * set lguest_data.irq_pending to X86_EFLAGS_IF.  If it's not zero, we
+        * jump to send_interrupts, otherwise we're done. */
+       testl $0, lguest_data+LGUEST_DATA_irq_pending
+       jnz send_interrupts
+       /* One cool thing about x86 is that you can do many things without using
+        * a register.  In this case, the normal path hasn't needed to save or
+        * restore any registers at all! */
+       ret
+send_interrupts:
+       /* OK, now we need a register: eax is used for the hypercall number,
+        * which is LHCALL_SEND_INTERRUPTS.
+        *
+        * We used not to bother with this pending detection at all, which was
+        * much simpler.  Sooner or later the Host would realize it had to
+        * send us an interrupt.  But that turns out to make performance 7
+        * times worse on a simple tcp benchmark.  So now we do this the hard
+        * way. */
+       pushl %eax
+       movl $LHCALL_SEND_INTERRUPTS, %eax
+       /* This is a vmcall instruction (same thing that KVM uses).  Older
+        * assembler versions might not know the "vmcall" instruction, so we
+        * create one manually here. */
+       .byte 0x0f,0x01,0xc1 /* KVM_HYPERCALL */
+       popl %eax
+       ret
+
+/* Finally, the "popf" or "restore flags" routine.  The %eax register holds the
+ * flags (in practice, either X86_EFLAGS_IF or 0): if it's X86_EFLAGS_IF we're
+ * enabling interrupts again, if it's 0 we're leaving them off. */
+ENTRY(lg_restore_fl)
+       /* This is just "lguest_data.irq_enabled = flags;" */
+       movl %eax, lguest_data+LGUEST_DATA_irq_enabled
+       /* Now, if the %eax value has enabled interrupts and
+        * lguest_data.irq_pending is set, we want to tell the Host so it can
+        * deliver any outstanding interrupts.  Fortunately, both values will
+        * be X86_EFLAGS_IF (ie. 512) in that case, and the "testl"
+        * instruction will AND them together for us.  If both are set, we
+        * jump to send_interrupts. */
+       testl lguest_data+LGUEST_DATA_irq_pending, %eax
+       jnz send_interrupts
+       /* Again, the normal path has used no extra registers.  Clever, huh? */
+       ret
 
 /* These demark the EIP range where host should never deliver interrupts. */
 .global lguest_noirq_start
index 80cafd76a2bdf7866eeb90bf1c212be5dc49e7fc..3cd7711bb94940d0f19ffb4bac4f4b5f9f6a1a5f 100644 (file)
@@ -564,7 +564,7 @@ static inline void save_pg_dir(void)
 }
 #endif /* !CONFIG_ACPI_SLEEP */
 
-void zap_low_mappings(void)
+void zap_low_mappings(bool early)
 {
        int i;
 
@@ -581,7 +581,11 @@ void zap_low_mappings(void)
                set_pgd(swapper_pg_dir+i, __pgd(0));
 #endif
        }
-       flush_tlb_all();
+
+       if (early)
+               __flush_tlb();
+       else
+               flush_tlb_all();
 }
 
 pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL | _PAGE_IOMAP);
@@ -956,7 +960,7 @@ void __init mem_init(void)
                test_wp_bit();
 
        save_pg_dir();
-       zap_low_mappings();
+       zap_low_mappings(true);
 }
 
 #ifdef CONFIG_MEMORY_HOTPLUG
index 58b32db33125a9eb13cc3859597cfb5b32b2cb4c..de2abbd0754481d0528ee527077d668d7b3e422b 100644 (file)
@@ -3,5 +3,5 @@
 nostackp := $(call cc-option, -fno-stack-protector)
 CFLAGS_cpu_$(BITS).o   := $(nostackp)
 
-obj-$(CONFIG_PM_SLEEP)         += cpu_$(BITS).o
+obj-$(CONFIG_PM_SLEEP)         += cpu.o
 obj-$(CONFIG_HIBERNATION)      += hibernate_$(BITS).o hibernate_asm_$(BITS).o
diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c
new file mode 100644 (file)
index 0000000..d277ef1
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * Suspend support specific for i386/x86-64.
+ *
+ * Distribute under GPLv2
+ *
+ * Copyright (c) 2007 Rafael J. Wysocki <rjw@sisk.pl>
+ * Copyright (c) 2002 Pavel Machek <pavel@suse.cz>
+ * Copyright (c) 2001 Patrick Mochel <mochel@osdl.org>
+ */
+
+#include <linux/suspend.h>
+#include <linux/smp.h>
+
+#include <asm/pgtable.h>
+#include <asm/proto.h>
+#include <asm/mtrr.h>
+#include <asm/page.h>
+#include <asm/mce.h>
+#include <asm/xcr.h>
+#include <asm/suspend.h>
+
+#ifdef CONFIG_X86_32
+static struct saved_context saved_context;
+
+unsigned long saved_context_ebx;
+unsigned long saved_context_esp, saved_context_ebp;
+unsigned long saved_context_esi, saved_context_edi;
+unsigned long saved_context_eflags;
+#else
+/* CONFIG_X86_64 */
+struct saved_context saved_context;
+#endif
+
+/**
+ *     __save_processor_state - save CPU registers before creating a
+ *             hibernation image and before restoring the memory state from it
+ *     @ctxt - structure to store the registers contents in
+ *
+ *     NOTE: If there is a CPU register the modification of which by the
+ *     boot kernel (ie. the kernel used for loading the hibernation image)
+ *     might affect the operations of the restored target kernel (ie. the one
+ *     saved in the hibernation image), then its contents must be saved by this
+ *     function.  In other words, if kernel A is hibernated and different
+ *     kernel B is used for loading the hibernation image into memory, the
+ *     kernel A's __save_processor_state() function must save all registers
+ *     needed by kernel A, so that it can operate correctly after the resume
+ *     regardless of what kernel B does in the meantime.
+ */
+static void __save_processor_state(struct saved_context *ctxt)
+{
+#ifdef CONFIG_X86_32
+       mtrr_save_fixed_ranges(NULL);
+#endif
+       kernel_fpu_begin();
+
+       /*
+        * descriptor tables
+        */
+#ifdef CONFIG_X86_32
+       store_gdt(&ctxt->gdt);
+       store_idt(&ctxt->idt);
+#else
+/* CONFIG_X86_64 */
+       store_gdt((struct desc_ptr *)&ctxt->gdt_limit);
+       store_idt((struct desc_ptr *)&ctxt->idt_limit);
+#endif
+       store_tr(ctxt->tr);
+
+       /* XMM0..XMM15 should be handled by kernel_fpu_begin(). */
+       /*
+        * segment registers
+        */
+#ifdef CONFIG_X86_32
+       savesegment(es, ctxt->es);
+       savesegment(fs, ctxt->fs);
+       savesegment(gs, ctxt->gs);
+       savesegment(ss, ctxt->ss);
+#else
+/* CONFIG_X86_64 */
+       asm volatile ("movw %%ds, %0" : "=m" (ctxt->ds));
+       asm volatile ("movw %%es, %0" : "=m" (ctxt->es));
+       asm volatile ("movw %%fs, %0" : "=m" (ctxt->fs));
+       asm volatile ("movw %%gs, %0" : "=m" (ctxt->gs));
+       asm volatile ("movw %%ss, %0" : "=m" (ctxt->ss));
+
+       rdmsrl(MSR_FS_BASE, ctxt->fs_base);
+       rdmsrl(MSR_GS_BASE, ctxt->gs_base);
+       rdmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base);
+       mtrr_save_fixed_ranges(NULL);
+
+       rdmsrl(MSR_EFER, ctxt->efer);
+#endif
+
+       /*
+        * control registers
+        */
+       ctxt->cr0 = read_cr0();
+       ctxt->cr2 = read_cr2();
+       ctxt->cr3 = read_cr3();
+#ifdef CONFIG_X86_32
+       ctxt->cr4 = read_cr4_safe();
+#else
+/* CONFIG_X86_64 */
+       ctxt->cr4 = read_cr4();
+       ctxt->cr8 = read_cr8();
+#endif
+}
+
+/* Needed by apm.c */
+void save_processor_state(void)
+{
+       __save_processor_state(&saved_context);
+}
+#ifdef CONFIG_X86_32
+EXPORT_SYMBOL(save_processor_state);
+#endif
+
+static void do_fpu_end(void)
+{
+       /*
+        * Restore FPU regs if necessary.
+        */
+       kernel_fpu_end();
+}
+
+static void fix_processor_context(void)
+{
+       int cpu = smp_processor_id();
+       struct tss_struct *t = &per_cpu(init_tss, cpu);
+
+       set_tss_desc(cpu, t);   /*
+                                * This just modifies memory; should not be
+                                * necessary. But... This is necessary, because
+                                * 386 hardware has concept of busy TSS or some
+                                * similar stupidity.
+                                */
+
+#ifdef CONFIG_X86_64
+       get_cpu_gdt_table(cpu)[GDT_ENTRY_TSS].type = 9;
+
+       syscall_init();                         /* This sets MSR_*STAR and related */
+#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
+       }
+
+}
+
+/**
+ *     __restore_processor_state - restore the contents of CPU registers saved
+ *             by __save_processor_state()
+ *     @ctxt - structure to load the registers contents from
+ */
+static void __restore_processor_state(struct saved_context *ctxt)
+{
+       /*
+        * control registers
+        */
+       /* cr4 was introduced in the Pentium CPU */
+#ifdef CONFIG_X86_32
+       if (ctxt->cr4)
+               write_cr4(ctxt->cr4);
+#else
+/* CONFIG X86_64 */
+       wrmsrl(MSR_EFER, ctxt->efer);
+       write_cr8(ctxt->cr8);
+       write_cr4(ctxt->cr4);
+#endif
+       write_cr3(ctxt->cr3);
+       write_cr2(ctxt->cr2);
+       write_cr0(ctxt->cr0);
+
+       /*
+        * now restore the descriptor tables to their proper values
+        * ltr is done i fix_processor_context().
+        */
+#ifdef CONFIG_X86_32
+       load_gdt(&ctxt->gdt);
+       load_idt(&ctxt->idt);
+#else
+/* CONFIG_X86_64 */
+       load_gdt((const struct desc_ptr *)&ctxt->gdt_limit);
+       load_idt((const struct desc_ptr *)&ctxt->idt_limit);
+#endif
+
+       /*
+        * segment registers
+        */
+#ifdef CONFIG_X86_32
+       loadsegment(es, ctxt->es);
+       loadsegment(fs, ctxt->fs);
+       loadsegment(gs, ctxt->gs);
+       loadsegment(ss, ctxt->ss);
+
+       /*
+        * sysenter MSRs
+        */
+       if (boot_cpu_has(X86_FEATURE_SEP))
+               enable_sep_cpu();
+#else
+/* CONFIG_X86_64 */
+       asm volatile ("movw %0, %%ds" :: "r" (ctxt->ds));
+       asm volatile ("movw %0, %%es" :: "r" (ctxt->es));
+       asm volatile ("movw %0, %%fs" :: "r" (ctxt->fs));
+       load_gs_index(ctxt->gs);
+       asm volatile ("movw %0, %%ss" :: "r" (ctxt->ss));
+
+       wrmsrl(MSR_FS_BASE, ctxt->fs_base);
+       wrmsrl(MSR_GS_BASE, ctxt->gs_base);
+       wrmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base);
+#endif
+
+       /*
+        * restore XCR0 for xsave capable cpu's.
+        */
+       if (cpu_has_xsave)
+               xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask);
+
+       fix_processor_context();
+
+       do_fpu_end();
+       mtrr_ap_init();
+
+#ifdef CONFIG_X86_32
+       mcheck_init(&boot_cpu_data);
+#endif
+}
+
+/* Needed by apm.c */
+void restore_processor_state(void)
+{
+       __restore_processor_state(&saved_context);
+}
+#ifdef CONFIG_X86_32
+EXPORT_SYMBOL(restore_processor_state);
+#endif
diff --git a/arch/x86/power/cpu_32.c b/arch/x86/power/cpu_32.c
deleted file mode 100644 (file)
index ce702c5..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Suspend support specific for i386.
- *
- * Distribute under GPLv2
- *
- * Copyright (c) 2002 Pavel Machek <pavel@suse.cz>
- * Copyright (c) 2001 Patrick Mochel <mochel@osdl.org>
- */
-
-#include <linux/module.h>
-#include <linux/suspend.h>
-#include <asm/mtrr.h>
-#include <asm/mce.h>
-#include <asm/xcr.h>
-#include <asm/suspend.h>
-
-static struct saved_context saved_context;
-
-unsigned long saved_context_ebx;
-unsigned long saved_context_esp, saved_context_ebp;
-unsigned long saved_context_esi, saved_context_edi;
-unsigned long saved_context_eflags;
-
-static void __save_processor_state(struct saved_context *ctxt)
-{
-       mtrr_save_fixed_ranges(NULL);
-       kernel_fpu_begin();
-
-       /*
-        * descriptor tables
-        */
-       store_gdt(&ctxt->gdt);
-       store_idt(&ctxt->idt);
-       store_tr(ctxt->tr);
-
-       /*
-        * segment registers
-        */
-       savesegment(es, ctxt->es);
-       savesegment(fs, ctxt->fs);
-       savesegment(gs, ctxt->gs);
-       savesegment(ss, ctxt->ss);
-
-       /*
-        * control registers
-        */
-       ctxt->cr0 = read_cr0();
-       ctxt->cr2 = read_cr2();
-       ctxt->cr3 = read_cr3();
-       ctxt->cr4 = read_cr4_safe();
-}
-
-/* Needed by apm.c */
-void save_processor_state(void)
-{
-       __save_processor_state(&saved_context);
-}
-EXPORT_SYMBOL(save_processor_state);
-
-static void do_fpu_end(void)
-{
-       /*
-        * Restore FPU regs if necessary.
-        */
-       kernel_fpu_end();
-}
-
-static void fix_processor_context(void)
-{
-       int cpu = smp_processor_id();
-       struct tss_struct *t = &per_cpu(init_tss, cpu);
-
-       set_tss_desc(cpu, t);   /*
-                                * This just modifies memory; should not be
-                                * necessary. But... This is necessary, because
-                                * 386 hardware has concept of busy TSS or some
-                                * similar stupidity.
-                                */
-
-       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) {
-               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);
-       }
-
-}
-
-static void __restore_processor_state(struct saved_context *ctxt)
-{
-       /*
-        * control registers
-        */
-       /* cr4 was introduced in the Pentium CPU */
-       if (ctxt->cr4)
-               write_cr4(ctxt->cr4);
-       write_cr3(ctxt->cr3);
-       write_cr2(ctxt->cr2);
-       write_cr0(ctxt->cr0);
-
-       /*
-        * now restore the descriptor tables to their proper values
-        * ltr is done i fix_processor_context().
-        */
-       load_gdt(&ctxt->gdt);
-       load_idt(&ctxt->idt);
-
-       /*
-        * segment registers
-        */
-       loadsegment(es, ctxt->es);
-       loadsegment(fs, ctxt->fs);
-       loadsegment(gs, ctxt->gs);
-       loadsegment(ss, ctxt->ss);
-
-       /*
-        * sysenter MSRs
-        */
-       if (boot_cpu_has(X86_FEATURE_SEP))
-               enable_sep_cpu();
-
-       /*
-        * restore XCR0 for xsave capable cpu's.
-        */
-       if (cpu_has_xsave)
-               xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask);
-
-       fix_processor_context();
-       do_fpu_end();
-       mtrr_ap_init();
-       mcheck_init(&boot_cpu_data);
-}
-
-/* Needed by apm.c */
-void restore_processor_state(void)
-{
-       __restore_processor_state(&saved_context);
-}
-EXPORT_SYMBOL(restore_processor_state);
diff --git a/arch/x86/power/cpu_64.c b/arch/x86/power/cpu_64.c
deleted file mode 100644 (file)
index 5343540..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Suspend and hibernation support for x86-64
- *
- * Distribute under GPLv2
- *
- * Copyright (c) 2007 Rafael J. Wysocki <rjw@sisk.pl>
- * Copyright (c) 2002 Pavel Machek <pavel@suse.cz>
- * Copyright (c) 2001 Patrick Mochel <mochel@osdl.org>
- */
-
-#include <linux/smp.h>
-#include <linux/suspend.h>
-#include <asm/proto.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/mtrr.h>
-#include <asm/xcr.h>
-#include <asm/suspend.h>
-
-static void fix_processor_context(void);
-
-struct saved_context saved_context;
-
-/**
- *     __save_processor_state - save CPU registers before creating a
- *             hibernation image and before restoring the memory state from it
- *     @ctxt - structure to store the registers contents in
- *
- *     NOTE: If there is a CPU register the modification of which by the
- *     boot kernel (ie. the kernel used for loading the hibernation image)
- *     might affect the operations of the restored target kernel (ie. the one
- *     saved in the hibernation image), then its contents must be saved by this
- *     function.  In other words, if kernel A is hibernated and different
- *     kernel B is used for loading the hibernation image into memory, the
- *     kernel A's __save_processor_state() function must save all registers
- *     needed by kernel A, so that it can operate correctly after the resume
- *     regardless of what kernel B does in the meantime.
- */
-static void __save_processor_state(struct saved_context *ctxt)
-{
-       kernel_fpu_begin();
-
-       /*
-        * descriptor tables
-        */
-       store_gdt((struct desc_ptr *)&ctxt->gdt_limit);
-       store_idt((struct desc_ptr *)&ctxt->idt_limit);
-       store_tr(ctxt->tr);
-
-       /* XMM0..XMM15 should be handled by kernel_fpu_begin(). */
-       /*
-        * segment registers
-        */
-       asm volatile ("movw %%ds, %0" : "=m" (ctxt->ds));
-       asm volatile ("movw %%es, %0" : "=m" (ctxt->es));
-       asm volatile ("movw %%fs, %0" : "=m" (ctxt->fs));
-       asm volatile ("movw %%gs, %0" : "=m" (ctxt->gs));
-       asm volatile ("movw %%ss, %0" : "=m" (ctxt->ss));
-
-       rdmsrl(MSR_FS_BASE, ctxt->fs_base);
-       rdmsrl(MSR_GS_BASE, ctxt->gs_base);
-       rdmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base);
-       mtrr_save_fixed_ranges(NULL);
-
-       /*
-        * control registers
-        */
-       rdmsrl(MSR_EFER, ctxt->efer);
-       ctxt->cr0 = read_cr0();
-       ctxt->cr2 = read_cr2();
-       ctxt->cr3 = read_cr3();
-       ctxt->cr4 = read_cr4();
-       ctxt->cr8 = read_cr8();
-}
-
-void save_processor_state(void)
-{
-       __save_processor_state(&saved_context);
-}
-
-static void do_fpu_end(void)
-{
-       /*
-        * Restore FPU regs if necessary
-        */
-       kernel_fpu_end();
-}
-
-/**
- *     __restore_processor_state - restore the contents of CPU registers saved
- *             by __save_processor_state()
- *     @ctxt - structure to load the registers contents from
- */
-static void __restore_processor_state(struct saved_context *ctxt)
-{
-       /*
-        * control registers
-        */
-       wrmsrl(MSR_EFER, ctxt->efer);
-       write_cr8(ctxt->cr8);
-       write_cr4(ctxt->cr4);
-       write_cr3(ctxt->cr3);
-       write_cr2(ctxt->cr2);
-       write_cr0(ctxt->cr0);
-
-       /*
-        * now restore the descriptor tables to their proper values
-        * ltr is done i fix_processor_context().
-        */
-       load_gdt((const struct desc_ptr *)&ctxt->gdt_limit);
-       load_idt((const struct desc_ptr *)&ctxt->idt_limit);
-
-
-       /*
-        * segment registers
-        */
-       asm volatile ("movw %0, %%ds" :: "r" (ctxt->ds));
-       asm volatile ("movw %0, %%es" :: "r" (ctxt->es));
-       asm volatile ("movw %0, %%fs" :: "r" (ctxt->fs));
-       load_gs_index(ctxt->gs);
-       asm volatile ("movw %0, %%ss" :: "r" (ctxt->ss));
-
-       wrmsrl(MSR_FS_BASE, ctxt->fs_base);
-       wrmsrl(MSR_GS_BASE, ctxt->gs_base);
-       wrmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base);
-
-       /*
-        * restore XCR0 for xsave capable cpu's.
-        */
-       if (cpu_has_xsave)
-               xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask);
-
-       fix_processor_context();
-
-       do_fpu_end();
-       mtrr_ap_init();
-}
-
-void restore_processor_state(void)
-{
-       __restore_processor_state(&saved_context);
-}
-
-static void fix_processor_context(void)
-{
-       int cpu = smp_processor_id();
-       struct tss_struct *t = &per_cpu(init_tss, cpu);
-
-       /*
-        * This just modifies memory; should not be necessary. But... This
-        * is necessary, because 386 hardware has concept of busy TSS or some
-        * similar stupidity.
-        */
-       set_tss_desc(cpu, t);
-
-       get_cpu_gdt_table(cpu)[GDT_ENTRY_TSS].type = 9;
-
-       syscall_init();                         /* This sets MSR_*STAR and related */
-       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){
-                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);
-       }
-}
index 67ad67bed8c14abb1c3daac72a0106d80e31c9af..22d6dde426192266c3915403f8a73785fef6f916 100644 (file)
@@ -292,7 +292,7 @@ static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
 #define smp_mb__before_atomic_inc()    barrier()
 #define smp_mb__after_atomic_inc()     barrier()
 
-#include <asm-generic/atomic.h>
+#include <asm-generic/atomic-long.h>
 #endif /* __KERNEL__ */
 
 #endif /* _XTENSA_ATOMIC_H */
diff --git a/arch/xtensa/include/asm/bitsperlong.h b/arch/xtensa/include/asm/bitsperlong.h
new file mode 100644 (file)
index 0000000..6dc0bb0
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/bitsperlong.h>
index 17e0c5383b108abb9dac7af627aa00ac1fd343ec..161bb89e98c8b20f8b76f9c194bffa2727fa6cf2 100644 (file)
@@ -129,7 +129,7 @@ static inline __attribute_const__ int get_order(unsigned long size)
 
 #else
 
-# include <asm-generic/page.h>
+# include <asm-generic/getorder.h>
 
 #endif
 
index 3981a466c779cfd57f8e4cd0033581d8dfc3edd4..c1accea8cb56c036cec14091d5b85f98b2c572e7 100644 (file)
@@ -34,8 +34,6 @@ void *module_alloc(unsigned long size)
 void module_free(struct module *mod, void *module_region)
 {
        vfree(module_region);
-       /* FIXME: If module_region == mod->init_region, trim exception
-          table entries. */
 }
 
 int module_frob_arch_sections(Elf32_Ehdr *hdr,
index 74d0e622a5153beb758ca95123da6c07628ebc23..4dfdd03e708f2a31a2507301592ae98a50f67fb4 100644 (file)
@@ -241,6 +241,11 @@ config CRYPTO_XTS
          key size 256, 384 or 512 bits. This implementation currently
          can't handle a sectorsize which is not a multiple of 16 bytes.
 
+config CRYPTO_FPU
+       tristate
+       select CRYPTO_BLKCIPHER
+       select CRYPTO_MANAGER
+
 comment "Hash modes"
 
 config CRYPTO_HMAC
@@ -486,6 +491,7 @@ config CRYPTO_AES_NI_INTEL
        select CRYPTO_AES_X86_64
        select CRYPTO_CRYPTD
        select CRYPTO_ALGAPI
+       select CRYPTO_FPU
        help
          Use Intel AES-NI instructions for AES algorithm.
 
@@ -505,6 +511,10 @@ config CRYPTO_AES_NI_INTEL
 
          See <http://csrc.nist.gov/encryption/aes/> for more information.
 
+         In addition to AES cipher algorithm support, the
+         acceleration for some popular block cipher mode is supported
+         too, including ECB, CBC, CTR, LRW, PCBC, XTS.
+
 config CRYPTO_ANUBIS
        tristate "Anubis cipher algorithm"
        select CRYPTO_ALGAPI
index 6906f92aeac03330653a9539550861f1f6cffb9f..9908dd830c2631041c3a681b3efae8b4eb687e39 100644 (file)
@@ -280,29 +280,13 @@ static struct notifier_block cryptomgr_notifier = {
 
 static int __init cryptomgr_init(void)
 {
-       int err;
-
-       err = testmgr_init();
-       if (err)
-               return err;
-
-       err = crypto_register_notifier(&cryptomgr_notifier);
-       if (err)
-               goto free_testmgr;
-
-       return 0;
-
-free_testmgr:
-       testmgr_exit();
-       return err;
+       return crypto_register_notifier(&cryptomgr_notifier);
 }
 
 static void __exit cryptomgr_exit(void)
 {
        int err = crypto_unregister_notifier(&cryptomgr_notifier);
        BUG_ON(err);
-
-       testmgr_exit();
 }
 
 subsys_initcall(cryptomgr_init);
index fd2545decb280a6045c1c5fa19447e6bc1fbe907..d5944f92b4162845e305c9dc6f2df85576808240 100644 (file)
@@ -217,14 +217,11 @@ struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, u32 mask)
 
        alg = crypto_alg_lookup(name, type, mask);
        if (!alg) {
-               char tmp[CRYPTO_MAX_ALG_NAME];
-
-               request_module(name);
+               request_module("%s", name);
 
                if (!((type ^ CRYPTO_ALG_NEED_FALLBACK) & mask &
-                     CRYPTO_ALG_NEED_FALLBACK) &&
-                   snprintf(tmp, sizeof(tmp), "%s-all", name) < sizeof(tmp))
-                       request_module(tmp);
+                     CRYPTO_ALG_NEED_FALLBACK))
+                       request_module("%s-all", name);
 
                alg = crypto_alg_lookup(name, type, mask);
        }
@@ -580,20 +577,17 @@ EXPORT_SYMBOL_GPL(crypto_alloc_tfm);
 void crypto_destroy_tfm(void *mem, struct crypto_tfm *tfm)
 {
        struct crypto_alg *alg;
-       int size;
 
        if (unlikely(!mem))
                return;
 
        alg = tfm->__crt_alg;
-       size = ksize(mem);
 
        if (!tfm->exit && alg->cra_exit)
                alg->cra_exit(tfm);
        crypto_exit_ops(tfm);
        crypto_mod_put(alg);
-       memset(mem, 0, size);
-       kfree(mem);
+       kzfree(mem);
 }
 EXPORT_SYMBOL_GPL(crypto_destroy_tfm);
 
index d14b22658d7a57d907344ba9145ae6c2c809660a..ae5fa99d5d3666b4f483469f1cd1464bb36cb172 100644 (file)
@@ -586,20 +586,24 @@ struct cryptd_ablkcipher *cryptd_alloc_ablkcipher(const char *alg_name,
                                                  u32 type, u32 mask)
 {
        char cryptd_alg_name[CRYPTO_MAX_ALG_NAME];
-       struct crypto_ablkcipher *tfm;
+       struct crypto_tfm *tfm;
 
        if (snprintf(cryptd_alg_name, CRYPTO_MAX_ALG_NAME,
                     "cryptd(%s)", alg_name) >= CRYPTO_MAX_ALG_NAME)
                return ERR_PTR(-EINVAL);
-       tfm = crypto_alloc_ablkcipher(cryptd_alg_name, type, mask);
+       type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
+       type |= CRYPTO_ALG_TYPE_BLKCIPHER;
+       mask &= ~CRYPTO_ALG_TYPE_MASK;
+       mask |= (CRYPTO_ALG_GENIV | CRYPTO_ALG_TYPE_BLKCIPHER_MASK);
+       tfm = crypto_alloc_base(cryptd_alg_name, type, mask);
        if (IS_ERR(tfm))
                return ERR_CAST(tfm);
-       if (crypto_ablkcipher_tfm(tfm)->__crt_alg->cra_module != THIS_MODULE) {
-               crypto_free_ablkcipher(tfm);
+       if (tfm->__crt_alg->cra_module != THIS_MODULE) {
+               crypto_free_tfm(tfm);
                return ERR_PTR(-EINVAL);
        }
 
-       return __cryptd_ablkcipher_cast(tfm);
+       return __cryptd_ablkcipher_cast(__crypto_ablkcipher_cast(tfm));
 }
 EXPORT_SYMBOL_GPL(cryptd_alloc_ablkcipher);
 
index fc76e1f37fc35d0fd4928ec9326b330c22937d53..113579a82dff41e6656d29b3f95767981dd6fc2a 100644 (file)
@@ -121,9 +121,6 @@ int crypto_register_notifier(struct notifier_block *nb);
 int crypto_unregister_notifier(struct notifier_block *nb);
 int crypto_probing_notify(unsigned long val, void *v);
 
-int __init testmgr_init(void);
-void testmgr_exit(void);
-
 static inline void crypto_alg_put(struct crypto_alg *alg)
 {
        if (atomic_dec_and_test(&alg->cra_refcnt) && alg->cra_destroy)
index ca9a4af91efe60f2cc5a17751651900be1c334b5..bcadc03726b7eb2d12ac71b251da31e4e38651bf 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/string.h>
 
 #include <crypto/compress.h>
+#include <crypto/internal/compress.h>
 
 #include "internal.h"
 
index c3c9124209a1901baae3f8e6d9b1a6e437e97901..d59ba5079d14617a51554b5042ea7a10f5ab8235 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/timex.h>
 #include <linux/interrupt.h>
 #include "tcrypt.h"
+#include "internal.h"
 
 /*
  * Need slab memory for testing (size in number of pages).
@@ -396,16 +397,16 @@ static void test_hash_speed(const char *algo, unsigned int sec,
        struct scatterlist sg[TVMEMSIZE];
        struct crypto_hash *tfm;
        struct hash_desc desc;
-       char output[1024];
+       static char output[1024];
        int i;
        int ret;
 
-       printk("\ntesting speed of %s\n", algo);
+       printk(KERN_INFO "\ntesting speed of %s\n", algo);
 
        tfm = crypto_alloc_hash(algo, 0, CRYPTO_ALG_ASYNC);
 
        if (IS_ERR(tfm)) {
-               printk("failed to load transform for %s: %ld\n", algo,
+               printk(KERN_ERR "failed to load transform for %s: %ld\n", algo,
                       PTR_ERR(tfm));
                return;
        }
@@ -414,7 +415,7 @@ static void test_hash_speed(const char *algo, unsigned int sec,
        desc.flags = 0;
 
        if (crypto_hash_digestsize(tfm) > sizeof(output)) {
-               printk("digestsize(%u) > outputbuffer(%zu)\n",
+               printk(KERN_ERR "digestsize(%u) > outputbuffer(%zu)\n",
                       crypto_hash_digestsize(tfm), sizeof(output));
                goto out;
        }
@@ -427,12 +428,14 @@ static void test_hash_speed(const char *algo, unsigned int sec,
 
        for (i = 0; speed[i].blen != 0; i++) {
                if (speed[i].blen > TVMEMSIZE * PAGE_SIZE) {
-                       printk("template (%u) too big for tvmem (%lu)\n",
+                       printk(KERN_ERR
+                              "template (%u) too big for tvmem (%lu)\n",
                               speed[i].blen, TVMEMSIZE * PAGE_SIZE);
                        goto out;
                }
 
-               printk("test%3u (%5u byte blocks,%5u bytes per update,%4u updates): ",
+               printk(KERN_INFO "test%3u "
+                      "(%5u byte blocks,%5u bytes per update,%4u updates): ",
                       i, speed[i].blen, speed[i].plen, speed[i].blen / speed[i].plen);
 
                if (sec)
@@ -443,7 +446,7 @@ static void test_hash_speed(const char *algo, unsigned int sec,
                                               speed[i].plen, output);
 
                if (ret) {
-                       printk("hashing failed ret=%d\n", ret);
+                       printk(KERN_ERR "hashing failed ret=%d\n", ret);
                        break;
                }
        }
@@ -466,239 +469,255 @@ static void test_available(void)
 
 static inline int tcrypt_test(const char *alg)
 {
-       return alg_test(alg, alg, 0, 0);
+       int ret;
+
+       ret = alg_test(alg, alg, 0, 0);
+       /* non-fips algs return -EINVAL in fips mode */
+       if (fips_enabled && ret == -EINVAL)
+               ret = 0;
+       return ret;
 }
 
-static void do_test(int m)
+static int do_test(int m)
 {
        int i;
+       int ret = 0;
 
        switch (m) {
        case 0:
                for (i = 1; i < 200; i++)
-                       do_test(i);
+                       ret += do_test(i);
                break;
 
        case 1:
-               tcrypt_test("md5");
+               ret += tcrypt_test("md5");
                break;
 
        case 2:
-               tcrypt_test("sha1");
+               ret += tcrypt_test("sha1");
                break;
 
        case 3:
-               tcrypt_test("ecb(des)");
-               tcrypt_test("cbc(des)");
+               ret += tcrypt_test("ecb(des)");
+               ret += tcrypt_test("cbc(des)");
                break;
 
        case 4:
-               tcrypt_test("ecb(des3_ede)");
-               tcrypt_test("cbc(des3_ede)");
+               ret += tcrypt_test("ecb(des3_ede)");
+               ret += tcrypt_test("cbc(des3_ede)");
                break;
 
        case 5:
-               tcrypt_test("md4");
+               ret += tcrypt_test("md4");
                break;
 
        case 6:
-               tcrypt_test("sha256");
+               ret += tcrypt_test("sha256");
                break;
 
        case 7:
-               tcrypt_test("ecb(blowfish)");
-               tcrypt_test("cbc(blowfish)");
+               ret += tcrypt_test("ecb(blowfish)");
+               ret += tcrypt_test("cbc(blowfish)");
                break;
 
        case 8:
-               tcrypt_test("ecb(twofish)");
-               tcrypt_test("cbc(twofish)");
+               ret += tcrypt_test("ecb(twofish)");
+               ret += tcrypt_test("cbc(twofish)");
                break;
 
        case 9:
-               tcrypt_test("ecb(serpent)");
+               ret += tcrypt_test("ecb(serpent)");
                break;
 
        case 10:
-               tcrypt_test("ecb(aes)");
-               tcrypt_test("cbc(aes)");
-               tcrypt_test("lrw(aes)");
-               tcrypt_test("xts(aes)");
-               tcrypt_test("rfc3686(ctr(aes))");
+               ret += tcrypt_test("ecb(aes)");
+               ret += tcrypt_test("cbc(aes)");
+               ret += tcrypt_test("lrw(aes)");
+               ret += tcrypt_test("xts(aes)");
+               ret += tcrypt_test("ctr(aes)");
+               ret += tcrypt_test("rfc3686(ctr(aes))");
                break;
 
        case 11:
-               tcrypt_test("sha384");
+               ret += tcrypt_test("sha384");
                break;
 
        case 12:
-               tcrypt_test("sha512");
+               ret += tcrypt_test("sha512");
                break;
 
        case 13:
-               tcrypt_test("deflate");
+               ret += tcrypt_test("deflate");
                break;
 
        case 14:
-               tcrypt_test("ecb(cast5)");
+               ret += tcrypt_test("ecb(cast5)");
                break;
 
        case 15:
-               tcrypt_test("ecb(cast6)");
+               ret += tcrypt_test("ecb(cast6)");
                break;
 
        case 16:
-               tcrypt_test("ecb(arc4)");
+               ret += tcrypt_test("ecb(arc4)");
                break;
 
        case 17:
-               tcrypt_test("michael_mic");
+               ret += tcrypt_test("michael_mic");
                break;
 
        case 18:
-               tcrypt_test("crc32c");
+               ret += tcrypt_test("crc32c");
                break;
 
        case 19:
-               tcrypt_test("ecb(tea)");
+               ret += tcrypt_test("ecb(tea)");
                break;
 
        case 20:
-               tcrypt_test("ecb(xtea)");
+               ret += tcrypt_test("ecb(xtea)");
                break;
 
        case 21:
-               tcrypt_test("ecb(khazad)");
+               ret += tcrypt_test("ecb(khazad)");
                break;
 
        case 22:
-               tcrypt_test("wp512");
+               ret += tcrypt_test("wp512");
                break;
 
        case 23:
-               tcrypt_test("wp384");
+               ret += tcrypt_test("wp384");
                break;
 
        case 24:
-               tcrypt_test("wp256");
+               ret += tcrypt_test("wp256");
                break;
 
        case 25:
-               tcrypt_test("ecb(tnepres)");
+               ret += tcrypt_test("ecb(tnepres)");
                break;
 
        case 26:
-               tcrypt_test("ecb(anubis)");
-               tcrypt_test("cbc(anubis)");
+               ret += tcrypt_test("ecb(anubis)");
+               ret += tcrypt_test("cbc(anubis)");
                break;
 
        case 27:
-               tcrypt_test("tgr192");
+               ret += tcrypt_test("tgr192");
                break;
 
        case 28:
 
-               tcrypt_test("tgr160");
+               ret += tcrypt_test("tgr160");
                break;
 
        case 29:
-               tcrypt_test("tgr128");
+               ret += tcrypt_test("tgr128");
                break;
 
        case 30:
-               tcrypt_test("ecb(xeta)");
+               ret += tcrypt_test("ecb(xeta)");
                break;
 
        case 31:
-               tcrypt_test("pcbc(fcrypt)");
+               ret += tcrypt_test("pcbc(fcrypt)");
                break;
 
        case 32:
-               tcrypt_test("ecb(camellia)");
-               tcrypt_test("cbc(camellia)");
+               ret += tcrypt_test("ecb(camellia)");
+               ret += tcrypt_test("cbc(camellia)");
                break;
        case 33:
-               tcrypt_test("sha224");
+               ret += tcrypt_test("sha224");
                break;
 
        case 34:
-               tcrypt_test("salsa20");
+               ret += tcrypt_test("salsa20");
                break;
 
        case 35:
-               tcrypt_test("gcm(aes)");
+               ret += tcrypt_test("gcm(aes)");
                break;
 
        case 36:
-               tcrypt_test("lzo");
+               ret += tcrypt_test("lzo");
                break;
 
        case 37:
-               tcrypt_test("ccm(aes)");
+               ret += tcrypt_test("ccm(aes)");
                break;
 
        case 38:
-               tcrypt_test("cts(cbc(aes))");
+               ret += tcrypt_test("cts(cbc(aes))");
                break;
 
         case 39:
-               tcrypt_test("rmd128");
+               ret += tcrypt_test("rmd128");
                break;
 
         case 40:
-               tcrypt_test("rmd160");
+               ret += tcrypt_test("rmd160");
                break;
 
        case 41:
-               tcrypt_test("rmd256");
+               ret += tcrypt_test("rmd256");
                break;
 
        case 42:
-               tcrypt_test("rmd320");
+               ret += tcrypt_test("rmd320");
                break;
 
        case 43:
-               tcrypt_test("ecb(seed)");
+               ret += tcrypt_test("ecb(seed)");
                break;
 
        case 44:
-               tcrypt_test("zlib");
+               ret += tcrypt_test("zlib");
+               break;
+
+       case 45:
+               ret += tcrypt_test("rfc4309(ccm(aes))");
                break;
 
        case 100:
-               tcrypt_test("hmac(md5)");
+               ret += tcrypt_test("hmac(md5)");
                break;
 
        case 101:
-               tcrypt_test("hmac(sha1)");
+               ret += tcrypt_test("hmac(sha1)");
                break;
 
        case 102:
-               tcrypt_test("hmac(sha256)");
+               ret += tcrypt_test("hmac(sha256)");
                break;
 
        case 103:
-               tcrypt_test("hmac(sha384)");
+               ret += tcrypt_test("hmac(sha384)");
                break;
 
        case 104:
-               tcrypt_test("hmac(sha512)");
+               ret += tcrypt_test("hmac(sha512)");
                break;
 
        case 105:
-               tcrypt_test("hmac(sha224)");
+               ret += tcrypt_test("hmac(sha224)");
                break;
 
        case 106:
-               tcrypt_test("xcbc(aes)");
+               ret += tcrypt_test("xcbc(aes)");
                break;
 
        case 107:
-               tcrypt_test("hmac(rmd128)");
+               ret += tcrypt_test("hmac(rmd128)");
                break;
 
        case 108:
-               tcrypt_test("hmac(rmd160)");
+               ret += tcrypt_test("hmac(rmd160)");
+               break;
+
+       case 150:
+               ret += tcrypt_test("ansi_cprng");
                break;
 
        case 200:
@@ -862,6 +881,8 @@ static void do_test(int m)
                test_available();
                break;
        }
+
+       return ret;
 }
 
 static int __init tcrypt_mod_init(void)
@@ -875,15 +896,21 @@ static int __init tcrypt_mod_init(void)
                        goto err_free_tv;
        }
 
-       do_test(mode);
+       err = do_test(mode);
+       if (err) {
+               printk(KERN_ERR "tcrypt: one or more tests failed!\n");
+               goto err_free_tv;
+       }
 
-       /* We intentionaly return -EAGAIN to prevent keeping
-        * the module. It does all its work from init()
-        * and doesn't offer any runtime functionality 
+       /* We intentionaly return -EAGAIN to prevent keeping the module,
+        * unless we're running in fips mode. It does all its work from
+        * init() and doesn't offer any runtime functionality, but in
+        * the fips case, checking for a successful load is helpful.
         * => we don't need it in the memory, do we?
         *                                        -- mludvig
         */
-       err = -EAGAIN;
+       if (!fips_enabled)
+               err = -EAGAIN;
 
 err_free_tv:
        for (i = 0; i < TVMEMSIZE && tvmem[i]; i++)
index b50c3c6b17a26301a8a799bf62a29fe5e0c89d46..e9e9d84293b9f953e6c41835778d2bb7a878c694 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <crypto/rng.h>
 
 #include "internal.h"
 #include "testmgr.h"
@@ -84,10 +85,16 @@ struct hash_test_suite {
        unsigned int count;
 };
 
+struct cprng_test_suite {
+       struct cprng_testvec *vecs;
+       unsigned int count;
+};
+
 struct alg_test_desc {
        const char *alg;
        int (*test)(const struct alg_test_desc *desc, const char *driver,
                    u32 type, u32 mask);
+       int fips_allowed;       /* set if alg is allowed in fips mode */
 
        union {
                struct aead_test_suite aead;
@@ -95,14 +102,12 @@ struct alg_test_desc {
                struct comp_test_suite comp;
                struct pcomp_test_suite pcomp;
                struct hash_test_suite hash;
+               struct cprng_test_suite cprng;
        } suite;
 };
 
 static unsigned int IDX[8] = { IDX1, IDX2, IDX3, IDX4, IDX5, IDX6, IDX7, IDX8 };
 
-static char *xbuf[XBUFSIZE];
-static char *axbuf[XBUFSIZE];
-
 static void hexdump(unsigned char *buf, unsigned int len)
 {
        print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET,
@@ -121,6 +126,33 @@ static void tcrypt_complete(struct crypto_async_request *req, int err)
        complete(&res->completion);
 }
 
+static int testmgr_alloc_buf(char *buf[XBUFSIZE])
+{
+       int i;
+
+       for (i = 0; i < XBUFSIZE; i++) {
+               buf[i] = (void *)__get_free_page(GFP_KERNEL);
+               if (!buf[i])
+                       goto err_free_buf;
+       }
+
+       return 0;
+
+err_free_buf:
+       while (i-- > 0)
+               free_page((unsigned long)buf[i]);
+
+       return -ENOMEM;
+}
+
+static void testmgr_free_buf(char *buf[XBUFSIZE])
+{
+       int i;
+
+       for (i = 0; i < XBUFSIZE; i++)
+               free_page((unsigned long)buf[i]);
+}
+
 static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template,
                     unsigned int tcount)
 {
@@ -130,8 +162,12 @@ static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template,
        char result[64];
        struct ahash_request *req;
        struct tcrypt_result tresult;
-       int ret;
        void *hash_buff;
+       char *xbuf[XBUFSIZE];
+       int ret = -ENOMEM;
+
+       if (testmgr_alloc_buf(xbuf))
+               goto out_nobuf;
 
        init_completion(&tresult.completion);
 
@@ -139,17 +175,25 @@ static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template,
        if (!req) {
                printk(KERN_ERR "alg: hash: Failed to allocate request for "
                       "%s\n", algo);
-               ret = -ENOMEM;
                goto out_noreq;
        }
        ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
                                   tcrypt_complete, &tresult);
 
+       j = 0;
        for (i = 0; i < tcount; i++) {
+               if (template[i].np)
+                       continue;
+
+               j++;
                memset(result, 0, 64);
 
                hash_buff = xbuf[0];
 
+               ret = -EINVAL;
+               if (WARN_ON(template[i].psize > PAGE_SIZE))
+                       goto out;
+
                memcpy(hash_buff, template[i].plaintext, template[i].psize);
                sg_init_one(&sg[0], hash_buff, template[i].psize);
 
@@ -159,7 +203,7 @@ static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template,
                                                  template[i].ksize);
                        if (ret) {
                                printk(KERN_ERR "alg: hash: setkey failed on "
-                                      "test %d for %s: ret=%d\n", i + 1, algo,
+                                      "test %d for %s: ret=%d\n", j, algo,
                                       -ret);
                                goto out;
                        }
@@ -181,14 +225,14 @@ static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template,
                        /* fall through */
                default:
                        printk(KERN_ERR "alg: hash: digest failed on test %d "
-                              "for %s: ret=%d\n", i + 1, algo, -ret);
+                              "for %s: ret=%d\n", j, algo, -ret);
                        goto out;
                }
 
                if (memcmp(result, template[i].digest,
                           crypto_ahash_digestsize(tfm))) {
                        printk(KERN_ERR "alg: hash: Test %d failed for %s\n",
-                              i + 1, algo);
+                              j, algo);
                        hexdump(result, crypto_ahash_digestsize(tfm));
                        ret = -EINVAL;
                        goto out;
@@ -203,7 +247,11 @@ static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template,
 
                        temp = 0;
                        sg_init_table(sg, template[i].np);
+                       ret = -EINVAL;
                        for (k = 0; k < template[i].np; k++) {
+                               if (WARN_ON(offset_in_page(IDX[k]) +
+                                           template[i].tap[k] > PAGE_SIZE))
+                                       goto out;
                                sg_set_buf(&sg[k],
                                           memcpy(xbuf[IDX[k] >> PAGE_SHIFT] +
                                                  offset_in_page(IDX[k]),
@@ -265,6 +313,8 @@ static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template,
 out:
        ahash_request_free(req);
 out_noreq:
+       testmgr_free_buf(xbuf);
+out_nobuf:
        return ret;
 }
 
@@ -273,7 +323,7 @@ static int test_aead(struct crypto_aead *tfm, int enc,
 {
        const char *algo = crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm));
        unsigned int i, j, k, n, temp;
-       int ret = 0;
+       int ret = -ENOMEM;
        char *q;
        char *key;
        struct aead_request *req;
@@ -285,6 +335,13 @@ static int test_aead(struct crypto_aead *tfm, int enc,
        void *input;
        void *assoc;
        char iv[MAX_IVLEN];
+       char *xbuf[XBUFSIZE];
+       char *axbuf[XBUFSIZE];
+
+       if (testmgr_alloc_buf(xbuf))
+               goto out_noxbuf;
+       if (testmgr_alloc_buf(axbuf))
+               goto out_noaxbuf;
 
        if (enc == ENCRYPT)
                e = "encryption";
@@ -297,7 +354,6 @@ static int test_aead(struct crypto_aead *tfm, int enc,
        if (!req) {
                printk(KERN_ERR "alg: aead: Failed to allocate request for "
                       "%s\n", algo);
-               ret = -ENOMEM;
                goto out;
        }
 
@@ -314,6 +370,11 @@ static int test_aead(struct crypto_aead *tfm, int enc,
                        input = xbuf[0];
                        assoc = axbuf[0];
 
+                       ret = -EINVAL;
+                       if (WARN_ON(template[i].ilen > PAGE_SIZE ||
+                                   template[i].alen > PAGE_SIZE))
+                               goto out;
+
                        memcpy(input, template[i].input, template[i].ilen);
                        memcpy(assoc, template[i].assoc, template[i].alen);
                        if (template[i].iv)
@@ -363,6 +424,16 @@ static int test_aead(struct crypto_aead *tfm, int enc,
 
                        switch (ret) {
                        case 0:
+                               if (template[i].novrfy) {
+                                       /* verification was supposed to fail */
+                                       printk(KERN_ERR "alg: aead: %s failed "
+                                              "on test %d for %s: ret was 0, "
+                                              "expected -EBADMSG\n",
+                                              e, j, algo);
+                                       /* so really, we got a bad message */
+                                       ret = -EBADMSG;
+                                       goto out;
+                               }
                                break;
                        case -EINPROGRESS:
                        case -EBUSY:
@@ -372,6 +443,10 @@ static int test_aead(struct crypto_aead *tfm, int enc,
                                        INIT_COMPLETION(result.completion);
                                        break;
                                }
+                       case -EBADMSG:
+                               if (template[i].novrfy)
+                                       /* verification failure was expected */
+                                       continue;
                                /* fall through */
                        default:
                                printk(KERN_ERR "alg: aead: %s failed on test "
@@ -459,7 +534,11 @@ static int test_aead(struct crypto_aead *tfm, int enc,
                        }
 
                        sg_init_table(asg, template[i].anp);
+                       ret = -EINVAL;
                        for (k = 0, temp = 0; k < template[i].anp; k++) {
+                               if (WARN_ON(offset_in_page(IDX[k]) +
+                                           template[i].atap[k] > PAGE_SIZE))
+                                       goto out;
                                sg_set_buf(&asg[k],
                                           memcpy(axbuf[IDX[k] >> PAGE_SHIFT] +
                                                  offset_in_page(IDX[k]),
@@ -481,6 +560,16 @@ static int test_aead(struct crypto_aead *tfm, int enc,
 
                        switch (ret) {
                        case 0:
+                               if (template[i].novrfy) {
+                                       /* verification was supposed to fail */
+                                       printk(KERN_ERR "alg: aead: %s failed "
+                                              "on chunk test %d for %s: ret "
+                                              "was 0, expected -EBADMSG\n",
+                                              e, j, algo);
+                                       /* so really, we got a bad message */
+                                       ret = -EBADMSG;
+                                       goto out;
+                               }
                                break;
                        case -EINPROGRESS:
                        case -EBUSY:
@@ -490,6 +579,10 @@ static int test_aead(struct crypto_aead *tfm, int enc,
                                        INIT_COMPLETION(result.completion);
                                        break;
                                }
+                       case -EBADMSG:
+                               if (template[i].novrfy)
+                                       /* verification failure was expected */
+                                       continue;
                                /* fall through */
                        default:
                                printk(KERN_ERR "alg: aead: %s failed on "
@@ -546,6 +639,10 @@ static int test_aead(struct crypto_aead *tfm, int enc,
 
 out:
        aead_request_free(req);
+       testmgr_free_buf(axbuf);
+out_noaxbuf:
+       testmgr_free_buf(xbuf);
+out_noxbuf:
        return ret;
 }
 
@@ -554,10 +651,14 @@ static int test_cipher(struct crypto_cipher *tfm, int enc,
 {
        const char *algo = crypto_tfm_alg_driver_name(crypto_cipher_tfm(tfm));
        unsigned int i, j, k;
-       int ret;
        char *q;
        const char *e;
        void *data;
+       char *xbuf[XBUFSIZE];
+       int ret = -ENOMEM;
+
+       if (testmgr_alloc_buf(xbuf))
+               goto out_nobuf;
 
        if (enc == ENCRYPT)
                e = "encryption";
@@ -571,6 +672,10 @@ static int test_cipher(struct crypto_cipher *tfm, int enc,
 
                j++;
 
+               ret = -EINVAL;
+               if (WARN_ON(template[i].ilen > PAGE_SIZE))
+                       goto out;
+
                data = xbuf[0];
                memcpy(data, template[i].input, template[i].ilen);
 
@@ -611,6 +716,8 @@ static int test_cipher(struct crypto_cipher *tfm, int enc,
        ret = 0;
 
 out:
+       testmgr_free_buf(xbuf);
+out_nobuf:
        return ret;
 }
 
@@ -620,7 +727,6 @@ static int test_skcipher(struct crypto_ablkcipher *tfm, int enc,
        const char *algo =
                crypto_tfm_alg_driver_name(crypto_ablkcipher_tfm(tfm));
        unsigned int i, j, k, n, temp;
-       int ret;
        char *q;
        struct ablkcipher_request *req;
        struct scatterlist sg[8];
@@ -628,6 +734,11 @@ static int test_skcipher(struct crypto_ablkcipher *tfm, int enc,
        struct tcrypt_result result;
        void *data;
        char iv[MAX_IVLEN];
+       char *xbuf[XBUFSIZE];
+       int ret = -ENOMEM;
+
+       if (testmgr_alloc_buf(xbuf))
+               goto out_nobuf;
 
        if (enc == ENCRYPT)
                e = "encryption";
@@ -640,7 +751,6 @@ static int test_skcipher(struct crypto_ablkcipher *tfm, int enc,
        if (!req) {
                printk(KERN_ERR "alg: skcipher: Failed to allocate request "
                       "for %s\n", algo);
-               ret = -ENOMEM;
                goto out;
        }
 
@@ -657,6 +767,10 @@ static int test_skcipher(struct crypto_ablkcipher *tfm, int enc,
                if (!(template[i].np)) {
                        j++;
 
+                       ret = -EINVAL;
+                       if (WARN_ON(template[i].ilen > PAGE_SIZE))
+                               goto out;
+
                        data = xbuf[0];
                        memcpy(data, template[i].input, template[i].ilen);
 
@@ -825,6 +939,8 @@ static int test_skcipher(struct crypto_ablkcipher *tfm, int enc,
 
 out:
        ablkcipher_request_free(req);
+       testmgr_free_buf(xbuf);
+out_nobuf:
        return ret;
 }
 
@@ -837,7 +953,8 @@ static int test_comp(struct crypto_comp *tfm, struct comp_testvec *ctemplate,
        int ret;
 
        for (i = 0; i < ctcount; i++) {
-               int ilen, dlen = COMP_BUF_SIZE;
+               int ilen;
+               unsigned int dlen = COMP_BUF_SIZE;
 
                memset(result, 0, sizeof (result));
 
@@ -869,7 +986,8 @@ static int test_comp(struct crypto_comp *tfm, struct comp_testvec *ctemplate,
        }
 
        for (i = 0; i < dtcount; i++) {
-               int ilen, dlen = COMP_BUF_SIZE;
+               int ilen;
+               unsigned int dlen = COMP_BUF_SIZE;
 
                memset(result, 0, sizeof (result));
 
@@ -914,24 +1032,25 @@ static int test_pcomp(struct crypto_pcomp *tfm,
        const char *algo = crypto_tfm_alg_driver_name(crypto_pcomp_tfm(tfm));
        unsigned int i;
        char result[COMP_BUF_SIZE];
-       int error;
+       int res;
 
        for (i = 0; i < ctcount; i++) {
                struct comp_request req;
+               unsigned int produced = 0;
 
-               error = crypto_compress_setup(tfm, ctemplate[i].params,
-                                             ctemplate[i].paramsize);
-               if (error) {
+               res = crypto_compress_setup(tfm, ctemplate[i].params,
+                                           ctemplate[i].paramsize);
+               if (res) {
                        pr_err("alg: pcomp: compression setup failed on test "
-                              "%d for %s: error=%d\n", i + 1, algo, error);
-                       return error;
+                              "%d for %s: error=%d\n", i + 1, algo, res);
+                       return res;
                }
 
-               error = crypto_compress_init(tfm);
-               if (error) {
+               res = crypto_compress_init(tfm);
+               if (res) {
                        pr_err("alg: pcomp: compression init failed on test "
-                              "%d for %s: error=%d\n", i + 1, algo, error);
-                       return error;
+                              "%d for %s: error=%d\n", i + 1, algo, res);
+                       return res;
                }
 
                memset(result, 0, sizeof(result));
@@ -941,32 +1060,37 @@ static int test_pcomp(struct crypto_pcomp *tfm,
                req.next_out = result;
                req.avail_out = ctemplate[i].outlen / 2;
 
-               error = crypto_compress_update(tfm, &req);
-               if (error && (error != -EAGAIN || req.avail_in)) {
+               res = crypto_compress_update(tfm, &req);
+               if (res < 0 && (res != -EAGAIN || req.avail_in)) {
                        pr_err("alg: pcomp: compression update failed on test "
-                              "%d for %s: error=%d\n", i + 1, algo, error);
-                       return error;
+                              "%d for %s: error=%d\n", i + 1, algo, res);
+                       return res;
                }
+               if (res > 0)
+                       produced += res;
 
                /* Add remaining input data */
                req.avail_in += (ctemplate[i].inlen + 1) / 2;
 
-               error = crypto_compress_update(tfm, &req);
-               if (error && (error != -EAGAIN || req.avail_in)) {
+               res = crypto_compress_update(tfm, &req);
+               if (res < 0 && (res != -EAGAIN || req.avail_in)) {
                        pr_err("alg: pcomp: compression update failed on test "
-                              "%d for %s: error=%d\n", i + 1, algo, error);
-                       return error;
+                              "%d for %s: error=%d\n", i + 1, algo, res);
+                       return res;
                }
+               if (res > 0)
+                       produced += res;
 
                /* Provide remaining output space */
                req.avail_out += COMP_BUF_SIZE - ctemplate[i].outlen / 2;
 
-               error = crypto_compress_final(tfm, &req);
-               if (error) {
+               res = crypto_compress_final(tfm, &req);
+               if (res < 0) {
                        pr_err("alg: pcomp: compression final failed on test "
-                              "%d for %s: error=%d\n", i + 1, algo, error);
-                       return error;
+                              "%d for %s: error=%d\n", i + 1, algo, res);
+                       return res;
                }
+               produced += res;
 
                if (COMP_BUF_SIZE - req.avail_out != ctemplate[i].outlen) {
                        pr_err("alg: comp: Compression test %d failed for %s: "
@@ -976,6 +1100,13 @@ static int test_pcomp(struct crypto_pcomp *tfm,
                        return -EINVAL;
                }
 
+               if (produced != ctemplate[i].outlen) {
+                       pr_err("alg: comp: Compression test %d failed for %s: "
+                              "returned len = %u (expected %d)\n", i + 1,
+                              algo, produced, ctemplate[i].outlen);
+                       return -EINVAL;
+               }
+
                if (memcmp(result, ctemplate[i].output, ctemplate[i].outlen)) {
                        pr_err("alg: pcomp: Compression test %d failed for "
                               "%s\n", i + 1, algo);
@@ -986,21 +1117,21 @@ static int test_pcomp(struct crypto_pcomp *tfm,
 
        for (i = 0; i < dtcount; i++) {
                struct comp_request req;
+               unsigned int produced = 0;
 
-               error = crypto_decompress_setup(tfm, dtemplate[i].params,
-                                               dtemplate[i].paramsize);
-               if (error) {
+               res = crypto_decompress_setup(tfm, dtemplate[i].params,
+                                             dtemplate[i].paramsize);
+               if (res) {
                        pr_err("alg: pcomp: decompression setup failed on "
-                              "test %d for %s: error=%d\n", i + 1, algo,
-                              error);
-                       return error;
+                              "test %d for %s: error=%d\n", i + 1, algo, res);
+                       return res;
                }
 
-               error = crypto_decompress_init(tfm);
-               if (error) {
+               res = crypto_decompress_init(tfm);
+               if (res) {
                        pr_err("alg: pcomp: decompression init failed on test "
-                              "%d for %s: error=%d\n", i + 1, algo, error);
-                       return error;
+                              "%d for %s: error=%d\n", i + 1, algo, res);
+                       return res;
                }
 
                memset(result, 0, sizeof(result));
@@ -1010,35 +1141,38 @@ static int test_pcomp(struct crypto_pcomp *tfm,
                req.next_out = result;
                req.avail_out = dtemplate[i].outlen / 2;
 
-               error = crypto_decompress_update(tfm, &req);
-               if (error  && (error != -EAGAIN || req.avail_in)) {
+               res = crypto_decompress_update(tfm, &req);
+               if (res < 0 && (res != -EAGAIN || req.avail_in)) {
                        pr_err("alg: pcomp: decompression update failed on "
-                              "test %d for %s: error=%d\n", i + 1, algo,
-                              error);
-                       return error;
+                              "test %d for %s: error=%d\n", i + 1, algo, res);
+                       return res;
                }
+               if (res > 0)
+                       produced += res;
 
                /* Add remaining input data */
                req.avail_in += (dtemplate[i].inlen + 1) / 2;
 
-               error = crypto_decompress_update(tfm, &req);
-               if (error  && (error != -EAGAIN || req.avail_in)) {
+               res = crypto_decompress_update(tfm, &req);
+               if (res < 0 && (res != -EAGAIN || req.avail_in)) {
                        pr_err("alg: pcomp: decompression update failed on "
-                              "test %d for %s: error=%d\n", i + 1, algo,
-                              error);
-                       return error;
+                              "test %d for %s: error=%d\n", i + 1, algo, res);
+                       return res;
                }
+               if (res > 0)
+                       produced += res;
 
                /* Provide remaining output space */
                req.avail_out += COMP_BUF_SIZE - dtemplate[i].outlen / 2;
 
-               error = crypto_decompress_final(tfm, &req);
-               if (error  && (error != -EAGAIN || req.avail_in)) {
+               res = crypto_decompress_final(tfm, &req);
+               if (res < 0 && (res != -EAGAIN || req.avail_in)) {
                        pr_err("alg: pcomp: decompression final failed on "
-                              "test %d for %s: error=%d\n", i + 1, algo,
-                              error);
-                       return error;
+                              "test %d for %s: error=%d\n", i + 1, algo, res);
+                       return res;
                }
+               if (res > 0)
+                       produced += res;
 
                if (COMP_BUF_SIZE - req.avail_out != dtemplate[i].outlen) {
                        pr_err("alg: comp: Decompression test %d failed for "
@@ -1048,6 +1182,13 @@ static int test_pcomp(struct crypto_pcomp *tfm,
                        return -EINVAL;
                }
 
+               if (produced != dtemplate[i].outlen) {
+                       pr_err("alg: comp: Decompression test %d failed for "
+                              "%s: returned len = %u (expected %d)\n", i + 1,
+                              algo, produced, dtemplate[i].outlen);
+                       return -EINVAL;
+               }
+
                if (memcmp(result, dtemplate[i].output, dtemplate[i].outlen)) {
                        pr_err("alg: pcomp: Decompression test %d failed for "
                               "%s\n", i + 1, algo);
@@ -1059,6 +1200,68 @@ static int test_pcomp(struct crypto_pcomp *tfm,
        return 0;
 }
 
+
+static int test_cprng(struct crypto_rng *tfm, struct cprng_testvec *template,
+                     unsigned int tcount)
+{
+       const char *algo = crypto_tfm_alg_driver_name(crypto_rng_tfm(tfm));
+       int err, i, j, seedsize;
+       u8 *seed;
+       char result[32];
+
+       seedsize = crypto_rng_seedsize(tfm);
+
+       seed = kmalloc(seedsize, GFP_KERNEL);
+       if (!seed) {
+               printk(KERN_ERR "alg: cprng: Failed to allocate seed space "
+                      "for %s\n", algo);
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < tcount; i++) {
+               memset(result, 0, 32);
+
+               memcpy(seed, template[i].v, template[i].vlen);
+               memcpy(seed + template[i].vlen, template[i].key,
+                      template[i].klen);
+               memcpy(seed + template[i].vlen + template[i].klen,
+                      template[i].dt, template[i].dtlen);
+
+               err = crypto_rng_reset(tfm, seed, seedsize);
+               if (err) {
+                       printk(KERN_ERR "alg: cprng: Failed to reset rng "
+                              "for %s\n", algo);
+                       goto out;
+               }
+
+               for (j = 0; j < template[i].loops; j++) {
+                       err = crypto_rng_get_bytes(tfm, result,
+                                                  template[i].rlen);
+                       if (err != template[i].rlen) {
+                               printk(KERN_ERR "alg: cprng: Failed to obtain "
+                                      "the correct amount of random data for "
+                                      "%s (requested %d, got %d)\n", algo,
+                                      template[i].rlen, err);
+                               goto out;
+                       }
+               }
+
+               err = memcmp(result, template[i].result,
+                            template[i].rlen);
+               if (err) {
+                       printk(KERN_ERR "alg: cprng: Test %d failed for %s\n",
+                              i, algo);
+                       hexdump(result, template[i].rlen);
+                       err = -EINVAL;
+                       goto out;
+               }
+       }
+
+out:
+       kfree(seed);
+       return err;
+}
+
 static int alg_test_aead(const struct alg_test_desc *desc, const char *driver,
                         u32 type, u32 mask)
 {
@@ -1258,11 +1461,42 @@ out:
        return err;
 }
 
+static int alg_test_cprng(const struct alg_test_desc *desc, const char *driver,
+                         u32 type, u32 mask)
+{
+       struct crypto_rng *rng;
+       int err;
+
+       rng = crypto_alloc_rng(driver, type, mask);
+       if (IS_ERR(rng)) {
+               printk(KERN_ERR "alg: cprng: Failed to load transform for %s: "
+                      "%ld\n", driver, PTR_ERR(rng));
+               return PTR_ERR(rng);
+       }
+
+       err = test_cprng(rng, desc->suite.cprng.vecs, desc->suite.cprng.count);
+
+       crypto_free_rng(rng);
+
+       return err;
+}
+
 /* Please keep this list sorted by algorithm name. */
 static const struct alg_test_desc alg_test_descs[] = {
        {
+               .alg = "ansi_cprng",
+               .test = alg_test_cprng,
+               .fips_allowed = 1,
+               .suite = {
+                       .cprng = {
+                               .vecs = ansi_cprng_aes_tv_template,
+                               .count = ANSI_CPRNG_AES_TEST_VECTORS
+                       }
+               }
+       }, {
                .alg = "cbc(aes)",
                .test = alg_test_skcipher,
+               .fips_allowed = 1,
                .suite = {
                        .cipher = {
                                .enc = {
@@ -1338,6 +1572,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "cbc(des3_ede)",
                .test = alg_test_skcipher,
+               .fips_allowed = 1,
                .suite = {
                        .cipher = {
                                .enc = {
@@ -1368,6 +1603,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "ccm(aes)",
                .test = alg_test_aead,
+               .fips_allowed = 1,
                .suite = {
                        .aead = {
                                .enc = {
@@ -1383,12 +1619,29 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "crc32c",
                .test = alg_test_crc32c,
+               .fips_allowed = 1,
                .suite = {
                        .hash = {
                                .vecs = crc32c_tv_template,
                                .count = CRC32C_TEST_VECTORS
                        }
                }
+       }, {
+               .alg = "ctr(aes)",
+               .test = alg_test_skcipher,
+               .fips_allowed = 1,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = aes_ctr_enc_tv_template,
+                                       .count = AES_CTR_ENC_TEST_VECTORS
+                               },
+                               .dec = {
+                                       .vecs = aes_ctr_dec_tv_template,
+                                       .count = AES_CTR_DEC_TEST_VECTORS
+                               }
+                       }
+               }
        }, {
                .alg = "cts(cbc(aes))",
                .test = alg_test_skcipher,
@@ -1422,6 +1675,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "ecb(aes)",
                .test = alg_test_skcipher,
+               .fips_allowed = 1,
                .suite = {
                        .cipher = {
                                .enc = {
@@ -1527,6 +1781,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "ecb(des)",
                .test = alg_test_skcipher,
+               .fips_allowed = 1,
                .suite = {
                        .cipher = {
                                .enc = {
@@ -1542,6 +1797,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "ecb(des3_ede)",
                .test = alg_test_skcipher,
+               .fips_allowed = 1,
                .suite = {
                        .cipher = {
                                .enc = {
@@ -1677,6 +1933,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "gcm(aes)",
                .test = alg_test_aead,
+               .fips_allowed = 1,
                .suite = {
                        .aead = {
                                .enc = {
@@ -1719,6 +1976,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "hmac(sha1)",
                .test = alg_test_hash,
+               .fips_allowed = 1,
                .suite = {
                        .hash = {
                                .vecs = hmac_sha1_tv_template,
@@ -1728,6 +1986,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "hmac(sha224)",
                .test = alg_test_hash,
+               .fips_allowed = 1,
                .suite = {
                        .hash = {
                                .vecs = hmac_sha224_tv_template,
@@ -1737,6 +1996,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "hmac(sha256)",
                .test = alg_test_hash,
+               .fips_allowed = 1,
                .suite = {
                        .hash = {
                                .vecs = hmac_sha256_tv_template,
@@ -1746,6 +2006,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "hmac(sha384)",
                .test = alg_test_hash,
+               .fips_allowed = 1,
                .suite = {
                        .hash = {
                                .vecs = hmac_sha384_tv_template,
@@ -1755,6 +2016,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "hmac(sha512)",
                .test = alg_test_hash,
+               .fips_allowed = 1,
                .suite = {
                        .hash = {
                                .vecs = hmac_sha512_tv_template,
@@ -1836,15 +2098,32 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "rfc3686(ctr(aes))",
                .test = alg_test_skcipher,
+               .fips_allowed = 1,
                .suite = {
                        .cipher = {
                                .enc = {
-                                       .vecs = aes_ctr_enc_tv_template,
-                                       .count = AES_CTR_ENC_TEST_VECTORS
+                                       .vecs = aes_ctr_rfc3686_enc_tv_template,
+                                       .count = AES_CTR_3686_ENC_TEST_VECTORS
                                },
                                .dec = {
-                                       .vecs = aes_ctr_dec_tv_template,
-                                       .count = AES_CTR_DEC_TEST_VECTORS
+                                       .vecs = aes_ctr_rfc3686_dec_tv_template,
+                                       .count = AES_CTR_3686_DEC_TEST_VECTORS
+                               }
+                       }
+               }
+       }, {
+               .alg = "rfc4309(ccm(aes))",
+               .test = alg_test_aead,
+               .fips_allowed = 1,
+               .suite = {
+                       .aead = {
+                               .enc = {
+                                       .vecs = aes_ccm_rfc4309_enc_tv_template,
+                                       .count = AES_CCM_4309_ENC_TEST_VECTORS
+                               },
+                               .dec = {
+                                       .vecs = aes_ccm_rfc4309_dec_tv_template,
+                                       .count = AES_CCM_4309_DEC_TEST_VECTORS
                                }
                        }
                }
@@ -1898,6 +2177,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "sha1",
                .test = alg_test_hash,
+               .fips_allowed = 1,
                .suite = {
                        .hash = {
                                .vecs = sha1_tv_template,
@@ -1907,6 +2187,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "sha224",
                .test = alg_test_hash,
+               .fips_allowed = 1,
                .suite = {
                        .hash = {
                                .vecs = sha224_tv_template,
@@ -1916,6 +2197,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "sha256",
                .test = alg_test_hash,
+               .fips_allowed = 1,
                .suite = {
                        .hash = {
                                .vecs = sha256_tv_template,
@@ -1925,6 +2207,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "sha384",
                .test = alg_test_hash,
+               .fips_allowed = 1,
                .suite = {
                        .hash = {
                                .vecs = sha384_tv_template,
@@ -1934,6 +2217,7 @@ static const struct alg_test_desc alg_test_descs[] = {
        }, {
                .alg = "sha512",
                .test = alg_test_hash,
+               .fips_allowed = 1,
                .suite = {
                        .hash = {
                                .vecs = sha512_tv_template,
@@ -2077,60 +2361,36 @@ int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
                if (i < 0)
                        goto notest;
 
-               return alg_test_cipher(alg_test_descs + i, driver, type, mask);
+               if (fips_enabled && !alg_test_descs[i].fips_allowed)
+                       goto non_fips_alg;
+
+               rc = alg_test_cipher(alg_test_descs + i, driver, type, mask);
+               goto test_done;
        }
 
        i = alg_find_test(alg);
        if (i < 0)
                goto notest;
 
+       if (fips_enabled && !alg_test_descs[i].fips_allowed)
+               goto non_fips_alg;
+
        rc = alg_test_descs[i].test(alg_test_descs + i, driver,
                                      type, mask);
+test_done:
        if (fips_enabled && rc)
                panic("%s: %s alg self test failed in fips mode!\n", driver, alg);
 
+       if (fips_enabled && !rc)
+               printk(KERN_INFO "alg: self-tests for %s (%s) passed\n",
+                      driver, alg);
+
        return rc;
 
 notest:
        printk(KERN_INFO "alg: No test for %s (%s)\n", alg, driver);
        return 0;
+non_fips_alg:
+       return -EINVAL;
 }
 EXPORT_SYMBOL_GPL(alg_test);
-
-int __init testmgr_init(void)
-{
-       int i;
-
-       for (i = 0; i < XBUFSIZE; i++) {
-               xbuf[i] = (void *)__get_free_page(GFP_KERNEL);
-               if (!xbuf[i])
-                       goto err_free_xbuf;
-       }
-
-       for (i = 0; i < XBUFSIZE; i++) {
-               axbuf[i] = (void *)__get_free_page(GFP_KERNEL);
-               if (!axbuf[i])
-                       goto err_free_axbuf;
-       }
-
-       return 0;
-
-err_free_axbuf:
-       for (i = 0; i < XBUFSIZE && axbuf[i]; i++)
-               free_page((unsigned long)axbuf[i]);
-err_free_xbuf:
-       for (i = 0; i < XBUFSIZE && xbuf[i]; i++)
-               free_page((unsigned long)xbuf[i]);
-
-       return -ENOMEM;
-}
-
-void testmgr_exit(void)
-{
-       int i;
-
-       for (i = 0; i < XBUFSIZE; i++)
-               free_page((unsigned long)axbuf[i]);
-       for (i = 0; i < XBUFSIZE; i++)
-               free_page((unsigned long)xbuf[i]);
-}
index 526f00a9c72feba6acd49b42f0281a79944657e5..69316228fc190ff9bd8b658ef4a9a5a819259bf8 100644 (file)
@@ -62,6 +62,7 @@ struct aead_testvec {
        int np;
        int anp;
        unsigned char fail;
+       unsigned char novrfy;   /* ccm dec verification failure expected */
        unsigned char wk; /* weak key flag */
        unsigned char klen;
        unsigned short ilen;
@@ -69,6 +70,18 @@ struct aead_testvec {
        unsigned short rlen;
 };
 
+struct cprng_testvec {
+       char *key;
+       char *dt;
+       char *v;
+       char *result;
+       unsigned char klen;
+       unsigned short dtlen;
+       unsigned short vlen;
+       unsigned short rlen;
+       unsigned short loops;
+};
+
 static char zeroed_string[48];
 
 /*
@@ -2841,12 +2854,16 @@ static struct cipher_testvec cast6_dec_tv_template[] = {
 #define AES_LRW_DEC_TEST_VECTORS 8
 #define AES_XTS_ENC_TEST_VECTORS 4
 #define AES_XTS_DEC_TEST_VECTORS 4
-#define AES_CTR_ENC_TEST_VECTORS 7
-#define AES_CTR_DEC_TEST_VECTORS 6
+#define AES_CTR_ENC_TEST_VECTORS 3
+#define AES_CTR_DEC_TEST_VECTORS 3
+#define AES_CTR_3686_ENC_TEST_VECTORS 7
+#define AES_CTR_3686_DEC_TEST_VECTORS 6
 #define AES_GCM_ENC_TEST_VECTORS 9
 #define AES_GCM_DEC_TEST_VECTORS 8
 #define AES_CCM_ENC_TEST_VECTORS 7
 #define AES_CCM_DEC_TEST_VECTORS 7
+#define AES_CCM_4309_ENC_TEST_VECTORS 7
+#define AES_CCM_4309_DEC_TEST_VECTORS 10
 
 static struct cipher_testvec aes_enc_tv_template[] = {
        { /* From FIPS-197 */
@@ -3983,6 +4000,164 @@ static struct cipher_testvec aes_xts_dec_tv_template[] = {
 
 
 static struct cipher_testvec aes_ctr_enc_tv_template[] = {
+       { /* From NIST Special Publication 800-38A, Appendix F.5 */
+               .key    = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6"
+                         "\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+               .klen   = 16,
+               .iv     = "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .input  = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+                         "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+                         "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+                         "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+                         "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+                         "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+                         "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+                         "\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+               .ilen   = 64,
+               .result = "\x87\x4d\x61\x91\xb6\x20\xe3\x26"
+                         "\x1b\xef\x68\x64\x99\x0d\xb6\xce"
+                         "\x98\x06\xf6\x6b\x79\x70\xfd\xff"
+                         "\x86\x17\x18\x7b\xb9\xff\xfd\xff"
+                         "\x5a\xe4\xdf\x3e\xdb\xd5\xd3\x5e"
+                         "\x5b\x4f\x09\x02\x0d\xb0\x3e\xab"
+                         "\x1e\x03\x1d\xda\x2f\xbe\x03\xd1"
+                         "\x79\x21\x70\xa0\xf3\x00\x9c\xee",
+               .rlen   = 64,
+       }, {
+               .key    = "\x8e\x73\xb0\xf7\xda\x0e\x64\x52"
+                         "\xc8\x10\xf3\x2b\x80\x90\x79\xe5"
+                         "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b",
+               .klen   = 24,
+               .iv     = "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .input  = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+                         "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+                         "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+                         "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+                         "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+                         "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+                         "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+                         "\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+               .ilen   = 64,
+               .result = "\x1a\xbc\x93\x24\x17\x52\x1c\xa2"
+                         "\x4f\x2b\x04\x59\xfe\x7e\x6e\x0b"
+                         "\x09\x03\x39\xec\x0a\xa6\xfa\xef"
+                         "\xd5\xcc\xc2\xc6\xf4\xce\x8e\x94"
+                         "\x1e\x36\xb2\x6b\xd1\xeb\xc6\x70"
+                         "\xd1\xbd\x1d\x66\x56\x20\xab\xf7"
+                         "\x4f\x78\xa7\xf6\xd2\x98\x09\x58"
+                         "\x5a\x97\xda\xec\x58\xc6\xb0\x50",
+               .rlen   = 64,
+       }, {
+               .key    = "\x60\x3d\xeb\x10\x15\xca\x71\xbe"
+                         "\x2b\x73\xae\xf0\x85\x7d\x77\x81"
+                         "\x1f\x35\x2c\x07\x3b\x61\x08\xd7"
+                         "\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
+               .klen   = 32,
+               .iv     = "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .input  = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+                         "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+                         "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+                         "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+                         "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+                         "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+                         "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+                         "\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+               .ilen   = 64,
+               .result = "\x60\x1e\xc3\x13\x77\x57\x89\xa5"
+                         "\xb7\xa7\xf5\x04\xbb\xf3\xd2\x28"
+                         "\xf4\x43\xe3\xca\x4d\x62\xb5\x9a"
+                         "\xca\x84\xe9\x90\xca\xca\xf5\xc5"
+                         "\x2b\x09\x30\xda\xa2\x3d\xe9\x4c"
+                         "\xe8\x70\x17\xba\x2d\x84\x98\x8d"
+                         "\xdf\xc9\xc5\x8d\xb6\x7a\xad\xa6"
+                         "\x13\xc2\xdd\x08\x45\x79\x41\xa6",
+               .rlen   = 64,
+       }
+};
+
+static struct cipher_testvec aes_ctr_dec_tv_template[] = {
+       { /* From NIST Special Publication 800-38A, Appendix F.5 */
+               .key    = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6"
+                         "\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+               .klen   = 16,
+               .iv     = "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .input  = "\x87\x4d\x61\x91\xb6\x20\xe3\x26"
+                         "\x1b\xef\x68\x64\x99\x0d\xb6\xce"
+                         "\x98\x06\xf6\x6b\x79\x70\xfd\xff"
+                         "\x86\x17\x18\x7b\xb9\xff\xfd\xff"
+                         "\x5a\xe4\xdf\x3e\xdb\xd5\xd3\x5e"
+                         "\x5b\x4f\x09\x02\x0d\xb0\x3e\xab"
+                         "\x1e\x03\x1d\xda\x2f\xbe\x03\xd1"
+                         "\x79\x21\x70\xa0\xf3\x00\x9c\xee",
+               .ilen   = 64,
+               .result = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+                         "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+                         "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+                         "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+                         "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+                         "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+                         "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+                         "\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+               .rlen   = 64,
+       }, {
+               .key    = "\x8e\x73\xb0\xf7\xda\x0e\x64\x52"
+                         "\xc8\x10\xf3\x2b\x80\x90\x79\xe5"
+                         "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b",
+               .klen   = 24,
+               .iv     = "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .input  = "\x1a\xbc\x93\x24\x17\x52\x1c\xa2"
+                         "\x4f\x2b\x04\x59\xfe\x7e\x6e\x0b"
+                         "\x09\x03\x39\xec\x0a\xa6\xfa\xef"
+                         "\xd5\xcc\xc2\xc6\xf4\xce\x8e\x94"
+                         "\x1e\x36\xb2\x6b\xd1\xeb\xc6\x70"
+                         "\xd1\xbd\x1d\x66\x56\x20\xab\xf7"
+                         "\x4f\x78\xa7\xf6\xd2\x98\x09\x58"
+                         "\x5a\x97\xda\xec\x58\xc6\xb0\x50",
+               .ilen   = 64,
+               .result = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+                         "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+                         "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+                         "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+                         "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+                         "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+                         "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+                         "\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+               .rlen   = 64,
+       }, {
+               .key    = "\x60\x3d\xeb\x10\x15\xca\x71\xbe"
+                         "\x2b\x73\xae\xf0\x85\x7d\x77\x81"
+                         "\x1f\x35\x2c\x07\x3b\x61\x08\xd7"
+                         "\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
+               .klen   = 32,
+               .iv     = "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .input  = "\x60\x1e\xc3\x13\x77\x57\x89\xa5"
+                         "\xb7\xa7\xf5\x04\xbb\xf3\xd2\x28"
+                         "\xf4\x43\xe3\xca\x4d\x62\xb5\x9a"
+                         "\xca\x84\xe9\x90\xca\xca\xf5\xc5"
+                         "\x2b\x09\x30\xda\xa2\x3d\xe9\x4c"
+                         "\xe8\x70\x17\xba\x2d\x84\x98\x8d"
+                         "\xdf\xc9\xc5\x8d\xb6\x7a\xad\xa6"
+                         "\x13\xc2\xdd\x08\x45\x79\x41\xa6",
+               .ilen   = 64,
+               .result = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+                         "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+                         "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+                         "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+                         "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+                         "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+                         "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+                         "\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+               .rlen   = 64,
+       }
+};
+
+static struct cipher_testvec aes_ctr_rfc3686_enc_tv_template[] = {
        { /* From RFC 3686 */
                .key    = "\xae\x68\x52\xf8\x12\x10\x67\xcc"
                          "\x4b\xf7\xa5\x76\x55\x77\xf3\x9e"
@@ -5114,7 +5289,7 @@ static struct cipher_testvec aes_ctr_enc_tv_template[] = {
        },
 };
 
-static struct cipher_testvec aes_ctr_dec_tv_template[] = {
+static struct cipher_testvec aes_ctr_rfc3686_dec_tv_template[] = {
        { /* From RFC 3686 */
                .key    = "\xae\x68\x52\xf8\x12\x10\x67\xcc"
                          "\x4b\xf7\xa5\x76\x55\x77\xf3\x9e"
@@ -5825,6 +6000,470 @@ static struct aead_testvec aes_ccm_dec_tv_template[] = {
        },
 };
 
+/*
+ * rfc4309 refers to section 8 of rfc3610 for test vectors, but they all
+ * use a 13-byte nonce, we only support an 11-byte nonce. Similarly, all of
+ * Special Publication 800-38C's test vectors also use nonce lengths our
+ * implementation doesn't support. The following are taken from fips cavs
+ * fax files on hand at Red Hat.
+ *
+ * nb: actual key lengths are (klen - 3), the last 3 bytes are actually
+ * part of the nonce which combine w/the iv, but need to be input this way.
+ */
+static struct aead_testvec aes_ccm_rfc4309_enc_tv_template[] = {
+       {
+               .key    = "\x83\xac\x54\x66\xc2\xeb\xe5\x05"
+                         "\x2e\x01\xd1\xfc\x5d\x82\x66\x2e"
+                         "\x96\xac\x59",
+               .klen   = 19,
+               .iv     = "\x30\x07\xa1\xe2\xa2\xc7\x55\x24",
+               .alen   = 0,
+               .input  = "\x19\xc8\x81\xf6\xe9\x86\xff\x93"
+                         "\x0b\x78\x67\xe5\xbb\xb7\xfc\x6e"
+                         "\x83\x77\xb3\xa6\x0c\x8c\x9f\x9c"
+                         "\x35\x2e\xad\xe0\x62\xf9\x91\xa1",
+               .ilen   = 32,
+               .result = "\xab\x6f\xe1\x69\x1d\x19\x99\xa8"
+                         "\x92\xa0\xc4\x6f\x7e\xe2\x8b\xb1"
+                         "\x70\xbb\x8c\xa6\x4c\x6e\x97\x8a"
+                         "\x57\x2b\xbe\x5d\x98\xa6\xb1\x32"
+                         "\xda\x24\xea\xd9\xa1\x39\x98\xfd"
+                         "\xa4\xbe\xd9\xf2\x1a\x6d\x22\xa8",
+               .rlen   = 48,
+       }, {
+               .key    = "\x1e\x2c\x7e\x01\x41\x9a\xef\xc0"
+                         "\x0d\x58\x96\x6e\x5c\xa2\x4b\xd3"
+                         "\x4f\xa3\x19",
+               .klen   = 19,
+               .iv     = "\xd3\x01\x5a\xd8\x30\x60\x15\x56",
+               .assoc  = "\xda\xe6\x28\x9c\x45\x2d\xfd\x63"
+                         "\x5e\xda\x4c\xb6\xe6\xfc\xf9\xb7"
+                         "\x0c\x56\xcb\xe4\xe0\x05\x7a\xe1"
+                         "\x0a\x63\x09\x78\xbc\x2c\x55\xde",
+               .alen   = 32,
+               .input  = "\x87\xa3\x36\xfd\x96\xb3\x93\x78"
+                         "\xa9\x28\x63\xba\x12\xa3\x14\x85"
+                         "\x57\x1e\x06\xc9\x7b\x21\xef\x76"
+                         "\x7f\x38\x7e\x8e\x29\xa4\x3e\x7e",
+               .ilen   = 32,
+               .result = "\x8a\x1e\x11\xf0\x02\x6b\xe2\x19"
+                         "\xfc\x70\xc4\x6d\x8e\xb7\x99\xab"
+                         "\xc5\x4b\xa2\xac\xd3\xf3\x48\xff"
+                         "\x3b\xb5\xce\x53\xef\xde\xbb\x02"
+                         "\xa9\x86\x15\x6c\x13\xfe\xda\x0a"
+                         "\x22\xb8\x29\x3d\xd8\x39\x9a\x23",
+               .rlen   = 48,
+       }, {
+               .key    = "\xf4\x6b\xc2\x75\x62\xfe\xb4\xe1"
+                         "\xa3\xf0\xff\xdd\x4e\x4b\x12\x75"
+                         "\x53\x14\x73\x66\x8d\x88\xf6\x80"
+                         "\xa0\x20\x35",
+               .klen   = 27,
+               .iv     = "\x26\xf2\x21\x8d\x50\x20\xda\xe2",
+               .assoc  = "\x5b\x9e\x13\x67\x02\x5e\xef\xc1"
+                         "\x6c\xf9\xd7\x1e\x52\x8f\x7a\x47"
+                         "\xe9\xd4\xcf\x20\x14\x6e\xf0\x2d"
+                         "\xd8\x9e\x2b\x56\x10\x23\x56\xe7",
+               .alen   = 32,
+               .ilen   = 0,
+               .result = "\x36\xea\x7a\x70\x08\xdc\x6a\xbc"
+                         "\xad\x0c\x7a\x63\xf6\x61\xfd\x9b",
+               .rlen   = 16,
+       }, {
+               .key    = "\x56\xdf\x5c\x8f\x26\x3f\x0e\x42"
+                         "\xef\x7a\xd3\xce\xfc\x84\x60\x62"
+                         "\xca\xb4\x40\xaf\x5f\xc9\xc9\x01"
+                         "\xd6\x3c\x8c",
+               .klen   = 27,
+               .iv     = "\x86\x84\xb6\xcd\xef\x09\x2e\x94",
+               .assoc  = "\x02\x65\x78\x3c\xe9\x21\x30\x91"
+                         "\xb1\xb9\xda\x76\x9a\x78\x6d\x95"
+                         "\xf2\x88\x32\xa3\xf2\x50\xcb\x4c"
+                         "\xe3\x00\x73\x69\x84\x69\x87\x79",
+               .alen   = 32,
+               .input  = "\x9f\xd2\x02\x4b\x52\x49\x31\x3c"
+                         "\x43\x69\x3a\x2d\x8e\x70\xad\x7e"
+                         "\xe0\xe5\x46\x09\x80\x89\x13\xb2"
+                         "\x8c\x8b\xd9\x3f\x86\xfb\xb5\x6b",
+               .ilen   = 32,
+               .result = "\x39\xdf\x7c\x3c\x5a\x29\xb9\x62"
+                         "\x5d\x51\xc2\x16\xd8\xbd\x06\x9f"
+                         "\x9b\x6a\x09\x70\xc1\x51\x83\xc2"
+                         "\x66\x88\x1d\x4f\x9a\xda\xe0\x1e"
+                         "\xc7\x79\x11\x58\xe5\x6b\x20\x40"
+                         "\x7a\xea\x46\x42\x8b\xe4\x6f\xe1",
+               .rlen   = 48,
+       }, {
+               .key    = "\xe0\x8d\x99\x71\x60\xd7\x97\x1a"
+                         "\xbd\x01\x99\xd5\x8a\xdf\x71\x3a"
+                         "\xd3\xdf\x24\x4b\x5e\x3d\x4b\x4e"
+                         "\x30\x7a\xb9\xd8\x53\x0a\x5e\x2b"
+                         "\x1e\x29\x91",
+               .klen   = 35,
+               .iv     = "\xad\x8e\xc1\x53\x0a\xcf\x2d\xbe",
+               .assoc  = "\x19\xb6\x1f\x57\xc4\xf3\xf0\x8b"
+                         "\x78\x2b\x94\x02\x29\x0f\x42\x27"
+                         "\x6b\x75\xcb\x98\x34\x08\x7e\x79"
+                         "\xe4\x3e\x49\x0d\x84\x8b\x22\x87",
+               .alen   = 32,
+               .input  = "\xe1\xd9\xd8\x13\xeb\x3a\x75\x3f"
+                         "\x9d\xbd\x5f\x66\xbe\xdc\xbb\x66"
+                         "\xbf\x17\x99\x62\x4a\x39\x27\x1f"
+                         "\x1d\xdc\x24\xae\x19\x2f\x98\x4c",
+               .ilen   = 32,
+               .result = "\x19\xb8\x61\x33\x45\x2b\x43\x96"
+                         "\x6f\x51\xd0\x20\x30\x7d\x9b\xc6"
+                         "\x26\x3d\xf8\xc9\x65\x16\xa8\x9f"
+                         "\xf0\x62\x17\x34\xf2\x1e\x8d\x75"
+                         "\x4e\x13\xcc\xc0\xc3\x2a\x54\x2d",
+               .rlen   = 40,
+       }, {
+               .key    = "\x7c\xc8\x18\x3b\x8d\x99\xe0\x7c"
+                         "\x45\x41\xb8\xbd\x5c\xa7\xc2\x32"
+                         "\x8a\xb8\x02\x59\xa4\xfe\xa9\x2c"
+                         "\x09\x75\x9a\x9b\x3c\x9b\x27\x39"
+                         "\xf9\xd9\x4e",
+               .klen   = 35,
+               .iv     = "\x63\xb5\x3d\x9d\x43\xf6\x1e\x50",
+               .assoc  = "\x57\xf5\x6b\x8b\x57\x5c\x3d\x3b"
+                         "\x13\x02\x01\x0c\x83\x4c\x96\x35"
+                         "\x8e\xd6\x39\xcf\x7d\x14\x9b\x94"
+                         "\xb0\x39\x36\xe6\x8f\x57\xe0\x13",
+               .alen   = 32,
+               .input  = "\x3b\x6c\x29\x36\xb6\xef\x07\xa6"
+                         "\x83\x72\x07\x4f\xcf\xfa\x66\x89"
+                         "\x5f\xca\xb1\xba\xd5\x8f\x2c\x27"
+                         "\x30\xdb\x75\x09\x93\xd4\x65\xe4",
+               .ilen   = 32,
+               .result = "\xb0\x88\x5a\x33\xaa\xe5\xc7\x1d"
+                         "\x85\x23\xc7\xc6\x2f\xf4\x1e\x3d"
+                         "\xcc\x63\x44\x25\x07\x78\x4f\x9e"
+                         "\x96\xb8\x88\xeb\xbc\x48\x1f\x06"
+                         "\x39\xaf\x39\xac\xd8\x4a\x80\x39"
+                         "\x7b\x72\x8a\xf7",
+               .rlen   = 44,
+       }, {
+               .key    = "\xab\xd0\xe9\x33\x07\x26\xe5\x83"
+                         "\x8c\x76\x95\xd4\xb6\xdc\xf3\x46"
+                         "\xf9\x8f\xad\xe3\x02\x13\x83\x77"
+                         "\x3f\xb0\xf1\xa1\xa1\x22\x0f\x2b"
+                         "\x24\xa7\x8b",
+               .klen   = 35,
+               .iv     = "\x07\xcb\xcc\x0e\xe6\x33\xbf\xf5",
+               .assoc  = "\xd4\xdb\x30\x1d\x03\xfe\xfd\x5f"
+                         "\x87\xd4\x8c\xb6\xb6\xf1\x7a\x5d"
+                         "\xab\x90\x65\x8d\x8e\xca\x4d\x4f"
+                         "\x16\x0c\x40\x90\x4b\xc7\x36\x73",
+               .alen   = 32,
+               .input  = "\xf5\xc6\x7d\x48\xc1\xb7\xe6\x92"
+                         "\x97\x5a\xca\xc4\xa9\x6d\xf9\x3d"
+                         "\x6c\xde\xbc\xf1\x90\xea\x6a\xb2"
+                         "\x35\x86\x36\xaf\x5c\xfe\x4b\x3a",
+               .ilen   = 32,
+               .result = "\x83\x6f\x40\x87\x72\xcf\xc1\x13"
+                         "\xef\xbb\x80\x21\x04\x6c\x58\x09"
+                         "\x07\x1b\xfc\xdf\xc0\x3f\x5b\xc7"
+                         "\xe0\x79\xa8\x6e\x71\x7c\x3f\xcf"
+                         "\x5c\xda\xb2\x33\xe5\x13\xe2\x0d"
+                         "\x74\xd1\xef\xb5\x0f\x3a\xb5\xf8",
+               .rlen   = 48,
+       },
+};
+
+static struct aead_testvec aes_ccm_rfc4309_dec_tv_template[] = {
+       {
+               .key    = "\xab\x2f\x8a\x74\xb7\x1c\xd2\xb1"
+                         "\xff\x80\x2e\x48\x7d\x82\xf8\xb9"
+                         "\xc6\xfb\x7d",
+               .klen   = 19,
+               .iv     = "\x80\x0d\x13\xab\xd8\xa6\xb2\xd8",
+               .alen   = 0,
+               .input  = "\xd5\xe8\x93\x9f\xc7\x89\x2e\x2b",
+               .ilen   = 8,
+               .result = "\x00",
+               .rlen   = 0,
+               .novrfy = 1,
+       }, {
+               .key    = "\xab\x2f\x8a\x74\xb7\x1c\xd2\xb1"
+                         "\xff\x80\x2e\x48\x7d\x82\xf8\xb9"
+                         "\xaf\x94\x87",
+               .klen   = 19,
+               .iv     = "\x78\x35\x82\x81\x7f\x88\x94\x68",
+               .alen   = 0,
+               .input  = "\x41\x3c\xb8\x87\x73\xcb\xf3\xf3",
+               .ilen   = 8,
+               .result = "\x00",
+               .rlen   = 0,
+       }, {
+               .key    = "\x61\x0e\x8c\xae\xe3\x23\xb6\x38"
+                         "\x76\x1c\xf6\x3a\x67\xa3\x9c\xd8"
+                         "\xc6\xfb\x7d",
+               .klen   = 19,
+               .iv     = "\x80\x0d\x13\xab\xd8\xa6\xb2\xd8",
+               .assoc  = "\xf3\x94\x87\x78\x35\x82\x81\x7f"
+                         "\x88\x94\x68\xb1\x78\x6b\x2b\xd6"
+                         "\x04\x1f\x4e\xed\x78\xd5\x33\x66"
+                         "\xd8\x94\x99\x91\x81\x54\x62\x57",
+               .alen   = 32,
+               .input  = "\xf0\x7c\x29\x02\xae\x1c\x2f\x55"
+                         "\xd0\xd1\x3d\x1a\xa3\x6d\xe4\x0a"
+                         "\x86\xb0\x87\x6b\x62\x33\x8c\x34"
+                         "\xce\xab\x57\xcc\x79\x0b\xe0\x6f"
+                         "\x5c\x3e\x48\x1f\x6c\x46\xf7\x51"
+                         "\x8b\x84\x83\x2a\xc1\x05\xb8\xc5",
+               .ilen   = 48,
+               .result = "\x50\x82\x3e\x07\xe2\x1e\xb6\xfb"
+                         "\x33\xe4\x73\xce\xd2\xfb\x95\x79"
+                         "\xe8\xb4\xb5\x77\x11\x10\x62\x6f"
+                         "\x6a\x82\xd1\x13\xec\xf5\xd0\x48",
+               .rlen   = 32,
+               .novrfy = 1,
+       }, {
+               .key    = "\x61\x0e\x8c\xae\xe3\x23\xb6\x38"
+                         "\x76\x1c\xf6\x3a\x67\xa3\x9c\xd8"
+                         "\x05\xe0\xc9",
+               .klen   = 19,
+               .iv     = "\x0f\xed\x34\xea\x97\xd4\x3b\xdf",
+               .assoc  = "\x49\x5c\x50\x1f\x1d\x94\xcc\x81"
+                         "\xba\xb7\xb6\x03\xaf\xa5\xc1\xa1"
+                         "\xd8\x5c\x42\x68\xe0\x6c\xda\x89"
+                         "\x05\xac\x56\xac\x1b\x2a\xd3\x86",
+               .alen   = 32,
+               .input  = "\x39\xbe\x7d\x15\x62\x77\xf3\x3c"
+                         "\xad\x83\x52\x6d\x71\x03\x25\x1c"
+                         "\xed\x81\x3a\x9a\x16\x7d\x19\x80"
+                         "\x72\x04\x72\xd0\xf6\xff\x05\x0f"
+                         "\xb7\x14\x30\x00\x32\x9e\xa0\xa6"
+                         "\x9e\x5a\x18\xa1\xb8\xfe\xdb\xd3",
+               .ilen   = 48,
+               .result = "\x75\x05\xbe\xc2\xd9\x1e\xde\x60"
+                         "\x47\x3d\x8c\x7d\xbd\xb5\xd9\xb7"
+                         "\xf2\xae\x61\x05\x8f\x82\x24\x3f"
+                         "\x9c\x67\x91\xe1\x38\x4f\xe4\x0c",
+               .rlen   = 32,
+       }, {
+               .key    = "\x39\xbb\xa7\xbe\x59\x97\x9e\x73"
+                         "\xa2\xbc\x6b\x98\xd7\x75\x7f\xe3"
+                         "\xa4\x48\x93\x39\x26\x71\x4a\xc6"
+                         "\xee\x49\x83",
+               .klen   = 27,
+               .iv     = "\xe9\xa9\xff\xe9\x57\xba\xfd\x9e",
+               .assoc  = "\x44\xa6\x2c\x05\xe9\xe1\x43\xb1"
+                         "\x58\x7c\xf2\x5c\x6d\x39\x0a\x64"
+                         "\xa4\xf0\x13\x05\xd1\x77\x99\x67"
+                         "\x11\xc4\xc6\xdb\x00\x56\x36\x61",
+               .alen   = 32,
+               .input  = "\x71\x99\xfa\xf4\x44\x12\x68\x9b",
+               .ilen   = 8,
+               .result = "\x00",
+               .rlen   = 0,
+       }, {
+               .key    = "\x58\x5d\xa0\x96\x65\x1a\x04\xd7"
+                         "\x96\xe5\xc5\x68\xaa\x95\x35\xe0"
+                         "\x29\xa0\xba\x9e\x48\x78\xd1\xba"
+                         "\xee\x49\x83",
+               .klen   = 27,
+               .iv     = "\xe9\xa9\xff\xe9\x57\xba\xfd\x9e",
+               .assoc  = "\x44\xa6\x2c\x05\xe9\xe1\x43\xb1"
+                         "\x58\x7c\xf2\x5c\x6d\x39\x0a\x64"
+                         "\xa4\xf0\x13\x05\xd1\x77\x99\x67"
+                         "\x11\xc4\xc6\xdb\x00\x56\x36\x61",
+               .alen   = 32,
+               .input  = "\xfb\xe5\x5d\x34\xbe\xe5\xe8\xe7"
+                         "\x5a\xef\x2f\xbf\x1f\x7f\xd4\xb2"
+                         "\x66\xca\x61\x1e\x96\x7a\x61\xb3"
+                         "\x1c\x16\x45\x52\xba\x04\x9c\x9f"
+                         "\xb1\xd2\x40\xbc\x52\x7c\x6f\xb1",
+               .ilen   = 40,
+               .result = "\x85\x34\x66\x42\xc8\x92\x0f\x36"
+                         "\x58\xe0\x6b\x91\x3c\x98\x5c\xbb"
+                         "\x0a\x85\xcc\x02\xad\x7a\x96\xe9"
+                         "\x65\x43\xa4\xc3\x0f\xdc\x55\x81",
+               .rlen   = 32,
+       }, {
+               .key    = "\x58\x5d\xa0\x96\x65\x1a\x04\xd7"
+                         "\x96\xe5\xc5\x68\xaa\x95\x35\xe0"
+                         "\x29\xa0\xba\x9e\x48\x78\xd1\xba"
+                         "\xd1\xfc\x57",
+               .klen   = 27,
+               .iv     = "\x9c\xfe\xb8\x9c\xad\x71\xaa\x1f",
+               .assoc  = "\x86\x67\xa5\xa9\x14\x5f\x0d\xc6"
+                         "\xff\x14\xc7\x44\xbf\x6c\x3a\xc3"
+                         "\xff\xb6\x81\xbd\xe2\xd5\x06\xc7"
+                         "\x3c\xa1\x52\x13\x03\x8a\x23\x3a",
+               .alen   = 32,
+               .input  = "\x3f\x66\xb0\x9d\xe5\x4b\x38\x00"
+                         "\xc6\x0e\x6e\xe5\xd6\x98\xa6\x37"
+                         "\x8c\x26\x33\xc6\xb2\xa2\x17\xfa"
+                         "\x64\x19\xc0\x30\xd7\xfc\x14\x6b"
+                         "\xe3\x33\xc2\x04\xb0\x37\xbe\x3f"
+                         "\xa9\xb4\x2d\x68\x03\xa3\x44\xef",
+               .ilen   = 48,
+               .result = "\x02\x87\x4d\x28\x80\x6e\xb2\xed"
+                         "\x99\x2a\xa8\xca\x04\x25\x45\x90"
+                         "\x1d\xdd\x5a\xd9\xe4\xdb\x9c\x9c"
+                         "\x49\xe9\x01\xfe\xa7\x80\x6d\x6b",
+               .rlen   = 32,
+               .novrfy = 1,
+       }, {
+               .key    = "\xa4\x4b\x54\x29\x0a\xb8\x6d\x01"
+                         "\x5b\x80\x2a\xcf\x25\xc4\xb7\x5c"
+                         "\x20\x2c\xad\x30\xc2\x2b\x41\xfb"
+                         "\x0e\x85\xbc\x33\xad\x0f\x2b\xff"
+                         "\xee\x49\x83",
+               .klen   = 35,
+               .iv     = "\xe9\xa9\xff\xe9\x57\xba\xfd\x9e",
+               .alen   = 0,
+               .input  = "\x1f\xb8\x8f\xa3\xdd\x54\x00\xf2",
+               .ilen   = 8,
+               .result = "\x00",
+               .rlen   = 0,
+       }, {
+               .key    = "\x39\xbb\xa7\xbe\x59\x97\x9e\x73"
+                         "\xa2\xbc\x6b\x98\xd7\x75\x7f\xe3"
+                         "\xa4\x48\x93\x39\x26\x71\x4a\xc6"
+                         "\xae\x8f\x11\x4c\xc2\x9c\x4a\xbb"
+                         "\x85\x34\x66",
+               .klen   = 35,
+               .iv     = "\x42\xc8\x92\x0f\x36\x58\xe0\x6b",
+               .alen   = 0,
+               .input  = "\x48\x01\x5e\x02\x24\x04\x66\x47"
+                         "\xa1\xea\x6f\xaf\xe8\xfc\xfb\xdd"
+                         "\xa5\xa9\x87\x8d\x84\xee\x2e\x77"
+                         "\xbb\x86\xb9\xf5\x5c\x6c\xff\xf6"
+                         "\x72\xc3\x8e\xf7\x70\xb1\xb2\x07"
+                         "\xbc\xa8\xa3\xbd\x83\x7c\x1d\x2a",
+               .ilen   = 48,
+               .result = "\xdc\x56\xf2\x71\xb0\xb1\xa0\x6c"
+                         "\xf0\x97\x3a\xfb\x6d\xe7\x32\x99"
+                         "\x3e\xaf\x70\x5e\xb2\x4d\xea\x39"
+                         "\x89\xd4\x75\x7a\x63\xb1\xda\x93",
+               .rlen   = 32,
+               .novrfy = 1,
+       }, {
+               .key    = "\x58\x5d\xa0\x96\x65\x1a\x04\xd7"
+                         "\x96\xe5\xc5\x68\xaa\x95\x35\xe0"
+                         "\x29\xa0\xba\x9e\x48\x78\xd1\xba"
+                         "\x0d\x1a\x53\x3b\xb5\xe3\xf8\x8b"
+                         "\xcf\x76\x3f",
+               .klen   = 35,
+               .iv     = "\xd9\x95\x75\x8f\x44\x89\x40\x7b",
+               .assoc  = "\x8f\x86\x6c\x4d\x1d\xc5\x39\x88"
+                         "\xc8\xf3\x5c\x52\x10\x63\x6f\x2b"
+                         "\x8a\x2a\xc5\x6f\x30\x23\x58\x7b"
+                         "\xfb\x36\x03\x11\xb4\xd9\xf2\xfe",
+               .alen   = 32,
+               .input  = "\x48\x58\xd6\xf3\xad\x63\x58\xbf"
+                         "\xae\xc7\x5e\xae\x83\x8f\x7b\xe4"
+                         "\x78\x5c\x4c\x67\x71\x89\x94\xbf"
+                         "\x47\xf1\x63\x7e\x1c\x59\xbd\xc5"
+                         "\x7f\x44\x0a\x0c\x01\x18\x07\x92"
+                         "\xe1\xd3\x51\xce\x32\x6d\x0c\x5b",
+               .ilen   = 48,
+               .result = "\xc2\x54\xc8\xde\x78\x87\x77\x40"
+                         "\x49\x71\xe4\xb7\xe7\xcb\x76\x61"
+                         "\x0a\x41\xb9\xe9\xc0\x76\x54\xab"
+                         "\x04\x49\x3b\x19\x93\x57\x25\x5d",
+               .rlen   = 32,
+       },
+};
+
+/*
+ * ANSI X9.31 Continuous Pseudo-Random Number Generator (AES mode)
+ * test vectors, taken from Appendix B.2.9 and B.2.10:
+ *     http://csrc.nist.gov/groups/STM/cavp/documents/rng/RNGVS.pdf
+ * Only AES-128 is supported at this time.
+ */
+#define ANSI_CPRNG_AES_TEST_VECTORS    6
+
+static struct cprng_testvec ansi_cprng_aes_tv_template[] = {
+       {
+               .key    = "\xf3\xb1\x66\x6d\x13\x60\x72\x42"
+                         "\xed\x06\x1c\xab\xb8\xd4\x62\x02",
+               .klen   = 16,
+               .dt     = "\xe6\xb3\xbe\x78\x2a\x23\xfa\x62"
+                         "\xd7\x1d\x4a\xfb\xb0\xe9\x22\xf9",
+               .dtlen  = 16,
+               .v      = "\x80\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .vlen   = 16,
+               .result = "\x59\x53\x1e\xd1\x3b\xb0\xc0\x55"
+                         "\x84\x79\x66\x85\xc1\x2f\x76\x41",
+               .rlen   = 16,
+               .loops  = 1,
+       }, {
+               .key    = "\xf3\xb1\x66\x6d\x13\x60\x72\x42"
+                         "\xed\x06\x1c\xab\xb8\xd4\x62\x02",
+               .klen   = 16,
+               .dt     = "\xe6\xb3\xbe\x78\x2a\x23\xfa\x62"
+                         "\xd7\x1d\x4a\xfb\xb0\xe9\x22\xfa",
+               .dtlen  = 16,
+               .v      = "\xc0\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .vlen   = 16,
+               .result = "\x7c\x22\x2c\xf4\xca\x8f\xa2\x4c"
+                         "\x1c\x9c\xb6\x41\xa9\xf3\x22\x0d",
+               .rlen   = 16,
+               .loops  = 1,
+       }, {
+               .key    = "\xf3\xb1\x66\x6d\x13\x60\x72\x42"
+                         "\xed\x06\x1c\xab\xb8\xd4\x62\x02",
+               .klen   = 16,
+               .dt     = "\xe6\xb3\xbe\x78\x2a\x23\xfa\x62"
+                         "\xd7\x1d\x4a\xfb\xb0\xe9\x22\xfb",
+               .dtlen  = 16,
+               .v      = "\xe0\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .vlen   = 16,
+               .result = "\x8a\xaa\x00\x39\x66\x67\x5b\xe5"
+                         "\x29\x14\x28\x81\xa9\x4d\x4e\xc7",
+               .rlen   = 16,
+               .loops  = 1,
+       }, {
+               .key    = "\xf3\xb1\x66\x6d\x13\x60\x72\x42"
+                         "\xed\x06\x1c\xab\xb8\xd4\x62\x02",
+               .klen   = 16,
+               .dt     = "\xe6\xb3\xbe\x78\x2a\x23\xfa\x62"
+                         "\xd7\x1d\x4a\xfb\xb0\xe9\x22\xfc",
+               .dtlen  = 16,
+               .v      = "\xf0\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .vlen   = 16,
+               .result = "\x88\xdd\xa4\x56\x30\x24\x23\xe5"
+                         "\xf6\x9d\xa5\x7e\x7b\x95\xc7\x3a",
+               .rlen   = 16,
+               .loops  = 1,
+       }, {
+               .key    = "\xf3\xb1\x66\x6d\x13\x60\x72\x42"
+                         "\xed\x06\x1c\xab\xb8\xd4\x62\x02",
+               .klen   = 16,
+               .dt     = "\xe6\xb3\xbe\x78\x2a\x23\xfa\x62"
+                         "\xd7\x1d\x4a\xfb\xb0\xe9\x22\xfd",
+               .dtlen  = 16,
+               .v      = "\xf8\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .vlen   = 16,
+               .result = "\x05\x25\x92\x46\x61\x79\xd2\xcb"
+                         "\x78\xc4\x0b\x14\x0a\x5a\x9a\xc8",
+               .rlen   = 16,
+               .loops  = 1,
+       }, {    /* Monte Carlo Test */
+               .key    = "\x9f\x5b\x51\x20\x0b\xf3\x34\xb5"
+                         "\xd8\x2b\xe8\xc3\x72\x55\xc8\x48",
+               .klen   = 16,
+               .dt     = "\x63\x76\xbb\xe5\x29\x02\xba\x3b"
+                         "\x67\xc9\x25\xfa\x70\x1f\x11\xac",
+               .dtlen  = 16,
+               .v      = "\x57\x2c\x8e\x76\x87\x26\x47\x97"
+                         "\x7e\x74\xfb\xdd\xc4\x95\x01\xd1",
+               .vlen   = 16,
+               .result = "\x48\xe9\xbd\x0d\x06\xee\x18\xfb"
+                         "\xe4\x57\x90\xd5\xc3\xfc\x9b\x73",
+               .rlen   = 16,
+               .loops  = 10000,
+       },
+};
+
 /* Cast5 test vectors from RFC 2144 */
 #define CAST5_ENC_TEST_VECTORS 3
 #define CAST5_DEC_TEST_VECTORS 3
index 33609bab614ed118096918f40e00cafb4de3ad4b..c3015733c9909cbf90554477a79430b1a31ab286 100644 (file)
@@ -165,15 +165,15 @@ static int zlib_compress_update(struct crypto_pcomp *tfm,
                return -EINVAL;
        }
 
+       ret = req->avail_out - stream->avail_out;
        pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
                 stream->avail_in, stream->avail_out,
-                req->avail_in - stream->avail_in,
-                req->avail_out - stream->avail_out);
+                req->avail_in - stream->avail_in, ret);
        req->next_in = stream->next_in;
        req->avail_in = stream->avail_in;
        req->next_out = stream->next_out;
        req->avail_out = stream->avail_out;
-       return 0;
+       return ret;
 }
 
 static int zlib_compress_final(struct crypto_pcomp *tfm,
@@ -195,15 +195,15 @@ static int zlib_compress_final(struct crypto_pcomp *tfm,
                return -EINVAL;
        }
 
+       ret = req->avail_out - stream->avail_out;
        pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
                 stream->avail_in, stream->avail_out,
-                req->avail_in - stream->avail_in,
-                req->avail_out - stream->avail_out);
+                req->avail_in - stream->avail_in, ret);
        req->next_in = stream->next_in;
        req->avail_in = stream->avail_in;
        req->next_out = stream->next_out;
        req->avail_out = stream->avail_out;
-       return 0;
+       return ret;
 }
 
 
@@ -280,15 +280,15 @@ static int zlib_decompress_update(struct crypto_pcomp *tfm,
                return -EINVAL;
        }
 
+       ret = req->avail_out - stream->avail_out;
        pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
                 stream->avail_in, stream->avail_out,
-                req->avail_in - stream->avail_in,
-                req->avail_out - stream->avail_out);
+                req->avail_in - stream->avail_in, ret);
        req->next_in = stream->next_in;
        req->avail_in = stream->avail_in;
        req->next_out = stream->next_out;
        req->avail_out = stream->avail_out;
-       return 0;
+       return ret;
 }
 
 static int zlib_decompress_final(struct crypto_pcomp *tfm,
@@ -328,15 +328,15 @@ static int zlib_decompress_final(struct crypto_pcomp *tfm,
                return -EINVAL;
        }
 
+       ret = req->avail_out - stream->avail_out;
        pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
                 stream->avail_in, stream->avail_out,
-                req->avail_in - stream->avail_in,
-                req->avail_out - stream->avail_out);
+                req->avail_in - stream->avail_in, ret);
        req->next_in = stream->next_in;
        req->avail_in = stream->avail_in;
        req->next_out = stream->next_out;
        req->avail_out = stream->avail_out;
-       return 0;
+       return ret;
 }
 
 
index 9120717c0701398a21db009b7b0b48dc95267763..2aa1908e5ce0076a92f65367b4cef10e3b92d221 100644 (file)
@@ -535,6 +535,15 @@ config PATA_OPTIDMA
 
          If unsure, say N.
 
+config PATA_PALMLD
+       tristate "Palm LifeDrive PATA support"
+       depends on MACH_PALMLD
+       help
+         This option enables support for Palm LifeDrive's internal ATA
+         port via the new ATA layer.
+
+         If unsure, say N.
+
 config PATA_PCMCIA
        tristate "PCMCIA PATA support"
        depends on PCMCIA
index 7f1ecf99528cfa21bf2a5f8229b9d6ac57bf38c5..1558059874f03db15246d39bcc3c049ff6311002 100644 (file)
@@ -50,6 +50,7 @@ obj-$(CONFIG_PATA_MPC52xx)    += pata_mpc52xx.o
 obj-$(CONFIG_PATA_MARVELL)     += pata_marvell.o
 obj-$(CONFIG_PATA_MPIIX)       += pata_mpiix.o
 obj-$(CONFIG_PATA_OLDPIIX)     += pata_oldpiix.o
+obj-$(CONFIG_PATA_PALMLD)      += pata_palmld.o
 obj-$(CONFIG_PATA_PCMCIA)      += pata_pcmcia.o
 obj-$(CONFIG_PATA_PDC2027X)    += pata_pdc2027x.o
 obj-$(CONFIG_PATA_PDC_OLD)     += pata_pdc202xx_old.o
index 6273d98d00ebc6f200f470dbbe856b5181b9a7c4..ac176da1f94e24d8b4bbe683a44f155cb2f06970 100644 (file)
@@ -748,9 +748,9 @@ static int ata_acpi_run_tf(struct ata_device *dev,
 /**
  * ata_acpi_exec_tfs - get then write drive taskfile settings
  * @dev: target ATA device
- * @nr_executed: out paramter for the number of executed commands
+ * @nr_executed: out parameter for the number of executed commands
  *
- * Evaluate _GTF and excute returned taskfiles.
+ * Evaluate _GTF and execute returned taskfiles.
  *
  * LOCKING:
  * EH context.
index 94919ad03df12ddd7845870b9ea7346827400b98..fa22f94ca4150247b39a0e26fa7541d4cbee4ba4 100644 (file)
@@ -2864,7 +2864,7 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
 /**
  *     ata_set_mode - Program timings and issue SET FEATURES - XFER
  *     @link: link on which timings will be programmed
- *     @r_failed_dev: out paramter for failed device
+ *     @r_failed_dev: out parameter for failed device
  *
  *     Set ATA device disk transfer mode (PIO3, UDMA6, etc.).  If
  *     ata_set_mode() fails, pointer to the failing device is
diff --git a/drivers/ata/pata_palmld.c b/drivers/ata/pata_palmld.c
new file mode 100644 (file)
index 0000000..11fb4cc
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * drivers/ata/pata_palmld.c
+ *
+ * Driver for IDE channel in Palm LifeDrive
+ *
+ * Based on research of:
+ *             Alex Osborne <ato@meshy.org>
+ *
+ * Rewrite for mainline:
+ *             Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Rewritten version based on pata_ixp4xx_cf.c:
+ * ixp4xx PATA/Compact Flash driver
+ * Copyright (C) 2006-07 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * This 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/libata.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <scsi/scsi_host.h>
+#include <mach/palmld.h>
+
+#define DRV_NAME "pata_palmld"
+
+static struct scsi_host_template palmld_sht = {
+       ATA_PIO_SHT(DRV_NAME),
+};
+
+static struct ata_port_operations palmld_port_ops = {
+       .inherits               = &ata_sff_port_ops,
+       .sff_data_xfer          = ata_sff_data_xfer_noirq,
+       .cable_detect           = ata_cable_40wire,
+};
+
+static __devinit int palmld_pata_probe(struct platform_device *pdev)
+{
+       struct ata_host *host;
+       struct ata_port *ap;
+       void __iomem *mem;
+       int ret;
+
+       /* allocate host */
+       host = ata_host_alloc(&pdev->dev, 1);
+       if (!host)
+               return -ENOMEM;
+
+       /* remap drive's physical memory address */
+       mem = devm_ioremap(&pdev->dev, PALMLD_IDE_PHYS, 0x1000);
+       if (!mem)
+               return -ENOMEM;
+
+       /* request and activate power GPIO, IRQ GPIO */
+       ret = gpio_request(GPIO_NR_PALMLD_IDE_PWEN, "HDD PWR");
+       if (ret)
+               goto err1;
+       ret = gpio_direction_output(GPIO_NR_PALMLD_IDE_PWEN, 1);
+       if (ret)
+               goto err2;
+
+       ret = gpio_request(GPIO_NR_PALMLD_IDE_RESET, "HDD RST");
+       if (ret)
+               goto err2;
+       ret = gpio_direction_output(GPIO_NR_PALMLD_IDE_RESET, 0);
+       if (ret)
+               goto err3;
+
+       /* reset the drive */
+       gpio_set_value(GPIO_NR_PALMLD_IDE_RESET, 0);
+       msleep(30);
+       gpio_set_value(GPIO_NR_PALMLD_IDE_RESET, 1);
+       msleep(30);
+
+       /* setup the ata port */
+       ap = host->ports[0];
+       ap->ops = &palmld_port_ops;
+       ap->pio_mask = ATA_PIO4;
+       ap->flags |= ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY | ATA_FLAG_PIO_POLLING;
+
+       /* memory mapping voodoo */
+       ap->ioaddr.cmd_addr = mem + 0x10;
+       ap->ioaddr.altstatus_addr = mem + 0xe;
+       ap->ioaddr.ctl_addr = mem + 0xe;
+
+       /* start the port */
+       ata_sff_std_ports(&ap->ioaddr);
+
+       /* activate host */
+       return ata_host_activate(host, 0, NULL, IRQF_TRIGGER_RISING,
+                                       &palmld_sht);
+
+err3:
+       gpio_free(GPIO_NR_PALMLD_IDE_RESET);
+err2:
+       gpio_free(GPIO_NR_PALMLD_IDE_PWEN);
+err1:
+       return ret;
+}
+
+static __devexit int palmld_pata_remove(struct platform_device *dev)
+{
+       struct ata_host *host = platform_get_drvdata(dev);
+
+       ata_host_detach(host);
+
+       /* power down the HDD */
+       gpio_set_value(GPIO_NR_PALMLD_IDE_PWEN, 0);
+
+       gpio_free(GPIO_NR_PALMLD_IDE_RESET);
+       gpio_free(GPIO_NR_PALMLD_IDE_PWEN);
+
+       return 0;
+}
+
+static struct platform_driver palmld_pata_platform_driver = {
+       .driver  = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = palmld_pata_probe,
+       .remove         = __devexit_p(palmld_pata_remove),
+};
+
+static int __init palmld_pata_init(void)
+{
+       return platform_driver_register(&palmld_pata_platform_driver);
+}
+
+static void __exit palmld_pata_exit(void)
+{
+       platform_driver_unregister(&palmld_pata_platform_driver);
+}
+
+MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
+MODULE_DESCRIPTION("PalmLD PATA driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+
+module_init(palmld_pata_init);
+module_exit(palmld_pata_exit);
index c6599618523e7fc265daf265880c9c1e7c0fe056..4b04a15146d7cf3dcb0f4aec9973a5683c73cf83 100644 (file)
@@ -279,7 +279,7 @@ static struct device *next_device(struct klist_iter *i)
  *
  * NOTE: The device that returns a non-zero value is not retained
  * in any way, nor is its refcount incremented. If the caller needs
- * to retain this data, it should do, and increment the reference
+ * to retain this data, it should do so, and increment the reference
  * count in the supplied callback.
  */
 int bus_for_each_dev(struct bus_type *bus, struct device *start,
index d3a59c688fe4fcaf0f7ebf514f44f59a08e90693..8a267c4276291bb775e2590a6935825ae35e9305 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/bitops.h>
 #include <linux/mutex.h>
 #include <linux/kthread.h>
-
+#include <linux/highmem.h>
 #include <linux/firmware.h>
 #include "base.h"
 
@@ -45,7 +45,10 @@ struct firmware_priv {
        struct bin_attribute attr_data;
        struct firmware *fw;
        unsigned long status;
-       int alloc_size;
+       struct page **pages;
+       int nr_pages;
+       int page_array_size;
+       const char *vdata;
        struct timer_list timeout;
 };
 
@@ -122,6 +125,10 @@ static ssize_t firmware_loading_show(struct device *dev,
        return sprintf(buf, "%d\n", loading);
 }
 
+/* Some architectures don't have PAGE_KERNEL_RO */
+#ifndef PAGE_KERNEL_RO
+#define PAGE_KERNEL_RO PAGE_KERNEL
+#endif
 /**
  * firmware_loading_store - set value in the 'loading' control file
  * @dev: device pointer
@@ -141,6 +148,7 @@ static ssize_t firmware_loading_store(struct device *dev,
 {
        struct firmware_priv *fw_priv = dev_get_drvdata(dev);
        int loading = simple_strtol(buf, NULL, 10);
+       int i;
 
        switch (loading) {
        case 1:
@@ -151,13 +159,30 @@ static ssize_t firmware_loading_store(struct device *dev,
                }
                vfree(fw_priv->fw->data);
                fw_priv->fw->data = NULL;
+               for (i = 0; i < fw_priv->nr_pages; i++)
+                       __free_page(fw_priv->pages[i]);
+               kfree(fw_priv->pages);
+               fw_priv->pages = NULL;
+               fw_priv->page_array_size = 0;
+               fw_priv->nr_pages = 0;
                fw_priv->fw->size = 0;
-               fw_priv->alloc_size = 0;
                set_bit(FW_STATUS_LOADING, &fw_priv->status);
                mutex_unlock(&fw_lock);
                break;
        case 0:
                if (test_bit(FW_STATUS_LOADING, &fw_priv->status)) {
+                       vfree(fw_priv->fw->data);
+                       fw_priv->fw->data = vmap(fw_priv->pages,
+                                                fw_priv->nr_pages,
+                                                0, PAGE_KERNEL_RO);
+                       if (!fw_priv->fw->data) {
+                               dev_err(dev, "%s: vmap() failed\n", __func__);
+                               goto err;
+                       }
+                       /* Pages will be freed by vfree() */
+                       fw_priv->pages = NULL;
+                       fw_priv->page_array_size = 0;
+                       fw_priv->nr_pages = 0;
                        complete(&fw_priv->completion);
                        clear_bit(FW_STATUS_LOADING, &fw_priv->status);
                        break;
@@ -167,6 +192,7 @@ static ssize_t firmware_loading_store(struct device *dev,
                dev_err(dev, "%s: unexpected value (%d)\n", __func__, loading);
                /* fallthrough */
        case -1:
+       err:
                fw_load_abort(fw_priv);
                break;
        }
@@ -191,8 +217,28 @@ firmware_data_read(struct kobject *kobj, struct bin_attribute *bin_attr,
                ret_count = -ENODEV;
                goto out;
        }
-       ret_count = memory_read_from_buffer(buffer, count, &offset,
-                                               fw->data, fw->size);
+       if (offset > fw->size)
+               return 0;
+       if (count > fw->size - offset)
+               count = fw->size - offset;
+
+       ret_count = count;
+
+       while (count) {
+               void *page_data;
+               int page_nr = offset >> PAGE_SHIFT;
+               int page_ofs = offset & (PAGE_SIZE-1);
+               int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);
+
+               page_data = kmap(fw_priv->pages[page_nr]);
+
+               memcpy(buffer, page_data + page_ofs, page_cnt);
+
+               kunmap(fw_priv->pages[page_nr]);
+               buffer += page_cnt;
+               offset += page_cnt;
+               count -= page_cnt;
+       }
 out:
        mutex_unlock(&fw_lock);
        return ret_count;
@@ -201,27 +247,39 @@ out:
 static int
 fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
 {
-       u8 *new_data;
-       int new_size = fw_priv->alloc_size;
+       int pages_needed = ALIGN(min_size, PAGE_SIZE) >> PAGE_SHIFT;
+
+       /* If the array of pages is too small, grow it... */
+       if (fw_priv->page_array_size < pages_needed) {
+               int new_array_size = max(pages_needed,
+                                        fw_priv->page_array_size * 2);
+               struct page **new_pages;
+
+               new_pages = kmalloc(new_array_size * sizeof(void *),
+                                   GFP_KERNEL);
+               if (!new_pages) {
+                       fw_load_abort(fw_priv);
+                       return -ENOMEM;
+               }
+               memcpy(new_pages, fw_priv->pages,
+                      fw_priv->page_array_size * sizeof(void *));
+               memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) *
+                      (new_array_size - fw_priv->page_array_size));
+               kfree(fw_priv->pages);
+               fw_priv->pages = new_pages;
+               fw_priv->page_array_size = new_array_size;
+       }
 
-       if (min_size <= fw_priv->alloc_size)
-               return 0;
+       while (fw_priv->nr_pages < pages_needed) {
+               fw_priv->pages[fw_priv->nr_pages] =
+                       alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
 
-       new_size = ALIGN(min_size, PAGE_SIZE);
-       new_data = vmalloc(new_size);
-       if (!new_data) {
-               printk(KERN_ERR "%s: unable to alloc buffer\n", __func__);
-               /* Make sure that we don't keep incomplete data */
-               fw_load_abort(fw_priv);
-               return -ENOMEM;
-       }
-       fw_priv->alloc_size = new_size;
-       if (fw_priv->fw->data) {
-               memcpy(new_data, fw_priv->fw->data, fw_priv->fw->size);
-               vfree(fw_priv->fw->data);
+               if (!fw_priv->pages[fw_priv->nr_pages]) {
+                       fw_load_abort(fw_priv);
+                       return -ENOMEM;
+               }
+               fw_priv->nr_pages++;
        }
-       fw_priv->fw->data = new_data;
-       BUG_ON(min_size > fw_priv->alloc_size);
        return 0;
 }
 
@@ -258,10 +316,25 @@ firmware_data_write(struct kobject *kobj, struct bin_attribute *bin_attr,
        if (retval)
                goto out;
 
-       memcpy((u8 *)fw->data + offset, buffer, count);
-
-       fw->size = max_t(size_t, offset + count, fw->size);
        retval = count;
+
+       while (count) {
+               void *page_data;
+               int page_nr = offset >> PAGE_SHIFT;
+               int page_ofs = offset & (PAGE_SIZE - 1);
+               int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);
+
+               page_data = kmap(fw_priv->pages[page_nr]);
+
+               memcpy(page_data + page_ofs, buffer, page_cnt);
+
+               kunmap(fw_priv->pages[page_nr]);
+               buffer += page_cnt;
+               offset += page_cnt;
+               count -= page_cnt;
+       }
+
+       fw->size = max_t(size_t, offset, fw->size);
 out:
        mutex_unlock(&fw_lock);
        return retval;
@@ -277,7 +350,11 @@ static struct bin_attribute firmware_attr_data_tmpl = {
 static void fw_dev_release(struct device *dev)
 {
        struct firmware_priv *fw_priv = dev_get_drvdata(dev);
+       int i;
 
+       for (i = 0; i < fw_priv->nr_pages; i++)
+               __free_page(fw_priv->pages[i]);
+       kfree(fw_priv->pages);
        kfree(fw_priv);
        kfree(dev);
 
index 8b4708e06244b2ba0b61b241b2ffd1d55b18f444..ead3f64c41d0506774788860f0f2232f22c9ce0a 100644 (file)
@@ -469,22 +469,6 @@ static void platform_drv_shutdown(struct device *_dev)
        drv->shutdown(dev);
 }
 
-static int platform_drv_suspend(struct device *_dev, pm_message_t state)
-{
-       struct platform_driver *drv = to_platform_driver(_dev->driver);
-       struct platform_device *dev = to_platform_device(_dev);
-
-       return drv->suspend(dev, state);
-}
-
-static int platform_drv_resume(struct device *_dev)
-{
-       struct platform_driver *drv = to_platform_driver(_dev->driver);
-       struct platform_device *dev = to_platform_device(_dev);
-
-       return drv->resume(dev);
-}
-
 /**
  * platform_driver_register
  * @drv: platform driver structure
@@ -498,10 +482,10 @@ int platform_driver_register(struct platform_driver *drv)
                drv->driver.remove = platform_drv_remove;
        if (drv->shutdown)
                drv->driver.shutdown = platform_drv_shutdown;
-       if (drv->suspend)
-               drv->driver.suspend = platform_drv_suspend;
-       if (drv->resume)
-               drv->driver.resume = platform_drv_resume;
+       if (drv->suspend || drv->resume)
+               pr_warning("Platform driver '%s' needs updating - please use "
+                       "dev_pm_ops\n", drv->driver.name);
+
        return driver_register(&drv->driver);
 }
 EXPORT_SYMBOL_GPL(platform_driver_register);
@@ -633,10 +617,12 @@ static int platform_match(struct device *dev, struct device_driver *drv)
 
 static int platform_legacy_suspend(struct device *dev, pm_message_t mesg)
 {
+       struct platform_driver *pdrv = to_platform_driver(dev->driver);
+       struct platform_device *pdev = to_platform_device(dev);
        int ret = 0;
 
-       if (dev->driver && dev->driver->suspend)
-               ret = dev->driver->suspend(dev, mesg);
+       if (dev->driver && pdrv->suspend)
+               ret = pdrv->suspend(pdev, mesg);
 
        return ret;
 }
@@ -667,10 +653,12 @@ static int platform_legacy_resume_early(struct device *dev)
 
 static int platform_legacy_resume(struct device *dev)
 {
+       struct platform_driver *pdrv = to_platform_driver(dev->driver);
+       struct platform_device *pdev = to_platform_device(dev);
        int ret = 0;
 
-       if (dev->driver && dev->driver->resume)
-               ret = dev->driver->resume(dev);
+       if (dev->driver && pdrv->resume)
+               ret = pdrv->resume(pdev);
 
        return ret;
 }
index 3e4bc699bc0f30349be3ed75b9ecc28cdb77ddf1..fae725458981793649bf3e339a20394ac9859448 100644 (file)
@@ -315,13 +315,13 @@ static void pm_dev_err(struct device *dev, pm_message_t state, char *info,
 /*------------------------- Resume routines -------------------------*/
 
 /**
- *     resume_device_noirq - Power on one device (early resume).
+ *     device_resume_noirq - Power on one device (early resume).
  *     @dev:   Device.
  *     @state: PM transition of the system being carried out.
  *
  *     Must be called with interrupts disabled.
  */
-static int resume_device_noirq(struct device *dev, pm_message_t state)
+static int device_resume_noirq(struct device *dev, pm_message_t state)
 {
        int error = 0;
 
@@ -334,9 +334,6 @@ static int resume_device_noirq(struct device *dev, pm_message_t state)
        if (dev->bus->pm) {
                pm_dev_dbg(dev, state, "EARLY ");
                error = pm_noirq_op(dev, dev->bus->pm, state);
-       } else if (dev->bus->resume_early) {
-               pm_dev_dbg(dev, state, "legacy EARLY ");
-               error = dev->bus->resume_early(dev);
        }
  End:
        TRACE_RESUME(error);
@@ -344,16 +341,16 @@ static int resume_device_noirq(struct device *dev, pm_message_t state)
 }
 
 /**
- *     dpm_power_up - Power on all regular (non-sysdev) devices.
+ *     dpm_resume_noirq - Power on all regular (non-sysdev) devices.
  *     @state: PM transition of the system being carried out.
  *
- *     Execute the appropriate "noirq resume" callback for all devices marked
- *     as DPM_OFF_IRQ.
+ *     Call the "noirq" resume handlers for all devices marked as
+ *     DPM_OFF_IRQ and enable device drivers to receive interrupts.
  *
  *     Must be called under dpm_list_mtx.  Device drivers should not receive
  *     interrupts while it's being executed.
  */
-static void dpm_power_up(pm_message_t state)
+void dpm_resume_noirq(pm_message_t state)
 {
        struct device *dev;
 
@@ -363,33 +360,21 @@ static void dpm_power_up(pm_message_t state)
                        int error;
 
                        dev->power.status = DPM_OFF;
-                       error = resume_device_noirq(dev, state);
+                       error = device_resume_noirq(dev, state);
                        if (error)
                                pm_dev_err(dev, state, " early", error);
                }
        mutex_unlock(&dpm_list_mtx);
-}
-
-/**
- *     device_power_up - Turn on all devices that need special attention.
- *     @state: PM transition of the system being carried out.
- *
- *     Call the "early" resume handlers and enable device drivers to receive
- *     interrupts.
- */
-void device_power_up(pm_message_t state)
-{
-       dpm_power_up(state);
        resume_device_irqs();
 }
-EXPORT_SYMBOL_GPL(device_power_up);
+EXPORT_SYMBOL_GPL(dpm_resume_noirq);
 
 /**
- *     resume_device - Restore state for one device.
+ *     device_resume - Restore state for one device.
  *     @dev:   Device.
  *     @state: PM transition of the system being carried out.
  */
-static int resume_device(struct device *dev, pm_message_t state)
+static int device_resume(struct device *dev, pm_message_t state)
 {
        int error = 0;
 
@@ -414,9 +399,6 @@ static int resume_device(struct device *dev, pm_message_t state)
                if (dev->type->pm) {
                        pm_dev_dbg(dev, state, "type ");
                        error = pm_op(dev, dev->type->pm, state);
-               } else if (dev->type->resume) {
-                       pm_dev_dbg(dev, state, "legacy type ");
-                       error = dev->type->resume(dev);
                }
                if (error)
                        goto End;
@@ -462,7 +444,7 @@ static void dpm_resume(pm_message_t state)
                        dev->power.status = DPM_RESUMING;
                        mutex_unlock(&dpm_list_mtx);
 
-                       error = resume_device(dev, state);
+                       error = device_resume(dev, state);
 
                        mutex_lock(&dpm_list_mtx);
                        if (error)
@@ -480,11 +462,11 @@ static void dpm_resume(pm_message_t state)
 }
 
 /**
- *     complete_device - Complete a PM transition for given device
+ *     device_complete - Complete a PM transition for given device
  *     @dev:   Device.
  *     @state: PM transition of the system being carried out.
  */
-static void complete_device(struct device *dev, pm_message_t state)
+static void device_complete(struct device *dev, pm_message_t state)
 {
        down(&dev->sem);
 
@@ -527,7 +509,7 @@ static void dpm_complete(pm_message_t state)
                        dev->power.status = DPM_ON;
                        mutex_unlock(&dpm_list_mtx);
 
-                       complete_device(dev, state);
+                       device_complete(dev, state);
 
                        mutex_lock(&dpm_list_mtx);
                }
@@ -540,19 +522,19 @@ static void dpm_complete(pm_message_t state)
 }
 
 /**
- *     device_resume - Restore state of each device in system.
+ *     dpm_resume_end - Restore state of each device in system.
  *     @state: PM transition of the system being carried out.
  *
  *     Resume all the devices, unlock them all, and allow new
  *     devices to be registered once again.
  */
-void device_resume(pm_message_t state)
+void dpm_resume_end(pm_message_t state)
 {
        might_sleep();
        dpm_resume(state);
        dpm_complete(state);
 }
-EXPORT_SYMBOL_GPL(device_resume);
+EXPORT_SYMBOL_GPL(dpm_resume_end);
 
 
 /*------------------------- Suspend routines -------------------------*/
@@ -577,13 +559,13 @@ static pm_message_t resume_event(pm_message_t sleep_state)
 }
 
 /**
- *     suspend_device_noirq - Shut down one device (late suspend).
+ *     device_suspend_noirq - Shut down one device (late suspend).
  *     @dev:   Device.
  *     @state: PM transition of the system being carried out.
  *
  *     This is called with interrupts off and only a single CPU running.
  */
-static int suspend_device_noirq(struct device *dev, pm_message_t state)
+static int device_suspend_noirq(struct device *dev, pm_message_t state)
 {
        int error = 0;
 
@@ -593,24 +575,20 @@ static int suspend_device_noirq(struct device *dev, pm_message_t state)
        if (dev->bus->pm) {
                pm_dev_dbg(dev, state, "LATE ");
                error = pm_noirq_op(dev, dev->bus->pm, state);
-       } else if (dev->bus->suspend_late) {
-               pm_dev_dbg(dev, state, "legacy LATE ");
-               error = dev->bus->suspend_late(dev, state);
-               suspend_report_result(dev->bus->suspend_late, error);
        }
        return error;
 }
 
 /**
- *     device_power_down - Shut down special devices.
+ *     dpm_suspend_noirq - Power down all regular (non-sysdev) devices.
  *     @state: PM transition of the system being carried out.
  *
- *     Prevent device drivers from receiving interrupts and call the "late"
+ *     Prevent device drivers from receiving interrupts and call the "noirq"
  *     suspend handlers.
  *
  *     Must be called under dpm_list_mtx.
  */
-int device_power_down(pm_message_t state)
+int dpm_suspend_noirq(pm_message_t state)
 {
        struct device *dev;
        int error = 0;
@@ -618,7 +596,7 @@ int device_power_down(pm_message_t state)
        suspend_device_irqs();
        mutex_lock(&dpm_list_mtx);
        list_for_each_entry_reverse(dev, &dpm_list, power.entry) {
-               error = suspend_device_noirq(dev, state);
+               error = device_suspend_noirq(dev, state);
                if (error) {
                        pm_dev_err(dev, state, " late", error);
                        break;
@@ -627,17 +605,17 @@ int device_power_down(pm_message_t state)
        }
        mutex_unlock(&dpm_list_mtx);
        if (error)
-               device_power_up(resume_event(state));
+               dpm_resume_noirq(resume_event(state));
        return error;
 }
-EXPORT_SYMBOL_GPL(device_power_down);
+EXPORT_SYMBOL_GPL(dpm_suspend_noirq);
 
 /**
- *     suspend_device - Save state of one device.
+ *     device_suspend - Save state of one device.
  *     @dev:   Device.
  *     @state: PM transition of the system being carried out.
  */
-static int suspend_device(struct device *dev, pm_message_t state)
+static int device_suspend(struct device *dev, pm_message_t state)
 {
        int error = 0;
 
@@ -660,10 +638,6 @@ static int suspend_device(struct device *dev, pm_message_t state)
                if (dev->type->pm) {
                        pm_dev_dbg(dev, state, "type ");
                        error = pm_op(dev, dev->type->pm, state);
-               } else if (dev->type->suspend) {
-                       pm_dev_dbg(dev, state, "legacy type ");
-                       error = dev->type->suspend(dev, state);
-                       suspend_report_result(dev->type->suspend, error);
                }
                if (error)
                        goto End;
@@ -704,7 +678,7 @@ static int dpm_suspend(pm_message_t state)
                get_device(dev);
                mutex_unlock(&dpm_list_mtx);
 
-               error = suspend_device(dev, state);
+               error = device_suspend(dev, state);
 
                mutex_lock(&dpm_list_mtx);
                if (error) {
@@ -723,11 +697,11 @@ static int dpm_suspend(pm_message_t state)
 }
 
 /**
- *     prepare_device - Execute the ->prepare() callback(s) for given device.
+ *     device_prepare - Execute the ->prepare() callback(s) for given device.
  *     @dev:   Device.
  *     @state: PM transition of the system being carried out.
  */
-static int prepare_device(struct device *dev, pm_message_t state)
+static int device_prepare(struct device *dev, pm_message_t state)
 {
        int error = 0;
 
@@ -781,7 +755,7 @@ static int dpm_prepare(pm_message_t state)
                dev->power.status = DPM_PREPARING;
                mutex_unlock(&dpm_list_mtx);
 
-               error = prepare_device(dev, state);
+               error = device_prepare(dev, state);
 
                mutex_lock(&dpm_list_mtx);
                if (error) {
@@ -807,12 +781,12 @@ static int dpm_prepare(pm_message_t state)
 }
 
 /**
- *     device_suspend - Save state and stop all devices in system.
+ *     dpm_suspend_start - Save state and stop all devices in system.
  *     @state: PM transition of the system being carried out.
  *
  *     Prepare and suspend all devices.
  */
-int device_suspend(pm_message_t state)
+int dpm_suspend_start(pm_message_t state)
 {
        int error;
 
@@ -822,7 +796,7 @@ int device_suspend(pm_message_t state)
                error = dpm_suspend(state);
        return error;
 }
-EXPORT_SYMBOL_GPL(device_suspend);
+EXPORT_SYMBOL_GPL(dpm_suspend_start);
 
 void __suspend_report_result(const char *function, void *fn, int ret)
 {
index 3236b434b964c04078d6dfda2d4364e70fafb11b..9742a78c9fe42a043bfa0c57e89ead65e4f6fc2f 100644 (file)
@@ -343,11 +343,15 @@ static void __sysdev_resume(struct sys_device *dev)
        /* First, call the class-specific one */
        if (cls->resume)
                cls->resume(dev);
+       WARN_ONCE(!irqs_disabled(),
+               "Interrupts enabled after %pF\n", cls->resume);
 
        /* Call auxillary drivers next. */
        list_for_each_entry(drv, &cls->drivers, entry) {
                if (drv->resume)
                        drv->resume(dev);
+               WARN_ONCE(!irqs_disabled(),
+                       "Interrupts enabled after %pF\n", drv->resume);
        }
 }
 
@@ -377,6 +381,9 @@ int sysdev_suspend(pm_message_t state)
        if (ret)
                return ret;
 
+       WARN_ONCE(!irqs_disabled(),
+               "Interrupts enabled while suspending system devices\n");
+
        pr_debug("Suspending System Devices\n");
 
        list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) {
@@ -393,6 +400,9 @@ int sysdev_suspend(pm_message_t state)
                                        if (ret)
                                                goto aux_driver;
                                }
+                               WARN_ONCE(!irqs_disabled(),
+                                       "Interrupts enabled after %pF\n",
+                                       drv->suspend);
                        }
 
                        /* Now call the generic one */
@@ -400,6 +410,9 @@ int sysdev_suspend(pm_message_t state)
                                ret = cls->suspend(sysdev, state);
                                if (ret)
                                        goto cls_driver;
+                               WARN_ONCE(!irqs_disabled(),
+                                       "Interrupts enabled after %pF\n",
+                                       cls->suspend);
                        }
                }
        }
@@ -452,6 +465,9 @@ int sysdev_resume(void)
 {
        struct sysdev_class *cls;
 
+       WARN_ONCE(!irqs_disabled(),
+               "Interrupts enabled while resuming system devices\n");
+
        pr_debug("Resuming System Devices\n");
 
        list_for_each_entry(cls, &system_kset->list, kset.kobj.entry) {
index f42fa50d35506276722ac6b21417468f847ba6c7..bb72ada9f074588e49796267b59600f848a615be 100644 (file)
@@ -112,7 +112,7 @@ config GDROM
          with up to 1 GB of data. This drive will also read standard CD ROM
          disks. Select this option to access any disks in your GD ROM drive.
          Most users will want to say "Y" here.
-         You can also build this as a module which will be called gdrom.ko
+         You can also build this as a module which will be called gdrom.
 
 source "drivers/block/paride/Kconfig"
 
@@ -438,7 +438,7 @@ source "drivers/s390/block/Kconfig"
 
 config XILINX_SYSACE
        tristate "Xilinx SystemACE support"
-       depends on 4xx
+       depends on 4xx || MICROBLAZE
        help
          Include support for the Xilinx SystemACE CompactFlash interface
 
index c0facaa55cf46ee96932d08ee453829735bdf939..43db3ea15b54936da4502526602c117876bd67fc 100644 (file)
@@ -254,7 +254,7 @@ static int index_to_minor(int index)
        return index << PART_BITS;
 }
 
-static int virtblk_probe(struct virtio_device *vdev)
+static int __devinit virtblk_probe(struct virtio_device *vdev)
 {
        struct virtio_blk *vblk;
        int err;
@@ -288,7 +288,7 @@ static int virtblk_probe(struct virtio_device *vdev)
        sg_init_table(vblk->sg, vblk->sg_elems);
 
        /* We expect one virtqueue, for output. */
-       vblk->vq = vdev->config->find_vq(vdev, 0, blk_done);
+       vblk->vq = virtio_find_single_vq(vdev, blk_done, "requests");
        if (IS_ERR(vblk->vq)) {
                err = PTR_ERR(vblk->vq);
                goto out_free_vblk;
@@ -388,14 +388,14 @@ out_put_disk:
 out_mempool:
        mempool_destroy(vblk->pool);
 out_free_vq:
-       vdev->config->del_vq(vblk->vq);
+       vdev->config->del_vqs(vdev);
 out_free_vblk:
        kfree(vblk);
 out:
        return err;
 }
 
-static void virtblk_remove(struct virtio_device *vdev)
+static void __devexit virtblk_remove(struct virtio_device *vdev)
 {
        struct virtio_blk *vblk = vdev->priv;
 
@@ -409,7 +409,7 @@ static void virtblk_remove(struct virtio_device *vdev)
        blk_cleanup_queue(vblk->disk->queue);
        put_disk(vblk->disk);
        mempool_destroy(vblk->pool);
-       vdev->config->del_vq(vblk->vq);
+       vdev->config->del_vqs(vdev);
        kfree(vblk);
 }
 
index 02ecfd5fa61c56f17ed658e3759e525794f53d81..30bae6de6a0d208382605866c3a6b251681275bc 100644 (file)
@@ -692,7 +692,7 @@ config HVCS
          this driver.
 
          To compile this driver as a module, choose M here: the
-         module will be called hvcs.ko.  Additionally, this module
+         module will be called hvcs.  Additionally, this module
          will depend on arch specific APIs exported from hvcserver.ko
          which will also be compiled when this driver is built as a
          module.
@@ -906,7 +906,7 @@ config DTLK
 
 config XILINX_HWICAP
        tristate "Xilinx HWICAP Support"
-       depends on XILINX_VIRTEX
+       depends on XILINX_VIRTEX || MICROBLAZE
        help
          This option enables support for Xilinx Internal Configuration
          Access Port (ICAP) driver.  The ICAP is used on Xilinx Virtex
index 3686912427ba3ebdba483a22b1f2c131b68e4a80..7a748fa0dfceb00ae93de59d4b5987ebfaff931d 100644 (file)
 #define PCI_DEVICE_ID_INTEL_G45_IG          0x2E22
 #define PCI_DEVICE_ID_INTEL_G41_HB          0x2E30
 #define PCI_DEVICE_ID_INTEL_G41_IG          0x2E32
+#define PCI_DEVICE_ID_INTEL_IGDNG_D_HB     0x0040
+#define PCI_DEVICE_ID_INTEL_IGDNG_D_IG     0x0042
+#define PCI_DEVICE_ID_INTEL_IGDNG_M_HB     0x0044
+#define PCI_DEVICE_ID_INTEL_IGDNG_M_IG     0x0046
 
 /* cover 915 and 945 variants */
 #define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \
@@ -75,7 +79,9 @@
                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q45_HB || \
                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G45_HB || \
                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_GM45_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G41_HB)
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G41_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDNG_D_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDNG_M_HB)
 
 extern int agp_memory_reserved;
 
@@ -1211,6 +1217,8 @@ static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size)
        case PCI_DEVICE_ID_INTEL_Q45_HB:
        case PCI_DEVICE_ID_INTEL_G45_HB:
        case PCI_DEVICE_ID_INTEL_G41_HB:
+       case PCI_DEVICE_ID_INTEL_IGDNG_D_HB:
+       case PCI_DEVICE_ID_INTEL_IGDNG_M_HB:
                *gtt_offset = *gtt_size = MB(2);
                break;
        default:
@@ -2186,6 +2194,10 @@ static const struct intel_driver_description {
            "G45/G43", NULL, &intel_i965_driver },
        { PCI_DEVICE_ID_INTEL_G41_HB, PCI_DEVICE_ID_INTEL_G41_IG, 0,
            "G41", NULL, &intel_i965_driver },
+       { PCI_DEVICE_ID_INTEL_IGDNG_D_HB, PCI_DEVICE_ID_INTEL_IGDNG_D_IG, 0,
+           "IGDNG/D", NULL, &intel_i965_driver },
+       { PCI_DEVICE_ID_INTEL_IGDNG_M_HB, PCI_DEVICE_ID_INTEL_IGDNG_M_IG, 0,
+           "IGDNG/M", NULL, &intel_i965_driver },
        { 0, 0, 0, NULL, NULL, NULL }
 };
 
@@ -2387,6 +2399,8 @@ static struct pci_device_id agp_intel_pci_table[] = {
        ID(PCI_DEVICE_ID_INTEL_Q45_HB),
        ID(PCI_DEVICE_ID_INTEL_G45_HB),
        ID(PCI_DEVICE_ID_INTEL_G41_HB),
+       ID(PCI_DEVICE_ID_INTEL_IGDNG_D_HB),
+       ID(PCI_DEVICE_ID_INTEL_IGDNG_M_HB),
        { }
 };
 
index fd3ebd1be570f98062ae3761bf6a51d3b1145427..72429b6b2fa831e8ce925145398acfbb7aa66170 100644 (file)
@@ -779,7 +779,7 @@ static void change_speed(struct async_struct *info,
                info->IER |= UART_IER_MSI;
        }
        /* TBD:
-        * Does clearing IER_MSI imply that we should disbale the VBL interrupt ?
+        * Does clearing IER_MSI imply that we should disable the VBL interrupt ?
         */
 
        /*
index 5fab6470f4b2beabbdd353063946bd513ef07554..f4b3f7293feb92b69d13a8c60531522d37335712 100644 (file)
@@ -88,7 +88,7 @@ config HW_RANDOM_N2RNG
 
 config HW_RANDOM_VIA
        tristate "VIA HW Random Number Generator support"
-       depends on HW_RANDOM && X86_32
+       depends on HW_RANDOM && X86
        default HW_RANDOM
        ---help---
          This driver provides kernel-side support for the Random Number
@@ -148,3 +148,15 @@ config HW_RANDOM_VIRTIO
 
          To compile this driver as a module, choose M here: the
          module will be called virtio-rng.  If unsure, say N.
+
+config HW_RANDOM_MXC_RNGA
+       tristate "Freescale i.MX RNGA Random Number Generator"
+       depends on HW_RANDOM && ARCH_HAS_RNGA
+       ---help---
+         This driver provides kernel-side support for the Random Number
+         Generator hardware found on Freescale i.MX processors.
+
+         To compile this driver as a module, choose M here: the
+         module will be called mxc-rnga.
+
+         If unsure, say Y.
index e81d21a5f28fb443c370fe5b00bc1eee3be85abb..fd1ecd2f67314e10e36fac3222cf888e93efc282 100644 (file)
@@ -15,3 +15,4 @@ obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o
 obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o
 obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o
 obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o
+obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o
diff --git a/drivers/char/hw_random/mxc-rnga.c b/drivers/char/hw_random/mxc-rnga.c
new file mode 100644 (file)
index 0000000..187c6be
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * RNG driver for Freescale RNGA
+ *
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Author: Alan Carvalho de Assis <acassis@gmail.com>
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * This driver is based on other RNG drivers.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/hw_random.h>
+#include <linux/io.h>
+
+/* RNGA Registers */
+#define RNGA_CONTROL                   0x00
+#define RNGA_STATUS                    0x04
+#define RNGA_ENTROPY                   0x08
+#define RNGA_OUTPUT_FIFO               0x0c
+#define RNGA_MODE                      0x10
+#define RNGA_VERIFICATION_CONTROL      0x14
+#define RNGA_OSC_CONTROL_COUNTER       0x18
+#define RNGA_OSC1_COUNTER              0x1c
+#define RNGA_OSC2_COUNTER              0x20
+#define RNGA_OSC_COUNTER_STATUS                0x24
+
+/* RNGA Registers Range */
+#define RNG_ADDR_RANGE                 0x28
+
+/* RNGA Control Register */
+#define RNGA_CONTROL_SLEEP             0x00000010
+#define RNGA_CONTROL_CLEAR_INT         0x00000008
+#define RNGA_CONTROL_MASK_INTS         0x00000004
+#define RNGA_CONTROL_HIGH_ASSURANCE    0x00000002
+#define RNGA_CONTROL_GO                        0x00000001
+
+#define RNGA_STATUS_LEVEL_MASK         0x0000ff00
+
+/* RNGA Status Register */
+#define RNGA_STATUS_OSC_DEAD           0x80000000
+#define RNGA_STATUS_SLEEP              0x00000010
+#define RNGA_STATUS_ERROR_INT          0x00000008
+#define RNGA_STATUS_FIFO_UNDERFLOW     0x00000004
+#define RNGA_STATUS_LAST_READ_STATUS   0x00000002
+#define RNGA_STATUS_SECURITY_VIOLATION 0x00000001
+
+static struct platform_device *rng_dev;
+
+static int mxc_rnga_data_present(struct hwrng *rng)
+{
+       int level;
+       void __iomem *rng_base = (void __iomem *)rng->priv;
+
+       /* how many random numbers is in FIFO? [0-16] */
+       level = ((__raw_readl(rng_base + RNGA_STATUS) &
+                       RNGA_STATUS_LEVEL_MASK) >> 8);
+
+       return level > 0 ? 1 : 0;
+}
+
+static int mxc_rnga_data_read(struct hwrng *rng, u32 * data)
+{
+       int err;
+       u32 ctrl;
+       void __iomem *rng_base = (void __iomem *)rng->priv;
+
+       /* retrieve a random number from FIFO */
+       *data = __raw_readl(rng_base + RNGA_OUTPUT_FIFO);
+
+       /* some error while reading this random number? */
+       err = __raw_readl(rng_base + RNGA_STATUS) & RNGA_STATUS_ERROR_INT;
+
+       /* if error: clear error interrupt, but doesn't return random number */
+       if (err) {
+               dev_dbg(&rng_dev->dev, "Error while reading random number!\n");
+               ctrl = __raw_readl(rng_base + RNGA_CONTROL);
+               __raw_writel(ctrl | RNGA_CONTROL_CLEAR_INT,
+                                       rng_base + RNGA_CONTROL);
+               return 0;
+       } else
+               return 4;
+}
+
+static int mxc_rnga_init(struct hwrng *rng)
+{
+       u32 ctrl, osc;
+       void __iomem *rng_base = (void __iomem *)rng->priv;
+
+       /* wake up */
+       ctrl = __raw_readl(rng_base + RNGA_CONTROL);
+       __raw_writel(ctrl & ~RNGA_CONTROL_SLEEP, rng_base + RNGA_CONTROL);
+
+       /* verify if oscillator is working */
+       osc = __raw_readl(rng_base + RNGA_STATUS);
+       if (osc & RNGA_STATUS_OSC_DEAD) {
+               dev_err(&rng_dev->dev, "RNGA Oscillator is dead!\n");
+               return -ENODEV;
+       }
+
+       /* go running */
+       ctrl = __raw_readl(rng_base + RNGA_CONTROL);
+       __raw_writel(ctrl | RNGA_CONTROL_GO, rng_base + RNGA_CONTROL);
+
+       return 0;
+}
+
+static void mxc_rnga_cleanup(struct hwrng *rng)
+{
+       u32 ctrl;
+       void __iomem *rng_base = (void __iomem *)rng->priv;
+
+       ctrl = __raw_readl(rng_base + RNGA_CONTROL);
+
+       /* stop rnga */
+       __raw_writel(ctrl & ~RNGA_CONTROL_GO, rng_base + RNGA_CONTROL);
+}
+
+static struct hwrng mxc_rnga = {
+       .name = "mxc-rnga",
+       .init = mxc_rnga_init,
+       .cleanup = mxc_rnga_cleanup,
+       .data_present = mxc_rnga_data_present,
+       .data_read = mxc_rnga_data_read
+};
+
+static int __init mxc_rnga_probe(struct platform_device *pdev)
+{
+       int err = -ENODEV;
+       struct clk *clk;
+       struct resource *res, *mem;
+       void __iomem *rng_base = NULL;
+
+       if (rng_dev)
+               return -EBUSY;
+
+       clk = clk_get(&pdev->dev, "rng");
+       if (IS_ERR(clk)) {
+               dev_err(&pdev->dev, "Could not get rng_clk!\n");
+               err = PTR_ERR(clk);
+               goto out;
+       }
+
+       clk_enable(clk);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               err = -ENOENT;
+               goto err_region;
+       }
+
+       mem = request_mem_region(res->start, resource_size(res), pdev->name);
+       if (mem == NULL) {
+               err = -EBUSY;
+               goto err_region;
+       }
+
+       rng_base = ioremap(res->start, resource_size(res));
+       if (!rng_base) {
+               err = -ENOMEM;
+               goto err_ioremap;
+       }
+
+       mxc_rnga.priv = (unsigned long)rng_base;
+
+       err = hwrng_register(&mxc_rnga);
+       if (err) {
+               dev_err(&pdev->dev, "MXC RNGA registering failed (%d)\n", err);
+               goto err_register;
+       }
+
+       rng_dev = pdev;
+
+       dev_info(&pdev->dev, "MXC RNGA Registered.\n");
+
+       return 0;
+
+err_register:
+       iounmap(rng_base);
+       rng_base = NULL;
+
+err_ioremap:
+       release_mem_region(res->start, resource_size(res));
+
+err_region:
+       clk_disable(clk);
+       clk_put(clk);
+
+out:
+       return err;
+}
+
+static int __exit mxc_rnga_remove(struct platform_device *pdev)
+{
+       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       void __iomem *rng_base = (void __iomem *)mxc_rnga.priv;
+       struct clk *clk = clk_get(&pdev->dev, "rng");
+
+       hwrng_unregister(&mxc_rnga);
+
+       iounmap(rng_base);
+
+       release_mem_region(res->start, resource_size(res));
+
+       clk_disable(clk);
+       clk_put(clk);
+
+       return 0;
+}
+
+static struct platform_driver mxc_rnga_driver = {
+       .driver = {
+                  .name = "mxc_rnga",
+                  .owner = THIS_MODULE,
+                  },
+       .remove = __exit_p(mxc_rnga_remove),
+};
+
+static int __init mod_init(void)
+{
+       return platform_driver_probe(&mxc_rnga_driver, mxc_rnga_probe);
+}
+
+static void __exit mod_exit(void)
+{
+       platform_driver_unregister(&mxc_rnga_driver);
+}
+
+module_init(mod_init);
+module_exit(mod_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("H/W RNGA driver for i.MX");
+MODULE_LICENSE("GPL");
index 538313f9e7ac6f8b45731b6ee49be2e8af0e0f8a..00dd3de1be51ef341c7c7a3819f0537d529a2ebd 100644 (file)
@@ -89,7 +89,7 @@ static struct hwrng omap_rng_ops = {
        .data_read      = omap_rng_data_read,
 };
 
-static int __init omap_rng_probe(struct platform_device *pdev)
+static int __devinit omap_rng_probe(struct platform_device *pdev)
 {
        struct resource *res, *mem;
        int ret;
index dcd352ad0e7f1e1378c654efd3266c56bf403604..a94e930575f273246adeeb644afe1577ea685079 100644 (file)
@@ -88,9 +88,9 @@ static struct hwrng timeriomem_rng_ops = {
        .priv           = 0,
 };
 
-static int __init timeriomem_rng_probe(struct platform_device *pdev)
+static int __devinit timeriomem_rng_probe(struct platform_device *pdev)
 {
-       struct resource *res, *mem;
+       struct resource *res;
        int ret;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -98,21 +98,12 @@ static int __init timeriomem_rng_probe(struct platform_device *pdev)
        if (!res)
                return -ENOENT;
 
-       mem = request_mem_region(res->start, res->end - res->start + 1,
-                                pdev->name);
-       if (mem == NULL)
-               return -EBUSY;
-
-       dev_set_drvdata(&pdev->dev, mem);
-
        timeriomem_rng_data = pdev->dev.platform_data;
 
        timeriomem_rng_data->address = ioremap(res->start,
                                                res->end - res->start + 1);
-       if (!timeriomem_rng_data->address) {
-               ret = -ENOMEM;
-               goto err_ioremap;
-       }
+       if (!timeriomem_rng_data->address)
+               return -EIO;
 
        if (timeriomem_rng_data->period != 0
                && usecs_to_jiffies(timeriomem_rng_data->period) > 0) {
@@ -125,7 +116,7 @@ static int __init timeriomem_rng_probe(struct platform_device *pdev)
 
        ret = hwrng_register(&timeriomem_rng_ops);
        if (ret)
-               goto err_register;
+               goto failed;
 
        dev_info(&pdev->dev, "32bits from 0x%p @ %dus\n",
                        timeriomem_rng_data->address,
@@ -133,24 +124,19 @@ static int __init timeriomem_rng_probe(struct platform_device *pdev)
 
        return 0;
 
-err_register:
+failed:
        dev_err(&pdev->dev, "problem registering\n");
        iounmap(timeriomem_rng_data->address);
-err_ioremap:
-       release_resource(mem);
 
        return ret;
 }
 
 static int __devexit timeriomem_rng_remove(struct platform_device *pdev)
 {
-       struct resource *mem = dev_get_drvdata(&pdev->dev);
-
        del_timer_sync(&timeriomem_rng_timer);
        hwrng_unregister(&timeriomem_rng_ops);
 
        iounmap(timeriomem_rng_data->address);
-       release_resource(mem);
 
        return 0;
 }
index 4e9573c1d39eabbd025c07a9b7a549e85080aaa8..794aacb715c1d85002808f6a7d194b012f85abaf 100644 (file)
@@ -132,6 +132,19 @@ static int via_rng_init(struct hwrng *rng)
        struct cpuinfo_x86 *c = &cpu_data(0);
        u32 lo, hi, old_lo;
 
+       /* VIA Nano CPUs don't have the MSR_VIA_RNG anymore.  The RNG
+        * is always enabled if CPUID rng_en is set.  There is no
+        * RNG configuration like it used to be the case in this
+        * register */
+       if ((c->x86 == 6) && (c->x86_model >= 0x0f)) {
+               if (!cpu_has_xstore_enabled) {
+                       printk(KERN_ERR PFX "can't enable hardware RNG "
+                               "if XSTORE is not enabled\n");
+                       return -ENODEV;
+               }
+               return 0;
+       }
+
        /* Control the RNG via MSR.  Tread lightly and pay very close
         * close attention to values written, as the reserved fields
         * are documented to be "undefined and unpredictable"; but it
@@ -205,5 +218,5 @@ static void __exit mod_exit(void)
 module_init(mod_init);
 module_exit(mod_exit);
 
-MODULE_DESCRIPTION("H/W RNG driver for VIA chipsets");
+MODULE_DESCRIPTION("H/W RNG driver for VIA CPU with PadLock");
 MODULE_LICENSE("GPL");
index 86e83f883139e154d8f8621b2aa6650468ed74d8..32216b623248497b1bade240792aa0e77a0c080e 100644 (file)
@@ -35,13 +35,13 @@ static DECLARE_COMPLETION(have_data);
 
 static void random_recv_done(struct virtqueue *vq)
 {
-       int len;
+       unsigned int len;
 
        /* We can get spurious callbacks, e.g. shared IRQs + virtio_pci. */
        if (!vq->vq_ops->get_buf(vq, &len))
                return;
 
-       data_left = len / sizeof(random_data[0]);
+       data_left += len;
        complete(&have_data);
 }
 
@@ -49,7 +49,7 @@ static void register_buffer(void)
 {
        struct scatterlist sg;
 
-       sg_init_one(&sg, random_data, RANDOM_DATA_SIZE);
+       sg_init_one(&sg, random_data+data_left, RANDOM_DATA_SIZE-data_left);
        /* There should always be room for one buffer. */
        if (vq->vq_ops->add_buf(vq, &sg, 0, 1, random_data) != 0)
                BUG();
@@ -59,24 +59,32 @@ static void register_buffer(void)
 /* At least we don't udelay() in a loop like some other drivers. */
 static int virtio_data_present(struct hwrng *rng, int wait)
 {
-       if (data_left)
+       if (data_left >= sizeof(u32))
                return 1;
 
+again:
        if (!wait)
                return 0;
 
        wait_for_completion(&have_data);
+
+       /* Not enough?  Re-register. */
+       if (unlikely(data_left < sizeof(u32))) {
+               register_buffer();
+               goto again;
+       }
+
        return 1;
 }
 
 /* virtio_data_present() must have succeeded before this is called. */
 static int virtio_data_read(struct hwrng *rng, u32 *data)
 {
-       BUG_ON(!data_left);
-
-       *data = random_data[--data_left];
+       BUG_ON(data_left < sizeof(u32));
+       data_left -= sizeof(u32);
+       *data = random_data[data_left / 4];
 
-       if (!data_left) {
+       if (data_left < sizeof(u32)) {
                init_completion(&have_data);
                register_buffer();
        }
@@ -94,13 +102,13 @@ static int virtrng_probe(struct virtio_device *vdev)
        int err;
 
        /* We expect a single virtqueue. */
-       vq = vdev->config->find_vq(vdev, 0, random_recv_done);
+       vq = virtio_find_single_vq(vdev, random_recv_done, "input");
        if (IS_ERR(vq))
                return PTR_ERR(vq);
 
        err = hwrng_register(&virtio_hwrng);
        if (err) {
-               vdev->config->del_vq(vq);
+               vdev->config->del_vqs(vdev);
                return err;
        }
 
@@ -112,7 +120,7 @@ static void virtrng_remove(struct virtio_device *vdev)
 {
        vdev->config->reset(vdev);
        hwrng_unregister(&virtio_hwrng);
-       vdev->config->del_vq(vq);
+       vdev->config->del_vqs(vdev);
 }
 
 static struct virtio_device_id id_table[] = {
index ff6f5a4b58fb5acd25622ad4fdd1b1a9c45b15f0..c74dacfa67950f870dcc4ffd7a71fa18dc915b27 100644 (file)
@@ -188,6 +188,9 @@ static void hvc_handle_input(struct virtqueue *vq)
  * Finally we put our input buffer in the input queue, ready to receive. */
 static int __devinit virtcons_probe(struct virtio_device *dev)
 {
+       vq_callback_t *callbacks[] = { hvc_handle_input, NULL};
+       const char *names[] = { "input", "output" };
+       struct virtqueue *vqs[2];
        int err;
 
        vdev = dev;
@@ -199,20 +202,15 @@ static int __devinit virtcons_probe(struct virtio_device *dev)
                goto fail;
        }
 
-       /* Find the input queue. */
+       /* Find the queues. */
        /* FIXME: This is why we want to wean off hvc: we do nothing
         * when input comes in. */
-       in_vq = vdev->config->find_vq(vdev, 0, hvc_handle_input);
-       if (IS_ERR(in_vq)) {
-               err = PTR_ERR(in_vq);
+       err = vdev->config->find_vqs(vdev, 2, vqs, callbacks, names);
+       if (err)
                goto free;
-       }
 
-       out_vq = vdev->config->find_vq(vdev, 1, NULL);
-       if (IS_ERR(out_vq)) {
-               err = PTR_ERR(out_vq);
-               goto free_in_vq;
-       }
+       in_vq = vqs[0];
+       out_vq = vqs[1];
 
        /* Start using the new console output. */
        virtio_cons.get_chars = get_chars;
@@ -233,17 +231,15 @@ static int __devinit virtcons_probe(struct virtio_device *dev)
        hvc = hvc_alloc(0, 0, &virtio_cons, PAGE_SIZE);
        if (IS_ERR(hvc)) {
                err = PTR_ERR(hvc);
-               goto free_out_vq;
+               goto free_vqs;
        }
 
        /* Register the input buffer the first time. */
        add_inbuf();
        return 0;
 
-free_out_vq:
-       vdev->config->del_vq(out_vq);
-free_in_vq:
-       vdev->config->del_vq(in_vq);
+free_vqs:
+       vdev->config->del_vqs(vdev);
 free:
        kfree(inbuf);
 fail:
index de9ebee8657b85ead0877f2f82037d80bcb0a0bc..c796a86ab7f36bbff85998425b31d78fb2417d32 100644 (file)
 #include <linux/io.h>
 #include <asm/system.h>
 #include <linux/uaccess.h>
-#include <linux/kmemleak.h>
 
 #define MAX_NR_CON_DRIVER 16
 
index 100bfd42206673e0345974a611f65b9f9b6c7352..6e6730f9dfd16cd068b77ed1359c16aff4bd017b 100644 (file)
@@ -7,7 +7,7 @@ menuconfig CONNECTOR
          of the netlink socket protocol.
 
          Connector support can also be built as a module.  If so, the module
-         will be called cn.ko.
+         will be called cn.
 
 if CONNECTOR
 
index 01afd758072f8242f550fc70b30b9c124aa8fa2b..5b27692372bf66d0e64f230174d5347599f6c34e 100644 (file)
@@ -12,7 +12,7 @@ if CRYPTO_HW
 
 config CRYPTO_DEV_PADLOCK
        tristate "Support for VIA PadLock ACE"
-       depends on X86_32 && !UML
+       depends on X86 && !UML
        select CRYPTO_ALGAPI
        help
          Some VIA processors come with an integrated crypto engine
@@ -34,7 +34,7 @@ config CRYPTO_DEV_PADLOCK_AES
          Available in VIA C3 and newer CPUs.
 
          If unsure say M. The compiled module will be
-         called padlock-aes.ko
+         called padlock-aes.
 
 config CRYPTO_DEV_PADLOCK_SHA
        tristate "PadLock driver for SHA1 and SHA256 algorithms"
@@ -47,7 +47,7 @@ config CRYPTO_DEV_PADLOCK_SHA
          Available in VIA C7 and newer processors.
 
          If unsure say M. The compiled module will be
-         called padlock-sha.ko
+         called padlock-sha.
 
 config CRYPTO_DEV_GEODE
        tristate "Support for the Geode LX AES engine"
@@ -79,7 +79,7 @@ config ZCRYPT_MONOLITHIC
        bool "Monolithic zcrypt module"
        depends on ZCRYPT="m"
        help
-         Select this option if you want to have a single module z90crypt.ko
+         Select this option if you want to have a single module z90crypt,
          that contains all parts of the crypto device driver (ap bus,
          request router and all the card drivers).
 
index 2bef086fb34268afaf0e65ec01e5017627142721..5f753fc087302801a16e3cc2f9002ed896854344 100644 (file)
@@ -2564,7 +2564,7 @@ static void hifn_tasklet_callback(unsigned long data)
                hifn_process_queue(dev);
 }
 
-static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+static int __devinit hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        int err, i;
        struct hifn_device *dev;
@@ -2696,7 +2696,7 @@ err_out_disable_pci_device:
        return err;
 }
 
-static void hifn_remove(struct pci_dev *pdev)
+static void __devexit hifn_remove(struct pci_dev *pdev)
 {
        int i;
        struct hifn_device *dev;
@@ -2744,7 +2744,7 @@ static struct pci_driver hifn_pci_driver = {
        .remove   = __devexit_p(hifn_remove),
 };
 
-static int __devinit hifn_init(void)
+static int __init hifn_init(void)
 {
        unsigned int freq;
        int err;
@@ -2789,7 +2789,7 @@ static int __devinit hifn_init(void)
        return 0;
 }
 
-static void __devexit hifn_fini(void)
+static void __exit hifn_fini(void)
 {
        pci_unregister_driver(&hifn_pci_driver);
 
index 856b3cc2558387b7b239923c37c54f9d47b250ff..87f92c39b5f001fc0fd18416026c05b2e708621b 100644 (file)
@@ -154,7 +154,11 @@ static inline void padlock_reset_key(struct cword *cword)
        int cpu = raw_smp_processor_id();
 
        if (cword != per_cpu(last_cword, cpu))
+#ifndef CONFIG_X86_64
                asm volatile ("pushfl; popfl");
+#else
+               asm volatile ("pushfq; popfq");
+#endif
 }
 
 static inline void padlock_store_cword(struct cword *cword)
@@ -208,10 +212,19 @@ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key,
 
        asm volatile ("test $1, %%cl;"
                      "je 1f;"
+#ifndef CONFIG_X86_64
                      "lea -1(%%ecx), %%eax;"
                      "mov $1, %%ecx;"
+#else
+                     "lea -1(%%rcx), %%rax;"
+                     "mov $1, %%rcx;"
+#endif
                      ".byte 0xf3,0x0f,0xa7,0xc8;"      /* rep xcryptecb */
+#ifndef CONFIG_X86_64
                      "mov %%eax, %%ecx;"
+#else
+                     "mov %%rax, %%rcx;"
+#endif
                      "1:"
                      ".byte 0xf3,0x0f,0xa7,0xc8"       /* rep xcryptecb */
                      : "+S"(input), "+D"(output)
index a3918c16b3dbb8650cef798fdfc173e4b66d5088..c70775fd3ce2266b3b2805b8c1cb440217a55b6f 100644 (file)
@@ -44,6 +44,8 @@
 #include <crypto/sha.h>
 #include <crypto/aead.h>
 #include <crypto/authenc.h>
+#include <crypto/skcipher.h>
+#include <crypto/scatterwalk.h>
 
 #include "talitos.h"
 
@@ -339,7 +341,8 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch)
                                status = error;
 
                dma_unmap_single(dev, request->dma_desc,
-                       sizeof(struct talitos_desc), DMA_BIDIRECTIONAL);
+                                sizeof(struct talitos_desc),
+                                DMA_BIDIRECTIONAL);
 
                /* copy entries so we can call callback outside lock */
                saved_req.desc = request->desc;
@@ -413,7 +416,8 @@ static struct talitos_desc *current_desc(struct device *dev, int ch)
 /*
  * user diagnostics; report root cause of error based on execution unit status
  */
-static void report_eu_error(struct device *dev, int ch, struct talitos_desc *desc)
+static void report_eu_error(struct device *dev, int ch,
+                           struct talitos_desc *desc)
 {
        struct talitos_private *priv = dev_get_drvdata(dev);
        int i;
@@ -684,8 +688,8 @@ struct talitos_ctx {
        unsigned int authsize;
 };
 
-static int aead_authenc_setauthsize(struct crypto_aead *authenc,
-                                                unsigned int authsize)
+static int aead_setauthsize(struct crypto_aead *authenc,
+                           unsigned int authsize)
 {
        struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
 
@@ -694,8 +698,8 @@ static int aead_authenc_setauthsize(struct crypto_aead *authenc,
        return 0;
 }
 
-static int aead_authenc_setkey(struct crypto_aead *authenc,
-                                           const u8 *key, unsigned int keylen)
+static int aead_setkey(struct crypto_aead *authenc,
+                      const u8 *key, unsigned int keylen)
 {
        struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
        struct rtattr *rta = (void *)key;
@@ -740,7 +744,7 @@ badkey:
 }
 
 /*
- * ipsec_esp_edesc - s/w-extended ipsec_esp descriptor
+ * talitos_edesc - s/w-extended descriptor
  * @src_nents: number of segments in input scatterlist
  * @dst_nents: number of segments in output scatterlist
  * @dma_len: length of dma mapped link_tbl space
@@ -752,17 +756,67 @@ badkey:
  * is greater than 1, an integrity check value is concatenated to the end
  * of link_tbl data
  */
-struct ipsec_esp_edesc {
+struct talitos_edesc {
        int src_nents;
        int dst_nents;
+       int src_is_chained;
+       int dst_is_chained;
        int dma_len;
        dma_addr_t dma_link_tbl;
        struct talitos_desc desc;
        struct talitos_ptr link_tbl[0];
 };
 
+static int talitos_map_sg(struct device *dev, struct scatterlist *sg,
+                         unsigned int nents, enum dma_data_direction dir,
+                         int chained)
+{
+       if (unlikely(chained))
+               while (sg) {
+                       dma_map_sg(dev, sg, 1, dir);
+                       sg = scatterwalk_sg_next(sg);
+               }
+       else
+               dma_map_sg(dev, sg, nents, dir);
+       return nents;
+}
+
+static void talitos_unmap_sg_chain(struct device *dev, struct scatterlist *sg,
+                                  enum dma_data_direction dir)
+{
+       while (sg) {
+               dma_unmap_sg(dev, sg, 1, dir);
+               sg = scatterwalk_sg_next(sg);
+       }
+}
+
+static void talitos_sg_unmap(struct device *dev,
+                            struct talitos_edesc *edesc,
+                            struct scatterlist *src,
+                            struct scatterlist *dst)
+{
+       unsigned int src_nents = edesc->src_nents ? : 1;
+       unsigned int dst_nents = edesc->dst_nents ? : 1;
+
+       if (src != dst) {
+               if (edesc->src_is_chained)
+                       talitos_unmap_sg_chain(dev, src, DMA_TO_DEVICE);
+               else
+                       dma_unmap_sg(dev, src, src_nents, DMA_TO_DEVICE);
+
+               if (edesc->dst_is_chained)
+                       talitos_unmap_sg_chain(dev, dst, DMA_FROM_DEVICE);
+               else
+                       dma_unmap_sg(dev, dst, dst_nents, DMA_FROM_DEVICE);
+       } else
+               if (edesc->src_is_chained)
+                       talitos_unmap_sg_chain(dev, src, DMA_BIDIRECTIONAL);
+               else
+                       dma_unmap_sg(dev, src, src_nents, DMA_BIDIRECTIONAL);
+}
+
 static void ipsec_esp_unmap(struct device *dev,
-                           struct ipsec_esp_edesc *edesc,
+                           struct talitos_edesc *edesc,
                            struct aead_request *areq)
 {
        unmap_single_talitos_ptr(dev, &edesc->desc.ptr[6], DMA_FROM_DEVICE);
@@ -772,15 +826,7 @@ static void ipsec_esp_unmap(struct device *dev,
 
        dma_unmap_sg(dev, areq->assoc, 1, DMA_TO_DEVICE);
 
-       if (areq->src != areq->dst) {
-               dma_unmap_sg(dev, areq->src, edesc->src_nents ? : 1,
-                            DMA_TO_DEVICE);
-               dma_unmap_sg(dev, areq->dst, edesc->dst_nents ? : 1,
-                            DMA_FROM_DEVICE);
-       } else {
-               dma_unmap_sg(dev, areq->src, edesc->src_nents ? : 1,
-                            DMA_BIDIRECTIONAL);
-       }
+       talitos_sg_unmap(dev, edesc, areq->src, areq->dst);
 
        if (edesc->dma_len)
                dma_unmap_single(dev, edesc->dma_link_tbl, edesc->dma_len,
@@ -795,13 +841,14 @@ static void ipsec_esp_encrypt_done(struct device *dev,
                                   int err)
 {
        struct aead_request *areq = context;
-       struct ipsec_esp_edesc *edesc =
-                container_of(desc, struct ipsec_esp_edesc, desc);
        struct crypto_aead *authenc = crypto_aead_reqtfm(areq);
        struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
+       struct talitos_edesc *edesc;
        struct scatterlist *sg;
        void *icvdata;
 
+       edesc = container_of(desc, struct talitos_edesc, desc);
+
        ipsec_esp_unmap(dev, edesc, areq);
 
        /* copy the generated ICV to dst */
@@ -819,17 +866,18 @@ static void ipsec_esp_encrypt_done(struct device *dev,
 }
 
 static void ipsec_esp_decrypt_swauth_done(struct device *dev,
-                                  struct talitos_desc *desc, void *context,
-                                  int err)
+                                         struct talitos_desc *desc,
+                                         void *context, int err)
 {
        struct aead_request *req = context;
-       struct ipsec_esp_edesc *edesc =
-                container_of(desc, struct ipsec_esp_edesc, desc);
        struct crypto_aead *authenc = crypto_aead_reqtfm(req);
        struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
+       struct talitos_edesc *edesc;
        struct scatterlist *sg;
        void *icvdata;
 
+       edesc = container_of(desc, struct talitos_edesc, desc);
+
        ipsec_esp_unmap(dev, edesc, req);
 
        if (!err) {
@@ -851,20 +899,20 @@ static void ipsec_esp_decrypt_swauth_done(struct device *dev,
 }
 
 static void ipsec_esp_decrypt_hwauth_done(struct device *dev,
-                                  struct talitos_desc *desc, void *context,
-                                  int err)
+                                         struct talitos_desc *desc,
+                                         void *context, int err)
 {
        struct aead_request *req = context;
-       struct ipsec_esp_edesc *edesc =
-                container_of(desc, struct ipsec_esp_edesc, desc);
+       struct talitos_edesc *edesc;
+
+       edesc = container_of(desc, struct talitos_edesc, desc);
 
        ipsec_esp_unmap(dev, edesc, req);
 
        /* check ICV auth status */
-       if (!err)
-               if ((desc->hdr_lo & DESC_HDR_LO_ICCR1_MASK) !=
-                   DESC_HDR_LO_ICCR1_PASS)
-                       err = -EBADMSG;
+       if (!err && ((desc->hdr_lo & DESC_HDR_LO_ICCR1_MASK) !=
+                    DESC_HDR_LO_ICCR1_PASS))
+               err = -EBADMSG;
 
        kfree(edesc);
 
@@ -886,7 +934,7 @@ static int sg_to_link_tbl(struct scatterlist *sg, int sg_count,
                link_tbl_ptr->j_extent = 0;
                link_tbl_ptr++;
                cryptlen -= sg_dma_len(sg);
-               sg = sg_next(sg);
+               sg = scatterwalk_sg_next(sg);
        }
 
        /* adjust (decrease) last one (or two) entry's len to cryptlen */
@@ -910,7 +958,7 @@ static int sg_to_link_tbl(struct scatterlist *sg, int sg_count,
 /*
  * fill in and submit ipsec_esp descriptor
  */
-static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq,
+static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
                     u8 *giv, u64 seq,
                     void (*callback) (struct device *dev,
                                       struct talitos_desc *desc,
@@ -952,32 +1000,31 @@ static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq,
        desc->ptr[4].len = cpu_to_be16(cryptlen);
        desc->ptr[4].j_extent = authsize;
 
-       if (areq->src == areq->dst)
-               sg_count = dma_map_sg(dev, areq->src, edesc->src_nents ? : 1,
-                                     DMA_BIDIRECTIONAL);
-       else
-               sg_count = dma_map_sg(dev, areq->src, edesc->src_nents ? : 1,
-                                     DMA_TO_DEVICE);
+       sg_count = talitos_map_sg(dev, areq->src, edesc->src_nents ? : 1,
+                                 (areq->src == areq->dst) ? DMA_BIDIRECTIONAL
+                                                          : DMA_TO_DEVICE,
+                                 edesc->src_is_chained);
 
        if (sg_count == 1) {
                desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->src));
        } else {
                sg_link_tbl_len = cryptlen;
 
-               if ((edesc->desc.hdr & DESC_HDR_MODE1_MDEU_CICV) &&
-                       (edesc->desc.hdr & DESC_HDR_MODE0_ENCRYPT) == 0) {
+               if (edesc->desc.hdr & DESC_HDR_MODE1_MDEU_CICV)
                        sg_link_tbl_len = cryptlen + authsize;
-               }
+
                sg_count = sg_to_link_tbl(areq->src, sg_count, sg_link_tbl_len,
                                          &edesc->link_tbl[0]);
                if (sg_count > 1) {
                        desc->ptr[4].j_extent |= DESC_PTR_LNKTBL_JUMP;
                        desc->ptr[4].ptr = cpu_to_be32(edesc->dma_link_tbl);
-                       dma_sync_single_for_device(ctx->dev, edesc->dma_link_tbl,
-                                                  edesc->dma_len, DMA_BIDIRECTIONAL);
+                       dma_sync_single_for_device(dev, edesc->dma_link_tbl,
+                                                  edesc->dma_len,
+                                                  DMA_BIDIRECTIONAL);
                } else {
                        /* Only one segment now, so no link tbl needed */
-                       desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->src));
+                       desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->
+                                                                     src));
                }
        }
 
@@ -985,10 +1032,11 @@ static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq,
        desc->ptr[5].len = cpu_to_be16(cryptlen);
        desc->ptr[5].j_extent = authsize;
 
-       if (areq->src != areq->dst) {
-               sg_count = dma_map_sg(dev, areq->dst, edesc->dst_nents ? : 1,
-                                     DMA_FROM_DEVICE);
-       }
+       if (areq->src != areq->dst)
+               sg_count = talitos_map_sg(dev, areq->dst,
+                                         edesc->dst_nents ? : 1,
+                                         DMA_FROM_DEVICE,
+                                         edesc->dst_is_chained);
 
        if (sg_count == 1) {
                desc->ptr[5].ptr = cpu_to_be32(sg_dma_address(areq->dst));
@@ -1033,49 +1081,55 @@ static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq,
        return ret;
 }
 
-
 /*
  * derive number of elements in scatterlist
  */
-static int sg_count(struct scatterlist *sg_list, int nbytes)
+static int sg_count(struct scatterlist *sg_list, int nbytes, int *chained)
 {
        struct scatterlist *sg = sg_list;
        int sg_nents = 0;
 
-       while (nbytes) {
+       *chained = 0;
+       while (nbytes > 0) {
                sg_nents++;
                nbytes -= sg->length;
-               sg = sg_next(sg);
+               if (!sg_is_last(sg) && (sg + 1)->length == 0)
+                       *chained = 1;
+               sg = scatterwalk_sg_next(sg);
        }
 
        return sg_nents;
 }
 
 /*
- * allocate and map the ipsec_esp extended descriptor
+ * allocate and map the extended descriptor
  */
-static struct ipsec_esp_edesc *ipsec_esp_edesc_alloc(struct aead_request *areq,
-                                                    int icv_stashing)
+static struct talitos_edesc *talitos_edesc_alloc(struct device *dev,
+                                                struct scatterlist *src,
+                                                struct scatterlist *dst,
+                                                unsigned int cryptlen,
+                                                unsigned int authsize,
+                                                int icv_stashing,
+                                                u32 cryptoflags)
 {
-       struct crypto_aead *authenc = crypto_aead_reqtfm(areq);
-       struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
-       struct ipsec_esp_edesc *edesc;
+       struct talitos_edesc *edesc;
        int src_nents, dst_nents, alloc_len, dma_len;
-       gfp_t flags = areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL :
+       int src_chained, dst_chained = 0;
+       gfp_t flags = cryptoflags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL :
                      GFP_ATOMIC;
 
-       if (areq->cryptlen + ctx->authsize > TALITOS_MAX_DATA_LEN) {
-               dev_err(ctx->dev, "cryptlen exceeds h/w max limit\n");
+       if (cryptlen + authsize > TALITOS_MAX_DATA_LEN) {
+               dev_err(dev, "length exceeds h/w max limit\n");
                return ERR_PTR(-EINVAL);
        }
 
-       src_nents = sg_count(areq->src, areq->cryptlen + ctx->authsize);
+       src_nents = sg_count(src, cryptlen + authsize, &src_chained);
        src_nents = (src_nents == 1) ? 0 : src_nents;
 
-       if (areq->dst == areq->src) {
+       if (dst == src) {
                dst_nents = src_nents;
        } else {
-               dst_nents = sg_count(areq->dst, areq->cryptlen + ctx->authsize);
+               dst_nents = sg_count(dst, cryptlen + authsize, &dst_chained);
                dst_nents = (dst_nents == 1) ? 0 : dst_nents;
        }
 
@@ -1084,39 +1138,52 @@ static struct ipsec_esp_edesc *ipsec_esp_edesc_alloc(struct aead_request *areq,
         * allowing for two separate entries for ICV and generated ICV (+ 2),
         * and the ICV data itself
         */
-       alloc_len = sizeof(struct ipsec_esp_edesc);
+       alloc_len = sizeof(struct talitos_edesc);
        if (src_nents || dst_nents) {
                dma_len = (src_nents + dst_nents + 2) *
-                                sizeof(struct talitos_ptr) + ctx->authsize;
+                                sizeof(struct talitos_ptr) + authsize;
                alloc_len += dma_len;
        } else {
                dma_len = 0;
-               alloc_len += icv_stashing ? ctx->authsize : 0;
+               alloc_len += icv_stashing ? authsize : 0;
        }
 
        edesc = kmalloc(alloc_len, GFP_DMA | flags);
        if (!edesc) {
-               dev_err(ctx->dev, "could not allocate edescriptor\n");
+               dev_err(dev, "could not allocate edescriptor\n");
                return ERR_PTR(-ENOMEM);
        }
 
        edesc->src_nents = src_nents;
        edesc->dst_nents = dst_nents;
+       edesc->src_is_chained = src_chained;
+       edesc->dst_is_chained = dst_chained;
        edesc->dma_len = dma_len;
-       edesc->dma_link_tbl = dma_map_single(ctx->dev, &edesc->link_tbl[0],
+       edesc->dma_link_tbl = dma_map_single(dev, &edesc->link_tbl[0],
                                             edesc->dma_len, DMA_BIDIRECTIONAL);
 
        return edesc;
 }
 
-static int aead_authenc_encrypt(struct aead_request *req)
+static struct talitos_edesc *aead_edesc_alloc(struct aead_request *areq,
+                                             int icv_stashing)
+{
+       struct crypto_aead *authenc = crypto_aead_reqtfm(areq);
+       struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
+
+       return talitos_edesc_alloc(ctx->dev, areq->src, areq->dst,
+                                  areq->cryptlen, ctx->authsize, icv_stashing,
+                                  areq->base.flags);
+}
+
+static int aead_encrypt(struct aead_request *req)
 {
        struct crypto_aead *authenc = crypto_aead_reqtfm(req);
        struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
-       struct ipsec_esp_edesc *edesc;
+       struct talitos_edesc *edesc;
 
        /* allocate extended descriptor */
-       edesc = ipsec_esp_edesc_alloc(req, 0);
+       edesc = aead_edesc_alloc(req, 0);
        if (IS_ERR(edesc))
                return PTR_ERR(edesc);
 
@@ -1126,70 +1193,67 @@ static int aead_authenc_encrypt(struct aead_request *req)
        return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_encrypt_done);
 }
 
-
-
-static int aead_authenc_decrypt(struct aead_request *req)
+static int aead_decrypt(struct aead_request *req)
 {
        struct crypto_aead *authenc = crypto_aead_reqtfm(req);
        struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
        unsigned int authsize = ctx->authsize;
        struct talitos_private *priv = dev_get_drvdata(ctx->dev);
-       struct ipsec_esp_edesc *edesc;
+       struct talitos_edesc *edesc;
        struct scatterlist *sg;
        void *icvdata;
 
        req->cryptlen -= authsize;
 
        /* allocate extended descriptor */
-       edesc = ipsec_esp_edesc_alloc(req, 1);
+       edesc = aead_edesc_alloc(req, 1);
        if (IS_ERR(edesc))
                return PTR_ERR(edesc);
 
        if ((priv->features & TALITOS_FTR_HW_AUTH_CHECK) &&
-           (((!edesc->src_nents && !edesc->dst_nents) ||
-               priv->features & TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT))) {
+           ((!edesc->src_nents && !edesc->dst_nents) ||
+            priv->features & TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT)) {
 
                /* decrypt and check the ICV */
-               edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND |
+               edesc->desc.hdr = ctx->desc_hdr_template |
+                                 DESC_HDR_DIR_INBOUND |
                                  DESC_HDR_MODE1_MDEU_CICV;
 
                /* reset integrity check result bits */
                edesc->desc.hdr_lo = 0;
 
-               return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_decrypt_hwauth_done);
+               return ipsec_esp(edesc, req, NULL, 0,
+                                ipsec_esp_decrypt_hwauth_done);
 
-       } else {
-
-               /* Have to check the ICV with software */
+       }
 
-               edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND;
+       /* Have to check the ICV with software */
+       edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND;
 
-               /* stash incoming ICV for later cmp with ICV generated by the h/w */
-               if (edesc->dma_len)
-                       icvdata = &edesc->link_tbl[edesc->src_nents +
-                                                  edesc->dst_nents + 2];
-               else
-                       icvdata = &edesc->link_tbl[0];
+       /* stash incoming ICV for later cmp with ICV generated by the h/w */
+       if (edesc->dma_len)
+               icvdata = &edesc->link_tbl[edesc->src_nents +
+                                          edesc->dst_nents + 2];
+       else
+               icvdata = &edesc->link_tbl[0];
 
-               sg = sg_last(req->src, edesc->src_nents ? : 1);
+       sg = sg_last(req->src, edesc->src_nents ? : 1);
 
-               memcpy(icvdata, (char *)sg_virt(sg) + sg->length - ctx->authsize,
-                      ctx->authsize);
+       memcpy(icvdata, (char *)sg_virt(sg) + sg->length - ctx->authsize,
+              ctx->authsize);
 
-               return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_decrypt_swauth_done);
-       }
+       return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_decrypt_swauth_done);
 }
 
-static int aead_authenc_givencrypt(
-       struct aead_givcrypt_request *req)
+static int aead_givencrypt(struct aead_givcrypt_request *req)
 {
        struct aead_request *areq = &req->areq;
        struct crypto_aead *authenc = crypto_aead_reqtfm(areq);
        struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
-       struct ipsec_esp_edesc *edesc;
+       struct talitos_edesc *edesc;
 
        /* allocate extended descriptor */
-       edesc = ipsec_esp_edesc_alloc(areq, 0);
+       edesc = aead_edesc_alloc(areq, 0);
        if (IS_ERR(edesc))
                return PTR_ERR(edesc);
 
@@ -1204,31 +1268,228 @@ static int aead_authenc_givencrypt(
                         ipsec_esp_encrypt_done);
 }
 
+static int ablkcipher_setkey(struct crypto_ablkcipher *cipher,
+                            const u8 *key, unsigned int keylen)
+{
+       struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+       struct ablkcipher_alg *alg = crypto_ablkcipher_alg(cipher);
+
+       if (keylen > TALITOS_MAX_KEY_SIZE)
+               goto badkey;
+
+       if (keylen < alg->min_keysize || keylen > alg->max_keysize)
+               goto badkey;
+
+       memcpy(&ctx->key, key, keylen);
+       ctx->keylen = keylen;
+
+       return 0;
+
+badkey:
+       crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
+       return -EINVAL;
+}
+
+static void common_nonsnoop_unmap(struct device *dev,
+                                 struct talitos_edesc *edesc,
+                                 struct ablkcipher_request *areq)
+{
+       unmap_single_talitos_ptr(dev, &edesc->desc.ptr[5], DMA_FROM_DEVICE);
+       unmap_single_talitos_ptr(dev, &edesc->desc.ptr[2], DMA_TO_DEVICE);
+       unmap_single_talitos_ptr(dev, &edesc->desc.ptr[1], DMA_TO_DEVICE);
+
+       talitos_sg_unmap(dev, edesc, areq->src, areq->dst);
+
+       if (edesc->dma_len)
+               dma_unmap_single(dev, edesc->dma_link_tbl, edesc->dma_len,
+                                DMA_BIDIRECTIONAL);
+}
+
+static void ablkcipher_done(struct device *dev,
+                           struct talitos_desc *desc, void *context,
+                           int err)
+{
+       struct ablkcipher_request *areq = context;
+       struct talitos_edesc *edesc;
+
+       edesc = container_of(desc, struct talitos_edesc, desc);
+
+       common_nonsnoop_unmap(dev, edesc, areq);
+
+       kfree(edesc);
+
+       areq->base.complete(&areq->base, err);
+}
+
+static int common_nonsnoop(struct talitos_edesc *edesc,
+                          struct ablkcipher_request *areq,
+                          u8 *giv,
+                          void (*callback) (struct device *dev,
+                                            struct talitos_desc *desc,
+                                            void *context, int error))
+{
+       struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+       struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+       struct device *dev = ctx->dev;
+       struct talitos_desc *desc = &edesc->desc;
+       unsigned int cryptlen = areq->nbytes;
+       unsigned int ivsize;
+       int sg_count, ret;
+
+       /* first DWORD empty */
+       desc->ptr[0].len = 0;
+       desc->ptr[0].ptr = 0;
+       desc->ptr[0].j_extent = 0;
+
+       /* cipher iv */
+       ivsize = crypto_ablkcipher_ivsize(cipher);
+       map_single_talitos_ptr(dev, &desc->ptr[1], ivsize, giv ?: areq->info, 0,
+                              DMA_TO_DEVICE);
+
+       /* cipher key */
+       map_single_talitos_ptr(dev, &desc->ptr[2], ctx->keylen,
+                              (char *)&ctx->key, 0, DMA_TO_DEVICE);
+
+       /*
+        * cipher in
+        */
+       desc->ptr[3].len = cpu_to_be16(cryptlen);
+       desc->ptr[3].j_extent = 0;
+
+       sg_count = talitos_map_sg(dev, areq->src, edesc->src_nents ? : 1,
+                                 (areq->src == areq->dst) ? DMA_BIDIRECTIONAL
+                                                          : DMA_TO_DEVICE,
+                                 edesc->src_is_chained);
+
+       if (sg_count == 1) {
+               desc->ptr[3].ptr = cpu_to_be32(sg_dma_address(areq->src));
+       } else {
+               sg_count = sg_to_link_tbl(areq->src, sg_count, cryptlen,
+                                         &edesc->link_tbl[0]);
+               if (sg_count > 1) {
+                       desc->ptr[3].j_extent |= DESC_PTR_LNKTBL_JUMP;
+                       desc->ptr[3].ptr = cpu_to_be32(edesc->dma_link_tbl);
+                       dma_sync_single_for_device(dev, edesc->dma_link_tbl,
+                                                  edesc->dma_len,
+                                                  DMA_BIDIRECTIONAL);
+               } else {
+                       /* Only one segment now, so no link tbl needed */
+                       desc->ptr[3].ptr = cpu_to_be32(sg_dma_address(areq->
+                                                                     src));
+               }
+       }
+
+       /* cipher out */
+       desc->ptr[4].len = cpu_to_be16(cryptlen);
+       desc->ptr[4].j_extent = 0;
+
+       if (areq->src != areq->dst)
+               sg_count = talitos_map_sg(dev, areq->dst,
+                                         edesc->dst_nents ? : 1,
+                                         DMA_FROM_DEVICE,
+                                         edesc->dst_is_chained);
+
+       if (sg_count == 1) {
+               desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->dst));
+       } else {
+               struct talitos_ptr *link_tbl_ptr =
+                       &edesc->link_tbl[edesc->src_nents + 1];
+
+               desc->ptr[4].j_extent |= DESC_PTR_LNKTBL_JUMP;
+               desc->ptr[4].ptr = cpu_to_be32((struct talitos_ptr *)
+                                              edesc->dma_link_tbl +
+                                              edesc->src_nents + 1);
+               sg_count = sg_to_link_tbl(areq->dst, sg_count, cryptlen,
+                                         link_tbl_ptr);
+               dma_sync_single_for_device(ctx->dev, edesc->dma_link_tbl,
+                                          edesc->dma_len, DMA_BIDIRECTIONAL);
+       }
+
+       /* iv out */
+       map_single_talitos_ptr(dev, &desc->ptr[5], ivsize, ctx->iv, 0,
+                              DMA_FROM_DEVICE);
+
+       /* last DWORD empty */
+       desc->ptr[6].len = 0;
+       desc->ptr[6].ptr = 0;
+       desc->ptr[6].j_extent = 0;
+
+       ret = talitos_submit(dev, desc, callback, areq);
+       if (ret != -EINPROGRESS) {
+               common_nonsnoop_unmap(dev, edesc, areq);
+               kfree(edesc);
+       }
+       return ret;
+}
+
+static struct talitos_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request *
+                                                   areq)
+{
+       struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+       struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+
+       return talitos_edesc_alloc(ctx->dev, areq->src, areq->dst, areq->nbytes,
+                                  0, 0, areq->base.flags);
+}
+
+static int ablkcipher_encrypt(struct ablkcipher_request *areq)
+{
+       struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+       struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+       struct talitos_edesc *edesc;
+
+       /* allocate extended descriptor */
+       edesc = ablkcipher_edesc_alloc(areq);
+       if (IS_ERR(edesc))
+               return PTR_ERR(edesc);
+
+       /* set encrypt */
+       edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_MODE0_ENCRYPT;
+
+       return common_nonsnoop(edesc, areq, NULL, ablkcipher_done);
+}
+
+static int ablkcipher_decrypt(struct ablkcipher_request *areq)
+{
+       struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+       struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+       struct talitos_edesc *edesc;
+
+       /* allocate extended descriptor */
+       edesc = ablkcipher_edesc_alloc(areq);
+       if (IS_ERR(edesc))
+               return PTR_ERR(edesc);
+
+       edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND;
+
+       return common_nonsnoop(edesc, areq, NULL, ablkcipher_done);
+}
+
 struct talitos_alg_template {
-       char name[CRYPTO_MAX_ALG_NAME];
-       char driver_name[CRYPTO_MAX_ALG_NAME];
-       unsigned int blocksize;
-       struct aead_alg aead;
-       struct device *dev;
+       struct crypto_alg alg;
        __be32 desc_hdr_template;
 };
 
 static struct talitos_alg_template driver_algs[] = {
-       /* single-pass ipsec_esp descriptor */
+       /* AEAD algorithms.  These use a single-pass ipsec_esp descriptor */
        {
-               .name = "authenc(hmac(sha1),cbc(aes))",
-               .driver_name = "authenc-hmac-sha1-cbc-aes-talitos",
-               .blocksize = AES_BLOCK_SIZE,
-               .aead = {
-                       .setkey = aead_authenc_setkey,
-                       .setauthsize = aead_authenc_setauthsize,
-                       .encrypt = aead_authenc_encrypt,
-                       .decrypt = aead_authenc_decrypt,
-                       .givencrypt = aead_authenc_givencrypt,
-                       .geniv = "<built-in>",
-                       .ivsize = AES_BLOCK_SIZE,
-                       .maxauthsize = SHA1_DIGEST_SIZE,
-                       },
+               .alg = {
+                       .cra_name = "authenc(hmac(sha1),cbc(aes))",
+                       .cra_driver_name = "authenc-hmac-sha1-cbc-aes-talitos",
+                       .cra_blocksize = AES_BLOCK_SIZE,
+                       .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
+                       .cra_type = &crypto_aead_type,
+                       .cra_aead = {
+                               .setkey = aead_setkey,
+                               .setauthsize = aead_setauthsize,
+                               .encrypt = aead_encrypt,
+                               .decrypt = aead_decrypt,
+                               .givencrypt = aead_givencrypt,
+                               .geniv = "<built-in>",
+                               .ivsize = AES_BLOCK_SIZE,
+                               .maxauthsize = SHA1_DIGEST_SIZE,
+                       }
+               },
                .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP |
                                     DESC_HDR_SEL0_AESU |
                                     DESC_HDR_MODE0_AESU_CBC |
@@ -1238,19 +1499,23 @@ static struct talitos_alg_template driver_algs[] = {
                                     DESC_HDR_MODE1_MDEU_SHA1_HMAC,
        },
        {
-               .name = "authenc(hmac(sha1),cbc(des3_ede))",
-               .driver_name = "authenc-hmac-sha1-cbc-3des-talitos",
-               .blocksize = DES3_EDE_BLOCK_SIZE,
-               .aead = {
-                       .setkey = aead_authenc_setkey,
-                       .setauthsize = aead_authenc_setauthsize,
-                       .encrypt = aead_authenc_encrypt,
-                       .decrypt = aead_authenc_decrypt,
-                       .givencrypt = aead_authenc_givencrypt,
-                       .geniv = "<built-in>",
-                       .ivsize = DES3_EDE_BLOCK_SIZE,
-                       .maxauthsize = SHA1_DIGEST_SIZE,
-                       },
+               .alg = {
+                       .cra_name = "authenc(hmac(sha1),cbc(des3_ede))",
+                       .cra_driver_name = "authenc-hmac-sha1-cbc-3des-talitos",
+                       .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+                       .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
+                       .cra_type = &crypto_aead_type,
+                       .cra_aead = {
+                               .setkey = aead_setkey,
+                               .setauthsize = aead_setauthsize,
+                               .encrypt = aead_encrypt,
+                               .decrypt = aead_decrypt,
+                               .givencrypt = aead_givencrypt,
+                               .geniv = "<built-in>",
+                               .ivsize = DES3_EDE_BLOCK_SIZE,
+                               .maxauthsize = SHA1_DIGEST_SIZE,
+                       }
+               },
                .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP |
                                     DESC_HDR_SEL0_DEU |
                                     DESC_HDR_MODE0_DEU_CBC |
@@ -1261,19 +1526,23 @@ static struct talitos_alg_template driver_algs[] = {
                                     DESC_HDR_MODE1_MDEU_SHA1_HMAC,
        },
        {
-               .name = "authenc(hmac(sha256),cbc(aes))",
-               .driver_name = "authenc-hmac-sha256-cbc-aes-talitos",
-               .blocksize = AES_BLOCK_SIZE,
-               .aead = {
-                       .setkey = aead_authenc_setkey,
-                       .setauthsize = aead_authenc_setauthsize,
-                       .encrypt = aead_authenc_encrypt,
-                       .decrypt = aead_authenc_decrypt,
-                       .givencrypt = aead_authenc_givencrypt,
-                       .geniv = "<built-in>",
-                       .ivsize = AES_BLOCK_SIZE,
-                       .maxauthsize = SHA256_DIGEST_SIZE,
-                       },
+               .alg = {
+                       .cra_name = "authenc(hmac(sha256),cbc(aes))",
+                       .cra_driver_name = "authenc-hmac-sha256-cbc-aes-talitos",
+                       .cra_blocksize = AES_BLOCK_SIZE,
+                       .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
+                       .cra_type = &crypto_aead_type,
+                       .cra_aead = {
+                               .setkey = aead_setkey,
+                               .setauthsize = aead_setauthsize,
+                               .encrypt = aead_encrypt,
+                               .decrypt = aead_decrypt,
+                               .givencrypt = aead_givencrypt,
+                               .geniv = "<built-in>",
+                               .ivsize = AES_BLOCK_SIZE,
+                               .maxauthsize = SHA256_DIGEST_SIZE,
+                       }
+               },
                .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP |
                                     DESC_HDR_SEL0_AESU |
                                     DESC_HDR_MODE0_AESU_CBC |
@@ -1283,19 +1552,23 @@ static struct talitos_alg_template driver_algs[] = {
                                     DESC_HDR_MODE1_MDEU_SHA256_HMAC,
        },
        {
-               .name = "authenc(hmac(sha256),cbc(des3_ede))",
-               .driver_name = "authenc-hmac-sha256-cbc-3des-talitos",
-               .blocksize = DES3_EDE_BLOCK_SIZE,
-               .aead = {
-                       .setkey = aead_authenc_setkey,
-                       .setauthsize = aead_authenc_setauthsize,
-                       .encrypt = aead_authenc_encrypt,
-                       .decrypt = aead_authenc_decrypt,
-                       .givencrypt = aead_authenc_givencrypt,
-                       .geniv = "<built-in>",
-                       .ivsize = DES3_EDE_BLOCK_SIZE,
-                       .maxauthsize = SHA256_DIGEST_SIZE,
-                       },
+               .alg = {
+                       .cra_name = "authenc(hmac(sha256),cbc(des3_ede))",
+                       .cra_driver_name = "authenc-hmac-sha256-cbc-3des-talitos",
+                       .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+                       .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
+                       .cra_type = &crypto_aead_type,
+                       .cra_aead = {
+                               .setkey = aead_setkey,
+                               .setauthsize = aead_setauthsize,
+                               .encrypt = aead_encrypt,
+                               .decrypt = aead_decrypt,
+                               .givencrypt = aead_givencrypt,
+                               .geniv = "<built-in>",
+                               .ivsize = DES3_EDE_BLOCK_SIZE,
+                               .maxauthsize = SHA256_DIGEST_SIZE,
+                       }
+               },
                .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP |
                                     DESC_HDR_SEL0_DEU |
                                     DESC_HDR_MODE0_DEU_CBC |
@@ -1306,19 +1579,23 @@ static struct talitos_alg_template driver_algs[] = {
                                     DESC_HDR_MODE1_MDEU_SHA256_HMAC,
        },
        {
-               .name = "authenc(hmac(md5),cbc(aes))",
-               .driver_name = "authenc-hmac-md5-cbc-aes-talitos",
-               .blocksize = AES_BLOCK_SIZE,
-               .aead = {
-                       .setkey = aead_authenc_setkey,
-                       .setauthsize = aead_authenc_setauthsize,
-                       .encrypt = aead_authenc_encrypt,
-                       .decrypt = aead_authenc_decrypt,
-                       .givencrypt = aead_authenc_givencrypt,
-                       .geniv = "<built-in>",
-                       .ivsize = AES_BLOCK_SIZE,
-                       .maxauthsize = MD5_DIGEST_SIZE,
-                       },
+               .alg = {
+                       .cra_name = "authenc(hmac(md5),cbc(aes))",
+                       .cra_driver_name = "authenc-hmac-md5-cbc-aes-talitos",
+                       .cra_blocksize = AES_BLOCK_SIZE,
+                       .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
+                       .cra_type = &crypto_aead_type,
+                       .cra_aead = {
+                               .setkey = aead_setkey,
+                               .setauthsize = aead_setauthsize,
+                               .encrypt = aead_encrypt,
+                               .decrypt = aead_decrypt,
+                               .givencrypt = aead_givencrypt,
+                               .geniv = "<built-in>",
+                               .ivsize = AES_BLOCK_SIZE,
+                               .maxauthsize = MD5_DIGEST_SIZE,
+                       }
+               },
                .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP |
                                     DESC_HDR_SEL0_AESU |
                                     DESC_HDR_MODE0_AESU_CBC |
@@ -1328,19 +1605,23 @@ static struct talitos_alg_template driver_algs[] = {
                                     DESC_HDR_MODE1_MDEU_MD5_HMAC,
        },
        {
-               .name = "authenc(hmac(md5),cbc(des3_ede))",
-               .driver_name = "authenc-hmac-md5-cbc-3des-talitos",
-               .blocksize = DES3_EDE_BLOCK_SIZE,
-               .aead = {
-                       .setkey = aead_authenc_setkey,
-                       .setauthsize = aead_authenc_setauthsize,
-                       .encrypt = aead_authenc_encrypt,
-                       .decrypt = aead_authenc_decrypt,
-                       .givencrypt = aead_authenc_givencrypt,
-                       .geniv = "<built-in>",
-                       .ivsize = DES3_EDE_BLOCK_SIZE,
-                       .maxauthsize = MD5_DIGEST_SIZE,
-                       },
+               .alg = {
+                       .cra_name = "authenc(hmac(md5),cbc(des3_ede))",
+                       .cra_driver_name = "authenc-hmac-md5-cbc-3des-talitos",
+                       .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+                       .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
+                       .cra_type = &crypto_aead_type,
+                       .cra_aead = {
+                               .setkey = aead_setkey,
+                               .setauthsize = aead_setauthsize,
+                               .encrypt = aead_encrypt,
+                               .decrypt = aead_decrypt,
+                               .givencrypt = aead_givencrypt,
+                               .geniv = "<built-in>",
+                               .ivsize = DES3_EDE_BLOCK_SIZE,
+                               .maxauthsize = MD5_DIGEST_SIZE,
+                       }
+               },
                .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP |
                                     DESC_HDR_SEL0_DEU |
                                     DESC_HDR_MODE0_DEU_CBC |
@@ -1349,6 +1630,52 @@ static struct talitos_alg_template driver_algs[] = {
                                     DESC_HDR_MODE1_MDEU_INIT |
                                     DESC_HDR_MODE1_MDEU_PAD |
                                     DESC_HDR_MODE1_MDEU_MD5_HMAC,
+       },
+       /* ABLKCIPHER algorithms. */
+       {
+               .alg = {
+                       .cra_name = "cbc(aes)",
+                       .cra_driver_name = "cbc-aes-talitos",
+                       .cra_blocksize = AES_BLOCK_SIZE,
+                       .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+                                     CRYPTO_ALG_ASYNC,
+                       .cra_type = &crypto_ablkcipher_type,
+                       .cra_ablkcipher = {
+                               .setkey = ablkcipher_setkey,
+                               .encrypt = ablkcipher_encrypt,
+                               .decrypt = ablkcipher_decrypt,
+                               .geniv = "eseqiv",
+                               .min_keysize = AES_MIN_KEY_SIZE,
+                               .max_keysize = AES_MAX_KEY_SIZE,
+                               .ivsize = AES_BLOCK_SIZE,
+                       }
+               },
+               .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
+                                    DESC_HDR_SEL0_AESU |
+                                    DESC_HDR_MODE0_AESU_CBC,
+       },
+       {
+               .alg = {
+                       .cra_name = "cbc(des3_ede)",
+                       .cra_driver_name = "cbc-3des-talitos",
+                       .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+                       .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+                                     CRYPTO_ALG_ASYNC,
+                       .cra_type = &crypto_ablkcipher_type,
+                       .cra_ablkcipher = {
+                               .setkey = ablkcipher_setkey,
+                               .encrypt = ablkcipher_encrypt,
+                               .decrypt = ablkcipher_decrypt,
+                               .geniv = "eseqiv",
+                               .min_keysize = DES3_EDE_KEY_SIZE,
+                               .max_keysize = DES3_EDE_KEY_SIZE,
+                               .ivsize = DES3_EDE_BLOCK_SIZE,
+                       }
+               },
+               .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
+                                    DESC_HDR_SEL0_DEU |
+                                    DESC_HDR_MODE0_DEU_CBC |
+                                    DESC_HDR_MODE0_DEU_3DES,
        }
 };
 
@@ -1362,12 +1689,14 @@ struct talitos_crypto_alg {
 static int talitos_cra_init(struct crypto_tfm *tfm)
 {
        struct crypto_alg *alg = tfm->__crt_alg;
-       struct talitos_crypto_alg *talitos_alg =
-                container_of(alg, struct talitos_crypto_alg, crypto_alg);
+       struct talitos_crypto_alg *talitos_alg;
        struct talitos_ctx *ctx = crypto_tfm_ctx(tfm);
 
+       talitos_alg =  container_of(alg, struct talitos_crypto_alg, crypto_alg);
+
        /* update context with ptr to dev */
        ctx->dev = talitos_alg->dev;
+
        /* copy descriptor header template value */
        ctx->desc_hdr_template = talitos_alg->desc_hdr_template;
 
@@ -1453,19 +1782,13 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev,
                return ERR_PTR(-ENOMEM);
 
        alg = &t_alg->crypto_alg;
+       *alg = template->alg;
 
-       snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", template->name);
-       snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
-                template->driver_name);
        alg->cra_module = THIS_MODULE;
        alg->cra_init = talitos_cra_init;
        alg->cra_priority = TALITOS_CRA_PRIORITY;
-       alg->cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC;
-       alg->cra_blocksize = template->blocksize;
        alg->cra_alignmask = 0;
-       alg->cra_type = &crypto_aead_type;
        alg->cra_ctxsize = sizeof(struct talitos_ctx);
-       alg->cra_u.aead = template->aead;
 
        t_alg->desc_hdr_template = template->desc_hdr_template;
        t_alg->dev = dev;
index facfdb1fa71c5ece5c6f7d7f14acf17227ffefd1..d205d493a68aa60f5256918ca91b1e43badcf65e 100644 (file)
@@ -1084,7 +1084,7 @@ static void e752x_init_sysbus_parity_mask(struct e752x_pvt *pvt)
        struct pci_dev *dev = pvt->dev_d0f1;
        int enable = 1;
 
-       /* Allow module paramter override, else see if CPU supports parity */
+       /* Allow module parameter override, else see if CPU supports parity */
        if (sysbus_parity != -1) {
                enable = sysbus_parity;
        } else if (cpu_id[0] &&
index edb02530e461af4f91e442cdd581f91aa934c588..11f373971fa5fe8cbedee6a5fce9a29bb4d02a83 100644 (file)
@@ -69,7 +69,7 @@ comment "Memory mapped GPIO expanders:"
 
 config GPIO_XILINX
        bool "Xilinx GPIO support"
-       depends on PPC_OF
+       depends on PPC_OF || MICROBLAZE
        help
          Say yes here to support the Xilinx FPGA GPIO device
 
index 0411d912d82abb9a82b812eb5e1639029659c60a..80a257554b307a4bc0346e5f38e3c154ec22f4c5 100644 (file)
@@ -371,7 +371,8 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
        list->user_token = list->hash.key << PAGE_SHIFT;
        mutex_unlock(&dev->struct_mutex);
 
-       list->master = dev->primary->master;
+       if (!(map->flags & _DRM_DRIVER))
+               list->master = dev->primary->master;
        *maplist = list;
        return 0;
        }
index 6f6b26479d82281e98ff1f9998d5f472e6938201..801a0d0e08103095dec0861a7fe9967d3759a3f2 100644 (file)
@@ -589,85 +589,13 @@ int drm_do_probe_ddc_edid(struct i2c_adapter *adapter,
 }
 EXPORT_SYMBOL(drm_do_probe_ddc_edid);
 
-/**
- * Get EDID information.
- *
- * \param adapter : i2c device adaptor.
- * \param buf     : EDID data buffer to be filled
- * \param len     : EDID data buffer length
- * \return 0 on success or -1 on failure.
- *
- * Initialize DDC, then fetch EDID information
- * by calling drm_do_probe_ddc_edid function.
- */
-static int drm_ddc_read(struct i2c_adapter *adapter,
-                       unsigned char *buf, int len)
-{
-       struct i2c_algo_bit_data *algo_data = adapter->algo_data;
-       int i, j;
-       int ret = -1;
-
-       algo_data->setscl(algo_data->data, 1);
-
-       for (i = 0; i < 1; i++) {
-               /* For some old monitors we need the
-                * following process to initialize/stop DDC
-                */
-               algo_data->setsda(algo_data->data, 1);
-               msleep(13);
-
-               algo_data->setscl(algo_data->data, 1);
-               for (j = 0; j < 5; j++) {
-                       msleep(10);
-                       if (algo_data->getscl(algo_data->data))
-                               break;
-               }
-               if (j == 5)
-                       continue;
-
-               algo_data->setsda(algo_data->data, 0);
-               msleep(15);
-               algo_data->setscl(algo_data->data, 0);
-               msleep(15);
-               algo_data->setsda(algo_data->data, 1);
-               msleep(15);
-
-               /* Do the real work */
-               ret = drm_do_probe_ddc_edid(adapter, buf, len);
-               algo_data->setsda(algo_data->data, 0);
-               algo_data->setscl(algo_data->data, 0);
-               msleep(15);
-
-               algo_data->setscl(algo_data->data, 1);
-               for (j = 0; j < 10; j++) {
-                       msleep(10);
-                       if (algo_data->getscl(algo_data->data))
-                               break;
-               }
-
-               algo_data->setsda(algo_data->data, 1);
-               msleep(15);
-               algo_data->setscl(algo_data->data, 0);
-               algo_data->setsda(algo_data->data, 0);
-               if (ret == 0)
-                       break;
-       }
-       /* Release the DDC lines when done or the Apple Cinema HD display
-        * will switch off
-        */
-       algo_data->setsda(algo_data->data, 1);
-       algo_data->setscl(algo_data->data, 1);
-
-       return ret;
-}
-
 static int drm_ddc_read_edid(struct drm_connector *connector,
                             struct i2c_adapter *adapter,
                             char *buf, int len)
 {
        int ret;
 
-       ret = drm_ddc_read(adapter, buf, len);
+       ret = drm_do_probe_ddc_edid(adapter, buf, len);
        if (ret != 0) {
                dev_info(&connector->dev->pdev->dev, "%s: no EDID data\n",
                         drm_get_connector_name(connector));
index 4984aa89cf3ddb5e805f3f2f0a6f628d211ea895..ec43005100d978877167721b081d4c985f2dabdf 100644 (file)
@@ -133,7 +133,7 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size)
 
        BUG_ON((size & (PAGE_SIZE - 1)) != 0);
 
-       obj = kcalloc(1, sizeof(*obj), GFP_KERNEL);
+       obj = kzalloc(sizeof(*obj), GFP_KERNEL);
 
        obj->dev = dev;
        obj->filp = shmem_file_setup("drm mm object", size, VM_NORESERVE);
index af539f7d87dd2639bafe0c1576e069d4c971da1e..ac35145c3e20b279e7b17c1bdf40e9f442fc4fe1 100644 (file)
@@ -62,6 +62,7 @@ int drm_ht_create(struct drm_open_hash *ht, unsigned int order)
        }
        return 0;
 }
+EXPORT_SYMBOL(drm_ht_create);
 
 void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key)
 {
@@ -156,6 +157,7 @@ int drm_ht_just_insert_please(struct drm_open_hash *ht, struct drm_hash_item *it
        }
        return 0;
 }
+EXPORT_SYMBOL(drm_ht_just_insert_please);
 
 int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key,
                     struct drm_hash_item **item)
@@ -169,6 +171,7 @@ int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key,
        *item = hlist_entry(list, struct drm_hash_item, head);
        return 0;
 }
+EXPORT_SYMBOL(drm_ht_find_item);
 
 int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key)
 {
@@ -202,3 +205,4 @@ void drm_ht_remove(struct drm_open_hash *ht)
                ht->table = NULL;
        }
 }
+EXPORT_SYMBOL(drm_ht_remove);
index 367c590ffbba2d83b5f516d76cb6efacdd1baff1..7819fd930a515ce8840c2b7f0b11c9e33cc08b0c 100644 (file)
  */
 
 #include "drmP.h"
+#include "drm_mm.h"
 #include <linux/slab.h>
 
+#define MM_UNUSED_TARGET 4
+
 unsigned long drm_mm_tail_space(struct drm_mm *mm)
 {
        struct list_head *tail_node;
@@ -74,16 +77,62 @@ int drm_mm_remove_space_from_tail(struct drm_mm *mm, unsigned long size)
        return 0;
 }
 
+static struct drm_mm_node *drm_mm_kmalloc(struct drm_mm *mm, int atomic)
+{
+       struct drm_mm_node *child;
+
+       if (atomic)
+               child = kmalloc(sizeof(*child), GFP_ATOMIC);
+       else
+               child = kmalloc(sizeof(*child), GFP_KERNEL);
+
+       if (unlikely(child == NULL)) {
+               spin_lock(&mm->unused_lock);
+               if (list_empty(&mm->unused_nodes))
+                       child = NULL;
+               else {
+                       child =
+                           list_entry(mm->unused_nodes.next,
+                                      struct drm_mm_node, fl_entry);
+                       list_del(&child->fl_entry);
+                       --mm->num_unused;
+               }
+               spin_unlock(&mm->unused_lock);
+       }
+       return child;
+}
+
+int drm_mm_pre_get(struct drm_mm *mm)
+{
+       struct drm_mm_node *node;
+
+       spin_lock(&mm->unused_lock);
+       while (mm->num_unused < MM_UNUSED_TARGET) {
+               spin_unlock(&mm->unused_lock);
+               node = kmalloc(sizeof(*node), GFP_KERNEL);
+               spin_lock(&mm->unused_lock);
+
+               if (unlikely(node == NULL)) {
+                       int ret = (mm->num_unused < 2) ? -ENOMEM : 0;
+                       spin_unlock(&mm->unused_lock);
+                       return ret;
+               }
+               ++mm->num_unused;
+               list_add_tail(&node->fl_entry, &mm->unused_nodes);
+       }
+       spin_unlock(&mm->unused_lock);
+       return 0;
+}
+EXPORT_SYMBOL(drm_mm_pre_get);
 
 static int drm_mm_create_tail_node(struct drm_mm *mm,
-                           unsigned long start,
-                           unsigned long size)
+                                  unsigned long start,
+                                  unsigned long size, int atomic)
 {
        struct drm_mm_node *child;
 
-       child = (struct drm_mm_node *)
-               drm_alloc(sizeof(*child), DRM_MEM_MM);
-       if (!child)
+       child = drm_mm_kmalloc(mm, atomic);
+       if (unlikely(child == NULL))
                return -ENOMEM;
 
        child->free = 1;
@@ -97,8 +146,7 @@ static int drm_mm_create_tail_node(struct drm_mm *mm,
        return 0;
 }
 
-
-int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size)
+int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size, int atomic)
 {
        struct list_head *tail_node;
        struct drm_mm_node *entry;
@@ -106,20 +154,21 @@ int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size)
        tail_node = mm->ml_entry.prev;
        entry = list_entry(tail_node, struct drm_mm_node, ml_entry);
        if (!entry->free) {
-               return drm_mm_create_tail_node(mm, entry->start + entry->size, size);
+               return drm_mm_create_tail_node(mm, entry->start + entry->size,
+                                              size, atomic);
        }
        entry->size += size;
        return 0;
 }
 
 static struct drm_mm_node *drm_mm_split_at_start(struct drm_mm_node *parent,
-                                           unsigned long size)
+                                                unsigned long size,
+                                                int atomic)
 {
        struct drm_mm_node *child;
 
-       child = (struct drm_mm_node *)
-               drm_alloc(sizeof(*child), DRM_MEM_MM);
-       if (!child)
+       child = drm_mm_kmalloc(parent->mm, atomic);
+       if (unlikely(child == NULL))
                return NULL;
 
        INIT_LIST_HEAD(&child->fl_entry);
@@ -151,8 +200,9 @@ struct drm_mm_node *drm_mm_get_block(struct drm_mm_node * parent,
                tmp = parent->start % alignment;
 
        if (tmp) {
-               align_splitoff = drm_mm_split_at_start(parent, alignment - tmp);
-               if (!align_splitoff)
+               align_splitoff =
+                   drm_mm_split_at_start(parent, alignment - tmp, 0);
+               if (unlikely(align_splitoff == NULL))
                        return NULL;
        }
 
@@ -161,7 +211,7 @@ struct drm_mm_node *drm_mm_get_block(struct drm_mm_node * parent,
                parent->free = 0;
                return parent;
        } else {
-               child = drm_mm_split_at_start(parent, size);
+               child = drm_mm_split_at_start(parent, size, 0);
        }
 
        if (align_splitoff)
@@ -169,14 +219,49 @@ struct drm_mm_node *drm_mm_get_block(struct drm_mm_node * parent,
 
        return child;
 }
+
 EXPORT_SYMBOL(drm_mm_get_block);
 
+struct drm_mm_node *drm_mm_get_block_atomic(struct drm_mm_node *parent,
+                                           unsigned long size,
+                                           unsigned alignment)
+{
+
+       struct drm_mm_node *align_splitoff = NULL;
+       struct drm_mm_node *child;
+       unsigned tmp = 0;
+
+       if (alignment)
+               tmp = parent->start % alignment;
+
+       if (tmp) {
+               align_splitoff =
+                   drm_mm_split_at_start(parent, alignment - tmp, 1);
+               if (unlikely(align_splitoff == NULL))
+                       return NULL;
+       }
+
+       if (parent->size == size) {
+               list_del_init(&parent->fl_entry);
+               parent->free = 0;
+               return parent;
+       } else {
+               child = drm_mm_split_at_start(parent, size, 1);
+       }
+
+       if (align_splitoff)
+               drm_mm_put_block(align_splitoff);
+
+       return child;
+}
+EXPORT_SYMBOL(drm_mm_get_block_atomic);
+
 /*
  * Put a block. Merge with the previous and / or next block if they are free.
  * Otherwise add to the free stack.
  */
 
-void drm_mm_put_block(struct drm_mm_node * cur)
+void drm_mm_put_block(struct drm_mm_node *cur)
 {
 
        struct drm_mm *mm = cur->mm;
@@ -188,21 +273,27 @@ void drm_mm_put_block(struct drm_mm_node * cur)
        int merged = 0;
 
        if (cur_head->prev != root_head) {
-               prev_node = list_entry(cur_head->prev, struct drm_mm_node, ml_entry);
+               prev_node =
+                   list_entry(cur_head->prev, struct drm_mm_node, ml_entry);
                if (prev_node->free) {
                        prev_node->size += cur->size;
                        merged = 1;
                }
        }
        if (cur_head->next != root_head) {
-               next_node = list_entry(cur_head->next, struct drm_mm_node, ml_entry);
+               next_node =
+                   list_entry(cur_head->next, struct drm_mm_node, ml_entry);
                if (next_node->free) {
                        if (merged) {
                                prev_node->size += next_node->size;
                                list_del(&next_node->ml_entry);
                                list_del(&next_node->fl_entry);
-                               drm_free(next_node, sizeof(*next_node),
-                                        DRM_MEM_MM);
+                               if (mm->num_unused < MM_UNUSED_TARGET) {
+                                       list_add(&next_node->fl_entry,
+                                                &mm->unused_nodes);
+                                       ++mm->num_unused;
+                               } else
+                                       kfree(next_node);
                        } else {
                                next_node->size += cur->size;
                                next_node->start = cur->start;
@@ -215,14 +306,19 @@ void drm_mm_put_block(struct drm_mm_node * cur)
                list_add(&cur->fl_entry, &mm->fl_entry);
        } else {
                list_del(&cur->ml_entry);
-               drm_free(cur, sizeof(*cur), DRM_MEM_MM);
+               if (mm->num_unused < MM_UNUSED_TARGET) {
+                       list_add(&cur->fl_entry, &mm->unused_nodes);
+                       ++mm->num_unused;
+               } else
+                       kfree(cur);
        }
 }
+
 EXPORT_SYMBOL(drm_mm_put_block);
 
-struct drm_mm_node *drm_mm_search_free(const struct drm_mm * mm,
-                                 unsigned long size,
-                                 unsigned alignment, int best_match)
+struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm,
+                                      unsigned long size,
+                                      unsigned alignment, int best_match)
 {
        struct list_head *list;
        const struct list_head *free_stack = &mm->fl_entry;
@@ -247,7 +343,6 @@ struct drm_mm_node *drm_mm_search_free(const struct drm_mm * mm,
                                wasted += alignment - tmp;
                }
 
-
                if (entry->size >= size + wasted) {
                        if (!best_match)
                                return entry;
@@ -260,6 +355,7 @@ struct drm_mm_node *drm_mm_search_free(const struct drm_mm * mm,
 
        return best;
 }
+EXPORT_SYMBOL(drm_mm_search_free);
 
 int drm_mm_clean(struct drm_mm * mm)
 {
@@ -267,14 +363,17 @@ int drm_mm_clean(struct drm_mm * mm)
 
        return (head->next->next == head);
 }
-EXPORT_SYMBOL(drm_mm_search_free);
+EXPORT_SYMBOL(drm_mm_clean);
 
 int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
 {
        INIT_LIST_HEAD(&mm->ml_entry);
        INIT_LIST_HEAD(&mm->fl_entry);
+       INIT_LIST_HEAD(&mm->unused_nodes);
+       mm->num_unused = 0;
+       spin_lock_init(&mm->unused_lock);
 
-       return drm_mm_create_tail_node(mm, start, size);
+       return drm_mm_create_tail_node(mm, start, size, 0);
 }
 EXPORT_SYMBOL(drm_mm_init);
 
@@ -282,6 +381,7 @@ void drm_mm_takedown(struct drm_mm * mm)
 {
        struct list_head *bnode = mm->fl_entry.next;
        struct drm_mm_node *entry;
+       struct drm_mm_node *next;
 
        entry = list_entry(bnode, struct drm_mm_node, fl_entry);
 
@@ -293,7 +393,16 @@ void drm_mm_takedown(struct drm_mm * mm)
 
        list_del(&entry->fl_entry);
        list_del(&entry->ml_entry);
+       kfree(entry);
+
+       spin_lock(&mm->unused_lock);
+       list_for_each_entry_safe(entry, next, &mm->unused_nodes, fl_entry) {
+               list_del(&entry->fl_entry);
+               kfree(entry);
+               --mm->num_unused;
+       }
+       spin_unlock(&mm->unused_lock);
 
-       drm_free(entry, sizeof(*entry), DRM_MEM_MM);
+       BUG_ON(mm->num_unused != 0);
 }
 EXPORT_SYMBOL(drm_mm_takedown);
index c9b80fdd4630a386f5acda7c35a4610f6c13c9f3..54f492a488a93c68387bc388a6579c92edb7f988 100644 (file)
@@ -38,6 +38,7 @@
 #include "drm.h"
 #include "drm_crtc.h"
 
+#define DRM_MODESET_DEBUG      "drm_mode"
 /**
  * drm_mode_debug_printmodeline - debug print a mode
  * @dev: DRM device
  */
 void drm_mode_debug_printmodeline(struct drm_display_mode *mode)
 {
-       DRM_DEBUG("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
-                 mode->base.id, mode->name, mode->vrefresh, mode->clock,
-                 mode->hdisplay, mode->hsync_start,
-                 mode->hsync_end, mode->htotal,
-                 mode->vdisplay, mode->vsync_start,
-                 mode->vsync_end, mode->vtotal, mode->type, mode->flags);
+       DRM_DEBUG_MODE(DRM_MODESET_DEBUG,
+               "Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
+               mode->base.id, mode->name, mode->vrefresh, mode->clock,
+               mode->hdisplay, mode->hsync_start,
+               mode->hsync_end, mode->htotal,
+               mode->vdisplay, mode->vsync_start,
+               mode->vsync_end, mode->vtotal, mode->type, mode->flags);
 }
 EXPORT_SYMBOL(drm_mode_debug_printmodeline);
 
@@ -401,7 +403,9 @@ void drm_mode_prune_invalid(struct drm_device *dev,
                        list_del(&mode->head);
                        if (verbose) {
                                drm_mode_debug_printmodeline(mode);
-                               DRM_DEBUG("Not using %s mode %d\n", mode->name, mode->status);
+                               DRM_DEBUG_MODE(DRM_MODESET_DEBUG,
+                                       "Not using %s mode %d\n",
+                                       mode->name, mode->status);
                        }
                        drm_mode_destroy(dev, mode);
                }
index b9631e3a1ea69f421177cfead3e1c2ce3be9993b..89050684fe0d2c7b33a2fdf0a31287c5955e5778 100644 (file)
@@ -51,7 +51,22 @@ struct idr drm_minors_idr;
 struct class *drm_class;
 struct proc_dir_entry *drm_proc_root;
 struct dentry *drm_debugfs_root;
-
+void drm_ut_debug_printk(unsigned int request_level,
+                        const char *prefix,
+                        const char *function_name,
+                        const char *format, ...)
+{
+       va_list args;
+
+       if (drm_debug & request_level) {
+               if (function_name)
+                       printk(KERN_DEBUG "[%s:%s], ", prefix, function_name);
+               va_start(args, format);
+               vprintk(format, args);
+               va_end(args);
+       }
+}
+EXPORT_SYMBOL(drm_ut_debug_printk);
 static int drm_minor_get_id(struct drm_device *dev, int type)
 {
        int new_id;
index 0ccb63ee50ee5fea5b2232e6b3b481c108d56f03..1a60626f6803733d656f7bb6dcb8b7c8a33e697c 100644 (file)
@@ -33,6 +33,8 @@
 #include "i915_drm.h"
 #include "i915_drv.h"
 
+#define I915_DRV       "i915_drv"
+
 /* Really want an OS-independent resettable timer.  Would like to have
  * this loop run for (eg) 3 sec, but have the timer reset every time
  * the head pointer changes, so that EBUSY only happens if the ring
@@ -99,7 +101,7 @@ static int i915_init_phys_hws(struct drm_device *dev)
        memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
 
        I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
-       DRM_DEBUG("Enabled hardware status page\n");
+       DRM_DEBUG_DRIVER(I915_DRV, "Enabled hardware status page\n");
        return 0;
 }
 
@@ -185,7 +187,8 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
                master_priv->sarea_priv = (drm_i915_sarea_t *)
                        ((u8 *)master_priv->sarea->handle + init->sarea_priv_offset);
        } else {
-               DRM_DEBUG("sarea not found assuming DRI2 userspace\n");
+               DRM_DEBUG_DRIVER(I915_DRV,
+                               "sarea not found assuming DRI2 userspace\n");
        }
 
        if (init->ring_size != 0) {
@@ -235,7 +238,7 @@ static int i915_dma_resume(struct drm_device * dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 
-       DRM_DEBUG("%s\n", __func__);
+       DRM_DEBUG_DRIVER(I915_DRV, "%s\n", __func__);
 
        if (dev_priv->ring.map.handle == NULL) {
                DRM_ERROR("can not ioremap virtual address for"
@@ -248,13 +251,14 @@ static int i915_dma_resume(struct drm_device * dev)
                DRM_ERROR("Can not find hardware status page\n");
                return -EINVAL;
        }
-       DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
+       DRM_DEBUG_DRIVER(I915_DRV, "hw status page @ %p\n",
+                               dev_priv->hw_status_page);
 
        if (dev_priv->status_gfx_addr != 0)
                I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
        else
                I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
-       DRM_DEBUG("Enabled hardware status page\n");
+       DRM_DEBUG_DRIVER(I915_DRV, "Enabled hardware status page\n");
 
        return 0;
 }
@@ -548,10 +552,10 @@ static int i915_dispatch_flip(struct drm_device * dev)
        if (!master_priv->sarea_priv)
                return -EINVAL;
 
-       DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
-                 __func__,
-                 dev_priv->current_page,
-                 master_priv->sarea_priv->pf_current_page);
+       DRM_DEBUG_DRIVER(I915_DRV, "%s: page=%d pfCurrentPage=%d\n",
+                         __func__,
+                        dev_priv->current_page,
+                        master_priv->sarea_priv->pf_current_page);
 
        i915_kernel_lost_context(dev);
 
@@ -629,8 +633,9 @@ static int i915_batchbuffer(struct drm_device *dev, void *data,
                return -EINVAL;
        }
 
-       DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d\n",
-                 batch->start, batch->used, batch->num_cliprects);
+       DRM_DEBUG_DRIVER(I915_DRV,
+                       "i915 batchbuffer, start %x used %d cliprects %d\n",
+                       batch->start, batch->used, batch->num_cliprects);
 
        RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
 
@@ -678,8 +683,9 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
        void *batch_data;
        int ret;
 
-       DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n",
-                 cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects);
+       DRM_DEBUG_DRIVER(I915_DRV,
+                       "i915 cmdbuffer, buf %p sz %d cliprects %d\n",
+                       cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects);
 
        RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
 
@@ -734,7 +740,7 @@ static int i915_flip_bufs(struct drm_device *dev, void *data,
 {
        int ret;
 
-       DRM_DEBUG("%s\n", __func__);
+       DRM_DEBUG_DRIVER(I915_DRV, "%s\n", __func__);
 
        RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
 
@@ -777,7 +783,8 @@ static int i915_getparam(struct drm_device *dev, void *data,
                value = dev_priv->num_fence_regs - dev_priv->fence_reg_start;
                break;
        default:
-               DRM_DEBUG("Unknown parameter %d\n", param->param);
+               DRM_DEBUG_DRIVER(I915_DRV, "Unknown parameter %d\n",
+                                       param->param);
                return -EINVAL;
        }
 
@@ -817,7 +824,8 @@ static int i915_setparam(struct drm_device *dev, void *data,
                dev_priv->fence_reg_start = param->value;
                break;
        default:
-               DRM_DEBUG("unknown parameter %d\n", param->param);
+               DRM_DEBUG_DRIVER(I915_DRV, "unknown parameter %d\n",
+                                       param->param);
                return -EINVAL;
        }
 
@@ -865,9 +873,10 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
 
        memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
        I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
-       DRM_DEBUG("load hws HWS_PGA with gfx mem 0x%x\n",
-                       dev_priv->status_gfx_addr);
-       DRM_DEBUG("load hws at %p\n", dev_priv->hw_status_page);
+       DRM_DEBUG_DRIVER(I915_DRV, "load hws HWS_PGA with gfx mem 0x%x\n",
+                               dev_priv->status_gfx_addr);
+       DRM_DEBUG_DRIVER(I915_DRV, "load hws at %p\n",
+                               dev_priv->hw_status_page);
        return 0;
 }
 
@@ -922,7 +931,7 @@ static int i915_probe_agp(struct drm_device *dev, unsigned long *aperture_size,
         * Some of the preallocated space is taken by the GTT
         * and popup.  GTT is 1K per MB of aperture size, and popup is 4K.
         */
-       if (IS_G4X(dev) || IS_IGD(dev))
+       if (IS_G4X(dev) || IS_IGD(dev) || IS_IGDNG(dev))
                overhead = 4096;
        else
                overhead = (*aperture_size / 1024) + 4096;
@@ -1153,8 +1162,11 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 #endif
 
        dev->driver->get_vblank_counter = i915_get_vblank_counter;
-       if (IS_GM45(dev))
+       dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
+       if (IS_G4X(dev) || IS_IGDNG(dev)) {
+               dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
                dev->driver->get_vblank_counter = gm45_get_vblank_counter;
+       }
 
        i915_gem_load(dev);
 
@@ -1198,7 +1210,9 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        }
 
        /* Must be done after probing outputs */
-       intel_opregion_init(dev, 0);
+       /* FIXME: verify on IGDNG */
+       if (!IS_IGDNG(dev))
+               intel_opregion_init(dev, 0);
 
        return 0;
 
@@ -1232,7 +1246,8 @@ int i915_driver_unload(struct drm_device *dev)
        if (dev_priv->regs != NULL)
                iounmap(dev_priv->regs);
 
-       intel_opregion_free(dev, 0);
+       if (!IS_IGDNG(dev))
+               intel_opregion_free(dev, 0);
 
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                intel_modeset_cleanup(dev);
@@ -1256,7 +1271,7 @@ int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv)
 {
        struct drm_i915_file_private *i915_file_priv;
 
-       DRM_DEBUG("\n");
+       DRM_DEBUG_DRIVER(I915_DRV, "\n");
        i915_file_priv = (struct drm_i915_file_private *)
            drm_alloc(sizeof(*i915_file_priv), DRM_MEM_FILES);
 
@@ -1265,8 +1280,7 @@ int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv)
 
        file_priv->driver_priv = i915_file_priv;
 
-       i915_file_priv->mm.last_gem_seqno = 0;
-       i915_file_priv->mm.last_gem_throttle_seqno = 0;
+       INIT_LIST_HEAD(&i915_file_priv->mm.request_list);
 
        return 0;
 }
@@ -1303,6 +1317,7 @@ void i915_driver_lastclose(struct drm_device * dev)
 void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
+       i915_gem_release(dev, file_priv);
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                i915_mem_release(dev, file_priv, dev_priv->agp_heap);
 }
index c431fa54bbb55b4d5d8afc32d9ea1468d05f66e5..8ef6bcec211bbc3f6440ba79b198a3d53e633eb8 100644 (file)
@@ -126,6 +126,13 @@ struct drm_i915_fence_reg {
        struct drm_gem_object *obj;
 };
 
+struct sdvo_device_mapping {
+       u8 dvo_port;
+       u8 slave_addr;
+       u8 dvo_wiring;
+       u8 initialized;
+};
+
 typedef struct drm_i915_private {
        struct drm_device *dev;
 
@@ -143,6 +150,8 @@ typedef struct drm_i915_private {
        drm_local_map_t hws_map;
        struct drm_gem_object *hws_obj;
 
+       struct resource mch_res;
+
        unsigned int cpp;
        int back_offset;
        int front_offset;
@@ -158,6 +167,11 @@ typedef struct drm_i915_private {
        /** Cached value of IMR to avoid reads in updating the bitfield */
        u32 irq_mask_reg;
        u32 pipestat[2];
+       /** splitted irq regs for graphics and display engine on IGDNG,
+           irq_mask_reg is still used for display irq. */
+       u32 gt_irq_mask_reg;
+       u32 gt_irq_enable_reg;
+       u32 de_irq_enable_reg;
 
        u32 hotplug_supported_mask;
        struct work_struct hotplug_work;
@@ -285,6 +299,13 @@ typedef struct drm_i915_private {
        u8 saveDACMASK;
        u8 saveCR[37];
        uint64_t saveFENCE[16];
+       u32 saveCURACNTR;
+       u32 saveCURAPOS;
+       u32 saveCURABASE;
+       u32 saveCURBCNTR;
+       u32 saveCURBPOS;
+       u32 saveCURBBASE;
+       u32 saveCURSIZE;
 
        struct {
                struct drm_mm gtt_space;
@@ -382,6 +403,7 @@ typedef struct drm_i915_private {
                /* storage for physical objects */
                struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT];
        } mm;
+       struct sdvo_device_mapping sdvo_mappings[2];
 } drm_i915_private_t;
 
 /** driver private structure attached to each drm_gem_object */
@@ -491,13 +513,16 @@ struct drm_i915_gem_request {
        /** Time at which this request was emitted, in jiffies. */
        unsigned long emitted_jiffies;
 
+       /** global list entry for this request */
        struct list_head list;
+
+       /** file_priv list entry for this request */
+       struct list_head client_list;
 };
 
 struct drm_i915_file_private {
        struct {
-               uint32_t last_gem_seqno;
-               uint32_t last_gem_throttle_seqno;
+               struct list_head request_list;
        } mm;
 };
 
@@ -642,6 +667,7 @@ void i915_gem_detach_phys_object(struct drm_device *dev,
 void i915_gem_free_all_phys_object(struct drm_device *dev);
 int i915_gem_object_get_pages(struct drm_gem_object *obj);
 void i915_gem_object_put_pages(struct drm_gem_object *obj);
+void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv);
 
 /* i915_gem_tiling.c */
 void i915_gem_detect_bit_6_swizzle(struct drm_device *dev);
@@ -785,7 +811,9 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
                       (dev)->pci_device == 0x2E02 || \
                       (dev)->pci_device == 0x2E12 || \
                       (dev)->pci_device == 0x2E22 || \
-                      (dev)->pci_device == 0x2E32)
+                      (dev)->pci_device == 0x2E32 || \
+                      (dev)->pci_device == 0x0042 || \
+                      (dev)->pci_device == 0x0046)
 
 #define IS_I965GM(dev) ((dev)->pci_device == 0x2A02 || \
                        (dev)->pci_device == 0x2A12)
@@ -807,20 +835,26 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
                        (dev)->pci_device == 0x29D2 ||  \
                        (IS_IGD(dev)))
 
+#define IS_IGDNG_D(dev)        ((dev)->pci_device == 0x0042)
+#define IS_IGDNG_M(dev)        ((dev)->pci_device == 0x0046)
+#define IS_IGDNG(dev)  (IS_IGDNG_D(dev) || IS_IGDNG_M(dev))
+
 #define IS_I9XX(dev) (IS_I915G(dev) || IS_I915GM(dev) || IS_I945G(dev) || \
-                     IS_I945GM(dev) || IS_I965G(dev) || IS_G33(dev))
+                     IS_I945GM(dev) || IS_I965G(dev) || IS_G33(dev) || \
+                     IS_IGDNG(dev))
 
 #define IS_MOBILE(dev) (IS_I830(dev) || IS_I85X(dev) || IS_I915GM(dev) || \
                        IS_I945GM(dev) || IS_I965GM(dev) || IS_GM45(dev) || \
-                       IS_IGD(dev))
+                       IS_IGD(dev) || IS_IGDNG_M(dev))
 
-#define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_GM45(dev) || IS_G4X(dev))
+#define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_GM45(dev) || IS_G4X(dev) || \
+                               IS_IGDNG(dev))
 /* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte
  * rows, which changed the alignment requirements and fence programming.
  */
 #define HAS_128_BYTE_Y_TILING(dev) (IS_I9XX(dev) && !(IS_I915G(dev) || \
                                                      IS_I915GM(dev)))
-#define SUPPORTS_INTEGRATED_HDMI(dev)  (IS_G4X(dev))
+#define SUPPORTS_INTEGRATED_HDMI(dev)  (IS_G4X(dev) || IS_IGDNG(dev))
 #define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev))
 
 #define PRIMARY_RINGBUFFER_SIZE         (128*1024)
index 39f5c658ef5e7c9754444672e86c166cd12a0191..c0ae6bbbd9b522380d5201a2a5bce7d505ec2b04 100644 (file)
@@ -989,10 +989,10 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
                return -ENODEV;
 
        /* Only handle setting domains to types used by the CPU. */
-       if (write_domain & ~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT))
+       if (write_domain & I915_GEM_GPU_DOMAINS)
                return -EINVAL;
 
-       if (read_domains & ~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT))
+       if (read_domains & I915_GEM_GPU_DOMAINS)
                return -EINVAL;
 
        /* Having something in the write domain implies it's in the read
@@ -1481,14 +1481,19 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj)
  * Returned sequence numbers are nonzero on success.
  */
 static uint32_t
-i915_add_request(struct drm_device *dev, uint32_t flush_domains)
+i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
+                uint32_t flush_domains)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_file_private *i915_file_priv = NULL;
        struct drm_i915_gem_request *request;
        uint32_t seqno;
        int was_empty;
        RING_LOCALS;
 
+       if (file_priv != NULL)
+               i915_file_priv = file_priv->driver_priv;
+
        request = drm_calloc(1, sizeof(*request), DRM_MEM_DRIVER);
        if (request == NULL)
                return 0;
@@ -1515,6 +1520,12 @@ i915_add_request(struct drm_device *dev, uint32_t flush_domains)
        request->emitted_jiffies = jiffies;
        was_empty = list_empty(&dev_priv->mm.request_list);
        list_add_tail(&request->list, &dev_priv->mm.request_list);
+       if (i915_file_priv) {
+               list_add_tail(&request->client_list,
+                             &i915_file_priv->mm.request_list);
+       } else {
+               INIT_LIST_HEAD(&request->client_list);
+       }
 
        /* Associate any objects on the flushing list matching the write
         * domain we're flushing with our flush.
@@ -1664,6 +1675,7 @@ i915_gem_retire_requests(struct drm_device *dev)
                        i915_gem_retire_request(dev, request);
 
                        list_del(&request->list);
+                       list_del(&request->client_list);
                        drm_free(request, sizeof(*request), DRM_MEM_DRIVER);
                } else
                        break;
@@ -1702,7 +1714,10 @@ i915_wait_request(struct drm_device *dev, uint32_t seqno)
        BUG_ON(seqno == 0);
 
        if (!i915_seqno_passed(i915_get_gem_seqno(dev), seqno)) {
-               ier = I915_READ(IER);
+               if (IS_IGDNG(dev))
+                       ier = I915_READ(DEIER) | I915_READ(GTIER);
+               else
+                       ier = I915_READ(IER);
                if (!ier) {
                        DRM_ERROR("something (likely vbetool) disabled "
                                  "interrupts, re-enabling\n");
@@ -1754,8 +1769,7 @@ i915_gem_flush(struct drm_device *dev,
        if (flush_domains & I915_GEM_DOMAIN_CPU)
                drm_agp_chipset_flush(dev);
 
-       if ((invalidate_domains | flush_domains) & ~(I915_GEM_DOMAIN_CPU |
-                                                    I915_GEM_DOMAIN_GTT)) {
+       if ((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) {
                /*
                 * read/write caches:
                 *
@@ -1977,7 +1991,7 @@ i915_gem_evict_something(struct drm_device *dev)
                        i915_gem_flush(dev,
                                       obj->write_domain,
                                       obj->write_domain);
-                       i915_add_request(dev, obj->write_domain);
+                       i915_add_request(dev, NULL, obj->write_domain);
 
                        obj = NULL;
                        continue;
@@ -1991,7 +2005,7 @@ i915_gem_evict_something(struct drm_device *dev)
                /* If we didn't do any of the above, there's nothing to be done
                 * and we just can't fit it in.
                 */
-               return -ENOMEM;
+               return -ENOSPC;
        }
        return ret;
 }
@@ -2006,7 +2020,7 @@ i915_gem_evict_everything(struct drm_device *dev)
                if (ret != 0)
                        break;
        }
-       if (ret == -ENOMEM)
+       if (ret == -ENOSPC)
                return 0;
        return ret;
 }
@@ -2215,7 +2229,7 @@ try_again:
                loff_t offset;
 
                if (avail == 0)
-                       return -ENOMEM;
+                       return -ENOSPC;
 
                for (i = dev_priv->fence_reg_start;
                     i < dev_priv->num_fence_regs; i++) {
@@ -2248,7 +2262,7 @@ try_again:
                                i915_gem_flush(dev,
                                               I915_GEM_GPU_DOMAINS,
                                               I915_GEM_GPU_DOMAINS);
-                               seqno = i915_add_request(dev,
+                               seqno = i915_add_request(dev, NULL,
                                                         I915_GEM_GPU_DOMAINS);
                                if (seqno == 0)
                                        return -ENOMEM;
@@ -2364,7 +2378,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
                spin_unlock(&dev_priv->mm.active_list_lock);
                if (lists_empty) {
                        DRM_ERROR("GTT full, but LRU list empty\n");
-                       return -ENOMEM;
+                       return -ENOSPC;
                }
 
                ret = i915_gem_evict_something(dev);
@@ -2409,8 +2423,8 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
         * wasn't in the GTT, there shouldn't be any way it could have been in
         * a GPU cache
         */
-       BUG_ON(obj->read_domains & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT));
-       BUG_ON(obj->write_domain & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT));
+       BUG_ON(obj->read_domains & I915_GEM_GPU_DOMAINS);
+       BUG_ON(obj->write_domain & I915_GEM_GPU_DOMAINS);
 
        return 0;
 }
@@ -2452,7 +2466,7 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj)
 
        /* Queue the GPU write cache flushing we need. */
        i915_gem_flush(dev, 0, obj->write_domain);
-       seqno = i915_add_request(dev, obj->write_domain);
+       seqno = i915_add_request(dev, NULL, obj->write_domain);
        obj->write_domain = 0;
        i915_gem_object_move_to_active(obj, seqno);
 }
@@ -3035,20 +3049,12 @@ i915_dispatch_gem_execbuffer(struct drm_device *dev,
        drm_i915_private_t *dev_priv = dev->dev_private;
        int nbox = exec->num_cliprects;
        int i = 0, count;
-       uint32_t        exec_start, exec_len;
+       uint32_t exec_start, exec_len;
        RING_LOCALS;
 
        exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
        exec_len = (uint32_t) exec->batch_len;
 
-       if ((exec_start | exec_len) & 0x7) {
-               DRM_ERROR("alignment\n");
-               return -EINVAL;
-       }
-
-       if (!exec_start)
-               return -EINVAL;
-
        count = nbox ? nbox : 1;
 
        for (i = 0; i < count; i++) {
@@ -3089,6 +3095,10 @@ i915_dispatch_gem_execbuffer(struct drm_device *dev,
 /* Throttle our rendering by waiting until the ring has completed our requests
  * emitted over 20 msec ago.
  *
+ * Note that if we were to use the current jiffies each time around the loop,
+ * we wouldn't escape the function with any frames outstanding if the time to
+ * render a frame was over 20ms.
+ *
  * This should get us reasonable parallelism between CPU and GPU but also
  * relatively low latency when blocking on a particular request to finish.
  */
@@ -3097,15 +3107,25 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file_priv)
 {
        struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
        int ret = 0;
-       uint32_t seqno;
+       unsigned long recent_enough = jiffies - msecs_to_jiffies(20);
 
        mutex_lock(&dev->struct_mutex);
-       seqno = i915_file_priv->mm.last_gem_throttle_seqno;
-       i915_file_priv->mm.last_gem_throttle_seqno =
-               i915_file_priv->mm.last_gem_seqno;
-       if (seqno)
-               ret = i915_wait_request(dev, seqno);
+       while (!list_empty(&i915_file_priv->mm.request_list)) {
+               struct drm_i915_gem_request *request;
+
+               request = list_first_entry(&i915_file_priv->mm.request_list,
+                                          struct drm_i915_gem_request,
+                                          client_list);
+
+               if (time_after_eq(request->emitted_jiffies, recent_enough))
+                       break;
+
+               ret = i915_wait_request(dev, request->seqno);
+               if (ret != 0)
+                       break;
+       }
        mutex_unlock(&dev->struct_mutex);
+
        return ret;
 }
 
@@ -3182,12 +3202,29 @@ err:
        return ret;
 }
 
+static int
+i915_gem_check_execbuffer (struct drm_i915_gem_execbuffer *exec,
+                          uint64_t exec_offset)
+{
+       uint32_t exec_start, exec_len;
+
+       exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
+       exec_len = (uint32_t) exec->batch_len;
+
+       if ((exec_start | exec_len) & 0x7)
+               return -EINVAL;
+
+       if (!exec_start)
+               return -EINVAL;
+
+       return 0;
+}
+
 int
 i915_gem_execbuffer(struct drm_device *dev, void *data,
                    struct drm_file *file_priv)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
        struct drm_i915_gem_execbuffer *args = data;
        struct drm_i915_gem_exec_object *exec_list = NULL;
        struct drm_gem_object **object_list = NULL;
@@ -3312,7 +3349,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
                        break;
 
                /* error other than GTT full, or we've already tried again */
-               if (ret != -ENOMEM || pin_tries >= 1) {
+               if (ret != -ENOSPC || pin_tries >= 1) {
                        if (ret != -ERESTARTSYS)
                                DRM_ERROR("Failed to pin buffers %d\n", ret);
                        goto err;
@@ -3331,8 +3368,20 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
 
        /* Set the pending read domains for the batch buffer to COMMAND */
        batch_obj = object_list[args->buffer_count-1];
-       batch_obj->pending_read_domains = I915_GEM_DOMAIN_COMMAND;
-       batch_obj->pending_write_domain = 0;
+       if (batch_obj->pending_write_domain) {
+               DRM_ERROR("Attempting to use self-modifying batch buffer\n");
+               ret = -EINVAL;
+               goto err;
+       }
+       batch_obj->pending_read_domains |= I915_GEM_DOMAIN_COMMAND;
+
+       /* Sanity check the batch buffer, prior to moving objects */
+       exec_offset = exec_list[args->buffer_count - 1].offset;
+       ret = i915_gem_check_execbuffer (args, exec_offset);
+       if (ret != 0) {
+               DRM_ERROR("execbuf with invalid offset/length\n");
+               goto err;
+       }
 
        i915_verify_inactive(dev, __FILE__, __LINE__);
 
@@ -3363,7 +3412,8 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
                               dev->invalidate_domains,
                               dev->flush_domains);
                if (dev->flush_domains)
-                       (void)i915_add_request(dev, dev->flush_domains);
+                       (void)i915_add_request(dev, file_priv,
+                                              dev->flush_domains);
        }
 
        for (i = 0; i < args->buffer_count; i++) {
@@ -3381,8 +3431,6 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
        }
 #endif
 
-       exec_offset = exec_list[args->buffer_count - 1].offset;
-
 #if WATCH_EXEC
        i915_gem_dump_object(batch_obj,
                              args->batch_len,
@@ -3412,9 +3460,8 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
         * *some* interrupts representing completion of buffers that we can
         * wait on when trying to clear up gtt space).
         */
-       seqno = i915_add_request(dev, flush_domains);
+       seqno = i915_add_request(dev, file_priv, flush_domains);
        BUG_ON(seqno == 0);
-       i915_file_priv->mm.last_gem_seqno = seqno;
        for (i = 0; i < args->buffer_count; i++) {
                struct drm_gem_object *obj = object_list[i];
 
@@ -3520,8 +3567,7 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
                atomic_inc(&dev->pin_count);
                atomic_add(obj->size, &dev->pin_memory);
                if (!obj_priv->active &&
-                   (obj->write_domain & ~(I915_GEM_DOMAIN_CPU |
-                                          I915_GEM_DOMAIN_GTT)) == 0 &&
+                   (obj->write_domain & I915_GEM_GPU_DOMAINS) == 0 &&
                    !list_empty(&obj_priv->list))
                        list_del_init(&obj_priv->list);
        }
@@ -3548,8 +3594,7 @@ i915_gem_object_unpin(struct drm_gem_object *obj)
         */
        if (obj_priv->pin_count == 0) {
                if (!obj_priv->active &&
-                   (obj->write_domain & ~(I915_GEM_DOMAIN_CPU |
-                                          I915_GEM_DOMAIN_GTT)) == 0)
+                   (obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
                        list_move_tail(&obj_priv->list,
                                       &dev_priv->mm.inactive_list);
                atomic_dec(&dev->pin_count);
@@ -3653,15 +3698,14 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
        struct drm_gem_object *obj;
        struct drm_i915_gem_object *obj_priv;
 
-       mutex_lock(&dev->struct_mutex);
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
        if (obj == NULL) {
                DRM_ERROR("Bad handle in i915_gem_busy_ioctl(): %d\n",
                          args->handle);
-               mutex_unlock(&dev->struct_mutex);
                return -EBADF;
        }
 
+       mutex_lock(&dev->struct_mutex);
        /* Update the active list for the hardware's current position.
         * Otherwise this only updates on a delayed timer or when irqs are
         * actually unmasked, and our working set ends up being larger than
@@ -3800,9 +3844,8 @@ i915_gem_idle(struct drm_device *dev)
 
        /* Flush the GPU along with all non-CPU write domains
         */
-       i915_gem_flush(dev, ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT),
-                      ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT));
-       seqno = i915_add_request(dev, ~I915_GEM_DOMAIN_CPU);
+       i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
+       seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS);
 
        if (seqno == 0) {
                mutex_unlock(&dev->struct_mutex);
@@ -4352,3 +4395,17 @@ i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
        drm_agp_chipset_flush(dev);
        return 0;
 }
+
+void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv)
+{
+       struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
+
+       /* Clean up our request list when the client is going away, so that
+        * later retire_requests won't dereference our soon-to-be-gone
+        * file_priv.
+        */
+       mutex_lock(&dev->struct_mutex);
+       while (!list_empty(&i915_file_priv->mm.request_list))
+               list_del_init(i915_file_priv->mm.request_list.next);
+       mutex_unlock(&dev->struct_mutex);
+}
index 540dd336e6ec682ade96cc0c56f9f7078a2e97ac..9a05cadaa4ad0efbcfd0d1082d5c37609b78cc5f 100644 (file)
@@ -25,6 +25,8 @@
  *
  */
 
+#include <linux/acpi.h>
+#include <linux/pnp.h>
 #include "linux/string.h"
 #include "linux/bitops.h"
 #include "drmP.h"
  * to match what the GPU expects.
  */
 
+#define MCHBAR_I915 0x44
+#define MCHBAR_I965 0x48
+#define MCHBAR_SIZE (4*4096)
+
+#define DEVEN_REG 0x54
+#define   DEVEN_MCHBAR_EN (1 << 28)
+
+/* Allocate space for the MCH regs if needed, return nonzero on error */
+static int
+intel_alloc_mchbar_resource(struct drm_device *dev)
+{
+       struct pci_dev *bridge_dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       int reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
+       u32 temp_lo, temp_hi = 0;
+       u64 mchbar_addr;
+       int ret = 0;
+
+       bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
+       if (!bridge_dev) {
+               DRM_DEBUG("no bridge dev?!\n");
+               ret = -ENODEV;
+               goto out;
+       }
+
+       if (IS_I965G(dev))
+               pci_read_config_dword(bridge_dev, reg + 4, &temp_hi);
+       pci_read_config_dword(bridge_dev, reg, &temp_lo);
+       mchbar_addr = ((u64)temp_hi << 32) | temp_lo;
+
+       /* If ACPI doesn't have it, assume we need to allocate it ourselves */
+       if (mchbar_addr &&
+           pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE)) {
+               ret = 0;
+               goto out_put;
+       }
+
+       /* Get some space for it */
+       ret = pci_bus_alloc_resource(bridge_dev->bus, &dev_priv->mch_res,
+                                    MCHBAR_SIZE, MCHBAR_SIZE,
+                                    PCIBIOS_MIN_MEM,
+                                    0,   pcibios_align_resource,
+                                    bridge_dev);
+       if (ret) {
+               DRM_DEBUG("failed bus alloc: %d\n", ret);
+               dev_priv->mch_res.start = 0;
+               goto out_put;
+       }
+
+       if (IS_I965G(dev))
+               pci_write_config_dword(bridge_dev, reg + 4,
+                                      upper_32_bits(dev_priv->mch_res.start));
+
+       pci_write_config_dword(bridge_dev, reg,
+                              lower_32_bits(dev_priv->mch_res.start));
+out_put:
+       pci_dev_put(bridge_dev);
+out:
+       return ret;
+}
+
+/* Setup MCHBAR if possible, return true if we should disable it again */
+static bool
+intel_setup_mchbar(struct drm_device *dev)
+{
+       struct pci_dev *bridge_dev;
+       int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
+       u32 temp;
+       bool need_disable = false, enabled;
+
+       bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
+       if (!bridge_dev) {
+               DRM_DEBUG("no bridge dev?!\n");
+               goto out;
+       }
+
+       if (IS_I915G(dev) || IS_I915GM(dev)) {
+               pci_read_config_dword(bridge_dev, DEVEN_REG, &temp);
+               enabled = !!(temp & DEVEN_MCHBAR_EN);
+       } else {
+               pci_read_config_dword(bridge_dev, mchbar_reg, &temp);
+               enabled = temp & 1;
+       }
+
+       /* If it's already enabled, don't have to do anything */
+       if (enabled)
+               goto out_put;
+
+       if (intel_alloc_mchbar_resource(dev))
+               goto out_put;
+
+       need_disable = true;
+
+       /* Space is allocated or reserved, so enable it. */
+       if (IS_I915G(dev) || IS_I915GM(dev)) {
+               pci_write_config_dword(bridge_dev, DEVEN_REG,
+                                      temp | DEVEN_MCHBAR_EN);
+       } else {
+               pci_read_config_dword(bridge_dev, mchbar_reg, &temp);
+               pci_write_config_dword(bridge_dev, mchbar_reg, temp | 1);
+       }
+out_put:
+       pci_dev_put(bridge_dev);
+out:
+       return need_disable;
+}
+
+static void
+intel_teardown_mchbar(struct drm_device *dev, bool disable)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct pci_dev *bridge_dev;
+       int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
+       u32 temp;
+
+       bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
+       if (!bridge_dev) {
+               DRM_DEBUG("no bridge dev?!\n");
+               return;
+       }
+
+       if (disable) {
+               if (IS_I915G(dev) || IS_I915GM(dev)) {
+                       pci_read_config_dword(bridge_dev, DEVEN_REG, &temp);
+                       temp &= ~DEVEN_MCHBAR_EN;
+                       pci_write_config_dword(bridge_dev, DEVEN_REG, temp);
+               } else {
+                       pci_read_config_dword(bridge_dev, mchbar_reg, &temp);
+                       temp &= ~1;
+                       pci_write_config_dword(bridge_dev, mchbar_reg, temp);
+               }
+       }
+
+       if (dev_priv->mch_res.start)
+               release_resource(&dev_priv->mch_res);
+}
+
 /**
  * Detects bit 6 swizzling of address lookup between IGD access and CPU
  * access through main memory.
@@ -91,6 +230,7 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
        drm_i915_private_t *dev_priv = dev->dev_private;
        uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
        uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
+       bool need_disable;
 
        if (!IS_I9XX(dev)) {
                /* As far as we know, the 865 doesn't have these bit 6
@@ -101,6 +241,9 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
        } else if (IS_MOBILE(dev)) {
                uint32_t dcc;
 
+               /* Try to make sure MCHBAR is enabled before poking at it */
+               need_disable = intel_setup_mchbar(dev);
+
                /* On mobile 9xx chipsets, channel interleave by the CPU is
                 * determined by DCC.  For single-channel, neither the CPU
                 * nor the GPU do swizzling.  For dual channel interleaved,
@@ -140,6 +283,8 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
                        swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
                        swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
                }
+
+               intel_teardown_mchbar(dev, need_disable);
        } else {
                /* The 965, G33, and newer, have a very flexible memory
                 * configuration.  It will enable dual-channel mode
@@ -170,6 +315,13 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
                }
        }
 
+       /* FIXME: check with memory config on IGDNG */
+       if (IS_IGDNG(dev)) {
+               DRM_ERROR("disable tiling on IGDNG...\n");
+               swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
+               swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
+       }
+
        dev_priv->mm.bit_6_swizzle_x = swizzle_x;
        dev_priv->mm.bit_6_swizzle_y = swizzle_y;
 }
index 98bb4c878c4ef892a5aeb42b64a335e95eb45b24..b86b7b7130c603beca04456ccca0abc4c5bbfbcc 100644 (file)
 #define DRM_I915_VBLANK_PIPE_ALL       (DRM_I915_VBLANK_PIPE_A | \
                                         DRM_I915_VBLANK_PIPE_B)
 
+void
+igdng_enable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask)
+{
+       if ((dev_priv->gt_irq_mask_reg & mask) != 0) {
+               dev_priv->gt_irq_mask_reg &= ~mask;
+               I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
+               (void) I915_READ(GTIMR);
+       }
+}
+
+static inline void
+igdng_disable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask)
+{
+       if ((dev_priv->gt_irq_mask_reg & mask) != mask) {
+               dev_priv->gt_irq_mask_reg |= mask;
+               I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
+               (void) I915_READ(GTIMR);
+       }
+}
+
+/* For display hotplug interrupt */
+void
+igdng_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
+{
+       if ((dev_priv->irq_mask_reg & mask) != 0) {
+               dev_priv->irq_mask_reg &= ~mask;
+               I915_WRITE(DEIMR, dev_priv->irq_mask_reg);
+               (void) I915_READ(DEIMR);
+       }
+}
+
+static inline void
+igdng_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
+{
+       if ((dev_priv->irq_mask_reg & mask) != mask) {
+               dev_priv->irq_mask_reg |= mask;
+               I915_WRITE(DEIMR, dev_priv->irq_mask_reg);
+               (void) I915_READ(DEIMR);
+       }
+}
+
 void
 i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask)
 {
@@ -196,6 +237,47 @@ static void i915_hotplug_work_func(struct work_struct *work)
        drm_sysfs_hotplug_event(dev);
 }
 
+irqreturn_t igdng_irq_handler(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       int ret = IRQ_NONE;
+       u32 de_iir, gt_iir;
+       u32 new_de_iir, new_gt_iir;
+       struct drm_i915_master_private *master_priv;
+
+       de_iir = I915_READ(DEIIR);
+       gt_iir = I915_READ(GTIIR);
+
+       for (;;) {
+               if (de_iir == 0 && gt_iir == 0)
+                       break;
+
+               ret = IRQ_HANDLED;
+
+               I915_WRITE(DEIIR, de_iir);
+               new_de_iir = I915_READ(DEIIR);
+               I915_WRITE(GTIIR, gt_iir);
+               new_gt_iir = I915_READ(GTIIR);
+
+               if (dev->primary->master) {
+                       master_priv = dev->primary->master->driver_priv;
+                       if (master_priv->sarea_priv)
+                               master_priv->sarea_priv->last_dispatch =
+                                       READ_BREADCRUMB(dev_priv);
+               }
+
+               if (gt_iir & GT_USER_INTERRUPT) {
+                       dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev);
+                       DRM_WAKEUP(&dev_priv->irq_queue);
+               }
+
+               de_iir = new_de_iir;
+               gt_iir = new_gt_iir;
+       }
+
+       return ret;
+}
+
 irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 {
        struct drm_device *dev = (struct drm_device *) arg;
@@ -212,6 +294,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 
        atomic_inc(&dev_priv->irq_received);
 
+       if (IS_IGDNG(dev))
+               return igdng_irq_handler(dev);
+
        iir = I915_READ(IIR);
 
        if (IS_I965G(dev)) {
@@ -349,8 +434,12 @@ void i915_user_irq_get(struct drm_device *dev)
        unsigned long irqflags;
 
        spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
-       if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1))
-               i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
+       if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) {
+               if (IS_IGDNG(dev))
+                       igdng_enable_graphics_irq(dev_priv, GT_USER_INTERRUPT);
+               else
+                       i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
+       }
        spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
 }
 
@@ -361,8 +450,12 @@ void i915_user_irq_put(struct drm_device *dev)
 
        spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
        BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0);
-       if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0))
-               i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
+       if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) {
+               if (IS_IGDNG(dev))
+                       igdng_disable_graphics_irq(dev_priv, GT_USER_INTERRUPT);
+               else
+                       i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
+       }
        spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
 }
 
@@ -455,6 +548,9 @@ int i915_enable_vblank(struct drm_device *dev, int pipe)
        if (!(pipeconf & PIPEACONF_ENABLE))
                return -EINVAL;
 
+       if (IS_IGDNG(dev))
+               return 0;
+
        spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
        if (IS_I965G(dev))
                i915_enable_pipestat(dev_priv, pipe,
@@ -474,6 +570,9 @@ void i915_disable_vblank(struct drm_device *dev, int pipe)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        unsigned long irqflags;
 
+       if (IS_IGDNG(dev))
+               return;
+
        spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
        i915_disable_pipestat(dev_priv, pipe,
                              PIPE_VBLANK_INTERRUPT_ENABLE |
@@ -484,7 +583,9 @@ void i915_disable_vblank(struct drm_device *dev, int pipe)
 void i915_enable_interrupt (struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       opregion_enable_asle(dev);
+
+       if (!IS_IGDNG(dev))
+               opregion_enable_asle(dev);
        dev_priv->irq_enabled = 1;
 }
 
@@ -545,12 +646,65 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
 
 /* drm_dma.h hooks
 */
+static void igdng_irq_preinstall(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+       I915_WRITE(HWSTAM, 0xeffe);
+
+       /* XXX hotplug from PCH */
+
+       I915_WRITE(DEIMR, 0xffffffff);
+       I915_WRITE(DEIER, 0x0);
+       (void) I915_READ(DEIER);
+
+       /* and GT */
+       I915_WRITE(GTIMR, 0xffffffff);
+       I915_WRITE(GTIER, 0x0);
+       (void) I915_READ(GTIER);
+}
+
+static int igdng_irq_postinstall(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       /* enable kind of interrupts always enabled */
+       u32 display_mask = DE_MASTER_IRQ_CONTROL /*| DE_PCH_EVENT */;
+       u32 render_mask = GT_USER_INTERRUPT;
+
+       dev_priv->irq_mask_reg = ~display_mask;
+       dev_priv->de_irq_enable_reg = display_mask;
+
+       /* should always can generate irq */
+       I915_WRITE(DEIIR, I915_READ(DEIIR));
+       I915_WRITE(DEIMR, dev_priv->irq_mask_reg);
+       I915_WRITE(DEIER, dev_priv->de_irq_enable_reg);
+       (void) I915_READ(DEIER);
+
+       /* user interrupt should be enabled, but masked initial */
+       dev_priv->gt_irq_mask_reg = 0xffffffff;
+       dev_priv->gt_irq_enable_reg = render_mask;
+
+       I915_WRITE(GTIIR, I915_READ(GTIIR));
+       I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
+       I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg);
+       (void) I915_READ(GTIER);
+
+       return 0;
+}
+
 void i915_driver_irq_preinstall(struct drm_device * dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 
        atomic_set(&dev_priv->irq_received, 0);
 
+       INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
+
+       if (IS_IGDNG(dev)) {
+               igdng_irq_preinstall(dev);
+               return;
+       }
+
        if (I915_HAS_HOTPLUG(dev)) {
                I915_WRITE(PORT_HOTPLUG_EN, 0);
                I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
@@ -562,7 +716,6 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
        I915_WRITE(IMR, 0xffffffff);
        I915_WRITE(IER, 0x0);
        (void) I915_READ(IER);
-       INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
 }
 
 int i915_driver_irq_postinstall(struct drm_device *dev)
@@ -570,9 +723,12 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR;
 
+       DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
+
        dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
 
-       dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
+       if (IS_IGDNG(dev))
+               return igdng_irq_postinstall(dev);
 
        /* Unmask the interrupts that we always want on. */
        dev_priv->irq_mask_reg = ~I915_INTERRUPT_ENABLE_FIX;
@@ -613,11 +769,24 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
        (void) I915_READ(IER);
 
        opregion_enable_asle(dev);
-       DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
 
        return 0;
 }
 
+static void igdng_irq_uninstall(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       I915_WRITE(HWSTAM, 0xffffffff);
+
+       I915_WRITE(DEIMR, 0xffffffff);
+       I915_WRITE(DEIER, 0x0);
+       I915_WRITE(DEIIR, I915_READ(DEIIR));
+
+       I915_WRITE(GTIMR, 0xffffffff);
+       I915_WRITE(GTIER, 0x0);
+       I915_WRITE(GTIIR, I915_READ(GTIIR));
+}
+
 void i915_driver_irq_uninstall(struct drm_device * dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -627,6 +796,11 @@ void i915_driver_irq_uninstall(struct drm_device * dev)
 
        dev_priv->vblank_pipe = 0;
 
+       if (IS_IGDNG(dev)) {
+               igdng_irq_uninstall(dev);
+               return;
+       }
+
        if (I915_HAS_HOTPLUG(dev)) {
                I915_WRITE(PORT_HOTPLUG_EN, 0);
                I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
index 375569d01d011fc00be4b94dbae0db06668af6de..f6237a0b1133c0429cc27a2a0c26282bd6051b8c 100644 (file)
 #define   PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13)
 #define   PLL_REF_INPUT_MASK           (3 << 13)
 #define   PLL_LOAD_PULSE_PHASE_SHIFT           9
+/* IGDNG */
+# define PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT     9
+# define PLL_REF_SDVO_HDMI_MULTIPLIER_MASK      (7 << 9)
+# define PLL_REF_SDVO_HDMI_MULTIPLIER(x)       (((x)-1) << 9)
+# define DPLL_FPA1_P1_POST_DIV_SHIFT            0
+# define DPLL_FPA1_P1_POST_DIV_MASK             0xff
+
 /*
  * Parallel to Serial Load Pulse phase selection.
  * Selects the phase for the 10X DPLL clock for the PCIe
 /* Hotplug control (945+ only) */
 #define PORT_HOTPLUG_EN                0x61110
 #define   HDMIB_HOTPLUG_INT_EN                 (1 << 29)
+#define   DPB_HOTPLUG_INT_EN                   (1 << 29)
 #define   HDMIC_HOTPLUG_INT_EN                 (1 << 28)
+#define   DPC_HOTPLUG_INT_EN                   (1 << 28)
 #define   HDMID_HOTPLUG_INT_EN                 (1 << 27)
+#define   DPD_HOTPLUG_INT_EN                   (1 << 27)
 #define   SDVOB_HOTPLUG_INT_EN                 (1 << 26)
 #define   SDVOC_HOTPLUG_INT_EN                 (1 << 25)
 #define   TV_HOTPLUG_INT_EN                    (1 << 18)
 
 #define PORT_HOTPLUG_STAT      0x61114
 #define   HDMIB_HOTPLUG_INT_STATUS             (1 << 29)
+#define   DPB_HOTPLUG_INT_STATUS               (1 << 29)
 #define   HDMIC_HOTPLUG_INT_STATUS             (1 << 28)
+#define   DPC_HOTPLUG_INT_STATUS               (1 << 28)
 #define   HDMID_HOTPLUG_INT_STATUS             (1 << 27)
+#define   DPD_HOTPLUG_INT_STATUS               (1 << 27)
 #define   CRT_HOTPLUG_INT_STATUS               (1 << 11)
 #define   TV_HOTPLUG_INT_STATUS                        (1 << 10)
 #define   CRT_HOTPLUG_MONITOR_MASK             (3 << 8)
 # define DAC_A_1_3_V                   (0 << 4)
 # define DAC_A_1_1_V                   (1 << 4)
 # define DAC_A_0_7_V                   (2 << 4)
-# define DAC_A_OFF                     (3 << 4)
+# define DAC_A_MASK                    (3 << 4)
 # define DAC_B_1_3_V                   (0 << 2)
 # define DAC_B_1_1_V                   (1 << 2)
 # define DAC_B_0_7_V                   (2 << 2)
-# define DAC_B_OFF                     (3 << 2)
+# define DAC_B_MASK                    (3 << 2)
 # define DAC_C_1_3_V                   (0 << 0)
 # define DAC_C_1_1_V                   (1 << 0)
 # define DAC_C_0_7_V                   (2 << 0)
-# define DAC_C_OFF                     (3 << 0)
+# define DAC_C_MASK                    (3 << 0)
 
 /**
  * CSC coefficients are stored in a floating point format with 9 bits of
 #define TV_V_CHROMA_0          0x68400
 #define TV_V_CHROMA_42         0x684a8
 
+/* Display Port */
+#define DP_B                           0x64100
+#define DP_C                           0x64200
+#define DP_D                           0x64300
+
+#define   DP_PORT_EN                   (1 << 31)
+#define   DP_PIPEB_SELECT              (1 << 30)
+
+/* Link training mode - select a suitable mode for each stage */
+#define   DP_LINK_TRAIN_PAT_1          (0 << 28)
+#define   DP_LINK_TRAIN_PAT_2          (1 << 28)
+#define   DP_LINK_TRAIN_PAT_IDLE       (2 << 28)
+#define   DP_LINK_TRAIN_OFF            (3 << 28)
+#define   DP_LINK_TRAIN_MASK           (3 << 28)
+#define   DP_LINK_TRAIN_SHIFT          28
+
+/* Signal voltages. These are mostly controlled by the other end */
+#define   DP_VOLTAGE_0_4               (0 << 25)
+#define   DP_VOLTAGE_0_6               (1 << 25)
+#define   DP_VOLTAGE_0_8               (2 << 25)
+#define   DP_VOLTAGE_1_2               (3 << 25)
+#define   DP_VOLTAGE_MASK              (7 << 25)
+#define   DP_VOLTAGE_SHIFT             25
+
+/* Signal pre-emphasis levels, like voltages, the other end tells us what
+ * they want
+ */
+#define   DP_PRE_EMPHASIS_0            (0 << 22)
+#define   DP_PRE_EMPHASIS_3_5          (1 << 22)
+#define   DP_PRE_EMPHASIS_6            (2 << 22)
+#define   DP_PRE_EMPHASIS_9_5          (3 << 22)
+#define   DP_PRE_EMPHASIS_MASK         (7 << 22)
+#define   DP_PRE_EMPHASIS_SHIFT                22
+
+/* How many wires to use. I guess 3 was too hard */
+#define   DP_PORT_WIDTH_1              (0 << 19)
+#define   DP_PORT_WIDTH_2              (1 << 19)
+#define   DP_PORT_WIDTH_4              (3 << 19)
+#define   DP_PORT_WIDTH_MASK           (7 << 19)
+
+/* Mystic DPCD version 1.1 special mode */
+#define   DP_ENHANCED_FRAMING          (1 << 18)
+
+/** locked once port is enabled */
+#define   DP_PORT_REVERSAL             (1 << 15)
+
+/** sends the clock on lane 15 of the PEG for debug */
+#define   DP_CLOCK_OUTPUT_ENABLE       (1 << 13)
+
+#define   DP_SCRAMBLING_DISABLE                (1 << 12)
+
+/** limit RGB values to avoid confusing TVs */
+#define   DP_COLOR_RANGE_16_235                (1 << 8)
+
+/** Turn on the audio link */
+#define   DP_AUDIO_OUTPUT_ENABLE       (1 << 6)
+
+/** vs and hs sync polarity */
+#define   DP_SYNC_VS_HIGH              (1 << 4)
+#define   DP_SYNC_HS_HIGH              (1 << 3)
+
+/** A fantasy */
+#define   DP_DETECTED                  (1 << 2)
+
+/** The aux channel provides a way to talk to the
+ * signal sink for DDC etc. Max packet size supported
+ * is 20 bytes in each direction, hence the 5 fixed
+ * data registers
+ */
+#define DPB_AUX_CH_CTL                 0x64110
+#define DPB_AUX_CH_DATA1               0x64114
+#define DPB_AUX_CH_DATA2               0x64118
+#define DPB_AUX_CH_DATA3               0x6411c
+#define DPB_AUX_CH_DATA4               0x64120
+#define DPB_AUX_CH_DATA5               0x64124
+
+#define DPC_AUX_CH_CTL                 0x64210
+#define DPC_AUX_CH_DATA1               0x64214
+#define DPC_AUX_CH_DATA2               0x64218
+#define DPC_AUX_CH_DATA3               0x6421c
+#define DPC_AUX_CH_DATA4               0x64220
+#define DPC_AUX_CH_DATA5               0x64224
+
+#define DPD_AUX_CH_CTL                 0x64310
+#define DPD_AUX_CH_DATA1               0x64314
+#define DPD_AUX_CH_DATA2               0x64318
+#define DPD_AUX_CH_DATA3               0x6431c
+#define DPD_AUX_CH_DATA4               0x64320
+#define DPD_AUX_CH_DATA5               0x64324
+
+#define   DP_AUX_CH_CTL_SEND_BUSY          (1 << 31)
+#define   DP_AUX_CH_CTL_DONE               (1 << 30)
+#define   DP_AUX_CH_CTL_INTERRUPT          (1 << 29)
+#define   DP_AUX_CH_CTL_TIME_OUT_ERROR     (1 << 28)
+#define   DP_AUX_CH_CTL_TIME_OUT_400us     (0 << 26)
+#define   DP_AUX_CH_CTL_TIME_OUT_600us     (1 << 26)
+#define   DP_AUX_CH_CTL_TIME_OUT_800us     (2 << 26)
+#define   DP_AUX_CH_CTL_TIME_OUT_1600us            (3 << 26)
+#define   DP_AUX_CH_CTL_TIME_OUT_MASK      (3 << 26)
+#define   DP_AUX_CH_CTL_RECEIVE_ERROR      (1 << 25)
+#define   DP_AUX_CH_CTL_MESSAGE_SIZE_MASK    (0x1f << 20)
+#define   DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT   20
+#define   DP_AUX_CH_CTL_PRECHARGE_2US_MASK   (0xf << 16)
+#define   DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT  16
+#define   DP_AUX_CH_CTL_AUX_AKSV_SELECT            (1 << 15)
+#define   DP_AUX_CH_CTL_MANCHESTER_TEST            (1 << 14)
+#define   DP_AUX_CH_CTL_SYNC_TEST          (1 << 13)
+#define   DP_AUX_CH_CTL_DEGLITCH_TEST      (1 << 12)
+#define   DP_AUX_CH_CTL_PRECHARGE_TEST     (1 << 11)
+#define   DP_AUX_CH_CTL_BIT_CLOCK_2X_MASK    (0x7ff)
+#define   DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT   0
+
+/*
+ * Computing GMCH M and N values for the Display Port link
+ *
+ * GMCH M/N = dot clock * bytes per pixel / ls_clk * # of lanes
+ *
+ * ls_clk (we assume) is the DP link clock (1.62 or 2.7 GHz)
+ *
+ * The GMCH value is used internally
+ *
+ * bytes_per_pixel is the number of bytes coming out of the plane,
+ * which is after the LUTs, so we want the bytes for our color format.
+ * For our current usage, this is always 3, one byte for R, G and B.
+ */
+#define PIPEA_GMCH_DATA_M                      0x70050
+#define PIPEB_GMCH_DATA_M                      0x71050
+
+/* Transfer unit size for display port - 1, default is 0x3f (for TU size 64) */
+#define   PIPE_GMCH_DATA_M_TU_SIZE_MASK                (0x3f << 25)
+#define   PIPE_GMCH_DATA_M_TU_SIZE_SHIFT       25
+
+#define   PIPE_GMCH_DATA_M_MASK                        (0xffffff)
+
+#define PIPEA_GMCH_DATA_N                      0x70054
+#define PIPEB_GMCH_DATA_N                      0x71054
+#define   PIPE_GMCH_DATA_N_MASK                        (0xffffff)
+
+/*
+ * Computing Link M and N values for the Display Port link
+ *
+ * Link M / N = pixel_clock / ls_clk
+ *
+ * (the DP spec calls pixel_clock the 'strm_clk')
+ *
+ * The Link value is transmitted in the Main Stream
+ * Attributes and VB-ID.
+ */
+
+#define PIPEA_DP_LINK_M                                0x70060
+#define PIPEB_DP_LINK_M                                0x71060
+#define   PIPEA_DP_LINK_M_MASK                 (0xffffff)
+
+#define PIPEA_DP_LINK_N                                0x70064
+#define PIPEB_DP_LINK_N                                0x71064
+#define   PIPEA_DP_LINK_N_MASK                 (0xffffff)
+
 /* Display & cursor control */
 
 /* Pipe A */
 # define VGA_2X_MODE                           (1 << 30)
 # define VGA_PIPE_B_SELECT                     (1 << 29)
 
+/* IGDNG */
+
+#define CPU_VGACNTRL   0x41000
+
+#define DIGITAL_PORT_HOTPLUG_CNTRL      0x44030
+#define  DIGITAL_PORTA_HOTPLUG_ENABLE           (1 << 4)
+#define  DIGITAL_PORTA_SHORT_PULSE_2MS          (0 << 2)
+#define  DIGITAL_PORTA_SHORT_PULSE_4_5MS        (1 << 2)
+#define  DIGITAL_PORTA_SHORT_PULSE_6MS          (2 << 2)
+#define  DIGITAL_PORTA_SHORT_PULSE_100MS        (3 << 2)
+#define  DIGITAL_PORTA_NO_DETECT                (0 << 0)
+#define  DIGITAL_PORTA_LONG_PULSE_DETECT_MASK   (1 << 1)
+#define  DIGITAL_PORTA_SHORT_PULSE_DETECT_MASK  (1 << 0)
+
+/* refresh rate hardware control */
+#define RR_HW_CTL       0x45300
+#define  RR_HW_LOW_POWER_FRAMES_MASK    0xff
+#define  RR_HW_HIGH_POWER_FRAMES_MASK   0xff00
+
+#define FDI_PLL_BIOS_0  0x46000
+#define FDI_PLL_BIOS_1  0x46004
+#define FDI_PLL_BIOS_2  0x46008
+#define DISPLAY_PORT_PLL_BIOS_0         0x4600c
+#define DISPLAY_PORT_PLL_BIOS_1         0x46010
+#define DISPLAY_PORT_PLL_BIOS_2         0x46014
+
+#define FDI_PLL_FREQ_CTL        0x46030
+#define  FDI_PLL_FREQ_CHANGE_REQUEST    (1<<24)
+#define  FDI_PLL_FREQ_LOCK_LIMIT_MASK   0xfff00
+#define  FDI_PLL_FREQ_DISABLE_COUNT_LIMIT_MASK  0xff
+
+
+#define PIPEA_DATA_M1           0x60030
+#define  TU_SIZE(x)             (((x)-1) << 25) /* default size 64 */
+#define  TU_SIZE_MASK           0x7e000000
+#define  PIPEA_DATA_M1_OFFSET   0
+#define PIPEA_DATA_N1           0x60034
+#define  PIPEA_DATA_N1_OFFSET   0
+
+#define PIPEA_DATA_M2           0x60038
+#define  PIPEA_DATA_M2_OFFSET   0
+#define PIPEA_DATA_N2           0x6003c
+#define  PIPEA_DATA_N2_OFFSET   0
+
+#define PIPEA_LINK_M1           0x60040
+#define  PIPEA_LINK_M1_OFFSET   0
+#define PIPEA_LINK_N1           0x60044
+#define  PIPEA_LINK_N1_OFFSET   0
+
+#define PIPEA_LINK_M2           0x60048
+#define  PIPEA_LINK_M2_OFFSET   0
+#define PIPEA_LINK_N2           0x6004c
+#define  PIPEA_LINK_N2_OFFSET   0
+
+/* PIPEB timing regs are same start from 0x61000 */
+
+#define PIPEB_DATA_M1           0x61030
+#define  PIPEB_DATA_M1_OFFSET   0
+#define PIPEB_DATA_N1           0x61034
+#define  PIPEB_DATA_N1_OFFSET   0
+
+#define PIPEB_DATA_M2           0x61038
+#define  PIPEB_DATA_M2_OFFSET   0
+#define PIPEB_DATA_N2           0x6103c
+#define  PIPEB_DATA_N2_OFFSET   0
+
+#define PIPEB_LINK_M1           0x61040
+#define  PIPEB_LINK_M1_OFFSET   0
+#define PIPEB_LINK_N1           0x61044
+#define  PIPEB_LINK_N1_OFFSET   0
+
+#define PIPEB_LINK_M2           0x61048
+#define  PIPEB_LINK_M2_OFFSET   0
+#define PIPEB_LINK_N2           0x6104c
+#define  PIPEB_LINK_N2_OFFSET   0
+
+/* CPU panel fitter */
+#define PFA_CTL_1               0x68080
+#define PFB_CTL_1               0x68880
+#define  PF_ENABLE              (1<<31)
+
+/* legacy palette */
+#define LGC_PALETTE_A           0x4a000
+#define LGC_PALETTE_B           0x4a800
+
+/* interrupts */
+#define DE_MASTER_IRQ_CONTROL   (1 << 31)
+#define DE_SPRITEB_FLIP_DONE    (1 << 29)
+#define DE_SPRITEA_FLIP_DONE    (1 << 28)
+#define DE_PLANEB_FLIP_DONE     (1 << 27)
+#define DE_PLANEA_FLIP_DONE     (1 << 26)
+#define DE_PCU_EVENT            (1 << 25)
+#define DE_GTT_FAULT            (1 << 24)
+#define DE_POISON               (1 << 23)
+#define DE_PERFORM_COUNTER      (1 << 22)
+#define DE_PCH_EVENT            (1 << 21)
+#define DE_AUX_CHANNEL_A        (1 << 20)
+#define DE_DP_A_HOTPLUG         (1 << 19)
+#define DE_GSE                  (1 << 18)
+#define DE_PIPEB_VBLANK         (1 << 15)
+#define DE_PIPEB_EVEN_FIELD     (1 << 14)
+#define DE_PIPEB_ODD_FIELD      (1 << 13)
+#define DE_PIPEB_LINE_COMPARE   (1 << 12)
+#define DE_PIPEB_VSYNC          (1 << 11)
+#define DE_PIPEB_FIFO_UNDERRUN  (1 << 8)
+#define DE_PIPEA_VBLANK         (1 << 7)
+#define DE_PIPEA_EVEN_FIELD     (1 << 6)
+#define DE_PIPEA_ODD_FIELD      (1 << 5)
+#define DE_PIPEA_LINE_COMPARE   (1 << 4)
+#define DE_PIPEA_VSYNC          (1 << 3)
+#define DE_PIPEA_FIFO_UNDERRUN  (1 << 0)
+
+#define DEISR   0x44000
+#define DEIMR   0x44004
+#define DEIIR   0x44008
+#define DEIER   0x4400c
+
+/* GT interrupt */
+#define GT_SYNC_STATUS          (1 << 2)
+#define GT_USER_INTERRUPT       (1 << 0)
+
+#define GTISR   0x44010
+#define GTIMR   0x44014
+#define GTIIR   0x44018
+#define GTIER   0x4401c
+
+/* PCH */
+
+/* south display engine interrupt */
+#define SDE_CRT_HOTPLUG         (1 << 11)
+#define SDE_PORTD_HOTPLUG       (1 << 10)
+#define SDE_PORTC_HOTPLUG       (1 << 9)
+#define SDE_PORTB_HOTPLUG       (1 << 8)
+#define SDE_SDVOB_HOTPLUG       (1 << 6)
+
+#define SDEISR  0xc4000
+#define SDEIMR  0xc4004
+#define SDEIIR  0xc4008
+#define SDEIER  0xc400c
+
+/* digital port hotplug */
+#define PCH_PORT_HOTPLUG        0xc4030
+#define PORTD_HOTPLUG_ENABLE            (1 << 20)
+#define PORTD_PULSE_DURATION_2ms        (0)
+#define PORTD_PULSE_DURATION_4_5ms      (1 << 18)
+#define PORTD_PULSE_DURATION_6ms        (2 << 18)
+#define PORTD_PULSE_DURATION_100ms      (3 << 18)
+#define PORTD_HOTPLUG_NO_DETECT         (0)
+#define PORTD_HOTPLUG_SHORT_DETECT      (1 << 16)
+#define PORTD_HOTPLUG_LONG_DETECT       (1 << 17)
+#define PORTC_HOTPLUG_ENABLE            (1 << 12)
+#define PORTC_PULSE_DURATION_2ms        (0)
+#define PORTC_PULSE_DURATION_4_5ms      (1 << 10)
+#define PORTC_PULSE_DURATION_6ms        (2 << 10)
+#define PORTC_PULSE_DURATION_100ms      (3 << 10)
+#define PORTC_HOTPLUG_NO_DETECT         (0)
+#define PORTC_HOTPLUG_SHORT_DETECT      (1 << 8)
+#define PORTC_HOTPLUG_LONG_DETECT       (1 << 9)
+#define PORTB_HOTPLUG_ENABLE            (1 << 4)
+#define PORTB_PULSE_DURATION_2ms        (0)
+#define PORTB_PULSE_DURATION_4_5ms      (1 << 2)
+#define PORTB_PULSE_DURATION_6ms        (2 << 2)
+#define PORTB_PULSE_DURATION_100ms      (3 << 2)
+#define PORTB_HOTPLUG_NO_DETECT         (0)
+#define PORTB_HOTPLUG_SHORT_DETECT      (1 << 0)
+#define PORTB_HOTPLUG_LONG_DETECT       (1 << 1)
+
+#define PCH_GPIOA               0xc5010
+#define PCH_GPIOB               0xc5014
+#define PCH_GPIOC               0xc5018
+#define PCH_GPIOD               0xc501c
+#define PCH_GPIOE               0xc5020
+#define PCH_GPIOF               0xc5024
+
+#define PCH_DPLL_A              0xc6014
+#define PCH_DPLL_B              0xc6018
+
+#define PCH_FPA0                0xc6040
+#define PCH_FPA1                0xc6044
+#define PCH_FPB0                0xc6048
+#define PCH_FPB1                0xc604c
+
+#define PCH_DPLL_TEST           0xc606c
+
+#define PCH_DREF_CONTROL        0xC6200
+#define  DREF_CONTROL_MASK      0x7fc3
+#define  DREF_CPU_SOURCE_OUTPUT_DISABLE         (0<<13)
+#define  DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD      (2<<13)
+#define  DREF_CPU_SOURCE_OUTPUT_NONSPREAD       (3<<13)
+#define  DREF_CPU_SOURCE_OUTPUT_MASK           (3<<13)
+#define  DREF_SSC_SOURCE_DISABLE                (0<<11)
+#define  DREF_SSC_SOURCE_ENABLE                 (2<<11)
+#define  DREF_SSC_SOURCE_MASK                  (2<<11)
+#define  DREF_NONSPREAD_SOURCE_DISABLE          (0<<9)
+#define  DREF_NONSPREAD_CK505_ENABLE           (1<<9)
+#define  DREF_NONSPREAD_SOURCE_ENABLE           (2<<9)
+#define  DREF_NONSPREAD_SOURCE_MASK            (2<<9)
+#define  DREF_SUPERSPREAD_SOURCE_DISABLE        (0<<7)
+#define  DREF_SUPERSPREAD_SOURCE_ENABLE         (2<<7)
+#define  DREF_SSC4_DOWNSPREAD                   (0<<6)
+#define  DREF_SSC4_CENTERSPREAD                 (1<<6)
+#define  DREF_SSC1_DISABLE                      (0<<1)
+#define  DREF_SSC1_ENABLE                       (1<<1)
+#define  DREF_SSC4_DISABLE                      (0)
+#define  DREF_SSC4_ENABLE                       (1)
+
+#define PCH_RAWCLK_FREQ         0xc6204
+#define  FDL_TP1_TIMER_SHIFT    12
+#define  FDL_TP1_TIMER_MASK     (3<<12)
+#define  FDL_TP2_TIMER_SHIFT    10
+#define  FDL_TP2_TIMER_MASK     (3<<10)
+#define  RAWCLK_FREQ_MASK       0x3ff
+
+#define PCH_DPLL_TMR_CFG        0xc6208
+
+#define PCH_SSC4_PARMS          0xc6210
+#define PCH_SSC4_AUX_PARMS      0xc6214
+
+/* transcoder */
+
+#define TRANS_HTOTAL_A          0xe0000
+#define  TRANS_HTOTAL_SHIFT     16
+#define  TRANS_HACTIVE_SHIFT    0
+#define TRANS_HBLANK_A          0xe0004
+#define  TRANS_HBLANK_END_SHIFT 16
+#define  TRANS_HBLANK_START_SHIFT 0
+#define TRANS_HSYNC_A           0xe0008
+#define  TRANS_HSYNC_END_SHIFT  16
+#define  TRANS_HSYNC_START_SHIFT 0
+#define TRANS_VTOTAL_A          0xe000c
+#define  TRANS_VTOTAL_SHIFT     16
+#define  TRANS_VACTIVE_SHIFT    0
+#define TRANS_VBLANK_A          0xe0010
+#define  TRANS_VBLANK_END_SHIFT 16
+#define  TRANS_VBLANK_START_SHIFT 0
+#define TRANS_VSYNC_A           0xe0014
+#define  TRANS_VSYNC_END_SHIFT  16
+#define  TRANS_VSYNC_START_SHIFT 0
+
+#define TRANSA_DATA_M1          0xe0030
+#define TRANSA_DATA_N1          0xe0034
+#define TRANSA_DATA_M2          0xe0038
+#define TRANSA_DATA_N2          0xe003c
+#define TRANSA_DP_LINK_M1       0xe0040
+#define TRANSA_DP_LINK_N1       0xe0044
+#define TRANSA_DP_LINK_M2       0xe0048
+#define TRANSA_DP_LINK_N2       0xe004c
+
+#define TRANS_HTOTAL_B          0xe1000
+#define TRANS_HBLANK_B          0xe1004
+#define TRANS_HSYNC_B           0xe1008
+#define TRANS_VTOTAL_B          0xe100c
+#define TRANS_VBLANK_B          0xe1010
+#define TRANS_VSYNC_B           0xe1014
+
+#define TRANSB_DATA_M1          0xe1030
+#define TRANSB_DATA_N1          0xe1034
+#define TRANSB_DATA_M2          0xe1038
+#define TRANSB_DATA_N2          0xe103c
+#define TRANSB_DP_LINK_M1       0xe1040
+#define TRANSB_DP_LINK_N1       0xe1044
+#define TRANSB_DP_LINK_M2       0xe1048
+#define TRANSB_DP_LINK_N2       0xe104c
+
+#define TRANSACONF              0xf0008
+#define TRANSBCONF              0xf1008
+#define  TRANS_DISABLE          (0<<31)
+#define  TRANS_ENABLE           (1<<31)
+#define  TRANS_STATE_MASK       (1<<30)
+#define  TRANS_STATE_DISABLE    (0<<30)
+#define  TRANS_STATE_ENABLE     (1<<30)
+#define  TRANS_FSYNC_DELAY_HB1  (0<<27)
+#define  TRANS_FSYNC_DELAY_HB2  (1<<27)
+#define  TRANS_FSYNC_DELAY_HB3  (2<<27)
+#define  TRANS_FSYNC_DELAY_HB4  (3<<27)
+#define  TRANS_DP_AUDIO_ONLY    (1<<26)
+#define  TRANS_DP_VIDEO_AUDIO   (0<<26)
+#define  TRANS_PROGRESSIVE      (0<<21)
+#define  TRANS_8BPC             (0<<5)
+#define  TRANS_10BPC            (1<<5)
+#define  TRANS_6BPC             (2<<5)
+#define  TRANS_12BPC            (3<<5)
+
+#define FDI_RXA_CHICKEN         0xc200c
+#define FDI_RXB_CHICKEN         0xc2010
+#define  FDI_RX_PHASE_SYNC_POINTER_ENABLE       (1)
+
+/* CPU: FDI_TX */
+#define FDI_TXA_CTL             0x60100
+#define FDI_TXB_CTL             0x61100
+#define  FDI_TX_DISABLE         (0<<31)
+#define  FDI_TX_ENABLE          (1<<31)
+#define  FDI_LINK_TRAIN_PATTERN_1       (0<<28)
+#define  FDI_LINK_TRAIN_PATTERN_2       (1<<28)
+#define  FDI_LINK_TRAIN_PATTERN_IDLE    (2<<28)
+#define  FDI_LINK_TRAIN_NONE            (3<<28)
+#define  FDI_LINK_TRAIN_VOLTAGE_0_4V    (0<<25)
+#define  FDI_LINK_TRAIN_VOLTAGE_0_6V    (1<<25)
+#define  FDI_LINK_TRAIN_VOLTAGE_0_8V    (2<<25)
+#define  FDI_LINK_TRAIN_VOLTAGE_1_2V    (3<<25)
+#define  FDI_LINK_TRAIN_PRE_EMPHASIS_NONE (0<<22)
+#define  FDI_LINK_TRAIN_PRE_EMPHASIS_1_5X (1<<22)
+#define  FDI_LINK_TRAIN_PRE_EMPHASIS_2X   (2<<22)
+#define  FDI_LINK_TRAIN_PRE_EMPHASIS_3X   (3<<22)
+#define  FDI_DP_PORT_WIDTH_X1           (0<<19)
+#define  FDI_DP_PORT_WIDTH_X2           (1<<19)
+#define  FDI_DP_PORT_WIDTH_X3           (2<<19)
+#define  FDI_DP_PORT_WIDTH_X4           (3<<19)
+#define  FDI_TX_ENHANCE_FRAME_ENABLE    (1<<18)
+/* IGDNG: hardwired to 1 */
+#define  FDI_TX_PLL_ENABLE              (1<<14)
+/* both Tx and Rx */
+#define  FDI_SCRAMBLING_ENABLE          (0<<7)
+#define  FDI_SCRAMBLING_DISABLE         (1<<7)
+
+/* FDI_RX, FDI_X is hard-wired to Transcoder_X */
+#define FDI_RXA_CTL             0xf000c
+#define FDI_RXB_CTL             0xf100c
+#define  FDI_RX_ENABLE          (1<<31)
+#define  FDI_RX_DISABLE         (0<<31)
+/* train, dp width same as FDI_TX */
+#define  FDI_DP_PORT_WIDTH_X8           (7<<19)
+#define  FDI_8BPC                       (0<<16)
+#define  FDI_10BPC                      (1<<16)
+#define  FDI_6BPC                       (2<<16)
+#define  FDI_12BPC                      (3<<16)
+#define  FDI_LINK_REVERSE_OVERWRITE     (1<<15)
+#define  FDI_DMI_LINK_REVERSE_MASK      (1<<14)
+#define  FDI_RX_PLL_ENABLE              (1<<13)
+#define  FDI_FS_ERR_CORRECT_ENABLE      (1<<11)
+#define  FDI_FE_ERR_CORRECT_ENABLE      (1<<10)
+#define  FDI_FS_ERR_REPORT_ENABLE       (1<<9)
+#define  FDI_FE_ERR_REPORT_ENABLE       (1<<8)
+#define  FDI_RX_ENHANCE_FRAME_ENABLE    (1<<6)
+#define  FDI_SEL_RAWCLK                 (0<<4)
+#define  FDI_SEL_PCDCLK                 (1<<4)
+
+#define FDI_RXA_MISC            0xf0010
+#define FDI_RXB_MISC            0xf1010
+#define FDI_RXA_TUSIZE1         0xf0030
+#define FDI_RXA_TUSIZE2         0xf0038
+#define FDI_RXB_TUSIZE1         0xf1030
+#define FDI_RXB_TUSIZE2         0xf1038
+
+/* FDI_RX interrupt register format */
+#define FDI_RX_INTER_LANE_ALIGN         (1<<10)
+#define FDI_RX_SYMBOL_LOCK              (1<<9) /* train 2 */
+#define FDI_RX_BIT_LOCK                 (1<<8) /* train 1 */
+#define FDI_RX_TRAIN_PATTERN_2_FAIL     (1<<7)
+#define FDI_RX_FS_CODE_ERR              (1<<6)
+#define FDI_RX_FE_CODE_ERR              (1<<5)
+#define FDI_RX_SYMBOL_ERR_RATE_ABOVE    (1<<4)
+#define FDI_RX_HDCP_LINK_FAIL           (1<<3)
+#define FDI_RX_PIXEL_FIFO_OVERFLOW      (1<<2)
+#define FDI_RX_CROSS_CLOCK_OVERFLOW     (1<<1)
+#define FDI_RX_SYMBOL_QUEUE_OVERFLOW    (1<<0)
+
+#define FDI_RXA_IIR             0xf0014
+#define FDI_RXA_IMR             0xf0018
+#define FDI_RXB_IIR             0xf1014
+#define FDI_RXB_IMR             0xf1018
+
+#define FDI_PLL_CTL_1           0xfe000
+#define FDI_PLL_CTL_2           0xfe004
+
+/* CRT */
+#define PCH_ADPA                0xe1100
+#define  ADPA_TRANS_SELECT_MASK (1<<30)
+#define  ADPA_TRANS_A_SELECT    0
+#define  ADPA_TRANS_B_SELECT    (1<<30)
+#define  ADPA_CRT_HOTPLUG_MASK  0x03ff0000 /* bit 25-16 */
+#define  ADPA_CRT_HOTPLUG_MONITOR_NONE  (0<<24)
+#define  ADPA_CRT_HOTPLUG_MONITOR_MASK  (3<<24)
+#define  ADPA_CRT_HOTPLUG_MONITOR_COLOR (3<<24)
+#define  ADPA_CRT_HOTPLUG_MONITOR_MONO  (2<<24)
+#define  ADPA_CRT_HOTPLUG_ENABLE        (1<<23)
+#define  ADPA_CRT_HOTPLUG_PERIOD_64     (0<<22)
+#define  ADPA_CRT_HOTPLUG_PERIOD_128    (1<<22)
+#define  ADPA_CRT_HOTPLUG_WARMUP_5MS    (0<<21)
+#define  ADPA_CRT_HOTPLUG_WARMUP_10MS   (1<<21)
+#define  ADPA_CRT_HOTPLUG_SAMPLE_2S     (0<<20)
+#define  ADPA_CRT_HOTPLUG_SAMPLE_4S     (1<<20)
+#define  ADPA_CRT_HOTPLUG_VOLTAGE_40    (0<<18)
+#define  ADPA_CRT_HOTPLUG_VOLTAGE_50    (1<<18)
+#define  ADPA_CRT_HOTPLUG_VOLTAGE_60    (2<<18)
+#define  ADPA_CRT_HOTPLUG_VOLTAGE_70    (3<<18)
+#define  ADPA_CRT_HOTPLUG_VOLREF_325MV  (0<<17)
+#define  ADPA_CRT_HOTPLUG_VOLREF_475MV  (1<<17)
+#define  ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1<<16)
+
+/* or SDVOB */
+#define HDMIB   0xe1140
+#define  PORT_ENABLE    (1 << 31)
+#define  TRANSCODER_A   (0)
+#define  TRANSCODER_B   (1 << 30)
+#define  COLOR_FORMAT_8bpc      (0)
+#define  COLOR_FORMAT_12bpc     (3 << 26)
+#define  SDVOB_HOTPLUG_ENABLE   (1 << 23)
+#define  SDVO_ENCODING          (0)
+#define  TMDS_ENCODING          (2 << 10)
+#define  NULL_PACKET_VSYNC_ENABLE       (1 << 9)
+#define  SDVOB_BORDER_ENABLE    (1 << 7)
+#define  AUDIO_ENABLE           (1 << 6)
+#define  VSYNC_ACTIVE_HIGH      (1 << 4)
+#define  HSYNC_ACTIVE_HIGH      (1 << 3)
+#define  PORT_DETECTED          (1 << 2)
+
+#define HDMIC   0xe1150
+#define HDMID   0xe1160
+
+#define PCH_LVDS       0xe1180
+#define  LVDS_DETECTED (1 << 1)
+
+#define BLC_PWM_CPU_CTL2       0x48250
+#define  PWM_ENABLE            (1 << 31)
+#define  PWM_PIPE_A            (0 << 29)
+#define  PWM_PIPE_B            (1 << 29)
+#define BLC_PWM_CPU_CTL                0x48254
+
+#define BLC_PWM_PCH_CTL1       0xc8250
+#define  PWM_PCH_ENABLE                (1 << 31)
+#define  PWM_POLARITY_ACTIVE_LOW       (1 << 29)
+#define  PWM_POLARITY_ACTIVE_HIGH      (0 << 29)
+#define  PWM_POLARITY_ACTIVE_LOW2      (1 << 28)
+#define  PWM_POLARITY_ACTIVE_HIGH2     (0 << 28)
+
+#define BLC_PWM_PCH_CTL2       0xc8254
+
+#define PCH_PP_STATUS          0xc7200
+#define PCH_PP_CONTROL         0xc7204
+#define  EDP_FORCE_VDD         (1 << 3)
+#define  EDP_BLC_ENABLE                (1 << 2)
+#define  PANEL_POWER_RESET     (1 << 1)
+#define  PANEL_POWER_OFF       (0 << 0)
+#define  PANEL_POWER_ON                (1 << 0)
+#define PCH_PP_ON_DELAYS       0xc7208
+#define  EDP_PANEL             (1 << 30)
+#define PCH_PP_OFF_DELAYS      0xc720c
+#define PCH_PP_DIVISOR         0xc7210
+
 #endif /* _I915_REG_H_ */
index ce8a21344a71e14add15215c318577fbdb569648..a98e2831ed31787ee6985fb058bdc3d32725367c 100644 (file)
@@ -295,6 +295,16 @@ int i915_save_state(struct drm_device *dev)
        i915_save_palette(dev, PIPE_B);
        dev_priv->savePIPEBSTAT = I915_READ(PIPEBSTAT);
 
+       /* Cursor state */
+       dev_priv->saveCURACNTR = I915_READ(CURACNTR);
+       dev_priv->saveCURAPOS = I915_READ(CURAPOS);
+       dev_priv->saveCURABASE = I915_READ(CURABASE);
+       dev_priv->saveCURBCNTR = I915_READ(CURBCNTR);
+       dev_priv->saveCURBPOS = I915_READ(CURBPOS);
+       dev_priv->saveCURBBASE = I915_READ(CURBBASE);
+       if (!IS_I9XX(dev))
+               dev_priv->saveCURSIZE = I915_READ(CURSIZE);
+
        /* CRT state */
        dev_priv->saveADPA = I915_READ(ADPA);
 
@@ -480,6 +490,16 @@ int i915_restore_state(struct drm_device *dev)
        I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR);
        I915_WRITE(DSPBADDR, I915_READ(DSPBADDR));
 
+       /* Cursor state */
+       I915_WRITE(CURAPOS, dev_priv->saveCURAPOS);
+       I915_WRITE(CURACNTR, dev_priv->saveCURACNTR);
+       I915_WRITE(CURABASE, dev_priv->saveCURABASE);
+       I915_WRITE(CURBPOS, dev_priv->saveCURBPOS);
+       I915_WRITE(CURBCNTR, dev_priv->saveCURBCNTR);
+       I915_WRITE(CURBBASE, dev_priv->saveCURBBASE);
+       if (!IS_I9XX(dev))
+               I915_WRITE(CURSIZE, dev_priv->saveCURSIZE);
+
        /* CRT state */
        I915_WRITE(ADPA, dev_priv->saveADPA);
 
index 9d78cff33b2478198a72646e183544fafa1aec8d..754dd22fdd778f4f1ba0bab2deb10a51f40ba9df 100644 (file)
@@ -30,6 +30,8 @@
 #include "i915_drv.h"
 #include "intel_bios.h"
 
+#define        SLAVE_ADDR1     0x70
+#define        SLAVE_ADDR2     0x72
 
 static void *
 find_section(struct bdb_header *bdb, int section_id)
@@ -193,6 +195,88 @@ parse_general_features(struct drm_i915_private *dev_priv,
        }
 }
 
+static void
+parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
+                      struct bdb_header *bdb)
+{
+       struct sdvo_device_mapping *p_mapping;
+       struct bdb_general_definitions *p_defs;
+       struct child_device_config *p_child;
+       int i, child_device_num, count;
+       u16     block_size, *block_ptr;
+
+       p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
+       if (!p_defs) {
+               DRM_DEBUG("No general definition block is found\n");
+               return;
+       }
+       /* judge whether the size of child device meets the requirements.
+        * If the child device size obtained from general definition block
+        * is different with sizeof(struct child_device_config), skip the
+        * parsing of sdvo device info
+        */
+       if (p_defs->child_dev_size != sizeof(*p_child)) {
+               /* different child dev size . Ignore it */
+               DRM_DEBUG("different child size is found. Invalid.\n");
+               return;
+       }
+       /* get the block size of general definitions */
+       block_ptr = (u16 *)((char *)p_defs - 2);
+       block_size = *block_ptr;
+       /* get the number of child device */
+       child_device_num = (block_size - sizeof(*p_defs)) /
+                               sizeof(*p_child);
+       count = 0;
+       for (i = 0; i < child_device_num; i++) {
+               p_child = &(p_defs->devices[i]);
+               if (!p_child->device_type) {
+                       /* skip the device block if device type is invalid */
+                       continue;
+               }
+               if (p_child->slave_addr != SLAVE_ADDR1 &&
+                       p_child->slave_addr != SLAVE_ADDR2) {
+                       /*
+                        * If the slave address is neither 0x70 nor 0x72,
+                        * it is not a SDVO device. Skip it.
+                        */
+                       continue;
+               }
+               if (p_child->dvo_port != DEVICE_PORT_DVOB &&
+                       p_child->dvo_port != DEVICE_PORT_DVOC) {
+                       /* skip the incorrect SDVO port */
+                       DRM_DEBUG("Incorrect SDVO port. Skip it \n");
+                       continue;
+               }
+               DRM_DEBUG("the SDVO device with slave addr %2x is found on "
+                               "%s port\n",
+                               p_child->slave_addr,
+                               (p_child->dvo_port == DEVICE_PORT_DVOB) ?
+                                       "SDVOB" : "SDVOC");
+               p_mapping = &(dev_priv->sdvo_mappings[p_child->dvo_port - 1]);
+               if (!p_mapping->initialized) {
+                       p_mapping->dvo_port = p_child->dvo_port;
+                       p_mapping->slave_addr = p_child->slave_addr;
+                       p_mapping->dvo_wiring = p_child->dvo_wiring;
+                       p_mapping->initialized = 1;
+               } else {
+                       DRM_DEBUG("Maybe one SDVO port is shared by "
+                                        "two SDVO device.\n");
+               }
+               if (p_child->slave2_addr) {
+                       /* Maybe this is a SDVO device with multiple inputs */
+                       /* And the mapping info is not added */
+                       DRM_DEBUG("there exists the slave2_addr. Maybe this "
+                               "is a SDVO device with multiple inputs.\n");
+               }
+               count++;
+       }
+
+       if (!count) {
+               /* No SDVO device info is found */
+               DRM_DEBUG("No SDVO device info is found in VBT\n");
+       }
+       return;
+}
 /**
  * intel_init_bios - initialize VBIOS settings & find VBT
  * @dev: DRM device
@@ -242,7 +326,7 @@ intel_init_bios(struct drm_device *dev)
        parse_general_features(dev_priv, bdb);
        parse_lfp_panel_data(dev_priv, bdb);
        parse_sdvo_panel_data(dev_priv, bdb);
-
+       parse_sdvo_device_mapping(dev_priv, bdb);
        pci_unmap_rom(pdev, bios);
 
        return 0;
index 8ca2cde15804598374acf140671db2747bdd0010..fe72e1c225d8ab1085a752f3ccbf6d298c44fca3 100644 (file)
@@ -135,6 +135,86 @@ struct bdb_general_features {
        u8 rsvd11:6; /* finish byte */
 } __attribute__((packed));
 
+/* pre-915 */
+#define GPIO_PIN_DVI_LVDS      0x03 /* "DVI/LVDS DDC GPIO pins" */
+#define GPIO_PIN_ADD_I2C       0x05 /* "ADDCARD I2C GPIO pins" */
+#define GPIO_PIN_ADD_DDC       0x04 /* "ADDCARD DDC GPIO pins" */
+#define GPIO_PIN_ADD_DDC_I2C   0x06 /* "ADDCARD DDC/I2C GPIO pins" */
+
+/* Pre 915 */
+#define DEVICE_TYPE_NONE       0x00
+#define DEVICE_TYPE_CRT                0x01
+#define DEVICE_TYPE_TV         0x09
+#define DEVICE_TYPE_EFP                0x12
+#define DEVICE_TYPE_LFP                0x22
+/* On 915+ */
+#define DEVICE_TYPE_CRT_DPMS           0x6001
+#define DEVICE_TYPE_CRT_DPMS_HOTPLUG   0x4001
+#define DEVICE_TYPE_TV_COMPOSITE       0x0209
+#define DEVICE_TYPE_TV_MACROVISION     0x0289
+#define DEVICE_TYPE_TV_RF_COMPOSITE    0x020c
+#define DEVICE_TYPE_TV_SVIDEO_COMPOSITE        0x0609
+#define DEVICE_TYPE_TV_SCART           0x0209
+#define DEVICE_TYPE_TV_CODEC_HOTPLUG_PWR 0x6009
+#define DEVICE_TYPE_EFP_HOTPLUG_PWR    0x6012
+#define DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR        0x6052
+#define DEVICE_TYPE_EFP_DVI_I          0x6053
+#define DEVICE_TYPE_EFP_DVI_D_DUAL     0x6152
+#define DEVICE_TYPE_EFP_DVI_D_HDCP     0x60d2
+#define DEVICE_TYPE_OPENLDI_HOTPLUG_PWR        0x6062
+#define DEVICE_TYPE_OPENLDI_DUALPIX    0x6162
+#define DEVICE_TYPE_LFP_PANELLINK      0x5012
+#define DEVICE_TYPE_LFP_CMOS_PWR       0x5042
+#define DEVICE_TYPE_LFP_LVDS_PWR       0x5062
+#define DEVICE_TYPE_LFP_LVDS_DUAL      0x5162
+#define DEVICE_TYPE_LFP_LVDS_DUAL_HDCP 0x51e2
+
+#define DEVICE_CFG_NONE                0x00
+#define DEVICE_CFG_12BIT_DVOB  0x01
+#define DEVICE_CFG_12BIT_DVOC  0x02
+#define DEVICE_CFG_24BIT_DVOBC 0x09
+#define DEVICE_CFG_24BIT_DVOCB 0x0a
+#define DEVICE_CFG_DUAL_DVOB   0x11
+#define DEVICE_CFG_DUAL_DVOC   0x12
+#define DEVICE_CFG_DUAL_DVOBC  0x13
+#define DEVICE_CFG_DUAL_LINK_DVOBC     0x19
+#define DEVICE_CFG_DUAL_LINK_DVOCB     0x1a
+
+#define DEVICE_WIRE_NONE       0x00
+#define DEVICE_WIRE_DVOB       0x01
+#define DEVICE_WIRE_DVOC       0x02
+#define DEVICE_WIRE_DVOBC      0x03
+#define DEVICE_WIRE_DVOBB      0x05
+#define DEVICE_WIRE_DVOCC      0x06
+#define DEVICE_WIRE_DVOB_MASTER 0x0d
+#define DEVICE_WIRE_DVOC_MASTER 0x0e
+
+#define DEVICE_PORT_DVOA       0x00 /* none on 845+ */
+#define DEVICE_PORT_DVOB       0x01
+#define DEVICE_PORT_DVOC       0x02
+
+struct child_device_config {
+       u16 handle;
+       u16 device_type;
+       u8  device_id[10]; /* See DEVICE_TYPE_* above */
+       u16 addin_offset;
+       u8  dvo_port; /* See Device_PORT_* above */
+       u8  i2c_pin;
+       u8  slave_addr;
+       u8  ddc_pin;
+       u16 edid_ptr;
+       u8  dvo_cfg; /* See DEVICE_CFG_* above */
+       u8  dvo2_port;
+       u8  i2c2_pin;
+       u8  slave2_addr;
+       u8  ddc2_pin;
+       u8  capabilities;
+       u8  dvo_wiring;/* See DEVICE_WIRE_* above */
+       u8  dvo2_wiring;
+       u16 extended_type;
+       u8  dvo_function;
+} __attribute__((packed));
+
 struct bdb_general_definitions {
        /* DDC GPIO */
        u8 crt_ddc_gmbus_pin;
@@ -149,14 +229,19 @@ struct bdb_general_definitions {
        u8 boot_display[2];
        u8 child_dev_size;
 
-       /* device info */
-       u8 tv_or_lvds_info[33];
-       u8 dev1[33];
-       u8 dev2[33];
-       u8 dev3[33];
-       u8 dev4[33];
-       /* may be another device block here on some platforms */
-};
+       /*
+        * Device info:
+        * If TV is present, it'll be at devices[0].
+        * LVDS will be next, either devices[0] or [1], if present.
+        * On some platforms the number of device is 6. But could be as few as
+        * 4 if both TV and LVDS are missing.
+        * And the device num is related with the size of general definition
+        * block. It is obtained by using the following formula:
+        * number = (block_size - sizeof(bdb_general_definitions))/
+        *              sizeof(child_device_config);
+        */
+       struct child_device_config devices[0];
+} __attribute__((packed));
 
 struct bdb_lvds_options {
        u8 panel_type;
index 79acc4f4c1f803911ba7a99c72846b1f9f0b2db3..6de97fc66029ed2f28707649f65dfd19ea87d042 100644 (file)
@@ -37,9 +37,14 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
 {
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 temp;
+       u32 temp, reg;
 
-       temp = I915_READ(ADPA);
+       if (IS_IGDNG(dev))
+               reg = PCH_ADPA;
+       else
+               reg = ADPA;
+
+       temp = I915_READ(reg);
        temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
        temp |= ADPA_DAC_ENABLE;
 
@@ -58,7 +63,7 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
                break;
        }
 
-       I915_WRITE(ADPA, temp);
+       I915_WRITE(reg, temp);
 }
 
 static int intel_crt_mode_valid(struct drm_connector *connector,
@@ -101,17 +106,23 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
        struct drm_i915_private *dev_priv = dev->dev_private;
        int dpll_md_reg;
        u32 adpa, dpll_md;
+       u32 adpa_reg;
 
        if (intel_crtc->pipe == 0)
                dpll_md_reg = DPLL_A_MD;
        else
                dpll_md_reg = DPLL_B_MD;
 
+       if (IS_IGDNG(dev))
+               adpa_reg = PCH_ADPA;
+       else
+               adpa_reg = ADPA;
+
        /*
         * Disable separate mode multiplier used when cloning SDVO to CRT
         * XXX this needs to be adjusted when we really are cloning
         */
-       if (IS_I965G(dev)) {
+       if (IS_I965G(dev) && !IS_IGDNG(dev)) {
                dpll_md = I915_READ(dpll_md_reg);
                I915_WRITE(dpll_md_reg,
                           dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
@@ -125,13 +136,53 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
 
        if (intel_crtc->pipe == 0) {
                adpa |= ADPA_PIPE_A_SELECT;
-               I915_WRITE(BCLRPAT_A, 0);
+               if (!IS_IGDNG(dev))
+                       I915_WRITE(BCLRPAT_A, 0);
        } else {
                adpa |= ADPA_PIPE_B_SELECT;
-               I915_WRITE(BCLRPAT_B, 0);
+               if (!IS_IGDNG(dev))
+                       I915_WRITE(BCLRPAT_B, 0);
        }
 
-       I915_WRITE(ADPA, adpa);
+       I915_WRITE(adpa_reg, adpa);
+}
+
+static bool intel_igdng_crt_detect_hotplug(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 adpa, temp;
+       bool ret;
+
+       temp = adpa = I915_READ(PCH_ADPA);
+
+       adpa &= ~ADPA_CRT_HOTPLUG_MASK;
+
+       adpa |= (ADPA_CRT_HOTPLUG_PERIOD_128 |
+                       ADPA_CRT_HOTPLUG_WARMUP_10MS |
+                       ADPA_CRT_HOTPLUG_SAMPLE_4S |
+                       ADPA_CRT_HOTPLUG_VOLTAGE_50 | /* default */
+                       ADPA_CRT_HOTPLUG_VOLREF_325MV |
+                       ADPA_CRT_HOTPLUG_ENABLE |
+                       ADPA_CRT_HOTPLUG_FORCE_TRIGGER);
+
+       DRM_DEBUG("pch crt adpa 0x%x", adpa);
+       I915_WRITE(PCH_ADPA, adpa);
+
+       /* This might not be needed as not specified in spec...*/
+       udelay(1000);
+
+       /* Check the status to see if both blue and green are on now */
+       adpa = I915_READ(PCH_ADPA);
+       if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) ==
+                       ADPA_CRT_HOTPLUG_MONITOR_COLOR)
+               ret = true;
+       else
+               ret = false;
+
+       /* restore origin register */
+       I915_WRITE(PCH_ADPA, temp);
+       return ret;
 }
 
 /**
@@ -148,6 +199,10 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 hotplug_en;
        int i, tries = 0;
+
+       if (IS_IGDNG(dev))
+               return intel_igdng_crt_detect_hotplug(connector);
+
        /*
         * On 4 series desktop, CRT detect sequence need to be done twice
         * to get a reliable result.
@@ -423,6 +478,7 @@ void intel_crt_init(struct drm_device *dev)
 {
        struct drm_connector *connector;
        struct intel_output *intel_output;
+       u32 i2c_reg;
 
        intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL);
        if (!intel_output)
@@ -439,7 +495,11 @@ void intel_crt_init(struct drm_device *dev)
                                          &intel_output->enc);
 
        /* Set up the DDC bus. */
-       intel_output->ddc_bus = intel_i2c_create(dev, GPIOA, "CRTDDC_A");
+       if (IS_IGDNG(dev))
+               i2c_reg = PCH_GPIOA;
+       else
+               i2c_reg = GPIOA;
+       intel_output->ddc_bus = intel_i2c_create(dev, i2c_reg, "CRTDDC_A");
        if (!intel_output->ddc_bus) {
                dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
                           "failed.\n");
index c9d6f10ba92eb833620d1c686c234ffc574eb81a..028f5b66e3d83eaedd66eeaea168ca68cde185ef 100644 (file)
@@ -137,6 +137,8 @@ struct intel_limit {
 #define INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS   7
 #define INTEL_LIMIT_IGD_SDVO_DAC    8
 #define INTEL_LIMIT_IGD_LVDS       9
+#define INTEL_LIMIT_IGDNG_SDVO_DAC  10
+#define INTEL_LIMIT_IGDNG_LVDS     11
 
 /*The parameter is for SDVO on G4x platform*/
 #define G4X_DOT_SDVO_MIN           25000
@@ -216,12 +218,43 @@ struct intel_limit {
 #define G4X_P2_DUAL_CHANNEL_LVDS_FAST           7
 #define G4X_P2_DUAL_CHANNEL_LVDS_LIMIT          0
 
+/* IGDNG */
+/* as we calculate clock using (register_value + 2) for
+   N/M1/M2, so here the range value for them is (actual_value-2).
+ */
+#define IGDNG_DOT_MIN         25000
+#define IGDNG_DOT_MAX         350000
+#define IGDNG_VCO_MIN         1760000
+#define IGDNG_VCO_MAX         3510000
+#define IGDNG_N_MIN           1
+#define IGDNG_N_MAX           5
+#define IGDNG_M_MIN           79
+#define IGDNG_M_MAX           118
+#define IGDNG_M1_MIN          12
+#define IGDNG_M1_MAX          23
+#define IGDNG_M2_MIN          5
+#define IGDNG_M2_MAX          9
+#define IGDNG_P_SDVO_DAC_MIN  5
+#define IGDNG_P_SDVO_DAC_MAX  80
+#define IGDNG_P_LVDS_MIN      28
+#define IGDNG_P_LVDS_MAX      112
+#define IGDNG_P1_MIN          1
+#define IGDNG_P1_MAX          8
+#define IGDNG_P2_SDVO_DAC_SLOW 10
+#define IGDNG_P2_SDVO_DAC_FAST 5
+#define IGDNG_P2_LVDS_SLOW    14 /* single channel */
+#define IGDNG_P2_LVDS_FAST    7  /* double channel */
+#define IGDNG_P2_DOT_LIMIT    225000 /* 225Mhz */
+
 static bool
 intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
                    int target, int refclk, intel_clock_t *best_clock);
 static bool
 intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
                        int target, int refclk, intel_clock_t *best_clock);
+static bool
+intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
+                       int target, int refclk, intel_clock_t *best_clock);
 
 static const intel_limit_t intel_limits[] = {
     { /* INTEL_LIMIT_I8XX_DVO_DAC */
@@ -383,9 +416,47 @@ static const intel_limit_t intel_limits[] = {
                 .p2_slow = I9XX_P2_LVDS_SLOW,  .p2_fast = I9XX_P2_LVDS_SLOW },
        .find_pll = intel_find_best_PLL,
     },
-
+    { /* INTEL_LIMIT_IGDNG_SDVO_DAC */
+       .dot = { .min = IGDNG_DOT_MIN,          .max = IGDNG_DOT_MAX },
+       .vco = { .min = IGDNG_VCO_MIN,          .max = IGDNG_VCO_MAX },
+       .n   = { .min = IGDNG_N_MIN,            .max = IGDNG_N_MAX },
+       .m   = { .min = IGDNG_M_MIN,            .max = IGDNG_M_MAX },
+       .m1  = { .min = IGDNG_M1_MIN,           .max = IGDNG_M1_MAX },
+       .m2  = { .min = IGDNG_M2_MIN,           .max = IGDNG_M2_MAX },
+       .p   = { .min = IGDNG_P_SDVO_DAC_MIN,   .max = IGDNG_P_SDVO_DAC_MAX },
+       .p1  = { .min = IGDNG_P1_MIN,           .max = IGDNG_P1_MAX },
+       .p2  = { .dot_limit = IGDNG_P2_DOT_LIMIT,
+                .p2_slow = IGDNG_P2_SDVO_DAC_SLOW,
+                .p2_fast = IGDNG_P2_SDVO_DAC_FAST },
+       .find_pll = intel_igdng_find_best_PLL,
+    },
+    { /* INTEL_LIMIT_IGDNG_LVDS */
+       .dot = { .min = IGDNG_DOT_MIN,          .max = IGDNG_DOT_MAX },
+       .vco = { .min = IGDNG_VCO_MIN,          .max = IGDNG_VCO_MAX },
+       .n   = { .min = IGDNG_N_MIN,            .max = IGDNG_N_MAX },
+       .m   = { .min = IGDNG_M_MIN,            .max = IGDNG_M_MAX },
+       .m1  = { .min = IGDNG_M1_MIN,           .max = IGDNG_M1_MAX },
+       .m2  = { .min = IGDNG_M2_MIN,           .max = IGDNG_M2_MAX },
+       .p   = { .min = IGDNG_P_LVDS_MIN,       .max = IGDNG_P_LVDS_MAX },
+       .p1  = { .min = IGDNG_P1_MIN,           .max = IGDNG_P1_MAX },
+       .p2  = { .dot_limit = IGDNG_P2_DOT_LIMIT,
+                .p2_slow = IGDNG_P2_LVDS_SLOW,
+                .p2_fast = IGDNG_P2_LVDS_FAST },
+       .find_pll = intel_igdng_find_best_PLL,
+    },
 };
 
+static const intel_limit_t *intel_igdng_limit(struct drm_crtc *crtc)
+{
+       const intel_limit_t *limit;
+       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
+               limit = &intel_limits[INTEL_LIMIT_IGDNG_LVDS];
+       else
+               limit = &intel_limits[INTEL_LIMIT_IGDNG_SDVO_DAC];
+
+       return limit;
+}
+
 static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
@@ -418,7 +489,9 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc)
        struct drm_device *dev = crtc->dev;
        const intel_limit_t *limit;
 
-       if (IS_G4X(dev)) {
+       if (IS_IGDNG(dev))
+               limit = intel_igdng_limit(crtc);
+       else if (IS_G4X(dev)) {
                limit = intel_g4x_limit(crtc);
        } else if (IS_I9XX(dev) && !IS_IGD(dev)) {
                if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
@@ -630,7 +703,64 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
                        }
                }
        }
+       return found;
+}
 
+static bool
+intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
+                       int target, int refclk, intel_clock_t *best_clock)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       intel_clock_t clock;
+       int max_n;
+       bool found;
+       int err_most = 47;
+       found = false;
+
+       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
+               if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
+                   LVDS_CLKB_POWER_UP)
+                       clock.p2 = limit->p2.p2_fast;
+               else
+                       clock.p2 = limit->p2.p2_slow;
+       } else {
+               if (target < limit->p2.dot_limit)
+                       clock.p2 = limit->p2.p2_slow;
+               else
+                       clock.p2 = limit->p2.p2_fast;
+       }
+
+       memset(best_clock, 0, sizeof(*best_clock));
+       max_n = limit->n.max;
+       /* based on hardware requriment prefer smaller n to precision */
+       for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) {
+               /* based on hardware requirment prefere larger m1,m2, p1 */
+               for (clock.m1 = limit->m1.max;
+                    clock.m1 >= limit->m1.min; clock.m1--) {
+                       for (clock.m2 = limit->m2.max;
+                            clock.m2 >= limit->m2.min; clock.m2--) {
+                               for (clock.p1 = limit->p1.max;
+                                    clock.p1 >= limit->p1.min; clock.p1--) {
+                                       int this_err;
+
+                                       intel_clock(dev, refclk, &clock);
+                                       if (!intel_PLL_is_valid(crtc, &clock))
+                                               continue;
+                                       this_err = abs((10000 - (target*10000/clock.dot)));
+                                       if (this_err < err_most) {
+                                               *best_clock = clock;
+                                               err_most = this_err;
+                                               max_n = clock.n;
+                                               found = true;
+                                               /* found on first matching */
+                                               goto out;
+                                       }
+                               }
+                       }
+               }
+       }
+out:
        return found;
 }
 
@@ -785,18 +915,292 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
        return 0;
 }
 
+static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       int plane = intel_crtc->pipe;
+       int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B;
+       int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
+       int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
+       int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR;
+       int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
+       int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
+       int fdi_rx_iir_reg = (pipe == 0) ? FDI_RXA_IIR : FDI_RXB_IIR;
+       int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
+       int transconf_reg = (pipe == 0) ? TRANSACONF : TRANSBCONF;
+       int pf_ctl_reg = (pipe == 0) ? PFA_CTL_1 : PFB_CTL_1;
+       int cpu_htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
+       int cpu_hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
+       int cpu_hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
+       int cpu_vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
+       int cpu_vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
+       int cpu_vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
+       int trans_htot_reg = (pipe == 0) ? TRANS_HTOTAL_A : TRANS_HTOTAL_B;
+       int trans_hblank_reg = (pipe == 0) ? TRANS_HBLANK_A : TRANS_HBLANK_B;
+       int trans_hsync_reg = (pipe == 0) ? TRANS_HSYNC_A : TRANS_HSYNC_B;
+       int trans_vtot_reg = (pipe == 0) ? TRANS_VTOTAL_A : TRANS_VTOTAL_B;
+       int trans_vblank_reg = (pipe == 0) ? TRANS_VBLANK_A : TRANS_VBLANK_B;
+       int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B;
+       u32 temp;
+       int tries = 5, j;
 
+       /* XXX: When our outputs are all unaware of DPMS modes other than off
+        * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
+        */
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+               DRM_DEBUG("crtc %d dpms on\n", pipe);
+               /* enable PCH DPLL */
+               temp = I915_READ(pch_dpll_reg);
+               if ((temp & DPLL_VCO_ENABLE) == 0) {
+                       I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE);
+                       I915_READ(pch_dpll_reg);
+               }
 
-/**
- * Sets the power management mode of the pipe and plane.
- *
- * This code should probably grow support for turning the cursor off and back
- * on appropriately at the same time as we're turning the pipe off/on.
- */
-static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
+               /* enable PCH FDI RX PLL, wait warmup plus DMI latency */
+               temp = I915_READ(fdi_rx_reg);
+               I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE |
+                               FDI_SEL_PCDCLK |
+                               FDI_DP_PORT_WIDTH_X4); /* default 4 lanes */
+               I915_READ(fdi_rx_reg);
+               udelay(200);
+
+               /* Enable CPU FDI TX PLL, always on for IGDNG */
+               temp = I915_READ(fdi_tx_reg);
+               if ((temp & FDI_TX_PLL_ENABLE) == 0) {
+                       I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE);
+                       I915_READ(fdi_tx_reg);
+                       udelay(100);
+               }
+
+               /* Enable CPU pipe */
+               temp = I915_READ(pipeconf_reg);
+               if ((temp & PIPEACONF_ENABLE) == 0) {
+                       I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE);
+                       I915_READ(pipeconf_reg);
+                       udelay(100);
+               }
+
+               /* configure and enable CPU plane */
+               temp = I915_READ(dspcntr_reg);
+               if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
+                       I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE);
+                       /* Flush the plane changes */
+                       I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
+               }
+
+               /* enable CPU FDI TX and PCH FDI RX */
+               temp = I915_READ(fdi_tx_reg);
+               temp |= FDI_TX_ENABLE;
+               temp |= FDI_DP_PORT_WIDTH_X4; /* default */
+               temp &= ~FDI_LINK_TRAIN_NONE;
+               temp |= FDI_LINK_TRAIN_PATTERN_1;
+               I915_WRITE(fdi_tx_reg, temp);
+               I915_READ(fdi_tx_reg);
+
+               temp = I915_READ(fdi_rx_reg);
+               temp &= ~FDI_LINK_TRAIN_NONE;
+               temp |= FDI_LINK_TRAIN_PATTERN_1;
+               I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE);
+               I915_READ(fdi_rx_reg);
+
+               udelay(150);
+
+               /* Train FDI. */
+               /* umask FDI RX Interrupt symbol_lock and bit_lock bit
+                  for train result */
+               temp = I915_READ(fdi_rx_imr_reg);
+               temp &= ~FDI_RX_SYMBOL_LOCK;
+               temp &= ~FDI_RX_BIT_LOCK;
+               I915_WRITE(fdi_rx_imr_reg, temp);
+               I915_READ(fdi_rx_imr_reg);
+               udelay(150);
+
+               temp = I915_READ(fdi_rx_iir_reg);
+               DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
+
+               if ((temp & FDI_RX_BIT_LOCK) == 0) {
+                       for (j = 0; j < tries; j++) {
+                               temp = I915_READ(fdi_rx_iir_reg);
+                               DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
+                               if (temp & FDI_RX_BIT_LOCK)
+                                       break;
+                               udelay(200);
+                       }
+                       if (j != tries)
+                               I915_WRITE(fdi_rx_iir_reg,
+                                               temp | FDI_RX_BIT_LOCK);
+                       else
+                               DRM_DEBUG("train 1 fail\n");
+               } else {
+                       I915_WRITE(fdi_rx_iir_reg,
+                                       temp | FDI_RX_BIT_LOCK);
+                       DRM_DEBUG("train 1 ok 2!\n");
+               }
+               temp = I915_READ(fdi_tx_reg);
+               temp &= ~FDI_LINK_TRAIN_NONE;
+               temp |= FDI_LINK_TRAIN_PATTERN_2;
+               I915_WRITE(fdi_tx_reg, temp);
+
+               temp = I915_READ(fdi_rx_reg);
+               temp &= ~FDI_LINK_TRAIN_NONE;
+               temp |= FDI_LINK_TRAIN_PATTERN_2;
+               I915_WRITE(fdi_rx_reg, temp);
+
+               udelay(150);
+
+               temp = I915_READ(fdi_rx_iir_reg);
+               DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
+
+               if ((temp & FDI_RX_SYMBOL_LOCK) == 0) {
+                       for (j = 0; j < tries; j++) {
+                               temp = I915_READ(fdi_rx_iir_reg);
+                               DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
+                               if (temp & FDI_RX_SYMBOL_LOCK)
+                                       break;
+                               udelay(200);
+                       }
+                       if (j != tries) {
+                               I915_WRITE(fdi_rx_iir_reg,
+                                               temp | FDI_RX_SYMBOL_LOCK);
+                               DRM_DEBUG("train 2 ok 1!\n");
+                       } else
+                               DRM_DEBUG("train 2 fail\n");
+               } else {
+                       I915_WRITE(fdi_rx_iir_reg, temp | FDI_RX_SYMBOL_LOCK);
+                       DRM_DEBUG("train 2 ok 2!\n");
+               }
+               DRM_DEBUG("train done\n");
+
+               /* set transcoder timing */
+               I915_WRITE(trans_htot_reg, I915_READ(cpu_htot_reg));
+               I915_WRITE(trans_hblank_reg, I915_READ(cpu_hblank_reg));
+               I915_WRITE(trans_hsync_reg, I915_READ(cpu_hsync_reg));
+
+               I915_WRITE(trans_vtot_reg, I915_READ(cpu_vtot_reg));
+               I915_WRITE(trans_vblank_reg, I915_READ(cpu_vblank_reg));
+               I915_WRITE(trans_vsync_reg, I915_READ(cpu_vsync_reg));
+
+               /* enable PCH transcoder */
+               temp = I915_READ(transconf_reg);
+               I915_WRITE(transconf_reg, temp | TRANS_ENABLE);
+               I915_READ(transconf_reg);
+
+               while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0)
+                       ;
+
+               /* enable normal */
+
+               temp = I915_READ(fdi_tx_reg);
+               temp &= ~FDI_LINK_TRAIN_NONE;
+               I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE |
+                               FDI_TX_ENHANCE_FRAME_ENABLE);
+               I915_READ(fdi_tx_reg);
+
+               temp = I915_READ(fdi_rx_reg);
+               temp &= ~FDI_LINK_TRAIN_NONE;
+               I915_WRITE(fdi_rx_reg, temp | FDI_LINK_TRAIN_NONE |
+                               FDI_RX_ENHANCE_FRAME_ENABLE);
+               I915_READ(fdi_rx_reg);
+
+               /* wait one idle pattern time */
+               udelay(100);
+
+               intel_crtc_load_lut(crtc);
+
+       break;
+       case DRM_MODE_DPMS_OFF:
+               DRM_DEBUG("crtc %d dpms off\n", pipe);
+
+               /* Disable the VGA plane that we never use */
+               I915_WRITE(CPU_VGACNTRL, VGA_DISP_DISABLE);
+
+               /* Disable display plane */
+               temp = I915_READ(dspcntr_reg);
+               if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
+                       I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
+                       /* Flush the plane changes */
+                       I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
+                       I915_READ(dspbase_reg);
+               }
+
+               /* disable cpu pipe, disable after all planes disabled */
+               temp = I915_READ(pipeconf_reg);
+               if ((temp & PIPEACONF_ENABLE) != 0) {
+                       I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
+                       I915_READ(pipeconf_reg);
+                       /* wait for cpu pipe off, pipe state */
+                       while ((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) != 0)
+                               ;
+               } else
+                       DRM_DEBUG("crtc %d is disabled\n", pipe);
+
+               /* IGDNG-A : disable cpu panel fitter ? */
+               temp = I915_READ(pf_ctl_reg);
+               if ((temp & PF_ENABLE) != 0) {
+                       I915_WRITE(pf_ctl_reg, temp & ~PF_ENABLE);
+                       I915_READ(pf_ctl_reg);
+               }
+
+               /* disable CPU FDI tx and PCH FDI rx */
+               temp = I915_READ(fdi_tx_reg);
+               I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_ENABLE);
+               I915_READ(fdi_tx_reg);
+
+               temp = I915_READ(fdi_rx_reg);
+               I915_WRITE(fdi_rx_reg, temp & ~FDI_RX_ENABLE);
+               I915_READ(fdi_rx_reg);
+
+               /* still set train pattern 1 */
+               temp = I915_READ(fdi_tx_reg);
+               temp &= ~FDI_LINK_TRAIN_NONE;
+               temp |= FDI_LINK_TRAIN_PATTERN_1;
+               I915_WRITE(fdi_tx_reg, temp);
+
+               temp = I915_READ(fdi_rx_reg);
+               temp &= ~FDI_LINK_TRAIN_NONE;
+               temp |= FDI_LINK_TRAIN_PATTERN_1;
+               I915_WRITE(fdi_rx_reg, temp);
+
+               /* disable PCH transcoder */
+               temp = I915_READ(transconf_reg);
+               if ((temp & TRANS_ENABLE) != 0) {
+                       I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE);
+                       I915_READ(transconf_reg);
+                       /* wait for PCH transcoder off, transcoder state */
+                       while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) != 0)
+                               ;
+               }
+
+               /* disable PCH DPLL */
+               temp = I915_READ(pch_dpll_reg);
+               if ((temp & DPLL_VCO_ENABLE) != 0) {
+                       I915_WRITE(pch_dpll_reg, temp & ~DPLL_VCO_ENABLE);
+                       I915_READ(pch_dpll_reg);
+               }
+
+               temp = I915_READ(fdi_rx_reg);
+               if ((temp & FDI_RX_PLL_ENABLE) != 0) {
+                       temp &= ~FDI_SEL_PCDCLK;
+                       temp &= ~FDI_RX_PLL_ENABLE;
+                       I915_WRITE(fdi_rx_reg, temp);
+                       I915_READ(fdi_rx_reg);
+               }
+
+               /* Wait for the clocks to turn off. */
+               udelay(150);
+               break;
+       }
+}
+
+static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
 {
        struct drm_device *dev = crtc->dev;
-       struct drm_i915_master_private *master_priv;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
@@ -805,7 +1209,6 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
        int dspbase_reg = (pipe == 0) ? DSPAADDR : DSPBADDR;
        int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
        u32 temp;
-       bool enabled;
 
        /* XXX: When our outputs are all unaware of DPMS modes other than off
         * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
@@ -890,6 +1293,26 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
                udelay(150);
                break;
        }
+}
+
+/**
+ * Sets the power management mode of the pipe and plane.
+ *
+ * This code should probably grow support for turning the cursor off and back
+ * on appropriately at the same time as we're turning the pipe off/on.
+ */
+static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_master_private *master_priv;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       bool enabled;
+
+       if (IS_IGDNG(dev))
+               igdng_crtc_dpms(crtc, mode);
+       else
+               i9xx_crtc_dpms(crtc, mode);
 
        if (!dev->primary->master)
                return;
@@ -947,6 +1370,12 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
                                  struct drm_display_mode *mode,
                                  struct drm_display_mode *adjusted_mode)
 {
+       struct drm_device *dev = crtc->dev;
+       if (IS_IGDNG(dev)) {
+               /* FDI link clock is fixed at 2.7G */
+               if (mode->clock * 3 > 27000 * 4)
+                       return MODE_CLOCK_HIGH;
+       }
        return true;
 }
 
@@ -1030,6 +1459,48 @@ static int intel_panel_fitter_pipe (struct drm_device *dev)
        return 1;
 }
 
+struct fdi_m_n {
+       u32        tu;
+       u32        gmch_m;
+       u32        gmch_n;
+       u32        link_m;
+       u32        link_n;
+};
+
+static void
+fdi_reduce_ratio(u32 *num, u32 *den)
+{
+       while (*num > 0xffffff || *den > 0xffffff) {
+               *num >>= 1;
+               *den >>= 1;
+       }
+}
+
+#define DATA_N 0x800000
+#define LINK_N 0x80000
+
+static void
+igdng_compute_m_n(int bytes_per_pixel, int nlanes,
+               int pixel_clock, int link_clock,
+               struct fdi_m_n *m_n)
+{
+       u64 temp;
+
+       m_n->tu = 64; /* default size */
+
+       temp = (u64) DATA_N * pixel_clock;
+       temp = div_u64(temp, link_clock);
+       m_n->gmch_m = (temp * bytes_per_pixel) / nlanes;
+       m_n->gmch_n = DATA_N;
+       fdi_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
+
+       temp = (u64) LINK_N * pixel_clock;
+       m_n->link_m = div_u64(temp, link_clock);
+       m_n->link_n = LINK_N;
+       fdi_reduce_ratio(&m_n->link_m, &m_n->link_n);
+}
+
+
 static int intel_crtc_mode_set(struct drm_crtc *crtc,
                               struct drm_display_mode *mode,
                               struct drm_display_mode *adjusted_mode,
@@ -1063,6 +1534,17 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        struct drm_connector *connector;
        const intel_limit_t *limit;
        int ret;
+       struct fdi_m_n m_n = {0};
+       int data_m1_reg = (pipe == 0) ? PIPEA_DATA_M1 : PIPEB_DATA_M1;
+       int data_n1_reg = (pipe == 0) ? PIPEA_DATA_N1 : PIPEB_DATA_N1;
+       int link_m1_reg = (pipe == 0) ? PIPEA_LINK_M1 : PIPEB_LINK_M1;
+       int link_n1_reg = (pipe == 0) ? PIPEA_LINK_N1 : PIPEB_LINK_N1;
+       int pch_fp_reg = (pipe == 0) ? PCH_FPA0 : PCH_FPB0;
+       int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B;
+       int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
+       int lvds_reg = LVDS;
+       u32 temp;
+       int sdvo_pixel_multiply;
 
        drm_vblank_pre_modeset(dev, pipe);
 
@@ -1101,6 +1583,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                DRM_DEBUG("using SSC reference clock of %d MHz\n", refclk / 1000);
        } else if (IS_I9XX(dev)) {
                refclk = 96000;
+               if (IS_IGDNG(dev))
+                       refclk = 120000; /* 120Mhz refclk */
        } else {
                refclk = 48000;
        }
@@ -1114,6 +1598,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock);
        if (!ok) {
                DRM_ERROR("Couldn't find PLL settings for mode!\n");
+               drm_vblank_post_modeset(dev, pipe);
                return -EINVAL;
        }
 
@@ -1137,12 +1622,21 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                }
        }
 
+       /* FDI link */
+       if (IS_IGDNG(dev))
+               igdng_compute_m_n(3, 4, /* lane num 4 */
+                               adjusted_mode->clock,
+                               270000, /* lane clock */
+                               &m_n);
+
        if (IS_IGD(dev))
                fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2;
        else
                fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
 
-       dpll = DPLL_VGA_MODE_DIS;
+       if (!IS_IGDNG(dev))
+               dpll = DPLL_VGA_MODE_DIS;
+
        if (IS_I9XX(dev)) {
                if (is_lvds)
                        dpll |= DPLLB_MODE_LVDS;
@@ -1150,17 +1644,22 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        dpll |= DPLLB_MODE_DAC_SERIAL;
                if (is_sdvo) {
                        dpll |= DPLL_DVO_HIGH_SPEED;
-                       if (IS_I945G(dev) || IS_I945GM(dev)) {
-                               int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
+                       sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
+                       if (IS_I945G(dev) || IS_I945GM(dev))
                                dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
-                       }
+                       else if (IS_IGDNG(dev))
+                               dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
                }
 
                /* compute bitmask from p1 value */
                if (IS_IGD(dev))
                        dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT_IGD;
-               else
+               else {
                        dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
+                       /* also FPA1 */
+                       if (IS_IGDNG(dev))
+                               dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
+               }
                switch (clock.p2) {
                case 5:
                        dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
@@ -1175,7 +1674,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
                        break;
                }
-               if (IS_I965G(dev))
+               if (IS_I965G(dev) && !IS_IGDNG(dev))
                        dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
        } else {
                if (is_lvds) {
@@ -1207,10 +1706,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        /* Set up the display plane register */
        dspcntr = DISPPLANE_GAMMA_ENABLE;
 
-       if (pipe == 0)
-               dspcntr |= DISPPLANE_SEL_PIPE_A;
-       else
-               dspcntr |= DISPPLANE_SEL_PIPE_B;
+       /* IGDNG's plane is forced to pipe, bit 24 is to
+          enable color space conversion */
+       if (!IS_IGDNG(dev)) {
+               if (pipe == 0)
+                       dspcntr |= DISPPLANE_SEL_PIPE_A;
+               else
+                       dspcntr |= DISPPLANE_SEL_PIPE_B;
+       }
 
        if (pipe == 0 && !IS_I965G(dev)) {
                /* Enable pixel doubling when the dot clock is > 90% of the (display)
@@ -1231,12 +1734,17 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 
 
        /* Disable the panel fitter if it was on our pipe */
-       if (intel_panel_fitter_pipe(dev) == pipe)
+       if (!IS_IGDNG(dev) && intel_panel_fitter_pipe(dev) == pipe)
                I915_WRITE(PFIT_CONTROL, 0);
 
        DRM_DEBUG("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
        drm_mode_debug_printmodeline(mode);
 
+       /* assign to IGDNG registers */
+       if (IS_IGDNG(dev)) {
+               fp_reg = pch_fp_reg;
+               dpll_reg = pch_dpll_reg;
+       }
 
        if (dpll & DPLL_VCO_ENABLE) {
                I915_WRITE(fp_reg, fp);
@@ -1245,13 +1753,33 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                udelay(150);
        }
 
+       if (IS_IGDNG(dev)) {
+               /* enable PCH clock reference source */
+               /* XXX need to change the setting for other outputs */
+               u32 temp;
+               temp = I915_READ(PCH_DREF_CONTROL);
+               temp &= ~DREF_NONSPREAD_SOURCE_MASK;
+               temp |= DREF_NONSPREAD_CK505_ENABLE;
+               temp &= ~DREF_SSC_SOURCE_MASK;
+               temp |= DREF_SSC_SOURCE_ENABLE;
+               temp &= ~DREF_SSC1_ENABLE;
+               /* if no eDP, disable source output to CPU */
+               temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
+               temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
+               I915_WRITE(PCH_DREF_CONTROL, temp);
+       }
+
        /* The LVDS pin pair needs to be on before the DPLLs are enabled.
         * This is an exception to the general rule that mode_set doesn't turn
         * things on.
         */
        if (is_lvds) {
-               u32 lvds = I915_READ(LVDS);
+               u32 lvds;
 
+               if (IS_IGDNG(dev))
+                       lvds_reg = PCH_LVDS;
+
+               lvds = I915_READ(lvds_reg);
                lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT;
                /* Set the B0-B3 data pairs corresponding to whether we're going to
                 * set the DPLLs for dual-channel mode or not.
@@ -1266,8 +1794,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                 * panels behave in the two modes.
                 */
 
-               I915_WRITE(LVDS, lvds);
-               I915_READ(LVDS);
+               I915_WRITE(lvds_reg, lvds);
+               I915_READ(lvds_reg);
        }
 
        I915_WRITE(fp_reg, fp);
@@ -1276,8 +1804,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        /* Wait for the clocks to stabilize. */
        udelay(150);
 
-       if (IS_I965G(dev)) {
-               int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
+       if (IS_I965G(dev) && !IS_IGDNG(dev)) {
+               sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
                I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) |
                           ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT));
        } else {
@@ -1303,9 +1831,25 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        /* pipesrc and dspsize control the size that is scaled from, which should
         * always be the user's requested size.
         */
-       I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1));
-       I915_WRITE(dsppos_reg, 0);
+       if (!IS_IGDNG(dev)) {
+               I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) |
+                               (mode->hdisplay - 1));
+               I915_WRITE(dsppos_reg, 0);
+       }
        I915_WRITE(pipesrc_reg, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
+
+       if (IS_IGDNG(dev)) {
+               I915_WRITE(data_m1_reg, TU_SIZE(m_n.tu) | m_n.gmch_m);
+               I915_WRITE(data_n1_reg, TU_SIZE(m_n.tu) | m_n.gmch_n);
+               I915_WRITE(link_m1_reg, m_n.link_m);
+               I915_WRITE(link_n1_reg, m_n.link_n);
+
+                /* enable FDI RX PLL too */
+               temp = I915_READ(fdi_rx_reg);
+               I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE);
+               udelay(200);
+       }
+
        I915_WRITE(pipeconf_reg, pipeconf);
        I915_READ(pipeconf_reg);
 
@@ -1315,12 +1859,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 
        /* Flush the plane changes */
        ret = intel_pipe_set_base(crtc, x, y, old_fb);
-       if (ret != 0)
-           return ret;
-
        drm_vblank_post_modeset(dev, pipe);
 
-       return 0;
+       return ret;
 }
 
 /** Loads the palette/gamma unit for the CRTC with the prepared values */
@@ -1336,6 +1877,11 @@ void intel_crtc_load_lut(struct drm_crtc *crtc)
        if (!crtc->enabled)
                return;
 
+       /* use legacy palette for IGDNG */
+       if (IS_IGDNG(dev))
+               palreg = (intel_crtc->pipe == 0) ? LGC_PALETTE_A :
+                                                  LGC_PALETTE_B;
+
        for (i = 0; i < 256; i++) {
                I915_WRITE(palreg + 4 * i,
                           (intel_crtc->lut_r[i] << 16) |
@@ -1464,16 +2010,16 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
        uint32_t adder;
 
        if (x < 0) {
-               temp |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT);
+               temp |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
                x = -x;
        }
        if (y < 0) {
-               temp |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT);
+               temp |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
                y = -y;
        }
 
-       temp |= ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT);
-       temp |= ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
+       temp |= x << CURSOR_X_SHIFT;
+       temp |= y << CURSOR_Y_SHIFT;
 
        adder = intel_crtc->cursor_addr;
        I915_WRITE((pipe == 0) ? CURAPOS : CURBPOS, temp);
@@ -1590,6 +2136,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output,
        }
 
        encoder->crtc = crtc;
+       intel_output->base.encoder = encoder;
        intel_output->load_detect_temp = true;
 
        intel_crtc = to_intel_crtc(crtc);
@@ -1625,6 +2172,7 @@ void intel_release_load_detect_pipe(struct intel_output *intel_output, int dpms_
 
        if (intel_output->load_detect_temp) {
                encoder->crtc = NULL;
+               intel_output->base.encoder = NULL;
                intel_output->load_detect_temp = false;
                crtc->enabled = drm_helper_crtc_in_use(crtc);
                drm_helper_disable_unused_functions(dev);
@@ -1762,6 +2310,8 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
 {
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
+       if (intel_crtc->mode_set.mode)
+               drm_mode_destroy(crtc->dev, intel_crtc->mode_set.mode);
        drm_crtc_cleanup(crtc);
        kfree(intel_crtc);
 }
@@ -1888,7 +2438,24 @@ static void intel_setup_outputs(struct drm_device *dev)
        if (IS_MOBILE(dev) && !IS_I830(dev))
                intel_lvds_init(dev);
 
-       if (IS_I9XX(dev)) {
+       if (IS_IGDNG(dev)) {
+               int found;
+
+               if (I915_READ(HDMIB) & PORT_DETECTED) {
+                       /* check SDVOB */
+                       /* found = intel_sdvo_init(dev, HDMIB); */
+                       found = 0;
+                       if (!found)
+                               intel_hdmi_init(dev, HDMIB);
+               }
+
+               if (I915_READ(HDMIC) & PORT_DETECTED)
+                       intel_hdmi_init(dev, HDMIC);
+
+               if (I915_READ(HDMID) & PORT_DETECTED)
+                       intel_hdmi_init(dev, HDMID);
+
+       } else if (IS_I9XX(dev)) {
                int found;
                u32 reg;
 
@@ -1912,7 +2479,7 @@ static void intel_setup_outputs(struct drm_device *dev)
        } else
                intel_dvo_init(dev);
 
-       if (IS_I9XX(dev) && IS_MOBILE(dev))
+       if (IS_I9XX(dev) && IS_MOBILE(dev) && !IS_IGDNG(dev))
                intel_tv_init(dev);
 
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
index e4652dcdd9bb648f585da248127199ccd816bdac..0ecf6b76a401c043e00a12b3b027a07ef14cce01 100644 (file)
@@ -207,7 +207,7 @@ static int intelfb_set_par(struct fb_info *info)
 
        if (var->pixclock != -1) {
 
-               DRM_ERROR("PIXEL CLCOK SET\n");
+               DRM_ERROR("PIXEL CLOCK SET\n");
                return -EINVAL;
        } else {
                struct drm_crtc *crtc;
@@ -674,8 +674,12 @@ static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc *
        par->crtc_ids[0] = crtc->base.id;
 
        modeset->num_connectors = conn_count;
-       if (modeset->mode != modeset->crtc->desired_mode)
-               modeset->mode = modeset->crtc->desired_mode;
+       if (modeset->crtc->desired_mode) {
+               if (modeset->mode)
+                       drm_mode_destroy(dev, modeset->mode);
+               modeset->mode = drm_mode_duplicate(dev,
+                                                  modeset->crtc->desired_mode);
+       }
 
        par->crtc_count = 1;
 
@@ -824,8 +828,12 @@ static int intelfb_single_fb_probe(struct drm_device *dev)
                par->crtc_ids[crtc_count++] = crtc->base.id;
 
                modeset->num_connectors = conn_count;
-               if (modeset->mode != modeset->crtc->desired_mode)
-                       modeset->mode = modeset->crtc->desired_mode;
+               if (modeset->crtc->desired_mode) {
+                       if (modeset->mode)
+                               drm_mode_destroy(dev, modeset->mode);
+                       modeset->mode = drm_mode_duplicate(dev,
+                                                          modeset->crtc->desired_mode);
+               }
        }
        par->crtc_count = crtc_count;
 
@@ -857,9 +865,15 @@ void intelfb_restore(void)
        drm_crtc_helper_set_config(&kernelfb_mode);
 }
 
+static void intelfb_restore_work_fn(struct work_struct *ignored)
+{
+       intelfb_restore();
+}
+static DECLARE_WORK(intelfb_restore_work, intelfb_restore_work_fn);
+
 static void intelfb_sysrq(int dummy1, struct tty_struct *dummy3)
 {
-        intelfb_restore();
+        schedule_work(&intelfb_restore_work);
 }
 
 static struct sysrq_key_op sysrq_intelfb_restore_op = {
index 7d6bdd705326e4443b5dfe1b66981e8c06375307..4ea2a651b92c43079a4c3185a829e241822ca488 100644 (file)
@@ -56,7 +56,8 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
        sdvox = SDVO_ENCODING_HDMI |
                SDVO_BORDER_ENABLE |
                SDVO_VSYNC_ACTIVE_HIGH |
-               SDVO_HSYNC_ACTIVE_HIGH;
+               SDVO_HSYNC_ACTIVE_HIGH |
+               SDVO_NULL_PACKETS_DURING_VSYNC;
 
        if (hdmi_priv->has_hdmi_sink)
                sdvox |= SDVO_AUDIO_ENABLE;
@@ -144,6 +145,22 @@ intel_hdmi_sink_detect(struct drm_connector *connector)
        }
 }
 
+static enum drm_connector_status
+igdng_hdmi_detect(struct drm_connector *connector)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv;
+
+       /* FIXME hotplug detect */
+
+       hdmi_priv->has_hdmi_sink = false;
+       intel_hdmi_sink_detect(connector);
+       if (hdmi_priv->has_hdmi_sink)
+               return connector_status_connected;
+       else
+               return connector_status_disconnected;
+}
+
 static enum drm_connector_status
 intel_hdmi_detect(struct drm_connector *connector)
 {
@@ -153,6 +170,9 @@ intel_hdmi_detect(struct drm_connector *connector)
        struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv;
        u32 temp, bit;
 
+       if (IS_IGDNG(dev))
+               return igdng_hdmi_detect(connector);
+
        temp = I915_READ(PORT_HOTPLUG_EN);
 
        switch (hdmi_priv->sdvox_reg) {
@@ -269,8 +289,17 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
        /* Set up the DDC bus. */
        if (sdvox_reg == SDVOB)
                intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "HDMIB");
-       else
+       else if (sdvox_reg == SDVOC)
                intel_output->ddc_bus = intel_i2c_create(dev, GPIOD, "HDMIC");
+       else if (sdvox_reg == HDMIB)
+               intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOE,
+                                                               "HDMIB");
+       else if (sdvox_reg == HDMIC)
+               intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOD,
+                                                               "HDMIC");
+       else if (sdvox_reg == HDMID)
+               intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOF,
+                                                               "HDMID");
 
        if (!intel_output->ddc_bus)
                goto err_connector;
index 53cccfa58b951012f127ce79891a6d7eca79d288..f073ed8432e8fb9547d272653b51315a3bc90de3 100644 (file)
@@ -37,6 +37,8 @@
 #include "i915_drm.h"
 #include "i915_drv.h"
 
+#define I915_LVDS "i915_lvds"
+
 /**
  * Sets the backlight level.
  *
 static void intel_lvds_set_backlight(struct drm_device *dev, int level)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 blc_pwm_ctl;
+       u32 blc_pwm_ctl, reg;
+
+       if (IS_IGDNG(dev))
+               reg = BLC_PWM_CPU_CTL;
+       else
+               reg = BLC_PWM_CTL;
 
-       blc_pwm_ctl = I915_READ(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
-       I915_WRITE(BLC_PWM_CTL, (blc_pwm_ctl |
+       blc_pwm_ctl = I915_READ(reg) & ~BACKLIGHT_DUTY_CYCLE_MASK;
+       I915_WRITE(reg, (blc_pwm_ctl |
                                 (level << BACKLIGHT_DUTY_CYCLE_SHIFT)));
 }
 
@@ -58,8 +65,14 @@ static void intel_lvds_set_backlight(struct drm_device *dev, int level)
 static u32 intel_lvds_get_max_backlight(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 reg;
+
+       if (IS_IGDNG(dev))
+               reg = BLC_PWM_PCH_CTL2;
+       else
+               reg = BLC_PWM_CTL;
 
-       return ((I915_READ(BLC_PWM_CTL) & BACKLIGHT_MODULATION_FREQ_MASK) >>
+       return ((I915_READ(reg) & BACKLIGHT_MODULATION_FREQ_MASK) >>
                BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
 }
 
@@ -69,23 +82,31 @@ static u32 intel_lvds_get_max_backlight(struct drm_device *dev)
 static void intel_lvds_set_power(struct drm_device *dev, bool on)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 pp_status;
+       u32 pp_status, ctl_reg, status_reg;
+
+       if (IS_IGDNG(dev)) {
+               ctl_reg = PCH_PP_CONTROL;
+               status_reg = PCH_PP_STATUS;
+       } else {
+               ctl_reg = PP_CONTROL;
+               status_reg = PP_STATUS;
+       }
 
        if (on) {
-               I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) |
+               I915_WRITE(ctl_reg, I915_READ(ctl_reg) |
                           POWER_TARGET_ON);
                do {
-                       pp_status = I915_READ(PP_STATUS);
+                       pp_status = I915_READ(status_reg);
                } while ((pp_status & PP_ON) == 0);
 
                intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle);
        } else {
                intel_lvds_set_backlight(dev, 0);
 
-               I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) &
+               I915_WRITE(ctl_reg, I915_READ(ctl_reg) &
                           ~POWER_TARGET_ON);
                do {
-                       pp_status = I915_READ(PP_STATUS);
+                       pp_status = I915_READ(status_reg);
                } while (pp_status & PP_ON);
        }
 }
@@ -106,12 +127,28 @@ static void intel_lvds_save(struct drm_connector *connector)
 {
        struct drm_device *dev = connector->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg;
+       u32 pwm_ctl_reg;
+
+       if (IS_IGDNG(dev)) {
+               pp_on_reg = PCH_PP_ON_DELAYS;
+               pp_off_reg = PCH_PP_OFF_DELAYS;
+               pp_ctl_reg = PCH_PP_CONTROL;
+               pp_div_reg = PCH_PP_DIVISOR;
+               pwm_ctl_reg = BLC_PWM_CPU_CTL;
+       } else {
+               pp_on_reg = PP_ON_DELAYS;
+               pp_off_reg = PP_OFF_DELAYS;
+               pp_ctl_reg = PP_CONTROL;
+               pp_div_reg = PP_DIVISOR;
+               pwm_ctl_reg = BLC_PWM_CTL;
+       }
 
-       dev_priv->savePP_ON = I915_READ(PP_ON_DELAYS);
-       dev_priv->savePP_OFF = I915_READ(PP_OFF_DELAYS);
-       dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL);
-       dev_priv->savePP_DIVISOR = I915_READ(PP_DIVISOR);
-       dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
+       dev_priv->savePP_ON = I915_READ(pp_on_reg);
+       dev_priv->savePP_OFF = I915_READ(pp_off_reg);
+       dev_priv->savePP_CONTROL = I915_READ(pp_ctl_reg);
+       dev_priv->savePP_DIVISOR = I915_READ(pp_div_reg);
+       dev_priv->saveBLC_PWM_CTL = I915_READ(pwm_ctl_reg);
        dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL &
                                       BACKLIGHT_DUTY_CYCLE_MASK);
 
@@ -127,12 +164,28 @@ static void intel_lvds_restore(struct drm_connector *connector)
 {
        struct drm_device *dev = connector->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg;
+       u32 pwm_ctl_reg;
+
+       if (IS_IGDNG(dev)) {
+               pp_on_reg = PCH_PP_ON_DELAYS;
+               pp_off_reg = PCH_PP_OFF_DELAYS;
+               pp_ctl_reg = PCH_PP_CONTROL;
+               pp_div_reg = PCH_PP_DIVISOR;
+               pwm_ctl_reg = BLC_PWM_CPU_CTL;
+       } else {
+               pp_on_reg = PP_ON_DELAYS;
+               pp_off_reg = PP_OFF_DELAYS;
+               pp_ctl_reg = PP_CONTROL;
+               pp_div_reg = PP_DIVISOR;
+               pwm_ctl_reg = BLC_PWM_CTL;
+       }
 
-       I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL);
-       I915_WRITE(PP_ON_DELAYS, dev_priv->savePP_ON);
-       I915_WRITE(PP_OFF_DELAYS, dev_priv->savePP_OFF);
-       I915_WRITE(PP_DIVISOR, dev_priv->savePP_DIVISOR);
-       I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL);
+       I915_WRITE(pwm_ctl_reg, dev_priv->saveBLC_PWM_CTL);
+       I915_WRITE(pp_on_reg, dev_priv->savePP_ON);
+       I915_WRITE(pp_off_reg, dev_priv->savePP_OFF);
+       I915_WRITE(pp_div_reg, dev_priv->savePP_DIVISOR);
+       I915_WRITE(pp_ctl_reg, dev_priv->savePP_CONTROL);
        if (dev_priv->savePP_CONTROL & POWER_TARGET_ON)
                intel_lvds_set_power(dev, true);
        else
@@ -216,8 +269,14 @@ static void intel_lvds_prepare(struct drm_encoder *encoder)
 {
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 reg;
+
+       if (IS_IGDNG(dev))
+               reg = BLC_PWM_CPU_CTL;
+       else
+               reg = BLC_PWM_CTL;
 
-       dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
+       dev_priv->saveBLC_PWM_CTL = I915_READ(reg);
        dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL &
                                       BACKLIGHT_DUTY_CYCLE_MASK);
 
@@ -251,6 +310,10 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
         * settings.
         */
 
+       /* No panel fitting yet, fixme */
+       if (IS_IGDNG(dev))
+               return;
+
        /*
         * Enable automatic panel scaling so that non-native modes fill the
         * screen.  Should be enabled before the pipe is enabled, according to
@@ -382,7 +445,8 @@ static const struct drm_encoder_funcs intel_lvds_enc_funcs = {
 
 static int __init intel_no_lvds_dmi_callback(const struct dmi_system_id *id)
 {
-       DRM_DEBUG("Skipping LVDS initialization for %s\n", id->ident);
+       DRM_DEBUG_KMS(I915_LVDS,
+                     "Skipping LVDS initialization for %s\n", id->ident);
        return 1;
 }
 
@@ -420,8 +484,21 @@ static const struct dmi_system_id intel_no_lvds[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "Studio Hybrid 140g"),
                },
        },
-
-       /* FIXME: add a check for the Aopen Mini PC */
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "AOpen Mini PC",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "AOpen"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "i965GMx-IF"),
+               },
+       },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "Aopen i945GTt-VFA",
+               .matches = {
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "AO00001JW"),
+               },
+       },
 
        { }     /* terminating entry */
 };
@@ -442,12 +519,18 @@ void intel_lvds_init(struct drm_device *dev)
        struct drm_display_mode *scan; /* *modes, *bios_mode; */
        struct drm_crtc *crtc;
        u32 lvds;
-       int pipe;
+       int pipe, gpio = GPIOC;
 
        /* Skip init on machines we know falsely report LVDS */
        if (dmi_check_system(intel_no_lvds))
                return;
 
+       if (IS_IGDNG(dev)) {
+               if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0)
+                       return;
+               gpio = PCH_GPIOC;
+       }
+
        intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL);
        if (!intel_output) {
                return;
@@ -482,7 +565,7 @@ void intel_lvds_init(struct drm_device *dev)
         */
 
        /* Set up the DDC bus. */
-       intel_output->ddc_bus = intel_i2c_create(dev, GPIOC, "LVDSDDC_C");
+       intel_output->ddc_bus = intel_i2c_create(dev, gpio, "LVDSDDC_C");
        if (!intel_output->ddc_bus) {
                dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
                           "failed.\n");
@@ -524,6 +607,11 @@ void intel_lvds_init(struct drm_device *dev)
         * on.  If so, assume that whatever is currently programmed is the
         * correct mode.
         */
+
+       /* IGDNG: FIXME if still fail, not try pipe mode now */
+       if (IS_IGDNG(dev))
+               goto failed;
+
        lvds = I915_READ(LVDS);
        pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
        crtc = intel_get_crtc_from_pipe(dev, pipe);
@@ -542,11 +630,22 @@ void intel_lvds_init(struct drm_device *dev)
                goto failed;
 
 out:
+       if (IS_IGDNG(dev)) {
+               u32 pwm;
+               /* make sure PWM is enabled */
+               pwm = I915_READ(BLC_PWM_CPU_CTL2);
+               pwm |= (PWM_ENABLE | PWM_PIPE_B);
+               I915_WRITE(BLC_PWM_CPU_CTL2, pwm);
+
+               pwm = I915_READ(BLC_PWM_PCH_CTL1);
+               pwm |= PWM_PCH_ENABLE;
+               I915_WRITE(BLC_PWM_PCH_CTL1, pwm);
+       }
        drm_sysfs_connector_add(connector);
        return;
 
 failed:
-       DRM_DEBUG("No LVDS modes found, disabling.\n");
+       DRM_DEBUG_KMS(I915_LVDS, "No LVDS modes found, disabling.\n");
        if (intel_output->ddc_bus)
                intel_i2c_destroy(intel_output->ddc_bus);
        drm_connector_cleanup(connector);
index 3093b4d4a4ddb2329d407a09aa17bce413d5e77f..9a00adb3a50896033302bb70b6d715de72408dce 100644 (file)
@@ -36,7 +36,7 @@
 #include "intel_sdvo_regs.h"
 
 #undef SDVO_DEBUG
-
+#define I915_SDVO      "i915_sdvo"
 struct intel_sdvo_priv {
        struct intel_i2c_chan *i2c_bus;
        int slaveaddr;
@@ -277,20 +277,21 @@ static void intel_sdvo_debug_write(struct intel_output *intel_output, u8 cmd,
        struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
        int i;
 
-       printk(KERN_DEBUG "%s: W: %02X ", SDVO_NAME(sdvo_priv), cmd);
+       DRM_DEBUG_KMS(I915_SDVO, "%s: W: %02X ",
+                               SDVO_NAME(sdvo_priv), cmd);
        for (i = 0; i < args_len; i++)
-               printk(KERN_DEBUG "%02X ", ((u8 *)args)[i]);
+               DRM_LOG_KMS("%02X ", ((u8 *)args)[i]);
        for (; i < 8; i++)
-               printk(KERN_DEBUG "   ");
+               DRM_LOG_KMS("   ");
        for (i = 0; i < sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0]); i++) {
                if (cmd == sdvo_cmd_names[i].cmd) {
-                       printk(KERN_DEBUG "(%s)", sdvo_cmd_names[i].name);
+                       DRM_LOG_KMS("(%s)", sdvo_cmd_names[i].name);
                        break;
                }
        }
        if (i == sizeof(sdvo_cmd_names)/ sizeof(sdvo_cmd_names[0]))
-               printk(KERN_DEBUG "(%02X)", cmd);
-       printk(KERN_DEBUG "\n");
+               DRM_LOG_KMS("(%02X)", cmd);
+       DRM_LOG_KMS("\n");
 }
 #else
 #define intel_sdvo_debug_write(o, c, a, l)
@@ -329,16 +330,16 @@ static void intel_sdvo_debug_response(struct intel_output *intel_output,
        struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
        int i;
 
-       printk(KERN_DEBUG "%s: R: ", SDVO_NAME(sdvo_priv));
+       DRM_DEBUG_KMS(I915_SDVO, "%s: R: ", SDVO_NAME(sdvo_priv));
        for (i = 0; i < response_len; i++)
-               printk(KERN_DEBUG "%02X ", ((u8 *)response)[i]);
+               DRM_LOG_KMS("%02X ", ((u8 *)response)[i]);
        for (; i < 8; i++)
-               printk(KERN_DEBUG "   ");
+               DRM_LOG_KMS("   ");
        if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)
-               printk(KERN_DEBUG "(%s)", cmd_status_names[status]);
+               DRM_LOG_KMS("(%s)", cmd_status_names[status]);
        else
-               printk(KERN_DEBUG "(??? %d)", status);
-       printk(KERN_DEBUG "\n");
+               DRM_LOG_KMS("(??? %d)", status);
+       DRM_LOG_KMS("\n");
 }
 #else
 #define intel_sdvo_debug_response(o, r, l, s)
@@ -1742,6 +1743,43 @@ static struct i2c_algorithm intel_sdvo_i2c_bit_algo = {
        .master_xfer    = intel_sdvo_master_xfer,
 };
 
+static u8
+intel_sdvo_get_slave_addr(struct drm_device *dev, int output_device)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct sdvo_device_mapping *my_mapping, *other_mapping;
+
+       if (output_device == SDVOB) {
+               my_mapping = &dev_priv->sdvo_mappings[0];
+               other_mapping = &dev_priv->sdvo_mappings[1];
+       } else {
+               my_mapping = &dev_priv->sdvo_mappings[1];
+               other_mapping = &dev_priv->sdvo_mappings[0];
+       }
+
+       /* If the BIOS described our SDVO device, take advantage of it. */
+       if (my_mapping->slave_addr)
+               return my_mapping->slave_addr;
+
+       /* If the BIOS only described a different SDVO device, use the
+        * address that it isn't using.
+        */
+       if (other_mapping->slave_addr) {
+               if (other_mapping->slave_addr == 0x70)
+                       return 0x72;
+               else
+                       return 0x70;
+       }
+
+       /* No SDVO device info is found for another DVO port,
+        * so use mapping assumption we had before BIOS parsing.
+        */
+       if (output_device == SDVOB)
+               return 0x70;
+       else
+               return 0x72;
+}
+
 bool intel_sdvo_init(struct drm_device *dev, int output_device)
 {
        struct drm_connector *connector;
@@ -1753,6 +1791,7 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
        u8 ch[0x40];
        int i;
        int encoder_type, output_id;
+       u8 slave_addr;
 
        intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL);
        if (!intel_output) {
@@ -1771,16 +1810,15 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
        if (!i2cbus)
                goto err_inteloutput;
 
+       slave_addr = intel_sdvo_get_slave_addr(dev, output_device);
        sdvo_priv->i2c_bus = i2cbus;
 
        if (output_device == SDVOB) {
                output_id = 1;
-               sdvo_priv->i2c_bus->slave_addr = 0x38;
        } else {
                output_id = 2;
-               sdvo_priv->i2c_bus->slave_addr = 0x39;
        }
-
+       sdvo_priv->i2c_bus->slave_addr = slave_addr >> 1;
        sdvo_priv->output_device = output_device;
        intel_output->i2c_bus = i2cbus;
        intel_output->dev_priv = sdvo_priv;
@@ -1788,8 +1826,9 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
        /* Read the regs to test if we can talk to the device */
        for (i = 0; i < 0x40; i++) {
                if (!intel_sdvo_read_byte(intel_output, i, &ch[i])) {
-                       DRM_DEBUG("No SDVO device found on SDVO%c\n",
-                                 output_device == SDVOB ? 'B' : 'C');
+                       DRM_DEBUG_KMS(I915_SDVO,
+                                       "No SDVO device found on SDVO%c\n",
+                                       output_device == SDVOB ? 'B' : 'C');
                        goto err_i2c;
                }
        }
@@ -1873,9 +1912,10 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
 
                sdvo_priv->controlled_output = 0;
                memcpy (bytes, &sdvo_priv->caps.output_flags, 2);
-               DRM_DEBUG("%s: Unknown SDVO output type (0x%02x%02x)\n",
-                         SDVO_NAME(sdvo_priv),
-                         bytes[0], bytes[1]);
+               DRM_DEBUG_KMS(I915_SDVO,
+                               "%s: Unknown SDVO output type (0x%02x%02x)\n",
+                                 SDVO_NAME(sdvo_priv),
+                                 bytes[0], bytes[1]);
                encoder_type = DRM_MODE_ENCODER_NONE;
                connector_type = DRM_MODE_CONNECTOR_Unknown;
                goto err_i2c;
@@ -1905,21 +1945,21 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
                                               &sdvo_priv->pixel_clock_max);
 
 
-       DRM_DEBUG("%s device VID/DID: %02X:%02X.%02X, "
-                 "clock range %dMHz - %dMHz, "
-                 "input 1: %c, input 2: %c, "
-                 "output 1: %c, output 2: %c\n",
-                 SDVO_NAME(sdvo_priv),
-                 sdvo_priv->caps.vendor_id, sdvo_priv->caps.device_id,
-                 sdvo_priv->caps.device_rev_id,
-                 sdvo_priv->pixel_clock_min / 1000,
-                 sdvo_priv->pixel_clock_max / 1000,
-                 (sdvo_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N',
-                 (sdvo_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N',
-                 /* check currently supported outputs */
-                 sdvo_priv->caps.output_flags &
+       DRM_DEBUG_KMS(I915_SDVO, "%s device VID/DID: %02X:%02X.%02X, "
+                       "clock range %dMHz - %dMHz, "
+                       "input 1: %c, input 2: %c, "
+                       "output 1: %c, output 2: %c\n",
+                       SDVO_NAME(sdvo_priv),
+                       sdvo_priv->caps.vendor_id, sdvo_priv->caps.device_id,
+                       sdvo_priv->caps.device_rev_id,
+                       sdvo_priv->pixel_clock_min / 1000,
+                       sdvo_priv->pixel_clock_max / 1000,
+                       (sdvo_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N',
+                       (sdvo_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N',
+                       /* check currently supported outputs */
+                       sdvo_priv->caps.output_flags &
                        (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N',
-                 sdvo_priv->caps.output_flags &
+                       sdvo_priv->caps.output_flags &
                        (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N');
 
        return true;
index 98ac0546b7bd97ea924eb2d44e3e456ca91c8c2c..50d7ed70b338a2c867eccb7caa1562e1ce6cbf53 100644 (file)
@@ -1392,6 +1392,9 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct intel_output *intel_output)
                tv_ctl &= ~TV_TEST_MODE_MASK;
                tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
                tv_dac &= ~TVDAC_SENSE_MASK;
+               tv_dac &= ~DAC_A_MASK;
+               tv_dac &= ~DAC_B_MASK;
+               tv_dac &= ~DAC_C_MASK;
                tv_dac |= (TVDAC_STATE_CHG_EN |
                           TVDAC_A_SENSE_CTL |
                           TVDAC_B_SENSE_CTL |
index bc9d09dfa8e7de7063ebea70c6371d0cecf89a9d..146f3570af8e710f689d3f9823981b993a5e3632 100644 (file)
@@ -478,26 +478,27 @@ static void r700_cp_load_microcode(drm_radeon_private_t *dev_priv)
 
        if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV770)) {
                RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
-               DRM_INFO("Loading RV770 PFP Microcode\n");
+               DRM_INFO("Loading RV770/RV790 PFP Microcode\n");
                for (i = 0; i < R700_PFP_UCODE_SIZE; i++)
                        RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RV770_pfp_microcode[i]);
                RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
 
                RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
-               DRM_INFO("Loading RV770 CP Microcode\n");
+               DRM_INFO("Loading RV770/RV790 CP Microcode\n");
                for (i = 0; i < R700_PM4_UCODE_SIZE; i++)
                        RADEON_WRITE(R600_CP_ME_RAM_DATA, RV770_cp_microcode[i]);
                RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
 
-       } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV730)) {
+       } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV730) ||
+                  ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV740)) {
                RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
-               DRM_INFO("Loading RV730 PFP Microcode\n");
+               DRM_INFO("Loading RV730/RV740 PFP Microcode\n");
                for (i = 0; i < R700_PFP_UCODE_SIZE; i++)
                        RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RV730_pfp_microcode[i]);
                RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
 
                RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
-               DRM_INFO("Loading RV730 CP Microcode\n");
+               DRM_INFO("Loading RV730/RV740 CP Microcode\n");
                for (i = 0; i < R700_PM4_UCODE_SIZE; i++)
                        RADEON_WRITE(R600_CP_ME_RAM_DATA, RV730_cp_microcode[i]);
                RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
@@ -1324,6 +1325,10 @@ static void r700_gfx_init(struct drm_device *dev,
                dev_priv->r700_sc_prim_fifo_size = 0xf9;
                dev_priv->r700_sc_hiz_tile_fifo_size = 0x30;
                dev_priv->r700_sc_earlyz_tile_fifo_fize = 0x130;
+               if (dev_priv->r600_sx_max_export_pos_size > 16) {
+                       dev_priv->r600_sx_max_export_pos_size -= 16;
+                       dev_priv->r600_sx_max_export_smx_size += 16;
+               }
                break;
        case CHIP_RV710:
                dev_priv->r600_max_pipes = 2;
@@ -1345,6 +1350,31 @@ static void r700_gfx_init(struct drm_device *dev,
                dev_priv->r700_sc_hiz_tile_fifo_size = 0x30;
                dev_priv->r700_sc_earlyz_tile_fifo_fize = 0x130;
                break;
+       case CHIP_RV740:
+               dev_priv->r600_max_pipes = 4;
+               dev_priv->r600_max_tile_pipes = 4;
+               dev_priv->r600_max_simds = 8;
+               dev_priv->r600_max_backends = 4;
+               dev_priv->r600_max_gprs = 256;
+               dev_priv->r600_max_threads = 248;
+               dev_priv->r600_max_stack_entries = 512;
+               dev_priv->r600_max_hw_contexts = 8;
+               dev_priv->r600_max_gs_threads = 16 * 2;
+               dev_priv->r600_sx_max_export_size = 256;
+               dev_priv->r600_sx_max_export_pos_size = 32;
+               dev_priv->r600_sx_max_export_smx_size = 224;
+               dev_priv->r600_sq_num_cf_insts = 2;
+
+               dev_priv->r700_sx_num_of_sets = 7;
+               dev_priv->r700_sc_prim_fifo_size = 0x100;
+               dev_priv->r700_sc_hiz_tile_fifo_size = 0x30;
+               dev_priv->r700_sc_earlyz_tile_fifo_fize = 0x130;
+
+               if (dev_priv->r600_sx_max_export_pos_size > 16) {
+                       dev_priv->r600_sx_max_export_pos_size -= 16;
+                       dev_priv->r600_sx_max_export_smx_size += 16;
+               }
+               break;
        default:
                break;
        }
@@ -1493,6 +1523,7 @@ static void r700_gfx_init(struct drm_device *dev,
                break;
        case CHIP_RV730:
        case CHIP_RV710:
+       case CHIP_RV740:
        default:
                sq_ms_fifo_sizes |= R600_FETCH_FIFO_HIWATER(0x4);
                break;
@@ -1569,6 +1600,7 @@ static void r700_gfx_init(struct drm_device *dev,
        switch (dev_priv->flags & RADEON_FAMILY_MASK) {
        case CHIP_RV770:
        case CHIP_RV730:
+       case CHIP_RV740:
                gs_prim_buffer_depth = 384;
                break;
        case CHIP_RV710:
index aff90bb964885568567f17d43a2f1b8dd79f179c..89c4c44169f778f39d9aad86cc57a8a31b18adcf 100644 (file)
@@ -2109,7 +2109,7 @@ int radeon_master_create(struct drm_device *dev, struct drm_master *master)
 
        /* prebuild the SAREA */
        sareapage = max_t(unsigned long, SAREA_MAX, PAGE_SIZE);
-       ret = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK|_DRM_DRIVER,
+       ret = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK,
                         &master_priv->sarea);
        if (ret) {
                DRM_ERROR("SAREA setup failed\n");
index 0c6bfc1de153108fe2780b3d49978a26a008a9b7..127d0456f628bf87ed469e5a451347c5d981f5b4 100644 (file)
@@ -146,6 +146,7 @@ enum radeon_family {
        CHIP_RV770,
        CHIP_RV730,
        CHIP_RV710,
+       CHIP_RV740,
        CHIP_LAST,
 };
 
index 409e00afdd0754f6eb60707810a262df43a75fe9..327380888b4a5f15880bbef8f17f93658d12ab89 100644 (file)
@@ -195,10 +195,8 @@ via_free_sg_info(struct pci_dev *pdev, drm_via_sg_info_t *vsg)
        default:
                vsg->state = dr_via_sg_init;
        }
-       if (vsg->bounce_buffer) {
-               vfree(vsg->bounce_buffer);
-               vsg->bounce_buffer = NULL;
-       }
+       vfree(vsg->bounce_buffer);
+       vsg->bounce_buffer = NULL;
        vsg->free_on_sequence = 0;
 }
 
index 7e67dcb3d4f657d4bab800b8390b4af976b4554d..7831a0318d3ca5bad508d0a74d884c5013eabced 100644 (file)
@@ -116,9 +116,16 @@ config HID_CYPRESS
        ---help---
        Support for cypress mouse and barcode readers.
 
-config DRAGONRISE_FF
-       tristate "DragonRise Inc. force feedback support"
+config HID_DRAGONRISE
+       tristate "DragonRise Inc. support" if EMBEDDED
        depends on USB_HID
+       default !EMBEDDED
+       ---help---
+       Say Y here if you have DragonRise Inc.game controllers.
+
+config DRAGONRISE_FF
+       bool "DragonRise Inc. force feedback support"
+       depends on HID_DRAGONRISE
        select INPUT_FF_MEMLESS
        ---help---
        Say Y here if you want to enable force feedback support for DragonRise Inc.
@@ -160,7 +167,7 @@ config HID_LOGITECH
        Support for Logitech devices that are not fully compliant with HID standard.
 
 config LOGITECH_FF
-       bool "Logitech force feedback"
+       bool "Logitech force feedback support"
        depends on HID_LOGITECH
        select INPUT_FF_MEMLESS
        help
@@ -176,7 +183,7 @@ config LOGITECH_FF
          force feedback.
 
 config LOGIRUMBLEPAD2_FF
-       bool "Logitech Rumblepad 2 force feedback"
+       bool "Logitech Rumblepad 2 force feedback support"
        depends on HID_LOGITECH
        select INPUT_FF_MEMLESS
        help
@@ -211,11 +218,19 @@ config HID_PANTHERLORD
        ---help---
        Support for PantherLord/GreenAsia based device support.
 
+config HID_PANTHERLORD
+       tristate "Pantherlord support" if EMBEDDED
+       depends on USB_HID
+       default !EMBEDDED
+       ---help---
+         Say Y here if you have a PantherLord/GreenAsia based game controller
+         or adapter.
+
 config PANTHERLORD_FF
        bool "Pantherlord force feedback support"
        depends on HID_PANTHERLORD
        select INPUT_FF_MEMLESS
-       help
+       ---help---
          Say Y here if you have a PantherLord/GreenAsia based game controller
          or adapter and want to enable force feedback support for it.
 
@@ -247,15 +262,38 @@ config HID_SUNPLUS
        ---help---
        Support for Sunplus wireless desktop.
 
-config GREENASIA_FF
-       tristate "GreenAsia (Product ID 0x12) force feedback support"
+config HID_GREENASIA
+       tristate "GreenAsia (Product ID 0x12) support" if EMBEDDED
        depends on USB_HID
+       default !EMBEDDED
+       ---help---
+         Say Y here if you have a GreenAsia (Product ID 0x12) based game
+         controller or adapter.
+
+config GREENASIA_FF
+       bool "GreenAsia (Product ID 0x12) force feedback support"
+       depends on HID_GREENASIA
        select INPUT_FF_MEMLESS
        ---help---
        Say Y here if you have a GreenAsia (Product ID 0x12) based game controller
        (like MANTA Warrior MM816 and SpeedLink Strike2 SL-6635) or adapter
        and want to enable force feedback support for it.
 
+config HID_SMARTJOYPLUS
+       tristate "SmartJoy PLUS PS2/USB adapter support" if EMBEDDED
+       depends on USB_HID
+       default !EMBEDDED
+       ---help---
+       Support for SmartJoy PLUS PS2/USB adapter.
+
+config SMARTJOYPLUS_FF
+       bool "SmartJoy PLUS PS2/USB adapter force feedback support"
+       depends on HID_SMARTJOYPLUS
+       select INPUT_FF_MEMLESS
+       ---help---
+       Say Y here if you have a SmartJoy PLUS PS2/USB adapter and want to
+       enable force feedback support for it.
+
 config HID_TOPSEED
        tristate "TopSeed Cyberlink remote control support" if EMBEDDED
        depends on USB_HID
@@ -263,21 +301,45 @@ config HID_TOPSEED
        ---help---
        Say Y if you have a TopSeed Cyberlink remote control.
 
-config THRUSTMASTER_FF
-       tristate "ThrustMaster devices support"
+config HID_THRUSTMASTER
+       tristate "ThrustMaster devices support" if EMBEDDED
        depends on USB_HID
+       default !EMBEDDED
+       ---help---
+         Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
+         a THRUSTMASTER Ferrari GT Rumble Wheel.
+
+config THRUSTMASTER_FF
+       bool "ThrustMaster devices force feedback support"
+       depends on HID_THRUSTMASTER
        select INPUT_FF_MEMLESS
-       help
+       ---help---
          Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
-         a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel.
+         a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel and
+         want to enable force feedback support for it.
 
-config ZEROPLUS_FF
-       tristate "Zeroplus based game controller support"
+config HID_WACOM
+       tristate "Wacom Bluetooth devices support" if EMBEDDED
+       depends on BT_HIDP
+       default !EMBEDDED
+       ---help---
+       Support for Wacom Graphire Bluetooth tablet.
+
+config HID_ZEROPLUS
+       tristate "Zeroplus based game controller support" if EMBEDDED
        depends on USB_HID
-       select INPUT_FF_MEMLESS
-       help
+       default !EMBEDDED
+       ---help---
          Say Y here if you have a Zeroplus based game controller.
 
+config ZEROPLUS_FF
+       bool "Zeroplus based game controller force feedback support"
+       depends on HID_ZEROPLUS
+       select INPUT_FF_MEMLESS
+       ---help---
+         Say Y here if you have a Zeroplus based game controller and want
+         to have force feedback support for it.
+
 endmenu
 
 endif # HID_SUPPORT
index 1f7cb0fd4505c3e82aa3d521e35a01dac124f88c..db35151673b17f25f453bb7cf2b7018eb580b4dd 100644 (file)
@@ -22,7 +22,7 @@ obj-$(CONFIG_HID_BELKIN)      += hid-belkin.o
 obj-$(CONFIG_HID_CHERRY)       += hid-cherry.o
 obj-$(CONFIG_HID_CHICONY)      += hid-chicony.o
 obj-$(CONFIG_HID_CYPRESS)      += hid-cypress.o
-obj-$(CONFIG_DRAGONRISE_FF)    += hid-drff.o
+obj-$(CONFIG_HID_DRAGONRISE)   += hid-drff.o
 obj-$(CONFIG_HID_EZKEY)                += hid-ezkey.o
 obj-$(CONFIG_HID_GYRATION)     += hid-gyration.o
 obj-$(CONFIG_HID_KENSINGTON)   += hid-kensington.o
@@ -34,12 +34,14 @@ obj-$(CONFIG_HID_NTRIG)             += hid-ntrig.o
 obj-$(CONFIG_HID_PANTHERLORD)  += hid-pl.o
 obj-$(CONFIG_HID_PETALYNX)     += hid-petalynx.o
 obj-$(CONFIG_HID_SAMSUNG)      += hid-samsung.o
+obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
 obj-$(CONFIG_HID_SONY)         += hid-sony.o
 obj-$(CONFIG_HID_SUNPLUS)      += hid-sunplus.o
-obj-$(CONFIG_GREENASIA_FF)     += hid-gaff.o
-obj-$(CONFIG_THRUSTMASTER_FF)  += hid-tmff.o
+obj-$(CONFIG_HID_GREENASIA)    += hid-gaff.o
+obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o
 obj-$(CONFIG_HID_TOPSEED)      += hid-topseed.o
-obj-$(CONFIG_ZEROPLUS_FF)      += hid-zpff.o
+obj-$(CONFIG_HID_ZEROPLUS)     += hid-zpff.o
+obj-$(CONFIG_HID_WACOM)                += hid-wacom.o
 
 obj-$(CONFIG_USB_HID)          += usbhid/
 obj-$(CONFIG_USB_MOUSE)                += usbhid/
index acbce5745b0c8b41e2644ac05a3293d05c931165..303ccce05bb3b4c44cacb0d349ac1ccbfb3812b9 100644 (file)
@@ -436,10 +436,6 @@ static const struct hid_device_id apple_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY),
                .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
 
-       /* Apple wireless Mighty Mouse */
-       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c),
-               .driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL },
-
        { }
 };
 MODULE_DEVICE_TABLE(hid, apple_devices);
index 8551693d645fc602fe5f3bf3ccd1352fefc439c2..f2c21d5d24e80e43bc3e482218fd20873f106c07 100644 (file)
@@ -1312,6 +1312,8 @@ static const struct hid_device_id hid_blacklist[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) },
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
 
index 47ac1a7d66e1e3633de5223712bb3f373bb35e4f..04359ed64b8763b70553d052d9386c907329c193 100644 (file)
@@ -137,6 +137,14 @@ static const struct hid_usage_entry hid_usage_table[] = {
     {0, 0x44, "BarrelSwitch"},
     {0, 0x45, "Eraser"},
     {0, 0x46, "TabletPick"},
+    {0, 0x47, "Confidence"},
+    {0, 0x48, "Width"},
+    {0, 0x49, "Height"},
+    {0, 0x51, "ContactID"},
+    {0, 0x52, "InputMode"},
+    {0, 0x53, "DeviceIndex"},
+    {0, 0x54, "ContactCount"},
+    {0, 0x55, "ContactMaximumNumber"},
   { 15, 0, "PhysicalInterfaceDevice" },
     {0, 0x00, "Undefined"},
     {0, 0x01, "Physical_Interface_Device"},
@@ -514,9 +522,11 @@ static const char *events[EV_MAX + 1] = {
        [EV_FF_STATUS] = "ForceFeedbackStatus",
 };
 
-static const char *syncs[2] = {
+static const char *syncs[3] = {
        [SYN_REPORT] = "Report",                [SYN_CONFIG] = "Config",
+       [SYN_MT_REPORT] = "MT Report",
 };
+
 static const char *keys[KEY_MAX + 1] = {
        [KEY_RESERVED] = "Reserved",            [KEY_ESC] = "Esc",
        [KEY_1] = "1",                          [KEY_2] = "2",
@@ -734,8 +744,17 @@ static const char *absolutes[ABS_MAX + 1] = {
        [ABS_HAT2Y] = "Hat2Y",          [ABS_HAT3X] = "Hat3X",
        [ABS_HAT3Y] = "Hat 3Y",         [ABS_PRESSURE] = "Pressure",
        [ABS_DISTANCE] = "Distance",    [ABS_TILT_X] = "XTilt",
-       [ABS_TILT_Y] = "YTilt",         [ABS_TOOL_WIDTH] = "Tool Width",
+       [ABS_TILT_Y] = "YTilt",         [ABS_TOOL_WIDTH] = "ToolWidth",
        [ABS_VOLUME] = "Volume",        [ABS_MISC] = "Misc",
+       [ABS_MT_TOUCH_MAJOR] = "MTMajor",
+       [ABS_MT_TOUCH_MINOR] = "MTMinor",
+       [ABS_MT_WIDTH_MAJOR] = "MTMajorW",
+       [ABS_MT_WIDTH_MINOR] = "MTMinorW",
+       [ABS_MT_ORIENTATION] = "MTOrientation",
+       [ABS_MT_POSITION_X] = "MTPositionX",
+       [ABS_MT_POSITION_Y] = "MTPositionY",
+       [ABS_MT_TOOL_TYPE] = "MTToolType",
+       [ABS_MT_BLOB_ID] = "MTBlobID",
 };
 
 static const char *misc[MSC_MAX + 1] = {
index 34f3eb65100b5db04399fc74a46a534db8c12837..a239d20ad7a5f1e08d84500f9b02d821fa604ab3 100644 (file)
@@ -32,6 +32,8 @@
 #include <linux/hid.h>
 
 #include "hid-ids.h"
+
+#ifdef CONFIG_DRAGONRISE_FF
 #include "usbhid/usbhid.h"
 
 struct drff_device {
@@ -135,6 +137,12 @@ static int drff_init(struct hid_device *hid)
 
        return 0;
 }
+#else
+static inline int drff_init(struct hid_device *hid)
+{
+       return 0;
+}
+#endif
 
 static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
index 510ad3ab8d3369b5cb298813310b48790d73ed27..8a11ccddaf2e4b2b1382ee809db43cc55c82336c 100644 (file)
@@ -31,6 +31,8 @@
 #include <linux/usb.h>
 #include <linux/hid.h>
 #include "hid-ids.h"
+
+#ifdef CONFIG_GREENASIA_FF
 #include "usbhid/usbhid.h"
 
 struct gaff_device {
@@ -130,6 +132,12 @@ static int gaff_init(struct hid_device *hid)
 
        return 0;
 }
+#else
+static inline int gaff_init(struct hid_device *hdev)
+{
+       return 0;
+}
+#endif
 
 static int ga_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
index 4d5ee2bbc62b693aaf97467b2ff689596efe6278..6301010379215ca35eb07ea07c2be124e6fb50e6 100644 (file)
 #define USB_DEVICE_ID_VERNIER_LCSPEC   0x0006
 
 #define USB_VENDOR_ID_WACOM            0x056a
+#define USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH 0x81
 
 #define USB_VENDOR_ID_WISEGROUP                0x0925
+#define USB_DEVICE_ID_SMARTJOY_PLUS    0x0005
 #define USB_DEVICE_ID_1_PHIDGETSERVO_20        0x8101
 #define USB_DEVICE_ID_4_PHIDGETSERVO_20        0x8104
 #define USB_DEVICE_ID_8_8_4_IF_KIT     0x8201
index 51aff08e10ce66d78853a48b2536ab1179ee8d8f..56099709581cc689ec88210672ca30a7982cf833 100644 (file)
@@ -50,6 +50,12 @@ static const signed short ff_joystick[] = {
        -1
 };
 
+static const signed short ff_joystick_ac[] = {
+       FF_CONSTANT,
+       FF_AUTOCENTER,
+       -1
+};
+
 static const signed short ff_wheel[] = {
        FF_CONSTANT,
        FF_AUTOCENTER,
@@ -60,8 +66,8 @@ static const struct dev_type devices[] = {
        { 0x046d, 0xc211, ff_rumble },
        { 0x046d, 0xc219, ff_rumble },
        { 0x046d, 0xc283, ff_joystick },
-       { 0x046d, 0xc286, ff_joystick },
-       { 0x046d, 0xc294, ff_joystick },
+       { 0x046d, 0xc286, ff_joystick_ac },
+       { 0x046d, 0xc294, ff_wheel },
        { 0x046d, 0xc295, ff_joystick },
        { 0x046d, 0xca03, ff_wheel },
 };
index c5b252be9c217888b46f587a58e41d847142e651..75ed9d2c1a36a563dc36b29515d6acb1ba7478b9 100644 (file)
@@ -1,13 +1,8 @@
 /*
- *  HID driver for some ntrig "special" devices
+ *  HID driver for N-Trig touchscreens
  *
- *  Copyright (c) 1999 Andreas Gal
- *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
- *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
- *  Copyright (c) 2006-2007 Jiri Kosina
- *  Copyright (c) 2007 Paul Walmsley
- *  Copyright (c) 2008 Jiri Slaby
  *  Copyright (c) 2008 Rafi Rubin
+ *  Copyright (c) 2009 Stephane Chatty
  *
  */
 
 #define nt_map_key_clear(c)    hid_map_usage_clear(hi, usage, bit, max, \
                                        EV_KEY, (c))
 
+struct ntrig_data {
+       __s32 x, y, id, w, h;
+       char reading_a_point, found_contact_id;
+};
+
+/*
+ * this driver is aimed at two firmware versions in circulation:
+ *  - dual pen/finger single touch
+ *  - finger multitouch, pen not working
+ */
+
 static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                struct hid_field *field, struct hid_usage *usage,
                unsigned long **bit, int *max)
 {
-       if ((usage->hid & HID_USAGE_PAGE) == HID_UP_DIGITIZER &&
-                       (usage->hid & 0xff) == 0x47) {
-               nt_map_key_clear(BTN_TOOL_DOUBLETAP);
-               return 1;
+       switch (usage->hid & HID_USAGE_PAGE) {
+
+       case HID_UP_GENDESK:
+               switch (usage->hid) {
+               case HID_GD_X:
+                       hid_map_usage(hi, usage, bit, max,
+                                       EV_ABS, ABS_MT_POSITION_X);
+                       input_set_abs_params(hi->input, ABS_X,
+                                       field->logical_minimum,
+                                       field->logical_maximum, 0, 0);
+                       return 1;
+               case HID_GD_Y:
+                       hid_map_usage(hi, usage, bit, max,
+                                       EV_ABS, ABS_MT_POSITION_Y);
+                       input_set_abs_params(hi->input, ABS_Y,
+                                       field->logical_minimum,
+                                       field->logical_maximum, 0, 0);
+                       return 1;
+               }
+               return 0;
+
+       case HID_UP_DIGITIZER:
+               switch (usage->hid) {
+               /* we do not want to map these for now */
+               case HID_DG_INVERT: /* value is always 0 */
+               case HID_DG_ERASER: /* value is always 0 */
+               case HID_DG_CONTACTID: /* value is useless */
+               case HID_DG_BARRELSWITCH:  /* doubtful */
+               case HID_DG_INPUTMODE:
+               case HID_DG_DEVICEINDEX:
+               case HID_DG_CONTACTCOUNT:
+               case HID_DG_CONTACTMAX:
+                       return -1;
+
+               /* original mapping by Rafi Rubin */
+               case HID_DG_CONFIDENCE:
+                       nt_map_key_clear(BTN_TOOL_DOUBLETAP);
+                       return 1;
+
+               /* width/height mapped on TouchMajor/TouchMinor/Orientation */
+               case HID_DG_WIDTH:
+                       hid_map_usage(hi, usage, bit, max,
+                                       EV_ABS, ABS_MT_TOUCH_MAJOR);
+                       return 1;
+               case HID_DG_HEIGHT:
+                       hid_map_usage(hi, usage, bit, max,
+                                       EV_ABS, ABS_MT_TOUCH_MINOR);
+                       input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
+                                       0, 1, 0, 0);
+                       return 1;
+               }
+               return 0;
+
+       case 0xff000000:
+               /* we do not want to map these: no input-oriented meaning */
+               return -1;
        }
+
        return 0;
 }
 
@@ -51,6 +110,138 @@ static int ntrig_input_mapped(struct hid_device *hdev, struct hid_input *hi,
 
        return 0;
 }
+
+/*
+ * this function is called upon all reports
+ * so that we can filter contact point information,
+ * decide whether we are in multi or single touch mode
+ * and call input_mt_sync after each point if necessary
+ */
+static int ntrig_event (struct hid_device *hid, struct hid_field *field,
+                                       struct hid_usage *usage, __s32 value)
+{
+       struct input_dev *input = field->hidinput->input;
+       struct ntrig_data *nd = hid_get_drvdata(hid);
+
+        if (hid->claimed & HID_CLAIMED_INPUT) {
+               switch (usage->hid) {
+               case HID_GD_X:
+                       nd->x = value;
+                       nd->reading_a_point = 1;
+                       break;
+               case HID_GD_Y:
+                       nd->y = value;
+                       break;
+               case HID_DG_CONTACTID:
+                       nd->id = value;
+                       /* we receive this only when in multitouch mode */
+                       nd->found_contact_id = 1;
+                       break;
+               case HID_DG_WIDTH:
+                       nd->w = value;
+                       break;
+               case HID_DG_HEIGHT:
+                       nd->h = value;
+                       /*
+                        * when in single touch mode, this is the last
+                        * report received in a finger event. We want
+                        * to emit a normal (X, Y) position
+                        */
+                       if (! nd->found_contact_id) {
+                               input_event(input, EV_ABS, ABS_X, nd->x);
+                               input_event(input, EV_ABS, ABS_Y, nd->y);
+                       }
+                       break;
+               case HID_DG_TIPPRESSURE:
+                       /*
+                        * when in single touch mode, this is the last
+                        * report received in a pen event. We want
+                        * to emit a normal (X, Y) position
+                        */
+                       if (! nd->found_contact_id) {
+                               input_event(input, EV_ABS, ABS_X, nd->x);
+                               input_event(input, EV_ABS, ABS_Y, nd->y);
+                               input_event(input, EV_ABS, ABS_PRESSURE, value);
+                       }
+                       break;
+               case 0xff000002:
+                       /*
+                        * we receive this when the device is in multitouch
+                        * mode. The first of the three values tagged with
+                        * this usage tells if the contact point is real
+                        * or a placeholder
+                        */
+                       if (!nd->reading_a_point || value != 1)
+                               break;
+                       /* emit a normal (X, Y) for the first point only */
+                       if (nd->id == 0) {
+                               input_event(input, EV_ABS, ABS_X, nd->x);
+                               input_event(input, EV_ABS, ABS_Y, nd->y);
+                       }
+                       input_event(input, EV_ABS, ABS_MT_POSITION_X, nd->x);
+                       input_event(input, EV_ABS, ABS_MT_POSITION_Y, nd->y);
+                       if (nd->w > nd->h) {
+                               input_event(input, EV_ABS,
+                                               ABS_MT_ORIENTATION, 1);
+                               input_event(input, EV_ABS,
+                                               ABS_MT_TOUCH_MAJOR, nd->w);
+                               input_event(input, EV_ABS,
+                                               ABS_MT_TOUCH_MINOR, nd->h);
+                       } else {
+                               input_event(input, EV_ABS,
+                                               ABS_MT_ORIENTATION, 0);
+                               input_event(input, EV_ABS,
+                                               ABS_MT_TOUCH_MAJOR, nd->h);
+                               input_event(input, EV_ABS,
+                                               ABS_MT_TOUCH_MINOR, nd->w);
+                       }
+                       input_mt_sync(field->hidinput->input);
+                       nd->reading_a_point = 0;
+                       nd->found_contact_id = 0;
+                       break;
+
+               default:
+                       /* fallback to the generic hidinput handling */
+                       return 0;
+               }
+       }
+
+       /* we have handled the hidinput part, now remains hiddev */
+        if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
+                hid->hiddev_hid_event(hid, field, usage, value);
+
+       return 1;
+}
+
+static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       int ret;
+       struct ntrig_data *nd;
+
+       nd = kmalloc(sizeof(struct ntrig_data), GFP_KERNEL);
+       if (!nd) {
+               dev_err(&hdev->dev, "cannot allocate N-Trig data\n");
+               return -ENOMEM;
+       }
+       nd->reading_a_point = 0;
+       nd->found_contact_id = 0;
+       hid_set_drvdata(hdev, nd);
+
+       ret = hid_parse(hdev);
+       if (!ret)
+               ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+
+       if (ret)
+               kfree (nd);
+       return ret;
+}
+
+static void ntrig_remove(struct hid_device *hdev)
+{
+       hid_hw_stop(hdev);
+       kfree(hid_get_drvdata(hdev));
+}
+
 static const struct hid_device_id ntrig_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN),
                .driver_data = NTRIG_DUPLICATE_USAGES },
@@ -58,11 +249,20 @@ static const struct hid_device_id ntrig_devices[] = {
 };
 MODULE_DEVICE_TABLE(hid, ntrig_devices);
 
+static const struct hid_usage_id ntrig_grabbed_usages[] = {
+       { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
+       { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
+};
+
 static struct hid_driver ntrig_driver = {
        .name = "ntrig",
        .id_table = ntrig_devices,
+       .probe = ntrig_probe,
+       .remove = ntrig_remove,
        .input_mapping = ntrig_input_mapping,
        .input_mapped = ntrig_input_mapped,
+       .usage_table = ntrig_grabbed_usages,
+       .event = ntrig_event,
 };
 
 static int ntrig_init(void)
diff --git a/drivers/hid/hid-sjoy.c b/drivers/hid/hid-sjoy.c
new file mode 100644 (file)
index 0000000..eab169e
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ *  Force feedback support for SmartJoy PLUS PS2->USB adapter
+ *
+ *  Copyright (c) 2009 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ *
+ *  Based of hid-pl.c and hid-gaff.c
+ *   Copyright (c) 2007, 2009 Anssi Hannula <anssi.hannula@gmail.com>
+ *   Copyright (c) 2008 Lukasz Lubojanski <lukasz@lubojanski.info>
+ */
+
+/*
+ * 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 DEBUG */
+
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+#include "hid-ids.h"
+
+#ifdef CONFIG_SMARTJOYPLUS_FF
+#include "usbhid/usbhid.h"
+
+struct sjoyff_device {
+       struct hid_report *report;
+};
+
+static int hid_sjoyff_play(struct input_dev *dev, void *data,
+                        struct ff_effect *effect)
+{
+       struct hid_device *hid = input_get_drvdata(dev);
+       struct sjoyff_device *sjoyff = data;
+       u32 left, right;
+
+       left = effect->u.rumble.strong_magnitude;
+       right = effect->u.rumble.weak_magnitude;
+       dev_dbg(&dev->dev, "called with 0x%08x 0x%08x\n", left, right);
+
+       left = left * 0xff / 0xffff;
+       right = (right != 0); /* on/off only */
+
+       sjoyff->report->field[0]->value[1] = right;
+       sjoyff->report->field[0]->value[2] = left;
+       dev_dbg(&dev->dev, "running with 0x%02x 0x%02x\n", left, right);
+       usbhid_submit_report(hid, sjoyff->report, USB_DIR_OUT);
+
+       return 0;
+}
+
+static int sjoyff_init(struct hid_device *hid)
+{
+       struct sjoyff_device *sjoyff;
+       struct hid_report *report;
+       struct hid_input *hidinput = list_entry(hid->inputs.next,
+                                               struct hid_input, list);
+       struct list_head *report_list =
+                       &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+       struct list_head *report_ptr = report_list;
+       struct input_dev *dev;
+       int error;
+
+       if (list_empty(report_list)) {
+               dev_err(&hid->dev, "no output reports found\n");
+               return -ENODEV;
+       }
+
+       report_ptr = report_ptr->next;
+
+       if (report_ptr == report_list) {
+               dev_err(&hid->dev, "required output report is "
+                               "missing\n");
+               return -ENODEV;
+       }
+
+       report = list_entry(report_ptr, struct hid_report, list);
+       if (report->maxfield < 1) {
+               dev_err(&hid->dev, "no fields in the report\n");
+               return -ENODEV;
+       }
+
+       if (report->field[0]->report_count < 3) {
+               dev_err(&hid->dev, "not enough values in the field\n");
+               return -ENODEV;
+       }
+
+       sjoyff = kzalloc(sizeof(struct sjoyff_device), GFP_KERNEL);
+       if (!sjoyff)
+               return -ENOMEM;
+
+       dev = hidinput->input;
+
+       set_bit(FF_RUMBLE, dev->ffbit);
+
+       error = input_ff_create_memless(dev, sjoyff, hid_sjoyff_play);
+       if (error) {
+               kfree(sjoyff);
+               return error;
+       }
+
+       sjoyff->report = report;
+       sjoyff->report->field[0]->value[0] = 0x01;
+       sjoyff->report->field[0]->value[1] = 0x00;
+       sjoyff->report->field[0]->value[2] = 0x00;
+       usbhid_submit_report(hid, sjoyff->report, USB_DIR_OUT);
+
+       dev_info(&hid->dev,
+               "Force feedback for SmartJoy PLUS PS2/USB adapter\n");
+
+       return 0;
+}
+#else
+static inline int sjoyff_init(struct hid_device *hid)
+{
+       return 0;
+}
+#endif
+
+static int sjoy_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       int ret;
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               dev_err(&hdev->dev, "parse failed\n");
+               goto err;
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+       if (ret) {
+               dev_err(&hdev->dev, "hw start failed\n");
+               goto err;
+       }
+
+       sjoyff_init(hdev);
+
+       return 0;
+err:
+       return ret;
+}
+
+static const struct hid_device_id sjoy_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, sjoy_devices);
+
+static struct hid_driver sjoy_driver = {
+       .name = "smartjoyplus",
+       .id_table = sjoy_devices,
+       .probe = sjoy_probe,
+};
+
+static int sjoy_init(void)
+{
+       return hid_register_driver(&sjoy_driver);
+}
+
+static void sjoy_exit(void)
+{
+       hid_unregister_driver(&sjoy_driver);
+}
+
+module_init(sjoy_init);
+module_exit(sjoy_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jussi Kivilinna");
+
index 7c1f7b50330cd6d5bd6b13e9388560c2ef3a5950..fcd6ccd02fee28fb77d9775f962c38cdec516754 100644 (file)
 
 #include "hid-ids.h"
 
-#include "usbhid/usbhid.h"
-
-/* Usages for thrustmaster devices I know about */
-#define THRUSTMASTER_USAGE_FF  (HID_UP_GENDESK | 0xbb)
-
 static const signed short ff_rumble[] = {
        FF_RUMBLE,
        -1
@@ -48,6 +43,12 @@ static const signed short ff_joystick[] = {
        -1
 };
 
+#ifdef CONFIG_THRUSTMASTER_FF
+#include "usbhid/usbhid.h"
+
+/* Usages for thrustmaster devices I know about */
+#define THRUSTMASTER_USAGE_FF  (HID_UP_GENDESK | 0xbb)
+
 struct tmff_device {
        struct hid_report *report;
        struct hid_field *ff_field;
@@ -209,6 +210,12 @@ fail:
        kfree(tmff);
        return error;
 }
+#else
+static inline int tmff_init(struct hid_device *hid, const signed short *ff_bits)
+{
+       return 0;
+}
+#endif
 
 static int tm_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
new file mode 100644 (file)
index 0000000..1f9237f
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ *  Bluetooth Wacom Tablet support
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com>
+ *  Copyright (c) 2006 Andrew Zabolotny <zap@homelink.ru>
+ *  Copyright (c) 2009 Bastien Nocera <hadess@hadess.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.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+struct wacom_data {
+       __u16 tool;
+       unsigned char butstate;
+};
+
+static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
+               u8 *raw_data, int size)
+{
+       struct wacom_data *wdata = hid_get_drvdata(hdev);
+       struct hid_input *hidinput;
+       struct input_dev *input;
+       unsigned char *data = (unsigned char *) raw_data;
+       int tool, x, y, rw;
+
+       if (!(hdev->claimed & HID_CLAIMED_INPUT))
+               return 0;
+
+       tool = 0;
+       hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
+       input = hidinput->input;
+
+       /* Check if this is a tablet report */
+       if (data[0] != 0x03)
+               return 0;
+
+       /* Get X & Y positions */
+       x = le16_to_cpu(*(__le16 *) &data[2]);
+       y = le16_to_cpu(*(__le16 *) &data[4]);
+
+       /* Get current tool identifier */
+       if (data[1] & 0x90) { /* If pen is in the in/active area */
+               switch ((data[1] >> 5) & 3) {
+               case 0: /* Pen */
+                       tool = BTN_TOOL_PEN;
+                       break;
+
+               case 1: /* Rubber */
+                       tool = BTN_TOOL_RUBBER;
+                       break;
+
+               case 2: /* Mouse with wheel */
+               case 3: /* Mouse without wheel */
+                       tool = BTN_TOOL_MOUSE;
+                       break;
+               }
+
+               /* Reset tool if out of active tablet area */
+               if (!(data[1] & 0x10))
+                       tool = 0;
+       }
+
+       /* If tool changed, notify input subsystem */
+       if (wdata->tool != tool) {
+               if (wdata->tool) {
+                       /* Completely reset old tool state */
+                       if (wdata->tool == BTN_TOOL_MOUSE) {
+                               input_report_key(input, BTN_LEFT, 0);
+                               input_report_key(input, BTN_RIGHT, 0);
+                               input_report_key(input, BTN_MIDDLE, 0);
+                               input_report_abs(input, ABS_DISTANCE,
+                                               input->absmax[ABS_DISTANCE]);
+                       } else {
+                               input_report_key(input, BTN_TOUCH, 0);
+                               input_report_key(input, BTN_STYLUS, 0);
+                               input_report_key(input, BTN_STYLUS2, 0);
+                               input_report_abs(input, ABS_PRESSURE, 0);
+                       }
+                       input_report_key(input, wdata->tool, 0);
+                       input_sync(input);
+               }
+               wdata->tool = tool;
+               if (tool)
+                       input_report_key(input, tool, 1);
+       }
+
+       if (tool) {
+               input_report_abs(input, ABS_X, x);
+               input_report_abs(input, ABS_Y, y);
+
+               switch ((data[1] >> 5) & 3) {
+               case 2: /* Mouse with wheel */
+                       input_report_key(input, BTN_MIDDLE, data[1] & 0x04);
+                       rw = (data[6] & 0x01) ? -1 :
+                               (data[6] & 0x02) ? 1 : 0;
+                       input_report_rel(input, REL_WHEEL, rw);
+                       /* fall through */
+
+               case 3: /* Mouse without wheel */
+                       input_report_key(input, BTN_LEFT, data[1] & 0x01);
+                       input_report_key(input, BTN_RIGHT, data[1] & 0x02);
+                       /* Compute distance between mouse and tablet */
+                       rw = 44 - (data[6] >> 2);
+                       if (rw < 0)
+                               rw = 0;
+                       else if (rw > 31)
+                               rw = 31;
+                       input_report_abs(input, ABS_DISTANCE, rw);
+                       break;
+
+               default:
+                       input_report_abs(input, ABS_PRESSURE,
+                                       data[6] | (((__u16) (data[1] & 0x08)) << 5));
+                       input_report_key(input, BTN_TOUCH, data[1] & 0x01);
+                       input_report_key(input, BTN_STYLUS, data[1] & 0x02);
+                       input_report_key(input, BTN_STYLUS2, (tool == BTN_TOOL_PEN) && data[1] & 0x04);
+                       break;
+               }
+
+               input_sync(input);
+       }
+
+       /* Report the state of the two buttons at the top of the tablet
+        * as two extra fingerpad keys (buttons 4 & 5). */
+       rw = data[7] & 0x03;
+       if (rw != wdata->butstate) {
+               wdata->butstate = rw;
+               input_report_key(input, BTN_0, rw & 0x02);
+               input_report_key(input, BTN_1, rw & 0x01);
+               input_event(input, EV_MSC, MSC_SERIAL, 0xf0);
+               input_sync(input);
+       }
+
+       return 1;
+}
+
+static int wacom_probe(struct hid_device *hdev,
+               const struct hid_device_id *id)
+{
+       struct hid_input *hidinput;
+       struct input_dev *input;
+       struct wacom_data *wdata;
+       int ret;
+
+       wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
+       if (wdata == NULL) {
+               dev_err(&hdev->dev, "can't alloc wacom descriptor\n");
+               return -ENOMEM;
+       }
+
+       hid_set_drvdata(hdev, wdata);
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               dev_err(&hdev->dev, "parse failed\n");
+               goto err_free;
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+       if (ret) {
+               dev_err(&hdev->dev, "hw start failed\n");
+               goto err_free;
+       }
+
+       hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
+       input = hidinput->input;
+
+       /* Basics */
+       input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL);
+       input->absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) |
+               BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE);
+       input->relbit[0] |= BIT(REL_WHEEL);
+       set_bit(BTN_TOOL_PEN, input->keybit);
+       set_bit(BTN_TOUCH, input->keybit);
+       set_bit(BTN_STYLUS, input->keybit);
+       set_bit(BTN_STYLUS2, input->keybit);
+       set_bit(BTN_LEFT, input->keybit);
+       set_bit(BTN_RIGHT, input->keybit);
+       set_bit(BTN_MIDDLE, input->keybit);
+
+       /* Pad */
+       input->evbit[0] |= BIT(EV_MSC);
+       input->mscbit[0] |= BIT(MSC_SERIAL);
+
+       /* Distance, rubber and mouse */
+       input->absbit[0] |= BIT(ABS_DISTANCE);
+       set_bit(BTN_TOOL_RUBBER, input->keybit);
+       set_bit(BTN_TOOL_MOUSE, input->keybit);
+
+       input->absmax[ABS_PRESSURE] = 511;
+       input->absmax[ABS_DISTANCE] = 32;
+
+       input->absmax[ABS_X] = 16704;
+       input->absmax[ABS_Y] = 12064;
+       input->absfuzz[ABS_X] = 4;
+       input->absfuzz[ABS_Y] = 4;
+
+       return 0;
+err_free:
+       kfree(wdata);
+       return ret;
+}
+
+static void wacom_remove(struct hid_device *hdev)
+{
+       hid_hw_stop(hdev);
+       kfree(hid_get_drvdata(hdev));
+}
+
+static const struct hid_device_id wacom_devices[] = {
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
+
+       { }
+};
+MODULE_DEVICE_TABLE(hid, wacom_devices);
+
+static struct hid_driver wacom_driver = {
+       .name = "wacom",
+       .id_table = wacom_devices,
+       .probe = wacom_probe,
+       .remove = wacom_remove,
+       .raw_event = wacom_raw_event,
+};
+
+static int wacom_init(void)
+{
+       int ret;
+
+       ret = hid_register_driver(&wacom_driver);
+       if (ret)
+               printk(KERN_ERR "can't register wacom driver\n");
+       printk(KERN_ERR "wacom driver registered\n");
+       return ret;
+}
+
+static void wacom_exit(void)
+{
+       hid_unregister_driver(&wacom_driver);
+}
+
+module_init(wacom_init);
+module_exit(wacom_exit);
+MODULE_LICENSE("GPL");
+
index 85a198a185372967fa487a744d1d5517216a9136..57f710757bf425ac6b32fb49314121357e327b41 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "hid-ids.h"
 
+#ifdef CONFIG_ZEROPLUS_FF
 #include "usbhid/usbhid.h"
 
 struct zpff_device {
@@ -108,6 +109,12 @@ static int zpff_init(struct hid_device *hid)
 
        return 0;
 }
+#else
+static inline int zpff_init(struct hid_device *hid)
+{
+       return 0;
+}
+#endif
 
 static int zp_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
index 00ccf4b1985d936280a0fc698fb5092950b1f5f1..0c6639ea03dd1748076dd8742035f1f154603cd9 100644 (file)
@@ -349,10 +349,7 @@ int hidraw_connect(struct hid_device *hid)
        int minor, result;
        struct hidraw *dev;
 
-       /* TODO currently we accept any HID device. This should later
-        * probably be fixed to accept only those devices which provide
-        * non-input applications
-        */
+       /* we accept any HID device, no matter the applications */
 
        dev = kzalloc(sizeof(struct hidraw), GFP_KERNEL);
        if (!dev)
index ac8049b5f1e934a658f3127457efc7626794c7e8..76c4bbe9dccb334ef64359f701321f8fc13df5b3 100644 (file)
@@ -1234,12 +1234,11 @@ static int hid_post_reset(struct usb_interface *intf)
        struct hid_device *hid = usb_get_intfdata(intf);
        struct usbhid_device *usbhid = hid->driver_data;
        int status;
+
        spin_lock_irq(&usbhid->lock);
        clear_bit(HID_RESET_PENDING, &usbhid->iofl);
        spin_unlock_irq(&usbhid->lock);
        hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0);
-       /* FIXME: Any more reinitialization needed? */
        status = hid_start_in(hid);
        if (status < 0)
                hid_io_error(hid);
@@ -1251,14 +1250,14 @@ static int hid_post_reset(struct usb_interface *intf)
 int usbhid_get_power(struct hid_device *hid)
 {
        struct usbhid_device *usbhid = hid->driver_data;
+
        return usb_autopm_get_interface(usbhid->intf);
 }
 
 void usbhid_put_power(struct hid_device *hid)
 {
        struct usbhid_device *usbhid = hid->driver_data;
+
        usb_autopm_put_interface(usbhid->intf);
 }
 
index f1c6ca7e285235bd2033831929bec4d22e259672..c8460fa9cfac751b8c236d9ad171f823376951d7 100644 (file)
@@ -298,7 +298,7 @@ config I2C_BLACKFIN_TWI
 config I2C_BLACKFIN_TWI_CLK_KHZ
        int "Blackfin TWI I2C clock (kHz)"
        depends on I2C_BLACKFIN_TWI
-       range 10 400
+       range 21 400
        default 50
        help
          The unit of the TWI clock is kHz.
index fc548b3d002e581fe29bd351aa48c11356650e2c..26d8987e69bf171f2e0431789b4192da2a461a51 100644 (file)
@@ -104,9 +104,14 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
                        write_MASTER_CTL(iface,
                                read_MASTER_CTL(iface) | STOP);
                else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
-                               iface->cur_msg+1 < iface->msg_num)
-                       write_MASTER_CTL(iface,
-                               read_MASTER_CTL(iface) | RSTART);
+                        iface->cur_msg + 1 < iface->msg_num) {
+                       if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
+                               write_MASTER_CTL(iface,
+                                       read_MASTER_CTL(iface) | RSTART | MDIR);
+                       else
+                               write_MASTER_CTL(iface,
+                                       (read_MASTER_CTL(iface) | RSTART) & ~MDIR);
+               }
                SSYNC();
                /* Clear status */
                write_INT_STAT(iface, XMTSERV);
@@ -134,9 +139,13 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
                                read_MASTER_CTL(iface) | STOP);
                        SSYNC();
                } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
-                               iface->cur_msg+1 < iface->msg_num) {
-                       write_MASTER_CTL(iface,
-                               read_MASTER_CTL(iface) | RSTART);
+                          iface->cur_msg + 1 < iface->msg_num) {
+                       if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
+                               write_MASTER_CTL(iface,
+                                       read_MASTER_CTL(iface) | RSTART | MDIR);
+                       else
+                               write_MASTER_CTL(iface,
+                                       (read_MASTER_CTL(iface) | RSTART) & ~MDIR);
                        SSYNC();
                }
                /* Clear interrupt source */
@@ -196,8 +205,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
                        /* remove restart bit and enable master receive */
                        write_MASTER_CTL(iface,
                                read_MASTER_CTL(iface) & ~RSTART);
-                       write_MASTER_CTL(iface,
-                               read_MASTER_CTL(iface) | MEN | MDIR);
                        SSYNC();
                } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
                                iface->cur_msg+1 < iface->msg_num) {
@@ -222,18 +229,19 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
                        }
 
                        if (iface->pmsg[iface->cur_msg].len <= 255)
-                               write_MASTER_CTL(iface,
-                               iface->pmsg[iface->cur_msg].len << 6);
+                                       write_MASTER_CTL(iface,
+                                       (read_MASTER_CTL(iface) &
+                                       (~(0xff << 6))) |
+                               (iface->pmsg[iface->cur_msg].len << 6));
                        else {
-                               write_MASTER_CTL(iface, 0xff << 6);
+                               write_MASTER_CTL(iface,
+                                       (read_MASTER_CTL(iface) |
+                                       (0xff << 6)));
                                iface->manual_stop = 1;
                        }
                        /* remove restart bit and enable master receive */
                        write_MASTER_CTL(iface,
                                read_MASTER_CTL(iface) & ~RSTART);
-                       write_MASTER_CTL(iface, read_MASTER_CTL(iface) |
-                               MEN | ((iface->read_write == I2C_SMBUS_READ) ?
-                               MDIR : 0));
                        SSYNC();
                } else {
                        iface->result = 1;
@@ -441,6 +449,16 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
                }
                iface->transPtr = data->block;
                break;
+       case I2C_SMBUS_I2C_BLOCK_DATA:
+               if (read_write == I2C_SMBUS_READ) {
+                       iface->readNum = data->block[0];
+                       iface->cur_mode = TWI_I2C_MODE_COMBINED;
+               } else {
+                       iface->writeNum = data->block[0];
+                       iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+               }
+               iface->transPtr = (u8 *)&data->block[1];
+               break;
        default:
                return -1;
        }
@@ -564,7 +582,7 @@ static u32 bfin_twi_functionality(struct i2c_adapter *adap)
        return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
               I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
               I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL |
-              I2C_FUNC_I2C;
+              I2C_FUNC_I2C | I2C_FUNC_SMBUS_I2C_BLOCK;
 }
 
 static struct i2c_algorithm bfin_twi_algorithm = {
@@ -614,6 +632,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
        struct i2c_adapter *p_adap;
        struct resource *res;
        int rc;
+       unsigned int clkhilow;
 
        iface = kzalloc(sizeof(struct bfin_twi_iface), GFP_KERNEL);
        if (!iface) {
@@ -675,10 +694,14 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
        /* Set TWI internal clock as 10MHz */
        write_CONTROL(iface, ((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F);
 
+       /*
+        * We will not end up with a CLKDIV=0 because no one will specify
+        * 20kHz SCL or less in Kconfig now. (5 * 1024 / 20 = 0x100)
+        */
+       clkhilow = 5 * 1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ;
+
        /* Set Twi interface clock as specified */
-       write_CLKDIV(iface, ((5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ)
-                       << 8) | ((5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ)
-                       & 0xFF));
+       write_CLKDIV(iface, (clkhilow << 8) | clkhilow);
 
        /* Enable TWI */
        write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA);
index e5193bf754837bda5108651679c477ecd4248456..3542c6ba98f1ab9ba8bdd5279a8400a35f11592e 100644 (file)
@@ -216,6 +216,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
        struct ocores_i2c_platform_data *pdata;
        struct resource *res, *res2;
        int ret;
+       int i;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res)
@@ -271,6 +272,10 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
                goto add_adapter_failed;
        }
 
+       /* add in known devices to the bus */
+       for (i = 0; i < pdata->num_devices; i++)
+               i2c_new_device(&i2c->adap, pdata->devices + i);
+
        return 0;
 
 add_adapter_failed:
index ece0125a1ee520710f1e4ac18cd7b8eea83f0422..c73475dd0fba00c2dd5953b3b37ebf5837ad7f37 100644 (file)
@@ -333,8 +333,18 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
 
        if (cpu_is_omap2430() || cpu_is_omap34xx()) {
 
-               /* HSI2C controller internal clk rate should be 19.2 Mhz */
-               internal_clk = 19200;
+               /*
+                * HSI2C controller internal clk rate should be 19.2 Mhz for
+                * HS and for all modes on 2430. On 34xx we can use lower rate
+                * to get longer filter period for better noise suppression.
+                * The filter is iclk (fclk for HS) period.
+                */
+               if (dev->speed > 400 || cpu_is_omap_2430())
+                       internal_clk = 19200;
+               else if (dev->speed > 100)
+                       internal_clk = 9600;
+               else
+                       internal_clk = 4000;
                fclk_rate = clk_get_rate(dev->fclk) / 1000;
 
                /* Compute prescaler divisor */
@@ -343,17 +353,28 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
 
                /* If configured for High Speed */
                if (dev->speed > 400) {
+                       unsigned long scl;
+
                        /* For first phase of HS mode */
-                       fsscll = internal_clk / (400 * 2) - 6;
-                       fssclh = internal_clk / (400 * 2) - 6;
+                       scl = internal_clk / 400;
+                       fsscll = scl - (scl / 3) - 7;
+                       fssclh = (scl / 3) - 5;
 
                        /* For second phase of HS mode */
-                       hsscll = fclk_rate / (dev->speed * 2) - 6;
-                       hssclh = fclk_rate / (dev->speed * 2) - 6;
+                       scl = fclk_rate / dev->speed;
+                       hsscll = scl - (scl / 3) - 7;
+                       hssclh = (scl / 3) - 5;
+               } else if (dev->speed > 100) {
+                       unsigned long scl;
+
+                       /* Fast mode */
+                       scl = internal_clk / dev->speed;
+                       fsscll = scl - (scl / 3) - 7;
+                       fssclh = (scl / 3) - 5;
                } else {
-                       /* To handle F/S modes */
-                       fsscll = internal_clk / (dev->speed * 2) - 6;
-                       fssclh = internal_clk / (dev->speed * 2) - 6;
+                       /* Standard mode */
+                       fsscll = internal_clk / (dev->speed * 2) - 7;
+                       fssclh = internal_clk / (dev->speed * 2) - 5;
                }
                scll = (hsscll << OMAP_I2C_SCLL_HSSCLL) | fsscll;
                sclh = (hssclh << OMAP_I2C_SCLH_HSSCLH) | fssclh;
index acc7143d96550b1e7880f5f03e13f828271546fa..035a6c7e59df846b44ad49ba91400d250580a5e2 100644 (file)
 #include <linux/err.h>
 #include <linux/clk.h>
 
-#include <mach/hardware.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#include <mach/i2c.h>
+#include <plat/i2c.h>
+
+/*
+ * I2C register offsets will be shifted 0 or 1 bit left, depending on
+ * different SoCs
+ */
+#define REG_SHIFT_0    (0 << 0)
+#define REG_SHIFT_1    (1 << 0)
+#define REG_SHIFT(d)   ((d) & 0x1)
+
+static const struct platform_device_id i2c_pxa_id_table[] = {
+       { "pxa2xx-i2c",         REG_SHIFT_1 },
+       { "pxa3xx-pwri2c",      REG_SHIFT_0 },
+       { },
+};
+MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table);
 
 /*
  * I2C registers and bit definitions
@@ -985,6 +999,7 @@ static int i2c_pxa_probe(struct platform_device *dev)
        struct pxa_i2c *i2c;
        struct resource *res;
        struct i2c_pxa_platform_data *plat = dev->dev.platform_data;
+       struct platform_device_id *id = platform_get_device_id(dev);
        int ret;
        int irq;
 
@@ -1028,7 +1043,7 @@ static int i2c_pxa_probe(struct platform_device *dev)
                ret = -EIO;
                goto eremap;
        }
-       i2c->reg_shift = (cpu_is_pxa3xx() && (dev->id == 1)) ? 0 : 1;
+       i2c->reg_shift = REG_SHIFT(id->driver_data);
 
        i2c->iobase = res->start;
        i2c->iosize = res_len(res);
@@ -1150,6 +1165,7 @@ static struct platform_driver i2c_pxa_driver = {
                .name   = "pxa2xx-i2c",
                .owner  = THIS_MODULE,
        },
+       .id_table       = i2c_pxa_id_table,
 };
 
 static int __init i2c_adap_pxa_init(void)
index 1691ef0f1ee1ee64dcd9352cf785849b26592623..079a312d36fd098422a842e53e00b59ac758f395 100644 (file)
@@ -51,6 +51,11 @@ enum s3c24xx_i2c_state {
        STATE_STOP
 };
 
+enum s3c24xx_i2c_type {
+       TYPE_S3C2410,
+       TYPE_S3C2440,
+};
+
 struct s3c24xx_i2c {
        spinlock_t              lock;
        wait_queue_head_t       wait;
@@ -88,8 +93,10 @@ struct s3c24xx_i2c {
 static inline int s3c24xx_i2c_is2440(struct s3c24xx_i2c *i2c)
 {
        struct platform_device *pdev = to_platform_device(i2c->dev);
+       enum s3c24xx_i2c_type type;
 
-       return !strcmp(pdev->name, "s3c2440-i2c");
+       type = platform_get_device_id(pdev)->driver_data;
+       return type == TYPE_S3C2440;
 }
 
 /* s3c24xx_i2c_master_complete
@@ -969,52 +976,41 @@ static int s3c24xx_i2c_resume(struct platform_device *dev)
 
 /* device driver for platform bus bits */
 
-static struct platform_driver s3c2410_i2c_driver = {
-       .probe          = s3c24xx_i2c_probe,
-       .remove         = s3c24xx_i2c_remove,
-       .suspend_late   = s3c24xx_i2c_suspend_late,
-       .resume         = s3c24xx_i2c_resume,
-       .driver         = {
-               .owner  = THIS_MODULE,
-               .name   = "s3c2410-i2c",
-       },
+static struct platform_device_id s3c24xx_driver_ids[] = {
+       {
+               .name           = "s3c2410-i2c",
+               .driver_data    = TYPE_S3C2410,
+       }, {
+               .name           = "s3c2440-i2c",
+               .driver_data    = TYPE_S3C2440,
+       }, { },
 };
+MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);
 
-static struct platform_driver s3c2440_i2c_driver = {
+static struct platform_driver s3c24xx_i2c_driver = {
        .probe          = s3c24xx_i2c_probe,
        .remove         = s3c24xx_i2c_remove,
        .suspend_late   = s3c24xx_i2c_suspend_late,
        .resume         = s3c24xx_i2c_resume,
+       .id_table       = s3c24xx_driver_ids,
        .driver         = {
                .owner  = THIS_MODULE,
-               .name   = "s3c2440-i2c",
+               .name   = "s3c-i2c",
        },
 };
 
 static int __init i2c_adap_s3c_init(void)
 {
-       int ret;
-
-       ret = platform_driver_register(&s3c2410_i2c_driver);
-       if (ret == 0) {
-               ret = platform_driver_register(&s3c2440_i2c_driver);
-               if (ret)
-                       platform_driver_unregister(&s3c2410_i2c_driver);
-       }
-
-       return ret;
+       return platform_driver_register(&s3c24xx_i2c_driver);
 }
 subsys_initcall(i2c_adap_s3c_init);
 
 static void __exit i2c_adap_s3c_exit(void)
 {
-       platform_driver_unregister(&s3c2410_i2c_driver);
-       platform_driver_unregister(&s3c2440_i2c_driver);
+       platform_driver_unregister(&s3c24xx_i2c_driver);
 }
 module_exit(i2c_adap_s3c_exit);
 
 MODULE_DESCRIPTION("S3C24XX I2C Bus driver");
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:s3c2410-i2c");
-MODULE_ALIAS("platform:s3c2440-i2c");
index cf06494bb74453d61f7552108d0fbc6d23e7d275..9a5d0aaac9d0e1a7d1e134edf3f1a98309a9f827 100644 (file)
@@ -46,7 +46,7 @@ menuconfig IDE
          SMART parameters from disk drives.
 
          To compile this driver as a module, choose M here: the
-         module will be called ide-core.ko.
+         module will be called ide-core.
 
          For further information, please read <file:Documentation/ide/ide.txt>.
 
index 403d0e4265db1ef9d9163229fae6568a66d032ac..fc0949a8cfdeadb457282dddff2a49d104932404 100644 (file)
@@ -216,6 +216,7 @@ static const struct ide_port_info at91_ide_port_info __initdata = {
        .host_flags     = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA | IDE_HFLAG_SINGLE |
                          IDE_HFLAG_NO_IO_32BIT | IDE_HFLAG_UNMASK_IRQS,
        .pio_mask       = ATA_PIO6,
+       .chipset        = ide_generic,
 };
 
 /*
@@ -246,8 +247,7 @@ irqreturn_t at91_irq_handler(int irq, void *dev_id)
 static int __init at91_ide_probe(struct platform_device *pdev)
 {
        int ret;
-       hw_regs_t hw;
-       hw_regs_t *hws[] = { &hw, NULL, NULL, NULL };
+       struct ide_hw hw, *hws[] = { &hw };
        struct ide_host *host;
        struct resource *res;
        unsigned long tf_base = 0, ctl_base = 0;
@@ -304,10 +304,9 @@ static int __init at91_ide_probe(struct platform_device *pdev)
                ide_std_init_ports(&hw, tf_base, ctl_base + 6);
 
        hw.irq = board->irq_pin;
-       hw.chipset = ide_generic;
        hw.dev = &pdev->dev;
 
-       host = ide_host_alloc(&at91_ide_port_info, hws);
+       host = ide_host_alloc(&at91_ide_port_info, hws, 1);
        if (!host) {
                perr("failed to allocate ide host\n");
                return -ENOMEM;
index 46013644c965c1638faf8f519cd1578a177d114d..58121bd6c1152c62199cc3417713a8c7416c80d6 100644 (file)
@@ -449,7 +449,7 @@ static int auide_ddma_init(ide_hwif_t *hwif, const struct ide_port_info *d)
 }
 #endif
 
-static void auide_setup_ports(hw_regs_t *hw, _auide_hwif *ahwif)
+static void auide_setup_ports(struct ide_hw *hw, _auide_hwif *ahwif)
 {
        int i;
        unsigned long *ata_regs = hw->io_ports_array;
@@ -499,6 +499,7 @@ static const struct ide_port_info au1xxx_port_info = {
 #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
        .mwdma_mask             = ATA_MWDMA2,
 #endif
+       .chipset                = ide_au1xxx,
 };
 
 static int au_ide_probe(struct platform_device *dev)
@@ -507,7 +508,7 @@ static int au_ide_probe(struct platform_device *dev)
        struct resource *res;
        struct ide_host *host;
        int ret = 0;
-       hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+       struct ide_hw hw, *hws[] = { &hw };
 
 #if defined(CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA)
        char *mode = "MWDMA2";
@@ -548,9 +549,8 @@ static int au_ide_probe(struct platform_device *dev)
        auide_setup_ports(&hw, ahwif);
        hw.irq = ahwif->irq;
        hw.dev = &dev->dev;
-       hw.chipset = ide_au1xxx;
 
-       ret = ide_host_add(&au1xxx_port_info, hws, &host);
+       ret = ide_host_add(&au1xxx_port_info, hws, 1, &host);
        if (ret)
                goto out;
 
index d028f8864bc14f7324f24c25abc02c4258f98bb7..e3c6a59133051e65f88e7678d6ed16a058b86858 100644 (file)
@@ -121,7 +121,7 @@ static int xsurf_ack_intr(ide_hwif_t *hwif)
     return 1;
 }
 
-static void __init buddha_setup_ports(hw_regs_t *hw, unsigned long base,
+static void __init buddha_setup_ports(struct ide_hw *hw, unsigned long base,
                                      unsigned long ctl, unsigned long irq_port,
                                      ide_ack_intr_t *ack_intr)
 {
@@ -139,13 +139,12 @@ static void __init buddha_setup_ports(hw_regs_t *hw, unsigned long base,
 
        hw->irq = IRQ_AMIGA_PORTS;
        hw->ack_intr = ack_intr;
-
-       hw->chipset = ide_generic;
 }
 
 static const struct ide_port_info buddha_port_info = {
        .host_flags             = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
        .irq_flags              = IRQF_SHARED,
+       .chipset                = ide_generic,
 };
 
     /*
@@ -161,7 +160,7 @@ static int __init buddha_init(void)
 
        while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
                unsigned long board;
-               hw_regs_t hw[MAX_NUM_HWIFS], *hws[] = { NULL, NULL, NULL, NULL };
+               struct ide_hw hw[MAX_NUM_HWIFS], *hws[MAX_NUM_HWIFS];
 
                if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) {
                        buddha_num_hwifs = BUDDHA_NUM_HWIFS;
@@ -225,7 +224,7 @@ fail_base2:
                        hws[i] = &hw[i];
                }
 
-               ide_host_add(&buddha_port_info, hws, NULL);
+               ide_host_add(&buddha_port_info, hws, i, NULL);
        }
 
        return 0;
index 8890276fef7fbfaa3d163c9c9856421e025d11ee..1683ed5c7329c0466375d4337d679bb2b18206f2 100644 (file)
@@ -708,7 +708,7 @@ static int __init cmd640x_init(void)
        int second_port_cmd640 = 0, rc;
        const char *bus_type, *port2;
        u8 b, cfr;
-       hw_regs_t hw[2], *hws[] = { NULL, NULL, NULL, NULL };
+       struct ide_hw hw[2], *hws[2];
 
        if (cmd640_vlb && probe_for_cmd640_vlb()) {
                bus_type = "VLB";
@@ -762,11 +762,9 @@ static int __init cmd640x_init(void)
 
        ide_std_init_ports(&hw[0], 0x1f0, 0x3f6);
        hw[0].irq = 14;
-       hw[0].chipset = ide_cmd640;
 
        ide_std_init_ports(&hw[1], 0x170, 0x376);
        hw[1].irq = 15;
-       hw[1].chipset = ide_cmd640;
 
        printk(KERN_INFO "cmd640: buggy cmd640%c interface on %s, config=0x%02x"
                         "\n", 'a' + cmd640_chip_version - 1, bus_type, cfr);
@@ -824,7 +822,8 @@ static int __init cmd640x_init(void)
        cmd640_dump_regs();
 #endif
 
-       return ide_host_add(&cmd640_port_info, hws, NULL);
+       return ide_host_add(&cmd640_port_info, hws, second_port_cmd640 ? 2 : 1,
+                           NULL);
 }
 
 module_param_named(probe_vlb, cmd640_vlb, bool, 0);
index 87987a7d36c9c3c6d0cf391c92cd12a9c5426ae0..bd066bb9d61105262c342329fce891f38b015393 100644 (file)
@@ -110,7 +110,7 @@ static const struct ide_port_info cyrix_chipset __devinitdata = {
 static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        const struct ide_port_info *d = &cyrix_chipset;
-       hw_regs_t hw[4], *hws[] = { NULL, NULL, NULL, NULL };
+       struct ide_hw hw[2], *hws[] = { NULL, NULL };
 
        ide_setup_pci_noise(dev, d);
 
@@ -136,7 +136,7 @@ static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_devic
        ide_pci_setup_ports(dev, d, &hw[0], &hws[0]);
        hw[0].irq = 14;
 
-       return ide_host_add(d, hws, NULL);
+       return ide_host_add(d, hws, 2, NULL);
 }
 
 static const struct pci_device_id cs5520_pci_tbl[] = {
index f153b95619bb372e958f7c51c8ca1dcd1ccf043a..1e10eba62ceb7ba97568da89b24162e2b09da2d0 100644 (file)
@@ -68,6 +68,7 @@ static const struct ide_port_info delkin_cb_port_info = {
                                  IDE_HFLAG_NO_DMA,
        .irq_flags              = IRQF_SHARED,
        .init_chipset           = delkin_cb_init_chipset,
+       .chipset                = ide_pci,
 };
 
 static int __devinit
@@ -76,7 +77,7 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
        struct ide_host *host;
        unsigned long base;
        int rc;
-       hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+       struct ide_hw hw, *hws[] = { &hw };
 
        rc = pci_enable_device(dev);
        if (rc) {
@@ -97,9 +98,8 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
        ide_std_init_ports(&hw, base + 0x10, base + 0x1e);
        hw.irq = dev->irq;
        hw.dev = &dev->dev;
-       hw.chipset = ide_pci;           /* this enables IRQ sharing */
 
-       rc = ide_host_add(&delkin_cb_port_info, hws, &host);
+       rc = ide_host_add(&delkin_cb_port_info, hws, 1, &host);
        if (rc)
                goto out_disable;
 
index 0e2df6755ec9f3b45d540fe85b2ef999efd058ac..22fa27389c3b694a7341ab8cc3574fd0beb0fff7 100644 (file)
@@ -111,9 +111,10 @@ static const struct ide_port_info falconide_port_info = {
        .host_flags             = IDE_HFLAG_MMIO | IDE_HFLAG_SERIALIZE |
                                  IDE_HFLAG_NO_DMA,
        .irq_flags              = IRQF_SHARED,
+       .chipset                = ide_generic,
 };
 
-static void __init falconide_setup_ports(hw_regs_t *hw)
+static void __init falconide_setup_ports(struct ide_hw *hw)
 {
        int i;
 
@@ -128,8 +129,6 @@ static void __init falconide_setup_ports(hw_regs_t *hw)
 
        hw->irq = IRQ_MFP_IDE;
        hw->ack_intr = NULL;
-
-       hw->chipset = ide_generic;
 }
 
     /*
@@ -139,7 +138,7 @@ static void __init falconide_setup_ports(hw_regs_t *hw)
 static int __init falconide_init(void)
 {
        struct ide_host *host;
-       hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+       struct ide_hw hw, *hws[] = { &hw };
        int rc;
 
        if (!MACH_IS_ATARI || !ATARIHW_PRESENT(IDE))
@@ -154,7 +153,7 @@ static int __init falconide_init(void)
 
        falconide_setup_ports(&hw);
 
-       host = ide_host_alloc(&falconide_port_info, hws);
+       host = ide_host_alloc(&falconide_port_info, hws, 1);
        if (host == NULL) {
                rc = -ENOMEM;
                goto err;
index c7119516c5a7ccaff6029fbacc3e3a7dfe1017ec..4451a6a5dfe0af00a5ba05b7b70a69370b1d277a 100644 (file)
@@ -88,7 +88,7 @@ static int gayle_ack_intr_a1200(ide_hwif_t *hwif)
     return 1;
 }
 
-static void __init gayle_setup_ports(hw_regs_t *hw, unsigned long base,
+static void __init gayle_setup_ports(struct ide_hw *hw, unsigned long base,
                                     unsigned long ctl, unsigned long irq_port,
                                     ide_ack_intr_t *ack_intr)
 {
@@ -106,14 +106,13 @@ static void __init gayle_setup_ports(hw_regs_t *hw, unsigned long base,
 
        hw->irq = IRQ_AMIGA_PORTS;
        hw->ack_intr = ack_intr;
-
-       hw->chipset = ide_generic;
 }
 
 static const struct ide_port_info gayle_port_info = {
        .host_flags             = IDE_HFLAG_MMIO | IDE_HFLAG_SERIALIZE |
                                  IDE_HFLAG_NO_DMA,
        .irq_flags              = IRQF_SHARED,
+       .chipset                = ide_generic,
 };
 
     /*
@@ -126,7 +125,7 @@ static int __init gayle_init(void)
     unsigned long base, ctrlport, irqport;
     ide_ack_intr_t *ack_intr;
     int a4000, i, rc;
-    hw_regs_t hw[GAYLE_NUM_HWIFS], *hws[] = { NULL, NULL, NULL, NULL };
+    struct ide_hw hw[GAYLE_NUM_HWIFS], *hws[GAYLE_NUM_HWIFS];
 
     if (!MACH_IS_AMIGA)
        return -ENODEV;
@@ -171,7 +170,7 @@ found:
        hws[i] = &hw[i];
     }
 
-    rc = ide_host_add(&gayle_port_info, hws, NULL);
+    rc = ide_host_add(&gayle_port_info, hws, i, NULL);
     if (rc)
        release_mem_region(res_start, res_n);
 
index 0feb66c720e1bdb945bc922a6027f213bdcb2259..7ce68ef6b904f0e29539342b3c661cfc296318c5 100644 (file)
 #undef HPT_RESET_STATE_ENGINE
 #undef HPT_DELAY_INTERRUPT
 
-static const char *quirk_drives[] = {
-       "QUANTUM FIREBALLlct08 08",
-       "QUANTUM FIREBALLP KA6.4",
-       "QUANTUM FIREBALLP LM20.4",
-       "QUANTUM FIREBALLP LM20.5",
-       NULL
-};
-
 static const char *bad_ata100_5[] = {
        "IBM-DTLA-307075",
        "IBM-DTLA-307060",
@@ -729,27 +721,13 @@ static void hpt3xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
        hpt3xx_set_mode(drive, XFER_PIO_0 + pio);
 }
 
-static void hpt3xx_quirkproc(ide_drive_t *drive)
-{
-       char *m                 = (char *)&drive->id[ATA_ID_PROD];
-       const  char **list      = quirk_drives;
-
-       while (*list)
-               if (strstr(m, *list++)) {
-                       drive->quirk_list = 1;
-                       return;
-               }
-
-       drive->quirk_list = 0;
-}
-
 static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
 {
        ide_hwif_t *hwif        = drive->hwif;
        struct pci_dev  *dev    = to_pci_dev(hwif->dev);
        struct hpt_info *info   = hpt3xx_get_info(hwif->dev);
 
-       if (drive->quirk_list == 0)
+       if ((drive->dev_flags & IDE_DFLAG_NIEN_QUIRK) == 0)
                return;
 
        if (info->chip_type >= HPT370) {
@@ -1404,7 +1382,6 @@ static int __devinit hpt36x_init(struct pci_dev *dev, struct pci_dev *dev2)
 static const struct ide_port_ops hpt3xx_port_ops = {
        .set_pio_mode           = hpt3xx_set_pio_mode,
        .set_dma_mode           = hpt3xx_set_mode,
-       .quirkproc              = hpt3xx_quirkproc,
        .maskproc               = hpt3xx_maskproc,
        .mdma_filter            = hpt3xx_mdma_filter,
        .udma_filter            = hpt3xx_udma_filter,
index 36da913cc5532051ebbfc4ef260986238f60cbc0..5af3d0ffaf0af972630e9ac09f2cd546969b48be 100644 (file)
@@ -65,8 +65,6 @@ static struct cardinfo icside_cardinfo_v6_2 = {
 };
 
 struct icside_state {
-       unsigned int channel;
-       unsigned int enabled;
        void __iomem *irq_port;
        void __iomem *ioc_base;
        unsigned int sel;
@@ -116,18 +114,11 @@ static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
        struct icside_state *state = ec->irq_data;
        void __iomem *base = state->irq_port;
 
-       state->enabled = 1;
+       writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1);
+       readb(base + ICS_ARCIN_V6_INTROFFSET_2);
 
-       switch (state->channel) {
-       case 0:
-               writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1);
-               readb(base + ICS_ARCIN_V6_INTROFFSET_2);
-               break;
-       case 1:
-               writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2);
-               readb(base + ICS_ARCIN_V6_INTROFFSET_1);
-               break;
-       }
+       writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2);
+       readb(base + ICS_ARCIN_V6_INTROFFSET_1);
 }
 
 /* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
@@ -137,8 +128,6 @@ static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
 {
        struct icside_state *state = ec->irq_data;
 
-       state->enabled = 0;
-
        readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
        readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
 }
@@ -160,44 +149,6 @@ static const expansioncard_ops_t icside_ops_arcin_v6 = {
        .irqpending     = icside_irqpending_arcin_v6,
 };
 
-/*
- * Handle routing of interrupts.  This is called before
- * we write the command to the drive.
- */
-static void icside_maskproc(ide_drive_t *drive, int mask)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct expansion_card *ec = ECARD_DEV(hwif->dev);
-       struct icside_state *state = ecard_get_drvdata(ec);
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       state->channel = hwif->channel;
-
-       if (state->enabled && !mask) {
-               switch (hwif->channel) {
-               case 0:
-                       writeb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
-                       readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
-                       break;
-               case 1:
-                       writeb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
-                       readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
-                       break;
-               }
-       } else {
-               readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
-               readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
-       }
-
-       local_irq_restore(flags);
-}
-
-static const struct ide_port_ops icside_v6_no_dma_port_ops = {
-       .maskproc               = icside_maskproc,
-};
-
 #ifdef CONFIG_BLK_DEV_IDEDMA_ICS
 /*
  * SG-DMA support.
@@ -275,7 +226,6 @@ static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode)
 
 static const struct ide_port_ops icside_v6_port_ops = {
        .set_dma_mode           = icside_set_dma_mode,
-       .maskproc               = icside_maskproc,
 };
 
 static void icside_dma_host_set(ide_drive_t *drive, int on)
@@ -319,11 +269,6 @@ static int icside_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
         */
        BUG_ON(dma_channel_active(ec->dma));
 
-       /*
-        * Ensure that we have the right interrupt routed.
-        */
-       icside_maskproc(drive, 0);
-
        /*
         * Route the DMA signals to the correct interface.
         */
@@ -381,7 +326,7 @@ static int icside_dma_off_init(ide_hwif_t *hwif, const struct ide_port_info *d)
        return -EOPNOTSUPP;
 }
 
-static void icside_setup_ports(hw_regs_t *hw, void __iomem *base,
+static void icside_setup_ports(struct ide_hw *hw, void __iomem *base,
                               struct cardinfo *info, struct expansion_card *ec)
 {
        unsigned long port = (unsigned long)base + info->dataoffset;
@@ -398,11 +343,11 @@ static void icside_setup_ports(hw_regs_t *hw, void __iomem *base,
 
        hw->irq = ec->irq;
        hw->dev = &ec->dev;
-       hw->chipset = ide_acorn;
 }
 
 static const struct ide_port_info icside_v5_port_info = {
        .host_flags             = IDE_HFLAG_NO_DMA,
+       .chipset                = ide_acorn,
 };
 
 static int __devinit
@@ -410,7 +355,7 @@ icside_register_v5(struct icside_state *state, struct expansion_card *ec)
 {
        void __iomem *base;
        struct ide_host *host;
-       hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+       struct ide_hw hw, *hws[] = { &hw };
        int ret;
 
        base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0);
@@ -431,7 +376,7 @@ icside_register_v5(struct icside_state *state, struct expansion_card *ec)
 
        icside_setup_ports(&hw, base, &icside_cardinfo_v5, ec);
 
-       host = ide_host_alloc(&icside_v5_port_info, hws);
+       host = ide_host_alloc(&icside_v5_port_info, hws, 1);
        if (host == NULL)
                return -ENODEV;
 
@@ -452,11 +397,11 @@ err_free:
 
 static const struct ide_port_info icside_v6_port_info __initdata = {
        .init_dma               = icside_dma_off_init,
-       .port_ops               = &icside_v6_no_dma_port_ops,
        .dma_ops                = &icside_v6_dma_ops,
        .host_flags             = IDE_HFLAG_SERIALIZE | IDE_HFLAG_MMIO,
        .mwdma_mask             = ATA_MWDMA2,
        .swdma_mask             = ATA_SWDMA2,
+       .chipset                = ide_acorn,
 };
 
 static int __devinit
@@ -466,7 +411,7 @@ icside_register_v6(struct icside_state *state, struct expansion_card *ec)
        struct ide_host *host;
        unsigned int sel = 0;
        int ret;
-       hw_regs_t hw[2], *hws[] = { &hw[0], &hw[1], NULL, NULL };
+       struct ide_hw hw[2], *hws[] = { &hw[0], &hw[1] };
        struct ide_port_info d = icside_v6_port_info;
 
        ioc_base = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
@@ -506,7 +451,7 @@ icside_register_v6(struct icside_state *state, struct expansion_card *ec)
        icside_setup_ports(&hw[0], easi_base, &icside_cardinfo_v6_1, ec);
        icside_setup_ports(&hw[1], easi_base, &icside_cardinfo_v6_2, ec);
 
-       host = ide_host_alloc(&d, hws);
+       host = ide_host_alloc(&d, hws, 2);
        if (host == NULL)
                return -ENODEV;
 
index 78aca75a2c487ece474e08bcb220c5542caa8b4b..979d342c338ae71b39b03edd7986a7ea37732f97 100644 (file)
@@ -25,12 +25,13 @@ static const struct ide_port_info ide_4drives_port_info = {
        .port_ops               = &ide_4drives_port_ops,
        .host_flags             = IDE_HFLAG_SERIALIZE | IDE_HFLAG_NO_DMA |
                                  IDE_HFLAG_4DRIVES,
+       .chipset                = ide_4drives,
 };
 
 static int __init ide_4drives_init(void)
 {
        unsigned long base = 0x1f0, ctl = 0x3f6;
-       hw_regs_t hw, *hws[] = { &hw, &hw, NULL, NULL };
+       struct ide_hw hw, *hws[] = { &hw, &hw };
 
        if (probe_4drives == 0)
                return -ENODEV;
@@ -52,9 +53,8 @@ static int __init ide_4drives_init(void)
 
        ide_std_init_ports(&hw, base, ctl);
        hw.irq = 14;
-       hw.chipset = ide_4drives;
 
-       return ide_host_add(&ide_4drives_port_info, hws, NULL);
+       return ide_host_add(&ide_4drives_port_info, hws, 2, NULL);
 }
 
 module_init(ide_4drives_init);
index 757e5956b13297f38a204740486f9907c35a0ae7..702ef64a0f12fc6897ab4276a2fefbf3821ac879 100644 (file)
@@ -259,7 +259,7 @@ void ide_retry_pc(ide_drive_t *drive)
        pc->req_xfer = blk_rq_bytes(sense_rq);
 
        if (drive->media == ide_tape)
-               set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags);
+               drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC;
 
        /*
         * Push back the failed request and put request sense on top
@@ -577,7 +577,7 @@ static ide_startstop_t ide_transfer_pc(ide_drive_t *drive)
 
                /*
                 * If necessary schedule the packet transfer to occur 'timeout'
-                * miliseconds later in ide_delayed_transfer_pc() after the
+                * milliseconds later in ide_delayed_transfer_pc() after the
                 * device says it's ready for a packet.
                 */
                if (drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) {
index 9e47f3529d5555685bb829b1e92b7b621c15e624..527908ff298c408c0f86fdf24363ea9c70d6e652 100644 (file)
@@ -155,6 +155,7 @@ static const struct ide_port_info idecs_port_info = {
        .port_ops               = &idecs_port_ops,
        .host_flags             = IDE_HFLAG_NO_DMA,
        .irq_flags              = IRQF_SHARED,
+       .chipset                = ide_pci,
 };
 
 static struct ide_host *idecs_register(unsigned long io, unsigned long ctl,
@@ -163,7 +164,7 @@ static struct ide_host *idecs_register(unsigned long io, unsigned long ctl,
     struct ide_host *host;
     ide_hwif_t *hwif;
     int i, rc;
-    hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+    struct ide_hw hw, *hws[] = { &hw };
 
     if (!request_region(io, 8, DRV_NAME)) {
        printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
@@ -181,10 +182,9 @@ static struct ide_host *idecs_register(unsigned long io, unsigned long ctl,
     memset(&hw, 0, sizeof(hw));
     ide_std_init_ports(&hw, io, ctl);
     hw.irq = irq;
-    hw.chipset = ide_pci;
     hw.dev = &handle->dev;
 
-    rc = ide_host_add(&idecs_port_info, hws, &host);
+    rc = ide_host_add(&idecs_port_info, hws, 1, &host);
     if (rc)
        goto out_release;
 
index c6f7fcfb9d672f47fb585fc035a1ee9f74f9642d..6a1de21697096525d19b850ffbfba2f99a129c88 100644 (file)
@@ -302,14 +302,12 @@ static const struct drive_list_entry hpa_list[] = {
        { NULL,         NULL }
 };
 
-static void idedisk_check_hpa(ide_drive_t *drive)
+static u64 ide_disk_hpa_get_native_capacity(ide_drive_t *drive, int lba48)
 {
-       unsigned long long capacity, set_max;
-       int lba48 = ata_id_lba48_enabled(drive->id);
+       u64 capacity, set_max;
 
        capacity = drive->capacity64;
-
-       set_max = idedisk_read_native_max_address(drive, lba48);
+       set_max  = idedisk_read_native_max_address(drive, lba48);
 
        if (ide_in_drive_list(drive->id, hpa_list)) {
                /*
@@ -320,9 +318,31 @@ static void idedisk_check_hpa(ide_drive_t *drive)
                        set_max--;
        }
 
+       return set_max;
+}
+
+static u64 ide_disk_hpa_set_capacity(ide_drive_t *drive, u64 set_max, int lba48)
+{
+       set_max = idedisk_set_max_address(drive, set_max, lba48);
+       if (set_max)
+               drive->capacity64 = set_max;
+
+       return set_max;
+}
+
+static void idedisk_check_hpa(ide_drive_t *drive)
+{
+       u64 capacity, set_max;
+       int lba48 = ata_id_lba48_enabled(drive->id);
+
+       capacity = drive->capacity64;
+       set_max  = ide_disk_hpa_get_native_capacity(drive, lba48);
+
        if (set_max <= capacity)
                return;
 
+       drive->probed_capacity = set_max;
+
        printk(KERN_INFO "%s: Host Protected Area detected.\n"
                         "\tcurrent capacity is %llu sectors (%llu MB)\n"
                         "\tnative  capacity is %llu sectors (%llu MB)\n",
@@ -330,13 +350,13 @@ static void idedisk_check_hpa(ide_drive_t *drive)
                         capacity, sectors_to_MB(capacity),
                         set_max, sectors_to_MB(set_max));
 
-       set_max = idedisk_set_max_address(drive, set_max, lba48);
+       if ((drive->dev_flags & IDE_DFLAG_NOHPA) == 0)
+               return;
 
-       if (set_max) {
-               drive->capacity64 = set_max;
+       set_max = ide_disk_hpa_set_capacity(drive, set_max, lba48);
+       if (set_max)
                printk(KERN_INFO "%s: Host Protected Area disabled.\n",
                                 drive->name);
-       }
 }
 
 static int ide_disk_get_capacity(ide_drive_t *drive)
@@ -358,6 +378,8 @@ static int ide_disk_get_capacity(ide_drive_t *drive)
                drive->capacity64 = drive->cyl * drive->head * drive->sect;
        }
 
+       drive->probed_capacity = drive->capacity64;
+
        if (lba) {
                drive->dev_flags |= IDE_DFLAG_LBA;
 
@@ -376,7 +398,7 @@ static int ide_disk_get_capacity(ide_drive_t *drive)
                       "%llu sectors (%llu MB)\n",
                       drive->name, (unsigned long long)drive->capacity64,
                       sectors_to_MB(drive->capacity64));
-               drive->capacity64 = 1ULL << 28;
+               drive->probed_capacity = drive->capacity64 = 1ULL << 28;
        }
 
        if ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) &&
@@ -392,6 +414,34 @@ static int ide_disk_get_capacity(ide_drive_t *drive)
        return 0;
 }
 
+static u64 ide_disk_set_capacity(ide_drive_t *drive, u64 capacity)
+{
+       u64 set = min(capacity, drive->probed_capacity);
+       u16 *id = drive->id;
+       int lba48 = ata_id_lba48_enabled(id);
+
+       if ((drive->dev_flags & IDE_DFLAG_LBA) == 0 ||
+           ata_id_hpa_enabled(id) == 0)
+               goto out;
+
+       /*
+        * according to the spec the SET MAX ADDRESS command shall be
+        * immediately preceded by a READ NATIVE MAX ADDRESS command
+        */
+       capacity = ide_disk_hpa_get_native_capacity(drive, lba48);
+       if (capacity == 0)
+               goto out;
+
+       set = ide_disk_hpa_set_capacity(drive, set, lba48);
+       if (set) {
+               /* needed for ->resume to disable HPA */
+               drive->dev_flags |= IDE_DFLAG_NOHPA;
+               return set;
+       }
+out:
+       return drive->capacity64;
+}
+
 static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
 {
        ide_drive_t *drive = q->queuedata;
@@ -428,14 +478,14 @@ static int set_multcount(ide_drive_t *drive, int arg)
        if (arg < 0 || arg > (drive->id[ATA_ID_MAX_MULTSECT] & 0xff))
                return -EINVAL;
 
-       if (drive->special.b.set_multmode)
+       if (drive->special_flags & IDE_SFLAG_SET_MULTMODE)
                return -EBUSY;
 
        rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
        rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
 
        drive->mult_req = arg;
-       drive->special.b.set_multmode = 1;
+       drive->special_flags |= IDE_SFLAG_SET_MULTMODE;
        error = blk_execute_rq(drive->queue, NULL, rq, 0);
        blk_put_request(rq);
 
@@ -740,6 +790,7 @@ static int ide_disk_set_doorlock(ide_drive_t *drive, struct gendisk *disk,
 
 const struct ide_disk_ops ide_ata_disk_ops = {
        .check          = ide_disk_check,
+       .set_capacity   = ide_disk_set_capacity,
        .get_capacity   = ide_disk_get_capacity,
        .setup          = ide_disk_setup,
        .flush          = ide_disk_flush,
index 001f68f0bb285c62d0b42b6dbb1508d92182923a..219e6fb78dc6414304ff8b707c59554f9c82db75 100644 (file)
@@ -347,7 +347,6 @@ u8 ide_find_dma_mode(ide_drive_t *drive, u8 req_mode)
 
        return mode;
 }
-EXPORT_SYMBOL_GPL(ide_find_dma_mode);
 
 static int ide_tune_dma(ide_drive_t *drive)
 {
index 5d5fb961b5ce8ee83e9e6e5cfc216ca3d0314d65..2b91419796136e24b4a98a27dd85aab0c6caccc0 100644 (file)
@@ -52,7 +52,7 @@ static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq,
        }
 
        if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
-               drive->special.b.recalibrate = 1;
+               drive->special_flags |= IDE_SFLAG_RECALIBRATE;
 
        ++rq->errors;
 
@@ -268,9 +268,8 @@ static void ide_disk_pre_reset(ide_drive_t *drive)
 {
        int legacy = (drive->id[ATA_ID_CFS_ENABLE_2] & 0x0400) ? 0 : 1;
 
-       drive->special.all = 0;
-       drive->special.b.set_geometry = legacy;
-       drive->special.b.recalibrate  = legacy;
+       drive->special_flags =
+               legacy ? (IDE_SFLAG_SET_GEOMETRY | IDE_SFLAG_RECALIBRATE) : 0;
 
        drive->mult_count = 0;
        drive->dev_flags &= ~IDE_DFLAG_PARKED;
@@ -280,7 +279,7 @@ static void ide_disk_pre_reset(ide_drive_t *drive)
                drive->mult_req = 0;
 
        if (drive->mult_req != drive->mult_count)
-               drive->special.b.set_multmode = 1;
+               drive->special_flags |= IDE_SFLAG_SET_MULTMODE;
 }
 
 static void pre_reset(ide_drive_t *drive)
@@ -408,8 +407,9 @@ static ide_startstop_t do_reset1(ide_drive_t *drive, int do_not_try_atapi)
        /* more than enough time */
        udelay(10);
        /* clear SRST, leave nIEN (unless device is on the quirk list) */
-       tp_ops->write_devctl(hwif, (drive->quirk_list == 2 ? 0 : ATA_NIEN) |
-                            ATA_DEVCTL_OBS);
+       tp_ops->write_devctl(hwif,
+               ((drive->dev_flags & IDE_DFLAG_NIEN_QUIRK) ? 0 : ATA_NIEN) |
+                ATA_DEVCTL_OBS);
        /* more than enough time */
        udelay(10);
        hwif->poll_timeout = jiffies + WAIT_WORSTCASE;
index 4b6b71e2cdf5b6cc3f1fe1288e0f99408d5a3742..214119026b3f4e55eec0c0eb1f60898ecc62e047 100644 (file)
@@ -287,6 +287,19 @@ static int ide_gd_media_changed(struct gendisk *disk)
        return ret;
 }
 
+static unsigned long long ide_gd_set_capacity(struct gendisk *disk,
+                                             unsigned long long capacity)
+{
+       struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
+       ide_drive_t *drive = idkp->drive;
+       const struct ide_disk_ops *disk_ops = drive->disk_ops;
+
+       if (disk_ops->set_capacity)
+               return disk_ops->set_capacity(drive, capacity);
+
+       return drive->capacity64;
+}
+
 static int ide_gd_revalidate_disk(struct gendisk *disk)
 {
        struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
@@ -315,6 +328,7 @@ static struct block_device_operations ide_gd_ops = {
        .locked_ioctl           = ide_gd_ioctl,
        .getgeo                 = ide_gd_getgeo,
        .media_changed          = ide_gd_media_changed,
+       .set_capacity           = ide_gd_set_capacity,
        .revalidate_disk        = ide_gd_revalidate_disk
 };
 
index 7812ca0be13beb1c5af1ba98ea8b29b4bd2cbf4b..54d7c4685d23aa5e62ce606e7b994a57bb54b08a 100644 (file)
@@ -29,6 +29,7 @@ MODULE_PARM_DESC(probe_mask, "probe mask for legacy ISA IDE ports");
 
 static const struct ide_port_info ide_generic_port_info = {
        .host_flags             = IDE_HFLAG_NO_DMA,
+       .chipset                = ide_generic,
 };
 
 #ifdef CONFIG_ARM
@@ -85,7 +86,7 @@ static void ide_generic_check_pci_legacy_iobases(int *primary, int *secondary)
 
 static int __init ide_generic_init(void)
 {
-       hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+       struct ide_hw hw, *hws[] = { &hw };
        unsigned long io_addr;
        int i, rc = 0, primary = 0, secondary = 0;
 
@@ -132,9 +133,7 @@ static int __init ide_generic_init(void)
 #else
                        hw.irq = legacy_irqs[i];
 #endif
-                       hw.chipset = ide_generic;
-
-                       rc = ide_host_add(&ide_generic_port_info, hws, NULL);
+                       rc = ide_host_add(&ide_generic_port_info, hws, 1, NULL);
                        if (rc) {
                                release_region(io_addr + 0x206, 1);
                                release_region(io_addr, 8);
index c06ebdc4a130b9c609d2074748fdcf0e0077b651..520f42c5445a029313a1a5f31ab29a4d263ff106 100644 (file)
@@ -64,26 +64,26 @@ static const struct ide_tp_ops h8300_tp_ops = {
 
 #define H8300_IDE_GAP (2)
 
-static inline void hw_setup(hw_regs_t *hw)
+static inline void hw_setup(struct ide_hw *hw)
 {
        int i;
 
-       memset(hw, 0, sizeof(hw_regs_t));
+       memset(hw, 0, sizeof(*hw));
        for (i = 0; i <= 7; i++)
                hw->io_ports_array[i] = CONFIG_H8300_IDE_BASE + H8300_IDE_GAP*i;
        hw->io_ports.ctl_addr = CONFIG_H8300_IDE_ALT;
        hw->irq = EXT_IRQ0 + CONFIG_H8300_IDE_IRQ;
-       hw->chipset = ide_generic;
 }
 
 static const struct ide_port_info h8300_port_info = {
        .tp_ops                 = &h8300_tp_ops,
        .host_flags             = IDE_HFLAG_NO_IO_32BIT | IDE_HFLAG_NO_DMA,
+       .chipset                = ide_generic,
 };
 
 static int __init h8300_ide_init(void)
 {
-       hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+       struct ide_hw hw, *hws[] = { &hw };
 
        printk(KERN_INFO DRV_NAME ": H8/300 generic IDE interface\n");
 
@@ -96,7 +96,7 @@ static int __init h8300_ide_init(void)
 
        hw_setup(&hw);
 
-       return ide_host_add(&h8300_port_info, hws, NULL);
+       return ide_host_add(&h8300_port_info, hws, 1, NULL);
 
 out_busy:
        printk(KERN_ERR "ide-h8300: IDE I/F resource already used.\n");
index bba4297f2f03fcadf80f8bb3f3a05e780e6f3551..272cc38f6dbe55192283db6ea2902e3d576b6a26 100644 (file)
@@ -184,29 +184,42 @@ static void ide_tf_set_setmult_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
        tf->command = ATA_CMD_SET_MULTI;
 }
 
-static ide_startstop_t ide_disk_special(ide_drive_t *drive)
+/**
+ *     do_special              -       issue some special commands
+ *     @drive: drive the command is for
+ *
+ *     do_special() is used to issue ATA_CMD_INIT_DEV_PARAMS,
+ *     ATA_CMD_RESTORE and ATA_CMD_SET_MULTI commands to a drive.
+ */
+
+static ide_startstop_t do_special(ide_drive_t *drive)
 {
-       special_t *s = &drive->special;
        struct ide_cmd cmd;
 
+#ifdef DEBUG
+       printk(KERN_DEBUG "%s: %s: 0x%02x\n", drive->name, __func__,
+               drive->special_flags);
+#endif
+       if (drive->media != ide_disk) {
+               drive->special_flags = 0;
+               drive->mult_req = 0;
+               return ide_stopped;
+       }
+
        memset(&cmd, 0, sizeof(cmd));
        cmd.protocol = ATA_PROT_NODATA;
 
-       if (s->b.set_geometry) {
-               s->b.set_geometry = 0;
+       if (drive->special_flags & IDE_SFLAG_SET_GEOMETRY) {
+               drive->special_flags &= ~IDE_SFLAG_SET_GEOMETRY;
                ide_tf_set_specify_cmd(drive, &cmd.tf);
-       } else if (s->b.recalibrate) {
-               s->b.recalibrate = 0;
+       } else if (drive->special_flags & IDE_SFLAG_RECALIBRATE) {
+               drive->special_flags &= ~IDE_SFLAG_RECALIBRATE;
                ide_tf_set_restore_cmd(drive, &cmd.tf);
-       } else if (s->b.set_multmode) {
-               s->b.set_multmode = 0;
+       } else if (drive->special_flags & IDE_SFLAG_SET_MULTMODE) {
+               drive->special_flags &= ~IDE_SFLAG_SET_MULTMODE;
                ide_tf_set_setmult_cmd(drive, &cmd.tf);
-       } else if (s->all) {
-               int special = s->all;
-               s->all = 0;
-               printk(KERN_ERR "%s: bad special flag: 0x%02x\n", drive->name, special);
-               return ide_stopped;
-       }
+       } else
+               BUG();
 
        cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
        cmd.valid.in.tf  = IDE_VALID_IN_TF  | IDE_VALID_DEVICE;
@@ -217,31 +230,6 @@ static ide_startstop_t ide_disk_special(ide_drive_t *drive)
        return ide_started;
 }
 
-/**
- *     do_special              -       issue some special commands
- *     @drive: drive the command is for
- *
- *     do_special() is used to issue ATA_CMD_INIT_DEV_PARAMS,
- *     ATA_CMD_RESTORE and ATA_CMD_SET_MULTI commands to a drive.
- *
- *     It used to do much more, but has been scaled back.
- */
-
-static ide_startstop_t do_special (ide_drive_t *drive)
-{
-       special_t *s = &drive->special;
-
-#ifdef DEBUG
-       printk("%s: do_special: 0x%02x\n", drive->name, s->all);
-#endif
-       if (drive->media == ide_disk)
-               return ide_disk_special(drive);
-
-       s->all = 0;
-       drive->mult_req = 0;
-       return ide_stopped;
-}
-
 void ide_map_sg(ide_drive_t *drive, struct ide_cmd *cmd)
 {
        ide_hwif_t *hwif = drive->hwif;
@@ -351,7 +339,8 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
                printk(KERN_ERR "%s: drive not ready for command\n", drive->name);
                return startstop;
        }
-       if (!drive->special.all) {
+
+       if (drive->special_flags == 0) {
                struct ide_driver *drv;
 
                /*
@@ -499,11 +488,15 @@ repeat:
 
                if ((hwif->host->host_flags & IDE_HFLAG_SERIALIZE) &&
                    hwif != prev_port) {
+                       ide_drive_t *cur_dev =
+                               prev_port ? prev_port->cur_dev : NULL;
+
                        /*
                         * set nIEN for previous port, drives in the
-                        * quirk_list may not like intr setups/cleanups
+                        * quirk list may not like intr setups/cleanups
                         */
-                       if (prev_port && prev_port->cur_dev->quirk_list == 0)
+                       if (cur_dev &&
+                           (cur_dev->dev_flags & IDE_DFLAG_NIEN_QUIRK) == 0)
                                prev_port->tp_ops->write_devctl(prev_port,
                                                                ATA_NIEN |
                                                                ATA_DEVCTL_OBS);
index 06fe002116ecc733a1015216d7676e4b24439070..fa047150a1c691f47f9c74a8404810d451332619 100644 (file)
@@ -282,6 +282,29 @@ no_80w:
        return 0;
 }
 
+static const char *nien_quirk_list[] = {
+       "QUANTUM FIREBALLlct08 08",
+       "QUANTUM FIREBALLP KA6.4",
+       "QUANTUM FIREBALLP KA9.1",
+       "QUANTUM FIREBALLP KX13.6",
+       "QUANTUM FIREBALLP KX20.5",
+       "QUANTUM FIREBALLP KX27.3",
+       "QUANTUM FIREBALLP LM20.4",
+       "QUANTUM FIREBALLP LM20.5",
+       NULL
+};
+
+void ide_check_nien_quirk_list(ide_drive_t *drive)
+{
+       const char **list, *m = (char *)&drive->id[ATA_ID_PROD];
+
+       for (list = nien_quirk_list; *list != NULL; list++)
+               if (strstr(m, *list) != NULL) {
+                       drive->dev_flags |= IDE_DFLAG_NIEN_QUIRK;
+                       return;
+               }
+}
+
 int ide_driveid_update(ide_drive_t *drive)
 {
        u16 *id;
@@ -311,7 +334,6 @@ int ide_driveid_update(ide_drive_t *drive)
 
        return 1;
 out_err:
-       SELECT_MASK(drive, 0);
        if (rc == 2)
                printk(KERN_ERR "%s: %s: bad status\n", drive->name, __func__);
        kfree(id);
@@ -365,7 +387,7 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
 
        tp_ops->exec_command(hwif, ATA_CMD_SET_FEATURES);
 
-       if (drive->quirk_list == 2)
+       if (drive->dev_flags & IDE_DFLAG_NIEN_QUIRK)
                tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
 
        error = __ide_wait_stat(drive, drive->ready_stat,
index 8c5dcbf22547a23d0eca965fd573340ca50e06d8..b9654a7bb7becb2d7f2b07aa126b075e4e611b89 100644 (file)
@@ -1,7 +1,7 @@
 #include <linux/kernel.h>
 #include <linux/ide.h>
 
-static void ide_legacy_init_one(hw_regs_t **hws, hw_regs_t *hw,
+static void ide_legacy_init_one(struct ide_hw **hws, struct ide_hw *hw,
                                u8 port_no, const struct ide_port_info *d,
                                unsigned long config)
 {
@@ -33,7 +33,6 @@ static void ide_legacy_init_one(hw_regs_t **hws, hw_regs_t *hw,
 
        ide_std_init_ports(hw, base, ctl);
        hw->irq = irq;
-       hw->chipset = d->chipset;
        hw->config = config;
 
        hws[port_no] = hw;
@@ -41,7 +40,7 @@ static void ide_legacy_init_one(hw_regs_t **hws, hw_regs_t *hw,
 
 int ide_legacy_device_add(const struct ide_port_info *d, unsigned long config)
 {
-       hw_regs_t hw[2], *hws[] = { NULL, NULL, NULL, NULL };
+       struct ide_hw hw[2], *hws[] = { NULL, NULL };
 
        memset(&hw, 0, sizeof(hw));
 
@@ -53,6 +52,6 @@ int ide_legacy_device_add(const struct ide_port_info *d, unsigned long config)
            (d->host_flags & IDE_HFLAG_SINGLE))
                return -ENOENT;
 
-       return ide_host_add(d, hws, NULL);
+       return ide_host_add(d, hws, 2, NULL);
 }
 EXPORT_SYMBOL_GPL(ide_legacy_device_add);
index 6e80b774e88a8fb538c08d98298775eb3514eee0..017b1df3b8054c476b8e7e3dbc3b4112d2d739fc 100644 (file)
@@ -29,6 +29,7 @@ static struct pnp_device_id idepnp_devices[] = {
 
 static const struct ide_port_info ide_pnp_port_info = {
        .host_flags             = IDE_HFLAG_NO_DMA,
+       .chipset                = ide_generic,
 };
 
 static int idepnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
@@ -36,7 +37,7 @@ static int idepnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
        struct ide_host *host;
        unsigned long base, ctl;
        int rc;
-       hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+       struct ide_hw hw, *hws[] = { &hw };
 
        printk(KERN_INFO DRV_NAME ": generic PnP IDE interface\n");
 
@@ -62,9 +63,8 @@ static int idepnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
        memset(&hw, 0, sizeof(hw));
        ide_std_init_ports(&hw, base, ctl);
        hw.irq = pnp_irq(dev, 0);
-       hw.chipset = ide_generic;
 
-       rc = ide_host_add(&ide_pnp_port_info, hws, &host);
+       rc = ide_host_add(&ide_pnp_port_info, hws, 1, &host);
        if (rc)
                goto out;
 
index c895ed52b2e870909cd103d1e82c7318288a16f6..f371b0de314f75374a6728d206dabb3a24ef676e 100644 (file)
@@ -97,7 +97,7 @@ static void ide_disk_init_mult_count(ide_drive_t *drive)
                drive->mult_req = id[ATA_ID_MULTSECT] & 0xff;
 
                if (drive->mult_req)
-                       drive->special.b.set_multmode = 1;
+                       drive->special_flags |= IDE_SFLAG_SET_MULTMODE;
        }
 }
 
@@ -465,23 +465,8 @@ static u8 probe_for_drive(ide_drive_t *drive)
        int rc;
        u8 cmd;
 
-       /*
-        *      In order to keep things simple we have an id
-        *      block for all drives at all times. If the device
-        *      is pre ATA or refuses ATA/ATAPI identify we
-        *      will add faked data to this.
-        *
-        *      Also note that 0 everywhere means "can't do X"
-        */
        drive->dev_flags &= ~IDE_DFLAG_ID_READ;
 
-       drive->id = kzalloc(SECTOR_SIZE, GFP_KERNEL);
-       if (drive->id == NULL) {
-               printk(KERN_ERR "ide: out of memory for id data.\n");
-               return 0;
-       }
-
        m = (char *)&drive->id[ATA_ID_PROD];
        strcpy(m, "UNKNOWN");
 
@@ -497,7 +482,7 @@ static u8 probe_for_drive(ide_drive_t *drive)
                }
 
                if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
-                       goto out_free;
+                       return 0;
 
                /* identification failed? */
                if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) {
@@ -521,7 +506,7 @@ static u8 probe_for_drive(ide_drive_t *drive)
        }
 
        if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
-               goto out_free;
+               return 0;
 
        /* The drive wasn't being helpful. Add generic info only */
        if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) {
@@ -535,9 +520,6 @@ static u8 probe_for_drive(ide_drive_t *drive)
        }
 
        return 1;
-out_free:
-       kfree(drive->id);
-       return 0;
 }
 
 static void hwif_release_dev(struct device *dev)
@@ -702,8 +684,14 @@ static int ide_probe_port(ide_hwif_t *hwif)
        if (irqd)
                disable_irq(hwif->irq);
 
-       if (ide_port_wait_ready(hwif) == -EBUSY)
-               printk(KERN_DEBUG "%s: Wait for ready failed before probe !\n", hwif->name);
+       rc = ide_port_wait_ready(hwif);
+       if (rc == -ENODEV) {
+               printk(KERN_INFO "%s: no devices on the port\n", hwif->name);
+               goto out;
+       } else if (rc == -EBUSY)
+               printk(KERN_ERR "%s: not ready before the probe\n", hwif->name);
+       else
+               rc = -ENODEV;
 
        /*
         * Second drive should only exist if first drive was found,
@@ -714,7 +702,7 @@ static int ide_probe_port(ide_hwif_t *hwif)
                if (drive->dev_flags & IDE_DFLAG_PRESENT)
                        rc = 0;
        }
-
+out:
        /*
         * Use cached IRQ number. It might be (and is...) changed by probe
         * code above
@@ -732,6 +720,8 @@ static void ide_port_tune_devices(ide_hwif_t *hwif)
        int i;
 
        ide_port_for_each_present_dev(i, drive, hwif) {
+               ide_check_nien_quirk_list(drive);
+
                if (port_ops && port_ops->quirkproc)
                        port_ops->quirkproc(drive);
        }
@@ -817,8 +807,6 @@ static int ide_port_setup_devices(ide_hwif_t *hwif)
                if (ide_init_queue(drive)) {
                        printk(KERN_ERR "ide: failed to init %s\n",
                                        drive->name);
-                       kfree(drive->id);
-                       drive->id = NULL;
                        drive->dev_flags &= ~IDE_DFLAG_PRESENT;
                        continue;
                }
@@ -947,9 +935,6 @@ static void drive_release_dev (struct device *dev)
        blk_cleanup_queue(drive->queue);
        drive->queue = NULL;
 
-       kfree(drive->id);
-       drive->id = NULL;
-
        drive->dev_flags &= ~IDE_DFLAG_PRESENT;
 
        complete(&drive->gendev_rel_comp);
@@ -1035,6 +1020,15 @@ static void ide_port_init_devices(ide_hwif_t *hwif)
                if (port_ops && port_ops->init_dev)
                        port_ops->init_dev(drive);
        }
+
+       ide_port_for_each_dev(i, drive, hwif) {
+               /*
+                * default to PIO Mode 0 before we figure out
+                * the most suited mode for the attached device
+                */
+               if (port_ops && port_ops->set_pio_mode)
+                       port_ops->set_pio_mode(drive, 0);
+       }
 }
 
 static void ide_init_port(ide_hwif_t *hwif, unsigned int port,
@@ -1042,8 +1036,7 @@ static void ide_init_port(ide_hwif_t *hwif, unsigned int port,
 {
        hwif->channel = port;
 
-       if (d->chipset)
-               hwif->chipset = d->chipset;
+       hwif->chipset = d->chipset ? d->chipset : ide_pci;
 
        if (d->init_iops)
                d->init_iops(hwif);
@@ -1124,16 +1117,19 @@ static void ide_port_init_devices_data(ide_hwif_t *hwif)
 
        ide_port_for_each_dev(i, drive, hwif) {
                u8 j = (hwif->index * MAX_DRIVES) + i;
+               u16 *saved_id = drive->id;
 
                memset(drive, 0, sizeof(*drive));
+               memset(saved_id, 0, SECTOR_SIZE);
+               drive->id = saved_id;
 
                drive->media                    = ide_disk;
                drive->select                   = (i << 4) | ATA_DEVICE_OBS;
                drive->hwif                     = hwif;
                drive->ready_stat               = ATA_DRDY;
                drive->bad_wstat                = BAD_W_STAT;
-               drive->special.b.recalibrate    = 1;
-               drive->special.b.set_geometry   = 1;
+               drive->special_flags            = IDE_SFLAG_RECALIBRATE |
+                                                 IDE_SFLAG_SET_GEOMETRY;
                drive->name[0]                  = 'h';
                drive->name[1]                  = 'd';
                drive->name[2]                  = 'a' + j;
@@ -1168,11 +1164,10 @@ static void ide_init_port_data(ide_hwif_t *hwif, unsigned int index)
        ide_port_init_devices_data(hwif);
 }
 
-static void ide_init_port_hw(ide_hwif_t *hwif, hw_regs_t *hw)
+static void ide_init_port_hw(ide_hwif_t *hwif, struct ide_hw *hw)
 {
        memcpy(&hwif->io_ports, &hw->io_ports, sizeof(hwif->io_ports));
        hwif->irq = hw->irq;
-       hwif->chipset = hw->chipset;
        hwif->dev = hw->dev;
        hwif->gendev.parent = hw->parent ? hw->parent : hw->dev;
        hwif->ack_intr = hw->ack_intr;
@@ -1233,8 +1228,10 @@ static void ide_port_free_devices(ide_hwif_t *hwif)
        ide_drive_t *drive;
        int i;
 
-       ide_port_for_each_dev(i, drive, hwif)
+       ide_port_for_each_dev(i, drive, hwif) {
+               kfree(drive->id);
                kfree(drive);
+       }
 }
 
 static int ide_port_alloc_devices(ide_hwif_t *hwif, int node)
@@ -1248,6 +1245,18 @@ static int ide_port_alloc_devices(ide_hwif_t *hwif, int node)
                if (drive == NULL)
                        goto out_nomem;
 
+               /*
+                * In order to keep things simple we have an id
+                * block for all drives at all times. If the device
+                * is pre ATA or refuses ATA/ATAPI identify we
+                * will add faked data to this.
+                *
+                * Also note that 0 everywhere means "can't do X"
+                */
+               drive->id = kzalloc_node(SECTOR_SIZE, GFP_KERNEL, node);
+               if (drive->id == NULL)
+                       goto out_nomem;
+
                hwif->devices[i] = drive;
        }
        return 0;
@@ -1257,7 +1266,8 @@ out_nomem:
        return -ENOMEM;
 }
 
-struct ide_host *ide_host_alloc(const struct ide_port_info *d, hw_regs_t **hws)
+struct ide_host *ide_host_alloc(const struct ide_port_info *d,
+                               struct ide_hw **hws, unsigned int n_ports)
 {
        struct ide_host *host;
        struct device *dev = hws[0] ? hws[0]->dev : NULL;
@@ -1268,7 +1278,7 @@ struct ide_host *ide_host_alloc(const struct ide_port_info *d, hw_regs_t **hws)
        if (host == NULL)
                return NULL;
 
-       for (i = 0; i < MAX_HOST_PORTS; i++) {
+       for (i = 0; i < n_ports; i++) {
                ide_hwif_t *hwif;
                int idx;
 
@@ -1288,6 +1298,7 @@ struct ide_host *ide_host_alloc(const struct ide_port_info *d, hw_regs_t **hws)
                if (idx < 0) {
                        printk(KERN_ERR "%s: no free slot for interface\n",
                                        d ? d->name : "ide");
+                       ide_port_free_devices(hwif);
                        kfree(hwif);
                        continue;
                }
@@ -1344,7 +1355,7 @@ static void ide_disable_port(ide_hwif_t *hwif)
 }
 
 int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
-                     hw_regs_t **hws)
+                     struct ide_hw **hws)
 {
        ide_hwif_t *hwif, *mate = NULL;
        int i, j = 0;
@@ -1438,13 +1449,13 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
 }
 EXPORT_SYMBOL_GPL(ide_host_register);
 
-int ide_host_add(const struct ide_port_info *d, hw_regs_t **hws,
-                struct ide_host **hostp)
+int ide_host_add(const struct ide_port_info *d, struct ide_hw **hws,
+                unsigned int n_ports, struct ide_host **hostp)
 {
        struct ide_host *host;
        int rc;
 
-       host = ide_host_alloc(d, hws);
+       host = ide_host_alloc(d, hws, n_ports);
        if (host == NULL)
                return -ENOMEM;
 
index d9764f0bc82f54e4b250c6e03754d108e2252383..4b447a8a49d4f7c44cb1c37a2390f902802dc519 100644 (file)
@@ -240,18 +240,27 @@ static struct class *idetape_sysfs_class;
 
 static void ide_tape_release(struct device *);
 
-static struct ide_tape_obj *ide_tape_get(struct gendisk *disk)
+static struct ide_tape_obj *idetape_devs[MAX_HWIFS * MAX_DRIVES];
+
+static struct ide_tape_obj *ide_tape_get(struct gendisk *disk, bool cdev,
+                                        unsigned int i)
 {
        struct ide_tape_obj *tape = NULL;
 
        mutex_lock(&idetape_ref_mutex);
-       tape = ide_drv_g(disk, ide_tape_obj);
+
+       if (cdev)
+               tape = idetape_devs[i];
+       else
+               tape = ide_drv_g(disk, ide_tape_obj);
+
        if (tape) {
                if (ide_device_get(tape->drive))
                        tape = NULL;
                else
                        get_device(&tape->dev);
        }
+
        mutex_unlock(&idetape_ref_mutex);
        return tape;
 }
@@ -266,24 +275,6 @@ static void ide_tape_put(struct ide_tape_obj *tape)
        mutex_unlock(&idetape_ref_mutex);
 }
 
-/*
- * The variables below are used for the character device interface. Additional
- * state variables are defined in our ide_drive_t structure.
- */
-static struct ide_tape_obj *idetape_devs[MAX_HWIFS * MAX_DRIVES];
-
-static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i)
-{
-       struct ide_tape_obj *tape = NULL;
-
-       mutex_lock(&idetape_ref_mutex);
-       tape = idetape_devs[i];
-       if (tape)
-               get_device(&tape->dev);
-       mutex_unlock(&idetape_ref_mutex);
-       return tape;
-}
-
 /*
  * called on each failed packet command retry to analyze the request sense. We
  * currently do not utilize this information.
@@ -397,7 +388,8 @@ static int ide_tape_callback(ide_drive_t *drive, int dsc)
                if (readpos[0] & 0x4) {
                        printk(KERN_INFO "ide-tape: Block location is unknown"
                                         "to the tape\n");
-                       clear_bit(IDE_AFLAG_ADDRESS_VALID, &drive->atapi_flags);
+                       clear_bit(ilog2(IDE_AFLAG_ADDRESS_VALID),
+                                 &drive->atapi_flags);
                        uptodate = 0;
                        err = IDE_DRV_ERROR_GENERAL;
                } else {
@@ -406,7 +398,8 @@ static int ide_tape_callback(ide_drive_t *drive, int dsc)
 
                        tape->partition = readpos[1];
                        tape->first_frame = be32_to_cpup((__be32 *)&readpos[4]);
-                       set_bit(IDE_AFLAG_ADDRESS_VALID, &drive->atapi_flags);
+                       set_bit(ilog2(IDE_AFLAG_ADDRESS_VALID),
+                               &drive->atapi_flags);
                }
        }
 
@@ -656,15 +649,15 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
 
        if ((drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) == 0 &&
            (rq->cmd[13] & REQ_IDETAPE_PC2) == 0)
-               set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags);
+               drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC;
 
        if (drive->dev_flags & IDE_DFLAG_POST_RESET) {
-               set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags);
+               drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC;
                drive->dev_flags &= ~IDE_DFLAG_POST_RESET;
        }
 
-       if (!test_and_clear_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags) &&
-           (stat & ATA_DSC) == 0) {
+       if (!(drive->atapi_flags & IDE_AFLAG_IGNORE_DSC) &&
+           !(stat & ATA_DSC)) {
                if (postponed_rq == NULL) {
                        tape->dsc_polling_start = jiffies;
                        tape->dsc_poll_freq = tape->best_dsc_rw_freq;
@@ -684,7 +677,9 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
                        tape->dsc_poll_freq = IDETAPE_DSC_MA_SLOW;
                idetape_postpone_request(drive);
                return ide_stopped;
-       }
+       } else
+               drive->atapi_flags &= ~IDE_AFLAG_IGNORE_DSC;
+
        if (rq->cmd[13] & REQ_IDETAPE_READ) {
                pc = &tape->queued_pc;
                ide_tape_create_rw_cmd(tape, pc, rq, READ_6);
@@ -744,7 +739,7 @@ static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout)
        int load_attempted = 0;
 
        /* Wait for the tape to become ready */
-       set_bit(IDE_AFLAG_MEDIUM_PRESENT, &drive->atapi_flags);
+       set_bit(ilog2(IDE_AFLAG_MEDIUM_PRESENT), &drive->atapi_flags);
        timeout += jiffies;
        while (time_before(jiffies, timeout)) {
                if (ide_do_test_unit_ready(drive, disk) == 0)
@@ -820,7 +815,7 @@ static void __ide_tape_discard_merge_buffer(ide_drive_t *drive)
        if (tape->chrdev_dir != IDETAPE_DIR_READ)
                return;
 
-       clear_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags);
+       clear_bit(ilog2(IDE_AFLAG_FILEMARK), &drive->atapi_flags);
        tape->valid = 0;
        if (tape->buf != NULL) {
                kfree(tape->buf);
@@ -1113,7 +1108,8 @@ static int idetape_space_over_filemarks(ide_drive_t *drive, short mt_op,
 
        if (tape->chrdev_dir == IDETAPE_DIR_READ) {
                tape->valid = 0;
-               if (test_and_clear_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags))
+               if (test_and_clear_bit(ilog2(IDE_AFLAG_FILEMARK),
+                                      &drive->atapi_flags))
                        ++count;
                ide_tape_discard_merge_buffer(drive, 0);
        }
@@ -1168,7 +1164,7 @@ static ssize_t idetape_chrdev_read(struct file *file, char __user *buf,
        debug_log(DBG_CHRDEV, "Enter %s, count %Zd\n", __func__, count);
 
        if (tape->chrdev_dir != IDETAPE_DIR_READ) {
-               if (test_bit(IDE_AFLAG_DETECT_BS, &drive->atapi_flags))
+               if (test_bit(ilog2(IDE_AFLAG_DETECT_BS), &drive->atapi_flags))
                        if (count > tape->blk_size &&
                            (count % tape->blk_size) == 0)
                                tape->user_bs_factor = count / tape->blk_size;
@@ -1184,7 +1180,8 @@ static ssize_t idetape_chrdev_read(struct file *file, char __user *buf,
                /* refill if staging buffer is empty */
                if (!tape->valid) {
                        /* If we are at a filemark, nothing more to read */
-                       if (test_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags))
+                       if (test_bit(ilog2(IDE_AFLAG_FILEMARK),
+                                    &drive->atapi_flags))
                                break;
                        /* read */
                        if (idetape_queue_rw_tail(drive, REQ_IDETAPE_READ,
@@ -1202,7 +1199,7 @@ static ssize_t idetape_chrdev_read(struct file *file, char __user *buf,
                done += todo;
        }
 
-       if (!done && test_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags)) {
+       if (!done && test_bit(ilog2(IDE_AFLAG_FILEMARK), &drive->atapi_flags)) {
                debug_log(DBG_SENSE, "%s: spacing over filemark\n", tape->name);
 
                idetape_space_over_filemarks(drive, MTFSF, 1);
@@ -1336,7 +1333,8 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count)
                ide_tape_discard_merge_buffer(drive, 0);
                retval = ide_do_start_stop(drive, disk, !IDETAPE_LU_LOAD_MASK);
                if (!retval)
-                       clear_bit(IDE_AFLAG_MEDIUM_PRESENT, &drive->atapi_flags);
+                       clear_bit(ilog2(IDE_AFLAG_MEDIUM_PRESENT),
+                                 &drive->atapi_flags);
                return retval;
        case MTNOP:
                ide_tape_discard_merge_buffer(drive, 0);
@@ -1358,9 +1356,11 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count)
                            mt_count % tape->blk_size)
                                return -EIO;
                        tape->user_bs_factor = mt_count / tape->blk_size;
-                       clear_bit(IDE_AFLAG_DETECT_BS, &drive->atapi_flags);
+                       clear_bit(ilog2(IDE_AFLAG_DETECT_BS),
+                                 &drive->atapi_flags);
                } else
-                       set_bit(IDE_AFLAG_DETECT_BS, &drive->atapi_flags);
+                       set_bit(ilog2(IDE_AFLAG_DETECT_BS),
+                               &drive->atapi_flags);
                return 0;
        case MTSEEK:
                ide_tape_discard_merge_buffer(drive, 0);
@@ -1486,7 +1486,7 @@ static int idetape_chrdev_open(struct inode *inode, struct file *filp)
                return -ENXIO;
 
        lock_kernel();
-       tape = ide_tape_chrdev_get(i);
+       tape = ide_tape_get(NULL, true, i);
        if (!tape) {
                unlock_kernel();
                return -ENXIO;
@@ -1505,20 +1505,20 @@ static int idetape_chrdev_open(struct inode *inode, struct file *filp)
 
        filp->private_data = tape;
 
-       if (test_and_set_bit(IDE_AFLAG_BUSY, &drive->atapi_flags)) {
+       if (test_and_set_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags)) {
                retval = -EBUSY;
                goto out_put_tape;
        }
 
        retval = idetape_wait_ready(drive, 60 * HZ);
        if (retval) {
-               clear_bit(IDE_AFLAG_BUSY, &drive->atapi_flags);
+               clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags);
                printk(KERN_ERR "ide-tape: %s: drive not ready\n", tape->name);
                goto out_put_tape;
        }
 
        idetape_read_position(drive);
-       if (!test_bit(IDE_AFLAG_ADDRESS_VALID, &drive->atapi_flags))
+       if (!test_bit(ilog2(IDE_AFLAG_ADDRESS_VALID), &drive->atapi_flags))
                (void)idetape_rewind_tape(drive);
 
        /* Read block size and write protect status from drive. */
@@ -1534,7 +1534,7 @@ static int idetape_chrdev_open(struct inode *inode, struct file *filp)
        if (tape->write_prot) {
                if ((filp->f_flags & O_ACCMODE) == O_WRONLY ||
                    (filp->f_flags & O_ACCMODE) == O_RDWR) {
-                       clear_bit(IDE_AFLAG_BUSY, &drive->atapi_flags);
+                       clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags);
                        retval = -EROFS;
                        goto out_put_tape;
                }
@@ -1591,15 +1591,17 @@ static int idetape_chrdev_release(struct inode *inode, struct file *filp)
                        ide_tape_discard_merge_buffer(drive, 1);
        }
 
-       if (minor < 128 && test_bit(IDE_AFLAG_MEDIUM_PRESENT, &drive->atapi_flags))
+       if (minor < 128 && test_bit(ilog2(IDE_AFLAG_MEDIUM_PRESENT),
+                                   &drive->atapi_flags))
                (void) idetape_rewind_tape(drive);
+
        if (tape->chrdev_dir == IDETAPE_DIR_NONE) {
                if (tape->door_locked == DOOR_LOCKED) {
                        if (!ide_set_media_lock(drive, tape->disk, 0))
                                tape->door_locked = DOOR_UNLOCKED;
                }
        }
-       clear_bit(IDE_AFLAG_BUSY, &drive->atapi_flags);
+       clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags);
        ide_tape_put(tape);
        unlock_kernel();
        return 0;
@@ -1905,7 +1907,7 @@ static const struct file_operations idetape_fops = {
 
 static int idetape_open(struct block_device *bdev, fmode_t mode)
 {
-       struct ide_tape_obj *tape = ide_tape_get(bdev->bd_disk);
+       struct ide_tape_obj *tape = ide_tape_get(bdev->bd_disk, false, 0);
 
        if (!tape)
                return -ENXIO;
index a0c3e1b2f73c20b6b005eb9ce2b35ea61bbb42f1..75b85a8cd2d4935ba500927946fa292c890e0e8d 100644 (file)
@@ -98,7 +98,6 @@ ide_startstop_t do_rw_taskfile(ide_drive_t *drive, struct ide_cmd *orig_cmd)
        if ((cmd->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) {
                ide_tf_dump(drive->name, cmd);
                tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
-               SELECT_MASK(drive, 0);
 
                if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA) {
                        u8 data[2] = { cmd->tf.data, cmd->hob.data };
@@ -166,7 +165,7 @@ static ide_startstop_t task_no_data_intr(ide_drive_t *drive)
        if (!OK_STAT(stat, ATA_DRDY, BAD_STAT)) {
                if (custom && tf->command == ATA_CMD_SET_MULTI) {
                        drive->mult_req = drive->mult_count = 0;
-                       drive->special.b.recalibrate = 1;
+                       drive->special_flags |= IDE_SFLAG_RECALIBRATE;
                        (void)ide_dump_status(drive, __func__, stat);
                        return ide_stopped;
                } else if (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) {
index 92c9b90931e73393f0d47b311b3fb1839483a1df..16d056939f9f313119c5a0c51da62456d85669aa 100644 (file)
@@ -211,6 +211,11 @@ static unsigned int ide_noflush;
 module_param_call(noflush, ide_set_dev_param_mask, NULL, &ide_noflush, 0);
 MODULE_PARM_DESC(noflush, "disable flush requests for a device");
 
+static unsigned int ide_nohpa;
+
+module_param_call(nohpa, ide_set_dev_param_mask, NULL, &ide_nohpa, 0);
+MODULE_PARM_DESC(nohpa, "disable Host Protected Area for a device");
+
 static unsigned int ide_noprobe;
 
 module_param_call(noprobe, ide_set_dev_param_mask, NULL, &ide_noprobe, 0);
@@ -281,6 +286,11 @@ static void ide_dev_apply_params(ide_drive_t *drive, u8 unit)
                                 drive->name);
                drive->dev_flags |= IDE_DFLAG_NOFLUSH;
        }
+       if (ide_nohpa & (1 << i)) {
+               printk(KERN_INFO "ide: disabling Host Protected Area for %s\n",
+                                drive->name);
+               drive->dev_flags |= IDE_DFLAG_NOHPA;
+       }
        if (ide_noprobe & (1 << i)) {
                printk(KERN_INFO "ide: skipping probe for %s\n", drive->name);
                drive->dev_flags |= IDE_DFLAG_NOPROBE;
index 051b4ab0f359d033745e0a035235a656dea7be4e..ee9b55ecc62b10741d1c7693d00ca8209f66ca78 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 
-static void __devinit plat_ide_setup_ports(hw_regs_t *hw,
+static void __devinit plat_ide_setup_ports(struct ide_hw *hw,
                                           void __iomem *base,
                                           void __iomem *ctrl,
                                           struct pata_platform_info *pdata,
@@ -40,12 +40,11 @@ static void __devinit plat_ide_setup_ports(hw_regs_t *hw,
        hw->io_ports.ctl_addr = (unsigned long)ctrl;
 
        hw->irq = irq;
-
-       hw->chipset = ide_generic;
 }
 
 static const struct ide_port_info platform_ide_port_info = {
        .host_flags             = IDE_HFLAG_NO_DMA,
+       .chipset                = ide_generic,
 };
 
 static int __devinit plat_ide_probe(struct platform_device *pdev)
@@ -55,7 +54,7 @@ static int __devinit plat_ide_probe(struct platform_device *pdev)
        struct pata_platform_info *pdata;
        struct ide_host *host;
        int ret = 0, mmio = 0;
-       hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+       struct ide_hw hw, *hws[] = { &hw };
        struct ide_port_info d = platform_ide_port_info;
 
        pdata = pdev->dev.platform_data;
@@ -99,7 +98,7 @@ static int __devinit plat_ide_probe(struct platform_device *pdev)
        if (mmio)
                d.host_flags |= IDE_HFLAG_MMIO;
 
-       ret = ide_host_add(&d, hws, &host);
+       ret = ide_host_add(&d, hws, 1, &host);
        if (ret)
                goto out;
 
index 4b1718e832839186c12673f8b589022ba115c55a..1447c8c90565dbdbb669465da8e1e2a5186d8526 100644 (file)
@@ -62,7 +62,7 @@ int macide_ack_intr(ide_hwif_t* hwif)
        return 0;
 }
 
-static void __init macide_setup_ports(hw_regs_t *hw, unsigned long base,
+static void __init macide_setup_ports(struct ide_hw *hw, unsigned long base,
                                      int irq, ide_ack_intr_t *ack_intr)
 {
        int i;
@@ -76,13 +76,12 @@ static void __init macide_setup_ports(hw_regs_t *hw, unsigned long base,
 
        hw->irq = irq;
        hw->ack_intr = ack_intr;
-
-       hw->chipset = ide_generic;
 }
 
 static const struct ide_port_info macide_port_info = {
        .host_flags             = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
        .irq_flags              = IRQF_SHARED,
+       .chipset                = ide_generic,
 };
 
 static const char *mac_ide_name[] =
@@ -97,7 +96,7 @@ static int __init macide_init(void)
        ide_ack_intr_t *ack_intr;
        unsigned long base;
        int irq;
-       hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+       struct ide_hw hw, *hws[] = { &hw };
 
        if (!MACH_IS_MAC)
                return -ENODEV;
@@ -127,7 +126,7 @@ static int __init macide_init(void)
 
        macide_setup_ports(&hw, base, irq, ack_intr);
 
-       return ide_host_add(&macide_port_info, hws, NULL);
+       return ide_host_add(&macide_port_info, hws, 1, NULL);
 }
 
 module_init(macide_init);
index 09d813d313f4a44986a2f358d8ddc08c619533f1..3c1dc015215351ed1cf43e00c8fb85b859ff22d0 100644 (file)
@@ -306,6 +306,7 @@ static struct ide_port_info __devinitdata palm_bk3710_port_info = {
        .host_flags             = IDE_HFLAG_MMIO,
        .pio_mask               = ATA_PIO4,
        .mwdma_mask             = ATA_MWDMA2,
+       .chipset                = ide_palm3710,
 };
 
 static int __init palm_bk3710_probe(struct platform_device *pdev)
@@ -315,7 +316,7 @@ static int __init palm_bk3710_probe(struct platform_device *pdev)
        void __iomem *base;
        unsigned long rate, mem_size;
        int i, rc;
-       hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+       struct ide_hw hw, *hws[] = { &hw };
 
        clk = clk_get(&pdev->dev, "IDECLK");
        if (IS_ERR(clk))
@@ -363,13 +364,12 @@ static int __init palm_bk3710_probe(struct platform_device *pdev)
                        (base + IDE_PALM_ATA_PRI_CTL_OFFSET);
        hw.irq = irq->start;
        hw.dev = &pdev->dev;
-       hw.chipset = ide_palm3710;
 
        palm_bk3710_port_info.udma_mask = rate < 100000000 ? ATA_UDMA4 :
                                                             ATA_UDMA5;
 
        /* Register the IDE interface with Linux */
-       rc = ide_host_add(&palm_bk3710_port_info, hws, NULL);
+       rc = ide_host_add(&palm_bk3710_port_info, hws, 1, NULL);
        if (rc)
                goto out;
 
index b68906c3c17e49f4223a1c84c2b68f1a17d6f47e..65ba8239e7b563496ca93c905841f5c731d9e2e3 100644 (file)
 #define DBG(fmt, args...)
 #endif
 
-static const char *pdc_quirk_drives[] = {
-       "QUANTUM FIREBALLlct08 08",
-       "QUANTUM FIREBALLP KA6.4",
-       "QUANTUM FIREBALLP KA9.1",
-       "QUANTUM FIREBALLP LM20.4",
-       "QUANTUM FIREBALLP KX13.6",
-       "QUANTUM FIREBALLP KX20.5",
-       "QUANTUM FIREBALLP KX27.3",
-       "QUANTUM FIREBALLP LM20.5",
-       NULL
-};
-
 static u8 max_dma_rate(struct pci_dev *pdev)
 {
        u8 mode;
@@ -200,19 +188,6 @@ static u8 pdcnew_cable_detect(ide_hwif_t *hwif)
                return ATA_CBL_PATA80;
 }
 
-static void pdcnew_quirkproc(ide_drive_t *drive)
-{
-       const char **list, *m = (char *)&drive->id[ATA_ID_PROD];
-
-       for (list = pdc_quirk_drives; *list != NULL; list++)
-               if (strstr(m, *list) != NULL) {
-                       drive->quirk_list = 2;
-                       return;
-               }
-
-       drive->quirk_list = 0;
-}
-
 static void pdcnew_reset(ide_drive_t *drive)
 {
        /*
@@ -473,7 +448,6 @@ static struct pci_dev * __devinit pdc20270_get_dev2(struct pci_dev *dev)
 static const struct ide_port_ops pdcnew_port_ops = {
        .set_pio_mode           = pdcnew_set_pio_mode,
        .set_dma_mode           = pdcnew_set_dma_mode,
-       .quirkproc              = pdcnew_quirkproc,
        .resetproc              = pdcnew_reset,
        .cable_detect           = pdcnew_cable_detect,
 };
index e24ecc87a9b1837a60bdfce7ae59fffd1b2ad7f1..b6abf7e52cacb04cfa011e7a1f2adf476c28d885 100644 (file)
 
 #define PDC202XX_DEBUG_DRIVE_INFO      0
 
-static const char *pdc_quirk_drives[] = {
-       "QUANTUM FIREBALLlct08 08",
-       "QUANTUM FIREBALLP KA6.4",
-       "QUANTUM FIREBALLP KA9.1",
-       "QUANTUM FIREBALLP LM20.4",
-       "QUANTUM FIREBALLP KX13.6",
-       "QUANTUM FIREBALLP KX20.5",
-       "QUANTUM FIREBALLP KX27.3",
-       "QUANTUM FIREBALLP LM20.5",
-       NULL
-};
-
 static void pdc_old_disable_66MHz_clock(ide_hwif_t *);
 
 static void pdc202xx_set_mode(ide_drive_t *drive, const u8 speed)
@@ -151,19 +139,6 @@ static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif)
        outb(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg);
 }
 
-static void pdc202xx_quirkproc(ide_drive_t *drive)
-{
-       const char **list, *m = (char *)&drive->id[ATA_ID_PROD];
-
-       for (list = pdc_quirk_drives; *list != NULL; list++)
-               if (strstr(m, *list) != NULL) {
-                       drive->quirk_list = 2;
-                       return;
-               }
-
-       drive->quirk_list = 0;
-}
-
 static void pdc202xx_dma_start(ide_drive_t *drive)
 {
        if (drive->current_speed > XFER_UDMA_2)
@@ -203,52 +178,6 @@ static int pdc202xx_dma_end(ide_drive_t *drive)
        return ide_dma_end(drive);
 }
 
-static int pdc202xx_dma_test_irq(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif        = drive->hwif;
-       unsigned long high_16   = hwif->extra_base - 16;
-       u8 dma_stat             = inb(hwif->dma_base + ATA_DMA_STATUS);
-       u8 sc1d                 = inb(high_16 + 0x001d);
-
-       if (hwif->channel) {
-               /* bit7: Error, bit6: Interrupting, bit5: FIFO Full, bit4: FIFO Empty */
-               if ((sc1d & 0x50) == 0x50)
-                       goto somebody_else;
-               else if ((sc1d & 0x40) == 0x40)
-                       return (dma_stat & 4) == 4;
-       } else {
-               /* bit3: Error, bit2: Interrupting, bit1: FIFO Full, bit0: FIFO Empty */
-               if ((sc1d & 0x05) == 0x05)
-                       goto somebody_else;
-               else if ((sc1d & 0x04) == 0x04)
-                       return (dma_stat & 4) == 4;
-       }
-somebody_else:
-       return (dma_stat & 4) == 4;     /* return 1 if INTR asserted */
-}
-
-static void pdc202xx_reset(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif        = drive->hwif;
-       unsigned long high_16   = hwif->extra_base - 16;
-       u8 udma_speed_flag      = inb(high_16 | 0x001f);
-
-       printk(KERN_WARNING "PDC202xx: software reset...\n");
-
-       outb(udma_speed_flag | 0x10, high_16 | 0x001f);
-       mdelay(100);
-       outb(udma_speed_flag & ~0x10, high_16 | 0x001f);
-       mdelay(2000);   /* 2 seconds ?! */
-
-       ide_set_max_pio(drive);
-}
-
-static void pdc202xx_dma_lost_irq(ide_drive_t *drive)
-{
-       pdc202xx_reset(drive);
-       ide_dma_lost_irq(drive);
-}
-
 static int init_chipset_pdc202xx(struct pci_dev *dev)
 {
        unsigned long dmabase = pci_resource_start(dev, 4);
@@ -302,37 +231,22 @@ static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
 static const struct ide_port_ops pdc20246_port_ops = {
        .set_pio_mode           = pdc202xx_set_pio_mode,
        .set_dma_mode           = pdc202xx_set_mode,
-       .quirkproc              = pdc202xx_quirkproc,
 };
 
 static const struct ide_port_ops pdc2026x_port_ops = {
        .set_pio_mode           = pdc202xx_set_pio_mode,
        .set_dma_mode           = pdc202xx_set_mode,
-       .quirkproc              = pdc202xx_quirkproc,
-       .resetproc              = pdc202xx_reset,
        .cable_detect           = pdc2026x_cable_detect,
 };
 
-static const struct ide_dma_ops pdc20246_dma_ops = {
-       .dma_host_set           = ide_dma_host_set,
-       .dma_setup              = ide_dma_setup,
-       .dma_start              = ide_dma_start,
-       .dma_end                = ide_dma_end,
-       .dma_test_irq           = pdc202xx_dma_test_irq,
-       .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_sff_read_status    = ide_dma_sff_read_status,
-};
-
 static const struct ide_dma_ops pdc2026x_dma_ops = {
        .dma_host_set           = ide_dma_host_set,
        .dma_setup              = ide_dma_setup,
        .dma_start              = pdc202xx_dma_start,
        .dma_end                = pdc202xx_dma_end,
-       .dma_test_irq           = pdc202xx_dma_test_irq,
-       .dma_lost_irq           = pdc202xx_dma_lost_irq,
+       .dma_test_irq           = ide_dma_test_irq,
+       .dma_lost_irq           = ide_dma_lost_irq,
        .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_clear              = pdc202xx_reset,
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
@@ -354,7 +268,7 @@ static const struct ide_port_info pdc202xx_chipsets[] __devinitdata = {
                .name           = DRV_NAME,
                .init_chipset   = init_chipset_pdc202xx,
                .port_ops       = &pdc20246_port_ops,
-               .dma_ops        = &pdc20246_dma_ops,
+               .dma_ops        = &sff_dma_ops,
                .host_flags     = IDE_HFLAGS_PDC202XX,
                .pio_mask       = ATA_PIO4,
                .mwdma_mask     = ATA_MWDMA2,
index f76e4e6b408f018483c0761c0efe8cdadda46975..97642a7a79c4143afc17e04db691cf555ddc8b40 100644 (file)
@@ -1023,13 +1023,14 @@ static const struct ide_port_info pmac_port_info = {
  * Setup, register & probe an IDE channel driven by this driver, this is
  * called by one of the 2 probe functions (macio or PCI).
  */
-static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, hw_regs_t *hw)
+static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif,
+                                          struct ide_hw *hw)
 {
        struct device_node *np = pmif->node;
        const int *bidp;
        struct ide_host *host;
        ide_hwif_t *hwif;
-       hw_regs_t *hws[] = { hw, NULL, NULL, NULL };
+       struct ide_hw *hws[] = { hw };
        struct ide_port_info d = pmac_port_info;
        int rc;
 
@@ -1077,7 +1078,7 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, hw_regs_t *hw)
        /* Make sure we have sane timings */
        sanitize_timings(pmif);
 
-       host = ide_host_alloc(&d, hws);
+       host = ide_host_alloc(&d, hws, 1);
        if (host == NULL)
                return -ENOMEM;
        hwif = host->ports[0];
@@ -1124,7 +1125,7 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, hw_regs_t *hw)
        return 0;
 }
 
-static void __devinit pmac_ide_init_ports(hw_regs_t *hw, unsigned long base)
+static void __devinit pmac_ide_init_ports(struct ide_hw *hw, unsigned long base)
 {
        int i;
 
@@ -1144,7 +1145,7 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
        unsigned long regbase;
        pmac_ide_hwif_t *pmif;
        int irq, rc;
-       hw_regs_t hw;
+       struct ide_hw hw;
 
        pmif = kzalloc(sizeof(*pmif), GFP_KERNEL);
        if (pmif == NULL)
@@ -1268,7 +1269,7 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
        void __iomem *base;
        unsigned long rbase, rlen;
        int rc;
-       hw_regs_t hw;
+       struct ide_hw hw;
 
        np = pci_device_to_OF_node(pdev);
        if (np == NULL) {
index c79346679244228e5671570bea1d335b02cf78c9..ab49a97023d9294c0120635cbb57034ec7907149 100644 (file)
@@ -51,11 +51,11 @@ static int q40ide_default_irq(unsigned long base)
 /*
  * Addresses are pretranslated for Q40 ISA access.
  */
-static void q40_ide_setup_ports(hw_regs_t *hw, unsigned long base,
+static void q40_ide_setup_ports(struct ide_hw *hw, unsigned long base,
                        ide_ack_intr_t *ack_intr,
                        int irq)
 {
-       memset(hw, 0, sizeof(hw_regs_t));
+       memset(hw, 0, sizeof(*hw));
        /* BIG FAT WARNING: 
           assumption: only DATA port is ever used in 16 bit mode */
        hw->io_ports.data_addr = Q40_ISA_IO_W(base);
@@ -70,8 +70,6 @@ static void q40_ide_setup_ports(hw_regs_t *hw, unsigned long base,
 
        hw->irq = irq;
        hw->ack_intr = ack_intr;
-
-       hw->chipset = ide_generic;
 }
 
 static void q40ide_input_data(ide_drive_t *drive, struct ide_cmd *cmd,
@@ -119,6 +117,7 @@ static const struct ide_port_info q40ide_port_info = {
        .tp_ops                 = &q40ide_tp_ops,
        .host_flags             = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
        .irq_flags              = IRQF_SHARED,
+       .chipset                = ide_generic,
 };
 
 /* 
@@ -136,7 +135,7 @@ static const char *q40_ide_names[Q40IDE_NUM_HWIFS]={
 static int __init q40ide_init(void)
 {
     int i;
-    hw_regs_t hw[Q40IDE_NUM_HWIFS], *hws[] = { NULL, NULL, NULL, NULL };
+    struct ide_hw hw[Q40IDE_NUM_HWIFS], *hws[] = { NULL, NULL };
 
     if (!MACH_IS_Q40)
       return -ENODEV;
@@ -163,7 +162,7 @@ static int __init q40ide_init(void)
        hws[i] = &hw[i];
     }
 
-    return ide_host_add(&q40ide_port_info, hws, NULL);
+    return ide_host_add(&q40ide_port_info, hws, Q40IDE_NUM_HWIFS, NULL);
 }
 
 module_init(q40ide_init);
index d5003ca69801684bdc71e65db78767a41445c42e..00f54248f41f0d76fbf62e2c791123a0bf17dfe9 100644 (file)
 
 static const struct ide_port_info rapide_port_info = {
        .host_flags             = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
+       .chipset                = ide_generic,
 };
 
-static void rapide_setup_ports(hw_regs_t *hw, void __iomem *base,
+static void rapide_setup_ports(struct ide_hw *hw, void __iomem *base,
                               void __iomem *ctrl, unsigned int sz, int irq)
 {
        unsigned long port = (unsigned long)base;
@@ -35,7 +36,7 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
        void __iomem *base;
        struct ide_host *host;
        int ret;
-       hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+       struct ide_hw hw, *hws[] = { &hw };
 
        ret = ecard_request_resources(ec);
        if (ret)
@@ -49,10 +50,9 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
 
        memset(&hw, 0, sizeof(hw));
        rapide_setup_ports(&hw, base, base + 0x818, 1 << 6, ec->irq);
-       hw.chipset = ide_generic;
        hw.dev = &ec->dev;
 
-       ret = ide_host_add(&rapide_port_info, hws, &host);
+       ret = ide_host_add(&rapide_port_info, hws, 1, &host);
        if (ret)
                goto release;
 
index 5be41f25204f627e775aa4a962febf98a1cdb560..1104bb301eb98eb4f2d22b78a05ba33d1d99761c 100644 (file)
@@ -559,7 +559,7 @@ static int scc_ide_setup_pci_device(struct pci_dev *dev,
 {
        struct scc_ports *ports = pci_get_drvdata(dev);
        struct ide_host *host;
-       hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+       struct ide_hw hw, *hws[] = { &hw };
        int i, rc;
 
        memset(&hw, 0, sizeof(hw));
@@ -567,9 +567,8 @@ static int scc_ide_setup_pci_device(struct pci_dev *dev,
                hw.io_ports_array[i] = ports->dma + 0x20 + i * 4;
        hw.irq = dev->irq;
        hw.dev = &dev->dev;
-       hw.chipset = ide_pci;
 
-       rc = ide_host_add(d, hws, &host);
+       rc = ide_host_add(d, hws, 1, &host);
        if (rc)
                return rc;
 
@@ -823,6 +822,7 @@ static const struct ide_port_info scc_chipset __devinitdata = {
        .host_flags     = IDE_HFLAG_SINGLE,
        .irq_flags      = IRQF_SHARED,
        .pio_mask       = ATA_PIO4,
+       .chipset        = ide_pci,
 };
 
 /**
index 7a3a12d6e638eae21a9bbce4f3f269d55b5a8aa6..ab3db61d2ba038a84128b08870aa7bd091fc9624 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Copyright (C) 1998-2000  Andre Hedrick <andre@linux-ide.org>
  *  Copyright (C) 1995-1998  Mark Lord
- *  Copyright (C)      2007  Bartlomiej Zolnierkiewicz
+ *  Copyright (C) 2007-2009  Bartlomiej Zolnierkiewicz
  *
  *  May be copied or modified under the terms of the GNU General Public License
  */
@@ -301,11 +301,11 @@ static int ide_pci_check_iomem(struct pci_dev *dev, const struct ide_port_info *
 }
 
 /**
- *     ide_hw_configure        -       configure a hw_regs_t instance
+ *     ide_hw_configure        -       configure a struct ide_hw instance
  *     @dev: PCI device holding interface
  *     @d: IDE port info
  *     @port: port number
- *     @hw: hw_regs_t instance corresponding to this port
+ *     @hw: struct ide_hw instance corresponding to this port
  *
  *     Perform the initial set up for the hardware interface structure. This
  *     is done per interface port rather than per PCI device. There may be
@@ -315,7 +315,7 @@ static int ide_pci_check_iomem(struct pci_dev *dev, const struct ide_port_info *
  */
 
 static int ide_hw_configure(struct pci_dev *dev, const struct ide_port_info *d,
-                           unsigned int port, hw_regs_t *hw)
+                           unsigned int port, struct ide_hw *hw)
 {
        unsigned long ctl = 0, base = 0;
 
@@ -344,7 +344,6 @@ static int ide_hw_configure(struct pci_dev *dev, const struct ide_port_info *d,
 
        memset(hw, 0, sizeof(*hw));
        hw->dev = &dev->dev;
-       hw->chipset = d->chipset ? d->chipset : ide_pci;
        ide_std_init_ports(hw, base, ctl | 2);
 
        return 0;
@@ -446,8 +445,8 @@ out:
  *     ide_pci_setup_ports     -       configure ports/devices on PCI IDE
  *     @dev: PCI device
  *     @d: IDE port info
- *     @hw: hw_regs_t instances corresponding to this PCI IDE device
- *     @hws: hw_regs_t pointers table to update
+ *     @hw: struct ide_hw instances corresponding to this PCI IDE device
+ *     @hws: struct ide_hw pointers table to update
  *
  *     Scan the interfaces attached to this device and do any
  *     necessary per port setup. Attach the devices and ask the
@@ -459,7 +458,7 @@ out:
  */
 
 void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d,
-                        hw_regs_t *hw, hw_regs_t **hws)
+                        struct ide_hw *hw, struct ide_hw **hws)
 {
        int channels = (d->host_flags & IDE_HFLAG_SINGLE) ? 1 : 2, port;
        u8 tmp;
@@ -535,61 +534,15 @@ out:
        return ret;
 }
 
-int ide_pci_init_one(struct pci_dev *dev, const struct ide_port_info *d,
-                    void *priv)
-{
-       struct ide_host *host;
-       hw_regs_t hw[4], *hws[] = { NULL, NULL, NULL, NULL };
-       int ret;
-
-       ret = ide_setup_pci_controller(dev, d, 1);
-       if (ret < 0)
-               goto out;
-
-       ide_pci_setup_ports(dev, d, &hw[0], &hws[0]);
-
-       host = ide_host_alloc(d, hws);
-       if (host == NULL) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       host->dev[0] = &dev->dev;
-
-       host->host_priv = priv;
-
-       host->irq_flags = IRQF_SHARED;
-
-       pci_set_drvdata(dev, host);
-
-       ret = do_ide_setup_pci_device(dev, d, 1);
-       if (ret < 0)
-               goto out;
-
-       /* fixup IRQ */
-       if (ide_pci_is_in_compatibility_mode(dev)) {
-               hw[0].irq = pci_get_legacy_ide_irq(dev, 0);
-               hw[1].irq = pci_get_legacy_ide_irq(dev, 1);
-       } else
-               hw[1].irq = hw[0].irq = ret;
-
-       ret = ide_host_register(host, d, hws);
-       if (ret)
-               ide_host_free(host);
-out:
-       return ret;
-}
-EXPORT_SYMBOL_GPL(ide_pci_init_one);
-
 int ide_pci_init_two(struct pci_dev *dev1, struct pci_dev *dev2,
                     const struct ide_port_info *d, void *priv)
 {
        struct pci_dev *pdev[] = { dev1, dev2 };
        struct ide_host *host;
-       int ret, i;
-       hw_regs_t hw[4], *hws[] = { NULL, NULL, NULL, NULL };
+       int ret, i, n_ports = dev2 ? 4 : 2;
+       struct ide_hw hw[4], *hws[] = { NULL, NULL, NULL, NULL };
 
-       for (i = 0; i < 2; i++) {
+       for (i = 0; i < n_ports / 2; i++) {
                ret = ide_setup_pci_controller(pdev[i], d, !i);
                if (ret < 0)
                        goto out;
@@ -597,23 +550,24 @@ int ide_pci_init_two(struct pci_dev *dev1, struct pci_dev *dev2,
                ide_pci_setup_ports(pdev[i], d, &hw[i*2], &hws[i*2]);
        }
 
-       host = ide_host_alloc(d, hws);
+       host = ide_host_alloc(d, hws, n_ports);
        if (host == NULL) {
                ret = -ENOMEM;
                goto out;
        }
 
        host->dev[0] = &dev1->dev;
-       host->dev[1] = &dev2->dev;
+       if (dev2)
+               host->dev[1] = &dev2->dev;
 
        host->host_priv = priv;
-
        host->irq_flags = IRQF_SHARED;
 
        pci_set_drvdata(pdev[0], host);
-       pci_set_drvdata(pdev[1], host);
+       if (dev2)
+               pci_set_drvdata(pdev[1], host);
 
-       for (i = 0; i < 2; i++) {
+       for (i = 0; i < n_ports / 2; i++) {
                ret = do_ide_setup_pci_device(pdev[i], d, !i);
 
                /*
@@ -639,6 +593,13 @@ out:
 }
 EXPORT_SYMBOL_GPL(ide_pci_init_two);
 
+int ide_pci_init_one(struct pci_dev *dev, const struct ide_port_info *d,
+                    void *priv)
+{
+       return ide_pci_init_two(dev, NULL, d, priv);
+}
+EXPORT_SYMBOL_GPL(ide_pci_init_one);
+
 void ide_pci_remove(struct pci_dev *dev)
 {
        struct ide_host *host = pci_get_drvdata(dev);
index e5d2a48a84de9314133d2b54c49f63aa08f536e4..5f37f168f94446c0403a676c0ed0ba7e91b0514b 100644 (file)
@@ -91,7 +91,7 @@ typedef struct {
 
 
 static void
-sgiioc4_init_hwif_ports(hw_regs_t * hw, unsigned long data_port,
+sgiioc4_init_hwif_ports(struct ide_hw *hw, unsigned long data_port,
                        unsigned long ctrl_port, unsigned long irq_port)
 {
        unsigned long reg = data_port;
@@ -546,7 +546,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
        unsigned long cmd_base, irqport;
        unsigned long bar0, cmd_phys_base, ctl;
        void __iomem *virt_base;
-       hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+       struct ide_hw hw, *hws[] = { &hw };
        int rc;
 
        /*  Get the CmdBlk and CtrlBlk Base Registers */
@@ -575,13 +575,12 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
        memset(&hw, 0, sizeof(hw));
        sgiioc4_init_hwif_ports(&hw, cmd_base, ctl, irqport);
        hw.irq = dev->irq;
-       hw.chipset = ide_pci;
        hw.dev = &dev->dev;
 
        /* Initializing chipset IRQ Registers */
        writel(0x03, (void __iomem *)(irqport + IOC4_INTR_SET * 4));
 
-       rc = ide_host_add(&sgiioc4_port_info, hws, NULL);
+       rc = ide_host_add(&sgiioc4_port_info, hws, 1, NULL);
        if (!rc)
                return 0;
 
index e4973cd1fba9e8735191f73e32e3eb9575f1d97d..bd82d228608c053dd0ded5ad1faa24749e443858 100644 (file)
@@ -451,8 +451,8 @@ static int sil_sata_reset_poll(ide_drive_t *drive)
 static void sil_sata_pre_reset(ide_drive_t *drive)
 {
        if (drive->media == ide_disk) {
-               drive->special.b.set_geometry = 0;
-               drive->special.b.recalibrate = 0;
+               drive->special_flags &=
+                       ~(IDE_SFLAG_SET_GEOMETRY | IDE_SFLAG_RECALIBRATE);
        }
 }
 
index b0a460625335c9c469b94ea94a7d4210c305e2ab..0924abff52ff6f1db1d2878c8a816327769d86ec 100644 (file)
@@ -10,7 +10,7 @@
  * with the timing registers setup.
  *  -- Benjamin Herrenschmidt (01/11/03) benh@kernel.crashing.org
  *
- * Copyright (C) 2006-2007 MontaVista Software, Inc. <source@mvista.com>
+ * Copyright (C) 2006-2007,2009 MontaVista Software, Inc. <source@mvista.com>
  * Copyright (C)      2007 Bartlomiej Zolnierkiewicz
  */
 
@@ -146,14 +146,15 @@ static void sl82c105_dma_lost_irq(ide_drive_t *drive)
        u32 val, mask           = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA;
        u8 dma_cmd;
 
-       printk("sl82c105: lost IRQ, resetting host\n");
+       printk(KERN_WARNING "sl82c105: lost IRQ, resetting host\n");
 
        /*
         * Check the raw interrupt from the drive.
         */
        pci_read_config_dword(dev, 0x40, &val);
        if (val & mask)
-               printk("sl82c105: drive was requesting IRQ, but host lost it\n");
+               printk(KERN_INFO "sl82c105: drive was requesting IRQ, "
+                      "but host lost it\n");
 
        /*
         * Was DMA enabled?  If so, disable it - we're resetting the
@@ -162,7 +163,7 @@ static void sl82c105_dma_lost_irq(ide_drive_t *drive)
        dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
        if (dma_cmd & 1) {
                outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD);
-               printk("sl82c105: DMA was enabled\n");
+               printk(KERN_INFO "sl82c105: DMA was enabled\n");
        }
 
        sl82c105_reset_host(dev);
index e33d764e2945339a89544ec045f2f6769fb73474..ea89fddeed9122fa002f1149ffb0364a7f579100 100644 (file)
@@ -130,8 +130,7 @@ static const struct ide_port_info tx4938ide_port_info __initdata = {
 
 static int __init tx4938ide_probe(struct platform_device *pdev)
 {
-       hw_regs_t hw;
-       hw_regs_t *hws[] = { &hw, NULL, NULL, NULL };
+       struct ide_hw hw, *hws[] = { &hw };
        struct ide_host *host;
        struct resource *res;
        struct tx4938ide_platform_info *pdata = pdev->dev.platform_data;
@@ -183,7 +182,7 @@ static int __init tx4938ide_probe(struct platform_device *pdev)
                tx4938ide_tune_ebusc(pdata->ebus_ch, pdata->gbus_clock, 0);
        else
                d.port_ops = NULL;
-       ret = ide_host_add(&d, hws, &host);
+       ret = ide_host_add(&d, hws, 1, &host);
        if (!ret)
                platform_set_drvdata(pdev, host);
        return ret;
index 5ca76224f6d11a731b585f98a35ea8e2661c4e5e..64b58ecc3f0ea7131d697634e4c848554f5b7e17 100644 (file)
@@ -537,8 +537,7 @@ static const struct ide_port_info tx4939ide_port_info __initdata = {
 
 static int __init tx4939ide_probe(struct platform_device *pdev)
 {
-       hw_regs_t hw;
-       hw_regs_t *hws[] = { &hw, NULL, NULL, NULL };
+       struct ide_hw hw, *hws[] = { &hw };
        struct ide_host *host;
        struct resource *res;
        int irq, ret;
@@ -581,7 +580,7 @@ static int __init tx4939ide_probe(struct platform_device *pdev)
        hw.dev = &pdev->dev;
 
        pr_info("TX4939 IDE interface (base %#lx, irq %d)\n", mapbase, irq);
-       host = ide_host_alloc(&tx4939ide_port_info, hws);
+       host = ide_host_alloc(&tx4939ide_port_info, hws, 1);
        if (!host)
                return -ENOMEM;
        /* use extra_base for base address of the all registers */
index bb17cce3cb592dfb079cec561b11d1aa58b33221..f5c45b194f534df104bf4be40c39c302b9788e5e 100644 (file)
@@ -133,7 +133,7 @@ static inline int c2_poll_one(struct c2_dev *c2dev,
        struct c2_qp *qp;
        int is_recv = 0;
 
-       ce = (struct c2wr_ce *) c2_mq_consume(&cq->mq);
+       ce = c2_mq_consume(&cq->mq);
        if (!ce) {
                return -EAGAIN;
        }
@@ -146,7 +146,7 @@ static inline int c2_poll_one(struct c2_dev *c2dev,
        while ((qp =
                (struct c2_qp *) (unsigned long) ce->qp_user_context) == NULL) {
                c2_mq_free(&cq->mq);
-               ce = (struct c2wr_ce *) c2_mq_consume(&cq->mq);
+               ce = c2_mq_consume(&cq->mq);
                if (!ce)
                        return -EAGAIN;
        }
index ff9be1a13106cf757f12209f1343d7d63059ec96..32e3b1461d81d551f3b1aa2a602c9449d2597c8c 100644 (file)
@@ -176,7 +176,7 @@ struct t3_send_wr {
        struct t3_sge sgl[T3_MAX_SGE];  /* 4+ */
 };
 
-#define T3_MAX_FASTREG_DEPTH 24
+#define T3_MAX_FASTREG_DEPTH 10
 #define T3_MAX_FASTREG_FRAG 10
 
 struct t3_fastreg_wr {
index 160ef482712dea2a3b33a080d5cc721dbbb014dc..e2a63214008a90b1ddf137341bbbbc4eac2d16e4 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/spinlock.h>
 #include <linux/ethtool.h>
 #include <linux/rtnetlink.h>
+#include <linux/inetdevice.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -1152,12 +1153,39 @@ static int iwch_query_device(struct ib_device *ibdev,
 static int iwch_query_port(struct ib_device *ibdev,
                           u8 port, struct ib_port_attr *props)
 {
+       struct iwch_dev *dev;
+       struct net_device *netdev;
+       struct in_device *inetdev;
+
        PDBG("%s ibdev %p\n", __func__, ibdev);
 
+       dev = to_iwch_dev(ibdev);
+       netdev = dev->rdev.port_info.lldevs[port-1];
+
        memset(props, 0, sizeof(struct ib_port_attr));
        props->max_mtu = IB_MTU_4096;
-       props->active_mtu = IB_MTU_2048;
-       props->state = IB_PORT_ACTIVE;
+       if (netdev->mtu >= 4096)
+               props->active_mtu = IB_MTU_4096;
+       else if (netdev->mtu >= 2048)
+               props->active_mtu = IB_MTU_2048;
+       else if (netdev->mtu >= 1024)
+               props->active_mtu = IB_MTU_1024;
+       else if (netdev->mtu >= 512)
+               props->active_mtu = IB_MTU_512;
+       else
+               props->active_mtu = IB_MTU_256;
+
+       if (!netif_carrier_ok(netdev))
+               props->state = IB_PORT_DOWN;
+       else {
+               inetdev = in_dev_get(netdev);
+               if (inetdev->ifa_list)
+                       props->state = IB_PORT_ACTIVE;
+               else
+                       props->state = IB_PORT_INIT;
+               in_dev_put(inetdev);
+       }
+
        props->port_cap_flags =
            IB_PORT_CM_SUP |
            IB_PORT_SNMP_TUNNEL_SUP |
index 1798e6466bd07b87f6069182a00dc878b95c6858..689c35786dd2d0c778466c8fe4f4dfaeffb2c684 100644 (file)
@@ -165,7 +165,6 @@ struct hcp_modify_qp_control_block {
 #define MQPCB_MASK_ALT_P_KEY_IDX                EHCA_BMASK_IBM( 7,  7)
 #define MQPCB_MASK_RDMA_ATOMIC_CTRL             EHCA_BMASK_IBM( 8,  8)
 #define MQPCB_MASK_QP_STATE                     EHCA_BMASK_IBM( 9,  9)
-#define MQPCB_QP_STATE                          EHCA_BMASK_IBM(24, 31)
 #define MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES      EHCA_BMASK_IBM(11, 11)
 #define MQPCB_MASK_PATH_MIGRATION_STATE         EHCA_BMASK_IBM(12, 12)
 #define MQPCB_MASK_RDMA_ATOMIC_OUTST_DEST_QP    EHCA_BMASK_IBM(13, 13)
@@ -176,60 +175,33 @@ struct hcp_modify_qp_control_block {
 #define MQPCB_MASK_RETRY_COUNT                  EHCA_BMASK_IBM(18, 18)
 #define MQPCB_MASK_TIMEOUT                      EHCA_BMASK_IBM(19, 19)
 #define MQPCB_MASK_PATH_MTU                     EHCA_BMASK_IBM(20, 20)
-#define MQPCB_PATH_MTU                          EHCA_BMASK_IBM(24, 31)
 #define MQPCB_MASK_MAX_STATIC_RATE              EHCA_BMASK_IBM(21, 21)
-#define MQPCB_MAX_STATIC_RATE                   EHCA_BMASK_IBM(24, 31)
 #define MQPCB_MASK_DLID                         EHCA_BMASK_IBM(22, 22)
-#define MQPCB_DLID                              EHCA_BMASK_IBM(16, 31)
 #define MQPCB_MASK_RNR_RETRY_COUNT              EHCA_BMASK_IBM(23, 23)
-#define MQPCB_RNR_RETRY_COUNT                   EHCA_BMASK_IBM(29, 31)
 #define MQPCB_MASK_SOURCE_PATH_BITS             EHCA_BMASK_IBM(24, 24)
-#define MQPCB_SOURCE_PATH_BITS                  EHCA_BMASK_IBM(25, 31)
 #define MQPCB_MASK_TRAFFIC_CLASS                EHCA_BMASK_IBM(25, 25)
-#define MQPCB_TRAFFIC_CLASS                     EHCA_BMASK_IBM(24, 31)
 #define MQPCB_MASK_HOP_LIMIT                    EHCA_BMASK_IBM(26, 26)
-#define MQPCB_HOP_LIMIT                         EHCA_BMASK_IBM(24, 31)
 #define MQPCB_MASK_SOURCE_GID_IDX               EHCA_BMASK_IBM(27, 27)
-#define MQPCB_SOURCE_GID_IDX                    EHCA_BMASK_IBM(24, 31)
 #define MQPCB_MASK_FLOW_LABEL                   EHCA_BMASK_IBM(28, 28)
-#define MQPCB_FLOW_LABEL                        EHCA_BMASK_IBM(12, 31)
 #define MQPCB_MASK_DEST_GID                     EHCA_BMASK_IBM(30, 30)
 #define MQPCB_MASK_SERVICE_LEVEL_AL             EHCA_BMASK_IBM(31, 31)
-#define MQPCB_SERVICE_LEVEL_AL                  EHCA_BMASK_IBM(28, 31)
 #define MQPCB_MASK_SEND_GRH_FLAG_AL             EHCA_BMASK_IBM(32, 32)
-#define MQPCB_SEND_GRH_FLAG_AL                  EHCA_BMASK_IBM(31, 31)
 #define MQPCB_MASK_RETRY_COUNT_AL               EHCA_BMASK_IBM(33, 33)
-#define MQPCB_RETRY_COUNT_AL                    EHCA_BMASK_IBM(29, 31)
 #define MQPCB_MASK_TIMEOUT_AL                   EHCA_BMASK_IBM(34, 34)
-#define MQPCB_TIMEOUT_AL                        EHCA_BMASK_IBM(27, 31)
 #define MQPCB_MASK_MAX_STATIC_RATE_AL           EHCA_BMASK_IBM(35, 35)
-#define MQPCB_MAX_STATIC_RATE_AL                EHCA_BMASK_IBM(24, 31)
 #define MQPCB_MASK_DLID_AL                      EHCA_BMASK_IBM(36, 36)
-#define MQPCB_DLID_AL                           EHCA_BMASK_IBM(16, 31)
 #define MQPCB_MASK_RNR_RETRY_COUNT_AL           EHCA_BMASK_IBM(37, 37)
-#define MQPCB_RNR_RETRY_COUNT_AL                EHCA_BMASK_IBM(29, 31)
 #define MQPCB_MASK_SOURCE_PATH_BITS_AL          EHCA_BMASK_IBM(38, 38)
-#define MQPCB_SOURCE_PATH_BITS_AL               EHCA_BMASK_IBM(25, 31)
 #define MQPCB_MASK_TRAFFIC_CLASS_AL             EHCA_BMASK_IBM(39, 39)
-#define MQPCB_TRAFFIC_CLASS_AL                  EHCA_BMASK_IBM(24, 31)
 #define MQPCB_MASK_HOP_LIMIT_AL                 EHCA_BMASK_IBM(40, 40)
-#define MQPCB_HOP_LIMIT_AL                      EHCA_BMASK_IBM(24, 31)
 #define MQPCB_MASK_SOURCE_GID_IDX_AL            EHCA_BMASK_IBM(41, 41)
-#define MQPCB_SOURCE_GID_IDX_AL                 EHCA_BMASK_IBM(24, 31)
 #define MQPCB_MASK_FLOW_LABEL_AL                EHCA_BMASK_IBM(42, 42)
-#define MQPCB_FLOW_LABEL_AL                     EHCA_BMASK_IBM(12, 31)
 #define MQPCB_MASK_DEST_GID_AL                  EHCA_BMASK_IBM(44, 44)
 #define MQPCB_MASK_MAX_NR_OUTST_SEND_WR         EHCA_BMASK_IBM(45, 45)
-#define MQPCB_MAX_NR_OUTST_SEND_WR              EHCA_BMASK_IBM(16, 31)
 #define MQPCB_MASK_MAX_NR_OUTST_RECV_WR         EHCA_BMASK_IBM(46, 46)
-#define MQPCB_MAX_NR_OUTST_RECV_WR              EHCA_BMASK_IBM(16, 31)
 #define MQPCB_MASK_DISABLE_ETE_CREDIT_CHECK     EHCA_BMASK_IBM(47, 47)
-#define MQPCB_DISABLE_ETE_CREDIT_CHECK          EHCA_BMASK_IBM(31, 31)
-#define MQPCB_QP_NUMBER                         EHCA_BMASK_IBM( 8, 31)
 #define MQPCB_MASK_QP_ENABLE                    EHCA_BMASK_IBM(48, 48)
-#define MQPCB_QP_ENABLE                         EHCA_BMASK_IBM(31, 31)
 #define MQPCB_MASK_CURR_SRQ_LIMIT               EHCA_BMASK_IBM(49, 49)
-#define MQPCB_CURR_SRQ_LIMIT                    EHCA_BMASK_IBM(16, 31)
 #define MQPCB_MASK_QP_AFF_ASYN_EV_LOG_REG       EHCA_BMASK_IBM(50, 50)
 #define MQPCB_MASK_SHARED_RQ_HNDL               EHCA_BMASK_IBM(51, 51)
 
index 99bcbd7ffb0a3faf5ebe9281adbf297e67cbd491..4b89b791be6a3cf5fdb7947638778ddd4451f8ab 100644 (file)
@@ -479,13 +479,13 @@ void ehca_tasklet_neq(unsigned long data)
        struct ehca_eqe *eqe;
        u64 ret;
 
-       eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->neq);
+       eqe = ehca_poll_eq(shca, &shca->neq);
 
        while (eqe) {
                if (!EHCA_BMASK_GET(NEQE_COMPLETION_EVENT, eqe->entry))
                        parse_ec(shca, eqe->entry);
 
-               eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->neq);
+               eqe = ehca_poll_eq(shca, &shca->neq);
        }
 
        ret = hipz_h_reset_event(shca->ipz_hca_handle,
@@ -572,8 +572,7 @@ void ehca_process_eq(struct ehca_shca *shca, int is_irq)
        eqe_cnt = 0;
        do {
                u32 token;
-               eqe_cache[eqe_cnt].eqe =
-                       (struct ehca_eqe *)ehca_poll_eq(shca, eq);
+               eqe_cache[eqe_cnt].eqe = ehca_poll_eq(shca, eq);
                if (!eqe_cache[eqe_cnt].eqe)
                        break;
                eqe_value = eqe_cache[eqe_cnt].eqe->entry;
@@ -637,7 +636,7 @@ void ehca_process_eq(struct ehca_shca *shca, int is_irq)
                goto unlock_irq_spinlock;
        do {
                struct ehca_eqe *eqe;
-               eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->eq);
+               eqe = ehca_poll_eq(shca, &shca->eq);
                if (!eqe)
                        break;
                process_eqe(shca, eqe);
index 368311ce332bb2d0a9e6238c7e375d5bf37f9903..85905ab9391fec6703765117fcc29d0500d038d2 100644 (file)
@@ -52,7 +52,7 @@
 #include "ehca_tools.h"
 #include "hcp_if.h"
 
-#define HCAD_VERSION "0026"
+#define HCAD_VERSION "0027"
 
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>");
index 00c1081597141c7e2fac0b8f1a72f7273e04d50c..0338f1fabe8a9880884141c26f74a1ff61d182dc 100644 (file)
@@ -461,7 +461,7 @@ static struct ehca_qp *internal_create_qp(
                                              ib_device);
        struct ib_ucontext *context = NULL;
        u64 h_ret;
-       int is_llqp = 0, has_srq = 0;
+       int is_llqp = 0, has_srq = 0, is_user = 0;
        int qp_type, max_send_sge, max_recv_sge, ret;
 
        /* h_call's out parameters */
@@ -609,9 +609,6 @@ static struct ehca_qp *internal_create_qp(
                }
        }
 
-       if (pd->uobject && udata)
-               context = pd->uobject->context;
-
        my_qp = kmem_cache_zalloc(qp_cache, GFP_KERNEL);
        if (!my_qp) {
                ehca_err(pd->device, "pd=%p not enough memory to alloc qp", pd);
@@ -619,6 +616,11 @@ static struct ehca_qp *internal_create_qp(
                return ERR_PTR(-ENOMEM);
        }
 
+       if (pd->uobject && udata) {
+               is_user = 1;
+               context = pd->uobject->context;
+       }
+
        atomic_set(&my_qp->nr_events, 0);
        init_waitqueue_head(&my_qp->wait_completion);
        spin_lock_init(&my_qp->spinlock_s);
@@ -707,7 +709,7 @@ static struct ehca_qp *internal_create_qp(
                        (parms.squeue.is_small || parms.rqueue.is_small);
        }
 
-       h_ret = hipz_h_alloc_resource_qp(shca->ipz_hca_handle, &parms);
+       h_ret = hipz_h_alloc_resource_qp(shca->ipz_hca_handle, &parms, is_user);
        if (h_ret != H_SUCCESS) {
                ehca_err(pd->device, "h_alloc_resource_qp() failed h_ret=%lli",
                         h_ret);
@@ -769,18 +771,20 @@ static struct ehca_qp *internal_create_qp(
                        goto create_qp_exit2;
                }
 
-               my_qp->sq_map.entries = my_qp->ipz_squeue.queue_length /
-                        my_qp->ipz_squeue.qe_size;
-               my_qp->sq_map.map = vmalloc(my_qp->sq_map.entries *
-                                       sizeof(struct ehca_qmap_entry));
-               if (!my_qp->sq_map.map) {
-                       ehca_err(pd->device, "Couldn't allocate squeue "
-                                "map ret=%i", ret);
-                       goto create_qp_exit3;
+               if (!is_user) {
+                       my_qp->sq_map.entries = my_qp->ipz_squeue.queue_length /
+                               my_qp->ipz_squeue.qe_size;
+                       my_qp->sq_map.map = vmalloc(my_qp->sq_map.entries *
+                                                   sizeof(struct ehca_qmap_entry));
+                       if (!my_qp->sq_map.map) {
+                               ehca_err(pd->device, "Couldn't allocate squeue "
+                                        "map ret=%i", ret);
+                               goto create_qp_exit3;
+                       }
+                       INIT_LIST_HEAD(&my_qp->sq_err_node);
+                       /* to avoid the generation of bogus flush CQEs */
+                       reset_queue_map(&my_qp->sq_map);
                }
-               INIT_LIST_HEAD(&my_qp->sq_err_node);
-               /* to avoid the generation of bogus flush CQEs */
-               reset_queue_map(&my_qp->sq_map);
        }
 
        if (HAS_RQ(my_qp)) {
@@ -792,20 +796,21 @@ static struct ehca_qp *internal_create_qp(
                                 "and pages ret=%i", ret);
                        goto create_qp_exit4;
                }
-
-               my_qp->rq_map.entries = my_qp->ipz_rqueue.queue_length /
-                       my_qp->ipz_rqueue.qe_size;
-               my_qp->rq_map.map = vmalloc(my_qp->rq_map.entries *
-                               sizeof(struct ehca_qmap_entry));
-               if (!my_qp->rq_map.map) {
-                       ehca_err(pd->device, "Couldn't allocate squeue "
-                                       "map ret=%i", ret);
-                       goto create_qp_exit5;
+               if (!is_user) {
+                       my_qp->rq_map.entries = my_qp->ipz_rqueue.queue_length /
+                               my_qp->ipz_rqueue.qe_size;
+                       my_qp->rq_map.map = vmalloc(my_qp->rq_map.entries *
+                                                   sizeof(struct ehca_qmap_entry));
+                       if (!my_qp->rq_map.map) {
+                               ehca_err(pd->device, "Couldn't allocate squeue "
+                                        "map ret=%i", ret);
+                               goto create_qp_exit5;
+                       }
+                       INIT_LIST_HEAD(&my_qp->rq_err_node);
+                       /* to avoid the generation of bogus flush CQEs */
+                       reset_queue_map(&my_qp->rq_map);
                }
-               INIT_LIST_HEAD(&my_qp->rq_err_node);
-               /* to avoid the generation of bogus flush CQEs */
-               reset_queue_map(&my_qp->rq_map);
-       } else if (init_attr->srq) {
+       } else if (init_attr->srq && !is_user) {
                /* this is a base QP, use the queue map of the SRQ */
                my_qp->rq_map = my_srq->rq_map;
                INIT_LIST_HEAD(&my_qp->rq_err_node);
@@ -918,7 +923,7 @@ create_qp_exit7:
        kfree(my_qp->mod_qp_parm);
 
 create_qp_exit6:
-       if (HAS_RQ(my_qp))
+       if (HAS_RQ(my_qp) && !is_user)
                vfree(my_qp->rq_map.map);
 
 create_qp_exit5:
@@ -926,7 +931,7 @@ create_qp_exit5:
                ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
 
 create_qp_exit4:
-       if (HAS_SQ(my_qp))
+       if (HAS_SQ(my_qp) && !is_user)
                vfree(my_qp->sq_map.map);
 
 create_qp_exit3:
@@ -1244,6 +1249,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
        u64 update_mask;
        u64 h_ret;
        int bad_wqe_cnt = 0;
+       int is_user = 0;
        int squeue_locked = 0;
        unsigned long flags = 0;
 
@@ -1266,6 +1272,8 @@ static int internal_modify_qp(struct ib_qp *ibqp,
                ret = ehca2ib_return_code(h_ret);
                goto modify_qp_exit1;
        }
+       if (ibqp->uobject)
+               is_user = 1;
 
        qp_cur_state = ehca2ib_qp_state(mqpcb->qp_state);
 
@@ -1728,7 +1736,8 @@ static int internal_modify_qp(struct ib_qp *ibqp,
                        goto modify_qp_exit2;
                }
        }
-       if ((qp_new_state == IB_QPS_ERR) && (qp_cur_state != IB_QPS_ERR)) {
+       if ((qp_new_state == IB_QPS_ERR) && (qp_cur_state != IB_QPS_ERR)
+           && !is_user) {
                ret = check_for_left_cqes(my_qp, shca);
                if (ret)
                        goto modify_qp_exit2;
@@ -1738,16 +1747,17 @@ static int internal_modify_qp(struct ib_qp *ibqp,
                ipz_qeit_reset(&my_qp->ipz_rqueue);
                ipz_qeit_reset(&my_qp->ipz_squeue);
 
-               if (qp_cur_state == IB_QPS_ERR) {
+               if (qp_cur_state == IB_QPS_ERR && !is_user) {
                        del_from_err_list(my_qp->send_cq, &my_qp->sq_err_node);
 
                        if (HAS_RQ(my_qp))
                                del_from_err_list(my_qp->recv_cq,
                                                  &my_qp->rq_err_node);
                }
-               reset_queue_map(&my_qp->sq_map);
+               if (!is_user)
+                       reset_queue_map(&my_qp->sq_map);
 
-               if (HAS_RQ(my_qp))
+               if (HAS_RQ(my_qp) && !is_user)
                        reset_queue_map(&my_qp->rq_map);
        }
 
@@ -1952,19 +1962,13 @@ int ehca_query_qp(struct ib_qp *qp,
        qp_attr->cap.max_inline_data = my_qp->sq_max_inline_data_size;
        qp_attr->dest_qp_num = qpcb->dest_qp_nr;
 
-       qp_attr->pkey_index =
-               EHCA_BMASK_GET(MQPCB_PRIM_P_KEY_IDX, qpcb->prim_p_key_idx);
-
-       qp_attr->port_num =
-               EHCA_BMASK_GET(MQPCB_PRIM_PHYS_PORT, qpcb->prim_phys_port);
-
+       qp_attr->pkey_index = qpcb->prim_p_key_idx;
+       qp_attr->port_num = qpcb->prim_phys_port;
        qp_attr->timeout = qpcb->timeout;
        qp_attr->retry_cnt = qpcb->retry_count;
        qp_attr->rnr_retry = qpcb->rnr_retry_count;
 
-       qp_attr->alt_pkey_index =
-               EHCA_BMASK_GET(MQPCB_PRIM_P_KEY_IDX, qpcb->alt_p_key_idx);
-
+       qp_attr->alt_pkey_index = qpcb->alt_p_key_idx;
        qp_attr->alt_port_num = qpcb->alt_phys_port;
        qp_attr->alt_timeout = qpcb->timeout_al;
 
@@ -2051,8 +2055,7 @@ int ehca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
                update_mask |=
                        EHCA_BMASK_SET(MQPCB_MASK_CURR_SRQ_LIMIT, 1)
                        | EHCA_BMASK_SET(MQPCB_MASK_QP_AFF_ASYN_EV_LOG_REG, 1);
-               mqpcb->curr_srq_limit =
-                       EHCA_BMASK_SET(MQPCB_CURR_SRQ_LIMIT, attr->srq_limit);
+               mqpcb->curr_srq_limit = attr->srq_limit;
                mqpcb->qp_aff_asyn_ev_log_reg =
                        EHCA_BMASK_SET(QPX_AAELOG_RESET_SRQ_LIMIT, 1);
        }
@@ -2115,8 +2118,7 @@ int ehca_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr)
 
        srq_attr->max_wr = qpcb->max_nr_outst_recv_wr - 1;
        srq_attr->max_sge = 3;
-       srq_attr->srq_limit = EHCA_BMASK_GET(
-               MQPCB_CURR_SRQ_LIMIT, qpcb->curr_srq_limit);
+       srq_attr->srq_limit = qpcb->curr_srq_limit;
 
        if (ehca_debug_level >= 2)
                ehca_dmp(qpcb, 4*70, "qp_num=%x", my_qp->real_qp_num);
@@ -2138,10 +2140,12 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
        int ret;
        u64 h_ret;
        u8 port_num;
+       int is_user = 0;
        enum ib_qp_type qp_type;
        unsigned long flags;
 
        if (uobject) {
+               is_user = 1;
                if (my_qp->mm_count_galpa ||
                    my_qp->mm_count_rqueue || my_qp->mm_count_squeue) {
                        ehca_err(dev, "Resources still referenced in "
@@ -2168,10 +2172,10 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
         * SRQs will never get into an error list and do not have a recv_cq,
         * so we need to skip them here.
         */
-       if (HAS_RQ(my_qp) && !IS_SRQ(my_qp))
+       if (HAS_RQ(my_qp) && !IS_SRQ(my_qp) && !is_user)
                del_from_err_list(my_qp->recv_cq, &my_qp->rq_err_node);
 
-       if (HAS_SQ(my_qp))
+       if (HAS_SQ(my_qp) && !is_user)
                del_from_err_list(my_qp->send_cq, &my_qp->sq_err_node);
 
        /* now wait until all pending events have completed */
@@ -2209,13 +2213,13 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
 
        if (HAS_RQ(my_qp)) {
                ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
-
-               vfree(my_qp->rq_map.map);
+               if (!is_user)
+                       vfree(my_qp->rq_map.map);
        }
        if (HAS_SQ(my_qp)) {
                ipz_queue_dtor(my_pd, &my_qp->ipz_squeue);
-
-               vfree(my_qp->sq_map.map);
+               if (!is_user)
+                       vfree(my_qp->sq_map.map);
        }
        kmem_cache_free(qp_cache, my_qp);
        atomic_dec(&shca->num_qps);
index d0ab0c0d5e91719dd4774de548f23c361c865650..4d5dc3304d427233c787f2b5c97b24cb5d9b8431 100644 (file)
@@ -284,7 +284,7 @@ u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle,
        param->act_pages = (u32)outs[4];
 
        if (ret == H_SUCCESS)
-               hcp_galpas_ctor(&cq->galpas, outs[5], outs[6]);
+               hcp_galpas_ctor(&cq->galpas, 0, outs[5], outs[6]);
 
        if (ret == H_NOT_ENOUGH_RESOURCES)
                ehca_gen_err("Not enough resources. ret=%lli", ret);
@@ -293,7 +293,7 @@ u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle,
 }
 
 u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle,
-                            struct ehca_alloc_qp_parms *parms)
+                            struct ehca_alloc_qp_parms *parms, int is_user)
 {
        u64 ret;
        u64 allocate_controls, max_r10_reg, r11, r12;
@@ -359,7 +359,7 @@ u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle,
                (u32)EHCA_BMASK_GET(H_ALL_RES_QP_RQUEUE_SIZE_PAGES, outs[4]);
 
        if (ret == H_SUCCESS)
-               hcp_galpas_ctor(&parms->galpas, outs[6], outs[6]);
+               hcp_galpas_ctor(&parms->galpas, is_user, outs[6], outs[6]);
 
        if (ret == H_NOT_ENOUGH_RESOURCES)
                ehca_gen_err("Not enough resources. ret=%lli", ret);
index 2c3c6e0ea5c267f542968d43c6faec51e40a9f7b..39c1c3618ec7ac8b9c5861919c7f423863b10eeb 100644 (file)
@@ -78,7 +78,7 @@ u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle,
  * initialize resources, create empty QPPTs (2 rings).
  */
 u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle,
-                            struct ehca_alloc_qp_parms *parms);
+                            struct ehca_alloc_qp_parms *parms, int is_user);
 
 u64 hipz_h_query_port(const struct ipz_adapter_handle adapter_handle,
                      const u8 port_id,
index 214821095cb15c2ff0793882877f9889a5052bd0..b3e0e72e8a736cea96f79fa068248a219878524d 100644 (file)
@@ -54,12 +54,15 @@ int hcall_unmap_page(u64 mapaddr)
        return 0;
 }
 
-int hcp_galpas_ctor(struct h_galpas *galpas,
+int hcp_galpas_ctor(struct h_galpas *galpas, int is_user,
                    u64 paddr_kernel, u64 paddr_user)
 {
-       int ret = hcall_map_page(paddr_kernel, &galpas->kernel.fw_handle);
-       if (ret)
-               return ret;
+       if (!is_user) {
+               int ret = hcall_map_page(paddr_kernel, &galpas->kernel.fw_handle);
+               if (ret)
+                       return ret;
+       } else
+               galpas->kernel.fw_handle = 0;
 
        galpas->user.fw_handle = paddr_user;
 
index 5305c2a3ed94adc81fe7dbe4a96239c715b4a21d..204227d5303a257a105222e8b88af82c9971e79e 100644 (file)
@@ -78,7 +78,7 @@ static inline void hipz_galpa_store(struct h_galpa galpa, u32 offset, u64 value)
        *(volatile u64 __force *)addr = value;
 }
 
-int hcp_galpas_ctor(struct h_galpas *galpas,
+int hcp_galpas_ctor(struct h_galpas *galpas, int is_user,
                    u64 paddr_kernel, u64 paddr_user);
 
 int hcp_galpas_dtor(struct h_galpas *galpas);
index c3a32846543127f67d740bb539aa265d3ab436f6..1227c593627a62b5a1e27a237a63175c4038dfe0 100644 (file)
@@ -220,10 +220,13 @@ int ipz_queue_ctor(struct ehca_pd *pd, struct ipz_queue *queue,
        queue->small_page = NULL;
 
        /* allocate queue page pointers */
-       queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *));
+       queue->queue_pages = kmalloc(nr_of_pages * sizeof(void *), GFP_KERNEL);
        if (!queue->queue_pages) {
-               ehca_gen_err("Couldn't allocate queue page list");
-               return 0;
+               queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *));
+               if (!queue->queue_pages) {
+                       ehca_gen_err("Couldn't allocate queue page list");
+                       return 0;
+               }
        }
        memset(queue->queue_pages, 0, nr_of_pages * sizeof(void *));
 
@@ -240,7 +243,10 @@ int ipz_queue_ctor(struct ehca_pd *pd, struct ipz_queue *queue,
 ipz_queue_ctor_exit0:
        ehca_gen_err("Couldn't alloc pages queue=%p "
                 "nr_of_pages=%x",  queue, nr_of_pages);
-       vfree(queue->queue_pages);
+       if (is_vmalloc_addr(queue->queue_pages))
+               vfree(queue->queue_pages);
+       else
+               kfree(queue->queue_pages);
 
        return 0;
 }
@@ -262,7 +268,10 @@ int ipz_queue_dtor(struct ehca_pd *pd, struct ipz_queue *queue)
                        free_page((unsigned long)queue->queue_pages[i]);
        }
 
-       vfree(queue->queue_pages);
+       if (is_vmalloc_addr(queue->queue_pages))
+               vfree(queue->queue_pages);
+       else
+               kfree(queue->queue_pages);
 
        return 1;
 }
index 20724aee76f4766d80a9884da1e98f38d924ed50..c4a02648c8afe78ce6553e95fcc0742ed499274b 100644 (file)
@@ -1585,12 +1585,16 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                                break;
 
                        case IB_WR_LOCAL_INV:
+                               ctrl->srcrb_flags |=
+                                       cpu_to_be32(MLX4_WQE_CTRL_STRONG_ORDER);
                                set_local_inv_seg(wqe, wr->ex.invalidate_rkey);
                                wqe  += sizeof (struct mlx4_wqe_local_inval_seg);
                                size += sizeof (struct mlx4_wqe_local_inval_seg) / 16;
                                break;
 
                        case IB_WR_FAST_REG_MR:
+                               ctrl->srcrb_flags |=
+                                       cpu_to_be32(MLX4_WQE_CTRL_STRONG_ORDER);
                                set_fmr_seg(wqe, wr);
                                wqe  += sizeof (struct mlx4_wqe_fmr_seg);
                                size += sizeof (struct mlx4_wqe_fmr_seg) / 16;
index 6d55f9d748f6730d3e990d18013ed45e138fc7c7..8c2ed994d5401cc7fa86844ee7e1eff2ab927c63 100644 (file)
@@ -1059,7 +1059,7 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
        MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_MTT_OFFSET);
        if (mthca_is_memfree(dev))
                dev_lim->reserved_mtts = ALIGN((1 << (field >> 4)) * sizeof(u64),
-                                              MTHCA_MTT_SEG_SIZE) / MTHCA_MTT_SEG_SIZE;
+                                              dev->limits.mtt_seg_size) / dev->limits.mtt_seg_size;
        else
                dev_lim->reserved_mtts = 1 << (field >> 4);
        MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_MRW_SZ_OFFSET);
index 252590116df559cac09002d94bd5f6ed795299ef..9ef611f6dd36d52f531198d0a61d7ec11dbe78fd 100644 (file)
@@ -159,6 +159,7 @@ struct mthca_limits {
        int      reserved_eqs;
        int      num_mpts;
        int      num_mtt_segs;
+       int      mtt_seg_size;
        int      fmr_reserved_mtts;
        int      reserved_mtts;
        int      reserved_mrws;
index 28f0e0c40d7dfa87c8668c6b8264e8a17859b240..90e4e450a12022d4186ca19f1c94c9e897e5c785 100644 (file)
@@ -641,9 +641,11 @@ static void mthca_free_irqs(struct mthca_dev *dev)
        if (dev->eq_table.have_irq)
                free_irq(dev->pdev->irq, dev);
        for (i = 0; i < MTHCA_NUM_EQ; ++i)
-               if (dev->eq_table.eq[i].have_irq)
+               if (dev->eq_table.eq[i].have_irq) {
                        free_irq(dev->eq_table.eq[i].msi_x_vector,
                                 dev->eq_table.eq + i);
+                       dev->eq_table.eq[i].have_irq = 0;
+               }
 }
 
 static int mthca_map_reg(struct mthca_dev *dev,
index 1d83cf7caf38a4893a1e23355092cf134bb83a61..13da9f1d24c0a2bf9d715f32701d0cb02406cba2 100644 (file)
@@ -125,6 +125,10 @@ module_param_named(fmr_reserved_mtts, hca_profile.fmr_reserved_mtts, int, 0444);
 MODULE_PARM_DESC(fmr_reserved_mtts,
                 "number of memory translation table segments reserved for FMR");
 
+static int log_mtts_per_seg = ilog2(MTHCA_MTT_SEG_SIZE / 8);
+module_param_named(log_mtts_per_seg, log_mtts_per_seg, int, 0444);
+MODULE_PARM_DESC(log_mtts_per_seg, "Log2 number of MTT entries per segment (1-5)");
+
 static char mthca_version[] __devinitdata =
        DRV_NAME ": Mellanox InfiniBand HCA driver v"
        DRV_VERSION " (" DRV_RELDATE ")\n";
@@ -162,6 +166,7 @@ static int mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim *dev_lim)
        int err;
        u8 status;
 
+       mdev->limits.mtt_seg_size = (1 << log_mtts_per_seg) * 8;
        err = mthca_QUERY_DEV_LIM(mdev, dev_lim, &status);
        if (err) {
                mthca_err(mdev, "QUERY_DEV_LIM command failed, aborting.\n");
@@ -460,11 +465,11 @@ static int mthca_init_icm(struct mthca_dev *mdev,
        }
 
        /* CPU writes to non-reserved MTTs, while HCA might DMA to reserved mtts */
-       mdev->limits.reserved_mtts = ALIGN(mdev->limits.reserved_mtts * MTHCA_MTT_SEG_SIZE,
-                                          dma_get_cache_alignment()) / MTHCA_MTT_SEG_SIZE;
+       mdev->limits.reserved_mtts = ALIGN(mdev->limits.reserved_mtts * mdev->limits.mtt_seg_size,
+                                          dma_get_cache_alignment()) / mdev->limits.mtt_seg_size;
 
        mdev->mr_table.mtt_table = mthca_alloc_icm_table(mdev, init_hca->mtt_base,
-                                                        MTHCA_MTT_SEG_SIZE,
+                                                        mdev->limits.mtt_seg_size,
                                                         mdev->limits.num_mtt_segs,
                                                         mdev->limits.reserved_mtts,
                                                         1, 0);
@@ -1315,6 +1320,12 @@ static void __init mthca_validate_profile(void)
                printk(KERN_WARNING PFX "Corrected fmr_reserved_mtts to %d.\n",
                       hca_profile.fmr_reserved_mtts);
        }
+
+       if ((log_mtts_per_seg < 1) || (log_mtts_per_seg > 5)) {
+               printk(KERN_WARNING PFX "bad log_mtts_per_seg (%d). Using default - %d\n",
+                      log_mtts_per_seg, ilog2(MTHCA_MTT_SEG_SIZE / 8));
+               log_mtts_per_seg = ilog2(MTHCA_MTT_SEG_SIZE / 8);
+       }
 }
 
 static int __init mthca_init(void)
index 882e6b73591591213f211928be33da0b58ef8901..d606edf108589059a75bee4150b960b6c2fea52e 100644 (file)
@@ -220,7 +220,7 @@ static struct mthca_mtt *__mthca_alloc_mtt(struct mthca_dev *dev, int size,
 
        mtt->buddy = buddy;
        mtt->order = 0;
-       for (i = MTHCA_MTT_SEG_SIZE / 8; i < size; i <<= 1)
+       for (i = dev->limits.mtt_seg_size / 8; i < size; i <<= 1)
                ++mtt->order;
 
        mtt->first_seg = mthca_alloc_mtt_range(dev, mtt->order, buddy);
@@ -267,7 +267,7 @@ static int __mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt,
 
        while (list_len > 0) {
                mtt_entry[0] = cpu_to_be64(dev->mr_table.mtt_base +
-                                          mtt->first_seg * MTHCA_MTT_SEG_SIZE +
+                                          mtt->first_seg * dev->limits.mtt_seg_size +
                                           start_index * 8);
                mtt_entry[1] = 0;
                for (i = 0; i < list_len && i < MTHCA_MAILBOX_SIZE / 8 - 2; ++i)
@@ -326,7 +326,7 @@ static void mthca_tavor_write_mtt_seg(struct mthca_dev *dev,
        u64 __iomem *mtts;
        int i;
 
-       mtts = dev->mr_table.tavor_fmr.mtt_base + mtt->first_seg * MTHCA_MTT_SEG_SIZE +
+       mtts = dev->mr_table.tavor_fmr.mtt_base + mtt->first_seg * dev->limits.mtt_seg_size +
                start_index * sizeof (u64);
        for (i = 0; i < list_len; ++i)
                mthca_write64_raw(cpu_to_be64(buffer_list[i] | MTHCA_MTT_FLAG_PRESENT),
@@ -345,10 +345,10 @@ static void mthca_arbel_write_mtt_seg(struct mthca_dev *dev,
        /* For Arbel, all MTTs must fit in the same page. */
        BUG_ON(s / PAGE_SIZE != (s + list_len * sizeof(u64) - 1) / PAGE_SIZE);
        /* Require full segments */
-       BUG_ON(s % MTHCA_MTT_SEG_SIZE);
+       BUG_ON(s % dev->limits.mtt_seg_size);
 
        mtts = mthca_table_find(dev->mr_table.mtt_table, mtt->first_seg +
-                               s / MTHCA_MTT_SEG_SIZE, &dma_handle);
+                               s / dev->limits.mtt_seg_size, &dma_handle);
 
        BUG_ON(!mtts);
 
@@ -479,7 +479,7 @@ int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift,
        if (mr->mtt)
                mpt_entry->mtt_seg =
                        cpu_to_be64(dev->mr_table.mtt_base +
-                                   mr->mtt->first_seg * MTHCA_MTT_SEG_SIZE);
+                                   mr->mtt->first_seg * dev->limits.mtt_seg_size);
 
        if (0) {
                mthca_dbg(dev, "Dumping MPT entry %08x:\n", mr->ibmr.lkey);
@@ -626,7 +626,7 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
                goto err_out_table;
        }
 
-       mtt_seg = mr->mtt->first_seg * MTHCA_MTT_SEG_SIZE;
+       mtt_seg = mr->mtt->first_seg * dev->limits.mtt_seg_size;
 
        if (mthca_is_memfree(dev)) {
                mr->mem.arbel.mtts = mthca_table_find(dev->mr_table.mtt_table,
@@ -908,7 +908,7 @@ int mthca_init_mr_table(struct mthca_dev *dev)
                         dev->mr_table.mtt_base);
 
                dev->mr_table.tavor_fmr.mtt_base =
-                       ioremap(addr, mtts * MTHCA_MTT_SEG_SIZE);
+                       ioremap(addr, mtts * dev->limits.mtt_seg_size);
                if (!dev->mr_table.tavor_fmr.mtt_base) {
                        mthca_warn(dev, "MTT ioremap for FMR failed.\n");
                        err = -ENOMEM;
index d168c254061191657e0f05b3e99bb3f423ba7fc8..8edb28a9a0e7593168f4b45d5ab9c4d3c1a8507c 100644 (file)
@@ -94,7 +94,7 @@ s64 mthca_make_profile(struct mthca_dev *dev,
        profile[MTHCA_RES_RDB].size  = MTHCA_RDB_ENTRY_SIZE;
        profile[MTHCA_RES_MCG].size  = MTHCA_MGM_ENTRY_SIZE;
        profile[MTHCA_RES_MPT].size  = dev_lim->mpt_entry_sz;
-       profile[MTHCA_RES_MTT].size  = MTHCA_MTT_SEG_SIZE;
+       profile[MTHCA_RES_MTT].size  = dev->limits.mtt_seg_size;
        profile[MTHCA_RES_UAR].size  = dev_lim->uar_scratch_entry_sz;
        profile[MTHCA_RES_UDAV].size = MTHCA_AV_SIZE;
        profile[MTHCA_RES_UARC].size = request->uarc_size;
@@ -232,7 +232,7 @@ s64 mthca_make_profile(struct mthca_dev *dev,
                        dev->limits.num_mtt_segs = profile[i].num;
                        dev->mr_table.mtt_base   = profile[i].start;
                        init_hca->mtt_base       = profile[i].start;
-                       init_hca->mtt_seg_sz     = ffs(MTHCA_MTT_SEG_SIZE) - 7;
+                       init_hca->mtt_seg_sz     = ffs(dev->limits.mtt_seg_size) - 7;
                        break;
                case MTHCA_RES_UAR:
                        dev->limits.num_uars       = profile[i].num;
index b832a7b814a243f87ae89f7fe104926ed9b8ccfd..4a84d02ece0637fcbd3da54aed4131e6fbb45c4b 100644 (file)
@@ -667,7 +667,7 @@ static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_
                i = 0;
                while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET) & 0x00000040) == 0) && i++ < 10000)
                        mdelay(1);
-               if (i >= 10000) {
+               if (i > 10000) {
                        nes_debug(NES_DBG_INIT, "Did not see full soft reset done.\n");
                        return 0;
                }
@@ -675,7 +675,7 @@ static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_
                i = 0;
                while ((nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS) != 0x80) && i++ < 10000)
                        mdelay(1);
-               if (i >= 10000) {
+               if (i > 10000) {
                        printk(KERN_ERR PFX "Internal CPU not ready, status = %02X\n",
                               nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS));
                        return 0;
@@ -701,7 +701,7 @@ static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_
        i = 0;
        while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET) & 0x00000040) == 0) && i++ < 10000)
                mdelay(1);
-       if (i >= 10000) {
+       if (i > 10000) {
                nes_debug(NES_DBG_INIT, "Did not see port soft reset done.\n");
                return 0;
        }
@@ -711,7 +711,7 @@ static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_
        while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0)
                        & 0x0000000f)) != 0x0000000f) && i++ < 5000)
                mdelay(1);
-       if (i >= 5000) {
+       if (i > 5000) {
                nes_debug(NES_DBG_INIT, "Serdes 0 not ready, status=%x\n", u32temp);
                return 0;
        }
@@ -722,7 +722,7 @@ static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_
                while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS1)
                                & 0x0000000f)) != 0x0000000f) && i++ < 5000)
                        mdelay(1);
-               if (i >= 5000) {
+               if (i > 5000) {
                        nes_debug(NES_DBG_INIT, "Serdes 1 not ready, status=%x\n", u32temp);
                        return 0;
                }
@@ -792,7 +792,7 @@ static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count,
                while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0)
                                & 0x0000000f)) != 0x0000000f) && i++ < 5000)
                        mdelay(1);
-               if (i >= 5000) {
+               if (i > 5000) {
                        nes_debug(NES_DBG_PHY, "Init: serdes 0 not ready, status=%x\n", u32temp);
                        return 1;
                }
@@ -815,7 +815,7 @@ static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count,
                        while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS1)
                                & 0x0000000f)) != 0x0000000f) && (i++ < 5000))
                                mdelay(1);
-                       if (i >= 5000) {
+                       if (i > 5000) {
                                printk("%s: Init: serdes 1 not ready, status=%x\n", __func__, u32temp);
                                /* return 1; */
                        }
index 75223f50de586fa9dc08c77f4f0ccec0a73a6020..0ba6ec87629616e946a64aedad68d86a3b6d4010 100644 (file)
@@ -257,11 +257,8 @@ static void iscsi_iser_cleanup_task(struct iscsi_task *task)
 {
        struct iscsi_iser_task *iser_task = task->dd_data;
 
-       /*
-        * mgmt tasks do not need special cleanup and we do not
-        * allocate anything in the init task callout
-        */
-       if (!task->sc || task->state == ISCSI_TASK_PENDING)
+       /* mgmt tasks do not need special cleanup */
+       if (!task->sc)
                return;
 
        if (iser_task->status == ISER_TASK_STATUS_STARTED) {
@@ -517,7 +514,8 @@ iscsi_iser_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *s
 }
 
 static struct iscsi_endpoint *
-iscsi_iser_ep_connect(struct sockaddr *dst_addr, int non_blocking)
+iscsi_iser_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
+                     int non_blocking)
 {
        int err;
        struct iser_conn *ib_conn;
index 5c0a631d145537b5d597899147d186550dfde3df..06f46fcc07721a3189599f2a85c171173d6886a2 100644 (file)
@@ -232,7 +232,7 @@ config INPUT_GPIO_ROTARY_ENCODER
        depends on GPIOLIB && GENERIC_GPIO
        help
          Say Y here to add support for rotary encoders connected to GPIO lines.
-         Check file:Documentation/incput/rotary_encoder.txt for more
+         Check file:Documentation/input/rotary-encoder.txt for more
          information.
 
          To compile this driver as a module, choose M here: the
index da3c3a5d26892a5f763e754697ef36a12416bb27..c4b3fbd1a80f667f20f56eb90f6b736ccce00ad2 100644 (file)
@@ -192,7 +192,7 @@ config SERIO_RAW
 
 config SERIO_XILINX_XPS_PS2
        tristate "Xilinx XPS PS/2 Controller Support"
-       depends on PPC
+       depends on PPC || MICROBLAZE
        help
          This driver supports XPS PS/2 IP from the Xilinx EDK on
          PowerPC platform.
index a28c06d686e12e280beaf73009c4afa839037880..89b394183a758ef86b29b8532216ff64cd1768f7 100644 (file)
@@ -135,7 +135,7 @@ static int amba_kmi_probe(struct amba_device *dev, struct amba_id *id)
        io->dev.parent  = &dev->dev;
 
        kmi->io         = io;
-       kmi->base       = ioremap(dev->res.start, KMI_SIZE);
+       kmi->base       = ioremap(dev->res.start, resource_size(&dev->res));
        if (!kmi->base) {
                ret = -ENOMEM;
                goto out;
index 7d97d54588d9425501c4805e3157c07158d6b67b..77e9fdda0597381741691709529c2006a994fc8c 100644 (file)
@@ -183,7 +183,7 @@ int cf_command(int drvid, int mode,
           (mode != 1) ? "" : " 0 ",
           (mode != 1) ? "" : fwd_nr);
  
-  retval = divert_if.ll_cmd(&cs->ics); /* excute command */
+  retval = divert_if.ll_cmd(&cs->ics); /* execute command */
 
   if (!retval)
    { cs->prev = NULL;
index 3083338716b262eb8a730ee4c5fbc4dd3f202e27..47dbfe298b43ab4002e591a4da7702daa982e6dc 100644 (file)
@@ -502,7 +502,7 @@ tone_off:
                        break;
                }
                dsp->cmx_delay = (*((int *)data)) << 3;
-                       /* miliseconds to samples */
+                       /* milliseconds to samples */
                if (dsp->cmx_delay >= (CMX_BUFF_HALF>>1))
                        /* clip to half of maximum usable buffer
                        (half of half buffer) */
index 1aa46a390a0dfa780ec13d25c76e61b9128394a0..173d104d9ff2a95f147f901aaea9ad98cbe2be49 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/string.h>
 #include <linux/ctype.h>
 #include <linux/leds.h>
+#include <linux/gpio.h>
+
 #include <mach/regs-gpio.h>
 #include <mach/hardware.h>
 #include <mach/h1940-latch.h>
index aa2e7ae0cdaeede5d97cc34e66dfe26e0e718194..aa7acf3b92248e44ead8cc8da59586b11ed255f6 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/leds.h>
+#include <linux/gpio.h>
 
 #include <mach/hardware.h>
 #include <mach/regs-gpio.h>
index a3d3cbab359a8b1ae9bea16ecf59b2caef0f3212..0aaa0597a6223779e758d45875af4fb17cc3956c 100644 (file)
@@ -1,6 +1,6 @@
 config LGUEST
        tristate "Linux hypervisor example code"
-       depends on X86_32 && EXPERIMENTAL && !X86_PAE && FUTEX
+       depends on X86_32 && EXPERIMENTAL && EVENTFD
        select HVC_DRIVER
        ---help---
          This is a very simple module which allows you to run
index 4845fb3cf74bd8911dc3a48b8370c722be688512..a6974e9b8ebff8c8676f297da0e32a1e3e6d0105 100644 (file)
@@ -95,7 +95,7 @@ static __init int map_switcher(void)
         * array of struct pages.  It increments that pointer, but we don't
         * care. */
        pagep = switcher_page;
-       err = map_vm_area(switcher_vma, PAGE_KERNEL, &pagep);
+       err = map_vm_area(switcher_vma, PAGE_KERNEL_EXEC, &pagep);
        if (err) {
                printk("lguest: map_vm_area failed: %i\n", err);
                goto free_vma;
@@ -188,6 +188,9 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user)
 {
        /* We stop running once the Guest is dead. */
        while (!cpu->lg->dead) {
+               unsigned int irq;
+               bool more;
+
                /* First we run any hypercalls the Guest wants done. */
                if (cpu->hcall)
                        do_hypercalls(cpu);
@@ -195,23 +198,23 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user)
                /* It's possible the Guest did a NOTIFY hypercall to the
                 * Launcher, in which case we return from the read() now. */
                if (cpu->pending_notify) {
-                       if (put_user(cpu->pending_notify, user))
-                               return -EFAULT;
-                       return sizeof(cpu->pending_notify);
+                       if (!send_notify_to_eventfd(cpu)) {
+                               if (put_user(cpu->pending_notify, user))
+                                       return -EFAULT;
+                               return sizeof(cpu->pending_notify);
+                       }
                }
 
                /* Check for signals */
                if (signal_pending(current))
                        return -ERESTARTSYS;
 
-               /* If Waker set break_out, return to Launcher. */
-               if (cpu->break_out)
-                       return -EAGAIN;
-
                /* Check if there are any interrupts which can be delivered now:
                 * if so, this sets up the hander to be executed when we next
                 * run the Guest. */
-               maybe_do_interrupt(cpu);
+               irq = interrupt_pending(cpu, &more);
+               if (irq < LGUEST_IRQS)
+                       try_deliver_interrupt(cpu, irq, more);
 
                /* All long-lived kernel loops need to check with this horrible
                 * thing called the freezer.  If the Host is trying to suspend,
@@ -224,10 +227,15 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user)
                        break;
 
                /* If the Guest asked to be stopped, we sleep.  The Guest's
-                * clock timer or LHREQ_BREAK from the Waker will wake us. */
+                * clock timer will wake us. */
                if (cpu->halted) {
                        set_current_state(TASK_INTERRUPTIBLE);
-                       schedule();
+                       /* Just before we sleep, make sure no interrupt snuck in
+                        * which we should be doing. */
+                       if (interrupt_pending(cpu, &more) < LGUEST_IRQS)
+                               set_current_state(TASK_RUNNING);
+                       else
+                               schedule();
                        continue;
                }
 
index 54d66f05fefa0a82af7c96a78432cf2a763d6530..c29ffa19cb74410e5b37ddc74bf19d4a45c5d9e7 100644 (file)
@@ -37,6 +37,10 @@ static void do_hcall(struct lg_cpu *cpu, struct hcall_args *args)
                /* This call does nothing, except by breaking out of the Guest
                 * it makes us process all the asynchronous hypercalls. */
                break;
+       case LHCALL_SEND_INTERRUPTS:
+               /* This call does nothing too, but by breaking out of the Guest
+                * it makes us process any pending interrupts. */
+               break;
        case LHCALL_LGUEST_INIT:
                /* You can't get here unless you're already initialized.  Don't
                 * do that. */
@@ -73,11 +77,21 @@ static void do_hcall(struct lg_cpu *cpu, struct hcall_args *args)
                guest_set_stack(cpu, args->arg1, args->arg2, args->arg3);
                break;
        case LHCALL_SET_PTE:
+#ifdef CONFIG_X86_PAE
+               guest_set_pte(cpu, args->arg1, args->arg2,
+                               __pte(args->arg3 | (u64)args->arg4 << 32));
+#else
                guest_set_pte(cpu, args->arg1, args->arg2, __pte(args->arg3));
+#endif
+               break;
+       case LHCALL_SET_PGD:
+               guest_set_pgd(cpu->lg, args->arg1, args->arg2);
                break;
+#ifdef CONFIG_X86_PAE
        case LHCALL_SET_PMD:
                guest_set_pmd(cpu->lg, args->arg1, args->arg2);
                break;
+#endif
        case LHCALL_SET_CLOCKEVENT:
                guest_set_clockevent(cpu, args->arg1);
                break;
index 6e99adbe1946e8810951460872fdd59d79985ebf..0e9067b0d5072194d3ee1d496335cd8222b4109d 100644 (file)
@@ -128,30 +128,39 @@ static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi,
 /*H:205
  * Virtual Interrupts.
  *
- * maybe_do_interrupt() gets called before every entry to the Guest, to see if
- * we should divert the Guest to running an interrupt handler. */
-void maybe_do_interrupt(struct lg_cpu *cpu)
+ * interrupt_pending() returns the first pending interrupt which isn't blocked
+ * by the Guest.  It is called before every entry to the Guest, and just before
+ * we go to sleep when the Guest has halted itself. */
+unsigned int interrupt_pending(struct lg_cpu *cpu, bool *more)
 {
        unsigned int irq;
        DECLARE_BITMAP(blk, LGUEST_IRQS);
-       struct desc_struct *idt;
 
        /* If the Guest hasn't even initialized yet, we can do nothing. */
        if (!cpu->lg->lguest_data)
-               return;
+               return LGUEST_IRQS;
 
        /* Take our "irqs_pending" array and remove any interrupts the Guest
         * wants blocked: the result ends up in "blk". */
        if (copy_from_user(&blk, cpu->lg->lguest_data->blocked_interrupts,
                           sizeof(blk)))
-               return;
+               return LGUEST_IRQS;
        bitmap_andnot(blk, cpu->irqs_pending, blk, LGUEST_IRQS);
 
        /* Find the first interrupt. */
        irq = find_first_bit(blk, LGUEST_IRQS);
-       /* None?  Nothing to do */
-       if (irq >= LGUEST_IRQS)
-               return;
+       *more = find_next_bit(blk, LGUEST_IRQS, irq+1);
+
+       return irq;
+}
+
+/* This actually diverts the Guest to running an interrupt handler, once an
+ * interrupt has been identified by interrupt_pending(). */
+void try_deliver_interrupt(struct lg_cpu *cpu, unsigned int irq, bool more)
+{
+       struct desc_struct *idt;
+
+       BUG_ON(irq >= LGUEST_IRQS);
 
        /* They may be in the middle of an iret, where they asked us never to
         * deliver interrupts. */
@@ -170,8 +179,12 @@ void maybe_do_interrupt(struct lg_cpu *cpu)
                u32 irq_enabled;
                if (get_user(irq_enabled, &cpu->lg->lguest_data->irq_enabled))
                        irq_enabled = 0;
-               if (!irq_enabled)
+               if (!irq_enabled) {
+                       /* Make sure they know an IRQ is pending. */
+                       put_user(X86_EFLAGS_IF,
+                                &cpu->lg->lguest_data->irq_pending);
                        return;
+               }
        }
 
        /* Look at the IDT entry the Guest gave us for this interrupt.  The
@@ -194,6 +207,25 @@ void maybe_do_interrupt(struct lg_cpu *cpu)
         * here is a compromise which means at least it gets updated every
         * timer interrupt. */
        write_timestamp(cpu);
+
+       /* If there are no other interrupts we want to deliver, clear
+        * the pending flag. */
+       if (!more)
+               put_user(0, &cpu->lg->lguest_data->irq_pending);
+}
+
+/* And this is the routine when we want to set an interrupt for the Guest. */
+void set_interrupt(struct lg_cpu *cpu, unsigned int irq)
+{
+       /* Next time the Guest runs, the core code will see if it can deliver
+        * this interrupt. */
+       set_bit(irq, cpu->irqs_pending);
+
+       /* Make sure it sees it; it might be asleep (eg. halted), or
+        * running the Guest right now, in which case kick_process()
+        * will knock it out. */
+       if (!wake_up_process(cpu->tsk))
+               kick_process(cpu->tsk);
 }
 /*:*/
 
@@ -510,10 +542,7 @@ static enum hrtimer_restart clockdev_fn(struct hrtimer *timer)
        struct lg_cpu *cpu = container_of(timer, struct lg_cpu, hrt);
 
        /* Remember the first interrupt is the timer interrupt. */
-       set_bit(0, cpu->irqs_pending);
-       /* If the Guest is actually stopped, we need to wake it up. */
-       if (cpu->halted)
-               wake_up_process(cpu->tsk);
+       set_interrupt(cpu, 0);
        return HRTIMER_NORESTART;
 }
 
index af92a176697f379f1f8c345ceb1db061e3ac73b2..d4e8979735cb002f9f97cf929a1b45a900f2ddc6 100644 (file)
@@ -49,7 +49,7 @@ struct lg_cpu {
        u32 cr2;
        int ts;
        u32 esp1;
-       u8 ss1;
+       u16 ss1;
 
        /* Bitmap of what has changed: see CHANGED_* above. */
        int changed;
@@ -71,9 +71,7 @@ struct lg_cpu {
        /* Virtual clock device */
        struct hrtimer hrt;
 
-       /* Do we need to stop what we're doing and return to userspace? */
-       int break_out;
-       wait_queue_head_t break_wq;
+       /* Did the Guest tell us to halt? */
        int halted;
 
        /* Pending virtual interrupts */
@@ -82,6 +80,16 @@ struct lg_cpu {
        struct lg_cpu_arch arch;
 };
 
+struct lg_eventfd {
+       unsigned long addr;
+       struct file *event;
+};
+
+struct lg_eventfd_map {
+       unsigned int num;
+       struct lg_eventfd map[];
+};
+
 /* The private info the thread maintains about the guest. */
 struct lguest
 {
@@ -102,6 +110,8 @@ struct lguest
        unsigned int stack_pages;
        u32 tsc_khz;
 
+       struct lg_eventfd_map *eventfds;
+
        /* Dead? */
        const char *dead;
 };
@@ -137,9 +147,13 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user);
  * in the kernel. */
 #define pgd_flags(x)   (pgd_val(x) & ~PAGE_MASK)
 #define pgd_pfn(x)     (pgd_val(x) >> PAGE_SHIFT)
+#define pmd_flags(x)    (pmd_val(x) & ~PAGE_MASK)
+#define pmd_pfn(x)     (pmd_val(x) >> PAGE_SHIFT)
 
 /* interrupts_and_traps.c: */
-void maybe_do_interrupt(struct lg_cpu *cpu);
+unsigned int interrupt_pending(struct lg_cpu *cpu, bool *more);
+void try_deliver_interrupt(struct lg_cpu *cpu, unsigned int irq, bool more);
+void set_interrupt(struct lg_cpu *cpu, unsigned int irq);
 bool deliver_trap(struct lg_cpu *cpu, unsigned int num);
 void load_guest_idt_entry(struct lg_cpu *cpu, unsigned int i,
                          u32 low, u32 hi);
@@ -150,6 +164,7 @@ void setup_default_idt_entries(struct lguest_ro_state *state,
 void copy_traps(const struct lg_cpu *cpu, struct desc_struct *idt,
                const unsigned long *def);
 void guest_set_clockevent(struct lg_cpu *cpu, unsigned long delta);
+bool send_notify_to_eventfd(struct lg_cpu *cpu);
 void init_clockdev(struct lg_cpu *cpu);
 bool check_syscall_vector(struct lguest *lg);
 int init_interrupts(void);
@@ -168,7 +183,10 @@ void copy_gdt_tls(const struct lg_cpu *cpu, struct desc_struct *gdt);
 int init_guest_pagetable(struct lguest *lg);
 void free_guest_pagetable(struct lguest *lg);
 void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable);
+void guest_set_pgd(struct lguest *lg, unsigned long gpgdir, u32 i);
+#ifdef CONFIG_X86_PAE
 void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 i);
+#endif
 void guest_pagetable_clear_all(struct lg_cpu *cpu);
 void guest_pagetable_flush_user(struct lg_cpu *cpu);
 void guest_set_pte(struct lg_cpu *cpu, unsigned long gpgdir,
index df44d962626d327ba26a3b1a2aa83a2bba383390..e082cdac88b4bb283f41ebb611671d583ca78ecb 100644 (file)
@@ -228,7 +228,8 @@ extern void lguest_setup_irq(unsigned int irq);
  * function. */
 static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
                                    unsigned index,
-                                   void (*callback)(struct virtqueue *vq))
+                                   void (*callback)(struct virtqueue *vq),
+                                   const char *name)
 {
        struct lguest_device *ldev = to_lgdev(vdev);
        struct lguest_vq_info *lvq;
@@ -263,7 +264,7 @@ static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
        /* OK, tell virtio_ring.c to set up a virtqueue now we know its size
         * and we've got a pointer to its pages. */
        vq = vring_new_virtqueue(lvq->config.num, LGUEST_VRING_ALIGN,
-                                vdev, lvq->pages, lg_notify, callback);
+                                vdev, lvq->pages, lg_notify, callback, name);
        if (!vq) {
                err = -ENOMEM;
                goto unmap;
@@ -312,6 +313,38 @@ static void lg_del_vq(struct virtqueue *vq)
        kfree(lvq);
 }
 
+static void lg_del_vqs(struct virtio_device *vdev)
+{
+       struct virtqueue *vq, *n;
+
+       list_for_each_entry_safe(vq, n, &vdev->vqs, list)
+               lg_del_vq(vq);
+}
+
+static int lg_find_vqs(struct virtio_device *vdev, unsigned nvqs,
+                      struct virtqueue *vqs[],
+                      vq_callback_t *callbacks[],
+                      const char *names[])
+{
+       struct lguest_device *ldev = to_lgdev(vdev);
+       int i;
+
+       /* We must have this many virtqueues. */
+       if (nvqs > ldev->desc->num_vq)
+               return -ENOENT;
+
+       for (i = 0; i < nvqs; ++i) {
+               vqs[i] = lg_find_vq(vdev, i, callbacks[i], names[i]);
+               if (IS_ERR(vqs[i]))
+                       goto error;
+       }
+       return 0;
+
+error:
+       lg_del_vqs(vdev);
+       return PTR_ERR(vqs[i]);
+}
+
 /* The ops structure which hooks everything together. */
 static struct virtio_config_ops lguest_config_ops = {
        .get_features = lg_get_features,
@@ -321,8 +354,8 @@ static struct virtio_config_ops lguest_config_ops = {
        .get_status = lg_get_status,
        .set_status = lg_set_status,
        .reset = lg_reset,
-       .find_vq = lg_find_vq,
-       .del_vq = lg_del_vq,
+       .find_vqs = lg_find_vqs,
+       .del_vqs = lg_del_vqs,
 };
 
 /* The root device for the lguest virtio devices.  This makes them appear as
index b8ee103eed5f503e44ad5ebb27aab75e81ba5bec..32e297121058a3d7dc52fbd6d347eab496c08252 100644 (file)
@@ -7,32 +7,83 @@
 #include <linux/miscdevice.h>
 #include <linux/fs.h>
 #include <linux/sched.h>
+#include <linux/eventfd.h>
+#include <linux/file.h>
 #include "lg.h"
 
-/*L:055 When something happens, the Waker process needs a way to stop the
- * kernel running the Guest and return to the Launcher.  So the Waker writes
- * LHREQ_BREAK and the value "1" to /dev/lguest to do this.  Once the Launcher
- * has done whatever needs attention, it writes LHREQ_BREAK and "0" to release
- * the Waker. */
-static int break_guest_out(struct lg_cpu *cpu, const unsigned long __user*input)
+bool send_notify_to_eventfd(struct lg_cpu *cpu)
 {
-       unsigned long on;
+       unsigned int i;
+       struct lg_eventfd_map *map;
+
+       /* lg->eventfds is RCU-protected */
+       rcu_read_lock();
+       map = rcu_dereference(cpu->lg->eventfds);
+       for (i = 0; i < map->num; i++) {
+               if (map->map[i].addr == cpu->pending_notify) {
+                       eventfd_signal(map->map[i].event, 1);
+                       cpu->pending_notify = 0;
+                       break;
+               }
+       }
+       rcu_read_unlock();
+       return cpu->pending_notify == 0;
+}
 
-       /* Fetch whether they're turning break on or off. */
-       if (get_user(on, input) != 0)
-               return -EFAULT;
+static int add_eventfd(struct lguest *lg, unsigned long addr, int fd)
+{
+       struct lg_eventfd_map *new, *old = lg->eventfds;
 
-       if (on) {
-               cpu->break_out = 1;
-               /* Pop it out of the Guest (may be running on different CPU) */
-               wake_up_process(cpu->tsk);
-               /* Wait for them to reset it */
-               return wait_event_interruptible(cpu->break_wq, !cpu->break_out);
-       } else {
-               cpu->break_out = 0;
-               wake_up(&cpu->break_wq);
-               return 0;
+       if (!addr)
+               return -EINVAL;
+
+       /* Replace the old array with the new one, carefully: others can
+        * be accessing it at the same time */
+       new = kmalloc(sizeof(*new) + sizeof(new->map[0]) * (old->num + 1),
+                     GFP_KERNEL);
+       if (!new)
+               return -ENOMEM;
+
+       /* First make identical copy. */
+       memcpy(new->map, old->map, sizeof(old->map[0]) * old->num);
+       new->num = old->num;
+
+       /* Now append new entry. */
+       new->map[new->num].addr = addr;
+       new->map[new->num].event = eventfd_fget(fd);
+       if (IS_ERR(new->map[new->num].event)) {
+               kfree(new);
+               return PTR_ERR(new->map[new->num].event);
        }
+       new->num++;
+
+       /* Now put new one in place. */
+       rcu_assign_pointer(lg->eventfds, new);
+
+       /* We're not in a big hurry.  Wait until noone's looking at old
+        * version, then delete it. */
+       synchronize_rcu();
+       kfree(old);
+
+       return 0;
+}
+
+static int attach_eventfd(struct lguest *lg, const unsigned long __user *input)
+{
+       unsigned long addr, fd;
+       int err;
+
+       if (get_user(addr, input) != 0)
+               return -EFAULT;
+       input++;
+       if (get_user(fd, input) != 0)
+               return -EFAULT;
+
+       mutex_lock(&lguest_lock);
+       err = add_eventfd(lg, addr, fd);
+       mutex_unlock(&lguest_lock);
+
+       return 0;
 }
 
 /*L:050 Sending an interrupt is done by writing LHREQ_IRQ and an interrupt
@@ -45,9 +96,8 @@ static int user_send_irq(struct lg_cpu *cpu, const unsigned long __user *input)
                return -EFAULT;
        if (irq >= LGUEST_IRQS)
                return -EINVAL;
-       /* Next time the Guest runs, the core code will see if it can deliver
-        * this interrupt. */
-       set_bit(irq, cpu->irqs_pending);
+
+       set_interrupt(cpu, irq);
        return 0;
 }
 
@@ -126,9 +176,6 @@ static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip)
         * address. */
        lguest_arch_setup_regs(cpu, start_ip);
 
-       /* Initialize the queue for the Waker to wait on */
-       init_waitqueue_head(&cpu->break_wq);
-
        /* We keep a pointer to the Launcher task (ie. current task) for when
         * other Guests want to wake this one (eg. console input). */
        cpu->tsk = current;
@@ -185,6 +232,13 @@ static int initialize(struct file *file, const unsigned long __user *input)
                goto unlock;
        }
 
+       lg->eventfds = kmalloc(sizeof(*lg->eventfds), GFP_KERNEL);
+       if (!lg->eventfds) {
+               err = -ENOMEM;
+               goto free_lg;
+       }
+       lg->eventfds->num = 0;
+
        /* Populate the easy fields of our "struct lguest" */
        lg->mem_base = (void __user *)args[0];
        lg->pfn_limit = args[1];
@@ -192,7 +246,7 @@ static int initialize(struct file *file, const unsigned long __user *input)
        /* This is the first cpu (cpu 0) and it will start booting at args[2] */
        err = lg_cpu_start(&lg->cpus[0], 0, args[2]);
        if (err)
-               goto release_guest;
+               goto free_eventfds;
 
        /* Initialize the Guest's shadow page tables, using the toplevel
         * address the Launcher gave us.  This allocates memory, so can fail. */
@@ -211,7 +265,9 @@ static int initialize(struct file *file, const unsigned long __user *input)
 free_regs:
        /* FIXME: This should be in free_vcpu */
        free_page(lg->cpus[0].regs_page);
-release_guest:
+free_eventfds:
+       kfree(lg->eventfds);
+free_lg:
        kfree(lg);
 unlock:
        mutex_unlock(&lguest_lock);
@@ -252,11 +308,6 @@ static ssize_t write(struct file *file, const char __user *in,
                /* Once the Guest is dead, you can only read() why it died. */
                if (lg->dead)
                        return -ENOENT;
-
-               /* If you're not the task which owns the Guest, all you can do
-                * is break the Launcher out of running the Guest. */
-               if (current != cpu->tsk && req != LHREQ_BREAK)
-                       return -EPERM;
        }
 
        switch (req) {
@@ -264,8 +315,8 @@ static ssize_t write(struct file *file, const char __user *in,
                return initialize(file, input);
        case LHREQ_IRQ:
                return user_send_irq(cpu, input);
-       case LHREQ_BREAK:
-               return break_guest_out(cpu, input);
+       case LHREQ_EVENTFD:
+               return attach_eventfd(lg, input);
        default:
                return -EINVAL;
        }
@@ -303,6 +354,12 @@ static int close(struct inode *inode, struct file *file)
                 * the Launcher's memory management structure. */
                mmput(lg->cpus[i].mm);
        }
+
+       /* Release any eventfds they registered. */
+       for (i = 0; i < lg->eventfds->num; i++)
+               fput(lg->eventfds->map[i].event);
+       kfree(lg->eventfds);
+
        /* If lg->dead doesn't contain an error code it will be NULL or a
         * kmalloc()ed string, either of which is ok to hand to kfree(). */
        if (!IS_ERR(lg->dead))
index a059cf9980f711b97d2009545b574e63cf79fddc..a6fe1abda24002d623d74a7914f23b55ad708b4e 100644 (file)
  * page.  */
 #define SWITCHER_PGD_INDEX (PTRS_PER_PGD - 1)
 
+/* For PAE we need the PMD index as well. We use the last 2MB, so we
+ * will need the last pmd entry of the last pmd page.  */
+#ifdef CONFIG_X86_PAE
+#define SWITCHER_PMD_INDEX     (PTRS_PER_PMD - 1)
+#define RESERVE_MEM            2U
+#define CHECK_GPGD_MASK                _PAGE_PRESENT
+#else
+#define RESERVE_MEM            4U
+#define CHECK_GPGD_MASK                _PAGE_TABLE
+#endif
+
 /* We actually need a separate PTE page for each CPU.  Remember that after the
  * Switcher code itself comes two pages for each CPU, and we don't want this
  * CPU's guest to see the pages of any other CPU. */
@@ -73,24 +84,59 @@ static pgd_t *spgd_addr(struct lg_cpu *cpu, u32 i, unsigned long vaddr)
 {
        unsigned int index = pgd_index(vaddr);
 
+#ifndef CONFIG_X86_PAE
        /* We kill any Guest trying to touch the Switcher addresses. */
        if (index >= SWITCHER_PGD_INDEX) {
                kill_guest(cpu, "attempt to access switcher pages");
                index = 0;
        }
+#endif
        /* Return a pointer index'th pgd entry for the i'th page table. */
        return &cpu->lg->pgdirs[i].pgdir[index];
 }
 
+#ifdef CONFIG_X86_PAE
+/* This routine then takes the PGD entry given above, which contains the
+ * address of the PMD page.  It then returns a pointer to the PMD entry for the
+ * given address. */
+static pmd_t *spmd_addr(struct lg_cpu *cpu, pgd_t spgd, unsigned long vaddr)
+{
+       unsigned int index = pmd_index(vaddr);
+       pmd_t *page;
+
+       /* We kill any Guest trying to touch the Switcher addresses. */
+       if (pgd_index(vaddr) == SWITCHER_PGD_INDEX &&
+                                       index >= SWITCHER_PMD_INDEX) {
+               kill_guest(cpu, "attempt to access switcher pages");
+               index = 0;
+       }
+
+       /* You should never call this if the PGD entry wasn't valid */
+       BUG_ON(!(pgd_flags(spgd) & _PAGE_PRESENT));
+       page = __va(pgd_pfn(spgd) << PAGE_SHIFT);
+
+       return &page[index];
+}
+#endif
+
 /* This routine then takes the page directory entry returned above, which
  * contains the address of the page table entry (PTE) page.  It then returns a
  * pointer to the PTE entry for the given address. */
-static pte_t *spte_addr(pgd_t spgd, unsigned long vaddr)
+static pte_t *spte_addr(struct lg_cpu *cpu, pgd_t spgd, unsigned long vaddr)
 {
+#ifdef CONFIG_X86_PAE
+       pmd_t *pmd = spmd_addr(cpu, spgd, vaddr);
+       pte_t *page = __va(pmd_pfn(*pmd) << PAGE_SHIFT);
+
+       /* You should never call this if the PMD entry wasn't valid */
+       BUG_ON(!(pmd_flags(*pmd) & _PAGE_PRESENT));
+#else
        pte_t *page = __va(pgd_pfn(spgd) << PAGE_SHIFT);
        /* You should never call this if the PGD entry wasn't valid */
        BUG_ON(!(pgd_flags(spgd) & _PAGE_PRESENT));
-       return &page[(vaddr >> PAGE_SHIFT) % PTRS_PER_PTE];
+#endif
+
+       return &page[pte_index(vaddr)];
 }
 
 /* These two functions just like the above two, except they access the Guest
@@ -101,12 +147,32 @@ static unsigned long gpgd_addr(struct lg_cpu *cpu, unsigned long vaddr)
        return cpu->lg->pgdirs[cpu->cpu_pgd].gpgdir + index * sizeof(pgd_t);
 }
 
-static unsigned long gpte_addr(pgd_t gpgd, unsigned long vaddr)
+#ifdef CONFIG_X86_PAE
+static unsigned long gpmd_addr(pgd_t gpgd, unsigned long vaddr)
+{
+       unsigned long gpage = pgd_pfn(gpgd) << PAGE_SHIFT;
+       BUG_ON(!(pgd_flags(gpgd) & _PAGE_PRESENT));
+       return gpage + pmd_index(vaddr) * sizeof(pmd_t);
+}
+
+static unsigned long gpte_addr(struct lg_cpu *cpu,
+                              pmd_t gpmd, unsigned long vaddr)
+{
+       unsigned long gpage = pmd_pfn(gpmd) << PAGE_SHIFT;
+
+       BUG_ON(!(pmd_flags(gpmd) & _PAGE_PRESENT));
+       return gpage + pte_index(vaddr) * sizeof(pte_t);
+}
+#else
+static unsigned long gpte_addr(struct lg_cpu *cpu,
+                               pgd_t gpgd, unsigned long vaddr)
 {
        unsigned long gpage = pgd_pfn(gpgd) << PAGE_SHIFT;
+
        BUG_ON(!(pgd_flags(gpgd) & _PAGE_PRESENT));
-       return gpage + ((vaddr>>PAGE_SHIFT) % PTRS_PER_PTE) * sizeof(pte_t);
+       return gpage + pte_index(vaddr) * sizeof(pte_t);
 }
+#endif
 /*:*/
 
 /*M:014 get_pfn is slow: we could probably try to grab batches of pages here as
@@ -171,7 +237,7 @@ static void release_pte(pte_t pte)
        /* Remember that get_user_pages_fast() took a reference to the page, in
         * get_pfn()?  We have to put it back now. */
        if (pte_flags(pte) & _PAGE_PRESENT)
-               put_page(pfn_to_page(pte_pfn(pte)));
+               put_page(pte_page(pte));
 }
 /*:*/
 
@@ -184,11 +250,20 @@ static void check_gpte(struct lg_cpu *cpu, pte_t gpte)
 
 static void check_gpgd(struct lg_cpu *cpu, pgd_t gpgd)
 {
-       if ((pgd_flags(gpgd) & ~_PAGE_TABLE) ||
+       if ((pgd_flags(gpgd) & ~CHECK_GPGD_MASK) ||
           (pgd_pfn(gpgd) >= cpu->lg->pfn_limit))
                kill_guest(cpu, "bad page directory entry");
 }
 
+#ifdef CONFIG_X86_PAE
+static void check_gpmd(struct lg_cpu *cpu, pmd_t gpmd)
+{
+       if ((pmd_flags(gpmd) & ~_PAGE_TABLE) ||
+          (pmd_pfn(gpmd) >= cpu->lg->pfn_limit))
+               kill_guest(cpu, "bad page middle directory entry");
+}
+#endif
+
 /*H:330
  * (i) Looking up a page table entry when the Guest faults.
  *
@@ -207,6 +282,11 @@ bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
        pte_t gpte;
        pte_t *spte;
 
+#ifdef CONFIG_X86_PAE
+       pmd_t *spmd;
+       pmd_t gpmd;
+#endif
+
        /* First step: get the top-level Guest page table entry. */
        gpgd = lgread(cpu, gpgd_addr(cpu, vaddr), pgd_t);
        /* Toplevel not present?  We can't map it in. */
@@ -228,12 +308,45 @@ bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
                check_gpgd(cpu, gpgd);
                /* And we copy the flags to the shadow PGD entry.  The page
                 * number in the shadow PGD is the page we just allocated. */
-               *spgd = __pgd(__pa(ptepage) | pgd_flags(gpgd));
+               set_pgd(spgd, __pgd(__pa(ptepage) | pgd_flags(gpgd)));
        }
 
+#ifdef CONFIG_X86_PAE
+       gpmd = lgread(cpu, gpmd_addr(gpgd, vaddr), pmd_t);
+       /* middle level not present?  We can't map it in. */
+       if (!(pmd_flags(gpmd) & _PAGE_PRESENT))
+               return false;
+
+       /* Now look at the matching shadow entry. */
+       spmd = spmd_addr(cpu, *spgd, vaddr);
+
+       if (!(pmd_flags(*spmd) & _PAGE_PRESENT)) {
+               /* No shadow entry: allocate a new shadow PTE page. */
+               unsigned long ptepage = get_zeroed_page(GFP_KERNEL);
+
+               /* This is not really the Guest's fault, but killing it is
+               * simple for this corner case. */
+               if (!ptepage) {
+                       kill_guest(cpu, "out of memory allocating pte page");
+                       return false;
+               }
+
+               /* We check that the Guest pmd is OK. */
+               check_gpmd(cpu, gpmd);
+
+               /* And we copy the flags to the shadow PMD entry.  The page
+                * number in the shadow PMD is the page we just allocated. */
+               native_set_pmd(spmd, __pmd(__pa(ptepage) | pmd_flags(gpmd)));
+       }
+
+       /* OK, now we look at the lower level in the Guest page table: keep its
+        * address, because we might update it later. */
+       gpte_ptr = gpte_addr(cpu, gpmd, vaddr);
+#else
        /* OK, now we look at the lower level in the Guest page table: keep its
         * address, because we might update it later. */
-       gpte_ptr = gpte_addr(gpgd, vaddr);
+       gpte_ptr = gpte_addr(cpu, gpgd, vaddr);
+#endif
        gpte = lgread(cpu, gpte_ptr, pte_t);
 
        /* If this page isn't in the Guest page tables, we can't page it in. */
@@ -259,7 +372,7 @@ bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
                gpte = pte_mkdirty(gpte);
 
        /* Get the pointer to the shadow PTE entry we're going to set. */
-       spte = spte_addr(*spgd, vaddr);
+       spte = spte_addr(cpu, *spgd, vaddr);
        /* If there was a valid shadow PTE entry here before, we release it.
         * This can happen with a write to a previously read-only entry. */
        release_pte(*spte);
@@ -273,7 +386,7 @@ bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
                 * table entry, even if the Guest says it's writable.  That way
                 * we will come back here when a write does actually occur, so
                 * we can update the Guest's _PAGE_DIRTY flag. */
-               *spte = gpte_to_spte(cpu, pte_wrprotect(gpte), 0);
+               native_set_pte(spte, gpte_to_spte(cpu, pte_wrprotect(gpte), 0));
 
        /* Finally, we write the Guest PTE entry back: we've set the
         * _PAGE_ACCESSED and maybe the _PAGE_DIRTY flags. */
@@ -301,14 +414,23 @@ static bool page_writable(struct lg_cpu *cpu, unsigned long vaddr)
        pgd_t *spgd;
        unsigned long flags;
 
+#ifdef CONFIG_X86_PAE
+       pmd_t *spmd;
+#endif
        /* Look at the current top level entry: is it present? */
        spgd = spgd_addr(cpu, cpu->cpu_pgd, vaddr);
        if (!(pgd_flags(*spgd) & _PAGE_PRESENT))
                return false;
 
+#ifdef CONFIG_X86_PAE
+       spmd = spmd_addr(cpu, *spgd, vaddr);
+       if (!(pmd_flags(*spmd) & _PAGE_PRESENT))
+               return false;
+#endif
+
        /* Check the flags on the pte entry itself: it must be present and
         * writable. */
-       flags = pte_flags(*(spte_addr(*spgd, vaddr)));
+       flags = pte_flags(*(spte_addr(cpu, *spgd, vaddr)));
 
        return (flags & (_PAGE_PRESENT|_PAGE_RW)) == (_PAGE_PRESENT|_PAGE_RW);
 }
@@ -322,8 +444,43 @@ void pin_page(struct lg_cpu *cpu, unsigned long vaddr)
                kill_guest(cpu, "bad stack page %#lx", vaddr);
 }
 
+#ifdef CONFIG_X86_PAE
+static void release_pmd(pmd_t *spmd)
+{
+       /* If the entry's not present, there's nothing to release. */
+       if (pmd_flags(*spmd) & _PAGE_PRESENT) {
+               unsigned int i;
+               pte_t *ptepage = __va(pmd_pfn(*spmd) << PAGE_SHIFT);
+               /* For each entry in the page, we might need to release it. */
+               for (i = 0; i < PTRS_PER_PTE; i++)
+                       release_pte(ptepage[i]);
+               /* Now we can free the page of PTEs */
+               free_page((long)ptepage);
+               /* And zero out the PMD entry so we never release it twice. */
+               native_set_pmd(spmd, __pmd(0));
+       }
+}
+
+static void release_pgd(pgd_t *spgd)
+{
+       /* If the entry's not present, there's nothing to release. */
+       if (pgd_flags(*spgd) & _PAGE_PRESENT) {
+               unsigned int i;
+               pmd_t *pmdpage = __va(pgd_pfn(*spgd) << PAGE_SHIFT);
+
+               for (i = 0; i < PTRS_PER_PMD; i++)
+                       release_pmd(&pmdpage[i]);
+
+               /* Now we can free the page of PMDs */
+               free_page((long)pmdpage);
+               /* And zero out the PGD entry so we never release it twice. */
+               set_pgd(spgd, __pgd(0));
+       }
+}
+
+#else /* !CONFIG_X86_PAE */
 /*H:450 If we chase down the release_pgd() code, it looks like this: */
-static void release_pgd(struct lguest *lg, pgd_t *spgd)
+static void release_pgd(pgd_t *spgd)
 {
        /* If the entry's not present, there's nothing to release. */
        if (pgd_flags(*spgd) & _PAGE_PRESENT) {
@@ -341,7 +498,7 @@ static void release_pgd(struct lguest *lg, pgd_t *spgd)
                *spgd = __pgd(0);
        }
 }
-
+#endif
 /*H:445 We saw flush_user_mappings() twice: once from the flush_user_mappings()
  * hypercall and once in new_pgdir() when we re-used a top-level pgdir page.
  * It simply releases every PTE page from 0 up to the Guest's kernel address. */
@@ -350,7 +507,7 @@ static void flush_user_mappings(struct lguest *lg, int idx)
        unsigned int i;
        /* Release every pgd entry up to the kernel's address. */
        for (i = 0; i < pgd_index(lg->kernel_address); i++)
-               release_pgd(lg, lg->pgdirs[idx].pgdir + i);
+               release_pgd(lg->pgdirs[idx].pgdir + i);
 }
 
 /*H:440 (v) Flushing (throwing away) page tables,
@@ -369,7 +526,9 @@ unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr)
 {
        pgd_t gpgd;
        pte_t gpte;
-
+#ifdef CONFIG_X86_PAE
+       pmd_t gpmd;
+#endif
        /* First step: get the top-level Guest page table entry. */
        gpgd = lgread(cpu, gpgd_addr(cpu, vaddr), pgd_t);
        /* Toplevel not present?  We can't map it in. */
@@ -378,7 +537,14 @@ unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr)
                return -1UL;
        }
 
-       gpte = lgread(cpu, gpte_addr(gpgd, vaddr), pte_t);
+#ifdef CONFIG_X86_PAE
+       gpmd = lgread(cpu, gpmd_addr(gpgd, vaddr), pmd_t);
+       if (!(pmd_flags(gpmd) & _PAGE_PRESENT))
+               kill_guest(cpu, "Bad address %#lx", vaddr);
+       gpte = lgread(cpu, gpte_addr(cpu, gpmd, vaddr), pte_t);
+#else
+       gpte = lgread(cpu, gpte_addr(cpu, gpgd, vaddr), pte_t);
+#endif
        if (!(pte_flags(gpte) & _PAGE_PRESENT))
                kill_guest(cpu, "Bad address %#lx", vaddr);
 
@@ -405,6 +571,9 @@ static unsigned int new_pgdir(struct lg_cpu *cpu,
                              int *blank_pgdir)
 {
        unsigned int next;
+#ifdef CONFIG_X86_PAE
+       pmd_t *pmd_table;
+#endif
 
        /* We pick one entry at random to throw out.  Choosing the Least
         * Recently Used might be better, but this is easy. */
@@ -416,10 +585,27 @@ static unsigned int new_pgdir(struct lg_cpu *cpu,
                /* If the allocation fails, just keep using the one we have */
                if (!cpu->lg->pgdirs[next].pgdir)
                        next = cpu->cpu_pgd;
-               else
-                       /* This is a blank page, so there are no kernel
-                        * mappings: caller must map the stack! */
+               else {
+#ifdef CONFIG_X86_PAE
+                       /* In PAE mode, allocate a pmd page and populate the
+                        * last pgd entry. */
+                       pmd_table = (pmd_t *)get_zeroed_page(GFP_KERNEL);
+                       if (!pmd_table) {
+                               free_page((long)cpu->lg->pgdirs[next].pgdir);
+                               set_pgd(cpu->lg->pgdirs[next].pgdir, __pgd(0));
+                               next = cpu->cpu_pgd;
+                       } else {
+                               set_pgd(cpu->lg->pgdirs[next].pgdir +
+                                       SWITCHER_PGD_INDEX,
+                                       __pgd(__pa(pmd_table) | _PAGE_PRESENT));
+                               /* This is a blank page, so there are no kernel
+                                * mappings: caller must map the stack! */
+                               *blank_pgdir = 1;
+                       }
+#else
                        *blank_pgdir = 1;
+#endif
+               }
        }
        /* Record which Guest toplevel this shadows. */
        cpu->lg->pgdirs[next].gpgdir = gpgdir;
@@ -431,7 +617,7 @@ static unsigned int new_pgdir(struct lg_cpu *cpu,
 
 /*H:430 (iv) Switching page tables
  *
- * Now we've seen all the page table setting and manipulation, let's see what
+ * Now we've seen all the page table setting and manipulation, let's see
  * what happens when the Guest changes page tables (ie. changes the top-level
  * pgdir).  This occurs on almost every context switch. */
 void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable)
@@ -460,10 +646,25 @@ static void release_all_pagetables(struct lguest *lg)
 
        /* Every shadow pagetable this Guest has */
        for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++)
-               if (lg->pgdirs[i].pgdir)
+               if (lg->pgdirs[i].pgdir) {
+#ifdef CONFIG_X86_PAE
+                       pgd_t *spgd;
+                       pmd_t *pmdpage;
+                       unsigned int k;
+
+                       /* Get the last pmd page. */
+                       spgd = lg->pgdirs[i].pgdir + SWITCHER_PGD_INDEX;
+                       pmdpage = __va(pgd_pfn(*spgd) << PAGE_SHIFT);
+
+                       /* And release the pmd entries of that pmd page,
+                        * except for the switcher pmd. */
+                       for (k = 0; k < SWITCHER_PMD_INDEX; k++)
+                               release_pmd(&pmdpage[k]);
+#endif
                        /* Every PGD entry except the Switcher at the top */
                        for (j = 0; j < SWITCHER_PGD_INDEX; j++)
-                               release_pgd(lg, lg->pgdirs[i].pgdir + j);
+                               release_pgd(lg->pgdirs[i].pgdir + j);
+               }
 }
 
 /* We also throw away everything when a Guest tells us it's changed a kernel
@@ -504,24 +705,37 @@ static void do_set_pte(struct lg_cpu *cpu, int idx,
 {
        /* Look up the matching shadow page directory entry. */
        pgd_t *spgd = spgd_addr(cpu, idx, vaddr);
+#ifdef CONFIG_X86_PAE
+       pmd_t *spmd;
+#endif
 
        /* If the top level isn't present, there's no entry to update. */
        if (pgd_flags(*spgd) & _PAGE_PRESENT) {
-               /* Otherwise, we start by releasing the existing entry. */
-               pte_t *spte = spte_addr(*spgd, vaddr);
-               release_pte(*spte);
-
-               /* If they're setting this entry as dirty or accessed, we might
-                * as well put that entry they've given us in now.  This shaves
-                * 10% off a copy-on-write micro-benchmark. */
-               if (pte_flags(gpte) & (_PAGE_DIRTY | _PAGE_ACCESSED)) {
-                       check_gpte(cpu, gpte);
-                       *spte = gpte_to_spte(cpu, gpte,
-                                            pte_flags(gpte) & _PAGE_DIRTY);
-               } else
-                       /* Otherwise kill it and we can demand_page() it in
-                        * later. */
-                       *spte = __pte(0);
+#ifdef CONFIG_X86_PAE
+               spmd = spmd_addr(cpu, *spgd, vaddr);
+               if (pmd_flags(*spmd) & _PAGE_PRESENT) {
+#endif
+                       /* Otherwise, we start by releasing
+                        * the existing entry. */
+                       pte_t *spte = spte_addr(cpu, *spgd, vaddr);
+                       release_pte(*spte);
+
+                       /* If they're setting this entry as dirty or accessed,
+                        * we might as well put that entry they've given us
+                        * in now.  This shaves 10% off a
+                        * copy-on-write micro-benchmark. */
+                       if (pte_flags(gpte) & (_PAGE_DIRTY | _PAGE_ACCESSED)) {
+                               check_gpte(cpu, gpte);
+                               native_set_pte(spte,
+                                               gpte_to_spte(cpu, gpte,
+                                               pte_flags(gpte) & _PAGE_DIRTY));
+                       } else
+                               /* Otherwise kill it and we can demand_page()
+                                * it in later. */
+                               native_set_pte(spte, __pte(0));
+#ifdef CONFIG_X86_PAE
+               }
+#endif
        }
 }
 
@@ -568,12 +782,10 @@ void guest_set_pte(struct lg_cpu *cpu,
  *
  * So with that in mind here's our code to to update a (top-level) PGD entry:
  */
-void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 idx)
+void guest_set_pgd(struct lguest *lg, unsigned long gpgdir, u32 idx)
 {
        int pgdir;
 
-       /* The kernel seems to try to initialize this early on: we ignore its
-        * attempts to map over the Switcher. */
        if (idx >= SWITCHER_PGD_INDEX)
                return;
 
@@ -581,8 +793,14 @@ void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 idx)
        pgdir = find_pgdir(lg, gpgdir);
        if (pgdir < ARRAY_SIZE(lg->pgdirs))
                /* ... throw it away. */
-               release_pgd(lg, lg->pgdirs[pgdir].pgdir + idx);
+               release_pgd(lg->pgdirs[pgdir].pgdir + idx);
 }
+#ifdef CONFIG_X86_PAE
+void guest_set_pmd(struct lguest *lg, unsigned long pmdp, u32 idx)
+{
+       guest_pagetable_clear_all(&lg->cpus[0]);
+}
+#endif
 
 /* Once we know how much memory we have we can construct simple identity
  * (which set virtual == physical) and linear mappings
@@ -596,8 +814,16 @@ static unsigned long setup_pagetables(struct lguest *lg,
 {
        pgd_t __user *pgdir;
        pte_t __user *linear;
-       unsigned int mapped_pages, i, linear_pages, phys_linear;
        unsigned long mem_base = (unsigned long)lg->mem_base;
+       unsigned int mapped_pages, i, linear_pages;
+#ifdef CONFIG_X86_PAE
+       pmd_t __user *pmds;
+       unsigned int j;
+       pgd_t pgd;
+       pmd_t pmd;
+#else
+       unsigned int phys_linear;
+#endif
 
        /* We have mapped_pages frames to map, so we need
         * linear_pages page tables to map them. */
@@ -610,6 +836,9 @@ static unsigned long setup_pagetables(struct lguest *lg,
        /* Now we use the next linear_pages pages as pte pages */
        linear = (void *)pgdir - linear_pages * PAGE_SIZE;
 
+#ifdef CONFIG_X86_PAE
+       pmds = (void *)linear - PAGE_SIZE;
+#endif
        /* Linear mapping is easy: put every page's address into the
         * mapping in order. */
        for (i = 0; i < mapped_pages; i++) {
@@ -621,6 +850,22 @@ static unsigned long setup_pagetables(struct lguest *lg,
 
        /* The top level points to the linear page table pages above.
         * We setup the identity and linear mappings here. */
+#ifdef CONFIG_X86_PAE
+       for (i = j = 0; i < mapped_pages && j < PTRS_PER_PMD;
+            i += PTRS_PER_PTE, j++) {
+               native_set_pmd(&pmd, __pmd(((unsigned long)(linear + i)
+               - mem_base) | _PAGE_PRESENT | _PAGE_RW | _PAGE_USER));
+
+               if (copy_to_user(&pmds[j], &pmd, sizeof(pmd)) != 0)
+                       return -EFAULT;
+       }
+
+       set_pgd(&pgd, __pgd(((u32)pmds - mem_base) | _PAGE_PRESENT));
+       if (copy_to_user(&pgdir[0], &pgd, sizeof(pgd)) != 0)
+               return -EFAULT;
+       if (copy_to_user(&pgdir[3], &pgd, sizeof(pgd)) != 0)
+               return -EFAULT;
+#else
        phys_linear = (unsigned long)linear - mem_base;
        for (i = 0; i < mapped_pages; i += PTRS_PER_PTE) {
                pgd_t pgd;
@@ -633,6 +878,7 @@ static unsigned long setup_pagetables(struct lguest *lg,
                                    &pgd, sizeof(pgd)))
                        return -EFAULT;
        }
+#endif
 
        /* We return the top level (guest-physical) address: remember where
         * this is. */
@@ -648,7 +894,10 @@ int init_guest_pagetable(struct lguest *lg)
        u64 mem;
        u32 initrd_size;
        struct boot_params __user *boot = (struct boot_params *)lg->mem_base;
-
+#ifdef CONFIG_X86_PAE
+       pgd_t *pgd;
+       pmd_t *pmd_table;
+#endif
        /* Get the Guest memory size and the ramdisk size from the boot header
         * located at lg->mem_base (Guest address 0). */
        if (copy_from_user(&mem, &boot->e820_map[0].size, sizeof(mem))
@@ -663,6 +912,15 @@ int init_guest_pagetable(struct lguest *lg)
        lg->pgdirs[0].pgdir = (pgd_t *)get_zeroed_page(GFP_KERNEL);
        if (!lg->pgdirs[0].pgdir)
                return -ENOMEM;
+#ifdef CONFIG_X86_PAE
+       pgd = lg->pgdirs[0].pgdir;
+       pmd_table = (pmd_t *) get_zeroed_page(GFP_KERNEL);
+       if (!pmd_table)
+               return -ENOMEM;
+
+       set_pgd(pgd + SWITCHER_PGD_INDEX,
+               __pgd(__pa(pmd_table) | _PAGE_PRESENT));
+#endif
        lg->cpus[0].cpu_pgd = 0;
        return 0;
 }
@@ -672,17 +930,24 @@ void page_table_guest_data_init(struct lg_cpu *cpu)
 {
        /* We get the kernel address: above this is all kernel memory. */
        if (get_user(cpu->lg->kernel_address,
-                    &cpu->lg->lguest_data->kernel_address)
-           /* We tell the Guest that it can't use the top 4MB of virtual
-            * addresses used by the Switcher. */
-           || put_user(4U*1024*1024, &cpu->lg->lguest_data->reserve_mem)
-           || put_user(cpu->lg->pgdirs[0].gpgdir, &cpu->lg->lguest_data->pgdir))
+               &cpu->lg->lguest_data->kernel_address)
+               /* We tell the Guest that it can't use the top 2 or 4 MB
+                * of virtual addresses used by the Switcher. */
+               || put_user(RESERVE_MEM * 1024 * 1024,
+                       &cpu->lg->lguest_data->reserve_mem)
+               || put_user(cpu->lg->pgdirs[0].gpgdir,
+                       &cpu->lg->lguest_data->pgdir))
                kill_guest(cpu, "bad guest page %p", cpu->lg->lguest_data);
 
        /* In flush_user_mappings() we loop from 0 to
         * "pgd_index(lg->kernel_address)".  This assumes it won't hit the
         * Switcher mappings, so check that now. */
+#ifdef CONFIG_X86_PAE
+       if (pgd_index(cpu->lg->kernel_address) == SWITCHER_PGD_INDEX &&
+               pmd_index(cpu->lg->kernel_address) == SWITCHER_PMD_INDEX)
+#else
        if (pgd_index(cpu->lg->kernel_address) >= SWITCHER_PGD_INDEX)
+#endif
                kill_guest(cpu, "bad kernel address %#lx",
                                 cpu->lg->kernel_address);
 }
@@ -708,16 +973,30 @@ void free_guest_pagetable(struct lguest *lg)
 void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages)
 {
        pte_t *switcher_pte_page = __get_cpu_var(switcher_pte_pages);
-       pgd_t switcher_pgd;
        pte_t regs_pte;
        unsigned long pfn;
 
+#ifdef CONFIG_X86_PAE
+       pmd_t switcher_pmd;
+       pmd_t *pmd_table;
+
+       native_set_pmd(&switcher_pmd, pfn_pmd(__pa(switcher_pte_page) >>
+                      PAGE_SHIFT, PAGE_KERNEL_EXEC));
+
+       pmd_table = __va(pgd_pfn(cpu->lg->
+                       pgdirs[cpu->cpu_pgd].pgdir[SWITCHER_PGD_INDEX])
+                                                               << PAGE_SHIFT);
+       native_set_pmd(&pmd_table[SWITCHER_PMD_INDEX], switcher_pmd);
+#else
+       pgd_t switcher_pgd;
+
        /* Make the last PGD entry for this Guest point to the Switcher's PTE
         * page for this CPU (with appropriate flags). */
-       switcher_pgd = __pgd(__pa(switcher_pte_page) | __PAGE_KERNEL);
+       switcher_pgd = __pgd(__pa(switcher_pte_page) | __PAGE_KERNEL_EXEC);
 
        cpu->lg->pgdirs[cpu->cpu_pgd].pgdir[SWITCHER_PGD_INDEX] = switcher_pgd;
 
+#endif
        /* We also change the Switcher PTE page.  When we're running the Guest,
         * we want the Guest's "regs" page to appear where the first Switcher
         * page for this CPU is.  This is an optimization: when the Switcher
@@ -726,8 +1005,9 @@ void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages)
         * page is already mapped there, we don't have to copy them out
         * again. */
        pfn = __pa(cpu->regs_page) >> PAGE_SHIFT;
-       regs_pte = pfn_pte(pfn, __pgprot(__PAGE_KERNEL));
-       switcher_pte_page[(unsigned long)pages/PAGE_SIZE%PTRS_PER_PTE] = regs_pte;
+       native_set_pte(&regs_pte, pfn_pte(pfn, PAGE_KERNEL));
+       native_set_pte(&switcher_pte_page[pte_index((unsigned long)pages)],
+                       regs_pte);
 }
 /*:*/
 
@@ -752,21 +1032,21 @@ static __init void populate_switcher_pte_page(unsigned int cpu,
 
        /* The first entries are easy: they map the Switcher code. */
        for (i = 0; i < pages; i++) {
-               pte[i] = mk_pte(switcher_page[i],
-                               __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED));
+               native_set_pte(&pte[i], mk_pte(switcher_page[i],
+                               __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED)));
        }
 
        /* The only other thing we map is this CPU's pair of pages. */
        i = pages + cpu*2;
 
        /* First page (Guest registers) is writable from the Guest */
-       pte[i] = pfn_pte(page_to_pfn(switcher_page[i]),
-                        __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED|_PAGE_RW));
+       native_set_pte(&pte[i], pfn_pte(page_to_pfn(switcher_page[i]),
+                        __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED|_PAGE_RW)));
 
        /* The second page contains the "struct lguest_ro_state", and is
         * read-only. */
-       pte[i+1] = pfn_pte(page_to_pfn(switcher_page[i+1]),
-                          __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED));
+       native_set_pte(&pte[i+1], pfn_pte(page_to_pfn(switcher_page[i+1]),
+                          __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED)));
 }
 
 /* We've made it through the page table code.  Perhaps our tired brains are
index 7ede64ffeef9e02b54ced2c2d024ccf17d9d59cd..482ed5a18750659e07f7bda54a90429822079b6f 100644 (file)
@@ -150,7 +150,7 @@ void load_guest_gdt_entry(struct lg_cpu *cpu, u32 num, u32 lo, u32 hi)
 {
        /* We assume the Guest has the same number of GDT entries as the
         * Host, otherwise we'd have to dynamically allocate the Guest GDT. */
-       if (num > ARRAY_SIZE(cpu->arch.gdt))
+       if (num >= ARRAY_SIZE(cpu->arch.gdt))
                kill_guest(cpu, "too many gdt entries %i", num);
 
        /* Set it up, then fix it. */
index 60955a70d8807a6a93a2d362c0cd124c98f3a4d0..1bb66e1ed5a7d7a267b023d86ca0490b28bb7beb 100644 (file)
@@ -216,7 +216,7 @@ config DVB_USB_TTUSB2
        help
          Say Y here to support the Pinnacle 400e DVB-S USB2.0 receiver. The
          firmware protocol used by this module is similar to the one used by the
-         old ttusb-driver - that's why the module is called dvb-usb-ttusb2.ko.
+         old ttusb-driver - that's why the module is called dvb-usb-ttusb2.
 
 config DVB_USB_DTT200U
        tristate "WideView WT-200U and WT-220U (pen) DVB-T USB2.0 support (Yakumo/Hama/Typhoon/Yuan)"
index 9d48da2fb013d9db9c656fb20437d8aab9910c6d..57835f5715fcaab55587224339e594772d477e11 100644 (file)
@@ -758,10 +758,14 @@ config VIDEO_MX1
        ---help---
          This is a v4l2 driver for the i.MX1/i.MXL CMOS Sensor Interface
 
+config MX3_VIDEO
+       bool
+
 config VIDEO_MX3
        tristate "i.MX3x Camera Sensor Interface driver"
        depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA
        select VIDEOBUF_DMA_CONTIG
+       select MX3_VIDEO
        ---help---
          This is a v4l2 driver for the i.MX3x Camera Sensor Interface
 
index 3e6ffee8dfed4b1d1444bacf44f6bf2d71f899a2..ccd47f57f42cf75633dd6c5badb91786d835d1e0 100644 (file)
@@ -181,7 +181,7 @@ static int hdpvr_submit_buffers(struct hdpvr_device *dev)
                                 buff_list);
                if (buf->status != BUFSTAT_AVAILABLE) {
                        v4l2_err(&dev->v4l2_dev,
-                                "buffer not marked as availbale\n");
+                                "buffer not marked as available\n");
                        ret = -EFAULT;
                        goto err;
                }
index 693e4b511354fb0b227d28c1b517d428667d39f6..fa9249b4971ae32e61058dd5edc35f81f5362dc7 100644 (file)
@@ -130,7 +130,7 @@ mpi_ioc.h
  *  08-08-01  01.02.01  Original release for v1.2 work.
  *                      New format for FWVersion and ProductId in
  *                      MSG_IOC_FACTS_REPLY and MPI_FW_HEADER.
- *  08-31-01  01.02.02  Addded event MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE and
+ *  08-31-01  01.02.02  Added event MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE and
  *                      related structure and defines.
  *                      Added event MPI_EVENT_ON_BUS_TIMER_EXPIRED.
  *                      Added MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE.
@@ -190,7 +190,7 @@ mpi_ioc.h
  *  10-11-06  01.05.12  Added MPI_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED.
  *                      Added MaxInitiators field to PortFacts reply.
  *                      Added SAS Device Status Change ReasonCode for
- *                      asynchronous notificaiton.
+ *                      asynchronous notification.
  *                      Added MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE and event
  *                      data structure.
  *                      Added new ImageType values for FWDownload and FWUpload
@@ -623,7 +623,7 @@ mpi_fc.h
  *  11-02-00  01.01.01  Original release for post 1.0 work
  *  12-04-00  01.01.02  Added messages for Common Transport Send and
  *                      Primitive Send.
- *  01-09-01  01.01.03  Modifed some of the new flags to have an MPI prefix
+ *  01-09-01  01.01.03  Modified some of the new flags to have an MPI prefix
  *                      and modified the FcPrimitiveSend flags.
  *  01-25-01  01.01.04  Move InitiatorIndex in LinkServiceRsp reply to a larger
  *                      field.
index 5d496a99e034c9498c583957f7a6b028370e8c3c..0df065275cd3c5d7252350f8a4186b54adc45bb8 100644 (file)
@@ -146,7 +146,6 @@ static MPT_EVHANDLER                 MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
 static MPT_RESETHANDLER                 MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
 static struct mpt_pci_driver   *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
 
-static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
 
 /*
  *  Driver Callback Index's
@@ -159,7 +158,8 @@ static u8 last_drv_idx;
  *  Forward protos...
  */
 static irqreturn_t mpt_interrupt(int irq, void *bus_id);
-static int     mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
+static int     mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
+               MPT_FRAME_HDR *reply);
 static int     mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
                        u32 *req, int replyBytes, u16 *u16reply, int maxwait,
                        int sleepFlag);
@@ -190,9 +190,9 @@ static int  mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
 static int     mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
 static void    mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
 static void    mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
-static void    mpt_timer_expired(unsigned long data);
 static void    mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
-static int     SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
+static int     SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch,
+       int sleepFlag);
 static int     SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
 static int     mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
 static int     mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
@@ -207,8 +207,8 @@ static int  procmpt_iocinfo_read(char *buf, char **start, off_t offset,
 #endif
 static void    mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
 
-//int          mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
-static int     ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
+static int     ProcessEventNotification(MPT_ADAPTER *ioc,
+               EventNotificationReply_t *evReply, int *evHandlers);
 static void    mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
 static void    mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
 static void    mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
@@ -276,6 +276,56 @@ mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
        return 0;
 }
 
+/**
+ * mpt_is_discovery_complete - determine if discovery has completed
+ * @ioc: per adatper instance
+ *
+ * Returns 1 when discovery completed, else zero.
+ */
+static int
+mpt_is_discovery_complete(MPT_ADAPTER *ioc)
+{
+       ConfigExtendedPageHeader_t hdr;
+       CONFIGPARMS cfg;
+       SasIOUnitPage0_t *buffer;
+       dma_addr_t dma_handle;
+       int rc = 0;
+
+       memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
+       memset(&cfg, 0, sizeof(CONFIGPARMS));
+       hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+       hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
+       cfg.cfghdr.ehdr = &hdr;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+
+       if ((mpt_config(ioc, &cfg)))
+               goto out;
+       if (!hdr.ExtPageLength)
+               goto out;
+
+       buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
+           &dma_handle);
+       if (!buffer)
+               goto out;
+
+       cfg.physAddr = dma_handle;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+       if ((mpt_config(ioc, &cfg)))
+               goto out_free_consistent;
+
+       if (!(buffer->PhyData[0].PortFlags &
+           MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS))
+               rc = 1;
+
+ out_free_consistent:
+       pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
+           buffer, dma_handle);
+ out:
+       return rc;
+}
+
 /**
  *     mpt_fault_reset_work - work performed on workq after ioc fault
  *     @work: input argument, used to derive ioc
@@ -290,7 +340,7 @@ mpt_fault_reset_work(struct work_struct *work)
        int              rc;
        unsigned long    flags;
 
-       if (ioc->diagPending || !ioc->active)
+       if (ioc->ioc_reset_in_progress || !ioc->active)
                goto out;
 
        ioc_raw_state = mpt_GetIocState(ioc, 0);
@@ -307,6 +357,12 @@ mpt_fault_reset_work(struct work_struct *work)
                        printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
                            "reset (%04xh)\n", ioc->name, ioc_raw_state &
                            MPI_DOORBELL_DATA_MASK);
+       } else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) {
+               if ((mpt_is_discovery_complete(ioc))) {
+                       devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing "
+                           "discovery_quiesce_io flag\n", ioc->name));
+                       ioc->sas_discovery_quiesce_io = 0;
+               }
        }
 
  out:
@@ -317,11 +373,11 @@ mpt_fault_reset_work(struct work_struct *work)
                ioc = ioc->alt_ioc;
 
        /* rearm the timer */
-       spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
        if (ioc->reset_work_q)
                queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
                        msecs_to_jiffies(MPT_POLLING_INTERVAL));
-       spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
 }
 
 
@@ -501,9 +557,9 @@ mpt_interrupt(int irq, void *bus_id)
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *     mpt_base_reply - MPT base driver's callback routine
+ *     mptbase_reply - MPT base driver's callback routine
  *     @ioc: Pointer to MPT_ADAPTER structure
- *     @mf: Pointer to original MPT request frame
+ *     @req: Pointer to original MPT request frame
  *     @reply: Pointer to MPT reply frame (NULL if TurboReply)
  *
  *     MPT base driver's callback routine; all base driver
@@ -514,122 +570,49 @@ mpt_interrupt(int irq, void *bus_id)
  *     should be freed, or 0 if it shouldn't.
  */
 static int
-mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
+mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
 {
+       EventNotificationReply_t *pEventReply;
+       u8 event;
+       int evHandlers;
        int freereq = 1;
-       u8 func;
-
-       dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply() called\n", ioc->name));
-#ifdef CONFIG_FUSION_LOGGING
-       if ((ioc->debug_level & MPT_DEBUG_MSG_FRAME) &&
-                       !(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
-               dmfprintk(ioc, printk(MYIOC_s_INFO_FMT ": Original request frame (@%p) header\n",
-                   ioc->name, mf));
-               DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf);
-       }
-#endif
-
-       func = reply->u.hdr.Function;
-       dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, Function=%02Xh\n",
-                       ioc->name, func));
-
-       if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
-               EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
-               int evHandlers = 0;
-               int results;
-
-               results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
-               if (results != evHandlers) {
-                       /* CHECKME! Any special handling needed here? */
-                       devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
-                                       ioc->name, evHandlers, results));
-               }
 
-               /*
-                *      Hmmm...  It seems that EventNotificationReply is an exception
-                *      to the rule of one reply per request.
-                */
-               if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
+       switch (reply->u.hdr.Function) {
+       case MPI_FUNCTION_EVENT_NOTIFICATION:
+               pEventReply = (EventNotificationReply_t *)reply;
+               evHandlers = 0;
+               ProcessEventNotification(ioc, pEventReply, &evHandlers);
+               event = le32_to_cpu(pEventReply->Event) & 0xFF;
+               if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
                        freereq = 0;
-               } else {
-                       devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
-                               ioc->name, pEvReply));
-               }
-
-#ifdef CONFIG_PROC_FS
-//             LogEvent(ioc, pEvReply);
-#endif
-
-       } else if (func == MPI_FUNCTION_EVENT_ACK) {
-               dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, EventAck reply received\n",
-                               ioc->name));
-       } else if (func == MPI_FUNCTION_CONFIG) {
-               CONFIGPARMS *pCfg;
-               unsigned long flags;
-
-               dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "config_complete (mf=%p,mr=%p)\n",
-                               ioc->name, mf, reply));
-
-               pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
-
-               if (pCfg) {
-                       /* disable timer and remove from linked list */
-                       del_timer(&pCfg->timer);
-
-                       spin_lock_irqsave(&ioc->FreeQlock, flags);
-                       list_del(&pCfg->linkage);
-                       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-
-                       /*
-                        *      If IOC Status is SUCCESS, save the header
-                        *      and set the status code to GOOD.
-                        */
-                       pCfg->status = MPT_CONFIG_ERROR;
-                       if (reply) {
-                               ConfigReply_t   *pReply = (ConfigReply_t *)reply;
-                               u16              status;
-
-                               status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
-                               dcprintk(ioc, printk(MYIOC_s_NOTE_FMT "  IOCStatus=%04xh, IOCLogInfo=%08xh\n",
-                                    ioc->name, status, le32_to_cpu(pReply->IOCLogInfo)));
-
-                               pCfg->status = status;
-                               if (status == MPI_IOCSTATUS_SUCCESS) {
-                                       if ((pReply->Header.PageType &
-                                           MPI_CONFIG_PAGETYPE_MASK) ==
-                                           MPI_CONFIG_PAGETYPE_EXTENDED) {
-                                               pCfg->cfghdr.ehdr->ExtPageLength =
-                                                   le16_to_cpu(pReply->ExtPageLength);
-                                               pCfg->cfghdr.ehdr->ExtPageType =
-                                                   pReply->ExtPageType;
-                                       }
-                                       pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
-
-                                       /* If this is a regular header, save PageLength. */
-                                       /* LMP Do this better so not using a reserved field! */
-                                       pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
-                                       pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
-                                       pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
-                               }
-                       }
-
-                       /*
-                        *      Wake up the original calling thread
-                        */
-                       pCfg->wait_done = 1;
-                       wake_up(&mpt_waitq);
+               if (event != MPI_EVENT_EVENT_CHANGE)
+                       break;
+       case MPI_FUNCTION_CONFIG:
+       case MPI_FUNCTION_SAS_IO_UNIT_CONTROL:
+               ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
+               if (reply) {
+                       ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
+                       memcpy(ioc->mptbase_cmds.reply, reply,
+                           min(MPT_DEFAULT_FRAME_SIZE,
+                               4 * reply->u.reply.MsgLength));
                }
-       } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
-               /* we should be always getting a reply frame */
-               memcpy(ioc->persist_reply_frame, reply,
-                   min(MPT_DEFAULT_FRAME_SIZE,
-                   4*reply->u.reply.MsgLength));
-               del_timer(&ioc->persist_timer);
-               ioc->persist_wait_done = 1;
-               wake_up(&mpt_waitq);
-       } else {
-               printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
-                               ioc->name, func);
+               if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
+                       ioc->mptbase_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+                       complete(&ioc->mptbase_cmds.done);
+               } else
+                       freereq = 0;
+               if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_FREE_MF)
+                       freereq = 1;
+               break;
+       case MPI_FUNCTION_EVENT_ACK:
+               devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "EventAck reply received\n", ioc->name));
+               break;
+       default:
+               printk(MYIOC_s_ERR_FMT
+                   "Unexpected msg function (=%02Xh) reply received!\n",
+                   ioc->name, reply->u.hdr.Function);
+               break;
        }
 
        /*
@@ -988,17 +971,21 @@ mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
 
        /*  Put Request back on FreeQ!  */
        spin_lock_irqsave(&ioc->FreeQlock, flags);
-       mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
+       if (cpu_to_le32(mf->u.frame.linkage.arg1) == 0xdeadbeaf)
+               goto out;
+       /* signature to know if this mf is freed */
+       mf->u.frame.linkage.arg1 = cpu_to_le32(0xdeadbeaf);
        list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
 #ifdef MFCNT
        ioc->mfcnt--;
 #endif
+ out:
        spin_unlock_irqrestore(&ioc->FreeQlock, flags);
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *     mpt_add_sge - Place a simple SGE at address pAddr.
+ *     mpt_add_sge - Place a simple 32 bit SGE at address pAddr.
  *     @pAddr: virtual address for SGE
  *     @flagslength: SGE flags and data transfer length
  *     @dma_addr: Physical address
@@ -1006,23 +993,116 @@ mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
  *     This routine places a MPT request frame back on the MPT adapter's
  *     FreeQ.
  */
-void
-mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
+static void
+mpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
 {
-       if (sizeof(dma_addr_t) == sizeof(u64)) {
-               SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
+       SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
+       pSge->FlagsLength = cpu_to_le32(flagslength);
+       pSge->Address = cpu_to_le32(dma_addr);
+}
+
+/**
+ *     mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr.
+ *     @pAddr: virtual address for SGE
+ *     @flagslength: SGE flags and data transfer length
+ *     @dma_addr: Physical address
+ *
+ *     This routine places a MPT request frame back on the MPT adapter's
+ *     FreeQ.
+ **/
+static void
+mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
+{
+       SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
+       pSge->Address.Low = cpu_to_le32
+                       (lower_32_bits((unsigned long)(dma_addr)));
+       pSge->Address.High = cpu_to_le32
+                       (upper_32_bits((unsigned long)dma_addr));
+       pSge->FlagsLength = cpu_to_le32
+                       ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
+}
+
+/**
+ *     mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr (1078 workaround).
+ *     @pAddr: virtual address for SGE
+ *     @flagslength: SGE flags and data transfer length
+ *     @dma_addr: Physical address
+ *
+ *     This routine places a MPT request frame back on the MPT adapter's
+ *     FreeQ.
+ **/
+static void
+mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
+{
+       SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
+       u32 tmp;
+
+       pSge->Address.Low = cpu_to_le32
+                       (lower_32_bits((unsigned long)(dma_addr)));
+       tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
+
+       /*
+        * 1078 errata workaround for the 36GB limitation
+        */
+       if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32)  == 9) {
+               flagslength |=
+                   MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS);
+               tmp |= (1<<31);
+               if (mpt_debug_level & MPT_DEBUG_36GB_MEM)
+                       printk(KERN_DEBUG "1078 P0M2 addressing for "
+                           "addr = 0x%llx len = %d\n",
+                           (unsigned long long)dma_addr,
+                           MPI_SGE_LENGTH(flagslength));
+       }
+
+       pSge->Address.High = cpu_to_le32(tmp);
+       pSge->FlagsLength = cpu_to_le32(
+               (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_add_chain - Place a 32 bit chain SGE at address pAddr.
+ *     @pAddr: virtual address for SGE
+ *     @next: nextChainOffset value (u32's)
+ *     @length: length of next SGL segment
+ *     @dma_addr: Physical address
+ *
+ */
+static void
+mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
+{
+               SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
+               pChain->Length = cpu_to_le16(length);
+               pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
+               pChain->NextChainOffset = next;
+               pChain->Address = cpu_to_le32(dma_addr);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr.
+ *     @pAddr: virtual address for SGE
+ *     @next: nextChainOffset value (u32's)
+ *     @length: length of next SGL segment
+ *     @dma_addr: Physical address
+ *
+ */
+static void
+mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
+{
+               SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
                u32 tmp = dma_addr & 0xFFFFFFFF;
 
-               pSge->FlagsLength = cpu_to_le32(flagslength);
-               pSge->Address.Low = cpu_to_le32(tmp);
-               tmp = (u32) ((u64)dma_addr >> 32);
-               pSge->Address.High = cpu_to_le32(tmp);
+               pChain->Length = cpu_to_le16(length);
+               pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT |
+                                MPI_SGE_FLAGS_64_BIT_ADDRESSING);
 
-       } else {
-               SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
-               pSge->FlagsLength = cpu_to_le32(flagslength);
-               pSge->Address = cpu_to_le32(dma_addr);
-       }
+               pChain->NextChainOffset = next;
+
+               pChain->Address.Low = cpu_to_le32(tmp);
+               tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
+               pChain->Address.High = cpu_to_le32(tmp);
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -1225,7 +1305,7 @@ mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
        }
        flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
        flags_length |= ioc->HostPageBuffer_sz;
-       mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
+       ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
        ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
 
 return 0;
@@ -1534,21 +1614,42 @@ mpt_mapresources(MPT_ADAPTER *ioc)
 
        pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
 
-       if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
-           && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
-               dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
-                   ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
-                   ioc->name));
-       } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
-           && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
-               dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
-                   ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
-                   ioc->name));
+       if (sizeof(dma_addr_t) > 4) {
+               const uint64_t required_mask = dma_get_required_mask
+                   (&pdev->dev);
+               if (required_mask > DMA_BIT_MASK(32)
+                       && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
+                       && !pci_set_consistent_dma_mask(pdev,
+                                                DMA_BIT_MASK(64))) {
+                       ioc->dma_mask = DMA_BIT_MASK(64);
+                       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
+                               ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
+                               ioc->name));
+               } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
+                       && !pci_set_consistent_dma_mask(pdev,
+                                               DMA_BIT_MASK(32))) {
+                       ioc->dma_mask = DMA_BIT_MASK(32);
+                       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
+                               ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
+                               ioc->name));
+               } else {
+                       printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
+                           ioc->name, pci_name(pdev));
+                       return r;
+               }
        } else {
-               printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
-                   ioc->name, pci_name(pdev));
-               pci_release_selected_regions(pdev, ioc->bars);
-               return r;
+               if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
+                       && !pci_set_consistent_dma_mask(pdev,
+                                               DMA_BIT_MASK(32))) {
+                       ioc->dma_mask = DMA_BIT_MASK(32);
+                       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
+                               ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
+                               ioc->name));
+               } else {
+                       printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
+                           ioc->name, pci_name(pdev));
+                       return r;
+               }
        }
 
        mem_phys = msize = 0;
@@ -1632,6 +1733,7 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
 
        ioc->id = mpt_ids++;
        sprintf(ioc->name, "ioc%d", ioc->id);
+       dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));
 
        /*
         * set initial debug level
@@ -1650,14 +1752,36 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
                return r;
        }
 
+       /*
+        * Setting up proper handlers for scatter gather handling
+        */
+       if (ioc->dma_mask == DMA_BIT_MASK(64)) {
+               if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
+                       ioc->add_sge = &mpt_add_sge_64bit_1078;
+               else
+                       ioc->add_sge = &mpt_add_sge_64bit;
+               ioc->add_chain = &mpt_add_chain_64bit;
+               ioc->sg_addr_size = 8;
+       } else {
+               ioc->add_sge = &mpt_add_sge;
+               ioc->add_chain = &mpt_add_chain;
+               ioc->sg_addr_size = 4;
+       }
+       ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
+
        ioc->alloc_total = sizeof(MPT_ADAPTER);
        ioc->req_sz = MPT_DEFAULT_FRAME_SIZE;           /* avoid div by zero! */
        ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
 
        ioc->pcidev = pdev;
-       ioc->diagPending = 0;
-       spin_lock_init(&ioc->diagLock);
-       spin_lock_init(&ioc->initializing_hba_lock);
+
+       spin_lock_init(&ioc->taskmgmt_lock);
+       mutex_init(&ioc->internal_cmds.mutex);
+       init_completion(&ioc->internal_cmds.done);
+       mutex_init(&ioc->mptbase_cmds.mutex);
+       init_completion(&ioc->mptbase_cmds.done);
+       mutex_init(&ioc->taskmgmt_cmds.mutex);
+       init_completion(&ioc->taskmgmt_cmds.done);
 
        /* Initialize the event logging.
         */
@@ -1670,16 +1794,13 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
        ioc->mfcnt = 0;
 #endif
 
+       ioc->sh = NULL;
        ioc->cached_fw = NULL;
 
        /* Initilize SCSI Config Data structure
         */
        memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
 
-       /* Initialize the running configQ head.
-        */
-       INIT_LIST_HEAD(&ioc->configQ);
-
        /* Initialize the fc rport list head.
         */
        INIT_LIST_HEAD(&ioc->fc_rports);
@@ -1690,9 +1811,8 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
 
        /* Initialize workqueue */
        INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
-       spin_lock_init(&ioc->fault_reset_work_lock);
 
-       snprintf(ioc->reset_work_q_name, sizeof(ioc->reset_work_q_name),
+       snprintf(ioc->reset_work_q_name, MPT_KOBJ_NAME_LEN,
                 "mpt_poll_%d", ioc->id);
        ioc->reset_work_q =
                create_singlethread_workqueue(ioc->reset_work_q_name);
@@ -1767,11 +1887,14 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
        case MPI_MANUFACTPAGE_DEVID_SAS1064:
        case MPI_MANUFACTPAGE_DEVID_SAS1068:
                ioc->errata_flag_1064 = 1;
+               ioc->bus_type = SAS;
+               break;
 
        case MPI_MANUFACTPAGE_DEVID_SAS1064E:
        case MPI_MANUFACTPAGE_DEVID_SAS1068E:
        case MPI_MANUFACTPAGE_DEVID_SAS1078:
                ioc->bus_type = SAS;
+               break;
        }
 
 
@@ -1813,6 +1936,11 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
         */
        mpt_detect_bound_ports(ioc, pdev);
 
+       INIT_LIST_HEAD(&ioc->fw_event_list);
+       spin_lock_init(&ioc->fw_event_lock);
+       snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id);
+       ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name);
+
        if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
            CAN_SLEEP)) != 0){
                printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
@@ -1885,13 +2013,18 @@ mpt_detach(struct pci_dev *pdev)
        /*
         * Stop polling ioc for fault condition
         */
-       spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
        wq = ioc->reset_work_q;
        ioc->reset_work_q = NULL;
-       spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
        cancel_delayed_work(&ioc->fault_reset_work);
        destroy_workqueue(wq);
 
+       spin_lock_irqsave(&ioc->fw_event_lock, flags);
+       wq = ioc->fw_event_q;
+       ioc->fw_event_q = NULL;
+       spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+       destroy_workqueue(wq);
 
        sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
        remove_proc_entry(pname, NULL);
@@ -1994,6 +2127,21 @@ mpt_resume(struct pci_dev *pdev)
        if (err)
                return err;
 
+       if (ioc->dma_mask == DMA_BIT_MASK(64)) {
+               if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
+                       ioc->add_sge = &mpt_add_sge_64bit_1078;
+               else
+                       ioc->add_sge = &mpt_add_sge_64bit;
+               ioc->add_chain = &mpt_add_chain_64bit;
+               ioc->sg_addr_size = 8;
+       } else {
+
+               ioc->add_sge = &mpt_add_sge;
+               ioc->add_chain = &mpt_add_chain;
+               ioc->sg_addr_size = 4;
+       }
+       ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
+
        printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
            ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
            CHIPREG_READ32(&ioc->chip->Doorbell));
@@ -2091,12 +2239,16 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
        ioc->active = 0;
 
        if (ioc->alt_ioc) {
-               if (ioc->alt_ioc->active)
+               if (ioc->alt_ioc->active ||
+                   reason == MPT_HOSTEVENT_IOC_RECOVER) {
                        reset_alt_ioc_active = 1;
-
-               /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
-               CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
-               ioc->alt_ioc->active = 0;
+                       /* Disable alt-IOC's reply interrupts
+                        *  (and FreeQ) for a bit
+                        **/
+                       CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
+                               0xFFFFFFFF);
+                       ioc->alt_ioc->active = 0;
+               }
        }
 
        hard = 1;
@@ -2117,9 +2269,11 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                        }
 
                } else {
-                       printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
+                       printk(MYIOC_s_WARN_FMT
+                           "NOT READY WARNING!\n", ioc->name);
                }
-               return -1;
+               ret = -1;
+               goto out;
        }
 
        /* hard_reset_done = 0 if a soft reset was performed
@@ -2129,7 +2283,9 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
                        alt_ioc_ready = 1;
                else
-                       printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
+                       printk(MYIOC_s_WARN_FMT
+                           ": alt-ioc Not ready WARNING!\n",
+                           ioc->alt_ioc->name);
        }
 
        for (ii=0; ii<5; ii++) {
@@ -2150,7 +2306,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
        if (alt_ioc_ready) {
                if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
                        dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                           "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
+                           "Initial Alt IocFacts failed rc=%x\n",
+                           ioc->name, rc));
                        /* Retry - alt IOC was initialized once
                         */
                        rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
@@ -2194,16 +2351,20 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                            IRQF_SHARED, ioc->name, ioc);
                        if (rc < 0) {
                                printk(MYIOC_s_ERR_FMT "Unable to allocate "
-                                   "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
+                                   "interrupt %d!\n",
+                                   ioc->name, ioc->pcidev->irq);
                                if (ioc->msi_enable)
                                        pci_disable_msi(ioc->pcidev);
-                               return -EBUSY;
+                               ret = -EBUSY;
+                               goto out;
                        }
                        irq_allocated = 1;
                        ioc->pci_irq = ioc->pcidev->irq;
                        pci_set_master(ioc->pcidev);            /* ?? */
-                       dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
-                           "%d\n", ioc->name, ioc->pcidev->irq));
+                       pci_set_drvdata(ioc->pcidev, ioc);
+                       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
+                           "installed at interrupt %d\n", ioc->name,
+                           ioc->pcidev->irq));
                }
        }
 
@@ -2212,17 +2373,22 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
         * init as upper addresses are needed for init.
         * If fails, continue with alt-ioc processing
         */
+       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n",
+           ioc->name));
        if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
                ret = -3;
 
        /* May need to check/upload firmware & data here!
         * If fails, continue with alt-ioc processing
         */
+       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n",
+           ioc->name));
        if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
                ret = -4;
 // NEW!
        if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
-               printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
+               printk(MYIOC_s_WARN_FMT
+                   ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n",
                    ioc->alt_ioc->name, rc);
                alt_ioc_ready = 0;
                reset_alt_ioc_active = 0;
@@ -2232,8 +2398,9 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
                        alt_ioc_ready = 0;
                        reset_alt_ioc_active = 0;
-                       printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
-                           ioc->alt_ioc->name, rc);
+                       printk(MYIOC_s_WARN_FMT
+                               ": alt-ioc: (%d) init failure WARNING!\n",
+                                       ioc->alt_ioc->name, rc);
                }
        }
 
@@ -2269,28 +2436,36 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                }
        }
 
+       /*  Enable MPT base driver management of EventNotification
+        *  and EventAck handling.
+        */
+       if ((ret == 0) && (!ioc->facts.EventState)) {
+               dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
+                       "SendEventNotification\n",
+                   ioc->name));
+               ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */
+       }
+
+       if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
+               rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);
+
        if (ret == 0) {
                /* Enable! (reply interrupt) */
                CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
                ioc->active = 1;
        }
-
-       if (reset_alt_ioc_active && ioc->alt_ioc) {
-               /* (re)Enable alt-IOC! (reply interrupt) */
-               dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n",
-                   ioc->alt_ioc->name));
-               CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
-               ioc->alt_ioc->active = 1;
+       if (rc == 0) {  /* alt ioc */
+               if (reset_alt_ioc_active && ioc->alt_ioc) {
+                       /* (re)Enable alt-IOC! (reply interrupt) */
+                       dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc"
+                               "reply irq re-enabled\n",
+                               ioc->alt_ioc->name));
+                       CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
+                               MPI_HIM_DIM);
+                       ioc->alt_ioc->active = 1;
+               }
        }
 
-       /*  Enable MPT base driver management of EventNotification
-        *  and EventAck handling.
-        */
-       if ((ret == 0) && (!ioc->facts.EventState))
-               (void) SendEventNotification(ioc, 1);   /* 1=Enable EventNotification */
-
-       if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
-               (void) SendEventNotification(ioc->alt_ioc, 1);  /* 1=Enable EventNotification */
 
        /*      Add additional "reason" check before call to GetLanConfigPages
         *      (combined with GetIoUnitPage2 call).  This prevents a somewhat
@@ -2306,8 +2481,9 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                mutex_init(&ioc->raid_data.inactive_list_mutex);
                INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
 
-               if (ioc->bus_type == SAS) {
+               switch (ioc->bus_type) {
 
+               case SAS:
                        /* clear persistency table */
                        if(ioc->facts.IOCExceptions &
                            MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
@@ -2321,8 +2497,15 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                         */
                        mpt_findImVolumes(ioc);
 
-               } else if (ioc->bus_type == FC) {
-                       if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
+                       /* Check, and possibly reset, the coalescing value
+                        */
+                       mpt_read_ioc_pg_1(ioc);
+
+                       break;
+
+               case FC:
+                       if ((ioc->pfacts[0].ProtocolFlags &
+                               MPI_PORTFACTS_PROTOCOL_LAN) &&
                            (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
                                /*
                                 *  Pre-fetch the ports LAN MAC address!
@@ -2331,11 +2514,14 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                                (void) GetLanConfigPages(ioc);
                                a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
                                dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                                   "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
-                                   ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
-
+                                       "LanAddr = %02X:%02X:%02X"
+                                       ":%02X:%02X:%02X\n",
+                                       ioc->name, a[5], a[4],
+                                       a[3], a[2], a[1], a[0]));
                        }
-               } else {
+                       break;
+
+               case SPI:
                        /* Get NVRAM and adapter maximums from SPP 0 and 2
                         */
                        mpt_GetScsiPortSettings(ioc, 0);
@@ -2354,6 +2540,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                        mpt_read_ioc_pg_1(ioc);
 
                        mpt_read_ioc_pg_4(ioc);
+
+                       break;
                }
 
                GetIoUnitPage2(ioc);
@@ -2435,16 +2623,20 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
                if (_pcidev == peer) {
                        /* Paranoia checks */
                        if (ioc->alt_ioc != NULL) {
-                               printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
-                                       ioc->name, ioc->alt_ioc->name);
+                               printk(MYIOC_s_WARN_FMT
+                                   "Oops, already bound (%s <==> %s)!\n",
+                                   ioc->name, ioc->name, ioc->alt_ioc->name);
                                break;
                        } else if (ioc_srch->alt_ioc != NULL) {
-                               printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
-                                       ioc_srch->name, ioc_srch->alt_ioc->name);
+                               printk(MYIOC_s_WARN_FMT
+                                   "Oops, already bound (%s <==> %s)!\n",
+                                   ioc_srch->name, ioc_srch->name,
+                                   ioc_srch->alt_ioc->name);
                                break;
                        }
-                       dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
-                               ioc->name, ioc_srch->name));
+                       dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                               "FOUND! binding %s <==> %s\n",
+                               ioc->name, ioc->name, ioc_srch->name));
                        ioc_srch->alt_ioc = ioc;
                        ioc->alt_ioc = ioc_srch;
                }
@@ -2464,8 +2656,8 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
        int ret;
 
        if (ioc->cached_fw != NULL) {
-               ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
-                   "adapter\n", __func__, ioc->name));
+               ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                       "%s: Pushing FW onto adapter\n", __func__, ioc->name));
                if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
                    ioc->cached_fw, CAN_SLEEP)) < 0) {
                        printk(MYIOC_s_WARN_FMT
@@ -2474,11 +2666,30 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
                }
        }
 
+       /*
+        * Put the controller into ready state (if its not already)
+        */
+       if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) {
+               if (!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET,
+                   CAN_SLEEP)) {
+                       if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY)
+                               printk(MYIOC_s_ERR_FMT "%s:  IOC msg unit "
+                                   "reset failed to put ioc in ready state!\n",
+                                   ioc->name, __func__);
+               } else
+                       printk(MYIOC_s_ERR_FMT "%s:  IOC msg unit reset "
+                           "failed!\n", ioc->name, __func__);
+       }
+
+
        /* Disable adapter interrupts! */
+       synchronize_irq(ioc->pcidev->irq);
        CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
        ioc->active = 0;
+
        /* Clear any lingering interrupt */
        CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+       CHIPREG_READ32(&ioc->chip->IntStatus);
 
        if (ioc->alloc != NULL) {
                sz = ioc->alloc_sz;
@@ -2538,19 +2749,22 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
                if((ret = mpt_host_page_access_control(ioc,
                    MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
                        printk(MYIOC_s_ERR_FMT
-                          "host page buffers free failed (%d)!\n",
-                           ioc->name, ret);
+                          ": %s: host page buffers free failed (%d)!\n",
+                           ioc->name, __func__, ret);
                }
-               dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free  @ %p, sz=%d bytes\n",
-                       ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
+               dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                       "HostPageBuffer free  @ %p, sz=%d bytes\n",
+                       ioc->name, ioc->HostPageBuffer,
+                       ioc->HostPageBuffer_sz));
                pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
                    ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
                ioc->HostPageBuffer = NULL;
                ioc->HostPageBuffer_sz = 0;
                ioc->alloc_total -= ioc->HostPageBuffer_sz;
        }
-}
 
+       pci_set_drvdata(ioc->pcidev, NULL);
+}
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_adapter_dispose - Free all resources associated with an MPT adapter
@@ -2690,8 +2904,12 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
        }
 
        /* Is it already READY? */
-       if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
+       if (!statefault &&
+           ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)) {
+               dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
+                   "IOC is in READY state\n", ioc->name));
                return 0;
+       }
 
        /*
         *      Check to see if IOC is in FAULT state.
@@ -2764,8 +2982,9 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
 
                ii++; cntdn--;
                if (!cntdn) {
-                       printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
-                                       ioc->name, (int)((ii+5)/HZ));
+                       printk(MYIOC_s_ERR_FMT
+                               "Wait IOC_READY state (0x%x) timeout(%d)!\n",
+                               ioc->name, ioc_state, (int)((ii+5)/HZ));
                        return -ETIME;
                }
 
@@ -2778,9 +2997,8 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
        }
 
        if (statefault < 3) {
-               printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
-                               ioc->name,
-                               statefault==1 ? "stuck handshake" : "IOC FAULT");
+               printk(MYIOC_s_INFO_FMT "Recovered from %s\n", ioc->name,
+                       statefault == 1 ? "stuck handshake" : "IOC FAULT");
        }
 
        return hard_reset_done;
@@ -2833,8 +3051,9 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
 
        /* IOC *must* NOT be in RESET state! */
        if (ioc->last_state == MPI_IOC_STATE_RESET) {
-               printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
-                   ioc->name, ioc->last_state );
+               printk(KERN_ERR MYNAM
+                   ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
+                   ioc->name, ioc->last_state);
                return -44;
        }
 
@@ -2896,7 +3115,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
                 *      Old: u16{Major(4),Minor(4),SubMinor(8)}
                 *      New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
                 */
-               if (facts->MsgVersion < 0x0102) {
+               if (facts->MsgVersion < MPI_VERSION_01_02) {
                        /*
                         *      Handle old FC f/w style, convert to new...
                         */
@@ -2908,9 +3127,11 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
                        facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
 
                facts->ProductID = le16_to_cpu(facts->ProductID);
+
                if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
                    > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
                        ioc->ir_firmware = 1;
+
                facts->CurrentHostMfaHighAddr =
                                le32_to_cpu(facts->CurrentHostMfaHighAddr);
                facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
@@ -2926,7 +3147,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
                 * to 14 in MPI-1.01.0x.
                 */
                if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
-                   facts->MsgVersion > 0x0100) {
+                   facts->MsgVersion > MPI_VERSION_01_00) {
                        facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
                }
 
@@ -3108,6 +3329,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
 
        ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
        ioc_init.MaxBuses = (U8)ioc->number_of_buses;
+
        dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
                   ioc->name, ioc->facts.MsgVersion));
        if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
@@ -3122,7 +3344,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
        }
        ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz);   /* in BYTES */
 
-       if (sizeof(dma_addr_t) == sizeof(u64)) {
+       if (ioc->sg_addr_size == sizeof(u64)) {
                /* Save the upper 32-bits of the request
                 * (reply) and sense buffers.
                 */
@@ -3325,11 +3547,10 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
        FWUpload_t              *prequest;
        FWUploadReply_t         *preply;
        FWUploadTCSGE_t         *ptcsge;
-       int                      sgeoffset;
        u32                      flagsLength;
        int                      ii, sz, reply_sz;
        int                      cmdStatus;
-
+       int                     request_size;
        /* If the image size is 0, we are done.
         */
        if ((sz = ioc->facts.FWImageSize) == 0)
@@ -3364,42 +3585,41 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
        ptcsge->ImageSize = cpu_to_le32(sz);
        ptcsge++;
 
-       sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
-
        flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
-       mpt_add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
-
-       sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
-       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
-           ioc->name, prequest, sgeoffset));
+       ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
+       request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
+           ioc->SGE_size;
+       dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
+           " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
+           ioc->facts.FWImageSize, request_size));
        DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
 
-       ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
-                               reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
+       ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
+           reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
 
-       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
+       dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed "
+           "rc=%x \n", ioc->name, ii));
 
        cmdStatus = -EFAULT;
        if (ii == 0) {
                /* Handshake transfer was complete and successful.
                 * Check the Reply Frame.
                 */
-               int status, transfer_sz;
-               status = le16_to_cpu(preply->IOCStatus);
-               if (status == MPI_IOCSTATUS_SUCCESS) {
-                       transfer_sz = le32_to_cpu(preply->ActualImageSize);
-                       if (transfer_sz == sz)
+               int status;
+               status = le16_to_cpu(preply->IOCStatus) &
+                               MPI_IOCSTATUS_MASK;
+               if (status == MPI_IOCSTATUS_SUCCESS &&
+                   ioc->facts.FWImageSize ==
+                   le32_to_cpu(preply->ActualImageSize))
                                cmdStatus = 0;
-               }
        }
        dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
                        ioc->name, cmdStatus));
 
 
        if (cmdStatus) {
-
-               ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
-                       ioc->name));
+               ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, "
+                   "freeing image \n", ioc->name));
                mpt_free_fw_memory(ioc);
        }
        kfree(prequest);
@@ -3723,6 +3943,10 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
        CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
 
        if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
+
+               if (!ignore)
+                       return 0;
+
                drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
                        "address=%p\n",  ioc->name, __func__,
                        &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
@@ -3740,6 +3964,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
                                "looking for READY STATE: doorbell=%x"
                                " count=%d\n",
                                ioc->name, doorbell, count));
+
                        if (doorbell == MPI_IOC_STATE_READY) {
                                return 1;
                        }
@@ -3890,6 +4115,10 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
                                doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
                                doorbell &= MPI_IOC_STATE_MASK;
 
+                               drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                                   "looking for READY STATE: doorbell=%x"
+                                   " count=%d\n", ioc->name, doorbell, count));
+
                                if (doorbell == MPI_IOC_STATE_READY) {
                                        break;
                                }
@@ -3901,6 +4130,11 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
                                        mdelay (1000);
                                }
                        }
+
+                       if (doorbell != MPI_IOC_STATE_READY)
+                               printk(MYIOC_s_ERR_FMT "Failed to come READY "
+                                   "after reset! IocState=%x", ioc->name,
+                                   doorbell);
                }
        }
 
@@ -4019,8 +4253,9 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
                        if (sleepFlag != CAN_SLEEP)
                                count *= 10;
 
-                       printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
-                           ioc->name, (int)((count+5)/HZ));
+                       printk(MYIOC_s_ERR_FMT
+                           "Wait IOC_READY state (0x%x) timeout(%d)!\n",
+                           ioc->name, state, (int)((count+5)/HZ));
                        return -ETIME;
                }
 
@@ -4090,24 +4325,29 @@ initChainBuffers(MPT_ADAPTER *ioc)
         * num_sge = num sge in request frame + last chain buffer
         * scale = num sge per chain buffer if no chain element
         */
-       scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
-       if (sizeof(dma_addr_t) == sizeof(u64))
-               num_sge =  scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
+       scale = ioc->req_sz / ioc->SGE_size;
+       if (ioc->sg_addr_size == sizeof(u64))
+               num_sge =  scale + (ioc->req_sz - 60) / ioc->SGE_size;
        else
-               num_sge =  1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
+               num_sge =  1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
 
-       if (sizeof(dma_addr_t) == sizeof(u64)) {
+       if (ioc->sg_addr_size == sizeof(u64)) {
                numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
-                       (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
+                       (ioc->req_sz - 60) / ioc->SGE_size;
        } else {
-               numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
-                       (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
+               numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
+                   scale + (ioc->req_sz - 64) / ioc->SGE_size;
        }
        dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
                ioc->name, num_sge, numSGE));
 
-       if ( numSGE > MPT_SCSI_SG_DEPTH )
-               numSGE = MPT_SCSI_SG_DEPTH;
+       if (ioc->bus_type == FC) {
+               if (numSGE > MPT_SCSI_FC_SG_DEPTH)
+                       numSGE = MPT_SCSI_FC_SG_DEPTH;
+       } else {
+               if (numSGE > MPT_SCSI_SG_DEPTH)
+                       numSGE = MPT_SCSI_SG_DEPTH;
+       }
 
        num_chain = 1;
        while (numSGE - num_sge > 0) {
@@ -4161,12 +4401,42 @@ PrimeIocFifos(MPT_ADAPTER *ioc)
        dma_addr_t alloc_dma;
        u8 *mem;
        int i, reply_sz, sz, total_size, num_chain;
+       u64     dma_mask;
+
+       dma_mask = 0;
 
        /*  Prime reply FIFO...  */
 
        if (ioc->reply_frames == NULL) {
                if ( (num_chain = initChainBuffers(ioc)) < 0)
                        return -1;
+               /*
+                * 1078 errata workaround for the 36GB limitation
+                */
+               if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
+                   ioc->dma_mask > DMA_35BIT_MASK) {
+                       if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
+                           && !pci_set_consistent_dma_mask(ioc->pcidev,
+                           DMA_BIT_MASK(32))) {
+                               dma_mask = DMA_35BIT_MASK;
+                               d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                                   "setting 35 bit addressing for "
+                                   "Request/Reply/Chain and Sense Buffers\n",
+                                   ioc->name));
+                       } else {
+                               /*Reseting DMA mask to 64 bit*/
+                               pci_set_dma_mask(ioc->pcidev,
+                                       DMA_BIT_MASK(64));
+                               pci_set_consistent_dma_mask(ioc->pcidev,
+                                       DMA_BIT_MASK(64));
+
+                               printk(MYIOC_s_ERR_FMT
+                                   "failed setting 35 bit addressing for "
+                                   "Request/Reply/Chain and Sense Buffers\n",
+                                   ioc->name);
+                               return -1;
+                       }
+               }
 
                total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
                dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
@@ -4305,9 +4575,16 @@ PrimeIocFifos(MPT_ADAPTER *ioc)
                alloc_dma += ioc->reply_sz;
        }
 
+       if (dma_mask == DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
+           ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
+           ioc->dma_mask))
+               d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "restoring 64 bit addressing\n", ioc->name));
+
        return 0;
 
 out_fail:
+
        if (ioc->alloc != NULL) {
                sz = ioc->alloc_sz;
                pci_free_consistent(ioc->pcidev,
@@ -4324,6 +4601,13 @@ out_fail:
                                ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
                ioc->sense_buf_pool = NULL;
        }
+
+       if (dma_mask == DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
+           DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
+           DMA_BIT_MASK(64)))
+               d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "restoring 64 bit addressing\n", ioc->name));
+
        return -1;
 }
 
@@ -4759,7 +5043,14 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
        SasIoUnitControlReply_t         *sasIoUnitCntrReply;
        MPT_FRAME_HDR                   *mf = NULL;
        MPIHeader_t                     *mpi_hdr;
+       int                             ret = 0;
+       unsigned long                   timeleft;
+
+       mutex_lock(&ioc->mptbase_cmds.mutex);
 
+       /* init the internal cmd struct */
+       memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
+       INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
 
        /* insure garbage is not sent to fw */
        switch(persist_opcode) {
@@ -4769,17 +5060,19 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
                break;
 
        default:
-               return -1;
-               break;
+               ret = -1;
+               goto out;
        }
 
-       printk("%s: persist_opcode=%x\n",__func__, persist_opcode);
+       printk(KERN_DEBUG  "%s: persist_opcode=%x\n",
+               __func__, persist_opcode);
 
        /* Get a MF for this command.
         */
        if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
-               printk("%s: no msg frames!\n",__func__);
-               return -1;
+               printk(KERN_DEBUG "%s: no msg frames!\n", __func__);
+               ret = -1;
+               goto out;
         }
 
        mpi_hdr = (MPIHeader_t *) mf;
@@ -4789,27 +5082,42 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
        sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
        sasIoUnitCntrReq->Operation = persist_opcode;
 
-       init_timer(&ioc->persist_timer);
-       ioc->persist_timer.data = (unsigned long) ioc;
-       ioc->persist_timer.function = mpt_timer_expired;
-       ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
-       ioc->persist_wait_done=0;
-       add_timer(&ioc->persist_timer);
        mpt_put_msg_frame(mpt_base_index, ioc, mf);
-       wait_event(mpt_waitq, ioc->persist_wait_done);
+       timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);
+       if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               ret = -ETIME;
+               printk(KERN_DEBUG "%s: failed\n", __func__);
+               if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
+                       goto out;
+               if (!timeleft) {
+                       printk(KERN_DEBUG "%s: Issuing Reset from %s!!\n",
+                           ioc->name, __func__);
+                       mpt_HardResetHandler(ioc, CAN_SLEEP);
+                       mpt_free_msg_frame(ioc, mf);
+               }
+               goto out;
+       }
+
+       if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
+               ret = -1;
+               goto out;
+       }
 
        sasIoUnitCntrReply =
-           (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
+           (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;
        if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
-               printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
-                   __func__,
-                   sasIoUnitCntrReply->IOCStatus,
+               printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
+                   __func__, sasIoUnitCntrReply->IOCStatus,
                    sasIoUnitCntrReply->IOCLogInfo);
-               return -1;
-       }
+               printk(KERN_DEBUG "%s: failed\n", __func__);
+               ret = -1;
+       } else
+               printk(KERN_DEBUG "%s: success\n", __func__);
+ out:
 
-       printk("%s: success\n",__func__);
-       return 0;
+       CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
+       mutex_unlock(&ioc->mptbase_cmds.mutex);
+       return ret;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -5394,17 +5702,20 @@ mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
  *     -ENOMEM if pci_alloc failed
  **/
 int
-mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
+mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num,
+                       RaidPhysDiskPage0_t *phys_disk)
 {
-       CONFIGPARMS                     cfg;
-       ConfigPageHeader_t              hdr;
+       CONFIGPARMS                     cfg;
+       ConfigPageHeader_t              hdr;
        dma_addr_t                      dma_handle;
        pRaidPhysDiskPage0_t            buffer = NULL;
        int                             rc;
 
        memset(&cfg, 0 , sizeof(CONFIGPARMS));
        memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
+       memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t));
 
+       hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION;
        hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
        cfg.cfghdr.hdr = &hdr;
        cfg.physAddr = -1;
@@ -5450,6 +5761,161 @@ mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t
        return rc;
 }
 
+/**
+ *     mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num
+ *     @ioc: Pointer to a Adapter Structure
+ *     @phys_disk_num: io unit unique phys disk num generated by the ioc
+ *
+ *     Return:
+ *     returns number paths
+ **/
+int
+mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num)
+{
+       CONFIGPARMS                     cfg;
+       ConfigPageHeader_t              hdr;
+       dma_addr_t                      dma_handle;
+       pRaidPhysDiskPage1_t            buffer = NULL;
+       int                             rc;
+
+       memset(&cfg, 0 , sizeof(CONFIGPARMS));
+       memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
+
+       hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
+       hdr.PageNumber = 1;
+       cfg.cfghdr.hdr = &hdr;
+       cfg.physAddr = -1;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+
+       if (mpt_config(ioc, &cfg) != 0) {
+               rc = 0;
+               goto out;
+       }
+
+       if (!hdr.PageLength) {
+               rc = 0;
+               goto out;
+       }
+
+       buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
+           &dma_handle);
+
+       if (!buffer) {
+               rc = 0;
+               goto out;
+       }
+
+       cfg.physAddr = dma_handle;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+       cfg.pageAddr = phys_disk_num;
+
+       if (mpt_config(ioc, &cfg) != 0) {
+               rc = 0;
+               goto out;
+       }
+
+       rc = buffer->NumPhysDiskPaths;
+ out:
+
+       if (buffer)
+               pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
+                   dma_handle);
+
+       return rc;
+}
+EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths);
+
+/**
+ *     mpt_raid_phys_disk_pg1 - returns phys disk page 1
+ *     @ioc: Pointer to a Adapter Structure
+ *     @phys_disk_num: io unit unique phys disk num generated by the ioc
+ *     @phys_disk: requested payload data returned
+ *
+ *     Return:
+ *     0 on success
+ *     -EFAULT if read of config page header fails or data pointer not NULL
+ *     -ENOMEM if pci_alloc failed
+ **/
+int
+mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num,
+               RaidPhysDiskPage1_t *phys_disk)
+{
+       CONFIGPARMS                     cfg;
+       ConfigPageHeader_t              hdr;
+       dma_addr_t                      dma_handle;
+       pRaidPhysDiskPage1_t            buffer = NULL;
+       int                             rc;
+       int                             i;
+       __le64                          sas_address;
+
+       memset(&cfg, 0 , sizeof(CONFIGPARMS));
+       memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
+       rc = 0;
+
+       hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
+       hdr.PageNumber = 1;
+       cfg.cfghdr.hdr = &hdr;
+       cfg.physAddr = -1;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+
+       if (mpt_config(ioc, &cfg) != 0) {
+               rc = -EFAULT;
+               goto out;
+       }
+
+       if (!hdr.PageLength) {
+               rc = -EFAULT;
+               goto out;
+       }
+
+       buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
+           &dma_handle);
+
+       if (!buffer) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       cfg.physAddr = dma_handle;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+       cfg.pageAddr = phys_disk_num;
+
+       if (mpt_config(ioc, &cfg) != 0) {
+               rc = -EFAULT;
+               goto out;
+       }
+
+       phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths;
+       phys_disk->PhysDiskNum = phys_disk_num;
+       for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) {
+               phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID;
+               phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus;
+               phys_disk->Path[i].OwnerIdentifier =
+                               buffer->Path[i].OwnerIdentifier;
+               phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags);
+               memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64));
+               sas_address = le64_to_cpu(sas_address);
+               memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64));
+               memcpy(&sas_address,
+                               &buffer->Path[i].OwnerWWID, sizeof(__le64));
+               sas_address = le64_to_cpu(sas_address);
+               memcpy(&phys_disk->Path[i].OwnerWWID,
+                               &sas_address, sizeof(__le64));
+       }
+
+ out:
+
+       if (buffer)
+               pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
+                   dma_handle);
+
+       return rc;
+}
+EXPORT_SYMBOL(mpt_raid_phys_disk_pg1);
+
+
 /**
  *     mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
  *     @ioc: Pointer to a Adapter Strucutre
@@ -5775,30 +6241,28 @@ mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
  *     SendEventNotification - Send EventNotification (on or off) request to adapter
  *     @ioc: Pointer to MPT_ADAPTER structure
  *     @EvSwitch: Event switch flags
+ *     @sleepFlag: Specifies whether the process can sleep
  */
 static int
-SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
+SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
 {
-       EventNotification_t     *evnp;
+       EventNotification_t     evn;
+       MPIDefaultReply_t       reply_buf;
 
-       evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
-       if (evnp == NULL) {
-               devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
-                               ioc->name));
-               return 0;
-       }
-       memset(evnp, 0, sizeof(*evnp));
+       memset(&evn, 0, sizeof(EventNotification_t));
+       memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
 
-       devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
+       evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
+       evn.Switch = EvSwitch;
+       evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
 
-       evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
-       evnp->ChainOffset = 0;
-       evnp->MsgFlags = 0;
-       evnp->Switch = EvSwitch;
-
-       mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
+       devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "Sending EventNotification (%d) request %p\n",
+           ioc->name, EvSwitch, &evn));
 
-       return 0;
+       return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
+           (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30,
+           sleepFlag);
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -5814,7 +6278,7 @@ SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
 
        if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
                dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
-                   ioc->name,__func__));
+                   ioc->name, __func__));
                return -1;
        }
 
@@ -5851,12 +6315,19 @@ int
 mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
 {
        Config_t        *pReq;
+       ConfigReply_t   *pReply;
        ConfigExtendedPageHeader_t  *pExtHdr = NULL;
        MPT_FRAME_HDR   *mf;
-       unsigned long    flags;
-       int              ii, rc;
+       int              ii;
        int              flagsLength;
-       int              in_isr;
+       long             timeout;
+       int              ret;
+       u8               page_type = 0, extend_page;
+       unsigned long    timeleft;
+       unsigned long    flags;
+    int                 in_isr;
+       u8               issue_hard_reset = 0;
+       u8               retry_count = 0;
 
        /*      Prevent calling wait_event() (below), if caller happens
         *      to be in ISR context, because that is fatal!
@@ -5866,15 +6337,43 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
                dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
                                ioc->name));
                return -EPERM;
+    }
+
+       /* don't send a config page during diag reset */
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       if (ioc->ioc_reset_in_progress) {
+               dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: busy with host reset\n", ioc->name, __func__));
+               spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+               return -EBUSY;
+       }
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+
+       /* don't send if no chance of success */
+       if (!ioc->active ||
+           mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
+               dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: ioc not operational, %d, %xh\n",
+                   ioc->name, __func__, ioc->active,
+                   mpt_GetIocState(ioc, 0)));
+               return -EFAULT;
        }
 
+ retry_config:
+       mutex_lock(&ioc->mptbase_cmds.mutex);
+       /* init the internal cmd struct */
+       memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
+       INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
+
        /* Get and Populate a free Frame
         */
        if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
-               dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
-                               ioc->name));
-               return -EAGAIN;
+               dcprintk(ioc, printk(MYIOC_s_WARN_FMT
+               "mpt_config: no msg frames!\n", ioc->name));
+               ret = -EAGAIN;
+               goto out;
        }
+
        pReq = (Config_t *)mf;
        pReq->Action = pCfg->action;
        pReq->Reserved = 0;
@@ -5900,7 +6399,9 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
                pReq->ExtPageType = pExtHdr->ExtPageType;
                pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
 
-               /* Page Length must be treated as a reserved field for the extended header. */
+               /* Page Length must be treated as a reserved field for the
+                * extended header.
+                */
                pReq->Header.PageLength = 0;
        }
 
@@ -5913,78 +6414,91 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
        else
                flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
 
-       if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
+       if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
+           MPI_CONFIG_PAGETYPE_EXTENDED) {
                flagsLength |= pExtHdr->ExtPageLength * 4;
-
-               dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Config request type %d, page %d and action %d\n",
-                       ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
-       }
-       else {
+               page_type = pReq->ExtPageType;
+               extend_page = 1;
+       } else {
                flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
-
-               dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Config request type %d, page %d and action %d\n",
-                       ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
+               page_type = pReq->Header.PageType;
+               extend_page = 0;
        }
 
-       mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
-
-       /* Append pCfg pointer to end of mf
-        */
-       *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) =  (void *) pCfg;
+       dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "Sending Config request type 0x%x, page 0x%x and action %d\n",
+           ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));
 
-       /* Initalize the timer
-        */
-       init_timer_on_stack(&pCfg->timer);
-       pCfg->timer.data = (unsigned long) ioc;
-       pCfg->timer.function = mpt_timer_expired;
-       pCfg->wait_done = 0;
-
-       /* Set the timer; ensure 10 second minimum */
-       if (pCfg->timeout < 10)
-               pCfg->timer.expires = jiffies + HZ*10;
-       else
-               pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
-
-       /* Add to end of Q, set timer and then issue this command */
-       spin_lock_irqsave(&ioc->FreeQlock, flags);
-       list_add_tail(&pCfg->linkage, &ioc->configQ);
-       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-
-       add_timer(&pCfg->timer);
+       ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
+       timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
        mpt_put_msg_frame(mpt_base_index, ioc, mf);
-       wait_event(mpt_waitq, pCfg->wait_done);
-
-       /* mf has been freed - do not access */
+       timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done,
+               timeout);
+       if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               ret = -ETIME;
+               dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "Failed Sending Config request type 0x%x, page 0x%x,"
+                   " action %d, status %xh, time left %ld\n\n",
+                       ioc->name, page_type, pReq->Header.PageNumber,
+                       pReq->Action, ioc->mptbase_cmds.status, timeleft));
+               if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
+                       goto out;
+               if (!timeleft)
+                       issue_hard_reset = 1;
+               goto out;
+       }
 
-       rc = pCfg->status;
+       if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
+               ret = -1;
+               goto out;
+       }
+       pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply;
+       ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+       if (ret == MPI_IOCSTATUS_SUCCESS) {
+               if (extend_page) {
+                       pCfg->cfghdr.ehdr->ExtPageLength =
+                           le16_to_cpu(pReply->ExtPageLength);
+                       pCfg->cfghdr.ehdr->ExtPageType =
+                           pReply->ExtPageType;
+               }
+               pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
+               pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
+               pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
+               pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
 
-       return rc;
-}
+       }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *     mpt_timer_expired - Callback for timer process.
- *     Used only internal config functionality.
- *     @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
- */
-static void
-mpt_timer_expired(unsigned long data)
-{
-       MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
+       if (retry_count)
+               printk(MYIOC_s_INFO_FMT "Retry completed "
+                   "ret=0x%x timeleft=%ld\n",
+                   ioc->name, ret, timeleft);
 
-       dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
+       dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
+            ret, le32_to_cpu(pReply->IOCLogInfo)));
 
-       /* Perform a FW reload */
-       if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
-               printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
+out:
 
-       /* No more processing.
-        * Hard reset clean-up will wake up
-        * process and free all resources.
-        */
-       dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
+       CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
+       mutex_unlock(&ioc->mptbase_cmds.mutex);
+       if (issue_hard_reset) {
+               issue_hard_reset = 0;
+               printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
+                   ioc->name, __func__);
+               mpt_HardResetHandler(ioc, CAN_SLEEP);
+               mpt_free_msg_frame(ioc, mf);
+               /* attempt one retry for a timed out command */
+               if (!retry_count) {
+                       printk(MYIOC_s_INFO_FMT
+                           "Attempting Retry Config request"
+                           " type 0x%x, page 0x%x,"
+                           " action %d\n", ioc->name, page_type,
+                           pCfg->cfghdr.hdr->PageNumber, pCfg->action);
+                       retry_count++;
+                       goto retry_config;
+               }
+       }
+       return ret;
 
-       return;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -5998,41 +6512,34 @@ mpt_timer_expired(unsigned long data)
 static int
 mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 {
-       CONFIGPARMS *pCfg;
-       unsigned long flags;
-
-       dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-           ": IOC %s_reset routed to MPT base driver!\n",
-           ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
-           reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
-
-       if (reset_phase == MPT_IOC_SETUP_RESET) {
-               ;
-       } else if (reset_phase == MPT_IOC_PRE_RESET) {
-               /* If the internal config Q is not empty -
-                * delete timer. MF resources will be freed when
-                * the FIFO's are primed.
-                */
-               spin_lock_irqsave(&ioc->FreeQlock, flags);
-               list_for_each_entry(pCfg, &ioc->configQ, linkage)
-                       del_timer(&pCfg->timer);
-               spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-
-       } else {
-               CONFIGPARMS *pNext;
-
-               /* Search the configQ for internal commands.
-                * Flush the Q, and wake up all suspended threads.
-                */
-               spin_lock_irqsave(&ioc->FreeQlock, flags);
-               list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
-                       list_del(&pCfg->linkage);
-
-                       pCfg->status = MPT_CONFIG_ERROR;
-                       pCfg->wait_done = 1;
-                       wake_up(&mpt_waitq);
+       switch (reset_phase) {
+       case MPT_IOC_SETUP_RESET:
+               ioc->taskmgmt_quiesce_io = 1;
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
+               break;
+       case MPT_IOC_PRE_RESET:
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
+               break;
+       case MPT_IOC_POST_RESET:
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_POST_RESET\n",  ioc->name, __func__));
+/* wake up mptbase_cmds */
+               if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
+                       ioc->mptbase_cmds.status |=
+                           MPT_MGMT_STATUS_DID_IOCRESET;
+                       complete(&ioc->mptbase_cmds.done);
                }
-               spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+/* wake up taskmgmt_cmds */
+               if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
+                       ioc->taskmgmt_cmds.status |=
+                               MPT_MGMT_STATUS_DID_IOCRESET;
+                       complete(&ioc->taskmgmt_cmds.done);
+               }
+               break;
+       default:
+               break;
        }
 
        return 1;               /* currently means nothing really */
@@ -6344,6 +6851,59 @@ mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int sh
 
        *size = y;
 }
+/**
+ *     mpt_set_taskmgmt_in_progress_flag - set flags associated with task managment
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *
+ *     Returns 0 for SUCCESS or -1 if FAILED.
+ *
+ *     If -1 is return, then it was not possible to set the flags
+ **/
+int
+mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
+{
+       unsigned long    flags;
+       int              retval;
+
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress ||
+           (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) {
+               retval = -1;
+               goto out;
+       }
+       retval = 0;
+       ioc->taskmgmt_in_progress = 1;
+       ioc->taskmgmt_quiesce_io = 1;
+       if (ioc->alt_ioc) {
+               ioc->alt_ioc->taskmgmt_in_progress = 1;
+               ioc->alt_ioc->taskmgmt_quiesce_io = 1;
+       }
+ out:
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+       return retval;
+}
+EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag);
+
+/**
+ *     mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task managment
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *
+ **/
+void
+mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
+{
+       unsigned long    flags;
+
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       ioc->taskmgmt_in_progress = 0;
+       ioc->taskmgmt_quiesce_io = 0;
+       if (ioc->alt_ioc) {
+               ioc->alt_ioc->taskmgmt_in_progress = 0;
+               ioc->alt_ioc->taskmgmt_quiesce_io = 0;
+       }
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+}
+EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag);
 
 
 /**
@@ -6397,7 +6957,9 @@ int
 mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
 {
        int              rc;
+       u8       cb_idx;
        unsigned long    flags;
+       unsigned long    time_count;
 
        dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
 #ifdef MFCNT
@@ -6410,14 +6972,15 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
        /* Reset the adapter. Prevent more than 1 call to
         * mpt_do_ioc_recovery at any instant in time.
         */
-       spin_lock_irqsave(&ioc->diagLock, flags);
-       if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
-               spin_unlock_irqrestore(&ioc->diagLock, flags);
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       if (ioc->ioc_reset_in_progress) {
+               spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
                return 0;
-       } else {
-               ioc->diagPending = 1;
        }
-       spin_unlock_irqrestore(&ioc->diagLock, flags);
+       ioc->ioc_reset_in_progress = 1;
+       if (ioc->alt_ioc)
+               ioc->alt_ioc->ioc_reset_in_progress = 1;
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
 
        /* FIXME: If do_ioc_recovery fails, repeat....
         */
@@ -6427,47 +6990,57 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
         * Prevents timeouts occurring during a diagnostic reset...very bad.
         * For all other protocol drivers, this is a no-op.
         */
-       {
-               u8       cb_idx;
-               int      r = 0;
-
-               for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
-                       if (MptResetHandlers[cb_idx]) {
-                               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
-                                               ioc->name, cb_idx));
-                               r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
-                               if (ioc->alt_ioc) {
-                                       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
-                                                       ioc->name, ioc->alt_ioc->name, cb_idx));
-                                       r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
-                               }
-                       }
+       for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+               if (MptResetHandlers[cb_idx]) {
+                       mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
+                       if (ioc->alt_ioc)
+                               mpt_signal_reset(cb_idx, ioc->alt_ioc,
+                                       MPT_IOC_SETUP_RESET);
                }
        }
 
-       if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
-               printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
+       time_count = jiffies;
+       rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag);
+       if (rc != 0) {
+               printk(KERN_WARNING MYNAM
+                   ": WARNING - (%d) Cannot recover %s\n", rc, ioc->name);
+       } else {
+               if (ioc->hard_resets < -1)
+                       ioc->hard_resets++;
        }
-       ioc->reload_fw = 0;
-       if (ioc->alt_ioc)
-               ioc->alt_ioc->reload_fw = 0;
 
-       spin_lock_irqsave(&ioc->diagLock, flags);
-       ioc->diagPending = 0;
-       if (ioc->alt_ioc)
-               ioc->alt_ioc->diagPending = 0;
-       spin_unlock_irqrestore(&ioc->diagLock, flags);
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       ioc->ioc_reset_in_progress = 0;
+       ioc->taskmgmt_quiesce_io = 0;
+       ioc->taskmgmt_in_progress = 0;
+       if (ioc->alt_ioc) {
+               ioc->alt_ioc->ioc_reset_in_progress = 0;
+               ioc->alt_ioc->taskmgmt_quiesce_io = 0;
+               ioc->alt_ioc->taskmgmt_in_progress = 0;
+       }
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
 
-       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
+       dtmprintk(ioc,
+           printk(MYIOC_s_DEBUG_FMT
+               "HardResetHandler: completed (%d seconds): %s\n", ioc->name,
+               jiffies_to_msecs(jiffies - time_count)/1000, ((rc == 0) ?
+               "SUCCESS" : "FAILED")));
 
        return rc;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#ifdef CONFIG_FUSION_LOGGING
 static void
-EventDescriptionStr(u8 event, u32 evData0, char *evStr)
+mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
 {
        char *ds = NULL;
+       u32 evData0;
+       int ii;
+       u8 event;
+       char *evStr = ioc->evStr;
+
+       event = le32_to_cpu(pEventReply->Event) & 0xFF;
+       evData0 = le32_to_cpu(pEventReply->Data[0]);
 
        switch(event) {
        case MPI_EVENT_NONE:
@@ -6501,9 +7074,9 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
                if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
                        ds = "Loop State(LIP) Change";
                else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
-                       ds = "Loop State(LPE) Change";          /* ??? */
+                       ds = "Loop State(LPE) Change";
                else
-                       ds = "Loop State(LPB) Change";          /* ??? */
+                       ds = "Loop State(LPB) Change";
                break;
        case MPI_EVENT_LOGOUT:
                ds = "Logout";
@@ -6703,28 +7276,65 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
        }
        case MPI_EVENT_IR2:
        {
+               u8 id = (u8)(evData0);
+               u8 channel = (u8)(evData0 >> 8);
+               u8 phys_num = (u8)(evData0 >> 24);
                u8 ReasonCode = (u8)(evData0 >> 16);
+
                switch (ReasonCode) {
                case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
-                       ds = "IR2: LD State Changed";
+                       snprintf(evStr, EVENT_DESCR_STR_SZ,
+                           "IR2: LD State Changed: "
+                           "id=%d channel=%d phys_num=%d",
+                           id, channel, phys_num);
                        break;
                case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
-                       ds = "IR2: PD State Changed";
+                       snprintf(evStr, EVENT_DESCR_STR_SZ,
+                           "IR2: PD State Changed "
+                           "id=%d channel=%d phys_num=%d",
+                           id, channel, phys_num);
                        break;
                case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
-                       ds = "IR2: Bad Block Table Full";
+                       snprintf(evStr, EVENT_DESCR_STR_SZ,
+                           "IR2: Bad Block Table Full: "
+                           "id=%d channel=%d phys_num=%d",
+                           id, channel, phys_num);
                        break;
                case MPI_EVENT_IR2_RC_PD_INSERTED:
-                       ds = "IR2: PD Inserted";
+                       snprintf(evStr, EVENT_DESCR_STR_SZ,
+                           "IR2: PD Inserted: "
+                           "id=%d channel=%d phys_num=%d",
+                           id, channel, phys_num);
                        break;
                case MPI_EVENT_IR2_RC_PD_REMOVED:
-                       ds = "IR2: PD Removed";
+                       snprintf(evStr, EVENT_DESCR_STR_SZ,
+                           "IR2: PD Removed: "
+                           "id=%d channel=%d phys_num=%d",
+                           id, channel, phys_num);
                        break;
                case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
-                       ds = "IR2: Foreign CFG Detected";
+                       snprintf(evStr, EVENT_DESCR_STR_SZ,
+                           "IR2: Foreign CFG Detected: "
+                           "id=%d channel=%d phys_num=%d",
+                           id, channel, phys_num);
                        break;
                case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
-                       ds = "IR2: Rebuild Medium Error";
+                       snprintf(evStr, EVENT_DESCR_STR_SZ,
+                           "IR2: Rebuild Medium Error: "
+                           "id=%d channel=%d phys_num=%d",
+                           id, channel, phys_num);
+                       break;
+               case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
+                       snprintf(evStr, EVENT_DESCR_STR_SZ,
+                           "IR2: Dual Port Added: "
+                           "id=%d channel=%d phys_num=%d",
+                           id, channel, phys_num);
+                       break;
+               case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
+                       snprintf(evStr, EVENT_DESCR_STR_SZ,
+                           "IR2: Dual Port Removed: "
+                           "id=%d channel=%d phys_num=%d",
+                           id, channel, phys_num);
                        break;
                default:
                        ds = "IR2";
@@ -6760,13 +7370,18 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
        case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
        {
                u8 reason = (u8)(evData0);
-               u8 port_num = (u8)(evData0 >> 8);
-               u16 handle = le16_to_cpu(evData0 >> 16);
 
-               snprintf(evStr, EVENT_DESCR_STR_SZ,
-                   "SAS Initiator Device Status Change: reason=0x%02x "
-                   "port=%d handle=0x%04x",
-                   reason, port_num, handle);
+               switch (reason) {
+               case MPI_EVENT_SAS_INIT_RC_ADDED:
+                       ds = "SAS Initiator Status Change: Added";
+                       break;
+               case MPI_EVENT_SAS_INIT_RC_REMOVED:
+                       ds = "SAS Initiator Status Change: Deleted";
+                       break;
+               default:
+                       ds = "SAS Initiator Status Change";
+                       break;
+               }
                break;
        }
 
@@ -6814,6 +7429,24 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
                break;
        }
 
+       case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
+       {
+               u8 reason = (u8)(evData0);
+
+               switch (reason) {
+               case MPI_EVENT_SAS_EXP_RC_ADDED:
+                       ds = "Expander Status Change: Added";
+                       break;
+               case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING:
+                       ds = "Expander Status Change: Deleted";
+                       break;
+               default:
+                       ds = "Expander Status Change";
+                       break;
+               }
+               break;
+       }
+
        /*
         *  MPT base "custom" events may be added here...
         */
@@ -6823,8 +7456,20 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
        }
        if (ds)
                strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
-}
 
+
+       devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "MPT event:(%02Xh) : %s\n",
+           ioc->name, event, evStr));
+
+       devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
+           ": Event data:\n"));
+       for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++)
+               devtverboseprintk(ioc, printk(" %08x",
+                   le32_to_cpu(pEventReply->Data[ii])));
+       devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
+}
+#endif
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     ProcessEventNotification - Route EventNotificationReply to all event handlers
@@ -6841,37 +7486,24 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
 {
        u16 evDataLen;
        u32 evData0 = 0;
-//     u32 evCtx;
        int ii;
        u8 cb_idx;
        int r = 0;
        int handlers = 0;
-       char evStr[EVENT_DESCR_STR_SZ];
        u8 event;
 
        /*
         *  Do platform normalization of values
         */
        event = le32_to_cpu(pEventReply->Event) & 0xFF;
-//     evCtx = le32_to_cpu(pEventReply->EventContext);
        evDataLen = le16_to_cpu(pEventReply->EventDataLength);
        if (evDataLen) {
                evData0 = le32_to_cpu(pEventReply->Data[0]);
        }
 
-       EventDescriptionStr(event, evData0, evStr);
-       devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
-                       ioc->name,
-                       event,
-                       evStr));
-
 #ifdef CONFIG_FUSION_LOGGING
-       devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-           ": Event data:\n", ioc->name));
-       for (ii = 0; ii < evDataLen; ii++)
-               devtverboseprintk(ioc, printk(" %08x",
-                   le32_to_cpu(pEventReply->Data[ii])));
-       devtverboseprintk(ioc, printk("\n"));
+       if (evDataLen)
+               mpt_display_event_info(ioc, pEventReply);
 #endif
 
        /*
@@ -6926,8 +7558,9 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
         */
        for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
                if (MptEvHandlers[cb_idx]) {
-                       devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
-                                       ioc->name, cb_idx));
+                       devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                           "Routing Event to event handler #%d\n",
+                           ioc->name, cb_idx));
                        r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
                        handlers++;
                }
@@ -7011,8 +7644,6 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
        switch (info) {
        case 0x00010000:
                desc = "bug! MID not found";
-               if (ioc->reload_fw == 0)
-                       ioc->reload_fw++;
                break;
 
        case 0x00020000:
@@ -7613,7 +8244,6 @@ EXPORT_SYMBOL(mpt_get_msg_frame);
 EXPORT_SYMBOL(mpt_put_msg_frame);
 EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
 EXPORT_SYMBOL(mpt_free_msg_frame);
-EXPORT_SYMBOL(mpt_add_sge);
 EXPORT_SYMBOL(mpt_send_handshake_request);
 EXPORT_SYMBOL(mpt_verify_adapter);
 EXPORT_SYMBOL(mpt_GetIocState);
@@ -7650,7 +8280,7 @@ fusion_init(void)
        /*  Register ourselves (mptbase) in order to facilitate
         *  EventNotification handling.
         */
-       mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
+       mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER);
 
        /* Register for hard reset handling callbacks.
         */
index b3e981d2a506fd6aeabd27795e7b492eb466344a..1c8514dc31ca3ec51df54ca2a9711f6fb085b02f 100644 (file)
@@ -76,8 +76,8 @@
 #define COPYRIGHT      "Copyright (c) 1999-2008 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON       "3.04.07"
-#define MPT_LINUX_PACKAGE_NAME         "@(#)mptlinux-3.04.07"
+#define MPT_LINUX_VERSION_COMMON       "3.04.10"
+#define MPT_LINUX_PACKAGE_NAME         "@(#)mptlinux-3.04.09"
 #define WHAT_MAGIC_STRING              "@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
 #endif
 
 #define MPT_NAME_LENGTH                        32
+#define MPT_KOBJ_NAME_LEN              20
 
 #define MPT_PROCFS_MPTBASEDIR          "mpt"
                                                /* chg it to "driver/fusion" ? */
 
 #define MPT_COALESCING_TIMEOUT         0x10
 
+
 /*
  * SCSI transfer rate defines.
  */
 /*
  * Set the MAX_SGE value based on user input.
  */
-#ifdef  CONFIG_FUSION_MAX_SGE
-#if     CONFIG_FUSION_MAX_SGE  < 16
+#ifdef CONFIG_FUSION_MAX_SGE
+#if CONFIG_FUSION_MAX_SGE  < 16
 #define MPT_SCSI_SG_DEPTH      16
-#elif   CONFIG_FUSION_MAX_SGE  > 128
+#elif CONFIG_FUSION_MAX_SGE  > 128
 #define MPT_SCSI_SG_DEPTH      128
 #else
 #define MPT_SCSI_SG_DEPTH      CONFIG_FUSION_MAX_SGE
 #define MPT_SCSI_SG_DEPTH      40
 #endif
 
+#ifdef CONFIG_FUSION_MAX_FC_SGE
+#if CONFIG_FUSION_MAX_FC_SGE  < 16
+#define MPT_SCSI_FC_SG_DEPTH   16
+#elif CONFIG_FUSION_MAX_FC_SGE  > 256
+#define MPT_SCSI_FC_SG_DEPTH   256
+#else
+#define MPT_SCSI_FC_SG_DEPTH   CONFIG_FUSION_MAX_FC_SGE
+#endif
+#else
+#define MPT_SCSI_FC_SG_DEPTH   40
+#endif
+
 /* debug print string length used for events and iocstatus */
 # define EVENT_DESCR_STR_SZ             100
 
@@ -431,38 +445,36 @@ do { \
  *     IOCTL structure and associated defines
  */
 
-#define MPT_IOCTL_STATUS_DID_IOCRESET  0x01    /* IOC Reset occurred on the current*/
-#define MPT_IOCTL_STATUS_RF_VALID      0x02    /* The Reply Frame is VALID */
-#define MPT_IOCTL_STATUS_TIMER_ACTIVE  0x04    /* The timer is running */
-#define MPT_IOCTL_STATUS_SENSE_VALID   0x08    /* Sense data is valid */
-#define MPT_IOCTL_STATUS_COMMAND_GOOD  0x10    /* Command Status GOOD */
-#define MPT_IOCTL_STATUS_TMTIMER_ACTIVE        0x20    /* The TM timer is running */
-#define MPT_IOCTL_STATUS_TM_FAILED     0x40    /* User TM request failed */
-
 #define MPTCTL_RESET_OK                        0x01    /* Issue Bus Reset */
 
-typedef struct _MPT_IOCTL {
-       struct _MPT_ADAPTER     *ioc;
-       u8                       ReplyFrame[MPT_DEFAULT_FRAME_SIZE];    /* reply frame data */
-       u8                       sense[MPT_SENSE_BUFFER_ALLOC];
-       int                      wait_done;     /* wake-up value for this ioc */
-       u8                       rsvd;
-       u8                       status;        /* current command status */
-       u8                       reset;         /* 1 if bus reset allowed */
-       u8                       id;            /* target for reset */
-       struct mutex             ioctl_mutex;
-} MPT_IOCTL;
-
-#define MPT_SAS_MGMT_STATUS_RF_VALID   0x02    /* The Reply Frame is VALID */
-#define MPT_SAS_MGMT_STATUS_COMMAND_GOOD       0x10    /* Command Status GOOD */
-#define MPT_SAS_MGMT_STATUS_TM_FAILED  0x40    /* User TM request failed */
-
-typedef struct _MPT_SAS_MGMT {
+#define MPT_MGMT_STATUS_RF_VALID       0x01    /* The Reply Frame is VALID */
+#define MPT_MGMT_STATUS_COMMAND_GOOD   0x02    /* Command Status GOOD */
+#define MPT_MGMT_STATUS_PENDING                0x04    /* command is pending */
+#define MPT_MGMT_STATUS_DID_IOCRESET   0x08    /* IOC Reset occurred
+                                                  on the current*/
+#define MPT_MGMT_STATUS_SENSE_VALID    0x10    /* valid sense info */
+#define MPT_MGMT_STATUS_TIMER_ACTIVE   0x20    /* obsolete */
+#define MPT_MGMT_STATUS_FREE_MF                0x40    /* free the mf from
+                                                  complete routine */
+
+#define INITIALIZE_MGMT_STATUS(status) \
+       status = MPT_MGMT_STATUS_PENDING;
+#define CLEAR_MGMT_STATUS(status) \
+       status = 0;
+#define CLEAR_MGMT_PENDING_STATUS(status) \
+       status &= ~MPT_MGMT_STATUS_PENDING;
+#define SET_MGMT_MSG_CONTEXT(msg_context, value) \
+       msg_context = value;
+
+typedef struct _MPT_MGMT {
        struct mutex             mutex;
        struct completion        done;
        u8                       reply[MPT_DEFAULT_FRAME_SIZE]; /* reply frame data */
+       u8                       sense[MPT_SENSE_BUFFER_ALLOC];
        u8                       status;        /* current command status */
-}MPT_SAS_MGMT;
+       int                      completion_code;
+       u32                      msg_context;
+} MPT_MGMT;
 
 /*
  *  Event Structure and define
@@ -564,6 +576,10 @@ struct mptfc_rport_info
        u8              flags;
 };
 
+typedef void (*MPT_ADD_SGE)(void *pAddr, u32 flagslength, dma_addr_t dma_addr);
+typedef void (*MPT_ADD_CHAIN)(void *pAddr, u8 next, u16 length,
+               dma_addr_t dma_addr);
+
 /*
  *  Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS
  */
@@ -573,6 +589,10 @@ typedef struct _MPT_ADAPTER
        int                      pci_irq;       /* This irq           */
        char                     name[MPT_NAME_LENGTH]; /* "iocN"             */
        char                     prod_name[MPT_NAME_LENGTH];    /* "LSIFC9x9"         */
+#ifdef CONFIG_FUSION_LOGGING
+       /* used in mpt_display_event_info */
+       char                     evStr[EVENT_DESCR_STR_SZ];
+#endif
        char                     board_name[16];
        char                     board_assembly[16];
        char                     board_tracer[16];
@@ -600,6 +620,10 @@ typedef struct _MPT_ADAPTER
        int                      reply_depth;   /* Num Allocated reply frames */
        int                      reply_sz;      /* Reply frame size */
        int                      num_chain;     /* Number of chain buffers */
+       MPT_ADD_SGE              add_sge;       /* Pointer to add_sge
+                                                  function */
+       MPT_ADD_CHAIN            add_chain;     /* Pointer to add_chain
+                                                  function */
                /* Pool of buffers for chaining. ReqToChain
                 * and ChainToChain track index of chain buffers.
                 * ChainBuffer (DMA) virt/phys addresses.
@@ -640,11 +664,8 @@ typedef struct _MPT_ADAPTER
        RaidCfgData             raid_data;      /* Raid config. data */
        SasCfgData              sas_data;       /* Sas config. data */
        FcCfgData               fc_data;        /* Fc config. data */
-       MPT_IOCTL               *ioctl;         /* ioctl data pointer */
        struct proc_dir_entry   *ioc_dentry;
        struct _MPT_ADAPTER     *alt_ioc;       /* ptr to 929 bound adapter port */
-       spinlock_t               diagLock;      /* diagnostic reset lock */
-       int                      diagPending;
        u32                      biosVersion;   /* BIOS version from IO Unit Page 2 */
        int                      eventTypes;    /* Event logging parameters */
        int                      eventContext;  /* Next event context */
@@ -652,7 +673,6 @@ typedef struct _MPT_ADAPTER
        struct _mpt_ioctl_events *events;       /* pointer to event log */
        u8                      *cached_fw;     /* Pointer to FW */
        dma_addr_t              cached_fw_dma;
-       struct list_head         configQ;       /* linked list of config. requests */
        int                      hs_reply_idx;
 #ifndef MFCNT
        u32                      pad0;
@@ -665,9 +685,6 @@ typedef struct _MPT_ADAPTER
        IOCFactsReply_t          facts;
        PortFactsReply_t         pfacts[2];
        FCPortPage0_t            fc_port_page0[2];
-       struct timer_list        persist_timer; /* persist table timer */
-       int                      persist_wait_done; /* persist completion flag */
-       u8                       persist_reply_frame[MPT_DEFAULT_FRAME_SIZE]; /* persist reply */
        LANPage0_t               lan_cnfg_page0;
        LANPage1_t               lan_cnfg_page1;
 
@@ -682,23 +699,44 @@ typedef struct _MPT_ADAPTER
        int                      aen_event_read_flag; /* flag to indicate event log was read*/
        u8                       FirstWhoInit;
        u8                       upload_fw;     /* If set, do a fw upload */
-       u8                       reload_fw;     /* Force a FW Reload on next reset */
        u8                       NBShiftFactor;  /* NB Shift Factor based on Block Size (Facts)  */
        u8                       pad1[4];
        u8                       DoneCtx;
        u8                       TaskCtx;
        u8                       InternalCtx;
-       spinlock_t               initializing_hba_lock;
-       int                      initializing_hba_lock_flag;
        struct list_head         list;
        struct net_device       *netdev;
        struct list_head         sas_topology;
        struct mutex             sas_topology_mutex;
+
+       struct workqueue_struct *fw_event_q;
+       struct list_head         fw_event_list;
+       spinlock_t               fw_event_lock;
+       u8                       fw_events_off; /* if '1', then ignore events */
+       char                     fw_event_q_name[MPT_KOBJ_NAME_LEN];
+
        struct mutex             sas_discovery_mutex;
        u8                       sas_discovery_runtime;
        u8                       sas_discovery_ignore_events;
+
+       /* port_info object for the host */
+       struct mptsas_portinfo  *hba_port_info;
+       u64                      hba_port_sas_addr;
+       u16                      hba_port_num_phy;
+       struct list_head         sas_device_info_list;
+       struct mutex             sas_device_info_mutex;
+       u8                       old_sas_discovery_protocal;
+       u8                       sas_discovery_quiesce_io;
        int                      sas_index; /* index refrencing */
-       MPT_SAS_MGMT             sas_mgmt;
+       MPT_MGMT                 sas_mgmt;
+       MPT_MGMT                 mptbase_cmds; /* for sending config pages */
+       MPT_MGMT                 internal_cmds;
+       MPT_MGMT                 taskmgmt_cmds;
+       MPT_MGMT                 ioctl_cmds;
+       spinlock_t               taskmgmt_lock; /* diagnostic reset lock */
+       int                      taskmgmt_in_progress;
+       u8                       taskmgmt_quiesce_io;
+       u8                       ioc_reset_in_progress;
        struct work_struct       sas_persist_task;
 
        struct work_struct       fc_setup_reset_work;
@@ -707,15 +745,27 @@ typedef struct _MPT_ADAPTER
        u8                       fc_link_speed[2];
        spinlock_t               fc_rescan_work_lock;
        struct work_struct       fc_rescan_work;
-       char                     fc_rescan_work_q_name[20];
+       char                     fc_rescan_work_q_name[MPT_KOBJ_NAME_LEN];
        struct workqueue_struct *fc_rescan_work_q;
+
+       /* driver forced bus resets count */
+       unsigned long             hard_resets;
+       /* fw/external bus resets count */
+       unsigned long             soft_resets;
+       /* cmd timeouts */
+       unsigned long             timeouts;
+
        struct scsi_cmnd        **ScsiLookup;
        spinlock_t                scsi_lookup_lock;
-
-       char                     reset_work_q_name[20];
+       u64                     dma_mask;
+       u32                       broadcast_aen_busy;
+       char                     reset_work_q_name[MPT_KOBJ_NAME_LEN];
        struct workqueue_struct *reset_work_q;
        struct delayed_work      fault_reset_work;
-       spinlock_t               fault_reset_work_lock;
+
+       u8                      sg_addr_size;
+       u8                      in_rescan;
+       u8                      SGE_size;
 
 } MPT_ADAPTER;
 
@@ -753,13 +803,14 @@ typedef struct _mpt_sge {
        dma_addr_t      Address;
 } MptSge_t;
 
-#define mpt_addr_size() \
-       ((sizeof(dma_addr_t) == sizeof(u64)) ? MPI_SGE_FLAGS_64_BIT_ADDRESSING : \
-               MPI_SGE_FLAGS_32_BIT_ADDRESSING)
 
-#define mpt_msg_flags() \
-       ((sizeof(dma_addr_t) == sizeof(u64)) ? MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 : \
-               MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32)
+#define mpt_msg_flags(ioc) \
+       (ioc->sg_addr_size == sizeof(u64)) ?            \
+       MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 :             \
+       MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32
+
+#define MPT_SGE_FLAGS_64_BIT_ADDRESSING \
+       (MPI_SGE_FLAGS_64_BIT_ADDRESSING << MPI_SGE_FLAGS_SHIFT)
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -835,22 +886,14 @@ typedef struct _MPT_SCSI_HOST {
                /* Pool of memory for holding SCpnts before doing
                 * OS callbacks. freeQ is the free pool.
                 */
-       u8                        tmPending;
-       u8                        resetPending;
        u8                        negoNvram;            /* DV disabled, nego NVRAM */
        u8                        pad1;
-       u8                        tmState;
        u8                        rsvd[2];
        MPT_FRAME_HDR            *cmdPtr;               /* Ptr to nonOS request */
        struct scsi_cmnd         *abortSCpnt;
        MPT_LOCAL_REPLY           localReply;           /* internal cmd reply struct */
-       unsigned long             hard_resets;          /* driver forced bus resets count */
-       unsigned long             soft_resets;          /* fw/external bus resets count */
-       unsigned long             timeouts;             /* cmd timeouts */
        ushort                    sel_timeout[MPT_MAX_FC_DEVICES];
        char                      *info_kbuf;
-       wait_queue_head_t         scandv_waitq;
-       int                       scandv_wait_done;
        long                      last_queue_full;
        u16                       tm_iocstatus;
        u16                       spi_pending;
@@ -870,21 +913,16 @@ struct scsi_cmnd;
  * Generic structure passed to the base mpt_config function.
  */
 typedef struct _x_config_parms {
-       struct list_head         linkage;       /* linked list */
-       struct timer_list        timer;         /* timer function for this request  */
        union {
                ConfigExtendedPageHeader_t      *ehdr;
                ConfigPageHeader_t      *hdr;
        } cfghdr;
        dma_addr_t               physAddr;
-       int                      wait_done;     /* wait for this request */
        u32                      pageAddr;      /* properly formatted */
+       u16                      status;
        u8                       action;
        u8                       dir;
        u8                       timeout;       /* seconds */
-       u8                       pad1;
-       u16                      status;
-       u16                      pad2;
 } CONFIGPARMS;
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -909,7 +947,6 @@ extern MPT_FRAME_HDR        *mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc);
 extern void     mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
 extern void     mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
 extern void     mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
-extern void     mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr);
 
 extern int      mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag);
 extern int      mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp);
@@ -922,6 +959,12 @@ extern void         mpt_free_fw_memory(MPT_ADAPTER *ioc);
 extern int      mpt_findImVolumes(MPT_ADAPTER *ioc);
 extern int      mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
 extern int      mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk);
+extern int     mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num,
+               pRaidPhysDiskPage1_t phys_disk);
+extern int     mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc,
+               u8 phys_disk_num);
+extern int      mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc);
+extern void     mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc);
 extern void     mpt_halt_firmware(MPT_ADAPTER *ioc);
 
 
@@ -959,7 +1002,6 @@ extern int mpt_fwfault_debug;
 #define MPT_SGE_FLAGS_END_OF_BUFFER            (0x40000000)
 #define MPT_SGE_FLAGS_LOCAL_ADDRESS            (0x08000000)
 #define MPT_SGE_FLAGS_DIRECTION                        (0x04000000)
-#define MPT_SGE_FLAGS_ADDRESSING               (mpt_addr_size() << MPI_SGE_FLAGS_SHIFT)
 #define MPT_SGE_FLAGS_END_OF_LIST              (0x01000000)
 
 #define MPT_SGE_FLAGS_TRANSACTION_ELEMENT      (0x00000000)
@@ -972,14 +1014,12 @@ extern int mpt_fwfault_debug;
         MPT_SGE_FLAGS_END_OF_BUFFER |  \
         MPT_SGE_FLAGS_END_OF_LIST |    \
         MPT_SGE_FLAGS_SIMPLE_ELEMENT | \
-        MPT_SGE_FLAGS_ADDRESSING | \
         MPT_TRANSFER_IOC_TO_HOST)
 #define MPT_SGE_FLAGS_SSIMPLE_WRITE \
        (MPT_SGE_FLAGS_LAST_ELEMENT |   \
         MPT_SGE_FLAGS_END_OF_BUFFER |  \
         MPT_SGE_FLAGS_END_OF_LIST |    \
         MPT_SGE_FLAGS_SIMPLE_ELEMENT | \
-        MPT_SGE_FLAGS_ADDRESSING | \
         MPT_TRANSFER_HOST_TO_IOC)
 
 /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
index c63817117c0a881a3855fad1399790429b2da3cc..9b2e2198aee9dd07c12328c026fd7712bac95c03 100644 (file)
@@ -84,6 +84,7 @@ MODULE_VERSION(my_VERSION);
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
 static u8 mptctl_id = MPT_MAX_PROTOCOL_DRIVERS;
+static u8 mptctl_taskmgmt_id = MPT_MAX_PROTOCOL_DRIVERS;
 
 static DECLARE_WAIT_QUEUE_HEAD ( mptctl_wait );
 
@@ -127,10 +128,7 @@ static MptSge_t *kbuf_alloc_2_sgl(int bytes, u32 dir, int sge_offset, int *frags
                struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc);
 static void kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma,
                struct buflist *buflist, MPT_ADAPTER *ioc);
-static void mptctl_timeout_expired (MPT_IOCTL *ioctl);
-static int  mptctl_bus_reset(MPT_IOCTL *ioctl);
-static int mptctl_set_tm_flags(MPT_SCSI_HOST *hd);
-static void mptctl_free_tm_flags(MPT_ADAPTER *ioc);
+static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function);
 
 /*
  * Reset Handler cleanup function
@@ -183,10 +181,10 @@ mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock)
        int rc = 0;
 
        if (nonblock) {
-               if (!mutex_trylock(&ioc->ioctl->ioctl_mutex))
+               if (!mutex_trylock(&ioc->ioctl_cmds.mutex))
                        rc = -EAGAIN;
        } else {
-               if (mutex_lock_interruptible(&ioc->ioctl->ioctl_mutex))
+               if (mutex_lock_interruptible(&ioc->ioctl_cmds.mutex))
                        rc = -ERESTARTSYS;
        }
        return rc;
@@ -202,99 +200,78 @@ mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock)
 static int
 mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
 {
-       char *sense_data;
-       int sz, req_index;
-       u16 iocStatus;
-       u8 cmd;
+       char    *sense_data;
+       int     req_index;
+       int     sz;
 
-       if (req)
-                cmd = req->u.hdr.Function;
-       else
-               return 1;
-       dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\tcompleting mpi function (0x%02X), req=%p, "
-           "reply=%p\n", ioc->name,  req->u.hdr.Function, req, reply));
-
-       if (ioc->ioctl) {
-
-               if (reply==NULL) {
-
-                       dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_reply() NULL Reply "
-                               "Function=%x!\n", ioc->name, cmd));
+       if (!req)
+               return 0;
 
-                       ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
-                       ioc->ioctl->reset &= ~MPTCTL_RESET_OK;
+       dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "completing mpi function "
+           "(0x%02X), req=%p, reply=%p\n", ioc->name,  req->u.hdr.Function,
+           req, reply));
 
-                       /* We are done, issue wake up
-                       */
-                       ioc->ioctl->wait_done = 1;
-                       wake_up (&mptctl_wait);
-                       return 1;
+       /*
+        * Handling continuation of the same reply. Processing the first
+        * reply, and eating the other replys that come later.
+        */
+       if (ioc->ioctl_cmds.msg_context != req->u.hdr.MsgContext)
+               goto out_continuation;
 
-               }
+       ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
 
-               /* Copy the reply frame (which much exist
-                * for non-SCSI I/O) to the IOC structure.
-                */
-               memcpy(ioc->ioctl->ReplyFrame, reply,
-                       min(ioc->reply_sz, 4*reply->u.reply.MsgLength));
-               ioc->ioctl->status |= MPT_IOCTL_STATUS_RF_VALID;
+       if (!reply)
+               goto out;
 
-               /* Set the command status to GOOD if IOC Status is GOOD
-                * OR if SCSI I/O cmd and data underrun or recovered error.
-                */
-               iocStatus = le16_to_cpu(reply->u.reply.IOCStatus) & MPI_IOCSTATUS_MASK;
-               if (iocStatus  == MPI_IOCSTATUS_SUCCESS)
-                       ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
-
-               if (iocStatus || reply->u.reply.IOCLogInfo)
-                       dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\tiocstatus (0x%04X), "
-                               "loginfo (0x%08X)\n", ioc->name,
-                               iocStatus,
-                               le32_to_cpu(reply->u.reply.IOCLogInfo)));
-
-               if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
-                       (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
-
-                       if (reply->u.sreply.SCSIStatus || reply->u.sreply.SCSIState)
-                               dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                                       "\tscsi_status (0x%02x), scsi_state (0x%02x), "
-                                       "tag = (0x%04x), transfer_count (0x%08x)\n", ioc->name,
-                                       reply->u.sreply.SCSIStatus,
-                                       reply->u.sreply.SCSIState,
-                                       le16_to_cpu(reply->u.sreply.TaskTag),
-                                       le32_to_cpu(reply->u.sreply.TransferCount)));
-
-                       ioc->ioctl->reset &= ~MPTCTL_RESET_OK;
-
-                       if ((iocStatus == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN) ||
-                       (iocStatus == MPI_IOCSTATUS_SCSI_RECOVERED_ERROR)) {
-                       ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
-                       }
-               }
+       ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
+       sz = min(ioc->reply_sz, 4*reply->u.reply.MsgLength);
+       memcpy(ioc->ioctl_cmds.reply, reply, sz);
 
-               /* Copy the sense data - if present
-                */
-               if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) &&
-                       (reply->u.sreply.SCSIState &
-                        MPI_SCSI_STATE_AUTOSENSE_VALID)){
+       if (reply->u.reply.IOCStatus || reply->u.reply.IOCLogInfo)
+               dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "iocstatus (0x%04X), loginfo (0x%08X)\n", ioc->name,
+                   le16_to_cpu(reply->u.reply.IOCStatus),
+                   le32_to_cpu(reply->u.reply.IOCLogInfo)));
+
+       if ((req->u.hdr.Function == MPI_FUNCTION_SCSI_IO_REQUEST) ||
+               (req->u.hdr.Function ==
+                MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
+
+               if (reply->u.sreply.SCSIStatus || reply->u.sreply.SCSIState)
+                       dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                       "scsi_status (0x%02x), scsi_state (0x%02x), "
+                       "tag = (0x%04x), transfer_count (0x%08x)\n", ioc->name,
+                       reply->u.sreply.SCSIStatus,
+                       reply->u.sreply.SCSIState,
+                       le16_to_cpu(reply->u.sreply.TaskTag),
+                       le32_to_cpu(reply->u.sreply.TransferCount)));
+
+               if (reply->u.sreply.SCSIState &
+                       MPI_SCSI_STATE_AUTOSENSE_VALID) {
                        sz = req->u.scsireq.SenseBufferLength;
                        req_index =
                            le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
-                       sense_data =
-                           ((u8 *)ioc->sense_buf_pool +
+                       sense_data = ((u8 *)ioc->sense_buf_pool +
                             (req_index * MPT_SENSE_BUFFER_ALLOC));
-                       memcpy(ioc->ioctl->sense, sense_data, sz);
-                       ioc->ioctl->status |= MPT_IOCTL_STATUS_SENSE_VALID;
+                       memcpy(ioc->ioctl_cmds.sense, sense_data, sz);
+                       ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_SENSE_VALID;
                }
+       }
 
-               if (cmd == MPI_FUNCTION_SCSI_TASK_MGMT)
-                       mptctl_free_tm_flags(ioc);
-
-               /* We are done, issue wake up
-                */
-               ioc->ioctl->wait_done = 1;
-               wake_up (&mptctl_wait);
+ out:
+       /* We are done, issue wake up
+        */
+       if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) {
+               if (req->u.hdr.Function == MPI_FUNCTION_SCSI_TASK_MGMT)
+                       mpt_clear_taskmgmt_in_progress_flag(ioc);
+               ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+               complete(&ioc->ioctl_cmds.done);
        }
+
+ out_continuation:
+       if (reply && (reply->u.reply.MsgFlags &
+           MPI_MSGFLAGS_CONTINUATION_REPLY))
+               return 0;
        return 1;
 }
 
@@ -304,30 +281,66 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
  * Expecting an interrupt, however timed out.
  *
  */
-static void mptctl_timeout_expired (MPT_IOCTL *ioctl)
+static void
+mptctl_timeout_expired(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
 {
-       int rc = 1;
+       unsigned long flags;
 
-       if (ioctl == NULL)
-               return;
-       dctlprintk(ioctl->ioc,
-                  printk(MYIOC_s_DEBUG_FMT ": Timeout Expired! Host %d\n",
-                  ioctl->ioc->name, ioctl->ioc->id));
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": %s\n",
+               ioc->name, __func__));
 
-       ioctl->wait_done = 0;
-       if (ioctl->reset & MPTCTL_RESET_OK)
-               rc = mptctl_bus_reset(ioctl);
+       if (mpt_fwfault_debug)
+               mpt_halt_firmware(ioc);
 
-       if (rc) {
-               /* Issue a reset for this device.
-                * The IOC is not responding.
-                */
-               dctlprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
-                        ioctl->ioc->name));
-               mpt_HardResetHandler(ioctl->ioc, CAN_SLEEP);
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       if (ioc->ioc_reset_in_progress) {
+               spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+               CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
+               mpt_free_msg_frame(ioc, mf);
+               return;
        }
-       return;
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+
 
+       if (!mptctl_bus_reset(ioc, mf->u.hdr.Function))
+               return;
+
+       /* Issue a reset for this device.
+        * The IOC is not responding.
+        */
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
+                ioc->name));
+       CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
+       mpt_HardResetHandler(ioc, CAN_SLEEP);
+       mpt_free_msg_frame(ioc, mf);
+}
+
+static int
+mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
+{
+       if (!mf)
+               return 0;
+
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+               "TaskMgmt completed (mf=%p, mr=%p)\n",
+               ioc->name, mf, mr));
+
+       ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
+
+       if (!mr)
+               goto out;
+
+       ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
+       memcpy(ioc->taskmgmt_cmds.reply, mr,
+           min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
+ out:
+       if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
+               mpt_clear_taskmgmt_in_progress_flag(ioc);
+               ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+               complete(&ioc->taskmgmt_cmds.done);
+               return 1;
+       }
+       return 0;
 }
 
 /* mptctl_bus_reset
@@ -335,133 +348,150 @@ static void mptctl_timeout_expired (MPT_IOCTL *ioctl)
  * Bus reset code.
  *
  */
-static int mptctl_bus_reset(MPT_IOCTL *ioctl)
+static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
 {
        MPT_FRAME_HDR   *mf;
        SCSITaskMgmt_t  *pScsiTm;
-       MPT_SCSI_HOST   *hd;
+       SCSITaskMgmtReply_t *pScsiTmReply;
        int              ii;
-       int              retval=0;
-
-
-       ioctl->reset &= ~MPTCTL_RESET_OK;
-
-       if (ioctl->ioc->sh == NULL)
+       int              retval;
+       unsigned long    timeout;
+       unsigned long    time_count;
+       u16              iocstatus;
+
+       /* bus reset is only good for SCSI IO, RAID PASSTHRU */
+       if (!(function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) ||
+           (function == MPI_FUNCTION_SCSI_IO_REQUEST)) {
+               dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
+                       "TaskMgmt, not SCSI_IO!!\n", ioc->name));
                return -EPERM;
+       }
 
-       hd = shost_priv(ioctl->ioc->sh);
-       if (hd == NULL)
+       mutex_lock(&ioc->taskmgmt_cmds.mutex);
+       if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
+               mutex_unlock(&ioc->taskmgmt_cmds.mutex);
                return -EPERM;
+       }
 
-       /* Single threading ....
-        */
-       if (mptctl_set_tm_flags(hd) != 0)
-               return -EPERM;
+       retval = 0;
 
        /* Send request
         */
-       if ((mf = mpt_get_msg_frame(mptctl_id, ioctl->ioc)) == NULL) {
-               dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt, no msg frames!!\n",
-                               ioctl->ioc->name));
-
-               mptctl_free_tm_flags(ioctl->ioc);
-               return -ENOMEM;
+       mf = mpt_get_msg_frame(mptctl_taskmgmt_id, ioc);
+       if (mf == NULL) {
+               dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
+                       "TaskMgmt, no msg frames!!\n", ioc->name));
+               mpt_clear_taskmgmt_in_progress_flag(ioc);
+               retval = -ENOMEM;
+               goto mptctl_bus_reset_done;
        }
 
-       dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
-                       ioctl->ioc->name, mf));
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
+               ioc->name, mf));
 
        pScsiTm = (SCSITaskMgmt_t *) mf;
-       pScsiTm->TargetID = ioctl->id;
-       pScsiTm->Bus = hd->port;        /* 0 */
-       pScsiTm->ChainOffset = 0;
+       memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
        pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
-       pScsiTm->Reserved = 0;
        pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
-       pScsiTm->Reserved1 = 0;
        pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
-
+       pScsiTm->TargetID = 0;
+       pScsiTm->Bus = 0;
+       pScsiTm->ChainOffset = 0;
+       pScsiTm->Reserved = 0;
+       pScsiTm->Reserved1 = 0;
+       pScsiTm->TaskMsgContext = 0;
        for (ii= 0; ii < 8; ii++)
                pScsiTm->LUN[ii] = 0;
-
        for (ii=0; ii < 7; ii++)
                pScsiTm->Reserved2[ii] = 0;
 
-       pScsiTm->TaskMsgContext = 0;
-       dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT
-               "mptctl_bus_reset: issued.\n", ioctl->ioc->name));
-
-       DBG_DUMP_TM_REQUEST_FRAME(ioctl->ioc, (u32 *)mf);
+       switch (ioc->bus_type) {
+       case FC:
+               timeout = 40;
+               break;
+       case SAS:
+               timeout = 30;
+               break;
+       case SPI:
+       default:
+               timeout = 2;
+               break;
+       }
 
-       ioctl->wait_done=0;
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+               "TaskMgmt type=%d timeout=%ld\n",
+               ioc->name, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, timeout));
 
-       if ((ioctl->ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
-           (ioctl->ioc->facts.MsgVersion >= MPI_VERSION_01_05))
-               mpt_put_msg_frame_hi_pri(mptctl_id, ioctl->ioc, mf);
+       INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+       CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+       time_count = jiffies;
+       if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
+           (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
+               mpt_put_msg_frame_hi_pri(mptctl_taskmgmt_id, ioc, mf);
        else {
-               retval = mpt_send_handshake_request(mptctl_id, ioctl->ioc,
-                       sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
+               retval = mpt_send_handshake_request(mptctl_taskmgmt_id, ioc,
+                   sizeof(SCSITaskMgmt_t), (u32 *)pScsiTm, CAN_SLEEP);
                if (retval != 0) {
-                       dfailprintk(ioctl->ioc, printk(MYIOC_s_ERR_FMT "_send_handshake FAILED!"
-                               " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
-                               hd->ioc, mf));
+                       dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                               "TaskMgmt send_handshake FAILED!"
+                               " (ioc %p, mf %p, rc=%d) \n", ioc->name,
+                               ioc, mf, retval));
+                       mpt_clear_taskmgmt_in_progress_flag(ioc);
                        goto mptctl_bus_reset_done;
                }
        }
 
        /* Now wait for the command to complete */
-       ii = wait_event_timeout(mptctl_wait,
-            ioctl->wait_done == 1,
-            HZ*5 /* 5 second timeout */);
+       ii = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ);
+       if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "TaskMgmt failed\n", ioc->name));
+               mpt_free_msg_frame(ioc, mf);
+               mpt_clear_taskmgmt_in_progress_flag(ioc);
+               if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
+                       retval = 0;
+               else
+                       retval = -1; /* return failure */
+               goto mptctl_bus_reset_done;
+       }
 
-       if(ii <=0 && (ioctl->wait_done != 1 ))  {
-               mpt_free_msg_frame(hd->ioc, mf);
-               ioctl->wait_done = 0;
+       if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "TaskMgmt failed\n", ioc->name));
+               retval = -1; /* return failure */
+               goto mptctl_bus_reset_done;
+       }
+
+       pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "TaskMgmt fw_channel = %d, fw_id = %d, task_type=0x%02X, "
+           "iocstatus=0x%04X\n\tloginfo=0x%08X, response_code=0x%02X, "
+           "term_cmnds=%d\n", ioc->name, pScsiTmReply->Bus,
+           pScsiTmReply->TargetID, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+           le16_to_cpu(pScsiTmReply->IOCStatus),
+           le32_to_cpu(pScsiTmReply->IOCLogInfo),
+           pScsiTmReply->ResponseCode,
+           le32_to_cpu(pScsiTmReply->TerminationCount)));
+
+       iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+
+       if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
+          iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED ||
+          iocstatus == MPI_IOCSTATUS_SUCCESS)
+               retval = 0;
+       else {
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "TaskMgmt failed\n", ioc->name));
                retval = -1; /* return failure */
        }
 
-mptctl_bus_reset_done:
 
-       mptctl_free_tm_flags(ioctl->ioc);
+ mptctl_bus_reset_done:
+       mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+       CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
        return retval;
 }
 
-static int
-mptctl_set_tm_flags(MPT_SCSI_HOST *hd) {
-       unsigned long flags;
-
-       spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
-
-       if (hd->tmState == TM_STATE_NONE) {
-               hd->tmState = TM_STATE_IN_PROGRESS;
-               hd->tmPending = 1;
-               spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
-       } else {
-               spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
-               return -EBUSY;
-       }
-
-       return 0;
-}
-
-static void
-mptctl_free_tm_flags(MPT_ADAPTER *ioc)
-{
-       MPT_SCSI_HOST * hd;
-       unsigned long flags;
-
-       hd = shost_priv(ioc->sh);
-       if (hd == NULL)
-               return;
-
-       spin_lock_irqsave(&ioc->FreeQlock, flags);
-
-       hd->tmState = TM_STATE_NONE;
-       hd->tmPending = 0;
-       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-
-       return;
-}
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /* mptctl_ioc_reset
@@ -473,22 +503,23 @@ mptctl_free_tm_flags(MPT_ADAPTER *ioc)
 static int
 mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 {
-       MPT_IOCTL *ioctl = ioc->ioctl;
-       dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC %s_reset routed to IOCTL driver!\n", ioc->name,
-               reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
-               reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
-
-       if(ioctl == NULL)
-               return 1;
-
        switch(reset_phase) {
        case MPT_IOC_SETUP_RESET:
-               ioctl->status |= MPT_IOCTL_STATUS_DID_IOCRESET;
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
+               break;
+       case MPT_IOC_PRE_RESET:
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
                break;
        case MPT_IOC_POST_RESET:
-               ioctl->status &= ~MPT_IOCTL_STATUS_DID_IOCRESET;
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
+               if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) {
+                       ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET;
+                       complete(&ioc->ioctl_cmds.done);
+               }
                break;
-       case MPT_IOC_PRE_RESET:
        default:
                break;
        }
@@ -642,7 +673,7 @@ __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        else
                ret = -EINVAL;
 
-       mutex_unlock(&iocp->ioctl->ioctl_mutex);
+       mutex_unlock(&iocp->ioctl_cmds.mutex);
 
        return ret;
 }
@@ -758,6 +789,7 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
        int                      sge_offset = 0;
        u16                      iocstat;
        pFWDownloadReply_t       ReplyMsg = NULL;
+       unsigned long            timeleft;
 
        if (mpt_verify_adapter(ioc, &iocp) < 0) {
                printk(KERN_DEBUG MYNAM "ioctl_fwdl - ioc%d not found!\n",
@@ -841,8 +873,9 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
         *      96              8
         *      64              4
         */
-       maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t))
-                       / (sizeof(dma_addr_t) + sizeof(u32));
+       maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) -
+                       sizeof(FWDownloadTCSGE_t))
+                       / iocp->SGE_size;
        if (numfrags > maxfrags) {
                ret = -EMLINK;
                goto fwdl_out;
@@ -870,7 +903,7 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
                if (nib == 0 || nib == 3) {
                        ;
                } else if (sgIn->Address) {
-                       mpt_add_sge(sgOut, sgIn->FlagsLength, sgIn->Address);
+                       iocp->add_sge(sgOut, sgIn->FlagsLength, sgIn->Address);
                        n++;
                        if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) {
                                printk(MYIOC_s_ERR_FMT "%s@%d::_ioctl_fwdl - "
@@ -882,7 +915,7 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
                }
                sgIn++;
                bl++;
-               sgOut += (sizeof(dma_addr_t) + sizeof(u32));
+               sgOut += iocp->SGE_size;
        }
 
        DBG_DUMP_FW_DOWNLOAD(iocp, (u32 *)mf, numfrags);
@@ -891,16 +924,30 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
         * Finally, perform firmware download.
         */
        ReplyMsg = NULL;
+       SET_MGMT_MSG_CONTEXT(iocp->ioctl_cmds.msg_context, dlmsg->MsgContext);
+       INITIALIZE_MGMT_STATUS(iocp->ioctl_cmds.status)
        mpt_put_msg_frame(mptctl_id, iocp, mf);
 
        /* Now wait for the command to complete */
-       ret = wait_event_timeout(mptctl_wait,
-            iocp->ioctl->wait_done == 1,
-            HZ*60);
+retry_wait:
+       timeleft = wait_for_completion_timeout(&iocp->ioctl_cmds.done, HZ*60);
+       if (!(iocp->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               ret = -ETIME;
+               printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __func__);
+               if (iocp->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
+                       mpt_free_msg_frame(iocp, mf);
+                       goto fwdl_out;
+               }
+               if (!timeleft)
+                       mptctl_timeout_expired(iocp, mf);
+               else
+                       goto retry_wait;
+               goto fwdl_out;
+       }
 
-       if(ret <=0 && (iocp->ioctl->wait_done != 1 )) {
-       /* Now we need to reset the board */
-               mptctl_timeout_expired(iocp->ioctl);
+       if (!(iocp->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
+               printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __func__);
+               mpt_free_msg_frame(iocp, mf);
                ret = -ENODATA;
                goto fwdl_out;
        }
@@ -908,7 +955,7 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
        if (sgl)
                kfree_sgl(sgl, sgl_dma, buflist, iocp);
 
-       ReplyMsg = (pFWDownloadReply_t)iocp->ioctl->ReplyFrame;
+       ReplyMsg = (pFWDownloadReply_t)iocp->ioctl_cmds.reply;
        iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK;
        if (iocstat == MPI_IOCSTATUS_SUCCESS) {
                printk(MYIOC_s_INFO_FMT "F/W update successfull!\n", iocp->name);
@@ -932,6 +979,9 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
        return 0;
 
 fwdl_out:
+
+       CLEAR_MGMT_STATUS(iocp->ioctl_cmds.status);
+       SET_MGMT_MSG_CONTEXT(iocp->ioctl_cmds.msg_context, 0);
         kfree_sgl(sgl, sgl_dma, buflist, iocp);
        return ret;
 }
@@ -1003,7 +1053,7 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
         *
         */
        sgl = sglbuf;
-       sg_spill = ((ioc->req_sz - sge_offset)/(sizeof(dma_addr_t) + sizeof(u32))) - 1;
+       sg_spill = ((ioc->req_sz - sge_offset)/ioc->SGE_size) - 1;
        while (bytes_allocd < bytes) {
                this_alloc = min(alloc_sz, bytes-bytes_allocd);
                buflist[buflist_ent].len = this_alloc;
@@ -1024,8 +1074,9 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
                        dma_addr_t dma_addr;
 
                        bytes_allocd += this_alloc;
-                       sgl->FlagsLength = (0x10000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|this_alloc);
-                       dma_addr = pci_map_single(ioc->pcidev, buflist[buflist_ent].kptr, this_alloc, dir);
+                       sgl->FlagsLength = (0x10000000|sgdir|this_alloc);
+                       dma_addr = pci_map_single(ioc->pcidev,
+                               buflist[buflist_ent].kptr, this_alloc, dir);
                        sgl->Address = dma_addr;
 
                        fragcnt++;
@@ -1771,7 +1822,10 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
        int             msgContext;
        u16             req_idx;
        ulong           timeout;
+       unsigned long   timeleft;
        struct scsi_device *sdev;
+       unsigned long    flags;
+       u8               function;
 
        /* bufIn and bufOut are used for user to kernel space transfers
         */
@@ -1784,24 +1838,23 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                                __FILE__, __LINE__, iocnum);
                return -ENODEV;
        }
-       if (!ioc->ioctl) {
-               printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - "
-                       "No memory available during driver init.\n",
-                               __FILE__, __LINE__);
-               return -ENOMEM;
-       } else if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_IOCRESET) {
+
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       if (ioc->ioc_reset_in_progress) {
+               spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
                printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - "
-                       "Busy with IOC Reset \n", __FILE__, __LINE__);
+                       "Busy with diagnostic reset\n", __FILE__, __LINE__);
                return -EBUSY;
        }
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
 
        /* Verify that the final request frame will not be too large.
         */
        sz = karg.dataSgeOffset * 4;
        if (karg.dataInSize > 0)
-               sz += sizeof(dma_addr_t) + sizeof(u32);
+               sz += ioc->SGE_size;
        if (karg.dataOutSize > 0)
-               sz += sizeof(dma_addr_t) + sizeof(u32);
+               sz += ioc->SGE_size;
 
        if (sz > ioc->req_sz) {
                printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
@@ -1827,10 +1880,12 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
                        "Unable to read MF from mpt_ioctl_command struct @ %p\n",
                        ioc->name, __FILE__, __LINE__, mfPtr);
+               function = -1;
                rc = -EFAULT;
                goto done_free_mem;
        }
        hdr->MsgContext = cpu_to_le32(msgContext);
+       function = hdr->Function;
 
 
        /* Verify that this request is allowed.
@@ -1838,7 +1893,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
        dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sending mpi function (0x%02X), req=%p\n",
            ioc->name, hdr->Function, mf));
 
-       switch (hdr->Function) {
+       switch (function) {
        case MPI_FUNCTION_IOC_FACTS:
        case MPI_FUNCTION_PORT_FACTS:
                karg.dataOutSize  = karg.dataInSize = 0;
@@ -1893,7 +1948,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                        }
 
                        pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH;
-                       pScsiReq->MsgFlags |= mpt_msg_flags();
+                       pScsiReq->MsgFlags |= mpt_msg_flags(ioc);
 
 
                        /* verify that app has not requested
@@ -1935,8 +1990,6 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                        pScsiReq->Control = cpu_to_le32(scsidir | qtag);
                        pScsiReq->DataLength = cpu_to_le32(dataSize);
 
-                       ioc->ioctl->reset = MPTCTL_RESET_OK;
-                       ioc->ioctl->id = pScsiReq->TargetID;
 
                } else {
                        printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
@@ -1979,7 +2032,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                        int dataSize;
 
                        pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH;
-                       pScsiReq->MsgFlags |= mpt_msg_flags();
+                       pScsiReq->MsgFlags |= mpt_msg_flags(ioc);
 
 
                        /* verify that app has not requested
@@ -2014,8 +2067,6 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                        pScsiReq->Control = cpu_to_le32(scsidir | qtag);
                        pScsiReq->DataLength = cpu_to_le32(dataSize);
 
-                       ioc->ioctl->reset = MPTCTL_RESET_OK;
-                       ioc->ioctl->id = pScsiReq->TargetID;
                } else {
                        printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
                                "SCSI driver is not loaded. \n",
@@ -2026,20 +2077,17 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                break;
 
        case MPI_FUNCTION_SCSI_TASK_MGMT:
-               {
-                       MPT_SCSI_HOST *hd = NULL;
-                       if ((ioc->sh == NULL) || ((hd = shost_priv(ioc->sh)) == NULL)) {
-                               printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
-                                       "SCSI driver not loaded or SCSI host not found. \n",
-                                       ioc->name, __FILE__, __LINE__);
-                               rc = -EFAULT;
-                               goto done_free_mem;
-                       } else if (mptctl_set_tm_flags(hd) != 0) {
-                               rc = -EPERM;
-                               goto done_free_mem;
-                       }
-               }
+       {
+               SCSITaskMgmt_t  *pScsiTm;
+               pScsiTm = (SCSITaskMgmt_t *)mf;
+               dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                       "\tTaskType=0x%x MsgFlags=0x%x "
+                       "TaskMsgContext=0x%x id=%d channel=%d\n",
+                       ioc->name, pScsiTm->TaskType, le32_to_cpu
+                       (pScsiTm->TaskMsgContext), pScsiTm->MsgFlags,
+                       pScsiTm->TargetID, pScsiTm->Bus));
                break;
+       }
 
        case MPI_FUNCTION_IOC_INIT:
                {
@@ -2123,8 +2171,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                        if (karg.dataInSize > 0) {
                                flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT |
                                                MPI_SGE_FLAGS_END_OF_BUFFER |
-                                               MPI_SGE_FLAGS_DIRECTION |
-                                               mpt_addr_size() )
+                                               MPI_SGE_FLAGS_DIRECTION)
                                                << MPI_SGE_FLAGS_SHIFT;
                        } else {
                                flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
@@ -2141,8 +2188,8 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                                /* Set up this SGE.
                                 * Copy to MF and to sglbuf
                                 */
-                               mpt_add_sge(psge, flagsLength, dma_addr_out);
-                               psge += (sizeof(u32) + sizeof(dma_addr_t));
+                               ioc->add_sge(psge, flagsLength, dma_addr_out);
+                               psge += ioc->SGE_size;
 
                                /* Copy user data to kernel space.
                                 */
@@ -2175,18 +2222,25 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                                /* Set up this SGE
                                 * Copy to MF and to sglbuf
                                 */
-                               mpt_add_sge(psge, flagsLength, dma_addr_in);
+                               ioc->add_sge(psge, flagsLength, dma_addr_in);
                        }
                }
        } else  {
                /* Add a NULL SGE
                 */
-               mpt_add_sge(psge, flagsLength, (dma_addr_t) -1);
+               ioc->add_sge(psge, flagsLength, (dma_addr_t) -1);
        }
 
-       ioc->ioctl->wait_done = 0;
+       SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, hdr->MsgContext);
+       INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
        if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) {
 
+               mutex_lock(&ioc->taskmgmt_cmds.mutex);
+               if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
+                       mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+                       goto done_free_mem;
+               }
+
                DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
 
                if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
@@ -2197,10 +2251,11 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                                sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP);
                        if (rc != 0) {
                                dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                                   "_send_handshake FAILED! (ioc %p, mf %p)\n",
+                                   "send_handshake FAILED! (ioc %p, mf %p)\n",
                                    ioc->name, ioc, mf));
-                               mptctl_free_tm_flags(ioc);
+                               mpt_clear_taskmgmt_in_progress_flag(ioc);
                                rc = -ENODATA;
+                               mutex_unlock(&ioc->taskmgmt_cmds.mutex);
                                goto done_free_mem;
                        }
                }
@@ -2210,36 +2265,47 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
 
        /* Now wait for the command to complete */
        timeout = (karg.timeout > 0) ? karg.timeout : MPT_IOCTL_DEFAULT_TIMEOUT;
-       timeout = wait_event_timeout(mptctl_wait,
-            ioc->ioctl->wait_done == 1,
-            HZ*timeout);
-
-       if(timeout <=0 && (ioc->ioctl->wait_done != 1 )) {
-       /* Now we need to reset the board */
-
-               if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT)
-                       mptctl_free_tm_flags(ioc);
-
-               mptctl_timeout_expired(ioc->ioctl);
-               rc = -ENODATA;
+retry_wait:
+       timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done,
+                               HZ*timeout);
+       if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               rc = -ETIME;
+               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "%s: TIMED OUT!\n",
+                   ioc->name, __func__));
+               if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
+                       if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
+                               mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+                       goto done_free_mem;
+               }
+               if (!timeleft) {
+                       if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
+                               mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+                       mptctl_timeout_expired(ioc, mf);
+                       mf = NULL;
+               } else
+                       goto retry_wait;
                goto done_free_mem;
        }
 
+       if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
+               mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+
+
        mf = NULL;
 
        /* If a valid reply frame, copy to the user.
         * Offset 2: reply length in U32's
         */
-       if (ioc->ioctl->status & MPT_IOCTL_STATUS_RF_VALID) {
+       if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) {
                if (karg.maxReplyBytes < ioc->reply_sz) {
-                        sz = min(karg.maxReplyBytes, 4*ioc->ioctl->ReplyFrame[2]);
+                       sz = min(karg.maxReplyBytes,
+                               4*ioc->ioctl_cmds.reply[2]);
                } else {
-                        sz = min(ioc->reply_sz, 4*ioc->ioctl->ReplyFrame[2]);
+                        sz = min(ioc->reply_sz, 4*ioc->ioctl_cmds.reply[2]);
                }
-
                if (sz > 0) {
                        if (copy_to_user(karg.replyFrameBufPtr,
-                                &ioc->ioctl->ReplyFrame, sz)){
+                                ioc->ioctl_cmds.reply, sz)){
                                 printk(MYIOC_s_ERR_FMT
                                     "%s@%d::mptctl_do_mpt_command - "
                                 "Unable to write out reply frame %p\n",
@@ -2252,10 +2318,11 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
 
        /* If valid sense data, copy to user.
         */
-       if (ioc->ioctl->status & MPT_IOCTL_STATUS_SENSE_VALID) {
+       if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_SENSE_VALID) {
                sz = min(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE);
                if (sz > 0) {
-                       if (copy_to_user(karg.senseDataPtr, ioc->ioctl->sense, sz)) {
+                       if (copy_to_user(karg.senseDataPtr,
+                               ioc->ioctl_cmds.sense, sz)) {
                                printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
                                "Unable to write sense data to user %p\n",
                                ioc->name, __FILE__, __LINE__,
@@ -2269,7 +2336,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
        /* If the overall status is _GOOD and data in, copy data
         * to user.
         */
-       if ((ioc->ioctl->status & MPT_IOCTL_STATUS_COMMAND_GOOD) &&
+       if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD) &&
                                (karg.dataInSize > 0) && (bufIn.kptr)) {
 
                if (copy_to_user(karg.dataInBufPtr,
@@ -2284,9 +2351,8 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
 
 done_free_mem:
 
-       ioc->ioctl->status &= ~(MPT_IOCTL_STATUS_COMMAND_GOOD |
-               MPT_IOCTL_STATUS_SENSE_VALID |
-               MPT_IOCTL_STATUS_RF_VALID );
+       CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status)
+       SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0);
 
        /* Free the allocated memory.
         */
@@ -2336,6 +2402,8 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
        ToolboxIstwiReadWriteRequest_t  *IstwiRWRequest;
        MPT_FRAME_HDR           *mf = NULL;
        MPIHeader_t             *mpi_hdr;
+       unsigned long           timeleft;
+       int                     retval;
 
        /* Reset long to int. Should affect IA64 and SPARC only
         */
@@ -2466,9 +2534,9 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
                MPT_SCSI_HOST *hd =  shost_priv(ioc->sh);
 
                if (hd && (cim_rev == 1)) {
-                       karg.hard_resets = hd->hard_resets;
-                       karg.soft_resets = hd->soft_resets;
-                       karg.timeouts = hd->timeouts;
+                       karg.hard_resets = ioc->hard_resets;
+                       karg.soft_resets = ioc->soft_resets;
+                       karg.timeouts = ioc->timeouts;
                }
        }
 
@@ -2476,8 +2544,8 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
         * Gather ISTWI(Industry Standard Two Wire Interface) Data
         */
        if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
-               dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
-                   ioc->name,__func__));
+               dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
+                       "%s, no msg frames!!\n", ioc->name, __func__));
                goto out;
        }
 
@@ -2498,22 +2566,29 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
        pbuf = pci_alloc_consistent(ioc->pcidev, 4, &buf_dma);
        if (!pbuf)
                goto out;
-       mpt_add_sge((char *)&IstwiRWRequest->SGL,
+       ioc->add_sge((char *)&IstwiRWRequest->SGL,
            (MPT_SGE_FLAGS_SSIMPLE_READ|4), buf_dma);
 
-       ioc->ioctl->wait_done = 0;
+       retval = 0;
+       SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context,
+                               IstwiRWRequest->MsgContext);
+       INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
        mpt_put_msg_frame(mptctl_id, ioc, mf);
 
-       rc = wait_event_timeout(mptctl_wait,
-            ioc->ioctl->wait_done == 1,
-            HZ*MPT_IOCTL_DEFAULT_TIMEOUT /* 10 sec */);
-
-       if(rc <=0 && (ioc->ioctl->wait_done != 1 )) {
-               /*
-                * Now we need to reset the board
-                */
-               mpt_free_msg_frame(ioc, mf);
-               mptctl_timeout_expired(ioc->ioctl);
+retry_wait:
+       timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done,
+                       HZ*MPT_IOCTL_DEFAULT_TIMEOUT);
+       if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               retval = -ETIME;
+               printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name, __func__);
+               if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
+                       mpt_free_msg_frame(ioc, mf);
+                       goto out;
+               }
+               if (!timeleft)
+                       mptctl_timeout_expired(ioc, mf);
+               else
+                       goto retry_wait;
                goto out;
        }
 
@@ -2526,10 +2601,13 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
         *   bays have drives in them
         * pbuf[3] = Checksum (0x100 = (byte0 + byte2 + byte3)
         */
-       if (ioc->ioctl->status & MPT_IOCTL_STATUS_RF_VALID)
+       if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID)
                karg.rsvd = *(u32 *)pbuf;
 
  out:
+       CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status)
+       SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0);
+
        if (pbuf)
                pci_free_consistent(ioc->pcidev, 4, pbuf, buf_dma);
 
@@ -2753,7 +2831,7 @@ compat_mptfwxfer_ioctl(struct file *filp, unsigned int cmd,
 
        ret = mptctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen);
 
-       mutex_unlock(&iocp->ioctl->ioctl_mutex);
+       mutex_unlock(&iocp->ioctl_cmds.mutex);
 
        return ret;
 }
@@ -2807,7 +2885,7 @@ compat_mpt_command(struct file *filp, unsigned int cmd,
         */
        ret = mptctl_do_mpt_command (karg, &uarg->MF);
 
-       mutex_unlock(&iocp->ioctl->ioctl_mutex);
+       mutex_unlock(&iocp->ioctl_cmds.mutex);
 
        return ret;
 }
@@ -2859,21 +2937,10 @@ static long compat_mpctl_ioctl(struct file *f, unsigned int cmd, unsigned long a
 static int
 mptctl_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
-       MPT_IOCTL *mem;
        MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
 
-       /*
-        * Allocate and inite a MPT_IOCTL structure
-       */
-       mem = kzalloc(sizeof(MPT_IOCTL), GFP_KERNEL);
-       if (!mem) {
-               mptctl_remove(pdev);
-               return -ENOMEM;
-       }
-
-       ioc->ioctl = mem;
-       ioc->ioctl->ioc = ioc;
-       mutex_init(&ioc->ioctl->ioctl_mutex);
+       mutex_init(&ioc->ioctl_cmds.mutex);
+       init_completion(&ioc->ioctl_cmds.done);
        return 0;
 }
 
@@ -2887,9 +2954,6 @@ mptctl_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 static void
 mptctl_remove(struct pci_dev *pdev)
 {
-       MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
-
-       kfree ( ioc->ioctl );
 }
 
 static struct mpt_pci_driver mptctl_driver = {
@@ -2929,6 +2993,7 @@ static int __init mptctl_init(void)
                goto out_fail;
        }
 
+       mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER);
        mpt_reset_register(mptctl_id, mptctl_ioc_reset);
        mpt_event_register(mptctl_id, mptctl_event_process);
 
@@ -2953,6 +3018,7 @@ static void mptctl_exit(void)
 
        /* De-register callback handler from base module */
        mpt_deregister(mptctl_id);
+       mpt_reset_deregister(mptctl_taskmgmt_id);
 
         mpt_device_driver_deregister(MPTCTL_DRIVER);
 
index 510b9f492093432ea63ef5d03dadd39cd80ca048..28e4788792848d4854618ce9d0c8f2146399a998 100644 (file)
@@ -58,6 +58,7 @@
 #define MPT_DEBUG_FC                   0x00080000
 #define MPT_DEBUG_SAS                  0x00100000
 #define MPT_DEBUG_SAS_WIDE             0x00200000
+#define MPT_DEBUG_36GB_MEM              0x00400000
 
 /*
  * CONFIG_FUSION_LOGGING - enabled in Kconfig
 #define dsaswideprintk(IOC, CMD)               \
        MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS_WIDE)
 
+#define d36memprintk(IOC, CMD)         \
+       MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_36GB_MEM)
 
 
 /*
index c3c24fdf9fb621c20acb8249496c6440cad8b8b6..e61df133a59e8a934b25e9d93d419af6e6a50899 100644 (file)
@@ -1251,17 +1251,15 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
         * A slightly different algorithm is required for
         * 64bit SGEs.
         */
-       scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
-       if (sizeof(dma_addr_t) == sizeof(u64)) {
+       scale = ioc->req_sz/ioc->SGE_size;
+       if (ioc->sg_addr_size == sizeof(u64)) {
                numSGE = (scale - 1) *
                  (ioc->facts.MaxChainDepth-1) + scale +
-                 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
-                 sizeof(u32));
+                 (ioc->req_sz - 60) / ioc->SGE_size;
        } else {
                numSGE = 1 + (scale - 1) *
                  (ioc->facts.MaxChainDepth-1) + scale +
-                 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
-                 sizeof(u32));
+                 (ioc->req_sz - 64) / ioc->SGE_size;
        }
 
        if (numSGE < sh->sg_tablesize) {
@@ -1292,9 +1290,6 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        /* Clear the TM flags
         */
-       hd->tmPending = 0;
-       hd->tmState = TM_STATE_NONE;
-       hd->resetPending = 0;
        hd->abortSCpnt = NULL;
 
        /* Clear the pointer used to store
@@ -1312,8 +1307,6 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        hd->timer.data = (unsigned long) hd;
        hd->timer.function = mptscsih_timer_expired;
 
-       init_waitqueue_head(&hd->scandv_waitq);
-       hd->scandv_wait_done = 0;
        hd->last_queue_full = 0;
 
        sh->transportt = mptfc_transport_template;
index 79f5433359f9b3fc1b346cb78b5d11dcd60d15de..20e0b447e8e83a0ce07455de4d7f56215f43a568 100644 (file)
@@ -93,8 +93,37 @@ static u8    mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
 static u8      mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
 static u8      mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
 static u8      mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS;
-
-static void mptsas_hotplug_work(struct work_struct *work);
+static u8      mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS;
+
+static void mptsas_firmware_event_work(struct work_struct *work);
+static void mptsas_send_sas_event(struct fw_event_work *fw_event);
+static void mptsas_send_raid_event(struct fw_event_work *fw_event);
+static void mptsas_send_ir2_event(struct fw_event_work *fw_event);
+static void mptsas_parse_device_info(struct sas_identify *identify,
+               struct mptsas_devinfo *device_info);
+static inline void mptsas_set_rphy(MPT_ADAPTER *ioc,
+               struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy);
+static struct mptsas_phyinfo   *mptsas_find_phyinfo_by_sas_address
+               (MPT_ADAPTER *ioc, u64 sas_address);
+static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc,
+       struct mptsas_devinfo *device_info, u32 form, u32 form_specific);
+static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc,
+       struct mptsas_enclosure *enclosure, u32 form, u32 form_specific);
+static int mptsas_add_end_device(MPT_ADAPTER *ioc,
+       struct mptsas_phyinfo *phy_info);
+static void mptsas_del_end_device(MPT_ADAPTER *ioc,
+       struct mptsas_phyinfo *phy_info);
+static void mptsas_send_link_status_event(struct fw_event_work *fw_event);
+static struct mptsas_portinfo  *mptsas_find_portinfo_by_sas_address
+               (MPT_ADAPTER *ioc, u64 sas_address);
+static void mptsas_expander_delete(MPT_ADAPTER *ioc,
+               struct mptsas_portinfo *port_info, u8 force);
+static void mptsas_send_expander_event(struct fw_event_work *fw_event);
+static void mptsas_not_responding_devices(MPT_ADAPTER *ioc);
+static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc);
+static void mptsas_broadcast_primative_work(struct fw_event_work *fw_event);
+static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event);
+static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id);
 
 static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
                                        MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
@@ -218,30 +247,125 @@ static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
            le16_to_cpu(pg1->AttachedDevHandle)));
 }
 
-static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
+/* inhibit sas firmware event handling */
+static void
+mptsas_fw_event_off(MPT_ADAPTER *ioc)
 {
-       struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
-       return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioc->fw_event_lock, flags);
+       ioc->fw_events_off = 1;
+       ioc->sas_discovery_quiesce_io = 0;
+       spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+
 }
 
-static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
+/* enable sas firmware event handling */
+static void
+mptsas_fw_event_on(MPT_ADAPTER *ioc)
 {
-       struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
-       return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioc->fw_event_lock, flags);
+       ioc->fw_events_off = 0;
+       spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
 }
 
-static struct mptsas_portinfo *
-mptsas_get_hba_portinfo(MPT_ADAPTER *ioc)
+/* queue a sas firmware event */
+static void
+mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
+    unsigned long delay)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioc->fw_event_lock, flags);
+       list_add_tail(&fw_event->list, &ioc->fw_event_list);
+       INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work);
+       devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)\n",
+           ioc->name, __func__, fw_event));
+       queue_delayed_work(ioc->fw_event_q, &fw_event->work,
+           delay);
+       spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+}
+
+/* requeue a sas firmware event */
+static void
+mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
+    unsigned long delay)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&ioc->fw_event_lock, flags);
+       devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: reschedule task "
+           "(fw_event=0x%p)\n", ioc->name, __func__, fw_event));
+       fw_event->retries++;
+       queue_delayed_work(ioc->fw_event_q, &fw_event->work,
+           msecs_to_jiffies(delay));
+       spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+}
+
+/* free memory assoicated to a sas firmware event */
+static void
+mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioc->fw_event_lock, flags);
+       devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n",
+           ioc->name, __func__, fw_event));
+       list_del(&fw_event->list);
+       kfree(fw_event);
+       spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+}
+
+/* walk the firmware event queue, and either stop or wait for
+ * outstanding events to complete */
+static void
+mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc)
 {
-       struct list_head        *head = &ioc->sas_topology;
-       struct mptsas_portinfo  *pi = NULL;
+       struct fw_event_work *fw_event, *next;
+       struct mptsas_target_reset_event *target_reset_list, *n;
+       u8      flush_q;
+       MPT_SCSI_HOST   *hd = shost_priv(ioc->sh);
+
+       /* flush the target_reset_list */
+       if (!list_empty(&hd->target_reset_list)) {
+               list_for_each_entry_safe(target_reset_list, n,
+                   &hd->target_reset_list, list) {
+                       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                           "%s: removing target reset for id=%d\n",
+                           ioc->name, __func__,
+                          target_reset_list->sas_event_data.TargetID));
+                       list_del(&target_reset_list->list);
+                       kfree(target_reset_list);
+               }
+       }
+
+       if (list_empty(&ioc->fw_event_list) ||
+            !ioc->fw_event_q || in_interrupt())
+               return;
+
+       flush_q = 0;
+       list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
+               if (cancel_delayed_work(&fw_event->work))
+                       mptsas_free_fw_event(ioc, fw_event);
+               else
+                       flush_q = 1;
+       }
+       if (flush_q)
+               flush_workqueue(ioc->fw_event_q);
+}
 
-       /* always the first entry on sas_topology list */
 
-       if (!list_empty(head))
-               pi = list_entry(head->next, struct mptsas_portinfo, list);
+static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
+{
+       struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
+       return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
+}
 
-       return pi;
+static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
+{
+       struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
+       return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
 }
 
 /*
@@ -265,6 +389,38 @@ mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
        return rc;
 }
 
+/**
+ *     mptsas_find_portinfo_by_sas_address -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @handle:
+ *
+ *     This function should be called with the sas_topology_mutex already held
+ *
+ **/
+static struct mptsas_portinfo *
+mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
+{
+       struct mptsas_portinfo *port_info, *rc = NULL;
+       int i;
+
+       if (sas_address >= ioc->hba_port_sas_addr &&
+           sas_address < (ioc->hba_port_sas_addr +
+           ioc->hba_port_num_phy))
+               return ioc->hba_port_info;
+
+       mutex_lock(&ioc->sas_topology_mutex);
+       list_for_each_entry(port_info, &ioc->sas_topology, list)
+               for (i = 0; i < port_info->num_phys; i++)
+                       if (port_info->phy_info[i].identify.sas_address ==
+                           sas_address) {
+                               rc = port_info;
+                               goto out;
+                       }
+ out:
+       mutex_unlock(&ioc->sas_topology_mutex);
+       return rc;
+}
+
 /*
  * Returns true if there is a scsi end device
  */
@@ -308,6 +464,7 @@ mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_detai
                if(phy_info->port_details != port_details)
                        continue;
                memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
+               mptsas_set_rphy(ioc, phy_info, NULL);
                phy_info->port_details = NULL;
        }
        kfree(port_details);
@@ -379,6 +536,285 @@ starget)
                phy_info->port_details->starget = starget;
 }
 
+/**
+ *     mptsas_add_device_component -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @channel: fw mapped id's
+ *     @id:
+ *     @sas_address:
+ *     @device_info:
+ *
+ **/
+static void
+mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id,
+       u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id)
+{
+       struct mptsas_device_info       *sas_info, *next;
+       struct scsi_device      *sdev;
+       struct scsi_target      *starget;
+       struct sas_rphy *rphy;
+
+       /*
+        * Delete all matching devices out of the list
+        */
+       mutex_lock(&ioc->sas_device_info_mutex);
+       list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
+           list) {
+               if (!sas_info->is_logical_volume &&
+                   (sas_info->sas_address == sas_address ||
+                   (sas_info->fw.channel == channel &&
+                    sas_info->fw.id == id))) {
+                       list_del(&sas_info->list);
+                       kfree(sas_info);
+               }
+       }
+
+       sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
+       if (!sas_info)
+               goto out;
+
+       /*
+        * Set Firmware mapping
+        */
+       sas_info->fw.id = id;
+       sas_info->fw.channel = channel;
+
+       sas_info->sas_address = sas_address;
+       sas_info->device_info = device_info;
+       sas_info->slot = slot;
+       sas_info->enclosure_logical_id = enclosure_logical_id;
+       INIT_LIST_HEAD(&sas_info->list);
+       list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
+
+       /*
+        * Set OS mapping
+        */
+       shost_for_each_device(sdev, ioc->sh) {
+               starget = scsi_target(sdev);
+               rphy = dev_to_rphy(starget->dev.parent);
+               if (rphy->identify.sas_address == sas_address) {
+                       sas_info->os.id = starget->id;
+                       sas_info->os.channel = starget->channel;
+               }
+       }
+
+ out:
+       mutex_unlock(&ioc->sas_device_info_mutex);
+       return;
+}
+
+/**
+ *     mptsas_add_device_component_by_fw -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @channel:  fw mapped id's
+ *     @id:
+ *
+ **/
+static void
+mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
+{
+       struct mptsas_devinfo sas_device;
+       struct mptsas_enclosure enclosure_info;
+       int rc;
+
+       rc = mptsas_sas_device_pg0(ioc, &sas_device,
+           (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
+            MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+           (channel << 8) + id);
+       if (rc)
+               return;
+
+       memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
+       mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
+           (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
+            MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
+            sas_device.handle_enclosure);
+
+       mptsas_add_device_component(ioc, sas_device.channel,
+           sas_device.id, sas_device.sas_address, sas_device.device_info,
+           sas_device.slot, enclosure_info.enclosure_logical_id);
+}
+
+/**
+ *     mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding each individual device to list
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @channel: fw mapped id's
+ *     @id:
+ *
+ **/
+static void
+mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc,
+               struct scsi_target *starget)
+{
+       CONFIGPARMS                     cfg;
+       ConfigPageHeader_t              hdr;
+       dma_addr_t                      dma_handle;
+       pRaidVolumePage0_t              buffer = NULL;
+       int                             i;
+       RaidPhysDiskPage0_t             phys_disk;
+       struct mptsas_device_info       *sas_info, *next;
+
+       memset(&cfg, 0 , sizeof(CONFIGPARMS));
+       memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
+       hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
+       /* assumption that all volumes on channel = 0 */
+       cfg.pageAddr = starget->id;
+       cfg.cfghdr.hdr = &hdr;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.timeout = 10;
+
+       if (mpt_config(ioc, &cfg) != 0)
+               goto out;
+
+       if (!hdr.PageLength)
+               goto out;
+
+       buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
+           &dma_handle);
+
+       if (!buffer)
+               goto out;
+
+       cfg.physAddr = dma_handle;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+       if (mpt_config(ioc, &cfg) != 0)
+               goto out;
+
+       if (!buffer->NumPhysDisks)
+               goto out;
+
+       /*
+        * Adding entry for hidden components
+        */
+       for (i = 0; i < buffer->NumPhysDisks; i++) {
+
+               if (mpt_raid_phys_disk_pg0(ioc,
+                   buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
+                       continue;
+
+               mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus,
+                   phys_disk.PhysDiskID);
+
+               mutex_lock(&ioc->sas_device_info_mutex);
+               list_for_each_entry(sas_info, &ioc->sas_device_info_list,
+                   list) {
+                       if (!sas_info->is_logical_volume &&
+                           (sas_info->fw.channel == phys_disk.PhysDiskBus &&
+                           sas_info->fw.id == phys_disk.PhysDiskID)) {
+                               sas_info->is_hidden_raid_component = 1;
+                               sas_info->volume_id = starget->id;
+                       }
+               }
+               mutex_unlock(&ioc->sas_device_info_mutex);
+
+       }
+
+       /*
+        * Delete all matching devices out of the list
+        */
+       mutex_lock(&ioc->sas_device_info_mutex);
+       list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
+           list) {
+               if (sas_info->is_logical_volume && sas_info->fw.id ==
+                   starget->id) {
+                       list_del(&sas_info->list);
+                       kfree(sas_info);
+               }
+       }
+
+       sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
+       if (sas_info) {
+               sas_info->fw.id = starget->id;
+               sas_info->os.id = starget->id;
+               sas_info->os.channel = starget->channel;
+               sas_info->is_logical_volume = 1;
+               INIT_LIST_HEAD(&sas_info->list);
+               list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
+       }
+       mutex_unlock(&ioc->sas_device_info_mutex);
+
+ out:
+       if (buffer)
+               pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
+                   dma_handle);
+}
+
+/**
+ *     mptsas_add_device_component_starget -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @starget:
+ *
+ **/
+static void
+mptsas_add_device_component_starget(MPT_ADAPTER *ioc,
+       struct scsi_target *starget)
+{
+       VirtTarget      *vtarget;
+       struct sas_rphy *rphy;
+       struct mptsas_phyinfo   *phy_info = NULL;
+       struct mptsas_enclosure enclosure_info;
+
+       rphy = dev_to_rphy(starget->dev.parent);
+       vtarget = starget->hostdata;
+       phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+                       rphy->identify.sas_address);
+       if (!phy_info)
+               return;
+
+       memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
+       mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
+               (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
+               MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
+               phy_info->attached.handle_enclosure);
+
+       mptsas_add_device_component(ioc, phy_info->attached.channel,
+               phy_info->attached.id, phy_info->attached.sas_address,
+               phy_info->attached.device_info,
+               phy_info->attached.slot, enclosure_info.enclosure_logical_id);
+}
+
+/**
+ *     mptsas_del_device_component_by_os - Once a device has been removed, we mark the entry in the list as being cached
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @channel: os mapped id's
+ *     @id:
+ *
+ **/
+static void
+mptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id)
+{
+       struct mptsas_device_info       *sas_info, *next;
+
+       /*
+        * Set is_cached flag
+        */
+       list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
+               list) {
+               if (sas_info->os.channel == channel && sas_info->os.id == id)
+                       sas_info->is_cached = 1;
+       }
+}
+
+/**
+ *     mptsas_del_device_components - Cleaning the list
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *
+ **/
+static void
+mptsas_del_device_components(MPT_ADAPTER *ioc)
+{
+       struct mptsas_device_info       *sas_info, *next;
+
+       mutex_lock(&ioc->sas_device_info_mutex);
+       list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
+               list) {
+               list_del(&sas_info->list);
+               kfree(sas_info);
+       }
+       mutex_unlock(&ioc->sas_device_info_mutex);
+}
+
 
 /*
  * mptsas_setup_wide_ports
@@ -434,8 +870,8 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
                 * Forming a port
                 */
                if (!port_details) {
-                       port_details = kzalloc(sizeof(*port_details),
-                               GFP_KERNEL);
+                       port_details = kzalloc(sizeof(struct
+                               mptsas_portinfo_details), GFP_KERNEL);
                        if (!port_details)
                                goto out;
                        port_details->num_phys = 1;
@@ -523,15 +959,62 @@ mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
        VirtTarget                      *vtarget = NULL;
 
        shost_for_each_device(sdev, ioc->sh) {
-               if ((vdevice = sdev->hostdata) == NULL)
+               vdevice = sdev->hostdata;
+               if ((vdevice == NULL) ||
+                       (vdevice->vtarget == NULL))
+                       continue;
+               if ((vdevice->vtarget->tflags &
+                   MPT_TARGET_FLAGS_RAID_COMPONENT ||
+                   vdevice->vtarget->raidVolume))
                        continue;
                if (vdevice->vtarget->id == id &&
-                   vdevice->vtarget->channel == channel)
+                       vdevice->vtarget->channel == channel)
                        vtarget = vdevice->vtarget;
        }
        return vtarget;
 }
 
+static void
+mptsas_queue_device_delete(MPT_ADAPTER *ioc,
+       MpiEventDataSasDeviceStatusChange_t *sas_event_data)
+{
+       struct fw_event_work *fw_event;
+       int sz;
+
+       sz = offsetof(struct fw_event_work, event_data) +
+           sizeof(MpiEventDataSasDeviceStatusChange_t);
+       fw_event = kzalloc(sz, GFP_ATOMIC);
+       if (!fw_event) {
+               printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
+                   ioc->name, __func__, __LINE__);
+               return;
+       }
+       memcpy(fw_event->event_data, sas_event_data,
+           sizeof(MpiEventDataSasDeviceStatusChange_t));
+       fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE;
+       fw_event->ioc = ioc;
+       mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
+}
+
+static void
+mptsas_queue_rescan(MPT_ADAPTER *ioc)
+{
+       struct fw_event_work *fw_event;
+       int sz;
+
+       sz = offsetof(struct fw_event_work, event_data);
+       fw_event = kzalloc(sz, GFP_ATOMIC);
+       if (!fw_event) {
+               printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
+                   ioc->name, __func__, __LINE__);
+               return;
+       }
+       fw_event->event = -1;
+       fw_event->ioc = ioc;
+       mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
+}
+
+
 /**
  * mptsas_target_reset
  *
@@ -550,13 +1033,21 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
 {
        MPT_FRAME_HDR   *mf;
        SCSITaskMgmt_t  *pScsiTm;
-
-       if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
-               dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n",
-                   ioc->name,__func__, __LINE__));
+       if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0)
                return 0;
+
+
+       mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
+       if (mf == NULL) {
+               dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
+                       "%s, no msg frames @%d!!\n", ioc->name,
+                       __func__, __LINE__));
+               goto out_fail;
        }
 
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
+               ioc->name, mf));
+
        /* Format the Request
         */
        pScsiTm = (SCSITaskMgmt_t *) mf;
@@ -569,9 +1060,18 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
 
        DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
 
-       mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+          "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n",
+          ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id));
+
+       mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
 
        return 1;
+
+ out_fail:
+
+       mpt_clear_taskmgmt_in_progress_flag(ioc);
+       return 0;
 }
 
 /**
@@ -602,11 +1102,12 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc,
 
        vtarget->deleted = 1; /* block IO */
 
-       target_reset_list = kzalloc(sizeof(*target_reset_list),
+       target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event),
            GFP_ATOMIC);
        if (!target_reset_list) {
-               dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
-                   ioc->name,__func__, __LINE__));
+               dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
+                       "%s, failed to allocate mem @%d..!!\n",
+                       ioc->name, __func__, __LINE__));
                return;
        }
 
@@ -614,84 +1115,101 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc,
                sizeof(*sas_event_data));
        list_add_tail(&target_reset_list->list, &hd->target_reset_list);
 
-       if (hd->resetPending)
-               return;
+       target_reset_list->time_count = jiffies;
 
        if (mptsas_target_reset(ioc, channel, id)) {
                target_reset_list->target_reset_issued = 1;
-               hd->resetPending = 1;
        }
 }
 
 /**
- * mptsas_dev_reset_complete
- *
- * Completion for TARGET_RESET after NOT_RESPONDING_EVENT,
- * enable work queue to finish off removing device from upper layers.
- * then send next TARGET_RESET in the queue.
- *
- * @ioc
+ *     mptsas_taskmgmt_complete - complete SAS task management function
+ *     @ioc: Pointer to MPT_ADAPTER structure
  *
+ *     Completion for TARGET_RESET after NOT_RESPONDING_EVENT, enable work
+ *     queue to finish off removing device from upper layers. then send next
+ *     TARGET_RESET in the queue.
  **/
-static void
-mptsas_dev_reset_complete(MPT_ADAPTER *ioc)
+static int
+mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
 {
        MPT_SCSI_HOST   *hd = shost_priv(ioc->sh);
         struct list_head *head = &hd->target_reset_list;
-       struct mptsas_target_reset_event *target_reset_list;
-       struct mptsas_hotplug_event *ev;
-       EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
        u8              id, channel;
-       __le64          sas_address;
+       struct mptsas_target_reset_event        *target_reset_list;
+       SCSITaskMgmtReply_t *pScsiTmReply;
+
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: "
+           "(mf = %p, mr = %p)\n", ioc->name, mf, mr));
+
+       pScsiTmReply = (SCSITaskMgmtReply_t *)mr;
+       if (pScsiTmReply) {
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n"
+                   "\ttask_type = 0x%02X, iocstatus = 0x%04X "
+                   "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, "
+                   "term_cmnds = %d\n", ioc->name,
+                   pScsiTmReply->Bus, pScsiTmReply->TargetID,
+                   pScsiTmReply->TaskType,
+                   le16_to_cpu(pScsiTmReply->IOCStatus),
+                   le32_to_cpu(pScsiTmReply->IOCLogInfo),
+                   pScsiTmReply->ResponseCode,
+                   le32_to_cpu(pScsiTmReply->TerminationCount)));
+
+               if (pScsiTmReply->ResponseCode)
+                       mptscsih_taskmgmt_response_code(ioc,
+                       pScsiTmReply->ResponseCode);
+       }
+
+       if (pScsiTmReply && (pScsiTmReply->TaskType ==
+           MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType ==
+            MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) {
+               ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
+               ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
+               memcpy(ioc->taskmgmt_cmds.reply, mr,
+                   min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
+               if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
+                       ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+                       complete(&ioc->taskmgmt_cmds.done);
+                       return 1;
+               }
+               return 0;
+       }
+
+       mpt_clear_taskmgmt_in_progress_flag(ioc);
 
        if (list_empty(head))
-               return;
+               return 1;
 
-       target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, list);
+       target_reset_list = list_entry(head->next,
+           struct mptsas_target_reset_event, list);
 
-       sas_event_data = &target_reset_list->sas_event_data;
-       id = sas_event_data->TargetID;
-       channel = sas_event_data->Bus;
-       hd->resetPending = 0;
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "TaskMgmt: completed (%d seconds)\n",
+           ioc->name, jiffies_to_msecs(jiffies -
+           target_reset_list->time_count)/1000));
+
+       id = pScsiTmReply->TargetID;
+       channel = pScsiTmReply->Bus;
+       target_reset_list->time_count = jiffies;
 
        /*
         * retry target reset
         */
        if (!target_reset_list->target_reset_issued) {
-               if (mptsas_target_reset(ioc, channel, id)) {
+               if (mptsas_target_reset(ioc, channel, id))
                        target_reset_list->target_reset_issued = 1;
-                       hd->resetPending = 1;
-               }
-               return;
+               return 1;
        }
 
        /*
         * enable work queue to remove device from upper layers
         */
        list_del(&target_reset_list->list);
+       if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off)
+               mptsas_queue_device_delete(ioc,
+                       &target_reset_list->sas_event_data);
 
-       ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
-       if (!ev) {
-               dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
-                   ioc->name,__func__, __LINE__));
-               return;
-       }
-
-       INIT_WORK(&ev->work, mptsas_hotplug_work);
-       ev->ioc = ioc;
-       ev->handle = le16_to_cpu(sas_event_data->DevHandle);
-       ev->parent_handle =
-           le16_to_cpu(sas_event_data->ParentDevHandle);
-       ev->channel = channel;
-       ev->id =id;
-       ev->phy_id = sas_event_data->PhyNum;
-       memcpy(&sas_address, &sas_event_data->SASAddress,
-           sizeof(__le64));
-       ev->sas_address = le64_to_cpu(sas_address);
-       ev->device_info = le32_to_cpu(sas_event_data->DeviceInfo);
-       ev->event_type = MPTSAS_DEL_DEVICE;
-       schedule_work(&ev->work);
-       kfree(target_reset_list);
 
        /*
         * issue target reset to next device in the queue
@@ -699,34 +1217,19 @@ mptsas_dev_reset_complete(MPT_ADAPTER *ioc)
 
        head = &hd->target_reset_list;
        if (list_empty(head))
-               return;
+               return 1;
 
        target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
            list);
 
-       sas_event_data = &target_reset_list->sas_event_data;
-       id = sas_event_data->TargetID;
-       channel = sas_event_data->Bus;
+       id = target_reset_list->sas_event_data.TargetID;
+       channel = target_reset_list->sas_event_data.Bus;
+       target_reset_list->time_count = jiffies;
 
-       if (mptsas_target_reset(ioc, channel, id)) {
+       if (mptsas_target_reset(ioc, channel, id))
                target_reset_list->target_reset_issued = 1;
-               hd->resetPending = 1;
-       }
-}
 
-/**
- * mptsas_taskmgmt_complete
- *
- * @ioc
- * @mf
- * @mr
- *
- **/
-static int
-mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
-{
-       mptsas_dev_reset_complete(ioc);
-       return mptscsih_taskmgmt_complete(ioc, mf, mr);
+       return 1;
 }
 
 /**
@@ -740,37 +1243,59 @@ static int
 mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 {
        MPT_SCSI_HOST   *hd;
-       struct mptsas_target_reset_event *target_reset_list, *n;
        int rc;
 
        rc = mptscsih_ioc_reset(ioc, reset_phase);
+       if ((ioc->bus_type != SAS) || (!rc))
+               return rc;
 
-       if (ioc->bus_type != SAS)
-               goto out;
-
-       if (reset_phase != MPT_IOC_POST_RESET)
-               goto out;
-
-       if (!ioc->sh || !ioc->sh->hostdata)
-               goto out;
        hd = shost_priv(ioc->sh);
        if (!hd->ioc)
                goto out;
 
-       if (list_empty(&hd->target_reset_list))
-               goto out;
-
-       /* flush the target_reset_list */
-       list_for_each_entry_safe(target_reset_list, n,
-           &hd->target_reset_list, list) {
-               list_del(&target_reset_list->list);
-               kfree(target_reset_list);
+       switch (reset_phase) {
+       case MPT_IOC_SETUP_RESET:
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
+               mptsas_fw_event_off(ioc);
+               break;
+       case MPT_IOC_PRE_RESET:
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
+               break;
+       case MPT_IOC_POST_RESET:
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
+               if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
+                       ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET;
+                       complete(&ioc->sas_mgmt.done);
+               }
+               mptsas_cleanup_fw_event_q(ioc);
+               mptsas_queue_rescan(ioc);
+               mptsas_fw_event_on(ioc);
+               break;
+       default:
+               break;
        }
 
  out:
        return rc;
 }
 
+
+/**
+ * enum device_state -
+ * @DEVICE_RETRY: need to retry the TUR
+ * @DEVICE_ERROR: TUR return error, don't add device
+ * @DEVICE_READY: device can be added
+ *
+ */
+enum device_state{
+       DEVICE_RETRY,
+       DEVICE_ERROR,
+       DEVICE_READY,
+};
+
 static int
 mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
                u32 form, u32 form_specific)
@@ -836,15 +1361,308 @@ mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
        return error;
 }
 
+/**
+ *     mptsas_add_end_device - report a new end device to sas transport layer
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @phy_info: decribes attached device
+ *
+ *     return (0) success (1) failure
+ *
+ **/
+static int
+mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
+{
+       struct sas_rphy *rphy;
+       struct sas_port *port;
+       struct sas_identify identify;
+       char *ds = NULL;
+       u8 fw_id;
+
+       if (!phy_info) {
+               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                       "%s: exit at line=%d\n", ioc->name,
+                        __func__, __LINE__));
+               return 1;
+       }
+
+       fw_id = phy_info->attached.id;
+
+       if (mptsas_get_rphy(phy_info)) {
+               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                       "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                        __func__, fw_id, __LINE__));
+               return 2;
+       }
+
+       port = mptsas_get_port(phy_info);
+       if (!port) {
+               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                       "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                        __func__, fw_id, __LINE__));
+               return 3;
+       }
+
+       if (phy_info->attached.device_info &
+           MPI_SAS_DEVICE_INFO_SSP_TARGET)
+               ds = "ssp";
+       if (phy_info->attached.device_info &
+           MPI_SAS_DEVICE_INFO_STP_TARGET)
+               ds = "stp";
+       if (phy_info->attached.device_info &
+           MPI_SAS_DEVICE_INFO_SATA_DEVICE)
+               ds = "sata";
+
+       printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d,"
+           " phy %d, sas_addr 0x%llx\n", ioc->name, ds,
+           phy_info->attached.channel, phy_info->attached.id,
+           phy_info->attached.phy_id, (unsigned long long)
+           phy_info->attached.sas_address);
+
+       mptsas_parse_device_info(&identify, &phy_info->attached);
+       rphy = sas_end_device_alloc(port);
+       if (!rphy) {
+               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                       "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                        __func__, fw_id, __LINE__));
+               return 5; /* non-fatal: an rphy can be added later */
+       }
+
+       rphy->identify = identify;
+       if (sas_rphy_add(rphy)) {
+               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                       "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                        __func__, fw_id, __LINE__));
+               sas_rphy_free(rphy);
+               return 6;
+       }
+       mptsas_set_rphy(ioc, phy_info, rphy);
+       return 0;
+}
+
+/**
+ *     mptsas_del_end_device - report a deleted end device to sas transport layer
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @phy_info: decribes attached device
+ *
+ **/
+static void
+mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
+{
+       struct sas_rphy *rphy;
+       struct sas_port *port;
+       struct mptsas_portinfo *port_info;
+       struct mptsas_phyinfo *phy_info_parent;
+       int i;
+       char *ds = NULL;
+       u8 fw_id;
+       u64 sas_address;
+
+       if (!phy_info)
+               return;
+
+       fw_id = phy_info->attached.id;
+       sas_address = phy_info->attached.sas_address;
+
+       if (!phy_info->port_details) {
+               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                       "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                        __func__, fw_id, __LINE__));
+               return;
+       }
+       rphy = mptsas_get_rphy(phy_info);
+       if (!rphy) {
+               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                       "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                        __func__, fw_id, __LINE__));
+               return;
+       }
+
+       if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR
+               || phy_info->attached.device_info
+                       & MPI_SAS_DEVICE_INFO_SMP_INITIATOR
+               || phy_info->attached.device_info
+                       & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
+               ds = "initiator";
+       if (phy_info->attached.device_info &
+           MPI_SAS_DEVICE_INFO_SSP_TARGET)
+               ds = "ssp";
+       if (phy_info->attached.device_info &
+           MPI_SAS_DEVICE_INFO_STP_TARGET)
+               ds = "stp";
+       if (phy_info->attached.device_info &
+           MPI_SAS_DEVICE_INFO_SATA_DEVICE)
+               ds = "sata";
+
+       dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT
+           "removing %s device: fw_channel %d, fw_id %d, phy %d,"
+           "sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel,
+           phy_info->attached.id, phy_info->attached.phy_id,
+           (unsigned long long) sas_address);
+
+       port = mptsas_get_port(phy_info);
+       if (!port) {
+               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                       "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                        __func__, fw_id, __LINE__));
+               return;
+       }
+       port_info = phy_info->portinfo;
+       phy_info_parent = port_info->phy_info;
+       for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) {
+               if (!phy_info_parent->phy)
+                       continue;
+               if (phy_info_parent->attached.sas_address !=
+                   sas_address)
+                       continue;
+               dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev,
+                   MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n",
+                   ioc->name, phy_info_parent->phy_id,
+                   phy_info_parent->phy);
+               sas_port_delete_phy(port, phy_info_parent->phy);
+       }
+
+       dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
+           "delete port %d, sas_addr (0x%llx)\n", ioc->name,
+            port->port_identifier, (unsigned long long)sas_address);
+       sas_port_delete(port);
+       mptsas_set_port(ioc, phy_info, NULL);
+       mptsas_port_delete(ioc, phy_info->port_details);
+}
+
+struct mptsas_phyinfo *
+mptsas_refreshing_device_handles(MPT_ADAPTER *ioc,
+       struct mptsas_devinfo *sas_device)
+{
+       struct mptsas_phyinfo *phy_info;
+       struct mptsas_portinfo *port_info;
+       int i;
+
+       phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+           sas_device->sas_address);
+       if (!phy_info)
+               goto out;
+       port_info = phy_info->portinfo;
+       if (!port_info)
+               goto out;
+       mutex_lock(&ioc->sas_topology_mutex);
+       for (i = 0; i < port_info->num_phys; i++) {
+               if (port_info->phy_info[i].attached.sas_address !=
+                       sas_device->sas_address)
+                       continue;
+               port_info->phy_info[i].attached.channel = sas_device->channel;
+               port_info->phy_info[i].attached.id = sas_device->id;
+               port_info->phy_info[i].attached.sas_address =
+                   sas_device->sas_address;
+               port_info->phy_info[i].attached.handle = sas_device->handle;
+               port_info->phy_info[i].attached.handle_parent =
+                   sas_device->handle_parent;
+               port_info->phy_info[i].attached.handle_enclosure =
+                   sas_device->handle_enclosure;
+       }
+       mutex_unlock(&ioc->sas_topology_mutex);
+ out:
+       return phy_info;
+}
+
+/**
+ * mptsas_firmware_event_work - work thread for processing fw events
+ * @work: work queue payload containing info describing the event
+ * Context: user
+ *
+ */
+static void
+mptsas_firmware_event_work(struct work_struct *work)
+{
+       struct fw_event_work *fw_event =
+               container_of(work, struct fw_event_work, work.work);
+       MPT_ADAPTER *ioc = fw_event->ioc;
+
+       /* special rescan topology handling */
+       if (fw_event->event == -1) {
+               if (ioc->in_rescan) {
+                       devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                               "%s: rescan ignored as it is in progress\n",
+                               ioc->name, __func__));
+                       return;
+               }
+               devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rescan after "
+                   "reset\n", ioc->name, __func__));
+               ioc->in_rescan = 1;
+               mptsas_not_responding_devices(ioc);
+               mptsas_scan_sas_topology(ioc);
+               ioc->in_rescan = 0;
+               mptsas_free_fw_event(ioc, fw_event);
+               return;
+       }
+
+       /* events handling turned off during host reset */
+       if (ioc->fw_events_off) {
+               mptsas_free_fw_event(ioc, fw_event);
+               return;
+       }
+
+       devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), "
+           "event = (0x%02x)\n", ioc->name, __func__, fw_event,
+           (fw_event->event & 0xFF)));
+
+       switch (fw_event->event) {
+       case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
+               mptsas_send_sas_event(fw_event);
+               break;
+       case MPI_EVENT_INTEGRATED_RAID:
+               mptsas_send_raid_event(fw_event);
+               break;
+       case MPI_EVENT_IR2:
+               mptsas_send_ir2_event(fw_event);
+               break;
+       case MPI_EVENT_PERSISTENT_TABLE_FULL:
+               mptbase_sas_persist_operation(ioc,
+                   MPI_SAS_OP_CLEAR_NOT_PRESENT);
+               mptsas_free_fw_event(ioc, fw_event);
+               break;
+       case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
+               mptsas_broadcast_primative_work(fw_event);
+               break;
+       case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
+               mptsas_send_expander_event(fw_event);
+               break;
+       case MPI_EVENT_SAS_PHY_LINK_STATUS:
+               mptsas_send_link_status_event(fw_event);
+               break;
+       case MPI_EVENT_QUEUE_FULL:
+               mptsas_handle_queue_full_event(fw_event);
+               break;
+       }
+}
+
+
+
 static int
 mptsas_slave_configure(struct scsi_device *sdev)
 {
+       struct Scsi_Host        *host = sdev->host;
+       MPT_SCSI_HOST   *hd = shost_priv(host);
+       MPT_ADAPTER     *ioc = hd->ioc;
+       VirtDevice      *vdevice = sdev->hostdata;
 
-       if (sdev->channel == MPTSAS_RAID_CHANNEL)
+       if (vdevice->vtarget->deleted) {
+               sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n");
+               vdevice->vtarget->deleted = 0;
+       }
+
+       /*
+        * RAID volumes placed beyond the last expected port.
+        * Ignore sending sas mode pages in that case..
+        */
+       if (sdev->channel == MPTSAS_RAID_CHANNEL) {
+               mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev));
                goto out;
+       }
 
        sas_read_port_mode_page(sdev);
 
+       mptsas_add_device_component_starget(ioc, scsi_target(sdev));
+
  out:
        return mptscsih_slave_configure(sdev);
 }
@@ -875,9 +1693,18 @@ mptsas_target_alloc(struct scsi_target *starget)
         * RAID volumes placed beyond the last expected port.
         */
        if (starget->channel == MPTSAS_RAID_CHANNEL) {
-               for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
-                       if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
-                               channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
+               if (!ioc->raid_data.pIocPg2) {
+                       kfree(vtarget);
+                       return -ENXIO;
+               }
+               for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
+                       if (id == ioc->raid_data.pIocPg2->
+                                       RaidVolume[i].VolumeID) {
+                               channel = ioc->raid_data.pIocPg2->
+                                       RaidVolume[i].VolumeBus;
+                       }
+               }
+               vtarget->raidVolume = 1;
                goto out;
        }
 
@@ -926,11 +1753,18 @@ mptsas_target_destroy(struct scsi_target *starget)
        struct sas_rphy         *rphy;
        struct mptsas_portinfo  *p;
        int                      i;
-       MPT_ADAPTER *ioc = hd->ioc;
+       MPT_ADAPTER     *ioc = hd->ioc;
+       VirtTarget      *vtarget;
 
        if (!starget->hostdata)
                return;
 
+       vtarget = starget->hostdata;
+
+       mptsas_del_device_component_by_os(ioc, starget->channel,
+           starget->id);
+
+
        if (starget->channel == MPTSAS_RAID_CHANNEL)
                goto out;
 
@@ -940,12 +1774,21 @@ mptsas_target_destroy(struct scsi_target *starget)
                        if (p->phy_info[i].attached.sas_address !=
                                        rphy->identify.sas_address)
                                continue;
+
+                       starget_printk(KERN_INFO, starget, MYIOC_s_FMT
+                       "delete device: fw_channel %d, fw_id %d, phy %d, "
+                       "sas_addr 0x%llx\n", ioc->name,
+                       p->phy_info[i].attached.channel,
+                       p->phy_info[i].attached.id,
+                       p->phy_info[i].attached.phy_id, (unsigned long long)
+                       p->phy_info[i].attached.sas_address);
+
                        mptsas_set_starget(&p->phy_info[i], NULL);
-                       goto out;
                }
        }
 
  out:
+       vtarget->starget = NULL;
        kfree(starget->hostdata);
        starget->hostdata = NULL;
 }
@@ -1008,6 +1851,8 @@ mptsas_slave_alloc(struct scsi_device *sdev)
 static int
 mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
 {
+       MPT_SCSI_HOST   *hd;
+       MPT_ADAPTER     *ioc;
        VirtDevice      *vdevice = SCpnt->device->hostdata;
 
        if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
@@ -1016,6 +1861,12 @@ mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
                return 0;
        }
 
+       hd = shost_priv(SCpnt->device->host);
+       ioc = hd->ioc;
+
+       if (ioc->sas_discovery_quiesce_io)
+               return SCSI_MLQUEUE_HOST_BUSY;
+
 //     scsi_print_command(SCpnt);
 
        return mptscsih_qcmd(SCpnt,done);
@@ -1114,14 +1965,19 @@ static int mptsas_get_linkerrors(struct sas_phy *phy)
 static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
                MPT_FRAME_HDR *reply)
 {
-       ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD;
+       ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
        if (reply != NULL) {
-               ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID;
+               ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID;
                memcpy(ioc->sas_mgmt.reply, reply,
                    min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
        }
-       complete(&ioc->sas_mgmt.done);
-       return 1;
+
+       if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
+               ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING;
+               complete(&ioc->sas_mgmt.done);
+               return 1;
+       }
+       return 0;
 }
 
 static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
@@ -1160,6 +2016,7 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
                MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
        req->PhyNum = phy->identify.phy_identifier;
 
+       INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
        mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
 
        timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
@@ -1174,7 +2031,7 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
 
        /* a reply frame is expected */
        if ((ioc->sas_mgmt.status &
-           MPT_IOCTL_STATUS_RF_VALID) == 0) {
+           MPT_MGMT_STATUS_RF_VALID) == 0) {
                error = -ENXIO;
                goto out_unlock;
        }
@@ -1191,6 +2048,7 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
        error = 0;
 
  out_unlock:
+       CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
        mutex_unlock(&ioc->sas_mgmt.mutex);
  out:
        return error;
@@ -1304,7 +2162,7 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
                struct mptsas_portinfo *port_info;
 
                mutex_lock(&ioc->sas_topology_mutex);
-               port_info = mptsas_get_hba_portinfo(ioc);
+               port_info = ioc->hba_port_info;
                if (port_info && port_info->phy_info)
                        sas_address =
                                port_info->phy_info[0].phy->identify.sas_address;
@@ -1319,26 +2177,32 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
        /* request */
        flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
                       MPI_SGE_FLAGS_END_OF_BUFFER |
-                      MPI_SGE_FLAGS_DIRECTION |
-                      mpt_addr_size()) << MPI_SGE_FLAGS_SHIFT;
+                      MPI_SGE_FLAGS_DIRECTION)
+                      << MPI_SGE_FLAGS_SHIFT;
        flagsLength |= (blk_rq_bytes(req) - 4);
 
        dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
                                      blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
        if (!dma_addr_out)
                goto put_mf;
-       mpt_add_sge(psge, flagsLength, dma_addr_out);
-       psge += (sizeof(u32) + sizeof(dma_addr_t));
+       ioc->add_sge(psge, flagsLength, dma_addr_out);
+       psge += ioc->SGE_size;
 
        /* response */
-       flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
+       flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+               MPI_SGE_FLAGS_SYSTEM_ADDRESS |
+               MPI_SGE_FLAGS_IOC_TO_HOST |
+               MPI_SGE_FLAGS_END_OF_BUFFER;
+
+       flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
        flagsLength |= blk_rq_bytes(rsp) + 4;
        dma_addr_in =  pci_map_single(ioc->pcidev, bio_data(rsp->bio),
                                      blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
        if (!dma_addr_in)
                goto unmap;
-       mpt_add_sge(psge, flagsLength, dma_addr_in);
+       ioc->add_sge(psge, flagsLength, dma_addr_in);
 
+       INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
        mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
 
        timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
@@ -1351,7 +2215,7 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
        }
        mf = NULL;
 
-       if (ioc->sas_mgmt.status & MPT_IOCTL_STATUS_RF_VALID) {
+       if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
                SmpPassthroughReply_t *smprep;
 
                smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
@@ -1360,7 +2224,8 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
                req->resid_len = 0;
                rsp->resid_len -= smprep->ResponseDataLength;
        } else {
-               printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n",
+               printk(MYIOC_s_ERR_FMT
+                   "%s: smp passthru reply failed to be returned\n",
                    ioc->name, __func__);
                ret = -ENXIO;
        }
@@ -1375,6 +2240,7 @@ put_mf:
        if (mf)
                mpt_free_msg_frame(ioc, mf);
 out_unlock:
+       CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
        mutex_unlock(&ioc->sas_mgmt.mutex);
 out:
        return ret;
@@ -1438,7 +2304,7 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
 
        port_info->num_phys = buffer->NumPhys;
        port_info->phy_info = kcalloc(port_info->num_phys,
-               sizeof(*port_info->phy_info),GFP_KERNEL);
+               sizeof(struct mptsas_phyinfo), GFP_KERNEL);
        if (!port_info->phy_info) {
                error = -ENOMEM;
                goto out_free_consistent;
@@ -1600,10 +2466,6 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
        __le64 sas_address;
        int error=0;
 
-       if (ioc->sas_discovery_runtime &&
-               mptsas_is_end_device(device_info))
-                       goto out;
-
        hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
        hdr.ExtPageLength = 0;
        hdr.PageNumber = 0;
@@ -1644,6 +2506,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
 
        mptsas_print_device_pg0(ioc, buffer);
 
+       memset(device_info, 0, sizeof(struct mptsas_devinfo));
        device_info->handle = le16_to_cpu(buffer->DevHandle);
        device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
        device_info->handle_enclosure =
@@ -1675,7 +2538,9 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
        SasExpanderPage0_t *buffer;
        dma_addr_t dma_handle;
        int i, error;
+       __le64 sas_address;
 
+       memset(port_info, 0, sizeof(struct mptsas_portinfo));
        hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
        hdr.ExtPageLength = 0;
        hdr.PageNumber = 0;
@@ -1721,18 +2586,23 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
        }
 
        /* save config data */
-       port_info->num_phys = buffer->NumPhys;
+       port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1;
        port_info->phy_info = kcalloc(port_info->num_phys,
-               sizeof(*port_info->phy_info),GFP_KERNEL);
+               sizeof(struct mptsas_phyinfo), GFP_KERNEL);
        if (!port_info->phy_info) {
                error = -ENOMEM;
                goto out_free_consistent;
        }
 
+       memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
        for (i = 0; i < port_info->num_phys; i++) {
                port_info->phy_info[i].portinfo = port_info;
                port_info->phy_info[i].handle =
                    le16_to_cpu(buffer->DevHandle);
+               port_info->phy_info[i].identify.sas_address =
+                   le64_to_cpu(sas_address);
+               port_info->phy_info[i].identify.handle_parent =
+                   le16_to_cpu(buffer->ParentDevHandle);
        }
 
  out_free_consistent:
@@ -1752,11 +2622,7 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
        dma_addr_t dma_handle;
        int error=0;
 
-       if (ioc->sas_discovery_runtime &&
-               mptsas_is_end_device(&phy_info->attached))
-                       goto out;
-
-       hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
+       hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION;
        hdr.ExtPageLength = 0;
        hdr.PageNumber = 1;
        hdr.Reserved1 = 0;
@@ -1791,6 +2657,12 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
        cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
 
        error = mpt_config(ioc, &cfg);
+
+       if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
+               error = -ENODEV;
+               goto out;
+       }
+
        if (error)
                goto out_free_consistent;
 
@@ -2010,16 +2882,21 @@ static int mptsas_probe_one_phy(struct device *dev,
                                goto out;
                        }
                        mptsas_set_port(ioc, phy_info, port);
-                       dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                           "sas_port_alloc: port=%p dev=%p port_id=%d\n",
-                           ioc->name, port, dev, port->port_identifier));
+                       devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev,
+                           MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n",
+                           ioc->name, port->port_identifier,
+                           (unsigned long long)phy_info->
+                           attached.sas_address));
                }
-               dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_add_phy: phy_id=%d\n",
-                   ioc->name, phy_info->phy_id));
+               dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                       "sas_port_add_phy: phy_id=%d\n",
+                       ioc->name, phy_info->phy_id));
                sas_port_add_phy(port, phy_info->phy);
                phy_info->sas_port_add_phy = 0;
+               devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev,
+                   MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name,
+                    phy_info->phy_id, phy_info->phy));
        }
-
        if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
 
                struct sas_rphy *rphy;
@@ -2032,18 +2909,17 @@ static int mptsas_probe_one_phy(struct device *dev,
                 * the adding/removing of devices that occur
                 * after start of day.
                 */
-               if (ioc->sas_discovery_runtime &&
-                       mptsas_is_end_device(&phy_info->attached))
-                               goto out;
+               if (mptsas_is_end_device(&phy_info->attached) &&
+                   phy_info->attached.handle_parent) {
+                       goto out;
+               }
 
                mptsas_parse_device_info(&identify, &phy_info->attached);
                if (scsi_is_host_device(parent)) {
                        struct mptsas_portinfo *port_info;
                        int i;
 
-                       mutex_lock(&ioc->sas_topology_mutex);
-                       port_info = mptsas_get_hba_portinfo(ioc);
-                       mutex_unlock(&ioc->sas_topology_mutex);
+                       port_info = ioc->hba_port_info;
 
                        for (i = 0; i < port_info->num_phys; i++)
                                if (port_info->phy_info[i].identify.sas_address ==
@@ -2102,7 +2978,7 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
        struct mptsas_portinfo *port_info, *hba;
        int error = -ENOMEM, i;
 
-       hba = kzalloc(sizeof(*port_info), GFP_KERNEL);
+       hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
        if (! hba)
                goto out;
 
@@ -2112,9 +2988,10 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
 
        mptsas_sas_io_unit_pg1(ioc);
        mutex_lock(&ioc->sas_topology_mutex);
-       port_info = mptsas_get_hba_portinfo(ioc);
+       port_info = ioc->hba_port_info;
        if (!port_info) {
-               port_info = hba;
+               ioc->hba_port_info = port_info = hba;
+               ioc->hba_port_num_phy = port_info->num_phys;
                list_add_tail(&port_info->list, &ioc->sas_topology);
        } else {
                for (i = 0; i < hba->num_phys; i++) {
@@ -2130,15 +3007,22 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
                hba = NULL;
        }
        mutex_unlock(&ioc->sas_topology_mutex);
+#if defined(CPQ_CIM)
+       ioc->num_ports = port_info->num_phys;
+#endif
        for (i = 0; i < port_info->num_phys; i++) {
                mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
                        (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
                         MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
-
+               port_info->phy_info[i].identify.handle =
+                   port_info->phy_info[i].handle;
                mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
                        (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
                         MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
-                        port_info->phy_info[i].handle);
+                        port_info->phy_info[i].identify.handle);
+               if (!ioc->hba_port_sas_addr)
+                       ioc->hba_port_sas_addr =
+                           port_info->phy_info[i].identify.sas_address;
                port_info->phy_info[i].identify.phy_id =
                    port_info->phy_info[i].phy_id = i;
                if (port_info->phy_info[i].attached.handle)
@@ -2163,248 +3047,721 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
        return error;
 }
 
-static int
-mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
+static void
+mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
 {
-       struct mptsas_portinfo *port_info, *p, *ex;
-       struct device *parent;
-       struct sas_rphy *rphy;
-       int error = -ENOMEM, i, j;
-
-       ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
-       if (!ex)
-               goto out;
-
-       error = mptsas_sas_expander_pg0(ioc, ex,
-           (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
-            MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
-       if (error)
-               goto out_free_port_info;
-
-       *handle = ex->phy_info[0].handle;
-
-       mutex_lock(&ioc->sas_topology_mutex);
-       port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
-       if (!port_info) {
-               port_info = ex;
-               list_add_tail(&port_info->list, &ioc->sas_topology);
-       } else {
-               for (i = 0; i < ex->num_phys; i++) {
-                       port_info->phy_info[i].handle =
-                               ex->phy_info[i].handle;
-                       port_info->phy_info[i].port_id =
-                               ex->phy_info[i].port_id;
-               }
-               kfree(ex->phy_info);
-               kfree(ex);
-               ex = NULL;
-       }
-       mutex_unlock(&ioc->sas_topology_mutex);
-
+       struct mptsas_portinfo *parent;
+       struct device *parent_dev;
+       struct sas_rphy *rphy;
+       int             i;
+       u64             sas_address; /* expander sas address */
+       u32             handle;
+
+       handle = port_info->phy_info[0].handle;
+       sas_address = port_info->phy_info[0].identify.sas_address;
        for (i = 0; i < port_info->num_phys; i++) {
                mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
-                       (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
-                        MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
-
-               if (port_info->phy_info[i].identify.handle) {
-                       mptsas_sas_device_pg0(ioc,
-                               &port_info->phy_info[i].identify,
-                               (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
-                                MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
-                               port_info->phy_info[i].identify.handle);
-                       port_info->phy_info[i].identify.phy_id =
-                           port_info->phy_info[i].phy_id;
-               }
+                   (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
+                   MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle);
+
+               mptsas_sas_device_pg0(ioc,
+                   &port_info->phy_info[i].identify,
+                   (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
+                   MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+                   port_info->phy_info[i].identify.handle);
+               port_info->phy_info[i].identify.phy_id =
+                   port_info->phy_info[i].phy_id;
 
                if (port_info->phy_info[i].attached.handle) {
                        mptsas_sas_device_pg0(ioc,
-                               &port_info->phy_info[i].attached,
-                               (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
-                                MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
-                               port_info->phy_info[i].attached.handle);
+                           &port_info->phy_info[i].attached,
+                           (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
+                            MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+                           port_info->phy_info[i].attached.handle);
                        port_info->phy_info[i].attached.phy_id =
                            port_info->phy_info[i].phy_id;
                }
        }
 
-       parent = &ioc->sh->shost_gendev;
-       for (i = 0; i < port_info->num_phys; i++) {
-               mutex_lock(&ioc->sas_topology_mutex);
-               list_for_each_entry(p, &ioc->sas_topology, list) {
-                       for (j = 0; j < p->num_phys; j++) {
-                               if (port_info->phy_info[i].identify.handle !=
-                                               p->phy_info[j].attached.handle)
-                                       continue;
-                               rphy = mptsas_get_rphy(&p->phy_info[j]);
-                               parent = &rphy->dev;
-                       }
-               }
+       mutex_lock(&ioc->sas_topology_mutex);
+       parent = mptsas_find_portinfo_by_handle(ioc,
+           port_info->phy_info[0].identify.handle_parent);
+       if (!parent) {
                mutex_unlock(&ioc->sas_topology_mutex);
+               return;
+       }
+       for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev;
+           i++) {
+               if (parent->phy_info[i].attached.sas_address == sas_address) {
+                       rphy = mptsas_get_rphy(&parent->phy_info[i]);
+                       parent_dev = &rphy->dev;
+               }
        }
+       mutex_unlock(&ioc->sas_topology_mutex);
 
        mptsas_setup_wide_ports(ioc, port_info);
-
        for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
-               mptsas_probe_one_phy(parent, &port_info->phy_info[i],
+               mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i],
                    ioc->sas_index, 0);
-
-       return 0;
-
- out_free_port_info:
-       if (ex) {
-               kfree(ex->phy_info);
-               kfree(ex);
-       }
- out:
-       return error;
 }
 
-/*
- * mptsas_delete_expander_phys
- *
- *
- * This will traverse topology, and remove expanders
- * that are no longer present
- */
 static void
-mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
+mptsas_expander_event_add(MPT_ADAPTER *ioc,
+    MpiEventDataSasExpanderStatusChange_t *expander_data)
 {
-       struct mptsas_portinfo buffer;
-       struct mptsas_portinfo *port_info, *n, *parent;
-       struct mptsas_phyinfo *phy_info;
-       struct sas_port * port;
+       struct mptsas_portinfo *port_info;
        int i;
-       u64     expander_sas_address;
+       __le64 sas_address;
+
+       port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
+       if (!port_info)
+               BUG();
+       port_info->num_phys = (expander_data->NumPhys) ?
+           expander_data->NumPhys : 1;
+       port_info->phy_info = kcalloc(port_info->num_phys,
+           sizeof(struct mptsas_phyinfo), GFP_KERNEL);
+       if (!port_info->phy_info)
+               BUG();
+       memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
+       for (i = 0; i < port_info->num_phys; i++) {
+               port_info->phy_info[i].portinfo = port_info;
+               port_info->phy_info[i].handle =
+                   le16_to_cpu(expander_data->DevHandle);
+               port_info->phy_info[i].identify.sas_address =
+                   le64_to_cpu(sas_address);
+               port_info->phy_info[i].identify.handle_parent =
+                   le16_to_cpu(expander_data->ParentDevHandle);
+       }
 
        mutex_lock(&ioc->sas_topology_mutex);
-       list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
+       list_add_tail(&port_info->list, &ioc->sas_topology);
+       mutex_unlock(&ioc->sas_topology_mutex);
 
-               if (!(port_info->phy_info[0].identify.device_info &
-                   MPI_SAS_DEVICE_INFO_SMP_TARGET))
-                       continue;
+       printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
+           "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
+           (unsigned long long)sas_address);
 
-               if (mptsas_sas_expander_pg0(ioc, &buffer,
-                    (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
-                    MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
-                    port_info->phy_info[0].handle)) {
+       mptsas_expander_refresh(ioc, port_info);
+}
 
-                       /*
-                        * Obtain the port_info instance to the parent port
-                        */
-                       parent = mptsas_find_portinfo_by_handle(ioc,
-                           port_info->phy_info[0].identify.handle_parent);
-
-                       if (!parent)
-                               goto next_port;
+/**
+ * mptsas_delete_expander_siblings - remove siblings attached to expander
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @parent: the parent port_info object
+ * @expander: the expander port_info object
+ **/
+static void
+mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo
+    *parent, struct mptsas_portinfo *expander)
+{
+       struct mptsas_phyinfo *phy_info;
+       struct mptsas_portinfo *port_info;
+       struct sas_rphy *rphy;
+       int i;
 
-                       expander_sas_address =
-                               port_info->phy_info[0].identify.sas_address;
+       phy_info = expander->phy_info;
+       for (i = 0; i < expander->num_phys; i++, phy_info++) {
+               rphy = mptsas_get_rphy(phy_info);
+               if (!rphy)
+                       continue;
+               if (rphy->identify.device_type == SAS_END_DEVICE)
+                       mptsas_del_end_device(ioc, phy_info);
+       }
 
+       phy_info = expander->phy_info;
+       for (i = 0; i < expander->num_phys; i++, phy_info++) {
+               rphy = mptsas_get_rphy(phy_info);
+               if (!rphy)
+                       continue;
+               if (rphy->identify.device_type ==
+                   MPI_SAS_DEVICE_INFO_EDGE_EXPANDER ||
+                   rphy->identify.device_type ==
+                   MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
+                       port_info = mptsas_find_portinfo_by_sas_address(ioc,
+                           rphy->identify.sas_address);
+                       if (!port_info)
+                               continue;
+                       if (port_info == parent) /* backlink rphy */
+                               continue;
                        /*
-                        * Delete rphys in the parent that point
-                        * to this expander.  The transport layer will
-                        * cleanup all the children.
-                        */
-                       phy_info = parent->phy_info;
-                       for (i = 0; i < parent->num_phys; i++, phy_info++) {
-                               port = mptsas_get_port(phy_info);
-                               if (!port)
-                                       continue;
-                               if (phy_info->attached.sas_address !=
-                                       expander_sas_address)
-                                       continue;
-                               dsaswideprintk(ioc,
-                                   dev_printk(KERN_DEBUG, &port->dev,
-                                   MYIOC_s_FMT "delete port (%d)\n", ioc->name,
-                                   port->port_identifier));
-                               sas_port_delete(port);
-                               mptsas_port_delete(ioc, phy_info->port_details);
-                       }
- next_port:
+                       Delete this expander even if the expdevpage is exists
+                       because the parent expander is already deleted
+                       */
+                       mptsas_expander_delete(ioc, port_info, 1);
+               }
+       }
+}
 
-                       phy_info = port_info->phy_info;
-                       for (i = 0; i < port_info->num_phys; i++, phy_info++)
-                               mptsas_port_delete(ioc, phy_info->port_details);
 
-                       list_del(&port_info->list);
-                       kfree(port_info->phy_info);
-                       kfree(port_info);
-               }
-               /*
-               * Free this memory allocated from inside
-               * mptsas_sas_expander_pg0
-               */
+/**
+ *     mptsas_expander_delete - remove this expander
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @port_info: expander port_info struct
+ *     @force: Flag to forcefully delete the expander
+ *
+ **/
+
+static void mptsas_expander_delete(MPT_ADAPTER *ioc,
+               struct mptsas_portinfo *port_info, u8 force)
+{
+
+       struct mptsas_portinfo *parent;
+       int             i;
+       u64             expander_sas_address;
+       struct mptsas_phyinfo *phy_info;
+       struct mptsas_portinfo buffer;
+       struct mptsas_portinfo_details *port_details;
+       struct sas_port *port;
+
+       if (!port_info)
+               return;
+
+       /* see if expander is still there before deleting */
+       mptsas_sas_expander_pg0(ioc, &buffer,
+           (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
+           MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
+           port_info->phy_info[0].identify.handle);
+
+       if (buffer.num_phys) {
                kfree(buffer.phy_info);
+               if (!force)
+                       return;
        }
-       mutex_unlock(&ioc->sas_topology_mutex);
+
+
+       /*
+        * Obtain the port_info instance to the parent port
+        */
+       port_details = NULL;
+       expander_sas_address =
+           port_info->phy_info[0].identify.sas_address;
+       parent = mptsas_find_portinfo_by_handle(ioc,
+           port_info->phy_info[0].identify.handle_parent);
+       mptsas_delete_expander_siblings(ioc, parent, port_info);
+       if (!parent)
+               goto out;
+
+       /*
+        * Delete rphys in the parent that point
+        * to this expander.
+        */
+       phy_info = parent->phy_info;
+       port = NULL;
+       for (i = 0; i < parent->num_phys; i++, phy_info++) {
+               if (!phy_info->phy)
+                       continue;
+               if (phy_info->attached.sas_address !=
+                   expander_sas_address)
+                       continue;
+               if (!port) {
+                       port = mptsas_get_port(phy_info);
+                       port_details = phy_info->port_details;
+               }
+               dev_printk(KERN_DEBUG, &phy_info->phy->dev,
+                   MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name,
+                   phy_info->phy_id, phy_info->phy);
+               sas_port_delete_phy(port, phy_info->phy);
+       }
+       if (port) {
+               dev_printk(KERN_DEBUG, &port->dev,
+                   MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n",
+                   ioc->name, port->port_identifier,
+                   (unsigned long long)expander_sas_address);
+               sas_port_delete(port);
+               mptsas_port_delete(ioc, port_details);
+       }
+ out:
+
+       printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, "
+           "sas_addr (0x%llx)\n",  ioc->name, port_info->num_phys,
+           (unsigned long long)expander_sas_address);
+
+       /*
+        * free link
+        */
+       list_del(&port_info->list);
+       kfree(port_info->phy_info);
+       kfree(port_info);
 }
 
-/*
- * Start of day discovery
+
+/**
+ * mptsas_send_expander_event - expanders events
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @expander_data: event data
+ *
+ *
+ * This function handles adding, removing, and refreshing
+ * device handles within the expander objects.
  */
 static void
+mptsas_send_expander_event(struct fw_event_work *fw_event)
+{
+       MPT_ADAPTER *ioc;
+       MpiEventDataSasExpanderStatusChange_t *expander_data;
+       struct mptsas_portinfo *port_info;
+       __le64 sas_address;
+       int i;
+
+       ioc = fw_event->ioc;
+       expander_data = (MpiEventDataSasExpanderStatusChange_t *)
+           fw_event->event_data;
+       memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
+       port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
+
+       if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) {
+               if (port_info) {
+                       for (i = 0; i < port_info->num_phys; i++) {
+                               port_info->phy_info[i].portinfo = port_info;
+                               port_info->phy_info[i].handle =
+                                   le16_to_cpu(expander_data->DevHandle);
+                               port_info->phy_info[i].identify.sas_address =
+                                   le64_to_cpu(sas_address);
+                               port_info->phy_info[i].identify.handle_parent =
+                                   le16_to_cpu(expander_data->ParentDevHandle);
+                       }
+                       mptsas_expander_refresh(ioc, port_info);
+               } else if (!port_info && expander_data->NumPhys)
+                       mptsas_expander_event_add(ioc, expander_data);
+       } else if (expander_data->ReasonCode ==
+           MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING)
+               mptsas_expander_delete(ioc, port_info, 0);
+
+       mptsas_free_fw_event(ioc, fw_event);
+}
+
+
+/**
+ * mptsas_expander_add -
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @handle:
+ *
+ */
+struct mptsas_portinfo *
+mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle)
+{
+       struct mptsas_portinfo buffer, *port_info;
+       int i;
+
+       if ((mptsas_sas_expander_pg0(ioc, &buffer,
+           (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
+           MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)))
+               return NULL;
+
+       port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC);
+       if (!port_info) {
+               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+               "%s: exit at line=%d\n", ioc->name,
+               __func__, __LINE__));
+               return NULL;
+       }
+       port_info->num_phys = buffer.num_phys;
+       port_info->phy_info = buffer.phy_info;
+       for (i = 0; i < port_info->num_phys; i++)
+               port_info->phy_info[i].portinfo = port_info;
+       mutex_lock(&ioc->sas_topology_mutex);
+       list_add_tail(&port_info->list, &ioc->sas_topology);
+       mutex_unlock(&ioc->sas_topology_mutex);
+       printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
+           "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
+           (unsigned long long)buffer.phy_info[0].identify.sas_address);
+       mptsas_expander_refresh(ioc, port_info);
+       return port_info;
+}
+
+static void
+mptsas_send_link_status_event(struct fw_event_work *fw_event)
+{
+       MPT_ADAPTER *ioc;
+       MpiEventDataSasPhyLinkStatus_t *link_data;
+       struct mptsas_portinfo *port_info;
+       struct mptsas_phyinfo *phy_info = NULL;
+       __le64 sas_address;
+       u8 phy_num;
+       u8 link_rate;
+
+       ioc = fw_event->ioc;
+       link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data;
+
+       memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64));
+       sas_address = le64_to_cpu(sas_address);
+       link_rate = link_data->LinkRates >> 4;
+       phy_num = link_data->PhyNum;
+
+       port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
+       if (port_info) {
+               phy_info = &port_info->phy_info[phy_num];
+               if (phy_info)
+                       phy_info->negotiated_link_rate = link_rate;
+       }
+
+       if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
+           link_rate == MPI_SAS_IOUNIT0_RATE_3_0) {
+
+               if (!port_info) {
+                       if (ioc->old_sas_discovery_protocal) {
+                               port_info = mptsas_expander_add(ioc,
+                                       le16_to_cpu(link_data->DevHandle));
+                               if (port_info)
+                                       goto out;
+                       }
+                       goto out;
+               }
+
+               if (port_info == ioc->hba_port_info)
+                       mptsas_probe_hba_phys(ioc);
+               else
+                       mptsas_expander_refresh(ioc, port_info);
+       } else if (phy_info && phy_info->phy) {
+               if (link_rate ==  MPI_SAS_IOUNIT0_RATE_PHY_DISABLED)
+                       phy_info->phy->negotiated_linkrate =
+                           SAS_PHY_DISABLED;
+               else if (link_rate ==
+                   MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
+                       phy_info->phy->negotiated_linkrate =
+                           SAS_LINK_RATE_FAILED;
+               else
+                       phy_info->phy->negotiated_linkrate =
+                           SAS_LINK_RATE_UNKNOWN;
+       }
+ out:
+       mptsas_free_fw_event(ioc, fw_event);
+}
+
+static void
+mptsas_not_responding_devices(MPT_ADAPTER *ioc)
+{
+       struct mptsas_portinfo buffer, *port_info;
+       struct mptsas_device_info       *sas_info;
+       struct mptsas_devinfo sas_device;
+       u32     handle;
+       VirtTarget *vtarget = NULL;
+       struct mptsas_phyinfo *phy_info;
+       u8 found_expander;
+       int retval, retry_count;
+       unsigned long flags;
+
+       mpt_findImVolumes(ioc);
+
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       if (ioc->ioc_reset_in_progress) {
+               dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                  "%s: exiting due to a parallel reset \n", ioc->name,
+                   __func__));
+               spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+               return;
+       }
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+
+       /* devices, logical volumes */
+       mutex_lock(&ioc->sas_device_info_mutex);
+ redo_device_scan:
+       list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
+               if (sas_info->is_cached)
+                       continue;
+               if (!sas_info->is_logical_volume) {
+                       sas_device.handle = 0;
+                       retry_count = 0;
+retry_page:
+                       retval = mptsas_sas_device_pg0(ioc, &sas_device,
+                               (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
+                               << MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+                               (sas_info->fw.channel << 8) +
+                               sas_info->fw.id);
+
+                       if (sas_device.handle)
+                               continue;
+                       if (retval == -EBUSY) {
+                               spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+                               if (ioc->ioc_reset_in_progress) {
+                                       dfailprintk(ioc,
+                                       printk(MYIOC_s_DEBUG_FMT
+                                       "%s: exiting due to reset\n",
+                                       ioc->name, __func__));
+                                       spin_unlock_irqrestore
+                                       (&ioc->taskmgmt_lock, flags);
+                                       mutex_unlock(&ioc->
+                                       sas_device_info_mutex);
+                                       return;
+                               }
+                               spin_unlock_irqrestore(&ioc->taskmgmt_lock,
+                               flags);
+                       }
+
+                       if (retval && (retval != -ENODEV)) {
+                               if (retry_count < 10) {
+                                       retry_count++;
+                                       goto retry_page;
+                               } else {
+                                       devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                                       "%s: Config page retry exceeded retry "
+                                       "count deleting device 0x%llx\n",
+                                       ioc->name, __func__,
+                                       sas_info->sas_address));
+                               }
+                       }
+
+                       /* delete device */
+                       vtarget = mptsas_find_vtarget(ioc,
+                               sas_info->fw.channel, sas_info->fw.id);
+
+                       if (vtarget)
+                               vtarget->deleted = 1;
+
+                       phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+                                       sas_info->sas_address);
+
+                       if (phy_info) {
+                               mptsas_del_end_device(ioc, phy_info);
+                               goto redo_device_scan;
+                       }
+               } else
+                       mptsas_volume_delete(ioc, sas_info->fw.id);
+       }
+       mutex_lock(&ioc->sas_device_info_mutex);
+
+       /* expanders */
+       mutex_lock(&ioc->sas_topology_mutex);
+ redo_expander_scan:
+       list_for_each_entry(port_info, &ioc->sas_topology, list) {
+
+               if (port_info->phy_info &&
+                   (!(port_info->phy_info[0].identify.device_info &
+                   MPI_SAS_DEVICE_INFO_SMP_TARGET)))
+                       continue;
+               found_expander = 0;
+               handle = 0xFFFF;
+               while (!mptsas_sas_expander_pg0(ioc, &buffer,
+                   (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
+                    MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) &&
+                   !found_expander) {
+
+                       handle = buffer.phy_info[0].handle;
+                       if (buffer.phy_info[0].identify.sas_address ==
+                           port_info->phy_info[0].identify.sas_address) {
+                               found_expander = 1;
+                       }
+                       kfree(buffer.phy_info);
+               }
+
+               if (!found_expander) {
+                       mptsas_expander_delete(ioc, port_info, 0);
+                       goto redo_expander_scan;
+               }
+       }
+       mutex_lock(&ioc->sas_topology_mutex);
+}
+
+/**
+ *     mptsas_probe_expanders - adding expanders
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *
+ **/
+static void
+mptsas_probe_expanders(MPT_ADAPTER *ioc)
+{
+       struct mptsas_portinfo buffer, *port_info;
+       u32                     handle;
+       int i;
+
+       handle = 0xFFFF;
+       while (!mptsas_sas_expander_pg0(ioc, &buffer,
+           (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
+            MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) {
+
+               handle = buffer.phy_info[0].handle;
+               port_info = mptsas_find_portinfo_by_sas_address(ioc,
+                   buffer.phy_info[0].identify.sas_address);
+
+               if (port_info) {
+                       /* refreshing handles */
+                       for (i = 0; i < buffer.num_phys; i++) {
+                               port_info->phy_info[i].handle = handle;
+                               port_info->phy_info[i].identify.handle_parent =
+                                   buffer.phy_info[0].identify.handle_parent;
+                       }
+                       mptsas_expander_refresh(ioc, port_info);
+                       kfree(buffer.phy_info);
+                       continue;
+               }
+
+               port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
+               if (!port_info) {
+                       dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                       "%s: exit at line=%d\n", ioc->name,
+                       __func__, __LINE__));
+                       return;
+               }
+               port_info->num_phys = buffer.num_phys;
+               port_info->phy_info = buffer.phy_info;
+               for (i = 0; i < port_info->num_phys; i++)
+                       port_info->phy_info[i].portinfo = port_info;
+               mutex_lock(&ioc->sas_topology_mutex);
+               list_add_tail(&port_info->list, &ioc->sas_topology);
+               mutex_unlock(&ioc->sas_topology_mutex);
+               printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
+                   "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
+           (unsigned long long)buffer.phy_info[0].identify.sas_address);
+               mptsas_expander_refresh(ioc, port_info);
+       }
+}
+
+static void
+mptsas_probe_devices(MPT_ADAPTER *ioc)
+{
+       u16 handle;
+       struct mptsas_devinfo sas_device;
+       struct mptsas_phyinfo *phy_info;
+
+       handle = 0xFFFF;
+       while (!(mptsas_sas_device_pg0(ioc, &sas_device,
+           MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
+
+               handle = sas_device.handle;
+
+               if ((sas_device.device_info &
+                    (MPI_SAS_DEVICE_INFO_SSP_TARGET |
+                     MPI_SAS_DEVICE_INFO_STP_TARGET |
+                     MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
+                       continue;
+
+               phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
+               if (!phy_info)
+                       continue;
+
+               if (mptsas_get_rphy(phy_info))
+                       continue;
+
+               mptsas_add_end_device(ioc, phy_info);
+       }
+}
+
+/**
+ *     mptsas_scan_sas_topology -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @sas_address:
+ *
+ **/
+static void
 mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
 {
-       u32 handle = 0xFFFF;
+       struct scsi_device *sdev;
        int i;
 
-       mutex_lock(&ioc->sas_discovery_mutex);
        mptsas_probe_hba_phys(ioc);
-       while (!mptsas_probe_expander_phys(ioc, &handle))
-               ;
+       mptsas_probe_expanders(ioc);
+       mptsas_probe_devices(ioc);
+
        /*
          Reporting RAID volumes.
        */
-       if (!ioc->ir_firmware)
-               goto out;
-       if (!ioc->raid_data.pIocPg2)
-               goto out;
-       if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
-               goto out;
+       if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 ||
+           !ioc->raid_data.pIocPg2->NumActiveVolumes)
+               return;
        for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
+               sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
+                   ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
+               if (sdev) {
+                       scsi_device_put(sdev);
+                       continue;
+               }
+               printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
+                   "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
+                   ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID);
                scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
                    ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
        }
- out:
-       mutex_unlock(&ioc->sas_discovery_mutex);
 }
 
-/*
- * Work queue thread to handle Runtime discovery
- * Mere purpose is the hot add/delete of expanders
- *(Mutex UNLOCKED)
- */
+
 static void
-__mptsas_discovery_work(MPT_ADAPTER *ioc)
+mptsas_handle_queue_full_event(struct fw_event_work *fw_event)
 {
-       u32 handle = 0xFFFF;
+       MPT_ADAPTER *ioc;
+       EventDataQueueFull_t *qfull_data;
+       struct mptsas_device_info *sas_info;
+       struct scsi_device      *sdev;
+       int depth;
+       int id = -1;
+       int channel = -1;
+       int fw_id, fw_channel;
+       u16 current_depth;
+
+
+       ioc = fw_event->ioc;
+       qfull_data = (EventDataQueueFull_t *)fw_event->event_data;
+       fw_id = qfull_data->TargetID;
+       fw_channel = qfull_data->Bus;
+       current_depth = le16_to_cpu(qfull_data->CurrentDepth);
+
+       /* if hidden raid component, look for the volume id */
+       mutex_lock(&ioc->sas_device_info_mutex);
+       if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) {
+               list_for_each_entry(sas_info, &ioc->sas_device_info_list,
+                   list) {
+                       if (sas_info->is_cached ||
+                           sas_info->is_logical_volume)
+                               continue;
+                       if (sas_info->is_hidden_raid_component &&
+                           (sas_info->fw.channel == fw_channel &&
+                           sas_info->fw.id == fw_id)) {
+                               id = sas_info->volume_id;
+                               channel = MPTSAS_RAID_CHANNEL;
+                               goto out;
+                       }
+               }
+       } else {
+               list_for_each_entry(sas_info, &ioc->sas_device_info_list,
+                   list) {
+                       if (sas_info->is_cached ||
+                           sas_info->is_hidden_raid_component ||
+                           sas_info->is_logical_volume)
+                               continue;
+                       if (sas_info->fw.channel == fw_channel &&
+                           sas_info->fw.id == fw_id) {
+                               id = sas_info->os.id;
+                               channel = sas_info->os.channel;
+                               goto out;
+                       }
+               }
 
-       ioc->sas_discovery_runtime=1;
-       mptsas_delete_expander_phys(ioc);
-       mptsas_probe_hba_phys(ioc);
-       while (!mptsas_probe_expander_phys(ioc, &handle))
-               ;
-       ioc->sas_discovery_runtime=0;
-}
+       }
 
-/*
- * Work queue thread to handle Runtime discovery
- * Mere purpose is the hot add/delete of expanders
- *(Mutex LOCKED)
- */
-static void
-mptsas_discovery_work(struct work_struct *work)
-{
-       struct mptsas_discovery_event *ev =
-               container_of(work, struct mptsas_discovery_event, work);
-       MPT_ADAPTER *ioc = ev->ioc;
+ out:
+       mutex_unlock(&ioc->sas_device_info_mutex);
+
+       if (id != -1) {
+               shost_for_each_device(sdev, ioc->sh) {
+                       if (sdev->id == id && sdev->channel == channel) {
+                               if (current_depth > sdev->queue_depth) {
+                                       sdev_printk(KERN_INFO, sdev,
+                                           "strange observation, the queue "
+                                           "depth is (%d) meanwhile fw queue "
+                                           "depth (%d)\n", sdev->queue_depth,
+                                           current_depth);
+                                       continue;
+                               }
+                               depth = scsi_track_queue_full(sdev,
+                                   current_depth - 1);
+                               if (depth > 0)
+                                       sdev_printk(KERN_INFO, sdev,
+                                       "Queue depth reduced to (%d)\n",
+                                          depth);
+                               else if (depth < 0)
+                                       sdev_printk(KERN_INFO, sdev,
+                                       "Tagged Command Queueing is being "
+                                       "disabled\n");
+                               else if (depth == 0)
+                                       sdev_printk(KERN_INFO, sdev,
+                                       "Queue depth not changed yet\n");
+                       }
+               }
+       }
 
-       mutex_lock(&ioc->sas_discovery_mutex);
-       __mptsas_discovery_work(ioc);
-       mutex_unlock(&ioc->sas_discovery_mutex);
-       kfree(ev);
+       mptsas_free_fw_event(ioc, fw_event);
 }
 
+
 static struct mptsas_phyinfo *
 mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
 {
@@ -2429,69 +3786,80 @@ mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
        return phy_info;
 }
 
+/**
+ *     mptsas_find_phyinfo_by_phys_disk_num -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @phys_disk_num:
+ *     @channel:
+ *     @id:
+ *
+ **/
 static struct mptsas_phyinfo *
-mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id)
+mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num,
+       u8 channel, u8 id)
 {
-       struct mptsas_portinfo *port_info;
        struct mptsas_phyinfo *phy_info = NULL;
+       struct mptsas_portinfo *port_info;
+       RaidPhysDiskPage1_t *phys_disk = NULL;
+       int num_paths;
+       u64 sas_address = 0;
        int i;
 
-       mutex_lock(&ioc->sas_topology_mutex);
-       list_for_each_entry(port_info, &ioc->sas_topology, list) {
-               for (i = 0; i < port_info->num_phys; i++) {
-                       if (!mptsas_is_end_device(
-                               &port_info->phy_info[i].attached))
-                               continue;
-                       if (port_info->phy_info[i].attached.id != id)
-                               continue;
-                       if (port_info->phy_info[i].attached.channel != channel)
-                               continue;
-                       phy_info = &port_info->phy_info[i];
-                       break;
+       phy_info = NULL;
+       if (!ioc->raid_data.pIocPg3)
+               return NULL;
+       /* dual port support */
+       num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num);
+       if (!num_paths)
+               goto out;
+       phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
+          (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
+       if (!phys_disk)
+               goto out;
+       mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk);
+       for (i = 0; i < num_paths; i++) {
+               if ((phys_disk->Path[i].Flags & 1) != 0)
+                       /* entry no longer valid */
+                       continue;
+               if ((id == phys_disk->Path[i].PhysDiskID) &&
+                   (channel == phys_disk->Path[i].PhysDiskBus)) {
+                       memcpy(&sas_address, &phys_disk->Path[i].WWID,
+                               sizeof(u64));
+                       phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+                                       sas_address);
+                       goto out;
                }
        }
-       mutex_unlock(&ioc->sas_topology_mutex);
-       return phy_info;
-}
 
-static struct mptsas_phyinfo *
-mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
-{
-       struct mptsas_portinfo *port_info;
-       struct mptsas_phyinfo *phy_info = NULL;
-       int i;
+ out:
+       kfree(phys_disk);
+       if (phy_info)
+               return phy_info;
 
+       /*
+        * Extra code to handle RAID0 case, where the sas_address is not updated
+        * in phys_disk_page_1 when hotswapped
+        */
        mutex_lock(&ioc->sas_topology_mutex);
        list_for_each_entry(port_info, &ioc->sas_topology, list) {
-               for (i = 0; i < port_info->num_phys; i++) {
+               for (i = 0; i < port_info->num_phys && !phy_info; i++) {
                        if (!mptsas_is_end_device(
                                &port_info->phy_info[i].attached))
                                continue;
                        if (port_info->phy_info[i].attached.phys_disk_num == ~0)
                                continue;
-                       if (port_info->phy_info[i].attached.phys_disk_num != id)
-                               continue;
-                       if (port_info->phy_info[i].attached.channel != channel)
-                               continue;
-                       phy_info = &port_info->phy_info[i];
-                       break;
+                       if ((port_info->phy_info[i].attached.phys_disk_num ==
+                           phys_disk_num) &&
+                           (port_info->phy_info[i].attached.id == id) &&
+                           (port_info->phy_info[i].attached.channel ==
+                            channel))
+                               phy_info = &port_info->phy_info[i];
                }
        }
        mutex_unlock(&ioc->sas_topology_mutex);
        return phy_info;
 }
 
-/*
- * Work queue thread to clear the persitency table
- */
-static void
-mptsas_persist_clear_table(struct work_struct *work)
-{
-       MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task);
-
-       mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
-}
-
 static void
 mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
 {
@@ -2517,7 +3885,8 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
        pRaidVolumePage0_t              buffer = NULL;
        RaidPhysDiskPage0_t             phys_disk;
        int                             i;
-       struct mptsas_hotplug_event     *ev;
+       struct mptsas_phyinfo   *phy_info;
+       struct mptsas_devinfo           sas_device;
 
        memset(&cfg, 0 , sizeof(CONFIGPARMS));
        memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
@@ -2557,20 +3926,16 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
                    buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
                        continue;
 
-               ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
-               if (!ev) {
-                       printk(MYIOC_s_WARN_FMT "mptsas: lost hotplug event\n", ioc->name);
-                       goto out;
-               }
+               if (mptsas_sas_device_pg0(ioc, &sas_device,
+                   (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
+                    MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+                       (phys_disk.PhysDiskBus << 8) +
+                       phys_disk.PhysDiskID))
+                       continue;
 
-               INIT_WORK(&ev->work, mptsas_hotplug_work);
-               ev->ioc = ioc;
-               ev->id = phys_disk.PhysDiskID;
-               ev->channel = phys_disk.PhysDiskBus;
-               ev->phys_disk_num_valid = 1;
-               ev->phys_disk_num = phys_disk.PhysDiskNum;
-               ev->event_type = MPTSAS_ADD_DEVICE;
-               schedule_work(&ev->work);
+               phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+                   sas_device.sas_address);
+               mptsas_add_end_device(ioc, phy_info);
        }
 
  out:
@@ -2582,417 +3947,386 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
  * Work queue thread to handle SAS hotplug events
  */
 static void
-mptsas_hotplug_work(struct work_struct *work)
+mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
+    struct mptsas_hotplug_event *hot_plug_info)
 {
-       struct mptsas_hotplug_event *ev =
-               container_of(work, struct mptsas_hotplug_event, work);
-
-       MPT_ADAPTER *ioc = ev->ioc;
        struct mptsas_phyinfo *phy_info;
-       struct sas_rphy *rphy;
-       struct sas_port *port;
-       struct scsi_device *sdev;
        struct scsi_target * starget;
-       struct sas_identify identify;
-       char *ds = NULL;
        struct mptsas_devinfo sas_device;
        VirtTarget *vtarget;
-       VirtDevice *vdevice;
+       int i;
+
+       switch (hot_plug_info->event_type) {
+
+       case MPTSAS_ADD_PHYSDISK:
+
+               if (!ioc->raid_data.pIocPg2)
+                       break;
+
+               for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
+                       if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID ==
+                           hot_plug_info->id) {
+                               printk(MYIOC_s_WARN_FMT "firmware bug: unable "
+                                   "to add hidden disk - target_id matchs "
+                                   "volume_id\n", ioc->name);
+                               mptsas_free_fw_event(ioc, fw_event);
+                               return;
+                       }
+               }
+               mpt_findImVolumes(ioc);
+
+       case MPTSAS_ADD_DEVICE:
+               memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
+               mptsas_sas_device_pg0(ioc, &sas_device,
+                   (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
+                   MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+                   (hot_plug_info->channel << 8) +
+                   hot_plug_info->id);
+
+               if (!sas_device.handle)
+                       return;
+
+               phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
+               if (!phy_info)
+                       break;
+
+               if (mptsas_get_rphy(phy_info))
+                       break;
+
+               mptsas_add_end_device(ioc, phy_info);
+               break;
 
-       mutex_lock(&ioc->sas_discovery_mutex);
-       switch (ev->event_type) {
        case MPTSAS_DEL_DEVICE:
+               phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+                   hot_plug_info->sas_address);
+               mptsas_del_end_device(ioc, phy_info);
+               break;
 
-               phy_info = NULL;
-               if (ev->phys_disk_num_valid) {
-                       if (ev->hidden_raid_component){
-                               if (mptsas_sas_device_pg0(ioc, &sas_device,
-                                   (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
-                                    MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
-                                   (ev->channel << 8) + ev->id)) {
-                                       dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                                       "%s: exit at line=%d\n", ioc->name,
-                                               __func__, __LINE__));
-                                       break;
-                               }
-                               phy_info = mptsas_find_phyinfo_by_sas_address(
-                                   ioc, sas_device.sas_address);
-                       }else
-                               phy_info = mptsas_find_phyinfo_by_phys_disk_num(
-                                   ioc, ev->channel, ev->phys_disk_num);
-               }
+       case MPTSAS_DEL_PHYSDISK:
 
-               if (!phy_info)
-                       phy_info = mptsas_find_phyinfo_by_target(ioc,
-                           ev->channel, ev->id);
+               mpt_findImVolumes(ioc);
 
-               /*
-                * Sanity checks, for non-existing phys and remote rphys.
-                */
-               if (!phy_info){
+               phy_info = mptsas_find_phyinfo_by_phys_disk_num(
+                               ioc, hot_plug_info->phys_disk_num,
+                               hot_plug_info->channel,
+                               hot_plug_info->id);
+               mptsas_del_end_device(ioc, phy_info);
+               break;
+
+       case MPTSAS_ADD_PHYSDISK_REPROBE:
+
+               if (mptsas_sas_device_pg0(ioc, &sas_device,
+                   (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
+                    MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+                   (hot_plug_info->channel << 8) + hot_plug_info->id)) {
                        dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                               "%s: exit at line=%d\n", ioc->name,
-                               __func__, __LINE__));
+                       "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                                __func__, hot_plug_info->id, __LINE__));
                        break;
                }
-               if (!phy_info->port_details) {
+
+               phy_info = mptsas_find_phyinfo_by_sas_address(
+                   ioc, sas_device.sas_address);
+
+               if (!phy_info) {
                        dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                               "%s: exit at line=%d\n", ioc->name,
-                               __func__, __LINE__));
+                               "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                                __func__, hot_plug_info->id, __LINE__));
                        break;
                }
-               rphy = mptsas_get_rphy(phy_info);
-               if (!rphy) {
+
+               starget = mptsas_get_starget(phy_info);
+               if (!starget) {
                        dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                               "%s: exit at line=%d\n", ioc->name,
-                               __func__, __LINE__));
+                               "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                                __func__, hot_plug_info->id, __LINE__));
                        break;
                }
 
-               port = mptsas_get_port(phy_info);
-               if (!port) {
+               vtarget = starget->hostdata;
+               if (!vtarget) {
                        dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                               "%s: exit at line=%d\n", ioc->name,
-                               __func__, __LINE__));
+                               "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                                __func__, hot_plug_info->id, __LINE__));
                        break;
                }
 
-               starget = mptsas_get_starget(phy_info);
-               if (starget) {
-                       vtarget = starget->hostdata;
-
-                       if (!vtarget) {
-                               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                                       "%s: exit at line=%d\n", ioc->name,
-                                       __func__, __LINE__));
-                               break;
-                       }
+               mpt_findImVolumes(ioc);
 
-                       /*
-                        * Handling  RAID components
-                        */
-                       if (ev->phys_disk_num_valid &&
-                           ev->hidden_raid_component) {
-                               printk(MYIOC_s_INFO_FMT
-                                   "RAID Hidding: channel=%d, id=%d, "
-                                   "physdsk %d \n", ioc->name, ev->channel,
-                                   ev->id, ev->phys_disk_num);
-                               vtarget->id = ev->phys_disk_num;
-                               vtarget->tflags |=
-                                   MPT_TARGET_FLAGS_RAID_COMPONENT;
-                               mptsas_reprobe_target(starget, 1);
-                               phy_info->attached.phys_disk_num =
-                                   ev->phys_disk_num;
-                       break;
-                       }
-               }
+               starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: "
+                   "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
+                   ioc->name, hot_plug_info->channel, hot_plug_info->id,
+                   hot_plug_info->phys_disk_num, (unsigned long long)
+                   sas_device.sas_address);
 
-               if (phy_info->attached.device_info &
-                   MPI_SAS_DEVICE_INFO_SSP_TARGET)
-                       ds = "ssp";
-               if (phy_info->attached.device_info &
-                   MPI_SAS_DEVICE_INFO_STP_TARGET)
-                       ds = "stp";
-               if (phy_info->attached.device_info &
-                   MPI_SAS_DEVICE_INFO_SATA_DEVICE)
-                       ds = "sata";
-
-               printk(MYIOC_s_INFO_FMT
-                      "removing %s device, channel %d, id %d, phy %d\n",
-                      ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
-               dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
-                   "delete port (%d)\n", ioc->name, port->port_identifier);
-               sas_port_delete(port);
-               mptsas_port_delete(ioc, phy_info->port_details);
+               vtarget->id = hot_plug_info->phys_disk_num;
+               vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
+               phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num;
+               mptsas_reprobe_target(starget, 1);
                break;
-       case MPTSAS_ADD_DEVICE:
 
-               if (ev->phys_disk_num_valid)
-                       mpt_findImVolumes(ioc);
+       case MPTSAS_DEL_PHYSDISK_REPROBE:
 
-               /*
-                * Refresh sas device pg0 data
-                */
                if (mptsas_sas_device_pg0(ioc, &sas_device,
                    (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
                     MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
-                       (ev->channel << 8) + ev->id)) {
+                       (hot_plug_info->channel << 8) + hot_plug_info->id)) {
                                dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                                       "%s: exit at line=%d\n", ioc->name,
-                                       __func__, __LINE__));
+                                   "%s: fw_id=%d exit at line=%d\n",
+                                   ioc->name, __func__,
+                                   hot_plug_info->id, __LINE__));
                        break;
                }
 
-               __mptsas_discovery_work(ioc);
-
                phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
                                sas_device.sas_address);
-
-               if (!phy_info || !phy_info->port_details) {
+               if (!phy_info) {
                        dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                               "%s: exit at line=%d\n", ioc->name,
-                               __func__, __LINE__));
+                           "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                        __func__, hot_plug_info->id, __LINE__));
                        break;
                }
 
                starget = mptsas_get_starget(phy_info);
-               if (starget && (!ev->hidden_raid_component)){
-
-                       vtarget = starget->hostdata;
-
-                       if (!vtarget) {
-                               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                                   "%s: exit at line=%d\n", ioc->name,
-                                   __func__, __LINE__));
-                               break;
-                       }
-                       /*
-                        * Handling  RAID components
-                        */
-                       if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
-                               printk(MYIOC_s_INFO_FMT
-                                   "RAID Exposing: channel=%d, id=%d, "
-                                   "physdsk %d \n", ioc->name, ev->channel,
-                                   ev->id, ev->phys_disk_num);
-                               vtarget->tflags &=
-                                   ~MPT_TARGET_FLAGS_RAID_COMPONENT;
-                               vtarget->id = ev->id;
-                               mptsas_reprobe_target(starget, 0);
-                               phy_info->attached.phys_disk_num = ~0;
-                       }
+               if (!starget) {
+                       dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                           "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                        __func__, hot_plug_info->id, __LINE__));
                        break;
                }
 
-               if (mptsas_get_rphy(phy_info)) {
+               vtarget = starget->hostdata;
+               if (!vtarget) {
                        dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                               "%s: exit at line=%d\n", ioc->name,
-                               __func__, __LINE__));
-                       if (ev->channel) printk("%d\n", __LINE__);
+                           "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                        __func__, hot_plug_info->id, __LINE__));
                        break;
                }
 
-               port = mptsas_get_port(phy_info);
-               if (!port) {
+               if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
                        dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                               "%s: exit at line=%d\n", ioc->name,
-                               __func__, __LINE__));
+                           "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                        __func__, hot_plug_info->id, __LINE__));
                        break;
                }
-               memcpy(&phy_info->attached, &sas_device,
-                   sizeof(struct mptsas_devinfo));
-
-               if (phy_info->attached.device_info &
-                   MPI_SAS_DEVICE_INFO_SSP_TARGET)
-                       ds = "ssp";
-               if (phy_info->attached.device_info &
-                   MPI_SAS_DEVICE_INFO_STP_TARGET)
-                       ds = "stp";
-               if (phy_info->attached.device_info &
-                   MPI_SAS_DEVICE_INFO_SATA_DEVICE)
-                       ds = "sata";
-
-               printk(MYIOC_s_INFO_FMT
-                      "attaching %s device, channel %d, id %d, phy %d\n",
-                      ioc->name, ds, ev->channel, ev->id, ev->phy_id);
 
-               mptsas_parse_device_info(&identify, &phy_info->attached);
-               rphy = sas_end_device_alloc(port);
-               if (!rphy) {
-                       dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                               "%s: exit at line=%d\n", ioc->name,
-                               __func__, __LINE__));
-                       break; /* non-fatal: an rphy can be added later */
-               }
+               mpt_findImVolumes(ioc);
 
-               rphy->identify = identify;
-               if (sas_rphy_add(rphy)) {
-                       dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                               "%s: exit at line=%d\n", ioc->name,
-                               __func__, __LINE__));
-                       sas_rphy_free(rphy);
-                       break;
-               }
-               mptsas_set_rphy(ioc, phy_info, rphy);
+               starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:"
+                   " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
+                   ioc->name, hot_plug_info->channel, hot_plug_info->id,
+                   hot_plug_info->phys_disk_num, (unsigned long long)
+                   sas_device.sas_address);
+
+               vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
+               vtarget->id = hot_plug_info->id;
+               phy_info->attached.phys_disk_num = ~0;
+               mptsas_reprobe_target(starget, 0);
+               mptsas_add_device_component_by_fw(ioc,
+                   hot_plug_info->channel, hot_plug_info->id);
                break;
+
        case MPTSAS_ADD_RAID:
-               sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
-                   ev->id, 0);
-               if (sdev) {
-                       scsi_device_put(sdev);
-                       break;
-               }
-               printk(MYIOC_s_INFO_FMT
-                      "attaching raid volume, channel %d, id %d\n",
-                      ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
-               scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0);
+
                mpt_findImVolumes(ioc);
+               printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
+                   "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
+                   hot_plug_info->id);
+               scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
+                   hot_plug_info->id, 0);
                break;
+
        case MPTSAS_DEL_RAID:
-               sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
-                   ev->id, 0);
-               if (!sdev)
-                       break;
-               printk(MYIOC_s_INFO_FMT
-                      "removing raid volume, channel %d, id %d\n",
-                      ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
-               vdevice = sdev->hostdata;
-               scsi_remove_device(sdev);
-               scsi_device_put(sdev);
+
                mpt_findImVolumes(ioc);
+               printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
+                   "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
+                   hot_plug_info->id);
+               scsi_remove_device(hot_plug_info->sdev);
+               scsi_device_put(hot_plug_info->sdev);
                break;
+
        case MPTSAS_ADD_INACTIVE_VOLUME:
+
+               mpt_findImVolumes(ioc);
                mptsas_adding_inactive_raid_components(ioc,
-                   ev->channel, ev->id);
+                   hot_plug_info->channel, hot_plug_info->id);
                break;
-       case MPTSAS_IGNORE_EVENT:
+
        default:
                break;
        }
 
-       mutex_unlock(&ioc->sas_discovery_mutex);
-       kfree(ev);
+       mptsas_free_fw_event(ioc, fw_event);
 }
 
 static void
-mptsas_send_sas_event(MPT_ADAPTER *ioc,
-               EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
+mptsas_send_sas_event(struct fw_event_work *fw_event)
 {
-       struct mptsas_hotplug_event *ev;
-       u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
-       __le64 sas_address;
+       MPT_ADAPTER *ioc;
+       struct mptsas_hotplug_event hot_plug_info;
+       EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
+       u32 device_info;
+       u64 sas_address;
+
+       ioc = fw_event->ioc;
+       sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
+           fw_event->event_data;
+       device_info = le32_to_cpu(sas_event_data->DeviceInfo);
 
        if ((device_info &
-            (MPI_SAS_DEVICE_INFO_SSP_TARGET |
-             MPI_SAS_DEVICE_INFO_STP_TARGET |
-             MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0)
+               (MPI_SAS_DEVICE_INFO_SSP_TARGET |
+               MPI_SAS_DEVICE_INFO_STP_TARGET |
+               MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) {
+               mptsas_free_fw_event(ioc, fw_event);
+               return;
+       }
+
+       if (sas_event_data->ReasonCode ==
+               MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) {
+               mptbase_sas_persist_operation(ioc,
+               MPI_SAS_OP_CLEAR_NOT_PRESENT);
+               mptsas_free_fw_event(ioc, fw_event);
                return;
+       }
 
        switch (sas_event_data->ReasonCode) {
        case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
-
-               mptsas_target_reset_queue(ioc, sas_event_data);
-               break;
-
        case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
-               ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
-               if (!ev) {
-                       printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
-                       break;
-               }
-
-               INIT_WORK(&ev->work, mptsas_hotplug_work);
-               ev->ioc = ioc;
-               ev->handle = le16_to_cpu(sas_event_data->DevHandle);
-               ev->parent_handle =
-                   le16_to_cpu(sas_event_data->ParentDevHandle);
-               ev->channel = sas_event_data->Bus;
-               ev->id = sas_event_data->TargetID;
-               ev->phy_id = sas_event_data->PhyNum;
+               memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
+               hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle);
+               hot_plug_info.channel = sas_event_data->Bus;
+               hot_plug_info.id = sas_event_data->TargetID;
+               hot_plug_info.phy_id = sas_event_data->PhyNum;
                memcpy(&sas_address, &sas_event_data->SASAddress,
-                   sizeof(__le64));
-               ev->sas_address = le64_to_cpu(sas_address);
-               ev->device_info = device_info;
-
+                   sizeof(u64));
+               hot_plug_info.sas_address = le64_to_cpu(sas_address);
+               hot_plug_info.device_info = device_info;
                if (sas_event_data->ReasonCode &
                    MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
-                       ev->event_type = MPTSAS_ADD_DEVICE;
+                       hot_plug_info.event_type = MPTSAS_ADD_DEVICE;
                else
-                       ev->event_type = MPTSAS_DEL_DEVICE;
-               schedule_work(&ev->work);
+                       hot_plug_info.event_type = MPTSAS_DEL_DEVICE;
+               mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
                break;
+
        case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
-       /*
-        * Persistent table is full.
-        */
-               INIT_WORK(&ioc->sas_persist_task,
-                   mptsas_persist_clear_table);
-               schedule_work(&ioc->sas_persist_task);
+               mptbase_sas_persist_operation(ioc,
+                   MPI_SAS_OP_CLEAR_NOT_PRESENT);
+               mptsas_free_fw_event(ioc, fw_event);
                break;
-       /*
-        * TODO, handle other events
-        */
+
        case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
-       case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
+       /* TODO */
        case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
-       case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
-       case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
-       case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
-       case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
+       /* TODO */
        default:
+               mptsas_free_fw_event(ioc, fw_event);
                break;
        }
 }
+
 static void
-mptsas_send_raid_event(MPT_ADAPTER *ioc,
-               EVENT_DATA_RAID *raid_event_data)
+mptsas_send_raid_event(struct fw_event_work *fw_event)
 {
-       struct mptsas_hotplug_event *ev;
-       int status = le32_to_cpu(raid_event_data->SettingsStatus);
-       int state = (status >> 8) & 0xff;
-
-       if (ioc->bus_type != SAS)
-               return;
-
-       ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
-       if (!ev) {
-               printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
-               return;
+       MPT_ADAPTER *ioc;
+       EVENT_DATA_RAID *raid_event_data;
+       struct mptsas_hotplug_event hot_plug_info;
+       int status;
+       int state;
+       struct scsi_device *sdev = NULL;
+       VirtDevice *vdevice = NULL;
+       RaidPhysDiskPage0_t phys_disk;
+
+       ioc = fw_event->ioc;
+       raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data;
+       status = le32_to_cpu(raid_event_data->SettingsStatus);
+       state = (status >> 8) & 0xff;
+
+       memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
+       hot_plug_info.id = raid_event_data->VolumeID;
+       hot_plug_info.channel = raid_event_data->VolumeBus;
+       hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum;
+
+       if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
+           raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
+           raid_event_data->ReasonCode ==
+           MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
+               sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
+                   hot_plug_info.id, 0);
+               hot_plug_info.sdev = sdev;
+               if (sdev)
+                       vdevice = sdev->hostdata;
        }
 
-       INIT_WORK(&ev->work, mptsas_hotplug_work);
-       ev->ioc = ioc;
-       ev->id = raid_event_data->VolumeID;
-       ev->channel = raid_event_data->VolumeBus;
-       ev->event_type = MPTSAS_IGNORE_EVENT;
+       devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
+           "ReasonCode=%02x\n", ioc->name, __func__,
+           raid_event_data->ReasonCode));
 
        switch (raid_event_data->ReasonCode) {
        case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
-               ev->phys_disk_num_valid = 1;
-               ev->phys_disk_num = raid_event_data->PhysDiskNum;
-               ev->event_type = MPTSAS_ADD_DEVICE;
+               hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
                break;
        case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
-               ev->phys_disk_num_valid = 1;
-               ev->phys_disk_num = raid_event_data->PhysDiskNum;
-               ev->hidden_raid_component = 1;
-               ev->event_type = MPTSAS_DEL_DEVICE;
+               hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
                break;
        case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
                switch (state) {
                case MPI_PD_STATE_ONLINE:
                case MPI_PD_STATE_NOT_COMPATIBLE:
-                       ev->phys_disk_num_valid = 1;
-                       ev->phys_disk_num = raid_event_data->PhysDiskNum;
-                       ev->hidden_raid_component = 1;
-                       ev->event_type = MPTSAS_ADD_DEVICE;
+                       mpt_raid_phys_disk_pg0(ioc,
+                           raid_event_data->PhysDiskNum, &phys_disk);
+                       hot_plug_info.id = phys_disk.PhysDiskID;
+                       hot_plug_info.channel = phys_disk.PhysDiskBus;
+                       hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
                        break;
+               case MPI_PD_STATE_FAILED:
                case MPI_PD_STATE_MISSING:
                case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
                case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
                case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
-                       ev->phys_disk_num_valid = 1;
-                       ev->phys_disk_num = raid_event_data->PhysDiskNum;
-                       ev->event_type = MPTSAS_DEL_DEVICE;
+                       hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
                        break;
                default:
                        break;
                }
                break;
        case MPI_EVENT_RAID_RC_VOLUME_DELETED:
-               ev->event_type = MPTSAS_DEL_RAID;
+               if (!sdev)
+                       break;
+               vdevice->vtarget->deleted = 1; /* block IO */
+               hot_plug_info.event_type = MPTSAS_DEL_RAID;
                break;
        case MPI_EVENT_RAID_RC_VOLUME_CREATED:
-               ev->event_type = MPTSAS_ADD_RAID;
+               if (sdev) {
+                       scsi_device_put(sdev);
+                       break;
+               }
+               hot_plug_info.event_type = MPTSAS_ADD_RAID;
                break;
        case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
+               if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
+                       if (!sdev)
+                               break;
+                       vdevice->vtarget->deleted = 1; /* block IO */
+                       hot_plug_info.event_type = MPTSAS_DEL_RAID;
+                       break;
+               }
                switch (state) {
                case MPI_RAIDVOL0_STATUS_STATE_FAILED:
                case MPI_RAIDVOL0_STATUS_STATE_MISSING:
-                       ev->event_type = MPTSAS_DEL_RAID;
+                       if (!sdev)
+                               break;
+                       vdevice->vtarget->deleted = 1; /* block IO */
+                       hot_plug_info.event_type = MPTSAS_DEL_RAID;
                        break;
                case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
                case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
-                       ev->event_type = MPTSAS_ADD_RAID;
+                       if (sdev) {
+                               scsi_device_put(sdev);
+                               break;
+                       }
+                       hot_plug_info.event_type = MPTSAS_ADD_RAID;
                        break;
                default:
                        break;
@@ -3001,32 +4335,188 @@ mptsas_send_raid_event(MPT_ADAPTER *ioc,
        default:
                break;
        }
-       schedule_work(&ev->work);
+
+       if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT)
+               mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
+       else
+               mptsas_free_fw_event(ioc, fw_event);
 }
 
-static void
-mptsas_send_discovery_event(MPT_ADAPTER *ioc,
-       EVENT_DATA_SAS_DISCOVERY *discovery_data)
+/**
+ *     mptsas_issue_tm - send mptsas internal tm request
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @type: Task Management type
+ *     @channel: channel number for task management
+ *     @id: Logical Target ID for reset (if appropriate)
+ *     @lun: Logical unit for reset (if appropriate)
+ *     @task_context: Context for the task to be aborted
+ *     @timeout: timeout for task management control
+ *
+ *     return 0 on success and -1 on failure:
+ *
+ */
+static int
+mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun,
+       int task_context, ulong timeout, u8 *issue_reset)
 {
-       struct mptsas_discovery_event *ev;
+       MPT_FRAME_HDR   *mf;
+       SCSITaskMgmt_t  *pScsiTm;
+       int              retval;
+       unsigned long    timeleft;
+
+       *issue_reset = 0;
+       mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
+       if (mf == NULL) {
+               retval = -1; /* return failure */
+               dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no "
+                   "msg frames!!\n", ioc->name));
+               goto out;
+       }
 
-       /*
-        * DiscoveryStatus
-        *
-        * This flag will be non-zero when firmware
-        * kicks off discovery, and return to zero
-        * once its completed.
-        */
-       if (discovery_data->DiscoveryStatus)
-               return;
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, "
+           "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, "
+           "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf,
+            type, timeout, channel, id, (unsigned long long)lun,
+            task_context));
+
+       pScsiTm = (SCSITaskMgmt_t *) mf;
+       memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
+       pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+       pScsiTm->TaskType = type;
+       pScsiTm->MsgFlags = 0;
+       pScsiTm->TargetID = id;
+       pScsiTm->Bus = channel;
+       pScsiTm->ChainOffset = 0;
+       pScsiTm->Reserved = 0;
+       pScsiTm->Reserved1 = 0;
+       pScsiTm->TaskMsgContext = task_context;
+       int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
+
+       INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+       CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
+       retval = 0;
+       mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
+
+       /* Now wait for the command to complete */
+       timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
+           timeout*HZ);
+       if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               retval = -1; /* return failure */
+               dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
+                   "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf));
+               mpt_free_msg_frame(ioc, mf);
+               if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
+                       goto out;
+               *issue_reset = 1;
+               goto out;
+       }
+
+       if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
+               retval = -1; /* return failure */
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "TaskMgmt request: failed with no reply\n", ioc->name));
+               goto out;
+       }
+
+ out:
+       CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+       return retval;
+}
 
-       ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
-       if (!ev)
+/**
+ *     mptsas_broadcast_primative_work - Handle broadcast primitives
+ *     @work: work queue payload containing info describing the event
+ *
+ *     this will be handled in workqueue context.
+ */
+static void
+mptsas_broadcast_primative_work(struct fw_event_work *fw_event)
+{
+       MPT_ADAPTER *ioc = fw_event->ioc;
+       MPT_FRAME_HDR   *mf;
+       VirtDevice      *vdevice;
+       int                     ii;
+       struct scsi_cmnd        *sc;
+       SCSITaskMgmtReply_t     *pScsiTmReply;
+       u8                      issue_reset;
+       int                     task_context;
+       u8                      channel, id;
+       int                      lun;
+       u32                      termination_count;
+       u32                      query_count;
+
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "%s - enter\n", ioc->name, __func__));
+
+       mutex_lock(&ioc->taskmgmt_cmds.mutex);
+       if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
+               mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+               mptsas_requeue_fw_event(ioc, fw_event, 1000);
                return;
-       INIT_WORK(&ev->work, mptsas_discovery_work);
-       ev->ioc = ioc;
-       schedule_work(&ev->work);
-};
+       }
+
+       issue_reset = 0;
+       termination_count = 0;
+       query_count = 0;
+       mpt_findImVolumes(ioc);
+       pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
+
+       for (ii = 0; ii < ioc->req_depth; ii++) {
+               if (ioc->fw_events_off)
+                       goto out;
+               sc = mptscsih_get_scsi_lookup(ioc, ii);
+               if (!sc)
+                       continue;
+               mf = MPT_INDEX_2_MFPTR(ioc, ii);
+               if (!mf)
+                       continue;
+               task_context = mf->u.frame.hwhdr.msgctxu.MsgContext;
+               vdevice = sc->device->hostdata;
+               if (!vdevice || !vdevice->vtarget)
+                       continue;
+               if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
+                       continue; /* skip hidden raid components */
+               if (vdevice->vtarget->raidVolume)
+                       continue; /* skip hidden raid components */
+               channel = vdevice->vtarget->channel;
+               id = vdevice->vtarget->id;
+               lun = vdevice->lun;
+               if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK,
+                   channel, id, (u64)lun, task_context, 30, &issue_reset))
+                       goto out;
+               query_count++;
+               termination_count +=
+                   le32_to_cpu(pScsiTmReply->TerminationCount);
+               if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) &&
+                   (pScsiTmReply->ResponseCode ==
+                   MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
+                   pScsiTmReply->ResponseCode ==
+                   MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
+                       continue;
+               if (mptsas_issue_tm(ioc,
+                   MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET,
+                   channel, id, (u64)lun, 0, 30, &issue_reset))
+                       goto out;
+               termination_count +=
+                   le32_to_cpu(pScsiTmReply->TerminationCount);
+       }
+
+ out:
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "%s - exit, query_count = %d termination_count = %d\n",
+           ioc->name, __func__, query_count, termination_count));
+
+       ioc->broadcast_aen_busy = 0;
+       mpt_clear_taskmgmt_in_progress_flag(ioc);
+       mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+
+       if (issue_reset) {
+               printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
+                   ioc->name, __func__);
+               mpt_HardResetHandler(ioc, CAN_SLEEP);
+       }
+       mptsas_free_fw_event(ioc, fw_event);
+}
 
 /*
  * mptsas_send_ir2_event - handle exposing hidden disk when
@@ -3037,76 +4527,159 @@ mptsas_send_discovery_event(MPT_ADAPTER *ioc,
  *
  */
 static void
-mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data)
+mptsas_send_ir2_event(struct fw_event_work *fw_event)
 {
-       struct mptsas_hotplug_event *ev;
-
-       if (ir2_data->ReasonCode !=
-           MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED)
-               return;
-
-       ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
-       if (!ev)
+       MPT_ADAPTER     *ioc;
+       struct mptsas_hotplug_event hot_plug_info;
+       MPI_EVENT_DATA_IR2      *ir2_data;
+       u8 reasonCode;
+       RaidPhysDiskPage0_t phys_disk;
+
+       ioc = fw_event->ioc;
+       ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
+       reasonCode = ir2_data->ReasonCode;
+
+       devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
+           "ReasonCode=%02x\n", ioc->name, __func__, reasonCode));
+
+       memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
+       hot_plug_info.id = ir2_data->TargetID;
+       hot_plug_info.channel = ir2_data->Bus;
+       switch (reasonCode) {
+       case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
+               hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
+               break;
+       case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
+               hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
+               hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
+               break;
+       case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
+               hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
+               mpt_raid_phys_disk_pg0(ioc,
+                   ir2_data->PhysDiskNum, &phys_disk);
+               hot_plug_info.id = phys_disk.PhysDiskID;
+               hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
+               break;
+       default:
+               mptsas_free_fw_event(ioc, fw_event);
                return;
-
-       INIT_WORK(&ev->work, mptsas_hotplug_work);
-       ev->ioc = ioc;
-       ev->id = ir2_data->TargetID;
-       ev->channel = ir2_data->Bus;
-       ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME;
-
-       schedule_work(&ev->work);
-};
+       }
+       mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
+}
 
 static int
 mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
 {
-       int rc=1;
-       u8 event = le32_to_cpu(reply->Event) & 0xFF;
-
-       if (!ioc->sh)
-               goto out;
+       u32 event = le32_to_cpu(reply->Event);
+       int sz, event_data_sz;
+       struct fw_event_work *fw_event;
+       unsigned long delay;
 
-       /*
-        * sas_discovery_ignore_events
-        *
-        * This flag is to prevent anymore processing of
-        * sas events once mptsas_remove function is called.
-        */
-       if (ioc->sas_discovery_ignore_events) {
-               rc = mptscsih_event_process(ioc, reply);
-               goto out;
-       }
+       /* events turned off due to host reset or driver unloading */
+       if (ioc->fw_events_off)
+               return 0;
 
+       delay = msecs_to_jiffies(1);
        switch (event) {
+       case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
+       {
+               EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data =
+                   (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data;
+               if (broadcast_event_data->Primitive !=
+                   MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
+                       return 0;
+               if (ioc->broadcast_aen_busy)
+                       return 0;
+               ioc->broadcast_aen_busy = 1;
+               break;
+       }
        case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
-               mptsas_send_sas_event(ioc,
-                       (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
+       {
+               EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
+                   (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
+
+               if (sas_event_data->ReasonCode ==
+                   MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
+                       mptsas_target_reset_queue(ioc, sas_event_data);
+                       return 0;
+               }
                break;
-       case MPI_EVENT_INTEGRATED_RAID:
-               mptsas_send_raid_event(ioc,
-                       (EVENT_DATA_RAID *)reply->Data);
+       }
+       case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
+       {
+               MpiEventDataSasExpanderStatusChange_t *expander_data =
+                   (MpiEventDataSasExpanderStatusChange_t *)reply->Data;
+
+               if (ioc->old_sas_discovery_protocal)
+                       return 0;
+
+               if (expander_data->ReasonCode ==
+                   MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING &&
+                   ioc->device_missing_delay)
+                       delay = HZ * ioc->device_missing_delay;
                break;
+       }
+       case MPI_EVENT_SAS_DISCOVERY:
+       {
+               u32 discovery_status;
+               EventDataSasDiscovery_t *discovery_data =
+                   (EventDataSasDiscovery_t *)reply->Data;
+
+               discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
+               ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
+               if (ioc->old_sas_discovery_protocal && !discovery_status)
+                       mptsas_queue_rescan(ioc);
+               return 0;
+       }
+       case MPI_EVENT_INTEGRATED_RAID:
        case MPI_EVENT_PERSISTENT_TABLE_FULL:
-               INIT_WORK(&ioc->sas_persist_task,
-                   mptsas_persist_clear_table);
-               schedule_work(&ioc->sas_persist_task);
-               break;
-        case MPI_EVENT_SAS_DISCOVERY:
-               mptsas_send_discovery_event(ioc,
-                       (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
-               break;
        case MPI_EVENT_IR2:
-               mptsas_send_ir2_event(ioc,
-                   (PTR_MPI_EVENT_DATA_IR2)reply->Data);
+       case MPI_EVENT_SAS_PHY_LINK_STATUS:
+       case MPI_EVENT_QUEUE_FULL:
                break;
        default:
-               rc = mptscsih_event_process(ioc, reply);
-               break;
+               return 0;
        }
- out:
 
-       return rc;
+       event_data_sz = ((reply->MsgLength * 4) -
+           offsetof(EventNotificationReply_t, Data));
+       sz = offsetof(struct fw_event_work, event_data) + event_data_sz;
+       fw_event = kzalloc(sz, GFP_ATOMIC);
+       if (!fw_event) {
+               printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name,
+                __func__, __LINE__);
+               return 0;
+       }
+       memcpy(fw_event->event_data, reply->Data, event_data_sz);
+       fw_event->event = event;
+       fw_event->ioc = ioc;
+       mptsas_add_fw_event(ioc, fw_event, delay);
+       return 0;
+}
+
+/* Delete a volume when no longer listed in ioc pg2
+ */
+static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id)
+{
+       struct scsi_device *sdev;
+       int i;
+
+       sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0);
+       if (!sdev)
+               return;
+       if (!ioc->raid_data.pIocPg2)
+               goto out;
+       if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
+               goto out;
+       for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
+               if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id)
+                       goto release_sdev;
+ out:
+       printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
+           "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id);
+       scsi_remove_device(sdev);
+ release_sdev:
+       scsi_device_put(sdev);
 }
 
 static int
@@ -3128,6 +4701,7 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                return r;
 
        ioc = pci_get_drvdata(pdev);
+       mptsas_fw_event_off(ioc);
        ioc->DoneCtx = mptsasDoneCtx;
        ioc->TaskCtx = mptsasTaskCtx;
        ioc->InternalCtx = mptsasInternalCtx;
@@ -3211,17 +4785,15 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
         * A slightly different algorithm is required for
         * 64bit SGEs.
         */
-       scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
-       if (sizeof(dma_addr_t) == sizeof(u64)) {
+       scale = ioc->req_sz/ioc->SGE_size;
+       if (ioc->sg_addr_size == sizeof(u64)) {
                numSGE = (scale - 1) *
                  (ioc->facts.MaxChainDepth-1) + scale +
-                 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
-                 sizeof(u32));
+                 (ioc->req_sz - 60) / ioc->SGE_size;
        } else {
                numSGE = 1 + (scale - 1) *
                  (ioc->facts.MaxChainDepth-1) + scale +
-                 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
-                 sizeof(u32));
+                 (ioc->req_sz - 64) / ioc->SGE_size;
        }
 
        if (numSGE < sh->sg_tablesize) {
@@ -3251,9 +4823,6 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        /* Clear the TM flags
         */
-       hd->tmPending = 0;
-       hd->tmState = TM_STATE_NONE;
-       hd->resetPending = 0;
        hd->abortSCpnt = NULL;
 
        /* Clear the pointer used to store
@@ -3273,10 +4842,11 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        ioc->sas_data.ptClear = mpt_pt_clear;
 
-       init_waitqueue_head(&hd->scandv_waitq);
-       hd->scandv_wait_done = 0;
        hd->last_queue_full = 0;
        INIT_LIST_HEAD(&hd->target_reset_list);
+       INIT_LIST_HEAD(&ioc->sas_device_info_list);
+       mutex_init(&ioc->sas_device_info_mutex);
+
        spin_unlock_irqrestore(&ioc->FreeQlock, flags);
 
        if (ioc->sas_data.ptClear==1) {
@@ -3291,8 +4861,11 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                goto out_mptsas_probe;
        }
 
+       /* older firmware doesn't support expander events */
+       if ((ioc->facts.HeaderVersion >> 8) < 0xE)
+               ioc->old_sas_discovery_protocal = 1;
        mptsas_scan_sas_topology(ioc);
-
+       mptsas_fw_event_on(ioc);
        return 0;
 
  out_mptsas_probe:
@@ -3301,12 +4874,25 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        return error;
 }
 
+void
+mptsas_shutdown(struct pci_dev *pdev)
+{
+       MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
+
+       mptsas_fw_event_off(ioc);
+       mptsas_cleanup_fw_event_q(ioc);
+}
+
 static void __devexit mptsas_remove(struct pci_dev *pdev)
 {
        MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
        struct mptsas_portinfo *p, *n;
        int i;
 
+       mptsas_shutdown(pdev);
+
+       mptsas_del_device_components(ioc);
+
        ioc->sas_discovery_ignore_events = 1;
        sas_remove_host(ioc->sh);
 
@@ -3315,11 +4901,12 @@ static void __devexit mptsas_remove(struct pci_dev *pdev)
                list_del(&p->list);
                for (i = 0 ; i < p->num_phys ; i++)
                        mptsas_port_delete(ioc, p->phy_info[i].port_details);
+
                kfree(p->phy_info);
                kfree(p);
        }
        mutex_unlock(&ioc->sas_topology_mutex);
-
+       ioc->hba_port_info = NULL;
        mptscsih_remove(pdev);
 }
 
@@ -3344,7 +4931,7 @@ static struct pci_driver mptsas_driver = {
        .id_table       = mptsas_pci_table,
        .probe          = mptsas_probe,
        .remove         = __devexit_p(mptsas_remove),
-       .shutdown       = mptscsih_shutdown,
+       .shutdown       = mptsas_shutdown,
 #ifdef CONFIG_PM
        .suspend        = mptscsih_suspend,
        .resume         = mptscsih_resume,
@@ -3364,10 +4951,12 @@ mptsas_init(void)
                return -ENODEV;
 
        mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
-       mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
+       mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
        mptsasInternalCtx =
                mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
        mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
+       mptsasDeviceResetCtx =
+               mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
 
        mpt_event_register(mptsasDoneCtx, mptsas_event_process);
        mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
@@ -3392,6 +4981,7 @@ mptsas_exit(void)
        mpt_deregister(mptsasInternalCtx);
        mpt_deregister(mptsasTaskCtx);
        mpt_deregister(mptsasDoneCtx);
+       mpt_deregister(mptsasDeviceResetCtx);
 }
 
 module_init(mptsas_init);
index 2b544e0877e6f0f3dd1ccc686edcfe2cd3e9a744..953c2bfcf6aaa470f05a0e3be18c966c05f3dc6b 100644 (file)
@@ -53,6 +53,7 @@ struct mptsas_target_reset_event {
        struct list_head        list;
        EVENT_DATA_SAS_DEVICE_STATUS_CHANGE sas_event_data;
        u8      target_reset_issued;
+       unsigned long    time_count;
 };
 
 enum mptsas_hotplug_action {
@@ -60,12 +61,37 @@ enum mptsas_hotplug_action {
        MPTSAS_DEL_DEVICE,
        MPTSAS_ADD_RAID,
        MPTSAS_DEL_RAID,
+       MPTSAS_ADD_PHYSDISK,
+       MPTSAS_ADD_PHYSDISK_REPROBE,
+       MPTSAS_DEL_PHYSDISK,
+       MPTSAS_DEL_PHYSDISK_REPROBE,
        MPTSAS_ADD_INACTIVE_VOLUME,
        MPTSAS_IGNORE_EVENT,
 };
 
+struct mptsas_mapping{
+       u8                      id;
+       u8                      channel;
+};
+
+struct mptsas_device_info {
+       struct list_head        list;
+       struct mptsas_mapping   os;     /* operating system mapping*/
+       struct mptsas_mapping   fw;     /* firmware mapping */
+       u64                     sas_address;
+       u32                     device_info; /* specific bits for devices */
+       u16                     slot;           /* enclosure slot id */
+       u64                     enclosure_logical_id; /*enclosure address */
+       u8                      is_logical_volume; /* is this logical volume */
+       /* this belongs to volume */
+       u8                      is_hidden_raid_component;
+       /* this valid when is_hidden_raid_component set */
+       u8                      volume_id;
+       /* cached data for a removed device */
+       u8                      is_cached;
+};
+
 struct mptsas_hotplug_event {
-       struct work_struct      work;
        MPT_ADAPTER             *ioc;
        enum mptsas_hotplug_action event_type;
        u64                     sas_address;
@@ -73,11 +99,18 @@ struct mptsas_hotplug_event {
        u8                      id;
        u32                     device_info;
        u16                     handle;
-       u16                     parent_handle;
        u8                      phy_id;
-       u8                      phys_disk_num_valid;    /* hrc (hidden raid component) */
        u8                      phys_disk_num;          /* hrc - unique index*/
-       u8                      hidden_raid_component;  /* hrc - don't expose*/
+       struct scsi_device      *sdev;
+};
+
+struct fw_event_work {
+       struct list_head        list;
+       struct delayed_work      work;
+       MPT_ADAPTER     *ioc;
+       u32                     event;
+       u8                      retries;
+       u8                      event_data[1];
 };
 
 struct mptsas_discovery_event {
index e62c6bc4ad33ec83407a002a1549a5edd49cdc90..8440f78f69696e63be7e4e72fd84c4ccfd91d526 100644 (file)
@@ -80,7 +80,7 @@ MODULE_VERSION(my_VERSION);
 /*
  *  Other private/forward protos...
  */
-static struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
+struct scsi_cmnd       *mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
 static struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i);
 static void    mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd);
 static int     SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *scmd);
@@ -92,18 +92,24 @@ static int  mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
                                 SCSIIORequest_t *pReq, int req_idx);
 static void    mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
 static void    mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
-static int     mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
-static int     mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
 
-static int     mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout);
+int    mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id,
+               int lun, int ctx2abort, ulong timeout);
 
 int            mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
 int            mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
 
+void
+mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code);
+static int     mptscsih_get_completion_code(MPT_ADAPTER *ioc,
+               MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
 int            mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
 static int     mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
 static void    mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
 
+static int
+mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,
+                               SCSITaskMgmtReply_t *pScsiTmReply);
 void           mptscsih_remove(struct pci_dev *);
 void           mptscsih_shutdown(struct pci_dev *);
 #ifdef CONFIG_PM
@@ -113,69 +119,6 @@ int                mptscsih_resume(struct pci_dev *pdev);
 
 #define SNS_LEN(scp)   SCSI_SENSE_BUFFERSIZE
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *     mptscsih_add_sge - Place a simple SGE at address pAddr.
- *     @pAddr: virtual address for SGE
- *     @flagslength: SGE flags and data transfer length
- *     @dma_addr: Physical address
- *
- *     This routine places a MPT request frame back on the MPT adapter's
- *     FreeQ.
- */
-static inline void
-mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
-{
-       if (sizeof(dma_addr_t) == sizeof(u64)) {
-               SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
-               u32 tmp = dma_addr & 0xFFFFFFFF;
-
-               pSge->FlagsLength = cpu_to_le32(flagslength);
-               pSge->Address.Low = cpu_to_le32(tmp);
-               tmp = (u32) ((u64)dma_addr >> 32);
-               pSge->Address.High = cpu_to_le32(tmp);
-
-       } else {
-               SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
-               pSge->FlagsLength = cpu_to_le32(flagslength);
-               pSge->Address = cpu_to_le32(dma_addr);
-       }
-} /* mptscsih_add_sge() */
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *     mptscsih_add_chain - Place a chain SGE at address pAddr.
- *     @pAddr: virtual address for SGE
- *     @next: nextChainOffset value (u32's)
- *     @length: length of next SGL segment
- *     @dma_addr: Physical address
- *
- *     This routine places a MPT request frame back on the MPT adapter's
- *     FreeQ.
- */
-static inline void
-mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
-{
-       if (sizeof(dma_addr_t) == sizeof(u64)) {
-               SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
-               u32 tmp = dma_addr & 0xFFFFFFFF;
-
-               pChain->Length = cpu_to_le16(length);
-               pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
-
-               pChain->NextChainOffset = next;
-
-               pChain->Address.Low = cpu_to_le32(tmp);
-               tmp = (u32) ((u64)dma_addr >> 32);
-               pChain->Address.High = cpu_to_le32(tmp);
-       } else {
-               SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
-               pChain->Length = cpu_to_le16(length);
-               pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
-               pChain->NextChainOffset = next;
-               pChain->Address = cpu_to_le32(dma_addr);
-       }
-} /* mptscsih_add_chain() */
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -281,10 +224,10 @@ mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
         */
 
 nextSGEset:
-       numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
+       numSgeSlots = ((frm_sz - sgeOffset) / ioc->SGE_size);
        numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
 
-       sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
+       sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | sgdir;
 
        /* Get first (num - 1) SG elements
         * Skip any SG entries with a length of 0
@@ -293,17 +236,19 @@ nextSGEset:
        for (ii=0; ii < (numSgeThisFrame-1); ii++) {
                thisxfer = sg_dma_len(sg);
                if (thisxfer == 0) {
-                       sg = sg_next(sg); /* Get next SG element from the OS */
+                       /* Get next SG element from the OS */
+                       sg = sg_next(sg);
                        sg_done++;
                        continue;
                }
 
                v2 = sg_dma_address(sg);
-               mptscsih_add_sge(psge, sgflags | thisxfer, v2);
+               ioc->add_sge(psge, sgflags | thisxfer, v2);
 
-               sg = sg_next(sg);       /* Get next SG element from the OS */
-               psge += (sizeof(u32) + sizeof(dma_addr_t));
-               sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
+               /* Get next SG element from the OS */
+               sg = sg_next(sg);
+               psge += ioc->SGE_size;
+               sgeOffset += ioc->SGE_size;
                sg_done++;
        }
 
@@ -320,12 +265,8 @@ nextSGEset:
                thisxfer = sg_dma_len(sg);
 
                v2 = sg_dma_address(sg);
-               mptscsih_add_sge(psge, sgflags | thisxfer, v2);
-               /*
-               sg = sg_next(sg);
-               psge += (sizeof(u32) + sizeof(dma_addr_t));
-               */
-               sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
+               ioc->add_sge(psge, sgflags | thisxfer, v2);
+               sgeOffset += ioc->SGE_size;
                sg_done++;
 
                if (chainSge) {
@@ -334,7 +275,8 @@ nextSGEset:
                         * Update the chain element
                         * Offset and Length fields.
                         */
-                       mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
+                       ioc->add_chain((char *)chainSge, 0, sgeOffset,
+                               ioc->ChainBufferDMA + chain_dma_off);
                } else {
                        /* The current buffer is the original MF
                         * and there is no Chain buffer.
@@ -367,7 +309,7 @@ nextSGEset:
                 * set properly).
                 */
                if (sg_done) {
-                       u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
+                       u32 *ptmp = (u32 *) (psge - ioc->SGE_size);
                        sgflags = le32_to_cpu(*ptmp);
                        sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
                        *ptmp = cpu_to_le32(sgflags);
@@ -381,8 +323,9 @@ nextSGEset:
                         * Old chain element is now complete.
                         */
                        u8 nextChain = (u8) (sgeOffset >> 2);
-                       sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
-                       mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
+                       sgeOffset += ioc->SGE_size;
+                       ioc->add_chain((char *)chainSge, nextChain, sgeOffset,
+                                        ioc->ChainBufferDMA + chain_dma_off);
                } else {
                        /* The original MF buffer requires a chain buffer -
                         * set the offset.
@@ -592,14 +535,15 @@ mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pSc
        }
 
        scsi_print_command(sc);
-       printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d\n",
-           ioc->name, pScsiReply->Bus, pScsiReply->TargetID);
+       printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d, lun = %d\n",
+           ioc->name, pScsiReply->Bus, pScsiReply->TargetID, sc->device->lun);
        printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, "
            "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow,
            scsi_get_resid(sc));
        printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, "
            "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag),
            le32_to_cpu(pScsiReply->TransferCount), sc->result);
+
        printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), "
            "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n",
            ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus,
@@ -654,16 +598,14 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
        req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
        req_idx_MR = (mr != NULL) ?
            le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
+
+       /* Special case, where already freed message frame is received from
+        * Firmware. It happens with Resetting IOC.
+        * Return immediately. Do not care
+        */
        if ((req_idx != req_idx_MR) ||
-           (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
-               printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
-                   ioc->name);
-               printk (MYIOC_s_ERR_FMT
-                   "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
-                   ioc->name, req_idx, req_idx_MR, mf, mr,
-                   mptscsih_get_scsi_lookup(ioc, req_idx_MR));
+           (le32_to_cpu(mf->u.frame.linkage.arg1) == 0xdeadbeaf))
                return 0;
-       }
 
        sc = mptscsih_getclear_scsi_lookup(ioc, req_idx);
        if (sc == NULL) {
@@ -810,12 +752,16 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                         */
 
                case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:        /* 0x0048 */
-               case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:         /* 0x004C */
                        /* Linux handles an unsolicited DID_RESET better
                         * than an unsolicited DID_ABORT.
                         */
                        sc->result = DID_RESET << 16;
 
+               case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:         /* 0x004C */
+                       if (ioc->bus_type == FC)
+                               sc->result = DID_ERROR << 16;
+                       else
+                               sc->result = DID_RESET << 16;
                        break;
 
                case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:      /* 0x0049 */
@@ -992,9 +938,9 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
                scsi_dma_unmap(sc);
                sc->result = DID_RESET << 16;
                sc->host_scribble = NULL;
-               sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
-                   "completing cmds: fw_channel %d, fw_id %d, sc=%p,"
-                   " mf = %p, idx=%x\n", ioc->name, channel, id, sc, mf, ii);
+               dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
+                   "completing cmds: fw_channel %d, fw_id %d, sc=%p, mf = %p, "
+                   "idx=%x\n", ioc->name, channel, id, sc, mf, ii));
                sc->scsi_done(sc);
        }
 }
@@ -1053,9 +999,11 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
                        scsi_dma_unmap(sc);
                        sc->host_scribble = NULL;
                        sc->result = DID_NO_CONNECT << 16;
-                       sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT "completing cmds: fw_channel %d,"
-                          "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name, vdevice->vtarget->channel,
-                          vdevice->vtarget->id, sc, mf, ii);
+                       dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device,
+                          MYIOC_s_FMT "completing cmds: fw_channel %d, "
+                          "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name,
+                          vdevice->vtarget->channel, vdevice->vtarget->id,
+                          sc, mf, ii));
                        sc->scsi_done(sc);
                        spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
                }
@@ -1346,7 +1294,6 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
        MPT_FRAME_HDR           *mf;
        SCSIIORequest_t         *pScsiReq;
        VirtDevice              *vdevice = SCpnt->device->hostdata;
-       int      lun;
        u32      datalen;
        u32      scsictl;
        u32      scsidir;
@@ -1357,13 +1304,12 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
 
        hd = shost_priv(SCpnt->device->host);
        ioc = hd->ioc;
-       lun = SCpnt->device->lun;
        SCpnt->scsi_done = done;
 
        dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n",
                ioc->name, SCpnt, done));
 
-       if (hd->resetPending) {
+       if (ioc->taskmgmt_quiesce_io) {
                dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
                        ioc->name, SCpnt));
                return SCSI_MLQUEUE_HOST_BUSY;
@@ -1422,7 +1368,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
        pScsiReq->CDBLength = SCpnt->cmd_len;
        pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
        pScsiReq->Reserved = 0;
-       pScsiReq->MsgFlags = mpt_msg_flags();
+       pScsiReq->MsgFlags = mpt_msg_flags(ioc);
        int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
        pScsiReq->Control = cpu_to_le32(scsictl);
 
@@ -1448,7 +1394,8 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
         */
        if (datalen == 0) {
                /* Add a NULL SGE */
-               mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
+               ioc->add_sge((char *)&pScsiReq->SGL,
+                       MPT_SGE_FLAGS_SSIMPLE_READ | 0,
                        (dma_addr_t) -1);
        } else {
                /* Add a 32 or 64 bit SGE */
@@ -1528,8 +1475,8 @@ mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *     mptscsih_TMHandler - Generic handler for SCSI Task Management.
- *     @hd: Pointer to MPT SCSI HOST structure
+ *     mptscsih_IssueTaskMgmt - Generic send Task Management function.
+ *     @hd: Pointer to MPT_SCSI_HOST structure
  *     @type: Task Management type
  *     @channel: channel number for task management
  *     @id: Logical Target ID for reset (if appropriate)
@@ -1537,145 +1484,68 @@ mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
  *     @ctx2abort: Context for the task to be aborted (if appropriate)
  *     @timeout: timeout for task management control
  *
- *     Fall through to mpt_HardResetHandler if: not operational, too many
- *     failed TM requests or handshake failure.
+ *     Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
+ *     or a non-interrupt thread.  In the former, must not call schedule().
  *
- *     Remark: Currently invoked from a non-interrupt thread (_bh).
+ *     Not all fields are meaningfull for all task types.
  *
- *     Note: With old EH code, at most 1 SCSI TaskMgmt function per IOC
- *     will be active.
+ *     Returns 0 for SUCCESS, or FAILED.
  *
- *     Returns 0 for SUCCESS, or %FAILED.
  **/
 int
-mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
+mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun,
+       int ctx2abort, ulong timeout)
 {
-       MPT_ADAPTER     *ioc;
-       int              rc = -1;
+       MPT_FRAME_HDR   *mf;
+       SCSITaskMgmt_t  *pScsiTm;
+       int              ii;
+       int              retval;
+       MPT_ADAPTER     *ioc = hd->ioc;
+       unsigned long    timeleft;
+       u8               issue_hard_reset;
        u32              ioc_raw_state;
-       unsigned long    flags;
-
-       ioc = hd->ioc;
-       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler Entered!\n", ioc->name));
-
-       // SJR - CHECKME - Can we avoid this here?
-       // (mpt_HardResetHandler has this check...)
-       spin_lock_irqsave(&ioc->diagLock, flags);
-       if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
-               spin_unlock_irqrestore(&ioc->diagLock, flags);
-               return FAILED;
-       }
-       spin_unlock_irqrestore(&ioc->diagLock, flags);
-
-       /*  Wait a fixed amount of time for the TM pending flag to be cleared.
-        *  If we time out and not bus reset, then we return a FAILED status
-        *  to the caller.
-        *  The call to mptscsih_tm_pending_wait() will set the pending flag
-        *  if we are
-        *  successful. Otherwise, reload the FW.
-        */
-       if (mptscsih_tm_pending_wait(hd) == FAILED) {
-               if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
-                       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler abort: "
-                          "Timed out waiting for last TM (%d) to complete! \n",
-                          ioc->name, hd->tmPending));
-                       return FAILED;
-               } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
-                       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler target "
-                               "reset: Timed out waiting for last TM (%d) "
-                               "to complete! \n", ioc->name,
-                               hd->tmPending));
-                       return FAILED;
-               } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
-                       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler bus reset: "
-                          "Timed out waiting for last TM (%d) to complete! \n",
-                         ioc->name, hd->tmPending));
-                       return FAILED;
-               }
-       } else {
-               spin_lock_irqsave(&ioc->FreeQlock, flags);
-               hd->tmPending |=  (1 << type);
-               spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-       }
+       unsigned long    time_count;
 
+       issue_hard_reset = 0;
        ioc_raw_state = mpt_GetIocState(ioc, 0);
 
        if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
                printk(MYIOC_s_WARN_FMT
-                       "TM Handler for type=%x: IOC Not operational (0x%x)!\n",
+                       "TaskMgmt type=%x: IOC Not operational (0x%x)!\n",
                        ioc->name, type, ioc_raw_state);
-               printk(MYIOC_s_WARN_FMT " Issuing HardReset!!\n", ioc->name);
+               printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
+                   ioc->name, __func__);
                if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
-                       printk(MYIOC_s_WARN_FMT "TMHandler: HardReset "
+                       printk(MYIOC_s_WARN_FMT "TaskMgmt HardReset "
                            "FAILED!!\n", ioc->name);
-               return FAILED;
+               return 0;
        }
 
        if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
                printk(MYIOC_s_WARN_FMT
-                       "TM Handler for type=%x: ioc_state: "
+                       "TaskMgmt type=%x: ioc_state: "
                        "DOORBELL_ACTIVE (0x%x)!\n",
                        ioc->name, type, ioc_raw_state);
                return FAILED;
        }
 
-       /* Isse the Task Mgmt request.
-        */
-       if (hd->hard_resets < -1)
-               hd->hard_resets++;
-
-       rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun,
-           ctx2abort, timeout);
-       if (rc)
-               printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n",
-                      ioc->name);
-       else
-               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issue of TaskMgmt Successful!\n",
-                          ioc->name));
-
-       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                       "TMHandler rc = %d!\n", ioc->name, rc));
-
-       return rc;
-}
-
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *     mptscsih_IssueTaskMgmt - Generic send Task Management function.
- *     @hd: Pointer to MPT_SCSI_HOST structure
- *     @type: Task Management type
- *     @channel: channel number for task management
- *     @id: Logical Target ID for reset (if appropriate)
- *     @lun: Logical Unit for reset (if appropriate)
- *     @ctx2abort: Context for the task to be aborted (if appropriate)
- *     @timeout: timeout for task management control
- *
- *     Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
- *     or a non-interrupt thread.  In the former, must not call schedule().
- *
- *     Not all fields are meaningfull for all task types.
- *
- *     Returns 0 for SUCCESS, or FAILED.
- *
- **/
-static int
-mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
-{
-       MPT_FRAME_HDR   *mf;
-       SCSITaskMgmt_t  *pScsiTm;
-       int              ii;
-       int              retval;
-       MPT_ADAPTER     *ioc = hd->ioc;
+       mutex_lock(&ioc->taskmgmt_cmds.mutex);
+       if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
+               mf = NULL;
+               retval = FAILED;
+               goto out;
+       }
 
        /* Return Fail to calling function if no message frames available.
         */
        if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
-               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
-                               ioc->name));
-               return FAILED;
+               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                       "TaskMgmt no msg frames!!\n", ioc->name));
+               retval = FAILED;
+               mpt_clear_taskmgmt_in_progress_flag(ioc);
+               goto out;
        }
-       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
                        ioc->name, mf));
 
        /* Format the Request
@@ -1699,11 +1569,14 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, i
 
        pScsiTm->TaskMsgContext = ctx2abort;
 
-       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
-               "type=%d\n", ioc->name, ctx2abort, type));
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt: ctx2abort (0x%08x) "
+               "task_type = 0x%02X, timeout = %ld\n", ioc->name, ctx2abort,
+               type, timeout));
 
        DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
 
+       INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+       time_count = jiffies;
        if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
            (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
                mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
@@ -1711,47 +1584,50 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, i
                retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
                        sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
                if (retval) {
-                       dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "send_handshake FAILED!"
-                       " (hd %p, ioc %p, mf %p, rc=%d) \n", ioc->name, hd,
-                       ioc, mf, retval));
-                       goto fail_out;
+                       dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                               "TaskMgmt handshake FAILED!(mf=%p, rc=%d) \n",
+                               ioc->name, mf, retval));
+                       mpt_free_msg_frame(ioc, mf);
+                       mpt_clear_taskmgmt_in_progress_flag(ioc);
+                       goto out;
                }
        }
 
-       if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
-               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "task management request TIMED OUT!"
-                       " (hd %p, ioc %p, mf %p) \n", ioc->name, hd,
-                       ioc, mf));
-               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
-                        ioc->name));
-               retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
-               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rc=%d \n",
-                        ioc->name, retval));
-               goto fail_out;
+       timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
+               timeout*HZ);
+       if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               retval = FAILED;
+               dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
+                   "TaskMgmt TIMED OUT!(mf=%p)\n", ioc->name, mf));
+               mpt_clear_taskmgmt_in_progress_flag(ioc);
+               if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
+                       goto out;
+               issue_hard_reset = 1;
+               goto out;
        }
 
-       /*
-        * Handle success case, see if theres a non-zero ioc_status.
-        */
-       if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS ||
-          hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
-          hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
-               retval = 0;
-       else
-               retval = FAILED;
+       retval = mptscsih_taskmgmt_reply(ioc, type,
+           (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply);
 
-       return retval;
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "TaskMgmt completed (%d seconds)\n",
+           ioc->name, jiffies_to_msecs(jiffies - time_count)/1000));
 
fail_out:
+ out:
 
-       /*
-        * Free task management mf, and corresponding tm flags
-        */
-       mpt_free_msg_frame(ioc, mf);
-       hd->tmPending = 0;
-       hd->tmState = TM_STATE_NONE;
-       return FAILED;
+       CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+       if (issue_hard_reset) {
+               printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
+                       ioc->name, __func__);
+               retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
+               mpt_free_msg_frame(ioc, mf);
+       }
+
+       retval = (retval == 0) ? 0 : FAILED;
+       mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+       return retval;
 }
+EXPORT_SYMBOL(mptscsih_IssueTaskMgmt);
 
 static int
 mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
@@ -1838,13 +1714,8 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
                goto out;
        }
 
-       if (hd->resetPending) {
-               retval = FAILED;
-               goto out;
-       }
-
-       if (hd->timeouts < -1)
-               hd->timeouts++;
+       if (ioc->timeouts < -1)
+               ioc->timeouts++;
 
        if (mpt_fwfault_debug)
                mpt_halt_firmware(ioc);
@@ -1861,22 +1732,30 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
 
        hd->abortSCpnt = SCpnt;
 
-       retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
-           vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun,
-           ctx2abort, mptscsih_get_tm_timeout(ioc));
+       retval = mptscsih_IssueTaskMgmt(hd,
+                        MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
+                        vdevice->vtarget->channel,
+                        vdevice->vtarget->id, vdevice->lun,
+                        ctx2abort, mptscsih_get_tm_timeout(ioc));
 
        if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx &&
-           SCpnt->serial_number == sn)
+           SCpnt->serial_number == sn) {
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "task abort: command still in active list! (sc=%p)\n",
+                   ioc->name, SCpnt));
                retval = FAILED;
+       } else {
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "task abort: command cleared from active list! (sc=%p)\n",
+                   ioc->name, SCpnt));
+               retval = SUCCESS;
+       }
 
  out:
        printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
-           ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
+           ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), SCpnt);
 
-       if (retval == 0)
-               return SUCCESS;
-       else
-               return FAILED;
+       return retval;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -1909,14 +1788,9 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
               ioc->name, SCpnt);
        scsi_print_command(SCpnt);
 
-       if (hd->resetPending) {
-               retval = FAILED;
-               goto out;
-       }
-
        vdevice = SCpnt->device->hostdata;
        if (!vdevice || !vdevice->vtarget) {
-               retval = 0;
+               retval = SUCCESS;
                goto out;
        }
 
@@ -1927,9 +1801,11 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
                goto out;
        }
 
-       retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
-           vdevice->vtarget->channel, vdevice->vtarget->id, 0, 0,
-           mptscsih_get_tm_timeout(ioc));
+       retval = mptscsih_IssueTaskMgmt(hd,
+                               MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
+                               vdevice->vtarget->channel,
+                               vdevice->vtarget->id, 0, 0,
+                               mptscsih_get_tm_timeout(ioc));
 
  out:
        printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
@@ -1972,12 +1848,16 @@ mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
               ioc->name, SCpnt);
        scsi_print_command(SCpnt);
 
-       if (hd->timeouts < -1)
-               hd->timeouts++;
+       if (ioc->timeouts < -1)
+               ioc->timeouts++;
 
        vdevice = SCpnt->device->hostdata;
-       retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
-           vdevice->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc));
+       if (!vdevice || !vdevice->vtarget)
+               return SUCCESS;
+       retval = mptscsih_IssueTaskMgmt(hd,
+                                       MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+                                       vdevice->vtarget->channel, 0, 0, 0,
+                                       mptscsih_get_tm_timeout(ioc));
 
        printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
            ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
@@ -2001,8 +1881,9 @@ int
 mptscsih_host_reset(struct scsi_cmnd *SCpnt)
 {
        MPT_SCSI_HOST *  hd;
-       int              retval;
+       int              status = SUCCESS;
        MPT_ADAPTER     *ioc;
+       int             retval;
 
        /*  If we can't locate the host to reset, then we failed. */
        if ((hd = shost_priv(SCpnt->device->host)) == NULL){
@@ -2021,86 +1902,71 @@ mptscsih_host_reset(struct scsi_cmnd *SCpnt)
        /*  If our attempts to reset the host failed, then return a failed
         *  status.  The host will be taken off line by the SCSI mid-layer.
         */
-       if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) {
-               retval = FAILED;
-       } else {
-               /*  Make sure TM pending is cleared and TM state is set to
-                *  NONE.
-                */
-               retval = 0;
-               hd->tmPending = 0;
-               hd->tmState = TM_STATE_NONE;
-       }
+    retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
+       if (retval < 0)
+               status = FAILED;
+       else
+               status = SUCCESS;
 
        printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
            ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
 
-       return retval;
+       return status;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *     mptscsih_tm_pending_wait - wait for pending task management request to complete
- *     @hd: Pointer to MPT host structure.
- *
- *     Returns {SUCCESS,FAILED}.
- */
 static int
-mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
+mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,
+       SCSITaskMgmtReply_t *pScsiTmReply)
 {
-       unsigned long  flags;
-       int            loop_count = 4 * 10;  /* Wait 10 seconds */
-       int            status = FAILED;
-       MPT_ADAPTER     *ioc = hd->ioc;
+       u16                      iocstatus;
+       u32                      termination_count;
+       int                      retval;
 
-       do {
-               spin_lock_irqsave(&ioc->FreeQlock, flags);
-               if (hd->tmState == TM_STATE_NONE) {
-                       hd->tmState = TM_STATE_IN_PROGRESS;
-                       hd->tmPending = 1;
-                       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-                       status = SUCCESS;
-                       break;
-               }
-               spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-               msleep(250);
-       } while (--loop_count);
+       if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
+               retval = FAILED;
+               goto out;
+       }
 
-       return status;
-}
+       DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *     mptscsih_tm_wait_for_completion - wait for completion of TM task
- *     @hd: Pointer to MPT host structure.
- *     @timeout: timeout value
- *
- *     Returns {SUCCESS,FAILED}.
- */
-static int
-mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
-{
-       unsigned long  flags;
-       int            loop_count = 4 * timeout;
-       int            status = FAILED;
-       MPT_ADAPTER     *ioc = hd->ioc;
+       iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+       termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
 
-       do {
-               spin_lock_irqsave(&ioc->FreeQlock, flags);
-               if(hd->tmPending == 0) {
-                       status = SUCCESS;
-                       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-                       break;
-               }
-               spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-               msleep(250);
-       } while (--loop_count);
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n"
+           "\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n"
+           "\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus,
+           pScsiTmReply->TargetID, type, le16_to_cpu(pScsiTmReply->IOCStatus),
+           le32_to_cpu(pScsiTmReply->IOCLogInfo), pScsiTmReply->ResponseCode,
+           termination_count));
 
-       return status;
+       if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
+           pScsiTmReply->ResponseCode)
+               mptscsih_taskmgmt_response_code(ioc,
+                   pScsiTmReply->ResponseCode);
+
+       if (iocstatus == MPI_IOCSTATUS_SUCCESS) {
+               retval = 0;
+               goto out;
+       }
+
+       retval = FAILED;
+       if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
+               if (termination_count == 1)
+                       retval = 0;
+               goto out;
+       }
+
+       if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
+          iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
+               retval = 0;
+
+ out:
+       return retval;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static void
+void
 mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
 {
        char *desc;
@@ -2134,6 +2000,7 @@ mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
        printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
                ioc->name, response_code, desc);
 }
+EXPORT_SYMBOL(mptscsih_taskmgmt_response_code);
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
@@ -2150,97 +2017,28 @@ mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
  *     Returns 1 indicating alloc'd request frame ptr should be freed.
  **/
 int
-mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
+mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf,
+       MPT_FRAME_HDR *mr)
 {
-       SCSITaskMgmtReply_t     *pScsiTmReply;
-       SCSITaskMgmt_t          *pScsiTmReq;
-       MPT_SCSI_HOST           *hd;
-       unsigned long            flags;
-       u16                      iocstatus;
-       u8                       tmType;
-       u32                      termination_count;
-
-       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
-           ioc->name, mf, mr));
-       if (!ioc->sh) {
-               dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
-                   "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name));
-               return 1;
-       }
-
-       if (mr == NULL) {
-               dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
-                   "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf));
-               return 1;
-       }
-
-       hd = shost_priv(ioc->sh);
-       pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
-       pScsiTmReq = (SCSITaskMgmt_t*)mf;
-       tmType = pScsiTmReq->TaskType;
-       iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
-       termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+               "TaskMgmt completed (mf=%p, mr=%p)\n", ioc->name, mf, mr));
 
-       if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
-           pScsiTmReply->ResponseCode)
-               mptscsih_taskmgmt_response_code(ioc,
-                   pScsiTmReply->ResponseCode);
-       DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
+       ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
 
-#ifdef CONFIG_FUSION_LOGGING
-       if ((ioc->debug_level & MPT_DEBUG_REPLY) ||
-                               (ioc->debug_level & MPT_DEBUG_TM ))
-               printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
-                       "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
-                       "term_cmnds=%d\n", __func__, ioc->id, pScsiTmReply->Bus,
-                        pScsiTmReply->TargetID, pScsiTmReq->TaskType,
-                       le16_to_cpu(pScsiTmReply->IOCStatus),
-                       le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
-                       le32_to_cpu(pScsiTmReply->TerminationCount));
-#endif
-       if (!iocstatus) {
-               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT " TaskMgmt SUCCESS\n", ioc->name));
-                       hd->abortSCpnt = NULL;
+       if (!mr)
                goto out;
-       }
-
-       /* Error?  (anything non-zero?) */
-
-       /* clear flags and continue.
-        */
-       switch (tmType) {
-
-       case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
-               if (termination_count == 1)
-                       iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED;
-               hd->abortSCpnt = NULL;
-               break;
-
-       case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS:
-
-               /* If an internal command is present
-                * or the TM failed - reload the FW.
-                * FC FW may respond FAILED to an ABORT
-                */
-               if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED ||
-                   hd->cmdPtr)
-                       if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
-                               printk(MYIOC_s_WARN_FMT " Firmware Reload FAILED!!\n", ioc->name);
-               break;
-
-       case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
-       default:
-               break;
-       }
 
+       ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
+       memcpy(ioc->taskmgmt_cmds.reply, mr,
+           min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
  out:
-       spin_lock_irqsave(&ioc->FreeQlock, flags);
-       hd->tmPending = 0;
-       hd->tmState = TM_STATE_NONE;
-       hd->tm_iocstatus = iocstatus;
-       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-
-       return 1;
+       if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
+               mpt_clear_taskmgmt_in_progress_flag(ioc);
+               ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+               complete(&ioc->taskmgmt_cmds.done);
+               return 1;
+       }
+       return 0;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -2290,8 +2088,10 @@ int
 mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
 {
        struct inactive_raid_component_info *component_info;
-       int i;
+       int i, j;
+       RaidPhysDiskPage1_t *phys_disk;
        int rc = 0;
+       int num_paths;
 
        if (!ioc->raid_data.pIocPg3)
                goto out;
@@ -2303,6 +2103,45 @@ mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
                }
        }
 
+       if (ioc->bus_type != SAS)
+               goto out;
+
+       /*
+        * Check if dual path
+        */
+       for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
+               num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
+                   ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
+               if (num_paths < 2)
+                       continue;
+               phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
+                  (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
+               if (!phys_disk)
+                       continue;
+               if ((mpt_raid_phys_disk_pg1(ioc,
+                   ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
+                   phys_disk))) {
+                       kfree(phys_disk);
+                       continue;
+               }
+               for (j = 0; j < num_paths; j++) {
+                       if ((phys_disk->Path[j].Flags &
+                           MPI_RAID_PHYSDISK1_FLAG_INVALID))
+                               continue;
+                       if ((phys_disk->Path[j].Flags &
+                           MPI_RAID_PHYSDISK1_FLAG_BROKEN))
+                               continue;
+                       if ((id == phys_disk->Path[j].PhysDiskID) &&
+                           (channel == phys_disk->Path[j].PhysDiskBus)) {
+                               rc = 1;
+                               kfree(phys_disk);
+                               goto out;
+                       }
+               }
+               kfree(phys_disk);
+       }
+
+
        /*
         * Check inactive list for matching phys disks
         */
@@ -2327,8 +2166,10 @@ u8
 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
 {
        struct inactive_raid_component_info *component_info;
-       int i;
+       int i, j;
+       RaidPhysDiskPage1_t *phys_disk;
        int rc = -ENXIO;
+       int num_paths;
 
        if (!ioc->raid_data.pIocPg3)
                goto out;
@@ -2340,6 +2181,44 @@ mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
                }
        }
 
+       if (ioc->bus_type != SAS)
+               goto out;
+
+       /*
+        * Check if dual path
+        */
+       for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
+               num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
+                   ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
+               if (num_paths < 2)
+                       continue;
+               phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
+                  (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
+               if (!phys_disk)
+                       continue;
+               if ((mpt_raid_phys_disk_pg1(ioc,
+                   ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
+                   phys_disk))) {
+                       kfree(phys_disk);
+                       continue;
+               }
+               for (j = 0; j < num_paths; j++) {
+                       if ((phys_disk->Path[j].Flags &
+                           MPI_RAID_PHYSDISK1_FLAG_INVALID))
+                               continue;
+                       if ((phys_disk->Path[j].Flags &
+                           MPI_RAID_PHYSDISK1_FLAG_BROKEN))
+                               continue;
+                       if ((id == phys_disk->Path[j].PhysDiskID) &&
+                           (channel == phys_disk->Path[j].PhysDiskBus)) {
+                               rc = phys_disk->PhysDiskNum;
+                               kfree(phys_disk);
+                               goto out;
+                       }
+               }
+               kfree(phys_disk);
+       }
+
        /*
         * Check inactive list for matching phys disks
         */
@@ -2457,7 +2336,6 @@ mptscsih_slave_configure(struct scsi_device *sdev)
                    sdev->ppr, sdev->inquiry_len));
 
        vdevice->configured_lun = 1;
-       mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
 
        dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
                "Queue depth=%d, tflags=%x\n",
@@ -2469,6 +2347,7 @@ mptscsih_slave_configure(struct scsi_device *sdev)
                    ioc->name, vtarget->negoFlags, vtarget->maxOffset,
                    vtarget->minSyncFactor));
 
+       mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
        dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
                "tagged %d, simple %d, ordered %d\n",
                ioc->name,sdev->tagged_supported, sdev->simple_tags,
@@ -2542,15 +2421,13 @@ mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR
 }
 
 /**
- * mptscsih_get_scsi_lookup
+ * mptscsih_get_scsi_lookup - retrieves scmd entry
  * @ioc: Pointer to MPT_ADAPTER structure
  * @i: index into the array
  *
- * retrieves scmd entry from ScsiLookup[] array list
- *
  * Returns the scsi_cmd pointer
- **/
-static struct scsi_cmnd *
+ */
+struct scsi_cmnd *
 mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i)
 {
        unsigned long   flags;
@@ -2562,15 +2439,15 @@ mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i)
 
        return scmd;
 }
+EXPORT_SYMBOL(mptscsih_get_scsi_lookup);
 
 /**
- * mptscsih_getclear_scsi_lookup
+ * mptscsih_getclear_scsi_lookup -  retrieves and clears scmd entry from ScsiLookup[] array list
  * @ioc: Pointer to MPT_ADAPTER structure
  * @i: index into the array
  *
- * retrieves and clears scmd entry from ScsiLookup[] array list
- *
  * Returns the scsi_cmd pointer
+ *
  **/
 static struct scsi_cmnd *
 mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i)
@@ -2635,94 +2512,33 @@ int
 mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 {
        MPT_SCSI_HOST   *hd;
-       unsigned long    flags;
 
-       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-           ": IOC %s_reset routed to SCSI host driver!\n",
-           ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
-           reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
-
-       /* If a FW reload request arrives after base installed but
-        * before all scsi hosts have been attached, then an alt_ioc
-        * may have a NULL sh pointer.
-        */
        if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)
                return 0;
-       else
-               hd = shost_priv(ioc->sh);
-
-       if (reset_phase == MPT_IOC_SETUP_RESET) {
-               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Setup-Diag Reset\n", ioc->name));
-
-               /* Clean Up:
-                * 1. Set Hard Reset Pending Flag
-                * All new commands go to doneQ
-                */
-               hd->resetPending = 1;
-
-       } else if (reset_phase == MPT_IOC_PRE_RESET) {
-               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Diag Reset\n", ioc->name));
 
-               /* 2. Flush running commands
-                *      Clean ScsiLookup (and associated memory)
-                *      AND clean mytaskQ
-                */
-
-               /* 2b. Reply to OS all known outstanding I/O commands.
-                */
+       hd = shost_priv(ioc->sh);
+       switch (reset_phase) {
+       case MPT_IOC_SETUP_RESET:
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
+               break;
+       case MPT_IOC_PRE_RESET:
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
                mptscsih_flush_running_cmds(hd);
-
-               /* 2c. If there was an internal command that
-                * has not completed, configuration or io request,
-                * free these resources.
-                */
-               if (hd->cmdPtr) {
-                       del_timer(&hd->timer);
-                       mpt_free_msg_frame(ioc, hd->cmdPtr);
-               }
-
-               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Reset complete.\n", ioc->name));
-
-       } else {
-               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Diag Reset\n", ioc->name));
-
-               /* Once a FW reload begins, all new OS commands are
-                * redirected to the doneQ w/ a reset status.
-                * Init all control structures.
-                */
-
-               /* 2. Chain Buffer initialization
-                */
-
-               /* 4. Renegotiate to all devices, if SPI
-                */
-
-               /* 5. Enable new commands to be posted
-                */
-               spin_lock_irqsave(&ioc->FreeQlock, flags);
-               hd->tmPending = 0;
-               spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-               hd->resetPending = 0;
-               hd->tmState = TM_STATE_NONE;
-
-               /* 6. If there was an internal command,
-                * wake this process up.
-                */
-               if (hd->cmdPtr) {
-                       /*
-                        * Wake up the original calling thread
-                        */
-                       hd->pLocal = &hd->localReply;
-                       hd->pLocal->completion = MPT_SCANDV_DID_RESET;
-                       hd->scandv_wait_done = 1;
-                       wake_up(&hd->scandv_waitq);
-                       hd->cmdPtr = NULL;
+               break;
+       case MPT_IOC_POST_RESET:
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
+               if (ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING) {
+                       ioc->internal_cmds.status |=
+                               MPT_MGMT_STATUS_DID_IOCRESET;
+                       complete(&ioc->internal_cmds.done);
                }
-
-               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Reset complete.\n", ioc->name));
-
+               break;
+       default:
+               break;
        }
-
        return 1;               /* currently means nothing really */
 }
 
@@ -2730,55 +2546,16 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 int
 mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
 {
-       MPT_SCSI_HOST *hd;
        u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
 
-       devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
-                       ioc->name, event));
-
-       if (ioc->sh == NULL ||
-               ((hd = shost_priv(ioc->sh)) == NULL))
-               return 1;
-
-       switch (event) {
-       case MPI_EVENT_UNIT_ATTENTION:                  /* 03 */
-               /* FIXME! */
-               break;
-       case MPI_EVENT_IOC_BUS_RESET:                   /* 04 */
-       case MPI_EVENT_EXT_BUS_RESET:                   /* 05 */
-               if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
-                       hd->soft_resets++;
-               break;
-       case MPI_EVENT_LOGOUT:                          /* 09 */
-               /* FIXME! */
-               break;
-
-       case MPI_EVENT_RESCAN:                          /* 06 */
-               break;
-
-               /*
-                *  CHECKME! Don't think we need to do
-                *  anything for these, but...
-                */
-       case MPI_EVENT_LINK_STATUS_CHANGE:              /* 07 */
-       case MPI_EVENT_LOOP_STATE_CHANGE:               /* 08 */
-               /*
-                *  CHECKME!  Falling thru...
-                */
-               break;
-
-       case MPI_EVENT_INTEGRATED_RAID:                 /* 0B */
-               break;
+       devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+               "MPT event (=%02Xh) routed to SCSI host driver!\n",
+               ioc->name, event));
 
-       case MPI_EVENT_NONE:                            /* 00 */
-       case MPI_EVENT_LOG_DATA:                        /* 01 */
-       case MPI_EVENT_STATE_CHANGE:                    /* 02 */
-       case MPI_EVENT_EVENT_CHANGE:                    /* 0A */
-       default:
-               dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": Ignoring event (=%02Xh)\n",
-                   ioc->name, event));
-               break;
-       }
+       if ((event == MPI_EVENT_IOC_BUS_RESET ||
+           event == MPI_EVENT_EXT_BUS_RESET) &&
+           (ioc->bus_type == SPI) && (ioc->soft_resets < -1))
+                       ioc->soft_resets++;
 
        return 1;               /* currently means nothing really */
 }
@@ -2809,153 +2586,44 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
  *     Used ONLY for DV and other internal commands.
  */
 int
-mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
+mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
+                               MPT_FRAME_HDR *reply)
 {
-       MPT_SCSI_HOST   *hd;
        SCSIIORequest_t *pReq;
-       int              completionCode;
+       SCSIIOReply_t   *pReply;
+       u8               cmd;
        u16              req_idx;
+       u8      *sense_data;
+       int              sz;
 
-       hd = shost_priv(ioc->sh);
-
-       if ((mf == NULL) ||
-           (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
-               printk(MYIOC_s_ERR_FMT
-                       "ScanDvComplete, %s req frame ptr! (=%p)\n",
-                               ioc->name, mf?"BAD":"NULL", (void *) mf);
-               goto wakeup;
-       }
-
-       del_timer(&hd->timer);
-       req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
-       mptscsih_set_scsi_lookup(ioc, req_idx, NULL);
-       pReq = (SCSIIORequest_t *) mf;
+       ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
+       ioc->internal_cmds.completion_code = MPT_SCANDV_GOOD;
+       if (!reply)
+               goto out;
 
-       if (mf != hd->cmdPtr) {
-               printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
-                               ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
+       pReply = (SCSIIOReply_t *) reply;
+       pReq = (SCSIIORequest_t *) req;
+       ioc->internal_cmds.completion_code =
+           mptscsih_get_completion_code(ioc, req, reply);
+       ioc->internal_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
+       memcpy(ioc->internal_cmds.reply, reply,
+           min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength));
+       cmd = reply->u.hdr.Function;
+       if (((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
+           (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) &&
+           (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
+               req_idx = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
+               sense_data = ((u8 *)ioc->sense_buf_pool +
+                   (req_idx * MPT_SENSE_BUFFER_ALLOC));
+               sz = min_t(int, pReq->SenseBufferLength,
+                   MPT_SENSE_BUFFER_ALLOC);
+               memcpy(ioc->internal_cmds.sense, sense_data, sz);
        }
-       hd->cmdPtr = NULL;
-
-       ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
-                       ioc->name, mf, mr, req_idx));
-
-       hd->pLocal = &hd->localReply;
-       hd->pLocal->scsiStatus = 0;
-
-       /* If target struct exists, clear sense valid flag.
-        */
-       if (mr == NULL) {
-               completionCode = MPT_SCANDV_GOOD;
-       } else {
-               SCSIIOReply_t   *pReply;
-               u16              status;
-               u8               scsi_status;
-
-               pReply = (SCSIIOReply_t *) mr;
-
-               status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
-               scsi_status = pReply->SCSIStatus;
-
-
-               switch(status) {
-
-               case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:       /* 0x0043 */
-                       completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
-                       break;
-
-               case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:          /* 0x0046 */
-               case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:        /* 0x0048 */
-               case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:         /* 0x004B */
-               case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:         /* 0x004C */
-                       completionCode = MPT_SCANDV_DID_RESET;
-                       break;
-
-               case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:          /* 0x0045 */
-               case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:        /* 0x0040 */
-               case MPI_IOCSTATUS_SUCCESS:                     /* 0x0000 */
-                       if (pReply->Function == MPI_FUNCTION_CONFIG) {
-                               ConfigReply_t *pr = (ConfigReply_t *)mr;
-                               completionCode = MPT_SCANDV_GOOD;
-                               hd->pLocal->header.PageVersion = pr->Header.PageVersion;
-                               hd->pLocal->header.PageLength = pr->Header.PageLength;
-                               hd->pLocal->header.PageNumber = pr->Header.PageNumber;
-                               hd->pLocal->header.PageType = pr->Header.PageType;
-
-                       } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
-                               /* If the RAID Volume request is successful,
-                                * return GOOD, else indicate that
-                                * some type of error occurred.
-                                */
-                               MpiRaidActionReply_t    *pr = (MpiRaidActionReply_t *)mr;
-                               if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
-                                       completionCode = MPT_SCANDV_GOOD;
-                               else
-                                       completionCode = MPT_SCANDV_SOME_ERROR;
-                               memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
-
-                       } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
-                               u8              *sense_data;
-                               int              sz;
-
-                               /* save sense data in global structure
-                                */
-                               completionCode = MPT_SCANDV_SENSE;
-                               hd->pLocal->scsiStatus = scsi_status;
-                               sense_data = ((u8 *)ioc->sense_buf_pool +
-                                       (req_idx * MPT_SENSE_BUFFER_ALLOC));
-
-                               sz = min_t(int, pReq->SenseBufferLength,
-                                                       SCSI_STD_SENSE_BYTES);
-                               memcpy(hd->pLocal->sense, sense_data, sz);
-
-                               ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "  Check Condition, sense ptr %p\n",
-                                   ioc->name, sense_data));
-                       } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
-                               if (pReq->CDB[0] == INQUIRY)
-                                       completionCode = MPT_SCANDV_ISSUE_SENSE;
-                               else
-                                       completionCode = MPT_SCANDV_DID_RESET;
-                       }
-                       else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
-                               completionCode = MPT_SCANDV_DID_RESET;
-                       else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
-                               completionCode = MPT_SCANDV_DID_RESET;
-                       else {
-                               completionCode = MPT_SCANDV_GOOD;
-                               hd->pLocal->scsiStatus = scsi_status;
-                       }
-                       break;
-
-               case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:         /* 0x0047 */
-                       if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
-                               completionCode = MPT_SCANDV_DID_RESET;
-                       else
-                               completionCode = MPT_SCANDV_SOME_ERROR;
-                       break;
-
-               default:
-                       completionCode = MPT_SCANDV_SOME_ERROR;
-                       break;
-
-               }       /* switch(status) */
-
-       } /* end of address reply case */
-
-       hd->pLocal->completion = completionCode;
-
-       /* MF and RF are freed in mpt_interrupt
-        */
-wakeup:
-       /* Free Chain buffers (will never chain) in scan or dv */
-       //mptscsih_freeChainBuffers(ioc, req_idx);
-
-       /*
-        * Wake up the original calling thread
-        */
-       hd->scandv_wait_done = 1;
-       wake_up(&hd->scandv_waitq);
-
+ out:
+       if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING))
+               return 0;
+       ioc->internal_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+       complete(&ioc->internal_cmds.done);
        return 1;
 }
 
@@ -3004,6 +2672,95 @@ mptscsih_timer_expired(unsigned long data)
        return;
 }
 
+/**
+ *     mptscsih_get_completion_code -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @req: Pointer to original MPT request frame
+ *     @reply: Pointer to MPT reply frame (NULL if TurboReply)
+ *
+ **/
+static int
+mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
+                               MPT_FRAME_HDR *reply)
+{
+       SCSIIOReply_t   *pReply;
+       MpiRaidActionReply_t *pr;
+       u8               scsi_status;
+       u16              status;
+       int              completion_code;
+
+       pReply = (SCSIIOReply_t *)reply;
+       status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+       scsi_status = pReply->SCSIStatus;
+
+       devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh,"
+           "IOCLogInfo=%08xh\n", ioc->name, status, pReply->SCSIState,
+           scsi_status, le32_to_cpu(pReply->IOCLogInfo)));
+
+       switch (status) {
+
+       case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:       /* 0x0043 */
+               completion_code = MPT_SCANDV_SELECTION_TIMEOUT;
+               break;
+
+       case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:          /* 0x0046 */
+       case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:        /* 0x0048 */
+       case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:         /* 0x004B */
+       case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:         /* 0x004C */
+               completion_code = MPT_SCANDV_DID_RESET;
+               break;
+
+       case MPI_IOCSTATUS_BUSY:
+       case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
+               completion_code = MPT_SCANDV_BUSY;
+               break;
+
+       case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:          /* 0x0045 */
+       case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:        /* 0x0040 */
+       case MPI_IOCSTATUS_SUCCESS:                     /* 0x0000 */
+               if (pReply->Function == MPI_FUNCTION_CONFIG) {
+                       completion_code = MPT_SCANDV_GOOD;
+               } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
+                       pr = (MpiRaidActionReply_t *)reply;
+                       if (le16_to_cpu(pr->ActionStatus) ==
+                               MPI_RAID_ACTION_ASTATUS_SUCCESS)
+                               completion_code = MPT_SCANDV_GOOD;
+                       else
+                               completion_code = MPT_SCANDV_SOME_ERROR;
+               } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)
+                       completion_code = MPT_SCANDV_SENSE;
+               else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
+                       if (req->u.scsireq.CDB[0] == INQUIRY)
+                               completion_code = MPT_SCANDV_ISSUE_SENSE;
+                       else
+                               completion_code = MPT_SCANDV_DID_RESET;
+               } else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
+                       completion_code = MPT_SCANDV_DID_RESET;
+               else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
+                       completion_code = MPT_SCANDV_DID_RESET;
+               else if (scsi_status == MPI_SCSI_STATUS_BUSY)
+                       completion_code = MPT_SCANDV_BUSY;
+               else
+                       completion_code = MPT_SCANDV_GOOD;
+               break;
+
+       case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:         /* 0x0047 */
+               if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
+                       completion_code = MPT_SCANDV_DID_RESET;
+               else
+                       completion_code = MPT_SCANDV_SOME_ERROR;
+               break;
+       default:
+               completion_code = MPT_SCANDV_SOME_ERROR;
+               break;
+
+       }       /* switch(status) */
+
+       devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "  completionCode set to %08xh\n", ioc->name, completion_code));
+       return completion_code;
+}
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
@@ -3030,22 +2787,27 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
 {
        MPT_FRAME_HDR   *mf;
        SCSIIORequest_t *pScsiReq;
-       SCSIIORequest_t  ReqCopy;
        int              my_idx, ii, dir;
-       int              rc, cmdTimeout;
-       int             in_isr;
+       int              timeout;
        char             cmdLen;
        char             CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-       char             cmd = io->cmd;
-       MPT_ADAPTER     *ioc = hd->ioc;
+       u8               cmd = io->cmd;
+       MPT_ADAPTER *ioc = hd->ioc;
+       int              ret = 0;
+       unsigned long    timeleft;
+       unsigned long    flags;
 
-       in_isr = in_interrupt();
-       if (in_isr) {
-               dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Internal SCSI IO request not allowed in ISR context!\n",
-                                       ioc->name));
-               return -EPERM;
+       /* don't send internal command during diag reset */
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       if (ioc->ioc_reset_in_progress) {
+               spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+               dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                       "%s: busy with host reset\n", ioc->name, __func__));
+               return MPT_SCANDV_BUSY;
        }
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
 
+       mutex_lock(&ioc->internal_cmds.mutex);
 
        /* Set command specific information
         */
@@ -3055,13 +2817,13 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
                dir = MPI_SCSIIO_CONTROL_READ;
                CDB[0] = cmd;
                CDB[4] = io->size;
-               cmdTimeout = 10;
+               timeout = 10;
                break;
 
        case TEST_UNIT_READY:
                cmdLen = 6;
                dir = MPI_SCSIIO_CONTROL_READ;
-               cmdTimeout = 10;
+               timeout = 10;
                break;
 
        case START_STOP:
@@ -3069,7 +2831,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
                dir = MPI_SCSIIO_CONTROL_READ;
                CDB[0] = cmd;
                CDB[4] = 1;     /*Spin up the disk */
-               cmdTimeout = 15;
+               timeout = 15;
                break;
 
        case REQUEST_SENSE:
@@ -3077,7 +2839,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
                CDB[0] = cmd;
                CDB[4] = io->size;
                dir = MPI_SCSIIO_CONTROL_READ;
-               cmdTimeout = 10;
+               timeout = 10;
                break;
 
        case READ_BUFFER:
@@ -3096,7 +2858,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
                CDB[6] = (io->size >> 16) & 0xFF;
                CDB[7] = (io->size >>  8) & 0xFF;
                CDB[8] = io->size & 0xFF;
-               cmdTimeout = 10;
+               timeout = 10;
                break;
 
        case WRITE_BUFFER:
@@ -3111,21 +2873,21 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
                CDB[6] = (io->size >> 16) & 0xFF;
                CDB[7] = (io->size >>  8) & 0xFF;
                CDB[8] = io->size & 0xFF;
-               cmdTimeout = 10;
+               timeout = 10;
                break;
 
        case RESERVE:
                cmdLen = 6;
                dir = MPI_SCSIIO_CONTROL_READ;
                CDB[0] = cmd;
-               cmdTimeout = 10;
+               timeout = 10;
                break;
 
        case RELEASE:
                cmdLen = 6;
                dir = MPI_SCSIIO_CONTROL_READ;
                CDB[0] = cmd;
-               cmdTimeout = 10;
+               timeout = 10;
                break;
 
        case SYNCHRONIZE_CACHE:
@@ -3133,20 +2895,23 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
                dir = MPI_SCSIIO_CONTROL_READ;
                CDB[0] = cmd;
 //             CDB[1] = 0x02;  /* set immediate bit */
-               cmdTimeout = 10;
+               timeout = 10;
                break;
 
        default:
                /* Error Case */
-               return -EFAULT;
+               ret = -EFAULT;
+               goto out;
        }
 
        /* Get and Populate a free Frame
+        * MsgContext set in mpt_get_msg_frame call
         */
        if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
-               dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "No msg frames!\n",
-                   ioc->name));
-               return -EBUSY;
+               dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n",
+                   ioc->name, __func__));
+               ret = MPT_SCANDV_BUSY;
+               goto out;
        }
 
        pScsiReq = (SCSIIORequest_t *) mf;
@@ -3172,7 +2937,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
 
        pScsiReq->Reserved = 0;
 
-       pScsiReq->MsgFlags = mpt_msg_flags();
+       pScsiReq->MsgFlags = mpt_msg_flags(ioc);
        /* MsgContext set in mpt_get_msg_fram call  */
 
        int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
@@ -3184,74 +2949,58 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
 
        if (cmd == REQUEST_SENSE) {
                pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
-               ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Untagged! 0x%2x\n",
-                       ioc->name, cmd));
+               devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: Untagged! 0x%02x\n", ioc->name, __func__, cmd));
        }
 
-       for (ii=0; ii < 16; ii++)
+       for (ii = 0; ii < 16; ii++)
                pScsiReq->CDB[ii] = CDB[ii];
 
        pScsiReq->DataLength = cpu_to_le32(io->size);
        pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
                                           + (my_idx * MPT_SENSE_BUFFER_ALLOC));
 
-       ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
-                       ioc->name, cmd, io->channel, io->id, io->lun));
+       devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "%s: Sending Command 0x%02x for fw_channel=%d fw_id=%d lun=%d\n",
+           ioc->name, __func__, cmd, io->channel, io->id, io->lun));
 
-       if (dir == MPI_SCSIIO_CONTROL_READ) {
-               mpt_add_sge((char *) &pScsiReq->SGL,
-                       MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
-                       io->data_dma);
-       } else {
-               mpt_add_sge((char *) &pScsiReq->SGL,
-                       MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
-                       io->data_dma);
-       }
-
-       /* The ISR will free the request frame, but we need
-        * the information to initialize the target. Duplicate.
-        */
-       memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
-
-       /* Issue this command after:
-        *      finish init
-        *      add timer
-        * Wait until the reply has been received
-        *  ScsiScanDvCtx callback function will
-        *      set hd->pLocal;
-        *      set scandv_wait_done and call wake_up
-        */
-       hd->pLocal = NULL;
-       hd->timer.expires = jiffies + HZ*cmdTimeout;
-       hd->scandv_wait_done = 0;
-
-       /* Save cmd pointer, for resource free if timeout or
-        * FW reload occurs
-        */
-       hd->cmdPtr = mf;
+       if (dir == MPI_SCSIIO_CONTROL_READ)
+               ioc->add_sge((char *) &pScsiReq->SGL,
+                   MPT_SGE_FLAGS_SSIMPLE_READ | io->size, io->data_dma);
+       else
+               ioc->add_sge((char *) &pScsiReq->SGL,
+                   MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, io->data_dma);
 
-       add_timer(&hd->timer);
+       INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
        mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
-       wait_event(hd->scandv_waitq, hd->scandv_wait_done);
-
-       if (hd->pLocal) {
-               rc = hd->pLocal->completion;
-               hd->pLocal->skip = 0;
-
-               /* Always set fatal error codes in some cases.
-                */
-               if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
-                       rc = -ENXIO;
-               else if (rc == MPT_SCANDV_SOME_ERROR)
-                       rc =  -rc;
-       } else {
-               rc = -EFAULT;
-               /* This should never happen. */
-               ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "_do_cmd: Null pLocal!!!\n",
-                               ioc->name));
+       timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done,
+           timeout*HZ);
+       if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               ret = MPT_SCANDV_DID_RESET;
+               dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __func__,
+                   cmd));
+               if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
+                       mpt_free_msg_frame(ioc, mf);
+                       goto out;
+               }
+               if (!timeleft) {
+                       printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
+                           ioc->name, __func__);
+                       mpt_HardResetHandler(ioc, CAN_SLEEP);
+                       mpt_free_msg_frame(ioc, mf);
+               }
+               goto out;
        }
 
-       return rc;
+       ret = ioc->internal_cmds.completion_code;
+       devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n",
+                       ioc->name, __func__, ret));
+
+ out:
+       CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
+       mutex_unlock(&ioc->internal_cmds.mutex);
+       return ret;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -3491,6 +3240,7 @@ struct device_attribute *mptscsih_host_attrs[] = {
        &dev_attr_debug_level,
        NULL,
 };
+
 EXPORT_SYMBOL(mptscsih_host_attrs);
 
 EXPORT_SYMBOL(mptscsih_remove);
@@ -3516,6 +3266,5 @@ EXPORT_SYMBOL(mptscsih_event_process);
 EXPORT_SYMBOL(mptscsih_ioc_reset);
 EXPORT_SYMBOL(mptscsih_change_queue_depth);
 EXPORT_SYMBOL(mptscsih_timer_expired);
-EXPORT_SYMBOL(mptscsih_TMHandler);
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
index 319aa3033371999e8c75b2f151a84942744d04fb..eb3f677528ac703b1dac56f6795441fc155108df 100644 (file)
@@ -60,6 +60,7 @@
 #define MPT_SCANDV_SELECTION_TIMEOUT   (0x00000008)
 #define MPT_SCANDV_ISSUE_SENSE         (0x00000010)
 #define MPT_SCANDV_FALLBACK            (0x00000020)
+#define MPT_SCANDV_BUSY                        (0x00000040)
 
 #define MPT_SCANDV_MAX_RETRIES         (10)
 
@@ -89,6 +90,7 @@
 
 #endif
 
+
 typedef struct _internal_cmd {
        char            *data;          /* data pointer */
        dma_addr_t      data_dma;       /* data dma address */
@@ -112,6 +114,8 @@ extern int mptscsih_resume(struct pci_dev *pdev);
 extern int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int func);
 extern const char * mptscsih_info(struct Scsi_Host *SChost);
 extern int mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *));
+extern int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel,
+       u8 id, int lun, int ctx2abort, ulong timeout);
 extern void mptscsih_slave_destroy(struct scsi_device *device);
 extern int mptscsih_slave_configure(struct scsi_device *device);
 extern int mptscsih_abort(struct scsi_cmnd * SCpnt);
@@ -126,7 +130,8 @@ extern int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pE
 extern int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
 extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth);
 extern void mptscsih_timer_expired(unsigned long data);
-extern int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout);
 extern u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id);
 extern int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id);
 extern struct device_attribute *mptscsih_host_attrs[];
+extern struct scsi_cmnd        *mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
+extern void mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code);
index 61620144e49c32c82a834e9911035dc675691f1e..c5b808fd55ba6fc2b523939836abe347e85aeeea 100644 (file)
@@ -300,7 +300,7 @@ mptspi_writeIOCPage4(MPT_SCSI_HOST *hd, u8 channel , u8 id)
        flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
                (IOCPage4Ptr->Header.PageLength + ii) * 4;
 
-       mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
+       ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
 
        ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
                "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
@@ -614,19 +614,24 @@ static void mptspi_read_parameters(struct scsi_target *starget)
        spi_width(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WIDE) ? 1 : 0;
 }
 
-static int
+int
 mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
 {
+       MPT_ADAPTER     *ioc = hd->ioc;
        MpiRaidActionRequest_t  *pReq;
        MPT_FRAME_HDR           *mf;
-       MPT_ADAPTER *ioc = hd->ioc;
+       int                     ret;
+       unsigned long           timeleft;
+
+       mutex_lock(&ioc->internal_cmds.mutex);
 
        /* Get and Populate a free Frame
         */
        if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
-               ddvprintk(ioc, printk(MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
-                                       ioc->name));
-               return -EAGAIN;
+               dfailprintk(hd->ioc, printk(MYIOC_s_WARN_FMT
+                       "%s: no msg frames!\n", ioc->name, __func__));
+               ret = -EAGAIN;
+               goto out;
        }
        pReq = (MpiRaidActionRequest_t *)mf;
        if (quiesce)
@@ -643,29 +648,36 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
        pReq->Reserved2 = 0;
        pReq->ActionDataWord = 0; /* Reserved for this action */
 
-       mpt_add_sge((char *)&pReq->ActionDataSGE,
+       ioc->add_sge((char *)&pReq->ActionDataSGE,
                MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
 
        ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n",
                        ioc->name, pReq->Action, channel, id));
 
-       hd->pLocal = NULL;
-       hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */
-       hd->scandv_wait_done = 0;
-
-       /* Save cmd pointer, for resource free if timeout or
-        * FW reload occurs
-        */
-       hd->cmdPtr = mf;
-
-       add_timer(&hd->timer);
+       INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
        mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
-       wait_event(hd->scandv_waitq, hd->scandv_wait_done);
+       timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done, 10*HZ);
+       if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               ret = -ETIME;
+               dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: TIMED OUT!\n",
+                   ioc->name, __func__));
+               if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
+                       goto out;
+               if (!timeleft) {
+                       printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
+                           ioc->name, __func__);
+                       mpt_HardResetHandler(ioc, CAN_SLEEP);
+                       mpt_free_msg_frame(ioc, mf);
+               }
+               goto out;
+       }
 
-       if ((hd->pLocal == NULL) || (hd->pLocal->completion != 0))
-               return -1;
+       ret = ioc->internal_cmds.completion_code;
 
-       return 0;
+ out:
+       CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
+       mutex_unlock(&ioc->internal_cmds.mutex);
+       return ret;
 }
 
 static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
@@ -1423,17 +1435,15 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
         * A slightly different algorithm is required for
         * 64bit SGEs.
         */
-       scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
-       if (sizeof(dma_addr_t) == sizeof(u64)) {
+       scale = ioc->req_sz/ioc->SGE_size;
+       if (ioc->sg_addr_size == sizeof(u64)) {
                numSGE = (scale - 1) *
                  (ioc->facts.MaxChainDepth-1) + scale +
-                 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
-                 sizeof(u32));
+                 (ioc->req_sz - 60) / ioc->SGE_size;
        } else {
                numSGE = 1 + (scale - 1) *
                  (ioc->facts.MaxChainDepth-1) + scale +
-                 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
-                 sizeof(u32));
+                 (ioc->req_sz - 64) / ioc->SGE_size;
        }
 
        if (numSGE < sh->sg_tablesize) {
@@ -1464,9 +1474,6 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        /* Clear the TM flags
         */
-       hd->tmPending = 0;
-       hd->tmState = TM_STATE_NONE;
-       hd->resetPending = 0;
        hd->abortSCpnt = NULL;
 
        /* Clear the pointer used to store
@@ -1493,8 +1500,6 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                mpt_saf_te));
        ioc->spi_data.noQas = 0;
 
-       init_waitqueue_head(&hd->scandv_waitq);
-       hd->scandv_wait_done = 0;
        hd->last_queue_full = 0;
        hd->spi_pending = 0;
 
@@ -1514,7 +1519,7 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
         * issue internal bus reset
         */
        if (ioc->spi_data.bus_reset)
-               mptscsih_TMHandler(hd,
+               mptscsih_IssueTaskMgmt(hd,
                    MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
                    0, 0, 0, 0, 5);
 
index e9f4323dd2cb4ea67e6263ec75059b3c5604cc85..875f7a875734252cd868996ec048a53793e9deb3 100644 (file)
@@ -108,6 +108,10 @@ static int t7l66xb_mmc_disable(struct platform_device *mmc)
 
 /*--------------------------------------------------------------------------*/
 
+static const struct tmio_mmc_data t7166xb_mmc_data = {
+       .hclk = 24000000,
+};
+
 static const struct resource t7l66xb_mmc_resources[] = {
        {
                .start = 0x800,
@@ -149,6 +153,7 @@ static struct mfd_cell t7l66xb_cells[] = {
                .name = "tmio-mmc",
                .enable = t7l66xb_mmc_enable,
                .disable = t7l66xb_mmc_disable,
+               .driver_data = &t7166xb_mmc_data,
                .num_resources = ARRAY_SIZE(t7l66xb_mmc_resources),
                .resources = t7l66xb_mmc_resources,
        },
index 43222c12fec14fc906993322c31f3cbad89f3e41..c3993ac20542db00bdc2e5e6a8c54a244d3a3e4a 100644 (file)
@@ -75,6 +75,10 @@ static int tc6387xb_mmc_disable(struct platform_device *mmc)
 
 /*--------------------------------------------------------------------------*/
 
+const static struct tmio_mmc_data tc6387xb_mmc_data = {
+       .hclk = 24000000,
+};
+
 static struct resource tc6387xb_mmc_resources[] = {
        {
                .start = 0x800,
@@ -98,6 +102,7 @@ static struct mfd_cell tc6387xb_cells[] = {
                .name = "tmio-mmc",
                .enable = tc6387xb_mmc_enable,
                .disable = tc6387xb_mmc_disable,
+               .driver_data = &tc6387xb_mmc_data,
                .num_resources = ARRAY_SIZE(tc6387xb_mmc_resources),
                .resources = tc6387xb_mmc_resources,
        },
index 77a12fc8045e4367fff065f861237035e658f597..9d2abb5d6e2cd4c69f4b535583b41fa89fce2242 100644 (file)
@@ -136,6 +136,10 @@ static int tc6393xb_nand_enable(struct platform_device *nand)
        return 0;
 }
 
+const static struct tmio_mmc_data tc6393xb_mmc_data = {
+       .hclk = 24000000,
+};
+
 static struct resource __devinitdata tc6393xb_nand_resources[] = {
        {
                .start  = 0x1000,
@@ -351,6 +355,7 @@ static struct mfd_cell __devinitdata tc6393xb_cells[] = {
        },
        [TC6393XB_CELL_MMC] = {
                .name = "tmio-mmc",
+               .driver_data = &tc6393xb_mmc_data,
                .num_resources = ARRAY_SIZE(tc6393xb_mmc_resources),
                .resources = tc6393xb_mmc_resources,
        },
index 6d1ac180f6ee8013b212ff06bf6dca6ff475b1cb..68ab39d7cb3586eaf0260ba14e71b4b16efa0595 100644 (file)
@@ -235,5 +235,6 @@ config ISL29003
 
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
+source "drivers/misc/cb710/Kconfig"
 
 endif # MISC_DEVICES
index 7871f05dcb9b8d29804dbe7e68743c01369937da..36f733cd60e65fe772c10a0fd75ee1ba5defbb6a 100644 (file)
@@ -21,3 +21,4 @@ obj-$(CONFIG_HP_ILO)          += hpilo.o
 obj-$(CONFIG_ISL29003)         += isl29003.o
 obj-$(CONFIG_C2PORT)           += c2port/
 obj-y                          += eeprom/
+obj-y                          += cb710/
diff --git a/drivers/misc/cb710/Kconfig b/drivers/misc/cb710/Kconfig
new file mode 100644 (file)
index 0000000..22429b8
--- /dev/null
@@ -0,0 +1,25 @@
+config CB710_CORE
+       tristate "ENE CB710/720 Flash memory card reader support"
+       depends on PCI
+       help
+         This option enables support for PCI ENE CB710/720 Flash memory card
+         reader found in some laptops (ie. some versions of HP Compaq nx9500).
+
+         You will also have to select some flash card format drivers (MMC/SD,
+         MemoryStick).
+
+         This driver can also be built as a module. If so, the module
+         will be called cb710.
+
+config CB710_DEBUG
+       bool "Enable driver debugging"
+       depends on CB710_CORE != n
+       default n
+       help
+         This is an option for use by developers; most people should
+         say N here.  This adds a lot of debugging output to dmesg.
+
+config CB710_DEBUG_ASSUMPTIONS
+       bool
+       depends on CB710_CORE != n
+       default y
diff --git a/drivers/misc/cb710/Makefile b/drivers/misc/cb710/Makefile
new file mode 100644 (file)
index 0000000..7b80cbf
--- /dev/null
@@ -0,0 +1,8 @@
+ifeq ($(CONFIG_CB710_DEBUG),y)
+       EXTRA_CFLAGS            += -DDEBUG
+endif
+
+obj-$(CONFIG_CB710_CORE)       += cb710.o
+
+cb710-y                                := core.o sgbuf2.o
+cb710-$(CONFIG_CB710_DEBUG)    += debug.o
diff --git a/drivers/misc/cb710/core.c b/drivers/misc/cb710/core.c
new file mode 100644 (file)
index 0000000..b14eab0
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ *  cb710/core.c
+ *
+ *  Copyright by MichaÅ‚ MirosÅ‚aw, 2008-2009
+ *
+ * This 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/slab.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/idr.h>
+#include <linux/cb710.h>
+
+static DEFINE_IDA(cb710_ida);
+static DEFINE_SPINLOCK(cb710_ida_lock);
+
+void cb710_pci_update_config_reg(struct pci_dev *pdev,
+       int reg, uint32_t mask, uint32_t xor)
+{
+       u32 rval;
+
+       pci_read_config_dword(pdev, reg, &rval);
+       rval = (rval & mask) ^ xor;
+       pci_write_config_dword(pdev, reg, rval);
+}
+EXPORT_SYMBOL_GPL(cb710_pci_update_config_reg);
+
+/* Some magic writes based on Windows driver init code */
+static int __devinit cb710_pci_configure(struct pci_dev *pdev)
+{
+       unsigned int devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0);
+       struct pci_dev *pdev0 = pci_get_slot(pdev->bus, devfn);
+       u32 val;
+
+       cb710_pci_update_config_reg(pdev, 0x48,
+               ~0x000000FF, 0x0000003F);
+
+       pci_read_config_dword(pdev, 0x48, &val);
+       if (val & 0x80000000)
+               return 0;
+
+       if (!pdev0)
+               return -ENODEV;
+
+       if (pdev0->vendor == PCI_VENDOR_ID_ENE
+           && pdev0->device == PCI_DEVICE_ID_ENE_720) {
+               cb710_pci_update_config_reg(pdev0, 0x8C,
+                       ~0x00F00000, 0x00100000);
+               cb710_pci_update_config_reg(pdev0, 0xB0,
+                       ~0x08000000, 0x08000000);
+       }
+
+       cb710_pci_update_config_reg(pdev0, 0x8C,
+               ~0x00000F00, 0x00000200);
+       cb710_pci_update_config_reg(pdev0, 0x90,
+               ~0x00060000, 0x00040000);
+
+       pci_dev_put(pdev0);
+
+       return 0;
+}
+
+static irqreturn_t cb710_irq_handler(int irq, void *data)
+{
+       struct cb710_chip *chip = data;
+       struct cb710_slot *slot = &chip->slot[0];
+       irqreturn_t handled = IRQ_NONE;
+       unsigned nr;
+
+       spin_lock(&chip->irq_lock); /* incl. smp_rmb() */
+
+       for (nr = chip->slots; nr; ++slot, --nr) {
+               cb710_irq_handler_t handler_func = slot->irq_handler;
+               if (handler_func && handler_func(slot))
+                       handled = IRQ_HANDLED;
+       }
+
+       spin_unlock(&chip->irq_lock);
+
+       return handled;
+}
+
+static void cb710_release_slot(struct device *dev)
+{
+#ifdef CONFIG_CB710_DEBUG_ASSUMPTIONS
+       struct cb710_slot *slot = cb710_pdev_to_slot(to_platform_device(dev));
+       struct cb710_chip *chip = cb710_slot_to_chip(slot);
+
+       /* slot struct can be freed now */
+       atomic_dec(&chip->slot_refs_count);
+#endif
+}
+
+static int __devinit cb710_register_slot(struct cb710_chip *chip,
+       unsigned slot_mask, unsigned io_offset, const char *name)
+{
+       int nr = chip->slots;
+       struct cb710_slot *slot = &chip->slot[nr];
+       int err;
+
+       dev_dbg(cb710_chip_dev(chip),
+               "register: %s.%d; slot %d; mask %d; IO offset: 0x%02X\n",
+               name, chip->platform_id, nr, slot_mask, io_offset);
+
+       /* slot->irq_handler == NULL here; this needs to be
+        * seen before platform_device_register() */
+       ++chip->slots;
+       smp_wmb();
+
+       slot->iobase = chip->iobase + io_offset;
+       slot->pdev.name = name;
+       slot->pdev.id = chip->platform_id;
+       slot->pdev.dev.parent = &chip->pdev->dev;
+       slot->pdev.dev.release = cb710_release_slot;
+
+       err = platform_device_register(&slot->pdev);
+
+#ifdef CONFIG_CB710_DEBUG_ASSUMPTIONS
+       atomic_inc(&chip->slot_refs_count);
+#endif
+
+       if (err) {
+               /* device_initialize() called from platform_device_register()
+                * wants this on error path */
+               platform_device_put(&slot->pdev);
+
+               /* slot->irq_handler == NULL here anyway, so no lock needed */
+               --chip->slots;
+               return err;
+       }
+
+       chip->slot_mask |= slot_mask;
+
+       return 0;
+}
+
+static void cb710_unregister_slot(struct cb710_chip *chip,
+       unsigned slot_mask)
+{
+       int nr = chip->slots - 1;
+
+       if (!(chip->slot_mask & slot_mask))
+               return;
+
+       platform_device_unregister(&chip->slot[nr].pdev);
+
+       /* complementary to spin_unlock() in cb710_set_irq_handler() */
+       smp_rmb();
+       BUG_ON(chip->slot[nr].irq_handler != NULL);
+
+       /* slot->irq_handler == NULL here, so no lock needed */
+       --chip->slots;
+       chip->slot_mask &= ~slot_mask;
+}
+
+void cb710_set_irq_handler(struct cb710_slot *slot,
+       cb710_irq_handler_t handler)
+{
+       struct cb710_chip *chip = cb710_slot_to_chip(slot);
+       unsigned long flags;
+
+       spin_lock_irqsave(&chip->irq_lock, flags);
+       slot->irq_handler = handler;
+       spin_unlock_irqrestore(&chip->irq_lock, flags);
+}
+EXPORT_SYMBOL_GPL(cb710_set_irq_handler);
+
+#ifdef CONFIG_PM
+
+static int cb710_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct cb710_chip *chip = pci_get_drvdata(pdev);
+
+       free_irq(pdev->irq, chip);
+       pci_save_state(pdev);
+       pci_disable_device(pdev);
+       if (state.event & PM_EVENT_SLEEP)
+               pci_set_power_state(pdev, PCI_D3cold);
+       return 0;
+}
+
+static int cb710_resume(struct pci_dev *pdev)
+{
+       struct cb710_chip *chip = pci_get_drvdata(pdev);
+       int err;
+
+       pci_set_power_state(pdev, PCI_D0);
+       pci_restore_state(pdev);
+       err = pcim_enable_device(pdev);
+       if (err)
+               return err;
+
+       return devm_request_irq(&pdev->dev, pdev->irq,
+               cb710_irq_handler, IRQF_SHARED, KBUILD_MODNAME, chip);
+}
+
+#endif /* CONFIG_PM */
+
+static int __devinit cb710_probe(struct pci_dev *pdev,
+       const struct pci_device_id *ent)
+{
+       struct cb710_chip *chip;
+       unsigned long flags;
+       u32 val;
+       int err;
+       int n = 0;
+
+       err = cb710_pci_configure(pdev);
+       if (err)
+               return err;
+
+       /* this is actually magic... */
+       pci_read_config_dword(pdev, 0x48, &val);
+       if (!(val & 0x80000000)) {
+               pci_write_config_dword(pdev, 0x48, val|0x71000000);
+               pci_read_config_dword(pdev, 0x48, &val);
+       }
+
+       dev_dbg(&pdev->dev, "PCI config[0x48] = 0x%08X\n", val);
+       if (!(val & 0x70000000))
+               return -ENODEV;
+       val = (val >> 28) & 7;
+       if (val & CB710_SLOT_MMC)
+               ++n;
+       if (val & CB710_SLOT_MS)
+               ++n;
+       if (val & CB710_SLOT_SM)
+               ++n;
+
+       chip = devm_kzalloc(&pdev->dev,
+               sizeof(*chip) + n * sizeof(*chip->slot), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       err = pcim_enable_device(pdev);
+       if (err)
+               return err;
+
+       err = pcim_iomap_regions(pdev, 0x0001, KBUILD_MODNAME);
+       if (err)
+               return err;
+
+       chip->pdev = pdev;
+       chip->iobase = pcim_iomap_table(pdev)[0];
+
+       pci_set_drvdata(pdev, chip);
+
+       err = devm_request_irq(&pdev->dev, pdev->irq,
+               cb710_irq_handler, IRQF_SHARED, KBUILD_MODNAME, chip);
+       if (err)
+               return err;
+
+       do {
+               if (!ida_pre_get(&cb710_ida, GFP_KERNEL))
+                       return -ENOMEM;
+
+               spin_lock_irqsave(&cb710_ida_lock, flags);
+               err = ida_get_new(&cb710_ida, &chip->platform_id);
+               spin_unlock_irqrestore(&cb710_ida_lock, flags);
+
+               if (err && err != -EAGAIN)
+                       return err;
+       } while (err);
+
+
+       dev_info(&pdev->dev, "id %d, IO 0x%p, IRQ %d\n",
+               chip->platform_id, chip->iobase, pdev->irq);
+
+       if (val & CB710_SLOT_MMC) {     /* MMC/SD slot */
+               err = cb710_register_slot(chip,
+                       CB710_SLOT_MMC, 0x00, "cb710-mmc");
+               if (err)
+                       return err;
+       }
+
+       if (val & CB710_SLOT_MS) {      /* MemoryStick slot */
+               err = cb710_register_slot(chip,
+                       CB710_SLOT_MS, 0x40, "cb710-ms");
+               if (err)
+                       goto unreg_mmc;
+       }
+
+       if (val & CB710_SLOT_SM) {      /* SmartMedia slot */
+               err = cb710_register_slot(chip,
+                       CB710_SLOT_SM, 0x60, "cb710-sm");
+               if (err)
+                       goto unreg_ms;
+       }
+
+       return 0;
+unreg_ms:
+       cb710_unregister_slot(chip, CB710_SLOT_MS);
+unreg_mmc:
+       cb710_unregister_slot(chip, CB710_SLOT_MMC);
+
+#ifdef CONFIG_CB710_DEBUG_ASSUMPTIONS
+       BUG_ON(atomic_read(&chip->slot_refs_count) != 0);
+#endif
+       return err;
+}
+
+static void __devexit cb710_remove_one(struct pci_dev *pdev)
+{
+       struct cb710_chip *chip = pci_get_drvdata(pdev);
+       unsigned long flags;
+
+       cb710_unregister_slot(chip, CB710_SLOT_SM);
+       cb710_unregister_slot(chip, CB710_SLOT_MS);
+       cb710_unregister_slot(chip, CB710_SLOT_MMC);
+#ifdef CONFIG_CB710_DEBUG_ASSUMPTIONS
+       BUG_ON(atomic_read(&chip->slot_refs_count) != 0);
+#endif
+
+       spin_lock_irqsave(&cb710_ida_lock, flags);
+       ida_remove(&cb710_ida, chip->platform_id);
+       spin_unlock_irqrestore(&cb710_ida_lock, flags);
+}
+
+static const struct pci_device_id cb710_pci_tbl[] = {
+       { PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_CB710_FLASH,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       { 0, }
+};
+
+static struct pci_driver cb710_driver = {
+       .name = KBUILD_MODNAME,
+       .id_table = cb710_pci_tbl,
+       .probe = cb710_probe,
+       .remove = __devexit_p(cb710_remove_one),
+#ifdef CONFIG_PM
+       .suspend = cb710_suspend,
+       .resume = cb710_resume,
+#endif
+};
+
+static int __init cb710_init_module(void)
+{
+       return pci_register_driver(&cb710_driver);
+}
+
+static void __exit cb710_cleanup_module(void)
+{
+       pci_unregister_driver(&cb710_driver);
+       ida_destroy(&cb710_ida);
+}
+
+module_init(cb710_init_module);
+module_exit(cb710_cleanup_module);
+
+MODULE_AUTHOR("MichaÅ‚ MirosÅ‚aw <mirq-linux@rere.qmqm.pl>");
+MODULE_DESCRIPTION("ENE CB710 memory card reader driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, cb710_pci_tbl);
diff --git a/drivers/misc/cb710/debug.c b/drivers/misc/cb710/debug.c
new file mode 100644 (file)
index 0000000..02358d0
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ *  cb710/debug.c
+ *
+ *  Copyright by MichaÅ‚ MirosÅ‚aw, 2008-2009
+ *
+ * This 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/cb710.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#define CB710_REG_COUNT                0x80
+
+static const u16 allow[CB710_REG_COUNT/16] = {
+       0xFFF0, 0xFFFF, 0xFFFF, 0xFFFF,
+       0xFFF0, 0xFFFF, 0xFFFF, 0xFFFF,
+};
+static const char *const prefix[ARRAY_SIZE(allow)] = {
+       "MMC", "MMC", "MMC", "MMC",
+       "MS?", "MS?", "SM?", "SM?"
+};
+
+static inline int allow_reg_read(unsigned block, unsigned offset, unsigned bits)
+{
+       unsigned mask = (1 << bits/8) - 1;
+       offset *= bits/8;
+       return ((allow[block] >> offset) & mask) == mask;
+}
+
+#define CB710_READ_REGS_TEMPLATE(t)                                    \
+static void cb710_read_regs_##t(void __iomem *iobase,                  \
+       u##t *reg, unsigned select)                                     \
+{                                                                      \
+       unsigned i, j;                                                  \
+                                                                       \
+       for (i = 0; i < ARRAY_SIZE(allow); ++i, reg += 16/(t/8)) {      \
+               if (!(select & (1 << i)))                                       \
+                       continue;                                       \
+                                                                       \
+               for (j = 0; j < 0x10/(t/8); ++j) {                      \
+                       if (!allow_reg_read(i, j, t))                   \
+                               continue;                               \
+                       reg[j] = ioread##t(iobase                       \
+                               + (i << 4) + (j * (t/8)));              \
+               }                                                       \
+       }                                                               \
+}
+
+static const char cb710_regf_8[] = "%02X";
+static const char cb710_regf_16[] = "%04X";
+static const char cb710_regf_32[] = "%08X";
+static const char cb710_xes[] = "xxxxxxxx";
+
+#define CB710_DUMP_REGS_TEMPLATE(t)                                    \
+static void cb710_dump_regs_##t(struct device *dev,                    \
+       const u##t *reg, unsigned select)                               \
+{                                                                      \
+       const char *const xp = &cb710_xes[8 - t/4];                     \
+       const char *const format = cb710_regf_##t;                      \
+                                                                       \
+       char msg[100], *p;                                              \
+       unsigned i, j;                                                  \
+                                                                       \
+       for (i = 0; i < ARRAY_SIZE(allow); ++i, reg += 16/(t/8)) {      \
+               if (!(select & (1 << i)))                               \
+                       continue;                                       \
+               p = msg;                                                \
+               for (j = 0; j < 0x10/(t/8); ++j) {                      \
+                       *p++ = ' ';                                     \
+                       if (j == 8/(t/8))                               \
+                               *p++ = ' ';                             \
+                       if (allow_reg_read(i, j, t))                    \
+                               p += sprintf(p, format, reg[j]);        \
+                       else                                            \
+                               p += sprintf(p, "%s", xp);              \
+               }                                                       \
+               dev_dbg(dev, "%s 0x%02X %s\n", prefix[i], i << 4, msg); \
+       }                                                               \
+}
+
+#define CB710_READ_AND_DUMP_REGS_TEMPLATE(t)                           \
+static void cb710_read_and_dump_regs_##t(struct cb710_chip *chip,      \
+       unsigned select)                                                \
+{                                                                      \
+       u##t regs[CB710_REG_COUNT/sizeof(u##t)];                        \
+                                                                       \
+       memset(&regs, 0, sizeof(regs));                                 \
+       cb710_read_regs_##t(chip->iobase, regs, select);                \
+       cb710_dump_regs_##t(cb710_chip_dev(chip), regs, select);        \
+}
+
+#define CB710_REG_ACCESS_TEMPLATES(t)          \
+  CB710_READ_REGS_TEMPLATE(t)                  \
+  CB710_DUMP_REGS_TEMPLATE(t)                  \
+  CB710_READ_AND_DUMP_REGS_TEMPLATE(t)
+
+CB710_REG_ACCESS_TEMPLATES(8)
+CB710_REG_ACCESS_TEMPLATES(16)
+CB710_REG_ACCESS_TEMPLATES(32)
+
+void cb710_dump_regs(struct cb710_chip *chip, unsigned select)
+{
+       if (!(select & CB710_DUMP_REGS_MASK))
+               select = CB710_DUMP_REGS_ALL;
+       if (!(select & CB710_DUMP_ACCESS_MASK))
+               select |= CB710_DUMP_ACCESS_8;
+
+       if (select & CB710_DUMP_ACCESS_32)
+               cb710_read_and_dump_regs_32(chip, select);
+       if (select & CB710_DUMP_ACCESS_16)
+               cb710_read_and_dump_regs_16(chip, select);
+       if (select & CB710_DUMP_ACCESS_8)
+               cb710_read_and_dump_regs_8(chip, select);
+}
+EXPORT_SYMBOL_GPL(cb710_dump_regs);
+
diff --git a/drivers/misc/cb710/sgbuf2.c b/drivers/misc/cb710/sgbuf2.c
new file mode 100644 (file)
index 0000000..d38a7ac
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ *  cb710/sgbuf2.c
+ *
+ *  Copyright by MichaÅ‚ MirosÅ‚aw, 2008-2009
+ *
+ * This 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/cb710.h>
+
+static bool sg_dwiter_next(struct sg_mapping_iter *miter)
+{
+       if (sg_miter_next(miter)) {
+               miter->consumed = 0;
+               return true;
+       } else
+               return false;
+}
+
+static bool sg_dwiter_is_at_end(struct sg_mapping_iter *miter)
+{
+       return miter->length == miter->consumed && !sg_dwiter_next(miter);
+}
+
+static uint32_t sg_dwiter_read_buffer(struct sg_mapping_iter *miter)
+{
+       size_t len, left = 4;
+       uint32_t data;
+       void *addr = &data;
+
+       do {
+               len = min(miter->length - miter->consumed, left);
+               memcpy(addr, miter->addr + miter->consumed, len);
+               miter->consumed += len;
+               left -= len;
+               if (!left)
+                       return data;
+               addr += len;
+       } while (sg_dwiter_next(miter));
+
+       memset(addr, 0, left);
+       return data;
+}
+
+static inline bool needs_unaligned_copy(const void *ptr)
+{
+#ifdef HAVE_EFFICIENT_UNALIGNED_ACCESS
+       return false;
+#else
+       return ((ptr - NULL) & 3) != 0;
+#endif
+}
+
+static bool sg_dwiter_get_next_block(struct sg_mapping_iter *miter, uint32_t **ptr)
+{
+       size_t len;
+
+       if (sg_dwiter_is_at_end(miter))
+               return true;
+
+       len = miter->length - miter->consumed;
+
+       if (likely(len >= 4 && !needs_unaligned_copy(
+                       miter->addr + miter->consumed))) {
+               *ptr = miter->addr + miter->consumed;
+               miter->consumed += 4;
+               return true;
+       }
+
+       return false;
+}
+
+/**
+ * cb710_sg_dwiter_read_next_block() - get next 32-bit word from sg buffer
+ * @miter: sg mapping iterator used for reading
+ *
+ * Description:
+ *   Returns 32-bit word starting at byte pointed to by @miter@
+ *   handling any alignment issues.  Bytes past the buffer's end
+ *   are not accessed (read) but are returned as zeroes.  @miter@
+ *   is advanced by 4 bytes or to the end of buffer whichever is
+ *   closer.
+ *
+ * Context:
+ *   Same requirements as in sg_miter_next().
+ *
+ * Returns:
+ *   32-bit word just read.
+ */
+uint32_t cb710_sg_dwiter_read_next_block(struct sg_mapping_iter *miter)
+{
+       uint32_t *ptr = NULL;
+
+       if (likely(sg_dwiter_get_next_block(miter, &ptr)))
+               return ptr ? *ptr : 0;
+
+       return sg_dwiter_read_buffer(miter);
+}
+EXPORT_SYMBOL_GPL(cb710_sg_dwiter_read_next_block);
+
+static void sg_dwiter_write_slow(struct sg_mapping_iter *miter, uint32_t data)
+{
+       size_t len, left = 4;
+       void *addr = &data;
+
+       do {
+               len = min(miter->length - miter->consumed, left);
+               memcpy(miter->addr, addr, len);
+               miter->consumed += len;
+               left -= len;
+               if (!left)
+                       return;
+               addr += len;
+               flush_kernel_dcache_page(miter->page);
+       } while (sg_dwiter_next(miter));
+}
+
+/**
+ * cb710_sg_dwiter_write_next_block() - write next 32-bit word to sg buffer
+ * @miter: sg mapping iterator used for writing
+ *
+ * Description:
+ *   Writes 32-bit word starting at byte pointed to by @miter@
+ *   handling any alignment issues.  Bytes which would be written
+ *   past the buffer's end are silently discarded. @miter@ is
+ *   advanced by 4 bytes or to the end of buffer whichever is closer.
+ *
+ * Context:
+ *   Same requirements as in sg_miter_next().
+ */
+void cb710_sg_dwiter_write_next_block(struct sg_mapping_iter *miter, uint32_t data)
+{
+       uint32_t *ptr = NULL;
+
+       if (likely(sg_dwiter_get_next_block(miter, &ptr))) {
+               if (ptr)
+                       *ptr = data;
+               else
+                       return;
+       } else
+               sg_dwiter_write_slow(miter, data);
+
+       if (miter->length == miter->consumed)
+               flush_kernel_dcache_page(miter->page);
+}
+EXPORT_SYMBOL_GPL(cb710_sg_dwiter_write_next_block);
+
index 98ffc41eaf2c631bebdfed37a9847b17f28b97cd..adc205c49fbf1e2b6541aad793addc20fd40dab8 100644 (file)
@@ -147,7 +147,8 @@ struct mmc_blk_request {
 static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
 {
        int err;
-       __be32 blocks;
+       u32 result;
+       __be32 *blocks;
 
        struct mmc_request mrq;
        struct mmc_command cmd;
@@ -199,14 +200,21 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
        mrq.cmd = &cmd;
        mrq.data = &data;
 
-       sg_init_one(&sg, &blocks, 4);
+       blocks = kmalloc(4, GFP_KERNEL);
+       if (!blocks)
+               return (u32)-1;
+
+       sg_init_one(&sg, blocks, 4);
 
        mmc_wait_for_req(card->host, &mrq);
 
+       result = ntohl(*blocks);
+       kfree(blocks);
+
        if (cmd.error || data.error)
-               return (u32)-1;
+               result = (u32)-1;
 
-       return ntohl(blocks);
+       return result;
 }
 
 static u32 get_card_status(struct mmc_card *card, struct request *req)
index 26491173275619fa75544a1992ba79eaf1ed963a..d84c880fac84f41a0d388540d74d22a4a7649705 100644 (file)
@@ -708,7 +708,13 @@ static void mmc_power_up(struct mmc_host *host)
         */
        mmc_delay(10);
 
-       host->ios.clock = host->f_min;
+       if (host->f_min > 400000) {
+               pr_warning("%s: Minimum clock frequency too high for "
+                               "identification mode\n", mmc_hostname(host));
+               host->ios.clock = host->f_min;
+       } else
+               host->ios.clock = 400000;
+
        host->ios.power_mode = MMC_POWER_ON;
        mmc_set_ios(host);
 
@@ -855,61 +861,72 @@ void mmc_rescan(struct work_struct *work)
 
        mmc_bus_get(host);
 
-       if (host->bus_ops == NULL) {
-               /*
-                * Only we can add a new handler, so it's safe to
-                * release the lock here.
-                */
+       /* if there is a card registered, check whether it is still present */
+       if ((host->bus_ops != NULL) && host->bus_ops->detect && !host->bus_dead)
+               host->bus_ops->detect(host);
+
+       mmc_bus_put(host);
+
+
+       mmc_bus_get(host);
+
+       /* if there still is a card present, stop here */
+       if (host->bus_ops != NULL) {
                mmc_bus_put(host);
+               goto out;
+       }
 
-               if (host->ops->get_cd && host->ops->get_cd(host) == 0)
-                       goto out;
+       /* detect a newly inserted card */
 
-               mmc_claim_host(host);
+       /*
+        * Only we can add a new handler, so it's safe to
+        * release the lock here.
+        */
+       mmc_bus_put(host);
 
-               mmc_power_up(host);
-               mmc_go_idle(host);
+       if (host->ops->get_cd && host->ops->get_cd(host) == 0)
+               goto out;
 
-               mmc_send_if_cond(host, host->ocr_avail);
+       mmc_claim_host(host);
 
-               /*
-                * First we search for SDIO...
-                */
-               err = mmc_send_io_op_cond(host, 0, &ocr);
-               if (!err) {
-                       if (mmc_attach_sdio(host, ocr))
-                               mmc_power_off(host);
-                       goto out;
-               }
+       mmc_power_up(host);
+       mmc_go_idle(host);
 
-               /*
-                * ...then normal SD...
-                */
-               err = mmc_send_app_op_cond(host, 0, &ocr);
-               if (!err) {
-                       if (mmc_attach_sd(host, ocr))
-                               mmc_power_off(host);
-                       goto out;
-               }
+       mmc_send_if_cond(host, host->ocr_avail);
 
-               /*
-                * ...and finally MMC.
-                */
-               err = mmc_send_op_cond(host, 0, &ocr);
-               if (!err) {
-                       if (mmc_attach_mmc(host, ocr))
-                               mmc_power_off(host);
-                       goto out;
-               }
+       /*
+        * First we search for SDIO...
+        */
+       err = mmc_send_io_op_cond(host, 0, &ocr);
+       if (!err) {
+               if (mmc_attach_sdio(host, ocr))
+                       mmc_power_off(host);
+               goto out;
+       }
 
-               mmc_release_host(host);
-               mmc_power_off(host);
-       } else {
-               if (host->bus_ops->detect && !host->bus_dead)
-                       host->bus_ops->detect(host);
+       /*
+        * ...then normal SD...
+        */
+       err = mmc_send_app_op_cond(host, 0, &ocr);
+       if (!err) {
+               if (mmc_attach_sd(host, ocr))
+                       mmc_power_off(host);
+               goto out;
+       }
 
-               mmc_bus_put(host);
+       /*
+        * ...and finally MMC.
+        */
+       err = mmc_send_op_cond(host, 0, &ocr);
+       if (!err) {
+               if (mmc_attach_mmc(host, ocr))
+                       mmc_power_off(host);
+               goto out;
        }
+
+       mmc_release_host(host);
+       mmc_power_off(host);
+
 out:
        if (host->caps & MMC_CAP_NEEDS_POLL)
                mmc_schedule_delayed_work(&host->detect, HZ);
index b4cf691f3f64ec9cdbbc2792d32ae35bbf37bbfe..40111a6d8d5bc791e00fcdb315f6d2384dc46cfb 100644 (file)
@@ -83,6 +83,17 @@ config MMC_SDHCI_OF
 
          If unsure, say N.
 
+config MMC_SDHCI_PLTFM
+       tristate "SDHCI support on the platform specific bus"
+       depends on MMC_SDHCI
+       help
+         This selects the platform specific bus support for Secure Digital Host
+         Controller Interface.
+
+         If you have a controller with this interface, say Y or M here.
+
+         If unsure, say N.
+
 config MMC_OMAP
        tristate "TI OMAP Multimedia Card Interface support"
        depends on ARCH_OMAP
@@ -155,7 +166,7 @@ config MMC_ATMELMCI_DMA
 
 config MMC_IMX
        tristate "Motorola i.MX Multimedia Card Interface support"
-       depends on ARCH_IMX
+       depends on ARCH_MX1
        help
          This selects the Motorola i.MX Multimedia card Interface.
          If you have a i.MX platform with a Multimedia Card slot,
@@ -237,7 +248,20 @@ config MMC_SDRICOH_CS
 
 config MMC_TMIO
        tristate "Toshiba Mobile IO Controller (TMIO) MMC/SD function support"
-       depends on MFD_TMIO
+       depends on MFD_TMIO || MFD_ASIC3
        help
          This provides support for the SD/MMC cell found in TC6393XB,
-         T7L66XB and also ipaq ASIC3
+         T7L66XB and also HTC ASIC3
+
+config MMC_CB710
+       tristate "ENE CB710 MMC/SD Interface support"
+       depends on PCI
+       select CB710_CORE
+       help
+         This option enables support for MMC/SD part of ENE CB710/720 Flash
+         memory card reader found in some laptops (ie. some versions of
+         HP Compaq nx9500).
+
+         This driver can also be built as a module. If so, the module
+         will be called cb710-mmc.
+
index 970a997620e1ad3c72838c05c68e39b16548b966..79da397c5fea191ccc76dc29b1a7b6f76c499821 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_MMC_SDHCI)               += sdhci.o
 obj-$(CONFIG_MMC_SDHCI_PCI)    += sdhci-pci.o
 obj-$(CONFIG_MMC_RICOH_MMC)    += ricoh_mmc.o
 obj-$(CONFIG_MMC_SDHCI_OF)     += sdhci-of.o
+obj-$(CONFIG_MMC_SDHCI_PLTFM)  += sdhci-pltfm.o
 obj-$(CONFIG_MMC_WBSD)         += wbsd.o
 obj-$(CONFIG_MMC_AU1X)         += au1xmmc.o
 obj-$(CONFIG_MMC_OMAP)         += omap.o
@@ -29,4 +30,8 @@ endif
 obj-$(CONFIG_MMC_S3C)          += s3cmci.o
 obj-$(CONFIG_MMC_SDRICOH_CS)   += sdricoh_cs.o
 obj-$(CONFIG_MMC_TMIO)         += tmio_mmc.o
+obj-$(CONFIG_MMC_CB710)        += cb710-mmc.o
 
+ifeq ($(CONFIG_CB710_DEBUG),y)
+       CFLAGS-cb710-mmc        += -DDEBUG
+endif
index b58364ed6bba7e487d4bf772e433b259a22933c5..fc8a0fe7c5c57b1fbf3282733b285c7da40aaf8f 100644 (file)
@@ -7,6 +7,12 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+
+/*
+ * Superset of MCI IP registers integrated in Atmel AVR32 and AT91 Processors
+ * Registers and bitfields marked with [2] are only available in MCI2
+ */
+
 #ifndef __DRIVERS_MMC_ATMEL_MCI_H__
 #define __DRIVERS_MMC_ATMEL_MCI_H__
 
 #define MCI_CR                 0x0000  /* Control */
 # define MCI_CR_MCIEN          (  1 <<  0)     /* MCI Enable */
 # define MCI_CR_MCIDIS         (  1 <<  1)     /* MCI Disable */
+# define MCI_CR_PWSEN          (  1 <<  2)     /* Power Save Enable */
+# define MCI_CR_PWSDIS         (  1 <<  3)     /* Power Save Disable */
 # define MCI_CR_SWRST          (  1 <<  7)     /* Software Reset */
 #define MCI_MR                 0x0004  /* Mode */
 # define MCI_MR_CLKDIV(x)      ((x) <<  0)     /* Clock Divider */
+# define MCI_MR_PWSDIV(x)      ((x) <<  8)     /* Power Saving Divider */
 # define MCI_MR_RDPROOF                (  1 << 11)     /* Read Proof */
 # define MCI_MR_WRPROOF                (  1 << 12)     /* Write Proof */
+# define MCI_MR_PDCFBYTE       (  1 << 13)     /* Force Byte Transfer */
+# define MCI_MR_PDCPADV                (  1 << 14)     /* Padding Value */
+# define MCI_MR_PDCMODE                (  1 << 15)     /* PDC-oriented Mode */
 #define MCI_DTOR               0x0008  /* Data Timeout */
 # define MCI_DTOCYC(x)         ((x) <<  0)     /* Data Timeout Cycles */
 # define MCI_DTOMUL(x)         ((x) <<  4)     /* Data Timeout Multiplier */
@@ -28,6 +40,7 @@
 # define MCI_SDCSEL_MASK       (  3 <<  0)
 # define MCI_SDCBUS_1BIT       (  0 <<  6)     /* 1-bit data bus */
 # define MCI_SDCBUS_4BIT       (  2 <<  6)     /* 4-bit data bus */
+# define MCI_SDCBUS_8BIT       (  3 <<  6)     /* 8-bit data bus[2] */
 # define MCI_SDCBUS_MASK       (  3 <<  6)
 #define MCI_ARGR               0x0010  /* Command Argument */
 #define MCI_CMDR               0x0014  /* Command */
@@ -56,6 +69,9 @@
 #define MCI_BLKR               0x0018  /* Block */
 # define MCI_BCNT(x)           ((x) <<  0)     /* Data Block Count */
 # define MCI_BLKLEN(x)         ((x) << 16)     /* Data Block Length */
+#define MCI_CSTOR              0x001c  /* Completion Signal Timeout[2] */
+# define MCI_CSTOCYC(x)                ((x) <<  0)     /* CST cycles */
+# define MCI_CSTOMUL(x)                ((x) <<  4)     /* CST multiplier */
 #define MCI_RSPR               0x0020  /* Response 0 */
 #define MCI_RSPR1              0x0024  /* Response 1 */
 #define MCI_RSPR2              0x0028  /* Response 2 */
 # define MCI_DTOE              (  1 <<  22)    /* Data Time-Out Error */
 # define MCI_OVRE              (  1 <<  30)    /* RX Overrun Error */
 # define MCI_UNRE              (  1 <<  31)    /* TX Underrun Error */
+#define MCI_DMA                        0x0050  /* DMA Configuration[2] */
+# define MCI_DMA_OFFSET(x)     ((x) <<  0)     /* DMA Write Buffer Offset */
+# define MCI_DMA_CHKSIZE(x)    ((x) <<  4)     /* DMA Channel Read and Write Chunk Size */
+# define MCI_DMAEN             (  1 <<  8)     /* DMA Hardware Handshaking Enable */
+#define MCI_CFG                        0x0054  /* Configuration[2] */
+# define MCI_CFG_FIFOMODE_1DATA        (  1 <<  0)     /* MCI Internal FIFO control mode */
+# define MCI_CFG_FERRCTRL_COR  (  1 <<  4)     /* Flow Error flag reset control mode */
+# define MCI_CFG_HSMODE                (  1 <<  8)     /* High Speed Mode */
+# define MCI_CFG_LSYNC         (  1 << 12)     /* Synchronize on the last block */
+#define MCI_WPMR               0x00e4  /* Write Protection Mode[2] */
+# define MCI_WP_EN             (  1 <<  0)     /* WP Enable */
+# define MCI_WP_KEY            (0x4d4349 << 8) /* WP Key */
+#define MCI_WPSR               0x00e8  /* Write Protection Status[2] */
+# define MCI_GET_WP_VS(x)      ((x) & 0x0f)
+# define MCI_GET_WP_VSRC(x)    (((x) >> 8) & 0xffff)
+#define MCI_FIFO_APERTURE      0x0200  /* FIFO Aperture[2] */
 
+/* This is not including the FIFO Aperture on MCI2 */
 #define MCI_REGS_SIZE          0x100
 
 /* Register access macros */
index cf6a100bb38ff99a4fb56588ab3eb9b84ee7cf87..7b603e4b41dbe9eb60a03e2dd57a13d47f64d94d 100644 (file)
@@ -177,6 +177,7 @@ struct atmel_mci {
  *     available.
  * @wp_pin: GPIO pin used for card write protect sending, or negative
  *     if not available.
+ * @detect_is_active_high: The state of the detect pin when it is active.
  * @detect_timer: Timer used for debouncing @detect_pin interrupts.
  */
 struct atmel_mci_slot {
@@ -196,6 +197,7 @@ struct atmel_mci_slot {
 
        int                     detect_pin;
        int                     wp_pin;
+       bool                    detect_is_active_high;
 
        struct timer_list       detect_timer;
 };
@@ -924,7 +926,8 @@ static int atmci_get_cd(struct mmc_host *mmc)
        struct atmel_mci_slot   *slot = mmc_priv(mmc);
 
        if (gpio_is_valid(slot->detect_pin)) {
-               present = !gpio_get_value(slot->detect_pin);
+               present = !(gpio_get_value(slot->detect_pin) ^
+                           slot->detect_is_active_high);
                dev_dbg(&mmc->class_dev, "card is %spresent\n",
                                present ? "" : "not ");
        }
@@ -1028,7 +1031,8 @@ static void atmci_detect_change(unsigned long data)
                return;
 
        enable_irq(gpio_to_irq(slot->detect_pin));
-       present = !gpio_get_value(slot->detect_pin);
+       present = !(gpio_get_value(slot->detect_pin) ^
+                   slot->detect_is_active_high);
        present_old = test_bit(ATMCI_CARD_PRESENT, &slot->flags);
 
        dev_vdbg(&slot->mmc->class_dev, "detect change: %d (was %d)\n",
@@ -1456,6 +1460,7 @@ static int __init atmci_init_slot(struct atmel_mci *host,
        slot->host = host;
        slot->detect_pin = slot_data->detect_pin;
        slot->wp_pin = slot_data->wp_pin;
+       slot->detect_is_active_high = slot_data->detect_is_active_high;
        slot->sdc_reg = sdc_reg;
 
        mmc->ops = &atmci_ops;
@@ -1477,7 +1482,8 @@ static int __init atmci_init_slot(struct atmel_mci *host,
                if (gpio_request(slot->detect_pin, "mmc_detect")) {
                        dev_dbg(&mmc->class_dev, "no detect pin available\n");
                        slot->detect_pin = -EBUSY;
-               } else if (gpio_get_value(slot->detect_pin)) {
+               } else if (gpio_get_value(slot->detect_pin) ^
+                               slot->detect_is_active_high) {
                        clear_bit(ATMCI_CARD_PRESENT, &slot->flags);
                }
        }
diff --git a/drivers/mmc/host/cb710-mmc.c b/drivers/mmc/host/cb710-mmc.c
new file mode 100644 (file)
index 0000000..11efefb
--- /dev/null
@@ -0,0 +1,804 @@
+/*
+ *  cb710/mmc.c
+ *
+ *  Copyright by MichaÅ‚ MirosÅ‚aw, 2008-2009
+ *
+ * This 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/slab.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include "cb710-mmc.h"
+
+static const u8 cb710_clock_divider_log2[8] = {
+/*     1, 2, 4, 8, 16, 32, 128, 512 */
+       0, 1, 2, 3,  4,  5,   7,   9
+};
+#define CB710_MAX_DIVIDER_IDX  \
+       (ARRAY_SIZE(cb710_clock_divider_log2) - 1)
+
+static const u8 cb710_src_freq_mhz[16] = {
+       33, 10, 20, 25, 30, 35, 40, 45,
+       50, 55, 60, 65, 70, 75, 80, 85
+};
+
+static void cb710_mmc_set_clock(struct mmc_host *mmc, int hz)
+{
+       struct cb710_slot *slot = cb710_mmc_to_slot(mmc);
+       struct pci_dev *pdev = cb710_slot_to_chip(slot)->pdev;
+       u32 src_freq_idx;
+       u32 divider_idx;
+       int src_hz;
+
+       /* this is magic, unverifiable for me, unless I get
+        * MMC card with cables connected to bus signals */
+       pci_read_config_dword(pdev, 0x48, &src_freq_idx);
+       src_freq_idx = (src_freq_idx >> 16) & 0xF;
+       src_hz = cb710_src_freq_mhz[src_freq_idx] * 1000000;
+
+       for (divider_idx = 0; divider_idx < CB710_MAX_DIVIDER_IDX; ++divider_idx) {
+               if (hz >= src_hz >> cb710_clock_divider_log2[divider_idx])
+                       break;
+       }
+
+       if (src_freq_idx)
+               divider_idx |= 0x8;
+
+       cb710_pci_update_config_reg(pdev, 0x40, ~0xF0000000, divider_idx << 28);
+
+       dev_dbg(cb710_slot_dev(slot),
+               "clock set to %d Hz, wanted %d Hz; flag = %d\n",
+               src_hz >> cb710_clock_divider_log2[divider_idx & 7],
+               hz, (divider_idx & 8) != 0);
+}
+
+static void __cb710_mmc_enable_irq(struct cb710_slot *slot,
+       unsigned short enable, unsigned short mask)
+{
+       /* clear global IE
+        * - it gets set later if any interrupt sources are enabled */
+       mask |= CB710_MMC_IE_IRQ_ENABLE;
+
+       /* look like interrupt is fired whenever
+        * WORD[0x0C] & WORD[0x10] != 0;
+        * -> bit 15 port 0x0C seems to be global interrupt enable
+        */
+
+       enable = (cb710_read_port_16(slot, CB710_MMC_IRQ_ENABLE_PORT)
+               & ~mask) | enable;
+
+       if (enable)
+               enable |= CB710_MMC_IE_IRQ_ENABLE;
+
+       cb710_write_port_16(slot, CB710_MMC_IRQ_ENABLE_PORT, enable);
+}
+
+static void cb710_mmc_enable_irq(struct cb710_slot *slot,
+       unsigned short enable, unsigned short mask)
+{
+       struct cb710_mmc_reader *reader = mmc_priv(cb710_slot_to_mmc(slot));
+       unsigned long flags;
+
+       spin_lock_irqsave(&reader->irq_lock, flags);
+       /* this is the only thing irq_lock protects */
+       __cb710_mmc_enable_irq(slot, enable, mask);
+       spin_unlock_irqrestore(&reader->irq_lock, flags);
+}
+
+static void cb710_mmc_reset_events(struct cb710_slot *slot)
+{
+       cb710_write_port_8(slot, CB710_MMC_STATUS0_PORT, 0xFF);
+       cb710_write_port_8(slot, CB710_MMC_STATUS1_PORT, 0xFF);
+       cb710_write_port_8(slot, CB710_MMC_STATUS2_PORT, 0xFF);
+}
+
+static int cb710_mmc_is_card_inserted(struct cb710_slot *slot)
+{
+       return cb710_read_port_8(slot, CB710_MMC_STATUS3_PORT)
+               & CB710_MMC_S3_CARD_DETECTED;
+}
+
+static void cb710_mmc_enable_4bit_data(struct cb710_slot *slot, int enable)
+{
+       dev_dbg(cb710_slot_dev(slot), "configuring %d-data-line%s mode\n",
+               enable ? 4 : 1, enable ? "s" : "");
+       if (enable)
+               cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT,
+                       CB710_MMC_C1_4BIT_DATA_BUS, 0);
+       else
+               cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT,
+                       0, CB710_MMC_C1_4BIT_DATA_BUS);
+}
+
+static int cb710_check_event(struct cb710_slot *slot, u8 what)
+{
+       u16 status;
+
+       status = cb710_read_port_16(slot, CB710_MMC_STATUS_PORT);
+
+       if (status & CB710_MMC_S0_FIFO_UNDERFLOW) {
+               /* it is just a guess, so log it */
+               dev_dbg(cb710_slot_dev(slot),
+                       "CHECK : ignoring bit 6 in status %04X\n", status);
+               cb710_write_port_8(slot, CB710_MMC_STATUS0_PORT,
+                       CB710_MMC_S0_FIFO_UNDERFLOW);
+               status &= ~CB710_MMC_S0_FIFO_UNDERFLOW;
+       }
+
+       if (status & CB710_MMC_STATUS_ERROR_EVENTS) {
+               dev_dbg(cb710_slot_dev(slot),
+                       "CHECK : returning EIO on status %04X\n", status);
+               cb710_write_port_8(slot, CB710_MMC_STATUS0_PORT, status & 0xFF);
+               cb710_write_port_8(slot, CB710_MMC_STATUS1_PORT,
+                       CB710_MMC_S1_RESET);
+               return -EIO;
+       }
+
+       /* 'what' is a bit in MMC_STATUS1 */
+       if ((status >> 8) & what) {
+               cb710_write_port_8(slot, CB710_MMC_STATUS1_PORT, what);
+               return 1;
+       }
+
+       return 0;
+}
+
+static int cb710_wait_for_event(struct cb710_slot *slot, u8 what)
+{
+       int err = 0;
+       unsigned limit = 2000000;       /* FIXME: real timeout */
+
+#ifdef CONFIG_CB710_DEBUG
+       u32 e, x;
+       e = cb710_read_port_32(slot, CB710_MMC_STATUS_PORT);
+#endif
+
+       while (!(err = cb710_check_event(slot, what))) {
+               if (!--limit) {
+                       cb710_dump_regs(cb710_slot_to_chip(slot),
+                               CB710_DUMP_REGS_MMC);
+                       err = -ETIMEDOUT;
+                       break;
+               }
+               udelay(1);
+       }
+
+#ifdef CONFIG_CB710_DEBUG
+       x = cb710_read_port_32(slot, CB710_MMC_STATUS_PORT);
+
+       limit = 2000000 - limit;
+       if (limit > 100)
+               dev_dbg(cb710_slot_dev(slot),
+                       "WAIT10: waited %d loops, what %d, entry val %08X, exit val %08X\n",
+                       limit, what, e, x);
+#endif
+       return err < 0 ? err : 0;
+}
+
+
+static int cb710_wait_while_busy(struct cb710_slot *slot, uint8_t mask)
+{
+       unsigned limit = 500000;        /* FIXME: real timeout */
+       int err = 0;
+
+#ifdef CONFIG_CB710_DEBUG
+       u32 e, x;
+       e = cb710_read_port_32(slot, CB710_MMC_STATUS_PORT);
+#endif
+
+       while (cb710_read_port_8(slot, CB710_MMC_STATUS2_PORT) & mask) {
+               if (!--limit) {
+                       cb710_dump_regs(cb710_slot_to_chip(slot),
+                               CB710_DUMP_REGS_MMC);
+                       err = -ETIMEDOUT;
+                       break;
+               }
+               udelay(1);
+       }
+
+#ifdef CONFIG_CB710_DEBUG
+       x = cb710_read_port_32(slot, CB710_MMC_STATUS_PORT);
+
+       limit = 500000 - limit;
+       if (limit > 100)
+               dev_dbg(cb710_slot_dev(slot),
+                       "WAIT12: waited %d loops, mask %02X, entry val %08X, exit val %08X\n",
+                       limit, mask, e, x);
+#endif
+       return 0;
+}
+
+static void cb710_mmc_set_transfer_size(struct cb710_slot *slot,
+       size_t count, size_t blocksize)
+{
+       cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20);
+       cb710_write_port_32(slot, CB710_MMC_TRANSFER_SIZE_PORT,
+               ((count - 1) << 16)|(blocksize - 1));
+
+       dev_vdbg(cb710_slot_dev(slot), "set up for %zu block%s of %zu bytes\n",
+               count, count == 1 ? "" : "s", blocksize);
+}
+
+static void cb710_mmc_fifo_hack(struct cb710_slot *slot)
+{
+       /* without this, received data is prepended with 8-bytes of zeroes */
+       u32 r1, r2;
+       int ok = 0;
+
+       r1 = cb710_read_port_32(slot, CB710_MMC_DATA_PORT);
+       r2 = cb710_read_port_32(slot, CB710_MMC_DATA_PORT);
+       if (cb710_read_port_8(slot, CB710_MMC_STATUS0_PORT)
+           & CB710_MMC_S0_FIFO_UNDERFLOW) {
+               cb710_write_port_8(slot, CB710_MMC_STATUS0_PORT,
+                       CB710_MMC_S0_FIFO_UNDERFLOW);
+               ok = 1;
+       }
+
+       dev_dbg(cb710_slot_dev(slot),
+               "FIFO-read-hack: expected STATUS0 bit was %s\n",
+               ok ? "set." : "NOT SET!");
+       dev_dbg(cb710_slot_dev(slot),
+               "FIFO-read-hack: dwords ignored: %08X %08X - %s\n",
+               r1, r2, (r1|r2) ? "BAD (NOT ZERO)!" : "ok");
+}
+
+static int cb710_mmc_receive_pio(struct cb710_slot *slot,
+       struct sg_mapping_iter *miter, size_t dw_count)
+{
+       if (!(cb710_read_port_8(slot, CB710_MMC_STATUS2_PORT) & CB710_MMC_S2_FIFO_READY)) {
+               int err = cb710_wait_for_event(slot,
+                       CB710_MMC_S1_PIO_TRANSFER_DONE);
+               if (err)
+                       return err;
+       }
+
+       cb710_sg_dwiter_write_from_io(miter,
+               slot->iobase + CB710_MMC_DATA_PORT, dw_count);
+
+       return 0;
+}
+
+static bool cb710_is_transfer_size_supported(struct mmc_data *data)
+{
+       return !(data->blksz & 15 && (data->blocks != 1 || data->blksz != 8));
+}
+
+static int cb710_mmc_receive(struct cb710_slot *slot, struct mmc_data *data)
+{
+       struct sg_mapping_iter miter;
+       size_t len, blocks = data->blocks;
+       int err = 0;
+
+       /* TODO: I don't know how/if the hardware handles non-16B-boundary blocks
+        * except single 8B block */
+       if (unlikely(data->blksz & 15 && (data->blocks != 1 || data->blksz != 8)))
+               return -EINVAL;
+
+       sg_miter_start(&miter, data->sg, data->sg_len, 0);
+
+       cb710_modify_port_8(slot, CB710_MMC_CONFIG2_PORT,
+               15, CB710_MMC_C2_READ_PIO_SIZE_MASK);
+
+       cb710_mmc_fifo_hack(slot);
+
+       while (blocks-- > 0) {
+               len = data->blksz;
+
+               while (len >= 16) {
+                       err = cb710_mmc_receive_pio(slot, &miter, 4);
+                       if (err)
+                               goto out;
+                       len -= 16;
+               }
+
+               if (!len)
+                       continue;
+
+               cb710_modify_port_8(slot, CB710_MMC_CONFIG2_PORT,
+                       len - 1, CB710_MMC_C2_READ_PIO_SIZE_MASK);
+
+               len = (len >= 8) ? 4 : 2;
+               err = cb710_mmc_receive_pio(slot, &miter, len);
+               if (err)
+                       goto out;
+       }
+out:
+       cb710_sg_miter_stop_writing(&miter);
+       return err;
+}
+
+static int cb710_mmc_send(struct cb710_slot *slot, struct mmc_data *data)
+{
+       struct sg_mapping_iter miter;
+       size_t len, blocks = data->blocks;
+       int err = 0;
+
+       /* TODO: I don't know how/if the hardware handles multiple
+        * non-16B-boundary blocks */
+       if (unlikely(data->blocks > 1 && data->blksz & 15))
+               return -EINVAL;
+
+       sg_miter_start(&miter, data->sg, data->sg_len, 0);
+
+       cb710_modify_port_8(slot, CB710_MMC_CONFIG2_PORT,
+               0, CB710_MMC_C2_READ_PIO_SIZE_MASK);
+
+       while (blocks-- > 0) {
+               len = (data->blksz + 15) >> 4;
+               do {
+                       if (!(cb710_read_port_8(slot, CB710_MMC_STATUS2_PORT)
+                           & CB710_MMC_S2_FIFO_EMPTY)) {
+                               err = cb710_wait_for_event(slot,
+                                       CB710_MMC_S1_PIO_TRANSFER_DONE);
+                               if (err)
+                                       goto out;
+                       }
+                       cb710_sg_dwiter_read_to_io(&miter,
+                               slot->iobase + CB710_MMC_DATA_PORT, 4);
+               } while (--len);
+       }
+out:
+       sg_miter_stop(&miter);
+       return err;
+}
+
+static u16 cb710_encode_cmd_flags(struct cb710_mmc_reader *reader,
+       struct mmc_command *cmd)
+{
+       unsigned int flags = cmd->flags;
+       u16 cb_flags = 0;
+
+       /* Windows driver returned 0 for commands for which no response
+        * is expected. It happened that there were only two such commands
+        * used: MMC_GO_IDLE_STATE and MMC_GO_INACTIVE_STATE so it might
+        * as well be a bug in that driver.
+        *
+        * Original driver set bit 14 for MMC/SD application
+        * commands. There's no difference 'on the wire' and
+        * it apparently works without it anyway.
+        */
+
+       switch (flags & MMC_CMD_MASK) {
+       case MMC_CMD_AC:        cb_flags = CB710_MMC_CMD_AC;    break;
+       case MMC_CMD_ADTC:      cb_flags = CB710_MMC_CMD_ADTC;  break;
+       case MMC_CMD_BC:        cb_flags = CB710_MMC_CMD_BC;    break;
+       case MMC_CMD_BCR:       cb_flags = CB710_MMC_CMD_BCR;   break;
+       }
+
+       if (flags & MMC_RSP_BUSY)
+               cb_flags |= CB710_MMC_RSP_BUSY;
+
+       cb_flags |= cmd->opcode << CB710_MMC_CMD_CODE_SHIFT;
+
+       if (cmd->data && (cmd->data->flags & MMC_DATA_READ))
+               cb_flags |= CB710_MMC_DATA_READ;
+
+       if (flags & MMC_RSP_PRESENT) {
+               /* Windows driver set 01 at bits 4,3 except for
+                * MMC_SET_BLOCKLEN where it set 10. Maybe the
+                * hardware can do something special about this
+                * command? The original driver looks buggy/incomplete
+                * anyway so we ignore this for now.
+                *
+                * I assume that 00 here means no response is expected.
+                */
+               cb_flags |= CB710_MMC_RSP_PRESENT;
+
+               if (flags & MMC_RSP_136)
+                       cb_flags |= CB710_MMC_RSP_136;
+               if (!(flags & MMC_RSP_CRC))
+                       cb_flags |= CB710_MMC_RSP_NO_CRC;
+       }
+
+       return cb_flags;
+}
+
+static void cb710_receive_response(struct cb710_slot *slot,
+       struct mmc_command *cmd)
+{
+       unsigned rsp_opcode, wanted_opcode;
+
+       /* Looks like final byte with CRC is always stripped (same as SDHCI) */
+       if (cmd->flags & MMC_RSP_136) {
+               u32 resp[4];
+
+               resp[0] = cb710_read_port_32(slot, CB710_MMC_RESPONSE3_PORT);
+               resp[1] = cb710_read_port_32(slot, CB710_MMC_RESPONSE2_PORT);
+               resp[2] = cb710_read_port_32(slot, CB710_MMC_RESPONSE1_PORT);
+               resp[3] = cb710_read_port_32(slot, CB710_MMC_RESPONSE0_PORT);
+               rsp_opcode = resp[0] >> 24;
+
+               cmd->resp[0] = (resp[0] << 8)|(resp[1] >> 24);
+               cmd->resp[1] = (resp[1] << 8)|(resp[2] >> 24);
+               cmd->resp[2] = (resp[2] << 8)|(resp[3] >> 24);
+               cmd->resp[3] = (resp[3] << 8);
+       } else {
+               rsp_opcode = cb710_read_port_32(slot, CB710_MMC_RESPONSE1_PORT) & 0x3F;
+               cmd->resp[0] = cb710_read_port_32(slot, CB710_MMC_RESPONSE0_PORT);
+       }
+
+       wanted_opcode = (cmd->flags & MMC_RSP_OPCODE) ? cmd->opcode : 0x3F;
+       if (rsp_opcode != wanted_opcode)
+               cmd->error = -EILSEQ;
+}
+
+static int cb710_mmc_transfer_data(struct cb710_slot *slot,
+       struct mmc_data *data)
+{
+       int error, to;
+
+       if (data->flags & MMC_DATA_READ)
+               error = cb710_mmc_receive(slot, data);
+       else
+               error = cb710_mmc_send(slot, data);
+
+       to = cb710_wait_for_event(slot, CB710_MMC_S1_DATA_TRANSFER_DONE);
+       if (!error)
+               error = to;
+
+       if (!error)
+               data->bytes_xfered = data->blksz * data->blocks;
+       return error;
+}
+
+static int cb710_mmc_command(struct mmc_host *mmc, struct mmc_command *cmd)
+{
+       struct cb710_slot *slot = cb710_mmc_to_slot(mmc);
+       struct cb710_mmc_reader *reader = mmc_priv(mmc);
+       struct mmc_data *data = cmd->data;
+
+       u16 cb_cmd = cb710_encode_cmd_flags(reader, cmd);
+       dev_dbg(cb710_slot_dev(slot), "cmd request: 0x%04X\n", cb_cmd);
+
+       if (data) {
+               if (!cb710_is_transfer_size_supported(data)) {
+                       data->error = -EINVAL;
+                       return -1;
+               }
+               cb710_mmc_set_transfer_size(slot, data->blocks, data->blksz);
+       }
+
+       cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20|CB710_MMC_S2_BUSY_10);
+       cb710_write_port_16(slot, CB710_MMC_CMD_TYPE_PORT, cb_cmd);
+       cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20);
+       cb710_write_port_32(slot, CB710_MMC_CMD_PARAM_PORT, cmd->arg);
+       cb710_mmc_reset_events(slot);
+       cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20);
+       cb710_modify_port_8(slot, CB710_MMC_CONFIG0_PORT, 0x01, 0);
+
+       cmd->error = cb710_wait_for_event(slot, CB710_MMC_S1_COMMAND_SENT);
+       if (cmd->error)
+               return -1;
+
+       if (cmd->flags & MMC_RSP_PRESENT) {
+               cb710_receive_response(slot, cmd);
+               if (cmd->error)
+                       return -1;
+       }
+
+       if (data)
+               data->error = cb710_mmc_transfer_data(slot, data);
+       return 0;
+}
+
+static void cb710_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+       struct cb710_slot *slot = cb710_mmc_to_slot(mmc);
+       struct cb710_mmc_reader *reader = mmc_priv(mmc);
+
+       WARN_ON(reader->mrq != NULL);
+
+       reader->mrq = mrq;
+       cb710_mmc_enable_irq(slot, CB710_MMC_IE_TEST_MASK, 0);
+
+       if (cb710_mmc_is_card_inserted(slot)) {
+               if (!cb710_mmc_command(mmc, mrq->cmd) && mrq->stop)
+                       cb710_mmc_command(mmc, mrq->stop);
+               mdelay(1);
+       } else {
+               mrq->cmd->error = -ENOMEDIUM;
+       }
+
+       tasklet_schedule(&reader->finish_req_tasklet);
+}
+
+static int cb710_mmc_powerup(struct cb710_slot *slot)
+{
+#ifdef CONFIG_CB710_DEBUG
+       struct cb710_chip *chip = cb710_slot_to_chip(slot);
+#endif
+       int err;
+
+       /* a lot of magic; see comment in cb710_mmc_set_clock() */
+       dev_dbg(cb710_slot_dev(slot), "bus powerup\n");
+       cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
+       err = cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20);
+       if (unlikely(err))
+               return err;
+       cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, 0x80, 0);
+       cb710_modify_port_8(slot, CB710_MMC_CONFIG3_PORT, 0x80, 0);
+       cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
+       mdelay(1);
+       dev_dbg(cb710_slot_dev(slot), "after delay 1\n");
+       cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
+       err = cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20);
+       if (unlikely(err))
+               return err;
+       cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, 0x09, 0);
+       cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
+       mdelay(1);
+       dev_dbg(cb710_slot_dev(slot), "after delay 2\n");
+       cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
+       err = cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20);
+       if (unlikely(err))
+               return err;
+       cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, 0, 0x08);
+       cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
+       mdelay(2);
+       dev_dbg(cb710_slot_dev(slot), "after delay 3\n");
+       cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
+       cb710_modify_port_8(slot, CB710_MMC_CONFIG0_PORT, 0x06, 0);
+       cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, 0x70, 0);
+       cb710_modify_port_8(slot, CB710_MMC_CONFIG2_PORT, 0x80, 0);
+       cb710_modify_port_8(slot, CB710_MMC_CONFIG3_PORT, 0x03, 0);
+       cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
+       err = cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20);
+       if (unlikely(err))
+               return err;
+       /* This port behaves weird: quick byte reads of 0x08,0x09 return
+        * 0xFF,0x00 after writing 0xFFFF to 0x08; it works correctly when
+        * read/written from userspace...  What am I missing here?
+        * (it doesn't depend on write-to-read delay) */
+       cb710_write_port_16(slot, CB710_MMC_CONFIGB_PORT, 0xFFFF);
+       cb710_modify_port_8(slot, CB710_MMC_CONFIG0_PORT, 0x06, 0);
+       cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
+       dev_dbg(cb710_slot_dev(slot), "bus powerup finished\n");
+
+       return cb710_check_event(slot, 0);
+}
+
+static void cb710_mmc_powerdown(struct cb710_slot *slot)
+{
+       cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, 0, 0x81);
+       cb710_modify_port_8(slot, CB710_MMC_CONFIG3_PORT, 0, 0x80);
+}
+
+static void cb710_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct cb710_slot *slot = cb710_mmc_to_slot(mmc);
+       struct cb710_mmc_reader *reader = mmc_priv(mmc);
+       int err;
+
+       cb710_mmc_set_clock(mmc, ios->clock);
+
+       if (!cb710_mmc_is_card_inserted(slot)) {
+               dev_dbg(cb710_slot_dev(slot),
+                       "no card inserted - ignoring bus powerup request\n");
+               ios->power_mode = MMC_POWER_OFF;
+       }
+
+       if (ios->power_mode != reader->last_power_mode)
+       switch (ios->power_mode) {
+       case MMC_POWER_ON:
+               err = cb710_mmc_powerup(slot);
+               if (err) {
+                       dev_warn(cb710_slot_dev(slot),
+                               "powerup failed (%d)- retrying\n", err);
+                       cb710_mmc_powerdown(slot);
+                       udelay(1);
+                       err = cb710_mmc_powerup(slot);
+                       if (err)
+                               dev_warn(cb710_slot_dev(slot),
+                                       "powerup retry failed (%d) - expect errors\n",
+                                       err);
+               }
+               reader->last_power_mode = MMC_POWER_ON;
+               break;
+       case MMC_POWER_OFF:
+               cb710_mmc_powerdown(slot);
+               reader->last_power_mode = MMC_POWER_OFF;
+               break;
+       case MMC_POWER_UP:
+       default:
+               /* ignore */;
+       }
+
+       cb710_mmc_enable_4bit_data(slot, ios->bus_width != MMC_BUS_WIDTH_1);
+
+       cb710_mmc_enable_irq(slot, CB710_MMC_IE_TEST_MASK, 0);
+}
+
+static int cb710_mmc_get_ro(struct mmc_host *mmc)
+{
+       struct cb710_slot *slot = cb710_mmc_to_slot(mmc);
+
+       return cb710_read_port_8(slot, CB710_MMC_STATUS3_PORT)
+               & CB710_MMC_S3_WRITE_PROTECTED;
+}
+
+static int cb710_mmc_irq_handler(struct cb710_slot *slot)
+{
+       struct mmc_host *mmc = cb710_slot_to_mmc(slot);
+       struct cb710_mmc_reader *reader = mmc_priv(mmc);
+       u32 status, config1, config2, irqen;
+
+       status = cb710_read_port_32(slot, CB710_MMC_STATUS_PORT);
+       irqen = cb710_read_port_32(slot, CB710_MMC_IRQ_ENABLE_PORT);
+       config2 = cb710_read_port_32(slot, CB710_MMC_CONFIGB_PORT);
+       config1 = cb710_read_port_32(slot, CB710_MMC_CONFIG_PORT);
+
+       dev_dbg(cb710_slot_dev(slot), "interrupt; status: %08X, "
+               "ie: %08X, c2: %08X, c1: %08X\n",
+               status, irqen, config2, config1);
+
+       if (status & (CB710_MMC_S1_CARD_CHANGED << 8)) {
+               /* ack the event */
+               cb710_write_port_8(slot, CB710_MMC_STATUS1_PORT,
+                       CB710_MMC_S1_CARD_CHANGED);
+               if ((irqen & CB710_MMC_IE_CISTATUS_MASK)
+                   == CB710_MMC_IE_CISTATUS_MASK)
+                       mmc_detect_change(mmc, HZ/5);
+       } else {
+               dev_dbg(cb710_slot_dev(slot), "unknown interrupt (test)\n");
+               spin_lock(&reader->irq_lock);
+               __cb710_mmc_enable_irq(slot, 0, CB710_MMC_IE_TEST_MASK);
+               spin_unlock(&reader->irq_lock);
+       }
+
+       return 1;
+}
+
+static void cb710_mmc_finish_request_tasklet(unsigned long data)
+{
+       struct mmc_host *mmc = (void *)data;
+       struct cb710_mmc_reader *reader = mmc_priv(mmc);
+       struct mmc_request *mrq = reader->mrq;
+
+       reader->mrq = NULL;
+       mmc_request_done(mmc, mrq);
+}
+
+static const struct mmc_host_ops cb710_mmc_host = {
+       .request = cb710_mmc_request,
+       .set_ios = cb710_mmc_set_ios,
+       .get_ro = cb710_mmc_get_ro
+};
+
+#ifdef CONFIG_PM
+
+static int cb710_mmc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct cb710_slot *slot = cb710_pdev_to_slot(pdev);
+       struct mmc_host *mmc = cb710_slot_to_mmc(slot);
+       int err;
+
+       err = mmc_suspend_host(mmc, state);
+       if (err)
+               return err;
+
+       cb710_mmc_enable_irq(slot, 0, ~0);
+       return 0;
+}
+
+static int cb710_mmc_resume(struct platform_device *pdev)
+{
+       struct cb710_slot *slot = cb710_pdev_to_slot(pdev);
+       struct mmc_host *mmc = cb710_slot_to_mmc(slot);
+
+       cb710_mmc_enable_irq(slot, 0, ~0);
+
+       return mmc_resume_host(mmc);
+}
+
+#endif /* CONFIG_PM */
+
+static int __devinit cb710_mmc_init(struct platform_device *pdev)
+{
+       struct cb710_slot *slot = cb710_pdev_to_slot(pdev);
+       struct cb710_chip *chip = cb710_slot_to_chip(slot);
+       struct mmc_host *mmc;
+       struct cb710_mmc_reader *reader;
+       int err;
+       u32 val;
+
+       mmc = mmc_alloc_host(sizeof(*reader), cb710_slot_dev(slot));
+       if (!mmc)
+               return -ENOMEM;
+
+       dev_set_drvdata(&pdev->dev, mmc);
+
+       /* harmless (maybe) magic */
+       pci_read_config_dword(chip->pdev, 0x48, &val);
+       val = cb710_src_freq_mhz[(val >> 16) & 0xF];
+       dev_dbg(cb710_slot_dev(slot), "source frequency: %dMHz\n", val);
+       val *= 1000000;
+
+       mmc->ops = &cb710_mmc_host;
+       mmc->f_max = val;
+       mmc->f_min = val >> cb710_clock_divider_log2[CB710_MAX_DIVIDER_IDX];
+       mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
+       mmc->caps = MMC_CAP_4_BIT_DATA;
+
+       reader = mmc_priv(mmc);
+
+       tasklet_init(&reader->finish_req_tasklet,
+               cb710_mmc_finish_request_tasklet, (unsigned long)mmc);
+       spin_lock_init(&reader->irq_lock);
+       cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
+
+       cb710_mmc_enable_irq(slot, 0, ~0);
+       cb710_set_irq_handler(slot, cb710_mmc_irq_handler);
+
+       err = mmc_add_host(mmc);
+       if (unlikely(err))
+               goto err_free_mmc;
+
+       dev_dbg(cb710_slot_dev(slot), "mmc_hostname is %s\n",
+               mmc_hostname(mmc));
+
+       cb710_mmc_enable_irq(slot, CB710_MMC_IE_CARD_INSERTION_STATUS, 0);
+
+       return 0;
+
+err_free_mmc:
+       dev_dbg(cb710_slot_dev(slot), "mmc_add_host() failed: %d\n", err);
+
+       mmc_free_host(mmc);
+       return err;
+}
+
+static int __devexit cb710_mmc_exit(struct platform_device *pdev)
+{
+       struct cb710_slot *slot = cb710_pdev_to_slot(pdev);
+       struct mmc_host *mmc = cb710_slot_to_mmc(slot);
+       struct cb710_mmc_reader *reader = mmc_priv(mmc);
+
+       cb710_mmc_enable_irq(slot, 0, CB710_MMC_IE_CARD_INSERTION_STATUS);
+
+       mmc_remove_host(mmc);
+
+       /* IRQs should be disabled now, but let's stay on the safe side */
+       cb710_mmc_enable_irq(slot, 0, ~0);
+       cb710_set_irq_handler(slot, NULL);
+
+       /* clear config ports - just in case */
+       cb710_write_port_32(slot, CB710_MMC_CONFIG_PORT, 0);
+       cb710_write_port_16(slot, CB710_MMC_CONFIGB_PORT, 0);
+
+       tasklet_kill(&reader->finish_req_tasklet);
+
+       mmc_free_host(mmc);
+       return 0;
+}
+
+static struct platform_driver cb710_mmc_driver = {
+       .driver.name = "cb710-mmc",
+       .probe = cb710_mmc_init,
+       .remove = __devexit_p(cb710_mmc_exit),
+#ifdef CONFIG_PM
+       .suspend = cb710_mmc_suspend,
+       .resume = cb710_mmc_resume,
+#endif
+};
+
+static int __init cb710_mmc_init_module(void)
+{
+       return platform_driver_register(&cb710_mmc_driver);
+}
+
+static void __exit cb710_mmc_cleanup_module(void)
+{
+       platform_driver_unregister(&cb710_mmc_driver);
+}
+
+module_init(cb710_mmc_init_module);
+module_exit(cb710_mmc_cleanup_module);
+
+MODULE_AUTHOR("MichaÅ‚ MirosÅ‚aw <mirq-linux@rere.qmqm.pl>");
+MODULE_DESCRIPTION("ENE CB710 memory card reader driver - MMC/SD part");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:cb710-mmc");
diff --git a/drivers/mmc/host/cb710-mmc.h b/drivers/mmc/host/cb710-mmc.h
new file mode 100644 (file)
index 0000000..e845c77
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ *  cb710/cb710-mmc.h
+ *
+ *  Copyright by MichaÅ‚ MirosÅ‚aw, 2008-2009
+ *
+ * This 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_CB710_MMC_H
+#define LINUX_CB710_MMC_H
+
+#include <linux/cb710.h>
+
+/* per-MMC-reader structure */
+struct cb710_mmc_reader {
+       struct tasklet_struct finish_req_tasklet;
+       struct mmc_request *mrq;
+       spinlock_t irq_lock;
+       unsigned char last_power_mode;
+};
+
+/* some device struct walking */
+
+static inline struct mmc_host *cb710_slot_to_mmc(struct cb710_slot *slot)
+{
+       return dev_get_drvdata(&slot->pdev.dev);
+}
+
+static inline struct cb710_slot *cb710_mmc_to_slot(struct mmc_host *mmc)
+{
+       struct platform_device *pdev = container_of(mmc_dev(mmc),
+               struct platform_device, dev);
+       return cb710_pdev_to_slot(pdev);
+}
+
+/* registers (this might be all wrong ;) */
+
+#define CB710_MMC_DATA_PORT            0x00
+
+#define CB710_MMC_CONFIG_PORT          0x04
+#define CB710_MMC_CONFIG0_PORT         0x04
+#define CB710_MMC_CONFIG1_PORT         0x05
+#define   CB710_MMC_C1_4BIT_DATA_BUS           0x40
+#define CB710_MMC_CONFIG2_PORT         0x06
+#define   CB710_MMC_C2_READ_PIO_SIZE_MASK      0x0F    /* N-1 */
+#define CB710_MMC_CONFIG3_PORT         0x07
+
+#define CB710_MMC_CONFIGB_PORT         0x08
+
+#define CB710_MMC_IRQ_ENABLE_PORT      0x0C
+#define   CB710_MMC_IE_TEST_MASK               0x00BF
+#define   CB710_MMC_IE_CARD_INSERTION_STATUS   0x1000
+#define   CB710_MMC_IE_IRQ_ENABLE              0x8000
+#define   CB710_MMC_IE_CISTATUS_MASK           \
+               (CB710_MMC_IE_CARD_INSERTION_STATUS|CB710_MMC_IE_IRQ_ENABLE)
+
+#define CB710_MMC_STATUS_PORT          0x10
+#define   CB710_MMC_STATUS_ERROR_EVENTS                0x60FF
+#define CB710_MMC_STATUS0_PORT         0x10
+#define   CB710_MMC_S0_FIFO_UNDERFLOW          0x40
+#define CB710_MMC_STATUS1_PORT         0x11
+#define   CB710_MMC_S1_COMMAND_SENT            0x01
+#define   CB710_MMC_S1_DATA_TRANSFER_DONE      0x02
+#define   CB710_MMC_S1_PIO_TRANSFER_DONE       0x04
+#define   CB710_MMC_S1_CARD_CHANGED            0x10
+#define   CB710_MMC_S1_RESET                   0x20
+#define CB710_MMC_STATUS2_PORT         0x12
+#define   CB710_MMC_S2_FIFO_READY              0x01
+#define   CB710_MMC_S2_FIFO_EMPTY              0x02
+#define   CB710_MMC_S2_BUSY_10                 0x10
+#define   CB710_MMC_S2_BUSY_20                 0x20
+#define CB710_MMC_STATUS3_PORT         0x13
+#define   CB710_MMC_S3_CARD_DETECTED           0x02
+#define   CB710_MMC_S3_WRITE_PROTECTED         0x04
+
+#define CB710_MMC_CMD_TYPE_PORT                0x14
+#define   CB710_MMC_RSP_TYPE_MASK              0x0007
+#define     CB710_MMC_RSP_R1                   (0)
+#define     CB710_MMC_RSP_136                  (5)
+#define     CB710_MMC_RSP_NO_CRC               (2)
+#define   CB710_MMC_RSP_PRESENT_MASK           0x0018
+#define     CB710_MMC_RSP_NONE                 (0 << 3)
+#define     CB710_MMC_RSP_PRESENT              (1 << 3)
+#define     CB710_MMC_RSP_PRESENT_X            (2 << 3)
+#define   CB710_MMC_CMD_TYPE_MASK              0x0060
+#define     CB710_MMC_CMD_BC                   (0 << 5)
+#define     CB710_MMC_CMD_BCR                  (1 << 5)
+#define     CB710_MMC_CMD_AC                   (2 << 5)
+#define     CB710_MMC_CMD_ADTC                 (3 << 5)
+#define   CB710_MMC_DATA_READ                  0x0080
+#define   CB710_MMC_CMD_CODE_MASK              0x3F00
+#define   CB710_MMC_CMD_CODE_SHIFT             8
+#define   CB710_MMC_IS_APP_CMD                 0x4000
+#define   CB710_MMC_RSP_BUSY                   0x8000
+
+#define CB710_MMC_CMD_PARAM_PORT       0x18
+#define CB710_MMC_TRANSFER_SIZE_PORT   0x1C
+#define CB710_MMC_RESPONSE0_PORT       0x20
+#define CB710_MMC_RESPONSE1_PORT       0x24
+#define CB710_MMC_RESPONSE2_PORT       0x28
+#define CB710_MMC_RESPONSE3_PORT       0x2C
+
+#endif /* LINUX_CB710_MMC_H */
index f48349d18c9264ba988b12d0373c7a4d5d7da8eb..240608cc7ae9b853c46f696986a821048bebb35b 100644 (file)
  */
 #define r1b_timeout            (HZ * 3)
 
+/* One of the critical speed parameters is the amount of data which may
+ * be transfered in one command. If this value is too low, the SD card
+ * controller has to do multiple partial block writes (argggh!). With
+ * today (2008) SD cards there is little speed gain if we transfer more
+ * than 64 KBytes at a time. So use this value until there is any indication
+ * that we should do more here.
+ */
+#define MMC_SPI_BLOCKSATONCE   128
 
 /****************************************************************************/
 
@@ -327,15 +335,16 @@ checkstatus:
 
        /* Status byte: the entire seven-bit R1 response.  */
        if (cmd->resp[0] != 0) {
-               if ((R1_SPI_PARAMETER | R1_SPI_ADDRESS
-                                     | R1_SPI_ILLEGAL_COMMAND)
+               if ((R1_SPI_PARAMETER | R1_SPI_ADDRESS)
                                & cmd->resp[0])
-                       value = -EINVAL;
+                       value = -EFAULT; /* Bad address */
+               else if (R1_SPI_ILLEGAL_COMMAND & cmd->resp[0])
+                       value = -ENOSYS; /* Function not implemented */
                else if (R1_SPI_COM_CRC & cmd->resp[0])
-                       value = -EILSEQ;
+                       value = -EILSEQ; /* Illegal byte sequence */
                else if ((R1_SPI_ERASE_SEQ | R1_SPI_ERASE_RESET)
                                & cmd->resp[0])
-                       value = -EIO;
+                       value = -EIO;    /* I/O error */
                /* else R1_SPI_IDLE, "it's resetting" */
        }
 
@@ -1366,6 +1375,10 @@ static int mmc_spi_probe(struct spi_device *spi)
 
        mmc->ops = &mmc_spi_ops;
        mmc->max_blk_size = MMC_SPI_BLOCKSIZE;
+       mmc->max_hw_segs = MMC_SPI_BLOCKSATONCE;
+       mmc->max_phys_segs = MMC_SPI_BLOCKSATONCE;
+       mmc->max_req_size = MMC_SPI_BLOCKSATONCE * MMC_SPI_BLOCKSIZE;
+       mmc->max_blk_count = MMC_SPI_BLOCKSATONCE;
 
        mmc->caps = MMC_CAP_SPI;
 
index 7d4febdab286f2e96f70a8f9988d600a5ab36350..e1aa8471ab1c31ca31a0d7ad48bee0eb5187a46c 100644 (file)
@@ -546,7 +546,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
                host->mclk = clk_get_rate(host->clk);
                DBG(host, "eventual mclk rate: %u Hz\n", host->mclk);
        }
-       host->base = ioremap(dev->res.start, SZ_4K);
+       host->base = ioremap(dev->res.start, resource_size(&dev->res));
        if (!host->base) {
                ret = -ENOMEM;
                goto clk_disable;
index f4cbe473670e0ad0a096fa43d12302b67490fadf..bc14bb1b057935816868065972b4e078b090089d 100644 (file)
@@ -746,8 +746,6 @@ static int mxcmci_probe(struct platform_device *pdev)
        }
 
        mmc->f_min = clk_get_rate(host->clk) >> 16;
-       if (mmc->f_min < 400000)
-               mmc->f_min = 400000;
        mmc->f_max = clk_get_rate(host->clk) >> 1;
 
        /* recommended in data sheet */
index dceb5ee3bda068da5668b87783f9cd8339e9207f..e7a331de573358a7326303f61724bb0f148025d8 100644 (file)
@@ -1593,7 +1593,6 @@ static int mmc_omap_resume(struct platform_device *pdev)
 #endif
 
 static struct platform_driver mmc_omap_driver = {
-       .probe          = mmc_omap_probe,
        .remove         = mmc_omap_remove,
        .suspend        = mmc_omap_suspend,
        .resume         = mmc_omap_resume,
@@ -1605,7 +1604,7 @@ static struct platform_driver mmc_omap_driver = {
 
 static int __init mmc_omap_init(void)
 {
-       return platform_driver_register(&mmc_omap_driver);
+       return platform_driver_probe(&mmc_omap_driver, mmc_omap_probe);
 }
 
 static void __exit mmc_omap_exit(void)
index c40cb96255a2c92a6e395df960dd7989b9143800..1cf9cfb3b64fb13f262f652ef74323e4bb1392ec 100644 (file)
@@ -1073,7 +1073,6 @@ static int __init omap_mmc_probe(struct platform_device *pdev)
        mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
        mmc->max_seg_size = mmc->max_req_size;
 
-       mmc->ocr_avail = mmc_slot(host).ocr_mask;
        mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
 
        if (pdata->slots[host->slot_id].wires >= 8)
@@ -1110,13 +1109,14 @@ static int __init omap_mmc_probe(struct platform_device *pdev)
                goto err_irq;
        }
 
+       /* initialize power supplies, gpios, etc */
        if (pdata->init != NULL) {
                if (pdata->init(&pdev->dev) != 0) {
-                       dev_dbg(mmc_dev(host->mmc),
-                               "Unable to configure MMC IRQs\n");
+                       dev_dbg(mmc_dev(host->mmc), "late init error\n");
                        goto err_irq_cd_init;
                }
        }
+       mmc->ocr_avail = mmc_slot(host).ocr_mask;
 
        /* Request IRQ for card detect */
        if ((mmc_slot(host).card_detect_irq)) {
index 430095725f9f294af3db79a136b07196db2d2f7e..d7d7109ef47e10b665059433ec962db77f176f7d 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/err.h>
 #include <linux/mmc/host.h>
 #include <linux/io.h>
+#include <linux/regulator/consumer.h>
 
 #include <asm/sizes.h>
 
@@ -67,8 +68,42 @@ struct pxamci_host {
        unsigned int            dma_dir;
        unsigned int            dma_drcmrrx;
        unsigned int            dma_drcmrtx;
+
+       struct regulator        *vcc;
 };
 
+static inline void pxamci_init_ocr(struct pxamci_host *host)
+{
+#ifdef CONFIG_REGULATOR
+       host->vcc = regulator_get(mmc_dev(host->mmc), "vmmc");
+
+       if (IS_ERR(host->vcc))
+               host->vcc = NULL;
+       else {
+               host->mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vcc);
+               if (host->pdata && host->pdata->ocr_mask)
+                       dev_warn(mmc_dev(host->mmc),
+                               "ocr_mask/setpower will not be used\n");
+       }
+#endif
+       if (host->vcc == NULL) {
+               /* fall-back to platform data */
+               host->mmc->ocr_avail = host->pdata ?
+                       host->pdata->ocr_mask :
+                       MMC_VDD_32_33 | MMC_VDD_33_34;
+       }
+}
+
+static inline void pxamci_set_power(struct pxamci_host *host, unsigned int vdd)
+{
+#ifdef CONFIG_REGULATOR
+       if (host->vcc)
+               mmc_regulator_set_ocr(host->vcc, vdd);
+#endif
+       if (!host->vcc && host->pdata && host->pdata->setpower)
+               host->pdata->setpower(mmc_dev(host->mmc), vdd);
+}
+
 static void pxamci_stop_clock(struct pxamci_host *host)
 {
        if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
@@ -438,8 +473,7 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        if (host->power_mode != ios->power_mode) {
                host->power_mode = ios->power_mode;
 
-               if (host->pdata && host->pdata->setpower)
-                       host->pdata->setpower(mmc_dev(mmc), ios->vdd);
+               pxamci_set_power(host, ios->vdd);
 
                if (ios->power_mode == MMC_POWER_ON)
                        host->cmdat |= CMDAT_INIT;
@@ -562,9 +596,8 @@ static int pxamci_probe(struct platform_device *pdev)
        mmc->f_max = (cpu_is_pxa300() || cpu_is_pxa310()) ? 26000000
                                                          : host->clkrate;
 
-       mmc->ocr_avail = host->pdata ?
-                        host->pdata->ocr_mask :
-                        MMC_VDD_32_33|MMC_VDD_33_34;
+       pxamci_init_ocr(host);
+
        mmc->caps = 0;
        host->cmdat = 0;
        if (!cpu_is_pxa25x()) {
@@ -661,6 +694,9 @@ static int pxamci_remove(struct platform_device *pdev)
        if (mmc) {
                struct pxamci_host *host = mmc_priv(mmc);
 
+               if (host->vcc)
+                       regulator_put(host->vcc);
+
                if (host->pdata && host->pdata->exit)
                        host->pdata->exit(&pdev->dev, mmc);
 
index 2db166b7096f42ddf1ed5eac276de476adb9fc3e..4eb4f37544ab5c37a426393a9e614d4eca4e27a8 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/mmc/host.h>
 #include <linux/platform_device.h>
 #include <linux/cpufreq.h>
+#include <linux/gpio.h>
 #include <linux/irq.h>
 #include <linux/io.h>
 
@@ -789,7 +790,7 @@ static void s3cmci_dma_setup(struct s3cmci_host *host,
 
        last_source = source;
 
-       s3c2410_dma_devconfig(host->dma, source, 3,
+       s3c2410_dma_devconfig(host->dma, source,
                              host->mem->start + host->sdidata);
 
        if (!setup_ok) {
@@ -1121,7 +1122,7 @@ static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        case MMC_POWER_OFF:
        default:
                s3c2410_gpio_setpin(S3C2410_GPE5, 0);
-               s3c2410_gpio_cfgpin(S3C2410_GPE5, S3C2410_GPE5_OUTP);
+               s3c2410_gpio_cfgpin(S3C2410_GPE5, S3C2410_GPIO_OUTPUT);
 
                if (host->is2440)
                        mci_con |= S3C2440_SDICON_SDRESET;
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
new file mode 100644 (file)
index 0000000..297f40a
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * sdhci-pltfm.c Support for SDHCI platform devices
+ * Copyright (c) 2009 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Supports:
+ * SDHCI platform devices
+ *
+ * Inspired by sdhci-pci.c, by Pierre Ossman
+ */
+
+#include <linux/delay.h>
+#include <linux/highmem.h>
+#include <linux/platform_device.h>
+
+#include <linux/mmc/host.h>
+
+#include <linux/io.h>
+
+#include "sdhci.h"
+
+/*****************************************************************************\
+ *                                                                           *
+ * SDHCI core callbacks                                                      *
+ *                                                                           *
+\*****************************************************************************/
+
+static struct sdhci_ops sdhci_pltfm_ops = {
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * Device probing/removal                                                    *
+ *                                                                           *
+\*****************************************************************************/
+
+static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
+{
+       struct sdhci_host *host;
+       struct resource *iomem;
+       int ret;
+
+       BUG_ON(pdev == NULL);
+
+       iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!iomem) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       if (resource_size(iomem) != 0x100)
+               dev_err(&pdev->dev, "Invalid iomem size. You may "
+                       "experience problems.\n");
+
+       if (pdev->dev.parent)
+               host = sdhci_alloc_host(pdev->dev.parent, 0);
+       else
+               host = sdhci_alloc_host(&pdev->dev, 0);
+
+       if (IS_ERR(host)) {
+               ret = PTR_ERR(host);
+               goto err;
+       }
+
+       host->hw_name = "platform";
+       host->ops = &sdhci_pltfm_ops;
+       host->irq = platform_get_irq(pdev, 0);
+
+       if (!request_mem_region(iomem->start, resource_size(iomem),
+               mmc_hostname(host->mmc))) {
+               dev_err(&pdev->dev, "cannot request region\n");
+               ret = -EBUSY;
+               goto err_request;
+       }
+
+       host->ioaddr = ioremap(iomem->start, resource_size(iomem));
+       if (!host->ioaddr) {
+               dev_err(&pdev->dev, "failed to remap registers\n");
+               ret = -ENOMEM;
+               goto err_remap;
+       }
+
+       ret = sdhci_add_host(host);
+       if (ret)
+               goto err_add_host;
+
+       platform_set_drvdata(pdev, host);
+
+       return 0;
+
+err_add_host:
+       iounmap(host->ioaddr);
+err_remap:
+       release_mem_region(iomem->start, resource_size(iomem));
+err_request:
+       sdhci_free_host(host);
+err:
+       printk(KERN_ERR"Probing of sdhci-pltfm failed: %d\n", ret);
+       return ret;
+}
+
+static int __devexit sdhci_pltfm_remove(struct platform_device *pdev)
+{
+       struct sdhci_host *host = platform_get_drvdata(pdev);
+       struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       int dead;
+       u32 scratch;
+
+       dead = 0;
+       scratch = readl(host->ioaddr + SDHCI_INT_STATUS);
+       if (scratch == (u32)-1)
+               dead = 1;
+
+       sdhci_remove_host(host, dead);
+       iounmap(host->ioaddr);
+       release_mem_region(iomem->start, resource_size(iomem));
+       sdhci_free_host(host);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver sdhci_pltfm_driver = {
+       .driver = {
+               .name   = "sdhci",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = sdhci_pltfm_probe,
+       .remove         = __devexit_p(sdhci_pltfm_remove),
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * Driver init/exit                                                          *
+ *                                                                           *
+\*****************************************************************************/
+
+static int __init sdhci_drv_init(void)
+{
+       return platform_driver_register(&sdhci_pltfm_driver);
+}
+
+static void __exit sdhci_drv_exit(void)
+{
+       platform_driver_unregister(&sdhci_pltfm_driver);
+}
+
+module_init(sdhci_drv_init);
+module_exit(sdhci_drv_exit);
+
+MODULE_DESCRIPTION("Secure Digital Host Controller Interface platform driver");
+MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:sdhci");
+
index 9234be2226e743fc40b1d5b54e53a8500c09dd19..35789c6edc199928191ba24d519a92fe93e33fc7 100644 (file)
@@ -78,6 +78,11 @@ static void sdhci_dumpregs(struct sdhci_host *host)
                sdhci_readl(host, SDHCI_CAPABILITIES),
                sdhci_readl(host, SDHCI_MAX_CURRENT));
 
+       if (host->flags & SDHCI_USE_ADMA)
+               printk(KERN_DEBUG DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
+                      readl(host->ioaddr + SDHCI_ADMA_ERROR),
+                      readl(host->ioaddr + SDHCI_ADMA_ADDRESS));
+
        printk(KERN_DEBUG DRIVER_NAME ": ===========================================\n");
 }
 
@@ -1005,12 +1010,34 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
 {
        u8 pwr;
 
-       if (host->power == power)
+       if (power == (unsigned short)-1)
+               pwr = 0;
+       else {
+               switch (1 << power) {
+               case MMC_VDD_165_195:
+                       pwr = SDHCI_POWER_180;
+                       break;
+               case MMC_VDD_29_30:
+               case MMC_VDD_30_31:
+                       pwr = SDHCI_POWER_300;
+                       break;
+               case MMC_VDD_32_33:
+               case MMC_VDD_33_34:
+                       pwr = SDHCI_POWER_330;
+                       break;
+               default:
+                       BUG();
+               }
+       }
+
+       if (host->pwr == pwr)
                return;
 
-       if (power == (unsigned short)-1) {
+       host->pwr = pwr;
+
+       if (pwr == 0) {
                sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
-               goto out;
+               return;
        }
 
        /*
@@ -1020,35 +1047,16 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
        if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
                sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
 
-       pwr = SDHCI_POWER_ON;
-
-       switch (1 << power) {
-       case MMC_VDD_165_195:
-               pwr |= SDHCI_POWER_180;
-               break;
-       case MMC_VDD_29_30:
-       case MMC_VDD_30_31:
-               pwr |= SDHCI_POWER_300;
-               break;
-       case MMC_VDD_32_33:
-       case MMC_VDD_33_34:
-               pwr |= SDHCI_POWER_330;
-               break;
-       default:
-               BUG();
-       }
-
        /*
         * At least the Marvell CaFe chip gets confused if we set the voltage
         * and set turn on power at the same time, so set the voltage first.
         */
        if ((host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER))
-               sdhci_writeb(host, pwr & ~SDHCI_POWER_ON, SDHCI_POWER_CONTROL);
+               sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
 
-       sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+       pwr |= SDHCI_POWER_ON;
 
-out:
-       host->power = power;
+       sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
 }
 
 /*****************************************************************************\
index 65c6f996bbd31cc7e9851ac781c69241c68c3fa5..2de08349c3ca95d0c9ac3fa387574a68b0a41834 100644 (file)
@@ -255,7 +255,7 @@ struct sdhci_host {
        unsigned int            timeout_clk;    /* Timeout freq (KHz) */
 
        unsigned int            clock;          /* Current clock (MHz) */
-       unsigned short          power;          /* Current voltage */
+       u8                      pwr;            /* Current voltage */
 
        struct mmc_request      *mrq;           /* Current request */
        struct mmc_command      *cmd;           /* Current command */
index 63fbd5b7d312b503e285a68a1895af709c134027..91991b460c4547c7a90a583ca987f087c6babd53 100644 (file)
@@ -10,7 +10,7 @@
  *
  * Driver for the MMC / SD / SDIO cell found in:
  *
- * TC6393XB TC6391XB TC6387XB T7L66XB
+ * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3
  *
  * This driver draws mainly on scattered spec sheets, Reverse engineering
  * of the toshiba e800  SD driver and some parts of the 2.4 ASIC3 driver (4 bit
 
 #include "tmio_mmc.h"
 
-/*
- * Fixme - documentation conflicts on what the clock values are for the
- * various dividers.
- * One document I have says that its a divisor of a 24MHz clock, another 33.
- * This probably depends on HCLK for a given platform, so we may need to
- * require HCLK be passed to us from the MFD core.
- *
- */
-
 static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock)
 {
-       void __iomem *cnf = host->cnf;
-       void __iomem *ctl = host->ctl;
        u32 clk = 0, clock;
 
        if (new_clock) {
-               for (clock = 46875, clk = 0x100; new_clock >= (clock<<1); ) {
+               for (clock = host->mmc->f_min, clk = 0x80000080;
+                       new_clock >= (clock<<1); clk >>= 1)
                        clock <<= 1;
-                       clk >>= 1;
-               }
-               if (clk & 0x1)
-                       clk = 0x20000;
-
-               clk >>= 2;
-               tmio_iowrite8((clk & 0x8000) ? 0 : 1, cnf + CNF_SD_CLK_MODE);
                clk |= 0x100;
        }
 
-       tmio_iowrite16(clk, ctl + CTL_SD_CARD_CLK_CTL);
+       sd_config_write8(host, CNF_SD_CLK_MODE, clk >> 22);
+       sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & 0x1ff);
 }
 
 static void tmio_mmc_clk_stop(struct tmio_mmc_host *host)
 {
-       void __iomem *ctl = host->ctl;
-
-       tmio_iowrite16(0x0000, ctl + CTL_CLK_AND_WAIT_CTL);
+       sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000);
        msleep(10);
-       tmio_iowrite16(tmio_ioread16(ctl + CTL_SD_CARD_CLK_CTL) & ~0x0100,
-              ctl + CTL_SD_CARD_CLK_CTL);
+       sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 &
+               sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
        msleep(10);
 }
 
 static void tmio_mmc_clk_start(struct tmio_mmc_host *host)
 {
-       void __iomem *ctl = host->ctl;
-
-       tmio_iowrite16(tmio_ioread16(ctl + CTL_SD_CARD_CLK_CTL) | 0x0100,
-              ctl + CTL_SD_CARD_CLK_CTL);
+       sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 |
+               sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
        msleep(10);
-       tmio_iowrite16(0x0100, ctl + CTL_CLK_AND_WAIT_CTL);
+       sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100);
        msleep(10);
 }
 
 static void reset(struct tmio_mmc_host *host)
 {
-       void __iomem *ctl = host->ctl;
-
        /* FIXME - should we set stop clock reg here */
-       tmio_iowrite16(0x0000, ctl + CTL_RESET_SD);
-       tmio_iowrite16(0x0000, ctl + CTL_RESET_SDIO);
+       sd_ctrl_write16(host, CTL_RESET_SD, 0x0000);
+       sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000);
        msleep(10);
-       tmio_iowrite16(0x0001, ctl + CTL_RESET_SD);
-       tmio_iowrite16(0x0001, ctl + CTL_RESET_SDIO);
+       sd_ctrl_write16(host, CTL_RESET_SD, 0x0001);
+       sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001);
        msleep(10);
 }
 
@@ -129,13 +107,12 @@ tmio_mmc_finish_request(struct tmio_mmc_host *host)
 static int
 tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command *cmd)
 {
-       void __iomem *ctl = host->ctl;
        struct mmc_data *data = host->data;
        int c = cmd->opcode;
 
        /* Command 12 is handled by hardware */
        if (cmd->opcode == 12 && !cmd->arg) {
-               tmio_iowrite16(0x001, ctl + CTL_STOP_INTERNAL_ACTION);
+               sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x001);
                return 0;
        }
 
@@ -160,18 +137,18 @@ tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command *cmd)
        if (data) {
                c |= DATA_PRESENT;
                if (data->blocks > 1) {
-                       tmio_iowrite16(0x100, ctl + CTL_STOP_INTERNAL_ACTION);
+                       sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x100);
                        c |= TRANSFER_MULTI;
                }
                if (data->flags & MMC_DATA_READ)
                        c |= TRANSFER_READ;
        }
 
-       enable_mmc_irqs(ctl, TMIO_MASK_CMD);
+       enable_mmc_irqs(host, TMIO_MASK_CMD);
 
        /* Fire off the command */
-       tmio_iowrite32(cmd->arg, ctl + CTL_ARG_REG);
-       tmio_iowrite16(c, ctl + CTL_SD_CMD);
+       sd_ctrl_write32(host, CTL_ARG_REG, cmd->arg);
+       sd_ctrl_write16(host, CTL_SD_CMD, c);
 
        return 0;
 }
@@ -183,7 +160,6 @@ tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command *cmd)
  */
 static inline void tmio_mmc_pio_irq(struct tmio_mmc_host *host)
 {
-       void __iomem *ctl = host->ctl;
        struct mmc_data *data = host->data;
        unsigned short *buf;
        unsigned int count;
@@ -206,9 +182,9 @@ static inline void tmio_mmc_pio_irq(struct tmio_mmc_host *host)
 
        /* Transfer the data */
        if (data->flags & MMC_DATA_READ)
-               tmio_ioread16_rep(ctl + CTL_SD_DATA_PORT, buf, count >> 1);
+               sd_ctrl_read16_rep(host, CTL_SD_DATA_PORT, buf, count >> 1);
        else
-               tmio_iowrite16_rep(ctl + CTL_SD_DATA_PORT, buf, count >> 1);
+               sd_ctrl_write16_rep(host, CTL_SD_DATA_PORT, buf, count >> 1);
 
        host->sg_off += count;
 
@@ -222,7 +198,6 @@ static inline void tmio_mmc_pio_irq(struct tmio_mmc_host *host)
 
 static inline void tmio_mmc_data_irq(struct tmio_mmc_host *host)
 {
-       void __iomem *ctl = host->ctl;
        struct mmc_data *data = host->data;
        struct mmc_command *stop;
 
@@ -251,13 +226,13 @@ static inline void tmio_mmc_data_irq(struct tmio_mmc_host *host)
         */
 
        if (data->flags & MMC_DATA_READ)
-               disable_mmc_irqs(ctl, TMIO_MASK_READOP);
+               disable_mmc_irqs(host, TMIO_MASK_READOP);
        else
-               disable_mmc_irqs(ctl, TMIO_MASK_WRITEOP);
+               disable_mmc_irqs(host, TMIO_MASK_WRITEOP);
 
        if (stop) {
                if (stop->opcode == 12 && !stop->arg)
-                       tmio_iowrite16(0x000, ctl + CTL_STOP_INTERNAL_ACTION);
+                       sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x000);
                else
                        BUG();
        }
@@ -268,9 +243,8 @@ static inline void tmio_mmc_data_irq(struct tmio_mmc_host *host)
 static inline void tmio_mmc_cmd_irq(struct tmio_mmc_host *host,
        unsigned int stat)
 {
-       void __iomem *ctl = host->ctl, *addr;
        struct mmc_command *cmd = host->cmd;
-       int i;
+       int i, addr;
 
        if (!host->cmd) {
                pr_debug("Spurious CMD irq\n");
@@ -284,8 +258,8 @@ static inline void tmio_mmc_cmd_irq(struct tmio_mmc_host *host,
         * modify the order of the response for short response command types.
         */
 
-       for (i = 3, addr = ctl + CTL_RESPONSE ; i >= 0 ; i--, addr += 4)
-               cmd->resp[i] = tmio_ioread32(addr);
+       for (i = 3, addr = CTL_RESPONSE ; i >= 0 ; i--, addr += 4)
+               cmd->resp[i] = sd_ctrl_read32(host, addr);
 
        if (cmd->flags &  MMC_RSP_136) {
                cmd->resp[0] = (cmd->resp[0] << 8) | (cmd->resp[1] >> 24);
@@ -307,9 +281,9 @@ static inline void tmio_mmc_cmd_irq(struct tmio_mmc_host *host,
         */
        if (host->data && !cmd->error) {
                if (host->data->flags & MMC_DATA_READ)
-                       enable_mmc_irqs(ctl, TMIO_MASK_READOP);
+                       enable_mmc_irqs(host, TMIO_MASK_READOP);
                else
-                       enable_mmc_irqs(ctl, TMIO_MASK_WRITEOP);
+                       enable_mmc_irqs(host, TMIO_MASK_WRITEOP);
        } else {
                tmio_mmc_finish_request(host);
        }
@@ -321,20 +295,19 @@ static inline void tmio_mmc_cmd_irq(struct tmio_mmc_host *host,
 static irqreturn_t tmio_mmc_irq(int irq, void *devid)
 {
        struct tmio_mmc_host *host = devid;
-       void __iomem *ctl = host->ctl;
        unsigned int ireg, irq_mask, status;
 
        pr_debug("MMC IRQ begin\n");
 
-       status = tmio_ioread32(ctl + CTL_STATUS);
-       irq_mask = tmio_ioread32(ctl + CTL_IRQ_MASK);
+       status = sd_ctrl_read32(host, CTL_STATUS);
+       irq_mask = sd_ctrl_read32(host, CTL_IRQ_MASK);
        ireg = status & TMIO_MASK_IRQ & ~irq_mask;
 
        pr_debug_status(status);
        pr_debug_status(ireg);
 
        if (!ireg) {
-               disable_mmc_irqs(ctl, status & ~irq_mask);
+               disable_mmc_irqs(host, status & ~irq_mask);
 
                pr_debug("tmio_mmc: Spurious irq, disabling! "
                        "0x%08x 0x%08x 0x%08x\n", status, irq_mask, ireg);
@@ -346,7 +319,7 @@ static irqreturn_t tmio_mmc_irq(int irq, void *devid)
        while (ireg) {
                /* Card insert / remove attempts */
                if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)) {
-                       ack_mmc_irqs(ctl, TMIO_STAT_CARD_INSERT |
+                       ack_mmc_irqs(host, TMIO_STAT_CARD_INSERT |
                                TMIO_STAT_CARD_REMOVE);
                        mmc_detect_change(host->mmc, 0);
                }
@@ -358,25 +331,25 @@ static irqreturn_t tmio_mmc_irq(int irq, void *devid)
 
                /* Command completion */
                if (ireg & TMIO_MASK_CMD) {
-                       ack_mmc_irqs(ctl, TMIO_MASK_CMD);
+                       ack_mmc_irqs(host, TMIO_MASK_CMD);
                        tmio_mmc_cmd_irq(host, status);
                }
 
                /* Data transfer */
                if (ireg & (TMIO_STAT_RXRDY | TMIO_STAT_TXRQ)) {
-                       ack_mmc_irqs(ctl, TMIO_STAT_RXRDY | TMIO_STAT_TXRQ);
+                       ack_mmc_irqs(host, TMIO_STAT_RXRDY | TMIO_STAT_TXRQ);
                        tmio_mmc_pio_irq(host);
                }
 
                /* Data transfer completion */
                if (ireg & TMIO_STAT_DATAEND) {
-                       ack_mmc_irqs(ctl, TMIO_STAT_DATAEND);
+                       ack_mmc_irqs(host, TMIO_STAT_DATAEND);
                        tmio_mmc_data_irq(host);
                }
 
                /* Check status - keep going until we've handled it all */
-               status = tmio_ioread32(ctl + CTL_STATUS);
-               irq_mask = tmio_ioread32(ctl + CTL_IRQ_MASK);
+               status = sd_ctrl_read32(host, CTL_STATUS);
+               irq_mask = sd_ctrl_read32(host, CTL_IRQ_MASK);
                ireg = status & TMIO_MASK_IRQ & ~irq_mask;
 
                pr_debug("Status at end of loop: %08x\n", status);
@@ -391,8 +364,6 @@ out:
 static int tmio_mmc_start_data(struct tmio_mmc_host *host,
        struct mmc_data *data)
 {
-       void __iomem *ctl = host->ctl;
-
        pr_debug("setup data transfer: blocksize %08x  nr_blocks %d\n",
            data->blksz, data->blocks);
 
@@ -407,8 +378,8 @@ static int tmio_mmc_start_data(struct tmio_mmc_host *host,
        host->data = data;
 
        /* Set transfer length / blocksize */
-       tmio_iowrite16(data->blksz,  ctl + CTL_SD_XFER_LEN);
-       tmio_iowrite16(data->blocks, ctl + CTL_XFER_BLK_COUNT);
+       sd_ctrl_write16(host, CTL_SD_XFER_LEN, data->blksz);
+       sd_ctrl_write16(host, CTL_XFER_BLK_COUNT, data->blocks);
 
        return 0;
 }
@@ -449,8 +420,6 @@ fail:
 static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
        struct tmio_mmc_host *host = mmc_priv(mmc);
-       void __iomem *cnf = host->cnf;
-       void __iomem *ctl = host->ctl;
 
        if (ios->clock)
                tmio_mmc_set_clock(host, ios->clock);
@@ -458,12 +427,12 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        /* Power sequence - OFF -> ON -> UP */
        switch (ios->power_mode) {
        case MMC_POWER_OFF: /* power down SD bus */
-               tmio_iowrite8(0x00, cnf + CNF_PWR_CTL_2);
+               sd_config_write8(host, CNF_PWR_CTL_2, 0x00);
                tmio_mmc_clk_stop(host);
                break;
        case MMC_POWER_ON: /* power up SD bus */
 
-               tmio_iowrite8(0x02, cnf + CNF_PWR_CTL_2);
+               sd_config_write8(host, CNF_PWR_CTL_2, 0x02);
                break;
        case MMC_POWER_UP: /* start bus clock */
                tmio_mmc_clk_start(host);
@@ -472,10 +441,10 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 
        switch (ios->bus_width) {
        case MMC_BUS_WIDTH_1:
-               tmio_iowrite16(0x80e0, ctl + CTL_SD_MEM_CARD_OPT);
+               sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0);
        break;
        case MMC_BUS_WIDTH_4:
-               tmio_iowrite16(0x00e0, ctl + CTL_SD_MEM_CARD_OPT);
+               sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0);
        break;
        }
 
@@ -486,9 +455,8 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 static int tmio_mmc_get_ro(struct mmc_host *mmc)
 {
        struct tmio_mmc_host *host = mmc_priv(mmc);
-       void __iomem *ctl = host->ctl;
 
-       return (tmio_ioread16(ctl + CTL_STATUS) & TMIO_STAT_WRPROTECT) ? 0 : 1;
+       return (sd_ctrl_read16(host, CTL_STATUS) & TMIO_STAT_WRPROTECT) ? 0 : 1;
 }
 
 static struct mmc_host_ops tmio_mmc_ops = {
@@ -518,13 +486,8 @@ static int tmio_mmc_resume(struct platform_device *dev)
        struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data;
        struct mmc_host *mmc = platform_get_drvdata(dev);
        struct tmio_mmc_host *host = mmc_priv(mmc);
-       void __iomem *cnf = host->cnf;
        int ret = 0;
 
-       /* Enable the MMC/SD Control registers */
-       tmio_iowrite16(SDCREN, cnf + CNF_CMD);
-       tmio_iowrite32(dev->resource[0].start & 0xfffe, cnf + CNF_CTL_BASE);
-
        /* Tell the MFD core we are ready to be enabled */
        if (cell->enable) {
                ret = cell->enable(dev);
@@ -532,6 +495,11 @@ static int tmio_mmc_resume(struct platform_device *dev)
                        goto out;
        }
 
+       /* Enable the MMC/SD Control registers */
+       sd_config_write16(host, CNF_CMD, SDCREN);
+       sd_config_write32(host, CNF_CTL_BASE,
+               (dev->resource[0].start >> host->bus_shift) & 0xfffe);
+
        mmc_resume_host(mmc);
 
 out:
@@ -545,20 +513,25 @@ out:
 static int __devinit tmio_mmc_probe(struct platform_device *dev)
 {
        struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data;
+       struct tmio_mmc_data *pdata;
        struct resource *res_ctl, *res_cnf;
        struct tmio_mmc_host *host;
        struct mmc_host *mmc;
-       int ret = -ENOMEM;
+       int ret = -EINVAL;
 
        if (dev->num_resources != 3)
                goto out;
 
        res_ctl = platform_get_resource(dev, IORESOURCE_MEM, 0);
        res_cnf = platform_get_resource(dev, IORESOURCE_MEM, 1);
-       if (!res_ctl || !res_cnf) {
-               ret = -EINVAL;
+       if (!res_ctl || !res_cnf)
                goto out;
-       }
+
+       pdata = cell->driver_data;
+       if (!pdata || !pdata->hclk)
+               goto out;
+
+       ret = -ENOMEM;
 
        mmc = mmc_alloc_host(sizeof(struct tmio_mmc_host), &dev->dev);
        if (!mmc)
@@ -568,6 +541,9 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
        host->mmc = mmc;
        platform_set_drvdata(dev, mmc);
 
+       /* SD control register space size is 0x200, 0x400 for bus_shift=1 */
+       host->bus_shift = resource_size(res_ctl) >> 10;
+
        host->ctl = ioremap(res_ctl->start, resource_size(res_ctl));
        if (!host->ctl)
                goto host_free;
@@ -578,15 +554,10 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
 
        mmc->ops = &tmio_mmc_ops;
        mmc->caps = MMC_CAP_4_BIT_DATA;
-       mmc->f_min = 46875; /* 24000000 / 512 */
-       mmc->f_max = 24000000;
+       mmc->f_max = pdata->hclk;
+       mmc->f_min = mmc->f_max / 512;
        mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
 
-       /* Enable the MMC/SD Control registers */
-       tmio_iowrite16(SDCREN, host->cnf + CNF_CMD);
-       tmio_iowrite32(dev->resource[0].start & 0xfffe,
-               host->cnf + CNF_CTL_BASE);
-
        /* Tell the MFD core we are ready to be enabled */
        if (cell->enable) {
                ret = cell->enable(dev);
@@ -594,14 +565,19 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
                        goto unmap_cnf;
        }
 
+       /* Enable the MMC/SD Control registers */
+       sd_config_write16(host, CNF_CMD, SDCREN);
+       sd_config_write32(host, CNF_CTL_BASE,
+               (dev->resource[0].start >> host->bus_shift) & 0xfffe);
+
        /* Disable SD power during suspend */
-       tmio_iowrite8(0x01, host->cnf + CNF_PWR_CTL_3);
+       sd_config_write8(host, CNF_PWR_CTL_3, 0x01);
 
        /* The below is required but why? FIXME */
-       tmio_iowrite8(0x1f, host->cnf + CNF_STOP_CLK_CTL);
+       sd_config_write8(host, CNF_STOP_CLK_CTL, 0x1f);
 
        /* Power down SD bus*/
-       tmio_iowrite8(0x0,  host->cnf + CNF_PWR_CTL_2);
+       sd_config_write8(host, CNF_PWR_CTL_2, 0x00);
 
        tmio_mmc_clk_stop(host);
        reset(host);
@@ -612,22 +588,20 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
        else
                goto unmap_cnf;
 
-       disable_mmc_irqs(host->ctl, TMIO_MASK_ALL);
+       disable_mmc_irqs(host, TMIO_MASK_ALL);
 
-       ret = request_irq(host->irq, tmio_mmc_irq, IRQF_DISABLED, "tmio-mmc",
-               host);
+       ret = request_irq(host->irq, tmio_mmc_irq, IRQF_DISABLED |
+               IRQF_TRIGGER_FALLING, "tmio-mmc", host);
        if (ret)
                goto unmap_cnf;
 
-       set_irq_type(host->irq, IRQ_TYPE_EDGE_FALLING);
-
        mmc_add_host(mmc);
 
        printk(KERN_INFO "%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc),
               (unsigned long)host->ctl, host->irq);
 
        /* Unmask the IRQs we want to know about */
-       enable_mmc_irqs(host->ctl,  TMIO_MASK_IRQ);
+       enable_mmc_irqs(host, TMIO_MASK_IRQ);
 
        return 0;
 
index 9c831ab2ece6d37af2bbfadce6311b85bc011c22..9fa9985949743be7920eccb0a1627036ea8dcc37 100644 (file)
                TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT)
 #define TMIO_MASK_IRQ     (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD)
 
-#define enable_mmc_irqs(ctl, i) \
+
+#define enable_mmc_irqs(host, i) \
        do { \
                u32 mask;\
-               mask  = tmio_ioread32((ctl) + CTL_IRQ_MASK); \
+               mask  = sd_ctrl_read32((host), CTL_IRQ_MASK); \
                mask &= ~((i) & TMIO_MASK_IRQ); \
-               tmio_iowrite32(mask, (ctl) + CTL_IRQ_MASK); \
+               sd_ctrl_write32((host), CTL_IRQ_MASK, mask); \
        } while (0)
 
-#define disable_mmc_irqs(ctl, i) \
+#define disable_mmc_irqs(host, i) \
        do { \
                u32 mask;\
-               mask  = tmio_ioread32((ctl) + CTL_IRQ_MASK); \
+               mask  = sd_ctrl_read32((host), CTL_IRQ_MASK); \
                mask |= ((i) & TMIO_MASK_IRQ); \
-               tmio_iowrite32(mask, (ctl) + CTL_IRQ_MASK); \
+               sd_ctrl_write32((host), CTL_IRQ_MASK, mask); \
        } while (0)
 
-#define ack_mmc_irqs(ctl, i) \
+#define ack_mmc_irqs(host, i) \
        do { \
                u32 mask;\
-               mask  = tmio_ioread32((ctl) + CTL_STATUS); \
+               mask  = sd_ctrl_read32((host), CTL_STATUS); \
                mask &= ~((i) & TMIO_MASK_IRQ); \
-               tmio_iowrite32(mask, (ctl) + CTL_STATUS); \
+               sd_ctrl_write32((host), CTL_STATUS, mask); \
        } while (0)
 
 
 struct tmio_mmc_host {
        void __iomem *cnf;
        void __iomem *ctl;
+       unsigned long bus_shift;
        struct mmc_command      *cmd;
        struct mmc_request      *mrq;
        struct mmc_data         *data;
@@ -123,6 +125,63 @@ struct tmio_mmc_host {
        unsigned int            sg_off;
 };
 
+#include <linux/io.h>
+
+static inline u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr)
+{
+       return readw(host->ctl + (addr << host->bus_shift));
+}
+
+static inline void sd_ctrl_read16_rep(struct tmio_mmc_host *host, int addr,
+               u16 *buf, int count)
+{
+       readsw(host->ctl + (addr << host->bus_shift), buf, count);
+}
+
+static inline u32 sd_ctrl_read32(struct tmio_mmc_host *host, int addr)
+{
+       return readw(host->ctl + (addr << host->bus_shift)) |
+              readw(host->ctl + ((addr + 2) << host->bus_shift)) << 16;
+}
+
+static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr,
+               u16 val)
+{
+       writew(val, host->ctl + (addr << host->bus_shift));
+}
+
+static inline void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr,
+               u16 *buf, int count)
+{
+       writesw(host->ctl + (addr << host->bus_shift), buf, count);
+}
+
+static inline void sd_ctrl_write32(struct tmio_mmc_host *host, int addr,
+               u32 val)
+{
+       writew(val, host->ctl + (addr << host->bus_shift));
+       writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift));
+}
+
+static inline void sd_config_write8(struct tmio_mmc_host *host, int addr,
+               u8 val)
+{
+       writeb(val, host->cnf + (addr << host->bus_shift));
+}
+
+static inline void sd_config_write16(struct tmio_mmc_host *host, int addr,
+               u16 val)
+{
+       writew(val, host->cnf + (addr << host->bus_shift));
+}
+
+static inline void sd_config_write32(struct tmio_mmc_host *host, int addr,
+               u32 val)
+{
+       writew(val, host->cnf + (addr << host->bus_shift));
+       writew(val >> 16, host->cnf + ((addr + 2) << host->bus_shift));
+}
+
 #include <linux/scatterlist.h>
 #include <linux/blkdev.h>
 
index 7d04fb9ddcaae15a2ae260c73697d3a99b1106d1..b8e35a0b4d72df589446f1ad026f35644d285b22 100644 (file)
@@ -154,7 +154,8 @@ config MTD_AFS_PARTS
 
          You will still need the parsing functions to be called by the driver
          for your particular device. It won't happen automatically. The
-         'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example.
+         'armflash' map driver (CONFIG_MTD_ARM_INTEGRATOR) does this, for
+         example.
 
 config MTD_OF_PARTS
        tristate "Flash partition map based on OF description"
index 6fde0a2e3567d589fb4757a12eb49929b1c6c463..325fab92a62ccec543e013e701667b8013d85649 100644 (file)
@@ -49,7 +49,7 @@ config MTD_MS02NV
          If you want to compile this driver as a module ( = code which can be
          inserted in and removed from the running kernel whenever you want),
          say M here and read <file:Documentation/kbuild/modules.txt>.
-         The module will be called ms02-nv.ko.
+         The module will be called ms02-nv.
 
 config MTD_DATAFLASH
        tristate "Support for AT45xxx DataFlash"
index 890936d0275ed21b957e2a46a9af52764a1fe28b..f3276897859e2b5e72af0317ab2b7c0a80e810be 100644 (file)
@@ -260,7 +260,7 @@ config MTD_NAND_BASLER_EXCITE
        help
           This enables the driver for the NAND flash device found on the
           Basler eXcite Smart Camera. If built as a module, the driver
-          will be named "excite_nandflash.ko".
+          will be named excite_nandflash.
 
 config MTD_NAND_CAFE
        tristate "NAND support for OLPC CAFÉ chip"
@@ -282,7 +282,7 @@ config MTD_NAND_CS553X
          controller is enabled for NAND, and currently requires that
          the controller be in MMIO mode.
 
-         If you say "m", the module will be called "cs553x_nand.ko".
+         If you say "m", the module will be called cs553x_nand.
 
 config MTD_NAND_ATMEL
        tristate "Support for NAND Flash / SmartMedia on AT91 and AVR32"
index f2e9de1414dfcdb4002419c72b60bf1d1ce4927f..6391e3dc80025ff243db8391facb4fddf6bf796e 100644 (file)
@@ -39,7 +39,6 @@
 #include <mach/gpmc.h>
 #include <mach/onenand.h>
 #include <mach/gpio.h>
-#include <mach/pm.h>
 
 #include <mach/dma.h>
 
index 214a92d1ef75938fd58f9adea4289074f5e11121..3111b6c7cbc3225e039de507559cdb334cbb2c30 100644 (file)
@@ -1880,7 +1880,7 @@ config FEC_MPC52xx
        ---help---
          This option enables support for the MPC5200's on-chip
          Fast Ethernet Controller
-         If compiled as module, it will be called 'fec_mpc52xx.ko'.
+         If compiled as module, it will be called fec_mpc52xx.
 
 config FEC_MPC52xx_MDIO
        bool "MPC52xx FEC MDIO bus driver"
@@ -1892,7 +1892,7 @@ config FEC_MPC52xx_MDIO
          (Motorola? industry standard).
          If your board uses an external PHY connected to FEC, enable this.
          If not sure, enable.
-         If compiled as module, it will be called 'fec_mpc52xx_phy.ko'.
+         If compiled as module, it will be called fec_mpc52xx_phy.
 
 config NE_H8300
        tristate "NE2000 compatible support for H8/300"
@@ -2264,6 +2264,17 @@ config BNX2
          To compile this driver as a module, choose M here: the module
          will be called bnx2.  This is recommended.
 
+config CNIC
+       tristate "Broadcom CNIC support"
+       depends on BNX2
+       depends on UIO
+       help
+         This driver supports offload features of Broadcom NetXtremeII
+         gigabit Ethernet cards.
+
+         To compile this driver as a module, choose M here: the module
+         will be called cnic.  This is recommended.
+
 config SPIDER_NET
        tristate "Spider Gigabit Ethernet driver"
        depends on PCI && (PPC_IBM_CELL_BLADE || PPC_CELLEB)
index a1c25cb4669fb8b9a95b7a1410355423d46b5599..db30ebd7b262336bb3949da5db58e7173d4bfa64 100644 (file)
@@ -73,6 +73,7 @@ obj-$(CONFIG_STNIC) += stnic.o 8390.o
 obj-$(CONFIG_FEALNX) += fealnx.o
 obj-$(CONFIG_TIGON3) += tg3.o
 obj-$(CONFIG_BNX2) += bnx2.o
+obj-$(CONFIG_CNIC) += cnic.o
 obj-$(CONFIG_BNX2X) += bnx2x.o
 bnx2x-objs := bnx2x_main.o bnx2x_link.o
 spidernet-y += spider_net.o spider_net_ethtool.o
index 78cc71469136350142d07ee34c72292e4678219c..b642647170be800fbfd85ab86ecc4cca2763f20d 100644 (file)
@@ -1220,7 +1220,7 @@ static int __init ltpc_setup(char *str)
                if (ints[0] > 2) {
                        dma = ints[3];
                }
-               /* ignore any other paramters */
+               /* ignore any other parameters */
        }
        return 1;
 }
index a740053d3af34c00c25a23e9223d8a9d5d0667c9..b6d188115caff792889899236972a5926ace1de8 100644 (file)
@@ -456,7 +456,8 @@ static inline void queue_put_desc(unsigned int queue, u32 phys,
        debug_desc(phys, desc);
        BUG_ON(phys & 0x1F);
        qmgr_put_entry(queue, phys);
-       BUG_ON(qmgr_stat_overflow(queue));
+       /* Don't check for queue overflow here, we've allocated sufficient
+          length and queues >= 32 don't support this check anyway. */
 }
 
 
@@ -512,8 +513,8 @@ static int eth_poll(struct napi_struct *napi, int budget)
 #endif
                        napi_complete(napi);
                        qmgr_enable_irq(rxq);
-                       if (!qmgr_stat_empty(rxq) &&
-                           napi_reschedule(napi)) {
+                       if (!qmgr_stat_below_low_watermark(rxq) &&
+                           napi_reschedule(napi)) { /* not empty again */
 #if DEBUG_RX
                                printk(KERN_DEBUG "%s: eth_poll"
                                       " napi_reschedule successed\n",
@@ -630,9 +631,9 @@ static void eth_txdone_irq(void *unused)
                        port->tx_buff_tab[n_desc] = NULL;
                }
 
-               start = qmgr_stat_empty(port->plat->txreadyq);
+               start = qmgr_stat_below_low_watermark(port->plat->txreadyq);
                queue_put_desc(port->plat->txreadyq, phys, desc);
-               if (start) {
+               if (start) { /* TX-ready queue was empty */
 #if DEBUG_TX
                        printk(KERN_DEBUG "%s: eth_txdone_irq xmit ready\n",
                               port->netdev->name);
@@ -708,13 +709,14 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev)
        queue_put_desc(TX_QUEUE(port->id), tx_desc_phys(port, n), desc);
        dev->trans_start = jiffies;
 
-       if (qmgr_stat_empty(txreadyq)) {
+       if (qmgr_stat_below_low_watermark(txreadyq)) { /* empty */
 #if DEBUG_TX
                printk(KERN_DEBUG "%s: eth_xmit queue full\n", dev->name);
 #endif
                netif_stop_queue(dev);
                /* we could miss TX ready interrupt */
-               if (!qmgr_stat_empty(txreadyq)) {
+               /* really empty in fact */
+               if (!qmgr_stat_below_low_watermark(txreadyq)) {
 #if DEBUG_TX
                        printk(KERN_DEBUG "%s: eth_xmit ready again\n",
                               dev->name);
@@ -814,29 +816,29 @@ static int request_queues(struct port *port)
        int err;
 
        err = qmgr_request_queue(RXFREE_QUEUE(port->id), RX_DESCS, 0, 0,
-                           "%s:RX-free", port->netdev->name);
+                                "%s:RX-free", port->netdev->name);
        if (err)
                return err;
 
        err = qmgr_request_queue(port->plat->rxq, RX_DESCS, 0, 0,
-                           "%s:RX", port->netdev->name);
+                                "%s:RX", port->netdev->name);
        if (err)
                goto rel_rxfree;
 
        err = qmgr_request_queue(TX_QUEUE(port->id), TX_DESCS, 0, 0,
-                           "%s:TX", port->netdev->name);
+                                "%s:TX", port->netdev->name);
        if (err)
                goto rel_rx;
 
        err = qmgr_request_queue(port->plat->txreadyq, TX_DESCS, 0, 0,
-                           "%s:TX-ready", port->netdev->name);
+                                "%s:TX-ready", port->netdev->name);
        if (err)
                goto rel_tx;
 
        /* TX-done queue handles skbs sent out by the NPEs */
        if (!ports_open) {
                err = qmgr_request_queue(TXDONE_QUEUE, TXDONE_QUEUE_LEN, 0, 0,
-                                   "%s:TX-done", DRV_NAME);
+                                        "%s:TX-done", DRV_NAME);
                if (err)
                        goto rel_txready;
        }
index e678498de6dbed9ee0948eec2ee2457912c9ef7f..d24158e7f3097261633d22a342cbdb249e415d01 100644 (file)
@@ -97,7 +97,7 @@
 #define B44_DMARX_STAT 0x021CUL /* DMA RX Current Active Desc. + Status */
 #define  DMARX_STAT_CDMASK     0x00000fff /* Current Descriptor Mask */
 #define  DMARX_STAT_SMASK      0x0000f000 /* State Mask */
-#define  DMARX_STAT_SDISABLED  0x00000000 /* State Disbaled */
+#define  DMARX_STAT_SDISABLED  0x00000000 /* State Disabled */
 #define  DMARX_STAT_SACTIVE    0x00001000 /* State Active */
 #define  DMARX_STAT_SIDLE      0x00002000 /* State Idle Wait */
 #define  DMARX_STAT_SSTOPPED   0x00003000 /* State Stopped */
index b0cb29d4cc01e735b7855e99f7e3a7c81650d3db..3f5fcb0156a180a49977f200b7a16fe5e19f6a38 100644 (file)
 #include <linux/firmware.h>
 #include <linux/log2.h>
 
+#if defined(CONFIG_CNIC) || defined(CONFIG_CNIC_MODULE)
+#define BCM_CNIC 1
+#include "cnic_if.h"
+#endif
 #include "bnx2.h"
 #include "bnx2_fw.h"
 
@@ -315,6 +319,158 @@ bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
        spin_unlock_bh(&bp->indirect_lock);
 }
 
+#ifdef BCM_CNIC
+static int
+bnx2_drv_ctl(struct net_device *dev, struct drv_ctl_info *info)
+{
+       struct bnx2 *bp = netdev_priv(dev);
+       struct drv_ctl_io *io = &info->data.io;
+
+       switch (info->cmd) {
+       case DRV_CTL_IO_WR_CMD:
+               bnx2_reg_wr_ind(bp, io->offset, io->data);
+               break;
+       case DRV_CTL_IO_RD_CMD:
+               io->data = bnx2_reg_rd_ind(bp, io->offset);
+               break;
+       case DRV_CTL_CTX_WR_CMD:
+               bnx2_ctx_wr(bp, io->cid_addr, io->offset, io->data);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static void bnx2_setup_cnic_irq_info(struct bnx2 *bp)
+{
+       struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+       struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
+       int sb_id;
+
+       if (bp->flags & BNX2_FLAG_USING_MSIX) {
+               cp->drv_state |= CNIC_DRV_STATE_USING_MSIX;
+               bnapi->cnic_present = 0;
+               sb_id = bp->irq_nvecs;
+               cp->irq_arr[0].irq_flags |= CNIC_IRQ_FL_MSIX;
+       } else {
+               cp->drv_state &= ~CNIC_DRV_STATE_USING_MSIX;
+               bnapi->cnic_tag = bnapi->last_status_idx;
+               bnapi->cnic_present = 1;
+               sb_id = 0;
+               cp->irq_arr[0].irq_flags &= ~CNIC_IRQ_FL_MSIX;
+       }
+
+       cp->irq_arr[0].vector = bp->irq_tbl[sb_id].vector;
+       cp->irq_arr[0].status_blk = (void *)
+               ((unsigned long) bnapi->status_blk.msi +
+               (BNX2_SBLK_MSIX_ALIGN_SIZE * sb_id));
+       cp->irq_arr[0].status_blk_num = sb_id;
+       cp->num_irq = 1;
+}
+
+static int bnx2_register_cnic(struct net_device *dev, struct cnic_ops *ops,
+                             void *data)
+{
+       struct bnx2 *bp = netdev_priv(dev);
+       struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+
+       if (ops == NULL)
+               return -EINVAL;
+
+       if (cp->drv_state & CNIC_DRV_STATE_REGD)
+               return -EBUSY;
+
+       bp->cnic_data = data;
+       rcu_assign_pointer(bp->cnic_ops, ops);
+
+       cp->num_irq = 0;
+       cp->drv_state = CNIC_DRV_STATE_REGD;
+
+       bnx2_setup_cnic_irq_info(bp);
+
+       return 0;
+}
+
+static int bnx2_unregister_cnic(struct net_device *dev)
+{
+       struct bnx2 *bp = netdev_priv(dev);
+       struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
+       struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+
+       cp->drv_state = 0;
+       bnapi->cnic_present = 0;
+       rcu_assign_pointer(bp->cnic_ops, NULL);
+       synchronize_rcu();
+       return 0;
+}
+
+struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev)
+{
+       struct bnx2 *bp = netdev_priv(dev);
+       struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+
+       cp->drv_owner = THIS_MODULE;
+       cp->chip_id = bp->chip_id;
+       cp->pdev = bp->pdev;
+       cp->io_base = bp->regview;
+       cp->drv_ctl = bnx2_drv_ctl;
+       cp->drv_register_cnic = bnx2_register_cnic;
+       cp->drv_unregister_cnic = bnx2_unregister_cnic;
+
+       return cp;
+}
+EXPORT_SYMBOL(bnx2_cnic_probe);
+
+static void
+bnx2_cnic_stop(struct bnx2 *bp)
+{
+       struct cnic_ops *c_ops;
+       struct cnic_ctl_info info;
+
+       rcu_read_lock();
+       c_ops = rcu_dereference(bp->cnic_ops);
+       if (c_ops) {
+               info.cmd = CNIC_CTL_STOP_CMD;
+               c_ops->cnic_ctl(bp->cnic_data, &info);
+       }
+       rcu_read_unlock();
+}
+
+static void
+bnx2_cnic_start(struct bnx2 *bp)
+{
+       struct cnic_ops *c_ops;
+       struct cnic_ctl_info info;
+
+       rcu_read_lock();
+       c_ops = rcu_dereference(bp->cnic_ops);
+       if (c_ops) {
+               if (!(bp->flags & BNX2_FLAG_USING_MSIX)) {
+                       struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
+
+                       bnapi->cnic_tag = bnapi->last_status_idx;
+               }
+               info.cmd = CNIC_CTL_START_CMD;
+               c_ops->cnic_ctl(bp->cnic_data, &info);
+       }
+       rcu_read_unlock();
+}
+
+#else
+
+static void
+bnx2_cnic_stop(struct bnx2 *bp)
+{
+}
+
+static void
+bnx2_cnic_start(struct bnx2 *bp)
+{
+}
+
+#endif
+
 static int
 bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
 {
@@ -488,6 +644,7 @@ bnx2_napi_enable(struct bnx2 *bp)
 static void
 bnx2_netif_stop(struct bnx2 *bp)
 {
+       bnx2_cnic_stop(bp);
        bnx2_disable_int_sync(bp);
        if (netif_running(bp->dev)) {
                bnx2_napi_disable(bp);
@@ -504,6 +661,7 @@ bnx2_netif_start(struct bnx2 *bp)
                        netif_tx_wake_all_queues(bp->dev);
                        bnx2_napi_enable(bp);
                        bnx2_enable_int(bp);
+                       bnx2_cnic_start(bp);
                }
        }
 }
@@ -3164,6 +3322,11 @@ bnx2_has_work(struct bnx2_napi *bnapi)
        if (bnx2_has_fast_work(bnapi))
                return 1;
 
+#ifdef BCM_CNIC
+       if (bnapi->cnic_present && (bnapi->cnic_tag != sblk->status_idx))
+               return 1;
+#endif
+
        if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) !=
            (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS))
                return 1;
@@ -3193,6 +3356,23 @@ bnx2_chk_missed_msi(struct bnx2 *bp)
        bp->idle_chk_status_idx = bnapi->last_status_idx;
 }
 
+#ifdef BCM_CNIC
+static void bnx2_poll_cnic(struct bnx2 *bp, struct bnx2_napi *bnapi)
+{
+       struct cnic_ops *c_ops;
+
+       if (!bnapi->cnic_present)
+               return;
+
+       rcu_read_lock();
+       c_ops = rcu_dereference(bp->cnic_ops);
+       if (c_ops)
+               bnapi->cnic_tag = c_ops->cnic_handler(bp->cnic_data,
+                                                     bnapi->status_blk.msi);
+       rcu_read_unlock();
+}
+#endif
+
 static void bnx2_poll_link(struct bnx2 *bp, struct bnx2_napi *bnapi)
 {
        struct status_block *sblk = bnapi->status_blk.msi;
@@ -3267,6 +3447,10 @@ static int bnx2_poll(struct napi_struct *napi, int budget)
 
                work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
 
+#ifdef BCM_CNIC
+               bnx2_poll_cnic(bp, bnapi);
+#endif
+
                /* bnapi->last_status_idx is used below to tell the hw how
                 * much work has been processed, so we must read it before
                 * checking for more work.
@@ -4632,8 +4816,11 @@ bnx2_init_chip(struct bnx2 *bp)
        val = REG_RD(bp, BNX2_MQ_CONFIG);
        val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
        val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256;
-       if (CHIP_ID(bp) == CHIP_ID_5709_A0 || CHIP_ID(bp) == CHIP_ID_5709_A1)
-               val |= BNX2_MQ_CONFIG_HALT_DIS;
+       if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+               val |= BNX2_MQ_CONFIG_BIN_MQ_MODE;
+               if (CHIP_REV(bp) == CHIP_REV_Ax)
+                       val |= BNX2_MQ_CONFIG_HALT_DIS;
+       }
 
        REG_WR(bp, BNX2_MQ_CONFIG, val);
 
@@ -7471,7 +7658,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        INIT_WORK(&bp->reset_task, bnx2_reset_task);
 
        dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0);
-       mem_len = MB_GET_CID_ADDR(TX_TSS_CID + TX_MAX_TSS_RINGS);
+       mem_len = MB_GET_CID_ADDR(TX_TSS_CID + TX_MAX_TSS_RINGS + 1);
        dev->mem_end = dev->mem_start + mem_len;
        dev->irq = pdev->irq;
 
index 5b570e17c839a2d35db6fba9f27da71a1efaf41e..a1ff739bc9b5e5709f6e3093bf516ace7d148515 100644 (file)
@@ -361,6 +361,9 @@ struct l2_fhdr {
 #define BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE       (1<<28)
 
 #define BNX2_L2CTX_HOST_BDIDX                          0x00000004
+#define BNX2_L2CTX_STATUSB_NUM_SHIFT                    16
+#define BNX2_L2CTX_STATUSB_NUM(sb_id)                   \
+       (((sb_id) > 0) ? (((sb_id) + 7) << BNX2_L2CTX_STATUSB_NUM_SHIFT) : 0)
 #define BNX2_L2CTX_HOST_BSEQ                           0x00000008
 #define BNX2_L2CTX_NX_BSEQ                             0x0000000c
 #define BNX2_L2CTX_NX_BDHADDR_HI                       0x00000010
@@ -5900,6 +5903,7 @@ struct l2_fhdr {
 #define BNX2_RXP_FTQ_CTL_CUR_DEPTH                      (0x3ffL<<22)
 
 #define BNX2_RXP_SCRATCH                               0x000e0000
+#define BNX2_RXP_SCRATCH_RXP_FLOOD                      0x000e0024
 #define BNX2_RXP_SCRATCH_RSS_TBL_SZ                     0x000e0038
 #define BNX2_RXP_SCRATCH_RSS_TBL                        0x000e003c
 #define BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES            128
@@ -6678,6 +6682,11 @@ struct bnx2_napi {
        u32                     last_status_idx;
        u32                     int_num;
 
+#ifdef BCM_CNIC
+       u32                     cnic_tag;
+       int                     cnic_present;
+#endif
+
        struct bnx2_rx_ring_info        rx_ring;
        struct bnx2_tx_ring_info        tx_ring;
 };
@@ -6727,6 +6736,11 @@ struct bnx2 {
        int             tx_ring_size;
        u32             tx_wake_thresh;
 
+#ifdef BCM_CNIC
+       struct cnic_ops         *cnic_ops;
+       void                    *cnic_data;
+#endif
+
        /* End of fields used in the performance code paths. */
 
        unsigned int            current_interval;
@@ -6885,6 +6899,10 @@ struct bnx2 {
 
        u32                     idle_chk_status_idx;
 
+#ifdef BCM_CNIC
+       struct cnic_eth_dev     cnic_eth_dev;
+#endif
+
        const struct firmware   *mips_firmware;
        const struct firmware   *rv2p_firmware;
 };
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
new file mode 100644 (file)
index 0000000..44f77eb
--- /dev/null
@@ -0,0 +1,2717 @@
+/* cnic.c: Broadcom CNIC core network driver.
+ *
+ * Copyright (c) 2006-2009 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Original skeleton written by: John(Zongxi) Chen (zongxi@broadcom.com)
+ * Modified and maintained by: Michael Chan <mchan@broadcom.com>
+ */
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/uio_driver.h>
+#include <linux/in.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/module.h>
+
+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+#define BCM_VLAN 1
+#endif
+#include <net/ip.h>
+#include <net/tcp.h>
+#include <net/route.h>
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+#include <scsi/iscsi_if.h>
+
+#include "cnic_if.h"
+#include "bnx2.h"
+#include "cnic.h"
+#include "cnic_defs.h"
+
+#define DRV_MODULE_NAME                "cnic"
+#define PFX DRV_MODULE_NAME    ": "
+
+static char version[] __devinitdata =
+       "Broadcom NetXtreme II CNIC Driver " DRV_MODULE_NAME " v" CNIC_MODULE_VERSION " (" CNIC_MODULE_RELDATE ")\n";
+
+MODULE_AUTHOR("Michael Chan <mchan@broadcom.com> and John(Zongxi) "
+             "Chen (zongxi@broadcom.com");
+MODULE_DESCRIPTION("Broadcom NetXtreme II CNIC Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(CNIC_MODULE_VERSION);
+
+static LIST_HEAD(cnic_dev_list);
+static DEFINE_RWLOCK(cnic_dev_lock);
+static DEFINE_MUTEX(cnic_lock);
+
+static struct cnic_ulp_ops *cnic_ulp_tbl[MAX_CNIC_ULP_TYPE];
+
+static int cnic_service_bnx2(void *, void *);
+static int cnic_ctl(void *, struct cnic_ctl_info *);
+
+static struct cnic_ops cnic_bnx2_ops = {
+       .cnic_owner     = THIS_MODULE,
+       .cnic_handler   = cnic_service_bnx2,
+       .cnic_ctl       = cnic_ctl,
+};
+
+static void cnic_shutdown_bnx2_rx_ring(struct cnic_dev *);
+static void cnic_init_bnx2_tx_ring(struct cnic_dev *);
+static void cnic_init_bnx2_rx_ring(struct cnic_dev *);
+static int cnic_cm_set_pg(struct cnic_sock *);
+
+static int cnic_uio_open(struct uio_info *uinfo, struct inode *inode)
+{
+       struct cnic_dev *dev = uinfo->priv;
+       struct cnic_local *cp = dev->cnic_priv;
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       if (cp->uio_dev != -1)
+               return -EBUSY;
+
+       cp->uio_dev = iminor(inode);
+
+       cnic_shutdown_bnx2_rx_ring(dev);
+
+       cnic_init_bnx2_tx_ring(dev);
+       cnic_init_bnx2_rx_ring(dev);
+
+       return 0;
+}
+
+static int cnic_uio_close(struct uio_info *uinfo, struct inode *inode)
+{
+       struct cnic_dev *dev = uinfo->priv;
+       struct cnic_local *cp = dev->cnic_priv;
+
+       cp->uio_dev = -1;
+       return 0;
+}
+
+static inline void cnic_hold(struct cnic_dev *dev)
+{
+       atomic_inc(&dev->ref_count);
+}
+
+static inline void cnic_put(struct cnic_dev *dev)
+{
+       atomic_dec(&dev->ref_count);
+}
+
+static inline void csk_hold(struct cnic_sock *csk)
+{
+       atomic_inc(&csk->ref_count);
+}
+
+static inline void csk_put(struct cnic_sock *csk)
+{
+       atomic_dec(&csk->ref_count);
+}
+
+static struct cnic_dev *cnic_from_netdev(struct net_device *netdev)
+{
+       struct cnic_dev *cdev;
+
+       read_lock(&cnic_dev_lock);
+       list_for_each_entry(cdev, &cnic_dev_list, list) {
+               if (netdev == cdev->netdev) {
+                       cnic_hold(cdev);
+                       read_unlock(&cnic_dev_lock);
+                       return cdev;
+               }
+       }
+       read_unlock(&cnic_dev_lock);
+       return NULL;
+}
+
+static void cnic_ctx_wr(struct cnic_dev *dev, u32 cid_addr, u32 off, u32 val)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       struct cnic_eth_dev *ethdev = cp->ethdev;
+       struct drv_ctl_info info;
+       struct drv_ctl_io *io = &info.data.io;
+
+       info.cmd = DRV_CTL_CTX_WR_CMD;
+       io->cid_addr = cid_addr;
+       io->offset = off;
+       io->data = val;
+       ethdev->drv_ctl(dev->netdev, &info);
+}
+
+static void cnic_reg_wr_ind(struct cnic_dev *dev, u32 off, u32 val)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       struct cnic_eth_dev *ethdev = cp->ethdev;
+       struct drv_ctl_info info;
+       struct drv_ctl_io *io = &info.data.io;
+
+       info.cmd = DRV_CTL_IO_WR_CMD;
+       io->offset = off;
+       io->data = val;
+       ethdev->drv_ctl(dev->netdev, &info);
+}
+
+static u32 cnic_reg_rd_ind(struct cnic_dev *dev, u32 off)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       struct cnic_eth_dev *ethdev = cp->ethdev;
+       struct drv_ctl_info info;
+       struct drv_ctl_io *io = &info.data.io;
+
+       info.cmd = DRV_CTL_IO_RD_CMD;
+       io->offset = off;
+       ethdev->drv_ctl(dev->netdev, &info);
+       return io->data;
+}
+
+static int cnic_in_use(struct cnic_sock *csk)
+{
+       return test_bit(SK_F_INUSE, &csk->flags);
+}
+
+static void cnic_kwq_completion(struct cnic_dev *dev, u32 count)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       struct cnic_eth_dev *ethdev = cp->ethdev;
+       struct drv_ctl_info info;
+
+       info.cmd = DRV_CTL_COMPLETION_CMD;
+       info.data.comp.comp_count = count;
+       ethdev->drv_ctl(dev->netdev, &info);
+}
+
+static int cnic_send_nlmsg(struct cnic_local *cp, u32 type,
+                          struct cnic_sock *csk)
+{
+       struct iscsi_path path_req;
+       char *buf = NULL;
+       u16 len = 0;
+       u32 msg_type = ISCSI_KEVENT_IF_DOWN;
+       struct cnic_ulp_ops *ulp_ops;
+
+       if (cp->uio_dev == -1)
+               return -ENODEV;
+
+       if (csk) {
+               len = sizeof(path_req);
+               buf = (char *) &path_req;
+               memset(&path_req, 0, len);
+
+               msg_type = ISCSI_KEVENT_PATH_REQ;
+               path_req.handle = (u64) csk->l5_cid;
+               if (test_bit(SK_F_IPV6, &csk->flags)) {
+                       memcpy(&path_req.dst.v6_addr, &csk->dst_ip[0],
+                              sizeof(struct in6_addr));
+                       path_req.ip_addr_len = 16;
+               } else {
+                       memcpy(&path_req.dst.v4_addr, &csk->dst_ip[0],
+                              sizeof(struct in_addr));
+                       path_req.ip_addr_len = 4;
+               }
+               path_req.vlan_id = csk->vlan_id;
+               path_req.pmtu = csk->mtu;
+       }
+
+       rcu_read_lock();
+       ulp_ops = rcu_dereference(cp->ulp_ops[CNIC_ULP_ISCSI]);
+       if (ulp_ops)
+               ulp_ops->iscsi_nl_send_msg(cp->dev, msg_type, buf, len);
+       rcu_read_unlock();
+       return 0;
+}
+
+static int cnic_iscsi_nl_msg_recv(struct cnic_dev *dev, u32 msg_type,
+                                 char *buf, u16 len)
+{
+       int rc = -EINVAL;
+
+       switch (msg_type) {
+       case ISCSI_UEVENT_PATH_UPDATE: {
+               struct cnic_local *cp;
+               u32 l5_cid;
+               struct cnic_sock *csk;
+               struct iscsi_path *path_resp;
+
+               if (len < sizeof(*path_resp))
+                       break;
+
+               path_resp = (struct iscsi_path *) buf;
+               cp = dev->cnic_priv;
+               l5_cid = (u32) path_resp->handle;
+               if (l5_cid >= MAX_CM_SK_TBL_SZ)
+                       break;
+
+               csk = &cp->csk_tbl[l5_cid];
+               csk_hold(csk);
+               if (cnic_in_use(csk)) {
+                       memcpy(csk->ha, path_resp->mac_addr, 6);
+                       if (test_bit(SK_F_IPV6, &csk->flags))
+                               memcpy(&csk->src_ip[0], &path_resp->src.v6_addr,
+                                      sizeof(struct in6_addr));
+                       else
+                               memcpy(&csk->src_ip[0], &path_resp->src.v4_addr,
+                                      sizeof(struct in_addr));
+                       if (is_valid_ether_addr(csk->ha))
+                               cnic_cm_set_pg(csk);
+               }
+               csk_put(csk);
+               rc = 0;
+       }
+       }
+
+       return rc;
+}
+
+static int cnic_offld_prep(struct cnic_sock *csk)
+{
+       if (test_and_set_bit(SK_F_OFFLD_SCHED, &csk->flags))
+               return 0;
+
+       if (!test_bit(SK_F_CONNECT_START, &csk->flags)) {
+               clear_bit(SK_F_OFFLD_SCHED, &csk->flags);
+               return 0;
+       }
+
+       return 1;
+}
+
+static int cnic_close_prep(struct cnic_sock *csk)
+{
+       clear_bit(SK_F_CONNECT_START, &csk->flags);
+       smp_mb__after_clear_bit();
+
+       if (test_and_clear_bit(SK_F_OFFLD_COMPLETE, &csk->flags)) {
+               while (test_and_set_bit(SK_F_OFFLD_SCHED, &csk->flags))
+                       msleep(1);
+
+               return 1;
+       }
+       return 0;
+}
+
+static int cnic_abort_prep(struct cnic_sock *csk)
+{
+       clear_bit(SK_F_CONNECT_START, &csk->flags);
+       smp_mb__after_clear_bit();
+
+       while (test_and_set_bit(SK_F_OFFLD_SCHED, &csk->flags))
+               msleep(1);
+
+       if (test_and_clear_bit(SK_F_OFFLD_COMPLETE, &csk->flags)) {
+               csk->state = L4_KCQE_OPCODE_VALUE_RESET_COMP;
+               return 1;
+       }
+
+       return 0;
+}
+
+int cnic_register_driver(int ulp_type, struct cnic_ulp_ops *ulp_ops)
+{
+       struct cnic_dev *dev;
+
+       if (ulp_type >= MAX_CNIC_ULP_TYPE) {
+               printk(KERN_ERR PFX "cnic_register_driver: Bad type %d\n",
+                      ulp_type);
+               return -EINVAL;
+       }
+       mutex_lock(&cnic_lock);
+       if (cnic_ulp_tbl[ulp_type]) {
+               printk(KERN_ERR PFX "cnic_register_driver: Type %d has already "
+                                   "been registered\n", ulp_type);
+               mutex_unlock(&cnic_lock);
+               return -EBUSY;
+       }
+
+       read_lock(&cnic_dev_lock);
+       list_for_each_entry(dev, &cnic_dev_list, list) {
+               struct cnic_local *cp = dev->cnic_priv;
+
+               clear_bit(ULP_F_INIT, &cp->ulp_flags[ulp_type]);
+       }
+       read_unlock(&cnic_dev_lock);
+
+       rcu_assign_pointer(cnic_ulp_tbl[ulp_type], ulp_ops);
+       mutex_unlock(&cnic_lock);
+
+       /* Prevent race conditions with netdev_event */
+       rtnl_lock();
+       read_lock(&cnic_dev_lock);
+       list_for_each_entry(dev, &cnic_dev_list, list) {
+               struct cnic_local *cp = dev->cnic_priv;
+
+               if (!test_and_set_bit(ULP_F_INIT, &cp->ulp_flags[ulp_type]))
+                       ulp_ops->cnic_init(dev);
+       }
+       read_unlock(&cnic_dev_lock);
+       rtnl_unlock();
+
+       return 0;
+}
+
+int cnic_unregister_driver(int ulp_type)
+{
+       struct cnic_dev *dev;
+
+       if (ulp_type >= MAX_CNIC_ULP_TYPE) {
+               printk(KERN_ERR PFX "cnic_unregister_driver: Bad type %d\n",
+                      ulp_type);
+               return -EINVAL;
+       }
+       mutex_lock(&cnic_lock);
+       if (!cnic_ulp_tbl[ulp_type]) {
+               printk(KERN_ERR PFX "cnic_unregister_driver: Type %d has not "
+                                   "been registered\n", ulp_type);
+               goto out_unlock;
+       }
+       read_lock(&cnic_dev_lock);
+       list_for_each_entry(dev, &cnic_dev_list, list) {
+               struct cnic_local *cp = dev->cnic_priv;
+
+               if (rcu_dereference(cp->ulp_ops[ulp_type])) {
+                       printk(KERN_ERR PFX "cnic_unregister_driver: Type %d "
+                              "still has devices registered\n", ulp_type);
+                       read_unlock(&cnic_dev_lock);
+                       goto out_unlock;
+               }
+       }
+       read_unlock(&cnic_dev_lock);
+
+       rcu_assign_pointer(cnic_ulp_tbl[ulp_type], NULL);
+
+       mutex_unlock(&cnic_lock);
+       synchronize_rcu();
+       return 0;
+
+out_unlock:
+       mutex_unlock(&cnic_lock);
+       return -EINVAL;
+}
+
+static int cnic_start_hw(struct cnic_dev *);
+static void cnic_stop_hw(struct cnic_dev *);
+
+static int cnic_register_device(struct cnic_dev *dev, int ulp_type,
+                               void *ulp_ctx)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       struct cnic_ulp_ops *ulp_ops;
+
+       if (ulp_type >= MAX_CNIC_ULP_TYPE) {
+               printk(KERN_ERR PFX "cnic_register_device: Bad type %d\n",
+                      ulp_type);
+               return -EINVAL;
+       }
+       mutex_lock(&cnic_lock);
+       if (cnic_ulp_tbl[ulp_type] == NULL) {
+               printk(KERN_ERR PFX "cnic_register_device: Driver with type %d "
+                                   "has not been registered\n", ulp_type);
+               mutex_unlock(&cnic_lock);
+               return -EAGAIN;
+       }
+       if (rcu_dereference(cp->ulp_ops[ulp_type])) {
+               printk(KERN_ERR PFX "cnic_register_device: Type %d has already "
+                      "been registered to this device\n", ulp_type);
+               mutex_unlock(&cnic_lock);
+               return -EBUSY;
+       }
+
+       clear_bit(ULP_F_START, &cp->ulp_flags[ulp_type]);
+       cp->ulp_handle[ulp_type] = ulp_ctx;
+       ulp_ops = cnic_ulp_tbl[ulp_type];
+       rcu_assign_pointer(cp->ulp_ops[ulp_type], ulp_ops);
+       cnic_hold(dev);
+
+       if (test_bit(CNIC_F_CNIC_UP, &dev->flags))
+               if (!test_and_set_bit(ULP_F_START, &cp->ulp_flags[ulp_type]))
+                       ulp_ops->cnic_start(cp->ulp_handle[ulp_type]);
+
+       mutex_unlock(&cnic_lock);
+
+       return 0;
+
+}
+EXPORT_SYMBOL(cnic_register_driver);
+
+static int cnic_unregister_device(struct cnic_dev *dev, int ulp_type)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+
+       if (ulp_type >= MAX_CNIC_ULP_TYPE) {
+               printk(KERN_ERR PFX "cnic_unregister_device: Bad type %d\n",
+                      ulp_type);
+               return -EINVAL;
+       }
+       mutex_lock(&cnic_lock);
+       if (rcu_dereference(cp->ulp_ops[ulp_type])) {
+               rcu_assign_pointer(cp->ulp_ops[ulp_type], NULL);
+               cnic_put(dev);
+       } else {
+               printk(KERN_ERR PFX "cnic_unregister_device: device not "
+                      "registered to this ulp type %d\n", ulp_type);
+               mutex_unlock(&cnic_lock);
+               return -EINVAL;
+       }
+       mutex_unlock(&cnic_lock);
+
+       synchronize_rcu();
+
+       return 0;
+}
+EXPORT_SYMBOL(cnic_unregister_driver);
+
+static int cnic_init_id_tbl(struct cnic_id_tbl *id_tbl, u32 size, u32 start_id)
+{
+       id_tbl->start = start_id;
+       id_tbl->max = size;
+       id_tbl->next = 0;
+       spin_lock_init(&id_tbl->lock);
+       id_tbl->table = kzalloc(DIV_ROUND_UP(size, 32) * 4, GFP_KERNEL);
+       if (!id_tbl->table)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void cnic_free_id_tbl(struct cnic_id_tbl *id_tbl)
+{
+       kfree(id_tbl->table);
+       id_tbl->table = NULL;
+}
+
+static int cnic_alloc_id(struct cnic_id_tbl *id_tbl, u32 id)
+{
+       int ret = -1;
+
+       id -= id_tbl->start;
+       if (id >= id_tbl->max)
+               return ret;
+
+       spin_lock(&id_tbl->lock);
+       if (!test_bit(id, id_tbl->table)) {
+               set_bit(id, id_tbl->table);
+               ret = 0;
+       }
+       spin_unlock(&id_tbl->lock);
+       return ret;
+}
+
+/* Returns -1 if not successful */
+static u32 cnic_alloc_new_id(struct cnic_id_tbl *id_tbl)
+{
+       u32 id;
+
+       spin_lock(&id_tbl->lock);
+       id = find_next_zero_bit(id_tbl->table, id_tbl->max, id_tbl->next);
+       if (id >= id_tbl->max) {
+               id = -1;
+               if (id_tbl->next != 0) {
+                       id = find_first_zero_bit(id_tbl->table, id_tbl->next);
+                       if (id >= id_tbl->next)
+                               id = -1;
+               }
+       }
+
+       if (id < id_tbl->max) {
+               set_bit(id, id_tbl->table);
+               id_tbl->next = (id + 1) & (id_tbl->max - 1);
+               id += id_tbl->start;
+       }
+
+       spin_unlock(&id_tbl->lock);
+
+       return id;
+}
+
+static void cnic_free_id(struct cnic_id_tbl *id_tbl, u32 id)
+{
+       if (id == -1)
+               return;
+
+       id -= id_tbl->start;
+       if (id >= id_tbl->max)
+               return;
+
+       clear_bit(id, id_tbl->table);
+}
+
+static void cnic_free_dma(struct cnic_dev *dev, struct cnic_dma *dma)
+{
+       int i;
+
+       if (!dma->pg_arr)
+               return;
+
+       for (i = 0; i < dma->num_pages; i++) {
+               if (dma->pg_arr[i]) {
+                       pci_free_consistent(dev->pcidev, BCM_PAGE_SIZE,
+                                           dma->pg_arr[i], dma->pg_map_arr[i]);
+                       dma->pg_arr[i] = NULL;
+               }
+       }
+       if (dma->pgtbl) {
+               pci_free_consistent(dev->pcidev, dma->pgtbl_size,
+                                   dma->pgtbl, dma->pgtbl_map);
+               dma->pgtbl = NULL;
+       }
+       kfree(dma->pg_arr);
+       dma->pg_arr = NULL;
+       dma->num_pages = 0;
+}
+
+static void cnic_setup_page_tbl(struct cnic_dev *dev, struct cnic_dma *dma)
+{
+       int i;
+       u32 *page_table = dma->pgtbl;
+
+       for (i = 0; i < dma->num_pages; i++) {
+               /* Each entry needs to be in big endian format. */
+               *page_table = (u32) ((u64) dma->pg_map_arr[i] >> 32);
+               page_table++;
+               *page_table = (u32) dma->pg_map_arr[i];
+               page_table++;
+       }
+}
+
+static int cnic_alloc_dma(struct cnic_dev *dev, struct cnic_dma *dma,
+                         int pages, int use_pg_tbl)
+{
+       int i, size;
+       struct cnic_local *cp = dev->cnic_priv;
+
+       size = pages * (sizeof(void *) + sizeof(dma_addr_t));
+       dma->pg_arr = kzalloc(size, GFP_ATOMIC);
+       if (dma->pg_arr == NULL)
+               return -ENOMEM;
+
+       dma->pg_map_arr = (dma_addr_t *) (dma->pg_arr + pages);
+       dma->num_pages = pages;
+
+       for (i = 0; i < pages; i++) {
+               dma->pg_arr[i] = pci_alloc_consistent(dev->pcidev,
+                                                     BCM_PAGE_SIZE,
+                                                     &dma->pg_map_arr[i]);
+               if (dma->pg_arr[i] == NULL)
+                       goto error;
+       }
+       if (!use_pg_tbl)
+               return 0;
+
+       dma->pgtbl_size = ((pages * 8) + BCM_PAGE_SIZE - 1) &
+                         ~(BCM_PAGE_SIZE - 1);
+       dma->pgtbl = pci_alloc_consistent(dev->pcidev, dma->pgtbl_size,
+                                         &dma->pgtbl_map);
+       if (dma->pgtbl == NULL)
+               goto error;
+
+       cp->setup_pgtbl(dev, dma);
+
+       return 0;
+
+error:
+       cnic_free_dma(dev, dma);
+       return -ENOMEM;
+}
+
+static void cnic_free_resc(struct cnic_dev *dev)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       int i = 0;
+
+       if (cp->cnic_uinfo) {
+               cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL);
+               while (cp->uio_dev != -1 && i < 15) {
+                       msleep(100);
+                       i++;
+               }
+               uio_unregister_device(cp->cnic_uinfo);
+               kfree(cp->cnic_uinfo);
+               cp->cnic_uinfo = NULL;
+       }
+
+       if (cp->l2_buf) {
+               pci_free_consistent(dev->pcidev, cp->l2_buf_size,
+                                   cp->l2_buf, cp->l2_buf_map);
+               cp->l2_buf = NULL;
+       }
+
+       if (cp->l2_ring) {
+               pci_free_consistent(dev->pcidev, cp->l2_ring_size,
+                                   cp->l2_ring, cp->l2_ring_map);
+               cp->l2_ring = NULL;
+       }
+
+       for (i = 0; i < cp->ctx_blks; i++) {
+               if (cp->ctx_arr[i].ctx) {
+                       pci_free_consistent(dev->pcidev, cp->ctx_blk_size,
+                                           cp->ctx_arr[i].ctx,
+                                           cp->ctx_arr[i].mapping);
+                       cp->ctx_arr[i].ctx = NULL;
+               }
+       }
+       kfree(cp->ctx_arr);
+       cp->ctx_arr = NULL;
+       cp->ctx_blks = 0;
+
+       cnic_free_dma(dev, &cp->gbl_buf_info);
+       cnic_free_dma(dev, &cp->conn_buf_info);
+       cnic_free_dma(dev, &cp->kwq_info);
+       cnic_free_dma(dev, &cp->kcq_info);
+       kfree(cp->iscsi_tbl);
+       cp->iscsi_tbl = NULL;
+       kfree(cp->ctx_tbl);
+       cp->ctx_tbl = NULL;
+
+       cnic_free_id_tbl(&cp->cid_tbl);
+}
+
+static int cnic_alloc_context(struct cnic_dev *dev)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+
+       if (CHIP_NUM(cp) == CHIP_NUM_5709) {
+               int i, k, arr_size;
+
+               cp->ctx_blk_size = BCM_PAGE_SIZE;
+               cp->cids_per_blk = BCM_PAGE_SIZE / 128;
+               arr_size = BNX2_MAX_CID / cp->cids_per_blk *
+                          sizeof(struct cnic_ctx);
+               cp->ctx_arr = kzalloc(arr_size, GFP_KERNEL);
+               if (cp->ctx_arr == NULL)
+                       return -ENOMEM;
+
+               k = 0;
+               for (i = 0; i < 2; i++) {
+                       u32 j, reg, off, lo, hi;
+
+                       if (i == 0)
+                               off = BNX2_PG_CTX_MAP;
+                       else
+                               off = BNX2_ISCSI_CTX_MAP;
+
+                       reg = cnic_reg_rd_ind(dev, off);
+                       lo = reg >> 16;
+                       hi = reg & 0xffff;
+                       for (j = lo; j < hi; j += cp->cids_per_blk, k++)
+                               cp->ctx_arr[k].cid = j;
+               }
+
+               cp->ctx_blks = k;
+               if (cp->ctx_blks >= (BNX2_MAX_CID / cp->cids_per_blk)) {
+                       cp->ctx_blks = 0;
+                       return -ENOMEM;
+               }
+
+               for (i = 0; i < cp->ctx_blks; i++) {
+                       cp->ctx_arr[i].ctx =
+                               pci_alloc_consistent(dev->pcidev, BCM_PAGE_SIZE,
+                                                    &cp->ctx_arr[i].mapping);
+                       if (cp->ctx_arr[i].ctx == NULL)
+                               return -ENOMEM;
+               }
+       }
+       return 0;
+}
+
+static int cnic_alloc_bnx2_resc(struct cnic_dev *dev)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       struct uio_info *uinfo;
+       int ret;
+
+       ret = cnic_alloc_dma(dev, &cp->kwq_info, KWQ_PAGE_CNT, 1);
+       if (ret)
+               goto error;
+       cp->kwq = (struct kwqe **) cp->kwq_info.pg_arr;
+
+       ret = cnic_alloc_dma(dev, &cp->kcq_info, KCQ_PAGE_CNT, 1);
+       if (ret)
+               goto error;
+       cp->kcq = (struct kcqe **) cp->kcq_info.pg_arr;
+
+       ret = cnic_alloc_context(dev);
+       if (ret)
+               goto error;
+
+       cp->l2_ring_size = 2 * BCM_PAGE_SIZE;
+       cp->l2_ring = pci_alloc_consistent(dev->pcidev, cp->l2_ring_size,
+                                          &cp->l2_ring_map);
+       if (!cp->l2_ring)
+               goto error;
+
+       cp->l2_buf_size = (cp->l2_rx_ring_size + 1) * cp->l2_single_buf_size;
+       cp->l2_buf_size = PAGE_ALIGN(cp->l2_buf_size);
+       cp->l2_buf = pci_alloc_consistent(dev->pcidev, cp->l2_buf_size,
+                                          &cp->l2_buf_map);
+       if (!cp->l2_buf)
+               goto error;
+
+       uinfo = kzalloc(sizeof(*uinfo), GFP_ATOMIC);
+       if (!uinfo)
+               goto error;
+
+       uinfo->mem[0].addr = dev->netdev->base_addr;
+       uinfo->mem[0].internal_addr = dev->regview;
+       uinfo->mem[0].size = dev->netdev->mem_end - dev->netdev->mem_start;
+       uinfo->mem[0].memtype = UIO_MEM_PHYS;
+
+       uinfo->mem[1].addr = (unsigned long) cp->status_blk & PAGE_MASK;
+       if (cp->ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX)
+               uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE * 9;
+       else
+               uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE;
+       uinfo->mem[1].memtype = UIO_MEM_LOGICAL;
+
+       uinfo->mem[2].addr = (unsigned long) cp->l2_ring;
+       uinfo->mem[2].size = cp->l2_ring_size;
+       uinfo->mem[2].memtype = UIO_MEM_LOGICAL;
+
+       uinfo->mem[3].addr = (unsigned long) cp->l2_buf;
+       uinfo->mem[3].size = cp->l2_buf_size;
+       uinfo->mem[3].memtype = UIO_MEM_LOGICAL;
+
+       uinfo->name = "bnx2_cnic";
+       uinfo->version = CNIC_MODULE_VERSION;
+       uinfo->irq = UIO_IRQ_CUSTOM;
+
+       uinfo->open = cnic_uio_open;
+       uinfo->release = cnic_uio_close;
+
+       uinfo->priv = dev;
+
+       ret = uio_register_device(&dev->pcidev->dev, uinfo);
+       if (ret) {
+               kfree(uinfo);
+               goto error;
+       }
+
+       cp->cnic_uinfo = uinfo;
+
+       return 0;
+
+error:
+       cnic_free_resc(dev);
+       return ret;
+}
+
+static inline u32 cnic_kwq_avail(struct cnic_local *cp)
+{
+       return cp->max_kwq_idx -
+               ((cp->kwq_prod_idx - cp->kwq_con_idx) & cp->max_kwq_idx);
+}
+
+static int cnic_submit_bnx2_kwqes(struct cnic_dev *dev, struct kwqe *wqes[],
+                                 u32 num_wqes)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       struct kwqe *prod_qe;
+       u16 prod, sw_prod, i;
+
+       if (!test_bit(CNIC_F_CNIC_UP, &dev->flags))
+               return -EAGAIN;         /* bnx2 is down */
+
+       spin_lock_bh(&cp->cnic_ulp_lock);
+       if (num_wqes > cnic_kwq_avail(cp) &&
+           !(cp->cnic_local_flags & CNIC_LCL_FL_KWQ_INIT)) {
+               spin_unlock_bh(&cp->cnic_ulp_lock);
+               return -EAGAIN;
+       }
+
+       cp->cnic_local_flags &= ~CNIC_LCL_FL_KWQ_INIT;
+
+       prod = cp->kwq_prod_idx;
+       sw_prod = prod & MAX_KWQ_IDX;
+       for (i = 0; i < num_wqes; i++) {
+               prod_qe = &cp->kwq[KWQ_PG(sw_prod)][KWQ_IDX(sw_prod)];
+               memcpy(prod_qe, wqes[i], sizeof(struct kwqe));
+               prod++;
+               sw_prod = prod & MAX_KWQ_IDX;
+       }
+       cp->kwq_prod_idx = prod;
+
+       CNIC_WR16(dev, cp->kwq_io_addr, cp->kwq_prod_idx);
+
+       spin_unlock_bh(&cp->cnic_ulp_lock);
+       return 0;
+}
+
+static void service_kcqes(struct cnic_dev *dev, int num_cqes)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       int i, j;
+
+       i = 0;
+       j = 1;
+       while (num_cqes) {
+               struct cnic_ulp_ops *ulp_ops;
+               int ulp_type;
+               u32 kcqe_op_flag = cp->completed_kcq[i]->kcqe_op_flag;
+               u32 kcqe_layer = kcqe_op_flag & KCQE_FLAGS_LAYER_MASK;
+
+               if (unlikely(kcqe_op_flag & KCQE_RAMROD_COMPLETION))
+                       cnic_kwq_completion(dev, 1);
+
+               while (j < num_cqes) {
+                       u32 next_op = cp->completed_kcq[i + j]->kcqe_op_flag;
+
+                       if ((next_op & KCQE_FLAGS_LAYER_MASK) != kcqe_layer)
+                               break;
+
+                       if (unlikely(next_op & KCQE_RAMROD_COMPLETION))
+                               cnic_kwq_completion(dev, 1);
+                       j++;
+               }
+
+               if (kcqe_layer == KCQE_FLAGS_LAYER_MASK_L5_RDMA)
+                       ulp_type = CNIC_ULP_RDMA;
+               else if (kcqe_layer == KCQE_FLAGS_LAYER_MASK_L5_ISCSI)
+                       ulp_type = CNIC_ULP_ISCSI;
+               else if (kcqe_layer == KCQE_FLAGS_LAYER_MASK_L4)
+                       ulp_type = CNIC_ULP_L4;
+               else if (kcqe_layer == KCQE_FLAGS_LAYER_MASK_L2)
+                       goto end;
+               else {
+                       printk(KERN_ERR PFX "%s: Unknown type of KCQE(0x%x)\n",
+                              dev->netdev->name, kcqe_op_flag);
+                       goto end;
+               }
+
+               rcu_read_lock();
+               ulp_ops = rcu_dereference(cp->ulp_ops[ulp_type]);
+               if (likely(ulp_ops)) {
+                       ulp_ops->indicate_kcqes(cp->ulp_handle[ulp_type],
+                                                 cp->completed_kcq + i, j);
+               }
+               rcu_read_unlock();
+end:
+               num_cqes -= j;
+               i += j;
+               j = 1;
+       }
+       return;
+}
+
+static u16 cnic_bnx2_next_idx(u16 idx)
+{
+       return idx + 1;
+}
+
+static u16 cnic_bnx2_hw_idx(u16 idx)
+{
+       return idx;
+}
+
+static int cnic_get_kcqes(struct cnic_dev *dev, u16 hw_prod, u16 *sw_prod)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       u16 i, ri, last;
+       struct kcqe *kcqe;
+       int kcqe_cnt = 0, last_cnt = 0;
+
+       i = ri = last = *sw_prod;
+       ri &= MAX_KCQ_IDX;
+
+       while ((i != hw_prod) && (kcqe_cnt < MAX_COMPLETED_KCQE)) {
+               kcqe = &cp->kcq[KCQ_PG(ri)][KCQ_IDX(ri)];
+               cp->completed_kcq[kcqe_cnt++] = kcqe;
+               i = cp->next_idx(i);
+               ri = i & MAX_KCQ_IDX;
+               if (likely(!(kcqe->kcqe_op_flag & KCQE_FLAGS_NEXT))) {
+                       last_cnt = kcqe_cnt;
+                       last = i;
+               }
+       }
+
+       *sw_prod = last;
+       return last_cnt;
+}
+
+static void cnic_chk_bnx2_pkt_rings(struct cnic_local *cp)
+{
+       u16 rx_cons = *cp->rx_cons_ptr;
+       u16 tx_cons = *cp->tx_cons_ptr;
+
+       if (cp->tx_cons != tx_cons || cp->rx_cons != rx_cons) {
+               cp->tx_cons = tx_cons;
+               cp->rx_cons = rx_cons;
+               uio_event_notify(cp->cnic_uinfo);
+       }
+}
+
+static int cnic_service_bnx2(void *data, void *status_blk)
+{
+       struct cnic_dev *dev = data;
+       struct status_block *sblk = status_blk;
+       struct cnic_local *cp = dev->cnic_priv;
+       u32 status_idx = sblk->status_idx;
+       u16 hw_prod, sw_prod;
+       int kcqe_cnt;
+
+       if (unlikely(!test_bit(CNIC_F_CNIC_UP, &dev->flags)))
+               return status_idx;
+
+       cp->kwq_con_idx = *cp->kwq_con_idx_ptr;
+
+       hw_prod = sblk->status_completion_producer_index;
+       sw_prod = cp->kcq_prod_idx;
+       while (sw_prod != hw_prod) {
+               kcqe_cnt = cnic_get_kcqes(dev, hw_prod, &sw_prod);
+               if (kcqe_cnt == 0)
+                       goto done;
+
+               service_kcqes(dev, kcqe_cnt);
+
+               /* Tell compiler that status_blk fields can change. */
+               barrier();
+               if (status_idx != sblk->status_idx) {
+                       status_idx = sblk->status_idx;
+                       cp->kwq_con_idx = *cp->kwq_con_idx_ptr;
+                       hw_prod = sblk->status_completion_producer_index;
+               } else
+                       break;
+       }
+
+done:
+       CNIC_WR16(dev, cp->kcq_io_addr, sw_prod);
+
+       cp->kcq_prod_idx = sw_prod;
+
+       cnic_chk_bnx2_pkt_rings(cp);
+       return status_idx;
+}
+
+static void cnic_service_bnx2_msix(unsigned long data)
+{
+       struct cnic_dev *dev = (struct cnic_dev *) data;
+       struct cnic_local *cp = dev->cnic_priv;
+       struct status_block_msix *status_blk = cp->bnx2_status_blk;
+       u32 status_idx = status_blk->status_idx;
+       u16 hw_prod, sw_prod;
+       int kcqe_cnt;
+
+       cp->kwq_con_idx = status_blk->status_cmd_consumer_index;
+
+       hw_prod = status_blk->status_completion_producer_index;
+       sw_prod = cp->kcq_prod_idx;
+       while (sw_prod != hw_prod) {
+               kcqe_cnt = cnic_get_kcqes(dev, hw_prod, &sw_prod);
+               if (kcqe_cnt == 0)
+                       goto done;
+
+               service_kcqes(dev, kcqe_cnt);
+
+               /* Tell compiler that status_blk fields can change. */
+               barrier();
+               if (status_idx != status_blk->status_idx) {
+                       status_idx = status_blk->status_idx;
+                       cp->kwq_con_idx = status_blk->status_cmd_consumer_index;
+                       hw_prod = status_blk->status_completion_producer_index;
+               } else
+                       break;
+       }
+
+done:
+       CNIC_WR16(dev, cp->kcq_io_addr, sw_prod);
+       cp->kcq_prod_idx = sw_prod;
+
+       cnic_chk_bnx2_pkt_rings(cp);
+
+       cp->last_status_idx = status_idx;
+       CNIC_WR(dev, BNX2_PCICFG_INT_ACK_CMD, cp->int_num |
+               BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | cp->last_status_idx);
+}
+
+static irqreturn_t cnic_irq(int irq, void *dev_instance)
+{
+       struct cnic_dev *dev = dev_instance;
+       struct cnic_local *cp = dev->cnic_priv;
+       u16 prod = cp->kcq_prod_idx & MAX_KCQ_IDX;
+
+       if (cp->ack_int)
+               cp->ack_int(dev);
+
+       prefetch(cp->status_blk);
+       prefetch(&cp->kcq[KCQ_PG(prod)][KCQ_IDX(prod)]);
+
+       if (likely(test_bit(CNIC_F_CNIC_UP, &dev->flags)))
+               tasklet_schedule(&cp->cnic_irq_task);
+
+       return IRQ_HANDLED;
+}
+
+static void cnic_ulp_stop(struct cnic_dev *dev)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       int if_type;
+
+       rcu_read_lock();
+       for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) {
+               struct cnic_ulp_ops *ulp_ops;
+
+               ulp_ops = rcu_dereference(cp->ulp_ops[if_type]);
+               if (!ulp_ops)
+                       continue;
+
+               if (test_and_clear_bit(ULP_F_START, &cp->ulp_flags[if_type]))
+                       ulp_ops->cnic_stop(cp->ulp_handle[if_type]);
+       }
+       rcu_read_unlock();
+}
+
+static void cnic_ulp_start(struct cnic_dev *dev)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       int if_type;
+
+       rcu_read_lock();
+       for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) {
+               struct cnic_ulp_ops *ulp_ops;
+
+               ulp_ops = rcu_dereference(cp->ulp_ops[if_type]);
+               if (!ulp_ops || !ulp_ops->cnic_start)
+                       continue;
+
+               if (!test_and_set_bit(ULP_F_START, &cp->ulp_flags[if_type]))
+                       ulp_ops->cnic_start(cp->ulp_handle[if_type]);
+       }
+       rcu_read_unlock();
+}
+
+static int cnic_ctl(void *data, struct cnic_ctl_info *info)
+{
+       struct cnic_dev *dev = data;
+
+       switch (info->cmd) {
+       case CNIC_CTL_STOP_CMD:
+               cnic_hold(dev);
+               mutex_lock(&cnic_lock);
+
+               cnic_ulp_stop(dev);
+               cnic_stop_hw(dev);
+
+               mutex_unlock(&cnic_lock);
+               cnic_put(dev);
+               break;
+       case CNIC_CTL_START_CMD:
+               cnic_hold(dev);
+               mutex_lock(&cnic_lock);
+
+               if (!cnic_start_hw(dev))
+                       cnic_ulp_start(dev);
+
+               mutex_unlock(&cnic_lock);
+               cnic_put(dev);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static void cnic_ulp_init(struct cnic_dev *dev)
+{
+       int i;
+       struct cnic_local *cp = dev->cnic_priv;
+
+       rcu_read_lock();
+       for (i = 0; i < MAX_CNIC_ULP_TYPE_EXT; i++) {
+               struct cnic_ulp_ops *ulp_ops;
+
+               ulp_ops = rcu_dereference(cnic_ulp_tbl[i]);
+               if (!ulp_ops || !ulp_ops->cnic_init)
+                       continue;
+
+               if (!test_and_set_bit(ULP_F_INIT, &cp->ulp_flags[i]))
+                       ulp_ops->cnic_init(dev);
+
+       }
+       rcu_read_unlock();
+}
+
+static void cnic_ulp_exit(struct cnic_dev *dev)
+{
+       int i;
+       struct cnic_local *cp = dev->cnic_priv;
+
+       rcu_read_lock();
+       for (i = 0; i < MAX_CNIC_ULP_TYPE_EXT; i++) {
+               struct cnic_ulp_ops *ulp_ops;
+
+               ulp_ops = rcu_dereference(cnic_ulp_tbl[i]);
+               if (!ulp_ops || !ulp_ops->cnic_exit)
+                       continue;
+
+               if (test_and_clear_bit(ULP_F_INIT, &cp->ulp_flags[i]))
+                       ulp_ops->cnic_exit(dev);
+
+       }
+       rcu_read_unlock();
+}
+
+static int cnic_cm_offload_pg(struct cnic_sock *csk)
+{
+       struct cnic_dev *dev = csk->dev;
+       struct l4_kwq_offload_pg *l4kwqe;
+       struct kwqe *wqes[1];
+
+       l4kwqe = (struct l4_kwq_offload_pg *) &csk->kwqe1;
+       memset(l4kwqe, 0, sizeof(*l4kwqe));
+       wqes[0] = (struct kwqe *) l4kwqe;
+
+       l4kwqe->op_code = L4_KWQE_OPCODE_VALUE_OFFLOAD_PG;
+       l4kwqe->flags =
+               L4_LAYER_CODE << L4_KWQ_OFFLOAD_PG_LAYER_CODE_SHIFT;
+       l4kwqe->l2hdr_nbytes = ETH_HLEN;
+
+       l4kwqe->da0 = csk->ha[0];
+       l4kwqe->da1 = csk->ha[1];
+       l4kwqe->da2 = csk->ha[2];
+       l4kwqe->da3 = csk->ha[3];
+       l4kwqe->da4 = csk->ha[4];
+       l4kwqe->da5 = csk->ha[5];
+
+       l4kwqe->sa0 = dev->mac_addr[0];
+       l4kwqe->sa1 = dev->mac_addr[1];
+       l4kwqe->sa2 = dev->mac_addr[2];
+       l4kwqe->sa3 = dev->mac_addr[3];
+       l4kwqe->sa4 = dev->mac_addr[4];
+       l4kwqe->sa5 = dev->mac_addr[5];
+
+       l4kwqe->etype = ETH_P_IP;
+       l4kwqe->ipid_count = DEF_IPID_COUNT;
+       l4kwqe->host_opaque = csk->l5_cid;
+
+       if (csk->vlan_id) {
+               l4kwqe->pg_flags |= L4_KWQ_OFFLOAD_PG_VLAN_TAGGING;
+               l4kwqe->vlan_tag = csk->vlan_id;
+               l4kwqe->l2hdr_nbytes += 4;
+       }
+
+       return dev->submit_kwqes(dev, wqes, 1);
+}
+
+static int cnic_cm_update_pg(struct cnic_sock *csk)
+{
+       struct cnic_dev *dev = csk->dev;
+       struct l4_kwq_update_pg *l4kwqe;
+       struct kwqe *wqes[1];
+
+       l4kwqe = (struct l4_kwq_update_pg *) &csk->kwqe1;
+       memset(l4kwqe, 0, sizeof(*l4kwqe));
+       wqes[0] = (struct kwqe *) l4kwqe;
+
+       l4kwqe->opcode = L4_KWQE_OPCODE_VALUE_UPDATE_PG;
+       l4kwqe->flags =
+               L4_LAYER_CODE << L4_KWQ_UPDATE_PG_LAYER_CODE_SHIFT;
+       l4kwqe->pg_cid = csk->pg_cid;
+
+       l4kwqe->da0 = csk->ha[0];
+       l4kwqe->da1 = csk->ha[1];
+       l4kwqe->da2 = csk->ha[2];
+       l4kwqe->da3 = csk->ha[3];
+       l4kwqe->da4 = csk->ha[4];
+       l4kwqe->da5 = csk->ha[5];
+
+       l4kwqe->pg_host_opaque = csk->l5_cid;
+       l4kwqe->pg_valids = L4_KWQ_UPDATE_PG_VALIDS_DA;
+
+       return dev->submit_kwqes(dev, wqes, 1);
+}
+
+static int cnic_cm_upload_pg(struct cnic_sock *csk)
+{
+       struct cnic_dev *dev = csk->dev;
+       struct l4_kwq_upload *l4kwqe;
+       struct kwqe *wqes[1];
+
+       l4kwqe = (struct l4_kwq_upload *) &csk->kwqe1;
+       memset(l4kwqe, 0, sizeof(*l4kwqe));
+       wqes[0] = (struct kwqe *) l4kwqe;
+
+       l4kwqe->opcode = L4_KWQE_OPCODE_VALUE_UPLOAD_PG;
+       l4kwqe->flags =
+               L4_LAYER_CODE << L4_KWQ_UPLOAD_LAYER_CODE_SHIFT;
+       l4kwqe->cid = csk->pg_cid;
+
+       return dev->submit_kwqes(dev, wqes, 1);
+}
+
+static int cnic_cm_conn_req(struct cnic_sock *csk)
+{
+       struct cnic_dev *dev = csk->dev;
+       struct l4_kwq_connect_req1 *l4kwqe1;
+       struct l4_kwq_connect_req2 *l4kwqe2;
+       struct l4_kwq_connect_req3 *l4kwqe3;
+       struct kwqe *wqes[3];
+       u8 tcp_flags = 0;
+       int num_wqes = 2;
+
+       l4kwqe1 = (struct l4_kwq_connect_req1 *) &csk->kwqe1;
+       l4kwqe2 = (struct l4_kwq_connect_req2 *) &csk->kwqe2;
+       l4kwqe3 = (struct l4_kwq_connect_req3 *) &csk->kwqe3;
+       memset(l4kwqe1, 0, sizeof(*l4kwqe1));
+       memset(l4kwqe2, 0, sizeof(*l4kwqe2));
+       memset(l4kwqe3, 0, sizeof(*l4kwqe3));
+
+       l4kwqe3->op_code = L4_KWQE_OPCODE_VALUE_CONNECT3;
+       l4kwqe3->flags =
+               L4_LAYER_CODE << L4_KWQ_CONNECT_REQ3_LAYER_CODE_SHIFT;
+       l4kwqe3->ka_timeout = csk->ka_timeout;
+       l4kwqe3->ka_interval = csk->ka_interval;
+       l4kwqe3->ka_max_probe_count = csk->ka_max_probe_count;
+       l4kwqe3->tos = csk->tos;
+       l4kwqe3->ttl = csk->ttl;
+       l4kwqe3->snd_seq_scale = csk->snd_seq_scale;
+       l4kwqe3->pmtu = csk->mtu;
+       l4kwqe3->rcv_buf = csk->rcv_buf;
+       l4kwqe3->snd_buf = csk->snd_buf;
+       l4kwqe3->seed = csk->seed;
+
+       wqes[0] = (struct kwqe *) l4kwqe1;
+       if (test_bit(SK_F_IPV6, &csk->flags)) {
+               wqes[1] = (struct kwqe *) l4kwqe2;
+               wqes[2] = (struct kwqe *) l4kwqe3;
+               num_wqes = 3;
+
+               l4kwqe1->conn_flags = L4_KWQ_CONNECT_REQ1_IP_V6;
+               l4kwqe2->op_code = L4_KWQE_OPCODE_VALUE_CONNECT2;
+               l4kwqe2->flags =
+                       L4_KWQ_CONNECT_REQ2_LINKED_WITH_NEXT |
+                       L4_LAYER_CODE << L4_KWQ_CONNECT_REQ2_LAYER_CODE_SHIFT;
+               l4kwqe2->src_ip_v6_2 = be32_to_cpu(csk->src_ip[1]);
+               l4kwqe2->src_ip_v6_3 = be32_to_cpu(csk->src_ip[2]);
+               l4kwqe2->src_ip_v6_4 = be32_to_cpu(csk->src_ip[3]);
+               l4kwqe2->dst_ip_v6_2 = be32_to_cpu(csk->dst_ip[1]);
+               l4kwqe2->dst_ip_v6_3 = be32_to_cpu(csk->dst_ip[2]);
+               l4kwqe2->dst_ip_v6_4 = be32_to_cpu(csk->dst_ip[3]);
+               l4kwqe3->mss = l4kwqe3->pmtu - sizeof(struct ipv6hdr) -
+                              sizeof(struct tcphdr);
+       } else {
+               wqes[1] = (struct kwqe *) l4kwqe3;
+               l4kwqe3->mss = l4kwqe3->pmtu - sizeof(struct iphdr) -
+                              sizeof(struct tcphdr);
+       }
+
+       l4kwqe1->op_code = L4_KWQE_OPCODE_VALUE_CONNECT1;
+       l4kwqe1->flags =
+               (L4_LAYER_CODE << L4_KWQ_CONNECT_REQ1_LAYER_CODE_SHIFT) |
+                L4_KWQ_CONNECT_REQ3_LINKED_WITH_NEXT;
+       l4kwqe1->cid = csk->cid;
+       l4kwqe1->pg_cid = csk->pg_cid;
+       l4kwqe1->src_ip = be32_to_cpu(csk->src_ip[0]);
+       l4kwqe1->dst_ip = be32_to_cpu(csk->dst_ip[0]);
+       l4kwqe1->src_port = be16_to_cpu(csk->src_port);
+       l4kwqe1->dst_port = be16_to_cpu(csk->dst_port);
+       if (csk->tcp_flags & SK_TCP_NO_DELAY_ACK)
+               tcp_flags |= L4_KWQ_CONNECT_REQ1_NO_DELAY_ACK;
+       if (csk->tcp_flags & SK_TCP_KEEP_ALIVE)
+               tcp_flags |= L4_KWQ_CONNECT_REQ1_KEEP_ALIVE;
+       if (csk->tcp_flags & SK_TCP_NAGLE)
+               tcp_flags |= L4_KWQ_CONNECT_REQ1_NAGLE_ENABLE;
+       if (csk->tcp_flags & SK_TCP_TIMESTAMP)
+               tcp_flags |= L4_KWQ_CONNECT_REQ1_TIME_STAMP;
+       if (csk->tcp_flags & SK_TCP_SACK)
+               tcp_flags |= L4_KWQ_CONNECT_REQ1_SACK;
+       if (csk->tcp_flags & SK_TCP_SEG_SCALING)
+               tcp_flags |= L4_KWQ_CONNECT_REQ1_SEG_SCALING;
+
+       l4kwqe1->tcp_flags = tcp_flags;
+
+       return dev->submit_kwqes(dev, wqes, num_wqes);
+}
+
+static int cnic_cm_close_req(struct cnic_sock *csk)
+{
+       struct cnic_dev *dev = csk->dev;
+       struct l4_kwq_close_req *l4kwqe;
+       struct kwqe *wqes[1];
+
+       l4kwqe = (struct l4_kwq_close_req *) &csk->kwqe2;
+       memset(l4kwqe, 0, sizeof(*l4kwqe));
+       wqes[0] = (struct kwqe *) l4kwqe;
+
+       l4kwqe->op_code = L4_KWQE_OPCODE_VALUE_CLOSE;
+       l4kwqe->flags = L4_LAYER_CODE << L4_KWQ_CLOSE_REQ_LAYER_CODE_SHIFT;
+       l4kwqe->cid = csk->cid;
+
+       return dev->submit_kwqes(dev, wqes, 1);
+}
+
+static int cnic_cm_abort_req(struct cnic_sock *csk)
+{
+       struct cnic_dev *dev = csk->dev;
+       struct l4_kwq_reset_req *l4kwqe;
+       struct kwqe *wqes[1];
+
+       l4kwqe = (struct l4_kwq_reset_req *) &csk->kwqe2;
+       memset(l4kwqe, 0, sizeof(*l4kwqe));
+       wqes[0] = (struct kwqe *) l4kwqe;
+
+       l4kwqe->op_code = L4_KWQE_OPCODE_VALUE_RESET;
+       l4kwqe->flags = L4_LAYER_CODE << L4_KWQ_RESET_REQ_LAYER_CODE_SHIFT;
+       l4kwqe->cid = csk->cid;
+
+       return dev->submit_kwqes(dev, wqes, 1);
+}
+
+static int cnic_cm_create(struct cnic_dev *dev, int ulp_type, u32 cid,
+                         u32 l5_cid, struct cnic_sock **csk, void *context)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       struct cnic_sock *csk1;
+
+       if (l5_cid >= MAX_CM_SK_TBL_SZ)
+               return -EINVAL;
+
+       csk1 = &cp->csk_tbl[l5_cid];
+       if (atomic_read(&csk1->ref_count))
+               return -EAGAIN;
+
+       if (test_and_set_bit(SK_F_INUSE, &csk1->flags))
+               return -EBUSY;
+
+       csk1->dev = dev;
+       csk1->cid = cid;
+       csk1->l5_cid = l5_cid;
+       csk1->ulp_type = ulp_type;
+       csk1->context = context;
+
+       csk1->ka_timeout = DEF_KA_TIMEOUT;
+       csk1->ka_interval = DEF_KA_INTERVAL;
+       csk1->ka_max_probe_count = DEF_KA_MAX_PROBE_COUNT;
+       csk1->tos = DEF_TOS;
+       csk1->ttl = DEF_TTL;
+       csk1->snd_seq_scale = DEF_SND_SEQ_SCALE;
+       csk1->rcv_buf = DEF_RCV_BUF;
+       csk1->snd_buf = DEF_SND_BUF;
+       csk1->seed = DEF_SEED;
+
+       *csk = csk1;
+       return 0;
+}
+
+static void cnic_cm_cleanup(struct cnic_sock *csk)
+{
+       if (csk->src_port) {
+               struct cnic_dev *dev = csk->dev;
+               struct cnic_local *cp = dev->cnic_priv;
+
+               cnic_free_id(&cp->csk_port_tbl, csk->src_port);
+               csk->src_port = 0;
+       }
+}
+
+static void cnic_close_conn(struct cnic_sock *csk)
+{
+       if (test_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags)) {
+               cnic_cm_upload_pg(csk);
+               clear_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags);
+       }
+       cnic_cm_cleanup(csk);
+}
+
+static int cnic_cm_destroy(struct cnic_sock *csk)
+{
+       if (!cnic_in_use(csk))
+               return -EINVAL;
+
+       csk_hold(csk);
+       clear_bit(SK_F_INUSE, &csk->flags);
+       smp_mb__after_clear_bit();
+       while (atomic_read(&csk->ref_count) != 1)
+               msleep(1);
+       cnic_cm_cleanup(csk);
+
+       csk->flags = 0;
+       csk_put(csk);
+       return 0;
+}
+
+static inline u16 cnic_get_vlan(struct net_device *dev,
+                               struct net_device **vlan_dev)
+{
+       if (dev->priv_flags & IFF_802_1Q_VLAN) {
+               *vlan_dev = vlan_dev_real_dev(dev);
+               return vlan_dev_vlan_id(dev);
+       }
+       *vlan_dev = dev;
+       return 0;
+}
+
+static int cnic_get_v4_route(struct sockaddr_in *dst_addr,
+                            struct dst_entry **dst)
+{
+#if defined(CONFIG_INET)
+       struct flowi fl;
+       int err;
+       struct rtable *rt;
+
+       memset(&fl, 0, sizeof(fl));
+       fl.nl_u.ip4_u.daddr = dst_addr->sin_addr.s_addr;
+
+       err = ip_route_output_key(&init_net, &rt, &fl);
+       if (!err)
+               *dst = &rt->u.dst;
+       return err;
+#else
+       return -ENETUNREACH;
+#endif
+}
+
+static int cnic_get_v6_route(struct sockaddr_in6 *dst_addr,
+                            struct dst_entry **dst)
+{
+#if defined(CONFIG_IPV6) || (defined(CONFIG_IPV6_MODULE) && defined(MODULE))
+       struct flowi fl;
+
+       memset(&fl, 0, sizeof(fl));
+       ipv6_addr_copy(&fl.fl6_dst, &dst_addr->sin6_addr);
+       if (ipv6_addr_type(&fl.fl6_dst) & IPV6_ADDR_LINKLOCAL)
+               fl.oif = dst_addr->sin6_scope_id;
+
+       *dst = ip6_route_output(&init_net, NULL, &fl);
+       if (*dst)
+               return 0;
+#endif
+
+       return -ENETUNREACH;
+}
+
+static struct cnic_dev *cnic_cm_select_dev(struct sockaddr_in *dst_addr,
+                                          int ulp_type)
+{
+       struct cnic_dev *dev = NULL;
+       struct dst_entry *dst;
+       struct net_device *netdev = NULL;
+       int err = -ENETUNREACH;
+
+       if (dst_addr->sin_family == AF_INET)
+               err = cnic_get_v4_route(dst_addr, &dst);
+       else if (dst_addr->sin_family == AF_INET6) {
+               struct sockaddr_in6 *dst_addr6 =
+                       (struct sockaddr_in6 *) dst_addr;
+
+               err = cnic_get_v6_route(dst_addr6, &dst);
+       } else
+               return NULL;
+
+       if (err)
+               return NULL;
+
+       if (!dst->dev)
+               goto done;
+
+       cnic_get_vlan(dst->dev, &netdev);
+
+       dev = cnic_from_netdev(netdev);
+
+done:
+       dst_release(dst);
+       if (dev)
+               cnic_put(dev);
+       return dev;
+}
+
+static int cnic_resolve_addr(struct cnic_sock *csk, struct cnic_sockaddr *saddr)
+{
+       struct cnic_dev *dev = csk->dev;
+       struct cnic_local *cp = dev->cnic_priv;
+
+       return cnic_send_nlmsg(cp, ISCSI_KEVENT_PATH_REQ, csk);
+}
+
+static int cnic_get_route(struct cnic_sock *csk, struct cnic_sockaddr *saddr)
+{
+       struct cnic_dev *dev = csk->dev;
+       struct cnic_local *cp = dev->cnic_priv;
+       int is_v6, err, rc = -ENETUNREACH;
+       struct dst_entry *dst;
+       struct net_device *realdev;
+       u32 local_port;
+
+       if (saddr->local.v6.sin6_family == AF_INET6 &&
+           saddr->remote.v6.sin6_family == AF_INET6)
+               is_v6 = 1;
+       else if (saddr->local.v4.sin_family == AF_INET &&
+                saddr->remote.v4.sin_family == AF_INET)
+               is_v6 = 0;
+       else
+               return -EINVAL;
+
+       clear_bit(SK_F_IPV6, &csk->flags);
+
+       if (is_v6) {
+#if defined(CONFIG_IPV6) || (defined(CONFIG_IPV6_MODULE) && defined(MODULE))
+               set_bit(SK_F_IPV6, &csk->flags);
+               err = cnic_get_v6_route(&saddr->remote.v6, &dst);
+               if (err)
+                       return err;
+
+               if (!dst || dst->error || !dst->dev)
+                       goto err_out;
+
+               memcpy(&csk->dst_ip[0], &saddr->remote.v6.sin6_addr,
+                      sizeof(struct in6_addr));
+               csk->dst_port = saddr->remote.v6.sin6_port;
+               local_port = saddr->local.v6.sin6_port;
+#else
+               return rc;
+#endif
+
+       } else {
+               err = cnic_get_v4_route(&saddr->remote.v4, &dst);
+               if (err)
+                       return err;
+
+               if (!dst || dst->error || !dst->dev)
+                       goto err_out;
+
+               csk->dst_ip[0] = saddr->remote.v4.sin_addr.s_addr;
+               csk->dst_port = saddr->remote.v4.sin_port;
+               local_port = saddr->local.v4.sin_port;
+       }
+
+       csk->vlan_id = cnic_get_vlan(dst->dev, &realdev);
+       if (realdev != dev->netdev)
+               goto err_out;
+
+       if (local_port >= CNIC_LOCAL_PORT_MIN &&
+           local_port < CNIC_LOCAL_PORT_MAX) {
+               if (cnic_alloc_id(&cp->csk_port_tbl, local_port))
+                       local_port = 0;
+       } else
+               local_port = 0;
+
+       if (!local_port) {
+               local_port = cnic_alloc_new_id(&cp->csk_port_tbl);
+               if (local_port == -1) {
+                       rc = -ENOMEM;
+                       goto err_out;
+               }
+       }
+       csk->src_port = local_port;
+
+       csk->mtu = dst_mtu(dst);
+       rc = 0;
+
+err_out:
+       dst_release(dst);
+       return rc;
+}
+
+static void cnic_init_csk_state(struct cnic_sock *csk)
+{
+       csk->state = 0;
+       clear_bit(SK_F_OFFLD_SCHED, &csk->flags);
+       clear_bit(SK_F_CLOSING, &csk->flags);
+}
+
+static int cnic_cm_connect(struct cnic_sock *csk, struct cnic_sockaddr *saddr)
+{
+       int err = 0;
+
+       if (!cnic_in_use(csk))
+               return -EINVAL;
+
+       if (test_and_set_bit(SK_F_CONNECT_START, &csk->flags))
+               return -EINVAL;
+
+       cnic_init_csk_state(csk);
+
+       err = cnic_get_route(csk, saddr);
+       if (err)
+               goto err_out;
+
+       err = cnic_resolve_addr(csk, saddr);
+       if (!err)
+               return 0;
+
+err_out:
+       clear_bit(SK_F_CONNECT_START, &csk->flags);
+       return err;
+}
+
+static int cnic_cm_abort(struct cnic_sock *csk)
+{
+       struct cnic_local *cp = csk->dev->cnic_priv;
+       u32 opcode;
+
+       if (!cnic_in_use(csk))
+               return -EINVAL;
+
+       if (cnic_abort_prep(csk))
+               return cnic_cm_abort_req(csk);
+
+       /* Getting here means that we haven't started connect, or
+        * connect was not successful.
+        */
+
+       csk->state = L4_KCQE_OPCODE_VALUE_RESET_COMP;
+       if (test_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags))
+               opcode = csk->state;
+       else
+               opcode = L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD;
+       cp->close_conn(csk, opcode);
+
+       return 0;
+}
+
+static int cnic_cm_close(struct cnic_sock *csk)
+{
+       if (!cnic_in_use(csk))
+               return -EINVAL;
+
+       if (cnic_close_prep(csk)) {
+               csk->state = L4_KCQE_OPCODE_VALUE_CLOSE_COMP;
+               return cnic_cm_close_req(csk);
+       }
+       return 0;
+}
+
+static void cnic_cm_upcall(struct cnic_local *cp, struct cnic_sock *csk,
+                          u8 opcode)
+{
+       struct cnic_ulp_ops *ulp_ops;
+       int ulp_type = csk->ulp_type;
+
+       rcu_read_lock();
+       ulp_ops = rcu_dereference(cp->ulp_ops[ulp_type]);
+       if (ulp_ops) {
+               if (opcode == L4_KCQE_OPCODE_VALUE_CONNECT_COMPLETE)
+                       ulp_ops->cm_connect_complete(csk);
+               else if (opcode == L4_KCQE_OPCODE_VALUE_CLOSE_COMP)
+                       ulp_ops->cm_close_complete(csk);
+               else if (opcode == L4_KCQE_OPCODE_VALUE_RESET_RECEIVED)
+                       ulp_ops->cm_remote_abort(csk);
+               else if (opcode == L4_KCQE_OPCODE_VALUE_RESET_COMP)
+                       ulp_ops->cm_abort_complete(csk);
+               else if (opcode == L4_KCQE_OPCODE_VALUE_CLOSE_RECEIVED)
+                       ulp_ops->cm_remote_close(csk);
+       }
+       rcu_read_unlock();
+}
+
+static int cnic_cm_set_pg(struct cnic_sock *csk)
+{
+       if (cnic_offld_prep(csk)) {
+               if (test_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags))
+                       cnic_cm_update_pg(csk);
+               else
+                       cnic_cm_offload_pg(csk);
+       }
+       return 0;
+}
+
+static void cnic_cm_process_offld_pg(struct cnic_dev *dev, struct l4_kcq *kcqe)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       u32 l5_cid = kcqe->pg_host_opaque;
+       u8 opcode = kcqe->op_code;
+       struct cnic_sock *csk = &cp->csk_tbl[l5_cid];
+
+       csk_hold(csk);
+       if (!cnic_in_use(csk))
+               goto done;
+
+       if (opcode == L4_KCQE_OPCODE_VALUE_UPDATE_PG) {
+               clear_bit(SK_F_OFFLD_SCHED, &csk->flags);
+               goto done;
+       }
+       csk->pg_cid = kcqe->pg_cid;
+       set_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags);
+       cnic_cm_conn_req(csk);
+
+done:
+       csk_put(csk);
+}
+
+static void cnic_cm_process_kcqe(struct cnic_dev *dev, struct kcqe *kcqe)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       struct l4_kcq *l4kcqe = (struct l4_kcq *) kcqe;
+       u8 opcode = l4kcqe->op_code;
+       u32 l5_cid;
+       struct cnic_sock *csk;
+
+       if (opcode == L4_KCQE_OPCODE_VALUE_OFFLOAD_PG ||
+           opcode == L4_KCQE_OPCODE_VALUE_UPDATE_PG) {
+               cnic_cm_process_offld_pg(dev, l4kcqe);
+               return;
+       }
+
+       l5_cid = l4kcqe->conn_id;
+       if (opcode & 0x80)
+               l5_cid = l4kcqe->cid;
+       if (l5_cid >= MAX_CM_SK_TBL_SZ)
+               return;
+
+       csk = &cp->csk_tbl[l5_cid];
+       csk_hold(csk);
+
+       if (!cnic_in_use(csk)) {
+               csk_put(csk);
+               return;
+       }
+
+       switch (opcode) {
+       case L4_KCQE_OPCODE_VALUE_CONNECT_COMPLETE:
+               if (l4kcqe->status == 0)
+                       set_bit(SK_F_OFFLD_COMPLETE, &csk->flags);
+
+               smp_mb__before_clear_bit();
+               clear_bit(SK_F_OFFLD_SCHED, &csk->flags);
+               cnic_cm_upcall(cp, csk, opcode);
+               break;
+
+       case L4_KCQE_OPCODE_VALUE_RESET_RECEIVED:
+               if (test_and_clear_bit(SK_F_OFFLD_COMPLETE, &csk->flags))
+                       csk->state = opcode;
+               /* fall through */
+       case L4_KCQE_OPCODE_VALUE_CLOSE_COMP:
+       case L4_KCQE_OPCODE_VALUE_RESET_COMP:
+               cp->close_conn(csk, opcode);
+               break;
+
+       case L4_KCQE_OPCODE_VALUE_CLOSE_RECEIVED:
+               cnic_cm_upcall(cp, csk, opcode);
+               break;
+       }
+       csk_put(csk);
+}
+
+static void cnic_cm_indicate_kcqe(void *data, struct kcqe *kcqe[], u32 num)
+{
+       struct cnic_dev *dev = data;
+       int i;
+
+       for (i = 0; i < num; i++)
+               cnic_cm_process_kcqe(dev, kcqe[i]);
+}
+
+static struct cnic_ulp_ops cm_ulp_ops = {
+       .indicate_kcqes         = cnic_cm_indicate_kcqe,
+};
+
+static void cnic_cm_free_mem(struct cnic_dev *dev)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+
+       kfree(cp->csk_tbl);
+       cp->csk_tbl = NULL;
+       cnic_free_id_tbl(&cp->csk_port_tbl);
+}
+
+static int cnic_cm_alloc_mem(struct cnic_dev *dev)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+
+       cp->csk_tbl = kzalloc(sizeof(struct cnic_sock) * MAX_CM_SK_TBL_SZ,
+                             GFP_KERNEL);
+       if (!cp->csk_tbl)
+               return -ENOMEM;
+
+       if (cnic_init_id_tbl(&cp->csk_port_tbl, CNIC_LOCAL_PORT_RANGE,
+                            CNIC_LOCAL_PORT_MIN)) {
+               cnic_cm_free_mem(dev);
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static int cnic_ready_to_close(struct cnic_sock *csk, u32 opcode)
+{
+       if ((opcode == csk->state) ||
+           (opcode == L4_KCQE_OPCODE_VALUE_RESET_RECEIVED &&
+            csk->state == L4_KCQE_OPCODE_VALUE_CLOSE_COMP)) {
+               if (!test_and_set_bit(SK_F_CLOSING, &csk->flags))
+                       return 1;
+       }
+       return 0;
+}
+
+static void cnic_close_bnx2_conn(struct cnic_sock *csk, u32 opcode)
+{
+       struct cnic_dev *dev = csk->dev;
+       struct cnic_local *cp = dev->cnic_priv;
+
+       clear_bit(SK_F_CONNECT_START, &csk->flags);
+       if (cnic_ready_to_close(csk, opcode)) {
+               cnic_close_conn(csk);
+               cnic_cm_upcall(cp, csk, opcode);
+       }
+}
+
+static void cnic_cm_stop_bnx2_hw(struct cnic_dev *dev)
+{
+}
+
+static int cnic_cm_init_bnx2_hw(struct cnic_dev *dev)
+{
+       u32 seed;
+
+       get_random_bytes(&seed, 4);
+       cnic_ctx_wr(dev, 45, 0, seed);
+       return 0;
+}
+
+static int cnic_cm_open(struct cnic_dev *dev)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       int err;
+
+       err = cnic_cm_alloc_mem(dev);
+       if (err)
+               return err;
+
+       err = cp->start_cm(dev);
+
+       if (err)
+               goto err_out;
+
+       dev->cm_create = cnic_cm_create;
+       dev->cm_destroy = cnic_cm_destroy;
+       dev->cm_connect = cnic_cm_connect;
+       dev->cm_abort = cnic_cm_abort;
+       dev->cm_close = cnic_cm_close;
+       dev->cm_select_dev = cnic_cm_select_dev;
+
+       cp->ulp_handle[CNIC_ULP_L4] = dev;
+       rcu_assign_pointer(cp->ulp_ops[CNIC_ULP_L4], &cm_ulp_ops);
+       return 0;
+
+err_out:
+       cnic_cm_free_mem(dev);
+       return err;
+}
+
+static int cnic_cm_shutdown(struct cnic_dev *dev)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       int i;
+
+       cp->stop_cm(dev);
+
+       if (!cp->csk_tbl)
+               return 0;
+
+       for (i = 0; i < MAX_CM_SK_TBL_SZ; i++) {
+               struct cnic_sock *csk = &cp->csk_tbl[i];
+
+               clear_bit(SK_F_INUSE, &csk->flags);
+               cnic_cm_cleanup(csk);
+       }
+       cnic_cm_free_mem(dev);
+
+       return 0;
+}
+
+static void cnic_init_context(struct cnic_dev *dev, u32 cid)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       u32 cid_addr;
+       int i;
+
+       if (CHIP_NUM(cp) == CHIP_NUM_5709)
+               return;
+
+       cid_addr = GET_CID_ADDR(cid);
+
+       for (i = 0; i < CTX_SIZE; i += 4)
+               cnic_ctx_wr(dev, cid_addr, i, 0);
+}
+
+static int cnic_setup_5709_context(struct cnic_dev *dev, int valid)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       int ret = 0, i;
+       u32 valid_bit = valid ? BNX2_CTX_HOST_PAGE_TBL_DATA0_VALID : 0;
+
+       if (CHIP_NUM(cp) != CHIP_NUM_5709)
+               return 0;
+
+       for (i = 0; i < cp->ctx_blks; i++) {
+               int j;
+               u32 idx = cp->ctx_arr[i].cid / cp->cids_per_blk;
+               u32 val;
+
+               memset(cp->ctx_arr[i].ctx, 0, BCM_PAGE_SIZE);
+
+               CNIC_WR(dev, BNX2_CTX_HOST_PAGE_TBL_DATA0,
+                       (cp->ctx_arr[i].mapping & 0xffffffff) | valid_bit);
+               CNIC_WR(dev, BNX2_CTX_HOST_PAGE_TBL_DATA1,
+                       (u64) cp->ctx_arr[i].mapping >> 32);
+               CNIC_WR(dev, BNX2_CTX_HOST_PAGE_TBL_CTRL, idx |
+                       BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ);
+               for (j = 0; j < 10; j++) {
+
+                       val = CNIC_RD(dev, BNX2_CTX_HOST_PAGE_TBL_CTRL);
+                       if (!(val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ))
+                               break;
+                       udelay(5);
+               }
+               if (val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) {
+                       ret = -EBUSY;
+                       break;
+               }
+       }
+       return ret;
+}
+
+static void cnic_free_irq(struct cnic_dev *dev)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       struct cnic_eth_dev *ethdev = cp->ethdev;
+
+       if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) {
+               cp->disable_int_sync(dev);
+               tasklet_disable(&cp->cnic_irq_task);
+               free_irq(ethdev->irq_arr[0].vector, dev);
+       }
+}
+
+static int cnic_init_bnx2_irq(struct cnic_dev *dev)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       struct cnic_eth_dev *ethdev = cp->ethdev;
+
+       if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) {
+               int err, i = 0;
+               int sblk_num = cp->status_blk_num;
+               u32 base = ((sblk_num - 1) * BNX2_HC_SB_CONFIG_SIZE) +
+                          BNX2_HC_SB_CONFIG_1;
+
+               CNIC_WR(dev, base, BNX2_HC_SB_CONFIG_1_ONE_SHOT);
+
+               CNIC_WR(dev, base + BNX2_HC_COMP_PROD_TRIP_OFF, (2 << 16) | 8);
+               CNIC_WR(dev, base + BNX2_HC_COM_TICKS_OFF, (64 << 16) | 220);
+               CNIC_WR(dev, base + BNX2_HC_CMD_TICKS_OFF, (64 << 16) | 220);
+
+               cp->bnx2_status_blk = cp->status_blk;
+               cp->last_status_idx = cp->bnx2_status_blk->status_idx;
+               tasklet_init(&cp->cnic_irq_task, &cnic_service_bnx2_msix,
+                            (unsigned long) dev);
+               err = request_irq(ethdev->irq_arr[0].vector, cnic_irq, 0,
+                                 "cnic", dev);
+               if (err) {
+                       tasklet_disable(&cp->cnic_irq_task);
+                       return err;
+               }
+               while (cp->bnx2_status_blk->status_completion_producer_index &&
+                      i < 10) {
+                       CNIC_WR(dev, BNX2_HC_COALESCE_NOW,
+                               1 << (11 + sblk_num));
+                       udelay(10);
+                       i++;
+                       barrier();
+               }
+               if (cp->bnx2_status_blk->status_completion_producer_index) {
+                       cnic_free_irq(dev);
+                       goto failed;
+               }
+
+       } else {
+               struct status_block *sblk = cp->status_blk;
+               u32 hc_cmd = CNIC_RD(dev, BNX2_HC_COMMAND);
+               int i = 0;
+
+               while (sblk->status_completion_producer_index && i < 10) {
+                       CNIC_WR(dev, BNX2_HC_COMMAND,
+                               hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
+                       udelay(10);
+                       i++;
+                       barrier();
+               }
+               if (sblk->status_completion_producer_index)
+                       goto failed;
+
+       }
+       return 0;
+
+failed:
+       printk(KERN_ERR PFX "%s: " "KCQ index not resetting to 0.\n",
+              dev->netdev->name);
+       return -EBUSY;
+}
+
+static void cnic_enable_bnx2_int(struct cnic_dev *dev)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       struct cnic_eth_dev *ethdev = cp->ethdev;
+
+       if (!(ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX))
+               return;
+
+       CNIC_WR(dev, BNX2_PCICFG_INT_ACK_CMD, cp->int_num |
+               BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | cp->last_status_idx);
+}
+
+static void cnic_disable_bnx2_int_sync(struct cnic_dev *dev)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       struct cnic_eth_dev *ethdev = cp->ethdev;
+
+       if (!(ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX))
+               return;
+
+       CNIC_WR(dev, BNX2_PCICFG_INT_ACK_CMD, cp->int_num |
+               BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
+       CNIC_RD(dev, BNX2_PCICFG_INT_ACK_CMD);
+       synchronize_irq(ethdev->irq_arr[0].vector);
+}
+
+static void cnic_init_bnx2_tx_ring(struct cnic_dev *dev)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       struct cnic_eth_dev *ethdev = cp->ethdev;
+       u32 cid_addr, tx_cid, sb_id;
+       u32 val, offset0, offset1, offset2, offset3;
+       int i;
+       struct tx_bd *txbd;
+       dma_addr_t buf_map;
+       struct status_block *s_blk = cp->status_blk;
+
+       sb_id = cp->status_blk_num;
+       tx_cid = 20;
+       cnic_init_context(dev, tx_cid);
+       cnic_init_context(dev, tx_cid + 1);
+       cp->tx_cons_ptr = &s_blk->status_tx_quick_consumer_index2;
+       if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) {
+               struct status_block_msix *sblk = cp->status_blk;
+
+               tx_cid = TX_TSS_CID + sb_id - 1;
+               cnic_init_context(dev, tx_cid);
+               CNIC_WR(dev, BNX2_TSCH_TSS_CFG, (sb_id << 24) |
+                       (TX_TSS_CID << 7));
+               cp->tx_cons_ptr = &sblk->status_tx_quick_consumer_index;
+       }
+       cp->tx_cons = *cp->tx_cons_ptr;
+
+       cid_addr = GET_CID_ADDR(tx_cid);
+       if (CHIP_NUM(cp) == CHIP_NUM_5709) {
+               u32 cid_addr2 = GET_CID_ADDR(tx_cid + 4) + 0x40;
+
+               for (i = 0; i < PHY_CTX_SIZE; i += 4)
+                       cnic_ctx_wr(dev, cid_addr2, i, 0);
+
+               offset0 = BNX2_L2CTX_TYPE_XI;
+               offset1 = BNX2_L2CTX_CMD_TYPE_XI;
+               offset2 = BNX2_L2CTX_TBDR_BHADDR_HI_XI;
+               offset3 = BNX2_L2CTX_TBDR_BHADDR_LO_XI;
+       } else {
+               offset0 = BNX2_L2CTX_TYPE;
+               offset1 = BNX2_L2CTX_CMD_TYPE;
+               offset2 = BNX2_L2CTX_TBDR_BHADDR_HI;
+               offset3 = BNX2_L2CTX_TBDR_BHADDR_LO;
+       }
+       val = BNX2_L2CTX_TYPE_TYPE_L2 | BNX2_L2CTX_TYPE_SIZE_L2;
+       cnic_ctx_wr(dev, cid_addr, offset0, val);
+
+       val = BNX2_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16);
+       cnic_ctx_wr(dev, cid_addr, offset1, val);
+
+       txbd = (struct tx_bd *) cp->l2_ring;
+
+       buf_map = cp->l2_buf_map;
+       for (i = 0; i < MAX_TX_DESC_CNT; i++, txbd++) {
+               txbd->tx_bd_haddr_hi = (u64) buf_map >> 32;
+               txbd->tx_bd_haddr_lo = (u64) buf_map & 0xffffffff;
+       }
+       val = (u64) cp->l2_ring_map >> 32;
+       cnic_ctx_wr(dev, cid_addr, offset2, val);
+       txbd->tx_bd_haddr_hi = val;
+
+       val = (u64) cp->l2_ring_map & 0xffffffff;
+       cnic_ctx_wr(dev, cid_addr, offset3, val);
+       txbd->tx_bd_haddr_lo = val;
+}
+
+static void cnic_init_bnx2_rx_ring(struct cnic_dev *dev)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       struct cnic_eth_dev *ethdev = cp->ethdev;
+       u32 cid_addr, sb_id, val, coal_reg, coal_val;
+       int i;
+       struct rx_bd *rxbd;
+       struct status_block *s_blk = cp->status_blk;
+
+       sb_id = cp->status_blk_num;
+       cnic_init_context(dev, 2);
+       cp->rx_cons_ptr = &s_blk->status_rx_quick_consumer_index2;
+       coal_reg = BNX2_HC_COMMAND;
+       coal_val = CNIC_RD(dev, coal_reg);
+       if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) {
+               struct status_block_msix *sblk = cp->status_blk;
+
+               cp->rx_cons_ptr = &sblk->status_rx_quick_consumer_index;
+               coal_reg = BNX2_HC_COALESCE_NOW;
+               coal_val = 1 << (11 + sb_id);
+       }
+       i = 0;
+       while (!(*cp->rx_cons_ptr != 0) && i < 10) {
+               CNIC_WR(dev, coal_reg, coal_val);
+               udelay(10);
+               i++;
+               barrier();
+       }
+       cp->rx_cons = *cp->rx_cons_ptr;
+
+       cid_addr = GET_CID_ADDR(2);
+       val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE |
+             BNX2_L2CTX_CTX_TYPE_SIZE_L2 | (0x02 << 8);
+       cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_CTX_TYPE, val);
+
+       if (sb_id == 0)
+               val = 2 << BNX2_L2CTX_STATUSB_NUM_SHIFT;
+       else
+               val = BNX2_L2CTX_STATUSB_NUM(sb_id);
+       cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_HOST_BDIDX, val);
+
+       rxbd = (struct rx_bd *) (cp->l2_ring + BCM_PAGE_SIZE);
+       for (i = 0; i < MAX_RX_DESC_CNT; i++, rxbd++) {
+               dma_addr_t buf_map;
+               int n = (i % cp->l2_rx_ring_size) + 1;
+
+               buf_map = cp->l2_buf_map + (n * cp->l2_single_buf_size);
+               rxbd->rx_bd_len = cp->l2_single_buf_size;
+               rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
+               rxbd->rx_bd_haddr_hi = (u64) buf_map >> 32;
+               rxbd->rx_bd_haddr_lo = (u64) buf_map & 0xffffffff;
+       }
+       val = (u64) (cp->l2_ring_map + BCM_PAGE_SIZE) >> 32;
+       cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val);
+       rxbd->rx_bd_haddr_hi = val;
+
+       val = (u64) (cp->l2_ring_map + BCM_PAGE_SIZE) & 0xffffffff;
+       cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
+       rxbd->rx_bd_haddr_lo = val;
+
+       val = cnic_reg_rd_ind(dev, BNX2_RXP_SCRATCH_RXP_FLOOD);
+       cnic_reg_wr_ind(dev, BNX2_RXP_SCRATCH_RXP_FLOOD, val | (1 << 2));
+}
+
+static void cnic_shutdown_bnx2_rx_ring(struct cnic_dev *dev)
+{
+       struct kwqe *wqes[1], l2kwqe;
+
+       memset(&l2kwqe, 0, sizeof(l2kwqe));
+       wqes[0] = &l2kwqe;
+       l2kwqe.kwqe_op_flag = (L2_LAYER_CODE << KWQE_FLAGS_LAYER_SHIFT) |
+                             (L2_KWQE_OPCODE_VALUE_FLUSH <<
+                              KWQE_OPCODE_SHIFT) | 2;
+       dev->submit_kwqes(dev, wqes, 1);
+}
+
+static void cnic_set_bnx2_mac(struct cnic_dev *dev)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       u32 val;
+
+       val = cp->func << 2;
+
+       cp->shmem_base = cnic_reg_rd_ind(dev, BNX2_SHM_HDR_ADDR_0 + val);
+
+       val = cnic_reg_rd_ind(dev, cp->shmem_base +
+                             BNX2_PORT_HW_CFG_ISCSI_MAC_UPPER);
+       dev->mac_addr[0] = (u8) (val >> 8);
+       dev->mac_addr[1] = (u8) val;
+
+       CNIC_WR(dev, BNX2_EMAC_MAC_MATCH4, val);
+
+       val = cnic_reg_rd_ind(dev, cp->shmem_base +
+                             BNX2_PORT_HW_CFG_ISCSI_MAC_LOWER);
+       dev->mac_addr[2] = (u8) (val >> 24);
+       dev->mac_addr[3] = (u8) (val >> 16);
+       dev->mac_addr[4] = (u8) (val >> 8);
+       dev->mac_addr[5] = (u8) val;
+
+       CNIC_WR(dev, BNX2_EMAC_MAC_MATCH5, val);
+
+       val = 4 | BNX2_RPM_SORT_USER2_BC_EN;
+       if (CHIP_NUM(cp) != CHIP_NUM_5709)
+               val |= BNX2_RPM_SORT_USER2_PROM_VLAN;
+
+       CNIC_WR(dev, BNX2_RPM_SORT_USER2, 0x0);
+       CNIC_WR(dev, BNX2_RPM_SORT_USER2, val);
+       CNIC_WR(dev, BNX2_RPM_SORT_USER2, val | BNX2_RPM_SORT_USER2_ENA);
+}
+
+static int cnic_start_bnx2_hw(struct cnic_dev *dev)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       struct cnic_eth_dev *ethdev = cp->ethdev;
+       struct status_block *sblk = cp->status_blk;
+       u32 val;
+       int err;
+
+       cnic_set_bnx2_mac(dev);
+
+       val = CNIC_RD(dev, BNX2_MQ_CONFIG);
+       val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
+       if (BCM_PAGE_BITS > 12)
+               val |= (12 - 8)  << 4;
+       else
+               val |= (BCM_PAGE_BITS - 8)  << 4;
+
+       CNIC_WR(dev, BNX2_MQ_CONFIG, val);
+
+       CNIC_WR(dev, BNX2_HC_COMP_PROD_TRIP, (2 << 16) | 8);
+       CNIC_WR(dev, BNX2_HC_COM_TICKS, (64 << 16) | 220);
+       CNIC_WR(dev, BNX2_HC_CMD_TICKS, (64 << 16) | 220);
+
+       err = cnic_setup_5709_context(dev, 1);
+       if (err)
+               return err;
+
+       cnic_init_context(dev, KWQ_CID);
+       cnic_init_context(dev, KCQ_CID);
+
+       cp->kwq_cid_addr = GET_CID_ADDR(KWQ_CID);
+       cp->kwq_io_addr = MB_GET_CID_ADDR(KWQ_CID) + L5_KRNLQ_HOST_QIDX;
+
+       cp->max_kwq_idx = MAX_KWQ_IDX;
+       cp->kwq_prod_idx = 0;
+       cp->kwq_con_idx = 0;
+       cp->cnic_local_flags |= CNIC_LCL_FL_KWQ_INIT;
+
+       if (CHIP_NUM(cp) == CHIP_NUM_5706 || CHIP_NUM(cp) == CHIP_NUM_5708)
+               cp->kwq_con_idx_ptr = &sblk->status_rx_quick_consumer_index15;
+       else
+               cp->kwq_con_idx_ptr = &sblk->status_cmd_consumer_index;
+
+       /* Initialize the kernel work queue context. */
+       val = KRNLQ_TYPE_TYPE_KRNLQ | KRNLQ_SIZE_TYPE_SIZE |
+             (BCM_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ;
+       cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_TYPE, val);
+
+       val = (BCM_PAGE_SIZE / sizeof(struct kwqe) - 1) << 16;
+       cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val);
+
+       val = ((BCM_PAGE_SIZE / sizeof(struct kwqe)) << 16) | KWQ_PAGE_CNT;
+       cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val);
+
+       val = (u32) ((u64) cp->kwq_info.pgtbl_map >> 32);
+       cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_PGTBL_HADDR_HI, val);
+
+       val = (u32) cp->kwq_info.pgtbl_map;
+       cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_PGTBL_HADDR_LO, val);
+
+       cp->kcq_cid_addr = GET_CID_ADDR(KCQ_CID);
+       cp->kcq_io_addr = MB_GET_CID_ADDR(KCQ_CID) + L5_KRNLQ_HOST_QIDX;
+
+       cp->kcq_prod_idx = 0;
+
+       /* Initialize the kernel complete queue context. */
+       val = KRNLQ_TYPE_TYPE_KRNLQ | KRNLQ_SIZE_TYPE_SIZE |
+             (BCM_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ;
+       cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_TYPE, val);
+
+       val = (BCM_PAGE_SIZE / sizeof(struct kcqe) - 1) << 16;
+       cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val);
+
+       val = ((BCM_PAGE_SIZE / sizeof(struct kcqe)) << 16) | KCQ_PAGE_CNT;
+       cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val);
+
+       val = (u32) ((u64) cp->kcq_info.pgtbl_map >> 32);
+       cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_PGTBL_HADDR_HI, val);
+
+       val = (u32) cp->kcq_info.pgtbl_map;
+       cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_PGTBL_HADDR_LO, val);
+
+       cp->int_num = 0;
+       if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) {
+               u32 sb_id = cp->status_blk_num;
+               u32 sb = BNX2_L2CTX_STATUSB_NUM(sb_id);
+
+               cp->int_num = sb_id << BNX2_PCICFG_INT_ACK_CMD_INT_NUM_SHIFT;
+               cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_HOST_QIDX, sb);
+               cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_HOST_QIDX, sb);
+       }
+
+       /* Enable Commnad Scheduler notification when we write to the
+        * host producer index of the kernel contexts. */
+       CNIC_WR(dev, BNX2_MQ_KNL_CMD_MASK1, 2);
+
+       /* Enable Command Scheduler notification when we write to either
+        * the Send Queue or Receive Queue producer indexes of the kernel
+        * bypass contexts. */
+       CNIC_WR(dev, BNX2_MQ_KNL_BYP_CMD_MASK1, 7);
+       CNIC_WR(dev, BNX2_MQ_KNL_BYP_WRITE_MASK1, 7);
+
+       /* Notify COM when the driver post an application buffer. */
+       CNIC_WR(dev, BNX2_MQ_KNL_RX_V2P_MASK2, 0x2000);
+
+       /* Set the CP and COM doorbells.  These two processors polls the
+        * doorbell for a non zero value before running.  This must be done
+        * after setting up the kernel queue contexts. */
+       cnic_reg_wr_ind(dev, BNX2_CP_SCRATCH + 0x20, 1);
+       cnic_reg_wr_ind(dev, BNX2_COM_SCRATCH + 0x20, 1);
+
+       cnic_init_bnx2_tx_ring(dev);
+       cnic_init_bnx2_rx_ring(dev);
+
+       err = cnic_init_bnx2_irq(dev);
+       if (err) {
+               printk(KERN_ERR PFX "%s: cnic_init_irq failed\n",
+                      dev->netdev->name);
+               cnic_reg_wr_ind(dev, BNX2_CP_SCRATCH + 0x20, 0);
+               cnic_reg_wr_ind(dev, BNX2_COM_SCRATCH + 0x20, 0);
+               return err;
+       }
+
+       return 0;
+}
+
+static int cnic_start_hw(struct cnic_dev *dev)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       struct cnic_eth_dev *ethdev = cp->ethdev;
+       int err;
+
+       if (test_bit(CNIC_F_CNIC_UP, &dev->flags))
+               return -EALREADY;
+
+       err = ethdev->drv_register_cnic(dev->netdev, cp->cnic_ops, dev);
+       if (err) {
+               printk(KERN_ERR PFX "%s: register_cnic failed\n",
+                      dev->netdev->name);
+               goto err2;
+       }
+
+       dev->regview = ethdev->io_base;
+       cp->chip_id = ethdev->chip_id;
+       pci_dev_get(dev->pcidev);
+       cp->func = PCI_FUNC(dev->pcidev->devfn);
+       cp->status_blk = ethdev->irq_arr[0].status_blk;
+       cp->status_blk_num = ethdev->irq_arr[0].status_blk_num;
+
+       err = cp->alloc_resc(dev);
+       if (err) {
+               printk(KERN_ERR PFX "%s: allocate resource failure\n",
+                      dev->netdev->name);
+               goto err1;
+       }
+
+       err = cp->start_hw(dev);
+       if (err)
+               goto err1;
+
+       err = cnic_cm_open(dev);
+       if (err)
+               goto err1;
+
+       set_bit(CNIC_F_CNIC_UP, &dev->flags);
+
+       cp->enable_int(dev);
+
+       return 0;
+
+err1:
+       ethdev->drv_unregister_cnic(dev->netdev);
+       cp->free_resc(dev);
+       pci_dev_put(dev->pcidev);
+err2:
+       return err;
+}
+
+static void cnic_stop_bnx2_hw(struct cnic_dev *dev)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       struct cnic_eth_dev *ethdev = cp->ethdev;
+
+       cnic_disable_bnx2_int_sync(dev);
+
+       cnic_reg_wr_ind(dev, BNX2_CP_SCRATCH + 0x20, 0);
+       cnic_reg_wr_ind(dev, BNX2_COM_SCRATCH + 0x20, 0);
+
+       cnic_init_context(dev, KWQ_CID);
+       cnic_init_context(dev, KCQ_CID);
+
+       cnic_setup_5709_context(dev, 0);
+       cnic_free_irq(dev);
+
+       ethdev->drv_unregister_cnic(dev->netdev);
+
+       cnic_free_resc(dev);
+}
+
+static void cnic_stop_hw(struct cnic_dev *dev)
+{
+       if (test_bit(CNIC_F_CNIC_UP, &dev->flags)) {
+               struct cnic_local *cp = dev->cnic_priv;
+
+               clear_bit(CNIC_F_CNIC_UP, &dev->flags);
+               rcu_assign_pointer(cp->ulp_ops[CNIC_ULP_L4], NULL);
+               synchronize_rcu();
+               cnic_cm_shutdown(dev);
+               cp->stop_hw(dev);
+               pci_dev_put(dev->pcidev);
+       }
+}
+
+static void cnic_free_dev(struct cnic_dev *dev)
+{
+       int i = 0;
+
+       while ((atomic_read(&dev->ref_count) != 0) && i < 10) {
+               msleep(100);
+               i++;
+       }
+       if (atomic_read(&dev->ref_count) != 0)
+               printk(KERN_ERR PFX "%s: Failed waiting for ref count to go"
+                                   " to zero.\n", dev->netdev->name);
+
+       printk(KERN_INFO PFX "Removed CNIC device: %s\n", dev->netdev->name);
+       dev_put(dev->netdev);
+       kfree(dev);
+}
+
+static struct cnic_dev *cnic_alloc_dev(struct net_device *dev,
+                                      struct pci_dev *pdev)
+{
+       struct cnic_dev *cdev;
+       struct cnic_local *cp;
+       int alloc_size;
+
+       alloc_size = sizeof(struct cnic_dev) + sizeof(struct cnic_local);
+
+       cdev = kzalloc(alloc_size , GFP_KERNEL);
+       if (cdev == NULL) {
+               printk(KERN_ERR PFX "%s: allocate dev struct failure\n",
+                      dev->name);
+               return NULL;
+       }
+
+       cdev->netdev = dev;
+       cdev->cnic_priv = (char *)cdev + sizeof(struct cnic_dev);
+       cdev->register_device = cnic_register_device;
+       cdev->unregister_device = cnic_unregister_device;
+       cdev->iscsi_nl_msg_recv = cnic_iscsi_nl_msg_recv;
+
+       cp = cdev->cnic_priv;
+       cp->dev = cdev;
+       cp->uio_dev = -1;
+       cp->l2_single_buf_size = 0x400;
+       cp->l2_rx_ring_size = 3;
+
+       spin_lock_init(&cp->cnic_ulp_lock);
+
+       printk(KERN_INFO PFX "Added CNIC device: %s\n", dev->name);
+
+       return cdev;
+}
+
+static struct cnic_dev *init_bnx2_cnic(struct net_device *dev)
+{
+       struct pci_dev *pdev;
+       struct cnic_dev *cdev;
+       struct cnic_local *cp;
+       struct cnic_eth_dev *ethdev = NULL;
+       struct cnic_eth_dev *(*probe)(void *) = NULL;
+
+       probe = __symbol_get("bnx2_cnic_probe");
+       if (probe) {
+               ethdev = (*probe)(dev);
+               symbol_put_addr(probe);
+       }
+       if (!ethdev)
+               return NULL;
+
+       pdev = ethdev->pdev;
+       if (!pdev)
+               return NULL;
+
+       dev_hold(dev);
+       pci_dev_get(pdev);
+       if (pdev->device == PCI_DEVICE_ID_NX2_5709 ||
+           pdev->device == PCI_DEVICE_ID_NX2_5709S) {
+               u8 rev;
+
+               pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
+               if (rev < 0x10) {
+                       pci_dev_put(pdev);
+                       goto cnic_err;
+               }
+       }
+       pci_dev_put(pdev);
+
+       cdev = cnic_alloc_dev(dev, pdev);
+       if (cdev == NULL)
+               goto cnic_err;
+
+       set_bit(CNIC_F_BNX2_CLASS, &cdev->flags);
+       cdev->submit_kwqes = cnic_submit_bnx2_kwqes;
+
+       cp = cdev->cnic_priv;
+       cp->ethdev = ethdev;
+       cdev->pcidev = pdev;
+
+       cp->cnic_ops = &cnic_bnx2_ops;
+       cp->start_hw = cnic_start_bnx2_hw;
+       cp->stop_hw = cnic_stop_bnx2_hw;
+       cp->setup_pgtbl = cnic_setup_page_tbl;
+       cp->alloc_resc = cnic_alloc_bnx2_resc;
+       cp->free_resc = cnic_free_resc;
+       cp->start_cm = cnic_cm_init_bnx2_hw;
+       cp->stop_cm = cnic_cm_stop_bnx2_hw;
+       cp->enable_int = cnic_enable_bnx2_int;
+       cp->disable_int_sync = cnic_disable_bnx2_int_sync;
+       cp->close_conn = cnic_close_bnx2_conn;
+       cp->next_idx = cnic_bnx2_next_idx;
+       cp->hw_idx = cnic_bnx2_hw_idx;
+       return cdev;
+
+cnic_err:
+       dev_put(dev);
+       return NULL;
+}
+
+static struct cnic_dev *is_cnic_dev(struct net_device *dev)
+{
+       struct ethtool_drvinfo drvinfo;
+       struct cnic_dev *cdev = NULL;
+
+       if (dev->ethtool_ops && dev->ethtool_ops->get_drvinfo) {
+               memset(&drvinfo, 0, sizeof(drvinfo));
+               dev->ethtool_ops->get_drvinfo(dev, &drvinfo);
+
+               if (!strcmp(drvinfo.driver, "bnx2"))
+                       cdev = init_bnx2_cnic(dev);
+               if (cdev) {
+                       write_lock(&cnic_dev_lock);
+                       list_add(&cdev->list, &cnic_dev_list);
+                       write_unlock(&cnic_dev_lock);
+               }
+       }
+       return cdev;
+}
+
+/**
+ * netdev event handler
+ */
+static int cnic_netdev_event(struct notifier_block *this, unsigned long event,
+                                                        void *ptr)
+{
+       struct net_device *netdev = ptr;
+       struct cnic_dev *dev;
+       int if_type;
+       int new_dev = 0;
+
+       dev = cnic_from_netdev(netdev);
+
+       if (!dev && (event == NETDEV_REGISTER || event == NETDEV_UP)) {
+               /* Check for the hot-plug device */
+               dev = is_cnic_dev(netdev);
+               if (dev) {
+                       new_dev = 1;
+                       cnic_hold(dev);
+               }
+       }
+       if (dev) {
+               struct cnic_local *cp = dev->cnic_priv;
+
+               if (new_dev)
+                       cnic_ulp_init(dev);
+               else if (event == NETDEV_UNREGISTER)
+                       cnic_ulp_exit(dev);
+               else if (event == NETDEV_UP) {
+                       mutex_lock(&cnic_lock);
+                       if (!cnic_start_hw(dev))
+                               cnic_ulp_start(dev);
+                       mutex_unlock(&cnic_lock);
+               }
+
+               rcu_read_lock();
+               for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) {
+                       struct cnic_ulp_ops *ulp_ops;
+                       void *ctx;
+
+                       ulp_ops = rcu_dereference(cp->ulp_ops[if_type]);
+                       if (!ulp_ops || !ulp_ops->indicate_netevent)
+                               continue;
+
+                       ctx = cp->ulp_handle[if_type];
+
+                       ulp_ops->indicate_netevent(ctx, event);
+               }
+               rcu_read_unlock();
+
+               if (event == NETDEV_GOING_DOWN) {
+                       mutex_lock(&cnic_lock);
+                       cnic_ulp_stop(dev);
+                       cnic_stop_hw(dev);
+                       mutex_unlock(&cnic_lock);
+               } else if (event == NETDEV_UNREGISTER) {
+                       write_lock(&cnic_dev_lock);
+                       list_del_init(&dev->list);
+                       write_unlock(&cnic_dev_lock);
+
+                       cnic_put(dev);
+                       cnic_free_dev(dev);
+                       goto done;
+               }
+               cnic_put(dev);
+       }
+done:
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block cnic_netdev_notifier = {
+       .notifier_call = cnic_netdev_event
+};
+
+static void cnic_release(void)
+{
+       struct cnic_dev *dev;
+
+       while (!list_empty(&cnic_dev_list)) {
+               dev = list_entry(cnic_dev_list.next, struct cnic_dev, list);
+               if (test_bit(CNIC_F_CNIC_UP, &dev->flags)) {
+                       cnic_ulp_stop(dev);
+                       cnic_stop_hw(dev);
+               }
+
+               cnic_ulp_exit(dev);
+               list_del_init(&dev->list);
+               cnic_free_dev(dev);
+       }
+}
+
+static int __init cnic_init(void)
+{
+       int rc = 0;
+
+       printk(KERN_INFO "%s", version);
+
+       rc = register_netdevice_notifier(&cnic_netdev_notifier);
+       if (rc) {
+               cnic_release();
+               return rc;
+       }
+
+       return 0;
+}
+
+static void __exit cnic_exit(void)
+{
+       unregister_netdevice_notifier(&cnic_netdev_notifier);
+       cnic_release();
+       return;
+}
+
+module_init(cnic_init);
+module_exit(cnic_exit);
diff --git a/drivers/net/cnic.h b/drivers/net/cnic.h
new file mode 100644 (file)
index 0000000..5192d4a
--- /dev/null
@@ -0,0 +1,299 @@
+/* cnic.h: Broadcom CNIC core network driver.
+ *
+ * Copyright (c) 2006-2009 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ */
+
+
+#ifndef CNIC_H
+#define CNIC_H
+
+#define KWQ_PAGE_CNT   4
+#define KCQ_PAGE_CNT   16
+
+#define KWQ_CID                24
+#define KCQ_CID                25
+
+/*
+ *     krnlq_context definition
+ */
+#define L5_KRNLQ_FLAGS 0x00000000
+#define L5_KRNLQ_SIZE  0x00000000
+#define L5_KRNLQ_TYPE  0x00000000
+#define KRNLQ_FLAGS_PG_SZ                                      (0xf<<0)
+#define KRNLQ_FLAGS_PG_SZ_256                                  (0<<0)
+#define KRNLQ_FLAGS_PG_SZ_512                                  (1<<0)
+#define KRNLQ_FLAGS_PG_SZ_1K                                   (2<<0)
+#define KRNLQ_FLAGS_PG_SZ_2K                                   (3<<0)
+#define KRNLQ_FLAGS_PG_SZ_4K                                   (4<<0)
+#define KRNLQ_FLAGS_PG_SZ_8K                                   (5<<0)
+#define KRNLQ_FLAGS_PG_SZ_16K                                  (6<<0)
+#define KRNLQ_FLAGS_PG_SZ_32K                                  (7<<0)
+#define KRNLQ_FLAGS_PG_SZ_64K                                  (8<<0)
+#define KRNLQ_FLAGS_PG_SZ_128K                                 (9<<0)
+#define KRNLQ_FLAGS_PG_SZ_256K                                 (10<<0)
+#define KRNLQ_FLAGS_PG_SZ_512K                                 (11<<0)
+#define KRNLQ_FLAGS_PG_SZ_1M                                   (12<<0)
+#define KRNLQ_FLAGS_PG_SZ_2M                                   (13<<0)
+#define KRNLQ_FLAGS_QE_SELF_SEQ                                        (1<<15)
+#define KRNLQ_SIZE_TYPE_SIZE   ((((0x28 + 0x1f) & ~0x1f) / 0x20) << 16)
+#define KRNLQ_TYPE_TYPE                                                (0xf<<28)
+#define KRNLQ_TYPE_TYPE_EMPTY                                  (0<<28)
+#define KRNLQ_TYPE_TYPE_KRNLQ                                  (6<<28)
+
+#define L5_KRNLQ_HOST_QIDX             0x00000004
+#define L5_KRNLQ_HOST_FW_QIDX          0x00000008
+#define L5_KRNLQ_NX_QE_SELF_SEQ        0x0000000c
+#define L5_KRNLQ_QE_SELF_SEQ_MAX       0x0000000c
+#define L5_KRNLQ_NX_QE_HADDR_HI        0x00000010
+#define L5_KRNLQ_NX_QE_HADDR_LO        0x00000014
+#define L5_KRNLQ_PGTBL_PGIDX           0x00000018
+#define L5_KRNLQ_NX_PG_QIDX            0x00000018
+#define L5_KRNLQ_PGTBL_NPAGES          0x0000001c
+#define L5_KRNLQ_QIDX_INCR             0x0000001c
+#define L5_KRNLQ_PGTBL_HADDR_HI        0x00000020
+#define L5_KRNLQ_PGTBL_HADDR_LO        0x00000024
+
+#define BNX2_PG_CTX_MAP                        0x1a0034
+#define BNX2_ISCSI_CTX_MAP             0x1a0074
+
+struct cnic_redirect_entry {
+       struct dst_entry *old_dst;
+       struct dst_entry *new_dst;
+};
+
+#define MAX_COMPLETED_KCQE     64
+
+#define MAX_CNIC_L5_CONTEXT    256
+
+#define MAX_CM_SK_TBL_SZ       MAX_CNIC_L5_CONTEXT
+
+#define MAX_ISCSI_TBL_SZ       256
+
+#define CNIC_LOCAL_PORT_MIN    60000
+#define CNIC_LOCAL_PORT_MAX    61000
+#define CNIC_LOCAL_PORT_RANGE  (CNIC_LOCAL_PORT_MAX - CNIC_LOCAL_PORT_MIN)
+
+#define KWQE_CNT (BCM_PAGE_SIZE / sizeof(struct kwqe))
+#define KCQE_CNT (BCM_PAGE_SIZE / sizeof(struct kcqe))
+#define MAX_KWQE_CNT (KWQE_CNT - 1)
+#define MAX_KCQE_CNT (KCQE_CNT - 1)
+
+#define MAX_KWQ_IDX    ((KWQ_PAGE_CNT * KWQE_CNT) - 1)
+#define MAX_KCQ_IDX    ((KCQ_PAGE_CNT * KCQE_CNT) - 1)
+
+#define KWQ_PG(x) (((x) & ~MAX_KWQE_CNT) >> (BCM_PAGE_BITS - 5))
+#define KWQ_IDX(x) ((x) & MAX_KWQE_CNT)
+
+#define KCQ_PG(x) (((x) & ~MAX_KCQE_CNT) >> (BCM_PAGE_BITS - 5))
+#define KCQ_IDX(x) ((x) & MAX_KCQE_CNT)
+
+#define BNX2X_NEXT_KCQE(x) (((x) & (MAX_KCQE_CNT - 1)) ==              \
+               (MAX_KCQE_CNT - 1)) ?                                   \
+               (x) + 2 : (x) + 1
+
+#define BNX2X_KWQ_DATA_PG(cp, x) ((x) / (cp)->kwq_16_data_pp)
+#define BNX2X_KWQ_DATA_IDX(cp, x) ((x) % (cp)->kwq_16_data_pp)
+#define BNX2X_KWQ_DATA(cp, x)                                          \
+       &(cp)->kwq_16_data[BNX2X_KWQ_DATA_PG(cp, x)][BNX2X_KWQ_DATA_IDX(cp, x)]
+
+#define DEF_IPID_COUNT         0xc001
+
+#define DEF_KA_TIMEOUT         10000
+#define DEF_KA_INTERVAL                300000
+#define DEF_KA_MAX_PROBE_COUNT 3
+#define DEF_TOS                        0
+#define DEF_TTL                        0xfe
+#define DEF_SND_SEQ_SCALE      0
+#define DEF_RCV_BUF            0xffff
+#define DEF_SND_BUF            0xffff
+#define DEF_SEED               0
+#define DEF_MAX_RT_TIME                500
+#define DEF_MAX_DA_COUNT       2
+#define DEF_SWS_TIMER          1000
+#define DEF_MAX_CWND           0xffff
+
+struct cnic_ctx {
+       u32             cid;
+       void            *ctx;
+       dma_addr_t      mapping;
+};
+
+#define BNX2_MAX_CID           0x2000
+
+struct cnic_dma {
+       int             num_pages;
+       void            **pg_arr;
+       dma_addr_t      *pg_map_arr;
+       int             pgtbl_size;
+       u32             *pgtbl;
+       dma_addr_t      pgtbl_map;
+};
+
+struct cnic_id_tbl {
+       spinlock_t      lock;
+       u32             start;
+       u32             max;
+       u32             next;
+       unsigned long   *table;
+};
+
+#define CNIC_KWQ16_DATA_SIZE   128
+
+struct kwqe_16_data {
+       u8      data[CNIC_KWQ16_DATA_SIZE];
+};
+
+struct cnic_iscsi {
+       struct cnic_dma         task_array_info;
+       struct cnic_dma         r2tq_info;
+       struct cnic_dma         hq_info;
+};
+
+struct cnic_context {
+       u32                     cid;
+       struct kwqe_16_data     *kwqe_data;
+       dma_addr_t              kwqe_data_mapping;
+       wait_queue_head_t       waitq;
+       int                     wait_cond;
+       unsigned long           timestamp;
+       u32                     ctx_flags;
+#define        CTX_FL_OFFLD_START      0x00000001
+       u8                      ulp_proto_id;
+       union {
+               struct cnic_iscsi       *iscsi;
+       } proto;
+};
+
+struct cnic_local {
+
+       spinlock_t cnic_ulp_lock;
+       void *ulp_handle[MAX_CNIC_ULP_TYPE];
+       unsigned long ulp_flags[MAX_CNIC_ULP_TYPE];
+#define ULP_F_INIT     0
+#define ULP_F_START    1
+       struct cnic_ulp_ops *ulp_ops[MAX_CNIC_ULP_TYPE];
+
+       /* protected by ulp_lock */
+       u32 cnic_local_flags;
+#define        CNIC_LCL_FL_KWQ_INIT    0x00000001
+
+       struct cnic_dev *dev;
+
+       struct cnic_eth_dev *ethdev;
+
+       void            *l2_ring;
+       dma_addr_t      l2_ring_map;
+       int             l2_ring_size;
+       int             l2_rx_ring_size;
+
+       void            *l2_buf;
+       dma_addr_t      l2_buf_map;
+       int             l2_buf_size;
+       int             l2_single_buf_size;
+
+       u16             *rx_cons_ptr;
+       u16             *tx_cons_ptr;
+       u16             rx_cons;
+       u16             tx_cons;
+
+       u32 kwq_cid_addr;
+       u32 kcq_cid_addr;
+
+       struct cnic_dma         kwq_info;
+       struct kwqe             **kwq;
+
+       struct cnic_dma         kwq_16_data_info;
+
+       u16             max_kwq_idx;
+
+       u16             kwq_prod_idx;
+       u32             kwq_io_addr;
+
+       u16             *kwq_con_idx_ptr;
+       u16             kwq_con_idx;
+
+       struct cnic_dma kcq_info;
+       struct kcqe     **kcq;
+
+       u16             kcq_prod_idx;
+       u32             kcq_io_addr;
+
+       void                            *status_blk;
+       struct status_block_msix        *bnx2_status_blk;
+       struct host_status_block        *bnx2x_status_blk;
+
+       u32                             status_blk_num;
+       u32                             int_num;
+       u32                             last_status_idx;
+       struct tasklet_struct           cnic_irq_task;
+
+       struct kcqe             *completed_kcq[MAX_COMPLETED_KCQE];
+
+       struct cnic_sock        *csk_tbl;
+       struct cnic_id_tbl      csk_port_tbl;
+
+       struct cnic_dma         conn_buf_info;
+       struct cnic_dma         gbl_buf_info;
+
+       struct cnic_iscsi       *iscsi_tbl;
+       struct cnic_context     *ctx_tbl;
+       struct cnic_id_tbl      cid_tbl;
+       int                     max_iscsi_conn;
+       atomic_t                iscsi_conn;
+
+       /* per connection parameters */
+       int                     num_iscsi_tasks;
+       int                     num_ccells;
+       int                     task_array_size;
+       int                     r2tq_size;
+       int                     hq_size;
+       int                     num_cqs;
+
+       struct cnic_ctx         *ctx_arr;
+       int                     ctx_blks;
+       int                     ctx_blk_size;
+       int                     cids_per_blk;
+
+       u32                     chip_id;
+       int                     func;
+       u32                     shmem_base;
+
+       u32                     uio_dev;
+       struct uio_info         *cnic_uinfo;
+
+       struct cnic_ops         *cnic_ops;
+       int                     (*start_hw)(struct cnic_dev *);
+       void                    (*stop_hw)(struct cnic_dev *);
+       void                    (*setup_pgtbl)(struct cnic_dev *,
+                                              struct cnic_dma *);
+       int                     (*alloc_resc)(struct cnic_dev *);
+       void                    (*free_resc)(struct cnic_dev *);
+       int                     (*start_cm)(struct cnic_dev *);
+       void                    (*stop_cm)(struct cnic_dev *);
+       void                    (*enable_int)(struct cnic_dev *);
+       void                    (*disable_int_sync)(struct cnic_dev *);
+       void                    (*ack_int)(struct cnic_dev *);
+       void                    (*close_conn)(struct cnic_sock *, u32 opcode);
+       u16                     (*next_idx)(u16);
+       u16                     (*hw_idx)(u16);
+};
+
+struct bnx2x_bd_chain_next {
+       u32     addr_lo;
+       u32     addr_hi;
+       u8      reserved[8];
+};
+
+#define ISCSI_RAMROD_CMD_ID_UPDATE_CONN                (ISCSI_KCQE_OPCODE_UPDATE_CONN)
+#define ISCSI_RAMROD_CMD_ID_INIT               (ISCSI_KCQE_OPCODE_INIT)
+
+#define CDU_REGION_NUMBER_XCM_AG 2
+#define CDU_REGION_NUMBER_UCM_AG 4
+
+#endif
+
diff --git a/drivers/net/cnic_defs.h b/drivers/net/cnic_defs.h
new file mode 100644 (file)
index 0000000..cee80f6
--- /dev/null
@@ -0,0 +1,580 @@
+
+/* cnic.c: Broadcom CNIC core network driver.
+ *
+ * Copyright (c) 2006-2009 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ */
+
+#ifndef CNIC_DEFS_H
+#define CNIC_DEFS_H
+
+/* KWQ (kernel work queue) request op codes */
+#define L2_KWQE_OPCODE_VALUE_FLUSH                  (4)
+
+#define L4_KWQE_OPCODE_VALUE_CONNECT1               (50)
+#define L4_KWQE_OPCODE_VALUE_CONNECT2               (51)
+#define L4_KWQE_OPCODE_VALUE_CONNECT3               (52)
+#define L4_KWQE_OPCODE_VALUE_RESET                  (53)
+#define L4_KWQE_OPCODE_VALUE_CLOSE                  (54)
+#define L4_KWQE_OPCODE_VALUE_UPDATE_SECRET          (60)
+#define L4_KWQE_OPCODE_VALUE_INIT_ULP               (61)
+
+#define L4_KWQE_OPCODE_VALUE_OFFLOAD_PG             (1)
+#define L4_KWQE_OPCODE_VALUE_UPDATE_PG              (9)
+#define L4_KWQE_OPCODE_VALUE_UPLOAD_PG              (14)
+
+#define L5CM_RAMROD_CMD_ID_BASE                        (0x80)
+#define L5CM_RAMROD_CMD_ID_TCP_CONNECT         (L5CM_RAMROD_CMD_ID_BASE + 3)
+#define L5CM_RAMROD_CMD_ID_CLOSE               (L5CM_RAMROD_CMD_ID_BASE + 12)
+#define L5CM_RAMROD_CMD_ID_ABORT               (L5CM_RAMROD_CMD_ID_BASE + 13)
+#define L5CM_RAMROD_CMD_ID_SEARCHER_DELETE     (L5CM_RAMROD_CMD_ID_BASE + 14)
+#define L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD   (L5CM_RAMROD_CMD_ID_BASE + 15)
+
+/* KCQ (kernel completion queue) response op codes */
+#define L4_KCQE_OPCODE_VALUE_CLOSE_COMP             (53)
+#define L4_KCQE_OPCODE_VALUE_RESET_COMP             (54)
+#define L4_KCQE_OPCODE_VALUE_FW_TCP_UPDATE          (55)
+#define L4_KCQE_OPCODE_VALUE_CONNECT_COMPLETE       (56)
+#define L4_KCQE_OPCODE_VALUE_RESET_RECEIVED         (57)
+#define L4_KCQE_OPCODE_VALUE_CLOSE_RECEIVED         (58)
+#define L4_KCQE_OPCODE_VALUE_INIT_ULP               (61)
+
+#define L4_KCQE_OPCODE_VALUE_OFFLOAD_PG             (1)
+#define L4_KCQE_OPCODE_VALUE_UPDATE_PG              (9)
+#define L4_KCQE_OPCODE_VALUE_UPLOAD_PG              (14)
+
+/* KCQ (kernel completion queue) completion status */
+#define L4_KCQE_COMPLETION_STATUS_SUCCESS                  (0)
+#define L4_KCQE_COMPLETION_STATUS_TIMEOUT        (0x93)
+
+#define L4_LAYER_CODE (4)
+#define L2_LAYER_CODE (2)
+
+/*
+ * L4 KCQ CQE
+ */
+struct l4_kcq {
+       u32 cid;
+       u32 pg_cid;
+       u32 conn_id;
+       u32 pg_host_opaque;
+#if defined(__BIG_ENDIAN)
+       u16 status;
+       u16 reserved1;
+#elif defined(__LITTLE_ENDIAN)
+       u16 reserved1;
+       u16 status;
+#endif
+       u32 reserved2[2];
+#if defined(__BIG_ENDIAN)
+       u8 flags;
+#define L4_KCQ_RESERVED3 (0x7<<0)
+#define L4_KCQ_RESERVED3_SHIFT 0
+#define L4_KCQ_RAMROD_COMPLETION (0x1<<3) /* Everest only */
+#define L4_KCQ_RAMROD_COMPLETION_SHIFT 3
+#define L4_KCQ_LAYER_CODE (0x7<<4)
+#define L4_KCQ_LAYER_CODE_SHIFT 4
+#define L4_KCQ_RESERVED4 (0x1<<7)
+#define L4_KCQ_RESERVED4_SHIFT 7
+       u8 op_code;
+       u16 qe_self_seq;
+#elif defined(__LITTLE_ENDIAN)
+       u16 qe_self_seq;
+       u8 op_code;
+       u8 flags;
+#define L4_KCQ_RESERVED3 (0xF<<0)
+#define L4_KCQ_RESERVED3_SHIFT 0
+#define L4_KCQ_RAMROD_COMPLETION (0x1<<3) /* Everest only */
+#define L4_KCQ_RAMROD_COMPLETION_SHIFT 3
+#define L4_KCQ_LAYER_CODE (0x7<<4)
+#define L4_KCQ_LAYER_CODE_SHIFT 4
+#define L4_KCQ_RESERVED4 (0x1<<7)
+#define L4_KCQ_RESERVED4_SHIFT 7
+#endif
+};
+
+
+/*
+ * L4 KCQ CQE PG upload
+ */
+struct l4_kcq_upload_pg {
+       u32 pg_cid;
+#if defined(__BIG_ENDIAN)
+       u16 pg_status;
+       u16 pg_ipid_count;
+#elif defined(__LITTLE_ENDIAN)
+       u16 pg_ipid_count;
+       u16 pg_status;
+#endif
+       u32 reserved1[5];
+#if defined(__BIG_ENDIAN)
+       u8 flags;
+#define L4_KCQ_UPLOAD_PG_RESERVED3 (0xF<<0)
+#define L4_KCQ_UPLOAD_PG_RESERVED3_SHIFT 0
+#define L4_KCQ_UPLOAD_PG_LAYER_CODE (0x7<<4)
+#define L4_KCQ_UPLOAD_PG_LAYER_CODE_SHIFT 4
+#define L4_KCQ_UPLOAD_PG_RESERVED4 (0x1<<7)
+#define L4_KCQ_UPLOAD_PG_RESERVED4_SHIFT 7
+       u8 op_code;
+       u16 qe_self_seq;
+#elif defined(__LITTLE_ENDIAN)
+       u16 qe_self_seq;
+       u8 op_code;
+       u8 flags;
+#define L4_KCQ_UPLOAD_PG_RESERVED3 (0xF<<0)
+#define L4_KCQ_UPLOAD_PG_RESERVED3_SHIFT 0
+#define L4_KCQ_UPLOAD_PG_LAYER_CODE (0x7<<4)
+#define L4_KCQ_UPLOAD_PG_LAYER_CODE_SHIFT 4
+#define L4_KCQ_UPLOAD_PG_RESERVED4 (0x1<<7)
+#define L4_KCQ_UPLOAD_PG_RESERVED4_SHIFT 7
+#endif
+};
+
+
+/*
+ * Gracefully close the connection request
+ */
+struct l4_kwq_close_req {
+#if defined(__BIG_ENDIAN)
+       u8 flags;
+#define L4_KWQ_CLOSE_REQ_RESERVED1 (0xF<<0)
+#define L4_KWQ_CLOSE_REQ_RESERVED1_SHIFT 0
+#define L4_KWQ_CLOSE_REQ_LAYER_CODE (0x7<<4)
+#define L4_KWQ_CLOSE_REQ_LAYER_CODE_SHIFT 4
+#define L4_KWQ_CLOSE_REQ_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_CLOSE_REQ_LINKED_WITH_NEXT_SHIFT 7
+       u8 op_code;
+       u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+       u16 reserved0;
+       u8 op_code;
+       u8 flags;
+#define L4_KWQ_CLOSE_REQ_RESERVED1 (0xF<<0)
+#define L4_KWQ_CLOSE_REQ_RESERVED1_SHIFT 0
+#define L4_KWQ_CLOSE_REQ_LAYER_CODE (0x7<<4)
+#define L4_KWQ_CLOSE_REQ_LAYER_CODE_SHIFT 4
+#define L4_KWQ_CLOSE_REQ_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_CLOSE_REQ_LINKED_WITH_NEXT_SHIFT 7
+#endif
+       u32 cid;
+       u32 reserved2[6];
+};
+
+
+/*
+ * The first request to be passed in order to establish connection in option2
+ */
+struct l4_kwq_connect_req1 {
+#if defined(__BIG_ENDIAN)
+       u8 flags;
+#define L4_KWQ_CONNECT_REQ1_RESERVED1 (0xF<<0)
+#define L4_KWQ_CONNECT_REQ1_RESERVED1_SHIFT 0
+#define L4_KWQ_CONNECT_REQ1_LAYER_CODE (0x7<<4)
+#define L4_KWQ_CONNECT_REQ1_LAYER_CODE_SHIFT 4
+#define L4_KWQ_CONNECT_REQ1_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_CONNECT_REQ1_LINKED_WITH_NEXT_SHIFT 7
+       u8 op_code;
+       u8 reserved0;
+       u8 conn_flags;
+#define L4_KWQ_CONNECT_REQ1_IS_PG_HOST_OPAQUE (0x1<<0)
+#define L4_KWQ_CONNECT_REQ1_IS_PG_HOST_OPAQUE_SHIFT 0
+#define L4_KWQ_CONNECT_REQ1_IP_V6 (0x1<<1)
+#define L4_KWQ_CONNECT_REQ1_IP_V6_SHIFT 1
+#define L4_KWQ_CONNECT_REQ1_PASSIVE_FLAG (0x1<<2)
+#define L4_KWQ_CONNECT_REQ1_PASSIVE_FLAG_SHIFT 2
+#define L4_KWQ_CONNECT_REQ1_RSRV (0x1F<<3)
+#define L4_KWQ_CONNECT_REQ1_RSRV_SHIFT 3
+#elif defined(__LITTLE_ENDIAN)
+       u8 conn_flags;
+#define L4_KWQ_CONNECT_REQ1_IS_PG_HOST_OPAQUE (0x1<<0)
+#define L4_KWQ_CONNECT_REQ1_IS_PG_HOST_OPAQUE_SHIFT 0
+#define L4_KWQ_CONNECT_REQ1_IP_V6 (0x1<<1)
+#define L4_KWQ_CONNECT_REQ1_IP_V6_SHIFT 1
+#define L4_KWQ_CONNECT_REQ1_PASSIVE_FLAG (0x1<<2)
+#define L4_KWQ_CONNECT_REQ1_PASSIVE_FLAG_SHIFT 2
+#define L4_KWQ_CONNECT_REQ1_RSRV (0x1F<<3)
+#define L4_KWQ_CONNECT_REQ1_RSRV_SHIFT 3
+       u8 reserved0;
+       u8 op_code;
+       u8 flags;
+#define L4_KWQ_CONNECT_REQ1_RESERVED1 (0xF<<0)
+#define L4_KWQ_CONNECT_REQ1_RESERVED1_SHIFT 0
+#define L4_KWQ_CONNECT_REQ1_LAYER_CODE (0x7<<4)
+#define L4_KWQ_CONNECT_REQ1_LAYER_CODE_SHIFT 4
+#define L4_KWQ_CONNECT_REQ1_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_CONNECT_REQ1_LINKED_WITH_NEXT_SHIFT 7
+#endif
+       u32 cid;
+       u32 pg_cid;
+       u32 src_ip;
+       u32 dst_ip;
+#if defined(__BIG_ENDIAN)
+       u16 dst_port;
+       u16 src_port;
+#elif defined(__LITTLE_ENDIAN)
+       u16 src_port;
+       u16 dst_port;
+#endif
+#if defined(__BIG_ENDIAN)
+       u8 rsrv1[3];
+       u8 tcp_flags;
+#define L4_KWQ_CONNECT_REQ1_NO_DELAY_ACK (0x1<<0)
+#define L4_KWQ_CONNECT_REQ1_NO_DELAY_ACK_SHIFT 0
+#define L4_KWQ_CONNECT_REQ1_KEEP_ALIVE (0x1<<1)
+#define L4_KWQ_CONNECT_REQ1_KEEP_ALIVE_SHIFT 1
+#define L4_KWQ_CONNECT_REQ1_NAGLE_ENABLE (0x1<<2)
+#define L4_KWQ_CONNECT_REQ1_NAGLE_ENABLE_SHIFT 2
+#define L4_KWQ_CONNECT_REQ1_TIME_STAMP (0x1<<3)
+#define L4_KWQ_CONNECT_REQ1_TIME_STAMP_SHIFT 3
+#define L4_KWQ_CONNECT_REQ1_SACK (0x1<<4)
+#define L4_KWQ_CONNECT_REQ1_SACK_SHIFT 4
+#define L4_KWQ_CONNECT_REQ1_SEG_SCALING (0x1<<5)
+#define L4_KWQ_CONNECT_REQ1_SEG_SCALING_SHIFT 5
+#define L4_KWQ_CONNECT_REQ1_RESERVED2 (0x3<<6)
+#define L4_KWQ_CONNECT_REQ1_RESERVED2_SHIFT 6
+#elif defined(__LITTLE_ENDIAN)
+       u8 tcp_flags;
+#define L4_KWQ_CONNECT_REQ1_NO_DELAY_ACK (0x1<<0)
+#define L4_KWQ_CONNECT_REQ1_NO_DELAY_ACK_SHIFT 0
+#define L4_KWQ_CONNECT_REQ1_KEEP_ALIVE (0x1<<1)
+#define L4_KWQ_CONNECT_REQ1_KEEP_ALIVE_SHIFT 1
+#define L4_KWQ_CONNECT_REQ1_NAGLE_ENABLE (0x1<<2)
+#define L4_KWQ_CONNECT_REQ1_NAGLE_ENABLE_SHIFT 2
+#define L4_KWQ_CONNECT_REQ1_TIME_STAMP (0x1<<3)
+#define L4_KWQ_CONNECT_REQ1_TIME_STAMP_SHIFT 3
+#define L4_KWQ_CONNECT_REQ1_SACK (0x1<<4)
+#define L4_KWQ_CONNECT_REQ1_SACK_SHIFT 4
+#define L4_KWQ_CONNECT_REQ1_SEG_SCALING (0x1<<5)
+#define L4_KWQ_CONNECT_REQ1_SEG_SCALING_SHIFT 5
+#define L4_KWQ_CONNECT_REQ1_RESERVED2 (0x3<<6)
+#define L4_KWQ_CONNECT_REQ1_RESERVED2_SHIFT 6
+       u8 rsrv1[3];
+#endif
+       u32 rsrv2;
+};
+
+
+/*
+ * The second ( optional )request to be passed in order to establish
+ * connection in option2 - for IPv6 only
+ */
+struct l4_kwq_connect_req2 {
+#if defined(__BIG_ENDIAN)
+       u8 flags;
+#define L4_KWQ_CONNECT_REQ2_RESERVED1 (0xF<<0)
+#define L4_KWQ_CONNECT_REQ2_RESERVED1_SHIFT 0
+#define L4_KWQ_CONNECT_REQ2_LAYER_CODE (0x7<<4)
+#define L4_KWQ_CONNECT_REQ2_LAYER_CODE_SHIFT 4
+#define L4_KWQ_CONNECT_REQ2_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_CONNECT_REQ2_LINKED_WITH_NEXT_SHIFT 7
+       u8 op_code;
+       u8 reserved0;
+       u8 rsrv;
+#elif defined(__LITTLE_ENDIAN)
+       u8 rsrv;
+       u8 reserved0;
+       u8 op_code;
+       u8 flags;
+#define L4_KWQ_CONNECT_REQ2_RESERVED1 (0xF<<0)
+#define L4_KWQ_CONNECT_REQ2_RESERVED1_SHIFT 0
+#define L4_KWQ_CONNECT_REQ2_LAYER_CODE (0x7<<4)
+#define L4_KWQ_CONNECT_REQ2_LAYER_CODE_SHIFT 4
+#define L4_KWQ_CONNECT_REQ2_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_CONNECT_REQ2_LINKED_WITH_NEXT_SHIFT 7
+#endif
+       u32 reserved2;
+       u32 src_ip_v6_2;
+       u32 src_ip_v6_3;
+       u32 src_ip_v6_4;
+       u32 dst_ip_v6_2;
+       u32 dst_ip_v6_3;
+       u32 dst_ip_v6_4;
+};
+
+
+/*
+ * The third ( and last )request to be passed in order to establish
+ * connection in option2
+ */
+struct l4_kwq_connect_req3 {
+#if defined(__BIG_ENDIAN)
+       u8 flags;
+#define L4_KWQ_CONNECT_REQ3_RESERVED1 (0xF<<0)
+#define L4_KWQ_CONNECT_REQ3_RESERVED1_SHIFT 0
+#define L4_KWQ_CONNECT_REQ3_LAYER_CODE (0x7<<4)
+#define L4_KWQ_CONNECT_REQ3_LAYER_CODE_SHIFT 4
+#define L4_KWQ_CONNECT_REQ3_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_CONNECT_REQ3_LINKED_WITH_NEXT_SHIFT 7
+       u8 op_code;
+       u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+       u16 reserved0;
+       u8 op_code;
+       u8 flags;
+#define L4_KWQ_CONNECT_REQ3_RESERVED1 (0xF<<0)
+#define L4_KWQ_CONNECT_REQ3_RESERVED1_SHIFT 0
+#define L4_KWQ_CONNECT_REQ3_LAYER_CODE (0x7<<4)
+#define L4_KWQ_CONNECT_REQ3_LAYER_CODE_SHIFT 4
+#define L4_KWQ_CONNECT_REQ3_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_CONNECT_REQ3_LINKED_WITH_NEXT_SHIFT 7
+#endif
+       u32 ka_timeout;
+       u32 ka_interval ;
+#if defined(__BIG_ENDIAN)
+       u8 snd_seq_scale;
+       u8 ttl;
+       u8 tos;
+       u8 ka_max_probe_count;
+#elif defined(__LITTLE_ENDIAN)
+       u8 ka_max_probe_count;
+       u8 tos;
+       u8 ttl;
+       u8 snd_seq_scale;
+#endif
+#if defined(__BIG_ENDIAN)
+       u16 pmtu;
+       u16 mss;
+#elif defined(__LITTLE_ENDIAN)
+       u16 mss;
+       u16 pmtu;
+#endif
+       u32 rcv_buf;
+       u32 snd_buf;
+       u32 seed;
+};
+
+
+/*
+ * a KWQE request to offload a PG connection
+ */
+struct l4_kwq_offload_pg {
+#if defined(__BIG_ENDIAN)
+       u8 flags;
+#define L4_KWQ_OFFLOAD_PG_RESERVED1 (0xF<<0)
+#define L4_KWQ_OFFLOAD_PG_RESERVED1_SHIFT 0
+#define L4_KWQ_OFFLOAD_PG_LAYER_CODE (0x7<<4)
+#define L4_KWQ_OFFLOAD_PG_LAYER_CODE_SHIFT 4
+#define L4_KWQ_OFFLOAD_PG_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_OFFLOAD_PG_LINKED_WITH_NEXT_SHIFT 7
+       u8 op_code;
+       u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+       u16 reserved0;
+       u8 op_code;
+       u8 flags;
+#define L4_KWQ_OFFLOAD_PG_RESERVED1 (0xF<<0)
+#define L4_KWQ_OFFLOAD_PG_RESERVED1_SHIFT 0
+#define L4_KWQ_OFFLOAD_PG_LAYER_CODE (0x7<<4)
+#define L4_KWQ_OFFLOAD_PG_LAYER_CODE_SHIFT 4
+#define L4_KWQ_OFFLOAD_PG_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_OFFLOAD_PG_LINKED_WITH_NEXT_SHIFT 7
+#endif
+#if defined(__BIG_ENDIAN)
+       u8 l2hdr_nbytes;
+       u8 pg_flags;
+#define L4_KWQ_OFFLOAD_PG_SNAP_ENCAP (0x1<<0)
+#define L4_KWQ_OFFLOAD_PG_SNAP_ENCAP_SHIFT 0
+#define L4_KWQ_OFFLOAD_PG_VLAN_TAGGING (0x1<<1)
+#define L4_KWQ_OFFLOAD_PG_VLAN_TAGGING_SHIFT 1
+#define L4_KWQ_OFFLOAD_PG_RESERVED2 (0x3F<<2)
+#define L4_KWQ_OFFLOAD_PG_RESERVED2_SHIFT 2
+       u8 da0;
+       u8 da1;
+#elif defined(__LITTLE_ENDIAN)
+       u8 da1;
+       u8 da0;
+       u8 pg_flags;
+#define L4_KWQ_OFFLOAD_PG_SNAP_ENCAP (0x1<<0)
+#define L4_KWQ_OFFLOAD_PG_SNAP_ENCAP_SHIFT 0
+#define L4_KWQ_OFFLOAD_PG_VLAN_TAGGING (0x1<<1)
+#define L4_KWQ_OFFLOAD_PG_VLAN_TAGGING_SHIFT 1
+#define L4_KWQ_OFFLOAD_PG_RESERVED2 (0x3F<<2)
+#define L4_KWQ_OFFLOAD_PG_RESERVED2_SHIFT 2
+       u8 l2hdr_nbytes;
+#endif
+#if defined(__BIG_ENDIAN)
+       u8 da2;
+       u8 da3;
+       u8 da4;
+       u8 da5;
+#elif defined(__LITTLE_ENDIAN)
+       u8 da5;
+       u8 da4;
+       u8 da3;
+       u8 da2;
+#endif
+#if defined(__BIG_ENDIAN)
+       u8 sa0;
+       u8 sa1;
+       u8 sa2;
+       u8 sa3;
+#elif defined(__LITTLE_ENDIAN)
+       u8 sa3;
+       u8 sa2;
+       u8 sa1;
+       u8 sa0;
+#endif
+#if defined(__BIG_ENDIAN)
+       u8 sa4;
+       u8 sa5;
+       u16 etype;
+#elif defined(__LITTLE_ENDIAN)
+       u16 etype;
+       u8 sa5;
+       u8 sa4;
+#endif
+#if defined(__BIG_ENDIAN)
+       u16 vlan_tag;
+       u16 ipid_start;
+#elif defined(__LITTLE_ENDIAN)
+       u16 ipid_start;
+       u16 vlan_tag;
+#endif
+#if defined(__BIG_ENDIAN)
+       u16 ipid_count;
+       u16 reserved3;
+#elif defined(__LITTLE_ENDIAN)
+       u16 reserved3;
+       u16 ipid_count;
+#endif
+       u32 host_opaque;
+};
+
+
+/*
+ * Abortively close the connection request
+ */
+struct l4_kwq_reset_req {
+#if defined(__BIG_ENDIAN)
+       u8 flags;
+#define L4_KWQ_RESET_REQ_RESERVED1 (0xF<<0)
+#define L4_KWQ_RESET_REQ_RESERVED1_SHIFT 0
+#define L4_KWQ_RESET_REQ_LAYER_CODE (0x7<<4)
+#define L4_KWQ_RESET_REQ_LAYER_CODE_SHIFT 4
+#define L4_KWQ_RESET_REQ_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_RESET_REQ_LINKED_WITH_NEXT_SHIFT 7
+       u8 op_code;
+       u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+       u16 reserved0;
+       u8 op_code;
+       u8 flags;
+#define L4_KWQ_RESET_REQ_RESERVED1 (0xF<<0)
+#define L4_KWQ_RESET_REQ_RESERVED1_SHIFT 0
+#define L4_KWQ_RESET_REQ_LAYER_CODE (0x7<<4)
+#define L4_KWQ_RESET_REQ_LAYER_CODE_SHIFT 4
+#define L4_KWQ_RESET_REQ_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_RESET_REQ_LINKED_WITH_NEXT_SHIFT 7
+#endif
+       u32 cid;
+       u32 reserved2[6];
+};
+
+
+/*
+ * a KWQE request to update a PG connection
+ */
+struct l4_kwq_update_pg {
+#if defined(__BIG_ENDIAN)
+       u8 flags;
+#define L4_KWQ_UPDATE_PG_RESERVED1 (0xF<<0)
+#define L4_KWQ_UPDATE_PG_RESERVED1_SHIFT 0
+#define L4_KWQ_UPDATE_PG_LAYER_CODE (0x7<<4)
+#define L4_KWQ_UPDATE_PG_LAYER_CODE_SHIFT 4
+#define L4_KWQ_UPDATE_PG_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_UPDATE_PG_LINKED_WITH_NEXT_SHIFT 7
+       u8 opcode;
+       u16 oper16;
+#elif defined(__LITTLE_ENDIAN)
+       u16 oper16;
+       u8 opcode;
+       u8 flags;
+#define L4_KWQ_UPDATE_PG_RESERVED1 (0xF<<0)
+#define L4_KWQ_UPDATE_PG_RESERVED1_SHIFT 0
+#define L4_KWQ_UPDATE_PG_LAYER_CODE (0x7<<4)
+#define L4_KWQ_UPDATE_PG_LAYER_CODE_SHIFT 4
+#define L4_KWQ_UPDATE_PG_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_UPDATE_PG_LINKED_WITH_NEXT_SHIFT 7
+#endif
+       u32 pg_cid;
+       u32 pg_host_opaque;
+#if defined(__BIG_ENDIAN)
+       u8 pg_valids;
+#define L4_KWQ_UPDATE_PG_VALIDS_IPID_COUNT (0x1<<0)
+#define L4_KWQ_UPDATE_PG_VALIDS_IPID_COUNT_SHIFT 0
+#define L4_KWQ_UPDATE_PG_VALIDS_DA (0x1<<1)
+#define L4_KWQ_UPDATE_PG_VALIDS_DA_SHIFT 1
+#define L4_KWQ_UPDATE_PG_RESERVERD2 (0x3F<<2)
+#define L4_KWQ_UPDATE_PG_RESERVERD2_SHIFT 2
+       u8 pg_unused_a;
+       u16 pg_ipid_count;
+#elif defined(__LITTLE_ENDIAN)
+       u16 pg_ipid_count;
+       u8 pg_unused_a;
+       u8 pg_valids;
+#define L4_KWQ_UPDATE_PG_VALIDS_IPID_COUNT (0x1<<0)
+#define L4_KWQ_UPDATE_PG_VALIDS_IPID_COUNT_SHIFT 0
+#define L4_KWQ_UPDATE_PG_VALIDS_DA (0x1<<1)
+#define L4_KWQ_UPDATE_PG_VALIDS_DA_SHIFT 1
+#define L4_KWQ_UPDATE_PG_RESERVERD2 (0x3F<<2)
+#define L4_KWQ_UPDATE_PG_RESERVERD2_SHIFT 2
+#endif
+#if defined(__BIG_ENDIAN)
+       u16 reserverd3;
+       u8 da0;
+       u8 da1;
+#elif defined(__LITTLE_ENDIAN)
+       u8 da1;
+       u8 da0;
+       u16 reserverd3;
+#endif
+#if defined(__BIG_ENDIAN)
+       u8 da2;
+       u8 da3;
+       u8 da4;
+       u8 da5;
+#elif defined(__LITTLE_ENDIAN)
+       u8 da5;
+       u8 da4;
+       u8 da3;
+       u8 da2;
+#endif
+       u32 reserved4;
+       u32 reserved5;
+};
+
+
+/*
+ * a KWQE request to upload a PG or L4 context
+ */
+struct l4_kwq_upload {
+#if defined(__BIG_ENDIAN)
+       u8 flags;
+#define L4_KWQ_UPLOAD_RESERVED1 (0xF<<0)
+#define L4_KWQ_UPLOAD_RESERVED1_SHIFT 0
+#define L4_KWQ_UPLOAD_LAYER_CODE (0x7<<4)
+#define L4_KWQ_UPLOAD_LAYER_CODE_SHIFT 4
+#define L4_KWQ_UPLOAD_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_UPLOAD_LINKED_WITH_NEXT_SHIFT 7
+       u8 opcode;
+       u16 oper16;
+#elif defined(__LITTLE_ENDIAN)
+       u16 oper16;
+       u8 opcode;
+       u8 flags;
+#define L4_KWQ_UPLOAD_RESERVED1 (0xF<<0)
+#define L4_KWQ_UPLOAD_RESERVED1_SHIFT 0
+#define L4_KWQ_UPLOAD_LAYER_CODE (0x7<<4)
+#define L4_KWQ_UPLOAD_LAYER_CODE_SHIFT 4
+#define L4_KWQ_UPLOAD_LINKED_WITH_NEXT (0x1<<7)
+#define L4_KWQ_UPLOAD_LINKED_WITH_NEXT_SHIFT 7
+#endif
+       u32 cid;
+       u32 reserved2[6];
+};
+
+#endif /* CNIC_DEFS_H */
diff --git a/drivers/net/cnic_if.h b/drivers/net/cnic_if.h
new file mode 100644 (file)
index 0000000..0638096
--- /dev/null
@@ -0,0 +1,299 @@
+/* cnic_if.h: Broadcom CNIC core network driver.
+ *
+ * Copyright (c) 2006 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ */
+
+
+#ifndef CNIC_IF_H
+#define CNIC_IF_H
+
+#define CNIC_MODULE_VERSION    "2.0.0"
+#define CNIC_MODULE_RELDATE    "May 21, 2009"
+
+#define CNIC_ULP_RDMA          0
+#define CNIC_ULP_ISCSI         1
+#define CNIC_ULP_L4            2
+#define MAX_CNIC_ULP_TYPE_EXT  2
+#define MAX_CNIC_ULP_TYPE      3
+
+struct kwqe {
+       u32 kwqe_op_flag;
+
+#define KWQE_OPCODE_MASK       0x00ff0000
+#define KWQE_OPCODE_SHIFT      16
+#define KWQE_FLAGS_LAYER_SHIFT 28
+#define KWQE_OPCODE(x)         ((x & KWQE_OPCODE_MASK) >> KWQE_OPCODE_SHIFT)
+
+       u32 kwqe_info0;
+       u32 kwqe_info1;
+       u32 kwqe_info2;
+       u32 kwqe_info3;
+       u32 kwqe_info4;
+       u32 kwqe_info5;
+       u32 kwqe_info6;
+};
+
+struct kwqe_16 {
+       u32 kwqe_info0;
+       u32 kwqe_info1;
+       u32 kwqe_info2;
+       u32 kwqe_info3;
+};
+
+struct kcqe {
+       u32 kcqe_info0;
+       u32 kcqe_info1;
+       u32 kcqe_info2;
+       u32 kcqe_info3;
+       u32 kcqe_info4;
+       u32 kcqe_info5;
+       u32 kcqe_info6;
+       u32 kcqe_op_flag;
+               #define KCQE_RAMROD_COMPLETION          (0x1<<27) /* Everest */
+               #define KCQE_FLAGS_LAYER_MASK           (0x7<<28)
+               #define KCQE_FLAGS_LAYER_MASK_MISC      (0<<28)
+               #define KCQE_FLAGS_LAYER_MASK_L2        (2<<28)
+               #define KCQE_FLAGS_LAYER_MASK_L3        (3<<28)
+               #define KCQE_FLAGS_LAYER_MASK_L4        (4<<28)
+               #define KCQE_FLAGS_LAYER_MASK_L5_RDMA   (5<<28)
+               #define KCQE_FLAGS_LAYER_MASK_L5_ISCSI  (6<<28)
+               #define KCQE_FLAGS_NEXT                 (1<<31)
+               #define KCQE_FLAGS_OPCODE_MASK          (0xff<<16)
+               #define KCQE_FLAGS_OPCODE_SHIFT         (16)
+               #define KCQE_OPCODE(op)                 \
+               (((op) & KCQE_FLAGS_OPCODE_MASK) >> KCQE_FLAGS_OPCODE_SHIFT)
+};
+
+#define MAX_CNIC_CTL_DATA      64
+#define MAX_DRV_CTL_DATA       64
+
+#define CNIC_CTL_STOP_CMD              1
+#define CNIC_CTL_START_CMD             2
+#define CNIC_CTL_COMPLETION_CMD                3
+
+#define DRV_CTL_IO_WR_CMD              0x101
+#define DRV_CTL_IO_RD_CMD              0x102
+#define DRV_CTL_CTX_WR_CMD             0x103
+#define DRV_CTL_CTXTBL_WR_CMD          0x104
+#define DRV_CTL_COMPLETION_CMD         0x105
+
+struct cnic_ctl_completion {
+       u32     cid;
+};
+
+struct drv_ctl_completion {
+       u32     comp_count;
+};
+
+struct cnic_ctl_info {
+       int     cmd;
+       union {
+               struct cnic_ctl_completion comp;
+               char bytes[MAX_CNIC_CTL_DATA];
+       } data;
+};
+
+struct drv_ctl_io {
+       u32             cid_addr;
+       u32             offset;
+       u32             data;
+       dma_addr_t      dma_addr;
+};
+
+struct drv_ctl_info {
+       int     cmd;
+       union {
+               struct drv_ctl_completion comp;
+               struct drv_ctl_io io;
+               char bytes[MAX_DRV_CTL_DATA];
+       } data;
+};
+
+struct cnic_ops {
+       struct module   *cnic_owner;
+       /* Calls to these functions are protected by RCU.  When
+        * unregistering, we wait for any calls to complete before
+        * continuing.
+        */
+       int             (*cnic_handler)(void *, void *);
+       int             (*cnic_ctl)(void *, struct cnic_ctl_info *);
+};
+
+#define MAX_CNIC_VEC   8
+
+struct cnic_irq {
+       unsigned int    vector;
+       void            *status_blk;
+       u32             status_blk_num;
+       u32             irq_flags;
+#define CNIC_IRQ_FL_MSIX               0x00000001
+};
+
+struct cnic_eth_dev {
+       struct module   *drv_owner;
+       u32             drv_state;
+#define CNIC_DRV_STATE_REGD            0x00000001
+#define CNIC_DRV_STATE_USING_MSIX      0x00000002
+       u32             chip_id;
+       u32             max_kwqe_pending;
+       struct pci_dev  *pdev;
+       void __iomem    *io_base;
+
+       u32             ctx_tbl_offset;
+       u32             ctx_tbl_len;
+       int             ctx_blk_size;
+       u32             starting_cid;
+       u32             max_iscsi_conn;
+       u32             max_fcoe_conn;
+       u32             max_rdma_conn;
+       u32             reserved0[2];
+
+       int             num_irq;
+       struct cnic_irq irq_arr[MAX_CNIC_VEC];
+       int             (*drv_register_cnic)(struct net_device *,
+                                            struct cnic_ops *, void *);
+       int             (*drv_unregister_cnic)(struct net_device *);
+       int             (*drv_submit_kwqes_32)(struct net_device *,
+                                              struct kwqe *[], u32);
+       int             (*drv_submit_kwqes_16)(struct net_device *,
+                                              struct kwqe_16 *[], u32);
+       int             (*drv_ctl)(struct net_device *, struct drv_ctl_info *);
+       unsigned long   reserved1[2];
+};
+
+struct cnic_sockaddr {
+       union {
+               struct sockaddr_in      v4;
+               struct sockaddr_in6     v6;
+       } local;
+       union {
+               struct sockaddr_in      v4;
+               struct sockaddr_in6     v6;
+       } remote;
+};
+
+struct cnic_sock {
+       struct cnic_dev *dev;
+       void    *context;
+       u32     src_ip[4];
+       u32     dst_ip[4];
+       u16     src_port;
+       u16     dst_port;
+       u16     vlan_id;
+       unsigned char old_ha[6];
+       unsigned char ha[6];
+       u32     mtu;
+       u32     cid;
+       u32     l5_cid;
+       u32     pg_cid;
+       int     ulp_type;
+
+       u32     ka_timeout;
+       u32     ka_interval;
+       u8      ka_max_probe_count;
+       u8      tos;
+       u8      ttl;
+       u8      snd_seq_scale;
+       u32     rcv_buf;
+       u32     snd_buf;
+       u32     seed;
+
+       unsigned long   tcp_flags;
+#define SK_TCP_NO_DELAY_ACK    0x1
+#define SK_TCP_KEEP_ALIVE      0x2
+#define SK_TCP_NAGLE           0x4
+#define SK_TCP_TIMESTAMP       0x8
+#define SK_TCP_SACK            0x10
+#define SK_TCP_SEG_SCALING     0x20
+       unsigned long   flags;
+#define SK_F_INUSE             0
+#define SK_F_OFFLD_COMPLETE    1
+#define SK_F_OFFLD_SCHED       2
+#define SK_F_PG_OFFLD_COMPLETE 3
+#define SK_F_CONNECT_START     4
+#define SK_F_IPV6              5
+#define SK_F_CLOSING           7
+
+       atomic_t ref_count;
+       u32 state;
+       struct kwqe kwqe1;
+       struct kwqe kwqe2;
+       struct kwqe kwqe3;
+};
+
+struct cnic_dev {
+       struct net_device       *netdev;
+       struct pci_dev          *pcidev;
+       void __iomem            *regview;
+       struct list_head        list;
+
+       int (*register_device)(struct cnic_dev *dev, int ulp_type,
+                              void *ulp_ctx);
+       int (*unregister_device)(struct cnic_dev *dev, int ulp_type);
+       int (*submit_kwqes)(struct cnic_dev *dev, struct kwqe *wqes[],
+                               u32 num_wqes);
+       int (*submit_kwqes_16)(struct cnic_dev *dev, struct kwqe_16 *wqes[],
+                               u32 num_wqes);
+
+       int (*cm_create)(struct cnic_dev *, int, u32, u32, struct cnic_sock **,
+                        void *);
+       int (*cm_destroy)(struct cnic_sock *);
+       int (*cm_connect)(struct cnic_sock *, struct cnic_sockaddr *);
+       int (*cm_abort)(struct cnic_sock *);
+       int (*cm_close)(struct cnic_sock *);
+       struct cnic_dev *(*cm_select_dev)(struct sockaddr_in *, int ulp_type);
+       int (*iscsi_nl_msg_recv)(struct cnic_dev *dev, u32 msg_type,
+                                char *data, u16 data_size);
+       unsigned long   flags;
+#define CNIC_F_CNIC_UP         1
+#define CNIC_F_BNX2_CLASS      3
+#define CNIC_F_BNX2X_CLASS     4
+       atomic_t        ref_count;
+       u8              mac_addr[6];
+
+       int             max_iscsi_conn;
+       int             max_fcoe_conn;
+       int             max_rdma_conn;
+
+       void            *cnic_priv;
+};
+
+#define CNIC_WR(dev, off, val)         writel(val, dev->regview + off)
+#define CNIC_WR16(dev, off, val)       writew(val, dev->regview + off)
+#define CNIC_WR8(dev, off, val)                writeb(val, dev->regview + off)
+#define CNIC_RD(dev, off)              readl(dev->regview + off)
+#define CNIC_RD16(dev, off)            readw(dev->regview + off)
+
+struct cnic_ulp_ops {
+       /* Calls to these functions are protected by RCU.  When
+        * unregistering, we wait for any calls to complete before
+        * continuing.
+        */
+
+       void (*cnic_init)(struct cnic_dev *dev);
+       void (*cnic_exit)(struct cnic_dev *dev);
+       void (*cnic_start)(void *ulp_ctx);
+       void (*cnic_stop)(void *ulp_ctx);
+       void (*indicate_kcqes)(void *ulp_ctx, struct kcqe *cqes[],
+                               u32 num_cqes);
+       void (*indicate_netevent)(void *ulp_ctx, unsigned long event);
+       void (*cm_connect_complete)(struct cnic_sock *);
+       void (*cm_close_complete)(struct cnic_sock *);
+       void (*cm_abort_complete)(struct cnic_sock *);
+       void (*cm_remote_close)(struct cnic_sock *);
+       void (*cm_remote_abort)(struct cnic_sock *);
+       void (*iscsi_nl_send_msg)(struct cnic_dev *dev, u32 msg_type,
+                                 char *data, u16 data_size);
+       struct module *owner;
+};
+
+extern int cnic_register_driver(int ulp_type, struct cnic_ulp_ops *ulp_ops);
+
+extern int cnic_unregister_driver(int ulp_type);
+
+#endif
index 0f9ee1348552b6d634e14b632476d8b29e6b9502..af5364f4955065421f50a30180ba378915dcc50a 100644 (file)
@@ -2785,7 +2785,7 @@ static int e100_resume(struct pci_dev *pdev)
        /* ack any pending wake events, disable PME */
        pci_enable_wake(pdev, 0, 0);
 
-       /* disbale reverse auto-negotiation */
+       /* disable reverse auto-negotiation */
        if (nic->phy == phy_82552_v) {
                u16 smartspeed = mdio_read(netdev, nic->mii.phy_id,
                                           E100_82552_SMARTSPEED);
index f37360aa12a8d11d21d5e72b416a02250bbb1a62..44f0bf23dafc241de92c7dfde76d4f9c5d4e24a3 100644 (file)
@@ -62,7 +62,7 @@ struct e1000_info;
        e_printk(KERN_NOTICE, adapter, format, ## arg)
 
 
-/* Interrupt modes, as used by the IntMode paramter */
+/* Interrupt modes, as used by the IntMode parameter */
 #define E1000E_INT_MODE_LEGACY         0
 #define E1000E_INT_MODE_MSI            1
 #define E1000E_INT_MODE_MSIX           2
index 16a41389575aeb5f510f30b7f8343e67ff392ed4..78952f8324e222df8320162cbe8eb911af58a738 100644 (file)
@@ -268,7 +268,7 @@ struct ehea_qp_init_attr {
 };
 
 /*
- * Event Queue attributes, passed as paramter
+ * Event Queue attributes, passed as parameter
  */
 struct ehea_eq_attr {
        u32 type;
index 4bff35e46871642b1908ef8abd82a043615e0dd7..d488733893a6e011dada7b47270c78b3459a26f4 100644 (file)
@@ -45,7 +45,7 @@ struct igbvf_adapter;
 /* Interrupt defines */
 #define IGBVF_START_ITR                 648 /* ~6000 ints/sec */
 
-/* Interrupt modes, as used by the IntMode paramter */
+/* Interrupt modes, as used by the IntMode parameter */
 #define IGBVF_INT_MODE_LEGACY           0
 #define IGBVF_INT_MODE_MSI              1
 #define IGBVF_INT_MODE_MSIX             2
index dd9318f19497c82915722fe774f5fe48f40ed222..dfc2541bb55628dc4c0c934958834cdc980a646b 100644 (file)
@@ -514,7 +514,7 @@ enum ipg_regs {
 #define                IPG_DMALIST_ALIGN_PAD   0x07
 #define                IPG_MULTICAST_HASHTABLE_SIZE    0x40
 
-/* Number of miliseconds to wait after issuing a software reset.
+/* Number of milliseconds to wait after issuing a software reset.
  * 0x05 <= IPG_AC_RESETWAIT to account for proper 10Mbps operation.
  */
 #define         IPG_AC_RESETWAIT             0x05
index 7bcc49de163787a5bc1c0f5015d711a40700d80f..e8eeef0c9c9ace85ccb9696cb81ee5fd1c94e452 100644 (file)
@@ -371,7 +371,7 @@ static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv)
        int i;
 
        /* If we haven't received a specific coalescing setting
-        * (module param), we set the moderation paramters as follows:
+        * (module param), we set the moderation parameters as follows:
         * - moder_cnt is set to the number of mtu sized packets to
         *   satisfy our coelsing target.
         * - moder_time is set to a fixed value.
index 8830dcb92ec8b9c9348f00c8aa1ec4bddbad3e30..ce064e324200ab58de0836a2f6fc4bcff40e3715 100644 (file)
@@ -497,8 +497,10 @@ static void mlx4_free_irqs(struct mlx4_dev *dev)
        if (eq_table->have_irq)
                free_irq(dev->pdev->irq, dev);
        for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i)
-               if (eq_table->eq[i].have_irq)
+               if (eq_table->eq[i].have_irq) {
                        free_irq(eq_table->eq[i].irq, eq_table->eq + i);
+                       eq_table->eq[i].have_irq = 0;
+               }
 
        kfree(eq_table->irq_names);
 }
index 30bea968969426659671cedca5e1562e0584c057..018348c011933b1240153f24ee95ba836c83c22c 100644 (file)
@@ -100,6 +100,10 @@ module_param_named(use_prio, use_prio, bool, 0444);
 MODULE_PARM_DESC(use_prio, "Enable steering by VLAN priority on ETH ports "
                  "(0/1, default 0)");
 
+static int log_mtts_per_seg = ilog2(MLX4_MTT_ENTRY_PER_SEG);
+module_param_named(log_mtts_per_seg, log_mtts_per_seg, int, 0444);
+MODULE_PARM_DESC(log_mtts_per_seg, "Log2 number of MTT entries per segment (1-5)");
+
 int mlx4_check_port_params(struct mlx4_dev *dev,
                           enum mlx4_port_type *port_type)
 {
@@ -203,12 +207,13 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
        dev->caps.max_cqes           = dev_cap->max_cq_sz - 1;
        dev->caps.reserved_cqs       = dev_cap->reserved_cqs;
        dev->caps.reserved_eqs       = dev_cap->reserved_eqs;
+       dev->caps.mtts_per_seg       = 1 << log_mtts_per_seg;
        dev->caps.reserved_mtts      = DIV_ROUND_UP(dev_cap->reserved_mtts,
-                                                   MLX4_MTT_ENTRY_PER_SEG);
+                                                   dev->caps.mtts_per_seg);
        dev->caps.reserved_mrws      = dev_cap->reserved_mrws;
        dev->caps.reserved_uars      = dev_cap->reserved_uars;
        dev->caps.reserved_pds       = dev_cap->reserved_pds;
-       dev->caps.mtt_entry_sz       = MLX4_MTT_ENTRY_PER_SEG * dev_cap->mtt_entry_sz;
+       dev->caps.mtt_entry_sz       = dev->caps.mtts_per_seg * dev_cap->mtt_entry_sz;
        dev->caps.max_msg_sz         = dev_cap->max_msg_sz;
        dev->caps.page_size_cap      = ~(u32) (dev_cap->min_page_sz - 1);
        dev->caps.flags              = dev_cap->flags;
@@ -1304,6 +1309,11 @@ static int __init mlx4_verify_params(void)
                return -1;
        }
 
+       if ((log_mtts_per_seg < 1) || (log_mtts_per_seg > 5)) {
+               printk(KERN_WARNING "mlx4_core: bad log_mtts_per_seg: %d\n", log_mtts_per_seg);
+               return -1;
+       }
+
        return 0;
 }
 
index 0caf74cae8bccea2446004f65d1a8ddd53efacb4..3b8973d19933d7bf2b2aa4f418ce13bc1aeca860 100644 (file)
@@ -209,7 +209,7 @@ int mlx4_mtt_init(struct mlx4_dev *dev, int npages, int page_shift,
        } else
                mtt->page_shift = page_shift;
 
-       for (mtt->order = 0, i = MLX4_MTT_ENTRY_PER_SEG; i < npages; i <<= 1)
+       for (mtt->order = 0, i = dev->caps.mtts_per_seg; i < npages; i <<= 1)
                ++mtt->order;
 
        mtt->first_seg = mlx4_alloc_mtt_range(dev, mtt->order);
@@ -350,7 +350,7 @@ int mlx4_mr_enable(struct mlx4_dev *dev, struct mlx4_mr *mr)
                mpt_entry->pd_flags |= cpu_to_be32(MLX4_MPT_PD_FLAG_FAST_REG |
                                                   MLX4_MPT_PD_FLAG_RAE);
                mpt_entry->mtt_sz    = cpu_to_be32((1 << mr->mtt.order) *
-                                                  MLX4_MTT_ENTRY_PER_SEG);
+                                                  dev->caps.mtts_per_seg);
        } else {
                mpt_entry->flags    |= cpu_to_be32(MLX4_MPT_FLAG_SW_OWNS);
        }
@@ -391,7 +391,7 @@ static int mlx4_write_mtt_chunk(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
            (start_index + npages - 1) / (PAGE_SIZE / sizeof (u64)))
                return -EINVAL;
 
-       if (start_index & (MLX4_MTT_ENTRY_PER_SEG - 1))
+       if (start_index & (dev->caps.mtts_per_seg - 1))
                return -EINVAL;
 
        mtts = mlx4_table_find(&priv->mr_table.mtt_table, mtt->first_seg +
index cebdf3243ca16cccb974b553d4e46b556fd0ac46..bd22df95adf9a51fa76632404bbf9488df833b5b 100644 (file)
@@ -98,7 +98,7 @@ u64 mlx4_make_profile(struct mlx4_dev *dev,
        profile[MLX4_RES_EQ].size     = dev_cap->eqc_entry_sz;
        profile[MLX4_RES_DMPT].size   = dev_cap->dmpt_entry_sz;
        profile[MLX4_RES_CMPT].size   = dev_cap->cmpt_entry_sz;
-       profile[MLX4_RES_MTT].size    = MLX4_MTT_ENTRY_PER_SEG * dev_cap->mtt_entry_sz;
+       profile[MLX4_RES_MTT].size    = dev->caps.mtts_per_seg * dev_cap->mtt_entry_sz;
        profile[MLX4_RES_MCG].size    = MLX4_MGM_ENTRY_SIZE;
 
        profile[MLX4_RES_QP].num      = request->num_qp;
index 8754e44cadaeceed4e2c11b1f38250adc74e01c2..3bd0b5933d590f9312870b979b66025180ccd4a7 100644 (file)
@@ -3242,8 +3242,8 @@ struct niu {
        struct niu_parent               *parent;
 
        u32                             flags;
-#define NIU_FLAGS_HOTPLUG_PHY_PRESENT  0x02000000 /* Removebale PHY detected*/
-#define NIU_FLAGS_HOTPLUG_PHY          0x01000000 /* Removebale PHY */
+#define NIU_FLAGS_HOTPLUG_PHY_PRESENT  0x02000000 /* Removeable PHY detected*/
+#define NIU_FLAGS_HOTPLUG_PHY          0x01000000 /* Removeable PHY */
 #define NIU_FLAGS_VPD_VALID            0x00800000 /* VPD has valid version */
 #define NIU_FLAGS_MSIX                 0x00400000 /* MSI-X in use */
 #define NIU_FLAGS_MCAST                        0x00200000 /* multicast filter enabled */
index c92ced2479478729e5e329463f7acd1e49599f90..1fd5ecb24425c4b9c44db951368abbcc14a08249 100644 (file)
@@ -3174,7 +3174,7 @@ static int ql_adapter_reset(struct ql_adapter *qdev)
 
        if (value & RST_FO_FR) {
                QPRINTK(qdev, IFDOWN, ERR,
-                       "ETIMEOUT!!! errored out of resetting the chip!\n");
+                       "ETIMEDOUT!!! errored out of resetting the chip!\n");
                status = -ETIMEDOUT;
        }
 
index 9f81b797f10b84126151cfed392190804cc25f9e..ac9493f6c1a149f1c5ccbc07f020f656256b8060 100644 (file)
@@ -141,7 +141,7 @@ end:
 /* We are being asked by firmware to accept
  * a change to the port.  This is only
  * a change to max frame sizes (Tx/Rx), pause
- * paramters, or loopback mode. We wake up a worker
+ * parameters, or loopback mode. We wake up a worker
  * to handler processing this since a mailbox command
  * will need to be sent to ACK the request.
  */
@@ -371,7 +371,7 @@ static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp)
        /* We are being asked by firmware to accept
         * a change to the port.  This is only
         * a change to max frame sizes (Tx/Rx), pause
-        * paramters, or loopback mode.
+        * parameters, or loopback mode.
         */
        case AEN_IDC_REQ:
                status = ql_idc_req_aen(qdev);
@@ -380,7 +380,7 @@ static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp)
        /* Process and inbound IDC event.
         * This will happen when we're trying to
         * change tx/rx max frame size, change pause
-        * paramters or loopback mode.
+        * parameters or loopback mode.
         */
        case AEN_IDC_CMPLT:
        case AEN_IDC_EXT:
index 1ff589988d10f2aaa1aca9051e9db2864f6de6a5..2976757a36fbdfe0ad96f74e4d6ca754a7fcc7ee 100644 (file)
@@ -413,7 +413,7 @@ struct smt_p_reason {
 #define SMT_RDF_SUCCESS        0x00000003      /* success (PMF) */
 #define SMT_RDF_BADSET 0x00000004      /* bad set count (PMF) */
 #define SMT_RDF_ILLEGAL 0x00000005     /* read only (PMF) */
-#define SMT_RDF_NOPARAM        0x6             /* paramter not supported (PMF) */
+#define SMT_RDF_NOPARAM        0x6             /* parameter not supported (PMF) */
 #define SMT_RDF_RANGE  0x8             /* out of range */
 #define SMT_RDF_AUTHOR 0x9             /* not autohorized */
 #define SMT_RDF_LENGTH 0x0a            /* length error */
index 329f890e2903075c23cea798acbb5f79e3f12196..f1f773b17fe121fc09f68eb84325a01b304bd87f 100644 (file)
@@ -45,7 +45,8 @@
     defined(CONFIG_MACH_ZYLONITE) ||\
     defined(CONFIG_MACH_LITTLETON) ||\
     defined(CONFIG_MACH_ZYLONITE2) ||\
-    defined(CONFIG_ARCH_VIPER)
+    defined(CONFIG_ARCH_VIPER) ||\
+    defined(CONFIG_MACH_STARGATE2)
 
 #include <asm/mach-types.h>
 
@@ -73,7 +74,7 @@
 /* We actually can't write halfwords properly if not word aligned */
 static inline void SMC_outw(u16 val, void __iomem *ioaddr, int reg)
 {
-       if (machine_is_mainstone() && reg & 2) {
+       if ((machine_is_mainstone() || machine_is_stargate2()) && reg & 2) {
                unsigned int v = val << 16;
                v |= readl(ioaddr + (reg & ~2)) & 0xffff;
                writel(v, ioaddr + (reg & ~2));
index 534c0f38483c3ea97cb47097182f817deab369db..0337b9d673f46d45bbbbf083545ba4a76d5d0fbb 100644 (file)
@@ -79,7 +79,7 @@ MODULE_AUTHOR("Mike Phillips <mikep@linuxtr.net>") ;
 MODULE_DESCRIPTION("3Com 3C359 Velocity XL Token Ring Adapter Driver \n") ;
 MODULE_FIRMWARE(FW_NAME);
 
-/* Module paramters */
+/* Module parameters */
 
 /* Ring Speed 0,4,16 
  * 0 = Autosense   
index 2e70ee8f1459981089a73fd4a75b722cc112c46d..46a2cc92d97988ab605a9c6209a81737bd424dd8 100644 (file)
@@ -169,7 +169,7 @@ static char *open_min_error[] = {
        "Monitor Contention failer for RPL", "FDX Protocol Error"
 };
 
-/* Module paramters */
+/* Module parameters */
 
 /* Ring Speed 0,4,16
  * 0 = Autosense         
index d068a9d36883028d350eaf248d35a6332f722bef..2d819fc85589609b42debab889e29ab00ade265d 100644 (file)
@@ -132,7 +132,7 @@ static char *open_min_error[] = {"No error", "Function Failure", "Signal Lost",
                                   "Reserved", "Reserved", "No Monitor Detected for RPL", 
                                   "Monitor Contention failer for RPL", "FDX Protocol Error"};
 
-/* Module paramters */
+/* Module parameters */
 
 MODULE_AUTHOR("Mike Phillips <mikep@linuxtr.net>") ; 
 MODULE_DESCRIPTION("Olympic PCI/Cardbus Chipset Driver") ; 
index 6fcb500257bc37c6b330b86c6cca19a747ad440b..61fe80dda3e314fe209e160a5f6a6ab832d39caa 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Limitation:
  * Can only get/set setttings of the first queue.
- * Need to re-open the interface manually after changing some paramters.
+ * Need to re-open the interface manually after changing some parameters.
  *
  * 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
index f3a2fce6166ccebc68dc6650e9b7ac8ed6fb4be4..47f68cfa7e21344b6ebcb426023f032af43a9f28 100644 (file)
@@ -398,7 +398,7 @@ static void rx_complete (struct urb *urb)
 
        /* stalls need manual reset. this is rare ... except that
         * when going through USB 2.0 TTs, unplug appears this way.
-        * we avoid the highspeed version of the ETIMEOUT/EILSEQ
+        * we avoid the highspeed version of the ETIMEDOUT/EILSEQ
         * storm, recovering as needed.
         */
        case -EPIPE:
index 4d1d47953fc6e4d780c538b5ffd00c901ffc06bf..7fa620ddeb2170ea7b3393ea6b5cfdbf9adfb2e8 100644 (file)
@@ -845,6 +845,10 @@ static int virtnet_probe(struct virtio_device *vdev)
        int err;
        struct net_device *dev;
        struct virtnet_info *vi;
+       struct virtqueue *vqs[3];
+       vq_callback_t *callbacks[] = { skb_recv_done, skb_xmit_done, NULL};
+       const char *names[] = { "input", "output", "control" };
+       int nvqs;
 
        /* Allocate ourselves a network device with room for our info */
        dev = alloc_etherdev(sizeof(struct virtnet_info));
@@ -905,25 +909,19 @@ static int virtnet_probe(struct virtio_device *vdev)
        if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
                vi->mergeable_rx_bufs = true;
 
-       /* We expect two virtqueues, receive then send. */
-       vi->rvq = vdev->config->find_vq(vdev, 0, skb_recv_done);
-       if (IS_ERR(vi->rvq)) {
-               err = PTR_ERR(vi->rvq);
+       /* We expect two virtqueues, receive then send,
+        * and optionally control. */
+       nvqs = virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ) ? 3 : 2;
+
+       err = vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names);
+       if (err)
                goto free;
-       }
 
-       vi->svq = vdev->config->find_vq(vdev, 1, skb_xmit_done);
-       if (IS_ERR(vi->svq)) {
-               err = PTR_ERR(vi->svq);
-               goto free_recv;
-       }
+       vi->rvq = vqs[0];
+       vi->svq = vqs[1];
 
        if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) {
-               vi->cvq = vdev->config->find_vq(vdev, 2, NULL);
-               if (IS_ERR(vi->cvq)) {
-                       err = PTR_ERR(vi->svq);
-                       goto free_send;
-               }
+               vi->cvq = vqs[2];
 
                if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VLAN))
                        dev->features |= NETIF_F_HW_VLAN_FILTER;
@@ -941,7 +939,7 @@ static int virtnet_probe(struct virtio_device *vdev)
        err = register_netdev(dev);
        if (err) {
                pr_debug("virtio_net: registering device failed\n");
-               goto free_ctrl;
+               goto free_vqs;
        }
 
        /* Last of all, set up some receive buffers. */
@@ -962,13 +960,8 @@ static int virtnet_probe(struct virtio_device *vdev)
 
 unregister:
        unregister_netdev(dev);
-free_ctrl:
-       if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ))
-               vdev->config->del_vq(vi->cvq);
-free_send:
-       vdev->config->del_vq(vi->svq);
-free_recv:
-       vdev->config->del_vq(vi->rvq);
+free_vqs:
+       vdev->config->del_vqs(vdev);
 free:
        free_netdev(dev);
        return err;
@@ -994,12 +987,10 @@ static void virtnet_remove(struct virtio_device *vdev)
 
        BUG_ON(vi->num != 0);
 
-       vdev->config->del_vq(vi->svq);
-       vdev->config->del_vq(vi->rvq);
-       if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ))
-               vdev->config->del_vq(vi->cvq);
        unregister_netdev(vi->dev);
 
+       vdev->config->del_vqs(vi->vdev);
+
        while (vi->pages)
                __free_pages(get_a_page(vi, GFP_KERNEL), 0);
 
index 765a7f5d6aa4c7b0ee17dd3d58e970b6d59e2798..a6dc317083d32c66ed027d440a295931125be25a 100644 (file)
@@ -579,7 +579,8 @@ static inline void queue_put_desc(unsigned int queue, u32 phys,
        debug_desc(phys, desc);
        BUG_ON(phys & 0x1F);
        qmgr_put_entry(queue, phys);
-       BUG_ON(qmgr_stat_overflow(queue));
+       /* Don't check for queue overflow here, we've allocated sufficient
+          length and queues >= 32 don't support this check anyway. */
 }
 
 
@@ -789,10 +790,10 @@ static void hss_hdlc_txdone_irq(void *pdev)
                free_buffer_irq(port->tx_buff_tab[n_desc]);
                port->tx_buff_tab[n_desc] = NULL;
 
-               start = qmgr_stat_empty(port->plat->txreadyq);
+               start = qmgr_stat_below_low_watermark(port->plat->txreadyq);
                queue_put_desc(port->plat->txreadyq,
                               tx_desc_phys(port, n_desc), desc);
-               if (start) {
+               if (start) { /* TX-ready queue was empty */
 #if DEBUG_TX
                        printk(KERN_DEBUG "%s: hss_hdlc_txdone_irq xmit"
                               " ready\n", dev->name);
@@ -867,13 +868,13 @@ static int hss_hdlc_xmit(struct sk_buff *skb, struct net_device *dev)
        queue_put_desc(queue_ids[port->id].tx, tx_desc_phys(port, n), desc);
        dev->trans_start = jiffies;
 
-       if (qmgr_stat_empty(txreadyq)) {
+       if (qmgr_stat_below_low_watermark(txreadyq)) { /* empty */
 #if DEBUG_TX
                printk(KERN_DEBUG "%s: hss_hdlc_xmit queue full\n", dev->name);
 #endif
                netif_stop_queue(dev);
                /* we could miss TX ready interrupt */
-               if (!qmgr_stat_empty(txreadyq)) {
+               if (!qmgr_stat_below_low_watermark(txreadyq)) {
 #if DEBUG_TX
                        printk(KERN_DEBUG "%s: hss_hdlc_xmit ready again\n",
                               dev->name);
index 3d94e7dfea69ec61c05236ecdf4a77aec77ab5cb..3359497012aa468f32654388558887fb298e8f4c 100644 (file)
@@ -310,7 +310,7 @@ config PRISM54
          If you want to compile the driver as a module ( = code which can be
          inserted in and removed from the running kernel whenever you want),
          say M here and read <file:Documentation/kbuild/modules.txt>.
-         The module will be called prism54.ko.
+         The module will be called prism54.
 
 config USB_ZD1201
        tristate "USB ZD1201 based Wireless device support"
index 932d207bce231955548e6e68adbc1585bb1e4b59..c15db229351573ee7d37ee7494b002160744db86 100644 (file)
@@ -29,7 +29,7 @@ config HOSTAP
        PLX/PCI/CS version of the driver to actually use the driver.
 
        The driver can be compiled as a module and it will be called
-       "hostap.ko".
+       hostap.
 
 config HOSTAP_FIRMWARE
        bool "Support downloading firmware images with Host AP driver"
@@ -68,7 +68,7 @@ config HOSTAP_PLX
        driver.
 
        The driver can be compiled as a module and will be named
-       "hostap_plx.ko".
+       hostap_plx.
 
 config HOSTAP_PCI
        tristate "Host AP driver for Prism2.5 PCI adaptors"
@@ -81,7 +81,7 @@ config HOSTAP_PCI
        driver.
 
        The driver can be compiled as a module and will be named
-       "hostap_pci.ko".
+       hostap_pci.
 
 config HOSTAP_CS
        tristate "Host AP driver for Prism2/2.5/3 PC Cards"
@@ -94,4 +94,4 @@ config HOSTAP_CS
        driver.
 
        The driver can be compiled as a module and will be named
-       "hostap_cs.ko".
+       hostap_cs.
index 8304f6406a175230173b73c577523b286797c5f0..736162324ba4e8457bbaaabaa3176d9c697e8e9c 100644 (file)
@@ -75,7 +75,7 @@ config IWLAGN
          If you want to compile the driver as a module ( = code which can be
          inserted in and removed from the running kernel whenever you want),
          say M here and read <file:Documentation/kbuild/modules.txt>.  The
-         module will be called iwlagn.ko.
+         module will be called iwlagn.
 
 
 config IWL4965
@@ -113,7 +113,7 @@ config IWL3945
          If you want to compile the driver as a module ( = code which can be
          inserted in and removed from the running kernel whenever you want),
          say M here and read <file:Documentation/kbuild/modules.txt>.  The
-         module will be called iwl3945.ko.
+         module will be called iwl3945.
 
 config IWL3945_SPECTRUM_MEASUREMENT
        bool "Enable Spectrum Measurement in iwl3945 driver"
index bebf735cd4bd3f22ba8ea21d5c7313f44d262c6b..ff0042ffe3e9d84820311decf72aa9ddd9a7cb21 100644 (file)
@@ -584,7 +584,7 @@ static int rndis_set_config_parameter(struct usbnet *dev, char *param,
        ret = rndis_set_oid(dev, OID_GEN_RNDIS_CONFIG_PARAMETER,
                                                        infobuf, info_len);
        if (ret != 0)
-               devdbg(dev, "setting rndis config paramater failed, %d.", ret);
+               devdbg(dev, "setting rndis config parameter failed, %d.", ret);
 
        kfree(infobuf);
        return ret;
index bfc5d9cf716e83b52e5c5a5aa749ff1491dfb15f..1ae11c7f17affe210ed50782611c15f6db99796d 100644 (file)
@@ -9,11 +9,11 @@ menuconfig RT2X00
 
          When building one of the individual drivers, the rt2x00 library
          will also be created. That library (when the driver is built as
-         a module) will be called "rt2x00lib.ko".
+         a module) will be called rt2x00lib.
 
          Additionally PCI and USB libraries will also be build depending
          on the types of drivers being selected, these libraries will be
-         called "rt2x00pci.ko" and "rt2x00usb.ko".
+         called rt2x00pci and rt2x00usb.
 
 if RT2X00
 
@@ -26,7 +26,7 @@ config RT2400PCI
          This adds support for rt2400 wireless chipset family.
          Supported chips: RT2460.
 
-         When compiled as a module, this driver will be called "rt2400pci.ko".
+         When compiled as a module, this driver will be called rt2400pci.
 
 config RT2500PCI
        tristate "Ralink rt2500 (PCI/PCMCIA) support"
@@ -37,7 +37,7 @@ config RT2500PCI
          This adds support for rt2500 wireless chipset family.
          Supported chips: RT2560.
 
-         When compiled as a module, this driver will be called "rt2500pci.ko".
+         When compiled as a module, this driver will be called rt2500pci.
 
 config RT61PCI
        tristate "Ralink rt2501/rt61 (PCI/PCMCIA) support"
@@ -51,7 +51,7 @@ config RT61PCI
          This adds support for rt2501 wireless chipset family.
          Supported chips: RT2561, RT2561S & RT2661.
 
-         When compiled as a module, this driver will be called "rt61pci.ko".
+         When compiled as a module, this driver will be called rt61pci.
 
 config RT2500USB
        tristate "Ralink rt2500 (USB) support"
@@ -62,7 +62,7 @@ config RT2500USB
          This adds support for rt2500 wireless chipset family.
          Supported chips: RT2571 & RT2572.
 
-         When compiled as a module, this driver will be called "rt2500usb.ko".
+         When compiled as a module, this driver will be called rt2500usb.
 
 config RT73USB
        tristate "Ralink rt2501/rt73 (USB) support"
@@ -75,7 +75,7 @@ config RT73USB
          This adds support for rt2501 wireless chipset family.
          Supported chips: RT2571W, RT2573 & RT2671.
 
-         When compiled as a module, this driver will be called "rt73usb.ko".
+         When compiled as a module, this driver will be called rt73usb.
 
 config RT2X00_LIB_PCI
        tristate
index a631613177d037b744e8f866bfde1cf6e2f491e0..d83e3794d340fd3d6a78abdf24c67128b596e51b 100644 (file)
@@ -235,7 +235,7 @@ void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna);
  * @rt2x00dev: Pointer to &struct rt2x00_dev.
  *
  * Initialize work structure and all link tuning related
- * paramters. This will not start the link tuning process itself.
+ * parameters. This will not start the link tuning process itself.
  */
 void rt2x00link_register(struct rt2x00_dev *rt2x00dev);
 
index e55b33961aeb8c7d030642027c3075536a979f5d..fa2821be44c2d43e83bfbfb375ed1453788c2e8f 100644 (file)
@@ -138,7 +138,7 @@ psa_read(struct net_device *        dev,
 
 /*------------------------------------------------------------------*/
 /*
- * Write the Paramter Storage Area to the WaveLAN card's memory
+ * Write the Parameter Storage Area to the WaveLAN card's memory
  */
 static void
 psa_write(struct net_device *  dev,
index f821dbc952a42bb2e53a49c110decc859eff3d55..27f3b81333dec00bf0c5c212b2f0162261a40564 100644 (file)
@@ -1,21 +1,21 @@
 config OF_DEVICE
        def_bool y
-       depends on OF && (SPARC || PPC_OF)
+       depends on OF && (SPARC || PPC_OF || MICROBLAZE)
 
 config OF_GPIO
        def_bool y
-       depends on OF && PPC_OF && GPIOLIB
+       depends on OF && (PPC_OF || MICROBLAZE) && GPIOLIB
        help
          OpenFirmware GPIO accessors
 
 config OF_I2C
        def_tristate I2C
-       depends on PPC_OF && I2C
+       depends on (PPC_OF || MICROBLAZE) && I2C
        help
          OpenFirmware I2C accessors
 
 config OF_SPI
        def_tristate SPI
-       depends on OF && PPC_OF && SPI
+       depends on OF && (PPC_OF || MICROBLAZE) && SPI
        help
          OpenFirmware SPI accessors
index 3eee70928d4581e6a77cb4d804611123f6bcf38d..2d6da78fddb649849c42f9778b52e6b4ce3e7713 100644 (file)
@@ -679,7 +679,7 @@ alloc_err:
        return rc;
 }
 
-static int sn_pci_hotplug_init(void)
+static int __init sn_pci_hotplug_init(void)
 {
        struct pci_bus *pci_bus = NULL;
        int rc;
@@ -716,7 +716,7 @@ static int sn_pci_hotplug_init(void)
        return registered == 1 ? 0 : -ENODEV;
 }
 
-static void sn_pci_hotplug_exit(void)
+static void __exit sn_pci_hotplug_exit(void)
 {
        struct hotplug_slot *bss_hotplug_slot;
 
index 276473543982b521d8f29eb3da93bb315086a57c..fbf965b31c14b3cacf165a4b9f82c6e5a667508d 100644 (file)
@@ -217,7 +217,7 @@ config PCMCIA_PXA2XX
        depends on ARM && ARCH_PXA && PCMCIA
        depends on (ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL \
                    || MACH_ARMCORE || ARCH_PXA_PALM || TRIZEPS_PCMCIA \
-                   || ARCH_VIPER || ARCH_PXA_ESERIES)
+                   || ARCH_VIPER || ARCH_PXA_ESERIES || MACH_STARGATE2)
        help
          Say Y here to include support for the PXA2xx PCMCIA controller
 
index bbac46327227e5d0e12a9125179525daf34a4c37..047394d98ac24995993e79addd26843f56c6bc08 100644 (file)
@@ -73,5 +73,6 @@ pxa2xx-obj-$(CONFIG_TRIZEPS_PCMCIA)           += pxa2xx_trizeps4.o
 pxa2xx-obj-$(CONFIG_MACH_PALMTX)               += pxa2xx_palmtx.o
 pxa2xx-obj-$(CONFIG_MACH_PALMLD)               += pxa2xx_palmld.o
 pxa2xx-obj-$(CONFIG_MACH_E740)                 += pxa2xx_e740.o
+pxa2xx-obj-$(CONFIG_MACH_STARGATE2)            += pxa2xx_stargate2.o
 
 obj-$(CONFIG_PCMCIA_PXA2XX)                    += pxa2xx_core.o $(pxa2xx-obj-y)
diff --git a/drivers/pcmcia/pxa2xx_stargate2.c b/drivers/pcmcia/pxa2xx_stargate2.c
new file mode 100644 (file)
index 0000000..490749e
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * linux/drivers/pcmcia/pxa2xx_stargate2.c
+ *
+ * Stargate 2 PCMCIA specific routines.
+ *
+ * Created:    December 6, 2005
+ * Author:     Ed C. Epp
+ * Copyright:  Intel Corp 2005
+ *              Jonathan Cameron <jic23@cam.ac.uk> 2009
+ *
+ * This 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/interrupt.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <pcmcia/ss.h>
+
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include "soc_common.h"
+
+#define SG2_S0_BUFF_CTL                120
+#define SG2_S0_POWER_CTL       108
+#define SG2_S0_GPIO_RESET      82
+#define SG2_S0_GPIO_DETECT     53
+#define SG2_S0_GPIO_READY      81
+
+static struct pcmcia_irqs irqs[] = {
+       { 0, IRQ_GPIO(SG2_S0_GPIO_DETECT), "PCMCIA0 CD" },
+};
+
+static int sg2_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+       skt->irq = IRQ_GPIO(SG2_S0_GPIO_READY);
+       return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
+}
+
+static void sg2_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+       soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
+}
+
+static void sg2_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+                                   struct pcmcia_state *state)
+{
+       state->detect = !gpio_get_value(SG2_S0_GPIO_DETECT);
+       state->ready  = !!gpio_get_value(SG2_S0_GPIO_READY);
+       state->bvd1   = 0; /* not available - battery detect on card */
+       state->bvd2   = 0; /* not available */
+       state->vs_3v  = 1; /* not available - voltage detect for card */
+       state->vs_Xv  = 0; /* not available */
+       state->wrprot = 0; /* not available - write protect */
+}
+
+static int sg2_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+                                      const socket_state_t *state)
+{
+       /* Enable card power */
+       switch (state->Vcc) {
+       case 0:
+               /* sets power ctl register high */
+               gpio_set_value(SG2_S0_POWER_CTL, 1);
+               break;
+       case 33:
+       case 50:
+               /* sets power control register low (clear) */
+               gpio_set_value(SG2_S0_POWER_CTL, 0);
+               msleep(100);
+               break;
+       default:
+               pr_err("%s(): bad Vcc %u\n",
+                      __func__, state->Vcc);
+               return -1;
+       }
+
+       /* reset */
+       gpio_set_value(SG2_S0_GPIO_RESET, !!(state->flags & SS_RESET));
+
+       return 0;
+}
+
+static void sg2_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
+{
+       soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
+}
+
+static void sg2_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
+{
+       soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
+}
+
+static struct pcmcia_low_level sg2_pcmcia_ops __initdata = {
+       .owner                  = THIS_MODULE,
+       .hw_init                = sg2_pcmcia_hw_init,
+       .hw_shutdown            = sg2_pcmcia_hw_shutdown,
+       .socket_state           = sg2_pcmcia_socket_state,
+       .configure_socket       = sg2_pcmcia_configure_socket,
+       .socket_init            = sg2_pcmcia_socket_init,
+       .socket_suspend         = sg2_pcmcia_socket_suspend,
+       .nr                     = 1,
+};
+
+static struct platform_device *sg2_pcmcia_device;
+
+static int __init sg2_pcmcia_init(void)
+{
+       int ret;
+
+       if (!machine_is_stargate2())
+               return -ENODEV;
+
+       sg2_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+       if (!sg2_pcmcia_device)
+               return -ENOMEM;
+
+       ret = gpio_request(SG2_S0_BUFF_CTL, "SG2 CF buff ctl");
+       if (ret)
+               goto error_put_platform_device;
+       ret = gpio_request(SG2_S0_POWER_CTL, "SG2 CF power ctl");
+       if (ret)
+               goto error_free_gpio_buff_ctl;
+       ret = gpio_request(SG2_S0_GPIO_RESET, "SG2 CF reset");
+       if (ret)
+               goto error_free_gpio_power_ctl;
+       /* Set gpio directions */
+       gpio_direction_output(SG2_S0_BUFF_CTL, 0);
+       gpio_direction_output(SG2_S0_POWER_CTL, 1);
+       gpio_direction_output(SG2_S0_GPIO_RESET, 1);
+
+       ret = platform_device_add_data(sg2_pcmcia_device,
+                                      &sg2_pcmcia_ops,
+                                      sizeof(sg2_pcmcia_ops));
+       if (ret)
+               goto error_free_gpio_reset;
+
+       ret = platform_device_add(sg2_pcmcia_device);
+       if (ret)
+               goto error_free_gpio_reset;
+
+       return 0;
+error_free_gpio_reset:
+       gpio_free(SG2_S0_GPIO_RESET);
+error_free_gpio_power_ctl:
+       gpio_free(SG2_S0_POWER_CTL);
+error_free_gpio_buff_ctl:
+       gpio_free(SG2_S0_BUFF_CTL);
+error_put_platform_device:
+       platform_device_put(sg2_pcmcia_device);
+
+       return ret;
+}
+
+static void __exit sg2_pcmcia_exit(void)
+{
+       platform_device_unregister(sg2_pcmcia_device);
+       gpio_free(SG2_S0_BUFF_CTL);
+       gpio_free(SG2_S0_POWER_CTL);
+       gpio_free(SG2_S0_GPIO_RESET);
+}
+
+fs_initcall(sg2_pcmcia_init);
+module_exit(sg2_pcmcia_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
index f604061d2bb0334981540e592b3aeee02320489c..ba97654278862ea5824c9645bcaa740dfcfe3061 100644 (file)
@@ -638,6 +638,24 @@ int pnp_possible_config(struct pnp_dev *dev, int type, resource_size_t start,
 }
 EXPORT_SYMBOL(pnp_possible_config);
 
+int pnp_range_reserved(resource_size_t start, resource_size_t end)
+{
+       struct pnp_dev *dev;
+       struct pnp_resource *pnp_res;
+       resource_size_t *dev_start, *dev_end;
+
+       pnp_for_each_dev(dev) {
+               list_for_each_entry(pnp_res, &dev->resources, list) {
+                       dev_start = &pnp_res->res.start;
+                       dev_end   = &pnp_res->res.end;
+                       if (ranged_conflict(&start, &end, dev_start, dev_end))
+                               return 1;
+               }
+       }
+       return 0;
+}
+EXPORT_SYMBOL(pnp_range_reserved);
+
 /* format is: pnp_reserve_irq=irq1[,irq2] .... */
 static int __init pnp_setup_reserve_irq(char *str)
 {
index f7a3283dd02947962ce5c71d3a221b121231a728..551332e4ed02a28122b72b817bf0682814ed13c2 100644 (file)
 #include <linux/module.h>
 #include <linux/rtc.h>
 #include <linux/platform_device.h>
-#include <mach/hardware.h>
+#include <linux/io.h>
+
+#define EP93XX_RTC_DATA                        0x000
+#define EP93XX_RTC_MATCH               0x004
+#define EP93XX_RTC_STATUS              0x008
+#define  EP93XX_RTC_STATUS_INTR                 (1<<0)
+#define EP93XX_RTC_LOAD                        0x00C
+#define EP93XX_RTC_CONTROL             0x010
+#define  EP93XX_RTC_CONTROL_MIE                 (1<<0)
+#define EP93XX_RTC_SWCOMP              0x108
+#define  EP93XX_RTC_SWCOMP_DEL_MASK     0x001f0000
+#define  EP93XX_RTC_SWCOMP_DEL_SHIFT    16
+#define  EP93XX_RTC_SWCOMP_INT_MASK     0x0000ffff
+#define  EP93XX_RTC_SWCOMP_INT_SHIFT    0
+
+#define DRV_VERSION "0.3"
 
-#define EP93XX_RTC_REG(x)      (EP93XX_RTC_BASE + (x))
-#define EP93XX_RTC_DATA                EP93XX_RTC_REG(0x0000)
-#define EP93XX_RTC_LOAD                EP93XX_RTC_REG(0x000C)
-#define EP93XX_RTC_SWCOMP      EP93XX_RTC_REG(0x0108)
-
-#define DRV_VERSION "0.2"
+/*
+ * struct device dev.platform_data is used to store our private data
+ * because struct rtc_device does not have a variable to hold it.
+ */
+struct ep93xx_rtc {
+       void __iomem    *mmio_base;
+};
 
-static int ep93xx_get_swcomp(struct device *dev, unsigned short *preload,
+static int ep93xx_rtc_get_swcomp(struct device *dev, unsigned short *preload,
                                unsigned short *delete)
 {
-       unsigned short comp = __raw_readl(EP93XX_RTC_SWCOMP);
+       struct ep93xx_rtc *ep93xx_rtc = dev->platform_data;
+       unsigned long comp;
+
+       comp = __raw_readl(ep93xx_rtc->mmio_base + EP93XX_RTC_SWCOMP);
 
        if (preload)
-               *preload = comp & 0xffff;
+               *preload = (comp & EP93XX_RTC_SWCOMP_INT_MASK)
+                               >> EP93XX_RTC_SWCOMP_INT_SHIFT;
 
        if (delete)
-               *delete = (comp >> 16) & 0x1f;
+               *delete = (comp & EP93XX_RTC_SWCOMP_DEL_MASK)
+                               >> EP93XX_RTC_SWCOMP_DEL_SHIFT;
 
        return 0;
 }
 
 static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
-       unsigned long time = __raw_readl(EP93XX_RTC_DATA);
+       struct ep93xx_rtc *ep93xx_rtc = dev->platform_data;
+       unsigned long time;
+
+        time = __raw_readl(ep93xx_rtc->mmio_base + EP93XX_RTC_DATA);
 
        rtc_time_to_tm(time, tm);
        return 0;
@@ -45,7 +69,9 @@ static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm)
 
 static int ep93xx_rtc_set_mmss(struct device *dev, unsigned long secs)
 {
-       __raw_writel(secs + 1, EP93XX_RTC_LOAD);
+       struct ep93xx_rtc *ep93xx_rtc = dev->platform_data;
+
+       __raw_writel(secs + 1, ep93xx_rtc->mmio_base + EP93XX_RTC_LOAD);
        return 0;
 }
 
@@ -53,7 +79,7 @@ static int ep93xx_rtc_proc(struct device *dev, struct seq_file *seq)
 {
        unsigned short preload, delete;
 
-       ep93xx_get_swcomp(dev, &preload, &delete);
+       ep93xx_rtc_get_swcomp(dev, &preload, &delete);
 
        seq_printf(seq, "preload\t\t: %d\n", preload);
        seq_printf(seq, "delete\t\t: %d\n", delete);
@@ -67,54 +93,104 @@ static const struct rtc_class_ops ep93xx_rtc_ops = {
        .proc           = ep93xx_rtc_proc,
 };
 
-static ssize_t ep93xx_sysfs_show_comp_preload(struct device *dev,
+static ssize_t ep93xx_rtc_show_comp_preload(struct device *dev,
                        struct device_attribute *attr, char *buf)
 {
        unsigned short preload;
 
-       ep93xx_get_swcomp(dev, &preload, NULL);
+       ep93xx_rtc_get_swcomp(dev, &preload, NULL);
 
        return sprintf(buf, "%d\n", preload);
 }
-static DEVICE_ATTR(comp_preload, S_IRUGO, ep93xx_sysfs_show_comp_preload, NULL);
+static DEVICE_ATTR(comp_preload, S_IRUGO, ep93xx_rtc_show_comp_preload, NULL);
 
-static ssize_t ep93xx_sysfs_show_comp_delete(struct device *dev,
+static ssize_t ep93xx_rtc_show_comp_delete(struct device *dev,
                        struct device_attribute *attr, char *buf)
 {
        unsigned short delete;
 
-       ep93xx_get_swcomp(dev, NULL, &delete);
+       ep93xx_rtc_get_swcomp(dev, NULL, &delete);
 
        return sprintf(buf, "%d\n", delete);
 }
-static DEVICE_ATTR(comp_delete, S_IRUGO, ep93xx_sysfs_show_comp_delete, NULL);
+static DEVICE_ATTR(comp_delete, S_IRUGO, ep93xx_rtc_show_comp_delete, NULL);
 
 
-static int __devinit ep93xx_rtc_probe(struct platform_device *dev)
+static int __init ep93xx_rtc_probe(struct platform_device *pdev)
 {
-       struct rtc_device *rtc = rtc_device_register("ep93xx",
-                               &dev->dev, &ep93xx_rtc_ops, THIS_MODULE);
+       struct ep93xx_rtc *ep93xx_rtc;
+       struct resource *res;
+       struct rtc_device *rtc;
+       int err;
+
+       ep93xx_rtc = kzalloc(sizeof(struct ep93xx_rtc), GFP_KERNEL);
+       if (ep93xx_rtc == NULL)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL)
+               return -ENXIO;
+
+       res = request_mem_region(res->start, resource_size(res), pdev->name);
+       if (res == NULL)
+               return -EBUSY;
+
+       ep93xx_rtc->mmio_base = ioremap(res->start, resource_size(res));
+       if (ep93xx_rtc->mmio_base == NULL) {
+               err = -ENXIO;
+               goto fail;
+       }
 
+       pdev->dev.platform_data = ep93xx_rtc;
+
+       rtc = rtc_device_register(pdev->name,
+                               &pdev->dev, &ep93xx_rtc_ops, THIS_MODULE);
        if (IS_ERR(rtc)) {
-               return PTR_ERR(rtc);
+               err = PTR_ERR(rtc);
+               goto fail;
        }
 
-       platform_set_drvdata(dev, rtc);
+       platform_set_drvdata(pdev, rtc);
 
-       device_create_file(&dev->dev, &dev_attr_comp_preload);
-       device_create_file(&dev->dev, &dev_attr_comp_delete);
+       err = device_create_file(&pdev->dev, &dev_attr_comp_preload);
+       if (err)
+               goto fail;
+       err = device_create_file(&pdev->dev, &dev_attr_comp_delete);
+       if (err) {
+               device_remove_file(&pdev->dev, &dev_attr_comp_preload);
+               goto fail;
+       }
 
        return 0;
+
+fail:
+       if (ep93xx_rtc->mmio_base) {
+               iounmap(ep93xx_rtc->mmio_base);
+               pdev->dev.platform_data = NULL;
+       }
+       release_mem_region(res->start, resource_size(res));
+       return err;
 }
 
-static int __devexit ep93xx_rtc_remove(struct platform_device *dev)
+static int __exit ep93xx_rtc_remove(struct platform_device *pdev)
 {
-       struct rtc_device *rtc = platform_get_drvdata(dev);
+       struct rtc_device *rtc = platform_get_drvdata(pdev);
+       struct ep93xx_rtc *ep93xx_rtc = pdev->dev.platform_data;
+       struct resource *res;
+
+       /* cleanup sysfs */
+       device_remove_file(&pdev->dev, &dev_attr_comp_delete);
+       device_remove_file(&pdev->dev, &dev_attr_comp_preload);
+
+       rtc_device_unregister(rtc);
+
+       iounmap(ep93xx_rtc->mmio_base);
+       pdev->dev.platform_data = NULL;
 
-       if (rtc)
-               rtc_device_unregister(rtc);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(res->start, resource_size(res));
 
-       platform_set_drvdata(dev, NULL);
+       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
@@ -122,23 +198,22 @@ static int __devexit ep93xx_rtc_remove(struct platform_device *dev)
 /* work with hotplug and coldplug */
 MODULE_ALIAS("platform:ep93xx-rtc");
 
-static struct platform_driver ep93xx_rtc_platform_driver = {
+static struct platform_driver ep93xx_rtc_driver = {
        .driver         = {
                .name   = "ep93xx-rtc",
                .owner  = THIS_MODULE,
        },
-       .probe          = ep93xx_rtc_probe,
-       .remove         = __devexit_p(ep93xx_rtc_remove),
+       .remove         = __exit_p(ep93xx_rtc_remove),
 };
 
 static int __init ep93xx_rtc_init(void)
 {
-       return platform_driver_register(&ep93xx_rtc_platform_driver);
+        return platform_driver_probe(&ep93xx_rtc_driver, ep93xx_rtc_probe);
 }
 
 static void __exit ep93xx_rtc_exit(void)
 {
-       platform_driver_unregister(&ep93xx_rtc_platform_driver);
+       platform_driver_unregister(&ep93xx_rtc_driver);
 }
 
 MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
index aaf1f75fa2939e12e7ecd5ee48111ef37b47a7d8..457231bb1029748ca4c1be64d1689577ae4ad00d 100644 (file)
@@ -117,7 +117,7 @@ static int pl030_probe(struct amba_device *dev, struct amba_id *id)
                goto err_rtc;
        }
 
-       rtc->base = ioremap(dev->res.start, SZ_4K);
+       rtc->base = ioremap(dev->res.start, resource_size(&dev->res));
        if (!rtc->base) {
                ret = -ENOMEM;
                goto err_map;
index 451fc13784d1b9ecdcf2efaae611575aecd1c782..f41873f98f6668322d7a29173c803d4435999316 100644 (file)
@@ -142,8 +142,7 @@ static int pl031_probe(struct amba_device *adev, struct amba_id *id)
                goto out;
        }
 
-       ldata->base = ioremap(adev->res.start,
-                             adev->res.end - adev->res.start + 1);
+       ldata->base = ioremap(adev->res.start, resource_size(&adev->res));
        if (!ldata->base) {
                ret = -ENOMEM;
                goto out_no_remap;
index 27a1be0cd4d467a1b3c4ba1d6ab501d3b4ea2fdf..442bb98a2821c5a34519b08e452bfb9ffa1bf629 100644 (file)
@@ -851,8 +851,10 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
 
        /* Check the cqr */
        rc = dasd_check_cqr(cqr);
-       if (rc)
+       if (rc) {
+               cqr->intrc = rc;
                return rc;
+       }
        device = (struct dasd_device *) cqr->startdev;
        if (cqr->retries < 0) {
                /* internal error 14 - start_IO run out of retries */
@@ -915,6 +917,7 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
                BUG();
                break;
        }
+       cqr->intrc = rc;
        return rc;
 }
 
@@ -1454,8 +1457,12 @@ int dasd_sleep_on(struct dasd_ccw_req *cqr)
        dasd_add_request_tail(cqr);
        wait_event(generic_waitq, _wait_for_wakeup(cqr));
 
-       /* Request status is either done or failed. */
-       rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
+       if (cqr->status == DASD_CQR_DONE)
+               rc = 0;
+       else if (cqr->intrc)
+               rc = cqr->intrc;
+       else
+               rc = -EIO;
        return rc;
 }
 
@@ -1477,8 +1484,15 @@ int dasd_sleep_on_interruptible(struct dasd_ccw_req *cqr)
                dasd_cancel_req(cqr);
                /* wait (non-interruptible) for final status */
                wait_event(generic_waitq, _wait_for_wakeup(cqr));
+               cqr->intrc = rc;
        }
-       rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
+
+       if (cqr->status == DASD_CQR_DONE)
+               rc = 0;
+       else if (cqr->intrc)
+               rc = cqr->intrc;
+       else
+               rc = -EIO;
        return rc;
 }
 
@@ -1523,8 +1537,12 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr)
 
        wait_event(generic_waitq, _wait_for_wakeup(cqr));
 
-       /* Request status is either done or failed. */
-       rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
+       if (cqr->status == DASD_CQR_DONE)
+               rc = 0;
+       else if (cqr->intrc)
+               rc = cqr->intrc;
+       else
+               rc = -EIO;
        return rc;
 }
 
@@ -2427,12 +2445,12 @@ static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device,
 
 
 int dasd_generic_read_dev_chars(struct dasd_device *device, char *magic,
-                               void **rdc_buffer, int rdc_buffer_size)
+                               void *rdc_buffer, int rdc_buffer_size)
 {
        int ret;
        struct dasd_ccw_req *cqr;
 
-       cqr = dasd_generic_build_rdc(device, *rdc_buffer, rdc_buffer_size,
+       cqr = dasd_generic_build_rdc(device, rdc_buffer, rdc_buffer_size,
                                     magic);
        if (IS_ERR(cqr))
                return PTR_ERR(cqr);
index 2efaddfae56088be5d25bf27e4f53991105ec070..644086ba2ede9365e0733964855e41c992e6f2a5 100644 (file)
@@ -202,6 +202,7 @@ dasd_start_diag(struct dasd_ccw_req * cqr)
                rc = -EIO;
                break;
        }
+       cqr->intrc = rc;
        return rc;
 }
 
index a41c94053e64be88f1179153be06156c313d9093..cf0cfdba1244bb95891955820f6e873b24bdb6c7 100644 (file)
@@ -1097,20 +1097,20 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
 {
        struct dasd_eckd_private *private;
        struct dasd_block *block;
-       void *rdc_data;
        int is_known, rc;
 
        private = (struct dasd_eckd_private *) device->private;
-       if (private == NULL) {
-               private = kzalloc(sizeof(struct dasd_eckd_private),
-                                 GFP_KERNEL | GFP_DMA);
-               if (private == NULL) {
+       if (!private) {
+               private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA);
+               if (!private) {
                        dev_warn(&device->cdev->dev,
                                 "Allocating memory for private DASD data "
                                 "failed\n");
                        return -ENOMEM;
                }
                device->private = (void *) private;
+       } else {
+               memset(private, 0, sizeof(*private));
        }
        /* Invalidate status of initial analysis. */
        private->init_cqr_status = -1;
@@ -1161,9 +1161,8 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
                goto out_err3;
 
        /* Read Device Characteristics */
-       rdc_data = (void *) &(private->rdc_data);
-       memset(rdc_data, 0, sizeof(rdc_data));
-       rc = dasd_generic_read_dev_chars(device, "ECKD", &rdc_data, 64);
+       rc = dasd_generic_read_dev_chars(device, "ECKD", &private->rdc_data,
+                                        64);
        if (rc) {
                DBF_EVENT(DBF_WARNING,
                          "Read device characteristics failed, rc=%d for "
@@ -1183,7 +1182,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
                 private->rdc_data.dev_model,
                 private->rdc_data.cu_type,
                 private->rdc_data.cu_model.model,
-                   private->real_cyl,
+                private->real_cyl,
                 private->rdc_data.trk_per_cyl,
                 private->rdc_data.sec_per_trk);
        return 0;
@@ -2336,9 +2335,10 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
 {
        int tpm, cmdrtd, cmdwtd;
        int use_prefix;
-
-       struct dasd_eckd_private *private;
+#if defined(CONFIG_64BIT)
        int fcx_in_css, fcx_in_gneq, fcx_in_features;
+#endif
+       struct dasd_eckd_private *private;
        struct dasd_device *basedev;
        sector_t first_rec, last_rec;
        sector_t first_trk, last_trk;
@@ -2361,11 +2361,15 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
        last_offs = sector_div(last_trk, blk_per_trk);
        cdlspecial = (private->uses_cdl && first_rec < 2*blk_per_trk);
 
-       /* is transport mode supported ? */
+       /* is transport mode supported? */
+#if defined(CONFIG_64BIT)
        fcx_in_css = css_general_characteristics.fcx;
        fcx_in_gneq = private->gneq->reserved2[7] & 0x04;
        fcx_in_features = private->features.feature[40] & 0x80;
        tpm = fcx_in_css && fcx_in_gneq && fcx_in_features;
+#else
+       tpm = 0;
+#endif
 
        /* is read track data and write track data in command mode supported? */
        cmdrtd = private->features.feature[9] & 0x20;
@@ -3013,8 +3017,9 @@ static void dasd_eckd_dump_sense_ccw(struct dasd_device *device,
                      " I/O status report for device %s:\n",
                      dev_name(&device->cdev->dev));
        len += sprintf(page + len, KERN_ERR PRINTK_HEADER
-                      " in req: %p CS: 0x%02X DS: 0x%02X\n", req,
-                      scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw));
+                      " in req: %p CS: 0x%02X DS: 0x%02X CC: 0x%02X RC: %d\n",
+                      req, scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw),
+                      scsw_cc(&irb->scsw), req->intrc);
        len += sprintf(page + len, KERN_ERR PRINTK_HEADER
                       " device %s: Failing CCW: %p\n",
                       dev_name(&device->cdev->dev),
@@ -3115,9 +3120,10 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device,
                      " I/O status report for device %s:\n",
                      dev_name(&device->cdev->dev));
        len += sprintf(page + len, KERN_ERR PRINTK_HEADER
-                      " in req: %p CS: 0x%02X DS: 0x%02X "
+                      " in req: %p CS: 0x%02X DS: 0x%02X CC: 0x%02X RC: %d "
                       "fcxs: 0x%02X schxs: 0x%02X\n", req,
                       scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw),
+                      scsw_cc(&irb->scsw), req->intrc,
                       irb->scsw.tm.fcxs, irb->scsw.tm.schxs);
        len += sprintf(page + len, KERN_ERR PRINTK_HEADER
                       " device %s: Failing TCW: %p\n",
@@ -3273,8 +3279,14 @@ static struct dasd_discipline dasd_eckd_discipline = {
 static int __init
 dasd_eckd_init(void)
 {
+       int ret;
+
        ASCEBC(dasd_eckd_discipline.ebcname, 4);
-       return ccw_driver_register(&dasd_eckd_driver);
+       ret = ccw_driver_register(&dasd_eckd_driver);
+       if (!ret)
+               wait_for_device_probe();
+
+       return ret;
 }
 
 static void __exit
index 8912358daa2fd0c3c6561b7469c5d2d23b5e1d5d..597c6ffdb9f2308258a292a0b584f440f9c0ec6a 100644 (file)
@@ -122,20 +122,20 @@ dasd_fba_check_characteristics(struct dasd_device *device)
        struct dasd_block *block;
        struct dasd_fba_private *private;
        struct ccw_device *cdev = device->cdev;
-       void *rdc_data;
        int rc;
 
        private = (struct dasd_fba_private *) device->private;
-       if (private == NULL) {
-               private = kzalloc(sizeof(struct dasd_fba_private),
-                                 GFP_KERNEL | GFP_DMA);
-               if (private == NULL) {
+       if (!private) {
+               private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA);
+               if (!private) {
                        dev_warn(&device->cdev->dev,
                                 "Allocating memory for private DASD "
                                 "data failed\n");
                        return -ENOMEM;
                }
                device->private = (void *) private;
+       } else {
+               memset(private, 0, sizeof(*private));
        }
        block = dasd_alloc_block();
        if (IS_ERR(block)) {
@@ -150,8 +150,8 @@ dasd_fba_check_characteristics(struct dasd_device *device)
        block->base = device;
 
        /* Read Device Characteristics */
-       rdc_data = (void *) &(private->rdc_data);
-       rc = dasd_generic_read_dev_chars(device, "FBA ", &rdc_data, 32);
+       rc = dasd_generic_read_dev_chars(device, "FBA ", &private->rdc_data,
+                                        32);
        if (rc) {
                DBF_EVENT(DBF_WARNING, "Read device characteristics returned "
                          "error %d for device: %s",
@@ -604,8 +604,14 @@ static struct dasd_discipline dasd_fba_discipline = {
 static int __init
 dasd_fba_init(void)
 {
+       int ret;
+
        ASCEBC(dasd_fba_discipline.ebcname, 4);
-       return ccw_driver_register(&dasd_fba_driver);
+       ret = ccw_driver_register(&dasd_fba_driver);
+       if (!ret)
+               wait_for_device_probe();
+
+       return ret;
 }
 
 static void __exit
index c1e487f774c67fb5638be3cdbdadf73f1ea87474..f97ceb795078ee9c1cb0df2bba09c0755575dc9f 100644 (file)
@@ -173,6 +173,7 @@ struct dasd_ccw_req {
        void *data;                     /* pointer to data area */
 
        /* these are important for recovering erroneous requests          */
+       int intrc;                      /* internal error, e.g. from start_IO */
        struct irb irb;                 /* device status in case of an error */
        struct dasd_ccw_req *refers;    /* ERP-chain queueing. */
        void *function;                 /* originating ERP action */
@@ -578,7 +579,7 @@ int dasd_generic_set_offline (struct ccw_device *cdev);
 int dasd_generic_notify(struct ccw_device *, int);
 void dasd_generic_handle_state_change(struct dasd_device *);
 
-int dasd_generic_read_dev_chars(struct dasd_device *, char *, void **, int);
+int dasd_generic_read_dev_chars(struct dasd_device *, char *, void *, int);
 char *dasd_get_sense(struct irb *);
 
 /* externals in dasd_devmap.c */
index a4c7ffcd9987adb6dcec33687181597c84662ec9..b21caf177e370ef929f637c0f289b96a0db713db 100644 (file)
@@ -127,7 +127,7 @@ dcssblk_assign_free_minor(struct dcssblk_dev_info *dev_info)
                found = 0;
                // test if minor available
                list_for_each_entry(entry, &dcssblk_devices, lh)
-                       if (minor == MINOR(disk_devt(entry->gd)))
+                       if (minor == entry->gd->first_minor)
                                found++;
                if (!found) break; // got unused minor
        }
@@ -625,7 +625,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
        if (rc)
                goto release_gd;
        sprintf(dev_info->gd->disk_name, "dcssblk%d",
-               MINOR(disk_devt(dev_info->gd)));
+               dev_info->gd->first_minor);
        list_add_tail(&dev_info->lh, &dcssblk_devices);
 
        if (!try_module_get(THIS_MODULE)) {
index d028d2ee83dd36a3dff91061fbfc8d830eca3470..ed5396dae58eef0edc2eb6f451419737c0b5dfd7 100644 (file)
@@ -64,7 +64,7 @@ static struct con3270 *condev;
 #define CON_UPDATE_ERASE       1       /* Use EWRITEA instead of WRITE. */
 #define CON_UPDATE_LIST                2       /* Update lines in tty3270->update. */
 #define CON_UPDATE_STATUS      4       /* Update status line. */
-#define CON_UPDATE_ALL         7
+#define CON_UPDATE_ALL         8       /* Recreate screen. */
 
 static void con3270_update(struct con3270 *);
 
@@ -73,18 +73,10 @@ static void con3270_update(struct con3270 *);
  */
 static void con3270_set_timer(struct con3270 *cp, int expires)
 {
-       if (expires == 0) {
-               if (timer_pending(&cp->timer))
-                       del_timer(&cp->timer);
-               return;
-       }
-       if (timer_pending(&cp->timer) &&
-           mod_timer(&cp->timer, jiffies + expires))
-               return;
-       cp->timer.function = (void (*)(unsigned long)) con3270_update;
-       cp->timer.data = (unsigned long) cp;
-       cp->timer.expires = jiffies + expires;
-       add_timer(&cp->timer);
+       if (expires == 0)
+               del_timer(&cp->timer);
+       else
+               mod_timer(&cp->timer, jiffies + expires);
 }
 
 /*
@@ -225,6 +217,12 @@ con3270_update(struct con3270 *cp)
 
        spin_lock_irqsave(&cp->view.lock, flags);
        updated = 0;
+       if (cp->update_flags & CON_UPDATE_ALL) {
+               con3270_rebuild_update(cp);
+               con3270_update_status(cp);
+               cp->update_flags = CON_UPDATE_ERASE | CON_UPDATE_LIST |
+                       CON_UPDATE_STATUS;
+       }
        if (cp->update_flags & CON_UPDATE_ERASE) {
                /* Use erase write alternate to initialize display. */
                raw3270_request_set_cmd(wrq, TC_EWRITEA);
@@ -302,7 +300,6 @@ con3270_read_tasklet(struct raw3270_request *rrq)
                deactivate = 1;
                break;
        case 0x6d:      /* clear: start from scratch. */
-               con3270_rebuild_update(cp);
                cp->update_flags = CON_UPDATE_ALL;
                con3270_set_timer(cp, 1);
                break;
@@ -382,30 +379,21 @@ con3270_issue_read(struct con3270 *cp)
 static int
 con3270_activate(struct raw3270_view *view)
 {
-       unsigned long flags;
        struct con3270 *cp;
 
        cp = (struct con3270 *) view;
-       spin_lock_irqsave(&cp->view.lock, flags);
-       cp->nr_up = 0;
-       con3270_rebuild_update(cp);
-       con3270_update_status(cp);
        cp->update_flags = CON_UPDATE_ALL;
        con3270_set_timer(cp, 1);
-       spin_unlock_irqrestore(&cp->view.lock, flags);
        return 0;
 }
 
 static void
 con3270_deactivate(struct raw3270_view *view)
 {
-       unsigned long flags;
        struct con3270 *cp;
 
        cp = (struct con3270 *) view;
-       spin_lock_irqsave(&cp->view.lock, flags);
        del_timer(&cp->timer);
-       spin_unlock_irqrestore(&cp->view.lock, flags);
 }
 
 static int
@@ -504,6 +492,7 @@ con3270_write(struct console *co, const char *str, unsigned int count)
                        con3270_cline_end(cp);
        }
        /* Setup timer to output current console buffer after 1/10 second */
+       cp->nr_up = 0;
        if (cp->view.dev && !timer_pending(&cp->timer))
                con3270_set_timer(cp, HZ/10);
        spin_unlock_irqrestore(&cp->view.lock,flags);
@@ -624,7 +613,8 @@ con3270_init(void)
 
        INIT_LIST_HEAD(&condev->lines);
        INIT_LIST_HEAD(&condev->update);
-       init_timer(&condev->timer);
+       setup_timer(&condev->timer, (void (*)(unsigned long)) con3270_update,
+                   (unsigned long) condev);
        tasklet_init(&condev->readlet, 
                     (void (*)(unsigned long)) con3270_read_tasklet,
                     (unsigned long) condev->read);
index a7fe6302c9820c3790f3c14bffb4f0aee4b35679..38385677c65380e45730b42b8af38d78c9f8ac50 100644 (file)
@@ -112,7 +112,7 @@ struct tty3270 {
 #define TTY_UPDATE_LIST                2       /* Update lines in tty3270->update. */
 #define TTY_UPDATE_INPUT       4       /* Update input line. */
 #define TTY_UPDATE_STATUS      8       /* Update status line. */
-#define TTY_UPDATE_ALL         15
+#define TTY_UPDATE_ALL         16      /* Recreate screen. */
 
 static void tty3270_update(struct tty3270 *);
 
@@ -121,19 +121,10 @@ static void tty3270_update(struct tty3270 *);
  */
 static void tty3270_set_timer(struct tty3270 *tp, int expires)
 {
-       if (expires == 0) {
-               if (timer_pending(&tp->timer) && del_timer(&tp->timer))
-                       raw3270_put_view(&tp->view);
-               return;
-       }
-       if (timer_pending(&tp->timer) &&
-           mod_timer(&tp->timer, jiffies + expires))
-               return;
-       raw3270_get_view(&tp->view);
-       tp->timer.function = (void (*)(unsigned long)) tty3270_update;
-       tp->timer.data = (unsigned long) tp;
-       tp->timer.expires = jiffies + expires;
-       add_timer(&tp->timer);
+       if (expires == 0)
+               del_timer(&tp->timer);
+       else
+               mod_timer(&tp->timer, jiffies + expires);
 }
 
 /*
@@ -337,7 +328,6 @@ tty3270_write_callback(struct raw3270_request *rq, void *data)
        tp = (struct tty3270 *) rq->view;
        if (rq->rc != 0) {
                /* Write wasn't successfull. Refresh all. */
-               tty3270_rebuild_update(tp);
                tp->update_flags = TTY_UPDATE_ALL;
                tty3270_set_timer(tp, 1);
        }
@@ -366,6 +356,12 @@ tty3270_update(struct tty3270 *tp)
 
        spin_lock(&tp->view.lock);
        updated = 0;
+       if (tp->update_flags & TTY_UPDATE_ALL) {
+               tty3270_rebuild_update(tp);
+               tty3270_update_status(tp);
+               tp->update_flags = TTY_UPDATE_ERASE | TTY_UPDATE_LIST |
+                       TTY_UPDATE_INPUT | TTY_UPDATE_STATUS;
+       }
        if (tp->update_flags & TTY_UPDATE_ERASE) {
                /* Use erase write alternate to erase display. */
                raw3270_request_set_cmd(wrq, TC_EWRITEA);
@@ -425,7 +421,6 @@ tty3270_update(struct tty3270 *tp)
                xchg(&tp->write, wrq);
        }
        spin_unlock(&tp->view.lock);
-       raw3270_put_view(&tp->view);
 }
 
 /*
@@ -570,7 +565,6 @@ tty3270_read_tasklet(struct raw3270_request *rrq)
                tty3270_set_timer(tp, 1);
        } else if (tp->input->string[0] == 0x6d) {
                /* Display has been cleared. Redraw. */
-               tty3270_rebuild_update(tp);
                tp->update_flags = TTY_UPDATE_ALL;
                tty3270_set_timer(tp, 1);
        }
@@ -641,22 +635,20 @@ static int
 tty3270_activate(struct raw3270_view *view)
 {
        struct tty3270 *tp;
-       unsigned long flags;
 
        tp = (struct tty3270 *) view;
-       spin_lock_irqsave(&tp->view.lock, flags);
-       tp->nr_up = 0;
-       tty3270_rebuild_update(tp);
-       tty3270_update_status(tp);
        tp->update_flags = TTY_UPDATE_ALL;
        tty3270_set_timer(tp, 1);
-       spin_unlock_irqrestore(&tp->view.lock, flags);
        return 0;
 }
 
 static void
 tty3270_deactivate(struct raw3270_view *view)
 {
+       struct tty3270 *tp;
+
+       tp = (struct tty3270 *) view;
+       del_timer(&tp->timer);
 }
 
 static int
@@ -743,6 +735,7 @@ tty3270_free_view(struct tty3270 *tp)
 {
        int pages;
 
+       del_timer_sync(&tp->timer);
        kbd_free(tp->kbd);
        raw3270_request_free(tp->kreset);
        raw3270_request_free(tp->read);
@@ -889,7 +882,8 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
        INIT_LIST_HEAD(&tp->update);
        INIT_LIST_HEAD(&tp->rcl_lines);
        tp->rcl_max = 20;
-       init_timer(&tp->timer);
+       setup_timer(&tp->timer, (void (*)(unsigned long)) tty3270_update,
+                   (unsigned long) tp);
        tasklet_init(&tp->readlet, 
                     (void (*)(unsigned long)) tty3270_read_tasklet,
                     (unsigned long) tp->read);
@@ -1754,14 +1748,6 @@ static const struct tty_operations tty3270_ops = {
        .set_termios = tty3270_set_termios
 };
 
-static void tty3270_notifier(int index, int active)
-{
-       if (active)
-               tty_register_device(tty3270_driver, index, NULL);
-       else
-               tty_unregister_device(tty3270_driver, index);
-}
-
 /*
  * 3270 tty registration code called from tty_init().
  * Most kernel services (incl. kmalloc) are available at this poimt.
@@ -1796,12 +1782,6 @@ static int __init tty3270_init(void)
                return ret;
        }
        tty3270_driver = driver;
-       ret = raw3270_register_notifier(tty3270_notifier);
-       if (ret) {
-               put_tty_driver(driver);
-               return ret;
-
-       }
        return 0;
 }
 
@@ -1810,7 +1790,6 @@ tty3270_exit(void)
 {
        struct tty_driver *driver;
 
-       raw3270_unregister_notifier(tty3270_notifier);
        driver = tty3270_driver;
        tty3270_driver = NULL;
        tty_unregister_driver(driver);
index 2aebb9823044765427ceb806118b921276b94dbb..5ec7789bd9d84a0ab171d75d66315f4bce8e4b9c 100644 (file)
@@ -12,6 +12,7 @@
 #define KMSG_COMPONENT "cio"
 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
 
+#include <linux/ftrace.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -28,7 +29,7 @@
 #include <asm/chpid.h>
 #include <asm/airq.h>
 #include <asm/isc.h>
-#include <asm/cpu.h>
+#include <asm/cputime.h>
 #include <asm/fcx.h>
 #include <asm/nmi.h>
 #include <asm/crw.h>
@@ -626,8 +627,7 @@ out:
  *         handlers).
  *
  */
-void
-do_IRQ (struct pt_regs *regs)
+void __irq_entry do_IRQ(struct pt_regs *regs)
 {
        struct tpi_info *tpi_info;
        struct subchannel *sch;
index 151754d54745a3565fde4dca29a00f3de6b6a208..bf0a24af39a0542be842f5705cc49ec58da63b2f 100644 (file)
@@ -114,7 +114,7 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
        struct subchannel *sch;
        int ret;
 
-       if (!cdev)
+       if (!cdev || !cdev->dev.parent)
                return -ENODEV;
        if (cdev->private->state == DEV_STATE_NOT_OPER)
                return -ENODEV;
@@ -122,8 +122,6 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
            cdev->private->state != DEV_STATE_W4SENSE)
                return -EINVAL;
        sch = to_subchannel(cdev->dev.parent);
-       if (!sch)
-               return -ENODEV;
        ret = cio_clear(sch);
        if (ret == 0)
                cdev->private->intparm = intparm;
@@ -161,11 +159,9 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
        struct subchannel *sch;
        int ret;
 
-       if (!cdev)
+       if (!cdev || !cdev->dev.parent)
                return -ENODEV;
        sch = to_subchannel(cdev->dev.parent);
-       if (!sch)
-               return -ENODEV;
        if (cdev->private->state == DEV_STATE_NOT_OPER)
                return -ENODEV;
        if (cdev->private->state == DEV_STATE_VERIFY ||
@@ -339,7 +335,7 @@ int ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
        struct subchannel *sch;
        int ret;
 
-       if (!cdev)
+       if (!cdev || !cdev->dev.parent)
                return -ENODEV;
        if (cdev->private->state == DEV_STATE_NOT_OPER)
                return -ENODEV;
@@ -347,8 +343,6 @@ int ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
            cdev->private->state != DEV_STATE_W4SENSE)
                return -EINVAL;
        sch = to_subchannel(cdev->dev.parent);
-       if (!sch)
-               return -ENODEV;
        ret = cio_halt(sch);
        if (ret == 0)
                cdev->private->intparm = intparm;
@@ -372,11 +366,9 @@ int ccw_device_resume(struct ccw_device *cdev)
 {
        struct subchannel *sch;
 
-       if (!cdev)
+       if (!cdev || !cdev->dev.parent)
                return -ENODEV;
        sch = to_subchannel(cdev->dev.parent);
-       if (!sch)
-               return -ENODEV;
        if (cdev->private->state == DEV_STATE_NOT_OPER)
                return -ENODEV;
        if (cdev->private->state != DEV_STATE_ONLINE ||
@@ -471,11 +463,11 @@ __u8 ccw_device_get_path_mask(struct ccw_device *cdev)
 {
        struct subchannel *sch;
 
-       sch = to_subchannel(cdev->dev.parent);
-       if (!sch)
+       if (!cdev->dev.parent)
                return 0;
-       else
-               return sch->lpm;
+
+       sch = to_subchannel(cdev->dev.parent);
+       return sch->lpm;
 }
 
 /*
index accd957454e7210aab8c5de0d054a5a7b099eae8..d79cf5bf0e62312d98506ccb105618a640e64d09 100644 (file)
@@ -881,42 +881,26 @@ no_handler:
        qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED);
 }
 
-static int qdio_establish_check_errors(struct ccw_device *cdev, int cstat,
-                                      int dstat)
+static void qdio_establish_handle_irq(struct ccw_device *cdev, int cstat,
+                                     int dstat)
 {
        struct qdio_irq *irq_ptr = cdev->private->qdio_data;
 
-       if (cstat || (dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END))) {
-               DBF_ERROR("EQ:ck con");
-               goto error;
-       }
+       DBF_DEV_EVENT(DBF_INFO, irq_ptr, "qest irq");
 
-       if (!(dstat & DEV_STAT_DEV_END)) {
-               DBF_ERROR("EQ:no dev");
+       if (cstat)
                goto error;
-       }
-
-       if (dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) {
-               DBF_ERROR("EQ: bad io");
+       if (dstat & ~(DEV_STAT_DEV_END | DEV_STAT_CHN_END))
                goto error;
-       }
-       return 0;
+       if (!(dstat & DEV_STAT_DEV_END))
+               goto error;
+       qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ESTABLISHED);
+       return;
+
 error:
        DBF_ERROR("%4x EQ:error", irq_ptr->schid.sch_no);
        DBF_ERROR("ds: %2x cs:%2x", dstat, cstat);
-
        qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR);
-       return 1;
-}
-
-static void qdio_establish_handle_irq(struct ccw_device *cdev, int cstat,
-                                     int dstat)
-{
-       struct qdio_irq *irq_ptr = cdev->private->qdio_data;
-
-       DBF_DEV_EVENT(DBF_INFO, irq_ptr, "qest irq");
-       if (!qdio_establish_check_errors(cdev, cstat, dstat))
-               qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ESTABLISHED);
 }
 
 /* qdio interrupt handler */
@@ -946,7 +930,6 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm,
                }
        }
        qdio_irq_check_sense(irq_ptr, irb);
-
        cstat = irb->scsw.cmd.cstat;
        dstat = irb->scsw.cmd.dstat;
 
@@ -954,22 +937,19 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm,
        case QDIO_IRQ_STATE_INACTIVE:
                qdio_establish_handle_irq(cdev, cstat, dstat);
                break;
-
        case QDIO_IRQ_STATE_CLEANUP:
                qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE);
                break;
-
        case QDIO_IRQ_STATE_ESTABLISHED:
        case QDIO_IRQ_STATE_ACTIVE:
                if (cstat & SCHN_STAT_PCI) {
                        qdio_int_handler_pci(irq_ptr);
                        return;
                }
-               if ((cstat & ~SCHN_STAT_PCI) || dstat) {
+               if (cstat || dstat)
                        qdio_handle_activate_check(cdev, intparm, cstat,
                                                   dstat);
-                       break;
-               }
+               break;
        default:
                WARN_ON(1);
        }
@@ -1514,7 +1494,7 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags,
 
        if ((bufnr > QDIO_MAX_BUFFERS_PER_Q) ||
            (count > QDIO_MAX_BUFFERS_PER_Q) ||
-           (q_nr > QDIO_MAX_QUEUES_PER_IRQ))
+           (q_nr >= QDIO_MAX_QUEUES_PER_IRQ))
                return -EINVAL;
 
        if (!count)
index 136d0f0b1e93e7e155172caf55c2fabc31bccb8a..eff943923c6fac1d3e0862c0134b3a2a9920efa0 100644 (file)
@@ -25,18 +25,6 @@ struct qdio_perf_stats perf_stats;
 static struct proc_dir_entry *qdio_perf_pde;
 #endif
 
-inline void qdio_perf_stat_inc(atomic_long_t *count)
-{
-       if (qdio_performance_stats)
-               atomic_long_inc(count);
-}
-
-inline void qdio_perf_stat_dec(atomic_long_t *count)
-{
-       if (qdio_performance_stats)
-               atomic_long_dec(count);
-}
-
 /*
  * procfs functions
  */
index 7821ac4fa51759196f6dbdc0bf56045aef9140aa..ff4504ce1e3c0ad5577e86d0642895d08b8c7924 100644 (file)
@@ -9,7 +9,6 @@
 #define QDIO_PERF_H
 
 #include <linux/types.h>
-#include <linux/device.h>
 #include <asm/atomic.h>
 
 struct qdio_perf_stats {
@@ -50,10 +49,13 @@ struct qdio_perf_stats {
 extern struct qdio_perf_stats perf_stats;
 extern int qdio_performance_stats;
 
+static inline void qdio_perf_stat_inc(atomic_long_t *count)
+{
+       if (qdio_performance_stats)
+               atomic_long_inc(count);
+}
+
 int qdio_setup_perf_stats(void);
 void qdio_remove_perf_stats(void);
 
-extern void qdio_perf_stat_inc(atomic_long_t *count);
-extern void qdio_perf_stat_dec(atomic_long_t *count);
-
 #endif
index cbc8566fab705f954aae795f18ff58744b93b9c7..e38e5d306faf577f9ccc9bfb25a75a1f29c4785e 100644 (file)
@@ -173,8 +173,9 @@ static void kvm_notify(struct virtqueue *vq)
  * this device and sets it up.
  */
 static struct virtqueue *kvm_find_vq(struct virtio_device *vdev,
-                                   unsigned index,
-                                   void (*callback)(struct virtqueue *vq))
+                                    unsigned index,
+                                    void (*callback)(struct virtqueue *vq),
+                                    const char *name)
 {
        struct kvm_device *kdev = to_kvmdev(vdev);
        struct kvm_vqconfig *config;
@@ -194,7 +195,7 @@ static struct virtqueue *kvm_find_vq(struct virtio_device *vdev,
 
        vq = vring_new_virtqueue(config->num, KVM_S390_VIRTIO_RING_ALIGN,
                                 vdev, (void *) config->address,
-                                kvm_notify, callback);
+                                kvm_notify, callback, name);
        if (!vq) {
                err = -ENOMEM;
                goto unmap;
@@ -226,6 +227,38 @@ static void kvm_del_vq(struct virtqueue *vq)
                                       KVM_S390_VIRTIO_RING_ALIGN));
 }
 
+static void kvm_del_vqs(struct virtio_device *vdev)
+{
+       struct virtqueue *vq, *n;
+
+       list_for_each_entry_safe(vq, n, &vdev->vqs, list)
+               kvm_del_vq(vq);
+}
+
+static int kvm_find_vqs(struct virtio_device *vdev, unsigned nvqs,
+                       struct virtqueue *vqs[],
+                       vq_callback_t *callbacks[],
+                       const char *names[])
+{
+       struct kvm_device *kdev = to_kvmdev(vdev);
+       int i;
+
+       /* We must have this many virtqueues. */
+       if (nvqs > kdev->desc->num_vq)
+               return -ENOENT;
+
+       for (i = 0; i < nvqs; ++i) {
+               vqs[i] = kvm_find_vq(vdev, i, callbacks[i], names[i]);
+               if (IS_ERR(vqs[i]))
+                       goto error;
+       }
+       return 0;
+
+error:
+       kvm_del_vqs(vdev);
+       return PTR_ERR(vqs[i]);
+}
+
 /*
  * The config ops structure as defined by virtio config
  */
@@ -237,8 +270,8 @@ static struct virtio_config_ops kvm_vq_configspace_ops = {
        .get_status = kvm_get_status,
        .set_status = kvm_set_status,
        .reset = kvm_reset,
-       .find_vq = kvm_find_vq,
-       .del_vq = kvm_del_vq,
+       .find_vqs = kvm_find_vqs,
+       .del_vqs = kvm_del_vqs,
 };
 
 /*
index a7745c82b4ae594a05ebbdc52b284e90ed4e844c..cb909a5b5047e11fc6b3d6ddcca3a31811f73106 100644 (file)
@@ -8,7 +8,7 @@ config LCS
           Select this option if you want to use LCS networking on IBM System z.
           This device driver supports Token Ring (IEEE 802.5),
           FDDI (IEEE 802.7) and Ethernet.
-          To compile as a module, choose M. The module name is lcs.ko.
+          To compile as a module, choose M. The module name is lcs.
           If you do not know what it is, it's safe to choose Y.
 
 config CTCM
@@ -21,7 +21,7 @@ config CTCM
          It also supports virtual CTCs when running under VM.
          This driver also supports channel-to-channel MPC SNA devices.
          MPC is an SNA protocol device used by Communication Server for Linux.
-         To compile as a module, choose M. The module name is ctcm.ko.
+         To compile as a module, choose M. The module name is ctcm.
          To compile into the kernel, choose Y.
          If you do not need any channel-to-channel connection, choose N.
 
@@ -34,7 +34,7 @@ config NETIUCV
          link between VM guests. Using ifconfig a point-to-point connection
          can be established to the Linux on IBM System z
          running on the other VM guest. To compile as a module, choose M.
-         The module name is netiucv.ko. If unsure, choose Y.
+         The module name is netiucv. If unsure, choose Y.
 
 config SMSGIUCV
        tristate "IUCV special message support (VM only)"
@@ -50,7 +50,7 @@ config CLAW
          This driver supports channel attached CLAW devices.
          CLAW is Common Link Access for Workstation.  Common devices
           that use CLAW are RS/6000s, Cisco Routers (CIP) and 3172 devices.
-         To compile as a module, choose M. The module name is claw.ko.
+         To compile as a module, choose M. The module name is claw.
          To compile into the kernel, choose Y.
 
 config QETH
@@ -65,14 +65,14 @@ config QETH
          <http://www.ibm.com/developerworks/linux/linux390>
 
          To compile this driver as a module, choose M.
-         The module name is qeth.ko.
+         The module name is qeth.
 
 config QETH_L2
         tristate "qeth layer 2 device support"
         depends on QETH
         help
           Select this option to be able to run qeth devices in layer 2 mode.
-          To compile as a module, choose M. The module name is qeth_l2.ko.
+          To compile as a module, choose M. The module name is qeth_l2.
           If unsure, choose y.
 
 config QETH_L3
@@ -80,7 +80,7 @@ config QETH_L3
         depends on QETH
         help
           Select this option to be able to run qeth devices in layer 3 mode.
-          To compile as a module choose M. The module name is qeth_l3.ko.
+          To compile as a module choose M. The module name is qeth_l3.
           If unsure, choose Y.
 
 config QETH_IPV6
index 733fe3bf6285f0e20c6d6737b600beac7ec7332e..b2fe5cdbcaeec3cb4462b22040fa6282bd70c7b5 100644 (file)
 
 #include "zfcp_ext.h"
 
+#define ZFCP_MODEL_PRIV 0x4
+
+static struct ccw_device_id zfcp_ccw_device_id[] = {
+       { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x3) },
+       { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, ZFCP_MODEL_PRIV) },
+       {},
+};
+MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id);
+
+/**
+ * zfcp_ccw_priv_sch - check if subchannel is privileged
+ * @adapter: Adapter/Subchannel to check
+ */
+int zfcp_ccw_priv_sch(struct zfcp_adapter *adapter)
+{
+       return adapter->ccw_device->id.dev_model == ZFCP_MODEL_PRIV;
+}
+
 /**
  * zfcp_ccw_probe - probe function of zfcp driver
  * @ccw_device: pointer to belonging ccw device
@@ -176,8 +194,8 @@ static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event)
                                        "ccnoti4", NULL);
                break;
        case CIO_BOXED:
-               dev_warn(&adapter->ccw_device->dev,
-                        "The ccw device did not respond in time.\n");
+               dev_warn(&adapter->ccw_device->dev, "The FCP device "
+                        "did not respond within the specified time\n");
                zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5", NULL);
                break;
        }
@@ -199,14 +217,6 @@ static void zfcp_ccw_shutdown(struct ccw_device *cdev)
        up(&zfcp_data.config_sema);
 }
 
-static struct ccw_device_id zfcp_ccw_device_id[] = {
-       { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x3) },
-       { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x4) }, /* priv. */
-       {},
-};
-
-MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id);
-
 static struct ccw_driver zfcp_ccw_driver = {
        .owner       = THIS_MODULE,
        .name        = "zfcp",
index 0a1a5dd8d01831b9e13986ba9fd553b7ffc55342..b99b87ce5a39618d8236167fd98b4db6e43a9a3b 100644 (file)
@@ -163,7 +163,7 @@ void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req)
        }
 
        response->fsf_command = fsf_req->fsf_command;
-       response->fsf_reqid = (unsigned long)fsf_req;
+       response->fsf_reqid = fsf_req->req_id;
        response->fsf_seqno = fsf_req->seq_no;
        response->fsf_issued = fsf_req->issued;
        response->fsf_prot_status = qtcb->prefix.prot_status;
@@ -737,7 +737,7 @@ void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req)
        spin_lock_irqsave(&adapter->san_dbf_lock, flags);
        memset(r, 0, sizeof(*r));
        strncpy(r->tag, "octc", ZFCP_DBF_TAG_SIZE);
-       r->fsf_reqid = (unsigned long)fsf_req;
+       r->fsf_reqid = fsf_req->req_id;
        r->fsf_seqno = fsf_req->seq_no;
        r->s_id = fc_host_port_id(adapter->scsi_host);
        r->d_id = wka_port->d_id;
@@ -773,7 +773,7 @@ void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req)
        spin_lock_irqsave(&adapter->san_dbf_lock, flags);
        memset(r, 0, sizeof(*r));
        strncpy(r->tag, "rctc", ZFCP_DBF_TAG_SIZE);
-       r->fsf_reqid = (unsigned long)fsf_req;
+       r->fsf_reqid = fsf_req->req_id;
        r->fsf_seqno = fsf_req->seq_no;
        r->s_id = wka_port->d_id;
        r->d_id = fc_host_port_id(adapter->scsi_host);
@@ -803,7 +803,7 @@ static void zfcp_san_dbf_event_els(const char *tag, int level,
        spin_lock_irqsave(&adapter->san_dbf_lock, flags);
        memset(rec, 0, sizeof(*rec));
        strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE);
-       rec->fsf_reqid = (unsigned long)fsf_req;
+       rec->fsf_reqid = fsf_req->req_id;
        rec->fsf_seqno = fsf_req->seq_no;
        rec->s_id = s_id;
        rec->d_id = d_id;
@@ -965,7 +965,7 @@ static void zfcp_scsi_dbf_event(const char *tag, const char *tag2, int level,
                                                      ZFCP_DBF_SCSI_FCP_SNS_INFO);
                                }
 
-                               rec->fsf_reqid = (unsigned long)fsf_req;
+                               rec->fsf_reqid = fsf_req->req_id;
                                rec->fsf_seqno = fsf_req->seq_no;
                                rec->fsf_issued = fsf_req->issued;
                        }
index 4c362a9069f07463c8db6869a86575099024300a..2074d45dbf6c4b1a426b5f9aafc39a11e1c41fe9 100644 (file)
 
 /********************* CIO/QDIO SPECIFIC DEFINES *****************************/
 
-/* Adapter Identification Parameters */
-#define ZFCP_CONTROL_UNIT_TYPE  0x1731
-#define ZFCP_CONTROL_UNIT_MODEL 0x03
-#define ZFCP_DEVICE_TYPE        0x1732
-#define ZFCP_DEVICE_MODEL       0x03
-#define ZFCP_DEVICE_MODEL_PRIV 0x04
-
 /* DMQ bug workaround: don't use last SBALE */
 #define ZFCP_MAX_SBALES_PER_SBAL       (QDIO_MAX_ELEMENTS_PER_BUFFER - 1)
 
index fdc9b4352a6493e888ffb9ac4535619c2b379bc9..e50ea465bc2b993b44829a7d1554259e475fa2da 100644 (file)
@@ -880,6 +880,7 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
                                zfcp_port_put(port);
                        return ZFCP_ERP_CONTINUES;
                }
+               /* fall through */
        case ZFCP_ERP_STEP_NAMESERVER_LOOKUP:
                if (!port->d_id)
                        return ZFCP_ERP_FAILED;
@@ -894,8 +895,13 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
                                act->step = ZFCP_ERP_STEP_PORT_CLOSING;
                                return ZFCP_ERP_CONTINUES;
                        }
-               /* fall through otherwise */
                }
+               if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) {
+                       port->d_id = 0;
+                       _zfcp_erp_port_reopen(port, 0, "erpsoc1", NULL);
+                       return ZFCP_ERP_EXIT;
+               }
+               /* fall through otherwise */
        }
        return ZFCP_ERP_FAILED;
 }
index 2e31b536548c2e28344831c3f4266f32c70c5c6b..120a9a1c81f7cf491e12b208d48c346ab5586780 100644 (file)
@@ -27,6 +27,7 @@ extern int zfcp_sg_setup_table(struct scatterlist *, int);
 
 /* zfcp_ccw.c */
 extern int zfcp_ccw_register(void);
+extern int zfcp_ccw_priv_sch(struct zfcp_adapter *);
 extern struct zfcp_adapter *zfcp_get_adapter_by_busid(char *);
 
 /* zfcp_cfdc.c */
index 19ae0842047c4750f0614479381c39b76d40d7ca..35493a82d2a8accd43afb2fc2af0c43385d1df38 100644 (file)
@@ -116,7 +116,7 @@ static void zfcp_wka_port_put(struct zfcp_wka_port *wka_port)
 {
        if (atomic_dec_return(&wka_port->refcount) != 0)
                return;
-       /* wait 10 miliseconds, other reqs might pop in */
+       /* wait 10 milliseconds, other reqs might pop in */
        schedule_delayed_work(&wka_port->work, HZ / 100);
 }
 
@@ -150,9 +150,14 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range,
        struct zfcp_port *port;
 
        read_lock_irqsave(&zfcp_data.config_lock, flags);
-       list_for_each_entry(port, &fsf_req->adapter->port_list_head, list)
+       list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) {
                if ((port->d_id & range) == (elem->nport_did & range))
                        zfcp_test_link(port);
+               if (!port->d_id)
+                       zfcp_erp_port_reopen(port,
+                                            ZFCP_STATUS_COMMON_ERP_FAILED,
+                                            "fcrscn1", NULL);
+       }
 
        read_unlock_irqrestore(&zfcp_data.config_lock, flags);
 }
index 74dee32afba84619d564055909e26d41954e5ef3..e6dae3744e7981c348ddd554dbdf6dd27049c98f 100644 (file)
@@ -526,6 +526,7 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
                break;
        case FSF_TOPO_AL:
                fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
+               /* fall through */
        default:
                dev_err(&adapter->ccw_device->dev,
                        "Unknown or unsupported arbitrated loop "
@@ -897,6 +898,7 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)
                switch (fsq->word[0]) {
                case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
                        zfcp_test_link(unit->port);
+                       /* fall through */
                case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
                        req->status |= ZFCP_STATUS_FSFREQ_ERROR;
                        break;
@@ -993,6 +995,7 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)
                break;
        case FSF_PORT_HANDLE_NOT_VALID:
                zfcp_erp_adapter_reopen(adapter, 0, "fsscth1", req);
+               /* fall through */
        case FSF_GENERIC_COMMAND_REJECTED:
        case FSF_PAYLOAD_SIZE_MISMATCH:
        case FSF_REQUEST_SIZE_TOO_LARGE:
@@ -1399,7 +1402,7 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
        struct fsf_plogi *plogi;
 
        if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
-               return;
+               goto out;
 
        switch (header->fsf_status) {
        case FSF_PORT_ALREADY_OPEN:
@@ -1461,6 +1464,9 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
                req->status |= ZFCP_STATUS_FSFREQ_ERROR;
                break;
        }
+
+out:
+       zfcp_port_put(port);
 }
 
 /**
@@ -1473,6 +1479,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
        struct qdio_buffer_element *sbale;
        struct zfcp_adapter *adapter = erp_action->adapter;
        struct zfcp_fsf_req *req;
+       struct zfcp_port *port = erp_action->port;
        int retval = -EIO;
 
        spin_lock_bh(&adapter->req_q_lock);
@@ -1493,16 +1500,18 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
         sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
 
        req->handler = zfcp_fsf_open_port_handler;
-       req->qtcb->bottom.support.d_id = erp_action->port->d_id;
-       req->data = erp_action->port;
+       req->qtcb->bottom.support.d_id = port->d_id;
+       req->data = port;
        req->erp_action = erp_action;
        erp_action->fsf_req = req;
+       zfcp_port_get(port);
 
        zfcp_fsf_start_erp_timer(req);
        retval = zfcp_fsf_req_send(req);
        if (retval) {
                zfcp_fsf_req_free(req);
                erp_action->fsf_req = NULL;
+               zfcp_port_put(port);
        }
 out:
        spin_unlock_bh(&adapter->req_q_lock);
@@ -1590,8 +1599,10 @@ static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req)
        case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:
                dev_warn(&req->adapter->ccw_device->dev,
                         "Opening WKA port 0x%x failed\n", wka_port->d_id);
+               /* fall through */
        case FSF_ADAPTER_STATUS_AVAILABLE:
                req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+               /* fall through */
        case FSF_ACCESS_DENIED:
                wka_port->status = ZFCP_WKA_PORT_OFFLINE;
                break;
@@ -1876,7 +1887,7 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
 
                if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE) &&
                    (adapter->adapter_features & FSF_FEATURE_LUN_SHARING) &&
-                   (adapter->ccw_device->id.dev_model != ZFCP_DEVICE_MODEL_PRIV)) {
+                   !zfcp_ccw_priv_sch(adapter)) {
                        exclusive = (bottom->lun_access_info &
                                        FSF_UNIT_ACCESS_EXCLUSIVE);
                        readwrite = (bottom->lun_access_info &
@@ -2314,7 +2325,7 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
 {
        struct zfcp_fsf_req *req;
        struct fcp_cmnd_iu *fcp_cmnd_iu;
-       unsigned int sbtype;
+       unsigned int sbtype = SBAL_FLAGS0_TYPE_READ;
        int real_bytes, retval = -EIO;
        struct zfcp_adapter *adapter = unit->port->adapter;
 
@@ -2356,11 +2367,9 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
        switch (scsi_cmnd->sc_data_direction) {
        case DMA_NONE:
                req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
-               sbtype = SBAL_FLAGS0_TYPE_READ;
                break;
        case DMA_FROM_DEVICE:
                req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ;
-               sbtype = SBAL_FLAGS0_TYPE_READ;
                fcp_cmnd_iu->rddata = 1;
                break;
        case DMA_TO_DEVICE:
@@ -2369,8 +2378,6 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
                fcp_cmnd_iu->wddata = 1;
                break;
        case DMA_BIDIRECTIONAL:
-       default:
-               retval = -EIO;
                goto failed_scsi_cmnd;
        }
 
@@ -2394,9 +2401,7 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
                                             scsi_sglist(scsi_cmnd),
                                             FSF_MAX_SBALS_PER_REQ);
        if (unlikely(real_bytes < 0)) {
-               if (req->sbal_number < FSF_MAX_SBALS_PER_REQ)
-                       retval = -EIO;
-               else {
+               if (req->sbal_number >= FSF_MAX_SBALS_PER_REQ) {
                        dev_err(&adapter->ccw_device->dev,
                                "Oversize data package, unit 0x%016Lx "
                                "on port 0x%016Lx closed\n",
index e8fbeaeb5fbfb4046d1a04ed3cab14e642bdce2a..7d0da230eb637ce92468f2d6565e1b04be4fdde3 100644 (file)
 #include "zfcp_ext.h"
 #include <asm/atomic.h>
 
+static unsigned int default_depth = 32;
+module_param_named(queue_depth, default_depth, uint, 0600);
+MODULE_PARM_DESC(queue_depth, "Default queue depth for new SCSI devices");
+
 /* Find start of Sense Information in FCP response unit*/
 char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu)
 {
@@ -24,6 +28,12 @@ char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu)
        return fcp_sns_info_ptr;
 }
 
+static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth)
+{
+       scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
+       return sdev->queue_depth;
+}
+
 static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
 {
        struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata;
@@ -34,7 +44,7 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
 static int zfcp_scsi_slave_configure(struct scsi_device *sdp)
 {
        if (sdp->tagged_supported)
-               scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, 32);
+               scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, default_depth);
        else
                scsi_adjust_queue_depth(sdp, 0, 1);
        return 0;
@@ -647,6 +657,7 @@ struct zfcp_data zfcp_data = {
                .name                    = "zfcp",
                .module                  = THIS_MODULE,
                .proc_name               = "zfcp",
+               .change_queue_depth      = zfcp_scsi_change_queue_depth,
                .slave_alloc             = zfcp_scsi_slave_alloc,
                .slave_configure         = zfcp_scsi_slave_configure,
                .slave_destroy           = zfcp_scsi_slave_destroy,
index fb2740789b6879d48ce2501272e3ddc53337108c..6a19ed9a1194aff51553bed7ad9384f5925d6779 100644 (file)
@@ -191,20 +191,19 @@ config SCSI_ENCLOSURE
          it has an enclosure device.  Selecting this option will just allow
          certain enclosure conditions to be reported and is not required.
 
-comment "Some SCSI devices (e.g. CD jukebox) support multiple LUNs"
-       depends on SCSI
-
 config SCSI_MULTI_LUN
        bool "Probe all LUNs on each SCSI device"
        depends on SCSI
        help
-         If you have a SCSI device that supports more than one LUN (Logical
-         Unit Number), e.g. a CD jukebox, and only one LUN is detected, you
-         can say Y here to force the SCSI driver to probe for multiple LUNs.
-         A SCSI device with multiple LUNs acts logically like multiple SCSI
-         devices. The vast majority of SCSI devices have only one LUN, and
-         so most people can say N here. The max_luns boot/module parameter 
-         allows to override this setting.
+         Some devices support more than one LUN (Logical Unit Number) in order
+         to allow access to several media, e.g. CD jukebox, USB card reader,
+         mobile phone in mass storage mode. This option forces the kernel to
+         probe for all LUNs by default. This setting can be overriden by
+         max_luns boot/module parameter. Note that this option does not affect
+         devices conforming to SCSI-3 or higher as they can explicitely report
+         their number of LUNs. It is safe to say Y here unless you have one of
+         those rare devices which reacts in an unexpected way when probed for
+         multiple LUNs.
 
 config SCSI_CONSTANTS
        bool "Verbose SCSI error reporting (kernel size +=12K)"
@@ -355,6 +354,7 @@ config ISCSI_TCP
         http://open-iscsi.org
 
 source "drivers/scsi/cxgb3i/Kconfig"
+source "drivers/scsi/bnx2i/Kconfig"
 
 config SGIWD93_SCSI
        tristate "SGI WD93C93 SCSI Driver"
@@ -508,6 +508,7 @@ config SCSI_AIC7XXX_OLD
 
 source "drivers/scsi/aic7xxx/Kconfig.aic79xx"
 source "drivers/scsi/aic94xx/Kconfig"
+source "drivers/scsi/mvsas/Kconfig"
 
 config SCSI_DPT_I2O
        tristate "Adaptec I2O RAID support "
@@ -1050,16 +1051,6 @@ config SCSI_IZIP_SLOW_CTR
 
          Generally, saying N is fine.
 
-config SCSI_MVSAS
-       tristate "Marvell 88SE6440 SAS/SATA support"
-       depends on PCI && SCSI
-       select SCSI_SAS_LIBSAS
-       help
-         This driver supports Marvell SAS/SATA PCI devices.
-
-         To compiler this driver as a module, choose M here: the module
-         will be called mvsas.
-
 config SCSI_NCR53C406A
        tristate "NCR53c406a SCSI support"
        depends on ISA && SCSI
index a5049cfb40edb1c4e3c69aa9e4e95076590a0e57..25429ea63d0ad0708d236e1242819b6fc152e676 100644 (file)
@@ -126,9 +126,10 @@ obj-$(CONFIG_SCSI_IBMVSCSIS)       += ibmvscsi/
 obj-$(CONFIG_SCSI_IBMVFC)      += ibmvscsi/
 obj-$(CONFIG_SCSI_HPTIOP)      += hptiop.o
 obj-$(CONFIG_SCSI_STEX)                += stex.o
-obj-$(CONFIG_SCSI_MVSAS)       += mvsas.o
+obj-$(CONFIG_SCSI_MVSAS)       += mvsas/
 obj-$(CONFIG_PS3_ROM)          += ps3rom.o
 obj-$(CONFIG_SCSI_CXGB3_ISCSI) += libiscsi.o libiscsi_tcp.o cxgb3i/
+obj-$(CONFIG_SCSI_BNX2_ISCSI)  += libiscsi.o bnx2i/
 
 obj-$(CONFIG_ARM)              += arm/
 
index c889d8458684b002d5e03bd9bebf3a4e639cf4c4..1cdf09a4779a560532e7dc2edafc4dc4f91e2170 100644 (file)
@@ -224,7 +224,7 @@ NCR_D700_probe_one(struct NCR_D700_private *p, int siop, int irq,
        return ret;
 }
 
-static int
+static irqreturn_t
 NCR_D700_intr(int irq, void *data)
 {
        struct NCR_D700_private *p = (struct NCR_D700_private *)data;
diff --git a/drivers/scsi/bnx2i/57xx_iscsi_constants.h b/drivers/scsi/bnx2i/57xx_iscsi_constants.h
new file mode 100644 (file)
index 0000000..2fceb19
--- /dev/null
@@ -0,0 +1,155 @@
+/* 57xx_iscsi_constants.h: Broadcom NetXtreme II iSCSI HSI
+ *
+ * Copyright (c) 2006 - 2009 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ */
+#ifndef __57XX_ISCSI_CONSTANTS_H_
+#define __57XX_ISCSI_CONSTANTS_H_
+
+/**
+* This file defines HSI constants for the iSCSI flows
+*/
+
+/* iSCSI request op codes */
+#define ISCSI_OPCODE_CLEANUP_REQUEST    (7)
+
+/* iSCSI response/messages op codes */
+#define ISCSI_OPCODE_CLEANUP_RESPONSE          (0x27)
+#define ISCSI_OPCODE_NOPOUT_LOCAL_COMPLETION    (0)
+
+/* iSCSI task types */
+#define ISCSI_TASK_TYPE_READ    (0)
+#define ISCSI_TASK_TYPE_WRITE   (1)
+#define ISCSI_TASK_TYPE_MPATH   (2)
+
+/* initial CQ sequence numbers */
+#define ISCSI_INITIAL_SN    (1)
+
+/* KWQ (kernel work queue) layer codes */
+#define ISCSI_KWQE_LAYER_CODE   (6)
+
+/* KWQ (kernel work queue) request op codes */
+#define ISCSI_KWQE_OPCODE_OFFLOAD_CONN1 (0)
+#define ISCSI_KWQE_OPCODE_OFFLOAD_CONN2 (1)
+#define ISCSI_KWQE_OPCODE_UPDATE_CONN   (2)
+#define ISCSI_KWQE_OPCODE_DESTROY_CONN  (3)
+#define ISCSI_KWQE_OPCODE_INIT1         (4)
+#define ISCSI_KWQE_OPCODE_INIT2         (5)
+
+/* KCQ (kernel completion queue) response op codes */
+#define ISCSI_KCQE_OPCODE_OFFLOAD_CONN  (0x10)
+#define ISCSI_KCQE_OPCODE_UPDATE_CONN   (0x12)
+#define ISCSI_KCQE_OPCODE_DESTROY_CONN  (0x13)
+#define ISCSI_KCQE_OPCODE_INIT          (0x14)
+#define ISCSI_KCQE_OPCODE_FW_CLEAN_TASK        (0x15)
+#define ISCSI_KCQE_OPCODE_TCP_RESET     (0x16)
+#define ISCSI_KCQE_OPCODE_TCP_SYN       (0x17)
+#define ISCSI_KCQE_OPCODE_TCP_FIN       (0X18)
+#define ISCSI_KCQE_OPCODE_TCP_ERROR     (0x19)
+#define ISCSI_KCQE_OPCODE_CQ_EVENT_NOTIFICATION (0x20)
+#define ISCSI_KCQE_OPCODE_ISCSI_ERROR   (0x21)
+
+/* KCQ (kernel completion queue) completion status */
+#define ISCSI_KCQE_COMPLETION_STATUS_SUCCESS                            (0x0)
+#define ISCSI_KCQE_COMPLETION_STATUS_INVALID_OPCODE                     (0x1)
+#define ISCSI_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE                  (0x2)
+#define ISCSI_KCQE_COMPLETION_STATUS_CTX_FREE_FAILURE                   (0x3)
+#define ISCSI_KCQE_COMPLETION_STATUS_NIC_ERROR                          (0x4)
+
+#define ISCSI_KCQE_COMPLETION_STATUS_HDR_DIG_ERR                        (0x5)
+#define ISCSI_KCQE_COMPLETION_STATUS_DATA_DIG_ERR                       (0x6)
+
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_UNEXPECTED_OPCODE     (0xa)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_OPCODE                (0xb)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_AHS_LEN               (0xc)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_ITT                   (0xd)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_STATSN                (0xe)
+
+/* Response */
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_EXP_DATASN            (0xf)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T              (0x10)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATA_SEG_LEN_IS_ZERO  (0x2c)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATA_SEG_LEN_TOO_BIG  (0x2d)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_0                 (0x11)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_1                 (0x12)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_2                 (0x13)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_3                 (0x14)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_4                 (0x15)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_5                 (0x16)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_6                 (0x17)
+
+/* Data-In */
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REMAIN_RCV_LEN        (0x18)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_MAX_RCV_PDU_LEN       (0x19)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_F_BIT_ZERO            (0x1a)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_TTT_NOT_RSRV          (0x1b)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATASN                (0x1c)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REMAIN_BURST_LEN      (0x1d)
+
+/* R2T */
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_BUFFER_OFF            (0x1f)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_LUN                   (0x20)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_R2TSN                 (0x21)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_0 (0x22)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_1 (0x23)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T_EXCEED       (0x24)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_TTT_IS_RSRV           (0x25)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_MAX_BURST_LEN         (0x26)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATA_SEG_LEN_NOT_ZERO (0x27)
+
+/* TMF */
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REJECT_PDU_LEN        (0x28)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_ASYNC_PDU_LEN         (0x29)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_NOPIN_PDU_LEN         (0x2a)
+#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T_IN_CLEANUP   (0x2b)
+
+/* IP/TCP processing errors: */
+#define ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_IP_FRAGMENT               (0x40)
+#define ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_IP_OPTIONS                (0x41)
+#define ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_URGENT_FLAG               (0x42)
+#define ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_MAX_RTRANS                (0x43)
+
+/* iSCSI licensing errors */
+/* general iSCSI license not installed */
+#define ISCSI_KCQE_COMPLETION_STATUS_ISCSI_NOT_SUPPORTED                (0x50)
+/* additional LOM specific iSCSI license not installed */
+#define ISCSI_KCQE_COMPLETION_STATUS_LOM_ISCSI_NOT_ENABLED              (0x51)
+
+/* SQ/RQ/CQ DB structure sizes */
+#define ISCSI_SQ_DB_SIZE    (16)
+#define ISCSI_RQ_DB_SIZE    (16)
+#define ISCSI_CQ_DB_SIZE    (80)
+
+#define ISCSI_SQN_TO_NOTIFY_NOT_VALID                                   0xFFFF
+
+/* Page size codes (for flags field in connection offload request) */
+#define ISCSI_PAGE_SIZE_256     (0)
+#define ISCSI_PAGE_SIZE_512     (1)
+#define ISCSI_PAGE_SIZE_1K      (2)
+#define ISCSI_PAGE_SIZE_2K      (3)
+#define ISCSI_PAGE_SIZE_4K      (4)
+#define ISCSI_PAGE_SIZE_8K      (5)
+#define ISCSI_PAGE_SIZE_16K     (6)
+#define ISCSI_PAGE_SIZE_32K     (7)
+#define ISCSI_PAGE_SIZE_64K     (8)
+#define ISCSI_PAGE_SIZE_128K    (9)
+#define ISCSI_PAGE_SIZE_256K    (10)
+#define ISCSI_PAGE_SIZE_512K    (11)
+#define ISCSI_PAGE_SIZE_1M      (12)
+#define ISCSI_PAGE_SIZE_2M      (13)
+#define ISCSI_PAGE_SIZE_4M      (14)
+#define ISCSI_PAGE_SIZE_8M      (15)
+
+/* Iscsi PDU related defines */
+#define ISCSI_HEADER_SIZE   (48)
+#define ISCSI_DIGEST_SHIFT  (2)
+#define ISCSI_DIGEST_SIZE   (4)
+
+#define B577XX_ISCSI_CONNECTION_TYPE    3
+
+#endif /*__57XX_ISCSI_CONSTANTS_H_ */
diff --git a/drivers/scsi/bnx2i/57xx_iscsi_hsi.h b/drivers/scsi/bnx2i/57xx_iscsi_hsi.h
new file mode 100644 (file)
index 0000000..36af1af
--- /dev/null
@@ -0,0 +1,1509 @@
+/* 57xx_iscsi_hsi.h: Broadcom NetXtreme II iSCSI HSI.
+ *
+ * Copyright (c) 2006 - 2009 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ */
+#ifndef __57XX_ISCSI_HSI_LINUX_LE__
+#define __57XX_ISCSI_HSI_LINUX_LE__
+
+/*
+ * iSCSI Async CQE
+ */
+struct bnx2i_async_msg {
+#if defined(__BIG_ENDIAN)
+       u8 op_code;
+       u8 reserved1;
+       u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+       u16 reserved0;
+       u8 reserved1;
+       u8 op_code;
+#endif
+       u32 reserved2;
+       u32 exp_cmd_sn;
+       u32 max_cmd_sn;
+       u32 reserved3[2];
+#if defined(__BIG_ENDIAN)
+       u16 reserved5;
+       u8 err_code;
+       u8 reserved4;
+#elif defined(__LITTLE_ENDIAN)
+       u8 reserved4;
+       u8 err_code;
+       u16 reserved5;
+#endif
+       u32 reserved6;
+       u32 lun[2];
+#if defined(__BIG_ENDIAN)
+       u8 async_event;
+       u8 async_vcode;
+       u16 param1;
+#elif defined(__LITTLE_ENDIAN)
+       u16 param1;
+       u8 async_vcode;
+       u8 async_event;
+#endif
+#if defined(__BIG_ENDIAN)
+       u16 param2;
+       u16 param3;
+#elif defined(__LITTLE_ENDIAN)
+       u16 param3;
+       u16 param2;
+#endif
+       u32 reserved7[3];
+       u32 cq_req_sn;
+};
+
+
+/*
+ * iSCSI Buffer Descriptor (BD)
+ */
+struct iscsi_bd {
+       u32 buffer_addr_hi;
+       u32 buffer_addr_lo;
+#if defined(__BIG_ENDIAN)
+       u16 reserved0;
+       u16 buffer_length;
+#elif defined(__LITTLE_ENDIAN)
+       u16 buffer_length;
+       u16 reserved0;
+#endif
+#if defined(__BIG_ENDIAN)
+       u16 reserved3;
+       u16 flags;
+#define ISCSI_BD_RESERVED1 (0x3F<<0)
+#define ISCSI_BD_RESERVED1_SHIFT 0
+#define ISCSI_BD_LAST_IN_BD_CHAIN (0x1<<6)
+#define ISCSI_BD_LAST_IN_BD_CHAIN_SHIFT 6
+#define ISCSI_BD_FIRST_IN_BD_CHAIN (0x1<<7)
+#define ISCSI_BD_FIRST_IN_BD_CHAIN_SHIFT 7
+#define ISCSI_BD_RESERVED2 (0xFF<<8)
+#define ISCSI_BD_RESERVED2_SHIFT 8
+#elif defined(__LITTLE_ENDIAN)
+       u16 flags;
+#define ISCSI_BD_RESERVED1 (0x3F<<0)
+#define ISCSI_BD_RESERVED1_SHIFT 0
+#define ISCSI_BD_LAST_IN_BD_CHAIN (0x1<<6)
+#define ISCSI_BD_LAST_IN_BD_CHAIN_SHIFT 6
+#define ISCSI_BD_FIRST_IN_BD_CHAIN (0x1<<7)
+#define ISCSI_BD_FIRST_IN_BD_CHAIN_SHIFT 7
+#define ISCSI_BD_RESERVED2 (0xFF<<8)
+#define ISCSI_BD_RESERVED2_SHIFT 8
+       u16 reserved3;
+#endif
+};
+
+
+/*
+ * iSCSI Cleanup SQ WQE
+ */
+struct bnx2i_cleanup_request {
+#if defined(__BIG_ENDIAN)
+       u8 op_code;
+       u8 reserved1;
+       u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+       u16 reserved0;
+       u8 reserved1;
+       u8 op_code;
+#endif
+       u32 reserved2[3];
+#if defined(__BIG_ENDIAN)
+       u16 reserved3;
+       u16 itt;
+#define ISCSI_CLEANUP_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_CLEANUP_REQUEST_INDEX_SHIFT 0
+#define ISCSI_CLEANUP_REQUEST_TYPE (0x3<<14)
+#define ISCSI_CLEANUP_REQUEST_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+       u16 itt;
+#define ISCSI_CLEANUP_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_CLEANUP_REQUEST_INDEX_SHIFT 0
+#define ISCSI_CLEANUP_REQUEST_TYPE (0x3<<14)
+#define ISCSI_CLEANUP_REQUEST_TYPE_SHIFT 14
+       u16 reserved3;
+#endif
+       u32 reserved4[10];
+#if defined(__BIG_ENDIAN)
+       u8 cq_index;
+       u8 reserved6;
+       u16 reserved5;
+#elif defined(__LITTLE_ENDIAN)
+       u16 reserved5;
+       u8 reserved6;
+       u8 cq_index;
+#endif
+};
+
+
+/*
+ * iSCSI Cleanup CQE
+ */
+struct bnx2i_cleanup_response {
+#if defined(__BIG_ENDIAN)
+       u8 op_code;
+       u8 status;
+       u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+       u16 reserved0;
+       u8 status;
+       u8 op_code;
+#endif
+       u32 reserved1[3];
+       u32 reserved2[2];
+#if defined(__BIG_ENDIAN)
+       u16 reserved4;
+       u8 err_code;
+       u8 reserved3;
+#elif defined(__LITTLE_ENDIAN)
+       u8 reserved3;
+       u8 err_code;
+       u16 reserved4;
+#endif
+       u32 reserved5[7];
+#if defined(__BIG_ENDIAN)
+       u16 reserved6;
+       u16 itt;
+#define ISCSI_CLEANUP_RESPONSE_INDEX (0x3FFF<<0)
+#define ISCSI_CLEANUP_RESPONSE_INDEX_SHIFT 0
+#define ISCSI_CLEANUP_RESPONSE_TYPE (0x3<<14)
+#define ISCSI_CLEANUP_RESPONSE_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+       u16 itt;
+#define ISCSI_CLEANUP_RESPONSE_INDEX (0x3FFF<<0)
+#define ISCSI_CLEANUP_RESPONSE_INDEX_SHIFT 0
+#define ISCSI_CLEANUP_RESPONSE_TYPE (0x3<<14)
+#define ISCSI_CLEANUP_RESPONSE_TYPE_SHIFT 14
+       u16 reserved6;
+#endif
+       u32 cq_req_sn;
+};
+
+
+/*
+ * SCSI read/write SQ WQE
+ */
+struct bnx2i_cmd_request {
+#if defined(__BIG_ENDIAN)
+       u8 op_code;
+       u8 op_attr;
+#define ISCSI_CMD_REQUEST_TASK_ATTR (0x7<<0)
+#define ISCSI_CMD_REQUEST_TASK_ATTR_SHIFT 0
+#define ISCSI_CMD_REQUEST_RESERVED1 (0x3<<3)
+#define ISCSI_CMD_REQUEST_RESERVED1_SHIFT 3
+#define ISCSI_CMD_REQUEST_WRITE (0x1<<5)
+#define ISCSI_CMD_REQUEST_WRITE_SHIFT 5
+#define ISCSI_CMD_REQUEST_READ (0x1<<6)
+#define ISCSI_CMD_REQUEST_READ_SHIFT 6
+#define ISCSI_CMD_REQUEST_FINAL (0x1<<7)
+#define ISCSI_CMD_REQUEST_FINAL_SHIFT 7
+       u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+       u16 reserved0;
+       u8 op_attr;
+#define ISCSI_CMD_REQUEST_TASK_ATTR (0x7<<0)
+#define ISCSI_CMD_REQUEST_TASK_ATTR_SHIFT 0
+#define ISCSI_CMD_REQUEST_RESERVED1 (0x3<<3)
+#define ISCSI_CMD_REQUEST_RESERVED1_SHIFT 3
+#define ISCSI_CMD_REQUEST_WRITE (0x1<<5)
+#define ISCSI_CMD_REQUEST_WRITE_SHIFT 5
+#define ISCSI_CMD_REQUEST_READ (0x1<<6)
+#define ISCSI_CMD_REQUEST_READ_SHIFT 6
+#define ISCSI_CMD_REQUEST_FINAL (0x1<<7)
+#define ISCSI_CMD_REQUEST_FINAL_SHIFT 7
+       u8 op_code;
+#endif
+#if defined(__BIG_ENDIAN)
+       u16 ud_buffer_offset;
+       u16 sd_buffer_offset;
+#elif defined(__LITTLE_ENDIAN)
+       u16 sd_buffer_offset;
+       u16 ud_buffer_offset;
+#endif
+       u32 lun[2];
+#if defined(__BIG_ENDIAN)
+       u16 reserved2;
+       u16 itt;
+#define ISCSI_CMD_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_CMD_REQUEST_INDEX_SHIFT 0
+#define ISCSI_CMD_REQUEST_TYPE (0x3<<14)
+#define ISCSI_CMD_REQUEST_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+       u16 itt;
+#define ISCSI_CMD_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_CMD_REQUEST_INDEX_SHIFT 0
+#define ISCSI_CMD_REQUEST_TYPE (0x3<<14)
+#define ISCSI_CMD_REQUEST_TYPE_SHIFT 14
+       u16 reserved2;
+#endif
+       u32 total_data_transfer_length;
+       u32 cmd_sn;
+       u32 reserved3;
+       u32 cdb[4];
+       u32 zero_fill;
+       u32 bd_list_addr_lo;
+       u32 bd_list_addr_hi;
+#if defined(__BIG_ENDIAN)
+       u8 cq_index;
+       u8 sd_start_bd_index;
+       u8 ud_start_bd_index;
+       u8 num_bds;
+#elif defined(__LITTLE_ENDIAN)
+       u8 num_bds;
+       u8 ud_start_bd_index;
+       u8 sd_start_bd_index;
+       u8 cq_index;
+#endif
+};
+
+
+/*
+ * task statistics for write response
+ */
+struct bnx2i_write_resp_task_stat {
+       u32 num_data_ins;
+};
+
+/*
+ * task statistics for read response
+ */
+struct bnx2i_read_resp_task_stat {
+#if defined(__BIG_ENDIAN)
+       u16 num_data_outs;
+       u16 num_r2ts;
+#elif defined(__LITTLE_ENDIAN)
+       u16 num_r2ts;
+       u16 num_data_outs;
+#endif
+};
+
+/*
+ * task statistics for iSCSI cmd response
+ */
+union bnx2i_cmd_resp_task_stat {
+       struct bnx2i_write_resp_task_stat write_stat;
+       struct bnx2i_read_resp_task_stat read_stat;
+};
+
+/*
+ * SCSI Command CQE
+ */
+struct bnx2i_cmd_response {
+#if defined(__BIG_ENDIAN)
+       u8 op_code;
+       u8 response_flags;
+#define ISCSI_CMD_RESPONSE_RESERVED0 (0x1<<0)
+#define ISCSI_CMD_RESPONSE_RESERVED0_SHIFT 0
+#define ISCSI_CMD_RESPONSE_RESIDUAL_UNDERFLOW (0x1<<1)
+#define ISCSI_CMD_RESPONSE_RESIDUAL_UNDERFLOW_SHIFT 1
+#define ISCSI_CMD_RESPONSE_RESIDUAL_OVERFLOW (0x1<<2)
+#define ISCSI_CMD_RESPONSE_RESIDUAL_OVERFLOW_SHIFT 2
+#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_UNDERFLOW (0x1<<3)
+#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_UNDERFLOW_SHIFT 3
+#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_OVERFLOW (0x1<<4)
+#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_OVERFLOW_SHIFT 4
+#define ISCSI_CMD_RESPONSE_RESERVED1 (0x7<<5)
+#define ISCSI_CMD_RESPONSE_RESERVED1_SHIFT 5
+       u8 response;
+       u8 status;
+#elif defined(__LITTLE_ENDIAN)
+       u8 status;
+       u8 response;
+       u8 response_flags;
+#define ISCSI_CMD_RESPONSE_RESERVED0 (0x1<<0)
+#define ISCSI_CMD_RESPONSE_RESERVED0_SHIFT 0
+#define ISCSI_CMD_RESPONSE_RESIDUAL_UNDERFLOW (0x1<<1)
+#define ISCSI_CMD_RESPONSE_RESIDUAL_UNDERFLOW_SHIFT 1
+#define ISCSI_CMD_RESPONSE_RESIDUAL_OVERFLOW (0x1<<2)
+#define ISCSI_CMD_RESPONSE_RESIDUAL_OVERFLOW_SHIFT 2
+#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_UNDERFLOW (0x1<<3)
+#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_UNDERFLOW_SHIFT 3
+#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_OVERFLOW (0x1<<4)
+#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_OVERFLOW_SHIFT 4
+#define ISCSI_CMD_RESPONSE_RESERVED1 (0x7<<5)
+#define ISCSI_CMD_RESPONSE_RESERVED1_SHIFT 5
+       u8 op_code;
+#endif
+       u32 data_length;
+       u32 exp_cmd_sn;
+       u32 max_cmd_sn;
+       u32 reserved2;
+       u32 residual_count;
+#if defined(__BIG_ENDIAN)
+       u16 reserved4;
+       u8 err_code;
+       u8 reserved3;
+#elif defined(__LITTLE_ENDIAN)
+       u8 reserved3;
+       u8 err_code;
+       u16 reserved4;
+#endif
+       u32 reserved5[5];
+       union bnx2i_cmd_resp_task_stat task_stat;
+       u32 reserved6;
+#if defined(__BIG_ENDIAN)
+       u16 reserved7;
+       u16 itt;
+#define ISCSI_CMD_RESPONSE_INDEX (0x3FFF<<0)
+#define ISCSI_CMD_RESPONSE_INDEX_SHIFT 0
+#define ISCSI_CMD_RESPONSE_TYPE (0x3<<14)
+#define ISCSI_CMD_RESPONSE_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+       u16 itt;
+#define ISCSI_CMD_RESPONSE_INDEX (0x3FFF<<0)
+#define ISCSI_CMD_RESPONSE_INDEX_SHIFT 0
+#define ISCSI_CMD_RESPONSE_TYPE (0x3<<14)
+#define ISCSI_CMD_RESPONSE_TYPE_SHIFT 14
+       u16 reserved7;
+#endif
+       u32 cq_req_sn;
+};
+
+
+
+/*
+ * firmware middle-path request SQ WQE
+ */
+struct bnx2i_fw_mp_request {
+#if defined(__BIG_ENDIAN)
+       u8 op_code;
+       u8 op_attr;
+       u16 hdr_opaque1;
+#elif defined(__LITTLE_ENDIAN)
+       u16 hdr_opaque1;
+       u8 op_attr;
+       u8 op_code;
+#endif
+       u32 data_length;
+       u32 hdr_opaque2[2];
+#if defined(__BIG_ENDIAN)
+       u16 reserved0;
+       u16 itt;
+#define ISCSI_FW_MP_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_FW_MP_REQUEST_INDEX_SHIFT 0
+#define ISCSI_FW_MP_REQUEST_TYPE (0x3<<14)
+#define ISCSI_FW_MP_REQUEST_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+       u16 itt;
+#define ISCSI_FW_MP_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_FW_MP_REQUEST_INDEX_SHIFT 0
+#define ISCSI_FW_MP_REQUEST_TYPE (0x3<<14)
+#define ISCSI_FW_MP_REQUEST_TYPE_SHIFT 14
+       u16 reserved0;
+#endif
+       u32 hdr_opaque3[4];
+       u32 resp_bd_list_addr_lo;
+       u32 resp_bd_list_addr_hi;
+       u32 resp_buffer;
+#define ISCSI_FW_MP_REQUEST_RESP_BUFFER_LENGTH (0xFFFFFF<<0)
+#define ISCSI_FW_MP_REQUEST_RESP_BUFFER_LENGTH_SHIFT 0
+#define ISCSI_FW_MP_REQUEST_NUM_RESP_BDS (0xFF<<24)
+#define ISCSI_FW_MP_REQUEST_NUM_RESP_BDS_SHIFT 24
+#if defined(__BIG_ENDIAN)
+       u16 reserved4;
+       u8 reserved3;
+       u8 flags;
+#define ISCSI_FW_MP_REQUEST_RESERVED1 (0x1<<0)
+#define ISCSI_FW_MP_REQUEST_RESERVED1_SHIFT 0
+#define ISCSI_FW_MP_REQUEST_LOCAL_COMPLETION (0x1<<1)
+#define ISCSI_FW_MP_REQUEST_LOCAL_COMPLETION_SHIFT 1
+#define ISCSI_FW_MP_REQUEST_UPDATE_EXP_STAT_SN (0x1<<2)
+#define ISCSI_FW_MP_REQUEST_UPDATE_EXP_STAT_SN_SHIFT 2
+#define ISCSI_FW_MP_REQUEST_RESERVED2 (0x1F<<3)
+#define ISCSI_FW_MP_REQUEST_RESERVED2_SHIFT 3
+#elif defined(__LITTLE_ENDIAN)
+       u8 flags;
+#define ISCSI_FW_MP_REQUEST_RESERVED1 (0x1<<0)
+#define ISCSI_FW_MP_REQUEST_RESERVED1_SHIFT 0
+#define ISCSI_FW_MP_REQUEST_LOCAL_COMPLETION (0x1<<1)
+#define ISCSI_FW_MP_REQUEST_LOCAL_COMPLETION_SHIFT 1
+#define ISCSI_FW_MP_REQUEST_UPDATE_EXP_STAT_SN (0x1<<2)
+#define ISCSI_FW_MP_REQUEST_UPDATE_EXP_STAT_SN_SHIFT 2
+#define ISCSI_FW_MP_REQUEST_RESERVED2 (0x1F<<3)
+#define ISCSI_FW_MP_REQUEST_RESERVED2_SHIFT 3
+       u8 reserved3;
+       u16 reserved4;
+#endif
+       u32 bd_list_addr_lo;
+       u32 bd_list_addr_hi;
+#if defined(__BIG_ENDIAN)
+       u8 cq_index;
+       u8 reserved6;
+       u8 reserved5;
+       u8 num_bds;
+#elif defined(__LITTLE_ENDIAN)
+       u8 num_bds;
+       u8 reserved5;
+       u8 reserved6;
+       u8 cq_index;
+#endif
+};
+
+
+/*
+ * firmware response - CQE: used only by firmware
+ */
+struct bnx2i_fw_response {
+       u32 hdr_dword1[2];
+       u32 hdr_exp_cmd_sn;
+       u32 hdr_max_cmd_sn;
+       u32 hdr_ttt;
+       u32 hdr_res_cnt;
+       u32 cqe_flags;
+#define ISCSI_FW_RESPONSE_RESERVED2 (0xFF<<0)
+#define ISCSI_FW_RESPONSE_RESERVED2_SHIFT 0
+#define ISCSI_FW_RESPONSE_ERR_CODE (0xFF<<8)
+#define ISCSI_FW_RESPONSE_ERR_CODE_SHIFT 8
+#define ISCSI_FW_RESPONSE_RESERVED3 (0xFFFF<<16)
+#define ISCSI_FW_RESPONSE_RESERVED3_SHIFT 16
+       u32 stat_sn;
+       u32 hdr_dword2[2];
+       u32 hdr_dword3[2];
+       u32 task_stat;
+       u32 reserved0;
+       u32 hdr_itt;
+       u32 cq_req_sn;
+};
+
+
+/*
+ * iSCSI KCQ CQE parameters
+ */
+union iscsi_kcqe_params {
+       u32 reserved0[4];
+};
+
+/*
+ * iSCSI KCQ CQE
+ */
+struct iscsi_kcqe {
+       u32 iscsi_conn_id;
+       u32 completion_status;
+       u32 iscsi_conn_context_id;
+       union iscsi_kcqe_params params;
+#if defined(__BIG_ENDIAN)
+       u8 flags;
+#define ISCSI_KCQE_RESERVED0 (0xF<<0)
+#define ISCSI_KCQE_RESERVED0_SHIFT 0
+#define ISCSI_KCQE_LAYER_CODE (0x7<<4)
+#define ISCSI_KCQE_LAYER_CODE_SHIFT 4
+#define ISCSI_KCQE_RESERVED1 (0x1<<7)
+#define ISCSI_KCQE_RESERVED1_SHIFT 7
+       u8 op_code;
+       u16 qe_self_seq;
+#elif defined(__LITTLE_ENDIAN)
+       u16 qe_self_seq;
+       u8 op_code;
+       u8 flags;
+#define ISCSI_KCQE_RESERVED0 (0xF<<0)
+#define ISCSI_KCQE_RESERVED0_SHIFT 0
+#define ISCSI_KCQE_LAYER_CODE (0x7<<4)
+#define ISCSI_KCQE_LAYER_CODE_SHIFT 4
+#define ISCSI_KCQE_RESERVED1 (0x1<<7)
+#define ISCSI_KCQE_RESERVED1_SHIFT 7
+#endif
+};
+
+
+
+/*
+ * iSCSI KWQE header
+ */
+struct iscsi_kwqe_header {
+#if defined(__BIG_ENDIAN)
+       u8 flags;
+#define ISCSI_KWQE_HEADER_RESERVED0 (0xF<<0)
+#define ISCSI_KWQE_HEADER_RESERVED0_SHIFT 0
+#define ISCSI_KWQE_HEADER_LAYER_CODE (0x7<<4)
+#define ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT 4
+#define ISCSI_KWQE_HEADER_RESERVED1 (0x1<<7)
+#define ISCSI_KWQE_HEADER_RESERVED1_SHIFT 7
+       u8 op_code;
+#elif defined(__LITTLE_ENDIAN)
+       u8 op_code;
+       u8 flags;
+#define ISCSI_KWQE_HEADER_RESERVED0 (0xF<<0)
+#define ISCSI_KWQE_HEADER_RESERVED0_SHIFT 0
+#define ISCSI_KWQE_HEADER_LAYER_CODE (0x7<<4)
+#define ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT 4
+#define ISCSI_KWQE_HEADER_RESERVED1 (0x1<<7)
+#define ISCSI_KWQE_HEADER_RESERVED1_SHIFT 7
+#endif
+};
+
+/*
+ * iSCSI firmware init request 1
+ */
+struct iscsi_kwqe_init1 {
+#if defined(__BIG_ENDIAN)
+       struct iscsi_kwqe_header hdr;
+       u8 reserved0;
+       u8 num_cqs;
+#elif defined(__LITTLE_ENDIAN)
+       u8 num_cqs;
+       u8 reserved0;
+       struct iscsi_kwqe_header hdr;
+#endif
+       u32 dummy_buffer_addr_lo;
+       u32 dummy_buffer_addr_hi;
+#if defined(__BIG_ENDIAN)
+       u16 num_ccells_per_conn;
+       u16 num_tasks_per_conn;
+#elif defined(__LITTLE_ENDIAN)
+       u16 num_tasks_per_conn;
+       u16 num_ccells_per_conn;
+#endif
+#if defined(__BIG_ENDIAN)
+       u16 sq_wqes_per_page;
+       u16 sq_num_wqes;
+#elif defined(__LITTLE_ENDIAN)
+       u16 sq_num_wqes;
+       u16 sq_wqes_per_page;
+#endif
+#if defined(__BIG_ENDIAN)
+       u8 cq_log_wqes_per_page;
+       u8 flags;
+#define ISCSI_KWQE_INIT1_PAGE_SIZE (0xF<<0)
+#define ISCSI_KWQE_INIT1_PAGE_SIZE_SHIFT 0
+#define ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE (0x1<<4)
+#define ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE_SHIFT 4
+#define ISCSI_KWQE_INIT1_KEEP_ALIVE_ENABLE (0x1<<5)
+#define ISCSI_KWQE_INIT1_KEEP_ALIVE_ENABLE_SHIFT 5
+#define ISCSI_KWQE_INIT1_RESERVED1 (0x3<<6)
+#define ISCSI_KWQE_INIT1_RESERVED1_SHIFT 6
+       u16 cq_num_wqes;
+#elif defined(__LITTLE_ENDIAN)
+       u16 cq_num_wqes;
+       u8 flags;
+#define ISCSI_KWQE_INIT1_PAGE_SIZE (0xF<<0)
+#define ISCSI_KWQE_INIT1_PAGE_SIZE_SHIFT 0
+#define ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE (0x1<<4)
+#define ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE_SHIFT 4
+#define ISCSI_KWQE_INIT1_KEEP_ALIVE_ENABLE (0x1<<5)
+#define ISCSI_KWQE_INIT1_KEEP_ALIVE_ENABLE_SHIFT 5
+#define ISCSI_KWQE_INIT1_RESERVED1 (0x3<<6)
+#define ISCSI_KWQE_INIT1_RESERVED1_SHIFT 6
+       u8 cq_log_wqes_per_page;
+#endif
+#if defined(__BIG_ENDIAN)
+       u16 cq_num_pages;
+       u16 sq_num_pages;
+#elif defined(__LITTLE_ENDIAN)
+       u16 sq_num_pages;
+       u16 cq_num_pages;
+#endif
+#if defined(__BIG_ENDIAN)
+       u16 rq_buffer_size;
+       u16 rq_num_wqes;
+#elif defined(__LITTLE_ENDIAN)
+       u16 rq_num_wqes;
+       u16 rq_buffer_size;
+#endif
+};
+
+/*
+ * iSCSI firmware init request 2
+ */
+struct iscsi_kwqe_init2 {
+#if defined(__BIG_ENDIAN)
+       struct iscsi_kwqe_header hdr;
+       u16 max_cq_sqn;
+#elif defined(__LITTLE_ENDIAN)
+       u16 max_cq_sqn;
+       struct iscsi_kwqe_header hdr;
+#endif
+       u32 error_bit_map[2];
+       u32 reserved1[5];
+};
+
+/*
+ * Initial iSCSI connection offload request 1
+ */
+struct iscsi_kwqe_conn_offload1 {
+#if defined(__BIG_ENDIAN)
+       struct iscsi_kwqe_header hdr;
+       u16 iscsi_conn_id;
+#elif defined(__LITTLE_ENDIAN)
+       u16 iscsi_conn_id;
+       struct iscsi_kwqe_header hdr;
+#endif
+       u32 sq_page_table_addr_lo;
+       u32 sq_page_table_addr_hi;
+       u32 cq_page_table_addr_lo;
+       u32 cq_page_table_addr_hi;
+       u32 reserved0[3];
+};
+
+/*
+ * iSCSI Page Table Entry (PTE)
+ */
+struct iscsi_pte {
+       u32 hi;
+       u32 lo;
+};
+
+/*
+ * Initial iSCSI connection offload request 2
+ */
+struct iscsi_kwqe_conn_offload2 {
+#if defined(__BIG_ENDIAN)
+       struct iscsi_kwqe_header hdr;
+       u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+       u16 reserved0;
+       struct iscsi_kwqe_header hdr;
+#endif
+       u32 rq_page_table_addr_lo;
+       u32 rq_page_table_addr_hi;
+       struct iscsi_pte sq_first_pte;
+       struct iscsi_pte cq_first_pte;
+       u32 num_additional_wqes;
+};
+
+
+/*
+ * Initial iSCSI connection offload request 3
+ */
+struct iscsi_kwqe_conn_offload3 {
+#if defined(__BIG_ENDIAN)
+       struct iscsi_kwqe_header hdr;
+       u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+       u16 reserved0;
+       struct iscsi_kwqe_header hdr;
+#endif
+       u32 reserved1;
+       struct iscsi_pte qp_first_pte[3];
+};
+
+
+/*
+ * iSCSI connection update request
+ */
+struct iscsi_kwqe_conn_update {
+#if defined(__BIG_ENDIAN)
+       struct iscsi_kwqe_header hdr;
+       u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+       u16 reserved0;
+       struct iscsi_kwqe_header hdr;
+#endif
+#if defined(__BIG_ENDIAN)
+       u8 session_error_recovery_level;
+       u8 max_outstanding_r2ts;
+       u8 reserved2;
+       u8 conn_flags;
+#define ISCSI_KWQE_CONN_UPDATE_HEADER_DIGEST (0x1<<0)
+#define ISCSI_KWQE_CONN_UPDATE_HEADER_DIGEST_SHIFT 0
+#define ISCSI_KWQE_CONN_UPDATE_DATA_DIGEST (0x1<<1)
+#define ISCSI_KWQE_CONN_UPDATE_DATA_DIGEST_SHIFT 1
+#define ISCSI_KWQE_CONN_UPDATE_INITIAL_R2T (0x1<<2)
+#define ISCSI_KWQE_CONN_UPDATE_INITIAL_R2T_SHIFT 2
+#define ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA (0x1<<3)
+#define ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA_SHIFT 3
+#define ISCSI_KWQE_CONN_UPDATE_RESERVED1 (0xF<<4)
+#define ISCSI_KWQE_CONN_UPDATE_RESERVED1_SHIFT 4
+#elif defined(__LITTLE_ENDIAN)
+       u8 conn_flags;
+#define ISCSI_KWQE_CONN_UPDATE_HEADER_DIGEST (0x1<<0)
+#define ISCSI_KWQE_CONN_UPDATE_HEADER_DIGEST_SHIFT 0
+#define ISCSI_KWQE_CONN_UPDATE_DATA_DIGEST (0x1<<1)
+#define ISCSI_KWQE_CONN_UPDATE_DATA_DIGEST_SHIFT 1
+#define ISCSI_KWQE_CONN_UPDATE_INITIAL_R2T (0x1<<2)
+#define ISCSI_KWQE_CONN_UPDATE_INITIAL_R2T_SHIFT 2
+#define ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA (0x1<<3)
+#define ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA_SHIFT 3
+#define ISCSI_KWQE_CONN_UPDATE_RESERVED1 (0xF<<4)
+#define ISCSI_KWQE_CONN_UPDATE_RESERVED1_SHIFT 4
+       u8 reserved2;
+       u8 max_outstanding_r2ts;
+       u8 session_error_recovery_level;
+#endif
+       u32 context_id;
+       u32 max_send_pdu_length;
+       u32 max_recv_pdu_length;
+       u32 first_burst_length;
+       u32 max_burst_length;
+       u32 exp_stat_sn;
+};
+
+/*
+ * iSCSI destroy connection request
+ */
+struct iscsi_kwqe_conn_destroy {
+#if defined(__BIG_ENDIAN)
+       struct iscsi_kwqe_header hdr;
+       u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+       u16 reserved0;
+       struct iscsi_kwqe_header hdr;
+#endif
+       u32 context_id;
+       u32 reserved1[6];
+};
+
+/*
+ * iSCSI KWQ WQE
+ */
+union iscsi_kwqe {
+       struct iscsi_kwqe_init1 init1;
+       struct iscsi_kwqe_init2 init2;
+       struct iscsi_kwqe_conn_offload1 conn_offload1;
+       struct iscsi_kwqe_conn_offload2 conn_offload2;
+       struct iscsi_kwqe_conn_update conn_update;
+       struct iscsi_kwqe_conn_destroy conn_destroy;
+};
+
+/*
+ * iSCSI Login SQ WQE
+ */
+struct bnx2i_login_request {
+#if defined(__BIG_ENDIAN)
+       u8 op_code;
+       u8 op_attr;
+#define ISCSI_LOGIN_REQUEST_NEXT_STAGE (0x3<<0)
+#define ISCSI_LOGIN_REQUEST_NEXT_STAGE_SHIFT 0
+#define ISCSI_LOGIN_REQUEST_CURRENT_STAGE (0x3<<2)
+#define ISCSI_LOGIN_REQUEST_CURRENT_STAGE_SHIFT 2
+#define ISCSI_LOGIN_REQUEST_RESERVED0 (0x3<<4)
+#define ISCSI_LOGIN_REQUEST_RESERVED0_SHIFT 4
+#define ISCSI_LOGIN_REQUEST_CONT (0x1<<6)
+#define ISCSI_LOGIN_REQUEST_CONT_SHIFT 6
+#define ISCSI_LOGIN_REQUEST_TRANSIT (0x1<<7)
+#define ISCSI_LOGIN_REQUEST_TRANSIT_SHIFT 7
+       u8 version_max;
+       u8 version_min;
+#elif defined(__LITTLE_ENDIAN)
+       u8 version_min;
+       u8 version_max;
+       u8 op_attr;
+#define ISCSI_LOGIN_REQUEST_NEXT_STAGE (0x3<<0)
+#define ISCSI_LOGIN_REQUEST_NEXT_STAGE_SHIFT 0
+#define ISCSI_LOGIN_REQUEST_CURRENT_STAGE (0x3<<2)
+#define ISCSI_LOGIN_REQUEST_CURRENT_STAGE_SHIFT 2
+#define ISCSI_LOGIN_REQUEST_RESERVED0 (0x3<<4)
+#define ISCSI_LOGIN_REQUEST_RESERVED0_SHIFT 4
+#define ISCSI_LOGIN_REQUEST_CONT (0x1<<6)
+#define ISCSI_LOGIN_REQUEST_CONT_SHIFT 6
+#define ISCSI_LOGIN_REQUEST_TRANSIT (0x1<<7)
+#define ISCSI_LOGIN_REQUEST_TRANSIT_SHIFT 7
+       u8 op_code;
+#endif
+       u32 data_length;
+       u32 isid_lo;
+#if defined(__BIG_ENDIAN)
+       u16 isid_hi;
+       u16 tsih;
+#elif defined(__LITTLE_ENDIAN)
+       u16 tsih;
+       u16 isid_hi;
+#endif
+#if defined(__BIG_ENDIAN)
+       u16 reserved2;
+       u16 itt;
+#define ISCSI_LOGIN_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_LOGIN_REQUEST_INDEX_SHIFT 0
+#define ISCSI_LOGIN_REQUEST_TYPE (0x3<<14)
+#define ISCSI_LOGIN_REQUEST_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+       u16 itt;
+#define ISCSI_LOGIN_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_LOGIN_REQUEST_INDEX_SHIFT 0
+#define ISCSI_LOGIN_REQUEST_TYPE (0x3<<14)
+#define ISCSI_LOGIN_REQUEST_TYPE_SHIFT 14
+       u16 reserved2;
+#endif
+#if defined(__BIG_ENDIAN)
+       u16 cid;
+       u16 reserved3;
+#elif defined(__LITTLE_ENDIAN)
+       u16 reserved3;
+       u16 cid;
+#endif
+       u32 cmd_sn;
+       u32 exp_stat_sn;
+       u32 reserved4;
+       u32 resp_bd_list_addr_lo;
+       u32 resp_bd_list_addr_hi;
+       u32 resp_buffer;
+#define ISCSI_LOGIN_REQUEST_RESP_BUFFER_LENGTH (0xFFFFFF<<0)
+#define ISCSI_LOGIN_REQUEST_RESP_BUFFER_LENGTH_SHIFT 0
+#define ISCSI_LOGIN_REQUEST_NUM_RESP_BDS (0xFF<<24)
+#define ISCSI_LOGIN_REQUEST_NUM_RESP_BDS_SHIFT 24
+#if defined(__BIG_ENDIAN)
+       u16 reserved8;
+       u8 reserved7;
+       u8 flags;
+#define ISCSI_LOGIN_REQUEST_RESERVED5 (0x3<<0)
+#define ISCSI_LOGIN_REQUEST_RESERVED5_SHIFT 0
+#define ISCSI_LOGIN_REQUEST_UPDATE_EXP_STAT_SN (0x1<<2)
+#define ISCSI_LOGIN_REQUEST_UPDATE_EXP_STAT_SN_SHIFT 2
+#define ISCSI_LOGIN_REQUEST_RESERVED6 (0x1F<<3)
+#define ISCSI_LOGIN_REQUEST_RESERVED6_SHIFT 3
+#elif defined(__LITTLE_ENDIAN)
+       u8 flags;
+#define ISCSI_LOGIN_REQUEST_RESERVED5 (0x3<<0)
+#define ISCSI_LOGIN_REQUEST_RESERVED5_SHIFT 0
+#define ISCSI_LOGIN_REQUEST_UPDATE_EXP_STAT_SN (0x1<<2)
+#define ISCSI_LOGIN_REQUEST_UPDATE_EXP_STAT_SN_SHIFT 2
+#define ISCSI_LOGIN_REQUEST_RESERVED6 (0x1F<<3)
+#define ISCSI_LOGIN_REQUEST_RESERVED6_SHIFT 3
+       u8 reserved7;
+       u16 reserved8;
+#endif
+       u32 bd_list_addr_lo;
+       u32 bd_list_addr_hi;
+#if defined(__BIG_ENDIAN)
+       u8 cq_index;
+       u8 reserved10;
+       u8 reserved9;
+       u8 num_bds;
+#elif defined(__LITTLE_ENDIAN)
+       u8 num_bds;
+       u8 reserved9;
+       u8 reserved10;
+       u8 cq_index;
+#endif
+};
+
+
+/*
+ * iSCSI Login CQE
+ */
+struct bnx2i_login_response {
+#if defined(__BIG_ENDIAN)
+       u8 op_code;
+       u8 response_flags;
+#define ISCSI_LOGIN_RESPONSE_NEXT_STAGE (0x3<<0)
+#define ISCSI_LOGIN_RESPONSE_NEXT_STAGE_SHIFT 0
+#define ISCSI_LOGIN_RESPONSE_CURRENT_STAGE (0x3<<2)
+#define ISCSI_LOGIN_RESPONSE_CURRENT_STAGE_SHIFT 2
+#define ISCSI_LOGIN_RESPONSE_RESERVED0 (0x3<<4)
+#define ISCSI_LOGIN_RESPONSE_RESERVED0_SHIFT 4
+#define ISCSI_LOGIN_RESPONSE_CONT (0x1<<6)
+#define ISCSI_LOGIN_RESPONSE_CONT_SHIFT 6
+#define ISCSI_LOGIN_RESPONSE_TRANSIT (0x1<<7)
+#define ISCSI_LOGIN_RESPONSE_TRANSIT_SHIFT 7
+       u8 version_max;
+       u8 version_active;
+#elif defined(__LITTLE_ENDIAN)
+       u8 version_active;
+       u8 version_max;
+       u8 response_flags;
+#define ISCSI_LOGIN_RESPONSE_NEXT_STAGE (0x3<<0)
+#define ISCSI_LOGIN_RESPONSE_NEXT_STAGE_SHIFT 0
+#define ISCSI_LOGIN_RESPONSE_CURRENT_STAGE (0x3<<2)
+#define ISCSI_LOGIN_RESPONSE_CURRENT_STAGE_SHIFT 2
+#define ISCSI_LOGIN_RESPONSE_RESERVED0 (0x3<<4)
+#define ISCSI_LOGIN_RESPONSE_RESERVED0_SHIFT 4
+#define ISCSI_LOGIN_RESPONSE_CONT (0x1<<6)
+#define ISCSI_LOGIN_RESPONSE_CONT_SHIFT 6
+#define ISCSI_LOGIN_RESPONSE_TRANSIT (0x1<<7)
+#define ISCSI_LOGIN_RESPONSE_TRANSIT_SHIFT 7
+       u8 op_code;
+#endif
+       u32 data_length;
+       u32 exp_cmd_sn;
+       u32 max_cmd_sn;
+       u32 reserved1[2];
+#if defined(__BIG_ENDIAN)
+       u16 reserved3;
+       u8 err_code;
+       u8 reserved2;
+#elif defined(__LITTLE_ENDIAN)
+       u8 reserved2;
+       u8 err_code;
+       u16 reserved3;
+#endif
+       u32 stat_sn;
+       u32 isid_lo;
+#if defined(__BIG_ENDIAN)
+       u16 isid_hi;
+       u16 tsih;
+#elif defined(__LITTLE_ENDIAN)
+       u16 tsih;
+       u16 isid_hi;
+#endif
+#if defined(__BIG_ENDIAN)
+       u8 status_class;
+       u8 status_detail;
+       u16 reserved4;
+#elif defined(__LITTLE_ENDIAN)
+       u16 reserved4;
+       u8 status_detail;
+       u8 status_class;
+#endif
+       u32 reserved5[3];
+#if defined(__BIG_ENDIAN)
+       u16 reserved6;
+       u16 itt;
+#define ISCSI_LOGIN_RESPONSE_INDEX (0x3FFF<<0)
+#define ISCSI_LOGIN_RESPONSE_INDEX_SHIFT 0
+#define ISCSI_LOGIN_RESPONSE_TYPE (0x3<<14)
+#define ISCSI_LOGIN_RESPONSE_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+       u16 itt;
+#define ISCSI_LOGIN_RESPONSE_INDEX (0x3FFF<<0)
+#define ISCSI_LOGIN_RESPONSE_INDEX_SHIFT 0
+#define ISCSI_LOGIN_RESPONSE_TYPE (0x3<<14)
+#define ISCSI_LOGIN_RESPONSE_TYPE_SHIFT 14
+       u16 reserved6;
+#endif
+       u32 cq_req_sn;
+};
+
+
+/*
+ * iSCSI Logout SQ WQE
+ */
+struct bnx2i_logout_request {
+#if defined(__BIG_ENDIAN)
+       u8 op_code;
+       u8 op_attr;
+#define ISCSI_LOGOUT_REQUEST_REASON (0x7F<<0)
+#define ISCSI_LOGOUT_REQUEST_REASON_SHIFT 0
+#define ISCSI_LOGOUT_REQUEST_ALWAYS_ONE (0x1<<7)
+#define ISCSI_LOGOUT_REQUEST_ALWAYS_ONE_SHIFT 7
+       u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+       u16 reserved0;
+       u8 op_attr;
+#define ISCSI_LOGOUT_REQUEST_REASON (0x7F<<0)
+#define ISCSI_LOGOUT_REQUEST_REASON_SHIFT 0
+#define ISCSI_LOGOUT_REQUEST_ALWAYS_ONE (0x1<<7)
+#define ISCSI_LOGOUT_REQUEST_ALWAYS_ONE_SHIFT 7
+       u8 op_code;
+#endif
+       u32 data_length;
+       u32 reserved1[2];
+#if defined(__BIG_ENDIAN)
+       u16 reserved2;
+       u16 itt;
+#define ISCSI_LOGOUT_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_LOGOUT_REQUEST_INDEX_SHIFT 0
+#define ISCSI_LOGOUT_REQUEST_TYPE (0x3<<14)
+#define ISCSI_LOGOUT_REQUEST_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+       u16 itt;
+#define ISCSI_LOGOUT_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_LOGOUT_REQUEST_INDEX_SHIFT 0
+#define ISCSI_LOGOUT_REQUEST_TYPE (0x3<<14)
+#define ISCSI_LOGOUT_REQUEST_TYPE_SHIFT 14
+       u16 reserved2;
+#endif
+#if defined(__BIG_ENDIAN)
+       u16 cid;
+       u16 reserved3;
+#elif defined(__LITTLE_ENDIAN)
+       u16 reserved3;
+       u16 cid;
+#endif
+       u32 cmd_sn;
+       u32 reserved4[5];
+       u32 zero_fill;
+       u32 bd_list_addr_lo;
+       u32 bd_list_addr_hi;
+#if defined(__BIG_ENDIAN)
+       u8 cq_index;
+       u8 reserved6;
+       u8 reserved5;
+       u8 num_bds;
+#elif defined(__LITTLE_ENDIAN)
+       u8 num_bds;
+       u8 reserved5;
+       u8 reserved6;
+       u8 cq_index;
+#endif
+};
+
+
+/*
+ * iSCSI Logout CQE
+ */
+struct bnx2i_logout_response {
+#if defined(__BIG_ENDIAN)
+       u8 op_code;
+       u8 reserved1;
+       u8 response;
+       u8 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+       u8 reserved0;
+       u8 response;
+       u8 reserved1;
+       u8 op_code;
+#endif
+       u32 reserved2;
+       u32 exp_cmd_sn;
+       u32 max_cmd_sn;
+       u32 reserved3[2];
+#if defined(__BIG_ENDIAN)
+       u16 reserved5;
+       u8 err_code;
+       u8 reserved4;
+#elif defined(__LITTLE_ENDIAN)
+       u8 reserved4;
+       u8 err_code;
+       u16 reserved5;
+#endif
+       u32 reserved6[3];
+#if defined(__BIG_ENDIAN)
+       u16 time_to_wait;
+       u16 time_to_retain;
+#elif defined(__LITTLE_ENDIAN)
+       u16 time_to_retain;
+       u16 time_to_wait;
+#endif
+       u32 reserved7[3];
+#if defined(__BIG_ENDIAN)
+       u16 reserved8;
+       u16 itt;
+#define ISCSI_LOGOUT_RESPONSE_INDEX (0x3FFF<<0)
+#define ISCSI_LOGOUT_RESPONSE_INDEX_SHIFT 0
+#define ISCSI_LOGOUT_RESPONSE_TYPE (0x3<<14)
+#define ISCSI_LOGOUT_RESPONSE_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+       u16 itt;
+#define ISCSI_LOGOUT_RESPONSE_INDEX (0x3FFF<<0)
+#define ISCSI_LOGOUT_RESPONSE_INDEX_SHIFT 0
+#define ISCSI_LOGOUT_RESPONSE_TYPE (0x3<<14)
+#define ISCSI_LOGOUT_RESPONSE_TYPE_SHIFT 14
+       u16 reserved8;
+#endif
+       u32 cq_req_sn;
+};
+
+
+/*
+ * iSCSI Nop-In CQE
+ */
+struct bnx2i_nop_in_msg {
+#if defined(__BIG_ENDIAN)
+       u8 op_code;
+       u8 reserved1;
+       u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+       u16 reserved0;
+       u8 reserved1;
+       u8 op_code;
+#endif
+       u32 data_length;
+       u32 exp_cmd_sn;
+       u32 max_cmd_sn;
+       u32 ttt;
+       u32 reserved2;
+#if defined(__BIG_ENDIAN)
+       u16 reserved4;
+       u8 err_code;
+       u8 reserved3;
+#elif defined(__LITTLE_ENDIAN)
+       u8 reserved3;
+       u8 err_code;
+       u16 reserved4;
+#endif
+       u32 reserved5;
+       u32 lun[2];
+       u32 reserved6[4];
+#if defined(__BIG_ENDIAN)
+       u16 reserved7;
+       u16 itt;
+#define ISCSI_NOP_IN_MSG_INDEX (0x3FFF<<0)
+#define ISCSI_NOP_IN_MSG_INDEX_SHIFT 0
+#define ISCSI_NOP_IN_MSG_TYPE (0x3<<14)
+#define ISCSI_NOP_IN_MSG_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+       u16 itt;
+#define ISCSI_NOP_IN_MSG_INDEX (0x3FFF<<0)
+#define ISCSI_NOP_IN_MSG_INDEX_SHIFT 0
+#define ISCSI_NOP_IN_MSG_TYPE (0x3<<14)
+#define ISCSI_NOP_IN_MSG_TYPE_SHIFT 14
+       u16 reserved7;
+#endif
+       u32 cq_req_sn;
+};
+
+
+/*
+ * iSCSI NOP-OUT SQ WQE
+ */
+struct bnx2i_nop_out_request {
+#if defined(__BIG_ENDIAN)
+       u8 op_code;
+       u8 op_attr;
+#define ISCSI_NOP_OUT_REQUEST_RESERVED1 (0x7F<<0)
+#define ISCSI_NOP_OUT_REQUEST_RESERVED1_SHIFT 0
+#define ISCSI_NOP_OUT_REQUEST_ALWAYS_ONE (0x1<<7)
+#define ISCSI_NOP_OUT_REQUEST_ALWAYS_ONE_SHIFT 7
+       u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+       u16 reserved0;
+       u8 op_attr;
+#define ISCSI_NOP_OUT_REQUEST_RESERVED1 (0x7F<<0)
+#define ISCSI_NOP_OUT_REQUEST_RESERVED1_SHIFT 0
+#define ISCSI_NOP_OUT_REQUEST_ALWAYS_ONE (0x1<<7)
+#define ISCSI_NOP_OUT_REQUEST_ALWAYS_ONE_SHIFT 7
+       u8 op_code;
+#endif
+       u32 data_length;
+       u32 lun[2];
+#if defined(__BIG_ENDIAN)
+       u16 reserved2;
+       u16 itt;
+#define ISCSI_NOP_OUT_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_NOP_OUT_REQUEST_INDEX_SHIFT 0
+#define ISCSI_NOP_OUT_REQUEST_TYPE (0x3<<14)
+#define ISCSI_NOP_OUT_REQUEST_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+       u16 itt;
+#define ISCSI_NOP_OUT_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_NOP_OUT_REQUEST_INDEX_SHIFT 0
+#define ISCSI_NOP_OUT_REQUEST_TYPE (0x3<<14)
+#define ISCSI_NOP_OUT_REQUEST_TYPE_SHIFT 14
+       u16 reserved2;
+#endif
+       u32 ttt;
+       u32 cmd_sn;
+       u32 reserved3[2];
+       u32 resp_bd_list_addr_lo;
+       u32 resp_bd_list_addr_hi;
+       u32 resp_buffer;
+#define ISCSI_NOP_OUT_REQUEST_RESP_BUFFER_LENGTH (0xFFFFFF<<0)
+#define ISCSI_NOP_OUT_REQUEST_RESP_BUFFER_LENGTH_SHIFT 0
+#define ISCSI_NOP_OUT_REQUEST_NUM_RESP_BDS (0xFF<<24)
+#define ISCSI_NOP_OUT_REQUEST_NUM_RESP_BDS_SHIFT 24
+#if defined(__BIG_ENDIAN)
+       u16 reserved7;
+       u8 reserved6;
+       u8 flags;
+#define ISCSI_NOP_OUT_REQUEST_RESERVED4 (0x1<<0)
+#define ISCSI_NOP_OUT_REQUEST_RESERVED4_SHIFT 0
+#define ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION (0x1<<1)
+#define ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION_SHIFT 1
+#define ISCSI_NOP_OUT_REQUEST_ZERO_FILL (0x3F<<2)
+#define ISCSI_NOP_OUT_REQUEST_ZERO_FILL_SHIFT 2
+#elif defined(__LITTLE_ENDIAN)
+       u8 flags;
+#define ISCSI_NOP_OUT_REQUEST_RESERVED4 (0x1<<0)
+#define ISCSI_NOP_OUT_REQUEST_RESERVED4_SHIFT 0
+#define ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION (0x1<<1)
+#define ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION_SHIFT 1
+#define ISCSI_NOP_OUT_REQUEST_ZERO_FILL (0x3F<<2)
+#define ISCSI_NOP_OUT_REQUEST_ZERO_FILL_SHIFT 2
+       u8 reserved6;
+       u16 reserved7;
+#endif
+       u32 bd_list_addr_lo;
+       u32 bd_list_addr_hi;
+#if defined(__BIG_ENDIAN)
+       u8 cq_index;
+       u8 reserved9;
+       u8 reserved8;
+       u8 num_bds;
+#elif defined(__LITTLE_ENDIAN)
+       u8 num_bds;
+       u8 reserved8;
+       u8 reserved9;
+       u8 cq_index;
+#endif
+};
+
+/*
+ * iSCSI Reject CQE
+ */
+struct bnx2i_reject_msg {
+#if defined(__BIG_ENDIAN)
+       u8 op_code;
+       u8 reserved1;
+       u8 reason;
+       u8 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+       u8 reserved0;
+       u8 reason;
+       u8 reserved1;
+       u8 op_code;
+#endif
+       u32 data_length;
+       u32 exp_cmd_sn;
+       u32 max_cmd_sn;
+       u32 reserved2[2];
+#if defined(__BIG_ENDIAN)
+       u16 reserved4;
+       u8 err_code;
+       u8 reserved3;
+#elif defined(__LITTLE_ENDIAN)
+       u8 reserved3;
+       u8 err_code;
+       u16 reserved4;
+#endif
+       u32 reserved5[8];
+       u32 cq_req_sn;
+};
+
+/*
+ * bnx2i iSCSI TMF SQ WQE
+ */
+struct bnx2i_tmf_request {
+#if defined(__BIG_ENDIAN)
+       u8 op_code;
+       u8 op_attr;
+#define ISCSI_TMF_REQUEST_FUNCTION (0x7F<<0)
+#define ISCSI_TMF_REQUEST_FUNCTION_SHIFT 0
+#define ISCSI_TMF_REQUEST_ALWAYS_ONE (0x1<<7)
+#define ISCSI_TMF_REQUEST_ALWAYS_ONE_SHIFT 7
+       u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+       u16 reserved0;
+       u8 op_attr;
+#define ISCSI_TMF_REQUEST_FUNCTION (0x7F<<0)
+#define ISCSI_TMF_REQUEST_FUNCTION_SHIFT 0
+#define ISCSI_TMF_REQUEST_ALWAYS_ONE (0x1<<7)
+#define ISCSI_TMF_REQUEST_ALWAYS_ONE_SHIFT 7
+       u8 op_code;
+#endif
+       u32 data_length;
+       u32 lun[2];
+#if defined(__BIG_ENDIAN)
+       u16 reserved1;
+       u16 itt;
+#define ISCSI_TMF_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_TMF_REQUEST_INDEX_SHIFT 0
+#define ISCSI_TMF_REQUEST_TYPE (0x3<<14)
+#define ISCSI_TMF_REQUEST_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+       u16 itt;
+#define ISCSI_TMF_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_TMF_REQUEST_INDEX_SHIFT 0
+#define ISCSI_TMF_REQUEST_TYPE (0x3<<14)
+#define ISCSI_TMF_REQUEST_TYPE_SHIFT 14
+       u16 reserved1;
+#endif
+       u32 ref_itt;
+       u32 cmd_sn;
+       u32 reserved2;
+       u32 ref_cmd_sn;
+       u32 reserved3[3];
+       u32 zero_fill;
+       u32 bd_list_addr_lo;
+       u32 bd_list_addr_hi;
+#if defined(__BIG_ENDIAN)
+       u8 cq_index;
+       u8 reserved5;
+       u8 reserved4;
+       u8 num_bds;
+#elif defined(__LITTLE_ENDIAN)
+       u8 num_bds;
+       u8 reserved4;
+       u8 reserved5;
+       u8 cq_index;
+#endif
+};
+
+/*
+ * iSCSI Text SQ WQE
+ */
+struct bnx2i_text_request {
+#if defined(__BIG_ENDIAN)
+       u8 op_code;
+       u8 op_attr;
+#define ISCSI_TEXT_REQUEST_RESERVED1 (0x3F<<0)
+#define ISCSI_TEXT_REQUEST_RESERVED1_SHIFT 0
+#define ISCSI_TEXT_REQUEST_CONT (0x1<<6)
+#define ISCSI_TEXT_REQUEST_CONT_SHIFT 6
+#define ISCSI_TEXT_REQUEST_FINAL (0x1<<7)
+#define ISCSI_TEXT_REQUEST_FINAL_SHIFT 7
+       u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+       u16 reserved0;
+       u8 op_attr;
+#define ISCSI_TEXT_REQUEST_RESERVED1 (0x3F<<0)
+#define ISCSI_TEXT_REQUEST_RESERVED1_SHIFT 0
+#define ISCSI_TEXT_REQUEST_CONT (0x1<<6)
+#define ISCSI_TEXT_REQUEST_CONT_SHIFT 6
+#define ISCSI_TEXT_REQUEST_FINAL (0x1<<7)
+#define ISCSI_TEXT_REQUEST_FINAL_SHIFT 7
+       u8 op_code;
+#endif
+       u32 data_length;
+       u32 lun[2];
+#if defined(__BIG_ENDIAN)
+       u16 reserved3;
+       u16 itt;
+#define ISCSI_TEXT_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_TEXT_REQUEST_INDEX_SHIFT 0
+#define ISCSI_TEXT_REQUEST_TYPE (0x3<<14)
+#define ISCSI_TEXT_REQUEST_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+       u16 itt;
+#define ISCSI_TEXT_REQUEST_INDEX (0x3FFF<<0)
+#define ISCSI_TEXT_REQUEST_INDEX_SHIFT 0
+#define ISCSI_TEXT_REQUEST_TYPE (0x3<<14)
+#define ISCSI_TEXT_REQUEST_TYPE_SHIFT 14
+       u16 reserved3;
+#endif
+       u32 ttt;
+       u32 cmd_sn;
+       u32 reserved4[2];
+       u32 resp_bd_list_addr_lo;
+       u32 resp_bd_list_addr_hi;
+       u32 resp_buffer;
+#define ISCSI_TEXT_REQUEST_RESP_BUFFER_LENGTH (0xFFFFFF<<0)
+#define ISCSI_TEXT_REQUEST_RESP_BUFFER_LENGTH_SHIFT 0
+#define ISCSI_TEXT_REQUEST_NUM_RESP_BDS (0xFF<<24)
+#define ISCSI_TEXT_REQUEST_NUM_RESP_BDS_SHIFT 24
+       u32 zero_fill;
+       u32 bd_list_addr_lo;
+       u32 bd_list_addr_hi;
+#if defined(__BIG_ENDIAN)
+       u8 cq_index;
+       u8 reserved7;
+       u8 reserved6;
+       u8 num_bds;
+#elif defined(__LITTLE_ENDIAN)
+       u8 num_bds;
+       u8 reserved6;
+       u8 reserved7;
+       u8 cq_index;
+#endif
+};
+
+/*
+ * iSCSI SQ WQE
+ */
+union iscsi_request {
+       struct bnx2i_cmd_request cmd;
+       struct bnx2i_tmf_request tmf;
+       struct bnx2i_nop_out_request nop_out;
+       struct bnx2i_login_request login_req;
+       struct bnx2i_text_request text;
+       struct bnx2i_logout_request logout_req;
+       struct bnx2i_cleanup_request cleanup;
+};
+
+
+/*
+ * iSCSI TMF CQE
+ */
+struct bnx2i_tmf_response {
+#if defined(__BIG_ENDIAN)
+       u8 op_code;
+       u8 reserved1;
+       u8 response;
+       u8 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+       u8 reserved0;
+       u8 response;
+       u8 reserved1;
+       u8 op_code;
+#endif
+       u32 reserved2;
+       u32 exp_cmd_sn;
+       u32 max_cmd_sn;
+       u32 reserved3[2];
+#if defined(__BIG_ENDIAN)
+       u16 reserved5;
+       u8 err_code;
+       u8 reserved4;
+#elif defined(__LITTLE_ENDIAN)
+       u8 reserved4;
+       u8 err_code;
+       u16 reserved5;
+#endif
+       u32 reserved6[7];
+#if defined(__BIG_ENDIAN)
+       u16 reserved7;
+       u16 itt;
+#define ISCSI_TMF_RESPONSE_INDEX (0x3FFF<<0)
+#define ISCSI_TMF_RESPONSE_INDEX_SHIFT 0
+#define ISCSI_TMF_RESPONSE_TYPE (0x3<<14)
+#define ISCSI_TMF_RESPONSE_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+       u16 itt;
+#define ISCSI_TMF_RESPONSE_INDEX (0x3FFF<<0)
+#define ISCSI_TMF_RESPONSE_INDEX_SHIFT 0
+#define ISCSI_TMF_RESPONSE_TYPE (0x3<<14)
+#define ISCSI_TMF_RESPONSE_TYPE_SHIFT 14
+       u16 reserved7;
+#endif
+       u32 cq_req_sn;
+};
+
+/*
+ * iSCSI Text CQE
+ */
+struct bnx2i_text_response {
+#if defined(__BIG_ENDIAN)
+       u8 op_code;
+       u8 response_flags;
+#define ISCSI_TEXT_RESPONSE_RESERVED1 (0x3F<<0)
+#define ISCSI_TEXT_RESPONSE_RESERVED1_SHIFT 0
+#define ISCSI_TEXT_RESPONSE_CONT (0x1<<6)
+#define ISCSI_TEXT_RESPONSE_CONT_SHIFT 6
+#define ISCSI_TEXT_RESPONSE_FINAL (0x1<<7)
+#define ISCSI_TEXT_RESPONSE_FINAL_SHIFT 7
+       u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+       u16 reserved0;
+       u8 response_flags;
+#define ISCSI_TEXT_RESPONSE_RESERVED1 (0x3F<<0)
+#define ISCSI_TEXT_RESPONSE_RESERVED1_SHIFT 0
+#define ISCSI_TEXT_RESPONSE_CONT (0x1<<6)
+#define ISCSI_TEXT_RESPONSE_CONT_SHIFT 6
+#define ISCSI_TEXT_RESPONSE_FINAL (0x1<<7)
+#define ISCSI_TEXT_RESPONSE_FINAL_SHIFT 7
+       u8 op_code;
+#endif
+       u32 data_length;
+       u32 exp_cmd_sn;
+       u32 max_cmd_sn;
+       u32 ttt;
+       u32 reserved2;
+#if defined(__BIG_ENDIAN)
+       u16 reserved4;
+       u8 err_code;
+       u8 reserved3;
+#elif defined(__LITTLE_ENDIAN)
+       u8 reserved3;
+       u8 err_code;
+       u16 reserved4;
+#endif
+       u32 reserved5;
+       u32 lun[2];
+       u32 reserved6[4];
+#if defined(__BIG_ENDIAN)
+       u16 reserved7;
+       u16 itt;
+#define ISCSI_TEXT_RESPONSE_INDEX (0x3FFF<<0)
+#define ISCSI_TEXT_RESPONSE_INDEX_SHIFT 0
+#define ISCSI_TEXT_RESPONSE_TYPE (0x3<<14)
+#define ISCSI_TEXT_RESPONSE_TYPE_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+       u16 itt;
+#define ISCSI_TEXT_RESPONSE_INDEX (0x3FFF<<0)
+#define ISCSI_TEXT_RESPONSE_INDEX_SHIFT 0
+#define ISCSI_TEXT_RESPONSE_TYPE (0x3<<14)
+#define ISCSI_TEXT_RESPONSE_TYPE_SHIFT 14
+       u16 reserved7;
+#endif
+       u32 cq_req_sn;
+};
+
+/*
+ * iSCSI CQE
+ */
+union iscsi_response {
+       struct bnx2i_cmd_response cmd;
+       struct bnx2i_tmf_response tmf;
+       struct bnx2i_login_response login_resp;
+       struct bnx2i_text_response text;
+       struct bnx2i_logout_response logout_resp;
+       struct bnx2i_cleanup_response cleanup;
+       struct bnx2i_reject_msg reject;
+       struct bnx2i_async_msg async;
+       struct bnx2i_nop_in_msg nop_in;
+};
+
+#endif /* __57XX_ISCSI_HSI_LINUX_LE__ */
diff --git a/drivers/scsi/bnx2i/Kconfig b/drivers/scsi/bnx2i/Kconfig
new file mode 100644 (file)
index 0000000..820d428
--- /dev/null
@@ -0,0 +1,7 @@
+config SCSI_BNX2_ISCSI
+       tristate "Broadcom NetXtreme II iSCSI support"
+       select SCSI_ISCSI_ATTRS
+       select CNIC
+       ---help---
+       This driver supports iSCSI offload for the Broadcom NetXtreme II
+       devices.
diff --git a/drivers/scsi/bnx2i/Makefile b/drivers/scsi/bnx2i/Makefile
new file mode 100644 (file)
index 0000000..b5802bd
--- /dev/null
@@ -0,0 +1,3 @@
+bnx2i-y := bnx2i_init.o bnx2i_hwi.o bnx2i_iscsi.o bnx2i_sysfs.o
+
+obj-$(CONFIG_SCSI_BNX2_ISCSI) += bnx2i.o
diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h
new file mode 100644 (file)
index 0000000..d7576f2
--- /dev/null
@@ -0,0 +1,771 @@
+/* bnx2i.h: Broadcom NetXtreme II iSCSI driver.
+ *
+ * Copyright (c) 2006 - 2009 Broadcom Corporation
+ * Copyright (c) 2007, 2008 Red Hat, Inc.  All rights reserved.
+ * Copyright (c) 2007, 2008 Mike Christie
+ *
+ * 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.
+ *
+ * Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ */
+
+#ifndef _BNX2I_H_
+#define _BNX2I_H_
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/in.h>
+#include <linux/kfifo.h>
+#include <linux/netdevice.h>
+#include <linux/completion.h>
+
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi.h>
+#include <scsi/iscsi_proto.h>
+#include <scsi/libiscsi.h>
+#include <scsi/scsi_transport_iscsi.h>
+
+#include "../../net/cnic_if.h"
+#include "57xx_iscsi_hsi.h"
+#include "57xx_iscsi_constants.h"
+
+#define BNX2_ISCSI_DRIVER_NAME         "bnx2i"
+
+#define BNX2I_MAX_ADAPTERS             8
+
+#define ISCSI_MAX_CONNS_PER_HBA                128
+#define ISCSI_MAX_SESS_PER_HBA         ISCSI_MAX_CONNS_PER_HBA
+#define ISCSI_MAX_CMDS_PER_SESS                128
+
+/* Total active commands across all connections supported by devices */
+#define ISCSI_MAX_CMDS_PER_HBA_5708    (28 * (ISCSI_MAX_CMDS_PER_SESS - 1))
+#define ISCSI_MAX_CMDS_PER_HBA_5709    (128 * (ISCSI_MAX_CMDS_PER_SESS - 1))
+#define ISCSI_MAX_CMDS_PER_HBA_57710   (256 * (ISCSI_MAX_CMDS_PER_SESS - 1))
+
+#define ISCSI_MAX_BDS_PER_CMD          32
+
+#define MAX_PAGES_PER_CTRL_STRUCT_POOL 8
+#define BNX2I_RESERVED_SLOW_PATH_CMD_SLOTS     4
+
+/* 5706/08 hardware has limit on maximum buffer size per BD it can handle */
+#define MAX_BD_LENGTH                  65535
+#define BD_SPLIT_SIZE                  32768
+
+/* min, max & default values for SQ/RQ/CQ size, configurable via' modparam */
+#define BNX2I_SQ_WQES_MIN              16
+#define BNX2I_570X_SQ_WQES_MAX                 128
+#define BNX2I_5770X_SQ_WQES_MAX        512
+#define BNX2I_570X_SQ_WQES_DEFAULT     128
+#define BNX2I_5770X_SQ_WQES_DEFAULT    256
+
+#define BNX2I_570X_CQ_WQES_MAX                 128
+#define BNX2I_5770X_CQ_WQES_MAX        512
+
+#define BNX2I_RQ_WQES_MIN              16
+#define BNX2I_RQ_WQES_MAX              32
+#define BNX2I_RQ_WQES_DEFAULT          16
+
+/* CCELLs per conn */
+#define BNX2I_CCELLS_MIN               16
+#define BNX2I_CCELLS_MAX               96
+#define BNX2I_CCELLS_DEFAULT           64
+
+#define ITT_INVALID_SIGNATURE          0xFFFF
+
+#define ISCSI_CMD_CLEANUP_TIMEOUT      100
+
+#define BNX2I_CONN_CTX_BUF_SIZE                16384
+
+#define BNX2I_SQ_WQE_SIZE              64
+#define BNX2I_RQ_WQE_SIZE              256
+#define BNX2I_CQE_SIZE                 64
+
+#define MB_KERNEL_CTX_SHIFT            8
+#define MB_KERNEL_CTX_SIZE             (1 << MB_KERNEL_CTX_SHIFT)
+
+#define CTX_SHIFT                      7
+#define GET_CID_NUM(cid_addr)          ((cid_addr) >> CTX_SHIFT)
+
+#define CTX_OFFSET                     0x10000
+#define MAX_CID_CNT                    0x4000
+
+/* 5709 context registers */
+#define BNX2_MQ_CONFIG2                        0x00003d00
+#define BNX2_MQ_CONFIG2_CONT_SZ                (0x7L<<4)
+#define BNX2_MQ_CONFIG2_FIRST_L4L5     (0x1fL<<8)
+
+/* 57710's BAR2 is mapped to doorbell registers */
+#define BNX2X_DOORBELL_PCI_BAR         2
+#define BNX2X_MAX_CQS                  8
+
+#define CNIC_ARM_CQE                   1
+#define CNIC_DISARM_CQE                        0
+
+#define REG_RD(__hba, offset)                          \
+               readl(__hba->regview + offset)
+#define REG_WR(__hba, offset, val)                     \
+               writel(val, __hba->regview + offset)
+
+
+/**
+ * struct generic_pdu_resc - login pdu resource structure
+ *
+ * @req_buf:            driver buffer used to stage payload associated with
+ *                      the login request
+ * @req_dma_addr:       dma address for iscsi login request payload buffer
+ * @req_buf_size:       actual login request payload length
+ * @req_wr_ptr:         pointer into login request buffer when next data is
+ *                      to be written
+ * @resp_hdr:           iscsi header where iscsi login response header is to
+ *                      be recreated
+ * @resp_buf:           buffer to stage login response payload
+ * @resp_dma_addr:      login response payload buffer dma address
+ * @resp_buf_size:      login response paylod length
+ * @resp_wr_ptr:        pointer into login response buffer when next data is
+ *                      to be written
+ * @req_bd_tbl:         iscsi login request payload BD table
+ * @req_bd_dma:         login request BD table dma address
+ * @resp_bd_tbl:        iscsi login response payload BD table
+ * @resp_bd_dma:        login request BD table dma address
+ *
+ * following structure defines buffer info for generic pdus such as iSCSI Login,
+ *     Logout and NOP
+ */
+struct generic_pdu_resc {
+       char *req_buf;
+       dma_addr_t req_dma_addr;
+       u32 req_buf_size;
+       char *req_wr_ptr;
+       struct iscsi_hdr resp_hdr;
+       char *resp_buf;
+       dma_addr_t resp_dma_addr;
+       u32 resp_buf_size;
+       char *resp_wr_ptr;
+       char *req_bd_tbl;
+       dma_addr_t req_bd_dma;
+       char *resp_bd_tbl;
+       dma_addr_t resp_bd_dma;
+};
+
+
+/**
+ * struct bd_resc_page - tracks DMA'able memory allocated for BD tables
+ *
+ * @link:               list head to link elements
+ * @max_ptrs:           maximun pointers that can be stored in this page
+ * @num_valid:          number of pointer valid in this page
+ * @page:               base addess for page pointer array
+ *
+ * structure to track DMA'able memory allocated for command BD tables
+ */
+struct bd_resc_page {
+       struct list_head link;
+       u32 max_ptrs;
+       u32 num_valid;
+       void *page[1];
+};
+
+
+/**
+ * struct io_bdt - I/O buffer destricptor table
+ *
+ * @bd_tbl:             BD table's virtual address
+ * @bd_tbl_dma:         BD table's dma address
+ * @bd_valid:           num valid BD entries
+ *
+ * IO BD table
+ */
+struct io_bdt {
+       struct iscsi_bd *bd_tbl;
+       dma_addr_t bd_tbl_dma;
+       u16 bd_valid;
+};
+
+
+/**
+ * bnx2i_cmd - iscsi command structure
+ *
+ * @scsi_cmd:           SCSI-ML task pointer corresponding to this iscsi cmd
+ * @sg:                 SG list
+ * @io_tbl:             buffer descriptor (BD) table
+ * @bd_tbl_dma:         buffer descriptor (BD) table's dma address
+ */
+struct bnx2i_cmd {
+       struct iscsi_hdr hdr;
+       struct bnx2i_conn *conn;
+       struct scsi_cmnd *scsi_cmd;
+       struct scatterlist *sg;
+       struct io_bdt io_tbl;
+       dma_addr_t bd_tbl_dma;
+       struct bnx2i_cmd_request req;
+};
+
+
+/**
+ * struct bnx2i_conn - iscsi connection structure
+ *
+ * @cls_conn:              pointer to iscsi cls conn
+ * @hba:                   adapter structure pointer
+ * @iscsi_conn_cid:        iscsi conn id
+ * @fw_cid:                firmware iscsi context id
+ * @ep:                    endpoint structure pointer
+ * @gen_pdu:               login/nopout/logout pdu resources
+ * @violation_notified:    bit mask used to track iscsi error/warning messages
+ *                         already printed out
+ *
+ * iSCSI connection structure
+ */
+struct bnx2i_conn {
+       struct iscsi_cls_conn *cls_conn;
+       struct bnx2i_hba *hba;
+       struct completion cmd_cleanup_cmpl;
+       int is_bound;
+
+       u32 iscsi_conn_cid;
+#define BNX2I_CID_RESERVED     0x5AFF
+       u32 fw_cid;
+
+       struct timer_list poll_timer;
+       /*
+        * Queue Pair (QP) related structure elements.
+        */
+       struct bnx2i_endpoint *ep;
+
+       /*
+        * Buffer for login negotiation process
+        */
+       struct generic_pdu_resc gen_pdu;
+       u64 violation_notified;
+};
+
+
+
+/**
+ * struct iscsi_cid_queue - Per adapter iscsi cid queue
+ *
+ * @cid_que_base:           queue base memory
+ * @cid_que:                queue memory pointer
+ * @cid_q_prod_idx:         produce index
+ * @cid_q_cons_idx:         consumer index
+ * @cid_q_max_idx:          max index. used to detect wrap around condition
+ * @cid_free_cnt:           queue size
+ * @conn_cid_tbl:           iscsi cid to conn structure mapping table
+ *
+ * Per adapter iSCSI CID Queue
+ */
+struct iscsi_cid_queue {
+       void *cid_que_base;
+       u32 *cid_que;
+       u32 cid_q_prod_idx;
+       u32 cid_q_cons_idx;
+       u32 cid_q_max_idx;
+       u32 cid_free_cnt;
+       struct bnx2i_conn **conn_cid_tbl;
+};
+
+/**
+ * struct bnx2i_hba - bnx2i adapter structure
+ *
+ * @link:                  list head to link elements
+ * @cnic:                  pointer to cnic device
+ * @pcidev:                pointer to pci dev
+ * @netdev:                pointer to netdev structure
+ * @regview:               mapped PCI register space
+ * @age:                   age, incremented by every recovery
+ * @cnic_dev_type:         cnic device type, 5706/5708/5709/57710
+ * @mail_queue_access:     mailbox queue access mode, applicable to 5709 only
+ * @reg_with_cnic:         indicates whether the device is register with CNIC
+ * @adapter_state:         adapter state, UP, GOING_DOWN, LINK_DOWN
+ * @mtu_supported:         Ethernet MTU supported
+ * @shost:                 scsi host pointer
+ * @max_sqes:              SQ size
+ * @max_rqes:              RQ size
+ * @max_cqes:              CQ size
+ * @num_ccell:             number of command cells per connection
+ * @ofld_conns_active:     active connection list
+ * @max_active_conns:      max offload connections supported by this device
+ * @cid_que:               iscsi cid queue
+ * @ep_rdwr_lock:          read / write lock to synchronize various ep lists
+ * @ep_ofld_list:          connection list for pending offload completion
+ * @ep_destroy_list:       connection list for pending offload completion
+ * @mp_bd_tbl:             BD table to be used with middle path requests
+ * @mp_bd_dma:             DMA address of 'mp_bd_tbl' memory buffer
+ * @dummy_buffer:          Dummy buffer to be used with zero length scsicmd reqs
+ * @dummy_buf_dma:         DMA address of 'dummy_buffer' memory buffer
+ * @lock:                         lock to synchonize access to hba structure
+ * @pci_did:               PCI device ID
+ * @pci_vid:               PCI vendor ID
+ * @pci_sdid:              PCI subsystem device ID
+ * @pci_svid:              PCI subsystem vendor ID
+ * @pci_func:              PCI function number in system pci tree
+ * @pci_devno:             PCI device number in system pci tree
+ * @num_wqe_sent:          statistic counter, total wqe's sent
+ * @num_cqe_rcvd:          statistic counter, total cqe's received
+ * @num_intr_claimed:      statistic counter, total interrupts claimed
+ * @link_changed_count:    statistic counter, num of link change notifications
+ *                         received
+ * @ipaddr_changed_count:  statistic counter, num times IP address changed while
+ *                         at least one connection is offloaded
+ * @num_sess_opened:       statistic counter, total num sessions opened
+ * @num_conn_opened:       statistic counter, total num conns opened on this hba
+ * @ctx_ccell_tasks:       captures number of ccells and tasks supported by
+ *                         currently offloaded connection, used to decode
+ *                         context memory
+ *
+ * Adapter Data Structure
+ */
+struct bnx2i_hba {
+       struct list_head link;
+       struct cnic_dev *cnic;
+       struct pci_dev *pcidev;
+       struct net_device *netdev;
+       void __iomem *regview;
+
+       u32 age;
+       unsigned long cnic_dev_type;
+               #define BNX2I_NX2_DEV_5706              0x0
+               #define BNX2I_NX2_DEV_5708              0x1
+               #define BNX2I_NX2_DEV_5709              0x2
+               #define BNX2I_NX2_DEV_57710             0x3
+       u32 mail_queue_access;
+               #define BNX2I_MQ_KERNEL_MODE            0x0
+               #define BNX2I_MQ_KERNEL_BYPASS_MODE     0x1
+               #define BNX2I_MQ_BIN_MODE               0x2
+       unsigned long  reg_with_cnic;
+               #define BNX2I_CNIC_REGISTERED           1
+
+       unsigned long  adapter_state;
+               #define ADAPTER_STATE_UP                0
+               #define ADAPTER_STATE_GOING_DOWN        1
+               #define ADAPTER_STATE_LINK_DOWN         2
+               #define ADAPTER_STATE_INIT_FAILED       31
+       unsigned int mtu_supported;
+               #define BNX2I_MAX_MTU_SUPPORTED         1500
+
+       struct Scsi_Host *shost;
+
+       u32 max_sqes;
+       u32 max_rqes;
+       u32 max_cqes;
+       u32 num_ccell;
+
+       int ofld_conns_active;
+
+       int max_active_conns;
+       struct iscsi_cid_queue cid_que;
+
+       rwlock_t ep_rdwr_lock;
+       struct list_head ep_ofld_list;
+       struct list_head ep_destroy_list;
+
+       /*
+        * BD table to be used with MP (Middle Path requests.
+        */
+       char *mp_bd_tbl;
+       dma_addr_t mp_bd_dma;
+       char *dummy_buffer;
+       dma_addr_t dummy_buf_dma;
+
+       spinlock_t lock;        /* protects hba structure access */
+       struct mutex net_dev_lock;/* sync net device access */
+
+       /*
+        * PCI related info.
+        */
+       u16 pci_did;
+       u16 pci_vid;
+       u16 pci_sdid;
+       u16 pci_svid;
+       u16 pci_func;
+       u16 pci_devno;
+
+       /*
+        * Following are a bunch of statistics useful during development
+        * and later stage for score boarding.
+        */
+       u32 num_wqe_sent;
+       u32 num_cqe_rcvd;
+       u32 num_intr_claimed;
+       u32 link_changed_count;
+       u32 ipaddr_changed_count;
+       u32 num_sess_opened;
+       u32 num_conn_opened;
+       unsigned int ctx_ccell_tasks;
+};
+
+
+/*******************************************************************************
+ *     QP [ SQ / RQ / CQ ] info.
+ ******************************************************************************/
+
+/*
+ * SQ/RQ/CQ generic structure definition
+ */
+struct         sqe {
+       u8 sqe_byte[BNX2I_SQ_WQE_SIZE];
+};
+
+struct         rqe {
+       u8 rqe_byte[BNX2I_RQ_WQE_SIZE];
+};
+
+struct         cqe {
+       u8 cqe_byte[BNX2I_CQE_SIZE];
+};
+
+
+enum {
+#if defined(__LITTLE_ENDIAN)
+       CNIC_EVENT_COAL_INDEX   = 0x0,
+       CNIC_SEND_DOORBELL      = 0x4,
+       CNIC_EVENT_CQ_ARM       = 0x7,
+       CNIC_RECV_DOORBELL      = 0x8
+#elif defined(__BIG_ENDIAN)
+       CNIC_EVENT_COAL_INDEX   = 0x2,
+       CNIC_SEND_DOORBELL      = 0x6,
+       CNIC_EVENT_CQ_ARM       = 0x4,
+       CNIC_RECV_DOORBELL      = 0xa
+#endif
+};
+
+
+/*
+ * CQ DB
+ */
+struct bnx2x_iscsi_cq_pend_cmpl {
+       /* CQ producer, updated by Ustorm */
+       u16 ustrom_prod;
+       /* CQ pending completion counter */
+       u16 pend_cntr;
+};
+
+
+struct bnx2i_5771x_cq_db {
+       struct bnx2x_iscsi_cq_pend_cmpl qp_pend_cmpl[BNX2X_MAX_CQS];
+       /* CQ pending completion ITT array */
+       u16 itt[BNX2X_MAX_CQS];
+       /* Cstorm CQ sequence to notify array, updated by driver */;
+       u16 sqn[BNX2X_MAX_CQS];
+       u32 reserved[4] /* 16 byte allignment */;
+};
+
+
+struct bnx2i_5771x_sq_rq_db {
+       u16 prod_idx;
+       u8 reserved0[14]; /* Pad structure size to 16 bytes */
+};
+
+
+struct bnx2i_5771x_dbell_hdr {
+       u8 header;
+       /* 1 for rx doorbell, 0 for tx doorbell */
+#define B577XX_DOORBELL_HDR_RX                         (0x1<<0)
+#define B577XX_DOORBELL_HDR_RX_SHIFT                   0
+       /* 0 for normal doorbell, 1 for advertise wnd doorbell */
+#define B577XX_DOORBELL_HDR_DB_TYPE                    (0x1<<1)
+#define B577XX_DOORBELL_HDR_DB_TYPE_SHIFT              1
+       /* rdma tx only: DPM transaction size specifier (64/128/256/512B) */
+#define B577XX_DOORBELL_HDR_DPM_SIZE                   (0x3<<2)
+#define B577XX_DOORBELL_HDR_DPM_SIZE_SHIFT             2
+       /* connection type */
+#define B577XX_DOORBELL_HDR_CONN_TYPE                  (0xF<<4)
+#define B577XX_DOORBELL_HDR_CONN_TYPE_SHIFT            4
+};
+
+struct bnx2i_5771x_dbell {
+       struct bnx2i_5771x_dbell_hdr dbell;
+       u8 pad[3];
+
+};
+
+/**
+ * struct qp_info - QP (share queue region) atrributes structure
+ *
+ * @ctx_base:           ioremapped pci register base to access doorbell register
+ *                      pertaining to this offloaded connection
+ * @sq_virt:            virtual address of send queue (SQ) region
+ * @sq_phys:            DMA address of SQ memory region
+ * @sq_mem_size:        SQ size
+ * @sq_prod_qe:         SQ producer entry pointer
+ * @sq_cons_qe:         SQ consumer entry pointer
+ * @sq_first_qe:        virtaul address of first entry in SQ
+ * @sq_last_qe:         virtaul address of last entry in SQ
+ * @sq_prod_idx:        SQ producer index
+ * @sq_cons_idx:        SQ consumer index
+ * @sqe_left:           number sq entry left
+ * @sq_pgtbl_virt:      page table describing buffer consituting SQ region
+ * @sq_pgtbl_phys:      dma address of 'sq_pgtbl_virt'
+ * @sq_pgtbl_size:      SQ page table size
+ * @cq_virt:            virtual address of completion queue (CQ) region
+ * @cq_phys:            DMA address of RQ memory region
+ * @cq_mem_size:        CQ size
+ * @cq_prod_qe:         CQ producer entry pointer
+ * @cq_cons_qe:         CQ consumer entry pointer
+ * @cq_first_qe:        virtaul address of first entry in CQ
+ * @cq_last_qe:         virtaul address of last entry in CQ
+ * @cq_prod_idx:        CQ producer index
+ * @cq_cons_idx:        CQ consumer index
+ * @cqe_left:           number cq entry left
+ * @cqe_size:           size of each CQ entry
+ * @cqe_exp_seq_sn:     next expected CQE sequence number
+ * @cq_pgtbl_virt:      page table describing buffer consituting CQ region
+ * @cq_pgtbl_phys:      dma address of 'cq_pgtbl_virt'
+ * @cq_pgtbl_size:     CQ page table size
+ * @rq_virt:            virtual address of receive queue (RQ) region
+ * @rq_phys:            DMA address of RQ memory region
+ * @rq_mem_size:        RQ size
+ * @rq_prod_qe:         RQ producer entry pointer
+ * @rq_cons_qe:         RQ consumer entry pointer
+ * @rq_first_qe:        virtaul address of first entry in RQ
+ * @rq_last_qe:         virtaul address of last entry in RQ
+ * @rq_prod_idx:        RQ producer index
+ * @rq_cons_idx:        RQ consumer index
+ * @rqe_left:           number rq entry left
+ * @rq_pgtbl_virt:      page table describing buffer consituting RQ region
+ * @rq_pgtbl_phys:      dma address of 'rq_pgtbl_virt'
+ * @rq_pgtbl_size:      RQ page table size
+ *
+ * queue pair (QP) is a per connection shared data structure which is used
+ *     to send work requests (SQ), receive completion notifications (CQ)
+ *     and receive asynchoronous / scsi sense info (RQ). 'qp_info' structure
+ *     below holds queue memory, consumer/producer indexes and page table
+ *     information
+ */
+struct qp_info {
+       void __iomem *ctx_base;
+#define DPM_TRIGER_TYPE                        0x40
+
+#define BNX2I_570x_QUE_DB_SIZE         0
+#define BNX2I_5771x_QUE_DB_SIZE                16
+       struct sqe *sq_virt;
+       dma_addr_t sq_phys;
+       u32 sq_mem_size;
+
+       struct sqe *sq_prod_qe;
+       struct sqe *sq_cons_qe;
+       struct sqe *sq_first_qe;
+       struct sqe *sq_last_qe;
+       u16 sq_prod_idx;
+       u16 sq_cons_idx;
+       u32 sqe_left;
+
+       void *sq_pgtbl_virt;
+       dma_addr_t sq_pgtbl_phys;
+       u32 sq_pgtbl_size;      /* set to PAGE_SIZE for 5708 & 5709 */
+
+       struct cqe *cq_virt;
+       dma_addr_t cq_phys;
+       u32 cq_mem_size;
+
+       struct cqe *cq_prod_qe;
+       struct cqe *cq_cons_qe;
+       struct cqe *cq_first_qe;
+       struct cqe *cq_last_qe;
+       u16 cq_prod_idx;
+       u16 cq_cons_idx;
+       u32 cqe_left;
+       u32 cqe_size;
+       u32 cqe_exp_seq_sn;
+
+       void *cq_pgtbl_virt;
+       dma_addr_t cq_pgtbl_phys;
+       u32 cq_pgtbl_size;      /* set to PAGE_SIZE for 5708 & 5709 */
+
+       struct rqe *rq_virt;
+       dma_addr_t rq_phys;
+       u32 rq_mem_size;
+
+       struct rqe *rq_prod_qe;
+       struct rqe *rq_cons_qe;
+       struct rqe *rq_first_qe;
+       struct rqe *rq_last_qe;
+       u16 rq_prod_idx;
+       u16 rq_cons_idx;
+       u32 rqe_left;
+
+       void *rq_pgtbl_virt;
+       dma_addr_t rq_pgtbl_phys;
+       u32 rq_pgtbl_size;      /* set to PAGE_SIZE for 5708 & 5709 */
+};
+
+
+
+/*
+ * CID handles
+ */
+struct ep_handles {
+       u32 fw_cid;
+       u32 drv_iscsi_cid;
+       u16 pg_cid;
+       u16 rsvd;
+};
+
+
+enum {
+       EP_STATE_IDLE                   = 0x0,
+       EP_STATE_PG_OFLD_START          = 0x1,
+       EP_STATE_PG_OFLD_COMPL          = 0x2,
+       EP_STATE_OFLD_START             = 0x4,
+       EP_STATE_OFLD_COMPL             = 0x8,
+       EP_STATE_CONNECT_START          = 0x10,
+       EP_STATE_CONNECT_COMPL          = 0x20,
+       EP_STATE_ULP_UPDATE_START       = 0x40,
+       EP_STATE_ULP_UPDATE_COMPL       = 0x80,
+       EP_STATE_DISCONN_START          = 0x100,
+       EP_STATE_DISCONN_COMPL          = 0x200,
+       EP_STATE_CLEANUP_START          = 0x400,
+       EP_STATE_CLEANUP_CMPL           = 0x800,
+       EP_STATE_TCP_FIN_RCVD           = 0x1000,
+       EP_STATE_TCP_RST_RCVD           = 0x2000,
+       EP_STATE_PG_OFLD_FAILED         = 0x1000000,
+       EP_STATE_ULP_UPDATE_FAILED      = 0x2000000,
+       EP_STATE_CLEANUP_FAILED         = 0x4000000,
+       EP_STATE_OFLD_FAILED            = 0x8000000,
+       EP_STATE_CONNECT_FAILED         = 0x10000000,
+       EP_STATE_DISCONN_TIMEDOUT       = 0x20000000,
+};
+
+/**
+ * struct bnx2i_endpoint - representation of tcp connection in NX2 world
+ *
+ * @link:               list head to link elements
+ * @hba:                adapter to which this connection belongs
+ * @conn:               iscsi connection this EP is linked to
+ * @sess:               iscsi session this EP is linked to
+ * @cm_sk:              cnic sock struct
+ * @hba_age:            age to detect if 'iscsid' issues ep_disconnect()
+ *                      after HBA reset is completed by bnx2i/cnic/bnx2
+ *                      modules
+ * @state:              tracks offload connection state machine
+ * @teardown_mode:      indicates if conn teardown is abortive or orderly
+ * @qp:                 QP information
+ * @ids:                contains chip allocated *context id* & driver assigned
+ *                      *iscsi cid*
+ * @ofld_timer:         offload timer to detect timeout
+ * @ofld_wait:          wait queue
+ *
+ * Endpoint Structure - equivalent of tcp socket structure
+ */
+struct bnx2i_endpoint {
+       struct list_head link;
+       struct bnx2i_hba *hba;
+       struct bnx2i_conn *conn;
+       struct cnic_sock *cm_sk;
+       u32 hba_age;
+       u32 state;
+       unsigned long timestamp;
+       int num_active_cmds;
+
+       struct qp_info qp;
+       struct ep_handles ids;
+               #define ep_iscsi_cid    ids.drv_iscsi_cid
+               #define ep_cid          ids.fw_cid
+               #define ep_pg_cid       ids.pg_cid
+       struct timer_list ofld_timer;
+       wait_queue_head_t ofld_wait;
+};
+
+
+
+/* Global variables */
+extern unsigned int error_mask1, error_mask2;
+extern u64 iscsi_error_mask;
+extern unsigned int en_tcp_dack;
+extern unsigned int event_coal_div;
+
+extern struct scsi_transport_template *bnx2i_scsi_xport_template;
+extern struct iscsi_transport bnx2i_iscsi_transport;
+extern struct cnic_ulp_ops bnx2i_cnic_cb;
+
+extern unsigned int sq_size;
+extern unsigned int rq_size;
+
+extern struct device_attribute *bnx2i_dev_attributes[];
+
+
+
+/*
+ * Function Prototypes
+ */
+extern void bnx2i_identify_device(struct bnx2i_hba *hba);
+extern void bnx2i_register_device(struct bnx2i_hba *hba);
+
+extern void bnx2i_ulp_init(struct cnic_dev *dev);
+extern void bnx2i_ulp_exit(struct cnic_dev *dev);
+extern void bnx2i_start(void *handle);
+extern void bnx2i_stop(void *handle);
+extern void bnx2i_reg_dev_all(void);
+extern void bnx2i_unreg_dev_all(void);
+extern struct bnx2i_hba *get_adapter_list_head(void);
+
+struct bnx2i_conn *bnx2i_get_conn_from_id(struct bnx2i_hba *hba,
+                                         u16 iscsi_cid);
+
+int bnx2i_alloc_ep_pool(void);
+void bnx2i_release_ep_pool(void);
+struct bnx2i_endpoint *bnx2i_ep_ofld_list_next(struct bnx2i_hba *hba);
+struct bnx2i_endpoint *bnx2i_ep_destroy_list_next(struct bnx2i_hba *hba);
+
+struct bnx2i_hba *bnx2i_find_hba_for_cnic(struct cnic_dev *cnic);
+
+struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic);
+void bnx2i_free_hba(struct bnx2i_hba *hba);
+
+void bnx2i_get_rq_buf(struct bnx2i_conn *conn, char *ptr, int len);
+void bnx2i_put_rq_buf(struct bnx2i_conn *conn, int count);
+
+void bnx2i_iscsi_unmap_sg_list(struct bnx2i_cmd *cmd);
+
+void bnx2i_drop_session(struct iscsi_cls_session *session);
+
+extern int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba);
+extern int bnx2i_send_iscsi_login(struct bnx2i_conn *conn,
+                                 struct iscsi_task *mtask);
+extern int bnx2i_send_iscsi_tmf(struct bnx2i_conn *conn,
+                                 struct iscsi_task *mtask);
+extern int bnx2i_send_iscsi_scsicmd(struct bnx2i_conn *conn,
+                                   struct bnx2i_cmd *cmnd);
+extern int bnx2i_send_iscsi_nopout(struct bnx2i_conn *conn,
+                                  struct iscsi_task *mtask, u32 ttt,
+                                  char *datap, int data_len, int unsol);
+extern int bnx2i_send_iscsi_logout(struct bnx2i_conn *conn,
+                                  struct iscsi_task *mtask);
+extern void bnx2i_send_cmd_cleanup_req(struct bnx2i_hba *hba,
+                                      struct bnx2i_cmd *cmd);
+extern void bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba,
+                                    struct bnx2i_endpoint *ep);
+extern void bnx2i_update_iscsi_conn(struct iscsi_conn *conn);
+extern void bnx2i_send_conn_destroy(struct bnx2i_hba *hba,
+                                   struct bnx2i_endpoint *ep);
+
+extern int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba,
+                              struct bnx2i_endpoint *ep);
+extern void bnx2i_free_qp_resc(struct bnx2i_hba *hba,
+                              struct bnx2i_endpoint *ep);
+extern void bnx2i_ep_ofld_timer(unsigned long data);
+extern struct bnx2i_endpoint *bnx2i_find_ep_in_ofld_list(
+               struct bnx2i_hba *hba, u32 iscsi_cid);
+extern struct bnx2i_endpoint *bnx2i_find_ep_in_destroy_list(
+               struct bnx2i_hba *hba, u32 iscsi_cid);
+
+extern int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep);
+extern void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action);
+
+/* Debug related function prototypes */
+extern void bnx2i_print_pend_cmd_queue(struct bnx2i_conn *conn);
+extern void bnx2i_print_active_cmd_queue(struct bnx2i_conn *conn);
+extern void bnx2i_print_xmit_pdu_queue(struct bnx2i_conn *conn);
+extern void bnx2i_print_recv_state(struct bnx2i_conn *conn);
+
+#endif
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c
new file mode 100644 (file)
index 0000000..906cef5
--- /dev/null
@@ -0,0 +1,2405 @@
+/* bnx2i_hwi.c: Broadcom NetXtreme II iSCSI driver.
+ *
+ * Copyright (c) 2006 - 2009 Broadcom Corporation
+ * Copyright (c) 2007, 2008 Red Hat, Inc.  All rights reserved.
+ * Copyright (c) 2007, 2008 Mike Christie
+ *
+ * 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.
+ *
+ * Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ */
+
+#include <scsi/scsi_tcq.h>
+#include <scsi/libiscsi.h>
+#include "bnx2i.h"
+
+/**
+ * bnx2i_get_cid_num - get cid from ep
+ * @ep:        endpoint pointer
+ *
+ * Only applicable to 57710 family of devices
+ */
+static u32 bnx2i_get_cid_num(struct bnx2i_endpoint *ep)
+{
+       u32 cid;
+
+       if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type))
+               cid = ep->ep_cid;
+       else
+               cid = GET_CID_NUM(ep->ep_cid);
+       return cid;
+}
+
+
+/**
+ * bnx2i_adjust_qp_size - Adjust SQ/RQ/CQ size for 57710 device type
+ * @hba:               Adapter for which adjustments is to be made
+ *
+ * Only applicable to 57710 family of devices
+ */
+static void bnx2i_adjust_qp_size(struct bnx2i_hba *hba)
+{
+       u32 num_elements_per_pg;
+
+       if (test_bit(BNX2I_NX2_DEV_5706, &hba->cnic_dev_type) ||
+           test_bit(BNX2I_NX2_DEV_5708, &hba->cnic_dev_type) ||
+           test_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type)) {
+               if (!is_power_of_2(hba->max_sqes))
+                       hba->max_sqes = rounddown_pow_of_two(hba->max_sqes);
+
+               if (!is_power_of_2(hba->max_rqes))
+                       hba->max_rqes = rounddown_pow_of_two(hba->max_rqes);
+       }
+
+       /* Adjust each queue size if the user selection does not
+        * yield integral num of page buffers
+        */
+       /* adjust SQ */
+       num_elements_per_pg = PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
+       if (hba->max_sqes < num_elements_per_pg)
+               hba->max_sqes = num_elements_per_pg;
+       else if (hba->max_sqes % num_elements_per_pg)
+               hba->max_sqes = (hba->max_sqes + num_elements_per_pg - 1) &
+                                ~(num_elements_per_pg - 1);
+
+       /* adjust CQ */
+       num_elements_per_pg = PAGE_SIZE / BNX2I_CQE_SIZE;
+       if (hba->max_cqes < num_elements_per_pg)
+               hba->max_cqes = num_elements_per_pg;
+       else if (hba->max_cqes % num_elements_per_pg)
+               hba->max_cqes = (hba->max_cqes + num_elements_per_pg - 1) &
+                                ~(num_elements_per_pg - 1);
+
+       /* adjust RQ */
+       num_elements_per_pg = PAGE_SIZE / BNX2I_RQ_WQE_SIZE;
+       if (hba->max_rqes < num_elements_per_pg)
+               hba->max_rqes = num_elements_per_pg;
+       else if (hba->max_rqes % num_elements_per_pg)
+               hba->max_rqes = (hba->max_rqes + num_elements_per_pg - 1) &
+                                ~(num_elements_per_pg - 1);
+}
+
+
+/**
+ * bnx2i_get_link_state - get network interface link state
+ * @hba:       adapter instance pointer
+ *
+ * updates adapter structure flag based on netdev state
+ */
+static void bnx2i_get_link_state(struct bnx2i_hba *hba)
+{
+       if (test_bit(__LINK_STATE_NOCARRIER, &hba->netdev->state))
+               set_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state);
+       else
+               clear_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state);
+}
+
+
+/**
+ * bnx2i_iscsi_license_error - displays iscsi license related error message
+ * @hba:               adapter instance pointer
+ * @error_code:                error classification
+ *
+ * Puts out an error log when driver is unable to offload iscsi connection
+ *     due to license restrictions
+ */
+static void bnx2i_iscsi_license_error(struct bnx2i_hba *hba, u32 error_code)
+{
+       if (error_code == ISCSI_KCQE_COMPLETION_STATUS_ISCSI_NOT_SUPPORTED)
+               /* iSCSI offload not supported on this device */
+               printk(KERN_ERR "bnx2i: iSCSI not supported, dev=%s\n",
+                               hba->netdev->name);
+       if (error_code == ISCSI_KCQE_COMPLETION_STATUS_LOM_ISCSI_NOT_ENABLED)
+               /* iSCSI offload not supported on this LOM device */
+               printk(KERN_ERR "bnx2i: LOM is not enable to "
+                               "offload iSCSI connections, dev=%s\n",
+                               hba->netdev->name);
+       set_bit(ADAPTER_STATE_INIT_FAILED, &hba->adapter_state);
+}
+
+
+/**
+ * bnx2i_arm_cq_event_coalescing - arms CQ to enable EQ notification
+ * @ep:                endpoint (transport indentifier) structure
+ * @action:    action, ARM or DISARM. For now only ARM_CQE is used
+ *
+ * Arm'ing CQ will enable chip to generate global EQ events inorder to interrupt
+ *     the driver. EQ event is generated CQ index is hit or at least 1 CQ is
+ *     outstanding and on chip timer expires
+ */
+void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action)
+{
+       struct bnx2i_5771x_cq_db *cq_db;
+       u16 cq_index;
+
+       if (!test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type))
+               return;
+
+       if (action == CNIC_ARM_CQE) {
+               cq_index = ep->qp.cqe_exp_seq_sn +
+                          ep->num_active_cmds / event_coal_div;
+               cq_index %= (ep->qp.cqe_size * 2 + 1);
+               if (!cq_index) {
+                       cq_index = 1;
+                       cq_db = (struct bnx2i_5771x_cq_db *)
+                                       ep->qp.cq_pgtbl_virt;
+                       cq_db->sqn[0] = cq_index;
+               }
+       }
+}
+
+
+/**
+ * bnx2i_get_rq_buf - copy RQ buffer contents to driver buffer
+ * @conn:              iscsi connection on which RQ event occured
+ * @ptr:               driver buffer to which RQ buffer contents is to
+ *                     be copied
+ * @len:               length of valid data inside RQ buf
+ *
+ * Copies RQ buffer contents from shared (DMA'able) memory region to
+ *     driver buffer. RQ is used to DMA unsolicitated iscsi pdu's and
+ *     scsi sense info
+ */
+void bnx2i_get_rq_buf(struct bnx2i_conn *bnx2i_conn, char *ptr, int len)
+{
+       if (!bnx2i_conn->ep->qp.rqe_left)
+               return;
+
+       bnx2i_conn->ep->qp.rqe_left--;
+       memcpy(ptr, (u8 *) bnx2i_conn->ep->qp.rq_cons_qe, len);
+       if (bnx2i_conn->ep->qp.rq_cons_qe == bnx2i_conn->ep->qp.rq_last_qe) {
+               bnx2i_conn->ep->qp.rq_cons_qe = bnx2i_conn->ep->qp.rq_first_qe;
+               bnx2i_conn->ep->qp.rq_cons_idx = 0;
+       } else {
+               bnx2i_conn->ep->qp.rq_cons_qe++;
+               bnx2i_conn->ep->qp.rq_cons_idx++;
+       }
+}
+
+
+static void bnx2i_ring_577xx_doorbell(struct bnx2i_conn *conn)
+{
+       struct bnx2i_5771x_dbell dbell;
+       u32 msg;
+
+       memset(&dbell, 0, sizeof(dbell));
+       dbell.dbell.header = (B577XX_ISCSI_CONNECTION_TYPE <<
+                             B577XX_DOORBELL_HDR_CONN_TYPE_SHIFT);
+       msg = *((u32 *)&dbell);
+       /* TODO : get doorbell register mapping */
+       writel(cpu_to_le32(msg), conn->ep->qp.ctx_base);
+}
+
+
+/**
+ * bnx2i_put_rq_buf - Replenish RQ buffer, if required ring on chip doorbell
+ * @conn:      iscsi connection on which event to post
+ * @count:     number of RQ buffer being posted to chip
+ *
+ * No need to ring hardware doorbell for 57710 family of devices
+ */
+void bnx2i_put_rq_buf(struct bnx2i_conn *bnx2i_conn, int count)
+{
+       struct bnx2i_5771x_sq_rq_db *rq_db;
+       u16 hi_bit = (bnx2i_conn->ep->qp.rq_prod_idx & 0x8000);
+       struct bnx2i_endpoint *ep = bnx2i_conn->ep;
+
+       ep->qp.rqe_left += count;
+       ep->qp.rq_prod_idx &= 0x7FFF;
+       ep->qp.rq_prod_idx += count;
+
+       if (ep->qp.rq_prod_idx > bnx2i_conn->hba->max_rqes) {
+               ep->qp.rq_prod_idx %= bnx2i_conn->hba->max_rqes;
+               if (!hi_bit)
+                       ep->qp.rq_prod_idx |= 0x8000;
+       } else
+               ep->qp.rq_prod_idx |= hi_bit;
+
+       if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) {
+               rq_db = (struct bnx2i_5771x_sq_rq_db *) ep->qp.rq_pgtbl_virt;
+               rq_db->prod_idx = ep->qp.rq_prod_idx;
+               /* no need to ring hardware doorbell for 57710 */
+       } else {
+               writew(ep->qp.rq_prod_idx,
+                      ep->qp.ctx_base + CNIC_RECV_DOORBELL);
+       }
+       mmiowb();
+}
+
+
+/**
+ * bnx2i_ring_sq_dbell - Ring SQ doorbell to wake-up the processing engine
+ * @conn:              iscsi connection to which new SQ entries belong
+ * @count:             number of SQ WQEs to post
+ *
+ * SQ DB is updated in host memory and TX Doorbell is rung for 57710 family
+ *     of devices. For 5706/5708/5709 new SQ WQE count is written into the
+ *     doorbell register
+ */
+static void bnx2i_ring_sq_dbell(struct bnx2i_conn *bnx2i_conn, int count)
+{
+       struct bnx2i_5771x_sq_rq_db *sq_db;
+       struct bnx2i_endpoint *ep = bnx2i_conn->ep;
+
+       ep->num_active_cmds++;
+       wmb();  /* flush SQ WQE memory before the doorbell is rung */
+       if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) {
+               sq_db = (struct bnx2i_5771x_sq_rq_db *) ep->qp.sq_pgtbl_virt;
+               sq_db->prod_idx = ep->qp.sq_prod_idx;
+               bnx2i_ring_577xx_doorbell(bnx2i_conn);
+       } else
+               writew(count, ep->qp.ctx_base + CNIC_SEND_DOORBELL);
+
+       mmiowb(); /* flush posted PCI writes */
+}
+
+
+/**
+ * bnx2i_ring_dbell_update_sq_params - update SQ driver parameters
+ * @conn:      iscsi connection to which new SQ entries belong
+ * @count:     number of SQ WQEs to post
+ *
+ * this routine will update SQ driver parameters and ring the doorbell
+ */
+static void bnx2i_ring_dbell_update_sq_params(struct bnx2i_conn *bnx2i_conn,
+                                             int count)
+{
+       int tmp_cnt;
+
+       if (count == 1) {
+               if (bnx2i_conn->ep->qp.sq_prod_qe ==
+                   bnx2i_conn->ep->qp.sq_last_qe)
+                       bnx2i_conn->ep->qp.sq_prod_qe =
+                                               bnx2i_conn->ep->qp.sq_first_qe;
+               else
+                       bnx2i_conn->ep->qp.sq_prod_qe++;
+       } else {
+               if ((bnx2i_conn->ep->qp.sq_prod_qe + count) <=
+                   bnx2i_conn->ep->qp.sq_last_qe)
+                       bnx2i_conn->ep->qp.sq_prod_qe += count;
+               else {
+                       tmp_cnt = bnx2i_conn->ep->qp.sq_last_qe -
+                               bnx2i_conn->ep->qp.sq_prod_qe;
+                       bnx2i_conn->ep->qp.sq_prod_qe =
+                               &bnx2i_conn->ep->qp.sq_first_qe[count -
+                                                               (tmp_cnt + 1)];
+               }
+       }
+       bnx2i_conn->ep->qp.sq_prod_idx += count;
+       /* Ring the doorbell */
+       bnx2i_ring_sq_dbell(bnx2i_conn, bnx2i_conn->ep->qp.sq_prod_idx);
+}
+
+
+/**
+ * bnx2i_send_iscsi_login - post iSCSI login request MP WQE to hardware
+ * @conn:      iscsi connection
+ * @cmd:       driver command structure which is requesting
+ *             a WQE to sent to chip for further processing
+ *
+ * prepare and post an iSCSI Login request WQE to CNIC firmware
+ */
+int bnx2i_send_iscsi_login(struct bnx2i_conn *bnx2i_conn,
+                          struct iscsi_task *task)
+{
+       struct bnx2i_cmd *bnx2i_cmd;
+       struct bnx2i_login_request *login_wqe;
+       struct iscsi_login *login_hdr;
+       u32 dword;
+
+       bnx2i_cmd = (struct bnx2i_cmd *)task->dd_data;
+       login_hdr = (struct iscsi_login *)task->hdr;
+       login_wqe = (struct bnx2i_login_request *)
+                                               bnx2i_conn->ep->qp.sq_prod_qe;
+
+       login_wqe->op_code = login_hdr->opcode;
+       login_wqe->op_attr = login_hdr->flags;
+       login_wqe->version_max = login_hdr->max_version;
+       login_wqe->version_min = login_hdr->min_version;
+       login_wqe->data_length = ntoh24(login_hdr->dlength);
+       login_wqe->isid_lo = *((u32 *) login_hdr->isid);
+       login_wqe->isid_hi = *((u16 *) login_hdr->isid + 2);
+       login_wqe->tsih = login_hdr->tsih;
+       login_wqe->itt = task->itt |
+               (ISCSI_TASK_TYPE_MPATH << ISCSI_LOGIN_REQUEST_TYPE_SHIFT);
+       login_wqe->cid = login_hdr->cid;
+
+       login_wqe->cmd_sn = be32_to_cpu(login_hdr->cmdsn);
+       login_wqe->exp_stat_sn = be32_to_cpu(login_hdr->exp_statsn);
+
+       login_wqe->resp_bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.resp_bd_dma;
+       login_wqe->resp_bd_list_addr_hi =
+               (u32) ((u64) bnx2i_conn->gen_pdu.resp_bd_dma >> 32);
+
+       dword = ((1 << ISCSI_LOGIN_REQUEST_NUM_RESP_BDS_SHIFT) |
+                (bnx2i_conn->gen_pdu.resp_buf_size <<
+                 ISCSI_LOGIN_REQUEST_RESP_BUFFER_LENGTH_SHIFT));
+       login_wqe->resp_buffer = dword;
+       login_wqe->flags = 0;
+       login_wqe->bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.req_bd_dma;
+       login_wqe->bd_list_addr_hi =
+               (u32) ((u64) bnx2i_conn->gen_pdu.req_bd_dma >> 32);
+       login_wqe->num_bds = 1;
+       login_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
+
+       bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
+       return 0;
+}
+
+/**
+ * bnx2i_send_iscsi_tmf - post iSCSI task management request MP WQE to hardware
+ * @conn:      iscsi connection
+ * @mtask:     driver command structure which is requesting
+ *             a WQE to sent to chip for further processing
+ *
+ * prepare and post an iSCSI Login request WQE to CNIC firmware
+ */
+int bnx2i_send_iscsi_tmf(struct bnx2i_conn *bnx2i_conn,
+                        struct iscsi_task *mtask)
+{
+       struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
+       struct iscsi_tm *tmfabort_hdr;
+       struct scsi_cmnd *ref_sc;
+       struct iscsi_task *ctask;
+       struct bnx2i_cmd *bnx2i_cmd;
+       struct bnx2i_tmf_request *tmfabort_wqe;
+       u32 dword;
+
+       bnx2i_cmd = (struct bnx2i_cmd *)mtask->dd_data;
+       tmfabort_hdr = (struct iscsi_tm *)mtask->hdr;
+       tmfabort_wqe = (struct bnx2i_tmf_request *)
+                                               bnx2i_conn->ep->qp.sq_prod_qe;
+
+       tmfabort_wqe->op_code = tmfabort_hdr->opcode;
+       tmfabort_wqe->op_attr = 0;
+       tmfabort_wqe->op_attr =
+               ISCSI_TMF_REQUEST_ALWAYS_ONE | ISCSI_TM_FUNC_ABORT_TASK;
+       tmfabort_wqe->lun[0] = be32_to_cpu(tmfabort_hdr->lun[0]);
+       tmfabort_wqe->lun[1] = be32_to_cpu(tmfabort_hdr->lun[1]);
+
+       tmfabort_wqe->itt = (mtask->itt | (ISCSI_TASK_TYPE_MPATH << 14));
+       tmfabort_wqe->reserved2 = 0;
+       tmfabort_wqe->cmd_sn = be32_to_cpu(tmfabort_hdr->cmdsn);
+
+       ctask = iscsi_itt_to_task(conn, tmfabort_hdr->rtt);
+       if (!ctask || ctask->sc)
+               /*
+                * the iscsi layer must have completed the cmd while this
+                * was starting up.
+                */
+               return 0;
+       ref_sc = ctask->sc;
+
+       if (ref_sc->sc_data_direction == DMA_TO_DEVICE)
+               dword = (ISCSI_TASK_TYPE_WRITE << ISCSI_CMD_REQUEST_TYPE_SHIFT);
+       else
+               dword = (ISCSI_TASK_TYPE_READ << ISCSI_CMD_REQUEST_TYPE_SHIFT);
+       tmfabort_wqe->ref_itt = (dword | tmfabort_hdr->rtt);
+       tmfabort_wqe->ref_cmd_sn = be32_to_cpu(tmfabort_hdr->refcmdsn);
+
+       tmfabort_wqe->bd_list_addr_lo = (u32) bnx2i_conn->hba->mp_bd_dma;
+       tmfabort_wqe->bd_list_addr_hi = (u32)
+                               ((u64) bnx2i_conn->hba->mp_bd_dma >> 32);
+       tmfabort_wqe->num_bds = 1;
+       tmfabort_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
+
+       bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
+       return 0;
+}
+
+/**
+ * bnx2i_send_iscsi_scsicmd - post iSCSI scsicmd request WQE to hardware
+ * @conn:      iscsi connection
+ * @cmd:       driver command structure which is requesting
+ *             a WQE to sent to chip for further processing
+ *
+ * prepare and post an iSCSI SCSI-CMD request WQE to CNIC firmware
+ */
+int bnx2i_send_iscsi_scsicmd(struct bnx2i_conn *bnx2i_conn,
+                            struct bnx2i_cmd *cmd)
+{
+       struct bnx2i_cmd_request *scsi_cmd_wqe;
+
+       scsi_cmd_wqe = (struct bnx2i_cmd_request *)
+                                               bnx2i_conn->ep->qp.sq_prod_qe;
+       memcpy(scsi_cmd_wqe, &cmd->req, sizeof(struct bnx2i_cmd_request));
+       scsi_cmd_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
+
+       bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
+       return 0;
+}
+
+/**
+ * bnx2i_send_iscsi_nopout - post iSCSI NOPOUT request WQE to hardware
+ * @conn:              iscsi connection
+ * @cmd:               driver command structure which is requesting
+ *                     a WQE to sent to chip for further processing
+ * @ttt:               TTT to be used when building pdu header
+ * @datap:             payload buffer pointer
+ * @data_len:          payload data length
+ * @unsol:             indicated whether nopout pdu is unsolicited pdu or
+ *                     in response to target's NOPIN w/ TTT != FFFFFFFF
+ *
+ * prepare and post a nopout request WQE to CNIC firmware
+ */
+int bnx2i_send_iscsi_nopout(struct bnx2i_conn *bnx2i_conn,
+                           struct iscsi_task *task, u32 ttt,
+                           char *datap, int data_len, int unsol)
+{
+       struct bnx2i_endpoint *ep = bnx2i_conn->ep;
+       struct bnx2i_cmd *bnx2i_cmd;
+       struct bnx2i_nop_out_request *nopout_wqe;
+       struct iscsi_nopout *nopout_hdr;
+
+       bnx2i_cmd = (struct bnx2i_cmd *)task->dd_data;
+       nopout_hdr = (struct iscsi_nopout *)task->hdr;
+       nopout_wqe = (struct bnx2i_nop_out_request *)ep->qp.sq_prod_qe;
+       nopout_wqe->op_code = nopout_hdr->opcode;
+       nopout_wqe->op_attr = ISCSI_FLAG_CMD_FINAL;
+       memcpy(nopout_wqe->lun, nopout_hdr->lun, 8);
+
+       if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) {
+               u32 tmp = nopout_hdr->lun[0];
+               /* 57710 requires LUN field to be swapped */
+               nopout_hdr->lun[0] = nopout_hdr->lun[1];
+               nopout_hdr->lun[1] = tmp;
+       }
+
+       nopout_wqe->itt = ((u16)task->itt |
+                          (ISCSI_TASK_TYPE_MPATH <<
+                           ISCSI_TMF_REQUEST_TYPE_SHIFT));
+       nopout_wqe->ttt = ttt;
+       nopout_wqe->flags = 0;
+       if (!unsol)
+               nopout_wqe->flags = ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION;
+       else if (nopout_hdr->itt == RESERVED_ITT)
+               nopout_wqe->flags = ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION;
+
+       nopout_wqe->cmd_sn = be32_to_cpu(nopout_hdr->cmdsn);
+       nopout_wqe->data_length = data_len;
+       if (data_len) {
+               /* handle payload data, not required in first release */
+               printk(KERN_ALERT "NOPOUT: WARNING!! payload len != 0\n");
+       } else {
+               nopout_wqe->bd_list_addr_lo = (u32)
+                                       bnx2i_conn->hba->mp_bd_dma;
+               nopout_wqe->bd_list_addr_hi =
+                       (u32) ((u64) bnx2i_conn->hba->mp_bd_dma >> 32);
+               nopout_wqe->num_bds = 1;
+       }
+       nopout_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
+
+       bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
+       return 0;
+}
+
+
+/**
+ * bnx2i_send_iscsi_logout - post iSCSI logout request WQE to hardware
+ * @conn:      iscsi connection
+ * @cmd:       driver command structure which is requesting
+ *             a WQE to sent to chip for further processing
+ *
+ * prepare and post logout request WQE to CNIC firmware
+ */
+int bnx2i_send_iscsi_logout(struct bnx2i_conn *bnx2i_conn,
+                           struct iscsi_task *task)
+{
+       struct bnx2i_cmd *bnx2i_cmd;
+       struct bnx2i_logout_request *logout_wqe;
+       struct iscsi_logout *logout_hdr;
+
+       bnx2i_cmd = (struct bnx2i_cmd *)task->dd_data;
+       logout_hdr = (struct iscsi_logout *)task->hdr;
+
+       logout_wqe = (struct bnx2i_logout_request *)
+                                               bnx2i_conn->ep->qp.sq_prod_qe;
+       memset(logout_wqe, 0x00, sizeof(struct bnx2i_logout_request));
+
+       logout_wqe->op_code = logout_hdr->opcode;
+       logout_wqe->cmd_sn = be32_to_cpu(logout_hdr->cmdsn);
+       logout_wqe->op_attr =
+                       logout_hdr->flags | ISCSI_LOGOUT_REQUEST_ALWAYS_ONE;
+       logout_wqe->itt = ((u16)task->itt |
+                          (ISCSI_TASK_TYPE_MPATH <<
+                           ISCSI_LOGOUT_REQUEST_TYPE_SHIFT));
+       logout_wqe->data_length = 0;
+       logout_wqe->cid = 0;
+
+       logout_wqe->bd_list_addr_lo = (u32) bnx2i_conn->hba->mp_bd_dma;
+       logout_wqe->bd_list_addr_hi = (u32)
+                               ((u64) bnx2i_conn->hba->mp_bd_dma >> 32);
+       logout_wqe->num_bds = 1;
+       logout_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
+
+       bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
+       return 0;
+}
+
+
+/**
+ * bnx2i_update_iscsi_conn - post iSCSI logout request WQE to hardware
+ * @conn:      iscsi connection which requires iscsi parameter update
+ *
+ * sends down iSCSI Conn Update request to move iSCSI conn to FFP
+ */
+void bnx2i_update_iscsi_conn(struct iscsi_conn *conn)
+{
+       struct bnx2i_conn *bnx2i_conn = conn->dd_data;
+       struct bnx2i_hba *hba = bnx2i_conn->hba;
+       struct kwqe *kwqe_arr[2];
+       struct iscsi_kwqe_conn_update *update_wqe;
+       struct iscsi_kwqe_conn_update conn_update_kwqe;
+
+       update_wqe = &conn_update_kwqe;
+
+       update_wqe->hdr.op_code = ISCSI_KWQE_OPCODE_UPDATE_CONN;
+       update_wqe->hdr.flags =
+               (ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
+
+       /* 5771x requires conn context id to be passed as is */
+       if (test_bit(BNX2I_NX2_DEV_57710, &bnx2i_conn->ep->hba->cnic_dev_type))
+               update_wqe->context_id = bnx2i_conn->ep->ep_cid;
+       else
+               update_wqe->context_id = (bnx2i_conn->ep->ep_cid >> 7);
+       update_wqe->conn_flags = 0;
+       if (conn->hdrdgst_en)
+               update_wqe->conn_flags |= ISCSI_KWQE_CONN_UPDATE_HEADER_DIGEST;
+       if (conn->datadgst_en)
+               update_wqe->conn_flags |= ISCSI_KWQE_CONN_UPDATE_DATA_DIGEST;
+       if (conn->session->initial_r2t_en)
+               update_wqe->conn_flags |= ISCSI_KWQE_CONN_UPDATE_INITIAL_R2T;
+       if (conn->session->imm_data_en)
+               update_wqe->conn_flags |= ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA;
+
+       update_wqe->max_send_pdu_length = conn->max_xmit_dlength;
+       update_wqe->max_recv_pdu_length = conn->max_recv_dlength;
+       update_wqe->first_burst_length = conn->session->first_burst;
+       update_wqe->max_burst_length = conn->session->max_burst;
+       update_wqe->exp_stat_sn = conn->exp_statsn;
+       update_wqe->max_outstanding_r2ts = conn->session->max_r2t;
+       update_wqe->session_error_recovery_level = conn->session->erl;
+       iscsi_conn_printk(KERN_ALERT, conn,
+                         "bnx2i: conn update - MBL 0x%x FBL 0x%x"
+                         "MRDSL_I 0x%x MRDSL_T 0x%x \n",
+                         update_wqe->max_burst_length,
+                         update_wqe->first_burst_length,
+                         update_wqe->max_recv_pdu_length,
+                         update_wqe->max_send_pdu_length);
+
+       kwqe_arr[0] = (struct kwqe *) update_wqe;
+       if (hba->cnic && hba->cnic->submit_kwqes)
+               hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, 1);
+}
+
+
+/**
+ * bnx2i_ep_ofld_timer - post iSCSI logout request WQE to hardware
+ * @data:      endpoint (transport handle) structure pointer
+ *
+ * routine to handle connection offload/destroy request timeout
+ */
+void bnx2i_ep_ofld_timer(unsigned long data)
+{
+       struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) data;
+
+       if (ep->state == EP_STATE_OFLD_START) {
+               printk(KERN_ALERT "ofld_timer: CONN_OFLD timeout\n");
+               ep->state = EP_STATE_OFLD_FAILED;
+       } else if (ep->state == EP_STATE_DISCONN_START) {
+               printk(KERN_ALERT "ofld_timer: CONN_DISCON timeout\n");
+               ep->state = EP_STATE_DISCONN_TIMEDOUT;
+       } else if (ep->state == EP_STATE_CLEANUP_START) {
+               printk(KERN_ALERT "ofld_timer: CONN_CLEANUP timeout\n");
+               ep->state = EP_STATE_CLEANUP_FAILED;
+       }
+
+       wake_up_interruptible(&ep->ofld_wait);
+}
+
+
+static int bnx2i_power_of2(u32 val)
+{
+       u32 power = 0;
+       if (val & (val - 1))
+               return power;
+       val--;
+       while (val) {
+               val = val >> 1;
+               power++;
+       }
+       return power;
+}
+
+
+/**
+ * bnx2i_send_cmd_cleanup_req - send iscsi cmd context clean-up request
+ * @hba:       adapter structure pointer
+ * @cmd:       driver command structure which is requesting
+ *             a WQE to sent to chip for further processing
+ *
+ * prepares and posts CONN_OFLD_REQ1/2 KWQE
+ */
+void bnx2i_send_cmd_cleanup_req(struct bnx2i_hba *hba, struct bnx2i_cmd *cmd)
+{
+       struct bnx2i_cleanup_request *cmd_cleanup;
+
+       cmd_cleanup =
+               (struct bnx2i_cleanup_request *)cmd->conn->ep->qp.sq_prod_qe;
+       memset(cmd_cleanup, 0x00, sizeof(struct bnx2i_cleanup_request));
+
+       cmd_cleanup->op_code = ISCSI_OPCODE_CLEANUP_REQUEST;
+       cmd_cleanup->itt = cmd->req.itt;
+       cmd_cleanup->cq_index = 0; /* CQ# used for completion, 5771x only */
+
+       bnx2i_ring_dbell_update_sq_params(cmd->conn, 1);
+}
+
+
+/**
+ * bnx2i_send_conn_destroy - initiates iscsi connection teardown process
+ * @hba:       adapter structure pointer
+ * @ep:                endpoint (transport indentifier) structure
+ *
+ * this routine prepares and posts CONN_OFLD_REQ1/2 KWQE to initiate
+ *     iscsi connection context clean-up process
+ */
+void bnx2i_send_conn_destroy(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
+{
+       struct kwqe *kwqe_arr[2];
+       struct iscsi_kwqe_conn_destroy conn_cleanup;
+
+       memset(&conn_cleanup, 0x00, sizeof(struct iscsi_kwqe_conn_destroy));
+
+       conn_cleanup.hdr.op_code = ISCSI_KWQE_OPCODE_DESTROY_CONN;
+       conn_cleanup.hdr.flags =
+               (ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
+       /* 5771x requires conn context id to be passed as is */
+       if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type))
+               conn_cleanup.context_id = ep->ep_cid;
+       else
+               conn_cleanup.context_id = (ep->ep_cid >> 7);
+
+       conn_cleanup.reserved0 = (u16)ep->ep_iscsi_cid;
+
+       kwqe_arr[0] = (struct kwqe *) &conn_cleanup;
+       if (hba->cnic && hba->cnic->submit_kwqes)
+               hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, 1);
+}
+
+
+/**
+ * bnx2i_570x_send_conn_ofld_req - initiates iscsi conn context setup process
+ * @hba:               adapter structure pointer
+ * @ep:                endpoint (transport indentifier) structure
+ *
+ * 5706/5708/5709 specific - prepares and posts CONN_OFLD_REQ1/2 KWQE
+ */
+static void bnx2i_570x_send_conn_ofld_req(struct bnx2i_hba *hba,
+                                         struct bnx2i_endpoint *ep)
+{
+       struct kwqe *kwqe_arr[2];
+       struct iscsi_kwqe_conn_offload1 ofld_req1;
+       struct iscsi_kwqe_conn_offload2 ofld_req2;
+       dma_addr_t dma_addr;
+       int num_kwqes = 2;
+       u32 *ptbl;
+
+       ofld_req1.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN1;
+       ofld_req1.hdr.flags =
+               (ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
+
+       ofld_req1.iscsi_conn_id = (u16) ep->ep_iscsi_cid;
+
+       dma_addr = ep->qp.sq_pgtbl_phys;
+       ofld_req1.sq_page_table_addr_lo = (u32) dma_addr;
+       ofld_req1.sq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32);
+
+       dma_addr = ep->qp.cq_pgtbl_phys;
+       ofld_req1.cq_page_table_addr_lo = (u32) dma_addr;
+       ofld_req1.cq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32);
+
+       ofld_req2.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN2;
+       ofld_req2.hdr.flags =
+               (ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
+
+       dma_addr = ep->qp.rq_pgtbl_phys;
+       ofld_req2.rq_page_table_addr_lo = (u32) dma_addr;
+       ofld_req2.rq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32);
+
+       ptbl = (u32 *) ep->qp.sq_pgtbl_virt;
+
+       ofld_req2.sq_first_pte.hi = *ptbl++;
+       ofld_req2.sq_first_pte.lo = *ptbl;
+
+       ptbl = (u32 *) ep->qp.cq_pgtbl_virt;
+       ofld_req2.cq_first_pte.hi = *ptbl++;
+       ofld_req2.cq_first_pte.lo = *ptbl;
+
+       kwqe_arr[0] = (struct kwqe *) &ofld_req1;
+       kwqe_arr[1] = (struct kwqe *) &ofld_req2;
+       ofld_req2.num_additional_wqes = 0;
+
+       if (hba->cnic && hba->cnic->submit_kwqes)
+               hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
+}
+
+
+/**
+ * bnx2i_5771x_send_conn_ofld_req - initiates iscsi connection context creation
+ * @hba:               adapter structure pointer
+ * @ep:                endpoint (transport indentifier) structure
+ *
+ * 57710 specific - prepares and posts CONN_OFLD_REQ1/2 KWQE
+ */
+static void bnx2i_5771x_send_conn_ofld_req(struct bnx2i_hba *hba,
+                                          struct bnx2i_endpoint *ep)
+{
+       struct kwqe *kwqe_arr[5];
+       struct iscsi_kwqe_conn_offload1 ofld_req1;
+       struct iscsi_kwqe_conn_offload2 ofld_req2;
+       struct iscsi_kwqe_conn_offload3 ofld_req3[1];
+       dma_addr_t dma_addr;
+       int num_kwqes = 2;
+       u32 *ptbl;
+
+       ofld_req1.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN1;
+       ofld_req1.hdr.flags =
+               (ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
+
+       ofld_req1.iscsi_conn_id = (u16) ep->ep_iscsi_cid;
+
+       dma_addr = ep->qp.sq_pgtbl_phys + ISCSI_SQ_DB_SIZE;
+       ofld_req1.sq_page_table_addr_lo = (u32) dma_addr;
+       ofld_req1.sq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32);
+
+       dma_addr = ep->qp.cq_pgtbl_phys + ISCSI_CQ_DB_SIZE;
+       ofld_req1.cq_page_table_addr_lo = (u32) dma_addr;
+       ofld_req1.cq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32);
+
+       ofld_req2.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN2;
+       ofld_req2.hdr.flags =
+               (ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
+
+       dma_addr = ep->qp.rq_pgtbl_phys + ISCSI_RQ_DB_SIZE;
+       ofld_req2.rq_page_table_addr_lo = (u32) dma_addr;
+       ofld_req2.rq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32);
+
+       ptbl = (u32 *)((u8 *)ep->qp.sq_pgtbl_virt + ISCSI_SQ_DB_SIZE);
+       ofld_req2.sq_first_pte.hi = *ptbl++;
+       ofld_req2.sq_first_pte.lo = *ptbl;
+
+       ptbl = (u32 *)((u8 *)ep->qp.cq_pgtbl_virt + ISCSI_CQ_DB_SIZE);
+       ofld_req2.cq_first_pte.hi = *ptbl++;
+       ofld_req2.cq_first_pte.lo = *ptbl;
+
+       kwqe_arr[0] = (struct kwqe *) &ofld_req1;
+       kwqe_arr[1] = (struct kwqe *) &ofld_req2;
+
+       ofld_req2.num_additional_wqes = 1;
+       memset(ofld_req3, 0x00, sizeof(ofld_req3[0]));
+       ptbl = (u32 *)((u8 *)ep->qp.rq_pgtbl_virt + ISCSI_RQ_DB_SIZE);
+       ofld_req3[0].qp_first_pte[0].hi = *ptbl++;
+       ofld_req3[0].qp_first_pte[0].lo = *ptbl;
+
+       kwqe_arr[2] = (struct kwqe *) ofld_req3;
+       /* need if we decide to go with multiple KCQE's per conn */
+       num_kwqes += 1;
+
+       if (hba->cnic && hba->cnic->submit_kwqes)
+               hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
+}
+
+/**
+ * bnx2i_send_conn_ofld_req - initiates iscsi connection context setup process
+ *
+ * @hba:               adapter structure pointer
+ * @ep:                endpoint (transport indentifier) structure
+ *
+ * this routine prepares and posts CONN_OFLD_REQ1/2 KWQE
+ */
+void bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
+{
+       if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type))
+               bnx2i_5771x_send_conn_ofld_req(hba, ep);
+       else
+               bnx2i_570x_send_conn_ofld_req(hba, ep);
+}
+
+
+/**
+ * setup_qp_page_tables - iscsi QP page table setup function
+ * @ep:                endpoint (transport indentifier) structure
+ *
+ * Sets up page tables for SQ/RQ/CQ, 1G/sec (5706/5708/5709) devices requires
+ *     64-bit address in big endian format. Whereas 10G/sec (57710) requires
+ *     PT in little endian format
+ */
+static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
+{
+       int num_pages;
+       u32 *ptbl;
+       dma_addr_t page;
+       int cnic_dev_10g;
+
+       if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type))
+               cnic_dev_10g = 1;
+       else
+               cnic_dev_10g = 0;
+
+       /* SQ page table */
+       memset(ep->qp.sq_pgtbl_virt, 0, ep->qp.sq_pgtbl_size);
+       num_pages = ep->qp.sq_mem_size / PAGE_SIZE;
+       page = ep->qp.sq_phys;
+
+       if (cnic_dev_10g)
+               ptbl = (u32 *)((u8 *)ep->qp.sq_pgtbl_virt + ISCSI_SQ_DB_SIZE);
+       else
+               ptbl = (u32 *) ep->qp.sq_pgtbl_virt;
+       while (num_pages--) {
+               if (cnic_dev_10g) {
+                       /* PTE is written in little endian format for 57710 */
+                       *ptbl = (u32) page;
+                       ptbl++;
+                       *ptbl = (u32) ((u64) page >> 32);
+                       ptbl++;
+                       page += PAGE_SIZE;
+               } else {
+                       /* PTE is written in big endian format for
+                        * 5706/5708/5709 devices */
+                       *ptbl = (u32) ((u64) page >> 32);
+                       ptbl++;
+                       *ptbl = (u32) page;
+                       ptbl++;
+                       page += PAGE_SIZE;
+               }
+       }
+
+       /* RQ page table */
+       memset(ep->qp.rq_pgtbl_virt, 0, ep->qp.rq_pgtbl_size);
+       num_pages = ep->qp.rq_mem_size / PAGE_SIZE;
+       page = ep->qp.rq_phys;
+
+       if (cnic_dev_10g)
+               ptbl = (u32 *)((u8 *)ep->qp.rq_pgtbl_virt + ISCSI_RQ_DB_SIZE);
+       else
+               ptbl = (u32 *) ep->qp.rq_pgtbl_virt;
+       while (num_pages--) {
+               if (cnic_dev_10g) {
+                       /* PTE is written in little endian format for 57710 */
+                       *ptbl = (u32) page;
+                       ptbl++;
+                       *ptbl = (u32) ((u64) page >> 32);
+                       ptbl++;
+                       page += PAGE_SIZE;
+               } else {
+                       /* PTE is written in big endian format for
+                        * 5706/5708/5709 devices */
+                       *ptbl = (u32) ((u64) page >> 32);
+                       ptbl++;
+                       *ptbl = (u32) page;
+                       ptbl++;
+                       page += PAGE_SIZE;
+               }
+       }
+
+       /* CQ page table */
+       memset(ep->qp.cq_pgtbl_virt, 0, ep->qp.cq_pgtbl_size);
+       num_pages = ep->qp.cq_mem_size / PAGE_SIZE;
+       page = ep->qp.cq_phys;
+
+       if (cnic_dev_10g)
+               ptbl = (u32 *)((u8 *)ep->qp.cq_pgtbl_virt + ISCSI_CQ_DB_SIZE);
+       else
+               ptbl = (u32 *) ep->qp.cq_pgtbl_virt;
+       while (num_pages--) {
+               if (cnic_dev_10g) {
+                       /* PTE is written in little endian format for 57710 */
+                       *ptbl = (u32) page;
+                       ptbl++;
+                       *ptbl = (u32) ((u64) page >> 32);
+                       ptbl++;
+                       page += PAGE_SIZE;
+               } else {
+                       /* PTE is written in big endian format for
+                        * 5706/5708/5709 devices */
+                       *ptbl = (u32) ((u64) page >> 32);
+                       ptbl++;
+                       *ptbl = (u32) page;
+                       ptbl++;
+                       page += PAGE_SIZE;
+               }
+       }
+}
+
+
+/**
+ * bnx2i_alloc_qp_resc - allocates required resources for QP.
+ * @hba:       adapter structure pointer
+ * @ep:                endpoint (transport indentifier) structure
+ *
+ * Allocate QP (transport layer for iSCSI connection) resources, DMA'able
+ *     memory for SQ/RQ/CQ and page tables. EP structure elements such
+ *     as producer/consumer indexes/pointers, queue sizes and page table
+ *     contents are setup
+ */
+int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
+{
+       struct bnx2i_5771x_cq_db *cq_db;
+
+       ep->hba = hba;
+       ep->conn = NULL;
+       ep->ep_cid = ep->ep_iscsi_cid = ep->ep_pg_cid = 0;
+
+       /* Allocate page table memory for SQ which is page aligned */
+       ep->qp.sq_mem_size = hba->max_sqes * BNX2I_SQ_WQE_SIZE;
+       ep->qp.sq_mem_size =
+               (ep->qp.sq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+       ep->qp.sq_pgtbl_size =
+               (ep->qp.sq_mem_size / PAGE_SIZE) * sizeof(void *);
+       ep->qp.sq_pgtbl_size =
+               (ep->qp.sq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+
+       ep->qp.sq_pgtbl_virt =
+               dma_alloc_coherent(&hba->pcidev->dev, ep->qp.sq_pgtbl_size,
+                                  &ep->qp.sq_pgtbl_phys, GFP_KERNEL);
+       if (!ep->qp.sq_pgtbl_virt) {
+               printk(KERN_ALERT "bnx2i: unable to alloc SQ PT mem (%d)\n",
+                                 ep->qp.sq_pgtbl_size);
+               goto mem_alloc_err;
+       }
+
+       /* Allocate memory area for actual SQ element */
+       ep->qp.sq_virt =
+               dma_alloc_coherent(&hba->pcidev->dev, ep->qp.sq_mem_size,
+                                  &ep->qp.sq_phys, GFP_KERNEL);
+       if (!ep->qp.sq_virt) {
+               printk(KERN_ALERT "bnx2i: unable to alloc SQ BD memory %d\n",
+                                 ep->qp.sq_mem_size);
+               goto mem_alloc_err;
+       }
+
+       memset(ep->qp.sq_virt, 0x00, ep->qp.sq_mem_size);
+       ep->qp.sq_first_qe = ep->qp.sq_virt;
+       ep->qp.sq_prod_qe = ep->qp.sq_first_qe;
+       ep->qp.sq_cons_qe = ep->qp.sq_first_qe;
+       ep->qp.sq_last_qe = &ep->qp.sq_first_qe[hba->max_sqes - 1];
+       ep->qp.sq_prod_idx = 0;
+       ep->qp.sq_cons_idx = 0;
+       ep->qp.sqe_left = hba->max_sqes;
+
+       /* Allocate page table memory for CQ which is page aligned */
+       ep->qp.cq_mem_size = hba->max_cqes * BNX2I_CQE_SIZE;
+       ep->qp.cq_mem_size =
+               (ep->qp.cq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+       ep->qp.cq_pgtbl_size =
+               (ep->qp.cq_mem_size / PAGE_SIZE) * sizeof(void *);
+       ep->qp.cq_pgtbl_size =
+               (ep->qp.cq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+
+       ep->qp.cq_pgtbl_virt =
+               dma_alloc_coherent(&hba->pcidev->dev, ep->qp.cq_pgtbl_size,
+                                  &ep->qp.cq_pgtbl_phys, GFP_KERNEL);
+       if (!ep->qp.cq_pgtbl_virt) {
+               printk(KERN_ALERT "bnx2i: unable to alloc CQ PT memory %d\n",
+                                 ep->qp.cq_pgtbl_size);
+               goto mem_alloc_err;
+       }
+
+       /* Allocate memory area for actual CQ element */
+       ep->qp.cq_virt =
+               dma_alloc_coherent(&hba->pcidev->dev, ep->qp.cq_mem_size,
+                                  &ep->qp.cq_phys, GFP_KERNEL);
+       if (!ep->qp.cq_virt) {
+               printk(KERN_ALERT "bnx2i: unable to alloc CQ BD memory %d\n",
+                                 ep->qp.cq_mem_size);
+               goto mem_alloc_err;
+       }
+       memset(ep->qp.cq_virt, 0x00, ep->qp.cq_mem_size);
+
+       ep->qp.cq_first_qe = ep->qp.cq_virt;
+       ep->qp.cq_prod_qe = ep->qp.cq_first_qe;
+       ep->qp.cq_cons_qe = ep->qp.cq_first_qe;
+       ep->qp.cq_last_qe = &ep->qp.cq_first_qe[hba->max_cqes - 1];
+       ep->qp.cq_prod_idx = 0;
+       ep->qp.cq_cons_idx = 0;
+       ep->qp.cqe_left = hba->max_cqes;
+       ep->qp.cqe_exp_seq_sn = ISCSI_INITIAL_SN;
+       ep->qp.cqe_size = hba->max_cqes;
+
+       /* Invalidate all EQ CQE index, req only for 57710 */
+       cq_db = (struct bnx2i_5771x_cq_db *) ep->qp.cq_pgtbl_virt;
+       memset(cq_db->sqn, 0xFF, sizeof(cq_db->sqn[0]) * BNX2X_MAX_CQS);
+
+       /* Allocate page table memory for RQ which is page aligned */
+       ep->qp.rq_mem_size = hba->max_rqes * BNX2I_RQ_WQE_SIZE;
+       ep->qp.rq_mem_size =
+               (ep->qp.rq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+       ep->qp.rq_pgtbl_size =
+               (ep->qp.rq_mem_size / PAGE_SIZE) * sizeof(void *);
+       ep->qp.rq_pgtbl_size =
+               (ep->qp.rq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+
+       ep->qp.rq_pgtbl_virt =
+               dma_alloc_coherent(&hba->pcidev->dev, ep->qp.rq_pgtbl_size,
+                                  &ep->qp.rq_pgtbl_phys, GFP_KERNEL);
+       if (!ep->qp.rq_pgtbl_virt) {
+               printk(KERN_ALERT "bnx2i: unable to alloc RQ PT mem %d\n",
+                                 ep->qp.rq_pgtbl_size);
+               goto mem_alloc_err;
+       }
+
+       /* Allocate memory area for actual RQ element */
+       ep->qp.rq_virt =
+               dma_alloc_coherent(&hba->pcidev->dev, ep->qp.rq_mem_size,
+                                  &ep->qp.rq_phys, GFP_KERNEL);
+       if (!ep->qp.rq_virt) {
+               printk(KERN_ALERT "bnx2i: unable to alloc RQ BD memory %d\n",
+                                 ep->qp.rq_mem_size);
+               goto mem_alloc_err;
+       }
+
+       ep->qp.rq_first_qe = ep->qp.rq_virt;
+       ep->qp.rq_prod_qe = ep->qp.rq_first_qe;
+       ep->qp.rq_cons_qe = ep->qp.rq_first_qe;
+       ep->qp.rq_last_qe = &ep->qp.rq_first_qe[hba->max_rqes - 1];
+       ep->qp.rq_prod_idx = 0x8000;
+       ep->qp.rq_cons_idx = 0;
+       ep->qp.rqe_left = hba->max_rqes;
+
+       setup_qp_page_tables(ep);
+
+       return 0;
+
+mem_alloc_err:
+       bnx2i_free_qp_resc(hba, ep);
+       return -ENOMEM;
+}
+
+
+
+/**
+ * bnx2i_free_qp_resc - free memory resources held by QP
+ * @hba:       adapter structure pointer
+ * @ep:        endpoint (transport indentifier) structure
+ *
+ * Free QP resources - SQ/RQ/CQ memory and page tables.
+ */
+void bnx2i_free_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
+{
+       if (ep->qp.ctx_base) {
+               iounmap(ep->qp.ctx_base);
+               ep->qp.ctx_base = NULL;
+       }
+       /* Free SQ mem */
+       if (ep->qp.sq_pgtbl_virt) {
+               dma_free_coherent(&hba->pcidev->dev, ep->qp.sq_pgtbl_size,
+                                 ep->qp.sq_pgtbl_virt, ep->qp.sq_pgtbl_phys);
+               ep->qp.sq_pgtbl_virt = NULL;
+               ep->qp.sq_pgtbl_phys = 0;
+       }
+       if (ep->qp.sq_virt) {
+               dma_free_coherent(&hba->pcidev->dev, ep->qp.sq_mem_size,
+                                 ep->qp.sq_virt, ep->qp.sq_phys);
+               ep->qp.sq_virt = NULL;
+               ep->qp.sq_phys = 0;
+       }
+
+       /* Free RQ mem */
+       if (ep->qp.rq_pgtbl_virt) {
+               dma_free_coherent(&hba->pcidev->dev, ep->qp.rq_pgtbl_size,
+                                 ep->qp.rq_pgtbl_virt, ep->qp.rq_pgtbl_phys);
+               ep->qp.rq_pgtbl_virt = NULL;
+               ep->qp.rq_pgtbl_phys = 0;
+       }
+       if (ep->qp.rq_virt) {
+               dma_free_coherent(&hba->pcidev->dev, ep->qp.rq_mem_size,
+                                 ep->qp.rq_virt, ep->qp.rq_phys);
+               ep->qp.rq_virt = NULL;
+               ep->qp.rq_phys = 0;
+       }
+
+       /* Free CQ mem */
+       if (ep->qp.cq_pgtbl_virt) {
+               dma_free_coherent(&hba->pcidev->dev, ep->qp.cq_pgtbl_size,
+                                 ep->qp.cq_pgtbl_virt, ep->qp.cq_pgtbl_phys);
+               ep->qp.cq_pgtbl_virt = NULL;
+               ep->qp.cq_pgtbl_phys = 0;
+       }
+       if (ep->qp.cq_virt) {
+               dma_free_coherent(&hba->pcidev->dev, ep->qp.cq_mem_size,
+                                 ep->qp.cq_virt, ep->qp.cq_phys);
+               ep->qp.cq_virt = NULL;
+               ep->qp.cq_phys = 0;
+       }
+}
+
+
+/**
+ * bnx2i_send_fw_iscsi_init_msg - initiates initial handshake with iscsi f/w
+ * @hba:       adapter structure pointer
+ *
+ * Send down iscsi_init KWQEs which initiates the initial handshake with the f/w
+ *     This results in iSCSi support validation and on-chip context manager
+ *     initialization.  Firmware completes this handshake with a CQE carrying
+ *     the result of iscsi support validation. Parameter carried by
+ *     iscsi init request determines the number of offloaded connection and
+ *     tolerance level for iscsi protocol violation this hba/chip can support
+ */
+int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba)
+{
+       struct kwqe *kwqe_arr[3];
+       struct iscsi_kwqe_init1 iscsi_init;
+       struct iscsi_kwqe_init2 iscsi_init2;
+       int rc = 0;
+       u64 mask64;
+
+       bnx2i_adjust_qp_size(hba);
+
+       iscsi_init.flags =
+               ISCSI_PAGE_SIZE_4K << ISCSI_KWQE_INIT1_PAGE_SIZE_SHIFT;
+       if (en_tcp_dack)
+               iscsi_init.flags |= ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE;
+       iscsi_init.reserved0 = 0;
+       iscsi_init.num_cqs = 1;
+       iscsi_init.hdr.op_code = ISCSI_KWQE_OPCODE_INIT1;
+       iscsi_init.hdr.flags =
+               (ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
+
+       iscsi_init.dummy_buffer_addr_lo = (u32) hba->dummy_buf_dma;
+       iscsi_init.dummy_buffer_addr_hi =
+               (u32) ((u64) hba->dummy_buf_dma >> 32);
+
+       hba->ctx_ccell_tasks =
+                       ((hba->num_ccell & 0xFFFF) | (hba->max_sqes << 16));
+       iscsi_init.num_ccells_per_conn = hba->num_ccell;
+       iscsi_init.num_tasks_per_conn = hba->max_sqes;
+       iscsi_init.sq_wqes_per_page = PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
+       iscsi_init.sq_num_wqes = hba->max_sqes;
+       iscsi_init.cq_log_wqes_per_page =
+               (u8) bnx2i_power_of2(PAGE_SIZE / BNX2I_CQE_SIZE);
+       iscsi_init.cq_num_wqes = hba->max_cqes;
+       iscsi_init.cq_num_pages = (hba->max_cqes * BNX2I_CQE_SIZE +
+                                  (PAGE_SIZE - 1)) / PAGE_SIZE;
+       iscsi_init.sq_num_pages = (hba->max_sqes * BNX2I_SQ_WQE_SIZE +
+                                  (PAGE_SIZE - 1)) / PAGE_SIZE;
+       iscsi_init.rq_buffer_size = BNX2I_RQ_WQE_SIZE;
+       iscsi_init.rq_num_wqes = hba->max_rqes;
+
+
+       iscsi_init2.hdr.op_code = ISCSI_KWQE_OPCODE_INIT2;
+       iscsi_init2.hdr.flags =
+               (ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT);
+       iscsi_init2.max_cq_sqn = hba->max_cqes * 2 + 1;
+       mask64 = 0x0ULL;
+       mask64 |= (
+               /* CISCO MDS */
+               (1UL <<
+                 ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_TTT_NOT_RSRV) |
+               /* HP MSA1510i */
+               (1UL <<
+                 ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_EXP_DATASN) |
+               /* EMC */
+               (1ULL << ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_LUN));
+       if (error_mask1)
+               iscsi_init2.error_bit_map[0] = error_mask1;
+       else
+               iscsi_init2.error_bit_map[0] = (u32) mask64;
+
+       if (error_mask2)
+               iscsi_init2.error_bit_map[1] = error_mask2;
+       else
+               iscsi_init2.error_bit_map[1] = (u32) (mask64 >> 32);
+
+       iscsi_error_mask = mask64;
+
+       kwqe_arr[0] = (struct kwqe *) &iscsi_init;
+       kwqe_arr[1] = (struct kwqe *) &iscsi_init2;
+
+       if (hba->cnic && hba->cnic->submit_kwqes)
+               rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, 2);
+       return rc;
+}
+
+
+/**
+ * bnx2i_process_scsi_cmd_resp - this function handles scsi cmd completion.
+ * @conn:      iscsi connection
+ * @cqe:       pointer to newly DMA'ed CQE entry for processing
+ *
+ * process SCSI CMD Response CQE & complete the request to SCSI-ML
+ */
+static int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session,
+                                      struct bnx2i_conn *bnx2i_conn,
+                                      struct cqe *cqe)
+{
+       struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
+       struct bnx2i_cmd_response *resp_cqe;
+       struct bnx2i_cmd *bnx2i_cmd;
+       struct iscsi_task *task;
+       struct iscsi_cmd_rsp *hdr;
+       u32 datalen = 0;
+
+       resp_cqe = (struct bnx2i_cmd_response *)cqe;
+       spin_lock(&session->lock);
+       task = iscsi_itt_to_task(conn,
+                                resp_cqe->itt & ISCSI_CMD_RESPONSE_INDEX);
+       if (!task)
+               goto fail;
+
+       bnx2i_cmd = task->dd_data;
+
+       if (bnx2i_cmd->req.op_attr & ISCSI_CMD_REQUEST_READ) {
+               conn->datain_pdus_cnt +=
+                       resp_cqe->task_stat.read_stat.num_data_outs;
+               conn->rxdata_octets +=
+                       bnx2i_cmd->req.total_data_transfer_length;
+       } else {
+               conn->dataout_pdus_cnt +=
+                       resp_cqe->task_stat.read_stat.num_data_outs;
+               conn->r2t_pdus_cnt +=
+                       resp_cqe->task_stat.read_stat.num_r2ts;
+               conn->txdata_octets +=
+                       bnx2i_cmd->req.total_data_transfer_length;
+       }
+       bnx2i_iscsi_unmap_sg_list(bnx2i_cmd);
+
+       hdr = (struct iscsi_cmd_rsp *)task->hdr;
+       resp_cqe = (struct bnx2i_cmd_response *)cqe;
+       hdr->opcode = resp_cqe->op_code;
+       hdr->max_cmdsn = cpu_to_be32(resp_cqe->max_cmd_sn);
+       hdr->exp_cmdsn = cpu_to_be32(resp_cqe->exp_cmd_sn);
+       hdr->response = resp_cqe->response;
+       hdr->cmd_status = resp_cqe->status;
+       hdr->flags = resp_cqe->response_flags;
+       hdr->residual_count = cpu_to_be32(resp_cqe->residual_count);
+
+       if (resp_cqe->op_code == ISCSI_OP_SCSI_DATA_IN)
+               goto done;
+
+       if (resp_cqe->status == SAM_STAT_CHECK_CONDITION) {
+               datalen = resp_cqe->data_length;
+               if (datalen < 2)
+                       goto done;
+
+               if (datalen > BNX2I_RQ_WQE_SIZE) {
+                       iscsi_conn_printk(KERN_ERR, conn,
+                                         "sense data len %d > RQ sz\n",
+                                         datalen);
+                       datalen = BNX2I_RQ_WQE_SIZE;
+               } else if (datalen > ISCSI_DEF_MAX_RECV_SEG_LEN) {
+                       iscsi_conn_printk(KERN_ERR, conn,
+                                         "sense data len %d > conn data\n",
+                                         datalen);
+                       datalen = ISCSI_DEF_MAX_RECV_SEG_LEN;
+               }
+
+               bnx2i_get_rq_buf(bnx2i_cmd->conn, conn->data, datalen);
+               bnx2i_put_rq_buf(bnx2i_cmd->conn, 1);
+       }
+
+done:
+       __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr,
+                            conn->data, datalen);
+fail:
+       spin_unlock(&session->lock);
+       return 0;
+}
+
+
+/**
+ * bnx2i_process_login_resp - this function handles iscsi login response
+ * @session:           iscsi session pointer
+ * @bnx2i_conn:                iscsi connection pointer
+ * @cqe:               pointer to newly DMA'ed CQE entry for processing
+ *
+ * process Login Response CQE & complete it to open-iscsi user daemon
+ */
+static int bnx2i_process_login_resp(struct iscsi_session *session,
+                                   struct bnx2i_conn *bnx2i_conn,
+                                   struct cqe *cqe)
+{
+       struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
+       struct iscsi_task *task;
+       struct bnx2i_login_response *login;
+       struct iscsi_login_rsp *resp_hdr;
+       int pld_len;
+       int pad_len;
+
+       login = (struct bnx2i_login_response *) cqe;
+       spin_lock(&session->lock);
+       task = iscsi_itt_to_task(conn,
+                                login->itt & ISCSI_LOGIN_RESPONSE_INDEX);
+       if (!task)
+               goto done;
+
+       resp_hdr = (struct iscsi_login_rsp *) &bnx2i_conn->gen_pdu.resp_hdr;
+       memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
+       resp_hdr->opcode = login->op_code;
+       resp_hdr->flags = login->response_flags;
+       resp_hdr->max_version = login->version_max;
+       resp_hdr->active_version = login->version_active;;
+       resp_hdr->hlength = 0;
+
+       hton24(resp_hdr->dlength, login->data_length);
+       memcpy(resp_hdr->isid, &login->isid_lo, 6);
+       resp_hdr->tsih = cpu_to_be16(login->tsih);
+       resp_hdr->itt = task->hdr->itt;
+       resp_hdr->statsn = cpu_to_be32(login->stat_sn);
+       resp_hdr->exp_cmdsn = cpu_to_be32(login->exp_cmd_sn);
+       resp_hdr->max_cmdsn = cpu_to_be32(login->max_cmd_sn);
+       resp_hdr->status_class = login->status_class;
+       resp_hdr->status_detail = login->status_detail;
+       pld_len = login->data_length;
+       bnx2i_conn->gen_pdu.resp_wr_ptr =
+                                       bnx2i_conn->gen_pdu.resp_buf + pld_len;
+
+       pad_len = 0;
+       if (pld_len & 0x3)
+               pad_len = 4 - (pld_len % 4);
+
+       if (pad_len) {
+               int i = 0;
+               for (i = 0; i < pad_len; i++) {
+                       bnx2i_conn->gen_pdu.resp_wr_ptr[0] = 0;
+                       bnx2i_conn->gen_pdu.resp_wr_ptr++;
+               }
+       }
+
+       __iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr,
+               bnx2i_conn->gen_pdu.resp_buf,
+               bnx2i_conn->gen_pdu.resp_wr_ptr - bnx2i_conn->gen_pdu.resp_buf);
+done:
+       spin_unlock(&session->lock);
+       return 0;
+}
+
+/**
+ * bnx2i_process_tmf_resp - this function handles iscsi TMF response
+ * @session:           iscsi session pointer
+ * @bnx2i_conn:                iscsi connection pointer
+ * @cqe:               pointer to newly DMA'ed CQE entry for processing
+ *
+ * process iSCSI TMF Response CQE and wake up the driver eh thread.
+ */
+static int bnx2i_process_tmf_resp(struct iscsi_session *session,
+                                 struct bnx2i_conn *bnx2i_conn,
+                                 struct cqe *cqe)
+{
+       struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
+       struct iscsi_task *task;
+       struct bnx2i_tmf_response *tmf_cqe;
+       struct iscsi_tm_rsp *resp_hdr;
+
+       tmf_cqe = (struct bnx2i_tmf_response *)cqe;
+       spin_lock(&session->lock);
+       task = iscsi_itt_to_task(conn,
+                                tmf_cqe->itt & ISCSI_TMF_RESPONSE_INDEX);
+       if (!task)
+               goto done;
+
+       resp_hdr = (struct iscsi_tm_rsp *) &bnx2i_conn->gen_pdu.resp_hdr;
+       memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
+       resp_hdr->opcode = tmf_cqe->op_code;
+       resp_hdr->max_cmdsn = cpu_to_be32(tmf_cqe->max_cmd_sn);
+       resp_hdr->exp_cmdsn = cpu_to_be32(tmf_cqe->exp_cmd_sn);
+       resp_hdr->itt = task->hdr->itt;
+       resp_hdr->response = tmf_cqe->response;
+
+       __iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
+done:
+       spin_unlock(&session->lock);
+       return 0;
+}
+
+/**
+ * bnx2i_process_logout_resp - this function handles iscsi logout response
+ * @session:           iscsi session pointer
+ * @bnx2i_conn:                iscsi connection pointer
+ * @cqe:               pointer to newly DMA'ed CQE entry for processing
+ *
+ * process iSCSI Logout Response CQE & make function call to
+ * notify the user daemon.
+ */
+static int bnx2i_process_logout_resp(struct iscsi_session *session,
+                                    struct bnx2i_conn *bnx2i_conn,
+                                    struct cqe *cqe)
+{
+       struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
+       struct iscsi_task *task;
+       struct bnx2i_logout_response *logout;
+       struct iscsi_logout_rsp *resp_hdr;
+
+       logout = (struct bnx2i_logout_response *) cqe;
+       spin_lock(&session->lock);
+       task = iscsi_itt_to_task(conn,
+                                logout->itt & ISCSI_LOGOUT_RESPONSE_INDEX);
+       if (!task)
+               goto done;
+
+       resp_hdr = (struct iscsi_logout_rsp *) &bnx2i_conn->gen_pdu.resp_hdr;
+       memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
+       resp_hdr->opcode = logout->op_code;
+       resp_hdr->flags = logout->response;
+       resp_hdr->hlength = 0;
+
+       resp_hdr->itt = task->hdr->itt;
+       resp_hdr->statsn = task->hdr->exp_statsn;
+       resp_hdr->exp_cmdsn = cpu_to_be32(logout->exp_cmd_sn);
+       resp_hdr->max_cmdsn = cpu_to_be32(logout->max_cmd_sn);
+
+       resp_hdr->t2wait = cpu_to_be32(logout->time_to_wait);
+       resp_hdr->t2retain = cpu_to_be32(logout->time_to_retain);
+
+       __iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
+done:
+       spin_unlock(&session->lock);
+       return 0;
+}
+
+/**
+ * bnx2i_process_nopin_local_cmpl - this function handles iscsi nopin CQE
+ * @session:           iscsi session pointer
+ * @bnx2i_conn:                iscsi connection pointer
+ * @cqe:               pointer to newly DMA'ed CQE entry for processing
+ *
+ * process iSCSI NOPIN local completion CQE, frees IIT and command structures
+ */
+static void bnx2i_process_nopin_local_cmpl(struct iscsi_session *session,
+                                          struct bnx2i_conn *bnx2i_conn,
+                                          struct cqe *cqe)
+{
+       struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
+       struct bnx2i_nop_in_msg *nop_in;
+       struct iscsi_task *task;
+
+       nop_in = (struct bnx2i_nop_in_msg *)cqe;
+       spin_lock(&session->lock);
+       task = iscsi_itt_to_task(conn,
+                                nop_in->itt & ISCSI_NOP_IN_MSG_INDEX);
+       if (task)
+               iscsi_put_task(task);
+       spin_unlock(&session->lock);
+}
+
+/**
+ * bnx2i_unsol_pdu_adjust_rq - makes adjustments to RQ after unsol pdu is recvd
+ * @conn:      iscsi connection
+ *
+ * Firmware advances RQ producer index for every unsolicited PDU even if
+ *     payload data length is '0'. This function makes corresponding
+ *     adjustments on the driver side to match this f/w behavior
+ */
+static void bnx2i_unsol_pdu_adjust_rq(struct bnx2i_conn *bnx2i_conn)
+{
+       char dummy_rq_data[2];
+       bnx2i_get_rq_buf(bnx2i_conn, dummy_rq_data, 1);
+       bnx2i_put_rq_buf(bnx2i_conn, 1);
+}
+
+
+/**
+ * bnx2i_process_nopin_mesg - this function handles iscsi nopin CQE
+ * @session:           iscsi session pointer
+ * @bnx2i_conn:                iscsi connection pointer
+ * @cqe:               pointer to newly DMA'ed CQE entry for processing
+ *
+ * process iSCSI target's proactive iSCSI NOPIN request
+ */
+static int bnx2i_process_nopin_mesg(struct iscsi_session *session,
+                                    struct bnx2i_conn *bnx2i_conn,
+                                    struct cqe *cqe)
+{
+       struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
+       struct iscsi_task *task;
+       struct bnx2i_nop_in_msg *nop_in;
+       struct iscsi_nopin *hdr;
+       u32 itt;
+       int tgt_async_nop = 0;
+
+       nop_in = (struct bnx2i_nop_in_msg *)cqe;
+       itt = nop_in->itt & ISCSI_NOP_IN_MSG_INDEX;
+
+       spin_lock(&session->lock);
+       hdr = (struct iscsi_nopin *)&bnx2i_conn->gen_pdu.resp_hdr;
+       memset(hdr, 0, sizeof(struct iscsi_hdr));
+       hdr->opcode = nop_in->op_code;
+       hdr->max_cmdsn = cpu_to_be32(nop_in->max_cmd_sn);
+       hdr->exp_cmdsn = cpu_to_be32(nop_in->exp_cmd_sn);
+       hdr->ttt = cpu_to_be32(nop_in->ttt);
+
+       if (itt == (u16) RESERVED_ITT) {
+               bnx2i_unsol_pdu_adjust_rq(bnx2i_conn);
+               hdr->itt = RESERVED_ITT;
+               tgt_async_nop = 1;
+               goto done;
+       }
+
+       /* this is a response to one of our nop-outs */
+       task = iscsi_itt_to_task(conn, itt);
+       if (task) {
+               hdr->flags = ISCSI_FLAG_CMD_FINAL;
+               hdr->itt = task->hdr->itt;
+               hdr->ttt = cpu_to_be32(nop_in->ttt);
+               memcpy(hdr->lun, nop_in->lun, 8);
+       }
+done:
+       __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
+       spin_unlock(&session->lock);
+
+       return tgt_async_nop;
+}
+
+
+/**
+ * bnx2i_process_async_mesg - this function handles iscsi async message
+ * @session:           iscsi session pointer
+ * @bnx2i_conn:                iscsi connection pointer
+ * @cqe:               pointer to newly DMA'ed CQE entry for processing
+ *
+ * process iSCSI ASYNC Message
+ */
+static void bnx2i_process_async_mesg(struct iscsi_session *session,
+                                    struct bnx2i_conn *bnx2i_conn,
+                                    struct cqe *cqe)
+{
+       struct bnx2i_async_msg *async_cqe;
+       struct iscsi_async *resp_hdr;
+       u8 async_event;
+
+       bnx2i_unsol_pdu_adjust_rq(bnx2i_conn);
+
+       async_cqe = (struct bnx2i_async_msg *)cqe;
+       async_event = async_cqe->async_event;
+
+       if (async_event == ISCSI_ASYNC_MSG_SCSI_EVENT) {
+               iscsi_conn_printk(KERN_ALERT, bnx2i_conn->cls_conn->dd_data,
+                                 "async: scsi events not supported\n");
+               return;
+       }
+
+       spin_lock(&session->lock);
+       resp_hdr = (struct iscsi_async *) &bnx2i_conn->gen_pdu.resp_hdr;
+       memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
+       resp_hdr->opcode = async_cqe->op_code;
+       resp_hdr->flags = 0x80;
+
+       memcpy(resp_hdr->lun, async_cqe->lun, 8);
+       resp_hdr->exp_cmdsn = cpu_to_be32(async_cqe->exp_cmd_sn);
+       resp_hdr->max_cmdsn = cpu_to_be32(async_cqe->max_cmd_sn);
+
+       resp_hdr->async_event = async_cqe->async_event;
+       resp_hdr->async_vcode = async_cqe->async_vcode;
+
+       resp_hdr->param1 = cpu_to_be16(async_cqe->param1);
+       resp_hdr->param2 = cpu_to_be16(async_cqe->param2);
+       resp_hdr->param3 = cpu_to_be16(async_cqe->param3);
+
+       __iscsi_complete_pdu(bnx2i_conn->cls_conn->dd_data,
+                            (struct iscsi_hdr *)resp_hdr, NULL, 0);
+       spin_unlock(&session->lock);
+}
+
+
+/**
+ * bnx2i_process_reject_mesg - process iscsi reject pdu
+ * @session:           iscsi session pointer
+ * @bnx2i_conn:                iscsi connection pointer
+ * @cqe:               pointer to newly DMA'ed CQE entry for processing
+ *
+ * process iSCSI REJECT message
+ */
+static void bnx2i_process_reject_mesg(struct iscsi_session *session,
+                                     struct bnx2i_conn *bnx2i_conn,
+                                     struct cqe *cqe)
+{
+       struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
+       struct bnx2i_reject_msg *reject;
+       struct iscsi_reject *hdr;
+
+       reject = (struct bnx2i_reject_msg *) cqe;
+       if (reject->data_length) {
+               bnx2i_get_rq_buf(bnx2i_conn, conn->data, reject->data_length);
+               bnx2i_put_rq_buf(bnx2i_conn, 1);
+       } else
+               bnx2i_unsol_pdu_adjust_rq(bnx2i_conn);
+
+       spin_lock(&session->lock);
+       hdr = (struct iscsi_reject *) &bnx2i_conn->gen_pdu.resp_hdr;
+       memset(hdr, 0, sizeof(struct iscsi_hdr));
+       hdr->opcode = reject->op_code;
+       hdr->reason = reject->reason;
+       hton24(hdr->dlength, reject->data_length);
+       hdr->max_cmdsn = cpu_to_be32(reject->max_cmd_sn);
+       hdr->exp_cmdsn = cpu_to_be32(reject->exp_cmd_sn);
+       hdr->ffffffff = cpu_to_be32(RESERVED_ITT);
+       __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, conn->data,
+                            reject->data_length);
+       spin_unlock(&session->lock);
+}
+
+/**
+ * bnx2i_process_cmd_cleanup_resp - process scsi command clean-up completion
+ * @session:           iscsi session pointer
+ * @bnx2i_conn:                iscsi connection pointer
+ * @cqe:               pointer to newly DMA'ed CQE entry for processing
+ *
+ * process command cleanup response CQE during conn shutdown or error recovery
+ */
+static void bnx2i_process_cmd_cleanup_resp(struct iscsi_session *session,
+                                          struct bnx2i_conn *bnx2i_conn,
+                                          struct cqe *cqe)
+{
+       struct bnx2i_cleanup_response *cmd_clean_rsp;
+       struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
+       struct iscsi_task *task;
+
+       cmd_clean_rsp = (struct bnx2i_cleanup_response *)cqe;
+       spin_lock(&session->lock);
+       task = iscsi_itt_to_task(conn,
+                       cmd_clean_rsp->itt & ISCSI_CLEANUP_RESPONSE_INDEX);
+       if (!task)
+               printk(KERN_ALERT "bnx2i: cmd clean ITT %x not active\n",
+                       cmd_clean_rsp->itt & ISCSI_CLEANUP_RESPONSE_INDEX);
+       spin_unlock(&session->lock);
+       complete(&bnx2i_conn->cmd_cleanup_cmpl);
+}
+
+
+
+/**
+ * bnx2i_process_new_cqes - process newly DMA'ed CQE's
+ * @bnx2i_conn:                iscsi connection
+ *
+ * this function is called by generic KCQ handler to process all pending CQE's
+ */
+static void bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn)
+{
+       struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
+       struct iscsi_session *session = conn->session;
+       struct qp_info *qp = &bnx2i_conn->ep->qp;
+       struct bnx2i_nop_in_msg *nopin;
+       int tgt_async_msg;
+
+       while (1) {
+               nopin = (struct bnx2i_nop_in_msg *) qp->cq_cons_qe;
+               if (nopin->cq_req_sn != qp->cqe_exp_seq_sn)
+                       break;
+
+               if (unlikely(test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx)))
+                       break;
+
+               tgt_async_msg = 0;
+
+               switch (nopin->op_code) {
+               case ISCSI_OP_SCSI_CMD_RSP:
+               case ISCSI_OP_SCSI_DATA_IN:
+                       bnx2i_process_scsi_cmd_resp(session, bnx2i_conn,
+                                                   qp->cq_cons_qe);
+                       break;
+               case ISCSI_OP_LOGIN_RSP:
+                       bnx2i_process_login_resp(session, bnx2i_conn,
+                                                qp->cq_cons_qe);
+                       break;
+               case ISCSI_OP_SCSI_TMFUNC_RSP:
+                       bnx2i_process_tmf_resp(session, bnx2i_conn,
+                                              qp->cq_cons_qe);
+                       break;
+               case ISCSI_OP_LOGOUT_RSP:
+                       bnx2i_process_logout_resp(session, bnx2i_conn,
+                                                 qp->cq_cons_qe);
+                       break;
+               case ISCSI_OP_NOOP_IN:
+                       if (bnx2i_process_nopin_mesg(session, bnx2i_conn,
+                                                    qp->cq_cons_qe))
+                               tgt_async_msg = 1;
+                       break;
+               case ISCSI_OPCODE_NOPOUT_LOCAL_COMPLETION:
+                       bnx2i_process_nopin_local_cmpl(session, bnx2i_conn,
+                                                      qp->cq_cons_qe);
+                       break;
+               case ISCSI_OP_ASYNC_EVENT:
+                       bnx2i_process_async_mesg(session, bnx2i_conn,
+                                                qp->cq_cons_qe);
+                       tgt_async_msg = 1;
+                       break;
+               case ISCSI_OP_REJECT:
+                       bnx2i_process_reject_mesg(session, bnx2i_conn,
+                                                 qp->cq_cons_qe);
+                       break;
+               case ISCSI_OPCODE_CLEANUP_RESPONSE:
+                       bnx2i_process_cmd_cleanup_resp(session, bnx2i_conn,
+                                                      qp->cq_cons_qe);
+                       break;
+               default:
+                       printk(KERN_ALERT "bnx2i: unknown opcode 0x%x\n",
+                                         nopin->op_code);
+               }
+
+               if (!tgt_async_msg)
+                       bnx2i_conn->ep->num_active_cmds--;
+
+               /* clear out in production version only, till beta keep opcode
+                * field intact, will be helpful in debugging (context dump)
+                * nopin->op_code = 0;
+                */
+               qp->cqe_exp_seq_sn++;
+               if (qp->cqe_exp_seq_sn == (qp->cqe_size * 2 + 1))
+                       qp->cqe_exp_seq_sn = ISCSI_INITIAL_SN;
+
+               if (qp->cq_cons_qe == qp->cq_last_qe) {
+                       qp->cq_cons_qe = qp->cq_first_qe;
+                       qp->cq_cons_idx = 0;
+               } else {
+                       qp->cq_cons_qe++;
+                       qp->cq_cons_idx++;
+               }
+       }
+       bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE);
+}
+
+/**
+ * bnx2i_fastpath_notification - process global event queue (KCQ)
+ * @hba:               adapter structure pointer
+ * @new_cqe_kcqe:      pointer to newly DMA'ed KCQE entry
+ *
+ * Fast path event notification handler, KCQ entry carries context id
+ *     of the connection that has 1 or more pending CQ entries
+ */
+static void bnx2i_fastpath_notification(struct bnx2i_hba *hba,
+                                       struct iscsi_kcqe *new_cqe_kcqe)
+{
+       struct bnx2i_conn *conn;
+       u32 iscsi_cid;
+
+       iscsi_cid = new_cqe_kcqe->iscsi_conn_id;
+       conn = bnx2i_get_conn_from_id(hba, iscsi_cid);
+
+       if (!conn) {
+               printk(KERN_ALERT "cid #%x not valid\n", iscsi_cid);
+               return;
+       }
+       if (!conn->ep) {
+               printk(KERN_ALERT "cid #%x - ep not bound\n", iscsi_cid);
+               return;
+       }
+
+       bnx2i_process_new_cqes(conn);
+}
+
+
+/**
+ * bnx2i_process_update_conn_cmpl - process iscsi conn update completion KCQE
+ * @hba:               adapter structure pointer
+ * @update_kcqe:       kcqe pointer
+ *
+ * CONN_UPDATE completion handler, this completes iSCSI connection FFP migration
+ */
+static void bnx2i_process_update_conn_cmpl(struct bnx2i_hba *hba,
+                                          struct iscsi_kcqe *update_kcqe)
+{
+       struct bnx2i_conn *conn;
+       u32 iscsi_cid;
+
+       iscsi_cid = update_kcqe->iscsi_conn_id;
+       conn = bnx2i_get_conn_from_id(hba, iscsi_cid);
+
+       if (!conn) {
+               printk(KERN_ALERT "conn_update: cid %x not valid\n", iscsi_cid);
+               return;
+       }
+       if (!conn->ep) {
+               printk(KERN_ALERT "cid %x does not have ep bound\n", iscsi_cid);
+               return;
+       }
+
+       if (update_kcqe->completion_status) {
+               printk(KERN_ALERT "request failed cid %x\n", iscsi_cid);
+               conn->ep->state = EP_STATE_ULP_UPDATE_FAILED;
+       } else
+               conn->ep->state = EP_STATE_ULP_UPDATE_COMPL;
+
+       wake_up_interruptible(&conn->ep->ofld_wait);
+}
+
+
+/**
+ * bnx2i_recovery_que_add_conn - add connection to recovery queue
+ * @hba:               adapter structure pointer
+ * @bnx2i_conn:                iscsi connection
+ *
+ * Add connection to recovery queue and schedule adapter eh worker
+ */
+static void bnx2i_recovery_que_add_conn(struct bnx2i_hba *hba,
+                                       struct bnx2i_conn *bnx2i_conn)
+{
+       iscsi_conn_failure(bnx2i_conn->cls_conn->dd_data,
+                          ISCSI_ERR_CONN_FAILED);
+}
+
+
+/**
+ * bnx2i_process_tcp_error - process error notification on a given connection
+ *
+ * @hba:               adapter structure pointer
+ * @tcp_err:           tcp error kcqe pointer
+ *
+ * handles tcp level error notifications from FW.
+ */
+static void bnx2i_process_tcp_error(struct bnx2i_hba *hba,
+                                   struct iscsi_kcqe *tcp_err)
+{
+       struct bnx2i_conn *bnx2i_conn;
+       u32 iscsi_cid;
+
+       iscsi_cid = tcp_err->iscsi_conn_id;
+       bnx2i_conn = bnx2i_get_conn_from_id(hba, iscsi_cid);
+
+       if (!bnx2i_conn) {
+               printk(KERN_ALERT "bnx2i - cid 0x%x not valid\n", iscsi_cid);
+               return;
+       }
+
+       printk(KERN_ALERT "bnx2i - cid 0x%x had TCP errors, error code 0x%x\n",
+                         iscsi_cid, tcp_err->completion_status);
+       bnx2i_recovery_que_add_conn(bnx2i_conn->hba, bnx2i_conn);
+}
+
+
+/**
+ * bnx2i_process_iscsi_error - process error notification on a given connection
+ * @hba:               adapter structure pointer
+ * @iscsi_err:         iscsi error kcqe pointer
+ *
+ * handles iscsi error notifications from the FW. Firmware based in initial
+ *     handshake classifies iscsi protocol / TCP rfc violation into either
+ *     warning or error indications. If indication is of "Error" type, driver
+ *     will initiate session recovery for that connection/session. For
+ *     "Warning" type indication, driver will put out a system log message
+ *     (there will be only one message for each type for the life of the
+ *     session, this is to avoid un-necessarily overloading the system)
+ */
+static void bnx2i_process_iscsi_error(struct bnx2i_hba *hba,
+                                     struct iscsi_kcqe *iscsi_err)
+{
+       struct bnx2i_conn *bnx2i_conn;
+       u32 iscsi_cid;
+       char warn_notice[] = "iscsi_warning";
+       char error_notice[] = "iscsi_error";
+       char additional_notice[64];
+       char *message;
+       int need_recovery;
+       u64 err_mask64;
+
+       iscsi_cid = iscsi_err->iscsi_conn_id;
+       bnx2i_conn = bnx2i_get_conn_from_id(hba, iscsi_cid);
+       if (!bnx2i_conn) {
+               printk(KERN_ALERT "bnx2i - cid 0x%x not valid\n", iscsi_cid);
+               return;
+       }
+
+       err_mask64 = (0x1ULL << iscsi_err->completion_status);
+
+       if (err_mask64 & iscsi_error_mask) {
+               need_recovery = 0;
+               message = warn_notice;
+       } else {
+               need_recovery = 1;
+               message = error_notice;
+       }
+
+       switch (iscsi_err->completion_status) {
+       case ISCSI_KCQE_COMPLETION_STATUS_HDR_DIG_ERR:
+               strcpy(additional_notice, "hdr digest err");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_DATA_DIG_ERR:
+               strcpy(additional_notice, "data digest err");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_OPCODE:
+               strcpy(additional_notice, "wrong opcode rcvd");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_AHS_LEN:
+               strcpy(additional_notice, "AHS len > 0 rcvd");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_ITT:
+               strcpy(additional_notice, "invalid ITT rcvd");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_STATSN:
+               strcpy(additional_notice, "wrong StatSN rcvd");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_EXP_DATASN:
+               strcpy(additional_notice, "wrong DataSN rcvd");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T:
+               strcpy(additional_notice, "pend R2T violation");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_0:
+               strcpy(additional_notice, "ERL0, UO");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_1:
+               strcpy(additional_notice, "ERL0, U1");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_2:
+               strcpy(additional_notice, "ERL0, U2");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_3:
+               strcpy(additional_notice, "ERL0, U3");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_4:
+               strcpy(additional_notice, "ERL0, U4");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_5:
+               strcpy(additional_notice, "ERL0, U5");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_6:
+               strcpy(additional_notice, "ERL0, U6");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REMAIN_RCV_LEN:
+               strcpy(additional_notice, "invalid resi len");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_MAX_RCV_PDU_LEN:
+               strcpy(additional_notice, "MRDSL violation");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_F_BIT_ZERO:
+               strcpy(additional_notice, "F-bit not set");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_TTT_NOT_RSRV:
+               strcpy(additional_notice, "invalid TTT");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATASN:
+               strcpy(additional_notice, "invalid DataSN");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REMAIN_BURST_LEN:
+               strcpy(additional_notice, "burst len violation");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_BUFFER_OFF:
+               strcpy(additional_notice, "buf offset violation");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_LUN:
+               strcpy(additional_notice, "invalid LUN field");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_R2TSN:
+               strcpy(additional_notice, "invalid R2TSN field");
+               break;
+#define BNX2I_ERR_DESIRED_DATA_TRNS_LEN_0      \
+       ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_0
+       case BNX2I_ERR_DESIRED_DATA_TRNS_LEN_0:
+               strcpy(additional_notice, "invalid cmd len1");
+               break;
+#define BNX2I_ERR_DESIRED_DATA_TRNS_LEN_1      \
+       ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_1
+       case BNX2I_ERR_DESIRED_DATA_TRNS_LEN_1:
+               strcpy(additional_notice, "invalid cmd len2");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T_EXCEED:
+               strcpy(additional_notice,
+                      "pend r2t exceeds MaxOutstandingR2T value");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_TTT_IS_RSRV:
+               strcpy(additional_notice, "TTT is rsvd");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_MAX_BURST_LEN:
+               strcpy(additional_notice, "MBL violation");
+               break;
+#define BNX2I_ERR_DATA_SEG_LEN_NOT_ZERO        \
+       ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATA_SEG_LEN_NOT_ZERO
+       case BNX2I_ERR_DATA_SEG_LEN_NOT_ZERO:
+               strcpy(additional_notice, "data seg len != 0");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REJECT_PDU_LEN:
+               strcpy(additional_notice, "reject pdu len error");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_ASYNC_PDU_LEN:
+               strcpy(additional_notice, "async pdu len error");
+               break;
+       case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_NOPIN_PDU_LEN:
+               strcpy(additional_notice, "nopin pdu len error");
+               break;
+#define BNX2_ERR_PEND_R2T_IN_CLEANUP                   \
+       ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T_IN_CLEANUP
+       case BNX2_ERR_PEND_R2T_IN_CLEANUP:
+               strcpy(additional_notice, "pend r2t in cleanup");
+               break;
+
+       case ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_IP_FRAGMENT:
+               strcpy(additional_notice, "IP fragments rcvd");
+               break;
+       case ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_IP_OPTIONS:
+               strcpy(additional_notice, "IP options error");
+               break;
+       case ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_URGENT_FLAG:
+               strcpy(additional_notice, "urgent flag error");
+               break;
+       default:
+               printk(KERN_ALERT "iscsi_err - unknown err %x\n",
+                                 iscsi_err->completion_status);
+       }
+
+       if (need_recovery) {
+               iscsi_conn_printk(KERN_ALERT,
+                                 bnx2i_conn->cls_conn->dd_data,
+                                 "bnx2i: %s - %s\n",
+                                 message, additional_notice);
+
+               iscsi_conn_printk(KERN_ALERT,
+                                 bnx2i_conn->cls_conn->dd_data,
+                                 "conn_err - hostno %d conn %p, "
+                                 "iscsi_cid %x cid %x\n",
+                                 bnx2i_conn->hba->shost->host_no,
+                                 bnx2i_conn, bnx2i_conn->ep->ep_iscsi_cid,
+                                 bnx2i_conn->ep->ep_cid);
+               bnx2i_recovery_que_add_conn(bnx2i_conn->hba, bnx2i_conn);
+       } else
+               if (!test_and_set_bit(iscsi_err->completion_status,
+                                     (void *) &bnx2i_conn->violation_notified))
+                       iscsi_conn_printk(KERN_ALERT,
+                                         bnx2i_conn->cls_conn->dd_data,
+                                         "bnx2i: %s - %s\n",
+                                         message, additional_notice);
+}
+
+
+/**
+ * bnx2i_process_conn_destroy_cmpl - process iscsi conn destroy completion
+ * @hba:               adapter structure pointer
+ * @conn_destroy:      conn destroy kcqe pointer
+ *
+ * handles connection destroy completion request.
+ */
+static void bnx2i_process_conn_destroy_cmpl(struct bnx2i_hba *hba,
+                                           struct iscsi_kcqe *conn_destroy)
+{
+       struct bnx2i_endpoint *ep;
+
+       ep = bnx2i_find_ep_in_destroy_list(hba, conn_destroy->iscsi_conn_id);
+       if (!ep) {
+               printk(KERN_ALERT "bnx2i_conn_destroy_cmpl: no pending "
+                                 "offload request, unexpected complection\n");
+               return;
+       }
+
+       if (hba != ep->hba) {
+               printk(KERN_ALERT "conn destroy- error hba mis-match\n");
+               return;
+       }
+
+       if (conn_destroy->completion_status) {
+               printk(KERN_ALERT "conn_destroy_cmpl: op failed\n");
+               ep->state = EP_STATE_CLEANUP_FAILED;
+       } else
+               ep->state = EP_STATE_CLEANUP_CMPL;
+       wake_up_interruptible(&ep->ofld_wait);
+}
+
+
+/**
+ * bnx2i_process_ofld_cmpl - process initial iscsi conn offload completion
+ * @hba:               adapter structure pointer
+ * @ofld_kcqe:         conn offload kcqe pointer
+ *
+ * handles initial connection offload completion, ep_connect() thread is
+ *     woken-up to continue with LLP connect process
+ */
+static void bnx2i_process_ofld_cmpl(struct bnx2i_hba *hba,
+                                   struct iscsi_kcqe *ofld_kcqe)
+{
+       u32 cid_addr;
+       struct bnx2i_endpoint *ep;
+       u32 cid_num;
+
+       ep = bnx2i_find_ep_in_ofld_list(hba, ofld_kcqe->iscsi_conn_id);
+       if (!ep) {
+               printk(KERN_ALERT "ofld_cmpl: no pend offload request\n");
+               return;
+       }
+
+       if (hba != ep->hba) {
+               printk(KERN_ALERT "ofld_cmpl: error hba mis-match\n");
+               return;
+       }
+
+       if (ofld_kcqe->completion_status) {
+               if (ofld_kcqe->completion_status ==
+                   ISCSI_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE)
+                       printk(KERN_ALERT "bnx2i: unable to allocate"
+                                         " iSCSI context resources\n");
+               ep->state = EP_STATE_OFLD_FAILED;
+       } else {
+               ep->state = EP_STATE_OFLD_COMPL;
+               cid_addr = ofld_kcqe->iscsi_conn_context_id;
+               cid_num = bnx2i_get_cid_num(ep);
+               ep->ep_cid = cid_addr;
+               ep->qp.ctx_base = NULL;
+       }
+       wake_up_interruptible(&ep->ofld_wait);
+}
+
+/**
+ * bnx2i_indicate_kcqe - process iscsi conn update completion KCQE
+ * @hba:               adapter structure pointer
+ * @update_kcqe:       kcqe pointer
+ *
+ * Generic KCQ event handler/dispatcher
+ */
+static void bnx2i_indicate_kcqe(void *context, struct kcqe *kcqe[],
+                               u32 num_cqe)
+{
+       struct bnx2i_hba *hba = context;
+       int i = 0;
+       struct iscsi_kcqe *ikcqe = NULL;
+
+       while (i < num_cqe) {
+               ikcqe = (struct iscsi_kcqe *) kcqe[i++];
+
+               if (ikcqe->op_code ==
+                   ISCSI_KCQE_OPCODE_CQ_EVENT_NOTIFICATION)
+                       bnx2i_fastpath_notification(hba, ikcqe);
+               else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_OFFLOAD_CONN)
+                       bnx2i_process_ofld_cmpl(hba, ikcqe);
+               else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_UPDATE_CONN)
+                       bnx2i_process_update_conn_cmpl(hba, ikcqe);
+               else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_INIT) {
+                       if (ikcqe->completion_status !=
+                           ISCSI_KCQE_COMPLETION_STATUS_SUCCESS)
+                               bnx2i_iscsi_license_error(hba, ikcqe->\
+                                                         completion_status);
+                       else {
+                               set_bit(ADAPTER_STATE_UP, &hba->adapter_state);
+                               bnx2i_get_link_state(hba);
+                               printk(KERN_INFO "bnx2i [%.2x:%.2x.%.2x]: "
+                                                "ISCSI_INIT passed\n",
+                                                (u8)hba->pcidev->bus->number,
+                                                hba->pci_devno,
+                                                (u8)hba->pci_func);
+
+
+                       }
+               } else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_DESTROY_CONN)
+                       bnx2i_process_conn_destroy_cmpl(hba, ikcqe);
+               else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_ISCSI_ERROR)
+                       bnx2i_process_iscsi_error(hba, ikcqe);
+               else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_TCP_ERROR)
+                       bnx2i_process_tcp_error(hba, ikcqe);
+               else
+                       printk(KERN_ALERT "bnx2i: unknown opcode 0x%x\n",
+                                         ikcqe->op_code);
+       }
+}
+
+
+/**
+ * bnx2i_indicate_netevent - Generic netdev event handler
+ * @context:   adapter structure pointer
+ * @event:     event type
+ *
+ * Handles four netdev events, NETDEV_UP, NETDEV_DOWN,
+ *     NETDEV_GOING_DOWN and NETDEV_CHANGE
+ */
+static void bnx2i_indicate_netevent(void *context, unsigned long event)
+{
+       struct bnx2i_hba *hba = context;
+
+       switch (event) {
+       case NETDEV_UP:
+               if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state))
+                       bnx2i_send_fw_iscsi_init_msg(hba);
+               break;
+       case NETDEV_DOWN:
+               clear_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state);
+               clear_bit(ADAPTER_STATE_UP, &hba->adapter_state);
+               break;
+       case NETDEV_GOING_DOWN:
+               set_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state);
+               iscsi_host_for_each_session(hba->shost,
+                                           bnx2i_drop_session);
+               break;
+       case NETDEV_CHANGE:
+               bnx2i_get_link_state(hba);
+               break;
+       default:
+               ;
+       }
+}
+
+
+/**
+ * bnx2i_cm_connect_cmpl - process iscsi conn establishment completion
+ * @cm_sk:             cnic sock structure pointer
+ *
+ * function callback exported via bnx2i - cnic driver interface to
+ *     indicate completion of option-2 TCP connect request.
+ */
+static void bnx2i_cm_connect_cmpl(struct cnic_sock *cm_sk)
+{
+       struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context;
+
+       if (test_bit(ADAPTER_STATE_GOING_DOWN, &ep->hba->adapter_state))
+               ep->state = EP_STATE_CONNECT_FAILED;
+       else if (test_bit(SK_F_OFFLD_COMPLETE, &cm_sk->flags))
+               ep->state = EP_STATE_CONNECT_COMPL;
+       else
+               ep->state = EP_STATE_CONNECT_FAILED;
+
+       wake_up_interruptible(&ep->ofld_wait);
+}
+
+
+/**
+ * bnx2i_cm_close_cmpl - process tcp conn close completion
+ * @cm_sk:     cnic sock structure pointer
+ *
+ * function callback exported via bnx2i - cnic driver interface to
+ *     indicate completion of option-2 graceful TCP connect shutdown
+ */
+static void bnx2i_cm_close_cmpl(struct cnic_sock *cm_sk)
+{
+       struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context;
+
+       ep->state = EP_STATE_DISCONN_COMPL;
+       wake_up_interruptible(&ep->ofld_wait);
+}
+
+
+/**
+ * bnx2i_cm_abort_cmpl - process abortive tcp conn teardown completion
+ * @cm_sk:     cnic sock structure pointer
+ *
+ * function callback exported via bnx2i - cnic driver interface to
+ *     indicate completion of option-2 abortive TCP connect termination
+ */
+static void bnx2i_cm_abort_cmpl(struct cnic_sock *cm_sk)
+{
+       struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context;
+
+       ep->state = EP_STATE_DISCONN_COMPL;
+       wake_up_interruptible(&ep->ofld_wait);
+}
+
+
+/**
+ * bnx2i_cm_remote_close - process received TCP FIN
+ * @hba:               adapter structure pointer
+ * @update_kcqe:       kcqe pointer
+ *
+ * function callback exported via bnx2i - cnic driver interface to indicate
+ *     async TCP events such as FIN
+ */
+static void bnx2i_cm_remote_close(struct cnic_sock *cm_sk)
+{
+       struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context;
+
+       ep->state = EP_STATE_TCP_FIN_RCVD;
+       if (ep->conn)
+               bnx2i_recovery_que_add_conn(ep->hba, ep->conn);
+}
+
+/**
+ * bnx2i_cm_remote_abort - process TCP RST and start conn cleanup
+ * @hba:               adapter structure pointer
+ * @update_kcqe:       kcqe pointer
+ *
+ * function callback exported via bnx2i - cnic driver interface to
+ *     indicate async TCP events (RST) sent by the peer.
+ */
+static void bnx2i_cm_remote_abort(struct cnic_sock *cm_sk)
+{
+       struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context;
+
+       ep->state = EP_STATE_TCP_RST_RCVD;
+       if (ep->conn)
+               bnx2i_recovery_que_add_conn(ep->hba, ep->conn);
+}
+
+
+static void bnx2i_send_nl_mesg(struct cnic_dev *dev, u32 msg_type,
+                              char *buf, u16 buflen)
+{
+       struct bnx2i_hba *hba;
+
+       hba = bnx2i_find_hba_for_cnic(dev);
+       if (!hba)
+               return;
+
+       if (iscsi_offload_mesg(hba->shost, &bnx2i_iscsi_transport,
+                                  msg_type, buf, buflen))
+               printk(KERN_ALERT "bnx2i: private nl message send error\n");
+
+}
+
+
+/**
+ * bnx2i_cnic_cb - global template of bnx2i - cnic driver interface structure
+ *                     carrying callback function pointers
+ *
+ */
+struct cnic_ulp_ops bnx2i_cnic_cb = {
+       .cnic_init = bnx2i_ulp_init,
+       .cnic_exit = bnx2i_ulp_exit,
+       .cnic_start = bnx2i_start,
+       .cnic_stop = bnx2i_stop,
+       .indicate_kcqes = bnx2i_indicate_kcqe,
+       .indicate_netevent = bnx2i_indicate_netevent,
+       .cm_connect_complete = bnx2i_cm_connect_cmpl,
+       .cm_close_complete = bnx2i_cm_close_cmpl,
+       .cm_abort_complete = bnx2i_cm_abort_cmpl,
+       .cm_remote_close = bnx2i_cm_remote_close,
+       .cm_remote_abort = bnx2i_cm_remote_abort,
+       .iscsi_nl_send_msg = bnx2i_send_nl_mesg,
+       .owner = THIS_MODULE
+};
+
+
+/**
+ * bnx2i_map_ep_dbell_regs - map connection doorbell registers
+ * @ep: bnx2i endpoint
+ *
+ * maps connection's SQ and RQ doorbell registers, 5706/5708/5709 hosts these
+ *     register in BAR #0. Whereas in 57710 these register are accessed by
+ *     mapping BAR #1
+ */
+int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep)
+{
+       u32 cid_num;
+       u32 reg_off;
+       u32 first_l4l5;
+       u32 ctx_sz;
+       u32 config2;
+       resource_size_t reg_base;
+
+       cid_num = bnx2i_get_cid_num(ep);
+
+       if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) {
+               reg_base = pci_resource_start(ep->hba->pcidev,
+                                             BNX2X_DOORBELL_PCI_BAR);
+               reg_off = PAGE_SIZE * (cid_num & 0x1FFFF) + DPM_TRIGER_TYPE;
+               ep->qp.ctx_base = ioremap_nocache(reg_base + reg_off, 4);
+               goto arm_cq;
+       }
+
+       reg_base = ep->hba->netdev->base_addr;
+       if ((test_bit(BNX2I_NX2_DEV_5709, &ep->hba->cnic_dev_type)) &&
+           (ep->hba->mail_queue_access == BNX2I_MQ_BIN_MODE)) {
+               config2 = REG_RD(ep->hba, BNX2_MQ_CONFIG2);
+               first_l4l5 = config2 & BNX2_MQ_CONFIG2_FIRST_L4L5;
+               ctx_sz = (config2 & BNX2_MQ_CONFIG2_CONT_SZ) >> 3;
+               if (ctx_sz)
+                       reg_off = CTX_OFFSET + MAX_CID_CNT * MB_KERNEL_CTX_SIZE
+                                 + PAGE_SIZE *
+                                 (((cid_num - first_l4l5) / ctx_sz) + 256);
+               else
+                       reg_off = CTX_OFFSET + (MB_KERNEL_CTX_SIZE * cid_num);
+       } else
+               /* 5709 device in normal node and 5706/5708 devices */
+               reg_off = CTX_OFFSET + (MB_KERNEL_CTX_SIZE * cid_num);
+
+       ep->qp.ctx_base = ioremap_nocache(reg_base + reg_off,
+                                         MB_KERNEL_CTX_SIZE);
+       if (!ep->qp.ctx_base)
+               return -ENOMEM;
+
+arm_cq:
+       bnx2i_arm_cq_event_coalescing(ep, CNIC_ARM_CQE);
+       return 0;
+}
diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c
new file mode 100644 (file)
index 0000000..ae4b2d5
--- /dev/null
@@ -0,0 +1,438 @@
+/* bnx2i.c: Broadcom NetXtreme II iSCSI driver.
+ *
+ * Copyright (c) 2006 - 2009 Broadcom Corporation
+ * Copyright (c) 2007, 2008 Red Hat, Inc.  All rights reserved.
+ * Copyright (c) 2007, 2008 Mike Christie
+ *
+ * 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.
+ *
+ * Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ */
+
+#include "bnx2i.h"
+
+static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list);
+static u32 adapter_count;
+static int bnx2i_reg_device;
+
+#define DRV_MODULE_NAME                "bnx2i"
+#define DRV_MODULE_VERSION     "2.0.1d"
+#define DRV_MODULE_RELDATE     "Mar 25, 2009"
+
+static char version[] __devinitdata =
+               "Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \
+               " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+
+
+MODULE_AUTHOR("Anil Veerabhadrappa <anilgv@broadcom.com>");
+MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709 iSCSI Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+
+static DEFINE_RWLOCK(bnx2i_dev_lock);
+
+unsigned int event_coal_div = 1;
+module_param(event_coal_div, int, 0664);
+MODULE_PARM_DESC(event_coal_div, "Event Coalescing Divide Factor");
+
+unsigned int en_tcp_dack = 1;
+module_param(en_tcp_dack, int, 0664);
+MODULE_PARM_DESC(en_tcp_dack, "Enable TCP Delayed ACK");
+
+unsigned int error_mask1 = 0x00;
+module_param(error_mask1, int, 0664);
+MODULE_PARM_DESC(error_mask1, "Config FW iSCSI Error Mask #1");
+
+unsigned int error_mask2 = 0x00;
+module_param(error_mask2, int, 0664);
+MODULE_PARM_DESC(error_mask2, "Config FW iSCSI Error Mask #2");
+
+unsigned int sq_size;
+module_param(sq_size, int, 0664);
+MODULE_PARM_DESC(sq_size, "Configure SQ size");
+
+unsigned int rq_size = BNX2I_RQ_WQES_DEFAULT;
+module_param(rq_size, int, 0664);
+MODULE_PARM_DESC(rq_size, "Configure RQ size");
+
+u64 iscsi_error_mask = 0x00;
+
+static void bnx2i_unreg_one_device(struct bnx2i_hba *hba) ;
+
+
+/**
+ * bnx2i_identify_device - identifies NetXtreme II device type
+ * @hba:               Adapter structure pointer
+ *
+ * This function identifies the NX2 device type and sets appropriate
+ *     queue mailbox register access method, 5709 requires driver to
+ *     access MBOX regs using *bin* mode
+ */
+void bnx2i_identify_device(struct bnx2i_hba *hba)
+{
+       hba->cnic_dev_type = 0;
+       if ((hba->pci_did == PCI_DEVICE_ID_NX2_5706) ||
+           (hba->pci_did == PCI_DEVICE_ID_NX2_5706S))
+               set_bit(BNX2I_NX2_DEV_5706, &hba->cnic_dev_type);
+       else if ((hba->pci_did == PCI_DEVICE_ID_NX2_5708) ||
+           (hba->pci_did == PCI_DEVICE_ID_NX2_5708S))
+               set_bit(BNX2I_NX2_DEV_5708, &hba->cnic_dev_type);
+       else if ((hba->pci_did == PCI_DEVICE_ID_NX2_5709) ||
+           (hba->pci_did == PCI_DEVICE_ID_NX2_5709S)) {
+               set_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type);
+               hba->mail_queue_access = BNX2I_MQ_BIN_MODE;
+       } else if (hba->pci_did == PCI_DEVICE_ID_NX2_57710 ||
+                  hba->pci_did == PCI_DEVICE_ID_NX2_57711)
+               set_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type);
+}
+
+
+/**
+ * get_adapter_list_head - returns head of adapter list
+ */
+struct bnx2i_hba *get_adapter_list_head(void)
+{
+       struct bnx2i_hba *hba = NULL;
+       struct bnx2i_hba *tmp_hba;
+
+       if (!adapter_count)
+               goto hba_not_found;
+
+       read_lock(&bnx2i_dev_lock);
+       list_for_each_entry(tmp_hba, &adapter_list, link) {
+               if (tmp_hba->cnic && tmp_hba->cnic->cm_select_dev) {
+                       hba = tmp_hba;
+                       break;
+               }
+       }
+       read_unlock(&bnx2i_dev_lock);
+hba_not_found:
+       return hba;
+}
+
+
+/**
+ * bnx2i_find_hba_for_cnic - maps cnic device instance to bnx2i adapter instance
+ * @cnic:      pointer to cnic device instance
+ *
+ */
+struct bnx2i_hba *bnx2i_find_hba_for_cnic(struct cnic_dev *cnic)
+{
+       struct bnx2i_hba *hba, *temp;
+
+       read_lock(&bnx2i_dev_lock);
+       list_for_each_entry_safe(hba, temp, &adapter_list, link) {
+               if (hba->cnic == cnic) {
+                       read_unlock(&bnx2i_dev_lock);
+                       return hba;
+               }
+       }
+       read_unlock(&bnx2i_dev_lock);
+       return NULL;
+}
+
+
+/**
+ * bnx2i_start - cnic callback to initialize & start adapter instance
+ * @handle:    transparent handle pointing to adapter structure
+ *
+ * This function maps adapter structure to pcidev structure and initiates
+ *     firmware handshake to enable/initialize on chip iscsi components
+ *     This bnx2i - cnic interface api callback is issued after following
+ *     2 conditions are met -
+ *       a) underlying network interface is up (marked by event 'NETDEV_UP'
+ *             from netdev
+ *       b) bnx2i adapter instance is registered
+ */
+void bnx2i_start(void *handle)
+{
+#define BNX2I_INIT_POLL_TIME   (1000 / HZ)
+       struct bnx2i_hba *hba = handle;
+       int i = HZ;
+
+       bnx2i_send_fw_iscsi_init_msg(hba);
+       while (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) && i--)
+               msleep(BNX2I_INIT_POLL_TIME);
+}
+
+
+/**
+ * bnx2i_stop - cnic callback to shutdown adapter instance
+ * @handle:    transparent handle pointing to adapter structure
+ *
+ * driver checks if adapter is already in shutdown mode, if not start
+ *     the shutdown process
+ */
+void bnx2i_stop(void *handle)
+{
+       struct bnx2i_hba *hba = handle;
+
+       /* check if cleanup happened in GOING_DOWN context */
+       clear_bit(ADAPTER_STATE_UP, &hba->adapter_state);
+       if (!test_and_clear_bit(ADAPTER_STATE_GOING_DOWN,
+                               &hba->adapter_state))
+               iscsi_host_for_each_session(hba->shost,
+                                           bnx2i_drop_session);
+}
+
+/**
+ * bnx2i_register_device - register bnx2i adapter instance with the cnic driver
+ * @hba:       Adapter instance to register
+ *
+ * registers bnx2i adapter instance with the cnic driver while holding the
+ *     adapter structure lock
+ */
+void bnx2i_register_device(struct bnx2i_hba *hba)
+{
+       if (test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state) ||
+           test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
+               return;
+       }
+
+       hba->cnic->register_device(hba->cnic, CNIC_ULP_ISCSI, hba);
+
+       spin_lock(&hba->lock);
+       bnx2i_reg_device++;
+       spin_unlock(&hba->lock);
+
+       set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
+}
+
+
+/**
+ * bnx2i_reg_dev_all - registers all adapter instances with the cnic driver
+ *
+ * registers all bnx2i adapter instances with the cnic driver while holding
+ *     the global resource lock
+ */
+void bnx2i_reg_dev_all(void)
+{
+       struct bnx2i_hba *hba, *temp;
+
+       read_lock(&bnx2i_dev_lock);
+       list_for_each_entry_safe(hba, temp, &adapter_list, link)
+               bnx2i_register_device(hba);
+       read_unlock(&bnx2i_dev_lock);
+}
+
+
+/**
+ * bnx2i_unreg_one_device - unregister adapter instance with the cnic driver
+ * @hba:       Adapter instance to unregister
+ *
+ * registers bnx2i adapter instance with the cnic driver while holding
+ *     the adapter structure lock
+ */
+static void bnx2i_unreg_one_device(struct bnx2i_hba *hba)
+{
+       if (hba->ofld_conns_active ||
+           !test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic) ||
+           test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state))
+               return;
+
+       hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI);
+
+       spin_lock(&hba->lock);
+       bnx2i_reg_device--;
+       spin_unlock(&hba->lock);
+
+       /* ep_disconnect could come before NETDEV_DOWN, driver won't
+        * see NETDEV_DOWN as it already unregistered itself.
+        */
+       hba->adapter_state = 0;
+       clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
+}
+
+/**
+ * bnx2i_unreg_dev_all - unregisters all bnx2i instances with the cnic driver
+ *
+ * unregisters all bnx2i adapter instances with the cnic driver while holding
+ *     the global resource lock
+ */
+void bnx2i_unreg_dev_all(void)
+{
+       struct bnx2i_hba *hba, *temp;
+
+       read_lock(&bnx2i_dev_lock);
+       list_for_each_entry_safe(hba, temp, &adapter_list, link)
+               bnx2i_unreg_one_device(hba);
+       read_unlock(&bnx2i_dev_lock);
+}
+
+
+/**
+ * bnx2i_init_one - initialize an adapter instance and allocate memory resources
+ * @hba:       bnx2i adapter instance
+ * @cnic:      cnic device handle
+ *
+ * Global resource lock and host adapter lock is held during critical sections
+ *     below. This routine is called from cnic_register_driver() context and
+ *     work horse thread which does majority of device specific initialization
+ */
+static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic)
+{
+       int rc;
+
+       read_lock(&bnx2i_dev_lock);
+       if (bnx2i_reg_device &&
+           !test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
+               rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba);
+               if (rc)         /* duplicate registration */
+                       printk(KERN_ERR "bnx2i- dev reg failed\n");
+
+               spin_lock(&hba->lock);
+               bnx2i_reg_device++;
+               hba->age++;
+               spin_unlock(&hba->lock);
+
+               set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
+       }
+       read_unlock(&bnx2i_dev_lock);
+
+       write_lock(&bnx2i_dev_lock);
+       list_add_tail(&hba->link, &adapter_list);
+       adapter_count++;
+       write_unlock(&bnx2i_dev_lock);
+       return 0;
+}
+
+
+/**
+ * bnx2i_ulp_init - initialize an adapter instance
+ * @dev:       cnic device handle
+ *
+ * Called from cnic_register_driver() context to initialize all enumerated
+ *     cnic devices. This routine allocate adapter structure and other
+ *     device specific resources.
+ */
+void bnx2i_ulp_init(struct cnic_dev *dev)
+{
+       struct bnx2i_hba *hba;
+
+       /* Allocate a HBA structure for this device */
+       hba = bnx2i_alloc_hba(dev);
+       if (!hba) {
+               printk(KERN_ERR "bnx2i init: hba initialization failed\n");
+               return;
+       }
+
+       /* Get PCI related information and update hba struct members */
+       clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
+       if (bnx2i_init_one(hba, dev)) {
+               printk(KERN_ERR "bnx2i - hba %p init failed\n", hba);
+               bnx2i_free_hba(hba);
+       } else
+               hba->cnic = dev;
+}
+
+
+/**
+ * bnx2i_ulp_exit - shuts down adapter instance and frees all resources
+ * @dev:       cnic device handle
+ *
+ */
+void bnx2i_ulp_exit(struct cnic_dev *dev)
+{
+       struct bnx2i_hba *hba;
+
+       hba = bnx2i_find_hba_for_cnic(dev);
+       if (!hba) {
+               printk(KERN_INFO "bnx2i_ulp_exit: hba not "
+                                "found, dev 0x%p\n", dev);
+               return;
+       }
+       write_lock(&bnx2i_dev_lock);
+       list_del_init(&hba->link);
+       adapter_count--;
+
+       if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
+               hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI);
+               clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
+
+               spin_lock(&hba->lock);
+               bnx2i_reg_device--;
+               spin_unlock(&hba->lock);
+       }
+       write_unlock(&bnx2i_dev_lock);
+
+       bnx2i_free_hba(hba);
+}
+
+
+/**
+ * bnx2i_mod_init - module init entry point
+ *
+ * initialize any driver wide global data structures such as endpoint pool,
+ *     tcp port manager/queue, sysfs. finally driver will register itself
+ *     with the cnic module
+ */
+static int __init bnx2i_mod_init(void)
+{
+       int err;
+
+       printk(KERN_INFO "%s", version);
+
+       if (!is_power_of_2(sq_size))
+               sq_size = roundup_pow_of_two(sq_size);
+
+       bnx2i_scsi_xport_template =
+                       iscsi_register_transport(&bnx2i_iscsi_transport);
+       if (!bnx2i_scsi_xport_template) {
+               printk(KERN_ERR "Could not register bnx2i transport.\n");
+               err = -ENOMEM;
+               goto out;
+       }
+
+       err = cnic_register_driver(CNIC_ULP_ISCSI, &bnx2i_cnic_cb);
+       if (err) {
+               printk(KERN_ERR "Could not register bnx2i cnic driver.\n");
+               goto unreg_xport;
+       }
+
+       return 0;
+
+unreg_xport:
+       iscsi_unregister_transport(&bnx2i_iscsi_transport);
+out:
+       return err;
+}
+
+
+/**
+ * bnx2i_mod_exit - module cleanup/exit entry point
+ *
+ * Global resource lock and host adapter lock is held during critical sections
+ *     in this function. Driver will browse through the adapter list, cleans-up
+ *     each instance, unregisters iscsi transport name and finally driver will
+ *     unregister itself with the cnic module
+ */
+static void __exit bnx2i_mod_exit(void)
+{
+       struct bnx2i_hba *hba;
+
+       write_lock(&bnx2i_dev_lock);
+       while (!list_empty(&adapter_list)) {
+               hba = list_entry(adapter_list.next, struct bnx2i_hba, link);
+               list_del(&hba->link);
+               adapter_count--;
+
+               if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
+                       hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI);
+                       clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
+                       bnx2i_reg_device--;
+               }
+
+               write_unlock(&bnx2i_dev_lock);
+               bnx2i_free_hba(hba);
+               write_lock(&bnx2i_dev_lock);
+       }
+       write_unlock(&bnx2i_dev_lock);
+
+       iscsi_unregister_transport(&bnx2i_iscsi_transport);
+       cnic_unregister_driver(CNIC_ULP_ISCSI);
+}
+
+module_init(bnx2i_mod_init);
+module_exit(bnx2i_mod_exit);
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
new file mode 100644 (file)
index 0000000..f741219
--- /dev/null
@@ -0,0 +1,2064 @@
+/*
+ * bnx2i_iscsi.c: Broadcom NetXtreme II iSCSI driver.
+ *
+ * Copyright (c) 2006 - 2009 Broadcom Corporation
+ * Copyright (c) 2007, 2008 Red Hat, Inc.  All rights reserved.
+ * Copyright (c) 2007, 2008 Mike Christie
+ *
+ * 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.
+ *
+ * Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ */
+
+#include <scsi/scsi_tcq.h>
+#include <scsi/libiscsi.h>
+#include "bnx2i.h"
+
+struct scsi_transport_template *bnx2i_scsi_xport_template;
+struct iscsi_transport bnx2i_iscsi_transport;
+static struct scsi_host_template bnx2i_host_template;
+
+/*
+ * Global endpoint resource info
+ */
+static DEFINE_SPINLOCK(bnx2i_resc_lock); /* protects global resources */
+
+
+static int bnx2i_adapter_ready(struct bnx2i_hba *hba)
+{
+       int retval = 0;
+
+       if (!hba || !test_bit(ADAPTER_STATE_UP, &hba->adapter_state) ||
+           test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state) ||
+           test_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state))
+               retval = -EPERM;
+       return retval;
+}
+
+/**
+ * bnx2i_get_write_cmd_bd_idx - identifies various BD bookmarks
+ * @cmd:               iscsi cmd struct pointer
+ * @buf_off:           absolute buffer offset
+ * @start_bd_off:      u32 pointer to return the offset within the BD
+ *                     indicated by 'start_bd_idx' on which 'buf_off' falls
+ * @start_bd_idx:      index of the BD on which 'buf_off' falls
+ *
+ * identifies & marks various bd info for scsi command's imm data,
+ * unsolicited data and the first solicited data seq.
+ */
+static void bnx2i_get_write_cmd_bd_idx(struct bnx2i_cmd *cmd, u32 buf_off,
+                                      u32 *start_bd_off, u32 *start_bd_idx)
+{
+       struct iscsi_bd *bd_tbl = cmd->io_tbl.bd_tbl;
+       u32 cur_offset = 0;
+       u32 cur_bd_idx = 0;
+
+       if (buf_off) {
+               while (buf_off >= (cur_offset + bd_tbl->buffer_length)) {
+                       cur_offset += bd_tbl->buffer_length;
+                       cur_bd_idx++;
+                       bd_tbl++;
+               }
+       }
+
+       *start_bd_off = buf_off - cur_offset;
+       *start_bd_idx = cur_bd_idx;
+}
+
+/**
+ * bnx2i_setup_write_cmd_bd_info - sets up BD various information
+ * @task:      transport layer's cmd struct pointer
+ *
+ * identifies & marks various bd info for scsi command's immediate data,
+ * unsolicited data and first solicited data seq which includes BD start
+ * index & BD buf off. his function takes into account iscsi parameter such
+ * as immediate data and unsolicited data is support on this connection.
+ */
+static void bnx2i_setup_write_cmd_bd_info(struct iscsi_task *task)
+{
+       struct bnx2i_cmd *cmd = task->dd_data;
+       u32 start_bd_offset;
+       u32 start_bd_idx;
+       u32 buffer_offset = 0;
+       u32 cmd_len = cmd->req.total_data_transfer_length;
+
+       /* if ImmediateData is turned off & IntialR2T is turned on,
+        * there will be no immediate or unsolicited data, just return.
+        */
+       if (!iscsi_task_has_unsol_data(task) && !task->imm_count)
+               return;
+
+       /* Immediate data */
+       buffer_offset += task->imm_count;
+       if (task->imm_count == cmd_len)
+               return;
+
+       if (iscsi_task_has_unsol_data(task)) {
+               bnx2i_get_write_cmd_bd_idx(cmd, buffer_offset,
+                                          &start_bd_offset, &start_bd_idx);
+               cmd->req.ud_buffer_offset = start_bd_offset;
+               cmd->req.ud_start_bd_index = start_bd_idx;
+               buffer_offset += task->unsol_r2t.data_length;
+       }
+
+       if (buffer_offset != cmd_len) {
+               bnx2i_get_write_cmd_bd_idx(cmd, buffer_offset,
+                                          &start_bd_offset, &start_bd_idx);
+               if ((start_bd_offset > task->conn->session->first_burst) ||
+                   (start_bd_idx > scsi_sg_count(cmd->scsi_cmd))) {
+                       int i = 0;
+
+                       iscsi_conn_printk(KERN_ALERT, task->conn,
+                                         "bnx2i- error, buf offset 0x%x "
+                                         "bd_valid %d use_sg %d\n",
+                                         buffer_offset, cmd->io_tbl.bd_valid,
+                                         scsi_sg_count(cmd->scsi_cmd));
+                       for (i = 0; i < cmd->io_tbl.bd_valid; i++)
+                               iscsi_conn_printk(KERN_ALERT, task->conn,
+                                                 "bnx2i err, bd[%d]: len %x\n",
+                                                 i, cmd->io_tbl.bd_tbl[i].\
+                                                 buffer_length);
+               }
+               cmd->req.sd_buffer_offset = start_bd_offset;
+               cmd->req.sd_start_bd_index = start_bd_idx;
+       }
+}
+
+
+
+/**
+ * bnx2i_map_scsi_sg - maps IO buffer and prepares the BD table
+ * @hba:       adapter instance
+ * @cmd:       iscsi cmd struct pointer
+ *
+ * map SG list
+ */
+static int bnx2i_map_scsi_sg(struct bnx2i_hba *hba, struct bnx2i_cmd *cmd)
+{
+       struct scsi_cmnd *sc = cmd->scsi_cmd;
+       struct iscsi_bd *bd = cmd->io_tbl.bd_tbl;
+       struct scatterlist *sg;
+       int byte_count = 0;
+       int bd_count = 0;
+       int sg_count;
+       int sg_len;
+       u64 addr;
+       int i;
+
+       BUG_ON(scsi_sg_count(sc) > ISCSI_MAX_BDS_PER_CMD);
+
+       sg_count = scsi_dma_map(sc);
+
+       scsi_for_each_sg(sc, sg, sg_count, i) {
+               sg_len = sg_dma_len(sg);
+               addr = (u64) sg_dma_address(sg);
+               bd[bd_count].buffer_addr_lo = addr & 0xffffffff;
+               bd[bd_count].buffer_addr_hi = addr >> 32;
+               bd[bd_count].buffer_length = sg_len;
+               bd[bd_count].flags = 0;
+               if (bd_count == 0)
+                       bd[bd_count].flags = ISCSI_BD_FIRST_IN_BD_CHAIN;
+
+               byte_count += sg_len;
+               bd_count++;
+       }
+
+       if (bd_count)
+               bd[bd_count - 1].flags |= ISCSI_BD_LAST_IN_BD_CHAIN;
+
+       BUG_ON(byte_count != scsi_bufflen(sc));
+       return bd_count;
+}
+
+/**
+ * bnx2i_iscsi_map_sg_list - maps SG list
+ * @cmd:       iscsi cmd struct pointer
+ *
+ * creates BD list table for the command
+ */
+static void bnx2i_iscsi_map_sg_list(struct bnx2i_cmd *cmd)
+{
+       int bd_count;
+
+       bd_count  = bnx2i_map_scsi_sg(cmd->conn->hba, cmd);
+       if (!bd_count) {
+               struct iscsi_bd *bd = cmd->io_tbl.bd_tbl;
+
+               bd[0].buffer_addr_lo = bd[0].buffer_addr_hi = 0;
+               bd[0].buffer_length = bd[0].flags = 0;
+       }
+       cmd->io_tbl.bd_valid = bd_count;
+}
+
+
+/**
+ * bnx2i_iscsi_unmap_sg_list - unmaps SG list
+ * @cmd:       iscsi cmd struct pointer
+ *
+ * unmap IO buffers and invalidate the BD table
+ */
+void bnx2i_iscsi_unmap_sg_list(struct bnx2i_cmd *cmd)
+{
+       struct scsi_cmnd *sc = cmd->scsi_cmd;
+
+       if (cmd->io_tbl.bd_valid && sc) {
+               scsi_dma_unmap(sc);
+               cmd->io_tbl.bd_valid = 0;
+       }
+}
+
+static void bnx2i_setup_cmd_wqe_template(struct bnx2i_cmd *cmd)
+{
+       memset(&cmd->req, 0x00, sizeof(cmd->req));
+       cmd->req.op_code = 0xFF;
+       cmd->req.bd_list_addr_lo = (u32) cmd->io_tbl.bd_tbl_dma;
+       cmd->req.bd_list_addr_hi =
+               (u32) ((u64) cmd->io_tbl.bd_tbl_dma >> 32);
+
+}
+
+
+/**
+ * bnx2i_bind_conn_to_iscsi_cid - bind conn structure to 'iscsi_cid'
+ * @hba:       pointer to adapter instance
+ * @conn:      pointer to iscsi connection
+ * @iscsi_cid: iscsi context ID, range 0 - (MAX_CONN - 1)
+ *
+ * update iscsi cid table entry with connection pointer. This enables
+ *     driver to quickly get hold of connection structure pointer in
+ *     completion/interrupt thread using iscsi context ID
+ */
+static int bnx2i_bind_conn_to_iscsi_cid(struct bnx2i_hba *hba,
+                                       struct bnx2i_conn *bnx2i_conn,
+                                       u32 iscsi_cid)
+{
+       if (hba && hba->cid_que.conn_cid_tbl[iscsi_cid]) {
+               iscsi_conn_printk(KERN_ALERT, bnx2i_conn->cls_conn->dd_data,
+                                "conn bind - entry #%d not free\n", iscsi_cid);
+               return -EBUSY;
+       }
+
+       hba->cid_que.conn_cid_tbl[iscsi_cid] = bnx2i_conn;
+       return 0;
+}
+
+
+/**
+ * bnx2i_get_conn_from_id - maps an iscsi cid to corresponding conn ptr
+ * @hba:       pointer to adapter instance
+ * @iscsi_cid: iscsi context ID, range 0 - (MAX_CONN - 1)
+ */
+struct bnx2i_conn *bnx2i_get_conn_from_id(struct bnx2i_hba *hba,
+                                         u16 iscsi_cid)
+{
+       if (!hba->cid_que.conn_cid_tbl) {
+               printk(KERN_ERR "bnx2i: ERROR - missing conn<->cid table\n");
+               return NULL;
+
+       } else if (iscsi_cid >= hba->max_active_conns) {
+               printk(KERN_ERR "bnx2i: wrong cid #%d\n", iscsi_cid);
+               return NULL;
+       }
+       return hba->cid_que.conn_cid_tbl[iscsi_cid];
+}
+
+
+/**
+ * bnx2i_alloc_iscsi_cid - allocates a iscsi_cid from free pool
+ * @hba:       pointer to adapter instance
+ */
+static u32 bnx2i_alloc_iscsi_cid(struct bnx2i_hba *hba)
+{
+       int idx;
+
+       if (!hba->cid_que.cid_free_cnt)
+               return -1;
+
+       idx = hba->cid_que.cid_q_cons_idx;
+       hba->cid_que.cid_q_cons_idx++;
+       if (hba->cid_que.cid_q_cons_idx == hba->cid_que.cid_q_max_idx)
+               hba->cid_que.cid_q_cons_idx = 0;
+
+       hba->cid_que.cid_free_cnt--;
+       return hba->cid_que.cid_que[idx];
+}
+
+
+/**
+ * bnx2i_free_iscsi_cid - returns tcp port to free list
+ * @hba:               pointer to adapter instance
+ * @iscsi_cid:         iscsi context ID to free
+ */
+static void bnx2i_free_iscsi_cid(struct bnx2i_hba *hba, u16 iscsi_cid)
+{
+       int idx;
+
+       if (iscsi_cid == (u16) -1)
+               return;
+
+       hba->cid_que.cid_free_cnt++;
+
+       idx = hba->cid_que.cid_q_prod_idx;
+       hba->cid_que.cid_que[idx] = iscsi_cid;
+       hba->cid_que.conn_cid_tbl[iscsi_cid] = NULL;
+       hba->cid_que.cid_q_prod_idx++;
+       if (hba->cid_que.cid_q_prod_idx == hba->cid_que.cid_q_max_idx)
+               hba->cid_que.cid_q_prod_idx = 0;
+}
+
+
+/**
+ * bnx2i_setup_free_cid_que - sets up free iscsi cid queue
+ * @hba:       pointer to adapter instance
+ *
+ * allocates memory for iscsi cid queue & 'cid - conn ptr' mapping table,
+ *     and initialize table attributes
+ */
+static int bnx2i_setup_free_cid_que(struct bnx2i_hba *hba)
+{
+       int mem_size;
+       int i;
+
+       mem_size = hba->max_active_conns * sizeof(u32);
+       mem_size = (mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+
+       hba->cid_que.cid_que_base = kmalloc(mem_size, GFP_KERNEL);
+       if (!hba->cid_que.cid_que_base)
+               return -ENOMEM;
+
+       mem_size = hba->max_active_conns * sizeof(struct bnx2i_conn *);
+       mem_size = (mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+       hba->cid_que.conn_cid_tbl = kmalloc(mem_size, GFP_KERNEL);
+       if (!hba->cid_que.conn_cid_tbl) {
+               kfree(hba->cid_que.cid_que_base);
+               hba->cid_que.cid_que_base = NULL;
+               return -ENOMEM;
+       }
+
+       hba->cid_que.cid_que = (u32 *)hba->cid_que.cid_que_base;
+       hba->cid_que.cid_q_prod_idx = 0;
+       hba->cid_que.cid_q_cons_idx = 0;
+       hba->cid_que.cid_q_max_idx = hba->max_active_conns;
+       hba->cid_que.cid_free_cnt = hba->max_active_conns;
+
+       for (i = 0; i < hba->max_active_conns; i++) {
+               hba->cid_que.cid_que[i] = i;
+               hba->cid_que.conn_cid_tbl[i] = NULL;
+       }
+       return 0;
+}
+
+
+/**
+ * bnx2i_release_free_cid_que - releases 'iscsi_cid' queue resources
+ * @hba:       pointer to adapter instance
+ */
+static void bnx2i_release_free_cid_que(struct bnx2i_hba *hba)
+{
+       kfree(hba->cid_que.cid_que_base);
+       hba->cid_que.cid_que_base = NULL;
+
+       kfree(hba->cid_que.conn_cid_tbl);
+       hba->cid_que.conn_cid_tbl = NULL;
+}
+
+
+/**
+ * bnx2i_alloc_ep - allocates ep structure from global pool
+ * @hba:       pointer to adapter instance
+ *
+ * routine allocates a free endpoint structure from global pool and
+ *     a tcp port to be used for this connection.  Global resource lock,
+ *     'bnx2i_resc_lock' is held while accessing shared global data structures
+ */
+static struct iscsi_endpoint *bnx2i_alloc_ep(struct bnx2i_hba *hba)
+{
+       struct iscsi_endpoint *ep;
+       struct bnx2i_endpoint *bnx2i_ep;
+
+       ep = iscsi_create_endpoint(sizeof(*bnx2i_ep));
+       if (!ep) {
+               printk(KERN_ERR "bnx2i: Could not allocate ep\n");
+               return NULL;
+       }
+
+       bnx2i_ep = ep->dd_data;
+       INIT_LIST_HEAD(&bnx2i_ep->link);
+       bnx2i_ep->state = EP_STATE_IDLE;
+       bnx2i_ep->hba = hba;
+       bnx2i_ep->hba_age = hba->age;
+       hba->ofld_conns_active++;
+       init_waitqueue_head(&bnx2i_ep->ofld_wait);
+       return ep;
+}
+
+
+/**
+ * bnx2i_free_ep - free endpoint
+ * @ep:                pointer to iscsi endpoint structure
+ */
+static void bnx2i_free_ep(struct iscsi_endpoint *ep)
+{
+       struct bnx2i_endpoint *bnx2i_ep = ep->dd_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&bnx2i_resc_lock, flags);
+       bnx2i_ep->state = EP_STATE_IDLE;
+       bnx2i_ep->hba->ofld_conns_active--;
+
+       bnx2i_free_iscsi_cid(bnx2i_ep->hba, bnx2i_ep->ep_iscsi_cid);
+       if (bnx2i_ep->conn) {
+               bnx2i_ep->conn->ep = NULL;
+               bnx2i_ep->conn = NULL;
+       }
+
+       bnx2i_ep->hba = NULL;
+       spin_unlock_irqrestore(&bnx2i_resc_lock, flags);
+       iscsi_destroy_endpoint(ep);
+}
+
+
+/**
+ * bnx2i_alloc_bdt - allocates buffer descriptor (BD) table for the command
+ * @hba:       adapter instance pointer
+ * @session:   iscsi session pointer
+ * @cmd:       iscsi command structure
+ */
+static int bnx2i_alloc_bdt(struct bnx2i_hba *hba, struct iscsi_session *session,
+                          struct bnx2i_cmd *cmd)
+{
+       struct io_bdt *io = &cmd->io_tbl;
+       struct iscsi_bd *bd;
+
+       io->bd_tbl = dma_alloc_coherent(&hba->pcidev->dev,
+                                       ISCSI_MAX_BDS_PER_CMD * sizeof(*bd),
+                                       &io->bd_tbl_dma, GFP_KERNEL);
+       if (!io->bd_tbl) {
+               iscsi_session_printk(KERN_ERR, session, "Could not "
+                                    "allocate bdt.\n");
+               return -ENOMEM;
+       }
+       io->bd_valid = 0;
+       return 0;
+}
+
+/**
+ * bnx2i_destroy_cmd_pool - destroys iscsi command pool and release BD table
+ * @hba:       adapter instance pointer
+ * @session:   iscsi session pointer
+ * @cmd:       iscsi command structure
+ */
+static void bnx2i_destroy_cmd_pool(struct bnx2i_hba *hba,
+                                  struct iscsi_session *session)
+{
+       int i;
+
+       for (i = 0; i < session->cmds_max; i++) {
+               struct iscsi_task *task = session->cmds[i];
+               struct bnx2i_cmd *cmd = task->dd_data;
+
+               if (cmd->io_tbl.bd_tbl)
+                       dma_free_coherent(&hba->pcidev->dev,
+                                         ISCSI_MAX_BDS_PER_CMD *
+                                         sizeof(struct iscsi_bd),
+                                         cmd->io_tbl.bd_tbl,
+                                         cmd->io_tbl.bd_tbl_dma);
+       }
+
+}
+
+
+/**
+ * bnx2i_setup_cmd_pool - sets up iscsi command pool for the session
+ * @hba:       adapter instance pointer
+ * @session:   iscsi session pointer
+ */
+static int bnx2i_setup_cmd_pool(struct bnx2i_hba *hba,
+                               struct iscsi_session *session)
+{
+       int i;
+
+       for (i = 0; i < session->cmds_max; i++) {
+               struct iscsi_task *task = session->cmds[i];
+               struct bnx2i_cmd *cmd = task->dd_data;
+
+               /* Anil */
+               task->hdr = &cmd->hdr;
+               task->hdr_max = sizeof(struct iscsi_hdr);
+
+               if (bnx2i_alloc_bdt(hba, session, cmd))
+                       goto free_bdts;
+       }
+
+       return 0;
+
+free_bdts:
+       bnx2i_destroy_cmd_pool(hba, session);
+       return -ENOMEM;
+}
+
+
+/**
+ * bnx2i_setup_mp_bdt - allocate BD table resources
+ * @hba:       pointer to adapter structure
+ *
+ * Allocate memory for dummy buffer and associated BD
+ * table to be used by middle path (MP) requests
+ */
+static int bnx2i_setup_mp_bdt(struct bnx2i_hba *hba)
+{
+       int rc = 0;
+       struct iscsi_bd *mp_bdt;
+       u64 addr;
+
+       hba->mp_bd_tbl = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+                                           &hba->mp_bd_dma, GFP_KERNEL);
+       if (!hba->mp_bd_tbl) {
+               printk(KERN_ERR "unable to allocate Middle Path BDT\n");
+               rc = -1;
+               goto out;
+       }
+
+       hba->dummy_buffer = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+                                              &hba->dummy_buf_dma, GFP_KERNEL);
+       if (!hba->dummy_buffer) {
+               printk(KERN_ERR "unable to alloc Middle Path Dummy Buffer\n");
+               dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+                                 hba->mp_bd_tbl, hba->mp_bd_dma);
+               hba->mp_bd_tbl = NULL;
+               rc = -1;
+               goto out;
+       }
+
+       mp_bdt = (struct iscsi_bd *) hba->mp_bd_tbl;
+       addr = (unsigned long) hba->dummy_buf_dma;
+       mp_bdt->buffer_addr_lo = addr & 0xffffffff;
+       mp_bdt->buffer_addr_hi = addr >> 32;
+       mp_bdt->buffer_length = PAGE_SIZE;
+       mp_bdt->flags = ISCSI_BD_LAST_IN_BD_CHAIN |
+                       ISCSI_BD_FIRST_IN_BD_CHAIN;
+out:
+       return rc;
+}
+
+
+/**
+ * bnx2i_free_mp_bdt - releases ITT back to free pool
+ * @hba:       pointer to adapter instance
+ *
+ * free MP dummy buffer and associated BD table
+ */
+static void bnx2i_free_mp_bdt(struct bnx2i_hba *hba)
+{
+       if (hba->mp_bd_tbl) {
+               dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+                                 hba->mp_bd_tbl, hba->mp_bd_dma);
+               hba->mp_bd_tbl = NULL;
+       }
+       if (hba->dummy_buffer) {
+               dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+                                 hba->dummy_buffer, hba->dummy_buf_dma);
+               hba->dummy_buffer = NULL;
+       }
+               return;
+}
+
+/**
+ * bnx2i_drop_session - notifies iscsid of connection error.
+ * @hba:       adapter instance pointer
+ * @session:   iscsi session pointer
+ *
+ * This notifies iscsid that there is a error, so it can initiate
+ * recovery.
+ *
+ * This relies on caller using the iscsi class iterator so the object
+ * is refcounted and does not disapper from under us.
+ */
+void bnx2i_drop_session(struct iscsi_cls_session *cls_session)
+{
+       iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED);
+}
+
+/**
+ * bnx2i_ep_destroy_list_add - add an entry to EP destroy list
+ * @hba:       pointer to adapter instance
+ * @ep:                pointer to endpoint (transport indentifier) structure
+ *
+ * EP destroy queue manager
+ */
+static int bnx2i_ep_destroy_list_add(struct bnx2i_hba *hba,
+                                    struct bnx2i_endpoint *ep)
+{
+       write_lock_bh(&hba->ep_rdwr_lock);
+       list_add_tail(&ep->link, &hba->ep_destroy_list);
+       write_unlock_bh(&hba->ep_rdwr_lock);
+       return 0;
+}
+
+/**
+ * bnx2i_ep_destroy_list_del - add an entry to EP destroy list
+ *
+ * @hba:               pointer to adapter instance
+ * @ep:                pointer to endpoint (transport indentifier) structure
+ *
+ * EP destroy queue manager
+ */
+static int bnx2i_ep_destroy_list_del(struct bnx2i_hba *hba,
+                                    struct bnx2i_endpoint *ep)
+{
+       write_lock_bh(&hba->ep_rdwr_lock);
+       list_del_init(&ep->link);
+       write_unlock_bh(&hba->ep_rdwr_lock);
+
+       return 0;
+}
+
+/**
+ * bnx2i_ep_ofld_list_add - add an entry to ep offload pending list
+ * @hba:       pointer to adapter instance
+ * @ep:                pointer to endpoint (transport indentifier) structure
+ *
+ * pending conn offload completion queue manager
+ */
+static int bnx2i_ep_ofld_list_add(struct bnx2i_hba *hba,
+                                 struct bnx2i_endpoint *ep)
+{
+       write_lock_bh(&hba->ep_rdwr_lock);
+       list_add_tail(&ep->link, &hba->ep_ofld_list);
+       write_unlock_bh(&hba->ep_rdwr_lock);
+       return 0;
+}
+
+/**
+ * bnx2i_ep_ofld_list_del - add an entry to ep offload pending list
+ * @hba:               pointer to adapter instance
+ * @ep:                pointer to endpoint (transport indentifier) structure
+ *
+ * pending conn offload completion queue manager
+ */
+static int bnx2i_ep_ofld_list_del(struct bnx2i_hba *hba,
+                                 struct bnx2i_endpoint *ep)
+{
+       write_lock_bh(&hba->ep_rdwr_lock);
+       list_del_init(&ep->link);
+       write_unlock_bh(&hba->ep_rdwr_lock);
+       return 0;
+}
+
+
+/**
+ * bnx2i_find_ep_in_ofld_list - find iscsi_cid in pending list of endpoints
+ *
+ * @hba:               pointer to adapter instance
+ * @iscsi_cid:         iscsi context ID to find
+ *
+ */
+struct bnx2i_endpoint *
+bnx2i_find_ep_in_ofld_list(struct bnx2i_hba *hba, u32 iscsi_cid)
+{
+       struct list_head *list;
+       struct list_head *tmp;
+       struct bnx2i_endpoint *ep;
+
+       read_lock_bh(&hba->ep_rdwr_lock);
+       list_for_each_safe(list, tmp, &hba->ep_ofld_list) {
+               ep = (struct bnx2i_endpoint *)list;
+
+               if (ep->ep_iscsi_cid == iscsi_cid)
+                       break;
+               ep = NULL;
+       }
+       read_unlock_bh(&hba->ep_rdwr_lock);
+
+       if (!ep)
+               printk(KERN_ERR "l5 cid %d not found\n", iscsi_cid);
+       return ep;
+}
+
+
+/**
+ * bnx2i_find_ep_in_destroy_list - find iscsi_cid in destroy list
+ * @hba:               pointer to adapter instance
+ * @iscsi_cid:         iscsi context ID to find
+ *
+ */
+struct bnx2i_endpoint *
+bnx2i_find_ep_in_destroy_list(struct bnx2i_hba *hba, u32 iscsi_cid)
+{
+       struct list_head *list;
+       struct list_head *tmp;
+       struct bnx2i_endpoint *ep;
+
+       read_lock_bh(&hba->ep_rdwr_lock);
+       list_for_each_safe(list, tmp, &hba->ep_destroy_list) {
+               ep = (struct bnx2i_endpoint *)list;
+
+               if (ep->ep_iscsi_cid == iscsi_cid)
+                       break;
+               ep = NULL;
+       }
+       read_unlock_bh(&hba->ep_rdwr_lock);
+
+       if (!ep)
+               printk(KERN_ERR "l5 cid %d not found\n", iscsi_cid);
+
+       return ep;
+}
+
+/**
+ * bnx2i_setup_host_queue_size - assigns shost->can_queue param
+ * @hba:       pointer to adapter instance
+ * @shost:     scsi host pointer
+ *
+ * Initializes 'can_queue' parameter based on how many outstanding commands
+ *     the device can handle. Each device 5708/5709/57710 has different
+ *     capabilities
+ */
+static void bnx2i_setup_host_queue_size(struct bnx2i_hba *hba,
+                                       struct Scsi_Host *shost)
+{
+       if (test_bit(BNX2I_NX2_DEV_5708, &hba->cnic_dev_type))
+               shost->can_queue = ISCSI_MAX_CMDS_PER_HBA_5708;
+       else if (test_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type))
+               shost->can_queue = ISCSI_MAX_CMDS_PER_HBA_5709;
+       else if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type))
+               shost->can_queue = ISCSI_MAX_CMDS_PER_HBA_57710;
+       else
+               shost->can_queue = ISCSI_MAX_CMDS_PER_HBA_5708;
+}
+
+
+/**
+ * bnx2i_alloc_hba - allocate and init adapter instance
+ * @cnic:      cnic device pointer
+ *
+ * allocate & initialize adapter structure and call other
+ *     support routines to do per adapter initialization
+ */
+struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic)
+{
+       struct Scsi_Host *shost;
+       struct bnx2i_hba *hba;
+
+       shost = iscsi_host_alloc(&bnx2i_host_template, sizeof(*hba), 0);
+       if (!shost)
+               return NULL;
+       shost->dma_boundary = cnic->pcidev->dma_mask;
+       shost->transportt = bnx2i_scsi_xport_template;
+       shost->max_id = ISCSI_MAX_CONNS_PER_HBA;
+       shost->max_channel = 0;
+       shost->max_lun = 512;
+       shost->max_cmd_len = 16;
+
+       hba = iscsi_host_priv(shost);
+       hba->shost = shost;
+       hba->netdev = cnic->netdev;
+       /* Get PCI related information and update hba struct members */
+       hba->pcidev = cnic->pcidev;
+       pci_dev_get(hba->pcidev);
+       hba->pci_did = hba->pcidev->device;
+       hba->pci_vid = hba->pcidev->vendor;
+       hba->pci_sdid = hba->pcidev->subsystem_device;
+       hba->pci_svid = hba->pcidev->subsystem_vendor;
+       hba->pci_func = PCI_FUNC(hba->pcidev->devfn);
+       hba->pci_devno = PCI_SLOT(hba->pcidev->devfn);
+       bnx2i_identify_device(hba);
+
+       bnx2i_identify_device(hba);
+       bnx2i_setup_host_queue_size(hba, shost);
+
+       if (test_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type)) {
+               hba->regview = ioremap_nocache(hba->netdev->base_addr,
+                                              BNX2_MQ_CONFIG2);
+               if (!hba->regview)
+                       goto ioreg_map_err;
+       } else if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) {
+               hba->regview = ioremap_nocache(hba->netdev->base_addr, 4096);
+               if (!hba->regview)
+                       goto ioreg_map_err;
+       }
+
+       if (bnx2i_setup_mp_bdt(hba))
+               goto mp_bdt_mem_err;
+
+       INIT_LIST_HEAD(&hba->ep_ofld_list);
+       INIT_LIST_HEAD(&hba->ep_destroy_list);
+       rwlock_init(&hba->ep_rdwr_lock);
+
+       hba->mtu_supported = BNX2I_MAX_MTU_SUPPORTED;
+
+       /* different values for 5708/5709/57710 */
+       hba->max_active_conns = ISCSI_MAX_CONNS_PER_HBA;
+
+       if (bnx2i_setup_free_cid_que(hba))
+               goto cid_que_err;
+
+       /* SQ/RQ/CQ size can be changed via sysfx interface */
+       if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) {
+               if (sq_size && sq_size <= BNX2I_5770X_SQ_WQES_MAX)
+                       hba->max_sqes = sq_size;
+               else
+                       hba->max_sqes = BNX2I_5770X_SQ_WQES_DEFAULT;
+       } else {        /* 5706/5708/5709 */
+               if (sq_size && sq_size <= BNX2I_570X_SQ_WQES_MAX)
+                       hba->max_sqes = sq_size;
+               else
+                       hba->max_sqes = BNX2I_570X_SQ_WQES_DEFAULT;
+       }
+
+       hba->max_rqes = rq_size;
+       hba->max_cqes = hba->max_sqes + rq_size;
+       if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) {
+               if (hba->max_cqes > BNX2I_5770X_CQ_WQES_MAX)
+                       hba->max_cqes = BNX2I_5770X_CQ_WQES_MAX;
+       } else if (hba->max_cqes > BNX2I_570X_CQ_WQES_MAX)
+               hba->max_cqes = BNX2I_570X_CQ_WQES_MAX;
+
+       hba->num_ccell = hba->max_sqes / 2;
+
+       spin_lock_init(&hba->lock);
+       mutex_init(&hba->net_dev_lock);
+
+       if (iscsi_host_add(shost, &hba->pcidev->dev))
+               goto free_dump_mem;
+       return hba;
+
+free_dump_mem:
+       bnx2i_release_free_cid_que(hba);
+cid_que_err:
+       bnx2i_free_mp_bdt(hba);
+mp_bdt_mem_err:
+       if (hba->regview) {
+               iounmap(hba->regview);
+               hba->regview = NULL;
+       }
+ioreg_map_err:
+       pci_dev_put(hba->pcidev);
+       scsi_host_put(shost);
+       return NULL;
+}
+
+/**
+ * bnx2i_free_hba- releases hba structure and resources held by the adapter
+ * @hba:       pointer to adapter instance
+ *
+ * free adapter structure and call various cleanup routines.
+ */
+void bnx2i_free_hba(struct bnx2i_hba *hba)
+{
+       struct Scsi_Host *shost = hba->shost;
+
+       iscsi_host_remove(shost);
+       INIT_LIST_HEAD(&hba->ep_ofld_list);
+       INIT_LIST_HEAD(&hba->ep_destroy_list);
+       pci_dev_put(hba->pcidev);
+
+       if (hba->regview) {
+               iounmap(hba->regview);
+               hba->regview = NULL;
+       }
+       bnx2i_free_mp_bdt(hba);
+       bnx2i_release_free_cid_que(hba);
+       iscsi_host_free(shost);
+}
+
+/**
+ * bnx2i_conn_free_login_resources - free DMA resources used for login process
+ * @hba:               pointer to adapter instance
+ * @bnx2i_conn:                iscsi connection pointer
+ *
+ * Login related resources, mostly BDT & payload DMA memory is freed
+ */
+static void bnx2i_conn_free_login_resources(struct bnx2i_hba *hba,
+                                           struct bnx2i_conn *bnx2i_conn)
+{
+       if (bnx2i_conn->gen_pdu.resp_bd_tbl) {
+               dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+                                 bnx2i_conn->gen_pdu.resp_bd_tbl,
+                                 bnx2i_conn->gen_pdu.resp_bd_dma);
+               bnx2i_conn->gen_pdu.resp_bd_tbl = NULL;
+       }
+
+       if (bnx2i_conn->gen_pdu.req_bd_tbl) {
+               dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+                                 bnx2i_conn->gen_pdu.req_bd_tbl,
+                                 bnx2i_conn->gen_pdu.req_bd_dma);
+               bnx2i_conn->gen_pdu.req_bd_tbl = NULL;
+       }
+
+       if (bnx2i_conn->gen_pdu.resp_buf) {
+               dma_free_coherent(&hba->pcidev->dev,
+                                 ISCSI_DEF_MAX_RECV_SEG_LEN,
+                                 bnx2i_conn->gen_pdu.resp_buf,
+                                 bnx2i_conn->gen_pdu.resp_dma_addr);
+               bnx2i_conn->gen_pdu.resp_buf = NULL;
+       }
+
+       if (bnx2i_conn->gen_pdu.req_buf) {
+               dma_free_coherent(&hba->pcidev->dev,
+                                 ISCSI_DEF_MAX_RECV_SEG_LEN,
+                                 bnx2i_conn->gen_pdu.req_buf,
+                                 bnx2i_conn->gen_pdu.req_dma_addr);
+               bnx2i_conn->gen_pdu.req_buf = NULL;
+       }
+}
+
+/**
+ * bnx2i_conn_alloc_login_resources - alloc DMA resources for login/nop.
+ * @hba:               pointer to adapter instance
+ * @bnx2i_conn:                iscsi connection pointer
+ *
+ * Mgmt task DNA resources are allocated in this routine.
+ */
+static int bnx2i_conn_alloc_login_resources(struct bnx2i_hba *hba,
+                                           struct bnx2i_conn *bnx2i_conn)
+{
+       /* Allocate memory for login request/response buffers */
+       bnx2i_conn->gen_pdu.req_buf =
+               dma_alloc_coherent(&hba->pcidev->dev,
+                                  ISCSI_DEF_MAX_RECV_SEG_LEN,
+                                  &bnx2i_conn->gen_pdu.req_dma_addr,
+                                  GFP_KERNEL);
+       if (bnx2i_conn->gen_pdu.req_buf == NULL)
+               goto login_req_buf_failure;
+
+       bnx2i_conn->gen_pdu.req_buf_size = 0;
+       bnx2i_conn->gen_pdu.req_wr_ptr = bnx2i_conn->gen_pdu.req_buf;
+
+       bnx2i_conn->gen_pdu.resp_buf =
+               dma_alloc_coherent(&hba->pcidev->dev,
+                                  ISCSI_DEF_MAX_RECV_SEG_LEN,
+                                  &bnx2i_conn->gen_pdu.resp_dma_addr,
+                                  GFP_KERNEL);
+       if (bnx2i_conn->gen_pdu.resp_buf == NULL)
+               goto login_resp_buf_failure;
+
+       bnx2i_conn->gen_pdu.resp_buf_size = ISCSI_DEF_MAX_RECV_SEG_LEN;
+       bnx2i_conn->gen_pdu.resp_wr_ptr = bnx2i_conn->gen_pdu.resp_buf;
+
+       bnx2i_conn->gen_pdu.req_bd_tbl =
+               dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+                                  &bnx2i_conn->gen_pdu.req_bd_dma, GFP_KERNEL);
+       if (bnx2i_conn->gen_pdu.req_bd_tbl == NULL)
+               goto login_req_bd_tbl_failure;
+
+       bnx2i_conn->gen_pdu.resp_bd_tbl =
+               dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+                                  &bnx2i_conn->gen_pdu.resp_bd_dma,
+                                  GFP_KERNEL);
+       if (bnx2i_conn->gen_pdu.resp_bd_tbl == NULL)
+               goto login_resp_bd_tbl_failure;
+
+       return 0;
+
+login_resp_bd_tbl_failure:
+       dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+                         bnx2i_conn->gen_pdu.req_bd_tbl,
+                         bnx2i_conn->gen_pdu.req_bd_dma);
+       bnx2i_conn->gen_pdu.req_bd_tbl = NULL;
+
+login_req_bd_tbl_failure:
+       dma_free_coherent(&hba->pcidev->dev, ISCSI_DEF_MAX_RECV_SEG_LEN,
+                         bnx2i_conn->gen_pdu.resp_buf,
+                         bnx2i_conn->gen_pdu.resp_dma_addr);
+       bnx2i_conn->gen_pdu.resp_buf = NULL;
+login_resp_buf_failure:
+       dma_free_coherent(&hba->pcidev->dev, ISCSI_DEF_MAX_RECV_SEG_LEN,
+                         bnx2i_conn->gen_pdu.req_buf,
+                         bnx2i_conn->gen_pdu.req_dma_addr);
+       bnx2i_conn->gen_pdu.req_buf = NULL;
+login_req_buf_failure:
+       iscsi_conn_printk(KERN_ERR, bnx2i_conn->cls_conn->dd_data,
+                         "login resource alloc failed!!\n");
+       return -ENOMEM;
+
+}
+
+
+/**
+ * bnx2i_iscsi_prep_generic_pdu_bd - prepares BD table.
+ * @bnx2i_conn:                iscsi connection pointer
+ *
+ * Allocates buffers and BD tables before shipping requests to cnic
+ *     for PDUs prepared by 'iscsid' daemon
+ */
+static void bnx2i_iscsi_prep_generic_pdu_bd(struct bnx2i_conn *bnx2i_conn)
+{
+       struct iscsi_bd *bd_tbl;
+
+       bd_tbl = (struct iscsi_bd *) bnx2i_conn->gen_pdu.req_bd_tbl;
+
+       bd_tbl->buffer_addr_hi =
+               (u32) ((u64) bnx2i_conn->gen_pdu.req_dma_addr >> 32);
+       bd_tbl->buffer_addr_lo = (u32) bnx2i_conn->gen_pdu.req_dma_addr;
+       bd_tbl->buffer_length = bnx2i_conn->gen_pdu.req_wr_ptr -
+                               bnx2i_conn->gen_pdu.req_buf;
+       bd_tbl->reserved0 = 0;
+       bd_tbl->flags = ISCSI_BD_LAST_IN_BD_CHAIN |
+                       ISCSI_BD_FIRST_IN_BD_CHAIN;
+
+       bd_tbl = (struct iscsi_bd  *) bnx2i_conn->gen_pdu.resp_bd_tbl;
+       bd_tbl->buffer_addr_hi = (u64) bnx2i_conn->gen_pdu.resp_dma_addr >> 32;
+       bd_tbl->buffer_addr_lo = (u32) bnx2i_conn->gen_pdu.resp_dma_addr;
+       bd_tbl->buffer_length = ISCSI_DEF_MAX_RECV_SEG_LEN;
+       bd_tbl->reserved0 = 0;
+       bd_tbl->flags = ISCSI_BD_LAST_IN_BD_CHAIN |
+                       ISCSI_BD_FIRST_IN_BD_CHAIN;
+}
+
+
+/**
+ * bnx2i_iscsi_send_generic_request - called to send mgmt tasks.
+ * @task:      transport layer task pointer
+ *
+ * called to transmit PDUs prepared by the 'iscsid' daemon. iSCSI login,
+ *     Nop-out and Logout requests flow through this path.
+ */
+static int bnx2i_iscsi_send_generic_request(struct iscsi_task *task)
+{
+       struct bnx2i_cmd *cmd = task->dd_data;
+       struct bnx2i_conn *bnx2i_conn = cmd->conn;
+       int rc = 0;
+       char *buf;
+       int data_len;
+
+       bnx2i_iscsi_prep_generic_pdu_bd(bnx2i_conn);
+       switch (task->hdr->opcode & ISCSI_OPCODE_MASK) {
+       case ISCSI_OP_LOGIN:
+               bnx2i_send_iscsi_login(bnx2i_conn, task);
+               break;
+       case ISCSI_OP_NOOP_OUT:
+               data_len = bnx2i_conn->gen_pdu.req_buf_size;
+               buf = bnx2i_conn->gen_pdu.req_buf;
+               if (data_len)
+                       rc = bnx2i_send_iscsi_nopout(bnx2i_conn, task,
+                                                    RESERVED_ITT,
+                                                    buf, data_len, 1);
+               else
+                       rc = bnx2i_send_iscsi_nopout(bnx2i_conn, task,
+                                                    RESERVED_ITT,
+                                                    NULL, 0, 1);
+               break;
+       case ISCSI_OP_LOGOUT:
+               rc = bnx2i_send_iscsi_logout(bnx2i_conn, task);
+               break;
+       case ISCSI_OP_SCSI_TMFUNC:
+               rc = bnx2i_send_iscsi_tmf(bnx2i_conn, task);
+               break;
+       default:
+               iscsi_conn_printk(KERN_ALERT, bnx2i_conn->cls_conn->dd_data,
+                                 "send_gen: unsupported op 0x%x\n",
+                                 task->hdr->opcode);
+       }
+       return rc;
+}
+
+
+/**********************************************************************
+ *             SCSI-ML Interface
+ **********************************************************************/
+
+/**
+ * bnx2i_cpy_scsi_cdb - copies LUN & CDB fields in required format to sq wqe
+ * @sc:                SCSI-ML command pointer
+ * @cmd:       iscsi cmd pointer
+ */
+static void bnx2i_cpy_scsi_cdb(struct scsi_cmnd *sc, struct bnx2i_cmd *cmd)
+{
+       u32 dword;
+       int lpcnt;
+       u8 *srcp;
+       u32 *dstp;
+       u32 scsi_lun[2];
+
+       int_to_scsilun(sc->device->lun, (struct scsi_lun *) scsi_lun);
+       cmd->req.lun[0] = be32_to_cpu(scsi_lun[0]);
+       cmd->req.lun[1] = be32_to_cpu(scsi_lun[1]);
+
+       lpcnt = cmd->scsi_cmd->cmd_len / sizeof(dword);
+       srcp = (u8 *) sc->cmnd;
+       dstp = (u32 *) cmd->req.cdb;
+       while (lpcnt--) {
+               memcpy(&dword, (const void *) srcp, 4);
+               *dstp = cpu_to_be32(dword);
+               srcp += 4;
+               dstp++;
+       }
+       if (sc->cmd_len & 0x3) {
+               dword = (u32) srcp[0] | ((u32) srcp[1] << 8);
+               *dstp = cpu_to_be32(dword);
+       }
+}
+
+static void bnx2i_cleanup_task(struct iscsi_task *task)
+{
+       struct iscsi_conn *conn = task->conn;
+       struct bnx2i_conn *bnx2i_conn = conn->dd_data;
+       struct bnx2i_hba *hba = bnx2i_conn->hba;
+
+       /*
+        * mgmt task or cmd was never sent to us to transmit.
+        */
+       if (!task->sc || task->state == ISCSI_TASK_PENDING)
+               return;
+       /*
+        * need to clean-up task context to claim dma buffers
+        */
+       if (task->state == ISCSI_TASK_ABRT_TMF) {
+               bnx2i_send_cmd_cleanup_req(hba, task->dd_data);
+
+               spin_unlock_bh(&conn->session->lock);
+               wait_for_completion_timeout(&bnx2i_conn->cmd_cleanup_cmpl,
+                               msecs_to_jiffies(ISCSI_CMD_CLEANUP_TIMEOUT));
+               spin_lock_bh(&conn->session->lock);
+       }
+       bnx2i_iscsi_unmap_sg_list(task->dd_data);
+}
+
+/**
+ * bnx2i_mtask_xmit - transmit mtask to chip for further processing
+ * @conn:      transport layer conn structure pointer
+ * @task:      transport layer command structure pointer
+ */
+static int
+bnx2i_mtask_xmit(struct iscsi_conn *conn, struct iscsi_task *task)
+{
+       struct bnx2i_conn *bnx2i_conn = conn->dd_data;
+       struct bnx2i_cmd *cmd = task->dd_data;
+
+       memset(bnx2i_conn->gen_pdu.req_buf, 0, ISCSI_DEF_MAX_RECV_SEG_LEN);
+
+       bnx2i_setup_cmd_wqe_template(cmd);
+       bnx2i_conn->gen_pdu.req_buf_size = task->data_count;
+       if (task->data_count) {
+               memcpy(bnx2i_conn->gen_pdu.req_buf, task->data,
+                      task->data_count);
+               bnx2i_conn->gen_pdu.req_wr_ptr =
+                       bnx2i_conn->gen_pdu.req_buf + task->data_count;
+       }
+       cmd->conn = conn->dd_data;
+       cmd->scsi_cmd = NULL;
+       return bnx2i_iscsi_send_generic_request(task);
+}
+
+/**
+ * bnx2i_task_xmit - transmit iscsi command to chip for further processing
+ * @task:      transport layer command structure pointer
+ *
+ * maps SG buffers and send request to chip/firmware in the form of SQ WQE
+ */
+static int bnx2i_task_xmit(struct iscsi_task *task)
+{
+       struct iscsi_conn *conn = task->conn;
+       struct iscsi_session *session = conn->session;
+       struct Scsi_Host *shost = iscsi_session_to_shost(session->cls_session);
+       struct bnx2i_hba *hba = iscsi_host_priv(shost);
+       struct bnx2i_conn *bnx2i_conn = conn->dd_data;
+       struct scsi_cmnd *sc = task->sc;
+       struct bnx2i_cmd *cmd = task->dd_data;
+       struct iscsi_cmd *hdr = (struct iscsi_cmd *) task->hdr;
+
+       if (test_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state))
+               return -ENOTCONN;
+
+       if (!bnx2i_conn->is_bound)
+               return -ENOTCONN;
+
+       /*
+        * If there is no scsi_cmnd this must be a mgmt task
+        */
+       if (!sc)
+               return bnx2i_mtask_xmit(conn, task);
+
+       bnx2i_setup_cmd_wqe_template(cmd);
+       cmd->req.op_code = ISCSI_OP_SCSI_CMD;
+       cmd->conn = bnx2i_conn;
+       cmd->scsi_cmd = sc;
+       cmd->req.total_data_transfer_length = scsi_bufflen(sc);
+       cmd->req.cmd_sn = be32_to_cpu(hdr->cmdsn);
+
+       bnx2i_iscsi_map_sg_list(cmd);
+       bnx2i_cpy_scsi_cdb(sc, cmd);
+
+       cmd->req.op_attr = ISCSI_ATTR_SIMPLE;
+       if (sc->sc_data_direction == DMA_TO_DEVICE) {
+               cmd->req.op_attr |= ISCSI_CMD_REQUEST_WRITE;
+               cmd->req.itt = task->itt |
+                       (ISCSI_TASK_TYPE_WRITE << ISCSI_CMD_REQUEST_TYPE_SHIFT);
+               bnx2i_setup_write_cmd_bd_info(task);
+       } else {
+               if (scsi_bufflen(sc))
+                       cmd->req.op_attr |= ISCSI_CMD_REQUEST_READ;
+               cmd->req.itt = task->itt |
+                       (ISCSI_TASK_TYPE_READ << ISCSI_CMD_REQUEST_TYPE_SHIFT);
+       }
+
+       cmd->req.num_bds = cmd->io_tbl.bd_valid;
+       if (!cmd->io_tbl.bd_valid) {
+               cmd->req.bd_list_addr_lo = (u32) hba->mp_bd_dma;
+               cmd->req.bd_list_addr_hi = (u32) ((u64) hba->mp_bd_dma >> 32);
+               cmd->req.num_bds = 1;
+       }
+
+       bnx2i_send_iscsi_scsicmd(bnx2i_conn, cmd);
+       return 0;
+}
+
+/**
+ * bnx2i_session_create - create a new iscsi session
+ * @cmds_max:          max commands supported
+ * @qdepth:            scsi queue depth to support
+ * @initial_cmdsn:     initial iscsi CMDSN to be used for this session
+ *
+ * Creates a new iSCSI session instance on given device.
+ */
+static struct iscsi_cls_session *
+bnx2i_session_create(struct iscsi_endpoint *ep,
+                    uint16_t cmds_max, uint16_t qdepth,
+                    uint32_t initial_cmdsn)
+{
+       struct Scsi_Host *shost;
+       struct iscsi_cls_session *cls_session;
+       struct bnx2i_hba *hba;
+       struct bnx2i_endpoint *bnx2i_ep;
+
+       if (!ep) {
+               printk(KERN_ERR "bnx2i: missing ep.\n");
+               return NULL;
+       }
+
+       bnx2i_ep = ep->dd_data;
+       shost = bnx2i_ep->hba->shost;
+       hba = iscsi_host_priv(shost);
+       if (bnx2i_adapter_ready(hba))
+               return NULL;
+
+       /*
+        * user can override hw limit as long as it is within
+        * the min/max.
+        */
+       if (cmds_max > hba->max_sqes)
+               cmds_max = hba->max_sqes;
+       else if (cmds_max < BNX2I_SQ_WQES_MIN)
+               cmds_max = BNX2I_SQ_WQES_MIN;
+
+       cls_session = iscsi_session_setup(&bnx2i_iscsi_transport, shost,
+                                         cmds_max, sizeof(struct bnx2i_cmd),
+                                         initial_cmdsn, ISCSI_MAX_TARGET);
+       if (!cls_session)
+               return NULL;
+
+       if (bnx2i_setup_cmd_pool(hba, cls_session->dd_data))
+               goto session_teardown;
+       return cls_session;
+
+session_teardown:
+       iscsi_session_teardown(cls_session);
+       return NULL;
+}
+
+
+/**
+ * bnx2i_session_destroy - destroys iscsi session
+ * @cls_session:       pointer to iscsi cls session
+ *
+ * Destroys previously created iSCSI session instance and releases
+ *     all resources held by it
+ */
+static void bnx2i_session_destroy(struct iscsi_cls_session *cls_session)
+{
+       struct iscsi_session *session = cls_session->dd_data;
+       struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
+       struct bnx2i_hba *hba = iscsi_host_priv(shost);
+
+       bnx2i_destroy_cmd_pool(hba, session);
+       iscsi_session_teardown(cls_session);
+}
+
+
+/**
+ * bnx2i_conn_create - create iscsi connection instance
+ * @cls_session:       pointer to iscsi cls session
+ * @cid:               iscsi cid as per rfc (not NX2's CID terminology)
+ *
+ * Creates a new iSCSI connection instance for a given session
+ */
+static struct iscsi_cls_conn *
+bnx2i_conn_create(struct iscsi_cls_session *cls_session, uint32_t cid)
+{
+       struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
+       struct bnx2i_hba *hba = iscsi_host_priv(shost);
+       struct bnx2i_conn *bnx2i_conn;
+       struct iscsi_cls_conn *cls_conn;
+       struct iscsi_conn *conn;
+
+       cls_conn = iscsi_conn_setup(cls_session, sizeof(*bnx2i_conn),
+                                   cid);
+       if (!cls_conn)
+               return NULL;
+       conn = cls_conn->dd_data;
+
+       bnx2i_conn = conn->dd_data;
+       bnx2i_conn->cls_conn = cls_conn;
+       bnx2i_conn->hba = hba;
+       /* 'ep' ptr will be assigned in bind() call */
+       bnx2i_conn->ep = NULL;
+       init_completion(&bnx2i_conn->cmd_cleanup_cmpl);
+
+       if (bnx2i_conn_alloc_login_resources(hba, bnx2i_conn)) {
+               iscsi_conn_printk(KERN_ALERT, conn,
+                                 "conn_new: login resc alloc failed!!\n");
+               goto free_conn;
+       }
+
+       return cls_conn;
+
+free_conn:
+       iscsi_conn_teardown(cls_conn);
+       return NULL;
+}
+
+/**
+ * bnx2i_conn_bind - binds iscsi sess, conn and ep objects together
+ * @cls_session:       pointer to iscsi cls session
+ * @cls_conn:          pointer to iscsi cls conn
+ * @transport_fd:      64-bit EP handle
+ * @is_leading:                leading connection on this session?
+ *
+ * Binds together iSCSI session instance, iSCSI connection instance
+ *     and the TCP connection. This routine returns error code if
+ *     TCP connection does not belong on the device iSCSI sess/conn
+ *     is bound
+ */
+static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session,
+                          struct iscsi_cls_conn *cls_conn,
+                          uint64_t transport_fd, int is_leading)
+{
+       struct iscsi_conn *conn = cls_conn->dd_data;
+       struct bnx2i_conn *bnx2i_conn = conn->dd_data;
+       struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
+       struct bnx2i_hba *hba = iscsi_host_priv(shost);
+       struct bnx2i_endpoint *bnx2i_ep;
+       struct iscsi_endpoint *ep;
+       int ret_code;
+
+       ep = iscsi_lookup_endpoint(transport_fd);
+       if (!ep)
+               return -EINVAL;
+
+       bnx2i_ep = ep->dd_data;
+       if ((bnx2i_ep->state == EP_STATE_TCP_FIN_RCVD) ||
+           (bnx2i_ep->state == EP_STATE_TCP_RST_RCVD))
+               /* Peer disconnect via' FIN or RST */
+               return -EINVAL;
+
+       if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
+               return -EINVAL;
+
+       if (bnx2i_ep->hba != hba) {
+               /* Error - TCP connection does not belong to this device
+                */
+               iscsi_conn_printk(KERN_ALERT, cls_conn->dd_data,
+                                 "conn bind, ep=0x%p (%s) does not",
+                                 bnx2i_ep, bnx2i_ep->hba->netdev->name);
+               iscsi_conn_printk(KERN_ALERT, cls_conn->dd_data,
+                                 "belong to hba (%s)\n",
+                                 hba->netdev->name);
+               return -EEXIST;
+       }
+
+       bnx2i_ep->conn = bnx2i_conn;
+       bnx2i_conn->ep = bnx2i_ep;
+       bnx2i_conn->iscsi_conn_cid = bnx2i_ep->ep_iscsi_cid;
+       bnx2i_conn->fw_cid = bnx2i_ep->ep_cid;
+       bnx2i_conn->is_bound = 1;
+
+       ret_code = bnx2i_bind_conn_to_iscsi_cid(hba, bnx2i_conn,
+                                               bnx2i_ep->ep_iscsi_cid);
+
+       /* 5706/5708/5709 FW takes RQ as full when initiated, but for 57710
+        * driver needs to explicitly replenish RQ index during setup.
+        */
+       if (test_bit(BNX2I_NX2_DEV_57710, &bnx2i_ep->hba->cnic_dev_type))
+               bnx2i_put_rq_buf(bnx2i_conn, 0);
+
+       bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE);
+       return ret_code;
+}
+
+
+/**
+ * bnx2i_conn_destroy - destroy iscsi connection instance & release resources
+ * @cls_conn:  pointer to iscsi cls conn
+ *
+ * Destroy an iSCSI connection instance and release memory resources held by
+ *     this connection
+ */
+static void bnx2i_conn_destroy(struct iscsi_cls_conn *cls_conn)
+{
+       struct iscsi_conn *conn = cls_conn->dd_data;
+       struct bnx2i_conn *bnx2i_conn = conn->dd_data;
+       struct Scsi_Host *shost;
+       struct bnx2i_hba *hba;
+
+       shost = iscsi_session_to_shost(iscsi_conn_to_session(cls_conn));
+       hba = iscsi_host_priv(shost);
+
+       bnx2i_conn_free_login_resources(hba, bnx2i_conn);
+       iscsi_conn_teardown(cls_conn);
+}
+
+
+/**
+ * bnx2i_conn_get_param - return iscsi connection parameter to caller
+ * @cls_conn:  pointer to iscsi cls conn
+ * @param:     parameter type identifier
+ * @buf:       buffer pointer
+ *
+ * returns iSCSI connection parameters
+ */
+static int bnx2i_conn_get_param(struct iscsi_cls_conn *cls_conn,
+                               enum iscsi_param param, char *buf)
+{
+       struct iscsi_conn *conn = cls_conn->dd_data;
+       struct bnx2i_conn *bnx2i_conn = conn->dd_data;
+       int len = 0;
+
+       switch (param) {
+       case ISCSI_PARAM_CONN_PORT:
+               if (bnx2i_conn->ep)
+                       len = sprintf(buf, "%hu\n",
+                                     bnx2i_conn->ep->cm_sk->dst_port);
+               break;
+       case ISCSI_PARAM_CONN_ADDRESS:
+               if (bnx2i_conn->ep)
+                       len = sprintf(buf, NIPQUAD_FMT "\n",
+                                     NIPQUAD(bnx2i_conn->ep->cm_sk->dst_ip));
+               break;
+       default:
+               return iscsi_conn_get_param(cls_conn, param, buf);
+       }
+
+       return len;
+}
+
+/**
+ * bnx2i_host_get_param - returns host (adapter) related parameters
+ * @shost:     scsi host pointer
+ * @param:     parameter type identifier
+ * @buf:       buffer pointer
+ */
+static int bnx2i_host_get_param(struct Scsi_Host *shost,
+                               enum iscsi_host_param param, char *buf)
+{
+       struct bnx2i_hba *hba = iscsi_host_priv(shost);
+       int len = 0;
+
+       switch (param) {
+       case ISCSI_HOST_PARAM_HWADDRESS:
+               len = sysfs_format_mac(buf, hba->cnic->mac_addr, 6);
+               break;
+       case ISCSI_HOST_PARAM_NETDEV_NAME:
+               len = sprintf(buf, "%s\n", hba->netdev->name);
+               break;
+       default:
+               return iscsi_host_get_param(shost, param, buf);
+       }
+       return len;
+}
+
+/**
+ * bnx2i_conn_start - completes iscsi connection migration to FFP
+ * @cls_conn:  pointer to iscsi cls conn
+ *
+ * last call in FFP migration to handover iscsi conn to the driver
+ */
+static int bnx2i_conn_start(struct iscsi_cls_conn *cls_conn)
+{
+       struct iscsi_conn *conn = cls_conn->dd_data;
+       struct bnx2i_conn *bnx2i_conn = conn->dd_data;
+
+       bnx2i_conn->ep->state = EP_STATE_ULP_UPDATE_START;
+       bnx2i_update_iscsi_conn(conn);
+
+       /*
+        * this should normally not sleep for a long time so it should
+        * not disrupt the caller.
+        */
+       bnx2i_conn->ep->ofld_timer.expires = 1 * HZ + jiffies;
+       bnx2i_conn->ep->ofld_timer.function = bnx2i_ep_ofld_timer;
+       bnx2i_conn->ep->ofld_timer.data = (unsigned long) bnx2i_conn->ep;
+       add_timer(&bnx2i_conn->ep->ofld_timer);
+       /* update iSCSI context for this conn, wait for CNIC to complete */
+       wait_event_interruptible(bnx2i_conn->ep->ofld_wait,
+                       bnx2i_conn->ep->state != EP_STATE_ULP_UPDATE_START);
+
+       if (signal_pending(current))
+               flush_signals(current);
+       del_timer_sync(&bnx2i_conn->ep->ofld_timer);
+
+       iscsi_conn_start(cls_conn);
+       return 0;
+}
+
+
+/**
+ * bnx2i_conn_get_stats - returns iSCSI stats
+ * @cls_conn:  pointer to iscsi cls conn
+ * @stats:     pointer to iscsi statistic struct
+ */
+static void bnx2i_conn_get_stats(struct iscsi_cls_conn *cls_conn,
+                                struct iscsi_stats *stats)
+{
+       struct iscsi_conn *conn = cls_conn->dd_data;
+
+       stats->txdata_octets = conn->txdata_octets;
+       stats->rxdata_octets = conn->rxdata_octets;
+       stats->scsicmd_pdus = conn->scsicmd_pdus_cnt;
+       stats->dataout_pdus = conn->dataout_pdus_cnt;
+       stats->scsirsp_pdus = conn->scsirsp_pdus_cnt;
+       stats->datain_pdus = conn->datain_pdus_cnt;
+       stats->r2t_pdus = conn->r2t_pdus_cnt;
+       stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt;
+       stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt;
+       stats->custom_length = 3;
+       strcpy(stats->custom[2].desc, "eh_abort_cnt");
+       stats->custom[2].value = conn->eh_abort_cnt;
+       stats->digest_err = 0;
+       stats->timeout_err = 0;
+       stats->custom_length = 0;
+}
+
+
+/**
+ * bnx2i_check_route - checks if target IP route belongs to one of NX2 devices
+ * @dst_addr:  target IP address
+ *
+ * check if route resolves to BNX2 device
+ */
+static struct bnx2i_hba *bnx2i_check_route(struct sockaddr *dst_addr)
+{
+       struct sockaddr_in *desti = (struct sockaddr_in *) dst_addr;
+       struct bnx2i_hba *hba;
+       struct cnic_dev *cnic = NULL;
+
+       bnx2i_reg_dev_all();
+
+       hba = get_adapter_list_head();
+       if (hba && hba->cnic)
+               cnic = hba->cnic->cm_select_dev(desti, CNIC_ULP_ISCSI);
+       if (!cnic) {
+               printk(KERN_ALERT "bnx2i: no route,"
+                      "can't connect using cnic\n");
+               goto no_nx2_route;
+       }
+       hba = bnx2i_find_hba_for_cnic(cnic);
+       if (!hba)
+               goto no_nx2_route;
+
+       if (bnx2i_adapter_ready(hba)) {
+               printk(KERN_ALERT "bnx2i: check route, hba not found\n");
+               goto no_nx2_route;
+       }
+       if (hba->netdev->mtu > hba->mtu_supported) {
+               printk(KERN_ALERT "bnx2i: %s network i/f mtu is set to %d\n",
+                                 hba->netdev->name, hba->netdev->mtu);
+               printk(KERN_ALERT "bnx2i: iSCSI HBA can support mtu of %d\n",
+                                 hba->mtu_supported);
+               goto no_nx2_route;
+       }
+       return hba;
+no_nx2_route:
+       return NULL;
+}
+
+
+/**
+ * bnx2i_tear_down_conn - tear down iscsi/tcp connection and free resources
+ * @hba:       pointer to adapter instance
+ * @ep:                endpoint (transport indentifier) structure
+ *
+ * destroys cm_sock structure and on chip iscsi context
+ */
+static int bnx2i_tear_down_conn(struct bnx2i_hba *hba,
+                                struct bnx2i_endpoint *ep)
+{
+       if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic))
+               hba->cnic->cm_destroy(ep->cm_sk);
+
+       if (test_bit(ADAPTER_STATE_GOING_DOWN, &ep->hba->adapter_state))
+               ep->state = EP_STATE_DISCONN_COMPL;
+
+       if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type) &&
+           ep->state == EP_STATE_DISCONN_TIMEDOUT) {
+               printk(KERN_ALERT "bnx2i - ERROR - please submit GRC Dump,"
+                                 " NW/PCIe trace, driver msgs to developers"
+                                 " for analysis\n");
+               return 1;
+       }
+
+       ep->state = EP_STATE_CLEANUP_START;
+       init_timer(&ep->ofld_timer);
+       ep->ofld_timer.expires = 10*HZ + jiffies;
+       ep->ofld_timer.function = bnx2i_ep_ofld_timer;
+       ep->ofld_timer.data = (unsigned long) ep;
+       add_timer(&ep->ofld_timer);
+
+       bnx2i_ep_destroy_list_add(hba, ep);
+
+       /* destroy iSCSI context, wait for it to complete */
+       bnx2i_send_conn_destroy(hba, ep);
+       wait_event_interruptible(ep->ofld_wait,
+                                (ep->state != EP_STATE_CLEANUP_START));
+
+       if (signal_pending(current))
+               flush_signals(current);
+       del_timer_sync(&ep->ofld_timer);
+
+       bnx2i_ep_destroy_list_del(hba, ep);
+
+       if (ep->state != EP_STATE_CLEANUP_CMPL)
+               /* should never happen */
+               printk(KERN_ALERT "bnx2i - conn destroy failed\n");
+
+       return 0;
+}
+
+
+/**
+ * bnx2i_ep_connect - establish TCP connection to target portal
+ * @shost:             scsi host
+ * @dst_addr:          target IP address
+ * @non_blocking:      blocking or non-blocking call
+ *
+ * this routine initiates the TCP/IP connection by invoking Option-2 i/f
+ *     with l5_core and the CNIC. This is a multi-step process of resolving
+ *     route to target, create a iscsi connection context, handshaking with
+ *     CNIC module to create/initialize the socket struct and finally
+ *     sending down option-2 request to complete TCP 3-way handshake
+ */
+static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
+                                              struct sockaddr *dst_addr,
+                                              int non_blocking)
+{
+       u32 iscsi_cid = BNX2I_CID_RESERVED;
+       struct sockaddr_in *desti = (struct sockaddr_in *) dst_addr;
+       struct sockaddr_in6 *desti6;
+       struct bnx2i_endpoint *bnx2i_ep;
+       struct bnx2i_hba *hba;
+       struct cnic_dev *cnic;
+       struct cnic_sockaddr saddr;
+       struct iscsi_endpoint *ep;
+       int rc = 0;
+
+       if (shost)
+               /* driver is given scsi host to work with */
+               hba = iscsi_host_priv(shost);
+       else
+               /*
+                * check if the given destination can be reached through
+                * a iscsi capable NetXtreme2 device
+                */
+               hba = bnx2i_check_route(dst_addr);
+       if (!hba) {
+               rc = -ENOMEM;
+               goto check_busy;
+       }
+
+       cnic = hba->cnic;
+       ep = bnx2i_alloc_ep(hba);
+       if (!ep) {
+               rc = -ENOMEM;
+               goto check_busy;
+       }
+       bnx2i_ep = ep->dd_data;
+
+       mutex_lock(&hba->net_dev_lock);
+       if (bnx2i_adapter_ready(hba)) {
+               rc = -EPERM;
+               goto net_if_down;
+       }
+
+       bnx2i_ep->state = EP_STATE_IDLE;
+       bnx2i_ep->ep_iscsi_cid = (u16) -1;
+       bnx2i_ep->num_active_cmds = 0;
+       iscsi_cid = bnx2i_alloc_iscsi_cid(hba);
+       if (iscsi_cid == -1) {
+               printk(KERN_ALERT "alloc_ep: unable to allocate iscsi cid\n");
+               rc = -ENOMEM;
+               goto iscsi_cid_err;
+       }
+       bnx2i_ep->hba_age = hba->age;
+
+       rc = bnx2i_alloc_qp_resc(hba, bnx2i_ep);
+       if (rc != 0) {
+               printk(KERN_ALERT "bnx2i: ep_conn, alloc QP resc error\n");
+               rc = -ENOMEM;
+               goto qp_resc_err;
+       }
+
+       bnx2i_ep->ep_iscsi_cid = (u16)iscsi_cid;
+       bnx2i_ep->state = EP_STATE_OFLD_START;
+       bnx2i_ep_ofld_list_add(hba, bnx2i_ep);
+
+       init_timer(&bnx2i_ep->ofld_timer);
+       bnx2i_ep->ofld_timer.expires = 2 * HZ + jiffies;
+       bnx2i_ep->ofld_timer.function = bnx2i_ep_ofld_timer;
+       bnx2i_ep->ofld_timer.data = (unsigned long) bnx2i_ep;
+       add_timer(&bnx2i_ep->ofld_timer);
+
+       bnx2i_send_conn_ofld_req(hba, bnx2i_ep);
+
+       /* Wait for CNIC hardware to setup conn context and return 'cid' */
+       wait_event_interruptible(bnx2i_ep->ofld_wait,
+                                bnx2i_ep->state != EP_STATE_OFLD_START);
+
+       if (signal_pending(current))
+               flush_signals(current);
+       del_timer_sync(&bnx2i_ep->ofld_timer);
+
+       bnx2i_ep_ofld_list_del(hba, bnx2i_ep);
+
+       if (bnx2i_ep->state != EP_STATE_OFLD_COMPL) {
+               rc = -ENOSPC;
+               goto conn_failed;
+       }
+
+       rc = cnic->cm_create(cnic, CNIC_ULP_ISCSI, bnx2i_ep->ep_cid,
+                            iscsi_cid, &bnx2i_ep->cm_sk, bnx2i_ep);
+       if (rc) {
+               rc = -EINVAL;
+               goto conn_failed;
+       }
+
+       bnx2i_ep->cm_sk->rcv_buf = 256 * 1024;
+       bnx2i_ep->cm_sk->snd_buf = 256 * 1024;
+       clear_bit(SK_TCP_TIMESTAMP, &bnx2i_ep->cm_sk->tcp_flags);
+
+       memset(&saddr, 0, sizeof(saddr));
+       if (dst_addr->sa_family == AF_INET) {
+               desti = (struct sockaddr_in *) dst_addr;
+               saddr.remote.v4 = *desti;
+               saddr.local.v4.sin_family = desti->sin_family;
+       } else if (dst_addr->sa_family == AF_INET6) {
+               desti6 = (struct sockaddr_in6 *) dst_addr;
+               saddr.remote.v6 = *desti6;
+               saddr.local.v6.sin6_family = desti6->sin6_family;
+       }
+
+       bnx2i_ep->timestamp = jiffies;
+       bnx2i_ep->state = EP_STATE_CONNECT_START;
+       if (!test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
+               rc = -EINVAL;
+               goto conn_failed;
+       } else
+               rc = cnic->cm_connect(bnx2i_ep->cm_sk, &saddr);
+
+       if (rc)
+               goto release_ep;
+
+       if (bnx2i_map_ep_dbell_regs(bnx2i_ep))
+               goto release_ep;
+       mutex_unlock(&hba->net_dev_lock);
+       return ep;
+
+release_ep:
+       if (bnx2i_tear_down_conn(hba, bnx2i_ep)) {
+               mutex_unlock(&hba->net_dev_lock);
+               return ERR_PTR(rc);
+       }
+conn_failed:
+net_if_down:
+iscsi_cid_err:
+       bnx2i_free_qp_resc(hba, bnx2i_ep);
+qp_resc_err:
+       bnx2i_free_ep(ep);
+       mutex_unlock(&hba->net_dev_lock);
+check_busy:
+       bnx2i_unreg_dev_all();
+       return ERR_PTR(rc);
+}
+
+
+/**
+ * bnx2i_ep_poll - polls for TCP connection establishement
+ * @ep:                        TCP connection (endpoint) handle
+ * @timeout_ms:                timeout value in milli secs
+ *
+ * polls for TCP connect request to complete
+ */
+static int bnx2i_ep_poll(struct iscsi_endpoint *ep, int timeout_ms)
+{
+       struct bnx2i_endpoint *bnx2i_ep;
+       int rc = 0;
+
+       bnx2i_ep = ep->dd_data;
+       if ((bnx2i_ep->state == EP_STATE_IDLE) ||
+           (bnx2i_ep->state == EP_STATE_CONNECT_FAILED) ||
+           (bnx2i_ep->state == EP_STATE_OFLD_FAILED))
+               return -1;
+       if (bnx2i_ep->state == EP_STATE_CONNECT_COMPL)
+               return 1;
+
+       rc = wait_event_interruptible_timeout(bnx2i_ep->ofld_wait,
+                                             ((bnx2i_ep->state ==
+                                               EP_STATE_OFLD_FAILED) ||
+                                              (bnx2i_ep->state ==
+                                               EP_STATE_CONNECT_FAILED) ||
+                                              (bnx2i_ep->state ==
+                                               EP_STATE_CONNECT_COMPL)),
+                                             msecs_to_jiffies(timeout_ms));
+       if (!rc || (bnx2i_ep->state == EP_STATE_OFLD_FAILED))
+               rc = -1;
+
+       if (rc > 0)
+               return 1;
+       else if (!rc)
+               return 0;       /* timeout */
+       else
+               return rc;
+}
+
+
+/**
+ * bnx2i_ep_tcp_conn_active - check EP state transition
+ * @ep:                endpoint pointer
+ *
+ * check if underlying TCP connection is active
+ */
+static int bnx2i_ep_tcp_conn_active(struct bnx2i_endpoint *bnx2i_ep)
+{
+       int ret;
+       int cnic_dev_10g = 0;
+
+       if (test_bit(BNX2I_NX2_DEV_57710, &bnx2i_ep->hba->cnic_dev_type))
+               cnic_dev_10g = 1;
+
+       switch (bnx2i_ep->state) {
+       case EP_STATE_CONNECT_START:
+       case EP_STATE_CLEANUP_FAILED:
+       case EP_STATE_OFLD_FAILED:
+       case EP_STATE_DISCONN_TIMEDOUT:
+               ret = 0;
+               break;
+       case EP_STATE_CONNECT_COMPL:
+       case EP_STATE_ULP_UPDATE_START:
+       case EP_STATE_ULP_UPDATE_COMPL:
+       case EP_STATE_TCP_FIN_RCVD:
+       case EP_STATE_ULP_UPDATE_FAILED:
+               ret = 1;
+               break;
+       case EP_STATE_TCP_RST_RCVD:
+               ret = 0;
+               break;
+       case EP_STATE_CONNECT_FAILED:
+               if (cnic_dev_10g)
+                       ret = 1;
+               else
+                       ret = 0;
+               break;
+       default:
+               ret = 0;
+       }
+
+       return ret;
+}
+
+
+/**
+ * bnx2i_ep_disconnect - executes TCP connection teardown process
+ * @ep:                TCP connection (endpoint) handle
+ *
+ * executes  TCP connection teardown process
+ */
+static void bnx2i_ep_disconnect(struct iscsi_endpoint *ep)
+{
+       struct bnx2i_endpoint *bnx2i_ep;
+       struct bnx2i_conn *bnx2i_conn = NULL;
+       struct iscsi_session *session = NULL;
+       struct iscsi_conn *conn;
+       struct cnic_dev *cnic;
+       struct bnx2i_hba *hba;
+
+       bnx2i_ep = ep->dd_data;
+
+       /* driver should not attempt connection cleanup untill TCP_CONNECT
+        * completes either successfully or fails. Timeout is 9-secs, so
+        * wait for it to complete
+        */
+       while ((bnx2i_ep->state == EP_STATE_CONNECT_START) &&
+               !time_after(jiffies, bnx2i_ep->timestamp + (12 * HZ)))
+               msleep(250);
+
+       if (bnx2i_ep->conn) {
+               bnx2i_conn = bnx2i_ep->conn;
+               conn = bnx2i_conn->cls_conn->dd_data;
+               session = conn->session;
+
+               spin_lock_bh(&session->lock);
+               bnx2i_conn->is_bound = 0;
+               spin_unlock_bh(&session->lock);
+       }
+
+       hba = bnx2i_ep->hba;
+       if (bnx2i_ep->state == EP_STATE_IDLE)
+               goto return_bnx2i_ep;
+       cnic = hba->cnic;
+
+       mutex_lock(&hba->net_dev_lock);
+
+       if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state))
+               goto free_resc;
+       if (bnx2i_ep->hba_age != hba->age)
+               goto free_resc;
+
+       if (!bnx2i_ep_tcp_conn_active(bnx2i_ep))
+               goto destory_conn;
+
+       bnx2i_ep->state = EP_STATE_DISCONN_START;
+
+       init_timer(&bnx2i_ep->ofld_timer);
+       bnx2i_ep->ofld_timer.expires = 10*HZ + jiffies;
+       bnx2i_ep->ofld_timer.function = bnx2i_ep_ofld_timer;
+       bnx2i_ep->ofld_timer.data = (unsigned long) bnx2i_ep;
+       add_timer(&bnx2i_ep->ofld_timer);
+
+       if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
+               int close = 0;
+
+               if (session) {
+                       spin_lock_bh(&session->lock);
+                       if (session->state == ISCSI_STATE_LOGGING_OUT)
+                               close = 1;
+                       spin_unlock_bh(&session->lock);
+               }
+               if (close)
+                       cnic->cm_close(bnx2i_ep->cm_sk);
+               else
+                       cnic->cm_abort(bnx2i_ep->cm_sk);
+       } else
+               goto free_resc;
+
+       /* wait for option-2 conn teardown */
+       wait_event_interruptible(bnx2i_ep->ofld_wait,
+                                bnx2i_ep->state != EP_STATE_DISCONN_START);
+
+       if (signal_pending(current))
+               flush_signals(current);
+       del_timer_sync(&bnx2i_ep->ofld_timer);
+
+destory_conn:
+       if (bnx2i_tear_down_conn(hba, bnx2i_ep)) {
+               mutex_unlock(&hba->net_dev_lock);
+               return;
+       }
+free_resc:
+       mutex_unlock(&hba->net_dev_lock);
+       bnx2i_free_qp_resc(hba, bnx2i_ep);
+return_bnx2i_ep:
+       if (bnx2i_conn)
+               bnx2i_conn->ep = NULL;
+
+       bnx2i_free_ep(ep);
+
+       if (!hba->ofld_conns_active)
+               bnx2i_unreg_dev_all();
+}
+
+
+/**
+ * bnx2i_nl_set_path - ISCSI_UEVENT_PATH_UPDATE user message handler
+ * @buf:       pointer to buffer containing iscsi path message
+ *
+ */
+static int bnx2i_nl_set_path(struct Scsi_Host *shost, struct iscsi_path *params)
+{
+       struct bnx2i_hba *hba = iscsi_host_priv(shost);
+       char *buf = (char *) params;
+       u16 len = sizeof(*params);
+
+       /* handled by cnic driver */
+       hba->cnic->iscsi_nl_msg_recv(hba->cnic, ISCSI_UEVENT_PATH_UPDATE, buf,
+                                    len);
+
+       return 0;
+}
+
+
+/*
+ * 'Scsi_Host_Template' structure and 'iscsi_tranport' structure template
+ * used while registering with the scsi host and iSCSI transport module.
+ */
+static struct scsi_host_template bnx2i_host_template = {
+       .module                 = THIS_MODULE,
+       .name                   = "Broadcom Offload iSCSI Initiator",
+       .proc_name              = "bnx2i",
+       .queuecommand           = iscsi_queuecommand,
+       .eh_abort_handler       = iscsi_eh_abort,
+       .eh_device_reset_handler = iscsi_eh_device_reset,
+       .eh_target_reset_handler = iscsi_eh_target_reset,
+       .can_queue              = 1024,
+       .max_sectors            = 127,
+       .cmd_per_lun            = 32,
+       .this_id                = -1,
+       .use_clustering         = ENABLE_CLUSTERING,
+       .sg_tablesize           = ISCSI_MAX_BDS_PER_CMD,
+       .shost_attrs            = bnx2i_dev_attributes,
+};
+
+struct iscsi_transport bnx2i_iscsi_transport = {
+       .owner                  = THIS_MODULE,
+       .name                   = "bnx2i",
+       .caps                   = CAP_RECOVERY_L0 | CAP_HDRDGST |
+                                 CAP_MULTI_R2T | CAP_DATADGST |
+                                 CAP_DATA_PATH_OFFLOAD,
+       .param_mask             = ISCSI_MAX_RECV_DLENGTH |
+                                 ISCSI_MAX_XMIT_DLENGTH |
+                                 ISCSI_HDRDGST_EN |
+                                 ISCSI_DATADGST_EN |
+                                 ISCSI_INITIAL_R2T_EN |
+                                 ISCSI_MAX_R2T |
+                                 ISCSI_IMM_DATA_EN |
+                                 ISCSI_FIRST_BURST |
+                                 ISCSI_MAX_BURST |
+                                 ISCSI_PDU_INORDER_EN |
+                                 ISCSI_DATASEQ_INORDER_EN |
+                                 ISCSI_ERL |
+                                 ISCSI_CONN_PORT |
+                                 ISCSI_CONN_ADDRESS |
+                                 ISCSI_EXP_STATSN |
+                                 ISCSI_PERSISTENT_PORT |
+                                 ISCSI_PERSISTENT_ADDRESS |
+                                 ISCSI_TARGET_NAME | ISCSI_TPGT |
+                                 ISCSI_USERNAME | ISCSI_PASSWORD |
+                                 ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
+                                 ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
+                                 ISCSI_LU_RESET_TMO |
+                                 ISCSI_PING_TMO | ISCSI_RECV_TMO |
+                                 ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME,
+       .host_param_mask        = ISCSI_HOST_HWADDRESS | ISCSI_HOST_NETDEV_NAME,
+       .create_session         = bnx2i_session_create,
+       .destroy_session        = bnx2i_session_destroy,
+       .create_conn            = bnx2i_conn_create,
+       .bind_conn              = bnx2i_conn_bind,
+       .destroy_conn           = bnx2i_conn_destroy,
+       .set_param              = iscsi_set_param,
+       .get_conn_param         = bnx2i_conn_get_param,
+       .get_session_param      = iscsi_session_get_param,
+       .get_host_param         = bnx2i_host_get_param,
+       .start_conn             = bnx2i_conn_start,
+       .stop_conn              = iscsi_conn_stop,
+       .send_pdu               = iscsi_conn_send_pdu,
+       .xmit_task              = bnx2i_task_xmit,
+       .get_stats              = bnx2i_conn_get_stats,
+       /* TCP connect - disconnect - option-2 interface calls */
+       .ep_connect             = bnx2i_ep_connect,
+       .ep_poll                = bnx2i_ep_poll,
+       .ep_disconnect          = bnx2i_ep_disconnect,
+       .set_path               = bnx2i_nl_set_path,
+       /* Error recovery timeout call */
+       .session_recovery_timedout = iscsi_session_recovery_timedout,
+       .cleanup_task           = bnx2i_cleanup_task,
+};
diff --git a/drivers/scsi/bnx2i/bnx2i_sysfs.c b/drivers/scsi/bnx2i/bnx2i_sysfs.c
new file mode 100644 (file)
index 0000000..96426b7
--- /dev/null
@@ -0,0 +1,142 @@
+/* bnx2i_sysfs.c: Broadcom NetXtreme II iSCSI driver.
+ *
+ * Copyright (c) 2004 - 2009 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ */
+
+#include "bnx2i.h"
+
+/**
+ * bnx2i_dev_to_hba - maps dev pointer to adapter struct
+ * @dev:       device pointer
+ *
+ * Map device to hba structure
+ */
+static inline struct bnx2i_hba *bnx2i_dev_to_hba(struct device *dev)
+{
+       struct Scsi_Host *shost = class_to_shost(dev);
+       return iscsi_host_priv(shost);
+}
+
+
+/**
+ * bnx2i_show_sq_info - return(s currently configured send queue (SQ) size
+ * @dev:       device pointer
+ * @buf:       buffer to return current SQ size parameter
+ *
+ * Returns current SQ size parameter, this paramater determines the number
+ * outstanding iSCSI commands supported on a connection
+ */
+static ssize_t bnx2i_show_sq_info(struct device *dev,
+                                 struct device_attribute *attr, char *buf)
+{
+       struct bnx2i_hba *hba = bnx2i_dev_to_hba(dev);
+
+       return sprintf(buf, "0x%x\n", hba->max_sqes);
+}
+
+
+/**
+ * bnx2i_set_sq_info - update send queue (SQ) size parameter
+ * @dev:       device pointer
+ * @buf:       buffer to return current SQ size parameter
+ * @count:     parameter buffer size
+ *
+ * Interface for user to change shared queue size allocated for each conn
+ * Must be within SQ limits and a power of 2. For the latter this is needed
+ * because of how libiscsi preallocates tasks.
+ */
+static ssize_t bnx2i_set_sq_info(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t count)
+{
+       struct bnx2i_hba *hba = bnx2i_dev_to_hba(dev);
+       u32 val;
+       int max_sq_size;
+
+       if (hba->ofld_conns_active)
+               goto skip_config;
+
+       if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type))
+               max_sq_size = BNX2I_5770X_SQ_WQES_MAX;
+       else
+               max_sq_size = BNX2I_570X_SQ_WQES_MAX;
+
+       if (sscanf(buf, " 0x%x ", &val) > 0) {
+               if ((val >= BNX2I_SQ_WQES_MIN) && (val <= max_sq_size) &&
+                   (is_power_of_2(val)))
+                       hba->max_sqes = val;
+       }
+
+       return count;
+
+skip_config:
+       printk(KERN_ERR "bnx2i: device busy, cannot change SQ size\n");
+       return 0;
+}
+
+
+/**
+ * bnx2i_show_ccell_info - returns command cell (HQ) size
+ * @dev:       device pointer
+ * @buf:       buffer to return current SQ size parameter
+ *
+ * returns per-connection TCP history queue size parameter
+ */
+static ssize_t bnx2i_show_ccell_info(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       struct bnx2i_hba *hba = bnx2i_dev_to_hba(dev);
+
+       return sprintf(buf, "0x%x\n", hba->num_ccell);
+}
+
+
+/**
+ * bnx2i_get_link_state - set command cell (HQ) size
+ * @dev:       device pointer
+ * @buf:       buffer to return current SQ size parameter
+ * @count:     parameter buffer size
+ *
+ * updates per-connection TCP history queue size parameter
+ */
+static ssize_t bnx2i_set_ccell_info(struct device *dev,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t count)
+{
+       u32 val;
+       struct bnx2i_hba *hba = bnx2i_dev_to_hba(dev);
+
+       if (hba->ofld_conns_active)
+               goto skip_config;
+
+       if (sscanf(buf, " 0x%x ", &val) > 0) {
+               if ((val >= BNX2I_CCELLS_MIN) &&
+                   (val <= BNX2I_CCELLS_MAX)) {
+                       hba->num_ccell = val;
+               }
+       }
+
+       return count;
+
+skip_config:
+       printk(KERN_ERR "bnx2i: device busy, cannot change CCELL size\n");
+       return 0;
+}
+
+
+static DEVICE_ATTR(sq_size, S_IRUGO | S_IWUSR,
+                  bnx2i_show_sq_info, bnx2i_set_sq_info);
+static DEVICE_ATTR(num_ccell, S_IRUGO | S_IWUSR,
+                  bnx2i_show_ccell_info, bnx2i_set_ccell_info);
+
+struct device_attribute *bnx2i_dev_attributes[] = {
+       &dev_attr_sq_size,
+       &dev_attr_num_ccell,
+       NULL
+};
index 59b0958d2d116d0a85b2bbd4c045535a8028fdb5..e3133b58e5944d5c2c36a2bda0d2ed6a161076a5 100644 (file)
@@ -144,7 +144,6 @@ struct cxgb3i_adapter *cxgb3i_adapter_find_by_tdev(struct t3cdev *);
 void cxgb3i_adapter_open(struct t3cdev *);
 void cxgb3i_adapter_close(struct t3cdev *);
 
-struct cxgb3i_hba *cxgb3i_hba_find_by_netdev(struct net_device *);
 struct cxgb3i_hba *cxgb3i_hba_host_add(struct cxgb3i_adapter *,
                                       struct net_device *);
 void cxgb3i_hba_host_remove(struct cxgb3i_hba *);
index 9212400b9b13ecde501a5fe75831855d742fe86e..74369a3f963b66bdbdbaa0b71bdd6f848a074048 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/inet.h>
 #include <linux/crypto.h>
+#include <net/dst.h>
 #include <net/tcp.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
@@ -178,7 +179,7 @@ void cxgb3i_adapter_close(struct t3cdev *t3dev)
  * cxgb3i_hba_find_by_netdev - find the cxgb3i_hba structure via net_device
  * @t3dev: t3cdev adapter
  */
-struct cxgb3i_hba *cxgb3i_hba_find_by_netdev(struct net_device *ndev)
+static struct cxgb3i_hba *cxgb3i_hba_find_by_netdev(struct net_device *ndev)
 {
        struct cxgb3i_adapter *snic;
        int i;
@@ -261,20 +262,27 @@ void cxgb3i_hba_host_remove(struct cxgb3i_hba *hba)
 
 /**
  * cxgb3i_ep_connect - establish TCP connection to target portal
+ * @shost:             scsi host to use
  * @dst_addr:          target IP address
  * @non_blocking:      blocking or non-blocking call
  *
  * Initiates a TCP/IP connection to the dst_addr
  */
-static struct iscsi_endpoint *cxgb3i_ep_connect(struct sockaddr *dst_addr,
+static struct iscsi_endpoint *cxgb3i_ep_connect(struct Scsi_Host *shost,
+                                               struct sockaddr *dst_addr,
                                                int non_blocking)
 {
        struct iscsi_endpoint *ep;
        struct cxgb3i_endpoint *cep;
-       struct cxgb3i_hba *hba;
+       struct cxgb3i_hba *hba = NULL;
        struct s3_conn *c3cn = NULL;
        int err = 0;
 
+       if (shost)
+               hba = iscsi_host_priv(shost);
+
+       cxgb3i_api_debug("shost 0x%p, hba 0x%p.\n", shost, hba);
+
        c3cn = cxgb3i_c3cn_create();
        if (!c3cn) {
                cxgb3i_log_info("ep connect OOM.\n");
@@ -282,17 +290,27 @@ static struct iscsi_endpoint *cxgb3i_ep_connect(struct sockaddr *dst_addr,
                goto release_conn;
        }
 
-       err = cxgb3i_c3cn_connect(c3cn, (struct sockaddr_in *)dst_addr);
+       err = cxgb3i_c3cn_connect(hba ? hba->ndev : NULL, c3cn,
+                                (struct sockaddr_in *)dst_addr);
        if (err < 0) {
                cxgb3i_log_info("ep connect failed.\n");
                goto release_conn;
        }
+
        hba = cxgb3i_hba_find_by_netdev(c3cn->dst_cache->dev);
        if (!hba) {
                err = -ENOSPC;
                cxgb3i_log_info("NOT going through cxgbi device.\n");
                goto release_conn;
        }
+
+       if (shost && hba != iscsi_host_priv(shost)) {
+               err = -ENOSPC;
+               cxgb3i_log_info("Could not connect through request host%u\n",
+                               shost->host_no);
+               goto release_conn;
+       }
+
        if (c3cn_is_closing(c3cn)) {
                err = -ENOSPC;
                cxgb3i_log_info("ep connect unable to connect.\n");
index e11c9c180f39d322127f37b9aae88a5409b04863..c1d5be4adf9c6cdfe7fa530c93821f22f091ba97 100644 (file)
@@ -1479,12 +1479,13 @@ static struct net_device *cxgb3_egress_dev(struct net_device *root_dev,
        return NULL;
 }
 
-static struct rtable *find_route(__be32 saddr, __be32 daddr,
+static struct rtable *find_route(struct net_device *dev,
+                                __be32 saddr, __be32 daddr,
                                 __be16 sport, __be16 dport)
 {
        struct rtable *rt;
        struct flowi fl = {
-               .oif = 0,
+               .oif = dev ? dev->ifindex : 0,
                .nl_u = {
                         .ip4_u = {
                                   .daddr = daddr,
@@ -1573,36 +1574,40 @@ out_err:
  *
  * return 0 if active open request is sent, < 0 otherwise.
  */
-int cxgb3i_c3cn_connect(struct s3_conn *c3cn, struct sockaddr_in *usin)
+int cxgb3i_c3cn_connect(struct net_device *dev, struct s3_conn *c3cn,
+                       struct sockaddr_in *usin)
 {
        struct rtable *rt;
-       struct net_device *dev;
        struct cxgb3i_sdev_data *cdata;
        struct t3cdev *cdev;
        __be32 sipv4;
        int err;
 
+       c3cn_conn_debug("c3cn 0x%p, dev 0x%p.\n", c3cn, dev);
+
        if (usin->sin_family != AF_INET)
                return -EAFNOSUPPORT;
 
        c3cn->daddr.sin_port = usin->sin_port;
        c3cn->daddr.sin_addr.s_addr = usin->sin_addr.s_addr;
 
-       rt = find_route(c3cn->saddr.sin_addr.s_addr,
+       rt = find_route(dev, c3cn->saddr.sin_addr.s_addr,
                        c3cn->daddr.sin_addr.s_addr,
                        c3cn->saddr.sin_port,
                        c3cn->daddr.sin_port);
        if (rt == NULL) {
-               c3cn_conn_debug("NO route to 0x%x, port %u.\n",
+               c3cn_conn_debug("NO route to 0x%x, port %u, dev %s.\n",
                                c3cn->daddr.sin_addr.s_addr,
-                               ntohs(c3cn->daddr.sin_port));
+                               ntohs(c3cn->daddr.sin_port),
+                               dev ? dev->name : "any");
                return -ENETUNREACH;
        }
 
        if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) {
-               c3cn_conn_debug("multi-cast route to 0x%x, port %u.\n",
+               c3cn_conn_debug("multi-cast route to 0x%x, port %u, dev %s.\n",
                                c3cn->daddr.sin_addr.s_addr,
-                               ntohs(c3cn->daddr.sin_port));
+                               ntohs(c3cn->daddr.sin_port),
+                               dev ? dev->name : "any");
                ip_rt_put(rt);
                return -ENETUNREACH;
        }
index ebfca960c0a9d8358236c8658c084e44bda4ed3d..6a1d86b1fafea325c9bcbc415419732273b8568c 100644 (file)
@@ -169,7 +169,8 @@ void cxgb3i_sdev_add(struct t3cdev *, struct cxgb3_client *);
 void cxgb3i_sdev_remove(struct t3cdev *);
 
 struct s3_conn *cxgb3i_c3cn_create(void);
-int cxgb3i_c3cn_connect(struct s3_conn *, struct sockaddr_in *);
+int cxgb3i_c3cn_connect(struct net_device *, struct s3_conn *,
+                       struct sockaddr_in *);
 void cxgb3i_c3cn_rx_credits(struct s3_conn *, int);
 int cxgb3i_c3cn_send_pdus(struct s3_conn *, struct sk_buff *);
 void cxgb3i_c3cn_release(struct s3_conn *);
index 43b8c51e98d090d5cdf1f333fc449730e6002d1e..fd0544f7da81700d2e586387b0f20ae1b0cd64d2 100644 (file)
@@ -561,6 +561,12 @@ static int rdac_check_sense(struct scsi_device *sdev,
        struct rdac_dh_data *h = get_rdac_data(sdev);
        switch (sense_hdr->sense_key) {
        case NOT_READY:
+               if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x01)
+                       /* LUN Not Ready - Logical Unit Not Ready and is in
+                       * the process of becoming ready
+                       * Just retry.
+                       */
+                       return ADD_TO_MLQUEUE;
                if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x81)
                        /* LUN Not Ready - Storage firmware incompatible
                         * Manual code synchonisation required.
index 4b56c0436ba2727970fd245289ce271174f54425..b2613c2eaac7df353d671f4f2961ac738d948808 100644 (file)
@@ -342,7 +342,7 @@ uLONG osdGetThreadID(void);
 /* wakes up the specifed thread */
 void osdWakeThread(uLONG);
 
-/* osd sleep for x miliseconds */
+/* osd sleep for x milliseconds */
 void osdSleep(uLONG);
 
 #define DPT_THREAD_PRIORITY_LOWEST 0x00
index 03e1926f40b523c231033e809031ad9b1d138ec7..e606b4829d4430684a973c743d721bf81ba66d1f 100644 (file)
@@ -54,7 +54,6 @@ MODULE_LICENSE("GPL v2");
 /* fcoe host list */
 LIST_HEAD(fcoe_hostlist);
 DEFINE_RWLOCK(fcoe_hostlist_lock);
-DEFINE_TIMER(fcoe_timer, NULL, 0, 0);
 DEFINE_PER_CPU(struct fcoe_percpu_s, fcoe_percpu);
 
 /* Function Prototypes */
@@ -71,7 +70,7 @@ static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *);
 static int fcoe_hostlist_add(const struct fc_lport *);
 static int fcoe_hostlist_remove(const struct fc_lport *);
 
-static int fcoe_check_wait_queue(struct fc_lport *);
+static void fcoe_check_wait_queue(struct fc_lport *, struct sk_buff *);
 static int fcoe_device_notification(struct notifier_block *, ulong, void *);
 static void fcoe_dev_setup(void);
 static void fcoe_dev_cleanup(void);
@@ -146,6 +145,7 @@ static int fcoe_lport_config(struct fc_lport *lp)
        lp->link_up = 0;
        lp->qfull = 0;
        lp->max_retry_count = 3;
+       lp->max_rport_retry_count = 3;
        lp->e_d_tov = 2 * 1000; /* FC-FS default */
        lp->r_a_tov = 2 * 2 * 1000;
        lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS |
@@ -166,6 +166,18 @@ static int fcoe_lport_config(struct fc_lport *lp)
        return 0;
 }
 
+/**
+ * fcoe_queue_timer() - fcoe queue timer
+ * @lp: the fc_lport pointer
+ *
+ * Calls fcoe_check_wait_queue on timeout
+ *
+ */
+static void fcoe_queue_timer(ulong lp)
+{
+       fcoe_check_wait_queue((struct fc_lport *)lp, NULL);
+}
+
 /**
  * fcoe_netdev_config() - Set up netdev for SW FCoE
  * @lp : ptr to the fc_lport
@@ -236,6 +248,7 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)
        }
        skb_queue_head_init(&fc->fcoe_pending_queue);
        fc->fcoe_pending_queue_active = 0;
+       setup_timer(&fc->timer, fcoe_queue_timer, (unsigned long)lp);
 
        /* setup Source Mac Address */
        memcpy(fc->ctlr.ctl_src_addr, fc->real_dev->dev_addr,
@@ -386,6 +399,9 @@ static int fcoe_if_destroy(struct net_device *netdev)
        /* Free existing skbs */
        fcoe_clean_pending_queue(lp);
 
+       /* Stop the timer */
+       del_timer_sync(&fc->timer);
+
        /* Free memory used by statistical counters */
        fc_lport_free_stats(lp);
 
@@ -988,7 +1004,7 @@ u32 fcoe_fc_crc(struct fc_frame *fp)
  */
 int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)
 {
-       int wlen, rc = 0;
+       int wlen;
        u32 crc;
        struct ethhdr *eh;
        struct fcoe_crc_eof *cp;
@@ -1021,8 +1037,7 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)
        sof = fr_sof(fp);
        eof = fr_eof(fp);
 
-       elen = (fc->real_dev->priv_flags & IFF_802_1Q_VLAN) ?
-               sizeof(struct vlan_ethhdr) : sizeof(struct ethhdr);
+       elen = sizeof(struct ethhdr);
        hlen = sizeof(struct fcoe_hdr);
        tlen = sizeof(struct fcoe_crc_eof);
        wlen = (skb->len - tlen + sizeof(crc)) / FCOE_WORD_TO_BYTE;
@@ -1107,18 +1122,9 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)
        /* send down to lld */
        fr_dev(fp) = lp;
        if (fc->fcoe_pending_queue.qlen)
-               rc = fcoe_check_wait_queue(lp);
-
-       if (rc == 0)
-               rc = fcoe_start_io(skb);
-
-       if (rc) {
-               spin_lock_bh(&fc->fcoe_pending_queue.lock);
-               __skb_queue_tail(&fc->fcoe_pending_queue, skb);
-               spin_unlock_bh(&fc->fcoe_pending_queue.lock);
-               if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH)
-                       lp->qfull = 1;
-       }
+               fcoe_check_wait_queue(lp, skb);
+       else if (fcoe_start_io(skb))
+               fcoe_check_wait_queue(lp, skb);
 
        return 0;
 }
@@ -1267,32 +1273,6 @@ int fcoe_percpu_receive_thread(void *arg)
        return 0;
 }
 
-/**
- * fcoe_watchdog() - fcoe timer callback
- * @vp:
- *
- * This checks the pending queue length for fcoe and set lport qfull
- * if the FCOE_MAX_QUEUE_DEPTH is reached. This is done for all fc_lport on the
- * fcoe_hostlist.
- *
- * Returns: 0 for success
- */
-void fcoe_watchdog(ulong vp)
-{
-       struct fcoe_softc *fc;
-
-       read_lock(&fcoe_hostlist_lock);
-       list_for_each_entry(fc, &fcoe_hostlist, list) {
-               if (fc->ctlr.lp)
-                       fcoe_check_wait_queue(fc->ctlr.lp);
-       }
-       read_unlock(&fcoe_hostlist_lock);
-
-       fcoe_timer.expires = jiffies + (1 * HZ);
-       add_timer(&fcoe_timer);
-}
-
-
 /**
  * fcoe_check_wait_queue() - attempt to clear the transmit backlog
  * @lp: the fc_lport
@@ -1305,16 +1285,17 @@ void fcoe_watchdog(ulong vp)
  * The wait_queue is used when the skb transmit fails. skb will go
  * in the wait_queue which will be emptied by the timer function or
  * by the next skb transmit.
- *
- * Returns: 0 for success
  */
-static int fcoe_check_wait_queue(struct fc_lport *lp)
+static void fcoe_check_wait_queue(struct fc_lport *lp, struct sk_buff *skb)
 {
        struct fcoe_softc *fc = lport_priv(lp);
-       struct sk_buff *skb;
-       int rc = -1;
+       int rc;
 
        spin_lock_bh(&fc->fcoe_pending_queue.lock);
+
+       if (skb)
+               __skb_queue_tail(&fc->fcoe_pending_queue, skb);
+
        if (fc->fcoe_pending_queue_active)
                goto out;
        fc->fcoe_pending_queue_active = 1;
@@ -1340,23 +1321,26 @@ static int fcoe_check_wait_queue(struct fc_lport *lp)
 
        if (fc->fcoe_pending_queue.qlen < FCOE_LOW_QUEUE_DEPTH)
                lp->qfull = 0;
+       if (fc->fcoe_pending_queue.qlen && !timer_pending(&fc->timer))
+               mod_timer(&fc->timer, jiffies + 2);
        fc->fcoe_pending_queue_active = 0;
-       rc = fc->fcoe_pending_queue.qlen;
 out:
+       if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH)
+               lp->qfull = 1;
        spin_unlock_bh(&fc->fcoe_pending_queue.lock);
-       return rc;
+       return;
 }
 
 /**
  * fcoe_dev_setup() - setup link change notification interface
  */
-static void fcoe_dev_setup()
+static void fcoe_dev_setup(void)
 {
        register_netdevice_notifier(&fcoe_notifier);
 }
 
 /**
- * fcoe_dev_setup() - cleanup link change notification interface
+ * fcoe_dev_cleanup() - cleanup link change notification interface
  */
 static void fcoe_dev_cleanup(void)
 {
@@ -1815,10 +1799,6 @@ static int __init fcoe_init(void)
        /* Setup link change notification */
        fcoe_dev_setup();
 
-       setup_timer(&fcoe_timer, fcoe_watchdog, 0);
-
-       mod_timer(&fcoe_timer, jiffies + (10 * HZ));
-
        fcoe_if_init();
 
        return 0;
@@ -1844,9 +1824,6 @@ static void __exit fcoe_exit(void)
 
        fcoe_dev_cleanup();
 
-       /* Stop the timer */
-       del_timer_sync(&fcoe_timer);
-
        /* releases the associated fcoe hosts */
        list_for_each_entry_safe(fc, tmp, &fcoe_hostlist, list)
                fcoe_if_destroy(fc->real_dev);
index 917aae88689733feb40d49963928d5d6bf6863f9..a1eb8c1988b07584bed2a10280a6efbf768f8813 100644 (file)
@@ -61,6 +61,7 @@ struct fcoe_softc {
        struct packet_type  fip_packet_type;
        struct sk_buff_head fcoe_pending_queue;
        u8      fcoe_pending_queue_active;
+       struct timer_list timer;                /* queue timer */
        struct fcoe_ctlr ctlr;
 };
 
index 62ba0f39c6bd267f2e7a5fc30354792434569b29..929411880e4b16c010ca7ca3d7369fddec6abd88 100644 (file)
@@ -213,7 +213,7 @@ static void fcoe_ctlr_solicit(struct fcoe_ctlr *fip, struct fcoe_fcf *fcf)
        sol->desc.size.fd_size = htons(fcoe_size);
 
        skb_put(skb, sizeof(*sol));
-       skb->protocol = htons(ETH_P_802_3);
+       skb->protocol = htons(ETH_P_FIP);
        skb_reset_mac_header(skb);
        skb_reset_network_header(skb);
        fip->send(fip, skb);
@@ -365,7 +365,7 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, int ports, u8 *sa)
        }
 
        skb_put(skb, len);
-       skb->protocol = htons(ETH_P_802_3);
+       skb->protocol = htons(ETH_P_FIP);
        skb_reset_mac_header(skb);
        skb_reset_network_header(skb);
        fip->send(fip, skb);
@@ -424,7 +424,7 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip,
        if (dtype != ELS_FLOGI)
                memcpy(mac->fd_mac, fip->data_src_addr, ETH_ALEN);
 
-       skb->protocol = htons(ETH_P_802_3);
+       skb->protocol = htons(ETH_P_FIP);
        skb_reset_mac_header(skb);
        skb_reset_network_header(skb);
        return 0;
@@ -447,14 +447,10 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
        u16 old_xid;
        u8 op;
 
-       if (fip->state == FIP_ST_NON_FIP)
-               return 0;
-
        fh = (struct fc_frame_header *)skb->data;
        op = *(u8 *)(fh + 1);
 
-       switch (op) {
-       case ELS_FLOGI:
+       if (op == ELS_FLOGI) {
                old_xid = fip->flogi_oxid;
                fip->flogi_oxid = ntohs(fh->fh_ox_id);
                if (fip->state == FIP_ST_AUTO) {
@@ -466,6 +462,15 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
                        fip->map_dest = 1;
                        return 0;
                }
+               if (fip->state == FIP_ST_NON_FIP)
+                       fip->map_dest = 1;
+       }
+
+       if (fip->state == FIP_ST_NON_FIP)
+               return 0;
+
+       switch (op) {
+       case ELS_FLOGI:
                op = FIP_DT_FLOGI;
                break;
        case ELS_FDISC:
index 32ef6b87d8953142aa8bdd24092f7f2d77540c00..a84072865fc2615a7a9fcce47c48b94fe05f4592 100644 (file)
@@ -680,6 +680,7 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
        }
 
        lp->max_retry_count = fnic->config.flogi_retries;
+       lp->max_rport_retry_count = fnic->config.plogi_retries;
        lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS |
                              FCP_SPPF_CONF_COMPL);
        if (fnic->config.flags & VFCF_FCP_SEQ_LVL_ERR)
index 59349a316e137facdd9b7f76b412ac14f23190ae..1258da34fbc251bf779f85d1a2fdd0a015e51a34 100644 (file)
@@ -152,6 +152,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
                          struct Scsi_Host *host, gdth_ha_str *ha)
 {
     int size = 0,len = 0;
+    int hlen;
     off_t begin = 0,pos = 0;
     int id, i, j, k, sec, flag;
     int no_mdrv = 0, drv_no, is_mirr;
@@ -192,11 +193,11 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
     if (reserve_list[0] == 0xff)
         strcpy(hrec, "--");
     else {
-        sprintf(hrec, "%d", reserve_list[0]);
+        hlen = sprintf(hrec, "%d", reserve_list[0]);
         for (i = 1;  i < MAX_RES_ARGS; i++) {
             if (reserve_list[i] == 0xff) 
                 break;
-            sprintf(hrec,"%s,%d", hrec, reserve_list[i]);
+            hlen += snprintf(hrec + hlen , 161 - hlen, ",%d", reserve_list[i]);
         }
     }
     size = sprintf(buffer+len,
index ea4abee7a2a95e8d783da6b7f82da2bc7f39aab8..b4b805e8d7db7aaad258c75f9d8fd30088ff228c 100644 (file)
@@ -110,7 +110,7 @@ static const struct {
        { IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_DEAD, DID_ERROR, 0, 1, "transport dead" },
        { IBMVFC_FABRIC_MAPPED, IBMVFC_CONFIG_ERROR, DID_ERROR, 1, 1, "configuration error" },
        { IBMVFC_FABRIC_MAPPED, IBMVFC_NAME_SERVER_FAIL, DID_ERROR, 1, 1, "name server failure" },
-       { IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_HALTED, DID_REQUEUE, 0, 0, "link halted" },
+       { IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_HALTED, DID_REQUEUE, 1, 0, "link halted" },
        { IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_GENERAL, DID_OK, 1, 0, "general transport error" },
 
        { IBMVFC_VIOS_FAILURE, IBMVFC_CRQ_FAILURE, DID_REQUEUE, 1, 1, "CRQ failure" },
@@ -143,6 +143,7 @@ static void ibmvfc_npiv_login(struct ibmvfc_host *);
 static void ibmvfc_tgt_send_prli(struct ibmvfc_target *);
 static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *);
 static void ibmvfc_tgt_query_target(struct ibmvfc_target *);
+static void ibmvfc_npiv_logout(struct ibmvfc_host *);
 
 static const char *unknown_error = "unknown error";
 
@@ -275,7 +276,7 @@ static int ibmvfc_get_err_result(struct ibmvfc_cmd *vfc_cmd)
        int fc_rsp_len = rsp->fcp_rsp_len;
 
        if ((rsp->flags & FCP_RSP_LEN_VALID) &&
-           ((!fc_rsp_len && fc_rsp_len != 4 && fc_rsp_len != 8) ||
+           ((fc_rsp_len && fc_rsp_len != 4 && fc_rsp_len != 8) ||
             rsp->data.info.rsp_code))
                return DID_ERROR << 16;
 
@@ -431,6 +432,8 @@ static void ibmvfc_set_tgt_action(struct ibmvfc_target *tgt,
        case IBMVFC_TGT_ACTION_DEL_RPORT:
                break;
        default:
+               if (action == IBMVFC_TGT_ACTION_DEL_RPORT)
+                       tgt->add_rport = 0;
                tgt->action = action;
                break;
        }
@@ -475,6 +478,10 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost,
                if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT)
                        vhost->action = action;
                break;
+       case IBMVFC_HOST_ACTION_LOGO_WAIT:
+               if (vhost->action == IBMVFC_HOST_ACTION_LOGO)
+                       vhost->action = action;
+               break;
        case IBMVFC_HOST_ACTION_INIT_WAIT:
                if (vhost->action == IBMVFC_HOST_ACTION_INIT)
                        vhost->action = action;
@@ -483,7 +490,7 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost,
                switch (vhost->action) {
                case IBMVFC_HOST_ACTION_INIT_WAIT:
                case IBMVFC_HOST_ACTION_NONE:
-               case IBMVFC_HOST_ACTION_TGT_ADD:
+               case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
                        vhost->action = action;
                        break;
                default:
@@ -494,11 +501,11 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost,
                if (vhost->action == IBMVFC_HOST_ACTION_ALLOC_TGTS)
                        vhost->action = action;
                break;
+       case IBMVFC_HOST_ACTION_LOGO:
        case IBMVFC_HOST_ACTION_INIT:
        case IBMVFC_HOST_ACTION_TGT_DEL:
        case IBMVFC_HOST_ACTION_QUERY_TGTS:
        case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
-       case IBMVFC_HOST_ACTION_TGT_ADD:
        case IBMVFC_HOST_ACTION_NONE:
        default:
                vhost->action = action;
@@ -576,7 +583,7 @@ static void ibmvfc_init_host(struct ibmvfc_host *vhost, int relogin)
                }
 
                list_for_each_entry(tgt, &vhost->targets, queue)
-                       tgt->need_login = 1;
+                       ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
                scsi_block_requests(vhost->host);
                ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT);
                vhost->job_step = ibmvfc_npiv_login;
@@ -646,6 +653,7 @@ static void ibmvfc_release_crq_queue(struct ibmvfc_host *vhost)
        } while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
 
        vhost->state = IBMVFC_NO_CRQ;
+       vhost->logged_in = 0;
        dma_unmap_single(vhost->dev, crq->msg_token, PAGE_SIZE, DMA_BIDIRECTIONAL);
        free_page((unsigned long)crq->msgs);
 }
@@ -692,6 +700,7 @@ static int ibmvfc_reset_crq(struct ibmvfc_host *vhost)
        } while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
 
        vhost->state = IBMVFC_NO_CRQ;
+       vhost->logged_in = 0;
        ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);
 
        /* Clean out the queue */
@@ -807,10 +816,10 @@ static void ibmvfc_purge_requests(struct ibmvfc_host *vhost, int error_code)
 }
 
 /**
- * __ibmvfc_reset_host - Reset the connection to the server (no locking)
+ * ibmvfc_hard_reset_host - Reset the connection to the server by breaking the CRQ
  * @vhost:     struct ibmvfc host to reset
  **/
-static void __ibmvfc_reset_host(struct ibmvfc_host *vhost)
+static void ibmvfc_hard_reset_host(struct ibmvfc_host *vhost)
 {
        int rc;
 
@@ -826,9 +835,25 @@ static void __ibmvfc_reset_host(struct ibmvfc_host *vhost)
 }
 
 /**
- * ibmvfc_reset_host - Reset the connection to the server
+ * __ibmvfc_reset_host - Reset the connection to the server (no locking)
  * @vhost:     struct ibmvfc host to reset
  **/
+static void __ibmvfc_reset_host(struct ibmvfc_host *vhost)
+{
+       if (vhost->logged_in && vhost->action != IBMVFC_HOST_ACTION_LOGO_WAIT &&
+           !ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) {
+               scsi_block_requests(vhost->host);
+               ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_LOGO);
+               vhost->job_step = ibmvfc_npiv_logout;
+               wake_up(&vhost->work_wait_q);
+       } else
+               ibmvfc_hard_reset_host(vhost);
+}
+
+/**
+ * ibmvfc_reset_host - Reset the connection to the server
+ * @vhost:     ibmvfc host struct
+ **/
 static void ibmvfc_reset_host(struct ibmvfc_host *vhost)
 {
        unsigned long flags;
@@ -842,9 +867,13 @@ static void ibmvfc_reset_host(struct ibmvfc_host *vhost)
  * ibmvfc_retry_host_init - Retry host initialization if allowed
  * @vhost:     ibmvfc host struct
  *
+ * Returns: 1 if init will be retried / 0 if not
+ *
  **/
-static void ibmvfc_retry_host_init(struct ibmvfc_host *vhost)
+static int ibmvfc_retry_host_init(struct ibmvfc_host *vhost)
 {
+       int retry = 0;
+
        if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) {
                vhost->delay_init = 1;
                if (++vhost->init_retries > IBMVFC_MAX_HOST_INIT_RETRIES) {
@@ -853,11 +882,14 @@ static void ibmvfc_retry_host_init(struct ibmvfc_host *vhost)
                        ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE);
                } else if (vhost->init_retries == IBMVFC_MAX_HOST_INIT_RETRIES)
                        __ibmvfc_reset_host(vhost);
-               else
+               else {
                        ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT);
+                       retry = 1;
+               }
        }
 
        wake_up(&vhost->work_wait_q);
+       return retry;
 }
 
 /**
@@ -1137,8 +1169,9 @@ static void ibmvfc_set_login_info(struct ibmvfc_host *vhost)
        login_info->partition_num = vhost->partition_number;
        login_info->vfc_frame_version = 1;
        login_info->fcp_version = 3;
+       login_info->flags = IBMVFC_FLUSH_ON_HALT;
        if (vhost->client_migrated)
-               login_info->flags = IBMVFC_CLIENT_MIGRATED;
+               login_info->flags |= IBMVFC_CLIENT_MIGRATED;
 
        login_info->max_cmds = max_requests + IBMVFC_NUM_INTERNAL_REQ;
        login_info->capabilities = IBMVFC_CAN_MIGRATE;
@@ -1451,6 +1484,27 @@ static void ibmvfc_log_error(struct ibmvfc_event *evt)
                    rsp->flags, rsp_code, scsi_get_resid(cmnd), rsp->scsi_status);
 }
 
+/**
+ * ibmvfc_relogin - Log back into the specified device
+ * @sdev:      scsi device struct
+ *
+ **/
+static void ibmvfc_relogin(struct scsi_device *sdev)
+{
+       struct ibmvfc_host *vhost = shost_priv(sdev->host);
+       struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
+       struct ibmvfc_target *tgt;
+
+       list_for_each_entry(tgt, &vhost->targets, queue) {
+               if (rport == tgt->rport) {
+                       ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
+                       break;
+               }
+       }
+
+       ibmvfc_reinit_host(vhost);
+}
+
 /**
  * ibmvfc_scsi_done - Handle responses from commands
  * @evt:       ibmvfc event to be handled
@@ -1483,7 +1537,7 @@ static void ibmvfc_scsi_done(struct ibmvfc_event *evt)
                        if ((rsp->flags & FCP_SNS_LEN_VALID) && rsp->fcp_sense_len && rsp_len <= 8)
                                memcpy(cmnd->sense_buffer, rsp->data.sense + rsp_len, sense_len);
                        if ((vfc_cmd->status & IBMVFC_VIOS_FAILURE) && (vfc_cmd->error == IBMVFC_PLOGI_REQUIRED))
-                               ibmvfc_reinit_host(evt->vhost);
+                               ibmvfc_relogin(cmnd->device);
 
                        if (!cmnd->result && (!scsi_get_resid(cmnd) || (rsp->flags & FCP_RESID_OVER)))
                                cmnd->result = (DID_ERROR << 16);
@@ -2148,13 +2202,31 @@ static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq,
                                struct ibmvfc_host *vhost)
 {
        const char *desc = ibmvfc_get_ae_desc(crq->event);
+       struct ibmvfc_target *tgt;
 
        ibmvfc_log(vhost, 3, "%s event received. scsi_id: %llx, wwpn: %llx,"
                   " node_name: %llx\n", desc, crq->scsi_id, crq->wwpn, crq->node_name);
 
        switch (crq->event) {
-       case IBMVFC_AE_LINK_UP:
        case IBMVFC_AE_RESUME:
+               switch (crq->link_state) {
+               case IBMVFC_AE_LS_LINK_DOWN:
+                       ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
+                       break;
+               case IBMVFC_AE_LS_LINK_DEAD:
+                       ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
+                       break;
+               case IBMVFC_AE_LS_LINK_UP:
+               case IBMVFC_AE_LS_LINK_BOUNCED:
+               default:
+                       vhost->events_to_log |= IBMVFC_AE_LINKUP;
+                       vhost->delay_init = 1;
+                       __ibmvfc_reset_host(vhost);
+                       break;
+               };
+
+               break;
+       case IBMVFC_AE_LINK_UP:
                vhost->events_to_log |= IBMVFC_AE_LINKUP;
                vhost->delay_init = 1;
                __ibmvfc_reset_host(vhost);
@@ -2168,9 +2240,23 @@ static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq,
        case IBMVFC_AE_SCN_NPORT:
        case IBMVFC_AE_SCN_GROUP:
                vhost->events_to_log |= IBMVFC_AE_RSCN;
+               ibmvfc_reinit_host(vhost);
+               break;
        case IBMVFC_AE_ELS_LOGO:
        case IBMVFC_AE_ELS_PRLO:
        case IBMVFC_AE_ELS_PLOGI:
+               list_for_each_entry(tgt, &vhost->targets, queue) {
+                       if (!crq->scsi_id && !crq->wwpn && !crq->node_name)
+                               break;
+                       if (crq->scsi_id && tgt->scsi_id != crq->scsi_id)
+                               continue;
+                       if (crq->wwpn && tgt->ids.port_name != crq->wwpn)
+                               continue;
+                       if (crq->node_name && tgt->ids.node_name != crq->node_name)
+                               continue;
+                       ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
+               }
+
                ibmvfc_reinit_host(vhost);
                break;
        case IBMVFC_AE_LINK_DOWN:
@@ -2222,6 +2308,7 @@ static void ibmvfc_handle_crq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost)
                return;
        case IBMVFC_CRQ_XPORT_EVENT:
                vhost->state = IBMVFC_NO_CRQ;
+               vhost->logged_in = 0;
                ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);
                if (crq->format == IBMVFC_PARTITION_MIGRATED) {
                        /* We need to re-setup the interpartition connection */
@@ -2299,7 +2386,7 @@ static int ibmvfc_scan_finished(struct Scsi_Host *shost, unsigned long time)
                done = 1;
        }
 
-       if (vhost->state != IBMVFC_NO_CRQ && vhost->action == IBMVFC_HOST_ACTION_NONE)
+       if (vhost->scan_complete)
                done = 1;
        spin_unlock_irqrestore(shost->host_lock, flags);
        return done;
@@ -2434,14 +2521,6 @@ static ssize_t ibmvfc_show_host_partition_name(struct device *dev,
                        vhost->login_buf->resp.partition_name);
 }
 
-static struct device_attribute ibmvfc_host_partition_name = {
-       .attr = {
-               .name = "partition_name",
-               .mode = S_IRUGO,
-       },
-       .show = ibmvfc_show_host_partition_name,
-};
-
 static ssize_t ibmvfc_show_host_device_name(struct device *dev,
                                            struct device_attribute *attr, char *buf)
 {
@@ -2452,14 +2531,6 @@ static ssize_t ibmvfc_show_host_device_name(struct device *dev,
                        vhost->login_buf->resp.device_name);
 }
 
-static struct device_attribute ibmvfc_host_device_name = {
-       .attr = {
-               .name = "device_name",
-               .mode = S_IRUGO,
-       },
-       .show = ibmvfc_show_host_device_name,
-};
-
 static ssize_t ibmvfc_show_host_loc_code(struct device *dev,
                                         struct device_attribute *attr, char *buf)
 {
@@ -2470,14 +2541,6 @@ static ssize_t ibmvfc_show_host_loc_code(struct device *dev,
                        vhost->login_buf->resp.port_loc_code);
 }
 
-static struct device_attribute ibmvfc_host_loc_code = {
-       .attr = {
-               .name = "port_loc_code",
-               .mode = S_IRUGO,
-       },
-       .show = ibmvfc_show_host_loc_code,
-};
-
 static ssize_t ibmvfc_show_host_drc_name(struct device *dev,
                                         struct device_attribute *attr, char *buf)
 {
@@ -2488,14 +2551,6 @@ static ssize_t ibmvfc_show_host_drc_name(struct device *dev,
                        vhost->login_buf->resp.drc_name);
 }
 
-static struct device_attribute ibmvfc_host_drc_name = {
-       .attr = {
-               .name = "drc_name",
-               .mode = S_IRUGO,
-       },
-       .show = ibmvfc_show_host_drc_name,
-};
-
 static ssize_t ibmvfc_show_host_npiv_version(struct device *dev,
                                             struct device_attribute *attr, char *buf)
 {
@@ -2504,13 +2559,13 @@ static ssize_t ibmvfc_show_host_npiv_version(struct device *dev,
        return snprintf(buf, PAGE_SIZE, "%d\n", vhost->login_buf->resp.version);
 }
 
-static struct device_attribute ibmvfc_host_npiv_version = {
-       .attr = {
-               .name = "npiv_version",
-               .mode = S_IRUGO,
-       },
-       .show = ibmvfc_show_host_npiv_version,
-};
+static ssize_t ibmvfc_show_host_capabilities(struct device *dev,
+                                            struct device_attribute *attr, char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct ibmvfc_host *vhost = shost_priv(shost);
+       return snprintf(buf, PAGE_SIZE, "%llx\n", vhost->login_buf->resp.capabilities);
+}
 
 /**
  * ibmvfc_show_log_level - Show the adapter's error logging level
@@ -2556,14 +2611,14 @@ static ssize_t ibmvfc_store_log_level(struct device *dev,
        return strlen(buf);
 }
 
-static struct device_attribute ibmvfc_log_level_attr = {
-       .attr = {
-               .name =         "log_level",
-               .mode =         S_IRUGO | S_IWUSR,
-       },
-       .show = ibmvfc_show_log_level,
-       .store = ibmvfc_store_log_level
-};
+static DEVICE_ATTR(partition_name, S_IRUGO, ibmvfc_show_host_partition_name, NULL);
+static DEVICE_ATTR(device_name, S_IRUGO, ibmvfc_show_host_device_name, NULL);
+static DEVICE_ATTR(port_loc_code, S_IRUGO, ibmvfc_show_host_loc_code, NULL);
+static DEVICE_ATTR(drc_name, S_IRUGO, ibmvfc_show_host_drc_name, NULL);
+static DEVICE_ATTR(npiv_version, S_IRUGO, ibmvfc_show_host_npiv_version, NULL);
+static DEVICE_ATTR(capabilities, S_IRUGO, ibmvfc_show_host_capabilities, NULL);
+static DEVICE_ATTR(log_level, S_IRUGO | S_IWUSR,
+                  ibmvfc_show_log_level, ibmvfc_store_log_level);
 
 #ifdef CONFIG_SCSI_IBMVFC_TRACE
 /**
@@ -2612,12 +2667,13 @@ static struct bin_attribute ibmvfc_trace_attr = {
 #endif
 
 static struct device_attribute *ibmvfc_attrs[] = {
-       &ibmvfc_host_partition_name,
-       &ibmvfc_host_device_name,
-       &ibmvfc_host_loc_code,
-       &ibmvfc_host_drc_name,
-       &ibmvfc_host_npiv_version,
-       &ibmvfc_log_level_attr,
+       &dev_attr_partition_name,
+       &dev_attr_device_name,
+       &dev_attr_port_loc_code,
+       &dev_attr_drc_name,
+       &dev_attr_npiv_version,
+       &dev_attr_capabilities,
+       &dev_attr_log_level,
        NULL
 };
 
@@ -2774,15 +2830,19 @@ static void ibmvfc_init_tgt(struct ibmvfc_target *tgt,
  * @tgt:               ibmvfc target struct
  * @job_step:  initialization job step
  *
+ * Returns: 1 if step will be retried / 0 if not
+ *
  **/
-static void ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt,
+static int ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt,
                                  void (*job_step) (struct ibmvfc_target *))
 {
        if (++tgt->init_retries > IBMVFC_MAX_TGT_INIT_RETRIES) {
                ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
                wake_up(&tgt->vhost->work_wait_q);
+               return 0;
        } else
                ibmvfc_init_tgt(tgt, job_step);
+       return 1;
 }
 
 /* Defined in FC-LS */
@@ -2831,7 +2891,7 @@ static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt)
        struct ibmvfc_process_login *rsp = &evt->xfer_iu->prli;
        struct ibmvfc_prli_svc_parms *parms = &rsp->parms;
        u32 status = rsp->common.status;
-       int index;
+       int index, level = IBMVFC_DEFAULT_LOG_LEVEL;
 
        vhost->discovery_threads--;
        ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
@@ -2850,7 +2910,7 @@ static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt)
                                                tgt->ids.roles |= FC_PORT_ROLE_FCP_TARGET;
                                        if (parms->service_parms & IBMVFC_PRLI_INITIATOR_FUNC)
                                                tgt->ids.roles |= FC_PORT_ROLE_FCP_INITIATOR;
-                                       ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_ADD_RPORT);
+                                       tgt->add_rport = 1;
                                } else
                                        ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
                        } else if (prli_rsp[index].retry)
@@ -2867,13 +2927,14 @@ static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt)
                break;
        case IBMVFC_MAD_FAILED:
        default:
-               tgt_err(tgt, "Process Login failed: %s (%x:%x) rc=0x%02X\n",
-                       ibmvfc_get_cmd_error(rsp->status, rsp->error),
-                       rsp->status, rsp->error, status);
                if (ibmvfc_retry_cmd(rsp->status, rsp->error))
-                       ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli);
+                       level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli);
                else
                        ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
+
+               tgt_log(tgt, level, "Process Login failed: %s (%x:%x) rc=0x%02X\n",
+                       ibmvfc_get_cmd_error(rsp->status, rsp->error),
+                       rsp->status, rsp->error, status);
                break;
        };
 
@@ -2932,6 +2993,7 @@ static void ibmvfc_tgt_plogi_done(struct ibmvfc_event *evt)
        struct ibmvfc_host *vhost = evt->vhost;
        struct ibmvfc_port_login *rsp = &evt->xfer_iu->plogi;
        u32 status = rsp->common.status;
+       int level = IBMVFC_DEFAULT_LOG_LEVEL;
 
        vhost->discovery_threads--;
        ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
@@ -2960,15 +3022,15 @@ static void ibmvfc_tgt_plogi_done(struct ibmvfc_event *evt)
                break;
        case IBMVFC_MAD_FAILED:
        default:
-               tgt_err(tgt, "Port Login failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n",
-                       ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error,
-                       ibmvfc_get_fc_type(rsp->fc_type), rsp->fc_type,
-                       ibmvfc_get_ls_explain(rsp->fc_explain), rsp->fc_explain, status);
-
                if (ibmvfc_retry_cmd(rsp->status, rsp->error))
-                       ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi);
+                       level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi);
                else
                        ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
+
+               tgt_log(tgt, level, "Port Login failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n",
+                       ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error,
+                       ibmvfc_get_fc_type(rsp->fc_type), rsp->fc_type,
+                       ibmvfc_get_ls_explain(rsp->fc_explain), rsp->fc_explain, status);
                break;
        };
 
@@ -3129,13 +3191,13 @@ static void ibmvfc_tgt_adisc_done(struct ibmvfc_event *evt)
        case IBMVFC_MAD_SUCCESS:
                tgt_dbg(tgt, "ADISC succeeded\n");
                if (ibmvfc_adisc_needs_plogi(mad, tgt))
-                       tgt->need_login = 1;
+                       ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
                break;
        case IBMVFC_MAD_DRIVER_FAILED:
                break;
        case IBMVFC_MAD_FAILED:
        default:
-               tgt->need_login = 1;
+               ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
                fc_reason = (mad->fc_iu.response[1] & 0x00ff0000) >> 16;
                fc_explain = (mad->fc_iu.response[1] & 0x0000ff00) >> 8;
                tgt_info(tgt, "ADISC failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n",
@@ -3322,6 +3384,7 @@ static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt)
        struct ibmvfc_host *vhost = evt->vhost;
        struct ibmvfc_query_tgt *rsp = &evt->xfer_iu->query_tgt;
        u32 status = rsp->common.status;
+       int level = IBMVFC_DEFAULT_LOG_LEVEL;
 
        vhost->discovery_threads--;
        ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
@@ -3341,19 +3404,19 @@ static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt)
                break;
        case IBMVFC_MAD_FAILED:
        default:
-               tgt_err(tgt, "Query Target failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n",
-                       ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error,
-                       ibmvfc_get_fc_type(rsp->fc_type), rsp->fc_type,
-                       ibmvfc_get_gs_explain(rsp->fc_explain), rsp->fc_explain, status);
-
                if ((rsp->status & IBMVFC_FABRIC_MAPPED) == IBMVFC_FABRIC_MAPPED &&
                    rsp->error == IBMVFC_UNABLE_TO_PERFORM_REQ &&
                    rsp->fc_explain == IBMVFC_PORT_NAME_NOT_REG)
                        ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
                else if (ibmvfc_retry_cmd(rsp->status, rsp->error))
-                       ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target);
+                       level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target);
                else
                        ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
+
+               tgt_log(tgt, level, "Query Target failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n",
+                       ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error,
+                       ibmvfc_get_fc_type(rsp->fc_type), rsp->fc_type,
+                       ibmvfc_get_gs_explain(rsp->fc_explain), rsp->fc_explain, status);
                break;
        };
 
@@ -3420,7 +3483,7 @@ static int ibmvfc_alloc_target(struct ibmvfc_host *vhost, u64 scsi_id)
        }
        spin_unlock_irqrestore(vhost->host->host_lock, flags);
 
-       tgt = mempool_alloc(vhost->tgt_pool, GFP_KERNEL);
+       tgt = mempool_alloc(vhost->tgt_pool, GFP_NOIO);
        if (!tgt) {
                dev_err(vhost->dev, "Target allocation failure for scsi id %08llx\n",
                        scsi_id);
@@ -3472,6 +3535,7 @@ static void ibmvfc_discover_targets_done(struct ibmvfc_event *evt)
        struct ibmvfc_host *vhost = evt->vhost;
        struct ibmvfc_discover_targets *rsp = &evt->xfer_iu->discover_targets;
        u32 mad_status = rsp->common.status;
+       int level = IBMVFC_DEFAULT_LOG_LEVEL;
 
        switch (mad_status) {
        case IBMVFC_MAD_SUCCESS:
@@ -3480,9 +3544,9 @@ static void ibmvfc_discover_targets_done(struct ibmvfc_event *evt)
                ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_ALLOC_TGTS);
                break;
        case IBMVFC_MAD_FAILED:
-               dev_err(vhost->dev, "Discover Targets failed: %s (%x:%x)\n",
-                       ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error);
-               ibmvfc_retry_host_init(vhost);
+               level += ibmvfc_retry_host_init(vhost);
+               ibmvfc_log(vhost, level, "Discover Targets failed: %s (%x:%x)\n",
+                          ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error);
                break;
        case IBMVFC_MAD_DRIVER_FAILED:
                break;
@@ -3534,18 +3598,19 @@ static void ibmvfc_npiv_login_done(struct ibmvfc_event *evt)
        u32 mad_status = evt->xfer_iu->npiv_login.common.status;
        struct ibmvfc_npiv_login_resp *rsp = &vhost->login_buf->resp;
        unsigned int npiv_max_sectors;
+       int level = IBMVFC_DEFAULT_LOG_LEVEL;
 
        switch (mad_status) {
        case IBMVFC_MAD_SUCCESS:
                ibmvfc_free_event(evt);
                break;
        case IBMVFC_MAD_FAILED:
-               dev_err(vhost->dev, "NPIV Login failed: %s (%x:%x)\n",
-                       ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error);
                if (ibmvfc_retry_cmd(rsp->status, rsp->error))
-                       ibmvfc_retry_host_init(vhost);
+                       level += ibmvfc_retry_host_init(vhost);
                else
                        ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
+               ibmvfc_log(vhost, level, "NPIV Login failed: %s (%x:%x)\n",
+                          ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error);
                ibmvfc_free_event(evt);
                return;
        case IBMVFC_MAD_CRQ_ERROR:
@@ -3578,6 +3643,7 @@ static void ibmvfc_npiv_login_done(struct ibmvfc_event *evt)
                return;
        }
 
+       vhost->logged_in = 1;
        npiv_max_sectors = min((uint)(rsp->max_dma_len >> 9), IBMVFC_MAX_SECTORS);
        dev_info(vhost->dev, "Host partition: %s, device: %s %s %s max sectors %u\n",
                 rsp->partition_name, rsp->device_name, rsp->port_loc_code,
@@ -3635,6 +3701,65 @@ static void ibmvfc_npiv_login(struct ibmvfc_host *vhost)
                ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
 };
 
+/**
+ * ibmvfc_npiv_logout_done - Completion handler for NPIV Logout
+ * @vhost:             ibmvfc host struct
+ *
+ **/
+static void ibmvfc_npiv_logout_done(struct ibmvfc_event *evt)
+{
+       struct ibmvfc_host *vhost = evt->vhost;
+       u32 mad_status = evt->xfer_iu->npiv_logout.common.status;
+
+       ibmvfc_free_event(evt);
+
+       switch (mad_status) {
+       case IBMVFC_MAD_SUCCESS:
+               if (list_empty(&vhost->sent) &&
+                   vhost->action == IBMVFC_HOST_ACTION_LOGO_WAIT) {
+                       ibmvfc_init_host(vhost, 0);
+                       return;
+               }
+               break;
+       case IBMVFC_MAD_FAILED:
+       case IBMVFC_MAD_NOT_SUPPORTED:
+       case IBMVFC_MAD_CRQ_ERROR:
+       case IBMVFC_MAD_DRIVER_FAILED:
+       default:
+               ibmvfc_dbg(vhost, "NPIV Logout failed. 0x%X\n", mad_status);
+               break;
+       }
+
+       ibmvfc_hard_reset_host(vhost);
+}
+
+/**
+ * ibmvfc_npiv_logout - Issue an NPIV Logout
+ * @vhost:             ibmvfc host struct
+ *
+ **/
+static void ibmvfc_npiv_logout(struct ibmvfc_host *vhost)
+{
+       struct ibmvfc_npiv_logout_mad *mad;
+       struct ibmvfc_event *evt;
+
+       evt = ibmvfc_get_event(vhost);
+       ibmvfc_init_event(evt, ibmvfc_npiv_logout_done, IBMVFC_MAD_FORMAT);
+
+       mad = &evt->iu.npiv_logout;
+       memset(mad, 0, sizeof(*mad));
+       mad->common.version = 1;
+       mad->common.opcode = IBMVFC_NPIV_LOGOUT;
+       mad->common.length = sizeof(struct ibmvfc_npiv_logout_mad);
+
+       ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_LOGO_WAIT);
+
+       if (!ibmvfc_send_event(evt, vhost, default_timeout))
+               ibmvfc_dbg(vhost, "Sent NPIV logout\n");
+       else
+               ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
+}
+
 /**
  * ibmvfc_dev_init_to_do - Is there target initialization work to do?
  * @vhost:             ibmvfc host struct
@@ -3671,6 +3796,7 @@ static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost)
        switch (vhost->action) {
        case IBMVFC_HOST_ACTION_NONE:
        case IBMVFC_HOST_ACTION_INIT_WAIT:
+       case IBMVFC_HOST_ACTION_LOGO_WAIT:
                return 0;
        case IBMVFC_HOST_ACTION_TGT_INIT:
        case IBMVFC_HOST_ACTION_QUERY_TGTS:
@@ -3683,9 +3809,9 @@ static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost)
                        if (tgt->action == IBMVFC_TGT_ACTION_INIT_WAIT)
                                return 0;
                return 1;
+       case IBMVFC_HOST_ACTION_LOGO:
        case IBMVFC_HOST_ACTION_INIT:
        case IBMVFC_HOST_ACTION_ALLOC_TGTS:
-       case IBMVFC_HOST_ACTION_TGT_ADD:
        case IBMVFC_HOST_ACTION_TGT_DEL:
        case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
        case IBMVFC_HOST_ACTION_QUERY:
@@ -3740,25 +3866,26 @@ static void ibmvfc_log_ae(struct ibmvfc_host *vhost, int events)
 static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt)
 {
        struct ibmvfc_host *vhost = tgt->vhost;
-       struct fc_rport *rport = tgt->rport;
+       struct fc_rport *rport;
        unsigned long flags;
 
-       if (rport) {
-               tgt_dbg(tgt, "Setting rport roles\n");
-               fc_remote_port_rolechg(rport, tgt->ids.roles);
-               spin_lock_irqsave(vhost->host->host_lock, flags);
-               ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
+       tgt_dbg(tgt, "Adding rport\n");
+       rport = fc_remote_port_add(vhost->host, 0, &tgt->ids);
+       spin_lock_irqsave(vhost->host->host_lock, flags);
+
+       if (rport && tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) {
+               tgt_dbg(tgt, "Deleting rport\n");
+               list_del(&tgt->queue);
                spin_unlock_irqrestore(vhost->host->host_lock, flags);
+               fc_remote_port_delete(rport);
+               del_timer_sync(&tgt->timer);
+               kref_put(&tgt->kref, ibmvfc_release_tgt);
                return;
        }
 
-       tgt_dbg(tgt, "Adding rport\n");
-       rport = fc_remote_port_add(vhost->host, 0, &tgt->ids);
-       spin_lock_irqsave(vhost->host->host_lock, flags);
-       tgt->rport = rport;
-       ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
        if (rport) {
                tgt_dbg(tgt, "rport add succeeded\n");
+               tgt->rport = rport;
                rport->maxframe_size = tgt->service_parms.common.bb_rcv_sz & 0x0fff;
                rport->supported_classes = 0;
                tgt->target_id = rport->scsi_target_id;
@@ -3789,8 +3916,12 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)
        vhost->events_to_log = 0;
        switch (vhost->action) {
        case IBMVFC_HOST_ACTION_NONE:
+       case IBMVFC_HOST_ACTION_LOGO_WAIT:
        case IBMVFC_HOST_ACTION_INIT_WAIT:
                break;
+       case IBMVFC_HOST_ACTION_LOGO:
+               vhost->job_step(vhost);
+               break;
        case IBMVFC_HOST_ACTION_INIT:
                BUG_ON(vhost->state != IBMVFC_INITIALIZING);
                if (vhost->delay_init) {
@@ -3836,11 +3967,21 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)
 
                if (vhost->state == IBMVFC_INITIALIZING) {
                        if (vhost->action == IBMVFC_HOST_ACTION_TGT_DEL_FAILED) {
-                               ibmvfc_set_host_state(vhost, IBMVFC_ACTIVE);
-                               ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_ADD);
-                               vhost->init_retries = 0;
-                               spin_unlock_irqrestore(vhost->host->host_lock, flags);
-                               scsi_unblock_requests(vhost->host);
+                               if (vhost->reinit) {
+                                       vhost->reinit = 0;
+                                       scsi_block_requests(vhost->host);
+                                       ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
+                                       spin_unlock_irqrestore(vhost->host->host_lock, flags);
+                               } else {
+                                       ibmvfc_set_host_state(vhost, IBMVFC_ACTIVE);
+                                       ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);
+                                       wake_up(&vhost->init_wait_q);
+                                       schedule_work(&vhost->rport_add_work_q);
+                                       vhost->init_retries = 0;
+                                       spin_unlock_irqrestore(vhost->host->host_lock, flags);
+                                       scsi_unblock_requests(vhost->host);
+                               }
+
                                return;
                        } else {
                                ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT);
@@ -3871,24 +4012,6 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)
                if (!ibmvfc_dev_init_to_do(vhost))
                        ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL_FAILED);
                break;
-       case IBMVFC_HOST_ACTION_TGT_ADD:
-               list_for_each_entry(tgt, &vhost->targets, queue) {
-                       if (tgt->action == IBMVFC_TGT_ACTION_ADD_RPORT) {
-                               spin_unlock_irqrestore(vhost->host->host_lock, flags);
-                               ibmvfc_tgt_add_rport(tgt);
-                               return;
-                       }
-               }
-
-               if (vhost->reinit && !ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) {
-                       vhost->reinit = 0;
-                       scsi_block_requests(vhost->host);
-                       ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
-               } else {
-                       ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);
-                       wake_up(&vhost->init_wait_q);
-               }
-               break;
        default:
                break;
        };
@@ -4117,6 +4240,56 @@ nomem:
        return -ENOMEM;
 }
 
+/**
+ * ibmvfc_rport_add_thread - Worker thread for rport adds
+ * @work:      work struct
+ *
+ **/
+static void ibmvfc_rport_add_thread(struct work_struct *work)
+{
+       struct ibmvfc_host *vhost = container_of(work, struct ibmvfc_host,
+                                                rport_add_work_q);
+       struct ibmvfc_target *tgt;
+       struct fc_rport *rport;
+       unsigned long flags;
+       int did_work;
+
+       ENTER;
+       spin_lock_irqsave(vhost->host->host_lock, flags);
+       do {
+               did_work = 0;
+               if (vhost->state != IBMVFC_ACTIVE)
+                       break;
+
+               list_for_each_entry(tgt, &vhost->targets, queue) {
+                       if (tgt->add_rport) {
+                               did_work = 1;
+                               tgt->add_rport = 0;
+                               kref_get(&tgt->kref);
+                               rport = tgt->rport;
+                               if (!rport) {
+                                       spin_unlock_irqrestore(vhost->host->host_lock, flags);
+                                       ibmvfc_tgt_add_rport(tgt);
+                               } else if (get_device(&rport->dev)) {
+                                       spin_unlock_irqrestore(vhost->host->host_lock, flags);
+                                       tgt_dbg(tgt, "Setting rport roles\n");
+                                       fc_remote_port_rolechg(rport, tgt->ids.roles);
+                                       put_device(&rport->dev);
+                               }
+
+                               kref_put(&tgt->kref, ibmvfc_release_tgt);
+                               spin_lock_irqsave(vhost->host->host_lock, flags);
+                               break;
+                       }
+               }
+       } while(did_work);
+
+       if (vhost->state == IBMVFC_ACTIVE)
+               vhost->scan_complete = 1;
+       spin_unlock_irqrestore(vhost->host->host_lock, flags);
+       LEAVE;
+}
+
 /**
  * ibmvfc_probe - Adapter hot plug add entry point
  * @vdev:      vio device struct
@@ -4160,6 +4333,7 @@ static int ibmvfc_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        strcpy(vhost->partition_name, "UNKNOWN");
        init_waitqueue_head(&vhost->work_wait_q);
        init_waitqueue_head(&vhost->init_wait_q);
+       INIT_WORK(&vhost->rport_add_work_q, ibmvfc_rport_add_thread);
 
        if ((rc = ibmvfc_alloc_mem(vhost)))
                goto free_scsi_host;
index ca1dcf7a7568b95ab1f4d3608a5fd710a449798c..c2668d7d67f5308cdfc33819f0333e719f842947 100644 (file)
@@ -29,8 +29,8 @@
 #include "viosrp.h"
 
 #define IBMVFC_NAME    "ibmvfc"
-#define IBMVFC_DRIVER_VERSION          "1.0.5"
-#define IBMVFC_DRIVER_DATE             "(March 19, 2009)"
+#define IBMVFC_DRIVER_VERSION          "1.0.6"
+#define IBMVFC_DRIVER_DATE             "(May 28, 2009)"
 
 #define IBMVFC_DEFAULT_TIMEOUT 60
 #define IBMVFC_ADISC_CANCEL_TIMEOUT    45
  * Ensure we have resources for ERP and initialization:
  * 1 for ERP
  * 1 for initialization
+ * 1 for NPIV Logout
  * 2 for each discovery thread
  */
-#define IBMVFC_NUM_INTERNAL_REQ        (1 + 1 + (disc_threads * 2))
+#define IBMVFC_NUM_INTERNAL_REQ        (1 + 1 + 1 + (disc_threads * 2))
 
 #define IBMVFC_MAD_SUCCESS             0x00
 #define IBMVFC_MAD_NOT_SUPPORTED       0xF1
@@ -127,6 +128,7 @@ enum ibmvfc_mad_types {
        IBMVFC_IMPLICIT_LOGOUT  = 0x0040,
        IBMVFC_PASSTHRU         = 0x0200,
        IBMVFC_TMF_MAD          = 0x0100,
+       IBMVFC_NPIV_LOGOUT      = 0x0800,
 };
 
 struct ibmvfc_mad_common {
@@ -143,6 +145,10 @@ struct ibmvfc_npiv_login_mad {
        struct srp_direct_buf buffer;
 }__attribute__((packed, aligned (8)));
 
+struct ibmvfc_npiv_logout_mad {
+       struct ibmvfc_mad_common common;
+}__attribute__((packed, aligned (8)));
+
 #define IBMVFC_MAX_NAME 256
 
 struct ibmvfc_npiv_login {
@@ -201,7 +207,8 @@ struct ibmvfc_npiv_login_resp {
 #define IBMVFC_NATIVE_FC               0x01
 #define IBMVFC_CAN_FLUSH_ON_HALT       0x08
        u32 reserved;
-       u64 capabilites;
+       u64 capabilities;
+#define IBMVFC_CAN_FLUSH_ON_HALT       0x08
        u32 max_cmds;
        u32 scsi_id_sz;
        u64 max_dma_len;
@@ -541,9 +548,17 @@ struct ibmvfc_crq_queue {
        dma_addr_t msg_token;
 };
 
+enum ibmvfc_ae_link_state {
+       IBMVFC_AE_LS_LINK_UP            = 0x01,
+       IBMVFC_AE_LS_LINK_BOUNCED       = 0x02,
+       IBMVFC_AE_LS_LINK_DOWN          = 0x04,
+       IBMVFC_AE_LS_LINK_DEAD          = 0x08,
+};
+
 struct ibmvfc_async_crq {
        volatile u8 valid;
-       u8 pad[3];
+       u8 link_state;
+       u8 pad[2];
        u32 pad2;
        volatile u64 event;
        volatile u64 scsi_id;
@@ -561,6 +576,7 @@ struct ibmvfc_async_crq_queue {
 union ibmvfc_iu {
        struct ibmvfc_mad_common mad_common;
        struct ibmvfc_npiv_login_mad npiv_login;
+       struct ibmvfc_npiv_logout_mad npiv_logout;
        struct ibmvfc_discover_targets discover_targets;
        struct ibmvfc_port_login plogi;
        struct ibmvfc_process_login prli;
@@ -575,7 +591,6 @@ enum ibmvfc_target_action {
        IBMVFC_TGT_ACTION_NONE = 0,
        IBMVFC_TGT_ACTION_INIT,
        IBMVFC_TGT_ACTION_INIT_WAIT,
-       IBMVFC_TGT_ACTION_ADD_RPORT,
        IBMVFC_TGT_ACTION_DEL_RPORT,
 };
 
@@ -588,6 +603,7 @@ struct ibmvfc_target {
        int target_id;
        enum ibmvfc_target_action action;
        int need_login;
+       int add_rport;
        int init_retries;
        u32 cancel_key;
        struct ibmvfc_service_parms service_parms;
@@ -627,6 +643,8 @@ struct ibmvfc_event_pool {
 
 enum ibmvfc_host_action {
        IBMVFC_HOST_ACTION_NONE = 0,
+       IBMVFC_HOST_ACTION_LOGO,
+       IBMVFC_HOST_ACTION_LOGO_WAIT,
        IBMVFC_HOST_ACTION_INIT,
        IBMVFC_HOST_ACTION_INIT_WAIT,
        IBMVFC_HOST_ACTION_QUERY,
@@ -635,7 +653,6 @@ enum ibmvfc_host_action {
        IBMVFC_HOST_ACTION_ALLOC_TGTS,
        IBMVFC_HOST_ACTION_TGT_INIT,
        IBMVFC_HOST_ACTION_TGT_DEL_FAILED,
-       IBMVFC_HOST_ACTION_TGT_ADD,
 };
 
 enum ibmvfc_host_state {
@@ -682,6 +699,8 @@ struct ibmvfc_host {
        int client_migrated;
        int reinit;
        int delay_init;
+       int scan_complete;
+       int logged_in;
        int events_to_log;
 #define IBMVFC_AE_LINKUP       0x0001
 #define IBMVFC_AE_LINKDOWN     0x0002
@@ -692,6 +711,7 @@ struct ibmvfc_host {
        void (*job_step) (struct ibmvfc_host *);
        struct task_struct *work_thread;
        struct tasklet_struct tasklet;
+       struct work_struct rport_add_work_q;
        wait_queue_head_t init_wait_q;
        wait_queue_head_t work_wait_q;
 };
@@ -707,6 +727,12 @@ struct ibmvfc_host {
 #define tgt_err(t, fmt, ...)           \
        dev_err((t)->vhost->dev, "%llX: " fmt, (t)->scsi_id, ##__VA_ARGS__)
 
+#define tgt_log(t, level, fmt, ...) \
+       do { \
+               if ((t)->vhost->log_level >= level) \
+                       tgt_err(t, fmt, ##__VA_ARGS__); \
+       } while (0)
+
 #define ibmvfc_dbg(vhost, ...) \
        DBG_CMD(dev_info((vhost)->dev, ##__VA_ARGS__))
 
index c9aa7611e40824142534d21aa46fc4461936ba33..11d2602ae88ecd2ffd4c2ab8b759538dac8a02c8 100644 (file)
@@ -70,6 +70,7 @@
 #include <linux/moduleparam.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
+#include <linux/of.h>
 #include <asm/firmware.h>
 #include <asm/vio.h>
 #include <asm/firmware.h>
  */
 static int max_id = 64;
 static int max_channel = 3;
-static int init_timeout = 5;
+static int init_timeout = 300;
+static int login_timeout = 60;
+static int info_timeout = 30;
+static int abort_timeout = 60;
+static int reset_timeout = 60;
 static int max_requests = IBMVSCSI_MAX_REQUESTS_DEFAULT;
 static int max_events = IBMVSCSI_MAX_REQUESTS_DEFAULT + 2;
+static int fast_fail = 1;
+static int client_reserve = 1;
 
 static struct scsi_transport_template *ibmvscsi_transport_template;
 
@@ -110,6 +117,10 @@ module_param_named(init_timeout, init_timeout, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(init_timeout, "Initialization timeout in seconds");
 module_param_named(max_requests, max_requests, int, S_IRUGO);
 MODULE_PARM_DESC(max_requests, "Maximum requests for this adapter");
+module_param_named(fast_fail, fast_fail, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(fast_fail, "Enable fast fail. [Default=1]");
+module_param_named(client_reserve, client_reserve, int, S_IRUGO );
+MODULE_PARM_DESC(client_reserve, "Attempt client managed reserve/release");
 
 /* ------------------------------------------------------------
  * Routines for the event pool and event structs
@@ -781,105 +792,53 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
 /* ------------------------------------------------------------
  * Routines for driver initialization
  */
+
 /**
- * adapter_info_rsp: - Handle response to MAD adapter info request
- * @evt_struct:        srp_event_struct with the response
+ * map_persist_bufs: - Pre-map persistent data for adapter logins
+ * @hostdata:   ibmvscsi_host_data of host
  *
- * Used as a "done" callback by when sending adapter_info. Gets called
- * by ibmvscsi_handle_crq()
-*/
-static void adapter_info_rsp(struct srp_event_struct *evt_struct)
+ * Map the capabilities and adapter info DMA buffers to avoid runtime failures.
+ * Return 1 on error, 0 on success.
+ */
+static int map_persist_bufs(struct ibmvscsi_host_data *hostdata)
 {
-       struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
-       dma_unmap_single(hostdata->dev,
-                        evt_struct->iu.mad.adapter_info.buffer,
-                        evt_struct->iu.mad.adapter_info.common.length,
-                        DMA_BIDIRECTIONAL);
 
-       if (evt_struct->xfer_iu->mad.adapter_info.common.status) {
-               dev_err(hostdata->dev, "error %d getting adapter info\n",
-                       evt_struct->xfer_iu->mad.adapter_info.common.status);
-       } else {
-               dev_info(hostdata->dev, "host srp version: %s, "
-                        "host partition %s (%d), OS %d, max io %u\n",
-                        hostdata->madapter_info.srp_version,
-                        hostdata->madapter_info.partition_name,
-                        hostdata->madapter_info.partition_number,
-                        hostdata->madapter_info.os_type,
-                        hostdata->madapter_info.port_max_txu[0]);
-               
-               if (hostdata->madapter_info.port_max_txu[0]) 
-                       hostdata->host->max_sectors = 
-                               hostdata->madapter_info.port_max_txu[0] >> 9;
-               
-               if (hostdata->madapter_info.os_type == 3 &&
-                   strcmp(hostdata->madapter_info.srp_version, "1.6a") <= 0) {
-                       dev_err(hostdata->dev, "host (Ver. %s) doesn't support large transfers\n",
-                               hostdata->madapter_info.srp_version);
-                       dev_err(hostdata->dev, "limiting scatterlists to %d\n",
-                               MAX_INDIRECT_BUFS);
-                       hostdata->host->sg_tablesize = MAX_INDIRECT_BUFS;
-               }
+       hostdata->caps_addr = dma_map_single(hostdata->dev, &hostdata->caps,
+                                            sizeof(hostdata->caps), DMA_BIDIRECTIONAL);
+
+       if (dma_mapping_error(hostdata->dev, hostdata->caps_addr)) {
+               dev_err(hostdata->dev, "Unable to map capabilities buffer!\n");
+               return 1;
        }
+
+       hostdata->adapter_info_addr = dma_map_single(hostdata->dev,
+                                                    &hostdata->madapter_info,
+                                                    sizeof(hostdata->madapter_info),
+                                                    DMA_BIDIRECTIONAL);
+       if (dma_mapping_error(hostdata->dev, hostdata->adapter_info_addr)) {
+               dev_err(hostdata->dev, "Unable to map adapter info buffer!\n");
+               dma_unmap_single(hostdata->dev, hostdata->caps_addr,
+                                sizeof(hostdata->caps), DMA_BIDIRECTIONAL);
+               return 1;
+       }
+
+       return 0;
 }
 
 /**
- * send_mad_adapter_info: - Sends the mad adapter info request
- *      and stores the result so it can be retrieved with
- *      sysfs.  We COULD consider causing a failure if the
- *      returned SRP version doesn't match ours.
- * @hostdata:  ibmvscsi_host_data of host
- * 
- * Returns zero if successful.
-*/
-static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata)
+ * unmap_persist_bufs: - Unmap persistent data needed for adapter logins
+ * @hostdata:   ibmvscsi_host_data of host
+ *
+ * Unmap the capabilities and adapter info DMA buffers
+ */
+static void unmap_persist_bufs(struct ibmvscsi_host_data *hostdata)
 {
-       struct viosrp_adapter_info *req;
-       struct srp_event_struct *evt_struct;
-       unsigned long flags;
-       dma_addr_t addr;
-
-       evt_struct = get_event_struct(&hostdata->pool);
-       if (!evt_struct) {
-               dev_err(hostdata->dev,
-                       "couldn't allocate an event for ADAPTER_INFO_REQ!\n");
-               return;
-       }
-
-       init_event_struct(evt_struct,
-                         adapter_info_rsp,
-                         VIOSRP_MAD_FORMAT,
-                         init_timeout);
-       
-       req = &evt_struct->iu.mad.adapter_info;
-       memset(req, 0x00, sizeof(*req));
-       
-       req->common.type = VIOSRP_ADAPTER_INFO_TYPE;
-       req->common.length = sizeof(hostdata->madapter_info);
-       req->buffer = addr = dma_map_single(hostdata->dev,
-                                           &hostdata->madapter_info,
-                                           sizeof(hostdata->madapter_info),
-                                           DMA_BIDIRECTIONAL);
+       dma_unmap_single(hostdata->dev, hostdata->caps_addr,
+                        sizeof(hostdata->caps), DMA_BIDIRECTIONAL);
 
-       if (dma_mapping_error(hostdata->dev, req->buffer)) {
-               if (!firmware_has_feature(FW_FEATURE_CMO))
-                       dev_err(hostdata->dev,
-                               "Unable to map request_buffer for "
-                               "adapter_info!\n");
-               free_event_struct(&hostdata->pool, evt_struct);
-               return;
-       }
-       
-       spin_lock_irqsave(hostdata->host->host_lock, flags);
-       if (ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2)) {
-               dev_err(hostdata->dev, "couldn't send ADAPTER_INFO_REQ!\n");
-               dma_unmap_single(hostdata->dev,
-                                addr,
-                                sizeof(hostdata->madapter_info),
-                                DMA_BIDIRECTIONAL);
-       }
-       spin_unlock_irqrestore(hostdata->host->host_lock, flags);
-};
+       dma_unmap_single(hostdata->dev, hostdata->adapter_info_addr,
+                        sizeof(hostdata->madapter_info), DMA_BIDIRECTIONAL);
+}
 
 /**
  * login_rsp: - Handle response to SRP login request
@@ -909,9 +868,7 @@ static void login_rsp(struct srp_event_struct *evt_struct)
        }
 
        dev_info(hostdata->dev, "SRP_LOGIN succeeded\n");
-
-       if (evt_struct->xfer_iu->srp.login_rsp.req_lim_delta < 0)
-               dev_err(hostdata->dev, "Invalid request_limit.\n");
+       hostdata->client_migrated = 0;
 
        /* Now we know what the real request-limit is.
         * This value is set rather than added to request_limit because
@@ -922,15 +879,12 @@ static void login_rsp(struct srp_event_struct *evt_struct)
 
        /* If we had any pending I/Os, kick them */
        scsi_unblock_requests(hostdata->host);
-
-       send_mad_adapter_info(hostdata);
-       return;
 }
 
 /**
  * send_srp_login: - Sends the srp login
  * @hostdata:  ibmvscsi_host_data of host
- * 
+ *
  * Returns zero if successful.
 */
 static int send_srp_login(struct ibmvscsi_host_data *hostdata)
@@ -939,22 +893,17 @@ static int send_srp_login(struct ibmvscsi_host_data *hostdata)
        unsigned long flags;
        struct srp_login_req *login;
        struct srp_event_struct *evt_struct = get_event_struct(&hostdata->pool);
-       if (!evt_struct) {
-               dev_err(hostdata->dev, "couldn't allocate an event for login req!\n");
-               return FAILED;
-       }
 
-       init_event_struct(evt_struct,
-                         login_rsp,
-                         VIOSRP_SRP_FORMAT,
-                         init_timeout);
+       BUG_ON(!evt_struct);
+       init_event_struct(evt_struct, login_rsp,
+                         VIOSRP_SRP_FORMAT, login_timeout);
 
        login = &evt_struct->iu.srp.login_req;
-       memset(login, 0x00, sizeof(struct srp_login_req));
+       memset(login, 0, sizeof(*login));
        login->opcode = SRP_LOGIN_REQ;
        login->req_it_iu_len = sizeof(union srp_iu);
        login->req_buf_fmt = SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT;
-       
+
        spin_lock_irqsave(hostdata->host->host_lock, flags);
        /* Start out with a request limit of 0, since this is negotiated in
         * the login request we are just sending and login requests always
@@ -962,12 +911,240 @@ static int send_srp_login(struct ibmvscsi_host_data *hostdata)
         */
        atomic_set(&hostdata->request_limit, 0);
 
-       rc = ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2);
+       rc = ibmvscsi_send_srp_event(evt_struct, hostdata, login_timeout * 2);
        spin_unlock_irqrestore(hostdata->host->host_lock, flags);
        dev_info(hostdata->dev, "sent SRP login\n");
        return rc;
 };
 
+/**
+ * capabilities_rsp: - Handle response to MAD adapter capabilities request
+ * @evt_struct:        srp_event_struct with the response
+ *
+ * Used as a "done" callback by when sending adapter_info.
+ */
+static void capabilities_rsp(struct srp_event_struct *evt_struct)
+{
+       struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
+
+       if (evt_struct->xfer_iu->mad.capabilities.common.status) {
+               dev_err(hostdata->dev, "error 0x%X getting capabilities info\n",
+                       evt_struct->xfer_iu->mad.capabilities.common.status);
+       } else {
+               if (hostdata->caps.migration.common.server_support != SERVER_SUPPORTS_CAP)
+                       dev_info(hostdata->dev, "Partition migration not supported\n");
+
+               if (client_reserve) {
+                       if (hostdata->caps.reserve.common.server_support ==
+                           SERVER_SUPPORTS_CAP)
+                               dev_info(hostdata->dev, "Client reserve enabled\n");
+                       else
+                               dev_info(hostdata->dev, "Client reserve not supported\n");
+               }
+       }
+
+       send_srp_login(hostdata);
+}
+
+/**
+ * send_mad_capabilities: - Sends the mad capabilities request
+ *      and stores the result so it can be retrieved with
+ * @hostdata:  ibmvscsi_host_data of host
+ */
+static void send_mad_capabilities(struct ibmvscsi_host_data *hostdata)
+{
+       struct viosrp_capabilities *req;
+       struct srp_event_struct *evt_struct;
+       unsigned long flags;
+       struct device_node *of_node = hostdata->dev->archdata.of_node;
+       const char *location;
+
+       evt_struct = get_event_struct(&hostdata->pool);
+       BUG_ON(!evt_struct);
+
+       init_event_struct(evt_struct, capabilities_rsp,
+                         VIOSRP_MAD_FORMAT, info_timeout);
+
+       req = &evt_struct->iu.mad.capabilities;
+       memset(req, 0, sizeof(*req));
+
+       hostdata->caps.flags = CAP_LIST_SUPPORTED;
+       if (hostdata->client_migrated)
+               hostdata->caps.flags |= CLIENT_MIGRATED;
+
+       strncpy(hostdata->caps.name, dev_name(&hostdata->host->shost_gendev),
+               sizeof(hostdata->caps.name));
+       hostdata->caps.name[sizeof(hostdata->caps.name) - 1] = '\0';
+
+       location = of_get_property(of_node, "ibm,loc-code", NULL);
+       location = location ? location : dev_name(hostdata->dev);
+       strncpy(hostdata->caps.loc, location, sizeof(hostdata->caps.loc));
+       hostdata->caps.loc[sizeof(hostdata->caps.loc) - 1] = '\0';
+
+       req->common.type = VIOSRP_CAPABILITIES_TYPE;
+       req->buffer = hostdata->caps_addr;
+
+       hostdata->caps.migration.common.cap_type = MIGRATION_CAPABILITIES;
+       hostdata->caps.migration.common.length = sizeof(hostdata->caps.migration);
+       hostdata->caps.migration.common.server_support = SERVER_SUPPORTS_CAP;
+       hostdata->caps.migration.ecl = 1;
+
+       if (client_reserve) {
+               hostdata->caps.reserve.common.cap_type = RESERVATION_CAPABILITIES;
+               hostdata->caps.reserve.common.length = sizeof(hostdata->caps.reserve);
+               hostdata->caps.reserve.common.server_support = SERVER_SUPPORTS_CAP;
+               hostdata->caps.reserve.type = CLIENT_RESERVE_SCSI_2;
+               req->common.length = sizeof(hostdata->caps);
+       } else
+               req->common.length = sizeof(hostdata->caps) - sizeof(hostdata->caps.reserve);
+
+       spin_lock_irqsave(hostdata->host->host_lock, flags);
+       if (ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2))
+               dev_err(hostdata->dev, "couldn't send CAPABILITIES_REQ!\n");
+       spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+};
+
+/**
+ * fast_fail_rsp: - Handle response to MAD enable fast fail
+ * @evt_struct:        srp_event_struct with the response
+ *
+ * Used as a "done" callback by when sending enable fast fail. Gets called
+ * by ibmvscsi_handle_crq()
+ */
+static void fast_fail_rsp(struct srp_event_struct *evt_struct)
+{
+       struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
+       u8 status = evt_struct->xfer_iu->mad.fast_fail.common.status;
+
+       if (status == VIOSRP_MAD_NOT_SUPPORTED)
+               dev_err(hostdata->dev, "fast_fail not supported in server\n");
+       else if (status == VIOSRP_MAD_FAILED)
+               dev_err(hostdata->dev, "fast_fail request failed\n");
+       else if (status != VIOSRP_MAD_SUCCESS)
+               dev_err(hostdata->dev, "error 0x%X enabling fast_fail\n", status);
+
+       send_mad_capabilities(hostdata);
+}
+
+/**
+ * init_host - Start host initialization
+ * @hostdata:  ibmvscsi_host_data of host
+ *
+ * Returns zero if successful.
+ */
+static int enable_fast_fail(struct ibmvscsi_host_data *hostdata)
+{
+       int rc;
+       unsigned long flags;
+       struct viosrp_fast_fail *fast_fail_mad;
+       struct srp_event_struct *evt_struct;
+
+       if (!fast_fail) {
+               send_mad_capabilities(hostdata);
+               return 0;
+       }
+
+       evt_struct = get_event_struct(&hostdata->pool);
+       BUG_ON(!evt_struct);
+
+       init_event_struct(evt_struct, fast_fail_rsp, VIOSRP_MAD_FORMAT, info_timeout);
+
+       fast_fail_mad = &evt_struct->iu.mad.fast_fail;
+       memset(fast_fail_mad, 0, sizeof(*fast_fail_mad));
+       fast_fail_mad->common.type = VIOSRP_ENABLE_FAST_FAIL;
+       fast_fail_mad->common.length = sizeof(*fast_fail_mad);
+
+       spin_lock_irqsave(hostdata->host->host_lock, flags);
+       rc = ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2);
+       spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+       return rc;
+}
+
+/**
+ * adapter_info_rsp: - Handle response to MAD adapter info request
+ * @evt_struct:        srp_event_struct with the response
+ *
+ * Used as a "done" callback by when sending adapter_info. Gets called
+ * by ibmvscsi_handle_crq()
+*/
+static void adapter_info_rsp(struct srp_event_struct *evt_struct)
+{
+       struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
+
+       if (evt_struct->xfer_iu->mad.adapter_info.common.status) {
+               dev_err(hostdata->dev, "error %d getting adapter info\n",
+                       evt_struct->xfer_iu->mad.adapter_info.common.status);
+       } else {
+               dev_info(hostdata->dev, "host srp version: %s, "
+                        "host partition %s (%d), OS %d, max io %u\n",
+                        hostdata->madapter_info.srp_version,
+                        hostdata->madapter_info.partition_name,
+                        hostdata->madapter_info.partition_number,
+                        hostdata->madapter_info.os_type,
+                        hostdata->madapter_info.port_max_txu[0]);
+               
+               if (hostdata->madapter_info.port_max_txu[0]) 
+                       hostdata->host->max_sectors = 
+                               hostdata->madapter_info.port_max_txu[0] >> 9;
+               
+               if (hostdata->madapter_info.os_type == 3 &&
+                   strcmp(hostdata->madapter_info.srp_version, "1.6a") <= 0) {
+                       dev_err(hostdata->dev, "host (Ver. %s) doesn't support large transfers\n",
+                               hostdata->madapter_info.srp_version);
+                       dev_err(hostdata->dev, "limiting scatterlists to %d\n",
+                               MAX_INDIRECT_BUFS);
+                       hostdata->host->sg_tablesize = MAX_INDIRECT_BUFS;
+               }
+       }
+
+       enable_fast_fail(hostdata);
+}
+
+/**
+ * send_mad_adapter_info: - Sends the mad adapter info request
+ *      and stores the result so it can be retrieved with
+ *      sysfs.  We COULD consider causing a failure if the
+ *      returned SRP version doesn't match ours.
+ * @hostdata:  ibmvscsi_host_data of host
+ * 
+ * Returns zero if successful.
+*/
+static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata)
+{
+       struct viosrp_adapter_info *req;
+       struct srp_event_struct *evt_struct;
+       unsigned long flags;
+
+       evt_struct = get_event_struct(&hostdata->pool);
+       BUG_ON(!evt_struct);
+
+       init_event_struct(evt_struct,
+                         adapter_info_rsp,
+                         VIOSRP_MAD_FORMAT,
+                         info_timeout);
+       
+       req = &evt_struct->iu.mad.adapter_info;
+       memset(req, 0x00, sizeof(*req));
+       
+       req->common.type = VIOSRP_ADAPTER_INFO_TYPE;
+       req->common.length = sizeof(hostdata->madapter_info);
+       req->buffer = hostdata->adapter_info_addr;
+
+       spin_lock_irqsave(hostdata->host->host_lock, flags);
+       if (ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2))
+               dev_err(hostdata->dev, "couldn't send ADAPTER_INFO_REQ!\n");
+       spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+};
+
+/**
+ * init_adapter: Start virtual adapter initialization sequence
+ *
+ */
+static void init_adapter(struct ibmvscsi_host_data *hostdata)
+{
+       send_mad_adapter_info(hostdata);
+}
+
 /**
  * sync_completion: Signal that a synchronous command has completed
  * Note that after returning from this call, the evt_struct is freed.
@@ -1029,7 +1206,7 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
                init_event_struct(evt,
                                  sync_completion,
                                  VIOSRP_SRP_FORMAT,
-                                 init_timeout);
+                                 abort_timeout);
 
                tsk_mgmt = &evt->iu.srp.tsk_mgmt;
        
@@ -1043,7 +1220,7 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
                evt->sync_srp = &srp_rsp;
 
                init_completion(&evt->comp);
-               rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
+               rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, abort_timeout * 2);
 
                if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY)
                        break;
@@ -1152,7 +1329,7 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
                init_event_struct(evt,
                                  sync_completion,
                                  VIOSRP_SRP_FORMAT,
-                                 init_timeout);
+                                 reset_timeout);
 
                tsk_mgmt = &evt->iu.srp.tsk_mgmt;
 
@@ -1165,7 +1342,7 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
                evt->sync_srp = &srp_rsp;
 
                init_completion(&evt->comp);
-               rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
+               rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, reset_timeout * 2);
 
                if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY)
                        break;
@@ -1281,7 +1458,7 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
                        if ((rc = ibmvscsi_ops->send_crq(hostdata,
                                                         0xC002000000000000LL, 0)) == 0) {
                                /* Now login */
-                               send_srp_login(hostdata);
+                               init_adapter(hostdata);
                        } else {
                                dev_err(hostdata->dev, "Unable to send init rsp. rc=%ld\n", rc);
                        }
@@ -1291,7 +1468,7 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
                        dev_info(hostdata->dev, "partner initialization complete\n");
 
                        /* Now login */
-                       send_srp_login(hostdata);
+                       init_adapter(hostdata);
                        break;
                default:
                        dev_err(hostdata->dev, "unknown crq message type: %d\n", crq->format);
@@ -1303,6 +1480,7 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
                if (crq->format == 0x06) {
                        /* We need to re-setup the interpartition connection */
                        dev_info(hostdata->dev, "Re-enabling adapter!\n");
+                       hostdata->client_migrated = 1;
                        purge_requests(hostdata, DID_REQUEUE);
                        if ((ibmvscsi_ops->reenable_crq_queue(&hostdata->queue,
                                                              hostdata)) ||
@@ -1397,7 +1575,7 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata,
        init_event_struct(evt_struct,
                          sync_completion,
                          VIOSRP_MAD_FORMAT,
-                         init_timeout);
+                         info_timeout);
 
        host_config = &evt_struct->iu.mad.host_config;
 
@@ -1419,7 +1597,7 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata,
 
        init_completion(&evt_struct->comp);
        spin_lock_irqsave(hostdata->host->host_lock, flags);
-       rc = ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2);
+       rc = ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2);
        spin_unlock_irqrestore(hostdata->host->host_lock, flags);
        if (rc == 0)
                wait_for_completion(&evt_struct->comp);
@@ -1444,7 +1622,7 @@ static int ibmvscsi_slave_configure(struct scsi_device *sdev)
        spin_lock_irqsave(shost->host_lock, lock_flags);
        if (sdev->type == TYPE_DISK) {
                sdev->allow_restart = 1;
-               blk_queue_rq_timeout(sdev->request_queue, 60 * HZ);
+               blk_queue_rq_timeout(sdev->request_queue, 120 * HZ);
        }
        scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun);
        spin_unlock_irqrestore(shost->host_lock, lock_flags);
@@ -1471,6 +1649,46 @@ static int ibmvscsi_change_queue_depth(struct scsi_device *sdev, int qdepth)
 /* ------------------------------------------------------------
  * sysfs attributes
  */
+static ssize_t show_host_vhost_loc(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct ibmvscsi_host_data *hostdata = shost_priv(shost);
+       int len;
+
+       len = snprintf(buf, sizeof(hostdata->caps.loc), "%s\n",
+                      hostdata->caps.loc);
+       return len;
+}
+
+static struct device_attribute ibmvscsi_host_vhost_loc = {
+       .attr = {
+                .name = "vhost_loc",
+                .mode = S_IRUGO,
+                },
+       .show = show_host_vhost_loc,
+};
+
+static ssize_t show_host_vhost_name(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct ibmvscsi_host_data *hostdata = shost_priv(shost);
+       int len;
+
+       len = snprintf(buf, sizeof(hostdata->caps.name), "%s\n",
+                      hostdata->caps.name);
+       return len;
+}
+
+static struct device_attribute ibmvscsi_host_vhost_name = {
+       .attr = {
+                .name = "vhost_name",
+                .mode = S_IRUGO,
+                },
+       .show = show_host_vhost_name,
+};
+
 static ssize_t show_host_srp_version(struct device *dev,
                                     struct device_attribute *attr, char *buf)
 {
@@ -1594,6 +1812,8 @@ static struct device_attribute ibmvscsi_host_config = {
 };
 
 static struct device_attribute *ibmvscsi_attrs[] = {
+       &ibmvscsi_host_vhost_loc,
+       &ibmvscsi_host_vhost_name,
        &ibmvscsi_host_srp_version,
        &ibmvscsi_host_partition_name,
        &ibmvscsi_host_partition_number,
@@ -1674,6 +1894,11 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        atomic_set(&hostdata->request_limit, -1);
        hostdata->host->max_sectors = IBMVSCSI_MAX_SECTORS_DEFAULT;
 
+       if (map_persist_bufs(hostdata)) {
+               dev_err(&vdev->dev, "couldn't map persistent buffers\n");
+               goto persist_bufs_failed;
+       }
+
        rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_events);
        if (rc != 0 && rc != H_RESOURCE) {
                dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc);
@@ -1687,6 +1912,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        host->max_lun = 8;
        host->max_id = max_id;
        host->max_channel = max_channel;
+       host->max_cmd_len = 16;
 
        if (scsi_add_host(hostdata->host, hostdata->dev))
                goto add_host_failed;
@@ -1733,6 +1959,8 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
       init_pool_failed:
        ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_events);
       init_crq_failed:
+       unmap_persist_bufs(hostdata);
+      persist_bufs_failed:
        scsi_host_put(host);
       scsi_host_alloc_failed:
        return -1;
@@ -1741,6 +1969,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
 static int ibmvscsi_remove(struct vio_dev *vdev)
 {
        struct ibmvscsi_host_data *hostdata = vdev->dev.driver_data;
+       unmap_persist_bufs(hostdata);
        release_event_pool(&hostdata->pool, hostdata);
        ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata,
                                        max_events);
index 2d4339d5e16e4e3c9cfed8b7b4fe30b87cb84932..76425303def0c0265b89db3ea656132cf7b756c8 100644 (file)
@@ -90,6 +90,7 @@ struct event_pool {
 /* all driver data associated with a host adapter */
 struct ibmvscsi_host_data {
        atomic_t request_limit;
+       int client_migrated;
        struct device *dev;
        struct event_pool pool;
        struct crq_queue queue;
@@ -97,6 +98,9 @@ struct ibmvscsi_host_data {
        struct list_head sent;
        struct Scsi_Host *host;
        struct mad_adapter_info_data madapter_info;
+       struct capabilities caps;
+       dma_addr_t caps_addr;
+       dma_addr_t adapter_info_addr;
 };
 
 /* routines for managing a command/response queue */
index 204604501ad8cc347a3c01bc27205fc2bf614982..2cd735d1d1962fe43eee7b65f85f1774bfd95fef 100644 (file)
@@ -37,6 +37,7 @@
 
 #define SRP_VERSION "16.a"
 #define SRP_MAX_IU_LEN 256
+#define SRP_MAX_LOC_LEN 32
 
 union srp_iu {
        struct srp_login_req login_req;
@@ -86,7 +87,37 @@ enum viosrp_mad_types {
        VIOSRP_EMPTY_IU_TYPE = 0x01,
        VIOSRP_ERROR_LOG_TYPE = 0x02,
        VIOSRP_ADAPTER_INFO_TYPE = 0x03,
-       VIOSRP_HOST_CONFIG_TYPE = 0x04
+       VIOSRP_HOST_CONFIG_TYPE = 0x04,
+       VIOSRP_CAPABILITIES_TYPE = 0x05,
+       VIOSRP_ENABLE_FAST_FAIL = 0x08,
+};
+
+enum viosrp_mad_status {
+       VIOSRP_MAD_SUCCESS = 0x00,
+       VIOSRP_MAD_NOT_SUPPORTED = 0xF1,
+       VIOSRP_MAD_FAILED = 0xF7,
+};
+
+enum viosrp_capability_type {
+       MIGRATION_CAPABILITIES = 0x01,
+       RESERVATION_CAPABILITIES = 0x02,
+};
+
+enum viosrp_capability_support {
+       SERVER_DOES_NOT_SUPPORTS_CAP = 0x0,
+       SERVER_SUPPORTS_CAP = 0x01,
+       SERVER_CAP_DATA = 0x02,
+};
+
+enum viosrp_reserve_type {
+       CLIENT_RESERVE_SCSI_2 = 0x01,
+};
+
+enum viosrp_capability_flag {
+       CLIENT_MIGRATED = 0x01,
+       CLIENT_RECONNECT = 0x02,
+       CAP_LIST_SUPPORTED = 0x04,
+       CAP_LIST_DATA = 0x08,
 };
 
 /* 
@@ -127,11 +158,46 @@ struct viosrp_host_config {
        u64 buffer;
 };
 
+struct viosrp_fast_fail {
+       struct mad_common common;
+};
+
+struct viosrp_capabilities {
+       struct mad_common common;
+       u64 buffer;
+};
+
+struct mad_capability_common {
+       u32 cap_type;
+       u16 length;
+       u16 server_support;
+};
+
+struct mad_reserve_cap {
+       struct mad_capability_common common;
+       u32 type;
+};
+
+struct mad_migration_cap {
+       struct mad_capability_common common;
+       u32 ecl;
+};
+
+struct capabilities{
+       u32 flags;
+       char name[SRP_MAX_LOC_LEN];
+       char loc[SRP_MAX_LOC_LEN];
+       struct mad_migration_cap migration;
+       struct mad_reserve_cap reserve;
+};
+
 union mad_iu {
        struct viosrp_empty_iu empty_iu;
        struct viosrp_error_log error_log;
        struct viosrp_adapter_info adapter_info;
        struct viosrp_host_config host_config;
+       struct viosrp_fast_fail fast_fail;
+       struct viosrp_capabilities capabilities;
 };
 
 union viosrp_iu {
index dd689ded8609e0709cbb0980d7356359fc6a0524..0f8bc772b1124d910ffd96bf455736152dffcd6e 100644 (file)
@@ -7003,6 +7003,7 @@ static void ipr_pci_perm_failure(struct pci_dev *pdev)
                ioa_cfg->sdt_state = ABORT_DUMP;
        ioa_cfg->reset_retries = IPR_NUM_RESET_RELOAD_RETRIES;
        ioa_cfg->in_ioa_bringdown = 1;
+       ioa_cfg->allow_cmds = 0;
        ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
        spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
 }
@@ -7688,7 +7689,7 @@ static void __ipr_remove(struct pci_dev *pdev)
  * Return value:
  *     none
  **/
-static void ipr_remove(struct pci_dev *pdev)
+static void __devexit ipr_remove(struct pci_dev *pdev)
 {
        struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
 
@@ -7864,7 +7865,7 @@ static struct pci_driver ipr_driver = {
        .name = IPR_NAME,
        .id_table = ipr_pci_table,
        .probe = ipr_probe,
-       .remove = ipr_remove,
+       .remove = __devexit_p(ipr_remove),
        .shutdown = ipr_shutdown,
        .err_handler = &ipr_err_handler,
 };
index 992af05aacf154f8ee4cbb5ea663fbb22611f5e6..7af9bceb8aa9efa467c3ca58ed4da1694ec7d79c 100644 (file)
@@ -1159,6 +1159,10 @@ static void fc_exch_recv_seq_resp(struct fc_exch_mgr *mp, struct fc_frame *fp)
                atomic_inc(&mp->stats.xid_not_found);
                goto out;
        }
+       if (ep->esb_stat & ESB_ST_COMPLETE) {
+               atomic_inc(&mp->stats.xid_not_found);
+               goto out;
+       }
        if (ep->rxid == FC_XID_UNKNOWN)
                ep->rxid = ntohs(fh->fh_rx_id);
        if (ep->sid != 0 && ep->sid != ntoh24(fh->fh_d_id)) {
index 521f996f9b131dd96c654530cfd73b06a961560c..ad8b747837b08c8922f56d4690f091d304e2321e 100644 (file)
@@ -1896,7 +1896,7 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
                sc_cmd->result = (DID_ERROR << 16) | fsp->cdb_status;
                break;
        case FC_CMD_ABORTED:
-               sc_cmd->result = (DID_ABORT << 16) | fsp->io_status;
+               sc_cmd->result = (DID_ERROR << 16) | fsp->io_status;
                break;
        case FC_CMD_TIME_OUT:
                sc_cmd->result = (DID_BUS_BUSY << 16) | fsp->io_status;
index 747d73c5c8affa7efa94bf0ad94c705ea9063394..7bfbff7e0efb256656d1ef6ce8a5e8ac68fa9c69 100644 (file)
@@ -478,7 +478,7 @@ static void fc_rport_error_retry(struct fc_rport *rport, struct fc_frame *fp)
        if (PTR_ERR(fp) == -FC_EX_CLOSED)
                return fc_rport_error(rport, fp);
 
-       if (rdata->retries < rdata->local_port->max_retry_count) {
+       if (rdata->retries < rdata->local_port->max_rport_retry_count) {
                FC_DEBUG_RPORT("Error %ld in state %s, retrying\n",
                               PTR_ERR(fp), fc_rport_state(rport));
                rdata->retries++;
@@ -1330,7 +1330,7 @@ int fc_rport_init(struct fc_lport *lport)
 }
 EXPORT_SYMBOL(fc_rport_init);
 
-int fc_setup_rport()
+int fc_setup_rport(void)
 {
        rport_event_queue = create_singlethread_workqueue("fc_rport_eq");
        if (!rport_event_queue)
@@ -1339,7 +1339,7 @@ int fc_setup_rport()
 }
 EXPORT_SYMBOL(fc_setup_rport);
 
-void fc_destroy_rport()
+void fc_destroy_rport(void)
 {
        destroy_workqueue(rport_event_queue);
 }
index e72b4ad47d35bd6ff3855ec038eed77b15c1719d..59908aead531e6257ad63f1767cf736c82585956 100644 (file)
@@ -81,7 +81,8 @@ inline void iscsi_conn_queue_work(struct iscsi_conn *conn)
        struct Scsi_Host *shost = conn->session->host;
        struct iscsi_host *ihost = shost_priv(shost);
 
-       queue_work(ihost->workq, &conn->xmitwork);
+       if (ihost->workq)
+               queue_work(ihost->workq, &conn->xmitwork);
 }
 EXPORT_SYMBOL_GPL(iscsi_conn_queue_work);
 
@@ -109,11 +110,9 @@ iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
                 * if the window closed with IO queued, then kick the
                 * xmit thread
                 */
-               if (!list_empty(&session->leadconn->xmitqueue) ||
-                   !list_empty(&session->leadconn->mgmtqueue)) {
-                       if (!(session->tt->caps & CAP_DATA_PATH_OFFLOAD))
-                               iscsi_conn_queue_work(session->leadconn);
-               }
+               if (!list_empty(&session->leadconn->cmdqueue) ||
+                   !list_empty(&session->leadconn->mgmtqueue))
+                       iscsi_conn_queue_work(session->leadconn);
        }
 }
 EXPORT_SYMBOL_GPL(iscsi_update_cmdsn);
@@ -257,9 +256,11 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
        itt_t itt;
        int rc;
 
-       rc = conn->session->tt->alloc_pdu(task, ISCSI_OP_SCSI_CMD);
-       if (rc)
-               return rc;
+       if (conn->session->tt->alloc_pdu) {
+               rc = conn->session->tt->alloc_pdu(task, ISCSI_OP_SCSI_CMD);
+               if (rc)
+                       return rc;
+       }
        hdr = (struct iscsi_cmd *) task->hdr;
        itt = hdr->itt;
        memset(hdr, 0, sizeof(*hdr));
@@ -364,7 +365,6 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
                return -EIO;
 
        task->state = ISCSI_TASK_RUNNING;
-       list_move_tail(&task->running, &conn->run_list);
 
        conn->scsicmd_pdus_cnt++;
        ISCSI_DBG_SESSION(session, "iscsi prep [%s cid %d sc %p cdb 0x%x "
@@ -380,26 +380,25 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
 }
 
 /**
- * iscsi_complete_command - finish a task
+ * iscsi_free_task - free a task
  * @task: iscsi cmd task
  *
  * Must be called with session lock.
  * This function returns the scsi command to scsi-ml or cleans
  * up mgmt tasks then returns the task to the pool.
  */
-static void iscsi_complete_command(struct iscsi_task *task)
+static void iscsi_free_task(struct iscsi_task *task)
 {
        struct iscsi_conn *conn = task->conn;
        struct iscsi_session *session = conn->session;
        struct scsi_cmnd *sc = task->sc;
 
+       ISCSI_DBG_SESSION(session, "freeing task itt 0x%x state %d sc %p\n",
+                         task->itt, task->state, task->sc);
+
        session->tt->cleanup_task(task);
-       list_del_init(&task->running);
-       task->state = ISCSI_TASK_COMPLETED;
+       task->state = ISCSI_TASK_FREE;
        task->sc = NULL;
-
-       if (conn->task == task)
-               conn->task = NULL;
        /*
         * login task is preallocated so do not free
         */
@@ -408,9 +407,6 @@ static void iscsi_complete_command(struct iscsi_task *task)
 
        __kfifo_put(session->cmdpool.queue, (void*)&task, sizeof(void*));
 
-       if (conn->ping_task == task)
-               conn->ping_task = NULL;
-
        if (sc) {
                task->sc = NULL;
                /* SCSI eh reuses commands to verify us */
@@ -433,7 +429,7 @@ EXPORT_SYMBOL_GPL(__iscsi_get_task);
 static void __iscsi_put_task(struct iscsi_task *task)
 {
        if (atomic_dec_and_test(&task->refcount))
-               iscsi_complete_command(task);
+               iscsi_free_task(task);
 }
 
 void iscsi_put_task(struct iscsi_task *task)
@@ -446,26 +442,74 @@ void iscsi_put_task(struct iscsi_task *task)
 }
 EXPORT_SYMBOL_GPL(iscsi_put_task);
 
+/**
+ * iscsi_complete_task - finish a task
+ * @task: iscsi cmd task
+ * @state: state to complete task with
+ *
+ * Must be called with session lock.
+ */
+static void iscsi_complete_task(struct iscsi_task *task, int state)
+{
+       struct iscsi_conn *conn = task->conn;
+
+       ISCSI_DBG_SESSION(conn->session,
+                         "complete task itt 0x%x state %d sc %p\n",
+                         task->itt, task->state, task->sc);
+       if (task->state == ISCSI_TASK_COMPLETED ||
+           task->state == ISCSI_TASK_ABRT_TMF ||
+           task->state == ISCSI_TASK_ABRT_SESS_RECOV)
+               return;
+       WARN_ON_ONCE(task->state == ISCSI_TASK_FREE);
+       task->state = state;
+
+       if (!list_empty(&task->running))
+               list_del_init(&task->running);
+
+       if (conn->task == task)
+               conn->task = NULL;
+
+       if (conn->ping_task == task)
+               conn->ping_task = NULL;
+
+       /* release get from queueing */
+       __iscsi_put_task(task);
+}
+
 /*
- * session lock must be held
+ * session lock must be held and if not called for a task that is
+ * still pending or from the xmit thread, then xmit thread must
+ * be suspended.
  */
-static void fail_command(struct iscsi_conn *conn, struct iscsi_task *task,
-                        int err)
+static void fail_scsi_task(struct iscsi_task *task, int err)
 {
+       struct iscsi_conn *conn = task->conn;
        struct scsi_cmnd *sc;
+       int state;
 
+       /*
+        * if a command completes and we get a successful tmf response
+        * we will hit this because the scsi eh abort code does not take
+        * a ref to the task.
+        */
        sc = task->sc;
        if (!sc)
                return;
 
-       if (task->state == ISCSI_TASK_PENDING)
+       if (task->state == ISCSI_TASK_PENDING) {
                /*
                 * cmd never made it to the xmit thread, so we should not count
                 * the cmd in the sequencing
                 */
                conn->session->queued_cmdsn--;
+               /* it was never sent so just complete like normal */
+               state = ISCSI_TASK_COMPLETED;
+       } else if (err == DID_TRANSPORT_DISRUPTED)
+               state = ISCSI_TASK_ABRT_SESS_RECOV;
+       else
+               state = ISCSI_TASK_ABRT_TMF;
 
-       sc->result = err;
+       sc->result = err << 16;
        if (!scsi_bidi_cmnd(sc))
                scsi_set_resid(sc, scsi_bufflen(sc));
        else {
@@ -473,10 +517,7 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_task *task,
                scsi_in(sc)->resid = scsi_in(sc)->length;
        }
 
-       if (conn->task == task)
-               conn->task = NULL;
-       /* release ref from queuecommand */
-       __iscsi_put_task(task);
+       iscsi_complete_task(task, state);
 }
 
 static int iscsi_prep_mgmt_task(struct iscsi_conn *conn,
@@ -516,7 +557,6 @@ static int iscsi_prep_mgmt_task(struct iscsi_conn *conn,
                session->state = ISCSI_STATE_LOGGING_OUT;
 
        task->state = ISCSI_TASK_RUNNING;
-       list_move_tail(&task->running, &conn->mgmt_run_list);
        ISCSI_DBG_SESSION(session, "mgmtpdu [op 0x%x hdr->itt 0x%x "
                          "datalen %d]\n", hdr->opcode & ISCSI_OPCODE_MASK,
                          hdr->itt, task->data_count);
@@ -528,6 +568,7 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
                      char *data, uint32_t data_size)
 {
        struct iscsi_session *session = conn->session;
+       struct iscsi_host *ihost = shost_priv(session->host);
        struct iscsi_task *task;
        itt_t itt;
 
@@ -544,6 +585,9 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
                 */
                task = conn->login_task;
        else {
+               if (session->state != ISCSI_STATE_LOGGED_IN)
+                       return NULL;
+
                BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
                BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
 
@@ -559,6 +603,8 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
        atomic_set(&task->refcount, 1);
        task->conn = conn;
        task->sc = NULL;
+       INIT_LIST_HEAD(&task->running);
+       task->state = ISCSI_TASK_PENDING;
 
        if (data_size) {
                memcpy(task->data, data, data_size);
@@ -566,11 +612,14 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
        } else
                task->data_count = 0;
 
-       if (conn->session->tt->alloc_pdu(task, hdr->opcode)) {
-               iscsi_conn_printk(KERN_ERR, conn, "Could not allocate "
-                                "pdu for mgmt task.\n");
-               goto requeue_task;
+       if (conn->session->tt->alloc_pdu) {
+               if (conn->session->tt->alloc_pdu(task, hdr->opcode)) {
+                       iscsi_conn_printk(KERN_ERR, conn, "Could not allocate "
+                                        "pdu for mgmt task.\n");
+                       goto free_task;
+               }
        }
+
        itt = task->hdr->itt;
        task->hdr_len = sizeof(struct iscsi_hdr);
        memcpy(task->hdr, hdr, sizeof(struct iscsi_hdr));
@@ -583,30 +632,22 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
                                                   task->conn->session->age);
        }
 
-       INIT_LIST_HEAD(&task->running);
-       list_add_tail(&task->running, &conn->mgmtqueue);
-
-       if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) {
+       if (!ihost->workq) {
                if (iscsi_prep_mgmt_task(conn, task))
                        goto free_task;
 
                if (session->tt->xmit_task(task))
                        goto free_task;
-
-       } else
+       } else {
+               list_add_tail(&task->running, &conn->mgmtqueue);
                iscsi_conn_queue_work(conn);
+       }
 
        return task;
 
 free_task:
        __iscsi_put_task(task);
        return NULL;
-
-requeue_task:
-       if (task != conn->login_task)
-               __kfifo_put(session->cmdpool.queue, (void*)&task,
-                           sizeof(void*));
-       return NULL;
 }
 
 int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
@@ -701,11 +742,10 @@ invalid_datalen:
                        sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
        }
 out:
-       ISCSI_DBG_SESSION(session, "done [sc %p res %d itt 0x%x]\n",
+       ISCSI_DBG_SESSION(session, "cmd rsp done [sc %p res %d itt 0x%x]\n",
                          sc, sc->result, task->itt);
        conn->scsirsp_pdus_cnt++;
-
-       __iscsi_put_task(task);
+       iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
 }
 
 /**
@@ -724,6 +764,7 @@ iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
        if (!(rhdr->flags & ISCSI_FLAG_DATA_STATUS))
                return;
 
+       iscsi_update_cmdsn(conn->session, (struct iscsi_nopin *)hdr);
        sc->result = (DID_OK << 16) | rhdr->cmd_status;
        conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
        if (rhdr->flags & (ISCSI_FLAG_DATA_UNDERFLOW |
@@ -738,8 +779,11 @@ iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
                        sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
        }
 
+       ISCSI_DBG_SESSION(conn->session, "data in with status done "
+                         "[sc %p res %d itt 0x%x]\n",
+                         sc, sc->result, task->itt);
        conn->scsirsp_pdus_cnt++;
-       __iscsi_put_task(task);
+       iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
 }
 
 static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
@@ -823,7 +867,7 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
  *
  * The session lock must be held.
  */
-static struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
+struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
 {
        struct iscsi_session *session = conn->session;
        int i;
@@ -840,6 +884,7 @@ static struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
 
        return session->cmds[i];
 }
+EXPORT_SYMBOL_GPL(iscsi_itt_to_task);
 
 /**
  * __iscsi_complete_pdu - complete pdu
@@ -959,7 +1004,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
                }
 
                iscsi_tmf_rsp(conn, hdr);
-               __iscsi_put_task(task);
+               iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
                break;
        case ISCSI_OP_NOOP_IN:
                iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
@@ -977,7 +1022,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
                        goto recv_pdu;
 
                mod_timer(&conn->transport_timer, jiffies + conn->recv_timeout);
-               __iscsi_put_task(task);
+               iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
                break;
        default:
                rc = ISCSI_ERR_BAD_OPCODE;
@@ -989,7 +1034,7 @@ out:
 recv_pdu:
        if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
                rc = ISCSI_ERR_CONN_FAILED;
-       __iscsi_put_task(task);
+       iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
        return rc;
 }
 EXPORT_SYMBOL_GPL(__iscsi_complete_pdu);
@@ -1166,7 +1211,12 @@ void iscsi_requeue_task(struct iscsi_task *task)
 {
        struct iscsi_conn *conn = task->conn;
 
-       list_move_tail(&task->running, &conn->requeue);
+       /*
+        * this may be on the requeue list already if the xmit_task callout
+        * is handling the r2ts while we are adding new ones
+        */
+       if (list_empty(&task->running))
+               list_add_tail(&task->running, &conn->requeue);
        iscsi_conn_queue_work(conn);
 }
 EXPORT_SYMBOL_GPL(iscsi_requeue_task);
@@ -1206,6 +1256,7 @@ check_mgmt:
        while (!list_empty(&conn->mgmtqueue)) {
                conn->task = list_entry(conn->mgmtqueue.next,
                                         struct iscsi_task, running);
+               list_del_init(&conn->task->running);
                if (iscsi_prep_mgmt_task(conn, conn->task)) {
                        __iscsi_put_task(conn->task);
                        conn->task = NULL;
@@ -1217,23 +1268,26 @@ check_mgmt:
        }
 
        /* process pending command queue */
-       while (!list_empty(&conn->xmitqueue)) {
+       while (!list_empty(&conn->cmdqueue)) {
                if (conn->tmf_state == TMF_QUEUED)
                        break;
 
-               conn->task = list_entry(conn->xmitqueue.next,
+               conn->task = list_entry(conn->cmdqueue.next,
                                         struct iscsi_task, running);
+               list_del_init(&conn->task->running);
                if (conn->session->state == ISCSI_STATE_LOGGING_OUT) {
-                       fail_command(conn, conn->task, DID_IMM_RETRY << 16);
+                       fail_scsi_task(conn->task, DID_IMM_RETRY);
                        continue;
                }
                rc = iscsi_prep_scsi_cmd_pdu(conn->task);
                if (rc) {
                        if (rc == -ENOMEM) {
+                               list_add_tail(&conn->task->running,
+                                             &conn->cmdqueue);
                                conn->task = NULL;
                                goto again;
                        } else
-                               fail_command(conn, conn->task, DID_ABORT << 16);
+                               fail_scsi_task(conn->task, DID_ABORT);
                        continue;
                }
                rc = iscsi_xmit_task(conn);
@@ -1260,8 +1314,8 @@ check_mgmt:
 
                conn->task = list_entry(conn->requeue.next,
                                         struct iscsi_task, running);
+               list_del_init(&conn->task->running);
                conn->task->state = ISCSI_TASK_RUNNING;
-               list_move_tail(conn->requeue.next, &conn->run_list);
                rc = iscsi_xmit_task(conn);
                if (rc)
                        goto again;
@@ -1328,6 +1382,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
 {
        struct iscsi_cls_session *cls_session;
        struct Scsi_Host *host;
+       struct iscsi_host *ihost;
        int reason = 0;
        struct iscsi_session *session;
        struct iscsi_conn *conn;
@@ -1338,6 +1393,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
        sc->SCp.ptr = NULL;
 
        host = sc->device->host;
+       ihost = shost_priv(host);
        spin_unlock(host->host_lock);
 
        cls_session = starget_to_session(scsi_target(sc->device));
@@ -1350,13 +1406,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
                goto fault;
        }
 
-       /*
-        * ISCSI_STATE_FAILED is a temp. state. The recovery
-        * code will decide what is best to do with command queued
-        * during this time
-        */
-       if (session->state != ISCSI_STATE_LOGGED_IN &&
-           session->state != ISCSI_STATE_FAILED) {
+       if (session->state != ISCSI_STATE_LOGGED_IN) {
                /*
                 * to handle the race between when we set the recovery state
                 * and block the session we requeue here (commands could
@@ -1364,12 +1414,15 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
                 * up because the block code is not locked)
                 */
                switch (session->state) {
+               case ISCSI_STATE_FAILED:
                case ISCSI_STATE_IN_RECOVERY:
                        reason = FAILURE_SESSION_IN_RECOVERY;
-                       goto reject;
+                       sc->result = DID_IMM_RETRY << 16;
+                       break;
                case ISCSI_STATE_LOGGING_OUT:
                        reason = FAILURE_SESSION_LOGGING_OUT;
-                       goto reject;
+                       sc->result = DID_IMM_RETRY << 16;
+                       break;
                case ISCSI_STATE_RECOVERY_FAILED:
                        reason = FAILURE_SESSION_RECOVERY_TIMEOUT;
                        sc->result = DID_TRANSPORT_FAILFAST << 16;
@@ -1402,9 +1455,8 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
                reason = FAILURE_OOM;
                goto reject;
        }
-       list_add_tail(&task->running, &conn->xmitqueue);
 
-       if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) {
+       if (!ihost->workq) {
                reason = iscsi_prep_scsi_cmd_pdu(task);
                if (reason) {
                        if (reason == -ENOMEM) {
@@ -1419,8 +1471,10 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
                        reason = FAILURE_SESSION_NOT_READY;
                        goto prepd_reject;
                }
-       } else
+       } else {
+               list_add_tail(&task->running, &conn->cmdqueue);
                iscsi_conn_queue_work(conn);
+       }
 
        session->queued_cmdsn++;
        spin_unlock(&session->lock);
@@ -1429,7 +1483,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
 
 prepd_reject:
        sc->scsi_done = NULL;
-       iscsi_complete_command(task);
+       iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
 reject:
        spin_unlock(&session->lock);
        ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n",
@@ -1439,7 +1493,7 @@ reject:
 
 prepd_fault:
        sc->scsi_done = NULL;
-       iscsi_complete_command(task);
+       iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
 fault:
        spin_unlock(&session->lock);
        ISCSI_DBG_SESSION(session, "iscsi: cmd 0x%x is not queued (%d)\n",
@@ -1608,44 +1662,24 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
  * Fail commands. session lock held and recv side suspended and xmit
  * thread flushed
  */
-static void fail_all_commands(struct iscsi_conn *conn, unsigned lun,
-                             int error)
+static void fail_scsi_tasks(struct iscsi_conn *conn, unsigned lun,
+                           int error)
 {
-       struct iscsi_task *task, *tmp;
-
-       if (conn->task) {
-               if (lun == -1 ||
-                   (conn->task->sc && conn->task->sc->device->lun == lun))
-                       conn->task = NULL;
-       }
+       struct iscsi_task *task;
+       int i;
 
-       /* flush pending */
-       list_for_each_entry_safe(task, tmp, &conn->xmitqueue, running) {
-               if (lun == task->sc->device->lun || lun == -1) {
-                       ISCSI_DBG_SESSION(conn->session,
-                                         "failing pending sc %p itt 0x%x\n",
-                                         task->sc, task->itt);
-                       fail_command(conn, task, error << 16);
-               }
-       }
+       for (i = 0; i < conn->session->cmds_max; i++) {
+               task = conn->session->cmds[i];
+               if (!task->sc || task->state == ISCSI_TASK_FREE)
+                       continue;
 
-       list_for_each_entry_safe(task, tmp, &conn->requeue, running) {
-               if (lun == task->sc->device->lun || lun == -1) {
-                       ISCSI_DBG_SESSION(conn->session,
-                                         "failing requeued sc %p itt 0x%x\n",
-                                         task->sc, task->itt);
-                       fail_command(conn, task, error << 16);
-               }
-       }
+               if (lun != -1 && lun != task->sc->device->lun)
+                       continue;
 
-       /* fail all other running */
-       list_for_each_entry_safe(task, tmp, &conn->run_list, running) {
-               if (lun == task->sc->device->lun || lun == -1) {
-                       ISCSI_DBG_SESSION(conn->session,
-                                        "failing in progress sc %p itt 0x%x\n",
-                                        task->sc, task->itt);
-                       fail_command(conn, task, error << 16);
-               }
+               ISCSI_DBG_SESSION(conn->session,
+                                 "failing sc %p itt 0x%x state %d\n",
+                                 task->sc, task->itt, task->state);
+               fail_scsi_task(task, error);
        }
 }
 
@@ -1655,7 +1689,7 @@ void iscsi_suspend_tx(struct iscsi_conn *conn)
        struct iscsi_host *ihost = shost_priv(shost);
 
        set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
-       if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD))
+       if (ihost->workq)
                flush_workqueue(ihost->workq);
 }
 EXPORT_SYMBOL_GPL(iscsi_suspend_tx);
@@ -1663,8 +1697,23 @@ EXPORT_SYMBOL_GPL(iscsi_suspend_tx);
 static void iscsi_start_tx(struct iscsi_conn *conn)
 {
        clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
-       if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD))
-               iscsi_conn_queue_work(conn);
+       iscsi_conn_queue_work(conn);
+}
+
+/*
+ * We want to make sure a ping is in flight. It has timed out.
+ * And we are not busy processing a pdu that is making
+ * progress but got started before the ping and is taking a while
+ * to complete so the ping is just stuck behind it in a queue.
+ */
+static int iscsi_has_ping_timed_out(struct iscsi_conn *conn)
+{
+       if (conn->ping_task &&
+           time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) +
+                          (conn->ping_timeout * HZ), jiffies))
+               return 1;
+       else
+               return 0;
 }
 
 static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
@@ -1702,16 +1751,20 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
         * if the ping timedout then we are in the middle of cleaning up
         * and can let the iscsi eh handle it
         */
-       if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) +
-                           (conn->ping_timeout * HZ), jiffies))
+       if (iscsi_has_ping_timed_out(conn)) {
                rc = BLK_EH_RESET_TIMER;
+               goto done;
+       }
        /*
         * if we are about to check the transport then give the command
         * more time
         */
        if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ),
-                          jiffies))
+                          jiffies)) {
                rc = BLK_EH_RESET_TIMER;
+               goto done;
+       }
+
        /* if in the middle of checking the transport then give us more time */
        if (conn->ping_task)
                rc = BLK_EH_RESET_TIMER;
@@ -1738,13 +1791,13 @@ static void iscsi_check_transport_timeouts(unsigned long data)
 
        recv_timeout *= HZ;
        last_recv = conn->last_recv;
-       if (conn->ping_task &&
-           time_before_eq(conn->last_ping + (conn->ping_timeout * HZ),
-                          jiffies)) {
+
+       if (iscsi_has_ping_timed_out(conn)) {
                iscsi_conn_printk(KERN_ERR, conn, "ping timeout of %d secs "
-                                 "expired, last rx %lu, last ping %lu, "
-                                 "now %lu\n", conn->ping_timeout, last_recv,
-                                 conn->last_ping, jiffies);
+                                 "expired, recv timeout %d, last rx %lu, "
+                                 "last ping %lu, now %lu\n",
+                                 conn->ping_timeout, conn->recv_timeout,
+                                 last_recv, conn->last_ping, jiffies);
                spin_unlock(&session->lock);
                iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
                return;
@@ -1788,6 +1841,8 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
        cls_session = starget_to_session(scsi_target(sc->device));
        session = cls_session->dd_data;
 
+       ISCSI_DBG_SESSION(session, "aborting sc %p\n", sc);
+
        mutex_lock(&session->eh_mutex);
        spin_lock_bh(&session->lock);
        /*
@@ -1810,6 +1865,8 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
            sc->SCp.phase != session->age) {
                spin_unlock_bh(&session->lock);
                mutex_unlock(&session->eh_mutex);
+               ISCSI_DBG_SESSION(session, "failing abort due to dropped "
+                                 "session.\n");
                return FAILED;
        }
 
@@ -1829,7 +1886,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
        }
 
        if (task->state == ISCSI_TASK_PENDING) {
-               fail_command(conn, task, DID_ABORT << 16);
+               fail_scsi_task(task, DID_ABORT);
                goto success;
        }
 
@@ -1860,7 +1917,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
                 * then sent more data for the cmd.
                 */
                spin_lock(&session->lock);
-               fail_command(conn, task, DID_ABORT << 16);
+               fail_scsi_task(task, DID_ABORT);
                conn->tmf_state = TMF_INITIAL;
                spin_unlock(&session->lock);
                iscsi_start_tx(conn);
@@ -1967,7 +2024,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
        iscsi_suspend_tx(conn);
 
        spin_lock_bh(&session->lock);
-       fail_all_commands(conn, sc->device->lun, DID_ERROR);
+       fail_scsi_tasks(conn, sc->device->lun, DID_ERROR);
        conn->tmf_state = TMF_INITIAL;
        spin_unlock_bh(&session->lock);
 
@@ -2274,6 +2331,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
                if (cmd_task_size)
                        task->dd_data = &task[1];
                task->itt = cmd_i;
+               task->state = ISCSI_TASK_FREE;
                INIT_LIST_HEAD(&task->running);
        }
 
@@ -2360,10 +2418,8 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
        conn->transport_timer.data = (unsigned long)conn;
        conn->transport_timer.function = iscsi_check_transport_timeouts;
 
-       INIT_LIST_HEAD(&conn->run_list);
-       INIT_LIST_HEAD(&conn->mgmt_run_list);
        INIT_LIST_HEAD(&conn->mgmtqueue);
-       INIT_LIST_HEAD(&conn->xmitqueue);
+       INIT_LIST_HEAD(&conn->cmdqueue);
        INIT_LIST_HEAD(&conn->requeue);
        INIT_WORK(&conn->xmitwork, iscsi_xmitworker);
 
@@ -2531,27 +2587,28 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
 EXPORT_SYMBOL_GPL(iscsi_conn_start);
 
 static void
-flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn)
+fail_mgmt_tasks(struct iscsi_session *session, struct iscsi_conn *conn)
 {
-       struct iscsi_task *task, *tmp;
+       struct iscsi_task *task;
+       int i, state;
 
-       /* handle pending */
-       list_for_each_entry_safe(task, tmp, &conn->mgmtqueue, running) {
-               ISCSI_DBG_SESSION(session, "flushing pending mgmt task "
-                                 "itt 0x%x\n", task->itt);
-               /* release ref from prep task */
-               __iscsi_put_task(task);
-       }
+       for (i = 0; i < conn->session->cmds_max; i++) {
+               task = conn->session->cmds[i];
+               if (task->sc)
+                       continue;
 
-       /* handle running */
-       list_for_each_entry_safe(task, tmp, &conn->mgmt_run_list, running) {
-               ISCSI_DBG_SESSION(session, "flushing running mgmt task "
-                                 "itt 0x%x\n", task->itt);
-               /* release ref from prep task */
-               __iscsi_put_task(task);
-       }
+               if (task->state == ISCSI_TASK_FREE)
+                       continue;
+
+               ISCSI_DBG_SESSION(conn->session,
+                                 "failing mgmt itt 0x%x state %d\n",
+                                 task->itt, task->state);
+               state = ISCSI_TASK_ABRT_SESS_RECOV;
+               if (task->state == ISCSI_TASK_PENDING)
+                       state = ISCSI_TASK_COMPLETED;
+               iscsi_complete_task(task, state);
 
-       conn->task = NULL;
+       }
 }
 
 static void iscsi_start_session_recovery(struct iscsi_session *session,
@@ -2559,8 +2616,6 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
 {
        int old_stop_stage;
 
-       del_timer_sync(&conn->transport_timer);
-
        mutex_lock(&session->eh_mutex);
        spin_lock_bh(&session->lock);
        if (conn->stop_stage == STOP_CONN_TERM) {
@@ -2578,13 +2633,17 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
                session->state = ISCSI_STATE_TERMINATE;
        else if (conn->stop_stage != STOP_CONN_RECOVER)
                session->state = ISCSI_STATE_IN_RECOVERY;
+       spin_unlock_bh(&session->lock);
+
+       del_timer_sync(&conn->transport_timer);
+       iscsi_suspend_tx(conn);
 
+       spin_lock_bh(&session->lock);
        old_stop_stage = conn->stop_stage;
        conn->stop_stage = flag;
        conn->c_stage = ISCSI_CONN_STOPPED;
        spin_unlock_bh(&session->lock);
 
-       iscsi_suspend_tx(conn);
        /*
         * for connection level recovery we should not calculate
         * header digest. conn->hdr_size used for optimization
@@ -2605,11 +2664,8 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
         * flush queues.
         */
        spin_lock_bh(&session->lock);
-       if (flag == STOP_CONN_RECOVER)
-               fail_all_commands(conn, -1, DID_TRANSPORT_DISRUPTED);
-       else
-               fail_all_commands(conn, -1, DID_ERROR);
-       flush_control_queues(session, conn);
+       fail_scsi_tasks(conn, -1, DID_TRANSPORT_DISRUPTED);
+       fail_mgmt_tasks(session, conn);
        spin_unlock_bh(&session->lock);
        mutex_unlock(&session->eh_mutex);
 }
@@ -2651,6 +2707,23 @@ int iscsi_conn_bind(struct iscsi_cls_session *cls_session,
 }
 EXPORT_SYMBOL_GPL(iscsi_conn_bind);
 
+static int iscsi_switch_str_param(char **param, char *new_val_buf)
+{
+       char *new_val;
+
+       if (*param) {
+               if (!strcmp(*param, new_val_buf))
+                       return 0;
+       }
+
+       new_val = kstrdup(new_val_buf, GFP_NOIO);
+       if (!new_val)
+               return -ENOMEM;
+
+       kfree(*param);
+       *param = new_val;
+       return 0;
+}
 
 int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
                    enum iscsi_param param, char *buf, int buflen)
@@ -2723,38 +2796,15 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
                sscanf(buf, "%u", &conn->exp_statsn);
                break;
        case ISCSI_PARAM_USERNAME:
-               kfree(session->username);
-               session->username = kstrdup(buf, GFP_KERNEL);
-               if (!session->username)
-                       return -ENOMEM;
-               break;
+               return iscsi_switch_str_param(&session->username, buf);
        case ISCSI_PARAM_USERNAME_IN:
-               kfree(session->username_in);
-               session->username_in = kstrdup(buf, GFP_KERNEL);
-               if (!session->username_in)
-                       return -ENOMEM;
-               break;
+               return iscsi_switch_str_param(&session->username_in, buf);
        case ISCSI_PARAM_PASSWORD:
-               kfree(session->password);
-               session->password = kstrdup(buf, GFP_KERNEL);
-               if (!session->password)
-                       return -ENOMEM;
-               break;
+               return iscsi_switch_str_param(&session->password, buf);
        case ISCSI_PARAM_PASSWORD_IN:
-               kfree(session->password_in);
-               session->password_in = kstrdup(buf, GFP_KERNEL);
-               if (!session->password_in)
-                       return -ENOMEM;
-               break;
+               return iscsi_switch_str_param(&session->password_in, buf);
        case ISCSI_PARAM_TARGET_NAME:
-               /* this should not change between logins */
-               if (session->targetname)
-                       break;
-
-               session->targetname = kstrdup(buf, GFP_KERNEL);
-               if (!session->targetname)
-                       return -ENOMEM;
-               break;
+               return iscsi_switch_str_param(&session->targetname, buf);
        case ISCSI_PARAM_TPGT:
                sscanf(buf, "%d", &session->tpgt);
                break;
@@ -2762,25 +2812,11 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
                sscanf(buf, "%d", &conn->persistent_port);
                break;
        case ISCSI_PARAM_PERSISTENT_ADDRESS:
-               /*
-                * this is the address returned in discovery so it should
-                * not change between logins.
-                */
-               if (conn->persistent_address)
-                       break;
-
-               conn->persistent_address = kstrdup(buf, GFP_KERNEL);
-               if (!conn->persistent_address)
-                       return -ENOMEM;
-               break;
+               return iscsi_switch_str_param(&conn->persistent_address, buf);
        case ISCSI_PARAM_IFACE_NAME:
-               if (!session->ifacename)
-                       session->ifacename = kstrdup(buf, GFP_KERNEL);
-               break;
+               return iscsi_switch_str_param(&session->ifacename, buf);
        case ISCSI_PARAM_INITIATOR_NAME:
-               if (!session->initiatorname)
-                       session->initiatorname = kstrdup(buf, GFP_KERNEL);
-               break;
+               return iscsi_switch_str_param(&session->initiatorname, buf);
        default:
                return -ENOSYS;
        }
@@ -2851,10 +2887,7 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
                len = sprintf(buf, "%s\n", session->ifacename);
                break;
        case ISCSI_PARAM_INITIATOR_NAME:
-               if (!session->initiatorname)
-                       len = sprintf(buf, "%s\n", "unknown");
-               else
-                       len = sprintf(buf, "%s\n", session->initiatorname);
+               len = sprintf(buf, "%s\n", session->initiatorname);
                break;
        default:
                return -ENOSYS;
@@ -2920,29 +2953,16 @@ int iscsi_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param,
 
        switch (param) {
        case ISCSI_HOST_PARAM_NETDEV_NAME:
-               if (!ihost->netdev)
-                       len = sprintf(buf, "%s\n", "default");
-               else
-                       len = sprintf(buf, "%s\n", ihost->netdev);
+               len = sprintf(buf, "%s\n", ihost->netdev);
                break;
        case ISCSI_HOST_PARAM_HWADDRESS:
-               if (!ihost->hwaddress)
-                       len = sprintf(buf, "%s\n", "default");
-               else
-                       len = sprintf(buf, "%s\n", ihost->hwaddress);
+               len = sprintf(buf, "%s\n", ihost->hwaddress);
                break;
        case ISCSI_HOST_PARAM_INITIATOR_NAME:
-               if (!ihost->initiatorname)
-                       len = sprintf(buf, "%s\n", "unknown");
-               else
-                       len = sprintf(buf, "%s\n", ihost->initiatorname);
+               len = sprintf(buf, "%s\n", ihost->initiatorname);
                break;
        case ISCSI_HOST_PARAM_IPADDRESS:
-               if (!strlen(ihost->local_address))
-                       len = sprintf(buf, "%s\n", "unknown");
-               else
-                       len = sprintf(buf, "%s\n",
-                                     ihost->local_address);
+               len = sprintf(buf, "%s\n", ihost->local_address);
                break;
        default:
                return -ENOSYS;
@@ -2959,17 +2979,11 @@ int iscsi_host_set_param(struct Scsi_Host *shost, enum iscsi_host_param param,
 
        switch (param) {
        case ISCSI_HOST_PARAM_NETDEV_NAME:
-               if (!ihost->netdev)
-                       ihost->netdev = kstrdup(buf, GFP_KERNEL);
-               break;
+               return iscsi_switch_str_param(&ihost->netdev, buf);
        case ISCSI_HOST_PARAM_HWADDRESS:
-               if (!ihost->hwaddress)
-                       ihost->hwaddress = kstrdup(buf, GFP_KERNEL);
-               break;
+               return iscsi_switch_str_param(&ihost->hwaddress, buf);
        case ISCSI_HOST_PARAM_INITIATOR_NAME:
-               if (!ihost->initiatorname)
-                       ihost->initiatorname = kstrdup(buf, GFP_KERNEL);
-               break;
+               return iscsi_switch_str_param(&ihost->initiatorname, buf);
        default:
                return -ENOSYS;
        }
index b579ca9f4836a9c976b2c76856e1d0709650e1e4..2bc07090321da30562b3b21ef6c2b6b8dc51e887 100644 (file)
@@ -440,8 +440,8 @@ void iscsi_tcp_cleanup_task(struct iscsi_task *task)
        struct iscsi_tcp_task *tcp_task = task->dd_data;
        struct iscsi_r2t_info *r2t;
 
-       /* nothing to do for mgmt or pending tasks */
-       if (!task->sc || task->state == ISCSI_TASK_PENDING)
+       /* nothing to do for mgmt */
+       if (!task->sc)
                return;
 
        /* flush task's r2t queues */
@@ -473,7 +473,13 @@ static int iscsi_tcp_data_in(struct iscsi_conn *conn, struct iscsi_task *task)
        int datasn = be32_to_cpu(rhdr->datasn);
        unsigned total_in_length = scsi_in(task->sc)->length;
 
-       iscsi_update_cmdsn(conn->session, (struct iscsi_nopin*)rhdr);
+       /*
+        * lib iscsi will update this in the completion handling if there
+        * is status.
+        */
+       if (!(rhdr->flags & ISCSI_FLAG_DATA_STATUS))
+               iscsi_update_cmdsn(conn->session, (struct iscsi_nopin*)rhdr);
+
        if (tcp_conn->in.datalen == 0)
                return 0;
 
@@ -857,6 +863,12 @@ int iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb,
        int rc = 0;
 
        ISCSI_DBG_TCP(conn, "in %d bytes\n", skb->len - offset);
+       /*
+        * Update for each skb instead of pdu, because over slow networks a
+        * data_in's data could take a while to read in. We also want to
+        * account for r2ts.
+        */
+       conn->last_recv = jiffies;
 
        if (unlikely(conn->suspend_rx)) {
                ISCSI_DBG_TCP(conn, "Rx suspended!\n");
index 1105f9a111ba416d956f89802b71f85de2b7f447..540569849099fc88cd774b2ce2549f1f586d0196 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
 
 struct lpfc_sli2_slim;
 
+#define LPFC_PCI_DEV_LP                0x1
+#define LPFC_PCI_DEV_OC                0x2
+
+#define LPFC_SLI_REV2          2
+#define LPFC_SLI_REV3          3
+#define LPFC_SLI_REV4          4
+
 #define LPFC_MAX_TARGET                4096    /* max number of targets supported */
 #define LPFC_MAX_DISC_THREADS  64      /* max outstanding discovery els
                                           requests */
@@ -98,9 +105,11 @@ struct lpfc_dma_pool {
 };
 
 struct hbq_dmabuf {
+       struct lpfc_dmabuf hbuf;
        struct lpfc_dmabuf dbuf;
        uint32_t size;
        uint32_t tag;
+       struct lpfc_rcqe rcqe;
 };
 
 /* Priority bit.  Set value to exceed low water mark in lpfc_mem. */
@@ -134,7 +143,10 @@ typedef struct lpfc_vpd {
        } rev;
        struct {
 #ifdef __BIG_ENDIAN_BITFIELD
-               uint32_t rsvd2  :24;  /* Reserved                             */
+               uint32_t rsvd3  :19;  /* Reserved                             */
+               uint32_t cdss   : 1;  /* Configure Data Security SLI          */
+               uint32_t rsvd2  : 3;  /* Reserved                             */
+               uint32_t cbg    : 1;  /* Configure BlockGuard                 */
                uint32_t cmv    : 1;  /* Configure Max VPIs                   */
                uint32_t ccrp   : 1;  /* Config Command Ring Polling          */
                uint32_t csah   : 1;  /* Configure Synchronous Abort Handling */
@@ -152,7 +164,10 @@ typedef struct lpfc_vpd {
                uint32_t csah   : 1;  /* Configure Synchronous Abort Handling */
                uint32_t ccrp   : 1;  /* Config Command Ring Polling          */
                uint32_t cmv    : 1;  /* Configure Max VPIs                   */
-               uint32_t rsvd2  :24;  /* Reserved                             */
+               uint32_t cbg    : 1;  /* Configure BlockGuard                 */
+               uint32_t rsvd2  : 3;  /* Reserved                             */
+               uint32_t cdss   : 1;  /* Configure Data Security SLI          */
+               uint32_t rsvd3  :19;  /* Reserved                             */
 #endif
        } sli3Feat;
 } lpfc_vpd_t;
@@ -264,8 +279,8 @@ enum hba_state {
 };
 
 struct lpfc_vport {
-       struct list_head listentry;
        struct lpfc_hba *phba;
+       struct list_head listentry;
        uint8_t port_type;
 #define LPFC_PHYSICAL_PORT 1
 #define LPFC_NPIV_PORT  2
@@ -273,6 +288,9 @@ struct lpfc_vport {
        enum discovery_state port_state;
 
        uint16_t vpi;
+       uint16_t vfi;
+       uint8_t vfi_state;
+#define LPFC_VFI_REGISTERED    0x1
 
        uint32_t fc_flag;       /* FC flags */
 /* Several of these flags are HBA centric and should be moved to
@@ -385,6 +403,9 @@ struct lpfc_vport {
 #endif
        uint8_t stat_data_enabled;
        uint8_t stat_data_blocked;
+       struct list_head rcv_buffer_list;
+       uint32_t vport_flag;
+#define STATIC_VPORT   1
 };
 
 struct hbq_s {
@@ -420,8 +441,66 @@ enum intr_type_t {
 };
 
 struct lpfc_hba {
+       /* SCSI interface function jump table entries */
+       int (*lpfc_new_scsi_buf)
+               (struct lpfc_vport *, int);
+       struct lpfc_scsi_buf * (*lpfc_get_scsi_buf)
+               (struct lpfc_hba *);
+       int (*lpfc_scsi_prep_dma_buf)
+               (struct lpfc_hba *, struct lpfc_scsi_buf *);
+       void (*lpfc_scsi_unprep_dma_buf)
+               (struct lpfc_hba *, struct lpfc_scsi_buf *);
+       void (*lpfc_release_scsi_buf)
+               (struct lpfc_hba *, struct lpfc_scsi_buf *);
+       void (*lpfc_rampdown_queue_depth)
+               (struct lpfc_hba *);
+       void (*lpfc_scsi_prep_cmnd)
+               (struct lpfc_vport *, struct lpfc_scsi_buf *,
+                struct lpfc_nodelist *);
+       int (*lpfc_scsi_prep_task_mgmt_cmd)
+               (struct lpfc_vport *, struct lpfc_scsi_buf *,
+                unsigned int, uint8_t);
+
+       /* IOCB interface function jump table entries */
+       int (*__lpfc_sli_issue_iocb)
+               (struct lpfc_hba *, uint32_t,
+                struct lpfc_iocbq *, uint32_t);
+       void (*__lpfc_sli_release_iocbq)(struct lpfc_hba *,
+                        struct lpfc_iocbq *);
+       int (*lpfc_hba_down_post)(struct lpfc_hba *phba);
+
+
+       IOCB_t * (*lpfc_get_iocb_from_iocbq)
+               (struct lpfc_iocbq *);
+       void (*lpfc_scsi_cmd_iocb_cmpl)
+               (struct lpfc_hba *, struct lpfc_iocbq *, struct lpfc_iocbq *);
+
+       /* MBOX interface function jump table entries */
+       int (*lpfc_sli_issue_mbox)
+               (struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
+       /* Slow-path IOCB process function jump table entries */
+       void (*lpfc_sli_handle_slow_ring_event)
+               (struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+                uint32_t mask);
+       /* INIT device interface function jump table entries */
+       int (*lpfc_sli_hbq_to_firmware)
+               (struct lpfc_hba *, uint32_t, struct hbq_dmabuf *);
+       int (*lpfc_sli_brdrestart)
+               (struct lpfc_hba *);
+       int (*lpfc_sli_brdready)
+               (struct lpfc_hba *, uint32_t);
+       void (*lpfc_handle_eratt)
+               (struct lpfc_hba *);
+       void (*lpfc_stop_port)
+               (struct lpfc_hba *);
+
+
+       /* SLI4 specific HBA data structure */
+       struct lpfc_sli4_hba sli4_hba;
+
        struct lpfc_sli sli;
-       uint32_t sli_rev;               /* SLI2 or SLI3 */
+       uint8_t pci_dev_grp;    /* lpfc PCI dev group: 0x0, 0x1, 0x2,... */
+       uint32_t sli_rev;               /* SLI2, SLI3, or SLI4 */
        uint32_t sli3_options;          /* Mask of enabled SLI3 options */
 #define LPFC_SLI3_HBQ_ENABLED          0x01
 #define LPFC_SLI3_NPIV_ENABLED         0x02
@@ -429,6 +508,7 @@ struct lpfc_hba {
 #define LPFC_SLI3_CRP_ENABLED          0x08
 #define LPFC_SLI3_INB_ENABLED          0x10
 #define LPFC_SLI3_BG_ENABLED           0x20
+#define LPFC_SLI3_DSS_ENABLED          0x40
        uint32_t iocb_cmd_size;
        uint32_t iocb_rsp_size;
 
@@ -442,8 +522,13 @@ struct lpfc_hba {
 
        uint32_t hba_flag;      /* hba generic flags */
 #define HBA_ERATT_HANDLED      0x1 /* This flag is set when eratt handled */
-
-#define DEFER_ERATT            0x4 /* Deferred error attention in progress */
+#define DEFER_ERATT            0x2 /* Deferred error attention in progress */
+#define HBA_FCOE_SUPPORT       0x4 /* HBA function supports FCOE */
+#define HBA_RECEIVE_BUFFER     0x8 /* Rcv buffer posted to worker thread */
+#define HBA_POST_RECEIVE_BUFFER 0x10 /* Rcv buffers need to be posted */
+#define FCP_XRI_ABORT_EVENT    0x20
+#define ELS_XRI_ABORT_EVENT    0x40
+#define ASYNC_EVENT            0x80
        struct lpfc_dmabuf slim2p;
 
        MAILBOX_t *mbox;
@@ -502,6 +587,9 @@ struct lpfc_hba {
        uint32_t cfg_poll;
        uint32_t cfg_poll_tmo;
        uint32_t cfg_use_msi;
+       uint32_t cfg_fcp_imax;
+       uint32_t cfg_fcp_wq_count;
+       uint32_t cfg_fcp_eq_count;
        uint32_t cfg_sg_seg_cnt;
        uint32_t cfg_prot_sg_seg_cnt;
        uint32_t cfg_sg_dma_buf_size;
@@ -511,6 +599,8 @@ struct lpfc_hba {
        uint32_t cfg_enable_hba_reset;
        uint32_t cfg_enable_hba_heartbeat;
        uint32_t cfg_enable_bg;
+       uint32_t cfg_enable_fip;
+       uint32_t cfg_log_verbose;
 
        lpfc_vpd_t vpd;         /* vital product data */
 
@@ -526,11 +616,12 @@ struct lpfc_hba {
        unsigned long data_flags;
 
        uint32_t hbq_in_use;            /* HBQs in use flag */
-       struct list_head hbqbuf_in_list;  /* in-fly hbq buffer list */
+       struct list_head rb_pend_list;  /* Received buffers to be processed */
        uint32_t hbq_count;             /* Count of configured HBQs */
        struct hbq_s hbqs[LPFC_MAX_HBQS]; /* local copy of hbq indicies  */
 
        unsigned long pci_bar0_map;     /* Physical address for PCI BAR0 */
+       unsigned long pci_bar1_map;     /* Physical address for PCI BAR1 */
        unsigned long pci_bar2_map;     /* Physical address for PCI BAR2 */
        void __iomem *slim_memmap_p;    /* Kernel memory mapped address for
                                           PCI BAR0 */
@@ -593,7 +684,8 @@ struct lpfc_hba {
        /* pci_mem_pools */
        struct pci_pool *lpfc_scsi_dma_buf_pool;
        struct pci_pool *lpfc_mbuf_pool;
-       struct pci_pool *lpfc_hbq_pool;
+       struct pci_pool *lpfc_hrb_pool; /* header receive buffer pool */
+       struct pci_pool *lpfc_drb_pool; /* data receive buffer pool */
        struct lpfc_dma_pool lpfc_mbuf_safety_pool;
 
        mempool_t *mbox_mem_pool;
@@ -609,6 +701,14 @@ struct lpfc_hba {
        struct lpfc_vport *pport;       /* physical lpfc_vport pointer */
        uint16_t max_vpi;               /* Maximum virtual nports */
 #define LPFC_MAX_VPI 0xFFFF            /* Max number of VPI supported */
+       uint16_t max_vports;            /*
+                                        * For IOV HBAs max_vpi can change
+                                        * after a reset. max_vports is max
+                                        * number of vports present. This can
+                                        * be greater than max_vpi.
+                                        */
+       uint16_t vpi_base;
+       uint16_t vfi_base;
        unsigned long *vpi_bmask;       /* vpi allocation table */
 
        /* Data structure used by fabric iocb scheduler */
@@ -667,6 +767,11 @@ struct lpfc_hba {
 /* Maximum number of events that can be outstanding at any time*/
 #define LPFC_MAX_EVT_COUNT 512
        atomic_t fast_event_count;
+       struct lpfc_fcf fcf;
+       uint8_t fc_map[3];
+       uint8_t valid_vlan;
+       uint16_t vlan_id;
+       struct list_head fcf_conn_rec_list;
 };
 
 static inline struct Scsi_Host *
index c14f0cbdb125024372d765c746585c4c8844882b..d73e677201f8df229784fce5fc48e039dba7ae56 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
 #include <scsi/scsi_tcq.h>
 #include <scsi/scsi_transport_fc.h>
 
+#include "lpfc_hw4.h"
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
+#include "lpfc_sli4.h"
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -505,12 +507,14 @@ lpfc_issue_lip(struct Scsi_Host *shost)
                return -ENOMEM;
 
        memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t));
-       pmboxq->mb.mbxCommand = MBX_DOWN_LINK;
-       pmboxq->mb.mbxOwner = OWN_HOST;
+       pmboxq->u.mb.mbxCommand = MBX_DOWN_LINK;
+       pmboxq->u.mb.mbxOwner = OWN_HOST;
 
        mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO * 2);
 
-       if ((mbxstatus == MBX_SUCCESS) && (pmboxq->mb.mbxStatus == 0)) {
+       if ((mbxstatus == MBX_SUCCESS) &&
+           (pmboxq->u.mb.mbxStatus == 0 ||
+            pmboxq->u.mb.mbxStatus == MBXERR_LINK_DOWN)) {
                memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t));
                lpfc_init_link(phba, pmboxq, phba->cfg_topology,
                               phba->cfg_link_speed);
@@ -789,7 +793,8 @@ lpfc_get_hba_info(struct lpfc_hba *phba,
                  uint32_t *mrpi, uint32_t *arpi,
                  uint32_t *mvpi, uint32_t *avpi)
 {
-       struct lpfc_sli   *psli = &phba->sli;
+       struct lpfc_sli *psli = &phba->sli;
+       struct lpfc_mbx_read_config *rd_config;
        LPFC_MBOXQ_t *pmboxq;
        MAILBOX_t *pmb;
        int rc = 0;
@@ -800,7 +805,7 @@ lpfc_get_hba_info(struct lpfc_hba *phba,
         */
        if (phba->link_state < LPFC_LINK_DOWN ||
            !phba->mbox_mem_pool ||
-           (phba->sli.sli_flag & LPFC_SLI2_ACTIVE) == 0)
+           (phba->sli.sli_flag & LPFC_SLI_ACTIVE) == 0)
                return 0;
 
        if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO)
@@ -811,13 +816,13 @@ lpfc_get_hba_info(struct lpfc_hba *phba,
                return 0;
        memset(pmboxq, 0, sizeof (LPFC_MBOXQ_t));
 
-       pmb = &pmboxq->mb;
+       pmb = &pmboxq->u.mb;
        pmb->mbxCommand = MBX_READ_CONFIG;
        pmb->mbxOwner = OWN_HOST;
        pmboxq->context1 = NULL;
 
        if ((phba->pport->fc_flag & FC_OFFLINE_MODE) ||
-               (!(psli->sli_flag & LPFC_SLI2_ACTIVE)))
+               (!(psli->sli_flag & LPFC_SLI_ACTIVE)))
                rc = MBX_NOT_FINISHED;
        else
                rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
@@ -828,18 +833,37 @@ lpfc_get_hba_info(struct lpfc_hba *phba,
                return 0;
        }
 
-       if (mrpi)
-               *mrpi = pmb->un.varRdConfig.max_rpi;
-       if (arpi)
-               *arpi = pmb->un.varRdConfig.avail_rpi;
-       if (mxri)
-               *mxri = pmb->un.varRdConfig.max_xri;
-       if (axri)
-               *axri = pmb->un.varRdConfig.avail_xri;
-       if (mvpi)
-               *mvpi = pmb->un.varRdConfig.max_vpi;
-       if (avpi)
-               *avpi = pmb->un.varRdConfig.avail_vpi;
+       if (phba->sli_rev == LPFC_SLI_REV4) {
+               rd_config = &pmboxq->u.mqe.un.rd_config;
+               if (mrpi)
+                       *mrpi = bf_get(lpfc_mbx_rd_conf_rpi_count, rd_config);
+               if (arpi)
+                       *arpi = bf_get(lpfc_mbx_rd_conf_rpi_count, rd_config) -
+                                       phba->sli4_hba.max_cfg_param.rpi_used;
+               if (mxri)
+                       *mxri = bf_get(lpfc_mbx_rd_conf_xri_count, rd_config);
+               if (axri)
+                       *axri = bf_get(lpfc_mbx_rd_conf_xri_count, rd_config) -
+                                       phba->sli4_hba.max_cfg_param.xri_used;
+               if (mvpi)
+                       *mvpi = bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config);
+               if (avpi)
+                       *avpi = bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config) -
+                                       phba->sli4_hba.max_cfg_param.vpi_used;
+       } else {
+               if (mrpi)
+                       *mrpi = pmb->un.varRdConfig.max_rpi;
+               if (arpi)
+                       *arpi = pmb->un.varRdConfig.avail_rpi;
+               if (mxri)
+                       *mxri = pmb->un.varRdConfig.max_xri;
+               if (axri)
+                       *axri = pmb->un.varRdConfig.avail_xri;
+               if (mvpi)
+                       *mvpi = pmb->un.varRdConfig.max_vpi;
+               if (avpi)
+                       *avpi = pmb->un.varRdConfig.avail_vpi;
+       }
 
        mempool_free(pmboxq, phba->mbox_mem_pool);
        return 1;
@@ -2021,22 +2045,9 @@ static DEVICE_ATTR(lpfc_devloss_tmo, S_IRUGO | S_IWUSR,
 # lpfc_log_verbose: Only turn this flag on if you are willing to risk being
 # deluged with LOTS of information.
 # You can set a bit mask to record specific types of verbose messages:
-#
-# LOG_ELS                       0x1        ELS events
-# LOG_DISCOVERY                 0x2        Link discovery events
-# LOG_MBOX                      0x4        Mailbox events
-# LOG_INIT                      0x8        Initialization events
-# LOG_LINK_EVENT                0x10       Link events
-# LOG_FCP                       0x40       FCP traffic history
-# LOG_NODE                      0x80       Node table events
-# LOG_BG                        0x200      BlockBuard events
-# LOG_MISC                      0x400      Miscellaneous events
-# LOG_SLI                       0x800      SLI events
-# LOG_FCP_ERROR                 0x1000     Only log FCP errors
-# LOG_LIBDFC                    0x2000     LIBDFC events
-# LOG_ALL_MSG                   0xffff     LOG all messages
+# See lpfc_logmsh.h for definitions.
 */
-LPFC_VPORT_ATTR_HEX_RW(log_verbose, 0x0, 0x0, 0xffff,
+LPFC_VPORT_ATTR_HEX_RW(log_verbose, 0x0, 0x0, 0xffffffff,
                       "Verbose logging bit-mask");
 
 /*
@@ -2266,6 +2277,36 @@ lpfc_param_init(topology, 0, 0, 6)
 static DEVICE_ATTR(lpfc_topology, S_IRUGO | S_IWUSR,
                lpfc_topology_show, lpfc_topology_store);
 
+/**
+ * lpfc_static_vport_show: Read callback function for
+ *   lpfc_static_vport sysfs file.
+ * @dev: Pointer to class device object.
+ * @attr: device attribute structure.
+ * @buf: Data buffer.
+ *
+ * This function is the read call back function for
+ * lpfc_static_vport sysfs file. The lpfc_static_vport
+ * sysfs file report the mageability of the vport.
+ **/
+static ssize_t
+lpfc_static_vport_show(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct Scsi_Host  *shost = class_to_shost(dev);
+       struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+       if (vport->vport_flag & STATIC_VPORT)
+               sprintf(buf, "1\n");
+       else
+               sprintf(buf, "0\n");
+
+       return strlen(buf);
+}
+
+/*
+ * Sysfs attribute to control the statistical data collection.
+ */
+static DEVICE_ATTR(lpfc_static_vport, S_IRUGO,
+                  lpfc_static_vport_show, NULL);
 
 /**
  * lpfc_stat_data_ctrl_store - write call back for lpfc_stat_data_ctrl sysfs file
@@ -2341,7 +2382,7 @@ lpfc_stat_data_ctrl_store(struct device *dev, struct device_attribute *attr,
                if (vports == NULL)
                        return -ENOMEM;
 
-               for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+               for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
                        v_shost = lpfc_shost_from_vport(vports[i]);
                        spin_lock_irq(v_shost->host_lock);
                        /* Block and reset data collection */
@@ -2356,7 +2397,7 @@ lpfc_stat_data_ctrl_store(struct device *dev, struct device_attribute *attr,
                phba->bucket_base = base;
                phba->bucket_step = step;
 
-               for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+               for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
                        v_shost = lpfc_shost_from_vport(vports[i]);
 
                        /* Unblock data collection */
@@ -2373,7 +2414,7 @@ lpfc_stat_data_ctrl_store(struct device *dev, struct device_attribute *attr,
                if (vports == NULL)
                        return -ENOMEM;
 
-               for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+               for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
                        v_shost = lpfc_shost_from_vport(vports[i]);
                        spin_lock_irq(shost->host_lock);
                        vports[i]->stat_data_blocked = 1;
@@ -2844,14 +2885,38 @@ LPFC_ATTR_RW(poll_tmo, 10, 1, 255,
 /*
 # lpfc_use_msi: Use MSI (Message Signaled Interrupts) in systems that
 #              support this feature
-#       0  = MSI disabled
+#       0  = MSI disabled (default)
 #       1  = MSI enabled
-#       2  = MSI-X enabled (default)
-# Value range is [0,2]. Default value is 2.
+#       2  = MSI-X enabled
+# Value range is [0,2]. Default value is 0.
 */
-LPFC_ATTR_R(use_msi, 2, 0, 2, "Use Message Signaled Interrupts (1) or "
+LPFC_ATTR_R(use_msi, 0, 0, 2, "Use Message Signaled Interrupts (1) or "
            "MSI-X (2), if possible");
 
+/*
+# lpfc_fcp_imax: Set the maximum number of fast-path FCP interrupts per second
+#
+# Value range is [636,651042]. Default value is 10000.
+*/
+LPFC_ATTR_R(fcp_imax, LPFC_FP_DEF_IMAX, LPFC_MIM_IMAX, LPFC_DMULT_CONST,
+           "Set the maximum number of fast-path FCP interrupts per second");
+
+/*
+# lpfc_fcp_wq_count: Set the number of fast-path FCP work queues
+#
+# Value range is [1,31]. Default value is 4.
+*/
+LPFC_ATTR_R(fcp_wq_count, LPFC_FP_WQN_DEF, LPFC_FP_WQN_MIN, LPFC_FP_WQN_MAX,
+           "Set the number of fast-path FCP work queues, if possible");
+
+/*
+# lpfc_fcp_eq_count: Set the number of fast-path FCP event queues
+#
+# Value range is [1,7]. Default value is 1.
+*/
+LPFC_ATTR_R(fcp_eq_count, LPFC_FP_EQN_DEF, LPFC_FP_EQN_MIN, LPFC_FP_EQN_MAX,
+           "Set the number of fast-path FCP event queues, if possible");
+
 /*
 # lpfc_enable_hba_reset: Allow or prevent HBA resets to the hardware.
 #       0  = HBA resets disabled
@@ -2876,6 +2941,14 @@ LPFC_ATTR_R(enable_hba_heartbeat, 1, 0, 1, "Enable HBA Heartbeat.");
 */
 LPFC_ATTR_R(enable_bg, 0, 0, 1, "Enable BlockGuard Support");
 
+/*
+# lpfc_enable_fip: When set, FIP is required to start discovery. If not
+# set, the driver will add an FCF record manually if the port has no
+# FCF records available and start discovery.
+# Value range is [0,1]. Default value is 1 (enabled)
+*/
+LPFC_ATTR_RW(enable_fip, 0, 0, 1, "Enable FIP Discovery");
+
 
 /*
 # lpfc_prot_mask: i
@@ -2942,6 +3015,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
        &dev_attr_lpfc_peer_port_login,
        &dev_attr_lpfc_nodev_tmo,
        &dev_attr_lpfc_devloss_tmo,
+       &dev_attr_lpfc_enable_fip,
        &dev_attr_lpfc_fcp_class,
        &dev_attr_lpfc_use_adisc,
        &dev_attr_lpfc_ack0,
@@ -2969,6 +3043,9 @@ struct device_attribute *lpfc_hba_attrs[] = {
        &dev_attr_lpfc_poll,
        &dev_attr_lpfc_poll_tmo,
        &dev_attr_lpfc_use_msi,
+       &dev_attr_lpfc_fcp_imax,
+       &dev_attr_lpfc_fcp_wq_count,
+       &dev_attr_lpfc_fcp_eq_count,
        &dev_attr_lpfc_enable_bg,
        &dev_attr_lpfc_soft_wwnn,
        &dev_attr_lpfc_soft_wwpn,
@@ -2991,6 +3068,7 @@ struct device_attribute *lpfc_vport_attrs[] = {
        &dev_attr_lpfc_lun_queue_depth,
        &dev_attr_lpfc_nodev_tmo,
        &dev_attr_lpfc_devloss_tmo,
+       &dev_attr_lpfc_enable_fip,
        &dev_attr_lpfc_hba_queue_depth,
        &dev_attr_lpfc_peer_port_login,
        &dev_attr_lpfc_restrict_login,
@@ -3003,6 +3081,7 @@ struct device_attribute *lpfc_vport_attrs[] = {
        &dev_attr_lpfc_enable_da_id,
        &dev_attr_lpfc_max_scsicmpl_time,
        &dev_attr_lpfc_stat_data_ctrl,
+       &dev_attr_lpfc_static_vport,
        NULL,
 };
 
@@ -3199,7 +3278,7 @@ sysfs_mbox_write(struct kobject *kobj, struct bin_attribute *bin_attr,
                }
        }
 
-       memcpy((uint8_t *) & phba->sysfs_mbox.mbox->mb + off,
+       memcpy((uint8_t *) &phba->sysfs_mbox.mbox->u.mb + off,
               buf, count);
 
        phba->sysfs_mbox.offset = off + count;
@@ -3241,6 +3320,7 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
        struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
        struct lpfc_hba   *phba = vport->phba;
        int rc;
+       MAILBOX_t *pmb;
 
        if (off > MAILBOX_CMD_SIZE)
                return -ERANGE;
@@ -3265,8 +3345,8 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
        if (off == 0 &&
            phba->sysfs_mbox.state  == SMBOX_WRITING &&
            phba->sysfs_mbox.offset >= 2 * sizeof(uint32_t)) {
-
-               switch (phba->sysfs_mbox.mbox->mb.mbxCommand) {
+               pmb = &phba->sysfs_mbox.mbox->u.mb;
+               switch (pmb->mbxCommand) {
                        /* Offline only */
                case MBX_INIT_LINK:
                case MBX_DOWN_LINK:
@@ -3283,7 +3363,7 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
                        if (!(vport->fc_flag & FC_OFFLINE_MODE)) {
                                printk(KERN_WARNING "mbox_read:Command 0x%x "
                                       "is illegal in on-line state\n",
-                                      phba->sysfs_mbox.mbox->mb.mbxCommand);
+                                      pmb->mbxCommand);
                                sysfs_mbox_idle(phba);
                                spin_unlock_irq(&phba->hbalock);
                                return -EPERM;
@@ -3319,13 +3399,13 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
                case MBX_CONFIG_PORT:
                case MBX_RUN_BIU_DIAG:
                        printk(KERN_WARNING "mbox_read: Illegal Command 0x%x\n",
-                              phba->sysfs_mbox.mbox->mb.mbxCommand);
+                              pmb->mbxCommand);
                        sysfs_mbox_idle(phba);
                        spin_unlock_irq(&phba->hbalock);
                        return -EPERM;
                default:
                        printk(KERN_WARNING "mbox_read: Unknown Command 0x%x\n",
-                              phba->sysfs_mbox.mbox->mb.mbxCommand);
+                              pmb->mbxCommand);
                        sysfs_mbox_idle(phba);
                        spin_unlock_irq(&phba->hbalock);
                        return -EPERM;
@@ -3335,14 +3415,14 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
                 * or RESTART mailbox commands until the HBA is restarted.
                 */
                if (phba->pport->stopped &&
-                   phba->sysfs_mbox.mbox->mb.mbxCommand != MBX_DUMP_MEMORY &&
-                   phba->sysfs_mbox.mbox->mb.mbxCommand != MBX_RESTART &&
-                   phba->sysfs_mbox.mbox->mb.mbxCommand != MBX_WRITE_VPARMS &&
-                   phba->sysfs_mbox.mbox->mb.mbxCommand != MBX_WRITE_WWN)
+                   pmb->mbxCommand != MBX_DUMP_MEMORY &&
+                   pmb->mbxCommand != MBX_RESTART &&
+                   pmb->mbxCommand != MBX_WRITE_VPARMS &&
+                   pmb->mbxCommand != MBX_WRITE_WWN)
                        lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
                                        "1259 mbox: Issued mailbox cmd "
                                        "0x%x while in stopped state.\n",
-                                       phba->sysfs_mbox.mbox->mb.mbxCommand);
+                                       pmb->mbxCommand);
 
                phba->sysfs_mbox.mbox->vport = vport;
 
@@ -3356,7 +3436,7 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
                }
 
                if ((vport->fc_flag & FC_OFFLINE_MODE) ||
-                   (!(phba->sli.sli_flag & LPFC_SLI2_ACTIVE))){
+                   (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) {
 
                        spin_unlock_irq(&phba->hbalock);
                        rc = lpfc_sli_issue_mbox (phba,
@@ -3368,8 +3448,7 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
                        spin_unlock_irq(&phba->hbalock);
                        rc = lpfc_sli_issue_mbox_wait (phba,
                                                       phba->sysfs_mbox.mbox,
-                               lpfc_mbox_tmo_val(phba,
-                                   phba->sysfs_mbox.mbox->mb.mbxCommand) * HZ);
+                               lpfc_mbox_tmo_val(phba, pmb->mbxCommand) * HZ);
                        spin_lock_irq(&phba->hbalock);
                }
 
@@ -3391,7 +3470,7 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
                return -EAGAIN;
        }
 
-       memcpy(buf, (uint8_t *) & phba->sysfs_mbox.mbox->mb + off, count);
+       memcpy(buf, (uint8_t *) &pmb + off, count);
 
        phba->sysfs_mbox.offset = off + count;
 
@@ -3585,6 +3664,9 @@ lpfc_get_host_speed(struct Scsi_Host *shost)
                        case LA_8GHZ_LINK:
                                fc_host_speed(shost) = FC_PORTSPEED_8GBIT;
                        break;
+                       case LA_10GHZ_LINK:
+                               fc_host_speed(shost) = FC_PORTSPEED_10GBIT;
+                       break;
                        default:
                                fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
                        break;
@@ -3652,7 +3734,7 @@ lpfc_get_stats(struct Scsi_Host *shost)
         */
        if (phba->link_state < LPFC_LINK_DOWN ||
            !phba->mbox_mem_pool ||
-           (phba->sli.sli_flag & LPFC_SLI2_ACTIVE) == 0)
+           (phba->sli.sli_flag & LPFC_SLI_ACTIVE) == 0)
                return NULL;
 
        if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO)
@@ -3663,14 +3745,14 @@ lpfc_get_stats(struct Scsi_Host *shost)
                return NULL;
        memset(pmboxq, 0, sizeof (LPFC_MBOXQ_t));
 
-       pmb = &pmboxq->mb;
+       pmb = &pmboxq->u.mb;
        pmb->mbxCommand = MBX_READ_STATUS;
        pmb->mbxOwner = OWN_HOST;
        pmboxq->context1 = NULL;
        pmboxq->vport = vport;
 
        if ((vport->fc_flag & FC_OFFLINE_MODE) ||
-               (!(psli->sli_flag & LPFC_SLI2_ACTIVE)))
+               (!(psli->sli_flag & LPFC_SLI_ACTIVE)))
                rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
        else
                rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
@@ -3695,7 +3777,7 @@ lpfc_get_stats(struct Scsi_Host *shost)
        pmboxq->vport = vport;
 
        if ((vport->fc_flag & FC_OFFLINE_MODE) ||
-           (!(psli->sli_flag & LPFC_SLI2_ACTIVE)))
+           (!(psli->sli_flag & LPFC_SLI_ACTIVE)))
                rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
        else
                rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
@@ -3769,7 +3851,7 @@ lpfc_reset_stats(struct Scsi_Host *shost)
                return;
        memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));
 
-       pmb = &pmboxq->mb;
+       pmb = &pmboxq->u.mb;
        pmb->mbxCommand = MBX_READ_STATUS;
        pmb->mbxOwner = OWN_HOST;
        pmb->un.varWords[0] = 0x1; /* reset request */
@@ -3777,7 +3859,7 @@ lpfc_reset_stats(struct Scsi_Host *shost)
        pmboxq->vport = vport;
 
        if ((vport->fc_flag & FC_OFFLINE_MODE) ||
-               (!(psli->sli_flag & LPFC_SLI2_ACTIVE)))
+               (!(psli->sli_flag & LPFC_SLI_ACTIVE)))
                rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
        else
                rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
@@ -3795,7 +3877,7 @@ lpfc_reset_stats(struct Scsi_Host *shost)
        pmboxq->vport = vport;
 
        if ((vport->fc_flag & FC_OFFLINE_MODE) ||
-           (!(psli->sli_flag & LPFC_SLI2_ACTIVE)))
+           (!(psli->sli_flag & LPFC_SLI_ACTIVE)))
                rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
        else
                rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
@@ -3962,6 +4044,21 @@ lpfc_set_vport_symbolic_name(struct fc_vport *fc_vport)
                lpfc_ns_cmd(vport, SLI_CTNS_RSPN_ID, 0, 0);
 }
 
+/**
+ * lpfc_hba_log_verbose_init - Set hba's log verbose level
+ * @phba: Pointer to lpfc_hba struct.
+ *
+ * This function is called by the lpfc_get_cfgparam() routine to set the
+ * module lpfc_log_verbose into the @phba cfg_log_verbose for use with
+ * log messsage according to the module's lpfc_log_verbose parameter setting
+ * before hba port or vport created.
+ **/
+static void
+lpfc_hba_log_verbose_init(struct lpfc_hba *phba, uint32_t verbose)
+{
+       phba->cfg_log_verbose = verbose;
+}
+
 struct fc_function_template lpfc_transport_functions = {
        /* fixed attributes the driver supports */
        .show_host_node_name = 1,
@@ -4105,6 +4202,9 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
        lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
        lpfc_enable_npiv_init(phba, lpfc_enable_npiv);
        lpfc_use_msi_init(phba, lpfc_use_msi);
+       lpfc_fcp_imax_init(phba, lpfc_fcp_imax);
+       lpfc_fcp_wq_count_init(phba, lpfc_fcp_wq_count);
+       lpfc_fcp_eq_count_init(phba, lpfc_fcp_eq_count);
        lpfc_enable_hba_reset_init(phba, lpfc_enable_hba_reset);
        lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat);
        lpfc_enable_bg_init(phba, lpfc_enable_bg);
@@ -4113,26 +4213,10 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
        phba->cfg_soft_wwpn = 0L;
        lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt);
        lpfc_prot_sg_seg_cnt_init(phba, lpfc_prot_sg_seg_cnt);
-       /*
-        * Since the sg_tablesize is module parameter, the sg_dma_buf_size
-        * used to create the sg_dma_buf_pool must be dynamically calculated.
-        * 2 segments are added since the IOCB needs a command and response bde.
-        */
-       phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) +
-                       sizeof(struct fcp_rsp) +
-                       ((phba->cfg_sg_seg_cnt + 2) * sizeof(struct ulp_bde64));
-
-       if (phba->cfg_enable_bg) {
-               phba->cfg_sg_seg_cnt = LPFC_MAX_SG_SEG_CNT;
-               phba->cfg_sg_dma_buf_size +=
-                       phba->cfg_prot_sg_seg_cnt * sizeof(struct ulp_bde64);
-       }
-
-       /* Also reinitialize the host templates with new values. */
-       lpfc_vport_template.sg_tablesize = phba->cfg_sg_seg_cnt;
-       lpfc_template.sg_tablesize = phba->cfg_sg_seg_cnt;
-
        lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
+       lpfc_enable_fip_init(phba, lpfc_enable_fip);
+       lpfc_hba_log_verbose_init(phba, lpfc_log_verbose);
+
        return;
 }
 
index f88ce3f261900c50fce0d33a0abff80ade5d6ad9..d2a922997c0fa17faf05299fd4a85c4894e39e7c 100644 (file)
@@ -23,6 +23,8 @@ typedef int (*node_filter)(struct lpfc_nodelist *, void *);
 struct fc_rport;
 void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
 void lpfc_dump_wakeup_param(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_dump_static_vport(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
+int lpfc_dump_fcoe_param(struct lpfc_hba *, struct lpfcMboxq *);
 void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_config_async(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
 
@@ -35,17 +37,19 @@ int lpfc_config_msi(struct lpfc_hba *, LPFC_MBOXQ_t *);
 int lpfc_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *, int);
 void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_t *);
-int lpfc_reg_login(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *,
-                  LPFC_MBOXQ_t *, uint32_t);
+int lpfc_reg_rpi(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *,
+                LPFC_MBOXQ_t *, uint32_t);
 void lpfc_unreg_login(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
 void lpfc_unreg_did(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
-void lpfc_reg_vpi(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
+void lpfc_reg_vpi(struct lpfc_vport *, LPFC_MBOXQ_t *);
 void lpfc_unreg_vpi(struct lpfc_hba *, uint16_t, LPFC_MBOXQ_t *);
 void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
+void lpfc_request_features(struct lpfc_hba *, struct lpfcMboxq *);
 
 struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t);
 void lpfc_cleanup_rpis(struct lpfc_vport *, int);
 int lpfc_linkdown(struct lpfc_hba *);
+void lpfc_linkdown_port(struct lpfc_vport *);
 void lpfc_port_link_failure(struct lpfc_vport *);
 void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
 
@@ -54,6 +58,7 @@ void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_enqueue_node(struct lpfc_vport *, struct lpfc_nodelist *);
 void lpfc_dequeue_node(struct lpfc_vport *, struct lpfc_nodelist *);
 struct lpfc_nodelist *lpfc_enable_node(struct lpfc_vport *,
@@ -105,6 +110,7 @@ int lpfc_issue_els_adisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
 int lpfc_issue_els_logo(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
 int lpfc_issue_els_npiv_logo(struct lpfc_vport *, struct lpfc_nodelist *);
 int lpfc_issue_els_scr(struct lpfc_vport *, uint32_t, uint8_t);
+int lpfc_issue_fabric_reglogin(struct lpfc_vport *);
 int lpfc_els_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
 int lpfc_ct_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
 int lpfc_els_rsp_acc(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *,
@@ -149,15 +155,19 @@ int lpfc_online(struct lpfc_hba *);
 void lpfc_unblock_mgmt_io(struct lpfc_hba *);
 void lpfc_offline_prep(struct lpfc_hba *);
 void lpfc_offline(struct lpfc_hba *);
+void lpfc_reset_hba(struct lpfc_hba *);
 
 int lpfc_sli_setup(struct lpfc_hba *);
 int lpfc_sli_queue_setup(struct lpfc_hba *);
 
 void lpfc_handle_eratt(struct lpfc_hba *);
 void lpfc_handle_latt(struct lpfc_hba *);
-irqreturn_t lpfc_intr_handler(int, void *);
-irqreturn_t lpfc_sp_intr_handler(int, void *);
-irqreturn_t lpfc_fp_intr_handler(int, void *);
+irqreturn_t lpfc_sli_intr_handler(int, void *);
+irqreturn_t lpfc_sli_sp_intr_handler(int, void *);
+irqreturn_t lpfc_sli_fp_intr_handler(int, void *);
+irqreturn_t lpfc_sli4_intr_handler(int, void *);
+irqreturn_t lpfc_sli4_sp_intr_handler(int, void *);
+irqreturn_t lpfc_sli4_fp_intr_handler(int, void *);
 
 void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_config_ring(struct lpfc_hba *, int, LPFC_MBOXQ_t *);
@@ -165,16 +175,32 @@ void lpfc_config_port(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_kill_board(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbox_put(struct lpfc_hba *, LPFC_MBOXQ_t *);
 LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *);
+void __lpfc_mbox_cmpl_put(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbox_cmpl_put(struct lpfc_hba *, LPFC_MBOXQ_t *);
+int lpfc_mbox_cmd_check(struct lpfc_hba *, LPFC_MBOXQ_t *);
+int lpfc_mbox_dev_check(struct lpfc_hba *);
 int lpfc_mbox_tmo_val(struct lpfc_hba *, int);
+void lpfc_init_vfi(struct lpfcMboxq *, struct lpfc_vport *);
+void lpfc_reg_vfi(struct lpfcMboxq *, struct lpfc_vport *, dma_addr_t);
+void lpfc_init_vpi(struct lpfcMboxq *, uint16_t);
+void lpfc_unreg_vfi(struct lpfcMboxq *, uint16_t);
+void lpfc_reg_fcfi(struct lpfc_hba *, struct lpfcMboxq *);
+void lpfc_unreg_fcfi(struct lpfcMboxq *, uint16_t);
+void lpfc_resume_rpi(struct lpfcMboxq *, struct lpfc_nodelist *);
 
 void lpfc_config_hbq(struct lpfc_hba *, uint32_t, struct lpfc_hbq_init *,
        uint32_t , LPFC_MBOXQ_t *);
 struct hbq_dmabuf *lpfc_els_hbq_alloc(struct lpfc_hba *);
 void lpfc_els_hbq_free(struct lpfc_hba *, struct hbq_dmabuf *);
+struct hbq_dmabuf *lpfc_sli4_rb_alloc(struct lpfc_hba *);
+void lpfc_sli4_rb_free(struct lpfc_hba *, struct hbq_dmabuf *);
+void lpfc_sli4_build_dflt_fcf_record(struct lpfc_hba *, struct fcf_record *,
+                       uint16_t);
+void lpfc_unregister_unused_fcf(struct lpfc_hba *);
 
-int lpfc_mem_alloc(struct lpfc_hba *);
+int lpfc_mem_alloc(struct lpfc_hba *, int align);
 void lpfc_mem_free(struct lpfc_hba *);
+void lpfc_mem_free_all(struct lpfc_hba *);
 void lpfc_stop_vport_timers(struct lpfc_vport *);
 
 void lpfc_poll_timeout(unsigned long ptr);
@@ -186,6 +212,7 @@ void lpfc_sli_release_iocbq(struct lpfc_hba *, struct lpfc_iocbq *);
 uint16_t lpfc_sli_next_iotag(struct lpfc_hba *, struct lpfc_iocbq *);
 void lpfc_sli_cancel_iocbs(struct lpfc_hba *, struct list_head *, uint32_t,
                           uint32_t);
+void lpfc_sli_wake_mbox_wait(struct lpfc_hba *, LPFC_MBOXQ_t *);
 
 void lpfc_reset_barrier(struct lpfc_hba * phba);
 int lpfc_sli_brdready(struct lpfc_hba *, uint32_t);
@@ -198,12 +225,13 @@ int lpfc_sli_host_down(struct lpfc_vport *);
 int lpfc_sli_hba_down(struct lpfc_hba *);
 int lpfc_sli_issue_mbox(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
 int lpfc_sli_handle_mb_event(struct lpfc_hba *);
-int lpfc_sli_flush_mbox_queue(struct lpfc_hba *);
+void lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *);
 int lpfc_sli_check_eratt(struct lpfc_hba *);
-int lpfc_sli_handle_slow_ring_event(struct lpfc_hba *,
+void lpfc_sli_handle_slow_ring_event(struct lpfc_hba *,
                                    struct lpfc_sli_ring *, uint32_t);
+int lpfc_sli4_handle_received_buffer(struct lpfc_hba *);
 void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
-int lpfc_sli_issue_iocb(struct lpfc_hba *, struct lpfc_sli_ring *,
+int lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t,
                        struct lpfc_iocbq *, uint32_t);
 void lpfc_sli_pcimem_bcopy(void *, void *, uint32_t);
 void lpfc_sli_abort_iocb_ring(struct lpfc_hba *, struct lpfc_sli_ring *);
@@ -237,7 +265,7 @@ struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_vport *,
 
 int lpfc_sli_issue_mbox_wait(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
 
-int lpfc_sli_issue_iocb_wait(struct lpfc_hba *, struct lpfc_sli_ring *,
+int lpfc_sli_issue_iocb_wait(struct lpfc_hba *, uint32_t,
                             struct lpfc_iocbq *, struct lpfc_iocbq *,
                             uint32_t);
 void lpfc_sli_abort_fcp_cmpl(struct lpfc_hba *, struct lpfc_iocbq *,
@@ -254,6 +282,12 @@ void lpfc_in_buf_free(struct lpfc_hba *, struct lpfc_dmabuf *);
 const char* lpfc_info(struct Scsi_Host *);
 int lpfc_scan_finished(struct Scsi_Host *, unsigned long);
 
+int lpfc_init_api_table_setup(struct lpfc_hba *, uint8_t);
+int lpfc_sli_api_table_setup(struct lpfc_hba *, uint8_t);
+int lpfc_scsi_api_table_setup(struct lpfc_hba *, uint8_t);
+int lpfc_mbox_api_table_setup(struct lpfc_hba *, uint8_t);
+int lpfc_api_table_setup(struct lpfc_hba *, uint8_t);
+
 void lpfc_get_cfgparam(struct lpfc_hba *);
 void lpfc_get_vport_cfgparam(struct lpfc_vport *);
 int lpfc_alloc_sysfs_attr(struct lpfc_vport *);
@@ -314,8 +348,15 @@ lpfc_send_els_failure_event(struct lpfc_hba *, struct lpfc_iocbq *,
                                struct lpfc_iocbq *);
 struct lpfc_fast_path_event *lpfc_alloc_fast_evt(struct lpfc_hba *);
 void lpfc_free_fast_evt(struct lpfc_hba *, struct lpfc_fast_path_event *);
+void lpfc_create_static_vport(struct lpfc_hba *);
+void lpfc_stop_hba_timers(struct lpfc_hba *);
+void lpfc_stop_port(struct lpfc_hba *);
+void lpfc_parse_fcoe_conf(struct lpfc_hba *, uint8_t *, uint32_t);
+int lpfc_parse_vpd(struct lpfc_hba *, uint8_t *, int);
+void lpfc_start_fdiscs(struct lpfc_hba *phba);
 
 #define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code)
 #define HBA_EVENT_RSCN                   5
 #define HBA_EVENT_LINK_UP                2
 #define HBA_EVENT_LINK_DOWN              3
+
index 896c7b0351e51dcc2c529056442982129d0d02bf..1dbccfd3d022a6339bad81a04f291ec41abe89fb 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport_fc.h>
 
+#include "lpfc_hw4.h"
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
+#include "lpfc_sli4.h"
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -267,8 +269,6 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
             uint32_t tmo, uint8_t retry)
 {
        struct lpfc_hba  *phba = vport->phba;
-       struct lpfc_sli  *psli = &phba->sli;
-       struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
        IOCB_t *icmd;
        struct lpfc_iocbq *geniocb;
        int rc;
@@ -331,7 +331,7 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
        geniocb->drvrTimeout = icmd->ulpTimeout + LPFC_DRVR_TIMEOUT;
        geniocb->vport = vport;
        geniocb->retry = retry;
-       rc = lpfc_sli_issue_iocb(phba, pring, geniocb, 0);
+       rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, geniocb, 0);
 
        if (rc == IOCB_ERROR) {
                lpfc_sli_release_iocbq(phba, geniocb);
@@ -1578,6 +1578,9 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
                                case LA_8GHZ_LINK:
                                        ae->un.PortSpeed = HBA_PORTSPEED_8GBIT;
                                break;
+                               case LA_10GHZ_LINK:
+                                       ae->un.PortSpeed = HBA_PORTSPEED_10GBIT;
+                               break;
                                default:
                                        ae->un.PortSpeed =
                                                HBA_PORTSPEED_UNKNOWN;
@@ -1730,7 +1733,7 @@ lpfc_decode_firmware_rev(struct lpfc_hba *phba, char *fwrevision, int flag)
        uint8_t *fwname;
 
        if (vp->rev.rBit) {
-               if (psli->sli_flag & LPFC_SLI2_ACTIVE)
+               if (psli->sli_flag & LPFC_SLI_ACTIVE)
                        rev = vp->rev.sli2FwRev;
                else
                        rev = vp->rev.sli1FwRev;
@@ -1756,7 +1759,7 @@ lpfc_decode_firmware_rev(struct lpfc_hba *phba, char *fwrevision, int flag)
                }
                b4 = (rev & 0x0000000f);
 
-               if (psli->sli_flag & LPFC_SLI2_ACTIVE)
+               if (psli->sli_flag & LPFC_SLI_ACTIVE)
                        fwname = vp->rev.sli2FwName;
                else
                        fwname = vp->rev.sli1FwName;
index 52be5644e07ad6a9d6538c68a78e6ebe907e3f26..2b02b1fb39a09842a1b18216699ac31b83eef3bb 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2007-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2007-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport_fc.h>
 
+#include "lpfc_hw4.h"
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
+#include "lpfc_sli4.h"
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -280,6 +282,8 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size)
        struct lpfc_dmabuf *d_buf;
        struct hbq_dmabuf *hbq_buf;
 
+       if (phba->sli_rev != 3)
+               return 0;
        cnt = LPFC_HBQINFO_SIZE;
        spin_lock_irq(&phba->hbalock);
 
@@ -489,12 +493,15 @@ lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size)
                                 pring->next_cmdidx, pring->local_getidx,
                                 pring->flag, pgpp->rspPutInx, pring->numRiocb);
        }
-       word0 = readl(phba->HAregaddr);
-       word1 = readl(phba->CAregaddr);
-       word2 = readl(phba->HSregaddr);
-       word3 = readl(phba->HCregaddr);
-       len +=  snprintf(buf+len, size-len, "HA:%08x CA:%08x HS:%08x HC:%08x\n",
-       word0, word1, word2, word3);
+
+       if (phba->sli_rev <= LPFC_SLI_REV3) {
+               word0 = readl(phba->HAregaddr);
+               word1 = readl(phba->CAregaddr);
+               word2 = readl(phba->HSregaddr);
+               word3 = readl(phba->HCregaddr);
+               len +=  snprintf(buf+len, size-len, "HA:%08x CA:%08x HS:%08x "
+                                "HC:%08x\n", word0, word1, word2, word3);
+       }
        spin_unlock_irq(&phba->hbalock);
        return len;
 }
index ffd1089720728a7732a3c8f0707e068138ca71b6..1142070e948424c8f6b678ef5b5b93cc500dfb6b 100644 (file)
@@ -135,6 +135,7 @@ struct lpfc_nodelist {
 #define NLP_NODEV_REMOVE   0x08000000  /* Defer removal till discovery ends */
 #define NLP_TARGET_REMOVE  0x10000000   /* Target remove in process */
 #define NLP_SC_REQ         0x20000000  /* Target requires authentication */
+#define NLP_RPI_VALID      0x80000000  /* nlp_rpi is valid */
 
 /* ndlp usage management macros */
 #define NLP_CHK_NODE_ACT(ndlp)         (((ndlp)->nlp_usg_map \
index b8b34cf5c3d2fd2129c24a16c9fdb08d12229884..6bdeb14878a2b094eb7f175bea7982cdd337b957 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport_fc.h>
 
+#include "lpfc_hw4.h"
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
+#include "lpfc_sli4.h"
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -84,7 +86,8 @@ lpfc_els_chk_latt(struct lpfc_vport *vport)
        uint32_t ha_copy;
 
        if (vport->port_state >= LPFC_VPORT_READY ||
-           phba->link_state == LPFC_LINK_DOWN)
+           phba->link_state == LPFC_LINK_DOWN ||
+           phba->sli_rev > LPFC_SLI_REV3)
                return 0;
 
        /* Read the HBA Host Attention Register */
@@ -219,7 +222,7 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
                icmd->un.elsreq64.myID = vport->fc_myDID;
 
                /* For ELS_REQUEST64_CR, use the VPI by default */
-               icmd->ulpContext = vport->vpi;
+               icmd->ulpContext = vport->vpi + phba->vpi_base;
                icmd->ulpCt_h = 0;
                /* The CT field must be 0=INVALID_RPI for the ECHO cmd */
                if (elscmd == ELS_CMD_ECHO)
@@ -305,7 +308,7 @@ els_iocb_free_pcmb_exit:
  *   0 - successfully issued fabric registration login for @vport
  *   -ENXIO -- failed to issue fabric registration login for @vport
  **/
-static int
+int
 lpfc_issue_fabric_reglogin(struct lpfc_vport *vport)
 {
        struct lpfc_hba  *phba = vport->phba;
@@ -345,8 +348,7 @@ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport)
                err = 4;
                goto fail;
        }
-       rc = lpfc_reg_login(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox,
-                           0);
+       rc = lpfc_reg_rpi(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox, 0);
        if (rc) {
                err = 5;
                goto fail_free_mbox;
@@ -385,6 +387,75 @@ fail:
        return -ENXIO;
 }
 
+/**
+ * lpfc_issue_reg_vfi - Register VFI for this vport's fabric login
+ * @vport: pointer to a host virtual N_Port data structure.
+ *
+ * This routine issues a REG_VFI mailbox for the vfi, vpi, fcfi triplet for
+ * the @vport. This mailbox command is necessary for FCoE only.
+ *
+ * Return code
+ *   0 - successfully issued REG_VFI for @vport
+ *   A failure code otherwise.
+ **/
+static int
+lpfc_issue_reg_vfi(struct lpfc_vport *vport)
+{
+       struct lpfc_hba  *phba = vport->phba;
+       LPFC_MBOXQ_t *mboxq;
+       struct lpfc_nodelist *ndlp;
+       struct serv_parm *sp;
+       struct lpfc_dmabuf *dmabuf;
+       int rc = 0;
+
+       sp = &phba->fc_fabparam;
+       ndlp = lpfc_findnode_did(vport, Fabric_DID);
+       if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) {
+               rc = -ENODEV;
+               goto fail;
+       }
+
+       dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+       if (!dmabuf) {
+               rc = -ENOMEM;
+               goto fail;
+       }
+       dmabuf->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &dmabuf->phys);
+       if (!dmabuf->virt) {
+               rc = -ENOMEM;
+               goto fail_free_dmabuf;
+       }
+       mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mboxq) {
+               rc = -ENOMEM;
+               goto fail_free_coherent;
+       }
+       vport->port_state = LPFC_FABRIC_CFG_LINK;
+       memcpy(dmabuf->virt, &phba->fc_fabparam, sizeof(vport->fc_sparam));
+       lpfc_reg_vfi(mboxq, vport, dmabuf->phys);
+       mboxq->mbox_cmpl = lpfc_mbx_cmpl_reg_vfi;
+       mboxq->vport = vport;
+       mboxq->context1 = dmabuf;
+       rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
+       if (rc == MBX_NOT_FINISHED) {
+               rc = -ENXIO;
+               goto fail_free_mbox;
+       }
+       return 0;
+
+fail_free_mbox:
+       mempool_free(mboxq, phba->mbox_mem_pool);
+fail_free_coherent:
+       lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
+fail_free_dmabuf:
+       kfree(dmabuf);
+fail:
+       lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+       lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+               "0289 Issue Register VFI failed: Err %d\n", rc);
+       return rc;
+}
+
 /**
  * lpfc_cmpl_els_flogi_fabric - Completion function for flogi to a fabric port
  * @vport: pointer to a host virtual N_Port data structure.
@@ -497,17 +568,24 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                }
        }
 
-       lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE);
-
-       if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED &&
-           vport->fc_flag & FC_VPORT_NEEDS_REG_VPI) {
-               lpfc_register_new_vport(phba, vport, ndlp);
-               return 0;
+       if (phba->sli_rev < LPFC_SLI_REV4) {
+               lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE);
+               if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED &&
+                   vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)
+                       lpfc_register_new_vport(phba, vport, ndlp);
+               else
+                       lpfc_issue_fabric_reglogin(vport);
+       } else {
+               ndlp->nlp_type |= NLP_FABRIC;
+               lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
+               if (vport->vfi_state & LPFC_VFI_REGISTERED) {
+                       lpfc_start_fdiscs(phba);
+                       lpfc_do_scr_ns_plogi(phba, vport);
+               } else
+                       lpfc_issue_reg_vfi(vport);
        }
-       lpfc_issue_fabric_reglogin(vport);
        return 0;
 }
-
 /**
  * lpfc_cmpl_els_flogi_nport - Completion function for flogi to an N_Port
  * @vport: pointer to a host virtual N_Port data structure.
@@ -815,9 +893,14 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        if (sp->cmn.fcphHigh < FC_PH3)
                sp->cmn.fcphHigh = FC_PH3;
 
-       if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
+       if  (phba->sli_rev == LPFC_SLI_REV4) {
+               elsiocb->iocb.ulpCt_h = ((SLI4_CT_FCFI >> 1) & 1);
+               elsiocb->iocb.ulpCt_l = (SLI4_CT_FCFI & 1);
+               /* FLOGI needs to be 3 for WQE FCFI */
+               /* Set the fcfi to the fcfi we registered with */
+               elsiocb->iocb.ulpContext = phba->fcf.fcfi;
+       } else if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
                sp->cmn.request_multiple_Nport = 1;
-
                /* For FLOGI, Let FLOGI rsp set the NPortID for VPI 0 */
                icmd->ulpCt_h = 1;
                icmd->ulpCt_l = 0;
@@ -930,6 +1013,8 @@ lpfc_initial_flogi(struct lpfc_vport *vport)
                if (!ndlp)
                        return 0;
                lpfc_nlp_init(vport, ndlp, Fabric_DID);
+               /* Set the node type */
+               ndlp->nlp_type |= NLP_FABRIC;
                /* Put ndlp onto node list */
                lpfc_enqueue_node(vport, ndlp);
        } else if (!NLP_CHK_NODE_ACT(ndlp)) {
@@ -1350,14 +1435,12 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
        IOCB_t *icmd;
        struct lpfc_nodelist *ndlp;
        struct lpfc_iocbq *elsiocb;
-       struct lpfc_sli_ring *pring;
        struct lpfc_sli *psli;
        uint8_t *pcmd;
        uint16_t cmdsize;
        int ret;
 
        psli = &phba->sli;
-       pring = &psli->ring[LPFC_ELS_RING];     /* ELS ring */
 
        ndlp = lpfc_findnode_did(vport, did);
        if (ndlp && !NLP_CHK_NODE_ACT(ndlp))
@@ -1391,7 +1474,7 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
 
        phba->fc_stat.elsXmitPLOGI++;
        elsiocb->iocb_cmpl = lpfc_cmpl_els_plogi;
-       ret = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+       ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
 
        if (ret == IOCB_ERROR) {
                lpfc_els_free_iocb(phba, elsiocb);
@@ -1501,14 +1584,9 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        PRLI *npr;
        IOCB_t *icmd;
        struct lpfc_iocbq *elsiocb;
-       struct lpfc_sli_ring *pring;
-       struct lpfc_sli *psli;
        uint8_t *pcmd;
        uint16_t cmdsize;
 
-       psli = &phba->sli;
-       pring = &psli->ring[LPFC_ELS_RING];     /* ELS ring */
-
        cmdsize = (sizeof(uint32_t) + sizeof(PRLI));
        elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
                                     ndlp->nlp_DID, ELS_CMD_PRLI);
@@ -1550,7 +1628,8 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        spin_lock_irq(shost->host_lock);
        ndlp->nlp_flag |= NLP_PRLI_SND;
        spin_unlock_irq(shost->host_lock);
-       if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+       if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) ==
+           IOCB_ERROR) {
                spin_lock_irq(shost->host_lock);
                ndlp->nlp_flag &= ~NLP_PRLI_SND;
                spin_unlock_irq(shost->host_lock);
@@ -1608,7 +1687,8 @@ lpfc_adisc_done(struct lpfc_vport *vport)
         * and continue discovery.
         */
        if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
-           !(vport->fc_flag & FC_RSCN_MODE)) {
+           !(vport->fc_flag & FC_RSCN_MODE) &&
+           (phba->sli_rev < LPFC_SLI_REV4)) {
                lpfc_issue_reg_vpi(phba, vport);
                return;
        }
@@ -1788,8 +1868,6 @@ lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        ADISC *ap;
        IOCB_t *icmd;
        struct lpfc_iocbq *elsiocb;
-       struct lpfc_sli *psli = &phba->sli;
-       struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
        uint8_t *pcmd;
        uint16_t cmdsize;
 
@@ -1822,7 +1900,8 @@ lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        spin_lock_irq(shost->host_lock);
        ndlp->nlp_flag |= NLP_ADISC_SND;
        spin_unlock_irq(shost->host_lock);
-       if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+       if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) ==
+           IOCB_ERROR) {
                spin_lock_irq(shost->host_lock);
                ndlp->nlp_flag &= ~NLP_ADISC_SND;
                spin_unlock_irq(shost->host_lock);
@@ -1937,15 +2016,10 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        struct lpfc_hba  *phba = vport->phba;
        IOCB_t *icmd;
        struct lpfc_iocbq *elsiocb;
-       struct lpfc_sli_ring *pring;
-       struct lpfc_sli *psli;
        uint8_t *pcmd;
        uint16_t cmdsize;
        int rc;
 
-       psli = &phba->sli;
-       pring = &psli->ring[LPFC_ELS_RING];
-
        spin_lock_irq(shost->host_lock);
        if (ndlp->nlp_flag & NLP_LOGO_SND) {
                spin_unlock_irq(shost->host_lock);
@@ -1978,7 +2052,7 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        spin_lock_irq(shost->host_lock);
        ndlp->nlp_flag |= NLP_LOGO_SND;
        spin_unlock_irq(shost->host_lock);
-       rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+       rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
 
        if (rc == IOCB_ERROR) {
                spin_lock_irq(shost->host_lock);
@@ -2058,14 +2132,12 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
        struct lpfc_hba  *phba = vport->phba;
        IOCB_t *icmd;
        struct lpfc_iocbq *elsiocb;
-       struct lpfc_sli_ring *pring;
        struct lpfc_sli *psli;
        uint8_t *pcmd;
        uint16_t cmdsize;
        struct lpfc_nodelist *ndlp;
 
        psli = &phba->sli;
-       pring = &psli->ring[LPFC_ELS_RING];     /* ELS ring */
        cmdsize = (sizeof(uint32_t) + sizeof(SCR));
 
        ndlp = lpfc_findnode_did(vport, nportid);
@@ -2108,7 +2180,8 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
 
        phba->fc_stat.elsXmitSCR++;
        elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
-       if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+       if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) ==
+           IOCB_ERROR) {
                /* The additional lpfc_nlp_put will cause the following
                 * lpfc_els_free_iocb routine to trigger the rlease of
                 * the node.
@@ -2152,7 +2225,6 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
        struct lpfc_hba  *phba = vport->phba;
        IOCB_t *icmd;
        struct lpfc_iocbq *elsiocb;
-       struct lpfc_sli_ring *pring;
        struct lpfc_sli *psli;
        FARP *fp;
        uint8_t *pcmd;
@@ -2162,7 +2234,6 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
        struct lpfc_nodelist *ndlp;
 
        psli = &phba->sli;
-       pring = &psli->ring[LPFC_ELS_RING];     /* ELS ring */
        cmdsize = (sizeof(uint32_t) + sizeof(FARP));
 
        ndlp = lpfc_findnode_did(vport, nportid);
@@ -2219,7 +2290,8 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
 
        phba->fc_stat.elsXmitFARPR++;
        elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
-       if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+       if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) ==
+           IOCB_ERROR) {
                /* The additional lpfc_nlp_put will cause the following
                 * lpfc_els_free_iocb routine to trigger the release of
                 * the node.
@@ -2949,6 +3021,14 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
        struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
 
+       /*
+        * This routine is used to register and unregister in previous SLI
+        * modes.
+        */
+       if ((pmb->u.mb.mbxCommand == MBX_UNREG_LOGIN) &&
+           (phba->sli_rev == LPFC_SLI_REV4))
+               lpfc_sli4_free_rpi(phba, pmb->u.mb.un.varUnregLogin.rpi);
+
        pmb->context1 = NULL;
        lpfc_mbuf_free(phba, mp->virt, mp->phys);
        kfree(mp);
@@ -2961,6 +3041,7 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                 */
                lpfc_nlp_not_used(ndlp);
        }
+
        return;
 }
 
@@ -3170,7 +3251,6 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
        IOCB_t *icmd;
        IOCB_t *oldcmd;
        struct lpfc_iocbq *elsiocb;
-       struct lpfc_sli_ring *pring;
        struct lpfc_sli *psli;
        uint8_t *pcmd;
        uint16_t cmdsize;
@@ -3178,7 +3258,6 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
        ELS_PKT *els_pkt_ptr;
 
        psli = &phba->sli;
-       pring = &psli->ring[LPFC_ELS_RING];     /* ELS ring */
        oldcmd = &oldiocb->iocb;
 
        switch (flag) {
@@ -3266,7 +3345,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
        }
 
        phba->fc_stat.elsXmitACC++;
-       rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+       rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
        if (rc == IOCB_ERROR) {
                lpfc_els_free_iocb(phba, elsiocb);
                return 1;
@@ -3305,15 +3384,12 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
        IOCB_t *icmd;
        IOCB_t *oldcmd;
        struct lpfc_iocbq *elsiocb;
-       struct lpfc_sli_ring *pring;
        struct lpfc_sli *psli;
        uint8_t *pcmd;
        uint16_t cmdsize;
        int rc;
 
        psli = &phba->sli;
-       pring = &psli->ring[LPFC_ELS_RING];     /* ELS ring */
-
        cmdsize = 2 * sizeof(uint32_t);
        elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
                                     ndlp->nlp_DID, ELS_CMD_LS_RJT);
@@ -3346,7 +3422,7 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
 
        phba->fc_stat.elsXmitLSRJT++;
        elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
-       rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+       rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
 
        if (rc == IOCB_ERROR) {
                lpfc_els_free_iocb(phba, elsiocb);
@@ -3379,8 +3455,6 @@ lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
                       struct lpfc_nodelist *ndlp)
 {
        struct lpfc_hba  *phba = vport->phba;
-       struct lpfc_sli  *psli = &phba->sli;
-       struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
        ADISC *ap;
        IOCB_t *icmd, *oldcmd;
        struct lpfc_iocbq *elsiocb;
@@ -3422,7 +3496,7 @@ lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
 
        phba->fc_stat.elsXmitACC++;
        elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
-       rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+       rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
        if (rc == IOCB_ERROR) {
                lpfc_els_free_iocb(phba, elsiocb);
                return 1;
@@ -3459,14 +3533,12 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
        IOCB_t *icmd;
        IOCB_t *oldcmd;
        struct lpfc_iocbq *elsiocb;
-       struct lpfc_sli_ring *pring;
        struct lpfc_sli *psli;
        uint8_t *pcmd;
        uint16_t cmdsize;
        int rc;
 
        psli = &phba->sli;
-       pring = &psli->ring[LPFC_ELS_RING];     /* ELS ring */
 
        cmdsize = sizeof(uint32_t) + sizeof(PRLI);
        elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
@@ -3520,7 +3592,7 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
        phba->fc_stat.elsXmitACC++;
        elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
 
-       rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+       rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
        if (rc == IOCB_ERROR) {
                lpfc_els_free_iocb(phba, elsiocb);
                return 1;
@@ -3562,15 +3634,12 @@ lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format,
        RNID *rn;
        IOCB_t *icmd, *oldcmd;
        struct lpfc_iocbq *elsiocb;
-       struct lpfc_sli_ring *pring;
        struct lpfc_sli *psli;
        uint8_t *pcmd;
        uint16_t cmdsize;
        int rc;
 
        psli = &phba->sli;
-       pring = &psli->ring[LPFC_ELS_RING];
-
        cmdsize = sizeof(uint32_t) + sizeof(uint32_t)
                                        + (2 * sizeof(struct lpfc_name));
        if (format)
@@ -3626,7 +3695,7 @@ lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format,
        elsiocb->context1 = NULL;  /* Don't need ndlp for cmpl,
                                    * it could be freed */
 
-       rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+       rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
        if (rc == IOCB_ERROR) {
                lpfc_els_free_iocb(phba, elsiocb);
                return 1;
@@ -3839,7 +3908,9 @@ lpfc_rscn_payload_check(struct lpfc_vport *vport, uint32_t did)
                        payload_len -= sizeof(uint32_t);
                        switch (rscn_did.un.b.resv & RSCN_ADDRESS_FORMAT_MASK) {
                        case RSCN_ADDRESS_FORMAT_PORT:
-                               if (ns_did.un.word == rscn_did.un.word)
+                               if ((ns_did.un.b.domain == rscn_did.un.b.domain)
+                                   && (ns_did.un.b.area == rscn_did.un.b.area)
+                                   && (ns_did.un.b.id == rscn_did.un.b.id))
                                        goto return_did_out;
                                break;
                        case RSCN_ADDRESS_FORMAT_AREA:
@@ -4300,7 +4371,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
                        lpfc_init_link(phba, mbox,
                                       phba->cfg_topology,
                                       phba->cfg_link_speed);
-                       mbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
+                       mbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0;
                        mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
                        mbox->vport = vport;
                        rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
@@ -4440,8 +4511,6 @@ lpfc_els_rcv_lirr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
 static void
 lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
-       struct lpfc_sli *psli = &phba->sli;
-       struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
        MAILBOX_t *mb;
        IOCB_t *icmd;
        RPS_RSP *rps_rsp;
@@ -4451,7 +4520,7 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        uint16_t xri, status;
        uint32_t cmdsize;
 
-       mb = &pmb->mb;
+       mb = &pmb->u.mb;
 
        ndlp = (struct lpfc_nodelist *) pmb->context2;
        xri = (uint16_t) ((unsigned long)(pmb->context1));
@@ -4507,7 +4576,7 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                         ndlp->nlp_rpi);
        elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
        phba->fc_stat.elsXmitACC++;
-       if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR)
+       if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == IOCB_ERROR)
                lpfc_els_free_iocb(phba, elsiocb);
        return;
 }
@@ -4616,8 +4685,6 @@ lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize,
        IOCB_t *icmd, *oldcmd;
        RPL_RSP rpl_rsp;
        struct lpfc_iocbq *elsiocb;
-       struct lpfc_sli *psli = &phba->sli;
-       struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
        uint8_t *pcmd;
 
        elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
@@ -4654,7 +4721,8 @@ lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize,
                         ndlp->nlp_rpi);
        elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
        phba->fc_stat.elsXmitACC++;
-       if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+       if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) ==
+           IOCB_ERROR) {
                lpfc_els_free_iocb(phba, elsiocb);
                return 1;
        }
@@ -4883,7 +4951,10 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
                } else {
                        /* FAN verified - skip FLOGI */
                        vport->fc_myDID = vport->fc_prevDID;
-                       lpfc_issue_fabric_reglogin(vport);
+                       if (phba->sli_rev < LPFC_SLI_REV4)
+                               lpfc_issue_fabric_reglogin(vport);
+                       else
+                               lpfc_issue_reg_vfi(vport);
                }
        }
        return 0;
@@ -5566,11 +5637,10 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 
 dropit:
        if (vport && !(vport->load_flag & FC_UNLOADING))
-               lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-                       "(%d):0111 Dropping received ELS cmd "
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+                       "0111 Dropping received ELS cmd "
                        "Data: x%x x%x x%x\n",
-                       vport->vpi, icmd->ulpStatus,
-                       icmd->un.ulpWord[4], icmd->ulpTimeout);
+                       icmd->ulpStatus, icmd->un.ulpWord[4], icmd->ulpTimeout);
        phba->fc_stat.elsRcvDrop++;
 }
 
@@ -5646,10 +5716,9 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
             icmd->ulpCommand == CMD_IOCB_RCV_SEQ64_CX)) {
                if (icmd->unsli3.rcvsli3.vpi == 0xffff)
                        vport = phba->pport;
-               else {
-                       uint16_t vpi = icmd->unsli3.rcvsli3.vpi;
-                       vport = lpfc_find_vport_by_vpid(phba, vpi);
-               }
+               else
+                       vport = lpfc_find_vport_by_vpid(phba,
+                               icmd->unsli3.rcvsli3.vpi - phba->vpi_base);
        }
        /* If there are no BDEs associated
         * with this IOCB, there is nothing to do.
@@ -5781,7 +5850,7 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        struct lpfc_vport *vport = pmb->vport;
        struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
        struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
-       MAILBOX_t *mb = &pmb->mb;
+       MAILBOX_t *mb = &pmb->u.mb;
 
        spin_lock_irq(shost->host_lock);
        vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
@@ -5818,7 +5887,10 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 
        } else {
                if (vport == phba->pport)
-                       lpfc_issue_fabric_reglogin(vport);
+                       if (phba->sli_rev < LPFC_SLI_REV4)
+                               lpfc_issue_fabric_reglogin(vport);
+                       else
+                               lpfc_issue_reg_vfi(vport);
                else
                        lpfc_do_scr_ns_plogi(phba, vport);
        }
@@ -5850,7 +5922,7 @@ lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport,
 
        mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (mbox) {
-               lpfc_reg_vpi(phba, vport->vpi, vport->fc_myDID, mbox);
+               lpfc_reg_vpi(vport, mbox);
                mbox->vport = vport;
                mbox->context2 = lpfc_nlp_get(ndlp);
                mbox->mbox_cmpl = lpfc_cmpl_reg_new_vport;
@@ -6139,7 +6211,6 @@ lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
 {
        struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
        struct lpfc_hba  *phba = vport->phba;
-       struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
        IOCB_t *icmd;
        struct lpfc_iocbq *elsiocb;
        uint8_t *pcmd;
@@ -6169,7 +6240,8 @@ lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
        spin_lock_irq(shost->host_lock);
        ndlp->nlp_flag |= NLP_LOGO_SND;
        spin_unlock_irq(shost->host_lock);
-       if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+       if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) ==
+           IOCB_ERROR) {
                spin_lock_irq(shost->host_lock);
                ndlp->nlp_flag &= ~NLP_LOGO_SND;
                spin_unlock_irq(shost->host_lock);
@@ -6224,7 +6296,6 @@ lpfc_resume_fabric_iocbs(struct lpfc_hba *phba)
        struct lpfc_iocbq *iocb;
        unsigned long iflags;
        int ret;
-       struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
        IOCB_t *cmd;
 
 repeat:
@@ -6248,7 +6319,7 @@ repeat:
                        "Fabric sched1:   ste:x%x",
                        iocb->vport->port_state, 0, 0);
 
-               ret = lpfc_sli_issue_iocb(phba, pring, iocb, 0);
+               ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, iocb, 0);
 
                if (ret == IOCB_ERROR) {
                        iocb->iocb_cmpl = iocb->fabric_iocb_cmpl;
@@ -6394,7 +6465,6 @@ static int
 lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb)
 {
        unsigned long iflags;
-       struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
        int ready;
        int ret;
 
@@ -6418,7 +6488,7 @@ lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb)
                        "Fabric sched2:   ste:x%x",
                        iocb->vport->port_state, 0, 0);
 
-               ret = lpfc_sli_issue_iocb(phba, pring, iocb, 0);
+               ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, iocb, 0);
 
                if (ret == IOCB_ERROR) {
                        iocb->iocb_cmpl = iocb->fabric_iocb_cmpl;
@@ -6524,3 +6594,38 @@ void lpfc_fabric_abort_hba(struct lpfc_hba *phba)
        lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
                              IOERR_SLI_ABORTED);
 }
+
+/**
+ * lpfc_sli4_els_xri_aborted - Slow-path process of els xri abort
+ * @phba: pointer to lpfc hba data structure.
+ * @axri: pointer to the els xri abort wcqe structure.
+ *
+ * This routine is invoked by the worker thread to process a SLI4 slow-path
+ * ELS aborted xri.
+ **/
+void
+lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba,
+                         struct sli4_wcqe_xri_aborted *axri)
+{
+       uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri);
+       struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL;
+       unsigned long iflag = 0;
+
+       spin_lock_irqsave(&phba->sli4_hba.abts_sgl_list_lock, iflag);
+       list_for_each_entry_safe(sglq_entry, sglq_next,
+                       &phba->sli4_hba.lpfc_abts_els_sgl_list, list) {
+               if (sglq_entry->sli4_xritag == xri) {
+                       list_del(&sglq_entry->list);
+                       spin_unlock_irqrestore(
+                                       &phba->sli4_hba.abts_sgl_list_lock,
+                                        iflag);
+                       spin_lock_irqsave(&phba->hbalock, iflag);
+
+                       list_add_tail(&sglq_entry->list,
+                               &phba->sli4_hba.lpfc_sgl_list);
+                       spin_unlock_irqrestore(&phba->hbalock, iflag);
+                       return;
+               }
+       }
+       spin_unlock_irqrestore(&phba->sli4_hba.abts_sgl_list_lock, iflag);
+}
index e764ce0bf7049e2f074bc8d00e1b8d329504e489..35c41ae75be248a15f7344734f1b77210b99bedf 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport_fc.h>
 
+#include "lpfc_hw4.h"
 #include "lpfc_hw.h"
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_sli.h"
+#include "lpfc_sli4.h"
 #include "lpfc_scsi.h"
 #include "lpfc.h"
 #include "lpfc_logmsg.h"
@@ -273,6 +275,8 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
            !(ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
            (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE))
                lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
+
+       lpfc_unregister_unused_fcf(phba);
 }
 
 /**
@@ -295,10 +299,11 @@ lpfc_alloc_fast_evt(struct lpfc_hba *phba) {
 
        ret = kzalloc(sizeof(struct lpfc_fast_path_event),
                        GFP_ATOMIC);
-       if (ret)
+       if (ret) {
                atomic_inc(&phba->fast_event_count);
-       INIT_LIST_HEAD(&ret->work_evt.evt_listp);
-       ret->work_evt.evt = LPFC_EVT_FASTPATH_MGMT_EVT;
+               INIT_LIST_HEAD(&ret->work_evt.evt_listp);
+               ret->work_evt.evt = LPFC_EVT_FASTPATH_MGMT_EVT;
+       }
        return ret;
 }
 
@@ -491,6 +496,10 @@ lpfc_work_done(struct lpfc_hba *phba)
        phba->work_ha = 0;
        spin_unlock_irq(&phba->hbalock);
 
+       /* First, try to post the next mailbox command to SLI4 device */
+       if (phba->pci_dev_grp == LPFC_PCI_DEV_OC)
+               lpfc_sli4_post_async_mbox(phba);
+
        if (ha_copy & HA_ERATT)
                /* Handle the error attention event */
                lpfc_handle_eratt(phba);
@@ -501,9 +510,27 @@ lpfc_work_done(struct lpfc_hba *phba)
        if (ha_copy & HA_LATT)
                lpfc_handle_latt(phba);
 
+       /* Process SLI4 events */
+       if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) {
+               if (phba->hba_flag & FCP_XRI_ABORT_EVENT)
+                       lpfc_sli4_fcp_xri_abort_event_proc(phba);
+               if (phba->hba_flag & ELS_XRI_ABORT_EVENT)
+                       lpfc_sli4_els_xri_abort_event_proc(phba);
+               if (phba->hba_flag & ASYNC_EVENT)
+                       lpfc_sli4_async_event_proc(phba);
+               if (phba->hba_flag & HBA_POST_RECEIVE_BUFFER) {
+                       spin_lock_irq(&phba->hbalock);
+                       phba->hba_flag &= ~HBA_POST_RECEIVE_BUFFER;
+                       spin_unlock_irq(&phba->hbalock);
+                       lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
+               }
+               if (phba->hba_flag & HBA_RECEIVE_BUFFER)
+                       lpfc_sli4_handle_received_buffer(phba);
+       }
+
        vports = lpfc_create_vport_work_array(phba);
        if (vports != NULL)
-               for(i = 0; i <= phba->max_vpi; i++) {
+               for (i = 0; i <= phba->max_vports; i++) {
                        /*
                         * We could have no vports in array if unloading, so if
                         * this happens then just use the pport
@@ -555,23 +582,24 @@ lpfc_work_done(struct lpfc_hba *phba)
                /*
                 * Turn on Ring interrupts
                 */
-               spin_lock_irq(&phba->hbalock);
-               control = readl(phba->HCregaddr);
-               if (!(control & (HC_R0INT_ENA << LPFC_ELS_RING))) {
-                       lpfc_debugfs_slow_ring_trc(phba,
-                               "WRK Enable ring: cntl:x%x hacopy:x%x",
-                               control, ha_copy, 0);
-
-                       control |= (HC_R0INT_ENA << LPFC_ELS_RING);
-                       writel(control, phba->HCregaddr);
-                       readl(phba->HCregaddr); /* flush */
-               }
-               else {
-                       lpfc_debugfs_slow_ring_trc(phba,
-                               "WRK Ring ok:     cntl:x%x hacopy:x%x",
-                               control, ha_copy, 0);
+               if (phba->sli_rev <= LPFC_SLI_REV3) {
+                       spin_lock_irq(&phba->hbalock);
+                       control = readl(phba->HCregaddr);
+                       if (!(control & (HC_R0INT_ENA << LPFC_ELS_RING))) {
+                               lpfc_debugfs_slow_ring_trc(phba,
+                                       "WRK Enable ring: cntl:x%x hacopy:x%x",
+                                       control, ha_copy, 0);
+
+                               control |= (HC_R0INT_ENA << LPFC_ELS_RING);
+                               writel(control, phba->HCregaddr);
+                               readl(phba->HCregaddr); /* flush */
+                       } else {
+                               lpfc_debugfs_slow_ring_trc(phba,
+                                       "WRK Ring ok:     cntl:x%x hacopy:x%x",
+                                       control, ha_copy, 0);
+                       }
+                       spin_unlock_irq(&phba->hbalock);
                }
-               spin_unlock_irq(&phba->hbalock);
        }
        lpfc_work_list_done(phba);
 }
@@ -689,7 +717,7 @@ lpfc_port_link_failure(struct lpfc_vport *vport)
        lpfc_can_disctmo(vport);
 }
 
-static void
+void
 lpfc_linkdown_port(struct lpfc_vport *vport)
 {
        struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
@@ -716,6 +744,7 @@ lpfc_linkdown(struct lpfc_hba *phba)
        if (phba->link_state == LPFC_LINK_DOWN)
                return 0;
        spin_lock_irq(&phba->hbalock);
+       phba->fcf.fcf_flag &= ~(FCF_AVAILABLE | FCF_DISCOVERED);
        if (phba->link_state > LPFC_LINK_DOWN) {
                phba->link_state = LPFC_LINK_DOWN;
                phba->pport->fc_flag &= ~FC_LBIT;
@@ -723,7 +752,7 @@ lpfc_linkdown(struct lpfc_hba *phba)
        spin_unlock_irq(&phba->hbalock);
        vports = lpfc_create_vport_work_array(phba);
        if (vports != NULL)
-               for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+               for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
                        /* Issue a LINK DOWN event to all nodes */
                        lpfc_linkdown_port(vports[i]);
                }
@@ -833,10 +862,11 @@ lpfc_linkup(struct lpfc_hba *phba)
 
        vports = lpfc_create_vport_work_array(phba);
        if (vports != NULL)
-               for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++)
+               for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++)
                        lpfc_linkup_port(vports[i]);
        lpfc_destroy_vport_work_array(phba, vports);
-       if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
+       if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
+           (phba->sli_rev < LPFC_SLI_REV4))
                lpfc_issue_clear_la(phba, phba->pport);
 
        return 0;
@@ -854,7 +884,7 @@ lpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        struct lpfc_vport *vport = pmb->vport;
        struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
        struct lpfc_sli   *psli = &phba->sli;
-       MAILBOX_t *mb = &pmb->mb;
+       MAILBOX_t *mb = &pmb->u.mb;
        uint32_t control;
 
        /* Since we don't do discovery right now, turn these off here */
@@ -917,7 +947,7 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
        struct lpfc_vport *vport = pmb->vport;
 
-       if (pmb->mb.mbxStatus)
+       if (pmb->u.mb.mbxStatus)
                goto out;
 
        mempool_free(pmb, phba->mbox_mem_pool);
@@ -945,7 +975,7 @@ out:
        lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
                         "0306 CONFIG_LINK mbxStatus error x%x "
                         "HBA state x%x\n",
-                        pmb->mb.mbxStatus, vport->port_state);
+                        pmb->u.mb.mbxStatus, vport->port_state);
        mempool_free(pmb, phba->mbox_mem_pool);
 
        lpfc_linkdown(phba);
@@ -958,10 +988,593 @@ out:
        return;
 }
 
+static void
+lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+{
+       struct lpfc_vport *vport = mboxq->vport;
+       unsigned long flags;
+
+       if (mboxq->u.mb.mbxStatus) {
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+                        "2017 REG_FCFI mbxStatus error x%x "
+                        "HBA state x%x\n",
+                        mboxq->u.mb.mbxStatus, vport->port_state);
+               mempool_free(mboxq, phba->mbox_mem_pool);
+               return;
+       }
+
+       /* Start FCoE discovery by sending a FLOGI. */
+       phba->fcf.fcfi = bf_get(lpfc_reg_fcfi_fcfi, &mboxq->u.mqe.un.reg_fcfi);
+       /* Set the FCFI registered flag */
+       spin_lock_irqsave(&phba->hbalock, flags);
+       phba->fcf.fcf_flag |= FCF_REGISTERED;
+       spin_unlock_irqrestore(&phba->hbalock, flags);
+       if (vport->port_state != LPFC_FLOGI) {
+               spin_lock_irqsave(&phba->hbalock, flags);
+               phba->fcf.fcf_flag |= (FCF_DISCOVERED | FCF_IN_USE);
+               spin_unlock_irqrestore(&phba->hbalock, flags);
+               lpfc_initial_flogi(vport);
+       }
+
+       mempool_free(mboxq, phba->mbox_mem_pool);
+       return;
+}
+
+/**
+ * lpfc_fab_name_match - Check if the fcf fabric name match.
+ * @fab_name: pointer to fabric name.
+ * @new_fcf_record: pointer to fcf record.
+ *
+ * This routine compare the fcf record's fabric name with provided
+ * fabric name. If the fabric name are identical this function
+ * returns 1 else return 0.
+ **/
+static uint32_t
+lpfc_fab_name_match(uint8_t *fab_name, struct fcf_record *new_fcf_record)
+{
+       if ((fab_name[0] ==
+               bf_get(lpfc_fcf_record_fab_name_0, new_fcf_record)) &&
+           (fab_name[1] ==
+               bf_get(lpfc_fcf_record_fab_name_1, new_fcf_record)) &&
+           (fab_name[2] ==
+               bf_get(lpfc_fcf_record_fab_name_2, new_fcf_record)) &&
+           (fab_name[3] ==
+               bf_get(lpfc_fcf_record_fab_name_3, new_fcf_record)) &&
+           (fab_name[4] ==
+               bf_get(lpfc_fcf_record_fab_name_4, new_fcf_record)) &&
+           (fab_name[5] ==
+               bf_get(lpfc_fcf_record_fab_name_5, new_fcf_record)) &&
+           (fab_name[6] ==
+               bf_get(lpfc_fcf_record_fab_name_6, new_fcf_record)) &&
+           (fab_name[7] ==
+               bf_get(lpfc_fcf_record_fab_name_7, new_fcf_record)))
+               return 1;
+       else
+               return 0;
+}
+
+/**
+ * lpfc_mac_addr_match - Check if the fcf mac address match.
+ * @phba: pointer to lpfc hba data structure.
+ * @new_fcf_record: pointer to fcf record.
+ *
+ * This routine compare the fcf record's mac address with HBA's
+ * FCF mac address. If the mac addresses are identical this function
+ * returns 1 else return 0.
+ **/
+static uint32_t
+lpfc_mac_addr_match(struct lpfc_hba *phba, struct fcf_record *new_fcf_record)
+{
+       if ((phba->fcf.mac_addr[0] ==
+               bf_get(lpfc_fcf_record_mac_0, new_fcf_record)) &&
+           (phba->fcf.mac_addr[1] ==
+               bf_get(lpfc_fcf_record_mac_1, new_fcf_record)) &&
+           (phba->fcf.mac_addr[2] ==
+               bf_get(lpfc_fcf_record_mac_2, new_fcf_record)) &&
+           (phba->fcf.mac_addr[3] ==
+               bf_get(lpfc_fcf_record_mac_3, new_fcf_record)) &&
+           (phba->fcf.mac_addr[4] ==
+               bf_get(lpfc_fcf_record_mac_4, new_fcf_record)) &&
+           (phba->fcf.mac_addr[5] ==
+               bf_get(lpfc_fcf_record_mac_5, new_fcf_record)))
+               return 1;
+       else
+               return 0;
+}
+
+/**
+ * lpfc_copy_fcf_record - Copy fcf information to lpfc_hba.
+ * @phba: pointer to lpfc hba data structure.
+ * @new_fcf_record: pointer to fcf record.
+ *
+ * This routine copies the FCF information from the FCF
+ * record to lpfc_hba data structure.
+ **/
+static void
+lpfc_copy_fcf_record(struct lpfc_hba *phba, struct fcf_record *new_fcf_record)
+{
+       phba->fcf.fabric_name[0] =
+               bf_get(lpfc_fcf_record_fab_name_0, new_fcf_record);
+       phba->fcf.fabric_name[1] =
+               bf_get(lpfc_fcf_record_fab_name_1, new_fcf_record);
+       phba->fcf.fabric_name[2] =
+               bf_get(lpfc_fcf_record_fab_name_2, new_fcf_record);
+       phba->fcf.fabric_name[3] =
+               bf_get(lpfc_fcf_record_fab_name_3, new_fcf_record);
+       phba->fcf.fabric_name[4] =
+               bf_get(lpfc_fcf_record_fab_name_4, new_fcf_record);
+       phba->fcf.fabric_name[5] =
+               bf_get(lpfc_fcf_record_fab_name_5, new_fcf_record);
+       phba->fcf.fabric_name[6] =
+               bf_get(lpfc_fcf_record_fab_name_6, new_fcf_record);
+       phba->fcf.fabric_name[7] =
+               bf_get(lpfc_fcf_record_fab_name_7, new_fcf_record);
+       phba->fcf.mac_addr[0] =
+               bf_get(lpfc_fcf_record_mac_0, new_fcf_record);
+       phba->fcf.mac_addr[1] =
+               bf_get(lpfc_fcf_record_mac_1, new_fcf_record);
+       phba->fcf.mac_addr[2] =
+               bf_get(lpfc_fcf_record_mac_2, new_fcf_record);
+       phba->fcf.mac_addr[3] =
+               bf_get(lpfc_fcf_record_mac_3, new_fcf_record);
+       phba->fcf.mac_addr[4] =
+               bf_get(lpfc_fcf_record_mac_4, new_fcf_record);
+       phba->fcf.mac_addr[5] =
+               bf_get(lpfc_fcf_record_mac_5, new_fcf_record);
+       phba->fcf.fcf_indx = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record);
+       phba->fcf.priority = new_fcf_record->fip_priority;
+}
+
+/**
+ * lpfc_register_fcf - Register the FCF with hba.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine issues a register fcfi mailbox command to register
+ * the fcf with HBA.
+ **/
+static void
+lpfc_register_fcf(struct lpfc_hba *phba)
+{
+       LPFC_MBOXQ_t *fcf_mbxq;
+       int rc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&phba->hbalock, flags);
+
+       /* If the FCF is not availabe do nothing. */
+       if (!(phba->fcf.fcf_flag & FCF_AVAILABLE)) {
+               spin_unlock_irqrestore(&phba->hbalock, flags);
+               return;
+       }
+
+       /* The FCF is already registered, start discovery */
+       if (phba->fcf.fcf_flag & FCF_REGISTERED) {
+               phba->fcf.fcf_flag |= (FCF_DISCOVERED | FCF_IN_USE);
+               spin_unlock_irqrestore(&phba->hbalock, flags);
+               if (phba->pport->port_state != LPFC_FLOGI)
+                       lpfc_initial_flogi(phba->pport);
+               return;
+       }
+       spin_unlock_irqrestore(&phba->hbalock, flags);
+
+       fcf_mbxq = mempool_alloc(phba->mbox_mem_pool,
+               GFP_KERNEL);
+       if (!fcf_mbxq)
+               return;
+
+       lpfc_reg_fcfi(phba, fcf_mbxq);
+       fcf_mbxq->vport = phba->pport;
+       fcf_mbxq->mbox_cmpl = lpfc_mbx_cmpl_reg_fcfi;
+       rc = lpfc_sli_issue_mbox(phba, fcf_mbxq, MBX_NOWAIT);
+       if (rc == MBX_NOT_FINISHED)
+               mempool_free(fcf_mbxq, phba->mbox_mem_pool);
+
+       return;
+}
+
+/**
+ * lpfc_match_fcf_conn_list - Check if the FCF record can be used for discovery.
+ * @phba: pointer to lpfc hba data structure.
+ * @new_fcf_record: pointer to fcf record.
+ * @boot_flag: Indicates if this record used by boot bios.
+ * @addr_mode: The address mode to be used by this FCF
+ *
+ * This routine compare the fcf record with connect list obtained from the
+ * config region to decide if this FCF can be used for SAN discovery. It returns
+ * 1 if this record can be used for SAN discovery else return zero. If this FCF
+ * record can be used for SAN discovery, the boot_flag will indicate if this FCF
+ * is used by boot bios and addr_mode will indicate the addressing mode to be
+ * used for this FCF when the function returns.
+ * If the FCF record need to be used with a particular vlan id, the vlan is
+ * set in the vlan_id on return of the function. If not VLAN tagging need to
+ * be used with the FCF vlan_id will be set to 0xFFFF;
+ **/
+static int
+lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
+                       struct fcf_record *new_fcf_record,
+                       uint32_t *boot_flag, uint32_t *addr_mode,
+                       uint16_t *vlan_id)
+{
+       struct lpfc_fcf_conn_entry *conn_entry;
+
+       if (!phba->cfg_enable_fip) {
+               *boot_flag = 0;
+               *addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov,
+                               new_fcf_record);
+               if (phba->valid_vlan)
+                       *vlan_id = phba->vlan_id;
+               else
+                       *vlan_id = 0xFFFF;
+               return 1;
+       }
+
+       /*
+        * If there are no FCF connection table entry, driver connect to all
+        * FCFs.
+        */
+       if (list_empty(&phba->fcf_conn_rec_list)) {
+               *boot_flag = 0;
+               *addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov,
+                       new_fcf_record);
+               *vlan_id = 0xFFFF;
+               return 1;
+       }
+
+       list_for_each_entry(conn_entry, &phba->fcf_conn_rec_list, list) {
+               if (!(conn_entry->conn_rec.flags & FCFCNCT_VALID))
+                       continue;
+
+               if ((conn_entry->conn_rec.flags & FCFCNCT_FBNM_VALID) &&
+                       !lpfc_fab_name_match(conn_entry->conn_rec.fabric_name,
+                               new_fcf_record))
+                       continue;
+
+               if (conn_entry->conn_rec.flags & FCFCNCT_VLAN_VALID) {
+                       /*
+                        * If the vlan bit map does not have the bit set for the
+                        * vlan id to be used, then it is not a match.
+                        */
+                       if (!(new_fcf_record->vlan_bitmap
+                               [conn_entry->conn_rec.vlan_tag / 8] &
+                               (1 << (conn_entry->conn_rec.vlan_tag % 8))))
+                               continue;
+               }
+
+               /*
+                * Check if the connection record specifies a required
+                * addressing mode.
+                */
+               if ((conn_entry->conn_rec.flags & FCFCNCT_AM_VALID) &&
+                       !(conn_entry->conn_rec.flags & FCFCNCT_AM_PREFERRED)) {
+
+                       /*
+                        * If SPMA required but FCF not support this continue.
+                        */
+                       if ((conn_entry->conn_rec.flags & FCFCNCT_AM_SPMA) &&
+                               !(bf_get(lpfc_fcf_record_mac_addr_prov,
+                                       new_fcf_record) & LPFC_FCF_SPMA))
+                               continue;
+
+                       /*
+                        * If FPMA required but FCF not support this continue.
+                        */
+                       if (!(conn_entry->conn_rec.flags & FCFCNCT_AM_SPMA) &&
+                               !(bf_get(lpfc_fcf_record_mac_addr_prov,
+                               new_fcf_record) & LPFC_FCF_FPMA))
+                               continue;
+               }
+
+               /*
+                * This fcf record matches filtering criteria.
+                */
+               if (conn_entry->conn_rec.flags & FCFCNCT_BOOT)
+                       *boot_flag = 1;
+               else
+                       *boot_flag = 0;
+
+               *addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov,
+                               new_fcf_record);
+               /*
+                * If the user specified a required address mode, assign that
+                * address mode
+                */
+               if ((conn_entry->conn_rec.flags & FCFCNCT_AM_VALID) &&
+                       (!(conn_entry->conn_rec.flags & FCFCNCT_AM_PREFERRED)))
+                       *addr_mode = (conn_entry->conn_rec.flags &
+                               FCFCNCT_AM_SPMA) ?
+                               LPFC_FCF_SPMA : LPFC_FCF_FPMA;
+               /*
+                * If the user specified a prefered address mode, use the
+                * addr mode only if FCF support the addr_mode.
+                */
+               else if ((conn_entry->conn_rec.flags & FCFCNCT_AM_VALID) &&
+                       (conn_entry->conn_rec.flags & FCFCNCT_AM_PREFERRED) &&
+                       (conn_entry->conn_rec.flags & FCFCNCT_AM_SPMA) &&
+                       (*addr_mode & LPFC_FCF_SPMA))
+                               *addr_mode = LPFC_FCF_SPMA;
+               else if ((conn_entry->conn_rec.flags & FCFCNCT_AM_VALID) &&
+                       (conn_entry->conn_rec.flags & FCFCNCT_AM_PREFERRED) &&
+                       !(conn_entry->conn_rec.flags & FCFCNCT_AM_SPMA) &&
+                       (*addr_mode & LPFC_FCF_FPMA))
+                               *addr_mode = LPFC_FCF_FPMA;
+               /*
+                * If user did not specify any addressing mode, use FPMA if
+                * possible else use SPMA.
+                */
+               else if (*addr_mode & LPFC_FCF_FPMA)
+                       *addr_mode = LPFC_FCF_FPMA;
+
+               if (conn_entry->conn_rec.flags & FCFCNCT_VLAN_VALID)
+                       *vlan_id = conn_entry->conn_rec.vlan_tag;
+               else
+                       *vlan_id = 0xFFFF;
+
+               return 1;
+       }
+
+       return 0;
+}
+
+/**
+ * lpfc_mbx_cmpl_read_fcf_record - Completion handler for read_fcf mbox.
+ * @phba: pointer to lpfc hba data structure.
+ * @mboxq: pointer to mailbox object.
+ *
+ * This function iterate through all the fcf records available in
+ * HBA and choose the optimal FCF record for discovery. After finding
+ * the FCF for discovery it register the FCF record and kick start
+ * discovery.
+ * If FCF_IN_USE flag is set in currently used FCF, the routine try to
+ * use a FCF record which match fabric name and mac address of the
+ * currently used FCF record.
+ * If the driver support only one FCF, it will try to use the FCF record
+ * used by BOOT_BIOS.
+ */
+void
+lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+{
+       void *virt_addr;
+       dma_addr_t phys_addr;
+       uint8_t *bytep;
+       struct lpfc_mbx_sge sge;
+       struct lpfc_mbx_read_fcf_tbl *read_fcf;
+       uint32_t shdr_status, shdr_add_status;
+       union lpfc_sli4_cfg_shdr *shdr;
+       struct fcf_record *new_fcf_record;
+       int rc;
+       uint32_t boot_flag, addr_mode;
+       uint32_t next_fcf_index;
+       unsigned long flags;
+       uint16_t vlan_id;
+
+       /* Get the first SGE entry from the non-embedded DMA memory. This
+        * routine only uses a single SGE.
+        */
+       lpfc_sli4_mbx_sge_get(mboxq, 0, &sge);
+       phys_addr = getPaddr(sge.pa_hi, sge.pa_lo);
+       if (unlikely(!mboxq->sge_array)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+                               "2524 Failed to get the non-embedded SGE "
+                               "virtual address\n");
+               goto out;
+       }
+       virt_addr = mboxq->sge_array->addr[0];
+
+       shdr = (union lpfc_sli4_cfg_shdr *)virt_addr;
+       shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
+                                &shdr->response);
+       /*
+        * The FCF Record was read and there is no reason for the driver
+        * to maintain the FCF record data or memory. Instead, just need
+        * to book keeping the FCFIs can be used.
+        */
+       if (shdr_status || shdr_add_status) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2521 READ_FCF_RECORD mailbox failed "
+                               "with status x%x add_status x%x, mbx\n",
+                               shdr_status, shdr_add_status);
+               goto out;
+       }
+       /* Interpreting the returned information of FCF records */
+       read_fcf = (struct lpfc_mbx_read_fcf_tbl *)virt_addr;
+       lpfc_sli_pcimem_bcopy(read_fcf, read_fcf,
+                             sizeof(struct lpfc_mbx_read_fcf_tbl));
+       next_fcf_index = bf_get(lpfc_mbx_read_fcf_tbl_nxt_vindx, read_fcf);
+
+       new_fcf_record = (struct fcf_record *)(virt_addr +
+                         sizeof(struct lpfc_mbx_read_fcf_tbl));
+       lpfc_sli_pcimem_bcopy(new_fcf_record, new_fcf_record,
+                             sizeof(struct fcf_record));
+       bytep = virt_addr + sizeof(union lpfc_sli4_cfg_shdr);
+
+       rc = lpfc_match_fcf_conn_list(phba, new_fcf_record,
+                                     &boot_flag, &addr_mode,
+                                       &vlan_id);
+       /*
+        * If the fcf record does not match with connect list entries
+        * read the next entry.
+        */
+       if (!rc)
+               goto read_next_fcf;
+       /*
+        * If this is not the first FCF discovery of the HBA, use last
+        * FCF record for the discovery.
+        */
+       spin_lock_irqsave(&phba->hbalock, flags);
+       if (phba->fcf.fcf_flag & FCF_IN_USE) {
+               if (lpfc_fab_name_match(phba->fcf.fabric_name,
+                       new_fcf_record) &&
+                   lpfc_mac_addr_match(phba, new_fcf_record)) {
+                       phba->fcf.fcf_flag |= FCF_AVAILABLE;
+                       spin_unlock_irqrestore(&phba->hbalock, flags);
+                       goto out;
+               }
+               spin_unlock_irqrestore(&phba->hbalock, flags);
+               goto read_next_fcf;
+       }
+       if (phba->fcf.fcf_flag & FCF_AVAILABLE) {
+               /*
+                * If the current FCF record does not have boot flag
+                * set and new fcf record has boot flag set, use the
+                * new fcf record.
+                */
+               if (boot_flag && !(phba->fcf.fcf_flag & FCF_BOOT_ENABLE)) {
+                       /* Use this FCF record */
+                       lpfc_copy_fcf_record(phba, new_fcf_record);
+                       phba->fcf.addr_mode = addr_mode;
+                       phba->fcf.fcf_flag |= FCF_BOOT_ENABLE;
+                       if (vlan_id != 0xFFFF) {
+                               phba->fcf.fcf_flag |= FCF_VALID_VLAN;
+                               phba->fcf.vlan_id = vlan_id;
+                       }
+                       spin_unlock_irqrestore(&phba->hbalock, flags);
+                       goto read_next_fcf;
+               }
+               /*
+                * If the current FCF record has boot flag set and the
+                * new FCF record does not have boot flag, read the next
+                * FCF record.
+                */
+               if (!boot_flag && (phba->fcf.fcf_flag & FCF_BOOT_ENABLE)) {
+                       spin_unlock_irqrestore(&phba->hbalock, flags);
+                       goto read_next_fcf;
+               }
+               /*
+                * If there is a record with lower priority value for
+                * the current FCF, use that record.
+                */
+               if (lpfc_fab_name_match(phba->fcf.fabric_name, new_fcf_record)
+                       && (new_fcf_record->fip_priority <
+                               phba->fcf.priority)) {
+                       /* Use this FCF record */
+                       lpfc_copy_fcf_record(phba, new_fcf_record);
+                       phba->fcf.addr_mode = addr_mode;
+                       if (vlan_id != 0xFFFF) {
+                               phba->fcf.fcf_flag |= FCF_VALID_VLAN;
+                               phba->fcf.vlan_id = vlan_id;
+                       }
+                       spin_unlock_irqrestore(&phba->hbalock, flags);
+                       goto read_next_fcf;
+               }
+               spin_unlock_irqrestore(&phba->hbalock, flags);
+               goto read_next_fcf;
+       }
+       /*
+        * This is the first available FCF record, use this
+        * record.
+        */
+       lpfc_copy_fcf_record(phba, new_fcf_record);
+       phba->fcf.addr_mode = addr_mode;
+       if (boot_flag)
+               phba->fcf.fcf_flag |= FCF_BOOT_ENABLE;
+       phba->fcf.fcf_flag |= FCF_AVAILABLE;
+       if (vlan_id != 0xFFFF) {
+               phba->fcf.fcf_flag |= FCF_VALID_VLAN;
+               phba->fcf.vlan_id = vlan_id;
+       }
+       spin_unlock_irqrestore(&phba->hbalock, flags);
+       goto read_next_fcf;
+
+read_next_fcf:
+       lpfc_sli4_mbox_cmd_free(phba, mboxq);
+       if (next_fcf_index == LPFC_FCOE_FCF_NEXT_NONE || next_fcf_index == 0)
+               lpfc_register_fcf(phba);
+       else
+               lpfc_sli4_read_fcf_record(phba, next_fcf_index);
+       return;
+
+out:
+       lpfc_sli4_mbox_cmd_free(phba, mboxq);
+       lpfc_register_fcf(phba);
+
+       return;
+}
+
+/**
+ * lpfc_start_fdiscs - send fdiscs for each vports on this port.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This function loops through the list of vports on the @phba and issues an
+ * FDISC if possible.
+ */
+void
+lpfc_start_fdiscs(struct lpfc_hba *phba)
+{
+       struct lpfc_vport **vports;
+       int i;
+
+       vports = lpfc_create_vport_work_array(phba);
+       if (vports != NULL) {
+               for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
+                       if (vports[i]->port_type == LPFC_PHYSICAL_PORT)
+                               continue;
+                       /* There are no vpi for this vport */
+                       if (vports[i]->vpi > phba->max_vpi) {
+                               lpfc_vport_set_state(vports[i],
+                                                    FC_VPORT_FAILED);
+                               continue;
+                       }
+                       if (phba->fc_topology == TOPOLOGY_LOOP) {
+                               lpfc_vport_set_state(vports[i],
+                                                    FC_VPORT_LINKDOWN);
+                               continue;
+                       }
+                       if (phba->link_flag & LS_NPIV_FAB_SUPPORTED)
+                               lpfc_initial_fdisc(vports[i]);
+                       else {
+                               lpfc_vport_set_state(vports[i],
+                                                    FC_VPORT_NO_FABRIC_SUPP);
+                               lpfc_printf_vlog(vports[i], KERN_ERR,
+                                                LOG_ELS,
+                                                "0259 No NPIV "
+                                                "Fabric support\n");
+                       }
+               }
+       }
+       lpfc_destroy_vport_work_array(phba, vports);
+}
+
+void
+lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+{
+       struct lpfc_dmabuf *dmabuf = mboxq->context1;
+       struct lpfc_vport *vport = mboxq->vport;
+
+       if (mboxq->u.mb.mbxStatus) {
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+                        "2018 REG_VFI mbxStatus error x%x "
+                        "HBA state x%x\n",
+                        mboxq->u.mb.mbxStatus, vport->port_state);
+               if (phba->fc_topology == TOPOLOGY_LOOP) {
+                       /* FLOGI failed, use loop map to make discovery list */
+                       lpfc_disc_list_loopmap(vport);
+                       /* Start discovery */
+                       lpfc_disc_start(vport);
+                       goto fail_free_mem;
+               }
+               lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+               goto fail_free_mem;
+       }
+       /* Mark the vport has registered with its VFI */
+       vport->vfi_state |= LPFC_VFI_REGISTERED;
+
+       if (vport->port_state == LPFC_FABRIC_CFG_LINK) {
+               lpfc_start_fdiscs(phba);
+               lpfc_do_scr_ns_plogi(phba, vport);
+       }
+
+fail_free_mem:
+       mempool_free(mboxq, phba->mbox_mem_pool);
+       lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
+       kfree(dmabuf);
+       return;
+}
+
 static void
 lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
-       MAILBOX_t *mb = &pmb->mb;
+       MAILBOX_t *mb = &pmb->u.mb;
        struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) pmb->context1;
        struct lpfc_vport  *vport = pmb->vport;
 
@@ -1012,13 +1625,13 @@ static void
 lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
 {
        struct lpfc_vport *vport = phba->pport;
-       LPFC_MBOXQ_t *sparam_mbox, *cfglink_mbox;
+       LPFC_MBOXQ_t *sparam_mbox, *cfglink_mbox = NULL;
        int i;
        struct lpfc_dmabuf *mp;
        int rc;
+       struct fcf_record *fcf_record;
 
        sparam_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-       cfglink_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 
        spin_lock_irq(&phba->hbalock);
        switch (la->UlnkSpeed) {
@@ -1034,6 +1647,9 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
        case LA_8GHZ_LINK:
                phba->fc_linkspeed = LA_8GHZ_LINK;
                break;
+       case LA_10GHZ_LINK:
+               phba->fc_linkspeed = LA_10GHZ_LINK;
+               break;
        default:
                phba->fc_linkspeed = LA_UNKNW_LINK;
                break;
@@ -1115,22 +1731,66 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
                        lpfc_mbuf_free(phba, mp->virt, mp->phys);
                        kfree(mp);
                        mempool_free(sparam_mbox, phba->mbox_mem_pool);
-                       if (cfglink_mbox)
-                               mempool_free(cfglink_mbox, phba->mbox_mem_pool);
                        goto out;
                }
        }
 
-       if (cfglink_mbox) {
+       if (!(phba->hba_flag & HBA_FCOE_SUPPORT)) {
+               cfglink_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+               if (!cfglink_mbox)
+                       goto out;
                vport->port_state = LPFC_LOCAL_CFG_LINK;
                lpfc_config_link(phba, cfglink_mbox);
                cfglink_mbox->vport = vport;
                cfglink_mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link;
                rc = lpfc_sli_issue_mbox(phba, cfglink_mbox, MBX_NOWAIT);
-               if (rc != MBX_NOT_FINISHED)
-                       return;
-               mempool_free(cfglink_mbox, phba->mbox_mem_pool);
+               if (rc == MBX_NOT_FINISHED) {
+                       mempool_free(cfglink_mbox, phba->mbox_mem_pool);
+                       goto out;
+               }
+       } else {
+               /*
+                * Add the driver's default FCF record at FCF index 0 now. This
+                * is phase 1 implementation that support FCF index 0 and driver
+                * defaults.
+                */
+               if (phba->cfg_enable_fip == 0) {
+                       fcf_record = kzalloc(sizeof(struct fcf_record),
+                                       GFP_KERNEL);
+                       if (unlikely(!fcf_record)) {
+                               lpfc_printf_log(phba, KERN_ERR,
+                                       LOG_MBOX | LOG_SLI,
+                                       "2554 Could not allocate memmory for "
+                                       "fcf record\n");
+                               rc = -ENODEV;
+                               goto out;
+                       }
+
+                       lpfc_sli4_build_dflt_fcf_record(phba, fcf_record,
+                                               LPFC_FCOE_FCF_DEF_INDEX);
+                       rc = lpfc_sli4_add_fcf_record(phba, fcf_record);
+                       if (unlikely(rc)) {
+                               lpfc_printf_log(phba, KERN_ERR,
+                                       LOG_MBOX | LOG_SLI,
+                                       "2013 Could not manually add FCF "
+                                       "record 0, status %d\n", rc);
+                               rc = -ENODEV;
+                               kfree(fcf_record);
+                               goto out;
+                       }
+                       kfree(fcf_record);
+               }
+               /*
+                * The driver is expected to do FIP/FCF. Call the port
+                * and get the FCF Table.
+                */
+               rc = lpfc_sli4_read_fcf_record(phba,
+                                       LPFC_FCOE_FCF_GET_FIRST);
+               if (rc)
+                       goto out;
        }
+
+       return;
 out:
        lpfc_vport_set_state(vport, FC_VPORT_FAILED);
        lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
@@ -1147,10 +1807,12 @@ lpfc_enable_la(struct lpfc_hba *phba)
        struct lpfc_sli *psli = &phba->sli;
        spin_lock_irq(&phba->hbalock);
        psli->sli_flag |= LPFC_PROCESS_LA;
-       control = readl(phba->HCregaddr);
-       control |= HC_LAINT_ENA;
-       writel(control, phba->HCregaddr);
-       readl(phba->HCregaddr); /* flush */
+       if (phba->sli_rev <= LPFC_SLI_REV3) {
+               control = readl(phba->HCregaddr);
+               control |= HC_LAINT_ENA;
+               writel(control, phba->HCregaddr);
+               readl(phba->HCregaddr); /* flush */
+       }
        spin_unlock_irq(&phba->hbalock);
 }
 
@@ -1159,6 +1821,7 @@ lpfc_mbx_issue_link_down(struct lpfc_hba *phba)
 {
        lpfc_linkdown(phba);
        lpfc_enable_la(phba);
+       lpfc_unregister_unused_fcf(phba);
        /* turn on Link Attention interrupts - no CLEAR_LA needed */
 }
 
@@ -1175,7 +1838,7 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        struct lpfc_vport *vport = pmb->vport;
        struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
        READ_LA_VAR *la;
-       MAILBOX_t *mb = &pmb->mb;
+       MAILBOX_t *mb = &pmb->u.mb;
        struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
 
        /* Unblock ELS traffic */
@@ -1190,7 +1853,7 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                goto lpfc_mbx_cmpl_read_la_free_mbuf;
        }
 
-       la = (READ_LA_VAR *) & pmb->mb.un.varReadLA;
+       la = (READ_LA_VAR *) &pmb->u.mb.un.varReadLA;
 
        memcpy(&phba->alpa_map[0], mp->virt, 128);
 
@@ -1328,7 +1991,7 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 static void
 lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
-       MAILBOX_t *mb = &pmb->mb;
+       MAILBOX_t *mb = &pmb->u.mb;
        struct lpfc_vport *vport = pmb->vport;
        struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
 
@@ -1381,7 +2044,7 @@ lpfc_mbx_cmpl_reg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
        struct lpfc_vport *vport = pmb->vport;
        struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
-       MAILBOX_t *mb = &pmb->mb;
+       MAILBOX_t *mb = &pmb->u.mb;
 
        switch (mb->mbxStatus) {
        case 0x0011:
@@ -1416,6 +2079,128 @@ out:
        return;
 }
 
+/**
+ * lpfc_create_static_vport - Read HBA config region to create static vports.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine issue a DUMP mailbox command for config region 22 to get
+ * the list of static vports to be created. The function create vports
+ * based on the information returned from the HBA.
+ **/
+void
+lpfc_create_static_vport(struct lpfc_hba *phba)
+{
+       LPFC_MBOXQ_t *pmb = NULL;
+       MAILBOX_t *mb;
+       struct static_vport_info *vport_info;
+       int rc, i;
+       struct fc_vport_identifiers vport_id;
+       struct fc_vport *new_fc_vport;
+       struct Scsi_Host *shost;
+       struct lpfc_vport *vport;
+       uint16_t offset = 0;
+       uint8_t *vport_buff;
+
+       pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!pmb) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0542 lpfc_create_static_vport failed to"
+                               " allocate mailbox memory\n");
+               return;
+       }
+
+       mb = &pmb->u.mb;
+
+       vport_info = kzalloc(sizeof(struct static_vport_info), GFP_KERNEL);
+       if (!vport_info) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0543 lpfc_create_static_vport failed to"
+                               " allocate vport_info\n");
+               mempool_free(pmb, phba->mbox_mem_pool);
+               return;
+       }
+
+       vport_buff = (uint8_t *) vport_info;
+       do {
+               lpfc_dump_static_vport(phba, pmb, offset);
+               pmb->vport = phba->pport;
+               rc = lpfc_sli_issue_mbox_wait(phba, pmb, LPFC_MBOX_TMO);
+
+               if ((rc != MBX_SUCCESS) || mb->mbxStatus) {
+                       lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+                               "0544 lpfc_create_static_vport failed to"
+                               " issue dump mailbox command ret 0x%x "
+                               "status 0x%x\n",
+                               rc, mb->mbxStatus);
+                       goto out;
+               }
+
+               if (mb->un.varDmp.word_cnt >
+                       sizeof(struct static_vport_info) - offset)
+                       mb->un.varDmp.word_cnt =
+                       sizeof(struct static_vport_info) - offset;
+
+               lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET,
+                       vport_buff + offset,
+                       mb->un.varDmp.word_cnt);
+               offset += mb->un.varDmp.word_cnt;
+
+       } while (mb->un.varDmp.word_cnt &&
+               offset < sizeof(struct static_vport_info));
+
+
+       if ((le32_to_cpu(vport_info->signature) != VPORT_INFO_SIG) ||
+               ((le32_to_cpu(vport_info->rev) & VPORT_INFO_REV_MASK)
+                       != VPORT_INFO_REV)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                       "0545 lpfc_create_static_vport bad"
+                       " information header 0x%x 0x%x\n",
+                       le32_to_cpu(vport_info->signature),
+                       le32_to_cpu(vport_info->rev) & VPORT_INFO_REV_MASK);
+
+               goto out;
+       }
+
+       shost = lpfc_shost_from_vport(phba->pport);
+
+       for (i = 0; i < MAX_STATIC_VPORT_COUNT; i++) {
+               memset(&vport_id, 0, sizeof(vport_id));
+               vport_id.port_name = wwn_to_u64(vport_info->vport_list[i].wwpn);
+               vport_id.node_name = wwn_to_u64(vport_info->vport_list[i].wwnn);
+               if (!vport_id.port_name || !vport_id.node_name)
+                       continue;
+
+               vport_id.roles = FC_PORT_ROLE_FCP_INITIATOR;
+               vport_id.vport_type = FC_PORTTYPE_NPIV;
+               vport_id.disable = false;
+               new_fc_vport = fc_vport_create(shost, 0, &vport_id);
+
+               if (!new_fc_vport) {
+                       lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+                               "0546 lpfc_create_static_vport failed to"
+                               " create vport \n");
+                       continue;
+               }
+
+               vport = *(struct lpfc_vport **)new_fc_vport->dd_data;
+               vport->vport_flag |= STATIC_VPORT;
+       }
+
+out:
+       /*
+        * If this is timed out command, setting NULL to context2 tell SLI
+        * layer not to use this buffer.
+        */
+       spin_lock_irq(&phba->hbalock);
+       pmb->context2 = NULL;
+       spin_unlock_irq(&phba->hbalock);
+       kfree(vport_info);
+       if (rc != MBX_TIMEOUT)
+               mempool_free(pmb, phba->mbox_mem_pool);
+
+       return;
+}
+
 /*
  * This routine handles processing a Fabric REG_LOGIN mailbox
  * command upon completion. It is setup in the LPFC_MBOXQ
@@ -1426,16 +2211,17 @@ void
 lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
        struct lpfc_vport *vport = pmb->vport;
-       MAILBOX_t *mb = &pmb->mb;
+       MAILBOX_t *mb = &pmb->u.mb;
        struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
        struct lpfc_nodelist *ndlp;
-       struct lpfc_vport **vports;
-       int i;
 
        ndlp = (struct lpfc_nodelist *) pmb->context2;
        pmb->context1 = NULL;
        pmb->context2 = NULL;
        if (mb->mbxStatus) {
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+                                "0258 Register Fabric login error: 0x%x\n",
+                                mb->mbxStatus);
                lpfc_mbuf_free(phba, mp->virt, mp->phys);
                kfree(mp);
                mempool_free(pmb, phba->mbox_mem_pool);
@@ -1454,9 +2240,6 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                }
 
                lpfc_vport_set_state(vport, FC_VPORT_FAILED);
-               lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
-                                "0258 Register Fabric login error: 0x%x\n",
-                                mb->mbxStatus);
                /* Decrement the reference count to ndlp after the reference
                 * to the ndlp are done.
                 */
@@ -1465,34 +2248,12 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        }
 
        ndlp->nlp_rpi = mb->un.varWords[0];
+       ndlp->nlp_flag |= NLP_RPI_VALID;
        ndlp->nlp_type |= NLP_FABRIC;
        lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
 
        if (vport->port_state == LPFC_FABRIC_CFG_LINK) {
-               vports = lpfc_create_vport_work_array(phba);
-               if (vports != NULL)
-                       for(i = 0;
-                           i <= phba->max_vpi && vports[i] != NULL;
-                           i++) {
-                               if (vports[i]->port_type == LPFC_PHYSICAL_PORT)
-                                       continue;
-                               if (phba->fc_topology == TOPOLOGY_LOOP) {
-                                       lpfc_vport_set_state(vports[i],
-                                                       FC_VPORT_LINKDOWN);
-                                       continue;
-                               }
-                               if (phba->link_flag & LS_NPIV_FAB_SUPPORTED)
-                                       lpfc_initial_fdisc(vports[i]);
-                               else {
-                                       lpfc_vport_set_state(vports[i],
-                                               FC_VPORT_NO_FABRIC_SUPP);
-                                       lpfc_printf_vlog(vport, KERN_ERR,
-                                                        LOG_ELS,
-                                                       "0259 No NPIV "
-                                                       "Fabric support\n");
-                               }
-                       }
-               lpfc_destroy_vport_work_array(phba, vports);
+               lpfc_start_fdiscs(phba);
                lpfc_do_scr_ns_plogi(phba, vport);
        }
 
@@ -1516,13 +2277,16 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 void
 lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
-       MAILBOX_t *mb = &pmb->mb;
+       MAILBOX_t *mb = &pmb->u.mb;
        struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
        struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
        struct lpfc_vport *vport = pmb->vport;
 
        if (mb->mbxStatus) {
 out:
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+                                "0260 Register NameServer error: 0x%x\n",
+                                mb->mbxStatus);
                /* decrement the node reference count held for this
                 * callback function.
                 */
@@ -1546,15 +2310,13 @@ out:
                        return;
                }
                lpfc_vport_set_state(vport, FC_VPORT_FAILED);
-               lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
-                                "0260 Register NameServer error: 0x%x\n",
-                                mb->mbxStatus);
                return;
        }
 
        pmb->context1 = NULL;
 
        ndlp->nlp_rpi = mb->un.varWords[0];
+       ndlp->nlp_flag |= NLP_RPI_VALID;
        ndlp->nlp_type |= NLP_FABRIC;
        lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
 
@@ -2055,7 +2817,7 @@ lpfc_check_sli_ndlp(struct lpfc_hba *phba,
        if (pring->ringno == LPFC_ELS_RING) {
                switch (icmd->ulpCommand) {
                case CMD_GEN_REQUEST64_CR:
-                       if (icmd->ulpContext == (volatile ushort)ndlp->nlp_rpi)
+                       if (iocb->context_un.ndlp == ndlp)
                                return 1;
                case CMD_ELS_REQUEST64_CR:
                        if (icmd->un.elsreq64.remoteID == ndlp->nlp_DID)
@@ -2102,7 +2864,7 @@ lpfc_no_rpi(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
         */
        psli = &phba->sli;
        rpi = ndlp->nlp_rpi;
-       if (rpi) {
+       if (ndlp->nlp_flag & NLP_RPI_VALID) {
                /* Now process each ring */
                for (i = 0; i < psli->num_rings; i++) {
                        pring = &psli->ring[i];
@@ -2150,7 +2912,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
        LPFC_MBOXQ_t    *mbox;
        int rc;
 
-       if (ndlp->nlp_rpi) {
+       if (ndlp->nlp_flag & NLP_RPI_VALID) {
                mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
                if (mbox) {
                        lpfc_unreg_login(phba, vport->vpi, ndlp->nlp_rpi, mbox);
@@ -2162,6 +2924,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
                }
                lpfc_no_rpi(phba, ndlp);
                ndlp->nlp_rpi = 0;
+               ndlp->nlp_flag &= ~NLP_RPI_VALID;
                return 1;
        }
        return 0;
@@ -2252,7 +3015,7 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
 
        /* cleanup any ndlp on mbox q waiting for reglogin cmpl */
        if ((mb = phba->sli.mbox_active)) {
-               if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
+               if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) &&
                   (ndlp == (struct lpfc_nodelist *) mb->context2)) {
                        mb->context2 = NULL;
                        mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
@@ -2261,7 +3024,7 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
 
        spin_lock_irq(&phba->hbalock);
        list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
-               if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
+               if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) &&
                    (ndlp == (struct lpfc_nodelist *) mb->context2)) {
                        mp = (struct lpfc_dmabuf *) (mb->context1);
                        if (mp) {
@@ -2309,13 +3072,14 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
        int rc;
 
        lpfc_cancel_retry_delay_tmo(vport, ndlp);
-       if (ndlp->nlp_flag & NLP_DEFER_RM && !ndlp->nlp_rpi) {
+       if ((ndlp->nlp_flag & NLP_DEFER_RM) &&
+           !(ndlp->nlp_flag & NLP_RPI_VALID)) {
                /* For this case we need to cleanup the default rpi
                 * allocated by the firmware.
                 */
                if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))
                        != NULL) {
-                       rc = lpfc_reg_login(phba, vport->vpi, ndlp->nlp_DID,
+                       rc = lpfc_reg_rpi(phba, vport->vpi, ndlp->nlp_DID,
                            (uint8_t *) &vport->fc_sparam, mbox, 0);
                        if (rc) {
                                mempool_free(mbox, phba->mbox_mem_pool);
@@ -2553,7 +3317,8 @@ lpfc_issue_clear_la(struct lpfc_hba *phba, struct lpfc_vport *vport)
         * clear_la then don't send it.
         */
        if ((phba->link_state >= LPFC_CLEAR_LA) ||
-           (vport->port_type != LPFC_PHYSICAL_PORT))
+           (vport->port_type != LPFC_PHYSICAL_PORT) ||
+               (phba->sli_rev == LPFC_SLI_REV4))
                return;
 
                        /* Link up discovery */
@@ -2582,7 +3347,7 @@ lpfc_issue_reg_vpi(struct lpfc_hba *phba, struct lpfc_vport *vport)
 
        regvpimbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (regvpimbox) {
-               lpfc_reg_vpi(phba, vport->vpi, vport->fc_myDID, regvpimbox);
+               lpfc_reg_vpi(vport, regvpimbox);
                regvpimbox->mbox_cmpl = lpfc_mbx_cmpl_reg_vpi;
                regvpimbox->vport = vport;
                if (lpfc_sli_issue_mbox(phba, regvpimbox, MBX_NOWAIT)
@@ -2642,7 +3407,8 @@ lpfc_disc_start(struct lpfc_vport *vport)
         */
        if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
            !(vport->fc_flag & FC_PT2PT) &&
-           !(vport->fc_flag & FC_RSCN_MODE)) {
+           !(vport->fc_flag & FC_RSCN_MODE) &&
+           (phba->sli_rev < LPFC_SLI_REV4)) {
                lpfc_issue_reg_vpi(phba, vport);
                return;
        }
@@ -2919,11 +3685,13 @@ restart_disc:
                 * set port_state to PORT_READY if SLI2.
                 * cmpl_reg_vpi will set port_state to READY for SLI3.
                 */
-               if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
-                       lpfc_issue_reg_vpi(phba, vport);
-               else  { /* NPIV Not enabled */
-                       lpfc_issue_clear_la(phba, vport);
-                       vport->port_state = LPFC_VPORT_READY;
+               if (phba->sli_rev < LPFC_SLI_REV4) {
+                       if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
+                               lpfc_issue_reg_vpi(phba, vport);
+                       else  { /* NPIV Not enabled */
+                               lpfc_issue_clear_la(phba, vport);
+                               vport->port_state = LPFC_VPORT_READY;
+                       }
                }
 
                /* Setup and issue mailbox INITIALIZE LINK command */
@@ -2939,7 +3707,7 @@ restart_disc:
                lpfc_linkdown(phba);
                lpfc_init_link(phba, initlinkmbox, phba->cfg_topology,
                               phba->cfg_link_speed);
-               initlinkmbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
+               initlinkmbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0;
                initlinkmbox->vport = vport;
                initlinkmbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
                rc = lpfc_sli_issue_mbox(phba, initlinkmbox, MBX_NOWAIT);
@@ -2959,11 +3727,13 @@ restart_disc:
                 * set port_state to PORT_READY if SLI2.
                 * cmpl_reg_vpi will set port_state to READY for SLI3.
                 */
-               if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
-                       lpfc_issue_reg_vpi(phba, vport);
-               else {  /* NPIV Not enabled */
-                       lpfc_issue_clear_la(phba, vport);
-                       vport->port_state = LPFC_VPORT_READY;
+               if (phba->sli_rev < LPFC_SLI_REV4) {
+                       if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
+                               lpfc_issue_reg_vpi(phba, vport);
+                       else  { /* NPIV Not enabled */
+                               lpfc_issue_clear_la(phba, vport);
+                               vport->port_state = LPFC_VPORT_READY;
+                       }
                }
                break;
 
@@ -3036,7 +3806,7 @@ restart_disc:
 void
 lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
-       MAILBOX_t *mb = &pmb->mb;
+       MAILBOX_t *mb = &pmb->u.mb;
        struct lpfc_dmabuf   *mp = (struct lpfc_dmabuf *) (pmb->context1);
        struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
        struct lpfc_vport    *vport = pmb->vport;
@@ -3044,6 +3814,7 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        pmb->context1 = NULL;
 
        ndlp->nlp_rpi = mb->un.varWords[0];
+       ndlp->nlp_flag |= NLP_RPI_VALID;
        ndlp->nlp_type |= NLP_FABRIC;
        lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
 
@@ -3297,3 +4068,395 @@ lpfc_nlp_not_used(struct lpfc_nodelist *ndlp)
                        return 1;
        return 0;
 }
+
+/**
+ * lpfc_fcf_inuse - Check if FCF can be unregistered.
+ * @phba: Pointer to hba context object.
+ *
+ * This function iterate through all FC nodes associated
+ * will all vports to check if there is any node with
+ * fc_rports associated with it. If there is an fc_rport
+ * associated with the node, then the node is either in
+ * discovered state or its devloss_timer is pending.
+ */
+static int
+lpfc_fcf_inuse(struct lpfc_hba *phba)
+{
+       struct lpfc_vport **vports;
+       int i, ret = 0;
+       struct lpfc_nodelist *ndlp;
+       struct Scsi_Host  *shost;
+
+       vports = lpfc_create_vport_work_array(phba);
+
+       for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
+               shost = lpfc_shost_from_vport(vports[i]);
+               spin_lock_irq(shost->host_lock);
+               list_for_each_entry(ndlp, &vports[i]->fc_nodes, nlp_listp) {
+                       if (NLP_CHK_NODE_ACT(ndlp) && ndlp->rport &&
+                         (ndlp->rport->roles & FC_RPORT_ROLE_FCP_TARGET)) {
+                               ret = 1;
+                               spin_unlock_irq(shost->host_lock);
+                               goto out;
+                       }
+               }
+               spin_unlock_irq(shost->host_lock);
+       }
+out:
+       lpfc_destroy_vport_work_array(phba, vports);
+       return ret;
+}
+
+/**
+ * lpfc_unregister_vfi_cmpl - Completion handler for unreg vfi.
+ * @phba: Pointer to hba context object.
+ * @mboxq: Pointer to mailbox object.
+ *
+ * This function frees memory associated with the mailbox command.
+ */
+static void
+lpfc_unregister_vfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+{
+       struct lpfc_vport *vport = mboxq->vport;
+
+       if (mboxq->u.mb.mbxStatus) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX,
+                       "2555 UNREG_VFI mbxStatus error x%x "
+                       "HBA state x%x\n",
+                       mboxq->u.mb.mbxStatus, vport->port_state);
+       }
+       mempool_free(mboxq, phba->mbox_mem_pool);
+       return;
+}
+
+/**
+ * lpfc_unregister_fcfi_cmpl - Completion handler for unreg fcfi.
+ * @phba: Pointer to hba context object.
+ * @mboxq: Pointer to mailbox object.
+ *
+ * This function frees memory associated with the mailbox command.
+ */
+static void
+lpfc_unregister_fcfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+{
+       struct lpfc_vport *vport = mboxq->vport;
+
+       if (mboxq->u.mb.mbxStatus) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX,
+                       "2550 UNREG_FCFI mbxStatus error x%x "
+                       "HBA state x%x\n",
+                       mboxq->u.mb.mbxStatus, vport->port_state);
+       }
+       mempool_free(mboxq, phba->mbox_mem_pool);
+       return;
+}
+
+/**
+ * lpfc_unregister_unused_fcf - Unregister FCF if all devices are disconnected.
+ * @phba: Pointer to hba context object.
+ *
+ * This function check if there are any connected remote port for the FCF and
+ * if all the devices are disconnected, this function unregister FCFI.
+ * This function also tries to use another FCF for discovery.
+ */
+void
+lpfc_unregister_unused_fcf(struct lpfc_hba *phba)
+{
+       LPFC_MBOXQ_t *mbox;
+       int rc;
+       struct lpfc_vport **vports;
+       int i;
+
+       spin_lock_irq(&phba->hbalock);
+       /*
+        * If HBA is not running in FIP mode or
+        * If HBA does not support FCoE or
+        * If FCF is not registered.
+        * do nothing.
+        */
+       if (!(phba->hba_flag & HBA_FCOE_SUPPORT) ||
+               !(phba->fcf.fcf_flag & FCF_REGISTERED) ||
+               (phba->cfg_enable_fip == 0)) {
+               spin_unlock_irq(&phba->hbalock);
+               return;
+       }
+       spin_unlock_irq(&phba->hbalock);
+
+       if (lpfc_fcf_inuse(phba))
+               return;
+
+
+       /* Unregister VPIs */
+       vports = lpfc_create_vport_work_array(phba);
+       if (vports &&
+               (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED))
+               for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
+                       lpfc_mbx_unreg_vpi(vports[i]);
+                       vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+                       vports[i]->vfi_state &= ~LPFC_VFI_REGISTERED;
+               }
+       lpfc_destroy_vport_work_array(phba, vports);
+
+       /* Unregister VFI */
+       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX,
+                       "2556 UNREG_VFI mbox allocation failed"
+                       "HBA state x%x\n",
+                       phba->pport->port_state);
+               return;
+       }
+
+       lpfc_unreg_vfi(mbox, phba->pport->vfi);
+       mbox->vport = phba->pport;
+       mbox->mbox_cmpl = lpfc_unregister_vfi_cmpl;
+
+       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+       if (rc == MBX_NOT_FINISHED) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX,
+                       "2557 UNREG_VFI issue mbox failed rc x%x "
+                       "HBA state x%x\n",
+                       rc, phba->pport->port_state);
+               mempool_free(mbox, phba->mbox_mem_pool);
+               return;
+       }
+
+       /* Unregister FCF */
+       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX,
+                       "2551 UNREG_FCFI mbox allocation failed"
+                       "HBA state x%x\n",
+                       phba->pport->port_state);
+               return;
+       }
+
+       lpfc_unreg_fcfi(mbox, phba->fcf.fcfi);
+       mbox->vport = phba->pport;
+       mbox->mbox_cmpl = lpfc_unregister_fcfi_cmpl;
+       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+
+       if (rc == MBX_NOT_FINISHED) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX,
+                       "2552 UNREG_FCFI issue mbox failed rc x%x "
+                       "HBA state x%x\n",
+                       rc, phba->pport->port_state);
+               mempool_free(mbox, phba->mbox_mem_pool);
+               return;
+       }
+
+       spin_lock_irq(&phba->hbalock);
+       phba->fcf.fcf_flag &= ~(FCF_AVAILABLE | FCF_REGISTERED |
+               FCF_DISCOVERED | FCF_BOOT_ENABLE | FCF_IN_USE |
+               FCF_VALID_VLAN);
+       spin_unlock_irq(&phba->hbalock);
+
+       /*
+        * If driver is not unloading, check if there is any other
+        * FCF record that can be used for discovery.
+        */
+       if ((phba->pport->load_flag & FC_UNLOADING) ||
+               (phba->link_state < LPFC_LINK_UP))
+               return;
+
+       rc = lpfc_sli4_read_fcf_record(phba, LPFC_FCOE_FCF_GET_FIRST);
+
+       if (rc)
+               lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX,
+                       "2553 lpfc_unregister_unused_fcf failed to read FCF"
+                       " record HBA state x%x\n",
+                       phba->pport->port_state);
+}
+
+/**
+ * lpfc_read_fcf_conn_tbl - Create driver FCF connection table.
+ * @phba: Pointer to hba context object.
+ * @buff: Buffer containing the FCF connection table as in the config
+ *         region.
+ * This function create driver data structure for the FCF connection
+ * record table read from config region 23.
+ */
+static void
+lpfc_read_fcf_conn_tbl(struct lpfc_hba *phba,
+       uint8_t *buff)
+{
+       struct lpfc_fcf_conn_entry *conn_entry, *next_conn_entry;
+       struct lpfc_fcf_conn_hdr *conn_hdr;
+       struct lpfc_fcf_conn_rec *conn_rec;
+       uint32_t record_count;
+       int i;
+
+       /* Free the current connect table */
+       list_for_each_entry_safe(conn_entry, next_conn_entry,
+               &phba->fcf_conn_rec_list, list)
+               kfree(conn_entry);
+
+       conn_hdr = (struct lpfc_fcf_conn_hdr *) buff;
+       record_count = conn_hdr->length * sizeof(uint32_t)/
+               sizeof(struct lpfc_fcf_conn_rec);
+
+       conn_rec = (struct lpfc_fcf_conn_rec *)
+               (buff + sizeof(struct lpfc_fcf_conn_hdr));
+
+       for (i = 0; i < record_count; i++) {
+               if (!(conn_rec[i].flags & FCFCNCT_VALID))
+                       continue;
+               conn_entry = kzalloc(sizeof(struct lpfc_fcf_conn_entry),
+                       GFP_KERNEL);
+               if (!conn_entry) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2566 Failed to allocate connection"
+                               " table entry\n");
+                       return;
+               }
+
+               memcpy(&conn_entry->conn_rec, &conn_rec[i],
+                       sizeof(struct lpfc_fcf_conn_rec));
+               conn_entry->conn_rec.vlan_tag =
+                       le16_to_cpu(conn_entry->conn_rec.vlan_tag) & 0xFFF;
+               conn_entry->conn_rec.flags =
+                       le16_to_cpu(conn_entry->conn_rec.flags);
+               list_add_tail(&conn_entry->list,
+                       &phba->fcf_conn_rec_list);
+       }
+}
+
+/**
+ * lpfc_read_fcoe_param - Read FCoe parameters from conf region..
+ * @phba: Pointer to hba context object.
+ * @buff: Buffer containing the FCoE parameter data structure.
+ *
+ *  This function update driver data structure with config
+ *  parameters read from config region 23.
+ */
+static void
+lpfc_read_fcoe_param(struct lpfc_hba *phba,
+                       uint8_t *buff)
+{
+       struct lpfc_fip_param_hdr *fcoe_param_hdr;
+       struct lpfc_fcoe_params *fcoe_param;
+
+       fcoe_param_hdr = (struct lpfc_fip_param_hdr *)
+               buff;
+       fcoe_param = (struct lpfc_fcoe_params *)
+               buff + sizeof(struct lpfc_fip_param_hdr);
+
+       if ((fcoe_param_hdr->parm_version != FIPP_VERSION) ||
+               (fcoe_param_hdr->length != FCOE_PARAM_LENGTH))
+               return;
+
+       if (bf_get(lpfc_fip_param_hdr_fipp_mode, fcoe_param_hdr) ==
+                       FIPP_MODE_ON)
+               phba->cfg_enable_fip = 1;
+
+       if (bf_get(lpfc_fip_param_hdr_fipp_mode, fcoe_param_hdr) ==
+               FIPP_MODE_OFF)
+               phba->cfg_enable_fip = 0;
+
+       if (fcoe_param_hdr->parm_flags & FIPP_VLAN_VALID) {
+               phba->valid_vlan = 1;
+               phba->vlan_id = le16_to_cpu(fcoe_param->vlan_tag) &
+                       0xFFF;
+       }
+
+       phba->fc_map[0] = fcoe_param->fc_map[0];
+       phba->fc_map[1] = fcoe_param->fc_map[1];
+       phba->fc_map[2] = fcoe_param->fc_map[2];
+       return;
+}
+
+/**
+ * lpfc_get_rec_conf23 - Get a record type in config region data.
+ * @buff: Buffer containing config region 23 data.
+ * @size: Size of the data buffer.
+ * @rec_type: Record type to be searched.
+ *
+ * This function searches config region data to find the begining
+ * of the record specified by record_type. If record found, this
+ * function return pointer to the record else return NULL.
+ */
+static uint8_t *
+lpfc_get_rec_conf23(uint8_t *buff, uint32_t size, uint8_t rec_type)
+{
+       uint32_t offset = 0, rec_length;
+
+       if ((buff[0] == LPFC_REGION23_LAST_REC) ||
+               (size < sizeof(uint32_t)))
+               return NULL;
+
+       rec_length = buff[offset + 1];
+
+       /*
+        * One TLV record has one word header and number of data words
+        * specified in the rec_length field of the record header.
+        */
+       while ((offset + rec_length * sizeof(uint32_t) + sizeof(uint32_t))
+               <= size) {
+               if (buff[offset] == rec_type)
+                       return &buff[offset];
+
+               if (buff[offset] == LPFC_REGION23_LAST_REC)
+                       return NULL;
+
+               offset += rec_length * sizeof(uint32_t) + sizeof(uint32_t);
+               rec_length = buff[offset + 1];
+       }
+       return NULL;
+}
+
+/**
+ * lpfc_parse_fcoe_conf - Parse FCoE config data read from config region 23.
+ * @phba: Pointer to lpfc_hba data structure.
+ * @buff: Buffer containing config region 23 data.
+ * @size: Size of the data buffer.
+ *
+ * This fuction parse the FCoE config parameters in config region 23 and
+ * populate driver data structure with the parameters.
+ */
+void
+lpfc_parse_fcoe_conf(struct lpfc_hba *phba,
+               uint8_t *buff,
+               uint32_t size)
+{
+       uint32_t offset = 0, rec_length;
+       uint8_t *rec_ptr;
+
+       /*
+        * If data size is less than 2 words signature and version cannot be
+        * verified.
+        */
+       if (size < 2*sizeof(uint32_t))
+               return;
+
+       /* Check the region signature first */
+       if (memcmp(buff, LPFC_REGION23_SIGNATURE, 4)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                       "2567 Config region 23 has bad signature\n");
+               return;
+       }
+
+       offset += 4;
+
+       /* Check the data structure version */
+       if (buff[offset] != LPFC_REGION23_VERSION) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                       "2568 Config region 23 has bad version\n");
+               return;
+       }
+       offset += 4;
+
+       rec_length = buff[offset + 1];
+
+       /* Read FCoE param record */
+       rec_ptr = lpfc_get_rec_conf23(&buff[offset],
+                       size - offset, FCOE_PARAM_TYPE);
+       if (rec_ptr)
+               lpfc_read_fcoe_param(phba, rec_ptr);
+
+       /* Read FCF connection table */
+       rec_ptr = lpfc_get_rec_conf23(&buff[offset],
+               size - offset, FCOE_CONN_TBL_TYPE);
+       if (rec_ptr)
+               lpfc_read_fcf_conn_tbl(phba, rec_ptr);
+
+}
index 4168c7b498b87d6e3b79759eb5887931dbfe5f5f..02aa016b93e926c2f6808f2e83d353e10359df55 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -470,6 +470,35 @@ struct serv_parm { /* Structure is in Big Endian format */
        uint8_t vendorVersion[16];
 };
 
+/*
+ * Virtual Fabric Tagging Header
+ */
+struct fc_vft_header {
+        uint32_t word0;
+#define fc_vft_hdr_r_ctl_SHIFT         24
+#define fc_vft_hdr_r_ctl_MASK          0xFF
+#define fc_vft_hdr_r_ctl_WORD          word0
+#define fc_vft_hdr_ver_SHIFT           22
+#define fc_vft_hdr_ver_MASK            0x3
+#define fc_vft_hdr_ver_WORD            word0
+#define fc_vft_hdr_type_SHIFT          18
+#define fc_vft_hdr_type_MASK           0xF
+#define fc_vft_hdr_type_WORD           word0
+#define fc_vft_hdr_e_SHIFT             16
+#define fc_vft_hdr_e_MASK              0x1
+#define fc_vft_hdr_e_WORD              word0
+#define fc_vft_hdr_priority_SHIFT      13
+#define fc_vft_hdr_priority_MASK       0x7
+#define fc_vft_hdr_priority_WORD       word0
+#define fc_vft_hdr_vf_id_SHIFT         1
+#define fc_vft_hdr_vf_id_MASK          0xFFF
+#define fc_vft_hdr_vf_id_WORD          word0
+       uint32_t word1;
+#define fc_vft_hdr_hopct_SHIFT         24
+#define fc_vft_hdr_hopct_MASK          0xFF
+#define fc_vft_hdr_hopct_WORD          word1
+};
+
 /*
  *  Extended Link Service LS_COMMAND codes (Payload Word 0)
  */
@@ -1152,6 +1181,9 @@ typedef struct {
 #define PCI_DEVICE_ID_HORNET        0xfe05
 #define PCI_DEVICE_ID_ZEPHYR_SCSP   0xfe11
 #define PCI_DEVICE_ID_ZEPHYR_DCSP   0xfe12
+#define PCI_VENDOR_ID_SERVERENGINE  0x19a2
+#define PCI_DEVICE_ID_TIGERSHARK    0x0704
+#define PCI_DEVICE_ID_TIGERSHARK_S  0x0705
 
 #define JEDEC_ID_ADDRESS            0x0080001c
 #define FIREFLY_JEDEC_ID            0x1ACC
@@ -1342,15 +1374,21 @@ typedef struct {                /* FireFly BIU registers */
 #define MBX_READ_LA64       0x95
 #define MBX_REG_VPI        0x96
 #define MBX_UNREG_VPI      0x97
-#define MBX_REG_VNPID      0x96
-#define MBX_UNREG_VNPID            0x97
 
 #define MBX_WRITE_WWN       0x98
 #define MBX_SET_DEBUG       0x99
 #define MBX_LOAD_EXP_ROM    0x9C
-
-#define MBX_MAX_CMDS        0x9D
+#define MBX_SLI4_CONFIG            0x9B
+#define MBX_SLI4_REQ_FTRS   0x9D
+#define MBX_MAX_CMDS        0x9E
+#define MBX_RESUME_RPI      0x9E
 #define MBX_SLI2_CMD_MASK   0x80
+#define MBX_REG_VFI         0x9F
+#define MBX_REG_FCFI        0xA0
+#define MBX_UNREG_VFI       0xA1
+#define MBX_UNREG_FCFI     0xA2
+#define MBX_INIT_VFI        0xA3
+#define MBX_INIT_VPI        0xA4
 
 /* IOCB Commands */
 
@@ -1440,6 +1478,16 @@ typedef struct {         /* FireFly BIU registers */
 #define CMD_IOCB_LOGENTRY_CN           0x94
 #define CMD_IOCB_LOGENTRY_ASYNC_CN     0x96
 
+/* Unhandled Data Security SLI Commands */
+#define DSSCMD_IWRITE64_CR             0xD8
+#define DSSCMD_IWRITE64_CX             0xD9
+#define DSSCMD_IREAD64_CR              0xDA
+#define DSSCMD_IREAD64_CX              0xDB
+#define DSSCMD_INVALIDATE_DEK          0xDC
+#define DSSCMD_SET_KEK                 0xDD
+#define DSSCMD_GET_KEK_ID              0xDE
+#define DSSCMD_GEN_XFER                        0xDF
+
 #define CMD_MAX_IOCB_CMD        0xE6
 #define CMD_IOCB_MASK           0xff
 
@@ -1466,6 +1514,7 @@ typedef struct {          /* FireFly BIU registers */
 #define MBXERR_BAD_RCV_LENGTH       14
 #define MBXERR_DMA_ERROR            15
 #define MBXERR_ERROR                16
+#define MBXERR_LINK_DOWN            0x33
 #define MBX_NOT_FINISHED           255
 
 #define MBX_BUSY                   0xffffff /* Attempted cmd to busy Mailbox */
@@ -1504,32 +1553,6 @@ struct ulp_bde {
 #endif
 };
 
-struct ulp_bde64 {     /* SLI-2 */
-       union ULP_BDE_TUS {
-               uint32_t w;
-               struct {
-#ifdef __BIG_ENDIAN_BITFIELD
-                       uint32_t bdeFlags:8;    /* BDE Flags 0 IS A SUPPORTED
-                                                  VALUE !! */
-                       uint32_t bdeSize:24;    /* Size of buffer (in bytes) */
-#else  /*  __LITTLE_ENDIAN_BITFIELD */
-                       uint32_t bdeSize:24;    /* Size of buffer (in bytes) */
-                       uint32_t bdeFlags:8;    /* BDE Flags 0 IS A SUPPORTED
-                                                  VALUE !! */
-#endif
-#define BUFF_TYPE_BDE_64    0x00       /* BDE (Host_resident) */
-#define BUFF_TYPE_BDE_IMMED 0x01       /* Immediate Data BDE */
-#define BUFF_TYPE_BDE_64P   0x02       /* BDE (Port-resident) */
-#define BUFF_TYPE_BDE_64I   0x08       /* Input BDE (Host-resident) */
-#define BUFF_TYPE_BDE_64IP  0x0A       /* Input BDE (Port-resident) */
-#define BUFF_TYPE_BLP_64    0x40       /* BLP (Host-resident) */
-#define BUFF_TYPE_BLP_64P   0x42       /* BLP (Port-resident) */
-               } f;
-       } tus;
-       uint32_t addrLow;
-       uint32_t addrHigh;
-};
-
 typedef struct ULP_BDL {       /* SLI-2 */
 #ifdef __BIG_ENDIAN_BITFIELD
        uint32_t bdeFlags:8;    /* BDL Flags */
@@ -2287,7 +2310,7 @@ typedef struct {
        uint32_t rsvd3;
        uint32_t rsvd4;
        uint32_t rsvd5;
-       uint16_t rsvd6;
+       uint16_t vfi;
        uint16_t vpi;
 #else  /*  __LITTLE_ENDIAN */
        uint32_t rsvd1;
@@ -2297,7 +2320,7 @@ typedef struct {
        uint32_t rsvd4;
        uint32_t rsvd5;
        uint16_t vpi;
-       uint16_t rsvd6;
+       uint16_t vfi;
 #endif
 } REG_VPI_VAR;
 
@@ -2457,7 +2480,7 @@ typedef struct {
        uint32_t entry_index:16;
 #endif
 
-       uint32_t rsvd1;
+       uint32_t sli4_length;
        uint32_t word_cnt;
        uint32_t resp_offset;
 } DUMP_VAR;
@@ -2470,9 +2493,32 @@ typedef struct {
 #define  DMP_RSP_OFFSET          0x14   /* word 5 contains first word of rsp */
 #define  DMP_RSP_SIZE            0x6C   /* maximum of 27 words of rsp data */
 
+#define  DMP_REGION_VPORT       0x16   /* VPort info region */
+#define  DMP_VPORT_REGION_SIZE  0x200
+#define  DMP_MBOX_OFFSET_WORD   0x5
+
+#define  DMP_REGION_FCOEPARAM   0x17   /* fcoe param region */
+#define  DMP_FCOEPARAM_RGN_SIZE         0x400
+
 #define  WAKE_UP_PARMS_REGION_ID    4
 #define  WAKE_UP_PARMS_WORD_SIZE   15
 
+struct vport_rec {
+       uint8_t wwpn[8];
+       uint8_t wwnn[8];
+};
+
+#define VPORT_INFO_SIG 0x32324752
+#define VPORT_INFO_REV_MASK 0xff
+#define VPORT_INFO_REV 0x1
+#define MAX_STATIC_VPORT_COUNT 16
+struct static_vport_info {
+       uint32_t                signature;
+       uint32_t                rev;
+       struct vport_rec        vport_list[MAX_STATIC_VPORT_COUNT];
+       uint32_t                resvd[66];
+};
+
 /* Option rom version structure */
 struct prog_id {
 #ifdef __BIG_ENDIAN_BITFIELD
@@ -2697,7 +2743,9 @@ typedef struct {
 #endif
 
 #ifdef __BIG_ENDIAN_BITFIELD
-       uint32_t rsvd1     : 23;  /* Reserved                             */
+       uint32_t rsvd1     : 19;  /* Reserved                             */
+       uint32_t cdss      :  1;  /* Configure Data Security SLI          */
+       uint32_t rsvd2     :  3;  /* Reserved                             */
        uint32_t cbg       :  1;  /* Configure BlockGuard                 */
        uint32_t cmv       :  1;  /* Configure Max VPIs                   */
        uint32_t ccrp      :  1;  /* Config Command Ring Polling          */
@@ -2717,10 +2765,14 @@ typedef struct {
        uint32_t ccrp      :  1;  /* Config Command Ring Polling          */
        uint32_t cmv       :  1;  /* Configure Max VPIs                   */
        uint32_t cbg       :  1;  /* Configure BlockGuard                 */
-       uint32_t rsvd1     : 23;  /* Reserved                             */
+       uint32_t rsvd2     :  3;  /* Reserved                             */
+       uint32_t cdss      :  1;  /* Configure Data Security SLI          */
+       uint32_t rsvd1     : 19;  /* Reserved                             */
 #endif
 #ifdef __BIG_ENDIAN_BITFIELD
-       uint32_t rsvd2     : 23;  /* Reserved                             */
+       uint32_t rsvd3     : 19;  /* Reserved                             */
+       uint32_t gdss      :  1;  /* Configure Data Security SLI          */
+       uint32_t rsvd4     :  3;  /* Reserved                             */
        uint32_t gbg       :  1;  /* Grant BlockGuard                     */
        uint32_t gmv       :  1;  /* Grant Max VPIs                       */
        uint32_t gcrp      :  1;  /* Grant Command Ring Polling           */
@@ -2740,7 +2792,9 @@ typedef struct {
        uint32_t gcrp      :  1;  /* Grant Command Ring Polling           */
        uint32_t gmv       :  1;  /* Grant Max VPIs                       */
        uint32_t gbg       :  1;  /* Grant BlockGuard                     */
-       uint32_t rsvd2     : 23;  /* Reserved                             */
+       uint32_t rsvd4     :  3;  /* Reserved                             */
+       uint32_t gdss      :  1;  /* Configure Data Security SLI          */
+       uint32_t rsvd3     : 19;  /* Reserved                             */
 #endif
 
 #ifdef __BIG_ENDIAN_BITFIELD
@@ -2753,20 +2807,20 @@ typedef struct {
 
 #ifdef __BIG_ENDIAN_BITFIELD
        uint32_t max_hbq   : 16;  /* Max HBQs Host expect to configure    */
-       uint32_t rsvd3     : 16;  /* Max HBQs Host expect to configure    */
+       uint32_t rsvd5     : 16;  /* Max HBQs Host expect to configure    */
 #else  /*  __LITTLE_ENDIAN */
-       uint32_t rsvd3     : 16;  /* Max HBQs Host expect to configure    */
+       uint32_t rsvd5     : 16;  /* Max HBQs Host expect to configure    */
        uint32_t max_hbq   : 16;  /* Max HBQs Host expect to configure    */
 #endif
 
-       uint32_t rsvd4;           /* Reserved                             */
+       uint32_t rsvd6;           /* Reserved                             */
 
 #ifdef __BIG_ENDIAN_BITFIELD
-       uint32_t rsvd5      : 16;  /* Reserved                             */
+       uint32_t rsvd7      : 16;  /* Reserved                             */
        uint32_t max_vpi    : 16;  /* Max number of virt N-Ports           */
 #else  /*  __LITTLE_ENDIAN */
        uint32_t max_vpi    : 16;  /* Max number of virt N-Ports           */
-       uint32_t rsvd5      : 16;  /* Reserved                             */
+       uint32_t rsvd7      : 16;  /* Reserved                             */
 #endif
 
 } CONFIG_PORT_VAR;
@@ -3666,3 +3720,5 @@ lpfc_error_lost_link(IOCB_t *iocbp)
 #define MENLO_TIMEOUT 30
 #define SETVAR_MLOMNT 0x103107
 #define SETVAR_MLORST 0x103007
+
+#define BPL_ALIGN_SZ 8 /* 8 byte alignment for bpl and mbufs */
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
new file mode 100644 (file)
index 0000000..39c34b3
--- /dev/null
@@ -0,0 +1,2141 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Fibre Channel Host Bus Adapters.                                *
+ * Copyright (C) 2009 Emulex.  All rights reserved.                *
+ * EMULEX and SLI are trademarks of Emulex.                        *
+ * www.emulex.com                                                  *
+ *                                                                 *
+ * This program is free software; you can redistribute it and/or   *
+ * modify it under the terms of version 2 of the GNU General       *
+ * Public License as published by the Free Software Foundation.    *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
+ * more details, a copy of which can be found in the file COPYING  *
+ * included with this package.                                     *
+ *******************************************************************/
+
+/* Macros to deal with bit fields. Each bit field must have 3 #defines
+ * associated with it (_SHIFT, _MASK, and _WORD).
+ * EG. For a bit field that is in the 7th bit of the "field4" field of a
+ * structure and is 2 bits in size the following #defines must exist:
+ *     struct temp {
+ *             uint32_t        field1;
+ *             uint32_t        field2;
+ *             uint32_t        field3;
+ *             uint32_t        field4;
+ *     #define example_bit_field_SHIFT         7
+ *     #define example_bit_field_MASK          0x03
+ *     #define example_bit_field_WORD          field4
+ *             uint32_t        field5;
+ *     };
+ * Then the macros below may be used to get or set the value of that field.
+ * EG. To get the value of the bit field from the above example:
+ *     struct temp t1;
+ *     value = bf_get(example_bit_field, &t1);
+ * And then to set that bit field:
+ *     bf_set(example_bit_field, &t1, 2);
+ * Or clear that bit field:
+ *     bf_set(example_bit_field, &t1, 0);
+ */
+#define bf_get(name, ptr) \
+       (((ptr)->name##_WORD >> name##_SHIFT) & name##_MASK)
+#define bf_set(name, ptr, value) \
+       ((ptr)->name##_WORD = ((((value) & name##_MASK) << name##_SHIFT) | \
+                ((ptr)->name##_WORD & ~(name##_MASK << name##_SHIFT))))
+
+struct dma_address {
+       uint32_t addr_lo;
+       uint32_t addr_hi;
+};
+
+#define LPFC_SLI4_BAR0         1
+#define LPFC_SLI4_BAR1         2
+#define LPFC_SLI4_BAR2         4
+
+#define LPFC_SLI4_MBX_EMBED    true
+#define LPFC_SLI4_MBX_NEMBED   false
+
+#define LPFC_SLI4_MB_WORD_COUNT                64
+#define LPFC_MAX_MQ_PAGE               8
+#define LPFC_MAX_WQ_PAGE               8
+#define LPFC_MAX_CQ_PAGE               4
+#define LPFC_MAX_EQ_PAGE               8
+
+#define LPFC_VIR_FUNC_MAX       32 /* Maximum number of virtual functions */
+#define LPFC_PCI_FUNC_MAX        5 /* Maximum number of PCI functions */
+#define LPFC_VFR_PAGE_SIZE     0x1000 /* 4KB BAR2 per-VF register page size */
+
+/* Define SLI4 Alignment requirements. */
+#define LPFC_ALIGN_16_BYTE     16
+#define LPFC_ALIGN_64_BYTE     64
+
+/* Define SLI4 specific definitions. */
+#define LPFC_MQ_CQE_BYTE_OFFSET        256
+#define LPFC_MBX_CMD_HDR_LENGTH 16
+#define LPFC_MBX_ERROR_RANGE   0x4000
+#define LPFC_BMBX_BIT1_ADDR_HI 0x2
+#define LPFC_BMBX_BIT1_ADDR_LO 0
+#define LPFC_RPI_HDR_COUNT     64
+#define LPFC_HDR_TEMPLATE_SIZE 4096
+#define LPFC_RPI_ALLOC_ERROR   0xFFFF
+#define LPFC_FCF_RECORD_WD_CNT 132
+#define LPFC_ENTIRE_FCF_DATABASE 0
+#define LPFC_DFLT_FCF_INDEX     0
+
+/* Virtual function numbers */
+#define LPFC_VF0               0
+#define LPFC_VF1               1
+#define LPFC_VF2               2
+#define LPFC_VF3               3
+#define LPFC_VF4               4
+#define LPFC_VF5               5
+#define LPFC_VF6               6
+#define LPFC_VF7               7
+#define LPFC_VF8               8
+#define LPFC_VF9               9
+#define LPFC_VF10              10
+#define LPFC_VF11              11
+#define LPFC_VF12              12
+#define LPFC_VF13              13
+#define LPFC_VF14              14
+#define LPFC_VF15              15
+#define LPFC_VF16              16
+#define LPFC_VF17              17
+#define LPFC_VF18              18
+#define LPFC_VF19              19
+#define LPFC_VF20              20
+#define LPFC_VF21              21
+#define LPFC_VF22              22
+#define LPFC_VF23              23
+#define LPFC_VF24              24
+#define LPFC_VF25              25
+#define LPFC_VF26              26
+#define LPFC_VF27              27
+#define LPFC_VF28              28
+#define LPFC_VF29              29
+#define LPFC_VF30              30
+#define LPFC_VF31              31
+
+/* PCI function numbers */
+#define LPFC_PCI_FUNC0         0
+#define LPFC_PCI_FUNC1         1
+#define LPFC_PCI_FUNC2         2
+#define LPFC_PCI_FUNC3         3
+#define LPFC_PCI_FUNC4         4
+
+/* Active interrupt test count */
+#define LPFC_ACT_INTR_CNT      4
+
+/* Delay Multiplier constant */
+#define LPFC_DMULT_CONST       651042
+#define LPFC_MIM_IMAX          636
+#define LPFC_FP_DEF_IMAX       10000
+#define LPFC_SP_DEF_IMAX       10000
+
+struct ulp_bde64 {
+       union ULP_BDE_TUS {
+               uint32_t w;
+               struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+                       uint32_t bdeFlags:8;    /* BDE Flags 0 IS A SUPPORTED
+                                                  VALUE !! */
+                       uint32_t bdeSize:24;    /* Size of buffer (in bytes) */
+#else  /*  __LITTLE_ENDIAN_BITFIELD */
+                       uint32_t bdeSize:24;    /* Size of buffer (in bytes) */
+                       uint32_t bdeFlags:8;    /* BDE Flags 0 IS A SUPPORTED
+                                                  VALUE !! */
+#endif
+#define BUFF_TYPE_BDE_64    0x00       /* BDE (Host_resident) */
+#define BUFF_TYPE_BDE_IMMED 0x01       /* Immediate Data BDE */
+#define BUFF_TYPE_BDE_64P   0x02       /* BDE (Port-resident) */
+#define BUFF_TYPE_BDE_64I   0x08       /* Input BDE (Host-resident) */
+#define BUFF_TYPE_BDE_64IP  0x0A       /* Input BDE (Port-resident) */
+#define BUFF_TYPE_BLP_64    0x40       /* BLP (Host-resident) */
+#define BUFF_TYPE_BLP_64P   0x42       /* BLP (Port-resident) */
+               } f;
+       } tus;
+       uint32_t addrLow;
+       uint32_t addrHigh;
+};
+
+struct lpfc_sli4_flags {
+       uint32_t word0;
+#define lpfc_fip_flag_SHIFT 0
+#define lpfc_fip_flag_MASK 0x00000001
+#define lpfc_fip_flag_WORD word0
+};
+
+/* event queue entry structure */
+struct lpfc_eqe {
+       uint32_t word0;
+#define lpfc_eqe_resource_id_SHIFT     16
+#define lpfc_eqe_resource_id_MASK      0x000000FF
+#define lpfc_eqe_resource_id_WORD      word0
+#define lpfc_eqe_minor_code_SHIFT      4
+#define lpfc_eqe_minor_code_MASK       0x00000FFF
+#define lpfc_eqe_minor_code_WORD       word0
+#define lpfc_eqe_major_code_SHIFT      1
+#define lpfc_eqe_major_code_MASK       0x00000007
+#define lpfc_eqe_major_code_WORD       word0
+#define lpfc_eqe_valid_SHIFT           0
+#define lpfc_eqe_valid_MASK            0x00000001
+#define lpfc_eqe_valid_WORD            word0
+};
+
+/* completion queue entry structure (common fields for all cqe types) */
+struct lpfc_cqe {
+       uint32_t reserved0;
+       uint32_t reserved1;
+       uint32_t reserved2;
+       uint32_t word3;
+#define lpfc_cqe_valid_SHIFT           31
+#define lpfc_cqe_valid_MASK            0x00000001
+#define lpfc_cqe_valid_WORD            word3
+#define lpfc_cqe_code_SHIFT            16
+#define lpfc_cqe_code_MASK             0x000000FF
+#define lpfc_cqe_code_WORD             word3
+};
+
+/* Completion Queue Entry Status Codes */
+#define CQE_STATUS_SUCCESS             0x0
+#define CQE_STATUS_FCP_RSP_FAILURE     0x1
+#define CQE_STATUS_REMOTE_STOP         0x2
+#define CQE_STATUS_LOCAL_REJECT                0x3
+#define CQE_STATUS_NPORT_RJT           0x4
+#define CQE_STATUS_FABRIC_RJT          0x5
+#define CQE_STATUS_NPORT_BSY           0x6
+#define CQE_STATUS_FABRIC_BSY          0x7
+#define CQE_STATUS_INTERMED_RSP                0x8
+#define CQE_STATUS_LS_RJT              0x9
+#define CQE_STATUS_CMD_REJECT          0xb
+#define CQE_STATUS_FCP_TGT_LENCHECK    0xc
+#define CQE_STATUS_NEED_BUFF_ENTRY     0xf
+
+/* Status returned by hardware (valid only if status = CQE_STATUS_SUCCESS). */
+#define CQE_HW_STATUS_NO_ERR           0x0
+#define CQE_HW_STATUS_UNDERRUN         0x1
+#define CQE_HW_STATUS_OVERRUN          0x2
+
+/* Completion Queue Entry Codes */
+#define CQE_CODE_COMPL_WQE             0x1
+#define CQE_CODE_RELEASE_WQE           0x2
+#define CQE_CODE_RECEIVE               0x4
+#define CQE_CODE_XRI_ABORTED           0x5
+
+/* completion queue entry for wqe completions */
+struct lpfc_wcqe_complete {
+       uint32_t word0;
+#define lpfc_wcqe_c_request_tag_SHIFT  16
+#define lpfc_wcqe_c_request_tag_MASK   0x0000FFFF
+#define lpfc_wcqe_c_request_tag_WORD   word0
+#define lpfc_wcqe_c_status_SHIFT       8
+#define lpfc_wcqe_c_status_MASK                0x000000FF
+#define lpfc_wcqe_c_status_WORD                word0
+#define lpfc_wcqe_c_hw_status_SHIFT    0
+#define lpfc_wcqe_c_hw_status_MASK     0x000000FF
+#define lpfc_wcqe_c_hw_status_WORD     word0
+       uint32_t total_data_placed;
+       uint32_t parameter;
+       uint32_t word3;
+#define lpfc_wcqe_c_valid_SHIFT                lpfc_cqe_valid_SHIFT
+#define lpfc_wcqe_c_valid_MASK         lpfc_cqe_valid_MASK
+#define lpfc_wcqe_c_valid_WORD         lpfc_cqe_valid_WORD
+#define lpfc_wcqe_c_xb_SHIFT           28
+#define lpfc_wcqe_c_xb_MASK            0x00000001
+#define lpfc_wcqe_c_xb_WORD            word3
+#define lpfc_wcqe_c_pv_SHIFT           27
+#define lpfc_wcqe_c_pv_MASK            0x00000001
+#define lpfc_wcqe_c_pv_WORD            word3
+#define lpfc_wcqe_c_priority_SHIFT     24
+#define lpfc_wcqe_c_priority_MASK              0x00000007
+#define lpfc_wcqe_c_priority_WORD              word3
+#define lpfc_wcqe_c_code_SHIFT         lpfc_cqe_code_SHIFT
+#define lpfc_wcqe_c_code_MASK          lpfc_cqe_code_MASK
+#define lpfc_wcqe_c_code_WORD          lpfc_cqe_code_WORD
+};
+
+/* completion queue entry for wqe release */
+struct lpfc_wcqe_release {
+       uint32_t reserved0;
+       uint32_t reserved1;
+       uint32_t word2;
+#define lpfc_wcqe_r_wq_id_SHIFT                16
+#define lpfc_wcqe_r_wq_id_MASK         0x0000FFFF
+#define lpfc_wcqe_r_wq_id_WORD         word2
+#define lpfc_wcqe_r_wqe_index_SHIFT    0
+#define lpfc_wcqe_r_wqe_index_MASK     0x0000FFFF
+#define lpfc_wcqe_r_wqe_index_WORD     word2
+       uint32_t word3;
+#define lpfc_wcqe_r_valid_SHIFT                lpfc_cqe_valid_SHIFT
+#define lpfc_wcqe_r_valid_MASK         lpfc_cqe_valid_MASK
+#define lpfc_wcqe_r_valid_WORD         lpfc_cqe_valid_WORD
+#define lpfc_wcqe_r_code_SHIFT         lpfc_cqe_code_SHIFT
+#define lpfc_wcqe_r_code_MASK          lpfc_cqe_code_MASK
+#define lpfc_wcqe_r_code_WORD          lpfc_cqe_code_WORD
+};
+
+struct sli4_wcqe_xri_aborted {
+       uint32_t word0;
+#define lpfc_wcqe_xa_status_SHIFT              8
+#define lpfc_wcqe_xa_status_MASK               0x000000FF
+#define lpfc_wcqe_xa_status_WORD               word0
+       uint32_t parameter;
+       uint32_t word2;
+#define lpfc_wcqe_xa_remote_xid_SHIFT  16
+#define lpfc_wcqe_xa_remote_xid_MASK   0x0000FFFF
+#define lpfc_wcqe_xa_remote_xid_WORD   word2
+#define lpfc_wcqe_xa_xri_SHIFT         0
+#define lpfc_wcqe_xa_xri_MASK          0x0000FFFF
+#define lpfc_wcqe_xa_xri_WORD          word2
+       uint32_t word3;
+#define lpfc_wcqe_xa_valid_SHIFT       lpfc_cqe_valid_SHIFT
+#define lpfc_wcqe_xa_valid_MASK                lpfc_cqe_valid_MASK
+#define lpfc_wcqe_xa_valid_WORD                lpfc_cqe_valid_WORD
+#define lpfc_wcqe_xa_ia_SHIFT          30
+#define lpfc_wcqe_xa_ia_MASK           0x00000001
+#define lpfc_wcqe_xa_ia_WORD           word3
+#define CQE_XRI_ABORTED_IA_REMOTE      0
+#define CQE_XRI_ABORTED_IA_LOCAL       1
+#define lpfc_wcqe_xa_br_SHIFT          29
+#define lpfc_wcqe_xa_br_MASK           0x00000001
+#define lpfc_wcqe_xa_br_WORD           word3
+#define CQE_XRI_ABORTED_BR_BA_ACC      0
+#define CQE_XRI_ABORTED_BR_BA_RJT      1
+#define lpfc_wcqe_xa_eo_SHIFT          28
+#define lpfc_wcqe_xa_eo_MASK           0x00000001
+#define lpfc_wcqe_xa_eo_WORD           word3
+#define CQE_XRI_ABORTED_EO_REMOTE      0
+#define CQE_XRI_ABORTED_EO_LOCAL       1
+#define lpfc_wcqe_xa_code_SHIFT                lpfc_cqe_code_SHIFT
+#define lpfc_wcqe_xa_code_MASK         lpfc_cqe_code_MASK
+#define lpfc_wcqe_xa_code_WORD         lpfc_cqe_code_WORD
+};
+
+/* completion queue entry structure for rqe completion */
+struct lpfc_rcqe {
+       uint32_t word0;
+#define lpfc_rcqe_bindex_SHIFT         16
+#define lpfc_rcqe_bindex_MASK          0x0000FFF
+#define lpfc_rcqe_bindex_WORD          word0
+#define lpfc_rcqe_status_SHIFT         8
+#define lpfc_rcqe_status_MASK          0x000000FF
+#define lpfc_rcqe_status_WORD          word0
+#define FC_STATUS_RQ_SUCCESS           0x10 /* Async receive successful */
+#define FC_STATUS_RQ_BUF_LEN_EXCEEDED  0x11 /* payload truncated */
+#define FC_STATUS_INSUFF_BUF_NEED_BUF  0x12 /* Insufficient buffers */
+#define FC_STATUS_INSUFF_BUF_FRM_DISC  0x13 /* Frame Discard */
+       uint32_t reserved1;
+       uint32_t word2;
+#define lpfc_rcqe_length_SHIFT         16
+#define lpfc_rcqe_length_MASK          0x0000FFFF
+#define lpfc_rcqe_length_WORD          word2
+#define lpfc_rcqe_rq_id_SHIFT          6
+#define lpfc_rcqe_rq_id_MASK           0x000003FF
+#define lpfc_rcqe_rq_id_WORD           word2
+#define lpfc_rcqe_fcf_id_SHIFT         0
+#define lpfc_rcqe_fcf_id_MASK          0x0000003F
+#define lpfc_rcqe_fcf_id_WORD          word2
+       uint32_t word3;
+#define lpfc_rcqe_valid_SHIFT          lpfc_cqe_valid_SHIFT
+#define lpfc_rcqe_valid_MASK           lpfc_cqe_valid_MASK
+#define lpfc_rcqe_valid_WORD           lpfc_cqe_valid_WORD
+#define lpfc_rcqe_port_SHIFT           30
+#define lpfc_rcqe_port_MASK            0x00000001
+#define lpfc_rcqe_port_WORD            word3
+#define lpfc_rcqe_hdr_length_SHIFT     24
+#define lpfc_rcqe_hdr_length_MASK      0x0000001F
+#define lpfc_rcqe_hdr_length_WORD      word3
+#define lpfc_rcqe_code_SHIFT           lpfc_cqe_code_SHIFT
+#define lpfc_rcqe_code_MASK            lpfc_cqe_code_MASK
+#define lpfc_rcqe_code_WORD            lpfc_cqe_code_WORD
+#define lpfc_rcqe_eof_SHIFT            8
+#define lpfc_rcqe_eof_MASK             0x000000FF
+#define lpfc_rcqe_eof_WORD             word3
+#define FCOE_EOFn      0x41
+#define FCOE_EOFt      0x42
+#define FCOE_EOFni     0x49
+#define FCOE_EOFa      0x50
+#define lpfc_rcqe_sof_SHIFT            0
+#define lpfc_rcqe_sof_MASK             0x000000FF
+#define lpfc_rcqe_sof_WORD             word3
+#define FCOE_SOFi2     0x2d
+#define FCOE_SOFi3     0x2e
+#define FCOE_SOFn2     0x35
+#define FCOE_SOFn3     0x36
+};
+
+struct lpfc_wqe_generic{
+       struct ulp_bde64 bde;
+       uint32_t word3;
+       uint32_t word4;
+       uint32_t word5;
+       uint32_t word6;
+#define lpfc_wqe_gen_context_SHIFT     16
+#define lpfc_wqe_gen_context_MASK      0x0000FFFF
+#define lpfc_wqe_gen_context_WORD      word6
+#define lpfc_wqe_gen_xri_SHIFT         0
+#define lpfc_wqe_gen_xri_MASK          0x0000FFFF
+#define lpfc_wqe_gen_xri_WORD          word6
+       uint32_t word7;
+#define lpfc_wqe_gen_lnk_SHIFT         23
+#define lpfc_wqe_gen_lnk_MASK          0x00000001
+#define lpfc_wqe_gen_lnk_WORD          word7
+#define lpfc_wqe_gen_erp_SHIFT         22
+#define lpfc_wqe_gen_erp_MASK          0x00000001
+#define lpfc_wqe_gen_erp_WORD          word7
+#define lpfc_wqe_gen_pu_SHIFT          20
+#define lpfc_wqe_gen_pu_MASK           0x00000003
+#define lpfc_wqe_gen_pu_WORD           word7
+#define lpfc_wqe_gen_class_SHIFT       16
+#define lpfc_wqe_gen_class_MASK                0x00000007
+#define lpfc_wqe_gen_class_WORD                word7
+#define lpfc_wqe_gen_command_SHIFT     8
+#define lpfc_wqe_gen_command_MASK      0x000000FF
+#define lpfc_wqe_gen_command_WORD      word7
+#define lpfc_wqe_gen_status_SHIFT      4
+#define lpfc_wqe_gen_status_MASK       0x0000000F
+#define lpfc_wqe_gen_status_WORD       word7
+#define lpfc_wqe_gen_ct_SHIFT          2
+#define lpfc_wqe_gen_ct_MASK           0x00000007
+#define lpfc_wqe_gen_ct_WORD           word7
+       uint32_t abort_tag;
+       uint32_t word9;
+#define lpfc_wqe_gen_request_tag_SHIFT 0
+#define lpfc_wqe_gen_request_tag_MASK  0x0000FFFF
+#define lpfc_wqe_gen_request_tag_WORD  word9
+       uint32_t word10;
+#define lpfc_wqe_gen_ccp_SHIFT         24
+#define lpfc_wqe_gen_ccp_MASK          0x000000FF
+#define lpfc_wqe_gen_ccp_WORD          word10
+#define lpfc_wqe_gen_ccpe_SHIFT                23
+#define lpfc_wqe_gen_ccpe_MASK         0x00000001
+#define lpfc_wqe_gen_ccpe_WORD         word10
+#define lpfc_wqe_gen_pv_SHIFT          19
+#define lpfc_wqe_gen_pv_MASK           0x00000001
+#define lpfc_wqe_gen_pv_WORD           word10
+#define lpfc_wqe_gen_pri_SHIFT         16
+#define lpfc_wqe_gen_pri_MASK          0x00000007
+#define lpfc_wqe_gen_pri_WORD          word10
+       uint32_t word11;
+#define lpfc_wqe_gen_cq_id_SHIFT       16
+#define lpfc_wqe_gen_cq_id_MASK                0x000003FF
+#define lpfc_wqe_gen_cq_id_WORD                word11
+#define LPFC_WQE_CQ_ID_DEFAULT 0x3ff
+#define lpfc_wqe_gen_wqec_SHIFT                7
+#define lpfc_wqe_gen_wqec_MASK         0x00000001
+#define lpfc_wqe_gen_wqec_WORD         word11
+#define lpfc_wqe_gen_cmd_type_SHIFT    0
+#define lpfc_wqe_gen_cmd_type_MASK     0x0000000F
+#define lpfc_wqe_gen_cmd_type_WORD     word11
+       uint32_t payload[4];
+};
+
+struct lpfc_rqe {
+       uint32_t address_hi;
+       uint32_t address_lo;
+};
+
+/* buffer descriptors */
+struct lpfc_bde4 {
+       uint32_t addr_hi;
+       uint32_t addr_lo;
+       uint32_t word2;
+#define lpfc_bde4_last_SHIFT           31
+#define lpfc_bde4_last_MASK            0x00000001
+#define lpfc_bde4_last_WORD            word2
+#define lpfc_bde4_sge_offset_SHIFT     0
+#define lpfc_bde4_sge_offset_MASK      0x000003FF
+#define lpfc_bde4_sge_offset_WORD      word2
+       uint32_t word3;
+#define lpfc_bde4_length_SHIFT         0
+#define lpfc_bde4_length_MASK          0x000000FF
+#define lpfc_bde4_length_WORD          word3
+};
+
+struct lpfc_register {
+       uint32_t word0;
+};
+
+#define LPFC_UERR_STATUS_HI            0x00A4
+#define LPFC_UERR_STATUS_LO            0x00A0
+#define LPFC_ONLINE0                   0x00B0
+#define LPFC_ONLINE1                   0x00B4
+#define LPFC_SCRATCHPAD                        0x0058
+
+/* BAR0 Registers */
+#define LPFC_HST_STATE                 0x00AC
+#define lpfc_hst_state_perr_SHIFT      31
+#define lpfc_hst_state_perr_MASK       0x1
+#define lpfc_hst_state_perr_WORD       word0
+#define lpfc_hst_state_sfi_SHIFT       30
+#define lpfc_hst_state_sfi_MASK                0x1
+#define lpfc_hst_state_sfi_WORD                word0
+#define lpfc_hst_state_nip_SHIFT       29
+#define lpfc_hst_state_nip_MASK                0x1
+#define lpfc_hst_state_nip_WORD                word0
+#define lpfc_hst_state_ipc_SHIFT       28
+#define lpfc_hst_state_ipc_MASK                0x1
+#define lpfc_hst_state_ipc_WORD                word0
+#define lpfc_hst_state_xrom_SHIFT      27
+#define lpfc_hst_state_xrom_MASK       0x1
+#define lpfc_hst_state_xrom_WORD       word0
+#define lpfc_hst_state_dl_SHIFT                26
+#define lpfc_hst_state_dl_MASK         0x1
+#define lpfc_hst_state_dl_WORD         word0
+#define lpfc_hst_state_port_status_SHIFT       0
+#define lpfc_hst_state_port_status_MASK                0xFFFF
+#define lpfc_hst_state_port_status_WORD                word0
+
+#define LPFC_POST_STAGE_POWER_ON_RESET                 0x0000
+#define LPFC_POST_STAGE_AWAITING_HOST_RDY              0x0001
+#define LPFC_POST_STAGE_HOST_RDY                       0x0002
+#define LPFC_POST_STAGE_BE_RESET                       0x0003
+#define LPFC_POST_STAGE_SEEPROM_CS_START               0x0100
+#define LPFC_POST_STAGE_SEEPROM_CS_DONE                        0x0101
+#define LPFC_POST_STAGE_DDR_CONFIG_START               0x0200
+#define LPFC_POST_STAGE_DDR_CONFIG_DONE                        0x0201
+#define LPFC_POST_STAGE_DDR_CALIBRATE_START            0x0300
+#define LPFC_POST_STAGE_DDR_CALIBRATE_DONE             0x0301
+#define LPFC_POST_STAGE_DDR_TEST_START                 0x0400
+#define LPFC_POST_STAGE_DDR_TEST_DONE                  0x0401
+#define LPFC_POST_STAGE_REDBOOT_INIT_START             0x0600
+#define LPFC_POST_STAGE_REDBOOT_INIT_DONE              0x0601
+#define LPFC_POST_STAGE_FW_IMAGE_LOAD_START            0x0700
+#define LPFC_POST_STAGE_FW_IMAGE_LOAD_DONE             0x0701
+#define LPFC_POST_STAGE_ARMFW_START                    0x0800
+#define LPFC_POST_STAGE_DHCP_QUERY_START               0x0900
+#define LPFC_POST_STAGE_DHCP_QUERY_DONE                        0x0901
+#define LPFC_POST_STAGE_BOOT_TARGET_DISCOVERY_START    0x0A00
+#define LPFC_POST_STAGE_BOOT_TARGET_DISCOVERY_DONE     0x0A01
+#define LPFC_POST_STAGE_RC_OPTION_SET                  0x0B00
+#define LPFC_POST_STAGE_SWITCH_LINK                    0x0B01
+#define LPFC_POST_STAGE_SEND_ICDS_MESSAGE              0x0B02
+#define LPFC_POST_STAGE_PERFROM_TFTP                   0x0B03
+#define LPFC_POST_STAGE_PARSE_XML                      0x0B04
+#define LPFC_POST_STAGE_DOWNLOAD_IMAGE                 0x0B05
+#define LPFC_POST_STAGE_FLASH_IMAGE                    0x0B06
+#define LPFC_POST_STAGE_RC_DONE                                0x0B07
+#define LPFC_POST_STAGE_REBOOT_SYSTEM                  0x0B08
+#define LPFC_POST_STAGE_MAC_ADDRESS                    0x0C00
+#define LPFC_POST_STAGE_ARMFW_READY                    0xC000
+#define LPFC_POST_STAGE_ARMFW_UE                       0xF000
+
+#define lpfc_scratchpad_slirev_SHIFT                   4
+#define lpfc_scratchpad_slirev_MASK                    0xF
+#define lpfc_scratchpad_slirev_WORD                    word0
+#define lpfc_scratchpad_chiptype_SHIFT                 8
+#define lpfc_scratchpad_chiptype_MASK                  0xFF
+#define lpfc_scratchpad_chiptype_WORD                  word0
+#define lpfc_scratchpad_featurelevel1_SHIFT            16
+#define lpfc_scratchpad_featurelevel1_MASK             0xFF
+#define lpfc_scratchpad_featurelevel1_WORD             word0
+#define lpfc_scratchpad_featurelevel2_SHIFT            24
+#define lpfc_scratchpad_featurelevel2_MASK             0xFF
+#define lpfc_scratchpad_featurelevel2_WORD             word0
+
+/* BAR1 Registers */
+#define LPFC_IMR_MASK_ALL      0xFFFFFFFF
+#define LPFC_ISCR_CLEAR_ALL    0xFFFFFFFF
+
+#define LPFC_HST_ISR0          0x0C18
+#define LPFC_HST_ISR1          0x0C1C
+#define LPFC_HST_ISR2          0x0C20
+#define LPFC_HST_ISR3          0x0C24
+#define LPFC_HST_ISR4          0x0C28
+
+#define LPFC_HST_IMR0          0x0C48
+#define LPFC_HST_IMR1          0x0C4C
+#define LPFC_HST_IMR2          0x0C50
+#define LPFC_HST_IMR3          0x0C54
+#define LPFC_HST_IMR4          0x0C58
+
+#define LPFC_HST_ISCR0         0x0C78
+#define LPFC_HST_ISCR1         0x0C7C
+#define LPFC_HST_ISCR2         0x0C80
+#define LPFC_HST_ISCR3         0x0C84
+#define LPFC_HST_ISCR4         0x0C88
+
+#define LPFC_SLI4_INTR0                        BIT0
+#define LPFC_SLI4_INTR1                        BIT1
+#define LPFC_SLI4_INTR2                        BIT2
+#define LPFC_SLI4_INTR3                        BIT3
+#define LPFC_SLI4_INTR4                        BIT4
+#define LPFC_SLI4_INTR5                        BIT5
+#define LPFC_SLI4_INTR6                        BIT6
+#define LPFC_SLI4_INTR7                        BIT7
+#define LPFC_SLI4_INTR8                        BIT8
+#define LPFC_SLI4_INTR9                        BIT9
+#define LPFC_SLI4_INTR10               BIT10
+#define LPFC_SLI4_INTR11               BIT11
+#define LPFC_SLI4_INTR12               BIT12
+#define LPFC_SLI4_INTR13               BIT13
+#define LPFC_SLI4_INTR14               BIT14
+#define LPFC_SLI4_INTR15               BIT15
+#define LPFC_SLI4_INTR16               BIT16
+#define LPFC_SLI4_INTR17               BIT17
+#define LPFC_SLI4_INTR18               BIT18
+#define LPFC_SLI4_INTR19               BIT19
+#define LPFC_SLI4_INTR20               BIT20
+#define LPFC_SLI4_INTR21               BIT21
+#define LPFC_SLI4_INTR22               BIT22
+#define LPFC_SLI4_INTR23               BIT23
+#define LPFC_SLI4_INTR24               BIT24
+#define LPFC_SLI4_INTR25               BIT25
+#define LPFC_SLI4_INTR26               BIT26
+#define LPFC_SLI4_INTR27               BIT27
+#define LPFC_SLI4_INTR28               BIT28
+#define LPFC_SLI4_INTR29               BIT29
+#define LPFC_SLI4_INTR30               BIT30
+#define LPFC_SLI4_INTR31               BIT31
+
+/* BAR2 Registers */
+#define LPFC_RQ_DOORBELL               0x00A0
+#define lpfc_rq_doorbell_num_posted_SHIFT      16
+#define lpfc_rq_doorbell_num_posted_MASK       0x3FFF
+#define lpfc_rq_doorbell_num_posted_WORD       word0
+#define LPFC_RQ_POST_BATCH             8       /* RQEs to post at one time */
+#define lpfc_rq_doorbell_id_SHIFT              0
+#define lpfc_rq_doorbell_id_MASK               0x03FF
+#define lpfc_rq_doorbell_id_WORD               word0
+
+#define LPFC_WQ_DOORBELL               0x0040
+#define lpfc_wq_doorbell_num_posted_SHIFT      24
+#define lpfc_wq_doorbell_num_posted_MASK       0x00FF
+#define lpfc_wq_doorbell_num_posted_WORD       word0
+#define lpfc_wq_doorbell_index_SHIFT           16
+#define lpfc_wq_doorbell_index_MASK            0x00FF
+#define lpfc_wq_doorbell_index_WORD            word0
+#define lpfc_wq_doorbell_id_SHIFT              0
+#define lpfc_wq_doorbell_id_MASK               0xFFFF
+#define lpfc_wq_doorbell_id_WORD               word0
+
+#define LPFC_EQCQ_DOORBELL             0x0120
+#define lpfc_eqcq_doorbell_arm_SHIFT           29
+#define lpfc_eqcq_doorbell_arm_MASK            0x0001
+#define lpfc_eqcq_doorbell_arm_WORD            word0
+#define lpfc_eqcq_doorbell_num_released_SHIFT  16
+#define lpfc_eqcq_doorbell_num_released_MASK   0x1FFF
+#define lpfc_eqcq_doorbell_num_released_WORD   word0
+#define lpfc_eqcq_doorbell_qt_SHIFT            10
+#define lpfc_eqcq_doorbell_qt_MASK             0x0001
+#define lpfc_eqcq_doorbell_qt_WORD             word0
+#define LPFC_QUEUE_TYPE_COMPLETION     0
+#define LPFC_QUEUE_TYPE_EVENT          1
+#define lpfc_eqcq_doorbell_eqci_SHIFT          9
+#define lpfc_eqcq_doorbell_eqci_MASK           0x0001
+#define lpfc_eqcq_doorbell_eqci_WORD           word0
+#define lpfc_eqcq_doorbell_cqid_SHIFT          0
+#define lpfc_eqcq_doorbell_cqid_MASK           0x03FF
+#define lpfc_eqcq_doorbell_cqid_WORD           word0
+#define lpfc_eqcq_doorbell_eqid_SHIFT          0
+#define lpfc_eqcq_doorbell_eqid_MASK           0x01FF
+#define lpfc_eqcq_doorbell_eqid_WORD           word0
+
+#define LPFC_BMBX                      0x0160
+#define lpfc_bmbx_addr_SHIFT           2
+#define lpfc_bmbx_addr_MASK            0x3FFFFFFF
+#define lpfc_bmbx_addr_WORD            word0
+#define lpfc_bmbx_hi_SHIFT             1
+#define lpfc_bmbx_hi_MASK              0x0001
+#define lpfc_bmbx_hi_WORD              word0
+#define lpfc_bmbx_rdy_SHIFT            0
+#define lpfc_bmbx_rdy_MASK             0x0001
+#define lpfc_bmbx_rdy_WORD             word0
+
+#define LPFC_MQ_DOORBELL                       0x0140
+#define lpfc_mq_doorbell_num_posted_SHIFT      16
+#define lpfc_mq_doorbell_num_posted_MASK       0x3FFF
+#define lpfc_mq_doorbell_num_posted_WORD       word0
+#define lpfc_mq_doorbell_id_SHIFT              0
+#define lpfc_mq_doorbell_id_MASK               0x03FF
+#define lpfc_mq_doorbell_id_WORD               word0
+
+struct lpfc_sli4_cfg_mhdr {
+       uint32_t word1;
+#define lpfc_mbox_hdr_emb_SHIFT                0
+#define lpfc_mbox_hdr_emb_MASK         0x00000001
+#define lpfc_mbox_hdr_emb_WORD         word1
+#define lpfc_mbox_hdr_sge_cnt_SHIFT    3
+#define lpfc_mbox_hdr_sge_cnt_MASK     0x0000001F
+#define lpfc_mbox_hdr_sge_cnt_WORD     word1
+       uint32_t payload_length;
+       uint32_t tag_lo;
+       uint32_t tag_hi;
+       uint32_t reserved5;
+};
+
+union lpfc_sli4_cfg_shdr {
+       struct {
+               uint32_t word6;
+#define lpfc_mbox_hdr_opcode_SHIFT             0
+#define lpfc_mbox_hdr_opcode_MASK              0x000000FF
+#define lpfc_mbox_hdr_opcode_WORD              word6
+#define lpfc_mbox_hdr_subsystem_SHIFT          8
+#define lpfc_mbox_hdr_subsystem_MASK           0x000000FF
+#define lpfc_mbox_hdr_subsystem_WORD           word6
+#define lpfc_mbox_hdr_port_number_SHIFT                16
+#define lpfc_mbox_hdr_port_number_MASK         0x000000FF
+#define lpfc_mbox_hdr_port_number_WORD         word6
+#define lpfc_mbox_hdr_domain_SHIFT             24
+#define lpfc_mbox_hdr_domain_MASK              0x000000FF
+#define lpfc_mbox_hdr_domain_WORD              word6
+               uint32_t timeout;
+               uint32_t request_length;
+               uint32_t reserved9;
+       } request;
+       struct {
+               uint32_t word6;
+#define lpfc_mbox_hdr_opcode_SHIFT             0
+#define lpfc_mbox_hdr_opcode_MASK              0x000000FF
+#define lpfc_mbox_hdr_opcode_WORD              word6
+#define lpfc_mbox_hdr_subsystem_SHIFT          8
+#define lpfc_mbox_hdr_subsystem_MASK           0x000000FF
+#define lpfc_mbox_hdr_subsystem_WORD           word6
+#define lpfc_mbox_hdr_domain_SHIFT             24
+#define lpfc_mbox_hdr_domain_MASK              0x000000FF
+#define lpfc_mbox_hdr_domain_WORD              word6
+               uint32_t word7;
+#define lpfc_mbox_hdr_status_SHIFT             0
+#define lpfc_mbox_hdr_status_MASK              0x000000FF
+#define lpfc_mbox_hdr_status_WORD              word7
+#define lpfc_mbox_hdr_add_status_SHIFT         8
+#define lpfc_mbox_hdr_add_status_MASK          0x000000FF
+#define lpfc_mbox_hdr_add_status_WORD          word7
+               uint32_t response_length;
+               uint32_t actual_response_length;
+       } response;
+};
+
+/* Mailbox structures */
+struct mbox_header {
+       struct lpfc_sli4_cfg_mhdr cfg_mhdr;
+       union  lpfc_sli4_cfg_shdr cfg_shdr;
+};
+
+/* Subsystem Definitions */
+#define LPFC_MBOX_SUBSYSTEM_COMMON     0x1
+#define LPFC_MBOX_SUBSYSTEM_FCOE       0xC
+
+/* Device Specific Definitions */
+
+/* The HOST ENDIAN defines are in Big Endian format. */
+#define HOST_ENDIAN_LOW_WORD0   0xFF3412FF
+#define HOST_ENDIAN_HIGH_WORD1 0xFF7856FF
+
+/* Common Opcodes */
+#define LPFC_MBOX_OPCODE_CQ_CREATE             0x0C
+#define LPFC_MBOX_OPCODE_EQ_CREATE             0x0D
+#define LPFC_MBOX_OPCODE_MQ_CREATE             0x15
+#define LPFC_MBOX_OPCODE_GET_CNTL_ATTRIBUTES   0x20
+#define LPFC_MBOX_OPCODE_NOP                   0x21
+#define LPFC_MBOX_OPCODE_MQ_DESTROY            0x35
+#define LPFC_MBOX_OPCODE_CQ_DESTROY            0x36
+#define LPFC_MBOX_OPCODE_EQ_DESTROY            0x37
+#define LPFC_MBOX_OPCODE_FUNCTION_RESET                0x3D
+
+/* FCoE Opcodes */
+#define LPFC_MBOX_OPCODE_FCOE_WQ_CREATE                        0x01
+#define LPFC_MBOX_OPCODE_FCOE_WQ_DESTROY               0x02
+#define LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES           0x03
+#define LPFC_MBOX_OPCODE_FCOE_REMOVE_SGL_PAGES         0x04
+#define LPFC_MBOX_OPCODE_FCOE_RQ_CREATE                        0x05
+#define LPFC_MBOX_OPCODE_FCOE_RQ_DESTROY               0x06
+#define LPFC_MBOX_OPCODE_FCOE_READ_FCF_TABLE           0x08
+#define LPFC_MBOX_OPCODE_FCOE_ADD_FCF                  0x09
+#define LPFC_MBOX_OPCODE_FCOE_DELETE_FCF               0x0A
+#define LPFC_MBOX_OPCODE_FCOE_POST_HDR_TEMPLATE                0x0B
+
+/* Mailbox command structures */
+struct eq_context {
+       uint32_t word0;
+#define lpfc_eq_context_size_SHIFT     31
+#define lpfc_eq_context_size_MASK      0x00000001
+#define lpfc_eq_context_size_WORD      word0
+#define LPFC_EQE_SIZE_4                        0x0
+#define LPFC_EQE_SIZE_16               0x1
+#define lpfc_eq_context_valid_SHIFT    29
+#define lpfc_eq_context_valid_MASK     0x00000001
+#define lpfc_eq_context_valid_WORD     word0
+       uint32_t word1;
+#define lpfc_eq_context_count_SHIFT    26
+#define lpfc_eq_context_count_MASK     0x00000003
+#define lpfc_eq_context_count_WORD     word1
+#define LPFC_EQ_CNT_256                0x0
+#define LPFC_EQ_CNT_512                0x1
+#define LPFC_EQ_CNT_1024       0x2
+#define LPFC_EQ_CNT_2048       0x3
+#define LPFC_EQ_CNT_4096       0x4
+       uint32_t word2;
+#define lpfc_eq_context_delay_multi_SHIFT      13
+#define lpfc_eq_context_delay_multi_MASK       0x000003FF
+#define lpfc_eq_context_delay_multi_WORD       word2
+       uint32_t reserved3;
+};
+
+struct sgl_page_pairs {
+       uint32_t sgl_pg0_addr_lo;
+       uint32_t sgl_pg0_addr_hi;
+       uint32_t sgl_pg1_addr_lo;
+       uint32_t sgl_pg1_addr_hi;
+};
+
+struct lpfc_mbx_post_sgl_pages {
+       struct mbox_header header;
+       uint32_t word0;
+#define lpfc_post_sgl_pages_xri_SHIFT  0
+#define lpfc_post_sgl_pages_xri_MASK   0x0000FFFF
+#define lpfc_post_sgl_pages_xri_WORD   word0
+#define lpfc_post_sgl_pages_xricnt_SHIFT       16
+#define lpfc_post_sgl_pages_xricnt_MASK        0x0000FFFF
+#define lpfc_post_sgl_pages_xricnt_WORD        word0
+       struct sgl_page_pairs  sgl_pg_pairs[1];
+};
+
+/* word0 of page-1 struct shares the same SHIFT/MASK/WORD defines as above */
+struct lpfc_mbx_post_uembed_sgl_page1 {
+       union  lpfc_sli4_cfg_shdr cfg_shdr;
+       uint32_t word0;
+       struct sgl_page_pairs sgl_pg_pairs;
+};
+
+struct lpfc_mbx_sge {
+       uint32_t pa_lo;
+       uint32_t pa_hi;
+       uint32_t length;
+};
+
+struct lpfc_mbx_nembed_cmd {
+       struct lpfc_sli4_cfg_mhdr cfg_mhdr;
+#define LPFC_SLI4_MBX_SGE_MAX_PAGES    19
+       struct lpfc_mbx_sge sge[LPFC_SLI4_MBX_SGE_MAX_PAGES];
+};
+
+struct lpfc_mbx_nembed_sge_virt {
+       void *addr[LPFC_SLI4_MBX_SGE_MAX_PAGES];
+};
+
+struct lpfc_mbx_eq_create {
+       struct mbox_header header;
+       union {
+               struct {
+                       uint32_t word0;
+#define lpfc_mbx_eq_create_num_pages_SHIFT     0
+#define lpfc_mbx_eq_create_num_pages_MASK      0x0000FFFF
+#define lpfc_mbx_eq_create_num_pages_WORD      word0
+                       struct eq_context context;
+                       struct dma_address page[LPFC_MAX_EQ_PAGE];
+               } request;
+               struct {
+                       uint32_t word0;
+#define lpfc_mbx_eq_create_q_id_SHIFT  0
+#define lpfc_mbx_eq_create_q_id_MASK   0x0000FFFF
+#define lpfc_mbx_eq_create_q_id_WORD   word0
+               } response;
+       } u;
+};
+
+struct lpfc_mbx_eq_destroy {
+       struct mbox_header header;
+       union {
+               struct {
+                       uint32_t word0;
+#define lpfc_mbx_eq_destroy_q_id_SHIFT 0
+#define lpfc_mbx_eq_destroy_q_id_MASK  0x0000FFFF
+#define lpfc_mbx_eq_destroy_q_id_WORD  word0
+               } request;
+               struct {
+                       uint32_t word0;
+               } response;
+       } u;
+};
+
+struct lpfc_mbx_nop {
+       struct mbox_header header;
+       uint32_t context[2];
+};
+
+struct cq_context {
+       uint32_t word0;
+#define lpfc_cq_context_event_SHIFT    31
+#define lpfc_cq_context_event_MASK     0x00000001
+#define lpfc_cq_context_event_WORD     word0
+#define lpfc_cq_context_valid_SHIFT    29
+#define lpfc_cq_context_valid_MASK     0x00000001
+#define lpfc_cq_context_valid_WORD     word0
+#define lpfc_cq_context_count_SHIFT    27
+#define lpfc_cq_context_count_MASK     0x00000003
+#define lpfc_cq_context_count_WORD     word0
+#define LPFC_CQ_CNT_256                0x0
+#define LPFC_CQ_CNT_512                0x1
+#define LPFC_CQ_CNT_1024       0x2
+       uint32_t word1;
+#define lpfc_cq_eq_id_SHIFT            22
+#define lpfc_cq_eq_id_MASK             0x000000FF
+#define lpfc_cq_eq_id_WORD             word1
+       uint32_t reserved0;
+       uint32_t reserved1;
+};
+
+struct lpfc_mbx_cq_create {
+       struct mbox_header header;
+       union {
+               struct {
+                       uint32_t word0;
+#define lpfc_mbx_cq_create_num_pages_SHIFT     0
+#define lpfc_mbx_cq_create_num_pages_MASK      0x0000FFFF
+#define lpfc_mbx_cq_create_num_pages_WORD      word0
+                       struct cq_context context;
+                       struct dma_address page[LPFC_MAX_CQ_PAGE];
+               } request;
+               struct {
+                       uint32_t word0;
+#define lpfc_mbx_cq_create_q_id_SHIFT  0
+#define lpfc_mbx_cq_create_q_id_MASK   0x0000FFFF
+#define lpfc_mbx_cq_create_q_id_WORD   word0
+               } response;
+       } u;
+};
+
+struct lpfc_mbx_cq_destroy {
+       struct mbox_header header;
+       union {
+               struct {
+                       uint32_t word0;
+#define lpfc_mbx_cq_destroy_q_id_SHIFT 0
+#define lpfc_mbx_cq_destroy_q_id_MASK  0x0000FFFF
+#define lpfc_mbx_cq_destroy_q_id_WORD  word0
+               } request;
+               struct {
+                       uint32_t word0;
+               } response;
+       } u;
+};
+
+struct wq_context {
+       uint32_t reserved0;
+       uint32_t reserved1;
+       uint32_t reserved2;
+       uint32_t reserved3;
+};
+
+struct lpfc_mbx_wq_create {
+       struct mbox_header header;
+       union {
+               struct {
+                       uint32_t word0;
+#define lpfc_mbx_wq_create_num_pages_SHIFT     0
+#define lpfc_mbx_wq_create_num_pages_MASK      0x0000FFFF
+#define lpfc_mbx_wq_create_num_pages_WORD      word0
+#define lpfc_mbx_wq_create_cq_id_SHIFT         16
+#define lpfc_mbx_wq_create_cq_id_MASK          0x0000FFFF
+#define lpfc_mbx_wq_create_cq_id_WORD          word0
+                       struct dma_address page[LPFC_MAX_WQ_PAGE];
+               } request;
+               struct {
+                       uint32_t word0;
+#define lpfc_mbx_wq_create_q_id_SHIFT  0
+#define lpfc_mbx_wq_create_q_id_MASK   0x0000FFFF
+#define lpfc_mbx_wq_create_q_id_WORD   word0
+               } response;
+       } u;
+};
+
+struct lpfc_mbx_wq_destroy {
+       struct mbox_header header;
+       union {
+               struct {
+                       uint32_t word0;
+#define lpfc_mbx_wq_destroy_q_id_SHIFT 0
+#define lpfc_mbx_wq_destroy_q_id_MASK  0x0000FFFF
+#define lpfc_mbx_wq_destroy_q_id_WORD  word0
+               } request;
+               struct {
+                       uint32_t word0;
+               } response;
+       } u;
+};
+
+#define LPFC_HDR_BUF_SIZE 128
+#define LPFC_DATA_BUF_SIZE 4096
+struct rq_context {
+       uint32_t word0;
+#define lpfc_rq_context_rq_size_SHIFT  16
+#define lpfc_rq_context_rq_size_MASK   0x0000000F
+#define lpfc_rq_context_rq_size_WORD   word0
+#define LPFC_RQ_RING_SIZE_512          9       /* 512 entries */
+#define LPFC_RQ_RING_SIZE_1024         10      /* 1024 entries */
+#define LPFC_RQ_RING_SIZE_2048         11      /* 2048 entries */
+#define LPFC_RQ_RING_SIZE_4096         12      /* 4096 entries */
+       uint32_t reserved1;
+       uint32_t word2;
+#define lpfc_rq_context_cq_id_SHIFT    16
+#define lpfc_rq_context_cq_id_MASK     0x000003FF
+#define lpfc_rq_context_cq_id_WORD     word2
+#define lpfc_rq_context_buf_size_SHIFT 0
+#define lpfc_rq_context_buf_size_MASK  0x0000FFFF
+#define lpfc_rq_context_buf_size_WORD  word2
+       uint32_t reserved3;
+};
+
+struct lpfc_mbx_rq_create {
+       struct mbox_header header;
+       union {
+               struct {
+                       uint32_t word0;
+#define lpfc_mbx_rq_create_num_pages_SHIFT     0
+#define lpfc_mbx_rq_create_num_pages_MASK      0x0000FFFF
+#define lpfc_mbx_rq_create_num_pages_WORD      word0
+                       struct rq_context context;
+                       struct dma_address page[LPFC_MAX_WQ_PAGE];
+               } request;
+               struct {
+                       uint32_t word0;
+#define lpfc_mbx_rq_create_q_id_SHIFT  0
+#define lpfc_mbx_rq_create_q_id_MASK   0x0000FFFF
+#define lpfc_mbx_rq_create_q_id_WORD   word0
+               } response;
+       } u;
+};
+
+struct lpfc_mbx_rq_destroy {
+       struct mbox_header header;
+       union {
+               struct {
+                       uint32_t word0;
+#define lpfc_mbx_rq_destroy_q_id_SHIFT 0
+#define lpfc_mbx_rq_destroy_q_id_MASK  0x0000FFFF
+#define lpfc_mbx_rq_destroy_q_id_WORD  word0
+               } request;
+               struct {
+                       uint32_t word0;
+               } response;
+       } u;
+};
+
+struct mq_context {
+       uint32_t word0;
+#define lpfc_mq_context_cq_id_SHIFT    22
+#define lpfc_mq_context_cq_id_MASK     0x000003FF
+#define lpfc_mq_context_cq_id_WORD     word0
+#define lpfc_mq_context_count_SHIFT    16
+#define lpfc_mq_context_count_MASK     0x0000000F
+#define lpfc_mq_context_count_WORD     word0
+#define LPFC_MQ_CNT_16         0x5
+#define LPFC_MQ_CNT_32         0x6
+#define LPFC_MQ_CNT_64         0x7
+#define LPFC_MQ_CNT_128                0x8
+       uint32_t word1;
+#define lpfc_mq_context_valid_SHIFT    31
+#define lpfc_mq_context_valid_MASK     0x00000001
+#define lpfc_mq_context_valid_WORD     word1
+       uint32_t reserved2;
+       uint32_t reserved3;
+};
+
+struct lpfc_mbx_mq_create {
+       struct mbox_header header;
+       union {
+               struct {
+                       uint32_t word0;
+#define lpfc_mbx_mq_create_num_pages_SHIFT     0
+#define lpfc_mbx_mq_create_num_pages_MASK      0x0000FFFF
+#define lpfc_mbx_mq_create_num_pages_WORD      word0
+                       struct mq_context context;
+                       struct dma_address page[LPFC_MAX_MQ_PAGE];
+               } request;
+               struct {
+                       uint32_t word0;
+#define lpfc_mbx_mq_create_q_id_SHIFT  0
+#define lpfc_mbx_mq_create_q_id_MASK   0x0000FFFF
+#define lpfc_mbx_mq_create_q_id_WORD   word0
+               } response;
+       } u;
+};
+
+struct lpfc_mbx_mq_destroy {
+       struct mbox_header header;
+       union {
+               struct {
+                       uint32_t word0;
+#define lpfc_mbx_mq_destroy_q_id_SHIFT 0
+#define lpfc_mbx_mq_destroy_q_id_MASK  0x0000FFFF
+#define lpfc_mbx_mq_destroy_q_id_WORD  word0
+               } request;
+               struct {
+                       uint32_t word0;
+               } response;
+       } u;
+};
+
+struct lpfc_mbx_post_hdr_tmpl {
+       struct mbox_header header;
+       uint32_t word10;
+#define lpfc_mbx_post_hdr_tmpl_rpi_offset_SHIFT  0
+#define lpfc_mbx_post_hdr_tmpl_rpi_offset_MASK   0x0000FFFF
+#define lpfc_mbx_post_hdr_tmpl_rpi_offset_WORD   word10
+#define lpfc_mbx_post_hdr_tmpl_page_cnt_SHIFT   16
+#define lpfc_mbx_post_hdr_tmpl_page_cnt_MASK    0x0000FFFF
+#define lpfc_mbx_post_hdr_tmpl_page_cnt_WORD    word10
+       uint32_t rpi_paddr_lo;
+       uint32_t rpi_paddr_hi;
+};
+
+struct sli4_sge {      /* SLI-4 */
+       uint32_t addr_hi;
+       uint32_t addr_lo;
+
+       uint32_t word2;
+#define lpfc_sli4_sge_offset_SHIFT     0 /* Offset of buffer - Not used*/
+#define lpfc_sli4_sge_offset_MASK      0x00FFFFFF
+#define lpfc_sli4_sge_offset_WORD      word2
+#define lpfc_sli4_sge_last_SHIFT       31 /* Last SEG in the SGL sets
+                                               this  flag !! */
+#define lpfc_sli4_sge_last_MASK                0x00000001
+#define lpfc_sli4_sge_last_WORD                word2
+       uint32_t word3;
+#define lpfc_sli4_sge_len_SHIFT                0
+#define lpfc_sli4_sge_len_MASK         0x0001FFFF
+#define lpfc_sli4_sge_len_WORD         word3
+};
+
+struct fcf_record {
+       uint32_t max_rcv_size;
+       uint32_t fka_adv_period;
+       uint32_t fip_priority;
+       uint32_t word3;
+#define lpfc_fcf_record_mac_0_SHIFT            0
+#define lpfc_fcf_record_mac_0_MASK             0x000000FF
+#define lpfc_fcf_record_mac_0_WORD             word3
+#define lpfc_fcf_record_mac_1_SHIFT            8
+#define lpfc_fcf_record_mac_1_MASK             0x000000FF
+#define lpfc_fcf_record_mac_1_WORD             word3
+#define lpfc_fcf_record_mac_2_SHIFT            16
+#define lpfc_fcf_record_mac_2_MASK             0x000000FF
+#define lpfc_fcf_record_mac_2_WORD             word3
+#define lpfc_fcf_record_mac_3_SHIFT            24
+#define lpfc_fcf_record_mac_3_MASK             0x000000FF
+#define lpfc_fcf_record_mac_3_WORD             word3
+       uint32_t word4;
+#define lpfc_fcf_record_mac_4_SHIFT            0
+#define lpfc_fcf_record_mac_4_MASK             0x000000FF
+#define lpfc_fcf_record_mac_4_WORD             word4
+#define lpfc_fcf_record_mac_5_SHIFT            8
+#define lpfc_fcf_record_mac_5_MASK             0x000000FF
+#define lpfc_fcf_record_mac_5_WORD             word4
+#define lpfc_fcf_record_fcf_avail_SHIFT                16
+#define lpfc_fcf_record_fcf_avail_MASK         0x000000FF
+#define lpfc_fcf_record_fc_avail_WORD          word4
+#define lpfc_fcf_record_mac_addr_prov_SHIFT    24
+#define lpfc_fcf_record_mac_addr_prov_MASK     0x000000FF
+#define lpfc_fcf_record_mac_addr_prov_WORD     word4
+#define LPFC_FCF_FPMA           1      /* Fabric Provided MAC Address */
+#define LPFC_FCF_SPMA           2       /* Server Provided MAC Address */
+       uint32_t word5;
+#define lpfc_fcf_record_fab_name_0_SHIFT       0
+#define lpfc_fcf_record_fab_name_0_MASK                0x000000FF
+#define lpfc_fcf_record_fab_name_0_WORD                word5
+#define lpfc_fcf_record_fab_name_1_SHIFT       8
+#define lpfc_fcf_record_fab_name_1_MASK                0x000000FF
+#define lpfc_fcf_record_fab_name_1_WORD                word5
+#define lpfc_fcf_record_fab_name_2_SHIFT       16
+#define lpfc_fcf_record_fab_name_2_MASK                0x000000FF
+#define lpfc_fcf_record_fab_name_2_WORD                word5
+#define lpfc_fcf_record_fab_name_3_SHIFT       24
+#define lpfc_fcf_record_fab_name_3_MASK                0x000000FF
+#define lpfc_fcf_record_fab_name_3_WORD                word5
+       uint32_t word6;
+#define lpfc_fcf_record_fab_name_4_SHIFT       0
+#define lpfc_fcf_record_fab_name_4_MASK                0x000000FF
+#define lpfc_fcf_record_fab_name_4_WORD                word6
+#define lpfc_fcf_record_fab_name_5_SHIFT       8
+#define lpfc_fcf_record_fab_name_5_MASK                0x000000FF
+#define lpfc_fcf_record_fab_name_5_WORD                word6
+#define lpfc_fcf_record_fab_name_6_SHIFT       16
+#define lpfc_fcf_record_fab_name_6_MASK                0x000000FF
+#define lpfc_fcf_record_fab_name_6_WORD                word6
+#define lpfc_fcf_record_fab_name_7_SHIFT       24
+#define lpfc_fcf_record_fab_name_7_MASK                0x000000FF
+#define lpfc_fcf_record_fab_name_7_WORD                word6
+       uint32_t word7;
+#define lpfc_fcf_record_fc_map_0_SHIFT         0
+#define lpfc_fcf_record_fc_map_0_MASK          0x000000FF
+#define lpfc_fcf_record_fc_map_0_WORD          word7
+#define lpfc_fcf_record_fc_map_1_SHIFT         8
+#define lpfc_fcf_record_fc_map_1_MASK          0x000000FF
+#define lpfc_fcf_record_fc_map_1_WORD          word7
+#define lpfc_fcf_record_fc_map_2_SHIFT         16
+#define lpfc_fcf_record_fc_map_2_MASK          0x000000FF
+#define lpfc_fcf_record_fc_map_2_WORD          word7
+#define lpfc_fcf_record_fcf_valid_SHIFT                24
+#define lpfc_fcf_record_fcf_valid_MASK         0x000000FF
+#define lpfc_fcf_record_fcf_valid_WORD         word7
+       uint32_t word8;
+#define lpfc_fcf_record_fcf_index_SHIFT                0
+#define lpfc_fcf_record_fcf_index_MASK         0x0000FFFF
+#define lpfc_fcf_record_fcf_index_WORD         word8
+#define lpfc_fcf_record_fcf_state_SHIFT                16
+#define lpfc_fcf_record_fcf_state_MASK         0x0000FFFF
+#define lpfc_fcf_record_fcf_state_WORD         word8
+       uint8_t vlan_bitmap[512];
+};
+
+struct lpfc_mbx_read_fcf_tbl {
+       union lpfc_sli4_cfg_shdr cfg_shdr;
+       union {
+               struct {
+                       uint32_t word10;
+#define lpfc_mbx_read_fcf_tbl_indx_SHIFT       0
+#define lpfc_mbx_read_fcf_tbl_indx_MASK                0x0000FFFF
+#define lpfc_mbx_read_fcf_tbl_indx_WORD                word10
+               } request;
+               struct {
+                       uint32_t eventag;
+               } response;
+       } u;
+       uint32_t word11;
+#define lpfc_mbx_read_fcf_tbl_nxt_vindx_SHIFT  0
+#define lpfc_mbx_read_fcf_tbl_nxt_vindx_MASK   0x0000FFFF
+#define lpfc_mbx_read_fcf_tbl_nxt_vindx_WORD   word11
+};
+
+struct lpfc_mbx_add_fcf_tbl_entry {
+       union lpfc_sli4_cfg_shdr cfg_shdr;
+       uint32_t word10;
+#define lpfc_mbx_add_fcf_tbl_fcfi_SHIFT        0
+#define lpfc_mbx_add_fcf_tbl_fcfi_MASK         0x0000FFFF
+#define lpfc_mbx_add_fcf_tbl_fcfi_WORD         word10
+       struct lpfc_mbx_sge fcf_sge;
+};
+
+struct lpfc_mbx_del_fcf_tbl_entry {
+       struct mbox_header header;
+       uint32_t word10;
+#define lpfc_mbx_del_fcf_tbl_count_SHIFT       0
+#define lpfc_mbx_del_fcf_tbl_count_MASK                0x0000FFFF
+#define lpfc_mbx_del_fcf_tbl_count_WORD                word10
+#define lpfc_mbx_del_fcf_tbl_index_SHIFT       16
+#define lpfc_mbx_del_fcf_tbl_index_MASK                0x0000FFFF
+#define lpfc_mbx_del_fcf_tbl_index_WORD                word10
+};
+
+/* Status field for embedded SLI_CONFIG mailbox command */
+#define STATUS_SUCCESS                                 0x0
+#define STATUS_FAILED                                  0x1
+#define STATUS_ILLEGAL_REQUEST                         0x2
+#define STATUS_ILLEGAL_FIELD                           0x3
+#define STATUS_INSUFFICIENT_BUFFER                     0x4
+#define STATUS_UNAUTHORIZED_REQUEST                    0x5
+#define STATUS_FLASHROM_SAVE_FAILED                    0x17
+#define STATUS_FLASHROM_RESTORE_FAILED                 0x18
+#define STATUS_ICCBINDEX_ALLOC_FAILED                  0x1a
+#define STATUS_IOCTLHANDLE_ALLOC_FAILED                0x1b
+#define STATUS_INVALID_PHY_ADDR_FROM_OSM               0x1c
+#define STATUS_INVALID_PHY_ADDR_LEN_FROM_OSM           0x1d
+#define STATUS_ASSERT_FAILED                           0x1e
+#define STATUS_INVALID_SESSION                         0x1f
+#define STATUS_INVALID_CONNECTION                      0x20
+#define STATUS_BTL_PATH_EXCEEDS_OSM_LIMIT              0x21
+#define STATUS_BTL_NO_FREE_SLOT_PATH                   0x24
+#define STATUS_BTL_NO_FREE_SLOT_TGTID                  0x25
+#define STATUS_OSM_DEVSLOT_NOT_FOUND                   0x26
+#define STATUS_FLASHROM_READ_FAILED                    0x27
+#define STATUS_POLL_IOCTL_TIMEOUT                      0x28
+#define STATUS_ERROR_ACITMAIN                          0x2a
+#define STATUS_REBOOT_REQUIRED                         0x2c
+#define STATUS_FCF_IN_USE                              0x3a
+
+struct lpfc_mbx_sli4_config {
+       struct mbox_header header;
+};
+
+struct lpfc_mbx_init_vfi {
+       uint32_t word1;
+#define lpfc_init_vfi_vr_SHIFT         31
+#define lpfc_init_vfi_vr_MASK          0x00000001
+#define lpfc_init_vfi_vr_WORD          word1
+#define lpfc_init_vfi_vt_SHIFT         30
+#define lpfc_init_vfi_vt_MASK          0x00000001
+#define lpfc_init_vfi_vt_WORD          word1
+#define lpfc_init_vfi_vf_SHIFT         29
+#define lpfc_init_vfi_vf_MASK          0x00000001
+#define lpfc_init_vfi_vf_WORD          word1
+#define lpfc_init_vfi_vfi_SHIFT                0
+#define lpfc_init_vfi_vfi_MASK         0x0000FFFF
+#define lpfc_init_vfi_vfi_WORD         word1
+       uint32_t word2;
+#define lpfc_init_vfi_fcfi_SHIFT       0
+#define lpfc_init_vfi_fcfi_MASK                0x0000FFFF
+#define lpfc_init_vfi_fcfi_WORD                word2
+       uint32_t word3;
+#define lpfc_init_vfi_pri_SHIFT                13
+#define lpfc_init_vfi_pri_MASK         0x00000007
+#define lpfc_init_vfi_pri_WORD         word3
+#define lpfc_init_vfi_vf_id_SHIFT      1
+#define lpfc_init_vfi_vf_id_MASK       0x00000FFF
+#define lpfc_init_vfi_vf_id_WORD       word3
+       uint32_t word4;
+#define lpfc_init_vfi_hop_count_SHIFT  24
+#define lpfc_init_vfi_hop_count_MASK   0x000000FF
+#define lpfc_init_vfi_hop_count_WORD   word4
+};
+
+struct lpfc_mbx_reg_vfi {
+       uint32_t word1;
+#define lpfc_reg_vfi_vp_SHIFT          28
+#define lpfc_reg_vfi_vp_MASK           0x00000001
+#define lpfc_reg_vfi_vp_WORD           word1
+#define lpfc_reg_vfi_vfi_SHIFT         0
+#define lpfc_reg_vfi_vfi_MASK          0x0000FFFF
+#define lpfc_reg_vfi_vfi_WORD          word1
+       uint32_t word2;
+#define lpfc_reg_vfi_vpi_SHIFT         16
+#define lpfc_reg_vfi_vpi_MASK          0x0000FFFF
+#define lpfc_reg_vfi_vpi_WORD          word2
+#define lpfc_reg_vfi_fcfi_SHIFT                0
+#define lpfc_reg_vfi_fcfi_MASK         0x0000FFFF
+#define lpfc_reg_vfi_fcfi_WORD         word2
+       uint32_t word3_rsvd;
+       uint32_t word4_rsvd;
+       struct ulp_bde64 bde;
+       uint32_t word8_rsvd;
+       uint32_t word9_rsvd;
+       uint32_t word10;
+#define lpfc_reg_vfi_nport_id_SHIFT            0
+#define lpfc_reg_vfi_nport_id_MASK             0x00FFFFFF
+#define lpfc_reg_vfi_nport_id_WORD             word10
+};
+
+struct lpfc_mbx_init_vpi {
+       uint32_t word1;
+#define lpfc_init_vpi_vfi_SHIFT                16
+#define lpfc_init_vpi_vfi_MASK         0x0000FFFF
+#define lpfc_init_vpi_vfi_WORD         word1
+#define lpfc_init_vpi_vpi_SHIFT                0
+#define lpfc_init_vpi_vpi_MASK         0x0000FFFF
+#define lpfc_init_vpi_vpi_WORD         word1
+};
+
+struct lpfc_mbx_read_vpi {
+       uint32_t word1_rsvd;
+       uint32_t word2;
+#define lpfc_mbx_read_vpi_vnportid_SHIFT       0
+#define lpfc_mbx_read_vpi_vnportid_MASK                0x00FFFFFF
+#define lpfc_mbx_read_vpi_vnportid_WORD                word2
+       uint32_t word3_rsvd;
+       uint32_t word4;
+#define lpfc_mbx_read_vpi_acq_alpa_SHIFT       0
+#define lpfc_mbx_read_vpi_acq_alpa_MASK                0x000000FF
+#define lpfc_mbx_read_vpi_acq_alpa_WORD                word4
+#define lpfc_mbx_read_vpi_pb_SHIFT             15
+#define lpfc_mbx_read_vpi_pb_MASK              0x00000001
+#define lpfc_mbx_read_vpi_pb_WORD              word4
+#define lpfc_mbx_read_vpi_spec_alpa_SHIFT      16
+#define lpfc_mbx_read_vpi_spec_alpa_MASK       0x000000FF
+#define lpfc_mbx_read_vpi_spec_alpa_WORD       word4
+#define lpfc_mbx_read_vpi_ns_SHIFT             30
+#define lpfc_mbx_read_vpi_ns_MASK              0x00000001
+#define lpfc_mbx_read_vpi_ns_WORD              word4
+#define lpfc_mbx_read_vpi_hl_SHIFT             31
+#define lpfc_mbx_read_vpi_hl_MASK              0x00000001
+#define lpfc_mbx_read_vpi_hl_WORD              word4
+       uint32_t word5_rsvd;
+       uint32_t word6;
+#define lpfc_mbx_read_vpi_vpi_SHIFT            0
+#define lpfc_mbx_read_vpi_vpi_MASK             0x0000FFFF
+#define lpfc_mbx_read_vpi_vpi_WORD             word6
+       uint32_t word7;
+#define lpfc_mbx_read_vpi_mac_0_SHIFT          0
+#define lpfc_mbx_read_vpi_mac_0_MASK           0x000000FF
+#define lpfc_mbx_read_vpi_mac_0_WORD           word7
+#define lpfc_mbx_read_vpi_mac_1_SHIFT          8
+#define lpfc_mbx_read_vpi_mac_1_MASK           0x000000FF
+#define lpfc_mbx_read_vpi_mac_1_WORD           word7
+#define lpfc_mbx_read_vpi_mac_2_SHIFT          16
+#define lpfc_mbx_read_vpi_mac_2_MASK           0x000000FF
+#define lpfc_mbx_read_vpi_mac_2_WORD           word7
+#define lpfc_mbx_read_vpi_mac_3_SHIFT          24
+#define lpfc_mbx_read_vpi_mac_3_MASK           0x000000FF
+#define lpfc_mbx_read_vpi_mac_3_WORD           word7
+       uint32_t word8;
+#define lpfc_mbx_read_vpi_mac_4_SHIFT          0
+#define lpfc_mbx_read_vpi_mac_4_MASK           0x000000FF
+#define lpfc_mbx_read_vpi_mac_4_WORD           word8
+#define lpfc_mbx_read_vpi_mac_5_SHIFT          8
+#define lpfc_mbx_read_vpi_mac_5_MASK           0x000000FF
+#define lpfc_mbx_read_vpi_mac_5_WORD           word8
+#define lpfc_mbx_read_vpi_vlan_tag_SHIFT       16
+#define lpfc_mbx_read_vpi_vlan_tag_MASK                0x00000FFF
+#define lpfc_mbx_read_vpi_vlan_tag_WORD                word8
+#define lpfc_mbx_read_vpi_vv_SHIFT             28
+#define lpfc_mbx_read_vpi_vv_MASK              0x0000001
+#define lpfc_mbx_read_vpi_vv_WORD              word8
+};
+
+struct lpfc_mbx_unreg_vfi {
+       uint32_t word1_rsvd;
+       uint32_t word2;
+#define lpfc_unreg_vfi_vfi_SHIFT       0
+#define lpfc_unreg_vfi_vfi_MASK                0x0000FFFF
+#define lpfc_unreg_vfi_vfi_WORD                word2
+};
+
+struct lpfc_mbx_resume_rpi {
+       uint32_t word1;
+#define lpfc_resume_rpi_rpi_SHIFT      0
+#define lpfc_resume_rpi_rpi_MASK       0x0000FFFF
+#define lpfc_resume_rpi_rpi_WORD       word1
+       uint32_t event_tag;
+       uint32_t word3_rsvd;
+       uint32_t word4_rsvd;
+       uint32_t word5_rsvd;
+       uint32_t word6;
+#define lpfc_resume_rpi_vpi_SHIFT      0
+#define lpfc_resume_rpi_vpi_MASK       0x0000FFFF
+#define lpfc_resume_rpi_vpi_WORD       word6
+#define lpfc_resume_rpi_vfi_SHIFT      16
+#define lpfc_resume_rpi_vfi_MASK       0x0000FFFF
+#define lpfc_resume_rpi_vfi_WORD       word6
+};
+
+#define REG_FCF_INVALID_QID    0xFFFF
+struct lpfc_mbx_reg_fcfi {
+       uint32_t word1;
+#define lpfc_reg_fcfi_info_index_SHIFT 0
+#define lpfc_reg_fcfi_info_index_MASK  0x0000FFFF
+#define lpfc_reg_fcfi_info_index_WORD  word1
+#define lpfc_reg_fcfi_fcfi_SHIFT       16
+#define lpfc_reg_fcfi_fcfi_MASK                0x0000FFFF
+#define lpfc_reg_fcfi_fcfi_WORD                word1
+       uint32_t word2;
+#define lpfc_reg_fcfi_rq_id1_SHIFT     0
+#define lpfc_reg_fcfi_rq_id1_MASK      0x0000FFFF
+#define lpfc_reg_fcfi_rq_id1_WORD      word2
+#define lpfc_reg_fcfi_rq_id0_SHIFT     16
+#define lpfc_reg_fcfi_rq_id0_MASK      0x0000FFFF
+#define lpfc_reg_fcfi_rq_id0_WORD      word2
+       uint32_t word3;
+#define lpfc_reg_fcfi_rq_id3_SHIFT     0
+#define lpfc_reg_fcfi_rq_id3_MASK      0x0000FFFF
+#define lpfc_reg_fcfi_rq_id3_WORD      word3
+#define lpfc_reg_fcfi_rq_id2_SHIFT     16
+#define lpfc_reg_fcfi_rq_id2_MASK      0x0000FFFF
+#define lpfc_reg_fcfi_rq_id2_WORD      word3
+       uint32_t word4;
+#define lpfc_reg_fcfi_type_match0_SHIFT        24
+#define lpfc_reg_fcfi_type_match0_MASK 0x000000FF
+#define lpfc_reg_fcfi_type_match0_WORD word4
+#define lpfc_reg_fcfi_type_mask0_SHIFT 16
+#define lpfc_reg_fcfi_type_mask0_MASK  0x000000FF
+#define lpfc_reg_fcfi_type_mask0_WORD  word4
+#define lpfc_reg_fcfi_rctl_match0_SHIFT        8
+#define lpfc_reg_fcfi_rctl_match0_MASK 0x000000FF
+#define lpfc_reg_fcfi_rctl_match0_WORD word4
+#define lpfc_reg_fcfi_rctl_mask0_SHIFT 0
+#define lpfc_reg_fcfi_rctl_mask0_MASK  0x000000FF
+#define lpfc_reg_fcfi_rctl_mask0_WORD  word4
+       uint32_t word5;
+#define lpfc_reg_fcfi_type_match1_SHIFT        24
+#define lpfc_reg_fcfi_type_match1_MASK 0x000000FF
+#define lpfc_reg_fcfi_type_match1_WORD word5
+#define lpfc_reg_fcfi_type_mask1_SHIFT 16
+#define lpfc_reg_fcfi_type_mask1_MASK  0x000000FF
+#define lpfc_reg_fcfi_type_mask1_WORD  word5
+#define lpfc_reg_fcfi_rctl_match1_SHIFT        8
+#define lpfc_reg_fcfi_rctl_match1_MASK 0x000000FF
+#define lpfc_reg_fcfi_rctl_match1_WORD word5
+#define lpfc_reg_fcfi_rctl_mask1_SHIFT 0
+#define lpfc_reg_fcfi_rctl_mask1_MASK  0x000000FF
+#define lpfc_reg_fcfi_rctl_mask1_WORD  word5
+       uint32_t word6;
+#define lpfc_reg_fcfi_type_match2_SHIFT        24
+#define lpfc_reg_fcfi_type_match2_MASK 0x000000FF
+#define lpfc_reg_fcfi_type_match2_WORD word6
+#define lpfc_reg_fcfi_type_mask2_SHIFT 16
+#define lpfc_reg_fcfi_type_mask2_MASK  0x000000FF
+#define lpfc_reg_fcfi_type_mask2_WORD  word6
+#define lpfc_reg_fcfi_rctl_match2_SHIFT        8
+#define lpfc_reg_fcfi_rctl_match2_MASK 0x000000FF
+#define lpfc_reg_fcfi_rctl_match2_WORD word6
+#define lpfc_reg_fcfi_rctl_mask2_SHIFT 0
+#define lpfc_reg_fcfi_rctl_mask2_MASK  0x000000FF
+#define lpfc_reg_fcfi_rctl_mask2_WORD  word6
+       uint32_t word7;
+#define lpfc_reg_fcfi_type_match3_SHIFT        24
+#define lpfc_reg_fcfi_type_match3_MASK 0x000000FF
+#define lpfc_reg_fcfi_type_match3_WORD word7
+#define lpfc_reg_fcfi_type_mask3_SHIFT 16
+#define lpfc_reg_fcfi_type_mask3_MASK  0x000000FF
+#define lpfc_reg_fcfi_type_mask3_WORD  word7
+#define lpfc_reg_fcfi_rctl_match3_SHIFT        8
+#define lpfc_reg_fcfi_rctl_match3_MASK 0x000000FF
+#define lpfc_reg_fcfi_rctl_match3_WORD word7
+#define lpfc_reg_fcfi_rctl_mask3_SHIFT 0
+#define lpfc_reg_fcfi_rctl_mask3_MASK  0x000000FF
+#define lpfc_reg_fcfi_rctl_mask3_WORD  word7
+       uint32_t word8;
+#define lpfc_reg_fcfi_mam_SHIFT                13
+#define lpfc_reg_fcfi_mam_MASK         0x00000003
+#define lpfc_reg_fcfi_mam_WORD         word8
+#define LPFC_MAM_BOTH          0       /* Both SPMA and FPMA */
+#define LPFC_MAM_SPMA          1       /* Server Provided MAC Address */
+#define LPFC_MAM_FPMA          2       /* Fabric Provided MAC Address */
+#define lpfc_reg_fcfi_vv_SHIFT         12
+#define lpfc_reg_fcfi_vv_MASK          0x00000001
+#define lpfc_reg_fcfi_vv_WORD          word8
+#define lpfc_reg_fcfi_vlan_tag_SHIFT   0
+#define lpfc_reg_fcfi_vlan_tag_MASK    0x00000FFF
+#define lpfc_reg_fcfi_vlan_tag_WORD    word8
+};
+
+struct lpfc_mbx_unreg_fcfi {
+       uint32_t word1_rsv;
+       uint32_t word2;
+#define lpfc_unreg_fcfi_SHIFT          0
+#define lpfc_unreg_fcfi_MASK           0x0000FFFF
+#define lpfc_unreg_fcfi_WORD           word2
+};
+
+struct lpfc_mbx_read_rev {
+       uint32_t word1;
+#define lpfc_mbx_rd_rev_sli_lvl_SHIFT                  16
+#define lpfc_mbx_rd_rev_sli_lvl_MASK                   0x0000000F
+#define lpfc_mbx_rd_rev_sli_lvl_WORD                   word1
+#define lpfc_mbx_rd_rev_fcoe_SHIFT             20
+#define lpfc_mbx_rd_rev_fcoe_MASK              0x00000001
+#define lpfc_mbx_rd_rev_fcoe_WORD              word1
+#define lpfc_mbx_rd_rev_vpd_SHIFT              29
+#define lpfc_mbx_rd_rev_vpd_MASK               0x00000001
+#define lpfc_mbx_rd_rev_vpd_WORD               word1
+       uint32_t first_hw_rev;
+       uint32_t second_hw_rev;
+       uint32_t word4_rsvd;
+       uint32_t third_hw_rev;
+       uint32_t word6;
+#define lpfc_mbx_rd_rev_fcph_low_SHIFT         0
+#define lpfc_mbx_rd_rev_fcph_low_MASK          0x000000FF
+#define lpfc_mbx_rd_rev_fcph_low_WORD          word6
+#define lpfc_mbx_rd_rev_fcph_high_SHIFT                8
+#define lpfc_mbx_rd_rev_fcph_high_MASK         0x000000FF
+#define lpfc_mbx_rd_rev_fcph_high_WORD         word6
+#define lpfc_mbx_rd_rev_ftr_lvl_low_SHIFT      16
+#define lpfc_mbx_rd_rev_ftr_lvl_low_MASK       0x000000FF
+#define lpfc_mbx_rd_rev_ftr_lvl_low_WORD       word6
+#define lpfc_mbx_rd_rev_ftr_lvl_high_SHIFT     24
+#define lpfc_mbx_rd_rev_ftr_lvl_high_MASK      0x000000FF
+#define lpfc_mbx_rd_rev_ftr_lvl_high_WORD      word6
+       uint32_t word7_rsvd;
+       uint32_t fw_id_rev;
+       uint8_t  fw_name[16];
+       uint32_t ulp_fw_id_rev;
+       uint8_t  ulp_fw_name[16];
+       uint32_t word18_47_rsvd[30];
+       uint32_t word48;
+#define lpfc_mbx_rd_rev_avail_len_SHIFT                0
+#define lpfc_mbx_rd_rev_avail_len_MASK         0x00FFFFFF
+#define lpfc_mbx_rd_rev_avail_len_WORD         word48
+       uint32_t vpd_paddr_low;
+       uint32_t vpd_paddr_high;
+       uint32_t avail_vpd_len;
+       uint32_t rsvd_52_63[12];
+};
+
+struct lpfc_mbx_read_config {
+       uint32_t word1;
+#define lpfc_mbx_rd_conf_max_bbc_SHIFT         0
+#define lpfc_mbx_rd_conf_max_bbc_MASK          0x000000FF
+#define lpfc_mbx_rd_conf_max_bbc_WORD          word1
+#define lpfc_mbx_rd_conf_init_bbc_SHIFT                8
+#define lpfc_mbx_rd_conf_init_bbc_MASK         0x000000FF
+#define lpfc_mbx_rd_conf_init_bbc_WORD         word1
+       uint32_t word2;
+#define lpfc_mbx_rd_conf_nport_did_SHIFT       0
+#define lpfc_mbx_rd_conf_nport_did_MASK                0x00FFFFFF
+#define lpfc_mbx_rd_conf_nport_did_WORD                word2
+#define lpfc_mbx_rd_conf_topology_SHIFT                24
+#define lpfc_mbx_rd_conf_topology_MASK         0x000000FF
+#define lpfc_mbx_rd_conf_topology_WORD         word2
+       uint32_t word3;
+#define lpfc_mbx_rd_conf_ao_SHIFT              0
+#define lpfc_mbx_rd_conf_ao_MASK               0x00000001
+#define lpfc_mbx_rd_conf_ao_WORD               word3
+#define lpfc_mbx_rd_conf_bb_scn_SHIFT          8
+#define lpfc_mbx_rd_conf_bb_scn_MASK           0x0000000F
+#define lpfc_mbx_rd_conf_bb_scn_WORD           word3
+#define lpfc_mbx_rd_conf_cbb_scn_SHIFT         12
+#define lpfc_mbx_rd_conf_cbb_scn_MASK          0x0000000F
+#define lpfc_mbx_rd_conf_cbb_scn_WORD          word3
+#define lpfc_mbx_rd_conf_mc_SHIFT              29
+#define lpfc_mbx_rd_conf_mc_MASK               0x00000001
+#define lpfc_mbx_rd_conf_mc_WORD               word3
+       uint32_t word4;
+#define lpfc_mbx_rd_conf_e_d_tov_SHIFT         0
+#define lpfc_mbx_rd_conf_e_d_tov_MASK          0x0000FFFF
+#define lpfc_mbx_rd_conf_e_d_tov_WORD          word4
+       uint32_t word5;
+#define lpfc_mbx_rd_conf_lp_tov_SHIFT          0
+#define lpfc_mbx_rd_conf_lp_tov_MASK           0x0000FFFF
+#define lpfc_mbx_rd_conf_lp_tov_WORD           word5
+       uint32_t word6;
+#define lpfc_mbx_rd_conf_r_a_tov_SHIFT         0
+#define lpfc_mbx_rd_conf_r_a_tov_MASK          0x0000FFFF
+#define lpfc_mbx_rd_conf_r_a_tov_WORD          word6
+       uint32_t word7;
+#define lpfc_mbx_rd_conf_r_t_tov_SHIFT         0
+#define lpfc_mbx_rd_conf_r_t_tov_MASK          0x000000FF
+#define lpfc_mbx_rd_conf_r_t_tov_WORD          word7
+       uint32_t word8;
+#define lpfc_mbx_rd_conf_al_tov_SHIFT          0
+#define lpfc_mbx_rd_conf_al_tov_MASK           0x0000000F
+#define lpfc_mbx_rd_conf_al_tov_WORD           word8
+       uint32_t word9;
+#define lpfc_mbx_rd_conf_lmt_SHIFT             0
+#define lpfc_mbx_rd_conf_lmt_MASK              0x0000FFFF
+#define lpfc_mbx_rd_conf_lmt_WORD              word9
+       uint32_t word10;
+#define lpfc_mbx_rd_conf_max_alpa_SHIFT                0
+#define lpfc_mbx_rd_conf_max_alpa_MASK         0x000000FF
+#define lpfc_mbx_rd_conf_max_alpa_WORD         word10
+       uint32_t word11_rsvd;
+       uint32_t word12;
+#define lpfc_mbx_rd_conf_xri_base_SHIFT                0
+#define lpfc_mbx_rd_conf_xri_base_MASK         0x0000FFFF
+#define lpfc_mbx_rd_conf_xri_base_WORD         word12
+#define lpfc_mbx_rd_conf_xri_count_SHIFT       16
+#define lpfc_mbx_rd_conf_xri_count_MASK                0x0000FFFF
+#define lpfc_mbx_rd_conf_xri_count_WORD                word12
+       uint32_t word13;
+#define lpfc_mbx_rd_conf_rpi_base_SHIFT                0
+#define lpfc_mbx_rd_conf_rpi_base_MASK         0x0000FFFF
+#define lpfc_mbx_rd_conf_rpi_base_WORD         word13
+#define lpfc_mbx_rd_conf_rpi_count_SHIFT       16
+#define lpfc_mbx_rd_conf_rpi_count_MASK                0x0000FFFF
+#define lpfc_mbx_rd_conf_rpi_count_WORD                word13
+       uint32_t word14;
+#define lpfc_mbx_rd_conf_vpi_base_SHIFT                0
+#define lpfc_mbx_rd_conf_vpi_base_MASK         0x0000FFFF
+#define lpfc_mbx_rd_conf_vpi_base_WORD         word14
+#define lpfc_mbx_rd_conf_vpi_count_SHIFT       16
+#define lpfc_mbx_rd_conf_vpi_count_MASK                0x0000FFFF
+#define lpfc_mbx_rd_conf_vpi_count_WORD                word14
+       uint32_t word15;
+#define lpfc_mbx_rd_conf_vfi_base_SHIFT         0
+#define lpfc_mbx_rd_conf_vfi_base_MASK          0x0000FFFF
+#define lpfc_mbx_rd_conf_vfi_base_WORD          word15
+#define lpfc_mbx_rd_conf_vfi_count_SHIFT        16
+#define lpfc_mbx_rd_conf_vfi_count_MASK         0x0000FFFF
+#define lpfc_mbx_rd_conf_vfi_count_WORD         word15
+       uint32_t word16;
+#define lpfc_mbx_rd_conf_fcfi_base_SHIFT       0
+#define lpfc_mbx_rd_conf_fcfi_base_MASK                0x0000FFFF
+#define lpfc_mbx_rd_conf_fcfi_base_WORD                word16
+#define lpfc_mbx_rd_conf_fcfi_count_SHIFT      16
+#define lpfc_mbx_rd_conf_fcfi_count_MASK       0x0000FFFF
+#define lpfc_mbx_rd_conf_fcfi_count_WORD       word16
+       uint32_t word17;
+#define lpfc_mbx_rd_conf_rq_count_SHIFT                0
+#define lpfc_mbx_rd_conf_rq_count_MASK         0x0000FFFF
+#define lpfc_mbx_rd_conf_rq_count_WORD         word17
+#define lpfc_mbx_rd_conf_eq_count_SHIFT                16
+#define lpfc_mbx_rd_conf_eq_count_MASK         0x0000FFFF
+#define lpfc_mbx_rd_conf_eq_count_WORD         word17
+       uint32_t word18;
+#define lpfc_mbx_rd_conf_wq_count_SHIFT                0
+#define lpfc_mbx_rd_conf_wq_count_MASK         0x0000FFFF
+#define lpfc_mbx_rd_conf_wq_count_WORD         word18
+#define lpfc_mbx_rd_conf_cq_count_SHIFT                16
+#define lpfc_mbx_rd_conf_cq_count_MASK         0x0000FFFF
+#define lpfc_mbx_rd_conf_cq_count_WORD         word18
+};
+
+struct lpfc_mbx_request_features {
+       uint32_t word1;
+#define lpfc_mbx_rq_ftr_qry_SHIFT              0
+#define lpfc_mbx_rq_ftr_qry_MASK               0x00000001
+#define lpfc_mbx_rq_ftr_qry_WORD               word1
+       uint32_t word2;
+#define lpfc_mbx_rq_ftr_rq_iaab_SHIFT          0
+#define lpfc_mbx_rq_ftr_rq_iaab_MASK           0x00000001
+#define lpfc_mbx_rq_ftr_rq_iaab_WORD           word2
+#define lpfc_mbx_rq_ftr_rq_npiv_SHIFT          1
+#define lpfc_mbx_rq_ftr_rq_npiv_MASK           0x00000001
+#define lpfc_mbx_rq_ftr_rq_npiv_WORD           word2
+#define lpfc_mbx_rq_ftr_rq_dif_SHIFT           2
+#define lpfc_mbx_rq_ftr_rq_dif_MASK            0x00000001
+#define lpfc_mbx_rq_ftr_rq_dif_WORD            word2
+#define lpfc_mbx_rq_ftr_rq_vf_SHIFT            3
+#define lpfc_mbx_rq_ftr_rq_vf_MASK             0x00000001
+#define lpfc_mbx_rq_ftr_rq_vf_WORD             word2
+#define lpfc_mbx_rq_ftr_rq_fcpi_SHIFT          4
+#define lpfc_mbx_rq_ftr_rq_fcpi_MASK           0x00000001
+#define lpfc_mbx_rq_ftr_rq_fcpi_WORD           word2
+#define lpfc_mbx_rq_ftr_rq_fcpt_SHIFT          5
+#define lpfc_mbx_rq_ftr_rq_fcpt_MASK           0x00000001
+#define lpfc_mbx_rq_ftr_rq_fcpt_WORD           word2
+#define lpfc_mbx_rq_ftr_rq_fcpc_SHIFT          6
+#define lpfc_mbx_rq_ftr_rq_fcpc_MASK           0x00000001
+#define lpfc_mbx_rq_ftr_rq_fcpc_WORD           word2
+#define lpfc_mbx_rq_ftr_rq_ifip_SHIFT          7
+#define lpfc_mbx_rq_ftr_rq_ifip_MASK           0x00000001
+#define lpfc_mbx_rq_ftr_rq_ifip_WORD           word2
+       uint32_t word3;
+#define lpfc_mbx_rq_ftr_rsp_iaab_SHIFT         0
+#define lpfc_mbx_rq_ftr_rsp_iaab_MASK          0x00000001
+#define lpfc_mbx_rq_ftr_rsp_iaab_WORD          word3
+#define lpfc_mbx_rq_ftr_rsp_npiv_SHIFT         1
+#define lpfc_mbx_rq_ftr_rsp_npiv_MASK          0x00000001
+#define lpfc_mbx_rq_ftr_rsp_npiv_WORD          word3
+#define lpfc_mbx_rq_ftr_rsp_dif_SHIFT          2
+#define lpfc_mbx_rq_ftr_rsp_dif_MASK           0x00000001
+#define lpfc_mbx_rq_ftr_rsp_dif_WORD           word3
+#define lpfc_mbx_rq_ftr_rsp_vf_SHIFT           3
+#define lpfc_mbx_rq_ftr_rsp_vf__MASK           0x00000001
+#define lpfc_mbx_rq_ftr_rsp_vf_WORD            word3
+#define lpfc_mbx_rq_ftr_rsp_fcpi_SHIFT         4
+#define lpfc_mbx_rq_ftr_rsp_fcpi_MASK          0x00000001
+#define lpfc_mbx_rq_ftr_rsp_fcpi_WORD          word3
+#define lpfc_mbx_rq_ftr_rsp_fcpt_SHIFT         5
+#define lpfc_mbx_rq_ftr_rsp_fcpt_MASK          0x00000001
+#define lpfc_mbx_rq_ftr_rsp_fcpt_WORD          word3
+#define lpfc_mbx_rq_ftr_rsp_fcpc_SHIFT         6
+#define lpfc_mbx_rq_ftr_rsp_fcpc_MASK          0x00000001
+#define lpfc_mbx_rq_ftr_rsp_fcpc_WORD          word3
+#define lpfc_mbx_rq_ftr_rsp_ifip_SHIFT         7
+#define lpfc_mbx_rq_ftr_rsp_ifip_MASK          0x00000001
+#define lpfc_mbx_rq_ftr_rsp_ifip_WORD          word3
+};
+
+/* Mailbox Completion Queue Error Messages */
+#define MB_CQE_STATUS_SUCCESS                  0x0
+#define MB_CQE_STATUS_INSUFFICIENT_PRIVILEGES  0x1
+#define MB_CQE_STATUS_INVALID_PARAMETER                0x2
+#define MB_CQE_STATUS_INSUFFICIENT_RESOURCES   0x3
+#define MB_CEQ_STATUS_QUEUE_FLUSHING           0x4
+#define MB_CQE_STATUS_DMA_FAILED               0x5
+
+/* mailbox queue entry structure */
+struct lpfc_mqe {
+       uint32_t word0;
+#define lpfc_mqe_status_SHIFT          16
+#define lpfc_mqe_status_MASK           0x0000FFFF
+#define lpfc_mqe_status_WORD           word0
+#define lpfc_mqe_command_SHIFT         8
+#define lpfc_mqe_command_MASK          0x000000FF
+#define lpfc_mqe_command_WORD          word0
+       union {
+               uint32_t mb_words[LPFC_SLI4_MB_WORD_COUNT - 1];
+               /* sli4 mailbox commands */
+               struct lpfc_mbx_sli4_config sli4_config;
+               struct lpfc_mbx_init_vfi init_vfi;
+               struct lpfc_mbx_reg_vfi reg_vfi;
+               struct lpfc_mbx_reg_vfi unreg_vfi;
+               struct lpfc_mbx_init_vpi init_vpi;
+               struct lpfc_mbx_resume_rpi resume_rpi;
+               struct lpfc_mbx_read_fcf_tbl read_fcf_tbl;
+               struct lpfc_mbx_add_fcf_tbl_entry add_fcf_entry;
+               struct lpfc_mbx_del_fcf_tbl_entry del_fcf_entry;
+               struct lpfc_mbx_reg_fcfi reg_fcfi;
+               struct lpfc_mbx_unreg_fcfi unreg_fcfi;
+               struct lpfc_mbx_mq_create mq_create;
+               struct lpfc_mbx_eq_create eq_create;
+               struct lpfc_mbx_cq_create cq_create;
+               struct lpfc_mbx_wq_create wq_create;
+               struct lpfc_mbx_rq_create rq_create;
+               struct lpfc_mbx_mq_destroy mq_destroy;
+               struct lpfc_mbx_eq_destroy eq_destroy;
+               struct lpfc_mbx_cq_destroy cq_destroy;
+               struct lpfc_mbx_wq_destroy wq_destroy;
+               struct lpfc_mbx_rq_destroy rq_destroy;
+               struct lpfc_mbx_post_sgl_pages post_sgl_pages;
+               struct lpfc_mbx_nembed_cmd nembed_cmd;
+               struct lpfc_mbx_read_rev read_rev;
+               struct lpfc_mbx_read_vpi read_vpi;
+               struct lpfc_mbx_read_config rd_config;
+               struct lpfc_mbx_request_features req_ftrs;
+               struct lpfc_mbx_post_hdr_tmpl hdr_tmpl;
+               struct lpfc_mbx_nop nop;
+       } un;
+};
+
+struct lpfc_mcqe {
+       uint32_t word0;
+#define lpfc_mcqe_status_SHIFT         0
+#define lpfc_mcqe_status_MASK          0x0000FFFF
+#define lpfc_mcqe_status_WORD          word0
+#define lpfc_mcqe_ext_status_SHIFT     16
+#define lpfc_mcqe_ext_status_MASK      0x0000FFFF
+#define lpfc_mcqe_ext_status_WORD      word0
+       uint32_t mcqe_tag0;
+       uint32_t mcqe_tag1;
+       uint32_t trailer;
+#define lpfc_trailer_valid_SHIFT       31
+#define lpfc_trailer_valid_MASK                0x00000001
+#define lpfc_trailer_valid_WORD                trailer
+#define lpfc_trailer_async_SHIFT       30
+#define lpfc_trailer_async_MASK                0x00000001
+#define lpfc_trailer_async_WORD                trailer
+#define lpfc_trailer_hpi_SHIFT         29
+#define lpfc_trailer_hpi_MASK          0x00000001
+#define lpfc_trailer_hpi_WORD          trailer
+#define lpfc_trailer_completed_SHIFT   28
+#define lpfc_trailer_completed_MASK    0x00000001
+#define lpfc_trailer_completed_WORD    trailer
+#define lpfc_trailer_consumed_SHIFT    27
+#define lpfc_trailer_consumed_MASK     0x00000001
+#define lpfc_trailer_consumed_WORD     trailer
+#define lpfc_trailer_type_SHIFT                16
+#define lpfc_trailer_type_MASK         0x000000FF
+#define lpfc_trailer_type_WORD         trailer
+#define lpfc_trailer_code_SHIFT                8
+#define lpfc_trailer_code_MASK         0x000000FF
+#define lpfc_trailer_code_WORD         trailer
+#define LPFC_TRAILER_CODE_LINK 0x1
+#define LPFC_TRAILER_CODE_FCOE 0x2
+#define LPFC_TRAILER_CODE_DCBX 0x3
+};
+
+struct lpfc_acqe_link {
+       uint32_t word0;
+#define lpfc_acqe_link_speed_SHIFT             24
+#define lpfc_acqe_link_speed_MASK              0x000000FF
+#define lpfc_acqe_link_speed_WORD              word0
+#define LPFC_ASYNC_LINK_SPEED_ZERO             0x0
+#define LPFC_ASYNC_LINK_SPEED_10MBPS           0x1
+#define LPFC_ASYNC_LINK_SPEED_100MBPS          0x2
+#define LPFC_ASYNC_LINK_SPEED_1GBPS            0x3
+#define LPFC_ASYNC_LINK_SPEED_10GBPS           0x4
+#define lpfc_acqe_link_duplex_SHIFT            16
+#define lpfc_acqe_link_duplex_MASK             0x000000FF
+#define lpfc_acqe_link_duplex_WORD             word0
+#define LPFC_ASYNC_LINK_DUPLEX_NONE            0x0
+#define LPFC_ASYNC_LINK_DUPLEX_HALF            0x1
+#define LPFC_ASYNC_LINK_DUPLEX_FULL            0x2
+#define lpfc_acqe_link_status_SHIFT            8
+#define lpfc_acqe_link_status_MASK             0x000000FF
+#define lpfc_acqe_link_status_WORD             word0
+#define LPFC_ASYNC_LINK_STATUS_DOWN            0x0
+#define LPFC_ASYNC_LINK_STATUS_UP              0x1
+#define LPFC_ASYNC_LINK_STATUS_LOGICAL_DOWN    0x2
+#define LPFC_ASYNC_LINK_STATUS_LOGICAL_UP      0x3
+#define lpfc_acqe_link_physical_SHIFT          0
+#define lpfc_acqe_link_physical_MASK           0x000000FF
+#define lpfc_acqe_link_physical_WORD           word0
+#define LPFC_ASYNC_LINK_PORT_A                 0x0
+#define LPFC_ASYNC_LINK_PORT_B                 0x1
+       uint32_t word1;
+#define lpfc_acqe_link_fault_SHIFT     0
+#define lpfc_acqe_link_fault_MASK      0x000000FF
+#define lpfc_acqe_link_fault_WORD      word1
+#define LPFC_ASYNC_LINK_FAULT_NONE     0x0
+#define LPFC_ASYNC_LINK_FAULT_LOCAL    0x1
+#define LPFC_ASYNC_LINK_FAULT_REMOTE   0x2
+       uint32_t event_tag;
+       uint32_t trailer;
+};
+
+struct lpfc_acqe_fcoe {
+       uint32_t fcf_index;
+       uint32_t word1;
+#define lpfc_acqe_fcoe_fcf_count_SHIFT         0
+#define lpfc_acqe_fcoe_fcf_count_MASK          0x0000FFFF
+#define lpfc_acqe_fcoe_fcf_count_WORD          word1
+#define lpfc_acqe_fcoe_event_type_SHIFT                16
+#define lpfc_acqe_fcoe_event_type_MASK         0x0000FFFF
+#define lpfc_acqe_fcoe_event_type_WORD         word1
+#define LPFC_FCOE_EVENT_TYPE_NEW_FCF           0x1
+#define LPFC_FCOE_EVENT_TYPE_FCF_TABLE_FULL    0x2
+#define LPFC_FCOE_EVENT_TYPE_FCF_DEAD          0x3
+       uint32_t event_tag;
+       uint32_t trailer;
+};
+
+struct lpfc_acqe_dcbx {
+       uint32_t tlv_ttl;
+       uint32_t reserved;
+       uint32_t event_tag;
+       uint32_t trailer;
+};
+
+/*
+ * Define the bootstrap mailbox (bmbx) region used to communicate
+ * mailbox command between the host and port. The mailbox consists
+ * of a payload area of 256 bytes and a completion queue of length
+ * 16 bytes.
+ */
+struct lpfc_bmbx_create {
+       struct lpfc_mqe mqe;
+       struct lpfc_mcqe mcqe;
+};
+
+#define SGL_ALIGN_SZ 64
+#define SGL_PAGE_SIZE 4096
+/* align SGL addr on a size boundary - adjust address up */
+#define NO_XRI ((uint16_t)-1)
+struct wqe_common {
+       uint32_t word6;
+#define wqe_xri_SHIFT         0
+#define wqe_xri_MASK          0x0000FFFF
+#define wqe_xri_WORD          word6
+#define wqe_ctxt_tag_SHIFT    16
+#define wqe_ctxt_tag_MASK     0x0000FFFF
+#define wqe_ctxt_tag_WORD     word6
+       uint32_t word7;
+#define wqe_ct_SHIFT          2
+#define wqe_ct_MASK           0x00000003
+#define wqe_ct_WORD           word7
+#define wqe_status_SHIFT      4
+#define wqe_status_MASK       0x0000000f
+#define wqe_status_WORD       word7
+#define wqe_cmnd_SHIFT        8
+#define wqe_cmnd_MASK         0x000000ff
+#define wqe_cmnd_WORD         word7
+#define wqe_class_SHIFT       16
+#define wqe_class_MASK        0x00000007
+#define wqe_class_WORD        word7
+#define wqe_pu_SHIFT          20
+#define wqe_pu_MASK           0x00000003
+#define wqe_pu_WORD           word7
+#define wqe_erp_SHIFT         22
+#define wqe_erp_MASK          0x00000001
+#define wqe_erp_WORD          word7
+#define wqe_lnk_SHIFT         23
+#define wqe_lnk_MASK          0x00000001
+#define wqe_lnk_WORD          word7
+#define wqe_tmo_SHIFT         24
+#define wqe_tmo_MASK          0x000000ff
+#define wqe_tmo_WORD          word7
+       uint32_t abort_tag; /* word 8 in WQE */
+       uint32_t word9;
+#define wqe_reqtag_SHIFT      0
+#define wqe_reqtag_MASK       0x0000FFFF
+#define wqe_reqtag_WORD       word9
+#define wqe_rcvoxid_SHIFT     16
+#define wqe_rcvoxid_MASK       0x0000FFFF
+#define wqe_rcvoxid_WORD       word9
+       uint32_t word10;
+#define wqe_pri_SHIFT         16
+#define wqe_pri_MASK          0x00000007
+#define wqe_pri_WORD          word10
+#define wqe_pv_SHIFT          19
+#define wqe_pv_MASK           0x00000001
+#define wqe_pv_WORD           word10
+#define wqe_xc_SHIFT          21
+#define wqe_xc_MASK           0x00000001
+#define wqe_xc_WORD           word10
+#define wqe_ccpe_SHIFT        23
+#define wqe_ccpe_MASK         0x00000001
+#define wqe_ccpe_WORD         word10
+#define wqe_ccp_SHIFT         24
+#define wqe_ccp_MASK         0x000000ff
+#define wqe_ccp_WORD         word10
+       uint32_t word11;
+#define wqe_cmd_type_SHIFT  0
+#define wqe_cmd_type_MASK   0x0000000f
+#define wqe_cmd_type_WORD   word11
+#define wqe_wqec_SHIFT      7
+#define wqe_wqec_MASK       0x00000001
+#define wqe_wqec_WORD       word11
+#define wqe_cqid_SHIFT      16
+#define wqe_cqid_MASK       0x000003ff
+#define wqe_cqid_WORD       word11
+};
+
+struct wqe_did {
+       uint32_t word5;
+#define wqe_els_did_SHIFT         0
+#define wqe_els_did_MASK          0x00FFFFFF
+#define wqe_els_did_WORD          word5
+#define wqe_xmit_bls_ar_SHIFT         30
+#define wqe_xmit_bls_ar_MASK          0x00000001
+#define wqe_xmit_bls_ar_WORD          word5
+#define wqe_xmit_bls_xo_SHIFT         31
+#define wqe_xmit_bls_xo_MASK          0x00000001
+#define wqe_xmit_bls_xo_WORD          word5
+};
+
+struct els_request64_wqe {
+       struct ulp_bde64 bde;
+       uint32_t payload_len;
+       uint32_t word4;
+#define els_req64_sid_SHIFT         0
+#define els_req64_sid_MASK          0x00FFFFFF
+#define els_req64_sid_WORD          word4
+#define els_req64_sp_SHIFT          24
+#define els_req64_sp_MASK           0x00000001
+#define els_req64_sp_WORD           word4
+#define els_req64_vf_SHIFT          25
+#define els_req64_vf_MASK           0x00000001
+#define els_req64_vf_WORD           word4
+       struct wqe_did  wqe_dest;
+       struct wqe_common wqe_com; /* words 6-11 */
+       uint32_t word12;
+#define els_req64_vfid_SHIFT        1
+#define els_req64_vfid_MASK         0x00000FFF
+#define els_req64_vfid_WORD         word12
+#define els_req64_pri_SHIFT         13
+#define els_req64_pri_MASK          0x00000007
+#define els_req64_pri_WORD          word12
+       uint32_t word13;
+#define els_req64_hopcnt_SHIFT      24
+#define els_req64_hopcnt_MASK       0x000000ff
+#define els_req64_hopcnt_WORD       word13
+       uint32_t reserved[2];
+};
+
+struct xmit_els_rsp64_wqe {
+       struct ulp_bde64 bde;
+       uint32_t rsvd3;
+       uint32_t rsvd4;
+       struct wqe_did  wqe_dest;
+       struct wqe_common wqe_com; /* words 6-11 */
+       uint32_t rsvd_12_15[4];
+};
+
+struct xmit_bls_rsp64_wqe {
+       uint32_t payload0;
+       uint32_t word1;
+#define xmit_bls_rsp64_rxid_SHIFT  0
+#define xmit_bls_rsp64_rxid_MASK   0x0000ffff
+#define xmit_bls_rsp64_rxid_WORD   word1
+#define xmit_bls_rsp64_oxid_SHIFT  16
+#define xmit_bls_rsp64_oxid_MASK   0x0000ffff
+#define xmit_bls_rsp64_oxid_WORD   word1
+       uint32_t word2;
+#define xmit_bls_rsp64_seqcntlo_SHIFT  0
+#define xmit_bls_rsp64_seqcntlo_MASK   0x0000ffff
+#define xmit_bls_rsp64_seqcntlo_WORD   word2
+#define xmit_bls_rsp64_seqcnthi_SHIFT  16
+#define xmit_bls_rsp64_seqcnthi_MASK   0x0000ffff
+#define xmit_bls_rsp64_seqcnthi_WORD   word2
+       uint32_t rsrvd3;
+       uint32_t rsrvd4;
+       struct wqe_did  wqe_dest;
+       struct wqe_common wqe_com; /* words 6-11 */
+       uint32_t rsvd_12_15[4];
+};
+struct wqe_rctl_dfctl {
+       uint32_t word5;
+#define wqe_si_SHIFT 2
+#define wqe_si_MASK  0x000000001
+#define wqe_si_WORD  word5
+#define wqe_la_SHIFT 3
+#define wqe_la_MASK  0x000000001
+#define wqe_la_WORD  word5
+#define wqe_ls_SHIFT 7
+#define wqe_ls_MASK  0x000000001
+#define wqe_ls_WORD  word5
+#define wqe_dfctl_SHIFT 8
+#define wqe_dfctl_MASK  0x0000000ff
+#define wqe_dfctl_WORD  word5
+#define wqe_type_SHIFT 16
+#define wqe_type_MASK  0x0000000ff
+#define wqe_type_WORD  word5
+#define wqe_rctl_SHIFT 24
+#define wqe_rctl_MASK  0x0000000ff
+#define wqe_rctl_WORD  word5
+};
+
+struct xmit_seq64_wqe {
+       struct ulp_bde64 bde;
+       uint32_t paylaod_offset;
+       uint32_t relative_offset;
+       struct wqe_rctl_dfctl wge_ctl;
+       struct wqe_common wqe_com; /* words 6-11 */
+       /* Note: word10 different REVISIT */
+       uint32_t xmit_len;
+       uint32_t rsvd_12_15[3];
+};
+struct xmit_bcast64_wqe {
+       struct ulp_bde64 bde;
+       uint32_t paylaod_len;
+       uint32_t rsvd4;
+       struct wqe_rctl_dfctl wge_ctl; /* word 5 */
+       struct wqe_common wqe_com;     /* words 6-11 */
+       uint32_t rsvd_12_15[4];
+};
+
+struct gen_req64_wqe {
+       struct ulp_bde64 bde;
+       uint32_t command_len;
+       uint32_t payload_len;
+       struct wqe_rctl_dfctl wge_ctl; /* word 5 */
+       struct wqe_common wqe_com;     /* words 6-11 */
+       uint32_t rsvd_12_15[4];
+};
+
+struct create_xri_wqe {
+       uint32_t rsrvd[5];           /* words 0-4 */
+       struct wqe_did  wqe_dest;  /* word 5 */
+       struct wqe_common wqe_com; /* words 6-11 */
+       uint32_t rsvd_12_15[4];         /* word 12-15 */
+};
+
+#define T_REQUEST_TAG 3
+#define T_XRI_TAG 1
+
+struct abort_cmd_wqe {
+       uint32_t rsrvd[3];
+       uint32_t word3;
+#define        abort_cmd_ia_SHIFT  0
+#define        abort_cmd_ia_MASK  0x000000001
+#define        abort_cmd_ia_WORD  word3
+#define        abort_cmd_criteria_SHIFT  8
+#define        abort_cmd_criteria_MASK  0x0000000ff
+#define        abort_cmd_criteria_WORD  word3
+       uint32_t rsrvd4;
+       uint32_t rsrvd5;
+       struct wqe_common wqe_com;     /* words 6-11 */
+       uint32_t rsvd_12_15[4];         /* word 12-15 */
+};
+
+struct fcp_iwrite64_wqe {
+       struct ulp_bde64 bde;
+       uint32_t payload_len;
+       uint32_t total_xfer_len;
+       uint32_t initial_xfer_len;
+       struct wqe_common wqe_com;     /* words 6-11 */
+       uint32_t rsvd_12_15[4];         /* word 12-15 */
+};
+
+struct fcp_iread64_wqe {
+       struct ulp_bde64 bde;
+       uint32_t payload_len;          /* word 3 */
+       uint32_t total_xfer_len;       /* word 4 */
+       uint32_t rsrvd5;               /* word 5 */
+       struct wqe_common wqe_com;     /* words 6-11 */
+       uint32_t rsvd_12_15[4];         /* word 12-15 */
+};
+
+struct fcp_icmnd64_wqe {
+       struct ulp_bde64 bde;    /* words 0-2 */
+       uint32_t rsrvd[3];             /* words 3-5 */
+       struct wqe_common wqe_com;     /* words 6-11 */
+       uint32_t rsvd_12_15[4];         /* word 12-15 */
+};
+
+
+union lpfc_wqe {
+       uint32_t words[16];
+       struct lpfc_wqe_generic generic;
+       struct fcp_icmnd64_wqe fcp_icmd;
+       struct fcp_iread64_wqe fcp_iread;
+       struct fcp_iwrite64_wqe fcp_iwrite;
+       struct abort_cmd_wqe abort_cmd;
+       struct create_xri_wqe create_xri;
+       struct xmit_bcast64_wqe xmit_bcast64;
+       struct xmit_seq64_wqe xmit_sequence;
+       struct xmit_bls_rsp64_wqe xmit_bls_rsp;
+       struct xmit_els_rsp64_wqe xmit_els_rsp;
+       struct els_request64_wqe els_req;
+       struct gen_req64_wqe gen_req;
+};
+
+#define FCP_COMMAND 0x0
+#define FCP_COMMAND_DATA_OUT 0x1
+#define ELS_COMMAND_NON_FIP 0xC
+#define ELS_COMMAND_FIP 0xD
+#define OTHER_COMMAND 0x8
+
index 86d1bdcbf2d819003355d81c06318c451575d23d..2f5907f92eeaee7cac3079615ac035d67c27e1a5 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport_fc.h>
 
+#include "lpfc_hw4.h"
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
+#include "lpfc_sli4.h"
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -51,9 +53,23 @@ char *_dump_buf_dif;
 unsigned long _dump_buf_dif_order;
 spinlock_t _dump_buf_lock;
 
-static int lpfc_parse_vpd(struct lpfc_hba *, uint8_t *, int);
 static void lpfc_get_hba_model_desc(struct lpfc_hba *, uint8_t *, uint8_t *);
 static int lpfc_post_rcv_buf(struct lpfc_hba *);
+static int lpfc_sli4_queue_create(struct lpfc_hba *);
+static void lpfc_sli4_queue_destroy(struct lpfc_hba *);
+static int lpfc_create_bootstrap_mbox(struct lpfc_hba *);
+static int lpfc_setup_endian_order(struct lpfc_hba *);
+static int lpfc_sli4_read_config(struct lpfc_hba *);
+static void lpfc_destroy_bootstrap_mbox(struct lpfc_hba *);
+static void lpfc_free_sgl_list(struct lpfc_hba *);
+static int lpfc_init_sgl_list(struct lpfc_hba *);
+static int lpfc_init_active_sgl_array(struct lpfc_hba *);
+static void lpfc_free_active_sgl(struct lpfc_hba *);
+static int lpfc_hba_down_post_s3(struct lpfc_hba *phba);
+static int lpfc_hba_down_post_s4(struct lpfc_hba *phba);
+static int lpfc_sli4_cq_event_pool_create(struct lpfc_hba *);
+static void lpfc_sli4_cq_event_pool_destroy(struct lpfc_hba *);
+static void lpfc_sli4_cq_event_release_all(struct lpfc_hba *);
 
 static struct scsi_transport_template *lpfc_transport_template = NULL;
 static struct scsi_transport_template *lpfc_vport_transport_template = NULL;
@@ -92,7 +108,7 @@ lpfc_config_port_prep(struct lpfc_hba *phba)
                return -ENOMEM;
        }
 
-       mb = &pmb->mb;
+       mb = &pmb->u.mb;
        phba->link_state = LPFC_INIT_MBX_CMDS;
 
        if (lpfc_is_LC_HBA(phba->pcidev->device)) {
@@ -205,6 +221,11 @@ lpfc_config_port_prep(struct lpfc_hba *phba)
                                        mb->mbxCommand, mb->mbxStatus);
                        mb->un.varDmp.word_cnt = 0;
                }
+               /* dump mem may return a zero when finished or we got a
+                * mailbox error, either way we are done.
+                */
+               if (mb->un.varDmp.word_cnt == 0)
+                       break;
                if (mb->un.varDmp.word_cnt > DMP_VPD_SIZE - offset)
                        mb->un.varDmp.word_cnt = DMP_VPD_SIZE - offset;
                lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET,
@@ -233,7 +254,7 @@ out_free_mbox:
 static void
 lpfc_config_async_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq)
 {
-       if (pmboxq->mb.mbxStatus == MBX_SUCCESS)
+       if (pmboxq->u.mb.mbxStatus == MBX_SUCCESS)
                phba->temp_sensor_support = 1;
        else
                phba->temp_sensor_support = 0;
@@ -260,7 +281,7 @@ lpfc_dump_wakeup_param_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
        /* character array used for decoding dist type. */
        char dist_char[] = "nabx";
 
-       if (pmboxq->mb.mbxStatus != MBX_SUCCESS) {
+       if (pmboxq->u.mb.mbxStatus != MBX_SUCCESS) {
                mempool_free(pmboxq, phba->mbox_mem_pool);
                return;
        }
@@ -268,7 +289,7 @@ lpfc_dump_wakeup_param_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
        prg = (struct prog_id *) &prog_id_word;
 
        /* word 7 contain option rom version */
-       prog_id_word = pmboxq->mb.un.varWords[7];
+       prog_id_word = pmboxq->u.mb.un.varWords[7];
 
        /* Decode the Option rom version word to a readable string */
        if (prg->dist < 4)
@@ -325,7 +346,7 @@ lpfc_config_port_post(struct lpfc_hba *phba)
                phba->link_state = LPFC_HBA_ERROR;
                return -ENOMEM;
        }
-       mb = &pmb->mb;
+       mb = &pmb->u.mb;
 
        /* Get login parameters for NID.  */
        lpfc_read_sparam(phba, pmb, 0);
@@ -364,6 +385,7 @@ lpfc_config_port_post(struct lpfc_hba *phba)
        /* Update the fc_host data structures with new wwn. */
        fc_host_node_name(shost) = wwn_to_u64(vport->fc_nodename.u.wwn);
        fc_host_port_name(shost) = wwn_to_u64(vport->fc_portname.u.wwn);
+       fc_host_max_npiv_vports(shost) = phba->max_vpi;
 
        /* If no serial number in VPD data, use low 6 bytes of WWNN */
        /* This should be consolidated into parse_vpd ? - mr */
@@ -460,17 +482,18 @@ lpfc_config_port_post(struct lpfc_hba *phba)
                        lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
                                        "0352 Config MSI mailbox command "
                                        "failed, mbxCmd x%x, mbxStatus x%x\n",
-                                       pmb->mb.mbxCommand, pmb->mb.mbxStatus);
+                                       pmb->u.mb.mbxCommand,
+                                       pmb->u.mb.mbxStatus);
                        mempool_free(pmb, phba->mbox_mem_pool);
                        return -EIO;
                }
        }
 
+       spin_lock_irq(&phba->hbalock);
        /* Initialize ERATT handling flag */
        phba->hba_flag &= ~HBA_ERATT_HANDLED;
 
        /* Enable appropriate host interrupts */
-       spin_lock_irq(&phba->hbalock);
        status = readl(phba->HCregaddr);
        status |= HC_MBINT_ENA | HC_ERINT_ENA | HC_LAINT_ENA;
        if (psli->num_rings > 0)
@@ -571,16 +594,20 @@ lpfc_hba_down_prep(struct lpfc_hba *phba)
 {
        struct lpfc_vport **vports;
        int i;
-       /* Disable interrupts */
-       writel(0, phba->HCregaddr);
-       readl(phba->HCregaddr); /* flush */
+
+       if (phba->sli_rev <= LPFC_SLI_REV3) {
+               /* Disable interrupts */
+               writel(0, phba->HCregaddr);
+               readl(phba->HCregaddr); /* flush */
+       }
 
        if (phba->pport->load_flag & FC_UNLOADING)
                lpfc_cleanup_discovery_resources(phba->pport);
        else {
                vports = lpfc_create_vport_work_array(phba);
                if (vports != NULL)
-                       for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++)
+                       for (i = 0; i <= phba->max_vports &&
+                               vports[i] != NULL; i++)
                                lpfc_cleanup_discovery_resources(vports[i]);
                lpfc_destroy_vport_work_array(phba, vports);
        }
@@ -588,7 +615,7 @@ lpfc_hba_down_prep(struct lpfc_hba *phba)
 }
 
 /**
- * lpfc_hba_down_post - Perform lpfc uninitialization after HBA reset
+ * lpfc_hba_down_post_s3 - Perform lpfc uninitialization after HBA reset
  * @phba: pointer to lpfc HBA data structure.
  *
  * This routine will do uninitialization after the HBA is reset when bring
@@ -598,8 +625,8 @@ lpfc_hba_down_prep(struct lpfc_hba *phba)
  *   0 - sucess.
  *   Any other value - error.
  **/
-int
-lpfc_hba_down_post(struct lpfc_hba *phba)
+static int
+lpfc_hba_down_post_s3(struct lpfc_hba *phba)
 {
        struct lpfc_sli *psli = &phba->sli;
        struct lpfc_sli_ring *pring;
@@ -642,6 +669,77 @@ lpfc_hba_down_post(struct lpfc_hba *phba)
 
        return 0;
 }
+/**
+ * lpfc_hba_down_post_s4 - Perform lpfc uninitialization after HBA reset
+ * @phba: pointer to lpfc HBA data structure.
+ *
+ * This routine will do uninitialization after the HBA is reset when bring
+ * down the SLI Layer.
+ *
+ * Return codes
+ *   0 - sucess.
+ *   Any other value - error.
+ **/
+static int
+lpfc_hba_down_post_s4(struct lpfc_hba *phba)
+{
+       struct lpfc_scsi_buf *psb, *psb_next;
+       LIST_HEAD(aborts);
+       int ret;
+       unsigned long iflag = 0;
+       ret = lpfc_hba_down_post_s3(phba);
+       if (ret)
+               return ret;
+       /* At this point in time the HBA is either reset or DOA. Either
+        * way, nothing should be on lpfc_abts_els_sgl_list, it needs to be
+        * on the lpfc_sgl_list so that it can either be freed if the
+        * driver is unloading or reposted if the driver is restarting
+        * the port.
+        */
+       spin_lock_irq(&phba->hbalock);  /* required for lpfc_sgl_list and */
+                                       /* scsl_buf_list */
+       /* abts_sgl_list_lock required because worker thread uses this
+        * list.
+        */
+       spin_lock(&phba->sli4_hba.abts_sgl_list_lock);
+       list_splice_init(&phba->sli4_hba.lpfc_abts_els_sgl_list,
+                       &phba->sli4_hba.lpfc_sgl_list);
+       spin_unlock(&phba->sli4_hba.abts_sgl_list_lock);
+       /* abts_scsi_buf_list_lock required because worker thread uses this
+        * list.
+        */
+       spin_lock(&phba->sli4_hba.abts_scsi_buf_list_lock);
+       list_splice_init(&phba->sli4_hba.lpfc_abts_scsi_buf_list,
+                       &aborts);
+       spin_unlock(&phba->sli4_hba.abts_scsi_buf_list_lock);
+       spin_unlock_irq(&phba->hbalock);
+
+       list_for_each_entry_safe(psb, psb_next, &aborts, list) {
+               psb->pCmd = NULL;
+               psb->status = IOSTAT_SUCCESS;
+       }
+       spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
+       list_splice(&aborts, &phba->lpfc_scsi_buf_list);
+       spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag);
+       return 0;
+}
+
+/**
+ * lpfc_hba_down_post - Wrapper func for hba down post routine
+ * @phba: pointer to lpfc HBA data structure.
+ *
+ * This routine wraps the actual SLI3 or SLI4 routine for performing
+ * uninitialization after the HBA is reset when bring down the SLI Layer.
+ *
+ * Return codes
+ *   0 - sucess.
+ *   Any other value - error.
+ **/
+int
+lpfc_hba_down_post(struct lpfc_hba *phba)
+{
+       return (*phba->lpfc_hba_down_post)(phba);
+}
 
 /**
  * lpfc_hb_timeout - The HBA-timer timeout handler
@@ -809,7 +907,7 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba)
                                        "taking this port offline.\n");
 
                        spin_lock_irq(&phba->hbalock);
-                       psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+                       psli->sli_flag &= ~LPFC_SLI_ACTIVE;
                        spin_unlock_irq(&phba->hbalock);
 
                        lpfc_offline_prep(phba);
@@ -834,13 +932,15 @@ lpfc_offline_eratt(struct lpfc_hba *phba)
        struct lpfc_sli   *psli = &phba->sli;
 
        spin_lock_irq(&phba->hbalock);
-       psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+       psli->sli_flag &= ~LPFC_SLI_ACTIVE;
        spin_unlock_irq(&phba->hbalock);
        lpfc_offline_prep(phba);
 
        lpfc_offline(phba);
        lpfc_reset_barrier(phba);
+       spin_lock_irq(&phba->hbalock);
        lpfc_sli_brdreset(phba);
+       spin_unlock_irq(&phba->hbalock);
        lpfc_hba_down_post(phba);
        lpfc_sli_brdready(phba, HS_MBRDY);
        lpfc_unblock_mgmt_io(phba);
@@ -848,6 +948,25 @@ lpfc_offline_eratt(struct lpfc_hba *phba)
        return;
 }
 
+/**
+ * lpfc_sli4_offline_eratt - Bring lpfc offline on SLI4 hardware error attention
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is called to bring a SLI4 HBA offline when HBA hardware error
+ * other than Port Error 6 has been detected.
+ **/
+static void
+lpfc_sli4_offline_eratt(struct lpfc_hba *phba)
+{
+       lpfc_offline_prep(phba);
+       lpfc_offline(phba);
+       lpfc_sli4_brdreset(phba);
+       lpfc_hba_down_post(phba);
+       lpfc_sli4_post_status_check(phba);
+       lpfc_unblock_mgmt_io(phba);
+       phba->link_state = LPFC_HBA_ERROR;
+}
+
 /**
  * lpfc_handle_deferred_eratt - The HBA hardware deferred error handler
  * @phba: pointer to lpfc hba data structure.
@@ -864,6 +983,16 @@ lpfc_handle_deferred_eratt(struct lpfc_hba *phba)
        struct lpfc_sli_ring  *pring;
        struct lpfc_sli *psli = &phba->sli;
 
+       /* If the pci channel is offline, ignore possible errors,
+        * since we cannot communicate with the pci card anyway.
+        */
+       if (pci_channel_offline(phba->pcidev)) {
+               spin_lock_irq(&phba->hbalock);
+               phba->hba_flag &= ~DEFER_ERATT;
+               spin_unlock_irq(&phba->hbalock);
+               return;
+       }
+
        lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                "0479 Deferred Adapter Hardware Error "
                "Data: x%x x%x x%x\n",
@@ -871,7 +1000,7 @@ lpfc_handle_deferred_eratt(struct lpfc_hba *phba)
                phba->work_status[0], phba->work_status[1]);
 
        spin_lock_irq(&phba->hbalock);
-       psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+       psli->sli_flag &= ~LPFC_SLI_ACTIVE;
        spin_unlock_irq(&phba->hbalock);
 
 
@@ -909,13 +1038,30 @@ lpfc_handle_deferred_eratt(struct lpfc_hba *phba)
        if ((!phba->work_hs) && (!(phba->pport->load_flag & FC_UNLOADING)))
                phba->work_hs = old_host_status & ~HS_FFER1;
 
+       spin_lock_irq(&phba->hbalock);
        phba->hba_flag &= ~DEFER_ERATT;
+       spin_unlock_irq(&phba->hbalock);
        phba->work_status[0] = readl(phba->MBslimaddr + 0xa8);
        phba->work_status[1] = readl(phba->MBslimaddr + 0xac);
 }
 
+static void
+lpfc_board_errevt_to_mgmt(struct lpfc_hba *phba)
+{
+       struct lpfc_board_event_header board_event;
+       struct Scsi_Host *shost;
+
+       board_event.event_type = FC_REG_BOARD_EVENT;
+       board_event.subcategory = LPFC_EVENT_PORTINTERR;
+       shost = lpfc_shost_from_vport(phba->pport);
+       fc_host_post_vendor_event(shost, fc_get_event_number(),
+                                 sizeof(board_event),
+                                 (char *) &board_event,
+                                 LPFC_NL_VENDOR_ID);
+}
+
 /**
- * lpfc_handle_eratt - The HBA hardware error handler
+ * lpfc_handle_eratt_s3 - The SLI3 HBA hardware error handler
  * @phba: pointer to lpfc hba data structure.
  *
  * This routine is invoked to handle the following HBA hardware error
@@ -924,8 +1070,8 @@ lpfc_handle_deferred_eratt(struct lpfc_hba *phba)
  * 2 - DMA ring index out of range
  * 3 - Mailbox command came back as unknown
  **/
-void
-lpfc_handle_eratt(struct lpfc_hba *phba)
+static void
+lpfc_handle_eratt_s3(struct lpfc_hba *phba)
 {
        struct lpfc_vport *vport = phba->pport;
        struct lpfc_sli   *psli = &phba->sli;
@@ -934,24 +1080,23 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
        unsigned long temperature;
        struct temp_event temp_event_data;
        struct Scsi_Host  *shost;
-       struct lpfc_board_event_header board_event;
 
        /* If the pci channel is offline, ignore possible errors,
-        * since we cannot communicate with the pci card anyway. */
-       if (pci_channel_offline(phba->pcidev))
+        * since we cannot communicate with the pci card anyway.
+        */
+       if (pci_channel_offline(phba->pcidev)) {
+               spin_lock_irq(&phba->hbalock);
+               phba->hba_flag &= ~DEFER_ERATT;
+               spin_unlock_irq(&phba->hbalock);
                return;
+       }
+
        /* If resets are disabled then leave the HBA alone and return */
        if (!phba->cfg_enable_hba_reset)
                return;
 
        /* Send an internal error event to mgmt application */
-       board_event.event_type = FC_REG_BOARD_EVENT;
-       board_event.subcategory = LPFC_EVENT_PORTINTERR;
-       shost = lpfc_shost_from_vport(phba->pport);
-       fc_host_post_vendor_event(shost, fc_get_event_number(),
-                                 sizeof(board_event),
-                                 (char *) &board_event,
-                                 LPFC_NL_VENDOR_ID);
+       lpfc_board_errevt_to_mgmt(phba);
 
        if (phba->hba_flag & DEFER_ERATT)
                lpfc_handle_deferred_eratt(phba);
@@ -965,7 +1110,7 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
                                phba->work_status[0], phba->work_status[1]);
 
                spin_lock_irq(&phba->hbalock);
-               psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+               psli->sli_flag &= ~LPFC_SLI_ACTIVE;
                spin_unlock_irq(&phba->hbalock);
 
                /*
@@ -1036,6 +1181,65 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
        return;
 }
 
+/**
+ * lpfc_handle_eratt_s4 - The SLI4 HBA hardware error handler
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to handle the SLI4 HBA hardware error attention
+ * conditions.
+ **/
+static void
+lpfc_handle_eratt_s4(struct lpfc_hba *phba)
+{
+       struct lpfc_vport *vport = phba->pport;
+       uint32_t event_data;
+       struct Scsi_Host *shost;
+
+       /* If the pci channel is offline, ignore possible errors, since
+        * we cannot communicate with the pci card anyway.
+        */
+       if (pci_channel_offline(phba->pcidev))
+               return;
+       /* If resets are disabled then leave the HBA alone and return */
+       if (!phba->cfg_enable_hba_reset)
+               return;
+
+       /* Send an internal error event to mgmt application */
+       lpfc_board_errevt_to_mgmt(phba);
+
+       /* For now, the actual action for SLI4 device handling is not
+        * specified yet, just treated it as adaptor hardware failure
+        */
+       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                       "0143 SLI4 Adapter Hardware Error Data: x%x x%x\n",
+                       phba->work_status[0], phba->work_status[1]);
+
+       event_data = FC_REG_DUMP_EVENT;
+       shost = lpfc_shost_from_vport(vport);
+       fc_host_post_vendor_event(shost, fc_get_event_number(),
+                                 sizeof(event_data), (char *) &event_data,
+                                 SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
+
+       lpfc_sli4_offline_eratt(phba);
+}
+
+/**
+ * lpfc_handle_eratt - Wrapper func for handling hba error attention
+ * @phba: pointer to lpfc HBA data structure.
+ *
+ * This routine wraps the actual SLI3 or SLI4 hba error attention handling
+ * routine from the API jump table function pointer from the lpfc_hba struct.
+ *
+ * Return codes
+ *   0 - sucess.
+ *   Any other value - error.
+ **/
+void
+lpfc_handle_eratt(struct lpfc_hba *phba)
+{
+       (*phba->lpfc_handle_eratt)(phba);
+}
+
 /**
  * lpfc_handle_latt - The HBA link event handler
  * @phba: pointer to lpfc hba data structure.
@@ -1137,7 +1341,7 @@ lpfc_handle_latt_err_exit:
  *   0 - pointer to the VPD passed in is NULL
  *   1 - success
  **/
-static int
+int
 lpfc_parse_vpd(struct lpfc_hba *phba, uint8_t *vpd, int len)
 {
        uint8_t lenlo, lenhi;
@@ -1292,6 +1496,7 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
        uint16_t dev_id = phba->pcidev->device;
        int max_speed;
        int GE = 0;
+       int oneConnect = 0; /* default is not a oneConnect */
        struct {
                char * name;
                int    max_speed;
@@ -1437,6 +1642,14 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
        case PCI_DEVICE_ID_PROTEUS_S:
                m = (typeof(m)) {"LPemv12002-S", max_speed, "PCIe IOV"};
                break;
+       case PCI_DEVICE_ID_TIGERSHARK:
+               oneConnect = 1;
+               m = (typeof(m)) {"OCe10100-F", max_speed, "PCIe"};
+               break;
+       case PCI_DEVICE_ID_TIGERSHARK_S:
+               oneConnect = 1;
+               m = (typeof(m)) {"OCe10100-F-S", max_speed, "PCIe"};
+               break;
        default:
                m = (typeof(m)){ NULL };
                break;
@@ -1444,13 +1657,24 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
 
        if (mdp && mdp[0] == '\0')
                snprintf(mdp, 79,"%s", m.name);
-       if (descp && descp[0] == '\0')
-               snprintf(descp, 255,
-                       "Emulex %s %d%s %s %s",
-                       m.name, m.max_speed,
-                       (GE) ? "GE" : "Gb",
-                       m.bus,
-                       (GE) ? "FCoE Adapter" : "Fibre Channel Adapter");
+       /* oneConnect hba requires special processing, they are all initiators
+        * and we put the port number on the end
+        */
+       if (descp && descp[0] == '\0') {
+               if (oneConnect)
+                       snprintf(descp, 255,
+                               "Emulex OneConnect %s, FCoE Initiator, Port %s",
+                               m.name,
+                               phba->Port);
+               else
+                       snprintf(descp, 255,
+                               "Emulex %s %d%s %s %s",
+                               m.name, m.max_speed,
+                               (GE) ? "GE" : "Gb",
+                               m.bus,
+                               (GE) ? "FCoE Adapter" :
+                                       "Fibre Channel Adapter");
+       }
 }
 
 /**
@@ -1533,7 +1757,8 @@ lpfc_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt)
                icmd->ulpCommand = CMD_QUE_RING_BUF64_CN;
                icmd->ulpLe = 1;
 
-               if (lpfc_sli_issue_iocb(phba, pring, iocb, 0) == IOCB_ERROR) {
+               if (lpfc_sli_issue_iocb(phba, pring->ringno, iocb, 0) ==
+                   IOCB_ERROR) {
                        lpfc_mbuf_free(phba, mp1->virt, mp1->phys);
                        kfree(mp1);
                        cnt++;
@@ -1761,7 +1986,6 @@ lpfc_cleanup(struct lpfc_vport *vport)
         * Lets wait for this to happen, if needed.
         */
        while (!list_empty(&vport->fc_nodes)) {
-
                if (i++ > 3000) {
                        lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
                                "0233 Nodelist not empty\n");
@@ -1782,7 +2006,6 @@ lpfc_cleanup(struct lpfc_vport *vport)
                /* Wait for any activity on ndlps to settle */
                msleep(10);
        }
-       return;
 }
 
 /**
@@ -1803,22 +2026,36 @@ lpfc_stop_vport_timers(struct lpfc_vport *vport)
 }
 
 /**
- * lpfc_stop_phba_timers - Stop all the timers associated with an HBA
+ * lpfc_stop_hba_timers - Stop all the timers associated with an HBA
  * @phba: pointer to lpfc hba data structure.
  *
  * This routine stops all the timers associated with a HBA. This function is
  * invoked before either putting a HBA offline or unloading the driver.
  **/
-static void
-lpfc_stop_phba_timers(struct lpfc_hba *phba)
+void
+lpfc_stop_hba_timers(struct lpfc_hba *phba)
 {
-       del_timer_sync(&phba->fcp_poll_timer);
        lpfc_stop_vport_timers(phba->pport);
        del_timer_sync(&phba->sli.mbox_tmo);
        del_timer_sync(&phba->fabric_block_timer);
-       phba->hb_outstanding = 0;
-       del_timer_sync(&phba->hb_tmofunc);
        del_timer_sync(&phba->eratt_poll);
+       del_timer_sync(&phba->hb_tmofunc);
+       phba->hb_outstanding = 0;
+
+       switch (phba->pci_dev_grp) {
+       case LPFC_PCI_DEV_LP:
+               /* Stop any LightPulse device specific driver timers */
+               del_timer_sync(&phba->fcp_poll_timer);
+               break;
+       case LPFC_PCI_DEV_OC:
+               /* Stop any OneConnect device sepcific driver timers */
+               break;
+       default:
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0297 Invalid device group (x%x)\n",
+                               phba->pci_dev_grp);
+               break;
+       }
        return;
 }
 
@@ -1878,14 +2115,21 @@ lpfc_online(struct lpfc_hba *phba)
                return 1;
        }
 
-       if (lpfc_sli_hba_setup(phba)) { /* Initialize the HBA */
-               lpfc_unblock_mgmt_io(phba);
-               return 1;
+       if (phba->sli_rev == LPFC_SLI_REV4) {
+               if (lpfc_sli4_hba_setup(phba)) { /* Initialize SLI4 HBA */
+                       lpfc_unblock_mgmt_io(phba);
+                       return 1;
+               }
+       } else {
+               if (lpfc_sli_hba_setup(phba)) { /* Initialize SLI2/SLI3 HBA */
+                       lpfc_unblock_mgmt_io(phba);
+                       return 1;
+               }
        }
 
        vports = lpfc_create_vport_work_array(phba);
        if (vports != NULL)
-               for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+               for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
                        struct Scsi_Host *shost;
                        shost = lpfc_shost_from_vport(vports[i]);
                        spin_lock_irq(shost->host_lock);
@@ -1947,11 +2191,12 @@ lpfc_offline_prep(struct lpfc_hba * phba)
        /* Issue an unreg_login to all nodes on all vports */
        vports = lpfc_create_vport_work_array(phba);
        if (vports != NULL) {
-               for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+               for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
                        struct Scsi_Host *shost;
 
                        if (vports[i]->load_flag & FC_UNLOADING)
                                continue;
+                       vports[i]->vfi_state &= ~LPFC_VFI_REGISTERED;
                        shost = lpfc_shost_from_vport(vports[i]);
                        list_for_each_entry_safe(ndlp, next_ndlp,
                                                 &vports[i]->fc_nodes,
@@ -1975,7 +2220,7 @@ lpfc_offline_prep(struct lpfc_hba * phba)
        }
        lpfc_destroy_vport_work_array(phba, vports);
 
-       lpfc_sli_flush_mbox_queue(phba);
+       lpfc_sli_mbox_sys_shutdown(phba);
 }
 
 /**
@@ -1996,11 +2241,11 @@ lpfc_offline(struct lpfc_hba *phba)
        if (phba->pport->fc_flag & FC_OFFLINE_MODE)
                return;
 
-       /* stop all timers associated with this hba */
-       lpfc_stop_phba_timers(phba);
+       /* stop port and all timers associated with this hba */
+       lpfc_stop_port(phba);
        vports = lpfc_create_vport_work_array(phba);
        if (vports != NULL)
-               for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++)
+               for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++)
                        lpfc_stop_vport_timers(vports[i]);
        lpfc_destroy_vport_work_array(phba, vports);
        lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
@@ -2013,7 +2258,7 @@ lpfc_offline(struct lpfc_hba *phba)
        spin_unlock_irq(&phba->hbalock);
        vports = lpfc_create_vport_work_array(phba);
        if (vports != NULL)
-               for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+               for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
                        shost = lpfc_shost_from_vport(vports[i]);
                        spin_lock_irq(shost->host_lock);
                        vports[i]->work_port_events = 0;
@@ -2106,6 +2351,10 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
        shost->max_lun = vport->cfg_max_luns;
        shost->this_id = -1;
        shost->max_cmd_len = 16;
+       if (phba->sli_rev == LPFC_SLI_REV4) {
+               shost->dma_boundary = LPFC_SLI4_MAX_SEGMENT_SIZE;
+               shost->sg_tablesize = phba->cfg_sg_seg_cnt;
+       }
 
        /*
         * Set initial can_queue value since 0 is no longer supported and
@@ -2123,6 +2372,7 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
 
        /* Initialize all internally managed lists. */
        INIT_LIST_HEAD(&vport->fc_nodes);
+       INIT_LIST_HEAD(&vport->rcv_buffer_list);
        spin_lock_init(&vport->work_port_lock);
 
        init_timer(&vport->fc_disctmo);
@@ -2314,192 +2564,501 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost)
 }
 
 /**
- * lpfc_enable_msix - Enable MSI-X interrupt mode
+ * lpfc_stop_port_s3 - Stop SLI3 device port
  * @phba: pointer to lpfc hba data structure.
  *
- * This routine is invoked to enable the MSI-X interrupt vectors. The kernel
- * function pci_enable_msix() is called to enable the MSI-X vectors. Note that
- * pci_enable_msix(), once invoked, enables either all or nothing, depending
- * on the current availability of PCI vector resources. The device driver is
- * responsible for calling the individual request_irq() to register each MSI-X
- * vector with a interrupt handler, which is done in this function. Note that
- * later when device is unloading, the driver should always call free_irq()
- * on all MSI-X vectors it has done request_irq() on before calling
- * pci_disable_msix(). Failure to do so results in a BUG_ON() and a device
- * will be left with MSI-X enabled and leaks its vectors.
- *
- * Return codes
- *   0 - sucessful
- *   other values - error
+ * This routine is invoked to stop an SLI3 device port, it stops the device
+ * from generating interrupts and stops the device driver's timers for the
+ * device.
  **/
-static int
-lpfc_enable_msix(struct lpfc_hba *phba)
+static void
+lpfc_stop_port_s3(struct lpfc_hba *phba)
 {
-       int rc, i;
-       LPFC_MBOXQ_t *pmb;
+       /* Clear all interrupt enable conditions */
+       writel(0, phba->HCregaddr);
+       readl(phba->HCregaddr); /* flush */
+       /* Clear all pending interrupts */
+       writel(0xffffffff, phba->HAregaddr);
+       readl(phba->HAregaddr); /* flush */
 
-       /* Set up MSI-X multi-message vectors */
-       for (i = 0; i < LPFC_MSIX_VECTORS; i++)
-               phba->msix_entries[i].entry = i;
+       /* Reset some HBA SLI setup states */
+       lpfc_stop_hba_timers(phba);
+       phba->pport->work_port_events = 0;
+}
 
-       /* Configure MSI-X capability structure */
-       rc = pci_enable_msix(phba->pcidev, phba->msix_entries,
-                               ARRAY_SIZE(phba->msix_entries));
-       if (rc) {
-               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-                               "0420 PCI enable MSI-X failed (%d)\n", rc);
-               goto msi_fail_out;
-       } else
-               for (i = 0; i < LPFC_MSIX_VECTORS; i++)
-                       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-                                       "0477 MSI-X entry[%d]: vector=x%x "
-                                       "message=%d\n", i,
-                                       phba->msix_entries[i].vector,
-                                       phba->msix_entries[i].entry);
-       /*
-        * Assign MSI-X vectors to interrupt handlers
-        */
+/**
+ * lpfc_stop_port_s4 - Stop SLI4 device port
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to stop an SLI4 device port, it stops the device
+ * from generating interrupts and stops the device driver's timers for the
+ * device.
+ **/
+static void
+lpfc_stop_port_s4(struct lpfc_hba *phba)
+{
+       /* Reset some HBA SLI4 setup states */
+       lpfc_stop_hba_timers(phba);
+       phba->pport->work_port_events = 0;
+       phba->sli4_hba.intr_enable = 0;
+       /* Hard clear it for now, shall have more graceful way to wait later */
+       phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+}
 
-       /* vector-0 is associated to slow-path handler */
-       rc = request_irq(phba->msix_entries[0].vector, &lpfc_sp_intr_handler,
-                        IRQF_SHARED, LPFC_SP_DRIVER_HANDLER_NAME, phba);
-       if (rc) {
-               lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
-                               "0421 MSI-X slow-path request_irq failed "
-                               "(%d)\n", rc);
-               goto msi_fail_out;
-       }
+/**
+ * lpfc_stop_port - Wrapper function for stopping hba port
+ * @phba: Pointer to HBA context object.
+ *
+ * This routine wraps the actual SLI3 or SLI4 hba stop port routine from
+ * the API jump table function pointer from the lpfc_hba struct.
+ **/
+void
+lpfc_stop_port(struct lpfc_hba *phba)
+{
+       phba->lpfc_stop_port(phba);
+}
 
-       /* vector-1 is associated to fast-path handler */
-       rc = request_irq(phba->msix_entries[1].vector, &lpfc_fp_intr_handler,
-                        IRQF_SHARED, LPFC_FP_DRIVER_HANDLER_NAME, phba);
+/**
+ * lpfc_sli4_remove_dflt_fcf - Remove the driver default fcf record from the port.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to remove the driver default fcf record from
+ * the port.  This routine currently acts on FCF Index 0.
+ *
+ **/
+void
+lpfc_sli_remove_dflt_fcf(struct lpfc_hba *phba)
+{
+       int rc = 0;
+       LPFC_MBOXQ_t *mboxq;
+       struct lpfc_mbx_del_fcf_tbl_entry *del_fcf_record;
+       uint32_t mbox_tmo, req_len;
+       uint32_t shdr_status, shdr_add_status;
 
-       if (rc) {
-               lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
-                               "0429 MSI-X fast-path request_irq failed "
-                               "(%d)\n", rc);
-               goto irq_fail_out;
+       mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mboxq) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                       "2020 Failed to allocate mbox for ADD_FCF cmd\n");
+               return;
        }
 
+       req_len = sizeof(struct lpfc_mbx_del_fcf_tbl_entry) -
+                 sizeof(struct lpfc_sli4_cfg_mhdr);
+       rc = lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_FCOE,
+                             LPFC_MBOX_OPCODE_FCOE_DELETE_FCF,
+                             req_len, LPFC_SLI4_MBX_EMBED);
        /*
-        * Configure HBA MSI-X attention conditions to messages
+        * In phase 1, there is a single FCF index, 0.  In phase2, the driver
+        * supports multiple FCF indices.
         */
-       pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       del_fcf_record = &mboxq->u.mqe.un.del_fcf_entry;
+       bf_set(lpfc_mbx_del_fcf_tbl_count, del_fcf_record, 1);
+       bf_set(lpfc_mbx_del_fcf_tbl_index, del_fcf_record,
+              phba->fcf.fcf_indx);
 
-       if (!pmb) {
-               rc = -ENOMEM;
-               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                               "0474 Unable to allocate memory for issuing "
-                               "MBOX_CONFIG_MSI command\n");
-               goto mem_fail_out;
+       if (!phba->sli4_hba.intr_enable)
+               rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+       else {
+               mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG);
+               rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo);
        }
-       rc = lpfc_config_msi(phba, pmb);
-       if (rc)
-               goto mbx_fail_out;
-       rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
-       if (rc != MBX_SUCCESS) {
-               lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
-                               "0351 Config MSI mailbox command failed, "
-                               "mbxCmd x%x, mbxStatus x%x\n",
-                               pmb->mb.mbxCommand, pmb->mb.mbxStatus);
-               goto mbx_fail_out;
+       /* The IOCTL status is embedded in the mailbox subheader. */
+       shdr_status = bf_get(lpfc_mbox_hdr_status,
+                            &del_fcf_record->header.cfg_shdr.response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
+                                &del_fcf_record->header.cfg_shdr.response);
+       if (shdr_status || shdr_add_status || rc != MBX_SUCCESS) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "2516 DEL FCF of default FCF Index failed "
+                               "mbx status x%x, status x%x add_status x%x\n",
+                               rc, shdr_status, shdr_add_status);
        }
+       if (rc != MBX_TIMEOUT)
+               mempool_free(mboxq, phba->mbox_mem_pool);
+}
 
-       /* Free memory allocated for mailbox command */
-       mempool_free(pmb, phba->mbox_mem_pool);
-       return rc;
+/**
+ * lpfc_sli4_parse_latt_fault - Parse sli4 link-attention link fault code
+ * @phba: pointer to lpfc hba data structure.
+ * @acqe_link: pointer to the async link completion queue entry.
+ *
+ * This routine is to parse the SLI4 link-attention link fault code and
+ * translate it into the base driver's read link attention mailbox command
+ * status.
+ *
+ * Return: Link-attention status in terms of base driver's coding.
+ **/
+static uint16_t
+lpfc_sli4_parse_latt_fault(struct lpfc_hba *phba,
+                          struct lpfc_acqe_link *acqe_link)
+{
+       uint16_t latt_fault;
 
-mbx_fail_out:
-       /* Free memory allocated for mailbox command */
-       mempool_free(pmb, phba->mbox_mem_pool);
+       switch (bf_get(lpfc_acqe_link_fault, acqe_link)) {
+       case LPFC_ASYNC_LINK_FAULT_NONE:
+       case LPFC_ASYNC_LINK_FAULT_LOCAL:
+       case LPFC_ASYNC_LINK_FAULT_REMOTE:
+               latt_fault = 0;
+               break;
+       default:
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0398 Invalid link fault code: x%x\n",
+                               bf_get(lpfc_acqe_link_fault, acqe_link));
+               latt_fault = MBXERR_ERROR;
+               break;
+       }
+       return latt_fault;
+}
 
-mem_fail_out:
-       /* free the irq already requested */
-       free_irq(phba->msix_entries[1].vector, phba);
+/**
+ * lpfc_sli4_parse_latt_type - Parse sli4 link attention type
+ * @phba: pointer to lpfc hba data structure.
+ * @acqe_link: pointer to the async link completion queue entry.
+ *
+ * This routine is to parse the SLI4 link attention type and translate it
+ * into the base driver's link attention type coding.
+ *
+ * Return: Link attention type in terms of base driver's coding.
+ **/
+static uint8_t
+lpfc_sli4_parse_latt_type(struct lpfc_hba *phba,
+                         struct lpfc_acqe_link *acqe_link)
+{
+       uint8_t att_type;
 
-irq_fail_out:
-       /* free the irq already requested */
-       free_irq(phba->msix_entries[0].vector, phba);
+       switch (bf_get(lpfc_acqe_link_status, acqe_link)) {
+       case LPFC_ASYNC_LINK_STATUS_DOWN:
+       case LPFC_ASYNC_LINK_STATUS_LOGICAL_DOWN:
+               att_type = AT_LINK_DOWN;
+               break;
+       case LPFC_ASYNC_LINK_STATUS_UP:
+               /* Ignore physical link up events - wait for logical link up */
+               att_type = AT_RESERVED;
+               break;
+       case LPFC_ASYNC_LINK_STATUS_LOGICAL_UP:
+               att_type = AT_LINK_UP;
+               break;
+       default:
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0399 Invalid link attention type: x%x\n",
+                               bf_get(lpfc_acqe_link_status, acqe_link));
+               att_type = AT_RESERVED;
+               break;
+       }
+       return att_type;
+}
 
-msi_fail_out:
-       /* Unconfigure MSI-X capability structure */
-       pci_disable_msix(phba->pcidev);
-       return rc;
+/**
+ * lpfc_sli4_parse_latt_link_speed - Parse sli4 link-attention link speed
+ * @phba: pointer to lpfc hba data structure.
+ * @acqe_link: pointer to the async link completion queue entry.
+ *
+ * This routine is to parse the SLI4 link-attention link speed and translate
+ * it into the base driver's link-attention link speed coding.
+ *
+ * Return: Link-attention link speed in terms of base driver's coding.
+ **/
+static uint8_t
+lpfc_sli4_parse_latt_link_speed(struct lpfc_hba *phba,
+                               struct lpfc_acqe_link *acqe_link)
+{
+       uint8_t link_speed;
+
+       switch (bf_get(lpfc_acqe_link_speed, acqe_link)) {
+       case LPFC_ASYNC_LINK_SPEED_ZERO:
+               link_speed = LA_UNKNW_LINK;
+               break;
+       case LPFC_ASYNC_LINK_SPEED_10MBPS:
+               link_speed = LA_UNKNW_LINK;
+               break;
+       case LPFC_ASYNC_LINK_SPEED_100MBPS:
+               link_speed = LA_UNKNW_LINK;
+               break;
+       case LPFC_ASYNC_LINK_SPEED_1GBPS:
+               link_speed = LA_1GHZ_LINK;
+               break;
+       case LPFC_ASYNC_LINK_SPEED_10GBPS:
+               link_speed = LA_10GHZ_LINK;
+               break;
+       default:
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0483 Invalid link-attention link speed: x%x\n",
+                               bf_get(lpfc_acqe_link_speed, acqe_link));
+               link_speed = LA_UNKNW_LINK;
+               break;
+       }
+       return link_speed;
 }
 
 /**
- * lpfc_disable_msix - Disable MSI-X interrupt mode
+ * lpfc_sli4_async_link_evt - Process the asynchronous link event
  * @phba: pointer to lpfc hba data structure.
+ * @acqe_link: pointer to the async link completion queue entry.
  *
- * This routine is invoked to release the MSI-X vectors and then disable the
- * MSI-X interrupt mode.
+ * This routine is to handle the SLI4 asynchronous link event.
  **/
 static void
-lpfc_disable_msix(struct lpfc_hba *phba)
+lpfc_sli4_async_link_evt(struct lpfc_hba *phba,
+                        struct lpfc_acqe_link *acqe_link)
 {
-       int i;
+       struct lpfc_dmabuf *mp;
+       LPFC_MBOXQ_t *pmb;
+       MAILBOX_t *mb;
+       READ_LA_VAR *la;
+       uint8_t att_type;
 
-       /* Free up MSI-X multi-message vectors */
-       for (i = 0; i < LPFC_MSIX_VECTORS; i++)
-               free_irq(phba->msix_entries[i].vector, phba);
-       /* Disable MSI-X */
-       pci_disable_msix(phba->pcidev);
+       att_type = lpfc_sli4_parse_latt_type(phba, acqe_link);
+       if (att_type != AT_LINK_DOWN && att_type != AT_LINK_UP)
+               return;
+       pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!pmb) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "0395 The mboxq allocation failed\n");
+               return;
+       }
+       mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+       if (!mp) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "0396 The lpfc_dmabuf allocation failed\n");
+               goto out_free_pmb;
+       }
+       mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
+       if (!mp->virt) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "0397 The mbuf allocation failed\n");
+               goto out_free_dmabuf;
+       }
+
+       /* Cleanup any outstanding ELS commands */
+       lpfc_els_flush_all_cmd(phba);
+
+       /* Block ELS IOCBs until we have done process link event */
+       phba->sli.ring[LPFC_ELS_RING].flag |= LPFC_STOP_IOCB_EVENT;
+
+       /* Update link event statistics */
+       phba->sli.slistat.link_event++;
+
+       /* Create pseudo lpfc_handle_latt mailbox command from link ACQE */
+       lpfc_read_la(phba, pmb, mp);
+       pmb->vport = phba->pport;
+
+       /* Parse and translate status field */
+       mb = &pmb->u.mb;
+       mb->mbxStatus = lpfc_sli4_parse_latt_fault(phba, acqe_link);
+
+       /* Parse and translate link attention fields */
+       la = (READ_LA_VAR *) &pmb->u.mb.un.varReadLA;
+       la->eventTag = acqe_link->event_tag;
+       la->attType = att_type;
+       la->UlnkSpeed = lpfc_sli4_parse_latt_link_speed(phba, acqe_link);
+
+       /* Fake the the following irrelvant fields */
+       la->topology = TOPOLOGY_PT_PT;
+       la->granted_AL_PA = 0;
+       la->il = 0;
+       la->pb = 0;
+       la->fa = 0;
+       la->mm = 0;
+
+       /* Keep the link status for extra SLI4 state machine reference */
+       phba->sli4_hba.link_state.speed =
+                               bf_get(lpfc_acqe_link_speed, acqe_link);
+       phba->sli4_hba.link_state.duplex =
+                               bf_get(lpfc_acqe_link_duplex, acqe_link);
+       phba->sli4_hba.link_state.status =
+                               bf_get(lpfc_acqe_link_status, acqe_link);
+       phba->sli4_hba.link_state.physical =
+                               bf_get(lpfc_acqe_link_physical, acqe_link);
+       phba->sli4_hba.link_state.fault =
+                               bf_get(lpfc_acqe_link_fault, acqe_link);
+
+       /* Invoke the lpfc_handle_latt mailbox command callback function */
+       lpfc_mbx_cmpl_read_la(phba, pmb);
+
+       return;
+
+out_free_dmabuf:
+       kfree(mp);
+out_free_pmb:
+       mempool_free(pmb, phba->mbox_mem_pool);
 }
 
 /**
- * lpfc_enable_msi - Enable MSI interrupt mode
+ * lpfc_sli4_async_fcoe_evt - Process the asynchronous fcoe event
  * @phba: pointer to lpfc hba data structure.
+ * @acqe_link: pointer to the async fcoe completion queue entry.
  *
- * This routine is invoked to enable the MSI interrupt mode. The kernel
- * function pci_enable_msi() is called to enable the MSI vector. The
- * device driver is responsible for calling the request_irq() to register
- * MSI vector with a interrupt the handler, which is done in this function.
- *
- * Return codes
- *     0 - sucessful
- *     other values - error
- */
-static int
-lpfc_enable_msi(struct lpfc_hba *phba)
+ * This routine is to handle the SLI4 asynchronous fcoe event.
+ **/
+static void
+lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
+                        struct lpfc_acqe_fcoe *acqe_fcoe)
 {
+       uint8_t event_type = bf_get(lpfc_acqe_fcoe_event_type, acqe_fcoe);
        int rc;
 
-       rc = pci_enable_msi(phba->pcidev);
-       if (!rc)
-               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-                               "0462 PCI enable MSI mode success.\n");
-       else {
-               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-                               "0471 PCI enable MSI mode failed (%d)\n", rc);
-               return rc;
-       }
+       switch (event_type) {
+       case LPFC_FCOE_EVENT_TYPE_NEW_FCF:
+               lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+                       "2546 New FCF found index 0x%x tag 0x%x \n",
+                       acqe_fcoe->fcf_index,
+                       acqe_fcoe->event_tag);
+               /*
+                * If the current FCF is in discovered state,
+                * do nothing.
+                */
+               spin_lock_irq(&phba->hbalock);
+               if (phba->fcf.fcf_flag & FCF_DISCOVERED) {
+                       spin_unlock_irq(&phba->hbalock);
+                       break;
+               }
+               spin_unlock_irq(&phba->hbalock);
 
-       rc = request_irq(phba->pcidev->irq, lpfc_intr_handler,
-                        IRQF_SHARED, LPFC_DRIVER_NAME, phba);
-       if (rc) {
-               pci_disable_msi(phba->pcidev);
-               lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
-                               "0478 MSI request_irq failed (%d)\n", rc);
+               /* Read the FCF table and re-discover SAN. */
+               rc = lpfc_sli4_read_fcf_record(phba,
+                       LPFC_FCOE_FCF_GET_FIRST);
+               if (rc)
+                       lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+                               "2547 Read FCF record failed 0x%x\n",
+                               rc);
+               break;
+
+       case LPFC_FCOE_EVENT_TYPE_FCF_TABLE_FULL:
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                       "2548 FCF Table full count 0x%x tag 0x%x \n",
+                       bf_get(lpfc_acqe_fcoe_fcf_count, acqe_fcoe),
+                       acqe_fcoe->event_tag);
+               break;
+
+       case LPFC_FCOE_EVENT_TYPE_FCF_DEAD:
+               lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+                       "2549 FCF disconnected fron network index 0x%x"
+                       " tag 0x%x \n", acqe_fcoe->fcf_index,
+                       acqe_fcoe->event_tag);
+               /* If the event is not for currently used fcf do nothing */
+               if (phba->fcf.fcf_indx != acqe_fcoe->fcf_index)
+                       break;
+               /*
+                * Currently, driver support only one FCF - so treat this as
+                * a link down.
+                */
+               lpfc_linkdown(phba);
+               /* Unregister FCF if no devices connected to it */
+               lpfc_unregister_unused_fcf(phba);
+               break;
+
+       default:
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                       "0288 Unknown FCoE event type 0x%x event tag "
+                       "0x%x\n", event_type, acqe_fcoe->event_tag);
+               break;
        }
-       return rc;
 }
 
 /**
- * lpfc_disable_msi - Disable MSI interrupt mode
+ * lpfc_sli4_async_dcbx_evt - Process the asynchronous dcbx event
  * @phba: pointer to lpfc hba data structure.
+ * @acqe_link: pointer to the async dcbx completion queue entry.
  *
- * This routine is invoked to disable the MSI interrupt mode. The driver
- * calls free_irq() on MSI vector it has done request_irq() on before
- * calling pci_disable_msi(). Failure to do so results in a BUG_ON() and
- * a device will be left with MSI enabled and leaks its vector.
- */
-
+ * This routine is to handle the SLI4 asynchronous dcbx event.
+ **/
 static void
-lpfc_disable_msi(struct lpfc_hba *phba)
+lpfc_sli4_async_dcbx_evt(struct lpfc_hba *phba,
+                        struct lpfc_acqe_dcbx *acqe_dcbx)
 {
-       free_irq(phba->pcidev->irq, phba);
-       pci_disable_msi(phba->pcidev);
-       return;
+       lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                       "0290 The SLI4 DCBX asynchronous event is not "
+                       "handled yet\n");
+}
+
+/**
+ * lpfc_sli4_async_event_proc - Process all the pending asynchronous event
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked by the worker thread to process all the pending
+ * SLI4 asynchronous events.
+ **/
+void lpfc_sli4_async_event_proc(struct lpfc_hba *phba)
+{
+       struct lpfc_cq_event *cq_event;
+
+       /* First, declare the async event has been handled */
+       spin_lock_irq(&phba->hbalock);
+       phba->hba_flag &= ~ASYNC_EVENT;
+       spin_unlock_irq(&phba->hbalock);
+       /* Now, handle all the async events */
+       while (!list_empty(&phba->sli4_hba.sp_asynce_work_queue)) {
+               /* Get the first event from the head of the event queue */
+               spin_lock_irq(&phba->hbalock);
+               list_remove_head(&phba->sli4_hba.sp_asynce_work_queue,
+                                cq_event, struct lpfc_cq_event, list);
+               spin_unlock_irq(&phba->hbalock);
+               /* Process the asynchronous event */
+               switch (bf_get(lpfc_trailer_code, &cq_event->cqe.mcqe_cmpl)) {
+               case LPFC_TRAILER_CODE_LINK:
+                       lpfc_sli4_async_link_evt(phba,
+                                                &cq_event->cqe.acqe_link);
+                       break;
+               case LPFC_TRAILER_CODE_FCOE:
+                       lpfc_sli4_async_fcoe_evt(phba,
+                                                &cq_event->cqe.acqe_fcoe);
+                       break;
+               case LPFC_TRAILER_CODE_DCBX:
+                       lpfc_sli4_async_dcbx_evt(phba,
+                                                &cq_event->cqe.acqe_dcbx);
+                       break;
+               default:
+                       lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                                       "1804 Invalid asynchrous event code: "
+                                       "x%x\n", bf_get(lpfc_trailer_code,
+                                       &cq_event->cqe.mcqe_cmpl));
+                       break;
+               }
+               /* Free the completion event processed to the free pool */
+               lpfc_sli4_cq_event_release(phba, cq_event);
+       }
+}
+
+/**
+ * lpfc_api_table_setup - Set up per hba pci-device group func api jump table
+ * @phba: pointer to lpfc hba data structure.
+ * @dev_grp: The HBA PCI-Device group number.
+ *
+ * This routine is invoked to set up the per HBA PCI-Device group function
+ * API jump table entries.
+ *
+ * Return: 0 if success, otherwise -ENODEV
+ **/
+int
+lpfc_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
+{
+       int rc;
+
+       /* Set up lpfc PCI-device group */
+       phba->pci_dev_grp = dev_grp;
+
+       /* The LPFC_PCI_DEV_OC uses SLI4 */
+       if (dev_grp == LPFC_PCI_DEV_OC)
+               phba->sli_rev = LPFC_SLI_REV4;
+
+       /* Set up device INIT API function jump table */
+       rc = lpfc_init_api_table_setup(phba, dev_grp);
+       if (rc)
+               return -ENODEV;
+       /* Set up SCSI API function jump table */
+       rc = lpfc_scsi_api_table_setup(phba, dev_grp);
+       if (rc)
+               return -ENODEV;
+       /* Set up SLI API function jump table */
+       rc = lpfc_sli_api_table_setup(phba, dev_grp);
+       if (rc)
+               return -ENODEV;
+       /* Set up MBOX API function jump table */
+       rc = lpfc_mbox_api_table_setup(phba, dev_grp);
+       if (rc)
+               return -ENODEV;
+
+       return 0;
 }
 
 /**
@@ -2509,9 +3068,8 @@ lpfc_disable_msi(struct lpfc_hba *phba)
  *
  * This routine it invoked to log the currently used active interrupt mode
  * to the device.
- */
-static void
-lpfc_log_intr_mode(struct lpfc_hba *phba, uint32_t intr_mode)
+ **/
+static void lpfc_log_intr_mode(struct lpfc_hba *phba, uint32_t intr_mode)
 {
        switch (intr_mode) {
        case 0:
@@ -2534,659 +3092,4383 @@ lpfc_log_intr_mode(struct lpfc_hba *phba, uint32_t intr_mode)
        return;
 }
 
-static void
-lpfc_stop_port(struct lpfc_hba *phba)
-{
-       /* Clear all interrupt enable conditions */
-       writel(0, phba->HCregaddr);
-       readl(phba->HCregaddr); /* flush */
-       /* Clear all pending interrupts */
-       writel(0xffffffff, phba->HAregaddr);
-       readl(phba->HAregaddr); /* flush */
-
-       /* Reset some HBA SLI setup states */
-       lpfc_stop_phba_timers(phba);
-       phba->pport->work_port_events = 0;
-
-       return;
-}
-
 /**
- * lpfc_enable_intr - Enable device interrupt
+ * lpfc_enable_pci_dev - Enable a generic PCI device.
  * @phba: pointer to lpfc hba data structure.
  *
- * This routine is invoked to enable device interrupt and associate driver's
- * interrupt handler(s) to interrupt vector(s). Depends on the interrupt
- * mode configured to the driver, the driver will try to fallback from the
- * configured interrupt mode to an interrupt mode which is supported by the
- * platform, kernel, and device in the order of: MSI-X -> MSI -> IRQ.
+ * This routine is invoked to enable the PCI device that is common to all
+ * PCI devices.
  *
  * Return codes
- *   0 - sucessful
- *   other values - error
+ *     0 - sucessful
+ *     other values - error
  **/
-static uint32_t
-lpfc_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode)
+static int
+lpfc_enable_pci_dev(struct lpfc_hba *phba)
 {
-       uint32_t intr_mode = LPFC_INTR_ERROR;
-       int retval;
+       struct pci_dev *pdev;
+       int bars;
 
-       if (cfg_mode == 2) {
-               /* Need to issue conf_port mbox cmd before conf_msi mbox cmd */
-               retval = lpfc_sli_config_port(phba, 3);
-               if (!retval) {
-                       /* Now, try to enable MSI-X interrupt mode */
-                       retval = lpfc_enable_msix(phba);
-                       if (!retval) {
-                               /* Indicate initialization to MSI-X mode */
-                               phba->intr_type = MSIX;
-                               intr_mode = 2;
-                       }
-               }
-       }
+       /* Obtain PCI device reference */
+       if (!phba->pcidev)
+               goto out_error;
+       else
+               pdev = phba->pcidev;
+       /* Select PCI BARs */
+       bars = pci_select_bars(pdev, IORESOURCE_MEM);
+       /* Enable PCI device */
+       if (pci_enable_device_mem(pdev))
+               goto out_error;
+       /* Request PCI resource for the device */
+       if (pci_request_selected_regions(pdev, bars, LPFC_DRIVER_NAME))
+               goto out_disable_device;
+       /* Set up device as PCI master and save state for EEH */
+       pci_set_master(pdev);
+       pci_try_set_mwi(pdev);
+       pci_save_state(pdev);
 
-       /* Fallback to MSI if MSI-X initialization failed */
-       if (cfg_mode >= 1 && phba->intr_type == NONE) {
-               retval = lpfc_enable_msi(phba);
-               if (!retval) {
-                       /* Indicate initialization to MSI mode */
-                       phba->intr_type = MSI;
-                       intr_mode = 1;
-               }
-       }
+       return 0;
 
-       /* Fallback to INTx if both MSI-X/MSI initalization failed */
-       if (phba->intr_type == NONE) {
-               retval = request_irq(phba->pcidev->irq, lpfc_intr_handler,
-                                    IRQF_SHARED, LPFC_DRIVER_NAME, phba);
-               if (!retval) {
-                       /* Indicate initialization to INTx mode */
-                       phba->intr_type = INTx;
-                       intr_mode = 0;
-               }
-       }
-       return intr_mode;
+out_disable_device:
+       pci_disable_device(pdev);
+out_error:
+       return -ENODEV;
 }
 
 /**
- * lpfc_disable_intr - Disable device interrupt
+ * lpfc_disable_pci_dev - Disable a generic PCI device.
  * @phba: pointer to lpfc hba data structure.
  *
- * This routine is invoked to disable device interrupt and disassociate the
- * driver's interrupt handler(s) from interrupt vector(s). Depending on the
- * interrupt mode, the driver will release the interrupt vector(s) for the
- * message signaled interrupt.
+ * This routine is invoked to disable the PCI device that is common to all
+ * PCI devices.
  **/
 static void
-lpfc_disable_intr(struct lpfc_hba *phba)
+lpfc_disable_pci_dev(struct lpfc_hba *phba)
 {
-       /* Disable the currently initialized interrupt mode */
-       if (phba->intr_type == MSIX)
-               lpfc_disable_msix(phba);
-       else if (phba->intr_type == MSI)
-               lpfc_disable_msi(phba);
-       else if (phba->intr_type == INTx)
-               free_irq(phba->pcidev->irq, phba);
+       struct pci_dev *pdev;
+       int bars;
 
-       /* Reset interrupt management states */
-       phba->intr_type = NONE;
-       phba->sli.slistat.sli_intr = 0;
+       /* Obtain PCI device reference */
+       if (!phba->pcidev)
+               return;
+       else
+               pdev = phba->pcidev;
+       /* Select PCI BARs */
+       bars = pci_select_bars(pdev, IORESOURCE_MEM);
+       /* Release PCI resource and disable PCI device */
+       pci_release_selected_regions(pdev, bars);
+       pci_disable_device(pdev);
+       /* Null out PCI private reference to driver */
+       pci_set_drvdata(pdev, NULL);
 
        return;
 }
 
 /**
- * lpfc_pci_probe_one - lpfc PCI probe func to register device to PCI subsystem
- * @pdev: pointer to PCI device
- * @pid: pointer to PCI device identifier
- *
- * This routine is to be registered to the kernel's PCI subsystem. When an
- * Emulex HBA is presented in PCI bus, the kernel PCI subsystem looks at
- * PCI device-specific information of the device and driver to see if the
- * driver state that it can support this kind of device. If the match is
- * successful, the driver core invokes this routine. If this routine
- * determines it can claim the HBA, it does all the initialization that it
- * needs to do to handle the HBA properly.
+ * lpfc_reset_hba - Reset a hba
+ * @phba: pointer to lpfc hba data structure.
  *
- * Return code
- *   0 - driver can claim the device
- *   negative value - driver can not claim the device
+ * This routine is invoked to reset a hba device. It brings the HBA
+ * offline, performs a board restart, and then brings the board back
+ * online. The lpfc_offline calls lpfc_sli_hba_down which will clean up
+ * on outstanding mailbox commands.
  **/
-static int __devinit
-lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
+void
+lpfc_reset_hba(struct lpfc_hba *phba)
 {
-       struct lpfc_vport *vport = NULL;
-       struct lpfc_hba   *phba;
-       struct lpfc_sli   *psli;
-       struct lpfc_iocbq *iocbq_entry = NULL, *iocbq_next = NULL;
-       struct Scsi_Host  *shost = NULL;
-       void *ptr;
-       unsigned long bar0map_len, bar2map_len;
-       int error = -ENODEV, retval;
-       int  i, hbq_count;
-       uint16_t iotag;
-       uint32_t cfg_mode, intr_mode;
-       int bars = pci_select_bars(pdev, IORESOURCE_MEM);
-       struct lpfc_adapter_event_header adapter_event;
-
-       if (pci_enable_device_mem(pdev))
-               goto out;
-       if (pci_request_selected_regions(pdev, bars, LPFC_DRIVER_NAME))
-               goto out_disable_device;
-
-       phba = kzalloc(sizeof (struct lpfc_hba), GFP_KERNEL);
-       if (!phba)
-               goto out_release_regions;
-
-       atomic_set(&phba->fast_event_count, 0);
-       spin_lock_init(&phba->hbalock);
-
-       /* Initialize ndlp management spinlock */
-       spin_lock_init(&phba->ndlp_lock);
-
-       phba->pcidev = pdev;
+       /* If resets are disabled then set error state and return. */
+       if (!phba->cfg_enable_hba_reset) {
+               phba->link_state = LPFC_HBA_ERROR;
+               return;
+       }
+       lpfc_offline_prep(phba);
+       lpfc_offline(phba);
+       lpfc_sli_brdrestart(phba);
+       lpfc_online(phba);
+       lpfc_unblock_mgmt_io(phba);
+}
 
-       /* Assign an unused board number */
-       if ((phba->brd_no = lpfc_get_instance()) < 0)
-               goto out_free_phba;
+/**
+ * lpfc_sli_driver_resource_setup - Setup driver internal resources for SLI3 dev.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to set up the driver internal resources specific to
+ * support the SLI-3 HBA device it attached to.
+ *
+ * Return codes
+ *     0 - sucessful
+ *     other values - error
+ **/
+static int
+lpfc_sli_driver_resource_setup(struct lpfc_hba *phba)
+{
+       struct lpfc_sli *psli;
 
-       INIT_LIST_HEAD(&phba->port_list);
-       init_waitqueue_head(&phba->wait_4_mlo_m_q);
        /*
-        * Get all the module params for configuring this host and then
-        * establish the host.
+        * Initialize timers used by driver
         */
-       lpfc_get_cfgparam(phba);
-       phba->max_vpi = LPFC_MAX_VPI;
 
-       /* Initialize timers used by driver */
+       /* Heartbeat timer */
        init_timer(&phba->hb_tmofunc);
        phba->hb_tmofunc.function = lpfc_hb_timeout;
        phba->hb_tmofunc.data = (unsigned long)phba;
 
        psli = &phba->sli;
+       /* MBOX heartbeat timer */
        init_timer(&psli->mbox_tmo);
        psli->mbox_tmo.function = lpfc_mbox_timeout;
        psli->mbox_tmo.data = (unsigned long) phba;
+       /* FCP polling mode timer */
        init_timer(&phba->fcp_poll_timer);
        phba->fcp_poll_timer.function = lpfc_poll_timeout;
        phba->fcp_poll_timer.data = (unsigned long) phba;
+       /* Fabric block timer */
        init_timer(&phba->fabric_block_timer);
        phba->fabric_block_timer.function = lpfc_fabric_block_timeout;
        phba->fabric_block_timer.data = (unsigned long) phba;
+       /* EA polling mode timer */
        init_timer(&phba->eratt_poll);
        phba->eratt_poll.function = lpfc_poll_eratt;
        phba->eratt_poll.data = (unsigned long) phba;
 
-       pci_set_master(pdev);
-       pci_save_state(pdev);
-       pci_try_set_mwi(pdev);
+       /* Host attention work mask setup */
+       phba->work_ha_mask = (HA_ERATT | HA_MBATT | HA_LATT);
+       phba->work_ha_mask |= (HA_RXMASK << (LPFC_ELS_RING * 4));
+
+       /* Get all the module params for configuring this host */
+       lpfc_get_cfgparam(phba);
+       /*
+        * Since the sg_tablesize is module parameter, the sg_dma_buf_size
+        * used to create the sg_dma_buf_pool must be dynamically calculated.
+        * 2 segments are added since the IOCB needs a command and response bde.
+        */
+       phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) +
+               sizeof(struct fcp_rsp) +
+                       ((phba->cfg_sg_seg_cnt + 2) * sizeof(struct ulp_bde64));
+
+       if (phba->cfg_enable_bg) {
+               phba->cfg_sg_seg_cnt = LPFC_MAX_SG_SEG_CNT;
+               phba->cfg_sg_dma_buf_size +=
+                       phba->cfg_prot_sg_seg_cnt * sizeof(struct ulp_bde64);
+       }
 
-       if (pci_set_dma_mask(phba->pcidev, DMA_BIT_MASK(64)) != 0)
-               if (pci_set_dma_mask(phba->pcidev, DMA_BIT_MASK(32)) != 0)
-                       goto out_idr_remove;
+       /* Also reinitialize the host templates with new values. */
+       lpfc_vport_template.sg_tablesize = phba->cfg_sg_seg_cnt;
+       lpfc_template.sg_tablesize = phba->cfg_sg_seg_cnt;
+
+       phba->max_vpi = LPFC_MAX_VPI;
+       /* This will be set to correct value after config_port mbox */
+       phba->max_vports = 0;
 
        /*
-        * Get the bus address of Bar0 and Bar2 and the number of bytes
-        * required by each mapping.
+        * Initialize the SLI Layer to run with lpfc HBAs.
         */
-       phba->pci_bar0_map = pci_resource_start(phba->pcidev, 0);
-       bar0map_len        = pci_resource_len(phba->pcidev, 0);
+       lpfc_sli_setup(phba);
+       lpfc_sli_queue_setup(phba);
 
-       phba->pci_bar2_map = pci_resource_start(phba->pcidev, 2);
-       bar2map_len        = pci_resource_len(phba->pcidev, 2);
+       /* Allocate device driver memory */
+       if (lpfc_mem_alloc(phba, BPL_ALIGN_SZ))
+               return -ENOMEM;
 
-       /* Map HBA SLIM to a kernel virtual address. */
-       phba->slim_memmap_p = ioremap(phba->pci_bar0_map, bar0map_len);
-       if (!phba->slim_memmap_p) {
-               error = -ENODEV;
-               dev_printk(KERN_ERR, &pdev->dev,
-                          "ioremap failed for SLIM memory.\n");
-               goto out_idr_remove;
-       }
+       return 0;
+}
 
-       /* Map HBA Control Registers to a kernel virtual address. */
-       phba->ctrl_regs_memmap_p = ioremap(phba->pci_bar2_map, bar2map_len);
-       if (!phba->ctrl_regs_memmap_p) {
-               error = -ENODEV;
-               dev_printk(KERN_ERR, &pdev->dev,
-                          "ioremap failed for HBA control registers.\n");
-               goto out_iounmap_slim;
-       }
+/**
+ * lpfc_sli_driver_resource_unset - Unset drvr internal resources for SLI3 dev
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to unset the driver internal resources set up
+ * specific for supporting the SLI-3 HBA device it attached to.
+ **/
+static void
+lpfc_sli_driver_resource_unset(struct lpfc_hba *phba)
+{
+       /* Free device driver memory allocated */
+       lpfc_mem_free_all(phba);
 
-       /* Allocate memory for SLI-2 structures */
-       phba->slim2p.virt = dma_alloc_coherent(&phba->pcidev->dev,
-                                              SLI2_SLIM_SIZE,
-                                              &phba->slim2p.phys,
-                                              GFP_KERNEL);
-       if (!phba->slim2p.virt)
-               goto out_iounmap;
+       return;
+}
 
-       memset(phba->slim2p.virt, 0, SLI2_SLIM_SIZE);
-       phba->mbox = phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, mbx);
-       phba->pcb = (phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, pcb));
-       phba->IOCBs = (phba->slim2p.virt +
-                      offsetof(struct lpfc_sli2_slim, IOCBs));
+/**
+ * lpfc_sli4_driver_resource_setup - Setup drvr internal resources for SLI4 dev
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to set up the driver internal resources specific to
+ * support the SLI-4 HBA device it attached to.
+ *
+ * Return codes
+ *     0 - sucessful
+ *     other values - error
+ **/
+static int
+lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
+{
+       struct lpfc_sli *psli;
+       int rc;
+       int i, hbq_count;
 
-       phba->hbqslimp.virt = dma_alloc_coherent(&phba->pcidev->dev,
-                                                lpfc_sli_hbq_size(),
-                                                &phba->hbqslimp.phys,
-                                                GFP_KERNEL);
-       if (!phba->hbqslimp.virt)
-               goto out_free_slim;
+       /* Before proceed, wait for POST done and device ready */
+       rc = lpfc_sli4_post_status_check(phba);
+       if (rc)
+               return -ENODEV;
+
+       /*
+        * Initialize timers used by driver
+        */
+
+       /* Heartbeat timer */
+       init_timer(&phba->hb_tmofunc);
+       phba->hb_tmofunc.function = lpfc_hb_timeout;
+       phba->hb_tmofunc.data = (unsigned long)phba;
+
+       psli = &phba->sli;
+       /* MBOX heartbeat timer */
+       init_timer(&psli->mbox_tmo);
+       psli->mbox_tmo.function = lpfc_mbox_timeout;
+       psli->mbox_tmo.data = (unsigned long) phba;
+       /* Fabric block timer */
+       init_timer(&phba->fabric_block_timer);
+       phba->fabric_block_timer.function = lpfc_fabric_block_timeout;
+       phba->fabric_block_timer.data = (unsigned long) phba;
+       /* EA polling mode timer */
+       init_timer(&phba->eratt_poll);
+       phba->eratt_poll.function = lpfc_poll_eratt;
+       phba->eratt_poll.data = (unsigned long) phba;
+       /*
+        * We need to do a READ_CONFIG mailbox command here before
+        * calling lpfc_get_cfgparam. For VFs this will report the
+        * MAX_XRI, MAX_VPI, MAX_RPI, MAX_IOCB, and MAX_VFI settings.
+        * All of the resources allocated
+        * for this Port are tied to these values.
+        */
+       /* Get all the module params for configuring this host */
+       lpfc_get_cfgparam(phba);
+       phba->max_vpi = LPFC_MAX_VPI;
+       /* This will be set to correct value after the read_config mbox */
+       phba->max_vports = 0;
+
+       /* Program the default value of vlan_id and fc_map */
+       phba->valid_vlan = 0;
+       phba->fc_map[0] = LPFC_FCOE_FCF_MAP0;
+       phba->fc_map[1] = LPFC_FCOE_FCF_MAP1;
+       phba->fc_map[2] = LPFC_FCOE_FCF_MAP2;
+
+       /*
+        * Since the sg_tablesize is module parameter, the sg_dma_buf_size
+        * used to create the sg_dma_buf_pool must be dynamically calculated.
+        * 2 segments are added since the IOCB needs a command and response bde.
+        * To insure that the scsi sgl does not cross a 4k page boundary only
+        * sgl sizes of 1k, 2k, 4k, and 8k are supported.
+        * Table of sgl sizes and seg_cnt:
+        * sgl size,    sg_seg_cnt      total seg
+        * 1k           50              52
+        * 2k           114             116
+        * 4k           242             244
+        * 8k           498             500
+        * cmd(32) + rsp(160) + (52 * sizeof(sli4_sge)) = 1024
+        * cmd(32) + rsp(160) + (116 * sizeof(sli4_sge)) = 2048
+        * cmd(32) + rsp(160) + (244 * sizeof(sli4_sge)) = 4096
+        * cmd(32) + rsp(160) + (500 * sizeof(sli4_sge)) = 8192
+        */
+       if (phba->cfg_sg_seg_cnt <= LPFC_DEFAULT_SG_SEG_CNT)
+               phba->cfg_sg_seg_cnt = 50;
+       else if (phba->cfg_sg_seg_cnt <= 114)
+               phba->cfg_sg_seg_cnt = 114;
+       else if (phba->cfg_sg_seg_cnt <= 242)
+               phba->cfg_sg_seg_cnt = 242;
+       else
+               phba->cfg_sg_seg_cnt = 498;
 
+       phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd)
+                                       + sizeof(struct fcp_rsp);
+       phba->cfg_sg_dma_buf_size +=
+               ((phba->cfg_sg_seg_cnt + 2) * sizeof(struct sli4_sge));
+
+       /* Initialize buffer queue management fields */
        hbq_count = lpfc_sli_hbq_count();
-       ptr = phba->hbqslimp.virt;
-       for (i = 0; i < hbq_count; ++i) {
-               phba->hbqs[i].hbq_virt = ptr;
+       for (i = 0; i < hbq_count; ++i)
                INIT_LIST_HEAD(&phba->hbqs[i].hbq_buffer_list);
-               ptr += (lpfc_hbq_defs[i]->entry_count *
-                       sizeof(struct lpfc_hbq_entry));
-       }
-       phba->hbqs[LPFC_ELS_HBQ].hbq_alloc_buffer = lpfc_els_hbq_alloc;
-       phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer  = lpfc_els_hbq_free;
+       INIT_LIST_HEAD(&phba->rb_pend_list);
+       phba->hbqs[LPFC_ELS_HBQ].hbq_alloc_buffer = lpfc_sli4_rb_alloc;
+       phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer = lpfc_sli4_rb_free;
 
-       memset(phba->hbqslimp.virt, 0, lpfc_sli_hbq_size());
+       /*
+        * Initialize the SLI Layer to run with lpfc SLI4 HBAs.
+        */
+       /* Initialize the Abort scsi buffer list used by driver */
+       spin_lock_init(&phba->sli4_hba.abts_scsi_buf_list_lock);
+       INIT_LIST_HEAD(&phba->sli4_hba.lpfc_abts_scsi_buf_list);
+       /* This abort list used by worker thread */
+       spin_lock_init(&phba->sli4_hba.abts_sgl_list_lock);
 
-       INIT_LIST_HEAD(&phba->hbqbuf_in_list);
+       /*
+        * Initialize dirver internal slow-path work queues
+        */
 
-       /* Initialize the SLI Layer to run with lpfc HBAs. */
+       /* Driver internel slow-path CQ Event pool */
+       INIT_LIST_HEAD(&phba->sli4_hba.sp_cqe_event_pool);
+       /* Response IOCB work queue list */
+       INIT_LIST_HEAD(&phba->sli4_hba.sp_rspiocb_work_queue);
+       /* Asynchronous event CQ Event work queue list */
+       INIT_LIST_HEAD(&phba->sli4_hba.sp_asynce_work_queue);
+       /* Fast-path XRI aborted CQ Event work queue list */
+       INIT_LIST_HEAD(&phba->sli4_hba.sp_fcp_xri_aborted_work_queue);
+       /* Slow-path XRI aborted CQ Event work queue list */
+       INIT_LIST_HEAD(&phba->sli4_hba.sp_els_xri_aborted_work_queue);
+       /* Receive queue CQ Event work queue list */
+       INIT_LIST_HEAD(&phba->sli4_hba.sp_unsol_work_queue);
+
+       /* Initialize the driver internal SLI layer lists. */
        lpfc_sli_setup(phba);
        lpfc_sli_queue_setup(phba);
 
-       retval = lpfc_mem_alloc(phba);
-       if (retval) {
-               error = retval;
-               goto out_free_hbqslimp;
-       }
+       /* Allocate device driver memory */
+       rc = lpfc_mem_alloc(phba, SGL_ALIGN_SZ);
+       if (rc)
+               return -ENOMEM;
 
-       /* Initialize and populate the iocb list per host.  */
-       INIT_LIST_HEAD(&phba->lpfc_iocb_list);
-       for (i = 0; i < LPFC_IOCB_LIST_CNT; i++) {
-               iocbq_entry = kzalloc(sizeof(struct lpfc_iocbq), GFP_KERNEL);
-               if (iocbq_entry == NULL) {
-                       printk(KERN_ERR "%s: only allocated %d iocbs of "
-                               "expected %d count. Unloading driver.\n",
-                               __func__, i, LPFC_IOCB_LIST_CNT);
-                       error = -ENOMEM;
-                       goto out_free_iocbq;
-               }
+       /* Create the bootstrap mailbox command */
+       rc = lpfc_create_bootstrap_mbox(phba);
+       if (unlikely(rc))
+               goto out_free_mem;
 
-               iotag = lpfc_sli_next_iotag(phba, iocbq_entry);
-               if (iotag == 0) {
-                       kfree (iocbq_entry);
-                       printk(KERN_ERR "%s: failed to allocate IOTAG. "
-                              "Unloading driver.\n",
-                               __func__);
-                       error = -ENOMEM;
-                       goto out_free_iocbq;
-               }
+       /* Set up the host's endian order with the device. */
+       rc = lpfc_setup_endian_order(phba);
+       if (unlikely(rc))
+               goto out_free_bsmbx;
 
-               spin_lock_irq(&phba->hbalock);
-               list_add(&iocbq_entry->list, &phba->lpfc_iocb_list);
-               phba->total_iocbq_bufs++;
-               spin_unlock_irq(&phba->hbalock);
-       }
+       /* Set up the hba's configuration parameters. */
+       rc = lpfc_sli4_read_config(phba);
+       if (unlikely(rc))
+               goto out_free_bsmbx;
 
-       /* Initialize HBA structure */
-       phba->fc_edtov = FF_DEF_EDTOV;
-       phba->fc_ratov = FF_DEF_RATOV;
-       phba->fc_altov = FF_DEF_ALTOV;
-       phba->fc_arbtov = FF_DEF_ARBTOV;
+       /* Perform a function reset */
+       rc = lpfc_pci_function_reset(phba);
+       if (unlikely(rc))
+               goto out_free_bsmbx;
 
-       INIT_LIST_HEAD(&phba->work_list);
-       phba->work_ha_mask = (HA_ERATT | HA_MBATT | HA_LATT);
-       phba->work_ha_mask |= (HA_RXMASK << (LPFC_ELS_RING * 4));
+       /* Create all the SLI4 queues */
+       rc = lpfc_sli4_queue_create(phba);
+       if (rc)
+               goto out_free_bsmbx;
 
-       /* Initialize the wait queue head for the kernel thread */
-       init_waitqueue_head(&phba->work_waitq);
+       /* Create driver internal CQE event pool */
+       rc = lpfc_sli4_cq_event_pool_create(phba);
+       if (rc)
+               goto out_destroy_queue;
 
-       /* Startup the kernel thread for this host adapter. */
-       phba->worker_thread = kthread_run(lpfc_do_work, phba,
-                                      "lpfc_worker_%d", phba->brd_no);
-       if (IS_ERR(phba->worker_thread)) {
-               error = PTR_ERR(phba->worker_thread);
-               goto out_free_iocbq;
+       /* Initialize and populate the iocb list per host */
+       rc = lpfc_init_sgl_list(phba);
+       if (rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1400 Failed to initialize sgl list.\n");
+               goto out_destroy_cq_event_pool;
+       }
+       rc = lpfc_init_active_sgl_array(phba);
+       if (rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1430 Failed to initialize sgl list.\n");
+               goto out_free_sgl_list;
        }
 
-       /* Initialize the list of scsi buffers used by driver for scsi IO. */
-       spin_lock_init(&phba->scsi_buf_list_lock);
-       INIT_LIST_HEAD(&phba->lpfc_scsi_buf_list);
+       rc = lpfc_sli4_init_rpi_hdrs(phba);
+       if (rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1432 Failed to initialize rpi headers.\n");
+               goto out_free_active_sgl;
+       }
 
-       /* Initialize list of fabric iocbs */
-       INIT_LIST_HEAD(&phba->fabric_iocb_list);
+       phba->sli4_hba.fcp_eq_hdl = kzalloc((sizeof(struct lpfc_fcp_eq_hdl) *
+                                   phba->cfg_fcp_eq_count), GFP_KERNEL);
+       if (!phba->sli4_hba.fcp_eq_hdl) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2572 Failed allocate memory for fast-path "
+                               "per-EQ handle array\n");
+               goto out_remove_rpi_hdrs;
+       }
 
-       /* Initialize list to save ELS buffers */
-       INIT_LIST_HEAD(&phba->elsbuf);
+       phba->sli4_hba.msix_entries = kzalloc((sizeof(struct msix_entry) *
+                                     phba->sli4_hba.cfg_eqn), GFP_KERNEL);
+       if (!phba->sli4_hba.msix_entries) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2573 Failed allocate memory for msi-x "
+                               "interrupt vector entries\n");
+               goto out_free_fcp_eq_hdl;
+       }
 
-       vport = lpfc_create_port(phba, phba->brd_no, &phba->pcidev->dev);
-       if (!vport)
-               goto out_kthread_stop;
+       return rc;
 
-       shost = lpfc_shost_from_vport(vport);
-       phba->pport = vport;
-       lpfc_debugfs_initialize(vport);
+out_free_fcp_eq_hdl:
+       kfree(phba->sli4_hba.fcp_eq_hdl);
+out_remove_rpi_hdrs:
+       lpfc_sli4_remove_rpi_hdrs(phba);
+out_free_active_sgl:
+       lpfc_free_active_sgl(phba);
+out_free_sgl_list:
+       lpfc_free_sgl_list(phba);
+out_destroy_cq_event_pool:
+       lpfc_sli4_cq_event_pool_destroy(phba);
+out_destroy_queue:
+       lpfc_sli4_queue_destroy(phba);
+out_free_bsmbx:
+       lpfc_destroy_bootstrap_mbox(phba);
+out_free_mem:
+       lpfc_mem_free(phba);
+       return rc;
+}
 
-       pci_set_drvdata(pdev, shost);
+/**
+ * lpfc_sli4_driver_resource_unset - Unset drvr internal resources for SLI4 dev
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to unset the driver internal resources set up
+ * specific for supporting the SLI-4 HBA device it attached to.
+ **/
+static void
+lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba)
+{
+       struct lpfc_fcf_conn_entry *conn_entry, *next_conn_entry;
 
-       phba->MBslimaddr = phba->slim_memmap_p;
-       phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET;
-       phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET;
-       phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
-       phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
+       /* unregister default FCFI from the HBA */
+       lpfc_sli4_fcfi_unreg(phba, phba->fcf.fcfi);
 
-       /* Configure sysfs attributes */
-       if (lpfc_alloc_sysfs_attr(vport)) {
-               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                               "1476 Failed to allocate sysfs attr\n");
-               error = -ENOMEM;
-               goto out_destroy_port;
-       }
+       /* Free the default FCR table */
+       lpfc_sli_remove_dflt_fcf(phba);
 
-       cfg_mode = phba->cfg_use_msi;
-       while (true) {
-               /* Configure and enable interrupt */
-               intr_mode = lpfc_enable_intr(phba, cfg_mode);
-               if (intr_mode == LPFC_INTR_ERROR) {
-                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                                       "0426 Failed to enable interrupt.\n");
-                       goto out_free_sysfs_attr;
-               }
-               /* HBA SLI setup */
-               if (lpfc_sli_hba_setup(phba)) {
-                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                                       "1477 Failed to set up hba\n");
-                       error = -ENODEV;
-                       goto out_remove_device;
-               }
+       /* Free memory allocated for msi-x interrupt vector entries */
+       kfree(phba->sli4_hba.msix_entries);
 
-               /* Wait 50ms for the interrupts of previous mailbox commands */
-               msleep(50);
-               /* Check active interrupts received */
-               if (phba->sli.slistat.sli_intr > LPFC_MSIX_VECTORS) {
-                       /* Log the current active interrupt mode */
-                       phba->intr_mode = intr_mode;
-                       lpfc_log_intr_mode(phba, intr_mode);
-                       break;
-               } else {
-                       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-                                       "0451 Configure interrupt mode (%d) "
-                                       "failed active interrupt test.\n",
-                                       intr_mode);
-                       if (intr_mode == 0) {
-                               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                                               "0479 Failed to enable "
-                                               "interrupt.\n");
-                               error = -ENODEV;
-                               goto out_remove_device;
-                       }
-                       /* Stop HBA SLI setups */
-                       lpfc_stop_port(phba);
-                       /* Disable the current interrupt mode */
-                       lpfc_disable_intr(phba);
-                       /* Try next level of interrupt mode */
-                       cfg_mode = --intr_mode;
-               }
+       /* Free memory allocated for fast-path work queue handles */
+       kfree(phba->sli4_hba.fcp_eq_hdl);
+
+       /* Free the allocated rpi headers. */
+       lpfc_sli4_remove_rpi_hdrs(phba);
+
+       /* Free the ELS sgl list */
+       lpfc_free_active_sgl(phba);
+       lpfc_free_sgl_list(phba);
+
+       /* Free the SCSI sgl management array */
+       kfree(phba->sli4_hba.lpfc_scsi_psb_array);
+
+       /* Free the SLI4 queues */
+       lpfc_sli4_queue_destroy(phba);
+
+       /* Free the completion queue EQ event pool */
+       lpfc_sli4_cq_event_release_all(phba);
+       lpfc_sli4_cq_event_pool_destroy(phba);
+
+       /* Reset SLI4 HBA FCoE function */
+       lpfc_pci_function_reset(phba);
+
+       /* Free the bsmbx region. */
+       lpfc_destroy_bootstrap_mbox(phba);
+
+       /* Free the SLI Layer memory with SLI4 HBAs */
+       lpfc_mem_free_all(phba);
+
+       /* Free the current connect table */
+       list_for_each_entry_safe(conn_entry, next_conn_entry,
+               &phba->fcf_conn_rec_list, list)
+               kfree(conn_entry);
+
+       return;
+}
+
+/**
+ * lpfc_init_api_table_setup - Set up init api fucntion jump table
+ * @phba: The hba struct for which this call is being executed.
+ * @dev_grp: The HBA PCI-Device group number.
+ *
+ * This routine sets up the device INIT interface API function jump table
+ * in @phba struct.
+ *
+ * Returns: 0 - success, -ENODEV - failure.
+ **/
+int
+lpfc_init_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
+{
+       switch (dev_grp) {
+       case LPFC_PCI_DEV_LP:
+               phba->lpfc_hba_down_post = lpfc_hba_down_post_s3;
+               phba->lpfc_handle_eratt = lpfc_handle_eratt_s3;
+               phba->lpfc_stop_port = lpfc_stop_port_s3;
+               break;
+       case LPFC_PCI_DEV_OC:
+               phba->lpfc_hba_down_post = lpfc_hba_down_post_s4;
+               phba->lpfc_handle_eratt = lpfc_handle_eratt_s4;
+               phba->lpfc_stop_port = lpfc_stop_port_s4;
+               break;
+       default:
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1431 Invalid HBA PCI-device group: 0x%x\n",
+                               dev_grp);
+               return -ENODEV;
+               break;
        }
+       return 0;
+}
 
+/**
+ * lpfc_setup_driver_resource_phase1 - Phase1 etup driver internal resources.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to set up the driver internal resources before the
+ * device specific resource setup to support the HBA device it attached to.
+ *
+ * Return codes
+ *     0 - sucessful
+ *     other values - error
+ **/
+static int
+lpfc_setup_driver_resource_phase1(struct lpfc_hba *phba)
+{
        /*
-        * hba setup may have changed the hba_queue_depth so we need to adjust
-        * the value of can_queue.
+        * Driver resources common to all SLI revisions
         */
-       shost->can_queue = phba->cfg_hba_queue_depth - 10;
-       if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) {
+       atomic_set(&phba->fast_event_count, 0);
+       spin_lock_init(&phba->hbalock);
 
-               if (lpfc_prot_mask && lpfc_prot_guard) {
-                       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-                                       "1478 Registering BlockGuard with the "
-                                       "SCSI layer\n");
+       /* Initialize ndlp management spinlock */
+       spin_lock_init(&phba->ndlp_lock);
 
-                       scsi_host_set_prot(shost, lpfc_prot_mask);
-                       scsi_host_set_guard(shost, lpfc_prot_guard);
-               }
+       INIT_LIST_HEAD(&phba->port_list);
+       INIT_LIST_HEAD(&phba->work_list);
+       init_waitqueue_head(&phba->wait_4_mlo_m_q);
+
+       /* Initialize the wait queue head for the kernel thread */
+       init_waitqueue_head(&phba->work_waitq);
+
+       /* Initialize the scsi buffer list used by driver for scsi IO */
+       spin_lock_init(&phba->scsi_buf_list_lock);
+       INIT_LIST_HEAD(&phba->lpfc_scsi_buf_list);
+
+       /* Initialize the fabric iocb list */
+       INIT_LIST_HEAD(&phba->fabric_iocb_list);
+
+       /* Initialize list to save ELS buffers */
+       INIT_LIST_HEAD(&phba->elsbuf);
+
+       /* Initialize FCF connection rec list */
+       INIT_LIST_HEAD(&phba->fcf_conn_rec_list);
+
+       return 0;
+}
+
+/**
+ * lpfc_setup_driver_resource_phase2 - Phase2 setup driver internal resources.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to set up the driver internal resources after the
+ * device specific resource setup to support the HBA device it attached to.
+ *
+ * Return codes
+ *     0 - sucessful
+ *     other values - error
+ **/
+static int
+lpfc_setup_driver_resource_phase2(struct lpfc_hba *phba)
+{
+       int error;
+
+       /* Startup the kernel thread for this host adapter. */
+       phba->worker_thread = kthread_run(lpfc_do_work, phba,
+                                         "lpfc_worker_%d", phba->brd_no);
+       if (IS_ERR(phba->worker_thread)) {
+               error = PTR_ERR(phba->worker_thread);
+               return error;
        }
 
-       if (!_dump_buf_data) {
-               int pagecnt = 10;
-               while (pagecnt) {
-                       spin_lock_init(&_dump_buf_lock);
-                       _dump_buf_data =
-                               (char *) __get_free_pages(GFP_KERNEL, pagecnt);
-                       if (_dump_buf_data) {
-                               printk(KERN_ERR "BLKGRD allocated %d pages for "
-                                               "_dump_buf_data at 0x%p\n",
-                                               (1 << pagecnt), _dump_buf_data);
-                               _dump_buf_data_order = pagecnt;
-                               memset(_dump_buf_data, 0, ((1 << PAGE_SHIFT)
-                                                          << pagecnt));
-                               break;
-                       } else {
-                               --pagecnt;
-                       }
+       return 0;
+}
 
-               }
+/**
+ * lpfc_unset_driver_resource_phase2 - Phase2 unset driver internal resources.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to unset the driver internal resources set up after
+ * the device specific resource setup for supporting the HBA device it
+ * attached to.
+ **/
+static void
+lpfc_unset_driver_resource_phase2(struct lpfc_hba *phba)
+{
+       /* Stop kernel worker thread */
+       kthread_stop(phba->worker_thread);
+}
 
-               if (!_dump_buf_data_order)
-                       printk(KERN_ERR "BLKGRD ERROR unable to allocate "
-                                       "memory for hexdump\n");
+/**
+ * lpfc_free_iocb_list - Free iocb list.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to free the driver's IOCB list and memory.
+ **/
+static void
+lpfc_free_iocb_list(struct lpfc_hba *phba)
+{
+       struct lpfc_iocbq *iocbq_entry = NULL, *iocbq_next = NULL;
 
-       } else {
-               printk(KERN_ERR "BLKGRD already allocated _dump_buf_data=0x%p"
-                      "\n", _dump_buf_data);
+       spin_lock_irq(&phba->hbalock);
+       list_for_each_entry_safe(iocbq_entry, iocbq_next,
+                                &phba->lpfc_iocb_list, list) {
+               list_del(&iocbq_entry->list);
+               kfree(iocbq_entry);
+               phba->total_iocbq_bufs--;
        }
+       spin_unlock_irq(&phba->hbalock);
 
+       return;
+}
 
-       if (!_dump_buf_dif) {
-               int pagecnt = 10;
-               while (pagecnt) {
-                       _dump_buf_dif =
-                               (char *) __get_free_pages(GFP_KERNEL, pagecnt);
-                       if (_dump_buf_dif) {
-                               printk(KERN_ERR "BLKGRD allocated %d pages for "
-                                               "_dump_buf_dif at 0x%p\n",
-                                               (1 << pagecnt), _dump_buf_dif);
-                               _dump_buf_dif_order = pagecnt;
-                               memset(_dump_buf_dif, 0, ((1 << PAGE_SHIFT)
-                                                         << pagecnt));
-                               break;
-                       } else {
-                               --pagecnt;
-                       }
+/**
+ * lpfc_init_iocb_list - Allocate and initialize iocb list.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to allocate and initizlize the driver's IOCB
+ * list and set up the IOCB tag array accordingly.
+ *
+ * Return codes
+ *     0 - sucessful
+ *     other values - error
+ **/
+static int
+lpfc_init_iocb_list(struct lpfc_hba *phba, int iocb_count)
+{
+       struct lpfc_iocbq *iocbq_entry = NULL;
+       uint16_t iotag;
+       int i;
 
+       /* Initialize and populate the iocb list per host.  */
+       INIT_LIST_HEAD(&phba->lpfc_iocb_list);
+       for (i = 0; i < iocb_count; i++) {
+               iocbq_entry = kzalloc(sizeof(struct lpfc_iocbq), GFP_KERNEL);
+               if (iocbq_entry == NULL) {
+                       printk(KERN_ERR "%s: only allocated %d iocbs of "
+                               "expected %d count. Unloading driver.\n",
+                               __func__, i, LPFC_IOCB_LIST_CNT);
+                       goto out_free_iocbq;
                }
 
-               if (!_dump_buf_dif_order)
-                       printk(KERN_ERR "BLKGRD ERROR unable to allocate "
-                                       "memory for hexdump\n");
+               iotag = lpfc_sli_next_iotag(phba, iocbq_entry);
+               if (iotag == 0) {
+                       kfree(iocbq_entry);
+                       printk(KERN_ERR "%s: failed to allocate IOTAG. "
+                               "Unloading driver.\n", __func__);
+                       goto out_free_iocbq;
+               }
+               iocbq_entry->sli4_xritag = NO_XRI;
 
-       } else {
-               printk(KERN_ERR "BLKGRD already allocated _dump_buf_dif=0x%p\n",
-                               _dump_buf_dif);
+               spin_lock_irq(&phba->hbalock);
+               list_add(&iocbq_entry->list, &phba->lpfc_iocb_list);
+               phba->total_iocbq_bufs++;
+               spin_unlock_irq(&phba->hbalock);
        }
 
-       lpfc_host_attrib_init(shost);
+       return 0;
 
-       if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
-               spin_lock_irq(shost->host_lock);
-               lpfc_poll_start_timer(phba);
-               spin_unlock_irq(shost->host_lock);
+out_free_iocbq:
+       lpfc_free_iocb_list(phba);
+
+       return -ENOMEM;
+}
+
+/**
+ * lpfc_free_sgl_list - Free sgl list.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to free the driver's sgl list and memory.
+ **/
+static void
+lpfc_free_sgl_list(struct lpfc_hba *phba)
+{
+       struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL;
+       LIST_HEAD(sglq_list);
+       int rc = 0;
+
+       spin_lock_irq(&phba->hbalock);
+       list_splice_init(&phba->sli4_hba.lpfc_sgl_list, &sglq_list);
+       spin_unlock_irq(&phba->hbalock);
+
+       list_for_each_entry_safe(sglq_entry, sglq_next,
+                                &sglq_list, list) {
+               list_del(&sglq_entry->list);
+               lpfc_mbuf_free(phba, sglq_entry->virt, sglq_entry->phys);
+               kfree(sglq_entry);
+               phba->sli4_hba.total_sglq_bufs--;
+       }
+       rc = lpfc_sli4_remove_all_sgl_pages(phba);
+       if (rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                       "2005 Unable to deregister pages from HBA: %x", rc);
        }
+       kfree(phba->sli4_hba.lpfc_els_sgl_array);
+}
 
-       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-                       "0428 Perform SCSI scan\n");
-       /* Send board arrival event to upper layer */
-       adapter_event.event_type = FC_REG_ADAPTER_EVENT;
-       adapter_event.subcategory = LPFC_EVENT_ARRIVAL;
-       fc_host_post_vendor_event(shost, fc_get_event_number(),
-               sizeof(adapter_event),
-               (char *) &adapter_event,
-               LPFC_NL_VENDOR_ID);
+/**
+ * lpfc_init_active_sgl_array - Allocate the buf to track active ELS XRIs.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to allocate the driver's active sgl memory.
+ * This array will hold the sglq_entry's for active IOs.
+ **/
+static int
+lpfc_init_active_sgl_array(struct lpfc_hba *phba)
+{
+       int size;
+       size = sizeof(struct lpfc_sglq *);
+       size *= phba->sli4_hba.max_cfg_param.max_xri;
 
+       phba->sli4_hba.lpfc_sglq_active_list =
+               kzalloc(size, GFP_KERNEL);
+       if (!phba->sli4_hba.lpfc_sglq_active_list)
+               return -ENOMEM;
        return 0;
+}
+
+/**
+ * lpfc_free_active_sgl - Free the buf that tracks active ELS XRIs.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to walk through the array of active sglq entries
+ * and free all of the resources.
+ * This is just a place holder for now.
+ **/
+static void
+lpfc_free_active_sgl(struct lpfc_hba *phba)
+{
+       kfree(phba->sli4_hba.lpfc_sglq_active_list);
+}
+
+/**
+ * lpfc_init_sgl_list - Allocate and initialize sgl list.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to allocate and initizlize the driver's sgl
+ * list and set up the sgl xritag tag array accordingly.
+ *
+ * Return codes
+ *     0 - sucessful
+ *     other values - error
+ **/
+static int
+lpfc_init_sgl_list(struct lpfc_hba *phba)
+{
+       struct lpfc_sglq *sglq_entry = NULL;
+       int i;
+       int els_xri_cnt;
+
+       els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba);
+       lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+                               "2400 lpfc_init_sgl_list els %d.\n",
+                               els_xri_cnt);
+       /* Initialize and populate the sglq list per host/VF. */
+       INIT_LIST_HEAD(&phba->sli4_hba.lpfc_sgl_list);
+       INIT_LIST_HEAD(&phba->sli4_hba.lpfc_abts_els_sgl_list);
+
+       /* Sanity check on XRI management */
+       if (phba->sli4_hba.max_cfg_param.max_xri <= els_xri_cnt) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "2562 No room left for SCSI XRI allocation: "
+                               "max_xri=%d, els_xri=%d\n",
+                               phba->sli4_hba.max_cfg_param.max_xri,
+                               els_xri_cnt);
+               return -ENOMEM;
+       }
+
+       /* Allocate memory for the ELS XRI management array */
+       phba->sli4_hba.lpfc_els_sgl_array =
+                       kzalloc((sizeof(struct lpfc_sglq *) * els_xri_cnt),
+                       GFP_KERNEL);
+
+       if (!phba->sli4_hba.lpfc_els_sgl_array) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "2401 Failed to allocate memory for ELS "
+                               "XRI management array of size %d.\n",
+                               els_xri_cnt);
+               return -ENOMEM;
+       }
+
+       /* Keep the SCSI XRI into the XRI management array */
+       phba->sli4_hba.scsi_xri_max =
+                       phba->sli4_hba.max_cfg_param.max_xri - els_xri_cnt;
+       phba->sli4_hba.scsi_xri_cnt = 0;
+
+       phba->sli4_hba.lpfc_scsi_psb_array =
+                       kzalloc((sizeof(struct lpfc_scsi_buf *) *
+                       phba->sli4_hba.scsi_xri_max), GFP_KERNEL);
+
+       if (!phba->sli4_hba.lpfc_scsi_psb_array) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "2563 Failed to allocate memory for SCSI "
+                               "XRI management array of size %d.\n",
+                               phba->sli4_hba.scsi_xri_max);
+               kfree(phba->sli4_hba.lpfc_els_sgl_array);
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < els_xri_cnt; i++) {
+               sglq_entry = kzalloc(sizeof(struct lpfc_sglq), GFP_KERNEL);
+               if (sglq_entry == NULL) {
+                       printk(KERN_ERR "%s: only allocated %d sgls of "
+                               "expected %d count. Unloading driver.\n",
+                               __func__, i, els_xri_cnt);
+                       goto out_free_mem;
+               }
+
+               sglq_entry->sli4_xritag = lpfc_sli4_next_xritag(phba);
+               if (sglq_entry->sli4_xritag == NO_XRI) {
+                       kfree(sglq_entry);
+                       printk(KERN_ERR "%s: failed to allocate XRI.\n"
+                               "Unloading driver.\n", __func__);
+                       goto out_free_mem;
+               }
+               sglq_entry->buff_type = GEN_BUFF_TYPE;
+               sglq_entry->virt = lpfc_mbuf_alloc(phba, 0, &sglq_entry->phys);
+               if (sglq_entry->virt == NULL) {
+                       kfree(sglq_entry);
+                       printk(KERN_ERR "%s: failed to allocate mbuf.\n"
+                               "Unloading driver.\n", __func__);
+                       goto out_free_mem;
+               }
+               sglq_entry->sgl = sglq_entry->virt;
+               memset(sglq_entry->sgl, 0, LPFC_BPL_SIZE);
+
+               /* The list order is used by later block SGL registraton */
+               spin_lock_irq(&phba->hbalock);
+               list_add_tail(&sglq_entry->list, &phba->sli4_hba.lpfc_sgl_list);
+               phba->sli4_hba.lpfc_els_sgl_array[i] = sglq_entry;
+               phba->sli4_hba.total_sglq_bufs++;
+               spin_unlock_irq(&phba->hbalock);
+       }
+       return 0;
+
+out_free_mem:
+       kfree(phba->sli4_hba.lpfc_scsi_psb_array);
+       lpfc_free_sgl_list(phba);
+       return -ENOMEM;
+}
+
+/**
+ * lpfc_sli4_init_rpi_hdrs - Post the rpi header memory region to the port
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to post rpi header templates to the
+ * HBA consistent with the SLI-4 interface spec.  This routine
+ * posts a PAGE_SIZE memory region to the port to hold up to
+ * PAGE_SIZE modulo 64 rpi context headers.
+ * No locks are held here because this is an initialization routine
+ * called only from probe or lpfc_online when interrupts are not
+ * enabled and the driver is reinitializing the device.
+ *
+ * Return codes
+ *     0 - sucessful
+ *     ENOMEM - No availble memory
+ *      EIO - The mailbox failed to complete successfully.
+ **/
+int
+lpfc_sli4_init_rpi_hdrs(struct lpfc_hba *phba)
+{
+       int rc = 0;
+       int longs;
+       uint16_t rpi_count;
+       struct lpfc_rpi_hdr *rpi_hdr;
+
+       INIT_LIST_HEAD(&phba->sli4_hba.lpfc_rpi_hdr_list);
+
+       /*
+        * Provision an rpi bitmask range for discovery. The total count
+        * is the difference between max and base + 1.
+        */
+       rpi_count = phba->sli4_hba.max_cfg_param.rpi_base +
+                   phba->sli4_hba.max_cfg_param.max_rpi - 1;
+
+       longs = ((rpi_count) + BITS_PER_LONG - 1) / BITS_PER_LONG;
+       phba->sli4_hba.rpi_bmask = kzalloc(longs * sizeof(unsigned long),
+                                          GFP_KERNEL);
+       if (!phba->sli4_hba.rpi_bmask)
+               return -ENOMEM;
+
+       rpi_hdr = lpfc_sli4_create_rpi_hdr(phba);
+       if (!rpi_hdr) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                               "0391 Error during rpi post operation\n");
+               lpfc_sli4_remove_rpis(phba);
+               rc = -ENODEV;
+       }
+
+       return rc;
+}
+
+/**
+ * lpfc_sli4_create_rpi_hdr - Allocate an rpi header memory region
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to allocate a single 4KB memory region to
+ * support rpis and stores them in the phba.  This single region
+ * provides support for up to 64 rpis.  The region is used globally
+ * by the device.
+ *
+ * Returns:
+ *   A valid rpi hdr on success.
+ *   A NULL pointer on any failure.
+ **/
+struct lpfc_rpi_hdr *
+lpfc_sli4_create_rpi_hdr(struct lpfc_hba *phba)
+{
+       uint16_t rpi_limit, curr_rpi_range;
+       struct lpfc_dmabuf *dmabuf;
+       struct lpfc_rpi_hdr *rpi_hdr;
+
+       rpi_limit = phba->sli4_hba.max_cfg_param.rpi_base +
+                   phba->sli4_hba.max_cfg_param.max_rpi - 1;
+
+       spin_lock_irq(&phba->hbalock);
+       curr_rpi_range = phba->sli4_hba.next_rpi;
+       spin_unlock_irq(&phba->hbalock);
+
+       /*
+        * The port has a limited number of rpis. The increment here
+        * is LPFC_RPI_HDR_COUNT - 1 to account for the starting value
+        * and to allow the full max_rpi range per port.
+        */
+       if ((curr_rpi_range + (LPFC_RPI_HDR_COUNT - 1)) > rpi_limit)
+               return NULL;
+
+       /*
+        * First allocate the protocol header region for the port.  The
+        * port expects a 4KB DMA-mapped memory region that is 4K aligned.
+        */
+       dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+       if (!dmabuf)
+               return NULL;
+
+       dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev,
+                                         LPFC_HDR_TEMPLATE_SIZE,
+                                         &dmabuf->phys,
+                                         GFP_KERNEL);
+       if (!dmabuf->virt) {
+               rpi_hdr = NULL;
+               goto err_free_dmabuf;
+       }
+
+       memset(dmabuf->virt, 0, LPFC_HDR_TEMPLATE_SIZE);
+       if (!IS_ALIGNED(dmabuf->phys, LPFC_HDR_TEMPLATE_SIZE)) {
+               rpi_hdr = NULL;
+               goto err_free_coherent;
+       }
+
+       /* Save the rpi header data for cleanup later. */
+       rpi_hdr = kzalloc(sizeof(struct lpfc_rpi_hdr), GFP_KERNEL);
+       if (!rpi_hdr)
+               goto err_free_coherent;
+
+       rpi_hdr->dmabuf = dmabuf;
+       rpi_hdr->len = LPFC_HDR_TEMPLATE_SIZE;
+       rpi_hdr->page_count = 1;
+       spin_lock_irq(&phba->hbalock);
+       rpi_hdr->start_rpi = phba->sli4_hba.next_rpi;
+       list_add_tail(&rpi_hdr->list, &phba->sli4_hba.lpfc_rpi_hdr_list);
+
+       /*
+        * The next_rpi stores the next module-64 rpi value to post
+        * in any subsequent rpi memory region postings.
+        */
+       phba->sli4_hba.next_rpi += LPFC_RPI_HDR_COUNT;
+       spin_unlock_irq(&phba->hbalock);
+       return rpi_hdr;
+
+ err_free_coherent:
+       dma_free_coherent(&phba->pcidev->dev, LPFC_HDR_TEMPLATE_SIZE,
+                         dmabuf->virt, dmabuf->phys);
+ err_free_dmabuf:
+       kfree(dmabuf);
+       return NULL;
+}
+
+/**
+ * lpfc_sli4_remove_rpi_hdrs - Remove all rpi header memory regions
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to remove all memory resources allocated
+ * to support rpis. This routine presumes the caller has released all
+ * rpis consumed by fabric or port logins and is prepared to have
+ * the header pages removed.
+ **/
+void
+lpfc_sli4_remove_rpi_hdrs(struct lpfc_hba *phba)
+{
+       struct lpfc_rpi_hdr *rpi_hdr, *next_rpi_hdr;
+
+       list_for_each_entry_safe(rpi_hdr, next_rpi_hdr,
+                                &phba->sli4_hba.lpfc_rpi_hdr_list, list) {
+               list_del(&rpi_hdr->list);
+               dma_free_coherent(&phba->pcidev->dev, rpi_hdr->len,
+                                 rpi_hdr->dmabuf->virt, rpi_hdr->dmabuf->phys);
+               kfree(rpi_hdr->dmabuf);
+               kfree(rpi_hdr);
+       }
+
+       phba->sli4_hba.next_rpi = phba->sli4_hba.max_cfg_param.rpi_base;
+       memset(phba->sli4_hba.rpi_bmask, 0, sizeof(*phba->sli4_hba.rpi_bmask));
+}
+
+/**
+ * lpfc_hba_alloc - Allocate driver hba data structure for a device.
+ * @pdev: pointer to pci device data structure.
+ *
+ * This routine is invoked to allocate the driver hba data structure for an
+ * HBA device. If the allocation is successful, the phba reference to the
+ * PCI device data structure is set.
+ *
+ * Return codes
+ *      pointer to @phba - sucessful
+ *      NULL - error
+ **/
+static struct lpfc_hba *
+lpfc_hba_alloc(struct pci_dev *pdev)
+{
+       struct lpfc_hba *phba;
+
+       /* Allocate memory for HBA structure */
+       phba = kzalloc(sizeof(struct lpfc_hba), GFP_KERNEL);
+       if (!phba) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1417 Failed to allocate hba struct.\n");
+               return NULL;
+       }
+
+       /* Set reference to PCI device in HBA structure */
+       phba->pcidev = pdev;
+
+       /* Assign an unused board number */
+       phba->brd_no = lpfc_get_instance();
+       if (phba->brd_no < 0) {
+               kfree(phba);
+               return NULL;
+       }
+
+       return phba;
+}
+
+/**
+ * lpfc_hba_free - Free driver hba data structure with a device.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to free the driver hba data structure with an
+ * HBA device.
+ **/
+static void
+lpfc_hba_free(struct lpfc_hba *phba)
+{
+       /* Release the driver assigned board number */
+       idr_remove(&lpfc_hba_index, phba->brd_no);
+
+       kfree(phba);
+       return;
+}
+
+/**
+ * lpfc_create_shost - Create hba physical port with associated scsi host.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to create HBA physical port and associate a SCSI
+ * host with it.
+ *
+ * Return codes
+ *      0 - sucessful
+ *      other values - error
+ **/
+static int
+lpfc_create_shost(struct lpfc_hba *phba)
+{
+       struct lpfc_vport *vport;
+       struct Scsi_Host  *shost;
+
+       /* Initialize HBA FC structure */
+       phba->fc_edtov = FF_DEF_EDTOV;
+       phba->fc_ratov = FF_DEF_RATOV;
+       phba->fc_altov = FF_DEF_ALTOV;
+       phba->fc_arbtov = FF_DEF_ARBTOV;
+
+       vport = lpfc_create_port(phba, phba->brd_no, &phba->pcidev->dev);
+       if (!vport)
+               return -ENODEV;
+
+       shost = lpfc_shost_from_vport(vport);
+       phba->pport = vport;
+       lpfc_debugfs_initialize(vport);
+       /* Put reference to SCSI host to driver's device private data */
+       pci_set_drvdata(phba->pcidev, shost);
+
+       return 0;
+}
+
+/**
+ * lpfc_destroy_shost - Destroy hba physical port with associated scsi host.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to destroy HBA physical port and the associated
+ * SCSI host.
+ **/
+static void
+lpfc_destroy_shost(struct lpfc_hba *phba)
+{
+       struct lpfc_vport *vport = phba->pport;
+
+       /* Destroy physical port that associated with the SCSI host */
+       destroy_port(vport);
+
+       return;
+}
+
+/**
+ * lpfc_setup_bg - Setup Block guard structures and debug areas.
+ * @phba: pointer to lpfc hba data structure.
+ * @shost: the shost to be used to detect Block guard settings.
+ *
+ * This routine sets up the local Block guard protocol settings for @shost.
+ * This routine also allocates memory for debugging bg buffers.
+ **/
+static void
+lpfc_setup_bg(struct lpfc_hba *phba, struct Scsi_Host *shost)
+{
+       int pagecnt = 10;
+       if (lpfc_prot_mask && lpfc_prot_guard) {
+               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                               "1478 Registering BlockGuard with the "
+                               "SCSI layer\n");
+               scsi_host_set_prot(shost, lpfc_prot_mask);
+               scsi_host_set_guard(shost, lpfc_prot_guard);
+       }
+       if (!_dump_buf_data) {
+               while (pagecnt) {
+                       spin_lock_init(&_dump_buf_lock);
+                       _dump_buf_data =
+                               (char *) __get_free_pages(GFP_KERNEL, pagecnt);
+                       if (_dump_buf_data) {
+                               printk(KERN_ERR "BLKGRD allocated %d pages for "
+                                      "_dump_buf_data at 0x%p\n",
+                                      (1 << pagecnt), _dump_buf_data);
+                               _dump_buf_data_order = pagecnt;
+                               memset(_dump_buf_data, 0,
+                                      ((1 << PAGE_SHIFT) << pagecnt));
+                               break;
+                       } else
+                               --pagecnt;
+               }
+               if (!_dump_buf_data_order)
+                       printk(KERN_ERR "BLKGRD ERROR unable to allocate "
+                              "memory for hexdump\n");
+       } else
+               printk(KERN_ERR "BLKGRD already allocated _dump_buf_data=0x%p"
+                      "\n", _dump_buf_data);
+       if (!_dump_buf_dif) {
+               while (pagecnt) {
+                       _dump_buf_dif =
+                               (char *) __get_free_pages(GFP_KERNEL, pagecnt);
+                       if (_dump_buf_dif) {
+                               printk(KERN_ERR "BLKGRD allocated %d pages for "
+                                      "_dump_buf_dif at 0x%p\n",
+                                      (1 << pagecnt), _dump_buf_dif);
+                               _dump_buf_dif_order = pagecnt;
+                               memset(_dump_buf_dif, 0,
+                                      ((1 << PAGE_SHIFT) << pagecnt));
+                               break;
+                       } else
+                               --pagecnt;
+               }
+               if (!_dump_buf_dif_order)
+                       printk(KERN_ERR "BLKGRD ERROR unable to allocate "
+                              "memory for hexdump\n");
+       } else
+               printk(KERN_ERR "BLKGRD already allocated _dump_buf_dif=0x%p\n",
+                      _dump_buf_dif);
+}
+
+/**
+ * lpfc_post_init_setup - Perform necessary device post initialization setup.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to perform all the necessary post initialization
+ * setup for the device.
+ **/
+static void
+lpfc_post_init_setup(struct lpfc_hba *phba)
+{
+       struct Scsi_Host  *shost;
+       struct lpfc_adapter_event_header adapter_event;
+
+       /* Get the default values for Model Name and Description */
+       lpfc_get_hba_model_desc(phba, phba->ModelName, phba->ModelDesc);
+
+       /*
+        * hba setup may have changed the hba_queue_depth so we need to
+        * adjust the value of can_queue.
+        */
+       shost = pci_get_drvdata(phba->pcidev);
+       shost->can_queue = phba->cfg_hba_queue_depth - 10;
+       if (phba->sli3_options & LPFC_SLI3_BG_ENABLED)
+               lpfc_setup_bg(phba, shost);
+
+       lpfc_host_attrib_init(shost);
+
+       if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
+               spin_lock_irq(shost->host_lock);
+               lpfc_poll_start_timer(phba);
+               spin_unlock_irq(shost->host_lock);
+       }
+
+       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                       "0428 Perform SCSI scan\n");
+       /* Send board arrival event to upper layer */
+       adapter_event.event_type = FC_REG_ADAPTER_EVENT;
+       adapter_event.subcategory = LPFC_EVENT_ARRIVAL;
+       fc_host_post_vendor_event(shost, fc_get_event_number(),
+                                 sizeof(adapter_event),
+                                 (char *) &adapter_event,
+                                 LPFC_NL_VENDOR_ID);
+       return;
+}
+
+/**
+ * lpfc_sli_pci_mem_setup - Setup SLI3 HBA PCI memory space.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to set up the PCI device memory space for device
+ * with SLI-3 interface spec.
+ *
+ * Return codes
+ *     0 - sucessful
+ *     other values - error
+ **/
+static int
+lpfc_sli_pci_mem_setup(struct lpfc_hba *phba)
+{
+       struct pci_dev *pdev;
+       unsigned long bar0map_len, bar2map_len;
+       int i, hbq_count;
+       void *ptr;
+       int error = -ENODEV;
+
+       /* Obtain PCI device reference */
+       if (!phba->pcidev)
+               return error;
+       else
+               pdev = phba->pcidev;
+
+       /* Set the device DMA mask size */
+       if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0)
+               if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0)
+                       return error;
+
+       /* Get the bus address of Bar0 and Bar2 and the number of bytes
+        * required by each mapping.
+        */
+       phba->pci_bar0_map = pci_resource_start(pdev, 0);
+       bar0map_len = pci_resource_len(pdev, 0);
+
+       phba->pci_bar2_map = pci_resource_start(pdev, 2);
+       bar2map_len = pci_resource_len(pdev, 2);
+
+       /* Map HBA SLIM to a kernel virtual address. */
+       phba->slim_memmap_p = ioremap(phba->pci_bar0_map, bar0map_len);
+       if (!phba->slim_memmap_p) {
+               dev_printk(KERN_ERR, &pdev->dev,
+                          "ioremap failed for SLIM memory.\n");
+               goto out;
+       }
+
+       /* Map HBA Control Registers to a kernel virtual address. */
+       phba->ctrl_regs_memmap_p = ioremap(phba->pci_bar2_map, bar2map_len);
+       if (!phba->ctrl_regs_memmap_p) {
+               dev_printk(KERN_ERR, &pdev->dev,
+                          "ioremap failed for HBA control registers.\n");
+               goto out_iounmap_slim;
+       }
+
+       /* Allocate memory for SLI-2 structures */
+       phba->slim2p.virt = dma_alloc_coherent(&pdev->dev,
+                                              SLI2_SLIM_SIZE,
+                                              &phba->slim2p.phys,
+                                              GFP_KERNEL);
+       if (!phba->slim2p.virt)
+               goto out_iounmap;
+
+       memset(phba->slim2p.virt, 0, SLI2_SLIM_SIZE);
+       phba->mbox = phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, mbx);
+       phba->pcb = (phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, pcb));
+       phba->IOCBs = (phba->slim2p.virt +
+                      offsetof(struct lpfc_sli2_slim, IOCBs));
+
+       phba->hbqslimp.virt = dma_alloc_coherent(&pdev->dev,
+                                                lpfc_sli_hbq_size(),
+                                                &phba->hbqslimp.phys,
+                                                GFP_KERNEL);
+       if (!phba->hbqslimp.virt)
+               goto out_free_slim;
+
+       hbq_count = lpfc_sli_hbq_count();
+       ptr = phba->hbqslimp.virt;
+       for (i = 0; i < hbq_count; ++i) {
+               phba->hbqs[i].hbq_virt = ptr;
+               INIT_LIST_HEAD(&phba->hbqs[i].hbq_buffer_list);
+               ptr += (lpfc_hbq_defs[i]->entry_count *
+                       sizeof(struct lpfc_hbq_entry));
+       }
+       phba->hbqs[LPFC_ELS_HBQ].hbq_alloc_buffer = lpfc_els_hbq_alloc;
+       phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer = lpfc_els_hbq_free;
+
+       memset(phba->hbqslimp.virt, 0, lpfc_sli_hbq_size());
+
+       INIT_LIST_HEAD(&phba->rb_pend_list);
+
+       phba->MBslimaddr = phba->slim_memmap_p;
+       phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET;
+       phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET;
+       phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
+       phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
+
+       return 0;
+
+out_free_slim:
+       dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE,
+                         phba->slim2p.virt, phba->slim2p.phys);
+out_iounmap:
+       iounmap(phba->ctrl_regs_memmap_p);
+out_iounmap_slim:
+       iounmap(phba->slim_memmap_p);
+out:
+       return error;
+}
+
+/**
+ * lpfc_sli_pci_mem_unset - Unset SLI3 HBA PCI memory space.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to unset the PCI device memory space for device
+ * with SLI-3 interface spec.
+ **/
+static void
+lpfc_sli_pci_mem_unset(struct lpfc_hba *phba)
+{
+       struct pci_dev *pdev;
+
+       /* Obtain PCI device reference */
+       if (!phba->pcidev)
+               return;
+       else
+               pdev = phba->pcidev;
+
+       /* Free coherent DMA memory allocated */
+       dma_free_coherent(&pdev->dev, lpfc_sli_hbq_size(),
+                         phba->hbqslimp.virt, phba->hbqslimp.phys);
+       dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE,
+                         phba->slim2p.virt, phba->slim2p.phys);
+
+       /* I/O memory unmap */
+       iounmap(phba->ctrl_regs_memmap_p);
+       iounmap(phba->slim_memmap_p);
+
+       return;
+}
+
+/**
+ * lpfc_sli4_post_status_check - Wait for SLI4 POST done and check status
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to wait for SLI4 device Power On Self Test (POST)
+ * done and check status.
+ *
+ * Return 0 if successful, otherwise -ENODEV.
+ **/
+int
+lpfc_sli4_post_status_check(struct lpfc_hba *phba)
+{
+       struct lpfc_register sta_reg, uerrlo_reg, uerrhi_reg, scratchpad;
+       uint32_t onlnreg0, onlnreg1;
+       int i, port_error = -ENODEV;
+
+       if (!phba->sli4_hba.STAregaddr)
+               return -ENODEV;
+
+       /* With uncoverable error, log the error message and return error */
+       onlnreg0 = readl(phba->sli4_hba.ONLINE0regaddr);
+       onlnreg1 = readl(phba->sli4_hba.ONLINE1regaddr);
+       if ((onlnreg0 != LPFC_ONLINE_NERR) || (onlnreg1 != LPFC_ONLINE_NERR)) {
+               uerrlo_reg.word0 = readl(phba->sli4_hba.UERRLOregaddr);
+               uerrhi_reg.word0 = readl(phba->sli4_hba.UERRHIregaddr);
+               if (uerrlo_reg.word0 || uerrhi_reg.word0) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "1422 HBA Unrecoverable error: "
+                                       "uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, "
+                                       "online0_reg=0x%x, online1_reg=0x%x\n",
+                                       uerrlo_reg.word0, uerrhi_reg.word0,
+                                       onlnreg0, onlnreg1);
+               }
+               return -ENODEV;
+       }
+
+       /* Wait up to 30 seconds for the SLI Port POST done and ready */
+       for (i = 0; i < 3000; i++) {
+               sta_reg.word0 = readl(phba->sli4_hba.STAregaddr);
+               /* Encounter fatal POST error, break out */
+               if (bf_get(lpfc_hst_state_perr, &sta_reg)) {
+                       port_error = -ENODEV;
+                       break;
+               }
+               if (LPFC_POST_STAGE_ARMFW_READY ==
+                   bf_get(lpfc_hst_state_port_status, &sta_reg)) {
+                       port_error = 0;
+                       break;
+               }
+               msleep(10);
+       }
+
+       if (port_error)
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                       "1408 Failure HBA POST Status: sta_reg=0x%x, "
+                       "perr=x%x, sfi=x%x, nip=x%x, ipc=x%x, xrom=x%x, "
+                       "dl=x%x, pstatus=x%x\n", sta_reg.word0,
+                       bf_get(lpfc_hst_state_perr, &sta_reg),
+                       bf_get(lpfc_hst_state_sfi, &sta_reg),
+                       bf_get(lpfc_hst_state_nip, &sta_reg),
+                       bf_get(lpfc_hst_state_ipc, &sta_reg),
+                       bf_get(lpfc_hst_state_xrom, &sta_reg),
+                       bf_get(lpfc_hst_state_dl, &sta_reg),
+                       bf_get(lpfc_hst_state_port_status, &sta_reg));
+
+       /* Log device information */
+       scratchpad.word0 =  readl(phba->sli4_hba.SCRATCHPADregaddr);
+       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                       "2534 Device Info: ChipType=0x%x, SliRev=0x%x, "
+                       "FeatureL1=0x%x, FeatureL2=0x%x\n",
+                       bf_get(lpfc_scratchpad_chiptype, &scratchpad),
+                       bf_get(lpfc_scratchpad_slirev, &scratchpad),
+                       bf_get(lpfc_scratchpad_featurelevel1, &scratchpad),
+                       bf_get(lpfc_scratchpad_featurelevel2, &scratchpad));
+
+       return port_error;
+}
+
+/**
+ * lpfc_sli4_bar0_register_memmap - Set up SLI4 BAR0 register memory map.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to set up SLI4 BAR0 PCI config space register
+ * memory map.
+ **/
+static void
+lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba)
+{
+       phba->sli4_hba.UERRLOregaddr = phba->sli4_hba.conf_regs_memmap_p +
+                                       LPFC_UERR_STATUS_LO;
+       phba->sli4_hba.UERRHIregaddr = phba->sli4_hba.conf_regs_memmap_p +
+                                       LPFC_UERR_STATUS_HI;
+       phba->sli4_hba.ONLINE0regaddr = phba->sli4_hba.conf_regs_memmap_p +
+                                       LPFC_ONLINE0;
+       phba->sli4_hba.ONLINE1regaddr = phba->sli4_hba.conf_regs_memmap_p +
+                                       LPFC_ONLINE1;
+       phba->sli4_hba.SCRATCHPADregaddr = phba->sli4_hba.conf_regs_memmap_p +
+                                       LPFC_SCRATCHPAD;
+}
+
+/**
+ * lpfc_sli4_bar1_register_memmap - Set up SLI4 BAR1 register memory map.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to set up SLI4 BAR1 control status register (CSR)
+ * memory map.
+ **/
+static void
+lpfc_sli4_bar1_register_memmap(struct lpfc_hba *phba)
+{
+
+       phba->sli4_hba.STAregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
+                                   LPFC_HST_STATE;
+       phba->sli4_hba.ISRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
+                                   LPFC_HST_ISR0;
+       phba->sli4_hba.IMRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
+                                   LPFC_HST_IMR0;
+       phba->sli4_hba.ISCRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
+                                    LPFC_HST_ISCR0;
+       return;
+}
+
+/**
+ * lpfc_sli4_bar2_register_memmap - Set up SLI4 BAR2 register memory map.
+ * @phba: pointer to lpfc hba data structure.
+ * @vf: virtual function number
+ *
+ * This routine is invoked to set up SLI4 BAR2 doorbell register memory map
+ * based on the given viftual function number, @vf.
+ *
+ * Return 0 if successful, otherwise -ENODEV.
+ **/
+static int
+lpfc_sli4_bar2_register_memmap(struct lpfc_hba *phba, uint32_t vf)
+{
+       if (vf > LPFC_VIR_FUNC_MAX)
+               return -ENODEV;
+
+       phba->sli4_hba.RQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
+                               vf * LPFC_VFR_PAGE_SIZE + LPFC_RQ_DOORBELL);
+       phba->sli4_hba.WQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
+                               vf * LPFC_VFR_PAGE_SIZE + LPFC_WQ_DOORBELL);
+       phba->sli4_hba.EQCQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
+                               vf * LPFC_VFR_PAGE_SIZE + LPFC_EQCQ_DOORBELL);
+       phba->sli4_hba.MQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
+                               vf * LPFC_VFR_PAGE_SIZE + LPFC_MQ_DOORBELL);
+       phba->sli4_hba.BMBXregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
+                               vf * LPFC_VFR_PAGE_SIZE + LPFC_BMBX);
+       return 0;
+}
+
+/**
+ * lpfc_create_bootstrap_mbox - Create the bootstrap mailbox
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to create the bootstrap mailbox
+ * region consistent with the SLI-4 interface spec.  This
+ * routine allocates all memory necessary to communicate
+ * mailbox commands to the port and sets up all alignment
+ * needs.  No locks are expected to be held when calling
+ * this routine.
+ *
+ * Return codes
+ *     0 - sucessful
+ *     ENOMEM - could not allocated memory.
+ **/
+static int
+lpfc_create_bootstrap_mbox(struct lpfc_hba *phba)
+{
+       uint32_t bmbx_size;
+       struct lpfc_dmabuf *dmabuf;
+       struct dma_address *dma_address;
+       uint32_t pa_addr;
+       uint64_t phys_addr;
+
+       dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+       if (!dmabuf)
+               return -ENOMEM;
+
+       /*
+        * The bootstrap mailbox region is comprised of 2 parts
+        * plus an alignment restriction of 16 bytes.
+        */
+       bmbx_size = sizeof(struct lpfc_bmbx_create) + (LPFC_ALIGN_16_BYTE - 1);
+       dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev,
+                                         bmbx_size,
+                                         &dmabuf->phys,
+                                         GFP_KERNEL);
+       if (!dmabuf->virt) {
+               kfree(dmabuf);
+               return -ENOMEM;
+       }
+       memset(dmabuf->virt, 0, bmbx_size);
+
+       /*
+        * Initialize the bootstrap mailbox pointers now so that the register
+        * operations are simple later.  The mailbox dma address is required
+        * to be 16-byte aligned.  Also align the virtual memory as each
+        * maibox is copied into the bmbx mailbox region before issuing the
+        * command to the port.
+        */
+       phba->sli4_hba.bmbx.dmabuf = dmabuf;
+       phba->sli4_hba.bmbx.bmbx_size = bmbx_size;
+
+       phba->sli4_hba.bmbx.avirt = PTR_ALIGN(dmabuf->virt,
+                                             LPFC_ALIGN_16_BYTE);
+       phba->sli4_hba.bmbx.aphys = ALIGN(dmabuf->phys,
+                                             LPFC_ALIGN_16_BYTE);
+
+       /*
+        * Set the high and low physical addresses now.  The SLI4 alignment
+        * requirement is 16 bytes and the mailbox is posted to the port
+        * as two 30-bit addresses.  The other data is a bit marking whether
+        * the 30-bit address is the high or low address.
+        * Upcast bmbx aphys to 64bits so shift instruction compiles
+        * clean on 32 bit machines.
+        */
+       dma_address = &phba->sli4_hba.bmbx.dma_address;
+       phys_addr = (uint64_t)phba->sli4_hba.bmbx.aphys;
+       pa_addr = (uint32_t) ((phys_addr >> 34) & 0x3fffffff);
+       dma_address->addr_hi = (uint32_t) ((pa_addr << 2) |
+                                          LPFC_BMBX_BIT1_ADDR_HI);
+
+       pa_addr = (uint32_t) ((phba->sli4_hba.bmbx.aphys >> 4) & 0x3fffffff);
+       dma_address->addr_lo = (uint32_t) ((pa_addr << 2) |
+                                          LPFC_BMBX_BIT1_ADDR_LO);
+       return 0;
+}
+
+/**
+ * lpfc_destroy_bootstrap_mbox - Destroy all bootstrap mailbox resources
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to teardown the bootstrap mailbox
+ * region and release all host resources. This routine requires
+ * the caller to ensure all mailbox commands recovered, no
+ * additional mailbox comands are sent, and interrupts are disabled
+ * before calling this routine.
+ *
+ **/
+static void
+lpfc_destroy_bootstrap_mbox(struct lpfc_hba *phba)
+{
+       dma_free_coherent(&phba->pcidev->dev,
+                         phba->sli4_hba.bmbx.bmbx_size,
+                         phba->sli4_hba.bmbx.dmabuf->virt,
+                         phba->sli4_hba.bmbx.dmabuf->phys);
+
+       kfree(phba->sli4_hba.bmbx.dmabuf);
+       memset(&phba->sli4_hba.bmbx, 0, sizeof(struct lpfc_bmbx));
+}
+
+/**
+ * lpfc_sli4_read_config - Get the config parameters.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to read the configuration parameters from the HBA.
+ * The configuration parameters are used to set the base and maximum values
+ * for RPI's XRI's VPI's VFI's and FCFIs. These values also affect the resource
+ * allocation for the port.
+ *
+ * Return codes
+ *     0 - sucessful
+ *     ENOMEM - No availble memory
+ *      EIO - The mailbox failed to complete successfully.
+ **/
+static int
+lpfc_sli4_read_config(struct lpfc_hba *phba)
+{
+       LPFC_MBOXQ_t *pmb;
+       struct lpfc_mbx_read_config *rd_config;
+       uint32_t rc = 0;
+
+       pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!pmb) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "2011 Unable to allocate memory for issuing "
+                               "SLI_CONFIG_SPECIAL mailbox command\n");
+               return -ENOMEM;
+       }
+
+       lpfc_read_config(phba, pmb);
+
+       rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
+       if (rc != MBX_SUCCESS) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                       "2012 Mailbox failed , mbxCmd x%x "
+                       "READ_CONFIG, mbxStatus x%x\n",
+                       bf_get(lpfc_mqe_command, &pmb->u.mqe),
+                       bf_get(lpfc_mqe_status, &pmb->u.mqe));
+               rc = -EIO;
+       } else {
+               rd_config = &pmb->u.mqe.un.rd_config;
+               phba->sli4_hba.max_cfg_param.max_xri =
+                       bf_get(lpfc_mbx_rd_conf_xri_count, rd_config);
+               phba->sli4_hba.max_cfg_param.xri_base =
+                       bf_get(lpfc_mbx_rd_conf_xri_base, rd_config);
+               phba->sli4_hba.max_cfg_param.max_vpi =
+                       bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config);
+               phba->sli4_hba.max_cfg_param.vpi_base =
+                       bf_get(lpfc_mbx_rd_conf_vpi_base, rd_config);
+               phba->sli4_hba.max_cfg_param.max_rpi =
+                       bf_get(lpfc_mbx_rd_conf_rpi_count, rd_config);
+               phba->sli4_hba.max_cfg_param.rpi_base =
+                       bf_get(lpfc_mbx_rd_conf_rpi_base, rd_config);
+               phba->sli4_hba.max_cfg_param.max_vfi =
+                       bf_get(lpfc_mbx_rd_conf_vfi_count, rd_config);
+               phba->sli4_hba.max_cfg_param.vfi_base =
+                       bf_get(lpfc_mbx_rd_conf_vfi_base, rd_config);
+               phba->sli4_hba.max_cfg_param.max_fcfi =
+                       bf_get(lpfc_mbx_rd_conf_fcfi_count, rd_config);
+               phba->sli4_hba.max_cfg_param.fcfi_base =
+                       bf_get(lpfc_mbx_rd_conf_fcfi_base, rd_config);
+               phba->sli4_hba.max_cfg_param.max_eq =
+                       bf_get(lpfc_mbx_rd_conf_eq_count, rd_config);
+               phba->sli4_hba.max_cfg_param.max_rq =
+                       bf_get(lpfc_mbx_rd_conf_rq_count, rd_config);
+               phba->sli4_hba.max_cfg_param.max_wq =
+                       bf_get(lpfc_mbx_rd_conf_wq_count, rd_config);
+               phba->sli4_hba.max_cfg_param.max_cq =
+                       bf_get(lpfc_mbx_rd_conf_cq_count, rd_config);
+               phba->lmt = bf_get(lpfc_mbx_rd_conf_lmt, rd_config);
+               phba->sli4_hba.next_xri = phba->sli4_hba.max_cfg_param.xri_base;
+               phba->vpi_base = phba->sli4_hba.max_cfg_param.vpi_base;
+               phba->vfi_base = phba->sli4_hba.max_cfg_param.vfi_base;
+               phba->sli4_hba.next_rpi = phba->sli4_hba.max_cfg_param.rpi_base;
+               phba->max_vpi = phba->sli4_hba.max_cfg_param.max_vpi;
+               phba->max_vports = phba->max_vpi;
+               lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+                               "2003 cfg params XRI(B:%d M:%d), "
+                               "VPI(B:%d M:%d) "
+                               "VFI(B:%d M:%d) "
+                               "RPI(B:%d M:%d) "
+                               "FCFI(B:%d M:%d)\n",
+                               phba->sli4_hba.max_cfg_param.xri_base,
+                               phba->sli4_hba.max_cfg_param.max_xri,
+                               phba->sli4_hba.max_cfg_param.vpi_base,
+                               phba->sli4_hba.max_cfg_param.max_vpi,
+                               phba->sli4_hba.max_cfg_param.vfi_base,
+                               phba->sli4_hba.max_cfg_param.max_vfi,
+                               phba->sli4_hba.max_cfg_param.rpi_base,
+                               phba->sli4_hba.max_cfg_param.max_rpi,
+                               phba->sli4_hba.max_cfg_param.fcfi_base,
+                               phba->sli4_hba.max_cfg_param.max_fcfi);
+       }
+       mempool_free(pmb, phba->mbox_mem_pool);
+
+       /* Reset the DFT_HBA_Q_DEPTH to the max xri  */
+       if (phba->cfg_hba_queue_depth > (phba->sli4_hba.max_cfg_param.max_xri))
+               phba->cfg_hba_queue_depth =
+                               phba->sli4_hba.max_cfg_param.max_xri;
+       return rc;
+}
+
+/**
+ * lpfc_dev_endian_order_setup - Notify the port of the host's endian order.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to setup the host-side endian order to the
+ * HBA consistent with the SLI-4 interface spec.
+ *
+ * Return codes
+ *     0 - sucessful
+ *     ENOMEM - No availble memory
+ *      EIO - The mailbox failed to complete successfully.
+ **/
+static int
+lpfc_setup_endian_order(struct lpfc_hba *phba)
+{
+       LPFC_MBOXQ_t *mboxq;
+       uint32_t rc = 0;
+       uint32_t endian_mb_data[2] = {HOST_ENDIAN_LOW_WORD0,
+                                     HOST_ENDIAN_HIGH_WORD1};
+
+       mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mboxq) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0492 Unable to allocate memory for issuing "
+                               "SLI_CONFIG_SPECIAL mailbox command\n");
+               return -ENOMEM;
+       }
+
+       /*
+        * The SLI4_CONFIG_SPECIAL mailbox command requires the first two
+        * words to contain special data values and no other data.
+        */
+       memset(mboxq, 0, sizeof(LPFC_MBOXQ_t));
+       memcpy(&mboxq->u.mqe, &endian_mb_data, sizeof(endian_mb_data));
+       rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+       if (rc != MBX_SUCCESS) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0493 SLI_CONFIG_SPECIAL mailbox failed with "
+                               "status x%x\n",
+                               rc);
+               rc = -EIO;
+       }
+
+       mempool_free(mboxq, phba->mbox_mem_pool);
+       return rc;
+}
+
+/**
+ * lpfc_sli4_queue_create - Create all the SLI4 queues
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to allocate all the SLI4 queues for the FCoE HBA
+ * operation. For each SLI4 queue type, the parameters such as queue entry
+ * count (queue depth) shall be taken from the module parameter. For now,
+ * we just use some constant number as place holder.
+ *
+ * Return codes
+ *      0 - sucessful
+ *      ENOMEM - No availble memory
+ *      EIO - The mailbox failed to complete successfully.
+ **/
+static int
+lpfc_sli4_queue_create(struct lpfc_hba *phba)
+{
+       struct lpfc_queue *qdesc;
+       int fcp_eqidx, fcp_cqidx, fcp_wqidx;
+       int cfg_fcp_wq_count;
+       int cfg_fcp_eq_count;
+
+       /*
+        * Sanity check for confiugred queue parameters against the run-time
+        * device parameters
+        */
+
+       /* Sanity check on FCP fast-path WQ parameters */
+       cfg_fcp_wq_count = phba->cfg_fcp_wq_count;
+       if (cfg_fcp_wq_count >
+           (phba->sli4_hba.max_cfg_param.max_wq - LPFC_SP_WQN_DEF)) {
+               cfg_fcp_wq_count = phba->sli4_hba.max_cfg_param.max_wq -
+                                  LPFC_SP_WQN_DEF;
+               if (cfg_fcp_wq_count < LPFC_FP_WQN_MIN) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "2581 Not enough WQs (%d) from "
+                                       "the pci function for supporting "
+                                       "FCP WQs (%d)\n",
+                                       phba->sli4_hba.max_cfg_param.max_wq,
+                                       phba->cfg_fcp_wq_count);
+                       goto out_error;
+               }
+               lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+                               "2582 Not enough WQs (%d) from the pci "
+                               "function for supporting the requested "
+                               "FCP WQs (%d), the actual FCP WQs can "
+                               "be supported: %d\n",
+                               phba->sli4_hba.max_cfg_param.max_wq,
+                               phba->cfg_fcp_wq_count, cfg_fcp_wq_count);
+       }
+       /* The actual number of FCP work queues adopted */
+       phba->cfg_fcp_wq_count = cfg_fcp_wq_count;
+
+       /* Sanity check on FCP fast-path EQ parameters */
+       cfg_fcp_eq_count = phba->cfg_fcp_eq_count;
+       if (cfg_fcp_eq_count >
+           (phba->sli4_hba.max_cfg_param.max_eq - LPFC_SP_EQN_DEF)) {
+               cfg_fcp_eq_count = phba->sli4_hba.max_cfg_param.max_eq -
+                                  LPFC_SP_EQN_DEF;
+               if (cfg_fcp_eq_count < LPFC_FP_EQN_MIN) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "2574 Not enough EQs (%d) from the "
+                                       "pci function for supporting FCP "
+                                       "EQs (%d)\n",
+                                       phba->sli4_hba.max_cfg_param.max_eq,
+                                       phba->cfg_fcp_eq_count);
+                       goto out_error;
+               }
+               lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+                               "2575 Not enough EQs (%d) from the pci "
+                               "function for supporting the requested "
+                               "FCP EQs (%d), the actual FCP EQs can "
+                               "be supported: %d\n",
+                               phba->sli4_hba.max_cfg_param.max_eq,
+                               phba->cfg_fcp_eq_count, cfg_fcp_eq_count);
+       }
+       /* It does not make sense to have more EQs than WQs */
+       if (cfg_fcp_eq_count > phba->cfg_fcp_wq_count) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+                               "2593 The number of FCP EQs (%d) is more "
+                               "than the number of FCP WQs (%d), take "
+                               "the number of FCP EQs same as than of "
+                               "WQs (%d)\n", cfg_fcp_eq_count,
+                               phba->cfg_fcp_wq_count,
+                               phba->cfg_fcp_wq_count);
+               cfg_fcp_eq_count = phba->cfg_fcp_wq_count;
+       }
+       /* The actual number of FCP event queues adopted */
+       phba->cfg_fcp_eq_count = cfg_fcp_eq_count;
+       /* The overall number of event queues used */
+       phba->sli4_hba.cfg_eqn = phba->cfg_fcp_eq_count + LPFC_SP_EQN_DEF;
+
+       /*
+        * Create Event Queues (EQs)
+        */
+
+       /* Get EQ depth from module parameter, fake the default for now */
+       phba->sli4_hba.eq_esize = LPFC_EQE_SIZE_4B;
+       phba->sli4_hba.eq_ecount = LPFC_EQE_DEF_COUNT;
+
+       /* Create slow path event queue */
+       qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.eq_esize,
+                                     phba->sli4_hba.eq_ecount);
+       if (!qdesc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0496 Failed allocate slow-path EQ\n");
+               goto out_error;
+       }
+       phba->sli4_hba.sp_eq = qdesc;
+
+       /* Create fast-path FCP Event Queue(s) */
+       phba->sli4_hba.fp_eq = kzalloc((sizeof(struct lpfc_queue *) *
+                              phba->cfg_fcp_eq_count), GFP_KERNEL);
+       if (!phba->sli4_hba.fp_eq) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2576 Failed allocate memory for fast-path "
+                               "EQ record array\n");
+               goto out_free_sp_eq;
+       }
+       for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++) {
+               qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.eq_esize,
+                                             phba->sli4_hba.eq_ecount);
+               if (!qdesc) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "0497 Failed allocate fast-path EQ\n");
+                       goto out_free_fp_eq;
+               }
+               phba->sli4_hba.fp_eq[fcp_eqidx] = qdesc;
+       }
+
+       /*
+        * Create Complete Queues (CQs)
+        */
+
+       /* Get CQ depth from module parameter, fake the default for now */
+       phba->sli4_hba.cq_esize = LPFC_CQE_SIZE;
+       phba->sli4_hba.cq_ecount = LPFC_CQE_DEF_COUNT;
+
+       /* Create slow-path Mailbox Command Complete Queue */
+       qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize,
+                                     phba->sli4_hba.cq_ecount);
+       if (!qdesc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0500 Failed allocate slow-path mailbox CQ\n");
+               goto out_free_fp_eq;
+       }
+       phba->sli4_hba.mbx_cq = qdesc;
+
+       /* Create slow-path ELS Complete Queue */
+       qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize,
+                                     phba->sli4_hba.cq_ecount);
+       if (!qdesc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0501 Failed allocate slow-path ELS CQ\n");
+               goto out_free_mbx_cq;
+       }
+       phba->sli4_hba.els_cq = qdesc;
+
+       /* Create slow-path Unsolicited Receive Complete Queue */
+       qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize,
+                                     phba->sli4_hba.cq_ecount);
+       if (!qdesc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0502 Failed allocate slow-path USOL RX CQ\n");
+               goto out_free_els_cq;
+       }
+       phba->sli4_hba.rxq_cq = qdesc;
+
+       /* Create fast-path FCP Completion Queue(s), one-to-one with EQs */
+       phba->sli4_hba.fcp_cq = kzalloc((sizeof(struct lpfc_queue *) *
+                               phba->cfg_fcp_eq_count), GFP_KERNEL);
+       if (!phba->sli4_hba.fcp_cq) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2577 Failed allocate memory for fast-path "
+                               "CQ record array\n");
+               goto out_free_rxq_cq;
+       }
+       for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_eq_count; fcp_cqidx++) {
+               qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize,
+                                             phba->sli4_hba.cq_ecount);
+               if (!qdesc) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "0499 Failed allocate fast-path FCP "
+                                       "CQ (%d)\n", fcp_cqidx);
+                       goto out_free_fcp_cq;
+               }
+               phba->sli4_hba.fcp_cq[fcp_cqidx] = qdesc;
+       }
+
+       /* Create Mailbox Command Queue */
+       phba->sli4_hba.mq_esize = LPFC_MQE_SIZE;
+       phba->sli4_hba.mq_ecount = LPFC_MQE_DEF_COUNT;
+
+       qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.mq_esize,
+                                     phba->sli4_hba.mq_ecount);
+       if (!qdesc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0505 Failed allocate slow-path MQ\n");
+               goto out_free_fcp_cq;
+       }
+       phba->sli4_hba.mbx_wq = qdesc;
+
+       /*
+        * Create all the Work Queues (WQs)
+        */
+       phba->sli4_hba.wq_esize = LPFC_WQE_SIZE;
+       phba->sli4_hba.wq_ecount = LPFC_WQE_DEF_COUNT;
+
+       /* Create slow-path ELS Work Queue */
+       qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.wq_esize,
+                                     phba->sli4_hba.wq_ecount);
+       if (!qdesc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0504 Failed allocate slow-path ELS WQ\n");
+               goto out_free_mbx_wq;
+       }
+       phba->sli4_hba.els_wq = qdesc;
+
+       /* Create fast-path FCP Work Queue(s) */
+       phba->sli4_hba.fcp_wq = kzalloc((sizeof(struct lpfc_queue *) *
+                               phba->cfg_fcp_wq_count), GFP_KERNEL);
+       if (!phba->sli4_hba.fcp_wq) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2578 Failed allocate memory for fast-path "
+                               "WQ record array\n");
+               goto out_free_els_wq;
+       }
+       for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++) {
+               qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.wq_esize,
+                                             phba->sli4_hba.wq_ecount);
+               if (!qdesc) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "0503 Failed allocate fast-path FCP "
+                                       "WQ (%d)\n", fcp_wqidx);
+                       goto out_free_fcp_wq;
+               }
+               phba->sli4_hba.fcp_wq[fcp_wqidx] = qdesc;
+       }
+
+       /*
+        * Create Receive Queue (RQ)
+        */
+       phba->sli4_hba.rq_esize = LPFC_RQE_SIZE;
+       phba->sli4_hba.rq_ecount = LPFC_RQE_DEF_COUNT;
+
+       /* Create Receive Queue for header */
+       qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.rq_esize,
+                                     phba->sli4_hba.rq_ecount);
+       if (!qdesc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0506 Failed allocate receive HRQ\n");
+               goto out_free_fcp_wq;
+       }
+       phba->sli4_hba.hdr_rq = qdesc;
+
+       /* Create Receive Queue for data */
+       qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.rq_esize,
+                                     phba->sli4_hba.rq_ecount);
+       if (!qdesc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0507 Failed allocate receive DRQ\n");
+               goto out_free_hdr_rq;
+       }
+       phba->sli4_hba.dat_rq = qdesc;
+
+       return 0;
+
+out_free_hdr_rq:
+       lpfc_sli4_queue_free(phba->sli4_hba.hdr_rq);
+       phba->sli4_hba.hdr_rq = NULL;
+out_free_fcp_wq:
+       for (--fcp_wqidx; fcp_wqidx >= 0; fcp_wqidx--) {
+               lpfc_sli4_queue_free(phba->sli4_hba.fcp_wq[fcp_wqidx]);
+               phba->sli4_hba.fcp_wq[fcp_wqidx] = NULL;
+       }
+       kfree(phba->sli4_hba.fcp_wq);
+out_free_els_wq:
+       lpfc_sli4_queue_free(phba->sli4_hba.els_wq);
+       phba->sli4_hba.els_wq = NULL;
+out_free_mbx_wq:
+       lpfc_sli4_queue_free(phba->sli4_hba.mbx_wq);
+       phba->sli4_hba.mbx_wq = NULL;
+out_free_fcp_cq:
+       for (--fcp_cqidx; fcp_cqidx >= 0; fcp_cqidx--) {
+               lpfc_sli4_queue_free(phba->sli4_hba.fcp_cq[fcp_cqidx]);
+               phba->sli4_hba.fcp_cq[fcp_cqidx] = NULL;
+       }
+       kfree(phba->sli4_hba.fcp_cq);
+out_free_rxq_cq:
+       lpfc_sli4_queue_free(phba->sli4_hba.rxq_cq);
+       phba->sli4_hba.rxq_cq = NULL;
+out_free_els_cq:
+       lpfc_sli4_queue_free(phba->sli4_hba.els_cq);
+       phba->sli4_hba.els_cq = NULL;
+out_free_mbx_cq:
+       lpfc_sli4_queue_free(phba->sli4_hba.mbx_cq);
+       phba->sli4_hba.mbx_cq = NULL;
+out_free_fp_eq:
+       for (--fcp_eqidx; fcp_eqidx >= 0; fcp_eqidx--) {
+               lpfc_sli4_queue_free(phba->sli4_hba.fp_eq[fcp_eqidx]);
+               phba->sli4_hba.fp_eq[fcp_eqidx] = NULL;
+       }
+       kfree(phba->sli4_hba.fp_eq);
+out_free_sp_eq:
+       lpfc_sli4_queue_free(phba->sli4_hba.sp_eq);
+       phba->sli4_hba.sp_eq = NULL;
+out_error:
+       return -ENOMEM;
+}
+
+/**
+ * lpfc_sli4_queue_destroy - Destroy all the SLI4 queues
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to release all the SLI4 queues with the FCoE HBA
+ * operation.
+ *
+ * Return codes
+ *      0 - sucessful
+ *      ENOMEM - No availble memory
+ *      EIO - The mailbox failed to complete successfully.
+ **/
+static void
+lpfc_sli4_queue_destroy(struct lpfc_hba *phba)
+{
+       int fcp_qidx;
+
+       /* Release mailbox command work queue */
+       lpfc_sli4_queue_free(phba->sli4_hba.mbx_wq);
+       phba->sli4_hba.mbx_wq = NULL;
+
+       /* Release ELS work queue */
+       lpfc_sli4_queue_free(phba->sli4_hba.els_wq);
+       phba->sli4_hba.els_wq = NULL;
+
+       /* Release FCP work queue */
+       for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_wq_count; fcp_qidx++)
+               lpfc_sli4_queue_free(phba->sli4_hba.fcp_wq[fcp_qidx]);
+       kfree(phba->sli4_hba.fcp_wq);
+       phba->sli4_hba.fcp_wq = NULL;
+
+       /* Release unsolicited receive queue */
+       lpfc_sli4_queue_free(phba->sli4_hba.hdr_rq);
+       phba->sli4_hba.hdr_rq = NULL;
+       lpfc_sli4_queue_free(phba->sli4_hba.dat_rq);
+       phba->sli4_hba.dat_rq = NULL;
+
+       /* Release unsolicited receive complete queue */
+       lpfc_sli4_queue_free(phba->sli4_hba.rxq_cq);
+       phba->sli4_hba.rxq_cq = NULL;
+
+       /* Release ELS complete queue */
+       lpfc_sli4_queue_free(phba->sli4_hba.els_cq);
+       phba->sli4_hba.els_cq = NULL;
+
+       /* Release mailbox command complete queue */
+       lpfc_sli4_queue_free(phba->sli4_hba.mbx_cq);
+       phba->sli4_hba.mbx_cq = NULL;
+
+       /* Release FCP response complete queue */
+       for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++)
+               lpfc_sli4_queue_free(phba->sli4_hba.fcp_cq[fcp_qidx]);
+       kfree(phba->sli4_hba.fcp_cq);
+       phba->sli4_hba.fcp_cq = NULL;
+
+       /* Release fast-path event queue */
+       for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++)
+               lpfc_sli4_queue_free(phba->sli4_hba.fp_eq[fcp_qidx]);
+       kfree(phba->sli4_hba.fp_eq);
+       phba->sli4_hba.fp_eq = NULL;
+
+       /* Release slow-path event queue */
+       lpfc_sli4_queue_free(phba->sli4_hba.sp_eq);
+       phba->sli4_hba.sp_eq = NULL;
+
+       return;
+}
+
+/**
+ * lpfc_sli4_queue_setup - Set up all the SLI4 queues
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to set up all the SLI4 queues for the FCoE HBA
+ * operation.
+ *
+ * Return codes
+ *      0 - sucessful
+ *      ENOMEM - No availble memory
+ *      EIO - The mailbox failed to complete successfully.
+ **/
+int
+lpfc_sli4_queue_setup(struct lpfc_hba *phba)
+{
+       int rc = -ENOMEM;
+       int fcp_eqidx, fcp_cqidx, fcp_wqidx;
+       int fcp_cq_index = 0;
+
+       /*
+        * Set up Event Queues (EQs)
+        */
+
+       /* Set up slow-path event queue */
+       if (!phba->sli4_hba.sp_eq) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0520 Slow-path EQ not allocated\n");
+               goto out_error;
+       }
+       rc = lpfc_eq_create(phba, phba->sli4_hba.sp_eq,
+                           LPFC_SP_DEF_IMAX);
+       if (rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0521 Failed setup of slow-path EQ: "
+                               "rc = 0x%x\n", rc);
+               goto out_error;
+       }
+       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                       "2583 Slow-path EQ setup: queue-id=%d\n",
+                       phba->sli4_hba.sp_eq->queue_id);
+
+       /* Set up fast-path event queue */
+       for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++) {
+               if (!phba->sli4_hba.fp_eq[fcp_eqidx]) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "0522 Fast-path EQ (%d) not "
+                                       "allocated\n", fcp_eqidx);
+                       goto out_destroy_fp_eq;
+               }
+               rc = lpfc_eq_create(phba, phba->sli4_hba.fp_eq[fcp_eqidx],
+                                   phba->cfg_fcp_imax);
+               if (rc) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "0523 Failed setup of fast-path EQ "
+                                       "(%d), rc = 0x%x\n", fcp_eqidx, rc);
+                       goto out_destroy_fp_eq;
+               }
+               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                               "2584 Fast-path EQ setup: "
+                               "queue[%d]-id=%d\n", fcp_eqidx,
+                               phba->sli4_hba.fp_eq[fcp_eqidx]->queue_id);
+       }
+
+       /*
+        * Set up Complete Queues (CQs)
+        */
+
+       /* Set up slow-path MBOX Complete Queue as the first CQ */
+       if (!phba->sli4_hba.mbx_cq) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0528 Mailbox CQ not allocated\n");
+               goto out_destroy_fp_eq;
+       }
+       rc = lpfc_cq_create(phba, phba->sli4_hba.mbx_cq, phba->sli4_hba.sp_eq,
+                           LPFC_MCQ, LPFC_MBOX);
+       if (rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0529 Failed setup of slow-path mailbox CQ: "
+                               "rc = 0x%x\n", rc);
+               goto out_destroy_fp_eq;
+       }
+       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                       "2585 MBX CQ setup: cq-id=%d, parent eq-id=%d\n",
+                       phba->sli4_hba.mbx_cq->queue_id,
+                       phba->sli4_hba.sp_eq->queue_id);
+
+       /* Set up slow-path ELS Complete Queue */
+       if (!phba->sli4_hba.els_cq) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0530 ELS CQ not allocated\n");
+               goto out_destroy_mbx_cq;
+       }
+       rc = lpfc_cq_create(phba, phba->sli4_hba.els_cq, phba->sli4_hba.sp_eq,
+                           LPFC_WCQ, LPFC_ELS);
+       if (rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0531 Failed setup of slow-path ELS CQ: "
+                               "rc = 0x%x\n", rc);
+               goto out_destroy_mbx_cq;
+       }
+       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                       "2586 ELS CQ setup: cq-id=%d, parent eq-id=%d\n",
+                       phba->sli4_hba.els_cq->queue_id,
+                       phba->sli4_hba.sp_eq->queue_id);
+
+       /* Set up slow-path Unsolicited Receive Complete Queue */
+       if (!phba->sli4_hba.rxq_cq) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0532 USOL RX CQ not allocated\n");
+               goto out_destroy_els_cq;
+       }
+       rc = lpfc_cq_create(phba, phba->sli4_hba.rxq_cq, phba->sli4_hba.sp_eq,
+                           LPFC_RCQ, LPFC_USOL);
+       if (rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0533 Failed setup of slow-path USOL RX CQ: "
+                               "rc = 0x%x\n", rc);
+               goto out_destroy_els_cq;
+       }
+       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                       "2587 USL CQ setup: cq-id=%d, parent eq-id=%d\n",
+                       phba->sli4_hba.rxq_cq->queue_id,
+                       phba->sli4_hba.sp_eq->queue_id);
+
+       /* Set up fast-path FCP Response Complete Queue */
+       for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_eq_count; fcp_cqidx++) {
+               if (!phba->sli4_hba.fcp_cq[fcp_cqidx]) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "0526 Fast-path FCP CQ (%d) not "
+                                       "allocated\n", fcp_cqidx);
+                       goto out_destroy_fcp_cq;
+               }
+               rc = lpfc_cq_create(phba, phba->sli4_hba.fcp_cq[fcp_cqidx],
+                                   phba->sli4_hba.fp_eq[fcp_cqidx],
+                                   LPFC_WCQ, LPFC_FCP);
+               if (rc) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "0527 Failed setup of fast-path FCP "
+                                       "CQ (%d), rc = 0x%x\n", fcp_cqidx, rc);
+                       goto out_destroy_fcp_cq;
+               }
+               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                               "2588 FCP CQ setup: cq[%d]-id=%d, "
+                               "parent eq[%d]-id=%d\n",
+                               fcp_cqidx,
+                               phba->sli4_hba.fcp_cq[fcp_cqidx]->queue_id,
+                               fcp_cqidx,
+                               phba->sli4_hba.fp_eq[fcp_cqidx]->queue_id);
+       }
+
+       /*
+        * Set up all the Work Queues (WQs)
+        */
+
+       /* Set up Mailbox Command Queue */
+       if (!phba->sli4_hba.mbx_wq) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0538 Slow-path MQ not allocated\n");
+               goto out_destroy_fcp_cq;
+       }
+       rc = lpfc_mq_create(phba, phba->sli4_hba.mbx_wq,
+                           phba->sli4_hba.mbx_cq, LPFC_MBOX);
+       if (rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0539 Failed setup of slow-path MQ: "
+                               "rc = 0x%x\n", rc);
+               goto out_destroy_fcp_cq;
+       }
+       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                       "2589 MBX MQ setup: wq-id=%d, parent cq-id=%d\n",
+                       phba->sli4_hba.mbx_wq->queue_id,
+                       phba->sli4_hba.mbx_cq->queue_id);
+
+       /* Set up slow-path ELS Work Queue */
+       if (!phba->sli4_hba.els_wq) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0536 Slow-path ELS WQ not allocated\n");
+               goto out_destroy_mbx_wq;
+       }
+       rc = lpfc_wq_create(phba, phba->sli4_hba.els_wq,
+                           phba->sli4_hba.els_cq, LPFC_ELS);
+       if (rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0537 Failed setup of slow-path ELS WQ: "
+                               "rc = 0x%x\n", rc);
+               goto out_destroy_mbx_wq;
+       }
+       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                       "2590 ELS WQ setup: wq-id=%d, parent cq-id=%d\n",
+                       phba->sli4_hba.els_wq->queue_id,
+                       phba->sli4_hba.els_cq->queue_id);
+
+       /* Set up fast-path FCP Work Queue */
+       for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++) {
+               if (!phba->sli4_hba.fcp_wq[fcp_wqidx]) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "0534 Fast-path FCP WQ (%d) not "
+                                       "allocated\n", fcp_wqidx);
+                       goto out_destroy_fcp_wq;
+               }
+               rc = lpfc_wq_create(phba, phba->sli4_hba.fcp_wq[fcp_wqidx],
+                                   phba->sli4_hba.fcp_cq[fcp_cq_index],
+                                   LPFC_FCP);
+               if (rc) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "0535 Failed setup of fast-path FCP "
+                                       "WQ (%d), rc = 0x%x\n", fcp_wqidx, rc);
+                       goto out_destroy_fcp_wq;
+               }
+               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                               "2591 FCP WQ setup: wq[%d]-id=%d, "
+                               "parent cq[%d]-id=%d\n",
+                               fcp_wqidx,
+                               phba->sli4_hba.fcp_wq[fcp_wqidx]->queue_id,
+                               fcp_cq_index,
+                               phba->sli4_hba.fcp_cq[fcp_cq_index]->queue_id);
+               /* Round robin FCP Work Queue's Completion Queue assignment */
+               fcp_cq_index = ((fcp_cq_index + 1) % phba->cfg_fcp_eq_count);
+       }
+
+       /*
+        * Create Receive Queue (RQ)
+        */
+       if (!phba->sli4_hba.hdr_rq || !phba->sli4_hba.dat_rq) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0540 Receive Queue not allocated\n");
+               goto out_destroy_fcp_wq;
+       }
+       rc = lpfc_rq_create(phba, phba->sli4_hba.hdr_rq, phba->sli4_hba.dat_rq,
+                           phba->sli4_hba.rxq_cq, LPFC_USOL);
+       if (rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0541 Failed setup of Receive Queue: "
+                               "rc = 0x%x\n", rc);
+               goto out_destroy_fcp_wq;
+       }
+       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                       "2592 USL RQ setup: hdr-rq-id=%d, dat-rq-id=%d "
+                       "parent cq-id=%d\n",
+                       phba->sli4_hba.hdr_rq->queue_id,
+                       phba->sli4_hba.dat_rq->queue_id,
+                       phba->sli4_hba.rxq_cq->queue_id);
+       return 0;
+
+out_destroy_fcp_wq:
+       for (--fcp_wqidx; fcp_wqidx >= 0; fcp_wqidx--)
+               lpfc_wq_destroy(phba, phba->sli4_hba.fcp_wq[fcp_wqidx]);
+       lpfc_wq_destroy(phba, phba->sli4_hba.els_wq);
+out_destroy_mbx_wq:
+       lpfc_mq_destroy(phba, phba->sli4_hba.mbx_wq);
+out_destroy_fcp_cq:
+       for (--fcp_cqidx; fcp_cqidx >= 0; fcp_cqidx--)
+               lpfc_cq_destroy(phba, phba->sli4_hba.fcp_cq[fcp_cqidx]);
+       lpfc_cq_destroy(phba, phba->sli4_hba.rxq_cq);
+out_destroy_els_cq:
+       lpfc_cq_destroy(phba, phba->sli4_hba.els_cq);
+out_destroy_mbx_cq:
+       lpfc_cq_destroy(phba, phba->sli4_hba.mbx_cq);
+out_destroy_fp_eq:
+       for (--fcp_eqidx; fcp_eqidx >= 0; fcp_eqidx--)
+               lpfc_eq_destroy(phba, phba->sli4_hba.fp_eq[fcp_eqidx]);
+       lpfc_eq_destroy(phba, phba->sli4_hba.sp_eq);
+out_error:
+       return rc;
+}
+
+/**
+ * lpfc_sli4_queue_unset - Unset all the SLI4 queues
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to unset all the SLI4 queues with the FCoE HBA
+ * operation.
+ *
+ * Return codes
+ *      0 - sucessful
+ *      ENOMEM - No availble memory
+ *      EIO - The mailbox failed to complete successfully.
+ **/
+void
+lpfc_sli4_queue_unset(struct lpfc_hba *phba)
+{
+       int fcp_qidx;
+
+       /* Unset mailbox command work queue */
+       lpfc_mq_destroy(phba, phba->sli4_hba.mbx_wq);
+       /* Unset ELS work queue */
+       lpfc_wq_destroy(phba, phba->sli4_hba.els_wq);
+       /* Unset unsolicited receive queue */
+       lpfc_rq_destroy(phba, phba->sli4_hba.hdr_rq, phba->sli4_hba.dat_rq);
+       /* Unset FCP work queue */
+       for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_wq_count; fcp_qidx++)
+               lpfc_wq_destroy(phba, phba->sli4_hba.fcp_wq[fcp_qidx]);
+       /* Unset mailbox command complete queue */
+       lpfc_cq_destroy(phba, phba->sli4_hba.mbx_cq);
+       /* Unset ELS complete queue */
+       lpfc_cq_destroy(phba, phba->sli4_hba.els_cq);
+       /* Unset unsolicited receive complete queue */
+       lpfc_cq_destroy(phba, phba->sli4_hba.rxq_cq);
+       /* Unset FCP response complete queue */
+       for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++)
+               lpfc_cq_destroy(phba, phba->sli4_hba.fcp_cq[fcp_qidx]);
+       /* Unset fast-path event queue */
+       for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++)
+               lpfc_eq_destroy(phba, phba->sli4_hba.fp_eq[fcp_qidx]);
+       /* Unset slow-path event queue */
+       lpfc_eq_destroy(phba, phba->sli4_hba.sp_eq);
+}
+
+/**
+ * lpfc_sli4_cq_event_pool_create - Create completion-queue event free pool
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to allocate and set up a pool of completion queue
+ * events. The body of the completion queue event is a completion queue entry
+ * CQE. For now, this pool is used for the interrupt service routine to queue
+ * the following HBA completion queue events for the worker thread to process:
+ *   - Mailbox asynchronous events
+ *   - Receive queue completion unsolicited events
+ * Later, this can be used for all the slow-path events.
+ *
+ * Return codes
+ *      0 - sucessful
+ *      -ENOMEM - No availble memory
+ **/
+static int
+lpfc_sli4_cq_event_pool_create(struct lpfc_hba *phba)
+{
+       struct lpfc_cq_event *cq_event;
+       int i;
+
+       for (i = 0; i < (4 * phba->sli4_hba.cq_ecount); i++) {
+               cq_event = kmalloc(sizeof(struct lpfc_cq_event), GFP_KERNEL);
+               if (!cq_event)
+                       goto out_pool_create_fail;
+               list_add_tail(&cq_event->list,
+                             &phba->sli4_hba.sp_cqe_event_pool);
+       }
+       return 0;
+
+out_pool_create_fail:
+       lpfc_sli4_cq_event_pool_destroy(phba);
+       return -ENOMEM;
+}
+
+/**
+ * lpfc_sli4_cq_event_pool_destroy - Free completion-queue event free pool
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to free the pool of completion queue events at
+ * driver unload time. Note that, it is the responsibility of the driver
+ * cleanup routine to free all the outstanding completion-queue events
+ * allocated from this pool back into the pool before invoking this routine
+ * to destroy the pool.
+ **/
+static void
+lpfc_sli4_cq_event_pool_destroy(struct lpfc_hba *phba)
+{
+       struct lpfc_cq_event *cq_event, *next_cq_event;
+
+       list_for_each_entry_safe(cq_event, next_cq_event,
+                                &phba->sli4_hba.sp_cqe_event_pool, list) {
+               list_del(&cq_event->list);
+               kfree(cq_event);
+       }
+}
+
+/**
+ * __lpfc_sli4_cq_event_alloc - Allocate a completion-queue event from free pool
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is the lock free version of the API invoked to allocate a
+ * completion-queue event from the free pool.
+ *
+ * Return: Pointer to the newly allocated completion-queue event if successful
+ *         NULL otherwise.
+ **/
+struct lpfc_cq_event *
+__lpfc_sli4_cq_event_alloc(struct lpfc_hba *phba)
+{
+       struct lpfc_cq_event *cq_event = NULL;
+
+       list_remove_head(&phba->sli4_hba.sp_cqe_event_pool, cq_event,
+                        struct lpfc_cq_event, list);
+       return cq_event;
+}
+
+/**
+ * lpfc_sli4_cq_event_alloc - Allocate a completion-queue event from free pool
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is the lock version of the API invoked to allocate a
+ * completion-queue event from the free pool.
+ *
+ * Return: Pointer to the newly allocated completion-queue event if successful
+ *         NULL otherwise.
+ **/
+struct lpfc_cq_event *
+lpfc_sli4_cq_event_alloc(struct lpfc_hba *phba)
+{
+       struct lpfc_cq_event *cq_event;
+       unsigned long iflags;
+
+       spin_lock_irqsave(&phba->hbalock, iflags);
+       cq_event = __lpfc_sli4_cq_event_alloc(phba);
+       spin_unlock_irqrestore(&phba->hbalock, iflags);
+       return cq_event;
+}
+
+/**
+ * __lpfc_sli4_cq_event_release - Release a completion-queue event to free pool
+ * @phba: pointer to lpfc hba data structure.
+ * @cq_event: pointer to the completion queue event to be freed.
+ *
+ * This routine is the lock free version of the API invoked to release a
+ * completion-queue event back into the free pool.
+ **/
+void
+__lpfc_sli4_cq_event_release(struct lpfc_hba *phba,
+                            struct lpfc_cq_event *cq_event)
+{
+       list_add_tail(&cq_event->list, &phba->sli4_hba.sp_cqe_event_pool);
+}
+
+/**
+ * lpfc_sli4_cq_event_release - Release a completion-queue event to free pool
+ * @phba: pointer to lpfc hba data structure.
+ * @cq_event: pointer to the completion queue event to be freed.
+ *
+ * This routine is the lock version of the API invoked to release a
+ * completion-queue event back into the free pool.
+ **/
+void
+lpfc_sli4_cq_event_release(struct lpfc_hba *phba,
+                          struct lpfc_cq_event *cq_event)
+{
+       unsigned long iflags;
+       spin_lock_irqsave(&phba->hbalock, iflags);
+       __lpfc_sli4_cq_event_release(phba, cq_event);
+       spin_unlock_irqrestore(&phba->hbalock, iflags);
+}
+
+/**
+ * lpfc_sli4_cq_event_release_all - Release all cq events to the free pool
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is to free all the pending completion-queue events to the
+ * back into the free pool for device reset.
+ **/
+static void
+lpfc_sli4_cq_event_release_all(struct lpfc_hba *phba)
+{
+       LIST_HEAD(cqelist);
+       struct lpfc_cq_event *cqe;
+       unsigned long iflags;
+
+       /* Retrieve all the pending WCQEs from pending WCQE lists */
+       spin_lock_irqsave(&phba->hbalock, iflags);
+       /* Pending FCP XRI abort events */
+       list_splice_init(&phba->sli4_hba.sp_fcp_xri_aborted_work_queue,
+                        &cqelist);
+       /* Pending ELS XRI abort events */
+       list_splice_init(&phba->sli4_hba.sp_els_xri_aborted_work_queue,
+                        &cqelist);
+       /* Pending asynnc events */
+       list_splice_init(&phba->sli4_hba.sp_asynce_work_queue,
+                        &cqelist);
+       spin_unlock_irqrestore(&phba->hbalock, iflags);
+
+       while (!list_empty(&cqelist)) {
+               list_remove_head(&cqelist, cqe, struct lpfc_cq_event, list);
+               lpfc_sli4_cq_event_release(phba, cqe);
+       }
+}
+
+/**
+ * lpfc_pci_function_reset - Reset pci function.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to request a PCI function reset. It will destroys
+ * all resources assigned to the PCI function which originates this request.
+ *
+ * Return codes
+ *      0 - sucessful
+ *      ENOMEM - No availble memory
+ *      EIO - The mailbox failed to complete successfully.
+ **/
+int
+lpfc_pci_function_reset(struct lpfc_hba *phba)
+{
+       LPFC_MBOXQ_t *mboxq;
+       uint32_t rc = 0;
+       uint32_t shdr_status, shdr_add_status;
+       union lpfc_sli4_cfg_shdr *shdr;
+
+       mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mboxq) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0494 Unable to allocate memory for issuing "
+                               "SLI_FUNCTION_RESET mailbox command\n");
+               return -ENOMEM;
+       }
+
+       /* Set up PCI function reset SLI4_CONFIG mailbox-ioctl command */
+       lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON,
+                        LPFC_MBOX_OPCODE_FUNCTION_RESET, 0,
+                        LPFC_SLI4_MBX_EMBED);
+       rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+       shdr = (union lpfc_sli4_cfg_shdr *)
+               &mboxq->u.mqe.un.sli4_config.header.cfg_shdr;
+       shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+       if (rc != MBX_TIMEOUT)
+               mempool_free(mboxq, phba->mbox_mem_pool);
+       if (shdr_status || shdr_add_status || rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0495 SLI_FUNCTION_RESET mailbox failed with "
+                               "status x%x add_status x%x, mbx status x%x\n",
+                               shdr_status, shdr_add_status, rc);
+               rc = -ENXIO;
+       }
+       return rc;
+}
+
+/**
+ * lpfc_sli4_send_nop_mbox_cmds - Send sli-4 nop mailbox commands
+ * @phba: pointer to lpfc hba data structure.
+ * @cnt: number of nop mailbox commands to send.
+ *
+ * This routine is invoked to send a number @cnt of NOP mailbox command and
+ * wait for each command to complete.
+ *
+ * Return: the number of NOP mailbox command completed.
+ **/
+static int
+lpfc_sli4_send_nop_mbox_cmds(struct lpfc_hba *phba, uint32_t cnt)
+{
+       LPFC_MBOXQ_t *mboxq;
+       int length, cmdsent;
+       uint32_t mbox_tmo;
+       uint32_t rc = 0;
+       uint32_t shdr_status, shdr_add_status;
+       union lpfc_sli4_cfg_shdr *shdr;
+
+       if (cnt == 0) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+                               "2518 Requested to send 0 NOP mailbox cmd\n");
+               return cnt;
+       }
+
+       mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mboxq) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2519 Unable to allocate memory for issuing "
+                               "NOP mailbox command\n");
+               return 0;
+       }
+
+       /* Set up NOP SLI4_CONFIG mailbox-ioctl command */
+       length = (sizeof(struct lpfc_mbx_nop) -
+                 sizeof(struct lpfc_sli4_cfg_mhdr));
+       lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON,
+                        LPFC_MBOX_OPCODE_NOP, length, LPFC_SLI4_MBX_EMBED);
+
+       mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG);
+       for (cmdsent = 0; cmdsent < cnt; cmdsent++) {
+               if (!phba->sli4_hba.intr_enable)
+                       rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+               else
+                       rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo);
+               if (rc == MBX_TIMEOUT)
+                       break;
+               /* Check return status */
+               shdr = (union lpfc_sli4_cfg_shdr *)
+                       &mboxq->u.mqe.un.sli4_config.header.cfg_shdr;
+               shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+               shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
+                                        &shdr->response);
+               if (shdr_status || shdr_add_status || rc) {
+                       lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+                                       "2520 NOP mailbox command failed "
+                                       "status x%x add_status x%x mbx "
+                                       "status x%x\n", shdr_status,
+                                       shdr_add_status, rc);
+                       break;
+               }
+       }
+
+       if (rc != MBX_TIMEOUT)
+               mempool_free(mboxq, phba->mbox_mem_pool);
+
+       return cmdsent;
+}
+
+/**
+ * lpfc_sli4_fcfi_unreg - Unregister fcfi to device
+ * @phba: pointer to lpfc hba data structure.
+ * @fcfi: fcf index.
+ *
+ * This routine is invoked to unregister a FCFI from device.
+ **/
+void
+lpfc_sli4_fcfi_unreg(struct lpfc_hba *phba, uint16_t fcfi)
+{
+       LPFC_MBOXQ_t *mbox;
+       uint32_t mbox_tmo;
+       int rc;
+       unsigned long flags;
+
+       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+
+       if (!mbox)
+               return;
+
+       lpfc_unreg_fcfi(mbox, fcfi);
+
+       if (!phba->sli4_hba.intr_enable)
+               rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+       else {
+               mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG);
+               rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
+       }
+       if (rc != MBX_TIMEOUT)
+               mempool_free(mbox, phba->mbox_mem_pool);
+       if (rc != MBX_SUCCESS)
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "2517 Unregister FCFI command failed "
+                               "status %d, mbxStatus x%x\n", rc,
+                               bf_get(lpfc_mqe_status, &mbox->u.mqe));
+       else {
+               spin_lock_irqsave(&phba->hbalock, flags);
+               /* Mark the FCFI is no longer registered */
+               phba->fcf.fcf_flag &=
+                       ~(FCF_AVAILABLE | FCF_REGISTERED | FCF_DISCOVERED);
+               spin_unlock_irqrestore(&phba->hbalock, flags);
+       }
+}
+
+/**
+ * lpfc_sli4_pci_mem_setup - Setup SLI4 HBA PCI memory space.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to set up the PCI device memory space for device
+ * with SLI-4 interface spec.
+ *
+ * Return codes
+ *     0 - sucessful
+ *     other values - error
+ **/
+static int
+lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba)
+{
+       struct pci_dev *pdev;
+       unsigned long bar0map_len, bar1map_len, bar2map_len;
+       int error = -ENODEV;
+
+       /* Obtain PCI device reference */
+       if (!phba->pcidev)
+               return error;
+       else
+               pdev = phba->pcidev;
+
+       /* Set the device DMA mask size */
+       if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0)
+               if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0)
+                       return error;
+
+       /* Get the bus address of SLI4 device Bar0, Bar1, and Bar2 and the
+        * number of bytes required by each mapping. They are actually
+        * mapping to the PCI BAR regions 1, 2, and 4 by the SLI4 device.
+        */
+       phba->pci_bar0_map = pci_resource_start(pdev, LPFC_SLI4_BAR0);
+       bar0map_len = pci_resource_len(pdev, LPFC_SLI4_BAR0);
+
+       phba->pci_bar1_map = pci_resource_start(pdev, LPFC_SLI4_BAR1);
+       bar1map_len = pci_resource_len(pdev, LPFC_SLI4_BAR1);
+
+       phba->pci_bar2_map = pci_resource_start(pdev, LPFC_SLI4_BAR2);
+       bar2map_len = pci_resource_len(pdev, LPFC_SLI4_BAR2);
+
+       /* Map SLI4 PCI Config Space Register base to a kernel virtual addr */
+       phba->sli4_hba.conf_regs_memmap_p =
+                               ioremap(phba->pci_bar0_map, bar0map_len);
+       if (!phba->sli4_hba.conf_regs_memmap_p) {
+               dev_printk(KERN_ERR, &pdev->dev,
+                          "ioremap failed for SLI4 PCI config registers.\n");
+               goto out;
+       }
+
+       /* Map SLI4 HBA Control Register base to a kernel virtual address. */
+       phba->sli4_hba.ctrl_regs_memmap_p =
+                               ioremap(phba->pci_bar1_map, bar1map_len);
+       if (!phba->sli4_hba.ctrl_regs_memmap_p) {
+               dev_printk(KERN_ERR, &pdev->dev,
+                          "ioremap failed for SLI4 HBA control registers.\n");
+               goto out_iounmap_conf;
+       }
+
+       /* Map SLI4 HBA Doorbell Register base to a kernel virtual address. */
+       phba->sli4_hba.drbl_regs_memmap_p =
+                               ioremap(phba->pci_bar2_map, bar2map_len);
+       if (!phba->sli4_hba.drbl_regs_memmap_p) {
+               dev_printk(KERN_ERR, &pdev->dev,
+                          "ioremap failed for SLI4 HBA doorbell registers.\n");
+               goto out_iounmap_ctrl;
+       }
+
+       /* Set up BAR0 PCI config space register memory map */
+       lpfc_sli4_bar0_register_memmap(phba);
+
+       /* Set up BAR1 register memory map */
+       lpfc_sli4_bar1_register_memmap(phba);
+
+       /* Set up BAR2 register memory map */
+       error = lpfc_sli4_bar2_register_memmap(phba, LPFC_VF0);
+       if (error)
+               goto out_iounmap_all;
+
+       return 0;
+
+out_iounmap_all:
+       iounmap(phba->sli4_hba.drbl_regs_memmap_p);
+out_iounmap_ctrl:
+       iounmap(phba->sli4_hba.ctrl_regs_memmap_p);
+out_iounmap_conf:
+       iounmap(phba->sli4_hba.conf_regs_memmap_p);
+out:
+       return error;
+}
+
+/**
+ * lpfc_sli4_pci_mem_unset - Unset SLI4 HBA PCI memory space.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to unset the PCI device memory space for device
+ * with SLI-4 interface spec.
+ **/
+static void
+lpfc_sli4_pci_mem_unset(struct lpfc_hba *phba)
+{
+       struct pci_dev *pdev;
+
+       /* Obtain PCI device reference */
+       if (!phba->pcidev)
+               return;
+       else
+               pdev = phba->pcidev;
+
+       /* Free coherent DMA memory allocated */
+
+       /* Unmap I/O memory space */
+       iounmap(phba->sli4_hba.drbl_regs_memmap_p);
+       iounmap(phba->sli4_hba.ctrl_regs_memmap_p);
+       iounmap(phba->sli4_hba.conf_regs_memmap_p);
+
+       return;
+}
+
+/**
+ * lpfc_sli_enable_msix - Enable MSI-X interrupt mode on SLI-3 device
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to enable the MSI-X interrupt vectors to device
+ * with SLI-3 interface specs. The kernel function pci_enable_msix() is
+ * called to enable the MSI-X vectors. Note that pci_enable_msix(), once
+ * invoked, enables either all or nothing, depending on the current
+ * availability of PCI vector resources. The device driver is responsible
+ * for calling the individual request_irq() to register each MSI-X vector
+ * with a interrupt handler, which is done in this function. Note that
+ * later when device is unloading, the driver should always call free_irq()
+ * on all MSI-X vectors it has done request_irq() on before calling
+ * pci_disable_msix(). Failure to do so results in a BUG_ON() and a device
+ * will be left with MSI-X enabled and leaks its vectors.
+ *
+ * Return codes
+ *   0 - sucessful
+ *   other values - error
+ **/
+static int
+lpfc_sli_enable_msix(struct lpfc_hba *phba)
+{
+       int rc, i;
+       LPFC_MBOXQ_t *pmb;
+
+       /* Set up MSI-X multi-message vectors */
+       for (i = 0; i < LPFC_MSIX_VECTORS; i++)
+               phba->msix_entries[i].entry = i;
+
+       /* Configure MSI-X capability structure */
+       rc = pci_enable_msix(phba->pcidev, phba->msix_entries,
+                               ARRAY_SIZE(phba->msix_entries));
+       if (rc) {
+               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                               "0420 PCI enable MSI-X failed (%d)\n", rc);
+               goto msi_fail_out;
+       }
+       for (i = 0; i < LPFC_MSIX_VECTORS; i++)
+               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                               "0477 MSI-X entry[%d]: vector=x%x "
+                               "message=%d\n", i,
+                               phba->msix_entries[i].vector,
+                               phba->msix_entries[i].entry);
+       /*
+        * Assign MSI-X vectors to interrupt handlers
+        */
+
+       /* vector-0 is associated to slow-path handler */
+       rc = request_irq(phba->msix_entries[0].vector,
+                        &lpfc_sli_sp_intr_handler, IRQF_SHARED,
+                        LPFC_SP_DRIVER_HANDLER_NAME, phba);
+       if (rc) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+                               "0421 MSI-X slow-path request_irq failed "
+                               "(%d)\n", rc);
+               goto msi_fail_out;
+       }
+
+       /* vector-1 is associated to fast-path handler */
+       rc = request_irq(phba->msix_entries[1].vector,
+                        &lpfc_sli_fp_intr_handler, IRQF_SHARED,
+                        LPFC_FP_DRIVER_HANDLER_NAME, phba);
+
+       if (rc) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+                               "0429 MSI-X fast-path request_irq failed "
+                               "(%d)\n", rc);
+               goto irq_fail_out;
+       }
+
+       /*
+        * Configure HBA MSI-X attention conditions to messages
+        */
+       pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+
+       if (!pmb) {
+               rc = -ENOMEM;
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0474 Unable to allocate memory for issuing "
+                               "MBOX_CONFIG_MSI command\n");
+               goto mem_fail_out;
+       }
+       rc = lpfc_config_msi(phba, pmb);
+       if (rc)
+               goto mbx_fail_out;
+       rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
+       if (rc != MBX_SUCCESS) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
+                               "0351 Config MSI mailbox command failed, "
+                               "mbxCmd x%x, mbxStatus x%x\n",
+                               pmb->u.mb.mbxCommand, pmb->u.mb.mbxStatus);
+               goto mbx_fail_out;
+       }
+
+       /* Free memory allocated for mailbox command */
+       mempool_free(pmb, phba->mbox_mem_pool);
+       return rc;
+
+mbx_fail_out:
+       /* Free memory allocated for mailbox command */
+       mempool_free(pmb, phba->mbox_mem_pool);
+
+mem_fail_out:
+       /* free the irq already requested */
+       free_irq(phba->msix_entries[1].vector, phba);
+
+irq_fail_out:
+       /* free the irq already requested */
+       free_irq(phba->msix_entries[0].vector, phba);
+
+msi_fail_out:
+       /* Unconfigure MSI-X capability structure */
+       pci_disable_msix(phba->pcidev);
+       return rc;
+}
+
+/**
+ * lpfc_sli_disable_msix - Disable MSI-X interrupt mode on SLI-3 device.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to release the MSI-X vectors and then disable the
+ * MSI-X interrupt mode to device with SLI-3 interface spec.
+ **/
+static void
+lpfc_sli_disable_msix(struct lpfc_hba *phba)
+{
+       int i;
+
+       /* Free up MSI-X multi-message vectors */
+       for (i = 0; i < LPFC_MSIX_VECTORS; i++)
+               free_irq(phba->msix_entries[i].vector, phba);
+       /* Disable MSI-X */
+       pci_disable_msix(phba->pcidev);
+
+       return;
+}
+
+/**
+ * lpfc_sli_enable_msi - Enable MSI interrupt mode on SLI-3 device.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to enable the MSI interrupt mode to device with
+ * SLI-3 interface spec. The kernel function pci_enable_msi() is called to
+ * enable the MSI vector. The device driver is responsible for calling the
+ * request_irq() to register MSI vector with a interrupt the handler, which
+ * is done in this function.
+ *
+ * Return codes
+ *     0 - sucessful
+ *     other values - error
+ */
+static int
+lpfc_sli_enable_msi(struct lpfc_hba *phba)
+{
+       int rc;
+
+       rc = pci_enable_msi(phba->pcidev);
+       if (!rc)
+               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                               "0462 PCI enable MSI mode success.\n");
+       else {
+               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                               "0471 PCI enable MSI mode failed (%d)\n", rc);
+               return rc;
+       }
+
+       rc = request_irq(phba->pcidev->irq, lpfc_sli_intr_handler,
+                        IRQF_SHARED, LPFC_DRIVER_NAME, phba);
+       if (rc) {
+               pci_disable_msi(phba->pcidev);
+               lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+                               "0478 MSI request_irq failed (%d)\n", rc);
+       }
+       return rc;
+}
+
+/**
+ * lpfc_sli_disable_msi - Disable MSI interrupt mode to SLI-3 device.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to disable the MSI interrupt mode to device with
+ * SLI-3 interface spec. The driver calls free_irq() on MSI vector it has
+ * done request_irq() on before calling pci_disable_msi(). Failure to do so
+ * results in a BUG_ON() and a device will be left with MSI enabled and leaks
+ * its vector.
+ */
+static void
+lpfc_sli_disable_msi(struct lpfc_hba *phba)
+{
+       free_irq(phba->pcidev->irq, phba);
+       pci_disable_msi(phba->pcidev);
+       return;
+}
+
+/**
+ * lpfc_sli_enable_intr - Enable device interrupt to SLI-3 device.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to enable device interrupt and associate driver's
+ * interrupt handler(s) to interrupt vector(s) to device with SLI-3 interface
+ * spec. Depends on the interrupt mode configured to the driver, the driver
+ * will try to fallback from the configured interrupt mode to an interrupt
+ * mode which is supported by the platform, kernel, and device in the order
+ * of:
+ * MSI-X -> MSI -> IRQ.
+ *
+ * Return codes
+ *   0 - sucessful
+ *   other values - error
+ **/
+static uint32_t
+lpfc_sli_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode)
+{
+       uint32_t intr_mode = LPFC_INTR_ERROR;
+       int retval;
+
+       if (cfg_mode == 2) {
+               /* Need to issue conf_port mbox cmd before conf_msi mbox cmd */
+               retval = lpfc_sli_config_port(phba, LPFC_SLI_REV3);
+               if (!retval) {
+                       /* Now, try to enable MSI-X interrupt mode */
+                       retval = lpfc_sli_enable_msix(phba);
+                       if (!retval) {
+                               /* Indicate initialization to MSI-X mode */
+                               phba->intr_type = MSIX;
+                               intr_mode = 2;
+                       }
+               }
+       }
+
+       /* Fallback to MSI if MSI-X initialization failed */
+       if (cfg_mode >= 1 && phba->intr_type == NONE) {
+               retval = lpfc_sli_enable_msi(phba);
+               if (!retval) {
+                       /* Indicate initialization to MSI mode */
+                       phba->intr_type = MSI;
+                       intr_mode = 1;
+               }
+       }
+
+       /* Fallback to INTx if both MSI-X/MSI initalization failed */
+       if (phba->intr_type == NONE) {
+               retval = request_irq(phba->pcidev->irq, lpfc_sli_intr_handler,
+                                    IRQF_SHARED, LPFC_DRIVER_NAME, phba);
+               if (!retval) {
+                       /* Indicate initialization to INTx mode */
+                       phba->intr_type = INTx;
+                       intr_mode = 0;
+               }
+       }
+       return intr_mode;
+}
+
+/**
+ * lpfc_sli_disable_intr - Disable device interrupt to SLI-3 device.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to disable device interrupt and disassociate the
+ * driver's interrupt handler(s) from interrupt vector(s) to device with
+ * SLI-3 interface spec. Depending on the interrupt mode, the driver will
+ * release the interrupt vector(s) for the message signaled interrupt.
+ **/
+static void
+lpfc_sli_disable_intr(struct lpfc_hba *phba)
+{
+       /* Disable the currently initialized interrupt mode */
+       if (phba->intr_type == MSIX)
+               lpfc_sli_disable_msix(phba);
+       else if (phba->intr_type == MSI)
+               lpfc_sli_disable_msi(phba);
+       else if (phba->intr_type == INTx)
+               free_irq(phba->pcidev->irq, phba);
+
+       /* Reset interrupt management states */
+       phba->intr_type = NONE;
+       phba->sli.slistat.sli_intr = 0;
+
+       return;
+}
+
+/**
+ * lpfc_sli4_enable_msix - Enable MSI-X interrupt mode to SLI-4 device
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to enable the MSI-X interrupt vectors to device
+ * with SLI-4 interface spec. The kernel function pci_enable_msix() is called
+ * to enable the MSI-X vectors. Note that pci_enable_msix(), once invoked,
+ * enables either all or nothing, depending on the current availability of
+ * PCI vector resources. The device driver is responsible for calling the
+ * individual request_irq() to register each MSI-X vector with a interrupt
+ * handler, which is done in this function. Note that later when device is
+ * unloading, the driver should always call free_irq() on all MSI-X vectors
+ * it has done request_irq() on before calling pci_disable_msix(). Failure
+ * to do so results in a BUG_ON() and a device will be left with MSI-X
+ * enabled and leaks its vectors.
+ *
+ * Return codes
+ * 0 - sucessful
+ * other values - error
+ **/
+static int
+lpfc_sli4_enable_msix(struct lpfc_hba *phba)
+{
+       int rc, index;
+
+       /* Set up MSI-X multi-message vectors */
+       for (index = 0; index < phba->sli4_hba.cfg_eqn; index++)
+               phba->sli4_hba.msix_entries[index].entry = index;
+
+       /* Configure MSI-X capability structure */
+       rc = pci_enable_msix(phba->pcidev, phba->sli4_hba.msix_entries,
+                            phba->sli4_hba.cfg_eqn);
+       if (rc) {
+               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                               "0484 PCI enable MSI-X failed (%d)\n", rc);
+               goto msi_fail_out;
+       }
+       /* Log MSI-X vector assignment */
+       for (index = 0; index < phba->sli4_hba.cfg_eqn; index++)
+               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                               "0489 MSI-X entry[%d]: vector=x%x "
+                               "message=%d\n", index,
+                               phba->sli4_hba.msix_entries[index].vector,
+                               phba->sli4_hba.msix_entries[index].entry);
+       /*
+        * Assign MSI-X vectors to interrupt handlers
+        */
+
+       /* The first vector must associated to slow-path handler for MQ */
+       rc = request_irq(phba->sli4_hba.msix_entries[0].vector,
+                        &lpfc_sli4_sp_intr_handler, IRQF_SHARED,
+                        LPFC_SP_DRIVER_HANDLER_NAME, phba);
+       if (rc) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+                               "0485 MSI-X slow-path request_irq failed "
+                               "(%d)\n", rc);
+               goto msi_fail_out;
+       }
+
+       /* The rest of the vector(s) are associated to fast-path handler(s) */
+       for (index = 1; index < phba->sli4_hba.cfg_eqn; index++) {
+               phba->sli4_hba.fcp_eq_hdl[index - 1].idx = index - 1;
+               phba->sli4_hba.fcp_eq_hdl[index - 1].phba = phba;
+               rc = request_irq(phba->sli4_hba.msix_entries[index].vector,
+                                &lpfc_sli4_fp_intr_handler, IRQF_SHARED,
+                                LPFC_FP_DRIVER_HANDLER_NAME,
+                                &phba->sli4_hba.fcp_eq_hdl[index - 1]);
+               if (rc) {
+                       lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+                                       "0486 MSI-X fast-path (%d) "
+                                       "request_irq failed (%d)\n", index, rc);
+                       goto cfg_fail_out;
+               }
+       }
+
+       return rc;
+
+cfg_fail_out:
+       /* free the irq already requested */
+       for (--index; index >= 1; index--)
+               free_irq(phba->sli4_hba.msix_entries[index - 1].vector,
+                        &phba->sli4_hba.fcp_eq_hdl[index - 1]);
+
+       /* free the irq already requested */
+       free_irq(phba->sli4_hba.msix_entries[0].vector, phba);
+
+msi_fail_out:
+       /* Unconfigure MSI-X capability structure */
+       pci_disable_msix(phba->pcidev);
+       return rc;
+}
+
+/**
+ * lpfc_sli4_disable_msix - Disable MSI-X interrupt mode to SLI-4 device
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to release the MSI-X vectors and then disable the
+ * MSI-X interrupt mode to device with SLI-4 interface spec.
+ **/
+static void
+lpfc_sli4_disable_msix(struct lpfc_hba *phba)
+{
+       int index;
+
+       /* Free up MSI-X multi-message vectors */
+       free_irq(phba->sli4_hba.msix_entries[0].vector, phba);
+
+       for (index = 1; index < phba->sli4_hba.cfg_eqn; index++)
+               free_irq(phba->sli4_hba.msix_entries[index].vector,
+                        &phba->sli4_hba.fcp_eq_hdl[index - 1]);
+       /* Disable MSI-X */
+       pci_disable_msix(phba->pcidev);
+
+       return;
+}
+
+/**
+ * lpfc_sli4_enable_msi - Enable MSI interrupt mode to SLI-4 device
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to enable the MSI interrupt mode to device with
+ * SLI-4 interface spec. The kernel function pci_enable_msi() is called
+ * to enable the MSI vector. The device driver is responsible for calling
+ * the request_irq() to register MSI vector with a interrupt the handler,
+ * which is done in this function.
+ *
+ * Return codes
+ *     0 - sucessful
+ *     other values - error
+ **/
+static int
+lpfc_sli4_enable_msi(struct lpfc_hba *phba)
+{
+       int rc, index;
+
+       rc = pci_enable_msi(phba->pcidev);
+       if (!rc)
+               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                               "0487 PCI enable MSI mode success.\n");
+       else {
+               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                               "0488 PCI enable MSI mode failed (%d)\n", rc);
+               return rc;
+       }
+
+       rc = request_irq(phba->pcidev->irq, lpfc_sli4_intr_handler,
+                        IRQF_SHARED, LPFC_DRIVER_NAME, phba);
+       if (rc) {
+               pci_disable_msi(phba->pcidev);
+               lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+                               "0490 MSI request_irq failed (%d)\n", rc);
+       }
+
+       for (index = 0; index < phba->cfg_fcp_eq_count; index++) {
+               phba->sli4_hba.fcp_eq_hdl[index].idx = index;
+               phba->sli4_hba.fcp_eq_hdl[index].phba = phba;
+       }
+
+       return rc;
+}
+
+/**
+ * lpfc_sli4_disable_msi - Disable MSI interrupt mode to SLI-4 device
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to disable the MSI interrupt mode to device with
+ * SLI-4 interface spec. The driver calls free_irq() on MSI vector it has
+ * done request_irq() on before calling pci_disable_msi(). Failure to do so
+ * results in a BUG_ON() and a device will be left with MSI enabled and leaks
+ * its vector.
+ **/
+static void
+lpfc_sli4_disable_msi(struct lpfc_hba *phba)
+{
+       free_irq(phba->pcidev->irq, phba);
+       pci_disable_msi(phba->pcidev);
+       return;
+}
+
+/**
+ * lpfc_sli4_enable_intr - Enable device interrupt to SLI-4 device
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to enable device interrupt and associate driver's
+ * interrupt handler(s) to interrupt vector(s) to device with SLI-4
+ * interface spec. Depends on the interrupt mode configured to the driver,
+ * the driver will try to fallback from the configured interrupt mode to an
+ * interrupt mode which is supported by the platform, kernel, and device in
+ * the order of:
+ * MSI-X -> MSI -> IRQ.
+ *
+ * Return codes
+ *     0 - sucessful
+ *     other values - error
+ **/
+static uint32_t
+lpfc_sli4_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode)
+{
+       uint32_t intr_mode = LPFC_INTR_ERROR;
+       int retval, index;
+
+       if (cfg_mode == 2) {
+               /* Preparation before conf_msi mbox cmd */
+               retval = 0;
+               if (!retval) {
+                       /* Now, try to enable MSI-X interrupt mode */
+                       retval = lpfc_sli4_enable_msix(phba);
+                       if (!retval) {
+                               /* Indicate initialization to MSI-X mode */
+                               phba->intr_type = MSIX;
+                               intr_mode = 2;
+                       }
+               }
+       }
+
+       /* Fallback to MSI if MSI-X initialization failed */
+       if (cfg_mode >= 1 && phba->intr_type == NONE) {
+               retval = lpfc_sli4_enable_msi(phba);
+               if (!retval) {
+                       /* Indicate initialization to MSI mode */
+                       phba->intr_type = MSI;
+                       intr_mode = 1;
+               }
+       }
+
+       /* Fallback to INTx if both MSI-X/MSI initalization failed */
+       if (phba->intr_type == NONE) {
+               retval = request_irq(phba->pcidev->irq, lpfc_sli4_intr_handler,
+                                    IRQF_SHARED, LPFC_DRIVER_NAME, phba);
+               if (!retval) {
+                       /* Indicate initialization to INTx mode */
+                       phba->intr_type = INTx;
+                       intr_mode = 0;
+                       for (index = 0; index < phba->cfg_fcp_eq_count;
+                            index++) {
+                               phba->sli4_hba.fcp_eq_hdl[index].idx = index;
+                               phba->sli4_hba.fcp_eq_hdl[index].phba = phba;
+                       }
+               }
+       }
+       return intr_mode;
+}
+
+/**
+ * lpfc_sli4_disable_intr - Disable device interrupt to SLI-4 device
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to disable device interrupt and disassociate
+ * the driver's interrupt handler(s) from interrupt vector(s) to device
+ * with SLI-4 interface spec. Depending on the interrupt mode, the driver
+ * will release the interrupt vector(s) for the message signaled interrupt.
+ **/
+static void
+lpfc_sli4_disable_intr(struct lpfc_hba *phba)
+{
+       /* Disable the currently initialized interrupt mode */
+       if (phba->intr_type == MSIX)
+               lpfc_sli4_disable_msix(phba);
+       else if (phba->intr_type == MSI)
+               lpfc_sli4_disable_msi(phba);
+       else if (phba->intr_type == INTx)
+               free_irq(phba->pcidev->irq, phba);
+
+       /* Reset interrupt management states */
+       phba->intr_type = NONE;
+       phba->sli.slistat.sli_intr = 0;
+
+       return;
+}
+
+/**
+ * lpfc_unset_hba - Unset SLI3 hba device initialization
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to unset the HBA device initialization steps to
+ * a device with SLI-3 interface spec.
+ **/
+static void
+lpfc_unset_hba(struct lpfc_hba *phba)
+{
+       struct lpfc_vport *vport = phba->pport;
+       struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
+
+       spin_lock_irq(shost->host_lock);
+       vport->load_flag |= FC_UNLOADING;
+       spin_unlock_irq(shost->host_lock);
+
+       lpfc_stop_hba_timers(phba);
+
+       phba->pport->work_port_events = 0;
+
+       lpfc_sli_hba_down(phba);
+
+       lpfc_sli_brdrestart(phba);
+
+       lpfc_sli_disable_intr(phba);
+
+       return;
+}
+
+/**
+ * lpfc_sli4_unset_hba - Unset SLI4 hba device initialization.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to unset the HBA device initialization steps to
+ * a device with SLI-4 interface spec.
+ **/
+static void
+lpfc_sli4_unset_hba(struct lpfc_hba *phba)
+{
+       struct lpfc_vport *vport = phba->pport;
+       struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
+
+       spin_lock_irq(shost->host_lock);
+       vport->load_flag |= FC_UNLOADING;
+       spin_unlock_irq(shost->host_lock);
+
+       phba->pport->work_port_events = 0;
+
+       lpfc_sli4_hba_down(phba);
+
+       lpfc_sli4_disable_intr(phba);
+
+       return;
+}
+
+/**
+ * lpfc_sli4_hba_unset - Unset the fcoe hba
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called in the SLI4 code path to reset the HBA's FCoE
+ * function. The caller is not required to hold any lock. This routine
+ * issues PCI function reset mailbox command to reset the FCoE function.
+ * At the end of the function, it calls lpfc_hba_down_post function to
+ * free any pending commands.
+ **/
+static void
+lpfc_sli4_hba_unset(struct lpfc_hba *phba)
+{
+       int wait_cnt = 0;
+       LPFC_MBOXQ_t *mboxq;
+
+       lpfc_stop_hba_timers(phba);
+       phba->sli4_hba.intr_enable = 0;
+
+       /*
+        * Gracefully wait out the potential current outstanding asynchronous
+        * mailbox command.
+        */
+
+       /* First, block any pending async mailbox command from posted */
+       spin_lock_irq(&phba->hbalock);
+       phba->sli.sli_flag |= LPFC_SLI_ASYNC_MBX_BLK;
+       spin_unlock_irq(&phba->hbalock);
+       /* Now, trying to wait it out if we can */
+       while (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) {
+               msleep(10);
+               if (++wait_cnt > LPFC_ACTIVE_MBOX_WAIT_CNT)
+                       break;
+       }
+       /* Forcefully release the outstanding mailbox command if timed out */
+       if (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) {
+               spin_lock_irq(&phba->hbalock);
+               mboxq = phba->sli.mbox_active;
+               mboxq->u.mb.mbxStatus = MBX_NOT_FINISHED;
+               __lpfc_mbox_cmpl_put(phba, mboxq);
+               phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+               phba->sli.mbox_active = NULL;
+               spin_unlock_irq(&phba->hbalock);
+       }
+
+       /* Tear down the queues in the HBA */
+       lpfc_sli4_queue_unset(phba);
+
+       /* Disable PCI subsystem interrupt */
+       lpfc_sli4_disable_intr(phba);
+
+       /* Stop kthread signal shall trigger work_done one more time */
+       kthread_stop(phba->worker_thread);
+
+       /* Stop the SLI4 device port */
+       phba->pport->work_port_events = 0;
+}
+
+/**
+ * lpfc_pci_probe_one_s3 - PCI probe func to reg SLI-3 device to PCI subsystem.
+ * @pdev: pointer to PCI device
+ * @pid: pointer to PCI device identifier
+ *
+ * This routine is to be called to attach a device with SLI-3 interface spec
+ * to the PCI subsystem. When an Emulex HBA with SLI-3 interface spec is
+ * presented on PCI bus, the kernel PCI subsystem looks at PCI device-specific
+ * information of the device and driver to see if the driver state that it can
+ * support this kind of device. If the match is successful, the driver core
+ * invokes this routine. If this routine determines it can claim the HBA, it
+ * does all the initialization that it needs to do to handle the HBA properly.
+ *
+ * Return code
+ *     0 - driver can claim the device
+ *     negative value - driver can not claim the device
+ **/
+static int __devinit
+lpfc_pci_probe_one_s3(struct pci_dev *pdev, const struct pci_device_id *pid)
+{
+       struct lpfc_hba   *phba;
+       struct lpfc_vport *vport = NULL;
+       int error;
+       uint32_t cfg_mode, intr_mode;
+
+       /* Allocate memory for HBA structure */
+       phba = lpfc_hba_alloc(pdev);
+       if (!phba)
+               return -ENOMEM;
+
+       /* Perform generic PCI device enabling operation */
+       error = lpfc_enable_pci_dev(phba);
+       if (error) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1401 Failed to enable pci device.\n");
+               goto out_free_phba;
+       }
+
+       /* Set up SLI API function jump table for PCI-device group-0 HBAs */
+       error = lpfc_api_table_setup(phba, LPFC_PCI_DEV_LP);
+       if (error)
+               goto out_disable_pci_dev;
+
+       /* Set up SLI-3 specific device PCI memory space */
+       error = lpfc_sli_pci_mem_setup(phba);
+       if (error) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1402 Failed to set up pci memory space.\n");
+               goto out_disable_pci_dev;
+       }
+
+       /* Set up phase-1 common device driver resources */
+       error = lpfc_setup_driver_resource_phase1(phba);
+       if (error) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1403 Failed to set up driver resource.\n");
+               goto out_unset_pci_mem_s3;
+       }
+
+       /* Set up SLI-3 specific device driver resources */
+       error = lpfc_sli_driver_resource_setup(phba);
+       if (error) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1404 Failed to set up driver resource.\n");
+               goto out_unset_pci_mem_s3;
+       }
+
+       /* Initialize and populate the iocb list per host */
+       error = lpfc_init_iocb_list(phba, LPFC_IOCB_LIST_CNT);
+       if (error) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1405 Failed to initialize iocb list.\n");
+               goto out_unset_driver_resource_s3;
+       }
+
+       /* Set up common device driver resources */
+       error = lpfc_setup_driver_resource_phase2(phba);
+       if (error) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1406 Failed to set up driver resource.\n");
+               goto out_free_iocb_list;
+       }
+
+       /* Create SCSI host to the physical port */
+       error = lpfc_create_shost(phba);
+       if (error) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1407 Failed to create scsi host.\n");
+               goto out_unset_driver_resource;
+       }
+
+       /* Configure sysfs attributes */
+       vport = phba->pport;
+       error = lpfc_alloc_sysfs_attr(vport);
+       if (error) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1476 Failed to allocate sysfs attr\n");
+               goto out_destroy_shost;
+       }
+
+       /* Now, trying to enable interrupt and bring up the device */
+       cfg_mode = phba->cfg_use_msi;
+       while (true) {
+               /* Put device to a known state before enabling interrupt */
+               lpfc_stop_port(phba);
+               /* Configure and enable interrupt */
+               intr_mode = lpfc_sli_enable_intr(phba, cfg_mode);
+               if (intr_mode == LPFC_INTR_ERROR) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "0431 Failed to enable interrupt.\n");
+                       error = -ENODEV;
+                       goto out_free_sysfs_attr;
+               }
+               /* SLI-3 HBA setup */
+               if (lpfc_sli_hba_setup(phba)) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "1477 Failed to set up hba\n");
+                       error = -ENODEV;
+                       goto out_remove_device;
+               }
+
+               /* Wait 50ms for the interrupts of previous mailbox commands */
+               msleep(50);
+               /* Check active interrupts on message signaled interrupts */
+               if (intr_mode == 0 ||
+                   phba->sli.slistat.sli_intr > LPFC_MSIX_VECTORS) {
+                       /* Log the current active interrupt mode */
+                       phba->intr_mode = intr_mode;
+                       lpfc_log_intr_mode(phba, intr_mode);
+                       break;
+               } else {
+                       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                                       "0447 Configure interrupt mode (%d) "
+                                       "failed active interrupt test.\n",
+                                       intr_mode);
+                       /* Disable the current interrupt mode */
+                       lpfc_sli_disable_intr(phba);
+                       /* Try next level of interrupt mode */
+                       cfg_mode = --intr_mode;
+               }
+       }
+
+       /* Perform post initialization setup */
+       lpfc_post_init_setup(phba);
+
+       /* Check if there are static vports to be created. */
+       lpfc_create_static_vport(phba);
+
+       return 0;
+
+out_remove_device:
+       lpfc_unset_hba(phba);
+out_free_sysfs_attr:
+       lpfc_free_sysfs_attr(vport);
+out_destroy_shost:
+       lpfc_destroy_shost(phba);
+out_unset_driver_resource:
+       lpfc_unset_driver_resource_phase2(phba);
+out_free_iocb_list:
+       lpfc_free_iocb_list(phba);
+out_unset_driver_resource_s3:
+       lpfc_sli_driver_resource_unset(phba);
+out_unset_pci_mem_s3:
+       lpfc_sli_pci_mem_unset(phba);
+out_disable_pci_dev:
+       lpfc_disable_pci_dev(phba);
+out_free_phba:
+       lpfc_hba_free(phba);
+       return error;
+}
+
+/**
+ * lpfc_pci_remove_one_s3 - PCI func to unreg SLI-3 device from PCI subsystem.
+ * @pdev: pointer to PCI device
+ *
+ * This routine is to be called to disattach a device with SLI-3 interface
+ * spec from PCI subsystem. When an Emulex HBA with SLI-3 interface spec is
+ * removed from PCI bus, it performs all the necessary cleanup for the HBA
+ * device to be removed from the PCI subsystem properly.
+ **/
+static void __devexit
+lpfc_pci_remove_one_s3(struct pci_dev *pdev)
+{
+       struct Scsi_Host  *shost = pci_get_drvdata(pdev);
+       struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+       struct lpfc_vport **vports;
+       struct lpfc_hba   *phba = vport->phba;
+       int i;
+       int bars = pci_select_bars(pdev, IORESOURCE_MEM);
+
+       spin_lock_irq(&phba->hbalock);
+       vport->load_flag |= FC_UNLOADING;
+       spin_unlock_irq(&phba->hbalock);
+
+       lpfc_free_sysfs_attr(vport);
+
+       /* Release all the vports against this physical port */
+       vports = lpfc_create_vport_work_array(phba);
+       if (vports != NULL)
+               for (i = 1; i <= phba->max_vports && vports[i] != NULL; i++)
+                       fc_vport_terminate(vports[i]->fc_vport);
+       lpfc_destroy_vport_work_array(phba, vports);
+
+       /* Remove FC host and then SCSI host with the physical port */
+       fc_remove_host(shost);
+       scsi_remove_host(shost);
+       lpfc_cleanup(vport);
+
+       /*
+        * Bring down the SLI Layer. This step disable all interrupts,
+        * clears the rings, discards all mailbox commands, and resets
+        * the HBA.
+        */
+
+       /* HBA interrupt will be diabled after this call */
+       lpfc_sli_hba_down(phba);
+       /* Stop kthread signal shall trigger work_done one more time */
+       kthread_stop(phba->worker_thread);
+       /* Final cleanup of txcmplq and reset the HBA */
+       lpfc_sli_brdrestart(phba);
+
+       lpfc_stop_hba_timers(phba);
+       spin_lock_irq(&phba->hbalock);
+       list_del_init(&vport->listentry);
+       spin_unlock_irq(&phba->hbalock);
+
+       lpfc_debugfs_terminate(vport);
+
+       /* Disable interrupt */
+       lpfc_sli_disable_intr(phba);
+
+       pci_set_drvdata(pdev, NULL);
+       scsi_host_put(shost);
+
+       /*
+        * Call scsi_free before mem_free since scsi bufs are released to their
+        * corresponding pools here.
+        */
+       lpfc_scsi_free(phba);
+       lpfc_mem_free_all(phba);
+
+       dma_free_coherent(&pdev->dev, lpfc_sli_hbq_size(),
+                         phba->hbqslimp.virt, phba->hbqslimp.phys);
+
+       /* Free resources associated with SLI2 interface */
+       dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE,
+                         phba->slim2p.virt, phba->slim2p.phys);
+
+       /* unmap adapter SLIM and Control Registers */
+       iounmap(phba->ctrl_regs_memmap_p);
+       iounmap(phba->slim_memmap_p);
+
+       lpfc_hba_free(phba);
 
-out_remove_device:
-       spin_lock_irq(shost->host_lock);
-       vport->load_flag |= FC_UNLOADING;
-       spin_unlock_irq(shost->host_lock);
-       lpfc_stop_phba_timers(phba);
-       phba->pport->work_port_events = 0;
-       lpfc_disable_intr(phba);
-       lpfc_sli_hba_down(phba);
-       lpfc_sli_brdrestart(phba);
-out_free_sysfs_attr:
-       lpfc_free_sysfs_attr(vport);
-out_destroy_port:
-       destroy_port(vport);
-out_kthread_stop:
-       kthread_stop(phba->worker_thread);
-out_free_iocbq:
-       list_for_each_entry_safe(iocbq_entry, iocbq_next,
-                                               &phba->lpfc_iocb_list, list) {
-               kfree(iocbq_entry);
-               phba->total_iocbq_bufs--;
-       }
-       lpfc_mem_free(phba);
-out_free_hbqslimp:
-       dma_free_coherent(&pdev->dev, lpfc_sli_hbq_size(),
-                         phba->hbqslimp.virt, phba->hbqslimp.phys);
-out_free_slim:
-       dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE,
-                         phba->slim2p.virt, phba->slim2p.phys);
-out_iounmap:
-       iounmap(phba->ctrl_regs_memmap_p);
-out_iounmap_slim:
-       iounmap(phba->slim_memmap_p);
-out_idr_remove:
-       idr_remove(&lpfc_hba_index, phba->brd_no);
-out_free_phba:
-       kfree(phba);
-out_release_regions:
        pci_release_selected_regions(pdev, bars);
-out_disable_device:
        pci_disable_device(pdev);
-out:
-       pci_set_drvdata(pdev, NULL);
-       if (shost)
-               scsi_host_put(shost);
+}
+
+/**
+ * lpfc_pci_suspend_one_s3 - PCI func to suspend SLI-3 device for power mgmnt
+ * @pdev: pointer to PCI device
+ * @msg: power management message
+ *
+ * This routine is to be called from the kernel's PCI subsystem to support
+ * system Power Management (PM) to device with SLI-3 interface spec. When
+ * PM invokes this method, it quiesces the device by stopping the driver's
+ * worker thread for the device, turning off device's interrupt and DMA,
+ * and bring the device offline. Note that as the driver implements the
+ * minimum PM requirements to a power-aware driver's PM support for the
+ * suspend/resume -- all the possible PM messages (SUSPEND, HIBERNATE, FREEZE)
+ * to the suspend() method call will be treated as SUSPEND and the driver will
+ * fully reinitialize its device during resume() method call, the driver will
+ * set device to PCI_D3hot state in PCI config space instead of setting it
+ * according to the @msg provided by the PM.
+ *
+ * Return code
+ *     0 - driver suspended the device
+ *     Error otherwise
+ **/
+static int
+lpfc_pci_suspend_one_s3(struct pci_dev *pdev, pm_message_t msg)
+{
+       struct Scsi_Host *shost = pci_get_drvdata(pdev);
+       struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                       "0473 PCI device Power Management suspend.\n");
+
+       /* Bring down the device */
+       lpfc_offline_prep(phba);
+       lpfc_offline(phba);
+       kthread_stop(phba->worker_thread);
+
+       /* Disable interrupt from device */
+       lpfc_sli_disable_intr(phba);
+
+       /* Save device state to PCI config space */
+       pci_save_state(pdev);
+       pci_set_power_state(pdev, PCI_D3hot);
+
+       return 0;
+}
+
+/**
+ * lpfc_pci_resume_one_s3 - PCI func to resume SLI-3 device for power mgmnt
+ * @pdev: pointer to PCI device
+ *
+ * This routine is to be called from the kernel's PCI subsystem to support
+ * system Power Management (PM) to device with SLI-3 interface spec. When PM
+ * invokes this method, it restores the device's PCI config space state and
+ * fully reinitializes the device and brings it online. Note that as the
+ * driver implements the minimum PM requirements to a power-aware driver's
+ * PM for suspend/resume -- all the possible PM messages (SUSPEND, HIBERNATE,
+ * FREEZE) to the suspend() method call will be treated as SUSPEND and the
+ * driver will fully reinitialize its device during resume() method call,
+ * the device will be set to PCI_D0 directly in PCI config space before
+ * restoring the state.
+ *
+ * Return code
+ *     0 - driver suspended the device
+ *     Error otherwise
+ **/
+static int
+lpfc_pci_resume_one_s3(struct pci_dev *pdev)
+{
+       struct Scsi_Host *shost = pci_get_drvdata(pdev);
+       struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+       uint32_t intr_mode;
+       int error;
+
+       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                       "0452 PCI device Power Management resume.\n");
+
+       /* Restore device state from PCI config space */
+       pci_set_power_state(pdev, PCI_D0);
+       pci_restore_state(pdev);
+       if (pdev->is_busmaster)
+               pci_set_master(pdev);
+
+       /* Startup the kernel thread for this host adapter. */
+       phba->worker_thread = kthread_run(lpfc_do_work, phba,
+                                       "lpfc_worker_%d", phba->brd_no);
+       if (IS_ERR(phba->worker_thread)) {
+               error = PTR_ERR(phba->worker_thread);
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0434 PM resume failed to start worker "
+                               "thread: error=x%x.\n", error);
+               return error;
+       }
+
+       /* Configure and enable interrupt */
+       intr_mode = lpfc_sli_enable_intr(phba, phba->intr_mode);
+       if (intr_mode == LPFC_INTR_ERROR) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0430 PM resume Failed to enable interrupt\n");
+               return -EIO;
+       } else
+               phba->intr_mode = intr_mode;
+
+       /* Restart HBA and bring it online */
+       lpfc_sli_brdrestart(phba);
+       lpfc_online(phba);
+
+       /* Log the current active interrupt mode */
+       lpfc_log_intr_mode(phba, phba->intr_mode);
+
+       return 0;
+}
+
+/**
+ * lpfc_io_error_detected_s3 - Method for handling SLI-3 device PCI I/O error
+ * @pdev: pointer to PCI device.
+ * @state: the current PCI connection state.
+ *
+ * This routine is called from the PCI subsystem for I/O error handling to
+ * device with SLI-3 interface spec. This function is called by the PCI
+ * subsystem after a PCI bus error affecting this device has been detected.
+ * When this function is invoked, it will need to stop all the I/Os and
+ * interrupt(s) to the device. Once that is done, it will return
+ * PCI_ERS_RESULT_NEED_RESET for the PCI subsystem to perform proper recovery
+ * as desired.
+ *
+ * Return codes
+ *     PCI_ERS_RESULT_NEED_RESET - need to reset before recovery
+ *     PCI_ERS_RESULT_DISCONNECT - device could not be recovered
+ **/
+static pci_ers_result_t
+lpfc_io_error_detected_s3(struct pci_dev *pdev, pci_channel_state_t state)
+{
+       struct Scsi_Host *shost = pci_get_drvdata(pdev);
+       struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+       struct lpfc_sli *psli = &phba->sli;
+       struct lpfc_sli_ring  *pring;
+
+       if (state == pci_channel_io_perm_failure) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0472 PCI channel I/O permanent failure\n");
+               /* Block all SCSI devices' I/Os on the host */
+               lpfc_scsi_dev_block(phba);
+               /* Clean up all driver's outstanding SCSI I/Os */
+               lpfc_sli_flush_fcp_rings(phba);
+               return PCI_ERS_RESULT_DISCONNECT;
+       }
+
+       pci_disable_device(pdev);
+       /*
+        * There may be I/Os dropped by the firmware.
+        * Error iocb (I/O) on txcmplq and let the SCSI layer
+        * retry it after re-establishing link.
+        */
+       pring = &psli->ring[psli->fcp_ring];
+       lpfc_sli_abort_iocb_ring(phba, pring);
+
+       /* Disable interrupt */
+       lpfc_sli_disable_intr(phba);
+
+       /* Request a slot reset. */
+       return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * lpfc_io_slot_reset_s3 - Method for restarting PCI SLI-3 device from scratch.
+ * @pdev: pointer to PCI device.
+ *
+ * This routine is called from the PCI subsystem for error handling to
+ * device with SLI-3 interface spec. This is called after PCI bus has been
+ * reset to restart the PCI card from scratch, as if from a cold-boot.
+ * During the PCI subsystem error recovery, after driver returns
+ * PCI_ERS_RESULT_NEED_RESET, the PCI subsystem will perform proper error
+ * recovery and then call this routine before calling the .resume method
+ * to recover the device. This function will initialize the HBA device,
+ * enable the interrupt, but it will just put the HBA to offline state
+ * without passing any I/O traffic.
+ *
+ * Return codes
+ *     PCI_ERS_RESULT_RECOVERED - the device has been recovered
+ *     PCI_ERS_RESULT_DISCONNECT - device could not be recovered
+ */
+static pci_ers_result_t
+lpfc_io_slot_reset_s3(struct pci_dev *pdev)
+{
+       struct Scsi_Host *shost = pci_get_drvdata(pdev);
+       struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+       struct lpfc_sli *psli = &phba->sli;
+       uint32_t intr_mode;
+
+       dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n");
+       if (pci_enable_device_mem(pdev)) {
+               printk(KERN_ERR "lpfc: Cannot re-enable "
+                       "PCI device after reset.\n");
+               return PCI_ERS_RESULT_DISCONNECT;
+       }
+
+       pci_restore_state(pdev);
+       if (pdev->is_busmaster)
+               pci_set_master(pdev);
+
+       spin_lock_irq(&phba->hbalock);
+       psli->sli_flag &= ~LPFC_SLI_ACTIVE;
+       spin_unlock_irq(&phba->hbalock);
+
+       /* Configure and enable interrupt */
+       intr_mode = lpfc_sli_enable_intr(phba, phba->intr_mode);
+       if (intr_mode == LPFC_INTR_ERROR) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0427 Cannot re-enable interrupt after "
+                               "slot reset.\n");
+               return PCI_ERS_RESULT_DISCONNECT;
+       } else
+               phba->intr_mode = intr_mode;
+
+       /* Take device offline; this will perform cleanup */
+       lpfc_offline(phba);
+       lpfc_sli_brdrestart(phba);
+
+       /* Log the current active interrupt mode */
+       lpfc_log_intr_mode(phba, phba->intr_mode);
+
+       return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * lpfc_io_resume_s3 - Method for resuming PCI I/O operation on SLI-3 device.
+ * @pdev: pointer to PCI device
+ *
+ * This routine is called from the PCI subsystem for error handling to device
+ * with SLI-3 interface spec. It is called when kernel error recovery tells
+ * the lpfc driver that it is ok to resume normal PCI operation after PCI bus
+ * error recovery. After this call, traffic can start to flow from this device
+ * again.
+ */
+static void
+lpfc_io_resume_s3(struct pci_dev *pdev)
+{
+       struct Scsi_Host *shost = pci_get_drvdata(pdev);
+       struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+       lpfc_online(phba);
+}
+
+/**
+ * lpfc_sli4_get_els_iocb_cnt - Calculate the # of ELS IOCBs to reserve
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * returns the number of ELS/CT IOCBs to reserve
+ **/
+int
+lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *phba)
+{
+       int max_xri = phba->sli4_hba.max_cfg_param.max_xri;
+
+       if (max_xri <= 100)
+               return 4;
+       else if (max_xri <= 256)
+               return 8;
+       else if (max_xri <= 512)
+               return 16;
+       else if (max_xri <= 1024)
+               return 32;
+       else
+               return 48;
+}
+
+/**
+ * lpfc_pci_probe_one_s4 - PCI probe func to reg SLI-4 device to PCI subsys
+ * @pdev: pointer to PCI device
+ * @pid: pointer to PCI device identifier
+ *
+ * This routine is called from the kernel's PCI subsystem to device with
+ * SLI-4 interface spec. When an Emulex HBA with SLI-4 interface spec is
+ * presented on PCI bus, the kernel PCI subsystem looks at PCI device-specific
+ * information of the device and driver to see if the driver state that it
+ * can support this kind of device. If the match is successful, the driver
+ * core invokes this routine. If this routine determines it can claim the HBA,
+ * it does all the initialization that it needs to do to handle the HBA
+ * properly.
+ *
+ * Return code
+ *     0 - driver can claim the device
+ *     negative value - driver can not claim the device
+ **/
+static int __devinit
+lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
+{
+       struct lpfc_hba   *phba;
+       struct lpfc_vport *vport = NULL;
+       int error;
+       uint32_t cfg_mode, intr_mode;
+       int mcnt;
+
+       /* Allocate memory for HBA structure */
+       phba = lpfc_hba_alloc(pdev);
+       if (!phba)
+               return -ENOMEM;
+
+       /* Perform generic PCI device enabling operation */
+       error = lpfc_enable_pci_dev(phba);
+       if (error) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1409 Failed to enable pci device.\n");
+               goto out_free_phba;
+       }
+
+       /* Set up SLI API function jump table for PCI-device group-1 HBAs */
+       error = lpfc_api_table_setup(phba, LPFC_PCI_DEV_OC);
+       if (error)
+               goto out_disable_pci_dev;
+
+       /* Set up SLI-4 specific device PCI memory space */
+       error = lpfc_sli4_pci_mem_setup(phba);
+       if (error) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1410 Failed to set up pci memory space.\n");
+               goto out_disable_pci_dev;
+       }
+
+       /* Set up phase-1 common device driver resources */
+       error = lpfc_setup_driver_resource_phase1(phba);
+       if (error) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1411 Failed to set up driver resource.\n");
+               goto out_unset_pci_mem_s4;
+       }
+
+       /* Set up SLI-4 Specific device driver resources */
+       error = lpfc_sli4_driver_resource_setup(phba);
+       if (error) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1412 Failed to set up driver resource.\n");
+               goto out_unset_pci_mem_s4;
+       }
+
+       /* Initialize and populate the iocb list per host */
+       error = lpfc_init_iocb_list(phba,
+                       phba->sli4_hba.max_cfg_param.max_xri);
+       if (error) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1413 Failed to initialize iocb list.\n");
+               goto out_unset_driver_resource_s4;
+       }
+
+       /* Set up common device driver resources */
+       error = lpfc_setup_driver_resource_phase2(phba);
+       if (error) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1414 Failed to set up driver resource.\n");
+               goto out_free_iocb_list;
+       }
+
+       /* Create SCSI host to the physical port */
+       error = lpfc_create_shost(phba);
+       if (error) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1415 Failed to create scsi host.\n");
+               goto out_unset_driver_resource;
+       }
+
+       /* Configure sysfs attributes */
+       vport = phba->pport;
+       error = lpfc_alloc_sysfs_attr(vport);
+       if (error) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1416 Failed to allocate sysfs attr\n");
+               goto out_destroy_shost;
+       }
+
+       /* Now, trying to enable interrupt and bring up the device */
+       cfg_mode = phba->cfg_use_msi;
+       while (true) {
+               /* Put device to a known state before enabling interrupt */
+               lpfc_stop_port(phba);
+               /* Configure and enable interrupt */
+               intr_mode = lpfc_sli4_enable_intr(phba, cfg_mode);
+               if (intr_mode == LPFC_INTR_ERROR) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "0426 Failed to enable interrupt.\n");
+                       error = -ENODEV;
+                       goto out_free_sysfs_attr;
+               }
+               /* Set up SLI-4 HBA */
+               if (lpfc_sli4_hba_setup(phba)) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "1421 Failed to set up hba\n");
+                       error = -ENODEV;
+                       goto out_disable_intr;
+               }
+
+               /* Send NOP mbx cmds for non-INTx mode active interrupt test */
+               if (intr_mode != 0)
+                       mcnt = lpfc_sli4_send_nop_mbox_cmds(phba,
+                                                           LPFC_ACT_INTR_CNT);
+
+               /* Check active interrupts received only for MSI/MSI-X */
+               if (intr_mode == 0 ||
+                   phba->sli.slistat.sli_intr >= LPFC_ACT_INTR_CNT) {
+                       /* Log the current active interrupt mode */
+                       phba->intr_mode = intr_mode;
+                       lpfc_log_intr_mode(phba, intr_mode);
+                       break;
+               }
+               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                               "0451 Configure interrupt mode (%d) "
+                               "failed active interrupt test.\n",
+                               intr_mode);
+               /* Unset the preivous SLI-4 HBA setup */
+               lpfc_sli4_unset_hba(phba);
+               /* Try next level of interrupt mode */
+               cfg_mode = --intr_mode;
+       }
+
+       /* Perform post initialization setup */
+       lpfc_post_init_setup(phba);
+
+       return 0;
+
+out_disable_intr:
+       lpfc_sli4_disable_intr(phba);
+out_free_sysfs_attr:
+       lpfc_free_sysfs_attr(vport);
+out_destroy_shost:
+       lpfc_destroy_shost(phba);
+out_unset_driver_resource:
+       lpfc_unset_driver_resource_phase2(phba);
+out_free_iocb_list:
+       lpfc_free_iocb_list(phba);
+out_unset_driver_resource_s4:
+       lpfc_sli4_driver_resource_unset(phba);
+out_unset_pci_mem_s4:
+       lpfc_sli4_pci_mem_unset(phba);
+out_disable_pci_dev:
+       lpfc_disable_pci_dev(phba);
+out_free_phba:
+       lpfc_hba_free(phba);
        return error;
 }
 
 /**
- * lpfc_pci_remove_one - lpfc PCI func to unregister device from PCI subsystem
+ * lpfc_pci_remove_one_s4 - PCI func to unreg SLI-4 device from PCI subsystem
  * @pdev: pointer to PCI device
  *
- * This routine is to be registered to the kernel's PCI subsystem. When an
- * Emulex HBA is removed from PCI bus, it performs all the necessary cleanup
- * for the HBA device to be removed from the PCI subsystem properly.
+ * This routine is called from the kernel's PCI subsystem to device with
+ * SLI-4 interface spec. When an Emulex HBA with SLI-4 interface spec is
+ * removed from PCI bus, it performs all the necessary cleanup for the HBA
+ * device to be removed from the PCI subsystem properly.
  **/
 static void __devexit
-lpfc_pci_remove_one(struct pci_dev *pdev)
+lpfc_pci_remove_one_s4(struct pci_dev *pdev)
 {
-       struct Scsi_Host  *shost = pci_get_drvdata(pdev);
+       struct Scsi_Host *shost = pci_get_drvdata(pdev);
        struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
        struct lpfc_vport **vports;
-       struct lpfc_hba   *phba = vport->phba;
+       struct lpfc_hba *phba = vport->phba;
        int i;
-       int bars = pci_select_bars(pdev, IORESOURCE_MEM);
 
+       /* Mark the device unloading flag */
        spin_lock_irq(&phba->hbalock);
        vport->load_flag |= FC_UNLOADING;
        spin_unlock_irq(&phba->hbalock);
 
+       /* Free the HBA sysfs attributes */
        lpfc_free_sysfs_attr(vport);
 
        /* Release all the vports against this physical port */
        vports = lpfc_create_vport_work_array(phba);
        if (vports != NULL)
-               for (i = 1; i <= phba->max_vpi && vports[i] != NULL; i++)
+               for (i = 1; i <= phba->max_vports && vports[i] != NULL; i++)
                        fc_vport_terminate(vports[i]->fc_vport);
        lpfc_destroy_vport_work_array(phba, vports);
 
        /* Remove FC host and then SCSI host with the physical port */
        fc_remove_host(shost);
        scsi_remove_host(shost);
+
+       /* Perform cleanup on the physical port */
        lpfc_cleanup(vport);
 
        /*
-        * Bring down the SLI Layer. This step disable all interrupts,
+        * Bring down the SLI Layer. This step disables all interrupts,
         * clears the rings, discards all mailbox commands, and resets
-        * the HBA.
+        * the HBA FCoE function.
         */
+       lpfc_debugfs_terminate(vport);
+       lpfc_sli4_hba_unset(phba);
 
-       /* HBA interrupt will be diabled after this call */
-       lpfc_sli_hba_down(phba);
-       /* Stop kthread signal shall trigger work_done one more time */
-       kthread_stop(phba->worker_thread);
-       /* Final cleanup of txcmplq and reset the HBA */
-       lpfc_sli_brdrestart(phba);
-
-       lpfc_stop_phba_timers(phba);
        spin_lock_irq(&phba->hbalock);
        list_del_init(&vport->listentry);
        spin_unlock_irq(&phba->hbalock);
 
-       lpfc_debugfs_terminate(vport);
-
-       /* Disable interrupt */
-       lpfc_disable_intr(phba);
-
-       pci_set_drvdata(pdev, NULL);
-       scsi_host_put(shost);
-
-       /*
-        * Call scsi_free before mem_free since scsi bufs are released to their
-        * corresponding pools here.
+       /* Call scsi_free before lpfc_sli4_driver_resource_unset since scsi
+        * buffers are released to their corresponding pools here.
         */
        lpfc_scsi_free(phba);
-       lpfc_mem_free(phba);
-
-       dma_free_coherent(&pdev->dev, lpfc_sli_hbq_size(),
-                         phba->hbqslimp.virt, phba->hbqslimp.phys);
-
-       /* Free resources associated with SLI2 interface */
-       dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE,
-                         phba->slim2p.virt, phba->slim2p.phys);
+       lpfc_sli4_driver_resource_unset(phba);
 
-       /* unmap adapter SLIM and Control Registers */
-       iounmap(phba->ctrl_regs_memmap_p);
-       iounmap(phba->slim_memmap_p);
+       /* Unmap adapter Control and Doorbell registers */
+       lpfc_sli4_pci_mem_unset(phba);
 
-       idr_remove(&lpfc_hba_index, phba->brd_no);
+       /* Release PCI resources and disable device's PCI function */
+       scsi_host_put(shost);
+       lpfc_disable_pci_dev(phba);
 
-       kfree(phba);
+       /* Finally, free the driver's device data structure */
+       lpfc_hba_free(phba);
 
-       pci_release_selected_regions(pdev, bars);
-       pci_disable_device(pdev);
+       return;
 }
 
 /**
- * lpfc_pci_suspend_one - lpfc PCI func to suspend device for power management
+ * lpfc_pci_suspend_one_s4 - PCI func to suspend SLI-4 device for power mgmnt
  * @pdev: pointer to PCI device
  * @msg: power management message
  *
- * This routine is to be registered to the kernel's PCI subsystem to support
- * system Power Management (PM). When PM invokes this method, it quiesces the
- * device by stopping the driver's worker thread for the device, turning off
- * device's interrupt and DMA, and bring the device offline. Note that as the
- * driver implements the minimum PM requirements to a power-aware driver's PM
- * support for suspend/resume -- all the possible PM messages (SUSPEND,
- * HIBERNATE, FREEZE) to the suspend() method call will be treated as SUSPEND
- * and the driver will fully reinitialize its device during resume() method
- * call, the driver will set device to PCI_D3hot state in PCI config space
- * instead of setting it according to the @msg provided by the PM.
+ * This routine is called from the kernel's PCI subsystem to support system
+ * Power Management (PM) to device with SLI-4 interface spec. When PM invokes
+ * this method, it quiesces the device by stopping the driver's worker
+ * thread for the device, turning off device's interrupt and DMA, and bring
+ * the device offline. Note that as the driver implements the minimum PM
+ * requirements to a power-aware driver's PM support for suspend/resume -- all
+ * the possible PM messages (SUSPEND, HIBERNATE, FREEZE) to the suspend()
+ * method call will be treated as SUSPEND and the driver will fully
+ * reinitialize its device during resume() method call, the driver will set
+ * device to PCI_D3hot state in PCI config space instead of setting it
+ * according to the @msg provided by the PM.
  *
  * Return code
- *   0 - driver suspended the device
- *   Error otherwise
+ *     0 - driver suspended the device
+ *     Error otherwise
  **/
 static int
-lpfc_pci_suspend_one(struct pci_dev *pdev, pm_message_t msg)
+lpfc_pci_suspend_one_s4(struct pci_dev *pdev, pm_message_t msg)
 {
        struct Scsi_Host *shost = pci_get_drvdata(pdev);
        struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
 
        lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-                       "0473 PCI device Power Management suspend.\n");
+                       "0298 PCI device Power Management suspend.\n");
 
        /* Bring down the device */
        lpfc_offline_prep(phba);
@@ -3194,7 +7476,7 @@ lpfc_pci_suspend_one(struct pci_dev *pdev, pm_message_t msg)
        kthread_stop(phba->worker_thread);
 
        /* Disable interrupt from device */
-       lpfc_disable_intr(phba);
+       lpfc_sli4_disable_intr(phba);
 
        /* Save device state to PCI config space */
        pci_save_state(pdev);
@@ -3204,25 +7486,26 @@ lpfc_pci_suspend_one(struct pci_dev *pdev, pm_message_t msg)
 }
 
 /**
- * lpfc_pci_resume_one - lpfc PCI func to resume device for power management
+ * lpfc_pci_resume_one_s4 - PCI func to resume SLI-4 device for power mgmnt
  * @pdev: pointer to PCI device
  *
- * This routine is to be registered to the kernel's PCI subsystem to support
- * system Power Management (PM). When PM invokes this method, it restores
- * the device's PCI config space state and fully reinitializes the device
- * and brings it online. Note that as the driver implements the minimum PM
- * requirements to a power-aware driver's PM for suspend/resume -- all
- * the possible PM messages (SUSPEND, HIBERNATE, FREEZE) to the suspend()
- * method call will be treated as SUSPEND and the driver will fully
- * reinitialize its device during resume() method call, the device will be
- * set to PCI_D0 directly in PCI config space before restoring the state.
+ * This routine is called from the kernel's PCI subsystem to support system
+ * Power Management (PM) to device with SLI-4 interface spac. When PM invokes
+ * this method, it restores the device's PCI config space state and fully
+ * reinitializes the device and brings it online. Note that as the driver
+ * implements the minimum PM requirements to a power-aware driver's PM for
+ * suspend/resume -- all the possible PM messages (SUSPEND, HIBERNATE, FREEZE)
+ * to the suspend() method call will be treated as SUSPEND and the driver
+ * will fully reinitialize its device during resume() method call, the device
+ * will be set to PCI_D0 directly in PCI config space before restoring the
+ * state.
  *
  * Return code
- *   0 - driver suspended the device
- *   Error otherwise
+ *     0 - driver suspended the device
+ *     Error otherwise
  **/
 static int
-lpfc_pci_resume_one(struct pci_dev *pdev)
+lpfc_pci_resume_one_s4(struct pci_dev *pdev)
 {
        struct Scsi_Host *shost = pci_get_drvdata(pdev);
        struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
@@ -3230,7 +7513,7 @@ lpfc_pci_resume_one(struct pci_dev *pdev)
        int error;
 
        lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-                       "0452 PCI device Power Management resume.\n");
+                       "0292 PCI device Power Management resume.\n");
 
        /* Restore device state from PCI config space */
        pci_set_power_state(pdev, PCI_D0);
@@ -3238,22 +7521,22 @@ lpfc_pci_resume_one(struct pci_dev *pdev)
        if (pdev->is_busmaster)
                pci_set_master(pdev);
 
-       /* Startup the kernel thread for this host adapter. */
+        /* Startup the kernel thread for this host adapter. */
        phba->worker_thread = kthread_run(lpfc_do_work, phba,
                                        "lpfc_worker_%d", phba->brd_no);
        if (IS_ERR(phba->worker_thread)) {
                error = PTR_ERR(phba->worker_thread);
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                               "0434 PM resume failed to start worker "
+                               "0293 PM resume failed to start worker "
                                "thread: error=x%x.\n", error);
                return error;
        }
 
        /* Configure and enable interrupt */
-       intr_mode = lpfc_enable_intr(phba, phba->intr_mode);
+       intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode);
        if (intr_mode == LPFC_INTR_ERROR) {
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                               "0430 PM resume Failed to enable interrupt\n");
+                               "0294 PM resume Failed to enable interrupt\n");
                return -EIO;
        } else
                phba->intr_mode = intr_mode;
@@ -3269,129 +7552,316 @@ lpfc_pci_resume_one(struct pci_dev *pdev)
 }
 
 /**
- * lpfc_io_error_detected - Driver method for handling PCI I/O error detected
+ * lpfc_io_error_detected_s4 - Method for handling PCI I/O error to SLI-4 device
  * @pdev: pointer to PCI device.
  * @state: the current PCI connection state.
  *
- * This routine is registered to the PCI subsystem for error handling. This
- * function is called by the PCI subsystem after a PCI bus error affecting
- * this device has been detected. When this function is invoked, it will
- * need to stop all the I/Os and interrupt(s) to the device. Once that is
- * done, it will return PCI_ERS_RESULT_NEED_RESET for the PCI subsystem to
- * perform proper recovery as desired.
+ * This routine is called from the PCI subsystem for error handling to device
+ * with SLI-4 interface spec. This function is called by the PCI subsystem
+ * after a PCI bus error affecting this device has been detected. When this
+ * function is invoked, it will need to stop all the I/Os and interrupt(s)
+ * to the device. Once that is done, it will return PCI_ERS_RESULT_NEED_RESET
+ * for the PCI subsystem to perform proper recovery as desired.
  *
  * Return codes
- *   PCI_ERS_RESULT_NEED_RESET - need to reset before recovery
- *   PCI_ERS_RESULT_DISCONNECT - device could not be recovered
+ *     PCI_ERS_RESULT_NEED_RESET - need to reset before recovery
+ *     PCI_ERS_RESULT_DISCONNECT - device could not be recovered
  **/
-static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev,
-                               pci_channel_state_t state)
+static pci_ers_result_t
+lpfc_io_error_detected_s4(struct pci_dev *pdev, pci_channel_state_t state)
+{
+       return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * lpfc_io_slot_reset_s4 - Method for restart PCI SLI-4 device from scratch
+ * @pdev: pointer to PCI device.
+ *
+ * This routine is called from the PCI subsystem for error handling to device
+ * with SLI-4 interface spec. It is called after PCI bus has been reset to
+ * restart the PCI card from scratch, as if from a cold-boot. During the
+ * PCI subsystem error recovery, after the driver returns
+ * PCI_ERS_RESULT_NEED_RESET, the PCI subsystem will perform proper error
+ * recovery and then call this routine before calling the .resume method to
+ * recover the device. This function will initialize the HBA device, enable
+ * the interrupt, but it will just put the HBA to offline state without
+ * passing any I/O traffic.
+ *
+ * Return codes
+ *     PCI_ERS_RESULT_RECOVERED - the device has been recovered
+ *     PCI_ERS_RESULT_DISCONNECT - device could not be recovered
+ */
+static pci_ers_result_t
+lpfc_io_slot_reset_s4(struct pci_dev *pdev)
+{
+       return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * lpfc_io_resume_s4 - Method for resuming PCI I/O operation to SLI-4 device
+ * @pdev: pointer to PCI device
+ *
+ * This routine is called from the PCI subsystem for error handling to device
+ * with SLI-4 interface spec. It is called when kernel error recovery tells
+ * the lpfc driver that it is ok to resume normal PCI operation after PCI bus
+ * error recovery. After this call, traffic can start to flow from this device
+ * again.
+ **/
+static void
+lpfc_io_resume_s4(struct pci_dev *pdev)
+{
+       return;
+}
+
+/**
+ * lpfc_pci_probe_one - lpfc PCI probe func to reg dev to PCI subsystem
+ * @pdev: pointer to PCI device
+ * @pid: pointer to PCI device identifier
+ *
+ * This routine is to be registered to the kernel's PCI subsystem. When an
+ * Emulex HBA device is presented on PCI bus, the kernel PCI subsystem looks
+ * at PCI device-specific information of the device and driver to see if the
+ * driver state that it can support this kind of device. If the match is
+ * successful, the driver core invokes this routine. This routine dispatches
+ * the action to the proper SLI-3 or SLI-4 device probing routine, which will
+ * do all the initialization that it needs to do to handle the HBA device
+ * properly.
+ *
+ * Return code
+ *     0 - driver can claim the device
+ *     negative value - driver can not claim the device
+ **/
+static int __devinit
+lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
+{
+       int rc;
+       uint16_t dev_id;
+
+       if (pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id))
+               return -ENODEV;
+
+       switch (dev_id) {
+       case PCI_DEVICE_ID_TIGERSHARK:
+       case PCI_DEVICE_ID_TIGERSHARK_S:
+               rc = lpfc_pci_probe_one_s4(pdev, pid);
+               break;
+       default:
+               rc = lpfc_pci_probe_one_s3(pdev, pid);
+               break;
+       }
+       return rc;
+}
+
+/**
+ * lpfc_pci_remove_one - lpfc PCI func to unreg dev from PCI subsystem
+ * @pdev: pointer to PCI device
+ *
+ * This routine is to be registered to the kernel's PCI subsystem. When an
+ * Emulex HBA is removed from PCI bus, the driver core invokes this routine.
+ * This routine dispatches the action to the proper SLI-3 or SLI-4 device
+ * remove routine, which will perform all the necessary cleanup for the
+ * device to be removed from the PCI subsystem properly.
+ **/
+static void __devexit
+lpfc_pci_remove_one(struct pci_dev *pdev)
 {
        struct Scsi_Host *shost = pci_get_drvdata(pdev);
        struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
-       struct lpfc_sli *psli = &phba->sli;
-       struct lpfc_sli_ring  *pring;
 
-       if (state == pci_channel_io_perm_failure) {
+       switch (phba->pci_dev_grp) {
+       case LPFC_PCI_DEV_LP:
+               lpfc_pci_remove_one_s3(pdev);
+               break;
+       case LPFC_PCI_DEV_OC:
+               lpfc_pci_remove_one_s4(pdev);
+               break;
+       default:
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                               "0472 PCI channel I/O permanent failure\n");
-               /* Block all SCSI devices' I/Os on the host */
-               lpfc_scsi_dev_block(phba);
-               /* Clean up all driver's outstanding SCSI I/Os */
-               lpfc_sli_flush_fcp_rings(phba);
-               return PCI_ERS_RESULT_DISCONNECT;
+                               "1424 Invalid PCI device group: 0x%x\n",
+                               phba->pci_dev_grp);
+               break;
        }
+       return;
+}
 
-       pci_disable_device(pdev);
-       /*
-        * There may be I/Os dropped by the firmware.
-        * Error iocb (I/O) on txcmplq and let the SCSI layer
-        * retry it after re-establishing link.
-        */
-       pring = &psli->ring[psli->fcp_ring];
-       lpfc_sli_abort_iocb_ring(phba, pring);
+/**
+ * lpfc_pci_suspend_one - lpfc PCI func to suspend dev for power management
+ * @pdev: pointer to PCI device
+ * @msg: power management message
+ *
+ * This routine is to be registered to the kernel's PCI subsystem to support
+ * system Power Management (PM). When PM invokes this method, it dispatches
+ * the action to the proper SLI-3 or SLI-4 device suspend routine, which will
+ * suspend the device.
+ *
+ * Return code
+ *     0 - driver suspended the device
+ *     Error otherwise
+ **/
+static int
+lpfc_pci_suspend_one(struct pci_dev *pdev, pm_message_t msg)
+{
+       struct Scsi_Host *shost = pci_get_drvdata(pdev);
+       struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+       int rc = -ENODEV;
 
-       /* Disable interrupt */
-       lpfc_disable_intr(phba);
+       switch (phba->pci_dev_grp) {
+       case LPFC_PCI_DEV_LP:
+               rc = lpfc_pci_suspend_one_s3(pdev, msg);
+               break;
+       case LPFC_PCI_DEV_OC:
+               rc = lpfc_pci_suspend_one_s4(pdev, msg);
+               break;
+       default:
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1425 Invalid PCI device group: 0x%x\n",
+                               phba->pci_dev_grp);
+               break;
+       }
+       return rc;
+}
 
-       /* Request a slot reset. */
-       return PCI_ERS_RESULT_NEED_RESET;
+/**
+ * lpfc_pci_resume_one - lpfc PCI func to resume dev for power management
+ * @pdev: pointer to PCI device
+ *
+ * This routine is to be registered to the kernel's PCI subsystem to support
+ * system Power Management (PM). When PM invokes this method, it dispatches
+ * the action to the proper SLI-3 or SLI-4 device resume routine, which will
+ * resume the device.
+ *
+ * Return code
+ *     0 - driver suspended the device
+ *     Error otherwise
+ **/
+static int
+lpfc_pci_resume_one(struct pci_dev *pdev)
+{
+       struct Scsi_Host *shost = pci_get_drvdata(pdev);
+       struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+       int rc = -ENODEV;
+
+       switch (phba->pci_dev_grp) {
+       case LPFC_PCI_DEV_LP:
+               rc = lpfc_pci_resume_one_s3(pdev);
+               break;
+       case LPFC_PCI_DEV_OC:
+               rc = lpfc_pci_resume_one_s4(pdev);
+               break;
+       default:
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1426 Invalid PCI device group: 0x%x\n",
+                               phba->pci_dev_grp);
+               break;
+       }
+       return rc;
 }
 
 /**
- * lpfc_io_slot_reset - Restart a PCI device from scratch
+ * lpfc_io_error_detected - lpfc method for handling PCI I/O error
  * @pdev: pointer to PCI device.
+ * @state: the current PCI connection state.
  *
- * This routine is registered to the PCI subsystem for error handling. This is
- * called after PCI bus has been reset to restart the PCI card from scratch,
- * as if from a cold-boot. During the PCI subsystem error recovery, after the
- * driver returns PCI_ERS_RESULT_NEED_RESET, the PCI subsystem will perform
- * proper error recovery and then call this routine before calling the .resume
- * method to recover the device. This function will initialize the HBA device,
- * enable the interrupt, but it will just put the HBA to offline state without
- * passing any I/O traffic.
+ * This routine is registered to the PCI subsystem for error handling. This
+ * function is called by the PCI subsystem after a PCI bus error affecting
+ * this device has been detected. When this routine is invoked, it dispatches
+ * the action to the proper SLI-3 or SLI-4 device error detected handling
+ * routine, which will perform the proper error detected operation.
  *
  * Return codes
- *   PCI_ERS_RESULT_RECOVERED - the device has been recovered
- *   PCI_ERS_RESULT_DISCONNECT - device could not be recovered
- */
-static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev)
+ *     PCI_ERS_RESULT_NEED_RESET - need to reset before recovery
+ *     PCI_ERS_RESULT_DISCONNECT - device could not be recovered
+ **/
+static pci_ers_result_t
+lpfc_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
 {
        struct Scsi_Host *shost = pci_get_drvdata(pdev);
        struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
-       struct lpfc_sli *psli = &phba->sli;
-       uint32_t intr_mode;
+       pci_ers_result_t rc = PCI_ERS_RESULT_DISCONNECT;
 
-       dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n");
-       if (pci_enable_device_mem(pdev)) {
-               printk(KERN_ERR "lpfc: Cannot re-enable "
-                       "PCI device after reset.\n");
-               return PCI_ERS_RESULT_DISCONNECT;
+       switch (phba->pci_dev_grp) {
+       case LPFC_PCI_DEV_LP:
+               rc = lpfc_io_error_detected_s3(pdev, state);
+               break;
+       case LPFC_PCI_DEV_OC:
+               rc = lpfc_io_error_detected_s4(pdev, state);
+               break;
+       default:
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1427 Invalid PCI device group: 0x%x\n",
+                               phba->pci_dev_grp);
+               break;
        }
+       return rc;
+}
 
-       pci_restore_state(pdev);
-       if (pdev->is_busmaster)
-               pci_set_master(pdev);
-
-       spin_lock_irq(&phba->hbalock);
-       psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
-       spin_unlock_irq(&phba->hbalock);
+/**
+ * lpfc_io_slot_reset - lpfc method for restart PCI dev from scratch
+ * @pdev: pointer to PCI device.
+ *
+ * This routine is registered to the PCI subsystem for error handling. This
+ * function is called after PCI bus has been reset to restart the PCI card
+ * from scratch, as if from a cold-boot. When this routine is invoked, it
+ * dispatches the action to the proper SLI-3 or SLI-4 device reset handling
+ * routine, which will perform the proper device reset.
+ *
+ * Return codes
+ *     PCI_ERS_RESULT_RECOVERED - the device has been recovered
+ *     PCI_ERS_RESULT_DISCONNECT - device could not be recovered
+ **/
+static pci_ers_result_t
+lpfc_io_slot_reset(struct pci_dev *pdev)
+{
+       struct Scsi_Host *shost = pci_get_drvdata(pdev);
+       struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+       pci_ers_result_t rc = PCI_ERS_RESULT_DISCONNECT;
 
-       /* Configure and enable interrupt */
-       intr_mode = lpfc_enable_intr(phba, phba->intr_mode);
-       if (intr_mode == LPFC_INTR_ERROR) {
+       switch (phba->pci_dev_grp) {
+       case LPFC_PCI_DEV_LP:
+               rc = lpfc_io_slot_reset_s3(pdev);
+               break;
+       case LPFC_PCI_DEV_OC:
+               rc = lpfc_io_slot_reset_s4(pdev);
+               break;
+       default:
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                               "0427 Cannot re-enable interrupt after "
-                               "slot reset.\n");
-               return PCI_ERS_RESULT_DISCONNECT;
-       } else
-               phba->intr_mode = intr_mode;
-
-       /* Take device offline; this will perform cleanup */
-       lpfc_offline(phba);
-       lpfc_sli_brdrestart(phba);
-
-       /* Log the current active interrupt mode */
-       lpfc_log_intr_mode(phba, phba->intr_mode);
-
-       return PCI_ERS_RESULT_RECOVERED;
+                               "1428 Invalid PCI device group: 0x%x\n",
+                               phba->pci_dev_grp);
+               break;
+       }
+       return rc;
 }
 
 /**
- * lpfc_io_resume - Resume PCI I/O operation
+ * lpfc_io_resume - lpfc method for resuming PCI I/O operation
  * @pdev: pointer to PCI device
  *
- * This routine is registered to the PCI subsystem for error handling. It is
- * called when kernel error recovery tells the lpfc driver that it is ok to
- * resume normal PCI operation after PCI bus error recovery. After this call,
- * traffic can start to flow from this device again.
- */
-static void lpfc_io_resume(struct pci_dev *pdev)
+ * This routine is registered to the PCI subsystem for error handling. It
+ * is called when kernel error recovery tells the lpfc driver that it is
+ * OK to resume normal PCI operation after PCI bus error recovery. When
+ * this routine is invoked, it dispatches the action to the proper SLI-3
+ * or SLI-4 device io_resume routine, which will resume the device operation.
+ **/
+static void
+lpfc_io_resume(struct pci_dev *pdev)
 {
        struct Scsi_Host *shost = pci_get_drvdata(pdev);
        struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
 
-       lpfc_online(phba);
+       switch (phba->pci_dev_grp) {
+       case LPFC_PCI_DEV_LP:
+               lpfc_io_resume_s3(pdev);
+               break;
+       case LPFC_PCI_DEV_OC:
+               lpfc_io_resume_s4(pdev);
+               break;
+       default:
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1429 Invalid PCI device group: 0x%x\n",
+                               phba->pci_dev_grp);
+               break;
+       }
+       return;
 }
 
 static struct pci_device_id lpfc_id_table[] = {
@@ -3469,6 +7939,10 @@ static struct pci_device_id lpfc_id_table[] = {
                PCI_ANY_ID, PCI_ANY_ID, },
        {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PROTEUS_S,
                PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TIGERSHARK,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TIGERSHARK_S,
+               PCI_ANY_ID, PCI_ANY_ID, },
        { 0 }
 };
 
@@ -3486,7 +7960,7 @@ static struct pci_driver lpfc_driver = {
        .probe          = lpfc_pci_probe_one,
        .remove         = __devexit_p(lpfc_pci_remove_one),
        .suspend        = lpfc_pci_suspend_one,
-       .resume         = lpfc_pci_resume_one,
+       .resume         = lpfc_pci_resume_one,
        .err_handler    = &lpfc_err_handler,
 };
 
index 1aa85709b012d24826652d87e0c5da2121f1dda2..954ba57970a3ab294ef8db13d99ff798b6ca346c 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
  * included with this package.                                     *
  *******************************************************************/
 
-#define LOG_ELS                       0x1      /* ELS events */
-#define LOG_DISCOVERY                 0x2      /* Link discovery events */
-#define LOG_MBOX                      0x4      /* Mailbox events */
-#define LOG_INIT                      0x8      /* Initialization events */
-#define LOG_LINK_EVENT                0x10     /* Link events */
-#define LOG_IP                        0x20     /* IP traffic history */
-#define LOG_FCP                       0x40     /* FCP traffic history */
-#define LOG_NODE                      0x80     /* Node table events */
-#define LOG_TEMP                      0x100    /* Temperature sensor events */
-#define LOG_BG                       0x200     /* BlockGuard events */
-#define LOG_MISC                      0x400    /* Miscellaneous events */
-#define LOG_SLI                       0x800    /* SLI events */
-#define LOG_FCP_ERROR                 0x1000   /* log errors, not underruns */
-#define LOG_LIBDFC                    0x2000   /* Libdfc events */
-#define LOG_VPORT                     0x4000   /* NPIV events */
-#define LOG_ALL_MSG                   0xffff   /* LOG all messages */
+#define LOG_ELS                0x00000001      /* ELS events */
+#define LOG_DISCOVERY  0x00000002      /* Link discovery events */
+#define LOG_MBOX       0x00000004      /* Mailbox events */
+#define LOG_INIT       0x00000008      /* Initialization events */
+#define LOG_LINK_EVENT 0x00000010      /* Link events */
+#define LOG_IP         0x00000020      /* IP traffic history */
+#define LOG_FCP                0x00000040      /* FCP traffic history */
+#define LOG_NODE       0x00000080      /* Node table events */
+#define LOG_TEMP       0x00000100      /* Temperature sensor events */
+#define LOG_BG         0x00000200      /* BlockGuard events */
+#define LOG_MISC       0x00000400      /* Miscellaneous events */
+#define LOG_SLI                0x00000800      /* SLI events */
+#define LOG_FCP_ERROR  0x00001000      /* log errors, not underruns */
+#define LOG_LIBDFC     0x00002000      /* Libdfc events */
+#define LOG_VPORT      0x00004000      /* NPIV events */
+#define LOF_SECURITY   0x00008000      /* Security events */
+#define LOG_EVENT      0x00010000      /* CT,TEMP,DUMP, logging */
+#define LOG_ALL_MSG    0xffffffff      /* LOG all messages */
 
 #define lpfc_printf_vlog(vport, level, mask, fmt, arg...) \
-       do { \
-       { if (((mask) &(vport)->cfg_log_verbose) || (level[1] <= '3')) \
+do { \
+       { if (((mask) & (vport)->cfg_log_verbose) || (level[1] <= '3')) \
                dev_printk(level, &((vport)->phba->pcidev)->dev, "%d:(%d):" \
                           fmt, (vport)->phba->brd_no, vport->vpi, ##arg); } \
-       } while (0)
+} while (0)
 
 #define lpfc_printf_log(phba, level, mask, fmt, arg...) \
-       do { \
-       { if (((mask) &(phba)->pport->cfg_log_verbose) || (level[1] <= '3')) \
+do { \
+       { uint32_t log_verbose = (phba)->pport ? \
+                                (phba)->pport->cfg_log_verbose : \
+                                (phba)->cfg_log_verbose; \
+         if (((mask) & log_verbose) || (level[1] <= '3')) \
                dev_printk(level, &((phba)->pcidev)->dev, "%d:" \
-                          fmt, phba->brd_no, ##arg); } \
-       } while (0)
+                          fmt, phba->brd_no, ##arg); \
+       } \
+} while (0)
index 134fc7fc2127454ccf98083cdd375d2f39400158..b9b451c090101565d507f34c931009a0c25f15e8 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
 
 #include <scsi/scsi.h>
 
+#include "lpfc_hw4.h"
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
+#include "lpfc_sli4.h"
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
 #include "lpfc_crtn.h"
 #include "lpfc_compat.h"
 
+/**
+ * lpfc_dump_static_vport - Dump HBA's static vport information.
+ * @phba: pointer to lpfc hba data structure.
+ * @pmb: pointer to the driver internal queue element for mailbox command.
+ * @offset: offset for dumping vport info.
+ *
+ * The dump mailbox command provides a method for the device driver to obtain
+ * various types of information from the HBA device.
+ *
+ * This routine prepares the mailbox command for dumping list of static
+ * vports to be created.
+ **/
+void
+lpfc_dump_static_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb,
+               uint16_t offset)
+{
+       MAILBOX_t *mb;
+       void *ctx;
+
+       mb = &pmb->u.mb;
+       ctx = pmb->context2;
+
+       /* Setup to dump vport info region */
+       memset(pmb, 0, sizeof(LPFC_MBOXQ_t));
+       mb->mbxCommand = MBX_DUMP_MEMORY;
+       mb->un.varDmp.cv = 1;
+       mb->un.varDmp.type = DMP_NV_PARAMS;
+       mb->un.varDmp.entry_index = offset;
+       mb->un.varDmp.region_id = DMP_REGION_VPORT;
+       mb->un.varDmp.word_cnt = DMP_RSP_SIZE/sizeof(uint32_t);
+       mb->un.varDmp.co = 0;
+       mb->un.varDmp.resp_offset = 0;
+       pmb->context2 = ctx;
+       mb->mbxOwner = OWN_HOST;
+
+       return;
+}
+
 /**
  * lpfc_dump_mem - Prepare a mailbox command for retrieving HBA's VPD memory
  * @phba: pointer to lpfc hba data structure.
@@ -58,7 +98,7 @@ lpfc_dump_mem(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, uint16_t offset)
        MAILBOX_t *mb;
        void *ctx;
 
-       mb = &pmb->mb;
+       mb = &pmb->u.mb;
        ctx = pmb->context2;
 
        /* Setup to dump VPD region */
@@ -90,7 +130,7 @@ lpfc_dump_wakeup_param(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        MAILBOX_t *mb;
        void *ctx;
 
-       mb = &pmb->mb;
+       mb = &pmb->u.mb;
        /* Save context so that we can restore after memset */
        ctx = pmb->context2;
 
@@ -125,7 +165,7 @@ lpfc_read_nv(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 {
        MAILBOX_t *mb;
 
-       mb = &pmb->mb;
+       mb = &pmb->u.mb;
        memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
        mb->mbxCommand = MBX_READ_NV;
        mb->mbxOwner = OWN_HOST;
@@ -151,7 +191,7 @@ lpfc_config_async(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb,
 {
        MAILBOX_t *mb;
 
-       mb = &pmb->mb;
+       mb = &pmb->u.mb;
        memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
        mb->mbxCommand = MBX_ASYNCEVT_ENABLE;
        mb->un.varCfgAsyncEvent.ring = ring;
@@ -177,7 +217,7 @@ lpfc_heart_beat(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 {
        MAILBOX_t *mb;
 
-       mb = &pmb->mb;
+       mb = &pmb->u.mb;
        memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
        mb->mbxCommand = MBX_HEARTBEAT;
        mb->mbxOwner = OWN_HOST;
@@ -211,7 +251,7 @@ lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, struct lpfc_dmabuf *mp)
        struct lpfc_sli *psli;
 
        psli = &phba->sli;
-       mb = &pmb->mb;
+       mb = &pmb->u.mb;
        memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
        INIT_LIST_HEAD(&mp->list);
@@ -248,7 +288,7 @@ lpfc_clear_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 {
        MAILBOX_t *mb;
 
-       mb = &pmb->mb;
+       mb = &pmb->u.mb;
        memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
        mb->un.varClearLA.eventTag = phba->fc_eventTag;
@@ -275,7 +315,7 @@ void
 lpfc_config_link(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 {
        struct lpfc_vport  *vport = phba->pport;
-       MAILBOX_t *mb = &pmb->mb;
+       MAILBOX_t *mb = &pmb->u.mb;
        memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
        /* NEW_FEATURE
@@ -321,7 +361,7 @@ lpfc_config_link(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 int
 lpfc_config_msi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
-       MAILBOX_t *mb = &pmb->mb;
+       MAILBOX_t *mb = &pmb->u.mb;
        uint32_t attentionConditions[2];
 
        /* Sanity check */
@@ -405,7 +445,7 @@ lpfc_init_link(struct lpfc_hba * phba,
        struct lpfc_sli *psli;
        MAILBOX_t *mb;
 
-       mb = &pmb->mb;
+       mb = &pmb->u.mb;
        memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
        psli = &phba->sli;
@@ -492,7 +532,7 @@ lpfc_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, int vpi)
        struct lpfc_sli *psli;
 
        psli = &phba->sli;
-       mb = &pmb->mb;
+       mb = &pmb->u.mb;
        memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
        mb->mbxOwner = OWN_HOST;
@@ -515,7 +555,7 @@ lpfc_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, int vpi)
        mb->un.varRdSparm.un.sp64.tus.f.bdeSize = sizeof (struct serv_parm);
        mb->un.varRdSparm.un.sp64.addrHigh = putPaddrHigh(mp->phys);
        mb->un.varRdSparm.un.sp64.addrLow = putPaddrLow(mp->phys);
-       mb->un.varRdSparm.vpi = vpi;
+       mb->un.varRdSparm.vpi = vpi + phba->vpi_base;
 
        /* save address for completion */
        pmb->context1 = mp;
@@ -544,10 +584,12 @@ lpfc_unreg_did(struct lpfc_hba * phba, uint16_t vpi, uint32_t did,
 {
        MAILBOX_t *mb;
 
-       mb = &pmb->mb;
+       mb = &pmb->u.mb;
        memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
        mb->un.varUnregDID.did = did;
+       if (vpi != 0xffff)
+               vpi += phba->vpi_base;
        mb->un.varUnregDID.vpi = vpi;
 
        mb->mbxCommand = MBX_UNREG_D_ID;
@@ -573,7 +615,7 @@ lpfc_read_config(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 {
        MAILBOX_t *mb;
 
-       mb = &pmb->mb;
+       mb = &pmb->u.mb;
        memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
        mb->mbxCommand = MBX_READ_CONFIG;
@@ -598,7 +640,7 @@ lpfc_read_lnk_stat(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 {
        MAILBOX_t *mb;
 
-       mb = &pmb->mb;
+       mb = &pmb->u.mb;
        memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
        mb->mbxCommand = MBX_READ_LNK_STAT;
@@ -607,7 +649,7 @@ lpfc_read_lnk_stat(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 }
 
 /**
- * lpfc_reg_login - Prepare a mailbox command for registering remote login
+ * lpfc_reg_rpi - Prepare a mailbox command for registering remote login
  * @phba: pointer to lpfc hba data structure.
  * @vpi: virtual N_Port identifier.
  * @did: remote port identifier.
@@ -631,17 +673,23 @@ lpfc_read_lnk_stat(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
  *    1 - DMA memory allocation failed
  **/
 int
-lpfc_reg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t did,
+lpfc_reg_rpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t did,
               uint8_t *param, LPFC_MBOXQ_t *pmb, uint32_t flag)
 {
-       MAILBOX_t *mb = &pmb->mb;
+       MAILBOX_t *mb = &pmb->u.mb;
        uint8_t *sparam;
        struct lpfc_dmabuf *mp;
 
        memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
        mb->un.varRegLogin.rpi = 0;
-       mb->un.varRegLogin.vpi = vpi;
+       if (phba->sli_rev == LPFC_SLI_REV4) {
+               mb->un.varRegLogin.rpi = lpfc_sli4_alloc_rpi(phba);
+               if (mb->un.varRegLogin.rpi == LPFC_RPI_ALLOC_ERROR)
+                       return 1;
+       }
+
+       mb->un.varRegLogin.vpi = vpi + phba->vpi_base;
        mb->un.varRegLogin.did = did;
        mb->un.varWords[30] = flag;     /* Set flag to issue action on cmpl */
 
@@ -697,15 +745,16 @@ lpfc_unreg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t rpi,
 {
        MAILBOX_t *mb;
 
-       mb = &pmb->mb;
+       mb = &pmb->u.mb;
        memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
        mb->un.varUnregLogin.rpi = (uint16_t) rpi;
        mb->un.varUnregLogin.rsvd1 = 0;
-       mb->un.varUnregLogin.vpi = vpi;
+       mb->un.varUnregLogin.vpi = vpi + phba->vpi_base;
 
        mb->mbxCommand = MBX_UNREG_LOGIN;
        mb->mbxOwner = OWN_HOST;
+
        return;
 }
 
@@ -725,15 +774,15 @@ lpfc_unreg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t rpi,
  * This routine prepares the mailbox command for registering a virtual N_Port.
  **/
 void
-lpfc_reg_vpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t sid,
-            LPFC_MBOXQ_t *pmb)
+lpfc_reg_vpi(struct lpfc_vport *vport, LPFC_MBOXQ_t *pmb)
 {
-       MAILBOX_t *mb = &pmb->mb;
+       MAILBOX_t *mb = &pmb->u.mb;
 
        memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
-       mb->un.varRegVpi.vpi = vpi;
-       mb->un.varRegVpi.sid = sid;
+       mb->un.varRegVpi.vpi = vport->vpi + vport->phba->vpi_base;
+       mb->un.varRegVpi.sid = vport->fc_myDID;
+       mb->un.varRegVpi.vfi = vport->vfi + vport->phba->vfi_base;
 
        mb->mbxCommand = MBX_REG_VPI;
        mb->mbxOwner = OWN_HOST;
@@ -760,10 +809,10 @@ lpfc_reg_vpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t sid,
 void
 lpfc_unreg_vpi(struct lpfc_hba *phba, uint16_t vpi, LPFC_MBOXQ_t *pmb)
 {
-       MAILBOX_t *mb = &pmb->mb;
+       MAILBOX_t *mb = &pmb->u.mb;
        memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
-       mb->un.varUnregVpi.vpi = vpi;
+       mb->un.varUnregVpi.vpi = vpi + phba->vpi_base;
 
        mb->mbxCommand = MBX_UNREG_VPI;
        mb->mbxOwner = OWN_HOST;
@@ -852,7 +901,7 @@ lpfc_config_pcb_setup(struct lpfc_hba * phba)
 void
 lpfc_read_rev(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 {
-       MAILBOX_t *mb = &pmb->mb;
+       MAILBOX_t *mb = &pmb->u.mb;
        memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
        mb->un.varRdRev.cv = 1;
        mb->un.varRdRev.v3req = 1; /* Request SLI3 info */
@@ -945,7 +994,7 @@ lpfc_config_hbq(struct lpfc_hba *phba, uint32_t id,
                uint32_t hbq_entry_index, LPFC_MBOXQ_t *pmb)
 {
        int i;
-       MAILBOX_t *mb = &pmb->mb;
+       MAILBOX_t *mb = &pmb->u.mb;
        struct config_hbq_var *hbqmb = &mb->un.varCfgHbq;
 
        memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
@@ -1020,7 +1069,7 @@ void
 lpfc_config_ring(struct lpfc_hba * phba, int ring, LPFC_MBOXQ_t * pmb)
 {
        int i;
-       MAILBOX_t *mb = &pmb->mb;
+       MAILBOX_t *mb = &pmb->u.mb;
        struct lpfc_sli *psli;
        struct lpfc_sli_ring *pring;
 
@@ -1075,7 +1124,7 @@ void
 lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
        MAILBOX_t __iomem *mb_slim = (MAILBOX_t __iomem *) phba->MBslimaddr;
-       MAILBOX_t *mb = &pmb->mb;
+       MAILBOX_t *mb = &pmb->u.mb;
        dma_addr_t pdma_addr;
        uint32_t bar_low, bar_high;
        size_t offset;
@@ -1099,21 +1148,22 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 
        /* If HBA supports SLI=3 ask for it */
 
-       if (phba->sli_rev == 3 && phba->vpd.sli3Feat.cerbm) {
+       if (phba->sli_rev == LPFC_SLI_REV3 && phba->vpd.sli3Feat.cerbm) {
                if (phba->cfg_enable_bg)
                        mb->un.varCfgPort.cbg = 1; /* configure BlockGuard */
+               mb->un.varCfgPort.cdss = 1; /* Configure Security */
                mb->un.varCfgPort.cerbm = 1; /* Request HBQs */
                mb->un.varCfgPort.ccrp = 1; /* Command Ring Polling */
                mb->un.varCfgPort.cinb = 1; /* Interrupt Notification Block */
                mb->un.varCfgPort.max_hbq = lpfc_sli_hbq_count();
                if (phba->max_vpi && phba->cfg_enable_npiv &&
                    phba->vpd.sli3Feat.cmv) {
-                       mb->un.varCfgPort.max_vpi = phba->max_vpi;
+                       mb->un.varCfgPort.max_vpi = LPFC_MAX_VPI;
                        mb->un.varCfgPort.cmv = 1;
                } else
                        mb->un.varCfgPort.max_vpi = phba->max_vpi = 0;
        } else
-               phba->sli_rev = 2;
+               phba->sli_rev = LPFC_SLI_REV2;
        mb->un.varCfgPort.sli_mode = phba->sli_rev;
 
        /* Now setup pcb */
@@ -1245,7 +1295,7 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 void
 lpfc_kill_board(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 {
-       MAILBOX_t *mb = &pmb->mb;
+       MAILBOX_t *mb = &pmb->u.mb;
 
        memset(pmb, 0, sizeof(LPFC_MBOXQ_t));
        mb->mbxCommand = MBX_KILL_BOARD;
@@ -1304,29 +1354,98 @@ lpfc_mbox_get(struct lpfc_hba * phba)
        return mbq;
 }
 
+/**
+ * __lpfc_mbox_cmpl_put - Put mailbox cmd into mailbox cmd complete list
+ * @phba: pointer to lpfc hba data structure.
+ * @mbq: pointer to the driver internal queue element for mailbox command.
+ *
+ * This routine put the completed mailbox command into the mailbox command
+ * complete list. This is the unlocked version of the routine. The mailbox
+ * complete list is used by the driver worker thread to process mailbox
+ * complete callback functions outside the driver interrupt handler.
+ **/
+void
+__lpfc_mbox_cmpl_put(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbq)
+{
+       list_add_tail(&mbq->list, &phba->sli.mboxq_cmpl);
+}
+
 /**
  * lpfc_mbox_cmpl_put - Put mailbox command into mailbox command complete list
  * @phba: pointer to lpfc hba data structure.
  * @mbq: pointer to the driver internal queue element for mailbox command.
  *
  * This routine put the completed mailbox command into the mailbox command
- * complete list. This routine is called from driver interrupt handler
- * context.The mailbox complete list is used by the driver worker thread
- * to process mailbox complete callback functions outside the driver interrupt
- * handler.
+ * complete list. This is the locked version of the routine. The mailbox
+ * complete list is used by the driver worker thread to process mailbox
+ * complete callback functions outside the driver interrupt handler.
  **/
 void
-lpfc_mbox_cmpl_put(struct lpfc_hba * phba, LPFC_MBOXQ_t * mbq)
+lpfc_mbox_cmpl_put(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbq)
 {
        unsigned long iflag;
 
        /* This function expects to be called from interrupt context */
        spin_lock_irqsave(&phba->hbalock, iflag);
-       list_add_tail(&mbq->list, &phba->sli.mboxq_cmpl);
+       __lpfc_mbox_cmpl_put(phba, mbq);
        spin_unlock_irqrestore(&phba->hbalock, iflag);
        return;
 }
 
+/**
+ * lpfc_mbox_cmd_check - Check the validality of a mailbox command
+ * @phba: pointer to lpfc hba data structure.
+ * @mboxq: pointer to the driver internal queue element for mailbox command.
+ *
+ * This routine is to check whether a mailbox command is valid to be issued.
+ * This check will be performed by both the mailbox issue API when a client
+ * is to issue a mailbox command to the mailbox transport.
+ *
+ * Return 0 - pass the check, -ENODEV - fail the check
+ **/
+int
+lpfc_mbox_cmd_check(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+{
+       /* Mailbox command that have a completion handler must also have a
+        * vport specified.
+        */
+       if (mboxq->mbox_cmpl && mboxq->mbox_cmpl != lpfc_sli_def_mbox_cmpl &&
+           mboxq->mbox_cmpl != lpfc_sli_wake_mbox_wait) {
+               if (!mboxq->vport) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_VPORT,
+                                       "1814 Mbox x%x failed, no vport\n",
+                                       mboxq->u.mb.mbxCommand);
+                       dump_stack();
+                       return -ENODEV;
+               }
+       }
+       return 0;
+}
+
+/**
+ * lpfc_mbox_dev_check - Check the device state for issuing a mailbox command
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is to check whether the HBA device is ready for posting a
+ * mailbox command. It is used by the mailbox transport API at the time the
+ * to post a mailbox command to the device.
+ *
+ * Return 0 - pass the check, -ENODEV - fail the check
+ **/
+int
+lpfc_mbox_dev_check(struct lpfc_hba *phba)
+{
+       /* If the PCI channel is in offline state, do not issue mbox */
+       if (unlikely(pci_channel_offline(phba->pcidev)))
+               return -ENODEV;
+
+       /* If the HBA is in error state, do not issue mbox */
+       if (phba->link_state == LPFC_HBA_ERROR)
+               return -ENODEV;
+
+       return 0;
+}
+
 /**
  * lpfc_mbox_tmo_val - Retrieve mailbox command timeout value
  * @phba: pointer to lpfc hba data structure.
@@ -1350,6 +1469,475 @@ lpfc_mbox_tmo_val(struct lpfc_hba *phba, int cmd)
        case MBX_WRITE_WWN:     /* 0x98 */
        case MBX_LOAD_EXP_ROM:  /* 0x9C */
                return LPFC_MBOX_TMO_FLASH_CMD;
+       case MBX_SLI4_CONFIG:   /* 0x9b */
+               return LPFC_MBOX_SLI4_CONFIG_TMO;
        }
        return LPFC_MBOX_TMO;
 }
+
+/**
+ * lpfc_sli4_mbx_sge_set - Set a sge entry in non-embedded mailbox command
+ * @mbox: pointer to lpfc mbox command.
+ * @sgentry: sge entry index.
+ * @phyaddr: physical address for the sge
+ * @length: Length of the sge.
+ *
+ * This routine sets up an entry in the non-embedded mailbox command at the sge
+ * index location.
+ **/
+void
+lpfc_sli4_mbx_sge_set(struct lpfcMboxq *mbox, uint32_t sgentry,
+                     dma_addr_t phyaddr, uint32_t length)
+{
+       struct lpfc_mbx_nembed_cmd *nembed_sge;
+
+       nembed_sge = (struct lpfc_mbx_nembed_cmd *)
+                               &mbox->u.mqe.un.nembed_cmd;
+       nembed_sge->sge[sgentry].pa_lo = putPaddrLow(phyaddr);
+       nembed_sge->sge[sgentry].pa_hi = putPaddrHigh(phyaddr);
+       nembed_sge->sge[sgentry].length = length;
+}
+
+/**
+ * lpfc_sli4_mbx_sge_get - Get a sge entry from non-embedded mailbox command
+ * @mbox: pointer to lpfc mbox command.
+ * @sgentry: sge entry index.
+ *
+ * This routine gets an entry from the non-embedded mailbox command at the sge
+ * index location.
+ **/
+void
+lpfc_sli4_mbx_sge_get(struct lpfcMboxq *mbox, uint32_t sgentry,
+                     struct lpfc_mbx_sge *sge)
+{
+       struct lpfc_mbx_nembed_cmd *nembed_sge;
+
+       nembed_sge = (struct lpfc_mbx_nembed_cmd *)
+                               &mbox->u.mqe.un.nembed_cmd;
+       sge->pa_lo = nembed_sge->sge[sgentry].pa_lo;
+       sge->pa_hi = nembed_sge->sge[sgentry].pa_hi;
+       sge->length = nembed_sge->sge[sgentry].length;
+}
+
+/**
+ * lpfc_sli4_mbox_cmd_free - Free a sli4 mailbox command
+ * @phba: pointer to lpfc hba data structure.
+ * @mbox: pointer to lpfc mbox command.
+ *
+ * This routine frees SLI4 specific mailbox command for sending IOCTL command.
+ **/
+void
+lpfc_sli4_mbox_cmd_free(struct lpfc_hba *phba, struct lpfcMboxq *mbox)
+{
+       struct lpfc_mbx_sli4_config *sli4_cfg;
+       struct lpfc_mbx_sge sge;
+       dma_addr_t phyaddr;
+       uint32_t sgecount, sgentry;
+
+       sli4_cfg = &mbox->u.mqe.un.sli4_config;
+
+       /* For embedded mbox command, just free the mbox command */
+       if (bf_get(lpfc_mbox_hdr_emb, &sli4_cfg->header.cfg_mhdr)) {
+               mempool_free(mbox, phba->mbox_mem_pool);
+               return;
+       }
+
+       /* For non-embedded mbox command, we need to free the pages first */
+       sgecount = bf_get(lpfc_mbox_hdr_sge_cnt, &sli4_cfg->header.cfg_mhdr);
+       /* There is nothing we can do if there is no sge address array */
+       if (unlikely(!mbox->sge_array)) {
+               mempool_free(mbox, phba->mbox_mem_pool);
+               return;
+       }
+       /* Each non-embedded DMA memory was allocated in the length of a page */
+       for (sgentry = 0; sgentry < sgecount; sgentry++) {
+               lpfc_sli4_mbx_sge_get(mbox, sgentry, &sge);
+               phyaddr = getPaddr(sge.pa_hi, sge.pa_lo);
+               dma_free_coherent(&phba->pcidev->dev, PAGE_SIZE,
+                                 mbox->sge_array->addr[sgentry], phyaddr);
+       }
+       /* Free the sge address array memory */
+       kfree(mbox->sge_array);
+       /* Finally, free the mailbox command itself */
+       mempool_free(mbox, phba->mbox_mem_pool);
+}
+
+/**
+ * lpfc_sli4_config - Initialize the  SLI4 Config Mailbox command
+ * @phba: pointer to lpfc hba data structure.
+ * @mbox: pointer to lpfc mbox command.
+ * @subsystem: The sli4 config sub mailbox subsystem.
+ * @opcode: The sli4 config sub mailbox command opcode.
+ * @length: Length of the sli4 config mailbox command.
+ *
+ * This routine sets up the header fields of SLI4 specific mailbox command
+ * for sending IOCTL command.
+ *
+ * Return: the actual length of the mbox command allocated (mostly useful
+ *         for none embedded mailbox command).
+ **/
+int
+lpfc_sli4_config(struct lpfc_hba *phba, struct lpfcMboxq *mbox,
+                uint8_t subsystem, uint8_t opcode, uint32_t length, bool emb)
+{
+       struct lpfc_mbx_sli4_config *sli4_config;
+       union lpfc_sli4_cfg_shdr *cfg_shdr = NULL;
+       uint32_t alloc_len;
+       uint32_t resid_len;
+       uint32_t pagen, pcount;
+       void *viraddr;
+       dma_addr_t phyaddr;
+
+       /* Set up SLI4 mailbox command header fields */
+       memset(mbox, 0, sizeof(*mbox));
+       bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_SLI4_CONFIG);
+
+       /* Set up SLI4 ioctl command header fields */
+       sli4_config = &mbox->u.mqe.un.sli4_config;
+
+       /* Setup for the embedded mbox command */
+       if (emb) {
+               /* Set up main header fields */
+               bf_set(lpfc_mbox_hdr_emb, &sli4_config->header.cfg_mhdr, 1);
+               sli4_config->header.cfg_mhdr.payload_length =
+                                       LPFC_MBX_CMD_HDR_LENGTH + length;
+               /* Set up sub-header fields following main header */
+               bf_set(lpfc_mbox_hdr_opcode,
+                       &sli4_config->header.cfg_shdr.request, opcode);
+               bf_set(lpfc_mbox_hdr_subsystem,
+                       &sli4_config->header.cfg_shdr.request, subsystem);
+               sli4_config->header.cfg_shdr.request.request_length = length;
+               return length;
+       }
+
+       /* Setup for the none-embedded mbox command */
+       pcount = (PAGE_ALIGN(length))/PAGE_SIZE;
+       pcount = (pcount > LPFC_SLI4_MBX_SGE_MAX_PAGES) ?
+                               LPFC_SLI4_MBX_SGE_MAX_PAGES : pcount;
+       /* Allocate record for keeping SGE virtual addresses */
+       mbox->sge_array = kmalloc(sizeof(struct lpfc_mbx_nembed_sge_virt),
+                                 GFP_KERNEL);
+       if (!mbox->sge_array)
+               return 0;
+
+       for (pagen = 0, alloc_len = 0; pagen < pcount; pagen++) {
+               /* The DMA memory is always allocated in the length of a
+                * page even though the last SGE might not fill up to a
+                * page, this is used as a priori size of PAGE_SIZE for
+                * the later DMA memory free.
+                */
+               viraddr = dma_alloc_coherent(&phba->pcidev->dev, PAGE_SIZE,
+                                            &phyaddr, GFP_KERNEL);
+               /* In case of malloc fails, proceed with whatever we have */
+               if (!viraddr)
+                       break;
+               mbox->sge_array->addr[pagen] = viraddr;
+               /* Keep the first page for later sub-header construction */
+               if (pagen == 0)
+                       cfg_shdr = (union lpfc_sli4_cfg_shdr *)viraddr;
+               resid_len = length - alloc_len;
+               if (resid_len > PAGE_SIZE) {
+                       lpfc_sli4_mbx_sge_set(mbox, pagen, phyaddr,
+                                             PAGE_SIZE);
+                       alloc_len += PAGE_SIZE;
+               } else {
+                       lpfc_sli4_mbx_sge_set(mbox, pagen, phyaddr,
+                                             resid_len);
+                       alloc_len = length;
+               }
+       }
+
+       /* Set up main header fields in mailbox command */
+       sli4_config->header.cfg_mhdr.payload_length = alloc_len;
+       bf_set(lpfc_mbox_hdr_sge_cnt, &sli4_config->header.cfg_mhdr, pagen);
+
+       /* Set up sub-header fields into the first page */
+       if (pagen > 0) {
+               bf_set(lpfc_mbox_hdr_opcode, &cfg_shdr->request, opcode);
+               bf_set(lpfc_mbox_hdr_subsystem, &cfg_shdr->request, subsystem);
+               cfg_shdr->request.request_length =
+                               alloc_len - sizeof(union  lpfc_sli4_cfg_shdr);
+       }
+       /* The sub-header is in DMA memory, which needs endian converstion */
+       lpfc_sli_pcimem_bcopy(cfg_shdr, cfg_shdr,
+                             sizeof(union  lpfc_sli4_cfg_shdr));
+
+       return alloc_len;
+}
+
+/**
+ * lpfc_sli4_mbox_opcode_get - Get the opcode from a sli4 mailbox command
+ * @phba: pointer to lpfc hba data structure.
+ * @mbox: pointer to lpfc mbox command.
+ *
+ * This routine gets the opcode from a SLI4 specific mailbox command for
+ * sending IOCTL command. If the mailbox command is not MBX_SLI4_CONFIG
+ * (0x9B) or if the IOCTL sub-header is not present, opcode 0x0 shall be
+ * returned.
+ **/
+uint8_t
+lpfc_sli4_mbox_opcode_get(struct lpfc_hba *phba, struct lpfcMboxq *mbox)
+{
+       struct lpfc_mbx_sli4_config *sli4_cfg;
+       union lpfc_sli4_cfg_shdr *cfg_shdr;
+
+       if (mbox->u.mb.mbxCommand != MBX_SLI4_CONFIG)
+               return 0;
+       sli4_cfg = &mbox->u.mqe.un.sli4_config;
+
+       /* For embedded mbox command, get opcode from embedded sub-header*/
+       if (bf_get(lpfc_mbox_hdr_emb, &sli4_cfg->header.cfg_mhdr)) {
+               cfg_shdr = &mbox->u.mqe.un.sli4_config.header.cfg_shdr;
+               return bf_get(lpfc_mbox_hdr_opcode, &cfg_shdr->request);
+       }
+
+       /* For non-embedded mbox command, get opcode from first dma page */
+       if (unlikely(!mbox->sge_array))
+               return 0;
+       cfg_shdr = (union lpfc_sli4_cfg_shdr *)mbox->sge_array->addr[0];
+       return bf_get(lpfc_mbox_hdr_opcode, &cfg_shdr->request);
+}
+
+/**
+ * lpfc_request_features: Configure SLI4 REQUEST_FEATURES mailbox
+ * @mboxq: pointer to lpfc mbox command.
+ *
+ * This routine sets up the mailbox for an SLI4 REQUEST_FEATURES
+ * mailbox command.
+ **/
+void
+lpfc_request_features(struct lpfc_hba *phba, struct lpfcMboxq *mboxq)
+{
+       /* Set up SLI4 mailbox command header fields */
+       memset(mboxq, 0, sizeof(LPFC_MBOXQ_t));
+       bf_set(lpfc_mqe_command, &mboxq->u.mqe, MBX_SLI4_REQ_FTRS);
+
+       /* Set up host requested features. */
+       bf_set(lpfc_mbx_rq_ftr_rq_fcpi, &mboxq->u.mqe.un.req_ftrs, 1);
+
+       /* Virtual fabrics and FIPs are not supported yet. */
+       bf_set(lpfc_mbx_rq_ftr_rq_ifip, &mboxq->u.mqe.un.req_ftrs, 0);
+
+       /* Enable DIF (block guard) only if configured to do so. */
+       if (phba->cfg_enable_bg)
+               bf_set(lpfc_mbx_rq_ftr_rq_dif, &mboxq->u.mqe.un.req_ftrs, 1);
+
+       /* Enable NPIV only if configured to do so. */
+       if (phba->max_vpi && phba->cfg_enable_npiv)
+               bf_set(lpfc_mbx_rq_ftr_rq_npiv, &mboxq->u.mqe.un.req_ftrs, 1);
+
+       return;
+}
+
+/**
+ * lpfc_init_vfi - Initialize the INIT_VFI mailbox command
+ * @mbox: pointer to lpfc mbox command to initialize.
+ * @vport: Vport associated with the VF.
+ *
+ * This routine initializes @mbox to all zeros and then fills in the mailbox
+ * fields from @vport. INIT_VFI configures virtual fabrics identified by VFI
+ * in the context of an FCF. The driver issues this command to setup a VFI
+ * before issuing a FLOGI to login to the VSAN. The driver should also issue a
+ * REG_VFI after a successful VSAN login.
+ **/
+void
+lpfc_init_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport)
+{
+       struct lpfc_mbx_init_vfi *init_vfi;
+
+       memset(mbox, 0, sizeof(*mbox));
+       init_vfi = &mbox->u.mqe.un.init_vfi;
+       bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_INIT_VFI);
+       bf_set(lpfc_init_vfi_vr, init_vfi, 1);
+       bf_set(lpfc_init_vfi_vt, init_vfi, 1);
+       bf_set(lpfc_init_vfi_vfi, init_vfi, vport->vfi + vport->phba->vfi_base);
+       bf_set(lpfc_init_vfi_fcfi, init_vfi, vport->phba->fcf.fcfi);
+}
+
+/**
+ * lpfc_reg_vfi - Initialize the REG_VFI mailbox command
+ * @mbox: pointer to lpfc mbox command to initialize.
+ * @vport: vport associated with the VF.
+ * @phys: BDE DMA bus address used to send the service parameters to the HBA.
+ *
+ * This routine initializes @mbox to all zeros and then fills in the mailbox
+ * fields from @vport, and uses @buf as a DMAable buffer to send the vport's
+ * fc service parameters to the HBA for this VFI. REG_VFI configures virtual
+ * fabrics identified by VFI in the context of an FCF.
+ **/
+void
+lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys)
+{
+       struct lpfc_mbx_reg_vfi *reg_vfi;
+
+       memset(mbox, 0, sizeof(*mbox));
+       reg_vfi = &mbox->u.mqe.un.reg_vfi;
+       bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_REG_VFI);
+       bf_set(lpfc_reg_vfi_vp, reg_vfi, 1);
+       bf_set(lpfc_reg_vfi_vfi, reg_vfi, vport->vfi + vport->phba->vfi_base);
+       bf_set(lpfc_reg_vfi_fcfi, reg_vfi, vport->phba->fcf.fcfi);
+       bf_set(lpfc_reg_vfi_vpi, reg_vfi, vport->vpi + vport->phba->vpi_base);
+       reg_vfi->bde.addrHigh = putPaddrHigh(phys);
+       reg_vfi->bde.addrLow = putPaddrLow(phys);
+       reg_vfi->bde.tus.f.bdeSize = sizeof(vport->fc_sparam);
+       reg_vfi->bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64;
+       bf_set(lpfc_reg_vfi_nport_id, reg_vfi, vport->fc_myDID);
+}
+
+/**
+ * lpfc_init_vpi - Initialize the INIT_VPI mailbox command
+ * @mbox: pointer to lpfc mbox command to initialize.
+ * @vpi: VPI to be initialized.
+ *
+ * The INIT_VPI mailbox command supports virtual N_Ports. The driver uses the
+ * command to activate a virtual N_Port. The HBA assigns a MAC address to use
+ * with the virtual N Port.  The SLI Host issues this command before issuing a
+ * FDISC to connect to the Fabric. The SLI Host should issue a REG_VPI after a
+ * successful virtual NPort login.
+ **/
+void
+lpfc_init_vpi(struct lpfcMboxq *mbox, uint16_t vpi)
+{
+       memset(mbox, 0, sizeof(*mbox));
+       bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_INIT_VPI);
+       bf_set(lpfc_init_vpi_vpi, &mbox->u.mqe.un.init_vpi, vpi);
+}
+
+/**
+ * lpfc_unreg_vfi - Initialize the UNREG_VFI mailbox command
+ * @mbox: pointer to lpfc mbox command to initialize.
+ * @vfi: VFI to be unregistered.
+ *
+ * The UNREG_VFI mailbox command causes the SLI Host to put a virtual fabric
+ * (logical NPort) into the inactive state. The SLI Host must have logged out
+ * and unregistered all remote N_Ports to abort any activity on the virtual
+ * fabric. The SLI Port posts the mailbox response after marking the virtual
+ * fabric inactive.
+ **/
+void
+lpfc_unreg_vfi(struct lpfcMboxq *mbox, uint16_t vfi)
+{
+       memset(mbox, 0, sizeof(*mbox));
+       bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_UNREG_VFI);
+       bf_set(lpfc_unreg_vfi_vfi, &mbox->u.mqe.un.unreg_vfi, vfi);
+}
+
+/**
+ * lpfc_dump_fcoe_param - Dump config region 23 to get FCoe parameters.
+ * @phba: pointer to the hba structure containing.
+ * @mbox: pointer to lpfc mbox command to initialize.
+ *
+ * This function create a SLI4 dump mailbox command to dump FCoE
+ * parameters stored in region 23.
+ **/
+int
+lpfc_dump_fcoe_param(struct lpfc_hba *phba,
+               struct lpfcMboxq *mbox)
+{
+       struct lpfc_dmabuf *mp = NULL;
+       MAILBOX_t *mb;
+
+       memset(mbox, 0, sizeof(*mbox));
+       mb = &mbox->u.mb;
+
+       mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+       if (mp)
+               mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
+
+       if (!mp || !mp->virt) {
+               kfree(mp);
+               /* dump_fcoe_param failed to allocate memory */
+               lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
+                       "2569 lpfc_dump_fcoe_param: memory"
+                       " allocation failed \n");
+               return 1;
+       }
+
+       memset(mp->virt, 0, LPFC_BPL_SIZE);
+       INIT_LIST_HEAD(&mp->list);
+
+       /* save address for completion */
+       mbox->context1 = (uint8_t *) mp;
+
+       mb->mbxCommand = MBX_DUMP_MEMORY;
+       mb->un.varDmp.type = DMP_NV_PARAMS;
+       mb->un.varDmp.region_id = DMP_REGION_FCOEPARAM;
+       mb->un.varDmp.sli4_length = DMP_FCOEPARAM_RGN_SIZE;
+       mb->un.varWords[3] = putPaddrLow(mp->phys);
+       mb->un.varWords[4] = putPaddrHigh(mp->phys);
+       return 0;
+}
+
+/**
+ * lpfc_reg_fcfi - Initialize the REG_FCFI mailbox command
+ * @phba: pointer to the hba structure containing the FCF index and RQ ID.
+ * @mbox: pointer to lpfc mbox command to initialize.
+ *
+ * The REG_FCFI mailbox command supports Fibre Channel Forwarders (FCFs). The
+ * SLI Host uses the command to activate an FCF after it has acquired FCF
+ * information via a READ_FCF mailbox command. This mailbox command also is used
+ * to indicate where received unsolicited frames from this FCF will be sent. By
+ * default this routine will set up the FCF to forward all unsolicited frames
+ * the the RQ ID passed in the @phba. This can be overridden by the caller for
+ * more complicated setups.
+ **/
+void
+lpfc_reg_fcfi(struct lpfc_hba *phba, struct lpfcMboxq *mbox)
+{
+       struct lpfc_mbx_reg_fcfi *reg_fcfi;
+
+       memset(mbox, 0, sizeof(*mbox));
+       reg_fcfi = &mbox->u.mqe.un.reg_fcfi;
+       bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_REG_FCFI);
+       bf_set(lpfc_reg_fcfi_rq_id0, reg_fcfi, phba->sli4_hba.hdr_rq->queue_id);
+       bf_set(lpfc_reg_fcfi_rq_id1, reg_fcfi, REG_FCF_INVALID_QID);
+       bf_set(lpfc_reg_fcfi_rq_id2, reg_fcfi, REG_FCF_INVALID_QID);
+       bf_set(lpfc_reg_fcfi_rq_id3, reg_fcfi, REG_FCF_INVALID_QID);
+       bf_set(lpfc_reg_fcfi_info_index, reg_fcfi, phba->fcf.fcf_indx);
+       /* reg_fcf addr mode is bit wise inverted value of fcf addr_mode */
+       bf_set(lpfc_reg_fcfi_mam, reg_fcfi,
+               (~phba->fcf.addr_mode) & 0x3);
+       if (phba->fcf.fcf_flag & FCF_VALID_VLAN) {
+               bf_set(lpfc_reg_fcfi_vv, reg_fcfi, 1);
+               bf_set(lpfc_reg_fcfi_vlan_tag, reg_fcfi, phba->fcf.vlan_id);
+       }
+}
+
+/**
+ * lpfc_unreg_fcfi - Initialize the UNREG_FCFI mailbox command
+ * @mbox: pointer to lpfc mbox command to initialize.
+ * @fcfi: FCFI to be unregistered.
+ *
+ * The UNREG_FCFI mailbox command supports Fibre Channel Forwarders (FCFs).
+ * The SLI Host uses the command to inactivate an FCFI.
+ **/
+void
+lpfc_unreg_fcfi(struct lpfcMboxq *mbox, uint16_t fcfi)
+{
+       memset(mbox, 0, sizeof(*mbox));
+       bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_UNREG_FCFI);
+       bf_set(lpfc_unreg_fcfi, &mbox->u.mqe.un.unreg_fcfi, fcfi);
+}
+
+/**
+ * lpfc_resume_rpi - Initialize the RESUME_RPI mailbox command
+ * @mbox: pointer to lpfc mbox command to initialize.
+ * @ndlp: The nodelist structure that describes the RPI to resume.
+ *
+ * The RESUME_RPI mailbox command is used to restart I/O to an RPI after a
+ * link event.
+ **/
+void
+lpfc_resume_rpi(struct lpfcMboxq *mbox, struct lpfc_nodelist *ndlp)
+{
+       struct lpfc_mbx_resume_rpi *resume_rpi;
+
+       memset(mbox, 0, sizeof(*mbox));
+       resume_rpi = &mbox->u.mqe.un.resume_rpi;
+       bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_RESUME_RPI);
+       bf_set(lpfc_resume_rpi_rpi, resume_rpi, ndlp->nlp_rpi);
+       bf_set(lpfc_resume_rpi_vpi, resume_rpi,
+              ndlp->vport->vpi + ndlp->vport->phba->vpi_base);
+       bf_set(lpfc_resume_rpi_vfi, resume_rpi,
+              ndlp->vport->vfi + ndlp->vport->phba->vfi_base);
+}
index 35a976733398827968083062e2377543d0c1c8a3..e198c917c13ecc55d91839d8ca64a8051ee7f097 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
 
 #include <scsi/scsi.h>
 
+#include "lpfc_hw4.h"
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
+#include "lpfc_sli4.h"
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -45,7 +47,7 @@
  * @phba: HBA to allocate pools for
  *
  * Description: Creates and allocates PCI pools lpfc_scsi_dma_buf_pool,
- * lpfc_mbuf_pool, lpfc_hbq_pool.  Creates and allocates kmalloc-backed mempools
+ * lpfc_mbuf_pool, lpfc_hrb_pool.  Creates and allocates kmalloc-backed mempools
  * for LPFC_MBOXQ_t and lpfc_nodelist.  Also allocates the VPI bitmask.
  *
  * Notes: Not interrupt-safe.  Must be called with no locks held.  If any
  *   -ENOMEM on failure (if any memory allocations fail)
  **/
 int
-lpfc_mem_alloc(struct lpfc_hba * phba)
+lpfc_mem_alloc(struct lpfc_hba *phba, int align)
 {
        struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
        int longs;
        int i;
 
-       phba->lpfc_scsi_dma_buf_pool = pci_pool_create("lpfc_scsi_dma_buf_pool",
-                               phba->pcidev, phba->cfg_sg_dma_buf_size, 8, 0);
+       if (phba->sli_rev == LPFC_SLI_REV4)
+               phba->lpfc_scsi_dma_buf_pool =
+                       pci_pool_create("lpfc_scsi_dma_buf_pool",
+                               phba->pcidev,
+                               phba->cfg_sg_dma_buf_size,
+                               phba->cfg_sg_dma_buf_size,
+                               0);
+       else
+               phba->lpfc_scsi_dma_buf_pool =
+                       pci_pool_create("lpfc_scsi_dma_buf_pool",
+                               phba->pcidev, phba->cfg_sg_dma_buf_size,
+                               align, 0);
        if (!phba->lpfc_scsi_dma_buf_pool)
                goto fail;
 
        phba->lpfc_mbuf_pool = pci_pool_create("lpfc_mbuf_pool", phba->pcidev,
-                                                       LPFC_BPL_SIZE, 8,0);
+                                                       LPFC_BPL_SIZE,
+                                                       align, 0);
        if (!phba->lpfc_mbuf_pool)
                goto fail_free_dma_buf_pool;
 
@@ -97,23 +110,31 @@ lpfc_mem_alloc(struct lpfc_hba * phba)
                                                sizeof(struct lpfc_nodelist));
        if (!phba->nlp_mem_pool)
                goto fail_free_mbox_pool;
-
-       phba->lpfc_hbq_pool = pci_pool_create("lpfc_hbq_pool",phba->pcidev,
-                                             LPFC_BPL_SIZE, 8, 0);
-       if (!phba->lpfc_hbq_pool)
+       phba->lpfc_hrb_pool = pci_pool_create("lpfc_hrb_pool",
+                                             phba->pcidev,
+                                             LPFC_HDR_BUF_SIZE, align, 0);
+       if (!phba->lpfc_hrb_pool)
                goto fail_free_nlp_mem_pool;
+       phba->lpfc_drb_pool = pci_pool_create("lpfc_drb_pool",
+                                             phba->pcidev,
+                                             LPFC_DATA_BUF_SIZE, align, 0);
+       if (!phba->lpfc_drb_pool)
+               goto fail_free_hbq_pool;
 
        /* vpi zero is reserved for the physical port so add 1 to max */
        longs = ((phba->max_vpi + 1) + BITS_PER_LONG - 1) / BITS_PER_LONG;
        phba->vpi_bmask = kzalloc(longs * sizeof(unsigned long), GFP_KERNEL);
        if (!phba->vpi_bmask)
-               goto fail_free_hbq_pool;
+               goto fail_free_dbq_pool;
 
        return 0;
 
+ fail_free_dbq_pool:
+       pci_pool_destroy(phba->lpfc_drb_pool);
+       phba->lpfc_drb_pool = NULL;
  fail_free_hbq_pool:
-       lpfc_sli_hbqbuf_free_all(phba);
-       pci_pool_destroy(phba->lpfc_hbq_pool);
+       pci_pool_destroy(phba->lpfc_hrb_pool);
+       phba->lpfc_hrb_pool = NULL;
  fail_free_nlp_mem_pool:
        mempool_destroy(phba->nlp_mem_pool);
        phba->nlp_mem_pool = NULL;
@@ -136,27 +157,73 @@ lpfc_mem_alloc(struct lpfc_hba * phba)
 }
 
 /**
- * lpfc_mem_free - Frees all PCI and memory allocated by lpfc_mem_alloc
+ * lpfc_mem_free - Frees memory allocated by lpfc_mem_alloc
  * @phba: HBA to free memory for
  *
- * Description: Frees PCI pools lpfc_scsi_dma_buf_pool, lpfc_mbuf_pool,
- * lpfc_hbq_pool.  Frees kmalloc-backed mempools for LPFC_MBOXQ_t and
- * lpfc_nodelist.  Also frees the VPI bitmask
+ * Description: Free the memory allocated by lpfc_mem_alloc routine. This
+ * routine is a the counterpart of lpfc_mem_alloc.
  *
  * Returns: None
  **/
 void
-lpfc_mem_free(struct lpfc_hba * phba)
+lpfc_mem_free(struct lpfc_hba *phba)
 {
-       struct lpfc_sli *psli = &phba->sli;
-       struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
-       LPFC_MBOXQ_t *mbox, *next_mbox;
-       struct lpfc_dmabuf   *mp;
        int i;
+       struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
 
+       /* Free VPI bitmask memory */
        kfree(phba->vpi_bmask);
+
+       /* Free HBQ pools */
        lpfc_sli_hbqbuf_free_all(phba);
+       pci_pool_destroy(phba->lpfc_drb_pool);
+       phba->lpfc_drb_pool = NULL;
+       pci_pool_destroy(phba->lpfc_hrb_pool);
+       phba->lpfc_hrb_pool = NULL;
+
+       /* Free NLP memory pool */
+       mempool_destroy(phba->nlp_mem_pool);
+       phba->nlp_mem_pool = NULL;
+
+       /* Free mbox memory pool */
+       mempool_destroy(phba->mbox_mem_pool);
+       phba->mbox_mem_pool = NULL;
+
+       /* Free MBUF memory pool */
+       for (i = 0; i < pool->current_count; i++)
+               pci_pool_free(phba->lpfc_mbuf_pool, pool->elements[i].virt,
+                             pool->elements[i].phys);
+       kfree(pool->elements);
+
+       pci_pool_destroy(phba->lpfc_mbuf_pool);
+       phba->lpfc_mbuf_pool = NULL;
 
+       /* Free DMA buffer memory pool */
+       pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool);
+       phba->lpfc_scsi_dma_buf_pool = NULL;
+
+       return;
+}
+
+/**
+ * lpfc_mem_free_all - Frees all PCI and driver memory
+ * @phba: HBA to free memory for
+ *
+ * Description: Free memory from PCI and driver memory pools and also those
+ * used : lpfc_scsi_dma_buf_pool, lpfc_mbuf_pool, lpfc_hrb_pool. Frees
+ * kmalloc-backed mempools for LPFC_MBOXQ_t and lpfc_nodelist. Also frees
+ * the VPI bitmask.
+ *
+ * Returns: None
+ **/
+void
+lpfc_mem_free_all(struct lpfc_hba *phba)
+{
+       struct lpfc_sli *psli = &phba->sli;
+       LPFC_MBOXQ_t *mbox, *next_mbox;
+       struct lpfc_dmabuf   *mp;
+
+       /* Free memory used in mailbox queue back to mailbox memory pool */
        list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq, list) {
                mp = (struct lpfc_dmabuf *) (mbox->context1);
                if (mp) {
@@ -166,6 +233,7 @@ lpfc_mem_free(struct lpfc_hba * phba)
                list_del(&mbox->list);
                mempool_free(mbox, phba->mbox_mem_pool);
        }
+       /* Free memory used in mailbox cmpl list back to mailbox memory pool */
        list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq_cmpl, list) {
                mp = (struct lpfc_dmabuf *) (mbox->context1);
                if (mp) {
@@ -175,8 +243,10 @@ lpfc_mem_free(struct lpfc_hba * phba)
                list_del(&mbox->list);
                mempool_free(mbox, phba->mbox_mem_pool);
        }
-
+       /* Free the active mailbox command back to the mailbox memory pool */
+       spin_lock_irq(&phba->hbalock);
        psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+       spin_unlock_irq(&phba->hbalock);
        if (psli->mbox_active) {
                mbox = psli->mbox_active;
                mp = (struct lpfc_dmabuf *) (mbox->context1);
@@ -188,27 +258,14 @@ lpfc_mem_free(struct lpfc_hba * phba)
                psli->mbox_active = NULL;
        }
 
-       for (i = 0; i < pool->current_count; i++)
-               pci_pool_free(phba->lpfc_mbuf_pool, pool->elements[i].virt,
-                                                pool->elements[i].phys);
-       kfree(pool->elements);
-
-       pci_pool_destroy(phba->lpfc_hbq_pool);
-       mempool_destroy(phba->nlp_mem_pool);
-       mempool_destroy(phba->mbox_mem_pool);
-
-       pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool);
-       pci_pool_destroy(phba->lpfc_mbuf_pool);
-
-       phba->lpfc_hbq_pool = NULL;
-       phba->nlp_mem_pool = NULL;
-       phba->mbox_mem_pool = NULL;
-       phba->lpfc_scsi_dma_buf_pool = NULL;
-       phba->lpfc_mbuf_pool = NULL;
+       /* Free and destroy all the allocated memory pools */
+       lpfc_mem_free(phba);
 
        /* Free the iocb lookup array */
        kfree(psli->iocbq_lookup);
        psli->iocbq_lookup = NULL;
+
+       return;
 }
 
 /**
@@ -305,7 +362,7 @@ lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma)
  * lpfc_els_hbq_alloc - Allocate an HBQ buffer
  * @phba: HBA to allocate HBQ buffer for
  *
- * Description: Allocates a DMA-mapped HBQ buffer from the lpfc_hbq_pool PCI
+ * Description: Allocates a DMA-mapped HBQ buffer from the lpfc_hrb_pool PCI
  * pool along a non-DMA-mapped container for it.
  *
  * Notes: Not interrupt-safe.  Must be called with no locks held.
@@ -323,7 +380,7 @@ lpfc_els_hbq_alloc(struct lpfc_hba *phba)
        if (!hbqbp)
                return NULL;
 
-       hbqbp->dbuf.virt = pci_pool_alloc(phba->lpfc_hbq_pool, GFP_KERNEL,
+       hbqbp->dbuf.virt = pci_pool_alloc(phba->lpfc_hrb_pool, GFP_KERNEL,
                                          &hbqbp->dbuf.phys);
        if (!hbqbp->dbuf.virt) {
                kfree(hbqbp);
@@ -334,7 +391,7 @@ lpfc_els_hbq_alloc(struct lpfc_hba *phba)
 }
 
 /**
- * lpfc_mem_hbq_free - Frees an HBQ buffer allocated with lpfc_els_hbq_alloc
+ * lpfc_els_hbq_free - Frees an HBQ buffer allocated with lpfc_els_hbq_alloc
  * @phba: HBA buffer was allocated for
  * @hbqbp: HBQ container returned by lpfc_els_hbq_alloc
  *
@@ -348,11 +405,72 @@ lpfc_els_hbq_alloc(struct lpfc_hba *phba)
 void
 lpfc_els_hbq_free(struct lpfc_hba *phba, struct hbq_dmabuf *hbqbp)
 {
-       pci_pool_free(phba->lpfc_hbq_pool, hbqbp->dbuf.virt, hbqbp->dbuf.phys);
+       pci_pool_free(phba->lpfc_hrb_pool, hbqbp->dbuf.virt, hbqbp->dbuf.phys);
        kfree(hbqbp);
        return;
 }
 
+/**
+ * lpfc_sli4_rb_alloc - Allocate an SLI4 Receive buffer
+ * @phba: HBA to allocate a receive buffer for
+ *
+ * Description: Allocates a DMA-mapped receive buffer from the lpfc_hrb_pool PCI
+ * pool along a non-DMA-mapped container for it.
+ *
+ * Notes: Not interrupt-safe.  Must be called with no locks held.
+ *
+ * Returns:
+ *   pointer to HBQ on success
+ *   NULL on failure
+ **/
+struct hbq_dmabuf *
+lpfc_sli4_rb_alloc(struct lpfc_hba *phba)
+{
+       struct hbq_dmabuf *dma_buf;
+
+       dma_buf = kmalloc(sizeof(struct hbq_dmabuf), GFP_KERNEL);
+       if (!dma_buf)
+               return NULL;
+
+       dma_buf->hbuf.virt = pci_pool_alloc(phba->lpfc_hrb_pool, GFP_KERNEL,
+                                           &dma_buf->hbuf.phys);
+       if (!dma_buf->hbuf.virt) {
+               kfree(dma_buf);
+               return NULL;
+       }
+       dma_buf->dbuf.virt = pci_pool_alloc(phba->lpfc_drb_pool, GFP_KERNEL,
+                                           &dma_buf->dbuf.phys);
+       if (!dma_buf->dbuf.virt) {
+               pci_pool_free(phba->lpfc_hrb_pool, dma_buf->hbuf.virt,
+                             dma_buf->hbuf.phys);
+               kfree(dma_buf);
+               return NULL;
+       }
+       dma_buf->size = LPFC_BPL_SIZE;
+       return dma_buf;
+}
+
+/**
+ * lpfc_sli4_rb_free - Frees a receive buffer
+ * @phba: HBA buffer was allocated for
+ * @dmab: DMA Buffer container returned by lpfc_sli4_hbq_alloc
+ *
+ * Description: Frees both the container and the DMA-mapped buffers returned by
+ * lpfc_sli4_rb_alloc.
+ *
+ * Notes: Can be called with or without locks held.
+ *
+ * Returns: None
+ **/
+void
+lpfc_sli4_rb_free(struct lpfc_hba *phba, struct hbq_dmabuf *dmab)
+{
+       pci_pool_free(phba->lpfc_hrb_pool, dmab->hbuf.virt, dmab->hbuf.phys);
+       pci_pool_free(phba->lpfc_drb_pool, dmab->dbuf.virt, dmab->dbuf.phys);
+       kfree(dmab);
+       return;
+}
+
 /**
  * lpfc_in_buf_free - Free a DMA buffer
  * @phba: HBA buffer is associated with
index 08cdc77af41c12f42f34ab2da799f1f678811d7b..09f659f77bb3f2b399850215319eb9121489d181 100644 (file)
@@ -1,7 +1,7 @@
  /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport_fc.h>
 
+#include "lpfc_hw4.h"
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
+#include "lpfc_sli4.h"
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -361,7 +363,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        if (!mbox)
                goto out;
 
-       rc = lpfc_reg_login(phba, vport->vpi, icmd->un.rcvels.remoteID,
+       rc = lpfc_reg_rpi(phba, vport->vpi, icmd->un.rcvels.remoteID,
                            (uint8_t *) sp, mbox, 0);
        if (rc) {
                mempool_free(mbox, phba->mbox_mem_pool);
@@ -495,11 +497,19 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
        else
                lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
+       if ((ndlp->nlp_type & NLP_FABRIC) &&
+               vport->port_type == LPFC_NPIV_PORT) {
+               lpfc_linkdown_port(vport);
+               mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
+               spin_lock_irq(shost->host_lock);
+               ndlp->nlp_flag |= NLP_DELAY_TMO;
+               spin_unlock_irq(shost->host_lock);
 
-       if ((!(ndlp->nlp_type & NLP_FABRIC) &&
-            ((ndlp->nlp_type & NLP_FCP_TARGET) ||
-             !(ndlp->nlp_type & NLP_FCP_INITIATOR))) ||
-           (ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) {
+               ndlp->nlp_last_elscmd = ELS_CMD_FDISC;
+       } else if ((!(ndlp->nlp_type & NLP_FABRIC) &&
+               ((ndlp->nlp_type & NLP_FCP_TARGET) ||
+               !(ndlp->nlp_type & NLP_FCP_INITIATOR))) ||
+               (ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) {
                /* Only try to re-login if this is NOT a Fabric Node */
                mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
                spin_lock_irq(shost->host_lock);
@@ -567,7 +577,7 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
 {
        struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 
-       if (!ndlp->nlp_rpi) {
+       if (!(ndlp->nlp_flag & NLP_RPI_VALID)) {
                ndlp->nlp_flag &= ~NLP_NPR_ADISC;
                return 0;
        }
@@ -857,7 +867,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
 
        lpfc_unreg_rpi(vport, ndlp);
 
-       if (lpfc_reg_login(phba, vport->vpi, irsp->un.elsreq64.remoteID,
+       if (lpfc_reg_rpi(phba, vport->vpi, irsp->un.elsreq64.remoteID,
                           (uint8_t *) sp, mbox, 0) == 0) {
                switch (ndlp->nlp_DID) {
                case NameServer_DID:
@@ -1068,6 +1078,7 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_vport *vport,
        struct lpfc_iocbq *cmdiocb, *rspiocb;
        IOCB_t *irsp;
        ADISC *ap;
+       int rc;
 
        cmdiocb = (struct lpfc_iocbq *) arg;
        rspiocb = cmdiocb->context_un.rsp_iocb;
@@ -1093,6 +1104,15 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_vport *vport,
                return ndlp->nlp_state;
        }
 
+       if (phba->sli_rev == LPFC_SLI_REV4) {
+               rc = lpfc_sli4_resume_rpi(ndlp);
+               if (rc) {
+                       /* Stay in state and retry. */
+                       ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
+                       return ndlp->nlp_state;
+               }
+       }
+
        if (ndlp->nlp_type & NLP_FCP_TARGET) {
                ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
                lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE);
@@ -1100,6 +1120,7 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_vport *vport,
                ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
                lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
        }
+
        return ndlp->nlp_state;
 }
 
@@ -1190,7 +1211,7 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport,
 
        /* cleanup any ndlp on mbox q waiting for reglogin cmpl */
        if ((mb = phba->sli.mbox_active)) {
-               if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
+               if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) &&
                   (ndlp == (struct lpfc_nodelist *) mb->context2)) {
                        lpfc_nlp_put(ndlp);
                        mb->context2 = NULL;
@@ -1200,7 +1221,7 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport,
 
        spin_lock_irq(&phba->hbalock);
        list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
-               if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
+               if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) &&
                   (ndlp == (struct lpfc_nodelist *) mb->context2)) {
                        mp = (struct lpfc_dmabuf *) (mb->context1);
                        if (mp) {
@@ -1251,7 +1272,7 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport,
 {
        struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
        LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
-       MAILBOX_t *mb = &pmb->mb;
+       MAILBOX_t *mb = &pmb->u.mb;
        uint32_t did  = mb->un.varWords[1];
 
        if (mb->mbxStatus) {
@@ -1283,6 +1304,7 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport,
        }
 
        ndlp->nlp_rpi = mb->un.varWords[0];
+       ndlp->nlp_flag |= NLP_RPI_VALID;
 
        /* Only if we are not a fabric nport do we issue PRLI */
        if (!(ndlp->nlp_type & NLP_FABRIC)) {
@@ -1878,11 +1900,12 @@ lpfc_cmpl_reglogin_npr_node(struct lpfc_vport *vport,
                            void *arg, uint32_t evt)
 {
        LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
-       MAILBOX_t    *mb = &pmb->mb;
+       MAILBOX_t    *mb = &pmb->u.mb;
 
-       if (!mb->mbxStatus)
+       if (!mb->mbxStatus) {
                ndlp->nlp_rpi = mb->un.varWords[0];
-       else {
+               ndlp->nlp_flag |= NLP_RPI_VALID;
+       } else {
                if (ndlp->nlp_flag & NLP_NODEV_REMOVE) {
                        lpfc_drop_node(vport, ndlp);
                        return NLP_STE_FREED_NODE;
index 8032c5adb6a9b2400c318912a7aa376df512b096..7991ba1980ae5d6475c4ab9c34578e9e534d2cf3 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
 #include <scsi/scsi_transport_fc.h>
 
 #include "lpfc_version.h"
+#include "lpfc_hw4.h"
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
+#include "lpfc_sli4.h"
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -57,6 +59,8 @@ static char *dif_op_str[] = {
        "SCSI_PROT_READ_CONVERT",
        "SCSI_PROT_WRITE_CONVERT"
 };
+static void
+lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb);
 
 static void
 lpfc_debug_save_data(struct scsi_cmnd *cmnd)
@@ -325,7 +329,7 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)
 
        vports = lpfc_create_vport_work_array(phba);
        if (vports != NULL)
-               for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+               for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
                        shost = lpfc_shost_from_vport(vports[i]);
                        shost_for_each_device(sdev, shost) {
                                new_queue_depth =
@@ -379,7 +383,7 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba)
 
        vports = lpfc_create_vport_work_array(phba);
        if (vports != NULL)
-               for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+               for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
                        shost = lpfc_shost_from_vport(vports[i]);
                        shost_for_each_device(sdev, shost) {
                                if (vports[i]->cfg_lun_queue_depth <=
@@ -427,7 +431,7 @@ lpfc_scsi_dev_block(struct lpfc_hba *phba)
 
        vports = lpfc_create_vport_work_array(phba);
        if (vports != NULL)
-               for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+               for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
                        shost = lpfc_shost_from_vport(vports[i]);
                        shost_for_each_device(sdev, shost) {
                                rport = starget_to_rport(scsi_target(sdev));
@@ -438,22 +442,23 @@ lpfc_scsi_dev_block(struct lpfc_hba *phba)
 }
 
 /**
- * lpfc_new_scsi_buf - Scsi buffer allocator
+ * lpfc_new_scsi_buf_s3 - Scsi buffer allocator for HBA with SLI3 IF spec
  * @vport: The virtual port for which this call being executed.
+ * @num_to_allocate: The requested number of buffers to allocate.
  *
- * This routine allocates a scsi buffer, which contains all the necessary
- * information needed to initiate a SCSI I/O.  The non-DMAable buffer region
- * contains information to build the IOCB.  The DMAable region contains
- * memory for the FCP CMND, FCP RSP, and the initial BPL.  In addition to
- * allocating memory, the FCP CMND and FCP RSP BDEs are setup in the BPL
- * and the BPL BDE is setup in the IOCB.
+ * This routine allocates a scsi buffer for device with SLI-3 interface spec,
+ * the scsi buffer contains all the necessary information needed to initiate
+ * a SCSI I/O. The non-DMAable buffer region contains information to build
+ * the IOCB. The DMAable region contains memory for the FCP CMND, FCP RSP,
+ * and the initial BPL. In addition to allocating memory, the FCP CMND and
+ * FCP RSP BDEs are setup in the BPL and the BPL BDE is setup in the IOCB.
  *
  * Return codes:
- *   NULL - Error
- *   Pointer to lpfc_scsi_buf data structure - Success
+ *   int - number of scsi buffers that were allocated.
+ *   0 = failure, less than num_to_alloc is a partial failure.
  **/
-static struct lpfc_scsi_buf *
-lpfc_new_scsi_buf(struct lpfc_vport *vport)
+static int
+lpfc_new_scsi_buf_s3(struct lpfc_vport *vport, int num_to_alloc)
 {
        struct lpfc_hba *phba = vport->phba;
        struct lpfc_scsi_buf *psb;
@@ -463,107 +468,401 @@ lpfc_new_scsi_buf(struct lpfc_vport *vport)
        dma_addr_t pdma_phys_fcp_rsp;
        dma_addr_t pdma_phys_bpl;
        uint16_t iotag;
+       int bcnt;
 
-       psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL);
-       if (!psb)
-               return NULL;
+       for (bcnt = 0; bcnt < num_to_alloc; bcnt++) {
+               psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL);
+               if (!psb)
+                       break;
+
+               /*
+                * Get memory from the pci pool to map the virt space to pci
+                * bus space for an I/O.  The DMA buffer includes space for the
+                * struct fcp_cmnd, struct fcp_rsp and the number of bde's
+                * necessary to support the sg_tablesize.
+                */
+               psb->data = pci_pool_alloc(phba->lpfc_scsi_dma_buf_pool,
+                                       GFP_KERNEL, &psb->dma_handle);
+               if (!psb->data) {
+                       kfree(psb);
+                       break;
+               }
+
+               /* Initialize virtual ptrs to dma_buf region. */
+               memset(psb->data, 0, phba->cfg_sg_dma_buf_size);
+
+               /* Allocate iotag for psb->cur_iocbq. */
+               iotag = lpfc_sli_next_iotag(phba, &psb->cur_iocbq);
+               if (iotag == 0) {
+                       pci_pool_free(phba->lpfc_scsi_dma_buf_pool,
+                                       psb->data, psb->dma_handle);
+                       kfree(psb);
+                       break;
+               }
+               psb->cur_iocbq.iocb_flag |= LPFC_IO_FCP;
+
+               psb->fcp_cmnd = psb->data;
+               psb->fcp_rsp = psb->data + sizeof(struct fcp_cmnd);
+               psb->fcp_bpl = psb->data + sizeof(struct fcp_cmnd) +
+                       sizeof(struct fcp_rsp);
+
+               /* Initialize local short-hand pointers. */
+               bpl = psb->fcp_bpl;
+               pdma_phys_fcp_cmd = psb->dma_handle;
+               pdma_phys_fcp_rsp = psb->dma_handle + sizeof(struct fcp_cmnd);
+               pdma_phys_bpl = psb->dma_handle + sizeof(struct fcp_cmnd) +
+                       sizeof(struct fcp_rsp);
+
+               /*
+                * The first two bdes are the FCP_CMD and FCP_RSP. The balance
+                * are sg list bdes.  Initialize the first two and leave the
+                * rest for queuecommand.
+                */
+               bpl[0].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_cmd));
+               bpl[0].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_cmd));
+               bpl[0].tus.f.bdeSize = sizeof(struct fcp_cmnd);
+               bpl[0].tus.f.bdeFlags = BUFF_TYPE_BDE_64;
+               bpl[0].tus.w = le32_to_cpu(bpl[0].tus.w);
+
+               /* Setup the physical region for the FCP RSP */
+               bpl[1].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_rsp));
+               bpl[1].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_rsp));
+               bpl[1].tus.f.bdeSize = sizeof(struct fcp_rsp);
+               bpl[1].tus.f.bdeFlags = BUFF_TYPE_BDE_64;
+               bpl[1].tus.w = le32_to_cpu(bpl[1].tus.w);
+
+               /*
+                * Since the IOCB for the FCP I/O is built into this
+                * lpfc_scsi_buf, initialize it with all known data now.
+                */
+               iocb = &psb->cur_iocbq.iocb;
+               iocb->un.fcpi64.bdl.ulpIoTag32 = 0;
+               if ((phba->sli_rev == 3) &&
+                               !(phba->sli3_options & LPFC_SLI3_BG_ENABLED)) {
+                       /* fill in immediate fcp command BDE */
+                       iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BDE_IMMED;
+                       iocb->un.fcpi64.bdl.bdeSize = sizeof(struct fcp_cmnd);
+                       iocb->un.fcpi64.bdl.addrLow = offsetof(IOCB_t,
+                                       unsli3.fcp_ext.icd);
+                       iocb->un.fcpi64.bdl.addrHigh = 0;
+                       iocb->ulpBdeCount = 0;
+                       iocb->ulpLe = 0;
+                       /* fill in responce BDE */
+                       iocb->unsli3.fcp_ext.rbde.tus.f.bdeFlags =
+                                                       BUFF_TYPE_BDE_64;
+                       iocb->unsli3.fcp_ext.rbde.tus.f.bdeSize =
+                               sizeof(struct fcp_rsp);
+                       iocb->unsli3.fcp_ext.rbde.addrLow =
+                               putPaddrLow(pdma_phys_fcp_rsp);
+                       iocb->unsli3.fcp_ext.rbde.addrHigh =
+                               putPaddrHigh(pdma_phys_fcp_rsp);
+               } else {
+                       iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
+                       iocb->un.fcpi64.bdl.bdeSize =
+                                       (2 * sizeof(struct ulp_bde64));
+                       iocb->un.fcpi64.bdl.addrLow =
+                                       putPaddrLow(pdma_phys_bpl);
+                       iocb->un.fcpi64.bdl.addrHigh =
+                                       putPaddrHigh(pdma_phys_bpl);
+                       iocb->ulpBdeCount = 1;
+                       iocb->ulpLe = 1;
+               }
+               iocb->ulpClass = CLASS3;
+               psb->status = IOSTAT_SUCCESS;
+               /* Put it back into the SCSI buffer list */
+               lpfc_release_scsi_buf_s4(phba, psb);
 
-       /*
-        * Get memory from the pci pool to map the virt space to pci bus space
-        * for an I/O.  The DMA buffer includes space for the struct fcp_cmnd,
-        * struct fcp_rsp and the number of bde's necessary to support the
-        * sg_tablesize.
-        */
-       psb->data = pci_pool_alloc(phba->lpfc_scsi_dma_buf_pool, GFP_KERNEL,
-                                                       &psb->dma_handle);
-       if (!psb->data) {
-               kfree(psb);
-               return NULL;
        }
 
-       /* Initialize virtual ptrs to dma_buf region. */
-       memset(psb->data, 0, phba->cfg_sg_dma_buf_size);
+       return bcnt;
+}
 
-       /* Allocate iotag for psb->cur_iocbq. */
-       iotag = lpfc_sli_next_iotag(phba, &psb->cur_iocbq);
-       if (iotag == 0) {
-               pci_pool_free(phba->lpfc_scsi_dma_buf_pool,
-                             psb->data, psb->dma_handle);
-               kfree (psb);
-               return NULL;
+/**
+ * lpfc_sli4_fcp_xri_aborted - Fast-path process of fcp xri abort
+ * @phba: pointer to lpfc hba data structure.
+ * @axri: pointer to the fcp xri abort wcqe structure.
+ *
+ * This routine is invoked by the worker thread to process a SLI4 fast-path
+ * FCP aborted xri.
+ **/
+void
+lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,
+                         struct sli4_wcqe_xri_aborted *axri)
+{
+       uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri);
+       struct lpfc_scsi_buf *psb, *next_psb;
+       unsigned long iflag = 0;
+
+       spin_lock_irqsave(&phba->sli4_hba.abts_scsi_buf_list_lock, iflag);
+       list_for_each_entry_safe(psb, next_psb,
+               &phba->sli4_hba.lpfc_abts_scsi_buf_list, list) {
+               if (psb->cur_iocbq.sli4_xritag == xri) {
+                       list_del(&psb->list);
+                       psb->status = IOSTAT_SUCCESS;
+                       spin_unlock_irqrestore(
+                               &phba->sli4_hba.abts_scsi_buf_list_lock,
+                               iflag);
+                       lpfc_release_scsi_buf_s4(phba, psb);
+                       return;
+               }
+       }
+       spin_unlock_irqrestore(&phba->sli4_hba.abts_scsi_buf_list_lock,
+                               iflag);
+}
+
+/**
+ * lpfc_sli4_repost_scsi_sgl_list - Repsot the Scsi buffers sgl pages as block
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine walks the list of scsi buffers that have been allocated and
+ * repost them to the HBA by using SGL block post. This is needed after a
+ * pci_function_reset/warm_start or start. The lpfc_hba_down_post_s4 routine
+ * is responsible for moving all scsi buffers on the lpfc_abts_scsi_sgl_list
+ * to the lpfc_scsi_buf_list. If the repost fails, reject all scsi buffers.
+ *
+ * Returns: 0 = success, non-zero failure.
+ **/
+int
+lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba)
+{
+       struct lpfc_scsi_buf *psb;
+       int index, status, bcnt = 0, rcnt = 0, rc = 0;
+       LIST_HEAD(sblist);
+
+       for (index = 0; index < phba->sli4_hba.scsi_xri_cnt; index++) {
+               psb = phba->sli4_hba.lpfc_scsi_psb_array[index];
+               if (psb) {
+                       /* Remove from SCSI buffer list */
+                       list_del(&psb->list);
+                       /* Add it to a local SCSI buffer list */
+                       list_add_tail(&psb->list, &sblist);
+                       if (++rcnt == LPFC_NEMBED_MBOX_SGL_CNT) {
+                               bcnt = rcnt;
+                               rcnt = 0;
+                       }
+               } else
+                       /* A hole present in the XRI array, need to skip */
+                       bcnt = rcnt;
+
+               if (index == phba->sli4_hba.scsi_xri_cnt - 1)
+                       /* End of XRI array for SCSI buffer, complete */
+                       bcnt = rcnt;
+
+               /* Continue until collect up to a nembed page worth of sgls */
+               if (bcnt == 0)
+                       continue;
+               /* Now, post the SCSI buffer list sgls as a block */
+               status = lpfc_sli4_post_scsi_sgl_block(phba, &sblist, bcnt);
+               /* Reset SCSI buffer count for next round of posting */
+               bcnt = 0;
+               while (!list_empty(&sblist)) {
+                       list_remove_head(&sblist, psb, struct lpfc_scsi_buf,
+                                        list);
+                       if (status) {
+                               /* Put this back on the abort scsi list */
+                               psb->status = IOSTAT_LOCAL_REJECT;
+                               psb->result = IOERR_ABORT_REQUESTED;
+                               rc++;
+                       } else
+                               psb->status = IOSTAT_SUCCESS;
+                       /* Put it back into the SCSI buffer list */
+                       lpfc_release_scsi_buf_s4(phba, psb);
+               }
        }
-       psb->cur_iocbq.iocb_flag |= LPFC_IO_FCP;
+       return rc;
+}
 
-       psb->fcp_cmnd = psb->data;
-       psb->fcp_rsp = psb->data + sizeof(struct fcp_cmnd);
-       psb->fcp_bpl = psb->data + sizeof(struct fcp_cmnd) +
-                                                       sizeof(struct fcp_rsp);
+/**
+ * lpfc_new_scsi_buf_s4 - Scsi buffer allocator for HBA with SLI4 IF spec
+ * @vport: The virtual port for which this call being executed.
+ * @num_to_allocate: The requested number of buffers to allocate.
+ *
+ * This routine allocates a scsi buffer for device with SLI-4 interface spec,
+ * the scsi buffer contains all the necessary information needed to initiate
+ * a SCSI I/O.
+ *
+ * Return codes:
+ *   int - number of scsi buffers that were allocated.
+ *   0 = failure, less than num_to_alloc is a partial failure.
+ **/
+static int
+lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
+{
+       struct lpfc_hba *phba = vport->phba;
+       struct lpfc_scsi_buf *psb;
+       struct sli4_sge *sgl;
+       IOCB_t *iocb;
+       dma_addr_t pdma_phys_fcp_cmd;
+       dma_addr_t pdma_phys_fcp_rsp;
+       dma_addr_t pdma_phys_bpl, pdma_phys_bpl1;
+       uint16_t iotag, last_xritag = NO_XRI;
+       int status = 0, index;
+       int bcnt;
+       int non_sequential_xri = 0;
+       int rc = 0;
+       LIST_HEAD(sblist);
+
+       for (bcnt = 0; bcnt < num_to_alloc; bcnt++) {
+               psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL);
+               if (!psb)
+                       break;
 
-       /* Initialize local short-hand pointers. */
-       bpl = psb->fcp_bpl;
-       pdma_phys_fcp_cmd = psb->dma_handle;
-       pdma_phys_fcp_rsp = psb->dma_handle + sizeof(struct fcp_cmnd);
-       pdma_phys_bpl = psb->dma_handle + sizeof(struct fcp_cmnd) +
-                       sizeof(struct fcp_rsp);
+               /*
+                * Get memory from the pci pool to map the virt space to pci bus
+                * space for an I/O.  The DMA buffer includes space for the
+                * struct fcp_cmnd, struct fcp_rsp and the number of bde's
+                * necessary to support the sg_tablesize.
+                */
+               psb->data = pci_pool_alloc(phba->lpfc_scsi_dma_buf_pool,
+                                               GFP_KERNEL, &psb->dma_handle);
+               if (!psb->data) {
+                       kfree(psb);
+                       break;
+               }
 
-       /*
-        * The first two bdes are the FCP_CMD and FCP_RSP.  The balance are sg
-        * list bdes.  Initialize the first two and leave the rest for
-        * queuecommand.
-        */
-       bpl[0].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_cmd));
-       bpl[0].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_cmd));
-       bpl[0].tus.f.bdeSize = sizeof(struct fcp_cmnd);
-       bpl[0].tus.f.bdeFlags = BUFF_TYPE_BDE_64;
-       bpl[0].tus.w = le32_to_cpu(bpl[0].tus.w);
-
-       /* Setup the physical region for the FCP RSP */
-       bpl[1].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_rsp));
-       bpl[1].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_rsp));
-       bpl[1].tus.f.bdeSize = sizeof(struct fcp_rsp);
-       bpl[1].tus.f.bdeFlags = BUFF_TYPE_BDE_64;
-       bpl[1].tus.w = le32_to_cpu(bpl[1].tus.w);
+               /* Initialize virtual ptrs to dma_buf region. */
+               memset(psb->data, 0, phba->cfg_sg_dma_buf_size);
 
-       /*
-        * Since the IOCB for the FCP I/O is built into this lpfc_scsi_buf,
-        * initialize it with all known data now.
-        */
-       iocb = &psb->cur_iocbq.iocb;
-       iocb->un.fcpi64.bdl.ulpIoTag32 = 0;
-       if ((phba->sli_rev == 3) &&
-           !(phba->sli3_options & LPFC_SLI3_BG_ENABLED)) {
-               /* fill in immediate fcp command BDE */
-               iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BDE_IMMED;
+               /* Allocate iotag for psb->cur_iocbq. */
+               iotag = lpfc_sli_next_iotag(phba, &psb->cur_iocbq);
+               if (iotag == 0) {
+                       kfree(psb);
+                       break;
+               }
+
+               psb->cur_iocbq.sli4_xritag = lpfc_sli4_next_xritag(phba);
+               if (psb->cur_iocbq.sli4_xritag == NO_XRI) {
+                       pci_pool_free(phba->lpfc_scsi_dma_buf_pool,
+                             psb->data, psb->dma_handle);
+                       kfree(psb);
+                       break;
+               }
+               if (last_xritag != NO_XRI
+                       && psb->cur_iocbq.sli4_xritag != (last_xritag+1)) {
+                       non_sequential_xri = 1;
+               } else
+                       list_add_tail(&psb->list, &sblist);
+               last_xritag = psb->cur_iocbq.sli4_xritag;
+
+               index = phba->sli4_hba.scsi_xri_cnt++;
+               psb->cur_iocbq.iocb_flag |= LPFC_IO_FCP;
+
+               psb->fcp_bpl = psb->data;
+               psb->fcp_cmnd = (psb->data + phba->cfg_sg_dma_buf_size)
+                       - (sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp));
+               psb->fcp_rsp = (struct fcp_rsp *)((uint8_t *)psb->fcp_cmnd +
+                                       sizeof(struct fcp_cmnd));
+
+               /* Initialize local short-hand pointers. */
+               sgl = (struct sli4_sge *)psb->fcp_bpl;
+               pdma_phys_bpl = psb->dma_handle;
+               pdma_phys_fcp_cmd =
+                       (psb->dma_handle + phba->cfg_sg_dma_buf_size)
+                        - (sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp));
+               pdma_phys_fcp_rsp = pdma_phys_fcp_cmd + sizeof(struct fcp_cmnd);
+
+               /*
+                * The first two bdes are the FCP_CMD and FCP_RSP.  The balance
+                * are sg list bdes.  Initialize the first two and leave the
+                * rest for queuecommand.
+                */
+               sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_fcp_cmd));
+               sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_fcp_cmd));
+               bf_set(lpfc_sli4_sge_len, sgl, sizeof(struct fcp_cmnd));
+               bf_set(lpfc_sli4_sge_last, sgl, 0);
+               sgl->word2 = cpu_to_le32(sgl->word2);
+               sgl->word3 = cpu_to_le32(sgl->word3);
+               sgl++;
+
+               /* Setup the physical region for the FCP RSP */
+               sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_fcp_rsp));
+               sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_fcp_rsp));
+               bf_set(lpfc_sli4_sge_len, sgl, sizeof(struct fcp_rsp));
+               bf_set(lpfc_sli4_sge_last, sgl, 1);
+               sgl->word2 = cpu_to_le32(sgl->word2);
+               sgl->word3 = cpu_to_le32(sgl->word3);
+
+               /*
+                * Since the IOCB for the FCP I/O is built into this
+                * lpfc_scsi_buf, initialize it with all known data now.
+                */
+               iocb = &psb->cur_iocbq.iocb;
+               iocb->un.fcpi64.bdl.ulpIoTag32 = 0;
+               iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BDE_64;
+               /* setting the BLP size to 2 * sizeof BDE may not be correct.
+                * We are setting the bpl to point to out sgl. An sgl's
+                * entries are 16 bytes, a bpl entries are 12 bytes.
+                */
                iocb->un.fcpi64.bdl.bdeSize = sizeof(struct fcp_cmnd);
-               iocb->un.fcpi64.bdl.addrLow = offsetof(IOCB_t,
-                                                      unsli3.fcp_ext.icd);
-               iocb->un.fcpi64.bdl.addrHigh = 0;
-               iocb->ulpBdeCount = 0;
-               iocb->ulpLe = 0;
-               /* fill in responce BDE */
-               iocb->unsli3.fcp_ext.rbde.tus.f.bdeFlags = BUFF_TYPE_BDE_64;
-               iocb->unsli3.fcp_ext.rbde.tus.f.bdeSize =
-                                               sizeof(struct fcp_rsp);
-               iocb->unsli3.fcp_ext.rbde.addrLow =
-                                               putPaddrLow(pdma_phys_fcp_rsp);
-               iocb->unsli3.fcp_ext.rbde.addrHigh =
-                                               putPaddrHigh(pdma_phys_fcp_rsp);
-       } else {
-               iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
-               iocb->un.fcpi64.bdl.bdeSize = (2 * sizeof(struct ulp_bde64));
-               iocb->un.fcpi64.bdl.addrLow = putPaddrLow(pdma_phys_bpl);
-               iocb->un.fcpi64.bdl.addrHigh = putPaddrHigh(pdma_phys_bpl);
+               iocb->un.fcpi64.bdl.addrLow = putPaddrLow(pdma_phys_fcp_cmd);
+               iocb->un.fcpi64.bdl.addrHigh = putPaddrHigh(pdma_phys_fcp_cmd);
                iocb->ulpBdeCount = 1;
                iocb->ulpLe = 1;
+               iocb->ulpClass = CLASS3;
+               if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE)
+                       pdma_phys_bpl1 = pdma_phys_bpl + SGL_PAGE_SIZE;
+               else
+                       pdma_phys_bpl1 = 0;
+               psb->dma_phys_bpl = pdma_phys_bpl;
+               phba->sli4_hba.lpfc_scsi_psb_array[index] = psb;
+               if (non_sequential_xri) {
+                       status = lpfc_sli4_post_sgl(phba, pdma_phys_bpl,
+                                               pdma_phys_bpl1,
+                                               psb->cur_iocbq.sli4_xritag);
+                       if (status) {
+                               /* Put this back on the abort scsi list */
+                               psb->status = IOSTAT_LOCAL_REJECT;
+                               psb->result = IOERR_ABORT_REQUESTED;
+                               rc++;
+                       } else
+                               psb->status = IOSTAT_SUCCESS;
+                       /* Put it back into the SCSI buffer list */
+                       lpfc_release_scsi_buf_s4(phba, psb);
+                       break;
+               }
+       }
+       if (bcnt) {
+               status = lpfc_sli4_post_scsi_sgl_block(phba, &sblist, bcnt);
+               /* Reset SCSI buffer count for next round of posting */
+               while (!list_empty(&sblist)) {
+                       list_remove_head(&sblist, psb, struct lpfc_scsi_buf,
+                                list);
+                       if (status) {
+                               /* Put this back on the abort scsi list */
+                               psb->status = IOSTAT_LOCAL_REJECT;
+                               psb->result = IOERR_ABORT_REQUESTED;
+                               rc++;
+                       } else
+                               psb->status = IOSTAT_SUCCESS;
+                       /* Put it back into the SCSI buffer list */
+                       lpfc_release_scsi_buf_s4(phba, psb);
+               }
        }
-       iocb->ulpClass = CLASS3;
 
-       return psb;
+       return bcnt + non_sequential_xri - rc;
 }
 
 /**
- * lpfc_get_scsi_buf - Get a scsi buffer from lpfc_scsi_buf_list list of Hba
- * @phba: The Hba for which this call is being executed.
+ * lpfc_new_scsi_buf - Wrapper funciton for scsi buffer allocator
+ * @vport: The virtual port for which this call being executed.
+ * @num_to_allocate: The requested number of buffers to allocate.
+ *
+ * This routine wraps the actual SCSI buffer allocator function pointer from
+ * the lpfc_hba struct.
+ *
+ * Return codes:
+ *   int - number of scsi buffers that were allocated.
+ *   0 = failure, less than num_to_alloc is a partial failure.
+ **/
+static inline int
+lpfc_new_scsi_buf(struct lpfc_vport *vport, int num_to_alloc)
+{
+       return vport->phba->lpfc_new_scsi_buf(vport, num_to_alloc);
+}
+
+/**
+ * lpfc_get_scsi_buf - Get a scsi buffer from lpfc_scsi_buf_list of the HBA
+ * @phba: The HBA for which this call is being executed.
  *
  * This routine removes a scsi buffer from head of @phba lpfc_scsi_buf_list list
  * and returns to caller.
@@ -591,7 +890,7 @@ lpfc_get_scsi_buf(struct lpfc_hba * phba)
 }
 
 /**
- * lpfc_release_scsi_buf - Return a scsi buffer back to hba's lpfc_scsi_buf_list
+ * lpfc_release_scsi_buf - Return a scsi buffer back to hba scsi buf list
  * @phba: The Hba for which this call is being executed.
  * @psb: The scsi buffer which is being released.
  *
@@ -599,7 +898,7 @@ lpfc_get_scsi_buf(struct lpfc_hba * phba)
  * lpfc_scsi_buf_list list.
  **/
 static void
-lpfc_release_scsi_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
+lpfc_release_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
 {
        unsigned long iflag = 0;
 
@@ -610,21 +909,69 @@ lpfc_release_scsi_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
 }
 
 /**
- * lpfc_scsi_prep_dma_buf - Routine to do DMA mapping for scsi buffer
+ * lpfc_release_scsi_buf_s4: Return a scsi buffer back to hba scsi buf list.
+ * @phba: The Hba for which this call is being executed.
+ * @psb: The scsi buffer which is being released.
+ *
+ * This routine releases @psb scsi buffer by adding it to tail of @phba
+ * lpfc_scsi_buf_list list. For SLI4 XRI's are tied to the scsi buffer
+ * and cannot be reused for at least RA_TOV amount of time if it was
+ * aborted.
+ **/
+static void
+lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
+{
+       unsigned long iflag = 0;
+
+       if (psb->status == IOSTAT_LOCAL_REJECT
+               && psb->result == IOERR_ABORT_REQUESTED) {
+               spin_lock_irqsave(&phba->sli4_hba.abts_scsi_buf_list_lock,
+                                       iflag);
+               psb->pCmd = NULL;
+               list_add_tail(&psb->list,
+                       &phba->sli4_hba.lpfc_abts_scsi_buf_list);
+               spin_unlock_irqrestore(&phba->sli4_hba.abts_scsi_buf_list_lock,
+                                       iflag);
+       } else {
+
+               spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
+               psb->pCmd = NULL;
+               list_add_tail(&psb->list, &phba->lpfc_scsi_buf_list);
+               spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag);
+       }
+}
+
+/**
+ * lpfc_release_scsi_buf: Return a scsi buffer back to hba scsi buf list.
+ * @phba: The Hba for which this call is being executed.
+ * @psb: The scsi buffer which is being released.
+ *
+ * This routine releases @psb scsi buffer by adding it to tail of @phba
+ * lpfc_scsi_buf_list list.
+ **/
+static void
+lpfc_release_scsi_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
+{
+
+       phba->lpfc_release_scsi_buf(phba, psb);
+}
+
+/**
+ * lpfc_scsi_prep_dma_buf_s3 - DMA mapping for scsi buffer to SLI3 IF spec
  * @phba: The Hba for which this call is being executed.
  * @lpfc_cmd: The scsi buffer which is going to be mapped.
  *
  * This routine does the pci dma mapping for scatter-gather list of scsi cmnd
- * field of @lpfc_cmd. This routine scans through sg elements and format the
- * bdea. This routine also initializes all IOCB fields which are dependent on
- * scsi command request buffer.
+ * field of @lpfc_cmd for device with SLI-3 interface spec. This routine scans
+ * through sg elements and format the bdea. This routine also initializes all
+ * IOCB fields which are dependent on scsi command request buffer.
  *
  * Return codes:
  *   1 - Error
  *   0 - Success
  **/
 static int
-lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
+lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
 {
        struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd;
        struct scatterlist *sgel = NULL;
@@ -827,8 +1174,8 @@ lpfc_cmd_blksize(struct scsi_cmnd *sc)
  * @reftag:         out: ref tag (reference tag)
  *
  * Description:
- *   Extract DIF paramters from the command if possible.  Otherwise,
- *   use default paratmers.
+ *   Extract DIF parameters from the command if possible.  Otherwise,
+ *   use default parameters.
  *
  **/
 static inline void
@@ -1411,6 +1758,133 @@ out:
        return ret;
 }
 
+/**
+ * lpfc_scsi_prep_dma_buf_s4 - DMA mapping for scsi buffer to SLI4 IF spec
+ * @phba: The Hba for which this call is being executed.
+ * @lpfc_cmd: The scsi buffer which is going to be mapped.
+ *
+ * This routine does the pci dma mapping for scatter-gather list of scsi cmnd
+ * field of @lpfc_cmd for device with SLI-4 interface spec.
+ *
+ * Return codes:
+ *     1 - Error
+ *     0 - Success
+ **/
+static int
+lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
+{
+       struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd;
+       struct scatterlist *sgel = NULL;
+       struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd;
+       struct sli4_sge *sgl = (struct sli4_sge *)lpfc_cmd->fcp_bpl;
+       IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb;
+       dma_addr_t physaddr;
+       uint32_t num_bde = 0;
+       uint32_t dma_len;
+       uint32_t dma_offset = 0;
+       int nseg;
+
+       /*
+        * There are three possibilities here - use scatter-gather segment, use
+        * the single mapping, or neither.  Start the lpfc command prep by
+        * bumping the bpl beyond the fcp_cmnd and fcp_rsp regions to the first
+        * data bde entry.
+        */
+       if (scsi_sg_count(scsi_cmnd)) {
+               /*
+                * The driver stores the segment count returned from pci_map_sg
+                * because this a count of dma-mappings used to map the use_sg
+                * pages.  They are not guaranteed to be the same for those
+                * architectures that implement an IOMMU.
+                */
+
+               nseg = scsi_dma_map(scsi_cmnd);
+               if (unlikely(!nseg))
+                       return 1;
+               sgl += 1;
+               /* clear the last flag in the fcp_rsp map entry */
+               sgl->word2 = le32_to_cpu(sgl->word2);
+               bf_set(lpfc_sli4_sge_last, sgl, 0);
+               sgl->word2 = cpu_to_le32(sgl->word2);
+               sgl += 1;
+
+               lpfc_cmd->seg_cnt = nseg;
+               if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) {
+                       printk(KERN_ERR "%s: Too many sg segments from "
+                              "dma_map_sg.  Config %d, seg_cnt %d\n",
+                              __func__, phba->cfg_sg_seg_cnt,
+                              lpfc_cmd->seg_cnt);
+                       scsi_dma_unmap(scsi_cmnd);
+                       return 1;
+               }
+
+               /*
+                * The driver established a maximum scatter-gather segment count
+                * during probe that limits the number of sg elements in any
+                * single scsi command.  Just run through the seg_cnt and format
+                * the sge's.
+                * When using SLI-3 the driver will try to fit all the BDEs into
+                * the IOCB. If it can't then the BDEs get added to a BPL as it
+                * does for SLI-2 mode.
+                */
+               scsi_for_each_sg(scsi_cmnd, sgel, nseg, num_bde) {
+                       physaddr = sg_dma_address(sgel);
+                       dma_len = sg_dma_len(sgel);
+                       bf_set(lpfc_sli4_sge_len, sgl, sg_dma_len(sgel));
+                       sgl->addr_lo = cpu_to_le32(putPaddrLow(physaddr));
+                       sgl->addr_hi = cpu_to_le32(putPaddrHigh(physaddr));
+                       if ((num_bde + 1) == nseg)
+                               bf_set(lpfc_sli4_sge_last, sgl, 1);
+                       else
+                               bf_set(lpfc_sli4_sge_last, sgl, 0);
+                       bf_set(lpfc_sli4_sge_offset, sgl, dma_offset);
+                       sgl->word2 = cpu_to_le32(sgl->word2);
+                       sgl->word3 = cpu_to_le32(sgl->word3);
+                       dma_offset += dma_len;
+                       sgl++;
+               }
+       } else {
+               sgl += 1;
+               /* clear the last flag in the fcp_rsp map entry */
+               sgl->word2 = le32_to_cpu(sgl->word2);
+               bf_set(lpfc_sli4_sge_last, sgl, 1);
+               sgl->word2 = cpu_to_le32(sgl->word2);
+       }
+
+       /*
+        * Finish initializing those IOCB fields that are dependent on the
+        * scsi_cmnd request_buffer.  Note that for SLI-2 the bdeSize is
+        * explicitly reinitialized.
+        * all iocb memory resources are reused.
+        */
+       fcp_cmnd->fcpDl = cpu_to_be32(scsi_bufflen(scsi_cmnd));
+
+       /*
+        * Due to difference in data length between DIF/non-DIF paths,
+        * we need to set word 4 of IOCB here
+        */
+       iocb_cmd->un.fcpi.fcpi_parm = scsi_bufflen(scsi_cmnd);
+       return 0;
+}
+
+/**
+ * lpfc_scsi_prep_dma_buf - Wrapper function for DMA mapping of scsi buffer
+ * @phba: The Hba for which this call is being executed.
+ * @lpfc_cmd: The scsi buffer which is going to be mapped.
+ *
+ * This routine wraps the actual DMA mapping function pointer from the
+ * lpfc_hba struct.
+ *
+ * Return codes:
+ *     1 - Error
+ *     0 - Success
+ **/
+static inline int
+lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
+{
+       return phba->lpfc_scsi_prep_dma_buf(phba, lpfc_cmd);
+}
+
 /**
  * lpfc_send_scsi_error_event - Posts an event when there is SCSI error
  * @phba: Pointer to hba context object.
@@ -1504,15 +1978,15 @@ lpfc_send_scsi_error_event(struct lpfc_hba *phba, struct lpfc_vport *vport,
 }
 
 /**
- * lpfc_scsi_unprep_dma_buf - Routine to un-map DMA mapping of scatter gather
- * @phba: The Hba for which this call is being executed.
+ * lpfc_scsi_unprep_dma_buf_s3 - Un-map DMA mapping of SG-list for SLI3 dev
+ * @phba: The HBA for which this call is being executed.
  * @psb: The scsi buffer which is going to be un-mapped.
  *
  * This routine does DMA un-mapping of scatter gather list of scsi command
- * field of @lpfc_cmd.
+ * field of @lpfc_cmd for device with SLI-3 interface spec.
  **/
 static void
-lpfc_scsi_unprep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb)
+lpfc_scsi_unprep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
 {
        /*
         * There are only two special cases to consider.  (1) the scsi command
@@ -1528,6 +2002,36 @@ lpfc_scsi_unprep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb)
                                psb->pCmd->sc_data_direction);
 }
 
+/**
+ * lpfc_scsi_unprep_dma_buf_s4 - Un-map DMA mapping of SG-list for SLI4 dev
+ * @phba: The Hba for which this call is being executed.
+ * @psb: The scsi buffer which is going to be un-mapped.
+ *
+ * This routine does DMA un-mapping of scatter gather list of scsi command
+ * field of @lpfc_cmd for device with SLI-4 interface spec. If we have to
+ * remove the sgl for this scsi buffer then we will do it here. For now
+ * we should be able to just call the sli3 unprep routine.
+ **/
+static void
+lpfc_scsi_unprep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
+{
+       lpfc_scsi_unprep_dma_buf_s3(phba, psb);
+}
+
+/**
+ * lpfc_scsi_unprep_dma_buf - Wrapper function for unmap DMA mapping of SG-list
+ * @phba: The Hba for which this call is being executed.
+ * @psb: The scsi buffer which is going to be un-mapped.
+ *
+ * This routine does DMA un-mapping of scatter gather list of scsi command
+ * field of @lpfc_cmd for device with SLI-4 interface spec.
+ **/
+static void
+lpfc_scsi_unprep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
+{
+       phba->lpfc_scsi_unprep_dma_buf(phba, psb);
+}
+
 /**
  * lpfc_handler_fcp_err - FCP response handler
  * @vport: The virtual port for which this call is being executed.
@@ -1676,7 +2180,7 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
  * lpfc_scsi_cmd_iocb_cmpl - Scsi cmnd IOCB completion routine
  * @phba: The Hba for which this call is being executed.
  * @pIocbIn: The command IOCBQ for the scsi cmnd.
- * @pIocbOut: The response IOCBQ for the scsi cmnd .
+ * @pIocbOut: The response IOCBQ for the scsi cmnd.
  *
  * This routine assigns scsi command result by looking into response IOCB
  * status field appropriately. This routine handles QUEUE FULL condition as
@@ -1957,16 +2461,16 @@ lpfc_fcpcmd_to_iocb(uint8_t *data, struct fcp_cmnd *fcp_cmnd)
 }
 
 /**
- * lpfc_scsi_prep_cmnd -  Routine to convert scsi cmnd to FCP information unit
+ * lpfc_scsi_prep_cmnd_s3 - Convert scsi cmnd to FCP infor unit for SLI3 dev
  * @vport: The virtual port for which this call is being executed.
  * @lpfc_cmd: The scsi command which needs to send.
  * @pnode: Pointer to lpfc_nodelist.
  *
  * This routine initializes fcp_cmnd and iocb data structure from scsi command
- * to transfer.
+ * to transfer for device with SLI3 interface spec.
  **/
 static void
-lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
+lpfc_scsi_prep_cmnd_s3(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
                    struct lpfc_nodelist *pnode)
 {
        struct lpfc_hba *phba = vport->phba;
@@ -2013,8 +2517,11 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
        if (scsi_sg_count(scsi_cmnd)) {
                if (datadir == DMA_TO_DEVICE) {
                        iocb_cmd->ulpCommand = CMD_FCP_IWRITE64_CR;
-                       iocb_cmd->un.fcpi.fcpi_parm = 0;
-                       iocb_cmd->ulpPU = 0;
+                       if (phba->sli_rev < LPFC_SLI_REV4) {
+                               iocb_cmd->un.fcpi.fcpi_parm = 0;
+                               iocb_cmd->ulpPU = 0;
+                       } else
+                               iocb_cmd->ulpPU = PARM_READ_CHECK;
                        fcp_cmnd->fcpCntl3 = WRITE_DATA;
                        phba->fc4OutputRequests++;
                } else {
@@ -2051,20 +2558,60 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
 }
 
 /**
- * lpfc_scsi_prep_task_mgmt_cmnd - Convert scsi TM cmnd to FCP information unit
+ * lpfc_scsi_prep_cmnd_s4 - Convert scsi cmnd to FCP infor unit for SLI4 dev
+ * @vport: The virtual port for which this call is being executed.
+ * @lpfc_cmd: The scsi command which needs to send.
+ * @pnode: Pointer to lpfc_nodelist.
+ *
+ * This routine initializes fcp_cmnd and iocb data structure from scsi command
+ * to transfer for device with SLI4 interface spec.
+ **/
+static void
+lpfc_scsi_prep_cmnd_s4(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
+                      struct lpfc_nodelist *pnode)
+{
+       /*
+        * The prep cmnd routines do not touch the sgl or its
+        * entries. We may not have to do anything different.
+        * I will leave this function in place until we can
+        * run some IO through the driver and determine if changes
+        * are needed.
+        */
+       return lpfc_scsi_prep_cmnd_s3(vport, lpfc_cmd, pnode);
+}
+
+/**
+ * lpfc_scsi_prep_cmnd - Wrapper func for convert scsi cmnd to FCP info unit
+ * @vport: The virtual port for which this call is being executed.
+ * @lpfc_cmd: The scsi command which needs to send.
+ * @pnode: Pointer to lpfc_nodelist.
+ *
+ * This routine wraps the actual convert SCSI cmnd function pointer from
+ * the lpfc_hba struct.
+ **/
+static inline void
+lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
+                   struct lpfc_nodelist *pnode)
+{
+       vport->phba->lpfc_scsi_prep_cmnd(vport, lpfc_cmd, pnode);
+}
+
+/**
+ * lpfc_scsi_prep_task_mgmt_cmnd_s3 - Convert SLI3 scsi TM cmd to FCP info unit
  * @vport: The virtual port for which this call is being executed.
  * @lpfc_cmd: Pointer to lpfc_scsi_buf data structure.
  * @lun: Logical unit number.
  * @task_mgmt_cmd: SCSI task management command.
  *
- * This routine creates FCP information unit corresponding to @task_mgmt_cmd.
+ * This routine creates FCP information unit corresponding to @task_mgmt_cmd
+ * for device with SLI-3 interface spec.
  *
  * Return codes:
  *   0 - Error
  *   1 - Success
  **/
 static int
-lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport,
+lpfc_scsi_prep_task_mgmt_cmd_s3(struct lpfc_vport *vport,
                             struct lpfc_scsi_buf *lpfc_cmd,
                             unsigned int lun,
                             uint8_t task_mgmt_cmd)
@@ -2113,6 +2660,107 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport,
        return 1;
 }
 
+/**
+ * lpfc_scsi_prep_task_mgmt_cmnd_s4 - Convert SLI4 scsi TM cmd to FCP info unit
+ * @vport: The virtual port for which this call is being executed.
+ * @lpfc_cmd: Pointer to lpfc_scsi_buf data structure.
+ * @lun: Logical unit number.
+ * @task_mgmt_cmd: SCSI task management command.
+ *
+ * This routine creates FCP information unit corresponding to @task_mgmt_cmd
+ * for device with SLI-4 interface spec.
+ *
+ * Return codes:
+ *     0 - Error
+ *     1 - Success
+ **/
+static int
+lpfc_scsi_prep_task_mgmt_cmd_s4(struct lpfc_vport *vport,
+                               struct lpfc_scsi_buf *lpfc_cmd,
+                               unsigned int lun,
+                               uint8_t task_mgmt_cmd)
+{
+       /*
+        * The prep cmnd routines do not touch the sgl or its
+        * entries. We may not have to do anything different.
+        * I will leave this function in place until we can
+        * run some IO through the driver and determine if changes
+        * are needed.
+        */
+       return lpfc_scsi_prep_task_mgmt_cmd_s3(vport, lpfc_cmd, lun,
+                                               task_mgmt_cmd);
+}
+
+/**
+ * lpfc_scsi_prep_task_mgmt_cmnd - Wrapper func convert scsi TM cmd to FCP info
+ * @vport: The virtual port for which this call is being executed.
+ * @lpfc_cmd: Pointer to lpfc_scsi_buf data structure.
+ * @lun: Logical unit number.
+ * @task_mgmt_cmd: SCSI task management command.
+ *
+ * This routine wraps the actual convert SCSI TM to FCP information unit
+ * function pointer from the lpfc_hba struct.
+ *
+ * Return codes:
+ *     0 - Error
+ *     1 - Success
+ **/
+static inline int
+lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport,
+                            struct lpfc_scsi_buf *lpfc_cmd,
+                            unsigned int lun,
+                            uint8_t task_mgmt_cmd)
+{
+       struct lpfc_hba *phba = vport->phba;
+
+       return phba->lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun,
+                                                 task_mgmt_cmd);
+}
+
+/**
+ * lpfc_scsi_api_table_setup - Set up scsi api fucntion jump table
+ * @phba: The hba struct for which this call is being executed.
+ * @dev_grp: The HBA PCI-Device group number.
+ *
+ * This routine sets up the SCSI interface API function jump table in @phba
+ * struct.
+ * Returns: 0 - success, -ENODEV - failure.
+ **/
+int
+lpfc_scsi_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
+{
+
+       switch (dev_grp) {
+       case LPFC_PCI_DEV_LP:
+               phba->lpfc_new_scsi_buf = lpfc_new_scsi_buf_s3;
+               phba->lpfc_scsi_prep_dma_buf = lpfc_scsi_prep_dma_buf_s3;
+               phba->lpfc_scsi_prep_cmnd = lpfc_scsi_prep_cmnd_s3;
+               phba->lpfc_scsi_unprep_dma_buf = lpfc_scsi_unprep_dma_buf_s3;
+               phba->lpfc_scsi_prep_task_mgmt_cmd =
+                                       lpfc_scsi_prep_task_mgmt_cmd_s3;
+               phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s3;
+               break;
+       case LPFC_PCI_DEV_OC:
+               phba->lpfc_new_scsi_buf = lpfc_new_scsi_buf_s4;
+               phba->lpfc_scsi_prep_dma_buf = lpfc_scsi_prep_dma_buf_s4;
+               phba->lpfc_scsi_prep_cmnd = lpfc_scsi_prep_cmnd_s4;
+               phba->lpfc_scsi_unprep_dma_buf = lpfc_scsi_unprep_dma_buf_s4;
+               phba->lpfc_scsi_prep_task_mgmt_cmd =
+                                       lpfc_scsi_prep_task_mgmt_cmd_s4;
+               phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s4;
+               break;
+       default:
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1418 Invalid HBA PCI-device group: 0x%x\n",
+                               dev_grp);
+               return -ENODEV;
+               break;
+       }
+       phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf;
+       phba->lpfc_rampdown_queue_depth = lpfc_rampdown_queue_depth;
+       return 0;
+}
+
 /**
  * lpfc_taskmgmt_def_cmpl - IOCB completion routine for task management command
  * @phba: The Hba for which this call is being executed.
@@ -2178,9 +2826,8 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_vport *vport,
        lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
                         "0702 Issue Target Reset to TGT %d Data: x%x x%x\n",
                         tgt_id, rdata->pnode->nlp_rpi, rdata->pnode->nlp_flag);
-       status = lpfc_sli_issue_iocb_wait(phba,
-                                      &phba->sli.ring[phba->sli.fcp_ring],
-                                      iocbq, iocbqrsp, lpfc_cmd->timeout);
+       status = lpfc_sli_issue_iocb_wait(phba, LPFC_FCP_RING,
+                                         iocbq, iocbqrsp, lpfc_cmd->timeout);
        if (status != IOCB_SUCCESS) {
                if (status == IOCB_TIMEDOUT) {
                        iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl;
@@ -2305,7 +2952,6 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
        struct Scsi_Host  *shost = cmnd->device->host;
        struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
        struct lpfc_hba   *phba = vport->phba;
-       struct lpfc_sli   *psli = &phba->sli;
        struct lpfc_rport_data *rdata = cmnd->device->hostdata;
        struct lpfc_nodelist *ndlp = rdata->pnode;
        struct lpfc_scsi_buf *lpfc_cmd;
@@ -2427,7 +3073,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
        lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp);
 
        atomic_inc(&ndlp->cmd_pending);
-       err = lpfc_sli_issue_iocb(phba, &phba->sli.ring[psli->fcp_ring],
+       err = lpfc_sli_issue_iocb(phba, LPFC_FCP_RING,
                                  &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB);
        if (err) {
                atomic_dec(&ndlp->cmd_pending);
@@ -2490,7 +3136,6 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
        struct Scsi_Host  *shost = cmnd->device->host;
        struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
        struct lpfc_hba   *phba = vport->phba;
-       struct lpfc_sli_ring *pring = &phba->sli.ring[phba->sli.fcp_ring];
        struct lpfc_iocbq *iocb;
        struct lpfc_iocbq *abtsiocb;
        struct lpfc_scsi_buf *lpfc_cmd;
@@ -2531,7 +3176,10 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
        icmd = &abtsiocb->iocb;
        icmd->un.acxri.abortType = ABORT_TYPE_ABTS;
        icmd->un.acxri.abortContextTag = cmd->ulpContext;
-       icmd->un.acxri.abortIoTag = cmd->ulpIoTag;
+       if (phba->sli_rev == LPFC_SLI_REV4)
+               icmd->un.acxri.abortIoTag = iocb->sli4_xritag;
+       else
+               icmd->un.acxri.abortIoTag = cmd->ulpIoTag;
 
        icmd->ulpLe = 1;
        icmd->ulpClass = cmd->ulpClass;
@@ -2542,7 +3190,8 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
 
        abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl;
        abtsiocb->vport = vport;
-       if (lpfc_sli_issue_iocb(phba, pring, abtsiocb, 0) == IOCB_ERROR) {
+       if (lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, abtsiocb, 0) ==
+           IOCB_ERROR) {
                lpfc_sli_release_iocbq(phba, abtsiocb);
                ret = FAILED;
                goto out;
@@ -2668,8 +3317,7 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
                         "0703 Issue target reset to TGT %d LUN %d "
                         "rpi x%x nlp_flag x%x\n", cmnd->device->id,
                         cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag);
-       status = lpfc_sli_issue_iocb_wait(phba,
-                                         &phba->sli.ring[phba->sli.fcp_ring],
+       status = lpfc_sli_issue_iocb_wait(phba, LPFC_FCP_RING,
                                          iocbq, iocbqrsp, lpfc_cmd->timeout);
        if (status == IOCB_TIMEDOUT) {
                iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl;
@@ -2825,11 +3473,10 @@ lpfc_slave_alloc(struct scsi_device *sdev)
 {
        struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata;
        struct lpfc_hba   *phba = vport->phba;
-       struct lpfc_scsi_buf *scsi_buf = NULL;
        struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
-       uint32_t total = 0, i;
+       uint32_t total = 0;
        uint32_t num_to_alloc = 0;
-       unsigned long flags;
+       int num_allocated = 0;
 
        if (!rport || fc_remote_port_chkready(rport))
                return -ENXIO;
@@ -2863,20 +3510,13 @@ lpfc_slave_alloc(struct scsi_device *sdev)
                                 (phba->cfg_hba_queue_depth - total));
                num_to_alloc = phba->cfg_hba_queue_depth - total;
        }
-
-       for (i = 0; i < num_to_alloc; i++) {
-               scsi_buf = lpfc_new_scsi_buf(vport);
-               if (!scsi_buf) {
-                       lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
-                                        "0706 Failed to allocate "
-                                        "command buffer\n");
-                       break;
-               }
-
-               spin_lock_irqsave(&phba->scsi_buf_list_lock, flags);
-               phba->total_scsi_bufs++;
-               list_add_tail(&scsi_buf->list, &phba->lpfc_scsi_buf_list);
-               spin_unlock_irqrestore(&phba->scsi_buf_list_lock, flags);
+       num_allocated = lpfc_new_scsi_buf(vport, num_to_alloc);
+       if (num_to_alloc != num_allocated) {
+                       lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
+                                "0708 Allocation request of %d "
+                                "command buffers did not succeed.  "
+                                "Allocated %d buffers.\n",
+                                num_to_alloc, num_allocated);
        }
        return 0;
 }
index c7c440d5fa29668010bc53df87e0c2901328bdb7..65dfc8bd5b49ae385e6d15c51909c245aed71da0 100644 (file)
@@ -140,6 +140,8 @@ struct lpfc_scsi_buf {
        struct fcp_rsp *fcp_rsp;
        struct ulp_bde64 *fcp_bpl;
 
+       dma_addr_t dma_phys_bpl;
+
        /* cur_iocbq has phys of the dma-able buffer.
         * Iotag is in here
         */
index eb5c75c45ba4aa1e4414fb880101e77edd60a511..ff04daf18f48d1ba4df538638b746c2d87a1236d 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport_fc.h>
+#include <scsi/fc/fc_fs.h>
 
+#include "lpfc_hw4.h"
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
+#include "lpfc_sli4.h"
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
 #include "lpfc_logmsg.h"
 #include "lpfc_compat.h"
 #include "lpfc_debugfs.h"
-
-/*
- * Define macro to log: Mailbox command x%x cannot issue Data
- * This allows multiple uses of lpfc_msgBlk0311
- * w/o perturbing log msg utility.
- */
-#define LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag) \
-                       lpfc_printf_log(phba, \
-                               KERN_INFO, \
-                               LOG_MBOX | LOG_SLI, \
-                               "(%d):0311 Mailbox command x%x cannot " \
-                               "issue Data: x%x x%x x%x\n", \
-                               pmbox->vport ? pmbox->vport->vpi : 0, \
-                               pmbox->mb.mbxCommand,           \
-                               phba->pport->port_state,        \
-                               psli->sli_flag, \
-                               flag)
-
+#include "lpfc_vport.h"
 
 /* There are only four IOCB completion types. */
 typedef enum _lpfc_iocb_type {
@@ -67,6 +53,350 @@ typedef enum _lpfc_iocb_type {
        LPFC_ABORT_IOCB
 } lpfc_iocb_type;
 
+
+/* Provide function prototypes local to this module. */
+static int lpfc_sli_issue_mbox_s4(struct lpfc_hba *, LPFC_MBOXQ_t *,
+                                 uint32_t);
+static int lpfc_sli4_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *,
+                           uint8_t *, uint32_t *);
+
+static IOCB_t *
+lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq)
+{
+       return &iocbq->iocb;
+}
+
+/**
+ * lpfc_sli4_wq_put - Put a Work Queue Entry on an Work Queue
+ * @q: The Work Queue to operate on.
+ * @wqe: The work Queue Entry to put on the Work queue.
+ *
+ * This routine will copy the contents of @wqe to the next available entry on
+ * the @q. This function will then ring the Work Queue Doorbell to signal the
+ * HBA to start processing the Work Queue Entry. This function returns 0 if
+ * successful. If no entries are available on @q then this function will return
+ * -ENOMEM.
+ * The caller is expected to hold the hbalock when calling this routine.
+ **/
+static uint32_t
+lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe)
+{
+       union lpfc_wqe *temp_wqe = q->qe[q->host_index].wqe;
+       struct lpfc_register doorbell;
+       uint32_t host_index;
+
+       /* If the host has not yet processed the next entry then we are done */
+       if (((q->host_index + 1) % q->entry_count) == q->hba_index)
+               return -ENOMEM;
+       /* set consumption flag every once in a while */
+       if (!((q->host_index + 1) % LPFC_RELEASE_NOTIFICATION_INTERVAL))
+               bf_set(lpfc_wqe_gen_wqec, &wqe->generic, 1);
+
+       lpfc_sli_pcimem_bcopy(wqe, temp_wqe, q->entry_size);
+
+       /* Update the host index before invoking device */
+       host_index = q->host_index;
+       q->host_index = ((q->host_index + 1) % q->entry_count);
+
+       /* Ring Doorbell */
+       doorbell.word0 = 0;
+       bf_set(lpfc_wq_doorbell_num_posted, &doorbell, 1);
+       bf_set(lpfc_wq_doorbell_index, &doorbell, host_index);
+       bf_set(lpfc_wq_doorbell_id, &doorbell, q->queue_id);
+       writel(doorbell.word0, q->phba->sli4_hba.WQDBregaddr);
+       readl(q->phba->sli4_hba.WQDBregaddr); /* Flush */
+
+       return 0;
+}
+
+/**
+ * lpfc_sli4_wq_release - Updates internal hba index for WQ
+ * @q: The Work Queue to operate on.
+ * @index: The index to advance the hba index to.
+ *
+ * This routine will update the HBA index of a queue to reflect consumption of
+ * Work Queue Entries by the HBA. When the HBA indicates that it has consumed
+ * an entry the host calls this function to update the queue's internal
+ * pointers. This routine returns the number of entries that were consumed by
+ * the HBA.
+ **/
+static uint32_t
+lpfc_sli4_wq_release(struct lpfc_queue *q, uint32_t index)
+{
+       uint32_t released = 0;
+
+       if (q->hba_index == index)
+               return 0;
+       do {
+               q->hba_index = ((q->hba_index + 1) % q->entry_count);
+               released++;
+       } while (q->hba_index != index);
+       return released;
+}
+
+/**
+ * lpfc_sli4_mq_put - Put a Mailbox Queue Entry on an Mailbox Queue
+ * @q: The Mailbox Queue to operate on.
+ * @wqe: The Mailbox Queue Entry to put on the Work queue.
+ *
+ * This routine will copy the contents of @mqe to the next available entry on
+ * the @q. This function will then ring the Work Queue Doorbell to signal the
+ * HBA to start processing the Work Queue Entry. This function returns 0 if
+ * successful. If no entries are available on @q then this function will return
+ * -ENOMEM.
+ * The caller is expected to hold the hbalock when calling this routine.
+ **/
+static uint32_t
+lpfc_sli4_mq_put(struct lpfc_queue *q, struct lpfc_mqe *mqe)
+{
+       struct lpfc_mqe *temp_mqe = q->qe[q->host_index].mqe;
+       struct lpfc_register doorbell;
+       uint32_t host_index;
+
+       /* If the host has not yet processed the next entry then we are done */
+       if (((q->host_index + 1) % q->entry_count) == q->hba_index)
+               return -ENOMEM;
+       lpfc_sli_pcimem_bcopy(mqe, temp_mqe, q->entry_size);
+       /* Save off the mailbox pointer for completion */
+       q->phba->mbox = (MAILBOX_t *)temp_mqe;
+
+       /* Update the host index before invoking device */
+       host_index = q->host_index;
+       q->host_index = ((q->host_index + 1) % q->entry_count);
+
+       /* Ring Doorbell */
+       doorbell.word0 = 0;
+       bf_set(lpfc_mq_doorbell_num_posted, &doorbell, 1);
+       bf_set(lpfc_mq_doorbell_id, &doorbell, q->queue_id);
+       writel(doorbell.word0, q->phba->sli4_hba.MQDBregaddr);
+       readl(q->phba->sli4_hba.MQDBregaddr); /* Flush */
+       return 0;
+}
+
+/**
+ * lpfc_sli4_mq_release - Updates internal hba index for MQ
+ * @q: The Mailbox Queue to operate on.
+ *
+ * This routine will update the HBA index of a queue to reflect consumption of
+ * a Mailbox Queue Entry by the HBA. When the HBA indicates that it has consumed
+ * an entry the host calls this function to update the queue's internal
+ * pointers. This routine returns the number of entries that were consumed by
+ * the HBA.
+ **/
+static uint32_t
+lpfc_sli4_mq_release(struct lpfc_queue *q)
+{
+       /* Clear the mailbox pointer for completion */
+       q->phba->mbox = NULL;
+       q->hba_index = ((q->hba_index + 1) % q->entry_count);
+       return 1;
+}
+
+/**
+ * lpfc_sli4_eq_get - Gets the next valid EQE from a EQ
+ * @q: The Event Queue to get the first valid EQE from
+ *
+ * This routine will get the first valid Event Queue Entry from @q, update
+ * the queue's internal hba index, and return the EQE. If no valid EQEs are in
+ * the Queue (no more work to do), or the Queue is full of EQEs that have been
+ * processed, but not popped back to the HBA then this routine will return NULL.
+ **/
+static struct lpfc_eqe *
+lpfc_sli4_eq_get(struct lpfc_queue *q)
+{
+       struct lpfc_eqe *eqe = q->qe[q->hba_index].eqe;
+
+       /* If the next EQE is not valid then we are done */
+       if (!bf_get(lpfc_eqe_valid, eqe))
+               return NULL;
+       /* If the host has not yet processed the next entry then we are done */
+       if (((q->hba_index + 1) % q->entry_count) == q->host_index)
+               return NULL;
+
+       q->hba_index = ((q->hba_index + 1) % q->entry_count);
+       return eqe;
+}
+
+/**
+ * lpfc_sli4_eq_release - Indicates the host has finished processing an EQ
+ * @q: The Event Queue that the host has completed processing for.
+ * @arm: Indicates whether the host wants to arms this CQ.
+ *
+ * This routine will mark all Event Queue Entries on @q, from the last
+ * known completed entry to the last entry that was processed, as completed
+ * by clearing the valid bit for each completion queue entry. Then it will
+ * notify the HBA, by ringing the doorbell, that the EQEs have been processed.
+ * The internal host index in the @q will be updated by this routine to indicate
+ * that the host has finished processing the entries. The @arm parameter
+ * indicates that the queue should be rearmed when ringing the doorbell.
+ *
+ * This function will return the number of EQEs that were popped.
+ **/
+uint32_t
+lpfc_sli4_eq_release(struct lpfc_queue *q, bool arm)
+{
+       uint32_t released = 0;
+       struct lpfc_eqe *temp_eqe;
+       struct lpfc_register doorbell;
+
+       /* while there are valid entries */
+       while (q->hba_index != q->host_index) {
+               temp_eqe = q->qe[q->host_index].eqe;
+               bf_set(lpfc_eqe_valid, temp_eqe, 0);
+               released++;
+               q->host_index = ((q->host_index + 1) % q->entry_count);
+       }
+       if (unlikely(released == 0 && !arm))
+               return 0;
+
+       /* ring doorbell for number popped */
+       doorbell.word0 = 0;
+       if (arm) {
+               bf_set(lpfc_eqcq_doorbell_arm, &doorbell, 1);
+               bf_set(lpfc_eqcq_doorbell_eqci, &doorbell, 1);
+       }
+       bf_set(lpfc_eqcq_doorbell_num_released, &doorbell, released);
+       bf_set(lpfc_eqcq_doorbell_qt, &doorbell, LPFC_QUEUE_TYPE_EVENT);
+       bf_set(lpfc_eqcq_doorbell_eqid, &doorbell, q->queue_id);
+       writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr);
+       return released;
+}
+
+/**
+ * lpfc_sli4_cq_get - Gets the next valid CQE from a CQ
+ * @q: The Completion Queue to get the first valid CQE from
+ *
+ * This routine will get the first valid Completion Queue Entry from @q, update
+ * the queue's internal hba index, and return the CQE. If no valid CQEs are in
+ * the Queue (no more work to do), or the Queue is full of CQEs that have been
+ * processed, but not popped back to the HBA then this routine will return NULL.
+ **/
+static struct lpfc_cqe *
+lpfc_sli4_cq_get(struct lpfc_queue *q)
+{
+       struct lpfc_cqe *cqe;
+
+       /* If the next CQE is not valid then we are done */
+       if (!bf_get(lpfc_cqe_valid, q->qe[q->hba_index].cqe))
+               return NULL;
+       /* If the host has not yet processed the next entry then we are done */
+       if (((q->hba_index + 1) % q->entry_count) == q->host_index)
+               return NULL;
+
+       cqe = q->qe[q->hba_index].cqe;
+       q->hba_index = ((q->hba_index + 1) % q->entry_count);
+       return cqe;
+}
+
+/**
+ * lpfc_sli4_cq_release - Indicates the host has finished processing a CQ
+ * @q: The Completion Queue that the host has completed processing for.
+ * @arm: Indicates whether the host wants to arms this CQ.
+ *
+ * This routine will mark all Completion queue entries on @q, from the last
+ * known completed entry to the last entry that was processed, as completed
+ * by clearing the valid bit for each completion queue entry. Then it will
+ * notify the HBA, by ringing the doorbell, that the CQEs have been processed.
+ * The internal host index in the @q will be updated by this routine to indicate
+ * that the host has finished processing the entries. The @arm parameter
+ * indicates that the queue should be rearmed when ringing the doorbell.
+ *
+ * This function will return the number of CQEs that were released.
+ **/
+uint32_t
+lpfc_sli4_cq_release(struct lpfc_queue *q, bool arm)
+{
+       uint32_t released = 0;
+       struct lpfc_cqe *temp_qe;
+       struct lpfc_register doorbell;
+
+       /* while there are valid entries */
+       while (q->hba_index != q->host_index) {
+               temp_qe = q->qe[q->host_index].cqe;
+               bf_set(lpfc_cqe_valid, temp_qe, 0);
+               released++;
+               q->host_index = ((q->host_index + 1) % q->entry_count);
+       }
+       if (unlikely(released == 0 && !arm))
+               return 0;
+
+       /* ring doorbell for number popped */
+       doorbell.word0 = 0;
+       if (arm)
+               bf_set(lpfc_eqcq_doorbell_arm, &doorbell, 1);
+       bf_set(lpfc_eqcq_doorbell_num_released, &doorbell, released);
+       bf_set(lpfc_eqcq_doorbell_qt, &doorbell, LPFC_QUEUE_TYPE_COMPLETION);
+       bf_set(lpfc_eqcq_doorbell_cqid, &doorbell, q->queue_id);
+       writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr);
+       return released;
+}
+
+/**
+ * lpfc_sli4_rq_put - Put a Receive Buffer Queue Entry on a Receive Queue
+ * @q: The Header Receive Queue to operate on.
+ * @wqe: The Receive Queue Entry to put on the Receive queue.
+ *
+ * This routine will copy the contents of @wqe to the next available entry on
+ * the @q. This function will then ring the Receive Queue Doorbell to signal the
+ * HBA to start processing the Receive Queue Entry. This function returns the
+ * index that the rqe was copied to if successful. If no entries are available
+ * on @q then this function will return -ENOMEM.
+ * The caller is expected to hold the hbalock when calling this routine.
+ **/
+static int
+lpfc_sli4_rq_put(struct lpfc_queue *hq, struct lpfc_queue *dq,
+                struct lpfc_rqe *hrqe, struct lpfc_rqe *drqe)
+{
+       struct lpfc_rqe *temp_hrqe = hq->qe[hq->host_index].rqe;
+       struct lpfc_rqe *temp_drqe = dq->qe[dq->host_index].rqe;
+       struct lpfc_register doorbell;
+       int put_index = hq->host_index;
+
+       if (hq->type != LPFC_HRQ || dq->type != LPFC_DRQ)
+               return -EINVAL;
+       if (hq->host_index != dq->host_index)
+               return -EINVAL;
+       /* If the host has not yet processed the next entry then we are done */
+       if (((hq->host_index + 1) % hq->entry_count) == hq->hba_index)
+               return -EBUSY;
+       lpfc_sli_pcimem_bcopy(hrqe, temp_hrqe, hq->entry_size);
+       lpfc_sli_pcimem_bcopy(drqe, temp_drqe, dq->entry_size);
+
+       /* Update the host index to point to the next slot */
+       hq->host_index = ((hq->host_index + 1) % hq->entry_count);
+       dq->host_index = ((dq->host_index + 1) % dq->entry_count);
+
+       /* Ring The Header Receive Queue Doorbell */
+       if (!(hq->host_index % LPFC_RQ_POST_BATCH)) {
+               doorbell.word0 = 0;
+               bf_set(lpfc_rq_doorbell_num_posted, &doorbell,
+                      LPFC_RQ_POST_BATCH);
+               bf_set(lpfc_rq_doorbell_id, &doorbell, hq->queue_id);
+               writel(doorbell.word0, hq->phba->sli4_hba.RQDBregaddr);
+       }
+       return put_index;
+}
+
+/**
+ * lpfc_sli4_rq_release - Updates internal hba index for RQ
+ * @q: The Header Receive Queue to operate on.
+ *
+ * This routine will update the HBA index of a queue to reflect consumption of
+ * one Receive Queue Entry by the HBA. When the HBA indicates that it has
+ * consumed an entry the host calls this function to update the queue's
+ * internal pointers. This routine returns the number of entries that were
+ * consumed by the HBA.
+ **/
+static uint32_t
+lpfc_sli4_rq_release(struct lpfc_queue *hq, struct lpfc_queue *dq)
+{
+       if ((hq->type != LPFC_HRQ) || (dq->type != LPFC_DRQ))
+               return 0;
+       hq->hba_index = ((hq->hba_index + 1) % hq->entry_count);
+       dq->hba_index = ((dq->hba_index + 1) % dq->entry_count);
+       return 1;
+}
+
 /**
  * lpfc_cmd_iocb - Get next command iocb entry in the ring
  * @phba: Pointer to HBA context object.
@@ -120,6 +450,76 @@ __lpfc_sli_get_iocbq(struct lpfc_hba *phba)
        return iocbq;
 }
 
+/**
+ * __lpfc_clear_active_sglq - Remove the active sglq for this XRI.
+ * @phba: Pointer to HBA context object.
+ * @xritag: XRI value.
+ *
+ * This function clears the sglq pointer from the array of acive
+ * sglq's. The xritag that is passed in is used to index into the
+ * array. Before the xritag can be used it needs to be adjusted
+ * by subtracting the xribase.
+ *
+ * Returns sglq ponter = success, NULL = Failure.
+ **/
+static struct lpfc_sglq *
+__lpfc_clear_active_sglq(struct lpfc_hba *phba, uint16_t xritag)
+{
+       uint16_t adj_xri;
+       struct lpfc_sglq *sglq;
+       adj_xri = xritag - phba->sli4_hba.max_cfg_param.xri_base;
+       if (adj_xri > phba->sli4_hba.max_cfg_param.max_xri)
+               return NULL;
+       sglq = phba->sli4_hba.lpfc_sglq_active_list[adj_xri];
+       phba->sli4_hba.lpfc_sglq_active_list[adj_xri] = NULL;
+       return sglq;
+}
+
+/**
+ * __lpfc_get_active_sglq - Get the active sglq for this XRI.
+ * @phba: Pointer to HBA context object.
+ * @xritag: XRI value.
+ *
+ * This function returns the sglq pointer from the array of acive
+ * sglq's. The xritag that is passed in is used to index into the
+ * array. Before the xritag can be used it needs to be adjusted
+ * by subtracting the xribase.
+ *
+ * Returns sglq ponter = success, NULL = Failure.
+ **/
+static struct lpfc_sglq *
+__lpfc_get_active_sglq(struct lpfc_hba *phba, uint16_t xritag)
+{
+       uint16_t adj_xri;
+       struct lpfc_sglq *sglq;
+       adj_xri = xritag - phba->sli4_hba.max_cfg_param.xri_base;
+       if (adj_xri > phba->sli4_hba.max_cfg_param.max_xri)
+               return NULL;
+       sglq =  phba->sli4_hba.lpfc_sglq_active_list[adj_xri];
+       return sglq;
+}
+
+/**
+ * __lpfc_sli_get_sglq - Allocates an iocb object from sgl pool
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called with hbalock held. This function
+ * Gets a new driver sglq object from the sglq list. If the
+ * list is not empty then it is successful, it returns pointer to the newly
+ * allocated sglq object else it returns NULL.
+ **/
+static struct lpfc_sglq *
+__lpfc_sli_get_sglq(struct lpfc_hba *phba)
+{
+       struct list_head *lpfc_sgl_list = &phba->sli4_hba.lpfc_sgl_list;
+       struct lpfc_sglq *sglq = NULL;
+       uint16_t adj_xri;
+       list_remove_head(lpfc_sgl_list, sglq, struct lpfc_sglq, list);
+       adj_xri = sglq->sli4_xritag - phba->sli4_hba.max_cfg_param.xri_base;
+       phba->sli4_hba.lpfc_sglq_active_list[adj_xri] = sglq;
+       return sglq;
+}
+
 /**
  * lpfc_sli_get_iocbq - Allocates an iocb object from iocb pool
  * @phba: Pointer to HBA context object.
@@ -142,7 +542,7 @@ lpfc_sli_get_iocbq(struct lpfc_hba *phba)
 }
 
 /**
- * __lpfc_sli_release_iocbq - Release iocb to the iocb pool
+ * __lpfc_sli_release_iocbq_s4 - Release iocb to the iocb pool
  * @phba: Pointer to HBA context object.
  * @iocbq: Pointer to driver iocb object.
  *
@@ -150,9 +550,62 @@ lpfc_sli_get_iocbq(struct lpfc_hba *phba)
  * iocb object to the iocb pool. The iotag in the iocb object
  * does not change for each use of the iocb object. This function
  * clears all other fields of the iocb object when it is freed.
+ * The sqlq structure that holds the xritag and phys and virtual
+ * mappings for the scatter gather list is retrieved from the
+ * active array of sglq. The get of the sglq pointer also clears
+ * the entry in the array. If the status of the IO indiactes that
+ * this IO was aborted then the sglq entry it put on the
+ * lpfc_abts_els_sgl_list until the CQ_ABORTED_XRI is received. If the
+ * IO has good status or fails for any other reason then the sglq
+ * entry is added to the free list (lpfc_sgl_list).
  **/
 static void
-__lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
+__lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
+{
+       struct lpfc_sglq *sglq;
+       size_t start_clean = offsetof(struct lpfc_iocbq, iocb);
+       unsigned long iflag;
+
+       if (iocbq->sli4_xritag == NO_XRI)
+               sglq = NULL;
+       else
+               sglq = __lpfc_clear_active_sglq(phba, iocbq->sli4_xritag);
+       if (sglq)  {
+               if (iocbq->iocb_flag & LPFC_DRIVER_ABORTED
+                       || ((iocbq->iocb.ulpStatus == IOSTAT_LOCAL_REJECT)
+                       && (iocbq->iocb.un.ulpWord[4]
+                               == IOERR_SLI_ABORTED))) {
+                       spin_lock_irqsave(&phba->sli4_hba.abts_sgl_list_lock,
+                                       iflag);
+                       list_add(&sglq->list,
+                               &phba->sli4_hba.lpfc_abts_els_sgl_list);
+                       spin_unlock_irqrestore(
+                               &phba->sli4_hba.abts_sgl_list_lock, iflag);
+               } else
+                       list_add(&sglq->list, &phba->sli4_hba.lpfc_sgl_list);
+       }
+
+
+       /*
+        * Clean all volatile data fields, preserve iotag and node struct.
+        */
+       memset((char *)iocbq + start_clean, 0, sizeof(*iocbq) - start_clean);
+       iocbq->sli4_xritag = NO_XRI;
+       list_add_tail(&iocbq->list, &phba->lpfc_iocb_list);
+}
+
+/**
+ * __lpfc_sli_release_iocbq_s3 - Release iocb to the iocb pool
+ * @phba: Pointer to HBA context object.
+ * @iocbq: Pointer to driver iocb object.
+ *
+ * This function is called with hbalock held to release driver
+ * iocb object to the iocb pool. The iotag in the iocb object
+ * does not change for each use of the iocb object. This function
+ * clears all other fields of the iocb object when it is freed.
+ **/
+static void
+__lpfc_sli_release_iocbq_s3(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
 {
        size_t start_clean = offsetof(struct lpfc_iocbq, iocb);
 
@@ -160,9 +613,26 @@ __lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
         * Clean all volatile data fields, preserve iotag and node struct.
         */
        memset((char*)iocbq + start_clean, 0, sizeof(*iocbq) - start_clean);
+       iocbq->sli4_xritag = NO_XRI;
        list_add_tail(&iocbq->list, &phba->lpfc_iocb_list);
 }
 
+/**
+ * __lpfc_sli_release_iocbq - Release iocb to the iocb pool
+ * @phba: Pointer to HBA context object.
+ * @iocbq: Pointer to driver iocb object.
+ *
+ * This function is called with hbalock held to release driver
+ * iocb object to the iocb pool. The iotag in the iocb object
+ * does not change for each use of the iocb object. This function
+ * clears all other fields of the iocb object when it is freed.
+ **/
+static void
+__lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
+{
+       phba->__lpfc_sli_release_iocbq(phba, iocbq);
+}
+
 /**
  * lpfc_sli_release_iocbq - Release iocb to the iocb pool
  * @phba: Pointer to HBA context object.
@@ -281,6 +751,14 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
        case CMD_GEN_REQUEST64_CR:
        case CMD_GEN_REQUEST64_CX:
        case CMD_XMIT_ELS_RSP64_CX:
+       case DSSCMD_IWRITE64_CR:
+       case DSSCMD_IWRITE64_CX:
+       case DSSCMD_IREAD64_CR:
+       case DSSCMD_IREAD64_CX:
+       case DSSCMD_INVALIDATE_DEK:
+       case DSSCMD_SET_KEK:
+       case DSSCMD_GET_KEK_ID:
+       case DSSCMD_GEN_XFER:
                type = LPFC_SOL_IOCB;
                break;
        case CMD_ABORT_XRI_CN:
@@ -348,7 +826,7 @@ lpfc_sli_ring_map(struct lpfc_hba *phba)
        pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (!pmb)
                return -ENOMEM;
-       pmbox = &pmb->mb;
+       pmbox = &pmb->u.mb;
        phba->link_state = LPFC_INIT_MBX_CMDS;
        for (i = 0; i < psli->num_rings; i++) {
                lpfc_config_ring(phba, i, pmb);
@@ -779,8 +1257,8 @@ lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba)
                phba->hbqs[i].buffer_count = 0;
        }
        /* Return all HBQ buffer that are in-fly */
-       list_for_each_entry_safe(dmabuf, next_dmabuf,
-                       &phba->hbqbuf_in_list, list) {
+       list_for_each_entry_safe(dmabuf, next_dmabuf, &phba->rb_pend_list,
+                                list) {
                hbq_buf = container_of(dmabuf, struct hbq_dmabuf, dbuf);
                list_del(&hbq_buf->dbuf.list);
                if (hbq_buf->tag == -1) {
@@ -814,9 +1292,27 @@ lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba)
  * pointer to the hbq entry if it successfully post the buffer
  * else it will return NULL.
  **/
-static struct lpfc_hbq_entry *
+static int
 lpfc_sli_hbq_to_firmware(struct lpfc_hba *phba, uint32_t hbqno,
                         struct hbq_dmabuf *hbq_buf)
+{
+       return phba->lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buf);
+}
+
+/**
+ * lpfc_sli_hbq_to_firmware_s3 - Post the hbq buffer to SLI3 firmware
+ * @phba: Pointer to HBA context object.
+ * @hbqno: HBQ number.
+ * @hbq_buf: Pointer to HBQ buffer.
+ *
+ * This function is called with the hbalock held to post a hbq buffer to the
+ * firmware. If the function finds an empty slot in the HBQ, it will post the
+ * buffer and place it on the hbq_buffer_list. The function will return zero if
+ * it successfully post the buffer else it will return an error.
+ **/
+static int
+lpfc_sli_hbq_to_firmware_s3(struct lpfc_hba *phba, uint32_t hbqno,
+                           struct hbq_dmabuf *hbq_buf)
 {
        struct lpfc_hbq_entry *hbqe;
        dma_addr_t physaddr = hbq_buf->dbuf.phys;
@@ -838,8 +1334,40 @@ lpfc_sli_hbq_to_firmware(struct lpfc_hba *phba, uint32_t hbqno,
                                /* flush */
                readl(phba->hbq_put + hbqno);
                list_add_tail(&hbq_buf->dbuf.list, &hbqp->hbq_buffer_list);
-       }
-       return hbqe;
+               return 0;
+       } else
+               return -ENOMEM;
+}
+
+/**
+ * lpfc_sli_hbq_to_firmware_s4 - Post the hbq buffer to SLI4 firmware
+ * @phba: Pointer to HBA context object.
+ * @hbqno: HBQ number.
+ * @hbq_buf: Pointer to HBQ buffer.
+ *
+ * This function is called with the hbalock held to post an RQE to the SLI4
+ * firmware. If able to post the RQE to the RQ it will queue the hbq entry to
+ * the hbq_buffer_list and return zero, otherwise it will return an error.
+ **/
+static int
+lpfc_sli_hbq_to_firmware_s4(struct lpfc_hba *phba, uint32_t hbqno,
+                           struct hbq_dmabuf *hbq_buf)
+{
+       int rc;
+       struct lpfc_rqe hrqe;
+       struct lpfc_rqe drqe;
+
+       hrqe.address_lo = putPaddrLow(hbq_buf->hbuf.phys);
+       hrqe.address_hi = putPaddrHigh(hbq_buf->hbuf.phys);
+       drqe.address_lo = putPaddrLow(hbq_buf->dbuf.phys);
+       drqe.address_hi = putPaddrHigh(hbq_buf->dbuf.phys);
+       rc = lpfc_sli4_rq_put(phba->sli4_hba.hdr_rq, phba->sli4_hba.dat_rq,
+                             &hrqe, &drqe);
+       if (rc < 0)
+               return rc;
+       hbq_buf->tag = rc;
+       list_add_tail(&hbq_buf->dbuf.list, &phba->hbqs[hbqno].hbq_buffer_list);
+       return 0;
 }
 
 /* HBQ for ELS and CT traffic. */
@@ -914,7 +1442,7 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count)
                                 dbuf.list);
                hbq_buffer->tag = (phba->hbqs[hbqno].buffer_count |
                                      (hbqno << 16));
-               if (lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer)) {
+               if (!lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer)) {
                        phba->hbqs[hbqno].buffer_count++;
                        posted++;
                } else
@@ -964,6 +1492,25 @@ lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *phba, uint32_t qno)
                                         lpfc_hbq_defs[qno]->init_count));
 }
 
+/**
+ * lpfc_sli_hbqbuf_get - Remove the first hbq off of an hbq list
+ * @phba: Pointer to HBA context object.
+ * @hbqno: HBQ number.
+ *
+ * This function removes the first hbq buffer on an hbq list and returns a
+ * pointer to that buffer. If it finds no buffers on the list it returns NULL.
+ **/
+static struct hbq_dmabuf *
+lpfc_sli_hbqbuf_get(struct list_head *rb_list)
+{
+       struct lpfc_dmabuf *d_buf;
+
+       list_remove_head(rb_list, d_buf, struct lpfc_dmabuf, list);
+       if (!d_buf)
+               return NULL;
+       return container_of(d_buf, struct hbq_dmabuf, dbuf);
+}
+
 /**
  * lpfc_sli_hbqbuf_find - Find the hbq buffer associated with a tag
  * @phba: Pointer to HBA context object.
@@ -985,12 +1532,15 @@ lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag)
        if (hbqno >= LPFC_MAX_HBQS)
                return NULL;
 
+       spin_lock_irq(&phba->hbalock);
        list_for_each_entry(d_buf, &phba->hbqs[hbqno].hbq_buffer_list, list) {
                hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
                if (hbq_buf->tag == tag) {
+                       spin_unlock_irq(&phba->hbalock);
                        return hbq_buf;
                }
        }
+       spin_unlock_irq(&phba->hbalock);
        lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_VPORT,
                        "1803 Bad hbq tag. Data: x%x x%x\n",
                        tag, phba->hbqs[tag >> 16].buffer_count);
@@ -1013,9 +1563,8 @@ lpfc_sli_free_hbq(struct lpfc_hba *phba, struct hbq_dmabuf *hbq_buffer)
 
        if (hbq_buffer) {
                hbqno = hbq_buffer->tag >> 16;
-               if (!lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer)) {
+               if (lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer))
                        (phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer);
-               }
        }
 }
 
@@ -1086,6 +1635,15 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
        case MBX_HEARTBEAT:
        case MBX_PORT_CAPABILITIES:
        case MBX_PORT_IOV_CONTROL:
+       case MBX_SLI4_CONFIG:
+       case MBX_SLI4_REQ_FTRS:
+       case MBX_REG_FCFI:
+       case MBX_UNREG_FCFI:
+       case MBX_REG_VFI:
+       case MBX_UNREG_VFI:
+       case MBX_INIT_VPI:
+       case MBX_INIT_VFI:
+       case MBX_RESUME_RPI:
                ret = mbxCommand;
                break;
        default:
@@ -1106,7 +1664,7 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
  * will wake up thread waiting on the wait queue pointed by context1
  * of the mailbox.
  **/
-static void
+void
 lpfc_sli_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
 {
        wait_queue_head_t *pdone_q;
@@ -1140,7 +1698,7 @@ void
 lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
        struct lpfc_dmabuf *mp;
-       uint16_t rpi;
+       uint16_t rpi, vpi;
        int rc;
 
        mp = (struct lpfc_dmabuf *) (pmb->context1);
@@ -1150,24 +1708,30 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                kfree(mp);
        }
 
+       if ((pmb->u.mb.mbxCommand == MBX_UNREG_LOGIN) &&
+           (phba->sli_rev == LPFC_SLI_REV4))
+               lpfc_sli4_free_rpi(phba, pmb->u.mb.un.varUnregLogin.rpi);
+
        /*
         * If a REG_LOGIN succeeded  after node is destroyed or node
         * is in re-discovery driver need to cleanup the RPI.
         */
        if (!(phba->pport->load_flag & FC_UNLOADING) &&
-           pmb->mb.mbxCommand == MBX_REG_LOGIN64 &&
-           !pmb->mb.mbxStatus) {
-
-               rpi = pmb->mb.un.varWords[0];
-               lpfc_unreg_login(phba, pmb->mb.un.varRegLogin.vpi, rpi, pmb);
+           pmb->u.mb.mbxCommand == MBX_REG_LOGIN64 &&
+           !pmb->u.mb.mbxStatus) {
+               rpi = pmb->u.mb.un.varWords[0];
+               vpi = pmb->u.mb.un.varRegLogin.vpi - phba->vpi_base;
+               lpfc_unreg_login(phba, vpi, rpi, pmb);
                pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
                rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
                if (rc != MBX_NOT_FINISHED)
                        return;
        }
 
-       mempool_free(pmb, phba->mbox_mem_pool);
-       return;
+       if (bf_get(lpfc_mqe_command, &pmb->u.mqe) == MBX_SLI4_CONFIG)
+               lpfc_sli4_mbox_cmd_free(phba, pmb);
+       else
+               mempool_free(pmb, phba->mbox_mem_pool);
 }
 
 /**
@@ -1204,7 +1768,7 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba)
                if (pmb == NULL)
                        break;
 
-               pmbox = &pmb->mb;
+               pmbox = &pmb->u.mb;
 
                if (pmbox->mbxCommand != MBX_HEARTBEAT) {
                        if (pmb->vport) {
@@ -1233,9 +1797,10 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba)
                        /* Unknow mailbox command compl */
                        lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
                                        "(%d):0323 Unknown Mailbox command "
-                                       "%x Cmpl\n",
+                                       "x%x (x%x) Cmpl\n",
                                        pmb->vport ? pmb->vport->vpi : 0,
-                                       pmbox->mbxCommand);
+                                       pmbox->mbxCommand,
+                                       lpfc_sli4_mbox_opcode_get(phba, pmb));
                        phba->link_state = LPFC_HBA_ERROR;
                        phba->work_hs = HS_FFER3;
                        lpfc_handle_eratt(phba);
@@ -1250,29 +1815,29 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba)
                                                LOG_MBOX | LOG_SLI,
                                                "(%d):0305 Mbox cmd cmpl "
                                                "error - RETRYing Data: x%x "
-                                               "x%x x%x x%x\n",
+                                               "(x%x) x%x x%x x%x\n",
                                                pmb->vport ? pmb->vport->vpi :0,
                                                pmbox->mbxCommand,
+                                               lpfc_sli4_mbox_opcode_get(phba,
+                                                                         pmb),
                                                pmbox->mbxStatus,
                                                pmbox->un.varWords[0],
                                                pmb->vport->port_state);
                                pmbox->mbxStatus = 0;
                                pmbox->mbxOwner = OWN_HOST;
-                               spin_lock_irq(&phba->hbalock);
-                               phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
-                               spin_unlock_irq(&phba->hbalock);
                                rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
-                               if (rc == MBX_SUCCESS)
+                               if (rc != MBX_NOT_FINISHED)
                                        continue;
                        }
                }
 
                /* Mailbox cmd <cmd> Cmpl <cmpl> */
                lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
-                               "(%d):0307 Mailbox cmd x%x Cmpl x%p "
+                               "(%d):0307 Mailbox cmd x%x (x%x) Cmpl x%p "
                                "Data: x%x x%x x%x x%x x%x x%x x%x x%x x%x\n",
                                pmb->vport ? pmb->vport->vpi : 0,
                                pmbox->mbxCommand,
+                               lpfc_sli4_mbox_opcode_get(phba, pmb),
                                pmb->mbox_cmpl,
                                *((uint32_t *) pmbox),
                                pmbox->un.varWords[0],
@@ -1317,6 +1882,45 @@ lpfc_sli_get_buff(struct lpfc_hba *phba,
        return &hbq_entry->dbuf;
 }
 
+/**
+ * lpfc_complete_unsol_iocb - Complete an unsolicited sequence
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @saveq: Pointer to the iocbq struct representing the sequence starting frame.
+ * @fch_r_ctl: the r_ctl for the first frame of the sequence.
+ * @fch_type: the type for the first frame of the sequence.
+ *
+ * This function is called with no lock held. This function uses the r_ctl and
+ * type of the received sequence to find the correct callback function to call
+ * to process the sequence.
+ **/
+static int
+lpfc_complete_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+                        struct lpfc_iocbq *saveq, uint32_t fch_r_ctl,
+                        uint32_t fch_type)
+{
+       int i;
+
+       /* unSolicited Responses */
+       if (pring->prt[0].profile) {
+               if (pring->prt[0].lpfc_sli_rcv_unsol_event)
+                       (pring->prt[0].lpfc_sli_rcv_unsol_event) (phba, pring,
+                                                                       saveq);
+               return 1;
+       }
+       /* We must search, based on rctl / type
+          for the right routine */
+       for (i = 0; i < pring->num_mask; i++) {
+               if ((pring->prt[i].rctl == fch_r_ctl) &&
+                   (pring->prt[i].type == fch_type)) {
+                       if (pring->prt[i].lpfc_sli_rcv_unsol_event)
+                               (pring->prt[i].lpfc_sli_rcv_unsol_event)
+                                               (phba, pring, saveq);
+                       return 1;
+               }
+       }
+       return 0;
+}
 
 /**
  * lpfc_sli_process_unsol_iocb - Unsolicited iocb handler
@@ -1339,7 +1943,7 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        IOCB_t           * irsp;
        WORD5            * w5p;
        uint32_t           Rctl, Type;
-       uint32_t           match, i;
+       uint32_t           match;
        struct lpfc_iocbq *iocbq;
        struct lpfc_dmabuf *dmzbuf;
 
@@ -1482,35 +2086,12 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                }
        }
 
-       /* unSolicited Responses */
-       if (pring->prt[0].profile) {
-               if (pring->prt[0].lpfc_sli_rcv_unsol_event)
-                       (pring->prt[0].lpfc_sli_rcv_unsol_event) (phba, pring,
-                                                                       saveq);
-               match = 1;
-       } else {
-               /* We must search, based on rctl / type
-                  for the right routine */
-               for (i = 0; i < pring->num_mask; i++) {
-                       if ((pring->prt[i].rctl == Rctl)
-                           && (pring->prt[i].type == Type)) {
-                               if (pring->prt[i].lpfc_sli_rcv_unsol_event)
-                                       (pring->prt[i].lpfc_sli_rcv_unsol_event)
-                                                       (phba, pring, saveq);
-                               match = 1;
-                               break;
-                       }
-               }
-       }
-       if (match == 0) {
-               /* Unexpected Rctl / Type received */
-               /* Ring <ringno> handler: unexpected
-                  Rctl <Rctl> Type <Type> received */
+       if (!lpfc_complete_unsol_iocb(phba, pring, saveq, Rctl, Type))
                lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
                                "0313 Ring %d handler: unexpected Rctl x%x "
                                "Type x%x received\n",
                                pring->ringno, Rctl, Type);
-       }
+
        return 1;
 }
 
@@ -1551,6 +2132,37 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba,
        return NULL;
 }
 
+/**
+ * lpfc_sli_iocbq_lookup_by_tag - Find command iocb for the iotag
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @iotag: IOCB tag.
+ *
+ * This function looks up the iocb_lookup table to get the command iocb
+ * corresponding to the given iotag. This function is called with the
+ * hbalock held.
+ * This function returns the command iocb object if it finds the command
+ * iocb else returns NULL.
+ **/
+static struct lpfc_iocbq *
+lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba,
+                            struct lpfc_sli_ring *pring, uint16_t iotag)
+{
+       struct lpfc_iocbq *cmd_iocb;
+
+       if (iotag != 0 && iotag <= phba->sli.last_iotag) {
+               cmd_iocb = phba->sli.iocbq_lookup[iotag];
+               list_del_init(&cmd_iocb->list);
+               pring->txcmplq_cnt--;
+               return cmd_iocb;
+       }
+
+       lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                       "0372 iotag x%x is out off range: max iotag (x%x)\n",
+                       iotag, phba->sli.last_iotag);
+       return NULL;
+}
+
 /**
  * lpfc_sli_process_sol_iocb - process solicited iocb completion
  * @phba: Pointer to HBA context object.
@@ -1954,7 +2566,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba,
                        if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
                                (irsp->un.ulpWord[4] == IOERR_NO_RESOURCES)) {
                                spin_unlock_irqrestore(&phba->hbalock, iflag);
-                               lpfc_rampdown_queue_depth(phba);
+                               phba->lpfc_rampdown_queue_depth(phba);
                                spin_lock_irqsave(&phba->hbalock, iflag);
                        }
 
@@ -2068,39 +2680,215 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba,
 }
 
 /**
- * lpfc_sli_handle_slow_ring_event - Handle ring events for non-FCP rings
+ * lpfc_sli_sp_handle_rspiocb - Handle slow-path response iocb
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @rspiocbp: Pointer to driver response IOCB object.
+ *
+ * This function is called from the worker thread when there is a slow-path
+ * response IOCB to process. This function chains all the response iocbs until
+ * seeing the iocb with the LE bit set. The function will call
+ * lpfc_sli_process_sol_iocb function if the response iocb indicates a
+ * completion of a command iocb. The function will call the
+ * lpfc_sli_process_unsol_iocb function if this is an unsolicited iocb.
+ * The function frees the resources or calls the completion handler if this
+ * iocb is an abort completion. The function returns NULL when the response
+ * iocb has the LE bit set and all the chained iocbs are processed, otherwise
+ * this function shall chain the iocb on to the iocb_continueq and return the
+ * response iocb passed in.
+ **/
+static struct lpfc_iocbq *
+lpfc_sli_sp_handle_rspiocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+                       struct lpfc_iocbq *rspiocbp)
+{
+       struct lpfc_iocbq *saveq;
+       struct lpfc_iocbq *cmdiocbp;
+       struct lpfc_iocbq *next_iocb;
+       IOCB_t *irsp = NULL;
+       uint32_t free_saveq;
+       uint8_t iocb_cmd_type;
+       lpfc_iocb_type type;
+       unsigned long iflag;
+       int rc;
+
+       spin_lock_irqsave(&phba->hbalock, iflag);
+       /* First add the response iocb to the countinueq list */
+       list_add_tail(&rspiocbp->list, &(pring->iocb_continueq));
+       pring->iocb_continueq_cnt++;
+
+       /* Now, determine whetehr the list is completed for processing */
+       irsp = &rspiocbp->iocb;
+       if (irsp->ulpLe) {
+               /*
+                * By default, the driver expects to free all resources
+                * associated with this iocb completion.
+                */
+               free_saveq = 1;
+               saveq = list_get_first(&pring->iocb_continueq,
+                                      struct lpfc_iocbq, list);
+               irsp = &(saveq->iocb);
+               list_del_init(&pring->iocb_continueq);
+               pring->iocb_continueq_cnt = 0;
+
+               pring->stats.iocb_rsp++;
+
+               /*
+                * If resource errors reported from HBA, reduce
+                * queuedepths of the SCSI device.
+                */
+               if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+                   (irsp->un.ulpWord[4] == IOERR_NO_RESOURCES)) {
+                       spin_unlock_irqrestore(&phba->hbalock, iflag);
+                       phba->lpfc_rampdown_queue_depth(phba);
+                       spin_lock_irqsave(&phba->hbalock, iflag);
+               }
+
+               if (irsp->ulpStatus) {
+                       /* Rsp ring <ringno> error: IOCB */
+                       lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+                                       "0328 Rsp Ring %d error: "
+                                       "IOCB Data: "
+                                       "x%x x%x x%x x%x "
+                                       "x%x x%x x%x x%x "
+                                       "x%x x%x x%x x%x "
+                                       "x%x x%x x%x x%x\n",
+                                       pring->ringno,
+                                       irsp->un.ulpWord[0],
+                                       irsp->un.ulpWord[1],
+                                       irsp->un.ulpWord[2],
+                                       irsp->un.ulpWord[3],
+                                       irsp->un.ulpWord[4],
+                                       irsp->un.ulpWord[5],
+                                       *(((uint32_t *) irsp) + 6),
+                                       *(((uint32_t *) irsp) + 7),
+                                       *(((uint32_t *) irsp) + 8),
+                                       *(((uint32_t *) irsp) + 9),
+                                       *(((uint32_t *) irsp) + 10),
+                                       *(((uint32_t *) irsp) + 11),
+                                       *(((uint32_t *) irsp) + 12),
+                                       *(((uint32_t *) irsp) + 13),
+                                       *(((uint32_t *) irsp) + 14),
+                                       *(((uint32_t *) irsp) + 15));
+               }
+
+               /*
+                * Fetch the IOCB command type and call the correct completion
+                * routine. Solicited and Unsolicited IOCBs on the ELS ring
+                * get freed back to the lpfc_iocb_list by the discovery
+                * kernel thread.
+                */
+               iocb_cmd_type = irsp->ulpCommand & CMD_IOCB_MASK;
+               type = lpfc_sli_iocb_cmd_type(iocb_cmd_type);
+               switch (type) {
+               case LPFC_SOL_IOCB:
+                       spin_unlock_irqrestore(&phba->hbalock, iflag);
+                       rc = lpfc_sli_process_sol_iocb(phba, pring, saveq);
+                       spin_lock_irqsave(&phba->hbalock, iflag);
+                       break;
+
+               case LPFC_UNSOL_IOCB:
+                       spin_unlock_irqrestore(&phba->hbalock, iflag);
+                       rc = lpfc_sli_process_unsol_iocb(phba, pring, saveq);
+                       spin_lock_irqsave(&phba->hbalock, iflag);
+                       if (!rc)
+                               free_saveq = 0;
+                       break;
+
+               case LPFC_ABORT_IOCB:
+                       cmdiocbp = NULL;
+                       if (irsp->ulpCommand != CMD_XRI_ABORTED_CX)
+                               cmdiocbp = lpfc_sli_iocbq_lookup(phba, pring,
+                                                                saveq);
+                       if (cmdiocbp) {
+                               /* Call the specified completion routine */
+                               if (cmdiocbp->iocb_cmpl) {
+                                       spin_unlock_irqrestore(&phba->hbalock,
+                                                              iflag);
+                                       (cmdiocbp->iocb_cmpl)(phba, cmdiocbp,
+                                                             saveq);
+                                       spin_lock_irqsave(&phba->hbalock,
+                                                         iflag);
+                               } else
+                                       __lpfc_sli_release_iocbq(phba,
+                                                                cmdiocbp);
+                       }
+                       break;
+
+               case LPFC_UNKNOWN_IOCB:
+                       if (irsp->ulpCommand == CMD_ADAPTER_MSG) {
+                               char adaptermsg[LPFC_MAX_ADPTMSG];
+                               memset(adaptermsg, 0, LPFC_MAX_ADPTMSG);
+                               memcpy(&adaptermsg[0], (uint8_t *)irsp,
+                                      MAX_MSG_DATA);
+                               dev_warn(&((phba->pcidev)->dev),
+                                        "lpfc%d: %s\n",
+                                        phba->brd_no, adaptermsg);
+                       } else {
+                               /* Unknown IOCB command */
+                               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                                               "0335 Unknown IOCB "
+                                               "command Data: x%x "
+                                               "x%x x%x x%x\n",
+                                               irsp->ulpCommand,
+                                               irsp->ulpStatus,
+                                               irsp->ulpIoTag,
+                                               irsp->ulpContext);
+                       }
+                       break;
+               }
+
+               if (free_saveq) {
+                       list_for_each_entry_safe(rspiocbp, next_iocb,
+                                                &saveq->list, list) {
+                               list_del(&rspiocbp->list);
+                               __lpfc_sli_release_iocbq(phba, rspiocbp);
+                       }
+                       __lpfc_sli_release_iocbq(phba, saveq);
+               }
+               rspiocbp = NULL;
+       }
+       spin_unlock_irqrestore(&phba->hbalock, iflag);
+       return rspiocbp;
+}
+
+/**
+ * lpfc_sli_handle_slow_ring_event - Wrapper func for handling slow-path iocbs
  * @phba: Pointer to HBA context object.
  * @pring: Pointer to driver SLI ring object.
  * @mask: Host attention register mask for this ring.
  *
- * This function is called from the worker thread when there is a ring
- * event for non-fcp rings. The caller does not hold any lock .
- * The function processes each response iocb in the response ring until it
- * finds an iocb with LE bit set and chains all the iocbs upto the iocb with
- * LE bit set. The function will call lpfc_sli_process_sol_iocb function if the
- * response iocb indicates a completion of a command iocb. The function
- * will call lpfc_sli_process_unsol_iocb function if this is an unsolicited
- * iocb. The function frees the resources or calls the completion handler if
- * this iocb is an abort completion. The function returns 0 when the allocated
- * iocbs are not freed, otherwise returns 1.
+ * This routine wraps the actual slow_ring event process routine from the
+ * API jump table function pointer from the lpfc_hba struct.
  **/
-int
+void
 lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
                                struct lpfc_sli_ring *pring, uint32_t mask)
+{
+       phba->lpfc_sli_handle_slow_ring_event(phba, pring, mask);
+}
+
+/**
+ * lpfc_sli_handle_slow_ring_event_s3 - Handle SLI3 ring event for non-FCP rings
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @mask: Host attention register mask for this ring.
+ *
+ * This function is called from the worker thread when there is a ring event
+ * for non-fcp rings. The caller does not hold any lock. The function will
+ * remove each response iocb in the response ring and calls the handle
+ * response iocb routine (lpfc_sli_sp_handle_rspiocb) to process it.
+ **/
+static void
+lpfc_sli_handle_slow_ring_event_s3(struct lpfc_hba *phba,
+                                  struct lpfc_sli_ring *pring, uint32_t mask)
 {
        struct lpfc_pgp *pgp;
        IOCB_t *entry;
        IOCB_t *irsp = NULL;
        struct lpfc_iocbq *rspiocbp = NULL;
-       struct lpfc_iocbq *next_iocb;
-       struct lpfc_iocbq *cmdiocbp;
-       struct lpfc_iocbq *saveq;
-       uint8_t iocb_cmd_type;
-       lpfc_iocb_type type;
-       uint32_t status, free_saveq;
        uint32_t portRspPut, portRspMax;
-       int rc = 1;
        unsigned long iflag;
+       uint32_t status;
 
        pgp = &phba->port_gp[pring->ringno];
        spin_lock_irqsave(&phba->hbalock, iflag);
@@ -2128,7 +2916,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
                phba->work_hs = HS_FFER3;
                lpfc_handle_eratt(phba);
 
-               return 1;
+               return;
        }
 
        rmb();
@@ -2173,138 +2961,10 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
 
                writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx);
 
-               list_add_tail(&rspiocbp->list, &(pring->iocb_continueq));
-
-               pring->iocb_continueq_cnt++;
-               if (irsp->ulpLe) {
-                       /*
-                        * By default, the driver expects to free all resources
-                        * associated with this iocb completion.
-                        */
-                       free_saveq = 1;
-                       saveq = list_get_first(&pring->iocb_continueq,
-                                              struct lpfc_iocbq, list);
-                       irsp = &(saveq->iocb);
-                       list_del_init(&pring->iocb_continueq);
-                       pring->iocb_continueq_cnt = 0;
-
-                       pring->stats.iocb_rsp++;
-
-                       /*
-                        * If resource errors reported from HBA, reduce
-                        * queuedepths of the SCSI device.
-                        */
-                       if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
-                            (irsp->un.ulpWord[4] == IOERR_NO_RESOURCES)) {
-                               spin_unlock_irqrestore(&phba->hbalock, iflag);
-                               lpfc_rampdown_queue_depth(phba);
-                               spin_lock_irqsave(&phba->hbalock, iflag);
-                       }
-
-                       if (irsp->ulpStatus) {
-                               /* Rsp ring <ringno> error: IOCB */
-                               lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
-                                               "0328 Rsp Ring %d error: "
-                                               "IOCB Data: "
-                                               "x%x x%x x%x x%x "
-                                               "x%x x%x x%x x%x "
-                                               "x%x x%x x%x x%x "
-                                               "x%x x%x x%x x%x\n",
-                                               pring->ringno,
-                                               irsp->un.ulpWord[0],
-                                               irsp->un.ulpWord[1],
-                                               irsp->un.ulpWord[2],
-                                               irsp->un.ulpWord[3],
-                                               irsp->un.ulpWord[4],
-                                               irsp->un.ulpWord[5],
-                                               *(((uint32_t *) irsp) + 6),
-                                               *(((uint32_t *) irsp) + 7),
-                                               *(((uint32_t *) irsp) + 8),
-                                               *(((uint32_t *) irsp) + 9),
-                                               *(((uint32_t *) irsp) + 10),
-                                               *(((uint32_t *) irsp) + 11),
-                                               *(((uint32_t *) irsp) + 12),
-                                               *(((uint32_t *) irsp) + 13),
-                                               *(((uint32_t *) irsp) + 14),
-                                               *(((uint32_t *) irsp) + 15));
-                       }
-
-                       /*
-                        * Fetch the IOCB command type and call the correct
-                        * completion routine.  Solicited and Unsolicited
-                        * IOCBs on the ELS ring get freed back to the
-                        * lpfc_iocb_list by the discovery kernel thread.
-                        */
-                       iocb_cmd_type = irsp->ulpCommand & CMD_IOCB_MASK;
-                       type = lpfc_sli_iocb_cmd_type(iocb_cmd_type);
-                       if (type == LPFC_SOL_IOCB) {
-                               spin_unlock_irqrestore(&phba->hbalock, iflag);
-                               rc = lpfc_sli_process_sol_iocb(phba, pring,
-                                                              saveq);
-                               spin_lock_irqsave(&phba->hbalock, iflag);
-                       } else if (type == LPFC_UNSOL_IOCB) {
-                               spin_unlock_irqrestore(&phba->hbalock, iflag);
-                               rc = lpfc_sli_process_unsol_iocb(phba, pring,
-                                                                saveq);
-                               spin_lock_irqsave(&phba->hbalock, iflag);
-                               if (!rc)
-                                       free_saveq = 0;
-                       } else if (type == LPFC_ABORT_IOCB) {
-                               if ((irsp->ulpCommand != CMD_XRI_ABORTED_CX) &&
-                                   ((cmdiocbp =
-                                     lpfc_sli_iocbq_lookup(phba, pring,
-                                                           saveq)))) {
-                                       /* Call the specified completion
-                                          routine */
-                                       if (cmdiocbp->iocb_cmpl) {
-                                               spin_unlock_irqrestore(
-                                                      &phba->hbalock,
-                                                      iflag);
-                                               (cmdiocbp->iocb_cmpl) (phba,
-                                                            cmdiocbp, saveq);
-                                               spin_lock_irqsave(
-                                                         &phba->hbalock,
-                                                         iflag);
-                                       } else
-                                               __lpfc_sli_release_iocbq(phba,
-                                                                     cmdiocbp);
-                               }
-                       } else if (type == LPFC_UNKNOWN_IOCB) {
-                               if (irsp->ulpCommand == CMD_ADAPTER_MSG) {
-
-                                       char adaptermsg[LPFC_MAX_ADPTMSG];
-
-                                       memset(adaptermsg, 0,
-                                              LPFC_MAX_ADPTMSG);
-                                       memcpy(&adaptermsg[0], (uint8_t *) irsp,
-                                              MAX_MSG_DATA);
-                                       dev_warn(&((phba->pcidev)->dev),
-                                                "lpfc%d: %s\n",
-                                                phba->brd_no, adaptermsg);
-                               } else {
-                                       /* Unknown IOCB command */
-                                       lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
-                                                       "0335 Unknown IOCB "
-                                                       "command Data: x%x "
-                                                       "x%x x%x x%x\n",
-                                                       irsp->ulpCommand,
-                                                       irsp->ulpStatus,
-                                                       irsp->ulpIoTag,
-                                                       irsp->ulpContext);
-                               }
-                       }
-
-                       if (free_saveq) {
-                               list_for_each_entry_safe(rspiocbp, next_iocb,
-                                                        &saveq->list, list) {
-                                       list_del(&rspiocbp->list);
-                                       __lpfc_sli_release_iocbq(phba,
-                                                                rspiocbp);
-                               }
-                               __lpfc_sli_release_iocbq(phba, saveq);
-                       }
-                       rspiocbp = NULL;
-               }
+               spin_unlock_irqrestore(&phba->hbalock, iflag);
+               /* Handle the response IOCB */
+               rspiocbp = lpfc_sli_sp_handle_rspiocb(phba, pring, rspiocbp);
+               spin_lock_irqsave(&phba->hbalock, iflag);
 
                /*
                 * If the port response put pointer has not been updated, sync
@@ -2338,7 +2998,37 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
        }
 
        spin_unlock_irqrestore(&phba->hbalock, iflag);
-       return rc;
+       return;
+}
+
+/**
+ * lpfc_sli_handle_slow_ring_event_s4 - Handle SLI4 slow-path els events
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @mask: Host attention register mask for this ring.
+ *
+ * This function is called from the worker thread when there is a pending
+ * ELS response iocb on the driver internal slow-path response iocb worker
+ * queue. The caller does not hold any lock. The function will remove each
+ * response iocb from the response worker queue and calls the handle
+ * response iocb routine (lpfc_sli_sp_handle_rspiocb) to process it.
+ **/
+static void
+lpfc_sli_handle_slow_ring_event_s4(struct lpfc_hba *phba,
+                                  struct lpfc_sli_ring *pring, uint32_t mask)
+{
+       struct lpfc_iocbq *irspiocbq;
+       unsigned long iflag;
+
+       while (!list_empty(&phba->sli4_hba.sp_rspiocb_work_queue)) {
+               /* Get the response iocb from the head of work queue */
+               spin_lock_irqsave(&phba->hbalock, iflag);
+               list_remove_head(&phba->sli4_hba.sp_rspiocb_work_queue,
+                                irspiocbq, struct lpfc_iocbq, list);
+               spin_unlock_irqrestore(&phba->hbalock, iflag);
+               /* Process the response iocb */
+               lpfc_sli_sp_handle_rspiocb(phba, pring, irspiocbq);
+       }
 }
 
 /**
@@ -2420,7 +3110,7 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba)
 }
 
 /**
- * lpfc_sli_brdready - Check for host status bits
+ * lpfc_sli_brdready_s3 - Check for sli3 host ready status
  * @phba: Pointer to HBA context object.
  * @mask: Bit mask to be checked.
  *
@@ -2432,8 +3122,8 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba)
  * function returns 1 when HBA fail to restart otherwise returns
  * zero.
  **/
-int
-lpfc_sli_brdready(struct lpfc_hba *phba, uint32_t mask)
+static int
+lpfc_sli_brdready_s3(struct lpfc_hba *phba, uint32_t mask)
 {
        uint32_t status;
        int i = 0;
@@ -2477,6 +3167,56 @@ lpfc_sli_brdready(struct lpfc_hba *phba, uint32_t mask)
        return retval;
 }
 
+/**
+ * lpfc_sli_brdready_s4 - Check for sli4 host ready status
+ * @phba: Pointer to HBA context object.
+ * @mask: Bit mask to be checked.
+ *
+ * This function checks the host status register to check if HBA is
+ * ready. This function will wait in a loop for the HBA to be ready
+ * If the HBA is not ready , the function will will reset the HBA PCI
+ * function again. The function returns 1 when HBA fail to be ready
+ * otherwise returns zero.
+ **/
+static int
+lpfc_sli_brdready_s4(struct lpfc_hba *phba, uint32_t mask)
+{
+       uint32_t status;
+       int retval = 0;
+
+       /* Read the HBA Host Status Register */
+       status = lpfc_sli4_post_status_check(phba);
+
+       if (status) {
+               phba->pport->port_state = LPFC_VPORT_UNKNOWN;
+               lpfc_sli_brdrestart(phba);
+               status = lpfc_sli4_post_status_check(phba);
+       }
+
+       /* Check to see if any errors occurred during init */
+       if (status) {
+               phba->link_state = LPFC_HBA_ERROR;
+               retval = 1;
+       } else
+               phba->sli4_hba.intr_enable = 0;
+
+       return retval;
+}
+
+/**
+ * lpfc_sli_brdready - Wrapper func for checking the hba readyness
+ * @phba: Pointer to HBA context object.
+ * @mask: Bit mask to be checked.
+ *
+ * This routine wraps the actual SLI3 or SLI4 hba readyness check routine
+ * from the API jump table function pointer from the lpfc_hba struct.
+ **/
+int
+lpfc_sli_brdready(struct lpfc_hba *phba, uint32_t mask)
+{
+       return phba->lpfc_sli_brdready(phba, mask);
+}
+
 #define BARRIER_TEST_PATTERN (0xdeadbeef)
 
 /**
@@ -2532,7 +3272,7 @@ void lpfc_reset_barrier(struct lpfc_hba *phba)
                mdelay(1);
 
        if (readl(resp_buf + 1) != ~(BARRIER_TEST_PATTERN)) {
-               if (phba->sli.sli_flag & LPFC_SLI2_ACTIVE ||
+               if (phba->sli.sli_flag & LPFC_SLI_ACTIVE ||
                    phba->pport->stopped)
                        goto restore_hc;
                else
@@ -2613,7 +3353,9 @@ lpfc_sli_brdkill(struct lpfc_hba *phba)
                return 1;
        }
 
-       psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+       spin_lock_irq(&phba->hbalock);
+       psli->sli_flag &= ~LPFC_SLI_ACTIVE;
+       spin_unlock_irq(&phba->hbalock);
 
        mempool_free(pmb, phba->mbox_mem_pool);
 
@@ -2636,10 +3378,10 @@ lpfc_sli_brdkill(struct lpfc_hba *phba)
        }
        spin_lock_irq(&phba->hbalock);
        psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+       psli->mbox_active = NULL;
        phba->link_flag &= ~LS_IGNORE_ERATT;
        spin_unlock_irq(&phba->hbalock);
 
-       psli->mbox_active = NULL;
        lpfc_hba_down_post(phba);
        phba->link_state = LPFC_HBA_ERROR;
 
@@ -2647,7 +3389,7 @@ lpfc_sli_brdkill(struct lpfc_hba *phba)
 }
 
 /**
- * lpfc_sli_brdreset - Reset the HBA
+ * lpfc_sli_brdreset - Reset a sli-2 or sli-3 HBA
  * @phba: Pointer to HBA context object.
  *
  * This function resets the HBA by writing HC_INITFF to the control
@@ -2683,7 +3425,8 @@ lpfc_sli_brdreset(struct lpfc_hba *phba)
                              (cfg_value &
                               ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR)));
 
-       psli->sli_flag &= ~(LPFC_SLI2_ACTIVE | LPFC_PROCESS_LA);
+       psli->sli_flag &= ~(LPFC_SLI_ACTIVE | LPFC_PROCESS_LA);
+
        /* Now toggle INITFF bit in the Host Control Register */
        writel(HC_INITFF, phba->HCregaddr);
        mdelay(1);
@@ -2710,27 +3453,86 @@ lpfc_sli_brdreset(struct lpfc_hba *phba)
 }
 
 /**
- * lpfc_sli_brdrestart - Restart the HBA
+ * lpfc_sli4_brdreset - Reset a sli-4 HBA
  * @phba: Pointer to HBA context object.
  *
- * This function is called in the SLI initialization code path to
- * restart the HBA. The caller is not required to hold any lock.
- * This function writes MBX_RESTART mailbox command to the SLIM and
- * resets the HBA. At the end of the function, it calls lpfc_hba_down_post
- * function to free any pending commands. The function enables
- * POST only during the first initialization. The function returns zero.
- * The function does not guarantee completion of MBX_RESTART mailbox
- * command before the return of this function.
+ * This function resets a SLI4 HBA. This function disables PCI layer parity
+ * checking during resets the device. The caller is not required to hold
+ * any locks.
+ *
+ * This function returns 0 always.
  **/
 int
-lpfc_sli_brdrestart(struct lpfc_hba *phba)
+lpfc_sli4_brdreset(struct lpfc_hba *phba)
 {
-       MAILBOX_t *mb;
-       struct lpfc_sli *psli;
-       volatile uint32_t word0;
-       void __iomem *to_slim;
-
-       spin_lock_irq(&phba->hbalock);
+       struct lpfc_sli *psli = &phba->sli;
+       uint16_t cfg_value;
+       uint8_t qindx;
+
+       /* Reset HBA */
+       lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+                       "0295 Reset HBA Data: x%x x%x\n",
+                       phba->pport->port_state, psli->sli_flag);
+
+       /* perform board reset */
+       phba->fc_eventTag = 0;
+       phba->pport->fc_myDID = 0;
+       phba->pport->fc_prevDID = 0;
+
+       /* Turn off parity checking and serr during the physical reset */
+       pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value);
+       pci_write_config_word(phba->pcidev, PCI_COMMAND,
+                             (cfg_value &
+                             ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR)));
+
+       spin_lock_irq(&phba->hbalock);
+       psli->sli_flag &= ~(LPFC_PROCESS_LA);
+       phba->fcf.fcf_flag = 0;
+       /* Clean up the child queue list for the CQs */
+       list_del_init(&phba->sli4_hba.mbx_wq->list);
+       list_del_init(&phba->sli4_hba.els_wq->list);
+       list_del_init(&phba->sli4_hba.hdr_rq->list);
+       list_del_init(&phba->sli4_hba.dat_rq->list);
+       list_del_init(&phba->sli4_hba.mbx_cq->list);
+       list_del_init(&phba->sli4_hba.els_cq->list);
+       list_del_init(&phba->sli4_hba.rxq_cq->list);
+       for (qindx = 0; qindx < phba->cfg_fcp_wq_count; qindx++)
+               list_del_init(&phba->sli4_hba.fcp_wq[qindx]->list);
+       for (qindx = 0; qindx < phba->cfg_fcp_eq_count; qindx++)
+               list_del_init(&phba->sli4_hba.fcp_cq[qindx]->list);
+       spin_unlock_irq(&phba->hbalock);
+
+       /* Now physically reset the device */
+       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                       "0389 Performing PCI function reset!\n");
+       /* Perform FCoE PCI function reset */
+       lpfc_pci_function_reset(phba);
+
+       return 0;
+}
+
+/**
+ * lpfc_sli_brdrestart_s3 - Restart a sli-3 hba
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called in the SLI initialization code path to
+ * restart the HBA. The caller is not required to hold any lock.
+ * This function writes MBX_RESTART mailbox command to the SLIM and
+ * resets the HBA. At the end of the function, it calls lpfc_hba_down_post
+ * function to free any pending commands. The function enables
+ * POST only during the first initialization. The function returns zero.
+ * The function does not guarantee completion of MBX_RESTART mailbox
+ * command before the return of this function.
+ **/
+static int
+lpfc_sli_brdrestart_s3(struct lpfc_hba *phba)
+{
+       MAILBOX_t *mb;
+       struct lpfc_sli *psli;
+       volatile uint32_t word0;
+       void __iomem *to_slim;
+
+       spin_lock_irq(&phba->hbalock);
 
        psli = &phba->sli;
 
@@ -2762,7 +3564,7 @@ lpfc_sli_brdrestart(struct lpfc_hba *phba)
        lpfc_sli_brdreset(phba);
        phba->pport->stopped = 0;
        phba->link_state = LPFC_INIT_START;
-
+       phba->hba_flag = 0;
        spin_unlock_irq(&phba->hbalock);
 
        memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets));
@@ -2776,6 +3578,55 @@ lpfc_sli_brdrestart(struct lpfc_hba *phba)
        return 0;
 }
 
+/**
+ * lpfc_sli_brdrestart_s4 - Restart the sli-4 hba
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called in the SLI initialization code path to restart
+ * a SLI4 HBA. The caller is not required to hold any lock.
+ * At the end of the function, it calls lpfc_hba_down_post function to
+ * free any pending commands.
+ **/
+static int
+lpfc_sli_brdrestart_s4(struct lpfc_hba *phba)
+{
+       struct lpfc_sli *psli = &phba->sli;
+
+
+       /* Restart HBA */
+       lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+                       "0296 Restart HBA Data: x%x x%x\n",
+                       phba->pport->port_state, psli->sli_flag);
+
+       lpfc_sli4_brdreset(phba);
+
+       spin_lock_irq(&phba->hbalock);
+       phba->pport->stopped = 0;
+       phba->link_state = LPFC_INIT_START;
+       phba->hba_flag = 0;
+       spin_unlock_irq(&phba->hbalock);
+
+       memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets));
+       psli->stats_start = get_seconds();
+
+       lpfc_hba_down_post(phba);
+
+       return 0;
+}
+
+/**
+ * lpfc_sli_brdrestart - Wrapper func for restarting hba
+ * @phba: Pointer to HBA context object.
+ *
+ * This routine wraps the actual SLI3 or SLI4 hba restart routine from the
+ * API jump table function pointer from the lpfc_hba struct.
+**/
+int
+lpfc_sli_brdrestart(struct lpfc_hba *phba)
+{
+       return phba->lpfc_sli_brdrestart(phba);
+}
+
 /**
  * lpfc_sli_chipset_init - Wait for the restart of the HBA after a restart
  * @phba: Pointer to HBA context object.
@@ -2940,7 +3791,7 @@ lpfc_sli_hbq_setup(struct lpfc_hba *phba)
        if (!pmb)
                return -ENOMEM;
 
-       pmbox = &pmb->mb;
+       pmbox = &pmb->u.mb;
 
        /* Initialize the struct lpfc_sli_hbq structure for each hbq */
        phba->link_state = LPFC_INIT_MBX_CMDS;
@@ -2983,6 +3834,26 @@ lpfc_sli_hbq_setup(struct lpfc_hba *phba)
        return 0;
 }
 
+/**
+ * lpfc_sli4_rb_setup - Initialize and post RBs to HBA
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called during the SLI initialization to configure
+ * all the HBQs and post buffers to the HBQ. The caller is not
+ * required to hold any locks. This function will return zero if successful
+ * else it will return negative error code.
+ **/
+static int
+lpfc_sli4_rb_setup(struct lpfc_hba *phba)
+{
+       phba->hbq_in_use = 1;
+       phba->hbqs[0].entry_count = lpfc_hbq_defs[0]->entry_count;
+       phba->hbq_count = 1;
+       /* Initially populate or replenish the HBQs */
+       lpfc_sli_hbqbuf_init_hbqs(phba, 0);
+       return 0;
+}
+
 /**
  * lpfc_sli_config_port - Issue config port mailbox command
  * @phba: Pointer to HBA context object.
@@ -3047,33 +3918,43 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode)
                        lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                                "0442 Adapter failed to init, mbxCmd x%x "
                                "CONFIG_PORT, mbxStatus x%x Data: x%x\n",
-                               pmb->mb.mbxCommand, pmb->mb.mbxStatus, 0);
+                               pmb->u.mb.mbxCommand, pmb->u.mb.mbxStatus, 0);
                        spin_lock_irq(&phba->hbalock);
-                       phba->sli.sli_flag &= ~LPFC_SLI2_ACTIVE;
+                       phba->sli.sli_flag &= ~LPFC_SLI_ACTIVE;
                        spin_unlock_irq(&phba->hbalock);
                        rc = -ENXIO;
-               } else
+               } else {
+                       /* Allow asynchronous mailbox command to go through */
+                       spin_lock_irq(&phba->hbalock);
+                       phba->sli.sli_flag &= ~LPFC_SLI_ASYNC_MBX_BLK;
+                       spin_unlock_irq(&phba->hbalock);
                        done = 1;
+               }
        }
        if (!done) {
                rc = -EINVAL;
                goto do_prep_failed;
        }
-       if (pmb->mb.un.varCfgPort.sli_mode == 3) {
-               if (!pmb->mb.un.varCfgPort.cMA) {
+       if (pmb->u.mb.un.varCfgPort.sli_mode == 3) {
+               if (!pmb->u.mb.un.varCfgPort.cMA) {
                        rc = -ENXIO;
                        goto do_prep_failed;
                }
-               if (phba->max_vpi && pmb->mb.un.varCfgPort.gmv) {
+               if (phba->max_vpi && pmb->u.mb.un.varCfgPort.gmv) {
                        phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED;
-                       phba->max_vpi = pmb->mb.un.varCfgPort.max_vpi;
+                       phba->max_vpi = pmb->u.mb.un.varCfgPort.max_vpi;
+                       phba->max_vports = (phba->max_vpi > phba->max_vports) ?
+                               phba->max_vpi : phba->max_vports;
+
                } else
                        phba->max_vpi = 0;
-               if (pmb->mb.un.varCfgPort.gerbm)
+               if (pmb->u.mb.un.varCfgPort.gdss)
+                       phba->sli3_options |= LPFC_SLI3_DSS_ENABLED;
+               if (pmb->u.mb.un.varCfgPort.gerbm)
                        phba->sli3_options |= LPFC_SLI3_HBQ_ENABLED;
-               if (pmb->mb.un.varCfgPort.gcrp)
+               if (pmb->u.mb.un.varCfgPort.gcrp)
                        phba->sli3_options |= LPFC_SLI3_CRP_ENABLED;
-               if (pmb->mb.un.varCfgPort.ginb) {
+               if (pmb->u.mb.un.varCfgPort.ginb) {
                        phba->sli3_options |= LPFC_SLI3_INB_ENABLED;
                        phba->hbq_get = phba->mbox->us.s3_inb_pgp.hbq_get;
                        phba->port_gp = phba->mbox->us.s3_inb_pgp.port;
@@ -3089,7 +3970,7 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode)
                }
 
                if (phba->cfg_enable_bg) {
-                       if (pmb->mb.un.varCfgPort.gbg)
+                       if (pmb->u.mb.un.varCfgPort.gbg)
                                phba->sli3_options |= LPFC_SLI3_BG_ENABLED;
                        else
                                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -3184,8 +4065,9 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba)
                if (rc)
                        goto lpfc_sli_hba_setup_error;
        }
-
+       spin_lock_irq(&phba->hbalock);
        phba->sli.sli_flag |= LPFC_PROCESS_LA;
+       spin_unlock_irq(&phba->hbalock);
 
        rc = lpfc_config_port_post(phba);
        if (rc)
@@ -3200,6 +4082,488 @@ lpfc_sli_hba_setup_error:
        return rc;
 }
 
+/**
+ * lpfc_sli4_read_fcoe_params - Read fcoe params from conf region
+ * @phba: Pointer to HBA context object.
+ * @mboxq: mailbox pointer.
+ * This function issue a dump mailbox command to read config region
+ * 23 and parse the records in the region and populate driver
+ * data structure.
+ **/
+static int
+lpfc_sli4_read_fcoe_params(struct lpfc_hba *phba,
+               LPFC_MBOXQ_t *mboxq)
+{
+       struct lpfc_dmabuf *mp;
+       struct lpfc_mqe *mqe;
+       uint32_t data_length;
+       int rc;
+
+       /* Program the default value of vlan_id and fc_map */
+       phba->valid_vlan = 0;
+       phba->fc_map[0] = LPFC_FCOE_FCF_MAP0;
+       phba->fc_map[1] = LPFC_FCOE_FCF_MAP1;
+       phba->fc_map[2] = LPFC_FCOE_FCF_MAP2;
+
+       mqe = &mboxq->u.mqe;
+       if (lpfc_dump_fcoe_param(phba, mboxq))
+               return -ENOMEM;
+
+       mp = (struct lpfc_dmabuf *) mboxq->context1;
+       rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+
+       lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
+                       "(%d):2571 Mailbox cmd x%x Status x%x "
+                       "Data: x%x x%x x%x x%x x%x x%x x%x x%x x%x "
+                       "x%x x%x x%x x%x x%x x%x x%x x%x x%x "
+                       "CQ: x%x x%x x%x x%x\n",
+                       mboxq->vport ? mboxq->vport->vpi : 0,
+                       bf_get(lpfc_mqe_command, mqe),
+                       bf_get(lpfc_mqe_status, mqe),
+                       mqe->un.mb_words[0], mqe->un.mb_words[1],
+                       mqe->un.mb_words[2], mqe->un.mb_words[3],
+                       mqe->un.mb_words[4], mqe->un.mb_words[5],
+                       mqe->un.mb_words[6], mqe->un.mb_words[7],
+                       mqe->un.mb_words[8], mqe->un.mb_words[9],
+                       mqe->un.mb_words[10], mqe->un.mb_words[11],
+                       mqe->un.mb_words[12], mqe->un.mb_words[13],
+                       mqe->un.mb_words[14], mqe->un.mb_words[15],
+                       mqe->un.mb_words[16], mqe->un.mb_words[50],
+                       mboxq->mcqe.word0,
+                       mboxq->mcqe.mcqe_tag0,  mboxq->mcqe.mcqe_tag1,
+                       mboxq->mcqe.trailer);
+
+       if (rc) {
+               lpfc_mbuf_free(phba, mp->virt, mp->phys);
+               kfree(mp);
+               return -EIO;
+       }
+       data_length = mqe->un.mb_words[5];
+       if (data_length > DMP_FCOEPARAM_RGN_SIZE)
+               return -EIO;
+
+       lpfc_parse_fcoe_conf(phba, mp->virt, data_length);
+       lpfc_mbuf_free(phba, mp->virt, mp->phys);
+       kfree(mp);
+       return 0;
+}
+
+/**
+ * lpfc_sli4_read_rev - Issue READ_REV and collect vpd data
+ * @phba: pointer to lpfc hba data structure.
+ * @mboxq: pointer to the LPFC_MBOXQ_t structure.
+ * @vpd: pointer to the memory to hold resulting port vpd data.
+ * @vpd_size: On input, the number of bytes allocated to @vpd.
+ *           On output, the number of data bytes in @vpd.
+ *
+ * This routine executes a READ_REV SLI4 mailbox command.  In
+ * addition, this routine gets the port vpd data.
+ *
+ * Return codes
+ *     0 - sucessful
+ *     ENOMEM - could not allocated memory.
+ **/
+static int
+lpfc_sli4_read_rev(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
+                   uint8_t *vpd, uint32_t *vpd_size)
+{
+       int rc = 0;
+       uint32_t dma_size;
+       struct lpfc_dmabuf *dmabuf;
+       struct lpfc_mqe *mqe;
+
+       dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+       if (!dmabuf)
+               return -ENOMEM;
+
+       /*
+        * Get a DMA buffer for the vpd data resulting from the READ_REV
+        * mailbox command.
+        */
+       dma_size = *vpd_size;
+       dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev,
+                                         dma_size,
+                                         &dmabuf->phys,
+                                         GFP_KERNEL);
+       if (!dmabuf->virt) {
+               kfree(dmabuf);
+               return -ENOMEM;
+       }
+       memset(dmabuf->virt, 0, dma_size);
+
+       /*
+        * The SLI4 implementation of READ_REV conflicts at word1,
+        * bits 31:16 and SLI4 adds vpd functionality not present
+        * in SLI3.  This code corrects the conflicts.
+        */
+       lpfc_read_rev(phba, mboxq);
+       mqe = &mboxq->u.mqe;
+       mqe->un.read_rev.vpd_paddr_high = putPaddrHigh(dmabuf->phys);
+       mqe->un.read_rev.vpd_paddr_low = putPaddrLow(dmabuf->phys);
+       mqe->un.read_rev.word1 &= 0x0000FFFF;
+       bf_set(lpfc_mbx_rd_rev_vpd, &mqe->un.read_rev, 1);
+       bf_set(lpfc_mbx_rd_rev_avail_len, &mqe->un.read_rev, dma_size);
+
+       rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+       if (rc) {
+               dma_free_coherent(&phba->pcidev->dev, dma_size,
+                                 dmabuf->virt, dmabuf->phys);
+               return -EIO;
+       }
+
+       lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
+                       "(%d):0380 Mailbox cmd x%x Status x%x "
+                       "Data: x%x x%x x%x x%x x%x x%x x%x x%x x%x "
+                       "x%x x%x x%x x%x x%x x%x x%x x%x x%x "
+                       "CQ: x%x x%x x%x x%x\n",
+                       mboxq->vport ? mboxq->vport->vpi : 0,
+                       bf_get(lpfc_mqe_command, mqe),
+                       bf_get(lpfc_mqe_status, mqe),
+                       mqe->un.mb_words[0], mqe->un.mb_words[1],
+                       mqe->un.mb_words[2], mqe->un.mb_words[3],
+                       mqe->un.mb_words[4], mqe->un.mb_words[5],
+                       mqe->un.mb_words[6], mqe->un.mb_words[7],
+                       mqe->un.mb_words[8], mqe->un.mb_words[9],
+                       mqe->un.mb_words[10], mqe->un.mb_words[11],
+                       mqe->un.mb_words[12], mqe->un.mb_words[13],
+                       mqe->un.mb_words[14], mqe->un.mb_words[15],
+                       mqe->un.mb_words[16], mqe->un.mb_words[50],
+                       mboxq->mcqe.word0,
+                       mboxq->mcqe.mcqe_tag0,  mboxq->mcqe.mcqe_tag1,
+                       mboxq->mcqe.trailer);
+
+       /*
+        * The available vpd length cannot be bigger than the
+        * DMA buffer passed to the port.  Catch the less than
+        * case and update the caller's size.
+        */
+       if (mqe->un.read_rev.avail_vpd_len < *vpd_size)
+               *vpd_size = mqe->un.read_rev.avail_vpd_len;
+
+       lpfc_sli_pcimem_bcopy(dmabuf->virt, vpd, *vpd_size);
+       dma_free_coherent(&phba->pcidev->dev, dma_size,
+                         dmabuf->virt, dmabuf->phys);
+       kfree(dmabuf);
+       return 0;
+}
+
+/**
+ * lpfc_sli4_arm_cqeq_intr - Arm sli-4 device completion and event queues
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is called to explicitly arm the SLI4 device's completion and
+ * event queues
+ **/
+static void
+lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba)
+{
+       uint8_t fcp_eqidx;
+
+       lpfc_sli4_cq_release(phba->sli4_hba.mbx_cq, LPFC_QUEUE_REARM);
+       lpfc_sli4_cq_release(phba->sli4_hba.els_cq, LPFC_QUEUE_REARM);
+       lpfc_sli4_cq_release(phba->sli4_hba.rxq_cq, LPFC_QUEUE_REARM);
+       for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++)
+               lpfc_sli4_cq_release(phba->sli4_hba.fcp_cq[fcp_eqidx],
+                                    LPFC_QUEUE_REARM);
+       lpfc_sli4_eq_release(phba->sli4_hba.sp_eq, LPFC_QUEUE_REARM);
+       for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++)
+               lpfc_sli4_eq_release(phba->sli4_hba.fp_eq[fcp_eqidx],
+                                    LPFC_QUEUE_REARM);
+}
+
+/**
+ * lpfc_sli4_hba_setup - SLI4 device intialization PCI function
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is the main SLI4 device intialization PCI function. This
+ * function is called by the HBA intialization code, HBA reset code and
+ * HBA error attention handler code. Caller is not required to hold any
+ * locks.
+ **/
+int
+lpfc_sli4_hba_setup(struct lpfc_hba *phba)
+{
+       int rc;
+       LPFC_MBOXQ_t *mboxq;
+       struct lpfc_mqe *mqe;
+       uint8_t *vpd;
+       uint32_t vpd_size;
+       uint32_t ftr_rsp = 0;
+       struct Scsi_Host *shost = lpfc_shost_from_vport(phba->pport);
+       struct lpfc_vport *vport = phba->pport;
+       struct lpfc_dmabuf *mp;
+
+       /* Perform a PCI function reset to start from clean */
+       rc = lpfc_pci_function_reset(phba);
+       if (unlikely(rc))
+               return -ENODEV;
+
+       /* Check the HBA Host Status Register for readyness */
+       rc = lpfc_sli4_post_status_check(phba);
+       if (unlikely(rc))
+               return -ENODEV;
+       else {
+               spin_lock_irq(&phba->hbalock);
+               phba->sli.sli_flag |= LPFC_SLI_ACTIVE;
+               spin_unlock_irq(&phba->hbalock);
+       }
+
+       /*
+        * Allocate a single mailbox container for initializing the
+        * port.
+        */
+       mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mboxq)
+               return -ENOMEM;
+
+       /*
+        * Continue initialization with default values even if driver failed
+        * to read FCoE param config regions
+        */
+       if (lpfc_sli4_read_fcoe_params(phba, mboxq))
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT,
+                       "2570 Failed to read FCoE parameters \n");
+
+       /* Issue READ_REV to collect vpd and FW information. */
+       vpd_size = PAGE_SIZE;
+       vpd = kzalloc(vpd_size, GFP_KERNEL);
+       if (!vpd) {
+               rc = -ENOMEM;
+               goto out_free_mbox;
+       }
+
+       rc = lpfc_sli4_read_rev(phba, mboxq, vpd, &vpd_size);
+       if (unlikely(rc))
+               goto out_free_vpd;
+
+       mqe = &mboxq->u.mqe;
+       if ((bf_get(lpfc_mbx_rd_rev_sli_lvl,
+                   &mqe->un.read_rev) != LPFC_SLI_REV4) ||
+           (bf_get(lpfc_mbx_rd_rev_fcoe, &mqe->un.read_rev) == 0)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                       "0376 READ_REV Error. SLI Level %d "
+                       "FCoE enabled %d\n",
+                       bf_get(lpfc_mbx_rd_rev_sli_lvl, &mqe->un.read_rev),
+                       bf_get(lpfc_mbx_rd_rev_fcoe, &mqe->un.read_rev));
+               rc = -EIO;
+               goto out_free_vpd;
+       }
+       /* Single threaded at this point, no need for lock */
+       spin_lock_irq(&phba->hbalock);
+       phba->hba_flag |= HBA_FCOE_SUPPORT;
+       spin_unlock_irq(&phba->hbalock);
+       /*
+        * Evaluate the read rev and vpd data. Populate the driver
+        * state with the results. If this routine fails, the failure
+        * is not fatal as the driver will use generic values.
+        */
+       rc = lpfc_parse_vpd(phba, vpd, vpd_size);
+       if (unlikely(!rc)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                               "0377 Error %d parsing vpd. "
+                               "Using defaults.\n", rc);
+               rc = 0;
+       }
+
+       /* By now, we should determine the SLI revision, hard code for now */
+       phba->sli_rev = LPFC_SLI_REV4;
+
+       /*
+        * Discover the port's supported feature set and match it against the
+        * hosts requests.
+        */
+       lpfc_request_features(phba, mboxq);
+       rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+       if (unlikely(rc)) {
+               rc = -EIO;
+               goto out_free_vpd;
+       }
+
+       /*
+        * The port must support FCP initiator mode as this is the
+        * only mode running in the host.
+        */
+       if (!(bf_get(lpfc_mbx_rq_ftr_rsp_fcpi, &mqe->un.req_ftrs))) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
+                               "0378 No support for fcpi mode.\n");
+               ftr_rsp++;
+       }
+
+       /*
+        * If the port cannot support the host's requested features
+        * then turn off the global config parameters to disable the
+        * feature in the driver.  This is not a fatal error.
+        */
+       if ((phba->cfg_enable_bg) &&
+           !(bf_get(lpfc_mbx_rq_ftr_rsp_dif, &mqe->un.req_ftrs)))
+               ftr_rsp++;
+
+       if (phba->max_vpi && phba->cfg_enable_npiv &&
+           !(bf_get(lpfc_mbx_rq_ftr_rsp_npiv, &mqe->un.req_ftrs)))
+               ftr_rsp++;
+
+       if (ftr_rsp) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
+                               "0379 Feature Mismatch Data: x%08x %08x "
+                               "x%x x%x x%x\n", mqe->un.req_ftrs.word2,
+                               mqe->un.req_ftrs.word3, phba->cfg_enable_bg,
+                               phba->cfg_enable_npiv, phba->max_vpi);
+               if (!(bf_get(lpfc_mbx_rq_ftr_rsp_dif, &mqe->un.req_ftrs)))
+                       phba->cfg_enable_bg = 0;
+               if (!(bf_get(lpfc_mbx_rq_ftr_rsp_npiv, &mqe->un.req_ftrs)))
+                       phba->cfg_enable_npiv = 0;
+       }
+
+       /* These SLI3 features are assumed in SLI4 */
+       spin_lock_irq(&phba->hbalock);
+       phba->sli3_options |= (LPFC_SLI3_NPIV_ENABLED | LPFC_SLI3_HBQ_ENABLED);
+       spin_unlock_irq(&phba->hbalock);
+
+       /* Read the port's service parameters. */
+       lpfc_read_sparam(phba, mboxq, vport->vpi);
+       mboxq->vport = vport;
+       rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+       mp = (struct lpfc_dmabuf *) mboxq->context1;
+       if (rc == MBX_SUCCESS) {
+               memcpy(&vport->fc_sparam, mp->virt, sizeof(struct serv_parm));
+               rc = 0;
+       }
+
+       /*
+        * This memory was allocated by the lpfc_read_sparam routine. Release
+        * it to the mbuf pool.
+        */
+       lpfc_mbuf_free(phba, mp->virt, mp->phys);
+       kfree(mp);
+       mboxq->context1 = NULL;
+       if (unlikely(rc)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                               "0382 READ_SPARAM command failed "
+                               "status %d, mbxStatus x%x\n",
+                               rc, bf_get(lpfc_mqe_status, mqe));
+               phba->link_state = LPFC_HBA_ERROR;
+               rc = -EIO;
+               goto out_free_vpd;
+       }
+
+       if (phba->cfg_soft_wwnn)
+               u64_to_wwn(phba->cfg_soft_wwnn,
+                          vport->fc_sparam.nodeName.u.wwn);
+       if (phba->cfg_soft_wwpn)
+               u64_to_wwn(phba->cfg_soft_wwpn,
+                          vport->fc_sparam.portName.u.wwn);
+       memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName,
+              sizeof(struct lpfc_name));
+       memcpy(&vport->fc_portname, &vport->fc_sparam.portName,
+              sizeof(struct lpfc_name));
+
+       /* Update the fc_host data structures with new wwn. */
+       fc_host_node_name(shost) = wwn_to_u64(vport->fc_nodename.u.wwn);
+       fc_host_port_name(shost) = wwn_to_u64(vport->fc_portname.u.wwn);
+
+       /* Register SGL pool to the device using non-embedded mailbox command */
+       rc = lpfc_sli4_post_sgl_list(phba);
+       if (unlikely(rc)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                               "0582 Error %d during sgl post operation", rc);
+               rc = -ENODEV;
+               goto out_free_vpd;
+       }
+
+       /* Register SCSI SGL pool to the device */
+       rc = lpfc_sli4_repost_scsi_sgl_list(phba);
+       if (unlikely(rc)) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
+                               "0383 Error %d during scsi sgl post opeation",
+                               rc);
+               /* Some Scsi buffers were moved to the abort scsi list */
+               /* A pci function reset will repost them */
+               rc = -ENODEV;
+               goto out_free_vpd;
+       }
+
+       /* Post the rpi header region to the device. */
+       rc = lpfc_sli4_post_all_rpi_hdrs(phba);
+       if (unlikely(rc)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                               "0393 Error %d during rpi post operation\n",
+                               rc);
+               rc = -ENODEV;
+               goto out_free_vpd;
+       }
+       /* Temporary initialization of lpfc_fip_flag to non-fip */
+       bf_set(lpfc_fip_flag, &phba->sli4_hba.sli4_flags, 0);
+
+       /* Set up all the queues to the device */
+       rc = lpfc_sli4_queue_setup(phba);
+       if (unlikely(rc)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                               "0381 Error %d during queue setup.\n ", rc);
+               goto out_stop_timers;
+       }
+
+       /* Arm the CQs and then EQs on device */
+       lpfc_sli4_arm_cqeq_intr(phba);
+
+       /* Indicate device interrupt mode */
+       phba->sli4_hba.intr_enable = 1;
+
+       /* Allow asynchronous mailbox command to go through */
+       spin_lock_irq(&phba->hbalock);
+       phba->sli.sli_flag &= ~LPFC_SLI_ASYNC_MBX_BLK;
+       spin_unlock_irq(&phba->hbalock);
+
+       /* Post receive buffers to the device */
+       lpfc_sli4_rb_setup(phba);
+
+       /* Start the ELS watchdog timer */
+       /*
+        * The driver for SLI4 is not yet ready to process timeouts
+        * or interrupts.  Once it is, the comment bars can be removed.
+        */
+       /* mod_timer(&vport->els_tmofunc,
+        *           jiffies + HZ * (phba->fc_ratov*2)); */
+
+       /* Start heart beat timer */
+       mod_timer(&phba->hb_tmofunc,
+                 jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
+       phba->hb_outstanding = 0;
+       phba->last_completion_time = jiffies;
+
+       /* Start error attention (ERATT) polling timer */
+       mod_timer(&phba->eratt_poll, jiffies + HZ * LPFC_ERATT_POLL_INTERVAL);
+
+       /*
+        * The port is ready, set the host's link state to LINK_DOWN
+        * in preparation for link interrupts.
+        */
+       lpfc_init_link(phba, mboxq, phba->cfg_topology, phba->cfg_link_speed);
+       mboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+       lpfc_set_loopback_flag(phba);
+       /* Change driver state to LPFC_LINK_DOWN right before init link */
+       spin_lock_irq(&phba->hbalock);
+       phba->link_state = LPFC_LINK_DOWN;
+       spin_unlock_irq(&phba->hbalock);
+       rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
+       if (unlikely(rc != MBX_NOT_FINISHED)) {
+               kfree(vpd);
+               return 0;
+       } else
+               rc = -EIO;
+
+       /* Unset all the queues set up in this routine when error out */
+       if (rc)
+               lpfc_sli4_queue_unset(phba);
+
+out_stop_timers:
+       if (rc)
+               lpfc_stop_hba_timers(phba);
+out_free_vpd:
+       kfree(vpd);
+out_free_mbox:
+       mempool_free(mboxq, phba->mbox_mem_pool);
+       return rc;
+}
 
 /**
  * lpfc_mbox_timeout - Timeout call back function for mbox timer
@@ -3244,7 +4608,7 @@ void
 lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
 {
        LPFC_MBOXQ_t *pmbox = phba->sli.mbox_active;
-       MAILBOX_t *mb = &pmbox->mb;
+       MAILBOX_t *mb = &pmbox->u.mb;
        struct lpfc_sli *psli = &phba->sli;
        struct lpfc_sli_ring *pring;
 
@@ -3281,7 +4645,7 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
        spin_unlock_irq(&phba->pport->work_port_lock);
        spin_lock_irq(&phba->hbalock);
        phba->link_state = LPFC_LINK_UNKNOWN;
-       psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+       psli->sli_flag &= ~LPFC_SLI_ACTIVE;
        spin_unlock_irq(&phba->hbalock);
 
        pring = &psli->ring[psli->fcp_ring];
@@ -3289,32 +4653,20 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
 
        lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
                        "0345 Resetting board due to mailbox timeout\n");
-       /*
-        * lpfc_offline calls lpfc_sli_hba_down which will clean up
-        * on oustanding mailbox commands.
-        */
-       /* If resets are disabled then set error state and return. */
-       if (!phba->cfg_enable_hba_reset) {
-               phba->link_state = LPFC_HBA_ERROR;
-               return;
-       }
-       lpfc_offline_prep(phba);
-       lpfc_offline(phba);
-       lpfc_sli_brdrestart(phba);
-       lpfc_online(phba);
-       lpfc_unblock_mgmt_io(phba);
-       return;
+
+       /* Reset the HBA device */
+       lpfc_reset_hba(phba);
 }
 
 /**
- * lpfc_sli_issue_mbox - Issue a mailbox command to firmware
+ * lpfc_sli_issue_mbox_s3 - Issue an SLI3 mailbox command to firmware
  * @phba: Pointer to HBA context object.
  * @pmbox: Pointer to mailbox object.
  * @flag: Flag indicating how the mailbox need to be processed.
  *
  * This function is called by discovery code and HBA management code
- * to submit a mailbox command to firmware. This function gets the
- * hbalock to protect the data structures.
+ * to submit a mailbox command to firmware with SLI-3 interface spec. This
+ * function gets the hbalock to protect the data structures.
  * The mailbox command can be submitted in polling mode, in which case
  * this function will wait in a polling loop for the completion of the
  * mailbox.
@@ -3332,8 +4684,9 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
  * return codes the caller owns the mailbox command after the return of
  * the function.
  **/
-int
-lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
+static int
+lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox,
+                      uint32_t flag)
 {
        MAILBOX_t *mb;
        struct lpfc_sli *psli = &phba->sli;
@@ -3349,8 +4702,12 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
        spin_lock_irqsave(&phba->hbalock, drvr_flag);
        if (!pmbox) {
                /* processing mbox queue from intr_handler */
-               processing_queue = 1;
-               phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+               if (unlikely(psli->sli_flag & LPFC_SLI_ASYNC_MBX_BLK)) {
+                       spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
+                       return MBX_SUCCESS;
+               }
+               processing_queue = 1;
+               phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
                pmbox = lpfc_mbox_get(phba);
                if (!pmbox) {
                        spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
@@ -3365,7 +4722,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
                        lpfc_printf_log(phba, KERN_ERR,
                                        LOG_MBOX | LOG_VPORT,
                                        "1806 Mbox x%x failed. No vport\n",
-                                       pmbox->mb.mbxCommand);
+                                       pmbox->u.mb.mbxCommand);
                        dump_stack();
                        goto out_not_finished;
                }
@@ -3385,21 +4742,29 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
 
        psli = &phba->sli;
 
-       mb = &pmbox->mb;
+       mb = &pmbox->u.mb;
        status = MBX_SUCCESS;
 
        if (phba->link_state == LPFC_HBA_ERROR) {
                spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
 
                /* Mbox command <mbxCommand> cannot issue */
-               LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag);
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                               "(%d):0311 Mailbox command x%x cannot "
+                               "issue Data: x%x x%x\n",
+                               pmbox->vport ? pmbox->vport->vpi : 0,
+                               pmbox->u.mb.mbxCommand, psli->sli_flag, flag);
                goto out_not_finished;
        }
 
        if (mb->mbxCommand != MBX_KILL_BOARD && flag & MBX_NOWAIT &&
            !(readl(phba->HCregaddr) & HC_MBINT_ENA)) {
                spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
-               LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag);
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                               "(%d):2528 Mailbox command x%x cannot "
+                               "issue Data: x%x x%x\n",
+                               pmbox->vport ? pmbox->vport->vpi : 0,
+                               pmbox->u.mb.mbxCommand, psli->sli_flag, flag);
                goto out_not_finished;
        }
 
@@ -3413,14 +4778,24 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
                        spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
 
                        /* Mbox command <mbxCommand> cannot issue */
-                       LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag);
+                       lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                                       "(%d):2529 Mailbox command x%x "
+                                       "cannot issue Data: x%x x%x\n",
+                                       pmbox->vport ? pmbox->vport->vpi : 0,
+                                       pmbox->u.mb.mbxCommand,
+                                       psli->sli_flag, flag);
                        goto out_not_finished;
                }
 
-               if (!(psli->sli_flag & LPFC_SLI2_ACTIVE)) {
+               if (!(psli->sli_flag & LPFC_SLI_ACTIVE)) {
                        spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
                        /* Mbox command <mbxCommand> cannot issue */
-                       LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag);
+                       lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                                       "(%d):2530 Mailbox command x%x "
+                                       "cannot issue Data: x%x x%x\n",
+                                       pmbox->vport ? pmbox->vport->vpi : 0,
+                                       pmbox->u.mb.mbxCommand,
+                                       psli->sli_flag, flag);
                        goto out_not_finished;
                }
 
@@ -3462,12 +4837,17 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
 
        /* If we are not polling, we MUST be in SLI2 mode */
        if (flag != MBX_POLL) {
-               if (!(psli->sli_flag & LPFC_SLI2_ACTIVE) &&
+               if (!(psli->sli_flag & LPFC_SLI_ACTIVE) &&
                    (mb->mbxCommand != MBX_KILL_BOARD)) {
                        psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
                        spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
                        /* Mbox command <mbxCommand> cannot issue */
-                       LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag);
+                       lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                                       "(%d):2531 Mailbox command x%x "
+                                       "cannot issue Data: x%x x%x\n",
+                                       pmbox->vport ? pmbox->vport->vpi : 0,
+                                       pmbox->u.mb.mbxCommand,
+                                       psli->sli_flag, flag);
                        goto out_not_finished;
                }
                /* timeout active mbox command */
@@ -3506,7 +4886,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
        /* next set own bit for the adapter and copy over command word */
        mb->mbxOwner = OWN_CHIP;
 
-       if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
+       if (psli->sli_flag & LPFC_SLI_ACTIVE) {
                /* First copy command data to host SLIM area */
                lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE);
        } else {
@@ -3529,7 +4909,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
 
                if (mb->mbxCommand == MBX_CONFIG_PORT) {
                        /* switch over to host mailbox */
-                       psli->sli_flag |= LPFC_SLI2_ACTIVE;
+                       psli->sli_flag |= LPFC_SLI_ACTIVE;
                }
        }
 
@@ -3552,7 +4932,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
                writel(CA_MBATT, phba->CAregaddr);
                readl(phba->CAregaddr); /* flush */
 
-               if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
+               if (psli->sli_flag & LPFC_SLI_ACTIVE) {
                        /* First read mbox status word */
                        word0 = *((uint32_t *)phba->mbox);
                        word0 = le32_to_cpu(word0);
@@ -3591,7 +4971,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
                                spin_lock_irqsave(&phba->hbalock, drvr_flag);
                        }
 
-                       if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
+                       if (psli->sli_flag & LPFC_SLI_ACTIVE) {
                                /* First copy command data */
                                word0 = *((uint32_t *)phba->mbox);
                                word0 = le32_to_cpu(word0);
@@ -3604,7 +4984,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
                                        if (((slimword0 & OWN_CHIP) != OWN_CHIP)
                                            && slimmb->mbxStatus) {
                                                psli->sli_flag &=
-                                                   ~LPFC_SLI2_ACTIVE;
+                                                   ~LPFC_SLI_ACTIVE;
                                                word0 = slimword0;
                                        }
                                }
@@ -3616,7 +4996,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
                        ha_copy = readl(phba->HAregaddr);
                }
 
-               if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
+               if (psli->sli_flag & LPFC_SLI_ACTIVE) {
                        /* copy results back to user */
                        lpfc_sli_pcimem_bcopy(phba->mbox, mb, MAILBOX_CMD_SIZE);
                } else {
@@ -3643,12 +5023,419 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
 
 out_not_finished:
        if (processing_queue) {
-               pmbox->mb.mbxStatus = MBX_NOT_FINISHED;
+               pmbox->u.mb.mbxStatus = MBX_NOT_FINISHED;
                lpfc_mbox_cmpl_put(phba, pmbox);
        }
        return MBX_NOT_FINISHED;
 }
 
+/**
+ * lpfc_sli4_post_sync_mbox - Post an SLI4 mailbox to the bootstrap mailbox
+ * @phba: Pointer to HBA context object.
+ * @mboxq: Pointer to mailbox object.
+ *
+ * The function posts a mailbox to the port.  The mailbox is expected
+ * to be comletely filled in and ready for the port to operate on it.
+ * This routine executes a synchronous completion operation on the
+ * mailbox by polling for its completion.
+ *
+ * The caller must not be holding any locks when calling this routine.
+ *
+ * Returns:
+ *     MBX_SUCCESS - mailbox posted successfully
+ *     Any of the MBX error values.
+ **/
+static int
+lpfc_sli4_post_sync_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+{
+       int rc = MBX_SUCCESS;
+       unsigned long iflag;
+       uint32_t db_ready;
+       uint32_t mcqe_status;
+       uint32_t mbx_cmnd;
+       unsigned long timeout;
+       struct lpfc_sli *psli = &phba->sli;
+       struct lpfc_mqe *mb = &mboxq->u.mqe;
+       struct lpfc_bmbx_create *mbox_rgn;
+       struct dma_address *dma_address;
+       struct lpfc_register bmbx_reg;
+
+       /*
+        * Only one mailbox can be active to the bootstrap mailbox region
+        * at a time and there is no queueing provided.
+        */
+       spin_lock_irqsave(&phba->hbalock, iflag);
+       if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) {
+               spin_unlock_irqrestore(&phba->hbalock, iflag);
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                               "(%d):2532 Mailbox command x%x (x%x) "
+                               "cannot issue Data: x%x x%x\n",
+                               mboxq->vport ? mboxq->vport->vpi : 0,
+                               mboxq->u.mb.mbxCommand,
+                               lpfc_sli4_mbox_opcode_get(phba, mboxq),
+                               psli->sli_flag, MBX_POLL);
+               return MBXERR_ERROR;
+       }
+       /* The server grabs the token and owns it until release */
+       psli->sli_flag |= LPFC_SLI_MBOX_ACTIVE;
+       phba->sli.mbox_active = mboxq;
+       spin_unlock_irqrestore(&phba->hbalock, iflag);
+
+       /*
+        * Initialize the bootstrap memory region to avoid stale data areas
+        * in the mailbox post.  Then copy the caller's mailbox contents to
+        * the bmbx mailbox region.
+        */
+       mbx_cmnd = bf_get(lpfc_mqe_command, mb);
+       memset(phba->sli4_hba.bmbx.avirt, 0, sizeof(struct lpfc_bmbx_create));
+       lpfc_sli_pcimem_bcopy(mb, phba->sli4_hba.bmbx.avirt,
+                             sizeof(struct lpfc_mqe));
+
+       /* Post the high mailbox dma address to the port and wait for ready. */
+       dma_address = &phba->sli4_hba.bmbx.dma_address;
+       writel(dma_address->addr_hi, phba->sli4_hba.BMBXregaddr);
+
+       timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, mbx_cmnd)
+                                  * 1000) + jiffies;
+       do {
+               bmbx_reg.word0 = readl(phba->sli4_hba.BMBXregaddr);
+               db_ready = bf_get(lpfc_bmbx_rdy, &bmbx_reg);
+               if (!db_ready)
+                       msleep(2);
+
+               if (time_after(jiffies, timeout)) {
+                       rc = MBXERR_ERROR;
+                       goto exit;
+               }
+       } while (!db_ready);
+
+       /* Post the low mailbox dma address to the port. */
+       writel(dma_address->addr_lo, phba->sli4_hba.BMBXregaddr);
+       timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, mbx_cmnd)
+                                  * 1000) + jiffies;
+       do {
+               bmbx_reg.word0 = readl(phba->sli4_hba.BMBXregaddr);
+               db_ready = bf_get(lpfc_bmbx_rdy, &bmbx_reg);
+               if (!db_ready)
+                       msleep(2);
+
+               if (time_after(jiffies, timeout)) {
+                       rc = MBXERR_ERROR;
+                       goto exit;
+               }
+       } while (!db_ready);
+
+       /*
+        * Read the CQ to ensure the mailbox has completed.
+        * If so, update the mailbox status so that the upper layers
+        * can complete the request normally.
+        */
+       lpfc_sli_pcimem_bcopy(phba->sli4_hba.bmbx.avirt, mb,
+                             sizeof(struct lpfc_mqe));
+       mbox_rgn = (struct lpfc_bmbx_create *) phba->sli4_hba.bmbx.avirt;
+       lpfc_sli_pcimem_bcopy(&mbox_rgn->mcqe, &mboxq->mcqe,
+                             sizeof(struct lpfc_mcqe));
+       mcqe_status = bf_get(lpfc_mcqe_status, &mbox_rgn->mcqe);
+
+       /* Prefix the mailbox status with range x4000 to note SLI4 status. */
+       if (mcqe_status != MB_CQE_STATUS_SUCCESS) {
+               bf_set(lpfc_mqe_status, mb, LPFC_MBX_ERROR_RANGE | mcqe_status);
+               rc = MBXERR_ERROR;
+       }
+
+       lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
+                       "(%d):0356 Mailbox cmd x%x (x%x) Status x%x "
+                       "Data: x%x x%x x%x x%x x%x x%x x%x x%x x%x x%x x%x"
+                       " x%x x%x CQ: x%x x%x x%x x%x\n",
+                       mboxq->vport ? mboxq->vport->vpi : 0,
+                       mbx_cmnd, lpfc_sli4_mbox_opcode_get(phba, mboxq),
+                       bf_get(lpfc_mqe_status, mb),
+                       mb->un.mb_words[0], mb->un.mb_words[1],
+                       mb->un.mb_words[2], mb->un.mb_words[3],
+                       mb->un.mb_words[4], mb->un.mb_words[5],
+                       mb->un.mb_words[6], mb->un.mb_words[7],
+                       mb->un.mb_words[8], mb->un.mb_words[9],
+                       mb->un.mb_words[10], mb->un.mb_words[11],
+                       mb->un.mb_words[12], mboxq->mcqe.word0,
+                       mboxq->mcqe.mcqe_tag0,  mboxq->mcqe.mcqe_tag1,
+                       mboxq->mcqe.trailer);
+exit:
+       /* We are holding the token, no needed for lock when release */
+       spin_lock_irqsave(&phba->hbalock, iflag);
+       psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+       phba->sli.mbox_active = NULL;
+       spin_unlock_irqrestore(&phba->hbalock, iflag);
+       return rc;
+}
+
+/**
+ * lpfc_sli_issue_mbox_s4 - Issue an SLI4 mailbox command to firmware
+ * @phba: Pointer to HBA context object.
+ * @pmbox: Pointer to mailbox object.
+ * @flag: Flag indicating how the mailbox need to be processed.
+ *
+ * This function is called by discovery code and HBA management code to submit
+ * a mailbox command to firmware with SLI-4 interface spec.
+ *
+ * Return codes the caller owns the mailbox command after the return of the
+ * function.
+ **/
+static int
+lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
+                      uint32_t flag)
+{
+       struct lpfc_sli *psli = &phba->sli;
+       unsigned long iflags;
+       int rc;
+
+       /* Detect polling mode and jump to a handler */
+       if (!phba->sli4_hba.intr_enable) {
+               if (flag == MBX_POLL)
+                       rc = lpfc_sli4_post_sync_mbox(phba, mboxq);
+               else
+                       rc = -EIO;
+               if (rc != MBX_SUCCESS)
+                       lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                                       "(%d):2541 Mailbox command x%x "
+                                       "(x%x) cannot issue Data: x%x x%x\n",
+                                       mboxq->vport ? mboxq->vport->vpi : 0,
+                                       mboxq->u.mb.mbxCommand,
+                                       lpfc_sli4_mbox_opcode_get(phba, mboxq),
+                                       psli->sli_flag, flag);
+               return rc;
+       } else if (flag == MBX_POLL) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                               "(%d):2542 Mailbox command x%x (x%x) "
+                               "cannot issue Data: x%x x%x\n",
+                               mboxq->vport ? mboxq->vport->vpi : 0,
+                               mboxq->u.mb.mbxCommand,
+                               lpfc_sli4_mbox_opcode_get(phba, mboxq),
+                               psli->sli_flag, flag);
+               return -EIO;
+       }
+
+       /* Now, interrupt mode asynchrous mailbox command */
+       rc = lpfc_mbox_cmd_check(phba, mboxq);
+       if (rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                               "(%d):2543 Mailbox command x%x (x%x) "
+                               "cannot issue Data: x%x x%x\n",
+                               mboxq->vport ? mboxq->vport->vpi : 0,
+                               mboxq->u.mb.mbxCommand,
+                               lpfc_sli4_mbox_opcode_get(phba, mboxq),
+                               psli->sli_flag, flag);
+               goto out_not_finished;
+       }
+       rc = lpfc_mbox_dev_check(phba);
+       if (unlikely(rc)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                               "(%d):2544 Mailbox command x%x (x%x) "
+                               "cannot issue Data: x%x x%x\n",
+                               mboxq->vport ? mboxq->vport->vpi : 0,
+                               mboxq->u.mb.mbxCommand,
+                               lpfc_sli4_mbox_opcode_get(phba, mboxq),
+                               psli->sli_flag, flag);
+               goto out_not_finished;
+       }
+
+       /* Put the mailbox command to the driver internal FIFO */
+       psli->slistat.mbox_busy++;
+       spin_lock_irqsave(&phba->hbalock, iflags);
+       lpfc_mbox_put(phba, mboxq);
+       spin_unlock_irqrestore(&phba->hbalock, iflags);
+       lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
+                       "(%d):0354 Mbox cmd issue - Enqueue Data: "
+                       "x%x (x%x) x%x x%x x%x\n",
+                       mboxq->vport ? mboxq->vport->vpi : 0xffffff,
+                       bf_get(lpfc_mqe_command, &mboxq->u.mqe),
+                       lpfc_sli4_mbox_opcode_get(phba, mboxq),
+                       phba->pport->port_state,
+                       psli->sli_flag, MBX_NOWAIT);
+       /* Wake up worker thread to transport mailbox command from head */
+       lpfc_worker_wake_up(phba);
+
+       return MBX_BUSY;
+
+out_not_finished:
+       return MBX_NOT_FINISHED;
+}
+
+/**
+ * lpfc_sli4_post_async_mbox - Post an SLI4 mailbox command to device
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called by worker thread to send a mailbox command to
+ * SLI4 HBA firmware.
+ *
+ **/
+int
+lpfc_sli4_post_async_mbox(struct lpfc_hba *phba)
+{
+       struct lpfc_sli *psli = &phba->sli;
+       LPFC_MBOXQ_t *mboxq;
+       int rc = MBX_SUCCESS;
+       unsigned long iflags;
+       struct lpfc_mqe *mqe;
+       uint32_t mbx_cmnd;
+
+       /* Check interrupt mode before post async mailbox command */
+       if (unlikely(!phba->sli4_hba.intr_enable))
+               return MBX_NOT_FINISHED;
+
+       /* Check for mailbox command service token */
+       spin_lock_irqsave(&phba->hbalock, iflags);
+       if (unlikely(psli->sli_flag & LPFC_SLI_ASYNC_MBX_BLK)) {
+               spin_unlock_irqrestore(&phba->hbalock, iflags);
+               return MBX_NOT_FINISHED;
+       }
+       if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) {
+               spin_unlock_irqrestore(&phba->hbalock, iflags);
+               return MBX_NOT_FINISHED;
+       }
+       if (unlikely(phba->sli.mbox_active)) {
+               spin_unlock_irqrestore(&phba->hbalock, iflags);
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                               "0384 There is pending active mailbox cmd\n");
+               return MBX_NOT_FINISHED;
+       }
+       /* Take the mailbox command service token */
+       psli->sli_flag |= LPFC_SLI_MBOX_ACTIVE;
+
+       /* Get the next mailbox command from head of queue */
+       mboxq = lpfc_mbox_get(phba);
+
+       /* If no more mailbox command waiting for post, we're done */
+       if (!mboxq) {
+               psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+               spin_unlock_irqrestore(&phba->hbalock, iflags);
+               return MBX_SUCCESS;
+       }
+       phba->sli.mbox_active = mboxq;
+       spin_unlock_irqrestore(&phba->hbalock, iflags);
+
+       /* Check device readiness for posting mailbox command */
+       rc = lpfc_mbox_dev_check(phba);
+       if (unlikely(rc))
+               /* Driver clean routine will clean up pending mailbox */
+               goto out_not_finished;
+
+       /* Prepare the mbox command to be posted */
+       mqe = &mboxq->u.mqe;
+       mbx_cmnd = bf_get(lpfc_mqe_command, mqe);
+
+       /* Start timer for the mbox_tmo and log some mailbox post messages */
+       mod_timer(&psli->mbox_tmo, (jiffies +
+                 (HZ * lpfc_mbox_tmo_val(phba, mbx_cmnd))));
+
+       lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
+                       "(%d):0355 Mailbox cmd x%x (x%x) issue Data: "
+                       "x%x x%x\n",
+                       mboxq->vport ? mboxq->vport->vpi : 0, mbx_cmnd,
+                       lpfc_sli4_mbox_opcode_get(phba, mboxq),
+                       phba->pport->port_state, psli->sli_flag);
+
+       if (mbx_cmnd != MBX_HEARTBEAT) {
+               if (mboxq->vport) {
+                       lpfc_debugfs_disc_trc(mboxq->vport,
+                               LPFC_DISC_TRC_MBOX_VPORT,
+                               "MBOX Send vport: cmd:x%x mb:x%x x%x",
+                               mbx_cmnd, mqe->un.mb_words[0],
+                               mqe->un.mb_words[1]);
+               } else {
+                       lpfc_debugfs_disc_trc(phba->pport,
+                               LPFC_DISC_TRC_MBOX,
+                               "MBOX Send: cmd:x%x mb:x%x x%x",
+                               mbx_cmnd, mqe->un.mb_words[0],
+                               mqe->un.mb_words[1]);
+               }
+       }
+       psli->slistat.mbox_cmd++;
+
+       /* Post the mailbox command to the port */
+       rc = lpfc_sli4_mq_put(phba->sli4_hba.mbx_wq, mqe);
+       if (rc != MBX_SUCCESS) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                               "(%d):2533 Mailbox command x%x (x%x) "
+                               "cannot issue Data: x%x x%x\n",
+                               mboxq->vport ? mboxq->vport->vpi : 0,
+                               mboxq->u.mb.mbxCommand,
+                               lpfc_sli4_mbox_opcode_get(phba, mboxq),
+                               psli->sli_flag, MBX_NOWAIT);
+               goto out_not_finished;
+       }
+
+       return rc;
+
+out_not_finished:
+       spin_lock_irqsave(&phba->hbalock, iflags);
+       mboxq->u.mb.mbxStatus = MBX_NOT_FINISHED;
+       __lpfc_mbox_cmpl_put(phba, mboxq);
+       /* Release the token */
+       psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+       phba->sli.mbox_active = NULL;
+       spin_unlock_irqrestore(&phba->hbalock, iflags);
+
+       return MBX_NOT_FINISHED;
+}
+
+/**
+ * lpfc_sli_issue_mbox - Wrapper func for issuing mailbox command
+ * @phba: Pointer to HBA context object.
+ * @pmbox: Pointer to mailbox object.
+ * @flag: Flag indicating how the mailbox need to be processed.
+ *
+ * This routine wraps the actual SLI3 or SLI4 mailbox issuing routine from
+ * the API jump table function pointer from the lpfc_hba struct.
+ *
+ * Return codes the caller owns the mailbox command after the return of the
+ * function.
+ **/
+int
+lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
+{
+       return phba->lpfc_sli_issue_mbox(phba, pmbox, flag);
+}
+
+/**
+ * lpfc_mbox_api_table_setup - Set up mbox api fucntion jump table
+ * @phba: The hba struct for which this call is being executed.
+ * @dev_grp: The HBA PCI-Device group number.
+ *
+ * This routine sets up the mbox interface API function jump table in @phba
+ * struct.
+ * Returns: 0 - success, -ENODEV - failure.
+ **/
+int
+lpfc_mbox_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
+{
+
+       switch (dev_grp) {
+       case LPFC_PCI_DEV_LP:
+               phba->lpfc_sli_issue_mbox = lpfc_sli_issue_mbox_s3;
+               phba->lpfc_sli_handle_slow_ring_event =
+                               lpfc_sli_handle_slow_ring_event_s3;
+               phba->lpfc_sli_hbq_to_firmware = lpfc_sli_hbq_to_firmware_s3;
+               phba->lpfc_sli_brdrestart = lpfc_sli_brdrestart_s3;
+               phba->lpfc_sli_brdready = lpfc_sli_brdready_s3;
+               break;
+       case LPFC_PCI_DEV_OC:
+               phba->lpfc_sli_issue_mbox = lpfc_sli_issue_mbox_s4;
+               phba->lpfc_sli_handle_slow_ring_event =
+                               lpfc_sli_handle_slow_ring_event_s4;
+               phba->lpfc_sli_hbq_to_firmware = lpfc_sli_hbq_to_firmware_s4;
+               phba->lpfc_sli_brdrestart = lpfc_sli_brdrestart_s4;
+               phba->lpfc_sli_brdready = lpfc_sli_brdready_s4;
+               break;
+       default:
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1420 Invalid HBA PCI-device group: 0x%x\n",
+                               dev_grp);
+               return -ENODEV;
+               break;
+       }
+       return 0;
+}
+
 /**
  * __lpfc_sli_ringtx_put - Add an iocb to the txq
  * @phba: Pointer to HBA context object.
@@ -3701,35 +5488,34 @@ lpfc_sli_next_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 }
 
 /**
- * __lpfc_sli_issue_iocb - Lockless version of lpfc_sli_issue_iocb
+ * __lpfc_sli_issue_iocb_s3 - SLI3 device lockless ver of lpfc_sli_issue_iocb
  * @phba: Pointer to HBA context object.
- * @pring: Pointer to driver SLI ring object.
+ * @ring_number: SLI ring number to issue iocb on.
  * @piocb: Pointer to command iocb.
  * @flag: Flag indicating if this command can be put into txq.
  *
- * __lpfc_sli_issue_iocb is used by other functions in the driver
- * to issue an iocb command to the HBA. If the PCI slot is recovering
- * from error state or if HBA is resetting or if LPFC_STOP_IOCB_EVENT
- * flag is turned on, the function returns IOCB_ERROR.
- * When the link is down, this function allows only iocbs for
- * posting buffers.
- * This function finds next available slot in the command ring and
- * posts the command to the available slot and writes the port
- * attention register to request HBA start processing new iocb.
- * If there is no slot available in the ring and
- * flag & SLI_IOCB_RET_IOCB is set, the new iocb is added to the
- * txq, otherwise the function returns IOCB_BUSY.
- *
- * This function is called with hbalock held.
- * The function will return success after it successfully submit the
- * iocb to firmware or after adding to the txq.
+ * __lpfc_sli_issue_iocb_s3 is used by other functions in the driver to issue
+ * an iocb command to an HBA with SLI-3 interface spec. If the PCI slot is
+ * recovering from error state, if HBA is resetting or if LPFC_STOP_IOCB_EVENT
+ * flag is turned on, the function returns IOCB_ERROR. When the link is down,
+ * this function allows only iocbs for posting buffers. This function finds
+ * next available slot in the command ring and posts the command to the
+ * available slot and writes the port attention register to request HBA start
+ * processing new iocb. If there is no slot available in the ring and
+ * flag & SLI_IOCB_RET_IOCB is set, the new iocb is added to the txq, otherwise
+ * the function returns IOCB_BUSY.
+ *
+ * This function is called with hbalock held. The function will return success
+ * after it successfully submit the iocb to firmware or after adding to the
+ * txq.
  **/
 static int
-__lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+__lpfc_sli_issue_iocb_s3(struct lpfc_hba *phba, uint32_t ring_number,
                    struct lpfc_iocbq *piocb, uint32_t flag)
 {
        struct lpfc_iocbq *nextiocb;
        IOCB_t *iocb;
+       struct lpfc_sli_ring *pring = &phba->sli.ring[ring_number];
 
        if (piocb->iocb_cmpl && (!piocb->vport) &&
           (piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) &&
@@ -3833,74 +5619,566 @@ __lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        return IOCB_BUSY;
 }
 
+/**
+ * lpfc_sli4_bpl2sgl - Convert the bpl/bde to a sgl.
+ * @phba: Pointer to HBA context object.
+ * @piocb: Pointer to command iocb.
+ * @sglq: Pointer to the scatter gather queue object.
+ *
+ * This routine converts the bpl or bde that is in the IOCB
+ * to a sgl list for the sli4 hardware. The physical address
+ * of the bpl/bde is converted back to a virtual address.
+ * If the IOCB contains a BPL then the list of BDE's is
+ * converted to sli4_sge's. If the IOCB contains a single
+ * BDE then it is converted to a single sli_sge.
+ * The IOCB is still in cpu endianess so the contents of
+ * the bpl can be used without byte swapping.
+ *
+ * Returns valid XRI = Success, NO_XRI = Failure.
+**/
+static uint16_t
+lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
+               struct lpfc_sglq *sglq)
+{
+       uint16_t xritag = NO_XRI;
+       struct ulp_bde64 *bpl = NULL;
+       struct ulp_bde64 bde;
+       struct sli4_sge *sgl  = NULL;
+       IOCB_t *icmd;
+       int numBdes = 0;
+       int i = 0;
+
+       if (!piocbq || !sglq)
+               return xritag;
+
+       sgl  = (struct sli4_sge *)sglq->sgl;
+       icmd = &piocbq->iocb;
+       if (icmd->un.genreq64.bdl.bdeFlags == BUFF_TYPE_BLP_64) {
+               numBdes = icmd->un.genreq64.bdl.bdeSize /
+                               sizeof(struct ulp_bde64);
+               /* The addrHigh and addrLow fields within the IOCB
+                * have not been byteswapped yet so there is no
+                * need to swap them back.
+                */
+               bpl  = (struct ulp_bde64 *)
+                       ((struct lpfc_dmabuf *)piocbq->context3)->virt;
+
+               if (!bpl)
+                       return xritag;
+
+               for (i = 0; i < numBdes; i++) {
+                       /* Should already be byte swapped. */
+                       sgl->addr_hi =  bpl->addrHigh;
+                       sgl->addr_lo =  bpl->addrLow;
+                       /* swap the size field back to the cpu so we
+                        * can assign it to the sgl.
+                        */
+                       bde.tus.w  = le32_to_cpu(bpl->tus.w);
+                       bf_set(lpfc_sli4_sge_len, sgl, bde.tus.f.bdeSize);
+                       if ((i+1) == numBdes)
+                               bf_set(lpfc_sli4_sge_last, sgl, 1);
+                       else
+                               bf_set(lpfc_sli4_sge_last, sgl, 0);
+                       sgl->word2 = cpu_to_le32(sgl->word2);
+                       sgl->word3 = cpu_to_le32(sgl->word3);
+                       bpl++;
+                       sgl++;
+               }
+       } else if (icmd->un.genreq64.bdl.bdeFlags == BUFF_TYPE_BDE_64) {
+                       /* The addrHigh and addrLow fields of the BDE have not
+                        * been byteswapped yet so they need to be swapped
+                        * before putting them in the sgl.
+                        */
+                       sgl->addr_hi =
+                               cpu_to_le32(icmd->un.genreq64.bdl.addrHigh);
+                       sgl->addr_lo =
+                               cpu_to_le32(icmd->un.genreq64.bdl.addrLow);
+                       bf_set(lpfc_sli4_sge_len, sgl,
+                               icmd->un.genreq64.bdl.bdeSize);
+                       bf_set(lpfc_sli4_sge_last, sgl, 1);
+                       sgl->word2 = cpu_to_le32(sgl->word2);
+                       sgl->word3 = cpu_to_le32(sgl->word3);
+       }
+       return sglq->sli4_xritag;
+}
 
 /**
- * lpfc_sli_issue_iocb - Wrapper function for __lpfc_sli_issue_iocb
+ * lpfc_sli4_scmd_to_wqidx_distr - scsi command to SLI4 WQ index distribution
  * @phba: Pointer to HBA context object.
- * @pring: Pointer to driver SLI ring object.
  * @piocb: Pointer to command iocb.
- * @flag: Flag indicating if this command can be put into txq.
  *
- * lpfc_sli_issue_iocb is a wrapper around __lpfc_sli_issue_iocb
- * function. This function gets the hbalock and calls
- * __lpfc_sli_issue_iocb function and will return the error returned
- * by __lpfc_sli_issue_iocb function. This wrapper is used by
- * functions which do not hold hbalock.
+ * This routine performs a round robin SCSI command to SLI4 FCP WQ index
+ * distribution.
+ *
+ * Return: index into SLI4 fast-path FCP queue index.
  **/
-int
-lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
-                   struct lpfc_iocbq *piocb, uint32_t flag)
+static uint32_t
+lpfc_sli4_scmd_to_wqidx_distr(struct lpfc_hba *phba, struct lpfc_iocbq *piocb)
 {
-       unsigned long iflags;
-       int rc;
-
-       spin_lock_irqsave(&phba->hbalock, iflags);
-       rc = __lpfc_sli_issue_iocb(phba, pring, piocb, flag);
-       spin_unlock_irqrestore(&phba->hbalock, iflags);
+       static uint32_t fcp_qidx;
 
-       return rc;
+       return fcp_qidx++ % phba->cfg_fcp_wq_count;
 }
 
 /**
- * lpfc_extra_ring_setup - Extra ring setup function
+ * lpfc_sli_iocb2wqe - Convert the IOCB to a work queue entry.
  * @phba: Pointer to HBA context object.
+ * @piocb: Pointer to command iocb.
+ * @wqe: Pointer to the work queue entry.
  *
- * This function is called while driver attaches with the
- * HBA to setup the extra ring. The extra ring is used
- * only when driver needs to support target mode functionality
- * or IP over FC functionalities.
+ * This routine converts the iocb command to its Work Queue Entry
+ * equivalent. The wqe pointer should not have any fields set when
+ * this routine is called because it will memcpy over them.
+ * This routine does not set the CQ_ID or the WQEC bits in the
+ * wqe.
  *
- * This function is called with no lock held.
+ * Returns: 0 = Success, IOCB_ERROR = Failure.
  **/
 static int
-lpfc_extra_ring_setup( struct lpfc_hba *phba)
+lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
+               union lpfc_wqe *wqe)
 {
-       struct lpfc_sli *psli;
-       struct lpfc_sli_ring *pring;
+       uint32_t payload_len = 0;
+       uint8_t ct = 0;
+       uint32_t fip;
+       uint32_t abort_tag;
+       uint8_t command_type = ELS_COMMAND_NON_FIP;
+       uint8_t cmnd;
+       uint16_t xritag;
+       struct ulp_bde64 *bpl = NULL;
+
+       fip = bf_get(lpfc_fip_flag, &phba->sli4_hba.sli4_flags);
+       /* The fcp commands will set command type */
+       if ((!(iocbq->iocb_flag &  LPFC_IO_FCP)) && (!fip))
+               command_type = ELS_COMMAND_NON_FIP;
+       else if (!(iocbq->iocb_flag &  LPFC_IO_FCP))
+               command_type = ELS_COMMAND_FIP;
+       else if (iocbq->iocb_flag &  LPFC_IO_FCP)
+               command_type = FCP_COMMAND;
+       else {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                       "2019 Invalid cmd 0x%x\n",
+                       iocbq->iocb.ulpCommand);
+               return IOCB_ERROR;
+       }
+       /* Some of the fields are in the right position already */
+       memcpy(wqe, &iocbq->iocb, sizeof(union lpfc_wqe));
+       abort_tag = (uint32_t) iocbq->iotag;
+       xritag = iocbq->sli4_xritag;
+       wqe->words[7] = 0; /* The ct field has moved so reset */
+       /* words0-2 bpl convert bde */
+       if (iocbq->iocb.un.genreq64.bdl.bdeFlags == BUFF_TYPE_BLP_64) {
+               bpl  = (struct ulp_bde64 *)
+                       ((struct lpfc_dmabuf *)iocbq->context3)->virt;
+               if (!bpl)
+                       return IOCB_ERROR;
 
-       psli = &phba->sli;
+               /* Should already be byte swapped. */
+               wqe->generic.bde.addrHigh =  le32_to_cpu(bpl->addrHigh);
+               wqe->generic.bde.addrLow =  le32_to_cpu(bpl->addrLow);
+               /* swap the size field back to the cpu so we
+                * can assign it to the sgl.
+                */
+               wqe->generic.bde.tus.w  = le32_to_cpu(bpl->tus.w);
+               payload_len = wqe->generic.bde.tus.f.bdeSize;
+       } else
+               payload_len = iocbq->iocb.un.fcpi64.bdl.bdeSize;
 
-       /* Adjust cmd/rsp ring iocb entries more evenly */
+       iocbq->iocb.ulpIoTag = iocbq->iotag;
+       cmnd = iocbq->iocb.ulpCommand;
 
-       /* Take some away from the FCP ring */
-       pring = &psli->ring[psli->fcp_ring];
-       pring->numCiocb -= SLI2_IOCB_CMD_R1XTRA_ENTRIES;
-       pring->numRiocb -= SLI2_IOCB_RSP_R1XTRA_ENTRIES;
-       pring->numCiocb -= SLI2_IOCB_CMD_R3XTRA_ENTRIES;
-       pring->numRiocb -= SLI2_IOCB_RSP_R3XTRA_ENTRIES;
+       switch (iocbq->iocb.ulpCommand) {
+       case CMD_ELS_REQUEST64_CR:
+               if (!iocbq->iocb.ulpLe) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "2007 Only Limited Edition cmd Format"
+                               " supported 0x%x\n",
+                               iocbq->iocb.ulpCommand);
+                       return IOCB_ERROR;
+               }
+               wqe->els_req.payload_len = payload_len;
+               /* Els_reguest64 has a TMO */
+               bf_set(wqe_tmo, &wqe->els_req.wqe_com,
+                       iocbq->iocb.ulpTimeout);
+               /* Need a VF for word 4 set the vf bit*/
+               bf_set(els_req64_vf, &wqe->els_req, 0);
+               /* And a VFID for word 12 */
+               bf_set(els_req64_vfid, &wqe->els_req, 0);
+               /*
+                * Set ct field to 3, indicates that the context_tag field
+                * contains the FCFI and remote N_Port_ID is
+                * in word 5.
+                */
 
-       /* and give them to the extra ring */
-       pring = &psli->ring[psli->extra_ring];
+               ct = ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l);
+               bf_set(lpfc_wqe_gen_context, &wqe->generic,
+                               iocbq->iocb.ulpContext);
 
-       pring->numCiocb += SLI2_IOCB_CMD_R1XTRA_ENTRIES;
-       pring->numRiocb += SLI2_IOCB_RSP_R1XTRA_ENTRIES;
-       pring->numCiocb += SLI2_IOCB_CMD_R3XTRA_ENTRIES;
-       pring->numRiocb += SLI2_IOCB_RSP_R3XTRA_ENTRIES;
+               if (iocbq->vport->fc_myDID != 0) {
+                       bf_set(els_req64_sid, &wqe->els_req,
+                                iocbq->vport->fc_myDID);
+                       bf_set(els_req64_sp, &wqe->els_req, 1);
+               }
+               bf_set(lpfc_wqe_gen_ct, &wqe->generic, ct);
+               bf_set(lpfc_wqe_gen_pu, &wqe->generic, 0);
+               /* CCP CCPE PV PRI in word10 were set in the memcpy */
+       break;
+       case CMD_XMIT_SEQUENCE64_CR:
+               /* word3 iocb=io_tag32 wqe=payload_offset */
+               /* payload offset used for multilpe outstanding
+                * sequences on the same exchange
+                */
+               wqe->words[3] = 0;
+               /* word4 relative_offset memcpy */
+               /* word5 r_ctl/df_ctl memcpy */
+               bf_set(lpfc_wqe_gen_pu, &wqe->generic, 0);
+               wqe->xmit_sequence.xmit_len = payload_len;
+       break;
+       case CMD_XMIT_BCAST64_CN:
+               /* word3 iocb=iotag32 wqe=payload_len */
+               wqe->words[3] = 0; /* no definition for this in wqe */
+               /* word4 iocb=rsvd wqe=rsvd */
+               /* word5 iocb=rctl/type/df_ctl wqe=rctl/type/df_ctl memcpy */
+               /* word6 iocb=ctxt_tag/io_tag wqe=ctxt_tag/xri */
+               bf_set(lpfc_wqe_gen_ct, &wqe->generic,
+                       ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l));
+       break;
+       case CMD_FCP_IWRITE64_CR:
+               command_type = FCP_COMMAND_DATA_OUT;
+               /* The struct for wqe fcp_iwrite has 3 fields that are somewhat
+                * confusing.
+                * word3 is payload_len: byte offset to the sgl entry for the
+                * fcp_command.
+                * word4 is total xfer len, same as the IOCB->ulpParameter.
+                * word5 is initial xfer len 0 = wait for xfer-ready
+                */
 
-       /* Setup default profile for this ring */
-       pring->iotag_max = 4096;
-       pring->num_mask = 1;
-       pring->prt[0].profile = 0;      /* Mask 0 */
+               /* Always wait for xfer-ready before sending data */
+               wqe->fcp_iwrite.initial_xfer_len = 0;
+               /* word 4 (xfer length) should have been set on the memcpy */
+
+       /* allow write to fall through to read */
+       case CMD_FCP_IREAD64_CR:
+               /* FCP_CMD is always the 1st sgl entry */
+               wqe->fcp_iread.payload_len =
+                       payload_len + sizeof(struct fcp_rsp);
+
+               /* word 4 (xfer length) should have been set on the memcpy */
+
+               bf_set(lpfc_wqe_gen_erp, &wqe->generic,
+                       iocbq->iocb.ulpFCP2Rcvy);
+               bf_set(lpfc_wqe_gen_lnk, &wqe->generic, iocbq->iocb.ulpXS);
+               /* The XC bit and the XS bit are similar. The driver never
+                * tracked whether or not the exchange was previouslly open.
+                * XC = Exchange create, 0 is create. 1 is already open.
+                * XS = link cmd: 1 do not close the exchange after command.
+                * XS = 0 close exchange when command completes.
+                * The only time we would not set the XC bit is when the XS bit
+                * is set and we are sending our 2nd or greater command on
+                * this exchange.
+                */
+
+       /* ALLOW read & write to fall through to ICMD64 */
+       case CMD_FCP_ICMND64_CR:
+               /* Always open the exchange */
+               bf_set(wqe_xc, &wqe->fcp_iread.wqe_com, 0);
+
+               wqe->words[10] &= 0xffff0000; /* zero out ebde count */
+               bf_set(lpfc_wqe_gen_pu, &wqe->generic, iocbq->iocb.ulpPU);
+       break;
+       case CMD_GEN_REQUEST64_CR:
+               /* word3 command length is described as byte offset to the
+                * rsp_data. Would always be 16, sizeof(struct sli4_sge)
+                * sgl[0] = cmnd
+                * sgl[1] = rsp.
+                *
+                */
+               wqe->gen_req.command_len = payload_len;
+               /* Word4 parameter  copied in the memcpy */
+               /* Word5 [rctl, type, df_ctl, la] copied in memcpy */
+               /* word6 context tag copied in memcpy */
+               if (iocbq->iocb.ulpCt_h  || iocbq->iocb.ulpCt_l) {
+                       ct = ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l);
+                       lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "2015 Invalid CT %x command 0x%x\n",
+                               ct, iocbq->iocb.ulpCommand);
+                       return IOCB_ERROR;
+               }
+               bf_set(lpfc_wqe_gen_ct, &wqe->generic, 0);
+               bf_set(wqe_tmo, &wqe->gen_req.wqe_com,
+                       iocbq->iocb.ulpTimeout);
+
+               bf_set(lpfc_wqe_gen_pu, &wqe->generic, iocbq->iocb.ulpPU);
+               command_type = OTHER_COMMAND;
+       break;
+       case CMD_XMIT_ELS_RSP64_CX:
+               /* words0-2 BDE memcpy */
+               /* word3 iocb=iotag32 wqe=rsvd */
+               wqe->words[3] = 0;
+               /* word4 iocb=did wge=rsvd. */
+               wqe->words[4] = 0;
+               /* word5 iocb=rsvd wge=did */
+               bf_set(wqe_els_did, &wqe->xmit_els_rsp.wqe_dest,
+                        iocbq->iocb.un.elsreq64.remoteID);
+
+               bf_set(lpfc_wqe_gen_ct, &wqe->generic,
+                       ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l));
+
+               bf_set(lpfc_wqe_gen_pu, &wqe->generic, iocbq->iocb.ulpPU);
+               bf_set(wqe_rcvoxid, &wqe->generic, iocbq->iocb.ulpContext);
+               if (!iocbq->iocb.ulpCt_h && iocbq->iocb.ulpCt_l)
+                       bf_set(lpfc_wqe_gen_context, &wqe->generic,
+                              iocbq->vport->vpi + phba->vpi_base);
+               command_type = OTHER_COMMAND;
+       break;
+       case CMD_CLOSE_XRI_CN:
+       case CMD_ABORT_XRI_CN:
+       case CMD_ABORT_XRI_CX:
+               /* words 0-2 memcpy should be 0 rserved */
+               /* port will send abts */
+               if (iocbq->iocb.ulpCommand == CMD_CLOSE_XRI_CN)
+                       /*
+                        * The link is down so the fw does not need to send abts
+                        * on the wire.
+                        */
+                       bf_set(abort_cmd_ia, &wqe->abort_cmd, 1);
+               else
+                       bf_set(abort_cmd_ia, &wqe->abort_cmd, 0);
+               bf_set(abort_cmd_criteria, &wqe->abort_cmd, T_XRI_TAG);
+               abort_tag = iocbq->iocb.un.acxri.abortIoTag;
+               wqe->words[5] = 0;
+               bf_set(lpfc_wqe_gen_ct, &wqe->generic,
+                       ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l));
+               abort_tag = iocbq->iocb.un.acxri.abortIoTag;
+               wqe->generic.abort_tag = abort_tag;
+               /*
+                * The abort handler will send us CMD_ABORT_XRI_CN or
+                * CMD_CLOSE_XRI_CN and the fw only accepts CMD_ABORT_XRI_CX
+                */
+               bf_set(lpfc_wqe_gen_command, &wqe->generic, CMD_ABORT_XRI_CX);
+               cmnd = CMD_ABORT_XRI_CX;
+               command_type = OTHER_COMMAND;
+               xritag = 0;
+       break;
+       case CMD_XRI_ABORTED_CX:
+       case CMD_CREATE_XRI_CR: /* Do we expect to use this? */
+               /* words0-2 are all 0's no bde */
+               /* word3 and word4 are rsvrd */
+               wqe->words[3] = 0;
+               wqe->words[4] = 0;
+               /* word5 iocb=rsvd wge=did */
+               /* There is no remote port id in the IOCB? */
+               /* Let this fall through and fail */
+       case CMD_IOCB_FCP_IBIDIR64_CR: /* bidirectional xfer */
+       case CMD_FCP_TSEND64_CX: /* Target mode send xfer-ready */
+       case CMD_FCP_TRSP64_CX: /* Target mode rcv */
+       case CMD_FCP_AUTO_TRSP_CX: /* Auto target rsp */
+       default:
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "2014 Invalid command 0x%x\n",
+                               iocbq->iocb.ulpCommand);
+               return IOCB_ERROR;
+       break;
+
+       }
+       bf_set(lpfc_wqe_gen_xri, &wqe->generic, xritag);
+       bf_set(lpfc_wqe_gen_request_tag, &wqe->generic, iocbq->iotag);
+       wqe->generic.abort_tag = abort_tag;
+       bf_set(lpfc_wqe_gen_cmd_type, &wqe->generic, command_type);
+       bf_set(lpfc_wqe_gen_command, &wqe->generic, cmnd);
+       bf_set(lpfc_wqe_gen_class, &wqe->generic, iocbq->iocb.ulpClass);
+       bf_set(lpfc_wqe_gen_cq_id, &wqe->generic, LPFC_WQE_CQ_ID_DEFAULT);
+
+       return 0;
+}
+
+/**
+ * __lpfc_sli_issue_iocb_s4 - SLI4 device lockless ver of lpfc_sli_issue_iocb
+ * @phba: Pointer to HBA context object.
+ * @ring_number: SLI ring number to issue iocb on.
+ * @piocb: Pointer to command iocb.
+ * @flag: Flag indicating if this command can be put into txq.
+ *
+ * __lpfc_sli_issue_iocb_s4 is used by other functions in the driver to issue
+ * an iocb command to an HBA with SLI-4 interface spec.
+ *
+ * This function is called with hbalock held. The function will return success
+ * after it successfully submit the iocb to firmware or after adding to the
+ * txq.
+ **/
+static int
+__lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
+                        struct lpfc_iocbq *piocb, uint32_t flag)
+{
+       struct lpfc_sglq *sglq;
+       uint16_t xritag;
+       union lpfc_wqe wqe;
+       struct lpfc_sli_ring *pring = &phba->sli.ring[ring_number];
+       uint32_t fcp_wqidx;
+
+       if (piocb->sli4_xritag == NO_XRI) {
+               if (piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN ||
+                       piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)
+                       sglq = NULL;
+               else {
+                       sglq = __lpfc_sli_get_sglq(phba);
+                       if (!sglq)
+                               return IOCB_ERROR;
+                       piocb->sli4_xritag = sglq->sli4_xritag;
+               }
+       } else if (piocb->iocb_flag &  LPFC_IO_FCP) {
+               sglq = NULL; /* These IO's already have an XRI and
+                             * a mapped sgl.
+                             */
+       } else {
+               /* This is a continuation of a commandi,(CX) so this
+                * sglq is on the active list
+                */
+               sglq = __lpfc_get_active_sglq(phba, piocb->sli4_xritag);
+               if (!sglq)
+                       return IOCB_ERROR;
+       }
+
+       if (sglq) {
+               xritag = lpfc_sli4_bpl2sgl(phba, piocb, sglq);
+               if (xritag != sglq->sli4_xritag)
+                       return IOCB_ERROR;
+       }
+
+       if (lpfc_sli4_iocb2wqe(phba, piocb, &wqe))
+               return IOCB_ERROR;
+
+       if (piocb->iocb_flag &  LPFC_IO_FCP) {
+               fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba, piocb);
+               if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[fcp_wqidx], &wqe))
+                       return IOCB_ERROR;
+       } else {
+               if (lpfc_sli4_wq_put(phba->sli4_hba.els_wq, &wqe))
+                       return IOCB_ERROR;
+       }
+       lpfc_sli_ringtxcmpl_put(phba, pring, piocb);
+
+       return 0;
+}
+
+/**
+ * __lpfc_sli_issue_iocb - Wrapper func of lockless version for issuing iocb
+ *
+ * This routine wraps the actual lockless version for issusing IOCB function
+ * pointer from the lpfc_hba struct.
+ *
+ * Return codes:
+ *     IOCB_ERROR - Error
+ *     IOCB_SUCCESS - Success
+ *     IOCB_BUSY - Busy
+ **/
+static inline int
+__lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number,
+               struct lpfc_iocbq *piocb, uint32_t flag)
+{
+       return phba->__lpfc_sli_issue_iocb(phba, ring_number, piocb, flag);
+}
+
+/**
+ * lpfc_sli_api_table_setup - Set up sli api fucntion jump table
+ * @phba: The hba struct for which this call is being executed.
+ * @dev_grp: The HBA PCI-Device group number.
+ *
+ * This routine sets up the SLI interface API function jump table in @phba
+ * struct.
+ * Returns: 0 - success, -ENODEV - failure.
+ **/
+int
+lpfc_sli_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
+{
+
+       switch (dev_grp) {
+       case LPFC_PCI_DEV_LP:
+               phba->__lpfc_sli_issue_iocb = __lpfc_sli_issue_iocb_s3;
+               phba->__lpfc_sli_release_iocbq = __lpfc_sli_release_iocbq_s3;
+               break;
+       case LPFC_PCI_DEV_OC:
+               phba->__lpfc_sli_issue_iocb = __lpfc_sli_issue_iocb_s4;
+               phba->__lpfc_sli_release_iocbq = __lpfc_sli_release_iocbq_s4;
+               break;
+       default:
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "1419 Invalid HBA PCI-device group: 0x%x\n",
+                               dev_grp);
+               return -ENODEV;
+               break;
+       }
+       phba->lpfc_get_iocb_from_iocbq = lpfc_get_iocb_from_iocbq;
+       return 0;
+}
+
+/**
+ * lpfc_sli_issue_iocb - Wrapper function for __lpfc_sli_issue_iocb
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @piocb: Pointer to command iocb.
+ * @flag: Flag indicating if this command can be put into txq.
+ *
+ * lpfc_sli_issue_iocb is a wrapper around __lpfc_sli_issue_iocb
+ * function. This function gets the hbalock and calls
+ * __lpfc_sli_issue_iocb function and will return the error returned
+ * by __lpfc_sli_issue_iocb function. This wrapper is used by
+ * functions which do not hold hbalock.
+ **/
+int
+lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number,
+                   struct lpfc_iocbq *piocb, uint32_t flag)
+{
+       unsigned long iflags;
+       int rc;
+
+       spin_lock_irqsave(&phba->hbalock, iflags);
+       rc = __lpfc_sli_issue_iocb(phba, ring_number, piocb, flag);
+       spin_unlock_irqrestore(&phba->hbalock, iflags);
+
+       return rc;
+}
+
+/**
+ * lpfc_extra_ring_setup - Extra ring setup function
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called while driver attaches with the
+ * HBA to setup the extra ring. The extra ring is used
+ * only when driver needs to support target mode functionality
+ * or IP over FC functionalities.
+ *
+ * This function is called with no lock held.
+ **/
+static int
+lpfc_extra_ring_setup( struct lpfc_hba *phba)
+{
+       struct lpfc_sli *psli;
+       struct lpfc_sli_ring *pring;
+
+       psli = &phba->sli;
+
+       /* Adjust cmd/rsp ring iocb entries more evenly */
+
+       /* Take some away from the FCP ring */
+       pring = &psli->ring[psli->fcp_ring];
+       pring->numCiocb -= SLI2_IOCB_CMD_R1XTRA_ENTRIES;
+       pring->numRiocb -= SLI2_IOCB_RSP_R1XTRA_ENTRIES;
+       pring->numCiocb -= SLI2_IOCB_CMD_R3XTRA_ENTRIES;
+       pring->numRiocb -= SLI2_IOCB_RSP_R3XTRA_ENTRIES;
+
+       /* and give them to the extra ring */
+       pring = &psli->ring[psli->extra_ring];
+
+       pring->numCiocb += SLI2_IOCB_CMD_R1XTRA_ENTRIES;
+       pring->numRiocb += SLI2_IOCB_RSP_R1XTRA_ENTRIES;
+       pring->numCiocb += SLI2_IOCB_CMD_R3XTRA_ENTRIES;
+       pring->numRiocb += SLI2_IOCB_RSP_R3XTRA_ENTRIES;
+
+       /* Setup default profile for this ring */
+       pring->iotag_max = 4096;
+       pring->num_mask = 1;
+       pring->prt[0].profile = 0;      /* Mask 0 */
        pring->prt[0].rctl = phba->cfg_multi_ring_rctl;
        pring->prt[0].type = phba->cfg_multi_ring_type;
        pring->prt[0].lpfc_sli_rcv_unsol_event = NULL;
@@ -4147,6 +6425,52 @@ lpfc_sli_queue_setup(struct lpfc_hba *phba)
        return 1;
 }
 
+/**
+ * lpfc_sli_mbox_sys_flush - Flush mailbox command sub-system
+ * @phba: Pointer to HBA context object.
+ *
+ * This routine flushes the mailbox command subsystem. It will unconditionally
+ * flush all the mailbox commands in the three possible stages in the mailbox
+ * command sub-system: pending mailbox command queue; the outstanding mailbox
+ * command; and completed mailbox command queue. It is caller's responsibility
+ * to make sure that the driver is in the proper state to flush the mailbox
+ * command sub-system. Namely, the posting of mailbox commands into the
+ * pending mailbox command queue from the various clients must be stopped;
+ * either the HBA is in a state that it will never works on the outstanding
+ * mailbox command (such as in EEH or ERATT conditions) or the outstanding
+ * mailbox command has been completed.
+ **/
+static void
+lpfc_sli_mbox_sys_flush(struct lpfc_hba *phba)
+{
+       LIST_HEAD(completions);
+       struct lpfc_sli *psli = &phba->sli;
+       LPFC_MBOXQ_t *pmb;
+       unsigned long iflag;
+
+       /* Flush all the mailbox commands in the mbox system */
+       spin_lock_irqsave(&phba->hbalock, iflag);
+       /* The pending mailbox command queue */
+       list_splice_init(&phba->sli.mboxq, &completions);
+       /* The outstanding active mailbox command */
+       if (psli->mbox_active) {
+               list_add_tail(&psli->mbox_active->list, &completions);
+               psli->mbox_active = NULL;
+               psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+       }
+       /* The completed mailbox command queue */
+       list_splice_init(&phba->sli.mboxq_cmpl, &completions);
+       spin_unlock_irqrestore(&phba->hbalock, iflag);
+
+       /* Return all flushed mailbox commands with MBX_NOT_FINISHED status */
+       while (!list_empty(&completions)) {
+               list_remove_head(&completions, pmb, LPFC_MBOXQ_t, list);
+               pmb->u.mb.mbxStatus = MBX_NOT_FINISHED;
+               if (pmb->mbox_cmpl)
+                       pmb->mbox_cmpl(phba, pmb);
+       }
+}
+
 /**
  * lpfc_sli_host_down - Vport cleanup function
  * @vport: Pointer to virtual port object.
@@ -4240,9 +6564,11 @@ lpfc_sli_hba_down(struct lpfc_hba *phba)
        struct lpfc_sli *psli = &phba->sli;
        struct lpfc_sli_ring *pring;
        struct lpfc_dmabuf *buf_ptr;
-       LPFC_MBOXQ_t *pmb;
-       int i;
        unsigned long flags = 0;
+       int i;
+
+       /* Shutdown the mailbox command sub-system */
+       lpfc_sli_mbox_sys_shutdown(phba);
 
        lpfc_hba_down_prep(phba);
 
@@ -4287,28 +6613,42 @@ lpfc_sli_hba_down(struct lpfc_hba *phba)
 
        /* Return any active mbox cmds */
        del_timer_sync(&psli->mbox_tmo);
-       spin_lock_irqsave(&phba->hbalock, flags);
 
-       spin_lock(&phba->pport->work_port_lock);
+       spin_lock_irqsave(&phba->pport->work_port_lock, flags);
        phba->pport->work_port_events &= ~WORKER_MBOX_TMO;
-       spin_unlock(&phba->pport->work_port_lock);
+       spin_unlock_irqrestore(&phba->pport->work_port_lock, flags);
 
-       /* Return any pending or completed mbox cmds */
-       list_splice_init(&phba->sli.mboxq, &completions);
-       if (psli->mbox_active) {
-               list_add_tail(&psli->mbox_active->list, &completions);
-               psli->mbox_active = NULL;
-               psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
-       }
-       list_splice_init(&phba->sli.mboxq_cmpl, &completions);
-       spin_unlock_irqrestore(&phba->hbalock, flags);
+       return 1;
+}
+
+/**
+ * lpfc_sli4_hba_down - PCI function resource cleanup for the SLI4 HBA
+ * @phba: Pointer to HBA context object.
+ *
+ * This function cleans up all queues, iocb, buffers, mailbox commands while
+ * shutting down the SLI4 HBA FCoE function. This function is called with no
+ * lock held and always returns 1.
+ *
+ * This function does the following to cleanup driver FCoE function resources:
+ * - Free discovery resources for each virtual port
+ * - Cleanup any pending fabric iocbs
+ * - Iterate through the iocb txq and free each entry in the list.
+ * - Free up any buffer posted to the HBA.
+ * - Clean up all the queue entries: WQ, RQ, MQ, EQ, CQ, etc.
+ * - Free mailbox commands in the mailbox queue.
+ **/
+int
+lpfc_sli4_hba_down(struct lpfc_hba *phba)
+{
+       /* Stop the SLI4 device port */
+       lpfc_stop_port(phba);
+
+       /* Tear down the queues in the HBA */
+       lpfc_sli4_queue_unset(phba);
+
+       /* unregister default FCFI from the HBA */
+       lpfc_sli4_fcfi_unreg(phba, phba->fcf.fcfi);
 
-       while (!list_empty(&completions)) {
-               list_remove_head(&completions, pmb, LPFC_MBOXQ_t, list);
-               pmb->mb.mbxStatus = MBX_NOT_FINISHED;
-               if (pmb->mbox_cmpl)
-                       pmb->mbox_cmpl(phba,pmb);
-       }
        return 1;
 }
 
@@ -4639,7 +6979,10 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        iabt = &abtsiocbp->iocb;
        iabt->un.acxri.abortType = ABORT_TYPE_ABTS;
        iabt->un.acxri.abortContextTag = icmd->ulpContext;
-       iabt->un.acxri.abortIoTag = icmd->ulpIoTag;
+       if (phba->sli_rev == LPFC_SLI_REV4)
+               iabt->un.acxri.abortIoTag = cmdiocb->sli4_xritag;
+       else
+               iabt->un.acxri.abortIoTag = icmd->ulpIoTag;
        iabt->ulpLe = 1;
        iabt->ulpClass = icmd->ulpClass;
 
@@ -4655,7 +6998,7 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                         "abort cmd iotag x%x\n",
                         iabt->un.acxri.abortContextTag,
                         iabt->un.acxri.abortIoTag, abtsiocbp->iotag);
-       retval = __lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0);
+       retval = __lpfc_sli_issue_iocb(phba, pring->ringno, abtsiocbp, 0);
 
        if (retval)
                __lpfc_sli_release_iocbq(phba, abtsiocbp);
@@ -4838,7 +7181,10 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring,
                cmd = &iocbq->iocb;
                abtsiocb->iocb.un.acxri.abortType = ABORT_TYPE_ABTS;
                abtsiocb->iocb.un.acxri.abortContextTag = cmd->ulpContext;
-               abtsiocb->iocb.un.acxri.abortIoTag = cmd->ulpIoTag;
+               if (phba->sli_rev == LPFC_SLI_REV4)
+                       abtsiocb->iocb.un.acxri.abortIoTag = iocbq->sli4_xritag;
+               else
+                       abtsiocb->iocb.un.acxri.abortIoTag = cmd->ulpIoTag;
                abtsiocb->iocb.ulpLe = 1;
                abtsiocb->iocb.ulpClass = cmd->ulpClass;
                abtsiocb->vport = phba->pport;
@@ -4850,7 +7196,8 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring,
 
                /* Setup callback routine and issue the command. */
                abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl;
-               ret_val = lpfc_sli_issue_iocb(phba, pring, abtsiocb, 0);
+               ret_val = lpfc_sli_issue_iocb(phba, pring->ringno,
+                                             abtsiocb, 0);
                if (ret_val == IOCB_ERROR) {
                        lpfc_sli_release_iocbq(phba, abtsiocb);
                        errcnt++;
@@ -4931,7 +7278,7 @@ lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba,
  **/
 int
 lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
-                        struct lpfc_sli_ring *pring,
+                        uint32_t ring_number,
                         struct lpfc_iocbq *piocb,
                         struct lpfc_iocbq *prspiocbq,
                         uint32_t timeout)
@@ -4962,7 +7309,7 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
                readl(phba->HCregaddr); /* flush */
        }
 
-       retval = lpfc_sli_issue_iocb(phba, pring, piocb, 0);
+       retval = lpfc_sli_issue_iocb(phba, ring_number, piocb, 0);
        if (retval == IOCB_SUCCESS) {
                timeout_req = timeout * HZ;
                timeleft = wait_event_timeout(done_q,
@@ -5077,140 +7424,267 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
 }
 
 /**
- * lpfc_sli_flush_mbox_queue - mailbox queue cleanup function
+ * lpfc_sli_mbox_sys_shutdown - shutdown mailbox command sub-system
  * @phba: Pointer to HBA context.
  *
- * This function is called to cleanup any pending mailbox
- * objects in the driver queue before bringing the HBA offline.
- * This function is called while resetting the HBA.
- * The function is called without any lock held. The function
- * takes hbalock to update SLI data structure.
- * This function returns 1 when there is an active mailbox
- * command pending else returns 0.
+ * This function is called to shutdown the driver's mailbox sub-system.
+ * It first marks the mailbox sub-system is in a block state to prevent
+ * the asynchronous mailbox command from issued off the pending mailbox
+ * command queue. If the mailbox command sub-system shutdown is due to
+ * HBA error conditions such as EEH or ERATT, this routine shall invoke
+ * the mailbox sub-system flush routine to forcefully bring down the
+ * mailbox sub-system. Otherwise, if it is due to normal condition (such
+ * as with offline or HBA function reset), this routine will wait for the
+ * outstanding mailbox command to complete before invoking the mailbox
+ * sub-system flush routine to gracefully bring down mailbox sub-system.
  **/
-int
-lpfc_sli_flush_mbox_queue(struct lpfc_hba * phba)
+void
+lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *phba)
 {
-       struct lpfc_vport *vport = phba->pport;
-       int i = 0;
-       uint32_t ha_copy;
+       struct lpfc_sli *psli = &phba->sli;
+       uint8_t actcmd = MBX_HEARTBEAT;
+       unsigned long timeout;
 
-       while (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE && !vport->stopped) {
-               if (i++ > LPFC_MBOX_TMO * 1000)
-                       return 1;
+       spin_lock_irq(&phba->hbalock);
+       psli->sli_flag |= LPFC_SLI_ASYNC_MBX_BLK;
+       spin_unlock_irq(&phba->hbalock);
 
-               /*
-                * Call lpfc_sli_handle_mb_event only if a mailbox cmd
-                * did finish. This way we won't get the misleading
-                * "Stray Mailbox Interrupt" message.
-                */
+       if (psli->sli_flag & LPFC_SLI_ACTIVE) {
                spin_lock_irq(&phba->hbalock);
-               ha_copy = phba->work_ha;
-               phba->work_ha &= ~HA_MBATT;
+               if (phba->sli.mbox_active)
+                       actcmd = phba->sli.mbox_active->u.mb.mbxCommand;
                spin_unlock_irq(&phba->hbalock);
-
-               if (ha_copy & HA_MBATT)
-                       if (lpfc_sli_handle_mb_event(phba) == 0)
-                               i = 0;
-
-               msleep(1);
+               /* Determine how long we might wait for the active mailbox
+                * command to be gracefully completed by firmware.
+                */
+               timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, actcmd) *
+                                          1000) + jiffies;
+               while (phba->sli.mbox_active) {
+                       /* Check active mailbox complete status every 2ms */
+                       msleep(2);
+                       if (time_after(jiffies, timeout))
+                               /* Timeout, let the mailbox flush routine to
+                                * forcefully release active mailbox command
+                                */
+                               break;
+               }
        }
-
-       return (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) ? 1 : 0;
+       lpfc_sli_mbox_sys_flush(phba);
 }
 
 /**
- * lpfc_sli_check_eratt - check error attention events
+ * lpfc_sli_eratt_read - read sli-3 error attention events
  * @phba: Pointer to HBA context.
  *
- * This function is called form timer soft interrupt context to check HBA's
- * error attention register bit for error attention events.
+ * This function is called to read the SLI3 device error attention registers
+ * for possible error attention events. The caller must hold the hostlock
+ * with spin_lock_irq().
  *
  * This fucntion returns 1 when there is Error Attention in the Host Attention
  * Register and returns 0 otherwise.
  **/
-int
-lpfc_sli_check_eratt(struct lpfc_hba *phba)
+static int
+lpfc_sli_eratt_read(struct lpfc_hba *phba)
 {
        uint32_t ha_copy;
 
-       /* If PCI channel is offline, don't process it */
-       if (unlikely(pci_channel_offline(phba->pcidev)))
-               return 0;
-
-       /* If somebody is waiting to handle an eratt, don't process it
-        * here. The brdkill function will do this.
-        */
-       if (phba->link_flag & LS_IGNORE_ERATT)
-               return 0;
-
-       /* Check if interrupt handler handles this ERATT */
-       spin_lock_irq(&phba->hbalock);
-       if (phba->hba_flag & HBA_ERATT_HANDLED) {
-               /* Interrupt handler has handled ERATT */
-               spin_unlock_irq(&phba->hbalock);
-               return 0;
-       }
-
-       /*
-        * If there is deferred error attention, do not check for error
-        * attention
-        */
-       if (unlikely(phba->hba_flag & DEFER_ERATT)) {
-               spin_unlock_irq(&phba->hbalock);
-               return 0;
-       }
-
-       /* Read chip Host Attention (HA) register */
-       ha_copy = readl(phba->HAregaddr);
-       if (ha_copy & HA_ERATT) {
-               /* Read host status register to retrieve error event */
-               lpfc_sli_read_hs(phba);
+       /* Read chip Host Attention (HA) register */
+       ha_copy = readl(phba->HAregaddr);
+       if (ha_copy & HA_ERATT) {
+               /* Read host status register to retrieve error event */
+               lpfc_sli_read_hs(phba);
 
                /* Check if there is a deferred error condition is active */
                if ((HS_FFER1 & phba->work_hs) &&
-                       ((HS_FFER2 | HS_FFER3 | HS_FFER4 | HS_FFER5 |
-                       HS_FFER6 | HS_FFER7) & phba->work_hs)) {
+                   ((HS_FFER2 | HS_FFER3 | HS_FFER4 | HS_FFER5 |
+                    HS_FFER6 | HS_FFER7) & phba->work_hs)) {
+                       spin_lock_irq(&phba->hbalock);
                        phba->hba_flag |= DEFER_ERATT;
+                       spin_unlock_irq(&phba->hbalock);
                        /* Clear all interrupt enable conditions */
                        writel(0, phba->HCregaddr);
                        readl(phba->HCregaddr);
                }
 
                /* Set the driver HA work bitmap */
+               spin_lock_irq(&phba->hbalock);
                phba->work_ha |= HA_ERATT;
                /* Indicate polling handles this ERATT */
                phba->hba_flag |= HBA_ERATT_HANDLED;
                spin_unlock_irq(&phba->hbalock);
                return 1;
        }
+       return 0;
+}
+
+/**
+ * lpfc_sli4_eratt_read - read sli-4 error attention events
+ * @phba: Pointer to HBA context.
+ *
+ * This function is called to read the SLI4 device error attention registers
+ * for possible error attention events. The caller must hold the hostlock
+ * with spin_lock_irq().
+ *
+ * This fucntion returns 1 when there is Error Attention in the Host Attention
+ * Register and returns 0 otherwise.
+ **/
+static int
+lpfc_sli4_eratt_read(struct lpfc_hba *phba)
+{
+       uint32_t uerr_sta_hi, uerr_sta_lo;
+       uint32_t onlnreg0, onlnreg1;
+
+       /* For now, use the SLI4 device internal unrecoverable error
+        * registers for error attention. This can be changed later.
+        */
+       onlnreg0 = readl(phba->sli4_hba.ONLINE0regaddr);
+       onlnreg1 = readl(phba->sli4_hba.ONLINE1regaddr);
+       if ((onlnreg0 != LPFC_ONLINE_NERR) || (onlnreg1 != LPFC_ONLINE_NERR)) {
+               uerr_sta_lo = readl(phba->sli4_hba.UERRLOregaddr);
+               uerr_sta_hi = readl(phba->sli4_hba.UERRHIregaddr);
+               if (uerr_sta_lo || uerr_sta_hi) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "1423 HBA Unrecoverable error: "
+                                       "uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, "
+                                       "online0_reg=0x%x, online1_reg=0x%x\n",
+                                       uerr_sta_lo, uerr_sta_hi,
+                                       onlnreg0, onlnreg1);
+                       /* TEMP: as the driver error recover logic is not
+                        * fully developed, we just log the error message
+                        * and the device error attention action is now
+                        * temporarily disabled.
+                        */
+                       return 0;
+                       phba->work_status[0] = uerr_sta_lo;
+                       phba->work_status[1] = uerr_sta_hi;
+                       spin_lock_irq(&phba->hbalock);
+                       /* Set the driver HA work bitmap */
+                       phba->work_ha |= HA_ERATT;
+                       /* Indicate polling handles this ERATT */
+                       phba->hba_flag |= HBA_ERATT_HANDLED;
+                       spin_unlock_irq(&phba->hbalock);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/**
+ * lpfc_sli_check_eratt - check error attention events
+ * @phba: Pointer to HBA context.
+ *
+ * This function is called from timer soft interrupt context to check HBA's
+ * error attention register bit for error attention events.
+ *
+ * This fucntion returns 1 when there is Error Attention in the Host Attention
+ * Register and returns 0 otherwise.
+ **/
+int
+lpfc_sli_check_eratt(struct lpfc_hba *phba)
+{
+       uint32_t ha_copy;
+
+       /* If somebody is waiting to handle an eratt, don't process it
+        * here. The brdkill function will do this.
+        */
+       if (phba->link_flag & LS_IGNORE_ERATT)
+               return 0;
+
+       /* Check if interrupt handler handles this ERATT */
+       spin_lock_irq(&phba->hbalock);
+       if (phba->hba_flag & HBA_ERATT_HANDLED) {
+               /* Interrupt handler has handled ERATT */
+               spin_unlock_irq(&phba->hbalock);
+               return 0;
+       }
+
+       /*
+        * If there is deferred error attention, do not check for error
+        * attention
+        */
+       if (unlikely(phba->hba_flag & DEFER_ERATT)) {
+               spin_unlock_irq(&phba->hbalock);
+               return 0;
+       }
+
+       /* If PCI channel is offline, don't process it */
+       if (unlikely(pci_channel_offline(phba->pcidev))) {
+               spin_unlock_irq(&phba->hbalock);
+               return 0;
+       }
+
+       switch (phba->sli_rev) {
+       case LPFC_SLI_REV2:
+       case LPFC_SLI_REV3:
+               /* Read chip Host Attention (HA) register */
+               ha_copy = lpfc_sli_eratt_read(phba);
+               break;
+       case LPFC_SLI_REV4:
+               /* Read devcie Uncoverable Error (UERR) registers */
+               ha_copy = lpfc_sli4_eratt_read(phba);
+               break;
+       default:
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0299 Invalid SLI revision (%d)\n",
+                               phba->sli_rev);
+               ha_copy = 0;
+               break;
+       }
        spin_unlock_irq(&phba->hbalock);
+
+       return ha_copy;
+}
+
+/**
+ * lpfc_intr_state_check - Check device state for interrupt handling
+ * @phba: Pointer to HBA context.
+ *
+ * This inline routine checks whether a device or its PCI slot is in a state
+ * that the interrupt should be handled.
+ *
+ * This function returns 0 if the device or the PCI slot is in a state that
+ * interrupt should be handled, otherwise -EIO.
+ */
+static inline int
+lpfc_intr_state_check(struct lpfc_hba *phba)
+{
+       /* If the pci channel is offline, ignore all the interrupts */
+       if (unlikely(pci_channel_offline(phba->pcidev)))
+               return -EIO;
+
+       /* Update device level interrupt statistics */
+       phba->sli.slistat.sli_intr++;
+
+       /* Ignore all interrupts during initialization. */
+       if (unlikely(phba->link_state < LPFC_LINK_DOWN))
+               return -EIO;
+
        return 0;
 }
 
 /**
- * lpfc_sp_intr_handler - The slow-path interrupt handler of lpfc driver
+ * lpfc_sli_sp_intr_handler - Slow-path interrupt handler to SLI-3 device
  * @irq: Interrupt number.
  * @dev_id: The device context pointer.
  *
  * This function is directly called from the PCI layer as an interrupt
- * service routine when the device is enabled with MSI-X multi-message
- * interrupt mode and there are slow-path events in the HBA. However,
- * when the device is enabled with either MSI or Pin-IRQ interrupt mode,
- * this function is called as part of the device-level interrupt handler.
- * When the PCI slot is in error recovery or the HBA is undergoing
- * initialization, the interrupt handler will not process the interrupt.
- * The link attention and ELS ring attention events are handled by the
- * worker thread. The interrupt handler signals the worker thread and
- * and returns for these events. This function is called without any
- * lock held. It gets the hbalock to access and update SLI data
+ * service routine when device with SLI-3 interface spec is enabled with
+ * MSI-X multi-message interrupt mode and there are slow-path events in
+ * the HBA. However, when the device is enabled with either MSI or Pin-IRQ
+ * interrupt mode, this function is called as part of the device-level
+ * interrupt handler. When the PCI slot is in error recovery or the HBA
+ * is undergoing initialization, the interrupt handler will not process
+ * the interrupt. The link attention and ELS ring attention events are
+ * handled by the worker thread. The interrupt handler signals the worker
+ * thread and returns for these events. This function is called without
+ * any lock held. It gets the hbalock to access and update SLI data
  * structures.
  *
  * This function returns IRQ_HANDLED when interrupt is handled else it
  * returns IRQ_NONE.
  **/
 irqreturn_t
-lpfc_sp_intr_handler(int irq, void *dev_id)
+lpfc_sli_sp_intr_handler(int irq, void *dev_id)
 {
        struct lpfc_hba  *phba;
        uint32_t ha_copy;
@@ -5240,13 +7714,8 @@ lpfc_sp_intr_handler(int irq, void *dev_id)
         * individual interrupt handler in MSI-X multi-message interrupt mode
         */
        if (phba->intr_type == MSIX) {
-               /* If the pci channel is offline, ignore all the interrupts */
-               if (unlikely(pci_channel_offline(phba->pcidev)))
-                       return IRQ_NONE;
-               /* Update device-level interrupt statistics */
-               phba->sli.slistat.sli_intr++;
-               /* Ignore all interrupts during initialization. */
-               if (unlikely(phba->link_state < LPFC_LINK_DOWN))
+               /* Check device state for handling interrupt */
+               if (lpfc_intr_state_check(phba))
                        return IRQ_NONE;
                /* Need to read HA REG for slow-path events */
                spin_lock_irqsave(&phba->hbalock, iflag);
@@ -5271,7 +7740,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id)
                 * interrupt.
                 */
                if (unlikely(phba->hba_flag & DEFER_ERATT)) {
-                       spin_unlock_irq(&phba->hbalock);
+                       spin_unlock_irqrestore(&phba->hbalock, iflag);
                        return IRQ_NONE;
                }
 
@@ -5364,7 +7833,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id)
 
                if ((work_ha_copy & HA_MBATT) && (phba->sli.mbox_active)) {
                        pmb = phba->sli.mbox_active;
-                       pmbox = &pmb->mb;
+                       pmbox = &pmb->u.mb;
                        mbox = phba->mbox;
                        vport = pmb->vport;
 
@@ -5434,7 +7903,8 @@ lpfc_sp_intr_handler(int irq, void *dev_id)
                                                        LOG_MBOX | LOG_SLI,
                                                        "0350 rc should have"
                                                        "been MBX_BUSY");
-                                               goto send_current_mbox;
+                                               if (rc != MBX_NOT_FINISHED)
+                                                       goto send_current_mbox;
                                        }
                                }
                                spin_lock_irqsave(
@@ -5471,29 +7941,29 @@ send_current_mbox:
        }
        return IRQ_HANDLED;
 
-} /* lpfc_sp_intr_handler */
+} /* lpfc_sli_sp_intr_handler */
 
 /**
- * lpfc_fp_intr_handler - The fast-path interrupt handler of lpfc driver
+ * lpfc_sli_fp_intr_handler - Fast-path interrupt handler to SLI-3 device.
  * @irq: Interrupt number.
  * @dev_id: The device context pointer.
  *
  * This function is directly called from the PCI layer as an interrupt
- * service routine when the device is enabled with MSI-X multi-message
- * interrupt mode and there is a fast-path FCP IOCB ring event in the
- * HBA. However, when the device is enabled with either MSI or Pin-IRQ
- * interrupt mode, this function is called as part of the device-level
- * interrupt handler. When the PCI slot is in error recovery or the HBA
- * is undergoing initialization, the interrupt handler will not process
- * the interrupt. The SCSI FCP fast-path ring event are handled in the
- * intrrupt context. This function is called without any lock held. It
- * gets the hbalock to access and update SLI data structures.
+ * service routine when device with SLI-3 interface spec is enabled with
+ * MSI-X multi-message interrupt mode and there is a fast-path FCP IOCB
+ * ring event in the HBA. However, when the device is enabled with either
+ * MSI or Pin-IRQ interrupt mode, this function is called as part of the
+ * device-level interrupt handler. When the PCI slot is in error recovery
+ * or the HBA is undergoing initialization, the interrupt handler will not
+ * process the interrupt. The SCSI FCP fast-path ring event are handled in
+ * the intrrupt context. This function is called without any lock held.
+ * It gets the hbalock to access and update SLI data structures.
  *
  * This function returns IRQ_HANDLED when interrupt is handled else it
  * returns IRQ_NONE.
  **/
 irqreturn_t
-lpfc_fp_intr_handler(int irq, void *dev_id)
+lpfc_sli_fp_intr_handler(int irq, void *dev_id)
 {
        struct lpfc_hba  *phba;
        uint32_t ha_copy;
@@ -5513,13 +7983,8 @@ lpfc_fp_intr_handler(int irq, void *dev_id)
         * individual interrupt handler in MSI-X multi-message interrupt mode
         */
        if (phba->intr_type == MSIX) {
-               /* If pci channel is offline, ignore all the interrupts */
-               if (unlikely(pci_channel_offline(phba->pcidev)))
-                       return IRQ_NONE;
-               /* Update device-level interrupt statistics */
-               phba->sli.slistat.sli_intr++;
-               /* Ignore all interrupts during initialization. */
-               if (unlikely(phba->link_state < LPFC_LINK_DOWN))
+               /* Check device state for handling interrupt */
+               if (lpfc_intr_state_check(phba))
                        return IRQ_NONE;
                /* Need to read HA REG for FCP ring and other ring events */
                ha_copy = readl(phba->HAregaddr);
@@ -5530,7 +7995,7 @@ lpfc_fp_intr_handler(int irq, void *dev_id)
                 * any interrupt.
                 */
                if (unlikely(phba->hba_flag & DEFER_ERATT)) {
-                       spin_unlock_irq(&phba->hbalock);
+                       spin_unlock_irqrestore(&phba->hbalock, iflag);
                        return IRQ_NONE;
                }
                writel((ha_copy & (HA_R0_CLR_MSK | HA_R1_CLR_MSK)),
@@ -5566,26 +8031,27 @@ lpfc_fp_intr_handler(int irq, void *dev_id)
                }
        }
        return IRQ_HANDLED;
-}  /* lpfc_fp_intr_handler */
+}  /* lpfc_sli_fp_intr_handler */
 
 /**
- * lpfc_intr_handler - The device-level interrupt handler of lpfc driver
+ * lpfc_sli_intr_handler - Device-level interrupt handler to SLI-3 device
  * @irq: Interrupt number.
  * @dev_id: The device context pointer.
  *
- * This function is the device-level interrupt handler called from the PCI
- * layer when either MSI or Pin-IRQ interrupt mode is enabled and there is
- * an event in the HBA which requires driver attention. This function
- * invokes the slow-path interrupt attention handling function and fast-path
- * interrupt attention handling function in turn to process the relevant
- * HBA attention events. This function is called without any lock held. It
- * gets the hbalock to access and update SLI data structures.
+ * This function is the HBA device-level interrupt handler to device with
+ * SLI-3 interface spec, called from the PCI layer when either MSI or
+ * Pin-IRQ interrupt mode is enabled and there is an event in the HBA which
+ * requires driver attention. This function invokes the slow-path interrupt
+ * attention handling function and fast-path interrupt attention handling
+ * function in turn to process the relevant HBA attention events. This
+ * function is called without any lock held. It gets the hbalock to access
+ * and update SLI data structures.
  *
  * This function returns IRQ_HANDLED when interrupt is handled, else it
  * returns IRQ_NONE.
  **/
 irqreturn_t
-lpfc_intr_handler(int irq, void *dev_id)
+lpfc_sli_intr_handler(int irq, void *dev_id)
 {
        struct lpfc_hba  *phba;
        irqreturn_t sp_irq_rc, fp_irq_rc;
@@ -5600,15 +8066,8 @@ lpfc_intr_handler(int irq, void *dev_id)
        if (unlikely(!phba))
                return IRQ_NONE;
 
-       /* If the pci channel is offline, ignore all the interrupts. */
-       if (unlikely(pci_channel_offline(phba->pcidev)))
-               return IRQ_NONE;
-
-       /* Update device level interrupt statistics */
-       phba->sli.slistat.sli_intr++;
-
-       /* Ignore all interrupts during initialization. */
-       if (unlikely(phba->link_state < LPFC_LINK_DOWN))
+       /* Check device state for handling interrupt */
+       if (lpfc_intr_state_check(phba))
                return IRQ_NONE;
 
        spin_lock(&phba->hbalock);
@@ -5650,7 +8109,7 @@ lpfc_intr_handler(int irq, void *dev_id)
        status2 >>= (4*LPFC_ELS_RING);
 
        if (status1 || (status2 & HA_RXMASK))
-               sp_irq_rc = lpfc_sp_intr_handler(irq, dev_id);
+               sp_irq_rc = lpfc_sli_sp_intr_handler(irq, dev_id);
        else
                sp_irq_rc = IRQ_NONE;
 
@@ -5670,10 +8129,3322 @@ lpfc_intr_handler(int irq, void *dev_id)
                status2 = 0;
 
        if ((status1 & HA_RXMASK) || (status2 & HA_RXMASK))
-               fp_irq_rc = lpfc_fp_intr_handler(irq, dev_id);
+               fp_irq_rc = lpfc_sli_fp_intr_handler(irq, dev_id);
        else
                fp_irq_rc = IRQ_NONE;
 
        /* Return device-level interrupt handling status */
        return (sp_irq_rc == IRQ_HANDLED) ? sp_irq_rc : fp_irq_rc;
-}  /* lpfc_intr_handler */
+}  /* lpfc_sli_intr_handler */
+
+/**
+ * lpfc_sli4_fcp_xri_abort_event_proc - Process fcp xri abort event
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked by the worker thread to process all the pending
+ * SLI4 FCP abort XRI events.
+ **/
+void lpfc_sli4_fcp_xri_abort_event_proc(struct lpfc_hba *phba)
+{
+       struct lpfc_cq_event *cq_event;
+
+       /* First, declare the fcp xri abort event has been handled */
+       spin_lock_irq(&phba->hbalock);
+       phba->hba_flag &= ~FCP_XRI_ABORT_EVENT;
+       spin_unlock_irq(&phba->hbalock);
+       /* Now, handle all the fcp xri abort events */
+       while (!list_empty(&phba->sli4_hba.sp_fcp_xri_aborted_work_queue)) {
+               /* Get the first event from the head of the event queue */
+               spin_lock_irq(&phba->hbalock);
+               list_remove_head(&phba->sli4_hba.sp_fcp_xri_aborted_work_queue,
+                                cq_event, struct lpfc_cq_event, list);
+               spin_unlock_irq(&phba->hbalock);
+               /* Notify aborted XRI for FCP work queue */
+               lpfc_sli4_fcp_xri_aborted(phba, &cq_event->cqe.wcqe_axri);
+               /* Free the event processed back to the free pool */
+               lpfc_sli4_cq_event_release(phba, cq_event);
+       }
+}
+
+/**
+ * lpfc_sli4_els_xri_abort_event_proc - Process els xri abort event
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked by the worker thread to process all the pending
+ * SLI4 els abort xri events.
+ **/
+void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *phba)
+{
+       struct lpfc_cq_event *cq_event;
+
+       /* First, declare the els xri abort event has been handled */
+       spin_lock_irq(&phba->hbalock);
+       phba->hba_flag &= ~ELS_XRI_ABORT_EVENT;
+       spin_unlock_irq(&phba->hbalock);
+       /* Now, handle all the els xri abort events */
+       while (!list_empty(&phba->sli4_hba.sp_els_xri_aborted_work_queue)) {
+               /* Get the first event from the head of the event queue */
+               spin_lock_irq(&phba->hbalock);
+               list_remove_head(&phba->sli4_hba.sp_els_xri_aborted_work_queue,
+                                cq_event, struct lpfc_cq_event, list);
+               spin_unlock_irq(&phba->hbalock);
+               /* Notify aborted XRI for ELS work queue */
+               lpfc_sli4_els_xri_aborted(phba, &cq_event->cqe.wcqe_axri);
+               /* Free the event processed back to the free pool */
+               lpfc_sli4_cq_event_release(phba, cq_event);
+       }
+}
+
+static void
+lpfc_sli4_iocb_param_transfer(struct lpfc_iocbq *pIocbIn,
+                             struct lpfc_iocbq *pIocbOut,
+                             struct lpfc_wcqe_complete *wcqe)
+{
+       size_t offset = offsetof(struct lpfc_iocbq, iocb);
+
+       memcpy((char *)pIocbIn + offset, (char *)pIocbOut + offset,
+              sizeof(struct lpfc_iocbq) - offset);
+       memset(&pIocbIn->sli4_info, 0,
+              sizeof(struct lpfc_sli4_rspiocb_info));
+       /* Map WCQE parameters into irspiocb parameters */
+       pIocbIn->iocb.ulpStatus = bf_get(lpfc_wcqe_c_status, wcqe);
+       if (pIocbOut->iocb_flag & LPFC_IO_FCP)
+               if (pIocbIn->iocb.ulpStatus == IOSTAT_FCP_RSP_ERROR)
+                       pIocbIn->iocb.un.fcpi.fcpi_parm =
+                                       pIocbOut->iocb.un.fcpi.fcpi_parm -
+                                       wcqe->total_data_placed;
+               else
+                       pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter;
+       else
+               pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter;
+       /* Load in additional WCQE parameters */
+       pIocbIn->sli4_info.hw_status = bf_get(lpfc_wcqe_c_hw_status, wcqe);
+       pIocbIn->sli4_info.bfield = 0;
+       if (bf_get(lpfc_wcqe_c_xb, wcqe))
+               pIocbIn->sli4_info.bfield |= LPFC_XB;
+       if (bf_get(lpfc_wcqe_c_pv, wcqe)) {
+               pIocbIn->sli4_info.bfield |= LPFC_PV;
+               pIocbIn->sli4_info.priority =
+                                       bf_get(lpfc_wcqe_c_priority, wcqe);
+       }
+}
+
+/**
+ * lpfc_sli4_sp_handle_async_event - Handle an asynchroous event
+ * @phba: Pointer to HBA context object.
+ * @cqe: Pointer to mailbox completion queue entry.
+ *
+ * This routine process a mailbox completion queue entry with asynchrous
+ * event.
+ *
+ * Return: true if work posted to worker thread, otherwise false.
+ **/
+static bool
+lpfc_sli4_sp_handle_async_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe)
+{
+       struct lpfc_cq_event *cq_event;
+       unsigned long iflags;
+
+       lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+                       "0392 Async Event: word0:x%x, word1:x%x, "
+                       "word2:x%x, word3:x%x\n", mcqe->word0,
+                       mcqe->mcqe_tag0, mcqe->mcqe_tag1, mcqe->trailer);
+
+       /* Allocate a new internal CQ_EVENT entry */
+       cq_event = lpfc_sli4_cq_event_alloc(phba);
+       if (!cq_event) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "0394 Failed to allocate CQ_EVENT entry\n");
+               return false;
+       }
+
+       /* Move the CQE into an asynchronous event entry */
+       memcpy(&cq_event->cqe, mcqe, sizeof(struct lpfc_mcqe));
+       spin_lock_irqsave(&phba->hbalock, iflags);
+       list_add_tail(&cq_event->list, &phba->sli4_hba.sp_asynce_work_queue);
+       /* Set the async event flag */
+       phba->hba_flag |= ASYNC_EVENT;
+       spin_unlock_irqrestore(&phba->hbalock, iflags);
+
+       return true;
+}
+
+/**
+ * lpfc_sli4_sp_handle_mbox_event - Handle a mailbox completion event
+ * @phba: Pointer to HBA context object.
+ * @cqe: Pointer to mailbox completion queue entry.
+ *
+ * This routine process a mailbox completion queue entry with mailbox
+ * completion event.
+ *
+ * Return: true if work posted to worker thread, otherwise false.
+ **/
+static bool
+lpfc_sli4_sp_handle_mbox_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe)
+{
+       uint32_t mcqe_status;
+       MAILBOX_t *mbox, *pmbox;
+       struct lpfc_mqe *mqe;
+       struct lpfc_vport *vport;
+       struct lpfc_nodelist *ndlp;
+       struct lpfc_dmabuf *mp;
+       unsigned long iflags;
+       LPFC_MBOXQ_t *pmb;
+       bool workposted = false;
+       int rc;
+
+       /* If not a mailbox complete MCQE, out by checking mailbox consume */
+       if (!bf_get(lpfc_trailer_completed, mcqe))
+               goto out_no_mqe_complete;
+
+       /* Get the reference to the active mbox command */
+       spin_lock_irqsave(&phba->hbalock, iflags);
+       pmb = phba->sli.mbox_active;
+       if (unlikely(!pmb)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+                               "1832 No pending MBOX command to handle\n");
+               spin_unlock_irqrestore(&phba->hbalock, iflags);
+               goto out_no_mqe_complete;
+       }
+       spin_unlock_irqrestore(&phba->hbalock, iflags);
+       mqe = &pmb->u.mqe;
+       pmbox = (MAILBOX_t *)&pmb->u.mqe;
+       mbox = phba->mbox;
+       vport = pmb->vport;
+
+       /* Reset heartbeat timer */
+       phba->last_completion_time = jiffies;
+       del_timer(&phba->sli.mbox_tmo);
+
+       /* Move mbox data to caller's mailbox region, do endian swapping */
+       if (pmb->mbox_cmpl && mbox)
+               lpfc_sli_pcimem_bcopy(mbox, mqe, sizeof(struct lpfc_mqe));
+       /* Set the mailbox status with SLI4 range 0x4000 */
+       mcqe_status = bf_get(lpfc_mcqe_status, mcqe);
+       if (mcqe_status != MB_CQE_STATUS_SUCCESS)
+               bf_set(lpfc_mqe_status, mqe,
+                      (LPFC_MBX_ERROR_RANGE | mcqe_status));
+
+       if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) {
+               pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG;
+               lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_MBOX_VPORT,
+                                     "MBOX dflt rpi: status:x%x rpi:x%x",
+                                     mcqe_status,
+                                     pmbox->un.varWords[0], 0);
+               if (mcqe_status == MB_CQE_STATUS_SUCCESS) {
+                       mp = (struct lpfc_dmabuf *)(pmb->context1);
+                       ndlp = (struct lpfc_nodelist *)pmb->context2;
+                       /* Reg_LOGIN of dflt RPI was successful. Now lets get
+                        * RID of the PPI using the same mbox buffer.
+                        */
+                       lpfc_unreg_login(phba, vport->vpi,
+                                        pmbox->un.varWords[0], pmb);
+                       pmb->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi;
+                       pmb->context1 = mp;
+                       pmb->context2 = ndlp;
+                       pmb->vport = vport;
+                       rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+                       if (rc != MBX_BUSY)
+                               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX |
+                                               LOG_SLI, "0385 rc should "
+                                               "have been MBX_BUSY\n");
+                       if (rc != MBX_NOT_FINISHED)
+                               goto send_current_mbox;
+               }
+       }
+       spin_lock_irqsave(&phba->pport->work_port_lock, iflags);
+       phba->pport->work_port_events &= ~WORKER_MBOX_TMO;
+       spin_unlock_irqrestore(&phba->pport->work_port_lock, iflags);
+
+       /* There is mailbox completion work to do */
+       spin_lock_irqsave(&phba->hbalock, iflags);
+       __lpfc_mbox_cmpl_put(phba, pmb);
+       phba->work_ha |= HA_MBATT;
+       spin_unlock_irqrestore(&phba->hbalock, iflags);
+       workposted = true;
+
+send_current_mbox:
+       spin_lock_irqsave(&phba->hbalock, iflags);
+       /* Release the mailbox command posting token */
+       phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+       /* Setting active mailbox pointer need to be in sync to flag clear */
+       phba->sli.mbox_active = NULL;
+       spin_unlock_irqrestore(&phba->hbalock, iflags);
+       /* Wake up worker thread to post the next pending mailbox command */
+       lpfc_worker_wake_up(phba);
+out_no_mqe_complete:
+       if (bf_get(lpfc_trailer_consumed, mcqe))
+               lpfc_sli4_mq_release(phba->sli4_hba.mbx_wq);
+       return workposted;
+}
+
+/**
+ * lpfc_sli4_sp_handle_mcqe - Process a mailbox completion queue entry
+ * @phba: Pointer to HBA context object.
+ * @cqe: Pointer to mailbox completion queue entry.
+ *
+ * This routine process a mailbox completion queue entry, it invokes the
+ * proper mailbox complete handling or asynchrous event handling routine
+ * according to the MCQE's async bit.
+ *
+ * Return: true if work posted to worker thread, otherwise false.
+ **/
+static bool
+lpfc_sli4_sp_handle_mcqe(struct lpfc_hba *phba, struct lpfc_cqe *cqe)
+{
+       struct lpfc_mcqe mcqe;
+       bool workposted;
+
+       /* Copy the mailbox MCQE and convert endian order as needed */
+       lpfc_sli_pcimem_bcopy(cqe, &mcqe, sizeof(struct lpfc_mcqe));
+
+       /* Invoke the proper event handling routine */
+       if (!bf_get(lpfc_trailer_async, &mcqe))
+               workposted = lpfc_sli4_sp_handle_mbox_event(phba, &mcqe);
+       else
+               workposted = lpfc_sli4_sp_handle_async_event(phba, &mcqe);
+       return workposted;
+}
+
+/**
+ * lpfc_sli4_sp_handle_els_wcqe - Handle els work-queue completion event
+ * @phba: Pointer to HBA context object.
+ * @wcqe: Pointer to work-queue completion queue entry.
+ *
+ * This routine handles an ELS work-queue completion event.
+ *
+ * Return: true if work posted to worker thread, otherwise false.
+ **/
+static bool
+lpfc_sli4_sp_handle_els_wcqe(struct lpfc_hba *phba,
+                            struct lpfc_wcqe_complete *wcqe)
+{
+       struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+       struct lpfc_iocbq *cmdiocbq;
+       struct lpfc_iocbq *irspiocbq;
+       unsigned long iflags;
+       bool workposted = false;
+
+       spin_lock_irqsave(&phba->hbalock, iflags);
+       pring->stats.iocb_event++;
+       /* Look up the ELS command IOCB and create pseudo response IOCB */
+       cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring,
+                               bf_get(lpfc_wcqe_c_request_tag, wcqe));
+       spin_unlock_irqrestore(&phba->hbalock, iflags);
+
+       if (unlikely(!cmdiocbq)) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+                               "0386 ELS complete with no corresponding "
+                               "cmdiocb: iotag (%d)\n",
+                               bf_get(lpfc_wcqe_c_request_tag, wcqe));
+               return workposted;
+       }
+
+       /* Fake the irspiocbq and copy necessary response information */
+       irspiocbq = lpfc_sli_get_iocbq(phba);
+       if (!irspiocbq) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "0387 Failed to allocate an iocbq\n");
+               return workposted;
+       }
+       lpfc_sli4_iocb_param_transfer(irspiocbq, cmdiocbq, wcqe);
+
+       /* Add the irspiocb to the response IOCB work list */
+       spin_lock_irqsave(&phba->hbalock, iflags);
+       list_add_tail(&irspiocbq->list, &phba->sli4_hba.sp_rspiocb_work_queue);
+       /* Indicate ELS ring attention */
+       phba->work_ha |= (HA_R0ATT << (4*LPFC_ELS_RING));
+       spin_unlock_irqrestore(&phba->hbalock, iflags);
+       workposted = true;
+
+       return workposted;
+}
+
+/**
+ * lpfc_sli4_sp_handle_rel_wcqe - Handle slow-path WQ entry consumed event
+ * @phba: Pointer to HBA context object.
+ * @wcqe: Pointer to work-queue completion queue entry.
+ *
+ * This routine handles slow-path WQ entry comsumed event by invoking the
+ * proper WQ release routine to the slow-path WQ.
+ **/
+static void
+lpfc_sli4_sp_handle_rel_wcqe(struct lpfc_hba *phba,
+                            struct lpfc_wcqe_release *wcqe)
+{
+       /* Check for the slow-path ELS work queue */
+       if (bf_get(lpfc_wcqe_r_wq_id, wcqe) == phba->sli4_hba.els_wq->queue_id)
+               lpfc_sli4_wq_release(phba->sli4_hba.els_wq,
+                                    bf_get(lpfc_wcqe_r_wqe_index, wcqe));
+       else
+               lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+                               "2579 Slow-path wqe consume event carries "
+                               "miss-matched qid: wcqe-qid=x%x, sp-qid=x%x\n",
+                               bf_get(lpfc_wcqe_r_wqe_index, wcqe),
+                               phba->sli4_hba.els_wq->queue_id);
+}
+
+/**
+ * lpfc_sli4_sp_handle_abort_xri_wcqe - Handle a xri abort event
+ * @phba: Pointer to HBA context object.
+ * @cq: Pointer to a WQ completion queue.
+ * @wcqe: Pointer to work-queue completion queue entry.
+ *
+ * This routine handles an XRI abort event.
+ *
+ * Return: true if work posted to worker thread, otherwise false.
+ **/
+static bool
+lpfc_sli4_sp_handle_abort_xri_wcqe(struct lpfc_hba *phba,
+                                  struct lpfc_queue *cq,
+                                  struct sli4_wcqe_xri_aborted *wcqe)
+{
+       bool workposted = false;
+       struct lpfc_cq_event *cq_event;
+       unsigned long iflags;
+
+       /* Allocate a new internal CQ_EVENT entry */
+       cq_event = lpfc_sli4_cq_event_alloc(phba);
+       if (!cq_event) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "0602 Failed to allocate CQ_EVENT entry\n");
+               return false;
+       }
+
+       /* Move the CQE into the proper xri abort event list */
+       memcpy(&cq_event->cqe, wcqe, sizeof(struct sli4_wcqe_xri_aborted));
+       switch (cq->subtype) {
+       case LPFC_FCP:
+               spin_lock_irqsave(&phba->hbalock, iflags);
+               list_add_tail(&cq_event->list,
+                             &phba->sli4_hba.sp_fcp_xri_aborted_work_queue);
+               /* Set the fcp xri abort event flag */
+               phba->hba_flag |= FCP_XRI_ABORT_EVENT;
+               spin_unlock_irqrestore(&phba->hbalock, iflags);
+               workposted = true;
+               break;
+       case LPFC_ELS:
+               spin_lock_irqsave(&phba->hbalock, iflags);
+               list_add_tail(&cq_event->list,
+                             &phba->sli4_hba.sp_els_xri_aborted_work_queue);
+               /* Set the els xri abort event flag */
+               phba->hba_flag |= ELS_XRI_ABORT_EVENT;
+               spin_unlock_irqrestore(&phba->hbalock, iflags);
+               workposted = true;
+               break;
+       default:
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "0603 Invalid work queue CQE subtype (x%x)\n",
+                               cq->subtype);
+               workposted = false;
+               break;
+       }
+       return workposted;
+}
+
+/**
+ * lpfc_sli4_sp_handle_wcqe - Process a work-queue completion queue entry
+ * @phba: Pointer to HBA context object.
+ * @cq: Pointer to the completion queue.
+ * @wcqe: Pointer to a completion queue entry.
+ *
+ * This routine process a slow-path work-queue completion queue entry.
+ *
+ * Return: true if work posted to worker thread, otherwise false.
+ **/
+static bool
+lpfc_sli4_sp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
+                        struct lpfc_cqe *cqe)
+{
+       struct lpfc_wcqe_complete wcqe;
+       bool workposted = false;
+
+       /* Copy the work queue CQE and convert endian order if needed */
+       lpfc_sli_pcimem_bcopy(cqe, &wcqe, sizeof(struct lpfc_cqe));
+
+       /* Check and process for different type of WCQE and dispatch */
+       switch (bf_get(lpfc_wcqe_c_code, &wcqe)) {
+       case CQE_CODE_COMPL_WQE:
+               /* Process the WQ complete event */
+               workposted = lpfc_sli4_sp_handle_els_wcqe(phba,
+                                       (struct lpfc_wcqe_complete *)&wcqe);
+               break;
+       case CQE_CODE_RELEASE_WQE:
+               /* Process the WQ release event */
+               lpfc_sli4_sp_handle_rel_wcqe(phba,
+                                       (struct lpfc_wcqe_release *)&wcqe);
+               break;
+       case CQE_CODE_XRI_ABORTED:
+               /* Process the WQ XRI abort event */
+               workposted = lpfc_sli4_sp_handle_abort_xri_wcqe(phba, cq,
+                                       (struct sli4_wcqe_xri_aborted *)&wcqe);
+               break;
+       default:
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "0388 Not a valid WCQE code: x%x\n",
+                               bf_get(lpfc_wcqe_c_code, &wcqe));
+               break;
+       }
+       return workposted;
+}
+
+/**
+ * lpfc_sli4_sp_handle_rcqe - Process a receive-queue completion queue entry
+ * @phba: Pointer to HBA context object.
+ * @rcqe: Pointer to receive-queue completion queue entry.
+ *
+ * This routine process a receive-queue completion queue entry.
+ *
+ * Return: true if work posted to worker thread, otherwise false.
+ **/
+static bool
+lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_cqe *cqe)
+{
+       struct lpfc_rcqe rcqe;
+       bool workposted = false;
+       struct lpfc_queue *hrq = phba->sli4_hba.hdr_rq;
+       struct lpfc_queue *drq = phba->sli4_hba.dat_rq;
+       struct hbq_dmabuf *dma_buf;
+       uint32_t status;
+       unsigned long iflags;
+
+       /* Copy the receive queue CQE and convert endian order if needed */
+       lpfc_sli_pcimem_bcopy(cqe, &rcqe, sizeof(struct lpfc_rcqe));
+       lpfc_sli4_rq_release(hrq, drq);
+       if (bf_get(lpfc_rcqe_code, &rcqe) != CQE_CODE_RECEIVE)
+               goto out;
+       if (bf_get(lpfc_rcqe_rq_id, &rcqe) != hrq->queue_id)
+               goto out;
+
+       status = bf_get(lpfc_rcqe_status, &rcqe);
+       switch (status) {
+       case FC_STATUS_RQ_BUF_LEN_EXCEEDED:
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "2537 Receive Frame Truncated!!\n");
+       case FC_STATUS_RQ_SUCCESS:
+               spin_lock_irqsave(&phba->hbalock, iflags);
+               dma_buf = lpfc_sli_hbqbuf_get(&phba->hbqs[0].hbq_buffer_list);
+               if (!dma_buf) {
+                       spin_unlock_irqrestore(&phba->hbalock, iflags);
+                       goto out;
+               }
+               memcpy(&dma_buf->rcqe, &rcqe, sizeof(rcqe));
+               /* save off the frame for the word thread to process */
+               list_add_tail(&dma_buf->dbuf.list, &phba->rb_pend_list);
+               /* Frame received */
+               phba->hba_flag |= HBA_RECEIVE_BUFFER;
+               spin_unlock_irqrestore(&phba->hbalock, iflags);
+               workposted = true;
+               break;
+       case FC_STATUS_INSUFF_BUF_NEED_BUF:
+       case FC_STATUS_INSUFF_BUF_FRM_DISC:
+               /* Post more buffers if possible */
+               spin_lock_irqsave(&phba->hbalock, iflags);
+               phba->hba_flag |= HBA_POST_RECEIVE_BUFFER;
+               spin_unlock_irqrestore(&phba->hbalock, iflags);
+               workposted = true;
+               break;
+       }
+out:
+       return workposted;
+
+}
+
+/**
+ * lpfc_sli4_sp_handle_eqe - Process a slow-path event queue entry
+ * @phba: Pointer to HBA context object.
+ * @eqe: Pointer to fast-path event queue entry.
+ *
+ * This routine process a event queue entry from the slow-path event queue.
+ * It will check the MajorCode and MinorCode to determine this is for a
+ * completion event on a completion queue, if not, an error shall be logged
+ * and just return. Otherwise, it will get to the corresponding completion
+ * queue and process all the entries on that completion queue, rearm the
+ * completion queue, and then return.
+ *
+ **/
+static void
+lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe)
+{
+       struct lpfc_queue *cq = NULL, *childq, *speq;
+       struct lpfc_cqe *cqe;
+       bool workposted = false;
+       int ecount = 0;
+       uint16_t cqid;
+
+       if (bf_get(lpfc_eqe_major_code, eqe) != 0 ||
+           bf_get(lpfc_eqe_minor_code, eqe) != 0) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "0359 Not a valid slow-path completion "
+                               "event: majorcode=x%x, minorcode=x%x\n",
+                               bf_get(lpfc_eqe_major_code, eqe),
+                               bf_get(lpfc_eqe_minor_code, eqe));
+               return;
+       }
+
+       /* Get the reference to the corresponding CQ */
+       cqid = bf_get(lpfc_eqe_resource_id, eqe);
+
+       /* Search for completion queue pointer matching this cqid */
+       speq = phba->sli4_hba.sp_eq;
+       list_for_each_entry(childq, &speq->child_list, list) {
+               if (childq->queue_id == cqid) {
+                       cq = childq;
+                       break;
+               }
+       }
+       if (unlikely(!cq)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "0365 Slow-path CQ identifier (%d) does "
+                               "not exist\n", cqid);
+               return;
+       }
+
+       /* Process all the entries to the CQ */
+       switch (cq->type) {
+       case LPFC_MCQ:
+               while ((cqe = lpfc_sli4_cq_get(cq))) {
+                       workposted |= lpfc_sli4_sp_handle_mcqe(phba, cqe);
+                       if (!(++ecount % LPFC_GET_QE_REL_INT))
+                               lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM);
+               }
+               break;
+       case LPFC_WCQ:
+               while ((cqe = lpfc_sli4_cq_get(cq))) {
+                       workposted |= lpfc_sli4_sp_handle_wcqe(phba, cq, cqe);
+                       if (!(++ecount % LPFC_GET_QE_REL_INT))
+                               lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM);
+               }
+               break;
+       case LPFC_RCQ:
+               while ((cqe = lpfc_sli4_cq_get(cq))) {
+                       workposted |= lpfc_sli4_sp_handle_rcqe(phba, cqe);
+                       if (!(++ecount % LPFC_GET_QE_REL_INT))
+                               lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM);
+               }
+               break;
+       default:
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "0370 Invalid completion queue type (%d)\n",
+                               cq->type);
+               return;
+       }
+
+       /* Catch the no cq entry condition, log an error */
+       if (unlikely(ecount == 0))
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "0371 No entry from the CQ: identifier "
+                               "(x%x), type (%d)\n", cq->queue_id, cq->type);
+
+       /* In any case, flash and re-arm the RCQ */
+       lpfc_sli4_cq_release(cq, LPFC_QUEUE_REARM);
+
+       /* wake up worker thread if there are works to be done */
+       if (workposted)
+               lpfc_worker_wake_up(phba);
+}
+
+/**
+ * lpfc_sli4_fp_handle_fcp_wcqe - Process fast-path work queue completion entry
+ * @eqe: Pointer to fast-path completion queue entry.
+ *
+ * This routine process a fast-path work queue completion entry from fast-path
+ * event queue for FCP command response completion.
+ **/
+static void
+lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba,
+                            struct lpfc_wcqe_complete *wcqe)
+{
+       struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_FCP_RING];
+       struct lpfc_iocbq *cmdiocbq;
+       struct lpfc_iocbq irspiocbq;
+       unsigned long iflags;
+
+       spin_lock_irqsave(&phba->hbalock, iflags);
+       pring->stats.iocb_event++;
+       spin_unlock_irqrestore(&phba->hbalock, iflags);
+
+       /* Check for response status */
+       if (unlikely(bf_get(lpfc_wcqe_c_status, wcqe))) {
+               /* If resource errors reported from HBA, reduce queue
+                * depth of the SCSI device.
+                */
+               if ((bf_get(lpfc_wcqe_c_status, wcqe) ==
+                    IOSTAT_LOCAL_REJECT) &&
+                   (wcqe->parameter == IOERR_NO_RESOURCES)) {
+                       phba->lpfc_rampdown_queue_depth(phba);
+               }
+               /* Log the error status */
+               lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+                               "0373 FCP complete error: status=x%x, "
+                               "hw_status=x%x, total_data_specified=%d, "
+                               "parameter=x%x, word3=x%x\n",
+                               bf_get(lpfc_wcqe_c_status, wcqe),
+                               bf_get(lpfc_wcqe_c_hw_status, wcqe),
+                               wcqe->total_data_placed, wcqe->parameter,
+                               wcqe->word3);
+       }
+
+       /* Look up the FCP command IOCB and create pseudo response IOCB */
+       spin_lock_irqsave(&phba->hbalock, iflags);
+       cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring,
+                               bf_get(lpfc_wcqe_c_request_tag, wcqe));
+       spin_unlock_irqrestore(&phba->hbalock, iflags);
+       if (unlikely(!cmdiocbq)) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+                               "0374 FCP complete with no corresponding "
+                               "cmdiocb: iotag (%d)\n",
+                               bf_get(lpfc_wcqe_c_request_tag, wcqe));
+               return;
+       }
+       if (unlikely(!cmdiocbq->iocb_cmpl)) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+                               "0375 FCP cmdiocb not callback function "
+                               "iotag: (%d)\n",
+                               bf_get(lpfc_wcqe_c_request_tag, wcqe));
+               return;
+       }
+
+       /* Fake the irspiocb and copy necessary response information */
+       lpfc_sli4_iocb_param_transfer(&irspiocbq, cmdiocbq, wcqe);
+
+       /* Pass the cmd_iocb and the rsp state to the upper layer */
+       (cmdiocbq->iocb_cmpl)(phba, cmdiocbq, &irspiocbq);
+}
+
+/**
+ * lpfc_sli4_fp_handle_rel_wcqe - Handle fast-path WQ entry consumed event
+ * @phba: Pointer to HBA context object.
+ * @cq: Pointer to completion queue.
+ * @wcqe: Pointer to work-queue completion queue entry.
+ *
+ * This routine handles an fast-path WQ entry comsumed event by invoking the
+ * proper WQ release routine to the slow-path WQ.
+ **/
+static void
+lpfc_sli4_fp_handle_rel_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
+                            struct lpfc_wcqe_release *wcqe)
+{
+       struct lpfc_queue *childwq;
+       bool wqid_matched = false;
+       uint16_t fcp_wqid;
+
+       /* Check for fast-path FCP work queue release */
+       fcp_wqid = bf_get(lpfc_wcqe_r_wq_id, wcqe);
+       list_for_each_entry(childwq, &cq->child_list, list) {
+               if (childwq->queue_id == fcp_wqid) {
+                       lpfc_sli4_wq_release(childwq,
+                                       bf_get(lpfc_wcqe_r_wqe_index, wcqe));
+                       wqid_matched = true;
+                       break;
+               }
+       }
+       /* Report warning log message if no match found */
+       if (wqid_matched != true)
+               lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+                               "2580 Fast-path wqe consume event carries "
+                               "miss-matched qid: wcqe-qid=x%x\n", fcp_wqid);
+}
+
+/**
+ * lpfc_sli4_fp_handle_wcqe - Process fast-path work queue completion entry
+ * @cq: Pointer to the completion queue.
+ * @eqe: Pointer to fast-path completion queue entry.
+ *
+ * This routine process a fast-path work queue completion entry from fast-path
+ * event queue for FCP command response completion.
+ **/
+static int
+lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
+                        struct lpfc_cqe *cqe)
+{
+       struct lpfc_wcqe_release wcqe;
+       bool workposted = false;
+
+       /* Copy the work queue CQE and convert endian order if needed */
+       lpfc_sli_pcimem_bcopy(cqe, &wcqe, sizeof(struct lpfc_cqe));
+
+       /* Check and process for different type of WCQE and dispatch */
+       switch (bf_get(lpfc_wcqe_c_code, &wcqe)) {
+       case CQE_CODE_COMPL_WQE:
+               /* Process the WQ complete event */
+               lpfc_sli4_fp_handle_fcp_wcqe(phba,
+                               (struct lpfc_wcqe_complete *)&wcqe);
+               break;
+       case CQE_CODE_RELEASE_WQE:
+               /* Process the WQ release event */
+               lpfc_sli4_fp_handle_rel_wcqe(phba, cq,
+                               (struct lpfc_wcqe_release *)&wcqe);
+               break;
+       case CQE_CODE_XRI_ABORTED:
+               /* Process the WQ XRI abort event */
+               workposted = lpfc_sli4_sp_handle_abort_xri_wcqe(phba, cq,
+                               (struct sli4_wcqe_xri_aborted *)&wcqe);
+               break;
+       default:
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "0144 Not a valid WCQE code: x%x\n",
+                               bf_get(lpfc_wcqe_c_code, &wcqe));
+               break;
+       }
+       return workposted;
+}
+
+/**
+ * lpfc_sli4_fp_handle_eqe - Process a fast-path event queue entry
+ * @phba: Pointer to HBA context object.
+ * @eqe: Pointer to fast-path event queue entry.
+ *
+ * This routine process a event queue entry from the fast-path event queue.
+ * It will check the MajorCode and MinorCode to determine this is for a
+ * completion event on a completion queue, if not, an error shall be logged
+ * and just return. Otherwise, it will get to the corresponding completion
+ * queue and process all the entries on the completion queue, rearm the
+ * completion queue, and then return.
+ **/
+static void
+lpfc_sli4_fp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe,
+                       uint32_t fcp_cqidx)
+{
+       struct lpfc_queue *cq;
+       struct lpfc_cqe *cqe;
+       bool workposted = false;
+       uint16_t cqid;
+       int ecount = 0;
+
+       if (unlikely(bf_get(lpfc_eqe_major_code, eqe) != 0) ||
+           unlikely(bf_get(lpfc_eqe_minor_code, eqe) != 0)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "0366 Not a valid fast-path completion "
+                               "event: majorcode=x%x, minorcode=x%x\n",
+                               bf_get(lpfc_eqe_major_code, eqe),
+                               bf_get(lpfc_eqe_minor_code, eqe));
+               return;
+       }
+
+       cq = phba->sli4_hba.fcp_cq[fcp_cqidx];
+       if (unlikely(!cq)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "0367 Fast-path completion queue does not "
+                               "exist\n");
+               return;
+       }
+
+       /* Get the reference to the corresponding CQ */
+       cqid = bf_get(lpfc_eqe_resource_id, eqe);
+       if (unlikely(cqid != cq->queue_id)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "0368 Miss-matched fast-path completion "
+                               "queue identifier: eqcqid=%d, fcpcqid=%d\n",
+                               cqid, cq->queue_id);
+               return;
+       }
+
+       /* Process all the entries to the CQ */
+       while ((cqe = lpfc_sli4_cq_get(cq))) {
+               workposted |= lpfc_sli4_fp_handle_wcqe(phba, cq, cqe);
+               if (!(++ecount % LPFC_GET_QE_REL_INT))
+                       lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM);
+       }
+
+       /* Catch the no cq entry condition */
+       if (unlikely(ecount == 0))
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "0369 No entry from fast-path completion "
+                               "queue fcpcqid=%d\n", cq->queue_id);
+
+       /* In any case, flash and re-arm the CQ */
+       lpfc_sli4_cq_release(cq, LPFC_QUEUE_REARM);
+
+       /* wake up worker thread if there are works to be done */
+       if (workposted)
+               lpfc_worker_wake_up(phba);
+}
+
+static void
+lpfc_sli4_eq_flush(struct lpfc_hba *phba, struct lpfc_queue *eq)
+{
+       struct lpfc_eqe *eqe;
+
+       /* walk all the EQ entries and drop on the floor */
+       while ((eqe = lpfc_sli4_eq_get(eq)))
+               ;
+
+       /* Clear and re-arm the EQ */
+       lpfc_sli4_eq_release(eq, LPFC_QUEUE_REARM);
+}
+
+/**
+ * lpfc_sli4_sp_intr_handler - Slow-path interrupt handler to SLI-4 device
+ * @irq: Interrupt number.
+ * @dev_id: The device context pointer.
+ *
+ * This function is directly called from the PCI layer as an interrupt
+ * service routine when device with SLI-4 interface spec is enabled with
+ * MSI-X multi-message interrupt mode and there are slow-path events in
+ * the HBA. However, when the device is enabled with either MSI or Pin-IRQ
+ * interrupt mode, this function is called as part of the device-level
+ * interrupt handler. When the PCI slot is in error recovery or the HBA is
+ * undergoing initialization, the interrupt handler will not process the
+ * interrupt. The link attention and ELS ring attention events are handled
+ * by the worker thread. The interrupt handler signals the worker thread
+ * and returns for these events. This function is called without any lock
+ * held. It gets the hbalock to access and update SLI data structures.
+ *
+ * This function returns IRQ_HANDLED when interrupt is handled else it
+ * returns IRQ_NONE.
+ **/
+irqreturn_t
+lpfc_sli4_sp_intr_handler(int irq, void *dev_id)
+{
+       struct lpfc_hba *phba;
+       struct lpfc_queue *speq;
+       struct lpfc_eqe *eqe;
+       unsigned long iflag;
+       int ecount = 0;
+
+       /*
+        * Get the driver's phba structure from the dev_id
+        */
+       phba = (struct lpfc_hba *)dev_id;
+
+       if (unlikely(!phba))
+               return IRQ_NONE;
+
+       /* Get to the EQ struct associated with this vector */
+       speq = phba->sli4_hba.sp_eq;
+
+       /* Check device state for handling interrupt */
+       if (unlikely(lpfc_intr_state_check(phba))) {
+               /* Check again for link_state with lock held */
+               spin_lock_irqsave(&phba->hbalock, iflag);
+               if (phba->link_state < LPFC_LINK_DOWN)
+                       /* Flush, clear interrupt, and rearm the EQ */
+                       lpfc_sli4_eq_flush(phba, speq);
+               spin_unlock_irqrestore(&phba->hbalock, iflag);
+               return IRQ_NONE;
+       }
+
+       /*
+        * Process all the event on FCP slow-path EQ
+        */
+       while ((eqe = lpfc_sli4_eq_get(speq))) {
+               lpfc_sli4_sp_handle_eqe(phba, eqe);
+               if (!(++ecount % LPFC_GET_QE_REL_INT))
+                       lpfc_sli4_eq_release(speq, LPFC_QUEUE_NOARM);
+       }
+
+       /* Always clear and re-arm the slow-path EQ */
+       lpfc_sli4_eq_release(speq, LPFC_QUEUE_REARM);
+
+       /* Catch the no cq entry condition */
+       if (unlikely(ecount == 0)) {
+               if (phba->intr_type == MSIX)
+                       /* MSI-X treated interrupt served as no EQ share INT */
+                       lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+                                       "0357 MSI-X interrupt with no EQE\n");
+               else
+                       /* Non MSI-X treated on interrupt as EQ share INT */
+                       return IRQ_NONE;
+       }
+
+       return IRQ_HANDLED;
+} /* lpfc_sli4_sp_intr_handler */
+
+/**
+ * lpfc_sli4_fp_intr_handler - Fast-path interrupt handler to SLI-4 device
+ * @irq: Interrupt number.
+ * @dev_id: The device context pointer.
+ *
+ * This function is directly called from the PCI layer as an interrupt
+ * service routine when device with SLI-4 interface spec is enabled with
+ * MSI-X multi-message interrupt mode and there is a fast-path FCP IOCB
+ * ring event in the HBA. However, when the device is enabled with either
+ * MSI or Pin-IRQ interrupt mode, this function is called as part of the
+ * device-level interrupt handler. When the PCI slot is in error recovery
+ * or the HBA is undergoing initialization, the interrupt handler will not
+ * process the interrupt. The SCSI FCP fast-path ring event are handled in
+ * the intrrupt context. This function is called without any lock held.
+ * It gets the hbalock to access and update SLI data structures. Note that,
+ * the FCP EQ to FCP CQ are one-to-one map such that the FCP EQ index is
+ * equal to that of FCP CQ index.
+ *
+ * This function returns IRQ_HANDLED when interrupt is handled else it
+ * returns IRQ_NONE.
+ **/
+irqreturn_t
+lpfc_sli4_fp_intr_handler(int irq, void *dev_id)
+{
+       struct lpfc_hba *phba;
+       struct lpfc_fcp_eq_hdl *fcp_eq_hdl;
+       struct lpfc_queue *fpeq;
+       struct lpfc_eqe *eqe;
+       unsigned long iflag;
+       int ecount = 0;
+       uint32_t fcp_eqidx;
+
+       /* Get the driver's phba structure from the dev_id */
+       fcp_eq_hdl = (struct lpfc_fcp_eq_hdl *)dev_id;
+       phba = fcp_eq_hdl->phba;
+       fcp_eqidx = fcp_eq_hdl->idx;
+
+       if (unlikely(!phba))
+               return IRQ_NONE;
+
+       /* Get to the EQ struct associated with this vector */
+       fpeq = phba->sli4_hba.fp_eq[fcp_eqidx];
+
+       /* Check device state for handling interrupt */
+       if (unlikely(lpfc_intr_state_check(phba))) {
+               /* Check again for link_state with lock held */
+               spin_lock_irqsave(&phba->hbalock, iflag);
+               if (phba->link_state < LPFC_LINK_DOWN)
+                       /* Flush, clear interrupt, and rearm the EQ */
+                       lpfc_sli4_eq_flush(phba, fpeq);
+               spin_unlock_irqrestore(&phba->hbalock, iflag);
+               return IRQ_NONE;
+       }
+
+       /*
+        * Process all the event on FCP fast-path EQ
+        */
+       while ((eqe = lpfc_sli4_eq_get(fpeq))) {
+               lpfc_sli4_fp_handle_eqe(phba, eqe, fcp_eqidx);
+               if (!(++ecount % LPFC_GET_QE_REL_INT))
+                       lpfc_sli4_eq_release(fpeq, LPFC_QUEUE_NOARM);
+       }
+
+       /* Always clear and re-arm the fast-path EQ */
+       lpfc_sli4_eq_release(fpeq, LPFC_QUEUE_REARM);
+
+       if (unlikely(ecount == 0)) {
+               if (phba->intr_type == MSIX)
+                       /* MSI-X treated interrupt served as no EQ share INT */
+                       lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+                                       "0358 MSI-X interrupt with no EQE\n");
+               else
+                       /* Non MSI-X treated on interrupt as EQ share INT */
+                       return IRQ_NONE;
+       }
+
+       return IRQ_HANDLED;
+} /* lpfc_sli4_fp_intr_handler */
+
+/**
+ * lpfc_sli4_intr_handler - Device-level interrupt handler for SLI-4 device
+ * @irq: Interrupt number.
+ * @dev_id: The device context pointer.
+ *
+ * This function is the device-level interrupt handler to device with SLI-4
+ * interface spec, called from the PCI layer when either MSI or Pin-IRQ
+ * interrupt mode is enabled and there is an event in the HBA which requires
+ * driver attention. This function invokes the slow-path interrupt attention
+ * handling function and fast-path interrupt attention handling function in
+ * turn to process the relevant HBA attention events. This function is called
+ * without any lock held. It gets the hbalock to access and update SLI data
+ * structures.
+ *
+ * This function returns IRQ_HANDLED when interrupt is handled, else it
+ * returns IRQ_NONE.
+ **/
+irqreturn_t
+lpfc_sli4_intr_handler(int irq, void *dev_id)
+{
+       struct lpfc_hba  *phba;
+       irqreturn_t sp_irq_rc, fp_irq_rc;
+       bool fp_handled = false;
+       uint32_t fcp_eqidx;
+
+       /* Get the driver's phba structure from the dev_id */
+       phba = (struct lpfc_hba *)dev_id;
+
+       if (unlikely(!phba))
+               return IRQ_NONE;
+
+       /*
+        * Invokes slow-path host attention interrupt handling as appropriate.
+        */
+       sp_irq_rc = lpfc_sli4_sp_intr_handler(irq, dev_id);
+
+       /*
+        * Invoke fast-path host attention interrupt handling as appropriate.
+        */
+       for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++) {
+               fp_irq_rc = lpfc_sli4_fp_intr_handler(irq,
+                                       &phba->sli4_hba.fcp_eq_hdl[fcp_eqidx]);
+               if (fp_irq_rc == IRQ_HANDLED)
+                       fp_handled |= true;
+       }
+
+       return (fp_handled == true) ? IRQ_HANDLED : sp_irq_rc;
+} /* lpfc_sli4_intr_handler */
+
+/**
+ * lpfc_sli4_queue_free - free a queue structure and associated memory
+ * @queue: The queue structure to free.
+ *
+ * This function frees a queue structure and the DMAable memeory used for
+ * the host resident queue. This function must be called after destroying the
+ * queue on the HBA.
+ **/
+void
+lpfc_sli4_queue_free(struct lpfc_queue *queue)
+{
+       struct lpfc_dmabuf *dmabuf;
+
+       if (!queue)
+               return;
+
+       while (!list_empty(&queue->page_list)) {
+               list_remove_head(&queue->page_list, dmabuf, struct lpfc_dmabuf,
+                                list);
+               dma_free_coherent(&queue->phba->pcidev->dev, PAGE_SIZE,
+                                 dmabuf->virt, dmabuf->phys);
+               kfree(dmabuf);
+       }
+       kfree(queue);
+       return;
+}
+
+/**
+ * lpfc_sli4_queue_alloc - Allocate and initialize a queue structure
+ * @phba: The HBA that this queue is being created on.
+ * @entry_size: The size of each queue entry for this queue.
+ * @entry count: The number of entries that this queue will handle.
+ *
+ * This function allocates a queue structure and the DMAable memory used for
+ * the host resident queue. This function must be called before creating the
+ * queue on the HBA.
+ **/
+struct lpfc_queue *
+lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t entry_size,
+                     uint32_t entry_count)
+{
+       struct lpfc_queue *queue;
+       struct lpfc_dmabuf *dmabuf;
+       int x, total_qe_count;
+       void *dma_pointer;
+
+
+       queue = kzalloc(sizeof(struct lpfc_queue) +
+                       (sizeof(union sli4_qe) * entry_count), GFP_KERNEL);
+       if (!queue)
+               return NULL;
+       queue->page_count = (PAGE_ALIGN(entry_size * entry_count))/PAGE_SIZE;
+       INIT_LIST_HEAD(&queue->list);
+       INIT_LIST_HEAD(&queue->page_list);
+       INIT_LIST_HEAD(&queue->child_list);
+       for (x = 0, total_qe_count = 0; x < queue->page_count; x++) {
+               dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+               if (!dmabuf)
+                       goto out_fail;
+               dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev,
+                                                 PAGE_SIZE, &dmabuf->phys,
+                                                 GFP_KERNEL);
+               if (!dmabuf->virt) {
+                       kfree(dmabuf);
+                       goto out_fail;
+               }
+               dmabuf->buffer_tag = x;
+               list_add_tail(&dmabuf->list, &queue->page_list);
+               /* initialize queue's entry array */
+               dma_pointer = dmabuf->virt;
+               for (; total_qe_count < entry_count &&
+                    dma_pointer < (PAGE_SIZE + dmabuf->virt);
+                    total_qe_count++, dma_pointer += entry_size) {
+                       queue->qe[total_qe_count].address = dma_pointer;
+               }
+       }
+       queue->entry_size = entry_size;
+       queue->entry_count = entry_count;
+       queue->phba = phba;
+
+       return queue;
+out_fail:
+       lpfc_sli4_queue_free(queue);
+       return NULL;
+}
+
+/**
+ * lpfc_eq_create - Create an Event Queue on the HBA
+ * @phba: HBA structure that indicates port to create a queue on.
+ * @eq: The queue structure to use to create the event queue.
+ * @imax: The maximum interrupt per second limit.
+ *
+ * This function creates an event queue, as detailed in @eq, on a port,
+ * described by @phba by sending an EQ_CREATE mailbox command to the HBA.
+ *
+ * The @phba struct is used to send mailbox command to HBA. The @eq struct
+ * is used to get the entry count and entry size that are necessary to
+ * determine the number of pages to allocate and use for this queue. This
+ * function will send the EQ_CREATE mailbox command to the HBA to setup the
+ * event queue. This function is asynchronous and will wait for the mailbox
+ * command to finish before continuing.
+ *
+ * On success this function will return a zero. If unable to allocate enough
+ * memory this function will return ENOMEM. If the queue create mailbox command
+ * fails this function will return ENXIO.
+ **/
+uint32_t
+lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint16_t imax)
+{
+       struct lpfc_mbx_eq_create *eq_create;
+       LPFC_MBOXQ_t *mbox;
+       int rc, length, status = 0;
+       struct lpfc_dmabuf *dmabuf;
+       uint32_t shdr_status, shdr_add_status;
+       union lpfc_sli4_cfg_shdr *shdr;
+       uint16_t dmult;
+
+       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox)
+               return -ENOMEM;
+       length = (sizeof(struct lpfc_mbx_eq_create) -
+                 sizeof(struct lpfc_sli4_cfg_mhdr));
+       lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
+                        LPFC_MBOX_OPCODE_EQ_CREATE,
+                        length, LPFC_SLI4_MBX_EMBED);
+       eq_create = &mbox->u.mqe.un.eq_create;
+       bf_set(lpfc_mbx_eq_create_num_pages, &eq_create->u.request,
+              eq->page_count);
+       bf_set(lpfc_eq_context_size, &eq_create->u.request.context,
+              LPFC_EQE_SIZE);
+       bf_set(lpfc_eq_context_valid, &eq_create->u.request.context, 1);
+       /* Calculate delay multiper from maximum interrupt per second */
+       dmult = LPFC_DMULT_CONST/imax - 1;
+       bf_set(lpfc_eq_context_delay_multi, &eq_create->u.request.context,
+              dmult);
+       switch (eq->entry_count) {
+       default:
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "0360 Unsupported EQ count. (%d)\n",
+                               eq->entry_count);
+               if (eq->entry_count < 256)
+                       return -EINVAL;
+               /* otherwise default to smallest count (drop through) */
+       case 256:
+               bf_set(lpfc_eq_context_count, &eq_create->u.request.context,
+                      LPFC_EQ_CNT_256);
+               break;
+       case 512:
+               bf_set(lpfc_eq_context_count, &eq_create->u.request.context,
+                      LPFC_EQ_CNT_512);
+               break;
+       case 1024:
+               bf_set(lpfc_eq_context_count, &eq_create->u.request.context,
+                      LPFC_EQ_CNT_1024);
+               break;
+       case 2048:
+               bf_set(lpfc_eq_context_count, &eq_create->u.request.context,
+                      LPFC_EQ_CNT_2048);
+               break;
+       case 4096:
+               bf_set(lpfc_eq_context_count, &eq_create->u.request.context,
+                      LPFC_EQ_CNT_4096);
+               break;
+       }
+       list_for_each_entry(dmabuf, &eq->page_list, list) {
+               eq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
+                                       putPaddrLow(dmabuf->phys);
+               eq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
+                                       putPaddrHigh(dmabuf->phys);
+       }
+       mbox->vport = phba->pport;
+       mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+       mbox->context1 = NULL;
+       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+       shdr = (union lpfc_sli4_cfg_shdr *) &eq_create->header.cfg_shdr;
+       shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+       if (shdr_status || shdr_add_status || rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2500 EQ_CREATE mailbox failed with "
+                               "status x%x add_status x%x, mbx status x%x\n",
+                               shdr_status, shdr_add_status, rc);
+               status = -ENXIO;
+       }
+       eq->type = LPFC_EQ;
+       eq->subtype = LPFC_NONE;
+       eq->queue_id = bf_get(lpfc_mbx_eq_create_q_id, &eq_create->u.response);
+       if (eq->queue_id == 0xFFFF)
+               status = -ENXIO;
+       eq->host_index = 0;
+       eq->hba_index = 0;
+
+       if (rc != MBX_TIMEOUT)
+               mempool_free(mbox, phba->mbox_mem_pool);
+       return status;
+}
+
+/**
+ * lpfc_cq_create - Create a Completion Queue on the HBA
+ * @phba: HBA structure that indicates port to create a queue on.
+ * @cq: The queue structure to use to create the completion queue.
+ * @eq: The event queue to bind this completion queue to.
+ *
+ * This function creates a completion queue, as detailed in @wq, on a port,
+ * described by @phba by sending a CQ_CREATE mailbox command to the HBA.
+ *
+ * The @phba struct is used to send mailbox command to HBA. The @cq struct
+ * is used to get the entry count and entry size that are necessary to
+ * determine the number of pages to allocate and use for this queue. The @eq
+ * is used to indicate which event queue to bind this completion queue to. This
+ * function will send the CQ_CREATE mailbox command to the HBA to setup the
+ * completion queue. This function is asynchronous and will wait for the mailbox
+ * command to finish before continuing.
+ *
+ * On success this function will return a zero. If unable to allocate enough
+ * memory this function will return ENOMEM. If the queue create mailbox command
+ * fails this function will return ENXIO.
+ **/
+uint32_t
+lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq,
+              struct lpfc_queue *eq, uint32_t type, uint32_t subtype)
+{
+       struct lpfc_mbx_cq_create *cq_create;
+       struct lpfc_dmabuf *dmabuf;
+       LPFC_MBOXQ_t *mbox;
+       int rc, length, status = 0;
+       uint32_t shdr_status, shdr_add_status;
+       union lpfc_sli4_cfg_shdr *shdr;
+
+       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox)
+               return -ENOMEM;
+       length = (sizeof(struct lpfc_mbx_cq_create) -
+                 sizeof(struct lpfc_sli4_cfg_mhdr));
+       lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
+                        LPFC_MBOX_OPCODE_CQ_CREATE,
+                        length, LPFC_SLI4_MBX_EMBED);
+       cq_create = &mbox->u.mqe.un.cq_create;
+       bf_set(lpfc_mbx_cq_create_num_pages, &cq_create->u.request,
+                   cq->page_count);
+       bf_set(lpfc_cq_context_event, &cq_create->u.request.context, 1);
+       bf_set(lpfc_cq_context_valid, &cq_create->u.request.context, 1);
+       bf_set(lpfc_cq_eq_id, &cq_create->u.request.context, eq->queue_id);
+       switch (cq->entry_count) {
+       default:
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "0361 Unsupported CQ count. (%d)\n",
+                               cq->entry_count);
+               if (cq->entry_count < 256)
+                       return -EINVAL;
+               /* otherwise default to smallest count (drop through) */
+       case 256:
+               bf_set(lpfc_cq_context_count, &cq_create->u.request.context,
+                      LPFC_CQ_CNT_256);
+               break;
+       case 512:
+               bf_set(lpfc_cq_context_count, &cq_create->u.request.context,
+                      LPFC_CQ_CNT_512);
+               break;
+       case 1024:
+               bf_set(lpfc_cq_context_count, &cq_create->u.request.context,
+                      LPFC_CQ_CNT_1024);
+               break;
+       }
+       list_for_each_entry(dmabuf, &cq->page_list, list) {
+               cq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
+                                       putPaddrLow(dmabuf->phys);
+               cq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
+                                       putPaddrHigh(dmabuf->phys);
+       }
+       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+
+       /* The IOCTL status is embedded in the mailbox subheader. */
+       shdr = (union lpfc_sli4_cfg_shdr *) &cq_create->header.cfg_shdr;
+       shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+       if (shdr_status || shdr_add_status || rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2501 CQ_CREATE mailbox failed with "
+                               "status x%x add_status x%x, mbx status x%x\n",
+                               shdr_status, shdr_add_status, rc);
+               status = -ENXIO;
+               goto out;
+       }
+       cq->queue_id = bf_get(lpfc_mbx_cq_create_q_id, &cq_create->u.response);
+       if (cq->queue_id == 0xFFFF) {
+               status = -ENXIO;
+               goto out;
+       }
+       /* link the cq onto the parent eq child list */
+       list_add_tail(&cq->list, &eq->child_list);
+       /* Set up completion queue's type and subtype */
+       cq->type = type;
+       cq->subtype = subtype;
+       cq->queue_id = bf_get(lpfc_mbx_cq_create_q_id, &cq_create->u.response);
+       cq->host_index = 0;
+       cq->hba_index = 0;
+out:
+
+       if (rc != MBX_TIMEOUT)
+               mempool_free(mbox, phba->mbox_mem_pool);
+       return status;
+}
+
+/**
+ * lpfc_mq_create - Create a mailbox Queue on the HBA
+ * @phba: HBA structure that indicates port to create a queue on.
+ * @mq: The queue structure to use to create the mailbox queue.
+ *
+ * This function creates a mailbox queue, as detailed in @mq, on a port,
+ * described by @phba by sending a MQ_CREATE mailbox command to the HBA.
+ *
+ * The @phba struct is used to send mailbox command to HBA. The @cq struct
+ * is used to get the entry count and entry size that are necessary to
+ * determine the number of pages to allocate and use for this queue. This
+ * function will send the MQ_CREATE mailbox command to the HBA to setup the
+ * mailbox queue. This function is asynchronous and will wait for the mailbox
+ * command to finish before continuing.
+ *
+ * On success this function will return a zero. If unable to allocate enough
+ * memory this function will return ENOMEM. If the queue create mailbox command
+ * fails this function will return ENXIO.
+ **/
+uint32_t
+lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq,
+              struct lpfc_queue *cq, uint32_t subtype)
+{
+       struct lpfc_mbx_mq_create *mq_create;
+       struct lpfc_dmabuf *dmabuf;
+       LPFC_MBOXQ_t *mbox;
+       int rc, length, status = 0;
+       uint32_t shdr_status, shdr_add_status;
+       union lpfc_sli4_cfg_shdr *shdr;
+
+       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox)
+               return -ENOMEM;
+       length = (sizeof(struct lpfc_mbx_mq_create) -
+                 sizeof(struct lpfc_sli4_cfg_mhdr));
+       lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
+                        LPFC_MBOX_OPCODE_MQ_CREATE,
+                        length, LPFC_SLI4_MBX_EMBED);
+       mq_create = &mbox->u.mqe.un.mq_create;
+       bf_set(lpfc_mbx_mq_create_num_pages, &mq_create->u.request,
+                   mq->page_count);
+       bf_set(lpfc_mq_context_cq_id, &mq_create->u.request.context,
+                   cq->queue_id);
+       bf_set(lpfc_mq_context_valid, &mq_create->u.request.context, 1);
+       switch (mq->entry_count) {
+       default:
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "0362 Unsupported MQ count. (%d)\n",
+                               mq->entry_count);
+               if (mq->entry_count < 16)
+                       return -EINVAL;
+               /* otherwise default to smallest count (drop through) */
+       case 16:
+               bf_set(lpfc_mq_context_count, &mq_create->u.request.context,
+                      LPFC_MQ_CNT_16);
+               break;
+       case 32:
+               bf_set(lpfc_mq_context_count, &mq_create->u.request.context,
+                      LPFC_MQ_CNT_32);
+               break;
+       case 64:
+               bf_set(lpfc_mq_context_count, &mq_create->u.request.context,
+                      LPFC_MQ_CNT_64);
+               break;
+       case 128:
+               bf_set(lpfc_mq_context_count, &mq_create->u.request.context,
+                      LPFC_MQ_CNT_128);
+               break;
+       }
+       list_for_each_entry(dmabuf, &mq->page_list, list) {
+               mq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
+                                       putPaddrLow(dmabuf->phys);
+               mq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
+                                       putPaddrHigh(dmabuf->phys);
+       }
+       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+       /* The IOCTL status is embedded in the mailbox subheader. */
+       shdr = (union lpfc_sli4_cfg_shdr *) &mq_create->header.cfg_shdr;
+       shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+       if (shdr_status || shdr_add_status || rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2502 MQ_CREATE mailbox failed with "
+                               "status x%x add_status x%x, mbx status x%x\n",
+                               shdr_status, shdr_add_status, rc);
+               status = -ENXIO;
+               goto out;
+       }
+       mq->queue_id = bf_get(lpfc_mbx_mq_create_q_id, &mq_create->u.response);
+       if (mq->queue_id == 0xFFFF) {
+               status = -ENXIO;
+               goto out;
+       }
+       mq->type = LPFC_MQ;
+       mq->subtype = subtype;
+       mq->host_index = 0;
+       mq->hba_index = 0;
+
+       /* link the mq onto the parent cq child list */
+       list_add_tail(&mq->list, &cq->child_list);
+out:
+       if (rc != MBX_TIMEOUT)
+               mempool_free(mbox, phba->mbox_mem_pool);
+       return status;
+}
+
+/**
+ * lpfc_wq_create - Create a Work Queue on the HBA
+ * @phba: HBA structure that indicates port to create a queue on.
+ * @wq: The queue structure to use to create the work queue.
+ * @cq: The completion queue to bind this work queue to.
+ * @subtype: The subtype of the work queue indicating its functionality.
+ *
+ * This function creates a work queue, as detailed in @wq, on a port, described
+ * by @phba by sending a WQ_CREATE mailbox command to the HBA.
+ *
+ * The @phba struct is used to send mailbox command to HBA. The @wq struct
+ * is used to get the entry count and entry size that are necessary to
+ * determine the number of pages to allocate and use for this queue. The @cq
+ * is used to indicate which completion queue to bind this work queue to. This
+ * function will send the WQ_CREATE mailbox command to the HBA to setup the
+ * work queue. This function is asynchronous and will wait for the mailbox
+ * command to finish before continuing.
+ *
+ * On success this function will return a zero. If unable to allocate enough
+ * memory this function will return ENOMEM. If the queue create mailbox command
+ * fails this function will return ENXIO.
+ **/
+uint32_t
+lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
+              struct lpfc_queue *cq, uint32_t subtype)
+{
+       struct lpfc_mbx_wq_create *wq_create;
+       struct lpfc_dmabuf *dmabuf;
+       LPFC_MBOXQ_t *mbox;
+       int rc, length, status = 0;
+       uint32_t shdr_status, shdr_add_status;
+       union lpfc_sli4_cfg_shdr *shdr;
+
+       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox)
+               return -ENOMEM;
+       length = (sizeof(struct lpfc_mbx_wq_create) -
+                 sizeof(struct lpfc_sli4_cfg_mhdr));
+       lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
+                        LPFC_MBOX_OPCODE_FCOE_WQ_CREATE,
+                        length, LPFC_SLI4_MBX_EMBED);
+       wq_create = &mbox->u.mqe.un.wq_create;
+       bf_set(lpfc_mbx_wq_create_num_pages, &wq_create->u.request,
+                   wq->page_count);
+       bf_set(lpfc_mbx_wq_create_cq_id, &wq_create->u.request,
+                   cq->queue_id);
+       list_for_each_entry(dmabuf, &wq->page_list, list) {
+               wq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
+                                       putPaddrLow(dmabuf->phys);
+               wq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
+                                       putPaddrHigh(dmabuf->phys);
+       }
+       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+       /* The IOCTL status is embedded in the mailbox subheader. */
+       shdr = (union lpfc_sli4_cfg_shdr *) &wq_create->header.cfg_shdr;
+       shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+       if (shdr_status || shdr_add_status || rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2503 WQ_CREATE mailbox failed with "
+                               "status x%x add_status x%x, mbx status x%x\n",
+                               shdr_status, shdr_add_status, rc);
+               status = -ENXIO;
+               goto out;
+       }
+       wq->queue_id = bf_get(lpfc_mbx_wq_create_q_id, &wq_create->u.response);
+       if (wq->queue_id == 0xFFFF) {
+               status = -ENXIO;
+               goto out;
+       }
+       wq->type = LPFC_WQ;
+       wq->subtype = subtype;
+       wq->host_index = 0;
+       wq->hba_index = 0;
+
+       /* link the wq onto the parent cq child list */
+       list_add_tail(&wq->list, &cq->child_list);
+out:
+       if (rc == MBX_TIMEOUT)
+               mempool_free(mbox, phba->mbox_mem_pool);
+       return status;
+}
+
+/**
+ * lpfc_rq_create - Create a Receive Queue on the HBA
+ * @phba: HBA structure that indicates port to create a queue on.
+ * @hrq: The queue structure to use to create the header receive queue.
+ * @drq: The queue structure to use to create the data receive queue.
+ * @cq: The completion queue to bind this work queue to.
+ *
+ * This function creates a receive buffer queue pair , as detailed in @hrq and
+ * @drq, on a port, described by @phba by sending a RQ_CREATE mailbox command
+ * to the HBA.
+ *
+ * The @phba struct is used to send mailbox command to HBA. The @drq and @hrq
+ * struct is used to get the entry count that is necessary to determine the
+ * number of pages to use for this queue. The @cq is used to indicate which
+ * completion queue to bind received buffers that are posted to these queues to.
+ * This function will send the RQ_CREATE mailbox command to the HBA to setup the
+ * receive queue pair. This function is asynchronous and will wait for the
+ * mailbox command to finish before continuing.
+ *
+ * On success this function will return a zero. If unable to allocate enough
+ * memory this function will return ENOMEM. If the queue create mailbox command
+ * fails this function will return ENXIO.
+ **/
+uint32_t
+lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq,
+              struct lpfc_queue *drq, struct lpfc_queue *cq, uint32_t subtype)
+{
+       struct lpfc_mbx_rq_create *rq_create;
+       struct lpfc_dmabuf *dmabuf;
+       LPFC_MBOXQ_t *mbox;
+       int rc, length, status = 0;
+       uint32_t shdr_status, shdr_add_status;
+       union lpfc_sli4_cfg_shdr *shdr;
+
+       if (hrq->entry_count != drq->entry_count)
+               return -EINVAL;
+       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox)
+               return -ENOMEM;
+       length = (sizeof(struct lpfc_mbx_rq_create) -
+                 sizeof(struct lpfc_sli4_cfg_mhdr));
+       lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
+                        LPFC_MBOX_OPCODE_FCOE_RQ_CREATE,
+                        length, LPFC_SLI4_MBX_EMBED);
+       rq_create = &mbox->u.mqe.un.rq_create;
+       switch (hrq->entry_count) {
+       default:
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "2535 Unsupported RQ count. (%d)\n",
+                               hrq->entry_count);
+               if (hrq->entry_count < 512)
+                       return -EINVAL;
+               /* otherwise default to smallest count (drop through) */
+       case 512:
+               bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context,
+                      LPFC_RQ_RING_SIZE_512);
+               break;
+       case 1024:
+               bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context,
+                      LPFC_RQ_RING_SIZE_1024);
+               break;
+       case 2048:
+               bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context,
+                      LPFC_RQ_RING_SIZE_2048);
+               break;
+       case 4096:
+               bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context,
+                      LPFC_RQ_RING_SIZE_4096);
+               break;
+       }
+       bf_set(lpfc_rq_context_cq_id, &rq_create->u.request.context,
+              cq->queue_id);
+       bf_set(lpfc_mbx_rq_create_num_pages, &rq_create->u.request,
+              hrq->page_count);
+       bf_set(lpfc_rq_context_buf_size, &rq_create->u.request.context,
+              LPFC_HDR_BUF_SIZE);
+       list_for_each_entry(dmabuf, &hrq->page_list, list) {
+               rq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
+                                       putPaddrLow(dmabuf->phys);
+               rq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
+                                       putPaddrHigh(dmabuf->phys);
+       }
+       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+       /* The IOCTL status is embedded in the mailbox subheader. */
+       shdr = (union lpfc_sli4_cfg_shdr *) &rq_create->header.cfg_shdr;
+       shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+       if (shdr_status || shdr_add_status || rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2504 RQ_CREATE mailbox failed with "
+                               "status x%x add_status x%x, mbx status x%x\n",
+                               shdr_status, shdr_add_status, rc);
+               status = -ENXIO;
+               goto out;
+       }
+       hrq->queue_id = bf_get(lpfc_mbx_rq_create_q_id, &rq_create->u.response);
+       if (hrq->queue_id == 0xFFFF) {
+               status = -ENXIO;
+               goto out;
+       }
+       hrq->type = LPFC_HRQ;
+       hrq->subtype = subtype;
+       hrq->host_index = 0;
+       hrq->hba_index = 0;
+
+       /* now create the data queue */
+       lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
+                        LPFC_MBOX_OPCODE_FCOE_RQ_CREATE,
+                        length, LPFC_SLI4_MBX_EMBED);
+       switch (drq->entry_count) {
+       default:
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "2536 Unsupported RQ count. (%d)\n",
+                               drq->entry_count);
+               if (drq->entry_count < 512)
+                       return -EINVAL;
+               /* otherwise default to smallest count (drop through) */
+       case 512:
+               bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context,
+                      LPFC_RQ_RING_SIZE_512);
+               break;
+       case 1024:
+               bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context,
+                      LPFC_RQ_RING_SIZE_1024);
+               break;
+       case 2048:
+               bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context,
+                      LPFC_RQ_RING_SIZE_2048);
+               break;
+       case 4096:
+               bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context,
+                      LPFC_RQ_RING_SIZE_4096);
+               break;
+       }
+       bf_set(lpfc_rq_context_cq_id, &rq_create->u.request.context,
+              cq->queue_id);
+       bf_set(lpfc_mbx_rq_create_num_pages, &rq_create->u.request,
+              drq->page_count);
+       bf_set(lpfc_rq_context_buf_size, &rq_create->u.request.context,
+              LPFC_DATA_BUF_SIZE);
+       list_for_each_entry(dmabuf, &drq->page_list, list) {
+               rq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
+                                       putPaddrLow(dmabuf->phys);
+               rq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
+                                       putPaddrHigh(dmabuf->phys);
+       }
+       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+       /* The IOCTL status is embedded in the mailbox subheader. */
+       shdr = (union lpfc_sli4_cfg_shdr *) &rq_create->header.cfg_shdr;
+       shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+       if (shdr_status || shdr_add_status || rc) {
+               status = -ENXIO;
+               goto out;
+       }
+       drq->queue_id = bf_get(lpfc_mbx_rq_create_q_id, &rq_create->u.response);
+       if (drq->queue_id == 0xFFFF) {
+               status = -ENXIO;
+               goto out;
+       }
+       drq->type = LPFC_DRQ;
+       drq->subtype = subtype;
+       drq->host_index = 0;
+       drq->hba_index = 0;
+
+       /* link the header and data RQs onto the parent cq child list */
+       list_add_tail(&hrq->list, &cq->child_list);
+       list_add_tail(&drq->list, &cq->child_list);
+
+out:
+       if (rc != MBX_TIMEOUT)
+               mempool_free(mbox, phba->mbox_mem_pool);
+       return status;
+}
+
+/**
+ * lpfc_eq_destroy - Destroy an event Queue on the HBA
+ * @eq: The queue structure associated with the queue to destroy.
+ *
+ * This function destroys a queue, as detailed in @eq by sending an mailbox
+ * command, specific to the type of queue, to the HBA.
+ *
+ * The @eq struct is used to get the queue ID of the queue to destroy.
+ *
+ * On success this function will return a zero. If the queue destroy mailbox
+ * command fails this function will return ENXIO.
+ **/
+uint32_t
+lpfc_eq_destroy(struct lpfc_hba *phba, struct lpfc_queue *eq)
+{
+       LPFC_MBOXQ_t *mbox;
+       int rc, length, status = 0;
+       uint32_t shdr_status, shdr_add_status;
+       union lpfc_sli4_cfg_shdr *shdr;
+
+       if (!eq)
+               return -ENODEV;
+       mbox = mempool_alloc(eq->phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox)
+               return -ENOMEM;
+       length = (sizeof(struct lpfc_mbx_eq_destroy) -
+                 sizeof(struct lpfc_sli4_cfg_mhdr));
+       lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
+                        LPFC_MBOX_OPCODE_EQ_DESTROY,
+                        length, LPFC_SLI4_MBX_EMBED);
+       bf_set(lpfc_mbx_eq_destroy_q_id, &mbox->u.mqe.un.eq_destroy.u.request,
+              eq->queue_id);
+       mbox->vport = eq->phba->pport;
+       mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+
+       rc = lpfc_sli_issue_mbox(eq->phba, mbox, MBX_POLL);
+       /* The IOCTL status is embedded in the mailbox subheader. */
+       shdr = (union lpfc_sli4_cfg_shdr *)
+               &mbox->u.mqe.un.eq_destroy.header.cfg_shdr;
+       shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+       if (shdr_status || shdr_add_status || rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2505 EQ_DESTROY mailbox failed with "
+                               "status x%x add_status x%x, mbx status x%x\n",
+                               shdr_status, shdr_add_status, rc);
+               status = -ENXIO;
+       }
+
+       /* Remove eq from any list */
+       list_del_init(&eq->list);
+       if (rc != MBX_TIMEOUT)
+               mempool_free(mbox, eq->phba->mbox_mem_pool);
+       return status;
+}
+
+/**
+ * lpfc_cq_destroy - Destroy a Completion Queue on the HBA
+ * @cq: The queue structure associated with the queue to destroy.
+ *
+ * This function destroys a queue, as detailed in @cq by sending an mailbox
+ * command, specific to the type of queue, to the HBA.
+ *
+ * The @cq struct is used to get the queue ID of the queue to destroy.
+ *
+ * On success this function will return a zero. If the queue destroy mailbox
+ * command fails this function will return ENXIO.
+ **/
+uint32_t
+lpfc_cq_destroy(struct lpfc_hba *phba, struct lpfc_queue *cq)
+{
+       LPFC_MBOXQ_t *mbox;
+       int rc, length, status = 0;
+       uint32_t shdr_status, shdr_add_status;
+       union lpfc_sli4_cfg_shdr *shdr;
+
+       if (!cq)
+               return -ENODEV;
+       mbox = mempool_alloc(cq->phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox)
+               return -ENOMEM;
+       length = (sizeof(struct lpfc_mbx_cq_destroy) -
+                 sizeof(struct lpfc_sli4_cfg_mhdr));
+       lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
+                        LPFC_MBOX_OPCODE_CQ_DESTROY,
+                        length, LPFC_SLI4_MBX_EMBED);
+       bf_set(lpfc_mbx_cq_destroy_q_id, &mbox->u.mqe.un.cq_destroy.u.request,
+              cq->queue_id);
+       mbox->vport = cq->phba->pport;
+       mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+       rc = lpfc_sli_issue_mbox(cq->phba, mbox, MBX_POLL);
+       /* The IOCTL status is embedded in the mailbox subheader. */
+       shdr = (union lpfc_sli4_cfg_shdr *)
+               &mbox->u.mqe.un.wq_create.header.cfg_shdr;
+       shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+       if (shdr_status || shdr_add_status || rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2506 CQ_DESTROY mailbox failed with "
+                               "status x%x add_status x%x, mbx status x%x\n",
+                               shdr_status, shdr_add_status, rc);
+               status = -ENXIO;
+       }
+       /* Remove cq from any list */
+       list_del_init(&cq->list);
+       if (rc != MBX_TIMEOUT)
+               mempool_free(mbox, cq->phba->mbox_mem_pool);
+       return status;
+}
+
+/**
+ * lpfc_mq_destroy - Destroy a Mailbox Queue on the HBA
+ * @qm: The queue structure associated with the queue to destroy.
+ *
+ * This function destroys a queue, as detailed in @mq by sending an mailbox
+ * command, specific to the type of queue, to the HBA.
+ *
+ * The @mq struct is used to get the queue ID of the queue to destroy.
+ *
+ * On success this function will return a zero. If the queue destroy mailbox
+ * command fails this function will return ENXIO.
+ **/
+uint32_t
+lpfc_mq_destroy(struct lpfc_hba *phba, struct lpfc_queue *mq)
+{
+       LPFC_MBOXQ_t *mbox;
+       int rc, length, status = 0;
+       uint32_t shdr_status, shdr_add_status;
+       union lpfc_sli4_cfg_shdr *shdr;
+
+       if (!mq)
+               return -ENODEV;
+       mbox = mempool_alloc(mq->phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox)
+               return -ENOMEM;
+       length = (sizeof(struct lpfc_mbx_mq_destroy) -
+                 sizeof(struct lpfc_sli4_cfg_mhdr));
+       lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
+                        LPFC_MBOX_OPCODE_MQ_DESTROY,
+                        length, LPFC_SLI4_MBX_EMBED);
+       bf_set(lpfc_mbx_mq_destroy_q_id, &mbox->u.mqe.un.mq_destroy.u.request,
+              mq->queue_id);
+       mbox->vport = mq->phba->pport;
+       mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+       rc = lpfc_sli_issue_mbox(mq->phba, mbox, MBX_POLL);
+       /* The IOCTL status is embedded in the mailbox subheader. */
+       shdr = (union lpfc_sli4_cfg_shdr *)
+               &mbox->u.mqe.un.mq_destroy.header.cfg_shdr;
+       shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+       if (shdr_status || shdr_add_status || rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2507 MQ_DESTROY mailbox failed with "
+                               "status x%x add_status x%x, mbx status x%x\n",
+                               shdr_status, shdr_add_status, rc);
+               status = -ENXIO;
+       }
+       /* Remove mq from any list */
+       list_del_init(&mq->list);
+       if (rc != MBX_TIMEOUT)
+               mempool_free(mbox, mq->phba->mbox_mem_pool);
+       return status;
+}
+
+/**
+ * lpfc_wq_destroy - Destroy a Work Queue on the HBA
+ * @wq: The queue structure associated with the queue to destroy.
+ *
+ * This function destroys a queue, as detailed in @wq by sending an mailbox
+ * command, specific to the type of queue, to the HBA.
+ *
+ * The @wq struct is used to get the queue ID of the queue to destroy.
+ *
+ * On success this function will return a zero. If the queue destroy mailbox
+ * command fails this function will return ENXIO.
+ **/
+uint32_t
+lpfc_wq_destroy(struct lpfc_hba *phba, struct lpfc_queue *wq)
+{
+       LPFC_MBOXQ_t *mbox;
+       int rc, length, status = 0;
+       uint32_t shdr_status, shdr_add_status;
+       union lpfc_sli4_cfg_shdr *shdr;
+
+       if (!wq)
+               return -ENODEV;
+       mbox = mempool_alloc(wq->phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox)
+               return -ENOMEM;
+       length = (sizeof(struct lpfc_mbx_wq_destroy) -
+                 sizeof(struct lpfc_sli4_cfg_mhdr));
+       lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
+                        LPFC_MBOX_OPCODE_FCOE_WQ_DESTROY,
+                        length, LPFC_SLI4_MBX_EMBED);
+       bf_set(lpfc_mbx_wq_destroy_q_id, &mbox->u.mqe.un.wq_destroy.u.request,
+              wq->queue_id);
+       mbox->vport = wq->phba->pport;
+       mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+       rc = lpfc_sli_issue_mbox(wq->phba, mbox, MBX_POLL);
+       shdr = (union lpfc_sli4_cfg_shdr *)
+               &mbox->u.mqe.un.wq_destroy.header.cfg_shdr;
+       shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+       if (shdr_status || shdr_add_status || rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2508 WQ_DESTROY mailbox failed with "
+                               "status x%x add_status x%x, mbx status x%x\n",
+                               shdr_status, shdr_add_status, rc);
+               status = -ENXIO;
+       }
+       /* Remove wq from any list */
+       list_del_init(&wq->list);
+       if (rc != MBX_TIMEOUT)
+               mempool_free(mbox, wq->phba->mbox_mem_pool);
+       return status;
+}
+
+/**
+ * lpfc_rq_destroy - Destroy a Receive Queue on the HBA
+ * @rq: The queue structure associated with the queue to destroy.
+ *
+ * This function destroys a queue, as detailed in @rq by sending an mailbox
+ * command, specific to the type of queue, to the HBA.
+ *
+ * The @rq struct is used to get the queue ID of the queue to destroy.
+ *
+ * On success this function will return a zero. If the queue destroy mailbox
+ * command fails this function will return ENXIO.
+ **/
+uint32_t
+lpfc_rq_destroy(struct lpfc_hba *phba, struct lpfc_queue *hrq,
+               struct lpfc_queue *drq)
+{
+       LPFC_MBOXQ_t *mbox;
+       int rc, length, status = 0;
+       uint32_t shdr_status, shdr_add_status;
+       union lpfc_sli4_cfg_shdr *shdr;
+
+       if (!hrq || !drq)
+               return -ENODEV;
+       mbox = mempool_alloc(hrq->phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox)
+               return -ENOMEM;
+       length = (sizeof(struct lpfc_mbx_rq_destroy) -
+                 sizeof(struct mbox_header));
+       lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
+                        LPFC_MBOX_OPCODE_FCOE_RQ_DESTROY,
+                        length, LPFC_SLI4_MBX_EMBED);
+       bf_set(lpfc_mbx_rq_destroy_q_id, &mbox->u.mqe.un.rq_destroy.u.request,
+              hrq->queue_id);
+       mbox->vport = hrq->phba->pport;
+       mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+       rc = lpfc_sli_issue_mbox(hrq->phba, mbox, MBX_POLL);
+       /* The IOCTL status is embedded in the mailbox subheader. */
+       shdr = (union lpfc_sli4_cfg_shdr *)
+               &mbox->u.mqe.un.rq_destroy.header.cfg_shdr;
+       shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+       if (shdr_status || shdr_add_status || rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2509 RQ_DESTROY mailbox failed with "
+                               "status x%x add_status x%x, mbx status x%x\n",
+                               shdr_status, shdr_add_status, rc);
+               if (rc != MBX_TIMEOUT)
+                       mempool_free(mbox, hrq->phba->mbox_mem_pool);
+               return -ENXIO;
+       }
+       bf_set(lpfc_mbx_rq_destroy_q_id, &mbox->u.mqe.un.rq_destroy.u.request,
+              drq->queue_id);
+       rc = lpfc_sli_issue_mbox(drq->phba, mbox, MBX_POLL);
+       shdr = (union lpfc_sli4_cfg_shdr *)
+               &mbox->u.mqe.un.rq_destroy.header.cfg_shdr;
+       shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+       if (shdr_status || shdr_add_status || rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2510 RQ_DESTROY mailbox failed with "
+                               "status x%x add_status x%x, mbx status x%x\n",
+                               shdr_status, shdr_add_status, rc);
+               status = -ENXIO;
+       }
+       list_del_init(&hrq->list);
+       list_del_init(&drq->list);
+       if (rc != MBX_TIMEOUT)
+               mempool_free(mbox, hrq->phba->mbox_mem_pool);
+       return status;
+}
+
+/**
+ * lpfc_sli4_post_sgl - Post scatter gather list for an XRI to HBA
+ * @phba: The virtual port for which this call being executed.
+ * @pdma_phys_addr0: Physical address of the 1st SGL page.
+ * @pdma_phys_addr1: Physical address of the 2nd SGL page.
+ * @xritag: the xritag that ties this io to the SGL pages.
+ *
+ * This routine will post the sgl pages for the IO that has the xritag
+ * that is in the iocbq structure. The xritag is assigned during iocbq
+ * creation and persists for as long as the driver is loaded.
+ * if the caller has fewer than 256 scatter gather segments to map then
+ * pdma_phys_addr1 should be 0.
+ * If the caller needs to map more than 256 scatter gather segment then
+ * pdma_phys_addr1 should be a valid physical address.
+ * physical address for SGLs must be 64 byte aligned.
+ * If you are going to map 2 SGL's then the first one must have 256 entries
+ * the second sgl can have between 1 and 256 entries.
+ *
+ * Return codes:
+ *     0 - Success
+ *     -ENXIO, -ENOMEM - Failure
+ **/
+int
+lpfc_sli4_post_sgl(struct lpfc_hba *phba,
+               dma_addr_t pdma_phys_addr0,
+               dma_addr_t pdma_phys_addr1,
+               uint16_t xritag)
+{
+       struct lpfc_mbx_post_sgl_pages *post_sgl_pages;
+       LPFC_MBOXQ_t *mbox;
+       int rc;
+       uint32_t shdr_status, shdr_add_status;
+       union lpfc_sli4_cfg_shdr *shdr;
+
+       if (xritag == NO_XRI) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "0364 Invalid param:\n");
+               return -EINVAL;
+       }
+
+       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox)
+               return -ENOMEM;
+
+       lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
+                       LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES,
+                       sizeof(struct lpfc_mbx_post_sgl_pages) -
+                       sizeof(struct mbox_header), LPFC_SLI4_MBX_EMBED);
+
+       post_sgl_pages = (struct lpfc_mbx_post_sgl_pages *)
+                               &mbox->u.mqe.un.post_sgl_pages;
+       bf_set(lpfc_post_sgl_pages_xri, post_sgl_pages, xritag);
+       bf_set(lpfc_post_sgl_pages_xricnt, post_sgl_pages, 1);
+
+       post_sgl_pages->sgl_pg_pairs[0].sgl_pg0_addr_lo =
+                               cpu_to_le32(putPaddrLow(pdma_phys_addr0));
+       post_sgl_pages->sgl_pg_pairs[0].sgl_pg0_addr_hi =
+                               cpu_to_le32(putPaddrHigh(pdma_phys_addr0));
+
+       post_sgl_pages->sgl_pg_pairs[0].sgl_pg1_addr_lo =
+                               cpu_to_le32(putPaddrLow(pdma_phys_addr1));
+       post_sgl_pages->sgl_pg_pairs[0].sgl_pg1_addr_hi =
+                               cpu_to_le32(putPaddrHigh(pdma_phys_addr1));
+       if (!phba->sli4_hba.intr_enable)
+               rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+       else
+               rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO);
+       /* The IOCTL status is embedded in the mailbox subheader. */
+       shdr = (union lpfc_sli4_cfg_shdr *) &post_sgl_pages->header.cfg_shdr;
+       shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+       if (rc != MBX_TIMEOUT)
+               mempool_free(mbox, phba->mbox_mem_pool);
+       if (shdr_status || shdr_add_status || rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2511 POST_SGL mailbox failed with "
+                               "status x%x add_status x%x, mbx status x%x\n",
+                               shdr_status, shdr_add_status, rc);
+               rc = -ENXIO;
+       }
+       return 0;
+}
+/**
+ * lpfc_sli4_remove_all_sgl_pages - Post scatter gather list for an XRI to HBA
+ * @phba: The virtual port for which this call being executed.
+ *
+ * This routine will remove all of the sgl pages registered with the hba.
+ *
+ * Return codes:
+ *     0 - Success
+ *     -ENXIO, -ENOMEM - Failure
+ **/
+int
+lpfc_sli4_remove_all_sgl_pages(struct lpfc_hba *phba)
+{
+       LPFC_MBOXQ_t *mbox;
+       int rc;
+       uint32_t shdr_status, shdr_add_status;
+       union lpfc_sli4_cfg_shdr *shdr;
+
+       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox)
+               return -ENOMEM;
+
+       lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
+                       LPFC_MBOX_OPCODE_FCOE_REMOVE_SGL_PAGES, 0,
+                       LPFC_SLI4_MBX_EMBED);
+       if (!phba->sli4_hba.intr_enable)
+               rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+       else
+               rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO);
+       /* The IOCTL status is embedded in the mailbox subheader. */
+       shdr = (union lpfc_sli4_cfg_shdr *)
+               &mbox->u.mqe.un.sli4_config.header.cfg_shdr;
+       shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+       if (rc != MBX_TIMEOUT)
+               mempool_free(mbox, phba->mbox_mem_pool);
+       if (shdr_status || shdr_add_status || rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2512 REMOVE_ALL_SGL_PAGES mailbox failed with "
+                               "status x%x add_status x%x, mbx status x%x\n",
+                               shdr_status, shdr_add_status, rc);
+               rc = -ENXIO;
+       }
+       return rc;
+}
+
+/**
+ * lpfc_sli4_next_xritag - Get an xritag for the io
+ * @phba: Pointer to HBA context object.
+ *
+ * This function gets an xritag for the iocb. If there is no unused xritag
+ * it will return 0xffff.
+ * The function returns the allocated xritag if successful, else returns zero.
+ * Zero is not a valid xritag.
+ * The caller is not required to hold any lock.
+ **/
+uint16_t
+lpfc_sli4_next_xritag(struct lpfc_hba *phba)
+{
+       uint16_t xritag;
+
+       spin_lock_irq(&phba->hbalock);
+       xritag = phba->sli4_hba.next_xri;
+       if ((xritag != (uint16_t) -1) && xritag <
+               (phba->sli4_hba.max_cfg_param.max_xri
+                       + phba->sli4_hba.max_cfg_param.xri_base)) {
+               phba->sli4_hba.next_xri++;
+               phba->sli4_hba.max_cfg_param.xri_used++;
+               spin_unlock_irq(&phba->hbalock);
+               return xritag;
+       }
+       spin_unlock_irq(&phba->hbalock);
+
+       lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                       "2004 Failed to allocate XRI.last XRITAG is %d"
+                       " Max XRI is %d, Used XRI is %d\n",
+                       phba->sli4_hba.next_xri,
+                       phba->sli4_hba.max_cfg_param.max_xri,
+                       phba->sli4_hba.max_cfg_param.xri_used);
+       return -1;
+}
+
+/**
+ * lpfc_sli4_post_sgl_list - post a block of sgl list to the firmware.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to post a block of driver's sgl pages to the
+ * HBA using non-embedded mailbox command. No Lock is held. This routine
+ * is only called when the driver is loading and after all IO has been
+ * stopped.
+ **/
+int
+lpfc_sli4_post_sgl_list(struct lpfc_hba *phba)
+{
+       struct lpfc_sglq *sglq_entry;
+       struct lpfc_mbx_post_uembed_sgl_page1 *sgl;
+       struct sgl_page_pairs *sgl_pg_pairs;
+       void *viraddr;
+       LPFC_MBOXQ_t *mbox;
+       uint32_t reqlen, alloclen, pg_pairs;
+       uint32_t mbox_tmo;
+       uint16_t xritag_start = 0;
+       int els_xri_cnt, rc = 0;
+       uint32_t shdr_status, shdr_add_status;
+       union lpfc_sli4_cfg_shdr *shdr;
+
+       /* The number of sgls to be posted */
+       els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba);
+
+       reqlen = els_xri_cnt * sizeof(struct sgl_page_pairs) +
+                sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t);
+       if (reqlen > PAGE_SIZE) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+                               "2559 Block sgl registration required DMA "
+                               "size (%d) great than a page\n", reqlen);
+               return -ENOMEM;
+       }
+       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2560 Failed to allocate mbox cmd memory\n");
+               return -ENOMEM;
+       }
+
+       /* Allocate DMA memory and set up the non-embedded mailbox command */
+       alloclen = lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
+                        LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES, reqlen,
+                        LPFC_SLI4_MBX_NEMBED);
+
+       if (alloclen < reqlen) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0285 Allocated DMA memory size (%d) is "
+                               "less than the requested DMA memory "
+                               "size (%d)\n", alloclen, reqlen);
+               lpfc_sli4_mbox_cmd_free(phba, mbox);
+               return -ENOMEM;
+       }
+
+       /* Get the first SGE entry from the non-embedded DMA memory */
+       if (unlikely(!mbox->sge_array)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+                               "2525 Failed to get the non-embedded SGE "
+                               "virtual address\n");
+               lpfc_sli4_mbox_cmd_free(phba, mbox);
+               return -ENOMEM;
+       }
+       viraddr = mbox->sge_array->addr[0];
+
+       /* Set up the SGL pages in the non-embedded DMA pages */
+       sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr;
+       sgl_pg_pairs = &sgl->sgl_pg_pairs;
+
+       for (pg_pairs = 0; pg_pairs < els_xri_cnt; pg_pairs++) {
+               sglq_entry = phba->sli4_hba.lpfc_els_sgl_array[pg_pairs];
+               /* Set up the sge entry */
+               sgl_pg_pairs->sgl_pg0_addr_lo =
+                               cpu_to_le32(putPaddrLow(sglq_entry->phys));
+               sgl_pg_pairs->sgl_pg0_addr_hi =
+                               cpu_to_le32(putPaddrHigh(sglq_entry->phys));
+               sgl_pg_pairs->sgl_pg1_addr_lo =
+                               cpu_to_le32(putPaddrLow(0));
+               sgl_pg_pairs->sgl_pg1_addr_hi =
+                               cpu_to_le32(putPaddrHigh(0));
+               /* Keep the first xritag on the list */
+               if (pg_pairs == 0)
+                       xritag_start = sglq_entry->sli4_xritag;
+               sgl_pg_pairs++;
+       }
+       bf_set(lpfc_post_sgl_pages_xri, sgl, xritag_start);
+       pg_pairs = (pg_pairs > 0) ? (pg_pairs - 1) : pg_pairs;
+       bf_set(lpfc_post_sgl_pages_xricnt, sgl, pg_pairs);
+       /* Perform endian conversion if necessary */
+       sgl->word0 = cpu_to_le32(sgl->word0);
+
+       if (!phba->sli4_hba.intr_enable)
+               rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+       else {
+               mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG);
+               rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
+       }
+       shdr = (union lpfc_sli4_cfg_shdr *) &sgl->cfg_shdr;
+       shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+       if (rc != MBX_TIMEOUT)
+               lpfc_sli4_mbox_cmd_free(phba, mbox);
+       if (shdr_status || shdr_add_status || rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "2513 POST_SGL_BLOCK mailbox command failed "
+                               "status x%x add_status x%x mbx status x%x\n",
+                               shdr_status, shdr_add_status, rc);
+               rc = -ENXIO;
+       }
+       return rc;
+}
+
+/**
+ * lpfc_sli4_post_scsi_sgl_block - post a block of scsi sgl list to firmware
+ * @phba: pointer to lpfc hba data structure.
+ * @sblist: pointer to scsi buffer list.
+ * @count: number of scsi buffers on the list.
+ *
+ * This routine is invoked to post a block of @count scsi sgl pages from a
+ * SCSI buffer list @sblist to the HBA using non-embedded mailbox command.
+ * No Lock is held.
+ *
+ **/
+int
+lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist,
+                             int cnt)
+{
+       struct lpfc_scsi_buf *psb;
+       struct lpfc_mbx_post_uembed_sgl_page1 *sgl;
+       struct sgl_page_pairs *sgl_pg_pairs;
+       void *viraddr;
+       LPFC_MBOXQ_t *mbox;
+       uint32_t reqlen, alloclen, pg_pairs;
+       uint32_t mbox_tmo;
+       uint16_t xritag_start = 0;
+       int rc = 0;
+       uint32_t shdr_status, shdr_add_status;
+       dma_addr_t pdma_phys_bpl1;
+       union lpfc_sli4_cfg_shdr *shdr;
+
+       /* Calculate the requested length of the dma memory */
+       reqlen = cnt * sizeof(struct sgl_page_pairs) +
+                sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t);
+       if (reqlen > PAGE_SIZE) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+                               "0217 Block sgl registration required DMA "
+                               "size (%d) great than a page\n", reqlen);
+               return -ENOMEM;
+       }
+       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0283 Failed to allocate mbox cmd memory\n");
+               return -ENOMEM;
+       }
+
+       /* Allocate DMA memory and set up the non-embedded mailbox command */
+       alloclen = lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
+                               LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES, reqlen,
+                               LPFC_SLI4_MBX_NEMBED);
+
+       if (alloclen < reqlen) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2561 Allocated DMA memory size (%d) is "
+                               "less than the requested DMA memory "
+                               "size (%d)\n", alloclen, reqlen);
+               lpfc_sli4_mbox_cmd_free(phba, mbox);
+               return -ENOMEM;
+       }
+
+       /* Get the first SGE entry from the non-embedded DMA memory */
+       if (unlikely(!mbox->sge_array)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+                               "2565 Failed to get the non-embedded SGE "
+                               "virtual address\n");
+               lpfc_sli4_mbox_cmd_free(phba, mbox);
+               return -ENOMEM;
+       }
+       viraddr = mbox->sge_array->addr[0];
+
+       /* Set up the SGL pages in the non-embedded DMA pages */
+       sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr;
+       sgl_pg_pairs = &sgl->sgl_pg_pairs;
+
+       pg_pairs = 0;
+       list_for_each_entry(psb, sblist, list) {
+               /* Set up the sge entry */
+               sgl_pg_pairs->sgl_pg0_addr_lo =
+                       cpu_to_le32(putPaddrLow(psb->dma_phys_bpl));
+               sgl_pg_pairs->sgl_pg0_addr_hi =
+                       cpu_to_le32(putPaddrHigh(psb->dma_phys_bpl));
+               if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE)
+                       pdma_phys_bpl1 = psb->dma_phys_bpl + SGL_PAGE_SIZE;
+               else
+                       pdma_phys_bpl1 = 0;
+               sgl_pg_pairs->sgl_pg1_addr_lo =
+                       cpu_to_le32(putPaddrLow(pdma_phys_bpl1));
+               sgl_pg_pairs->sgl_pg1_addr_hi =
+                       cpu_to_le32(putPaddrHigh(pdma_phys_bpl1));
+               /* Keep the first xritag on the list */
+               if (pg_pairs == 0)
+                       xritag_start = psb->cur_iocbq.sli4_xritag;
+               sgl_pg_pairs++;
+               pg_pairs++;
+       }
+       bf_set(lpfc_post_sgl_pages_xri, sgl, xritag_start);
+       bf_set(lpfc_post_sgl_pages_xricnt, sgl, pg_pairs);
+       /* Perform endian conversion if necessary */
+       sgl->word0 = cpu_to_le32(sgl->word0);
+
+       if (!phba->sli4_hba.intr_enable)
+               rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+       else {
+               mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG);
+               rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
+       }
+       shdr = (union lpfc_sli4_cfg_shdr *) &sgl->cfg_shdr;
+       shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+       if (rc != MBX_TIMEOUT)
+               lpfc_sli4_mbox_cmd_free(phba, mbox);
+       if (shdr_status || shdr_add_status || rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "2564 POST_SGL_BLOCK mailbox command failed "
+                               "status x%x add_status x%x mbx status x%x\n",
+                               shdr_status, shdr_add_status, rc);
+               rc = -ENXIO;
+       }
+       return rc;
+}
+
+/**
+ * lpfc_fc_frame_check - Check that this frame is a valid frame to handle
+ * @phba: pointer to lpfc_hba struct that the frame was received on
+ * @fc_hdr: A pointer to the FC Header data (In Big Endian Format)
+ *
+ * This function checks the fields in the @fc_hdr to see if the FC frame is a
+ * valid type of frame that the LPFC driver will handle. This function will
+ * return a zero if the frame is a valid frame or a non zero value when the
+ * frame does not pass the check.
+ **/
+static int
+lpfc_fc_frame_check(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr)
+{
+       char *rctl_names[] = FC_RCTL_NAMES_INIT;
+       char *type_names[] = FC_TYPE_NAMES_INIT;
+       struct fc_vft_header *fc_vft_hdr;
+
+       switch (fc_hdr->fh_r_ctl) {
+       case FC_RCTL_DD_UNCAT:          /* uncategorized information */
+       case FC_RCTL_DD_SOL_DATA:       /* solicited data */
+       case FC_RCTL_DD_UNSOL_CTL:      /* unsolicited control */
+       case FC_RCTL_DD_SOL_CTL:        /* solicited control or reply */
+       case FC_RCTL_DD_UNSOL_DATA:     /* unsolicited data */
+       case FC_RCTL_DD_DATA_DESC:      /* data descriptor */
+       case FC_RCTL_DD_UNSOL_CMD:      /* unsolicited command */
+       case FC_RCTL_DD_CMD_STATUS:     /* command status */
+       case FC_RCTL_ELS_REQ:   /* extended link services request */
+       case FC_RCTL_ELS_REP:   /* extended link services reply */
+       case FC_RCTL_ELS4_REQ:  /* FC-4 ELS request */
+       case FC_RCTL_ELS4_REP:  /* FC-4 ELS reply */
+       case FC_RCTL_BA_NOP:    /* basic link service NOP */
+       case FC_RCTL_BA_ABTS:   /* basic link service abort */
+       case FC_RCTL_BA_RMC:    /* remove connection */
+       case FC_RCTL_BA_ACC:    /* basic accept */
+       case FC_RCTL_BA_RJT:    /* basic reject */
+       case FC_RCTL_BA_PRMT:
+       case FC_RCTL_ACK_1:     /* acknowledge_1 */
+       case FC_RCTL_ACK_0:     /* acknowledge_0 */
+       case FC_RCTL_P_RJT:     /* port reject */
+       case FC_RCTL_F_RJT:     /* fabric reject */
+       case FC_RCTL_P_BSY:     /* port busy */
+       case FC_RCTL_F_BSY:     /* fabric busy to data frame */
+       case FC_RCTL_F_BSYL:    /* fabric busy to link control frame */
+       case FC_RCTL_LCR:       /* link credit reset */
+       case FC_RCTL_END:       /* end */
+               break;
+       case FC_RCTL_VFTH:      /* Virtual Fabric tagging Header */
+               fc_vft_hdr = (struct fc_vft_header *)fc_hdr;
+               fc_hdr = &((struct fc_frame_header *)fc_vft_hdr)[1];
+               return lpfc_fc_frame_check(phba, fc_hdr);
+       default:
+               goto drop;
+       }
+       switch (fc_hdr->fh_type) {
+       case FC_TYPE_BLS:
+       case FC_TYPE_ELS:
+       case FC_TYPE_FCP:
+       case FC_TYPE_CT:
+               break;
+       case FC_TYPE_IP:
+       case FC_TYPE_ILS:
+       default:
+               goto drop;
+       }
+       lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+                       "2538 Received frame rctl:%s type:%s\n",
+                       rctl_names[fc_hdr->fh_r_ctl],
+                       type_names[fc_hdr->fh_type]);
+       return 0;
+drop:
+       lpfc_printf_log(phba, KERN_WARNING, LOG_ELS,
+                       "2539 Dropped frame rctl:%s type:%s\n",
+                       rctl_names[fc_hdr->fh_r_ctl],
+                       type_names[fc_hdr->fh_type]);
+       return 1;
+}
+
+/**
+ * lpfc_fc_hdr_get_vfi - Get the VFI from an FC frame
+ * @fc_hdr: A pointer to the FC Header data (In Big Endian Format)
+ *
+ * This function processes the FC header to retrieve the VFI from the VF
+ * header, if one exists. This function will return the VFI if one exists
+ * or 0 if no VSAN Header exists.
+ **/
+static uint32_t
+lpfc_fc_hdr_get_vfi(struct fc_frame_header *fc_hdr)
+{
+       struct fc_vft_header *fc_vft_hdr = (struct fc_vft_header *)fc_hdr;
+
+       if (fc_hdr->fh_r_ctl != FC_RCTL_VFTH)
+               return 0;
+       return bf_get(fc_vft_hdr_vf_id, fc_vft_hdr);
+}
+
+/**
+ * lpfc_fc_frame_to_vport - Finds the vport that a frame is destined to
+ * @phba: Pointer to the HBA structure to search for the vport on
+ * @fc_hdr: A pointer to the FC Header data (In Big Endian Format)
+ * @fcfi: The FC Fabric ID that the frame came from
+ *
+ * This function searches the @phba for a vport that matches the content of the
+ * @fc_hdr passed in and the @fcfi. This function uses the @fc_hdr to fetch the
+ * VFI, if the Virtual Fabric Tagging Header exists, and the DID. This function
+ * returns the matching vport pointer or NULL if unable to match frame to a
+ * vport.
+ **/
+static struct lpfc_vport *
+lpfc_fc_frame_to_vport(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr,
+                      uint16_t fcfi)
+{
+       struct lpfc_vport **vports;
+       struct lpfc_vport *vport = NULL;
+       int i;
+       uint32_t did = (fc_hdr->fh_d_id[0] << 16 |
+                       fc_hdr->fh_d_id[1] << 8 |
+                       fc_hdr->fh_d_id[2]);
+
+       vports = lpfc_create_vport_work_array(phba);
+       if (vports != NULL)
+               for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+                       if (phba->fcf.fcfi == fcfi &&
+                           vports[i]->vfi == lpfc_fc_hdr_get_vfi(fc_hdr) &&
+                           vports[i]->fc_myDID == did) {
+                               vport = vports[i];
+                               break;
+                       }
+               }
+       lpfc_destroy_vport_work_array(phba, vports);
+       return vport;
+}
+
+/**
+ * lpfc_fc_frame_add - Adds a frame to the vport's list of received sequences
+ * @dmabuf: pointer to a dmabuf that describes the hdr and data of the FC frame
+ *
+ * This function searches through the existing incomplete sequences that have
+ * been sent to this @vport. If the frame matches one of the incomplete
+ * sequences then the dbuf in the @dmabuf is added to the list of frames that
+ * make up that sequence. If no sequence is found that matches this frame then
+ * the function will add the hbuf in the @dmabuf to the @vport's rcv_buffer_list
+ * This function returns a pointer to the first dmabuf in the sequence list that
+ * the frame was linked to.
+ **/
+static struct hbq_dmabuf *
+lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf)
+{
+       struct fc_frame_header *new_hdr;
+       struct fc_frame_header *temp_hdr;
+       struct lpfc_dmabuf *d_buf;
+       struct lpfc_dmabuf *h_buf;
+       struct hbq_dmabuf *seq_dmabuf = NULL;
+       struct hbq_dmabuf *temp_dmabuf = NULL;
+
+       new_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt;
+       /* Use the hdr_buf to find the sequence that this frame belongs to */
+       list_for_each_entry(h_buf, &vport->rcv_buffer_list, list) {
+               temp_hdr = (struct fc_frame_header *)h_buf->virt;
+               if ((temp_hdr->fh_seq_id != new_hdr->fh_seq_id) ||
+                   (temp_hdr->fh_ox_id != new_hdr->fh_ox_id) ||
+                   (memcmp(&temp_hdr->fh_s_id, &new_hdr->fh_s_id, 3)))
+                       continue;
+               /* found a pending sequence that matches this frame */
+               seq_dmabuf = container_of(h_buf, struct hbq_dmabuf, hbuf);
+               break;
+       }
+       if (!seq_dmabuf) {
+               /*
+                * This indicates first frame received for this sequence.
+                * Queue the buffer on the vport's rcv_buffer_list.
+                */
+               list_add_tail(&dmabuf->hbuf.list, &vport->rcv_buffer_list);
+               return dmabuf;
+       }
+       temp_hdr = seq_dmabuf->hbuf.virt;
+       if (new_hdr->fh_seq_cnt < temp_hdr->fh_seq_cnt) {
+               list_add(&seq_dmabuf->dbuf.list, &dmabuf->dbuf.list);
+               return dmabuf;
+       }
+       /* find the correct place in the sequence to insert this frame */
+       list_for_each_entry_reverse(d_buf, &seq_dmabuf->dbuf.list, list) {
+               temp_dmabuf = container_of(d_buf, struct hbq_dmabuf, dbuf);
+               temp_hdr = (struct fc_frame_header *)temp_dmabuf->hbuf.virt;
+               /*
+                * If the frame's sequence count is greater than the frame on
+                * the list then insert the frame right after this frame
+                */
+               if (new_hdr->fh_seq_cnt > temp_hdr->fh_seq_cnt) {
+                       list_add(&dmabuf->dbuf.list, &temp_dmabuf->dbuf.list);
+                       return seq_dmabuf;
+               }
+       }
+       return NULL;
+}
+
+/**
+ * lpfc_seq_complete - Indicates if a sequence is complete
+ * @dmabuf: pointer to a dmabuf that describes the FC sequence
+ *
+ * This function checks the sequence, starting with the frame described by
+ * @dmabuf, to see if all the frames associated with this sequence are present.
+ * the frames associated with this sequence are linked to the @dmabuf using the
+ * dbuf list. This function looks for two major things. 1) That the first frame
+ * has a sequence count of zero. 2) There is a frame with last frame of sequence
+ * set. 3) That there are no holes in the sequence count. The function will
+ * return 1 when the sequence is complete, otherwise it will return 0.
+ **/
+static int
+lpfc_seq_complete(struct hbq_dmabuf *dmabuf)
+{
+       struct fc_frame_header *hdr;
+       struct lpfc_dmabuf *d_buf;
+       struct hbq_dmabuf *seq_dmabuf;
+       uint32_t fctl;
+       int seq_count = 0;
+
+       hdr = (struct fc_frame_header *)dmabuf->hbuf.virt;
+       /* make sure first fame of sequence has a sequence count of zero */
+       if (hdr->fh_seq_cnt != seq_count)
+               return 0;
+       fctl = (hdr->fh_f_ctl[0] << 16 |
+               hdr->fh_f_ctl[1] << 8 |
+               hdr->fh_f_ctl[2]);
+       /* If last frame of sequence we can return success. */
+       if (fctl & FC_FC_END_SEQ)
+               return 1;
+       list_for_each_entry(d_buf, &dmabuf->dbuf.list, list) {
+               seq_dmabuf = container_of(d_buf, struct hbq_dmabuf, dbuf);
+               hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt;
+               /* If there is a hole in the sequence count then fail. */
+               if (++seq_count != hdr->fh_seq_cnt)
+                       return 0;
+               fctl = (hdr->fh_f_ctl[0] << 16 |
+                       hdr->fh_f_ctl[1] << 8 |
+                       hdr->fh_f_ctl[2]);
+               /* If last frame of sequence we can return success. */
+               if (fctl & FC_FC_END_SEQ)
+                       return 1;
+       }
+       return 0;
+}
+
+/**
+ * lpfc_prep_seq - Prep sequence for ULP processing
+ * @vport: Pointer to the vport on which this sequence was received
+ * @dmabuf: pointer to a dmabuf that describes the FC sequence
+ *
+ * This function takes a sequence, described by a list of frames, and creates
+ * a list of iocbq structures to describe the sequence. This iocbq list will be
+ * used to issue to the generic unsolicited sequence handler. This routine
+ * returns a pointer to the first iocbq in the list. If the function is unable
+ * to allocate an iocbq then it throw out the received frames that were not
+ * able to be described and return a pointer to the first iocbq. If unable to
+ * allocate any iocbqs (including the first) this function will return NULL.
+ **/
+static struct lpfc_iocbq *
+lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
+{
+       struct lpfc_dmabuf *d_buf, *n_buf;
+       struct lpfc_iocbq *first_iocbq, *iocbq;
+       struct fc_frame_header *fc_hdr;
+       uint32_t sid;
+
+       fc_hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt;
+       /* remove from receive buffer list */
+       list_del_init(&seq_dmabuf->hbuf.list);
+       /* get the Remote Port's SID */
+       sid = (fc_hdr->fh_s_id[0] << 16 |
+              fc_hdr->fh_s_id[1] << 8 |
+              fc_hdr->fh_s_id[2]);
+       /* Get an iocbq struct to fill in. */
+       first_iocbq = lpfc_sli_get_iocbq(vport->phba);
+       if (first_iocbq) {
+               /* Initialize the first IOCB. */
+               first_iocbq->iocb.ulpStatus = IOSTAT_SUCCESS;
+               first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_SEQ64_CX;
+               first_iocbq->iocb.ulpContext = be16_to_cpu(fc_hdr->fh_ox_id);
+               first_iocbq->iocb.unsli3.rcvsli3.vpi =
+                                       vport->vpi + vport->phba->vpi_base;
+               /* put the first buffer into the first IOCBq */
+               first_iocbq->context2 = &seq_dmabuf->dbuf;
+               first_iocbq->context3 = NULL;
+               first_iocbq->iocb.ulpBdeCount = 1;
+               first_iocbq->iocb.un.cont64[0].tus.f.bdeSize =
+                                                       LPFC_DATA_BUF_SIZE;
+               first_iocbq->iocb.un.rcvels.remoteID = sid;
+       }
+       iocbq = first_iocbq;
+       /*
+        * Each IOCBq can have two Buffers assigned, so go through the list
+        * of buffers for this sequence and save two buffers in each IOCBq
+        */
+       list_for_each_entry_safe(d_buf, n_buf, &seq_dmabuf->dbuf.list, list) {
+               if (!iocbq) {
+                       lpfc_in_buf_free(vport->phba, d_buf);
+                       continue;
+               }
+               if (!iocbq->context3) {
+                       iocbq->context3 = d_buf;
+                       iocbq->iocb.ulpBdeCount++;
+                       iocbq->iocb.unsli3.rcvsli3.bde2.tus.f.bdeSize =
+                                                       LPFC_DATA_BUF_SIZE;
+               } else {
+                       iocbq = lpfc_sli_get_iocbq(vport->phba);
+                       if (!iocbq) {
+                               if (first_iocbq) {
+                                       first_iocbq->iocb.ulpStatus =
+                                                       IOSTAT_FCP_RSP_ERROR;
+                                       first_iocbq->iocb.un.ulpWord[4] =
+                                                       IOERR_NO_RESOURCES;
+                               }
+                               lpfc_in_buf_free(vport->phba, d_buf);
+                               continue;
+                       }
+                       iocbq->context2 = d_buf;
+                       iocbq->context3 = NULL;
+                       iocbq->iocb.ulpBdeCount = 1;
+                       iocbq->iocb.un.cont64[0].tus.f.bdeSize =
+                                                       LPFC_DATA_BUF_SIZE;
+                       iocbq->iocb.un.rcvels.remoteID = sid;
+                       list_add_tail(&iocbq->list, &first_iocbq->list);
+               }
+       }
+       return first_iocbq;
+}
+
+/**
+ * lpfc_sli4_handle_received_buffer - Handle received buffers from firmware
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called with no lock held. This function processes all
+ * the received buffers and gives it to upper layers when a received buffer
+ * indicates that it is the final frame in the sequence. The interrupt
+ * service routine processes received buffers at interrupt contexts and adds
+ * received dma buffers to the rb_pend_list queue and signals the worker thread.
+ * Worker thread calls lpfc_sli4_handle_received_buffer, which will call the
+ * appropriate receive function when the final frame in a sequence is received.
+ **/
+int
+lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba)
+{
+       LIST_HEAD(cmplq);
+       struct hbq_dmabuf *dmabuf, *seq_dmabuf;
+       struct fc_frame_header *fc_hdr;
+       struct lpfc_vport *vport;
+       uint32_t fcfi;
+       struct lpfc_iocbq *iocbq;
+
+       /* Clear hba flag and get all received buffers into the cmplq */
+       spin_lock_irq(&phba->hbalock);
+       phba->hba_flag &= ~HBA_RECEIVE_BUFFER;
+       list_splice_init(&phba->rb_pend_list, &cmplq);
+       spin_unlock_irq(&phba->hbalock);
+
+       /* Process each received buffer */
+       while ((dmabuf = lpfc_sli_hbqbuf_get(&cmplq)) != NULL) {
+               fc_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt;
+               /* check to see if this a valid type of frame */
+               if (lpfc_fc_frame_check(phba, fc_hdr)) {
+                       lpfc_in_buf_free(phba, &dmabuf->dbuf);
+                       continue;
+               }
+               fcfi = bf_get(lpfc_rcqe_fcf_id, &dmabuf->rcqe);
+               vport = lpfc_fc_frame_to_vport(phba, fc_hdr, fcfi);
+               if (!vport) {
+                       /* throw out the frame */
+                       lpfc_in_buf_free(phba, &dmabuf->dbuf);
+                       continue;
+               }
+               /* Link this frame */
+               seq_dmabuf = lpfc_fc_frame_add(vport, dmabuf);
+               if (!seq_dmabuf) {
+                       /* unable to add frame to vport - throw it out */
+                       lpfc_in_buf_free(phba, &dmabuf->dbuf);
+                       continue;
+               }
+               /* If not last frame in sequence continue processing frames. */
+               if (!lpfc_seq_complete(seq_dmabuf)) {
+                       /*
+                        * When saving off frames post a new one and mark this
+                        * frame to be freed when it is finished.
+                        **/
+                       lpfc_sli_hbqbuf_fill_hbqs(phba, LPFC_ELS_HBQ, 1);
+                       dmabuf->tag = -1;
+                       continue;
+               }
+               fc_hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt;
+               iocbq = lpfc_prep_seq(vport, seq_dmabuf);
+               if (!lpfc_complete_unsol_iocb(phba,
+                                             &phba->sli.ring[LPFC_ELS_RING],
+                                             iocbq, fc_hdr->fh_r_ctl,
+                                             fc_hdr->fh_type))
+                       lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+                                       "2540 Ring %d handler: unexpected Rctl "
+                                       "x%x Type x%x received\n",
+                                       LPFC_ELS_RING,
+                                       fc_hdr->fh_r_ctl, fc_hdr->fh_type);
+       };
+       return 0;
+}
+
+/**
+ * lpfc_sli4_post_all_rpi_hdrs - Post the rpi header memory region to the port
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to post rpi header templates to the
+ * HBA consistent with the SLI-4 interface spec.  This routine
+ * posts a PAGE_SIZE memory region to the port to hold up to
+ * PAGE_SIZE modulo 64 rpi context headers.
+ *
+ * This routine does not require any locks.  It's usage is expected
+ * to be driver load or reset recovery when the driver is
+ * sequential.
+ *
+ * Return codes
+ *     0 - sucessful
+ *      EIO - The mailbox failed to complete successfully.
+ *     When this error occurs, the driver is not guaranteed
+ *     to have any rpi regions posted to the device and
+ *     must either attempt to repost the regions or take a
+ *     fatal error.
+ **/
+int
+lpfc_sli4_post_all_rpi_hdrs(struct lpfc_hba *phba)
+{
+       struct lpfc_rpi_hdr *rpi_page;
+       uint32_t rc = 0;
+
+       /* Post all rpi memory regions to the port. */
+       list_for_each_entry(rpi_page, &phba->sli4_hba.lpfc_rpi_hdr_list, list) {
+               rc = lpfc_sli4_post_rpi_hdr(phba, rpi_page);
+               if (rc != MBX_SUCCESS) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                                       "2008 Error %d posting all rpi "
+                                       "headers\n", rc);
+                       rc = -EIO;
+                       break;
+               }
+       }
+
+       return rc;
+}
+
+/**
+ * lpfc_sli4_post_rpi_hdr - Post an rpi header memory region to the port
+ * @phba: pointer to lpfc hba data structure.
+ * @rpi_page:  pointer to the rpi memory region.
+ *
+ * This routine is invoked to post a single rpi header to the
+ * HBA consistent with the SLI-4 interface spec.  This memory region
+ * maps up to 64 rpi context regions.
+ *
+ * Return codes
+ *     0 - sucessful
+ *     ENOMEM - No available memory
+ *      EIO - The mailbox failed to complete successfully.
+ **/
+int
+lpfc_sli4_post_rpi_hdr(struct lpfc_hba *phba, struct lpfc_rpi_hdr *rpi_page)
+{
+       LPFC_MBOXQ_t *mboxq;
+       struct lpfc_mbx_post_hdr_tmpl *hdr_tmpl;
+       uint32_t rc = 0;
+       uint32_t mbox_tmo;
+       uint32_t shdr_status, shdr_add_status;
+       union lpfc_sli4_cfg_shdr *shdr;
+
+       /* The port is notified of the header region via a mailbox command. */
+       mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mboxq) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "2001 Unable to allocate memory for issuing "
+                               "SLI_CONFIG_SPECIAL mailbox command\n");
+               return -ENOMEM;
+       }
+
+       /* Post all rpi memory regions to the port. */
+       hdr_tmpl = &mboxq->u.mqe.un.hdr_tmpl;
+       mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG);
+       lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_FCOE,
+                        LPFC_MBOX_OPCODE_FCOE_POST_HDR_TEMPLATE,
+                        sizeof(struct lpfc_mbx_post_hdr_tmpl) -
+                        sizeof(struct mbox_header), LPFC_SLI4_MBX_EMBED);
+       bf_set(lpfc_mbx_post_hdr_tmpl_page_cnt,
+              hdr_tmpl, rpi_page->page_count);
+       bf_set(lpfc_mbx_post_hdr_tmpl_rpi_offset, hdr_tmpl,
+              rpi_page->start_rpi);
+       hdr_tmpl->rpi_paddr_lo = putPaddrLow(rpi_page->dmabuf->phys);
+       hdr_tmpl->rpi_paddr_hi = putPaddrHigh(rpi_page->dmabuf->phys);
+       if (!phba->sli4_hba.intr_enable)
+               rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+       else
+               rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo);
+       shdr = (union lpfc_sli4_cfg_shdr *) &hdr_tmpl->header.cfg_shdr;
+       shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+       if (rc != MBX_TIMEOUT)
+               mempool_free(mboxq, phba->mbox_mem_pool);
+       if (shdr_status || shdr_add_status || rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2514 POST_RPI_HDR mailbox failed with "
+                               "status x%x add_status x%x, mbx status x%x\n",
+                               shdr_status, shdr_add_status, rc);
+               rc = -ENXIO;
+       }
+       return rc;
+}
+
+/**
+ * lpfc_sli4_alloc_rpi - Get an available rpi in the device's range
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to post rpi header templates to the
+ * HBA consistent with the SLI-4 interface spec.  This routine
+ * posts a PAGE_SIZE memory region to the port to hold up to
+ * PAGE_SIZE modulo 64 rpi context headers.
+ *
+ * Returns
+ *     A nonzero rpi defined as rpi_base <= rpi < max_rpi if sucessful
+ *     LPFC_RPI_ALLOC_ERROR if no rpis are available.
+ **/
+int
+lpfc_sli4_alloc_rpi(struct lpfc_hba *phba)
+{
+       int rpi;
+       uint16_t max_rpi, rpi_base, rpi_limit;
+       uint16_t rpi_remaining;
+       struct lpfc_rpi_hdr *rpi_hdr;
+
+       max_rpi = phba->sli4_hba.max_cfg_param.max_rpi;
+       rpi_base = phba->sli4_hba.max_cfg_param.rpi_base;
+       rpi_limit = phba->sli4_hba.next_rpi;
+
+       /*
+        * The valid rpi range is not guaranteed to be zero-based.  Start
+        * the search at the rpi_base as reported by the port.
+        */
+       spin_lock_irq(&phba->hbalock);
+       rpi = find_next_zero_bit(phba->sli4_hba.rpi_bmask, rpi_limit, rpi_base);
+       if (rpi >= rpi_limit || rpi < rpi_base)
+               rpi = LPFC_RPI_ALLOC_ERROR;
+       else {
+               set_bit(rpi, phba->sli4_hba.rpi_bmask);
+               phba->sli4_hba.max_cfg_param.rpi_used++;
+               phba->sli4_hba.rpi_count++;
+       }
+
+       /*
+        * Don't try to allocate more rpi header regions if the device limit
+        * on available rpis max has been exhausted.
+        */
+       if ((rpi == LPFC_RPI_ALLOC_ERROR) &&
+           (phba->sli4_hba.rpi_count >= max_rpi)) {
+               spin_unlock_irq(&phba->hbalock);
+               return rpi;
+       }
+
+       /*
+        * If the driver is running low on rpi resources, allocate another
+        * page now.  Note that the next_rpi value is used because
+        * it represents how many are actually in use whereas max_rpi notes
+        * how many are supported max by the device.
+        */
+       rpi_remaining = phba->sli4_hba.next_rpi - rpi_base -
+               phba->sli4_hba.rpi_count;
+       spin_unlock_irq(&phba->hbalock);
+       if (rpi_remaining < LPFC_RPI_LOW_WATER_MARK) {
+               rpi_hdr = lpfc_sli4_create_rpi_hdr(phba);
+               if (!rpi_hdr) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                                       "2002 Error Could not grow rpi "
+                                       "count\n");
+               } else {
+                       lpfc_sli4_post_rpi_hdr(phba, rpi_hdr);
+               }
+       }
+
+       return rpi;
+}
+
+/**
+ * lpfc_sli4_free_rpi - Release an rpi for reuse.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to release an rpi to the pool of
+ * available rpis maintained by the driver.
+ **/
+void
+lpfc_sli4_free_rpi(struct lpfc_hba *phba, int rpi)
+{
+       spin_lock_irq(&phba->hbalock);
+       clear_bit(rpi, phba->sli4_hba.rpi_bmask);
+       phba->sli4_hba.rpi_count--;
+       phba->sli4_hba.max_cfg_param.rpi_used--;
+       spin_unlock_irq(&phba->hbalock);
+}
+
+/**
+ * lpfc_sli4_remove_rpis - Remove the rpi bitmask region
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to remove the memory region that
+ * provided rpi via a bitmask.
+ **/
+void
+lpfc_sli4_remove_rpis(struct lpfc_hba *phba)
+{
+       kfree(phba->sli4_hba.rpi_bmask);
+}
+
+/**
+ * lpfc_sli4_resume_rpi - Remove the rpi bitmask region
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to remove the memory region that
+ * provided rpi via a bitmask.
+ **/
+int
+lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp)
+{
+       LPFC_MBOXQ_t *mboxq;
+       struct lpfc_hba *phba = ndlp->phba;
+       int rc;
+
+       /* The port is notified of the header region via a mailbox command. */
+       mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mboxq)
+               return -ENOMEM;
+
+       /* Post all rpi memory regions to the port. */
+       lpfc_resume_rpi(mboxq, ndlp);
+       rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
+       if (rc == MBX_NOT_FINISHED) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "2010 Resume RPI Mailbox failed "
+                               "status %d, mbxStatus x%x\n", rc,
+                               bf_get(lpfc_mqe_status, &mboxq->u.mqe));
+               mempool_free(mboxq, phba->mbox_mem_pool);
+               return -EIO;
+       }
+       return 0;
+}
+
+/**
+ * lpfc_sli4_init_vpi - Initialize a vpi with the port
+ * @phba: pointer to lpfc hba data structure.
+ * @vpi: vpi value to activate with the port.
+ *
+ * This routine is invoked to activate a vpi with the
+ * port when the host intends to use vports with a
+ * nonzero vpi.
+ *
+ * Returns:
+ *    0 success
+ *    -Evalue otherwise
+ **/
+int
+lpfc_sli4_init_vpi(struct lpfc_hba *phba, uint16_t vpi)
+{
+       LPFC_MBOXQ_t *mboxq;
+       int rc = 0;
+       uint32_t mbox_tmo;
+
+       if (vpi == 0)
+               return -EINVAL;
+       mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mboxq)
+               return -ENOMEM;
+       lpfc_init_vpi(mboxq, vpi);
+       mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_INIT_VPI);
+       rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo);
+       if (rc != MBX_TIMEOUT)
+               mempool_free(mboxq, phba->mbox_mem_pool);
+       if (rc != MBX_SUCCESS) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "2022 INIT VPI Mailbox failed "
+                               "status %d, mbxStatus x%x\n", rc,
+                               bf_get(lpfc_mqe_status, &mboxq->u.mqe));
+               rc = -EIO;
+       }
+       return rc;
+}
+
+/**
+ * lpfc_mbx_cmpl_add_fcf_record - add fcf mbox completion handler.
+ * @phba: pointer to lpfc hba data structure.
+ * @mboxq: Pointer to mailbox object.
+ *
+ * This routine is invoked to manually add a single FCF record. The caller
+ * must pass a completely initialized FCF_Record.  This routine takes
+ * care of the nonembedded mailbox operations.
+ **/
+static void
+lpfc_mbx_cmpl_add_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+{
+       void *virt_addr;
+       union lpfc_sli4_cfg_shdr *shdr;
+       uint32_t shdr_status, shdr_add_status;
+
+       virt_addr = mboxq->sge_array->addr[0];
+       /* The IOCTL status is embedded in the mailbox subheader. */
+       shdr = (union lpfc_sli4_cfg_shdr *) virt_addr;
+       shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+
+       if ((shdr_status || shdr_add_status) &&
+               (shdr_status != STATUS_FCF_IN_USE))
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                       "2558 ADD_FCF_RECORD mailbox failed with "
+                       "status x%x add_status x%x\n",
+                       shdr_status, shdr_add_status);
+
+       lpfc_sli4_mbox_cmd_free(phba, mboxq);
+}
+
+/**
+ * lpfc_sli4_add_fcf_record - Manually add an FCF Record.
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_record:  pointer to the initialized fcf record to add.
+ *
+ * This routine is invoked to manually add a single FCF record. The caller
+ * must pass a completely initialized FCF_Record.  This routine takes
+ * care of the nonembedded mailbox operations.
+ **/
+int
+lpfc_sli4_add_fcf_record(struct lpfc_hba *phba, struct fcf_record *fcf_record)
+{
+       int rc = 0;
+       LPFC_MBOXQ_t *mboxq;
+       uint8_t *bytep;
+       void *virt_addr;
+       dma_addr_t phys_addr;
+       struct lpfc_mbx_sge sge;
+       uint32_t alloc_len, req_len;
+       uint32_t fcfindex;
+
+       mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mboxq) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                       "2009 Failed to allocate mbox for ADD_FCF cmd\n");
+               return -ENOMEM;
+       }
+
+       req_len = sizeof(struct fcf_record) + sizeof(union lpfc_sli4_cfg_shdr) +
+                 sizeof(uint32_t);
+
+       /* Allocate DMA memory and set up the non-embedded mailbox command */
+       alloc_len = lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_FCOE,
+                                    LPFC_MBOX_OPCODE_FCOE_ADD_FCF,
+                                    req_len, LPFC_SLI4_MBX_NEMBED);
+       if (alloc_len < req_len) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                       "2523 Allocated DMA memory size (x%x) is "
+                       "less than the requested DMA memory "
+                       "size (x%x)\n", alloc_len, req_len);
+               lpfc_sli4_mbox_cmd_free(phba, mboxq);
+               return -ENOMEM;
+       }
+
+       /*
+        * Get the first SGE entry from the non-embedded DMA memory.  This
+        * routine only uses a single SGE.
+        */
+       lpfc_sli4_mbx_sge_get(mboxq, 0, &sge);
+       phys_addr = getPaddr(sge.pa_hi, sge.pa_lo);
+       if (unlikely(!mboxq->sge_array)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+                               "2526 Failed to get the non-embedded SGE "
+                               "virtual address\n");
+               lpfc_sli4_mbox_cmd_free(phba, mboxq);
+               return -ENOMEM;
+       }
+       virt_addr = mboxq->sge_array->addr[0];
+       /*
+        * Configure the FCF record for FCFI 0.  This is the driver's
+        * hardcoded default and gets used in nonFIP mode.
+        */
+       fcfindex = bf_get(lpfc_fcf_record_fcf_index, fcf_record);
+       bytep = virt_addr + sizeof(union lpfc_sli4_cfg_shdr);
+       lpfc_sli_pcimem_bcopy(&fcfindex, bytep, sizeof(uint32_t));
+
+       /*
+        * Copy the fcf_index and the FCF Record Data. The data starts after
+        * the FCoE header plus word10. The data copy needs to be endian
+        * correct.
+        */
+       bytep += sizeof(uint32_t);
+       lpfc_sli_pcimem_bcopy(fcf_record, bytep, sizeof(struct fcf_record));
+       mboxq->vport = phba->pport;
+       mboxq->mbox_cmpl = lpfc_mbx_cmpl_add_fcf_record;
+       rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
+       if (rc == MBX_NOT_FINISHED) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                       "2515 ADD_FCF_RECORD mailbox failed with "
+                       "status 0x%x\n", rc);
+               lpfc_sli4_mbox_cmd_free(phba, mboxq);
+               rc = -EIO;
+       } else
+               rc = 0;
+
+       return rc;
+}
+
+/**
+ * lpfc_sli4_build_dflt_fcf_record - Build the driver's default FCF Record.
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_record:  pointer to the fcf record to write the default data.
+ * @fcf_index: FCF table entry index.
+ *
+ * This routine is invoked to build the driver's default FCF record.  The
+ * values used are hardcoded.  This routine handles memory initialization.
+ *
+ **/
+void
+lpfc_sli4_build_dflt_fcf_record(struct lpfc_hba *phba,
+                               struct fcf_record *fcf_record,
+                               uint16_t fcf_index)
+{
+       memset(fcf_record, 0, sizeof(struct fcf_record));
+       fcf_record->max_rcv_size = LPFC_FCOE_MAX_RCV_SIZE;
+       fcf_record->fka_adv_period = LPFC_FCOE_FKA_ADV_PER;
+       fcf_record->fip_priority = LPFC_FCOE_FIP_PRIORITY;
+       bf_set(lpfc_fcf_record_mac_0, fcf_record, phba->fc_map[0]);
+       bf_set(lpfc_fcf_record_mac_1, fcf_record, phba->fc_map[1]);
+       bf_set(lpfc_fcf_record_mac_2, fcf_record, phba->fc_map[2]);
+       bf_set(lpfc_fcf_record_mac_3, fcf_record, LPFC_FCOE_FCF_MAC3);
+       bf_set(lpfc_fcf_record_mac_4, fcf_record, LPFC_FCOE_FCF_MAC4);
+       bf_set(lpfc_fcf_record_mac_5, fcf_record, LPFC_FCOE_FCF_MAC5);
+       bf_set(lpfc_fcf_record_fc_map_0, fcf_record, phba->fc_map[0]);
+       bf_set(lpfc_fcf_record_fc_map_1, fcf_record, phba->fc_map[1]);
+       bf_set(lpfc_fcf_record_fc_map_2, fcf_record, phba->fc_map[2]);
+       bf_set(lpfc_fcf_record_fcf_valid, fcf_record, 1);
+       bf_set(lpfc_fcf_record_fcf_index, fcf_record, fcf_index);
+       bf_set(lpfc_fcf_record_mac_addr_prov, fcf_record,
+               LPFC_FCF_FPMA | LPFC_FCF_SPMA);
+       /* Set the VLAN bit map */
+       if (phba->valid_vlan) {
+               fcf_record->vlan_bitmap[phba->vlan_id / 8]
+                       = 1 << (phba->vlan_id % 8);
+       }
+}
+
+/**
+ * lpfc_sli4_read_fcf_record - Read the driver's default FCF Record.
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_index: FCF table entry offset.
+ *
+ * This routine is invoked to read up to @fcf_num of FCF record from the
+ * device starting with the given @fcf_index.
+ **/
+int
+lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index)
+{
+       int rc = 0, error;
+       LPFC_MBOXQ_t *mboxq;
+       void *virt_addr;
+       dma_addr_t phys_addr;
+       uint8_t *bytep;
+       struct lpfc_mbx_sge sge;
+       uint32_t alloc_len, req_len;
+       struct lpfc_mbx_read_fcf_tbl *read_fcf;
+
+       mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mboxq) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2000 Failed to allocate mbox for "
+                               "READ_FCF cmd\n");
+               return -ENOMEM;
+       }
+
+       req_len = sizeof(struct fcf_record) +
+                 sizeof(union lpfc_sli4_cfg_shdr) + 2 * sizeof(uint32_t);
+
+       /* Set up READ_FCF SLI4_CONFIG mailbox-ioctl command */
+       alloc_len = lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_FCOE,
+                        LPFC_MBOX_OPCODE_FCOE_READ_FCF_TABLE, req_len,
+                        LPFC_SLI4_MBX_NEMBED);
+
+       if (alloc_len < req_len) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "0291 Allocated DMA memory size (x%x) is "
+                               "less than the requested DMA memory "
+                               "size (x%x)\n", alloc_len, req_len);
+               lpfc_sli4_mbox_cmd_free(phba, mboxq);
+               return -ENOMEM;
+       }
+
+       /* Get the first SGE entry from the non-embedded DMA memory. This
+        * routine only uses a single SGE.
+        */
+       lpfc_sli4_mbx_sge_get(mboxq, 0, &sge);
+       phys_addr = getPaddr(sge.pa_hi, sge.pa_lo);
+       if (unlikely(!mboxq->sge_array)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+                               "2527 Failed to get the non-embedded SGE "
+                               "virtual address\n");
+               lpfc_sli4_mbox_cmd_free(phba, mboxq);
+               return -ENOMEM;
+       }
+       virt_addr = mboxq->sge_array->addr[0];
+       read_fcf = (struct lpfc_mbx_read_fcf_tbl *)virt_addr;
+
+       /* Set up command fields */
+       bf_set(lpfc_mbx_read_fcf_tbl_indx, &read_fcf->u.request, fcf_index);
+       /* Perform necessary endian conversion */
+       bytep = virt_addr + sizeof(union lpfc_sli4_cfg_shdr);
+       lpfc_sli_pcimem_bcopy(bytep, bytep, sizeof(uint32_t));
+       mboxq->vport = phba->pport;
+       mboxq->mbox_cmpl = lpfc_mbx_cmpl_read_fcf_record;
+       rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
+       if (rc == MBX_NOT_FINISHED) {
+               lpfc_sli4_mbox_cmd_free(phba, mboxq);
+               error = -EIO;
+       } else
+               error = 0;
+       return error;
+}
index 883938652a6a4eabb2417cf68b69aa1718492888..7d37eb7459bf05ac4ebe326c2df466e2dfb69a1e 100644 (file)
@@ -29,13 +29,23 @@ typedef enum _lpfc_ctx_cmd {
        LPFC_CTX_HOST
 } lpfc_ctx_cmd;
 
+/* This structure is used to carry the needed response IOCB states */
+struct lpfc_sli4_rspiocb_info {
+       uint8_t hw_status;
+       uint8_t bfield;
+#define LPFC_XB        0x1
+#define LPFC_PV        0x2
+       uint8_t priority;
+       uint8_t reserved;
+};
+
 /* This structure is used to handle IOCB requests / responses */
 struct lpfc_iocbq {
        /* lpfc_iocbqs are used in double linked lists */
        struct list_head list;
        struct list_head clist;
        uint16_t iotag;         /* pre-assigned IO tag */
-       uint16_t rsvd1;
+       uint16_t sli4_xritag;   /* pre-assigned XRI, (OXID) tag. */
 
        IOCB_t iocb;            /* IOCB cmd */
        uint8_t retry;          /* retry counter for IOCB cmd - if needed */
@@ -65,7 +75,7 @@ struct lpfc_iocbq {
                           struct lpfc_iocbq *);
        void (*iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
                           struct lpfc_iocbq *);
-
+       struct lpfc_sli4_rspiocb_info sli4_info;
 };
 
 #define SLI_IOCB_RET_IOCB      1       /* Return IOCB if cmd ring full */
@@ -81,14 +91,18 @@ struct lpfc_iocbq {
 typedef struct lpfcMboxq {
        /* MBOXQs are used in single linked lists */
        struct list_head list;  /* ptr to next mailbox command */
-       MAILBOX_t mb;           /* Mailbox cmd */
-       struct lpfc_vport *vport;/* virutal port pointer */
+       union {
+               MAILBOX_t mb;           /* Mailbox cmd */
+               struct lpfc_mqe mqe;
+       } u;
+       struct lpfc_vport *vport;/* virtual port pointer */
        void *context1;         /* caller context information */
        void *context2;         /* caller context information */
 
        void (*mbox_cmpl) (struct lpfc_hba *, struct lpfcMboxq *);
        uint8_t mbox_flag;
-
+       struct lpfc_mcqe mcqe;
+       struct lpfc_mbx_nembed_sge_virt *sge_array;
 } LPFC_MBOXQ_t;
 
 #define MBX_POLL        1      /* poll mailbox till command done, then
@@ -230,10 +244,11 @@ struct lpfc_sli {
 
        /* Additional sli_flags */
 #define LPFC_SLI_MBOX_ACTIVE      0x100        /* HBA mailbox is currently active */
-#define LPFC_SLI2_ACTIVE          0x200        /* SLI2 overlay in firmware is active */
+#define LPFC_SLI_ACTIVE           0x200        /* SLI in firmware is active */
 #define LPFC_PROCESS_LA           0x400        /* Able to process link attention */
 #define LPFC_BLOCK_MGMT_IO        0x800        /* Don't allow mgmt mbx or iocb cmds */
 #define LPFC_MENLO_MAINT          0x1000 /* need for menl fw download */
+#define LPFC_SLI_ASYNC_MBX_BLK    0x2000 /* Async mailbox is blocked */
 
        struct lpfc_sli_ring ring[LPFC_MAX_RING];
        int fcp_ring;           /* ring used for FCP initiator commands */
@@ -261,6 +276,8 @@ struct lpfc_sli {
 
 #define LPFC_MBOX_TMO           30     /* Sec tmo for outstanding mbox
                                           command */
+#define LPFC_MBOX_SLI4_CONFIG_TMO 60   /* Sec tmo for outstanding mbox
+                                          command */
 #define LPFC_MBOX_TMO_FLASH_CMD 300     /* Sec tmo for outstanding FLASH write
                                         * or erase cmds. This is especially
                                         * long because of the potential of
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
new file mode 100644 (file)
index 0000000..5196b46
--- /dev/null
@@ -0,0 +1,467 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Fibre Channel Host Bus Adapters.                                *
+ * Copyright (C) 2009 Emulex.  All rights reserved.                *
+ * EMULEX and SLI are trademarks of Emulex.                        *
+ * www.emulex.com                                                  *
+ *                                                                 *
+ * This program is free software; you can redistribute it and/or   *
+ * modify it under the terms of version 2 of the GNU General       *
+ * Public License as published by the Free Software Foundation.    *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
+ * more details, a copy of which can be found in the file COPYING  *
+ * included with this package.                                     *
+ *******************************************************************/
+
+#define LPFC_ACTIVE_MBOX_WAIT_CNT               100
+#define LPFC_RELEASE_NOTIFICATION_INTERVAL     32
+#define LPFC_GET_QE_REL_INT                    32
+#define LPFC_RPI_LOW_WATER_MARK                        10
+/* Number of SGL entries can be posted in a 4KB nonembedded mbox command */
+#define LPFC_NEMBED_MBOX_SGL_CNT               254
+
+/* Multi-queue arrangement for fast-path FCP work queues */
+#define LPFC_FN_EQN_MAX       8
+#define LPFC_SP_EQN_DEF       1
+#define LPFC_FP_EQN_DEF       1
+#define LPFC_FP_EQN_MIN       1
+#define LPFC_FP_EQN_MAX       (LPFC_FN_EQN_MAX - LPFC_SP_EQN_DEF)
+
+#define LPFC_FN_WQN_MAX       32
+#define LPFC_SP_WQN_DEF       1
+#define LPFC_FP_WQN_DEF       4
+#define LPFC_FP_WQN_MIN       1
+#define LPFC_FP_WQN_MAX       (LPFC_FN_WQN_MAX - LPFC_SP_WQN_DEF)
+
+/*
+ * Provide the default FCF Record attributes used by the driver
+ * when nonFIP mode is configured and there is no other default
+ * FCF Record attributes.
+ */
+#define LPFC_FCOE_FCF_DEF_INDEX        0
+#define LPFC_FCOE_FCF_GET_FIRST        0xFFFF
+#define LPFC_FCOE_FCF_NEXT_NONE        0xFFFF
+
+/* First 3 bytes of default FCF MAC is specified by FC_MAP */
+#define LPFC_FCOE_FCF_MAC3     0xFF
+#define LPFC_FCOE_FCF_MAC4     0xFF
+#define LPFC_FCOE_FCF_MAC5     0xFE
+#define LPFC_FCOE_FCF_MAP0     0x0E
+#define LPFC_FCOE_FCF_MAP1     0xFC
+#define LPFC_FCOE_FCF_MAP2     0x00
+#define LPFC_FCOE_MAX_RCV_SIZE 0x5AC
+#define LPFC_FCOE_FKA_ADV_PER  0
+#define LPFC_FCOE_FIP_PRIORITY 0x80
+
+enum lpfc_sli4_queue_type {
+       LPFC_EQ,
+       LPFC_GCQ,
+       LPFC_MCQ,
+       LPFC_WCQ,
+       LPFC_RCQ,
+       LPFC_MQ,
+       LPFC_WQ,
+       LPFC_HRQ,
+       LPFC_DRQ
+};
+
+/* The queue sub-type defines the functional purpose of the queue */
+enum lpfc_sli4_queue_subtype {
+       LPFC_NONE,
+       LPFC_MBOX,
+       LPFC_FCP,
+       LPFC_ELS,
+       LPFC_USOL
+};
+
+union sli4_qe {
+       void *address;
+       struct lpfc_eqe *eqe;
+       struct lpfc_cqe *cqe;
+       struct lpfc_mcqe *mcqe;
+       struct lpfc_wcqe_complete *wcqe_complete;
+       struct lpfc_wcqe_release *wcqe_release;
+       struct sli4_wcqe_xri_aborted *wcqe_xri_aborted;
+       struct lpfc_rcqe_complete *rcqe_complete;
+       struct lpfc_mqe *mqe;
+       union  lpfc_wqe *wqe;
+       struct lpfc_rqe *rqe;
+};
+
+struct lpfc_queue {
+       struct list_head list;
+       enum lpfc_sli4_queue_type type;
+       enum lpfc_sli4_queue_subtype subtype;
+       struct lpfc_hba *phba;
+       struct list_head child_list;
+       uint32_t entry_count;   /* Number of entries to support on the queue */
+       uint32_t entry_size;    /* Size of each queue entry. */
+       uint32_t queue_id;      /* Queue ID assigned by the hardware */
+       struct list_head page_list;
+       uint32_t page_count;    /* Number of pages allocated for this queue */
+
+       uint32_t host_index;    /* The host's index for putting or getting */
+       uint32_t hba_index;     /* The last known hba index for get or put */
+       union sli4_qe qe[1];    /* array to index entries (must be last) */
+};
+
+struct lpfc_cq_event {
+       struct list_head list;
+       union {
+               struct lpfc_mcqe                mcqe_cmpl;
+               struct lpfc_acqe_link           acqe_link;
+               struct lpfc_acqe_fcoe           acqe_fcoe;
+               struct lpfc_acqe_dcbx           acqe_dcbx;
+               struct lpfc_rcqe                rcqe_cmpl;
+               struct sli4_wcqe_xri_aborted    wcqe_axri;
+       } cqe;
+};
+
+struct lpfc_sli4_link {
+       uint8_t speed;
+       uint8_t duplex;
+       uint8_t status;
+       uint8_t physical;
+       uint8_t fault;
+};
+
+struct lpfc_fcf {
+       uint8_t  fabric_name[8];
+       uint8_t  mac_addr[6];
+       uint16_t fcf_indx;
+       uint16_t fcfi;
+       uint32_t fcf_flag;
+#define FCF_AVAILABLE  0x01 /* FCF available for discovery */
+#define FCF_REGISTERED 0x02 /* FCF registered with FW */
+#define FCF_DISCOVERED 0x04 /* FCF discovery started  */
+#define FCF_BOOT_ENABLE 0x08 /* Boot bios use this FCF */
+#define FCF_IN_USE     0x10 /* Atleast one discovery completed */
+#define FCF_VALID_VLAN 0x20 /* Use the vlan id specified */
+       uint32_t priority;
+       uint32_t addr_mode;
+       uint16_t vlan_id;
+};
+
+#define LPFC_REGION23_SIGNATURE "RG23"
+#define LPFC_REGION23_VERSION  1
+#define LPFC_REGION23_LAST_REC  0xff
+struct lpfc_fip_param_hdr {
+       uint8_t type;
+#define FCOE_PARAM_TYPE                0xA0
+       uint8_t length;
+#define FCOE_PARAM_LENGTH      2
+       uint8_t parm_version;
+#define FIPP_VERSION           0x01
+       uint8_t parm_flags;
+#define        lpfc_fip_param_hdr_fipp_mode_SHIFT      6
+#define        lpfc_fip_param_hdr_fipp_mode_MASK       0x3
+#define lpfc_fip_param_hdr_fipp_mode_WORD      parm_flags
+#define        FIPP_MODE_ON                            0x2
+#define        FIPP_MODE_OFF                           0x0
+#define FIPP_VLAN_VALID                                0x1
+};
+
+struct lpfc_fcoe_params {
+       uint8_t fc_map[3];
+       uint8_t reserved1;
+       uint16_t vlan_tag;
+       uint8_t reserved[2];
+};
+
+struct lpfc_fcf_conn_hdr {
+       uint8_t type;
+#define FCOE_CONN_TBL_TYPE             0xA1
+       uint8_t length;   /* words */
+       uint8_t reserved[2];
+};
+
+struct lpfc_fcf_conn_rec {
+       uint16_t flags;
+#define        FCFCNCT_VALID           0x0001
+#define        FCFCNCT_BOOT            0x0002
+#define        FCFCNCT_PRIMARY         0x0004   /* if not set, Secondary */
+#define        FCFCNCT_FBNM_VALID      0x0008
+#define        FCFCNCT_SWNM_VALID      0x0010
+#define        FCFCNCT_VLAN_VALID      0x0020
+#define        FCFCNCT_AM_VALID        0x0040
+#define        FCFCNCT_AM_PREFERRED    0x0080   /* if not set, AM Required */
+#define        FCFCNCT_AM_SPMA         0x0100   /* if not set, FPMA */
+
+       uint16_t vlan_tag;
+       uint8_t fabric_name[8];
+       uint8_t switch_name[8];
+};
+
+struct lpfc_fcf_conn_entry {
+       struct list_head list;
+       struct lpfc_fcf_conn_rec conn_rec;
+};
+
+/*
+ * Define the host's bootstrap mailbox.  This structure contains
+ * the member attributes needed to create, use, and destroy the
+ * bootstrap mailbox region.
+ *
+ * The macro definitions for the bmbx data structure are defined
+ * in lpfc_hw4.h with the register definition.
+ */
+struct lpfc_bmbx {
+       struct lpfc_dmabuf *dmabuf;
+       struct dma_address dma_address;
+       void *avirt;
+       dma_addr_t aphys;
+       uint32_t bmbx_size;
+};
+
+#define LPFC_EQE_SIZE LPFC_EQE_SIZE_4
+
+#define LPFC_EQE_SIZE_4B       4
+#define LPFC_EQE_SIZE_16B      16
+#define LPFC_CQE_SIZE          16
+#define LPFC_WQE_SIZE          64
+#define LPFC_MQE_SIZE          256
+#define LPFC_RQE_SIZE          8
+
+#define LPFC_EQE_DEF_COUNT     1024
+#define LPFC_CQE_DEF_COUNT      256
+#define LPFC_WQE_DEF_COUNT      64
+#define LPFC_MQE_DEF_COUNT      16
+#define LPFC_RQE_DEF_COUNT     512
+
+#define LPFC_QUEUE_NOARM       false
+#define LPFC_QUEUE_REARM       true
+
+
+/*
+ * SLI4 CT field defines
+ */
+#define SLI4_CT_RPI 0
+#define SLI4_CT_VPI 1
+#define SLI4_CT_VFI 2
+#define SLI4_CT_FCFI 3
+
+#define LPFC_SLI4_MAX_SEGMENT_SIZE 0x10000
+
+/*
+ * SLI4 specific data structures
+ */
+struct lpfc_max_cfg_param {
+       uint16_t max_xri;
+       uint16_t xri_base;
+       uint16_t xri_used;
+       uint16_t max_rpi;
+       uint16_t rpi_base;
+       uint16_t rpi_used;
+       uint16_t max_vpi;
+       uint16_t vpi_base;
+       uint16_t vpi_used;
+       uint16_t max_vfi;
+       uint16_t vfi_base;
+       uint16_t vfi_used;
+       uint16_t max_fcfi;
+       uint16_t fcfi_base;
+       uint16_t fcfi_used;
+       uint16_t max_eq;
+       uint16_t max_rq;
+       uint16_t max_cq;
+       uint16_t max_wq;
+};
+
+struct lpfc_hba;
+/* SLI4 HBA multi-fcp queue handler struct */
+struct lpfc_fcp_eq_hdl {
+       uint32_t idx;
+       struct lpfc_hba *phba;
+};
+
+/* SLI4 HBA data structure entries */
+struct lpfc_sli4_hba {
+       void __iomem *conf_regs_memmap_p; /* Kernel memory mapped address for
+                                            PCI BAR0, config space registers */
+       void __iomem *ctrl_regs_memmap_p; /* Kernel memory mapped address for
+                                            PCI BAR1, control registers */
+       void __iomem *drbl_regs_memmap_p; /* Kernel memory mapped address for
+                                            PCI BAR2, doorbell registers */
+       /* BAR0 PCI config space register memory map */
+       void __iomem *UERRLOregaddr; /* Address to UERR_STATUS_LO register */
+       void __iomem *UERRHIregaddr; /* Address to UERR_STATUS_HI register */
+       void __iomem *ONLINE0regaddr; /* Address to components of internal UE */
+       void __iomem *ONLINE1regaddr; /* Address to components of internal UE */
+#define LPFC_ONLINE_NERR       0xFFFFFFFF
+       void __iomem *SCRATCHPADregaddr; /* Address to scratchpad register */
+       /* BAR1 FCoE function CSR register memory map */
+       void __iomem *STAregaddr;    /* Address to HST_STATE register */
+       void __iomem *ISRregaddr;    /* Address to HST_ISR register */
+       void __iomem *IMRregaddr;    /* Address to HST_IMR register */
+       void __iomem *ISCRregaddr;   /* Address to HST_ISCR register */
+       /* BAR2 VF-0 doorbell register memory map */
+       void __iomem *RQDBregaddr;   /* Address to RQ_DOORBELL register */
+       void __iomem *WQDBregaddr;   /* Address to WQ_DOORBELL register */
+       void __iomem *EQCQDBregaddr; /* Address to EQCQ_DOORBELL register */
+       void __iomem *MQDBregaddr;   /* Address to MQ_DOORBELL register */
+       void __iomem *BMBXregaddr;   /* Address to BootStrap MBX register */
+
+       struct msix_entry *msix_entries;
+       uint32_t cfg_eqn;
+       struct lpfc_fcp_eq_hdl *fcp_eq_hdl; /* FCP per-WQ handle */
+       /* Pointers to the constructed SLI4 queues */
+       struct lpfc_queue **fp_eq; /* Fast-path event queue */
+       struct lpfc_queue *sp_eq;  /* Slow-path event queue */
+       struct lpfc_queue **fcp_wq;/* Fast-path FCP work queue */
+       struct lpfc_queue *mbx_wq; /* Slow-path MBOX work queue */
+       struct lpfc_queue *els_wq; /* Slow-path ELS work queue */
+       struct lpfc_queue *hdr_rq; /* Slow-path Header Receive queue */
+       struct lpfc_queue *dat_rq; /* Slow-path Data Receive queue */
+       struct lpfc_queue **fcp_cq;/* Fast-path FCP compl queue */
+       struct lpfc_queue *mbx_cq; /* Slow-path mailbox complete queue */
+       struct lpfc_queue *els_cq; /* Slow-path ELS response complete queue */
+       struct lpfc_queue *rxq_cq; /* Slow-path unsolicited complete queue */
+
+       /* Setup information for various queue parameters */
+       int eq_esize;
+       int eq_ecount;
+       int cq_esize;
+       int cq_ecount;
+       int wq_esize;
+       int wq_ecount;
+       int mq_esize;
+       int mq_ecount;
+       int rq_esize;
+       int rq_ecount;
+#define LPFC_SP_EQ_MAX_INTR_SEC         10000
+#define LPFC_FP_EQ_MAX_INTR_SEC         10000
+
+       uint32_t intr_enable;
+       struct lpfc_bmbx bmbx;
+       struct lpfc_max_cfg_param max_cfg_param;
+       uint16_t next_xri; /* last_xri - max_cfg_param.xri_base = used */
+       uint16_t next_rpi;
+       uint16_t scsi_xri_max;
+       uint16_t scsi_xri_cnt;
+       struct list_head lpfc_free_sgl_list;
+       struct list_head lpfc_sgl_list;
+       struct lpfc_sglq **lpfc_els_sgl_array;
+       struct list_head lpfc_abts_els_sgl_list;
+       struct lpfc_scsi_buf **lpfc_scsi_psb_array;
+       struct list_head lpfc_abts_scsi_buf_list;
+       uint32_t total_sglq_bufs;
+       struct lpfc_sglq **lpfc_sglq_active_list;
+       struct list_head lpfc_rpi_hdr_list;
+       unsigned long *rpi_bmask;
+       uint16_t rpi_count;
+       struct lpfc_sli4_flags sli4_flags;
+       struct list_head sp_rspiocb_work_queue;
+       struct list_head sp_cqe_event_pool;
+       struct list_head sp_asynce_work_queue;
+       struct list_head sp_fcp_xri_aborted_work_queue;
+       struct list_head sp_els_xri_aborted_work_queue;
+       struct list_head sp_unsol_work_queue;
+       struct lpfc_sli4_link link_state;
+       spinlock_t abts_scsi_buf_list_lock; /* list of aborted SCSI IOs */
+       spinlock_t abts_sgl_list_lock; /* list of aborted els IOs */
+};
+
+enum lpfc_sge_type {
+       GEN_BUFF_TYPE,
+       SCSI_BUFF_TYPE
+};
+
+struct lpfc_sglq {
+       /* lpfc_sglqs are used in double linked lists */
+       struct list_head list;
+       struct list_head clist;
+       enum lpfc_sge_type buff_type; /* is this a scsi sgl */
+       uint16_t iotag;         /* pre-assigned IO tag */
+       uint16_t sli4_xritag;   /* pre-assigned XRI, (OXID) tag. */
+       struct sli4_sge *sgl;   /* pre-assigned SGL */
+       void *virt;             /* virtual address. */
+       dma_addr_t phys;        /* physical address */
+};
+
+struct lpfc_rpi_hdr {
+       struct list_head list;
+       uint32_t len;
+       struct lpfc_dmabuf *dmabuf;
+       uint32_t page_count;
+       uint32_t start_rpi;
+};
+
+/*
+ * SLI4 specific function prototypes
+ */
+int lpfc_pci_function_reset(struct lpfc_hba *);
+int lpfc_sli4_hba_setup(struct lpfc_hba *);
+int lpfc_sli4_hba_down(struct lpfc_hba *);
+int lpfc_sli4_config(struct lpfc_hba *, struct lpfcMboxq *, uint8_t,
+                    uint8_t, uint32_t, bool);
+void lpfc_sli4_mbox_cmd_free(struct lpfc_hba *, struct lpfcMboxq *);
+void lpfc_sli4_mbx_sge_set(struct lpfcMboxq *, uint32_t, dma_addr_t, uint32_t);
+void lpfc_sli4_mbx_sge_get(struct lpfcMboxq *, uint32_t,
+                          struct lpfc_mbx_sge *);
+
+void lpfc_sli4_hba_reset(struct lpfc_hba *);
+struct lpfc_queue *lpfc_sli4_queue_alloc(struct lpfc_hba *, uint32_t,
+                       uint32_t);
+void lpfc_sli4_queue_free(struct lpfc_queue *);
+uint32_t lpfc_eq_create(struct lpfc_hba *, struct lpfc_queue *, uint16_t);
+uint32_t lpfc_cq_create(struct lpfc_hba *, struct lpfc_queue *,
+                       struct lpfc_queue *, uint32_t, uint32_t);
+uint32_t lpfc_mq_create(struct lpfc_hba *, struct lpfc_queue *,
+                       struct lpfc_queue *, uint32_t);
+uint32_t lpfc_wq_create(struct lpfc_hba *, struct lpfc_queue *,
+                       struct lpfc_queue *, uint32_t);
+uint32_t lpfc_rq_create(struct lpfc_hba *, struct lpfc_queue *,
+                       struct lpfc_queue *, struct lpfc_queue *, uint32_t);
+uint32_t lpfc_eq_destroy(struct lpfc_hba *, struct lpfc_queue *);
+uint32_t lpfc_cq_destroy(struct lpfc_hba *, struct lpfc_queue *);
+uint32_t lpfc_mq_destroy(struct lpfc_hba *, struct lpfc_queue *);
+uint32_t lpfc_wq_destroy(struct lpfc_hba *, struct lpfc_queue *);
+uint32_t lpfc_rq_destroy(struct lpfc_hba *, struct lpfc_queue *,
+                        struct lpfc_queue *);
+int lpfc_sli4_queue_setup(struct lpfc_hba *);
+void lpfc_sli4_queue_unset(struct lpfc_hba *);
+int lpfc_sli4_post_sgl(struct lpfc_hba *, dma_addr_t, dma_addr_t, uint16_t);
+int lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *);
+int lpfc_sli4_remove_all_sgl_pages(struct lpfc_hba *);
+uint16_t lpfc_sli4_next_xritag(struct lpfc_hba *);
+int lpfc_sli4_post_async_mbox(struct lpfc_hba *);
+int lpfc_sli4_post_sgl_list(struct lpfc_hba *phba);
+int lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *, struct list_head *, int);
+struct lpfc_cq_event *__lpfc_sli4_cq_event_alloc(struct lpfc_hba *);
+struct lpfc_cq_event *lpfc_sli4_cq_event_alloc(struct lpfc_hba *);
+void __lpfc_sli4_cq_event_release(struct lpfc_hba *, struct lpfc_cq_event *);
+void lpfc_sli4_cq_event_release(struct lpfc_hba *, struct lpfc_cq_event *);
+int lpfc_sli4_init_rpi_hdrs(struct lpfc_hba *);
+int lpfc_sli4_post_rpi_hdr(struct lpfc_hba *, struct lpfc_rpi_hdr *);
+int lpfc_sli4_post_all_rpi_hdrs(struct lpfc_hba *);
+struct lpfc_rpi_hdr *lpfc_sli4_create_rpi_hdr(struct lpfc_hba *);
+void lpfc_sli4_remove_rpi_hdrs(struct lpfc_hba *);
+int lpfc_sli4_alloc_rpi(struct lpfc_hba *);
+void lpfc_sli4_free_rpi(struct lpfc_hba *, int);
+void lpfc_sli4_remove_rpis(struct lpfc_hba *);
+void lpfc_sli4_async_event_proc(struct lpfc_hba *);
+int lpfc_sli4_resume_rpi(struct lpfc_nodelist *);
+void lpfc_sli4_fcp_xri_abort_event_proc(struct lpfc_hba *);
+void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *);
+void lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *,
+                              struct sli4_wcqe_xri_aborted *);
+void lpfc_sli4_els_xri_aborted(struct lpfc_hba *,
+                              struct sli4_wcqe_xri_aborted *);
+int lpfc_sli4_brdreset(struct lpfc_hba *);
+int lpfc_sli4_add_fcf_record(struct lpfc_hba *, struct fcf_record *);
+void lpfc_sli_remove_dflt_fcf(struct lpfc_hba *);
+int lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *);
+int lpfc_sli4_init_vpi(struct lpfc_hba *, uint16_t);
+uint32_t lpfc_sli4_cq_release(struct lpfc_queue *, bool);
+uint32_t lpfc_sli4_eq_release(struct lpfc_queue *, bool);
+void lpfc_sli4_fcfi_unreg(struct lpfc_hba *, uint16_t);
+int lpfc_sli4_read_fcf_record(struct lpfc_hba *, uint16_t);
+void lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *, LPFC_MBOXQ_t *);
+int lpfc_sli4_post_status_check(struct lpfc_hba *);
+uint8_t lpfc_sli4_mbox_opcode_get(struct lpfc_hba *, struct lpfcMboxq *);
+
index e599519e3078c214be69fd3ad415cc6648b653c2..6b8a148f0a55ca7f001dc87586972d9ac6b0ce65 100644 (file)
@@ -18,7 +18,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "8.3.1"
+#define LPFC_DRIVER_VERSION "8.3.2"
 
 #define LPFC_DRIVER_NAME               "lpfc"
 #define LPFC_SP_DRIVER_HANDLER_NAME    "lpfc:sp"
index 917ad56b0aff33c358e9632630142c75003f53e9..a6313ee84ac50356f289f02d28cc0c1788ba47d5 100644 (file)
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport_fc.h>
+#include "lpfc_hw4.h"
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
+#include "lpfc_sli4.h"
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -89,6 +91,8 @@ lpfc_alloc_vpi(struct lpfc_hba *phba)
                vpi = 0;
        else
                set_bit(vpi, phba->vpi_bmask);
+       if (phba->sli_rev == LPFC_SLI_REV4)
+               phba->sli4_hba.max_cfg_param.vpi_used++;
        spin_unlock_irq(&phba->hbalock);
        return vpi;
 }
@@ -96,8 +100,12 @@ lpfc_alloc_vpi(struct lpfc_hba *phba)
 static void
 lpfc_free_vpi(struct lpfc_hba *phba, int vpi)
 {
+       if (vpi == 0)
+               return;
        spin_lock_irq(&phba->hbalock);
        clear_bit(vpi, phba->vpi_bmask);
+       if (phba->sli_rev == LPFC_SLI_REV4)
+               phba->sli4_hba.max_cfg_param.vpi_used--;
        spin_unlock_irq(&phba->hbalock);
 }
 
@@ -113,7 +121,7 @@ lpfc_vport_sparm(struct lpfc_hba *phba, struct lpfc_vport *vport)
        if (!pmb) {
                return -ENOMEM;
        }
-       mb = &pmb->mb;
+       mb = &pmb->u.mb;
 
        lpfc_read_sparam(phba, pmb, vport->vpi);
        /*
@@ -243,23 +251,22 @@ static void lpfc_discovery_wait(struct lpfc_vport *vport)
                    (vport->fc_flag & wait_flags)  ||
                    ((vport->port_state > LPFC_VPORT_FAILED) &&
                     (vport->port_state < LPFC_VPORT_READY))) {
-                       lpfc_printf_log(phba, KERN_INFO, LOG_VPORT,
+                       lpfc_printf_vlog(vport, KERN_INFO, LOG_VPORT,
                                        "1833 Vport discovery quiesce Wait:"
-                                       " vpi x%x state x%x fc_flags x%x"
+                                       " state x%x fc_flags x%x"
                                        " num_nodes x%x, waiting 1000 msecs"
                                        " total wait msecs x%x\n",
-                                       vport->vpi, vport->port_state,
-                                       vport->fc_flag, vport->num_disc_nodes,
+                                       vport->port_state, vport->fc_flag,
+                                       vport->num_disc_nodes,
                                        jiffies_to_msecs(jiffies - start_time));
                        msleep(1000);
                } else {
                        /* Base case.  Wait variants satisfied.  Break out */
-                       lpfc_printf_log(phba, KERN_INFO, LOG_VPORT,
+                       lpfc_printf_vlog(vport, KERN_INFO, LOG_VPORT,
                                         "1834 Vport discovery quiesced:"
-                                        " vpi x%x state x%x fc_flags x%x"
+                                        " state x%x fc_flags x%x"
                                         " wait msecs x%x\n",
-                                        vport->vpi, vport->port_state,
-                                        vport->fc_flag,
+                                        vport->port_state, vport->fc_flag,
                                         jiffies_to_msecs(jiffies
                                                - start_time));
                        break;
@@ -267,12 +274,10 @@ static void lpfc_discovery_wait(struct lpfc_vport *vport)
        }
 
        if (time_after(jiffies, wait_time_max))
-               lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
                                "1835 Vport discovery quiesce failed:"
-                               " vpi x%x state x%x fc_flags x%x"
-                               " wait msecs x%x\n",
-                               vport->vpi, vport->port_state,
-                               vport->fc_flag,
+                               " state x%x fc_flags x%x wait msecs x%x\n",
+                               vport->port_state, vport->fc_flag,
                                jiffies_to_msecs(jiffies - start_time));
 }
 
@@ -308,6 +313,21 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
                goto error_out;
        }
 
+       /*
+        * In SLI4, the vpi must be activated before it can be used
+        * by the port.
+        */
+       if (phba->sli_rev == LPFC_SLI_REV4) {
+               rc = lpfc_sli4_init_vpi(phba, vpi);
+               if (rc) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+                                       "1838 Failed to INIT_VPI on vpi %d "
+                                       "status %d\n", vpi, rc);
+                       rc = VPORT_NORESOURCES;
+                       lpfc_free_vpi(phba, vpi);
+                       goto error_out;
+               }
+       }
 
        /* Assign an unused board number */
        if ((instance = lpfc_get_instance()) < 0) {
@@ -535,6 +555,16 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
                                 "physical host\n");
                return VPORT_ERROR;
        }
+
+       /* If the vport is a static vport fail the deletion. */
+       if ((vport->vport_flag & STATIC_VPORT) &&
+               !(phba->pport->load_flag & FC_UNLOADING)) {
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
+                                "1837 vport_delete failed: Cannot delete "
+                                "static vport.\n");
+               return VPORT_ERROR;
+       }
+
        /*
         * If we are not unloading the driver then prevent the vport_delete
         * from happening until after this vport's discovery is finished.
@@ -710,7 +740,7 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba)
        struct lpfc_vport *port_iterator;
        struct lpfc_vport **vports;
        int index = 0;
-       vports = kzalloc((phba->max_vpi + 1) * sizeof(struct lpfc_vport *),
+       vports = kzalloc((phba->max_vports + 1) * sizeof(struct lpfc_vport *),
                         GFP_KERNEL);
        if (vports == NULL)
                return NULL;
@@ -734,7 +764,7 @@ lpfc_destroy_vport_work_array(struct lpfc_hba *phba, struct lpfc_vport **vports)
        int i;
        if (vports == NULL)
                return;
-       for (i=0; vports[i] != NULL && i <= phba->max_vpi; i++)
+       for (i = 0; vports[i] != NULL && i <= phba->max_vports; i++)
                scsi_host_put(lpfc_shost_from_vport(vports[i]));
        kfree(vports);
 }
index 795201fa0b487d1a23113f38534666d90d23ec49..512c2cc1a33f5a9e8d1e30edfa41ed5212ecfec4 100644 (file)
@@ -469,7 +469,7 @@ typedef struct {
        u8      type;           /* Type of the device */
        u8      cur_status;     /* current status of the device */
        u8      tag_depth;      /* Level of tagging */
-       u8      sync_neg;       /* sync negotiation - ENABLE or DISBALE */
+       u8      sync_neg;       /* sync negotiation - ENABLE or DISABLE */
        u32     size;           /* configurable size in terms of 512 byte
                                   blocks */
 }__attribute__ ((packed)) phys_drv;
index 170399ef06f4ac3e7bcd5de6e343765588c6e419..b25b74764ec3305ec036bc2930cad04e87fcf3f6 100644 (file)
@@ -686,7 +686,7 @@ typedef struct {
  * @type       : Type of the device
  * @cur_status : current status of the device
  * @tag_depth  : Level of tagging
- * @sync_neg   : sync negotiation - ENABLE or DISBALE
+ * @sync_neg   : sync negotiation - ENABLE or DISABLE
  * @size       : configurable size in terms of 512 byte
  */
 typedef struct {
index 36b1d1052ba1281eb6e33d8fe154d7fce87aacf1..286c185fa9e40a5b7347de0dc99b06c4d2f0e617 100644 (file)
@@ -61,6 +61,7 @@
 #include <scsi/scsi_tcq.h>
 #include <scsi/scsi_transport_sas.h>
 #include <scsi/scsi_dbg.h>
+#include <scsi/scsi_eh.h>
 
 #include "mpt2sas_debug.h"
 
 #define MPT2SAS_DRIVER_NAME            "mpt2sas"
 #define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>"
 #define MPT2SAS_DESCRIPTION    "LSI MPT Fusion SAS 2.0 Device Driver"
-#define MPT2SAS_DRIVER_VERSION         "01.100.02.00"
+#define MPT2SAS_DRIVER_VERSION         "01.100.03.00"
 #define MPT2SAS_MAJOR_VERSION          01
 #define MPT2SAS_MINOR_VERSION          100
-#define MPT2SAS_BUILD_VERSION          02
+#define MPT2SAS_BUILD_VERSION          03
 #define MPT2SAS_RELEASE_VERSION                00
 
 /*
index ba6ab170bdf02ca5fc75e2b8a6b22bce943b23c1..14e473d1fa7b18193e0673d86dec3bfc8737aa84 100644 (file)
@@ -473,7 +473,7 @@ _ctl_poll(struct file *filep, poll_table *wait)
 }
 
 /**
- * _ctl_do_task_abort - assign an active smid to the abort_task
+ * _ctl_set_task_mid - assign an active smid to tm request
  * @ioc: per adapter object
  * @karg - (struct mpt2_ioctl_command)
  * @tm_request - pointer to mf from user space
@@ -482,7 +482,7 @@ _ctl_poll(struct file *filep, poll_table *wait)
  * during failure, the reply frame is filled.
  */
 static int
-_ctl_do_task_abort(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,
+_ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,
     Mpi2SCSITaskManagementRequest_t *tm_request)
 {
        u8 found = 0;
@@ -494,6 +494,14 @@ _ctl_do_task_abort(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,
        Mpi2SCSITaskManagementReply_t *tm_reply;
        u32 sz;
        u32 lun;
+       char *desc = NULL;
+
+       if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
+               desc = "abort_task";
+       else if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK)
+               desc = "query_task";
+       else
+               return 0;
 
        lun = scsilun_to_int((struct scsi_lun *)tm_request->LUN);
 
@@ -517,13 +525,13 @@ _ctl_do_task_abort(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,
        spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
 
        if (!found) {
-               dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ABORT_TASK: "
-                   "DevHandle(0x%04x), lun(%d), no active mid!!\n", ioc->name,
-                   tm_request->DevHandle, lun));
+               dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+                   "handle(0x%04x), lun(%d), no active mid!!\n", ioc->name,
+                   desc, tm_request->DevHandle, lun));
                tm_reply = ioc->ctl_cmds.reply;
                tm_reply->DevHandle = tm_request->DevHandle;
                tm_reply->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
-               tm_reply->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
+               tm_reply->TaskType = tm_request->TaskType;
                tm_reply->MsgLength = sizeof(Mpi2SCSITaskManagementReply_t)/4;
                tm_reply->VP_ID = tm_request->VP_ID;
                tm_reply->VF_ID = tm_request->VF_ID;
@@ -535,9 +543,9 @@ _ctl_do_task_abort(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,
                return 1;
        }
 
-       dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ABORT_TASK: "
-           "DevHandle(0x%04x), lun(%d), smid(%d)\n", ioc->name,
-           tm_request->DevHandle, lun, tm_request->TaskMID));
+       dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+           "handle(0x%04x), lun(%d), task_mid(%d)\n", ioc->name,
+           desc, tm_request->DevHandle, lun, tm_request->TaskMID));
        return 0;
 }
 
@@ -739,8 +747,10 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
                    (Mpi2SCSITaskManagementRequest_t *)mpi_request;
 
                if (tm_request->TaskType ==
-                   MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
-                       if (_ctl_do_task_abort(ioc, &karg, tm_request)) {
+                   MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK ||
+                   tm_request->TaskType ==
+                   MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK) {
+                       if (_ctl_set_task_mid(ioc, &karg, tm_request)) {
                                mpt2sas_base_free_smid(ioc, smid);
                                goto out;
                        }
index e3a7967259e75fe5cfac5f5101a4e8f2912992f6..2a01a5f2a84dddc4d105d5ef88030abe1adc21ab 100644 (file)
@@ -197,12 +197,12 @@ static struct pci_device_id scsih_pci_table[] = {
 MODULE_DEVICE_TABLE(pci, scsih_pci_table);
 
 /**
- * scsih_set_debug_level - global setting of ioc->logging_level.
+ * _scsih_set_debug_level - global setting of ioc->logging_level.
  *
  * Note: The logging levels are defined in mpt2sas_debug.h.
  */
 static int
-scsih_set_debug_level(const char *val, struct kernel_param *kp)
+_scsih_set_debug_level(const char *val, struct kernel_param *kp)
 {
        int ret = param_set_int(val, kp);
        struct MPT2SAS_ADAPTER *ioc;
@@ -215,7 +215,7 @@ scsih_set_debug_level(const char *val, struct kernel_param *kp)
                ioc->logging_level = logging_level;
        return 0;
 }
-module_param_call(logging_level, scsih_set_debug_level, param_get_int,
+module_param_call(logging_level, _scsih_set_debug_level, param_get_int,
     &logging_level, 0644);
 
 /**
@@ -883,6 +883,41 @@ _scsih_scsi_lookup_find_by_target(struct MPT2SAS_ADAPTER *ioc, int id,
        return found;
 }
 
+/**
+ * _scsih_scsi_lookup_find_by_lun - search for matching channel:id:lun
+ * @ioc: per adapter object
+ * @id: target id
+ * @lun: lun number
+ * @channel: channel
+ * Context: This function will acquire ioc->scsi_lookup_lock.
+ *
+ * This will search for a matching channel:id:lun in the scsi_lookup array,
+ * returning 1 if found.
+ */
+static u8
+_scsih_scsi_lookup_find_by_lun(struct MPT2SAS_ADAPTER *ioc, int id,
+    unsigned int lun, int channel)
+{
+       u8 found;
+       unsigned long   flags;
+       int i;
+
+       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+       found = 0;
+       for (i = 0 ; i < ioc->request_depth; i++) {
+               if (ioc->scsi_lookup[i].scmd &&
+                   (ioc->scsi_lookup[i].scmd->device->id == id &&
+                   ioc->scsi_lookup[i].scmd->device->channel == channel &&
+                   ioc->scsi_lookup[i].scmd->device->lun == lun)) {
+                       found = 1;
+                       goto out;
+               }
+       }
+ out:
+       spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+       return found;
+}
+
 /**
  * _scsih_get_chain_buffer_dma - obtain block of chains (dma address)
  * @ioc: per adapter object
@@ -1047,14 +1082,14 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,
 }
 
 /**
- * scsih_change_queue_depth - setting device queue depth
+ * _scsih_change_queue_depth - setting device queue depth
  * @sdev: scsi device struct
  * @qdepth: requested queue depth
  *
  * Returns queue depth.
  */
 static int
-scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
+_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
 {
        struct Scsi_Host *shost = sdev->host;
        int max_depth;
@@ -1079,14 +1114,14 @@ scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
 }
 
 /**
- * scsih_change_queue_depth - changing device queue tag type
+ * _scsih_change_queue_depth - changing device queue tag type
  * @sdev: scsi device struct
  * @tag_type: requested tag type
  *
  * Returns queue tag type.
  */
 static int
-scsih_change_queue_type(struct scsi_device *sdev, int tag_type)
+_scsih_change_queue_type(struct scsi_device *sdev, int tag_type)
 {
        if (sdev->tagged_supported) {
                scsi_set_tag_type(sdev, tag_type);
@@ -1101,14 +1136,14 @@ scsih_change_queue_type(struct scsi_device *sdev, int tag_type)
 }
 
 /**
- * scsih_target_alloc - target add routine
+ * _scsih_target_alloc - target add routine
  * @starget: scsi target struct
  *
  * Returns 0 if ok. Any other return is assumed to be an error and
  * the device is ignored.
  */
 static int
-scsih_target_alloc(struct scsi_target *starget)
+_scsih_target_alloc(struct scsi_target *starget)
 {
        struct Scsi_Host *shost = dev_to_shost(&starget->dev);
        struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
@@ -1163,13 +1198,13 @@ scsih_target_alloc(struct scsi_target *starget)
 }
 
 /**
- * scsih_target_destroy - target destroy routine
+ * _scsih_target_destroy - target destroy routine
  * @starget: scsi target struct
  *
  * Returns nothing.
  */
 static void
-scsih_target_destroy(struct scsi_target *starget)
+_scsih_target_destroy(struct scsi_target *starget)
 {
        struct Scsi_Host *shost = dev_to_shost(&starget->dev);
        struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
@@ -1212,14 +1247,14 @@ scsih_target_destroy(struct scsi_target *starget)
 }
 
 /**
- * scsih_slave_alloc - device add routine
+ * _scsih_slave_alloc - device add routine
  * @sdev: scsi device struct
  *
  * Returns 0 if ok. Any other return is assumed to be an error and
  * the device is ignored.
  */
 static int
-scsih_slave_alloc(struct scsi_device *sdev)
+_scsih_slave_alloc(struct scsi_device *sdev)
 {
        struct Scsi_Host *shost;
        struct MPT2SAS_ADAPTER *ioc;
@@ -1273,13 +1308,13 @@ scsih_slave_alloc(struct scsi_device *sdev)
 }
 
 /**
- * scsih_slave_destroy - device destroy routine
+ * _scsih_slave_destroy - device destroy routine
  * @sdev: scsi device struct
  *
  * Returns nothing.
  */
 static void
-scsih_slave_destroy(struct scsi_device *sdev)
+_scsih_slave_destroy(struct scsi_device *sdev)
 {
        struct MPT2SAS_TARGET *sas_target_priv_data;
        struct scsi_target *starget;
@@ -1295,13 +1330,13 @@ scsih_slave_destroy(struct scsi_device *sdev)
 }
 
 /**
- * scsih_display_sata_capabilities - sata capabilities
+ * _scsih_display_sata_capabilities - sata capabilities
  * @ioc: per adapter object
  * @sas_device: the sas_device object
  * @sdev: scsi device struct
  */
 static void
-scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,
+_scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,
     struct _sas_device *sas_device, struct scsi_device *sdev)
 {
        Mpi2ConfigReply_t mpi_reply;
@@ -1401,14 +1436,14 @@ _scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc,
 }
 
 /**
- * scsih_slave_configure - device configure routine.
+ * _scsih_slave_configure - device configure routine.
  * @sdev: scsi device struct
  *
  * Returns 0 if ok. Any other return is assumed to be an error and
  * the device is ignored.
  */
 static int
-scsih_slave_configure(struct scsi_device *sdev)
+_scsih_slave_configure(struct scsi_device *sdev)
 {
        struct Scsi_Host *shost = sdev->host;
        struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
@@ -1489,7 +1524,7 @@ scsih_slave_configure(struct scsi_device *sdev)
                    r_level, raid_device->handle,
                    (unsigned long long)raid_device->wwid,
                    raid_device->num_pds, ds);
-               scsih_change_queue_depth(sdev, qdepth);
+               _scsih_change_queue_depth(sdev, qdepth);
                return 0;
        }
 
@@ -1532,10 +1567,10 @@ scsih_slave_configure(struct scsi_device *sdev)
                    sas_device->slot);
 
                if (!ssp_target)
-                       scsih_display_sata_capabilities(ioc, sas_device, sdev);
+                       _scsih_display_sata_capabilities(ioc, sas_device, sdev);
        }
 
-       scsih_change_queue_depth(sdev, qdepth);
+       _scsih_change_queue_depth(sdev, qdepth);
 
        if (ssp_target)
                sas_read_port_mode_page(sdev);
@@ -1543,7 +1578,7 @@ scsih_slave_configure(struct scsi_device *sdev)
 }
 
 /**
- * scsih_bios_param - fetch head, sector, cylinder info for a disk
+ * _scsih_bios_param - fetch head, sector, cylinder info for a disk
  * @sdev: scsi device struct
  * @bdev: pointer to block device context
  * @capacity: device size (in 512 byte sectors)
@@ -1555,7 +1590,7 @@ scsih_slave_configure(struct scsi_device *sdev)
  * Return nothing.
  */
 static int
-scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev,
+_scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev,
     sector_t capacity, int params[])
 {
        int             heads;
@@ -1636,7 +1671,7 @@ _scsih_response_code(struct MPT2SAS_ADAPTER *ioc, u8 response_code)
 }
 
 /**
- * scsih_tm_done - tm completion routine
+ * _scsih_tm_done - tm completion routine
  * @ioc: per adapter object
  * @smid: system request message index
  * @VF_ID: virtual function id
@@ -1648,7 +1683,7 @@ _scsih_response_code(struct MPT2SAS_ADAPTER *ioc, u8 response_code)
  * Return nothing.
  */
 static void
-scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
+_scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
 {
        MPI2DefaultReply_t *mpi_reply;
 
@@ -1823,13 +1858,13 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
 }
 
 /**
- * scsih_abort - eh threads main abort routine
+ * _scsih_abort - eh threads main abort routine
  * @sdev: scsi device struct
  *
  * Returns SUCCESS if command aborted else FAILED
  */
 static int
-scsih_abort(struct scsi_cmnd *scmd)
+_scsih_abort(struct scsi_cmnd *scmd)
 {
        struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
        struct MPT2SAS_DEVICE *sas_device_priv_data;
@@ -1889,15 +1924,86 @@ scsih_abort(struct scsi_cmnd *scmd)
        return r;
 }
 
+/**
+ * _scsih_dev_reset - eh threads main device reset routine
+ * @sdev: scsi device struct
+ *
+ * Returns SUCCESS if command aborted else FAILED
+ */
+static int
+_scsih_dev_reset(struct scsi_cmnd *scmd)
+{
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
+       struct MPT2SAS_DEVICE *sas_device_priv_data;
+       struct _sas_device *sas_device;
+       unsigned long flags;
+       u16     handle;
+       int r;
+
+       printk(MPT2SAS_INFO_FMT "attempting device reset! scmd(%p)\n",
+           ioc->name, scmd);
+       scsi_print_command(scmd);
+
+       sas_device_priv_data = scmd->device->hostdata;
+       if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
+               printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
+                   ioc->name, scmd);
+               scmd->result = DID_NO_CONNECT << 16;
+               scmd->scsi_done(scmd);
+               r = SUCCESS;
+               goto out;
+       }
+
+       /* for hidden raid components obtain the volume_handle */
+       handle = 0;
+       if (sas_device_priv_data->sas_target->flags &
+           MPT_TARGET_FLAGS_RAID_COMPONENT) {
+               spin_lock_irqsave(&ioc->sas_device_lock, flags);
+               sas_device = _scsih_sas_device_find_by_handle(ioc,
+                  sas_device_priv_data->sas_target->handle);
+               if (sas_device)
+                       handle = sas_device->volume_handle;
+               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+       } else
+               handle = sas_device_priv_data->sas_target->handle;
+
+       if (!handle) {
+               scmd->result = DID_RESET << 16;
+               r = FAILED;
+               goto out;
+       }
+
+       mutex_lock(&ioc->tm_cmds.mutex);
+       mpt2sas_scsih_issue_tm(ioc, handle, 0,
+           MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, scmd->device->lun,
+           30);
+
+       /*
+        *  sanity check see whether all commands to this device been
+        *  completed
+        */
+       if (_scsih_scsi_lookup_find_by_lun(ioc, scmd->device->id,
+           scmd->device->lun, scmd->device->channel))
+               r = FAILED;
+       else
+               r = SUCCESS;
+       ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
+       mutex_unlock(&ioc->tm_cmds.mutex);
+
+ out:
+       printk(MPT2SAS_INFO_FMT "device reset: %s scmd(%p)\n",
+           ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+       return r;
+}
 
 /**
- * scsih_dev_reset - eh threads main device reset routine
+ * _scsih_target_reset - eh threads main target reset routine
  * @sdev: scsi device struct
  *
  * Returns SUCCESS if command aborted else FAILED
  */
 static int
-scsih_dev_reset(struct scsi_cmnd *scmd)
+_scsih_target_reset(struct scsi_cmnd *scmd)
 {
        struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
        struct MPT2SAS_DEVICE *sas_device_priv_data;
@@ -1912,7 +2018,7 @@ scsih_dev_reset(struct scsi_cmnd *scmd)
 
        sas_device_priv_data = scmd->device->hostdata;
        if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
-               printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
+               printk(MPT2SAS_INFO_FMT "target been deleted! scmd(%p)\n",
                    ioc->name, scmd);
                scmd->result = DID_NO_CONNECT << 16;
                scmd->scsi_done(scmd);
@@ -1962,13 +2068,13 @@ scsih_dev_reset(struct scsi_cmnd *scmd)
 }
 
 /**
- * scsih_abort - eh threads main host reset routine
+ * _scsih_abort - eh threads main host reset routine
  * @sdev: scsi device struct
  *
  * Returns SUCCESS if command aborted else FAILED
  */
 static int
-scsih_host_reset(struct scsi_cmnd *scmd)
+_scsih_host_reset(struct scsi_cmnd *scmd)
 {
        struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
        int r, retval;
@@ -2390,7 +2496,107 @@ mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
 }
 
 /**
- * scsih_qcmd - main scsi request entry point
+ * _scsih_setup_eedp - setup MPI request for EEDP transfer
+ * @scmd: pointer to scsi command object
+ * @mpi_request: pointer to the SCSI_IO reqest message frame
+ *
+ * Supporting protection 1 and 3.
+ *
+ * Returns nothing
+ */
+static void
+_scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
+{
+       u16 eedp_flags;
+       unsigned char prot_op = scsi_get_prot_op(scmd);
+       unsigned char prot_type = scsi_get_prot_type(scmd);
+
+       if (prot_type == SCSI_PROT_DIF_TYPE0 ||
+          prot_type == SCSI_PROT_DIF_TYPE2 ||
+          prot_op == SCSI_PROT_NORMAL)
+               return;
+
+       if (prot_op ==  SCSI_PROT_READ_STRIP)
+               eedp_flags = MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP;
+       else if (prot_op ==  SCSI_PROT_WRITE_INSERT)
+               eedp_flags = MPI2_SCSIIO_EEDPFLAGS_INSERT_OP;
+       else
+               return;
+
+       mpi_request->EEDPBlockSize = scmd->device->sector_size;
+
+       switch (prot_type) {
+       case SCSI_PROT_DIF_TYPE1:
+
+               /*
+               * enable ref/guard checking
+               * auto increment ref tag
+               */
+               mpi_request->EEDPFlags = eedp_flags |
+                   MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
+                   MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
+                   MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
+               mpi_request->CDB.EEDP32.PrimaryReferenceTag =
+                   cpu_to_be32(scsi_get_lba(scmd));
+
+               break;
+
+       case SCSI_PROT_DIF_TYPE3:
+
+               /*
+               * enable guard checking
+               */
+               mpi_request->EEDPFlags = eedp_flags |
+                   MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
+
+               break;
+       }
+}
+
+/**
+ * _scsih_eedp_error_handling - return sense code for EEDP errors
+ * @scmd: pointer to scsi command object
+ * @ioc_status: ioc status
+ *
+ * Returns nothing
+ */
+static void
+_scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
+{
+       u8 ascq;
+       u8 sk;
+       u8 host_byte;
+
+       switch (ioc_status) {
+       case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
+               ascq = 0x01;
+               break;
+       case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
+               ascq = 0x02;
+               break;
+       case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
+               ascq = 0x03;
+               break;
+       default:
+               ascq = 0x00;
+               break;
+       }
+
+       if (scmd->sc_data_direction == DMA_TO_DEVICE) {
+               sk = ILLEGAL_REQUEST;
+               host_byte = DID_ABORT;
+       } else {
+               sk = ABORTED_COMMAND;
+               host_byte = DID_OK;
+       }
+
+       scsi_build_sense_buffer(0, scmd->sense_buffer, sk, 0x10, ascq);
+       scmd->result = DRIVER_SENSE << 24 | (host_byte << 16) |
+           SAM_STAT_CHECK_CONDITION;
+}
+
+/**
+ * _scsih_qcmd - main scsi request entry point
  * @scmd: pointer to scsi command object
  * @done: function pointer to be invoked on completion
  *
@@ -2401,7 +2607,7 @@ mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
  * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full
  */
 static int
-scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
+_scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
 {
        struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
        struct MPT2SAS_DEVICE *sas_device_priv_data;
@@ -2470,6 +2676,7 @@ scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
        }
        mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
        memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t));
+       _scsih_setup_eedp(scmd, mpi_request);
        mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
        if (sas_device_priv_data->sas_target->flags &
            MPT_TARGET_FLAGS_RAID_COMPONENT)
@@ -2604,6 +2811,15 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
        case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
                desc_ioc_state = "scsi ext terminated";
                break;
+       case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
+               desc_ioc_state = "eedp guard error";
+               break;
+       case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
+               desc_ioc_state = "eedp ref tag error";
+               break;
+       case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
+               desc_ioc_state = "eedp app tag error";
+               break;
        default:
                desc_ioc_state = "unknown";
                break;
@@ -2783,7 +2999,7 @@ _scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)
 }
 
 /**
- * scsih_io_done - scsi request callback
+ * _scsih_io_done - scsi request callback
  * @ioc: per adapter object
  * @smid: system request message index
  * @VF_ID: virtual function id
@@ -2794,7 +3010,7 @@ _scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)
  * Return nothing.
  */
 static void
-scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
+_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
 {
        Mpi2SCSIIORequest_t *mpi_request;
        Mpi2SCSIIOReply_t *mpi_reply;
@@ -2939,6 +3155,11 @@ scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
                        scmd->result = DID_RESET << 16;
                break;
 
+       case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
+       case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
+       case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
+               _scsih_eedp_error_handling(scmd, ioc_status);
+               break;
        case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
        case MPI2_IOCSTATUS_INVALID_FUNCTION:
        case MPI2_IOCSTATUS_INVALID_SGL:
@@ -5130,18 +5351,19 @@ static struct scsi_host_template scsih_driver_template = {
        .module                         = THIS_MODULE,
        .name                           = "Fusion MPT SAS Host",
        .proc_name                      = MPT2SAS_DRIVER_NAME,
-       .queuecommand                   = scsih_qcmd,
-       .target_alloc                   = scsih_target_alloc,
-       .slave_alloc                    = scsih_slave_alloc,
-       .slave_configure                = scsih_slave_configure,
-       .target_destroy                 = scsih_target_destroy,
-       .slave_destroy                  = scsih_slave_destroy,
-       .change_queue_depth             = scsih_change_queue_depth,
-       .change_queue_type              = scsih_change_queue_type,
-       .eh_abort_handler               = scsih_abort,
-       .eh_device_reset_handler        = scsih_dev_reset,
-       .eh_host_reset_handler          = scsih_host_reset,
-       .bios_param                     = scsih_bios_param,
+       .queuecommand                   = _scsih_qcmd,
+       .target_alloc                   = _scsih_target_alloc,
+       .slave_alloc                    = _scsih_slave_alloc,
+       .slave_configure                = _scsih_slave_configure,
+       .target_destroy                 = _scsih_target_destroy,
+       .slave_destroy                  = _scsih_slave_destroy,
+       .change_queue_depth             = _scsih_change_queue_depth,
+       .change_queue_type              = _scsih_change_queue_type,
+       .eh_abort_handler               = _scsih_abort,
+       .eh_device_reset_handler        = _scsih_dev_reset,
+       .eh_target_reset_handler        = _scsih_target_reset,
+       .eh_host_reset_handler          = _scsih_host_reset,
+       .bios_param                     = _scsih_bios_param,
        .can_queue                      = 1,
        .this_id                        = -1,
        .sg_tablesize                   = MPT2SAS_SG_DEPTH,
@@ -5228,13 +5450,13 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
 }
 
 /**
- * scsih_remove - detach and remove add host
+ * _scsih_remove - detach and remove add host
  * @pdev: PCI device struct
  *
  * Return nothing.
  */
 static void __devexit
-scsih_remove(struct pci_dev *pdev)
+_scsih_remove(struct pci_dev *pdev)
 {
        struct Scsi_Host *shost = pci_get_drvdata(pdev);
        struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
@@ -5442,14 +5664,14 @@ _scsih_probe_devices(struct MPT2SAS_ADAPTER *ioc)
 }
 
 /**
- * scsih_probe - attach and add scsi host
+ * _scsih_probe - attach and add scsi host
  * @pdev: PCI device struct
  * @id: pci device id
  *
  * Returns 0 success, anything else error.
  */
 static int
-scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+_scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct MPT2SAS_ADAPTER *ioc;
        struct Scsi_Host *shost;
@@ -5503,6 +5725,9 @@ scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                goto out_add_shost_fail;
        }
 
+       scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION
+           | SHOST_DIF_TYPE3_PROTECTION);
+
        /* event thread */
        snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name),
            "fw_event%d", ioc->id);
@@ -5536,14 +5761,14 @@ scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
 #ifdef CONFIG_PM
 /**
- * scsih_suspend - power management suspend main entry point
+ * _scsih_suspend - power management suspend main entry point
  * @pdev: PCI device struct
  * @state: PM state change to (usually PCI_D3)
  *
  * Returns 0 success, anything else error.
  */
 static int
-scsih_suspend(struct pci_dev *pdev, pm_message_t state)
+_scsih_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct Scsi_Host *shost = pci_get_drvdata(pdev);
        struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
@@ -5564,13 +5789,13 @@ scsih_suspend(struct pci_dev *pdev, pm_message_t state)
 }
 
 /**
- * scsih_resume - power management resume main entry point
+ * _scsih_resume - power management resume main entry point
  * @pdev: PCI device struct
  *
  * Returns 0 success, anything else error.
  */
 static int
-scsih_resume(struct pci_dev *pdev)
+_scsih_resume(struct pci_dev *pdev)
 {
        struct Scsi_Host *shost = pci_get_drvdata(pdev);
        struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
@@ -5599,22 +5824,22 @@ scsih_resume(struct pci_dev *pdev)
 static struct pci_driver scsih_driver = {
        .name           = MPT2SAS_DRIVER_NAME,
        .id_table       = scsih_pci_table,
-       .probe          = scsih_probe,
-       .remove         = __devexit_p(scsih_remove),
+       .probe          = _scsih_probe,
+       .remove         = __devexit_p(_scsih_remove),
 #ifdef CONFIG_PM
-       .suspend        = scsih_suspend,
-       .resume         = scsih_resume,
+       .suspend        = _scsih_suspend,
+       .resume         = _scsih_resume,
 #endif
 };
 
 
 /**
- * scsih_init - main entry point for this driver.
+ * _scsih_init - main entry point for this driver.
  *
  * Returns 0 success, anything else error.
  */
 static int __init
-scsih_init(void)
+_scsih_init(void)
 {
        int error;
 
@@ -5630,10 +5855,10 @@ scsih_init(void)
        mpt2sas_base_initialize_callback_handler();
 
         /* queuecommand callback hander */
-       scsi_io_cb_idx = mpt2sas_base_register_callback_handler(scsih_io_done);
+       scsi_io_cb_idx = mpt2sas_base_register_callback_handler(_scsih_io_done);
 
        /* task managment callback handler */
-       tm_cb_idx = mpt2sas_base_register_callback_handler(scsih_tm_done);
+       tm_cb_idx = mpt2sas_base_register_callback_handler(_scsih_tm_done);
 
        /* base internal commands callback handler */
        base_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_base_done);
@@ -5659,12 +5884,12 @@ scsih_init(void)
 }
 
 /**
- * scsih_exit - exit point for this driver (when it is a module).
+ * _scsih_exit - exit point for this driver (when it is a module).
  *
  * Returns 0 success, anything else error.
  */
 static void __exit
-scsih_exit(void)
+_scsih_exit(void)
 {
        printk(KERN_INFO "mpt2sas version %s unloading\n",
            MPT2SAS_DRIVER_VERSION);
@@ -5682,5 +5907,5 @@ scsih_exit(void)
        mpt2sas_ctl_exit();
 }
 
-module_init(scsih_init);
-module_exit(scsih_exit);
+module_init(_scsih_init);
+module_exit(_scsih_exit);
index 5c65da519e39af511334816c18977912a4920637..686695b155c7af9899864c5d3103e3cfd49624b8 100644 (file)
@@ -264,7 +264,7 @@ struct rep_manu_reply{
 };
 
 /**
- * transport_expander_report_manufacture - obtain SMP report_manufacture
+ * _transport_expander_report_manufacture - obtain SMP report_manufacture
  * @ioc: per adapter object
  * @sas_address: expander sas address
  * @edev: the sas_expander_device object
@@ -274,7 +274,7 @@ struct rep_manu_reply{
  * Returns 0 for success, non-zero for failure.
  */
 static int
-transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
+_transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
     u64 sas_address, struct sas_expander_device *edev)
 {
        Mpi2SmpPassthroughRequest_t *mpi_request;
@@ -578,7 +578,7 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,
            MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
            mpt2sas_port->remote_identify.device_type ==
            MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER)
-               transport_expander_report_manufacture(ioc,
+               _transport_expander_report_manufacture(ioc,
                    mpt2sas_port->remote_identify.sas_address,
                    rphy_to_expander_device(rphy));
 
@@ -852,7 +852,7 @@ rphy_to_ioc(struct sas_rphy *rphy)
 }
 
 /**
- * transport_get_linkerrors -
+ * _transport_get_linkerrors -
  * @phy: The sas phy object
  *
  * Only support sas_host direct attached phys.
@@ -860,7 +860,7 @@ rphy_to_ioc(struct sas_rphy *rphy)
  *
  */
 static int
-transport_get_linkerrors(struct sas_phy *phy)
+_transport_get_linkerrors(struct sas_phy *phy)
 {
        struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
        struct _sas_phy *mpt2sas_phy;
@@ -903,14 +903,14 @@ transport_get_linkerrors(struct sas_phy *phy)
 }
 
 /**
- * transport_get_enclosure_identifier -
+ * _transport_get_enclosure_identifier -
  * @phy: The sas phy object
  *
  * Obtain the enclosure logical id for an expander.
  * Returns 0 for success, non-zero for failure.
  */
 static int
-transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
+_transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
 {
        struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
        struct _sas_node *sas_expander;
@@ -929,13 +929,13 @@ transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
 }
 
 /**
- * transport_get_bay_identifier -
+ * _transport_get_bay_identifier -
  * @phy: The sas phy object
  *
  * Returns the slot id for a device that resides inside an enclosure.
  */
 static int
-transport_get_bay_identifier(struct sas_rphy *rphy)
+_transport_get_bay_identifier(struct sas_rphy *rphy)
 {
        struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
        struct _sas_device *sas_device;
@@ -953,7 +953,7 @@ transport_get_bay_identifier(struct sas_rphy *rphy)
 }
 
 /**
- * transport_phy_reset -
+ * _transport_phy_reset -
  * @phy: The sas phy object
  * @hard_reset:
  *
@@ -961,7 +961,7 @@ transport_get_bay_identifier(struct sas_rphy *rphy)
  * Returns 0 for success, non-zero for failure.
  */
 static int
-transport_phy_reset(struct sas_phy *phy, int hard_reset)
+_transport_phy_reset(struct sas_phy *phy, int hard_reset)
 {
        struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
        struct _sas_phy *mpt2sas_phy;
@@ -1002,7 +1002,7 @@ transport_phy_reset(struct sas_phy *phy, int hard_reset)
 }
 
 /**
- * transport_smp_handler - transport portal for smp passthru
+ * _transport_smp_handler - transport portal for smp passthru
  * @shost: shost object
  * @rphy: sas transport rphy object
  * @req:
@@ -1012,7 +1012,7 @@ transport_phy_reset(struct sas_phy *phy, int hard_reset)
  *           smp_rep_general /sys/class/bsg/expander-5:0
  */
 static int
-transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
+_transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
     struct request *req)
 {
        struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
@@ -1200,11 +1200,11 @@ transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
 }
 
 struct sas_function_template mpt2sas_transport_functions = {
-       .get_linkerrors         = transport_get_linkerrors,
-       .get_enclosure_identifier = transport_get_enclosure_identifier,
-       .get_bay_identifier     = transport_get_bay_identifier,
-       .phy_reset              = transport_phy_reset,
-       .smp_handler            = transport_smp_handler,
+       .get_linkerrors         = _transport_get_linkerrors,
+       .get_enclosure_identifier = _transport_get_enclosure_identifier,
+       .get_bay_identifier     = _transport_get_bay_identifier,
+       .phy_reset              = _transport_phy_reset,
+       .smp_handler            = _transport_smp_handler,
 };
 
 struct scsi_transport_template *mpt2sas_transport_template;
diff --git a/drivers/scsi/mvsas.c b/drivers/scsi/mvsas.c
deleted file mode 100644 (file)
index e4acebd..0000000
+++ /dev/null
@@ -1,3222 +0,0 @@
-/*
-       mvsas.c - Marvell 88SE6440 SAS/SATA support
-
-       Copyright 2007 Red Hat, Inc.
-       Copyright 2008 Marvell. <kewei@marvell.com>
-
-       This program is free software; you can redistribute it and/or
-       modify it under the terms of the GNU General Public License as
-       published by the Free Software Foundation; either version 2,
-       or (at your option) any later version.
-
-       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; see the file COPYING.  If not,
-       write to the Free Software Foundation, 675 Mass Ave, Cambridge,
-       MA 02139, USA.
-
-       ---------------------------------------------------------------
-
-       Random notes:
-       * hardware supports controlling the endian-ness of data
-         structures.  this permits elimination of all the le32_to_cpu()
-         and cpu_to_le32() conversions.
-
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-#include <linux/ctype.h>
-#include <scsi/libsas.h>
-#include <scsi/scsi_tcq.h>
-#include <scsi/sas_ata.h>
-#include <asm/io.h>
-
-#define DRV_NAME       "mvsas"
-#define DRV_VERSION    "0.5.2"
-#define _MV_DUMP       0
-#define MVS_DISABLE_NVRAM
-#define MVS_DISABLE_MSI
-
-#define mr32(reg)      readl(regs + MVS_##reg)
-#define mw32(reg,val)  writel((val), regs + MVS_##reg)
-#define mw32_f(reg,val)        do {                    \
-       writel((val), regs + MVS_##reg);        \
-       readl(regs + MVS_##reg);                \
-       } while (0)
-
-#define MVS_ID_NOT_MAPPED      0x7f
-#define MVS_CHIP_SLOT_SZ       (1U << mvi->chip->slot_width)
-
-/* offset for D2H FIS in the Received FIS List Structure */
-#define SATA_RECEIVED_D2H_FIS(reg_set) \
-       ((void *) mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x40)
-#define SATA_RECEIVED_PIO_FIS(reg_set) \
-       ((void *) mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x20)
-#define UNASSOC_D2H_FIS(id)            \
-       ((void *) mvi->rx_fis + 0x100 * id)
-
-#define for_each_phy(__lseq_mask, __mc, __lseq, __rest)                        \
-       for ((__mc) = (__lseq_mask), (__lseq) = 0;                      \
-                                       (__mc) != 0 && __rest;          \
-                                       (++__lseq), (__mc) >>= 1)
-
-/* driver compile-time configuration */
-enum driver_configuration {
-       MVS_TX_RING_SZ          = 1024, /* TX ring size (12-bit) */
-       MVS_RX_RING_SZ          = 1024, /* RX ring size (12-bit) */
-                                       /* software requires power-of-2
-                                          ring size */
-
-       MVS_SLOTS               = 512,  /* command slots */
-       MVS_SLOT_BUF_SZ         = 8192, /* cmd tbl + IU + status + PRD */
-       MVS_SSP_CMD_SZ          = 64,   /* SSP command table buffer size */
-       MVS_ATA_CMD_SZ          = 96,   /* SATA command table buffer size */
-       MVS_OAF_SZ              = 64,   /* Open address frame buffer size */
-
-       MVS_RX_FIS_COUNT        = 17,   /* Optional rx'd FISs (max 17) */
-
-       MVS_QUEUE_SIZE          = 30,   /* Support Queue depth */
-       MVS_CAN_QUEUE           = MVS_SLOTS - 1,        /* SCSI Queue depth */
-};
-
-/* unchangeable hardware details */
-enum hardware_details {
-       MVS_MAX_PHYS            = 8,    /* max. possible phys */
-       MVS_MAX_PORTS           = 8,    /* max. possible ports */
-       MVS_RX_FISL_SZ          = 0x400 + (MVS_RX_FIS_COUNT * 0x100),
-};
-
-/* peripheral registers (BAR2) */
-enum peripheral_registers {
-       SPI_CTL                 = 0x10, /* EEPROM control */
-       SPI_CMD                 = 0x14, /* EEPROM command */
-       SPI_DATA                = 0x18, /* EEPROM data */
-};
-
-enum peripheral_register_bits {
-       TWSI_RDY                = (1U << 7),    /* EEPROM interface ready */
-       TWSI_RD                 = (1U << 4),    /* EEPROM read access */
-
-       SPI_ADDR_MASK           = 0x3ffff,      /* bits 17:0 */
-};
-
-/* enhanced mode registers (BAR4) */
-enum hw_registers {
-       MVS_GBL_CTL             = 0x04,  /* global control */
-       MVS_GBL_INT_STAT        = 0x08,  /* global irq status */
-       MVS_GBL_PI              = 0x0C,  /* ports implemented bitmask */
-       MVS_GBL_PORT_TYPE       = 0xa0,  /* port type */
-
-       MVS_CTL                 = 0x100, /* SAS/SATA port configuration */
-       MVS_PCS                 = 0x104, /* SAS/SATA port control/status */
-       MVS_CMD_LIST_LO         = 0x108, /* cmd list addr */
-       MVS_CMD_LIST_HI         = 0x10C,
-       MVS_RX_FIS_LO           = 0x110, /* RX FIS list addr */
-       MVS_RX_FIS_HI           = 0x114,
-
-       MVS_TX_CFG              = 0x120, /* TX configuration */
-       MVS_TX_LO               = 0x124, /* TX (delivery) ring addr */
-       MVS_TX_HI               = 0x128,
-
-       MVS_TX_PROD_IDX         = 0x12C, /* TX producer pointer */
-       MVS_TX_CONS_IDX         = 0x130, /* TX consumer pointer (RO) */
-       MVS_RX_CFG              = 0x134, /* RX configuration */
-       MVS_RX_LO               = 0x138, /* RX (completion) ring addr */
-       MVS_RX_HI               = 0x13C,
-       MVS_RX_CONS_IDX         = 0x140, /* RX consumer pointer (RO) */
-
-       MVS_INT_COAL            = 0x148, /* Int coalescing config */
-       MVS_INT_COAL_TMOUT      = 0x14C, /* Int coalescing timeout */
-       MVS_INT_STAT            = 0x150, /* Central int status */
-       MVS_INT_MASK            = 0x154, /* Central int enable */
-       MVS_INT_STAT_SRS        = 0x158, /* SATA register set status */
-       MVS_INT_MASK_SRS        = 0x15C,
-
-                                        /* ports 1-3 follow after this */
-       MVS_P0_INT_STAT         = 0x160, /* port0 interrupt status */
-       MVS_P0_INT_MASK         = 0x164, /* port0 interrupt mask */
-       MVS_P4_INT_STAT         = 0x200, /* Port 4 interrupt status */
-       MVS_P4_INT_MASK         = 0x204, /* Port 4 interrupt enable mask */
-
-                                        /* ports 1-3 follow after this */
-       MVS_P0_SER_CTLSTAT      = 0x180, /* port0 serial control/status */
-       MVS_P4_SER_CTLSTAT      = 0x220, /* port4 serial control/status */
-
-       MVS_CMD_ADDR            = 0x1B8, /* Command register port (addr) */
-       MVS_CMD_DATA            = 0x1BC, /* Command register port (data) */
-
-                                        /* ports 1-3 follow after this */
-       MVS_P0_CFG_ADDR         = 0x1C0, /* port0 phy register address */
-       MVS_P0_CFG_DATA         = 0x1C4, /* port0 phy register data */
-       MVS_P4_CFG_ADDR         = 0x230, /* Port 4 config address */
-       MVS_P4_CFG_DATA         = 0x234, /* Port 4 config data */
-
-                                        /* ports 1-3 follow after this */
-       MVS_P0_VSR_ADDR         = 0x1E0, /* port0 VSR address */
-       MVS_P0_VSR_DATA         = 0x1E4, /* port0 VSR data */
-       MVS_P4_VSR_ADDR         = 0x250, /* port 4 VSR addr */
-       MVS_P4_VSR_DATA         = 0x254, /* port 4 VSR data */
-};
-
-enum hw_register_bits {
-       /* MVS_GBL_CTL */
-       INT_EN                  = (1U << 1),    /* Global int enable */
-       HBA_RST                 = (1U << 0),    /* HBA reset */
-
-       /* MVS_GBL_INT_STAT */
-       INT_XOR                 = (1U << 4),    /* XOR engine event */
-       INT_SAS_SATA            = (1U << 0),    /* SAS/SATA event */
-
-       /* MVS_GBL_PORT_TYPE */                 /* shl for ports 1-3 */
-       SATA_TARGET             = (1U << 16),   /* port0 SATA target enable */
-       MODE_AUTO_DET_PORT7 = (1U << 15),       /* port0 SAS/SATA autodetect */
-       MODE_AUTO_DET_PORT6 = (1U << 14),
-       MODE_AUTO_DET_PORT5 = (1U << 13),
-       MODE_AUTO_DET_PORT4 = (1U << 12),
-       MODE_AUTO_DET_PORT3 = (1U << 11),
-       MODE_AUTO_DET_PORT2 = (1U << 10),
-       MODE_AUTO_DET_PORT1 = (1U << 9),
-       MODE_AUTO_DET_PORT0 = (1U << 8),
-       MODE_AUTO_DET_EN    =   MODE_AUTO_DET_PORT0 | MODE_AUTO_DET_PORT1 |
-                               MODE_AUTO_DET_PORT2 | MODE_AUTO_DET_PORT3 |
-                               MODE_AUTO_DET_PORT4 | MODE_AUTO_DET_PORT5 |
-                               MODE_AUTO_DET_PORT6 | MODE_AUTO_DET_PORT7,
-       MODE_SAS_PORT7_MASK = (1U << 7),  /* port0 SAS(1), SATA(0) mode */
-       MODE_SAS_PORT6_MASK = (1U << 6),
-       MODE_SAS_PORT5_MASK = (1U << 5),
-       MODE_SAS_PORT4_MASK = (1U << 4),
-       MODE_SAS_PORT3_MASK = (1U << 3),
-       MODE_SAS_PORT2_MASK = (1U << 2),
-       MODE_SAS_PORT1_MASK = (1U << 1),
-       MODE_SAS_PORT0_MASK = (1U << 0),
-       MODE_SAS_SATA   =       MODE_SAS_PORT0_MASK | MODE_SAS_PORT1_MASK |
-                               MODE_SAS_PORT2_MASK | MODE_SAS_PORT3_MASK |
-                               MODE_SAS_PORT4_MASK | MODE_SAS_PORT5_MASK |
-                               MODE_SAS_PORT6_MASK | MODE_SAS_PORT7_MASK,
-
-                               /* SAS_MODE value may be
-                                * dictated (in hw) by values
-                                * of SATA_TARGET & AUTO_DET
-                                */
-
-       /* MVS_TX_CFG */
-       TX_EN                   = (1U << 16),   /* Enable TX */
-       TX_RING_SZ_MASK         = 0xfff,        /* TX ring size, bits 11:0 */
-
-       /* MVS_RX_CFG */
-       RX_EN                   = (1U << 16),   /* Enable RX */
-       RX_RING_SZ_MASK         = 0xfff,        /* RX ring size, bits 11:0 */
-
-       /* MVS_INT_COAL */
-       COAL_EN                 = (1U << 16),   /* Enable int coalescing */
-
-       /* MVS_INT_STAT, MVS_INT_MASK */
-       CINT_I2C                = (1U << 31),   /* I2C event */
-       CINT_SW0                = (1U << 30),   /* software event 0 */
-       CINT_SW1                = (1U << 29),   /* software event 1 */
-       CINT_PRD_BC             = (1U << 28),   /* PRD BC err for read cmd */
-       CINT_DMA_PCIE           = (1U << 27),   /* DMA to PCIE timeout */
-       CINT_MEM                = (1U << 26),   /* int mem parity err */
-       CINT_I2C_SLAVE          = (1U << 25),   /* slave I2C event */
-       CINT_SRS                = (1U << 3),    /* SRS event */
-       CINT_CI_STOP            = (1U << 1),    /* cmd issue stopped */
-       CINT_DONE               = (1U << 0),    /* cmd completion */
-
-                                               /* shl for ports 1-3 */
-       CINT_PORT_STOPPED       = (1U << 16),   /* port0 stopped */
-       CINT_PORT               = (1U << 8),    /* port0 event */
-       CINT_PORT_MASK_OFFSET   = 8,
-       CINT_PORT_MASK          = (0xFF << CINT_PORT_MASK_OFFSET),
-
-       /* TX (delivery) ring bits */
-       TXQ_CMD_SHIFT           = 29,
-       TXQ_CMD_SSP             = 1,            /* SSP protocol */
-       TXQ_CMD_SMP             = 2,            /* SMP protocol */
-       TXQ_CMD_STP             = 3,            /* STP/SATA protocol */
-       TXQ_CMD_SSP_FREE_LIST   = 4,            /* add to SSP targ free list */
-       TXQ_CMD_SLOT_RESET      = 7,            /* reset command slot */
-       TXQ_MODE_I              = (1U << 28),   /* mode: 0=target,1=initiator */
-       TXQ_PRIO_HI             = (1U << 27),   /* priority: 0=normal, 1=high */
-       TXQ_SRS_SHIFT           = 20,           /* SATA register set */
-       TXQ_SRS_MASK            = 0x7f,
-       TXQ_PHY_SHIFT           = 12,           /* PHY bitmap */
-       TXQ_PHY_MASK            = 0xff,
-       TXQ_SLOT_MASK           = 0xfff,        /* slot number */
-
-       /* RX (completion) ring bits */
-       RXQ_GOOD                = (1U << 23),   /* Response good */
-       RXQ_SLOT_RESET          = (1U << 21),   /* Slot reset complete */
-       RXQ_CMD_RX              = (1U << 20),   /* target cmd received */
-       RXQ_ATTN                = (1U << 19),   /* attention */
-       RXQ_RSP                 = (1U << 18),   /* response frame xfer'd */
-       RXQ_ERR                 = (1U << 17),   /* err info rec xfer'd */
-       RXQ_DONE                = (1U << 16),   /* cmd complete */
-       RXQ_SLOT_MASK           = 0xfff,        /* slot number */
-
-       /* mvs_cmd_hdr bits */
-       MCH_PRD_LEN_SHIFT       = 16,           /* 16-bit PRD table len */
-       MCH_SSP_FR_TYPE_SHIFT   = 13,           /* SSP frame type */
-
-                                               /* SSP initiator only */
-       MCH_SSP_FR_CMD          = 0x0,          /* COMMAND frame */
-
-                                               /* SSP initiator or target */
-       MCH_SSP_FR_TASK         = 0x1,          /* TASK frame */
-
-                                               /* SSP target only */
-       MCH_SSP_FR_XFER_RDY     = 0x4,          /* XFER_RDY frame */
-       MCH_SSP_FR_RESP         = 0x5,          /* RESPONSE frame */
-       MCH_SSP_FR_READ         = 0x6,          /* Read DATA frame(s) */
-       MCH_SSP_FR_READ_RESP    = 0x7,          /* ditto, plus RESPONSE */
-
-       MCH_PASSTHRU            = (1U << 12),   /* pass-through (SSP) */
-       MCH_FBURST              = (1U << 11),   /* first burst (SSP) */
-       MCH_CHK_LEN             = (1U << 10),   /* chk xfer len (SSP) */
-       MCH_RETRY               = (1U << 9),    /* tport layer retry (SSP) */
-       MCH_PROTECTION          = (1U << 8),    /* protection info rec (SSP) */
-       MCH_RESET               = (1U << 7),    /* Reset (STP/SATA) */
-       MCH_FPDMA               = (1U << 6),    /* First party DMA (STP/SATA) */
-       MCH_ATAPI               = (1U << 5),    /* ATAPI (STP/SATA) */
-       MCH_BIST                = (1U << 4),    /* BIST activate (STP/SATA) */
-       MCH_PMP_MASK            = 0xf,          /* PMP from cmd FIS (STP/SATA)*/
-
-       CCTL_RST                = (1U << 5),    /* port logic reset */
-
-                                               /* 0(LSB first), 1(MSB first) */
-       CCTL_ENDIAN_DATA        = (1U << 3),    /* PRD data */
-       CCTL_ENDIAN_RSP         = (1U << 2),    /* response frame */
-       CCTL_ENDIAN_OPEN        = (1U << 1),    /* open address frame */
-       CCTL_ENDIAN_CMD         = (1U << 0),    /* command table */
-
-       /* MVS_Px_SER_CTLSTAT (per-phy control) */
-       PHY_SSP_RST             = (1U << 3),    /* reset SSP link layer */
-       PHY_BCAST_CHG           = (1U << 2),    /* broadcast(change) notif */
-       PHY_RST_HARD            = (1U << 1),    /* hard reset + phy reset */
-       PHY_RST                 = (1U << 0),    /* phy reset */
-       PHY_MIN_SPP_PHYS_LINK_RATE_MASK = (0xF << 8),
-       PHY_MAX_SPP_PHYS_LINK_RATE_MASK = (0xF << 12),
-       PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET = (16),
-       PHY_NEG_SPP_PHYS_LINK_RATE_MASK =
-                       (0xF << PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET),
-       PHY_READY_MASK          = (1U << 20),
-
-       /* MVS_Px_INT_STAT, MVS_Px_INT_MASK (per-phy events) */
-       PHYEV_DEC_ERR           = (1U << 24),   /* Phy Decoding Error */
-       PHYEV_UNASSOC_FIS       = (1U << 19),   /* unassociated FIS rx'd */
-       PHYEV_AN                = (1U << 18),   /* SATA async notification */
-       PHYEV_BIST_ACT          = (1U << 17),   /* BIST activate FIS */
-       PHYEV_SIG_FIS           = (1U << 16),   /* signature FIS */
-       PHYEV_POOF              = (1U << 12),   /* phy ready from 1 -> 0 */
-       PHYEV_IU_BIG            = (1U << 11),   /* IU too long err */
-       PHYEV_IU_SMALL          = (1U << 10),   /* IU too short err */
-       PHYEV_UNK_TAG           = (1U << 9),    /* unknown tag */
-       PHYEV_BROAD_CH          = (1U << 8),    /* broadcast(CHANGE) */
-       PHYEV_COMWAKE           = (1U << 7),    /* COMWAKE rx'd */
-       PHYEV_PORT_SEL          = (1U << 6),    /* port selector present */
-       PHYEV_HARD_RST          = (1U << 5),    /* hard reset rx'd */
-       PHYEV_ID_TMOUT          = (1U << 4),    /* identify timeout */
-       PHYEV_ID_FAIL           = (1U << 3),    /* identify failed */
-       PHYEV_ID_DONE           = (1U << 2),    /* identify done */
-       PHYEV_HARD_RST_DONE     = (1U << 1),    /* hard reset done */
-       PHYEV_RDY_CH            = (1U << 0),    /* phy ready changed state */
-
-       /* MVS_PCS */
-       PCS_EN_SATA_REG_SHIFT   = (16),         /* Enable SATA Register Set */
-       PCS_EN_PORT_XMT_SHIFT   = (12),         /* Enable Port Transmit */
-       PCS_EN_PORT_XMT_SHIFT2  = (8),          /* For 6480 */
-       PCS_SATA_RETRY          = (1U << 8),    /* retry ctl FIS on R_ERR */
-       PCS_RSP_RX_EN           = (1U << 7),    /* raw response rx */
-       PCS_SELF_CLEAR          = (1U << 5),    /* self-clearing int mode */
-       PCS_FIS_RX_EN           = (1U << 4),    /* FIS rx enable */
-       PCS_CMD_STOP_ERR        = (1U << 3),    /* cmd stop-on-err enable */
-       PCS_CMD_RST             = (1U << 1),    /* reset cmd issue */
-       PCS_CMD_EN              = (1U << 0),    /* enable cmd issue */
-
-       /* Port n Attached Device Info */
-       PORT_DEV_SSP_TRGT       = (1U << 19),
-       PORT_DEV_SMP_TRGT       = (1U << 18),
-       PORT_DEV_STP_TRGT       = (1U << 17),
-       PORT_DEV_SSP_INIT       = (1U << 11),
-       PORT_DEV_SMP_INIT       = (1U << 10),
-       PORT_DEV_STP_INIT       = (1U << 9),
-       PORT_PHY_ID_MASK        = (0xFFU << 24),
-       PORT_DEV_TRGT_MASK      = (0x7U << 17),
-       PORT_DEV_INIT_MASK      = (0x7U << 9),
-       PORT_DEV_TYPE_MASK      = (0x7U << 0),
-
-       /* Port n PHY Status */
-       PHY_RDY                 = (1U << 2),
-       PHY_DW_SYNC             = (1U << 1),
-       PHY_OOB_DTCTD           = (1U << 0),
-
-       /* VSR */
-       /* PHYMODE 6 (CDB) */
-       PHY_MODE6_LATECLK       = (1U << 29),   /* Lock Clock */
-       PHY_MODE6_DTL_SPEED     = (1U << 27),   /* Digital Loop Speed */
-       PHY_MODE6_FC_ORDER      = (1U << 26),   /* Fibre Channel Mode Order*/
-       PHY_MODE6_MUCNT_EN      = (1U << 24),   /* u Count Enable */
-       PHY_MODE6_SEL_MUCNT_LEN = (1U << 22),   /* Training Length Select */
-       PHY_MODE6_SELMUPI       = (1U << 20),   /* Phase Multi Select (init) */
-       PHY_MODE6_SELMUPF       = (1U << 18),   /* Phase Multi Select (final) */
-       PHY_MODE6_SELMUFF       = (1U << 16),   /* Freq Loop Multi Sel(final) */
-       PHY_MODE6_SELMUFI       = (1U << 14),   /* Freq Loop Multi Sel(init) */
-       PHY_MODE6_FREEZE_LOOP   = (1U << 12),   /* Freeze Rx CDR Loop */
-       PHY_MODE6_INT_RXFOFFS   = (1U << 3),    /* Rx CDR Freq Loop Enable */
-       PHY_MODE6_FRC_RXFOFFS   = (1U << 2),    /* Initial Rx CDR Offset */
-       PHY_MODE6_STAU_0D8      = (1U << 1),    /* Rx CDR Freq Loop Saturate */
-       PHY_MODE6_RXSAT_DIS     = (1U << 0),    /* Saturate Ctl */
-};
-
-enum mvs_info_flags {
-       MVF_MSI                 = (1U << 0),    /* MSI is enabled */
-       MVF_PHY_PWR_FIX         = (1U << 1),    /* bug workaround */
-};
-
-enum sas_cmd_port_registers {
-       CMD_CMRST_OOB_DET       = 0x100, /* COMRESET OOB detect register */
-       CMD_CMWK_OOB_DET        = 0x104, /* COMWAKE OOB detect register */
-       CMD_CMSAS_OOB_DET       = 0x108, /* COMSAS OOB detect register */
-       CMD_BRST_OOB_DET        = 0x10c, /* burst OOB detect register */
-       CMD_OOB_SPACE           = 0x110, /* OOB space control register */
-       CMD_OOB_BURST           = 0x114, /* OOB burst control register */
-       CMD_PHY_TIMER           = 0x118, /* PHY timer control register */
-       CMD_PHY_CONFIG0         = 0x11c, /* PHY config register 0 */
-       CMD_PHY_CONFIG1         = 0x120, /* PHY config register 1 */
-       CMD_SAS_CTL0            = 0x124, /* SAS control register 0 */
-       CMD_SAS_CTL1            = 0x128, /* SAS control register 1 */
-       CMD_SAS_CTL2            = 0x12c, /* SAS control register 2 */
-       CMD_SAS_CTL3            = 0x130, /* SAS control register 3 */
-       CMD_ID_TEST             = 0x134, /* ID test register */
-       CMD_PL_TIMER            = 0x138, /* PL timer register */
-       CMD_WD_TIMER            = 0x13c, /* WD timer register */
-       CMD_PORT_SEL_COUNT      = 0x140, /* port selector count register */
-       CMD_APP_MEM_CTL         = 0x144, /* Application Memory Control */
-       CMD_XOR_MEM_CTL         = 0x148, /* XOR Block Memory Control */
-       CMD_DMA_MEM_CTL         = 0x14c, /* DMA Block Memory Control */
-       CMD_PORT_MEM_CTL0       = 0x150, /* Port Memory Control 0 */
-       CMD_PORT_MEM_CTL1       = 0x154, /* Port Memory Control 1 */
-       CMD_SATA_PORT_MEM_CTL0  = 0x158, /* SATA Port Memory Control 0 */
-       CMD_SATA_PORT_MEM_CTL1  = 0x15c, /* SATA Port Memory Control 1 */
-       CMD_XOR_MEM_BIST_CTL    = 0x160, /* XOR Memory BIST Control */
-       CMD_XOR_MEM_BIST_STAT   = 0x164, /* XOR Memroy BIST Status */
-       CMD_DMA_MEM_BIST_CTL    = 0x168, /* DMA Memory BIST Control */
-       CMD_DMA_MEM_BIST_STAT   = 0x16c, /* DMA Memory BIST Status */
-       CMD_PORT_MEM_BIST_CTL   = 0x170, /* Port Memory BIST Control */
-       CMD_PORT_MEM_BIST_STAT0 = 0x174, /* Port Memory BIST Status 0 */
-       CMD_PORT_MEM_BIST_STAT1 = 0x178, /* Port Memory BIST Status 1 */
-       CMD_STP_MEM_BIST_CTL    = 0x17c, /* STP Memory BIST Control */
-       CMD_STP_MEM_BIST_STAT0  = 0x180, /* STP Memory BIST Status 0 */
-       CMD_STP_MEM_BIST_STAT1  = 0x184, /* STP Memory BIST Status 1 */
-       CMD_RESET_COUNT         = 0x188, /* Reset Count */
-       CMD_MONTR_DATA_SEL      = 0x18C, /* Monitor Data/Select */
-       CMD_PLL_PHY_CONFIG      = 0x190, /* PLL/PHY Configuration */
-       CMD_PHY_CTL             = 0x194, /* PHY Control and Status */
-       CMD_PHY_TEST_COUNT0     = 0x198, /* Phy Test Count 0 */
-       CMD_PHY_TEST_COUNT1     = 0x19C, /* Phy Test Count 1 */
-       CMD_PHY_TEST_COUNT2     = 0x1A0, /* Phy Test Count 2 */
-       CMD_APP_ERR_CONFIG      = 0x1A4, /* Application Error Configuration */
-       CMD_PND_FIFO_CTL0       = 0x1A8, /* Pending FIFO Control 0 */
-       CMD_HOST_CTL            = 0x1AC, /* Host Control Status */
-       CMD_HOST_WR_DATA        = 0x1B0, /* Host Write Data */
-       CMD_HOST_RD_DATA        = 0x1B4, /* Host Read Data */
-       CMD_PHY_MODE_21         = 0x1B8, /* Phy Mode 21 */
-       CMD_SL_MODE0            = 0x1BC, /* SL Mode 0 */
-       CMD_SL_MODE1            = 0x1C0, /* SL Mode 1 */
-       CMD_PND_FIFO_CTL1       = 0x1C4, /* Pending FIFO Control 1 */
-};
-
-/* SAS/SATA configuration port registers, aka phy registers */
-enum sas_sata_config_port_regs {
-       PHYR_IDENTIFY           = 0x00, /* info for IDENTIFY frame */
-       PHYR_ADDR_LO            = 0x04, /* my SAS address (low) */
-       PHYR_ADDR_HI            = 0x08, /* my SAS address (high) */
-       PHYR_ATT_DEV_INFO       = 0x0C, /* attached device info */
-       PHYR_ATT_ADDR_LO        = 0x10, /* attached dev SAS addr (low) */
-       PHYR_ATT_ADDR_HI        = 0x14, /* attached dev SAS addr (high) */
-       PHYR_SATA_CTL           = 0x18, /* SATA control */
-       PHYR_PHY_STAT           = 0x1C, /* PHY status */
-       PHYR_SATA_SIG0          = 0x20, /*port SATA signature FIS(Byte 0-3) */
-       PHYR_SATA_SIG1          = 0x24, /*port SATA signature FIS(Byte 4-7) */
-       PHYR_SATA_SIG2          = 0x28, /*port SATA signature FIS(Byte 8-11) */
-       PHYR_SATA_SIG3          = 0x2c, /*port SATA signature FIS(Byte 12-15) */
-       PHYR_R_ERR_COUNT        = 0x30, /* port R_ERR count register */
-       PHYR_CRC_ERR_COUNT      = 0x34, /* port CRC error count register */
-       PHYR_WIDE_PORT          = 0x38, /* wide port participating */
-       PHYR_CURRENT0           = 0x80, /* current connection info 0 */
-       PHYR_CURRENT1           = 0x84, /* current connection info 1 */
-       PHYR_CURRENT2           = 0x88, /* current connection info 2 */
-};
-
-/*  SAS/SATA Vendor Specific Port Registers */
-enum sas_sata_vsp_regs {
-       VSR_PHY_STAT            = 0x00, /* Phy Status */
-       VSR_PHY_MODE1           = 0x01, /* phy tx */
-       VSR_PHY_MODE2           = 0x02, /* tx scc */
-       VSR_PHY_MODE3           = 0x03, /* pll */
-       VSR_PHY_MODE4           = 0x04, /* VCO */
-       VSR_PHY_MODE5           = 0x05, /* Rx */
-       VSR_PHY_MODE6           = 0x06, /* CDR */
-       VSR_PHY_MODE7           = 0x07, /* Impedance */
-       VSR_PHY_MODE8           = 0x08, /* Voltage */
-       VSR_PHY_MODE9           = 0x09, /* Test */
-       VSR_PHY_MODE10          = 0x0A, /* Power */
-       VSR_PHY_MODE11          = 0x0B, /* Phy Mode */
-       VSR_PHY_VS0             = 0x0C, /* Vednor Specific 0 */
-       VSR_PHY_VS1             = 0x0D, /* Vednor Specific 1 */
-};
-
-enum pci_cfg_registers {
-       PCR_PHY_CTL     = 0x40,
-       PCR_PHY_CTL2    = 0x90,
-       PCR_DEV_CTRL    = 0xE8,
-};
-
-enum pci_cfg_register_bits {
-       PCTL_PWR_ON     = (0xFU << 24),
-       PCTL_OFF        = (0xFU << 12),
-       PRD_REQ_SIZE    = (0x4000),
-       PRD_REQ_MASK    = (0x00007000),
-};
-
-enum nvram_layout_offsets {
-       NVR_SIG         = 0x00,         /* 0xAA, 0x55 */
-       NVR_SAS_ADDR    = 0x02,         /* 8-byte SAS address */
-};
-
-enum chip_flavors {
-       chip_6320,
-       chip_6440,
-       chip_6480,
-};
-
-enum port_type {
-       PORT_TYPE_SAS   =  (1L << 1),
-       PORT_TYPE_SATA  =  (1L << 0),
-};
-
-/* Command Table Format */
-enum ct_format {
-       /* SSP */
-       SSP_F_H         =  0x00,
-       SSP_F_IU        =  0x18,
-       SSP_F_MAX       =  0x4D,
-       /* STP */
-       STP_CMD_FIS     =  0x00,
-       STP_ATAPI_CMD   =  0x40,
-       STP_F_MAX       =  0x10,
-       /* SMP */
-       SMP_F_T         =  0x00,
-       SMP_F_DEP       =  0x01,
-       SMP_F_MAX       =  0x101,
-};
-
-enum status_buffer {
-       SB_EIR_OFF      =  0x00,        /* Error Information Record */
-       SB_RFB_OFF      =  0x08,        /* Response Frame Buffer */
-       SB_RFB_MAX      =  0x400,       /* RFB size*/
-};
-
-enum error_info_rec {
-       CMD_ISS_STPD    = (1U << 31),   /* Cmd Issue Stopped */
-       CMD_PI_ERR      = (1U << 30),   /* Protection info error.  see flags2 */
-       RSP_OVER        = (1U << 29),   /* rsp buffer overflow */
-       RETRY_LIM       = (1U << 28),   /* FIS/frame retry limit exceeded */
-       UNK_FIS         = (1U << 27),   /* unknown FIS */
-       DMA_TERM        = (1U << 26),   /* DMA terminate primitive rx'd */
-       SYNC_ERR        = (1U << 25),   /* SYNC rx'd during frame xmit */
-       TFILE_ERR       = (1U << 24),   /* SATA taskfile Error bit set */
-       R_ERR           = (1U << 23),   /* SATA returned R_ERR prim */
-       RD_OFS          = (1U << 20),   /* Read DATA frame invalid offset */
-       XFER_RDY_OFS    = (1U << 19),   /* XFER_RDY offset error */
-       UNEXP_XFER_RDY  = (1U << 18),   /* unexpected XFER_RDY error */
-       DATA_OVER_UNDER = (1U << 16),   /* data overflow/underflow */
-       INTERLOCK       = (1U << 15),   /* interlock error */
-       NAK             = (1U << 14),   /* NAK rx'd */
-       ACK_NAK_TO      = (1U << 13),   /* ACK/NAK timeout */
-       CXN_CLOSED      = (1U << 12),   /* cxn closed w/out ack/nak */
-       OPEN_TO         = (1U << 11),   /* I_T nexus lost, open cxn timeout */
-       PATH_BLOCKED    = (1U << 10),   /* I_T nexus lost, pathway blocked */
-       NO_DEST         = (1U << 9),    /* I_T nexus lost, no destination */
-       STP_RES_BSY     = (1U << 8),    /* STP resources busy */
-       BREAK           = (1U << 7),    /* break received */
-       BAD_DEST        = (1U << 6),    /* bad destination */
-       BAD_PROTO       = (1U << 5),    /* protocol not supported */
-       BAD_RATE        = (1U << 4),    /* cxn rate not supported */
-       WRONG_DEST      = (1U << 3),    /* wrong destination error */
-       CREDIT_TO       = (1U << 2),    /* credit timeout */
-       WDOG_TO         = (1U << 1),    /* watchdog timeout */
-       BUF_PAR         = (1U << 0),    /* buffer parity error */
-};
-
-enum error_info_rec_2 {
-       SLOT_BSY_ERR    = (1U << 31),   /* Slot Busy Error */
-       GRD_CHK_ERR     = (1U << 14),   /* Guard Check Error */
-       APP_CHK_ERR     = (1U << 13),   /* Application Check error */
-       REF_CHK_ERR     = (1U << 12),   /* Reference Check Error */
-       USR_BLK_NM      = (1U << 0),    /* User Block Number */
-};
-
-struct mvs_chip_info {
-       u32             n_phy;
-       u32             srs_sz;
-       u32             slot_width;
-};
-
-struct mvs_err_info {
-       __le32                  flags;
-       __le32                  flags2;
-};
-
-struct mvs_prd {
-       __le64                  addr;           /* 64-bit buffer address */
-       __le32                  reserved;
-       __le32                  len;            /* 16-bit length */
-};
-
-struct mvs_cmd_hdr {
-       __le32                  flags;          /* PRD tbl len; SAS, SATA ctl */
-       __le32                  lens;           /* cmd, max resp frame len */
-       __le32                  tags;           /* targ port xfer tag; tag */
-       __le32                  data_len;       /* data xfer len */
-       __le64                  cmd_tbl;        /* command table address */
-       __le64                  open_frame;     /* open addr frame address */
-       __le64                  status_buf;     /* status buffer address */
-       __le64                  prd_tbl;        /* PRD tbl address */
-       __le32                  reserved[4];
-};
-
-struct mvs_port {
-       struct asd_sas_port     sas_port;
-       u8                      port_attached;
-       u8                      taskfileset;
-       u8                      wide_port_phymap;
-       struct list_head        list;
-};
-
-struct mvs_phy {
-       struct mvs_port         *port;
-       struct asd_sas_phy      sas_phy;
-       struct sas_identify     identify;
-       struct scsi_device      *sdev;
-       u64             dev_sas_addr;
-       u64             att_dev_sas_addr;
-       u32             att_dev_info;
-       u32             dev_info;
-       u32             phy_type;
-       u32             phy_status;
-       u32             irq_status;
-       u32             frame_rcvd_size;
-       u8              frame_rcvd[32];
-       u8              phy_attached;
-       enum sas_linkrate       minimum_linkrate;
-       enum sas_linkrate       maximum_linkrate;
-};
-
-struct mvs_slot_info {
-       struct list_head        list;
-       struct sas_task         *task;
-       u32                     n_elem;
-       u32                     tx;
-
-       /* DMA buffer for storing cmd tbl, open addr frame, status buffer,
-        * and PRD table
-        */
-       void                    *buf;
-       dma_addr_t              buf_dma;
-#if _MV_DUMP
-       u32                     cmd_size;
-#endif
-
-       void                    *response;
-       struct mvs_port         *port;
-};
-
-struct mvs_info {
-       unsigned long           flags;
-
-       spinlock_t              lock;           /* host-wide lock */
-       struct pci_dev          *pdev;          /* our device */
-       void __iomem            *regs;          /* enhanced mode registers */
-       void __iomem            *peri_regs;     /* peripheral registers */
-
-       u8                      sas_addr[SAS_ADDR_SIZE];
-       struct sas_ha_struct    sas;            /* SCSI/SAS glue */
-       struct Scsi_Host        *shost;
-
-       __le32                  *tx;            /* TX (delivery) DMA ring */
-       dma_addr_t              tx_dma;
-       u32                     tx_prod;        /* cached next-producer idx */
-
-       __le32                  *rx;            /* RX (completion) DMA ring */
-       dma_addr_t              rx_dma;
-       u32                     rx_cons;        /* RX consumer idx */
-
-       __le32                  *rx_fis;        /* RX'd FIS area */
-       dma_addr_t              rx_fis_dma;
-
-       struct mvs_cmd_hdr      *slot;  /* DMA command header slots */
-       dma_addr_t              slot_dma;
-
-       const struct mvs_chip_info *chip;
-
-       u8                      tags[MVS_SLOTS];
-       struct mvs_slot_info    slot_info[MVS_SLOTS];
-                               /* further per-slot information */
-       struct mvs_phy          phy[MVS_MAX_PHYS];
-       struct mvs_port         port[MVS_MAX_PHYS];
-#ifdef MVS_USE_TASKLET
-       struct tasklet_struct   tasklet;
-#endif
-};
-
-static int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
-                          void *funcdata);
-static u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port);
-static void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val);
-static u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port);
-static void mvs_write_port_irq_stat(struct mvs_info *mvi, u32 port, u32 val);
-static void mvs_write_port_irq_mask(struct mvs_info *mvi, u32 port, u32 val);
-static u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port);
-
-static u32 mvs_is_phy_ready(struct mvs_info *mvi, int i);
-static void mvs_detect_porttype(struct mvs_info *mvi, int i);
-static void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st);
-static void mvs_release_task(struct mvs_info *mvi, int phy_no);
-
-static int mvs_scan_finished(struct Scsi_Host *, unsigned long);
-static void mvs_scan_start(struct Scsi_Host *);
-static int mvs_slave_configure(struct scsi_device *sdev);
-
-static struct scsi_transport_template *mvs_stt;
-
-static const struct mvs_chip_info mvs_chips[] = {
-       [chip_6320] =           { 2, 16, 9  },
-       [chip_6440] =           { 4, 16, 9  },
-       [chip_6480] =           { 8, 32, 10 },
-};
-
-static struct scsi_host_template mvs_sht = {
-       .module                 = THIS_MODULE,
-       .name                   = DRV_NAME,
-       .queuecommand           = sas_queuecommand,
-       .target_alloc           = sas_target_alloc,
-       .slave_configure        = mvs_slave_configure,
-       .slave_destroy          = sas_slave_destroy,
-       .scan_finished          = mvs_scan_finished,
-       .scan_start             = mvs_scan_start,
-       .change_queue_depth     = sas_change_queue_depth,
-       .change_queue_type      = sas_change_queue_type,
-       .bios_param             = sas_bios_param,
-       .can_queue              = 1,
-       .cmd_per_lun            = 1,
-       .this_id                = -1,
-       .sg_tablesize           = SG_ALL,
-       .max_sectors            = SCSI_DEFAULT_MAX_SECTORS,
-       .use_clustering         = ENABLE_CLUSTERING,
-       .eh_device_reset_handler        = sas_eh_device_reset_handler,
-       .eh_bus_reset_handler   = sas_eh_bus_reset_handler,
-       .slave_alloc            = sas_slave_alloc,
-       .target_destroy         = sas_target_destroy,
-       .ioctl                  = sas_ioctl,
-};
-
-static void mvs_hexdump(u32 size, u8 *data, u32 baseaddr)
-{
-       u32 i;
-       u32 run;
-       u32 offset;
-
-       offset = 0;
-       while (size) {
-               printk("%08X : ", baseaddr + offset);
-               if (size >= 16)
-                       run = 16;
-               else
-                       run = size;
-               size -= run;
-               for (i = 0; i < 16; i++) {
-                       if (i < run)
-                               printk("%02X ", (u32)data[i]);
-                       else
-                               printk("   ");
-               }
-               printk(": ");
-               for (i = 0; i < run; i++)
-                       printk("%c", isalnum(data[i]) ? data[i] : '.');
-               printk("\n");
-               data = &data[16];
-               offset += run;
-       }
-       printk("\n");
-}
-
-#if _MV_DUMP
-static void mvs_hba_sb_dump(struct mvs_info *mvi, u32 tag,
-                                  enum sas_protocol proto)
-{
-       u32 offset;
-       struct pci_dev *pdev = mvi->pdev;
-       struct mvs_slot_info *slot = &mvi->slot_info[tag];
-
-       offset = slot->cmd_size + MVS_OAF_SZ +
-           sizeof(struct mvs_prd) * slot->n_elem;
-       dev_printk(KERN_DEBUG, &pdev->dev, "+---->Status buffer[%d] :\n",
-                       tag);
-       mvs_hexdump(32, (u8 *) slot->response,
-                   (u32) slot->buf_dma + offset);
-}
-#endif
-
-static void mvs_hba_memory_dump(struct mvs_info *mvi, u32 tag,
-                               enum sas_protocol proto)
-{
-#if _MV_DUMP
-       u32 sz, w_ptr;
-       u64 addr;
-       void __iomem *regs = mvi->regs;
-       struct pci_dev *pdev = mvi->pdev;
-       struct mvs_slot_info *slot = &mvi->slot_info[tag];
-
-       /*Delivery Queue */
-       sz = mr32(TX_CFG) & TX_RING_SZ_MASK;
-       w_ptr = slot->tx;
-       addr = mr32(TX_HI) << 16 << 16 | mr32(TX_LO);
-       dev_printk(KERN_DEBUG, &pdev->dev,
-               "Delivery Queue Size=%04d , WRT_PTR=%04X\n", sz, w_ptr);
-       dev_printk(KERN_DEBUG, &pdev->dev,
-               "Delivery Queue Base Address=0x%llX (PA)"
-               "(tx_dma=0x%llX), Entry=%04d\n",
-               addr, mvi->tx_dma, w_ptr);
-       mvs_hexdump(sizeof(u32), (u8 *)(&mvi->tx[mvi->tx_prod]),
-                       (u32) mvi->tx_dma + sizeof(u32) * w_ptr);
-       /*Command List */
-       addr = mvi->slot_dma;
-       dev_printk(KERN_DEBUG, &pdev->dev,
-               "Command List Base Address=0x%llX (PA)"
-               "(slot_dma=0x%llX), Header=%03d\n",
-               addr, slot->buf_dma, tag);
-       dev_printk(KERN_DEBUG, &pdev->dev, "Command Header[%03d]:\n", tag);
-       /*mvs_cmd_hdr */
-       mvs_hexdump(sizeof(struct mvs_cmd_hdr), (u8 *)(&mvi->slot[tag]),
-               (u32) mvi->slot_dma + tag * sizeof(struct mvs_cmd_hdr));
-       /*1.command table area */
-       dev_printk(KERN_DEBUG, &pdev->dev, "+---->Command Table :\n");
-       mvs_hexdump(slot->cmd_size, (u8 *) slot->buf, (u32) slot->buf_dma);
-       /*2.open address frame area */
-       dev_printk(KERN_DEBUG, &pdev->dev, "+---->Open Address Frame :\n");
-       mvs_hexdump(MVS_OAF_SZ, (u8 *) slot->buf + slot->cmd_size,
-                               (u32) slot->buf_dma + slot->cmd_size);
-       /*3.status buffer */
-       mvs_hba_sb_dump(mvi, tag, proto);
-       /*4.PRD table */
-       dev_printk(KERN_DEBUG, &pdev->dev, "+---->PRD table :\n");
-       mvs_hexdump(sizeof(struct mvs_prd) * slot->n_elem,
-               (u8 *) slot->buf + slot->cmd_size + MVS_OAF_SZ,
-               (u32) slot->buf_dma + slot->cmd_size + MVS_OAF_SZ);
-#endif
-}
-
-static void mvs_hba_cq_dump(struct mvs_info *mvi)
-{
-#if (_MV_DUMP > 2)
-       u64 addr;
-       void __iomem *regs = mvi->regs;
-       struct pci_dev *pdev = mvi->pdev;
-       u32 entry = mvi->rx_cons + 1;
-       u32 rx_desc = le32_to_cpu(mvi->rx[entry]);
-
-       /*Completion Queue */
-       addr = mr32(RX_HI) << 16 << 16 | mr32(RX_LO);
-       dev_printk(KERN_DEBUG, &pdev->dev, "Completion Task = 0x%p\n",
-                  mvi->slot_info[rx_desc & RXQ_SLOT_MASK].task);
-       dev_printk(KERN_DEBUG, &pdev->dev,
-               "Completion List Base Address=0x%llX (PA), "
-               "CQ_Entry=%04d, CQ_WP=0x%08X\n",
-               addr, entry - 1, mvi->rx[0]);
-       mvs_hexdump(sizeof(u32), (u8 *)(&rx_desc),
-                   mvi->rx_dma + sizeof(u32) * entry);
-#endif
-}
-
-static void mvs_hba_interrupt_enable(struct mvs_info *mvi)
-{
-       void __iomem *regs = mvi->regs;
-       u32 tmp;
-
-       tmp = mr32(GBL_CTL);
-
-       mw32(GBL_CTL, tmp | INT_EN);
-}
-
-static void mvs_hba_interrupt_disable(struct mvs_info *mvi)
-{
-       void __iomem *regs = mvi->regs;
-       u32 tmp;
-
-       tmp = mr32(GBL_CTL);
-
-       mw32(GBL_CTL, tmp & ~INT_EN);
-}
-
-static int mvs_int_rx(struct mvs_info *mvi, bool self_clear);
-
-/* move to PCI layer or libata core? */
-static int pci_go_64(struct pci_dev *pdev)
-{
-       int rc;
-
-       if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
-               rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
-               if (rc) {
-                       rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
-                       if (rc) {
-                               dev_printk(KERN_ERR, &pdev->dev,
-                                          "64-bit DMA enable failed\n");
-                               return rc;
-                       }
-               }
-       } else {
-               rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-               if (rc) {
-                       dev_printk(KERN_ERR, &pdev->dev,
-                                  "32-bit DMA enable failed\n");
-                       return rc;
-               }
-               rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
-               if (rc) {
-                       dev_printk(KERN_ERR, &pdev->dev,
-                                  "32-bit consistent DMA enable failed\n");
-                       return rc;
-               }
-       }
-
-       return rc;
-}
-
-static int mvs_find_tag(struct mvs_info *mvi, struct sas_task *task, u32 *tag)
-{
-       if (task->lldd_task) {
-               struct mvs_slot_info *slot;
-               slot = (struct mvs_slot_info *) task->lldd_task;
-               *tag = slot - mvi->slot_info;
-               return 1;
-       }
-       return 0;
-}
-
-static void mvs_tag_clear(struct mvs_info *mvi, u32 tag)
-{
-       void *bitmap = (void *) &mvi->tags;
-       clear_bit(tag, bitmap);
-}
-
-static void mvs_tag_free(struct mvs_info *mvi, u32 tag)
-{
-       mvs_tag_clear(mvi, tag);
-}
-
-static void mvs_tag_set(struct mvs_info *mvi, unsigned int tag)
-{
-       void *bitmap = (void *) &mvi->tags;
-       set_bit(tag, bitmap);
-}
-
-static int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out)
-{
-       unsigned int index, tag;
-       void *bitmap = (void *) &mvi->tags;
-
-       index = find_first_zero_bit(bitmap, MVS_SLOTS);
-       tag = index;
-       if (tag >= MVS_SLOTS)
-               return -SAS_QUEUE_FULL;
-       mvs_tag_set(mvi, tag);
-       *tag_out = tag;
-       return 0;
-}
-
-static void mvs_tag_init(struct mvs_info *mvi)
-{
-       int i;
-       for (i = 0; i < MVS_SLOTS; ++i)
-               mvs_tag_clear(mvi, i);
-}
-
-#ifndef MVS_DISABLE_NVRAM
-static int mvs_eep_read(void __iomem *regs, u32 addr, u32 *data)
-{
-       int timeout = 1000;
-
-       if (addr & ~SPI_ADDR_MASK)
-               return -EINVAL;
-
-       writel(addr, regs + SPI_CMD);
-       writel(TWSI_RD, regs + SPI_CTL);
-
-       while (timeout-- > 0) {
-               if (readl(regs + SPI_CTL) & TWSI_RDY) {
-                       *data = readl(regs + SPI_DATA);
-                       return 0;
-               }
-
-               udelay(10);
-       }
-
-       return -EBUSY;
-}
-
-static int mvs_eep_read_buf(void __iomem *regs, u32 addr,
-                           void *buf, u32 buflen)
-{
-       u32 addr_end, tmp_addr, i, j;
-       u32 tmp = 0;
-       int rc;
-       u8 *tmp8, *buf8 = buf;
-
-       addr_end = addr + buflen;
-       tmp_addr = ALIGN(addr, 4);
-       if (addr > 0xff)
-               return -EINVAL;
-
-       j = addr & 0x3;
-       if (j) {
-               rc = mvs_eep_read(regs, tmp_addr, &tmp);
-               if (rc)
-                       return rc;
-
-               tmp8 = (u8 *)&tmp;
-               for (i = j; i < 4; i++)
-                       *buf8++ = tmp8[i];
-
-               tmp_addr += 4;
-       }
-
-       for (j = ALIGN(addr_end, 4); tmp_addr < j; tmp_addr += 4) {
-               rc = mvs_eep_read(regs, tmp_addr, &tmp);
-               if (rc)
-                       return rc;
-
-               memcpy(buf8, &tmp, 4);
-               buf8 += 4;
-       }
-
-       if (tmp_addr < addr_end) {
-               rc = mvs_eep_read(regs, tmp_addr, &tmp);
-               if (rc)
-                       return rc;
-
-               tmp8 = (u8 *)&tmp;
-               j = addr_end - tmp_addr;
-               for (i = 0; i < j; i++)
-                       *buf8++ = tmp8[i];
-
-               tmp_addr += 4;
-       }
-
-       return 0;
-}
-#endif
-
-static int mvs_nvram_read(struct mvs_info *mvi, u32 addr,
-                         void *buf, u32 buflen)
-{
-#ifndef MVS_DISABLE_NVRAM
-       void __iomem *regs = mvi->regs;
-       int rc, i;
-       u32 sum;
-       u8 hdr[2], *tmp;
-       const char *msg;
-
-       rc = mvs_eep_read_buf(regs, addr, &hdr, 2);
-       if (rc) {
-               msg = "nvram hdr read failed";
-               goto err_out;
-       }
-       rc = mvs_eep_read_buf(regs, addr + 2, buf, buflen);
-       if (rc) {
-               msg = "nvram read failed";
-               goto err_out;
-       }
-
-       if (hdr[0] != 0x5A) {
-               /* entry id */
-               msg = "invalid nvram entry id";
-               rc = -ENOENT;
-               goto err_out;
-       }
-
-       tmp = buf;
-       sum = ((u32)hdr[0]) + ((u32)hdr[1]);
-       for (i = 0; i < buflen; i++)
-               sum += ((u32)tmp[i]);
-
-       if (sum) {
-               msg = "nvram checksum failure";
-               rc = -EILSEQ;
-               goto err_out;
-       }
-
-       return 0;
-
-err_out:
-       dev_printk(KERN_ERR, &mvi->pdev->dev, "%s", msg);
-       return rc;
-#else
-       /* FIXME , For SAS target mode */
-       memcpy(buf, "\x50\x05\x04\x30\x11\xab\x00\x00", 8);
-       return 0;
-#endif
-}
-
-static void mvs_bytes_dmaed(struct mvs_info *mvi, int i)
-{
-       struct mvs_phy *phy = &mvi->phy[i];
-       struct asd_sas_phy *sas_phy = mvi->sas.sas_phy[i];
-
-       if (!phy->phy_attached)
-               return;
-
-       if (sas_phy->phy) {
-               struct sas_phy *sphy = sas_phy->phy;
-
-               sphy->negotiated_linkrate = sas_phy->linkrate;
-               sphy->minimum_linkrate = phy->minimum_linkrate;
-               sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
-               sphy->maximum_linkrate = phy->maximum_linkrate;
-               sphy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
-       }
-
-       if (phy->phy_type & PORT_TYPE_SAS) {
-               struct sas_identify_frame *id;
-
-               id = (struct sas_identify_frame *)phy->frame_rcvd;
-               id->dev_type = phy->identify.device_type;
-               id->initiator_bits = SAS_PROTOCOL_ALL;
-               id->target_bits = phy->identify.target_port_protocols;
-       } else if (phy->phy_type & PORT_TYPE_SATA) {
-               /* TODO */
-       }
-       mvi->sas.sas_phy[i]->frame_rcvd_size = phy->frame_rcvd_size;
-       mvi->sas.notify_port_event(mvi->sas.sas_phy[i],
-                                  PORTE_BYTES_DMAED);
-}
-
-static int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time)
-{
-       /* give the phy enabling interrupt event time to come in (1s
-        * is empirically about all it takes) */
-       if (time < HZ)
-               return 0;
-       /* Wait for discovery to finish */
-       scsi_flush_work(shost);
-       return 1;
-}
-
-static void mvs_scan_start(struct Scsi_Host *shost)
-{
-       int i;
-       struct mvs_info *mvi = SHOST_TO_SAS_HA(shost)->lldd_ha;
-
-       for (i = 0; i < mvi->chip->n_phy; ++i) {
-               mvs_bytes_dmaed(mvi, i);
-       }
-}
-
-static int mvs_slave_configure(struct scsi_device *sdev)
-{
-       struct domain_device *dev = sdev_to_domain_dev(sdev);
-       int ret = sas_slave_configure(sdev);
-
-       if (ret)
-               return ret;
-
-       if (dev_is_sata(dev)) {
-               /* struct ata_port *ap = dev->sata_dev.ap; */
-               /* struct ata_device *adev = ap->link.device; */
-
-               /* clamp at no NCQ for the time being */
-               /* adev->flags |= ATA_DFLAG_NCQ_OFF; */
-               scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, 1);
-       }
-       return 0;
-}
-
-static void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
-{
-       struct pci_dev *pdev = mvi->pdev;
-       struct sas_ha_struct *sas_ha = &mvi->sas;
-       struct mvs_phy *phy = &mvi->phy[phy_no];
-       struct asd_sas_phy *sas_phy = &phy->sas_phy;
-
-       phy->irq_status = mvs_read_port_irq_stat(mvi, phy_no);
-       /*
-       * events is port event now ,
-       * we need check the interrupt status which belongs to per port.
-       */
-       dev_printk(KERN_DEBUG, &pdev->dev,
-               "Port %d Event = %X\n",
-               phy_no, phy->irq_status);
-
-       if (phy->irq_status & (PHYEV_POOF | PHYEV_DEC_ERR)) {
-               mvs_release_task(mvi, phy_no);
-               if (!mvs_is_phy_ready(mvi, phy_no)) {
-                       sas_phy_disconnected(sas_phy);
-                       sas_ha->notify_phy_event(sas_phy, PHYE_LOSS_OF_SIGNAL);
-                       dev_printk(KERN_INFO, &pdev->dev,
-                               "Port %d Unplug Notice\n", phy_no);
-
-               } else
-                       mvs_phy_control(sas_phy, PHY_FUNC_LINK_RESET, NULL);
-       }
-       if (!(phy->irq_status & PHYEV_DEC_ERR)) {
-               if (phy->irq_status & PHYEV_COMWAKE) {
-                       u32 tmp = mvs_read_port_irq_mask(mvi, phy_no);
-                       mvs_write_port_irq_mask(mvi, phy_no,
-                                               tmp | PHYEV_SIG_FIS);
-               }
-               if (phy->irq_status & (PHYEV_SIG_FIS | PHYEV_ID_DONE)) {
-                       phy->phy_status = mvs_is_phy_ready(mvi, phy_no);
-                       if (phy->phy_status) {
-                               mvs_detect_porttype(mvi, phy_no);
-
-                               if (phy->phy_type & PORT_TYPE_SATA) {
-                                       u32 tmp = mvs_read_port_irq_mask(mvi,
-                                                               phy_no);
-                                       tmp &= ~PHYEV_SIG_FIS;
-                                       mvs_write_port_irq_mask(mvi,
-                                                               phy_no, tmp);
-                               }
-
-                               mvs_update_phyinfo(mvi, phy_no, 0);
-                               sas_ha->notify_phy_event(sas_phy,
-                                                       PHYE_OOB_DONE);
-                               mvs_bytes_dmaed(mvi, phy_no);
-                       } else {
-                               dev_printk(KERN_DEBUG, &pdev->dev,
-                                       "plugin interrupt but phy is gone\n");
-                               mvs_phy_control(sas_phy, PHY_FUNC_LINK_RESET,
-                                                       NULL);
-                       }
-               } else if (phy->irq_status & PHYEV_BROAD_CH) {
-                       mvs_release_task(mvi, phy_no);
-                       sas_ha->notify_port_event(sas_phy,
-                                               PORTE_BROADCAST_RCVD);
-               }
-       }
-       mvs_write_port_irq_stat(mvi, phy_no, phy->irq_status);
-}
-
-static void mvs_int_sata(struct mvs_info *mvi)
-{
-       u32 tmp;
-       void __iomem *regs = mvi->regs;
-       tmp = mr32(INT_STAT_SRS);
-       mw32(INT_STAT_SRS, tmp & 0xFFFF);
-}
-
-static void mvs_slot_reset(struct mvs_info *mvi, struct sas_task *task,
-                               u32 slot_idx)
-{
-       void __iomem *regs = mvi->regs;
-       struct domain_device *dev = task->dev;
-       struct asd_sas_port *sas_port = dev->port;
-       struct mvs_port *port = mvi->slot_info[slot_idx].port;
-       u32 reg_set, phy_mask;
-
-       if (!sas_protocol_ata(task->task_proto)) {
-               reg_set = 0;
-               phy_mask = (port->wide_port_phymap) ? port->wide_port_phymap :
-                               sas_port->phy_mask;
-       } else {
-               reg_set = port->taskfileset;
-               phy_mask = sas_port->phy_mask;
-       }
-       mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | slot_idx |
-                                       (TXQ_CMD_SLOT_RESET << TXQ_CMD_SHIFT) |
-                                       (phy_mask << TXQ_PHY_SHIFT) |
-                                       (reg_set << TXQ_SRS_SHIFT));
-
-       mw32(TX_PROD_IDX, mvi->tx_prod);
-       mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
-}
-
-static int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task,
-                       u32 slot_idx, int err)
-{
-       struct mvs_port *port = mvi->slot_info[slot_idx].port;
-       struct task_status_struct *tstat = &task->task_status;
-       struct ata_task_resp *resp = (struct ata_task_resp *)tstat->buf;
-       int stat = SAM_GOOD;
-
-       resp->frame_len = sizeof(struct dev_to_host_fis);
-       memcpy(&resp->ending_fis[0],
-              SATA_RECEIVED_D2H_FIS(port->taskfileset),
-              sizeof(struct dev_to_host_fis));
-       tstat->buf_valid_size = sizeof(*resp);
-       if (unlikely(err))
-               stat = SAS_PROTO_RESPONSE;
-       return stat;
-}
-
-static void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc)
-{
-       u32 slot_idx = rx_desc & RXQ_SLOT_MASK;
-       mvs_tag_clear(mvi, slot_idx);
-}
-
-static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task,
-                         struct mvs_slot_info *slot, u32 slot_idx)
-{
-       if (!sas_protocol_ata(task->task_proto))
-               if (slot->n_elem)
-                       pci_unmap_sg(mvi->pdev, task->scatter,
-                                    slot->n_elem, task->data_dir);
-
-       switch (task->task_proto) {
-       case SAS_PROTOCOL_SMP:
-               pci_unmap_sg(mvi->pdev, &task->smp_task.smp_resp, 1,
-                            PCI_DMA_FROMDEVICE);
-               pci_unmap_sg(mvi->pdev, &task->smp_task.smp_req, 1,
-                            PCI_DMA_TODEVICE);
-               break;
-
-       case SAS_PROTOCOL_SATA:
-       case SAS_PROTOCOL_STP:
-       case SAS_PROTOCOL_SSP:
-       default:
-               /* do nothing */
-               break;
-       }
-       list_del(&slot->list);
-       task->lldd_task = NULL;
-       slot->task = NULL;
-       slot->port = NULL;
-}
-
-static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
-                        u32 slot_idx)
-{
-       struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
-       u32 err_dw0 = le32_to_cpu(*(u32 *) (slot->response));
-       u32 err_dw1 = le32_to_cpu(*(u32 *) (slot->response + 4));
-       int stat = SAM_CHECK_COND;
-
-       if (err_dw1 & SLOT_BSY_ERR) {
-               stat = SAS_QUEUE_FULL;
-               mvs_slot_reset(mvi, task, slot_idx);
-       }
-       switch (task->task_proto) {
-       case SAS_PROTOCOL_SSP:
-               break;
-       case SAS_PROTOCOL_SMP:
-               break;
-       case SAS_PROTOCOL_SATA:
-       case SAS_PROTOCOL_STP:
-       case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
-               if (err_dw0 & TFILE_ERR)
-                       stat = mvs_sata_done(mvi, task, slot_idx, 1);
-               break;
-       default:
-               break;
-       }
-
-       mvs_hexdump(16, (u8 *) slot->response, 0);
-       return stat;
-}
-
-static int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
-{
-       u32 slot_idx = rx_desc & RXQ_SLOT_MASK;
-       struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
-       struct sas_task *task = slot->task;
-       struct task_status_struct *tstat;
-       struct mvs_port *port;
-       bool aborted;
-       void *to;
-
-       if (unlikely(!task || !task->lldd_task))
-               return -1;
-
-       mvs_hba_cq_dump(mvi);
-
-       spin_lock(&task->task_state_lock);
-       aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED;
-       if (!aborted) {
-               task->task_state_flags &=
-                   ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
-               task->task_state_flags |= SAS_TASK_STATE_DONE;
-       }
-       spin_unlock(&task->task_state_lock);
-
-       if (aborted) {
-               mvs_slot_task_free(mvi, task, slot, slot_idx);
-               mvs_slot_free(mvi, rx_desc);
-               return -1;
-       }
-
-       port = slot->port;
-       tstat = &task->task_status;
-       memset(tstat, 0, sizeof(*tstat));
-       tstat->resp = SAS_TASK_COMPLETE;
-
-       if (unlikely(!port->port_attached || flags)) {
-               mvs_slot_err(mvi, task, slot_idx);
-               if (!sas_protocol_ata(task->task_proto))
-                       tstat->stat = SAS_PHY_DOWN;
-               goto out;
-       }
-
-       /* error info record present */
-       if (unlikely((rx_desc & RXQ_ERR) && (*(u64 *) slot->response))) {
-               tstat->stat = mvs_slot_err(mvi, task, slot_idx);
-               goto out;
-       }
-
-       switch (task->task_proto) {
-       case SAS_PROTOCOL_SSP:
-               /* hw says status == 0, datapres == 0 */
-               if (rx_desc & RXQ_GOOD) {
-                       tstat->stat = SAM_GOOD;
-                       tstat->resp = SAS_TASK_COMPLETE;
-               }
-               /* response frame present */
-               else if (rx_desc & RXQ_RSP) {
-                       struct ssp_response_iu *iu =
-                           slot->response + sizeof(struct mvs_err_info);
-                       sas_ssp_task_response(&mvi->pdev->dev, task, iu);
-               }
-
-               /* should never happen? */
-               else
-                       tstat->stat = SAM_CHECK_COND;
-               break;
-
-       case SAS_PROTOCOL_SMP: {
-                       struct scatterlist *sg_resp = &task->smp_task.smp_resp;
-                       tstat->stat = SAM_GOOD;
-                       to = kmap_atomic(sg_page(sg_resp), KM_IRQ0);
-                       memcpy(to + sg_resp->offset,
-                               slot->response + sizeof(struct mvs_err_info),
-                               sg_dma_len(sg_resp));
-                       kunmap_atomic(to, KM_IRQ0);
-                       break;
-               }
-
-       case SAS_PROTOCOL_SATA:
-       case SAS_PROTOCOL_STP:
-       case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: {
-                       tstat->stat = mvs_sata_done(mvi, task, slot_idx, 0);
-                       break;
-               }
-
-       default:
-               tstat->stat = SAM_CHECK_COND;
-               break;
-       }
-
-out:
-       mvs_slot_task_free(mvi, task, slot, slot_idx);
-       if (unlikely(tstat->stat != SAS_QUEUE_FULL))
-               mvs_slot_free(mvi, rx_desc);
-
-       spin_unlock(&mvi->lock);
-       task->task_done(task);
-       spin_lock(&mvi->lock);
-       return tstat->stat;
-}
-
-static void mvs_release_task(struct mvs_info *mvi, int phy_no)
-{
-       struct list_head *pos, *n;
-       struct mvs_slot_info *slot;
-       struct mvs_phy *phy = &mvi->phy[phy_no];
-       struct mvs_port *port = phy->port;
-       u32 rx_desc;
-
-       if (!port)
-               return;
-
-       list_for_each_safe(pos, n, &port->list) {
-               slot = container_of(pos, struct mvs_slot_info, list);
-               rx_desc = (u32) (slot - mvi->slot_info);
-               mvs_slot_complete(mvi, rx_desc, 1);
-       }
-}
-
-static void mvs_int_full(struct mvs_info *mvi)
-{
-       void __iomem *regs = mvi->regs;
-       u32 tmp, stat;
-       int i;
-
-       stat = mr32(INT_STAT);
-
-       mvs_int_rx(mvi, false);
-
-       for (i = 0; i < MVS_MAX_PORTS; i++) {
-               tmp = (stat >> i) & (CINT_PORT | CINT_PORT_STOPPED);
-               if (tmp)
-                       mvs_int_port(mvi, i, tmp);
-       }
-
-       if (stat & CINT_SRS)
-               mvs_int_sata(mvi);
-
-       mw32(INT_STAT, stat);
-}
-
-static int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
-{
-       void __iomem *regs = mvi->regs;
-       u32 rx_prod_idx, rx_desc;
-       bool attn = false;
-       struct pci_dev *pdev = mvi->pdev;
-
-       /* the first dword in the RX ring is special: it contains
-        * a mirror of the hardware's RX producer index, so that
-        * we don't have to stall the CPU reading that register.
-        * The actual RX ring is offset by one dword, due to this.
-        */
-       rx_prod_idx = mvi->rx_cons;
-       mvi->rx_cons = le32_to_cpu(mvi->rx[0]);
-       if (mvi->rx_cons == 0xfff)      /* h/w hasn't touched RX ring yet */
-               return 0;
-
-       /* The CMPL_Q may come late, read from register and try again
-       * note: if coalescing is enabled,
-       * it will need to read from register every time for sure
-       */
-       if (mvi->rx_cons == rx_prod_idx)
-               mvi->rx_cons = mr32(RX_CONS_IDX) & RX_RING_SZ_MASK;
-
-       if (mvi->rx_cons == rx_prod_idx)
-               return 0;
-
-       while (mvi->rx_cons != rx_prod_idx) {
-
-               /* increment our internal RX consumer pointer */
-               rx_prod_idx = (rx_prod_idx + 1) & (MVS_RX_RING_SZ - 1);
-
-               rx_desc = le32_to_cpu(mvi->rx[rx_prod_idx + 1]);
-
-               if (likely(rx_desc & RXQ_DONE))
-                       mvs_slot_complete(mvi, rx_desc, 0);
-               if (rx_desc & RXQ_ATTN) {
-                       attn = true;
-                       dev_printk(KERN_DEBUG, &pdev->dev, "ATTN %X\n",
-                               rx_desc);
-               } else if (rx_desc & RXQ_ERR) {
-                       if (!(rx_desc & RXQ_DONE))
-                               mvs_slot_complete(mvi, rx_desc, 0);
-                       dev_printk(KERN_DEBUG, &pdev->dev, "RXQ_ERR %X\n",
-                               rx_desc);
-               } else if (rx_desc & RXQ_SLOT_RESET) {
-                       dev_printk(KERN_DEBUG, &pdev->dev, "Slot reset[%X]\n",
-                               rx_desc);
-                       mvs_slot_free(mvi, rx_desc);
-               }
-       }
-
-       if (attn && self_clear)
-               mvs_int_full(mvi);
-
-       return 0;
-}
-
-#ifdef MVS_USE_TASKLET
-static void mvs_tasklet(unsigned long data)
-{
-       struct mvs_info *mvi = (struct mvs_info *) data;
-       unsigned long flags;
-
-       spin_lock_irqsave(&mvi->lock, flags);
-
-#ifdef MVS_DISABLE_MSI
-       mvs_int_full(mvi);
-#else
-       mvs_int_rx(mvi, true);
-#endif
-       spin_unlock_irqrestore(&mvi->lock, flags);
-}
-#endif
-
-static irqreturn_t mvs_interrupt(int irq, void *opaque)
-{
-       struct mvs_info *mvi = opaque;
-       void __iomem *regs = mvi->regs;
-       u32 stat;
-
-       stat = mr32(GBL_INT_STAT);
-
-       if (stat == 0 || stat == 0xffffffff)
-               return IRQ_NONE;
-
-       /* clear CMD_CMPLT ASAP */
-       mw32_f(INT_STAT, CINT_DONE);
-
-#ifndef MVS_USE_TASKLET
-       spin_lock(&mvi->lock);
-
-       mvs_int_full(mvi);
-
-       spin_unlock(&mvi->lock);
-#else
-       tasklet_schedule(&mvi->tasklet);
-#endif
-       return IRQ_HANDLED;
-}
-
-#ifndef MVS_DISABLE_MSI
-static irqreturn_t mvs_msi_interrupt(int irq, void *opaque)
-{
-       struct mvs_info *mvi = opaque;
-
-#ifndef MVS_USE_TASKLET
-       spin_lock(&mvi->lock);
-
-       mvs_int_rx(mvi, true);
-
-       spin_unlock(&mvi->lock);
-#else
-       tasklet_schedule(&mvi->tasklet);
-#endif
-       return IRQ_HANDLED;
-}
-#endif
-
-struct mvs_task_exec_info {
-       struct sas_task *task;
-       struct mvs_cmd_hdr *hdr;
-       struct mvs_port *port;
-       u32 tag;
-       int n_elem;
-};
-
-static int mvs_task_prep_smp(struct mvs_info *mvi,
-                            struct mvs_task_exec_info *tei)
-{
-       int elem, rc, i;
-       struct sas_task *task = tei->task;
-       struct mvs_cmd_hdr *hdr = tei->hdr;
-       struct scatterlist *sg_req, *sg_resp;
-       u32 req_len, resp_len, tag = tei->tag;
-       void *buf_tmp;
-       u8 *buf_oaf;
-       dma_addr_t buf_tmp_dma;
-       struct mvs_prd *buf_prd;
-       struct scatterlist *sg;
-       struct mvs_slot_info *slot = &mvi->slot_info[tag];
-       struct asd_sas_port *sas_port = task->dev->port;
-       u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
-#if _MV_DUMP
-       u8 *buf_cmd;
-       void *from;
-#endif
-       /*
-        * DMA-map SMP request, response buffers
-        */
-       sg_req = &task->smp_task.smp_req;
-       elem = pci_map_sg(mvi->pdev, sg_req, 1, PCI_DMA_TODEVICE);
-       if (!elem)
-               return -ENOMEM;
-       req_len = sg_dma_len(sg_req);
-
-       sg_resp = &task->smp_task.smp_resp;
-       elem = pci_map_sg(mvi->pdev, sg_resp, 1, PCI_DMA_FROMDEVICE);
-       if (!elem) {
-               rc = -ENOMEM;
-               goto err_out;
-       }
-       resp_len = sg_dma_len(sg_resp);
-
-       /* must be in dwords */
-       if ((req_len & 0x3) || (resp_len & 0x3)) {
-               rc = -EINVAL;
-               goto err_out_2;
-       }
-
-       /*
-        * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
-        */
-
-       /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */
-       buf_tmp = slot->buf;
-       buf_tmp_dma = slot->buf_dma;
-
-#if _MV_DUMP
-       buf_cmd = buf_tmp;
-       hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
-       buf_tmp += req_len;
-       buf_tmp_dma += req_len;
-       slot->cmd_size = req_len;
-#else
-       hdr->cmd_tbl = cpu_to_le64(sg_dma_address(sg_req));
-#endif
-
-       /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
-       buf_oaf = buf_tmp;
-       hdr->open_frame = cpu_to_le64(buf_tmp_dma);
-
-       buf_tmp += MVS_OAF_SZ;
-       buf_tmp_dma += MVS_OAF_SZ;
-
-       /* region 3: PRD table ********************************************* */
-       buf_prd = buf_tmp;
-       if (tei->n_elem)
-               hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
-       else
-               hdr->prd_tbl = 0;
-
-       i = sizeof(struct mvs_prd) * tei->n_elem;
-       buf_tmp += i;
-       buf_tmp_dma += i;
-
-       /* region 4: status buffer (larger the PRD, smaller this buf) ****** */
-       slot->response = buf_tmp;
-       hdr->status_buf = cpu_to_le64(buf_tmp_dma);
-
-       /*
-        * Fill in TX ring and command slot header
-        */
-       slot->tx = mvi->tx_prod;
-       mvi->tx[mvi->tx_prod] = cpu_to_le32((TXQ_CMD_SMP << TXQ_CMD_SHIFT) |
-                                       TXQ_MODE_I | tag |
-                                       (sas_port->phy_mask << TXQ_PHY_SHIFT));
-
-       hdr->flags |= flags;
-       hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | ((req_len - 4) / 4));
-       hdr->tags = cpu_to_le32(tag);
-       hdr->data_len = 0;
-
-       /* generate open address frame hdr (first 12 bytes) */
-       buf_oaf[0] = (1 << 7) | (0 << 4) | 0x01; /* initiator, SMP, ftype 1h */
-       buf_oaf[1] = task->dev->linkrate & 0xf;
-       *(u16 *)(buf_oaf + 2) = 0xFFFF;         /* SAS SPEC */
-       memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE);
-
-       /* fill in PRD (scatter/gather) table, if any */
-       for_each_sg(task->scatter, sg, tei->n_elem, i) {
-               buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
-               buf_prd->len = cpu_to_le32(sg_dma_len(sg));
-               buf_prd++;
-       }
-
-#if _MV_DUMP
-       /* copy cmd table */
-       from = kmap_atomic(sg_page(sg_req), KM_IRQ0);
-       memcpy(buf_cmd, from + sg_req->offset, req_len);
-       kunmap_atomic(from, KM_IRQ0);
-#endif
-       return 0;
-
-err_out_2:
-       pci_unmap_sg(mvi->pdev, &tei->task->smp_task.smp_resp, 1,
-                    PCI_DMA_FROMDEVICE);
-err_out:
-       pci_unmap_sg(mvi->pdev, &tei->task->smp_task.smp_req, 1,
-                    PCI_DMA_TODEVICE);
-       return rc;
-}
-
-static void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port *port)
-{
-       void __iomem *regs = mvi->regs;
-       u32 tmp, offs;
-       u8 *tfs = &port->taskfileset;
-
-       if (*tfs == MVS_ID_NOT_MAPPED)
-               return;
-
-       offs = 1U << ((*tfs & 0x0f) + PCS_EN_SATA_REG_SHIFT);
-       if (*tfs < 16) {
-               tmp = mr32(PCS);
-               mw32(PCS, tmp & ~offs);
-       } else {
-               tmp = mr32(CTL);
-               mw32(CTL, tmp & ~offs);
-       }
-
-       tmp = mr32(INT_STAT_SRS) & (1U << *tfs);
-       if (tmp)
-               mw32(INT_STAT_SRS, tmp);
-
-       *tfs = MVS_ID_NOT_MAPPED;
-}
-
-static u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port *port)
-{
-       int i;
-       u32 tmp, offs;
-       void __iomem *regs = mvi->regs;
-
-       if (port->taskfileset != MVS_ID_NOT_MAPPED)
-               return 0;
-
-       tmp = mr32(PCS);
-
-       for (i = 0; i < mvi->chip->srs_sz; i++) {
-               if (i == 16)
-                       tmp = mr32(CTL);
-               offs = 1U << ((i & 0x0f) + PCS_EN_SATA_REG_SHIFT);
-               if (!(tmp & offs)) {
-                       port->taskfileset = i;
-
-                       if (i < 16)
-                               mw32(PCS, tmp | offs);
-                       else
-                               mw32(CTL, tmp | offs);
-                       tmp = mr32(INT_STAT_SRS) & (1U << i);
-                       if (tmp)
-                               mw32(INT_STAT_SRS, tmp);
-                       return 0;
-               }
-       }
-       return MVS_ID_NOT_MAPPED;
-}
-
-static u32 mvs_get_ncq_tag(struct sas_task *task, u32 *tag)
-{
-       struct ata_queued_cmd *qc = task->uldd_task;
-
-       if (qc) {
-               if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
-                       qc->tf.command == ATA_CMD_FPDMA_READ) {
-                       *tag = qc->tag;
-                       return 1;
-               }
-       }
-
-       return 0;
-}
-
-static int mvs_task_prep_ata(struct mvs_info *mvi,
-                            struct mvs_task_exec_info *tei)
-{
-       struct sas_task *task = tei->task;
-       struct domain_device *dev = task->dev;
-       struct mvs_cmd_hdr *hdr = tei->hdr;
-       struct asd_sas_port *sas_port = dev->port;
-       struct mvs_slot_info *slot;
-       struct scatterlist *sg;
-       struct mvs_prd *buf_prd;
-       struct mvs_port *port = tei->port;
-       u32 tag = tei->tag;
-       u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
-       void *buf_tmp;
-       u8 *buf_cmd, *buf_oaf;
-       dma_addr_t buf_tmp_dma;
-       u32 i, req_len, resp_len;
-       const u32 max_resp_len = SB_RFB_MAX;
-
-       if (mvs_assign_reg_set(mvi, port) == MVS_ID_NOT_MAPPED)
-               return -EBUSY;
-
-       slot = &mvi->slot_info[tag];
-       slot->tx = mvi->tx_prod;
-       mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag |
-                                       (TXQ_CMD_STP << TXQ_CMD_SHIFT) |
-                                       (sas_port->phy_mask << TXQ_PHY_SHIFT) |
-                                       (port->taskfileset << TXQ_SRS_SHIFT));
-
-       if (task->ata_task.use_ncq)
-               flags |= MCH_FPDMA;
-       if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) {
-               if (task->ata_task.fis.command != ATA_CMD_ID_ATAPI)
-                       flags |= MCH_ATAPI;
-       }
-
-       /* FIXME: fill in port multiplier number */
-
-       hdr->flags = cpu_to_le32(flags);
-
-       /* FIXME: the low order order 5 bits for the TAG if enable NCQ */
-       if (task->ata_task.use_ncq && mvs_get_ncq_tag(task, &hdr->tags))
-               task->ata_task.fis.sector_count |= hdr->tags << 3;
-       else
-               hdr->tags = cpu_to_le32(tag);
-       hdr->data_len = cpu_to_le32(task->total_xfer_len);
-
-       /*
-        * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
-        */
-
-       /* region 1: command table area (MVS_ATA_CMD_SZ bytes) ************** */
-       buf_cmd = buf_tmp = slot->buf;
-       buf_tmp_dma = slot->buf_dma;
-
-       hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
-
-       buf_tmp += MVS_ATA_CMD_SZ;
-       buf_tmp_dma += MVS_ATA_CMD_SZ;
-#if _MV_DUMP
-       slot->cmd_size = MVS_ATA_CMD_SZ;
-#endif
-
-       /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
-       /* used for STP.  unused for SATA? */
-       buf_oaf = buf_tmp;
-       hdr->open_frame = cpu_to_le64(buf_tmp_dma);
-
-       buf_tmp += MVS_OAF_SZ;
-       buf_tmp_dma += MVS_OAF_SZ;
-
-       /* region 3: PRD table ********************************************* */
-       buf_prd = buf_tmp;
-       if (tei->n_elem)
-               hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
-       else
-               hdr->prd_tbl = 0;
-
-       i = sizeof(struct mvs_prd) * tei->n_elem;
-       buf_tmp += i;
-       buf_tmp_dma += i;
-
-       /* region 4: status buffer (larger the PRD, smaller this buf) ****** */
-       /* FIXME: probably unused, for SATA.  kept here just in case
-        * we get a STP/SATA error information record
-        */
-       slot->response = buf_tmp;
-       hdr->status_buf = cpu_to_le64(buf_tmp_dma);
-
-       req_len = sizeof(struct host_to_dev_fis);
-       resp_len = MVS_SLOT_BUF_SZ - MVS_ATA_CMD_SZ -
-           sizeof(struct mvs_err_info) - i;
-
-       /* request, response lengths */
-       resp_len = min(resp_len, max_resp_len);
-       hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
-
-       task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
-       /* fill in command FIS and ATAPI CDB */
-       memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis));
-       if (dev->sata_dev.command_set == ATAPI_COMMAND_SET)
-               memcpy(buf_cmd + STP_ATAPI_CMD,
-                       task->ata_task.atapi_packet, 16);
-
-       /* generate open address frame hdr (first 12 bytes) */
-       buf_oaf[0] = (1 << 7) | (2 << 4) | 0x1; /* initiator, STP, ftype 1h */
-       buf_oaf[1] = task->dev->linkrate & 0xf;
-       *(u16 *)(buf_oaf + 2) = cpu_to_be16(tag);
-       memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE);
-
-       /* fill in PRD (scatter/gather) table, if any */
-       for_each_sg(task->scatter, sg, tei->n_elem, i) {
-               buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
-               buf_prd->len = cpu_to_le32(sg_dma_len(sg));
-               buf_prd++;
-       }
-
-       return 0;
-}
-
-static int mvs_task_prep_ssp(struct mvs_info *mvi,
-                            struct mvs_task_exec_info *tei)
-{
-       struct sas_task *task = tei->task;
-       struct mvs_cmd_hdr *hdr = tei->hdr;
-       struct mvs_port *port = tei->port;
-       struct mvs_slot_info *slot;
-       struct scatterlist *sg;
-       struct mvs_prd *buf_prd;
-       struct ssp_frame_hdr *ssp_hdr;
-       void *buf_tmp;
-       u8 *buf_cmd, *buf_oaf, fburst = 0;
-       dma_addr_t buf_tmp_dma;
-       u32 flags;
-       u32 resp_len, req_len, i, tag = tei->tag;
-       const u32 max_resp_len = SB_RFB_MAX;
-       u8 phy_mask;
-
-       slot = &mvi->slot_info[tag];
-
-       phy_mask = (port->wide_port_phymap) ? port->wide_port_phymap :
-               task->dev->port->phy_mask;
-       slot->tx = mvi->tx_prod;
-       mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag |
-                               (TXQ_CMD_SSP << TXQ_CMD_SHIFT) |
-                               (phy_mask << TXQ_PHY_SHIFT));
-
-       flags = MCH_RETRY;
-       if (task->ssp_task.enable_first_burst) {
-               flags |= MCH_FBURST;
-               fburst = (1 << 7);
-       }
-       hdr->flags = cpu_to_le32(flags |
-                                (tei->n_elem << MCH_PRD_LEN_SHIFT) |
-                                (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT));
-
-       hdr->tags = cpu_to_le32(tag);
-       hdr->data_len = cpu_to_le32(task->total_xfer_len);
-
-       /*
-        * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
-        */
-
-       /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */
-       buf_cmd = buf_tmp = slot->buf;
-       buf_tmp_dma = slot->buf_dma;
-
-       hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
-
-       buf_tmp += MVS_SSP_CMD_SZ;
-       buf_tmp_dma += MVS_SSP_CMD_SZ;
-#if _MV_DUMP
-       slot->cmd_size = MVS_SSP_CMD_SZ;
-#endif
-
-       /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
-       buf_oaf = buf_tmp;
-       hdr->open_frame = cpu_to_le64(buf_tmp_dma);
-
-       buf_tmp += MVS_OAF_SZ;
-       buf_tmp_dma += MVS_OAF_SZ;
-
-       /* region 3: PRD table ********************************************* */
-       buf_prd = buf_tmp;
-       if (tei->n_elem)
-               hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
-       else
-               hdr->prd_tbl = 0;
-
-       i = sizeof(struct mvs_prd) * tei->n_elem;
-       buf_tmp += i;
-       buf_tmp_dma += i;
-
-       /* region 4: status buffer (larger the PRD, smaller this buf) ****** */
-       slot->response = buf_tmp;
-       hdr->status_buf = cpu_to_le64(buf_tmp_dma);
-
-       resp_len = MVS_SLOT_BUF_SZ - MVS_SSP_CMD_SZ - MVS_OAF_SZ -
-           sizeof(struct mvs_err_info) - i;
-       resp_len = min(resp_len, max_resp_len);
-
-       req_len = sizeof(struct ssp_frame_hdr) + 28;
-
-       /* request, response lengths */
-       hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
-
-       /* generate open address frame hdr (first 12 bytes) */
-       buf_oaf[0] = (1 << 7) | (1 << 4) | 0x1; /* initiator, SSP, ftype 1h */
-       buf_oaf[1] = task->dev->linkrate & 0xf;
-       *(u16 *)(buf_oaf + 2) = cpu_to_be16(tag);
-       memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE);
-
-       /* fill in SSP frame header (Command Table.SSP frame header) */
-       ssp_hdr = (struct ssp_frame_hdr *)buf_cmd;
-       ssp_hdr->frame_type = SSP_COMMAND;
-       memcpy(ssp_hdr->hashed_dest_addr, task->dev->hashed_sas_addr,
-              HASHED_SAS_ADDR_SIZE);
-       memcpy(ssp_hdr->hashed_src_addr,
-              task->dev->port->ha->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
-       ssp_hdr->tag = cpu_to_be16(tag);
-
-       /* fill in command frame IU */
-       buf_cmd += sizeof(*ssp_hdr);
-       memcpy(buf_cmd, &task->ssp_task.LUN, 8);
-       buf_cmd[9] = fburst | task->ssp_task.task_attr |
-                       (task->ssp_task.task_prio << 3);
-       memcpy(buf_cmd + 12, &task->ssp_task.cdb, 16);
-
-       /* fill in PRD (scatter/gather) table, if any */
-       for_each_sg(task->scatter, sg, tei->n_elem, i) {
-               buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
-               buf_prd->len = cpu_to_le32(sg_dma_len(sg));
-               buf_prd++;
-       }
-
-       return 0;
-}
-
-static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags)
-{
-       struct domain_device *dev = task->dev;
-       struct mvs_info *mvi = dev->port->ha->lldd_ha;
-       struct pci_dev *pdev = mvi->pdev;
-       void __iomem *regs = mvi->regs;
-       struct mvs_task_exec_info tei;
-       struct sas_task *t = task;
-       struct mvs_slot_info *slot;
-       u32 tag = 0xdeadbeef, rc, n_elem = 0;
-       unsigned long flags;
-       u32 n = num, pass = 0;
-
-       spin_lock_irqsave(&mvi->lock, flags);
-       do {
-               dev = t->dev;
-               tei.port = &mvi->port[dev->port->id];
-
-               if (!tei.port->port_attached) {
-                       if (sas_protocol_ata(t->task_proto)) {
-                               rc = SAS_PHY_DOWN;
-                               goto out_done;
-                       } else {
-                               struct task_status_struct *ts = &t->task_status;
-                               ts->resp = SAS_TASK_UNDELIVERED;
-                               ts->stat = SAS_PHY_DOWN;
-                               t->task_done(t);
-                               if (n > 1)
-                                       t = list_entry(t->list.next,
-                                                       struct sas_task, list);
-                               continue;
-                       }
-               }
-
-               if (!sas_protocol_ata(t->task_proto)) {
-                       if (t->num_scatter) {
-                               n_elem = pci_map_sg(mvi->pdev, t->scatter,
-                                                   t->num_scatter,
-                                                   t->data_dir);
-                               if (!n_elem) {
-                                       rc = -ENOMEM;
-                                       goto err_out;
-                               }
-                       }
-               } else {
-                       n_elem = t->num_scatter;
-               }
-
-               rc = mvs_tag_alloc(mvi, &tag);
-               if (rc)
-                       goto err_out;
-
-               slot = &mvi->slot_info[tag];
-               t->lldd_task = NULL;
-               slot->n_elem = n_elem;
-               memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
-               tei.task = t;
-               tei.hdr = &mvi->slot[tag];
-               tei.tag = tag;
-               tei.n_elem = n_elem;
-
-               switch (t->task_proto) {
-               case SAS_PROTOCOL_SMP:
-                       rc = mvs_task_prep_smp(mvi, &tei);
-                       break;
-               case SAS_PROTOCOL_SSP:
-                       rc = mvs_task_prep_ssp(mvi, &tei);
-                       break;
-               case SAS_PROTOCOL_SATA:
-               case SAS_PROTOCOL_STP:
-               case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
-                       rc = mvs_task_prep_ata(mvi, &tei);
-                       break;
-               default:
-                       dev_printk(KERN_ERR, &pdev->dev,
-                               "unknown sas_task proto: 0x%x\n",
-                               t->task_proto);
-                       rc = -EINVAL;
-                       break;
-               }
-
-               if (rc)
-                       goto err_out_tag;
-
-               slot->task = t;
-               slot->port = tei.port;
-               t->lldd_task = (void *) slot;
-               list_add_tail(&slot->list, &slot->port->list);
-               /* TODO: select normal or high priority */
-
-               spin_lock(&t->task_state_lock);
-               t->task_state_flags |= SAS_TASK_AT_INITIATOR;
-               spin_unlock(&t->task_state_lock);
-
-               mvs_hba_memory_dump(mvi, tag, t->task_proto);
-
-               ++pass;
-               mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
-               if (n > 1)
-                       t = list_entry(t->list.next, struct sas_task, list);
-       } while (--n);
-
-       rc = 0;
-       goto out_done;
-
-err_out_tag:
-       mvs_tag_free(mvi, tag);
-err_out:
-       dev_printk(KERN_ERR, &pdev->dev, "mvsas exec failed[%d]!\n", rc);
-       if (!sas_protocol_ata(t->task_proto))
-               if (n_elem)
-                       pci_unmap_sg(mvi->pdev, t->scatter, n_elem,
-                                    t->data_dir);
-out_done:
-       if (pass)
-               mw32(TX_PROD_IDX, (mvi->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1));
-       spin_unlock_irqrestore(&mvi->lock, flags);
-       return rc;
-}
-
-static int mvs_task_abort(struct sas_task *task)
-{
-       int rc;
-       unsigned long flags;
-       struct mvs_info *mvi = task->dev->port->ha->lldd_ha;
-       struct pci_dev *pdev = mvi->pdev;
-       int tag;
-
-       spin_lock_irqsave(&task->task_state_lock, flags);
-       if (task->task_state_flags & SAS_TASK_STATE_DONE) {
-               rc = TMF_RESP_FUNC_COMPLETE;
-               spin_unlock_irqrestore(&task->task_state_lock, flags);
-               goto out_done;
-       }
-       spin_unlock_irqrestore(&task->task_state_lock, flags);
-
-       switch (task->task_proto) {
-       case SAS_PROTOCOL_SMP:
-               dev_printk(KERN_DEBUG, &pdev->dev, "SMP Abort! \n");
-               break;
-       case SAS_PROTOCOL_SSP:
-               dev_printk(KERN_DEBUG, &pdev->dev, "SSP Abort! \n");
-               break;
-       case SAS_PROTOCOL_SATA:
-       case SAS_PROTOCOL_STP:
-       case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:{
-               dev_printk(KERN_DEBUG, &pdev->dev, "STP Abort! \n");
-#if _MV_DUMP
-               dev_printk(KERN_DEBUG, &pdev->dev, "Dump D2H FIS: \n");
-               mvs_hexdump(sizeof(struct host_to_dev_fis),
-                               (void *)&task->ata_task.fis, 0);
-               dev_printk(KERN_DEBUG, &pdev->dev, "Dump ATAPI Cmd : \n");
-               mvs_hexdump(16, task->ata_task.atapi_packet, 0);
-#endif
-               spin_lock_irqsave(&task->task_state_lock, flags);
-               if (task->task_state_flags & SAS_TASK_NEED_DEV_RESET) {
-                       /* TODO */
-                       ;
-               }
-               spin_unlock_irqrestore(&task->task_state_lock, flags);
-               break;
-       }
-       default:
-               break;
-       }
-
-       if (mvs_find_tag(mvi, task, &tag)) {
-               spin_lock_irqsave(&mvi->lock, flags);
-               mvs_slot_task_free(mvi, task, &mvi->slot_info[tag], tag);
-               spin_unlock_irqrestore(&mvi->lock, flags);
-       }
-       if (!mvs_task_exec(task, 1, GFP_ATOMIC))
-               rc = TMF_RESP_FUNC_COMPLETE;
-       else
-               rc = TMF_RESP_FUNC_FAILED;
-out_done:
-       return rc;
-}
-
-static void mvs_free(struct mvs_info *mvi)
-{
-       int i;
-
-       if (!mvi)
-               return;
-
-       for (i = 0; i < MVS_SLOTS; i++) {
-               struct mvs_slot_info *slot = &mvi->slot_info[i];
-
-               if (slot->buf)
-                       dma_free_coherent(&mvi->pdev->dev, MVS_SLOT_BUF_SZ,
-                                         slot->buf, slot->buf_dma);
-       }
-
-       if (mvi->tx)
-               dma_free_coherent(&mvi->pdev->dev,
-                                 sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ,
-                                 mvi->tx, mvi->tx_dma);
-       if (mvi->rx_fis)
-               dma_free_coherent(&mvi->pdev->dev, MVS_RX_FISL_SZ,
-                                 mvi->rx_fis, mvi->rx_fis_dma);
-       if (mvi->rx)
-               dma_free_coherent(&mvi->pdev->dev,
-                                 sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1),
-                                 mvi->rx, mvi->rx_dma);
-       if (mvi->slot)
-               dma_free_coherent(&mvi->pdev->dev,
-                                 sizeof(*mvi->slot) * MVS_SLOTS,
-                                 mvi->slot, mvi->slot_dma);
-#ifdef MVS_ENABLE_PERI
-       if (mvi->peri_regs)
-               iounmap(mvi->peri_regs);
-#endif
-       if (mvi->regs)
-               iounmap(mvi->regs);
-       if (mvi->shost)
-               scsi_host_put(mvi->shost);
-       kfree(mvi->sas.sas_port);
-       kfree(mvi->sas.sas_phy);
-       kfree(mvi);
-}
-
-/* FIXME: locking? */
-static int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
-                          void *funcdata)
-{
-       struct mvs_info *mvi = sas_phy->ha->lldd_ha;
-       int rc = 0, phy_id = sas_phy->id;
-       u32 tmp;
-
-       tmp = mvs_read_phy_ctl(mvi, phy_id);
-
-       switch (func) {
-       case PHY_FUNC_SET_LINK_RATE:{
-                       struct sas_phy_linkrates *rates = funcdata;
-                       u32 lrmin = 0, lrmax = 0;
-
-                       lrmin = (rates->minimum_linkrate << 8);
-                       lrmax = (rates->maximum_linkrate << 12);
-
-                       if (lrmin) {
-                               tmp &= ~(0xf << 8);
-                               tmp |= lrmin;
-                       }
-                       if (lrmax) {
-                               tmp &= ~(0xf << 12);
-                               tmp |= lrmax;
-                       }
-                       mvs_write_phy_ctl(mvi, phy_id, tmp);
-                       break;
-               }
-
-       case PHY_FUNC_HARD_RESET:
-               if (tmp & PHY_RST_HARD)
-                       break;
-               mvs_write_phy_ctl(mvi, phy_id, tmp | PHY_RST_HARD);
-               break;
-
-       case PHY_FUNC_LINK_RESET:
-               mvs_write_phy_ctl(mvi, phy_id, tmp | PHY_RST);
-               break;
-
-       case PHY_FUNC_DISABLE:
-       case PHY_FUNC_RELEASE_SPINUP_HOLD:
-       default:
-               rc = -EOPNOTSUPP;
-       }
-
-       return rc;
-}
-
-static void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id)
-{
-       struct mvs_phy *phy = &mvi->phy[phy_id];
-       struct asd_sas_phy *sas_phy = &phy->sas_phy;
-
-       sas_phy->enabled = (phy_id < mvi->chip->n_phy) ? 1 : 0;
-       sas_phy->class = SAS;
-       sas_phy->iproto = SAS_PROTOCOL_ALL;
-       sas_phy->tproto = 0;
-       sas_phy->type = PHY_TYPE_PHYSICAL;
-       sas_phy->role = PHY_ROLE_INITIATOR;
-       sas_phy->oob_mode = OOB_NOT_CONNECTED;
-       sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN;
-
-       sas_phy->id = phy_id;
-       sas_phy->sas_addr = &mvi->sas_addr[0];
-       sas_phy->frame_rcvd = &phy->frame_rcvd[0];
-       sas_phy->ha = &mvi->sas;
-       sas_phy->lldd_phy = phy;
-}
-
-static struct mvs_info *__devinit mvs_alloc(struct pci_dev *pdev,
-                                           const struct pci_device_id *ent)
-{
-       struct mvs_info *mvi;
-       unsigned long res_start, res_len, res_flag;
-       struct asd_sas_phy **arr_phy;
-       struct asd_sas_port **arr_port;
-       const struct mvs_chip_info *chip = &mvs_chips[ent->driver_data];
-       int i;
-
-       /*
-        * alloc and init our per-HBA mvs_info struct
-        */
-
-       mvi = kzalloc(sizeof(*mvi), GFP_KERNEL);
-       if (!mvi)
-               return NULL;
-
-       spin_lock_init(&mvi->lock);
-#ifdef MVS_USE_TASKLET
-       tasklet_init(&mvi->tasklet, mvs_tasklet, (unsigned long)mvi);
-#endif
-       mvi->pdev = pdev;
-       mvi->chip = chip;
-
-       if (pdev->device == 0x6440 && pdev->revision == 0)
-               mvi->flags |= MVF_PHY_PWR_FIX;
-
-       /*
-        * alloc and init SCSI, SAS glue
-        */
-
-       mvi->shost = scsi_host_alloc(&mvs_sht, sizeof(void *));
-       if (!mvi->shost)
-               goto err_out;
-
-       arr_phy = kcalloc(MVS_MAX_PHYS, sizeof(void *), GFP_KERNEL);
-       arr_port = kcalloc(MVS_MAX_PHYS, sizeof(void *), GFP_KERNEL);
-       if (!arr_phy || !arr_port)
-               goto err_out;
-
-       for (i = 0; i < MVS_MAX_PHYS; i++) {
-               mvs_phy_init(mvi, i);
-               arr_phy[i] = &mvi->phy[i].sas_phy;
-               arr_port[i] = &mvi->port[i].sas_port;
-               mvi->port[i].taskfileset = MVS_ID_NOT_MAPPED;
-               mvi->port[i].wide_port_phymap = 0;
-               mvi->port[i].port_attached = 0;
-               INIT_LIST_HEAD(&mvi->port[i].list);
-       }
-
-       SHOST_TO_SAS_HA(mvi->shost) = &mvi->sas;
-       mvi->shost->transportt = mvs_stt;
-       mvi->shost->max_id = 21;
-       mvi->shost->max_lun = ~0;
-       mvi->shost->max_channel = 0;
-       mvi->shost->max_cmd_len = 16;
-
-       mvi->sas.sas_ha_name = DRV_NAME;
-       mvi->sas.dev = &pdev->dev;
-       mvi->sas.lldd_module = THIS_MODULE;
-       mvi->sas.sas_addr = &mvi->sas_addr[0];
-       mvi->sas.sas_phy = arr_phy;
-       mvi->sas.sas_port = arr_port;
-       mvi->sas.num_phys = chip->n_phy;
-       mvi->sas.lldd_max_execute_num = 1;
-       mvi->sas.lldd_queue_size = MVS_QUEUE_SIZE;
-       mvi->shost->can_queue = MVS_CAN_QUEUE;
-       mvi->shost->cmd_per_lun = MVS_SLOTS / mvi->sas.num_phys;
-       mvi->sas.lldd_ha = mvi;
-       mvi->sas.core.shost = mvi->shost;
-
-       mvs_tag_init(mvi);
-
-       /*
-        * ioremap main and peripheral registers
-        */
-
-#ifdef MVS_ENABLE_PERI
-       res_start = pci_resource_start(pdev, 2);
-       res_len = pci_resource_len(pdev, 2);
-       if (!res_start || !res_len)
-               goto err_out;
-
-       mvi->peri_regs = ioremap_nocache(res_start, res_len);
-       if (!mvi->peri_regs)
-               goto err_out;
-#endif
-
-       res_start = pci_resource_start(pdev, 4);
-       res_len = pci_resource_len(pdev, 4);
-       if (!res_start || !res_len)
-               goto err_out;
-
-       res_flag = pci_resource_flags(pdev, 4);
-       if (res_flag & IORESOURCE_CACHEABLE)
-               mvi->regs = ioremap(res_start, res_len);
-       else
-               mvi->regs = ioremap_nocache(res_start, res_len);
-
-       if (!mvi->regs)
-               goto err_out;
-
-       /*
-        * alloc and init our DMA areas
-        */
-
-       mvi->tx = dma_alloc_coherent(&pdev->dev,
-                                    sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ,
-                                    &mvi->tx_dma, GFP_KERNEL);
-       if (!mvi->tx)
-               goto err_out;
-       memset(mvi->tx, 0, sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ);
-
-       mvi->rx_fis = dma_alloc_coherent(&pdev->dev, MVS_RX_FISL_SZ,
-                                        &mvi->rx_fis_dma, GFP_KERNEL);
-       if (!mvi->rx_fis)
-               goto err_out;
-       memset(mvi->rx_fis, 0, MVS_RX_FISL_SZ);
-
-       mvi->rx = dma_alloc_coherent(&pdev->dev,
-                                    sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1),
-                                    &mvi->rx_dma, GFP_KERNEL);
-       if (!mvi->rx)
-               goto err_out;
-       memset(mvi->rx, 0, sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1));
-
-       mvi->rx[0] = cpu_to_le32(0xfff);
-       mvi->rx_cons = 0xfff;
-
-       mvi->slot = dma_alloc_coherent(&pdev->dev,
-                                      sizeof(*mvi->slot) * MVS_SLOTS,
-                                      &mvi->slot_dma, GFP_KERNEL);
-       if (!mvi->slot)
-               goto err_out;
-       memset(mvi->slot, 0, sizeof(*mvi->slot) * MVS_SLOTS);
-
-       for (i = 0; i < MVS_SLOTS; i++) {
-               struct mvs_slot_info *slot = &mvi->slot_info[i];
-
-               slot->buf = dma_alloc_coherent(&pdev->dev, MVS_SLOT_BUF_SZ,
-                                              &slot->buf_dma, GFP_KERNEL);
-               if (!slot->buf)
-                       goto err_out;
-               memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
-       }
-
-       /* finally, read NVRAM to get our SAS address */
-       if (mvs_nvram_read(mvi, NVR_SAS_ADDR, &mvi->sas_addr, 8))
-               goto err_out;
-       return mvi;
-
-err_out:
-       mvs_free(mvi);
-       return NULL;
-}
-
-static u32 mvs_cr32(void __iomem *regs, u32 addr)
-{
-       mw32(CMD_ADDR, addr);
-       return mr32(CMD_DATA);
-}
-
-static void mvs_cw32(void __iomem *regs, u32 addr, u32 val)
-{
-       mw32(CMD_ADDR, addr);
-       mw32(CMD_DATA, val);
-}
-
-static u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port)
-{
-       void __iomem *regs = mvi->regs;
-       return (port < 4)?mr32(P0_SER_CTLSTAT + port * 4):
-               mr32(P4_SER_CTLSTAT + (port - 4) * 4);
-}
-
-static void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val)
-{
-       void __iomem *regs = mvi->regs;
-       if (port < 4)
-               mw32(P0_SER_CTLSTAT + port * 4, val);
-       else
-               mw32(P4_SER_CTLSTAT + (port - 4) * 4, val);
-}
-
-static u32 mvs_read_port(struct mvs_info *mvi, u32 off, u32 off2, u32 port)
-{
-       void __iomem *regs = mvi->regs + off;
-       void __iomem *regs2 = mvi->regs + off2;
-       return (port < 4)?readl(regs + port * 8):
-               readl(regs2 + (port - 4) * 8);
-}
-
-static void mvs_write_port(struct mvs_info *mvi, u32 off, u32 off2,
-                               u32 port, u32 val)
-{
-       void __iomem *regs = mvi->regs + off;
-       void __iomem *regs2 = mvi->regs + off2;
-       if (port < 4)
-               writel(val, regs + port * 8);
-       else
-               writel(val, regs2 + (port - 4) * 8);
-}
-
-static u32 mvs_read_port_cfg_data(struct mvs_info *mvi, u32 port)
-{
-       return mvs_read_port(mvi, MVS_P0_CFG_DATA, MVS_P4_CFG_DATA, port);
-}
-
-static void mvs_write_port_cfg_data(struct mvs_info *mvi, u32 port, u32 val)
-{
-       mvs_write_port(mvi, MVS_P0_CFG_DATA, MVS_P4_CFG_DATA, port, val);
-}
-
-static void mvs_write_port_cfg_addr(struct mvs_info *mvi, u32 port, u32 addr)
-{
-       mvs_write_port(mvi, MVS_P0_CFG_ADDR, MVS_P4_CFG_ADDR, port, addr);
-}
-
-static u32 mvs_read_port_vsr_data(struct mvs_info *mvi, u32 port)
-{
-       return mvs_read_port(mvi, MVS_P0_VSR_DATA, MVS_P4_VSR_DATA, port);
-}
-
-static void mvs_write_port_vsr_data(struct mvs_info *mvi, u32 port, u32 val)
-{
-       mvs_write_port(mvi, MVS_P0_VSR_DATA, MVS_P4_VSR_DATA, port, val);
-}
-
-static void mvs_write_port_vsr_addr(struct mvs_info *mvi, u32 port, u32 addr)
-{
-       mvs_write_port(mvi, MVS_P0_VSR_ADDR, MVS_P4_VSR_ADDR, port, addr);
-}
-
-static u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port)
-{
-       return mvs_read_port(mvi, MVS_P0_INT_STAT, MVS_P4_INT_STAT, port);
-}
-
-static void mvs_write_port_irq_stat(struct mvs_info *mvi, u32 port, u32 val)
-{
-       mvs_write_port(mvi, MVS_P0_INT_STAT, MVS_P4_INT_STAT, port, val);
-}
-
-static u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port)
-{
-       return mvs_read_port(mvi, MVS_P0_INT_MASK, MVS_P4_INT_MASK, port);
-}
-
-static void mvs_write_port_irq_mask(struct mvs_info *mvi, u32 port, u32 val)
-{
-       mvs_write_port(mvi, MVS_P0_INT_MASK, MVS_P4_INT_MASK, port, val);
-}
-
-static void __devinit mvs_phy_hacks(struct mvs_info *mvi)
-{
-       void __iomem *regs = mvi->regs;
-       u32 tmp;
-
-       /* workaround for SATA R-ERR, to ignore phy glitch */
-       tmp = mvs_cr32(regs, CMD_PHY_TIMER);
-       tmp &= ~(1 << 9);
-       tmp |= (1 << 10);
-       mvs_cw32(regs, CMD_PHY_TIMER, tmp);
-
-       /* enable retry 127 times */
-       mvs_cw32(regs, CMD_SAS_CTL1, 0x7f7f);
-
-       /* extend open frame timeout to max */
-       tmp = mvs_cr32(regs, CMD_SAS_CTL0);
-       tmp &= ~0xffff;
-       tmp |= 0x3fff;
-       mvs_cw32(regs, CMD_SAS_CTL0, tmp);
-
-       /* workaround for WDTIMEOUT , set to 550 ms */
-       mvs_cw32(regs, CMD_WD_TIMER, 0x86470);
-
-       /* not to halt for different port op during wideport link change */
-       mvs_cw32(regs, CMD_APP_ERR_CONFIG, 0xffefbf7d);
-
-       /* workaround for Seagate disk not-found OOB sequence, recv
-        * COMINIT before sending out COMWAKE */
-       tmp = mvs_cr32(regs, CMD_PHY_MODE_21);
-       tmp &= 0x0000ffff;
-       tmp |= 0x00fa0000;
-       mvs_cw32(regs, CMD_PHY_MODE_21, tmp);
-
-       tmp = mvs_cr32(regs, CMD_PHY_TIMER);
-       tmp &= 0x1fffffff;
-       tmp |= (2U << 29);      /* 8 ms retry */
-       mvs_cw32(regs, CMD_PHY_TIMER, tmp);
-
-       /* TEST - for phy decoding error, adjust voltage levels */
-       mw32(P0_VSR_ADDR + 0, 0x8);
-       mw32(P0_VSR_DATA + 0, 0x2F0);
-
-       mw32(P0_VSR_ADDR + 8, 0x8);
-       mw32(P0_VSR_DATA + 8, 0x2F0);
-
-       mw32(P0_VSR_ADDR + 16, 0x8);
-       mw32(P0_VSR_DATA + 16, 0x2F0);
-
-       mw32(P0_VSR_ADDR + 24, 0x8);
-       mw32(P0_VSR_DATA + 24, 0x2F0);
-
-}
-
-static void mvs_enable_xmt(struct mvs_info *mvi, int PhyId)
-{
-       void __iomem *regs = mvi->regs;
-       u32 tmp;
-
-       tmp = mr32(PCS);
-       if (mvi->chip->n_phy <= 4)
-               tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT);
-       else
-               tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT2);
-       mw32(PCS, tmp);
-}
-
-static void mvs_detect_porttype(struct mvs_info *mvi, int i)
-{
-       void __iomem *regs = mvi->regs;
-       u32 reg;
-       struct mvs_phy *phy = &mvi->phy[i];
-
-       /* TODO check & save device type */
-       reg = mr32(GBL_PORT_TYPE);
-
-       if (reg & MODE_SAS_SATA & (1 << i))
-               phy->phy_type |= PORT_TYPE_SAS;
-       else
-               phy->phy_type |= PORT_TYPE_SATA;
-}
-
-static void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf)
-{
-       u32 *s = (u32 *) buf;
-
-       if (!s)
-               return NULL;
-
-       mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG3);
-       s[3] = mvs_read_port_cfg_data(mvi, i);
-
-       mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG2);
-       s[2] = mvs_read_port_cfg_data(mvi, i);
-
-       mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG1);
-       s[1] = mvs_read_port_cfg_data(mvi, i);
-
-       mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0);
-       s[0] = mvs_read_port_cfg_data(mvi, i);
-
-       return (void *)s;
-}
-
-static u32 mvs_is_sig_fis_received(u32 irq_status)
-{
-       return irq_status & PHYEV_SIG_FIS;
-}
-
-static void mvs_update_wideport(struct mvs_info *mvi, int i)
-{
-       struct mvs_phy *phy = &mvi->phy[i];
-       struct mvs_port *port = phy->port;
-       int j, no;
-
-       for_each_phy(port->wide_port_phymap, no, j, mvi->chip->n_phy)
-               if (no & 1) {
-                       mvs_write_port_cfg_addr(mvi, no, PHYR_WIDE_PORT);
-                       mvs_write_port_cfg_data(mvi, no,
-                                               port->wide_port_phymap);
-               } else {
-                       mvs_write_port_cfg_addr(mvi, no, PHYR_WIDE_PORT);
-                       mvs_write_port_cfg_data(mvi, no, 0);
-               }
-}
-
-static u32 mvs_is_phy_ready(struct mvs_info *mvi, int i)
-{
-       u32 tmp;
-       struct mvs_phy *phy = &mvi->phy[i];
-       struct mvs_port *port = phy->port;;
-
-       tmp = mvs_read_phy_ctl(mvi, i);
-
-       if ((tmp & PHY_READY_MASK) && !(phy->irq_status & PHYEV_POOF)) {
-               if (!port)
-                       phy->phy_attached = 1;
-               return tmp;
-       }
-
-       if (port) {
-               if (phy->phy_type & PORT_TYPE_SAS) {
-                       port->wide_port_phymap &= ~(1U << i);
-                       if (!port->wide_port_phymap)
-                               port->port_attached = 0;
-                       mvs_update_wideport(mvi, i);
-               } else if (phy->phy_type & PORT_TYPE_SATA)
-                       port->port_attached = 0;
-               mvs_free_reg_set(mvi, phy->port);
-               phy->port = NULL;
-               phy->phy_attached = 0;
-               phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
-       }
-       return 0;
-}
-
-static void mvs_update_phyinfo(struct mvs_info *mvi, int i,
-                                       int get_st)
-{
-       struct mvs_phy *phy = &mvi->phy[i];
-       struct pci_dev *pdev = mvi->pdev;
-       u32 tmp;
-       u64 tmp64;
-
-       mvs_write_port_cfg_addr(mvi, i, PHYR_IDENTIFY);
-       phy->dev_info = mvs_read_port_cfg_data(mvi, i);
-
-       mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_HI);
-       phy->dev_sas_addr = (u64) mvs_read_port_cfg_data(mvi, i) << 32;
-
-       mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_LO);
-       phy->dev_sas_addr |= mvs_read_port_cfg_data(mvi, i);
-
-       if (get_st) {
-               phy->irq_status = mvs_read_port_irq_stat(mvi, i);
-               phy->phy_status = mvs_is_phy_ready(mvi, i);
-       }
-
-       if (phy->phy_status) {
-               u32 phy_st;
-               struct asd_sas_phy *sas_phy = mvi->sas.sas_phy[i];
-
-               mvs_write_port_cfg_addr(mvi, i, PHYR_PHY_STAT);
-               phy_st = mvs_read_port_cfg_data(mvi, i);
-
-               sas_phy->linkrate =
-                       (phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
-                               PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET;
-               phy->minimum_linkrate =
-                       (phy->phy_status &
-                               PHY_MIN_SPP_PHYS_LINK_RATE_MASK) >> 8;
-               phy->maximum_linkrate =
-                       (phy->phy_status &
-                               PHY_MAX_SPP_PHYS_LINK_RATE_MASK) >> 12;
-
-               if (phy->phy_type & PORT_TYPE_SAS) {
-                       /* Updated attached_sas_addr */
-                       mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_HI);
-                       phy->att_dev_sas_addr =
-                               (u64) mvs_read_port_cfg_data(mvi, i) << 32;
-                       mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_LO);
-                       phy->att_dev_sas_addr |= mvs_read_port_cfg_data(mvi, i);
-                       mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_DEV_INFO);
-                       phy->att_dev_info = mvs_read_port_cfg_data(mvi, i);
-                       phy->identify.device_type =
-                           phy->att_dev_info & PORT_DEV_TYPE_MASK;
-
-                       if (phy->identify.device_type == SAS_END_DEV)
-                               phy->identify.target_port_protocols =
-                                                       SAS_PROTOCOL_SSP;
-                       else if (phy->identify.device_type != NO_DEVICE)
-                               phy->identify.target_port_protocols =
-                                                       SAS_PROTOCOL_SMP;
-                       if (phy_st & PHY_OOB_DTCTD)
-                               sas_phy->oob_mode = SAS_OOB_MODE;
-                       phy->frame_rcvd_size =
-                           sizeof(struct sas_identify_frame);
-               } else if (phy->phy_type & PORT_TYPE_SATA) {
-                       phy->identify.target_port_protocols = SAS_PROTOCOL_STP;
-                       if (mvs_is_sig_fis_received(phy->irq_status)) {
-                               phy->att_dev_sas_addr = i;      /* temp */
-                               if (phy_st & PHY_OOB_DTCTD)
-                                       sas_phy->oob_mode = SATA_OOB_MODE;
-                               phy->frame_rcvd_size =
-                                   sizeof(struct dev_to_host_fis);
-                               mvs_get_d2h_reg(mvi, i,
-                                               (void *)sas_phy->frame_rcvd);
-                       } else {
-                               dev_printk(KERN_DEBUG, &pdev->dev,
-                                       "No sig fis\n");
-                               phy->phy_type &= ~(PORT_TYPE_SATA);
-                               goto out_done;
-                       }
-               }
-               tmp64 = cpu_to_be64(phy->att_dev_sas_addr);
-               memcpy(sas_phy->attached_sas_addr, &tmp64, SAS_ADDR_SIZE);
-
-               dev_printk(KERN_DEBUG, &pdev->dev,
-                       "phy[%d] Get Attached Address 0x%llX ,"
-                       " SAS Address 0x%llX\n",
-                       i,
-                       (unsigned long long)phy->att_dev_sas_addr,
-                       (unsigned long long)phy->dev_sas_addr);
-               dev_printk(KERN_DEBUG, &pdev->dev,
-                       "Rate = %x , type = %d\n",
-                       sas_phy->linkrate, phy->phy_type);
-
-               /* workaround for HW phy decoding error on 1.5g disk drive */
-               mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE6);
-               tmp = mvs_read_port_vsr_data(mvi, i);
-               if (((phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
-                    PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET) ==
-                       SAS_LINK_RATE_1_5_GBPS)
-                       tmp &= ~PHY_MODE6_LATECLK;
-               else
-                       tmp |= PHY_MODE6_LATECLK;
-               mvs_write_port_vsr_data(mvi, i, tmp);
-
-       }
-out_done:
-       if (get_st)
-               mvs_write_port_irq_stat(mvi, i, phy->irq_status);
-}
-
-static void mvs_port_formed(struct asd_sas_phy *sas_phy)
-{
-       struct sas_ha_struct *sas_ha = sas_phy->ha;
-       struct mvs_info *mvi = sas_ha->lldd_ha;
-       struct asd_sas_port *sas_port = sas_phy->port;
-       struct mvs_phy *phy = sas_phy->lldd_phy;
-       struct mvs_port *port = &mvi->port[sas_port->id];
-       unsigned long flags;
-
-       spin_lock_irqsave(&mvi->lock, flags);
-       port->port_attached = 1;
-       phy->port = port;
-       port->taskfileset = MVS_ID_NOT_MAPPED;
-       if (phy->phy_type & PORT_TYPE_SAS) {
-               port->wide_port_phymap = sas_port->phy_mask;
-               mvs_update_wideport(mvi, sas_phy->id);
-       }
-       spin_unlock_irqrestore(&mvi->lock, flags);
-}
-
-static int mvs_I_T_nexus_reset(struct domain_device *dev)
-{
-       return TMF_RESP_FUNC_FAILED;
-}
-
-static int __devinit mvs_hw_init(struct mvs_info *mvi)
-{
-       void __iomem *regs = mvi->regs;
-       int i;
-       u32 tmp, cctl;
-
-       /* make sure interrupts are masked immediately (paranoia) */
-       mw32(GBL_CTL, 0);
-       tmp = mr32(GBL_CTL);
-
-       /* Reset Controller */
-       if (!(tmp & HBA_RST)) {
-               if (mvi->flags & MVF_PHY_PWR_FIX) {
-                       pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp);
-                       tmp &= ~PCTL_PWR_ON;
-                       tmp |= PCTL_OFF;
-                       pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp);
-
-                       pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp);
-                       tmp &= ~PCTL_PWR_ON;
-                       tmp |= PCTL_OFF;
-                       pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp);
-               }
-
-               /* global reset, incl. COMRESET/H_RESET_N (self-clearing) */
-               mw32_f(GBL_CTL, HBA_RST);
-       }
-
-       /* wait for reset to finish; timeout is just a guess */
-       i = 1000;
-       while (i-- > 0) {
-               msleep(10);
-
-               if (!(mr32(GBL_CTL) & HBA_RST))
-                       break;
-       }
-       if (mr32(GBL_CTL) & HBA_RST) {
-               dev_printk(KERN_ERR, &mvi->pdev->dev, "HBA reset failed\n");
-               return -EBUSY;
-       }
-
-       /* Init Chip */
-       /* make sure RST is set; HBA_RST /should/ have done that for us */
-       cctl = mr32(CTL);
-       if (cctl & CCTL_RST)
-               cctl &= ~CCTL_RST;
-       else
-               mw32_f(CTL, cctl | CCTL_RST);
-
-       /* write to device control _AND_ device status register? - A.C. */
-       pci_read_config_dword(mvi->pdev, PCR_DEV_CTRL, &tmp);
-       tmp &= ~PRD_REQ_MASK;
-       tmp |= PRD_REQ_SIZE;
-       pci_write_config_dword(mvi->pdev, PCR_DEV_CTRL, tmp);
-
-       pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp);
-       tmp |= PCTL_PWR_ON;
-       tmp &= ~PCTL_OFF;
-       pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp);
-
-       pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp);
-       tmp |= PCTL_PWR_ON;
-       tmp &= ~PCTL_OFF;
-       pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp);
-
-       mw32_f(CTL, cctl);
-
-       /* reset control */
-       mw32(PCS, 0);           /*MVS_PCS */
-
-       mvs_phy_hacks(mvi);
-
-       mw32(CMD_LIST_LO, mvi->slot_dma);
-       mw32(CMD_LIST_HI, (mvi->slot_dma >> 16) >> 16);
-
-       mw32(RX_FIS_LO, mvi->rx_fis_dma);
-       mw32(RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16);
-
-       mw32(TX_CFG, MVS_CHIP_SLOT_SZ);
-       mw32(TX_LO, mvi->tx_dma);
-       mw32(TX_HI, (mvi->tx_dma >> 16) >> 16);
-
-       mw32(RX_CFG, MVS_RX_RING_SZ);
-       mw32(RX_LO, mvi->rx_dma);
-       mw32(RX_HI, (mvi->rx_dma >> 16) >> 16);
-
-       /* enable auto port detection */
-       mw32(GBL_PORT_TYPE, MODE_AUTO_DET_EN);
-       msleep(1100);
-       /* init and reset phys */
-       for (i = 0; i < mvi->chip->n_phy; i++) {
-               u32 lo = be32_to_cpu(*(u32 *)&mvi->sas_addr[4]);
-               u32 hi = be32_to_cpu(*(u32 *)&mvi->sas_addr[0]);
-
-               mvs_detect_porttype(mvi, i);
-
-               /* set phy local SAS address */
-               mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_LO);
-               mvs_write_port_cfg_data(mvi, i, lo);
-               mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_HI);
-               mvs_write_port_cfg_data(mvi, i, hi);
-
-               /* reset phy */
-               tmp = mvs_read_phy_ctl(mvi, i);
-               tmp |= PHY_RST;
-               mvs_write_phy_ctl(mvi, i, tmp);
-       }
-
-       msleep(100);
-
-       for (i = 0; i < mvi->chip->n_phy; i++) {
-               /* clear phy int status */
-               tmp = mvs_read_port_irq_stat(mvi, i);
-               tmp &= ~PHYEV_SIG_FIS;
-               mvs_write_port_irq_stat(mvi, i, tmp);
-
-               /* set phy int mask */
-               tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH | PHYEV_UNASSOC_FIS |
-                       PHYEV_ID_DONE | PHYEV_DEC_ERR;
-               mvs_write_port_irq_mask(mvi, i, tmp);
-
-               msleep(100);
-               mvs_update_phyinfo(mvi, i, 1);
-               mvs_enable_xmt(mvi, i);
-       }
-
-       /* FIXME: update wide port bitmaps */
-
-       /* little endian for open address and command table, etc. */
-       /* A.C.
-        * it seems that ( from the spec ) turning on big-endian won't
-        * do us any good on big-endian machines, need further confirmation
-        */
-       cctl = mr32(CTL);
-       cctl |= CCTL_ENDIAN_CMD;
-       cctl |= CCTL_ENDIAN_DATA;
-       cctl &= ~CCTL_ENDIAN_OPEN;
-       cctl |= CCTL_ENDIAN_RSP;
-       mw32_f(CTL, cctl);
-
-       /* reset CMD queue */
-       tmp = mr32(PCS);
-       tmp |= PCS_CMD_RST;
-       mw32(PCS, tmp);
-       /* interrupt coalescing may cause missing HW interrput in some case,
-        * and the max count is 0x1ff, while our max slot is 0x200,
-        * it will make count 0.
-        */
-       tmp = 0;
-       mw32(INT_COAL, tmp);
-
-       tmp = 0x100;
-       mw32(INT_COAL_TMOUT, tmp);
-
-       /* ladies and gentlemen, start your engines */
-       mw32(TX_CFG, 0);
-       mw32(TX_CFG, MVS_CHIP_SLOT_SZ | TX_EN);
-       mw32(RX_CFG, MVS_RX_RING_SZ | RX_EN);
-       /* enable CMD/CMPL_Q/RESP mode */
-       mw32(PCS, PCS_SATA_RETRY | PCS_FIS_RX_EN | PCS_CMD_EN);
-
-       /* enable completion queue interrupt */
-       tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM | CINT_SRS);
-       mw32(INT_MASK, tmp);
-
-       /* Enable SRS interrupt */
-       mw32(INT_MASK_SRS, 0xFF);
-       return 0;
-}
-
-static void __devinit mvs_print_info(struct mvs_info *mvi)
-{
-       struct pci_dev *pdev = mvi->pdev;
-       static int printed_version;
-
-       if (!printed_version++)
-               dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
-
-       dev_printk(KERN_INFO, &pdev->dev, "%u phys, addr %llx\n",
-                  mvi->chip->n_phy, SAS_ADDR(mvi->sas_addr));
-}
-
-static int __devinit mvs_pci_init(struct pci_dev *pdev,
-                                 const struct pci_device_id *ent)
-{
-       int rc;
-       struct mvs_info *mvi;
-       irq_handler_t irq_handler = mvs_interrupt;
-
-       rc = pci_enable_device(pdev);
-       if (rc)
-               return rc;
-
-       pci_set_master(pdev);
-
-       rc = pci_request_regions(pdev, DRV_NAME);
-       if (rc)
-               goto err_out_disable;
-
-       rc = pci_go_64(pdev);
-       if (rc)
-               goto err_out_regions;
-
-       mvi = mvs_alloc(pdev, ent);
-       if (!mvi) {
-               rc = -ENOMEM;
-               goto err_out_regions;
-       }
-
-       rc = mvs_hw_init(mvi);
-       if (rc)
-               goto err_out_mvi;
-
-#ifndef MVS_DISABLE_MSI
-       if (!pci_enable_msi(pdev)) {
-               u32 tmp;
-               void __iomem *regs = mvi->regs;
-               mvi->flags |= MVF_MSI;
-               irq_handler = mvs_msi_interrupt;
-               tmp = mr32(PCS);
-               mw32(PCS, tmp | PCS_SELF_CLEAR);
-       }
-#endif
-
-       rc = request_irq(pdev->irq, irq_handler, IRQF_SHARED, DRV_NAME, mvi);
-       if (rc)
-               goto err_out_msi;
-
-       rc = scsi_add_host(mvi->shost, &pdev->dev);
-       if (rc)
-               goto err_out_irq;
-
-       rc = sas_register_ha(&mvi->sas);
-       if (rc)
-               goto err_out_shost;
-
-       pci_set_drvdata(pdev, mvi);
-
-       mvs_print_info(mvi);
-
-       mvs_hba_interrupt_enable(mvi);
-
-       scsi_scan_host(mvi->shost);
-
-       return 0;
-
-err_out_shost:
-       scsi_remove_host(mvi->shost);
-err_out_irq:
-       free_irq(pdev->irq, mvi);
-err_out_msi:
-       if (mvi->flags |= MVF_MSI)
-               pci_disable_msi(pdev);
-err_out_mvi:
-       mvs_free(mvi);
-err_out_regions:
-       pci_release_regions(pdev);
-err_out_disable:
-       pci_disable_device(pdev);
-       return rc;
-}
-
-static void __devexit mvs_pci_remove(struct pci_dev *pdev)
-{
-       struct mvs_info *mvi = pci_get_drvdata(pdev);
-
-       pci_set_drvdata(pdev, NULL);
-
-       if (mvi) {
-               sas_unregister_ha(&mvi->sas);
-               mvs_hba_interrupt_disable(mvi);
-               sas_remove_host(mvi->shost);
-               scsi_remove_host(mvi->shost);
-
-               free_irq(pdev->irq, mvi);
-               if (mvi->flags & MVF_MSI)
-                       pci_disable_msi(pdev);
-               mvs_free(mvi);
-               pci_release_regions(pdev);
-       }
-       pci_disable_device(pdev);
-}
-
-static struct sas_domain_function_template mvs_transport_ops = {
-       .lldd_execute_task      = mvs_task_exec,
-       .lldd_control_phy       = mvs_phy_control,
-       .lldd_abort_task        = mvs_task_abort,
-       .lldd_port_formed       = mvs_port_formed,
-       .lldd_I_T_nexus_reset   = mvs_I_T_nexus_reset,
-};
-
-static struct pci_device_id __devinitdata mvs_pci_table[] = {
-       { PCI_VDEVICE(MARVELL, 0x6320), chip_6320 },
-       { PCI_VDEVICE(MARVELL, 0x6340), chip_6440 },
-       {
-               .vendor         = PCI_VENDOR_ID_MARVELL,
-               .device         = 0x6440,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = 0x6480,
-               .class          = 0,
-               .class_mask     = 0,
-               .driver_data    = chip_6480,
-       },
-       { PCI_VDEVICE(MARVELL, 0x6440), chip_6440 },
-       { PCI_VDEVICE(MARVELL, 0x6480), chip_6480 },
-
-       { }     /* terminate list */
-};
-
-static struct pci_driver mvs_pci_driver = {
-       .name           = DRV_NAME,
-       .id_table       = mvs_pci_table,
-       .probe          = mvs_pci_init,
-       .remove         = __devexit_p(mvs_pci_remove),
-};
-
-static int __init mvs_init(void)
-{
-       int rc;
-
-       mvs_stt = sas_domain_attach_transport(&mvs_transport_ops);
-       if (!mvs_stt)
-               return -ENOMEM;
-
-       rc = pci_register_driver(&mvs_pci_driver);
-       if (rc)
-               goto err_out;
-
-       return 0;
-
-err_out:
-       sas_release_transport(mvs_stt);
-       return rc;
-}
-
-static void __exit mvs_exit(void)
-{
-       pci_unregister_driver(&mvs_pci_driver);
-       sas_release_transport(mvs_stt);
-}
-
-module_init(mvs_init);
-module_exit(mvs_exit);
-
-MODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>");
-MODULE_DESCRIPTION("Marvell 88SE6440 SAS/SATA controller driver");
-MODULE_VERSION(DRV_VERSION);
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(pci, mvs_pci_table);
diff --git a/drivers/scsi/mvsas/Kconfig b/drivers/scsi/mvsas/Kconfig
new file mode 100644 (file)
index 0000000..6de7af2
--- /dev/null
@@ -0,0 +1,42 @@
+#
+# Kernel configuration file for 88SE64XX/88SE94XX SAS/SATA driver.
+#
+# Copyright 2007 Red Hat, Inc.
+# Copyright 2008 Marvell. <kewei@marvell.com>
+#
+# This file is licensed under GPLv2.
+#
+# This file is part of the 88SE64XX/88SE94XX driver.
+#
+# The 88SE64XX/88SE94XX driver is free software; you can redistribute
+# it and/or modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; version 2 of the
+# License.
+#
+# The 88SE64XX/88SE94XX 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 88SE64XX/88SE94XX Driver; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+#
+#
+
+config SCSI_MVSAS
+       tristate "Marvell 88SE64XX/88SE94XX SAS/SATA support"
+       depends on PCI
+       select SCSI_SAS_LIBSAS
+       select FW_LOADER
+       help
+               This driver supports Marvell's SAS/SATA 3Gb/s PCI-E 88SE64XX and 6Gb/s
+               PCI-E 88SE94XX chip based host adapters.
+
+config SCSI_MVSAS_DEBUG
+       bool "Compile in debug mode"
+       default y
+       depends on SCSI_MVSAS
+       help
+               Compiles the 88SE64XX/88SE94XX driver in debug mode.  In debug mode,
+               the driver prints some messages to the console.
diff --git a/drivers/scsi/mvsas/Makefile b/drivers/scsi/mvsas/Makefile
new file mode 100644 (file)
index 0000000..52ac426
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# Makefile for Marvell 88SE64xx/88SE84xx SAS/SATA driver.
+#
+# Copyright 2007 Red Hat, Inc.
+# Copyright 2008 Marvell. <kewei@marvell.com>
+#
+# This file is licensed under GPLv2.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+
+ifeq ($(CONFIG_SCSI_MVSAS_DEBUG),y)
+       EXTRA_CFLAGS += -DMV_DEBUG
+endif
+
+obj-$(CONFIG_SCSI_MVSAS) += mvsas.o
+mvsas-y +=  mv_init.o  \
+           mv_sas.o   \
+           mv_64xx.o  \
+           mv_94xx.o
diff --git a/drivers/scsi/mvsas/mv_64xx.c b/drivers/scsi/mvsas/mv_64xx.c
new file mode 100644 (file)
index 0000000..10a5077
--- /dev/null
@@ -0,0 +1,793 @@
+/*
+ * Marvell 88SE64xx hardware specific
+ *
+ * Copyright 2007 Red Hat, Inc.
+ * Copyright 2008 Marvell. <kewei@marvell.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+*/
+
+#include "mv_sas.h"
+#include "mv_64xx.h"
+#include "mv_chips.h"
+
+static void mvs_64xx_detect_porttype(struct mvs_info *mvi, int i)
+{
+       void __iomem *regs = mvi->regs;
+       u32 reg;
+       struct mvs_phy *phy = &mvi->phy[i];
+
+       /* TODO check & save device type */
+       reg = mr32(MVS_GBL_PORT_TYPE);
+       phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
+       if (reg & MODE_SAS_SATA & (1 << i))
+               phy->phy_type |= PORT_TYPE_SAS;
+       else
+               phy->phy_type |= PORT_TYPE_SATA;
+}
+
+static void __devinit mvs_64xx_enable_xmt(struct mvs_info *mvi, int phy_id)
+{
+       void __iomem *regs = mvi->regs;
+       u32 tmp;
+
+       tmp = mr32(MVS_PCS);
+       if (mvi->chip->n_phy <= 4)
+               tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT);
+       else
+               tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT2);
+       mw32(MVS_PCS, tmp);
+}
+
+static void __devinit mvs_64xx_phy_hacks(struct mvs_info *mvi)
+{
+       void __iomem *regs = mvi->regs;
+
+       mvs_phy_hacks(mvi);
+
+       if (!(mvi->flags & MVF_FLAG_SOC)) {
+               /* TEST - for phy decoding error, adjust voltage levels */
+               mw32(MVS_P0_VSR_ADDR + 0, 0x8);
+               mw32(MVS_P0_VSR_DATA + 0, 0x2F0);
+
+               mw32(MVS_P0_VSR_ADDR + 8, 0x8);
+               mw32(MVS_P0_VSR_DATA + 8, 0x2F0);
+
+               mw32(MVS_P0_VSR_ADDR + 16, 0x8);
+               mw32(MVS_P0_VSR_DATA + 16, 0x2F0);
+
+               mw32(MVS_P0_VSR_ADDR + 24, 0x8);
+               mw32(MVS_P0_VSR_DATA + 24, 0x2F0);
+       } else {
+               int i;
+               /* disable auto port detection */
+               mw32(MVS_GBL_PORT_TYPE, 0);
+               for (i = 0; i < mvi->chip->n_phy; i++) {
+                       mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE7);
+                       mvs_write_port_vsr_data(mvi, i, 0x90000000);
+                       mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE9);
+                       mvs_write_port_vsr_data(mvi, i, 0x50f2);
+                       mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE11);
+                       mvs_write_port_vsr_data(mvi, i, 0x0e);
+               }
+       }
+}
+
+static void mvs_64xx_stp_reset(struct mvs_info *mvi, u32 phy_id)
+{
+       void __iomem *regs = mvi->regs;
+       u32 reg, tmp;
+
+       if (!(mvi->flags & MVF_FLAG_SOC)) {
+               if (phy_id < 4)
+                       pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &reg);
+               else
+                       pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &reg);
+
+       } else
+               reg = mr32(MVS_PHY_CTL);
+
+       tmp = reg;
+       if (phy_id < 4)
+               tmp |= (1U << phy_id) << PCTL_LINK_OFFS;
+       else
+               tmp |= (1U << (phy_id - 4)) << PCTL_LINK_OFFS;
+
+       if (!(mvi->flags & MVF_FLAG_SOC)) {
+               if (phy_id < 4) {
+                       pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp);
+                       mdelay(10);
+                       pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, reg);
+               } else {
+                       pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp);
+                       mdelay(10);
+                       pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, reg);
+               }
+       } else {
+               mw32(MVS_PHY_CTL, tmp);
+               mdelay(10);
+               mw32(MVS_PHY_CTL, reg);
+       }
+}
+
+static void mvs_64xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard)
+{
+       u32 tmp;
+       tmp = mvs_read_port_irq_stat(mvi, phy_id);
+       tmp &= ~PHYEV_RDY_CH;
+       mvs_write_port_irq_stat(mvi, phy_id, tmp);
+       tmp = mvs_read_phy_ctl(mvi, phy_id);
+       if (hard)
+               tmp |= PHY_RST_HARD;
+       else
+               tmp |= PHY_RST;
+       mvs_write_phy_ctl(mvi, phy_id, tmp);
+       if (hard) {
+               do {
+                       tmp = mvs_read_phy_ctl(mvi, phy_id);
+               } while (tmp & PHY_RST_HARD);
+       }
+}
+
+static int __devinit mvs_64xx_chip_reset(struct mvs_info *mvi)
+{
+       void __iomem *regs = mvi->regs;
+       u32 tmp;
+       int i;
+
+       /* make sure interrupts are masked immediately (paranoia) */
+       mw32(MVS_GBL_CTL, 0);
+       tmp = mr32(MVS_GBL_CTL);
+
+       /* Reset Controller */
+       if (!(tmp & HBA_RST)) {
+               if (mvi->flags & MVF_PHY_PWR_FIX) {
+                       pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp);
+                       tmp &= ~PCTL_PWR_OFF;
+                       tmp |= PCTL_PHY_DSBL;
+                       pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp);
+
+                       pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp);
+                       tmp &= ~PCTL_PWR_OFF;
+                       tmp |= PCTL_PHY_DSBL;
+                       pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp);
+               }
+       }
+
+       /* make sure interrupts are masked immediately (paranoia) */
+       mw32(MVS_GBL_CTL, 0);
+       tmp = mr32(MVS_GBL_CTL);
+
+       /* Reset Controller */
+       if (!(tmp & HBA_RST)) {
+               /* global reset, incl. COMRESET/H_RESET_N (self-clearing) */
+               mw32_f(MVS_GBL_CTL, HBA_RST);
+       }
+
+       /* wait for reset to finish; timeout is just a guess */
+       i = 1000;
+       while (i-- > 0) {
+               msleep(10);
+
+               if (!(mr32(MVS_GBL_CTL) & HBA_RST))
+                       break;
+       }
+       if (mr32(MVS_GBL_CTL) & HBA_RST) {
+               dev_printk(KERN_ERR, mvi->dev, "HBA reset failed\n");
+               return -EBUSY;
+       }
+       return 0;
+}
+
+static void mvs_64xx_phy_disable(struct mvs_info *mvi, u32 phy_id)
+{
+       void __iomem *regs = mvi->regs;
+       u32 tmp;
+       if (!(mvi->flags & MVF_FLAG_SOC)) {
+               u32 offs;
+               if (phy_id < 4)
+                       offs = PCR_PHY_CTL;
+               else {
+                       offs = PCR_PHY_CTL2;
+                       phy_id -= 4;
+               }
+               pci_read_config_dword(mvi->pdev, offs, &tmp);
+               tmp |= 1U << (PCTL_PHY_DSBL_OFFS + phy_id);
+               pci_write_config_dword(mvi->pdev, offs, tmp);
+       } else {
+               tmp = mr32(MVS_PHY_CTL);
+               tmp |= 1U << (PCTL_PHY_DSBL_OFFS + phy_id);
+               mw32(MVS_PHY_CTL, tmp);
+       }
+}
+
+static void mvs_64xx_phy_enable(struct mvs_info *mvi, u32 phy_id)
+{
+       void __iomem *regs = mvi->regs;
+       u32 tmp;
+       if (!(mvi->flags & MVF_FLAG_SOC)) {
+               u32 offs;
+               if (phy_id < 4)
+                       offs = PCR_PHY_CTL;
+               else {
+                       offs = PCR_PHY_CTL2;
+                       phy_id -= 4;
+               }
+               pci_read_config_dword(mvi->pdev, offs, &tmp);
+               tmp &= ~(1U << (PCTL_PHY_DSBL_OFFS + phy_id));
+               pci_write_config_dword(mvi->pdev, offs, tmp);
+       } else {
+               tmp = mr32(MVS_PHY_CTL);
+               tmp &= ~(1U << (PCTL_PHY_DSBL_OFFS + phy_id));
+               mw32(MVS_PHY_CTL, tmp);
+       }
+}
+
+static int __devinit mvs_64xx_init(struct mvs_info *mvi)
+{
+       void __iomem *regs = mvi->regs;
+       int i;
+       u32 tmp, cctl;
+
+       if (mvi->pdev && mvi->pdev->revision == 0)
+               mvi->flags |= MVF_PHY_PWR_FIX;
+       if (!(mvi->flags & MVF_FLAG_SOC)) {
+               mvs_show_pcie_usage(mvi);
+               tmp = mvs_64xx_chip_reset(mvi);
+               if (tmp)
+                       return tmp;
+       } else {
+               tmp = mr32(MVS_PHY_CTL);
+               tmp &= ~PCTL_PWR_OFF;
+               tmp |= PCTL_PHY_DSBL;
+               mw32(MVS_PHY_CTL, tmp);
+       }
+
+       /* Init Chip */
+       /* make sure RST is set; HBA_RST /should/ have done that for us */
+       cctl = mr32(MVS_CTL) & 0xFFFF;
+       if (cctl & CCTL_RST)
+               cctl &= ~CCTL_RST;
+       else
+               mw32_f(MVS_CTL, cctl | CCTL_RST);
+
+       if (!(mvi->flags & MVF_FLAG_SOC)) {
+               /* write to device control _AND_ device status register */
+               pci_read_config_dword(mvi->pdev, PCR_DEV_CTRL, &tmp);
+               tmp &= ~PRD_REQ_MASK;
+               tmp |= PRD_REQ_SIZE;
+               pci_write_config_dword(mvi->pdev, PCR_DEV_CTRL, tmp);
+
+               pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp);
+               tmp &= ~PCTL_PWR_OFF;
+               tmp &= ~PCTL_PHY_DSBL;
+               pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp);
+
+               pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp);
+               tmp &= PCTL_PWR_OFF;
+               tmp &= ~PCTL_PHY_DSBL;
+               pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp);
+       } else {
+               tmp = mr32(MVS_PHY_CTL);
+               tmp &= ~PCTL_PWR_OFF;
+               tmp |= PCTL_COM_ON;
+               tmp &= ~PCTL_PHY_DSBL;
+               tmp |= PCTL_LINK_RST;
+               mw32(MVS_PHY_CTL, tmp);
+               msleep(100);
+               tmp &= ~PCTL_LINK_RST;
+               mw32(MVS_PHY_CTL, tmp);
+               msleep(100);
+       }
+
+       /* reset control */
+       mw32(MVS_PCS, 0);               /* MVS_PCS */
+       /* init phys */
+       mvs_64xx_phy_hacks(mvi);
+
+       /* enable auto port detection */
+       mw32(MVS_GBL_PORT_TYPE, MODE_AUTO_DET_EN);
+
+       mw32(MVS_CMD_LIST_LO, mvi->slot_dma);
+       mw32(MVS_CMD_LIST_HI, (mvi->slot_dma >> 16) >> 16);
+
+       mw32(MVS_RX_FIS_LO, mvi->rx_fis_dma);
+       mw32(MVS_RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16);
+
+       mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ);
+       mw32(MVS_TX_LO, mvi->tx_dma);
+       mw32(MVS_TX_HI, (mvi->tx_dma >> 16) >> 16);
+
+       mw32(MVS_RX_CFG, MVS_RX_RING_SZ);
+       mw32(MVS_RX_LO, mvi->rx_dma);
+       mw32(MVS_RX_HI, (mvi->rx_dma >> 16) >> 16);
+
+       for (i = 0; i < mvi->chip->n_phy; i++) {
+               /* set phy local SAS address */
+               /* should set little endian SAS address to 64xx chip */
+               mvs_set_sas_addr(mvi, i, PHYR_ADDR_LO, PHYR_ADDR_HI,
+                               cpu_to_be64(mvi->phy[i].dev_sas_addr));
+
+               mvs_64xx_enable_xmt(mvi, i);
+
+               mvs_64xx_phy_reset(mvi, i, 1);
+               msleep(500);
+               mvs_64xx_detect_porttype(mvi, i);
+       }
+       if (mvi->flags & MVF_FLAG_SOC) {
+               /* set select registers */
+               writel(0x0E008000, regs + 0x000);
+               writel(0x59000008, regs + 0x004);
+               writel(0x20, regs + 0x008);
+               writel(0x20, regs + 0x00c);
+               writel(0x20, regs + 0x010);
+               writel(0x20, regs + 0x014);
+               writel(0x20, regs + 0x018);
+               writel(0x20, regs + 0x01c);
+       }
+       for (i = 0; i < mvi->chip->n_phy; i++) {
+               /* clear phy int status */
+               tmp = mvs_read_port_irq_stat(mvi, i);
+               tmp &= ~PHYEV_SIG_FIS;
+               mvs_write_port_irq_stat(mvi, i, tmp);
+
+               /* set phy int mask */
+               tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH | PHYEV_UNASSOC_FIS |
+                       PHYEV_ID_DONE | PHYEV_DCDR_ERR | PHYEV_CRC_ERR |
+                       PHYEV_DEC_ERR;
+               mvs_write_port_irq_mask(mvi, i, tmp);
+
+               msleep(100);
+               mvs_update_phyinfo(mvi, i, 1);
+       }
+
+       /* FIXME: update wide port bitmaps */
+
+       /* little endian for open address and command table, etc. */
+       /*
+        * it seems that ( from the spec ) turning on big-endian won't
+        * do us any good on big-endian machines, need further confirmation
+        */
+       cctl = mr32(MVS_CTL);
+       cctl |= CCTL_ENDIAN_CMD;
+       cctl |= CCTL_ENDIAN_DATA;
+       cctl &= ~CCTL_ENDIAN_OPEN;
+       cctl |= CCTL_ENDIAN_RSP;
+       mw32_f(MVS_CTL, cctl);
+
+       /* reset CMD queue */
+       tmp = mr32(MVS_PCS);
+       tmp |= PCS_CMD_RST;
+       mw32(MVS_PCS, tmp);
+       /* interrupt coalescing may cause missing HW interrput in some case,
+        * and the max count is 0x1ff, while our max slot is 0x200,
+        * it will make count 0.
+        */
+       tmp = 0;
+       mw32(MVS_INT_COAL, tmp);
+
+       tmp = 0x100;
+       mw32(MVS_INT_COAL_TMOUT, tmp);
+
+       /* ladies and gentlemen, start your engines */
+       mw32(MVS_TX_CFG, 0);
+       mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ | TX_EN);
+       mw32(MVS_RX_CFG, MVS_RX_RING_SZ | RX_EN);
+       /* enable CMD/CMPL_Q/RESP mode */
+       mw32(MVS_PCS, PCS_SATA_RETRY | PCS_FIS_RX_EN |
+               PCS_CMD_EN | PCS_CMD_STOP_ERR);
+
+       /* enable completion queue interrupt */
+       tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM | CINT_SRS | CINT_CI_STOP |
+               CINT_DMA_PCIE);
+
+       mw32(MVS_INT_MASK, tmp);
+
+       /* Enable SRS interrupt */
+       mw32(MVS_INT_MASK_SRS_0, 0xFFFF);
+
+       return 0;
+}
+
+static int mvs_64xx_ioremap(struct mvs_info *mvi)
+{
+       if (!mvs_ioremap(mvi, 4, 2))
+               return 0;
+       return -1;
+}
+
+static void mvs_64xx_iounmap(struct mvs_info *mvi)
+{
+       mvs_iounmap(mvi->regs);
+       mvs_iounmap(mvi->regs_ex);
+}
+
+static void mvs_64xx_interrupt_enable(struct mvs_info *mvi)
+{
+       void __iomem *regs = mvi->regs;
+       u32 tmp;
+
+       tmp = mr32(MVS_GBL_CTL);
+       mw32(MVS_GBL_CTL, tmp | INT_EN);
+}
+
+static void mvs_64xx_interrupt_disable(struct mvs_info *mvi)
+{
+       void __iomem *regs = mvi->regs;
+       u32 tmp;
+
+       tmp = mr32(MVS_GBL_CTL);
+       mw32(MVS_GBL_CTL, tmp & ~INT_EN);
+}
+
+static u32 mvs_64xx_isr_status(struct mvs_info *mvi, int irq)
+{
+       void __iomem *regs = mvi->regs;
+       u32 stat;
+
+       if (!(mvi->flags & MVF_FLAG_SOC)) {
+               stat = mr32(MVS_GBL_INT_STAT);
+
+               if (stat == 0 || stat == 0xffffffff)
+                       return 0;
+       } else
+               stat = 1;
+       return stat;
+}
+
+static irqreturn_t mvs_64xx_isr(struct mvs_info *mvi, int irq, u32 stat)
+{
+       void __iomem *regs = mvi->regs;
+
+       /* clear CMD_CMPLT ASAP */
+       mw32_f(MVS_INT_STAT, CINT_DONE);
+#ifndef MVS_USE_TASKLET
+       spin_lock(&mvi->lock);
+#endif
+       mvs_int_full(mvi);
+#ifndef MVS_USE_TASKLET
+       spin_unlock(&mvi->lock);
+#endif
+       return IRQ_HANDLED;
+}
+
+static void mvs_64xx_command_active(struct mvs_info *mvi, u32 slot_idx)
+{
+       u32 tmp;
+       mvs_cw32(mvi, 0x40 + (slot_idx >> 3), 1 << (slot_idx % 32));
+       mvs_cw32(mvi, 0x00 + (slot_idx >> 3), 1 << (slot_idx % 32));
+       do {
+               tmp = mvs_cr32(mvi, 0x00 + (slot_idx >> 3));
+       } while (tmp & 1 << (slot_idx % 32));
+       do {
+               tmp = mvs_cr32(mvi, 0x40 + (slot_idx >> 3));
+       } while (tmp & 1 << (slot_idx % 32));
+}
+
+static void mvs_64xx_issue_stop(struct mvs_info *mvi, enum mvs_port_type type,
+                               u32 tfs)
+{
+       void __iomem *regs = mvi->regs;
+       u32 tmp;
+
+       if (type == PORT_TYPE_SATA) {
+               tmp = mr32(MVS_INT_STAT_SRS_0) | (1U << tfs);
+               mw32(MVS_INT_STAT_SRS_0, tmp);
+       }
+       mw32(MVS_INT_STAT, CINT_CI_STOP);
+       tmp = mr32(MVS_PCS) | 0xFF00;
+       mw32(MVS_PCS, tmp);
+}
+
+static void mvs_64xx_free_reg_set(struct mvs_info *mvi, u8 *tfs)
+{
+       void __iomem *regs = mvi->regs;
+       u32 tmp, offs;
+
+       if (*tfs == MVS_ID_NOT_MAPPED)
+               return;
+
+       offs = 1U << ((*tfs & 0x0f) + PCS_EN_SATA_REG_SHIFT);
+       if (*tfs < 16) {
+               tmp = mr32(MVS_PCS);
+               mw32(MVS_PCS, tmp & ~offs);
+       } else {
+               tmp = mr32(MVS_CTL);
+               mw32(MVS_CTL, tmp & ~offs);
+       }
+
+       tmp = mr32(MVS_INT_STAT_SRS_0) & (1U << *tfs);
+       if (tmp)
+               mw32(MVS_INT_STAT_SRS_0, tmp);
+
+       *tfs = MVS_ID_NOT_MAPPED;
+       return;
+}
+
+static u8 mvs_64xx_assign_reg_set(struct mvs_info *mvi, u8 *tfs)
+{
+       int i;
+       u32 tmp, offs;
+       void __iomem *regs = mvi->regs;
+
+       if (*tfs != MVS_ID_NOT_MAPPED)
+               return 0;
+
+       tmp = mr32(MVS_PCS);
+
+       for (i = 0; i < mvi->chip->srs_sz; i++) {
+               if (i == 16)
+                       tmp = mr32(MVS_CTL);
+               offs = 1U << ((i & 0x0f) + PCS_EN_SATA_REG_SHIFT);
+               if (!(tmp & offs)) {
+                       *tfs = i;
+
+                       if (i < 16)
+                               mw32(MVS_PCS, tmp | offs);
+                       else
+                               mw32(MVS_CTL, tmp | offs);
+                       tmp = mr32(MVS_INT_STAT_SRS_0) & (1U << i);
+                       if (tmp)
+                               mw32(MVS_INT_STAT_SRS_0, tmp);
+                       return 0;
+               }
+       }
+       return MVS_ID_NOT_MAPPED;
+}
+
+void mvs_64xx_make_prd(struct scatterlist *scatter, int nr, void *prd)
+{
+       int i;
+       struct scatterlist *sg;
+       struct mvs_prd *buf_prd = prd;
+       for_each_sg(scatter, sg, nr, i) {
+               buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
+               buf_prd->len = cpu_to_le32(sg_dma_len(sg));
+               buf_prd++;
+       }
+}
+
+static int mvs_64xx_oob_done(struct mvs_info *mvi, int i)
+{
+       u32 phy_st;
+       mvs_write_port_cfg_addr(mvi, i,
+                       PHYR_PHY_STAT);
+       phy_st = mvs_read_port_cfg_data(mvi, i);
+       if (phy_st & PHY_OOB_DTCTD)
+               return 1;
+       return 0;
+}
+
+static void mvs_64xx_fix_phy_info(struct mvs_info *mvi, int i,
+                               struct sas_identify_frame *id)
+
+{
+       struct mvs_phy *phy = &mvi->phy[i];
+       struct asd_sas_phy *sas_phy = &phy->sas_phy;
+
+       sas_phy->linkrate =
+               (phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
+                       PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET;
+
+       phy->minimum_linkrate =
+               (phy->phy_status &
+                       PHY_MIN_SPP_PHYS_LINK_RATE_MASK) >> 8;
+       phy->maximum_linkrate =
+               (phy->phy_status &
+                       PHY_MAX_SPP_PHYS_LINK_RATE_MASK) >> 12;
+
+       mvs_write_port_cfg_addr(mvi, i, PHYR_IDENTIFY);
+       phy->dev_info = mvs_read_port_cfg_data(mvi, i);
+
+       mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_DEV_INFO);
+       phy->att_dev_info = mvs_read_port_cfg_data(mvi, i);
+
+       mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_HI);
+       phy->att_dev_sas_addr =
+            (u64) mvs_read_port_cfg_data(mvi, i) << 32;
+       mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_LO);
+       phy->att_dev_sas_addr |= mvs_read_port_cfg_data(mvi, i);
+       phy->att_dev_sas_addr = SAS_ADDR(&phy->att_dev_sas_addr);
+}
+
+static void mvs_64xx_phy_work_around(struct mvs_info *mvi, int i)
+{
+       u32 tmp;
+       struct mvs_phy *phy = &mvi->phy[i];
+       /* workaround for HW phy decoding error on 1.5g disk drive */
+       mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE6);
+       tmp = mvs_read_port_vsr_data(mvi, i);
+       if (((phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
+            PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET) ==
+               SAS_LINK_RATE_1_5_GBPS)
+               tmp &= ~PHY_MODE6_LATECLK;
+       else
+               tmp |= PHY_MODE6_LATECLK;
+       mvs_write_port_vsr_data(mvi, i, tmp);
+}
+
+void mvs_64xx_phy_set_link_rate(struct mvs_info *mvi, u32 phy_id,
+                       struct sas_phy_linkrates *rates)
+{
+       u32 lrmin = 0, lrmax = 0;
+       u32 tmp;
+
+       tmp = mvs_read_phy_ctl(mvi, phy_id);
+       lrmin = (rates->minimum_linkrate << 8);
+       lrmax = (rates->maximum_linkrate << 12);
+
+       if (lrmin) {
+               tmp &= ~(0xf << 8);
+               tmp |= lrmin;
+       }
+       if (lrmax) {
+               tmp &= ~(0xf << 12);
+               tmp |= lrmax;
+       }
+       mvs_write_phy_ctl(mvi, phy_id, tmp);
+       mvs_64xx_phy_reset(mvi, phy_id, 1);
+}
+
+static void mvs_64xx_clear_active_cmds(struct mvs_info *mvi)
+{
+       u32 tmp;
+       void __iomem *regs = mvi->regs;
+       tmp = mr32(MVS_PCS);
+       mw32(MVS_PCS, tmp & 0xFFFF);
+       mw32(MVS_PCS, tmp);
+       tmp = mr32(MVS_CTL);
+       mw32(MVS_CTL, tmp & 0xFFFF);
+       mw32(MVS_CTL, tmp);
+}
+
+
+u32 mvs_64xx_spi_read_data(struct mvs_info *mvi)
+{
+       void __iomem *regs = mvi->regs_ex;
+       return ior32(SPI_DATA_REG_64XX);
+}
+
+void mvs_64xx_spi_write_data(struct mvs_info *mvi, u32 data)
+{
+       void __iomem *regs = mvi->regs_ex;
+        iow32(SPI_DATA_REG_64XX, data);
+}
+
+
+int mvs_64xx_spi_buildcmd(struct mvs_info *mvi,
+                       u32      *dwCmd,
+                       u8       cmd,
+                       u8       read,
+                       u8       length,
+                       u32      addr
+                       )
+{
+       u32  dwTmp;
+
+       dwTmp = ((u32)cmd << 24) | ((u32)length << 19);
+       if (read)
+               dwTmp |= 1U<<23;
+
+       if (addr != MV_MAX_U32) {
+               dwTmp |= 1U<<22;
+               dwTmp |= (addr & 0x0003FFFF);
+       }
+
+       *dwCmd = dwTmp;
+       return 0;
+}
+
+
+int mvs_64xx_spi_issuecmd(struct mvs_info *mvi, u32 cmd)
+{
+       void __iomem *regs = mvi->regs_ex;
+       int     retry;
+
+       for (retry = 0; retry < 1; retry++) {
+               iow32(SPI_CTRL_REG_64XX, SPI_CTRL_VENDOR_ENABLE);
+               iow32(SPI_CMD_REG_64XX, cmd);
+               iow32(SPI_CTRL_REG_64XX,
+                       SPI_CTRL_VENDOR_ENABLE | SPI_CTRL_SPISTART);
+       }
+
+       return 0;
+}
+
+int mvs_64xx_spi_waitdataready(struct mvs_info *mvi, u32 timeout)
+{
+       void __iomem *regs = mvi->regs_ex;
+       u32 i, dwTmp;
+
+       for (i = 0; i < timeout; i++) {
+               dwTmp = ior32(SPI_CTRL_REG_64XX);
+               if (!(dwTmp & SPI_CTRL_SPISTART))
+                       return 0;
+               msleep(10);
+       }
+
+       return -1;
+}
+
+#ifndef DISABLE_HOTPLUG_DMA_FIX
+void mvs_64xx_fix_dma(dma_addr_t buf_dma, int buf_len, int from, void *prd)
+{
+       int i;
+       struct mvs_prd *buf_prd = prd;
+       buf_prd += from;
+       for (i = 0; i < MAX_SG_ENTRY - from; i++) {
+               buf_prd->addr = cpu_to_le64(buf_dma);
+               buf_prd->len = cpu_to_le32(buf_len);
+               ++buf_prd;
+       }
+}
+#endif
+
+const struct mvs_dispatch mvs_64xx_dispatch = {
+       "mv64xx",
+       mvs_64xx_init,
+       NULL,
+       mvs_64xx_ioremap,
+       mvs_64xx_iounmap,
+       mvs_64xx_isr,
+       mvs_64xx_isr_status,
+       mvs_64xx_interrupt_enable,
+       mvs_64xx_interrupt_disable,
+       mvs_read_phy_ctl,
+       mvs_write_phy_ctl,
+       mvs_read_port_cfg_data,
+       mvs_write_port_cfg_data,
+       mvs_write_port_cfg_addr,
+       mvs_read_port_vsr_data,
+       mvs_write_port_vsr_data,
+       mvs_write_port_vsr_addr,
+       mvs_read_port_irq_stat,
+       mvs_write_port_irq_stat,
+       mvs_read_port_irq_mask,
+       mvs_write_port_irq_mask,
+       mvs_get_sas_addr,
+       mvs_64xx_command_active,
+       mvs_64xx_issue_stop,
+       mvs_start_delivery,
+       mvs_rx_update,
+       mvs_int_full,
+       mvs_64xx_assign_reg_set,
+       mvs_64xx_free_reg_set,
+       mvs_get_prd_size,
+       mvs_get_prd_count,
+       mvs_64xx_make_prd,
+       mvs_64xx_detect_porttype,
+       mvs_64xx_oob_done,
+       mvs_64xx_fix_phy_info,
+       mvs_64xx_phy_work_around,
+       mvs_64xx_phy_set_link_rate,
+       mvs_hw_max_link_rate,
+       mvs_64xx_phy_disable,
+       mvs_64xx_phy_enable,
+       mvs_64xx_phy_reset,
+       mvs_64xx_stp_reset,
+       mvs_64xx_clear_active_cmds,
+       mvs_64xx_spi_read_data,
+       mvs_64xx_spi_write_data,
+       mvs_64xx_spi_buildcmd,
+       mvs_64xx_spi_issuecmd,
+       mvs_64xx_spi_waitdataready,
+#ifndef DISABLE_HOTPLUG_DMA_FIX
+       mvs_64xx_fix_dma,
+#endif
+};
+
diff --git a/drivers/scsi/mvsas/mv_64xx.h b/drivers/scsi/mvsas/mv_64xx.h
new file mode 100644 (file)
index 0000000..42e947d
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Marvell 88SE64xx hardware specific head file
+ *
+ * Copyright 2007 Red Hat, Inc.
+ * Copyright 2008 Marvell. <kewei@marvell.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+*/
+
+#ifndef _MVS64XX_REG_H_
+#define _MVS64XX_REG_H_
+
+#include <linux/types.h>
+
+#define MAX_LINK_RATE          SAS_LINK_RATE_3_0_GBPS
+
+/* enhanced mode registers (BAR4) */
+enum hw_registers {
+       MVS_GBL_CTL             = 0x04,  /* global control */
+       MVS_GBL_INT_STAT        = 0x08,  /* global irq status */
+       MVS_GBL_PI              = 0x0C,  /* ports implemented bitmask */
+
+       MVS_PHY_CTL             = 0x40,  /* SOC PHY Control */
+       MVS_PORTS_IMP           = 0x9C,  /* SOC Port Implemented */
+
+       MVS_GBL_PORT_TYPE       = 0xa0,  /* port type */
+
+       MVS_CTL                 = 0x100, /* SAS/SATA port configuration */
+       MVS_PCS                 = 0x104, /* SAS/SATA port control/status */
+       MVS_CMD_LIST_LO         = 0x108, /* cmd list addr */
+       MVS_CMD_LIST_HI         = 0x10C,
+       MVS_RX_FIS_LO           = 0x110, /* RX FIS list addr */
+       MVS_RX_FIS_HI           = 0x114,
+
+       MVS_TX_CFG              = 0x120, /* TX configuration */
+       MVS_TX_LO               = 0x124, /* TX (delivery) ring addr */
+       MVS_TX_HI               = 0x128,
+
+       MVS_TX_PROD_IDX         = 0x12C, /* TX producer pointer */
+       MVS_TX_CONS_IDX         = 0x130, /* TX consumer pointer (RO) */
+       MVS_RX_CFG              = 0x134, /* RX configuration */
+       MVS_RX_LO               = 0x138, /* RX (completion) ring addr */
+       MVS_RX_HI               = 0x13C,
+       MVS_RX_CONS_IDX         = 0x140, /* RX consumer pointer (RO) */
+
+       MVS_INT_COAL            = 0x148, /* Int coalescing config */
+       MVS_INT_COAL_TMOUT      = 0x14C, /* Int coalescing timeout */
+       MVS_INT_STAT            = 0x150, /* Central int status */
+       MVS_INT_MASK            = 0x154, /* Central int enable */
+       MVS_INT_STAT_SRS_0      = 0x158, /* SATA register set status */
+       MVS_INT_MASK_SRS_0      = 0x15C,
+
+                                        /* ports 1-3 follow after this */
+       MVS_P0_INT_STAT         = 0x160, /* port0 interrupt status */
+       MVS_P0_INT_MASK         = 0x164, /* port0 interrupt mask */
+                                        /* ports 5-7 follow after this */
+       MVS_P4_INT_STAT         = 0x200, /* Port4 interrupt status */
+       MVS_P4_INT_MASK         = 0x204, /* Port4 interrupt enable mask */
+
+                                        /* ports 1-3 follow after this */
+       MVS_P0_SER_CTLSTAT      = 0x180, /* port0 serial control/status */
+                                        /* ports 5-7 follow after this */
+       MVS_P4_SER_CTLSTAT      = 0x220, /* port4 serial control/status */
+
+       MVS_CMD_ADDR            = 0x1B8, /* Command register port (addr) */
+       MVS_CMD_DATA            = 0x1BC, /* Command register port (data) */
+
+                                        /* ports 1-3 follow after this */
+       MVS_P0_CFG_ADDR         = 0x1C0, /* port0 phy register address */
+       MVS_P0_CFG_DATA         = 0x1C4, /* port0 phy register data */
+                                        /* ports 5-7 follow after this */
+       MVS_P4_CFG_ADDR         = 0x230, /* Port4 config address */
+       MVS_P4_CFG_DATA         = 0x234, /* Port4 config data */
+
+                                        /* ports 1-3 follow after this */
+       MVS_P0_VSR_ADDR         = 0x1E0, /* port0 VSR address */
+       MVS_P0_VSR_DATA         = 0x1E4, /* port0 VSR data */
+                                        /* ports 5-7 follow after this */
+       MVS_P4_VSR_ADDR         = 0x250, /* port4 VSR addr */
+       MVS_P4_VSR_DATA         = 0x254, /* port4 VSR data */
+};
+
+enum pci_cfg_registers {
+       PCR_PHY_CTL             = 0x40,
+       PCR_PHY_CTL2            = 0x90,
+       PCR_DEV_CTRL            = 0xE8,
+       PCR_LINK_STAT           = 0xF2,
+};
+
+/*  SAS/SATA Vendor Specific Port Registers */
+enum sas_sata_vsp_regs {
+       VSR_PHY_STAT            = 0x00, /* Phy Status */
+       VSR_PHY_MODE1           = 0x01, /* phy tx */
+       VSR_PHY_MODE2           = 0x02, /* tx scc */
+       VSR_PHY_MODE3           = 0x03, /* pll */
+       VSR_PHY_MODE4           = 0x04, /* VCO */
+       VSR_PHY_MODE5           = 0x05, /* Rx */
+       VSR_PHY_MODE6           = 0x06, /* CDR */
+       VSR_PHY_MODE7           = 0x07, /* Impedance */
+       VSR_PHY_MODE8           = 0x08, /* Voltage */
+       VSR_PHY_MODE9           = 0x09, /* Test */
+       VSR_PHY_MODE10          = 0x0A, /* Power */
+       VSR_PHY_MODE11          = 0x0B, /* Phy Mode */
+       VSR_PHY_VS0             = 0x0C, /* Vednor Specific 0 */
+       VSR_PHY_VS1             = 0x0D, /* Vednor Specific 1 */
+};
+
+enum chip_register_bits {
+       PHY_MIN_SPP_PHYS_LINK_RATE_MASK = (0xF << 8),
+       PHY_MAX_SPP_PHYS_LINK_RATE_MASK = (0xF << 12),
+       PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET = (16),
+       PHY_NEG_SPP_PHYS_LINK_RATE_MASK =
+                       (0xF << PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET),
+};
+
+#define MAX_SG_ENTRY           64
+
+struct mvs_prd {
+       __le64                  addr;           /* 64-bit buffer address */
+       __le32                  reserved;
+       __le32                  len;            /* 16-bit length */
+};
+
+#define SPI_CTRL_REG                           0xc0
+#define SPI_CTRL_VENDOR_ENABLE         (1U<<29)
+#define SPI_CTRL_SPIRDY                        (1U<<22)
+#define SPI_CTRL_SPISTART                      (1U<<20)
+
+#define SPI_CMD_REG            0xc4
+#define SPI_DATA_REG           0xc8
+
+#define SPI_CTRL_REG_64XX              0x10
+#define SPI_CMD_REG_64XX               0x14
+#define SPI_DATA_REG_64XX              0x18
+
+#endif
diff --git a/drivers/scsi/mvsas/mv_94xx.c b/drivers/scsi/mvsas/mv_94xx.c
new file mode 100644 (file)
index 0000000..0940fae
--- /dev/null
@@ -0,0 +1,672 @@
+/*
+ * Marvell 88SE94xx hardware specific
+ *
+ * Copyright 2007 Red Hat, Inc.
+ * Copyright 2008 Marvell. <kewei@marvell.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+*/
+
+#include "mv_sas.h"
+#include "mv_94xx.h"
+#include "mv_chips.h"
+
+static void mvs_94xx_detect_porttype(struct mvs_info *mvi, int i)
+{
+       u32 reg;
+       struct mvs_phy *phy = &mvi->phy[i];
+       u32 phy_status;
+
+       mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE3);
+       reg = mvs_read_port_vsr_data(mvi, i);
+       phy_status = ((reg & 0x3f0000) >> 16) & 0xff;
+       phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
+       switch (phy_status) {
+       case 0x10:
+               phy->phy_type |= PORT_TYPE_SAS;
+               break;
+       case 0x1d:
+       default:
+               phy->phy_type |= PORT_TYPE_SATA;
+               break;
+       }
+}
+
+static void __devinit mvs_94xx_enable_xmt(struct mvs_info *mvi, int phy_id)
+{
+       void __iomem *regs = mvi->regs;
+       u32 tmp;
+
+       tmp = mr32(MVS_PCS);
+       tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT2);
+       mw32(MVS_PCS, tmp);
+}
+
+static void mvs_94xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard)
+{
+       u32 tmp;
+
+       tmp = mvs_read_port_irq_stat(mvi, phy_id);
+       tmp &= ~PHYEV_RDY_CH;
+       mvs_write_port_irq_stat(mvi, phy_id, tmp);
+       if (hard) {
+               tmp = mvs_read_phy_ctl(mvi, phy_id);
+               tmp |= PHY_RST_HARD;
+               mvs_write_phy_ctl(mvi, phy_id, tmp);
+               do {
+                       tmp = mvs_read_phy_ctl(mvi, phy_id);
+               } while (tmp & PHY_RST_HARD);
+       } else {
+               mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_STAT);
+               tmp = mvs_read_port_vsr_data(mvi, phy_id);
+               tmp |= PHY_RST;
+               mvs_write_port_vsr_data(mvi, phy_id, tmp);
+       }
+}
+
+static void mvs_94xx_phy_disable(struct mvs_info *mvi, u32 phy_id)
+{
+       u32 tmp;
+       mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_MODE2);
+       tmp = mvs_read_port_vsr_data(mvi, phy_id);
+       mvs_write_port_vsr_data(mvi, phy_id, tmp | 0x00800000);
+}
+
+static void mvs_94xx_phy_enable(struct mvs_info *mvi, u32 phy_id)
+{
+       mvs_write_port_vsr_addr(mvi, phy_id, 0x1B4);
+       mvs_write_port_vsr_data(mvi, phy_id, 0x8300ffc1);
+       mvs_write_port_vsr_addr(mvi, phy_id, 0x104);
+       mvs_write_port_vsr_data(mvi, phy_id, 0x00018080);
+       mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_MODE2);
+       mvs_write_port_vsr_data(mvi, phy_id, 0x00207fff);
+}
+
+static int __devinit mvs_94xx_init(struct mvs_info *mvi)
+{
+       void __iomem *regs = mvi->regs;
+       int i;
+       u32 tmp, cctl;
+
+       mvs_show_pcie_usage(mvi);
+       if (mvi->flags & MVF_FLAG_SOC) {
+               tmp = mr32(MVS_PHY_CTL);
+               tmp &= ~PCTL_PWR_OFF;
+               tmp |= PCTL_PHY_DSBL;
+               mw32(MVS_PHY_CTL, tmp);
+       }
+
+       /* Init Chip */
+       /* make sure RST is set; HBA_RST /should/ have done that for us */
+       cctl = mr32(MVS_CTL) & 0xFFFF;
+       if (cctl & CCTL_RST)
+               cctl &= ~CCTL_RST;
+       else
+               mw32_f(MVS_CTL, cctl | CCTL_RST);
+
+       if (mvi->flags & MVF_FLAG_SOC) {
+               tmp = mr32(MVS_PHY_CTL);
+               tmp &= ~PCTL_PWR_OFF;
+               tmp |= PCTL_COM_ON;
+               tmp &= ~PCTL_PHY_DSBL;
+               tmp |= PCTL_LINK_RST;
+               mw32(MVS_PHY_CTL, tmp);
+               msleep(100);
+               tmp &= ~PCTL_LINK_RST;
+               mw32(MVS_PHY_CTL, tmp);
+               msleep(100);
+       }
+
+       /* reset control */
+       mw32(MVS_PCS, 0);               /* MVS_PCS */
+       mw32(MVS_STP_REG_SET_0, 0);
+       mw32(MVS_STP_REG_SET_1, 0);
+
+       /* init phys */
+       mvs_phy_hacks(mvi);
+
+       /* disable Multiplexing, enable phy implemented */
+       mw32(MVS_PORTS_IMP, 0xFF);
+
+
+       mw32(MVS_PA_VSR_ADDR, 0x00000104);
+       mw32(MVS_PA_VSR_PORT, 0x00018080);
+       mw32(MVS_PA_VSR_ADDR, VSR_PHY_MODE8);
+       mw32(MVS_PA_VSR_PORT, 0x0084ffff);
+
+       /* set LED blink when IO*/
+       mw32(MVS_PA_VSR_ADDR, 0x00000030);
+       tmp = mr32(MVS_PA_VSR_PORT);
+       tmp &= 0xFFFF00FF;
+       tmp |= 0x00003300;
+       mw32(MVS_PA_VSR_PORT, tmp);
+
+       mw32(MVS_CMD_LIST_LO, mvi->slot_dma);
+       mw32(MVS_CMD_LIST_HI, (mvi->slot_dma >> 16) >> 16);
+
+       mw32(MVS_RX_FIS_LO, mvi->rx_fis_dma);
+       mw32(MVS_RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16);
+
+       mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ);
+       mw32(MVS_TX_LO, mvi->tx_dma);
+       mw32(MVS_TX_HI, (mvi->tx_dma >> 16) >> 16);
+
+       mw32(MVS_RX_CFG, MVS_RX_RING_SZ);
+       mw32(MVS_RX_LO, mvi->rx_dma);
+       mw32(MVS_RX_HI, (mvi->rx_dma >> 16) >> 16);
+
+       for (i = 0; i < mvi->chip->n_phy; i++) {
+               mvs_94xx_phy_disable(mvi, i);
+               /* set phy local SAS address */
+               mvs_set_sas_addr(mvi, i, CONFIG_ID_FRAME3, CONFIG_ID_FRAME4,
+                                               (mvi->phy[i].dev_sas_addr));
+
+               mvs_94xx_enable_xmt(mvi, i);
+               mvs_94xx_phy_enable(mvi, i);
+
+               mvs_94xx_phy_reset(mvi, i, 1);
+               msleep(500);
+               mvs_94xx_detect_porttype(mvi, i);
+       }
+
+       if (mvi->flags & MVF_FLAG_SOC) {
+               /* set select registers */
+               writel(0x0E008000, regs + 0x000);
+               writel(0x59000008, regs + 0x004);
+               writel(0x20, regs + 0x008);
+               writel(0x20, regs + 0x00c);
+               writel(0x20, regs + 0x010);
+               writel(0x20, regs + 0x014);
+               writel(0x20, regs + 0x018);
+               writel(0x20, regs + 0x01c);
+       }
+       for (i = 0; i < mvi->chip->n_phy; i++) {
+               /* clear phy int status */
+               tmp = mvs_read_port_irq_stat(mvi, i);
+               tmp &= ~PHYEV_SIG_FIS;
+               mvs_write_port_irq_stat(mvi, i, tmp);
+
+               /* set phy int mask */
+               tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH |
+                       PHYEV_ID_DONE  | PHYEV_DCDR_ERR | PHYEV_CRC_ERR ;
+               mvs_write_port_irq_mask(mvi, i, tmp);
+
+               msleep(100);
+               mvs_update_phyinfo(mvi, i, 1);
+       }
+
+       /* FIXME: update wide port bitmaps */
+
+       /* little endian for open address and command table, etc. */
+       /*
+        * it seems that ( from the spec ) turning on big-endian won't
+        * do us any good on big-endian machines, need further confirmation
+        */
+       cctl = mr32(MVS_CTL);
+       cctl |= CCTL_ENDIAN_CMD;
+       cctl |= CCTL_ENDIAN_DATA;
+       cctl &= ~CCTL_ENDIAN_OPEN;
+       cctl |= CCTL_ENDIAN_RSP;
+       mw32_f(MVS_CTL, cctl);
+
+       /* reset CMD queue */
+       tmp = mr32(MVS_PCS);
+       tmp |= PCS_CMD_RST;
+       mw32(MVS_PCS, tmp);
+       /* interrupt coalescing may cause missing HW interrput in some case,
+        * and the max count is 0x1ff, while our max slot is 0x200,
+        * it will make count 0.
+        */
+       tmp = 0;
+       mw32(MVS_INT_COAL, tmp);
+
+       tmp = 0x100;
+       mw32(MVS_INT_COAL_TMOUT, tmp);
+
+       /* ladies and gentlemen, start your engines */
+       mw32(MVS_TX_CFG, 0);
+       mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ | TX_EN);
+       mw32(MVS_RX_CFG, MVS_RX_RING_SZ | RX_EN);
+       /* enable CMD/CMPL_Q/RESP mode */
+       mw32(MVS_PCS, PCS_SATA_RETRY_2 | PCS_FIS_RX_EN |
+               PCS_CMD_EN | PCS_CMD_STOP_ERR);
+
+       /* enable completion queue interrupt */
+       tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM | CINT_SRS | CINT_CI_STOP |
+               CINT_DMA_PCIE);
+       tmp |= CINT_PHY_MASK;
+       mw32(MVS_INT_MASK, tmp);
+
+       /* Enable SRS interrupt */
+       mw32(MVS_INT_MASK_SRS_0, 0xFFFF);
+
+       return 0;
+}
+
+static int mvs_94xx_ioremap(struct mvs_info *mvi)
+{
+       if (!mvs_ioremap(mvi, 2, -1)) {
+               mvi->regs_ex = mvi->regs + 0x10200;
+               mvi->regs += 0x20000;
+               if (mvi->id == 1)
+                       mvi->regs += 0x4000;
+               return 0;
+       }
+       return -1;
+}
+
+static void mvs_94xx_iounmap(struct mvs_info *mvi)
+{
+       if (mvi->regs) {
+               mvi->regs -= 0x20000;
+               if (mvi->id == 1)
+                       mvi->regs -= 0x4000;
+               mvs_iounmap(mvi->regs);
+       }
+}
+
+static void mvs_94xx_interrupt_enable(struct mvs_info *mvi)
+{
+       void __iomem *regs = mvi->regs_ex;
+       u32 tmp;
+
+       tmp = mr32(MVS_GBL_CTL);
+       tmp |= (IRQ_SAS_A | IRQ_SAS_B);
+       mw32(MVS_GBL_INT_STAT, tmp);
+       writel(tmp, regs + 0x0C);
+       writel(tmp, regs + 0x10);
+       writel(tmp, regs + 0x14);
+       writel(tmp, regs + 0x18);
+       mw32(MVS_GBL_CTL, tmp);
+}
+
+static void mvs_94xx_interrupt_disable(struct mvs_info *mvi)
+{
+       void __iomem *regs = mvi->regs_ex;
+       u32 tmp;
+
+       tmp = mr32(MVS_GBL_CTL);
+
+       tmp &= ~(IRQ_SAS_A | IRQ_SAS_B);
+       mw32(MVS_GBL_INT_STAT, tmp);
+       writel(tmp, regs + 0x0C);
+       writel(tmp, regs + 0x10);
+       writel(tmp, regs + 0x14);
+       writel(tmp, regs + 0x18);
+       mw32(MVS_GBL_CTL, tmp);
+}
+
+static u32 mvs_94xx_isr_status(struct mvs_info *mvi, int irq)
+{
+       void __iomem *regs = mvi->regs_ex;
+       u32 stat = 0;
+       if (!(mvi->flags & MVF_FLAG_SOC)) {
+               stat = mr32(MVS_GBL_INT_STAT);
+
+               if (!(stat & (IRQ_SAS_A | IRQ_SAS_B)))
+                       return 0;
+       }
+       return stat;
+}
+
+static irqreturn_t mvs_94xx_isr(struct mvs_info *mvi, int irq, u32 stat)
+{
+       void __iomem *regs = mvi->regs;
+
+       if (((stat & IRQ_SAS_A) && mvi->id == 0) ||
+                       ((stat & IRQ_SAS_B) && mvi->id == 1)) {
+               mw32_f(MVS_INT_STAT, CINT_DONE);
+       #ifndef MVS_USE_TASKLET
+               spin_lock(&mvi->lock);
+       #endif
+               mvs_int_full(mvi);
+       #ifndef MVS_USE_TASKLET
+               spin_unlock(&mvi->lock);
+       #endif
+       }
+       return IRQ_HANDLED;
+}
+
+static void mvs_94xx_command_active(struct mvs_info *mvi, u32 slot_idx)
+{
+       u32 tmp;
+       mvs_cw32(mvi, 0x300 + (slot_idx >> 3), 1 << (slot_idx % 32));
+       do {
+               tmp = mvs_cr32(mvi, 0x300 + (slot_idx >> 3));
+       } while (tmp & 1 << (slot_idx % 32));
+}
+
+static void mvs_94xx_issue_stop(struct mvs_info *mvi, enum mvs_port_type type,
+                               u32 tfs)
+{
+       void __iomem *regs = mvi->regs;
+       u32 tmp;
+
+       if (type == PORT_TYPE_SATA) {
+               tmp = mr32(MVS_INT_STAT_SRS_0) | (1U << tfs);
+               mw32(MVS_INT_STAT_SRS_0, tmp);
+       }
+       mw32(MVS_INT_STAT, CINT_CI_STOP);
+       tmp = mr32(MVS_PCS) | 0xFF00;
+       mw32(MVS_PCS, tmp);
+}
+
+static void mvs_94xx_free_reg_set(struct mvs_info *mvi, u8 *tfs)
+{
+       void __iomem *regs = mvi->regs;
+       u32 tmp;
+       u8 reg_set = *tfs;
+
+       if (*tfs == MVS_ID_NOT_MAPPED)
+               return;
+
+       mvi->sata_reg_set &= ~bit(reg_set);
+       if (reg_set < 32) {
+               w_reg_set_enable(reg_set, (u32)mvi->sata_reg_set);
+               tmp = mr32(MVS_INT_STAT_SRS_0) & (u32)mvi->sata_reg_set;
+               if (tmp)
+                       mw32(MVS_INT_STAT_SRS_0, tmp);
+       } else {
+               w_reg_set_enable(reg_set, mvi->sata_reg_set);
+               tmp = mr32(MVS_INT_STAT_SRS_1) & mvi->sata_reg_set;
+               if (tmp)
+                       mw32(MVS_INT_STAT_SRS_1, tmp);
+       }
+
+       *tfs = MVS_ID_NOT_MAPPED;
+
+       return;
+}
+
+static u8 mvs_94xx_assign_reg_set(struct mvs_info *mvi, u8 *tfs)
+{
+       int i;
+       void __iomem *regs = mvi->regs;
+
+       if (*tfs != MVS_ID_NOT_MAPPED)
+               return 0;
+
+       i = mv_ffc64(mvi->sata_reg_set);
+       if (i > 32) {
+               mvi->sata_reg_set |= bit(i);
+               w_reg_set_enable(i, (u32)(mvi->sata_reg_set >> 32));
+               *tfs = i;
+               return 0;
+       } else if (i >= 0) {
+               mvi->sata_reg_set |= bit(i);
+               w_reg_set_enable(i, (u32)mvi->sata_reg_set);
+               *tfs = i;
+               return 0;
+       }
+       return MVS_ID_NOT_MAPPED;
+}
+
+static void mvs_94xx_make_prd(struct scatterlist *scatter, int nr, void *prd)
+{
+       int i;
+       struct scatterlist *sg;
+       struct mvs_prd *buf_prd = prd;
+       for_each_sg(scatter, sg, nr, i) {
+               buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
+               buf_prd->im_len.len = cpu_to_le32(sg_dma_len(sg));
+               buf_prd++;
+       }
+}
+
+static int mvs_94xx_oob_done(struct mvs_info *mvi, int i)
+{
+       u32 phy_st;
+       phy_st = mvs_read_phy_ctl(mvi, i);
+       if (phy_st & PHY_READY_MASK)    /* phy ready */
+               return 1;
+       return 0;
+}
+
+static void mvs_94xx_get_dev_identify_frame(struct mvs_info *mvi, int port_id,
+                                       struct sas_identify_frame *id)
+{
+       int i;
+       u32 id_frame[7];
+
+       for (i = 0; i < 7; i++) {
+               mvs_write_port_cfg_addr(mvi, port_id,
+                                       CONFIG_ID_FRAME0 + i * 4);
+               id_frame[i] = mvs_read_port_cfg_data(mvi, port_id);
+       }
+       memcpy(id, id_frame, 28);
+}
+
+static void mvs_94xx_get_att_identify_frame(struct mvs_info *mvi, int port_id,
+                                       struct sas_identify_frame *id)
+{
+       int i;
+       u32 id_frame[7];
+
+       /* mvs_hexdump(28, (u8 *)id_frame, 0); */
+       for (i = 0; i < 7; i++) {
+               mvs_write_port_cfg_addr(mvi, port_id,
+                                       CONFIG_ATT_ID_FRAME0 + i * 4);
+               id_frame[i] = mvs_read_port_cfg_data(mvi, port_id);
+               mv_dprintk("94xx phy %d atta frame %d %x.\n",
+                       port_id + mvi->id * mvi->chip->n_phy, i, id_frame[i]);
+       }
+       /* mvs_hexdump(28, (u8 *)id_frame, 0); */
+       memcpy(id, id_frame, 28);
+}
+
+static u32 mvs_94xx_make_dev_info(struct sas_identify_frame *id)
+{
+       u32 att_dev_info = 0;
+
+       att_dev_info |= id->dev_type;
+       if (id->stp_iport)
+               att_dev_info |= PORT_DEV_STP_INIT;
+       if (id->smp_iport)
+               att_dev_info |= PORT_DEV_SMP_INIT;
+       if (id->ssp_iport)
+               att_dev_info |= PORT_DEV_SSP_INIT;
+       if (id->stp_tport)
+               att_dev_info |= PORT_DEV_STP_TRGT;
+       if (id->smp_tport)
+               att_dev_info |= PORT_DEV_SMP_TRGT;
+       if (id->ssp_tport)
+               att_dev_info |= PORT_DEV_SSP_TRGT;
+
+       att_dev_info |= (u32)id->phy_id<<24;
+       return att_dev_info;
+}
+
+static u32 mvs_94xx_make_att_info(struct sas_identify_frame *id)
+{
+       return mvs_94xx_make_dev_info(id);
+}
+
+static void mvs_94xx_fix_phy_info(struct mvs_info *mvi, int i,
+                               struct sas_identify_frame *id)
+{
+       struct mvs_phy *phy = &mvi->phy[i];
+       struct asd_sas_phy *sas_phy = &phy->sas_phy;
+       mv_dprintk("get all reg link rate is 0x%x\n", phy->phy_status);
+       sas_phy->linkrate =
+               (phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
+                       PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET;
+       sas_phy->linkrate += 0x8;
+       mv_dprintk("get link rate is %d\n", sas_phy->linkrate);
+       phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
+       phy->maximum_linkrate = SAS_LINK_RATE_6_0_GBPS;
+       mvs_94xx_get_dev_identify_frame(mvi, i, id);
+       phy->dev_info = mvs_94xx_make_dev_info(id);
+
+       if (phy->phy_type & PORT_TYPE_SAS) {
+               mvs_94xx_get_att_identify_frame(mvi, i, id);
+               phy->att_dev_info = mvs_94xx_make_att_info(id);
+               phy->att_dev_sas_addr = *(u64 *)id->sas_addr;
+       } else {
+               phy->att_dev_info = PORT_DEV_STP_TRGT | 1;
+       }
+
+}
+
+void mvs_94xx_phy_set_link_rate(struct mvs_info *mvi, u32 phy_id,
+                       struct sas_phy_linkrates *rates)
+{
+       /* TODO */
+}
+
+static void mvs_94xx_clear_active_cmds(struct mvs_info *mvi)
+{
+       u32 tmp;
+       void __iomem *regs = mvi->regs;
+       tmp = mr32(MVS_STP_REG_SET_0);
+       mw32(MVS_STP_REG_SET_0, 0);
+       mw32(MVS_STP_REG_SET_0, tmp);
+       tmp = mr32(MVS_STP_REG_SET_1);
+       mw32(MVS_STP_REG_SET_1, 0);
+       mw32(MVS_STP_REG_SET_1, tmp);
+}
+
+
+u32 mvs_94xx_spi_read_data(struct mvs_info *mvi)
+{
+       void __iomem *regs = mvi->regs_ex - 0x10200;
+       return mr32(SPI_RD_DATA_REG_94XX);
+}
+
+void mvs_94xx_spi_write_data(struct mvs_info *mvi, u32 data)
+{
+       void __iomem *regs = mvi->regs_ex - 0x10200;
+        mw32(SPI_RD_DATA_REG_94XX, data);
+}
+
+
+int mvs_94xx_spi_buildcmd(struct mvs_info *mvi,
+                               u32      *dwCmd,
+                               u8       cmd,
+                               u8       read,
+                               u8       length,
+                               u32      addr
+                               )
+{
+       void __iomem *regs = mvi->regs_ex - 0x10200;
+       u32  dwTmp;
+
+       dwTmp = ((u32)cmd << 8) | ((u32)length << 4);
+       if (read)
+               dwTmp |= SPI_CTRL_READ_94XX;
+
+       if (addr != MV_MAX_U32) {
+               mw32(SPI_ADDR_REG_94XX, (addr & 0x0003FFFFL));
+               dwTmp |= SPI_ADDR_VLD_94XX;
+       }
+
+       *dwCmd = dwTmp;
+       return 0;
+}
+
+
+int mvs_94xx_spi_issuecmd(struct mvs_info *mvi, u32 cmd)
+{
+       void __iomem *regs = mvi->regs_ex - 0x10200;
+       mw32(SPI_CTRL_REG_94XX, cmd | SPI_CTRL_SpiStart_94XX);
+
+       return 0;
+}
+
+int mvs_94xx_spi_waitdataready(struct mvs_info *mvi, u32 timeout)
+{
+       void __iomem *regs = mvi->regs_ex - 0x10200;
+       u32   i, dwTmp;
+
+       for (i = 0; i < timeout; i++) {
+               dwTmp = mr32(SPI_CTRL_REG_94XX);
+               if (!(dwTmp & SPI_CTRL_SpiStart_94XX))
+                       return 0;
+               msleep(10);
+       }
+
+       return -1;
+}
+
+#ifndef DISABLE_HOTPLUG_DMA_FIX
+void mvs_94xx_fix_dma(dma_addr_t buf_dma, int buf_len, int from, void *prd)
+{
+       int i;
+       struct mvs_prd *buf_prd = prd;
+       buf_prd += from;
+       for (i = 0; i < MAX_SG_ENTRY - from; i++) {
+               buf_prd->addr = cpu_to_le64(buf_dma);
+               buf_prd->im_len.len = cpu_to_le32(buf_len);
+               ++buf_prd;
+       }
+}
+#endif
+
+const struct mvs_dispatch mvs_94xx_dispatch = {
+       "mv94xx",
+       mvs_94xx_init,
+       NULL,
+       mvs_94xx_ioremap,
+       mvs_94xx_iounmap,
+       mvs_94xx_isr,
+       mvs_94xx_isr_status,
+       mvs_94xx_interrupt_enable,
+       mvs_94xx_interrupt_disable,
+       mvs_read_phy_ctl,
+       mvs_write_phy_ctl,
+       mvs_read_port_cfg_data,
+       mvs_write_port_cfg_data,
+       mvs_write_port_cfg_addr,
+       mvs_read_port_vsr_data,
+       mvs_write_port_vsr_data,
+       mvs_write_port_vsr_addr,
+       mvs_read_port_irq_stat,
+       mvs_write_port_irq_stat,
+       mvs_read_port_irq_mask,
+       mvs_write_port_irq_mask,
+       mvs_get_sas_addr,
+       mvs_94xx_command_active,
+       mvs_94xx_issue_stop,
+       mvs_start_delivery,
+       mvs_rx_update,
+       mvs_int_full,
+       mvs_94xx_assign_reg_set,
+       mvs_94xx_free_reg_set,
+       mvs_get_prd_size,
+       mvs_get_prd_count,
+       mvs_94xx_make_prd,
+       mvs_94xx_detect_porttype,
+       mvs_94xx_oob_done,
+       mvs_94xx_fix_phy_info,
+       NULL,
+       mvs_94xx_phy_set_link_rate,
+       mvs_hw_max_link_rate,
+       mvs_94xx_phy_disable,
+       mvs_94xx_phy_enable,
+       mvs_94xx_phy_reset,
+       NULL,
+       mvs_94xx_clear_active_cmds,
+       mvs_94xx_spi_read_data,
+       mvs_94xx_spi_write_data,
+       mvs_94xx_spi_buildcmd,
+       mvs_94xx_spi_issuecmd,
+       mvs_94xx_spi_waitdataready,
+#ifndef DISABLE_HOTPLUG_DMA_FIX
+       mvs_94xx_fix_dma,
+#endif
+};
+
diff --git a/drivers/scsi/mvsas/mv_94xx.h b/drivers/scsi/mvsas/mv_94xx.h
new file mode 100644 (file)
index 0000000..23ed9b1
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * Marvell 88SE94xx hardware specific head file
+ *
+ * Copyright 2007 Red Hat, Inc.
+ * Copyright 2008 Marvell. <kewei@marvell.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+*/
+
+#ifndef _MVS94XX_REG_H_
+#define _MVS94XX_REG_H_
+
+#include <linux/types.h>
+
+#define MAX_LINK_RATE          SAS_LINK_RATE_6_0_GBPS
+
+enum hw_registers {
+       MVS_GBL_CTL             = 0x04,  /* global control */
+       MVS_GBL_INT_STAT        = 0x00,  /* global irq status */
+       MVS_GBL_PI              = 0x0C,  /* ports implemented bitmask */
+
+       MVS_PHY_CTL             = 0x40,  /* SOC PHY Control */
+       MVS_PORTS_IMP           = 0x9C,  /* SOC Port Implemented */
+
+       MVS_GBL_PORT_TYPE       = 0xa0,  /* port type */
+
+       MVS_CTL                 = 0x100, /* SAS/SATA port configuration */
+       MVS_PCS                 = 0x104, /* SAS/SATA port control/status */
+       MVS_CMD_LIST_LO         = 0x108, /* cmd list addr */
+       MVS_CMD_LIST_HI         = 0x10C,
+       MVS_RX_FIS_LO           = 0x110, /* RX FIS list addr */
+       MVS_RX_FIS_HI           = 0x114,
+       MVS_STP_REG_SET_0       = 0x118, /* STP/SATA Register Set Enable */
+       MVS_STP_REG_SET_1       = 0x11C,
+       MVS_TX_CFG              = 0x120, /* TX configuration */
+       MVS_TX_LO               = 0x124, /* TX (delivery) ring addr */
+       MVS_TX_HI               = 0x128,
+
+       MVS_TX_PROD_IDX         = 0x12C, /* TX producer pointer */
+       MVS_TX_CONS_IDX         = 0x130, /* TX consumer pointer (RO) */
+       MVS_RX_CFG              = 0x134, /* RX configuration */
+       MVS_RX_LO               = 0x138, /* RX (completion) ring addr */
+       MVS_RX_HI               = 0x13C,
+       MVS_RX_CONS_IDX         = 0x140, /* RX consumer pointer (RO) */
+
+       MVS_INT_COAL            = 0x148, /* Int coalescing config */
+       MVS_INT_COAL_TMOUT      = 0x14C, /* Int coalescing timeout */
+       MVS_INT_STAT            = 0x150, /* Central int status */
+       MVS_INT_MASK            = 0x154, /* Central int enable */
+       MVS_INT_STAT_SRS_0      = 0x158, /* SATA register set status */
+       MVS_INT_MASK_SRS_0      = 0x15C,
+       MVS_INT_STAT_SRS_1      = 0x160,
+       MVS_INT_MASK_SRS_1      = 0x164,
+       MVS_NON_NCQ_ERR_0       = 0x168, /* SRS Non-specific NCQ Error */
+       MVS_NON_NCQ_ERR_1       = 0x16C,
+       MVS_CMD_ADDR            = 0x170, /* Command register port (addr) */
+       MVS_CMD_DATA            = 0x174, /* Command register port (data) */
+       MVS_MEM_PARITY_ERR      = 0x178, /* Memory parity error */
+
+                                        /* ports 1-3 follow after this */
+       MVS_P0_INT_STAT         = 0x180, /* port0 interrupt status */
+       MVS_P0_INT_MASK         = 0x184, /* port0 interrupt mask */
+                                        /* ports 5-7 follow after this */
+       MVS_P4_INT_STAT         = 0x1A0, /* Port4 interrupt status */
+       MVS_P4_INT_MASK         = 0x1A4, /* Port4 interrupt enable mask */
+
+                                        /* ports 1-3 follow after this */
+       MVS_P0_SER_CTLSTAT      = 0x1D0, /* port0 serial control/status */
+                                        /* ports 5-7 follow after this */
+       MVS_P4_SER_CTLSTAT      = 0x1E0, /* port4 serial control/status */
+
+                                        /* ports 1-3 follow after this */
+       MVS_P0_CFG_ADDR         = 0x200, /* port0 phy register address */
+       MVS_P0_CFG_DATA         = 0x204, /* port0 phy register data */
+                                        /* ports 5-7 follow after this */
+       MVS_P4_CFG_ADDR         = 0x220, /* Port4 config address */
+       MVS_P4_CFG_DATA         = 0x224, /* Port4 config data */
+
+                                        /* phys 1-3 follow after this */
+       MVS_P0_VSR_ADDR         = 0x250, /* phy0 VSR address */
+       MVS_P0_VSR_DATA         = 0x254, /* phy0 VSR data */
+                                        /* phys 1-3 follow after this */
+                                        /* multiplexing */
+       MVS_P4_VSR_ADDR         = 0x250, /* phy4 VSR address */
+       MVS_P4_VSR_DATA         = 0x254, /* phy4 VSR data */
+       MVS_PA_VSR_ADDR         = 0x290, /* All port VSR addr */
+       MVS_PA_VSR_PORT         = 0x294, /* All port VSR data */
+};
+
+enum pci_cfg_registers {
+       PCR_PHY_CTL             = 0x40,
+       PCR_PHY_CTL2            = 0x90,
+       PCR_DEV_CTRL            = 0x78,
+       PCR_LINK_STAT           = 0x82,
+};
+
+/*  SAS/SATA Vendor Specific Port Registers */
+enum sas_sata_vsp_regs {
+       VSR_PHY_STAT            = 0x00 * 4, /* Phy Status */
+       VSR_PHY_MODE1           = 0x01 * 4, /* phy tx */
+       VSR_PHY_MODE2           = 0x02 * 4, /* tx scc */
+       VSR_PHY_MODE3           = 0x03 * 4, /* pll */
+       VSR_PHY_MODE4           = 0x04 * 4, /* VCO */
+       VSR_PHY_MODE5           = 0x05 * 4, /* Rx */
+       VSR_PHY_MODE6           = 0x06 * 4, /* CDR */
+       VSR_PHY_MODE7           = 0x07 * 4, /* Impedance */
+       VSR_PHY_MODE8           = 0x08 * 4, /* Voltage */
+       VSR_PHY_MODE9           = 0x09 * 4, /* Test */
+       VSR_PHY_MODE10          = 0x0A * 4, /* Power */
+       VSR_PHY_MODE11          = 0x0B * 4, /* Phy Mode */
+       VSR_PHY_VS0             = 0x0C * 4, /* Vednor Specific 0 */
+       VSR_PHY_VS1             = 0x0D * 4, /* Vednor Specific 1 */
+};
+
+enum chip_register_bits {
+       PHY_MIN_SPP_PHYS_LINK_RATE_MASK = (0x7 << 8),
+       PHY_MAX_SPP_PHYS_LINK_RATE_MASK = (0x7 << 8),
+       PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET = (12),
+       PHY_NEG_SPP_PHYS_LINK_RATE_MASK =
+                       (0x3 << PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET),
+};
+
+enum pci_interrupt_cause {
+       /*  MAIN_IRQ_CAUSE (R10200) Bits*/
+       IRQ_COM_IN_I2O_IOP0            = (1 << 0),
+       IRQ_COM_IN_I2O_IOP1            = (1 << 1),
+       IRQ_COM_IN_I2O_IOP2            = (1 << 2),
+       IRQ_COM_IN_I2O_IOP3            = (1 << 3),
+       IRQ_COM_OUT_I2O_HOS0           = (1 << 4),
+       IRQ_COM_OUT_I2O_HOS1           = (1 << 5),
+       IRQ_COM_OUT_I2O_HOS2           = (1 << 6),
+       IRQ_COM_OUT_I2O_HOS3           = (1 << 7),
+       IRQ_PCIF_TO_CPU_DRBL0          = (1 << 8),
+       IRQ_PCIF_TO_CPU_DRBL1          = (1 << 9),
+       IRQ_PCIF_TO_CPU_DRBL2          = (1 << 10),
+       IRQ_PCIF_TO_CPU_DRBL3          = (1 << 11),
+       IRQ_PCIF_DRBL0                 = (1 << 12),
+       IRQ_PCIF_DRBL1                 = (1 << 13),
+       IRQ_PCIF_DRBL2                 = (1 << 14),
+       IRQ_PCIF_DRBL3                 = (1 << 15),
+       IRQ_XOR_A                      = (1 << 16),
+       IRQ_XOR_B                      = (1 << 17),
+       IRQ_SAS_A                      = (1 << 18),
+       IRQ_SAS_B                      = (1 << 19),
+       IRQ_CPU_CNTRL                  = (1 << 20),
+       IRQ_GPIO                       = (1 << 21),
+       IRQ_UART                       = (1 << 22),
+       IRQ_SPI                        = (1 << 23),
+       IRQ_I2C                        = (1 << 24),
+       IRQ_SGPIO                      = (1 << 25),
+       IRQ_COM_ERR                    = (1 << 29),
+       IRQ_I2O_ERR                    = (1 << 30),
+       IRQ_PCIE_ERR                   = (1 << 31),
+};
+
+#define MAX_SG_ENTRY           255
+
+struct mvs_prd_imt {
+       __le32                  len:22;
+       u8                      _r_a:2;
+       u8                      misc_ctl:4;
+       u8                      inter_sel:4;
+};
+
+struct mvs_prd {
+       /* 64-bit buffer address */
+       __le64                  addr;
+       /* 22-bit length */
+       struct mvs_prd_imt      im_len;
+} __attribute__ ((packed));
+
+#define SPI_CTRL_REG_94XX              0xc800
+#define SPI_ADDR_REG_94XX              0xc804
+#define SPI_WR_DATA_REG_94XX         0xc808
+#define SPI_RD_DATA_REG_94XX           0xc80c
+#define SPI_CTRL_READ_94XX             (1U << 2)
+#define SPI_ADDR_VLD_94XX              (1U << 1)
+#define SPI_CTRL_SpiStart_94XX         (1U << 0)
+
+#define mv_ffc(x)   ffz(x)
+
+static inline int
+mv_ffc64(u64 v)
+{
+       int i;
+       i = mv_ffc((u32)v);
+       if (i >= 0)
+               return i;
+       i = mv_ffc((u32)(v>>32));
+
+       if (i != 0)
+               return 32 + i;
+
+       return -1;
+}
+
+#define r_reg_set_enable(i) \
+       (((i) > 31) ? mr32(MVS_STP_REG_SET_1) : \
+       mr32(MVS_STP_REG_SET_0))
+
+#define w_reg_set_enable(i, tmp) \
+       (((i) > 31) ? mw32(MVS_STP_REG_SET_1, tmp) : \
+       mw32(MVS_STP_REG_SET_0, tmp))
+
+extern const struct mvs_dispatch mvs_94xx_dispatch;
+#endif
+
diff --git a/drivers/scsi/mvsas/mv_chips.h b/drivers/scsi/mvsas/mv_chips.h
new file mode 100644 (file)
index 0000000..a67e1c4
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * Marvell 88SE64xx/88SE94xx register IO interface
+ *
+ * Copyright 2007 Red Hat, Inc.
+ * Copyright 2008 Marvell. <kewei@marvell.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+*/
+
+
+#ifndef _MV_CHIPS_H_
+#define _MV_CHIPS_H_
+
+#define mr32(reg)      readl(regs + reg)
+#define mw32(reg, val) writel((val), regs + reg)
+#define mw32_f(reg, val)       do {                    \
+                               mw32(reg, val); \
+                               mr32(reg);      \
+                       } while (0)
+
+#define iow32(reg, val)        outl(val, (unsigned long)(regs + reg))
+#define ior32(reg)             inl((unsigned long)(regs + reg))
+#define iow16(reg, val)        outw((unsigned long)(val, regs + reg))
+#define ior16(reg)             inw((unsigned long)(regs + reg))
+#define iow8(reg, val)                 outb((unsigned long)(val, regs + reg))
+#define ior8(reg)              inb((unsigned long)(regs + reg))
+
+static inline u32 mvs_cr32(struct mvs_info *mvi, u32 addr)
+{
+       void __iomem *regs = mvi->regs;
+       mw32(MVS_CMD_ADDR, addr);
+       return mr32(MVS_CMD_DATA);
+}
+
+static inline void mvs_cw32(struct mvs_info *mvi, u32 addr, u32 val)
+{
+       void __iomem *regs = mvi->regs;
+       mw32(MVS_CMD_ADDR, addr);
+       mw32(MVS_CMD_DATA, val);
+}
+
+static inline u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port)
+{
+       void __iomem *regs = mvi->regs;
+       return (port < 4) ? mr32(MVS_P0_SER_CTLSTAT + port * 4) :
+               mr32(MVS_P4_SER_CTLSTAT + (port - 4) * 4);
+}
+
+static inline void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val)
+{
+       void __iomem *regs = mvi->regs;
+       if (port < 4)
+               mw32(MVS_P0_SER_CTLSTAT + port * 4, val);
+       else
+               mw32(MVS_P4_SER_CTLSTAT + (port - 4) * 4, val);
+}
+
+static inline u32 mvs_read_port(struct mvs_info *mvi, u32 off,
+                               u32 off2, u32 port)
+{
+       void __iomem *regs = mvi->regs + off;
+       void __iomem *regs2 = mvi->regs + off2;
+       return (port < 4) ? readl(regs + port * 8) :
+               readl(regs2 + (port - 4) * 8);
+}
+
+static inline void mvs_write_port(struct mvs_info *mvi, u32 off, u32 off2,
+                               u32 port, u32 val)
+{
+       void __iomem *regs = mvi->regs + off;
+       void __iomem *regs2 = mvi->regs + off2;
+       if (port < 4)
+               writel(val, regs + port * 8);
+       else
+               writel(val, regs2 + (port - 4) * 8);
+}
+
+static inline u32 mvs_read_port_cfg_data(struct mvs_info *mvi, u32 port)
+{
+       return mvs_read_port(mvi, MVS_P0_CFG_DATA,
+                       MVS_P4_CFG_DATA, port);
+}
+
+static inline void mvs_write_port_cfg_data(struct mvs_info *mvi,
+                                               u32 port, u32 val)
+{
+       mvs_write_port(mvi, MVS_P0_CFG_DATA,
+                       MVS_P4_CFG_DATA, port, val);
+}
+
+static inline void mvs_write_port_cfg_addr(struct mvs_info *mvi,
+                                               u32 port, u32 addr)
+{
+       mvs_write_port(mvi, MVS_P0_CFG_ADDR,
+                       MVS_P4_CFG_ADDR, port, addr);
+       mdelay(10);
+}
+
+static inline u32 mvs_read_port_vsr_data(struct mvs_info *mvi, u32 port)
+{
+       return mvs_read_port(mvi, MVS_P0_VSR_DATA,
+                       MVS_P4_VSR_DATA, port);
+}
+
+static inline void mvs_write_port_vsr_data(struct mvs_info *mvi,
+                                               u32 port, u32 val)
+{
+       mvs_write_port(mvi, MVS_P0_VSR_DATA,
+                       MVS_P4_VSR_DATA, port, val);
+}
+
+static inline void mvs_write_port_vsr_addr(struct mvs_info *mvi,
+                                               u32 port, u32 addr)
+{
+       mvs_write_port(mvi, MVS_P0_VSR_ADDR,
+                       MVS_P4_VSR_ADDR, port, addr);
+       mdelay(10);
+}
+
+static inline u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port)
+{
+       return mvs_read_port(mvi, MVS_P0_INT_STAT,
+                       MVS_P4_INT_STAT, port);
+}
+
+static inline void mvs_write_port_irq_stat(struct mvs_info *mvi,
+                                               u32 port, u32 val)
+{
+       mvs_write_port(mvi, MVS_P0_INT_STAT,
+                       MVS_P4_INT_STAT, port, val);
+}
+
+static inline u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port)
+{
+       return mvs_read_port(mvi, MVS_P0_INT_MASK,
+                       MVS_P4_INT_MASK, port);
+
+}
+
+static inline void mvs_write_port_irq_mask(struct mvs_info *mvi,
+                                               u32 port, u32 val)
+{
+       mvs_write_port(mvi, MVS_P0_INT_MASK,
+                       MVS_P4_INT_MASK, port, val);
+}
+
+static inline void __devinit mvs_phy_hacks(struct mvs_info *mvi)
+{
+       u32 tmp;
+
+       /* workaround for SATA R-ERR, to ignore phy glitch */
+       tmp = mvs_cr32(mvi, CMD_PHY_TIMER);
+       tmp &= ~(1 << 9);
+       tmp |= (1 << 10);
+       mvs_cw32(mvi, CMD_PHY_TIMER, tmp);
+
+       /* enable retry 127 times */
+       mvs_cw32(mvi, CMD_SAS_CTL1, 0x7f7f);
+
+       /* extend open frame timeout to max */
+       tmp = mvs_cr32(mvi, CMD_SAS_CTL0);
+       tmp &= ~0xffff;
+       tmp |= 0x3fff;
+       mvs_cw32(mvi, CMD_SAS_CTL0, tmp);
+
+       /* workaround for WDTIMEOUT , set to 550 ms */
+       mvs_cw32(mvi, CMD_WD_TIMER, 0x7a0000);
+
+       /* not to halt for different port op during wideport link change */
+       mvs_cw32(mvi, CMD_APP_ERR_CONFIG, 0xffefbf7d);
+
+       /* workaround for Seagate disk not-found OOB sequence, recv
+        * COMINIT before sending out COMWAKE */
+       tmp = mvs_cr32(mvi, CMD_PHY_MODE_21);
+       tmp &= 0x0000ffff;
+       tmp |= 0x00fa0000;
+       mvs_cw32(mvi, CMD_PHY_MODE_21, tmp);
+
+       tmp = mvs_cr32(mvi, CMD_PHY_TIMER);
+       tmp &= 0x1fffffff;
+       tmp |= (2U << 29);      /* 8 ms retry */
+       mvs_cw32(mvi, CMD_PHY_TIMER, tmp);
+}
+
+static inline void mvs_int_sata(struct mvs_info *mvi)
+{
+       u32 tmp;
+       void __iomem *regs = mvi->regs;
+       tmp = mr32(MVS_INT_STAT_SRS_0);
+       if (tmp)
+               mw32(MVS_INT_STAT_SRS_0, tmp);
+       MVS_CHIP_DISP->clear_active_cmds(mvi);
+}
+
+static inline void mvs_int_full(struct mvs_info *mvi)
+{
+       void __iomem *regs = mvi->regs;
+       u32 tmp, stat;
+       int i;
+
+       stat = mr32(MVS_INT_STAT);
+       mvs_int_rx(mvi, false);
+
+       for (i = 0; i < mvi->chip->n_phy; i++) {
+               tmp = (stat >> i) & (CINT_PORT | CINT_PORT_STOPPED);
+               if (tmp)
+                       mvs_int_port(mvi, i, tmp);
+       }
+
+       if (stat & CINT_SRS)
+               mvs_int_sata(mvi);
+
+       mw32(MVS_INT_STAT, stat);
+}
+
+static inline void mvs_start_delivery(struct mvs_info *mvi, u32 tx)
+{
+       void __iomem *regs = mvi->regs;
+       mw32(MVS_TX_PROD_IDX, tx);
+}
+
+static inline u32 mvs_rx_update(struct mvs_info *mvi)
+{
+       void __iomem *regs = mvi->regs;
+       return mr32(MVS_RX_CONS_IDX);
+}
+
+static inline u32 mvs_get_prd_size(void)
+{
+       return sizeof(struct mvs_prd);
+}
+
+static inline u32 mvs_get_prd_count(void)
+{
+       return MAX_SG_ENTRY;
+}
+
+static inline void mvs_show_pcie_usage(struct mvs_info *mvi)
+{
+       u16 link_stat, link_spd;
+       const char *spd[] = {
+               "UnKnown",
+               "2.5",
+               "5.0",
+       };
+       if (mvi->flags & MVF_FLAG_SOC || mvi->id > 0)
+               return;
+
+       pci_read_config_word(mvi->pdev, PCR_LINK_STAT, &link_stat);
+       link_spd = (link_stat & PLS_LINK_SPD) >> PLS_LINK_SPD_OFFS;
+       if (link_spd >= 3)
+               link_spd = 0;
+       dev_printk(KERN_INFO, mvi->dev,
+               "mvsas: PCI-E x%u, Bandwidth Usage: %s Gbps\n",
+              (link_stat & PLS_NEG_LINK_WD) >> PLS_NEG_LINK_WD_OFFS,
+              spd[link_spd]);
+}
+
+static inline u32 mvs_hw_max_link_rate(void)
+{
+       return MAX_LINK_RATE;
+}
+
+#endif  /* _MV_CHIPS_H_ */
+
diff --git a/drivers/scsi/mvsas/mv_defs.h b/drivers/scsi/mvsas/mv_defs.h
new file mode 100644 (file)
index 0000000..f8cb9de
--- /dev/null
@@ -0,0 +1,502 @@
+/*
+ * Marvell 88SE64xx/88SE94xx const head file
+ *
+ * Copyright 2007 Red Hat, Inc.
+ * Copyright 2008 Marvell. <kewei@marvell.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+*/
+
+#ifndef _MV_DEFS_H_
+#define _MV_DEFS_H_
+
+
+enum chip_flavors {
+       chip_6320,
+       chip_6440,
+       chip_6485,
+       chip_9480,
+       chip_9180,
+};
+
+/* driver compile-time configuration */
+enum driver_configuration {
+       MVS_SLOTS               = 512,  /* command slots */
+       MVS_TX_RING_SZ          = 1024, /* TX ring size (12-bit) */
+       MVS_RX_RING_SZ          = 1024, /* RX ring size (12-bit) */
+                                       /* software requires power-of-2
+                                          ring size */
+       MVS_SOC_SLOTS           = 64,
+       MVS_SOC_TX_RING_SZ      = MVS_SOC_SLOTS * 2,
+       MVS_SOC_RX_RING_SZ      = MVS_SOC_SLOTS * 2,
+
+       MVS_SLOT_BUF_SZ         = 8192, /* cmd tbl + IU + status + PRD */
+       MVS_SSP_CMD_SZ          = 64,   /* SSP command table buffer size */
+       MVS_ATA_CMD_SZ          = 96,   /* SATA command table buffer size */
+       MVS_OAF_SZ              = 64,   /* Open address frame buffer size */
+       MVS_QUEUE_SIZE  = 32,   /* Support Queue depth */
+       MVS_CAN_QUEUE           = MVS_SLOTS - 2,        /* SCSI Queue depth */
+       MVS_SOC_CAN_QUEUE       = MVS_SOC_SLOTS - 2,
+};
+
+/* unchangeable hardware details */
+enum hardware_details {
+       MVS_MAX_PHYS            = 8,    /* max. possible phys */
+       MVS_MAX_PORTS           = 8,    /* max. possible ports */
+       MVS_SOC_PHYS            = 4,    /* soc phys */
+       MVS_SOC_PORTS           = 4,    /* soc phys */
+       MVS_MAX_DEVICES = 1024, /* max supported device */
+};
+
+/* peripheral registers (BAR2) */
+enum peripheral_registers {
+       SPI_CTL                 = 0x10, /* EEPROM control */
+       SPI_CMD                 = 0x14, /* EEPROM command */
+       SPI_DATA                = 0x18, /* EEPROM data */
+};
+
+enum peripheral_register_bits {
+       TWSI_RDY                = (1U << 7),    /* EEPROM interface ready */
+       TWSI_RD                 = (1U << 4),    /* EEPROM read access */
+
+       SPI_ADDR_MASK           = 0x3ffff,      /* bits 17:0 */
+};
+
+enum hw_register_bits {
+       /* MVS_GBL_CTL */
+       INT_EN                  = (1U << 1),    /* Global int enable */
+       HBA_RST                 = (1U << 0),    /* HBA reset */
+
+       /* MVS_GBL_INT_STAT */
+       INT_XOR                 = (1U << 4),    /* XOR engine event */
+       INT_SAS_SATA            = (1U << 0),    /* SAS/SATA event */
+
+       /* MVS_GBL_PORT_TYPE */                 /* shl for ports 1-3 */
+       SATA_TARGET             = (1U << 16),   /* port0 SATA target enable */
+       MODE_AUTO_DET_PORT7 = (1U << 15),       /* port0 SAS/SATA autodetect */
+       MODE_AUTO_DET_PORT6 = (1U << 14),
+       MODE_AUTO_DET_PORT5 = (1U << 13),
+       MODE_AUTO_DET_PORT4 = (1U << 12),
+       MODE_AUTO_DET_PORT3 = (1U << 11),
+       MODE_AUTO_DET_PORT2 = (1U << 10),
+       MODE_AUTO_DET_PORT1 = (1U << 9),
+       MODE_AUTO_DET_PORT0 = (1U << 8),
+       MODE_AUTO_DET_EN    =   MODE_AUTO_DET_PORT0 | MODE_AUTO_DET_PORT1 |
+                               MODE_AUTO_DET_PORT2 | MODE_AUTO_DET_PORT3 |
+                               MODE_AUTO_DET_PORT4 | MODE_AUTO_DET_PORT5 |
+                               MODE_AUTO_DET_PORT6 | MODE_AUTO_DET_PORT7,
+       MODE_SAS_PORT7_MASK = (1U << 7),  /* port0 SAS(1), SATA(0) mode */
+       MODE_SAS_PORT6_MASK = (1U << 6),
+       MODE_SAS_PORT5_MASK = (1U << 5),
+       MODE_SAS_PORT4_MASK = (1U << 4),
+       MODE_SAS_PORT3_MASK = (1U << 3),
+       MODE_SAS_PORT2_MASK = (1U << 2),
+       MODE_SAS_PORT1_MASK = (1U << 1),
+       MODE_SAS_PORT0_MASK = (1U << 0),
+       MODE_SAS_SATA   =       MODE_SAS_PORT0_MASK | MODE_SAS_PORT1_MASK |
+                               MODE_SAS_PORT2_MASK | MODE_SAS_PORT3_MASK |
+                               MODE_SAS_PORT4_MASK | MODE_SAS_PORT5_MASK |
+                               MODE_SAS_PORT6_MASK | MODE_SAS_PORT7_MASK,
+
+                               /* SAS_MODE value may be
+                                * dictated (in hw) by values
+                                * of SATA_TARGET & AUTO_DET
+                                */
+
+       /* MVS_TX_CFG */
+       TX_EN                   = (1U << 16),   /* Enable TX */
+       TX_RING_SZ_MASK         = 0xfff,        /* TX ring size, bits 11:0 */
+
+       /* MVS_RX_CFG */
+       RX_EN                   = (1U << 16),   /* Enable RX */
+       RX_RING_SZ_MASK         = 0xfff,        /* RX ring size, bits 11:0 */
+
+       /* MVS_INT_COAL */
+       COAL_EN                 = (1U << 16),   /* Enable int coalescing */
+
+       /* MVS_INT_STAT, MVS_INT_MASK */
+       CINT_I2C                = (1U << 31),   /* I2C event */
+       CINT_SW0                = (1U << 30),   /* software event 0 */
+       CINT_SW1                = (1U << 29),   /* software event 1 */
+       CINT_PRD_BC             = (1U << 28),   /* PRD BC err for read cmd */
+       CINT_DMA_PCIE           = (1U << 27),   /* DMA to PCIE timeout */
+       CINT_MEM                = (1U << 26),   /* int mem parity err */
+       CINT_I2C_SLAVE          = (1U << 25),   /* slave I2C event */
+       CINT_SRS                = (1U << 3),    /* SRS event */
+       CINT_CI_STOP            = (1U << 1),    /* cmd issue stopped */
+       CINT_DONE               = (1U << 0),    /* cmd completion */
+
+                                               /* shl for ports 1-3 */
+       CINT_PORT_STOPPED       = (1U << 16),   /* port0 stopped */
+       CINT_PORT               = (1U << 8),    /* port0 event */
+       CINT_PORT_MASK_OFFSET   = 8,
+       CINT_PORT_MASK          = (0xFF << CINT_PORT_MASK_OFFSET),
+       CINT_PHY_MASK_OFFSET    = 4,
+       CINT_PHY_MASK           = (0x0F << CINT_PHY_MASK_OFFSET),
+
+       /* TX (delivery) ring bits */
+       TXQ_CMD_SHIFT           = 29,
+       TXQ_CMD_SSP             = 1,            /* SSP protocol */
+       TXQ_CMD_SMP             = 2,            /* SMP protocol */
+       TXQ_CMD_STP             = 3,            /* STP/SATA protocol */
+       TXQ_CMD_SSP_FREE_LIST   = 4,            /* add to SSP targ free list */
+       TXQ_CMD_SLOT_RESET      = 7,            /* reset command slot */
+       TXQ_MODE_I              = (1U << 28),   /* mode: 0=target,1=initiator */
+       TXQ_MODE_TARGET         = 0,
+       TXQ_MODE_INITIATOR      = 1,
+       TXQ_PRIO_HI             = (1U << 27),   /* priority: 0=normal, 1=high */
+       TXQ_PRI_NORMAL          = 0,
+       TXQ_PRI_HIGH            = 1,
+       TXQ_SRS_SHIFT           = 20,           /* SATA register set */
+       TXQ_SRS_MASK            = 0x7f,
+       TXQ_PHY_SHIFT           = 12,           /* PHY bitmap */
+       TXQ_PHY_MASK            = 0xff,
+       TXQ_SLOT_MASK           = 0xfff,        /* slot number */
+
+       /* RX (completion) ring bits */
+       RXQ_GOOD                = (1U << 23),   /* Response good */
+       RXQ_SLOT_RESET          = (1U << 21),   /* Slot reset complete */
+       RXQ_CMD_RX              = (1U << 20),   /* target cmd received */
+       RXQ_ATTN                = (1U << 19),   /* attention */
+       RXQ_RSP                 = (1U << 18),   /* response frame xfer'd */
+       RXQ_ERR                 = (1U << 17),   /* err info rec xfer'd */
+       RXQ_DONE                = (1U << 16),   /* cmd complete */
+       RXQ_SLOT_MASK           = 0xfff,        /* slot number */
+
+       /* mvs_cmd_hdr bits */
+       MCH_PRD_LEN_SHIFT       = 16,           /* 16-bit PRD table len */
+       MCH_SSP_FR_TYPE_SHIFT   = 13,           /* SSP frame type */
+
+                                               /* SSP initiator only */
+       MCH_SSP_FR_CMD          = 0x0,          /* COMMAND frame */
+
+                                               /* SSP initiator or target */
+       MCH_SSP_FR_TASK         = 0x1,          /* TASK frame */
+
+                                               /* SSP target only */
+       MCH_SSP_FR_XFER_RDY     = 0x4,          /* XFER_RDY frame */
+       MCH_SSP_FR_RESP         = 0x5,          /* RESPONSE frame */
+       MCH_SSP_FR_READ         = 0x6,          /* Read DATA frame(s) */
+       MCH_SSP_FR_READ_RESP    = 0x7,          /* ditto, plus RESPONSE */
+
+       MCH_SSP_MODE_PASSTHRU   = 1,
+       MCH_SSP_MODE_NORMAL     = 0,
+       MCH_PASSTHRU            = (1U << 12),   /* pass-through (SSP) */
+       MCH_FBURST              = (1U << 11),   /* first burst (SSP) */
+       MCH_CHK_LEN             = (1U << 10),   /* chk xfer len (SSP) */
+       MCH_RETRY               = (1U << 9),    /* tport layer retry (SSP) */
+       MCH_PROTECTION          = (1U << 8),    /* protection info rec (SSP) */
+       MCH_RESET               = (1U << 7),    /* Reset (STP/SATA) */
+       MCH_FPDMA               = (1U << 6),    /* First party DMA (STP/SATA) */
+       MCH_ATAPI               = (1U << 5),    /* ATAPI (STP/SATA) */
+       MCH_BIST                = (1U << 4),    /* BIST activate (STP/SATA) */
+       MCH_PMP_MASK            = 0xf,          /* PMP from cmd FIS (STP/SATA)*/
+
+       CCTL_RST                = (1U << 5),    /* port logic reset */
+
+                                               /* 0(LSB first), 1(MSB first) */
+       CCTL_ENDIAN_DATA        = (1U << 3),    /* PRD data */
+       CCTL_ENDIAN_RSP         = (1U << 2),    /* response frame */
+       CCTL_ENDIAN_OPEN        = (1U << 1),    /* open address frame */
+       CCTL_ENDIAN_CMD         = (1U << 0),    /* command table */
+
+       /* MVS_Px_SER_CTLSTAT (per-phy control) */
+       PHY_SSP_RST             = (1U << 3),    /* reset SSP link layer */
+       PHY_BCAST_CHG           = (1U << 2),    /* broadcast(change) notif */
+       PHY_RST_HARD            = (1U << 1),    /* hard reset + phy reset */
+       PHY_RST                 = (1U << 0),    /* phy reset */
+       PHY_READY_MASK          = (1U << 20),
+
+       /* MVS_Px_INT_STAT, MVS_Px_INT_MASK (per-phy events) */
+       PHYEV_DEC_ERR           = (1U << 24),   /* Phy Decoding Error */
+       PHYEV_DCDR_ERR          = (1U << 23),   /* STP Deocder Error */
+       PHYEV_CRC_ERR           = (1U << 22),   /* STP CRC Error */
+       PHYEV_UNASSOC_FIS       = (1U << 19),   /* unassociated FIS rx'd */
+       PHYEV_AN                = (1U << 18),   /* SATA async notification */
+       PHYEV_BIST_ACT          = (1U << 17),   /* BIST activate FIS */
+       PHYEV_SIG_FIS           = (1U << 16),   /* signature FIS */
+       PHYEV_POOF              = (1U << 12),   /* phy ready from 1 -> 0 */
+       PHYEV_IU_BIG            = (1U << 11),   /* IU too long err */
+       PHYEV_IU_SMALL          = (1U << 10),   /* IU too short err */
+       PHYEV_UNK_TAG           = (1U << 9),    /* unknown tag */
+       PHYEV_BROAD_CH          = (1U << 8),    /* broadcast(CHANGE) */
+       PHYEV_COMWAKE           = (1U << 7),    /* COMWAKE rx'd */
+       PHYEV_PORT_SEL          = (1U << 6),    /* port selector present */
+       PHYEV_HARD_RST          = (1U << 5),    /* hard reset rx'd */
+       PHYEV_ID_TMOUT          = (1U << 4),    /* identify timeout */
+       PHYEV_ID_FAIL           = (1U << 3),    /* identify failed */
+       PHYEV_ID_DONE           = (1U << 2),    /* identify done */
+       PHYEV_HARD_RST_DONE     = (1U << 1),    /* hard reset done */
+       PHYEV_RDY_CH            = (1U << 0),    /* phy ready changed state */
+
+       /* MVS_PCS */
+       PCS_EN_SATA_REG_SHIFT   = (16),         /* Enable SATA Register Set */
+       PCS_EN_PORT_XMT_SHIFT   = (12),         /* Enable Port Transmit */
+       PCS_EN_PORT_XMT_SHIFT2  = (8),          /* For 6485 */
+       PCS_SATA_RETRY          = (1U << 8),    /* retry ctl FIS on R_ERR */
+       PCS_RSP_RX_EN           = (1U << 7),    /* raw response rx */
+       PCS_SATA_RETRY_2        = (1U << 6),    /* For 9180 */
+       PCS_SELF_CLEAR          = (1U << 5),    /* self-clearing int mode */
+       PCS_FIS_RX_EN           = (1U << 4),    /* FIS rx enable */
+       PCS_CMD_STOP_ERR        = (1U << 3),    /* cmd stop-on-err enable */
+       PCS_CMD_RST             = (1U << 1),    /* reset cmd issue */
+       PCS_CMD_EN              = (1U << 0),    /* enable cmd issue */
+
+       /* Port n Attached Device Info */
+       PORT_DEV_SSP_TRGT       = (1U << 19),
+       PORT_DEV_SMP_TRGT       = (1U << 18),
+       PORT_DEV_STP_TRGT       = (1U << 17),
+       PORT_DEV_SSP_INIT       = (1U << 11),
+       PORT_DEV_SMP_INIT       = (1U << 10),
+       PORT_DEV_STP_INIT       = (1U << 9),
+       PORT_PHY_ID_MASK        = (0xFFU << 24),
+       PORT_SSP_TRGT_MASK      = (0x1U << 19),
+       PORT_SSP_INIT_MASK      = (0x1U << 11),
+       PORT_DEV_TRGT_MASK      = (0x7U << 17),
+       PORT_DEV_INIT_MASK      = (0x7U << 9),
+       PORT_DEV_TYPE_MASK      = (0x7U << 0),
+
+       /* Port n PHY Status */
+       PHY_RDY                 = (1U << 2),
+       PHY_DW_SYNC             = (1U << 1),
+       PHY_OOB_DTCTD           = (1U << 0),
+
+       /* VSR */
+       /* PHYMODE 6 (CDB) */
+       PHY_MODE6_LATECLK       = (1U << 29),   /* Lock Clock */
+       PHY_MODE6_DTL_SPEED     = (1U << 27),   /* Digital Loop Speed */
+       PHY_MODE6_FC_ORDER      = (1U << 26),   /* Fibre Channel Mode Order*/
+       PHY_MODE6_MUCNT_EN      = (1U << 24),   /* u Count Enable */
+       PHY_MODE6_SEL_MUCNT_LEN = (1U << 22),   /* Training Length Select */
+       PHY_MODE6_SELMUPI       = (1U << 20),   /* Phase Multi Select (init) */
+       PHY_MODE6_SELMUPF       = (1U << 18),   /* Phase Multi Select (final) */
+       PHY_MODE6_SELMUFF       = (1U << 16),   /* Freq Loop Multi Sel(final) */
+       PHY_MODE6_SELMUFI       = (1U << 14),   /* Freq Loop Multi Sel(init) */
+       PHY_MODE6_FREEZE_LOOP   = (1U << 12),   /* Freeze Rx CDR Loop */
+       PHY_MODE6_INT_RXFOFFS   = (1U << 3),    /* Rx CDR Freq Loop Enable */
+       PHY_MODE6_FRC_RXFOFFS   = (1U << 2),    /* Initial Rx CDR Offset */
+       PHY_MODE6_STAU_0D8      = (1U << 1),    /* Rx CDR Freq Loop Saturate */
+       PHY_MODE6_RXSAT_DIS     = (1U << 0),    /* Saturate Ctl */
+};
+
+/* SAS/SATA configuration port registers, aka phy registers */
+enum sas_sata_config_port_regs {
+       PHYR_IDENTIFY           = 0x00, /* info for IDENTIFY frame */
+       PHYR_ADDR_LO            = 0x04, /* my SAS address (low) */
+       PHYR_ADDR_HI            = 0x08, /* my SAS address (high) */
+       PHYR_ATT_DEV_INFO       = 0x0C, /* attached device info */
+       PHYR_ATT_ADDR_LO        = 0x10, /* attached dev SAS addr (low) */
+       PHYR_ATT_ADDR_HI        = 0x14, /* attached dev SAS addr (high) */
+       PHYR_SATA_CTL           = 0x18, /* SATA control */
+       PHYR_PHY_STAT           = 0x1C, /* PHY status */
+       PHYR_SATA_SIG0  = 0x20, /*port SATA signature FIS(Byte 0-3) */
+       PHYR_SATA_SIG1  = 0x24, /*port SATA signature FIS(Byte 4-7) */
+       PHYR_SATA_SIG2  = 0x28, /*port SATA signature FIS(Byte 8-11) */
+       PHYR_SATA_SIG3  = 0x2c, /*port SATA signature FIS(Byte 12-15) */
+       PHYR_R_ERR_COUNT        = 0x30, /* port R_ERR count register */
+       PHYR_CRC_ERR_COUNT      = 0x34, /* port CRC error count register */
+       PHYR_WIDE_PORT  = 0x38, /* wide port participating */
+       PHYR_CURRENT0           = 0x80, /* current connection info 0 */
+       PHYR_CURRENT1           = 0x84, /* current connection info 1 */
+       PHYR_CURRENT2           = 0x88, /* current connection info 2 */
+       CONFIG_ID_FRAME0       = 0x100, /* Port device ID frame register 0 */
+       CONFIG_ID_FRAME1       = 0x104, /* Port device ID frame register 1 */
+       CONFIG_ID_FRAME2       = 0x108, /* Port device ID frame register 2 */
+       CONFIG_ID_FRAME3       = 0x10c, /* Port device ID frame register 3 */
+       CONFIG_ID_FRAME4       = 0x110, /* Port device ID frame register 4 */
+       CONFIG_ID_FRAME5       = 0x114, /* Port device ID frame register 5 */
+       CONFIG_ID_FRAME6       = 0x118, /* Port device ID frame register 6 */
+       CONFIG_ATT_ID_FRAME0   = 0x11c, /* attached ID frame register 0 */
+       CONFIG_ATT_ID_FRAME1   = 0x120, /* attached ID frame register 1 */
+       CONFIG_ATT_ID_FRAME2   = 0x124, /* attached ID frame register 2 */
+       CONFIG_ATT_ID_FRAME3   = 0x128, /* attached ID frame register 3 */
+       CONFIG_ATT_ID_FRAME4   = 0x12c, /* attached ID frame register 4 */
+       CONFIG_ATT_ID_FRAME5   = 0x130, /* attached ID frame register 5 */
+       CONFIG_ATT_ID_FRAME6   = 0x134, /* attached ID frame register 6 */
+};
+
+enum sas_cmd_port_registers {
+       CMD_CMRST_OOB_DET       = 0x100, /* COMRESET OOB detect register */
+       CMD_CMWK_OOB_DET        = 0x104, /* COMWAKE OOB detect register */
+       CMD_CMSAS_OOB_DET       = 0x108, /* COMSAS OOB detect register */
+       CMD_BRST_OOB_DET        = 0x10c, /* burst OOB detect register */
+       CMD_OOB_SPACE   = 0x110, /* OOB space control register */
+       CMD_OOB_BURST   = 0x114, /* OOB burst control register */
+       CMD_PHY_TIMER           = 0x118, /* PHY timer control register */
+       CMD_PHY_CONFIG0 = 0x11c, /* PHY config register 0 */
+       CMD_PHY_CONFIG1 = 0x120, /* PHY config register 1 */
+       CMD_SAS_CTL0            = 0x124, /* SAS control register 0 */
+       CMD_SAS_CTL1            = 0x128, /* SAS control register 1 */
+       CMD_SAS_CTL2            = 0x12c, /* SAS control register 2 */
+       CMD_SAS_CTL3            = 0x130, /* SAS control register 3 */
+       CMD_ID_TEST             = 0x134, /* ID test register */
+       CMD_PL_TIMER            = 0x138, /* PL timer register */
+       CMD_WD_TIMER            = 0x13c, /* WD timer register */
+       CMD_PORT_SEL_COUNT      = 0x140, /* port selector count register */
+       CMD_APP_MEM_CTL = 0x144, /* Application Memory Control */
+       CMD_XOR_MEM_CTL = 0x148, /* XOR Block Memory Control */
+       CMD_DMA_MEM_CTL = 0x14c, /* DMA Block Memory Control */
+       CMD_PORT_MEM_CTL0       = 0x150, /* Port Memory Control 0 */
+       CMD_PORT_MEM_CTL1       = 0x154, /* Port Memory Control 1 */
+       CMD_SATA_PORT_MEM_CTL0  = 0x158, /* SATA Port Memory Control 0 */
+       CMD_SATA_PORT_MEM_CTL1  = 0x15c, /* SATA Port Memory Control 1 */
+       CMD_XOR_MEM_BIST_CTL    = 0x160, /* XOR Memory BIST Control */
+       CMD_XOR_MEM_BIST_STAT   = 0x164, /* XOR Memroy BIST Status */
+       CMD_DMA_MEM_BIST_CTL    = 0x168, /* DMA Memory BIST Control */
+       CMD_DMA_MEM_BIST_STAT   = 0x16c, /* DMA Memory BIST Status */
+       CMD_PORT_MEM_BIST_CTL   = 0x170, /* Port Memory BIST Control */
+       CMD_PORT_MEM_BIST_STAT0 = 0x174, /* Port Memory BIST Status 0 */
+       CMD_PORT_MEM_BIST_STAT1 = 0x178, /* Port Memory BIST Status 1 */
+       CMD_STP_MEM_BIST_CTL    = 0x17c, /* STP Memory BIST Control */
+       CMD_STP_MEM_BIST_STAT0  = 0x180, /* STP Memory BIST Status 0 */
+       CMD_STP_MEM_BIST_STAT1  = 0x184, /* STP Memory BIST Status 1 */
+       CMD_RESET_COUNT         = 0x188, /* Reset Count */
+       CMD_MONTR_DATA_SEL      = 0x18C, /* Monitor Data/Select */
+       CMD_PLL_PHY_CONFIG      = 0x190, /* PLL/PHY Configuration */
+       CMD_PHY_CTL             = 0x194, /* PHY Control and Status */
+       CMD_PHY_TEST_COUNT0     = 0x198, /* Phy Test Count 0 */
+       CMD_PHY_TEST_COUNT1     = 0x19C, /* Phy Test Count 1 */
+       CMD_PHY_TEST_COUNT2     = 0x1A0, /* Phy Test Count 2 */
+       CMD_APP_ERR_CONFIG      = 0x1A4, /* Application Error Configuration */
+       CMD_PND_FIFO_CTL0       = 0x1A8, /* Pending FIFO Control 0 */
+       CMD_HOST_CTL            = 0x1AC, /* Host Control Status */
+       CMD_HOST_WR_DATA        = 0x1B0, /* Host Write Data */
+       CMD_HOST_RD_DATA        = 0x1B4, /* Host Read Data */
+       CMD_PHY_MODE_21         = 0x1B8, /* Phy Mode 21 */
+       CMD_SL_MODE0            = 0x1BC, /* SL Mode 0 */
+       CMD_SL_MODE1            = 0x1C0, /* SL Mode 1 */
+       CMD_PND_FIFO_CTL1       = 0x1C4, /* Pending FIFO Control 1 */
+};
+
+enum mvs_info_flags {
+       MVF_MSI         = (1U << 0),    /* MSI is enabled */
+       MVF_PHY_PWR_FIX = (1U << 1),    /* bug workaround */
+       MVF_FLAG_SOC            = (1U << 2),    /* SoC integrated controllers */
+};
+
+enum mvs_event_flags {
+       PHY_PLUG_EVENT  = (3U),
+       PHY_PLUG_IN             = (1U << 0),    /* phy plug in */
+       PHY_PLUG_OUT            = (1U << 1),    /* phy plug out */
+};
+
+enum mvs_port_type {
+       PORT_TGT_MASK   =  (1U << 5),
+       PORT_INIT_PORT  =  (1U << 4),
+       PORT_TGT_PORT   =  (1U << 3),
+       PORT_INIT_TGT_PORT = (PORT_INIT_PORT | PORT_TGT_PORT),
+       PORT_TYPE_SAS   =  (1U << 1),
+       PORT_TYPE_SATA  =  (1U << 0),
+};
+
+/* Command Table Format */
+enum ct_format {
+       /* SSP */
+       SSP_F_H         =  0x00,
+       SSP_F_IU        =  0x18,
+       SSP_F_MAX       =  0x4D,
+       /* STP */
+       STP_CMD_FIS     =  0x00,
+       STP_ATAPI_CMD   =  0x40,
+       STP_F_MAX       =  0x10,
+       /* SMP */
+       SMP_F_T         =  0x00,
+       SMP_F_DEP       =  0x01,
+       SMP_F_MAX       =  0x101,
+};
+
+enum status_buffer {
+       SB_EIR_OFF      =  0x00,        /* Error Information Record */
+       SB_RFB_OFF      =  0x08,        /* Response Frame Buffer */
+       SB_RFB_MAX      =  0x400,       /* RFB size*/
+};
+
+enum error_info_rec {
+       CMD_ISS_STPD    = (1U << 31),   /* Cmd Issue Stopped */
+       CMD_PI_ERR      = (1U << 30),   /* Protection info error.  see flags2 */
+       RSP_OVER        = (1U << 29),   /* rsp buffer overflow */
+       RETRY_LIM       = (1U << 28),   /* FIS/frame retry limit exceeded */
+       UNK_FIS         = (1U << 27),   /* unknown FIS */
+       DMA_TERM        = (1U << 26),   /* DMA terminate primitive rx'd */
+       SYNC_ERR        = (1U << 25),   /* SYNC rx'd during frame xmit */
+       TFILE_ERR       = (1U << 24),   /* SATA taskfile Error bit set */
+       R_ERR           = (1U << 23),   /* SATA returned R_ERR prim */
+       RD_OFS          = (1U << 20),   /* Read DATA frame invalid offset */
+       XFER_RDY_OFS    = (1U << 19),   /* XFER_RDY offset error */
+       UNEXP_XFER_RDY  = (1U << 18),   /* unexpected XFER_RDY error */
+       DATA_OVER_UNDER = (1U << 16),   /* data overflow/underflow */
+       INTERLOCK       = (1U << 15),   /* interlock error */
+       NAK             = (1U << 14),   /* NAK rx'd */
+       ACK_NAK_TO      = (1U << 13),   /* ACK/NAK timeout */
+       CXN_CLOSED      = (1U << 12),   /* cxn closed w/out ack/nak */
+       OPEN_TO         = (1U << 11),   /* I_T nexus lost, open cxn timeout */
+       PATH_BLOCKED    = (1U << 10),   /* I_T nexus lost, pathway blocked */
+       NO_DEST         = (1U << 9),    /* I_T nexus lost, no destination */
+       STP_RES_BSY     = (1U << 8),    /* STP resources busy */
+       BREAK           = (1U << 7),    /* break received */
+       BAD_DEST        = (1U << 6),    /* bad destination */
+       BAD_PROTO       = (1U << 5),    /* protocol not supported */
+       BAD_RATE        = (1U << 4),    /* cxn rate not supported */
+       WRONG_DEST      = (1U << 3),    /* wrong destination error */
+       CREDIT_TO       = (1U << 2),    /* credit timeout */
+       WDOG_TO         = (1U << 1),    /* watchdog timeout */
+       BUF_PAR         = (1U << 0),    /* buffer parity error */
+};
+
+enum error_info_rec_2 {
+       SLOT_BSY_ERR    = (1U << 31),   /* Slot Busy Error */
+       GRD_CHK_ERR     = (1U << 14),   /* Guard Check Error */
+       APP_CHK_ERR     = (1U << 13),   /* Application Check error */
+       REF_CHK_ERR     = (1U << 12),   /* Reference Check Error */
+       USR_BLK_NM      = (1U << 0),    /* User Block Number */
+};
+
+enum pci_cfg_register_bits {
+       PCTL_PWR_OFF    = (0xFU << 24),
+       PCTL_COM_ON     = (0xFU << 20),
+       PCTL_LINK_RST   = (0xFU << 16),
+       PCTL_LINK_OFFS  = (16),
+       PCTL_PHY_DSBL   = (0xFU << 12),
+       PCTL_PHY_DSBL_OFFS      = (12),
+       PRD_REQ_SIZE    = (0x4000),
+       PRD_REQ_MASK    = (0x00007000),
+       PLS_NEG_LINK_WD         = (0x3FU << 4),
+       PLS_NEG_LINK_WD_OFFS    = 4,
+       PLS_LINK_SPD            = (0x0FU << 0),
+       PLS_LINK_SPD_OFFS       = 0,
+};
+
+enum open_frame_protocol {
+       PROTOCOL_SMP    = 0x0,
+       PROTOCOL_SSP    = 0x1,
+       PROTOCOL_STP    = 0x2,
+};
+
+/* define for response frame datapres field */
+enum datapres_field {
+       NO_DATA         = 0,
+       RESPONSE_DATA   = 1,
+       SENSE_DATA      = 2,
+};
+
+/* define task management IU */
+struct mvs_tmf_task{
+       u8 tmf;
+       u16 tag_of_task_to_be_managed;
+};
+#endif
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c
new file mode 100644 (file)
index 0000000..8646a19
--- /dev/null
@@ -0,0 +1,703 @@
+/*
+ * Marvell 88SE64xx/88SE94xx pci init
+ *
+ * Copyright 2007 Red Hat, Inc.
+ * Copyright 2008 Marvell. <kewei@marvell.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+*/
+
+
+#include "mv_sas.h"
+
+static struct scsi_transport_template *mvs_stt;
+static const struct mvs_chip_info mvs_chips[] = {
+       [chip_6320] =   { 1, 2, 0x400, 17, 16,  9, &mvs_64xx_dispatch, },
+       [chip_6440] =   { 1, 4, 0x400, 17, 16,  9, &mvs_64xx_dispatch, },
+       [chip_6485] =   { 1, 8, 0x800, 33, 32, 10, &mvs_64xx_dispatch, },
+       [chip_9180] =   { 2, 4, 0x800, 17, 64,  9, &mvs_94xx_dispatch, },
+       [chip_9480] =   { 2, 4, 0x800, 17, 64,  9, &mvs_94xx_dispatch, },
+};
+
+#define SOC_SAS_NUM 2
+
+static struct scsi_host_template mvs_sht = {
+       .module                 = THIS_MODULE,
+       .name                   = DRV_NAME,
+       .queuecommand           = sas_queuecommand,
+       .target_alloc           = sas_target_alloc,
+       .slave_configure        = mvs_slave_configure,
+       .slave_destroy          = sas_slave_destroy,
+       .scan_finished          = mvs_scan_finished,
+       .scan_start             = mvs_scan_start,
+       .change_queue_depth     = sas_change_queue_depth,
+       .change_queue_type      = sas_change_queue_type,
+       .bios_param             = sas_bios_param,
+       .can_queue              = 1,
+       .cmd_per_lun            = 1,
+       .this_id                = -1,
+       .sg_tablesize           = SG_ALL,
+       .max_sectors            = SCSI_DEFAULT_MAX_SECTORS,
+       .use_clustering         = ENABLE_CLUSTERING,
+       .eh_device_reset_handler        = sas_eh_device_reset_handler,
+       .eh_bus_reset_handler   = sas_eh_bus_reset_handler,
+       .slave_alloc            = mvs_slave_alloc,
+       .target_destroy         = sas_target_destroy,
+       .ioctl                  = sas_ioctl,
+};
+
+static struct sas_domain_function_template mvs_transport_ops = {
+       .lldd_dev_found         = mvs_dev_found,
+       .lldd_dev_gone  = mvs_dev_gone,
+
+       .lldd_execute_task      = mvs_queue_command,
+       .lldd_control_phy       = mvs_phy_control,
+
+       .lldd_abort_task        = mvs_abort_task,
+       .lldd_abort_task_set    = mvs_abort_task_set,
+       .lldd_clear_aca         = mvs_clear_aca,
+       .lldd_clear_task_set    = mvs_clear_task_set,
+       .lldd_I_T_nexus_reset   = mvs_I_T_nexus_reset,
+       .lldd_lu_reset          = mvs_lu_reset,
+       .lldd_query_task        = mvs_query_task,
+
+       .lldd_port_formed       = mvs_port_formed,
+       .lldd_port_deformed     = mvs_port_deformed,
+
+};
+
+static void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id)
+{
+       struct mvs_phy *phy = &mvi->phy[phy_id];
+       struct asd_sas_phy *sas_phy = &phy->sas_phy;
+
+       phy->mvi = mvi;
+       init_timer(&phy->timer);
+       sas_phy->enabled = (phy_id < mvi->chip->n_phy) ? 1 : 0;
+       sas_phy->class = SAS;
+       sas_phy->iproto = SAS_PROTOCOL_ALL;
+       sas_phy->tproto = 0;
+       sas_phy->type = PHY_TYPE_PHYSICAL;
+       sas_phy->role = PHY_ROLE_INITIATOR;
+       sas_phy->oob_mode = OOB_NOT_CONNECTED;
+       sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN;
+
+       sas_phy->id = phy_id;
+       sas_phy->sas_addr = &mvi->sas_addr[0];
+       sas_phy->frame_rcvd = &phy->frame_rcvd[0];
+       sas_phy->ha = (struct sas_ha_struct *)mvi->shost->hostdata;
+       sas_phy->lldd_phy = phy;
+}
+
+static void mvs_free(struct mvs_info *mvi)
+{
+       int i;
+       struct mvs_wq *mwq;
+       int slot_nr;
+
+       if (!mvi)
+               return;
+
+       if (mvi->flags & MVF_FLAG_SOC)
+               slot_nr = MVS_SOC_SLOTS;
+       else
+               slot_nr = MVS_SLOTS;
+
+       for (i = 0; i < mvi->tags_num; i++) {
+               struct mvs_slot_info *slot = &mvi->slot_info[i];
+               if (slot->buf)
+                       dma_free_coherent(mvi->dev, MVS_SLOT_BUF_SZ,
+                                         slot->buf, slot->buf_dma);
+       }
+
+       if (mvi->tx)
+               dma_free_coherent(mvi->dev,
+                                 sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ,
+                                 mvi->tx, mvi->tx_dma);
+       if (mvi->rx_fis)
+               dma_free_coherent(mvi->dev, MVS_RX_FISL_SZ,
+                                 mvi->rx_fis, mvi->rx_fis_dma);
+       if (mvi->rx)
+               dma_free_coherent(mvi->dev,
+                                 sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1),
+                                 mvi->rx, mvi->rx_dma);
+       if (mvi->slot)
+               dma_free_coherent(mvi->dev,
+                                 sizeof(*mvi->slot) * slot_nr,
+                                 mvi->slot, mvi->slot_dma);
+#ifndef DISABLE_HOTPLUG_DMA_FIX
+       if (mvi->bulk_buffer)
+               dma_free_coherent(mvi->dev, TRASH_BUCKET_SIZE,
+                                 mvi->bulk_buffer, mvi->bulk_buffer_dma);
+#endif
+
+       MVS_CHIP_DISP->chip_iounmap(mvi);
+       if (mvi->shost)
+               scsi_host_put(mvi->shost);
+       list_for_each_entry(mwq, &mvi->wq_list, entry)
+               cancel_delayed_work(&mwq->work_q);
+       kfree(mvi);
+}
+
+#ifdef MVS_USE_TASKLET
+struct tasklet_struct  mv_tasklet;
+static void mvs_tasklet(unsigned long opaque)
+{
+       unsigned long flags;
+       u32 stat;
+       u16 core_nr, i = 0;
+
+       struct mvs_info *mvi;
+       struct sas_ha_struct *sha = (struct sas_ha_struct *)opaque;
+
+       core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
+       mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0];
+
+       if (unlikely(!mvi))
+               BUG_ON(1);
+
+       for (i = 0; i < core_nr; i++) {
+               mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i];
+               stat = MVS_CHIP_DISP->isr_status(mvi, mvi->irq);
+               if (stat)
+                       MVS_CHIP_DISP->isr(mvi, mvi->irq, stat);
+       }
+
+}
+#endif
+
+static irqreturn_t mvs_interrupt(int irq, void *opaque)
+{
+       u32 core_nr, i = 0;
+       u32 stat;
+       struct mvs_info *mvi;
+       struct sas_ha_struct *sha = opaque;
+
+       core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
+       mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0];
+
+       if (unlikely(!mvi))
+               return IRQ_NONE;
+
+       stat = MVS_CHIP_DISP->isr_status(mvi, irq);
+       if (!stat)
+               return IRQ_NONE;
+
+#ifdef MVS_USE_TASKLET
+       tasklet_schedule(&mv_tasklet);
+#else
+       for (i = 0; i < core_nr; i++) {
+               mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i];
+               MVS_CHIP_DISP->isr(mvi, irq, stat);
+       }
+#endif
+       return IRQ_HANDLED;
+}
+
+static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost)
+{
+       int i, slot_nr;
+
+       if (mvi->flags & MVF_FLAG_SOC)
+               slot_nr = MVS_SOC_SLOTS;
+       else
+               slot_nr = MVS_SLOTS;
+
+       spin_lock_init(&mvi->lock);
+       for (i = 0; i < mvi->chip->n_phy; i++) {
+               mvs_phy_init(mvi, i);
+               mvi->port[i].wide_port_phymap = 0;
+               mvi->port[i].port_attached = 0;
+               INIT_LIST_HEAD(&mvi->port[i].list);
+       }
+       for (i = 0; i < MVS_MAX_DEVICES; i++) {
+               mvi->devices[i].taskfileset = MVS_ID_NOT_MAPPED;
+               mvi->devices[i].dev_type = NO_DEVICE;
+               mvi->devices[i].device_id = i;
+               mvi->devices[i].dev_status = MVS_DEV_NORMAL;
+       }
+
+       /*
+        * alloc and init our DMA areas
+        */
+       mvi->tx = dma_alloc_coherent(mvi->dev,
+                                    sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ,
+                                    &mvi->tx_dma, GFP_KERNEL);
+       if (!mvi->tx)
+               goto err_out;
+       memset(mvi->tx, 0, sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ);
+       mvi->rx_fis = dma_alloc_coherent(mvi->dev, MVS_RX_FISL_SZ,
+                                        &mvi->rx_fis_dma, GFP_KERNEL);
+       if (!mvi->rx_fis)
+               goto err_out;
+       memset(mvi->rx_fis, 0, MVS_RX_FISL_SZ);
+
+       mvi->rx = dma_alloc_coherent(mvi->dev,
+                                    sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1),
+                                    &mvi->rx_dma, GFP_KERNEL);
+       if (!mvi->rx)
+               goto err_out;
+       memset(mvi->rx, 0, sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1));
+       mvi->rx[0] = cpu_to_le32(0xfff);
+       mvi->rx_cons = 0xfff;
+
+       mvi->slot = dma_alloc_coherent(mvi->dev,
+                                      sizeof(*mvi->slot) * slot_nr,
+                                      &mvi->slot_dma, GFP_KERNEL);
+       if (!mvi->slot)
+               goto err_out;
+       memset(mvi->slot, 0, sizeof(*mvi->slot) * slot_nr);
+
+#ifndef DISABLE_HOTPLUG_DMA_FIX
+       mvi->bulk_buffer = dma_alloc_coherent(mvi->dev,
+                                      TRASH_BUCKET_SIZE,
+                                      &mvi->bulk_buffer_dma, GFP_KERNEL);
+       if (!mvi->bulk_buffer)
+               goto err_out;
+#endif
+       for (i = 0; i < slot_nr; i++) {
+               struct mvs_slot_info *slot = &mvi->slot_info[i];
+
+               slot->buf = dma_alloc_coherent(mvi->dev, MVS_SLOT_BUF_SZ,
+                                              &slot->buf_dma, GFP_KERNEL);
+               if (!slot->buf) {
+                       printk(KERN_DEBUG"failed to allocate slot->buf.\n");
+                       goto err_out;
+               }
+               memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
+               ++mvi->tags_num;
+       }
+       /* Initialize tags */
+       mvs_tag_init(mvi);
+       return 0;
+err_out:
+       return 1;
+}
+
+
+int mvs_ioremap(struct mvs_info *mvi, int bar, int bar_ex)
+{
+       unsigned long res_start, res_len, res_flag, res_flag_ex = 0;
+       struct pci_dev *pdev = mvi->pdev;
+       if (bar_ex != -1) {
+               /*
+                * ioremap main and peripheral registers
+                */
+               res_start = pci_resource_start(pdev, bar_ex);
+               res_len = pci_resource_len(pdev, bar_ex);
+               if (!res_start || !res_len)
+                       goto err_out;
+
+               res_flag_ex = pci_resource_flags(pdev, bar_ex);
+               if (res_flag_ex & IORESOURCE_MEM) {
+                       if (res_flag_ex & IORESOURCE_CACHEABLE)
+                               mvi->regs_ex = ioremap(res_start, res_len);
+                       else
+                               mvi->regs_ex = ioremap_nocache(res_start,
+                                               res_len);
+               } else
+                       mvi->regs_ex = (void *)res_start;
+               if (!mvi->regs_ex)
+                       goto err_out;
+       }
+
+       res_start = pci_resource_start(pdev, bar);
+       res_len = pci_resource_len(pdev, bar);
+       if (!res_start || !res_len)
+               goto err_out;
+
+       res_flag = pci_resource_flags(pdev, bar);
+       if (res_flag & IORESOURCE_CACHEABLE)
+               mvi->regs = ioremap(res_start, res_len);
+       else
+               mvi->regs = ioremap_nocache(res_start, res_len);
+
+       if (!mvi->regs) {
+               if (mvi->regs_ex && (res_flag_ex & IORESOURCE_MEM))
+                       iounmap(mvi->regs_ex);
+               mvi->regs_ex = NULL;
+               goto err_out;
+       }
+
+       return 0;
+err_out:
+       return -1;
+}
+
+void mvs_iounmap(void __iomem *regs)
+{
+       iounmap(regs);
+}
+
+static struct mvs_info *__devinit mvs_pci_alloc(struct pci_dev *pdev,
+                               const struct pci_device_id *ent,
+                               struct Scsi_Host *shost, unsigned int id)
+{
+       struct mvs_info *mvi;
+       struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+
+       mvi = kzalloc(sizeof(*mvi) + MVS_SLOTS * sizeof(struct mvs_slot_info),
+                       GFP_KERNEL);
+       if (!mvi)
+               return NULL;
+
+       mvi->pdev = pdev;
+       mvi->dev = &pdev->dev;
+       mvi->chip_id = ent->driver_data;
+       mvi->chip = &mvs_chips[mvi->chip_id];
+       INIT_LIST_HEAD(&mvi->wq_list);
+       mvi->irq = pdev->irq;
+
+       ((struct mvs_prv_info *)sha->lldd_ha)->mvi[id] = mvi;
+       ((struct mvs_prv_info *)sha->lldd_ha)->n_phy = mvi->chip->n_phy;
+
+       mvi->id = id;
+       mvi->sas = sha;
+       mvi->shost = shost;
+#ifdef MVS_USE_TASKLET
+       tasklet_init(&mv_tasklet, mvs_tasklet, (unsigned long)sha);
+#endif
+
+       if (MVS_CHIP_DISP->chip_ioremap(mvi))
+               goto err_out;
+       if (!mvs_alloc(mvi, shost))
+               return mvi;
+err_out:
+       mvs_free(mvi);
+       return NULL;
+}
+
+/* move to PCI layer or libata core? */
+static int pci_go_64(struct pci_dev *pdev)
+{
+       int rc;
+
+       if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
+               rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+               if (rc) {
+                       rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+                       if (rc) {
+                               dev_printk(KERN_ERR, &pdev->dev,
+                                          "64-bit DMA enable failed\n");
+                               return rc;
+                       }
+               }
+       } else {
+               rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+               if (rc) {
+                       dev_printk(KERN_ERR, &pdev->dev,
+                                  "32-bit DMA enable failed\n");
+                       return rc;
+               }
+               rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+               if (rc) {
+                       dev_printk(KERN_ERR, &pdev->dev,
+                                  "32-bit consistent DMA enable failed\n");
+                       return rc;
+               }
+       }
+
+       return rc;
+}
+
+static int __devinit mvs_prep_sas_ha_init(struct Scsi_Host *shost,
+                               const struct mvs_chip_info *chip_info)
+{
+       int phy_nr, port_nr; unsigned short core_nr;
+       struct asd_sas_phy **arr_phy;
+       struct asd_sas_port **arr_port;
+       struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+
+       core_nr = chip_info->n_host;
+       phy_nr  = core_nr * chip_info->n_phy;
+       port_nr = phy_nr;
+
+       memset(sha, 0x00, sizeof(struct sas_ha_struct));
+       arr_phy  = kcalloc(phy_nr, sizeof(void *), GFP_KERNEL);
+       arr_port = kcalloc(port_nr, sizeof(void *), GFP_KERNEL);
+       if (!arr_phy || !arr_port)
+               goto exit_free;
+
+       sha->sas_phy = arr_phy;
+       sha->sas_port = arr_port;
+
+       sha->lldd_ha = kzalloc(sizeof(struct mvs_prv_info), GFP_KERNEL);
+       if (!sha->lldd_ha)
+               goto exit_free;
+
+       ((struct mvs_prv_info *)sha->lldd_ha)->n_host = core_nr;
+
+       shost->transportt = mvs_stt;
+       shost->max_id = 128;
+       shost->max_lun = ~0;
+       shost->max_channel = 1;
+       shost->max_cmd_len = 16;
+
+       return 0;
+exit_free:
+       kfree(arr_phy);
+       kfree(arr_port);
+       return -1;
+
+}
+
+static void  __devinit mvs_post_sas_ha_init(struct Scsi_Host *shost,
+                       const struct mvs_chip_info *chip_info)
+{
+       int can_queue, i = 0, j = 0;
+       struct mvs_info *mvi = NULL;
+       struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+       unsigned short nr_core = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
+
+       for (j = 0; j < nr_core; j++) {
+               mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[j];
+               for (i = 0; i < chip_info->n_phy; i++) {
+                       sha->sas_phy[j * chip_info->n_phy  + i] =
+                               &mvi->phy[i].sas_phy;
+                       sha->sas_port[j * chip_info->n_phy + i] =
+                               &mvi->port[i].sas_port;
+               }
+       }
+
+       sha->sas_ha_name = DRV_NAME;
+       sha->dev = mvi->dev;
+       sha->lldd_module = THIS_MODULE;
+       sha->sas_addr = &mvi->sas_addr[0];
+
+       sha->num_phys = nr_core * chip_info->n_phy;
+
+       sha->lldd_max_execute_num = 1;
+
+       if (mvi->flags & MVF_FLAG_SOC)
+               can_queue = MVS_SOC_CAN_QUEUE;
+       else
+               can_queue = MVS_CAN_QUEUE;
+
+       sha->lldd_queue_size = can_queue;
+       shost->can_queue = can_queue;
+       mvi->shost->cmd_per_lun = MVS_SLOTS/sha->num_phys;
+       sha->core.shost = mvi->shost;
+}
+
+static void mvs_init_sas_add(struct mvs_info *mvi)
+{
+       u8 i;
+       for (i = 0; i < mvi->chip->n_phy; i++) {
+               mvi->phy[i].dev_sas_addr = 0x5005043011ab0000ULL;
+               mvi->phy[i].dev_sas_addr =
+                       cpu_to_be64((u64)(*(u64 *)&mvi->phy[i].dev_sas_addr));
+       }
+
+       memcpy(mvi->sas_addr, &mvi->phy[0].dev_sas_addr, SAS_ADDR_SIZE);
+}
+
+static int __devinit mvs_pci_init(struct pci_dev *pdev,
+                                 const struct pci_device_id *ent)
+{
+       unsigned int rc, nhost = 0;
+       struct mvs_info *mvi;
+       irq_handler_t irq_handler = mvs_interrupt;
+       struct Scsi_Host *shost = NULL;
+       const struct mvs_chip_info *chip;
+
+       dev_printk(KERN_INFO, &pdev->dev,
+               "mvsas: driver version %s\n", DRV_VERSION);
+       rc = pci_enable_device(pdev);
+       if (rc)
+               goto err_out_enable;
+
+       pci_set_master(pdev);
+
+       rc = pci_request_regions(pdev, DRV_NAME);
+       if (rc)
+               goto err_out_disable;
+
+       rc = pci_go_64(pdev);
+       if (rc)
+               goto err_out_regions;
+
+       shost = scsi_host_alloc(&mvs_sht, sizeof(void *));
+       if (!shost) {
+               rc = -ENOMEM;
+               goto err_out_regions;
+       }
+
+       chip = &mvs_chips[ent->driver_data];
+       SHOST_TO_SAS_HA(shost) =
+               kcalloc(1, sizeof(struct sas_ha_struct), GFP_KERNEL);
+       if (!SHOST_TO_SAS_HA(shost)) {
+               kfree(shost);
+               rc = -ENOMEM;
+               goto err_out_regions;
+       }
+
+       rc = mvs_prep_sas_ha_init(shost, chip);
+       if (rc) {
+               kfree(shost);
+               rc = -ENOMEM;
+               goto err_out_regions;
+       }
+
+       pci_set_drvdata(pdev, SHOST_TO_SAS_HA(shost));
+
+       do {
+               mvi = mvs_pci_alloc(pdev, ent, shost, nhost);
+               if (!mvi) {
+                       rc = -ENOMEM;
+                       goto err_out_regions;
+               }
+
+               mvs_init_sas_add(mvi);
+
+               mvi->instance = nhost;
+               rc = MVS_CHIP_DISP->chip_init(mvi);
+               if (rc) {
+                       mvs_free(mvi);
+                       goto err_out_regions;
+               }
+               nhost++;
+       } while (nhost < chip->n_host);
+
+       mvs_post_sas_ha_init(shost, chip);
+
+       rc = scsi_add_host(shost, &pdev->dev);
+       if (rc)
+               goto err_out_shost;
+
+       rc = sas_register_ha(SHOST_TO_SAS_HA(shost));
+       if (rc)
+               goto err_out_shost;
+       rc = request_irq(pdev->irq, irq_handler, IRQF_SHARED,
+               DRV_NAME, SHOST_TO_SAS_HA(shost));
+       if (rc)
+               goto err_not_sas;
+
+       MVS_CHIP_DISP->interrupt_enable(mvi);
+
+       scsi_scan_host(mvi->shost);
+
+       return 0;
+
+err_not_sas:
+       sas_unregister_ha(SHOST_TO_SAS_HA(shost));
+err_out_shost:
+       scsi_remove_host(mvi->shost);
+err_out_regions:
+       pci_release_regions(pdev);
+err_out_disable:
+       pci_disable_device(pdev);
+err_out_enable:
+       return rc;
+}
+
+static void __devexit mvs_pci_remove(struct pci_dev *pdev)
+{
+       unsigned short core_nr, i = 0;
+       struct sas_ha_struct *sha = pci_get_drvdata(pdev);
+       struct mvs_info *mvi = NULL;
+
+       core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
+       mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0];
+
+#ifdef MVS_USE_TASKLET
+       tasklet_kill(&mv_tasklet);
+#endif
+
+       pci_set_drvdata(pdev, NULL);
+       sas_unregister_ha(sha);
+       sas_remove_host(mvi->shost);
+       scsi_remove_host(mvi->shost);
+
+       MVS_CHIP_DISP->interrupt_disable(mvi);
+       free_irq(mvi->irq, sha);
+       for (i = 0; i < core_nr; i++) {
+               mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i];
+               mvs_free(mvi);
+       }
+       kfree(sha->sas_phy);
+       kfree(sha->sas_port);
+       kfree(sha);
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       return;
+}
+
+static struct pci_device_id __devinitdata mvs_pci_table[] = {
+       { PCI_VDEVICE(MARVELL, 0x6320), chip_6320 },
+       { PCI_VDEVICE(MARVELL, 0x6340), chip_6440 },
+       {
+               .vendor         = PCI_VENDOR_ID_MARVELL,
+               .device         = 0x6440,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = 0x6480,
+               .class          = 0,
+               .class_mask     = 0,
+               .driver_data    = chip_6485,
+       },
+       { PCI_VDEVICE(MARVELL, 0x6440), chip_6440 },
+       { PCI_VDEVICE(MARVELL, 0x6485), chip_6485 },
+       { PCI_VDEVICE(MARVELL, 0x9480), chip_9480 },
+       { PCI_VDEVICE(MARVELL, 0x9180), chip_9180 },
+
+       { }     /* terminate list */
+};
+
+static struct pci_driver mvs_pci_driver = {
+       .name           = DRV_NAME,
+       .id_table       = mvs_pci_table,
+       .probe          = mvs_pci_init,
+       .remove         = __devexit_p(mvs_pci_remove),
+};
+
+/* task handler */
+struct task_struct *mvs_th;
+static int __init mvs_init(void)
+{
+       int rc;
+       mvs_stt = sas_domain_attach_transport(&mvs_transport_ops);
+       if (!mvs_stt)
+               return -ENOMEM;
+
+       rc = pci_register_driver(&mvs_pci_driver);
+
+       if (rc)
+               goto err_out;
+
+       return 0;
+
+err_out:
+       sas_release_transport(mvs_stt);
+       return rc;
+}
+
+static void __exit mvs_exit(void)
+{
+       pci_unregister_driver(&mvs_pci_driver);
+       sas_release_transport(mvs_stt);
+}
+
+module_init(mvs_init);
+module_exit(mvs_exit);
+
+MODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>");
+MODULE_DESCRIPTION("Marvell 88SE6440 SAS/SATA controller driver");
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
+#ifdef CONFIG_PCI
+MODULE_DEVICE_TABLE(pci, mvs_pci_table);
+#endif
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c
new file mode 100644 (file)
index 0000000..0d21386
--- /dev/null
@@ -0,0 +1,2154 @@
+/*
+ * Marvell 88SE64xx/88SE94xx main function
+ *
+ * Copyright 2007 Red Hat, Inc.
+ * Copyright 2008 Marvell. <kewei@marvell.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+*/
+
+#include "mv_sas.h"
+
+static int mvs_find_tag(struct mvs_info *mvi, struct sas_task *task, u32 *tag)
+{
+       if (task->lldd_task) {
+               struct mvs_slot_info *slot;
+               slot = task->lldd_task;
+               *tag = slot->slot_tag;
+               return 1;
+       }
+       return 0;
+}
+
+void mvs_tag_clear(struct mvs_info *mvi, u32 tag)
+{
+       void *bitmap = &mvi->tags;
+       clear_bit(tag, bitmap);
+}
+
+void mvs_tag_free(struct mvs_info *mvi, u32 tag)
+{
+       mvs_tag_clear(mvi, tag);
+}
+
+void mvs_tag_set(struct mvs_info *mvi, unsigned int tag)
+{
+       void *bitmap = &mvi->tags;
+       set_bit(tag, bitmap);
+}
+
+inline int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out)
+{
+       unsigned int index, tag;
+       void *bitmap = &mvi->tags;
+
+       index = find_first_zero_bit(bitmap, mvi->tags_num);
+       tag = index;
+       if (tag >= mvi->tags_num)
+               return -SAS_QUEUE_FULL;
+       mvs_tag_set(mvi, tag);
+       *tag_out = tag;
+       return 0;
+}
+
+void mvs_tag_init(struct mvs_info *mvi)
+{
+       int i;
+       for (i = 0; i < mvi->tags_num; ++i)
+               mvs_tag_clear(mvi, i);
+}
+
+void mvs_hexdump(u32 size, u8 *data, u32 baseaddr)
+{
+       u32 i;
+       u32 run;
+       u32 offset;
+
+       offset = 0;
+       while (size) {
+               printk(KERN_DEBUG"%08X : ", baseaddr + offset);
+               if (size >= 16)
+                       run = 16;
+               else
+                       run = size;
+               size -= run;
+               for (i = 0; i < 16; i++) {
+                       if (i < run)
+                               printk(KERN_DEBUG"%02X ", (u32)data[i]);
+                       else
+                               printk(KERN_DEBUG"   ");
+               }
+               printk(KERN_DEBUG": ");
+               for (i = 0; i < run; i++)
+                       printk(KERN_DEBUG"%c",
+                               isalnum(data[i]) ? data[i] : '.');
+               printk(KERN_DEBUG"\n");
+               data = &data[16];
+               offset += run;
+       }
+       printk(KERN_DEBUG"\n");
+}
+
+#if (_MV_DUMP > 1)
+static void mvs_hba_sb_dump(struct mvs_info *mvi, u32 tag,
+                                  enum sas_protocol proto)
+{
+       u32 offset;
+       struct mvs_slot_info *slot = &mvi->slot_info[tag];
+
+       offset = slot->cmd_size + MVS_OAF_SZ +
+           MVS_CHIP_DISP->prd_size() * slot->n_elem;
+       dev_printk(KERN_DEBUG, mvi->dev, "+---->Status buffer[%d] :\n",
+                       tag);
+       mvs_hexdump(32, (u8 *) slot->response,
+                   (u32) slot->buf_dma + offset);
+}
+#endif
+
+static void mvs_hba_memory_dump(struct mvs_info *mvi, u32 tag,
+                               enum sas_protocol proto)
+{
+#if (_MV_DUMP > 1)
+       u32 sz, w_ptr;
+       u64 addr;
+       struct mvs_slot_info *slot = &mvi->slot_info[tag];
+
+       /*Delivery Queue */
+       sz = MVS_CHIP_SLOT_SZ;
+       w_ptr = slot->tx;
+       addr = mvi->tx_dma;
+       dev_printk(KERN_DEBUG, mvi->dev,
+               "Delivery Queue Size=%04d , WRT_PTR=%04X\n", sz, w_ptr);
+       dev_printk(KERN_DEBUG, mvi->dev,
+               "Delivery Queue Base Address=0x%llX (PA)"
+               "(tx_dma=0x%llX), Entry=%04d\n",
+               addr, (unsigned long long)mvi->tx_dma, w_ptr);
+       mvs_hexdump(sizeof(u32), (u8 *)(&mvi->tx[mvi->tx_prod]),
+                       (u32) mvi->tx_dma + sizeof(u32) * w_ptr);
+       /*Command List */
+       addr = mvi->slot_dma;
+       dev_printk(KERN_DEBUG, mvi->dev,
+               "Command List Base Address=0x%llX (PA)"
+               "(slot_dma=0x%llX), Header=%03d\n",
+               addr, (unsigned long long)slot->buf_dma, tag);
+       dev_printk(KERN_DEBUG, mvi->dev, "Command Header[%03d]:\n", tag);
+       /*mvs_cmd_hdr */
+       mvs_hexdump(sizeof(struct mvs_cmd_hdr), (u8 *)(&mvi->slot[tag]),
+               (u32) mvi->slot_dma + tag * sizeof(struct mvs_cmd_hdr));
+       /*1.command table area */
+       dev_printk(KERN_DEBUG, mvi->dev, "+---->Command Table :\n");
+       mvs_hexdump(slot->cmd_size, (u8 *) slot->buf, (u32) slot->buf_dma);
+       /*2.open address frame area */
+       dev_printk(KERN_DEBUG, mvi->dev, "+---->Open Address Frame :\n");
+       mvs_hexdump(MVS_OAF_SZ, (u8 *) slot->buf + slot->cmd_size,
+                               (u32) slot->buf_dma + slot->cmd_size);
+       /*3.status buffer */
+       mvs_hba_sb_dump(mvi, tag, proto);
+       /*4.PRD table */
+       dev_printk(KERN_DEBUG, mvi->dev, "+---->PRD table :\n");
+       mvs_hexdump(MVS_CHIP_DISP->prd_size() * slot->n_elem,
+               (u8 *) slot->buf + slot->cmd_size + MVS_OAF_SZ,
+               (u32) slot->buf_dma + slot->cmd_size + MVS_OAF_SZ);
+#endif
+}
+
+static void mvs_hba_cq_dump(struct mvs_info *mvi)
+{
+#if (_MV_DUMP > 2)
+       u64 addr;
+       void __iomem *regs = mvi->regs;
+       u32 entry = mvi->rx_cons + 1;
+       u32 rx_desc = le32_to_cpu(mvi->rx[entry]);
+
+       /*Completion Queue */
+       addr = mr32(RX_HI) << 16 << 16 | mr32(RX_LO);
+       dev_printk(KERN_DEBUG, mvi->dev, "Completion Task = 0x%p\n",
+                  mvi->slot_info[rx_desc & RXQ_SLOT_MASK].task);
+       dev_printk(KERN_DEBUG, mvi->dev,
+               "Completion List Base Address=0x%llX (PA), "
+               "CQ_Entry=%04d, CQ_WP=0x%08X\n",
+               addr, entry - 1, mvi->rx[0]);
+       mvs_hexdump(sizeof(u32), (u8 *)(&rx_desc),
+                   mvi->rx_dma + sizeof(u32) * entry);
+#endif
+}
+
+void mvs_get_sas_addr(void *buf, u32 buflen)
+{
+       /*memcpy(buf, "\x50\x05\x04\x30\x11\xab\x64\x40", 8);*/
+}
+
+struct mvs_info *mvs_find_dev_mvi(struct domain_device *dev)
+{
+       unsigned long i = 0, j = 0, hi = 0;
+       struct sas_ha_struct *sha = dev->port->ha;
+       struct mvs_info *mvi = NULL;
+       struct asd_sas_phy *phy;
+
+       while (sha->sas_port[i]) {
+               if (sha->sas_port[i] == dev->port) {
+                       phy =  container_of(sha->sas_port[i]->phy_list.next,
+                               struct asd_sas_phy, port_phy_el);
+                       j = 0;
+                       while (sha->sas_phy[j]) {
+                               if (sha->sas_phy[j] == phy)
+                                       break;
+                               j++;
+                       }
+                       break;
+               }
+               i++;
+       }
+       hi = j/((struct mvs_prv_info *)sha->lldd_ha)->n_phy;
+       mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[hi];
+
+       return mvi;
+
+}
+
+/* FIXME */
+int mvs_find_dev_phyno(struct domain_device *dev, int *phyno)
+{
+       unsigned long i = 0, j = 0, n = 0, num = 0;
+       struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev;
+       struct mvs_info *mvi = mvi_dev->mvi_info;
+       struct sas_ha_struct *sha = dev->port->ha;
+
+       while (sha->sas_port[i]) {
+               if (sha->sas_port[i] == dev->port) {
+                       struct asd_sas_phy *phy;
+                       list_for_each_entry(phy,
+                               &sha->sas_port[i]->phy_list, port_phy_el) {
+                               j = 0;
+                               while (sha->sas_phy[j]) {
+                                       if (sha->sas_phy[j] == phy)
+                                               break;
+                                       j++;
+                               }
+                               phyno[n] = (j >= mvi->chip->n_phy) ?
+                                       (j - mvi->chip->n_phy) : j;
+                               num++;
+                               n++;
+                       }
+                       break;
+               }
+               i++;
+       }
+       return num;
+}
+
+static inline void mvs_free_reg_set(struct mvs_info *mvi,
+                               struct mvs_device *dev)
+{
+       if (!dev) {
+               mv_printk("device has been free.\n");
+               return;
+       }
+       if (dev->runing_req != 0)
+               return;
+       if (dev->taskfileset == MVS_ID_NOT_MAPPED)
+               return;
+       MVS_CHIP_DISP->free_reg_set(mvi, &dev->taskfileset);
+}
+
+static inline u8 mvs_assign_reg_set(struct mvs_info *mvi,
+                               struct mvs_device *dev)
+{
+       if (dev->taskfileset != MVS_ID_NOT_MAPPED)
+               return 0;
+       return MVS_CHIP_DISP->assign_reg_set(mvi, &dev->taskfileset);
+}
+
+void mvs_phys_reset(struct mvs_info *mvi, u32 phy_mask, int hard)
+{
+       u32 no;
+       for_each_phy(phy_mask, phy_mask, no) {
+               if (!(phy_mask & 1))
+                       continue;
+               MVS_CHIP_DISP->phy_reset(mvi, no, hard);
+       }
+}
+
+/* FIXME: locking? */
+int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
+                       void *funcdata)
+{
+       int rc = 0, phy_id = sas_phy->id;
+       u32 tmp, i = 0, hi;
+       struct sas_ha_struct *sha = sas_phy->ha;
+       struct mvs_info *mvi = NULL;
+
+       while (sha->sas_phy[i]) {
+               if (sha->sas_phy[i] == sas_phy)
+                       break;
+               i++;
+       }
+       hi = i/((struct mvs_prv_info *)sha->lldd_ha)->n_phy;
+       mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[hi];
+
+       switch (func) {
+       case PHY_FUNC_SET_LINK_RATE:
+               MVS_CHIP_DISP->phy_set_link_rate(mvi, phy_id, funcdata);
+               break;
+
+       case PHY_FUNC_HARD_RESET:
+               tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, phy_id);
+               if (tmp & PHY_RST_HARD)
+                       break;
+               MVS_CHIP_DISP->phy_reset(mvi, phy_id, 1);
+               break;
+
+       case PHY_FUNC_LINK_RESET:
+               MVS_CHIP_DISP->phy_enable(mvi, phy_id);
+               MVS_CHIP_DISP->phy_reset(mvi, phy_id, 0);
+               break;
+
+       case PHY_FUNC_DISABLE:
+               MVS_CHIP_DISP->phy_disable(mvi, phy_id);
+               break;
+       case PHY_FUNC_RELEASE_SPINUP_HOLD:
+       default:
+               rc = -EOPNOTSUPP;
+       }
+       msleep(200);
+       return rc;
+}
+
+void __devinit mvs_set_sas_addr(struct mvs_info *mvi, int port_id,
+                               u32 off_lo, u32 off_hi, u64 sas_addr)
+{
+       u32 lo = (u32)sas_addr;
+       u32 hi = (u32)(sas_addr>>32);
+
+       MVS_CHIP_DISP->write_port_cfg_addr(mvi, port_id, off_lo);
+       MVS_CHIP_DISP->write_port_cfg_data(mvi, port_id, lo);
+       MVS_CHIP_DISP->write_port_cfg_addr(mvi, port_id, off_hi);
+       MVS_CHIP_DISP->write_port_cfg_data(mvi, port_id, hi);
+}
+
+static void mvs_bytes_dmaed(struct mvs_info *mvi, int i)
+{
+       struct mvs_phy *phy = &mvi->phy[i];
+       struct asd_sas_phy *sas_phy = &phy->sas_phy;
+       struct sas_ha_struct *sas_ha;
+       if (!phy->phy_attached)
+               return;
+
+       if (!(phy->att_dev_info & PORT_DEV_TRGT_MASK)
+               && phy->phy_type & PORT_TYPE_SAS) {
+               return;
+       }
+
+       sas_ha = mvi->sas;
+       sas_ha->notify_phy_event(sas_phy, PHYE_OOB_DONE);
+
+       if (sas_phy->phy) {
+               struct sas_phy *sphy = sas_phy->phy;
+
+               sphy->negotiated_linkrate = sas_phy->linkrate;
+               sphy->minimum_linkrate = phy->minimum_linkrate;
+               sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
+               sphy->maximum_linkrate = phy->maximum_linkrate;
+               sphy->maximum_linkrate_hw = MVS_CHIP_DISP->phy_max_link_rate();
+       }
+
+       if (phy->phy_type & PORT_TYPE_SAS) {
+               struct sas_identify_frame *id;
+
+               id = (struct sas_identify_frame *)phy->frame_rcvd;
+               id->dev_type = phy->identify.device_type;
+               id->initiator_bits = SAS_PROTOCOL_ALL;
+               id->target_bits = phy->identify.target_port_protocols;
+       } else if (phy->phy_type & PORT_TYPE_SATA) {
+               /*Nothing*/
+       }
+       mv_dprintk("phy %d byte dmaded.\n", i + mvi->id * mvi->chip->n_phy);
+
+       sas_phy->frame_rcvd_size = phy->frame_rcvd_size;
+
+       mvi->sas->notify_port_event(sas_phy,
+                                  PORTE_BYTES_DMAED);
+}
+
+int mvs_slave_alloc(struct scsi_device *scsi_dev)
+{
+       struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
+       if (dev_is_sata(dev)) {
+               /* We don't need to rescan targets
+                * if REPORT_LUNS request is failed
+                */
+               if (scsi_dev->lun > 0)
+                       return -ENXIO;
+               scsi_dev->tagged_supported = 1;
+       }
+
+       return sas_slave_alloc(scsi_dev);
+}
+
+int mvs_slave_configure(struct scsi_device *sdev)
+{
+       struct domain_device *dev = sdev_to_domain_dev(sdev);
+       int ret = sas_slave_configure(sdev);
+
+       if (ret)
+               return ret;
+       if (dev_is_sata(dev)) {
+               /* may set PIO mode */
+       #if MV_DISABLE_NCQ
+               struct ata_port *ap = dev->sata_dev.ap;
+               struct ata_device *adev = ap->link.device;
+               adev->flags |= ATA_DFLAG_NCQ_OFF;
+               scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, 1);
+       #endif
+       }
+       return 0;
+}
+
+void mvs_scan_start(struct Scsi_Host *shost)
+{
+       int i, j;
+       unsigned short core_nr;
+       struct mvs_info *mvi;
+       struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+
+       core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
+
+       for (j = 0; j < core_nr; j++) {
+               mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[j];
+               for (i = 0; i < mvi->chip->n_phy; ++i)
+                       mvs_bytes_dmaed(mvi, i);
+       }
+}
+
+int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time)
+{
+       /* give the phy enabling interrupt event time to come in (1s
+        * is empirically about all it takes) */
+       if (time < HZ)
+               return 0;
+       /* Wait for discovery to finish */
+       scsi_flush_work(shost);
+       return 1;
+}
+
+static int mvs_task_prep_smp(struct mvs_info *mvi,
+                            struct mvs_task_exec_info *tei)
+{
+       int elem, rc, i;
+       struct sas_task *task = tei->task;
+       struct mvs_cmd_hdr *hdr = tei->hdr;
+       struct domain_device *dev = task->dev;
+       struct asd_sas_port *sas_port = dev->port;
+       struct scatterlist *sg_req, *sg_resp;
+       u32 req_len, resp_len, tag = tei->tag;
+       void *buf_tmp;
+       u8 *buf_oaf;
+       dma_addr_t buf_tmp_dma;
+       void *buf_prd;
+       struct mvs_slot_info *slot = &mvi->slot_info[tag];
+       u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
+#if _MV_DUMP
+       u8 *buf_cmd;
+       void *from;
+#endif
+       /*
+        * DMA-map SMP request, response buffers
+        */
+       sg_req = &task->smp_task.smp_req;
+       elem = dma_map_sg(mvi->dev, sg_req, 1, PCI_DMA_TODEVICE);
+       if (!elem)
+               return -ENOMEM;
+       req_len = sg_dma_len(sg_req);
+
+       sg_resp = &task->smp_task.smp_resp;
+       elem = dma_map_sg(mvi->dev, sg_resp, 1, PCI_DMA_FROMDEVICE);
+       if (!elem) {
+               rc = -ENOMEM;
+               goto err_out;
+       }
+       resp_len = SB_RFB_MAX;
+
+       /* must be in dwords */
+       if ((req_len & 0x3) || (resp_len & 0x3)) {
+               rc = -EINVAL;
+               goto err_out_2;
+       }
+
+       /*
+        * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
+        */
+
+       /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ***** */
+       buf_tmp = slot->buf;
+       buf_tmp_dma = slot->buf_dma;
+
+#if _MV_DUMP
+       buf_cmd = buf_tmp;
+       hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
+       buf_tmp += req_len;
+       buf_tmp_dma += req_len;
+       slot->cmd_size = req_len;
+#else
+       hdr->cmd_tbl = cpu_to_le64(sg_dma_address(sg_req));
+#endif
+
+       /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
+       buf_oaf = buf_tmp;
+       hdr->open_frame = cpu_to_le64(buf_tmp_dma);
+
+       buf_tmp += MVS_OAF_SZ;
+       buf_tmp_dma += MVS_OAF_SZ;
+
+       /* region 3: PRD table *********************************** */
+       buf_prd = buf_tmp;
+       if (tei->n_elem)
+               hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
+       else
+               hdr->prd_tbl = 0;
+
+       i = MVS_CHIP_DISP->prd_size() * tei->n_elem;
+       buf_tmp += i;
+       buf_tmp_dma += i;
+
+       /* region 4: status buffer (larger the PRD, smaller this buf) ****** */
+       slot->response = buf_tmp;
+       hdr->status_buf = cpu_to_le64(buf_tmp_dma);
+       if (mvi->flags & MVF_FLAG_SOC)
+               hdr->reserved[0] = 0;
+
+       /*
+        * Fill in TX ring and command slot header
+        */
+       slot->tx = mvi->tx_prod;
+       mvi->tx[mvi->tx_prod] = cpu_to_le32((TXQ_CMD_SMP << TXQ_CMD_SHIFT) |
+                                       TXQ_MODE_I | tag |
+                                       (sas_port->phy_mask << TXQ_PHY_SHIFT));
+
+       hdr->flags |= flags;
+       hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | ((req_len - 4) / 4));
+       hdr->tags = cpu_to_le32(tag);
+       hdr->data_len = 0;
+
+       /* generate open address frame hdr (first 12 bytes) */
+       /* initiator, SMP, ftype 1h */
+       buf_oaf[0] = (1 << 7) | (PROTOCOL_SMP << 4) | 0x01;
+       buf_oaf[1] = dev->linkrate & 0xf;
+       *(u16 *)(buf_oaf + 2) = 0xFFFF;         /* SAS SPEC */
+       memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE);
+
+       /* fill in PRD (scatter/gather) table, if any */
+       MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd);
+
+#if _MV_DUMP
+       /* copy cmd table */
+       from = kmap_atomic(sg_page(sg_req), KM_IRQ0);
+       memcpy(buf_cmd, from + sg_req->offset, req_len);
+       kunmap_atomic(from, KM_IRQ0);
+#endif
+       return 0;
+
+err_out_2:
+       dma_unmap_sg(mvi->dev, &tei->task->smp_task.smp_resp, 1,
+                    PCI_DMA_FROMDEVICE);
+err_out:
+       dma_unmap_sg(mvi->dev, &tei->task->smp_task.smp_req, 1,
+                    PCI_DMA_TODEVICE);
+       return rc;
+}
+
+static u32 mvs_get_ncq_tag(struct sas_task *task, u32 *tag)
+{
+       struct ata_queued_cmd *qc = task->uldd_task;
+
+       if (qc) {
+               if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
+                       qc->tf.command == ATA_CMD_FPDMA_READ) {
+                       *tag = qc->tag;
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+static int mvs_task_prep_ata(struct mvs_info *mvi,
+                            struct mvs_task_exec_info *tei)
+{
+       struct sas_task *task = tei->task;
+       struct domain_device *dev = task->dev;
+       struct mvs_device *mvi_dev = dev->lldd_dev;
+       struct mvs_cmd_hdr *hdr = tei->hdr;
+       struct asd_sas_port *sas_port = dev->port;
+       struct mvs_slot_info *slot;
+       void *buf_prd;
+       u32 tag = tei->tag, hdr_tag;
+       u32 flags, del_q;
+       void *buf_tmp;
+       u8 *buf_cmd, *buf_oaf;
+       dma_addr_t buf_tmp_dma;
+       u32 i, req_len, resp_len;
+       const u32 max_resp_len = SB_RFB_MAX;
+
+       if (mvs_assign_reg_set(mvi, mvi_dev) == MVS_ID_NOT_MAPPED) {
+               mv_dprintk("Have not enough regiset for dev %d.\n",
+                       mvi_dev->device_id);
+               return -EBUSY;
+       }
+       slot = &mvi->slot_info[tag];
+       slot->tx = mvi->tx_prod;
+       del_q = TXQ_MODE_I | tag |
+               (TXQ_CMD_STP << TXQ_CMD_SHIFT) |
+               (sas_port->phy_mask << TXQ_PHY_SHIFT) |
+               (mvi_dev->taskfileset << TXQ_SRS_SHIFT);
+       mvi->tx[mvi->tx_prod] = cpu_to_le32(del_q);
+
+#ifndef DISABLE_HOTPLUG_DMA_FIX
+       if (task->data_dir == DMA_FROM_DEVICE)
+               flags = (MVS_CHIP_DISP->prd_count() << MCH_PRD_LEN_SHIFT);
+       else
+               flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
+#else
+       flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
+#endif
+       if (task->ata_task.use_ncq)
+               flags |= MCH_FPDMA;
+       if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) {
+               if (task->ata_task.fis.command != ATA_CMD_ID_ATAPI)
+                       flags |= MCH_ATAPI;
+       }
+
+       /* FIXME: fill in port multiplier number */
+
+       hdr->flags = cpu_to_le32(flags);
+
+       /* FIXME: the low order order 5 bits for the TAG if enable NCQ */
+       if (task->ata_task.use_ncq && mvs_get_ncq_tag(task, &hdr_tag))
+               task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3);
+       else
+               hdr_tag = tag;
+
+       hdr->tags = cpu_to_le32(hdr_tag);
+
+       hdr->data_len = cpu_to_le32(task->total_xfer_len);
+
+       /*
+        * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
+        */
+
+       /* region 1: command table area (MVS_ATA_CMD_SZ bytes) ************** */
+       buf_cmd = buf_tmp = slot->buf;
+       buf_tmp_dma = slot->buf_dma;
+
+       hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
+
+       buf_tmp += MVS_ATA_CMD_SZ;
+       buf_tmp_dma += MVS_ATA_CMD_SZ;
+#if _MV_DUMP
+       slot->cmd_size = MVS_ATA_CMD_SZ;
+#endif
+
+       /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
+       /* used for STP.  unused for SATA? */
+       buf_oaf = buf_tmp;
+       hdr->open_frame = cpu_to_le64(buf_tmp_dma);
+
+       buf_tmp += MVS_OAF_SZ;
+       buf_tmp_dma += MVS_OAF_SZ;
+
+       /* region 3: PRD table ********************************************* */
+       buf_prd = buf_tmp;
+
+       if (tei->n_elem)
+               hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
+       else
+               hdr->prd_tbl = 0;
+       i = MVS_CHIP_DISP->prd_size() * MVS_CHIP_DISP->prd_count();
+
+       buf_tmp += i;
+       buf_tmp_dma += i;
+
+       /* region 4: status buffer (larger the PRD, smaller this buf) ****** */
+       /* FIXME: probably unused, for SATA.  kept here just in case
+        * we get a STP/SATA error information record
+        */
+       slot->response = buf_tmp;
+       hdr->status_buf = cpu_to_le64(buf_tmp_dma);
+       if (mvi->flags & MVF_FLAG_SOC)
+               hdr->reserved[0] = 0;
+
+       req_len = sizeof(struct host_to_dev_fis);
+       resp_len = MVS_SLOT_BUF_SZ - MVS_ATA_CMD_SZ -
+           sizeof(struct mvs_err_info) - i;
+
+       /* request, response lengths */
+       resp_len = min(resp_len, max_resp_len);
+       hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
+
+       if (likely(!task->ata_task.device_control_reg_update))
+               task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
+       /* fill in command FIS and ATAPI CDB */
+       memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis));
+       if (dev->sata_dev.command_set == ATAPI_COMMAND_SET)
+               memcpy(buf_cmd + STP_ATAPI_CMD,
+                       task->ata_task.atapi_packet, 16);
+
+       /* generate open address frame hdr (first 12 bytes) */
+       /* initiator, STP, ftype 1h */
+       buf_oaf[0] = (1 << 7) | (PROTOCOL_STP << 4) | 0x1;
+       buf_oaf[1] = dev->linkrate & 0xf;
+       *(u16 *)(buf_oaf + 2) = cpu_to_be16(mvi_dev->device_id + 1);
+       memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE);
+
+       /* fill in PRD (scatter/gather) table, if any */
+       MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd);
+#ifndef DISABLE_HOTPLUG_DMA_FIX
+       if (task->data_dir == DMA_FROM_DEVICE)
+               MVS_CHIP_DISP->dma_fix(mvi->bulk_buffer_dma,
+                               TRASH_BUCKET_SIZE, tei->n_elem, buf_prd);
+#endif
+       return 0;
+}
+
+static int mvs_task_prep_ssp(struct mvs_info *mvi,
+                            struct mvs_task_exec_info *tei, int is_tmf,
+                            struct mvs_tmf_task *tmf)
+{
+       struct sas_task *task = tei->task;
+       struct mvs_cmd_hdr *hdr = tei->hdr;
+       struct mvs_port *port = tei->port;
+       struct domain_device *dev = task->dev;
+       struct mvs_device *mvi_dev = dev->lldd_dev;
+       struct asd_sas_port *sas_port = dev->port;
+       struct mvs_slot_info *slot;
+       void *buf_prd;
+       struct ssp_frame_hdr *ssp_hdr;
+       void *buf_tmp;
+       u8 *buf_cmd, *buf_oaf, fburst = 0;
+       dma_addr_t buf_tmp_dma;
+       u32 flags;
+       u32 resp_len, req_len, i, tag = tei->tag;
+       const u32 max_resp_len = SB_RFB_MAX;
+       u32 phy_mask;
+
+       slot = &mvi->slot_info[tag];
+
+       phy_mask = ((port->wide_port_phymap) ? port->wide_port_phymap :
+               sas_port->phy_mask) & TXQ_PHY_MASK;
+
+       slot->tx = mvi->tx_prod;
+       mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag |
+                               (TXQ_CMD_SSP << TXQ_CMD_SHIFT) |
+                               (phy_mask << TXQ_PHY_SHIFT));
+
+       flags = MCH_RETRY;
+       if (task->ssp_task.enable_first_burst) {
+               flags |= MCH_FBURST;
+               fburst = (1 << 7);
+       }
+       if (is_tmf)
+               flags |= (MCH_SSP_FR_TASK << MCH_SSP_FR_TYPE_SHIFT);
+       else
+               flags |= (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT);
+       hdr->flags = cpu_to_le32(flags | (tei->n_elem << MCH_PRD_LEN_SHIFT));
+       hdr->tags = cpu_to_le32(tag);
+       hdr->data_len = cpu_to_le32(task->total_xfer_len);
+
+       /*
+        * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
+        */
+
+       /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */
+       buf_cmd = buf_tmp = slot->buf;
+       buf_tmp_dma = slot->buf_dma;
+
+       hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
+
+       buf_tmp += MVS_SSP_CMD_SZ;
+       buf_tmp_dma += MVS_SSP_CMD_SZ;
+#if _MV_DUMP
+       slot->cmd_size = MVS_SSP_CMD_SZ;
+#endif
+
+       /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
+       buf_oaf = buf_tmp;
+       hdr->open_frame = cpu_to_le64(buf_tmp_dma);
+
+       buf_tmp += MVS_OAF_SZ;
+       buf_tmp_dma += MVS_OAF_SZ;
+
+       /* region 3: PRD table ********************************************* */
+       buf_prd = buf_tmp;
+       if (tei->n_elem)
+               hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
+       else
+               hdr->prd_tbl = 0;
+
+       i = MVS_CHIP_DISP->prd_size() * tei->n_elem;
+       buf_tmp += i;
+       buf_tmp_dma += i;
+
+       /* region 4: status buffer (larger the PRD, smaller this buf) ****** */
+       slot->response = buf_tmp;
+       hdr->status_buf = cpu_to_le64(buf_tmp_dma);
+       if (mvi->flags & MVF_FLAG_SOC)
+               hdr->reserved[0] = 0;
+
+       resp_len = MVS_SLOT_BUF_SZ - MVS_SSP_CMD_SZ - MVS_OAF_SZ -
+           sizeof(struct mvs_err_info) - i;
+       resp_len = min(resp_len, max_resp_len);
+
+       req_len = sizeof(struct ssp_frame_hdr) + 28;
+
+       /* request, response lengths */
+       hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
+
+       /* generate open address frame hdr (first 12 bytes) */
+       /* initiator, SSP, ftype 1h */
+       buf_oaf[0] = (1 << 7) | (PROTOCOL_SSP << 4) | 0x1;
+       buf_oaf[1] = dev->linkrate & 0xf;
+       *(u16 *)(buf_oaf + 2) = cpu_to_be16(mvi_dev->device_id + 1);
+       memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE);
+
+       /* fill in SSP frame header (Command Table.SSP frame header) */
+       ssp_hdr = (struct ssp_frame_hdr *)buf_cmd;
+
+       if (is_tmf)
+               ssp_hdr->frame_type = SSP_TASK;
+       else
+               ssp_hdr->frame_type = SSP_COMMAND;
+
+       memcpy(ssp_hdr->hashed_dest_addr, dev->hashed_sas_addr,
+              HASHED_SAS_ADDR_SIZE);
+       memcpy(ssp_hdr->hashed_src_addr,
+              dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
+       ssp_hdr->tag = cpu_to_be16(tag);
+
+       /* fill in IU for TASK and Command Frame */
+       buf_cmd += sizeof(*ssp_hdr);
+       memcpy(buf_cmd, &task->ssp_task.LUN, 8);
+
+       if (ssp_hdr->frame_type != SSP_TASK) {
+               buf_cmd[9] = fburst | task->ssp_task.task_attr |
+                               (task->ssp_task.task_prio << 3);
+               memcpy(buf_cmd + 12, &task->ssp_task.cdb, 16);
+       } else{
+               buf_cmd[10] = tmf->tmf;
+               switch (tmf->tmf) {
+               case TMF_ABORT_TASK:
+               case TMF_QUERY_TASK:
+                       buf_cmd[12] =
+                               (tmf->tag_of_task_to_be_managed >> 8) & 0xff;
+                       buf_cmd[13] =
+                               tmf->tag_of_task_to_be_managed & 0xff;
+                       break;
+               default:
+                       break;
+               }
+       }
+       /* fill in PRD (scatter/gather) table, if any */
+       MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd);
+       return 0;
+}
+
+#define        DEV_IS_GONE(mvi_dev)    ((!mvi_dev || (mvi_dev->dev_type == NO_DEVICE)))
+static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,
+                               struct completion *completion,int is_tmf,
+                               struct mvs_tmf_task *tmf)
+{
+       struct domain_device *dev = task->dev;
+       struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev;
+       struct mvs_info *mvi = mvi_dev->mvi_info;
+       struct mvs_task_exec_info tei;
+       struct sas_task *t = task;
+       struct mvs_slot_info *slot;
+       u32 tag = 0xdeadbeef, rc, n_elem = 0;
+       u32 n = num, pass = 0;
+       unsigned long flags = 0;
+
+       if (!dev->port) {
+               struct task_status_struct *tsm = &t->task_status;
+
+               tsm->resp = SAS_TASK_UNDELIVERED;
+               tsm->stat = SAS_PHY_DOWN;
+               t->task_done(t);
+               return 0;
+       }
+
+       spin_lock_irqsave(&mvi->lock, flags);
+       do {
+               dev = t->dev;
+               mvi_dev = dev->lldd_dev;
+               if (DEV_IS_GONE(mvi_dev)) {
+                       if (mvi_dev)
+                               mv_dprintk("device %d not ready.\n",
+                                       mvi_dev->device_id);
+                       else
+                               mv_dprintk("device %016llx not ready.\n",
+                                       SAS_ADDR(dev->sas_addr));
+
+                       rc = SAS_PHY_DOWN;
+                       goto out_done;
+               }
+
+               if (dev->port->id >= mvi->chip->n_phy)
+                       tei.port = &mvi->port[dev->port->id - mvi->chip->n_phy];
+               else
+                       tei.port = &mvi->port[dev->port->id];
+
+               if (!tei.port->port_attached) {
+                       if (sas_protocol_ata(t->task_proto)) {
+                               mv_dprintk("port %d does not"
+                                       "attached device.\n", dev->port->id);
+                               rc = SAS_PHY_DOWN;
+                               goto out_done;
+                       } else {
+                               struct task_status_struct *ts = &t->task_status;
+                               ts->resp = SAS_TASK_UNDELIVERED;
+                               ts->stat = SAS_PHY_DOWN;
+                               t->task_done(t);
+                               if (n > 1)
+                                       t = list_entry(t->list.next,
+                                                       struct sas_task, list);
+                               continue;
+                       }
+               }
+
+               if (!sas_protocol_ata(t->task_proto)) {
+                       if (t->num_scatter) {
+                               n_elem = dma_map_sg(mvi->dev,
+                                                   t->scatter,
+                                                   t->num_scatter,
+                                                   t->data_dir);
+                               if (!n_elem) {
+                                       rc = -ENOMEM;
+                                       goto err_out;
+                               }
+                       }
+               } else {
+                       n_elem = t->num_scatter;
+               }
+
+               rc = mvs_tag_alloc(mvi, &tag);
+               if (rc)
+                       goto err_out;
+
+               slot = &mvi->slot_info[tag];
+
+
+               t->lldd_task = NULL;
+               slot->n_elem = n_elem;
+               slot->slot_tag = tag;
+               memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
+
+               tei.task = t;
+               tei.hdr = &mvi->slot[tag];
+               tei.tag = tag;
+               tei.n_elem = n_elem;
+               switch (t->task_proto) {
+               case SAS_PROTOCOL_SMP:
+                       rc = mvs_task_prep_smp(mvi, &tei);
+                       break;
+               case SAS_PROTOCOL_SSP:
+                       rc = mvs_task_prep_ssp(mvi, &tei, is_tmf, tmf);
+                       break;
+               case SAS_PROTOCOL_SATA:
+               case SAS_PROTOCOL_STP:
+               case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+                       rc = mvs_task_prep_ata(mvi, &tei);
+                       break;
+               default:
+                       dev_printk(KERN_ERR, mvi->dev,
+                               "unknown sas_task proto: 0x%x\n",
+                               t->task_proto);
+                       rc = -EINVAL;
+                       break;
+               }
+
+               if (rc) {
+                       mv_dprintk("rc is %x\n", rc);
+                       goto err_out_tag;
+               }
+               slot->task = t;
+               slot->port = tei.port;
+               t->lldd_task = slot;
+               list_add_tail(&slot->entry, &tei.port->list);
+               /* TODO: select normal or high priority */
+               spin_lock(&t->task_state_lock);
+               t->task_state_flags |= SAS_TASK_AT_INITIATOR;
+               spin_unlock(&t->task_state_lock);
+
+               mvs_hba_memory_dump(mvi, tag, t->task_proto);
+               mvi_dev->runing_req++;
+               ++pass;
+               mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
+               if (n > 1)
+                       t = list_entry(t->list.next, struct sas_task, list);
+       } while (--n);
+       rc = 0;
+       goto out_done;
+
+err_out_tag:
+       mvs_tag_free(mvi, tag);
+err_out:
+
+       dev_printk(KERN_ERR, mvi->dev, "mvsas exec failed[%d]!\n", rc);
+       if (!sas_protocol_ata(t->task_proto))
+               if (n_elem)
+                       dma_unmap_sg(mvi->dev, t->scatter, n_elem,
+                                    t->data_dir);
+out_done:
+       if (likely(pass)) {
+               MVS_CHIP_DISP->start_delivery(mvi,
+                       (mvi->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1));
+       }
+       spin_unlock_irqrestore(&mvi->lock, flags);
+       return rc;
+}
+
+int mvs_queue_command(struct sas_task *task, const int num,
+                       gfp_t gfp_flags)
+{
+       return mvs_task_exec(task, num, gfp_flags, NULL, 0, NULL);
+}
+
+static void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc)
+{
+       u32 slot_idx = rx_desc & RXQ_SLOT_MASK;
+       mvs_tag_clear(mvi, slot_idx);
+}
+
+static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task,
+                         struct mvs_slot_info *slot, u32 slot_idx)
+{
+       if (!slot->task)
+               return;
+       if (!sas_protocol_ata(task->task_proto))
+               if (slot->n_elem)
+                       dma_unmap_sg(mvi->dev, task->scatter,
+                                    slot->n_elem, task->data_dir);
+
+       switch (task->task_proto) {
+       case SAS_PROTOCOL_SMP:
+               dma_unmap_sg(mvi->dev, &task->smp_task.smp_resp, 1,
+                            PCI_DMA_FROMDEVICE);
+               dma_unmap_sg(mvi->dev, &task->smp_task.smp_req, 1,
+                            PCI_DMA_TODEVICE);
+               break;
+
+       case SAS_PROTOCOL_SATA:
+       case SAS_PROTOCOL_STP:
+       case SAS_PROTOCOL_SSP:
+       default:
+               /* do nothing */
+               break;
+       }
+       list_del_init(&slot->entry);
+       task->lldd_task = NULL;
+       slot->task = NULL;
+       slot->port = NULL;
+       slot->slot_tag = 0xFFFFFFFF;
+       mvs_slot_free(mvi, slot_idx);
+}
+
+static void mvs_update_wideport(struct mvs_info *mvi, int i)
+{
+       struct mvs_phy *phy = &mvi->phy[i];
+       struct mvs_port *port = phy->port;
+       int j, no;
+
+       for_each_phy(port->wide_port_phymap, j, no) {
+               if (j & 1) {
+                       MVS_CHIP_DISP->write_port_cfg_addr(mvi, no,
+                                               PHYR_WIDE_PORT);
+                       MVS_CHIP_DISP->write_port_cfg_data(mvi, no,
+                                               port->wide_port_phymap);
+               } else {
+                       MVS_CHIP_DISP->write_port_cfg_addr(mvi, no,
+                                               PHYR_WIDE_PORT);
+                       MVS_CHIP_DISP->write_port_cfg_data(mvi, no,
+                                               0);
+               }
+       }
+}
+
+static u32 mvs_is_phy_ready(struct mvs_info *mvi, int i)
+{
+       u32 tmp;
+       struct mvs_phy *phy = &mvi->phy[i];
+       struct mvs_port *port = phy->port;
+
+       tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, i);
+       if ((tmp & PHY_READY_MASK) && !(phy->irq_status & PHYEV_POOF)) {
+               if (!port)
+                       phy->phy_attached = 1;
+               return tmp;
+       }
+
+       if (port) {
+               if (phy->phy_type & PORT_TYPE_SAS) {
+                       port->wide_port_phymap &= ~(1U << i);
+                       if (!port->wide_port_phymap)
+                               port->port_attached = 0;
+                       mvs_update_wideport(mvi, i);
+               } else if (phy->phy_type & PORT_TYPE_SATA)
+                       port->port_attached = 0;
+               phy->port = NULL;
+               phy->phy_attached = 0;
+               phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
+       }
+       return 0;
+}
+
+static void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf)
+{
+       u32 *s = (u32 *) buf;
+
+       if (!s)
+               return NULL;
+
+       MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG3);
+       s[3] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i);
+
+       MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG2);
+       s[2] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i);
+
+       MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG1);
+       s[1] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i);
+
+       MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0);
+       s[0] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i);
+
+       /* Workaround: take some ATAPI devices for ATA */
+       if (((s[1] & 0x00FFFFFF) == 0x00EB1401) && (*(u8 *)&s[3] == 0x01))
+               s[1] = 0x00EB1401 | (*((u8 *)&s[1] + 3) & 0x10);
+
+       return s;
+}
+
+static u32 mvs_is_sig_fis_received(u32 irq_status)
+{
+       return irq_status & PHYEV_SIG_FIS;
+}
+
+void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st)
+{
+       struct mvs_phy *phy = &mvi->phy[i];
+       struct sas_identify_frame *id;
+
+       id = (struct sas_identify_frame *)phy->frame_rcvd;
+
+       if (get_st) {
+               phy->irq_status = MVS_CHIP_DISP->read_port_irq_stat(mvi, i);
+               phy->phy_status = mvs_is_phy_ready(mvi, i);
+       }
+
+       if (phy->phy_status) {
+               int oob_done = 0;
+               struct asd_sas_phy *sas_phy = &mvi->phy[i].sas_phy;
+
+               oob_done = MVS_CHIP_DISP->oob_done(mvi, i);
+
+               MVS_CHIP_DISP->fix_phy_info(mvi, i, id);
+               if (phy->phy_type & PORT_TYPE_SATA) {
+                       phy->identify.target_port_protocols = SAS_PROTOCOL_STP;
+                       if (mvs_is_sig_fis_received(phy->irq_status)) {
+                               phy->phy_attached = 1;
+                               phy->att_dev_sas_addr =
+                                       i + mvi->id * mvi->chip->n_phy;
+                               if (oob_done)
+                                       sas_phy->oob_mode = SATA_OOB_MODE;
+                               phy->frame_rcvd_size =
+                                   sizeof(struct dev_to_host_fis);
+                               mvs_get_d2h_reg(mvi, i, id);
+                       } else {
+                               u32 tmp;
+                               dev_printk(KERN_DEBUG, mvi->dev,
+                                       "Phy%d : No sig fis\n", i);
+                               tmp = MVS_CHIP_DISP->read_port_irq_mask(mvi, i);
+                               MVS_CHIP_DISP->write_port_irq_mask(mvi, i,
+                                               tmp | PHYEV_SIG_FIS);
+                               phy->phy_attached = 0;
+                               phy->phy_type &= ~PORT_TYPE_SATA;
+                               MVS_CHIP_DISP->phy_reset(mvi, i, 0);
+                               goto out_done;
+                       }
+               }               else if (phy->phy_type & PORT_TYPE_SAS
+                       || phy->att_dev_info & PORT_SSP_INIT_MASK) {
+                       phy->phy_attached = 1;
+                       phy->identify.device_type =
+                               phy->att_dev_info & PORT_DEV_TYPE_MASK;
+
+                       if (phy->identify.device_type == SAS_END_DEV)
+                               phy->identify.target_port_protocols =
+                                                       SAS_PROTOCOL_SSP;
+                       else if (phy->identify.device_type != NO_DEVICE)
+                               phy->identify.target_port_protocols =
+                                                       SAS_PROTOCOL_SMP;
+                       if (oob_done)
+                               sas_phy->oob_mode = SAS_OOB_MODE;
+                       phy->frame_rcvd_size =
+                           sizeof(struct sas_identify_frame);
+               }
+               memcpy(sas_phy->attached_sas_addr,
+                       &phy->att_dev_sas_addr, SAS_ADDR_SIZE);
+
+               if (MVS_CHIP_DISP->phy_work_around)
+                       MVS_CHIP_DISP->phy_work_around(mvi, i);
+       }
+       mv_dprintk("port %d attach dev info is %x\n",
+               i + mvi->id * mvi->chip->n_phy, phy->att_dev_info);
+       mv_dprintk("port %d attach sas addr is %llx\n",
+               i + mvi->id * mvi->chip->n_phy, phy->att_dev_sas_addr);
+out_done:
+       if (get_st)
+               MVS_CHIP_DISP->write_port_irq_stat(mvi, i, phy->irq_status);
+}
+
+static void mvs_port_notify_formed(struct asd_sas_phy *sas_phy, int lock)
+{
+       struct sas_ha_struct *sas_ha = sas_phy->ha;
+       struct mvs_info *mvi = NULL; int i = 0, hi;
+       struct mvs_phy *phy = sas_phy->lldd_phy;
+       struct asd_sas_port *sas_port = sas_phy->port;
+       struct mvs_port *port;
+       unsigned long flags = 0;
+       if (!sas_port)
+               return;
+
+       while (sas_ha->sas_phy[i]) {
+               if (sas_ha->sas_phy[i] == sas_phy)
+                       break;
+               i++;
+       }
+       hi = i/((struct mvs_prv_info *)sas_ha->lldd_ha)->n_phy;
+       mvi = ((struct mvs_prv_info *)sas_ha->lldd_ha)->mvi[hi];
+       if (sas_port->id >= mvi->chip->n_phy)
+               port = &mvi->port[sas_port->id - mvi->chip->n_phy];
+       else
+               port = &mvi->port[sas_port->id];
+       if (lock)
+               spin_lock_irqsave(&mvi->lock, flags);
+       port->port_attached = 1;
+       phy->port = port;
+       if (phy->phy_type & PORT_TYPE_SAS) {
+               port->wide_port_phymap = sas_port->phy_mask;
+               mv_printk("set wide port phy map %x\n", sas_port->phy_mask);
+               mvs_update_wideport(mvi, sas_phy->id);
+       }
+       if (lock)
+               spin_unlock_irqrestore(&mvi->lock, flags);
+}
+
+static void mvs_port_notify_deformed(struct asd_sas_phy *sas_phy, int lock)
+{
+       /*Nothing*/
+}
+
+
+void mvs_port_formed(struct asd_sas_phy *sas_phy)
+{
+       mvs_port_notify_formed(sas_phy, 1);
+}
+
+void mvs_port_deformed(struct asd_sas_phy *sas_phy)
+{
+       mvs_port_notify_deformed(sas_phy, 1);
+}
+
+struct mvs_device *mvs_alloc_dev(struct mvs_info *mvi)
+{
+       u32 dev;
+       for (dev = 0; dev < MVS_MAX_DEVICES; dev++) {
+               if (mvi->devices[dev].dev_type == NO_DEVICE) {
+                       mvi->devices[dev].device_id = dev;
+                       return &mvi->devices[dev];
+               }
+       }
+
+       if (dev == MVS_MAX_DEVICES)
+               mv_printk("max support %d devices, ignore ..\n",
+                       MVS_MAX_DEVICES);
+
+       return NULL;
+}
+
+void mvs_free_dev(struct mvs_device *mvi_dev)
+{
+       u32 id = mvi_dev->device_id;
+       memset(mvi_dev, 0, sizeof(*mvi_dev));
+       mvi_dev->device_id = id;
+       mvi_dev->dev_type = NO_DEVICE;
+       mvi_dev->dev_status = MVS_DEV_NORMAL;
+       mvi_dev->taskfileset = MVS_ID_NOT_MAPPED;
+}
+
+int mvs_dev_found_notify(struct domain_device *dev, int lock)
+{
+       unsigned long flags = 0;
+       int res = 0;
+       struct mvs_info *mvi = NULL;
+       struct domain_device *parent_dev = dev->parent;
+       struct mvs_device *mvi_device;
+
+       mvi = mvs_find_dev_mvi(dev);
+
+       if (lock)
+               spin_lock_irqsave(&mvi->lock, flags);
+
+       mvi_device = mvs_alloc_dev(mvi);
+       if (!mvi_device) {
+               res = -1;
+               goto found_out;
+       }
+       dev->lldd_dev = mvi_device;
+       mvi_device->dev_type = dev->dev_type;
+       mvi_device->mvi_info = mvi;
+       if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) {
+               int phy_id;
+               u8 phy_num = parent_dev->ex_dev.num_phys;
+               struct ex_phy *phy;
+               for (phy_id = 0; phy_id < phy_num; phy_id++) {
+                       phy = &parent_dev->ex_dev.ex_phy[phy_id];
+                       if (SAS_ADDR(phy->attached_sas_addr) ==
+                               SAS_ADDR(dev->sas_addr)) {
+                               mvi_device->attached_phy = phy_id;
+                               break;
+                       }
+               }
+
+               if (phy_id == phy_num) {
+                       mv_printk("Error: no attached dev:%016llx"
+                               "at ex:%016llx.\n",
+                               SAS_ADDR(dev->sas_addr),
+                               SAS_ADDR(parent_dev->sas_addr));
+                       res = -1;
+               }
+       }
+
+found_out:
+       if (lock)
+               spin_unlock_irqrestore(&mvi->lock, flags);
+       return res;
+}
+
+int mvs_dev_found(struct domain_device *dev)
+{
+       return mvs_dev_found_notify(dev, 1);
+}
+
+void mvs_dev_gone_notify(struct domain_device *dev, int lock)
+{
+       unsigned long flags = 0;
+       struct mvs_device *mvi_dev = dev->lldd_dev;
+       struct mvs_info *mvi = mvi_dev->mvi_info;
+
+       if (lock)
+               spin_lock_irqsave(&mvi->lock, flags);
+
+       if (mvi_dev) {
+               mv_dprintk("found dev[%d:%x] is gone.\n",
+                       mvi_dev->device_id, mvi_dev->dev_type);
+               mvs_free_reg_set(mvi, mvi_dev);
+               mvs_free_dev(mvi_dev);
+       } else {
+               mv_dprintk("found dev has gone.\n");
+       }
+       dev->lldd_dev = NULL;
+
+       if (lock)
+               spin_unlock_irqrestore(&mvi->lock, flags);
+}
+
+
+void mvs_dev_gone(struct domain_device *dev)
+{
+       mvs_dev_gone_notify(dev, 1);
+}
+
+static  struct sas_task *mvs_alloc_task(void)
+{
+       struct sas_task *task = kzalloc(sizeof(struct sas_task), GFP_KERNEL);
+
+       if (task) {
+               INIT_LIST_HEAD(&task->list);
+               spin_lock_init(&task->task_state_lock);
+               task->task_state_flags = SAS_TASK_STATE_PENDING;
+               init_timer(&task->timer);
+               init_completion(&task->completion);
+       }
+       return task;
+}
+
+static  void mvs_free_task(struct sas_task *task)
+{
+       if (task) {
+               BUG_ON(!list_empty(&task->list));
+               kfree(task);
+       }
+}
+
+static void mvs_task_done(struct sas_task *task)
+{
+       if (!del_timer(&task->timer))
+               return;
+       complete(&task->completion);
+}
+
+static void mvs_tmf_timedout(unsigned long data)
+{
+       struct sas_task *task = (struct sas_task *)data;
+
+       task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+       complete(&task->completion);
+}
+
+/* XXX */
+#define MVS_TASK_TIMEOUT 20
+static int mvs_exec_internal_tmf_task(struct domain_device *dev,
+                       void *parameter, u32 para_len, struct mvs_tmf_task *tmf)
+{
+       int res, retry;
+       struct sas_task *task = NULL;
+
+       for (retry = 0; retry < 3; retry++) {
+               task = mvs_alloc_task();
+               if (!task)
+                       return -ENOMEM;
+
+               task->dev = dev;
+               task->task_proto = dev->tproto;
+
+               memcpy(&task->ssp_task, parameter, para_len);
+               task->task_done = mvs_task_done;
+
+               task->timer.data = (unsigned long) task;
+               task->timer.function = mvs_tmf_timedout;
+               task->timer.expires = jiffies + MVS_TASK_TIMEOUT*HZ;
+               add_timer(&task->timer);
+
+               res = mvs_task_exec(task, 1, GFP_KERNEL, NULL, 1, tmf);
+
+               if (res) {
+                       del_timer(&task->timer);
+                       mv_printk("executing internel task failed:%d\n", res);
+                       goto ex_err;
+               }
+
+               wait_for_completion(&task->completion);
+               res = -TMF_RESP_FUNC_FAILED;
+               /* Even TMF timed out, return direct. */
+               if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
+                       if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
+                               mv_printk("TMF task[%x] timeout.\n", tmf->tmf);
+                               goto ex_err;
+                       }
+               }
+
+               if (task->task_status.resp == SAS_TASK_COMPLETE &&
+                   task->task_status.stat == SAM_GOOD) {
+                       res = TMF_RESP_FUNC_COMPLETE;
+                       break;
+               }
+
+               if (task->task_status.resp == SAS_TASK_COMPLETE &&
+                     task->task_status.stat == SAS_DATA_UNDERRUN) {
+                       /* no error, but return the number of bytes of
+                        * underrun */
+                       res = task->task_status.residual;
+                       break;
+               }
+
+               if (task->task_status.resp == SAS_TASK_COMPLETE &&
+                     task->task_status.stat == SAS_DATA_OVERRUN) {
+                       mv_dprintk("blocked task error.\n");
+                       res = -EMSGSIZE;
+                       break;
+               } else {
+                       mv_dprintk(" task to dev %016llx response: 0x%x "
+                                   "status 0x%x\n",
+                                   SAS_ADDR(dev->sas_addr),
+                                   task->task_status.resp,
+                                   task->task_status.stat);
+                       mvs_free_task(task);
+                       task = NULL;
+
+               }
+       }
+ex_err:
+       BUG_ON(retry == 3 && task != NULL);
+       if (task != NULL)
+               mvs_free_task(task);
+       return res;
+}
+
+static int mvs_debug_issue_ssp_tmf(struct domain_device *dev,
+                               u8 *lun, struct mvs_tmf_task *tmf)
+{
+       struct sas_ssp_task ssp_task;
+       DECLARE_COMPLETION_ONSTACK(completion);
+       if (!(dev->tproto & SAS_PROTOCOL_SSP))
+               return TMF_RESP_FUNC_ESUPP;
+
+       strncpy((u8 *)&ssp_task.LUN, lun, 8);
+
+       return mvs_exec_internal_tmf_task(dev, &ssp_task,
+                               sizeof(ssp_task), tmf);
+}
+
+
+/*  Standard mandates link reset for ATA  (type 0)
+    and hard reset for SSP (type 1) , only for RECOVERY */
+static int mvs_debug_I_T_nexus_reset(struct domain_device *dev)
+{
+       int rc;
+       struct sas_phy *phy = sas_find_local_phy(dev);
+       int reset_type = (dev->dev_type == SATA_DEV ||
+                       (dev->tproto & SAS_PROTOCOL_STP)) ? 0 : 1;
+       rc = sas_phy_reset(phy, reset_type);
+       msleep(2000);
+       return rc;
+}
+
+/* mandatory SAM-3 */
+int mvs_lu_reset(struct domain_device *dev, u8 *lun)
+{
+       unsigned long flags;
+       int i, phyno[WIDE_PORT_MAX_PHY], num , rc = TMF_RESP_FUNC_FAILED;
+       struct mvs_tmf_task tmf_task;
+       struct mvs_device * mvi_dev = dev->lldd_dev;
+       struct mvs_info *mvi = mvi_dev->mvi_info;
+
+       tmf_task.tmf = TMF_LU_RESET;
+       mvi_dev->dev_status = MVS_DEV_EH;
+       rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task);
+       if (rc == TMF_RESP_FUNC_COMPLETE) {
+               num = mvs_find_dev_phyno(dev, phyno);
+               spin_lock_irqsave(&mvi->lock, flags);
+               for (i = 0; i < num; i++)
+                       mvs_release_task(mvi, phyno[i], dev);
+               spin_unlock_irqrestore(&mvi->lock, flags);
+       }
+       /* If failed, fall-through I_T_Nexus reset */
+       mv_printk("%s for device[%x]:rc= %d\n", __func__,
+                       mvi_dev->device_id, rc);
+       return rc;
+}
+
+int mvs_I_T_nexus_reset(struct domain_device *dev)
+{
+       unsigned long flags;
+       int i, phyno[WIDE_PORT_MAX_PHY], num , rc = TMF_RESP_FUNC_FAILED;
+       struct mvs_device * mvi_dev = (struct mvs_device *)dev->lldd_dev;
+       struct mvs_info *mvi = mvi_dev->mvi_info;
+
+       if (mvi_dev->dev_status != MVS_DEV_EH)
+               return TMF_RESP_FUNC_COMPLETE;
+       rc = mvs_debug_I_T_nexus_reset(dev);
+       mv_printk("%s for device[%x]:rc= %d\n",
+               __func__, mvi_dev->device_id, rc);
+
+       /* housekeeper */
+       num = mvs_find_dev_phyno(dev, phyno);
+       spin_lock_irqsave(&mvi->lock, flags);
+       for (i = 0; i < num; i++)
+               mvs_release_task(mvi, phyno[i], dev);
+       spin_unlock_irqrestore(&mvi->lock, flags);
+
+       return rc;
+}
+/* optional SAM-3 */
+int mvs_query_task(struct sas_task *task)
+{
+       u32 tag;
+       struct scsi_lun lun;
+       struct mvs_tmf_task tmf_task;
+       int rc = TMF_RESP_FUNC_FAILED;
+
+       if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) {
+               struct scsi_cmnd * cmnd = (struct scsi_cmnd *)task->uldd_task;
+               struct domain_device *dev = task->dev;
+               struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev;
+               struct mvs_info *mvi = mvi_dev->mvi_info;
+
+               int_to_scsilun(cmnd->device->lun, &lun);
+               rc = mvs_find_tag(mvi, task, &tag);
+               if (rc == 0) {
+                       rc = TMF_RESP_FUNC_FAILED;
+                       return rc;
+               }
+
+               tmf_task.tmf = TMF_QUERY_TASK;
+               tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag);
+
+               rc = mvs_debug_issue_ssp_tmf(dev, lun.scsi_lun, &tmf_task);
+               switch (rc) {
+               /* The task is still in Lun, release it then */
+               case TMF_RESP_FUNC_SUCC:
+               /* The task is not in Lun or failed, reset the phy */
+               case TMF_RESP_FUNC_FAILED:
+               case TMF_RESP_FUNC_COMPLETE:
+                       break;
+               }
+       }
+       mv_printk("%s:rc= %d\n", __func__, rc);
+       return rc;
+}
+
+/*  mandatory SAM-3, still need free task/slot info */
+int mvs_abort_task(struct sas_task *task)
+{
+       struct scsi_lun lun;
+       struct mvs_tmf_task tmf_task;
+       struct domain_device *dev = task->dev;
+       struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev;
+       struct mvs_info *mvi = mvi_dev->mvi_info;
+       int rc = TMF_RESP_FUNC_FAILED;
+       unsigned long flags;
+       u32 tag;
+
+       if (mvi->exp_req)
+               mvi->exp_req--;
+       spin_lock_irqsave(&task->task_state_lock, flags);
+       if (task->task_state_flags & SAS_TASK_STATE_DONE) {
+               spin_unlock_irqrestore(&task->task_state_lock, flags);
+               rc = TMF_RESP_FUNC_COMPLETE;
+               goto out;
+       }
+       spin_unlock_irqrestore(&task->task_state_lock, flags);
+       if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) {
+               struct scsi_cmnd * cmnd = (struct scsi_cmnd *)task->uldd_task;
+
+               int_to_scsilun(cmnd->device->lun, &lun);
+               rc = mvs_find_tag(mvi, task, &tag);
+               if (rc == 0) {
+                       mv_printk("No such tag in %s\n", __func__);
+                       rc = TMF_RESP_FUNC_FAILED;
+                       return rc;
+               }
+
+               tmf_task.tmf = TMF_ABORT_TASK;
+               tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag);
+
+               rc = mvs_debug_issue_ssp_tmf(dev, lun.scsi_lun, &tmf_task);
+
+               /* if successful, clear the task and callback forwards.*/
+               if (rc == TMF_RESP_FUNC_COMPLETE) {
+                       u32 slot_no;
+                       struct mvs_slot_info *slot;
+
+                       if (task->lldd_task) {
+                               slot = task->lldd_task;
+                               slot_no = (u32) (slot - mvi->slot_info);
+                               mvs_slot_complete(mvi, slot_no, 1);
+                       }
+               }
+       } else if (task->task_proto & SAS_PROTOCOL_SATA ||
+               task->task_proto & SAS_PROTOCOL_STP) {
+               /* to do free register_set */
+       } else {
+               /* SMP */
+
+       }
+out:
+       if (rc != TMF_RESP_FUNC_COMPLETE)
+               mv_printk("%s:rc= %d\n", __func__, rc);
+       return rc;
+}
+
+int mvs_abort_task_set(struct domain_device *dev, u8 *lun)
+{
+       int rc = TMF_RESP_FUNC_FAILED;
+       struct mvs_tmf_task tmf_task;
+
+       tmf_task.tmf = TMF_ABORT_TASK_SET;
+       rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task);
+
+       return rc;
+}
+
+int mvs_clear_aca(struct domain_device *dev, u8 *lun)
+{
+       int rc = TMF_RESP_FUNC_FAILED;
+       struct mvs_tmf_task tmf_task;
+
+       tmf_task.tmf = TMF_CLEAR_ACA;
+       rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task);
+
+       return rc;
+}
+
+int mvs_clear_task_set(struct domain_device *dev, u8 *lun)
+{
+       int rc = TMF_RESP_FUNC_FAILED;
+       struct mvs_tmf_task tmf_task;
+
+       tmf_task.tmf = TMF_CLEAR_TASK_SET;
+       rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task);
+
+       return rc;
+}
+
+static int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task,
+                       u32 slot_idx, int err)
+{
+       struct mvs_device *mvi_dev = task->dev->lldd_dev;
+       struct task_status_struct *tstat = &task->task_status;
+       struct ata_task_resp *resp = (struct ata_task_resp *)tstat->buf;
+       int stat = SAM_GOOD;
+
+
+       resp->frame_len = sizeof(struct dev_to_host_fis);
+       memcpy(&resp->ending_fis[0],
+              SATA_RECEIVED_D2H_FIS(mvi_dev->taskfileset),
+              sizeof(struct dev_to_host_fis));
+       tstat->buf_valid_size = sizeof(*resp);
+       if (unlikely(err))
+               stat = SAS_PROTO_RESPONSE;
+       return stat;
+}
+
+static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
+                        u32 slot_idx)
+{
+       struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
+       int stat;
+       u32 err_dw0 = le32_to_cpu(*(u32 *) (slot->response));
+       u32 tfs = 0;
+       enum mvs_port_type type = PORT_TYPE_SAS;
+
+       if (err_dw0 & CMD_ISS_STPD)
+               MVS_CHIP_DISP->issue_stop(mvi, type, tfs);
+
+       MVS_CHIP_DISP->command_active(mvi, slot_idx);
+
+       stat = SAM_CHECK_COND;
+       switch (task->task_proto) {
+       case SAS_PROTOCOL_SSP:
+               stat = SAS_ABORTED_TASK;
+               break;
+       case SAS_PROTOCOL_SMP:
+               stat = SAM_CHECK_COND;
+               break;
+
+       case SAS_PROTOCOL_SATA:
+       case SAS_PROTOCOL_STP:
+       case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+       {
+               if (err_dw0 == 0x80400002)
+                       mv_printk("find reserved error, why?\n");
+
+               task->ata_task.use_ncq = 0;
+               stat = SAS_PROTO_RESPONSE;
+               mvs_sata_done(mvi, task, slot_idx, 1);
+
+       }
+               break;
+       default:
+               break;
+       }
+
+       return stat;
+}
+
+int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
+{
+       u32 slot_idx = rx_desc & RXQ_SLOT_MASK;
+       struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
+       struct sas_task *task = slot->task;
+       struct mvs_device *mvi_dev = NULL;
+       struct task_status_struct *tstat;
+
+       bool aborted;
+       void *to;
+       enum exec_status sts;
+
+       if (mvi->exp_req)
+               mvi->exp_req--;
+       if (unlikely(!task || !task->lldd_task))
+               return -1;
+
+       tstat = &task->task_status;
+       mvi_dev = task->dev->lldd_dev;
+
+       mvs_hba_cq_dump(mvi);
+
+       spin_lock(&task->task_state_lock);
+       task->task_state_flags &=
+               ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
+       task->task_state_flags |= SAS_TASK_STATE_DONE;
+       /* race condition*/
+       aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED;
+       spin_unlock(&task->task_state_lock);
+
+       memset(tstat, 0, sizeof(*tstat));
+       tstat->resp = SAS_TASK_COMPLETE;
+
+       if (unlikely(aborted)) {
+               tstat->stat = SAS_ABORTED_TASK;
+               if (mvi_dev)
+                       mvi_dev->runing_req--;
+               if (sas_protocol_ata(task->task_proto))
+                       mvs_free_reg_set(mvi, mvi_dev);
+
+               mvs_slot_task_free(mvi, task, slot, slot_idx);
+               return -1;
+       }
+
+       if (unlikely(!mvi_dev || !slot->port->port_attached || flags)) {
+               mv_dprintk("port has not device.\n");
+               tstat->stat = SAS_PHY_DOWN;
+               goto out;
+       }
+
+       /*
+       if (unlikely((rx_desc & RXQ_ERR) || (*(u64 *) slot->response))) {
+                mv_dprintk("Find device[%016llx] RXQ_ERR %X,
+                err info:%016llx\n",
+                SAS_ADDR(task->dev->sas_addr),
+                rx_desc, (u64)(*(u64 *) slot->response));
+       }
+       */
+
+       /* error info record present */
+       if (unlikely((rx_desc & RXQ_ERR) && (*(u64 *) slot->response))) {
+               tstat->stat = mvs_slot_err(mvi, task, slot_idx);
+               goto out;
+       }
+
+       switch (task->task_proto) {
+       case SAS_PROTOCOL_SSP:
+               /* hw says status == 0, datapres == 0 */
+               if (rx_desc & RXQ_GOOD) {
+                       tstat->stat = SAM_GOOD;
+                       tstat->resp = SAS_TASK_COMPLETE;
+               }
+               /* response frame present */
+               else if (rx_desc & RXQ_RSP) {
+                       struct ssp_response_iu *iu = slot->response +
+                                               sizeof(struct mvs_err_info);
+                       sas_ssp_task_response(mvi->dev, task, iu);
+               } else
+                       tstat->stat = SAM_CHECK_COND;
+               break;
+
+       case SAS_PROTOCOL_SMP: {
+                       struct scatterlist *sg_resp = &task->smp_task.smp_resp;
+                       tstat->stat = SAM_GOOD;
+                       to = kmap_atomic(sg_page(sg_resp), KM_IRQ0);
+                       memcpy(to + sg_resp->offset,
+                               slot->response + sizeof(struct mvs_err_info),
+                               sg_dma_len(sg_resp));
+                       kunmap_atomic(to, KM_IRQ0);
+                       break;
+               }
+
+       case SAS_PROTOCOL_SATA:
+       case SAS_PROTOCOL_STP:
+       case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: {
+                       tstat->stat = mvs_sata_done(mvi, task, slot_idx, 0);
+                       break;
+               }
+
+       default:
+               tstat->stat = SAM_CHECK_COND;
+               break;
+       }
+
+out:
+       if (mvi_dev) {
+               mvi_dev->runing_req--;
+               if (sas_protocol_ata(task->task_proto))
+                       mvs_free_reg_set(mvi, mvi_dev);
+       }
+       mvs_slot_task_free(mvi, task, slot, slot_idx);
+       sts = tstat->stat;
+
+       spin_unlock(&mvi->lock);
+       if (task->task_done)
+               task->task_done(task);
+       else
+               mv_dprintk("why has not task_done.\n");
+       spin_lock(&mvi->lock);
+
+       return sts;
+}
+
+void mvs_release_task(struct mvs_info *mvi,
+               int phy_no, struct domain_device *dev)
+{
+       int i = 0; u32 slot_idx;
+       struct mvs_phy *phy;
+       struct mvs_port *port;
+       struct mvs_slot_info *slot, *slot2;
+
+       phy = &mvi->phy[phy_no];
+       port = phy->port;
+       if (!port)
+               return;
+
+       list_for_each_entry_safe(slot, slot2, &port->list, entry) {
+               struct sas_task *task;
+               slot_idx = (u32) (slot - mvi->slot_info);
+               task = slot->task;
+
+               if (dev && task->dev != dev)
+                       continue;
+
+               mv_printk("Release slot [%x] tag[%x], task [%p]:\n",
+                       slot_idx, slot->slot_tag, task);
+
+               if (task->task_proto & SAS_PROTOCOL_SSP) {
+                       mv_printk("attached with SSP task CDB[");
+                       for (i = 0; i < 16; i++)
+                               mv_printk(" %02x", task->ssp_task.cdb[i]);
+                       mv_printk(" ]\n");
+               }
+
+               mvs_slot_complete(mvi, slot_idx, 1);
+       }
+}
+
+static void mvs_phy_disconnected(struct mvs_phy *phy)
+{
+       phy->phy_attached = 0;
+       phy->att_dev_info = 0;
+       phy->att_dev_sas_addr = 0;
+}
+
+static void mvs_work_queue(struct work_struct *work)
+{
+       struct delayed_work *dw = container_of(work, struct delayed_work, work);
+       struct mvs_wq *mwq = container_of(dw, struct mvs_wq, work_q);
+       struct mvs_info *mvi = mwq->mvi;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mvi->lock, flags);
+       if (mwq->handler & PHY_PLUG_EVENT) {
+               u32 phy_no = (unsigned long) mwq->data;
+               struct sas_ha_struct *sas_ha = mvi->sas;
+               struct mvs_phy *phy = &mvi->phy[phy_no];
+               struct asd_sas_phy *sas_phy = &phy->sas_phy;
+
+               if (phy->phy_event & PHY_PLUG_OUT) {
+                       u32 tmp;
+                       struct sas_identify_frame *id;
+                       id = (struct sas_identify_frame *)phy->frame_rcvd;
+                       tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, phy_no);
+                       phy->phy_event &= ~PHY_PLUG_OUT;
+                       if (!(tmp & PHY_READY_MASK)) {
+                               sas_phy_disconnected(sas_phy);
+                               mvs_phy_disconnected(phy);
+                               sas_ha->notify_phy_event(sas_phy,
+                                       PHYE_LOSS_OF_SIGNAL);
+                               mv_dprintk("phy%d Removed Device\n", phy_no);
+                       } else {
+                               MVS_CHIP_DISP->detect_porttype(mvi, phy_no);
+                               mvs_update_phyinfo(mvi, phy_no, 1);
+                               mvs_bytes_dmaed(mvi, phy_no);
+                               mvs_port_notify_formed(sas_phy, 0);
+                               mv_dprintk("phy%d Attached Device\n", phy_no);
+                       }
+               }
+       }
+       list_del(&mwq->entry);
+       spin_unlock_irqrestore(&mvi->lock, flags);
+       kfree(mwq);
+}
+
+static int mvs_handle_event(struct mvs_info *mvi, void *data, int handler)
+{
+       struct mvs_wq *mwq;
+       int ret = 0;
+
+       mwq = kmalloc(sizeof(struct mvs_wq), GFP_ATOMIC);
+       if (mwq) {
+               mwq->mvi = mvi;
+               mwq->data = data;
+               mwq->handler = handler;
+               MV_INIT_DELAYED_WORK(&mwq->work_q, mvs_work_queue, mwq);
+               list_add_tail(&mwq->entry, &mvi->wq_list);
+               schedule_delayed_work(&mwq->work_q, HZ * 2);
+       } else
+               ret = -ENOMEM;
+
+       return ret;
+}
+
+static void mvs_sig_time_out(unsigned long tphy)
+{
+       struct mvs_phy *phy = (struct mvs_phy *)tphy;
+       struct mvs_info *mvi = phy->mvi;
+       u8 phy_no;
+
+       for (phy_no = 0; phy_no < mvi->chip->n_phy; phy_no++) {
+               if (&mvi->phy[phy_no] == phy) {
+                       mv_dprintk("Get signature time out, reset phy %d\n",
+                               phy_no+mvi->id*mvi->chip->n_phy);
+                       MVS_CHIP_DISP->phy_reset(mvi, phy_no, 1);
+               }
+       }
+}
+
+static void mvs_sig_remove_timer(struct mvs_phy *phy)
+{
+       if (phy->timer.function)
+               del_timer(&phy->timer);
+       phy->timer.function = NULL;
+}
+
+void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
+{
+       u32 tmp;
+       struct sas_ha_struct *sas_ha = mvi->sas;
+       struct mvs_phy *phy = &mvi->phy[phy_no];
+       struct asd_sas_phy *sas_phy = &phy->sas_phy;
+
+       phy->irq_status = MVS_CHIP_DISP->read_port_irq_stat(mvi, phy_no);
+       mv_dprintk("port %d ctrl sts=0x%X.\n", phy_no+mvi->id*mvi->chip->n_phy,
+               MVS_CHIP_DISP->read_phy_ctl(mvi, phy_no));
+       mv_dprintk("Port %d irq sts = 0x%X\n", phy_no+mvi->id*mvi->chip->n_phy,
+               phy->irq_status);
+
+       /*
+       * events is port event now ,
+       * we need check the interrupt status which belongs to per port.
+       */
+
+       if (phy->irq_status & PHYEV_DCDR_ERR)
+               mv_dprintk("port %d STP decoding error.\n",
+               phy_no+mvi->id*mvi->chip->n_phy);
+
+       if (phy->irq_status & PHYEV_POOF) {
+               if (!(phy->phy_event & PHY_PLUG_OUT)) {
+                       int dev_sata = phy->phy_type & PORT_TYPE_SATA;
+                       int ready;
+                       mvs_release_task(mvi, phy_no, NULL);
+                       phy->phy_event |= PHY_PLUG_OUT;
+                       mvs_handle_event(mvi,
+                               (void *)(unsigned long)phy_no,
+                               PHY_PLUG_EVENT);
+                       ready = mvs_is_phy_ready(mvi, phy_no);
+                       if (!ready)
+                               mv_dprintk("phy%d Unplug Notice\n",
+                                       phy_no +
+                                       mvi->id * mvi->chip->n_phy);
+                       if (ready || dev_sata) {
+                               if (MVS_CHIP_DISP->stp_reset)
+                                       MVS_CHIP_DISP->stp_reset(mvi,
+                                                       phy_no);
+                               else
+                                       MVS_CHIP_DISP->phy_reset(mvi,
+                                                       phy_no, 0);
+                               return;
+                       }
+               }
+       }
+
+       if (phy->irq_status & PHYEV_COMWAKE) {
+               tmp = MVS_CHIP_DISP->read_port_irq_mask(mvi, phy_no);
+               MVS_CHIP_DISP->write_port_irq_mask(mvi, phy_no,
+                                       tmp | PHYEV_SIG_FIS);
+               if (phy->timer.function == NULL) {
+                       phy->timer.data = (unsigned long)phy;
+                       phy->timer.function = mvs_sig_time_out;
+                       phy->timer.expires = jiffies + 10*HZ;
+                       add_timer(&phy->timer);
+               }
+       }
+       if (phy->irq_status & (PHYEV_SIG_FIS | PHYEV_ID_DONE)) {
+               phy->phy_status = mvs_is_phy_ready(mvi, phy_no);
+               mvs_sig_remove_timer(phy);
+               mv_dprintk("notify plug in on phy[%d]\n", phy_no);
+               if (phy->phy_status) {
+                       mdelay(10);
+                       MVS_CHIP_DISP->detect_porttype(mvi, phy_no);
+                       if (phy->phy_type & PORT_TYPE_SATA) {
+                               tmp = MVS_CHIP_DISP->read_port_irq_mask(
+                                               mvi, phy_no);
+                               tmp &= ~PHYEV_SIG_FIS;
+                               MVS_CHIP_DISP->write_port_irq_mask(mvi,
+                                                       phy_no, tmp);
+                       }
+                       mvs_update_phyinfo(mvi, phy_no, 0);
+                       mvs_bytes_dmaed(mvi, phy_no);
+                       /* whether driver is going to handle hot plug */
+                       if (phy->phy_event & PHY_PLUG_OUT) {
+                               mvs_port_notify_formed(sas_phy, 0);
+                               phy->phy_event &= ~PHY_PLUG_OUT;
+                       }
+               } else {
+                       mv_dprintk("plugin interrupt but phy%d is gone\n",
+                               phy_no + mvi->id*mvi->chip->n_phy);
+               }
+       } else if (phy->irq_status & PHYEV_BROAD_CH) {
+               mv_dprintk("port %d broadcast change.\n",
+                       phy_no + mvi->id*mvi->chip->n_phy);
+               /* exception for Samsung disk drive*/
+               mdelay(1000);
+               sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD);
+       }
+       MVS_CHIP_DISP->write_port_irq_stat(mvi, phy_no, phy->irq_status);
+}
+
+int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
+{
+       u32 rx_prod_idx, rx_desc;
+       bool attn = false;
+
+       /* the first dword in the RX ring is special: it contains
+        * a mirror of the hardware's RX producer index, so that
+        * we don't have to stall the CPU reading that register.
+        * The actual RX ring is offset by one dword, due to this.
+        */
+       rx_prod_idx = mvi->rx_cons;
+       mvi->rx_cons = le32_to_cpu(mvi->rx[0]);
+       if (mvi->rx_cons == 0xfff)      /* h/w hasn't touched RX ring yet */
+               return 0;
+
+       /* The CMPL_Q may come late, read from register and try again
+       * note: if coalescing is enabled,
+       * it will need to read from register every time for sure
+       */
+       if (unlikely(mvi->rx_cons == rx_prod_idx))
+               mvi->rx_cons = MVS_CHIP_DISP->rx_update(mvi) & RX_RING_SZ_MASK;
+
+       if (mvi->rx_cons == rx_prod_idx)
+               return 0;
+
+       while (mvi->rx_cons != rx_prod_idx) {
+               /* increment our internal RX consumer pointer */
+               rx_prod_idx = (rx_prod_idx + 1) & (MVS_RX_RING_SZ - 1);
+               rx_desc = le32_to_cpu(mvi->rx[rx_prod_idx + 1]);
+
+               if (likely(rx_desc & RXQ_DONE))
+                       mvs_slot_complete(mvi, rx_desc, 0);
+               if (rx_desc & RXQ_ATTN) {
+                       attn = true;
+               } else if (rx_desc & RXQ_ERR) {
+                       if (!(rx_desc & RXQ_DONE))
+                               mvs_slot_complete(mvi, rx_desc, 0);
+               } else if (rx_desc & RXQ_SLOT_RESET) {
+                       mvs_slot_free(mvi, rx_desc);
+               }
+       }
+
+       if (attn && self_clear)
+               MVS_CHIP_DISP->int_full(mvi);
+       return 0;
+}
+
diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h
new file mode 100644 (file)
index 0000000..aa2270a
--- /dev/null
@@ -0,0 +1,406 @@
+/*
+ * Marvell 88SE64xx/88SE94xx main function head file
+ *
+ * Copyright 2007 Red Hat, Inc.
+ * Copyright 2008 Marvell. <kewei@marvell.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+*/
+
+#ifndef _MV_SAS_H_
+#define _MV_SAS_H_
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/vmalloc.h>
+#include <scsi/libsas.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/sas_ata.h>
+#include <linux/version.h>
+#include "mv_defs.h"
+
+#define DRV_NAME               "mvsas"
+#define DRV_VERSION            "0.8.2"
+#define _MV_DUMP               0
+#define MVS_ID_NOT_MAPPED      0x7f
+/* #define DISABLE_HOTPLUG_DMA_FIX */
+#define MAX_EXP_RUNNING_REQ    2
+#define WIDE_PORT_MAX_PHY              4
+#define        MV_DISABLE_NCQ  0
+#define mv_printk(fmt, arg ...)        \
+       printk(KERN_DEBUG"%s %d:" fmt, __FILE__, __LINE__, ## arg)
+#ifdef MV_DEBUG
+#define mv_dprintk(format, arg...)     \
+       printk(KERN_DEBUG"%s %d:" format, __FILE__, __LINE__, ## arg)
+#else
+#define mv_dprintk(format, arg...)
+#endif
+#define MV_MAX_U32                     0xffffffff
+
+extern struct mvs_tgt_initiator mvs_tgt;
+extern struct mvs_info *tgt_mvi;
+extern const struct mvs_dispatch mvs_64xx_dispatch;
+extern const struct mvs_dispatch mvs_94xx_dispatch;
+
+#define DEV_IS_EXPANDER(type)  \
+       ((type == EDGE_DEV) || (type == FANOUT_DEV))
+
+#define bit(n) ((u32)1 << n)
+
+#define for_each_phy(__lseq_mask, __mc, __lseq)                        \
+       for ((__mc) = (__lseq_mask), (__lseq) = 0;              \
+                                       (__mc) != 0 ;           \
+                                       (++__lseq), (__mc) >>= 1)
+
+#define MV_INIT_DELAYED_WORK(w, f, d)  INIT_DELAYED_WORK(w, f)
+#define UNASSOC_D2H_FIS(id)            \
+       ((void *) mvi->rx_fis + 0x100 * id)
+#define SATA_RECEIVED_FIS_LIST(reg_set)        \
+       ((void *) mvi->rx_fis + mvi->chip->fis_offs + 0x100 * reg_set)
+#define SATA_RECEIVED_SDB_FIS(reg_set) \
+       (SATA_RECEIVED_FIS_LIST(reg_set) + 0x58)
+#define SATA_RECEIVED_D2H_FIS(reg_set) \
+       (SATA_RECEIVED_FIS_LIST(reg_set) + 0x40)
+#define SATA_RECEIVED_PIO_FIS(reg_set) \
+       (SATA_RECEIVED_FIS_LIST(reg_set) + 0x20)
+#define SATA_RECEIVED_DMA_FIS(reg_set) \
+       (SATA_RECEIVED_FIS_LIST(reg_set) + 0x00)
+
+enum dev_status {
+       MVS_DEV_NORMAL = 0x0,
+       MVS_DEV_EH      = 0x1,
+};
+
+
+struct mvs_info;
+
+struct mvs_dispatch {
+       char *name;
+       int (*chip_init)(struct mvs_info *mvi);
+       int (*spi_init)(struct mvs_info *mvi);
+       int (*chip_ioremap)(struct mvs_info *mvi);
+       void (*chip_iounmap)(struct mvs_info *mvi);
+       irqreturn_t (*isr)(struct mvs_info *mvi, int irq, u32 stat);
+       u32 (*isr_status)(struct mvs_info *mvi, int irq);
+       void (*interrupt_enable)(struct mvs_info *mvi);
+       void (*interrupt_disable)(struct mvs_info *mvi);
+
+       u32 (*read_phy_ctl)(struct mvs_info *mvi, u32 port);
+       void (*write_phy_ctl)(struct mvs_info *mvi, u32 port, u32 val);
+
+       u32 (*read_port_cfg_data)(struct mvs_info *mvi, u32 port);
+       void (*write_port_cfg_data)(struct mvs_info *mvi, u32 port, u32 val);
+       void (*write_port_cfg_addr)(struct mvs_info *mvi, u32 port, u32 addr);
+
+       u32 (*read_port_vsr_data)(struct mvs_info *mvi, u32 port);
+       void (*write_port_vsr_data)(struct mvs_info *mvi, u32 port, u32 val);
+       void (*write_port_vsr_addr)(struct mvs_info *mvi, u32 port, u32 addr);
+
+       u32 (*read_port_irq_stat)(struct mvs_info *mvi, u32 port);
+       void (*write_port_irq_stat)(struct mvs_info *mvi, u32 port, u32 val);
+
+       u32 (*read_port_irq_mask)(struct mvs_info *mvi, u32 port);
+       void (*write_port_irq_mask)(struct mvs_info *mvi, u32 port, u32 val);
+
+       void (*get_sas_addr)(void *buf, u32 buflen);
+       void (*command_active)(struct mvs_info *mvi, u32 slot_idx);
+       void (*issue_stop)(struct mvs_info *mvi, enum mvs_port_type type,
+                               u32 tfs);
+       void (*start_delivery)(struct mvs_info *mvi, u32 tx);
+       u32 (*rx_update)(struct mvs_info *mvi);
+       void (*int_full)(struct mvs_info *mvi);
+       u8 (*assign_reg_set)(struct mvs_info *mvi, u8 *tfs);
+       void (*free_reg_set)(struct mvs_info *mvi, u8 *tfs);
+       u32 (*prd_size)(void);
+       u32 (*prd_count)(void);
+       void (*make_prd)(struct scatterlist *scatter, int nr, void *prd);
+       void (*detect_porttype)(struct mvs_info *mvi, int i);
+       int (*oob_done)(struct mvs_info *mvi, int i);
+       void (*fix_phy_info)(struct mvs_info *mvi, int i,
+                               struct sas_identify_frame *id);
+       void (*phy_work_around)(struct mvs_info *mvi, int i);
+       void (*phy_set_link_rate)(struct mvs_info *mvi, u32 phy_id,
+                               struct sas_phy_linkrates *rates);
+       u32 (*phy_max_link_rate)(void);
+       void (*phy_disable)(struct mvs_info *mvi, u32 phy_id);
+       void (*phy_enable)(struct mvs_info *mvi, u32 phy_id);
+       void (*phy_reset)(struct mvs_info *mvi, u32 phy_id, int hard);
+       void (*stp_reset)(struct mvs_info *mvi, u32 phy_id);
+       void (*clear_active_cmds)(struct mvs_info *mvi);
+       u32 (*spi_read_data)(struct mvs_info *mvi);
+       void (*spi_write_data)(struct mvs_info *mvi, u32 data);
+       int (*spi_buildcmd)(struct mvs_info *mvi,
+                                               u32      *dwCmd,
+                                               u8       cmd,
+                                               u8       read,
+                                               u8       length,
+                                               u32      addr
+                                               );
+       int (*spi_issuecmd)(struct mvs_info *mvi, u32 cmd);
+       int (*spi_waitdataready)(struct mvs_info *mvi, u32 timeout);
+#ifndef DISABLE_HOTPLUG_DMA_FIX
+       void (*dma_fix)(dma_addr_t buf_dma, int buf_len, int from, void *prd);
+#endif
+
+};
+
+struct mvs_chip_info {
+       u32             n_host;
+       u32             n_phy;
+       u32             fis_offs;
+       u32             fis_count;
+       u32             srs_sz;
+       u32             slot_width;
+       const struct mvs_dispatch *dispatch;
+};
+#define MVS_CHIP_SLOT_SZ       (1U << mvi->chip->slot_width)
+#define MVS_RX_FISL_SZ         \
+       (mvi->chip->fis_offs + (mvi->chip->fis_count * 0x100))
+#define MVS_CHIP_DISP          (mvi->chip->dispatch)
+
+struct mvs_err_info {
+       __le32                  flags;
+       __le32                  flags2;
+};
+
+struct mvs_cmd_hdr {
+       __le32                  flags;  /* PRD tbl len; SAS, SATA ctl */
+       __le32                  lens;   /* cmd, max resp frame len */
+       __le32                  tags;   /* targ port xfer tag; tag */
+       __le32                  data_len;       /* data xfer len */
+       __le64                  cmd_tbl;        /* command table address */
+       __le64                  open_frame;     /* open addr frame address */
+       __le64                  status_buf;     /* status buffer address */
+       __le64                  prd_tbl;                /* PRD tbl address */
+       __le32                  reserved[4];
+};
+
+struct mvs_port {
+       struct asd_sas_port     sas_port;
+       u8                      port_attached;
+       u8                      wide_port_phymap;
+       struct list_head        list;
+};
+
+struct mvs_phy {
+       struct mvs_info                 *mvi;
+       struct mvs_port         *port;
+       struct asd_sas_phy      sas_phy;
+       struct sas_identify     identify;
+       struct scsi_device      *sdev;
+       struct timer_list timer;
+       u64             dev_sas_addr;
+       u64             att_dev_sas_addr;
+       u32             att_dev_info;
+       u32             dev_info;
+       u32             phy_type;
+       u32             phy_status;
+       u32             irq_status;
+       u32             frame_rcvd_size;
+       u8              frame_rcvd[32];
+       u8              phy_attached;
+       u8              phy_mode;
+       u8              reserved[2];
+       u32             phy_event;
+       enum sas_linkrate       minimum_linkrate;
+       enum sas_linkrate       maximum_linkrate;
+};
+
+struct mvs_device {
+       struct list_head                dev_entry;
+       enum sas_dev_type dev_type;
+       struct mvs_info *mvi_info;
+       struct domain_device *sas_device;
+       u32 attached_phy;
+       u32 device_id;
+       u32 runing_req;
+       u8 taskfileset;
+       u8 dev_status;
+       u16 reserved;
+};
+
+struct mvs_slot_info {
+       struct list_head entry;
+       union {
+               struct sas_task *task;
+               void *tdata;
+       };
+       u32 n_elem;
+       u32 tx;
+       u32 slot_tag;
+
+       /* DMA buffer for storing cmd tbl, open addr frame, status buffer,
+        * and PRD table
+        */
+       void *buf;
+       dma_addr_t buf_dma;
+#if _MV_DUMP
+       u32 cmd_size;
+#endif
+       void *response;
+       struct mvs_port *port;
+       struct mvs_device       *device;
+       void *open_frame;
+};
+
+struct mvs_info {
+       unsigned long flags;
+
+       /* host-wide lock */
+       spinlock_t lock;
+
+       /* our device */
+       struct pci_dev *pdev;
+       struct device *dev;
+
+       /* enhanced mode registers */
+       void __iomem *regs;
+
+       /* peripheral or soc registers */
+       void __iomem *regs_ex;
+       u8 sas_addr[SAS_ADDR_SIZE];
+
+       /* SCSI/SAS glue */
+       struct sas_ha_struct *sas;
+       struct Scsi_Host *shost;
+
+       /* TX (delivery) DMA ring */
+       __le32 *tx;
+       dma_addr_t tx_dma;
+
+       /* cached next-producer idx */
+       u32 tx_prod;
+
+       /* RX (completion) DMA ring */
+       __le32  *rx;
+       dma_addr_t rx_dma;
+
+       /* RX consumer idx */
+       u32 rx_cons;
+
+       /* RX'd FIS area */
+       __le32 *rx_fis;
+       dma_addr_t rx_fis_dma;
+
+       /* DMA command header slots */
+       struct mvs_cmd_hdr *slot;
+       dma_addr_t slot_dma;
+
+       u32 chip_id;
+       const struct mvs_chip_info *chip;
+
+       int tags_num;
+       DECLARE_BITMAP(tags, MVS_SLOTS);
+       /* further per-slot information */
+       struct mvs_phy phy[MVS_MAX_PHYS];
+       struct mvs_port port[MVS_MAX_PHYS];
+       u32 irq;
+       u32 exp_req;
+       u32 id;
+       u64 sata_reg_set;
+       struct list_head *hba_list;
+       struct list_head soc_entry;
+       struct list_head wq_list;
+       unsigned long instance;
+       u16 flashid;
+       u32 flashsize;
+       u32 flashsectSize;
+
+       void *addon;
+       struct mvs_device       devices[MVS_MAX_DEVICES];
+#ifndef DISABLE_HOTPLUG_DMA_FIX
+       void *bulk_buffer;
+       dma_addr_t bulk_buffer_dma;
+#define TRASH_BUCKET_SIZE      0x20000
+#endif
+       struct mvs_slot_info slot_info[0];
+};
+
+struct mvs_prv_info{
+       u8 n_host;
+       u8 n_phy;
+       u16 reserve;
+       struct mvs_info *mvi[2];
+};
+
+struct mvs_wq {
+       struct delayed_work work_q;
+       struct mvs_info *mvi;
+       void *data;
+       int handler;
+       struct list_head entry;
+};
+
+struct mvs_task_exec_info {
+       struct sas_task *task;
+       struct mvs_cmd_hdr *hdr;
+       struct mvs_port *port;
+       u32 tag;
+       int n_elem;
+};
+
+
+/******************** function prototype *********************/
+void mvs_get_sas_addr(void *buf, u32 buflen);
+void mvs_tag_clear(struct mvs_info *mvi, u32 tag);
+void mvs_tag_free(struct mvs_info *mvi, u32 tag);
+void mvs_tag_set(struct mvs_info *mvi, unsigned int tag);
+int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out);
+void mvs_tag_init(struct mvs_info *mvi);
+void mvs_iounmap(void __iomem *regs);
+int mvs_ioremap(struct mvs_info *mvi, int bar, int bar_ex);
+void mvs_phys_reset(struct mvs_info *mvi, u32 phy_mask, int hard);
+int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
+                       void *funcdata);
+void __devinit mvs_set_sas_addr(struct mvs_info *mvi, int port_id,
+                               u32 off_lo, u32 off_hi, u64 sas_addr);
+int mvs_slave_alloc(struct scsi_device *scsi_dev);
+int mvs_slave_configure(struct scsi_device *sdev);
+void mvs_scan_start(struct Scsi_Host *shost);
+int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time);
+int mvs_queue_command(struct sas_task *task, const int num,
+                       gfp_t gfp_flags);
+int mvs_abort_task(struct sas_task *task);
+int mvs_abort_task_set(struct domain_device *dev, u8 *lun);
+int mvs_clear_aca(struct domain_device *dev, u8 *lun);
+int mvs_clear_task_set(struct domain_device *dev, u8 * lun);
+void mvs_port_formed(struct asd_sas_phy *sas_phy);
+void mvs_port_deformed(struct asd_sas_phy *sas_phy);
+int mvs_dev_found(struct domain_device *dev);
+void mvs_dev_gone(struct domain_device *dev);
+int mvs_lu_reset(struct domain_device *dev, u8 *lun);
+int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags);
+int mvs_I_T_nexus_reset(struct domain_device *dev);
+int mvs_query_task(struct sas_task *task);
+void mvs_release_task(struct mvs_info *mvi, int phy_no,
+                       struct domain_device *dev);
+void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events);
+void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st);
+int mvs_int_rx(struct mvs_info *mvi, bool self_clear);
+void mvs_hexdump(u32 size, u8 *data, u32 baseaddr);
+#endif
+
index 0e207aa67d16e3e8e4c8c6e4c1b2f0d6c88fe8c8..5fd73d77c3af86b17344c1e544dd4ed22bdd6105 100644 (file)
 # it under the terms of the GNU General Public License version 2
 #
 
-ifneq ($(OSD_INC),)
-# we are built out-of-tree Kconfigure everything as on
-
-CONFIG_SCSI_OSD_INITIATOR=m
-ccflags-y += -DCONFIG_SCSI_OSD_INITIATOR -DCONFIG_SCSI_OSD_INITIATOR_MODULE
-
-CONFIG_SCSI_OSD_ULD=m
-ccflags-y += -DCONFIG_SCSI_OSD_ULD -DCONFIG_SCSI_OSD_ULD_MODULE
-
-# CONFIG_SCSI_OSD_DPRINT_SENSE =
-#      0 - no print of errors
-#      1 - print errors
-#      2 - errors + warrnings
-ccflags-y += -DCONFIG_SCSI_OSD_DPRINT_SENSE=1
-
-# Uncomment to turn debug on
-# ccflags-y += -DCONFIG_SCSI_OSD_DEBUG
-
-# if we are built out-of-tree and the hosting kernel has OSD headers
-# then "ccflags-y +=" will not pick the out-off-tree headers. Only by doing
-# this it will work. This might break in future kernels
-LINUXINCLUDE := -I$(OSD_INC) $(LINUXINCLUDE)
-
-endif
-
 # libosd.ko - osd-initiator library
 libosd-y := osd_initiator.o
 obj-$(CONFIG_SCSI_OSD_INITIATOR) += libosd.o
diff --git a/drivers/scsi/osd/Makefile b/drivers/scsi/osd/Makefile
deleted file mode 100755 (executable)
index d905344..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#
-# Makefile for the OSD modules (out of tree)
-#
-# Copyright (C) 2008 Panasas Inc.  All rights reserved.
-#
-# Authors:
-#   Boaz Harrosh <bharrosh@panasas.com>
-#   Benny Halevy <bhalevy@panasas.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
-#
-# This Makefile is used to call the kernel Makefile in case of an out-of-tree
-# build.
-# $KSRC should point to a Kernel source tree otherwise host's default is
-# used. (eg. /lib/modules/`uname -r`/build)
-
-# include path for out-of-tree Headers
-OSD_INC ?= `pwd`/../../../include
-
-# allow users to override these
-# e.g. to compile for a kernel that you aren't currently running
-KSRC ?= /lib/modules/$(shell uname -r)/build
-KBUILD_OUTPUT ?=
-ARCH ?=
-V ?= 0
-
-# this is the basic Kbuild out-of-tree invocation, with the M= option
-KBUILD_BASE = +$(MAKE) -C $(KSRC) M=`pwd` KBUILD_OUTPUT=$(KBUILD_OUTPUT) ARCH=$(ARCH) V=$(V)
-
-all: libosd
-
-libosd: ;
-       $(KBUILD_BASE) OSD_INC=$(OSD_INC) modules
-
-clean:
-       $(KBUILD_BASE) clean
index 5776b2ab6b12a5fa54fe974b11e31619d8ee18e0..7a117c18114cd757de416045da2d453327742131 100644 (file)
@@ -118,39 +118,39 @@ static int _osd_print_system_info(struct osd_dev *od, void *caps)
                _osd_ver_desc(or));
 
        pFirst = get_attrs[a++].val_ptr;
-       OSD_INFO("OSD_ATTR_RI_VENDOR_IDENTIFICATION [%s]\n",
+       OSD_INFO("VENDOR_IDENTIFICATION  [%s]\n",
                (char *)pFirst);
 
        pFirst = get_attrs[a++].val_ptr;
-       OSD_INFO("OSD_ATTR_RI_PRODUCT_IDENTIFICATION [%s]\n",
+       OSD_INFO("PRODUCT_IDENTIFICATION [%s]\n",
                (char *)pFirst);
 
        pFirst = get_attrs[a++].val_ptr;
-       OSD_INFO("OSD_ATTR_RI_PRODUCT_MODEL [%s]\n",
+       OSD_INFO("PRODUCT_MODEL          [%s]\n",
                (char *)pFirst);
 
        pFirst = get_attrs[a++].val_ptr;
-       OSD_INFO("OSD_ATTR_RI_PRODUCT_REVISION_LEVEL [%u]\n",
+       OSD_INFO("PRODUCT_REVISION_LEVEL [%u]\n",
                pFirst ? get_unaligned_be32(pFirst) : ~0U);
 
        pFirst = get_attrs[a++].val_ptr;
-       OSD_INFO("OSD_ATTR_RI_PRODUCT_SERIAL_NUMBER [%s]\n",
+       OSD_INFO("PRODUCT_SERIAL_NUMBER  [%s]\n",
                (char *)pFirst);
 
        pFirst = get_attrs[a].val_ptr;
-       OSD_INFO("OSD_ATTR_RI_OSD_NAME [%s]\n", (char *)pFirst);
+       OSD_INFO("OSD_NAME               [%s]\n", (char *)pFirst);
        a++;
 
        pFirst = get_attrs[a++].val_ptr;
-       OSD_INFO("OSD_ATTR_RI_TOTAL_CAPACITY [0x%llx]\n",
+       OSD_INFO("TOTAL_CAPACITY         [0x%llx]\n",
                pFirst ? _LLU(get_unaligned_be64(pFirst)) : ~0ULL);
 
        pFirst = get_attrs[a++].val_ptr;
-       OSD_INFO("OSD_ATTR_RI_USED_CAPACITY [0x%llx]\n",
+       OSD_INFO("USED_CAPACITY          [0x%llx]\n",
                pFirst ? _LLU(get_unaligned_be64(pFirst)) : ~0ULL);
 
        pFirst = get_attrs[a++].val_ptr;
-       OSD_INFO("OSD_ATTR_RI_NUMBER_OF_PARTITIONS [%llu]\n",
+       OSD_INFO("NUMBER_OF_PARTITIONS   [%llu]\n",
                pFirst ? _LLU(get_unaligned_be64(pFirst)) : ~0ULL);
 
        if (a >= nelem)
@@ -158,7 +158,7 @@ static int _osd_print_system_info(struct osd_dev *od, void *caps)
 
        /* FIXME: Where are the time utilities */
        pFirst = get_attrs[a++].val_ptr;
-       OSD_INFO("OSD_ATTR_RI_CLOCK [0x%02x%02x%02x%02x%02x%02x]\n",
+       OSD_INFO("CLOCK                  [0x%02x%02x%02x%02x%02x%02x]\n",
                ((char *)pFirst)[0], ((char *)pFirst)[1],
                ((char *)pFirst)[2], ((char *)pFirst)[3],
                ((char *)pFirst)[4], ((char *)pFirst)[5]);
@@ -169,7 +169,8 @@ static int _osd_print_system_info(struct osd_dev *od, void *caps)
 
                hex_dump_to_buffer(get_attrs[a].val_ptr, len, 32, 1,
                                   sid_dump, sizeof(sid_dump), true);
-               OSD_INFO("OSD_ATTR_RI_OSD_SYSTEM_ID(%d) [%s]\n", len, sid_dump);
+               OSD_INFO("OSD_SYSTEM_ID(%d)\n"
+                        "        [%s]\n", len, sid_dump);
                a++;
        }
 out:
@@ -669,7 +670,7 @@ static int _osd_req_list_objects(struct osd_request *or,
        __be16 action, const struct osd_obj_id *obj, osd_id initial_id,
        struct osd_obj_id_list *list, unsigned nelem)
 {
-       struct request_queue *q = or->osd_dev->scsi_device->request_queue;
+       struct request_queue *q = osd_request_queue(or->osd_dev);
        u64 len = nelem * sizeof(osd_id) + sizeof(*list);
        struct bio *bio;
 
@@ -778,16 +779,32 @@ EXPORT_SYMBOL(osd_req_remove_object);
 */
 
 void osd_req_write(struct osd_request *or,
-       const struct osd_obj_id *obj, struct bio *bio, u64 offset)
+       const struct osd_obj_id *obj, u64 offset,
+       struct bio *bio, u64 len)
 {
-       _osd_req_encode_common(or, OSD_ACT_WRITE, obj, offset, bio->bi_size);
+       _osd_req_encode_common(or, OSD_ACT_WRITE, obj, offset, len);
        WARN_ON(or->out.bio || or->out.total_bytes);
-       bio->bi_rw |= (1 << BIO_RW);
+       WARN_ON(0 ==  bio_rw_flagged(bio, BIO_RW));
        or->out.bio = bio;
-       or->out.total_bytes = bio->bi_size;
+       or->out.total_bytes = len;
 }
 EXPORT_SYMBOL(osd_req_write);
 
+int osd_req_write_kern(struct osd_request *or,
+       const struct osd_obj_id *obj, u64 offset, void* buff, u64 len)
+{
+       struct request_queue *req_q = osd_request_queue(or->osd_dev);
+       struct bio *bio = bio_map_kern(req_q, buff, len, GFP_KERNEL);
+
+       if (IS_ERR(bio))
+               return PTR_ERR(bio);
+
+       bio->bi_rw |= (1 << BIO_RW); /* FIXME: bio_set_dir() */
+       osd_req_write(or, obj, offset, bio, len);
+       return 0;
+}
+EXPORT_SYMBOL(osd_req_write_kern);
+
 /*TODO: void osd_req_append(struct osd_request *,
        const struct osd_obj_id *, struct bio *data_out); */
 /*TODO: void osd_req_create_write(struct osd_request *,
@@ -813,16 +830,31 @@ void osd_req_flush_object(struct osd_request *or,
 EXPORT_SYMBOL(osd_req_flush_object);
 
 void osd_req_read(struct osd_request *or,
-       const struct osd_obj_id *obj, struct bio *bio, u64 offset)
+       const struct osd_obj_id *obj, u64 offset,
+       struct bio *bio, u64 len)
 {
-       _osd_req_encode_common(or, OSD_ACT_READ, obj, offset, bio->bi_size);
+       _osd_req_encode_common(or, OSD_ACT_READ, obj, offset, len);
        WARN_ON(or->in.bio || or->in.total_bytes);
-       bio->bi_rw &= ~(1 << BIO_RW);
+       WARN_ON(1 == bio_rw_flagged(bio, BIO_RW));
        or->in.bio = bio;
-       or->in.total_bytes = bio->bi_size;
+       or->in.total_bytes = len;
 }
 EXPORT_SYMBOL(osd_req_read);
 
+int osd_req_read_kern(struct osd_request *or,
+       const struct osd_obj_id *obj, u64 offset, void* buff, u64 len)
+{
+       struct request_queue *req_q = osd_request_queue(or->osd_dev);
+       struct bio *bio = bio_map_kern(req_q, buff, len, GFP_KERNEL);
+
+       if (IS_ERR(bio))
+               return PTR_ERR(bio);
+
+       osd_req_read(or, obj, offset, bio, len);
+       return 0;
+}
+EXPORT_SYMBOL(osd_req_read_kern);
+
 void osd_req_get_attributes(struct osd_request *or,
        const struct osd_obj_id *obj)
 {
@@ -1213,7 +1245,7 @@ static inline void osd_sec_parms_set_in_offset(bool is_v1,
 }
 
 static int _osd_req_finalize_data_integrity(struct osd_request *or,
-       bool has_in, bool has_out, const u8 *cap_key)
+       bool has_in, bool has_out, u64 out_data_bytes, const u8 *cap_key)
 {
        struct osd_security_parameters *sec_parms = _osd_req_sec_params(or);
        int ret;
@@ -1228,8 +1260,7 @@ static int _osd_req_finalize_data_integrity(struct osd_request *or,
                };
                unsigned pad;
 
-               or->out_data_integ.data_bytes = cpu_to_be64(
-                       or->out.bio ? or->out.bio->bi_size : 0);
+               or->out_data_integ.data_bytes = cpu_to_be64(out_data_bytes);
                or->out_data_integ.set_attributes_bytes = cpu_to_be64(
                        or->set_attr.total_bytes);
                or->out_data_integ.get_attributes_bytes = cpu_to_be64(
@@ -1306,6 +1337,8 @@ static int _init_blk_request(struct osd_request *or,
 
        or->request = req;
        req->cmd_type = REQ_TYPE_BLOCK_PC;
+       req->cmd_flags |= REQ_QUIET;
+
        req->timeout = or->timeout;
        req->retries = or->retries;
        req->sense = or->sense;
@@ -1339,6 +1372,7 @@ int osd_finalize_request(struct osd_request *or,
 {
        struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
        bool has_in, has_out;
+       u64 out_data_bytes = or->out.total_bytes;
        int ret;
 
        if (options & OSD_REQ_FUA)
@@ -1388,7 +1422,8 @@ int osd_finalize_request(struct osd_request *or,
                }
        }
 
-       ret = _osd_req_finalize_data_integrity(or, has_in, has_out, cap_key);
+       ret = _osd_req_finalize_data_integrity(or, has_in, has_out,
+                                              out_data_bytes, cap_key);
        if (ret)
                return ret;
 
index 22b59e13ba83fd7d91b71c6b78f7b945291ab5da..0bdef339090288d409e23557bf3c0956f400f241 100644 (file)
@@ -49,6 +49,7 @@
 #include <linux/device.h>
 #include <linux/idr.h>
 #include <linux/major.h>
+#include <linux/file.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_driver.h>
@@ -175,10 +176,9 @@ static const struct file_operations osd_fops = {
 
 struct osd_dev *osduld_path_lookup(const char *name)
 {
-       struct path path;
-       struct inode *inode;
-       struct cdev *cdev;
-       struct osd_uld_device *uninitialized_var(oud);
+       struct osd_uld_device *oud;
+       struct osd_dev *od;
+       struct file *file;
        int error;
 
        if (!name || !*name) {
@@ -186,52 +186,46 @@ struct osd_dev *osduld_path_lookup(const char *name)
                return ERR_PTR(-EINVAL);
        }
 
-       error = kern_path(name, LOOKUP_FOLLOW, &path);
-       if (error) {
-               OSD_ERR("path_lookup of %s failed=>%d\n", name, error);
-               return ERR_PTR(error);
-       }
+       od = kzalloc(sizeof(*od), GFP_KERNEL);
+       if (!od)
+               return ERR_PTR(-ENOMEM);
 
-       inode = path.dentry->d_inode;
-       error = -EINVAL; /* Not the right device e.g osd_uld_device */
-       if (!S_ISCHR(inode->i_mode)) {
-               OSD_DEBUG("!S_ISCHR()\n");
-               goto out;
+       file = filp_open(name, O_RDWR, 0);
+       if (IS_ERR(file)) {
+               error = PTR_ERR(file);
+               goto free_od;
        }
 
-       cdev = inode->i_cdev;
-       if (!cdev) {
-               OSD_ERR("Before mounting an OSD Based filesystem\n");
-               OSD_ERR("  user-mode must open+close the %s device\n", name);
-               OSD_ERR("  Example: bash: echo < %s\n", name);
-               goto out;
+       if (file->f_op != &osd_fops){
+               error = -EINVAL;
+               goto close_file;
        }
 
-       /* The Magic wand. Is it our char-dev */
-       /* TODO: Support sg devices */
-       if (cdev->owner != THIS_MODULE) {
-               OSD_ERR("Error mounting %s - is not an OSD device\n", name);
-               goto out;
-       }
+       oud = file->private_data;
 
-       oud = container_of(cdev, struct osd_uld_device, cdev);
+       *od = oud->od;
+       od->file = file;
 
-       __uld_get(oud);
-       error = 0;
+       return od;
 
-out:
-       path_put(&path);
-       return error ? ERR_PTR(error) : &oud->od;
+close_file:
+       fput(file);
+free_od:
+       kfree(od);
+       return ERR_PTR(error);
 }
 EXPORT_SYMBOL(osduld_path_lookup);
 
 void osduld_put_device(struct osd_dev *od)
 {
-       if (od) {
-               struct osd_uld_device *oud = container_of(od,
-                                               struct osd_uld_device, od);
 
-               __uld_put(oud);
+       if (od && !IS_ERR(od)) {
+               struct osd_uld_device *oud = od->file->private_data;
+
+               BUG_ON(od->scsi_device != oud->od.scsi_device);
+
+               fput(od->file);
+               kfree(od);
        }
 }
 EXPORT_SYMBOL(osduld_put_device);
index 5defe5ea5eda64937f605ebd6dceae3d6958c76f..8371d917a9a2408242a2439c9c69f298cc012964 100644 (file)
 * General Public License for more details.
 *
 ******************************************************************************/
-#define QLA1280_VERSION      "3.26"
+#define QLA1280_VERSION      "3.27"
 /*****************************************************************************
     Revision History:
+    Rev  3.27, February 10, 2009, Michael Reed
+       - General code cleanup.
+       - Improve error recovery.
     Rev  3.26, January 16, 2006 Jes Sorensen
        - Ditch all < 2.6 support
     Rev  3.25.1, February 10, 2005 Christoph Hellwig
@@ -435,7 +438,6 @@ static int qla1280_mailbox_command(struct scsi_qla_host *,
                                   uint8_t, uint16_t *);
 static int qla1280_bus_reset(struct scsi_qla_host *, int);
 static int qla1280_device_reset(struct scsi_qla_host *, int, int);
-static int qla1280_abort_device(struct scsi_qla_host *, int, int, int);
 static int qla1280_abort_command(struct scsi_qla_host *, struct srb *, int);
 static int qla1280_abort_isp(struct scsi_qla_host *);
 #ifdef QLA_64BIT_PTR
@@ -698,7 +700,7 @@ qla1280_info(struct Scsi_Host *host)
 }
 
 /**************************************************************************
- *   qla1200_queuecommand
+ *   qla1280_queuecommand
  *     Queue a command to the controller.
  *
  * Note:
@@ -713,12 +715,14 @@ qla1280_queuecommand(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
 {
        struct Scsi_Host *host = cmd->device->host;
        struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata;
-       struct srb *sp = (struct srb *)&cmd->SCp;
+       struct srb *sp = (struct srb *)CMD_SP(cmd);
        int status;
 
        cmd->scsi_done = fn;
        sp->cmd = cmd;
        sp->flags = 0;
+       sp->wait = NULL;
+       CMD_HANDLE(cmd) = (unsigned char *)NULL;
 
        qla1280_print_scsi_cmd(5, cmd);
 
@@ -738,21 +742,11 @@ qla1280_queuecommand(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
 
 enum action {
        ABORT_COMMAND,
-       ABORT_DEVICE,
        DEVICE_RESET,
        BUS_RESET,
        ADAPTER_RESET,
-       FAIL
 };
 
-/* timer action for error action processor */
-static void qla1280_error_wait_timeout(unsigned long __data)
-{
-       struct scsi_cmnd *cmd = (struct scsi_cmnd *)__data;
-       struct srb *sp = (struct srb *)CMD_SP(cmd);
-
-       complete(sp->wait);
-}
 
 static void qla1280_mailbox_timeout(unsigned long __data)
 {
@@ -767,8 +761,67 @@ static void qla1280_mailbox_timeout(unsigned long __data)
        complete(ha->mailbox_wait);
 }
 
+static int
+_qla1280_wait_for_single_command(struct scsi_qla_host *ha, struct srb *sp,
+                                struct completion *wait)
+{
+       int     status = FAILED;
+       struct scsi_cmnd *cmd = sp->cmd;
+
+       spin_unlock_irq(ha->host->host_lock);
+       wait_for_completion_timeout(wait, 4*HZ);
+       spin_lock_irq(ha->host->host_lock);
+       sp->wait = NULL;
+       if(CMD_HANDLE(cmd) == COMPLETED_HANDLE) {
+               status = SUCCESS;
+               (*cmd->scsi_done)(cmd);
+       }
+       return status;
+}
+
+static int
+qla1280_wait_for_single_command(struct scsi_qla_host *ha, struct srb *sp)
+{
+       DECLARE_COMPLETION_ONSTACK(wait);
+
+       sp->wait = &wait;
+       return _qla1280_wait_for_single_command(ha, sp, &wait);
+}
+
+static int
+qla1280_wait_for_pending_commands(struct scsi_qla_host *ha, int bus, int target)
+{
+       int             cnt;
+       int             status;
+       struct srb      *sp;
+       struct scsi_cmnd *cmd;
+
+       status = SUCCESS;
+
+       /*
+        * Wait for all commands with the designated bus/target
+        * to be completed by the firmware
+        */
+       for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
+               sp = ha->outstanding_cmds[cnt];
+               if (sp) {
+                       cmd = sp->cmd;
+
+                       if (bus >= 0 && SCSI_BUS_32(cmd) != bus)
+                               continue;
+                       if (target >= 0 && SCSI_TCN_32(cmd) != target)
+                               continue;
+
+                       status = qla1280_wait_for_single_command(ha, sp);
+                       if (status == FAILED)
+                               break;
+               }
+       }
+       return status;
+}
+
 /**************************************************************************
- * qla1200_error_action
+ * qla1280_error_action
  *    The function will attempt to perform a specified error action and
  *    wait for the results (or time out).
  *
@@ -780,11 +833,6 @@ static void qla1280_mailbox_timeout(unsigned long __data)
  * Returns:
  *      SUCCESS or FAILED
  *
- * Note:
- *      Resetting the bus always succeeds - is has to, otherwise the
- *      kernel will panic! Try a surgical technique - sending a BUS
- *      DEVICE RESET message - on the offending target before pulling
- *      the SCSI bus reset line.
  **************************************************************************/
 static int
 qla1280_error_action(struct scsi_cmnd *cmd, enum action action)
@@ -792,13 +840,19 @@ qla1280_error_action(struct scsi_cmnd *cmd, enum action action)
        struct scsi_qla_host *ha;
        int bus, target, lun;
        struct srb *sp;
-       uint16_t data;
-       unsigned char *handle;
-       int result, i;
+       int i, found;
+       int result=FAILED;
+       int wait_for_bus=-1;
+       int wait_for_target = -1;
        DECLARE_COMPLETION_ONSTACK(wait);
-       struct timer_list timer;
+
+       ENTER("qla1280_error_action");
 
        ha = (struct scsi_qla_host *)(CMD_HOST(cmd)->hostdata);
+       sp = (struct srb *)CMD_SP(cmd);
+       bus = SCSI_BUS_32(cmd);
+       target = SCSI_TCN_32(cmd);
+       lun = SCSI_LUN_32(cmd);
 
        dprintk(4, "error_action %i, istatus 0x%04x\n", action,
                RD_REG_WORD(&ha->iobase->istatus));
@@ -807,99 +861,47 @@ qla1280_error_action(struct scsi_cmnd *cmd, enum action action)
                RD_REG_WORD(&ha->iobase->host_cmd),
                RD_REG_WORD(&ha->iobase->ictrl), jiffies);
 
-       ENTER("qla1280_error_action");
        if (qla1280_verbose)
                printk(KERN_INFO "scsi(%li): Resetting Cmnd=0x%p, "
                       "Handle=0x%p, action=0x%x\n",
                       ha->host_no, cmd, CMD_HANDLE(cmd), action);
 
-       if (cmd == NULL) {
-               printk(KERN_WARNING "(scsi?:?:?:?) Reset called with NULL "
-                      "si_Cmnd pointer, failing.\n");
-               LEAVE("qla1280_error_action");
-               return FAILED;
-       }
-
-       ha = (struct scsi_qla_host *)cmd->device->host->hostdata;
-       sp = (struct srb *)CMD_SP(cmd);
-       handle = CMD_HANDLE(cmd);
-
-       /* Check for pending interrupts. */
-       data = qla1280_debounce_register(&ha->iobase->istatus);
-       /*
-        * The io_request_lock is held when the reset handler is called, hence
-        * the interrupt handler cannot be running in parallel as it also
-        * grabs the lock. /Jes
-        */
-       if (data & RISC_INT)
-               qla1280_isr(ha, &ha->done_q);
-
        /*
-        * Determine the suggested action that the mid-level driver wants
-        * us to perform.
+        * Check to see if we have the command in the outstanding_cmds[]
+        * array.  If not then it must have completed before this error
+        * action was initiated.  If the error_action isn't ABORT_COMMAND
+        * then the driver must proceed with the requested action.
         */
-       if (handle == (unsigned char *)INVALID_HANDLE || handle == NULL) {
-               if(action == ABORT_COMMAND) {
-                       /* we never got this command */
-                       printk(KERN_INFO "qla1280: Aborting a NULL handle\n");
-                       return SUCCESS; /* no action - we don't have command */
+       found = -1;
+       for (i = 0; i < MAX_OUTSTANDING_COMMANDS; i++) {
+               if (sp == ha->outstanding_cmds[i]) {
+                       found = i;
+                       sp->wait = &wait; /* we'll wait for it to complete */
+                       break;
                }
-       } else {
-               sp->wait = &wait;
        }
 
-       bus = SCSI_BUS_32(cmd);
-       target = SCSI_TCN_32(cmd);
-       lun = SCSI_LUN_32(cmd);
+       if (found < 0) {        /* driver doesn't have command */
+               result = SUCCESS;
+               if (qla1280_verbose) {
+                       printk(KERN_INFO
+                              "scsi(%ld:%d:%d:%d): specified command has "
+                              "already completed.\n", ha->host_no, bus,
+                               target, lun);
+               }
+       }
 
-       /* Overloading result.  Here it means the success or fail of the
-        * *issue* of the action.  When we return from the routine, it must
-        * mean the actual success or fail of the action */
-       result = FAILED;
        switch (action) {
-       case FAIL:
-               break;
 
        case ABORT_COMMAND:
-               if ((sp->flags & SRB_ABORT_PENDING)) {
-                       printk(KERN_WARNING
-                              "scsi(): Command has a pending abort "
-                              "message - ABORT_PENDING.\n");
-                       /* This should technically be impossible since we
-                        * now wait for abort completion */
-                       break;
-               }
-
-               for (i = 0; i < MAX_OUTSTANDING_COMMANDS; i++) {
-                       if (sp == ha->outstanding_cmds[i]) {
-                               dprintk(1, "qla1280: RISC aborting command\n");
-                               if (qla1280_abort_command(ha, sp, i) == 0)
-                                       result = SUCCESS;
-                               else {
-                                       /*
-                                        * Since we don't know what might
-                                        * have happend to the command, it
-                                        * is unsafe to remove it from the
-                                        * device's queue at this point.
-                                        * Wait and let the escalation
-                                        * process take care of it.
-                                        */
-                                       printk(KERN_WARNING
-                                              "scsi(%li:%i:%i:%i): Unable"
-                                              " to abort command!\n",
-                                              ha->host_no, bus, target, lun);
-                               }
-                       }
-               }
-               break;
-
-       case ABORT_DEVICE:
-               if (qla1280_verbose)
-                       printk(KERN_INFO
-                              "scsi(%ld:%d:%d:%d): Queueing abort device "
-                              "command.\n", ha->host_no, bus, target, lun);
-               if (qla1280_abort_device(ha, bus, target, lun) == 0)
-                       result = SUCCESS;
+               dprintk(1, "qla1280: RISC aborting command\n");
+               /*
+                * The abort might fail due to race when the host_lock
+                * is released to issue the abort.  As such, we
+                * don't bother to check the return status.
+                */
+               if (found >= 0)
+                       qla1280_abort_command(ha, sp, found);
                break;
 
        case DEVICE_RESET:
@@ -907,16 +909,21 @@ qla1280_error_action(struct scsi_cmnd *cmd, enum action action)
                        printk(KERN_INFO
                               "scsi(%ld:%d:%d:%d): Queueing device reset "
                               "command.\n", ha->host_no, bus, target, lun);
-               if (qla1280_device_reset(ha, bus, target) == 0)
-                       result = SUCCESS;
+               if (qla1280_device_reset(ha, bus, target) == 0) {
+                       /* issued device reset, set wait conditions */
+                       wait_for_bus = bus;
+                       wait_for_target = target;
+               }
                break;
 
        case BUS_RESET:
                if (qla1280_verbose)
                        printk(KERN_INFO "qla1280(%ld:%d): Issued bus "
                               "reset.\n", ha->host_no, bus);
-               if (qla1280_bus_reset(ha, bus) == 0)
-                       result = SUCCESS;
+               if (qla1280_bus_reset(ha, bus) == 0) {
+                       /* issued bus reset, set wait conditions */
+                       wait_for_bus = bus;
+               }
                break;
 
        case ADAPTER_RESET:
@@ -929,55 +936,48 @@ qla1280_error_action(struct scsi_cmnd *cmd, enum action action)
                               "continue automatically\n", ha->host_no);
                }
                ha->flags.reset_active = 1;
-               /*
-                * We restarted all of the commands automatically, so the
-                * mid-level code can expect completions momentitarily.
-                */
-               if (qla1280_abort_isp(ha) == 0)
-                       result = SUCCESS;
+
+               if (qla1280_abort_isp(ha) != 0) {       /* it's dead */
+                       result = FAILED;
+               }
 
                ha->flags.reset_active = 0;
        }
 
-       if (!list_empty(&ha->done_q))
-               qla1280_done(ha);
-
-       /* If we didn't manage to issue the action, or we have no
-        * command to wait for, exit here */
-       if (result == FAILED || handle == NULL ||
-           handle == (unsigned char *)INVALID_HANDLE) {
-               /*
-                * Clear completion queue to avoid qla1280_done() trying
-                * to complete the command at a later stage after we
-                * have exited the current context
-                */
-               sp->wait = NULL;
-               goto leave;
-       }
+       /*
+        * At this point, the host_lock has been released and retaken
+        * by the issuance of the mailbox command.
+        * Wait for the command passed in by the mid-layer if it
+        * was found by the driver.  It might have been returned
+        * between eh recovery steps, hence the check of the "found"
+        * variable.
+        */
 
-       /* set up a timer just in case we're really jammed */
-       init_timer(&timer);
-       timer.expires = jiffies + 4*HZ;
-       timer.data = (unsigned long)cmd;
-       timer.function = qla1280_error_wait_timeout;
-       add_timer(&timer);
+       if (found >= 0)
+               result = _qla1280_wait_for_single_command(ha, sp, &wait);
 
-       /* wait for the action to complete (or the timer to expire) */
-       spin_unlock_irq(ha->host->host_lock);
-       wait_for_completion(&wait);
-       del_timer_sync(&timer);
-       spin_lock_irq(ha->host->host_lock);
-       sp->wait = NULL;
+       if (action == ABORT_COMMAND && result != SUCCESS) {
+               printk(KERN_WARNING
+                      "scsi(%li:%i:%i:%i): "
+                      "Unable to abort command!\n",
+                      ha->host_no, bus, target, lun);
+       }
 
-       /* the only action we might get a fail for is abort */
-       if (action == ABORT_COMMAND) {
-               if(sp->flags & SRB_ABORTED)
-                       result = SUCCESS;
-               else
-                       result = FAILED;
+       /*
+        * If the command passed in by the mid-layer has been
+        * returned by the board, then wait for any additional
+        * commands which are supposed to complete based upon
+        * the error action.
+        *
+        * All commands are unconditionally returned during a
+        * call to qla1280_abort_isp(), ADAPTER_RESET.  No need
+        * to wait for them.
+        */
+       if (result == SUCCESS && wait_for_bus >= 0) {
+               result = qla1280_wait_for_pending_commands(ha,
+                                       wait_for_bus, wait_for_target);
        }
 
- leave:
        dprintk(1, "RESET returning %d\n", result);
 
        LEAVE("qla1280_error_action");
@@ -1280,13 +1280,12 @@ qla1280_done(struct scsi_qla_host *ha)
                switch ((CMD_RESULT(cmd) >> 16)) {
                case DID_RESET:
                        /* Issue marker command. */
-                       qla1280_marker(ha, bus, target, 0, MK_SYNC_ID);
+                       if (!ha->flags.abort_isp_active)
+                               qla1280_marker(ha, bus, target, 0, MK_SYNC_ID);
                        break;
                case DID_ABORT:
                        sp->flags &= ~SRB_ABORT_PENDING;
                        sp->flags |= SRB_ABORTED;
-                       if (sp->flags & SRB_TIMEOUT)
-                               CMD_RESULT(sp->cmd) = DID_TIME_OUT << 16;
                        break;
                default:
                        break;
@@ -1296,12 +1295,11 @@ qla1280_done(struct scsi_qla_host *ha)
                scsi_dma_unmap(cmd);
 
                /* Call the mid-level driver interrupt handler */
-               CMD_HANDLE(sp->cmd) = (unsigned char *)INVALID_HANDLE;
                ha->actthreads--;
 
-               (*(cmd)->scsi_done)(cmd);
-
-               if(sp->wait != NULL)
+               if (sp->wait == NULL)
+                       (*(cmd)->scsi_done)(cmd);
+               else
                        complete(sp->wait);
        }
        LEAVE("qla1280_done");
@@ -2417,9 +2415,6 @@ static int
 qla1280_mailbox_command(struct scsi_qla_host *ha, uint8_t mr, uint16_t *mb)
 {
        struct device_reg __iomem *reg = ha->iobase;
-#if 0
-       LIST_HEAD(done_q);
-#endif
        int status = 0;
        int cnt;
        uint16_t *optr, *iptr;
@@ -2493,19 +2488,9 @@ qla1280_mailbox_command(struct scsi_qla_host *ha, uint8_t mr, uint16_t *mb)
        mr = MAILBOX_REGISTER_COUNT;
        memcpy(optr, iptr, MAILBOX_REGISTER_COUNT * sizeof(uint16_t));
 
-#if 0
-       /* Go check for any response interrupts pending. */
-       qla1280_isr(ha, &done_q);
-#endif
-
        if (ha->flags.reset_marker)
                qla1280_rst_aen(ha);
 
-#if 0
-       if (!list_empty(&done_q))
-               qla1280_done(ha, &done_q);
-#endif
-
        if (status)
                dprintk(2, "qla1280_mailbox_command: **** FAILED, mailbox0 = "
                        "0x%x ****\n", mb[0]);
@@ -2640,41 +2625,6 @@ qla1280_device_reset(struct scsi_qla_host *ha, int bus, int target)
        return status;
 }
 
-/*
- * qla1280_abort_device
- *      Issue an abort message to the device
- *
- * Input:
- *      ha     = adapter block pointer.
- *      bus    = SCSI BUS.
- *      target = SCSI ID.
- *      lun    = SCSI LUN.
- *
- * Returns:
- *      0 = success
- */
-static int
-qla1280_abort_device(struct scsi_qla_host *ha, int bus, int target, int lun)
-{
-       uint16_t mb[MAILBOX_REGISTER_COUNT];
-       int status;
-
-       ENTER("qla1280_abort_device");
-
-       mb[0] = MBC_ABORT_DEVICE;
-       mb[1] = (bus ? target | BIT_7 : target) << 8 | lun;
-       status = qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]);
-
-       /* Issue marker command. */
-       qla1280_marker(ha, bus, target, lun, MK_SYNC_ID_LUN);
-
-       if (status)
-               dprintk(2, "qla1280_abort_device: **** FAILED ****\n");
-
-       LEAVE("qla1280_abort_device");
-       return status;
-}
-
 /*
  * qla1280_abort_command
  *      Abort command aborts a specified IOCB.
@@ -2833,7 +2783,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
 
        /* If room for request in request ring. */
        if ((req_cnt + 2) >= ha->req_q_cnt) {
-               status = 1;
+               status = SCSI_MLQUEUE_HOST_BUSY;
                dprintk(2, "qla1280_start_scsi: in-ptr=0x%x  req_q_cnt="
                        "0x%xreq_cnt=0x%x", ha->req_ring_index, ha->req_q_cnt,
                        req_cnt);
@@ -2845,7 +2795,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
                     ha->outstanding_cmds[cnt] != NULL; cnt++);
 
        if (cnt >= MAX_OUTSTANDING_COMMANDS) {
-               status = 1;
+               status = SCSI_MLQUEUE_HOST_BUSY;
                dprintk(2, "qla1280_start_scsi: NO ROOM IN "
                        "OUTSTANDING ARRAY, req_q_cnt=0x%x", ha->req_q_cnt);
                goto out;
@@ -3108,7 +3058,7 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
                ha->req_q_cnt, seg_cnt);
        /* If room for request in request ring. */
        if ((req_cnt + 2) >= ha->req_q_cnt) {
-               status = 1;
+               status = SCSI_MLQUEUE_HOST_BUSY;
                dprintk(2, "qla1280_32bit_start_scsi: in-ptr=0x%x, "
                        "req_q_cnt=0x%x, req_cnt=0x%x", ha->req_ring_index,
                        ha->req_q_cnt, req_cnt);
@@ -3120,7 +3070,7 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
                     (ha->outstanding_cmds[cnt] != 0); cnt++) ;
 
        if (cnt >= MAX_OUTSTANDING_COMMANDS) {
-               status = 1;
+               status = SCSI_MLQUEUE_HOST_BUSY;
                dprintk(2, "qla1280_32bit_start_scsi: NO ROOM IN OUTSTANDING "
                        "ARRAY, req_q_cnt=0x%x\n", ha->req_q_cnt);
                goto out;
@@ -3487,6 +3437,7 @@ qla1280_isr(struct scsi_qla_host *ha, struct list_head *done_q)
 
                                        /* Save ISP completion status */
                                        CMD_RESULT(sp->cmd) = 0;
+                                       CMD_HANDLE(sp->cmd) = COMPLETED_HANDLE;
 
                                        /* Place block on done queue */
                                        list_add_tail(&sp->list, done_q);
@@ -3495,7 +3446,7 @@ qla1280_isr(struct scsi_qla_host *ha, struct list_head *done_q)
                                         * If we get here we have a real problem!
                                         */
                                        printk(KERN_WARNING
-                                              "qla1280: ISP invalid handle");
+                                              "qla1280: ISP invalid handle\n");
                                }
                        }
                        break;
@@ -3753,6 +3704,8 @@ qla1280_status_entry(struct scsi_qla_host *ha, struct response *pkt,
                }
        }
 
+       CMD_HANDLE(sp->cmd) = COMPLETED_HANDLE;
+
        /* Place command on done queue. */
        list_add_tail(&sp->list, done_q);
  out:
@@ -3808,6 +3761,8 @@ qla1280_error_entry(struct scsi_qla_host *ha, struct response *pkt,
                        CMD_RESULT(sp->cmd) = DID_ERROR << 16;
                }
 
+               CMD_HANDLE(sp->cmd) = COMPLETED_HANDLE;
+
                /* Place command on done queue. */
                list_add_tail(&sp->list, done_q);
        }
@@ -3858,19 +3813,16 @@ qla1280_abort_isp(struct scsi_qla_host *ha)
                struct scsi_cmnd *cmd;
                sp = ha->outstanding_cmds[cnt];
                if (sp) {
-
                        cmd = sp->cmd;
                        CMD_RESULT(cmd) = DID_RESET << 16;
-
-                       sp->cmd = NULL;
+                       CMD_HANDLE(cmd) = COMPLETED_HANDLE;
                        ha->outstanding_cmds[cnt] = NULL;
-
-                       (*cmd->scsi_done)(cmd);
-
-                       sp->flags = 0;
+                       list_add_tail(&sp->list, &ha->done_q);
                }
        }
 
+       qla1280_done(ha);
+
        status = qla1280_load_firmware(ha);
        if (status)
                goto out;
@@ -3955,13 +3907,6 @@ qla1280_check_for_dead_scsi_bus(struct scsi_qla_host *ha, unsigned int bus)
 
                if (scsi_control == SCSI_PHASE_INVALID) {
                        ha->bus_settings[bus].scsi_bus_dead = 1;
-#if 0
-                       CMD_RESULT(cp) = DID_NO_CONNECT << 16;
-                       CMD_HANDLE(cp) = INVALID_HANDLE;
-                       /* ha->actthreads--; */
-
-                       (*(cp)->scsi_done)(cp);
-#endif
                        return 1;       /* bus is dead */
                } else {
                        ha->bus_settings[bus].scsi_bus_dead = 0;
index d7c44b8d2b4f5c9ef9c92c5bc8bb4a3029afc095..834884b9eed5b579e62a622ce4725c80ad897a7b 100644 (file)
@@ -88,7 +88,8 @@
 
 /* Maximum outstanding commands in ISP queues */
 #define MAX_OUTSTANDING_COMMANDS       512
-#define INVALID_HANDLE                 (MAX_OUTSTANDING_COMMANDS + 2)
+#define COMPLETED_HANDLE               ((unsigned char *) \
+                                       (MAX_OUTSTANDING_COMMANDS + 2))
 
 /* ISP request and response entry counts (37-65535) */
 #define REQUEST_ENTRY_CNT              255 /* Number of request entries. */
index b09993a06576cfbf37ead3608b53d5256bf084f4..0f8796201504c25a9f736f38f4ec8094b2578640 100644 (file)
@@ -97,7 +97,7 @@ qla2x00_sysfs_read_nvram(struct kobject *kobj,
                return 0;
 
        if (IS_NOCACHE_VPD_TYPE(ha))
-               ha->isp_ops->read_optrom(vha, ha->vpd, ha->flt_region_nvram << 2,
+               ha->isp_ops->read_optrom(vha, ha->nvram, ha->flt_region_nvram << 2,
                    ha->nvram_size);
        return memory_read_from_buffer(buf, count, &off, ha->nvram,
                                        ha->nvram_size);
@@ -692,6 +692,109 @@ static struct bin_attribute sysfs_edc_status_attr = {
        .read = qla2x00_sysfs_read_edc_status,
 };
 
+static ssize_t
+qla2x00_sysfs_read_xgmac_stats(struct kobject *kobj,
+                      struct bin_attribute *bin_attr,
+                      char *buf, loff_t off, size_t count)
+{
+       struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
+           struct device, kobj)));
+       struct qla_hw_data *ha = vha->hw;
+       int rval;
+       uint16_t actual_size;
+
+       if (!capable(CAP_SYS_ADMIN) || off != 0 || count > XGMAC_DATA_SIZE)
+               return 0;
+
+       if (ha->xgmac_data)
+               goto do_read;
+
+       ha->xgmac_data = dma_alloc_coherent(&ha->pdev->dev, XGMAC_DATA_SIZE,
+           &ha->xgmac_data_dma, GFP_KERNEL);
+       if (!ha->xgmac_data) {
+               qla_printk(KERN_WARNING, ha,
+                   "Unable to allocate memory for XGMAC read-data.\n");
+               return 0;
+       }
+
+do_read:
+       actual_size = 0;
+       memset(ha->xgmac_data, 0, XGMAC_DATA_SIZE);
+
+       rval = qla2x00_get_xgmac_stats(vha, ha->xgmac_data_dma,
+           XGMAC_DATA_SIZE, &actual_size);
+       if (rval != QLA_SUCCESS) {
+               qla_printk(KERN_WARNING, ha,
+                   "Unable to read XGMAC data (%x).\n", rval);
+               count = 0;
+       }
+
+       count = actual_size > count ? count: actual_size;
+       memcpy(buf, ha->xgmac_data, count);
+
+       return count;
+}
+
+static struct bin_attribute sysfs_xgmac_stats_attr = {
+       .attr = {
+               .name = "xgmac_stats",
+               .mode = S_IRUSR,
+       },
+       .size = 0,
+       .read = qla2x00_sysfs_read_xgmac_stats,
+};
+
+static ssize_t
+qla2x00_sysfs_read_dcbx_tlv(struct kobject *kobj,
+                      struct bin_attribute *bin_attr,
+                      char *buf, loff_t off, size_t count)
+{
+       struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
+           struct device, kobj)));
+       struct qla_hw_data *ha = vha->hw;
+       int rval;
+       uint16_t actual_size;
+
+       if (!capable(CAP_SYS_ADMIN) || off != 0 || count > DCBX_TLV_DATA_SIZE)
+               return 0;
+
+       if (ha->dcbx_tlv)
+               goto do_read;
+
+       ha->dcbx_tlv = dma_alloc_coherent(&ha->pdev->dev, DCBX_TLV_DATA_SIZE,
+           &ha->dcbx_tlv_dma, GFP_KERNEL);
+       if (!ha->dcbx_tlv) {
+               qla_printk(KERN_WARNING, ha,
+                   "Unable to allocate memory for DCBX TLV read-data.\n");
+               return 0;
+       }
+
+do_read:
+       actual_size = 0;
+       memset(ha->dcbx_tlv, 0, DCBX_TLV_DATA_SIZE);
+
+       rval = qla2x00_get_dcbx_params(vha, ha->dcbx_tlv_dma,
+           DCBX_TLV_DATA_SIZE);
+       if (rval != QLA_SUCCESS) {
+               qla_printk(KERN_WARNING, ha,
+                   "Unable to read DCBX TLV data (%x).\n", rval);
+               count = 0;
+       }
+
+       memcpy(buf, ha->dcbx_tlv, count);
+
+       return count;
+}
+
+static struct bin_attribute sysfs_dcbx_tlv_attr = {
+       .attr = {
+               .name = "dcbx_tlv",
+               .mode = S_IRUSR,
+       },
+       .size = 0,
+       .read = qla2x00_sysfs_read_dcbx_tlv,
+};
+
 static struct sysfs_entry {
        char *name;
        struct bin_attribute *attr;
@@ -706,6 +809,8 @@ static struct sysfs_entry {
        { "reset", &sysfs_reset_attr, },
        { "edc", &sysfs_edc_attr, 2 },
        { "edc_status", &sysfs_edc_status_attr, 2 },
+       { "xgmac_stats", &sysfs_xgmac_stats_attr, 3 },
+       { "dcbx_tlv", &sysfs_dcbx_tlv_attr, 3 },
        { NULL },
 };
 
@@ -721,6 +826,8 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *vha)
                        continue;
                if (iter->is4GBp_only == 2 && !IS_QLA25XX(vha->hw))
                        continue;
+               if (iter->is4GBp_only == 3 && !IS_QLA81XX(vha->hw))
+                       continue;
 
                ret = sysfs_create_bin_file(&host->shost_gendev.kobj,
                    iter->attr);
@@ -743,6 +850,8 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *vha)
                        continue;
                if (iter->is4GBp_only == 2 && !IS_QLA25XX(ha))
                        continue;
+               if (iter->is4GBp_only == 3 && !IS_QLA81XX(ha))
+                       continue;
 
                sysfs_remove_bin_file(&host->shost_gendev.kobj,
                    iter->attr);
@@ -1088,6 +1197,58 @@ qla2x00_flash_block_size_show(struct device *dev,
        return snprintf(buf, PAGE_SIZE, "0x%x\n", ha->fdt_block_size);
 }
 
+static ssize_t
+qla2x00_vlan_id_show(struct device *dev, struct device_attribute *attr,
+    char *buf)
+{
+       scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+
+       if (!IS_QLA81XX(vha->hw))
+               return snprintf(buf, PAGE_SIZE, "\n");
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", vha->fcoe_vlan_id);
+}
+
+static ssize_t
+qla2x00_vn_port_mac_address_show(struct device *dev,
+    struct device_attribute *attr, char *buf)
+{
+       scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+
+       if (!IS_QLA81XX(vha->hw))
+               return snprintf(buf, PAGE_SIZE, "\n");
+
+       return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n",
+           vha->fcoe_vn_port_mac[5], vha->fcoe_vn_port_mac[4],
+           vha->fcoe_vn_port_mac[3], vha->fcoe_vn_port_mac[2],
+           vha->fcoe_vn_port_mac[1], vha->fcoe_vn_port_mac[0]);
+}
+
+static ssize_t
+qla2x00_fabric_param_show(struct device *dev, struct device_attribute *attr,
+    char *buf)
+{
+       scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", vha->hw->switch_cap);
+}
+
+static ssize_t
+qla2x00_fw_state_show(struct device *dev, struct device_attribute *attr,
+    char *buf)
+{
+       scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+       int rval;
+       uint16_t state[5];
+
+       rval = qla2x00_get_firmware_state(vha, state);
+       if (rval != QLA_SUCCESS)
+               memset(state, -1, sizeof(state));
+
+       return snprintf(buf, PAGE_SIZE, "0x%x 0x%x 0x%x 0x%x 0x%x\n", state[0],
+           state[1], state[2], state[3], state[4]);
+}
+
 static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL);
 static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL);
 static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL);
@@ -1116,6 +1277,11 @@ static DEVICE_ATTR(mpi_version, S_IRUGO, qla2x00_mpi_version_show, NULL);
 static DEVICE_ATTR(phy_version, S_IRUGO, qla2x00_phy_version_show, NULL);
 static DEVICE_ATTR(flash_block_size, S_IRUGO, qla2x00_flash_block_size_show,
                   NULL);
+static DEVICE_ATTR(vlan_id, S_IRUGO, qla2x00_vlan_id_show, NULL);
+static DEVICE_ATTR(vn_port_mac_address, S_IRUGO,
+                  qla2x00_vn_port_mac_address_show, NULL);
+static DEVICE_ATTR(fabric_param, S_IRUGO, qla2x00_fabric_param_show, NULL);
+static DEVICE_ATTR(fw_state, S_IRUGO, qla2x00_fw_state_show, NULL);
 
 struct device_attribute *qla2x00_host_attrs[] = {
        &dev_attr_driver_version,
@@ -1138,6 +1304,10 @@ struct device_attribute *qla2x00_host_attrs[] = {
        &dev_attr_mpi_version,
        &dev_attr_phy_version,
        &dev_attr_flash_block_size,
+       &dev_attr_vlan_id,
+       &dev_attr_vn_port_mac_address,
+       &dev_attr_fabric_param,
+       &dev_attr_fw_state,
        NULL,
 };
 
@@ -1313,7 +1483,8 @@ qla2x00_terminate_rport_io(struct fc_rport *rport)
         * At this point all fcport's software-states are cleared.  Perform any
         * final cleanup of firmware resources (PCBs and XCBs).
         */
-       if (fcport->loop_id != FC_NO_LOOP_ID)
+       if (fcport->loop_id != FC_NO_LOOP_ID &&
+           !test_bit(UNLOADING, &fcport->vha->dpc_flags))
                fcport->vha->hw->isp_ops->fabric_logout(fcport->vha,
                        fcport->loop_id, fcport->d_id.b.domain,
                        fcport->d_id.b.area, fcport->d_id.b.al_pa);
@@ -1437,11 +1608,13 @@ static int
 qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
 {
        int     ret = 0;
-       int     cnt = 0;
-       uint8_t qos = QLA_DEFAULT_QUE_QOS;
+       uint8_t qos = 0;
        scsi_qla_host_t *base_vha = shost_priv(fc_vport->shost);
        scsi_qla_host_t *vha = NULL;
        struct qla_hw_data *ha = base_vha->hw;
+       uint16_t options = 0;
+       int     cnt;
+       struct req_que *req = ha->req_q_map[0];
 
        ret = qla24xx_vport_create_req_sanity_check(fc_vport);
        if (ret) {
@@ -1497,23 +1670,39 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
 
        qla24xx_vport_disable(fc_vport, disable);
 
-       /* Create a queue pair for the vport */
-       if (ha->mqenable) {
-               if (ha->npiv_info) {
-                       for (; cnt < ha->nvram_npiv_size; cnt++) {
-                               if (ha->npiv_info[cnt].port_name ==
-                                       vha->port_name &&
-                                       ha->npiv_info[cnt].node_name ==
-                                       vha->node_name) {
-                                       qos = ha->npiv_info[cnt].q_qos;
-                                       break;
-                               }
-                       }
+       if (ql2xmultique_tag) {
+               req = ha->req_q_map[1];
+               goto vport_queue;
+       } else if (ql2xmaxqueues == 1 || !ha->npiv_info)
+               goto vport_queue;
+       /* Create a request queue in QoS mode for the vport */
+       for (cnt = 0; cnt < ha->nvram_npiv_size; cnt++) {
+               if (memcmp(ha->npiv_info[cnt].port_name, vha->port_name, 8) == 0
+                       && memcmp(ha->npiv_info[cnt].node_name, vha->node_name,
+                                       8) == 0) {
+                       qos = ha->npiv_info[cnt].q_qos;
+                       break;
+               }
+       }
+       if (qos) {
+               ret = qla25xx_create_req_que(ha, options, vha->vp_idx, 0, 0,
+                       qos);
+               if (!ret)
+                       qla_printk(KERN_WARNING, ha,
+                       "Can't create request queue for vp_idx:%d\n",
+                       vha->vp_idx);
+               else {
+                       DEBUG2(qla_printk(KERN_INFO, ha,
+                       "Request Que:%d (QoS: %d) created for vp_idx:%d\n",
+                       ret, qos, vha->vp_idx));
+                       req = ha->req_q_map[ret];
                }
-               qla25xx_create_queues(vha, qos);
        }
 
+vport_queue:
+       vha->req = req;
        return 0;
+
 vport_create_failed_2:
        qla24xx_disable_vp(vha);
        qla24xx_deallocate_vp_id(vha);
@@ -1554,8 +1743,8 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
                    vha->host_no, vha->vp_idx, vha));
         }
 
-       if (ha->mqenable) {
-               if (qla25xx_delete_queues(vha, 0) != QLA_SUCCESS)
+       if (vha->req->id && !ql2xmultique_tag) {
+               if (qla25xx_delete_req_que(vha, vha->req) != QLA_SUCCESS)
                        qla_printk(KERN_WARNING, ha,
                                "Queue delete failed.\n");
        }
index 34760f8d4f1768f37a0687770d5f1a4d23e5d7da..4a990f4da4ea95254fda1e6c233e202e86ad6cea 100644 (file)
@@ -149,11 +149,9 @@ qla24xx_pause_risc(struct device_reg_24xx __iomem *reg)
        int rval = QLA_SUCCESS;
        uint32_t cnt;
 
-       if (RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE)
-               return rval;
-
        WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_PAUSE);
-       for (cnt = 30000; (RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0 &&
+       for (cnt = 30000;
+           ((RD_REG_DWORD(&reg->host_status) & HSRX_RISC_PAUSED) == 0) &&
            rval == QLA_SUCCESS; cnt--) {
                if (cnt)
                        udelay(100);
@@ -351,7 +349,7 @@ static inline void *
 qla25xx_copy_mq(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain)
 {
        uint32_t cnt, que_idx;
-       uint8_t req_cnt, rsp_cnt, que_cnt;
+       uint8_t que_cnt;
        struct qla2xxx_mq_chain *mq = ptr;
        struct device_reg_25xxmq __iomem *reg;
 
@@ -363,9 +361,8 @@ qla25xx_copy_mq(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain)
        mq->type = __constant_htonl(DUMP_CHAIN_MQ);
        mq->chain_size = __constant_htonl(sizeof(struct qla2xxx_mq_chain));
 
-       req_cnt = find_first_zero_bit(ha->req_qid_map, ha->max_queues);
-       rsp_cnt = find_first_zero_bit(ha->rsp_qid_map, ha->max_queues);
-       que_cnt = req_cnt > rsp_cnt ? req_cnt : rsp_cnt;
+       que_cnt = ha->max_req_queues > ha->max_rsp_queues ?
+               ha->max_req_queues : ha->max_rsp_queues;
        mq->count = htonl(que_cnt);
        for (cnt = 0; cnt < que_cnt; cnt++) {
                reg = (struct device_reg_25xxmq *) ((void *)
index 714ee67567e1c814080342665e4d19dde48513ee..00aa48d975a698edcb73b1024c3f302f29a66a6c 100644 (file)
@@ -93,6 +93,7 @@
 #define LSD(x) ((uint32_t)((uint64_t)(x)))
 #define MSD(x) ((uint32_t)((((uint64_t)(x)) >> 16) >> 16))
 
+#define MAKE_HANDLE(x, y) ((uint32_t)((((uint32_t)(x)) << 16) | (uint32_t)(y)))
 
 /*
  * I/O register
 #define REQUEST_ENTRY_CNT_24XX         2048    /* Number of request entries. */
 #define RESPONSE_ENTRY_CNT_2100                64      /* Number of response entries.*/
 #define RESPONSE_ENTRY_CNT_2300                512     /* Number of response entries.*/
+#define RESPONSE_ENTRY_CNT_MQ          128     /* Number of response entries.*/
 
 struct req_que;
 
@@ -186,7 +188,6 @@ struct req_que;
  * SCSI Request Block
  */
 typedef struct srb {
-       struct req_que *que;
        struct fc_port *fcport;
 
        struct scsi_cmnd *cmd;          /* Linux SCSI command pkt */
@@ -2008,7 +2009,7 @@ typedef struct vport_params {
 #define VP_RET_CODE_NOT_FOUND          6
 
 struct qla_hw_data;
-
+struct rsp_que;
 /*
  * ISP operations
  */
@@ -2030,10 +2031,9 @@ struct isp_operations {
        void (*enable_intrs) (struct qla_hw_data *);
        void (*disable_intrs) (struct qla_hw_data *);
 
-       int (*abort_command) (struct scsi_qla_host *, srb_t *,
-               struct req_que *);
-       int (*target_reset) (struct fc_port *, unsigned int);
-       int (*lun_reset) (struct fc_port *, unsigned int);
+       int (*abort_command) (srb_t *);
+       int (*target_reset) (struct fc_port *, unsigned int, int);
+       int (*lun_reset) (struct fc_port *, unsigned int, int);
        int (*fabric_login) (struct scsi_qla_host *, uint16_t, uint8_t,
                uint8_t, uint8_t, uint16_t *, uint8_t);
        int (*fabric_logout) (struct scsi_qla_host *, uint16_t, uint8_t,
@@ -2079,7 +2079,6 @@ struct isp_operations {
 #define QLA_PCI_MSIX_CONTROL   0xa2
 
 struct scsi_qla_host;
-struct rsp_que;
 
 struct qla_msix_entry {
        int have_irq;
@@ -2140,7 +2139,6 @@ struct qla_statistics {
 #define MBC_INITIALIZE_MULTIQ 0x1f
 #define QLA_QUE_PAGE 0X1000
 #define QLA_MQ_SIZE 32
-#define QLA_MAX_HOST_QUES 16
 #define QLA_MAX_QUEUES 256
 #define ISP_QUE_REG(ha, id) \
        ((ha->mqenable) ? \
@@ -2170,6 +2168,8 @@ struct rsp_que {
        struct qla_hw_data *hw;
        struct qla_msix_entry *msix;
        struct req_que *req;
+       srb_t *status_srb; /* status continuation entry */
+       struct work_struct q_work;
 };
 
 /* Request queue data structure */
@@ -2222,6 +2222,8 @@ struct qla_hw_data {
                uint32_t        fce_enabled             :1;
                uint32_t        fac_supported           :1;
                uint32_t        chip_reset_done         :1;
+               uint32_t        port0                   :1;
+               uint32_t        running_gold_fw         :1;
        } flags;
 
        /* This spinlock is used to protect "io transactions", you must
@@ -2246,7 +2248,8 @@ struct qla_hw_data {
        struct rsp_que **rsp_q_map;
        unsigned long req_qid_map[(QLA_MAX_QUEUES / 8) / sizeof(unsigned long)];
        unsigned long rsp_qid_map[(QLA_MAX_QUEUES / 8) / sizeof(unsigned long)];
-       uint16_t        max_queues;
+       uint8_t         max_req_queues;
+       uint8_t         max_rsp_queues;
        struct qla_npiv_entry *npiv_info;
        uint16_t        nvram_npiv_size;
 
@@ -2255,6 +2258,9 @@ struct qla_hw_data {
 #define FLOGI_MID_SUPPORT       BIT_10
 #define FLOGI_VSAN_SUPPORT      BIT_12
 #define FLOGI_SP_SUPPORT        BIT_13
+
+       uint8_t         port_no;                /* Physical port of adapter */
+
        /* Timeout timers. */
        uint8_t         loop_down_abort_time;    /* port down timer */
        atomic_t        loop_down_timer;         /* loop down timer */
@@ -2392,6 +2398,14 @@ struct qla_hw_data {
        dma_addr_t      edc_data_dma;
        uint16_t        edc_data_len;
 
+#define XGMAC_DATA_SIZE        PAGE_SIZE
+       void            *xgmac_data;
+       dma_addr_t      xgmac_data_dma;
+
+#define DCBX_TLV_DATA_SIZE PAGE_SIZE
+       void            *dcbx_tlv;
+       dma_addr_t      dcbx_tlv_dma;
+
        struct task_struct      *dpc_thread;
        uint8_t dpc_active;                  /* DPC routine is active */
 
@@ -2510,6 +2524,7 @@ struct qla_hw_data {
        uint32_t        flt_region_vpd;
        uint32_t        flt_region_nvram;
        uint32_t        flt_region_npiv_conf;
+       uint32_t        flt_region_gold_fw;
 
        /* Needed for BEACON */
        uint16_t        beacon_blink_led;
@@ -2536,6 +2551,7 @@ struct qla_hw_data {
        struct qla_chip_state_84xx *cs84xx;
        struct qla_statistics qla_stats;
        struct isp_operations *isp_ops;
+       struct workqueue_struct *wq;
 };
 
 /*
@@ -2545,6 +2561,8 @@ typedef struct scsi_qla_host {
        struct list_head list;
        struct list_head vp_fcports;    /* list of fcports */
        struct list_head work_list;
+       spinlock_t work_lock;
+
        /* Commonly used flags and state information. */
        struct Scsi_Host *host;
        unsigned long   host_no;
@@ -2591,8 +2609,6 @@ typedef struct scsi_qla_host {
 #define SWITCH_FOUND           BIT_0
 #define DFLG_NO_CABLE          BIT_1
 
-       srb_t           *status_srb;    /* Status continuation entry. */
-
        /* ISP configuration data. */
        uint16_t        loop_id;                /* Host adapter loop id */
 
@@ -2618,6 +2634,11 @@ typedef struct scsi_qla_host {
        uint8_t         node_name[WWN_SIZE];
        uint8_t         port_name[WWN_SIZE];
        uint8_t         fabric_node_name[WWN_SIZE];
+
+       uint16_t        fcoe_vlan_id;
+       uint16_t        fcoe_fcf_idx;
+       uint8_t         fcoe_vn_port_mac[6];
+
        uint32_t        vp_abort_cnt;
 
        struct fc_vport *fc_vport;      /* holds fc_vport * for each vport */
@@ -2643,7 +2664,7 @@ typedef struct scsi_qla_host {
 #define VP_ERR_FAB_LOGOUT      4
 #define VP_ERR_ADAP_NORESOURCES        5
        struct qla_hw_data *hw;
-       int     req_ques[QLA_MAX_HOST_QUES];
+       struct req_que *req;
 } scsi_qla_host_t;
 
 /*
index 96ccb9642ba09e27c17e6a86ab1b3071f1e40323..dfde2dd865cbfea7008c9f104fc9c69873e24e20 100644 (file)
@@ -878,7 +878,6 @@ struct device_reg_24xx {
                                        /* HCCR statuses. */
 #define HCCRX_HOST_INT         BIT_6   /* Host to RISC interrupt bit. */
 #define HCCRX_RISC_RESET       BIT_5   /* RISC Reset mode bit. */
-#define HCCRX_RISC_PAUSE       BIT_4   /* RISC Pause mode bit. */
                                        /* HCCR commands. */
                                        /* NOOP. */
 #define HCCRX_NOOP             0x00000000
@@ -1241,6 +1240,7 @@ struct qla_flt_header {
 #define FLT_REG_HW_EVENT_1     0x1f
 #define FLT_REG_NPIV_CONF_0    0x29
 #define FLT_REG_NPIV_CONF_1    0x2a
+#define FLT_REG_GOLD_FW                0x2f
 
 struct qla_flt_region {
        uint32_t code;
@@ -1405,6 +1405,8 @@ struct access_chip_rsp_84xx {
 #define MBC_IDC_ACK            0x101
 #define MBC_RESTART_MPI_FW     0x3d
 #define MBC_FLASH_ACCESS_CTRL  0x3e    /* Control flash access. */
+#define MBC_GET_XGMAC_STATS    0x7a
+#define MBC_GET_DCBX_PARAMS    0x51
 
 /* Flash access control option field bit definitions */
 #define FAC_OPT_FORCE_SEMAPHORE                BIT_15
@@ -1711,7 +1713,7 @@ struct ex_init_cb_81xx {
 #define FA_VPD0_ADDR_81                0xD0000
 #define FA_VPD1_ADDR_81                0xD0400
 #define FA_NVRAM0_ADDR_81      0xD0080
-#define FA_NVRAM1_ADDR_81      0xD0480
+#define FA_NVRAM1_ADDR_81      0xD0180
 #define FA_FEATURE_ADDR_81     0xD4000
 #define FA_FLASH_DESCR_ADDR_81 0xD8000
 #define FA_FLASH_LAYOUT_ADDR_81        0xD8400
index 528913f6bed99ffc010eb3ec6d680660403683c7..65b12d82867c9ff6a6b128785b0b0034d16e9dd3 100644 (file)
@@ -65,8 +65,11 @@ extern int ql2xfdmienable;
 extern int ql2xallocfwdump;
 extern int ql2xextended_error_logging;
 extern int ql2xqfullrampup;
+extern int ql2xqfulltracking;
 extern int ql2xiidmaenable;
 extern int ql2xmaxqueues;
+extern int ql2xmultique_tag;
+extern int ql2xfwloadbin;
 
 extern int qla2x00_loop_reset(scsi_qla_host_t *);
 extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
@@ -145,7 +148,7 @@ qla2x00_dump_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t);
 extern int
 qla2x00_execute_fw(scsi_qla_host_t *, uint32_t);
 
-extern void
+extern int
 qla2x00_get_fw_version(scsi_qla_host_t *, uint16_t *, uint16_t *, uint16_t *,
     uint16_t *, uint32_t *, uint8_t *, uint32_t *, uint8_t *);
 
@@ -165,13 +168,13 @@ extern int
 qla2x00_issue_iocb(scsi_qla_host_t *, void *, dma_addr_t, size_t);
 
 extern int
-qla2x00_abort_command(scsi_qla_host_t *, srb_t *, struct req_que *);
+qla2x00_abort_command(srb_t *);
 
 extern int
-qla2x00_abort_target(struct fc_port *, unsigned int);
+qla2x00_abort_target(struct fc_port *, unsigned int, int);
 
 extern int
-qla2x00_lun_reset(struct fc_port *, unsigned int);
+qla2x00_lun_reset(struct fc_port *, unsigned int, int);
 
 extern int
 qla2x00_get_adapter_id(scsi_qla_host_t *, uint16_t *, uint8_t *, uint8_t *,
@@ -236,9 +239,11 @@ extern int
 qla24xx_get_isp_stats(scsi_qla_host_t *, struct link_statistics *,
     dma_addr_t);
 
-extern int qla24xx_abort_command(scsi_qla_host_t *, srb_t *, struct req_que *);
-extern int qla24xx_abort_target(struct fc_port *, unsigned int);
-extern int qla24xx_lun_reset(struct fc_port *, unsigned int);
+extern int qla24xx_abort_command(srb_t *);
+extern int
+qla24xx_abort_target(struct fc_port *, unsigned int, int);
+extern int
+qla24xx_lun_reset(struct fc_port *, unsigned int, int);
 
 extern int
 qla2x00_system_error(scsi_qla_host_t *);
@@ -288,6 +293,18 @@ qla81xx_fac_do_write_enable(scsi_qla_host_t *, int);
 extern int
 qla81xx_fac_erase_sector(scsi_qla_host_t *, uint32_t, uint32_t);
 
+extern int
+qla2x00_get_xgmac_stats(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t *);
+
+extern int
+qla2x00_get_dcbx_params(scsi_qla_host_t *, dma_addr_t, uint16_t);
+
+extern int
+qla2x00_read_ram_word(scsi_qla_host_t *, uint32_t, uint32_t *);
+
+extern int
+qla2x00_write_ram_word(scsi_qla_host_t *, uint32_t, uint32_t);
+
 /*
  * Global Function Prototypes in qla_isr.c source file.
  */
@@ -295,8 +312,8 @@ extern irqreturn_t qla2100_intr_handler(int, void *);
 extern irqreturn_t qla2300_intr_handler(int, void *);
 extern irqreturn_t qla24xx_intr_handler(int, void *);
 extern void qla2x00_process_response_queue(struct rsp_que *);
-extern void qla24xx_process_response_queue(struct rsp_que *);
-
+extern void
+qla24xx_process_response_queue(struct scsi_qla_host *, struct rsp_que *);
 extern int qla2x00_request_irqs(struct qla_hw_data *, struct rsp_que *);
 extern void qla2x00_free_irqs(scsi_qla_host_t *);
 
@@ -401,19 +418,21 @@ extern int qla25xx_request_irq(struct rsp_que *);
 extern int qla25xx_init_req_que(struct scsi_qla_host *, struct req_que *);
 extern int qla25xx_init_rsp_que(struct scsi_qla_host *, struct rsp_que *);
 extern int qla25xx_create_req_que(struct qla_hw_data *, uint16_t, uint8_t,
-       uint16_t, uint8_t, uint8_t);
+       uint16_t, int, uint8_t);
 extern int qla25xx_create_rsp_que(struct qla_hw_data *, uint16_t, uint8_t,
-       uint16_t);
+       uint16_t, int);
 extern int qla25xx_update_req_que(struct scsi_qla_host *, uint8_t, uint8_t);
 extern void qla2x00_init_response_q_entries(struct rsp_que *);
 extern int qla25xx_delete_req_que(struct scsi_qla_host *, struct req_que *);
 extern int qla25xx_delete_rsp_que(struct scsi_qla_host *, struct rsp_que *);
 extern int qla25xx_create_queues(struct scsi_qla_host *, uint8_t);
-extern int qla25xx_delete_queues(struct scsi_qla_host *, uint8_t);
+extern int qla25xx_delete_queues(struct scsi_qla_host *);
 extern uint16_t qla24xx_rd_req_reg(struct qla_hw_data *, uint16_t);
 extern uint16_t qla25xx_rd_req_reg(struct qla_hw_data *, uint16_t);
 extern void qla24xx_wrt_req_reg(struct qla_hw_data *, uint16_t, uint16_t);
 extern void qla25xx_wrt_req_reg(struct qla_hw_data *, uint16_t, uint16_t);
 extern void qla25xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t);
 extern void qla24xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t);
+extern struct scsi_qla_host * qla25xx_get_host(struct rsp_que *);
+
 #endif /* _QLA_GBL_H */
index 557f58d5bf88074174c5b3c7213d6d7eed9c96d1..917534b9f2216c50784888d514d764e950c7a572 100644 (file)
@@ -1107,7 +1107,7 @@ qla2x00_mgmt_svr_login(scsi_qla_host_t *vha)
                return ret;
 
        ha->isp_ops->fabric_login(vha, vha->mgmt_svr_loop_id, 0xff, 0xff, 0xfa,
-           mb, BIT_1);
+           mb, BIT_1|BIT_0);
        if (mb[0] != MBS_COMMAND_COMPLETE) {
                DEBUG2_13(printk("%s(%ld): Failed MANAGEMENT_SERVER login: "
                    "loop_id=%x mb[0]=%x mb[1]=%x mb[2]=%x mb[6]=%x mb[7]=%x\n",
@@ -1879,6 +1879,9 @@ qla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list)
                        case BIT_13:
                                list[i].fp_speed = PORT_SPEED_4GB;
                                break;
+                       case BIT_12:
+                               list[i].fp_speed = PORT_SPEED_10GB;
+                               break;
                        case BIT_11:
                                list[i].fp_speed = PORT_SPEED_8GB;
                                break;
index bd7dd84c06485b4947ef4f38b66a799ff7230305..26202612932534cbd2b0bebcec847d1cb7d3ce6c 100644 (file)
@@ -634,7 +634,7 @@ qla2x00_chip_diag(scsi_qla_host_t *vha)
                goto chip_diag_failed;
 
        DEBUG3(printk("scsi(%ld): Reset register cleared by chip reset\n",
-           ha->host_no));
+           vha->host_no));
 
        /* Reset RISC processor. */
        WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
@@ -655,7 +655,7 @@ qla2x00_chip_diag(scsi_qla_host_t *vha)
                goto chip_diag_failed;
 
        /* Check product ID of chip */
-       DEBUG3(printk("scsi(%ld): Checking product ID of chip\n", ha->host_no));
+       DEBUG3(printk("scsi(%ld): Checking product ID of chip\n", vha->host_no));
 
        mb[1] = RD_MAILBOX_REG(ha, reg, 1);
        mb[2] = RD_MAILBOX_REG(ha, reg, 2);
@@ -730,9 +730,6 @@ qla24xx_chip_diag(scsi_qla_host_t *vha)
        struct qla_hw_data *ha = vha->hw;
        struct req_que *req = ha->req_q_map[0];
 
-       /* Perform RISC reset. */
-       qla24xx_reset_risc(vha);
-
        ha->fw_transfer_size = REQUEST_ENTRY_SIZE * req->length;
 
        rval = qla2x00_mbx_reg_test(vha);
@@ -786,7 +783,6 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
                    sizeof(uint32_t);
                if (ha->mqenable)
                        mq_size = sizeof(struct qla2xxx_mq_chain);
-
                /* Allocate memory for Fibre Channel Event Buffer. */
                if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))
                        goto try_eft;
@@ -850,8 +846,7 @@ cont_alloc:
        rsp_q_size = rsp->length * sizeof(response_t);
 
        dump_size = offsetof(struct qla2xxx_fw_dump, isp);
-       dump_size += fixed_size + mem_size + req_q_size + rsp_q_size +
-           eft_size;
+       dump_size += fixed_size + mem_size + req_q_size + rsp_q_size + eft_size;
        ha->chain_offset = dump_size;
        dump_size += mq_size + fce_size;
 
@@ -891,6 +886,56 @@ cont_alloc:
            htonl(offsetof(struct qla2xxx_fw_dump, isp));
 }
 
+static int
+qla81xx_mpi_sync(scsi_qla_host_t *vha)
+{
+#define MPS_MASK       0xe0
+       int rval;
+       uint16_t dc;
+       uint32_t dw;
+       struct qla_hw_data *ha = vha->hw;
+
+       if (!IS_QLA81XX(vha->hw))
+               return QLA_SUCCESS;
+
+       rval = qla2x00_write_ram_word(vha, 0x7c00, 1);
+       if (rval != QLA_SUCCESS) {
+               DEBUG2(qla_printk(KERN_WARNING, ha,
+                   "Sync-MPI: Unable to acquire semaphore.\n"));
+               goto done;
+       }
+
+       pci_read_config_word(vha->hw->pdev, 0x54, &dc);
+       rval = qla2x00_read_ram_word(vha, 0x7a15, &dw);
+       if (rval != QLA_SUCCESS) {
+               DEBUG2(qla_printk(KERN_WARNING, ha,
+                   "Sync-MPI: Unable to read sync.\n"));
+               goto done_release;
+       }
+
+       dc &= MPS_MASK;
+       if (dc == (dw & MPS_MASK))
+               goto done_release;
+
+       dw &= ~MPS_MASK;
+       dw |= dc;
+       rval = qla2x00_write_ram_word(vha, 0x7a15, dw);
+       if (rval != QLA_SUCCESS) {
+               DEBUG2(qla_printk(KERN_WARNING, ha,
+                   "Sync-MPI: Unable to gain sync.\n"));
+       }
+
+done_release:
+       rval = qla2x00_write_ram_word(vha, 0x7c00, 0);
+       if (rval != QLA_SUCCESS) {
+               DEBUG2(qla_printk(KERN_WARNING, ha,
+                   "Sync-MPI: Unable to release semaphore.\n"));
+       }
+
+done:
+       return rval;
+}
+
 /**
  * qla2x00_setup_chip() - Load and start RISC firmware.
  * @ha: HA context
@@ -915,6 +960,8 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
                spin_unlock_irqrestore(&ha->hardware_lock, flags);
        }
 
+       qla81xx_mpi_sync(vha);
+
        /* Load firmware sequences */
        rval = ha->isp_ops->load_risc(vha, &srisc_address);
        if (rval == QLA_SUCCESS) {
@@ -931,13 +978,16 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
                        /* Retrieve firmware information. */
                        if (rval == QLA_SUCCESS) {
                                fw_major_version = ha->fw_major_version;
-                               qla2x00_get_fw_version(vha,
+                               rval = qla2x00_get_fw_version(vha,
                                    &ha->fw_major_version,
                                    &ha->fw_minor_version,
                                    &ha->fw_subminor_version,
                                    &ha->fw_attributes, &ha->fw_memory_size,
                                    ha->mpi_version, &ha->mpi_capabilities,
                                    ha->phy_version);
+                               if (rval != QLA_SUCCESS)
+                                       goto failed;
+
                                ha->flags.npiv_supported = 0;
                                if (IS_QLA2XXX_MIDTYPE(ha) &&
                                         (ha->fw_attributes & BIT_2)) {
@@ -989,7 +1039,7 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
                            ha->fw_subminor_version);
                }
        }
-
+failed:
        if (rval) {
                DEBUG2_3(printk("scsi(%ld): Setup chip **** FAILED ****.\n",
                    vha->host_no));
@@ -1013,12 +1063,14 @@ qla2x00_init_response_q_entries(struct rsp_que *rsp)
        uint16_t cnt;
        response_t *pkt;
 
+       rsp->ring_ptr = rsp->ring;
+       rsp->ring_index    = 0;
+       rsp->status_srb = NULL;
        pkt = rsp->ring_ptr;
        for (cnt = 0; cnt < rsp->length; cnt++) {
                pkt->signature = RESPONSE_PROCESSED;
                pkt++;
        }
-
 }
 
 /**
@@ -1176,7 +1228,7 @@ qla24xx_config_rings(struct scsi_qla_host *vha)
                if (ha->flags.msix_enabled) {
                        msix = &ha->msix_entries[1];
                        DEBUG2_17(printk(KERN_INFO
-                       "Reistering vector 0x%x for base que\n", msix->entry));
+                       "Registering vector 0x%x for base que\n", msix->entry));
                        icb->msix = cpu_to_le16(msix->entry);
                }
                /* Use alternate PCI bus number */
@@ -1230,14 +1282,14 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
        spin_lock_irqsave(&ha->hardware_lock, flags);
 
        /* Clear outstanding commands array. */
-       for (que = 0; que < ha->max_queues; que++) {
+       for (que = 0; que < ha->max_req_queues; que++) {
                req = ha->req_q_map[que];
                if (!req)
                        continue;
-               for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++)
+               for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++)
                        req->outstanding_cmds[cnt] = NULL;
 
-               req->current_outstanding_cmd = 0;
+               req->current_outstanding_cmd = 1;
 
                /* Initialize firmware. */
                req->ring_ptr  = req->ring;
@@ -1245,13 +1297,10 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
                req->cnt      = req->length;
        }
 
-       for (que = 0; que < ha->max_queues; que++) {
+       for (que = 0; que < ha->max_rsp_queues; que++) {
                rsp = ha->rsp_q_map[que];
                if (!rsp)
                        continue;
-               rsp->ring_ptr = rsp->ring;
-               rsp->ring_index    = 0;
-
                /* Initialize response queue entries */
                qla2x00_init_response_q_entries(rsp);
        }
@@ -1307,7 +1356,7 @@ qla2x00_fw_ready(scsi_qla_host_t *vha)
        unsigned long   wtime, mtime, cs84xx_time;
        uint16_t        min_wait;       /* Minimum wait time if loop is down */
        uint16_t        wait_time;      /* Wait time if loop is coming ready */
-       uint16_t        state[3];
+       uint16_t        state[5];
        struct qla_hw_data *ha = vha->hw;
 
        rval = QLA_SUCCESS;
@@ -1406,8 +1455,9 @@ qla2x00_fw_ready(scsi_qla_host_t *vha)
                    vha->host_no, state[0], jiffies));
        } while (1);
 
-       DEBUG(printk("scsi(%ld): fw_state=%x curr time=%lx.\n",
-           vha->host_no, state[0], jiffies));
+       DEBUG(printk("scsi(%ld): fw_state=%x (%x, %x, %x, %x) curr time=%lx.\n",
+           vha->host_no, state[0], state[1], state[2], state[3], state[4],
+           jiffies));
 
        if (rval) {
                DEBUG2_3(printk("scsi(%ld): Firmware ready **** FAILED ****.\n",
@@ -1541,6 +1591,7 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len,
        char *st, *en;
        uint16_t index;
        struct qla_hw_data *ha = vha->hw;
+       int use_tbl = !IS_QLA25XX(ha) && !IS_QLA81XX(ha);
 
        if (memcmp(model, BINZERO, len) != 0) {
                strncpy(ha->model_number, model, len);
@@ -1553,14 +1604,16 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len,
                }
 
                index = (ha->pdev->subsystem_device & 0xff);
-               if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
+               if (use_tbl &&
+                   ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
                    index < QLA_MODEL_NAMES)
                        strncpy(ha->model_desc,
                            qla2x00_model_name[index * 2 + 1],
                            sizeof(ha->model_desc) - 1);
        } else {
                index = (ha->pdev->subsystem_device & 0xff);
-               if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
+               if (use_tbl &&
+                   ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
                    index < QLA_MODEL_NAMES) {
                        strcpy(ha->model_number,
                            qla2x00_model_name[index * 2]);
@@ -2061,8 +2114,10 @@ qla2x00_configure_loop(scsi_qla_host_t *vha)
        if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
                if (test_bit(LOCAL_LOOP_UPDATE, &save_flags))
                        set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
-               if (test_bit(RSCN_UPDATE, &save_flags))
+               if (test_bit(RSCN_UPDATE, &save_flags)) {
                        set_bit(RSCN_UPDATE, &vha->dpc_flags);
+                       vha->flags.rscn_queue_overflow = 1;
+               }
        }
 
        return (rval);
@@ -2110,7 +2165,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)
                goto cleanup_allocation;
 
        DEBUG3(printk("scsi(%ld): Entries in ID list (%d)\n",
-           ha->host_no, entries));
+           vha->host_no, entries));
        DEBUG3(qla2x00_dump_buffer((uint8_t *)ha->gid_list,
            entries * sizeof(struct gid_list_info)));
 
@@ -2243,7 +2298,8 @@ static void
 qla2x00_iidma_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
 {
 #define LS_UNKNOWN      2
-       static char *link_speeds[5] = { "1", "2", "?", "4", "8" };
+       static char *link_speeds[] = { "1", "2", "?", "4", "8", "10" };
+       char *link_speed;
        int rval;
        uint16_t mb[6];
        struct qla_hw_data *ha = vha->hw;
@@ -2266,10 +2322,15 @@ qla2x00_iidma_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
                    fcport->port_name[6], fcport->port_name[7], rval,
                    fcport->fp_speed, mb[0], mb[1]));
        } else {
+               link_speed = link_speeds[LS_UNKNOWN];
+               if (fcport->fp_speed < 5)
+                       link_speed = link_speeds[fcport->fp_speed];
+               else if (fcport->fp_speed == 0x13)
+                       link_speed = link_speeds[5];
                DEBUG2(qla_printk(KERN_INFO, ha,
                    "iIDMA adjusted to %s GB/s on "
                    "%02x%02x%02x%02x%02x%02x%02x%02x.\n",
-                   link_speeds[fcport->fp_speed], fcport->port_name[0],
+                   link_speed, fcport->port_name[0],
                    fcport->port_name[1], fcport->port_name[2],
                    fcport->port_name[3], fcport->port_name[4],
                    fcport->port_name[5], fcport->port_name[6],
@@ -3180,9 +3241,14 @@ qla2x00_loop_resync(scsi_qla_host_t *vha)
 {
        int rval = QLA_SUCCESS;
        uint32_t wait_time;
-       struct qla_hw_data *ha = vha->hw;
-       struct req_que *req = ha->req_q_map[vha->req_ques[0]];
-       struct rsp_que *rsp = req->rsp;
+       struct req_que *req;
+       struct rsp_que *rsp;
+
+       if (ql2xmultique_tag)
+               req = vha->hw->req_q_map[0];
+       else
+               req = vha->req;
+       rsp = req->rsp;
 
        atomic_set(&vha->loop_state, LOOP_UPDATE);
        clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
@@ -3448,7 +3514,7 @@ qla25xx_init_queues(struct qla_hw_data *ha)
        int ret = -1;
        int i;
 
-       for (i = 1; i < ha->max_queues; i++) {
+       for (i = 1; i < ha->max_rsp_queues; i++) {
                rsp = ha->rsp_q_map[i];
                if (rsp) {
                        rsp->options &= ~BIT_0;
@@ -3462,6 +3528,8 @@ qla25xx_init_queues(struct qla_hw_data *ha)
                                        "%s Rsp que:%d inited\n", __func__,
                                                rsp->id));
                }
+       }
+       for (i = 1; i < ha->max_req_queues; i++) {
                req = ha->req_q_map[i];
                if (req) {
                /* Clear outstanding commands array. */
@@ -3566,14 +3634,15 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
        nv = ha->nvram;
 
        /* Determine NVRAM starting address. */
-       ha->nvram_size = sizeof(struct nvram_24xx);
-       ha->nvram_base = FA_NVRAM_FUNC0_ADDR;
-       ha->vpd_size = FA_NVRAM_VPD_SIZE;
-       ha->vpd_base = FA_NVRAM_VPD0_ADDR;
-       if (PCI_FUNC(ha->pdev->devfn)) {
+       if (ha->flags.port0) {
+               ha->nvram_base = FA_NVRAM_FUNC0_ADDR;
+               ha->vpd_base = FA_NVRAM_VPD0_ADDR;
+       } else {
                ha->nvram_base = FA_NVRAM_FUNC1_ADDR;
                ha->vpd_base = FA_NVRAM_VPD1_ADDR;
        }
+       ha->nvram_size = sizeof(struct nvram_24xx);
+       ha->vpd_size = FA_NVRAM_VPD_SIZE;
 
        /* Get VPD data into cache */
        ha->vpd = ha->nvram + VPD_OFFSET;
@@ -3587,7 +3656,7 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
        for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
                chksum += le32_to_cpu(*dptr++);
 
-       DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no));
+       DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", vha->host_no));
        DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
 
        /* Bad NVRAM data, set defaults parameters. */
@@ -3612,7 +3681,7 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
                nv->exchange_count = __constant_cpu_to_le16(0);
                nv->hard_address = __constant_cpu_to_le16(124);
                nv->port_name[0] = 0x21;
-               nv->port_name[1] = 0x00 + PCI_FUNC(ha->pdev->devfn);
+               nv->port_name[1] = 0x00 + ha->port_no;
                nv->port_name[2] = 0x00;
                nv->port_name[3] = 0xe0;
                nv->port_name[4] = 0x8b;
@@ -3798,11 +3867,11 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
 }
 
 static int
-qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr)
+qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
+    uint32_t faddr)
 {
        int     rval = QLA_SUCCESS;
        int     segments, fragment;
-       uint32_t faddr;
        uint32_t *dcode, dlen;
        uint32_t risc_addr;
        uint32_t risc_size;
@@ -3811,12 +3880,11 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr)
        struct req_que *req = ha->req_q_map[0];
 
        qla_printk(KERN_INFO, ha,
-           "FW: Loading from flash (%x)...\n", ha->flt_region_fw);
+           "FW: Loading from flash (%x)...\n", faddr);
 
        rval = QLA_SUCCESS;
 
        segments = FA_RISC_CODE_SEGMENTS;
-       faddr = ha->flt_region_fw;
        dcode = (uint32_t *)req->ring;
        *srisc_addr = 0;
 
@@ -4104,6 +4172,9 @@ qla24xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
 {
        int rval;
 
+       if (ql2xfwloadbin == 1)
+               return qla81xx_load_risc(vha, srisc_addr);
+
        /*
         * FW Load priority:
         * 1) Firmware via request-firmware interface (.bin file).
@@ -4113,24 +4184,45 @@ qla24xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
        if (rval == QLA_SUCCESS)
                return rval;
 
-       return qla24xx_load_risc_flash(vha, srisc_addr);
+       return qla24xx_load_risc_flash(vha, srisc_addr,
+           vha->hw->flt_region_fw);
 }
 
 int
 qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
 {
        int rval;
+       struct qla_hw_data *ha = vha->hw;
+
+       if (ql2xfwloadbin == 2)
+               goto try_blob_fw;
 
        /*
         * FW Load priority:
         * 1) Firmware residing in flash.
         * 2) Firmware via request-firmware interface (.bin file).
+        * 3) Golden-Firmware residing in flash -- limited operation.
         */
-       rval = qla24xx_load_risc_flash(vha, srisc_addr);
+       rval = qla24xx_load_risc_flash(vha, srisc_addr, ha->flt_region_fw);
        if (rval == QLA_SUCCESS)
                return rval;
 
-       return qla24xx_load_risc_blob(vha, srisc_addr);
+try_blob_fw:
+       rval = qla24xx_load_risc_blob(vha, srisc_addr);
+       if (rval == QLA_SUCCESS || !ha->flt_region_gold_fw)
+               return rval;
+
+       qla_printk(KERN_ERR, ha,
+           "FW: Attempting to fallback to golden firmware...\n");
+       rval = qla24xx_load_risc_flash(vha, srisc_addr, ha->flt_region_gold_fw);
+       if (rval != QLA_SUCCESS)
+               return rval;
+
+       qla_printk(KERN_ERR, ha,
+           "FW: Please update operational firmware...\n");
+       ha->flags.running_gold_fw = 1;
+
+       return rval;
 }
 
 void
@@ -4146,7 +4238,7 @@ qla2x00_try_to_stop_firmware(scsi_qla_host_t *vha)
 
        ret = qla2x00_stop_firmware(vha);
        for (retries = 5; ret != QLA_SUCCESS && ret != QLA_FUNCTION_TIMEOUT &&
-           retries ; retries--) {
+           ret != QLA_INVALID_COMMAND && retries ; retries--) {
                ha->isp_ops->reset_chip(vha);
                if (ha->isp_ops->chip_diag(vha) != QLA_SUCCESS)
                        continue;
@@ -4165,13 +4257,19 @@ qla24xx_configure_vhba(scsi_qla_host_t *vha)
        uint16_t mb[MAILBOX_REGISTER_COUNT];
        struct qla_hw_data *ha = vha->hw;
        struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
-       struct req_que *req = ha->req_q_map[vha->req_ques[0]];
-       struct rsp_que *rsp = req->rsp;
+       struct req_que *req;
+       struct rsp_que *rsp;
 
        if (!vha->vp_idx)
                return -EINVAL;
 
        rval = qla2x00_fw_ready(base_vha);
+       if (ql2xmultique_tag)
+               req = ha->req_q_map[0];
+       else
+               req = vha->req;
+       rsp = req->rsp;
+
        if (rval == QLA_SUCCESS) {
                clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
                qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL);
@@ -4305,7 +4403,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
        for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
                chksum += le32_to_cpu(*dptr++);
 
-       DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no));
+       DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", vha->host_no));
        DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
 
        /* Bad NVRAM data, set defaults parameters. */
@@ -4329,7 +4427,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
                nv->execution_throttle = __constant_cpu_to_le16(0xFFFF);
                nv->exchange_count = __constant_cpu_to_le16(0);
                nv->port_name[0] = 0x21;
-               nv->port_name[1] = 0x00 + PCI_FUNC(ha->pdev->devfn);
+               nv->port_name[1] = 0x00 + ha->port_no;
                nv->port_name[2] = 0x00;
                nv->port_name[3] = 0xe0;
                nv->port_name[4] = 0x8b;
@@ -4358,12 +4456,12 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
                nv->max_luns_per_target = __constant_cpu_to_le16(128);
                nv->port_down_retry_count = __constant_cpu_to_le16(30);
                nv->link_down_timeout = __constant_cpu_to_le16(30);
-               nv->enode_mac[0] = 0x01;
+               nv->enode_mac[0] = 0x00;
                nv->enode_mac[1] = 0x02;
                nv->enode_mac[2] = 0x03;
                nv->enode_mac[3] = 0x04;
                nv->enode_mac[4] = 0x05;
-               nv->enode_mac[5] = 0x06 + PCI_FUNC(ha->pdev->devfn);
+               nv->enode_mac[5] = 0x06 + ha->port_no;
 
                rval = 1;
        }
@@ -4396,7 +4494,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
                icb->enode_mac[2] = 0x03;
                icb->enode_mac[3] = 0x04;
                icb->enode_mac[4] = 0x05;
-               icb->enode_mac[5] = 0x06 + PCI_FUNC(ha->pdev->devfn);
+               icb->enode_mac[5] = 0x06 + ha->port_no;
        }
 
        /* Use extended-initialization control block. */
index a8abbb95730df7d39eda9721471f04f4af1dd8db..13396beae2cedcde63b00c6156b44696168e6cc0 100644 (file)
@@ -15,6 +15,7 @@ static request_t *qla2x00_req_pkt(struct scsi_qla_host *, struct req_que *,
                                                        struct rsp_que *rsp);
 static void qla2x00_isp_cmd(struct scsi_qla_host *, struct req_que *);
 
+static void qla25xx_set_que(srb_t *, struct rsp_que **);
 /**
  * qla2x00_get_cmd_direction() - Determine control_flag data direction.
  * @cmd: SCSI command
@@ -92,9 +93,10 @@ qla2x00_calc_iocbs_64(uint16_t dsds)
  * Returns a pointer to the Continuation Type 0 IOCB packet.
  */
 static inline cont_entry_t *
-qla2x00_prep_cont_type0_iocb(struct req_que *req, struct scsi_qla_host *vha)
+qla2x00_prep_cont_type0_iocb(struct scsi_qla_host *vha)
 {
        cont_entry_t *cont_pkt;
+       struct req_que *req = vha->req;
        /* Adjust ring index. */
        req->ring_index++;
        if (req->ring_index == req->length) {
@@ -120,10 +122,11 @@ qla2x00_prep_cont_type0_iocb(struct req_que *req, struct scsi_qla_host *vha)
  * Returns a pointer to the continuation type 1 IOCB packet.
  */
 static inline cont_a64_entry_t *
-qla2x00_prep_cont_type1_iocb(struct req_que *req, scsi_qla_host_t *vha)
+qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha)
 {
        cont_a64_entry_t *cont_pkt;
 
+       struct req_que *req = vha->req;
        /* Adjust ring index. */
        req->ring_index++;
        if (req->ring_index == req->length) {
@@ -159,7 +162,6 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt,
        struct scsi_cmnd *cmd;
        struct scatterlist *sg;
        int i;
-       struct req_que *req;
 
        cmd = sp->cmd;
 
@@ -174,8 +176,6 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt,
        }
 
        vha = sp->fcport->vha;
-       req = sp->que;
-
        cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp));
 
        /* Three DSDs are available in the Command Type 2 IOCB */
@@ -192,7 +192,7 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt,
                         * Seven DSDs are available in the Continuation
                         * Type 0 IOCB.
                         */
-                       cont_pkt = qla2x00_prep_cont_type0_iocb(req, vha);
+                       cont_pkt = qla2x00_prep_cont_type0_iocb(vha);
                        cur_dsd = (uint32_t *)&cont_pkt->dseg_0_address;
                        avail_dsds = 7;
                }
@@ -220,7 +220,6 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt,
        struct scsi_cmnd *cmd;
        struct scatterlist *sg;
        int i;
-       struct req_que *req;
 
        cmd = sp->cmd;
 
@@ -235,8 +234,6 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt,
        }
 
        vha = sp->fcport->vha;
-       req = sp->que;
-
        cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp));
 
        /* Two DSDs are available in the Command Type 3 IOCB */
@@ -254,7 +251,7 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt,
                         * Five DSDs are available in the Continuation
                         * Type 1 IOCB.
                         */
-                       cont_pkt = qla2x00_prep_cont_type1_iocb(req, vha);
+                       cont_pkt = qla2x00_prep_cont_type1_iocb(vha);
                        cur_dsd = (uint32_t *)cont_pkt->dseg_0_address;
                        avail_dsds = 5;
                }
@@ -353,7 +350,6 @@ qla2x00_start_scsi(srb_t *sp)
        /* Build command packet */
        req->current_outstanding_cmd = handle;
        req->outstanding_cmds[handle] = sp;
-       sp->que = req;
        sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle;
        req->cnt -= req_cnt;
 
@@ -453,6 +449,7 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req,
                        mrk24->lun[2] = MSB(lun);
                        host_to_fcp_swap(mrk24->lun, sizeof(mrk24->lun));
                        mrk24->vp_index = vha->vp_idx;
+                       mrk24->handle = MAKE_HANDLE(req->id, mrk24->handle);
                } else {
                        SET_TARGET_ID(ha, mrk->target, loop_id);
                        mrk->lun = cpu_to_le16(lun);
@@ -531,9 +528,6 @@ qla2x00_req_pkt(struct scsi_qla_host *vha, struct req_que *req,
                        for (cnt = 0; cnt < REQUEST_ENTRY_SIZE / 4; cnt++)
                                *dword_ptr++ = 0;
 
-                       /* Set system defined field. */
-                       pkt->sys_define = (uint8_t)req->ring_index;
-
                        /* Set entry count. */
                        pkt->entry_count = 1;
 
@@ -656,7 +650,7 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt,
        }
 
        vha = sp->fcport->vha;
-       req = sp->que;
+       req = vha->req;
 
        /* Set transfer direction */
        if (cmd->sc_data_direction == DMA_TO_DEVICE) {
@@ -687,7 +681,7 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt,
                         * Five DSDs are available in the Continuation
                         * Type 1 IOCB.
                         */
-                       cont_pkt = qla2x00_prep_cont_type1_iocb(req, vha);
+                       cont_pkt = qla2x00_prep_cont_type1_iocb(vha);
                        cur_dsd = (uint32_t *)cont_pkt->dseg_0_address;
                        avail_dsds = 5;
                }
@@ -724,19 +718,13 @@ qla24xx_start_scsi(srb_t *sp)
        struct scsi_cmnd *cmd = sp->cmd;
        struct scsi_qla_host *vha = sp->fcport->vha;
        struct qla_hw_data *ha = vha->hw;
-       uint16_t que_id;
 
        /* Setup device pointers. */
        ret = 0;
-       que_id = vha->req_ques[0];
 
-       req = ha->req_q_map[que_id];
-       sp->que = req;
+       qla25xx_set_que(sp, &rsp);
+       req = vha->req;
 
-       if (req->rsp)
-               rsp = req->rsp;
-       else
-               rsp = ha->rsp_q_map[que_id];
        /* So we know we haven't pci_map'ed anything yet */
        tot_dsds = 0;
 
@@ -794,7 +782,7 @@ qla24xx_start_scsi(srb_t *sp)
        req->cnt -= req_cnt;
 
        cmd_pkt = (struct cmd_type_7 *)req->ring_ptr;
-       cmd_pkt->handle = handle;
+       cmd_pkt->handle = MAKE_HANDLE(req->id, handle);
 
        /* Zero out remaining portion of packet. */
        /*    tagged queuing modifier -- default is TSK_SIMPLE (0). */
@@ -823,6 +811,8 @@ qla24xx_start_scsi(srb_t *sp)
 
        /* Set total data segment count. */
        cmd_pkt->entry_count = (uint8_t)req_cnt;
+       /* Specify response queue number where completion should happen */
+       cmd_pkt->entry_status = (uint8_t) rsp->id;
        wmb();
 
        /* Adjust ring index. */
@@ -842,7 +832,7 @@ qla24xx_start_scsi(srb_t *sp)
        /* Manage unprocessed RIO/ZIO commands in response queue. */
        if (vha->flags.process_response_queue &&
                rsp->ring_ptr->signature != RESPONSE_PROCESSED)
-               qla24xx_process_response_queue(rsp);
+               qla24xx_process_response_queue(vha, rsp);
 
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
        return QLA_SUCCESS;
@@ -855,3 +845,16 @@ queuing_error:
 
        return QLA_FUNCTION_FAILED;
 }
+
+static void qla25xx_set_que(srb_t *sp, struct rsp_que **rsp)
+{
+       struct scsi_cmnd *cmd = sp->cmd;
+       struct qla_hw_data *ha = sp->fcport->vha->hw;
+       int affinity = cmd->request->cpu;
+
+       if (ql2xmultique_tag && affinity >= 0 &&
+               affinity < ha->max_rsp_queues - 1)
+               *rsp = ha->rsp_q_map[affinity + 1];
+        else
+               *rsp = ha->rsp_q_map[0];
+}
index d04981848e561aed9e9c7853619f78c532d84174..c8d0a176fea4a1287853716a7dd1d6f20c910060 100644 (file)
@@ -13,10 +13,9 @@ static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
 static void qla2x00_process_completed_request(struct scsi_qla_host *,
        struct req_que *, uint32_t);
 static void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *);
-static void qla2x00_status_cont_entry(scsi_qla_host_t *, sts_cont_entry_t *);
+static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
 static void qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
        sts_entry_t *);
-static struct scsi_qla_host *qla2x00_get_rsp_host(struct rsp_que *);
 
 /**
  * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
@@ -51,7 +50,7 @@ qla2100_intr_handler(int irq, void *dev_id)
        status = 0;
 
        spin_lock(&ha->hardware_lock);
-       vha = qla2x00_get_rsp_host(rsp);
+       vha = pci_get_drvdata(ha->pdev);
        for (iter = 50; iter--; ) {
                hccr = RD_REG_WORD(&reg->hccr);
                if (hccr & HCCR_RISC_PAUSE) {
@@ -147,7 +146,7 @@ qla2300_intr_handler(int irq, void *dev_id)
        status = 0;
 
        spin_lock(&ha->hardware_lock);
-       vha = qla2x00_get_rsp_host(rsp);
+       vha = pci_get_drvdata(ha->pdev);
        for (iter = 50; iter--; ) {
                stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
                if (stat & HSR_RISC_PAUSED) {
@@ -685,7 +684,7 @@ skip_rio:
                    vha->host_no));
 
                if (IS_FWI2_CAPABLE(ha))
-                       qla24xx_process_response_queue(rsp);
+                       qla24xx_process_response_queue(vha, rsp);
                else
                        qla2x00_process_response_queue(rsp);
                break;
@@ -766,7 +765,10 @@ qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, void *data)
        struct qla_hw_data *ha = vha->hw;
        struct req_que *req = NULL;
 
-       req = ha->req_q_map[vha->req_ques[0]];
+       if (!ql2xqfulltracking)
+               return;
+
+       req = vha->req;
        if (!req)
                return;
        if (req->max_q_depth <= sdev->queue_depth)
@@ -808,6 +810,9 @@ qla2x00_ramp_up_queue_depth(scsi_qla_host_t *vha, struct req_que *req,
        fc_port_t *fcport;
        struct scsi_device *sdev;
 
+       if (!ql2xqfulltracking)
+               return;
+
        sdev = sp->cmd->device;
        if (sdev->queue_depth >= req->max_q_depth)
                return;
@@ -858,8 +863,8 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha,
                qla2x00_ramp_up_queue_depth(vha, req, sp);
                qla2x00_sp_compl(ha, sp);
        } else {
-               DEBUG2(printk("scsi(%ld): Invalid ISP SCSI completion handle\n",
-                   vha->host_no));
+               DEBUG2(printk("scsi(%ld) Req:%d: Invalid ISP SCSI completion"
+                       " handle(%d)\n", vha->host_no, req->id, index));
                qla_printk(KERN_WARNING, ha,
                    "Invalid ISP SCSI completion handle\n");
 
@@ -881,7 +886,7 @@ qla2x00_process_response_queue(struct rsp_que *rsp)
        uint16_t        handle_cnt;
        uint16_t        cnt;
 
-       vha = qla2x00_get_rsp_host(rsp);
+       vha = pci_get_drvdata(ha->pdev);
 
        if (!vha->flags.online)
                return;
@@ -926,7 +931,7 @@ qla2x00_process_response_queue(struct rsp_que *rsp)
                        }
                        break;
                case STATUS_CONT_TYPE:
-                       qla2x00_status_cont_entry(vha, (sts_cont_entry_t *)pkt);
+                       qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
                        break;
                default:
                        /* Type Not Supported. */
@@ -945,7 +950,8 @@ qla2x00_process_response_queue(struct rsp_que *rsp)
 }
 
 static inline void
-qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len)
+qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len,
+       struct rsp_que *rsp)
 {
        struct scsi_cmnd *cp = sp->cmd;
 
@@ -962,7 +968,7 @@ qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len)
        sp->request_sense_ptr += sense_len;
        sp->request_sense_length -= sense_len;
        if (sp->request_sense_length != 0)
-               sp->fcport->vha->status_srb = sp;
+               rsp->status_srb = sp;
 
        DEBUG5(printk("%s(): Check condition Sense data, scsi(%ld:%d:%d:%d) "
            "cmd=%p pid=%ld\n", __func__, sp->fcport->vha->host_no,
@@ -992,7 +998,9 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
        uint32_t        sense_len, rsp_info_len, resid_len, fw_resid_len;
        uint8_t         *rsp_info, *sense_data;
        struct qla_hw_data *ha = vha->hw;
-       struct req_que *req = rsp->req;
+       uint32_t handle;
+       uint16_t que;
+       struct req_que *req;
 
        sts = (sts_entry_t *) pkt;
        sts24 = (struct sts_entry_24xx *) pkt;
@@ -1003,18 +1011,20 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                comp_status = le16_to_cpu(sts->comp_status);
                scsi_status = le16_to_cpu(sts->scsi_status) & SS_MASK;
        }
-
+       handle = (uint32_t) LSW(sts->handle);
+       que = MSW(sts->handle);
+       req = ha->req_q_map[que];
        /* Fast path completion. */
        if (comp_status == CS_COMPLETE && scsi_status == 0) {
-               qla2x00_process_completed_request(vha, req, sts->handle);
+               qla2x00_process_completed_request(vha, req, handle);
 
                return;
        }
 
        /* Validate handle. */
-       if (sts->handle < MAX_OUTSTANDING_COMMANDS) {
-               sp = req->outstanding_cmds[sts->handle];
-               req->outstanding_cmds[sts->handle] = NULL;
+       if (handle < MAX_OUTSTANDING_COMMANDS) {
+               sp = req->outstanding_cmds[handle];
+               req->outstanding_cmds[handle] = NULL;
        } else
                sp = NULL;
 
@@ -1030,7 +1040,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
        cp = sp->cmd;
        if (cp == NULL) {
                DEBUG2(printk("scsi(%ld): Command already returned back to OS "
-                   "pkt->handle=%d sp=%p.\n", vha->host_no, sts->handle, sp));
+                   "pkt->handle=%d sp=%p.\n", vha->host_no, handle, sp));
                qla_printk(KERN_WARNING, ha,
                    "Command is NULL: already returned to OS (sp=%p)\n", sp);
 
@@ -1121,6 +1131,8 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                            scsi_status));
 
                        /* Adjust queue depth for all luns on the port. */
+                       if (!ql2xqfulltracking)
+                               break;
                        fcport->last_queue_full = jiffies;
                        starget_for_each_device(cp->device->sdev_target,
                            fcport, qla2x00_adjust_sdev_qdepth_down);
@@ -1133,7 +1145,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                if (!(scsi_status & SS_SENSE_LEN_VALID))
                        break;
 
-               qla2x00_handle_sense(sp, sense_data, sense_len);
+               qla2x00_handle_sense(sp, sense_data, sense_len, rsp);
                break;
 
        case CS_DATA_UNDERRUN:
@@ -1179,6 +1191,8 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                                 * Adjust queue depth for all luns on the
                                 * port.
                                 */
+                               if (!ql2xqfulltracking)
+                                       break;
                                fcport->last_queue_full = jiffies;
                                starget_for_each_device(
                                    cp->device->sdev_target, fcport,
@@ -1192,12 +1206,12 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                        if (!(scsi_status & SS_SENSE_LEN_VALID))
                                break;
 
-                       qla2x00_handle_sense(sp, sense_data, sense_len);
+                       qla2x00_handle_sense(sp, sense_data, sense_len, rsp);
                } else {
                        /*
                         * If RISC reports underrun and target does not report
                         * it then we must have a lost frame, so tell upper
-                        * layer to retry it by reporting a bus busy.
+                        * layer to retry it by reporting an error.
                         */
                        if (!(scsi_status & SS_RESIDUAL_UNDER)) {
                                DEBUG2(printk("scsi(%ld:%d:%d:%d) Dropped "
@@ -1207,7 +1221,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                                        cp->device->id, cp->device->lun, resid,
                                        scsi_bufflen(cp)));
 
-                               cp->result = DID_BUS_BUSY << 16;
+                               cp->result = DID_ERROR << 16;
                                break;
                        }
 
@@ -1334,7 +1348,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
        }
 
        /* Place command on done queue. */
-       if (vha->status_srb == NULL)
+       if (rsp->status_srb == NULL)
                qla2x00_sp_compl(ha, sp);
 }
 
@@ -1346,11 +1360,11 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
  * Extended sense data.
  */
 static void
-qla2x00_status_cont_entry(scsi_qla_host_t *vha, sts_cont_entry_t *pkt)
+qla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
 {
        uint8_t         sense_sz = 0;
-       struct qla_hw_data *ha = vha->hw;
-       srb_t           *sp = vha->status_srb;
+       struct qla_hw_data *ha = rsp->hw;
+       srb_t           *sp = rsp->status_srb;
        struct scsi_cmnd *cp;
 
        if (sp != NULL && sp->request_sense_length != 0) {
@@ -1362,7 +1376,7 @@ qla2x00_status_cont_entry(scsi_qla_host_t *vha, sts_cont_entry_t *pkt)
                            "cmd is NULL: already returned to OS (sp=%p)\n",
                            sp);
 
-                       vha->status_srb = NULL;
+                       rsp->status_srb = NULL;
                        return;
                }
 
@@ -1383,7 +1397,7 @@ qla2x00_status_cont_entry(scsi_qla_host_t *vha, sts_cont_entry_t *pkt)
 
                /* Place command on done queue. */
                if (sp->request_sense_length == 0) {
-                       vha->status_srb = NULL;
+                       rsp->status_srb = NULL;
                        qla2x00_sp_compl(ha, sp);
                }
        }
@@ -1399,7 +1413,9 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
 {
        srb_t *sp;
        struct qla_hw_data *ha = vha->hw;
-       struct req_que *req = rsp->req;
+       uint32_t handle = LSW(pkt->handle);
+       uint16_t que = MSW(pkt->handle);
+       struct req_que *req = ha->req_q_map[que];
 #if defined(QL_DEBUG_LEVEL_2)
        if (pkt->entry_status & RF_INV_E_ORDER)
                qla_printk(KERN_ERR, ha, "%s: Invalid Entry Order\n", __func__);
@@ -1417,14 +1433,14 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
 #endif
 
        /* Validate handle. */
-       if (pkt->handle < MAX_OUTSTANDING_COMMANDS)
-               sp = req->outstanding_cmds[pkt->handle];
+       if (handle < MAX_OUTSTANDING_COMMANDS)
+               sp = req->outstanding_cmds[handle];
        else
                sp = NULL;
 
        if (sp) {
                /* Free outstanding command slot. */
-               req->outstanding_cmds[pkt->handle] = NULL;
+               req->outstanding_cmds[handle] = NULL;
 
                /* Bad payload or header */
                if (pkt->entry_status &
@@ -1486,13 +1502,10 @@ qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
  * qla24xx_process_response_queue() - Process response queue entries.
  * @ha: SCSI driver HA context
  */
-void
-qla24xx_process_response_queue(struct rsp_que *rsp)
+void qla24xx_process_response_queue(struct scsi_qla_host *vha,
+       struct rsp_que *rsp)
 {
        struct sts_entry_24xx *pkt;
-       struct scsi_qla_host *vha;
-
-       vha = qla2x00_get_rsp_host(rsp);
 
        if (!vha->flags.online)
                return;
@@ -1523,7 +1536,7 @@ qla24xx_process_response_queue(struct rsp_que *rsp)
                        qla2x00_status_entry(vha, rsp, pkt);
                        break;
                case STATUS_CONT_TYPE:
-                       qla2x00_status_cont_entry(vha, (sts_cont_entry_t *)pkt);
+                       qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
                        break;
                case VP_RPT_ID_IOCB_TYPE:
                        qla24xx_report_id_acquisition(vha,
@@ -1626,7 +1639,7 @@ qla24xx_intr_handler(int irq, void *dev_id)
        status = 0;
 
        spin_lock(&ha->hardware_lock);
-       vha = qla2x00_get_rsp_host(rsp);
+       vha = pci_get_drvdata(ha->pdev);
        for (iter = 50; iter--; ) {
                stat = RD_REG_DWORD(&reg->host_status);
                if (stat & HSRX_RISC_PAUSED) {
@@ -1664,7 +1677,7 @@ qla24xx_intr_handler(int irq, void *dev_id)
                        break;
                case 0x13:
                case 0x14:
-                       qla24xx_process_response_queue(rsp);
+                       qla24xx_process_response_queue(vha, rsp);
                        break;
                default:
                        DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
@@ -1692,6 +1705,7 @@ qla24xx_msix_rsp_q(int irq, void *dev_id)
        struct qla_hw_data *ha;
        struct rsp_que *rsp;
        struct device_reg_24xx __iomem *reg;
+       struct scsi_qla_host *vha;
 
        rsp = (struct rsp_que *) dev_id;
        if (!rsp) {
@@ -1704,7 +1718,8 @@ qla24xx_msix_rsp_q(int irq, void *dev_id)
 
        spin_lock_irq(&ha->hardware_lock);
 
-       qla24xx_process_response_queue(rsp);
+       vha = qla25xx_get_host(rsp);
+       qla24xx_process_response_queue(vha, rsp);
        WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
 
        spin_unlock_irq(&ha->hardware_lock);
@@ -1717,7 +1732,6 @@ qla25xx_msix_rsp_q(int irq, void *dev_id)
 {
        struct qla_hw_data *ha;
        struct rsp_que *rsp;
-       struct device_reg_24xx __iomem *reg;
 
        rsp = (struct rsp_que *) dev_id;
        if (!rsp) {
@@ -1726,13 +1740,8 @@ qla25xx_msix_rsp_q(int irq, void *dev_id)
                return IRQ_NONE;
        }
        ha = rsp->hw;
-       reg = &ha->iobase->isp24;
 
-       spin_lock_irq(&ha->hardware_lock);
-
-       qla24xx_process_response_queue(rsp);
-
-       spin_unlock_irq(&ha->hardware_lock);
+       queue_work_on((int) (rsp->id - 1), ha->wq, &rsp->q_work);
 
        return IRQ_HANDLED;
 }
@@ -1760,7 +1769,7 @@ qla24xx_msix_default(int irq, void *dev_id)
        status = 0;
 
        spin_lock_irq(&ha->hardware_lock);
-       vha = qla2x00_get_rsp_host(rsp);
+       vha = pci_get_drvdata(ha->pdev);
        do {
                stat = RD_REG_DWORD(&reg->host_status);
                if (stat & HSRX_RISC_PAUSED) {
@@ -1798,7 +1807,7 @@ qla24xx_msix_default(int irq, void *dev_id)
                        break;
                case 0x13:
                case 0x14:
-                       qla24xx_process_response_queue(rsp);
+                       qla24xx_process_response_queue(vha, rsp);
                        break;
                default:
                        DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
@@ -1822,31 +1831,14 @@ qla24xx_msix_default(int irq, void *dev_id)
 /* Interrupt handling helpers. */
 
 struct qla_init_msix_entry {
-       uint16_t entry;
-       uint16_t index;
        const char *name;
        irq_handler_t handler;
 };
 
-static struct qla_init_msix_entry base_queue = {
-       .entry = 0,
-       .index = 0,
-       .name = "qla2xxx (default)",
-       .handler = qla24xx_msix_default,
-};
-
-static struct qla_init_msix_entry base_rsp_queue = {
-       .entry = 1,
-       .index = 1,
-       .name = "qla2xxx (rsp_q)",
-       .handler = qla24xx_msix_rsp_q,
-};
-
-static struct qla_init_msix_entry multi_rsp_queue = {
-       .entry = 1,
-       .index = 1,
-       .name = "qla2xxx (multi_q)",
-       .handler = qla25xx_msix_rsp_q,
+static struct qla_init_msix_entry msix_entries[3] = {
+       { "qla2xxx (default)", qla24xx_msix_default },
+       { "qla2xxx (rsp_q)", qla24xx_msix_rsp_q },
+       { "qla2xxx (multiq)", qla25xx_msix_rsp_q },
 };
 
 static void
@@ -1873,7 +1865,6 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
        int i, ret;
        struct msix_entry *entries;
        struct qla_msix_entry *qentry;
-       struct qla_init_msix_entry *msix_queue;
 
        entries = kzalloc(sizeof(struct msix_entry) * ha->msix_count,
                                        GFP_KERNEL);
@@ -1900,7 +1891,7 @@ msix_failed:
                                ha->msix_count, ret);
                        goto msix_out;
                }
-               ha->max_queues = ha->msix_count - 1;
+               ha->max_rsp_queues = ha->msix_count - 1;
        }
        ha->msix_entries = kzalloc(sizeof(struct qla_msix_entry) *
                                ha->msix_count, GFP_KERNEL);
@@ -1918,45 +1909,27 @@ msix_failed:
                qentry->rsp = NULL;
        }
 
-       /* Enable MSI-X for AENs for queue 0 */
-       qentry = &ha->msix_entries[0];
-       ret = request_irq(qentry->vector, base_queue.handler, 0,
-                                       base_queue.name, rsp);
-       if (ret) {
-               qla_printk(KERN_WARNING, ha,
+       /* Enable MSI-X vectors for the base queue */
+       for (i = 0; i < 2; i++) {
+               qentry = &ha->msix_entries[i];
+               ret = request_irq(qentry->vector, msix_entries[i].handler,
+                                       0, msix_entries[i].name, rsp);
+               if (ret) {
+                       qla_printk(KERN_WARNING, ha,
                        "MSI-X: Unable to register handler -- %x/%d.\n",
                        qentry->vector, ret);
-               qla24xx_disable_msix(ha);
-               goto msix_out;
+                       qla24xx_disable_msix(ha);
+                       ha->mqenable = 0;
+                       goto msix_out;
+               }
+               qentry->have_irq = 1;
+               qentry->rsp = rsp;
+               rsp->msix = qentry;
        }
-       qentry->have_irq = 1;
-       qentry->rsp = rsp;
 
        /* Enable MSI-X vector for response queue update for queue 0 */
-       if (ha->max_queues > 1 && ha->mqiobase) {
+       if (ha->mqiobase &&  (ha->max_rsp_queues > 1 || ha->max_req_queues > 1))
                ha->mqenable = 1;
-               msix_queue = &multi_rsp_queue;
-               qla_printk(KERN_INFO, ha,
-                               "MQ enabled, Number of Queue Resources: %d \n",
-                               ha->max_queues);
-       } else {
-               ha->mqenable = 0;
-               msix_queue = &base_rsp_queue;
-       }
-
-       qentry = &ha->msix_entries[1];
-       ret = request_irq(qentry->vector, msix_queue->handler, 0,
-                                               msix_queue->name, rsp);
-       if (ret) {
-               qla_printk(KERN_WARNING, ha,
-                       "MSI-X: Unable to register handler -- %x/%d.\n",
-                       qentry->vector, ret);
-               qla24xx_disable_msix(ha);
-               ha->mqenable = 0;
-               goto msix_out;
-       }
-       qentry->have_irq = 1;
-       qentry->rsp = rsp;
 
 msix_out:
        kfree(entries);
@@ -2063,35 +2036,11 @@ qla2x00_free_irqs(scsi_qla_host_t *vha)
        }
 }
 
-static struct scsi_qla_host *
-qla2x00_get_rsp_host(struct rsp_que *rsp)
-{
-       srb_t *sp;
-       struct qla_hw_data *ha = rsp->hw;
-       struct scsi_qla_host *vha = NULL;
-       struct sts_entry_24xx *pkt;
-       struct req_que *req;
-
-       if (rsp->id) {
-               pkt = (struct sts_entry_24xx *) rsp->ring_ptr;
-               req = rsp->req;
-               if (pkt && pkt->handle < MAX_OUTSTANDING_COMMANDS) {
-                       sp = req->outstanding_cmds[pkt->handle];
-                       if (sp)
-                               vha = sp->fcport->vha;
-               }
-       }
-       if (!vha)
-       /* handle it in base queue */
-               vha = pci_get_drvdata(ha->pdev);
-
-       return vha;
-}
 
 int qla25xx_request_irq(struct rsp_que *rsp)
 {
        struct qla_hw_data *ha = rsp->hw;
-       struct qla_init_msix_entry *intr = &multi_rsp_queue;
+       struct qla_init_msix_entry *intr = &msix_entries[2];
        struct qla_msix_entry *msix = rsp->msix;
        int ret;
 
@@ -2106,3 +2055,30 @@ int qla25xx_request_irq(struct rsp_que *rsp)
        msix->rsp = rsp;
        return ret;
 }
+
+struct scsi_qla_host *
+qla25xx_get_host(struct rsp_que *rsp)
+{
+       srb_t *sp;
+       struct qla_hw_data *ha = rsp->hw;
+       struct scsi_qla_host *vha = NULL;
+       struct sts_entry_24xx *pkt;
+       struct req_que *req;
+       uint16_t que;
+       uint32_t handle;
+
+       pkt = (struct sts_entry_24xx *) rsp->ring_ptr;
+       que = MSW(pkt->handle);
+       handle = (uint32_t) LSW(pkt->handle);
+       req = ha->req_q_map[que];
+       if (handle < MAX_OUTSTANDING_COMMANDS) {
+               sp = req->outstanding_cmds[handle];
+               if (sp)
+                       return  sp->fcport->vha;
+               else
+                       goto base_que;
+       }
+base_que:
+       vha = pci_get_drvdata(ha->pdev);
+       return vha;
+}
index e67c1660bf4671aacf54c43e35dca5182b81fc33..451ece0760b0f6ea49bb7884f5f95b2ac5528783 100644 (file)
@@ -408,7 +408,7 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
  * Context:
  *     Kernel context.
  */
-void
+int
 qla2x00_get_fw_version(scsi_qla_host_t *vha, uint16_t *major, uint16_t *minor,
     uint16_t *subminor, uint16_t *attributes, uint32_t *memory, uint8_t *mpi,
     uint32_t *mpi_caps, uint8_t *phy)
@@ -427,6 +427,8 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha, uint16_t *major, uint16_t *minor,
        mcp->flags = 0;
        mcp->tov = MBX_TOV_SECONDS;
        rval = qla2x00_mailbox_command(vha, mcp);
+       if (rval != QLA_SUCCESS)
+               goto failed;
 
        /* Return mailbox data. */
        *major = mcp->mb[1];
@@ -446,7 +448,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha, uint16_t *major, uint16_t *minor,
                phy[1] = mcp->mb[9] >> 8;
                phy[2] = mcp->mb[9] & 0xff;
        }
-
+failed:
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
                DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
@@ -455,6 +457,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha, uint16_t *major, uint16_t *minor,
                /*EMPTY*/
                DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
        }
+       return rval;
 }
 
 /*
@@ -748,20 +751,20 @@ qla2x00_issue_iocb(scsi_qla_host_t *vha, void *buffer, dma_addr_t phys_addr,
  *     Kernel context.
  */
 int
-qla2x00_abort_command(scsi_qla_host_t *vha, srb_t *sp, struct req_que *req)
+qla2x00_abort_command(srb_t *sp)
 {
        unsigned long   flags = 0;
-       fc_port_t       *fcport;
        int             rval;
        uint32_t        handle = 0;
        mbx_cmd_t       mc;
        mbx_cmd_t       *mcp = &mc;
+       fc_port_t       *fcport = sp->fcport;
+       scsi_qla_host_t *vha = fcport->vha;
        struct qla_hw_data *ha = vha->hw;
+       struct req_que *req = vha->req;
 
        DEBUG11(printk("qla2x00_abort_command(%ld): entered.\n", vha->host_no));
 
-       fcport = sp->fcport;
-
        spin_lock_irqsave(&ha->hardware_lock, flags);
        for (handle = 1; handle < MAX_OUTSTANDING_COMMANDS; handle++) {
                if (req->outstanding_cmds[handle] == sp)
@@ -800,7 +803,7 @@ qla2x00_abort_command(scsi_qla_host_t *vha, srb_t *sp, struct req_que *req)
 }
 
 int
-qla2x00_abort_target(struct fc_port *fcport, unsigned int l)
+qla2x00_abort_target(struct fc_port *fcport, unsigned int l, int tag)
 {
        int rval, rval2;
        mbx_cmd_t  mc;
@@ -813,8 +816,8 @@ qla2x00_abort_target(struct fc_port *fcport, unsigned int l)
 
        l = l;
        vha = fcport->vha;
-       req = vha->hw->req_q_map[0];
-       rsp = vha->hw->rsp_q_map[0];
+       req = vha->hw->req_q_map[tag];
+       rsp = vha->hw->rsp_q_map[tag];
        mcp->mb[0] = MBC_ABORT_TARGET;
        mcp->out_mb = MBX_9|MBX_2|MBX_1|MBX_0;
        if (HAS_EXTENDED_IDS(vha->hw)) {
@@ -850,7 +853,7 @@ qla2x00_abort_target(struct fc_port *fcport, unsigned int l)
 }
 
 int
-qla2x00_lun_reset(struct fc_port *fcport, unsigned int l)
+qla2x00_lun_reset(struct fc_port *fcport, unsigned int l, int tag)
 {
        int rval, rval2;
        mbx_cmd_t  mc;
@@ -862,8 +865,8 @@ qla2x00_lun_reset(struct fc_port *fcport, unsigned int l)
        DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->vha->host_no));
 
        vha = fcport->vha;
-       req = vha->hw->req_q_map[0];
-       rsp = vha->hw->rsp_q_map[0];
+       req = vha->hw->req_q_map[tag];
+       rsp = vha->hw->rsp_q_map[tag];
        mcp->mb[0] = MBC_LUN_RESET;
        mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0;
        if (HAS_EXTENDED_IDS(vha->hw))
@@ -931,6 +934,8 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa,
        mcp->mb[9] = vha->vp_idx;
        mcp->out_mb = MBX_9|MBX_0;
        mcp->in_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+       if (IS_QLA81XX(vha->hw))
+               mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10;
        mcp->tov = MBX_TOV_SECONDS;
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(vha, mcp);
@@ -952,9 +957,19 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa,
                DEBUG2_3_11(printk("qla2x00_get_adapter_id(%ld): failed=%x.\n",
                    vha->host_no, rval));
        } else {
-               /*EMPTY*/
                DEBUG11(printk("qla2x00_get_adapter_id(%ld): done.\n",
                    vha->host_no));
+
+               if (IS_QLA81XX(vha->hw)) {
+                       vha->fcoe_vlan_id = mcp->mb[9] & 0xfff;
+                       vha->fcoe_fcf_idx = mcp->mb[10];
+                       vha->fcoe_vn_port_mac[5] = mcp->mb[11] >> 8;
+                       vha->fcoe_vn_port_mac[4] = mcp->mb[11] & 0xff;
+                       vha->fcoe_vn_port_mac[3] = mcp->mb[12] >> 8;
+                       vha->fcoe_vn_port_mac[2] = mcp->mb[12] & 0xff;
+                       vha->fcoe_vn_port_mac[1] = mcp->mb[13] >> 8;
+                       vha->fcoe_vn_port_mac[0] = mcp->mb[13] & 0xff;
+               }
        }
 
        return rval;
@@ -1252,7 +1267,7 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states)
 
        mcp->mb[0] = MBC_GET_FIRMWARE_STATE;
        mcp->out_mb = MBX_0;
-       mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0;
+       mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
        mcp->tov = MBX_TOV_SECONDS;
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(vha, mcp);
@@ -1261,6 +1276,8 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states)
        states[0] = mcp->mb[1];
        states[1] = mcp->mb[2];
        states[2] = mcp->mb[3];
+       states[3] = mcp->mb[4];
+       states[4] = mcp->mb[5];
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
@@ -1480,9 +1497,17 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
        dma_addr_t      lg_dma;
        uint32_t        iop[2];
        struct qla_hw_data *ha = vha->hw;
+       struct req_que *req;
+       struct rsp_que *rsp;
 
        DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
 
+       if (ql2xmultique_tag)
+               req = ha->req_q_map[0];
+       else
+               req = vha->req;
+       rsp = req->rsp;
+
        lg = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma);
        if (lg == NULL) {
                DEBUG2_3(printk("%s(%ld): failed to allocate Login IOCB.\n",
@@ -1493,6 +1518,7 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
 
        lg->entry_type = LOGINOUT_PORT_IOCB_TYPE;
        lg->entry_count = 1;
+       lg->handle = MAKE_HANDLE(req->id, lg->handle);
        lg->nport_handle = cpu_to_le16(loop_id);
        lg->control_flags = __constant_cpu_to_le16(LCF_COMMAND_PLOGI);
        if (opt & BIT_0)
@@ -1741,6 +1767,8 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
        struct logio_entry_24xx *lg;
        dma_addr_t      lg_dma;
        struct qla_hw_data *ha = vha->hw;
+       struct req_que *req;
+       struct rsp_que *rsp;
 
        DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
 
@@ -1752,8 +1780,14 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
        }
        memset(lg, 0, sizeof(struct logio_entry_24xx));
 
+       if (ql2xmaxqueues > 1)
+               req = ha->req_q_map[0];
+       else
+               req = vha->req;
+       rsp = req->rsp;
        lg->entry_type = LOGINOUT_PORT_IOCB_TYPE;
        lg->entry_count = 1;
+       lg->handle = MAKE_HANDLE(req->id, lg->handle);
        lg->nport_handle = cpu_to_le16(loop_id);
        lg->control_flags =
            __constant_cpu_to_le16(LCF_COMMAND_LOGO|LCF_IMPL_LOGO);
@@ -1864,9 +1898,6 @@ qla2x00_full_login_lip(scsi_qla_host_t *vha)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       if (IS_QLA81XX(vha->hw))
-           return QLA_SUCCESS;
-
        DEBUG11(printk("qla2x00_full_login_lip(%ld): entered.\n",
            vha->host_no));
 
@@ -2195,21 +2226,21 @@ qla24xx_get_isp_stats(scsi_qla_host_t *vha, struct link_statistics *stats,
 }
 
 int
-qla24xx_abort_command(scsi_qla_host_t *vha, srb_t *sp, struct req_que *req)
+qla24xx_abort_command(srb_t *sp)
 {
        int             rval;
-       fc_port_t       *fcport;
        unsigned long   flags = 0;
 
        struct abort_entry_24xx *abt;
        dma_addr_t      abt_dma;
        uint32_t        handle;
+       fc_port_t       *fcport = sp->fcport;
+       struct scsi_qla_host *vha = fcport->vha;
        struct qla_hw_data *ha = vha->hw;
+       struct req_que *req = vha->req;
 
        DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
 
-       fcport = sp->fcport;
-
        spin_lock_irqsave(&ha->hardware_lock, flags);
        for (handle = 1; handle < MAX_OUTSTANDING_COMMANDS; handle++) {
                if (req->outstanding_cmds[handle] == sp)
@@ -2231,6 +2262,7 @@ qla24xx_abort_command(scsi_qla_host_t *vha, srb_t *sp, struct req_que *req)
 
        abt->entry_type = ABORT_IOCB_TYPE;
        abt->entry_count = 1;
+       abt->handle = MAKE_HANDLE(req->id, abt->handle);
        abt->nport_handle = cpu_to_le16(fcport->loop_id);
        abt->handle_to_abort = handle;
        abt->port_id[0] = fcport->d_id.b.al_pa;
@@ -2272,7 +2304,7 @@ struct tsk_mgmt_cmd {
 
 static int
 __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport,
-    unsigned int l)
+    unsigned int l, int tag)
 {
        int             rval, rval2;
        struct tsk_mgmt_cmd *tsk;
@@ -2286,8 +2318,11 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport,
 
        vha = fcport->vha;
        ha = vha->hw;
-       req = ha->req_q_map[0];
-       rsp = ha->rsp_q_map[0];
+       req = vha->req;
+       if (ql2xmultique_tag)
+               rsp = ha->rsp_q_map[tag + 1];
+       else
+               rsp = req->rsp;
        tsk = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &tsk_dma);
        if (tsk == NULL) {
                DEBUG2_3(printk("%s(%ld): failed to allocate Task Management "
@@ -2298,6 +2333,7 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport,
 
        tsk->p.tsk.entry_type = TSK_MGMT_IOCB_TYPE;
        tsk->p.tsk.entry_count = 1;
+       tsk->p.tsk.handle = MAKE_HANDLE(req->id, tsk->p.tsk.handle);
        tsk->p.tsk.nport_handle = cpu_to_le16(fcport->loop_id);
        tsk->p.tsk.timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
        tsk->p.tsk.control_flags = cpu_to_le32(type);
@@ -2344,15 +2380,15 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport,
 }
 
 int
-qla24xx_abort_target(struct fc_port *fcport, unsigned int l)
+qla24xx_abort_target(struct fc_port *fcport, unsigned int l, int tag)
 {
-       return __qla24xx_issue_tmf("Target", TCF_TARGET_RESET, fcport, l);
+       return __qla24xx_issue_tmf("Target", TCF_TARGET_RESET, fcport, l, tag);
 }
 
 int
-qla24xx_lun_reset(struct fc_port *fcport, unsigned int l)
+qla24xx_lun_reset(struct fc_port *fcport, unsigned int l, int tag)
 {
-       return __qla24xx_issue_tmf("Lun", TCF_LUN_RESET, fcport, l);
+       return __qla24xx_issue_tmf("Lun", TCF_LUN_RESET, fcport, l, tag);
 }
 
 int
@@ -2446,6 +2482,8 @@ qla2x00_stop_firmware(scsi_qla_host_t *vha)
        if (rval != QLA_SUCCESS) {
                DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
                    vha->host_no, rval));
+               if (mcp->mb[0] == MBS_INVALID_COMMAND)
+                       rval = QLA_INVALID_COMMAND;
        } else {
                DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
        }
@@ -2717,8 +2755,11 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
                if (vp_idx == 0)
                        return;
 
-               if (MSB(stat) == 1)
+               if (MSB(stat) == 1) {
+                       DEBUG2(printk("scsi(%ld): Could not acquire ID for "
+                           "VP[%d].\n", vha->host_no, vp_idx));
                        return;
+               }
 
                list_for_each_entry_safe(vp, tvp, &ha->vp_list, list)
                        if (vp_idx == vp->vp_idx)
@@ -3141,6 +3182,8 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
                WRT_REG_DWORD(&reg->req_q_in, 0);
                WRT_REG_DWORD(&reg->req_q_out, 0);
        }
+       req->req_q_in = &reg->req_q_in;
+       req->req_q_out = &reg->req_q_out;
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
        rval = qla2x00_mailbox_command(vha, mcp);
@@ -3167,7 +3210,6 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
        mcp->mb[6] = MSW(MSD(rsp->dma));
        mcp->mb[7] = LSW(MSD(rsp->dma));
        mcp->mb[5] = rsp->length;
-       mcp->mb[11] = rsp->vp_idx;
        mcp->mb[14] = rsp->msix->entry;
        mcp->mb[13] = rsp->rid;
 
@@ -3179,7 +3221,7 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
        mcp->mb[8] = 0;
        /* que out ptr index */
        mcp->mb[9] = 0;
-       mcp->out_mb = MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8|MBX_7
+       mcp->out_mb = MBX_14|MBX_13|MBX_9|MBX_8|MBX_7
                        |MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
        mcp->in_mb = MBX_0;
        mcp->flags = MBX_DMA_OUT;
@@ -3384,7 +3426,7 @@ qla2x00_read_edc(scsi_qla_host_t *vha, uint16_t dev, uint16_t adr,
                DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
                    vha->host_no, rval, mcp->mb[0]));
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
        }
 
        return rval;
@@ -3428,3 +3470,141 @@ qla2x00_write_edc(scsi_qla_host_t *vha, uint16_t dev, uint16_t adr,
 
        return rval;
 }
+
+int
+qla2x00_get_xgmac_stats(scsi_qla_host_t *vha, dma_addr_t stats_dma,
+    uint16_t size_in_bytes, uint16_t *actual_size)
+{
+       int rval;
+       mbx_cmd_t mc;
+       mbx_cmd_t *mcp = &mc;
+
+       if (!IS_QLA81XX(vha->hw))
+               return QLA_FUNCTION_FAILED;
+
+       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+
+       mcp->mb[0] = MBC_GET_XGMAC_STATS;
+       mcp->mb[2] = MSW(stats_dma);
+       mcp->mb[3] = LSW(stats_dma);
+       mcp->mb[6] = MSW(MSD(stats_dma));
+       mcp->mb[7] = LSW(MSD(stats_dma));
+       mcp->mb[8] = size_in_bytes >> 2;
+       mcp->out_mb = MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
+       mcp->in_mb = MBX_2|MBX_1|MBX_0;
+       mcp->tov = MBX_TOV_SECONDS;
+       mcp->flags = 0;
+       rval = qla2x00_mailbox_command(vha, mcp);
+
+       if (rval != QLA_SUCCESS) {
+               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=0x%x "
+                   "mb[1]=0x%x mb[2]=0x%x.\n", __func__, vha->host_no, rval,
+                   mcp->mb[0], mcp->mb[1], mcp->mb[2]));
+       } else {
+               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+
+               *actual_size = mcp->mb[2] << 2;
+       }
+
+       return rval;
+}
+
+int
+qla2x00_get_dcbx_params(scsi_qla_host_t *vha, dma_addr_t tlv_dma,
+    uint16_t size)
+{
+       int rval;
+       mbx_cmd_t mc;
+       mbx_cmd_t *mcp = &mc;
+
+       if (!IS_QLA81XX(vha->hw))
+               return QLA_FUNCTION_FAILED;
+
+       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+
+       mcp->mb[0] = MBC_GET_DCBX_PARAMS;
+       mcp->mb[1] = 0;
+       mcp->mb[2] = MSW(tlv_dma);
+       mcp->mb[3] = LSW(tlv_dma);
+       mcp->mb[6] = MSW(MSD(tlv_dma));
+       mcp->mb[7] = LSW(MSD(tlv_dma));
+       mcp->mb[8] = size;
+       mcp->out_mb = MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+       mcp->in_mb = MBX_2|MBX_1|MBX_0;
+       mcp->tov = MBX_TOV_SECONDS;
+       mcp->flags = 0;
+       rval = qla2x00_mailbox_command(vha, mcp);
+
+       if (rval != QLA_SUCCESS) {
+               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=0x%x "
+                   "mb[1]=0x%x mb[2]=0x%x.\n", __func__, vha->host_no, rval,
+                   mcp->mb[0], mcp->mb[1], mcp->mb[2]));
+       } else {
+               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+       }
+
+       return rval;
+}
+
+int
+qla2x00_read_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t *data)
+{
+       int rval;
+       mbx_cmd_t mc;
+       mbx_cmd_t *mcp = &mc;
+
+       if (!IS_FWI2_CAPABLE(vha->hw))
+               return QLA_FUNCTION_FAILED;
+
+       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+
+       mcp->mb[0] = MBC_READ_RAM_EXTENDED;
+       mcp->mb[1] = LSW(risc_addr);
+       mcp->mb[8] = MSW(risc_addr);
+       mcp->out_mb = MBX_8|MBX_1|MBX_0;
+       mcp->in_mb = MBX_3|MBX_2|MBX_0;
+       mcp->tov = 30;
+       mcp->flags = 0;
+       rval = qla2x00_mailbox_command(vha, mcp);
+       if (rval != QLA_SUCCESS) {
+               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n", __func__,
+                   vha->host_no, rval, mcp->mb[0]));
+       } else {
+               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               *data = mcp->mb[3] << 16 | mcp->mb[2];
+       }
+
+       return rval;
+}
+
+int
+qla2x00_write_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t data)
+{
+       int rval;
+       mbx_cmd_t mc;
+       mbx_cmd_t *mcp = &mc;
+
+       if (!IS_FWI2_CAPABLE(vha->hw))
+                return QLA_FUNCTION_FAILED;
+
+       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+
+       mcp->mb[0] = MBC_WRITE_RAM_WORD_EXTENDED;
+       mcp->mb[1] = LSW(risc_addr);
+       mcp->mb[2] = LSW(data);
+       mcp->mb[3] = MSW(data);
+       mcp->mb[8] = MSW(risc_addr);
+       mcp->out_mb = MBX_8|MBX_3|MBX_2|MBX_1|MBX_0;
+       mcp->in_mb = MBX_0;
+       mcp->tov = 30;
+       mcp->flags = 0;
+       rval = qla2x00_mailbox_command(vha, mcp);
+       if (rval != QLA_SUCCESS) {
+               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n", __func__,
+                   vha->host_no, rval, mcp->mb[0]));
+       } else {
+               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+       }
+
+       return rval;
+}
index 51716c7e30083495ebcc59ed387fd498472ac181..650bcef08f2a4d080f5e325a7fd82766179aeb7b 100644 (file)
@@ -398,9 +398,8 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
 
        qla2x00_start_timer(vha, qla2x00_timer, WATCH_INTERVAL);
 
-       memset(vha->req_ques, 0, sizeof(vha->req_ques));
-       vha->req_ques[0] = ha->req_q_map[0]->id;
-       host->can_queue = ha->req_q_map[0]->length + 128;
+       vha->req = base_vha->req;
+       host->can_queue = base_vha->req->length + 128;
        host->this_id = 255;
        host->cmd_per_lun = 3;
        host->max_cmd_len = MAX_CMDSZ;
@@ -515,76 +514,53 @@ int qla25xx_update_req_que(struct scsi_qla_host *vha, uint8_t que, uint8_t qos)
 
 /* Delete all queues for a given vhost */
 int
-qla25xx_delete_queues(struct scsi_qla_host *vha, uint8_t que_no)
+qla25xx_delete_queues(struct scsi_qla_host *vha)
 {
        int cnt, ret = 0;
        struct req_que *req = NULL;
        struct rsp_que *rsp = NULL;
        struct qla_hw_data *ha = vha->hw;
 
-       if (que_no) {
-       /* Delete request queue */
-               req = ha->req_q_map[que_no];
+       /* Delete request queues */
+       for (cnt = 1; cnt < ha->max_req_queues; cnt++) {
+               req = ha->req_q_map[cnt];
                if (req) {
-                       rsp = req->rsp;
                        ret = qla25xx_delete_req_que(vha, req);
                        if (ret != QLA_SUCCESS) {
                                qla_printk(KERN_WARNING, ha,
-                               "Couldn't delete req que %d\n", req->id);
+                               "Couldn't delete req que %d\n",
+                               req->id);
                                return ret;
                        }
-                       /* Delete associated response queue */
-                       if (rsp) {
-                               ret = qla25xx_delete_rsp_que(vha, rsp);
-                               if (ret != QLA_SUCCESS) {
-                                       qla_printk(KERN_WARNING, ha,
-                                               "Couldn't delete rsp que %d\n",
-                                               rsp->id);
-                                       return ret;
-                               }
-                       }
                }
-       } else {  /* delete all queues of this host */
-               for (cnt = 0; cnt < QLA_MAX_HOST_QUES; cnt++) {
-                       /* Delete request queues */
-                       req = ha->req_q_map[vha->req_ques[cnt]];
-                       if (req && req->id) {
-                               rsp = req->rsp;
-                               ret = qla25xx_delete_req_que(vha, req);
-                               if (ret != QLA_SUCCESS) {
-                                       qla_printk(KERN_WARNING, ha,
-                                               "Couldn't delete req que %d\n",
-                                               vha->req_ques[cnt]);
-                                       return ret;
-                               }
-                               vha->req_ques[cnt] = ha->req_q_map[0]->id;
-                       /* Delete associated response queue */
-                               if (rsp && rsp->id) {
-                                       ret = qla25xx_delete_rsp_que(vha, rsp);
-                                       if (ret != QLA_SUCCESS) {
-                                               qla_printk(KERN_WARNING, ha,
-                                               "Couldn't delete rsp que %d\n",
-                                               rsp->id);
-                                               return ret;
-                                       }
-                               }
+       }
+
+       /* Delete response queues */
+       for (cnt = 1; cnt < ha->max_rsp_queues; cnt++) {
+               rsp = ha->rsp_q_map[cnt];
+               if (rsp) {
+                       ret = qla25xx_delete_rsp_que(vha, rsp);
+                       if (ret != QLA_SUCCESS) {
+                               qla_printk(KERN_WARNING, ha,
+                               "Couldn't delete rsp que %d\n",
+                               rsp->id);
+                               return ret;
                        }
                }
        }
-       qla_printk(KERN_INFO, ha, "Queues deleted for vport:%d\n",
-               vha->vp_idx);
        return ret;
 }
 
 int
 qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
-       uint8_t vp_idx, uint16_t rid, uint8_t rsp_que, uint8_t qos)
+       uint8_t vp_idx, uint16_t rid, int rsp_que, uint8_t qos)
 {
        int ret = 0;
        struct req_que *req = NULL;
        struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
        uint16_t que_id = 0;
        device_reg_t __iomem *reg;
+       uint32_t cnt;
 
        req = kzalloc(sizeof(struct req_que), GFP_KERNEL);
        if (req == NULL) {
@@ -604,8 +580,8 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
        }
 
        mutex_lock(&ha->vport_lock);
-       que_id = find_first_zero_bit(ha->req_qid_map, ha->max_queues);
-       if (que_id >= ha->max_queues) {
+       que_id = find_first_zero_bit(ha->req_qid_map, ha->max_req_queues);
+       if (que_id >= ha->max_req_queues) {
                mutex_unlock(&ha->vport_lock);
                qla_printk(KERN_INFO, ha, "No resources to create "
                         "additional request queue\n");
@@ -617,10 +593,10 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
        req->vp_idx = vp_idx;
        req->qos = qos;
 
-       if (ha->rsp_q_map[rsp_que]) {
+       if (rsp_que < 0)
+               req->rsp = NULL;
+       else
                req->rsp = ha->rsp_q_map[rsp_que];
-               req->rsp->req = req;
-       }
        /* Use alternate PCI bus number */
        if (MSB(req->rid))
                options |= BIT_4;
@@ -628,13 +604,16 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
        if (LSB(req->rid))
                options |= BIT_5;
        req->options = options;
+
+       for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++)
+               req->outstanding_cmds[cnt] = NULL;
+       req->current_outstanding_cmd = 1;
+
        req->ring_ptr = req->ring;
        req->ring_index = 0;
        req->cnt = req->length;
        req->id = que_id;
        reg = ISP_QUE_REG(ha, que_id);
-       req->req_q_in = &reg->isp25mq.req_q_in;
-       req->req_q_out = &reg->isp25mq.req_q_out;
        req->max_q_depth = ha->req_q_map[0]->max_q_depth;
        mutex_unlock(&ha->vport_lock);
 
@@ -654,10 +633,19 @@ que_failed:
        return 0;
 }
 
+static void qla_do_work(struct work_struct *work)
+{
+       struct rsp_que *rsp = container_of(work, struct rsp_que, q_work);
+       struct scsi_qla_host *vha;
+
+       vha = qla25xx_get_host(rsp);
+       qla24xx_process_response_queue(vha, rsp);
+}
+
 /* create response queue */
 int
 qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
-       uint8_t vp_idx, uint16_t rid)
+       uint8_t vp_idx, uint16_t rid, int req)
 {
        int ret = 0;
        struct rsp_que *rsp = NULL;
@@ -672,7 +660,7 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
                goto que_failed;
        }
 
-       rsp->length = RESPONSE_ENTRY_CNT_2300;
+       rsp->length = RESPONSE_ENTRY_CNT_MQ;
        rsp->ring = dma_alloc_coherent(&ha->pdev->dev,
                        (rsp->length + 1) * sizeof(response_t),
                        &rsp->dma, GFP_KERNEL);
@@ -683,8 +671,8 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
        }
 
        mutex_lock(&ha->vport_lock);
-       que_id = find_first_zero_bit(ha->rsp_qid_map, ha->max_queues);
-       if (que_id >= ha->max_queues) {
+       que_id = find_first_zero_bit(ha->rsp_qid_map, ha->max_rsp_queues);
+       if (que_id >= ha->max_rsp_queues) {
                mutex_unlock(&ha->vport_lock);
                qla_printk(KERN_INFO, ha, "No resources to create "
                         "additional response queue\n");
@@ -708,8 +696,6 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
        if (LSB(rsp->rid))
                options |= BIT_5;
        rsp->options = options;
-       rsp->ring_ptr = rsp->ring;
-       rsp->ring_index = 0;
        rsp->id = que_id;
        reg = ISP_QUE_REG(ha, que_id);
        rsp->rsp_q_in = &reg->isp25mq.rsp_q_in;
@@ -728,9 +714,14 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
                mutex_unlock(&ha->vport_lock);
                goto que_failed;
        }
+       if (req >= 0)
+               rsp->req = ha->req_q_map[req];
+       else
+               rsp->req = NULL;
 
        qla2x00_init_response_q_entries(rsp);
-
+       if (rsp->hw->wq)
+               INIT_WORK(&rsp->q_work, qla_do_work);
        return rsp->id;
 
 que_failed:
@@ -744,14 +735,16 @@ qla25xx_create_queues(struct scsi_qla_host *vha, uint8_t qos)
        uint16_t options = 0;
        uint8_t ret = 0;
        struct qla_hw_data *ha = vha->hw;
+       struct rsp_que *rsp;
 
        options |= BIT_1;
-       ret = qla25xx_create_rsp_que(ha, options, vha->vp_idx, 0);
+       ret = qla25xx_create_rsp_que(ha, options, vha->vp_idx, 0, -1);
        if (!ret) {
                qla_printk(KERN_WARNING, ha, "Response Que create failed\n");
                return ret;
        } else
                qla_printk(KERN_INFO, ha, "Response Que:%d created.\n", ret);
+       rsp = ha->rsp_q_map[ret];
 
        options = 0;
        if (qos & BIT_7)
@@ -759,10 +752,11 @@ qla25xx_create_queues(struct scsi_qla_host *vha, uint8_t qos)
        ret = qla25xx_create_req_que(ha, options, vha->vp_idx, 0, ret,
                                        qos & ~BIT_7);
        if (ret) {
-               vha->req_ques[0] = ret;
+               vha->req = ha->req_q_map[ret];
                qla_printk(KERN_INFO, ha, "Request Que:%d created.\n", ret);
        } else
                qla_printk(KERN_WARNING, ha, "Request Que create failed\n");
+       rsp->req = ha->req_q_map[ret];
 
        return ret;
 }
index e4fdcdad80d0b7c12c1be44b0eb75a834ef37d49..dcf011679c8bbab5de6ab3d0b0dc58af4527ec80 100644 (file)
@@ -77,6 +77,14 @@ module_param(ql2xmaxqdepth, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(ql2xmaxqdepth,
                "Maximum queue depth to report for target devices.");
 
+int ql2xqfulltracking = 1;
+module_param(ql2xqfulltracking, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql2xqfulltracking,
+               "Controls whether the driver tracks queue full status "
+               "returns and dynamically adjusts a scsi device's queue "
+               "depth.  Default is 1, perform tracking.  Set to 0 to "
+               "disable dynamic tracking and adjustment of queue depth.");
+
 int ql2xqfullrampup = 120;
 module_param(ql2xqfullrampup, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(ql2xqfullrampup,
@@ -96,6 +104,23 @@ MODULE_PARM_DESC(ql2xmaxqueues,
                "Enables MQ settings "
                "Default is 1 for single queue. Set it to number \
                        of queues in MQ mode.");
+
+int ql2xmultique_tag;
+module_param(ql2xmultique_tag, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xmultique_tag,
+               "Enables CPU affinity settings for the driver "
+               "Default is 0 for no affinity of request and response IO. "
+               "Set it to 1 to turn on the cpu affinity.");
+
+int ql2xfwloadbin;
+module_param(ql2xfwloadbin, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xfwloadbin,
+               "Option to specify location from which to load ISP firmware:\n"
+               " 2 -- load firmware via the request_firmware() (hotplug)\n"
+               "      interface.\n"
+               " 1 -- load firmware from flash.\n"
+               " 0 -- use default semantics.\n");
+
 /*
  * SCSI host template entry points
  */
@@ -187,7 +212,7 @@ static void qla2x00_sp_free_dma(srb_t *);
 /* -------------------------------------------------------------------------- */
 static int qla2x00_alloc_queues(struct qla_hw_data *ha)
 {
-       ha->req_q_map = kzalloc(sizeof(struct req_que *) * ha->max_queues,
+       ha->req_q_map = kzalloc(sizeof(struct req_que *) * ha->max_req_queues,
                                GFP_KERNEL);
        if (!ha->req_q_map) {
                qla_printk(KERN_WARNING, ha,
@@ -195,7 +220,7 @@ static int qla2x00_alloc_queues(struct qla_hw_data *ha)
                goto fail_req_map;
        }
 
-       ha->rsp_q_map = kzalloc(sizeof(struct rsp_que *) * ha->max_queues,
+       ha->rsp_q_map = kzalloc(sizeof(struct rsp_que *) * ha->max_rsp_queues,
                                GFP_KERNEL);
        if (!ha->rsp_q_map) {
                qla_printk(KERN_WARNING, ha,
@@ -213,16 +238,8 @@ fail_req_map:
        return -ENOMEM;
 }
 
-static void qla2x00_free_que(struct qla_hw_data *ha, struct req_que *req,
-       struct rsp_que *rsp)
+static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req)
 {
-       if (rsp && rsp->ring)
-               dma_free_coherent(&ha->pdev->dev,
-               (rsp->length + 1) * sizeof(response_t),
-               rsp->ring, rsp->dma);
-
-       kfree(rsp);
-       rsp = NULL;
        if (req && req->ring)
                dma_free_coherent(&ha->pdev->dev,
                (req->length + 1) * sizeof(request_t),
@@ -232,22 +249,77 @@ static void qla2x00_free_que(struct qla_hw_data *ha, struct req_que *req,
        req = NULL;
 }
 
+static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp)
+{
+       if (rsp && rsp->ring)
+               dma_free_coherent(&ha->pdev->dev,
+               (rsp->length + 1) * sizeof(response_t),
+               rsp->ring, rsp->dma);
+
+       kfree(rsp);
+       rsp = NULL;
+}
+
 static void qla2x00_free_queues(struct qla_hw_data *ha)
 {
        struct req_que *req;
        struct rsp_que *rsp;
        int cnt;
 
-       for (cnt = 0; cnt < ha->max_queues; cnt++) {
-               rsp = ha->rsp_q_map[cnt];
+       for (cnt = 0; cnt < ha->max_req_queues; cnt++) {
                req = ha->req_q_map[cnt];
-               qla2x00_free_que(ha, req, rsp);
+               qla2x00_free_req_que(ha, req);
+       }
+       kfree(ha->req_q_map);
+       ha->req_q_map = NULL;
+
+       for (cnt = 0; cnt < ha->max_rsp_queues; cnt++) {
+               rsp = ha->rsp_q_map[cnt];
+               qla2x00_free_rsp_que(ha, rsp);
        }
        kfree(ha->rsp_q_map);
        ha->rsp_q_map = NULL;
+}
 
-       kfree(ha->req_q_map);
-       ha->req_q_map = NULL;
+static int qla25xx_setup_mode(struct scsi_qla_host *vha)
+{
+       uint16_t options = 0;
+       int ques, req, ret;
+       struct qla_hw_data *ha = vha->hw;
+
+       if (ql2xmultique_tag) {
+               /* CPU affinity mode */
+               ha->wq = create_workqueue("qla2xxx_wq");
+               /* create a request queue for IO */
+               options |= BIT_7;
+               req = qla25xx_create_req_que(ha, options, 0, 0, -1,
+                       QLA_DEFAULT_QUE_QOS);
+               if (!req) {
+                       qla_printk(KERN_WARNING, ha,
+                               "Can't create request queue\n");
+                       goto fail;
+               }
+               vha->req = ha->req_q_map[req];
+               options |= BIT_1;
+               for (ques = 1; ques < ha->max_rsp_queues; ques++) {
+                       ret = qla25xx_create_rsp_que(ha, options, 0, 0, req);
+                       if (!ret) {
+                               qla_printk(KERN_WARNING, ha,
+                                       "Response Queue create failed\n");
+                               goto fail2;
+                       }
+               }
+               DEBUG2(qla_printk(KERN_INFO, ha,
+                       "CPU affinity mode enabled, no. of response"
+                       " queues:%d, no. of request queues:%d\n",
+                       ha->max_rsp_queues, ha->max_req_queues));
+       }
+       return 0;
+fail2:
+       qla25xx_delete_queues(vha);
+fail:
+       ha->mqenable = 0;
+       return 1;
 }
 
 static char *
@@ -387,7 +459,6 @@ qla2x00_get_new_sp(scsi_qla_host_t *vha, fc_port_t *fcport,
 
        sp->fcport = fcport;
        sp->cmd = cmd;
-       sp->que = ha->req_q_map[0];
        sp->flags = 0;
        CMD_SP(cmd) = (void *)sp;
        cmd->scsi_done = done;
@@ -612,7 +683,7 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *vha)
 void
 qla2x00_abort_fcport_cmds(fc_port_t *fcport)
 {
-       int cnt, que, id;
+       int cnt;
        unsigned long flags;
        srb_t *sp;
        scsi_qla_host_t *vha = fcport->vha;
@@ -620,32 +691,27 @@ qla2x00_abort_fcport_cmds(fc_port_t *fcport)
        struct req_que *req;
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
-       for (que = 0; que < QLA_MAX_HOST_QUES; que++) {
-               id = vha->req_ques[que];
-               req = ha->req_q_map[id];
-               if (!req)
+       req = vha->req;
+       for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
+               sp = req->outstanding_cmds[cnt];
+               if (!sp)
+                       continue;
+               if (sp->fcport != fcport)
                        continue;
-               for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
-                       sp = req->outstanding_cmds[cnt];
-                       if (!sp)
-                               continue;
-                       if (sp->fcport != fcport)
-                               continue;
 
-                       spin_unlock_irqrestore(&ha->hardware_lock, flags);
-                       if (ha->isp_ops->abort_command(vha, sp, req)) {
+               spin_unlock_irqrestore(&ha->hardware_lock, flags);
+               if (ha->isp_ops->abort_command(sp)) {
+                       DEBUG2(qla_printk(KERN_WARNING, ha,
+                       "Abort failed --  %lx\n",
+                       sp->cmd->serial_number));
+               } else {
+                       if (qla2x00_eh_wait_on_command(sp->cmd) !=
+                               QLA_SUCCESS)
                                DEBUG2(qla_printk(KERN_WARNING, ha,
-                               "Abort failed --  %lx\n",
+                               "Abort failed while waiting --  %lx\n",
                                sp->cmd->serial_number));
-                       } else {
-                               if (qla2x00_eh_wait_on_command(sp->cmd) !=
-                                       QLA_SUCCESS)
-                                       DEBUG2(qla_printk(KERN_WARNING, ha,
-                                       "Abort failed while waiting --  %lx\n",
-                                       sp->cmd->serial_number));
-                       }
-                       spin_lock_irqsave(&ha->hardware_lock, flags);
                }
+               spin_lock_irqsave(&ha->hardware_lock, flags);
        }
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
@@ -693,7 +759,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
        unsigned long flags;
        int wait = 0;
        struct qla_hw_data *ha = vha->hw;
-       struct req_que *req;
+       struct req_que *req = vha->req;
        srb_t *spt;
 
        qla2x00_block_error_handler(cmd);
@@ -709,7 +775,6 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
        spt = (srb_t *) CMD_SP(cmd);
        if (!spt)
                return SUCCESS;
-       req = spt->que;
 
        /* Check active list for command command. */
        spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -726,7 +791,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
                " pid=%ld.\n", __func__, vha->host_no, sp, serial));
 
                spin_unlock_irqrestore(&ha->hardware_lock, flags);
-               if (ha->isp_ops->abort_command(vha, sp, req)) {
+               if (ha->isp_ops->abort_command(sp)) {
                        DEBUG2(printk("%s(%ld): abort_command "
                        "mbx failed.\n", __func__, vha->host_no));
                        ret = FAILED;
@@ -777,7 +842,7 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *vha, unsigned int t,
                return status;
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
-       req = sp->que;
+       req = vha->req;
        for (cnt = 1; status == QLA_SUCCESS &&
                cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
                sp = req->outstanding_cmds[cnt];
@@ -820,7 +885,7 @@ static char *reset_errors[] = {
 
 static int
 __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type,
-    struct scsi_cmnd *cmd, int (*do_reset)(struct fc_port *, unsigned int))
+    struct scsi_cmnd *cmd, int (*do_reset)(struct fc_port *, unsigned int, int))
 {
        scsi_qla_host_t *vha = shost_priv(cmd->device->host);
        fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
@@ -841,7 +906,8 @@ __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type,
        if (qla2x00_wait_for_loop_ready(vha) != QLA_SUCCESS)
                goto eh_reset_failed;
        err = 2;
-       if (do_reset(fcport, cmd->device->lun) != QLA_SUCCESS)
+       if (do_reset(fcport, cmd->device->lun, cmd->request->cpu + 1)
+               != QLA_SUCCESS)
                goto eh_reset_failed;
        err = 3;
        if (qla2x00_eh_wait_for_pending_commands(vha, cmd->device->id,
@@ -996,6 +1062,9 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
                if (qla2x00_vp_abort_isp(vha))
                        goto eh_host_reset_lock;
        } else {
+               if (ha->wq)
+                       flush_workqueue(ha->wq);
+
                set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
                if (qla2x00_abort_isp(base_vha)) {
                        clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
@@ -1037,7 +1106,8 @@ qla2x00_loop_reset(scsi_qla_host_t *vha)
        struct fc_port *fcport;
        struct qla_hw_data *ha = vha->hw;
 
-       if (ha->flags.enable_lip_full_login && !vha->vp_idx) {
+       if (ha->flags.enable_lip_full_login && !vha->vp_idx &&
+           !IS_QLA81XX(ha)) {
                ret = qla2x00_full_login_lip(vha);
                if (ret != QLA_SUCCESS) {
                        DEBUG2_3(printk("%s(%ld): failed: "
@@ -1064,7 +1134,7 @@ qla2x00_loop_reset(scsi_qla_host_t *vha)
                        if (fcport->port_type != FCT_TARGET)
                                continue;
 
-                       ret = ha->isp_ops->target_reset(fcport, 0);
+                       ret = ha->isp_ops->target_reset(fcport, 0, 0);
                        if (ret != QLA_SUCCESS) {
                                DEBUG2_3(printk("%s(%ld): bus_reset failed: "
                                    "target_reset=%d d_id=%x.\n", __func__,
@@ -1088,7 +1158,7 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res)
        struct req_que *req;
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
-       for (que = 0; que < ha->max_queues; que++) {
+       for (que = 0; que < ha->max_req_queues; que++) {
                req = ha->req_q_map[que];
                if (!req)
                        continue;
@@ -1123,7 +1193,7 @@ qla2xxx_slave_configure(struct scsi_device *sdev)
        scsi_qla_host_t *vha = shost_priv(sdev->host);
        struct qla_hw_data *ha = vha->hw;
        struct fc_rport *rport = starget_to_rport(sdev->sdev_target);
-       struct req_que *req = ha->req_q_map[vha->req_ques[0]];
+       struct req_que *req = vha->req;
 
        if (sdev->tagged_supported)
                scsi_activate_tcq(sdev, req->max_q_depth);
@@ -1511,6 +1581,13 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
                ha->fw_srisc_address = RISC_START_ADDRESS_2400;
                break;
        }
+
+       /* Get adapter physical port no from interrupt pin register. */
+       pci_read_config_byte(ha->pdev, PCI_INTERRUPT_PIN, &ha->port_no);
+       if (ha->port_no & 1)
+               ha->flags.port0 = 1;
+       else
+               ha->flags.port0 = 0;
 }
 
 static int
@@ -1518,6 +1595,7 @@ qla2x00_iospace_config(struct qla_hw_data *ha)
 {
        resource_size_t pio;
        uint16_t msix;
+       int cpus;
 
        if (pci_request_selected_regions(ha->pdev, ha->bars,
            QLA2XXX_DRIVER_NAME)) {
@@ -1571,8 +1649,9 @@ skip_pio:
        }
 
        /* Determine queue resources */
-       ha->max_queues = 1;
-       if (ql2xmaxqueues <= 1 || (!IS_QLA25XX(ha) && !IS_QLA81XX(ha)))
+       ha->max_req_queues = ha->max_rsp_queues = 1;
+       if ((ql2xmaxqueues <= 1 || ql2xmultique_tag < 1) &&
+               (!IS_QLA25XX(ha) && !IS_QLA81XX(ha)))
                goto mqiobase_exit;
        ha->mqiobase = ioremap(pci_resource_start(ha->pdev, 3),
                        pci_resource_len(ha->pdev, 3));
@@ -1582,18 +1661,24 @@ skip_pio:
                ha->msix_count = msix;
                /* Max queues are bounded by available msix vectors */
                /* queue 0 uses two msix vectors */
-               if (ha->msix_count - 1 < ql2xmaxqueues)
-                       ha->max_queues = ha->msix_count - 1;
-               else if (ql2xmaxqueues > QLA_MQ_SIZE)
-                       ha->max_queues = QLA_MQ_SIZE;
-               else
-                       ha->max_queues = ql2xmaxqueues;
+               if (ql2xmultique_tag) {
+                       cpus = num_online_cpus();
+                       ha->max_rsp_queues = (ha->msix_count - 1 - cpus) ?
+                               (cpus + 1) : (ha->msix_count - 1);
+                       ha->max_req_queues = 2;
+               } else if (ql2xmaxqueues > 1) {
+                       ha->max_req_queues = ql2xmaxqueues > QLA_MQ_SIZE ?
+                                               QLA_MQ_SIZE : ql2xmaxqueues;
+                       DEBUG2(qla_printk(KERN_INFO, ha, "QoS mode set, max no"
+                       " of request queues:%d\n", ha->max_req_queues));
+               }
                qla_printk(KERN_INFO, ha,
                        "MSI-X vector count: %d\n", msix);
-       }
+       } else
+               qla_printk(KERN_INFO, ha, "BAR 3 not enabled\n");
 
 mqiobase_exit:
-       ha->msix_count = ha->max_queues + 1;
+       ha->msix_count = ha->max_rsp_queues + 1;
        return (0);
 
 iospace_error_exit:
@@ -1605,6 +1690,9 @@ qla2xxx_scan_start(struct Scsi_Host *shost)
 {
        scsi_qla_host_t *vha = shost_priv(shost);
 
+       if (vha->hw->flags.running_gold_fw)
+               return;
+
        set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
        set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
        set_bit(RSCN_UPDATE, &vha->dpc_flags);
@@ -1768,6 +1856,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
                ha->gid_list_info_size = 8;
                ha->optrom_size = OPTROM_SIZE_81XX;
+               ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX;
                ha->isp_ops = &qla81xx_isp_ops;
                ha->flash_conf_off = FARX_ACCESS_FLASH_CONF_81XX;
                ha->flash_data_off = FARX_ACCESS_FLASH_DATA_81XX;
@@ -1803,14 +1892,15 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
                ret = -ENOMEM;
                qla2x00_mem_free(ha);
-               qla2x00_free_que(ha, req, rsp);
+               qla2x00_free_req_que(ha, req);
+               qla2x00_free_rsp_que(ha, rsp);
                goto probe_hw_failed;
        }
 
        pci_set_drvdata(pdev, base_vha);
 
        host = base_vha->host;
-       base_vha->req_ques[0] = req->id;
+       base_vha->req = req;
        host->can_queue = req->length + 128;
        if (IS_QLA2XXX_MIDTYPE(ha))
                base_vha->mgmt_svr_loop_id = 10 + base_vha->vp_idx;
@@ -1841,7 +1931,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        }
        ha->rsp_q_map[0] = rsp;
        ha->req_q_map[0] = req;
-
+       rsp->req = req;
+       req->rsp = rsp;
+       set_bit(0, ha->req_qid_map);
+       set_bit(0, ha->rsp_qid_map);
        /* FWI2-capable only. */
        req->req_q_in = &ha->iobase->isp24.req_q_in;
        req->req_q_out = &ha->iobase->isp24.req_q_out;
@@ -1866,6 +1959,15 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                goto probe_failed;
        }
 
+       if (ha->mqenable)
+               if (qla25xx_setup_mode(base_vha))
+                       qla_printk(KERN_WARNING, ha,
+                               "Can't create queues, falling back to single"
+                               " queue mode\n");
+
+       if (ha->flags.running_gold_fw)
+               goto skip_dpc;
+
        /*
         * Startup the kernel thread for this host adapter
         */
@@ -1878,6 +1980,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                goto probe_failed;
        }
 
+skip_dpc:
        list_add_tail(&base_vha->list, &ha->vp_list);
        base_vha->host->irq = ha->pdev->irq;
 
@@ -1917,8 +2020,9 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        return 0;
 
 probe_init_failed:
-       qla2x00_free_que(ha, req, rsp);
-       ha->max_queues = 0;
+       qla2x00_free_req_que(ha, req);
+       qla2x00_free_rsp_que(ha, rsp);
+       ha->max_req_queues = ha->max_rsp_queues = 0;
 
 probe_failed:
        if (base_vha->timer_active)
@@ -1976,6 +2080,13 @@ qla2x00_remove_one(struct pci_dev *pdev)
 
        base_vha->flags.online = 0;
 
+       /* Flush the work queue and remove it */
+       if (ha->wq) {
+               flush_workqueue(ha->wq);
+               destroy_workqueue(ha->wq);
+               ha->wq = NULL;
+       }
+
        /* Kill the kernel thread for this host */
        if (ha->dpc_thread) {
                struct task_struct *t = ha->dpc_thread;
@@ -2017,6 +2128,8 @@ qla2x00_free_device(scsi_qla_host_t *vha)
 {
        struct qla_hw_data *ha = vha->hw;
 
+       qla25xx_delete_queues(vha);
+
        if (ha->flags.fce_enabled)
                qla2x00_disable_fce_trace(vha, NULL, NULL);
 
@@ -2329,6 +2442,14 @@ qla2x00_mem_free(struct qla_hw_data *ha)
                vfree(ha->fw_dump);
        }
 
+       if (ha->dcbx_tlv)
+               dma_free_coherent(&ha->pdev->dev, DCBX_TLV_DATA_SIZE,
+                   ha->dcbx_tlv, ha->dcbx_tlv_dma);
+
+       if (ha->xgmac_data)
+               dma_free_coherent(&ha->pdev->dev, XGMAC_DATA_SIZE,
+                   ha->xgmac_data, ha->xgmac_data_dma);
+
        if (ha->sns_cmd)
                dma_free_coherent(&ha->pdev->dev, sizeof(struct sns_cmd_pkt),
                ha->sns_cmd, ha->sns_cmd_dma);
@@ -2412,6 +2533,8 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
        INIT_LIST_HEAD(&vha->work_list);
        INIT_LIST_HEAD(&vha->list);
 
+       spin_lock_init(&vha->work_lock);
+
        sprintf(vha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, vha->host_no);
        return vha;
 
@@ -2420,13 +2543,11 @@ fail:
 }
 
 static struct qla_work_evt *
-qla2x00_alloc_work(struct scsi_qla_host *vha, enum qla_work_type type,
-    int locked)
+qla2x00_alloc_work(struct scsi_qla_host *vha, enum qla_work_type type)
 {
        struct qla_work_evt *e;
 
-       e = kzalloc(sizeof(struct qla_work_evt), locked ? GFP_ATOMIC:
-           GFP_KERNEL);
+       e = kzalloc(sizeof(struct qla_work_evt), GFP_ATOMIC);
        if (!e)
                return NULL;
 
@@ -2437,17 +2558,15 @@ qla2x00_alloc_work(struct scsi_qla_host *vha, enum qla_work_type type,
 }
 
 static int
-qla2x00_post_work(struct scsi_qla_host *vha, struct qla_work_evt *e, int locked)
+qla2x00_post_work(struct scsi_qla_host *vha, struct qla_work_evt *e)
 {
-       unsigned long uninitialized_var(flags);
-       struct qla_hw_data *ha = vha->hw;
+       unsigned long flags;
 
-       if (!locked)
-               spin_lock_irqsave(&ha->hardware_lock, flags);
+       spin_lock_irqsave(&vha->work_lock, flags);
        list_add_tail(&e->list, &vha->work_list);
+       spin_unlock_irqrestore(&vha->work_lock, flags);
        qla2xxx_wake_dpc(vha);
-       if (!locked)
-               spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
        return QLA_SUCCESS;
 }
 
@@ -2457,13 +2576,13 @@ qla2x00_post_aen_work(struct scsi_qla_host *vha, enum fc_host_event_code code,
 {
        struct qla_work_evt *e;
 
-       e = qla2x00_alloc_work(vha, QLA_EVT_AEN, 1);
+       e = qla2x00_alloc_work(vha, QLA_EVT_AEN);
        if (!e)
                return QLA_FUNCTION_FAILED;
 
        e->u.aen.code = code;
        e->u.aen.data = data;
-       return qla2x00_post_work(vha, e, 1);
+       return qla2x00_post_work(vha, e);
 }
 
 int
@@ -2471,25 +2590,27 @@ qla2x00_post_idc_ack_work(struct scsi_qla_host *vha, uint16_t *mb)
 {
        struct qla_work_evt *e;
 
-       e = qla2x00_alloc_work(vha, QLA_EVT_IDC_ACK, 1);
+       e = qla2x00_alloc_work(vha, QLA_EVT_IDC_ACK);
        if (!e)
                return QLA_FUNCTION_FAILED;
 
        memcpy(e->u.idc_ack.mb, mb, QLA_IDC_ACK_REGS * sizeof(uint16_t));
-       return qla2x00_post_work(vha, e, 1);
+       return qla2x00_post_work(vha, e);
 }
 
 static void
 qla2x00_do_work(struct scsi_qla_host *vha)
 {
-       struct qla_work_evt *e;
-       struct qla_hw_data *ha = vha->hw;
+       struct qla_work_evt *e, *tmp;
+       unsigned long flags;
+       LIST_HEAD(work);
 
-       spin_lock_irq(&ha->hardware_lock);
-       while (!list_empty(&vha->work_list)) {
-               e = list_entry(vha->work_list.next, struct qla_work_evt, list);
+       spin_lock_irqsave(&vha->work_lock, flags);
+       list_splice_init(&vha->work_list, &work);
+       spin_unlock_irqrestore(&vha->work_lock, flags);
+
+       list_for_each_entry_safe(e, tmp, &work, list) {
                list_del_init(&e->list);
-               spin_unlock_irq(&ha->hardware_lock);
 
                switch (e->type) {
                case QLA_EVT_AEN:
@@ -2502,10 +2623,9 @@ qla2x00_do_work(struct scsi_qla_host *vha)
                }
                if (e->flags & QLA_EVT_FLAG_FREE)
                        kfree(e);
-               spin_lock_irq(&ha->hardware_lock);
        }
-       spin_unlock_irq(&ha->hardware_lock);
 }
+
 /* Relogins all the fcports of a vport
  * Context: dpc thread
  */
index 152ecfc26cd201e4ad0b304708e2962a7619afa2..6260505dceb5ff20fc00e8305734453c08872a38 100644 (file)
@@ -219,8 +219,8 @@ qla2x00_write_nvram_word(struct qla_hw_data *ha, uint32_t addr, uint16_t data)
        wait_cnt = NVR_WAIT_CNT;
        do {
                if (!--wait_cnt) {
-                       DEBUG9_10(printk("%s(%ld): NVRAM didn't go ready...\n",
-                           __func__, vha->host_no));
+                       DEBUG9_10(qla_printk(KERN_WARNING, ha,
+                           "NVRAM didn't go ready...\n"));
                        break;
                }
                NVRAM_DELAY();
@@ -349,7 +349,7 @@ qla2x00_clear_nvram_protection(struct qla_hw_data *ha)
                wait_cnt = NVR_WAIT_CNT;
                do {
                        if (!--wait_cnt) {
-                               DEBUG9_10(qla_printk(
+                               DEBUG9_10(qla_printk(KERN_WARNING, ha,
                                    "NVRAM didn't go ready...\n"));
                                break;
                        }
@@ -408,7 +408,8 @@ qla2x00_set_nvram_protection(struct qla_hw_data *ha, int stat)
        wait_cnt = NVR_WAIT_CNT;
        do {
                if (!--wait_cnt) {
-                       DEBUG9_10(qla_printk("NVRAM didn't go ready...\n"));
+                       DEBUG9_10(qla_printk(KERN_WARNING, ha,
+                           "NVRAM didn't go ready...\n"));
                        break;
                }
                NVRAM_DELAY();
@@ -701,32 +702,35 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
                        break;
                case FLT_REG_VPD_0:
                        ha->flt_region_vpd_nvram = start;
-                       if (!(PCI_FUNC(ha->pdev->devfn) & 1))
+                       if (ha->flags.port0)
                                ha->flt_region_vpd = start;
                        break;
                case FLT_REG_VPD_1:
-                       if (PCI_FUNC(ha->pdev->devfn) & 1)
+                       if (!ha->flags.port0)
                                ha->flt_region_vpd = start;
                        break;
                case FLT_REG_NVRAM_0:
-                       if (!(PCI_FUNC(ha->pdev->devfn) & 1))
+                       if (ha->flags.port0)
                                ha->flt_region_nvram = start;
                        break;
                case FLT_REG_NVRAM_1:
-                       if (PCI_FUNC(ha->pdev->devfn) & 1)
+                       if (!ha->flags.port0)
                                ha->flt_region_nvram = start;
                        break;
                case FLT_REG_FDT:
                        ha->flt_region_fdt = start;
                        break;
                case FLT_REG_NPIV_CONF_0:
-                       if (!(PCI_FUNC(ha->pdev->devfn) & 1))
+                       if (ha->flags.port0)
                                ha->flt_region_npiv_conf = start;
                        break;
                case FLT_REG_NPIV_CONF_1:
-                       if (PCI_FUNC(ha->pdev->devfn) & 1)
+                       if (!ha->flags.port0)
                                ha->flt_region_npiv_conf = start;
                        break;
+               case FLT_REG_GOLD_FW:
+                       ha->flt_region_gold_fw = start;
+                       break;
                }
        }
        goto done;
@@ -744,12 +748,12 @@ no_flash_data:
        ha->flt_region_fw = def_fw[def];
        ha->flt_region_boot = def_boot[def];
        ha->flt_region_vpd_nvram = def_vpd_nvram[def];
-       ha->flt_region_vpd = !(PCI_FUNC(ha->pdev->devfn) & 1) ?
+       ha->flt_region_vpd = ha->flags.port0 ?
            def_vpd0[def]: def_vpd1[def];
-       ha->flt_region_nvram = !(PCI_FUNC(ha->pdev->devfn) & 1) ?
+       ha->flt_region_nvram = ha->flags.port0 ?
            def_nvram0[def]: def_nvram1[def];
        ha->flt_region_fdt = def_fdt[def];
-       ha->flt_region_npiv_conf = !(PCI_FUNC(ha->pdev->devfn) & 1) ?
+       ha->flt_region_npiv_conf = ha->flags.port0 ?
            def_npiv_conf0[def]: def_npiv_conf1[def];
 done:
        DEBUG2(qla_printk(KERN_DEBUG, ha, "FLT[%s]: boot=0x%x fw=0x%x "
@@ -924,6 +928,8 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha)
                struct fc_vport_identifiers vid;
                struct fc_vport *vport;
 
+               memcpy(&ha->npiv_info[i], entry, sizeof(struct qla_npiv_entry));
+
                flags = le16_to_cpu(entry->flags);
                if (flags == 0xffff)
                        continue;
@@ -937,9 +943,7 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha)
                vid.port_name = wwn_to_u64(entry->port_name);
                vid.node_name = wwn_to_u64(entry->node_name);
 
-               memcpy(&ha->npiv_info[i], entry, sizeof(struct qla_npiv_entry));
-
-               DEBUG2(qla_printk(KERN_DEBUG, ha, "NPIV[%02x]: wwpn=%llx "
+               DEBUG2(qla_printk(KERN_INFO, ha, "NPIV[%02x]: wwpn=%llx "
                        "wwnn=%llx vf_id=0x%x Q_qos=0x%x F_qos=0x%x.\n", cnt,
                        vid.port_name, vid.node_name, le16_to_cpu(entry->vf_id),
                        entry->q_qos, entry->f_qos));
@@ -955,7 +959,6 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha)
        }
 done:
        kfree(data);
-       ha->npiv_info = NULL;
 }
 
 static int
@@ -1079,8 +1082,9 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
                                    0xff0000) | ((fdata >> 16) & 0xff));
                        ret = qla24xx_erase_sector(vha, fdata);
                        if (ret != QLA_SUCCESS) {
-                               DEBUG9(qla_printk("Unable to erase sector: "
-                                   "address=%x.\n", faddr));
+                               DEBUG9(qla_printk(KERN_WARNING, ha,
+                                   "Unable to erase sector: address=%x.\n",
+                                   faddr));
                                break;
                        }
                }
@@ -1240,8 +1244,9 @@ qla24xx_write_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr,
                ret = qla24xx_write_flash_dword(ha,
                    nvram_data_addr(ha, naddr), cpu_to_le32(*dwptr));
                if (ret != QLA_SUCCESS) {
-                       DEBUG9(qla_printk("Unable to program nvram address=%x "
-                           "data=%x.\n", naddr, *dwptr));
+                       DEBUG9(qla_printk(KERN_WARNING, ha,
+                           "Unable to program nvram address=%x data=%x.\n",
+                           naddr, *dwptr));
                        break;
                }
        }
index 19d1afc3a34345fba4daa04f5c3f08959db5b891..b63feaf43126bd27f35c951453265c9e27c896bf 100644 (file)
@@ -7,7 +7,7 @@
 /*
  * Driver version
  */
-#define QLA2XXX_VERSION      "8.03.01-k1"
+#define QLA2XXX_VERSION      "8.03.01-k3"
 
 #define QLA_DRIVER_MAJOR_VER   8
 #define QLA_DRIVER_MINOR_VER   3
index 166417a6afbab0ceb2a30dec46a1cfddeb02a5a1..2de5f3ad640b2da78eba5401454c8415f44841e4 100644 (file)
@@ -1225,8 +1225,8 @@ EXPORT_SYMBOL(__scsi_device_lookup_by_target);
  * @starget:   SCSI target pointer
  * @lun:       SCSI Logical Unit Number
  *
- * Description: Looks up the scsi_device with the specified @channel, @id, @lun
- * for a given host.  The returned scsi_device has an additional reference that
+ * Description: Looks up the scsi_device with the specified @lun for a given
+ * @starget.  The returned scsi_device has an additional reference that
  * needs to be released with scsi_device_put once you're done with it.
  **/
 struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *starget,
index 213123b0486b74a985492715b1c79dde0321682f..41a21772df1289525ad8859608d1d54c73461e76 100644 (file)
@@ -887,7 +887,7 @@ static int resp_start_stop(struct scsi_cmnd * scp,
 static sector_t get_sdebug_capacity(void)
 {
        if (scsi_debug_virtual_gb > 0)
-               return 2048 * 1024 * scsi_debug_virtual_gb;
+               return 2048 * 1024 * (sector_t)scsi_debug_virtual_gb;
        else
                return sdebug_store_sectors;
 }
index 0c2c73be197469289e17defb2bebb28febc4814e..a1689353d7fd715cf91776e9b290381795876477 100644 (file)
@@ -641,9 +641,9 @@ EXPORT_SYMBOL(scsi_eh_prep_cmnd);
 /**
  * scsi_eh_restore_cmnd  - Restore a scsi command info as part of error recory
  * @scmd:       SCSI command structure to restore
- * @ses:        saved information from a coresponding call to scsi_prep_eh_cmnd
+ * @ses:        saved information from a coresponding call to scsi_eh_prep_cmnd
  *
- * Undo any damage done by above scsi_prep_eh_cmnd().
+ * Undo any damage done by above scsi_eh_prep_cmnd().
  */
 void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses)
 {
@@ -1451,28 +1451,21 @@ static void eh_lock_door_done(struct request *req, int uptodate)
  * @sdev:      SCSI device to prevent medium removal
  *
  * Locking:
- *     We must be called from process context; scsi_allocate_request()
- *     may sleep.
+ *     We must be called from process context.
  *
  * Notes:
  *     We queue up an asynchronous "ALLOW MEDIUM REMOVAL" request on the
  *     head of the devices request queue, and continue.
- *
- * Bugs:
- *     scsi_allocate_request() may sleep waiting for existing requests to
- *     be processed.  However, since we haven't kicked off any request
- *     processing for this host, this may deadlock.
- *
- *     If scsi_allocate_request() fails for what ever reason, we
- *     completely forget to lock the door.
  */
 static void scsi_eh_lock_door(struct scsi_device *sdev)
 {
        struct request *req;
 
+       /*
+        * blk_get_request with GFP_KERNEL (__GFP_WAIT) sleeps until a
+        * request becomes available
+        */
        req = blk_get_request(sdev->request_queue, READ, GFP_KERNEL);
-       if (!req)
-               return;
 
        req->cmd[0] = ALLOW_MEDIUM_REMOVAL;
        req->cmd[1] = 0;
index dd3f9d2b99fd05b7834e0abbb7e2cbe23e12d462..30f3275e119ed57473f1fd4e91270d38538eb025 100644 (file)
@@ -2412,20 +2412,18 @@ int
 scsi_internal_device_unblock(struct scsi_device *sdev)
 {
        struct request_queue *q = sdev->request_queue; 
-       int err;
        unsigned long flags;
        
        /* 
         * Try to transition the scsi device to SDEV_RUNNING
         * and goose the device queue if successful.  
         */
-       err = scsi_device_set_state(sdev, SDEV_RUNNING);
-       if (err) {
-               err = scsi_device_set_state(sdev, SDEV_CREATED);
-
-               if (err)
-                       return err;
-       }
+       if (sdev->sdev_state == SDEV_BLOCK)
+               sdev->sdev_state = SDEV_RUNNING;
+       else if (sdev->sdev_state == SDEV_CREATED_BLOCK)
+               sdev->sdev_state = SDEV_CREATED;
+       else
+               return -EINVAL;
 
        spin_lock_irqsave(q->queue_lock, flags);
        blk_start_queue(q);
index e2b50d8f57a86c686b932e2e6ae7db35001ff279..c44783801402083b7dbd610df35f8990eb090ef9 100644 (file)
@@ -115,12 +115,12 @@ MODULE_PARM_DESC(max_report_luns,
                 "REPORT LUNS maximum number of LUNS received (should be"
                 " between 1 and 16384)");
 
-static unsigned int scsi_inq_timeout = SCSI_TIMEOUT/HZ+3;
+static unsigned int scsi_inq_timeout = SCSI_TIMEOUT/HZ + 18;
 
 module_param_named(inq_timeout, scsi_inq_timeout, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(inq_timeout, 
                 "Timeout (in seconds) waiting for devices to answer INQUIRY."
-                " Default is 5. Some non-compliant devices need more.");
+                " Default is 20. Some devices may need more; most need less.");
 
 /* This lock protects only this list */
 static DEFINE_SPINLOCK(async_scan_lock);
index 0a2ce7b6325cdbf13d5aceda17add03898567f24..f3e664628d7ae273d6e97c2f794d990b7ea9dcfd 100644 (file)
@@ -37,7 +37,6 @@
 #define ISCSI_TRANSPORT_VERSION "2.0-870"
 
 struct iscsi_internal {
-       int daemon_pid;
        struct scsi_transport_template t;
        struct iscsi_transport *iscsi_transport;
        struct list_head list;
@@ -938,23 +937,9 @@ iscsi_if_transport_lookup(struct iscsi_transport *tt)
 }
 
 static int
-iscsi_broadcast_skb(struct sk_buff *skb, gfp_t gfp)
+iscsi_multicast_skb(struct sk_buff *skb, uint32_t group, gfp_t gfp)
 {
-       return netlink_broadcast(nls, skb, 0, 1, gfp);
-}
-
-static int
-iscsi_unicast_skb(struct sk_buff *skb, int pid)
-{
-       int rc;
-
-       rc = netlink_unicast(nls, skb, pid, MSG_DONTWAIT);
-       if (rc < 0) {
-               printk(KERN_ERR "iscsi: can not unicast skb (%d)\n", rc);
-               return rc;
-       }
-
-       return 0;
+       return nlmsg_multicast(nls, skb, 0, group, gfp);
 }
 
 int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
@@ -980,7 +965,7 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
                return -ENOMEM;
        }
 
-       nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);
+       nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
        ev = NLMSG_DATA(nlh);
        memset(ev, 0, sizeof(*ev));
        ev->transport_handle = iscsi_handle(conn->transport);
@@ -991,10 +976,45 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
        memcpy(pdu, hdr, sizeof(struct iscsi_hdr));
        memcpy(pdu + sizeof(struct iscsi_hdr), data, data_size);
 
-       return iscsi_unicast_skb(skb, priv->daemon_pid);
+       return iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC);
 }
 EXPORT_SYMBOL_GPL(iscsi_recv_pdu);
 
+int iscsi_offload_mesg(struct Scsi_Host *shost,
+                      struct iscsi_transport *transport, uint32_t type,
+                      char *data, uint16_t data_size)
+{
+       struct nlmsghdr *nlh;
+       struct sk_buff *skb;
+       struct iscsi_uevent *ev;
+       int len = NLMSG_SPACE(sizeof(*ev) + data_size);
+
+       skb = alloc_skb(len, GFP_NOIO);
+       if (!skb) {
+               printk(KERN_ERR "can not deliver iscsi offload message:OOM\n");
+               return -ENOMEM;
+       }
+
+       nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
+       ev = NLMSG_DATA(nlh);
+       memset(ev, 0, sizeof(*ev));
+       ev->type = type;
+       ev->transport_handle = iscsi_handle(transport);
+       switch (type) {
+       case ISCSI_KEVENT_PATH_REQ:
+               ev->r.req_path.host_no = shost->host_no;
+               break;
+       case ISCSI_KEVENT_IF_DOWN:
+               ev->r.notify_if_down.host_no = shost->host_no;
+               break;
+       }
+
+       memcpy((char *)ev + sizeof(*ev), data, data_size);
+
+       return iscsi_multicast_skb(skb, ISCSI_NL_GRP_UIP, GFP_NOIO);
+}
+EXPORT_SYMBOL_GPL(iscsi_offload_mesg);
+
 void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error)
 {
        struct nlmsghdr *nlh;
@@ -1014,7 +1034,7 @@ void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error)
                return;
        }
 
-       nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);
+       nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
        ev = NLMSG_DATA(nlh);
        ev->transport_handle = iscsi_handle(conn->transport);
        ev->type = ISCSI_KEVENT_CONN_ERROR;
@@ -1022,7 +1042,7 @@ void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error)
        ev->r.connerror.cid = conn->cid;
        ev->r.connerror.sid = iscsi_conn_get_sid(conn);
 
-       iscsi_broadcast_skb(skb, GFP_ATOMIC);
+       iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC);
 
        iscsi_cls_conn_printk(KERN_INFO, conn, "detected conn error (%d)\n",
                              error);
@@ -1030,8 +1050,8 @@ void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error)
 EXPORT_SYMBOL_GPL(iscsi_conn_error_event);
 
 static int
-iscsi_if_send_reply(int pid, int seq, int type, int done, int multi,
-                     void *payload, int size)
+iscsi_if_send_reply(uint32_t group, int seq, int type, int done, int multi,
+                   void *payload, int size)
 {
        struct sk_buff  *skb;
        struct nlmsghdr *nlh;
@@ -1045,10 +1065,10 @@ iscsi_if_send_reply(int pid, int seq, int type, int done, int multi,
                return -ENOMEM;
        }
 
-       nlh = __nlmsg_put(skb, pid, seq, t, (len - sizeof(*nlh)), 0);
+       nlh = __nlmsg_put(skb, 0, 0, t, (len - sizeof(*nlh)), 0);
        nlh->nlmsg_flags = flags;
        memcpy(NLMSG_DATA(nlh), payload, size);
-       return iscsi_unicast_skb(skb, pid);
+       return iscsi_multicast_skb(skb, group, GFP_ATOMIC);
 }
 
 static int
@@ -1085,7 +1105,7 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
                        return -ENOMEM;
                }
 
-               nlhstat = __nlmsg_put(skbstat, priv->daemon_pid, 0, 0,
+               nlhstat = __nlmsg_put(skbstat, 0, 0, 0,
                                      (len - sizeof(*nlhstat)), 0);
                evstat = NLMSG_DATA(nlhstat);
                memset(evstat, 0, sizeof(*evstat));
@@ -1109,7 +1129,8 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
                skb_trim(skbstat, NLMSG_ALIGN(actual_size));
                nlhstat->nlmsg_len = actual_size;
 
-               err = iscsi_unicast_skb(skbstat, priv->daemon_pid);
+               err = iscsi_multicast_skb(skbstat, ISCSI_NL_GRP_ISCSID,
+                                         GFP_ATOMIC);
        } while (err < 0 && err != -ECONNREFUSED);
 
        return err;
@@ -1143,7 +1164,7 @@ int iscsi_session_event(struct iscsi_cls_session *session,
                return -ENOMEM;
        }
 
-       nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);
+       nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
        ev = NLMSG_DATA(nlh);
        ev->transport_handle = iscsi_handle(session->transport);
 
@@ -1172,7 +1193,7 @@ int iscsi_session_event(struct iscsi_cls_session *session,
         * this will occur if the daemon is not up, so we just warn
         * the user and when the daemon is restarted it will handle it
         */
-       rc = iscsi_broadcast_skb(skb, GFP_KERNEL);
+       rc = iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_KERNEL);
        if (rc == -ESRCH)
                iscsi_cls_session_printk(KERN_ERR, session,
                                         "Cannot notify userspace of session "
@@ -1268,26 +1289,54 @@ iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev)
        return err;
 }
 
+static int iscsi_if_ep_connect(struct iscsi_transport *transport,
+                              struct iscsi_uevent *ev, int msg_type)
+{
+       struct iscsi_endpoint *ep;
+       struct sockaddr *dst_addr;
+       struct Scsi_Host *shost = NULL;
+       int non_blocking, err = 0;
+
+       if (!transport->ep_connect)
+               return -EINVAL;
+
+       if (msg_type == ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST) {
+               shost = scsi_host_lookup(ev->u.ep_connect_through_host.host_no);
+               if (!shost) {
+                       printk(KERN_ERR "ep connect failed. Could not find "
+                              "host no %u\n",
+                              ev->u.ep_connect_through_host.host_no);
+                       return -ENODEV;
+               }
+               non_blocking = ev->u.ep_connect_through_host.non_blocking;
+       } else
+               non_blocking = ev->u.ep_connect.non_blocking;
+
+       dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));
+       ep = transport->ep_connect(shost, dst_addr, non_blocking);
+       if (IS_ERR(ep)) {
+               err = PTR_ERR(ep);
+               goto release_host;
+       }
+
+       ev->r.ep_connect_ret.handle = ep->id;
+release_host:
+       if (shost)
+               scsi_host_put(shost);
+       return err;
+}
+
 static int
 iscsi_if_transport_ep(struct iscsi_transport *transport,
                      struct iscsi_uevent *ev, int msg_type)
 {
        struct iscsi_endpoint *ep;
-       struct sockaddr *dst_addr;
        int rc = 0;
 
        switch (msg_type) {
+       case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST:
        case ISCSI_UEVENT_TRANSPORT_EP_CONNECT:
-               if (!transport->ep_connect)
-                       return -EINVAL;
-
-               dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));
-               ep = transport->ep_connect(dst_addr,
-                                          ev->u.ep_connect.non_blocking);
-               if (IS_ERR(ep))
-                       return PTR_ERR(ep);
-
-               ev->r.ep_connect_ret.handle = ep->id;
+               rc = iscsi_if_ep_connect(transport, ev, msg_type);
                break;
        case ISCSI_UEVENT_TRANSPORT_EP_POLL:
                if (!transport->ep_poll)
@@ -1365,7 +1414,31 @@ iscsi_set_host_param(struct iscsi_transport *transport,
 }
 
 static int
-iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+iscsi_set_path(struct iscsi_transport *transport, struct iscsi_uevent *ev)
+{
+       struct Scsi_Host *shost;
+       struct iscsi_path *params;
+       int err;
+
+       if (!transport->set_path)
+               return -ENOSYS;
+
+       shost = scsi_host_lookup(ev->u.set_path.host_no);
+       if (!shost) {
+               printk(KERN_ERR "set path could not find host no %u\n",
+                      ev->u.set_path.host_no);
+               return -ENODEV;
+       }
+
+       params = (struct iscsi_path *)((char *)ev + sizeof(*ev));
+       err = transport->set_path(shost, params);
+
+       scsi_host_put(shost);
+       return err;
+}
+
+static int
+iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
 {
        int err = 0;
        struct iscsi_uevent *ev = NLMSG_DATA(nlh);
@@ -1375,6 +1448,11 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        struct iscsi_cls_conn *conn;
        struct iscsi_endpoint *ep = NULL;
 
+       if (nlh->nlmsg_type == ISCSI_UEVENT_PATH_UPDATE)
+               *group = ISCSI_NL_GRP_UIP;
+       else
+               *group = ISCSI_NL_GRP_ISCSID;
+
        priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle));
        if (!priv)
                return -EINVAL;
@@ -1383,8 +1461,6 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        if (!try_module_get(transport->owner))
                return -EINVAL;
 
-       priv->daemon_pid = NETLINK_CREDS(skb)->pid;
-
        switch (nlh->nlmsg_type) {
        case ISCSI_UEVENT_CREATE_SESSION:
                err = iscsi_if_create_session(priv, ep, ev,
@@ -1469,6 +1545,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        case ISCSI_UEVENT_TRANSPORT_EP_CONNECT:
        case ISCSI_UEVENT_TRANSPORT_EP_POLL:
        case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
+       case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST:
                err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type);
                break;
        case ISCSI_UEVENT_TGT_DSCVR:
@@ -1477,6 +1554,9 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        case ISCSI_UEVENT_SET_HOST_PARAM:
                err = iscsi_set_host_param(transport, ev);
                break;
+       case ISCSI_UEVENT_PATH_UPDATE:
+               err = iscsi_set_path(transport, ev);
+               break;
        default:
                err = -ENOSYS;
                break;
@@ -1499,6 +1579,7 @@ iscsi_if_rx(struct sk_buff *skb)
                uint32_t rlen;
                struct nlmsghdr *nlh;
                struct iscsi_uevent *ev;
+               uint32_t group;
 
                nlh = nlmsg_hdr(skb);
                if (nlh->nlmsg_len < sizeof(*nlh) ||
@@ -1511,7 +1592,7 @@ iscsi_if_rx(struct sk_buff *skb)
                if (rlen > skb->len)
                        rlen = skb->len;
 
-               err = iscsi_if_recv_msg(skb, nlh);
+               err = iscsi_if_recv_msg(skb, nlh, &group);
                if (err) {
                        ev->type = ISCSI_KEVENT_IF_ERROR;
                        ev->iferror = err;
@@ -1525,8 +1606,7 @@ iscsi_if_rx(struct sk_buff *skb)
                         */
                        if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
                                break;
-                       err = iscsi_if_send_reply(
-                               NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
+                       err = iscsi_if_send_reply(group, nlh->nlmsg_seq,
                                nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
                } while (err < 0 && err != -ECONNREFUSED);
                skb_pull(skb, rlen);
@@ -1774,7 +1854,6 @@ iscsi_register_transport(struct iscsi_transport *tt)
        if (!priv)
                return NULL;
        INIT_LIST_HEAD(&priv->list);
-       priv->daemon_pid = -1;
        priv->iscsi_transport = tt;
        priv->t.user_scan = iscsi_user_scan;
        priv->t.create_work_queue = 1;
index bcf3bd40bbd5fc3bfbecb29f0d7b21b5e393c8b3..878b17a9af3008ab5fe29afc7a8faa4a9c99d58d 100644 (file)
@@ -1902,24 +1902,6 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
        index = sdkp->index;
        dev = &sdp->sdev_gendev;
 
-       if (!sdp->request_queue->rq_timeout) {
-               if (sdp->type != TYPE_MOD)
-                       blk_queue_rq_timeout(sdp->request_queue, SD_TIMEOUT);
-               else
-                       blk_queue_rq_timeout(sdp->request_queue,
-                                            SD_MOD_TIMEOUT);
-       }
-
-       device_initialize(&sdkp->dev);
-       sdkp->dev.parent = &sdp->sdev_gendev;
-       sdkp->dev.class = &sd_disk_class;
-       dev_set_name(&sdkp->dev, dev_name(&sdp->sdev_gendev));
-
-       if (device_add(&sdkp->dev))
-               goto out_free_index;
-
-       get_device(&sdp->sdev_gendev);
-
        if (index < SD_MAX_DISKS) {
                gd->major = sd_major((index & 0xf0) >> 4);
                gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00);
@@ -1954,11 +1936,6 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
 
        sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
                  sdp->removable ? "removable " : "");
-
-       return;
-
- out_free_index:
-       ida_remove(&sd_index_ida, index);
 }
 
 /**
@@ -2026,6 +2003,24 @@ static int sd_probe(struct device *dev)
        sdkp->openers = 0;
        sdkp->previous_state = 1;
 
+       if (!sdp->request_queue->rq_timeout) {
+               if (sdp->type != TYPE_MOD)
+                       blk_queue_rq_timeout(sdp->request_queue, SD_TIMEOUT);
+               else
+                       blk_queue_rq_timeout(sdp->request_queue,
+                                            SD_MOD_TIMEOUT);
+       }
+
+       device_initialize(&sdkp->dev);
+       sdkp->dev.parent = &sdp->sdev_gendev;
+       sdkp->dev.class = &sd_disk_class;
+       dev_set_name(&sdkp->dev, dev_name(&sdp->sdev_gendev));
+
+       if (device_add(&sdkp->dev))
+               goto out_free_index;
+
+       get_device(&sdp->sdev_gendev);
+
        async_schedule(sd_probe_async, sdkp);
 
        return 0;
@@ -2055,8 +2050,10 @@ static int sd_probe(struct device *dev)
  **/
 static int sd_remove(struct device *dev)
 {
-       struct scsi_disk *sdkp = dev_get_drvdata(dev);
+       struct scsi_disk *sdkp;
 
+       async_synchronize_full();
+       sdkp = dev_get_drvdata(dev);
        device_del(&sdkp->dev);
        del_gendisk(sdkp->disk);
        sd_shutdown(dev);
index 89bd438e1fe30692e006a0bac18c18fc4c21cd86..b33d04250bbc3badeeb3f00644f137402af07bf1 100644 (file)
@@ -2964,7 +2964,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
                            !(STp->use_pf & PF_TESTED)) {
                                /* Try the other possible state of Page Format if not
                                   already tried */
-                               STp->use_pf = !STp->use_pf | PF_TESTED;
+                               STp->use_pf = (STp->use_pf ^ USE_PF) | PF_TESTED;
                                st_release_request(SRpnt);
                                SRpnt = NULL;
                                return st_int_ioctl(STp, cmd_in, arg);
index 583966ec82661f9959fe2434c853d50e2139d771..45374d66d26a4268ae9a765d45687c8a0c02c29a 100644 (file)
@@ -737,11 +737,14 @@ static int sym53c8xx_slave_alloc(struct scsi_device *sdev)
        struct sym_hcb *np = sym_get_hcb(sdev->host);
        struct sym_tcb *tp = &np->target[sdev->id];
        struct sym_lcb *lp;
+       unsigned long flags;
+       int error;
 
        if (sdev->id >= SYM_CONF_MAX_TARGET || sdev->lun >= SYM_CONF_MAX_LUN)
                return -ENXIO;
 
-       tp->starget = sdev->sdev_target;
+       spin_lock_irqsave(np->s.host->host_lock, flags);
+
        /*
         * Fail the device init if the device is flagged NOSCAN at BOOT in
         * the NVRAM.  This may speed up boot and maintain coherency with
@@ -753,26 +756,37 @@ static int sym53c8xx_slave_alloc(struct scsi_device *sdev)
 
        if (tp->usrflags & SYM_SCAN_BOOT_DISABLED) {
                tp->usrflags &= ~SYM_SCAN_BOOT_DISABLED;
-               starget_printk(KERN_INFO, tp->starget,
+               starget_printk(KERN_INFO, sdev->sdev_target,
                                "Scan at boot disabled in NVRAM\n");
-               return -ENXIO;
+               error = -ENXIO;
+               goto out;
        }
 
        if (tp->usrflags & SYM_SCAN_LUNS_DISABLED) {
-               if (sdev->lun != 0)
-                       return -ENXIO;
-               starget_printk(KERN_INFO, tp->starget,
+               if (sdev->lun != 0) {
+                       error = -ENXIO;
+                       goto out;
+               }
+               starget_printk(KERN_INFO, sdev->sdev_target,
                                "Multiple LUNs disabled in NVRAM\n");
        }
 
        lp = sym_alloc_lcb(np, sdev->id, sdev->lun);
-       if (!lp)
-               return -ENOMEM;
+       if (!lp) {
+               error = -ENOMEM;
+               goto out;
+       }
+       if (tp->nlcb == 1)
+               tp->starget = sdev->sdev_target;
 
        spi_min_period(tp->starget) = tp->usr_period;
        spi_max_width(tp->starget) = tp->usr_width;
 
-       return 0;
+       error = 0;
+out:
+       spin_unlock_irqrestore(np->s.host->host_lock, flags);
+
+       return error;
 }
 
 /*
@@ -819,12 +833,34 @@ static int sym53c8xx_slave_configure(struct scsi_device *sdev)
 static void sym53c8xx_slave_destroy(struct scsi_device *sdev)
 {
        struct sym_hcb *np = sym_get_hcb(sdev->host);
-       struct sym_lcb *lp = sym_lp(&np->target[sdev->id], sdev->lun);
+       struct sym_tcb *tp = &np->target[sdev->id];
+       struct sym_lcb *lp = sym_lp(tp, sdev->lun);
+       unsigned long flags;
+
+       spin_lock_irqsave(np->s.host->host_lock, flags);
+
+       if (lp->busy_itlq || lp->busy_itl) {
+               /*
+                * This really shouldn't happen, but we can't return an error
+                * so let's try to stop all on-going I/O.
+                */
+               starget_printk(KERN_WARNING, tp->starget,
+                              "Removing busy LCB (%d)\n", sdev->lun);
+               sym_reset_scsi_bus(np, 1);
+       }
 
-       if (lp->itlq_tbl)
-               sym_mfree_dma(lp->itlq_tbl, SYM_CONF_MAX_TASK * 4, "ITLQ_TBL");
-       kfree(lp->cb_tags);
-       sym_mfree_dma(lp, sizeof(*lp), "LCB");
+       if (sym_free_lcb(np, sdev->id, sdev->lun) == 0) {
+               /*
+                * It was the last unit for this target.
+                */
+               tp->head.sval        = 0;
+               tp->head.wval        = np->rv_scntl3;
+               tp->head.uval        = 0;
+               tp->tgoal.check_nego = 1;
+               tp->starget          = NULL;
+       }
+
+       spin_unlock_irqrestore(np->s.host->host_lock, flags);
 }
 
 /*
@@ -890,6 +926,8 @@ static void sym_exec_user_command (struct sym_hcb *np, struct sym_usrcmd *uc)
                        if (!((uc->target >> t) & 1))
                                continue;
                        tp = &np->target[t];
+                       if (!tp->nlcb)
+                               continue;
 
                        switch (uc->cmd) {
 
index ffa70d1ed182dcfee4e1a2fc4593db436c16ced7..69ad4945c9369467f0d2fa5095741845d8156ac8 100644 (file)
@@ -1896,6 +1896,15 @@ void sym_start_up(struct Scsi_Host *shost, int reason)
                tp->head.sval = 0;
                tp->head.wval = np->rv_scntl3;
                tp->head.uval = 0;
+               if (tp->lun0p)
+                       tp->lun0p->to_clear = 0;
+               if (tp->lunmp) {
+                       int ln;
+
+                       for (ln = 1; ln < SYM_CONF_MAX_LUN; ln++)
+                               if (tp->lunmp[ln])
+                                       tp->lunmp[ln]->to_clear = 0;
+               }
        }
 
        /*
@@ -4988,7 +4997,7 @@ struct sym_lcb *sym_alloc_lcb (struct sym_hcb *np, u_char tn, u_char ln)
         */
        if (ln && !tp->lunmp) {
                tp->lunmp = kcalloc(SYM_CONF_MAX_LUN, sizeof(struct sym_lcb *),
-                               GFP_KERNEL);
+                               GFP_ATOMIC);
                if (!tp->lunmp)
                        goto fail;
        }
@@ -5008,6 +5017,7 @@ struct sym_lcb *sym_alloc_lcb (struct sym_hcb *np, u_char tn, u_char ln)
                tp->lun0p = lp;
                tp->head.lun0_sa = cpu_to_scr(vtobus(lp));
        }
+       tp->nlcb++;
 
        /*
         *  Let the itl task point to error handling.
@@ -5084,6 +5094,43 @@ fail:
        return;
 }
 
+/*
+ *  Lun control block deallocation. Returns the number of valid remaing LCBs
+ *  for the target.
+ */
+int sym_free_lcb(struct sym_hcb *np, u_char tn, u_char ln)
+{
+       struct sym_tcb *tp = &np->target[tn];
+       struct sym_lcb *lp = sym_lp(tp, ln);
+
+       tp->nlcb--;
+
+       if (ln) {
+               if (!tp->nlcb) {
+                       kfree(tp->lunmp);
+                       sym_mfree_dma(tp->luntbl, 256, "LUNTBL");
+                       tp->lunmp = NULL;
+                       tp->luntbl = NULL;
+                       tp->head.luntbl_sa = cpu_to_scr(vtobus(np->badluntbl));
+               } else {
+                       tp->luntbl[ln] = cpu_to_scr(vtobus(&np->badlun_sa));
+                       tp->lunmp[ln] = NULL;
+               }
+       } else {
+               tp->lun0p = NULL;
+               tp->head.lun0_sa = cpu_to_scr(vtobus(&np->badlun_sa));
+       }
+
+       if (lp->itlq_tbl) {
+               sym_mfree_dma(lp->itlq_tbl, SYM_CONF_MAX_TASK*4, "ITLQ_TBL");
+               kfree(lp->cb_tags);
+       }
+
+       sym_mfree_dma(lp, sizeof(*lp), "LCB");
+
+       return tp->nlcb;
+}
+
 /*
  *  Queue a SCSI IO to the controller.
  */
index 9ebc8706b6bfc7b70fcdd884a5328130d53e65d4..053e63c86822d7c30a0d25edc0eac28a80eb5eec 100644 (file)
@@ -401,6 +401,7 @@ struct sym_tcb {
         *  An array of bus addresses is used on reselection.
         */
        u32     *luntbl;        /* LCBs bus address table       */
+       int     nlcb;           /* Number of valid LCBs (including LUN #0) */
 
        /*
         *  LUN table used by the C code.
@@ -1065,6 +1066,7 @@ int sym_clear_tasks(struct sym_hcb *np, int cam_status, int target, int lun, int
 struct sym_ccb *sym_get_ccb(struct sym_hcb *np, struct scsi_cmnd *cmd, u_char tag_order);
 void sym_free_ccb(struct sym_hcb *np, struct sym_ccb *cp);
 struct sym_lcb *sym_alloc_lcb(struct sym_hcb *np, u_char tn, u_char ln);
+int sym_free_lcb(struct sym_hcb *np, u_char tn, u_char ln);
 int sym_queue_scsiio(struct sym_hcb *np, struct scsi_cmnd *csio, struct sym_ccb *cp);
 int sym_abort_scsiio(struct sym_hcb *np, struct scsi_cmnd *ccb, int timed_out);
 int sym_reset_scsi_target(struct sym_hcb *np, int target);
index 641e800ed69333fbafc3b06dd982a0a3ec7f7605..1132c5cae7ab338346802fac23050cababd7550a 100644 (file)
@@ -861,7 +861,7 @@ config SERIAL_UARTLITE
          Say Y here if you want to use the Xilinx uartlite serial controller.
 
          To compile this driver as a module, choose M here: the
-         module will be called uartlite.ko.
+         module will be called uartlite.
 
 config SERIAL_UARTLITE_CONSOLE
        bool "Support for console on Xilinx uartlite serial port"
index cdc049d4350fc20aa684eb2d4387772c6b39a0f7..58a4879c7e48806ade2ae0e3a48223c2a92e03f4 100644 (file)
@@ -686,7 +686,7 @@ static int pl010_probe(struct amba_device *dev, struct amba_id *id)
                goto out;
        }
 
-       base = ioremap(dev->res.start, PAGE_SIZE);
+       base = ioremap(dev->res.start, resource_size(&dev->res));
        if (!base) {
                ret = -ENOMEM;
                goto free;
index 88fdac51b6c5155854477a755b6b38c87baa566a..bf82e28770a9845af5cfef55098605e98bcef728 100644 (file)
@@ -70,6 +70,23 @@ struct uart_amba_port {
        struct clk              *clk;
        unsigned int            im;     /* interrupt mask */
        unsigned int            old_status;
+       unsigned int            ifls;   /* vendor-specific */
+};
+
+/* There is by now at least one vendor with differing details, so handle it */
+struct vendor_data {
+       unsigned int            ifls;
+       unsigned int            fifosize;
+};
+
+static struct vendor_data vendor_arm = {
+       .ifls                   = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
+       .fifosize               = 16,
+};
+
+static struct vendor_data vendor_st = {
+       .ifls                   = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF,
+       .fifosize               = 64,
 };
 
 static void pl011_stop_tx(struct uart_port *port)
@@ -360,8 +377,7 @@ static int pl011_startup(struct uart_port *port)
        if (retval)
                goto clk_dis;
 
-       writew(UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
-              uap->port.membase + UART011_IFLS);
+       writew(uap->ifls, uap->port.membase + UART011_IFLS);
 
        /*
         * Provoke TX FIFO interrupt into asserting.
@@ -732,6 +748,7 @@ static struct uart_driver amba_reg = {
 static int pl011_probe(struct amba_device *dev, struct amba_id *id)
 {
        struct uart_amba_port *uap;
+       struct vendor_data *vendor = id->data;
        void __iomem *base;
        int i, ret;
 
@@ -750,7 +767,7 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id)
                goto out;
        }
 
-       base = ioremap(dev->res.start, PAGE_SIZE);
+       base = ioremap(dev->res.start, resource_size(&dev->res));
        if (!base) {
                ret = -ENOMEM;
                goto free;
@@ -762,12 +779,13 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id)
                goto unmap;
        }
 
+       uap->ifls = vendor->ifls;
        uap->port.dev = &dev->dev;
        uap->port.mapbase = dev->res.start;
        uap->port.membase = base;
        uap->port.iotype = UPIO_MEM;
        uap->port.irq = dev->irq[0];
-       uap->port.fifosize = 16;
+       uap->port.fifosize = vendor->fifosize;
        uap->port.ops = &amba_pl011_pops;
        uap->port.flags = UPF_BOOT_AUTOCONF;
        uap->port.line = i;
@@ -812,6 +830,12 @@ static struct amba_id pl011_ids[] __initdata = {
        {
                .id     = 0x00041011,
                .mask   = 0x000fffff,
+               .data   = &vendor_arm,
+       },
+       {
+               .id     = 0x00380802,
+               .mask   = 0x00ffffff,
+               .data   = &vendor_st,
        },
        { 0, 0 },
 };
@@ -845,7 +869,11 @@ static void __exit pl011_exit(void)
        uart_unregister_driver(&amba_reg);
 }
 
-module_init(pl011_init);
+/*
+ * While this can be a module, if builtin it's most likely the console
+ * So let's leave module_exit but move module_init to an earlier place
+ */
+arch_initcall(pl011_init);
 module_exit(pl011_exit);
 
 MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd");
index 7b5d1de9cfe39c3436d1074bb3b9c77933743507..285b414f30546d0a89285f823d802979adbbcac9 100644 (file)
@@ -71,7 +71,7 @@
 #define ONEMS 0xb0 /* One Millisecond register */
 #define UTS   0xb4 /* UART Test Register */
 #endif
-#if defined(CONFIG_ARCH_IMX) || defined(CONFIG_ARCH_MX1)
+#ifdef CONFIG_ARCH_MX1
 #define BIPR1 0xb0 /* Incremental Preset Register 1 */
 #define BIPR2 0xb4 /* Incremental Preset Register 2 */
 #define BIPR3 0xb8 /* Incremental Preset Register 3 */
 #define  UCR1_RTSDEN     (1<<5)         /* RTS delta interrupt enable */
 #define  UCR1_SNDBRK     (1<<4)         /* Send break */
 #define  UCR1_TDMAEN     (1<<3)         /* Transmitter ready DMA enable */
-#if defined(CONFIG_ARCH_IMX) || defined(CONFIG_ARCH_MX1)
+#ifdef CONFIG_ARCH_MX1
 #define  UCR1_UARTCLKEN  (1<<2)         /* UART clock enabled */
 #endif
 #if defined CONFIG_ARCH_MX3 || defined CONFIG_ARCH_MX2
 #define  UCR3_RXDSEN    (1<<6)  /* Receive status interrupt enable */
 #define  UCR3_AIRINTEN   (1<<5)  /* Async IR wake interrupt enable */
 #define  UCR3_AWAKEN    (1<<4)  /* Async wake interrupt enable */
-#ifdef CONFIG_ARCH_IMX
+#ifdef CONFIG_ARCH_MX1
 #define  UCR3_REF25     (1<<3)  /* Ref freq 25 MHz, only on mx1 */
 #define  UCR3_REF30     (1<<2)  /* Ref Freq 30 MHz, only on mx1 */
 #endif
 #define  UTS_SOFTRST    (1<<0)  /* Software reset */
 
 /* We've been assigned a range on the "Low-density serial ports" major */
-#ifdef CONFIG_ARCH_IMX
-#define SERIAL_IMX_MAJOR       204
-#define MINOR_START            41
-#define DEV_NAME               "ttySMX"
-#define MAX_INTERNAL_IRQ       IMX_IRQS
-#endif
-
 #ifdef CONFIG_ARCH_MXC
 #define SERIAL_IMX_MAJOR        207
 #define MINOR_START            16
index 83a185d52961e5075cd5330de7f770fc4eb28e79..e8aae227b5e0a3283702f5ee4f3ecd9fce3ce829 100644 (file)
@@ -118,7 +118,7 @@ config SPI_GPIO
 
 config SPI_IMX
        tristate "Freescale iMX SPI controller"
-       depends on ARCH_IMX && EXPERIMENTAL
+       depends on ARCH_MX1 && EXPERIMENTAL
        help
          This enables using the Freescale iMX SPI controller in master
          mode.
@@ -171,6 +171,15 @@ config SPI_ORION
        help
          This enables using the SPI master controller on the Orion chips.
 
+config SPI_PL022
+       tristate "ARM AMBA PL022 SSP controller (EXPERIMENTAL)"
+       depends on ARM_AMBA && EXPERIMENTAL
+       default y if MACH_U300
+       help
+         This selects the ARM(R) AMBA(R) PrimeCell PL022 SSP
+         controller. If you have an embedded system with an AMBA(R)
+         bus and a PL022 controller, say Y or M here.
+
 config SPI_PXA2XX
        tristate "PXA2xx SSP SPI master"
        depends on ARCH_PXA && EXPERIMENTAL
@@ -212,7 +221,7 @@ config SPI_TXX9
 
 config SPI_XILINX
        tristate "Xilinx SPI controller"
-       depends on XILINX_VIRTEX && EXPERIMENTAL
+       depends on (XILINX_VIRTEX || MICROBLAZE) && EXPERIMENTAL
        select SPI_BITBANG
        help
          This exposes the SPI controller IP from the Xilinx EDK.
index 5d0451936d8625eebd4f70dd59f65ab69c2db333..ecfadb180482119f9f6b23f8563e14b2019b2db8 100644 (file)
@@ -23,6 +23,7 @@ obj-$(CONFIG_SPI_PXA2XX)              += pxa2xx_spi.o
 obj-$(CONFIG_SPI_OMAP_UWIRE)           += omap_uwire.o
 obj-$(CONFIG_SPI_OMAP24XX)             += omap2_mcspi.o
 obj-$(CONFIG_SPI_ORION)                        += orion_spi.o
+obj-$(CONFIG_SPI_PL022)                        += amba-pl022.o
 obj-$(CONFIG_SPI_MPC52xx_PSC)          += mpc52xx_psc_spi.o
 obj-$(CONFIG_SPI_MPC83xx)              += spi_mpc83xx.o
 obj-$(CONFIG_SPI_S3C24XX_GPIO)         += spi_s3c24xx_gpio.o
diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c
new file mode 100644 (file)
index 0000000..da76797
--- /dev/null
@@ -0,0 +1,1866 @@
+/*
+ * drivers/spi/amba-pl022.c
+ *
+ * A driver for the ARM PL022 PrimeCell SSP/SPI bus master.
+ *
+ * Copyright (C) 2008-2009 ST-Ericsson AB
+ * Copyright (C) 2006 STMicroelectronics Pvt. Ltd.
+ *
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ *
+ * Initial version inspired by:
+ *     linux-2.6.17-rc3-mm1/drivers/spi/pxa2xx_spi.c
+ * Initial adoption to PL022 by:
+ *      Sachin Verma <sachin.verma@st.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.
+ */
+
+/*
+ * TODO:
+ * - add timeout on polled transfers
+ * - add generic DMA framework support
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/spi/spi.h>
+#include <linux/workqueue.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/pl022.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+/*
+ * This macro is used to define some register default values.
+ * reg is masked with mask, the OR:ed with an (again masked)
+ * val shifted sb steps to the left.
+ */
+#define SSP_WRITE_BITS(reg, val, mask, sb) \
+ ((reg) = (((reg) & ~(mask)) | (((val)<<(sb)) & (mask))))
+
+/*
+ * This macro is also used to define some default values.
+ * It will just shift val by sb steps to the left and mask
+ * the result with mask.
+ */
+#define GEN_MASK_BITS(val, mask, sb) \
+ (((val)<<(sb)) & (mask))
+
+#define DRIVE_TX               0
+#define DO_NOT_DRIVE_TX                1
+
+#define DO_NOT_QUEUE_DMA       0
+#define QUEUE_DMA              1
+
+#define RX_TRANSFER            1
+#define TX_TRANSFER            2
+
+/*
+ * Macros to access SSP Registers with their offsets
+ */
+#define SSP_CR0(r)     (r + 0x000)
+#define SSP_CR1(r)     (r + 0x004)
+#define SSP_DR(r)      (r + 0x008)
+#define SSP_SR(r)      (r + 0x00C)
+#define SSP_CPSR(r)    (r + 0x010)
+#define SSP_IMSC(r)    (r + 0x014)
+#define SSP_RIS(r)     (r + 0x018)
+#define SSP_MIS(r)     (r + 0x01C)
+#define SSP_ICR(r)     (r + 0x020)
+#define SSP_DMACR(r)   (r + 0x024)
+#define SSP_ITCR(r)    (r + 0x080)
+#define SSP_ITIP(r)    (r + 0x084)
+#define SSP_ITOP(r)    (r + 0x088)
+#define SSP_TDR(r)     (r + 0x08C)
+
+#define SSP_PID0(r)    (r + 0xFE0)
+#define SSP_PID1(r)    (r + 0xFE4)
+#define SSP_PID2(r)    (r + 0xFE8)
+#define SSP_PID3(r)    (r + 0xFEC)
+
+#define SSP_CID0(r)    (r + 0xFF0)
+#define SSP_CID1(r)    (r + 0xFF4)
+#define SSP_CID2(r)    (r + 0xFF8)
+#define SSP_CID3(r)    (r + 0xFFC)
+
+/*
+ * SSP Control Register 0  - SSP_CR0
+ */
+#define SSP_CR0_MASK_DSS       (0x1FUL << 0)
+#define SSP_CR0_MASK_HALFDUP   (0x1UL << 5)
+#define SSP_CR0_MASK_SPO       (0x1UL << 6)
+#define SSP_CR0_MASK_SPH       (0x1UL << 7)
+#define SSP_CR0_MASK_SCR       (0xFFUL << 8)
+#define SSP_CR0_MASK_CSS       (0x1FUL << 16)
+#define SSP_CR0_MASK_FRF       (0x3UL << 21)
+
+/*
+ * SSP Control Register 0  - SSP_CR1
+ */
+#define SSP_CR1_MASK_LBM       (0x1UL << 0)
+#define SSP_CR1_MASK_SSE       (0x1UL << 1)
+#define SSP_CR1_MASK_MS                (0x1UL << 2)
+#define SSP_CR1_MASK_SOD       (0x1UL << 3)
+#define SSP_CR1_MASK_RENDN     (0x1UL << 4)
+#define SSP_CR1_MASK_TENDN     (0x1UL << 5)
+#define SSP_CR1_MASK_MWAIT     (0x1UL << 6)
+#define SSP_CR1_MASK_RXIFLSEL  (0x7UL << 7)
+#define SSP_CR1_MASK_TXIFLSEL  (0x7UL << 10)
+
+/*
+ * SSP Data Register - SSP_DR
+ */
+#define SSP_DR_MASK_DATA       0xFFFFFFFF
+
+/*
+ * SSP Status Register - SSP_SR
+ */
+#define SSP_SR_MASK_TFE                (0x1UL << 0) /* Transmit FIFO empty */
+#define SSP_SR_MASK_TNF                (0x1UL << 1) /* Transmit FIFO not full */
+#define SSP_SR_MASK_RNE                (0x1UL << 2) /* Receive FIFO not empty */
+#define SSP_SR_MASK_RFF        (0x1UL << 3) /* Receive FIFO full */
+#define SSP_SR_MASK_BSY                (0x1UL << 4) /* Busy Flag */
+
+/*
+ * SSP Clock Prescale Register  - SSP_CPSR
+ */
+#define SSP_CPSR_MASK_CPSDVSR  (0xFFUL << 0)
+
+/*
+ * SSP Interrupt Mask Set/Clear Register - SSP_IMSC
+ */
+#define SSP_IMSC_MASK_RORIM (0x1UL << 0) /* Receive Overrun Interrupt mask */
+#define SSP_IMSC_MASK_RTIM  (0x1UL << 1) /* Receive timeout Interrupt mask */
+#define SSP_IMSC_MASK_RXIM  (0x1UL << 2) /* Receive FIFO Interrupt mask */
+#define SSP_IMSC_MASK_TXIM  (0x1UL << 3) /* Transmit FIFO Interrupt mask */
+
+/*
+ * SSP Raw Interrupt Status Register - SSP_RIS
+ */
+/* Receive Overrun Raw Interrupt status */
+#define SSP_RIS_MASK_RORRIS            (0x1UL << 0)
+/* Receive Timeout Raw Interrupt status */
+#define SSP_RIS_MASK_RTRIS             (0x1UL << 1)
+/* Receive FIFO Raw Interrupt status */
+#define SSP_RIS_MASK_RXRIS             (0x1UL << 2)
+/* Transmit FIFO Raw Interrupt status */
+#define SSP_RIS_MASK_TXRIS             (0x1UL << 3)
+
+/*
+ * SSP Masked Interrupt Status Register - SSP_MIS
+ */
+/* Receive Overrun Masked Interrupt status */
+#define SSP_MIS_MASK_RORMIS            (0x1UL << 0)
+/* Receive Timeout Masked Interrupt status */
+#define SSP_MIS_MASK_RTMIS             (0x1UL << 1)
+/* Receive FIFO Masked Interrupt status */
+#define SSP_MIS_MASK_RXMIS             (0x1UL << 2)
+/* Transmit FIFO Masked Interrupt status */
+#define SSP_MIS_MASK_TXMIS             (0x1UL << 3)
+
+/*
+ * SSP Interrupt Clear Register - SSP_ICR
+ */
+/* Receive Overrun Raw Clear Interrupt bit */
+#define SSP_ICR_MASK_RORIC             (0x1UL << 0)
+/* Receive Timeout Clear Interrupt bit */
+#define SSP_ICR_MASK_RTIC              (0x1UL << 1)
+
+/*
+ * SSP DMA Control Register - SSP_DMACR
+ */
+/* Receive DMA Enable bit */
+#define SSP_DMACR_MASK_RXDMAE          (0x1UL << 0)
+/* Transmit DMA Enable bit */
+#define SSP_DMACR_MASK_TXDMAE          (0x1UL << 1)
+
+/*
+ * SSP Integration Test control Register - SSP_ITCR
+ */
+#define SSP_ITCR_MASK_ITEN             (0x1UL << 0)
+#define SSP_ITCR_MASK_TESTFIFO         (0x1UL << 1)
+
+/*
+ * SSP Integration Test Input Register - SSP_ITIP
+ */
+#define ITIP_MASK_SSPRXD                (0x1UL << 0)
+#define ITIP_MASK_SSPFSSIN              (0x1UL << 1)
+#define ITIP_MASK_SSPCLKIN              (0x1UL << 2)
+#define ITIP_MASK_RXDMAC                (0x1UL << 3)
+#define ITIP_MASK_TXDMAC                (0x1UL << 4)
+#define ITIP_MASK_SSPTXDIN              (0x1UL << 5)
+
+/*
+ * SSP Integration Test output Register - SSP_ITOP
+ */
+#define ITOP_MASK_SSPTXD                (0x1UL << 0)
+#define ITOP_MASK_SSPFSSOUT             (0x1UL << 1)
+#define ITOP_MASK_SSPCLKOUT             (0x1UL << 2)
+#define ITOP_MASK_SSPOEn                (0x1UL << 3)
+#define ITOP_MASK_SSPCTLOEn             (0x1UL << 4)
+#define ITOP_MASK_RORINTR               (0x1UL << 5)
+#define ITOP_MASK_RTINTR                (0x1UL << 6)
+#define ITOP_MASK_RXINTR                (0x1UL << 7)
+#define ITOP_MASK_TXINTR                (0x1UL << 8)
+#define ITOP_MASK_INTR                  (0x1UL << 9)
+#define ITOP_MASK_RXDMABREQ             (0x1UL << 10)
+#define ITOP_MASK_RXDMASREQ             (0x1UL << 11)
+#define ITOP_MASK_TXDMABREQ             (0x1UL << 12)
+#define ITOP_MASK_TXDMASREQ             (0x1UL << 13)
+
+/*
+ * SSP Test Data Register - SSP_TDR
+ */
+#define TDR_MASK_TESTDATA              (0xFFFFFFFF)
+
+/*
+ * Message State
+ * we use the spi_message.state (void *) pointer to
+ * hold a single state value, that's why all this
+ * (void *) casting is done here.
+ */
+#define STATE_START                     ((void *) 0)
+#define STATE_RUNNING                   ((void *) 1)
+#define STATE_DONE                      ((void *) 2)
+#define STATE_ERROR                     ((void *) -1)
+
+/*
+ * Queue State
+ */
+#define QUEUE_RUNNING                   (0)
+#define QUEUE_STOPPED                   (1)
+/*
+ * SSP State - Whether Enabled or Disabled
+ */
+#define SSP_DISABLED                   (0)
+#define SSP_ENABLED                    (1)
+
+/*
+ * SSP DMA State - Whether DMA Enabled or Disabled
+ */
+#define SSP_DMA_DISABLED               (0)
+#define SSP_DMA_ENABLED                (1)
+
+/*
+ * SSP Clock Defaults
+ */
+#define NMDK_SSP_DEFAULT_CLKRATE 0x2
+#define NMDK_SSP_DEFAULT_PRESCALE 0x40
+
+/*
+ * SSP Clock Parameter ranges
+ */
+#define CPSDVR_MIN 0x02
+#define CPSDVR_MAX 0xFE
+#define SCR_MIN 0x00
+#define SCR_MAX 0xFF
+
+/*
+ * SSP Interrupt related Macros
+ */
+#define DEFAULT_SSP_REG_IMSC  0x0UL
+#define DISABLE_ALL_INTERRUPTS DEFAULT_SSP_REG_IMSC
+#define ENABLE_ALL_INTERRUPTS (~DEFAULT_SSP_REG_IMSC)
+
+#define CLEAR_ALL_INTERRUPTS  0x3
+
+
+/*
+ * The type of reading going on on this chip
+ */
+enum ssp_reading {
+       READING_NULL,
+       READING_U8,
+       READING_U16,
+       READING_U32
+};
+
+/**
+ * The type of writing going on on this chip
+ */
+enum ssp_writing {
+       WRITING_NULL,
+       WRITING_U8,
+       WRITING_U16,
+       WRITING_U32
+};
+
+/**
+ * struct vendor_data - vendor-specific config parameters
+ * for PL022 derivates
+ * @fifodepth: depth of FIFOs (both)
+ * @max_bpw: maximum number of bits per word
+ * @unidir: supports unidirection transfers
+ */
+struct vendor_data {
+       int fifodepth;
+       int max_bpw;
+       bool unidir;
+};
+
+/**
+ * struct pl022 - This is the private SSP driver data structure
+ * @adev: AMBA device model hookup
+ * @phybase: The physical memory where the SSP device resides
+ * @virtbase: The virtual memory where the SSP is mapped
+ * @master: SPI framework hookup
+ * @master_info: controller-specific data from machine setup
+ * @regs: SSP controller register's virtual address
+ * @pump_messages: Work struct for scheduling work to the workqueue
+ * @lock: spinlock to syncronise access to driver data
+ * @workqueue: a workqueue on which any spi_message request is queued
+ * @busy: workqueue is busy
+ * @run: workqueue is running
+ * @pump_transfers: Tasklet used in Interrupt Transfer mode
+ * @cur_msg: Pointer to current spi_message being processed
+ * @cur_transfer: Pointer to current spi_transfer
+ * @cur_chip: pointer to current clients chip(assigned from controller_state)
+ * @tx: current position in TX buffer to be read
+ * @tx_end: end position in TX buffer to be read
+ * @rx: current position in RX buffer to be written
+ * @rx_end: end position in RX buffer to be written
+ * @readingtype: the type of read currently going on
+ * @writingtype: the type or write currently going on
+ */
+struct pl022 {
+       struct amba_device              *adev;
+       struct vendor_data              *vendor;
+       resource_size_t                 phybase;
+       void __iomem                    *virtbase;
+       struct clk                      *clk;
+       struct spi_master               *master;
+       struct pl022_ssp_controller     *master_info;
+       /* Driver message queue */
+       struct workqueue_struct         *workqueue;
+       struct work_struct              pump_messages;
+       spinlock_t                      queue_lock;
+       struct list_head                queue;
+       int                             busy;
+       int                             run;
+       /* Message transfer pump */
+       struct tasklet_struct           pump_transfers;
+       struct spi_message              *cur_msg;
+       struct spi_transfer             *cur_transfer;
+       struct chip_data                *cur_chip;
+       void                            *tx;
+       void                            *tx_end;
+       void                            *rx;
+       void                            *rx_end;
+       enum ssp_reading                read;
+       enum ssp_writing                write;
+};
+
+/**
+ * struct chip_data - To maintain runtime state of SSP for each client chip
+ * @cr0: Value of control register CR0 of SSP
+ * @cr1: Value of control register CR1 of SSP
+ * @dmacr: Value of DMA control Register of SSP
+ * @cpsr: Value of Clock prescale register
+ * @n_bytes: how many bytes(power of 2) reqd for a given data width of client
+ * @enable_dma: Whether to enable DMA or not
+ * @write: function ptr to be used to write when doing xfer for this chip
+ * @read: function ptr to be used to read when doing xfer for this chip
+ * @cs_control: chip select callback provided by chip
+ * @xfer_type: polling/interrupt/DMA
+ *
+ * Runtime state of the SSP controller, maintained per chip,
+ * This would be set according to the current message that would be served
+ */
+struct chip_data {
+       u16 cr0;
+       u16 cr1;
+       u16 dmacr;
+       u16 cpsr;
+       u8 n_bytes;
+       u8 enable_dma:1;
+       enum ssp_reading read;
+       enum ssp_writing write;
+       void (*cs_control) (u32 command);
+       int xfer_type;
+};
+
+/**
+ * null_cs_control - Dummy chip select function
+ * @command: select/delect the chip
+ *
+ * If no chip select function is provided by client this is used as dummy
+ * chip select
+ */
+static void null_cs_control(u32 command)
+{
+       pr_debug("pl022: dummy chip select control, CS=0x%x\n", command);
+}
+
+/**
+ * giveback - current spi_message is over, schedule next message and call
+ * callback of this message. Assumes that caller already
+ * set message->status; dma and pio irqs are blocked
+ * @pl022: SSP driver private data structure
+ */
+static void giveback(struct pl022 *pl022)
+{
+       struct spi_transfer *last_transfer;
+       unsigned long flags;
+       struct spi_message *msg;
+       void (*curr_cs_control) (u32 command);
+
+       /*
+        * This local reference to the chip select function
+        * is needed because we set curr_chip to NULL
+        * as a step toward termininating the message.
+        */
+       curr_cs_control = pl022->cur_chip->cs_control;
+       spin_lock_irqsave(&pl022->queue_lock, flags);
+       msg = pl022->cur_msg;
+       pl022->cur_msg = NULL;
+       pl022->cur_transfer = NULL;
+       pl022->cur_chip = NULL;
+       queue_work(pl022->workqueue, &pl022->pump_messages);
+       spin_unlock_irqrestore(&pl022->queue_lock, flags);
+
+       last_transfer = list_entry(msg->transfers.prev,
+                                       struct spi_transfer,
+                                       transfer_list);
+
+       /* Delay if requested before any change in chip select */
+       if (last_transfer->delay_usecs)
+               /*
+                * FIXME: This runs in interrupt context.
+                * Is this really smart?
+                */
+               udelay(last_transfer->delay_usecs);
+
+       /*
+        * Drop chip select UNLESS cs_change is true or we are returning
+        * a message with an error, or next message is for another chip
+        */
+       if (!last_transfer->cs_change)
+               curr_cs_control(SSP_CHIP_DESELECT);
+       else {
+               struct spi_message *next_msg;
+
+               /* Holding of cs was hinted, but we need to make sure
+                * the next message is for the same chip.  Don't waste
+                * time with the following tests unless this was hinted.
+                *
+                * We cannot postpone this until pump_messages, because
+                * after calling msg->complete (below) the driver that
+                * sent the current message could be unloaded, which
+                * could invalidate the cs_control() callback...
+                */
+
+               /* get a pointer to the next message, if any */
+               spin_lock_irqsave(&pl022->queue_lock, flags);
+               if (list_empty(&pl022->queue))
+                       next_msg = NULL;
+               else
+                       next_msg = list_entry(pl022->queue.next,
+                                       struct spi_message, queue);
+               spin_unlock_irqrestore(&pl022->queue_lock, flags);
+
+               /* see if the next and current messages point
+                * to the same chip
+                */
+               if (next_msg && next_msg->spi != msg->spi)
+                       next_msg = NULL;
+               if (!next_msg || msg->state == STATE_ERROR)
+                       curr_cs_control(SSP_CHIP_DESELECT);
+       }
+       msg->state = NULL;
+       if (msg->complete)
+               msg->complete(msg->context);
+       /* This message is completed, so let's turn off the clock! */
+       clk_disable(pl022->clk);
+}
+
+/**
+ * flush - flush the FIFO to reach a clean state
+ * @pl022: SSP driver private data structure
+ */
+static int flush(struct pl022 *pl022)
+{
+       unsigned long limit = loops_per_jiffy << 1;
+
+       dev_dbg(&pl022->adev->dev, "flush\n");
+       do {
+               while (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RNE)
+                       readw(SSP_DR(pl022->virtbase));
+       } while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_BSY) && limit--);
+       return limit;
+}
+
+/**
+ * restore_state - Load configuration of current chip
+ * @pl022: SSP driver private data structure
+ */
+static void restore_state(struct pl022 *pl022)
+{
+       struct chip_data *chip = pl022->cur_chip;
+
+       writew(chip->cr0, SSP_CR0(pl022->virtbase));
+       writew(chip->cr1, SSP_CR1(pl022->virtbase));
+       writew(chip->dmacr, SSP_DMACR(pl022->virtbase));
+       writew(chip->cpsr, SSP_CPSR(pl022->virtbase));
+       writew(DISABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase));
+       writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase));
+}
+
+/**
+ * load_ssp_default_config - Load default configuration for SSP
+ * @pl022: SSP driver private data structure
+ */
+
+/*
+ * Default SSP Register Values
+ */
+#define DEFAULT_SSP_REG_CR0 ( \
+       GEN_MASK_BITS(SSP_DATA_BITS_12, SSP_CR0_MASK_DSS, 0)    | \
+       GEN_MASK_BITS(SSP_MICROWIRE_CHANNEL_FULL_DUPLEX, SSP_CR0_MASK_HALFDUP, 5) | \
+       GEN_MASK_BITS(SSP_CLK_POL_IDLE_LOW, SSP_CR0_MASK_SPO, 6) | \
+       GEN_MASK_BITS(SSP_CLK_FALLING_EDGE, SSP_CR0_MASK_SPH, 7) | \
+       GEN_MASK_BITS(NMDK_SSP_DEFAULT_CLKRATE, SSP_CR0_MASK_SCR, 8) | \
+       GEN_MASK_BITS(SSP_BITS_8, SSP_CR0_MASK_CSS, 16) | \
+       GEN_MASK_BITS(SSP_INTERFACE_MOTOROLA_SPI, SSP_CR0_MASK_FRF, 21) \
+)
+
+#define DEFAULT_SSP_REG_CR1 ( \
+       GEN_MASK_BITS(LOOPBACK_DISABLED, SSP_CR1_MASK_LBM, 0) | \
+       GEN_MASK_BITS(SSP_DISABLED, SSP_CR1_MASK_SSE, 1) | \
+       GEN_MASK_BITS(SSP_MASTER, SSP_CR1_MASK_MS, 2) | \
+       GEN_MASK_BITS(DO_NOT_DRIVE_TX, SSP_CR1_MASK_SOD, 3) | \
+       GEN_MASK_BITS(SSP_RX_MSB, SSP_CR1_MASK_RENDN, 4) | \
+       GEN_MASK_BITS(SSP_TX_MSB, SSP_CR1_MASK_TENDN, 5) | \
+       GEN_MASK_BITS(SSP_MWIRE_WAIT_ZERO, SSP_CR1_MASK_MWAIT, 6) |\
+       GEN_MASK_BITS(SSP_RX_1_OR_MORE_ELEM, SSP_CR1_MASK_RXIFLSEL, 7) | \
+       GEN_MASK_BITS(SSP_TX_1_OR_MORE_EMPTY_LOC, SSP_CR1_MASK_TXIFLSEL, 10) \
+)
+
+#define DEFAULT_SSP_REG_CPSR ( \
+       GEN_MASK_BITS(NMDK_SSP_DEFAULT_PRESCALE, SSP_CPSR_MASK_CPSDVSR, 0) \
+)
+
+#define DEFAULT_SSP_REG_DMACR (\
+       GEN_MASK_BITS(SSP_DMA_DISABLED, SSP_DMACR_MASK_RXDMAE, 0) | \
+       GEN_MASK_BITS(SSP_DMA_DISABLED, SSP_DMACR_MASK_TXDMAE, 1) \
+)
+
+
+static void load_ssp_default_config(struct pl022 *pl022)
+{
+       writew(DEFAULT_SSP_REG_CR0, SSP_CR0(pl022->virtbase));
+       writew(DEFAULT_SSP_REG_CR1, SSP_CR1(pl022->virtbase));
+       writew(DEFAULT_SSP_REG_DMACR, SSP_DMACR(pl022->virtbase));
+       writew(DEFAULT_SSP_REG_CPSR, SSP_CPSR(pl022->virtbase));
+       writew(DISABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase));
+       writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase));
+}
+
+/**
+ * This will write to TX and read from RX according to the parameters
+ * set in pl022.
+ */
+static void readwriter(struct pl022 *pl022)
+{
+
+       /*
+        * The FIFO depth is different inbetween primecell variants.
+        * I believe filling in too much in the FIFO might cause
+        * errons in 8bit wide transfers on ARM variants (just 8 words
+        * FIFO, means only 8x8 = 64 bits in FIFO) at least.
+        *
+        * FIXME: currently we have no logic to account for this.
+        * perhaps there is even something broken in HW regarding
+        * 8bit transfers (it doesn't fail on 16bit) so this needs
+        * more investigation...
+        */
+       dev_dbg(&pl022->adev->dev,
+               "%s, rx: %p, rxend: %p, tx: %p, txend: %p\n",
+               __func__, pl022->rx, pl022->rx_end, pl022->tx, pl022->tx_end);
+
+       /* Read as much as you can */
+       while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RNE)
+              && (pl022->rx < pl022->rx_end)) {
+               switch (pl022->read) {
+               case READING_NULL:
+                       readw(SSP_DR(pl022->virtbase));
+                       break;
+               case READING_U8:
+                       *(u8 *) (pl022->rx) =
+                               readw(SSP_DR(pl022->virtbase)) & 0xFFU;
+                       break;
+               case READING_U16:
+                       *(u16 *) (pl022->rx) =
+                               (u16) readw(SSP_DR(pl022->virtbase));
+                       break;
+               case READING_U32:
+                       *(u32 *) (pl022->rx) =
+                               readl(SSP_DR(pl022->virtbase));
+                       break;
+               }
+               pl022->rx += (pl022->cur_chip->n_bytes);
+       }
+       /*
+        * Write as much as you can, while keeping an eye on the RX FIFO!
+        */
+       while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_TNF)
+              && (pl022->tx < pl022->tx_end)) {
+               switch (pl022->write) {
+               case WRITING_NULL:
+                       writew(0x0, SSP_DR(pl022->virtbase));
+                       break;
+               case WRITING_U8:
+                       writew(*(u8 *) (pl022->tx), SSP_DR(pl022->virtbase));
+                       break;
+               case WRITING_U16:
+                       writew((*(u16 *) (pl022->tx)), SSP_DR(pl022->virtbase));
+                       break;
+               case WRITING_U32:
+                       writel(*(u32 *) (pl022->tx), SSP_DR(pl022->virtbase));
+                       break;
+               }
+               pl022->tx += (pl022->cur_chip->n_bytes);
+               /*
+                * This inner reader takes care of things appearing in the RX
+                * FIFO as we're transmitting. This will happen a lot since the
+                * clock starts running when you put things into the TX FIFO,
+                * and then things are continously clocked into the RX FIFO.
+                */
+               while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RNE)
+                      && (pl022->rx < pl022->rx_end)) {
+                       switch (pl022->read) {
+                       case READING_NULL:
+                               readw(SSP_DR(pl022->virtbase));
+                               break;
+                       case READING_U8:
+                               *(u8 *) (pl022->rx) =
+                                       readw(SSP_DR(pl022->virtbase)) & 0xFFU;
+                               break;
+                       case READING_U16:
+                               *(u16 *) (pl022->rx) =
+                                       (u16) readw(SSP_DR(pl022->virtbase));
+                               break;
+                       case READING_U32:
+                               *(u32 *) (pl022->rx) =
+                                       readl(SSP_DR(pl022->virtbase));
+                               break;
+                       }
+                       pl022->rx += (pl022->cur_chip->n_bytes);
+               }
+       }
+       /*
+        * When we exit here the TX FIFO should be full and the RX FIFO
+        * should be empty
+        */
+}
+
+
+/**
+ * next_transfer - Move to the Next transfer in the current spi message
+ * @pl022: SSP driver private data structure
+ *
+ * This function moves though the linked list of spi transfers in the
+ * current spi message and returns with the state of current spi
+ * message i.e whether its last transfer is done(STATE_DONE) or
+ * Next transfer is ready(STATE_RUNNING)
+ */
+static void *next_transfer(struct pl022 *pl022)
+{
+       struct spi_message *msg = pl022->cur_msg;
+       struct spi_transfer *trans = pl022->cur_transfer;
+
+       /* Move to next transfer */
+       if (trans->transfer_list.next != &msg->transfers) {
+               pl022->cur_transfer =
+                   list_entry(trans->transfer_list.next,
+                              struct spi_transfer, transfer_list);
+               return STATE_RUNNING;
+       }
+       return STATE_DONE;
+}
+/**
+ * pl022_interrupt_handler - Interrupt handler for SSP controller
+ *
+ * This function handles interrupts generated for an interrupt based transfer.
+ * If a receive overrun (ROR) interrupt is there then we disable SSP, flag the
+ * current message's state as STATE_ERROR and schedule the tasklet
+ * pump_transfers which will do the postprocessing of the current message by
+ * calling giveback(). Otherwise it reads data from RX FIFO till there is no
+ * more data, and writes data in TX FIFO till it is not full. If we complete
+ * the transfer we move to the next transfer and schedule the tasklet.
+ */
+static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id)
+{
+       struct pl022 *pl022 = dev_id;
+       struct spi_message *msg = pl022->cur_msg;
+       u16 irq_status = 0;
+       u16 flag = 0;
+
+       if (unlikely(!msg)) {
+               dev_err(&pl022->adev->dev,
+                       "bad message state in interrupt handler");
+               /* Never fail */
+               return IRQ_HANDLED;
+       }
+
+       /* Read the Interrupt Status Register */
+       irq_status = readw(SSP_MIS(pl022->virtbase));
+
+       if (unlikely(!irq_status))
+               return IRQ_NONE;
+
+       /* This handles the error code interrupts */
+       if (unlikely(irq_status & SSP_MIS_MASK_RORMIS)) {
+               /*
+                * Overrun interrupt - bail out since our Data has been
+                * corrupted
+                */
+               dev_err(&pl022->adev->dev,
+                       "FIFO overrun\n");
+               if (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RFF)
+                       dev_err(&pl022->adev->dev,
+                               "RXFIFO is full\n");
+               if (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_TNF)
+                       dev_err(&pl022->adev->dev,
+                               "TXFIFO is full\n");
+
+               /*
+                * Disable and clear interrupts, disable SSP,
+                * mark message with bad status so it can be
+                * retried.
+                */
+               writew(DISABLE_ALL_INTERRUPTS,
+                      SSP_IMSC(pl022->virtbase));
+               writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase));
+               writew((readw(SSP_CR1(pl022->virtbase)) &
+                       (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase));
+               msg->state = STATE_ERROR;
+
+               /* Schedule message queue handler */
+               tasklet_schedule(&pl022->pump_transfers);
+               return IRQ_HANDLED;
+       }
+
+       readwriter(pl022);
+
+       if ((pl022->tx == pl022->tx_end) && (flag == 0)) {
+               flag = 1;
+               /* Disable Transmit interrupt */
+               writew(readw(SSP_IMSC(pl022->virtbase)) &
+                      (~SSP_IMSC_MASK_TXIM),
+                      SSP_IMSC(pl022->virtbase));
+       }
+
+       /*
+        * Since all transactions must write as much as shall be read,
+        * we can conclude the entire transaction once RX is complete.
+        * At this point, all TX will always be finished.
+        */
+       if (pl022->rx >= pl022->rx_end) {
+               writew(DISABLE_ALL_INTERRUPTS,
+                      SSP_IMSC(pl022->virtbase));
+               writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase));
+               if (unlikely(pl022->rx > pl022->rx_end)) {
+                       dev_warn(&pl022->adev->dev, "read %u surplus "
+                                "bytes (did you request an odd "
+                                "number of bytes on a 16bit bus?)\n",
+                                (u32) (pl022->rx - pl022->rx_end));
+               }
+               /* Update total bytes transfered */
+               msg->actual_length += pl022->cur_transfer->len;
+               if (pl022->cur_transfer->cs_change)
+                       pl022->cur_chip->
+                               cs_control(SSP_CHIP_DESELECT);
+               /* Move to next transfer */
+               msg->state = next_transfer(pl022);
+               tasklet_schedule(&pl022->pump_transfers);
+               return IRQ_HANDLED;
+       }
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * This sets up the pointers to memory for the next message to
+ * send out on the SPI bus.
+ */
+static int set_up_next_transfer(struct pl022 *pl022,
+                               struct spi_transfer *transfer)
+{
+       int residue;
+
+       /* Sanity check the message for this bus width */
+       residue = pl022->cur_transfer->len % pl022->cur_chip->n_bytes;
+       if (unlikely(residue != 0)) {
+               dev_err(&pl022->adev->dev,
+                       "message of %u bytes to transmit but the current "
+                       "chip bus has a data width of %u bytes!\n",
+                       pl022->cur_transfer->len,
+                       pl022->cur_chip->n_bytes);
+               dev_err(&pl022->adev->dev, "skipping this message\n");
+               return -EIO;
+       }
+       pl022->tx = (void *)transfer->tx_buf;
+       pl022->tx_end = pl022->tx + pl022->cur_transfer->len;
+       pl022->rx = (void *)transfer->rx_buf;
+       pl022->rx_end = pl022->rx + pl022->cur_transfer->len;
+       pl022->write =
+           pl022->tx ? pl022->cur_chip->write : WRITING_NULL;
+       pl022->read = pl022->rx ? pl022->cur_chip->read : READING_NULL;
+       return 0;
+}
+
+/**
+ * pump_transfers - Tasklet function which schedules next interrupt transfer
+ * when running in interrupt transfer mode.
+ * @data: SSP driver private data structure
+ *
+ */
+static void pump_transfers(unsigned long data)
+{
+       struct pl022 *pl022 = (struct pl022 *) data;
+       struct spi_message *message = NULL;
+       struct spi_transfer *transfer = NULL;
+       struct spi_transfer *previous = NULL;
+
+       /* Get current state information */
+       message = pl022->cur_msg;
+       transfer = pl022->cur_transfer;
+
+       /* Handle for abort */
+       if (message->state == STATE_ERROR) {
+               message->status = -EIO;
+               giveback(pl022);
+               return;
+       }
+
+       /* Handle end of message */
+       if (message->state == STATE_DONE) {
+               message->status = 0;
+               giveback(pl022);
+               return;
+       }
+
+       /* Delay if requested at end of transfer before CS change */
+       if (message->state == STATE_RUNNING) {
+               previous = list_entry(transfer->transfer_list.prev,
+                                       struct spi_transfer,
+                                       transfer_list);
+               if (previous->delay_usecs)
+                       /*
+                        * FIXME: This runs in interrupt context.
+                        * Is this really smart?
+                        */
+                       udelay(previous->delay_usecs);
+
+               /* Drop chip select only if cs_change is requested */
+               if (previous->cs_change)
+                       pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
+       } else {
+               /* STATE_START */
+               message->state = STATE_RUNNING;
+       }
+
+       if (set_up_next_transfer(pl022, transfer)) {
+               message->state = STATE_ERROR;
+               message->status = -EIO;
+               giveback(pl022);
+               return;
+       }
+       /* Flush the FIFOs and let's go! */
+       flush(pl022);
+       writew(ENABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase));
+}
+
+/**
+ * NOT IMPLEMENTED
+ * configure_dma - It configures the DMA pipes for DMA transfers
+ * @data: SSP driver's private data structure
+ *
+ */
+static int configure_dma(void *data)
+{
+       struct pl022 *pl022 = data;
+       dev_dbg(&pl022->adev->dev, "configure DMA\n");
+       return -ENOTSUPP;
+}
+
+/**
+ * do_dma_transfer - It handles transfers of the current message
+ * if it is DMA xfer.
+ * NOT FULLY IMPLEMENTED
+ * @data: SSP driver's private data structure
+ */
+static void do_dma_transfer(void *data)
+{
+       struct pl022 *pl022 = data;
+
+       if (configure_dma(data)) {
+               dev_dbg(&pl022->adev->dev, "configuration of DMA Failed!\n");
+               goto err_config_dma;
+       }
+
+       /* TODO: Implememt DMA setup of pipes here */
+
+       /* Enable target chip, set up transfer */
+       pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
+       if (set_up_next_transfer(pl022, pl022->cur_transfer)) {
+               /* Error path */
+               pl022->cur_msg->state = STATE_ERROR;
+               pl022->cur_msg->status = -EIO;
+               giveback(pl022);
+               return;
+       }
+       /* Enable SSP */
+       writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE),
+              SSP_CR1(pl022->virtbase));
+
+       /* TODO: Enable the DMA transfer here */
+       return;
+
+ err_config_dma:
+       pl022->cur_msg->state = STATE_ERROR;
+       pl022->cur_msg->status = -EIO;
+       giveback(pl022);
+       return;
+}
+
+static void do_interrupt_transfer(void *data)
+{
+       struct pl022 *pl022 = data;
+
+       /* Enable target chip */
+       pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
+       if (set_up_next_transfer(pl022, pl022->cur_transfer)) {
+               /* Error path */
+               pl022->cur_msg->state = STATE_ERROR;
+               pl022->cur_msg->status = -EIO;
+               giveback(pl022);
+               return;
+       }
+       /* Enable SSP, turn on interrupts */
+       writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE),
+              SSP_CR1(pl022->virtbase));
+       writew(ENABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase));
+}
+
+static void do_polling_transfer(void *data)
+{
+       struct pl022 *pl022 = data;
+       struct spi_message *message = NULL;
+       struct spi_transfer *transfer = NULL;
+       struct spi_transfer *previous = NULL;
+       struct chip_data *chip;
+
+       chip = pl022->cur_chip;
+       message = pl022->cur_msg;
+
+       while (message->state != STATE_DONE) {
+               /* Handle for abort */
+               if (message->state == STATE_ERROR)
+                       break;
+               transfer = pl022->cur_transfer;
+
+               /* Delay if requested at end of transfer */
+               if (message->state == STATE_RUNNING) {
+                       previous =
+                           list_entry(transfer->transfer_list.prev,
+                                      struct spi_transfer, transfer_list);
+                       if (previous->delay_usecs)
+                               udelay(previous->delay_usecs);
+                       if (previous->cs_change)
+                               pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
+               } else {
+                       /* STATE_START */
+                       message->state = STATE_RUNNING;
+                       pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
+               }
+
+               /* Configuration Changing Per Transfer */
+               if (set_up_next_transfer(pl022, transfer)) {
+                       /* Error path */
+                       message->state = STATE_ERROR;
+                       break;
+               }
+               /* Flush FIFOs and enable SSP */
+               flush(pl022);
+               writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE),
+                      SSP_CR1(pl022->virtbase));
+
+               dev_dbg(&pl022->adev->dev, "POLLING TRANSFER ONGOING ... \n");
+               /* FIXME: insert a timeout so we don't hang here indefinately */
+               while (pl022->tx < pl022->tx_end || pl022->rx < pl022->rx_end)
+                       readwriter(pl022);
+
+               /* Update total byte transfered */
+               message->actual_length += pl022->cur_transfer->len;
+               if (pl022->cur_transfer->cs_change)
+                       pl022->cur_chip->cs_control(SSP_CHIP_DESELECT);
+               /* Move to next transfer */
+               message->state = next_transfer(pl022);
+       }
+
+       /* Handle end of message */
+       if (message->state == STATE_DONE)
+               message->status = 0;
+       else
+               message->status = -EIO;
+
+       giveback(pl022);
+       return;
+}
+
+/**
+ * pump_messages - Workqueue function which processes spi message queue
+ * @data: pointer to private data of SSP driver
+ *
+ * This function checks if there is any spi message in the queue that
+ * needs processing and delegate control to appropriate function
+ * do_polling_transfer()/do_interrupt_transfer()/do_dma_transfer()
+ * based on the kind of the transfer
+ *
+ */
+static void pump_messages(struct work_struct *work)
+{
+       struct pl022 *pl022 =
+               container_of(work, struct pl022, pump_messages);
+       unsigned long flags;
+
+       /* Lock queue and check for queue work */
+       spin_lock_irqsave(&pl022->queue_lock, flags);
+       if (list_empty(&pl022->queue) || pl022->run == QUEUE_STOPPED) {
+               pl022->busy = 0;
+               spin_unlock_irqrestore(&pl022->queue_lock, flags);
+               return;
+       }
+       /* Make sure we are not already running a message */
+       if (pl022->cur_msg) {
+               spin_unlock_irqrestore(&pl022->queue_lock, flags);
+               return;
+       }
+       /* Extract head of queue */
+       pl022->cur_msg =
+           list_entry(pl022->queue.next, struct spi_message, queue);
+
+       list_del_init(&pl022->cur_msg->queue);
+       pl022->busy = 1;
+       spin_unlock_irqrestore(&pl022->queue_lock, flags);
+
+       /* Initial message state */
+       pl022->cur_msg->state = STATE_START;
+       pl022->cur_transfer = list_entry(pl022->cur_msg->transfers.next,
+                                           struct spi_transfer,
+                                           transfer_list);
+
+       /* Setup the SPI using the per chip configuration */
+       pl022->cur_chip = spi_get_ctldata(pl022->cur_msg->spi);
+       /*
+        * We enable the clock here, then the clock will be disabled when
+        * giveback() is called in each method (poll/interrupt/DMA)
+        */
+       clk_enable(pl022->clk);
+       restore_state(pl022);
+       flush(pl022);
+
+       if (pl022->cur_chip->xfer_type == POLLING_TRANSFER)
+               do_polling_transfer(pl022);
+       else if (pl022->cur_chip->xfer_type == INTERRUPT_TRANSFER)
+               do_interrupt_transfer(pl022);
+       else
+               do_dma_transfer(pl022);
+}
+
+
+static int __init init_queue(struct pl022 *pl022)
+{
+       INIT_LIST_HEAD(&pl022->queue);
+       spin_lock_init(&pl022->queue_lock);
+
+       pl022->run = QUEUE_STOPPED;
+       pl022->busy = 0;
+
+       tasklet_init(&pl022->pump_transfers,
+                       pump_transfers, (unsigned long)pl022);
+
+       INIT_WORK(&pl022->pump_messages, pump_messages);
+       pl022->workqueue = create_singlethread_workqueue(
+                                       dev_name(pl022->master->dev.parent));
+       if (pl022->workqueue == NULL)
+               return -EBUSY;
+
+       return 0;
+}
+
+
+static int start_queue(struct pl022 *pl022)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pl022->queue_lock, flags);
+
+       if (pl022->run == QUEUE_RUNNING || pl022->busy) {
+               spin_unlock_irqrestore(&pl022->queue_lock, flags);
+               return -EBUSY;
+       }
+
+       pl022->run = QUEUE_RUNNING;
+       pl022->cur_msg = NULL;
+       pl022->cur_transfer = NULL;
+       pl022->cur_chip = NULL;
+       spin_unlock_irqrestore(&pl022->queue_lock, flags);
+
+       queue_work(pl022->workqueue, &pl022->pump_messages);
+
+       return 0;
+}
+
+
+static int stop_queue(struct pl022 *pl022)
+{
+       unsigned long flags;
+       unsigned limit = 500;
+       int status = 0;
+
+       spin_lock_irqsave(&pl022->queue_lock, flags);
+
+       /* This is a bit lame, but is optimized for the common execution path.
+        * A wait_queue on the pl022->busy could be used, but then the common
+        * execution path (pump_messages) would be required to call wake_up or
+        * friends on every SPI message. Do this instead */
+       pl022->run = QUEUE_STOPPED;
+       while (!list_empty(&pl022->queue) && pl022->busy && limit--) {
+               spin_unlock_irqrestore(&pl022->queue_lock, flags);
+               msleep(10);
+               spin_lock_irqsave(&pl022->queue_lock, flags);
+       }
+
+       if (!list_empty(&pl022->queue) || pl022->busy)
+               status = -EBUSY;
+
+       spin_unlock_irqrestore(&pl022->queue_lock, flags);
+
+       return status;
+}
+
+static int destroy_queue(struct pl022 *pl022)
+{
+       int status;
+
+       status = stop_queue(pl022);
+       /* we are unloading the module or failing to load (only two calls
+        * to this routine), and neither call can handle a return value.
+        * However, destroy_workqueue calls flush_workqueue, and that will
+        * block until all work is done.  If the reason that stop_queue
+        * timed out is that the work will never finish, then it does no
+        * good to call destroy_workqueue, so return anyway. */
+       if (status != 0)
+               return status;
+
+       destroy_workqueue(pl022->workqueue);
+
+       return 0;
+}
+
+static int verify_controller_parameters(struct pl022 *pl022,
+                                       struct pl022_config_chip *chip_info)
+{
+       if ((chip_info->lbm != LOOPBACK_ENABLED)
+           && (chip_info->lbm != LOOPBACK_DISABLED)) {
+               dev_err(chip_info->dev,
+                       "loopback Mode is configured incorrectly\n");
+               return -EINVAL;
+       }
+       if ((chip_info->iface < SSP_INTERFACE_MOTOROLA_SPI)
+           || (chip_info->iface > SSP_INTERFACE_UNIDIRECTIONAL)) {
+               dev_err(chip_info->dev,
+                       "interface is configured incorrectly\n");
+               return -EINVAL;
+       }
+       if ((chip_info->iface == SSP_INTERFACE_UNIDIRECTIONAL) &&
+           (!pl022->vendor->unidir)) {
+               dev_err(chip_info->dev,
+                       "unidirectional mode not supported in this "
+                       "hardware version\n");
+               return -EINVAL;
+       }
+       if ((chip_info->hierarchy != SSP_MASTER)
+           && (chip_info->hierarchy != SSP_SLAVE)) {
+               dev_err(chip_info->dev,
+                       "hierarchy is configured incorrectly\n");
+               return -EINVAL;
+       }
+       if (((chip_info->clk_freq).cpsdvsr < CPSDVR_MIN)
+           || ((chip_info->clk_freq).cpsdvsr > CPSDVR_MAX)) {
+               dev_err(chip_info->dev,
+                       "cpsdvsr is configured incorrectly\n");
+               return -EINVAL;
+       }
+       if ((chip_info->endian_rx != SSP_RX_MSB)
+           && (chip_info->endian_rx != SSP_RX_LSB)) {
+               dev_err(chip_info->dev,
+                       "RX FIFO endianess is configured incorrectly\n");
+               return -EINVAL;
+       }
+       if ((chip_info->endian_tx != SSP_TX_MSB)
+           && (chip_info->endian_tx != SSP_TX_LSB)) {
+               dev_err(chip_info->dev,
+                       "TX FIFO endianess is configured incorrectly\n");
+               return -EINVAL;
+       }
+       if ((chip_info->data_size < SSP_DATA_BITS_4)
+           || (chip_info->data_size > SSP_DATA_BITS_32)) {
+               dev_err(chip_info->dev,
+                       "DATA Size is configured incorrectly\n");
+               return -EINVAL;
+       }
+       if ((chip_info->com_mode != INTERRUPT_TRANSFER)
+           && (chip_info->com_mode != DMA_TRANSFER)
+           && (chip_info->com_mode != POLLING_TRANSFER)) {
+               dev_err(chip_info->dev,
+                       "Communication mode is configured incorrectly\n");
+               return -EINVAL;
+       }
+       if ((chip_info->rx_lev_trig < SSP_RX_1_OR_MORE_ELEM)
+           || (chip_info->rx_lev_trig > SSP_RX_32_OR_MORE_ELEM)) {
+               dev_err(chip_info->dev,
+                       "RX FIFO Trigger Level is configured incorrectly\n");
+               return -EINVAL;
+       }
+       if ((chip_info->tx_lev_trig < SSP_TX_1_OR_MORE_EMPTY_LOC)
+           || (chip_info->tx_lev_trig > SSP_TX_32_OR_MORE_EMPTY_LOC)) {
+               dev_err(chip_info->dev,
+                       "TX FIFO Trigger Level is configured incorrectly\n");
+               return -EINVAL;
+       }
+       if (chip_info->iface == SSP_INTERFACE_MOTOROLA_SPI) {
+               if ((chip_info->clk_phase != SSP_CLK_RISING_EDGE)
+                   && (chip_info->clk_phase != SSP_CLK_FALLING_EDGE)) {
+                       dev_err(chip_info->dev,
+                               "Clock Phase is configured incorrectly\n");
+                       return -EINVAL;
+               }
+               if ((chip_info->clk_pol != SSP_CLK_POL_IDLE_LOW)
+                   && (chip_info->clk_pol != SSP_CLK_POL_IDLE_HIGH)) {
+                       dev_err(chip_info->dev,
+                               "Clock Polarity is configured incorrectly\n");
+                       return -EINVAL;
+               }
+       }
+       if (chip_info->iface == SSP_INTERFACE_NATIONAL_MICROWIRE) {
+               if ((chip_info->ctrl_len < SSP_BITS_4)
+                   || (chip_info->ctrl_len > SSP_BITS_32)) {
+                       dev_err(chip_info->dev,
+                               "CTRL LEN is configured incorrectly\n");
+                       return -EINVAL;
+               }
+               if ((chip_info->wait_state != SSP_MWIRE_WAIT_ZERO)
+                   && (chip_info->wait_state != SSP_MWIRE_WAIT_ONE)) {
+                       dev_err(chip_info->dev,
+                               "Wait State is configured incorrectly\n");
+                       return -EINVAL;
+               }
+               if ((chip_info->duplex != SSP_MICROWIRE_CHANNEL_FULL_DUPLEX)
+                   && (chip_info->duplex !=
+                       SSP_MICROWIRE_CHANNEL_HALF_DUPLEX)) {
+                       dev_err(chip_info->dev,
+                               "DUPLEX is configured incorrectly\n");
+                       return -EINVAL;
+               }
+       }
+       if (chip_info->cs_control == NULL) {
+               dev_warn(chip_info->dev,
+                       "Chip Select Function is NULL for this chip\n");
+               chip_info->cs_control = null_cs_control;
+       }
+       return 0;
+}
+
+/**
+ * pl022_transfer - transfer function registered to SPI master framework
+ * @spi: spi device which is requesting transfer
+ * @msg: spi message which is to handled is queued to driver queue
+ *
+ * This function is registered to the SPI framework for this SPI master
+ * controller. It will queue the spi_message in the queue of driver if
+ * the queue is not stopped and return.
+ */
+static int pl022_transfer(struct spi_device *spi, struct spi_message *msg)
+{
+       struct pl022 *pl022 = spi_master_get_devdata(spi->master);
+       unsigned long flags;
+
+       spin_lock_irqsave(&pl022->queue_lock, flags);
+
+       if (pl022->run == QUEUE_STOPPED) {
+               spin_unlock_irqrestore(&pl022->queue_lock, flags);
+               return -ESHUTDOWN;
+       }
+       msg->actual_length = 0;
+       msg->status = -EINPROGRESS;
+       msg->state = STATE_START;
+
+       list_add_tail(&msg->queue, &pl022->queue);
+       if (pl022->run == QUEUE_RUNNING && !pl022->busy)
+               queue_work(pl022->workqueue, &pl022->pump_messages);
+
+       spin_unlock_irqrestore(&pl022->queue_lock, flags);
+       return 0;
+}
+
+static int calculate_effective_freq(struct pl022 *pl022,
+                                   int freq,
+                                   struct ssp_clock_params *clk_freq)
+{
+       /* Lets calculate the frequency parameters */
+       u16 cpsdvsr = 2;
+       u16 scr = 0;
+       bool freq_found = false;
+       u32 rate;
+       u32 max_tclk;
+       u32 min_tclk;
+
+       rate = clk_get_rate(pl022->clk);
+       /* cpsdvscr = 2 & scr 0 */
+       max_tclk = (rate / (CPSDVR_MIN * (1 + SCR_MIN)));
+       /* cpsdvsr = 254 & scr = 255 */
+       min_tclk = (rate / (CPSDVR_MAX * (1 + SCR_MAX)));
+
+       if ((freq <= max_tclk) && (freq >= min_tclk)) {
+               while (cpsdvsr <= CPSDVR_MAX && !freq_found) {
+                       while (scr <= SCR_MAX && !freq_found) {
+                               if ((rate /
+                                    (cpsdvsr * (1 + scr))) > freq)
+                                       scr += 1;
+                               else {
+                                       /*
+                                        * This bool is made true when
+                                        * effective frequency >=
+                                        * target frequency is found
+                                        */
+                                       freq_found = true;
+                                       if ((rate /
+                                            (cpsdvsr * (1 + scr))) != freq) {
+                                               if (scr == SCR_MIN) {
+                                                       cpsdvsr -= 2;
+                                                       scr = SCR_MAX;
+                                               } else
+                                                       scr -= 1;
+                                       }
+                               }
+                       }
+                       if (!freq_found) {
+                               cpsdvsr += 2;
+                               scr = SCR_MIN;
+                       }
+               }
+               if (cpsdvsr != 0) {
+                       dev_dbg(&pl022->adev->dev,
+                               "SSP Effective Frequency is %u\n",
+                               (rate / (cpsdvsr * (1 + scr))));
+                       clk_freq->cpsdvsr = (u8) (cpsdvsr & 0xFF);
+                       clk_freq->scr = (u8) (scr & 0xFF);
+                       dev_dbg(&pl022->adev->dev,
+                               "SSP cpsdvsr = %d, scr = %d\n",
+                               clk_freq->cpsdvsr, clk_freq->scr);
+               }
+       } else {
+               dev_err(&pl022->adev->dev,
+                       "controller data is incorrect: out of range frequency");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/**
+ * NOT IMPLEMENTED
+ * process_dma_info - Processes the DMA info provided by client drivers
+ * @chip_info: chip info provided by client device
+ * @chip: Runtime state maintained by the SSP controller for each spi device
+ *
+ * This function processes and stores DMA config provided by client driver
+ * into the runtime state maintained by the SSP controller driver
+ */
+static int process_dma_info(struct pl022_config_chip *chip_info,
+                           struct chip_data *chip)
+{
+       dev_err(chip_info->dev,
+               "cannot process DMA info, DMA not implemented!\n");
+       return -ENOTSUPP;
+}
+
+/**
+ * pl022_setup - setup function registered to SPI master framework
+ * @spi: spi device which is requesting setup
+ *
+ * This function is registered to the SPI framework for this SPI master
+ * controller. If it is the first time when setup is called by this device,
+ * this function will initialize the runtime state for this chip and save
+ * the same in the device structure. Else it will update the runtime info
+ * with the updated chip info. Nothing is really being written to the
+ * controller hardware here, that is not done until the actual transfer
+ * commence.
+ */
+
+/* FIXME: JUST GUESSING the spi->mode bits understood by this driver */
+#define MODEBITS       (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
+                       | SPI_LSB_FIRST | SPI_LOOP)
+
+static int pl022_setup(struct spi_device *spi)
+{
+       struct pl022_config_chip *chip_info;
+       struct chip_data *chip;
+       int status = 0;
+       struct pl022 *pl022 = spi_master_get_devdata(spi->master);
+
+       if (spi->mode & ~MODEBITS) {
+               dev_dbg(&spi->dev, "unsupported mode bits %x\n",
+                       spi->mode & ~MODEBITS);
+               return -EINVAL;
+       }
+
+       if (!spi->max_speed_hz)
+               return -EINVAL;
+
+       /* Get controller_state if one is supplied */
+       chip = spi_get_ctldata(spi);
+
+       if (chip == NULL) {
+               chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
+               if (!chip) {
+                       dev_err(&spi->dev,
+                               "cannot allocate controller state\n");
+                       return -ENOMEM;
+               }
+               dev_dbg(&spi->dev,
+                       "allocated memory for controller's runtime state\n");
+       }
+
+       /* Get controller data if one is supplied */
+       chip_info = spi->controller_data;
+
+       if (chip_info == NULL) {
+               /* spi_board_info.controller_data not is supplied */
+               dev_dbg(&spi->dev,
+                       "using default controller_data settings\n");
+
+               chip_info =
+                       kzalloc(sizeof(struct pl022_config_chip), GFP_KERNEL);
+
+               if (!chip_info) {
+                       dev_err(&spi->dev,
+                               "cannot allocate controller data\n");
+                       status = -ENOMEM;
+                       goto err_first_setup;
+               }
+
+               dev_dbg(&spi->dev, "allocated memory for controller data\n");
+
+               /* Pointer back to the SPI device */
+               chip_info->dev = &spi->dev;
+               /*
+                * Set controller data default values:
+                * Polling is supported by default
+                */
+               chip_info->lbm = LOOPBACK_DISABLED;
+               chip_info->com_mode = POLLING_TRANSFER;
+               chip_info->iface = SSP_INTERFACE_MOTOROLA_SPI;
+               chip_info->hierarchy = SSP_SLAVE;
+               chip_info->slave_tx_disable = DO_NOT_DRIVE_TX;
+               chip_info->endian_tx = SSP_TX_LSB;
+               chip_info->endian_rx = SSP_RX_LSB;
+               chip_info->data_size = SSP_DATA_BITS_12;
+               chip_info->rx_lev_trig = SSP_RX_1_OR_MORE_ELEM;
+               chip_info->tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC;
+               chip_info->clk_phase = SSP_CLK_FALLING_EDGE;
+               chip_info->clk_pol = SSP_CLK_POL_IDLE_LOW;
+               chip_info->ctrl_len = SSP_BITS_8;
+               chip_info->wait_state = SSP_MWIRE_WAIT_ZERO;
+               chip_info->duplex = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX;
+               chip_info->cs_control = null_cs_control;
+       } else {
+               dev_dbg(&spi->dev,
+                       "using user supplied controller_data settings\n");
+       }
+
+       /*
+        * We can override with custom divisors, else we use the board
+        * frequency setting
+        */
+       if ((0 == chip_info->clk_freq.cpsdvsr)
+           && (0 == chip_info->clk_freq.scr)) {
+               status = calculate_effective_freq(pl022,
+                                                 spi->max_speed_hz,
+                                                 &chip_info->clk_freq);
+               if (status < 0)
+                       goto err_config_params;
+       } else {
+               if ((chip_info->clk_freq.cpsdvsr % 2) != 0)
+                       chip_info->clk_freq.cpsdvsr =
+                               chip_info->clk_freq.cpsdvsr - 1;
+       }
+       status = verify_controller_parameters(pl022, chip_info);
+       if (status) {
+               dev_err(&spi->dev, "controller data is incorrect");
+               goto err_config_params;
+       }
+       /* Now set controller state based on controller data */
+       chip->xfer_type = chip_info->com_mode;
+       chip->cs_control = chip_info->cs_control;
+
+       if (chip_info->data_size <= 8) {
+               dev_dbg(&spi->dev, "1 <= n <=8 bits per word\n");
+               chip->n_bytes = 1;
+               chip->read = READING_U8;
+               chip->write = WRITING_U8;
+       } else if (chip_info->data_size <= 16) {
+               dev_dbg(&spi->dev, "9 <= n <= 16 bits per word\n");
+               chip->n_bytes = 2;
+               chip->read = READING_U16;
+               chip->write = WRITING_U16;
+       } else {
+               if (pl022->vendor->max_bpw >= 32) {
+                       dev_dbg(&spi->dev, "17 <= n <= 32 bits per word\n");
+                       chip->n_bytes = 4;
+                       chip->read = READING_U32;
+                       chip->write = WRITING_U32;
+               } else {
+                       dev_err(&spi->dev,
+                               "illegal data size for this controller!\n");
+                       dev_err(&spi->dev,
+                               "a standard pl022 can only handle "
+                               "1 <= n <= 16 bit words\n");
+                       goto err_config_params;
+               }
+       }
+
+       /* Now Initialize all register settings required for this chip */
+       chip->cr0 = 0;
+       chip->cr1 = 0;
+       chip->dmacr = 0;
+       chip->cpsr = 0;
+       if ((chip_info->com_mode == DMA_TRANSFER)
+           && ((pl022->master_info)->enable_dma)) {
+               chip->enable_dma = 1;
+               dev_dbg(&spi->dev, "DMA mode set in controller state\n");
+               status = process_dma_info(chip_info, chip);
+               if (status < 0)
+                       goto err_config_params;
+               SSP_WRITE_BITS(chip->dmacr, SSP_DMA_ENABLED,
+                              SSP_DMACR_MASK_RXDMAE, 0);
+               SSP_WRITE_BITS(chip->dmacr, SSP_DMA_ENABLED,
+                              SSP_DMACR_MASK_TXDMAE, 1);
+       } else {
+               chip->enable_dma = 0;
+               dev_dbg(&spi->dev, "DMA mode NOT set in controller state\n");
+               SSP_WRITE_BITS(chip->dmacr, SSP_DMA_DISABLED,
+                              SSP_DMACR_MASK_RXDMAE, 0);
+               SSP_WRITE_BITS(chip->dmacr, SSP_DMA_DISABLED,
+                              SSP_DMACR_MASK_TXDMAE, 1);
+       }
+
+       chip->cpsr = chip_info->clk_freq.cpsdvsr;
+
+       SSP_WRITE_BITS(chip->cr0, chip_info->data_size, SSP_CR0_MASK_DSS, 0);
+       SSP_WRITE_BITS(chip->cr0, chip_info->duplex, SSP_CR0_MASK_HALFDUP, 5);
+       SSP_WRITE_BITS(chip->cr0, chip_info->clk_pol, SSP_CR0_MASK_SPO, 6);
+       SSP_WRITE_BITS(chip->cr0, chip_info->clk_phase, SSP_CR0_MASK_SPH, 7);
+       SSP_WRITE_BITS(chip->cr0, chip_info->clk_freq.scr, SSP_CR0_MASK_SCR, 8);
+       SSP_WRITE_BITS(chip->cr0, chip_info->ctrl_len, SSP_CR0_MASK_CSS, 16);
+       SSP_WRITE_BITS(chip->cr0, chip_info->iface, SSP_CR0_MASK_FRF, 21);
+       SSP_WRITE_BITS(chip->cr1, chip_info->lbm, SSP_CR1_MASK_LBM, 0);
+       SSP_WRITE_BITS(chip->cr1, SSP_DISABLED, SSP_CR1_MASK_SSE, 1);
+       SSP_WRITE_BITS(chip->cr1, chip_info->hierarchy, SSP_CR1_MASK_MS, 2);
+       SSP_WRITE_BITS(chip->cr1, chip_info->slave_tx_disable, SSP_CR1_MASK_SOD, 3);
+       SSP_WRITE_BITS(chip->cr1, chip_info->endian_rx, SSP_CR1_MASK_RENDN, 4);
+       SSP_WRITE_BITS(chip->cr1, chip_info->endian_tx, SSP_CR1_MASK_TENDN, 5);
+       SSP_WRITE_BITS(chip->cr1, chip_info->wait_state, SSP_CR1_MASK_MWAIT, 6);
+       SSP_WRITE_BITS(chip->cr1, chip_info->rx_lev_trig, SSP_CR1_MASK_RXIFLSEL, 7);
+       SSP_WRITE_BITS(chip->cr1, chip_info->tx_lev_trig, SSP_CR1_MASK_TXIFLSEL, 10);
+
+       /* Save controller_state */
+       spi_set_ctldata(spi, chip);
+       return status;
+ err_config_params:
+ err_first_setup:
+       kfree(chip);
+       return status;
+}
+
+/**
+ * pl022_cleanup - cleanup function registered to SPI master framework
+ * @spi: spi device which is requesting cleanup
+ *
+ * This function is registered to the SPI framework for this SPI master
+ * controller. It will free the runtime state of chip.
+ */
+static void pl022_cleanup(struct spi_device *spi)
+{
+       struct chip_data *chip = spi_get_ctldata(spi);
+
+       spi_set_ctldata(spi, NULL);
+       kfree(chip);
+}
+
+
+static int __init
+pl022_probe(struct amba_device *adev, struct amba_id *id)
+{
+       struct device *dev = &adev->dev;
+       struct pl022_ssp_controller *platform_info = adev->dev.platform_data;
+       struct spi_master *master;
+       struct pl022 *pl022 = NULL;     /*Data for this driver */
+       int status = 0;
+
+       dev_info(&adev->dev,
+                "ARM PL022 driver, device ID: 0x%08x\n", adev->periphid);
+       if (platform_info == NULL) {
+               dev_err(&adev->dev, "probe - no platform data supplied\n");
+               status = -ENODEV;
+               goto err_no_pdata;
+       }
+
+       /* Allocate master with space for data */
+       master = spi_alloc_master(dev, sizeof(struct pl022));
+       if (master == NULL) {
+               dev_err(&adev->dev, "probe - cannot alloc SPI master\n");
+               status = -ENOMEM;
+               goto err_no_master;
+       }
+
+       pl022 = spi_master_get_devdata(master);
+       pl022->master = master;
+       pl022->master_info = platform_info;
+       pl022->adev = adev;
+       pl022->vendor = id->data;
+
+       /*
+        * Bus Number Which has been Assigned to this SSP controller
+        * on this board
+        */
+       master->bus_num = platform_info->bus_id;
+       master->num_chipselect = platform_info->num_chipselect;
+       master->cleanup = pl022_cleanup;
+       master->setup = pl022_setup;
+       master->transfer = pl022_transfer;
+
+       dev_dbg(&adev->dev, "BUSNO: %d\n", master->bus_num);
+
+       status = amba_request_regions(adev, NULL);
+       if (status)
+               goto err_no_ioregion;
+
+       pl022->virtbase = ioremap(adev->res.start, resource_size(&adev->res));
+       if (pl022->virtbase == NULL) {
+               status = -ENOMEM;
+               goto err_no_ioremap;
+       }
+       printk(KERN_INFO "pl022: mapped registers from 0x%08x to %p\n",
+              adev->res.start, pl022->virtbase);
+
+       pl022->clk = clk_get(&adev->dev, NULL);
+       if (IS_ERR(pl022->clk)) {
+               status = PTR_ERR(pl022->clk);
+               dev_err(&adev->dev, "could not retrieve SSP/SPI bus clock\n");
+               goto err_no_clk;
+       }
+
+       /* Disable SSP */
+       clk_enable(pl022->clk);
+       writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)),
+              SSP_CR1(pl022->virtbase));
+       load_ssp_default_config(pl022);
+       clk_disable(pl022->clk);
+
+       status = request_irq(adev->irq[0], pl022_interrupt_handler, 0, "pl022",
+                            pl022);
+       if (status < 0) {
+               dev_err(&adev->dev, "probe - cannot get IRQ (%d)\n", status);
+               goto err_no_irq;
+       }
+       /* Initialize and start queue */
+       status = init_queue(pl022);
+       if (status != 0) {
+               dev_err(&adev->dev, "probe - problem initializing queue\n");
+               goto err_init_queue;
+       }
+       status = start_queue(pl022);
+       if (status != 0) {
+               dev_err(&adev->dev, "probe - problem starting queue\n");
+               goto err_start_queue;
+       }
+       /* Register with the SPI framework */
+       amba_set_drvdata(adev, pl022);
+       status = spi_register_master(master);
+       if (status != 0) {
+               dev_err(&adev->dev,
+                       "probe - problem registering spi master\n");
+               goto err_spi_register;
+       }
+       dev_dbg(dev, "probe succeded\n");
+       return 0;
+
+ err_spi_register:
+ err_start_queue:
+ err_init_queue:
+       destroy_queue(pl022);
+       free_irq(adev->irq[0], pl022);
+ err_no_irq:
+       clk_put(pl022->clk);
+ err_no_clk:
+       iounmap(pl022->virtbase);
+ err_no_ioremap:
+       amba_release_regions(adev);
+ err_no_ioregion:
+       spi_master_put(master);
+ err_no_master:
+ err_no_pdata:
+       return status;
+}
+
+static int __exit
+pl022_remove(struct amba_device *adev)
+{
+       struct pl022 *pl022 = amba_get_drvdata(adev);
+       int status = 0;
+       if (!pl022)
+               return 0;
+
+       /* Remove the queue */
+       status = destroy_queue(pl022);
+       if (status != 0) {
+               dev_err(&adev->dev,
+                       "queue remove failed (%d)\n", status);
+               return status;
+       }
+       load_ssp_default_config(pl022);
+       free_irq(adev->irq[0], pl022);
+       clk_disable(pl022->clk);
+       clk_put(pl022->clk);
+       iounmap(pl022->virtbase);
+       amba_release_regions(adev);
+       tasklet_disable(&pl022->pump_transfers);
+       spi_unregister_master(pl022->master);
+       spi_master_put(pl022->master);
+       amba_set_drvdata(adev, NULL);
+       dev_dbg(&adev->dev, "remove succeded\n");
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int pl022_suspend(struct amba_device *adev, pm_message_t state)
+{
+       struct pl022 *pl022 = amba_get_drvdata(adev);
+       int status = 0;
+
+       status = stop_queue(pl022);
+       if (status) {
+               dev_warn(&adev->dev, "suspend cannot stop queue\n");
+               return status;
+       }
+
+       clk_enable(pl022->clk);
+       load_ssp_default_config(pl022);
+       clk_disable(pl022->clk);
+       dev_dbg(&adev->dev, "suspended\n");
+       return 0;
+}
+
+static int pl022_resume(struct amba_device *adev)
+{
+       struct pl022 *pl022 = amba_get_drvdata(adev);
+       int status = 0;
+
+       /* Start the queue running */
+       status = start_queue(pl022);
+       if (status)
+               dev_err(&adev->dev, "problem starting queue (%d)\n", status);
+       else
+               dev_dbg(&adev->dev, "resumed\n");
+
+       return status;
+}
+#else
+#define pl022_suspend NULL
+#define pl022_resume NULL
+#endif /* CONFIG_PM */
+
+static struct vendor_data vendor_arm = {
+       .fifodepth = 8,
+       .max_bpw = 16,
+       .unidir = false,
+};
+
+
+static struct vendor_data vendor_st = {
+       .fifodepth = 32,
+       .max_bpw = 32,
+       .unidir = false,
+};
+
+static struct amba_id pl022_ids[] = {
+       {
+               /*
+                * ARM PL022 variant, this has a 16bit wide
+                * and 8 locations deep TX/RX FIFO
+                */
+               .id     = 0x00041022,
+               .mask   = 0x000fffff,
+               .data   = &vendor_arm,
+       },
+       {
+               /*
+                * ST Micro derivative, this has 32bit wide
+                * and 32 locations deep TX/RX FIFO
+                */
+               .id     = 0x00108022,
+               .mask   = 0xffffffff,
+               .data   = &vendor_st,
+       },
+       { 0, 0 },
+};
+
+static struct amba_driver pl022_driver = {
+       .drv = {
+               .name   = "ssp-pl022",
+       },
+       .id_table       = pl022_ids,
+       .probe          = pl022_probe,
+       .remove         = __exit_p(pl022_remove),
+       .suspend        = pl022_suspend,
+       .resume         = pl022_resume,
+};
+
+
+static int __init pl022_init(void)
+{
+       return amba_driver_register(&pl022_driver);
+}
+
+module_init(pl022_init);
+
+static void __exit pl022_exit(void)
+{
+       amba_driver_unregister(&pl022_driver);
+}
+
+module_exit(pl022_exit);
+
+MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
+MODULE_DESCRIPTION("PL022 SSP Controller Driver");
+MODULE_LICENSE("GPL");
index f2447a5476bb8eb29065eab44c2832f2f31a9059..bbf9371cd2846c56e3650b4e7f88b8b05a820616 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
 #include <linux/platform_device.h>
+#include <linux/gpio.h>
 
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
index 9f6772bc68c2e0893abbe5325134b754d35c9798..1c2907c1dc818b91bc5c08d086f36052b086e10c 100644 (file)
@@ -2,7 +2,7 @@ This is a driver for the WIS GO7007SB multi-format video encoder.
 
 Pete Eberlein <pete@sensoray.com>
 
-The driver was orignally released under the GPL and is currently hosted at:
+The driver was originally released under the GPL and is currently hosted at:
 http://nikosapi.org/wiki/index.php/WIS_Go7007_Linux_driver
 The go7007 firmware can be acquired from the package on the site above.
 
@@ -24,7 +24,7 @@ These should be used instead of the non-standard GO7007 ioctls described
 below.
 
 
-The README files from the orignal package appear below:
+The README files from the original package appears below:
 
 ---------------------------------------------------------------------------
                      WIS GO7007SB Public Linux Driver
index f9ceef4322a329887c0157631c37c14dcfe80f71..7f82c905763d2fa1cbe067b5333d8b833700aefc 100644 (file)
@@ -3,7 +3,7 @@ characters 0 to 7. The escape code to define a new character is
 '\e[LG' followed by one digit from 0 to 7, representing the character
 number, and up to 8 couples of hex digits terminated by a semi-colon
 (';'). Each couple of digits represents a line, with 1-bits for each
-illuminated pixel with LSB on the right. Lines are numberred from the
+illuminated pixel with LSB on the right. Lines are numbered from the
 top of the character to the bottom. On a 5x7 matrix, only the 5 lower
 bits of the 7 first bytes are used for each character. If the string
 is incomplete, only complete lines will be redefined. Here are some
index c00f9ab9c46cb25729a033d16007df2c7ee78ba0..2edf2999f5c8d4649d3907c64ef5ebccfdd2c0f6 100644 (file)
@@ -5664,7 +5664,7 @@ VOID      AsicUpdateProtect(
 #if 0
        MacReg |= (pAd->CommonCfg.RtsThreshold << 8);
 #else
-       // If the user want disable RtsThreshold and enbale Amsdu/Ralink-Aggregation, set the RtsThreshold as 4096
+       // If the user want disable RtsThreshold and enable Amsdu/Ralink-Aggregation, set the RtsThreshold as 4096
         if ((
 #ifdef DOT11_N_SUPPORT
                        (pAd->CommonCfg.BACapability.field.AmsduEnable) ||
index 8a82cee8bf269b622e3efeb6b298e78cd715c195..a26bc033337ddb303a9b15858c4f52a84752b221 100644 (file)
@@ -5561,7 +5561,7 @@ VOID      AsicUpdateProtect(
 #if 0
        MacReg |= (pAd->CommonCfg.RtsThreshold << 8);
 #else
-       // If the user want disable RtsThreshold and enbale Amsdu/Ralink-Aggregation, set the RtsThreshold as 4096
+       // If the user want disable RtsThreshold and enable Amsdu/Ralink-Aggregation, set the RtsThreshold as 4096
         if ((
 #ifdef DOT11_N_SUPPORT
                        (pAd->CommonCfg.BACapability.field.AmsduEnable) ||
index 0ffbfa36699eb42655fae3899d681dadf7ca073d..0189bab013cf4c28a1f48b9c3f3e83810728ac26 100644 (file)
@@ -5575,7 +5575,7 @@ VOID      AsicUpdateProtect(
        RTMP_IO_READ32(pAd, TX_RTS_CFG, &MacReg);
        MacReg &= 0xFF0000FF;
 
-       // If the user want disable RtsThreshold and enbale Amsdu/Ralink-Aggregation, set the RtsThreshold as 4096
+       // If the user want disable RtsThreshold and enable Amsdu/Ralink-Aggregation, set the RtsThreshold as 4096
     if ((
 #ifdef DOT11_N_SUPPORT
                (pAd->CommonCfg.BACapability.field.AmsduEnable) ||
index 888198c9a1068503309e1f831ed4e1768dee96e1..824e65bdc4334cb3048d2d2e867b02f92329f73a 100644 (file)
@@ -2424,7 +2424,7 @@ int hfa384x_drvr_ramdl_write(hfa384x_t *hw, u32 daddr, void *buf, u32 len)
 *      0               success
 *      >0              f/w reported error - f/w status code
 *      <0              driver reported error
-*      -ETIMEOUT       timout waiting for the cmd regs to become
+*      -ETIMEDOUT      timout waiting for the cmd regs to become
 *                      available, or waiting for the control reg
 *                      to indicate the Aux port is enabled.
 *      -ENODATA        the buffer does NOT contain a valid PDA.
index c6c816b7ecb5d30cacf1dbfe4ca1115df3553788..5eee3f82be5d98d0cb1df531c9d78573c482ddbc 100644 (file)
@@ -22,6 +22,7 @@ config USB_ARCH_HAS_HCD
        default y if PCMCIA && !M32R                    # sl811_cs
        default y if ARM                                # SL-811
        default y if SUPERH                             # r8a66597-hcd
+       default y if MICROBLAZE
        default PCI
 
 # many non-PCI SOC chips embed OHCI
index 7cf74f8c2db1ea832848acc540399bf9c5d582e7..b0dbf4157d29d5b26779f95e081e358beec4c86d 100644 (file)
@@ -47,7 +47,7 @@ static int usb_hcd_ep93xx_probe(const struct hc_driver *driver,
        struct usb_hcd *hcd;
 
        if (pdev->resource[1].flags != IORESOURCE_IRQ) {
-               pr_debug("resource[1] is not IORESOURCE_IRQ");
+               dbg("resource[1] is not IORESOURCE_IRQ");
                return -ENOMEM;
        }
 
@@ -65,12 +65,18 @@ static int usb_hcd_ep93xx_probe(const struct hc_driver *driver,
 
        hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
        if (hcd->regs == NULL) {
-               pr_debug("ioremap failed");
+               dbg("ioremap failed");
                retval = -ENOMEM;
                goto err2;
        }
 
-       usb_host_clock = clk_get(&pdev->dev, "usb_host");
+       usb_host_clock = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(usb_host_clock)) {
+               dbg("clk_get failed");
+               retval = PTR_ERR(usb_host_clock);
+               goto err3;
+       }
+
        ep93xx_start_hc(&pdev->dev);
 
        ohci_hcd_init(hcd_to_ohci(hcd));
@@ -80,6 +86,7 @@ static int usb_hcd_ep93xx_probe(const struct hc_driver *driver,
                return retval;
 
        ep93xx_stop_hc(&pdev->dev);
+err3:
        iounmap(hcd->regs);
 err2:
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
index eabf20eeb370ee4ce578c831b36003a7837d2bd9..db964db42d3c0d0c258d56395ed4f14c7fb89c61 100644 (file)
@@ -102,7 +102,7 @@ struct edgeport_port {
        __u8 shadow_mcr;
        __u8 shadow_lsr;
        __u8 lsr_mask;
-       __u32 ump_read_timeout;         /* Number of miliseconds the UMP will
+       __u32 ump_read_timeout;         /* Number of milliseconds the UMP will
                                           wait without data before completing
                                           a read short */
        int baud_rate;
index 0048f1185a60eebb0e393390b50b944665904be8..2b5a691064b719fcfa94fdb4bcac82bf0fb26205 100644 (file)
@@ -397,7 +397,7 @@ config FB_SA1100
 
 config FB_IMX
        tristate "Motorola i.MX LCD support"
-       depends on FB && (ARCH_IMX || ARCH_MX2)
+       depends on FB && (ARCH_MX1 || ARCH_MX2)
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
@@ -1759,6 +1759,16 @@ config FB_68328
          Say Y here if you want to support the built-in frame buffer of
          the Motorola 68328 CPU family.
 
+config FB_PXA168
+       tristate "PXA168/910 LCD framebuffer support"
+       depends on FB && (CPU_PXA168 || CPU_PXA910)
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       ---help---
+         Frame buffer driver for the built-in LCD controller in the Marvell
+         MMP processor.
+
 config FB_PXA
        tristate "PXA LCD framebuffer support"
        depends on FB && ARCH_PXA
@@ -1996,7 +2006,7 @@ config FB_PS3_DEFAULT_SIZE_M
 
 config FB_XILINX
        tristate "Xilinx frame buffer support"
-       depends on FB && XILINX_VIRTEX
+       depends on FB && (XILINX_VIRTEX || MICROBLAZE)
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
index d8d0be5151e37f43ac11e86935d95f39e5beadf4..01a819f47371420ed9c138155ce77d2c417a2d13 100644 (file)
@@ -97,6 +97,7 @@ obj-$(CONFIG_FB_GBE)              += gbefb.o
 obj-$(CONFIG_FB_CIRRUS)                  += cirrusfb.o
 obj-$(CONFIG_FB_ASILIANT)        += asiliantfb.o
 obj-$(CONFIG_FB_PXA)             += pxafb.o
+obj-$(CONFIG_FB_PXA168)                  += pxa168fb.o
 obj-$(CONFIG_FB_W100)            += w100fb.o
 obj-$(CONFIG_FB_TMIO)            += tmiofb.o
 obj-$(CONFIG_FB_AU1100)                  += au1100fb.o
index d1f80bac54f0db342f97dbc4471370f310cb6261..fb8163d181abbb5383535b37e1b85a26367d5432 100644 (file)
@@ -351,7 +351,7 @@ static int clcdfb_register(struct clcd_fb *fb)
        }
 
        fb->fb.fix.mmio_start   = fb->dev->res.start;
-       fb->fb.fix.mmio_len     = 4096;
+       fb->fb.fix.mmio_len     = resource_size(&fb->dev->res);
 
        fb->regs = ioremap(fb->fb.fix.mmio_start, fb->fb.fix.mmio_len);
        if (!fb->regs) {
index 35e8eb02b9e90e0b008d557ed2065fcaff98f41b..e4e4d433b00701a16bac2255bd54a1a10b928188 100644 (file)
@@ -354,7 +354,7 @@ static int default_crt_on __devinitdata = 0;
 static int default_lcd_on __devinitdata = 1;
 
 #ifdef CONFIG_MTRR
-static int mtrr = 1;
+static bool mtrr = true;
 #endif
 
 #ifdef CONFIG_PMAC_BACKLIGHT
index 83c5cefc266c6f75562d36537589704a89352185..da7c01b39be248129a1a5f99274695cc510872d2 100644 (file)
@@ -1736,10 +1736,8 @@ static int __init cyber2000fb_init(void)
 
 #ifdef CONFIG_ARCH_SHARK
        err = cyberpro_vl_probe();
-       if (!err) {
+       if (!err)
                ret = 0;
-               __module_get(THIS_MODULE);
-       }
 #endif
 #ifdef CONFIG_PCI
        err = pci_register_driver(&cyberpro_driver);
@@ -1749,14 +1747,15 @@ static int __init cyber2000fb_init(void)
 
        return ret ? err : 0;
 }
+module_init(cyber2000fb_init);
 
+#ifndef CONFIG_ARCH_SHARK
 static void __exit cyberpro_exit(void)
 {
        pci_unregister_driver(&cyberpro_driver);
 }
-
-module_init(cyber2000fb_init);
 module_exit(cyberpro_exit);
+#endif
 
 MODULE_AUTHOR("Russell King");
 MODULE_DESCRIPTION("CyberPro 2000, 2010 and 5000 framebuffer driver");
index 9894de1c9b9fbe116498b6f31d5a6351434f8b18..b7af5256e887e0522e704a2165311220a5904666 100644 (file)
@@ -706,7 +706,7 @@ static void mx3fb_dma_done(void *arg)
        dev_dbg(mx3fb->dev, "irq %d callback\n", ichannel->eof_irq);
 
        /* We only need one interrupt, it will be re-enabled as needed */
-       disable_irq(ichannel->eof_irq);
+       disable_irq_nosync(ichannel->eof_irq);
 
        complete(&mx3_fbi->flip_cmpl);
 }
@@ -1366,7 +1366,7 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan)
 
        mx3fb_blank(FB_BLANK_UNBLANK, fbi);
 
-       dev_info(dev, "mx3fb: fb registered, using mode %s\n", fb_mode);
+       dev_info(dev, "registered, using mode %s\n", fb_mode);
 
        ret = register_framebuffer(fbi);
        if (ret < 0)
index 8aa6e47202b943369cb23912b0f8c66ed613877a..5d4f34887a22bb370f6f5bc2bedd05d2fc190b83 100644 (file)
@@ -133,8 +133,7 @@ struct {
        struct lcd_ctrl_extif   *extif;
        struct lcd_ctrl         *int_ctrl;
 
-       void                    (*power_up)(struct device *dev);
-       void                    (*power_down)(struct device *dev);
+       struct clk              *sys_ck;
 } hwa742;
 
 struct lcd_ctrl hwa742_ctrl;
@@ -915,14 +914,13 @@ static void hwa742_suspend(void)
        hwa742_set_update_mode(OMAPFB_UPDATE_DISABLED);
        /* Enable sleep mode */
        hwa742_write_reg(HWA742_POWER_SAVE, 1 << 1);
-       if (hwa742.power_down != NULL)
-               hwa742.power_down(hwa742.fbdev->dev);
+       clk_disable(hwa742.sys_ck);
 }
 
 static void hwa742_resume(void)
 {
-       if (hwa742.power_up != NULL)
-               hwa742.power_up(hwa742.fbdev->dev);
+       clk_enable(hwa742.sys_ck);
+
        /* Disable sleep mode */
        hwa742_write_reg(HWA742_POWER_SAVE, 0);
        while (1) {
@@ -955,14 +953,13 @@ static int hwa742_init(struct omapfb_device *fbdev, int ext_mode,
        omapfb_conf = fbdev->dev->platform_data;
        ctrl_conf = omapfb_conf->ctrl_platform_data;
 
-       if (ctrl_conf == NULL || ctrl_conf->get_clock_rate == NULL) {
+       if (ctrl_conf == NULL) {
                dev_err(fbdev->dev, "HWA742: missing platform data\n");
                r = -ENOENT;
                goto err1;
        }
 
-       hwa742.power_down = ctrl_conf->power_down;
-       hwa742.power_up = ctrl_conf->power_up;
+       hwa742.sys_ck = clk_get(NULL, "hwa_sys_ck");
 
        spin_lock_init(&hwa742.req_lock);
 
@@ -972,12 +969,11 @@ static int hwa742_init(struct omapfb_device *fbdev, int ext_mode,
        if ((r = hwa742.extif->init(fbdev)) < 0)
                goto err2;
 
-       ext_clk = ctrl_conf->get_clock_rate(fbdev->dev);
+       ext_clk = clk_get_rate(hwa742.sys_ck);
        if ((r = calc_extif_timings(ext_clk, &extif_mem_div)) < 0)
                goto err3;
        hwa742.extif->set_timings(&hwa742.reg_timings);
-       if (hwa742.power_up != NULL)
-               hwa742.power_up(fbdev->dev);
+       clk_enable(hwa742.sys_ck);
 
        calc_hwa742_clk_rates(ext_clk, &sys_clk, &pix_clk);
        if ((r = calc_extif_timings(sys_clk, &extif_mem_div)) < 0)
@@ -1040,8 +1036,7 @@ static int hwa742_init(struct omapfb_device *fbdev, int ext_mode,
 
        return 0;
 err4:
-       if (hwa742.power_down != NULL)
-               hwa742.power_down(fbdev->dev);
+       clk_disable(hwa742.sys_ck);
 err3:
        hwa742.extif->cleanup();
 err2:
@@ -1055,8 +1050,7 @@ static void hwa742_cleanup(void)
        hwa742_set_update_mode(OMAPFB_UPDATE_DISABLED);
        hwa742.extif->cleanup();
        hwa742.int_ctrl->cleanup();
-       if (hwa742.power_down != NULL)
-               hwa742.power_down(hwa742.fbdev->dev);
+       clk_disable(hwa742.sys_ck);
 }
 
 struct lcd_ctrl hwa742_ctrl = {
diff --git a/drivers/video/pxa168fb.c b/drivers/video/pxa168fb.c
new file mode 100644 (file)
index 0000000..84d8327
--- /dev/null
@@ -0,0 +1,803 @@
+/*
+ * linux/drivers/video/pxa168fb.c -- Marvell PXA168 LCD Controller
+ *
+ *  Copyright (C) 2008 Marvell International Ltd.
+ *  All rights reserved.
+ *
+ *  2009-02-16  adapted from original version for PXA168/910
+ *              Jun Nie <njun@marvell.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/uaccess.h>
+#include <video/pxa168fb.h>
+
+#include "pxa168fb.h"
+
+#define DEFAULT_REFRESH                60      /* Hz */
+
+static int determine_best_pix_fmt(struct fb_var_screeninfo *var)
+{
+       /*
+        * Pseudocolor mode?
+        */
+       if (var->bits_per_pixel == 8)
+               return PIX_FMT_PSEUDOCOLOR;
+
+       /*
+        * Check for 565/1555.
+        */
+       if (var->bits_per_pixel == 16 && var->red.length <= 5 &&
+           var->green.length <= 6 && var->blue.length <= 5) {
+               if (var->transp.length == 0) {
+                       if (var->red.offset >= var->blue.offset)
+                               return PIX_FMT_RGB565;
+                       else
+                               return PIX_FMT_BGR565;
+               }
+
+               if (var->transp.length == 1 && var->green.length <= 5) {
+                       if (var->red.offset >= var->blue.offset)
+                               return PIX_FMT_RGB1555;
+                       else
+                               return PIX_FMT_BGR1555;
+               }
+
+               /* fall through */
+       }
+
+       /*
+        * Check for 888/A888.
+        */
+       if (var->bits_per_pixel <= 32 && var->red.length <= 8 &&
+           var->green.length <= 8 && var->blue.length <= 8) {
+               if (var->bits_per_pixel == 24 && var->transp.length == 0) {
+                       if (var->red.offset >= var->blue.offset)
+                               return PIX_FMT_RGB888PACK;
+                       else
+                               return PIX_FMT_BGR888PACK;
+               }
+
+               if (var->bits_per_pixel == 32 && var->transp.length == 8) {
+                       if (var->red.offset >= var->blue.offset)
+                               return PIX_FMT_RGBA888;
+                       else
+                               return PIX_FMT_BGRA888;
+               } else {
+                       if (var->red.offset >= var->blue.offset)
+                               return PIX_FMT_RGB888UNPACK;
+                       else
+                               return PIX_FMT_BGR888UNPACK;
+               }
+
+               /* fall through */
+       }
+
+       return -EINVAL;
+}
+
+static void set_pix_fmt(struct fb_var_screeninfo *var, int pix_fmt)
+{
+       switch (pix_fmt) {
+       case PIX_FMT_RGB565:
+               var->bits_per_pixel = 16;
+               var->red.offset = 11;    var->red.length = 5;
+               var->green.offset = 5;   var->green.length = 6;
+               var->blue.offset = 0;    var->blue.length = 5;
+               var->transp.offset = 0;  var->transp.length = 0;
+               break;
+       case PIX_FMT_BGR565:
+               var->bits_per_pixel = 16;
+               var->red.offset = 0;     var->red.length = 5;
+               var->green.offset = 5;   var->green.length = 6;
+               var->blue.offset = 11;   var->blue.length = 5;
+               var->transp.offset = 0;  var->transp.length = 0;
+               break;
+       case PIX_FMT_RGB1555:
+               var->bits_per_pixel = 16;
+               var->red.offset = 10;    var->red.length = 5;
+               var->green.offset = 5;   var->green.length = 5;
+               var->blue.offset = 0;    var->blue.length = 5;
+               var->transp.offset = 15; var->transp.length = 1;
+               break;
+       case PIX_FMT_BGR1555:
+               var->bits_per_pixel = 16;
+               var->red.offset = 0;     var->red.length = 5;
+               var->green.offset = 5;   var->green.length = 5;
+               var->blue.offset = 10;   var->blue.length = 5;
+               var->transp.offset = 15; var->transp.length = 1;
+               break;
+       case PIX_FMT_RGB888PACK:
+               var->bits_per_pixel = 24;
+               var->red.offset = 16;    var->red.length = 8;
+               var->green.offset = 8;   var->green.length = 8;
+               var->blue.offset = 0;    var->blue.length = 8;
+               var->transp.offset = 0;  var->transp.length = 0;
+               break;
+       case PIX_FMT_BGR888PACK:
+               var->bits_per_pixel = 24;
+               var->red.offset = 0;     var->red.length = 8;
+               var->green.offset = 8;   var->green.length = 8;
+               var->blue.offset = 16;   var->blue.length = 8;
+               var->transp.offset = 0;  var->transp.length = 0;
+               break;
+       case PIX_FMT_RGBA888:
+               var->bits_per_pixel = 32;
+               var->red.offset = 16;    var->red.length = 8;
+               var->green.offset = 8;   var->green.length = 8;
+               var->blue.offset = 0;    var->blue.length = 8;
+               var->transp.offset = 24; var->transp.length = 8;
+               break;
+       case PIX_FMT_BGRA888:
+               var->bits_per_pixel = 32;
+               var->red.offset = 0;     var->red.length = 8;
+               var->green.offset = 8;   var->green.length = 8;
+               var->blue.offset = 16;   var->blue.length = 8;
+               var->transp.offset = 24; var->transp.length = 8;
+               break;
+       case PIX_FMT_PSEUDOCOLOR:
+               var->bits_per_pixel = 8;
+               var->red.offset = 0;     var->red.length = 8;
+               var->green.offset = 0;   var->green.length = 8;
+               var->blue.offset = 0;    var->blue.length = 8;
+               var->transp.offset = 0;  var->transp.length = 0;
+               break;
+       }
+}
+
+static void set_mode(struct pxa168fb_info *fbi, struct fb_var_screeninfo *var,
+                    struct fb_videomode *mode, int pix_fmt, int ystretch)
+{
+       struct fb_info *info = fbi->info;
+
+       set_pix_fmt(var, pix_fmt);
+
+       var->xres = mode->xres;
+       var->yres = mode->yres;
+       var->xres_virtual = max(var->xres, var->xres_virtual);
+       if (ystretch)
+               var->yres_virtual = info->fix.smem_len /
+                       (var->xres_virtual * (var->bits_per_pixel >> 3));
+       else
+               var->yres_virtual = max(var->yres, var->yres_virtual);
+       var->grayscale = 0;
+       var->accel_flags = FB_ACCEL_NONE;
+       var->pixclock = mode->pixclock;
+       var->left_margin = mode->left_margin;
+       var->right_margin = mode->right_margin;
+       var->upper_margin = mode->upper_margin;
+       var->lower_margin = mode->lower_margin;
+       var->hsync_len = mode->hsync_len;
+       var->vsync_len = mode->vsync_len;
+       var->sync = mode->sync;
+       var->vmode = FB_VMODE_NONINTERLACED;
+       var->rotate = FB_ROTATE_UR;
+}
+
+static int pxa168fb_check_var(struct fb_var_screeninfo *var,
+                             struct fb_info *info)
+{
+       struct pxa168fb_info *fbi = info->par;
+       int pix_fmt;
+
+       /*
+        * Determine which pixel format we're going to use.
+        */
+       pix_fmt = determine_best_pix_fmt(var);
+       if (pix_fmt < 0)
+               return pix_fmt;
+       set_pix_fmt(var, pix_fmt);
+       fbi->pix_fmt = pix_fmt;
+
+       /*
+        * Basic geometry sanity checks.
+        */
+       if (var->xoffset + var->xres > var->xres_virtual)
+               return -EINVAL;
+       if (var->yoffset + var->yres > var->yres_virtual)
+               return -EINVAL;
+       if (var->xres + var->right_margin +
+           var->hsync_len + var->left_margin > 2048)
+               return -EINVAL;
+       if (var->yres + var->lower_margin +
+           var->vsync_len + var->upper_margin > 2048)
+               return -EINVAL;
+
+       /*
+        * Check size of framebuffer.
+        */
+       if (var->xres_virtual * var->yres_virtual *
+           (var->bits_per_pixel >> 3) > info->fix.smem_len)
+               return -EINVAL;
+
+       return 0;
+}
+
+/*
+ * The hardware clock divider has an integer and a fractional
+ * stage:
+ *
+ *     clk2 = clk_in / integer_divider
+ *     clk_out = clk2 * (1 - (fractional_divider >> 12))
+ *
+ * Calculate integer and fractional divider for given clk_in
+ * and clk_out.
+ */
+static void set_clock_divider(struct pxa168fb_info *fbi,
+                             const struct fb_videomode *m)
+{
+       int divider_int;
+       int needed_pixclk;
+       u64 div_result;
+       u32 x = 0;
+
+       /*
+        * Notice: The field pixclock is used by linux fb
+        * is in pixel second. E.g. struct fb_videomode &
+        * struct fb_var_screeninfo
+        */
+
+       /*
+        * Check input values.
+        */
+       if (!m || !m->pixclock || !m->refresh) {
+               dev_err(fbi->dev, "Input refresh or pixclock is wrong.\n");
+               return;
+       }
+
+       /*
+        * Using PLL/AXI clock.
+        */
+       x = 0x80000000;
+
+       /*
+        * Calc divider according to refresh rate.
+        */
+       div_result = 1000000000000ll;
+       do_div(div_result, m->pixclock);
+       needed_pixclk = (u32)div_result;
+
+       divider_int = clk_get_rate(fbi->clk) / needed_pixclk;
+
+       /* check whether divisor is too small. */
+       if (divider_int < 2) {
+               dev_warn(fbi->dev, "Warning: clock source is too slow."
+                               "Try smaller resolution\n");
+               divider_int = 2;
+       }
+
+       /*
+        * Set setting to reg.
+        */
+       x |= divider_int;
+       writel(x, fbi->reg_base + LCD_CFG_SCLK_DIV);
+}
+
+static void set_dma_control0(struct pxa168fb_info *fbi)
+{
+       u32 x;
+
+       /*
+        * Set bit to enable graphics DMA.
+        */
+       x = readl(fbi->reg_base + LCD_SPU_DMA_CTRL0);
+       x |= fbi->active ? 0x00000100 : 0;
+       fbi->active = 0;
+
+       /*
+        * If we are in a pseudo-color mode, we need to enable
+        * palette lookup.
+        */
+       if (fbi->pix_fmt == PIX_FMT_PSEUDOCOLOR)
+               x |= 0x10000000;
+
+       /*
+        * Configure hardware pixel format.
+        */
+       x &= ~(0xF << 16);
+       x |= (fbi->pix_fmt >> 1) << 16;
+
+       /*
+        * Check red and blue pixel swap.
+        * 1. source data swap
+        * 2. panel output data swap
+        */
+       x &= ~(1 << 12);
+       x |= ((fbi->pix_fmt & 1) ^ (fbi->panel_rbswap)) << 12;
+
+       writel(x, fbi->reg_base + LCD_SPU_DMA_CTRL0);
+}
+
+static void set_dma_control1(struct pxa168fb_info *fbi, int sync)
+{
+       u32 x;
+
+       /*
+        * Configure default bits: vsync triggers DMA, gated clock
+        * enable, power save enable, configure alpha registers to
+        * display 100% graphics, and set pixel command.
+        */
+       x = readl(fbi->reg_base + LCD_SPU_DMA_CTRL1);
+       x |= 0x2032ff81;
+
+       /*
+        * We trigger DMA on the falling edge of vsync if vsync is
+        * active low, or on the rising edge if vsync is active high.
+        */
+       if (!(sync & FB_SYNC_VERT_HIGH_ACT))
+               x |= 0x08000000;
+
+       writel(x, fbi->reg_base + LCD_SPU_DMA_CTRL1);
+}
+
+static void set_graphics_start(struct fb_info *info, int xoffset, int yoffset)
+{
+       struct pxa168fb_info *fbi = info->par;
+       struct fb_var_screeninfo *var = &info->var;
+       int pixel_offset;
+       unsigned long addr;
+
+       pixel_offset = (yoffset * var->xres_virtual) + xoffset;
+
+       addr = fbi->fb_start_dma + (pixel_offset * (var->bits_per_pixel >> 3));
+       writel(addr, fbi->reg_base + LCD_CFG_GRA_START_ADDR0);
+}
+
+static void set_dumb_panel_control(struct fb_info *info)
+{
+       struct pxa168fb_info *fbi = info->par;
+       struct pxa168fb_mach_info *mi = fbi->dev->platform_data;
+       u32 x;
+
+       /*
+        * Preserve enable flag.
+        */
+       x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL) & 0x00000001;
+
+       x |= (fbi->is_blanked ? 0x7 : mi->dumb_mode) << 28;
+       x |= mi->gpio_output_data << 20;
+       x |= mi->gpio_output_mask << 12;
+       x |= mi->panel_rgb_reverse_lanes ? 0x00000080 : 0;
+       x |= mi->invert_composite_blank ? 0x00000040 : 0;
+       x |= (info->var.sync & FB_SYNC_COMP_HIGH_ACT) ? 0x00000020 : 0;
+       x |= mi->invert_pix_val_ena ? 0x00000010 : 0;
+       x |= (info->var.sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 0x00000008;
+       x |= (info->var.sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 0x00000004;
+       x |= mi->invert_pixclock ? 0x00000002 : 0;
+
+       writel(x, fbi->reg_base + LCD_SPU_DUMB_CTRL);
+}
+
+static void set_dumb_screen_dimensions(struct fb_info *info)
+{
+       struct pxa168fb_info *fbi = info->par;
+       struct fb_var_screeninfo *v = &info->var;
+       int x;
+       int y;
+
+       x = v->xres + v->right_margin + v->hsync_len + v->left_margin;
+       y = v->yres + v->lower_margin + v->vsync_len + v->upper_margin;
+
+       writel((y << 16) | x, fbi->reg_base + LCD_SPUT_V_H_TOTAL);
+}
+
+static int pxa168fb_set_par(struct fb_info *info)
+{
+       struct pxa168fb_info *fbi = info->par;
+       struct fb_var_screeninfo *var = &info->var;
+       struct fb_videomode mode;
+       u32 x;
+       struct pxa168fb_mach_info *mi;
+
+       mi = fbi->dev->platform_data;
+
+       /*
+        * Set additional mode info.
+        */
+       if (fbi->pix_fmt == PIX_FMT_PSEUDOCOLOR)
+               info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+       else
+               info->fix.visual = FB_VISUAL_TRUECOLOR;
+       info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
+       info->fix.ypanstep = var->yres;
+
+       /*
+        * Disable panel output while we setup the display.
+        */
+       x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL);
+       writel(x & ~1, fbi->reg_base + LCD_SPU_DUMB_CTRL);
+
+       /*
+        * Configure global panel parameters.
+        */
+       writel((var->yres << 16) | var->xres,
+               fbi->reg_base + LCD_SPU_V_H_ACTIVE);
+
+       /*
+        * convet var to video mode
+        */
+       fb_var_to_videomode(&mode, &info->var);
+
+       /* Calculate clock divisor. */
+       set_clock_divider(fbi, &mode);
+
+       /* Configure dma ctrl regs. */
+       set_dma_control0(fbi);
+       set_dma_control1(fbi, info->var.sync);
+
+       /*
+        * Configure graphics DMA parameters.
+        */
+       x = readl(fbi->reg_base + LCD_CFG_GRA_PITCH);
+       x = (x & ~0xFFFF) | ((var->xres_virtual * var->bits_per_pixel) >> 3);
+       writel(x, fbi->reg_base + LCD_CFG_GRA_PITCH);
+       writel((var->yres << 16) | var->xres,
+               fbi->reg_base + LCD_SPU_GRA_HPXL_VLN);
+       writel((var->yres << 16) | var->xres,
+               fbi->reg_base + LCD_SPU_GZM_HPXL_VLN);
+
+       /*
+        * Configure dumb panel ctrl regs & timings.
+        */
+       set_dumb_panel_control(info);
+       set_dumb_screen_dimensions(info);
+
+       writel((var->left_margin << 16) | var->right_margin,
+                       fbi->reg_base + LCD_SPU_H_PORCH);
+       writel((var->upper_margin << 16) | var->lower_margin,
+                       fbi->reg_base + LCD_SPU_V_PORCH);
+
+       /*
+        * Re-enable panel output.
+        */
+       x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL);
+       writel(x | 1, fbi->reg_base + LCD_SPU_DUMB_CTRL);
+
+       return 0;
+}
+
+static unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
+{
+       return ((chan & 0xffff) >> (16 - bf->length)) << bf->offset;
+}
+
+static u32 to_rgb(u16 red, u16 green, u16 blue)
+{
+       red >>= 8;
+       green >>= 8;
+       blue >>= 8;
+
+       return (red << 16) | (green << 8) | blue;
+}
+
+static int
+pxa168fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
+                unsigned int blue, unsigned int trans, struct fb_info *info)
+{
+       struct pxa168fb_info *fbi = info->par;
+       u32 val;
+
+       if (info->var.grayscale)
+               red = green = blue = (19595 * red + 38470 * green +
+                                       7471 * blue) >> 16;
+
+       if (info->fix.visual == FB_VISUAL_TRUECOLOR && regno < 16) {
+               val =  chan_to_field(red,   &info->var.red);
+               val |= chan_to_field(green, &info->var.green);
+               val |= chan_to_field(blue , &info->var.blue);
+               fbi->pseudo_palette[regno] = val;
+       }
+
+       if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) {
+               val = to_rgb(red, green, blue);
+               writel(val, fbi->reg_base + LCD_SPU_SRAM_WRDAT);
+               writel(0x8300 | regno, fbi->reg_base + LCD_SPU_SRAM_CTRL);
+       }
+
+       return 0;
+}
+
+static int pxa168fb_blank(int blank, struct fb_info *info)
+{
+       struct pxa168fb_info *fbi = info->par;
+
+       fbi->is_blanked = (blank == FB_BLANK_UNBLANK) ? 0 : 1;
+       set_dumb_panel_control(info);
+
+       return 0;
+}
+
+static int pxa168fb_pan_display(struct fb_var_screeninfo *var,
+                               struct fb_info *info)
+{
+       set_graphics_start(info, var->xoffset, var->yoffset);
+
+       return 0;
+}
+
+static irqreturn_t pxa168fb_handle_irq(int irq, void *dev_id)
+{
+       struct pxa168fb_info *fbi = dev_id;
+       u32 isr = readl(fbi->reg_base + SPU_IRQ_ISR);
+
+       if ((isr & GRA_FRAME_IRQ0_ENA_MASK)) {
+
+               writel(isr & (~GRA_FRAME_IRQ0_ENA_MASK),
+                       fbi->reg_base + SPU_IRQ_ISR);
+
+               return IRQ_HANDLED;
+       }
+       return IRQ_NONE;
+}
+
+static struct fb_ops pxa168fb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_check_var   = pxa168fb_check_var,
+       .fb_set_par     = pxa168fb_set_par,
+       .fb_setcolreg   = pxa168fb_setcolreg,
+       .fb_blank       = pxa168fb_blank,
+       .fb_pan_display = pxa168fb_pan_display,
+       .fb_fillrect    = cfb_fillrect,
+       .fb_copyarea    = cfb_copyarea,
+       .fb_imageblit   = cfb_imageblit,
+};
+
+static int __init pxa168fb_init_mode(struct fb_info *info,
+                             struct pxa168fb_mach_info *mi)
+{
+       struct pxa168fb_info *fbi = info->par;
+       struct fb_var_screeninfo *var = &info->var;
+       int ret = 0;
+       u32 total_w, total_h, refresh;
+       u64 div_result;
+       const struct fb_videomode *m;
+
+       /*
+        * Set default value
+        */
+       refresh = DEFAULT_REFRESH;
+
+       /* try to find best video mode. */
+       m = fb_find_best_mode(&info->var, &info->modelist);
+       if (m)
+               fb_videomode_to_var(&info->var, m);
+
+       /* Init settings. */
+       var->xres_virtual = var->xres;
+       var->yres_virtual = info->fix.smem_len /
+               (var->xres_virtual * (var->bits_per_pixel >> 3));
+       dev_dbg(fbi->dev, "pxa168fb: find best mode: res = %dx%d\n",
+                               var->xres, var->yres);
+
+       /* correct pixclock. */
+       total_w = var->xres + var->left_margin + var->right_margin +
+                 var->hsync_len;
+       total_h = var->yres + var->upper_margin + var->lower_margin +
+                 var->vsync_len;
+
+       div_result = 1000000000000ll;
+       do_div(div_result, total_w * total_h * refresh);
+       var->pixclock = (u32)div_result;
+
+       return ret;
+}
+
+static int __init pxa168fb_probe(struct platform_device *pdev)
+{
+       struct pxa168fb_mach_info *mi;
+       struct fb_info *info = 0;
+       struct pxa168fb_info *fbi = 0;
+       struct resource *res;
+       struct clk *clk;
+       int irq, ret;
+
+       mi = pdev->dev.platform_data;
+       if (mi == NULL) {
+               dev_err(&pdev->dev, "no platform data defined\n");
+               return -EINVAL;
+       }
+
+       clk = clk_get(&pdev->dev, "LCDCLK");
+       if (IS_ERR(clk)) {
+               dev_err(&pdev->dev, "unable to get LCDCLK");
+               return PTR_ERR(clk);
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "no IO memory defined\n");
+               return -ENOENT;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "no IRQ defined\n");
+               return -ENOENT;
+       }
+
+       info = framebuffer_alloc(sizeof(struct pxa168fb_info), &pdev->dev);
+       if (info == NULL) {
+               clk_put(clk);
+               return -ENOMEM;
+       }
+
+       /* Initialize private data */
+       fbi = info->par;
+       fbi->info = info;
+       fbi->clk = clk;
+       fbi->dev = info->dev = &pdev->dev;
+       fbi->panel_rbswap = mi->panel_rbswap;
+       fbi->is_blanked = 0;
+       fbi->active = mi->active;
+
+       /*
+        * Initialise static fb parameters.
+        */
+       info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK |
+                     FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
+       info->node = -1;
+       strlcpy(info->fix.id, mi->id, 16);
+       info->fix.type = FB_TYPE_PACKED_PIXELS;
+       info->fix.type_aux = 0;
+       info->fix.xpanstep = 0;
+       info->fix.ypanstep = 0;
+       info->fix.ywrapstep = 0;
+       info->fix.mmio_start = res->start;
+       info->fix.mmio_len = res->end - res->start + 1;
+       info->fix.accel = FB_ACCEL_NONE;
+       info->fbops = &pxa168fb_ops;
+       info->pseudo_palette = fbi->pseudo_palette;
+
+       /*
+        * Map LCD controller registers.
+        */
+       fbi->reg_base = ioremap_nocache(res->start, res->end - res->start);
+       if (fbi->reg_base == NULL) {
+               ret = -ENOMEM;
+               goto failed;
+       }
+
+       /*
+        * Allocate framebuffer memory.
+        */
+       info->fix.smem_len = PAGE_ALIGN(DEFAULT_FB_SIZE);
+
+       info->screen_base = dma_alloc_writecombine(fbi->dev, info->fix.smem_len,
+                                               &fbi->fb_start_dma, GFP_KERNEL);
+       if (info->screen_base == NULL) {
+               ret = -ENOMEM;
+               goto failed;
+       }
+
+       info->fix.smem_start = (unsigned long)fbi->fb_start_dma;
+
+       /*
+        * Set video mode according to platform data.
+        */
+       set_mode(fbi, &info->var, mi->modes, mi->pix_fmt, 1);
+
+       fb_videomode_to_modelist(mi->modes, mi->num_modes, &info->modelist);
+
+       /*
+        * init video mode data.
+        */
+       pxa168fb_init_mode(info, mi);
+
+       ret = pxa168fb_check_var(&info->var, info);
+       if (ret)
+               goto failed_free_fbmem;
+
+       /*
+        * Fill in sane defaults.
+        */
+       ret = pxa168fb_check_var(&info->var, info);
+       if (ret)
+               goto failed;
+
+       /*
+        * enable controller clock
+        */
+       clk_enable(fbi->clk);
+
+       pxa168fb_set_par(info);
+
+       /*
+        * Configure default register values.
+        */
+       writel(0, fbi->reg_base + LCD_SPU_BLANKCOLOR);
+       writel(mi->io_pin_allocation_mode, fbi->reg_base + SPU_IOPAD_CONTROL);
+       writel(0, fbi->reg_base + LCD_CFG_GRA_START_ADDR1);
+       writel(0, fbi->reg_base + LCD_SPU_GRA_OVSA_HPXL_VLN);
+       writel(0, fbi->reg_base + LCD_SPU_SRAM_PARA0);
+       writel(CFG_CSB_256x32(0x1)|CFG_CSB_256x24(0x1)|CFG_CSB_256x8(0x1),
+               fbi->reg_base + LCD_SPU_SRAM_PARA1);
+
+       /*
+        * Allocate color map.
+        */
+       if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+               ret = -ENOMEM;
+               goto failed_free_clk;
+       }
+
+       /*
+        * Register irq handler.
+        */
+       ret = request_irq(irq, pxa168fb_handle_irq, IRQF_SHARED,
+                                       info->fix.id, fbi);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "unable to request IRQ\n");
+               ret = -ENXIO;
+               goto failed_free_cmap;
+       }
+
+       /*
+        * Enable GFX interrupt
+        */
+       writel(GRA_FRAME_IRQ0_ENA(0x1), fbi->reg_base + SPU_IRQ_ENA);
+
+       /*
+        * Register framebuffer.
+        */
+       ret = register_framebuffer(info);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to register pxa168-fb: %d\n", ret);
+               ret = -ENXIO;
+               goto failed_free_irq;
+       }
+
+       platform_set_drvdata(pdev, fbi);
+       return 0;
+
+failed_free_irq:
+       free_irq(irq, fbi);
+failed_free_cmap:
+       fb_dealloc_cmap(&info->cmap);
+failed_free_clk:
+       clk_disable(fbi->clk);
+failed_free_fbmem:
+       dma_free_coherent(fbi->dev, info->fix.smem_len,
+                       info->screen_base, fbi->fb_start_dma);
+failed:
+       kfree(info);
+       clk_put(clk);
+
+       dev_err(&pdev->dev, "frame buffer device init failed with %d\n", ret);
+       return ret;
+}
+
+static struct platform_driver pxa168fb_driver = {
+       .driver         = {
+               .name   = "pxa168-fb",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = pxa168fb_probe,
+};
+
+static int __devinit pxa168fb_init(void)
+{
+       return platform_driver_register(&pxa168fb_driver);
+}
+module_init(pxa168fb_init);
+
+MODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com> "
+             "Green Wan <gwan@marvell.com>");
+MODULE_DESCRIPTION("Framebuffer driver for PXA168/910");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/pxa168fb.h b/drivers/video/pxa168fb.h
new file mode 100644 (file)
index 0000000..eee0927
--- /dev/null
@@ -0,0 +1,558 @@
+#ifndef __PXA168FB_H__
+#define __PXA168FB_H__
+
+/* ------------< LCD register >------------ */
+/* Video Frame 0&1 start address registers */
+#define        LCD_SPU_DMA_START_ADDR_Y0               0x00C0
+#define        LCD_SPU_DMA_START_ADDR_U0               0x00C4
+#define        LCD_SPU_DMA_START_ADDR_V0               0x00C8
+#define LCD_CFG_DMA_START_ADDR_0               0x00CC /* Cmd address */
+#define        LCD_SPU_DMA_START_ADDR_Y1               0x00D0
+#define        LCD_SPU_DMA_START_ADDR_U1               0x00D4
+#define        LCD_SPU_DMA_START_ADDR_V1               0x00D8
+#define LCD_CFG_DMA_START_ADDR_1               0x00DC /* Cmd address */
+
+/* YC & UV Pitch */
+#define LCD_SPU_DMA_PITCH_YC                   0x00E0
+#define     SPU_DMA_PITCH_C(c)                 ((c) << 16)
+#define     SPU_DMA_PITCH_Y(y)                 (y)
+#define LCD_SPU_DMA_PITCH_UV                   0x00E4
+#define     SPU_DMA_PITCH_V(v)                 ((v) << 16)
+#define     SPU_DMA_PITCH_U(u)                 (u)
+
+/* Video Starting Point on Screen Register */
+#define LCD_SPUT_DMA_OVSA_HPXL_VLN             0x00E8
+#define     CFG_DMA_OVSA_VLN(y)                        ((y) << 16) /* 0~0xfff */
+#define     CFG_DMA_OVSA_HPXL(x)               (x)     /* 0~0xfff */
+
+/* Video Size Register */
+#define LCD_SPU_DMA_HPXL_VLN                   0x00EC
+#define     CFG_DMA_VLN(y)                     ((y) << 16)
+#define     CFG_DMA_HPXL(x)                    (x)
+
+/* Video Size After zooming Register */
+#define LCD_SPU_DZM_HPXL_VLN                   0x00F0
+#define     CFG_DZM_VLN(y)                     ((y) << 16)
+#define     CFG_DZM_HPXL(x)                    (x)
+
+/* Graphic Frame 0&1 Starting Address Register */
+#define LCD_CFG_GRA_START_ADDR0                        0x00F4
+#define LCD_CFG_GRA_START_ADDR1                        0x00F8
+
+/* Graphic Frame Pitch */
+#define LCD_CFG_GRA_PITCH                      0x00FC
+
+/* Graphic Starting Point on Screen Register */
+#define LCD_SPU_GRA_OVSA_HPXL_VLN              0x0100
+#define     CFG_GRA_OVSA_VLN(y)                        ((y) << 16)
+#define     CFG_GRA_OVSA_HPXL(x)               (x)
+
+/* Graphic Size Register */
+#define LCD_SPU_GRA_HPXL_VLN                   0x0104
+#define     CFG_GRA_VLN(y)                     ((y) << 16)
+#define     CFG_GRA_HPXL(x)                    (x)
+
+/* Graphic Size after Zooming Register */
+#define LCD_SPU_GZM_HPXL_VLN                   0x0108
+#define     CFG_GZM_VLN(y)                     ((y) << 16)
+#define     CFG_GZM_HPXL(x)                    (x)
+
+/* HW Cursor Starting Point on Screen Register */
+#define LCD_SPU_HWC_OVSA_HPXL_VLN              0x010C
+#define     CFG_HWC_OVSA_VLN(y)                        ((y) << 16)
+#define     CFG_HWC_OVSA_HPXL(x)               (x)
+
+/* HW Cursor Size */
+#define LCD_SPU_HWC_HPXL_VLN                   0x0110
+#define     CFG_HWC_VLN(y)                     ((y) << 16)
+#define     CFG_HWC_HPXL(x)                    (x)
+
+/* Total Screen Size Register */
+#define LCD_SPUT_V_H_TOTAL                     0x0114
+#define     CFG_V_TOTAL(y)                     ((y) << 16)
+#define     CFG_H_TOTAL(x)                     (x)
+
+/* Total Screen Active Size Register */
+#define LCD_SPU_V_H_ACTIVE                     0x0118
+#define     CFG_V_ACTIVE(y)                    ((y) << 16)
+#define     CFG_H_ACTIVE(x)                    (x)
+
+/* Screen H&V Porch Register */
+#define LCD_SPU_H_PORCH                                0x011C
+#define     CFG_H_BACK_PORCH(b)                        ((b) << 16)
+#define     CFG_H_FRONT_PORCH(f)               (f)
+#define LCD_SPU_V_PORCH                                0x0120
+#define     CFG_V_BACK_PORCH(b)                        ((b) << 16)
+#define     CFG_V_FRONT_PORCH(f)               (f)
+
+/* Screen Blank Color Register */
+#define LCD_SPU_BLANKCOLOR                     0x0124
+#define     CFG_BLANKCOLOR_MASK                        0x00FFFFFF
+#define     CFG_BLANKCOLOR_R_MASK              0x000000FF
+#define     CFG_BLANKCOLOR_G_MASK              0x0000FF00
+#define     CFG_BLANKCOLOR_B_MASK              0x00FF0000
+
+/* HW Cursor Color 1&2 Register */
+#define LCD_SPU_ALPHA_COLOR1                   0x0128
+#define     CFG_HWC_COLOR1                     0x00FFFFFF
+#define     CFG_HWC_COLOR1_R(red)              ((red) << 16)
+#define     CFG_HWC_COLOR1_G(green)            ((green) << 8)
+#define     CFG_HWC_COLOR1_B(blue)             (blue)
+#define     CFG_HWC_COLOR1_R_MASK              0x000000FF
+#define     CFG_HWC_COLOR1_G_MASK              0x0000FF00
+#define     CFG_HWC_COLOR1_B_MASK              0x00FF0000
+#define LCD_SPU_ALPHA_COLOR2                   0x012C
+#define     CFG_HWC_COLOR2                     0x00FFFFFF
+#define     CFG_HWC_COLOR2_R_MASK              0x000000FF
+#define     CFG_HWC_COLOR2_G_MASK              0x0000FF00
+#define     CFG_HWC_COLOR2_B_MASK              0x00FF0000
+
+/* Video YUV Color Key Control */
+#define LCD_SPU_COLORKEY_Y                     0x0130
+#define     CFG_CKEY_Y2(y2)                    ((y2) << 24)
+#define     CFG_CKEY_Y2_MASK                   0xFF000000
+#define     CFG_CKEY_Y1(y1)                    ((y1) << 16)
+#define     CFG_CKEY_Y1_MASK                   0x00FF0000
+#define     CFG_CKEY_Y(y)                      ((y) << 8)
+#define     CFG_CKEY_Y_MASK                    0x0000FF00
+#define     CFG_ALPHA_Y(y)                     (y)
+#define     CFG_ALPHA_Y_MASK                   0x000000FF
+#define LCD_SPU_COLORKEY_U                     0x0134
+#define     CFG_CKEY_U2(u2)                    ((u2) << 24)
+#define     CFG_CKEY_U2_MASK                   0xFF000000
+#define     CFG_CKEY_U1(u1)                    ((u1) << 16)
+#define     CFG_CKEY_U1_MASK                   0x00FF0000
+#define     CFG_CKEY_U(u)                      ((u) << 8)
+#define     CFG_CKEY_U_MASK                    0x0000FF00
+#define     CFG_ALPHA_U(u)                     (u)
+#define     CFG_ALPHA_U_MASK                   0x000000FF
+#define LCD_SPU_COLORKEY_V                     0x0138
+#define     CFG_CKEY_V2(v2)                    ((v2) << 24)
+#define     CFG_CKEY_V2_MASK                   0xFF000000
+#define     CFG_CKEY_V1(v1)                    ((v1) << 16)
+#define     CFG_CKEY_V1_MASK                   0x00FF0000
+#define     CFG_CKEY_V(v)                      ((v) << 8)
+#define     CFG_CKEY_V_MASK                    0x0000FF00
+#define     CFG_ALPHA_V(v)                     (v)
+#define     CFG_ALPHA_V_MASK                   0x000000FF
+
+/* SPI Read Data Register */
+#define LCD_SPU_SPI_RXDATA                     0x0140
+
+/* Smart Panel Read Data Register */
+#define LCD_SPU_ISA_RSDATA                     0x0144
+#define     ISA_RXDATA_16BIT_1_DATA_MASK       0x000000FF
+#define     ISA_RXDATA_16BIT_2_DATA_MASK       0x0000FF00
+#define     ISA_RXDATA_16BIT_3_DATA_MASK       0x00FF0000
+#define     ISA_RXDATA_16BIT_4_DATA_MASK       0xFF000000
+#define     ISA_RXDATA_32BIT_1_DATA_MASK       0x00FFFFFF
+
+/* HWC SRAM Read Data Register */
+#define LCD_SPU_HWC_RDDAT                      0x0158
+
+/* Gamma Table SRAM Read Data Register */
+#define LCD_SPU_GAMMA_RDDAT                    0x015c
+#define     CFG_GAMMA_RDDAT_MASK               0x000000FF
+
+/* Palette Table SRAM Read Data Register */
+#define LCD_SPU_PALETTE_RDDAT                  0x0160
+#define     CFG_PALETTE_RDDAT_MASK             0x00FFFFFF
+
+/* I/O Pads Input Read Only Register */
+#define LCD_SPU_IOPAD_IN                       0x0178
+#define     CFG_IOPAD_IN_MASK                  0x0FFFFFFF
+
+/* Reserved Read Only Registers */
+#define LCD_CFG_RDREG5F                                0x017C
+#define     IRE_FRAME_CNT_MASK                 0x000000C0
+#define     IPE_FRAME_CNT_MASK                 0x00000030
+#define     GRA_FRAME_CNT_MASK                 0x0000000C  /* Graphic */
+#define     DMA_FRAME_CNT_MASK                 0x00000003  /* Video */
+
+/* SPI Control Register. */
+#define LCD_SPU_SPI_CTRL                       0x0180
+#define     CFG_SCLKCNT(div)                   ((div) << 24)  /* 0xFF~0x2 */
+#define     CFG_SCLKCNT_MASK                   0xFF000000
+#define     CFG_RXBITS(rx)                     ((rx) << 16)   /* 0x1F~0x1 */
+#define     CFG_RXBITS_MASK                    0x00FF0000
+#define     CFG_TXBITS(tx)                     ((tx) << 8)    /* 0x1F~0x1 */
+#define     CFG_TXBITS_MASK                    0x0000FF00
+#define     CFG_CLKINV(clk)                    ((clk) << 7)
+#define     CFG_CLKINV_MASK                    0x00000080
+#define     CFG_KEEPXFER(transfer)             ((transfer) << 6)
+#define     CFG_KEEPXFER_MASK                  0x00000040
+#define     CFG_RXBITSTO0(rx)                  ((rx) << 5)
+#define     CFG_RXBITSTO0_MASK                 0x00000020
+#define     CFG_TXBITSTO0(tx)                  ((tx) << 4)
+#define     CFG_TXBITSTO0_MASK                 0x00000010
+#define     CFG_SPI_ENA(spi)                   ((spi) << 3)
+#define     CFG_SPI_ENA_MASK                   0x00000008
+#define     CFG_SPI_SEL(spi)                   ((spi) << 2)
+#define     CFG_SPI_SEL_MASK                   0x00000004
+#define     CFG_SPI_3W4WB(wire)                        ((wire) << 1)
+#define     CFG_SPI_3W4WB_MASK                 0x00000002
+#define     CFG_SPI_START(start)               (start)
+#define     CFG_SPI_START_MASK                 0x00000001
+
+/* SPI Tx Data Register */
+#define LCD_SPU_SPI_TXDATA                     0x0184
+
+/*
+   1. Smart Pannel 8-bit Bus Control Register.
+   2. AHB Slave Path Data Port Register
+*/
+#define LCD_SPU_SMPN_CTRL                      0x0188
+
+/* DMA Control 0 Register */
+#define LCD_SPU_DMA_CTRL0                      0x0190
+#define     CFG_NOBLENDING(nb)                 ((nb) << 31)
+#define     CFG_NOBLENDING_MASK                        0x80000000
+#define     CFG_GAMMA_ENA(gn)                  ((gn) << 30)
+#define     CFG_GAMMA_ENA_MASK                 0x40000000
+#define     CFG_CBSH_ENA(cn)                   ((cn) << 29)
+#define     CFG_CBSH_ENA_MASK                  0x20000000
+#define     CFG_PALETTE_ENA(pn)                        ((pn) << 28)
+#define     CFG_PALETTE_ENA_MASK               0x10000000
+#define     CFG_ARBFAST_ENA(an)                        ((an) << 27)
+#define     CFG_ARBFAST_ENA_MASK               0x08000000
+#define     CFG_HWC_1BITMOD(mode)              ((mode) << 26)
+#define     CFG_HWC_1BITMOD_MASK               0x04000000
+#define     CFG_HWC_1BITENA(mn)                        ((mn) << 25)
+#define     CFG_HWC_1BITENA_MASK               0x02000000
+#define     CFG_HWC_ENA(cn)                    ((cn) << 24)
+#define     CFG_HWC_ENA_MASK                   0x01000000
+#define     CFG_DMAFORMAT(dmaformat)           ((dmaformat) << 20)
+#define     CFG_DMAFORMAT_MASK                 0x00F00000
+#define     CFG_GRAFORMAT(graformat)           ((graformat) << 16)
+#define     CFG_GRAFORMAT_MASK                 0x000F0000
+/* for graphic part */
+#define     CFG_GRA_FTOGGLE(toggle)            ((toggle) << 15)
+#define     CFG_GRA_FTOGGLE_MASK               0x00008000
+#define     CFG_GRA_HSMOOTH(smooth)            ((smooth) << 14)
+#define     CFG_GRA_HSMOOTH_MASK               0x00004000
+#define     CFG_GRA_TSTMODE(test)              ((test) << 13)
+#define     CFG_GRA_TSTMODE_MASK               0x00002000
+#define     CFG_GRA_SWAPRB(swap)               ((swap) << 12)
+#define     CFG_GRA_SWAPRB_MASK                        0x00001000
+#define     CFG_GRA_SWAPUV(swap)               ((swap) << 11)
+#define     CFG_GRA_SWAPUV_MASK                        0x00000800
+#define     CFG_GRA_SWAPYU(swap)               ((swap) << 10)
+#define     CFG_GRA_SWAPYU_MASK                        0x00000400
+#define     CFG_YUV2RGB_GRA(cvrt)              ((cvrt) << 9)
+#define     CFG_YUV2RGB_GRA_MASK               0x00000200
+#define     CFG_GRA_ENA(gra)                   ((gra) << 8)
+#define     CFG_GRA_ENA_MASK                   0x00000100
+/* for video part */
+#define     CFG_DMA_FTOGGLE(toggle)            ((toggle) << 7)
+#define     CFG_DMA_FTOGGLE_MASK               0x00000080
+#define     CFG_DMA_HSMOOTH(smooth)            ((smooth) << 6)
+#define     CFG_DMA_HSMOOTH_MASK               0x00000040
+#define     CFG_DMA_TSTMODE(test)              ((test) << 5)
+#define     CFG_DMA_TSTMODE_MASK               0x00000020
+#define     CFG_DMA_SWAPRB(swap)               ((swap) << 4)
+#define     CFG_DMA_SWAPRB_MASK                        0x00000010
+#define     CFG_DMA_SWAPUV(swap)               ((swap) << 3)
+#define     CFG_DMA_SWAPUV_MASK                        0x00000008
+#define     CFG_DMA_SWAPYU(swap)               ((swap) << 2)
+#define     CFG_DMA_SWAPYU_MASK                        0x00000004
+#define     CFG_DMA_SWAP_MASK                  0x0000001C
+#define     CFG_YUV2RGB_DMA(cvrt)              ((cvrt) << 1)
+#define     CFG_YUV2RGB_DMA_MASK               0x00000002
+#define     CFG_DMA_ENA(video)                 (video)
+#define     CFG_DMA_ENA_MASK                   0x00000001
+
+/* DMA Control 1 Register */
+#define LCD_SPU_DMA_CTRL1                      0x0194
+#define     CFG_FRAME_TRIG(trig)               ((trig) << 31)
+#define     CFG_FRAME_TRIG_MASK                        0x80000000
+#define     CFG_VSYNC_TRIG(trig)               ((trig) << 28)
+#define     CFG_VSYNC_TRIG_MASK                        0x70000000
+#define     CFG_VSYNC_INV(inv)                 ((inv) << 27)
+#define     CFG_VSYNC_INV_MASK                 0x08000000
+#define     CFG_COLOR_KEY_MODE(cmode)          ((cmode) << 24)
+#define     CFG_COLOR_KEY_MASK                 0x07000000
+#define     CFG_CARRY(carry)                   ((carry) << 23)
+#define     CFG_CARRY_MASK                     0x00800000
+#define     CFG_LNBUF_ENA(lnbuf)               ((lnbuf) << 22)
+#define     CFG_LNBUF_ENA_MASK                 0x00400000
+#define     CFG_GATED_ENA(gated)               ((gated) << 21)
+#define     CFG_GATED_ENA_MASK                 0x00200000
+#define     CFG_PWRDN_ENA(power)               ((power) << 20)
+#define     CFG_PWRDN_ENA_MASK                 0x00100000
+#define     CFG_DSCALE(dscale)                 ((dscale) << 18)
+#define     CFG_DSCALE_MASK                    0x000C0000
+#define     CFG_ALPHA_MODE(amode)              ((amode) << 16)
+#define     CFG_ALPHA_MODE_MASK                        0x00030000
+#define     CFG_ALPHA(alpha)                   ((alpha) << 8)
+#define     CFG_ALPHA_MASK                     0x0000FF00
+#define     CFG_PXLCMD(pxlcmd)                 (pxlcmd)
+#define     CFG_PXLCMD_MASK                    0x000000FF
+
+/* SRAM Control Register */
+#define LCD_SPU_SRAM_CTRL                      0x0198
+#define     CFG_SRAM_INIT_WR_RD(mode)          ((mode) << 14)
+#define     CFG_SRAM_INIT_WR_RD_MASK           0x0000C000
+#define     CFG_SRAM_ADDR_LCDID(id)            ((id) << 8)
+#define     CFG_SRAM_ADDR_LCDID_MASK           0x00000F00
+#define     CFG_SRAM_ADDR(addr)                        (addr)
+#define     CFG_SRAM_ADDR_MASK                 0x000000FF
+
+/* SRAM Write Data Register */
+#define LCD_SPU_SRAM_WRDAT                     0x019C
+
+/* SRAM RTC/WTC Control Register */
+#define LCD_SPU_SRAM_PARA0                     0x01A0
+
+/* SRAM Power Down Control Register */
+#define LCD_SPU_SRAM_PARA1                     0x01A4
+#define     CFG_CSB_256x32(hwc)                        ((hwc) << 15)   /* HWC */
+#define     CFG_CSB_256x32_MASK                        0x00008000
+#define     CFG_CSB_256x24(palette)            ((palette) << 14)       /* Palette */
+#define     CFG_CSB_256x24_MASK                        0x00004000
+#define     CFG_CSB_256x8(gamma)               ((gamma) << 13) /* Gamma */
+#define     CFG_CSB_256x8_MASK                 0x00002000
+#define     CFG_PDWN256x32(pdwn)               ((pdwn) << 7)   /* HWC */
+#define     CFG_PDWN256x32_MASK                        0x00000080
+#define     CFG_PDWN256x24(pdwn)               ((pdwn) << 6)   /* Palette */
+#define     CFG_PDWN256x24_MASK                        0x00000040
+#define     CFG_PDWN256x8(pdwn)                        ((pdwn) << 5)   /* Gamma */
+#define     CFG_PDWN256x8_MASK                 0x00000020
+#define     CFG_PDWN32x32(pdwn)                        ((pdwn) << 3)
+#define     CFG_PDWN32x32_MASK                 0x00000008
+#define     CFG_PDWN16x66(pdwn)                        ((pdwn) << 2)
+#define     CFG_PDWN16x66_MASK                 0x00000004
+#define     CFG_PDWN32x66(pdwn)                        ((pdwn) << 1)
+#define     CFG_PDWN32x66_MASK                 0x00000002
+#define     CFG_PDWN64x66(pdwn)                        (pdwn)
+#define     CFG_PDWN64x66_MASK                 0x00000001
+
+/* Smart or Dumb Panel Clock Divider */
+#define LCD_CFG_SCLK_DIV                       0x01A8
+#define     SCLK_SOURCE_SELECT(src)            ((src) << 31)
+#define     SCLK_SOURCE_SELECT_MASK            0x80000000
+#define     CLK_FRACDIV(frac)                  ((frac) << 16)
+#define     CLK_FRACDIV_MASK                   0x0FFF0000
+#define     CLK_INT_DIV(div)                   (div)
+#define     CLK_INT_DIV_MASK                   0x0000FFFF
+
+/* Video Contrast Register */
+#define LCD_SPU_CONTRAST                       0x01AC
+#define     CFG_BRIGHTNESS(bright)             ((bright) << 16)
+#define     CFG_BRIGHTNESS_MASK                        0xFFFF0000
+#define     CFG_CONTRAST(contrast)             (contrast)
+#define     CFG_CONTRAST_MASK                  0x0000FFFF
+
+/* Video Saturation Register */
+#define LCD_SPU_SATURATION                     0x01B0
+#define     CFG_C_MULTS(mult)                  ((mult) << 16)
+#define     CFG_C_MULTS_MASK                   0xFFFF0000
+#define     CFG_SATURATION(sat)                        (sat)
+#define     CFG_SATURATION_MASK                        0x0000FFFF
+
+/* Video Hue Adjust Register */
+#define LCD_SPU_CBSH_HUE                       0x01B4
+#define     CFG_SIN0(sin0)                     ((sin0) << 16)
+#define     CFG_SIN0_MASK                      0xFFFF0000
+#define     CFG_COS0(con0)                     (con0)
+#define     CFG_COS0_MASK                      0x0000FFFF
+
+/* Dump LCD Panel Control Register */
+#define LCD_SPU_DUMB_CTRL                      0x01B8
+#define     CFG_DUMBMODE(mode)                 ((mode) << 28)
+#define     CFG_DUMBMODE_MASK                  0xF0000000
+#define     CFG_LCDGPIO_O(data)                        ((data) << 20)
+#define     CFG_LCDGPIO_O_MASK                 0x0FF00000
+#define     CFG_LCDGPIO_ENA(gpio)              ((gpio) << 12)
+#define     CFG_LCDGPIO_ENA_MASK               0x000FF000
+#define     CFG_BIAS_OUT(bias)                 ((bias) << 8)
+#define     CFG_BIAS_OUT_MASK                  0x00000100
+#define     CFG_REVERSE_RGB(rRGB)              ((rRGB) << 7)
+#define     CFG_REVERSE_RGB_MASK               0x00000080
+#define     CFG_INV_COMPBLANK(blank)           ((blank) << 6)
+#define     CFG_INV_COMPBLANK_MASK             0x00000040
+#define     CFG_INV_COMPSYNC(sync)             ((sync) << 5)
+#define     CFG_INV_COMPSYNC_MASK              0x00000020
+#define     CFG_INV_HENA(hena)                 ((hena) << 4)
+#define     CFG_INV_HENA_MASK                  0x00000010
+#define     CFG_INV_VSYNC(vsync)               ((vsync) << 3)
+#define     CFG_INV_VSYNC_MASK                 0x00000008
+#define     CFG_INV_HSYNC(hsync)               ((hsync) << 2)
+#define     CFG_INV_HSYNC_MASK                 0x00000004
+#define     CFG_INV_PCLK(pclk)                 ((pclk) << 1)
+#define     CFG_INV_PCLK_MASK                  0x00000002
+#define     CFG_DUMB_ENA(dumb)                 (dumb)
+#define     CFG_DUMB_ENA_MASK                  0x00000001
+
+/* LCD I/O Pads Control Register */
+#define SPU_IOPAD_CONTROL                      0x01BC
+#define     CFG_GRA_VM_ENA(vm)                 ((vm) << 15)        /* gfx */
+#define     CFG_GRA_VM_ENA_MASK                        0x00008000
+#define     CFG_DMA_VM_ENA(vm)                 ((vm) << 13)    /* video */
+#define     CFG_DMA_VM_ENA_MASK                        0x00002000
+#define     CFG_CMD_VM_ENA(vm)                 ((vm) << 13)
+#define     CFG_CMD_VM_ENA_MASK                        0x00000800
+#define     CFG_CSC(csc)                       ((csc) << 8)    /* csc */
+#define     CFG_CSC_MASK                       0x00000300
+#define     CFG_AXICTRL(axi)                   ((axi) << 4)
+#define     CFG_AXICTRL_MASK                   0x000000F0
+#define     CFG_IOPADMODE(iopad)               (iopad)
+#define     CFG_IOPADMODE_MASK                 0x0000000F
+
+/* LCD Interrupt Control Register */
+#define SPU_IRQ_ENA                            0x01C0
+#define     DMA_FRAME_IRQ0_ENA(irq)            ((irq) << 31)
+#define     DMA_FRAME_IRQ0_ENA_MASK            0x80000000
+#define     DMA_FRAME_IRQ1_ENA(irq)            ((irq) << 30)
+#define     DMA_FRAME_IRQ1_ENA_MASK            0x40000000
+#define     DMA_FF_UNDERFLOW_ENA(ff)           ((ff) << 29)
+#define     DMA_FF_UNDERFLOW_ENA_MASK          0x20000000
+#define     GRA_FRAME_IRQ0_ENA(irq)            ((irq) << 27)
+#define     GRA_FRAME_IRQ0_ENA_MASK            0x08000000
+#define     GRA_FRAME_IRQ1_ENA(irq)            ((irq) << 26)
+#define     GRA_FRAME_IRQ1_ENA_MASK            0x04000000
+#define     GRA_FF_UNDERFLOW_ENA(ff)           ((ff) << 25)
+#define     GRA_FF_UNDERFLOW_ENA_MASK          0x02000000
+#define     VSYNC_IRQ_ENA(vsync_irq)           ((vsync_irq) << 23)
+#define     VSYNC_IRQ_ENA_MASK                 0x00800000
+#define     DUMB_FRAMEDONE_ENA(fdone)          ((fdone) << 22)
+#define     DUMB_FRAMEDONE_ENA_MASK            0x00400000
+#define     TWC_FRAMEDONE_ENA(fdone)           ((fdone) << 21)
+#define     TWC_FRAMEDONE_ENA_MASK             0x00200000
+#define     HWC_FRAMEDONE_ENA(fdone)           ((fdone) << 20)
+#define     HWC_FRAMEDONE_ENA_MASK             0x00100000
+#define     SLV_IRQ_ENA(irq)                   ((irq) << 19)
+#define     SLV_IRQ_ENA_MASK                   0x00080000
+#define     SPI_IRQ_ENA(irq)                   ((irq) << 18)
+#define     SPI_IRQ_ENA_MASK                   0x00040000
+#define     PWRDN_IRQ_ENA(irq)                 ((irq) << 17)
+#define     PWRDN_IRQ_ENA_MASK                 0x00020000
+#define     ERR_IRQ_ENA(irq)                   ((irq) << 16)
+#define     ERR_IRQ_ENA_MASK                   0x00010000
+#define     CLEAN_SPU_IRQ_ISR(irq)             (irq)
+#define     CLEAN_SPU_IRQ_ISR_MASK             0x0000FFFF
+
+/* LCD Interrupt Status Register */
+#define SPU_IRQ_ISR                            0x01C4
+#define     DMA_FRAME_IRQ0(irq)                        ((irq) << 31)
+#define     DMA_FRAME_IRQ0_MASK                        0x80000000
+#define     DMA_FRAME_IRQ1(irq)                        ((irq) << 30)
+#define     DMA_FRAME_IRQ1_MASK                        0x40000000
+#define     DMA_FF_UNDERFLOW(ff)               ((ff) << 29)
+#define     DMA_FF_UNDERFLOW_MASK              0x20000000
+#define     GRA_FRAME_IRQ0(irq)                        ((irq) << 27)
+#define     GRA_FRAME_IRQ0_MASK                        0x08000000
+#define     GRA_FRAME_IRQ1(irq)                        ((irq) << 26)
+#define     GRA_FRAME_IRQ1_MASK                        0x04000000
+#define     GRA_FF_UNDERFLOW(ff)               ((ff) << 25)
+#define     GRA_FF_UNDERFLOW_MASK              0x02000000
+#define     VSYNC_IRQ(vsync_irq)               ((vsync_irq) << 23)
+#define     VSYNC_IRQ_MASK                     0x00800000
+#define     DUMB_FRAMEDONE(fdone)              ((fdone) << 22)
+#define     DUMB_FRAMEDONE_MASK                        0x00400000
+#define     TWC_FRAMEDONE(fdone)               ((fdone) << 21)
+#define     TWC_FRAMEDONE_MASK                 0x00200000
+#define     HWC_FRAMEDONE(fdone)               ((fdone) << 20)
+#define     HWC_FRAMEDONE_MASK                 0x00100000
+#define     SLV_IRQ(irq)                       ((irq) << 19)
+#define     SLV_IRQ_MASK                       0x00080000
+#define     SPI_IRQ(irq)                       ((irq) << 18)
+#define     SPI_IRQ_MASK                       0x00040000
+#define     PWRDN_IRQ(irq)                     ((irq) << 17)
+#define     PWRDN_IRQ_MASK                     0x00020000
+#define     ERR_IRQ(irq)                       ((irq) << 16)
+#define     ERR_IRQ_MASK                       0x00010000
+/* read-only */
+#define     DMA_FRAME_IRQ0_LEVEL_MASK          0x00008000
+#define     DMA_FRAME_IRQ1_LEVEL_MASK          0x00004000
+#define     DMA_FRAME_CNT_ISR_MASK             0x00003000
+#define     GRA_FRAME_IRQ0_LEVEL_MASK          0x00000800
+#define     GRA_FRAME_IRQ1_LEVEL_MASK          0x00000400
+#define     GRA_FRAME_CNT_ISR_MASK             0x00000300
+#define     VSYNC_IRQ_LEVEL_MASK               0x00000080
+#define     DUMB_FRAMEDONE_LEVEL_MASK          0x00000040
+#define     TWC_FRAMEDONE_LEVEL_MASK           0x00000020
+#define     HWC_FRAMEDONE_LEVEL_MASK           0x00000010
+#define     SLV_FF_EMPTY_MASK                  0x00000008
+#define     DMA_FF_ALLEMPTY_MASK               0x00000004
+#define     GRA_FF_ALLEMPTY_MASK               0x00000002
+#define     PWRDN_IRQ_LEVEL_MASK               0x00000001
+
+
+/*
+ * defined Video Memory Color format for DMA control 0 register
+ * DMA0 bit[23:20]
+ */
+#define VMODE_RGB565           0x0
+#define VMODE_RGB1555          0x1
+#define VMODE_RGB888PACKED     0x2
+#define VMODE_RGB888UNPACKED   0x3
+#define VMODE_RGBA888          0x4
+#define VMODE_YUV422PACKED     0x5
+#define VMODE_YUV422PLANAR     0x6
+#define VMODE_YUV420PLANAR     0x7
+#define VMODE_SMPNCMD          0x8
+#define VMODE_PALETTE4BIT      0x9
+#define VMODE_PALETTE8BIT      0xa
+#define VMODE_RESERVED         0xb
+
+/*
+ * defined Graphic Memory Color format for DMA control 0 register
+ * DMA0 bit[19:16]
+ */
+#define GMODE_RGB565           0x0
+#define GMODE_RGB1555          0x1
+#define GMODE_RGB888PACKED     0x2
+#define GMODE_RGB888UNPACKED   0x3
+#define GMODE_RGBA888          0x4
+#define GMODE_YUV422PACKED     0x5
+#define GMODE_YUV422PLANAR     0x6
+#define GMODE_YUV420PLANAR     0x7
+#define GMODE_SMPNCMD          0x8
+#define GMODE_PALETTE4BIT      0x9
+#define GMODE_PALETTE8BIT      0xa
+#define GMODE_RESERVED         0xb
+
+/*
+ * define for DMA control 1 register
+ */
+#define DMA1_FRAME_TRIG                31 /* bit location */
+#define DMA1_VSYNC_MODE                28
+#define DMA1_VSYNC_INV         27
+#define DMA1_CKEY              24
+#define DMA1_CARRY             23
+#define DMA1_LNBUF_ENA         22
+#define DMA1_GATED_ENA         21
+#define DMA1_PWRDN_ENA         20
+#define DMA1_DSCALE            18
+#define DMA1_ALPHA_MODE                16
+#define DMA1_ALPHA             08
+#define DMA1_PXLCMD            00
+
+/*
+ * defined for Configure Dumb Mode
+ * DUMB LCD Panel bit[31:28]
+ */
+#define DUMB16_RGB565_0                0x0
+#define DUMB16_RGB565_1                0x1
+#define DUMB18_RGB666_0                0x2
+#define DUMB18_RGB666_1                0x3
+#define DUMB12_RGB444_0                0x4
+#define DUMB12_RGB444_1                0x5
+#define DUMB24_RGB888_0                0x6
+#define DUMB_BLANK             0x7
+
+/*
+ * defined for Configure I/O Pin Allocation Mode
+ * LCD LCD I/O Pads control register bit[3:0]
+ */
+#define IOPAD_DUMB24           0x0
+#define IOPAD_DUMB18SPI                0x1
+#define IOPAD_DUMB18GPIO       0x2
+#define IOPAD_DUMB16SPI                0x3
+#define IOPAD_DUMB16GPIO       0x4
+#define IOPAD_DUMB12           0x5
+#define IOPAD_SMART18SPI       0x6
+#define IOPAD_SMART16SPI       0x7
+#define IOPAD_SMART8BOTH       0x8
+
+#endif /* __PXA168FB_H__ */
index 421770b5e6abb7bcb99cf7d86a0fc5786d7ad2ea..ca5b4643a4014b2cd5c08fd68891fda9be177b36 100644 (file)
@@ -45,7 +45,7 @@ static struct fb_fix_screeninfo uvesafb_fix __devinitdata = {
 static int mtrr                __devinitdata = 3; /* enable mtrr by default */
 static int blank       = 1;               /* enable blanking by default */
 static int ypan                = 1;             /* 0: scroll, 1: ypan, 2: ywrap */
-static int pmi_setpal  __devinitdata = 1; /* use PMI for palette changes */
+static bool pmi_setpal __devinitdata = true; /* use PMI for palette changes */
 static int nocrtc      __devinitdata; /* ignore CRTC settings */
 static int noedid      __devinitdata; /* don't try DDC transfers */
 static int vram_remap  __devinitdata; /* set amt. of memory to be used */
@@ -2002,11 +2002,7 @@ static void __devexit uvesafb_exit(void)
 
 module_exit(uvesafb_exit);
 
-static int param_get_scroll(char *buffer, struct kernel_param *kp)
-{
-       return 0;
-}
-
+#define param_get_scroll NULL
 static int param_set_scroll(const char *val, struct kernel_param *kp)
 {
        ypan = 0;
@@ -2017,6 +2013,8 @@ static int param_set_scroll(const char *val, struct kernel_param *kp)
                ypan = 1;
        else if (!strcmp(val, "ywrap"))
                ypan = 2;
+       else
+               return -EINVAL;
 
        return 0;
 }
index 018c070a357f8138852a41fe4ec46d8cc4cf2f98..3a43ebf83a49d6b869339e8f94da1f097141cb07 100644 (file)
@@ -31,21 +31,37 @@ static ssize_t modalias_show(struct device *_d,
        return sprintf(buf, "virtio:d%08Xv%08X\n",
                       dev->id.device, dev->id.vendor);
 }
+static ssize_t features_show(struct device *_d,
+                            struct device_attribute *attr, char *buf)
+{
+       struct virtio_device *dev = container_of(_d, struct virtio_device, dev);
+       unsigned int i;
+       ssize_t len = 0;
+
+       /* We actually represent this as a bitstring, as it could be
+        * arbitrary length in future. */
+       for (i = 0; i < ARRAY_SIZE(dev->features)*BITS_PER_LONG; i++)
+               len += sprintf(buf+len, "%c",
+                              test_bit(i, dev->features) ? '1' : '0');
+       len += sprintf(buf+len, "\n");
+       return len;
+}
 static struct device_attribute virtio_dev_attrs[] = {
        __ATTR_RO(device),
        __ATTR_RO(vendor),
        __ATTR_RO(status),
        __ATTR_RO(modalias),
+       __ATTR_RO(features),
        __ATTR_NULL
 };
 
 static inline int virtio_id_match(const struct virtio_device *dev,
                                  const struct virtio_device_id *id)
 {
-       if (id->device != dev->id.device)
+       if (id->device != dev->id.device && id->device != VIRTIO_DEV_ANY_ID)
                return 0;
 
-       return id->vendor == VIRTIO_DEV_ANY_ID || id->vendor != dev->id.vendor;
+       return id->vendor == VIRTIO_DEV_ANY_ID || id->vendor == dev->id.vendor;
 }
 
 /* This looks through all the IDs a driver claims to support.  If any of them
@@ -118,13 +134,14 @@ static int virtio_dev_probe(struct device *_d)
                if (device_features & (1 << i))
                        set_bit(i, dev->features);
 
+       dev->config->finalize_features(dev);
+
        err = drv->probe(dev);
        if (err)
                add_status(dev, VIRTIO_CONFIG_S_FAILED);
-       else {
-               dev->config->finalize_features(dev);
+       else
                add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
-       }
+
        return err;
 }
 
@@ -185,6 +202,8 @@ int register_virtio_device(struct virtio_device *dev)
        /* Acknowledge that we've seen the device. */
        add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
 
+       INIT_LIST_HEAD(&dev->vqs);
+
        /* device_register() causes the bus infrastructure to look for a
         * matching driver. */
        err = device_register(&dev->dev);
index 9c76a061a04dc7235ad689cea438fc8d0c6cfedf..26b278264796b31a4b98403d728b1e9ccfd8257b 100644 (file)
@@ -204,6 +204,9 @@ static int balloon(void *_vballoon)
 static int virtballoon_probe(struct virtio_device *vdev)
 {
        struct virtio_balloon *vb;
+       struct virtqueue *vqs[2];
+       vq_callback_t *callbacks[] = { balloon_ack, balloon_ack };
+       const char *names[] = { "inflate", "deflate" };
        int err;
 
        vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL);
@@ -218,22 +221,17 @@ static int virtballoon_probe(struct virtio_device *vdev)
        vb->vdev = vdev;
 
        /* We expect two virtqueues. */
-       vb->inflate_vq = vdev->config->find_vq(vdev, 0, balloon_ack);
-       if (IS_ERR(vb->inflate_vq)) {
-               err = PTR_ERR(vb->inflate_vq);
+       err = vdev->config->find_vqs(vdev, 2, vqs, callbacks, names);
+       if (err)
                goto out_free_vb;
-       }
 
-       vb->deflate_vq = vdev->config->find_vq(vdev, 1, balloon_ack);
-       if (IS_ERR(vb->deflate_vq)) {
-               err = PTR_ERR(vb->deflate_vq);
-               goto out_del_inflate_vq;
-       }
+       vb->inflate_vq = vqs[0];
+       vb->deflate_vq = vqs[1];
 
        vb->thread = kthread_run(balloon, vb, "vballoon");
        if (IS_ERR(vb->thread)) {
                err = PTR_ERR(vb->thread);
-               goto out_del_deflate_vq;
+               goto out_del_vqs;
        }
 
        vb->tell_host_first
@@ -241,10 +239,8 @@ static int virtballoon_probe(struct virtio_device *vdev)
 
        return 0;
 
-out_del_deflate_vq:
-       vdev->config->del_vq(vb->deflate_vq);
-out_del_inflate_vq:
-       vdev->config->del_vq(vb->inflate_vq);
+out_del_vqs:
+       vdev->config->del_vqs(vdev);
 out_free_vb:
        kfree(vb);
 out:
@@ -264,8 +260,7 @@ static void virtballoon_remove(struct virtio_device *vdev)
        /* Now we reset the device so we can clean up the queues. */
        vdev->config->reset(vdev);
 
-       vdev->config->del_vq(vb->deflate_vq);
-       vdev->config->del_vq(vb->inflate_vq);
+       vdev->config->del_vqs(vdev);
        kfree(vb);
 }
 
index 330aacbdec1f7b48fd2774f19e5788461463f07a..193c8f0e5cc5708a8e1077c0a60bc04c3eaafd2d 100644 (file)
@@ -42,6 +42,26 @@ struct virtio_pci_device
        /* a list of queues so we can dispatch IRQs */
        spinlock_t lock;
        struct list_head virtqueues;
+
+       /* MSI-X support */
+       int msix_enabled;
+       int intx_enabled;
+       struct msix_entry *msix_entries;
+       /* Name strings for interrupts. This size should be enough,
+        * and I'm too lazy to allocate each name separately. */
+       char (*msix_names)[256];
+       /* Number of available vectors */
+       unsigned msix_vectors;
+       /* Vectors allocated */
+       unsigned msix_used_vectors;
+};
+
+/* Constants for MSI-X */
+/* Use first vector for configuration changes, second and the rest for
+ * virtqueues Thus, we need at least 2 vectors for MSI. */
+enum {
+       VP_MSIX_CONFIG_VECTOR = 0,
+       VP_MSIX_VQ_VECTOR = 1,
 };
 
 struct virtio_pci_vq_info
@@ -60,6 +80,9 @@ struct virtio_pci_vq_info
 
        /* the list node for the virtqueues list */
        struct list_head node;
+
+       /* MSI-X vector (or none) */
+       unsigned vector;
 };
 
 /* Qumranet donated their vendor ID for devices 0x1000 thru 0x10FF. */
@@ -109,7 +132,8 @@ static void vp_get(struct virtio_device *vdev, unsigned offset,
                   void *buf, unsigned len)
 {
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
-       void __iomem *ioaddr = vp_dev->ioaddr + VIRTIO_PCI_CONFIG + offset;
+       void __iomem *ioaddr = vp_dev->ioaddr +
+                               VIRTIO_PCI_CONFIG(vp_dev) + offset;
        u8 *ptr = buf;
        int i;
 
@@ -123,7 +147,8 @@ static void vp_set(struct virtio_device *vdev, unsigned offset,
                   const void *buf, unsigned len)
 {
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
-       void __iomem *ioaddr = vp_dev->ioaddr + VIRTIO_PCI_CONFIG + offset;
+       void __iomem *ioaddr = vp_dev->ioaddr +
+                               VIRTIO_PCI_CONFIG(vp_dev) + offset;
        const u8 *ptr = buf;
        int i;
 
@@ -164,6 +189,37 @@ static void vp_notify(struct virtqueue *vq)
        iowrite16(info->queue_index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NOTIFY);
 }
 
+/* Handle a configuration change: Tell driver if it wants to know. */
+static irqreturn_t vp_config_changed(int irq, void *opaque)
+{
+       struct virtio_pci_device *vp_dev = opaque;
+       struct virtio_driver *drv;
+       drv = container_of(vp_dev->vdev.dev.driver,
+                          struct virtio_driver, driver);
+
+       if (drv && drv->config_changed)
+               drv->config_changed(&vp_dev->vdev);
+       return IRQ_HANDLED;
+}
+
+/* Notify all virtqueues on an interrupt. */
+static irqreturn_t vp_vring_interrupt(int irq, void *opaque)
+{
+       struct virtio_pci_device *vp_dev = opaque;
+       struct virtio_pci_vq_info *info;
+       irqreturn_t ret = IRQ_NONE;
+       unsigned long flags;
+
+       spin_lock_irqsave(&vp_dev->lock, flags);
+       list_for_each_entry(info, &vp_dev->virtqueues, node) {
+               if (vring_interrupt(irq, info->vq) == IRQ_HANDLED)
+                       ret = IRQ_HANDLED;
+       }
+       spin_unlock_irqrestore(&vp_dev->lock, flags);
+
+       return ret;
+}
+
 /* A small wrapper to also acknowledge the interrupt when it's handled.
  * I really need an EIO hook for the vring so I can ack the interrupt once we
  * know that we'll be handling the IRQ but before we invoke the callback since
@@ -173,9 +229,6 @@ static void vp_notify(struct virtqueue *vq)
 static irqreturn_t vp_interrupt(int irq, void *opaque)
 {
        struct virtio_pci_device *vp_dev = opaque;
-       struct virtio_pci_vq_info *info;
-       irqreturn_t ret = IRQ_NONE;
-       unsigned long flags;
        u8 isr;
 
        /* reading the ISR has the effect of also clearing it so it's very
@@ -187,34 +240,137 @@ static irqreturn_t vp_interrupt(int irq, void *opaque)
                return IRQ_NONE;
 
        /* Configuration change?  Tell driver if it wants to know. */
-       if (isr & VIRTIO_PCI_ISR_CONFIG) {
-               struct virtio_driver *drv;
-               drv = container_of(vp_dev->vdev.dev.driver,
-                                  struct virtio_driver, driver);
+       if (isr & VIRTIO_PCI_ISR_CONFIG)
+               vp_config_changed(irq, opaque);
 
-               if (drv && drv->config_changed)
-                       drv->config_changed(&vp_dev->vdev);
+       return vp_vring_interrupt(irq, opaque);
+}
+
+static void vp_free_vectors(struct virtio_device *vdev)
+{
+       struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+       int i;
+
+       if (vp_dev->intx_enabled) {
+               free_irq(vp_dev->pci_dev->irq, vp_dev);
+               vp_dev->intx_enabled = 0;
        }
 
-       spin_lock_irqsave(&vp_dev->lock, flags);
-       list_for_each_entry(info, &vp_dev->virtqueues, node) {
-               if (vring_interrupt(irq, info->vq) == IRQ_HANDLED)
-                       ret = IRQ_HANDLED;
+       for (i = 0; i < vp_dev->msix_used_vectors; ++i)
+               free_irq(vp_dev->msix_entries[i].vector, vp_dev);
+       vp_dev->msix_used_vectors = 0;
+
+       if (vp_dev->msix_enabled) {
+               /* Disable the vector used for configuration */
+               iowrite16(VIRTIO_MSI_NO_VECTOR,
+                         vp_dev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR);
+               /* Flush the write out to device */
+               ioread16(vp_dev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR);
+
+               vp_dev->msix_enabled = 0;
+               pci_disable_msix(vp_dev->pci_dev);
        }
-       spin_unlock_irqrestore(&vp_dev->lock, flags);
+}
 
-       return ret;
+static int vp_enable_msix(struct pci_dev *dev, struct msix_entry *entries,
+                         int *options, int noptions)
+{
+       int i;
+       for (i = 0; i < noptions; ++i)
+               if (!pci_enable_msix(dev, entries, options[i]))
+                       return options[i];
+       return -EBUSY;
+}
+
+static int vp_request_vectors(struct virtio_device *vdev, unsigned max_vqs)
+{
+       struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+       const char *name = dev_name(&vp_dev->vdev.dev);
+       unsigned i, v;
+       int err = -ENOMEM;
+       /* We want at most one vector per queue and one for config changes.
+        * Fallback to separate vectors for config and a shared for queues.
+        * Finally fall back to regular interrupts. */
+       int options[] = { max_vqs + 1, 2 };
+       int nvectors = max(options[0], options[1]);
+
+       vp_dev->msix_entries = kmalloc(nvectors * sizeof *vp_dev->msix_entries,
+                                      GFP_KERNEL);
+       if (!vp_dev->msix_entries)
+               goto error_entries;
+       vp_dev->msix_names = kmalloc(nvectors * sizeof *vp_dev->msix_names,
+                                    GFP_KERNEL);
+       if (!vp_dev->msix_names)
+               goto error_names;
+
+       for (i = 0; i < nvectors; ++i)
+               vp_dev->msix_entries[i].entry = i;
+
+       err = vp_enable_msix(vp_dev->pci_dev, vp_dev->msix_entries,
+                            options, ARRAY_SIZE(options));
+       if (err < 0) {
+               /* Can't allocate enough MSI-X vectors, use regular interrupt */
+               vp_dev->msix_vectors = 0;
+               err = request_irq(vp_dev->pci_dev->irq, vp_interrupt,
+                                 IRQF_SHARED, name, vp_dev);
+               if (err)
+                       goto error_irq;
+               vp_dev->intx_enabled = 1;
+       } else {
+               vp_dev->msix_vectors = err;
+               vp_dev->msix_enabled = 1;
+
+               /* Set the vector used for configuration */
+               v = vp_dev->msix_used_vectors;
+               snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names,
+                        "%s-config", name);
+               err = request_irq(vp_dev->msix_entries[v].vector,
+                                 vp_config_changed, 0, vp_dev->msix_names[v],
+                                 vp_dev);
+               if (err)
+                       goto error_irq;
+               ++vp_dev->msix_used_vectors;
+
+               iowrite16(v, vp_dev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR);
+               /* Verify we had enough resources to assign the vector */
+               v = ioread16(vp_dev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR);
+               if (v == VIRTIO_MSI_NO_VECTOR) {
+                       err = -EBUSY;
+                       goto error_irq;
+               }
+       }
+
+       if (vp_dev->msix_vectors && vp_dev->msix_vectors != max_vqs + 1) {
+               /* Shared vector for all VQs */
+               v = vp_dev->msix_used_vectors;
+               snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names,
+                        "%s-virtqueues", name);
+               err = request_irq(vp_dev->msix_entries[v].vector,
+                                 vp_vring_interrupt, 0, vp_dev->msix_names[v],
+                                 vp_dev);
+               if (err)
+                       goto error_irq;
+               ++vp_dev->msix_used_vectors;
+       }
+       return 0;
+error_irq:
+       vp_free_vectors(vdev);
+       kfree(vp_dev->msix_names);
+error_names:
+       kfree(vp_dev->msix_entries);
+error_entries:
+       return err;
 }
 
-/* the config->find_vq() implementation */
 static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index,
-                                   void (*callback)(struct virtqueue *vq))
+                                   void (*callback)(struct virtqueue *vq),
+                                   const char *name)
 {
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
        struct virtio_pci_vq_info *info;
        struct virtqueue *vq;
        unsigned long flags, size;
-       u16 num;
+       u16 num, vector;
        int err;
 
        /* Select the queue we're interested in */
@@ -233,6 +389,7 @@ static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index,
 
        info->queue_index = index;
        info->num = num;
+       info->vector = VIRTIO_MSI_NO_VECTOR;
 
        size = PAGE_ALIGN(vring_size(num, VIRTIO_PCI_VRING_ALIGN));
        info->queue = alloc_pages_exact(size, GFP_KERNEL|__GFP_ZERO);
@@ -247,7 +404,7 @@ static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index,
 
        /* create the vring */
        vq = vring_new_virtqueue(info->num, VIRTIO_PCI_VRING_ALIGN,
-                                vdev, info->queue, vp_notify, callback);
+                                vdev, info->queue, vp_notify, callback, name);
        if (!vq) {
                err = -ENOMEM;
                goto out_activate_queue;
@@ -256,12 +413,43 @@ static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index,
        vq->priv = info;
        info->vq = vq;
 
+       /* allocate per-vq vector if available and necessary */
+       if (callback && vp_dev->msix_used_vectors < vp_dev->msix_vectors) {
+               vector = vp_dev->msix_used_vectors;
+               snprintf(vp_dev->msix_names[vector], sizeof *vp_dev->msix_names,
+                        "%s-%s", dev_name(&vp_dev->vdev.dev), name);
+               err = request_irq(vp_dev->msix_entries[vector].vector,
+                                 vring_interrupt, 0,
+                                 vp_dev->msix_names[vector], vq);
+               if (err)
+                       goto out_request_irq;
+               info->vector = vector;
+               ++vp_dev->msix_used_vectors;
+       } else
+               vector = VP_MSIX_VQ_VECTOR;
+
+        if (callback && vp_dev->msix_enabled) {
+               iowrite16(vector, vp_dev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR);
+               vector = ioread16(vp_dev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR);
+               if (vector == VIRTIO_MSI_NO_VECTOR) {
+                       err = -EBUSY;
+                       goto out_assign;
+               }
+       }
+
        spin_lock_irqsave(&vp_dev->lock, flags);
        list_add(&info->node, &vp_dev->virtqueues);
        spin_unlock_irqrestore(&vp_dev->lock, flags);
 
        return vq;
 
+out_assign:
+       if (info->vector != VIRTIO_MSI_NO_VECTOR) {
+               free_irq(vp_dev->msix_entries[info->vector].vector, vq);
+               --vp_dev->msix_used_vectors;
+       }
+out_request_irq:
+       vring_del_virtqueue(vq);
 out_activate_queue:
        iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
        free_pages_exact(info->queue, size);
@@ -270,21 +458,27 @@ out_info:
        return ERR_PTR(err);
 }
 
-/* the config->del_vq() implementation */
 static void vp_del_vq(struct virtqueue *vq)
 {
        struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
        struct virtio_pci_vq_info *info = vq->priv;
-       unsigned long flags, size;
+       unsigned long size;
 
-       spin_lock_irqsave(&vp_dev->lock, flags);
-       list_del(&info->node);
-       spin_unlock_irqrestore(&vp_dev->lock, flags);
+       iowrite16(info->queue_index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL);
+
+       if (info->vector != VIRTIO_MSI_NO_VECTOR)
+               free_irq(vp_dev->msix_entries[info->vector].vector, vq);
+
+       if (vp_dev->msix_enabled) {
+               iowrite16(VIRTIO_MSI_NO_VECTOR,
+                         vp_dev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR);
+               /* Flush the write out to device */
+               ioread8(vp_dev->ioaddr + VIRTIO_PCI_ISR);
+       }
 
        vring_del_virtqueue(vq);
 
        /* Select and deactivate the queue */
-       iowrite16(info->queue_index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL);
        iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
 
        size = PAGE_ALIGN(vring_size(info->num, VIRTIO_PCI_VRING_ALIGN));
@@ -292,14 +486,57 @@ static void vp_del_vq(struct virtqueue *vq)
        kfree(info);
 }
 
+/* the config->del_vqs() implementation */
+static void vp_del_vqs(struct virtio_device *vdev)
+{
+       struct virtqueue *vq, *n;
+
+       list_for_each_entry_safe(vq, n, &vdev->vqs, list)
+               vp_del_vq(vq);
+
+       vp_free_vectors(vdev);
+}
+
+/* the config->find_vqs() implementation */
+static int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs,
+                      struct virtqueue *vqs[],
+                      vq_callback_t *callbacks[],
+                      const char *names[])
+{
+       int vectors = 0;
+       int i, err;
+
+       /* How many vectors would we like? */
+       for (i = 0; i < nvqs; ++i)
+               if (callbacks[i])
+                       ++vectors;
+
+       err = vp_request_vectors(vdev, vectors);
+       if (err)
+               goto error_request;
+
+       for (i = 0; i < nvqs; ++i) {
+               vqs[i] = vp_find_vq(vdev, i, callbacks[i], names[i]);
+               if (IS_ERR(vqs[i]))
+                       goto error_find;
+       }
+       return 0;
+
+error_find:
+       vp_del_vqs(vdev);
+
+error_request:
+       return PTR_ERR(vqs[i]);
+}
+
 static struct virtio_config_ops virtio_pci_config_ops = {
        .get            = vp_get,
        .set            = vp_set,
        .get_status     = vp_get_status,
        .set_status     = vp_set_status,
        .reset          = vp_reset,
-       .find_vq        = vp_find_vq,
-       .del_vq         = vp_del_vq,
+       .find_vqs       = vp_find_vqs,
+       .del_vqs        = vp_del_vqs,
        .get_features   = vp_get_features,
        .finalize_features = vp_finalize_features,
 };
@@ -310,7 +547,7 @@ static void virtio_pci_release_dev(struct device *_d)
        struct virtio_pci_device *vp_dev = to_vp_device(dev);
        struct pci_dev *pci_dev = vp_dev->pci_dev;
 
-       free_irq(pci_dev->irq, vp_dev);
+       vp_del_vqs(dev);
        pci_set_drvdata(pci_dev, NULL);
        pci_iounmap(pci_dev, vp_dev->ioaddr);
        pci_release_regions(pci_dev);
@@ -369,21 +606,13 @@ static int __devinit virtio_pci_probe(struct pci_dev *pci_dev,
        vp_dev->vdev.id.vendor = pci_dev->subsystem_vendor;
        vp_dev->vdev.id.device = pci_dev->subsystem_device;
 
-       /* register a handler for the queue with the PCI device's interrupt */
-       err = request_irq(vp_dev->pci_dev->irq, vp_interrupt, IRQF_SHARED,
-                         dev_name(&vp_dev->vdev.dev), vp_dev);
-       if (err)
-               goto out_set_drvdata;
-
        /* finally register the virtio device */
        err = register_virtio_device(&vp_dev->vdev);
        if (err)
-               goto out_req_irq;
+               goto out_set_drvdata;
 
        return 0;
 
-out_req_irq:
-       free_irq(pci_dev->irq, vp_dev);
 out_set_drvdata:
        pci_set_drvdata(pci_dev, NULL);
        pci_iounmap(pci_dev, vp_dev->ioaddr);
index 5c52369ab9bb81115376ec3e8b959908bdbe8d8f..a882f2606515796334e403baa411ebcbe45c592a 100644 (file)
 
 #ifdef DEBUG
 /* For development, we want to crash whenever the ring is screwed. */
-#define BAD_RING(_vq, fmt...)                  \
-       do { dev_err(&(_vq)->vq.vdev->dev, fmt); BUG(); } while(0)
+#define BAD_RING(_vq, fmt, args...)                            \
+       do {                                                    \
+               dev_err(&(_vq)->vq.vdev->dev,                   \
+                       "%s:"fmt, (_vq)->vq.name, ##args);      \
+               BUG();                                          \
+       } while (0)
 /* Caller is supposed to guarantee no reentry. */
 #define START_USE(_vq)                                         \
        do {                                                    \
                if ((_vq)->in_use)                              \
-                       panic("in_use = %i\n", (_vq)->in_use);  \
+                       panic("%s:in_use = %i\n",               \
+                             (_vq)->vq.name, (_vq)->in_use);   \
                (_vq)->in_use = __LINE__;                       \
                mb();                                           \
-       } while(0)
+       } while (0)
 #define END_USE(_vq) \
        do { BUG_ON(!(_vq)->in_use); (_vq)->in_use = 0; mb(); } while(0)
 #else
-#define BAD_RING(_vq, fmt...)                  \
-       do { dev_err(&_vq->vq.vdev->dev, fmt); (_vq)->broken = true; } while(0)
+#define BAD_RING(_vq, fmt, args...)                            \
+       do {                                                    \
+               dev_err(&_vq->vq.vdev->dev,                     \
+                       "%s:"fmt, (_vq)->vq.name, ##args);      \
+               (_vq)->broken = true;                           \
+       } while (0)
 #define START_USE(vq)
 #define END_USE(vq)
 #endif
@@ -52,6 +61,9 @@ struct vring_virtqueue
        /* Other side has made a mess, don't try any more. */
        bool broken;
 
+       /* Host supports indirect buffers */
+       bool indirect;
+
        /* Number of free buffers */
        unsigned int num_free;
        /* Head of free buffer list. */
@@ -76,6 +88,55 @@ struct vring_virtqueue
 
 #define to_vvq(_vq) container_of(_vq, struct vring_virtqueue, vq)
 
+/* Set up an indirect table of descriptors and add it to the queue. */
+static int vring_add_indirect(struct vring_virtqueue *vq,
+                             struct scatterlist sg[],
+                             unsigned int out,
+                             unsigned int in)
+{
+       struct vring_desc *desc;
+       unsigned head;
+       int i;
+
+       desc = kmalloc((out + in) * sizeof(struct vring_desc), GFP_ATOMIC);
+       if (!desc)
+               return vq->vring.num;
+
+       /* Transfer entries from the sg list into the indirect page */
+       for (i = 0; i < out; i++) {
+               desc[i].flags = VRING_DESC_F_NEXT;
+               desc[i].addr = sg_phys(sg);
+               desc[i].len = sg->length;
+               desc[i].next = i+1;
+               sg++;
+       }
+       for (; i < (out + in); i++) {
+               desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
+               desc[i].addr = sg_phys(sg);
+               desc[i].len = sg->length;
+               desc[i].next = i+1;
+               sg++;
+       }
+
+       /* Last one doesn't continue. */
+       desc[i-1].flags &= ~VRING_DESC_F_NEXT;
+       desc[i-1].next = 0;
+
+       /* We're about to use a buffer */
+       vq->num_free--;
+
+       /* Use a single buffer which doesn't continue */
+       head = vq->free_head;
+       vq->vring.desc[head].flags = VRING_DESC_F_INDIRECT;
+       vq->vring.desc[head].addr = virt_to_phys(desc);
+       vq->vring.desc[head].len = i * sizeof(struct vring_desc);
+
+       /* Update free pointer */
+       vq->free_head = vq->vring.desc[head].next;
+
+       return head;
+}
+
 static int vring_add_buf(struct virtqueue *_vq,
                         struct scatterlist sg[],
                         unsigned int out,
@@ -85,12 +146,21 @@ static int vring_add_buf(struct virtqueue *_vq,
        struct vring_virtqueue *vq = to_vvq(_vq);
        unsigned int i, avail, head, uninitialized_var(prev);
 
+       START_USE(vq);
+
        BUG_ON(data == NULL);
+
+       /* If the host supports indirect descriptor tables, and we have multiple
+        * buffers, then go indirect. FIXME: tune this threshold */
+       if (vq->indirect && (out + in) > 1 && vq->num_free) {
+               head = vring_add_indirect(vq, sg, out, in);
+               if (head != vq->vring.num)
+                       goto add_head;
+       }
+
        BUG_ON(out + in > vq->vring.num);
        BUG_ON(out + in == 0);
 
-       START_USE(vq);
-
        if (vq->num_free < out + in) {
                pr_debug("Can't add buf len %i - avail = %i\n",
                         out + in, vq->num_free);
@@ -127,6 +197,7 @@ static int vring_add_buf(struct virtqueue *_vq,
        /* Update free pointer */
        vq->free_head = i;
 
+add_head:
        /* Set token. */
        vq->data[head] = data;
 
@@ -170,6 +241,11 @@ static void detach_buf(struct vring_virtqueue *vq, unsigned int head)
 
        /* Put back on free list: find end */
        i = head;
+
+       /* Free the indirect table */
+       if (vq->vring.desc[i].flags & VRING_DESC_F_INDIRECT)
+               kfree(phys_to_virt(vq->vring.desc[i].addr));
+
        while (vq->vring.desc[i].flags & VRING_DESC_F_NEXT) {
                i = vq->vring.desc[i].next;
                vq->num_free++;
@@ -284,7 +360,8 @@ struct virtqueue *vring_new_virtqueue(unsigned int num,
                                      struct virtio_device *vdev,
                                      void *pages,
                                      void (*notify)(struct virtqueue *),
-                                     void (*callback)(struct virtqueue *))
+                                     void (*callback)(struct virtqueue *),
+                                     const char *name)
 {
        struct vring_virtqueue *vq;
        unsigned int i;
@@ -303,14 +380,18 @@ struct virtqueue *vring_new_virtqueue(unsigned int num,
        vq->vq.callback = callback;
        vq->vq.vdev = vdev;
        vq->vq.vq_ops = &vring_vq_ops;
+       vq->vq.name = name;
        vq->notify = notify;
        vq->broken = false;
        vq->last_used_idx = 0;
        vq->num_added = 0;
+       list_add_tail(&vq->vq.list, &vdev->vqs);
 #ifdef DEBUG
        vq->in_use = false;
 #endif
 
+       vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC);
+
        /* No callback?  Tell other side not to bother us. */
        if (!callback)
                vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
@@ -327,6 +408,7 @@ EXPORT_SYMBOL_GPL(vring_new_virtqueue);
 
 void vring_del_virtqueue(struct virtqueue *vq)
 {
+       list_del(&vq->list);
        kfree(to_vvq(vq));
 }
 EXPORT_SYMBOL_GPL(vring_del_virtqueue);
@@ -338,6 +420,8 @@ void vring_transport_features(struct virtio_device *vdev)
 
        for (i = VIRTIO_TRANSPORT_F_START; i < VIRTIO_TRANSPORT_F_END; i++) {
                switch (i) {
+               case VIRTIO_RING_F_INDIRECT_DESC:
+                       break;
                default:
                        /* We don't understand this bit. */
                        clear_bit(i, vdev->features);
index 9adbb4f904799c0d0c73a2fe80e7bc2c6da3b643..fd2c7bd9dfbeea439c142ec1477b7e2ff2811f2b 100644 (file)
@@ -8,7 +8,7 @@ menuconfig W1
          If you want W1 support, you should say Y here.
 
          This W1 support can also be built as a module.  If so, the module
-         will be called wire.ko.
+         will be called wire.
 
 if W1
 
index 96d2f8e4c2756fdc50b4fc9e21aa496ec875f59d..3195fb8b7d9a33850a5d9a179265023c6a78a69c 100644 (file)
@@ -12,7 +12,7 @@ config W1_MASTER_MATROX
          using Matrox's G400 GPIO pins.
 
          This support is also available as a module.  If so, the module
-         will be called matrox_w1.ko.
+         will be called matrox_w1.
 
 config W1_MASTER_DS2490
        tristate "DS2490 USB <-> W1 transport layer for 1-wire"
@@ -22,7 +22,7 @@ config W1_MASTER_DS2490
          for example DS9490*.
 
          This support is also available as a module.  If so, the module
-         will be called ds2490.ko.
+         will be called ds2490.
 
 config W1_MASTER_DS2482
        tristate "Maxim DS2482 I2C to 1-Wire bridge"
@@ -56,7 +56,7 @@ config W1_MASTER_GPIO
          GPIO pins. This driver uses the GPIO API to control the wire.
 
          This support is also available as a module.  If so, the module
-         will be called w1-gpio.ko.
+         will be called w1-gpio.
 
 config HDQ_MASTER_OMAP
        tristate "OMAP HDQ driver"
index 5eb8f21da82e28e2efabf46673e185295a3328c1..b166f2852a64bb50b70252a0c1498322bdd456b7 100644 (file)
@@ -231,14 +231,14 @@ config DAVINCI_WATCHDOG
          NOTE: once enabled, this timer cannot be disabled.
          Say N if you are unsure.
 
-config ORION5X_WATCHDOG
-       tristate "Orion5x watchdog"
-       depends on ARCH_ORION5X
+config ORION_WATCHDOG
+       tristate "Orion watchdog"
+       depends on ARCH_ORION5X || ARCH_KIRKWOOD
        help
          Say Y here if to include support for the watchdog timer
-         in the Orion5x ARM SoCs.
+         in the Marvell Orion5x and Kirkwood ARM SoCs.
          To compile this driver as a module, choose M here: the
-         module will be called orion5x_wdt.
+         module will be called orion_wdt.
 
 # AVR32 Architecture
 
@@ -531,7 +531,7 @@ config SBC8360_WDT
          Board Computer produced by Axiomtek Co., Ltd. (www.axiomtek.com).
 
          To compile this driver as a module, choose M here: the
-         module will be called sbc8360.ko.
+         module will be called sbc8360.
 
          Most people will say N.
 
index 7f8c56b14f58e35d33258d3b5ae3ae1217f2e552..c3afa14d5be151256bf4e2b555332aef2e0f9c13 100644 (file)
@@ -40,7 +40,7 @@ obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
 obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
 obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
 obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
-obj-$(CONFIG_ORION5X_WATCHDOG) += orion5x_wdt.o
+obj-$(CONFIG_ORION_WATCHDOG) += orion_wdt.o
 
 # AVR32 Architecture
 obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
index 96eb2cbe5874dd887ba9ec072cdba9031fd2244c..0c90596766907cb8acf686c447a280341703832b 100644 (file)
@@ -192,7 +192,7 @@ static int iop_wdt_release(struct inode *inode, struct file *file)
                if (test_bit(WDT_ENABLED, &wdt_status))
                        state = wdt_disable();
 
-       /* if the timer is not disbaled reload and notify that we are still
+       /* if the timer is not disabled reload and notify that we are still
         * going down
         */
        if (state != 0) {
diff --git a/drivers/watchdog/orion5x_wdt.c b/drivers/watchdog/orion5x_wdt.c
deleted file mode 100644 (file)
index 2cde568..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- * drivers/watchdog/orion5x_wdt.c
- *
- * Watchdog driver for Orion5x processors
- *
- * Author: Sylver Bruneau <sylver.bruneau@googlemail.com>
- *
- * This file is licensed under  the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
-#include <linux/platform_device.h>
-#include <linux/watchdog.h>
-#include <linux/init.h>
-#include <linux/uaccess.h>
-#include <linux/io.h>
-#include <linux/spinlock.h>
-#include <mach/bridge-regs.h>
-#include <plat/orion5x_wdt.h>
-
-/*
- * Watchdog timer block registers.
- */
-#define TIMER_CTRL             (TIMER_VIRT_BASE + 0x0000)
-#define  WDT_EN                        0x0010
-#define WDT_VAL                        (TIMER_VIRT_BASE + 0x0024)
-
-#define WDT_MAX_CYCLE_COUNT    0xffffffff
-#define WDT_IN_USE             0
-#define WDT_OK_TO_CLOSE                1
-
-static int nowayout = WATCHDOG_NOWAYOUT;
-static int heartbeat = -1;             /* module parameter (seconds) */
-static unsigned int wdt_max_duration;  /* (seconds) */
-static unsigned int wdt_tclk;
-static unsigned long wdt_status;
-static spinlock_t wdt_lock;
-
-static void orion5x_wdt_ping(void)
-{
-       spin_lock(&wdt_lock);
-
-       /* Reload watchdog duration */
-       writel(wdt_tclk * heartbeat, WDT_VAL);
-
-       spin_unlock(&wdt_lock);
-}
-
-static void orion5x_wdt_enable(void)
-{
-       u32 reg;
-
-       spin_lock(&wdt_lock);
-
-       /* Set watchdog duration */
-       writel(wdt_tclk * heartbeat, WDT_VAL);
-
-       /* Clear watchdog timer interrupt */
-       reg = readl(BRIDGE_CAUSE);
-       reg &= ~WDT_INT_REQ;
-       writel(reg, BRIDGE_CAUSE);
-
-       /* Enable watchdog timer */
-       reg = readl(TIMER_CTRL);
-       reg |= WDT_EN;
-       writel(reg, TIMER_CTRL);
-
-       /* Enable reset on watchdog */
-       reg = readl(CPU_RESET_MASK);
-       reg |= WDT_RESET;
-       writel(reg, CPU_RESET_MASK);
-
-       spin_unlock(&wdt_lock);
-}
-
-static void orion5x_wdt_disable(void)
-{
-       u32 reg;
-
-       spin_lock(&wdt_lock);
-
-       /* Disable reset on watchdog */
-       reg = readl(CPU_RESET_MASK);
-       reg &= ~WDT_RESET;
-       writel(reg, CPU_RESET_MASK);
-
-       /* Disable watchdog timer */
-       reg = readl(TIMER_CTRL);
-       reg &= ~WDT_EN;
-       writel(reg, TIMER_CTRL);
-
-       spin_unlock(&wdt_lock);
-}
-
-static int orion5x_wdt_get_timeleft(int *time_left)
-{
-       spin_lock(&wdt_lock);
-       *time_left = readl(WDT_VAL) / wdt_tclk;
-       spin_unlock(&wdt_lock);
-       return 0;
-}
-
-static int orion5x_wdt_open(struct inode *inode, struct file *file)
-{
-       if (test_and_set_bit(WDT_IN_USE, &wdt_status))
-               return -EBUSY;
-       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-       orion5x_wdt_enable();
-       return nonseekable_open(inode, file);
-}
-
-static ssize_t orion5x_wdt_write(struct file *file, const char *data,
-                                       size_t len, loff_t *ppos)
-{
-       if (len) {
-               if (!nowayout) {
-                       size_t i;
-
-                       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-                       for (i = 0; i != len; i++) {
-                               char c;
-
-                               if (get_user(c, data + i))
-                                       return -EFAULT;
-                               if (c == 'V')
-                                       set_bit(WDT_OK_TO_CLOSE, &wdt_status);
-                       }
-               }
-               orion5x_wdt_ping();
-       }
-       return len;
-}
-
-static int orion5x_wdt_settimeout(int new_time)
-{
-       if ((new_time <= 0) || (new_time > wdt_max_duration))
-               return -EINVAL;
-
-       /* Set new watchdog time to be used when
-        * orion5x_wdt_enable() or orion5x_wdt_ping() is called. */
-       heartbeat = new_time;
-       return 0;
-}
-
-static const struct watchdog_info ident = {
-       .options        = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
-                         WDIOF_KEEPALIVEPING,
-       .identity       = "Orion5x Watchdog",
-};
-
-static long orion5x_wdt_ioctl(struct file *file, unsigned int cmd,
-                               unsigned long arg)
-{
-       int ret = -ENOTTY;
-       int time;
-
-       switch (cmd) {
-       case WDIOC_GETSUPPORT:
-               ret = copy_to_user((struct watchdog_info *)arg, &ident,
-                                  sizeof(ident)) ? -EFAULT : 0;
-               break;
-
-       case WDIOC_GETSTATUS:
-       case WDIOC_GETBOOTSTATUS:
-               ret = put_user(0, (int *)arg);
-               break;
-
-       case WDIOC_KEEPALIVE:
-               orion5x_wdt_ping();
-               ret = 0;
-               break;
-
-       case WDIOC_SETTIMEOUT:
-               ret = get_user(time, (int *)arg);
-               if (ret)
-                       break;
-
-               if (orion5x_wdt_settimeout(time)) {
-                       ret = -EINVAL;
-                       break;
-               }
-               orion5x_wdt_ping();
-               /* Fall through */
-
-       case WDIOC_GETTIMEOUT:
-               ret = put_user(heartbeat, (int *)arg);
-               break;
-
-       case WDIOC_GETTIMELEFT:
-               if (orion5x_wdt_get_timeleft(&time)) {
-                       ret = -EINVAL;
-                       break;
-               }
-               ret = put_user(time, (int *)arg);
-               break;
-       }
-       return ret;
-}
-
-static int orion5x_wdt_release(struct inode *inode, struct file *file)
-{
-       if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
-               orion5x_wdt_disable();
-       else
-               printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
-                                       "timer will not stop\n");
-       clear_bit(WDT_IN_USE, &wdt_status);
-       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
-       return 0;
-}
-
-
-static const struct file_operations orion5x_wdt_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .write          = orion5x_wdt_write,
-       .unlocked_ioctl = orion5x_wdt_ioctl,
-       .open           = orion5x_wdt_open,
-       .release        = orion5x_wdt_release,
-};
-
-static struct miscdevice orion5x_wdt_miscdev = {
-       .minor          = WATCHDOG_MINOR,
-       .name           = "watchdog",
-       .fops           = &orion5x_wdt_fops,
-};
-
-static int __devinit orion5x_wdt_probe(struct platform_device *pdev)
-{
-       struct orion5x_wdt_platform_data *pdata = pdev->dev.platform_data;
-       int ret;
-
-       if (pdata) {
-               wdt_tclk = pdata->tclk;
-       } else {
-               printk(KERN_ERR "Orion5x Watchdog misses platform data\n");
-               return -ENODEV;
-       }
-
-       if (orion5x_wdt_miscdev.parent)
-               return -EBUSY;
-       orion5x_wdt_miscdev.parent = &pdev->dev;
-
-       wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk;
-       if (orion5x_wdt_settimeout(heartbeat))
-               heartbeat = wdt_max_duration;
-
-       ret = misc_register(&orion5x_wdt_miscdev);
-       if (ret)
-               return ret;
-
-       printk(KERN_INFO "Orion5x Watchdog Timer: Initial timeout %d sec%s\n",
-                               heartbeat, nowayout ? ", nowayout" : "");
-       return 0;
-}
-
-static int __devexit orion5x_wdt_remove(struct platform_device *pdev)
-{
-       int ret;
-
-       if (test_bit(WDT_IN_USE, &wdt_status)) {
-               orion5x_wdt_disable();
-               clear_bit(WDT_IN_USE, &wdt_status);
-       }
-
-       ret = misc_deregister(&orion5x_wdt_miscdev);
-       if (!ret)
-               orion5x_wdt_miscdev.parent = NULL;
-
-       return ret;
-}
-
-static void orion5x_wdt_shutdown(struct platform_device *pdev)
-{
-       if (test_bit(WDT_IN_USE, &wdt_status))
-               orion5x_wdt_disable();
-}
-
-static struct platform_driver orion5x_wdt_driver = {
-       .probe          = orion5x_wdt_probe,
-       .remove         = __devexit_p(orion5x_wdt_remove),
-       .shutdown       = orion5x_wdt_shutdown,
-       .driver         = {
-               .owner  = THIS_MODULE,
-               .name   = "orion5x_wdt",
-       },
-};
-
-static int __init orion5x_wdt_init(void)
-{
-       spin_lock_init(&wdt_lock);
-       return platform_driver_register(&orion5x_wdt_driver);
-}
-
-static void __exit orion5x_wdt_exit(void)
-{
-       platform_driver_unregister(&orion5x_wdt_driver);
-}
-
-module_init(orion5x_wdt_init);
-module_exit(orion5x_wdt_exit);
-
-MODULE_AUTHOR("Sylver Bruneau <sylver.bruneau@googlemail.com>");
-MODULE_DESCRIPTION("Orion5x Processor Watchdog");
-
-module_param(heartbeat, int, 0);
-MODULE_PARM_DESC(heartbeat, "Initial watchdog heartbeat in seconds");
-
-module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
-                               __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
new file mode 100644 (file)
index 0000000..2d9fb96
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * drivers/watchdog/orion_wdt.c
+ *
+ * Watchdog driver for Orion/Kirkwood processors
+ *
+ * Author: Sylver Bruneau <sylver.bruneau@googlemail.com>
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+#include <linux/init.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <mach/bridge-regs.h>
+#include <plat/orion_wdt.h>
+
+/*
+ * Watchdog timer block registers.
+ */
+#define TIMER_CTRL             (TIMER_VIRT_BASE + 0x0000)
+#define  WDT_EN                        0x0010
+#define WDT_VAL                        (TIMER_VIRT_BASE + 0x0024)
+
+#define WDT_MAX_CYCLE_COUNT    0xffffffff
+#define WDT_IN_USE             0
+#define WDT_OK_TO_CLOSE                1
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+static int heartbeat = -1;             /* module parameter (seconds) */
+static unsigned int wdt_max_duration;  /* (seconds) */
+static unsigned int wdt_tclk;
+static unsigned long wdt_status;
+static spinlock_t wdt_lock;
+
+static void orion_wdt_ping(void)
+{
+       spin_lock(&wdt_lock);
+
+       /* Reload watchdog duration */
+       writel(wdt_tclk * heartbeat, WDT_VAL);
+
+       spin_unlock(&wdt_lock);
+}
+
+static void orion_wdt_enable(void)
+{
+       u32 reg;
+
+       spin_lock(&wdt_lock);
+
+       /* Set watchdog duration */
+       writel(wdt_tclk * heartbeat, WDT_VAL);
+
+       /* Clear watchdog timer interrupt */
+       reg = readl(BRIDGE_CAUSE);
+       reg &= ~WDT_INT_REQ;
+       writel(reg, BRIDGE_CAUSE);
+
+       /* Enable watchdog timer */
+       reg = readl(TIMER_CTRL);
+       reg |= WDT_EN;
+       writel(reg, TIMER_CTRL);
+
+       /* Enable reset on watchdog */
+       reg = readl(RSTOUTn_MASK);
+       reg |= WDT_RESET_OUT_EN;
+       writel(reg, RSTOUTn_MASK);
+
+       spin_unlock(&wdt_lock);
+}
+
+static void orion_wdt_disable(void)
+{
+       u32 reg;
+
+       spin_lock(&wdt_lock);
+
+       /* Disable reset on watchdog */
+       reg = readl(RSTOUTn_MASK);
+       reg &= ~WDT_RESET_OUT_EN;
+       writel(reg, RSTOUTn_MASK);
+
+       /* Disable watchdog timer */
+       reg = readl(TIMER_CTRL);
+       reg &= ~WDT_EN;
+       writel(reg, TIMER_CTRL);
+
+       spin_unlock(&wdt_lock);
+}
+
+static int orion_wdt_get_timeleft(int *time_left)
+{
+       spin_lock(&wdt_lock);
+       *time_left = readl(WDT_VAL) / wdt_tclk;
+       spin_unlock(&wdt_lock);
+       return 0;
+}
+
+static int orion_wdt_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+               return -EBUSY;
+       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+       orion_wdt_enable();
+       return nonseekable_open(inode, file);
+}
+
+static ssize_t orion_wdt_write(struct file *file, const char *data,
+                                       size_t len, loff_t *ppos)
+{
+       if (len) {
+               if (!nowayout) {
+                       size_t i;
+
+                       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+                       for (i = 0; i != len; i++) {
+                               char c;
+
+                               if (get_user(c, data + i))
+                                       return -EFAULT;
+                               if (c == 'V')
+                                       set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+                       }
+               }
+               orion_wdt_ping();
+       }
+       return len;
+}
+
+static int orion_wdt_settimeout(int new_time)
+{
+       if ((new_time <= 0) || (new_time > wdt_max_duration))
+               return -EINVAL;
+
+       /* Set new watchdog time to be used when
+        * orion_wdt_enable() or orion_wdt_ping() is called. */
+       heartbeat = new_time;
+       return 0;
+}
+
+static const struct watchdog_info ident = {
+       .options        = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
+                         WDIOF_KEEPALIVEPING,
+       .identity       = "Orion Watchdog",
+};
+
+static long orion_wdt_ioctl(struct file *file, unsigned int cmd,
+                               unsigned long arg)
+{
+       int ret = -ENOTTY;
+       int time;
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               ret = copy_to_user((struct watchdog_info *)arg, &ident,
+                                  sizeof(ident)) ? -EFAULT : 0;
+               break;
+
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               ret = put_user(0, (int *)arg);
+               break;
+
+       case WDIOC_KEEPALIVE:
+               orion_wdt_ping();
+               ret = 0;
+               break;
+
+       case WDIOC_SETTIMEOUT:
+               ret = get_user(time, (int *)arg);
+               if (ret)
+                       break;
+
+               if (orion_wdt_settimeout(time)) {
+                       ret = -EINVAL;
+                       break;
+               }
+               orion_wdt_ping();
+               /* Fall through */
+
+       case WDIOC_GETTIMEOUT:
+               ret = put_user(heartbeat, (int *)arg);
+               break;
+
+       case WDIOC_GETTIMELEFT:
+               if (orion_wdt_get_timeleft(&time)) {
+                       ret = -EINVAL;
+                       break;
+               }
+               ret = put_user(time, (int *)arg);
+               break;
+       }
+       return ret;
+}
+
+static int orion_wdt_release(struct inode *inode, struct file *file)
+{
+       if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
+               orion_wdt_disable();
+       else
+               printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
+                                       "timer will not stop\n");
+       clear_bit(WDT_IN_USE, &wdt_status);
+       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+       return 0;
+}
+
+
+static const struct file_operations orion_wdt_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .write          = orion_wdt_write,
+       .unlocked_ioctl = orion_wdt_ioctl,
+       .open           = orion_wdt_open,
+       .release        = orion_wdt_release,
+};
+
+static struct miscdevice orion_wdt_miscdev = {
+       .minor          = WATCHDOG_MINOR,
+       .name           = "watchdog",
+       .fops           = &orion_wdt_fops,
+};
+
+static int __devinit orion_wdt_probe(struct platform_device *pdev)
+{
+       struct orion_wdt_platform_data *pdata = pdev->dev.platform_data;
+       int ret;
+
+       if (pdata) {
+               wdt_tclk = pdata->tclk;
+       } else {
+               printk(KERN_ERR "Orion Watchdog misses platform data\n");
+               return -ENODEV;
+       }
+
+       if (orion_wdt_miscdev.parent)
+               return -EBUSY;
+       orion_wdt_miscdev.parent = &pdev->dev;
+
+       wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk;
+       if (orion_wdt_settimeout(heartbeat))
+               heartbeat = wdt_max_duration;
+
+       ret = misc_register(&orion_wdt_miscdev);
+       if (ret)
+               return ret;
+
+       printk(KERN_INFO "Orion Watchdog Timer: Initial timeout %d sec%s\n",
+                               heartbeat, nowayout ? ", nowayout" : "");
+       return 0;
+}
+
+static int __devexit orion_wdt_remove(struct platform_device *pdev)
+{
+       int ret;
+
+       if (test_bit(WDT_IN_USE, &wdt_status)) {
+               orion_wdt_disable();
+               clear_bit(WDT_IN_USE, &wdt_status);
+       }
+
+       ret = misc_deregister(&orion_wdt_miscdev);
+       if (!ret)
+               orion_wdt_miscdev.parent = NULL;
+
+       return ret;
+}
+
+static void orion_wdt_shutdown(struct platform_device *pdev)
+{
+       if (test_bit(WDT_IN_USE, &wdt_status))
+               orion_wdt_disable();
+}
+
+static struct platform_driver orion_wdt_driver = {
+       .probe          = orion_wdt_probe,
+       .remove         = __devexit_p(orion_wdt_remove),
+       .shutdown       = orion_wdt_shutdown,
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = "orion_wdt",
+       },
+};
+
+static int __init orion_wdt_init(void)
+{
+       spin_lock_init(&wdt_lock);
+       return platform_driver_register(&orion_wdt_driver);
+}
+
+static void __exit orion_wdt_exit(void)
+{
+       platform_driver_unregister(&orion_wdt_driver);
+}
+
+module_init(orion_wdt_init);
+module_exit(orion_wdt_exit);
+
+MODULE_AUTHOR("Sylver Bruneau <sylver.bruneau@googlemail.com>");
+MODULE_DESCRIPTION("Orion Processor Watchdog");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Initial watchdog heartbeat in seconds");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+                               __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index fddc2025dece777c513a7a7a72f8537751bf1834..10d03d7931c47236a42e2e7ac158ac7564308354 100644 (file)
@@ -43,7 +43,7 @@ static int xen_suspend(void *data)
        if (err) {
                printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
                        err);
-               device_power_up(PMSG_RESUME);
+               dpm_resume_noirq(PMSG_RESUME);
                return err;
        }
 
@@ -69,7 +69,7 @@ static int xen_suspend(void *data)
        }
 
        sysdev_resume();
-       device_power_up(PMSG_RESUME);
+       dpm_resume_noirq(PMSG_RESUME);
 
        return 0;
 }
@@ -92,18 +92,18 @@ static void do_suspend(void)
        }
 #endif
 
-       err = device_suspend(PMSG_SUSPEND);
+       err = dpm_suspend_start(PMSG_SUSPEND);
        if (err) {
-               printk(KERN_ERR "xen suspend: device_suspend %d\n", err);
+               printk(KERN_ERR "xen suspend: dpm_suspend_start %d\n", err);
                goto out;
        }
 
        printk(KERN_DEBUG "suspending xenstore...\n");
        xs_suspend();
 
-       err = device_power_down(PMSG_SUSPEND);
+       err = dpm_suspend_noirq(PMSG_SUSPEND);
        if (err) {
-               printk(KERN_ERR "device_power_down failed: %d\n", err);
+               printk(KERN_ERR "dpm_suspend_noirq failed: %d\n", err);
                goto resume_devices;
        }
 
@@ -119,10 +119,10 @@ static void do_suspend(void)
        } else
                xs_suspend_cancel();
 
-       device_power_up(PMSG_RESUME);
+       dpm_resume_noirq(PMSG_RESUME);
 
 resume_devices:
-       device_resume(PMSG_RESUME);
+       dpm_resume_end(PMSG_RESUME);
 
        /* Make sure timer events get retriggered on all CPUs */
        clock_was_set();
index 9f7270f36b2af4e207b26ff52f9b98ad502d8c00..525da2e8f73be1da26f67be2c1630b6f20518ac0 100644 (file)
@@ -62,6 +62,16 @@ source "fs/autofs/Kconfig"
 source "fs/autofs4/Kconfig"
 source "fs/fuse/Kconfig"
 
+config CUSE
+       tristate "Character device in Userpace support"
+       depends on FUSE_FS
+       help
+         This FUSE extension allows character devices to be
+         implemented in userspace.
+
+         If you want to develop or use userspace character device
+         based on CUSE, answer Y or M.
+
 config GENERIC_ACL
        bool
        select FS_POSIX_ACL
index 59000215e59b695a2cefbe656d2be797bf86afaf..5f80848c320c7a66c6425e75aea21533607134fa 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -358,9 +358,9 @@ static void bio_kmalloc_destructor(struct bio *bio)
  *
  *   If %__GFP_WAIT is set, then bio_alloc will always be able to allocate
  *   a bio. This is due to the mempool guarantees. To make this work, callers
- *   must never allocate more than 1 bio at the time from this pool. Callers
+ *   must never allocate more than 1 bio at a time from this pool. Callers
  *   that need to allocate more than 1 bio must always submit the previously
- *   allocate bio for IO before attempting to allocate a new one. Failure to
+ *   allocated bio for IO before attempting to allocate a new one. Failure to
  *   do so can cause livelocks under memory pressure.
  *
  **/
index 6aefb776dfeb6a86bc4cd6e0fbc40aef916df028..cdd51a3a7c537cd361d18ab21dabd1eafa4d4445 100644 (file)
@@ -471,7 +471,7 @@ asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd,
                ret = sys_fcntl(fd, cmd, (unsigned long)&f);
                set_fs(old_fs);
                if (cmd == F_GETLK && ret == 0) {
-                       /* GETLK was successfule and we need to return the data...
+                       /* GETLK was successful and we need to return the data...
                         * but it needs to fit in the compat structure.
                         * l_start shouldn't be too big, unless the original
                         * start + end is greater than COMPAT_OFF_T_MAX, in which
index b83f6bcfa51a4eefc745d819e8eb9592f4af990c..0aac371bff0b4c2e20e6748fdde3d6edf0c5afea 100644 (file)
@@ -1765,7 +1765,7 @@ static int do_i2c_smbus_ioctl(unsigned int fd, unsigned int cmd, unsigned long a
 
 /* Since old style bridge ioctl's endup using SIOCDEVPRIVATE
  * for some operations; this forces use of the newer bridge-utils that
- * use compatiable ioctls
+ * use compatible ioctls
  */
 static int old_bridge_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
index 762d287123ca992456b8bef7c16848dde753fb13..da6061a6df40ced1c03816b3210069b6f22b1067 100644 (file)
@@ -39,6 +39,9 @@ struct configfs_dirent {
        umode_t                 s_mode;
        struct dentry           * s_dentry;
        struct iattr            * s_iattr;
+#ifdef CONFIG_LOCKDEP
+       int                     s_depth;
+#endif
 };
 
 #define CONFIGFS_ROOT          0x0001
index 05373db21a4e8e4a8a297b3c83fb8ef85a0cb175..8e48b52205aac439106638c82546ff351f0ed955 100644 (file)
@@ -78,11 +78,97 @@ static const struct dentry_operations configfs_dentry_ops = {
        .d_delete       = configfs_d_delete,
 };
 
+#ifdef CONFIG_LOCKDEP
+
+/*
+ * Helpers to make lockdep happy with our recursive locking of default groups'
+ * inodes (see configfs_attach_group() and configfs_detach_group()).
+ * We put default groups i_mutexes in separate classes according to their depth
+ * from the youngest non-default group ancestor.
+ *
+ * For a non-default group A having default groups A/B, A/C, and A/C/D, default
+ * groups A/B and A/C will have their inode's mutex in class
+ * default_group_class[0], and default group A/C/D will be in
+ * default_group_class[1].
+ *
+ * The lock classes are declared and assigned in inode.c, according to the
+ * s_depth value.
+ * The s_depth value is initialized to -1, adjusted to >= 0 when attaching
+ * default groups, and reset to -1 when all default groups are attached. During
+ * attachment, if configfs_create() sees s_depth > 0, the lock class of the new
+ * inode's mutex is set to default_group_class[s_depth - 1].
+ */
+
+static void configfs_init_dirent_depth(struct configfs_dirent *sd)
+{
+       sd->s_depth = -1;
+}
+
+static void configfs_set_dir_dirent_depth(struct configfs_dirent *parent_sd,
+                                         struct configfs_dirent *sd)
+{
+       int parent_depth = parent_sd->s_depth;
+
+       if (parent_depth >= 0)
+               sd->s_depth = parent_depth + 1;
+}
+
+static void
+configfs_adjust_dir_dirent_depth_before_populate(struct configfs_dirent *sd)
+{
+       /*
+        * item's i_mutex class is already setup, so s_depth is now only
+        * used to set new sub-directories s_depth, which is always done
+        * with item's i_mutex locked.
+        */
+       /*
+        *  sd->s_depth == -1 iff we are a non default group.
+        *  else (we are a default group) sd->s_depth > 0 (see
+        *  create_dir()).
+        */
+       if (sd->s_depth == -1)
+               /*
+                * We are a non default group and we are going to create
+                * default groups.
+                */
+               sd->s_depth = 0;
+}
+
+static void
+configfs_adjust_dir_dirent_depth_after_populate(struct configfs_dirent *sd)
+{
+       /* We will not create default groups anymore. */
+       sd->s_depth = -1;
+}
+
+#else /* CONFIG_LOCKDEP */
+
+static void configfs_init_dirent_depth(struct configfs_dirent *sd)
+{
+}
+
+static void configfs_set_dir_dirent_depth(struct configfs_dirent *parent_sd,
+                                         struct configfs_dirent *sd)
+{
+}
+
+static void
+configfs_adjust_dir_dirent_depth_before_populate(struct configfs_dirent *sd)
+{
+}
+
+static void
+configfs_adjust_dir_dirent_depth_after_populate(struct configfs_dirent *sd)
+{
+}
+
+#endif /* CONFIG_LOCKDEP */
+
 /*
  * Allocates a new configfs_dirent and links it to the parent configfs_dirent
  */
-static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent * parent_sd,
-                                               void * element)
+static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent *parent_sd,
+                                                  void *element, int type)
 {
        struct configfs_dirent * sd;
 
@@ -94,6 +180,8 @@ static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent * pare
        INIT_LIST_HEAD(&sd->s_links);
        INIT_LIST_HEAD(&sd->s_children);
        sd->s_element = element;
+       sd->s_type = type;
+       configfs_init_dirent_depth(sd);
        spin_lock(&configfs_dirent_lock);
        if (parent_sd->s_type & CONFIGFS_USET_DROPPING) {
                spin_unlock(&configfs_dirent_lock);
@@ -138,12 +226,11 @@ int configfs_make_dirent(struct configfs_dirent * parent_sd,
 {
        struct configfs_dirent * sd;
 
-       sd = configfs_new_dirent(parent_sd, element);
+       sd = configfs_new_dirent(parent_sd, element, type);
        if (IS_ERR(sd))
                return PTR_ERR(sd);
 
        sd->s_mode = mode;
-       sd->s_type = type;
        sd->s_dentry = dentry;
        if (dentry) {
                dentry->d_fsdata = configfs_get(sd);
@@ -187,6 +274,7 @@ static int create_dir(struct config_item * k, struct dentry * p,
                error = configfs_make_dirent(p->d_fsdata, d, k, mode,
                                             CONFIGFS_DIR | CONFIGFS_USET_CREATING);
        if (!error) {
+               configfs_set_dir_dirent_depth(p->d_fsdata, d->d_fsdata);
                error = configfs_create(d, mode, init_dir);
                if (!error) {
                        inc_nlink(p->d_inode);
@@ -789,11 +877,13 @@ static int configfs_attach_group(struct config_item *parent_item,
                 * error, as rmdir() would.
                 */
                mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD);
+               configfs_adjust_dir_dirent_depth_before_populate(sd);
                ret = populate_groups(to_config_group(item));
                if (ret) {
                        configfs_detach_item(item);
                        dentry->d_inode->i_flags |= S_DEAD;
                }
+               configfs_adjust_dir_dirent_depth_after_populate(sd);
                mutex_unlock(&dentry->d_inode->i_mutex);
                if (ret)
                        d_delete(dentry);
@@ -916,11 +1006,11 @@ static int configfs_dump(struct configfs_dirent *sd, int level)
  * Note, btw, that this can be called at *any* time, even when a configfs
  * subsystem isn't registered, or when configfs is loading or unloading.
  * Just like configfs_register_subsystem().  So we take the same
- * precautions.  We pin the filesystem.  We lock each i_mutex _in_order_
- * on our way down the tree.  If we can find the target item in the
+ * precautions.  We pin the filesystem.  We lock configfs_dirent_lock.
+ * If we can find the target item in the
  * configfs tree, it must be part of the subsystem tree as well, so we
- * do not need the subsystem semaphore.  Holding the i_mutex chain locks
- * out mkdir() and rmdir(), who might be racing us.
+ * do not need the subsystem semaphore.  Holding configfs_dirent_lock helps
+ * locking out mkdir() and rmdir(), who might be racing us.
  */
 
 /*
@@ -933,17 +1023,21 @@ static int configfs_dump(struct configfs_dirent *sd, int level)
  * do that so we can unlock it if we find nothing.
  *
  * Here we do a depth-first search of the dentry hierarchy looking for
- * our object.  We take i_mutex on each step of the way down.  IT IS
- * ESSENTIAL THAT i_mutex LOCKING IS ORDERED.  If we come back up a branch,
- * we'll drop the i_mutex.
+ * our object.
+ * We deliberately ignore items tagged as dropping since they are virtually
+ * dead, as well as items in the middle of attachment since they virtually
+ * do not exist yet. This completes the locking out of racing mkdir() and
+ * rmdir().
+ * Note: subdirectories in the middle of attachment start with s_type =
+ * CONFIGFS_DIR|CONFIGFS_USET_CREATING set by create_dir().  When
+ * CONFIGFS_USET_CREATING is set, we ignore the item.  The actual set of
+ * s_type is in configfs_new_dirent(), which has configfs_dirent_lock.
  *
- * If the target is not found, -ENOENT is bubbled up and we have released
- * all locks.  If the target was found, the locks will be cleared by
- * configfs_depend_rollback().
+ * If the target is not found, -ENOENT is bubbled up.
  *
  * This adds a requirement that all config_items be unique!
  *
- * This is recursive because the locking traversal is tricky.  There isn't
+ * This is recursive.  There isn't
  * much on the stack, though, so folks that need this function - be careful
  * about your stack!  Patches will be accepted to make it iterative.
  */
@@ -955,13 +1049,13 @@ static int configfs_depend_prep(struct dentry *origin,
 
        BUG_ON(!origin || !sd);
 
-       /* Lock this guy on the way down */
-       mutex_lock(&sd->s_dentry->d_inode->i_mutex);
        if (sd->s_element == target)  /* Boo-yah */
                goto out;
 
        list_for_each_entry(child_sd, &sd->s_children, s_sibling) {
-               if (child_sd->s_type & CONFIGFS_DIR) {
+               if ((child_sd->s_type & CONFIGFS_DIR) &&
+                   !(child_sd->s_type & CONFIGFS_USET_DROPPING) &&
+                   !(child_sd->s_type & CONFIGFS_USET_CREATING)) {
                        ret = configfs_depend_prep(child_sd->s_dentry,
                                                   target);
                        if (!ret)
@@ -970,33 +1064,12 @@ static int configfs_depend_prep(struct dentry *origin,
        }
 
        /* We looped all our children and didn't find target */
-       mutex_unlock(&sd->s_dentry->d_inode->i_mutex);
        ret = -ENOENT;
 
 out:
        return ret;
 }
 
-/*
- * This is ONLY called if configfs_depend_prep() did its job.  So we can
- * trust the entire path from item back up to origin.
- *
- * We walk backwards from item, unlocking each i_mutex.  We finish by
- * unlocking origin.
- */
-static void configfs_depend_rollback(struct dentry *origin,
-                                    struct config_item *item)
-{
-       struct dentry *dentry = item->ci_dentry;
-
-       while (dentry != origin) {
-               mutex_unlock(&dentry->d_inode->i_mutex);
-               dentry = dentry->d_parent;
-       }
-
-       mutex_unlock(&origin->d_inode->i_mutex);
-}
-
 int configfs_depend_item(struct configfs_subsystem *subsys,
                         struct config_item *target)
 {
@@ -1037,17 +1110,21 @@ int configfs_depend_item(struct configfs_subsystem *subsys,
 
        /* Ok, now we can trust subsys/s_item */
 
-       /* Scan the tree, locking i_mutex recursively, return 0 if found */
+       spin_lock(&configfs_dirent_lock);
+       /* Scan the tree, return 0 if found */
        ret = configfs_depend_prep(subsys_sd->s_dentry, target);
        if (ret)
-               goto out_unlock_fs;
+               goto out_unlock_dirent_lock;
 
-       /* We hold all i_mutexes from the subsystem down to the target */
+       /*
+        * We are sure that the item is not about to be removed by rmdir(), and
+        * not in the middle of attachment by mkdir().
+        */
        p = target->ci_dentry->d_fsdata;
        p->s_dependent_count += 1;
 
-       configfs_depend_rollback(subsys_sd->s_dentry, target);
-
+out_unlock_dirent_lock:
+       spin_unlock(&configfs_dirent_lock);
 out_unlock_fs:
        mutex_unlock(&configfs_sb->s_root->d_inode->i_mutex);
 
@@ -1072,10 +1149,10 @@ void configfs_undepend_item(struct configfs_subsystem *subsys,
        struct configfs_dirent *sd;
 
        /*
-        * Since we can trust everything is pinned, we just need i_mutex
-        * on the item.
+        * Since we can trust everything is pinned, we just need
+        * configfs_dirent_lock.
         */
-       mutex_lock(&target->ci_dentry->d_inode->i_mutex);
+       spin_lock(&configfs_dirent_lock);
 
        sd = target->ci_dentry->d_fsdata;
        BUG_ON(sd->s_dependent_count < 1);
@@ -1086,7 +1163,7 @@ void configfs_undepend_item(struct configfs_subsystem *subsys,
         * After this unlock, we cannot trust the item to stay alive!
         * DO NOT REFERENCE item after this unlock.
         */
-       mutex_unlock(&target->ci_dentry->d_inode->i_mutex);
+       spin_unlock(&configfs_dirent_lock);
 }
 EXPORT_SYMBOL(configfs_undepend_item);
 
@@ -1286,13 +1363,6 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry)
        if (sd->s_type & CONFIGFS_USET_DEFAULT)
                return -EPERM;
 
-       /*
-        * Here's where we check for dependents.  We're protected by
-        * i_mutex.
-        */
-       if (sd->s_dependent_count)
-               return -EBUSY;
-
        /* Get a working ref until we have the child */
        parent_item = configfs_get_config_item(dentry->d_parent);
        subsys = to_config_group(parent_item)->cg_subsys;
@@ -1316,9 +1386,17 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry)
 
                mutex_lock(&configfs_symlink_mutex);
                spin_lock(&configfs_dirent_lock);
-               ret = configfs_detach_prep(dentry, &wait_mutex);
-               if (ret)
-                       configfs_detach_rollback(dentry);
+               /*
+                * Here's where we check for dependents.  We're protected by
+                * configfs_dirent_lock.
+                * If no dependent, atomically tag the item as dropping.
+                */
+               ret = sd->s_dependent_count ? -EBUSY : 0;
+               if (!ret) {
+                       ret = configfs_detach_prep(dentry, &wait_mutex);
+                       if (ret)
+                               configfs_detach_rollback(dentry);
+               }
                spin_unlock(&configfs_dirent_lock);
                mutex_unlock(&configfs_symlink_mutex);
 
@@ -1429,7 +1507,7 @@ static int configfs_dir_open(struct inode *inode, struct file *file)
         */
        err = -ENOENT;
        if (configfs_dirent_is_ready(parent_sd)) {
-               file->private_data = configfs_new_dirent(parent_sd, NULL);
+               file->private_data = configfs_new_dirent(parent_sd, NULL, 0);
                if (IS_ERR(file->private_data))
                        err = PTR_ERR(file->private_data);
                else
index 5d349d38e0561c4fd66e67bbda76c5f91ca87c69..4921e7426d95b4d3aed71a1dc0e0d7c89d1e2100 100644 (file)
 #include <linux/backing-dev.h>
 #include <linux/capability.h>
 #include <linux/sched.h>
+#include <linux/lockdep.h>
 
 #include <linux/configfs.h>
 #include "configfs_internal.h"
 
+#ifdef CONFIG_LOCKDEP
+static struct lock_class_key default_group_class[MAX_LOCK_DEPTH];
+#endif
+
 extern struct super_block * configfs_sb;
 
 static const struct address_space_operations configfs_aops = {
@@ -150,6 +155,38 @@ struct inode * configfs_new_inode(mode_t mode, struct configfs_dirent * sd)
        return inode;
 }
 
+#ifdef CONFIG_LOCKDEP
+
+static void configfs_set_inode_lock_class(struct configfs_dirent *sd,
+                                         struct inode *inode)
+{
+       int depth = sd->s_depth;
+
+       if (depth > 0) {
+               if (depth <= ARRAY_SIZE(default_group_class)) {
+                       lockdep_set_class(&inode->i_mutex,
+                                         &default_group_class[depth - 1]);
+               } else {
+                       /*
+                        * In practice the maximum level of locking depth is
+                        * already reached. Just inform about possible reasons.
+                        */
+                       printk(KERN_INFO "configfs: Too many levels of inodes"
+                              " for the locking correctness validator.\n");
+                       printk(KERN_INFO "Spurious warnings may appear.\n");
+               }
+       }
+}
+
+#else /* CONFIG_LOCKDEP */
+
+static void configfs_set_inode_lock_class(struct configfs_dirent *sd,
+                                         struct inode *inode)
+{
+}
+
+#endif /* CONFIG_LOCKDEP */
+
 int configfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *))
 {
        int error = 0;
@@ -162,6 +199,7 @@ int configfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *
                                        struct inode *p_inode = dentry->d_parent->d_inode;
                                        p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME;
                                }
+                               configfs_set_inode_lock_class(sd, inode);
                                goto Proceed;
                        }
                        else
index 858fba14aaa60712944aa2ef67102b3acc5cb071..c4dfa1dcc86f32d43469f5122c22ade5516544a5 100644 (file)
@@ -49,7 +49,8 @@ static struct dlm_direntry *get_free_de(struct dlm_ls *ls, int len)
        spin_unlock(&ls->ls_recover_list_lock);
 
        if (!found)
-               de = kzalloc(sizeof(struct dlm_direntry) + len, GFP_KERNEL);
+               de = kzalloc(sizeof(struct dlm_direntry) + len,
+                            ls->ls_allocation);
        return de;
 }
 
@@ -211,7 +212,7 @@ int dlm_recover_directory(struct dlm_ls *ls)
 
        dlm_dir_clear(ls);
 
-       last_name = kmalloc(DLM_RESNAME_MAXLEN, GFP_KERNEL);
+       last_name = kmalloc(DLM_RESNAME_MAXLEN, ls->ls_allocation);
        if (!last_name)
                goto out;
 
@@ -322,7 +323,7 @@ static int get_entry(struct dlm_ls *ls, int nodeid, char *name,
        if (namelen > DLM_RESNAME_MAXLEN)
                return -EINVAL;
 
-       de = kzalloc(sizeof(struct dlm_direntry) + namelen, GFP_KERNEL);
+       de = kzalloc(sizeof(struct dlm_direntry) + namelen, ls->ls_allocation);
        if (!de)
                return -ENOMEM;
 
index cd8e2df3c295f19dbe09141e6222ff4cd9c69a56..d489fcc86713de1d0484902d6e7f911b57377cd0 100644 (file)
@@ -384,7 +384,7 @@ static void threads_stop(void)
        dlm_astd_stop();
 }
 
-static int new_lockspace(char *name, int namelen, void **lockspace,
+static int new_lockspace(const char *name, int namelen, void **lockspace,
                         uint32_t flags, int lvblen)
 {
        struct dlm_ls *ls;
@@ -419,16 +419,14 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
                        break;
                }
                ls->ls_create_count++;
-               module_put(THIS_MODULE);
-               error = 1; /* not an error, return 0 */
+               *lockspace = ls;
+               error = 1;
                break;
        }
        spin_unlock(&lslist_lock);
 
-       if (error < 0)
-               goto out;
        if (error)
-               goto ret_zero;
+               goto out;
 
        error = -ENOMEM;
 
@@ -583,7 +581,6 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
        dlm_create_debug_file(ls);
 
        log_debug(ls, "join complete");
- ret_zero:
        *lockspace = ls;
        return 0;
 
@@ -614,7 +611,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
        return error;
 }
 
-int dlm_new_lockspace(char *name, int namelen, void **lockspace,
+int dlm_new_lockspace(const char *name, int namelen, void **lockspace,
                      uint32_t flags, int lvblen)
 {
        int error = 0;
@@ -628,7 +625,9 @@ int dlm_new_lockspace(char *name, int namelen, void **lockspace,
        error = new_lockspace(name, namelen, lockspace, flags, lvblen);
        if (!error)
                ls_count++;
-       else if (!ls_count)
+       if (error > 0)
+               error = 0;
+       if (!ls_count)
                threads_stop();
  out:
        mutex_unlock(&ls_lock);
index 609108a83267f3cfffd9d539f29496c0e5ffc1b1..cdb580a9c7a28352e903fa660c848826966b9dc1 100644 (file)
@@ -309,6 +309,20 @@ static void lowcomms_state_change(struct sock *sk)
                lowcomms_write_space(sk);
 }
 
+int dlm_lowcomms_connect_node(int nodeid)
+{
+       struct connection *con;
+
+       if (nodeid == dlm_our_nodeid())
+               return 0;
+
+       con = nodeid2con(nodeid, GFP_NOFS);
+       if (!con)
+               return -ENOMEM;
+       lowcomms_connect_sock(con);
+       return 0;
+}
+
 /* Make a socket active */
 static int add_sock(struct socket *sock, struct connection *con)
 {
@@ -486,7 +500,7 @@ static void process_sctp_notification(struct connection *con,
                                return;
                        }
 
-                       new_con = nodeid2con(nodeid, GFP_KERNEL);
+                       new_con = nodeid2con(nodeid, GFP_NOFS);
                        if (!new_con)
                                return;
 
@@ -722,7 +736,7 @@ static int tcp_accept_from_sock(struct connection *con)
         *  the same time and the connections cross on the wire.
         *  In this case we store the incoming one in "othercon"
         */
-       newcon = nodeid2con(nodeid, GFP_KERNEL);
+       newcon = nodeid2con(nodeid, GFP_NOFS);
        if (!newcon) {
                result = -ENOMEM;
                goto accept_err;
@@ -732,7 +746,7 @@ static int tcp_accept_from_sock(struct connection *con)
                struct connection *othercon = newcon->othercon;
 
                if (!othercon) {
-                       othercon = kmem_cache_zalloc(con_cache, GFP_KERNEL);
+                       othercon = kmem_cache_zalloc(con_cache, GFP_NOFS);
                        if (!othercon) {
                                log_print("failed to allocate incoming socket");
                                mutex_unlock(&newcon->sock_mutex);
@@ -1421,7 +1435,7 @@ static int work_start(void)
 static void stop_conn(struct connection *con)
 {
        con->flags |= 0x0F;
-       if (con->sock)
+       if (con->sock && con->sock->sk)
                con->sock->sk->sk_user_data = NULL;
 }
 
index a9a9618c0d3f2bcea8063a7217a7e2e036ed76fe..1311e6426287b61eed336c5f17f0cd1a67eab77f 100644 (file)
@@ -2,7 +2,7 @@
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2004-2009 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
@@ -19,6 +19,7 @@ void dlm_lowcomms_stop(void);
 int dlm_lowcomms_close(int nodeid);
 void *dlm_lowcomms_get_buffer(int nodeid, int len, gfp_t allocation, char **ppc);
 void dlm_lowcomms_commit_buffer(void *mh);
+int dlm_lowcomms_connect_node(int nodeid);
 
 #endif                         /* __LOWCOMMS_DOT_H__ */
 
index 26133f05ae3a7690911815358ad1f350343564b6..b128775913b29d6b43aeeec34910af6f9583ce9a 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
 *******************************************************************************
 **
-**  Copyright (C) 2005-2008 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2005-2009 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
@@ -17,6 +17,7 @@
 #include "recover.h"
 #include "rcom.h"
 #include "config.h"
+#include "lowcomms.h"
 
 static void add_ordered_member(struct dlm_ls *ls, struct dlm_member *new)
 {
@@ -45,9 +46,9 @@ static void add_ordered_member(struct dlm_ls *ls, struct dlm_member *new)
 static int dlm_add_member(struct dlm_ls *ls, int nodeid)
 {
        struct dlm_member *memb;
-       int w;
+       int w, error;
 
-       memb = kzalloc(sizeof(struct dlm_member), GFP_KERNEL);
+       memb = kzalloc(sizeof(struct dlm_member), ls->ls_allocation);
        if (!memb)
                return -ENOMEM;
 
@@ -57,6 +58,12 @@ static int dlm_add_member(struct dlm_ls *ls, int nodeid)
                return w;
        }
 
+       error = dlm_lowcomms_connect_node(nodeid);
+       if (error < 0) {
+               kfree(memb);
+               return error;
+       }
+
        memb->nodeid = nodeid;
        memb->weight = w;
        add_ordered_member(ls, memb);
@@ -136,7 +143,7 @@ static void make_member_array(struct dlm_ls *ls)
 
        ls->ls_total_weight = total;
 
-       array = kmalloc(sizeof(int) * total, GFP_KERNEL);
+       array = kmalloc(sizeof(int) * total, ls->ls_allocation);
        if (!array)
                return;
 
@@ -219,7 +226,7 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out)
                        continue;
                log_debug(ls, "new nodeid %d is a re-added member", rv->new[i]);
 
-               memb = kzalloc(sizeof(struct dlm_member), GFP_KERNEL);
+               memb = kzalloc(sizeof(struct dlm_member), ls->ls_allocation);
                if (!memb)
                        return -ENOMEM;
                memb->nodeid = rv->new[i];
@@ -334,7 +341,7 @@ int dlm_ls_start(struct dlm_ls *ls)
        int *ids = NULL, *new = NULL;
        int error, ids_count = 0, new_count = 0;
 
-       rv = kzalloc(sizeof(struct dlm_recover), GFP_KERNEL);
+       rv = kzalloc(sizeof(struct dlm_recover), ls->ls_allocation);
        if (!rv)
                return -ENOMEM;
 
index daa4183fbb8489ea759b439aec402092cd7dc0a6..7a2307c08911101e9f82b99e0c6bad22c03a6e24 100644 (file)
@@ -35,7 +35,7 @@ void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_message *ms)
        struct rq_entry *e;
        int length = ms->m_header.h_length - sizeof(struct dlm_message);
 
-       e = kmalloc(sizeof(struct rq_entry) + length, GFP_KERNEL);
+       e = kmalloc(sizeof(struct rq_entry) + length, ls->ls_allocation);
        if (!e) {
                log_print("dlm_add_requestqueue: out of memory len %d", length);
                return;
index 2a701d593d35f36d2511c25df916a5d61098b019..3f0e1974abdcfbfb8cd8afff3a19346667768672 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/anon_inodes.h>
 #include <linux/eventfd.h>
 #include <linux/syscalls.h>
+#include <linux/module.h>
 
 struct eventfd_ctx {
        wait_queue_head_t wqh;
@@ -56,6 +57,7 @@ int eventfd_signal(struct file *file, int n)
 
        return n;
 }
+EXPORT_SYMBOL_GPL(eventfd_signal);
 
 static int eventfd_release(struct inode *inode, struct file *file)
 {
@@ -197,6 +199,7 @@ struct file *eventfd_fget(int fd)
 
        return file;
 }
+EXPORT_SYMBOL_GPL(eventfd_fget);
 
 SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags)
 {
index b1512c4bb8c71d076dd5d27e1b7f08cda00c2e75..24667eedc02329554735f72420cbc04d99faa871 100644 (file)
@@ -175,10 +175,4 @@ int exofs_async_op(struct osd_request *or,
 
 int extract_attr_from_req(struct osd_request *or, struct osd_attr *attr);
 
-int osd_req_read_kern(struct osd_request *or,
-       const struct osd_obj_id *obj, u64 offset, void *buff, u64 len);
-
-int osd_req_write_kern(struct osd_request *or,
-       const struct osd_obj_id *obj, u64 offset, void *buff, u64 len);
-
 #endif /*ifndef __EXOFS_COM_H__*/
index ba8d9fab46932b26394331bb4d93ab60ba2736e5..77d0a295eb1cd3e95443da014fc9801cf64f5aff 100644 (file)
@@ -59,10 +59,9 @@ static void _pcol_init(struct page_collect *pcol, unsigned expected_pages,
                struct inode *inode)
 {
        struct exofs_sb_info *sbi = inode->i_sb->s_fs_info;
-       struct request_queue *req_q = sbi->s_dev->scsi_device->request_queue;
 
        pcol->sbi = sbi;
-       pcol->req_q = req_q;
+       pcol->req_q = osd_request_queue(sbi->s_dev);
        pcol->inode = inode;
        pcol->expected_pages = expected_pages;
 
@@ -266,7 +265,7 @@ static int read_exec(struct page_collect *pcol, bool is_sync)
                goto err;
        }
 
-       osd_req_read(or, &obj, pcol->bio, i_start);
+       osd_req_read(or, &obj, i_start, pcol->bio, pcol->length);
 
        if (is_sync) {
                exofs_sync_op(or, pcol->sbi->s_timeout, oi->i_cred);
@@ -522,7 +521,8 @@ static int write_exec(struct page_collect *pcol)
 
        *pcol_copy = *pcol;
 
-       osd_req_write(or, &obj, pcol_copy->bio, i_start);
+       pcol_copy->bio->bi_rw |= (1 << BIO_RW); /* FIXME: bio_set_dir() */
+       osd_req_write(or, &obj, i_start, pcol_copy->bio, pcol_copy->length);
        ret = exofs_async_op(or, writepages_done, pcol_copy, oi->i_cred);
        if (unlikely(ret)) {
                EXOFS_ERR("write_exec: exofs_async_op() Faild\n");
index 06ca92672eb5d6118ee644074019a650a96125f3..b3d2ccb87aaa8981374e824066bfd2aa608fa86a 100644 (file)
@@ -125,29 +125,3 @@ int extract_attr_from_req(struct osd_request *or, struct osd_attr *attr)
 
        return -EIO;
 }
-
-int osd_req_read_kern(struct osd_request *or,
-       const struct osd_obj_id *obj, u64 offset, void* buff, u64 len)
-{
-       struct request_queue *req_q = or->osd_dev->scsi_device->request_queue;
-       struct bio *bio = bio_map_kern(req_q, buff, len, GFP_KERNEL);
-
-       if (!bio)
-               return -ENOMEM;
-
-       osd_req_read(or, obj, bio, offset);
-       return 0;
-}
-
-int osd_req_write_kern(struct osd_request *or,
-       const struct osd_obj_id *obj, u64 offset, void* buff, u64 len)
-{
-       struct request_queue *req_q = or->osd_dev->scsi_device->request_queue;
-       struct bio *bio = bio_map_kern(req_q, buff, len, GFP_KERNEL);
-
-       if (!bio)
-               return -ENOMEM;
-
-       osd_req_write(or, obj, bio, offset);
-       return 0;
-}
index b2bbf45039e08170853bc058d975476b8971fbce..f2e5811936d07c23f9cdcb8565184fbd6769cb74 100644 (file)
@@ -27,7 +27,7 @@ struct ext2_inode_info {
        /*
         * i_block_group is the number of the block group which contains
         * this file's inode.  Constant across the lifetime of the inode,
-        * it is ued for making block allocation decisions - we try to
+        * it is used for making block allocation decisions - we try to
         * place a file's data blocks near its inode block, and new inodes
         * near to their parent directory's inode.
         */
index 72437065f6adee64994145be01efd281c482596a..e95eeb445e587fb09967a877822657dc7fd6d3c5 100644 (file)
@@ -3,5 +3,6 @@
 #
 
 obj-$(CONFIG_FUSE_FS) += fuse.o
+obj-$(CONFIG_CUSE) += cuse.o
 
 fuse-objs := dev.o dir.o file.o inode.o control.o
diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c
new file mode 100644 (file)
index 0000000..de792dc
--- /dev/null
@@ -0,0 +1,610 @@
+/*
+ * CUSE: Character device in Userspace
+ *
+ * Copyright (C) 2008-2009  SUSE Linux Products GmbH
+ * Copyright (C) 2008-2009  Tejun Heo <tj@kernel.org>
+ *
+ * This file is released under the GPLv2.
+ *
+ * CUSE enables character devices to be implemented from userland much
+ * like FUSE allows filesystems.  On initialization /dev/cuse is
+ * created.  By opening the file and replying to the CUSE_INIT request
+ * userland CUSE server can create a character device.  After that the
+ * operation is very similar to FUSE.
+ *
+ * A CUSE instance involves the following objects.
+ *
+ * cuse_conn   : contains fuse_conn and serves as bonding structure
+ * channel     : file handle connected to the userland CUSE server
+ * cdev                : the implemented character device
+ * dev         : generic device for cdev
+ *
+ * Note that 'channel' is what 'dev' is in FUSE.  As CUSE deals with
+ * devices, it's called 'channel' to reduce confusion.
+ *
+ * channel determines when the character device dies.  When channel is
+ * closed, everything begins to destruct.  The cuse_conn is taken off
+ * the lookup table preventing further access from cdev, cdev and
+ * generic device are removed and the base reference of cuse_conn is
+ * put.
+ *
+ * On each open, the matching cuse_conn is looked up and if found an
+ * additional reference is taken which is released when the file is
+ * closed.
+ */
+
+#include <linux/fuse.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/kdev_t.h>
+#include <linux/kthread.h>
+#include <linux/list.h>
+#include <linux/magic.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/stat.h>
+
+#include "fuse_i.h"
+
+#define CUSE_CONNTBL_LEN       64
+
+struct cuse_conn {
+       struct list_head        list;   /* linked on cuse_conntbl */
+       struct fuse_conn        fc;     /* fuse connection */
+       struct cdev             *cdev;  /* associated character device */
+       struct device           *dev;   /* device representing @cdev */
+
+       /* init parameters, set once during initialization */
+       bool                    unrestricted_ioctl;
+};
+
+static DEFINE_SPINLOCK(cuse_lock);             /* protects cuse_conntbl */
+static struct list_head cuse_conntbl[CUSE_CONNTBL_LEN];
+static struct class *cuse_class;
+
+static struct cuse_conn *fc_to_cc(struct fuse_conn *fc)
+{
+       return container_of(fc, struct cuse_conn, fc);
+}
+
+static struct list_head *cuse_conntbl_head(dev_t devt)
+{
+       return &cuse_conntbl[(MAJOR(devt) + MINOR(devt)) % CUSE_CONNTBL_LEN];
+}
+
+
+/**************************************************************************
+ * CUSE frontend operations
+ *
+ * These are file operations for the character device.
+ *
+ * On open, CUSE opens a file from the FUSE mnt and stores it to
+ * private_data of the open file.  All other ops call FUSE ops on the
+ * FUSE file.
+ */
+
+static ssize_t cuse_read(struct file *file, char __user *buf, size_t count,
+                        loff_t *ppos)
+{
+       loff_t pos = 0;
+
+       return fuse_direct_io(file, buf, count, &pos, 0);
+}
+
+static ssize_t cuse_write(struct file *file, const char __user *buf,
+                         size_t count, loff_t *ppos)
+{
+       loff_t pos = 0;
+       /*
+        * No locking or generic_write_checks(), the server is
+        * responsible for locking and sanity checks.
+        */
+       return fuse_direct_io(file, buf, count, &pos, 1);
+}
+
+static int cuse_open(struct inode *inode, struct file *file)
+{
+       dev_t devt = inode->i_cdev->dev;
+       struct cuse_conn *cc = NULL, *pos;
+       int rc;
+
+       /* look up and get the connection */
+       spin_lock(&cuse_lock);
+       list_for_each_entry(pos, cuse_conntbl_head(devt), list)
+               if (pos->dev->devt == devt) {
+                       fuse_conn_get(&pos->fc);
+                       cc = pos;
+                       break;
+               }
+       spin_unlock(&cuse_lock);
+
+       /* dead? */
+       if (!cc)
+               return -ENODEV;
+
+       /*
+        * Generic permission check is already done against the chrdev
+        * file, proceed to open.
+        */
+       rc = fuse_do_open(&cc->fc, 0, file, 0);
+       if (rc)
+               fuse_conn_put(&cc->fc);
+       return rc;
+}
+
+static int cuse_release(struct inode *inode, struct file *file)
+{
+       struct fuse_file *ff = file->private_data;
+       struct fuse_conn *fc = ff->fc;
+
+       fuse_sync_release(ff, file->f_flags);
+       fuse_conn_put(fc);
+
+       return 0;
+}
+
+static long cuse_file_ioctl(struct file *file, unsigned int cmd,
+                           unsigned long arg)
+{
+       struct fuse_file *ff = file->private_data;
+       struct cuse_conn *cc = fc_to_cc(ff->fc);
+       unsigned int flags = 0;
+
+       if (cc->unrestricted_ioctl)
+               flags |= FUSE_IOCTL_UNRESTRICTED;
+
+       return fuse_do_ioctl(file, cmd, arg, flags);
+}
+
+static long cuse_file_compat_ioctl(struct file *file, unsigned int cmd,
+                                  unsigned long arg)
+{
+       struct fuse_file *ff = file->private_data;
+       struct cuse_conn *cc = fc_to_cc(ff->fc);
+       unsigned int flags = FUSE_IOCTL_COMPAT;
+
+       if (cc->unrestricted_ioctl)
+               flags |= FUSE_IOCTL_UNRESTRICTED;
+
+       return fuse_do_ioctl(file, cmd, arg, flags);
+}
+
+static const struct file_operations cuse_frontend_fops = {
+       .owner                  = THIS_MODULE,
+       .read                   = cuse_read,
+       .write                  = cuse_write,
+       .open                   = cuse_open,
+       .release                = cuse_release,
+       .unlocked_ioctl         = cuse_file_ioctl,
+       .compat_ioctl           = cuse_file_compat_ioctl,
+       .poll                   = fuse_file_poll,
+};
+
+
+/**************************************************************************
+ * CUSE channel initialization and destruction
+ */
+
+struct cuse_devinfo {
+       const char              *name;
+};
+
+/**
+ * cuse_parse_one - parse one key=value pair
+ * @pp: i/o parameter for the current position
+ * @end: points to one past the end of the packed string
+ * @keyp: out parameter for key
+ * @valp: out parameter for value
+ *
+ * *@pp points to packed strings - "key0=val0\0key1=val1\0" which ends
+ * at @end - 1.  This function parses one pair and set *@keyp to the
+ * start of the key and *@valp to the start of the value.  Note that
+ * the original string is modified such that the key string is
+ * terminated with '\0'.  *@pp is updated to point to the next string.
+ *
+ * RETURNS:
+ * 1 on successful parse, 0 on EOF, -errno on failure.
+ */
+static int cuse_parse_one(char **pp, char *end, char **keyp, char **valp)
+{
+       char *p = *pp;
+       char *key, *val;
+
+       while (p < end && *p == '\0')
+               p++;
+       if (p == end)
+               return 0;
+
+       if (end[-1] != '\0') {
+               printk(KERN_ERR "CUSE: info not properly terminated\n");
+               return -EINVAL;
+       }
+
+       key = val = p;
+       p += strlen(p);
+
+       if (valp) {
+               strsep(&val, "=");
+               if (!val)
+                       val = key + strlen(key);
+               key = strstrip(key);
+               val = strstrip(val);
+       } else
+               key = strstrip(key);
+
+       if (!strlen(key)) {
+               printk(KERN_ERR "CUSE: zero length info key specified\n");
+               return -EINVAL;
+       }
+
+       *pp = p;
+       *keyp = key;
+       if (valp)
+               *valp = val;
+
+       return 1;
+}
+
+/**
+ * cuse_parse_dev_info - parse device info
+ * @p: device info string
+ * @len: length of device info string
+ * @devinfo: out parameter for parsed device info
+ *
+ * Parse @p to extract device info and store it into @devinfo.  String
+ * pointed to by @p is modified by parsing and @devinfo points into
+ * them, so @p shouldn't be freed while @devinfo is in use.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+static int cuse_parse_devinfo(char *p, size_t len, struct cuse_devinfo *devinfo)
+{
+       char *end = p + len;
+       char *key, *val;
+       int rc;
+
+       while (true) {
+               rc = cuse_parse_one(&p, end, &key, &val);
+               if (rc < 0)
+                       return rc;
+               if (!rc)
+                       break;
+               if (strcmp(key, "DEVNAME") == 0)
+                       devinfo->name = val;
+               else
+                       printk(KERN_WARNING "CUSE: unknown device info \"%s\"\n",
+                              key);
+       }
+
+       if (!devinfo->name || !strlen(devinfo->name)) {
+               printk(KERN_ERR "CUSE: DEVNAME unspecified\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void cuse_gendev_release(struct device *dev)
+{
+       kfree(dev);
+}
+
+/**
+ * cuse_process_init_reply - finish initializing CUSE channel
+ *
+ * This function creates the character device and sets up all the
+ * required data structures for it.  Please read the comment at the
+ * top of this file for high level overview.
+ */
+static void cuse_process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
+{
+       struct cuse_conn *cc = fc_to_cc(fc);
+       struct cuse_init_out *arg = &req->misc.cuse_init_out;
+       struct page *page = req->pages[0];
+       struct cuse_devinfo devinfo = { };
+       struct device *dev;
+       struct cdev *cdev;
+       dev_t devt;
+       int rc;
+
+       if (req->out.h.error ||
+           arg->major != FUSE_KERNEL_VERSION || arg->minor < 11) {
+               goto err;
+       }
+
+       fc->minor = arg->minor;
+       fc->max_read = max_t(unsigned, arg->max_read, 4096);
+       fc->max_write = max_t(unsigned, arg->max_write, 4096);
+
+       /* parse init reply */
+       cc->unrestricted_ioctl = arg->flags & CUSE_UNRESTRICTED_IOCTL;
+
+       rc = cuse_parse_devinfo(page_address(page), req->out.args[1].size,
+                               &devinfo);
+       if (rc)
+               goto err;
+
+       /* determine and reserve devt */
+       devt = MKDEV(arg->dev_major, arg->dev_minor);
+       if (!MAJOR(devt))
+               rc = alloc_chrdev_region(&devt, MINOR(devt), 1, devinfo.name);
+       else
+               rc = register_chrdev_region(devt, 1, devinfo.name);
+       if (rc) {
+               printk(KERN_ERR "CUSE: failed to register chrdev region\n");
+               goto err;
+       }
+
+       /* devt determined, create device */
+       rc = -ENOMEM;
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               goto err_region;
+
+       device_initialize(dev);
+       dev_set_uevent_suppress(dev, 1);
+       dev->class = cuse_class;
+       dev->devt = devt;
+       dev->release = cuse_gendev_release;
+       dev_set_drvdata(dev, cc);
+       dev_set_name(dev, "%s", devinfo.name);
+
+       rc = device_add(dev);
+       if (rc)
+               goto err_device;
+
+       /* register cdev */
+       rc = -ENOMEM;
+       cdev = cdev_alloc();
+       if (!cdev)
+               goto err_device;
+
+       cdev->owner = THIS_MODULE;
+       cdev->ops = &cuse_frontend_fops;
+
+       rc = cdev_add(cdev, devt, 1);
+       if (rc)
+               goto err_cdev;
+
+       cc->dev = dev;
+       cc->cdev = cdev;
+
+       /* make the device available */
+       spin_lock(&cuse_lock);
+       list_add(&cc->list, cuse_conntbl_head(devt));
+       spin_unlock(&cuse_lock);
+
+       /* announce device availability */
+       dev_set_uevent_suppress(dev, 0);
+       kobject_uevent(&dev->kobj, KOBJ_ADD);
+out:
+       __free_page(page);
+       return;
+
+err_cdev:
+       cdev_del(cdev);
+err_device:
+       put_device(dev);
+err_region:
+       unregister_chrdev_region(devt, 1);
+err:
+       fc->conn_error = 1;
+       goto out;
+}
+
+static int cuse_send_init(struct cuse_conn *cc)
+{
+       int rc;
+       struct fuse_req *req;
+       struct page *page;
+       struct fuse_conn *fc = &cc->fc;
+       struct cuse_init_in *arg;
+
+       BUILD_BUG_ON(CUSE_INIT_INFO_MAX > PAGE_SIZE);
+
+       req = fuse_get_req(fc);
+       if (IS_ERR(req)) {
+               rc = PTR_ERR(req);
+               goto err;
+       }
+
+       rc = -ENOMEM;
+       page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+       if (!page)
+               goto err_put_req;
+
+       arg = &req->misc.cuse_init_in;
+       arg->major = FUSE_KERNEL_VERSION;
+       arg->minor = FUSE_KERNEL_MINOR_VERSION;
+       arg->flags |= CUSE_UNRESTRICTED_IOCTL;
+       req->in.h.opcode = CUSE_INIT;
+       req->in.numargs = 1;
+       req->in.args[0].size = sizeof(struct cuse_init_in);
+       req->in.args[0].value = arg;
+       req->out.numargs = 2;
+       req->out.args[0].size = sizeof(struct cuse_init_out);
+       req->out.args[0].value = &req->misc.cuse_init_out;
+       req->out.args[1].size = CUSE_INIT_INFO_MAX;
+       req->out.argvar = 1;
+       req->out.argpages = 1;
+       req->pages[0] = page;
+       req->num_pages = 1;
+       req->end = cuse_process_init_reply;
+       fuse_request_send_background(fc, req);
+
+       return 0;
+
+err_put_req:
+       fuse_put_request(fc, req);
+err:
+       return rc;
+}
+
+static void cuse_fc_release(struct fuse_conn *fc)
+{
+       struct cuse_conn *cc = fc_to_cc(fc);
+       kfree(cc);
+}
+
+/**
+ * cuse_channel_open - open method for /dev/cuse
+ * @inode: inode for /dev/cuse
+ * @file: file struct being opened
+ *
+ * Userland CUSE server can create a CUSE device by opening /dev/cuse
+ * and replying to the initilaization request kernel sends.  This
+ * function is responsible for handling CUSE device initialization.
+ * Because the fd opened by this function is used during
+ * initialization, this function only creates cuse_conn and sends
+ * init.  The rest is delegated to a kthread.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+static int cuse_channel_open(struct inode *inode, struct file *file)
+{
+       struct cuse_conn *cc;
+       int rc;
+
+       /* set up cuse_conn */
+       cc = kzalloc(sizeof(*cc), GFP_KERNEL);
+       if (!cc)
+               return -ENOMEM;
+
+       fuse_conn_init(&cc->fc);
+
+       INIT_LIST_HEAD(&cc->list);
+       cc->fc.release = cuse_fc_release;
+
+       cc->fc.connected = 1;
+       cc->fc.blocked = 0;
+       rc = cuse_send_init(cc);
+       if (rc) {
+               fuse_conn_put(&cc->fc);
+               return rc;
+       }
+       file->private_data = &cc->fc;   /* channel owns base reference to cc */
+
+       return 0;
+}
+
+/**
+ * cuse_channel_release - release method for /dev/cuse
+ * @inode: inode for /dev/cuse
+ * @file: file struct being closed
+ *
+ * Disconnect the channel, deregister CUSE device and initiate
+ * destruction by putting the default reference.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+static int cuse_channel_release(struct inode *inode, struct file *file)
+{
+       struct cuse_conn *cc = fc_to_cc(file->private_data);
+       int rc;
+
+       /* remove from the conntbl, no more access from this point on */
+       spin_lock(&cuse_lock);
+       list_del_init(&cc->list);
+       spin_unlock(&cuse_lock);
+
+       /* remove device */
+       if (cc->dev)
+               device_unregister(cc->dev);
+       if (cc->cdev) {
+               unregister_chrdev_region(cc->cdev->dev, 1);
+               cdev_del(cc->cdev);
+       }
+
+       /* kill connection and shutdown channel */
+       fuse_conn_kill(&cc->fc);
+       rc = fuse_dev_release(inode, file);     /* puts the base reference */
+
+       return rc;
+}
+
+static struct file_operations cuse_channel_fops; /* initialized during init */
+
+
+/**************************************************************************
+ * Misc stuff and module initializatiion
+ *
+ * CUSE exports the same set of attributes to sysfs as fusectl.
+ */
+
+static ssize_t cuse_class_waiting_show(struct device *dev,
+                                      struct device_attribute *attr, char *buf)
+{
+       struct cuse_conn *cc = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d\n", atomic_read(&cc->fc.num_waiting));
+}
+
+static ssize_t cuse_class_abort_store(struct device *dev,
+                                     struct device_attribute *attr,
+                                     const char *buf, size_t count)
+{
+       struct cuse_conn *cc = dev_get_drvdata(dev);
+
+       fuse_abort_conn(&cc->fc);
+       return count;
+}
+
+static struct device_attribute cuse_class_dev_attrs[] = {
+       __ATTR(waiting, S_IFREG | 0400, cuse_class_waiting_show, NULL),
+       __ATTR(abort, S_IFREG | 0200, NULL, cuse_class_abort_store),
+       { }
+};
+
+static struct miscdevice cuse_miscdev = {
+       .minor          = MISC_DYNAMIC_MINOR,
+       .name           = "cuse",
+       .fops           = &cuse_channel_fops,
+};
+
+static int __init cuse_init(void)
+{
+       int i, rc;
+
+       /* init conntbl */
+       for (i = 0; i < CUSE_CONNTBL_LEN; i++)
+               INIT_LIST_HEAD(&cuse_conntbl[i]);
+
+       /* inherit and extend fuse_dev_operations */
+       cuse_channel_fops               = fuse_dev_operations;
+       cuse_channel_fops.owner         = THIS_MODULE;
+       cuse_channel_fops.open          = cuse_channel_open;
+       cuse_channel_fops.release       = cuse_channel_release;
+
+       cuse_class = class_create(THIS_MODULE, "cuse");
+       if (IS_ERR(cuse_class))
+               return PTR_ERR(cuse_class);
+
+       cuse_class->dev_attrs = cuse_class_dev_attrs;
+
+       rc = misc_register(&cuse_miscdev);
+       if (rc) {
+               class_destroy(cuse_class);
+               return rc;
+       }
+
+       return 0;
+}
+
+static void __exit cuse_exit(void)
+{
+       misc_deregister(&cuse_miscdev);
+       class_destroy(cuse_class);
+}
+
+module_init(cuse_init);
+module_exit(cuse_exit);
+
+MODULE_AUTHOR("Tejun Heo <tj@kernel.org>");
+MODULE_DESCRIPTION("Character device in Userspace");
+MODULE_LICENSE("GPL");
index ba76b68c52ffe2d127178d71ca5b5ab2ecc6a353..8fed2ed12f38b3ab468a042964ae800479f18d18 100644 (file)
@@ -46,6 +46,7 @@ struct fuse_req *fuse_request_alloc(void)
                fuse_request_init(req);
        return req;
 }
+EXPORT_SYMBOL_GPL(fuse_request_alloc);
 
 struct fuse_req *fuse_request_alloc_nofs(void)
 {
@@ -124,6 +125,7 @@ struct fuse_req *fuse_get_req(struct fuse_conn *fc)
        atomic_dec(&fc->num_waiting);
        return ERR_PTR(err);
 }
+EXPORT_SYMBOL_GPL(fuse_get_req);
 
 /*
  * Return request in fuse_file->reserved_req.  However that may
@@ -208,6 +210,7 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
                        fuse_request_free(req);
        }
 }
+EXPORT_SYMBOL_GPL(fuse_put_request);
 
 static unsigned len_args(unsigned numargs, struct fuse_arg *args)
 {
@@ -282,7 +285,7 @@ __releases(&fc->lock)
                        wake_up_all(&fc->blocked_waitq);
                }
                if (fc->num_background == FUSE_CONGESTION_THRESHOLD &&
-                   fc->connected) {
+                   fc->connected && fc->bdi_initialized) {
                        clear_bdi_congested(&fc->bdi, READ);
                        clear_bdi_congested(&fc->bdi, WRITE);
                }
@@ -400,6 +403,7 @@ void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req)
        }
        spin_unlock(&fc->lock);
 }
+EXPORT_SYMBOL_GPL(fuse_request_send);
 
 static void fuse_request_send_nowait_locked(struct fuse_conn *fc,
                                            struct fuse_req *req)
@@ -408,7 +412,8 @@ static void fuse_request_send_nowait_locked(struct fuse_conn *fc,
        fc->num_background++;
        if (fc->num_background == FUSE_MAX_BACKGROUND)
                fc->blocked = 1;
-       if (fc->num_background == FUSE_CONGESTION_THRESHOLD) {
+       if (fc->num_background == FUSE_CONGESTION_THRESHOLD &&
+           fc->bdi_initialized) {
                set_bdi_congested(&fc->bdi, READ);
                set_bdi_congested(&fc->bdi, WRITE);
        }
@@ -439,6 +444,7 @@ void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req)
        req->isreply = 1;
        fuse_request_send_nowait(fc, req);
 }
+EXPORT_SYMBOL_GPL(fuse_request_send_background);
 
 /*
  * Called under fc->lock
@@ -1105,8 +1111,9 @@ void fuse_abort_conn(struct fuse_conn *fc)
        }
        spin_unlock(&fc->lock);
 }
+EXPORT_SYMBOL_GPL(fuse_abort_conn);
 
-static int fuse_dev_release(struct inode *inode, struct file *file)
+int fuse_dev_release(struct inode *inode, struct file *file)
 {
        struct fuse_conn *fc = fuse_get_conn(file);
        if (fc) {
@@ -1120,6 +1127,7 @@ static int fuse_dev_release(struct inode *inode, struct file *file)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(fuse_dev_release);
 
 static int fuse_dev_fasync(int fd, struct file *file, int on)
 {
@@ -1142,6 +1150,7 @@ const struct file_operations fuse_dev_operations = {
        .release        = fuse_dev_release,
        .fasync         = fuse_dev_fasync,
 };
+EXPORT_SYMBOL_GPL(fuse_dev_operations);
 
 static struct miscdevice fuse_miscdevice = {
        .minor = FUSE_MINOR,
index 8b8eebc5614bb1e1f6dcba5ecd0ad1966d831f07..b3089a083d30c36a2afa17c03ca1345cc6d38206 100644 (file)
@@ -361,19 +361,6 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
        return ERR_PTR(err);
 }
 
-/*
- * Synchronous release for the case when something goes wrong in CREATE_OPEN
- */
-static void fuse_sync_release(struct fuse_conn *fc, struct fuse_file *ff,
-                             u64 nodeid, int flags)
-{
-       fuse_release_fill(ff, nodeid, flags, FUSE_RELEASE);
-       ff->reserved_req->force = 1;
-       fuse_request_send(fc, ff->reserved_req);
-       fuse_put_request(fc, ff->reserved_req);
-       kfree(ff);
-}
-
 /*
  * Atomic create+open operation
  *
@@ -445,12 +432,14 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
                goto out_free_ff;
 
        fuse_put_request(fc, req);
+       ff->fh = outopen.fh;
+       ff->nodeid = outentry.nodeid;
+       ff->open_flags = outopen.open_flags;
        inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
                          &outentry.attr, entry_attr_timeout(&outentry), 0);
        if (!inode) {
                flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
-               ff->fh = outopen.fh;
-               fuse_sync_release(fc, ff, outentry.nodeid, flags);
+               fuse_sync_release(ff, flags);
                fuse_send_forget(fc, forget_req, outentry.nodeid, 1);
                return -ENOMEM;
        }
@@ -460,11 +449,11 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
        fuse_invalidate_attr(dir);
        file = lookup_instantiate_filp(nd, entry, generic_file_open);
        if (IS_ERR(file)) {
-               ff->fh = outopen.fh;
-               fuse_sync_release(fc, ff, outentry.nodeid, flags);
+               fuse_sync_release(ff, flags);
                return PTR_ERR(file);
        }
-       fuse_finish_open(inode, file, ff, &outopen);
+       file->private_data = fuse_file_get(ff);
+       fuse_finish_open(inode, file);
        return 0;
 
  out_free_ff:
@@ -1035,7 +1024,7 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
        req->out.argpages = 1;
        req->num_pages = 1;
        req->pages[0] = page;
-       fuse_read_fill(req, file, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR);
+       fuse_read_fill(req, file, file->f_pos, PAGE_SIZE, FUSE_READDIR);
        fuse_request_send(fc, req);
        nbytes = req->out.args[0].size;
        err = req->out.h.error;
@@ -1101,12 +1090,14 @@ static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
 
 static int fuse_dir_open(struct inode *inode, struct file *file)
 {
-       return fuse_open_common(inode, file, 1);
+       return fuse_open_common(inode, file, true);
 }
 
 static int fuse_dir_release(struct inode *inode, struct file *file)
 {
-       return fuse_release_common(inode, file, 1);
+       fuse_release_common(file, FUSE_RELEASEDIR);
+
+       return 0;
 }
 
 static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
index 06f30e965676e00d9b781eaf9d666686c2a3f214..fce6ce694fdee3c4d6764c1dff661de755de675d 100644 (file)
 #include <linux/slab.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/module.h>
 
 static const struct file_operations fuse_direct_io_file_operations;
 
-static int fuse_send_open(struct inode *inode, struct file *file, int isdir,
-                         struct fuse_open_out *outargp)
+static int fuse_send_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
+                         int opcode, struct fuse_open_out *outargp)
 {
-       struct fuse_conn *fc = get_fuse_conn(inode);
        struct fuse_open_in inarg;
        struct fuse_req *req;
        int err;
@@ -31,8 +31,8 @@ static int fuse_send_open(struct inode *inode, struct file *file, int isdir,
        inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY);
        if (!fc->atomic_o_trunc)
                inarg.flags &= ~O_TRUNC;
-       req->in.h.opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN;
-       req->in.h.nodeid = get_node_id(inode);
+       req->in.h.opcode = opcode;
+       req->in.h.nodeid = nodeid;
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(inarg);
        req->in.args[0].value = &inarg;
@@ -49,22 +49,27 @@ static int fuse_send_open(struct inode *inode, struct file *file, int isdir,
 struct fuse_file *fuse_file_alloc(struct fuse_conn *fc)
 {
        struct fuse_file *ff;
+
        ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL);
-       if (ff) {
-               ff->reserved_req = fuse_request_alloc();
-               if (!ff->reserved_req) {
-                       kfree(ff);
-                       return NULL;
-               } else {
-                       INIT_LIST_HEAD(&ff->write_entry);
-                       atomic_set(&ff->count, 0);
-                       spin_lock(&fc->lock);
-                       ff->kh = ++fc->khctr;
-                       spin_unlock(&fc->lock);
-               }
-               RB_CLEAR_NODE(&ff->polled_node);
-               init_waitqueue_head(&ff->poll_wait);
+       if (unlikely(!ff))
+               return NULL;
+
+       ff->fc = fc;
+       ff->reserved_req = fuse_request_alloc();
+       if (unlikely(!ff->reserved_req)) {
+               kfree(ff);
+               return NULL;
        }
+
+       INIT_LIST_HEAD(&ff->write_entry);
+       atomic_set(&ff->count, 0);
+       RB_CLEAR_NODE(&ff->polled_node);
+       init_waitqueue_head(&ff->poll_wait);
+
+       spin_lock(&fc->lock);
+       ff->kh = ++fc->khctr;
+       spin_unlock(&fc->lock);
+
        return ff;
 }
 
@@ -74,7 +79,7 @@ void fuse_file_free(struct fuse_file *ff)
        kfree(ff);
 }
 
-static struct fuse_file *fuse_file_get(struct fuse_file *ff)
+struct fuse_file *fuse_file_get(struct fuse_file *ff)
 {
        atomic_inc(&ff->count);
        return ff;
@@ -82,40 +87,65 @@ static struct fuse_file *fuse_file_get(struct fuse_file *ff)
 
 static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req)
 {
-       dput(req->misc.release.dentry);
-       mntput(req->misc.release.vfsmount);
+       path_put(&req->misc.release.path);
 }
 
 static void fuse_file_put(struct fuse_file *ff)
 {
        if (atomic_dec_and_test(&ff->count)) {
                struct fuse_req *req = ff->reserved_req;
-               struct inode *inode = req->misc.release.dentry->d_inode;
-               struct fuse_conn *fc = get_fuse_conn(inode);
+
                req->end = fuse_release_end;
-               fuse_request_send_background(fc, req);
+               fuse_request_send_background(ff->fc, req);
                kfree(ff);
        }
 }
 
-void fuse_finish_open(struct inode *inode, struct file *file,
-                     struct fuse_file *ff, struct fuse_open_out *outarg)
+int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
+                bool isdir)
 {
-       if (outarg->open_flags & FOPEN_DIRECT_IO)
+       struct fuse_open_out outarg;
+       struct fuse_file *ff;
+       int err;
+       int opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN;
+
+       ff = fuse_file_alloc(fc);
+       if (!ff)
+               return -ENOMEM;
+
+       err = fuse_send_open(fc, nodeid, file, opcode, &outarg);
+       if (err) {
+               fuse_file_free(ff);
+               return err;
+       }
+
+       if (isdir)
+               outarg.open_flags &= ~FOPEN_DIRECT_IO;
+
+       ff->fh = outarg.fh;
+       ff->nodeid = nodeid;
+       ff->open_flags = outarg.open_flags;
+       file->private_data = fuse_file_get(ff);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(fuse_do_open);
+
+void fuse_finish_open(struct inode *inode, struct file *file)
+{
+       struct fuse_file *ff = file->private_data;
+
+       if (ff->open_flags & FOPEN_DIRECT_IO)
                file->f_op = &fuse_direct_io_file_operations;
-       if (!(outarg->open_flags & FOPEN_KEEP_CACHE))
+       if (!(ff->open_flags & FOPEN_KEEP_CACHE))
                invalidate_inode_pages2(inode->i_mapping);
-       if (outarg->open_flags & FOPEN_NONSEEKABLE)
+       if (ff->open_flags & FOPEN_NONSEEKABLE)
                nonseekable_open(inode, file);
-       ff->fh = outarg->fh;
-       file->private_data = fuse_file_get(ff);
 }
 
-int fuse_open_common(struct inode *inode, struct file *file, int isdir)
+int fuse_open_common(struct inode *inode, struct file *file, bool isdir)
 {
        struct fuse_conn *fc = get_fuse_conn(inode);
-       struct fuse_open_out outarg;
-       struct fuse_file *ff;
        int err;
 
        /* VFS checks this, but only _after_ ->open() */
@@ -126,78 +156,85 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir)
        if (err)
                return err;
 
-       ff = fuse_file_alloc(fc);
-       if (!ff)
-               return -ENOMEM;
-
-       err = fuse_send_open(inode, file, isdir, &outarg);
+       err = fuse_do_open(fc, get_node_id(inode), file, isdir);
        if (err)
-               fuse_file_free(ff);
-       else {
-               if (isdir)
-                       outarg.open_flags &= ~FOPEN_DIRECT_IO;
-               fuse_finish_open(inode, file, ff, &outarg);
-       }
+               return err;
 
-       return err;
+       fuse_finish_open(inode, file);
+
+       return 0;
 }
 
-void fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags, int opcode)
+static void fuse_prepare_release(struct fuse_file *ff, int flags, int opcode)
 {
+       struct fuse_conn *fc = ff->fc;
        struct fuse_req *req = ff->reserved_req;
        struct fuse_release_in *inarg = &req->misc.release.in;
 
+       spin_lock(&fc->lock);
+       list_del(&ff->write_entry);
+       if (!RB_EMPTY_NODE(&ff->polled_node))
+               rb_erase(&ff->polled_node, &fc->polled_files);
+       spin_unlock(&fc->lock);
+
+       wake_up_interruptible_sync(&ff->poll_wait);
+
        inarg->fh = ff->fh;
        inarg->flags = flags;
        req->in.h.opcode = opcode;
-       req->in.h.nodeid = nodeid;
+       req->in.h.nodeid = ff->nodeid;
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(struct fuse_release_in);
        req->in.args[0].value = inarg;
 }
 
-int fuse_release_common(struct inode *inode, struct file *file, int isdir)
+void fuse_release_common(struct file *file, int opcode)
 {
-       struct fuse_file *ff = file->private_data;
-       if (ff) {
-               struct fuse_conn *fc = get_fuse_conn(inode);
-               struct fuse_req *req = ff->reserved_req;
-
-               fuse_release_fill(ff, get_node_id(inode), file->f_flags,
-                                 isdir ? FUSE_RELEASEDIR : FUSE_RELEASE);
+       struct fuse_file *ff;
+       struct fuse_req *req;
 
-               /* Hold vfsmount and dentry until release is finished */
-               req->misc.release.vfsmount = mntget(file->f_path.mnt);
-               req->misc.release.dentry = dget(file->f_path.dentry);
+       ff = file->private_data;
+       if (unlikely(!ff))
+               return;
 
-               spin_lock(&fc->lock);
-               list_del(&ff->write_entry);
-               if (!RB_EMPTY_NODE(&ff->polled_node))
-                       rb_erase(&ff->polled_node, &fc->polled_files);
-               spin_unlock(&fc->lock);
+       req = ff->reserved_req;
+       fuse_prepare_release(ff, file->f_flags, opcode);
 
-               wake_up_interruptible_sync(&ff->poll_wait);
-               /*
-                * Normally this will send the RELEASE request,
-                * however if some asynchronous READ or WRITE requests
-                * are outstanding, the sending will be delayed
-                */
-               fuse_file_put(ff);
-       }
+       /* Hold vfsmount and dentry until release is finished */
+       path_get(&file->f_path);
+       req->misc.release.path = file->f_path;
 
-       /* Return value is ignored by VFS */
-       return 0;
+       /*
+        * Normally this will send the RELEASE request, however if
+        * some asynchronous READ or WRITE requests are outstanding,
+        * the sending will be delayed.
+        */
+       fuse_file_put(ff);
 }
 
 static int fuse_open(struct inode *inode, struct file *file)
 {
-       return fuse_open_common(inode, file, 0);
+       return fuse_open_common(inode, file, false);
 }
 
 static int fuse_release(struct inode *inode, struct file *file)
 {
-       return fuse_release_common(inode, file, 0);
+       fuse_release_common(file, FUSE_RELEASE);
+
+       /* return value is ignored by VFS */
+       return 0;
+}
+
+void fuse_sync_release(struct fuse_file *ff, int flags)
+{
+       WARN_ON(atomic_read(&ff->count) > 1);
+       fuse_prepare_release(ff, flags, FUSE_RELEASE);
+       ff->reserved_req->force = 1;
+       fuse_request_send(ff->fc, ff->reserved_req);
+       fuse_put_request(ff->fc, ff->reserved_req);
+       kfree(ff);
 }
+EXPORT_SYMBOL_GPL(fuse_sync_release);
 
 /*
  * Scramble the ID space with XTEA, so that the value of the files_struct
@@ -371,8 +408,8 @@ static int fuse_fsync(struct file *file, struct dentry *de, int datasync)
        return fuse_fsync_common(file, de, datasync, 0);
 }
 
-void fuse_read_fill(struct fuse_req *req, struct file *file,
-                   struct inode *inode, loff_t pos, size_t count, int opcode)
+void fuse_read_fill(struct fuse_req *req, struct file *file, loff_t pos,
+                   size_t count, int opcode)
 {
        struct fuse_read_in *inarg = &req->misc.read.in;
        struct fuse_file *ff = file->private_data;
@@ -382,7 +419,7 @@ void fuse_read_fill(struct fuse_req *req, struct file *file,
        inarg->size = count;
        inarg->flags = file->f_flags;
        req->in.h.opcode = opcode;
-       req->in.h.nodeid = get_node_id(inode);
+       req->in.h.nodeid = ff->nodeid;
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(struct fuse_read_in);
        req->in.args[0].value = inarg;
@@ -392,12 +429,12 @@ void fuse_read_fill(struct fuse_req *req, struct file *file,
 }
 
 static size_t fuse_send_read(struct fuse_req *req, struct file *file,
-                            struct inode *inode, loff_t pos, size_t count,
-                            fl_owner_t owner)
+                            loff_t pos, size_t count, fl_owner_t owner)
 {
-       struct fuse_conn *fc = get_fuse_conn(inode);
+       struct fuse_file *ff = file->private_data;
+       struct fuse_conn *fc = ff->fc;
 
-       fuse_read_fill(req, file, inode, pos, count, FUSE_READ);
+       fuse_read_fill(req, file, pos, count, FUSE_READ);
        if (owner != NULL) {
                struct fuse_read_in *inarg = &req->misc.read.in;
 
@@ -455,7 +492,7 @@ static int fuse_readpage(struct file *file, struct page *page)
        req->out.argpages = 1;
        req->num_pages = 1;
        req->pages[0] = page;
-       num_read = fuse_send_read(req, file, inode, pos, count, NULL);
+       num_read = fuse_send_read(req, file, pos, count, NULL);
        err = req->out.h.error;
        fuse_put_request(fc, req);
 
@@ -504,19 +541,18 @@ static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req)
                fuse_file_put(req->ff);
 }
 
-static void fuse_send_readpages(struct fuse_req *req, struct file *file,
-                               struct inode *inode)
+static void fuse_send_readpages(struct fuse_req *req, struct file *file)
 {
-       struct fuse_conn *fc = get_fuse_conn(inode);
+       struct fuse_file *ff = file->private_data;
+       struct fuse_conn *fc = ff->fc;
        loff_t pos = page_offset(req->pages[0]);
        size_t count = req->num_pages << PAGE_CACHE_SHIFT;
 
        req->out.argpages = 1;
        req->out.page_zeroing = 1;
-       fuse_read_fill(req, file, inode, pos, count, FUSE_READ);
+       fuse_read_fill(req, file, pos, count, FUSE_READ);
        req->misc.read.attr_ver = fuse_get_attr_version(fc);
        if (fc->async_read) {
-               struct fuse_file *ff = file->private_data;
                req->ff = fuse_file_get(ff);
                req->end = fuse_readpages_end;
                fuse_request_send_background(fc, req);
@@ -546,7 +582,7 @@ static int fuse_readpages_fill(void *_data, struct page *page)
            (req->num_pages == FUSE_MAX_PAGES_PER_REQ ||
             (req->num_pages + 1) * PAGE_CACHE_SIZE > fc->max_read ||
             req->pages[req->num_pages - 1]->index + 1 != page->index)) {
-               fuse_send_readpages(req, data->file, inode);
+               fuse_send_readpages(req, data->file);
                data->req = req = fuse_get_req(fc);
                if (IS_ERR(req)) {
                        unlock_page(page);
@@ -580,7 +616,7 @@ static int fuse_readpages(struct file *file, struct address_space *mapping,
        err = read_cache_pages(mapping, pages, fuse_readpages_fill, &data);
        if (!err) {
                if (data.req->num_pages)
-                       fuse_send_readpages(data.req, file, inode);
+                       fuse_send_readpages(data.req, file);
                else
                        fuse_put_request(fc, data.req);
        }
@@ -607,24 +643,19 @@ static ssize_t fuse_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
        return generic_file_aio_read(iocb, iov, nr_segs, pos);
 }
 
-static void fuse_write_fill(struct fuse_req *req, struct file *file,
-                           struct fuse_file *ff, struct inode *inode,
-                           loff_t pos, size_t count, int writepage)
+static void fuse_write_fill(struct fuse_req *req, struct fuse_file *ff,
+                           loff_t pos, size_t count)
 {
-       struct fuse_conn *fc = get_fuse_conn(inode);
        struct fuse_write_in *inarg = &req->misc.write.in;
        struct fuse_write_out *outarg = &req->misc.write.out;
 
-       memset(inarg, 0, sizeof(struct fuse_write_in));
        inarg->fh = ff->fh;
        inarg->offset = pos;
        inarg->size = count;
-       inarg->write_flags = writepage ? FUSE_WRITE_CACHE : 0;
-       inarg->flags = file ? file->f_flags : 0;
        req->in.h.opcode = FUSE_WRITE;
-       req->in.h.nodeid = get_node_id(inode);
+       req->in.h.nodeid = ff->nodeid;
        req->in.numargs = 2;
-       if (fc->minor < 9)
+       if (ff->fc->minor < 9)
                req->in.args[0].size = FUSE_COMPAT_WRITE_IN_SIZE;
        else
                req->in.args[0].size = sizeof(struct fuse_write_in);
@@ -636,13 +667,15 @@ static void fuse_write_fill(struct fuse_req *req, struct file *file,
 }
 
 static size_t fuse_send_write(struct fuse_req *req, struct file *file,
-                             struct inode *inode, loff_t pos, size_t count,
-                             fl_owner_t owner)
+                             loff_t pos, size_t count, fl_owner_t owner)
 {
-       struct fuse_conn *fc = get_fuse_conn(inode);
-       fuse_write_fill(req, file, file->private_data, inode, pos, count, 0);
+       struct fuse_file *ff = file->private_data;
+       struct fuse_conn *fc = ff->fc;
+       struct fuse_write_in *inarg = &req->misc.write.in;
+
+       fuse_write_fill(req, ff, pos, count);
+       inarg->flags = file->f_flags;
        if (owner != NULL) {
-               struct fuse_write_in *inarg = &req->misc.write.in;
                inarg->write_flags |= FUSE_WRITE_LOCKOWNER;
                inarg->lock_owner = fuse_lock_owner_id(fc, owner);
        }
@@ -700,7 +733,7 @@ static int fuse_buffered_write(struct file *file, struct inode *inode,
        req->num_pages = 1;
        req->pages[0] = page;
        req->page_offset = offset;
-       nres = fuse_send_write(req, file, inode, pos, count, NULL);
+       nres = fuse_send_write(req, file, pos, count, NULL);
        err = req->out.h.error;
        fuse_put_request(fc, req);
        if (!err && !nres)
@@ -741,7 +774,7 @@ static size_t fuse_send_write_pages(struct fuse_req *req, struct file *file,
        for (i = 0; i < req->num_pages; i++)
                fuse_wait_on_page_writeback(inode, req->pages[i]->index);
 
-       res = fuse_send_write(req, file, inode, pos, count, NULL);
+       res = fuse_send_write(req, file, pos, count, NULL);
 
        offset = req->page_offset;
        count = res;
@@ -979,25 +1012,23 @@ static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf,
        return 0;
 }
 
-static ssize_t fuse_direct_io(struct file *file, const char __user *buf,
-                             size_t count, loff_t *ppos, int write)
+ssize_t fuse_direct_io(struct file *file, const char __user *buf,
+                      size_t count, loff_t *ppos, int write)
 {
-       struct inode *inode = file->f_path.dentry->d_inode;
-       struct fuse_conn *fc = get_fuse_conn(inode);
+       struct fuse_file *ff = file->private_data;
+       struct fuse_conn *fc = ff->fc;
        size_t nmax = write ? fc->max_write : fc->max_read;
        loff_t pos = *ppos;
        ssize_t res = 0;
        struct fuse_req *req;
 
-       if (is_bad_inode(inode))
-               return -EIO;
-
        req = fuse_get_req(fc);
        if (IS_ERR(req))
                return PTR_ERR(req);
 
        while (count) {
                size_t nres;
+               fl_owner_t owner = current->files;
                size_t nbytes = min(count, nmax);
                int err = fuse_get_user_pages(req, buf, &nbytes, write);
                if (err) {
@@ -1006,11 +1037,10 @@ static ssize_t fuse_direct_io(struct file *file, const char __user *buf,
                }
 
                if (write)
-                       nres = fuse_send_write(req, file, inode, pos, nbytes,
-                                              current->files);
+                       nres = fuse_send_write(req, file, pos, nbytes, owner);
                else
-                       nres = fuse_send_read(req, file, inode, pos, nbytes,
-                                             current->files);
+                       nres = fuse_send_read(req, file, pos, nbytes, owner);
+
                fuse_release_user_pages(req, !write);
                if (req->out.h.error) {
                        if (!res)
@@ -1034,20 +1064,27 @@ static ssize_t fuse_direct_io(struct file *file, const char __user *buf,
                }
        }
        fuse_put_request(fc, req);
-       if (res > 0) {
-               if (write)
-                       fuse_write_update_size(inode, pos);
+       if (res > 0)
                *ppos = pos;
-       }
-       fuse_invalidate_attr(inode);
 
        return res;
 }
+EXPORT_SYMBOL_GPL(fuse_direct_io);
 
 static ssize_t fuse_direct_read(struct file *file, char __user *buf,
                                     size_t count, loff_t *ppos)
 {
-       return fuse_direct_io(file, buf, count, ppos, 0);
+       ssize_t res;
+       struct inode *inode = file->f_path.dentry->d_inode;
+
+       if (is_bad_inode(inode))
+               return -EIO;
+
+       res = fuse_direct_io(file, buf, count, ppos, 0);
+
+       fuse_invalidate_attr(inode);
+
+       return res;
 }
 
 static ssize_t fuse_direct_write(struct file *file, const char __user *buf,
@@ -1055,12 +1092,22 @@ static ssize_t fuse_direct_write(struct file *file, const char __user *buf,
 {
        struct inode *inode = file->f_path.dentry->d_inode;
        ssize_t res;
+
+       if (is_bad_inode(inode))
+               return -EIO;
+
        /* Don't allow parallel writes to the same file */
        mutex_lock(&inode->i_mutex);
        res = generic_write_checks(file, ppos, &count, 0);
-       if (!res)
+       if (!res) {
                res = fuse_direct_io(file, buf, count, ppos, 1);
+               if (res > 0)
+                       fuse_write_update_size(inode, *ppos);
+       }
        mutex_unlock(&inode->i_mutex);
+
+       fuse_invalidate_attr(inode);
+
        return res;
 }
 
@@ -1177,9 +1224,10 @@ static int fuse_writepage_locked(struct page *page)
        req->ff = fuse_file_get(ff);
        spin_unlock(&fc->lock);
 
-       fuse_write_fill(req, NULL, ff, inode, page_offset(page), 0, 1);
+       fuse_write_fill(req, ff, page_offset(page), 0);
 
        copy_highpage(tmp_page, page);
+       req->misc.write.in.write_flags |= FUSE_WRITE_CACHE;
        req->in.argpages = 1;
        req->num_pages = 1;
        req->pages[0] = tmp_page;
@@ -1603,12 +1651,11 @@ static int fuse_ioctl_copy_user(struct page **pages, struct iovec *iov,
  * limits ioctl data transfers to well-formed ioctls and is the forced
  * behavior for all FUSE servers.
  */
-static long fuse_file_do_ioctl(struct file *file, unsigned int cmd,
-                              unsigned long arg, unsigned int flags)
+long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
+                  unsigned int flags)
 {
-       struct inode *inode = file->f_dentry->d_inode;
        struct fuse_file *ff = file->private_data;
-       struct fuse_conn *fc = get_fuse_conn(inode);
+       struct fuse_conn *fc = ff->fc;
        struct fuse_ioctl_in inarg = {
                .fh = ff->fh,
                .cmd = cmd,
@@ -1627,13 +1674,6 @@ static long fuse_file_do_ioctl(struct file *file, unsigned int cmd,
        /* assume all the iovs returned by client always fits in a page */
        BUILD_BUG_ON(sizeof(struct iovec) * FUSE_IOCTL_MAX_IOV > PAGE_SIZE);
 
-       if (!fuse_allow_task(fc, current))
-               return -EACCES;
-
-       err = -EIO;
-       if (is_bad_inode(inode))
-               goto out;
-
        err = -ENOMEM;
        pages = kzalloc(sizeof(pages[0]) * FUSE_MAX_PAGES_PER_REQ, GFP_KERNEL);
        iov_page = alloc_page(GFP_KERNEL);
@@ -1694,7 +1734,7 @@ static long fuse_file_do_ioctl(struct file *file, unsigned int cmd,
 
        /* okay, let's send it to the client */
        req->in.h.opcode = FUSE_IOCTL;
-       req->in.h.nodeid = get_node_id(inode);
+       req->in.h.nodeid = ff->nodeid;
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(inarg);
        req->in.args[0].value = &inarg;
@@ -1777,17 +1817,33 @@ static long fuse_file_do_ioctl(struct file *file, unsigned int cmd,
 
        return err ? err : outarg.result;
 }
+EXPORT_SYMBOL_GPL(fuse_do_ioctl);
+
+static long fuse_file_ioctl_common(struct file *file, unsigned int cmd,
+                                  unsigned long arg, unsigned int flags)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct fuse_conn *fc = get_fuse_conn(inode);
+
+       if (!fuse_allow_task(fc, current))
+               return -EACCES;
+
+       if (is_bad_inode(inode))
+               return -EIO;
+
+       return fuse_do_ioctl(file, cmd, arg, flags);
+}
 
 static long fuse_file_ioctl(struct file *file, unsigned int cmd,
                            unsigned long arg)
 {
-       return fuse_file_do_ioctl(file, cmd, arg, 0);
+       return fuse_file_ioctl_common(file, cmd, arg, 0);
 }
 
 static long fuse_file_compat_ioctl(struct file *file, unsigned int cmd,
                                   unsigned long arg)
 {
-       return fuse_file_do_ioctl(file, cmd, arg, FUSE_IOCTL_COMPAT);
+       return fuse_file_ioctl_common(file, cmd, arg, FUSE_IOCTL_COMPAT);
 }
 
 /*
@@ -1841,11 +1897,10 @@ static void fuse_register_polled_file(struct fuse_conn *fc,
        spin_unlock(&fc->lock);
 }
 
-static unsigned fuse_file_poll(struct file *file, poll_table *wait)
+unsigned fuse_file_poll(struct file *file, poll_table *wait)
 {
-       struct inode *inode = file->f_dentry->d_inode;
        struct fuse_file *ff = file->private_data;
-       struct fuse_conn *fc = get_fuse_conn(inode);
+       struct fuse_conn *fc = ff->fc;
        struct fuse_poll_in inarg = { .fh = ff->fh, .kh = ff->kh };
        struct fuse_poll_out outarg;
        struct fuse_req *req;
@@ -1870,7 +1925,7 @@ static unsigned fuse_file_poll(struct file *file, poll_table *wait)
                return PTR_ERR(req);
 
        req->in.h.opcode = FUSE_POLL;
-       req->in.h.nodeid = get_node_id(inode);
+       req->in.h.nodeid = ff->nodeid;
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(inarg);
        req->in.args[0].value = &inarg;
@@ -1889,6 +1944,7 @@ static unsigned fuse_file_poll(struct file *file, poll_table *wait)
        }
        return POLLERR;
 }
+EXPORT_SYMBOL_GPL(fuse_file_poll);
 
 /*
  * This is called from fuse_handle_notify() on FUSE_NOTIFY_POLL and
index 6fc5aedaa0d52b3d86d94bde490aa5711e47cfd1..aaf2f9ff970ec4b824b6bf792264db9dd579f58c 100644 (file)
@@ -97,8 +97,13 @@ struct fuse_inode {
        struct list_head writepages;
 };
 
+struct fuse_conn;
+
 /** FUSE specific file data */
 struct fuse_file {
+       /** Fuse connection for this file */
+       struct fuse_conn *fc;
+
        /** Request reserved for flush and release */
        struct fuse_req *reserved_req;
 
@@ -108,9 +113,15 @@ struct fuse_file {
        /** File handle used by userspace */
        u64 fh;
 
+       /** Node id of this file */
+       u64 nodeid;
+
        /** Refcount */
        atomic_t count;
 
+       /** FOPEN_* flags returned by open */
+       u32 open_flags;
+
        /** Entry on inode's write_files list */
        struct list_head write_entry;
 
@@ -185,8 +196,6 @@ enum fuse_req_state {
        FUSE_REQ_FINISHED
 };
 
-struct fuse_conn;
-
 /**
  * A request to the client
  */
@@ -248,11 +257,12 @@ struct fuse_req {
                struct fuse_forget_in forget_in;
                struct {
                        struct fuse_release_in in;
-                       struct vfsmount *vfsmount;
-                       struct dentry *dentry;
+                       struct path path;
                } release;
                struct fuse_init_in init_in;
                struct fuse_init_out init_out;
+               struct cuse_init_in cuse_init_in;
+               struct cuse_init_out cuse_init_out;
                struct {
                        struct fuse_read_in in;
                        u64 attr_ver;
@@ -386,6 +396,9 @@ struct fuse_conn {
        /** Filesystem supports NFS exporting.  Only set in INIT */
        unsigned export_support:1;
 
+       /** Set if bdi is valid */
+       unsigned bdi_initialized:1;
+
        /*
         * The following bitfields are only for optimization purposes
         * and hence races in setting them will not cause malfunction
@@ -515,25 +528,24 @@ void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
  * Initialize READ or READDIR request
  */
 void fuse_read_fill(struct fuse_req *req, struct file *file,
-                   struct inode *inode, loff_t pos, size_t count, int opcode);
+                   loff_t pos, size_t count, int opcode);
 
 /**
  * Send OPEN or OPENDIR request
  */
-int fuse_open_common(struct inode *inode, struct file *file, int isdir);
+int fuse_open_common(struct inode *inode, struct file *file, bool isdir);
 
 struct fuse_file *fuse_file_alloc(struct fuse_conn *fc);
+struct fuse_file *fuse_file_get(struct fuse_file *ff);
 void fuse_file_free(struct fuse_file *ff);
-void fuse_finish_open(struct inode *inode, struct file *file,
-                     struct fuse_file *ff, struct fuse_open_out *outarg);
+void fuse_finish_open(struct inode *inode, struct file *file);
 
-/** Fill in ff->reserved_req with a RELEASE request */
-void fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags, int opcode);
+void fuse_sync_release(struct fuse_file *ff, int flags);
 
 /**
  * Send RELEASE or RELEASEDIR request
  */
-int fuse_release_common(struct inode *inode, struct file *file, int isdir);
+void fuse_release_common(struct file *file, int opcode);
 
 /**
  * Send FSYNC or FSYNCDIR request
@@ -652,10 +664,12 @@ void fuse_invalidate_entry_cache(struct dentry *entry);
  */
 struct fuse_conn *fuse_conn_get(struct fuse_conn *fc);
 
+void fuse_conn_kill(struct fuse_conn *fc);
+
 /**
  * Initialize fuse_conn
  */
-int fuse_conn_init(struct fuse_conn *fc, struct super_block *sb);
+void fuse_conn_init(struct fuse_conn *fc);
 
 /**
  * Release reference to fuse_conn
@@ -694,4 +708,13 @@ void fuse_release_nowrite(struct inode *inode);
 
 u64 fuse_get_attr_version(struct fuse_conn *fc);
 
+int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
+                bool isdir);
+ssize_t fuse_direct_io(struct file *file, const char __user *buf,
+                      size_t count, loff_t *ppos, int write);
+long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
+                  unsigned int flags);
+unsigned fuse_file_poll(struct file *file, poll_table *wait);
+int fuse_dev_release(struct inode *inode, struct file *file);
+
 #endif /* _FS_FUSE_I_H */
index 91f7c85f1ffd7e52f8aa9d61c6f309cd8ed5bf42..f0df55a529296e0df1b0f65bcfea7695c3674c09 100644 (file)
@@ -277,11 +277,14 @@ static void fuse_send_destroy(struct fuse_conn *fc)
        }
 }
 
-static void fuse_put_super(struct super_block *sb)
+static void fuse_bdi_destroy(struct fuse_conn *fc)
 {
-       struct fuse_conn *fc = get_fuse_conn_super(sb);
+       if (fc->bdi_initialized)
+               bdi_destroy(&fc->bdi);
+}
 
-       fuse_send_destroy(fc);
+void fuse_conn_kill(struct fuse_conn *fc)
+{
        spin_lock(&fc->lock);
        fc->connected = 0;
        fc->blocked = 0;
@@ -295,7 +298,16 @@ static void fuse_put_super(struct super_block *sb)
        list_del(&fc->entry);
        fuse_ctl_remove_conn(fc);
        mutex_unlock(&fuse_mutex);
-       bdi_destroy(&fc->bdi);
+       fuse_bdi_destroy(fc);
+}
+EXPORT_SYMBOL_GPL(fuse_conn_kill);
+
+static void fuse_put_super(struct super_block *sb)
+{
+       struct fuse_conn *fc = get_fuse_conn_super(sb);
+
+       fuse_send_destroy(fc);
+       fuse_conn_kill(fc);
        fuse_conn_put(fc);
 }
 
@@ -466,10 +478,8 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
        return 0;
 }
 
-int fuse_conn_init(struct fuse_conn *fc, struct super_block *sb)
+void fuse_conn_init(struct fuse_conn *fc)
 {
-       int err;
-
        memset(fc, 0, sizeof(*fc));
        spin_lock_init(&fc->lock);
        mutex_init(&fc->inst_mutex);
@@ -484,49 +494,12 @@ int fuse_conn_init(struct fuse_conn *fc, struct super_block *sb)
        INIT_LIST_HEAD(&fc->bg_queue);
        INIT_LIST_HEAD(&fc->entry);
        atomic_set(&fc->num_waiting, 0);
-       fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
-       fc->bdi.unplug_io_fn = default_unplug_io_fn;
-       /* fuse does it's own writeback accounting */
-       fc->bdi.capabilities = BDI_CAP_NO_ACCT_WB;
        fc->khctr = 0;
        fc->polled_files = RB_ROOT;
-       fc->dev = sb->s_dev;
-       err = bdi_init(&fc->bdi);
-       if (err)
-               goto error_mutex_destroy;
-       if (sb->s_bdev) {
-               err = bdi_register(&fc->bdi, NULL, "%u:%u-fuseblk",
-                                  MAJOR(fc->dev), MINOR(fc->dev));
-       } else {
-               err = bdi_register_dev(&fc->bdi, fc->dev);
-       }
-       if (err)
-               goto error_bdi_destroy;
-       /*
-        * For a single fuse filesystem use max 1% of dirty +
-        * writeback threshold.
-        *
-        * This gives about 1M of write buffer for memory maps on a
-        * machine with 1G and 10% dirty_ratio, which should be more
-        * than enough.
-        *
-        * Privileged users can raise it by writing to
-        *
-        *    /sys/class/bdi/<bdi>/max_ratio
-        */
-       bdi_set_max_ratio(&fc->bdi, 1);
        fc->reqctr = 0;
        fc->blocked = 1;
        fc->attr_version = 1;
        get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
-
-       return 0;
-
- error_bdi_destroy:
-       bdi_destroy(&fc->bdi);
- error_mutex_destroy:
-       mutex_destroy(&fc->inst_mutex);
-       return err;
 }
 EXPORT_SYMBOL_GPL(fuse_conn_init);
 
@@ -539,12 +512,14 @@ void fuse_conn_put(struct fuse_conn *fc)
                fc->release(fc);
        }
 }
+EXPORT_SYMBOL_GPL(fuse_conn_put);
 
 struct fuse_conn *fuse_conn_get(struct fuse_conn *fc)
 {
        atomic_inc(&fc->count);
        return fc;
 }
+EXPORT_SYMBOL_GPL(fuse_conn_get);
 
 static struct inode *fuse_get_root_inode(struct super_block *sb, unsigned mode)
 {
@@ -797,6 +772,48 @@ static void fuse_free_conn(struct fuse_conn *fc)
        kfree(fc);
 }
 
+static int fuse_bdi_init(struct fuse_conn *fc, struct super_block *sb)
+{
+       int err;
+
+       fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
+       fc->bdi.unplug_io_fn = default_unplug_io_fn;
+       /* fuse does it's own writeback accounting */
+       fc->bdi.capabilities = BDI_CAP_NO_ACCT_WB;
+
+       err = bdi_init(&fc->bdi);
+       if (err)
+               return err;
+
+       fc->bdi_initialized = 1;
+
+       if (sb->s_bdev) {
+               err =  bdi_register(&fc->bdi, NULL, "%u:%u-fuseblk",
+                                   MAJOR(fc->dev), MINOR(fc->dev));
+       } else {
+               err = bdi_register_dev(&fc->bdi, fc->dev);
+       }
+
+       if (err)
+               return err;
+
+       /*
+        * For a single fuse filesystem use max 1% of dirty +
+        * writeback threshold.
+        *
+        * This gives about 1M of write buffer for memory maps on a
+        * machine with 1G and 10% dirty_ratio, which should be more
+        * than enough.
+        *
+        * Privileged users can raise it by writing to
+        *
+        *    /sys/class/bdi/<bdi>/max_ratio
+        */
+       bdi_set_max_ratio(&fc->bdi, 1);
+
+       return 0;
+}
+
 static int fuse_fill_super(struct super_block *sb, void *data, int silent)
 {
        struct fuse_conn *fc;
@@ -843,11 +860,12 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
        if (!fc)
                goto err_fput;
 
-       err = fuse_conn_init(fc, sb);
-       if (err) {
-               kfree(fc);
-               goto err_fput;
-       }
+       fuse_conn_init(fc);
+
+       fc->dev = sb->s_dev;
+       err = fuse_bdi_init(fc, sb);
+       if (err)
+               goto err_put_conn;
 
        fc->release = fuse_free_conn;
        fc->flags = d.flags;
@@ -911,7 +929,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
  err_put_root:
        dput(root_dentry);
  err_put_conn:
-       bdi_destroy(&fc->bdi);
+       fuse_bdi_destroy(fc);
        fuse_conn_put(fc);
  err_fput:
        fput(file);
index d53a9bea1c2f287f8c68f402a082dece725b3832..3da2f1f4f7386081c025060702aacb535e187600 100644 (file)
@@ -1,3 +1,4 @@
+EXTRA_CFLAGS := -I$(src)
 obj-$(CONFIG_GFS2_FS) += gfs2.o
 gfs2-y := acl.o bmap.o dir.o eaops.o eattr.o glock.o \
        glops.o inode.o log.o lops.o main.o meta_io.o \
index 329763530dc065847057b5be1c81b408763b46dd..6d47379e794bc4a6b8a9f665aa3546da36dde441 100644 (file)
@@ -25,6 +25,7 @@
 #include "trans.h"
 #include "dir.h"
 #include "util.h"
+#include "trace_gfs2.h"
 
 /* This doesn't need to be that large as max 64 bit pointers in a 4k
  * block is 512, so __u16 is fine for that. It saves stack space to
@@ -589,6 +590,7 @@ int gfs2_block_map(struct inode *inode, sector_t lblock,
        clear_buffer_mapped(bh_map);
        clear_buffer_new(bh_map);
        clear_buffer_boundary(bh_map);
+       trace_gfs2_bmap(ip, bh_map, lblock, create, 1);
        if (gfs2_is_dir(ip)) {
                bsize = sdp->sd_jbsize;
                arr = sdp->sd_jheightsize;
@@ -623,6 +625,7 @@ int gfs2_block_map(struct inode *inode, sector_t lblock,
        ret = 0;
 out:
        release_metapath(&mp);
+       trace_gfs2_bmap(ip, bh_map, lblock, create, ret);
        bmap_unlock(ip, create);
        return ret;
 
index 2bf62bcc5181729b44e7247d7ed8947805cd1263..297421c0427a86ef58fa79cc2ce9518d10171381 100644 (file)
@@ -39,6 +39,8 @@
 #include "super.h"
 #include "util.h"
 #include "bmap.h"
+#define CREATE_TRACE_POINTS
+#include "trace_gfs2.h"
 
 struct gfs2_gl_hash_bucket {
         struct hlist_head hb_list;
@@ -155,7 +157,7 @@ static void glock_free(struct gfs2_glock *gl)
 
        if (aspace)
                gfs2_aspace_put(aspace);
-
+       trace_gfs2_glock_put(gl);
        sdp->sd_lockstruct.ls_ops->lm_put_lock(gfs2_glock_cachep, gl);
 }
 
@@ -317,14 +319,17 @@ restart:
                                                return 2;
                                        gh->gh_error = ret;
                                        list_del_init(&gh->gh_list);
+                                       trace_gfs2_glock_queue(gh, 0);
                                        gfs2_holder_wake(gh);
                                        goto restart;
                                }
                                set_bit(HIF_HOLDER, &gh->gh_iflags);
+                               trace_gfs2_promote(gh, 1);
                                gfs2_holder_wake(gh);
                                goto restart;
                        }
                        set_bit(HIF_HOLDER, &gh->gh_iflags);
+                       trace_gfs2_promote(gh, 0);
                        gfs2_holder_wake(gh);
                        continue;
                }
@@ -354,6 +359,7 @@ static inline void do_error(struct gfs2_glock *gl, const int ret)
                else
                        continue;
                list_del_init(&gh->gh_list);
+               trace_gfs2_glock_queue(gh, 0);
                gfs2_holder_wake(gh);
        }
 }
@@ -422,6 +428,7 @@ static void finish_xmote(struct gfs2_glock *gl, unsigned int ret)
        int rv;
 
        spin_lock(&gl->gl_spin);
+       trace_gfs2_glock_state_change(gl, state);
        state_change(gl, state);
        gh = find_first_waiter(gl);
 
@@ -851,6 +858,7 @@ static void handle_callback(struct gfs2_glock *gl, unsigned int state,
                        gl->gl_demote_state != state) {
                gl->gl_demote_state = LM_ST_UNLOCKED;
        }
+       trace_gfs2_demote_rq(gl);
 }
 
 /**
@@ -936,6 +944,7 @@ fail:
                        goto do_cancel;
                return;
        }
+       trace_gfs2_glock_queue(gh, 1);
        list_add_tail(&gh->gh_list, insert_pt);
 do_cancel:
        gh = list_entry(gl->gl_holders.next, struct gfs2_holder, gh_list);
@@ -1032,6 +1041,7 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
                    !test_bit(GLF_DEMOTE, &gl->gl_flags))
                        fast_path = 1;
        }
+       trace_gfs2_glock_queue(gh, 0);
        spin_unlock(&gl->gl_spin);
        if (likely(fast_path))
                return;
index f2e449c595b444e5d94ec674cd15d5dd4a367a9f..13c6237c5f678222a40a4d0e7f67a7707e3c38bc 100644 (file)
@@ -28,6 +28,7 @@
 #include "meta_io.h"
 #include "util.h"
 #include "dir.h"
+#include "trace_gfs2.h"
 
 #define PULL 1
 
@@ -313,6 +314,7 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks)
                gfs2_log_lock(sdp);
        }
        atomic_sub(blks, &sdp->sd_log_blks_free);
+       trace_gfs2_log_blocks(sdp, -blks);
        gfs2_log_unlock(sdp);
        mutex_unlock(&sdp->sd_log_reserve_mutex);
 
@@ -333,6 +335,7 @@ void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks)
 
        gfs2_log_lock(sdp);
        atomic_add(blks, &sdp->sd_log_blks_free);
+       trace_gfs2_log_blocks(sdp, blks);
        gfs2_assert_withdraw(sdp,
                             atomic_read(&sdp->sd_log_blks_free) <= sdp->sd_jdesc->jd_blocks);
        gfs2_log_unlock(sdp);
@@ -558,6 +561,7 @@ static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail)
 
        gfs2_log_lock(sdp);
        atomic_add(dist, &sdp->sd_log_blks_free);
+       trace_gfs2_log_blocks(sdp, dist);
        gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <= sdp->sd_jdesc->jd_blocks);
        gfs2_log_unlock(sdp);
 
@@ -715,6 +719,7 @@ void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
                up_write(&sdp->sd_log_flush_lock);
                return;
        }
+       trace_gfs2_log_flush(sdp, 1);
 
        ai = kzalloc(sizeof(struct gfs2_ail), GFP_NOFS | __GFP_NOFAIL);
        INIT_LIST_HEAD(&ai->ai_ail1_list);
@@ -746,6 +751,7 @@ void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
        else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){
                gfs2_log_lock(sdp);
                atomic_dec(&sdp->sd_log_blks_free); /* Adjust for unreserved buffer */
+               trace_gfs2_log_blocks(sdp, -1);
                gfs2_log_unlock(sdp);
                log_write_header(sdp, 0, PULL);
        }
@@ -763,7 +769,7 @@ void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
                ai = NULL;
        }
        gfs2_log_unlock(sdp);
-
+       trace_gfs2_log_flush(sdp, 0);
        up_write(&sdp->sd_log_flush_lock);
 
        kfree(ai);
@@ -787,6 +793,7 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
        gfs2_assert_withdraw(sdp, sdp->sd_log_blks_reserved + tr->tr_reserved >= reserved);
        unused = sdp->sd_log_blks_reserved - reserved + tr->tr_reserved;
        atomic_add(unused, &sdp->sd_log_blks_free);
+       trace_gfs2_log_blocks(sdp, unused);
        gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <=
                             sdp->sd_jdesc->jd_blocks);
        sdp->sd_log_blks_reserved = reserved;
index 00315f50fa467daa94214c8e37e877eb76eaf00c..9969ff062c5b82b9d518b1b841c0aac602f01280 100644 (file)
@@ -27,6 +27,7 @@
 #include "rgrp.h"
 #include "trans.h"
 #include "util.h"
+#include "trace_gfs2.h"
 
 /**
  * gfs2_pin - Pin a buffer in memory
@@ -53,6 +54,7 @@ static void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh)
        if (bd->bd_ail)
                list_move(&bd->bd_ail_st_list, &bd->bd_ail->ai_ail2_list);
        get_bh(bh);
+       trace_gfs2_pin(bd, 1);
 }
 
 /**
@@ -89,6 +91,7 @@ static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
        bd->bd_ail = ai;
        list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list);
        clear_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags);
+       trace_gfs2_pin(bd, 0);
        gfs2_log_unlock(sdp);
        unlock_buffer(bh);
 }
index cc34f271b3e7f470230efe58bbeeed3cf6682424..7bc3c45cd676d63bbc621e00a53485ede90c98e4 100644 (file)
@@ -33,6 +33,7 @@
 #include "log.h"
 #include "quota.h"
 #include "dir.h"
+#include "trace_gfs2.h"
 
 #define DO 0
 #define UNDO 1
@@ -775,6 +776,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
                /* Map the extents for this journal's blocks */
                map_journal_extents(sdp);
        }
+       trace_gfs2_log_blocks(sdp, atomic_read(&sdp->sd_log_blks_free));
 
        if (sdp->sd_lockstruct.ls_first) {
                unsigned int x;
index de3239731db8c0bcd0e41a57f6850313edb5774b..daa4ae341a292fe03175c378d441e767706fb9c8 100644 (file)
@@ -29,6 +29,7 @@
 #include "util.h"
 #include "log.h"
 #include "inode.h"
+#include "trace_gfs2.h"
 
 #define BFITNOENT ((u32)~0)
 #define NO_BLOCK ((u64)~0)
@@ -1519,7 +1520,7 @@ int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n)
        spin_lock(&sdp->sd_rindex_spin);
        rgd->rd_free_clone -= *n;
        spin_unlock(&sdp->sd_rindex_spin);
-
+       trace_gfs2_block_alloc(ip, block, *n, GFS2_BLKST_USED);
        *bn = block;
        return 0;
 
@@ -1571,7 +1572,7 @@ u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation)
        spin_lock(&sdp->sd_rindex_spin);
        rgd->rd_free_clone--;
        spin_unlock(&sdp->sd_rindex_spin);
-
+       trace_gfs2_block_alloc(dip, block, 1, GFS2_BLKST_DINODE);
        return block;
 }
 
@@ -1591,7 +1592,7 @@ void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen)
        rgd = rgblk_free(sdp, bstart, blen, GFS2_BLKST_FREE);
        if (!rgd)
                return;
-
+       trace_gfs2_block_alloc(ip, bstart, blen, GFS2_BLKST_FREE);
        rgd->rd_free += blen;
 
        gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
@@ -1619,7 +1620,7 @@ void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen)
        rgd = rgblk_free(sdp, bstart, blen, GFS2_BLKST_FREE);
        if (!rgd)
                return;
-
+       trace_gfs2_block_alloc(ip, bstart, blen, GFS2_BLKST_FREE);
        rgd->rd_free += blen;
 
        gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
@@ -1642,6 +1643,7 @@ void gfs2_unlink_di(struct inode *inode)
        rgd = rgblk_free(sdp, blkno, 1, GFS2_BLKST_UNLINKED);
        if (!rgd)
                return;
+       trace_gfs2_block_alloc(ip, blkno, 1, GFS2_BLKST_UNLINKED);
        gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
        gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
        gfs2_trans_add_rg(rgd);
@@ -1673,6 +1675,7 @@ static void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, u64 blkno)
 void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip)
 {
        gfs2_free_uninit_di(rgd, ip->i_no_addr);
+       trace_gfs2_block_alloc(ip, ip->i_no_addr, 1, GFS2_BLKST_FREE);
        gfs2_quota_change(ip, -1, ip->i_inode.i_uid, ip->i_inode.i_gid);
        gfs2_meta_wipe(ip, ip->i_no_addr, 1);
 }
index c8930b31cdf0b3011f80886987eedaa045c7de0d..0a68013364708dbcafe39398952defaa9f560450 100644 (file)
@@ -719,8 +719,6 @@ static void gfs2_put_super(struct super_block *sb)
        int error;
        struct gfs2_jdesc *jd;
 
-       lock_kernel();
-
        /*  Unfreeze the filesystem, if we need to  */
 
        mutex_lock(&sdp->sd_freeze_lock);
@@ -787,8 +785,6 @@ restart:
 
        /*  At this point, we're through participating in the lockspace  */
        gfs2_sys_fs_del(sdp);
-
-       unlock_kernel();
 }
 
 /**
diff --git a/fs/gfs2/trace_gfs2.h b/fs/gfs2/trace_gfs2.h
new file mode 100644 (file)
index 0000000..98d6ef1
--- /dev/null
@@ -0,0 +1,407 @@
+#if !defined(_TRACE_GFS2_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_GFS2_H
+
+#include <linux/tracepoint.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM gfs2
+#define TRACE_INCLUDE_FILE trace_gfs2
+
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include <linux/dlmconstants.h>
+#include <linux/gfs2_ondisk.h>
+#include "incore.h"
+#include "glock.h"
+
+#define dlm_state_name(nn) { DLM_LOCK_##nn, #nn }
+#define glock_trace_name(x) __print_symbolic(x,                \
+                           dlm_state_name(IV),         \
+                           dlm_state_name(NL),         \
+                           dlm_state_name(CR),         \
+                           dlm_state_name(CW),         \
+                           dlm_state_name(PR),         \
+                           dlm_state_name(PW),         \
+                           dlm_state_name(EX))
+
+#define block_state_name(x) __print_symbolic(x,                        \
+                           { GFS2_BLKST_FREE, "free" },        \
+                           { GFS2_BLKST_USED, "used" },        \
+                           { GFS2_BLKST_DINODE, "dinode" },    \
+                           { GFS2_BLKST_UNLINKED, "unlinked" })
+
+#define show_glock_flags(flags) __print_flags(flags, "",       \
+       {(1UL << GLF_LOCK),                     "l" },          \
+       {(1UL << GLF_DEMOTE),                   "D" },          \
+       {(1UL << GLF_PENDING_DEMOTE),           "d" },          \
+       {(1UL << GLF_DEMOTE_IN_PROGRESS),       "p" },          \
+       {(1UL << GLF_DIRTY),                    "y" },          \
+       {(1UL << GLF_LFLUSH),                   "f" },          \
+       {(1UL << GLF_INVALIDATE_IN_PROGRESS),   "i" },          \
+       {(1UL << GLF_REPLY_PENDING),            "r" },          \
+       {(1UL << GLF_INITIAL),                  "I" },          \
+       {(1UL << GLF_FROZEN),                   "F" })
+
+#ifndef NUMPTY
+#define NUMPTY
+static inline u8 glock_trace_state(unsigned int state)
+{
+       switch(state) {
+       case LM_ST_SHARED:
+               return DLM_LOCK_PR;
+       case LM_ST_DEFERRED:
+               return DLM_LOCK_CW;
+       case LM_ST_EXCLUSIVE:
+               return DLM_LOCK_EX;
+       }
+       return DLM_LOCK_NL;
+}
+#endif
+
+/* Section 1 - Locking
+ *
+ * Objectives:
+ * Latency: Remote demote request to state change
+ * Latency: Local lock request to state change
+ * Latency: State change to lock grant
+ * Correctness: Ordering of local lock state vs. I/O requests
+ * Correctness: Responses to remote demote requests
+ */
+
+/* General glock state change (DLM lock request completes) */
+TRACE_EVENT(gfs2_glock_state_change,
+
+       TP_PROTO(const struct gfs2_glock *gl, unsigned int new_state),
+
+       TP_ARGS(gl, new_state),
+
+       TP_STRUCT__entry(
+               __field(        dev_t,  dev                     )
+               __field(        u64,    glnum                   )
+               __field(        u32,    gltype                  )
+               __field(        u8,     cur_state               )
+               __field(        u8,     new_state               )
+               __field(        u8,     dmt_state               )
+               __field(        u8,     tgt_state               )
+               __field(        unsigned long,  flags           )
+       ),
+
+       TP_fast_assign(
+               __entry->dev            = gl->gl_sbd->sd_vfs->s_dev;
+               __entry->glnum          = gl->gl_name.ln_number;
+               __entry->gltype         = gl->gl_name.ln_type;
+               __entry->cur_state      = glock_trace_state(gl->gl_state);
+               __entry->new_state      = glock_trace_state(new_state);
+               __entry->tgt_state      = glock_trace_state(gl->gl_target);
+               __entry->dmt_state      = glock_trace_state(gl->gl_demote_state);
+               __entry->flags          = gl->gl_flags;
+       ),
+
+       TP_printk("%u,%u glock %d:%lld state %s to %s tgt:%s dmt:%s flags:%s",
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->gltype,
+                (unsigned long long)__entry->glnum,
+                 glock_trace_name(__entry->cur_state),
+                 glock_trace_name(__entry->new_state),
+                 glock_trace_name(__entry->tgt_state),
+                 glock_trace_name(__entry->dmt_state),
+                 show_glock_flags(__entry->flags))
+);
+
+/* State change -> unlocked, glock is being deallocated */
+TRACE_EVENT(gfs2_glock_put,
+
+       TP_PROTO(const struct gfs2_glock *gl),
+
+       TP_ARGS(gl),
+
+       TP_STRUCT__entry(
+               __field(        dev_t,  dev                     )
+               __field(        u64,    glnum                   )
+               __field(        u32,    gltype                  )
+               __field(        u8,     cur_state               )
+               __field(        unsigned long,  flags           )
+       ),
+
+       TP_fast_assign(
+               __entry->dev            = gl->gl_sbd->sd_vfs->s_dev;
+               __entry->gltype         = gl->gl_name.ln_type;
+               __entry->glnum          = gl->gl_name.ln_number;
+               __entry->cur_state      = glock_trace_state(gl->gl_state);
+               __entry->flags          = gl->gl_flags;
+       ),
+
+       TP_printk("%u,%u glock %d:%lld state %s => %s flags:%s",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                  __entry->gltype, (unsigned long long)__entry->glnum,
+                  glock_trace_name(__entry->cur_state),
+                 glock_trace_name(DLM_LOCK_IV),
+                 show_glock_flags(__entry->flags))
+
+);
+
+/* Callback (local or remote) requesting lock demotion */
+TRACE_EVENT(gfs2_demote_rq,
+
+       TP_PROTO(const struct gfs2_glock *gl),
+
+       TP_ARGS(gl),
+
+       TP_STRUCT__entry(
+               __field(        dev_t,  dev                     )
+               __field(        u64,    glnum                   )
+               __field(        u32,    gltype                  )
+               __field(        u8,     cur_state               )
+               __field(        u8,     dmt_state               )
+               __field(        unsigned long,  flags           )
+       ),
+
+       TP_fast_assign(
+               __entry->dev            = gl->gl_sbd->sd_vfs->s_dev;
+               __entry->gltype         = gl->gl_name.ln_type;
+               __entry->glnum          = gl->gl_name.ln_number;
+               __entry->cur_state      = glock_trace_state(gl->gl_state);
+               __entry->dmt_state      = glock_trace_state(gl->gl_demote_state);
+               __entry->flags          = gl->gl_flags;
+       ),
+
+       TP_printk("%u,%u glock %d:%lld demote %s to %s flags:%s",
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->gltype,
+                 (unsigned long long)__entry->glnum,
+                  glock_trace_name(__entry->cur_state),
+                  glock_trace_name(__entry->dmt_state),
+                 show_glock_flags(__entry->flags))
+
+);
+
+/* Promotion/grant of a glock */
+TRACE_EVENT(gfs2_promote,
+
+       TP_PROTO(const struct gfs2_holder *gh, int first),
+
+       TP_ARGS(gh, first),
+
+       TP_STRUCT__entry(
+               __field(        dev_t,  dev                     )
+               __field(        u64,    glnum                   )
+               __field(        u32,    gltype                  )
+               __field(        int,    first                   )
+               __field(        u8,     state                   )
+       ),
+
+       TP_fast_assign(
+               __entry->dev    = gh->gh_gl->gl_sbd->sd_vfs->s_dev;
+               __entry->glnum  = gh->gh_gl->gl_name.ln_number;
+               __entry->gltype = gh->gh_gl->gl_name.ln_type;
+               __entry->first  = first;
+               __entry->state  = glock_trace_state(gh->gh_state);
+       ),
+
+       TP_printk("%u,%u glock %u:%llu promote %s %s",
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->gltype,
+                 (unsigned long long)__entry->glnum,
+                 __entry->first ? "first": "other",
+                 glock_trace_name(__entry->state))
+);
+
+/* Queue/dequeue a lock request */
+TRACE_EVENT(gfs2_glock_queue,
+
+       TP_PROTO(const struct gfs2_holder *gh, int queue),
+
+       TP_ARGS(gh, queue),
+
+       TP_STRUCT__entry(
+               __field(        dev_t,  dev                     )
+               __field(        u64,    glnum                   )
+               __field(        u32,    gltype                  )
+               __field(        int,    queue                   )
+               __field(        u8,     state                   )
+       ),
+
+       TP_fast_assign(
+               __entry->dev    = gh->gh_gl->gl_sbd->sd_vfs->s_dev;
+               __entry->glnum  = gh->gh_gl->gl_name.ln_number;
+               __entry->gltype = gh->gh_gl->gl_name.ln_type;
+               __entry->queue  = queue;
+               __entry->state  = glock_trace_state(gh->gh_state);
+       ),
+
+       TP_printk("%u,%u glock %u:%llu %squeue %s",
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->gltype,
+                 (unsigned long long)__entry->glnum,
+                 __entry->queue ? "" : "de",
+                 glock_trace_name(__entry->state))
+);
+
+/* Section 2 - Log/journal
+ *
+ * Objectives:
+ * Latency: Log flush time
+ * Correctness: pin/unpin vs. disk I/O ordering
+ * Performance: Log usage stats
+ */
+
+/* Pin/unpin a block in the log */
+TRACE_EVENT(gfs2_pin,
+
+       TP_PROTO(const struct gfs2_bufdata *bd, int pin),
+
+       TP_ARGS(bd, pin),
+
+       TP_STRUCT__entry(
+               __field(        dev_t,  dev                     )
+               __field(        int,    pin                     )
+               __field(        u32,    len                     )
+               __field(        sector_t,       block           )
+               __field(        u64,    ino                     )
+       ),
+
+       TP_fast_assign(
+               __entry->dev            = bd->bd_gl->gl_sbd->sd_vfs->s_dev;
+               __entry->pin            = pin;
+               __entry->len            = bd->bd_bh->b_size;
+               __entry->block          = bd->bd_bh->b_blocknr;
+               __entry->ino            = bd->bd_gl->gl_name.ln_number;
+       ),
+
+       TP_printk("%u,%u log %s %llu/%lu inode %llu",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->pin ? "pin" : "unpin",
+                 (unsigned long long)__entry->block,
+                 (unsigned long)__entry->len,
+                 (unsigned long long)__entry->ino)
+);
+
+/* Flushing the log */
+TRACE_EVENT(gfs2_log_flush,
+
+       TP_PROTO(const struct gfs2_sbd *sdp, int start),
+
+       TP_ARGS(sdp, start),
+
+       TP_STRUCT__entry(
+               __field(        dev_t,  dev                     )
+               __field(        int,    start                   )
+               __field(        u64,    log_seq                 )
+       ),
+
+       TP_fast_assign(
+               __entry->dev            = sdp->sd_vfs->s_dev;
+               __entry->start          = start;
+               __entry->log_seq        = sdp->sd_log_sequence;
+       ),
+
+       TP_printk("%u,%u log flush %s %llu",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->start ? "start" : "end",
+                 (unsigned long long)__entry->log_seq)
+);
+
+/* Reserving/releasing blocks in the log */
+TRACE_EVENT(gfs2_log_blocks,
+
+       TP_PROTO(const struct gfs2_sbd *sdp, int blocks),
+
+       TP_ARGS(sdp, blocks),
+
+       TP_STRUCT__entry(
+               __field(        dev_t,  dev                     )
+               __field(        int,    blocks                  )
+       ),
+
+       TP_fast_assign(
+               __entry->dev            = sdp->sd_vfs->s_dev;
+               __entry->blocks         = blocks;
+       ),
+
+       TP_printk("%u,%u log reserve %d", MAJOR(__entry->dev),
+                 MINOR(__entry->dev), __entry->blocks)
+);
+
+/* Section 3 - bmap
+ *
+ * Objectives:
+ * Latency: Bmap request time
+ * Performance: Block allocator tracing
+ * Correctness: Test of disard generation vs. blocks allocated
+ */
+
+/* Map an extent of blocks, possibly a new allocation */
+TRACE_EVENT(gfs2_bmap,
+
+       TP_PROTO(const struct gfs2_inode *ip, const struct buffer_head *bh,
+               sector_t lblock, int create, int errno),
+
+       TP_ARGS(ip, bh, lblock, create, errno),
+
+       TP_STRUCT__entry(
+               __field(        dev_t,  dev                     )
+               __field(        sector_t, lblock                )
+               __field(        sector_t, pblock                )
+               __field(        u64,    inum                    )
+               __field(        unsigned long, state            )
+               __field(        u32,    len                     )
+               __field(        int,    create                  )
+               __field(        int,    errno                   )
+       ),
+
+       TP_fast_assign(
+               __entry->dev            = ip->i_gl->gl_sbd->sd_vfs->s_dev;
+               __entry->lblock         = lblock;
+               __entry->pblock         = buffer_mapped(bh) ?  bh->b_blocknr : 0;
+               __entry->inum           = ip->i_no_addr;
+               __entry->state          = bh->b_state;
+               __entry->len            = bh->b_size;
+               __entry->create         = create;
+               __entry->errno          = errno;
+       ),
+
+       TP_printk("%u,%u bmap %llu map %llu/%lu to %llu flags:%08lx %s %d",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 (unsigned long long)__entry->inum,
+                 (unsigned long long)__entry->lblock,
+                 (unsigned long)__entry->len,
+                 (unsigned long long)__entry->pblock,
+                 __entry->state, __entry->create ? "create " : "nocreate",
+                 __entry->errno)
+);
+
+/* Keep track of blocks as they are allocated/freed */
+TRACE_EVENT(gfs2_block_alloc,
+
+       TP_PROTO(const struct gfs2_inode *ip, u64 block, unsigned len,
+               u8 block_state),
+
+       TP_ARGS(ip, block, len, block_state),
+
+       TP_STRUCT__entry(
+               __field(        dev_t,  dev                     )
+               __field(        u64,    start                   )
+               __field(        u64,    inum                    )
+               __field(        u32,    len                     )
+               __field(        u8,     block_state             )
+       ),
+
+       TP_fast_assign(
+               __entry->dev            = ip->i_gl->gl_sbd->sd_vfs->s_dev;
+               __entry->start          = block;
+               __entry->inum           = ip->i_no_addr;
+               __entry->len            = len;
+               __entry->block_state    = block_state;
+       ),
+
+       TP_printk("%u,%u bmap %llu alloc %llu/%lu %s",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 (unsigned long long)__entry->inum,
+                 (unsigned long long)__entry->start,
+                 (unsigned long)__entry->len,
+                 block_state_name(__entry->block_state))
+);
+
+#endif /* _TRACE_GFS2_H */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#include <trace/define_trace.h>
+
index a88baebf77cf1ffddc62a0f26ce32f48dd09922d..f643be565df8e403a0fc807c4d1af554004c0d62 100644 (file)
@@ -1408,7 +1408,7 @@ EXPORT_SYMBOL(touch_atime);
  *     for writeback.  Note that this function is meant exclusively for
  *     usage in the file write path of filesystems, and filesystems may
  *     choose to explicitly ignore update via this function with the
- *     S_NOCTIME inode flag, e.g. for network filesystem where these
+ *     S_NOCMTIME inode flag, e.g. for network filesystem where these
  *     timestamps are handled by the server.
  */
 
index 0af36085eb28b21498036ce42f5fb682153b7baa..1a9c7878f8649b1df14531f66aa247fd2587e2c8 100644 (file)
@@ -556,27 +556,49 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
 
        /* add partitions */
        for (p = 1; p < state->limit; p++) {
-               sector_t size = state->parts[p].size;
-               sector_t from = state->parts[p].from;
+               sector_t size, from;
+try_scan:
+               size = state->parts[p].size;
                if (!size)
                        continue;
+
+               from = state->parts[p].from;
                if (from >= get_capacity(disk)) {
                        printk(KERN_WARNING
                               "%s: p%d ignored, start %llu is behind the end of the disk\n",
                               disk->disk_name, p, (unsigned long long) from);
                        continue;
                }
+
                if (from + size > get_capacity(disk)) {
-                       /*
-                        * we can not ignore partitions of broken tables
-                        * created by for example camera firmware, but we
-                        * limit them to the end of the disk to avoid
-                        * creating invalid block devices
-                        */
+                       struct block_device_operations *bdops = disk->fops;
+                       unsigned long long capacity;
+
                        printk(KERN_WARNING
-                              "%s: p%d size %llu limited to end of disk\n",
+                              "%s: p%d size %llu exceeds device capacity, ",
                               disk->disk_name, p, (unsigned long long) size);
-                       size = get_capacity(disk) - from;
+
+                       if (bdops->set_capacity &&
+                           (disk->flags & GENHD_FL_NATIVE_CAPACITY) == 0) {
+                               printk(KERN_CONT "enabling native capacity\n");
+                               capacity = bdops->set_capacity(disk, ~0ULL);
+                               disk->flags |= GENHD_FL_NATIVE_CAPACITY;
+                               if (capacity > get_capacity(disk)) {
+                                       set_capacity(disk, capacity);
+                                       check_disk_size_change(disk, bdev);
+                                       bdev->bd_invalidated = 0;
+                               }
+                               goto try_scan;
+                       } else {
+                               /*
+                                * we can not ignore partitions of broken tables
+                                * created by for example camera firmware, but
+                                * we limit them to the end of the disk to avoid
+                                * creating invalid block devices
+                                */
+                               printk(KERN_CONT "limited to end of disk\n");
+                               size = get_capacity(disk) - from;
+                       }
                }
                part = add_partition(disk, p, from, size,
                                     state->parts[p].flags);
index 29228f5899cd453836f1254dd70c382e68ce39d1..480f28127f09f08f7d26577eec6eea7a09c68d5d 100644 (file)
@@ -39,6 +39,7 @@ config XFS_QUOTA
 config XFS_POSIX_ACL
        bool "XFS POSIX ACL support"
        depends on XFS_FS
+       select FS_POSIX_ACL
        help
          POSIX Access Control Lists (ACLs) support permissions for users and
          groups beyond the owner/group/world scheme.
index 60f107e47fe94253f1b1b55a443959bd15a036cc..7a59daed1782898901b0fbd333618efc8c515eec 100644 (file)
@@ -40,7 +40,7 @@ xfs-$(CONFIG_PROC_FS)         += quota/xfs_qm_stats.o
 endif
 
 xfs-$(CONFIG_XFS_RT)           += xfs_rtalloc.o
-xfs-$(CONFIG_XFS_POSIX_ACL)    += xfs_acl.o
+xfs-$(CONFIG_XFS_POSIX_ACL)    += $(XFS_LINUX)/xfs_acl.o
 xfs-$(CONFIG_PROC_FS)          += $(XFS_LINUX)/xfs_stats.o
 xfs-$(CONFIG_SYSCTL)           += $(XFS_LINUX)/xfs_sysctl.o
 xfs-$(CONFIG_COMPAT)           += $(XFS_LINUX)/xfs_ioctl32.o
@@ -88,8 +88,7 @@ xfs-y                         += xfs_alloc.o \
                                   xfs_utils.o \
                                   xfs_vnodeops.o \
                                   xfs_rw.o \
-                                  xfs_dmops.o \
-                                  xfs_qmops.o
+                                  xfs_dmops.o
 
 xfs-$(CONFIG_XFS_TRACE)                += xfs_btree_trace.o \
                                   xfs_dir2_trace.o
diff --git a/fs/xfs/linux-2.6/xfs_acl.c b/fs/xfs/linux-2.6/xfs_acl.c
new file mode 100644 (file)
index 0000000..1e9d124
--- /dev/null
@@ -0,0 +1,523 @@
+/*
+ * Copyright (c) 2008, Christoph Hellwig
+ * 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.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT 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 the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include "xfs.h"
+#include "xfs_acl.h"
+#include "xfs_attr.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_inode.h"
+#include "xfs_vnodeops.h"
+#include <linux/xattr.h>
+#include <linux/posix_acl_xattr.h>
+
+
+#define XFS_ACL_NOT_CACHED     ((void *)-1)
+
+/*
+ * Locking scheme:
+ *  - all ACL updates are protected by inode->i_mutex, which is taken before
+ *    calling into this file.
+ *  - access and updates to the ip->i_acl and ip->i_default_acl pointers are
+ *    protected by inode->i_lock.
+ */
+
+STATIC struct posix_acl *
+xfs_acl_from_disk(struct xfs_acl *aclp)
+{
+       struct posix_acl_entry *acl_e;
+       struct posix_acl *acl;
+       struct xfs_acl_entry *ace;
+       int count, i;
+
+       count = be32_to_cpu(aclp->acl_cnt);
+
+       acl = posix_acl_alloc(count, GFP_KERNEL);
+       if (!acl)
+               return ERR_PTR(-ENOMEM);
+
+       for (i = 0; i < count; i++) {
+               acl_e = &acl->a_entries[i];
+               ace = &aclp->acl_entry[i];
+
+               /*
+                * The tag is 32 bits on disk and 16 bits in core.
+                *
+                * Because every access to it goes through the core
+                * format first this is not a problem.
+                */
+               acl_e->e_tag = be32_to_cpu(ace->ae_tag);
+               acl_e->e_perm = be16_to_cpu(ace->ae_perm);
+
+               switch (acl_e->e_tag) {
+               case ACL_USER:
+               case ACL_GROUP:
+                       acl_e->e_id = be32_to_cpu(ace->ae_id);
+                       break;
+               case ACL_USER_OBJ:
+               case ACL_GROUP_OBJ:
+               case ACL_MASK:
+               case ACL_OTHER:
+                       acl_e->e_id = ACL_UNDEFINED_ID;
+                       break;
+               default:
+                       goto fail;
+               }
+       }
+       return acl;
+
+fail:
+       posix_acl_release(acl);
+       return ERR_PTR(-EINVAL);
+}
+
+STATIC void
+xfs_acl_to_disk(struct xfs_acl *aclp, const struct posix_acl *acl)
+{
+       const struct posix_acl_entry *acl_e;
+       struct xfs_acl_entry *ace;
+       int i;
+
+       aclp->acl_cnt = cpu_to_be32(acl->a_count);
+       for (i = 0; i < acl->a_count; i++) {
+               ace = &aclp->acl_entry[i];
+               acl_e = &acl->a_entries[i];
+
+               ace->ae_tag = cpu_to_be32(acl_e->e_tag);
+               ace->ae_id = cpu_to_be32(acl_e->e_id);
+               ace->ae_perm = cpu_to_be16(acl_e->e_perm);
+       }
+}
+
+/*
+ * Update the cached ACL pointer in the inode.
+ *
+ * Because we don't hold any locks while reading/writing the attribute
+ * from/to disk another thread could have raced and updated the cached
+ * ACL value before us. In that case we release the previous cached value
+ * and update it with our new value.
+ */
+STATIC void
+xfs_update_cached_acl(struct inode *inode, struct posix_acl **p_acl,
+               struct posix_acl *acl)
+{
+       spin_lock(&inode->i_lock);
+       if (*p_acl && *p_acl != XFS_ACL_NOT_CACHED)
+               posix_acl_release(*p_acl);
+       *p_acl = posix_acl_dup(acl);
+       spin_unlock(&inode->i_lock);
+}
+
+struct posix_acl *
+xfs_get_acl(struct inode *inode, int type)
+{
+       struct xfs_inode *ip = XFS_I(inode);
+       struct posix_acl *acl = NULL, **p_acl;
+       struct xfs_acl *xfs_acl;
+       int len = sizeof(struct xfs_acl);
+       char *ea_name;
+       int error;
+
+       switch (type) {
+       case ACL_TYPE_ACCESS:
+               ea_name = SGI_ACL_FILE;
+               p_acl = &ip->i_acl;
+               break;
+       case ACL_TYPE_DEFAULT:
+               ea_name = SGI_ACL_DEFAULT;
+               p_acl = &ip->i_default_acl;
+               break;
+       default:
+               return ERR_PTR(-EINVAL);
+       }
+
+       spin_lock(&inode->i_lock);
+       if (*p_acl != XFS_ACL_NOT_CACHED)
+               acl = posix_acl_dup(*p_acl);
+       spin_unlock(&inode->i_lock);
+
+       /*
+        * If we have a cached ACLs value just return it, not need to
+        * go out to the disk.
+        */
+       if (acl)
+               return acl;
+
+       xfs_acl = kzalloc(sizeof(struct xfs_acl), GFP_KERNEL);
+       if (!xfs_acl)
+               return ERR_PTR(-ENOMEM);
+
+       error = -xfs_attr_get(ip, ea_name, (char *)xfs_acl, &len, ATTR_ROOT);
+       if (error) {
+               /*
+                * If the attribute doesn't exist make sure we have a negative
+                * cache entry, for any other error assume it is transient and
+                * leave the cache entry as XFS_ACL_NOT_CACHED.
+                */
+               if (error == -ENOATTR) {
+                       acl = NULL;
+                       goto out_update_cache;
+               }
+               goto out;
+       }
+
+       acl = xfs_acl_from_disk(xfs_acl);
+       if (IS_ERR(acl))
+               goto out;
+
+ out_update_cache:
+       xfs_update_cached_acl(inode, p_acl, acl);
+ out:
+       kfree(xfs_acl);
+       return acl;
+}
+
+STATIC int
+xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
+{
+       struct xfs_inode *ip = XFS_I(inode);
+       struct posix_acl **p_acl;
+       char *ea_name;
+       int error;
+
+       if (S_ISLNK(inode->i_mode))
+               return -EOPNOTSUPP;
+
+       switch (type) {
+       case ACL_TYPE_ACCESS:
+               ea_name = SGI_ACL_FILE;
+               p_acl = &ip->i_acl;
+               break;
+       case ACL_TYPE_DEFAULT:
+               if (!S_ISDIR(inode->i_mode))
+                       return acl ? -EACCES : 0;
+               ea_name = SGI_ACL_DEFAULT;
+               p_acl = &ip->i_default_acl;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (acl) {
+               struct xfs_acl *xfs_acl;
+               int len;
+
+               xfs_acl = kzalloc(sizeof(struct xfs_acl), GFP_KERNEL);
+               if (!xfs_acl)
+                       return -ENOMEM;
+
+               xfs_acl_to_disk(xfs_acl, acl);
+               len = sizeof(struct xfs_acl) -
+                       (sizeof(struct xfs_acl_entry) *
+                        (XFS_ACL_MAX_ENTRIES - acl->a_count));
+
+               error = -xfs_attr_set(ip, ea_name, (char *)xfs_acl,
+                               len, ATTR_ROOT);
+
+               kfree(xfs_acl);
+       } else {
+               /*
+                * A NULL ACL argument means we want to remove the ACL.
+                */
+               error = -xfs_attr_remove(ip, ea_name, ATTR_ROOT);
+
+               /*
+                * If the attribute didn't exist to start with that's fine.
+                */
+               if (error == -ENOATTR)
+                       error = 0;
+       }
+
+       if (!error)
+               xfs_update_cached_acl(inode, p_acl, acl);
+       return error;
+}
+
+int
+xfs_check_acl(struct inode *inode, int mask)
+{
+       struct xfs_inode *ip = XFS_I(inode);
+       struct posix_acl *acl;
+       int error = -EAGAIN;
+
+       xfs_itrace_entry(ip);
+
+       /*
+        * If there is no attribute fork no ACL exists on this inode and
+        * we can skip the whole exercise.
+        */
+       if (!XFS_IFORK_Q(ip))
+               return -EAGAIN;
+
+       acl = xfs_get_acl(inode, ACL_TYPE_ACCESS);
+       if (IS_ERR(acl))
+               return PTR_ERR(acl);
+       if (acl) {
+               error = posix_acl_permission(inode, acl, mask);
+               posix_acl_release(acl);
+       }
+
+       return error;
+}
+
+static int
+xfs_set_mode(struct inode *inode, mode_t mode)
+{
+       int error = 0;
+
+       if (mode != inode->i_mode) {
+               struct iattr iattr;
+
+               iattr.ia_valid = ATTR_MODE;
+               iattr.ia_mode = mode;
+
+               error = -xfs_setattr(XFS_I(inode), &iattr, XFS_ATTR_NOACL);
+       }
+
+       return error;
+}
+
+static int
+xfs_acl_exists(struct inode *inode, char *name)
+{
+       int len = sizeof(struct xfs_acl);
+
+       return (xfs_attr_get(XFS_I(inode), name, NULL, &len,
+                           ATTR_ROOT|ATTR_KERNOVAL) == 0);
+}
+
+int
+posix_acl_access_exists(struct inode *inode)
+{
+       return xfs_acl_exists(inode, SGI_ACL_FILE);
+}
+
+int
+posix_acl_default_exists(struct inode *inode)
+{
+       if (!S_ISDIR(inode->i_mode))
+               return 0;
+       return xfs_acl_exists(inode, SGI_ACL_DEFAULT);
+}
+
+/*
+ * No need for i_mutex because the inode is not yet exposed to the VFS.
+ */
+int
+xfs_inherit_acl(struct inode *inode, struct posix_acl *default_acl)
+{
+       struct posix_acl *clone;
+       mode_t mode;
+       int error = 0, inherit = 0;
+
+       if (S_ISDIR(inode->i_mode)) {
+               error = xfs_set_acl(inode, ACL_TYPE_DEFAULT, default_acl);
+               if (error)
+                       return error;
+       }
+
+       clone = posix_acl_clone(default_acl, GFP_KERNEL);
+       if (!clone)
+               return -ENOMEM;
+
+       mode = inode->i_mode;
+       error = posix_acl_create_masq(clone, &mode);
+       if (error < 0)
+               goto out_release_clone;
+
+       /*
+        * If posix_acl_create_masq returns a positive value we need to
+        * inherit a permission that can't be represented using the Unix
+        * mode bits and we actually need to set an ACL.
+        */
+       if (error > 0)
+               inherit = 1;
+
+       error = xfs_set_mode(inode, mode);
+       if (error)
+               goto out_release_clone;
+
+       if (inherit)
+               error = xfs_set_acl(inode, ACL_TYPE_ACCESS, clone);
+
+ out_release_clone:
+       posix_acl_release(clone);
+       return error;
+}
+
+int
+xfs_acl_chmod(struct inode *inode)
+{
+       struct posix_acl *acl, *clone;
+       int error;
+
+       if (S_ISLNK(inode->i_mode))
+               return -EOPNOTSUPP;
+
+       acl = xfs_get_acl(inode, ACL_TYPE_ACCESS);
+       if (IS_ERR(acl) || !acl)
+               return PTR_ERR(acl);
+
+       clone = posix_acl_clone(acl, GFP_KERNEL);
+       posix_acl_release(acl);
+       if (!clone)
+               return -ENOMEM;
+
+       error = posix_acl_chmod_masq(clone, inode->i_mode);
+       if (!error)
+               error = xfs_set_acl(inode, ACL_TYPE_ACCESS, clone);
+
+       posix_acl_release(clone);
+       return error;
+}
+
+void
+xfs_inode_init_acls(struct xfs_inode *ip)
+{
+       /*
+        * No need for locking, inode is not live yet.
+        */
+       ip->i_acl = XFS_ACL_NOT_CACHED;
+       ip->i_default_acl = XFS_ACL_NOT_CACHED;
+}
+
+void
+xfs_inode_clear_acls(struct xfs_inode *ip)
+{
+       /*
+        * No need for locking here, the inode is not live anymore
+        * and just about to be freed.
+        */
+       if (ip->i_acl != XFS_ACL_NOT_CACHED)
+               posix_acl_release(ip->i_acl);
+       if (ip->i_default_acl != XFS_ACL_NOT_CACHED)
+               posix_acl_release(ip->i_default_acl);
+}
+
+
+/*
+ * System xattr handlers.
+ *
+ * Currently Posix ACLs are the only system namespace extended attribute
+ * handlers supported by XFS, so we just implement the handlers here.
+ * If we ever support other system extended attributes this will need
+ * some refactoring.
+ */
+
+static int
+xfs_decode_acl(const char *name)
+{
+       if (strcmp(name, "posix_acl_access") == 0)
+               return ACL_TYPE_ACCESS;
+       else if (strcmp(name, "posix_acl_default") == 0)
+               return ACL_TYPE_DEFAULT;
+       return -EINVAL;
+}
+
+static int
+xfs_xattr_system_get(struct inode *inode, const char *name,
+               void *value, size_t size)
+{
+       struct posix_acl *acl;
+       int type, error;
+
+       type = xfs_decode_acl(name);
+       if (type < 0)
+               return type;
+
+       acl = xfs_get_acl(inode, type);
+       if (IS_ERR(acl))
+               return PTR_ERR(acl);
+       if (acl == NULL)
+               return -ENODATA;
+
+       error = posix_acl_to_xattr(acl, value, size);
+       posix_acl_release(acl);
+
+       return error;
+}
+
+static int
+xfs_xattr_system_set(struct inode *inode, const char *name,
+               const void *value, size_t size, int flags)
+{
+       struct posix_acl *acl = NULL;
+       int error = 0, type;
+
+       type = xfs_decode_acl(name);
+       if (type < 0)
+               return type;
+       if (flags & XATTR_CREATE)
+               return -EINVAL;
+       if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
+               return value ? -EACCES : 0;
+       if ((current_fsuid() != inode->i_uid) && !capable(CAP_FOWNER))
+               return -EPERM;
+
+       if (!value)
+               goto set_acl;
+
+       acl = posix_acl_from_xattr(value, size);
+       if (!acl) {
+               /*
+                * acl_set_file(3) may request that we set default ACLs with
+                * zero length -- defend (gracefully) against that here.
+                */
+               goto out;
+       }
+       if (IS_ERR(acl)) {
+               error = PTR_ERR(acl);
+               goto out;
+       }
+
+       error = posix_acl_valid(acl);
+       if (error)
+               goto out_release;
+
+       error = -EINVAL;
+       if (acl->a_count > XFS_ACL_MAX_ENTRIES)
+               goto out_release;
+
+       if (type == ACL_TYPE_ACCESS) {
+               mode_t mode = inode->i_mode;
+               error = posix_acl_equiv_mode(acl, &mode);
+
+               if (error <= 0) {
+                       posix_acl_release(acl);
+                       acl = NULL;
+
+                       if (error < 0)
+                               return error;
+               }
+
+               error = xfs_set_mode(inode, mode);
+               if (error)
+                       goto out_release;
+       }
+
+ set_acl:
+       error = xfs_set_acl(inode, type, acl);
+ out_release:
+       posix_acl_release(acl);
+ out:
+       return error;
+}
+
+struct xattr_handler xfs_xattr_system_handler = {
+       .prefix = XATTR_SYSTEM_PREFIX,
+       .get    = xfs_xattr_system_get,
+       .set    = xfs_xattr_system_set,
+};
index 34eaab608e6edd5adde0e6d2b72dd2ceae0e428c..5bb523d7f37e9263399444379f9ac16451b4dd62 100644 (file)
@@ -41,7 +41,6 @@
 #include "xfs_itable.h"
 #include "xfs_error.h"
 #include "xfs_rw.h"
-#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_bmap.h"
 #include "xfs_buf_item.h"
@@ -899,7 +898,8 @@ xfs_ioctl_setattr(
        struct xfs_mount        *mp = ip->i_mount;
        struct xfs_trans        *tp;
        unsigned int            lock_flags = 0;
-       struct xfs_dquot        *udqp = NULL, *gdqp = NULL;
+       struct xfs_dquot        *udqp = NULL;
+       struct xfs_dquot        *gdqp = NULL;
        struct xfs_dquot        *olddquot = NULL;
        int                     code;
 
@@ -919,7 +919,7 @@ xfs_ioctl_setattr(
         * because the i_*dquot fields will get updated anyway.
         */
        if (XFS_IS_QUOTA_ON(mp) && (mask & FSX_PROJID)) {
-               code = XFS_QM_DQVOPALLOC(mp, ip, ip->i_d.di_uid,
+               code = xfs_qm_vop_dqalloc(ip, ip->i_d.di_uid,
                                         ip->i_d.di_gid, fa->fsx_projid,
                                         XFS_QMOPT_PQUOTA, &udqp, &gdqp);
                if (code)
@@ -954,10 +954,11 @@ xfs_ioctl_setattr(
         * Do a quota reservation only if projid is actually going to change.
         */
        if (mask & FSX_PROJID) {
-               if (XFS_IS_PQUOTA_ON(mp) &&
+               if (XFS_IS_QUOTA_RUNNING(mp) &&
+                   XFS_IS_PQUOTA_ON(mp) &&
                    ip->i_d.di_projid != fa->fsx_projid) {
                        ASSERT(tp);
-                       code = XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, udqp, gdqp,
+                       code = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp,
                                                capable(CAP_FOWNER) ?
                                                XFS_QMOPT_FORCE_RES : 0);
                        if (code)       /* out of quota */
@@ -1059,8 +1060,8 @@ xfs_ioctl_setattr(
                 * in the transaction.
                 */
                if (ip->i_d.di_projid != fa->fsx_projid) {
-                       if (XFS_IS_PQUOTA_ON(mp)) {
-                               olddquot = XFS_QM_DQVOPCHOWN(mp, tp, ip,
+                       if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_PQUOTA_ON(mp)) {
+                               olddquot = xfs_qm_vop_chown(tp, ip,
                                                        &ip->i_gdquot, gdqp);
                        }
                        ip->i_d.di_projid = fa->fsx_projid;
@@ -1106,9 +1107,9 @@ xfs_ioctl_setattr(
        /*
         * Release any dquot(s) the inode had kept before chown.
         */
-       XFS_QM_DQRELE(mp, olddquot);
-       XFS_QM_DQRELE(mp, udqp);
-       XFS_QM_DQRELE(mp, gdqp);
+       xfs_qm_dqrele(olddquot);
+       xfs_qm_dqrele(udqp);
+       xfs_qm_dqrele(gdqp);
 
        if (code)
                return code;
@@ -1122,8 +1123,8 @@ xfs_ioctl_setattr(
        return 0;
 
  error_return:
-       XFS_QM_DQRELE(mp, udqp);
-       XFS_QM_DQRELE(mp, gdqp);
+       xfs_qm_dqrele(udqp);
+       xfs_qm_dqrele(gdqp);
        xfs_trans_cancel(tp, 0);
        if (lock_flags)
                xfs_iunlock(ip, lock_flags);
index 6075382336d70b0feca5d7e84b1a53b9926987fd..58973bb460388b2ef3dd8f85f2017ff347810c31 100644 (file)
@@ -17,6 +17,7 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_acl.h"
 #include "xfs_bit.h"
 #include "xfs_log.h"
 #include "xfs_inum.h"
@@ -51,6 +52,7 @@
 #include <linux/capability.h>
 #include <linux/xattr.h>
 #include <linux/namei.h>
+#include <linux/posix_acl.h>
 #include <linux/security.h>
 #include <linux/falloc.h>
 #include <linux/fiemap.h>
@@ -202,9 +204,8 @@ xfs_vn_mknod(
 {
        struct inode    *inode;
        struct xfs_inode *ip = NULL;
-       xfs_acl_t       *default_acl = NULL;
+       struct posix_acl *default_acl = NULL;
        struct xfs_name name;
-       int (*test_default_acl)(struct inode *) = _ACL_DEFAULT_EXISTS;
        int             error;
 
        /*
@@ -219,18 +220,14 @@ xfs_vn_mknod(
                rdev = 0;
        }
 
-       if (test_default_acl && test_default_acl(dir)) {
-               if (!_ACL_ALLOC(default_acl)) {
-                       return -ENOMEM;
-               }
-               if (!_ACL_GET_DEFAULT(dir, default_acl)) {
-                       _ACL_FREE(default_acl);
-                       default_acl = NULL;
-               }
-       }
+       if (IS_POSIXACL(dir)) {
+               default_acl = xfs_get_acl(dir, ACL_TYPE_DEFAULT);
+               if (IS_ERR(default_acl))
+                       return -PTR_ERR(default_acl);
 
-       if (IS_POSIXACL(dir) && !default_acl)
-               mode &= ~current_umask();
+               if (!default_acl)
+                       mode &= ~current_umask();
+       }
 
        xfs_dentry_to_name(&name, dentry);
        error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip, NULL);
@@ -244,10 +241,10 @@ xfs_vn_mknod(
                goto out_cleanup_inode;
 
        if (default_acl) {
-               error = _ACL_INHERIT(inode, mode, default_acl);
+               error = -xfs_inherit_acl(inode, default_acl);
                if (unlikely(error))
                        goto out_cleanup_inode;
-               _ACL_FREE(default_acl);
+               posix_acl_release(default_acl);
        }
 
 
@@ -257,8 +254,7 @@ xfs_vn_mknod(
  out_cleanup_inode:
        xfs_cleanup_inode(dir, inode, dentry);
  out_free_acl:
-       if (default_acl)
-               _ACL_FREE(default_acl);
+       posix_acl_release(default_acl);
        return -error;
 }
 
@@ -488,26 +484,6 @@ xfs_vn_put_link(
                kfree(s);
 }
 
-#ifdef CONFIG_XFS_POSIX_ACL
-STATIC int
-xfs_check_acl(
-       struct inode            *inode,
-       int                     mask)
-{
-       struct xfs_inode        *ip = XFS_I(inode);
-       int                     error;
-
-       xfs_itrace_entry(ip);
-
-       if (XFS_IFORK_Q(ip)) {
-               error = xfs_acl_iaccess(ip, mask, NULL);
-               if (error != -1)
-                       return -error;
-       }
-
-       return -EAGAIN;
-}
-
 STATIC int
 xfs_vn_permission(
        struct inode            *inode,
@@ -515,9 +491,6 @@ xfs_vn_permission(
 {
        return generic_permission(inode, mask, xfs_check_acl);
 }
-#else
-#define xfs_vn_permission NULL
-#endif
 
 STATIC int
 xfs_vn_getattr(
index 9142192ccbe692a678793ba3cb3d69058d1ed717..7078974a6eeed236f3cbc2d6420ba60aabbc0528 100644 (file)
@@ -42,7 +42,6 @@
 #include "xfs_error.h"
 #include "xfs_itable.h"
 #include "xfs_rw.h"
-#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_inode_item.h"
 #include "xfs_buf_item.h"
index 94d9a633d3d91bd6df491d67c425ebf8acf80f6a..cb6e2cca214f4b82528571c11e7dcd3138c7bf37 100644 (file)
@@ -50,9 +50,11 @@ xfs_fs_quota_sync(
 {
        struct xfs_mount        *mp = XFS_M(sb);
 
+       if (sb->s_flags & MS_RDONLY)
+               return -EROFS;
        if (!XFS_IS_QUOTA_RUNNING(mp))
                return -ENOSYS;
-       return -xfs_sync_inodes(mp, SYNC_DELWRI);
+       return -xfs_sync_data(mp, 0);
 }
 
 STATIC int
index 08d6bd9a39476aabf89656722b6fb17e70206656..2e09efbca8dbdeeb7cdfe9abcdb566eefb15c096 100644 (file)
@@ -43,7 +43,6 @@
 #include "xfs_itable.h"
 #include "xfs_fsops.h"
 #include "xfs_rw.h"
-#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_utils.h"
@@ -405,6 +404,14 @@ xfs_parseargs(
                return EINVAL;
        }
 
+#ifndef CONFIG_XFS_QUOTA
+       if (XFS_IS_QUOTA_RUNNING(mp)) {
+               cmn_err(CE_WARN,
+                       "XFS: quota support not available in this kernel.");
+               return EINVAL;
+       }
+#endif
+
        if ((mp->m_qflags & (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE)) &&
            (mp->m_qflags & (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE))) {
                cmn_err(CE_WARN,
@@ -1063,7 +1070,18 @@ xfs_fs_put_super(
        int                     unmount_event_flags = 0;
 
        xfs_syncd_stop(mp);
-       xfs_sync_inodes(mp, SYNC_ATTR|SYNC_DELWRI);
+
+       if (!(sb->s_flags & MS_RDONLY)) {
+               /*
+                * XXX(hch): this should be SYNC_WAIT.
+                *
+                * Or more likely not needed at all because the VFS is already
+                * calling ->sync_fs after shutting down all filestem
+                * operations and just before calling ->put_super.
+                */
+               xfs_sync_data(mp, 0);
+               xfs_sync_attr(mp, 0);
+       }
 
 #ifdef HAVE_DMAPI
        if (mp->m_flags & XFS_MOUNT_DMAPI) {
@@ -1098,7 +1116,6 @@ xfs_fs_put_super(
        xfs_freesb(mp);
        xfs_icsb_destroy_counters(mp);
        xfs_close_devices(mp);
-       xfs_qmops_put(mp);
        xfs_dmops_put(mp);
        xfs_free_fsname(mp);
        kfree(mp);
@@ -1158,6 +1175,7 @@ xfs_fs_statfs(
 {
        struct xfs_mount        *mp = XFS_M(dentry->d_sb);
        xfs_sb_t                *sbp = &mp->m_sb;
+       struct xfs_inode        *ip = XFS_I(dentry->d_inode);
        __uint64_t              fakeinos, id;
        xfs_extlen_t            lsize;
 
@@ -1186,7 +1204,10 @@ xfs_fs_statfs(
        statp->f_ffree = statp->f_files - (sbp->sb_icount - sbp->sb_ifree);
        spin_unlock(&mp->m_sb_lock);
 
-       XFS_QM_DQSTATVFS(XFS_I(dentry->d_inode), statp);
+       if ((ip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) ||
+           ((mp->m_qflags & (XFS_PQUOTA_ACCT|XFS_OQUOTA_ENFD))) ==
+                             (XFS_PQUOTA_ACCT|XFS_OQUOTA_ENFD))
+               xfs_qm_statvfs(ip, statp);
        return 0;
 }
 
@@ -1394,16 +1415,13 @@ xfs_fs_fill_super(
        error = xfs_dmops_get(mp);
        if (error)
                goto out_free_fsname;
-       error = xfs_qmops_get(mp);
-       if (error)
-               goto out_put_dmops;
 
        if (silent)
                flags |= XFS_MFSI_QUIET;
 
        error = xfs_open_devices(mp);
        if (error)
-               goto out_put_qmops;
+               goto out_put_dmops;
 
        if (xfs_icsb_init_counters(mp))
                mp->m_flags |= XFS_MOUNT_NO_PERCPU_SB;
@@ -1471,8 +1489,6 @@ xfs_fs_fill_super(
  out_destroy_counters:
        xfs_icsb_destroy_counters(mp);
        xfs_close_devices(mp);
- out_put_qmops:
-       xfs_qmops_put(mp);
  out_put_dmops:
        xfs_dmops_put(mp);
  out_free_fsname:
@@ -1706,18 +1722,8 @@ xfs_init_zones(void)
        if (!xfs_ili_zone)
                goto out_destroy_inode_zone;
 
-#ifdef CONFIG_XFS_POSIX_ACL
-       xfs_acl_zone = kmem_zone_init(sizeof(xfs_acl_t), "xfs_acl");
-       if (!xfs_acl_zone)
-               goto out_destroy_ili_zone;
-#endif
-
        return 0;
 
-#ifdef CONFIG_XFS_POSIX_ACL
- out_destroy_ili_zone:
-#endif
-       kmem_zone_destroy(xfs_ili_zone);
  out_destroy_inode_zone:
        kmem_zone_destroy(xfs_inode_zone);
  out_destroy_efi_zone:
@@ -1751,9 +1757,6 @@ xfs_init_zones(void)
 STATIC void
 xfs_destroy_zones(void)
 {
-#ifdef CONFIG_XFS_POSIX_ACL
-       kmem_zone_destroy(xfs_acl_zone);
-#endif
        kmem_zone_destroy(xfs_ili_zone);
        kmem_zone_destroy(xfs_inode_zone);
        kmem_zone_destroy(xfs_efi_zone);
index f7ba76633c292396d88f0bd4ce3fc0dffe1734f4..b619d6b8ca4323afc02abab54d967f352d899e6a 100644 (file)
 #include "xfs_buf_item.h"
 #include "xfs_inode_item.h"
 #include "xfs_rw.h"
+#include "xfs_quota.h"
 
 #include <linux/kthread.h>
 #include <linux/freezer.h>
 
-/*
- * Sync all the inodes in the given AG according to the
- * direction given by the flags.
- */
-STATIC int
-xfs_sync_inodes_ag(
-       xfs_mount_t     *mp,
-       int             ag,
-       int             flags)
-{
-       xfs_perag_t     *pag = &mp->m_perag[ag];
-       int             nr_found;
-       uint32_t        first_index = 0;
-       int             error = 0;
-       int             last_error = 0;
 
-       do {
-               struct inode    *inode;
-               xfs_inode_t     *ip = NULL;
-               int             lock_flags = XFS_ILOCK_SHARED;
+STATIC xfs_inode_t *
+xfs_inode_ag_lookup(
+       struct xfs_mount        *mp,
+       struct xfs_perag        *pag,
+       uint32_t                *first_index,
+       int                     tag)
+{
+       int                     nr_found;
+       struct xfs_inode        *ip;
 
-               /*
-                * use a gang lookup to find the next inode in the tree
-                * as the tree is sparse and a gang lookup walks to find
-                * the number of objects requested.
-                */
-               read_lock(&pag->pag_ici_lock);
+       /*
+        * use a gang lookup to find the next inode in the tree
+        * as the tree is sparse and a gang lookup walks to find
+        * the number of objects requested.
+        */
+       read_lock(&pag->pag_ici_lock);
+       if (tag == XFS_ICI_NO_TAG) {
                nr_found = radix_tree_gang_lookup(&pag->pag_ici_root,
-                               (void**)&ip, first_index, 1);
+                               (void **)&ip, *first_index, 1);
+       } else {
+               nr_found = radix_tree_gang_lookup_tag(&pag->pag_ici_root,
+                               (void **)&ip, *first_index, 1, tag);
+       }
+       if (!nr_found)
+               goto unlock;
 
-               if (!nr_found) {
-                       read_unlock(&pag->pag_ici_lock);
-                       break;
-               }
+       /*
+        * Update the index for the next lookup. Catch overflows
+        * into the next AG range which can occur if we have inodes
+        * in the last block of the AG and we are currently
+        * pointing to the last inode.
+        */
+       *first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1);
+       if (*first_index < XFS_INO_TO_AGINO(mp, ip->i_ino))
+               goto unlock;
 
-               /*
-                * Update the index for the next lookup. Catch overflows
-                * into the next AG range which can occur if we have inodes
-                * in the last block of the AG and we are currently
-                * pointing to the last inode.
-                */
-               first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1);
-               if (first_index < XFS_INO_TO_AGINO(mp, ip->i_ino)) {
-                       read_unlock(&pag->pag_ici_lock);
-                       break;
-               }
+       return ip;
 
-               /* nothing to sync during shutdown */
-               if (XFS_FORCED_SHUTDOWN(mp)) {
-                       read_unlock(&pag->pag_ici_lock);
-                       return 0;
-               }
+unlock:
+       read_unlock(&pag->pag_ici_lock);
+       return NULL;
+}
 
-               /*
-                * If we can't get a reference on the inode, it must be
-                * in reclaim. Leave it for the reclaim code to flush.
-                */
-               inode = VFS_I(ip);
-               if (!igrab(inode)) {
-                       read_unlock(&pag->pag_ici_lock);
-                       continue;
-               }
-               read_unlock(&pag->pag_ici_lock);
+STATIC int
+xfs_inode_ag_walk(
+       struct xfs_mount        *mp,
+       xfs_agnumber_t          ag,
+       int                     (*execute)(struct xfs_inode *ip,
+                                          struct xfs_perag *pag, int flags),
+       int                     flags,
+       int                     tag)
+{
+       struct xfs_perag        *pag = &mp->m_perag[ag];
+       uint32_t                first_index;
+       int                     last_error = 0;
+       int                     skipped;
 
-               /* avoid new or bad inodes */
-               if (is_bad_inode(inode) ||
-                   xfs_iflags_test(ip, XFS_INEW)) {
-                       IRELE(ip);
-                       continue;
-               }
+restart:
+       skipped = 0;
+       first_index = 0;
+       do {
+               int             error = 0;
+               xfs_inode_t     *ip;
 
-               /*
-                * If we have to flush data or wait for I/O completion
-                * we need to hold the iolock.
-                */
-               if (flags & SYNC_DELWRI) {
-                       if (VN_DIRTY(inode)) {
-                               if (flags & SYNC_TRYLOCK) {
-                                       if (xfs_ilock_nowait(ip, XFS_IOLOCK_SHARED))
-                                               lock_flags |= XFS_IOLOCK_SHARED;
-                               } else {
-                                       xfs_ilock(ip, XFS_IOLOCK_SHARED);
-                                       lock_flags |= XFS_IOLOCK_SHARED;
-                               }
-                               if (lock_flags & XFS_IOLOCK_SHARED) {
-                                       error = xfs_flush_pages(ip, 0, -1,
-                                                       (flags & SYNC_WAIT) ? 0
-                                                               : XFS_B_ASYNC,
-                                                       FI_NONE);
-                               }
-                       }
-                       if (VN_CACHED(inode) && (flags & SYNC_IOWAIT))
-                               xfs_ioend_wait(ip);
-               }
-               xfs_ilock(ip, XFS_ILOCK_SHARED);
-
-               if ((flags & SYNC_ATTR) && !xfs_inode_clean(ip)) {
-                       if (flags & SYNC_WAIT) {
-                               xfs_iflock(ip);
-                               if (!xfs_inode_clean(ip))
-                                       error = xfs_iflush(ip, XFS_IFLUSH_SYNC);
-                               else
-                                       xfs_ifunlock(ip);
-                       } else if (xfs_iflock_nowait(ip)) {
-                               if (!xfs_inode_clean(ip))
-                                       error = xfs_iflush(ip, XFS_IFLUSH_DELWRI);
-                               else
-                                       xfs_ifunlock(ip);
-                       }
-               }
-               xfs_iput(ip, lock_flags);
+               ip = xfs_inode_ag_lookup(mp, pag, &first_index, tag);
+               if (!ip)
+                       break;
 
+               error = execute(ip, pag, flags);
+               if (error == EAGAIN) {
+                       skipped++;
+                       continue;
+               }
                if (error)
                        last_error = error;
                /*
                 * bail out if the filesystem is corrupted.
                 */
                if (error == EFSCORRUPTED)
-                       return XFS_ERROR(error);
+                       break;
 
-       } while (nr_found);
+       } while (1);
+
+       if (skipped) {
+               delay(1);
+               goto restart;
+       }
 
+       xfs_put_perag(mp, pag);
        return last_error;
 }
 
 int
-xfs_sync_inodes(
-       xfs_mount_t     *mp,
-       int             flags)
+xfs_inode_ag_iterator(
+       struct xfs_mount        *mp,
+       int                     (*execute)(struct xfs_inode *ip,
+                                          struct xfs_perag *pag, int flags),
+       int                     flags,
+       int                     tag)
 {
-       int             error;
-       int             last_error;
-       int             i;
-       int             lflags = XFS_LOG_FORCE;
+       int                     error = 0;
+       int                     last_error = 0;
+       xfs_agnumber_t          ag;
 
-       if (mp->m_flags & XFS_MOUNT_RDONLY)
-               return 0;
-       error = 0;
-       last_error = 0;
+       for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) {
+               if (!mp->m_perag[ag].pag_ici_init)
+                       continue;
+               error = xfs_inode_ag_walk(mp, ag, execute, flags, tag);
+               if (error) {
+                       last_error = error;
+                       if (error == EFSCORRUPTED)
+                               break;
+               }
+       }
+       return XFS_ERROR(last_error);
+}
+
+/* must be called with pag_ici_lock held and releases it */
+int
+xfs_sync_inode_valid(
+       struct xfs_inode        *ip,
+       struct xfs_perag        *pag)
+{
+       struct inode            *inode = VFS_I(ip);
+
+       /* nothing to sync during shutdown */
+       if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
+               read_unlock(&pag->pag_ici_lock);
+               return EFSCORRUPTED;
+       }
+
+       /*
+        * If we can't get a reference on the inode, it must be in reclaim.
+        * Leave it for the reclaim code to flush. Also avoid inodes that
+        * haven't been fully initialised.
+        */
+       if (!igrab(inode)) {
+               read_unlock(&pag->pag_ici_lock);
+               return ENOENT;
+       }
+       read_unlock(&pag->pag_ici_lock);
+
+       if (is_bad_inode(inode) || xfs_iflags_test(ip, XFS_INEW)) {
+               IRELE(ip);
+               return ENOENT;
+       }
+
+       return 0;
+}
+
+STATIC int
+xfs_sync_inode_data(
+       struct xfs_inode        *ip,
+       struct xfs_perag        *pag,
+       int                     flags)
+{
+       struct inode            *inode = VFS_I(ip);
+       struct address_space *mapping = inode->i_mapping;
+       int                     error = 0;
+
+       error = xfs_sync_inode_valid(ip, pag);
+       if (error)
+               return error;
+
+       if (!mapping_tagged(mapping, PAGECACHE_TAG_DIRTY))
+               goto out_wait;
+
+       if (!xfs_ilock_nowait(ip, XFS_IOLOCK_SHARED)) {
+               if (flags & SYNC_TRYLOCK)
+                       goto out_wait;
+               xfs_ilock(ip, XFS_IOLOCK_SHARED);
+       }
+
+       error = xfs_flush_pages(ip, 0, -1, (flags & SYNC_WAIT) ?
+                               0 : XFS_B_ASYNC, FI_NONE);
+       xfs_iunlock(ip, XFS_IOLOCK_SHARED);
 
+ out_wait:
        if (flags & SYNC_WAIT)
-               lflags |= XFS_LOG_SYNC;
+               xfs_ioend_wait(ip);
+       IRELE(ip);
+       return error;
+}
 
-       for (i = 0; i < mp->m_sb.sb_agcount; i++) {
-               if (!mp->m_perag[i].pag_ici_init)
-                       continue;
-               error = xfs_sync_inodes_ag(mp, i, flags);
-               if (error)
-                       last_error = error;
-               if (error == EFSCORRUPTED)
-                       break;
+STATIC int
+xfs_sync_inode_attr(
+       struct xfs_inode        *ip,
+       struct xfs_perag        *pag,
+       int                     flags)
+{
+       int                     error = 0;
+
+       error = xfs_sync_inode_valid(ip, pag);
+       if (error)
+               return error;
+
+       xfs_ilock(ip, XFS_ILOCK_SHARED);
+       if (xfs_inode_clean(ip))
+               goto out_unlock;
+       if (!xfs_iflock_nowait(ip)) {
+               if (!(flags & SYNC_WAIT))
+                       goto out_unlock;
+               xfs_iflock(ip);
        }
-       if (flags & SYNC_DELWRI)
-               xfs_log_force(mp, 0, lflags);
 
-       return XFS_ERROR(last_error);
+       if (xfs_inode_clean(ip)) {
+               xfs_ifunlock(ip);
+               goto out_unlock;
+       }
+
+       error = xfs_iflush(ip, (flags & SYNC_WAIT) ?
+                          XFS_IFLUSH_SYNC : XFS_IFLUSH_DELWRI);
+
+ out_unlock:
+       xfs_iunlock(ip, XFS_ILOCK_SHARED);
+       IRELE(ip);
+       return error;
+}
+
+/*
+ * Write out pagecache data for the whole filesystem.
+ */
+int
+xfs_sync_data(
+       struct xfs_mount        *mp,
+       int                     flags)
+{
+       int                     error;
+
+       ASSERT((flags & ~(SYNC_TRYLOCK|SYNC_WAIT)) == 0);
+
+       error = xfs_inode_ag_iterator(mp, xfs_sync_inode_data, flags,
+                                     XFS_ICI_NO_TAG);
+       if (error)
+               return XFS_ERROR(error);
+
+       xfs_log_force(mp, 0,
+                     (flags & SYNC_WAIT) ?
+                      XFS_LOG_FORCE | XFS_LOG_SYNC :
+                      XFS_LOG_FORCE);
+       return 0;
+}
+
+/*
+ * Write out inode metadata (attributes) for the whole filesystem.
+ */
+int
+xfs_sync_attr(
+       struct xfs_mount        *mp,
+       int                     flags)
+{
+       ASSERT((flags & ~SYNC_WAIT) == 0);
+
+       return xfs_inode_ag_iterator(mp, xfs_sync_inode_attr, flags,
+                                    XFS_ICI_NO_TAG);
 }
 
 STATIC int
@@ -252,7 +353,7 @@ xfs_sync_fsdata(
         * If this is xfssyncd() then only sync the superblock if we can
         * lock it without sleeping and it is not pinned.
         */
-       if (flags & SYNC_BDFLUSH) {
+       if (flags & SYNC_TRYLOCK) {
                ASSERT(!(flags & SYNC_WAIT));
 
                bp = xfs_getsb(mp, XFS_BUF_TRYLOCK);
@@ -316,13 +417,13 @@ xfs_quiesce_data(
        int error;
 
        /* push non-blocking */
-       xfs_sync_inodes(mp, SYNC_DELWRI|SYNC_BDFLUSH);
-       XFS_QM_DQSYNC(mp, SYNC_BDFLUSH);
+       xfs_sync_data(mp, 0);
+       xfs_qm_sync(mp, SYNC_TRYLOCK);
        xfs_filestream_flush(mp);
 
        /* push and block */
-       xfs_sync_inodes(mp, SYNC_DELWRI|SYNC_WAIT|SYNC_IOWAIT);
-       XFS_QM_DQSYNC(mp, SYNC_WAIT);
+       xfs_sync_data(mp, SYNC_WAIT);
+       xfs_qm_sync(mp, SYNC_WAIT);
 
        /* write superblock and hoover up shutdown errors */
        error = xfs_sync_fsdata(mp, 0);
@@ -341,7 +442,7 @@ xfs_quiesce_fs(
        int     count = 0, pincount;
 
        xfs_flush_buftarg(mp->m_ddev_targp, 0);
-       xfs_reclaim_inodes(mp, 0, XFS_IFLUSH_DELWRI_ELSE_ASYNC);
+       xfs_reclaim_inodes(mp, XFS_IFLUSH_DELWRI_ELSE_ASYNC);
 
        /*
         * This loop must run at least twice.  The first instance of the loop
@@ -350,7 +451,7 @@ xfs_quiesce_fs(
         * logged before we can write the unmount record.
         */
        do {
-               xfs_sync_inodes(mp, SYNC_ATTR|SYNC_WAIT);
+               xfs_sync_attr(mp, SYNC_WAIT);
                pincount = xfs_flush_buftarg(mp->m_ddev_targp, 1);
                if (!pincount) {
                        delay(50);
@@ -433,8 +534,8 @@ xfs_flush_inodes_work(
        void            *arg)
 {
        struct inode    *inode = arg;
-       xfs_sync_inodes(mp, SYNC_DELWRI | SYNC_TRYLOCK);
-       xfs_sync_inodes(mp, SYNC_DELWRI | SYNC_TRYLOCK | SYNC_IOWAIT);
+       xfs_sync_data(mp, SYNC_TRYLOCK);
+       xfs_sync_data(mp, SYNC_TRYLOCK | SYNC_WAIT);
        iput(inode);
 }
 
@@ -465,10 +566,10 @@ xfs_sync_worker(
 
        if (!(mp->m_flags & XFS_MOUNT_RDONLY)) {
                xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE);
-               xfs_reclaim_inodes(mp, 0, XFS_IFLUSH_DELWRI_ELSE_ASYNC);
+               xfs_reclaim_inodes(mp, XFS_IFLUSH_DELWRI_ELSE_ASYNC);
                /* dgc: errors ignored here */
-               error = XFS_QM_DQSYNC(mp, SYNC_BDFLUSH);
-               error = xfs_sync_fsdata(mp, SYNC_BDFLUSH);
+               error = xfs_qm_sync(mp, SYNC_TRYLOCK);
+               error = xfs_sync_fsdata(mp, SYNC_TRYLOCK);
                if (xfs_log_need_covered(mp))
                        error = xfs_commit_dummy_trans(mp, XFS_LOG_FORCE);
        }
@@ -569,7 +670,7 @@ xfs_reclaim_inode(
                        xfs_ifunlock(ip);
                        xfs_iunlock(ip, XFS_ILOCK_EXCL);
                }
-               return 1;
+               return -EAGAIN;
        }
        __xfs_iflags_set(ip, XFS_IRECLAIM);
        spin_unlock(&ip->i_flags_lock);
@@ -654,101 +755,27 @@ xfs_inode_clear_reclaim_tag(
        xfs_put_perag(mp, pag);
 }
 
-
-STATIC void
-xfs_reclaim_inodes_ag(
-       xfs_mount_t     *mp,
-       int             ag,
-       int             noblock,
-       int             mode)
+STATIC int
+xfs_reclaim_inode_now(
+       struct xfs_inode        *ip,
+       struct xfs_perag        *pag,
+       int                     flags)
 {
-       xfs_inode_t     *ip = NULL;
-       xfs_perag_t     *pag = &mp->m_perag[ag];
-       int             nr_found;
-       uint32_t        first_index;
-       int             skipped;
-
-restart:
-       first_index = 0;
-       skipped = 0;
-       do {
-               /*
-                * use a gang lookup to find the next inode in the tree
-                * as the tree is sparse and a gang lookup walks to find
-                * the number of objects requested.
-                */
-               read_lock(&pag->pag_ici_lock);
-               nr_found = radix_tree_gang_lookup_tag(&pag->pag_ici_root,
-                                       (void**)&ip, first_index, 1,
-                                       XFS_ICI_RECLAIM_TAG);
-
-               if (!nr_found) {
-                       read_unlock(&pag->pag_ici_lock);
-                       break;
-               }
-
-               /*
-                * Update the index for the next lookup. Catch overflows
-                * into the next AG range which can occur if we have inodes
-                * in the last block of the AG and we are currently
-                * pointing to the last inode.
-                */
-               first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1);
-               if (first_index < XFS_INO_TO_AGINO(mp, ip->i_ino)) {
-                       read_unlock(&pag->pag_ici_lock);
-                       break;
-               }
-
-               /* ignore if already under reclaim */
-               if (xfs_iflags_test(ip, XFS_IRECLAIM)) {
-                       read_unlock(&pag->pag_ici_lock);
-                       continue;
-               }
-
-               if (noblock) {
-                       if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) {
-                               read_unlock(&pag->pag_ici_lock);
-                               continue;
-                       }
-                       if (xfs_ipincount(ip) ||
-                           !xfs_iflock_nowait(ip)) {
-                               xfs_iunlock(ip, XFS_ILOCK_EXCL);
-                               read_unlock(&pag->pag_ici_lock);
-                               continue;
-                       }
-               }
+       /* ignore if already under reclaim */
+       if (xfs_iflags_test(ip, XFS_IRECLAIM)) {
                read_unlock(&pag->pag_ici_lock);
-
-               /*
-                * hmmm - this is an inode already in reclaim. Do
-                * we even bother catching it here?
-                */
-               if (xfs_reclaim_inode(ip, noblock, mode))
-                       skipped++;
-       } while (nr_found);
-
-       if (skipped) {
-               delay(1);
-               goto restart;
+               return 0;
        }
-       return;
+       read_unlock(&pag->pag_ici_lock);
 
+       return xfs_reclaim_inode(ip, 0, flags);
 }
 
 int
 xfs_reclaim_inodes(
        xfs_mount_t     *mp,
-       int              noblock,
        int             mode)
 {
-       int             i;
-
-       for (i = 0; i < mp->m_sb.sb_agcount; i++) {
-               if (!mp->m_perag[i].pag_ici_init)
-                       continue;
-               xfs_reclaim_inodes_ag(mp, i, noblock, mode);
-       }
-       return 0;
+       return xfs_inode_ag_iterator(mp, xfs_reclaim_inode_now, mode,
+                                       XFS_ICI_RECLAIM_TAG);
 }
-
-
index 308d5bf6dfbda281376be436cfd0434085ccdaec..2a10301c99c79b8bf73e3d89a73f965ef580b23a 100644 (file)
@@ -29,17 +29,14 @@ typedef struct xfs_sync_work {
        struct completion       *w_completion;
 } xfs_sync_work_t;
 
-#define SYNC_ATTR              0x0001  /* sync attributes */
-#define SYNC_DELWRI            0x0002  /* look at delayed writes */
-#define SYNC_WAIT              0x0004  /* wait for i/o to complete */
-#define SYNC_BDFLUSH           0x0008  /* BDFLUSH is calling -- don't block */
-#define SYNC_IOWAIT            0x0010  /* wait for all I/O to complete */
-#define SYNC_TRYLOCK           0x0020  /* only try to lock inodes */
+#define SYNC_WAIT              0x0001  /* wait for i/o to complete */
+#define SYNC_TRYLOCK           0x0002  /* only try to lock inodes */
 
 int xfs_syncd_init(struct xfs_mount *mp);
 void xfs_syncd_stop(struct xfs_mount *mp);
 
-int xfs_sync_inodes(struct xfs_mount *mp, int flags);
+int xfs_sync_attr(struct xfs_mount *mp, int flags);
+int xfs_sync_data(struct xfs_mount *mp, int flags);
 int xfs_sync_fsdata(struct xfs_mount *mp, int flags);
 
 int xfs_quiesce_data(struct xfs_mount *mp);
@@ -48,10 +45,16 @@ void xfs_quiesce_attr(struct xfs_mount *mp);
 void xfs_flush_inodes(struct xfs_inode *ip);
 
 int xfs_reclaim_inode(struct xfs_inode *ip, int locked, int sync_mode);
-int xfs_reclaim_inodes(struct xfs_mount *mp, int noblock, int mode);
+int xfs_reclaim_inodes(struct xfs_mount *mp, int mode);
 
 void xfs_inode_set_reclaim_tag(struct xfs_inode *ip);
 void xfs_inode_clear_reclaim_tag(struct xfs_inode *ip);
 void __xfs_inode_clear_reclaim_tag(struct xfs_mount *mp, struct xfs_perag *pag,
                                struct xfs_inode *ip);
+
+int xfs_sync_inode_valid(struct xfs_inode *ip, struct xfs_perag *pag);
+int xfs_inode_ag_iterator(struct xfs_mount *mp,
+       int (*execute)(struct xfs_inode *ip, struct xfs_perag *pag, int flags),
+       int flags, int tag);
+
 #endif
index 964621fde6ed849936d8aea60e816d8dd0fea964..497c7fb75cc18f95cd1b746c36cef2b1a4e1b227 100644 (file)
 #include <linux/xattr.h>
 
 
-/*
- * ACL handling.  Should eventually be moved into xfs_acl.c
- */
-
-static int
-xfs_decode_acl(const char *name)
-{
-       if (strcmp(name, "posix_acl_access") == 0)
-               return _ACL_TYPE_ACCESS;
-       else if (strcmp(name, "posix_acl_default") == 0)
-               return _ACL_TYPE_DEFAULT;
-       return -EINVAL;
-}
-
-/*
- * Get system extended attributes which at the moment only
- * includes Posix ACLs.
- */
-static int
-xfs_xattr_system_get(struct inode *inode, const char *name,
-               void *buffer, size_t size)
-{
-       int acl;
-
-       acl = xfs_decode_acl(name);
-       if (acl < 0)
-               return acl;
-
-       return xfs_acl_vget(inode, buffer, size, acl);
-}
-
-static int
-xfs_xattr_system_set(struct inode *inode, const char *name,
-               const void *value, size_t size, int flags)
-{
-       int acl;
-
-       acl = xfs_decode_acl(name);
-       if (acl < 0)
-               return acl;
-       if (flags & XATTR_CREATE)
-               return -EINVAL;
-
-       if (!value)
-               return xfs_acl_vremove(inode, acl);
-
-       return xfs_acl_vset(inode, (void *)value, size, acl);
-}
-
-static struct xattr_handler xfs_xattr_system_handler = {
-       .prefix = XATTR_SYSTEM_PREFIX,
-       .get    = xfs_xattr_system_get,
-       .set    = xfs_xattr_system_set,
-};
-
-
-/*
- * Real xattr handling.  The only difference between the namespaces is
- * a flag passed to the low-level attr code.
- */
-
 static int
 __xfs_xattr_get(struct inode *inode, const char *name,
                void *value, size_t size, int xflags)
@@ -199,7 +138,9 @@ struct xattr_handler *xfs_xattr_handlers[] = {
        &xfs_xattr_user_handler,
        &xfs_xattr_trusted_handler,
        &xfs_xattr_security_handler,
+#ifdef CONFIG_XFS_POSIX_ACL
        &xfs_xattr_system_handler,
+#endif
        NULL
 };
 
@@ -310,7 +251,7 @@ xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size)
        /*
         * Then add the two synthetic ACL attributes.
         */
-       if (xfs_acl_vhasacl_access(inode)) {
+       if (posix_acl_access_exists(inode)) {
                error = list_one_attr(POSIX_ACL_XATTR_ACCESS,
                                strlen(POSIX_ACL_XATTR_ACCESS) + 1,
                                data, size, &context.count);
@@ -318,7 +259,7 @@ xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size)
                        return error;
        }
 
-       if (xfs_acl_vhasacl_default(inode)) {
+       if (posix_acl_default_exists(inode)) {
                error = list_one_attr(POSIX_ACL_XATTR_DEFAULT,
                                strlen(POSIX_ACL_XATTR_DEFAULT) + 1,
                                data, size, &context.count);
index e4babcc63423fef26351c5e9255757ec5d4dbba7..2f3f2229eaaf16c68e57a37b2e373fe2e131e26b 100644 (file)
@@ -42,7 +42,6 @@
 #include "xfs_error.h"
 #include "xfs_itable.h"
 #include "xfs_rw.h"
-#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_trans_space.h"
@@ -1194,7 +1193,9 @@ void
 xfs_qm_dqrele(
        xfs_dquot_t     *dqp)
 {
-       ASSERT(dqp);
+       if (!dqp)
+               return;
+
        xfs_dqtrace_entry(dqp, "DQRELE");
 
        xfs_dqlock(dqp);
index de0f402ddb4c2df0f97d040ccfc1df80a9bee190..6533ead9b8897dec1743a2e5b225ead3351ac817 100644 (file)
@@ -181,7 +181,6 @@ extern void         xfs_qm_adjust_dqlimits(xfs_mount_t *,
 extern int             xfs_qm_dqget(xfs_mount_t *, xfs_inode_t *,
                                        xfs_dqid_t, uint, uint, xfs_dquot_t **);
 extern void            xfs_qm_dqput(xfs_dquot_t *);
-extern void            xfs_qm_dqrele(xfs_dquot_t *);
 extern void            xfs_dqlock(xfs_dquot_t *);
 extern void            xfs_dqlock2(xfs_dquot_t *, xfs_dquot_t *);
 extern void            xfs_dqunlock(xfs_dquot_t *);
index 1728f6a7c4f50d4a37ee22900140b1a02e90c7d8..d0d4a9a0bbd792d23058c6afb10c9a4472f14f32 100644 (file)
@@ -42,7 +42,6 @@
 #include "xfs_error.h"
 #include "xfs_itable.h"
 #include "xfs_rw.h"
-#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_trans_priv.h"
index 5b6695049e0037849751e1fff5a908b012962c29..45b1bfef73884ce7ea6740fffc934db6140feded 100644 (file)
@@ -42,7 +42,6 @@
 #include "xfs_error.h"
 #include "xfs_bmap.h"
 #include "xfs_rw.h"
-#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_trans_space.h"
@@ -287,11 +286,13 @@ xfs_qm_rele_quotafs_ref(
  * Just destroy the quotainfo structure.
  */
 void
-xfs_qm_unmount_quotadestroy(
-       xfs_mount_t     *mp)
+xfs_qm_unmount(
+       struct xfs_mount        *mp)
 {
-       if (mp->m_quotainfo)
+       if (mp->m_quotainfo) {
+               xfs_qm_dqpurge_all(mp, XFS_QMOPT_QUOTALL | XFS_QMOPT_UMOUNTING);
                xfs_qm_destroy_quotainfo(mp);
+       }
 }
 
 
@@ -385,8 +386,13 @@ xfs_qm_mount_quotas(
        if (error) {
                xfs_fs_cmn_err(CE_WARN, mp,
                        "Failed to initialize disk quotas.");
+               return;
        }
-       return;
+
+#ifdef QUOTADEBUG
+       if (XFS_IS_QUOTA_ON(mp))
+               xfs_qm_internalqcheck(mp);
+#endif
 }
 
 /*
@@ -774,12 +780,11 @@ xfs_qm_dqattach_grouphint(
  * Given a locked inode, attach dquot(s) to it, taking U/G/P-QUOTAON
  * into account.
  * If XFS_QMOPT_DQALLOC, the dquot(s) will be allocated if needed.
- * If XFS_QMOPT_ILOCKED, then inode sent is already locked EXCL.
  * Inode may get unlocked and relocked in here, and the caller must deal with
  * the consequences.
  */
 int
-xfs_qm_dqattach(
+xfs_qm_dqattach_locked(
        xfs_inode_t     *ip,
        uint            flags)
 {
@@ -787,17 +792,14 @@ xfs_qm_dqattach(
        uint            nquotas = 0;
        int             error = 0;
 
-       if ((! XFS_IS_QUOTA_ON(mp)) ||
-           (! XFS_NOT_DQATTACHED(mp, ip)) ||
-           (ip->i_ino == mp->m_sb.sb_uquotino) ||
-           (ip->i_ino == mp->m_sb.sb_gquotino))
+       if (!XFS_IS_QUOTA_RUNNING(mp) ||
+           !XFS_IS_QUOTA_ON(mp) ||
+           !XFS_NOT_DQATTACHED(mp, ip) ||
+           ip->i_ino == mp->m_sb.sb_uquotino ||
+           ip->i_ino == mp->m_sb.sb_gquotino)
                return 0;
 
-       ASSERT((flags & XFS_QMOPT_ILOCKED) == 0 ||
-              xfs_isilocked(ip, XFS_ILOCK_EXCL));
-
-       if (! (flags & XFS_QMOPT_ILOCKED))
-               xfs_ilock(ip, XFS_ILOCK_EXCL);
+       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
 
        if (XFS_IS_UQUOTA_ON(mp)) {
                error = xfs_qm_dqattach_one(ip, ip->i_d.di_uid, XFS_DQ_USER,
@@ -849,8 +851,7 @@ xfs_qm_dqattach(
                xfs_qm_dqattach_grouphint(ip->i_udquot, ip->i_gdquot);
        }
 
-      done:
-
+ done:
 #ifdef QUOTADEBUG
        if (! error) {
                if (XFS_IS_UQUOTA_ON(mp))
@@ -858,15 +859,22 @@ xfs_qm_dqattach(
                if (XFS_IS_OQUOTA_ON(mp))
                        ASSERT(ip->i_gdquot);
        }
+       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
 #endif
+       return error;
+}
 
-       if (! (flags & XFS_QMOPT_ILOCKED))
-               xfs_iunlock(ip, XFS_ILOCK_EXCL);
+int
+xfs_qm_dqattach(
+       struct xfs_inode        *ip,
+       uint                    flags)
+{
+       int                     error;
+
+       xfs_ilock(ip, XFS_ILOCK_EXCL);
+       error = xfs_qm_dqattach_locked(ip, flags);
+       xfs_iunlock(ip, XFS_ILOCK_EXCL);
 
-#ifdef QUOTADEBUG
-       else
-               ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
-#endif
        return error;
 }
 
@@ -896,11 +904,6 @@ xfs_qm_dqdetach(
        }
 }
 
-/*
- * This is called to sync quotas. We can be told to use non-blocking
- * semantics by either the SYNC_BDFLUSH flag or the absence of the
- * SYNC_WAIT flag.
- */
 int
 xfs_qm_sync(
        xfs_mount_t     *mp,
@@ -909,17 +912,13 @@ xfs_qm_sync(
        int             recl, restarts;
        xfs_dquot_t     *dqp;
        uint            flush_flags;
-       boolean_t       nowait;
        int             error;
 
-       if (! XFS_IS_QUOTA_ON(mp))
+       if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp))
                return 0;
 
+       flush_flags = (flags & SYNC_WAIT) ? XFS_QMOPT_SYNC : XFS_QMOPT_DELWRI;
        restarts = 0;
-       /*
-        * We won't block unless we are asked to.
-        */
-       nowait = (boolean_t)(flags & SYNC_BDFLUSH || (flags & SYNC_WAIT) == 0);
 
   again:
        xfs_qm_mplist_lock(mp);
@@ -939,18 +938,10 @@ xfs_qm_sync(
                 * don't 'seem' to be dirty. ie. don't acquire dqlock.
                 * This is very similar to what xfs_sync does with inodes.
                 */
-               if (flags & SYNC_BDFLUSH) {
-                       if (! XFS_DQ_IS_DIRTY(dqp))
+               if (flags & SYNC_TRYLOCK) {
+                       if (!XFS_DQ_IS_DIRTY(dqp))
                                continue;
-               }
-
-               if (nowait) {
-                       /*
-                        * Try to acquire the dquot lock. We are NOT out of
-                        * lock order, but we just don't want to wait for this
-                        * lock, unless somebody wanted us to.
-                        */
-                       if (! xfs_qm_dqlock_nowait(dqp))
+                       if (!xfs_qm_dqlock_nowait(dqp))
                                continue;
                } else {
                        xfs_dqlock(dqp);
@@ -967,7 +958,7 @@ xfs_qm_sync(
                /* XXX a sentinel would be better */
                recl = XFS_QI_MPLRECLAIMS(mp);
                if (!xfs_dqflock_nowait(dqp)) {
-                       if (nowait) {
+                       if (flags & SYNC_TRYLOCK) {
                                xfs_dqunlock(dqp);
                                continue;
                        }
@@ -985,7 +976,6 @@ xfs_qm_sync(
                 * Let go of the mplist lock. We don't want to hold it
                 * across a disk write
                 */
-               flush_flags = (nowait) ? XFS_QMOPT_DELWRI : XFS_QMOPT_SYNC;
                xfs_qm_mplist_unlock(mp);
                xfs_dqtrace_entry(dqp, "XQM_SYNC: DQFLUSH");
                error = xfs_qm_dqflush(dqp, flush_flags);
@@ -2319,20 +2309,20 @@ xfs_qm_write_sb_changes(
  */
 int
 xfs_qm_vop_dqalloc(
-       xfs_mount_t     *mp,
-       xfs_inode_t     *ip,
-       uid_t           uid,
-       gid_t           gid,
-       prid_t          prid,
-       uint            flags,
-       xfs_dquot_t     **O_udqpp,
-       xfs_dquot_t     **O_gdqpp)
+       struct xfs_inode        *ip,
+       uid_t                   uid,
+       gid_t                   gid,
+       prid_t                  prid,
+       uint                    flags,
+       struct xfs_dquot        **O_udqpp,
+       struct xfs_dquot        **O_gdqpp)
 {
-       int             error;
-       xfs_dquot_t     *uq, *gq;
-       uint            lockflags;
+       struct xfs_mount        *mp = ip->i_mount;
+       struct xfs_dquot        *uq, *gq;
+       int                     error;
+       uint                    lockflags;
 
-       if (!XFS_IS_QUOTA_ON(mp))
+       if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp))
                return 0;
 
        lockflags = XFS_ILOCK_EXCL;
@@ -2346,8 +2336,8 @@ xfs_qm_vop_dqalloc(
         * if necessary. The dquot(s) will not be locked.
         */
        if (XFS_NOT_DQATTACHED(mp, ip)) {
-               if ((error = xfs_qm_dqattach(ip, XFS_QMOPT_DQALLOC |
-                                           XFS_QMOPT_ILOCKED))) {
+               error = xfs_qm_dqattach_locked(ip, XFS_QMOPT_DQALLOC);
+               if (error) {
                        xfs_iunlock(ip, lockflags);
                        return error;
                }
@@ -2469,6 +2459,7 @@ xfs_qm_vop_chown(
        uint            bfield = XFS_IS_REALTIME_INODE(ip) ?
                                 XFS_TRANS_DQ_RTBCOUNT : XFS_TRANS_DQ_BCOUNT;
 
+
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
        ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount));
 
@@ -2508,13 +2499,13 @@ xfs_qm_vop_chown_reserve(
        xfs_dquot_t     *gdqp,
        uint            flags)
 {
-       int             error;
-       xfs_mount_t     *mp;
+       xfs_mount_t     *mp = ip->i_mount;
        uint            delblks, blkflags, prjflags = 0;
        xfs_dquot_t     *unresudq, *unresgdq, *delblksudq, *delblksgdq;
+       int             error;
+
 
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
-       mp = ip->i_mount;
        ASSERT(XFS_IS_QUOTA_RUNNING(mp));
 
        delblks = ip->i_delayed_blks;
@@ -2582,28 +2573,23 @@ xfs_qm_vop_chown_reserve(
 
 int
 xfs_qm_vop_rename_dqattach(
-       xfs_inode_t     **i_tab)
+       struct xfs_inode        **i_tab)
 {
-       xfs_inode_t     *ip;
-       int             i;
-       int             error;
+       struct xfs_mount        *mp = i_tab[0]->i_mount;
+       int                     i;
 
-       ip = i_tab[0];
-
-       if (! XFS_IS_QUOTA_ON(ip->i_mount))
+       if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp))
                return 0;
 
-       if (XFS_NOT_DQATTACHED(ip->i_mount, ip)) {
-               error = xfs_qm_dqattach(ip, 0);
-               if (error)
-                       return error;
-       }
-       for (i = 1; (i < 4 && i_tab[i]); i++) {
+       for (i = 0; (i < 4 && i_tab[i]); i++) {
+               struct xfs_inode        *ip = i_tab[i];
+               int                     error;
+
                /*
                 * Watch out for duplicate entries in the table.
                 */
-               if ((ip = i_tab[i]) != i_tab[i-1]) {
-                       if (XFS_NOT_DQATTACHED(ip->i_mount, ip)) {
+               if (i == 0 || ip != i_tab[i-1]) {
+                       if (XFS_NOT_DQATTACHED(mp, ip)) {
                                error = xfs_qm_dqattach(ip, 0);
                                if (error)
                                        return error;
@@ -2614,17 +2600,19 @@ xfs_qm_vop_rename_dqattach(
 }
 
 void
-xfs_qm_vop_dqattach_and_dqmod_newinode(
-       xfs_trans_t     *tp,
-       xfs_inode_t     *ip,
-       xfs_dquot_t     *udqp,
-       xfs_dquot_t     *gdqp)
+xfs_qm_vop_create_dqattach(
+       struct xfs_trans        *tp,
+       struct xfs_inode        *ip,
+       struct xfs_dquot        *udqp,
+       struct xfs_dquot        *gdqp)
 {
-       if (!XFS_IS_QUOTA_ON(tp->t_mountp))
+       struct xfs_mount        *mp = tp->t_mountp;
+
+       if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp))
                return;
 
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
-       ASSERT(XFS_IS_QUOTA_RUNNING(tp->t_mountp));
+       ASSERT(XFS_IS_QUOTA_RUNNING(mp));
 
        if (udqp) {
                xfs_dqlock(udqp);
@@ -2632,7 +2620,7 @@ xfs_qm_vop_dqattach_and_dqmod_newinode(
                xfs_dqunlock(udqp);
                ASSERT(ip->i_udquot == NULL);
                ip->i_udquot = udqp;
-               ASSERT(XFS_IS_UQUOTA_ON(tp->t_mountp));
+               ASSERT(XFS_IS_UQUOTA_ON(mp));
                ASSERT(ip->i_d.di_uid == be32_to_cpu(udqp->q_core.d_id));
                xfs_trans_mod_dquot(tp, udqp, XFS_TRANS_DQ_ICOUNT, 1);
        }
@@ -2642,8 +2630,8 @@ xfs_qm_vop_dqattach_and_dqmod_newinode(
                xfs_dqunlock(gdqp);
                ASSERT(ip->i_gdquot == NULL);
                ip->i_gdquot = gdqp;
-               ASSERT(XFS_IS_OQUOTA_ON(tp->t_mountp));
-               ASSERT((XFS_IS_GQUOTA_ON(tp->t_mountp) ?
+               ASSERT(XFS_IS_OQUOTA_ON(mp));
+               ASSERT((XFS_IS_GQUOTA_ON(mp) ?
                        ip->i_d.di_gid : ip->i_d.di_projid) ==
                                be32_to_cpu(gdqp->q_core.d_id));
                xfs_trans_mod_dquot(tp, gdqp, XFS_TRANS_DQ_ICOUNT, 1);
index a371954cae1b6a86eaf296181b0b7c513a4a3130..495564b8af38020487f4c6edf86b10b3df929039 100644 (file)
@@ -127,8 +127,6 @@ typedef struct xfs_quotainfo {
 } xfs_quotainfo_t;
 
 
-extern xfs_dqtrxops_t  xfs_trans_dquot_ops;
-
 extern void    xfs_trans_mod_dquot(xfs_trans_t *, xfs_dquot_t *, uint, long);
 extern int     xfs_trans_reserve_quota_bydquots(xfs_trans_t *, xfs_mount_t *,
                        xfs_dquot_t *, xfs_dquot_t *, long, long, uint);
@@ -159,17 +157,11 @@ typedef struct xfs_dquot_acct {
 #define XFS_QM_RTBWARNLIMIT    5
 
 extern void            xfs_qm_destroy_quotainfo(xfs_mount_t *);
-extern void            xfs_qm_mount_quotas(xfs_mount_t *);
 extern int             xfs_qm_quotacheck(xfs_mount_t *);
-extern void            xfs_qm_unmount_quotadestroy(xfs_mount_t *);
-extern void            xfs_qm_unmount_quotas(xfs_mount_t *);
 extern int             xfs_qm_write_sb_changes(xfs_mount_t *, __int64_t);
-extern int             xfs_qm_sync(xfs_mount_t *, int);
 
 /* dquot stuff */
 extern boolean_t       xfs_qm_dqalloc_incore(xfs_dquot_t **);
-extern int             xfs_qm_dqattach(xfs_inode_t *, uint);
-extern void            xfs_qm_dqdetach(xfs_inode_t *);
 extern int             xfs_qm_dqpurge_all(xfs_mount_t *, uint);
 extern void            xfs_qm_dqrele_all_inodes(xfs_mount_t *, uint);
 
@@ -183,19 +175,6 @@ extern int         xfs_qm_scall_getqstat(xfs_mount_t *, fs_quota_stat_t *);
 extern int             xfs_qm_scall_quotaon(xfs_mount_t *, uint);
 extern int             xfs_qm_scall_quotaoff(xfs_mount_t *, uint);
 
-/* vop stuff */
-extern int             xfs_qm_vop_dqalloc(xfs_mount_t *, xfs_inode_t *,
-                                       uid_t, gid_t, prid_t, uint,
-                                       xfs_dquot_t **, xfs_dquot_t **);
-extern void            xfs_qm_vop_dqattach_and_dqmod_newinode(
-                                       xfs_trans_t *, xfs_inode_t *,
-                                       xfs_dquot_t *, xfs_dquot_t *);
-extern int             xfs_qm_vop_rename_dqattach(xfs_inode_t **);
-extern xfs_dquot_t *   xfs_qm_vop_chown(xfs_trans_t *, xfs_inode_t *,
-                                       xfs_dquot_t **, xfs_dquot_t *);
-extern int             xfs_qm_vop_chown_reserve(xfs_trans_t *, xfs_inode_t *,
-                                       xfs_dquot_t *, xfs_dquot_t *, uint);
-
 /* list stuff */
 extern void            xfs_qm_freelist_append(xfs_frlist_t *, xfs_dquot_t *);
 extern void            xfs_qm_freelist_unlink(xfs_dquot_t *);
index 63037c689a4b2df95888afe7231ff7915ecfa73a..a5346630dfae05d639a0cee2a24cadbaac057cad 100644 (file)
@@ -42,7 +42,6 @@
 #include "xfs_rtalloc.h"
 #include "xfs_error.h"
 #include "xfs_rw.h"
-#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_qm.h"
@@ -84,7 +83,7 @@ xfs_fill_statvfs_from_dquot(
  * return a statvfs of the project, not the entire filesystem.
  * This makes such trees appear as if they are filesystems in themselves.
  */
-STATIC void
+void
 xfs_qm_statvfs(
        xfs_inode_t             *ip,
        struct kstatfs          *statp)
@@ -92,20 +91,13 @@ xfs_qm_statvfs(
        xfs_mount_t             *mp = ip->i_mount;
        xfs_dquot_t             *dqp;
 
-       if (!(ip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) ||
-           !((mp->m_qflags & (XFS_PQUOTA_ACCT|XFS_OQUOTA_ENFD))) ==
-                             (XFS_PQUOTA_ACCT|XFS_OQUOTA_ENFD))
-               return;
-
        if (!xfs_qm_dqget(mp, NULL, ip->i_d.di_projid, XFS_DQ_PROJ, 0, &dqp)) {
-               xfs_disk_dquot_t        *dp = &dqp->q_core;
-
-               xfs_fill_statvfs_from_dquot(statp, dp);
+               xfs_fill_statvfs_from_dquot(statp, &dqp->q_core);
                xfs_qm_dqput(dqp);
        }
 }
 
-STATIC int
+int
 xfs_qm_newmount(
        xfs_mount_t     *mp,
        uint            *needquotamount,
@@ -114,9 +106,6 @@ xfs_qm_newmount(
        uint            quotaondisk;
        uint            uquotaondisk = 0, gquotaondisk = 0, pquotaondisk = 0;
 
-       *quotaflags = 0;
-       *needquotamount = B_FALSE;
-
        quotaondisk = xfs_sb_version_hasquota(&mp->m_sb) &&
                                (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_ACCT);
 
@@ -179,66 +168,6 @@ xfs_qm_newmount(
        return 0;
 }
 
-STATIC int
-xfs_qm_endmount(
-       xfs_mount_t     *mp,
-       uint            needquotamount,
-       uint            quotaflags)
-{
-       if (needquotamount) {
-               ASSERT(mp->m_qflags == 0);
-               mp->m_qflags = quotaflags;
-               xfs_qm_mount_quotas(mp);
-       }
-
-#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
-       if (! (XFS_IS_QUOTA_ON(mp)))
-               xfs_fs_cmn_err(CE_NOTE, mp, "Disk quotas not turned on");
-       else
-               xfs_fs_cmn_err(CE_NOTE, mp, "Disk quotas turned on");
-#endif
-
-#ifdef QUOTADEBUG
-       if (XFS_IS_QUOTA_ON(mp) && xfs_qm_internalqcheck(mp))
-               cmn_err(CE_WARN, "XFS: mount internalqcheck failed");
-#endif
-
-       return 0;
-}
-
-STATIC void
-xfs_qm_dqrele_null(
-       xfs_dquot_t     *dq)
-{
-       /*
-        * Called from XFS, where we always check first for a NULL dquot.
-        */
-       if (!dq)
-               return;
-       xfs_qm_dqrele(dq);
-}
-
-
-struct xfs_qmops xfs_qmcore_xfs = {
-       .xfs_qminit             = xfs_qm_newmount,
-       .xfs_qmdone             = xfs_qm_unmount_quotadestroy,
-       .xfs_qmmount            = xfs_qm_endmount,
-       .xfs_qmunmount          = xfs_qm_unmount_quotas,
-       .xfs_dqrele             = xfs_qm_dqrele_null,
-       .xfs_dqattach           = xfs_qm_dqattach,
-       .xfs_dqdetach           = xfs_qm_dqdetach,
-       .xfs_dqpurgeall         = xfs_qm_dqpurge_all,
-       .xfs_dqvopalloc         = xfs_qm_vop_dqalloc,
-       .xfs_dqvopcreate        = xfs_qm_vop_dqattach_and_dqmod_newinode,
-       .xfs_dqvoprename        = xfs_qm_vop_rename_dqattach,
-       .xfs_dqvopchown         = xfs_qm_vop_chown,
-       .xfs_dqvopchownresv     = xfs_qm_vop_chown_reserve,
-       .xfs_dqstatvfs          = xfs_qm_statvfs,
-       .xfs_dqsync             = xfs_qm_sync,
-       .xfs_dqtrxops           = &xfs_trans_dquot_ops,
-};
-EXPORT_SYMBOL(xfs_qmcore_xfs);
-
 void __init
 xfs_qm_init(void)
 {
index 709f5f545cf5cfc6eebd259d836b84584b997b2e..21b08c0396a1d8b6e5ab292ebb7db903c97b155c 100644 (file)
@@ -42,7 +42,6 @@
 #include "xfs_rtalloc.h"
 #include "xfs_error.h"
 #include "xfs_rw.h"
-#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_qm.h"
index c7b66f6506ced750585d266ae76e4c61debd2496..4e4276b956e8c5f925490dec8e4dfb320ed071a2 100644 (file)
@@ -45,7 +45,6 @@
 #include "xfs_rtalloc.h"
 #include "xfs_error.h"
 #include "xfs_rw.h"
-#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_utils.h"
@@ -847,105 +846,55 @@ xfs_qm_export_flags(
 }
 
 
-/*
- * Release all the dquots on the inodes in an AG.
- */
-STATIC void
-xfs_qm_dqrele_inodes_ag(
-       xfs_mount_t     *mp,
-       int             ag,
-       uint            flags)
+STATIC int
+xfs_dqrele_inode(
+       struct xfs_inode        *ip,
+       struct xfs_perag        *pag,
+       int                     flags)
 {
-       xfs_inode_t     *ip = NULL;
-       xfs_perag_t     *pag = &mp->m_perag[ag];
-       int             first_index = 0;
-       int             nr_found;
-
-       do {
-               /*
-                * use a gang lookup to find the next inode in the tree
-                * as the tree is sparse and a gang lookup walks to find
-                * the number of objects requested.
-                */
-               read_lock(&pag->pag_ici_lock);
-               nr_found = radix_tree_gang_lookup(&pag->pag_ici_root,
-                               (void**)&ip, first_index, 1);
-
-               if (!nr_found) {
-                       read_unlock(&pag->pag_ici_lock);
-                       break;
-               }
-
-               /*
-                * Update the index for the next lookup. Catch overflows
-                * into the next AG range which can occur if we have inodes
-                * in the last block of the AG and we are currently
-                * pointing to the last inode.
-                */
-               first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1);
-               if (first_index < XFS_INO_TO_AGINO(mp, ip->i_ino)) {
-                       read_unlock(&pag->pag_ici_lock);
-                       break;
-               }
-
-               /* skip quota inodes */
-               if (ip == XFS_QI_UQIP(mp) || ip == XFS_QI_GQIP(mp)) {
-                       ASSERT(ip->i_udquot == NULL);
-                       ASSERT(ip->i_gdquot == NULL);
-                       read_unlock(&pag->pag_ici_lock);
-                       continue;
-               }
+       int                     error;
 
-               /*
-                * If we can't get a reference on the inode, it must be
-                * in reclaim. Leave it for the reclaim code to flush.
-                */
-               if (!igrab(VFS_I(ip))) {
-                       read_unlock(&pag->pag_ici_lock);
-                       continue;
-               }
+       /* skip quota inodes */
+       if (ip == XFS_QI_UQIP(ip->i_mount) || ip == XFS_QI_GQIP(ip->i_mount)) {
+               ASSERT(ip->i_udquot == NULL);
+               ASSERT(ip->i_gdquot == NULL);
                read_unlock(&pag->pag_ici_lock);
+               return 0;
+       }
 
-               /* avoid new inodes though we shouldn't find any here */
-               if (xfs_iflags_test(ip, XFS_INEW)) {
-                       IRELE(ip);
-                       continue;
-               }
+       error = xfs_sync_inode_valid(ip, pag);
+       if (error)
+               return error;
 
-               xfs_ilock(ip, XFS_ILOCK_EXCL);
-               if ((flags & XFS_UQUOTA_ACCT) && ip->i_udquot) {
-                       xfs_qm_dqrele(ip->i_udquot);
-                       ip->i_udquot = NULL;
-               }
-               if (flags & (XFS_PQUOTA_ACCT|XFS_GQUOTA_ACCT) &&
-                   ip->i_gdquot) {
-                       xfs_qm_dqrele(ip->i_gdquot);
-                       ip->i_gdquot = NULL;
-               }
-               xfs_iput(ip, XFS_ILOCK_EXCL);
+       xfs_ilock(ip, XFS_ILOCK_EXCL);
+       if ((flags & XFS_UQUOTA_ACCT) && ip->i_udquot) {
+               xfs_qm_dqrele(ip->i_udquot);
+               ip->i_udquot = NULL;
+       }
+       if (flags & (XFS_PQUOTA_ACCT|XFS_GQUOTA_ACCT) && ip->i_gdquot) {
+               xfs_qm_dqrele(ip->i_gdquot);
+               ip->i_gdquot = NULL;
+       }
+       xfs_iput(ip, XFS_ILOCK_EXCL);
+       IRELE(ip);
 
-       } while (nr_found);
+       return 0;
 }
 
+
 /*
  * Go thru all the inodes in the file system, releasing their dquots.
+ *
  * Note that the mount structure gets modified to indicate that quotas are off
- * AFTER this, in the case of quotaoff. This also gets called from
- * xfs_rootumount.
+ * AFTER this, in the case of quotaoff.
  */
 void
 xfs_qm_dqrele_all_inodes(
        struct xfs_mount *mp,
        uint             flags)
 {
-       int             i;
-
        ASSERT(mp->m_quotainfo);
-       for (i = 0; i < mp->m_sb.sb_agcount; i++) {
-               if (!mp->m_perag[i].pag_ici_init)
-                       continue;
-               xfs_qm_dqrele_inodes_ag(mp, i, flags);
-       }
+       xfs_inode_ag_iterator(mp, xfs_dqrele_inode, flags, XFS_ICI_NO_TAG);
 }
 
 /*------------------------------------------------------------------------*/
index 447173bcf96de899b7369e66e232363fb5cd5eae..97ac9640be989226a71035489cf677533b4830c1 100644 (file)
@@ -42,7 +42,6 @@
 #include "xfs_rtalloc.h"
 #include "xfs_error.h"
 #include "xfs_rw.h"
-#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_trans_priv.h"
@@ -111,7 +110,7 @@ xfs_trans_log_dquot(
  * Carry forward whatever is left of the quota blk reservation to
  * the spanky new transaction
  */
-STATIC void
+void
 xfs_trans_dup_dqinfo(
        xfs_trans_t     *otp,
        xfs_trans_t     *ntp)
@@ -167,19 +166,17 @@ xfs_trans_dup_dqinfo(
 /*
  * Wrap around mod_dquot to account for both user and group quotas.
  */
-STATIC void
+void
 xfs_trans_mod_dquot_byino(
        xfs_trans_t     *tp,
        xfs_inode_t     *ip,
        uint            field,
        long            delta)
 {
-       xfs_mount_t     *mp;
-
-       ASSERT(tp);
-       mp = tp->t_mountp;
+       xfs_mount_t     *mp = tp->t_mountp;
 
-       if (!XFS_IS_QUOTA_ON(mp) ||
+       if (!XFS_IS_QUOTA_RUNNING(mp) ||
+           !XFS_IS_QUOTA_ON(mp) ||
            ip->i_ino == mp->m_sb.sb_uquotino ||
            ip->i_ino == mp->m_sb.sb_gquotino)
                return;
@@ -229,6 +226,7 @@ xfs_trans_mod_dquot(
        xfs_dqtrx_t     *qtrx;
 
        ASSERT(tp);
+       ASSERT(XFS_IS_QUOTA_RUNNING(tp->t_mountp));
        qtrx = NULL;
 
        if (tp->t_dqinfo == NULL)
@@ -346,7 +344,7 @@ xfs_trans_dqlockedjoin(
  * Unreserve just the reservations done by this transaction.
  * dquot is still left locked at exit.
  */
-STATIC void
+void
 xfs_trans_apply_dquot_deltas(
        xfs_trans_t             *tp)
 {
@@ -357,7 +355,7 @@ xfs_trans_apply_dquot_deltas(
        long                    totalbdelta;
        long                    totalrtbdelta;
 
-       if (! (tp->t_flags & XFS_TRANS_DQ_DIRTY))
+       if (!(tp->t_flags & XFS_TRANS_DQ_DIRTY))
                return;
 
        ASSERT(tp->t_dqinfo);
@@ -531,7 +529,7 @@ xfs_trans_apply_dquot_deltas(
  * we simply throw those away, since that's the expected behavior
  * when a transaction is curtailed without a commit.
  */
-STATIC void
+void
 xfs_trans_unreserve_and_mod_dquots(
        xfs_trans_t             *tp)
 {
@@ -768,7 +766,7 @@ xfs_trans_reserve_quota_bydquots(
 {
        int             resvd = 0, error;
 
-       if (!XFS_IS_QUOTA_ON(mp))
+       if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp))
                return 0;
 
        if (tp && tp->t_dqinfo == NULL)
@@ -811,18 +809,17 @@ xfs_trans_reserve_quota_bydquots(
  * This doesn't change the actual usage, just the reservation.
  * The inode sent in is locked.
  */
-STATIC int
+int
 xfs_trans_reserve_quota_nblks(
-       xfs_trans_t     *tp,
-       xfs_mount_t     *mp,
-       xfs_inode_t     *ip,
-       long            nblks,
-       long            ninos,
-       uint            flags)
+       struct xfs_trans        *tp,
+       struct xfs_inode        *ip,
+       long                    nblks,
+       long                    ninos,
+       uint                    flags)
 {
-       int             error;
+       struct xfs_mount        *mp = ip->i_mount;
 
-       if (!XFS_IS_QUOTA_ON(mp))
+       if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp))
                return 0;
        if (XFS_IS_PQUOTA_ON(mp))
                flags |= XFS_QMOPT_ENOSPC;
@@ -831,7 +828,6 @@ xfs_trans_reserve_quota_nblks(
        ASSERT(ip->i_ino != mp->m_sb.sb_gquotino);
 
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
-       ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount));
        ASSERT((flags & ~(XFS_QMOPT_FORCE_RES | XFS_QMOPT_ENOSPC)) ==
                                XFS_TRANS_DQ_RES_RTBLKS ||
               (flags & ~(XFS_QMOPT_FORCE_RES | XFS_QMOPT_ENOSPC)) ==
@@ -840,11 +836,9 @@ xfs_trans_reserve_quota_nblks(
        /*
         * Reserve nblks against these dquots, with trans as the mediator.
         */
-       error = xfs_trans_reserve_quota_bydquots(tp, mp,
-                                                ip->i_udquot, ip->i_gdquot,
-                                                nblks, ninos,
-                                                flags);
-       return error;
+       return xfs_trans_reserve_quota_bydquots(tp, mp,
+                                               ip->i_udquot, ip->i_gdquot,
+                                               nblks, ninos, flags);
 }
 
 /*
@@ -895,25 +889,15 @@ STATIC void
 xfs_trans_alloc_dqinfo(
        xfs_trans_t     *tp)
 {
-       (tp)->t_dqinfo = kmem_zone_zalloc(xfs_Gqm->qm_dqtrxzone, KM_SLEEP);
+       tp->t_dqinfo = kmem_zone_zalloc(xfs_Gqm->qm_dqtrxzone, KM_SLEEP);
 }
 
-STATIC void
+void
 xfs_trans_free_dqinfo(
        xfs_trans_t     *tp)
 {
        if (!tp->t_dqinfo)
                return;
-       kmem_zone_free(xfs_Gqm->qm_dqtrxzone, (tp)->t_dqinfo);
-       (tp)->t_dqinfo = NULL;
+       kmem_zone_free(xfs_Gqm->qm_dqtrxzone, tp->t_dqinfo);
+       tp->t_dqinfo = NULL;
 }
-
-xfs_dqtrxops_t xfs_trans_dquot_ops = {
-       .qo_dup_dqinfo                  = xfs_trans_dup_dqinfo,
-       .qo_free_dqinfo                 = xfs_trans_free_dqinfo,
-       .qo_mod_dquot_byino             = xfs_trans_mod_dquot_byino,
-       .qo_apply_dquot_deltas          = xfs_trans_apply_dquot_deltas,
-       .qo_reserve_quota_nblks         = xfs_trans_reserve_quota_nblks,
-       .qo_reserve_quota_bydquots      = xfs_trans_reserve_quota_bydquots,
-       .qo_unreserve_and_mod_dquots    = xfs_trans_unreserve_and_mod_dquots,
-};
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
deleted file mode 100644 (file)
index a8cdd73..0000000
+++ /dev/null
@@ -1,874 +0,0 @@
-/*
- * Copyright (c) 2001-2002,2005 Silicon Graphics, 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.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT 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 the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-#include "xfs.h"
-#include "xfs_fs.h"
-#include "xfs_types.h"
-#include "xfs_bit.h"
-#include "xfs_inum.h"
-#include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
-#include "xfs_dinode.h"
-#include "xfs_inode.h"
-#include "xfs_btree.h"
-#include "xfs_acl.h"
-#include "xfs_attr.h"
-#include "xfs_vnodeops.h"
-
-#include <linux/capability.h>
-#include <linux/posix_acl_xattr.h>
-
-STATIC int     xfs_acl_setmode(struct inode *, xfs_acl_t *, int *);
-STATIC void     xfs_acl_filter_mode(mode_t, xfs_acl_t *);
-STATIC void    xfs_acl_get_endian(xfs_acl_t *);
-STATIC int     xfs_acl_access(uid_t, gid_t, xfs_acl_t *, mode_t, cred_t *);
-STATIC int     xfs_acl_invalid(xfs_acl_t *);
-STATIC void    xfs_acl_sync_mode(mode_t, xfs_acl_t *);
-STATIC void    xfs_acl_get_attr(struct inode *, xfs_acl_t *, int, int, int *);
-STATIC void    xfs_acl_set_attr(struct inode *, xfs_acl_t *, int, int *);
-STATIC int     xfs_acl_allow_set(struct inode *, int);
-
-kmem_zone_t *xfs_acl_zone;
-
-
-/*
- * Test for existence of access ACL attribute as efficiently as possible.
- */
-int
-xfs_acl_vhasacl_access(
-       struct inode    *vp)
-{
-       int             error;
-
-       xfs_acl_get_attr(vp, NULL, _ACL_TYPE_ACCESS, ATTR_KERNOVAL, &error);
-       return (error == 0);
-}
-
-/*
- * Test for existence of default ACL attribute as efficiently as possible.
- */
-int
-xfs_acl_vhasacl_default(
-       struct inode    *vp)
-{
-       int             error;
-
-       if (!S_ISDIR(vp->i_mode))
-               return 0;
-       xfs_acl_get_attr(vp, NULL, _ACL_TYPE_DEFAULT, ATTR_KERNOVAL, &error);
-       return (error == 0);
-}
-
-/*
- * Convert from extended attribute representation to in-memory for XFS.
- */
-STATIC int
-posix_acl_xattr_to_xfs(
-       posix_acl_xattr_header  *src,
-       size_t                  size,
-       xfs_acl_t               *dest)
-{
-       posix_acl_xattr_entry   *src_entry;
-       xfs_acl_entry_t         *dest_entry;
-       int                     n;
-
-       if (!src || !dest)
-               return EINVAL;
-
-       if (size < sizeof(posix_acl_xattr_header))
-               return EINVAL;
-
-       if (src->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
-               return EOPNOTSUPP;
-
-       memset(dest, 0, sizeof(xfs_acl_t));
-       dest->acl_cnt = posix_acl_xattr_count(size);
-       if (dest->acl_cnt < 0 || dest->acl_cnt > XFS_ACL_MAX_ENTRIES)
-               return EINVAL;
-
-       /*
-        * acl_set_file(3) may request that we set default ACLs with
-        * zero length -- defend (gracefully) against that here.
-        */
-       if (!dest->acl_cnt)
-               return 0;
-
-       src_entry = (posix_acl_xattr_entry *)((char *)src + sizeof(*src));
-       dest_entry = &dest->acl_entry[0];
-
-       for (n = 0; n < dest->acl_cnt; n++, src_entry++, dest_entry++) {
-               dest_entry->ae_perm = le16_to_cpu(src_entry->e_perm);
-               if (_ACL_PERM_INVALID(dest_entry->ae_perm))
-                       return EINVAL;
-               dest_entry->ae_tag  = le16_to_cpu(src_entry->e_tag);
-               switch(dest_entry->ae_tag) {
-               case ACL_USER:
-               case ACL_GROUP:
-                       dest_entry->ae_id = le32_to_cpu(src_entry->e_id);
-                       break;
-               case ACL_USER_OBJ:
-               case ACL_GROUP_OBJ:
-               case ACL_MASK:
-               case ACL_OTHER:
-                       dest_entry->ae_id = ACL_UNDEFINED_ID;
-                       break;
-               default:
-                       return EINVAL;
-               }
-       }
-       if (xfs_acl_invalid(dest))
-               return EINVAL;
-
-       return 0;
-}
-
-/*
- * Comparison function called from xfs_sort().
- * Primary key is ae_tag, secondary key is ae_id.
- */
-STATIC int
-xfs_acl_entry_compare(
-       const void      *va,
-       const void      *vb)
-{
-       xfs_acl_entry_t *a = (xfs_acl_entry_t *)va,
-                       *b = (xfs_acl_entry_t *)vb;
-
-       if (a->ae_tag == b->ae_tag)
-               return (a->ae_id - b->ae_id);
-       return (a->ae_tag - b->ae_tag);
-}
-
-/*
- * Convert from in-memory XFS to extended attribute representation.
- */
-STATIC int
-posix_acl_xfs_to_xattr(
-       xfs_acl_t               *src,
-       posix_acl_xattr_header  *dest,
-       size_t                  size)
-{
-       int                     n;
-       size_t                  new_size = posix_acl_xattr_size(src->acl_cnt);
-       posix_acl_xattr_entry   *dest_entry;
-       xfs_acl_entry_t         *src_entry;
-
-       if (size < new_size)
-               return -ERANGE;
-
-       /* Need to sort src XFS ACL by <ae_tag,ae_id> */
-       xfs_sort(src->acl_entry, src->acl_cnt, sizeof(src->acl_entry[0]),
-                xfs_acl_entry_compare);
-
-       dest->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
-       dest_entry = &dest->a_entries[0];
-       src_entry = &src->acl_entry[0];
-       for (n = 0; n < src->acl_cnt; n++, dest_entry++, src_entry++) {
-               dest_entry->e_perm = cpu_to_le16(src_entry->ae_perm);
-               if (_ACL_PERM_INVALID(src_entry->ae_perm))
-                       return -EINVAL;
-               dest_entry->e_tag  = cpu_to_le16(src_entry->ae_tag);
-               switch (src_entry->ae_tag) {
-               case ACL_USER:
-               case ACL_GROUP:
-                       dest_entry->e_id = cpu_to_le32(src_entry->ae_id);
-                               break;
-               case ACL_USER_OBJ:
-               case ACL_GROUP_OBJ:
-               case ACL_MASK:
-               case ACL_OTHER:
-                       dest_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID);
-                       break;
-               default:
-                       return -EINVAL;
-               }
-       }
-       return new_size;
-}
-
-int
-xfs_acl_vget(
-       struct inode    *vp,
-       void            *acl,
-       size_t          size,
-       int             kind)
-{
-       int                     error;
-       xfs_acl_t               *xfs_acl = NULL;
-       posix_acl_xattr_header  *ext_acl = acl;
-       int                     flags = 0;
-
-       if(size) {
-               if (!(_ACL_ALLOC(xfs_acl))) {
-                       error = ENOMEM;
-                       goto out;
-               }
-               memset(xfs_acl, 0, sizeof(xfs_acl_t));
-       } else
-               flags = ATTR_KERNOVAL;
-
-       xfs_acl_get_attr(vp, xfs_acl, kind, flags, &error);
-       if (error)
-               goto out;
-
-       if (!size) {
-               error = -posix_acl_xattr_size(XFS_ACL_MAX_ENTRIES);
-       } else {
-               if (xfs_acl_invalid(xfs_acl)) {
-                       error = EINVAL;
-                       goto out;
-               }
-               if (kind == _ACL_TYPE_ACCESS)
-                       xfs_acl_sync_mode(XFS_I(vp)->i_d.di_mode, xfs_acl);
-               error = -posix_acl_xfs_to_xattr(xfs_acl, ext_acl, size);
-       }
-out:
-       if(xfs_acl)
-               _ACL_FREE(xfs_acl);
-       return -error;
-}
-
-int
-xfs_acl_vremove(
-       struct inode    *vp,
-       int             kind)
-{
-       int             error;
-
-       error = xfs_acl_allow_set(vp, kind);
-       if (!error) {
-               error = xfs_attr_remove(XFS_I(vp),
-                                               kind == _ACL_TYPE_DEFAULT?
-                                               SGI_ACL_DEFAULT: SGI_ACL_FILE,
-                                               ATTR_ROOT);
-               if (error == ENOATTR)
-                       error = 0;      /* 'scool */
-       }
-       return -error;
-}
-
-int
-xfs_acl_vset(
-       struct inode            *vp,
-       void                    *acl,
-       size_t                  size,
-       int                     kind)
-{
-       posix_acl_xattr_header  *ext_acl = acl;
-       xfs_acl_t               *xfs_acl;
-       int                     error;
-       int                     basicperms = 0; /* more than std unix perms? */
-
-       if (!acl)
-               return -EINVAL;
-
-       if (!(_ACL_ALLOC(xfs_acl)))
-               return -ENOMEM;
-
-       error = posix_acl_xattr_to_xfs(ext_acl, size, xfs_acl);
-       if (error) {
-               _ACL_FREE(xfs_acl);
-               return -error;
-       }
-       if (!xfs_acl->acl_cnt) {
-               _ACL_FREE(xfs_acl);
-               return 0;
-       }
-
-       error = xfs_acl_allow_set(vp, kind);
-
-       /* Incoming ACL exists, set file mode based on its value */
-       if (!error && kind == _ACL_TYPE_ACCESS)
-               error = xfs_acl_setmode(vp, xfs_acl, &basicperms);
-
-       if (error)
-               goto out;
-
-       /*
-        * If we have more than std unix permissions, set up the actual attr.
-        * Otherwise, delete any existing attr.  This prevents us from
-        * having actual attrs for permissions that can be stored in the
-        * standard permission bits.
-        */
-       if (!basicperms) {
-               xfs_acl_set_attr(vp, xfs_acl, kind, &error);
-       } else {
-               error = -xfs_acl_vremove(vp, _ACL_TYPE_ACCESS);
-       }
-
-out:
-       _ACL_FREE(xfs_acl);
-       return -error;
-}
-
-int
-xfs_acl_iaccess(
-       xfs_inode_t     *ip,
-       mode_t          mode,
-       cred_t          *cr)
-{
-       xfs_acl_t       *acl;
-       int             rval;
-       struct xfs_name acl_name = {SGI_ACL_FILE, SGI_ACL_FILE_SIZE};
-
-       if (!(_ACL_ALLOC(acl)))
-               return -1;
-
-       /* If the file has no ACL return -1. */
-       rval = sizeof(xfs_acl_t);
-       if (xfs_attr_fetch(ip, &acl_name, (char *)acl, &rval, ATTR_ROOT)) {
-               _ACL_FREE(acl);
-               return -1;
-       }
-       xfs_acl_get_endian(acl);
-
-       /* If the file has an empty ACL return -1. */
-       if (acl->acl_cnt == XFS_ACL_NOT_PRESENT) {
-               _ACL_FREE(acl);
-               return -1;
-       }
-
-       /* Synchronize ACL with mode bits */
-       xfs_acl_sync_mode(ip->i_d.di_mode, acl);
-
-       rval = xfs_acl_access(ip->i_d.di_uid, ip->i_d.di_gid, acl, mode, cr);
-       _ACL_FREE(acl);
-       return rval;
-}
-
-STATIC int
-xfs_acl_allow_set(
-       struct inode    *vp,
-       int             kind)
-{
-       if (vp->i_flags & (S_IMMUTABLE|S_APPEND))
-               return EPERM;
-       if (kind == _ACL_TYPE_DEFAULT && !S_ISDIR(vp->i_mode))
-               return ENOTDIR;
-       if (vp->i_sb->s_flags & MS_RDONLY)
-               return EROFS;
-       if (XFS_I(vp)->i_d.di_uid != current_fsuid() && !capable(CAP_FOWNER))
-               return EPERM;
-       return 0;
-}
-
-/*
- * Note: cr is only used here for the capability check if the ACL test fails.
- *       It is not used to find out the credentials uid or groups etc, as was
- *       done in IRIX. It is assumed that the uid and groups for the current
- *       thread are taken from "current" instead of the cr parameter.
- */
-STATIC int
-xfs_acl_access(
-       uid_t           fuid,
-       gid_t           fgid,
-       xfs_acl_t       *fap,
-       mode_t          md,
-       cred_t          *cr)
-{
-       xfs_acl_entry_t matched;
-       int             i, allows;
-       int             maskallows = -1;        /* true, but not 1, either */
-       int             seen_userobj = 0;
-
-       matched.ae_tag = 0;     /* Invalid type */
-       matched.ae_perm = 0;
-
-       for (i = 0; i < fap->acl_cnt; i++) {
-               /*
-                * Break out if we've got a user_obj entry or
-                * a user entry and the mask (and have processed USER_OBJ)
-                */
-               if (matched.ae_tag == ACL_USER_OBJ)
-                       break;
-               if (matched.ae_tag == ACL_USER) {
-                       if (maskallows != -1 && seen_userobj)
-                               break;
-                       if (fap->acl_entry[i].ae_tag != ACL_MASK &&
-                           fap->acl_entry[i].ae_tag != ACL_USER_OBJ)
-                               continue;
-               }
-               /* True if this entry allows the requested access */
-               allows = ((fap->acl_entry[i].ae_perm & md) == md);
-
-               switch (fap->acl_entry[i].ae_tag) {
-               case ACL_USER_OBJ:
-                       seen_userobj = 1;
-                       if (fuid != current_fsuid())
-                               continue;
-                       matched.ae_tag = ACL_USER_OBJ;
-                       matched.ae_perm = allows;
-                       break;
-               case ACL_USER:
-                       if (fap->acl_entry[i].ae_id != current_fsuid())
-                               continue;
-                       matched.ae_tag = ACL_USER;
-                       matched.ae_perm = allows;
-                       break;
-               case ACL_GROUP_OBJ:
-                       if ((matched.ae_tag == ACL_GROUP_OBJ ||
-                           matched.ae_tag == ACL_GROUP) && !allows)
-                               continue;
-                       if (!in_group_p(fgid))
-                               continue;
-                       matched.ae_tag = ACL_GROUP_OBJ;
-                       matched.ae_perm = allows;
-                       break;
-               case ACL_GROUP:
-                       if ((matched.ae_tag == ACL_GROUP_OBJ ||
-                           matched.ae_tag == ACL_GROUP) && !allows)
-                               continue;
-                       if (!in_group_p(fap->acl_entry[i].ae_id))
-                               continue;
-                       matched.ae_tag = ACL_GROUP;
-                       matched.ae_perm = allows;
-                       break;
-               case ACL_MASK:
-                       maskallows = allows;
-                       break;
-               case ACL_OTHER:
-                       if (matched.ae_tag != 0)
-                               continue;
-                       matched.ae_tag = ACL_OTHER;
-                       matched.ae_perm = allows;
-                       break;
-               }
-       }
-       /*
-        * First possibility is that no matched entry allows access.
-        * The capability to override DAC may exist, so check for it.
-        */
-       switch (matched.ae_tag) {
-       case ACL_OTHER:
-       case ACL_USER_OBJ:
-               if (matched.ae_perm)
-                       return 0;
-               break;
-       case ACL_USER:
-       case ACL_GROUP_OBJ:
-       case ACL_GROUP:
-               if (maskallows && matched.ae_perm)
-                       return 0;
-               break;
-       case 0:
-               break;
-       }
-
-       /* EACCES tells generic_permission to check for capability overrides */
-       return EACCES;
-}
-
-/*
- * ACL validity checker.
- *   This acl validation routine checks each ACL entry read in makes sense.
- */
-STATIC int
-xfs_acl_invalid(
-       xfs_acl_t       *aclp)
-{
-       xfs_acl_entry_t *entry, *e;
-       int             user = 0, group = 0, other = 0, mask = 0;
-       int             mask_required = 0;
-       int             i, j;
-
-       if (!aclp)
-               goto acl_invalid;
-
-       if (aclp->acl_cnt > XFS_ACL_MAX_ENTRIES)
-               goto acl_invalid;
-
-       for (i = 0; i < aclp->acl_cnt; i++) {
-               entry = &aclp->acl_entry[i];
-               switch (entry->ae_tag) {
-               case ACL_USER_OBJ:
-                       if (user++)
-                               goto acl_invalid;
-                       break;
-               case ACL_GROUP_OBJ:
-                       if (group++)
-                               goto acl_invalid;
-                       break;
-               case ACL_OTHER:
-                       if (other++)
-                               goto acl_invalid;
-                       break;
-               case ACL_USER:
-               case ACL_GROUP:
-                       for (j = i + 1; j < aclp->acl_cnt; j++) {
-                               e = &aclp->acl_entry[j];
-                               if (e->ae_id == entry->ae_id &&
-                                   e->ae_tag == entry->ae_tag)
-                                       goto acl_invalid;
-                       }
-                       mask_required++;
-                       break;
-               case ACL_MASK:
-                       if (mask++)
-                               goto acl_invalid;
-                       break;
-               default:
-                       goto acl_invalid;
-               }
-       }
-       if (!user || !group || !other || (mask_required && !mask))
-               goto acl_invalid;
-       else
-               return 0;
-acl_invalid:
-       return EINVAL;
-}
-
-/*
- * Do ACL endian conversion.
- */
-STATIC void
-xfs_acl_get_endian(
-       xfs_acl_t       *aclp)
-{
-       xfs_acl_entry_t *ace, *end;
-
-       INT_SET(aclp->acl_cnt, ARCH_CONVERT, aclp->acl_cnt);
-       end = &aclp->acl_entry[0]+aclp->acl_cnt;
-       for (ace = &aclp->acl_entry[0]; ace < end; ace++) {
-               INT_SET(ace->ae_tag, ARCH_CONVERT, ace->ae_tag);
-               INT_SET(ace->ae_id, ARCH_CONVERT, ace->ae_id);
-               INT_SET(ace->ae_perm, ARCH_CONVERT, ace->ae_perm);
-       }
-}
-
-/*
- * Get the ACL from the EA and do endian conversion.
- */
-STATIC void
-xfs_acl_get_attr(
-       struct inode    *vp,
-       xfs_acl_t       *aclp,
-       int             kind,
-       int             flags,
-       int             *error)
-{
-       int             len = sizeof(xfs_acl_t);
-
-       ASSERT((flags & ATTR_KERNOVAL) ? (aclp == NULL) : 1);
-       flags |= ATTR_ROOT;
-       *error = xfs_attr_get(XFS_I(vp),
-                                       kind == _ACL_TYPE_ACCESS ?
-                                       SGI_ACL_FILE : SGI_ACL_DEFAULT,
-                                       (char *)aclp, &len, flags);
-       if (*error || (flags & ATTR_KERNOVAL))
-               return;
-       xfs_acl_get_endian(aclp);
-}
-
-/*
- * Set the EA with the ACL and do endian conversion.
- */
-STATIC void
-xfs_acl_set_attr(
-       struct inode    *vp,
-       xfs_acl_t       *aclp,
-       int             kind,
-       int             *error)
-{
-       xfs_acl_entry_t *ace, *newace, *end;
-       xfs_acl_t       *newacl;
-       int             len;
-
-       if (!(_ACL_ALLOC(newacl))) {
-               *error = ENOMEM;
-               return;
-       }
-
-       len = sizeof(xfs_acl_t) -
-             (sizeof(xfs_acl_entry_t) * (XFS_ACL_MAX_ENTRIES - aclp->acl_cnt));
-       end = &aclp->acl_entry[0]+aclp->acl_cnt;
-       for (ace = &aclp->acl_entry[0], newace = &newacl->acl_entry[0];
-            ace < end;
-            ace++, newace++) {
-               INT_SET(newace->ae_tag, ARCH_CONVERT, ace->ae_tag);
-               INT_SET(newace->ae_id, ARCH_CONVERT, ace->ae_id);
-               INT_SET(newace->ae_perm, ARCH_CONVERT, ace->ae_perm);
-       }
-       INT_SET(newacl->acl_cnt, ARCH_CONVERT, aclp->acl_cnt);
-       *error = xfs_attr_set(XFS_I(vp),
-                               kind == _ACL_TYPE_ACCESS ?
-                               SGI_ACL_FILE: SGI_ACL_DEFAULT,
-                               (char *)newacl, len, ATTR_ROOT);
-       _ACL_FREE(newacl);
-}
-
-int
-xfs_acl_vtoacl(
-       struct inode    *vp,
-       xfs_acl_t       *access_acl,
-       xfs_acl_t       *default_acl)
-{
-       int             error = 0;
-
-       if (access_acl) {
-               /*
-                * Get the Access ACL and the mode.  If either cannot
-                * be obtained for some reason, invalidate the access ACL.
-                */
-               xfs_acl_get_attr(vp, access_acl, _ACL_TYPE_ACCESS, 0, &error);
-               if (error)
-                       access_acl->acl_cnt = XFS_ACL_NOT_PRESENT;
-               else /* We have a good ACL and the file mode, synchronize. */
-                       xfs_acl_sync_mode(XFS_I(vp)->i_d.di_mode, access_acl);
-       }
-
-       if (default_acl) {
-               xfs_acl_get_attr(vp, default_acl, _ACL_TYPE_DEFAULT, 0, &error);
-               if (error)
-                       default_acl->acl_cnt = XFS_ACL_NOT_PRESENT;
-       }
-       return error;
-}
-
-/*
- * This function retrieves the parent directory's acl, processes it
- * and lets the child inherit the acl(s) that it should.
- */
-int
-xfs_acl_inherit(
-       struct inode    *vp,
-       mode_t          mode,
-       xfs_acl_t       *pdaclp)
-{
-       xfs_acl_t       *cacl;
-       int             error = 0;
-       int             basicperms = 0;
-
-       /*
-        * If the parent does not have a default ACL, or it's an
-        * invalid ACL, we're done.
-        */
-       if (!vp)
-               return 0;
-       if (!pdaclp || xfs_acl_invalid(pdaclp))
-               return 0;
-
-       /*
-        * Copy the default ACL of the containing directory to
-        * the access ACL of the new file and use the mode that
-        * was passed in to set up the correct initial values for
-        * the u::,g::[m::], and o:: entries.  This is what makes
-        * umask() "work" with ACL's.
-        */
-
-       if (!(_ACL_ALLOC(cacl)))
-               return ENOMEM;
-
-       memcpy(cacl, pdaclp, sizeof(xfs_acl_t));
-       xfs_acl_filter_mode(mode, cacl);
-       error = xfs_acl_setmode(vp, cacl, &basicperms);
-       if (error)
-               goto out_error;
-
-       /*
-        * Set the Default and Access ACL on the file.  The mode is already
-        * set on the file, so we don't need to worry about that.
-        *
-        * If the new file is a directory, its default ACL is a copy of
-        * the containing directory's default ACL.
-        */
-       if (S_ISDIR(vp->i_mode))
-               xfs_acl_set_attr(vp, pdaclp, _ACL_TYPE_DEFAULT, &error);
-       if (!error && !basicperms)
-               xfs_acl_set_attr(vp, cacl, _ACL_TYPE_ACCESS, &error);
-out_error:
-       _ACL_FREE(cacl);
-       return error;
-}
-
-/*
- * Set up the correct mode on the file based on the supplied ACL.  This
- * makes sure that the mode on the file reflects the state of the
- * u::,g::[m::], and o:: entries in the ACL.  Since the mode is where
- * the ACL is going to get the permissions for these entries, we must
- * synchronize the mode whenever we set the ACL on a file.
- */
-STATIC int
-xfs_acl_setmode(
-       struct inode    *vp,
-       xfs_acl_t       *acl,
-       int             *basicperms)
-{
-       struct iattr    iattr;
-       xfs_acl_entry_t *ap;
-       xfs_acl_entry_t *gap = NULL;
-       int             i, nomask = 1;
-
-       *basicperms = 1;
-
-       if (acl->acl_cnt == XFS_ACL_NOT_PRESENT)
-               return 0;
-
-       /*
-        * Copy the u::, g::, o::, and m:: bits from the ACL into the
-        * mode.  The m:: bits take precedence over the g:: bits.
-        */
-       iattr.ia_valid = ATTR_MODE;
-       iattr.ia_mode = XFS_I(vp)->i_d.di_mode;
-       iattr.ia_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO);
-       ap = acl->acl_entry;
-       for (i = 0; i < acl->acl_cnt; ++i) {
-               switch (ap->ae_tag) {
-               case ACL_USER_OBJ:
-                       iattr.ia_mode |= ap->ae_perm << 6;
-                       break;
-               case ACL_GROUP_OBJ:
-                       gap = ap;
-                       break;
-               case ACL_MASK:  /* more than just standard modes */
-                       nomask = 0;
-                       iattr.ia_mode |= ap->ae_perm << 3;
-                       *basicperms = 0;
-                       break;
-               case ACL_OTHER:
-                       iattr.ia_mode |= ap->ae_perm;
-                       break;
-               default:        /* more than just standard modes */
-                       *basicperms = 0;
-                       break;
-               }
-               ap++;
-       }
-
-       /* Set the group bits from ACL_GROUP_OBJ if there's no ACL_MASK */
-       if (gap && nomask)
-               iattr.ia_mode |= gap->ae_perm << 3;
-
-       return xfs_setattr(XFS_I(vp), &iattr, 0);
-}
-
-/*
- * The permissions for the special ACL entries (u::, g::[m::], o::) are
- * actually stored in the file mode (if there is both a group and a mask,
- * the group is stored in the ACL entry and the mask is stored on the file).
- * This allows the mode to remain automatically in sync with the ACL without
- * the need for a call-back to the ACL system at every point where the mode
- * could change.  This function takes the permissions from the specified mode
- * and places it in the supplied ACL.
- *
- * This implementation draws its validity from the fact that, when the ACL
- * was assigned, the mode was copied from the ACL.
- * If the mode did not change, therefore, the mode remains exactly what was
- * taken from the special ACL entries at assignment.
- * If a subsequent chmod() was done, the POSIX spec says that the change in
- * mode must cause an update to the ACL seen at user level and used for
- * access checks.  Before and after a mode change, therefore, the file mode
- * most accurately reflects what the special ACL entries should permit/deny.
- *
- * CAVEAT: If someone sets the SGI_ACL_FILE attribute directly,
- *         the existing mode bits will override whatever is in the
- *         ACL. Similarly, if there is a pre-existing ACL that was
- *         never in sync with its mode (owing to a bug in 6.5 and
- *         before), it will now magically (or mystically) be
- *         synchronized.  This could cause slight astonishment, but
- *         it is better than inconsistent permissions.
- *
- * The supplied ACL is a template that may contain any combination
- * of special entries.  These are treated as place holders when we fill
- * out the ACL.  This routine does not add or remove special entries, it
- * simply unites each special entry with its associated set of permissions.
- */
-STATIC void
-xfs_acl_sync_mode(
-       mode_t          mode,
-       xfs_acl_t       *acl)
-{
-       int             i, nomask = 1;
-       xfs_acl_entry_t *ap;
-       xfs_acl_entry_t *gap = NULL;
-
-       /*
-        * Set ACL entries. POSIX1003.1eD16 requires that the MASK
-        * be set instead of the GROUP entry, if there is a MASK.
-        */
-       for (ap = acl->acl_entry, i = 0; i < acl->acl_cnt; ap++, i++) {
-               switch (ap->ae_tag) {
-               case ACL_USER_OBJ:
-                       ap->ae_perm = (mode >> 6) & 0x7;
-                       break;
-               case ACL_GROUP_OBJ:
-                       gap = ap;
-                       break;
-               case ACL_MASK:
-                       nomask = 0;
-                       ap->ae_perm = (mode >> 3) & 0x7;
-                       break;
-               case ACL_OTHER:
-                       ap->ae_perm = mode & 0x7;
-                       break;
-               default:
-                       break;
-               }
-       }
-       /* Set the ACL_GROUP_OBJ if there's no ACL_MASK */
-       if (gap && nomask)
-               gap->ae_perm = (mode >> 3) & 0x7;
-}
-
-/*
- * When inheriting an Access ACL from a directory Default ACL,
- * the ACL bits are set to the intersection of the ACL default
- * permission bits and the file permission bits in mode. If there
- * are no permission bits on the file then we must not give them
- * the ACL. This is what what makes umask() work with ACLs.
- */
-STATIC void
-xfs_acl_filter_mode(
-       mode_t          mode,
-       xfs_acl_t       *acl)
-{
-       int             i, nomask = 1;
-       xfs_acl_entry_t *ap;
-       xfs_acl_entry_t *gap = NULL;
-
-       /*
-        * Set ACL entries. POSIX1003.1eD16 requires that the MASK
-        * be merged with GROUP entry, if there is a MASK.
-        */
-       for (ap = acl->acl_entry, i = 0; i < acl->acl_cnt; ap++, i++) {
-               switch (ap->ae_tag) {
-               case ACL_USER_OBJ:
-                       ap->ae_perm &= (mode >> 6) & 0x7;
-                       break;
-               case ACL_GROUP_OBJ:
-                       gap = ap;
-                       break;
-               case ACL_MASK:
-                       nomask = 0;
-                       ap->ae_perm &= (mode >> 3) & 0x7;
-                       break;
-               case ACL_OTHER:
-                       ap->ae_perm &= mode & 0x7;
-                       break;
-               default:
-                       break;
-               }
-       }
-       /* Set the ACL_GROUP_OBJ if there's no ACL_MASK */
-       if (gap && nomask)
-               gap->ae_perm &= (mode >> 3) & 0x7;
-}
index 642f1db4def478598bccd2b94425385620dccf92..63dc1f2efad5bbf1c291b79b312d326b3aebc82d 100644 (file)
 #ifndef __XFS_ACL_H__
 #define __XFS_ACL_H__
 
-/*
- * Access Control Lists
- */
-typedef __uint16_t     xfs_acl_perm_t;
-typedef __int32_t      xfs_acl_tag_t;
-typedef __int32_t      xfs_acl_id_t;
+struct inode;
+struct posix_acl;
+struct xfs_inode;
 
 #define XFS_ACL_MAX_ENTRIES 25
 #define XFS_ACL_NOT_PRESENT (-1)
 
-typedef struct xfs_acl_entry {
-       xfs_acl_tag_t   ae_tag;
-       xfs_acl_id_t    ae_id;
-       xfs_acl_perm_t  ae_perm;
-} xfs_acl_entry_t;
-
-typedef struct xfs_acl {
-       __int32_t       acl_cnt;
-       xfs_acl_entry_t acl_entry[XFS_ACL_MAX_ENTRIES];
-} xfs_acl_t;
+/* On-disk XFS access control list structure */
+struct xfs_acl {
+       __be32          acl_cnt;
+       struct xfs_acl_entry {
+               __be32  ae_tag;
+               __be32  ae_id;
+               __be16  ae_perm;
+       } acl_entry[XFS_ACL_MAX_ENTRIES];
+};
 
 /* On-disk XFS extended attribute names */
-#define SGI_ACL_FILE   "SGI_ACL_FILE"
-#define SGI_ACL_DEFAULT        "SGI_ACL_DEFAULT"
+#define SGI_ACL_FILE           "SGI_ACL_FILE"
+#define SGI_ACL_DEFAULT                "SGI_ACL_DEFAULT"
 #define SGI_ACL_FILE_SIZE      (sizeof(SGI_ACL_FILE)-1)
 #define SGI_ACL_DEFAULT_SIZE   (sizeof(SGI_ACL_DEFAULT)-1)
 
-#define _ACL_TYPE_ACCESS       1
-#define _ACL_TYPE_DEFAULT      2
-
 #ifdef CONFIG_XFS_POSIX_ACL
+extern int xfs_check_acl(struct inode *inode, int mask);
+extern struct posix_acl *xfs_get_acl(struct inode *inode, int type);
+extern int xfs_inherit_acl(struct inode *inode, struct posix_acl *default_acl);
+extern int xfs_acl_chmod(struct inode *inode);
+extern void xfs_inode_init_acls(struct xfs_inode *ip);
+extern void xfs_inode_clear_acls(struct xfs_inode *ip);
+extern int posix_acl_access_exists(struct inode *inode);
+extern int posix_acl_default_exists(struct inode *inode);
 
-struct vattr;
-struct xfs_inode;
-
-extern struct kmem_zone *xfs_acl_zone;
-#define xfs_acl_zone_init(zone, name)  \
-               (zone) = kmem_zone_init(sizeof(xfs_acl_t), (name))
-#define xfs_acl_zone_destroy(zone)     kmem_zone_destroy(zone)
-
-extern int xfs_acl_inherit(struct inode *, mode_t mode, xfs_acl_t *);
-extern int xfs_acl_iaccess(struct xfs_inode *, mode_t, cred_t *);
-extern int xfs_acl_vtoacl(struct inode *, xfs_acl_t *, xfs_acl_t *);
-extern int xfs_acl_vhasacl_access(struct inode *);
-extern int xfs_acl_vhasacl_default(struct inode *);
-extern int xfs_acl_vset(struct inode *, void *, size_t, int);
-extern int xfs_acl_vget(struct inode *, void *, size_t, int);
-extern int xfs_acl_vremove(struct inode *, int);
-
-#define _ACL_PERM_INVALID(perm)        ((perm) & ~(ACL_READ|ACL_WRITE|ACL_EXECUTE))
-
-#define _ACL_INHERIT(c,m,d)    (xfs_acl_inherit(c,m,d))
-#define _ACL_GET_ACCESS(pv,pa) (xfs_acl_vtoacl(pv,pa,NULL) == 0)
-#define _ACL_GET_DEFAULT(pv,pd)        (xfs_acl_vtoacl(pv,NULL,pd) == 0)
-#define _ACL_ACCESS_EXISTS     xfs_acl_vhasacl_access
-#define _ACL_DEFAULT_EXISTS    xfs_acl_vhasacl_default
-
-#define _ACL_ALLOC(a)          ((a) = kmem_zone_alloc(xfs_acl_zone, KM_SLEEP))
-#define _ACL_FREE(a)           ((a)? kmem_zone_free(xfs_acl_zone, (a)):(void)0)
-
+extern struct xattr_handler xfs_xattr_system_handler;
 #else
-#define xfs_acl_zone_init(zone,name)
-#define xfs_acl_zone_destroy(zone)
-#define xfs_acl_vset(v,p,sz,t) (-EOPNOTSUPP)
-#define xfs_acl_vget(v,p,sz,t) (-EOPNOTSUPP)
-#define xfs_acl_vremove(v,t)   (-EOPNOTSUPP)
-#define xfs_acl_vhasacl_access(v)      (0)
-#define xfs_acl_vhasacl_default(v)     (0)
-#define _ACL_ALLOC(a)          (1)     /* successfully allocate nothing */
-#define _ACL_FREE(a)           ((void)0)
-#define _ACL_INHERIT(c,m,d)    (0)
-#define _ACL_GET_ACCESS(pv,pa) (0)
-#define _ACL_GET_DEFAULT(pv,pd)        (0)
-#define _ACL_ACCESS_EXISTS     (NULL)
-#define _ACL_DEFAULT_EXISTS    (NULL)
-#endif
-
+# define xfs_check_acl                                 NULL
+# define xfs_get_acl(inode, type)                      NULL
+# define xfs_inherit_acl(inode, default_acl)           0
+# define xfs_acl_chmod(inode)                          0
+# define xfs_inode_init_acls(ip)
+# define xfs_inode_clear_acls(ip)
+# define posix_acl_access_exists(inode)                        0
+# define posix_acl_default_exists(inode)               0
+#endif /* CONFIG_XFS_POSIX_ACL */
 #endif /* __XFS_ACL_H__ */
index c8641f713caae0c97d9ad08481de1627626bb007..f24b50b68d03a6b3d89027bff545d19d3296f85e 100644 (file)
@@ -212,6 +212,8 @@ typedef struct xfs_perag
 /*
  * tags for inode radix tree
  */
+#define XFS_ICI_NO_TAG         (-1)    /* special flag for an untagged lookup
+                                          in xfs_inode_ag_iterator */
 #define XFS_ICI_RECLAIM_TAG    0       /* inode is to be reclaimed */
 
 #define        XFS_AG_MAXLEVELS(mp)            ((mp)->m_ag_maxlevels)
index 53d5e70d13609a720127319da3d43d6e4c42dc0c..0902249354a065efc56c4e3e6248db59237b3f5c 100644 (file)
@@ -73,28 +73,6 @@ static inline void be64_add_cpu(__be64 *a, __s64 b)
 
 #endif /* __KERNEL__ */
 
-/* do we need conversion? */
-#define ARCH_NOCONVERT 1
-#ifdef XFS_NATIVE_HOST
-# define ARCH_CONVERT  ARCH_NOCONVERT
-#else
-# define ARCH_CONVERT  0
-#endif
-
-/* generic swapping macros */
-
-#ifndef HAVE_SWABMACROS
-#define INT_SWAP16(type,var) ((typeof(type))(__swab16((__u16)(var))))
-#define INT_SWAP32(type,var) ((typeof(type))(__swab32((__u32)(var))))
-#define INT_SWAP64(type,var) ((typeof(type))(__swab64((__u64)(var))))
-#endif
-
-#define INT_SWAP(type, var) \
-    ((sizeof(type) == 8) ? INT_SWAP64(type,var) : \
-    ((sizeof(type) == 4) ? INT_SWAP32(type,var) : \
-    ((sizeof(type) == 2) ? INT_SWAP16(type,var) : \
-    (var))))
-
 /*
  * get and set integers from potentially unaligned locations
  */
@@ -107,16 +85,6 @@ static inline void be64_add_cpu(__be64 *a, __s64 b)
        ((__u8*)(pointer))[1] = (((value)     ) & 0xff); \
     }
 
-/* does not return a value */
-#define INT_SET(reference,arch,valueref) \
-    (__builtin_constant_p(valueref) ? \
-       (void)( (reference) = ( ((arch) != ARCH_NOCONVERT) ? (INT_SWAP((reference),(valueref))) : (valueref)) ) : \
-       (void)( \
-           ((reference) = (valueref)), \
-           ( ((arch) != ARCH_NOCONVERT) ? (reference) = INT_SWAP((reference),(reference)) : 0 ) \
-       ) \
-    )
-
 /*
  * In directories inode numbers are stored as unaligned arrays of unsigned
  * 8bit integers on disk.
index 5fde1654b43098a34f0fccc649eada810ee87bd0..db15feb906fffa0e38b0e44f23ef3967faea33fd 100644 (file)
@@ -45,7 +45,6 @@
 #include "xfs_error.h"
 #include "xfs_quota.h"
 #include "xfs_trans_space.h"
-#include "xfs_acl.h"
 #include "xfs_rw.h"
 #include "xfs_vnodeops.h"
 
@@ -249,8 +248,9 @@ xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name,
        /*
         * Attach the dquots to the inode.
         */
-       if ((error = XFS_QM_DQATTACH(mp, dp, 0)))
-               return (error);
+       error = xfs_qm_dqattach(dp, 0);
+       if (error)
+               return error;
 
        /*
         * If the inode doesn't have an attribute fork, add one.
@@ -311,7 +311,7 @@ xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name,
        }
        xfs_ilock(dp, XFS_ILOCK_EXCL);
 
-       error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, args.trans, dp, args.total, 0,
+       error = xfs_trans_reserve_quota_nblks(args.trans, dp, args.total, 0,
                                rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :
                                       XFS_QMOPT_RES_REGBLKS);
        if (error) {
@@ -501,8 +501,9 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
        /*
         * Attach the dquots to the inode.
         */
-       if ((error = XFS_QM_DQATTACH(mp, dp, 0)))
-               return (error);
+       error = xfs_qm_dqattach(dp, 0);
+       if (error)
+               return error;
 
        /*
         * Start our first transaction of the day.
index ca7c6005a487cab8a9d7b700a9c34b937fc6bc8c..7928b9983c1d53e6d0ca3c2719ce361bb95175f8 100644 (file)
@@ -2691,7 +2691,7 @@ xfs_bmap_rtalloc(
                 * Adjust the disk quota also. This was reserved
                 * earlier.
                 */
-               XFS_TRANS_MOD_DQUOT_BYINO(mp, ap->tp, ap->ip,
+               xfs_trans_mod_dquot_byino(ap->tp, ap->ip,
                        ap->wasdel ? XFS_TRANS_DQ_DELRTBCOUNT :
                                        XFS_TRANS_DQ_RTBCOUNT, (long) ralen);
        } else {
@@ -2995,7 +2995,7 @@ xfs_bmap_btalloc(
                 * Adjust the disk quota also. This was reserved
                 * earlier.
                 */
-               XFS_TRANS_MOD_DQUOT_BYINO(mp, ap->tp, ap->ip,
+               xfs_trans_mod_dquot_byino(ap->tp, ap->ip,
                        ap->wasdel ? XFS_TRANS_DQ_DELBCOUNT :
                                        XFS_TRANS_DQ_BCOUNT,
                        (long) args.len);
@@ -3066,7 +3066,7 @@ xfs_bmap_btree_to_extents(
                return error;
        xfs_bmap_add_free(cbno, 1, cur->bc_private.b.flist, mp);
        ip->i_d.di_nblocks--;
-       XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, XFS_TRANS_DQ_BCOUNT, -1L);
+       xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L);
        xfs_trans_binval(tp, cbp);
        if (cur->bc_bufs[0] == cbp)
                cur->bc_bufs[0] = NULL;
@@ -3386,7 +3386,7 @@ xfs_bmap_del_extent(
         * Adjust quota data.
         */
        if (qfield)
-               XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, qfield, (long)-nblks);
+               xfs_trans_mod_dquot_byino(tp, ip, qfield, (long)-nblks);
 
        /*
         * Account for change in delayed indirect blocks.
@@ -3523,7 +3523,7 @@ xfs_bmap_extents_to_btree(
        *firstblock = cur->bc_private.b.firstblock = args.fsbno;
        cur->bc_private.b.allocated++;
        ip->i_d.di_nblocks++;
-       XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, XFS_TRANS_DQ_BCOUNT, 1L);
+       xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, 1L);
        abp = xfs_btree_get_bufl(mp, tp, args.fsbno, 0);
        /*
         * Fill in the child block.
@@ -3690,7 +3690,7 @@ xfs_bmap_local_to_extents(
                XFS_BMAP_TRACE_POST_UPDATE("new", ip, 0, whichfork);
                XFS_IFORK_NEXT_SET(ip, whichfork, 1);
                ip->i_d.di_nblocks = 1;
-               XFS_TRANS_MOD_DQUOT_BYINO(args.mp, tp, ip,
+               xfs_trans_mod_dquot_byino(tp, ip,
                        XFS_TRANS_DQ_BCOUNT, 1L);
                flags |= xfs_ilog_fext(whichfork);
        } else {
@@ -4048,7 +4048,7 @@ xfs_bmap_add_attrfork(
                        XFS_TRANS_PERM_LOG_RES, XFS_ADDAFORK_LOG_COUNT)))
                goto error0;
        xfs_ilock(ip, XFS_ILOCK_EXCL);
-       error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, blks, 0, rsvd ?
+       error = xfs_trans_reserve_quota_nblks(tp, ip, blks, 0, rsvd ?
                        XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :
                        XFS_QMOPT_RES_REGBLKS);
        if (error) {
@@ -4983,10 +4983,11 @@ xfs_bmapi(
                                 * adjusted later.  We return if we haven't
                                 * allocated blocks already inside this loop.
                                 */
-                               if ((error = XFS_TRANS_RESERVE_QUOTA_NBLKS(
-                                               mp, NULL, ip, (long)alen, 0,
+                               error = xfs_trans_reserve_quota_nblks(
+                                               NULL, ip, (long)alen, 0,
                                                rt ? XFS_QMOPT_RES_RTBLKS :
-                                                    XFS_QMOPT_RES_REGBLKS))) {
+                                                    XFS_QMOPT_RES_REGBLKS);
+                               if (error) {
                                        if (n == 0) {
                                                *nmap = 0;
                                                ASSERT(cur == NULL);
@@ -5035,8 +5036,8 @@ xfs_bmapi(
                                        if (XFS_IS_QUOTA_ON(mp))
                                                /* unreserve the blocks now */
                                                (void)
-                                               XFS_TRANS_UNRESERVE_QUOTA_NBLKS(
-                                                       mp, NULL, ip,
+                                               xfs_trans_unreserve_quota_nblks(
+                                                       NULL, ip,
                                                        (long)alen, 0, rt ?
                                                        XFS_QMOPT_RES_RTBLKS :
                                                        XFS_QMOPT_RES_REGBLKS);
@@ -5691,14 +5692,14 @@ xfs_bunmapi(
                                do_div(rtexts, mp->m_sb.sb_rextsize);
                                xfs_mod_incore_sb(mp, XFS_SBS_FREXTENTS,
                                                (int64_t)rtexts, rsvd);
-                               (void)XFS_TRANS_RESERVE_QUOTA_NBLKS(mp,
-                                       NULL, ip, -((long)del.br_blockcount), 0,
+                               (void)xfs_trans_reserve_quota_nblks(NULL,
+                                       ip, -((long)del.br_blockcount), 0,
                                        XFS_QMOPT_RES_RTBLKS);
                        } else {
                                xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS,
                                                (int64_t)del.br_blockcount, rsvd);
-                               (void)XFS_TRANS_RESERVE_QUOTA_NBLKS(mp,
-                                       NULL, ip, -((long)del.br_blockcount), 0,
+                               (void)xfs_trans_reserve_quota_nblks(NULL,
+                                       ip, -((long)del.br_blockcount), 0,
                                        XFS_QMOPT_RES_REGBLKS);
                        }
                        ip->i_delayed_blks -= del.br_blockcount;
@@ -6085,6 +6086,7 @@ xfs_getbmap(
                        break;
        }
 
+       kmem_free(out);
        return error;
 }
 
index 0760d352586fcb3e791405f8f2cd857830f4d41f..5c1ade06578edbdad83711f59974a46cdddb7a0e 100644 (file)
@@ -590,7 +590,7 @@ xfs_bmbt_alloc_block(
        cur->bc_private.b.allocated++;
        cur->bc_private.b.ip->i_d.di_nblocks++;
        xfs_trans_log_inode(args.tp, cur->bc_private.b.ip, XFS_ILOG_CORE);
-       XFS_TRANS_MOD_DQUOT_BYINO(args.mp, args.tp, cur->bc_private.b.ip,
+       xfs_trans_mod_dquot_byino(args.tp, cur->bc_private.b.ip,
                        XFS_TRANS_DQ_BCOUNT, 1L);
 
        new->l = cpu_to_be64(args.fsbno);
@@ -618,7 +618,7 @@ xfs_bmbt_free_block(
        ip->i_d.di_nblocks--;
 
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-       XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, XFS_TRANS_DQ_BCOUNT, -1L);
+       xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L);
        xfs_trans_binval(tp, bp);
        return 0;
 }
index 6c87c8f304efb8f7d887c7c41a667e4c85105882..edf8bdf4141fdbd626acf69dc8db4b2d471c568d 100644 (file)
@@ -542,10 +542,8 @@ xfs_filestream_associate(
         * waiting for the lock because someone else is waiting on the lock we
         * hold and we cannot drop that as we are in a transaction here.
         *
-        * Lucky for us, this inversion is rarely a problem because it's a
-        * directory inode that we are trying to lock here and that means the
-        * only place that matters is xfs_sync_inodes() and SYNC_DELWRI is
-        * used. i.e. freeze, remount-ro, quotasync or unmount.
+        * Lucky for us, this inversion is not a problem because it's a
+        * directory inode that we are trying to lock here.
         *
         * So, if we can't get the iolock without sleeping then just give up
         */
index f7c06fac82297205b208225fbbc29e3d7f0b19d4..c4ea51b55dce09999174e329ca44334d48856b6a 100644 (file)
@@ -239,10 +239,13 @@ typedef struct xfs_fsop_resblks {
  * Minimum and maximum sizes need for growth checks
  */
 #define XFS_MIN_AG_BLOCKS      64
-#define XFS_MIN_LOG_BLOCKS     512
-#define XFS_MAX_LOG_BLOCKS     (64 * 1024)
-#define XFS_MIN_LOG_BYTES      (256 * 1024)
-#define XFS_MAX_LOG_BYTES      (128 * 1024 * 1024)
+#define XFS_MIN_LOG_BLOCKS     512ULL
+#define XFS_MAX_LOG_BLOCKS     (1024 * 1024ULL)
+#define XFS_MIN_LOG_BYTES      (10 * 1024 * 1024ULL)
+
+/* keep the maximum size under 2^31 by a small amount */
+#define XFS_MAX_LOG_BYTES \
+       ((2 * 1024 * 1024 * 1024ULL) - XFS_MIN_LOG_BYTES)
 
 /*
  * Structures for XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG & XFS_IOC_FSGROWFSRT
index 89b81eedce6ac8b35da16cb98fca1bdb1a048c4d..76c540f719e49bb73ef6fd7c99b8d1e0c6d80a54 100644 (file)
@@ -18,6 +18,7 @@
 #include "xfs.h"
 #include "xfs_fs.h"
 #include "xfs_types.h"
+#include "xfs_acl.h"
 #include "xfs_bit.h"
 #include "xfs_log.h"
 #include "xfs_inum.h"
@@ -82,6 +83,7 @@ xfs_inode_alloc(
        memset(&ip->i_d, 0, sizeof(xfs_icdinode_t));
        ip->i_size = 0;
        ip->i_new_size = 0;
+       xfs_inode_init_acls(ip);
 
        /*
         * Initialize inode's trace buffers.
@@ -500,10 +502,7 @@ xfs_ireclaim(
         * ilock one but will still hold the iolock.
         */
        xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
-       /*
-        * Release dquots (and their references) if any.
-        */
-       XFS_QM_DQDETACH(ip->i_mount, ip);
+       xfs_qm_dqdetach(ip);
        xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
 
        switch (ip->i_d.di_mode & S_IFMT) {
@@ -561,6 +560,7 @@ xfs_ireclaim(
        ASSERT(atomic_read(&ip->i_pincount) == 0);
        ASSERT(!spin_is_locked(&ip->i_flags_lock));
        ASSERT(completion_done(&ip->i_flush));
+       xfs_inode_clear_acls(ip);
        kmem_zone_free(xfs_inode_zone, ip);
 }
 
index 123b20c8cbf23ddd54e697d0f3a0d058e126f44b..1f22d65fed0a48d230a117f848598ba220017ad1 100644 (file)
@@ -49,7 +49,6 @@
 #include "xfs_utils.h"
 #include "xfs_dir2_trace.h"
 #include "xfs_quota.h"
-#include "xfs_acl.h"
 #include "xfs_filestream.h"
 #include "xfs_vnodeops.h"
 
index f879c1bc4b96deba7ec1c42fb8bc9fcfd0109a1d..77016702938b23cca6c9b4e6a4b48e164ae176ac 100644 (file)
@@ -18,6 +18,7 @@
 #ifndef        __XFS_INODE_H__
 #define        __XFS_INODE_H__
 
+struct posix_acl;
 struct xfs_dinode;
 struct xfs_inode;
 
@@ -272,6 +273,11 @@ typedef struct xfs_inode {
        /* VFS inode */
        struct inode            i_vnode;        /* embedded VFS inode */
 
+#ifdef CONFIG_XFS_POSIX_ACL
+       struct posix_acl        *i_acl;
+       struct posix_acl        *i_default_acl;
+#endif
+
        /* Trace buffers per inode. */
 #ifdef XFS_INODE_TRACE
        struct ktrace           *i_trace;       /* general inode trace */
index 5aaa2d7ec15589da6307c119b0497ed05f29ccb7..67ae5555a30a6e8be0bd415b1596bea17854add5 100644 (file)
@@ -42,7 +42,6 @@
 #include "xfs_error.h"
 #include "xfs_itable.h"
 #include "xfs_rw.h"
-#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_trans_space.h"
@@ -385,7 +384,7 @@ xfs_iomap_write_direct(
         * Make sure that the dquots are there. This doesn't hold
         * the ilock across a disk read.
         */
-       error = XFS_QM_DQATTACH(ip->i_mount, ip, XFS_QMOPT_ILOCKED);
+       error = xfs_qm_dqattach_locked(ip, 0);
        if (error)
                return XFS_ERROR(error);
 
@@ -444,8 +443,7 @@ xfs_iomap_write_direct(
        if (error)
                goto error_out;
 
-       error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip,
-                                             qblocks, 0, quota_flag);
+       error = xfs_trans_reserve_quota_nblks(tp, ip, qblocks, 0, quota_flag);
        if (error)
                goto error1;
 
@@ -495,7 +493,7 @@ xfs_iomap_write_direct(
 
 error0:        /* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */
        xfs_bmap_cancel(&free_list);
-       XFS_TRANS_UNRESERVE_QUOTA_NBLKS(mp, tp, ip, qblocks, 0, quota_flag);
+       xfs_trans_unreserve_quota_nblks(tp, ip, qblocks, 0, quota_flag);
 
 error1:        /* Just cancel transaction */
        xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
@@ -582,7 +580,7 @@ xfs_iomap_write_delay(
         * Make sure that the dquots are there. This doesn't hold
         * the ilock across a disk read.
         */
-       error = XFS_QM_DQATTACH(mp, ip, XFS_QMOPT_ILOCKED);
+       error = xfs_qm_dqattach_locked(ip, 0);
        if (error)
                return XFS_ERROR(error);
 
@@ -684,7 +682,8 @@ xfs_iomap_write_allocate(
        /*
         * Make sure that the dquots are there.
         */
-       if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
+       error = xfs_qm_dqattach(ip, 0);
+       if (error)
                return XFS_ERROR(error);
 
        offset_fsb = XFS_B_TO_FSBT(mp, offset);
index 7ba450116d4ffc97f247c99a8a89f190bf5a89f2..47da2fb45377309728acbeb3b4351908d61d6bde 100644 (file)
@@ -1975,16 +1975,30 @@ xlog_recover_do_reg_buffer(
                error = 0;
                if (buf_f->blf_flags &
                   (XFS_BLI_UDQUOT_BUF|XFS_BLI_PDQUOT_BUF|XFS_BLI_GDQUOT_BUF)) {
+                       if (item->ri_buf[i].i_addr == NULL) {
+                               cmn_err(CE_ALERT,
+                                       "XFS: NULL dquot in %s.", __func__);
+                               goto next;
+                       }
+                       if (item->ri_buf[i].i_len < sizeof(xfs_dqblk_t)) {
+                               cmn_err(CE_ALERT,
+                                       "XFS: dquot too small (%d) in %s.",
+                                       item->ri_buf[i].i_len, __func__);
+                               goto next;
+                       }
                        error = xfs_qm_dqcheck((xfs_disk_dquot_t *)
                                               item->ri_buf[i].i_addr,
                                               -1, 0, XFS_QMOPT_DOWARN,
                                               "dquot_buf_recover");
+                       if (error)
+                               goto next;
                }
-               if (!error)
-                       memcpy(xfs_buf_offset(bp,
-                               (uint)bit << XFS_BLI_SHIFT),    /* dest */
-                               item->ri_buf[i].i_addr,         /* source */
-                               nbits<<XFS_BLI_SHIFT);          /* length */
+
+               memcpy(xfs_buf_offset(bp,
+                       (uint)bit << XFS_BLI_SHIFT),    /* dest */
+                       item->ri_buf[i].i_addr,         /* source */
+                       nbits<<XFS_BLI_SHIFT);          /* length */
+ next:
                i++;
                bit += nbits;
        }
@@ -2615,7 +2629,19 @@ xlog_recover_do_dquot_trans(
                return (0);
 
        recddq = (xfs_disk_dquot_t *)item->ri_buf[1].i_addr;
-       ASSERT(recddq);
+
+       if (item->ri_buf[1].i_addr == NULL) {
+               cmn_err(CE_ALERT,
+                       "XFS: NULL dquot in %s.", __func__);
+               return XFS_ERROR(EIO);
+       }
+       if (item->ri_buf[1].i_len < sizeof(xfs_dqblk_t)) {
+               cmn_err(CE_ALERT,
+                       "XFS: dquot too small (%d) in %s.",
+                       item->ri_buf[1].i_len, __func__);
+               return XFS_ERROR(EIO);
+       }
+
        /*
         * This type of quotas was turned off, so ignore this record.
         */
index 65a99725d0cc589d9e1b96690a2c12448849e249..5c6f092659c1cfb3f0edef669a197d10a955b34d 100644 (file)
@@ -959,6 +959,53 @@ xfs_check_sizes(xfs_mount_t *mp)
        return 0;
 }
 
+/*
+ * Clear the quotaflags in memory and in the superblock.
+ */
+int
+xfs_mount_reset_sbqflags(
+       struct xfs_mount        *mp)
+{
+       int                     error;
+       struct xfs_trans        *tp;
+
+       mp->m_qflags = 0;
+
+       /*
+        * It is OK to look at sb_qflags here in mount path,
+        * without m_sb_lock.
+        */
+       if (mp->m_sb.sb_qflags == 0)
+               return 0;
+       spin_lock(&mp->m_sb_lock);
+       mp->m_sb.sb_qflags = 0;
+       spin_unlock(&mp->m_sb_lock);
+
+       /*
+        * If the fs is readonly, let the incore superblock run
+        * with quotas off but don't flush the update out to disk
+        */
+       if (mp->m_flags & XFS_MOUNT_RDONLY)
+               return 0;
+
+#ifdef QUOTADEBUG
+       xfs_fs_cmn_err(CE_NOTE, mp, "Writing superblock quota changes");
+#endif
+
+       tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);
+       error = xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
+                                     XFS_DEFAULT_LOG_COUNT);
+       if (error) {
+               xfs_trans_cancel(tp, 0);
+               xfs_fs_cmn_err(CE_ALERT, mp,
+                       "xfs_mount_reset_sbqflags: Superblock update failed!");
+               return error;
+       }
+
+       xfs_mod_sb(tp, XFS_SB_QFLAGS);
+       return xfs_trans_commit(tp, 0);
+}
+
 /*
  * This function does the following on an initial mount of a file system:
  *     - reads the superblock from disk and init the mount struct
@@ -976,7 +1023,8 @@ xfs_mountfs(
        xfs_sb_t        *sbp = &(mp->m_sb);
        xfs_inode_t     *rip;
        __uint64_t      resblks;
-       uint            quotamount, quotaflags;
+       uint            quotamount = 0;
+       uint            quotaflags = 0;
        int             error = 0;
 
        xfs_mount_common(mp, sbp);
@@ -1210,9 +1258,28 @@ xfs_mountfs(
        /*
         * Initialise the XFS quota management subsystem for this mount
         */
-       error = XFS_QM_INIT(mp, &quotamount, &quotaflags);
-       if (error)
-               goto out_rtunmount;
+       if (XFS_IS_QUOTA_RUNNING(mp)) {
+               error = xfs_qm_newmount(mp, &quotamount, &quotaflags);
+               if (error)
+                       goto out_rtunmount;
+       } else {
+               ASSERT(!XFS_IS_QUOTA_ON(mp));
+
+               /*
+                * If a file system had quotas running earlier, but decided to
+                * mount without -o uquota/pquota/gquota options, revoke the
+                * quotachecked license.
+                */
+               if (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_ACCT) {
+                       cmn_err(CE_NOTE,
+                               "XFS: resetting qflags for filesystem %s",
+                               mp->m_fsname);
+
+                       error = xfs_mount_reset_sbqflags(mp);
+                       if (error)
+                               return error;
+               }
+       }
 
        /*
         * Finish recovering the file system.  This part needed to be
@@ -1228,9 +1295,19 @@ xfs_mountfs(
        /*
         * Complete the quota initialisation, post-log-replay component.
         */
-       error = XFS_QM_MOUNT(mp, quotamount, quotaflags);
-       if (error)
-               goto out_rtunmount;
+       if (quotamount) {
+               ASSERT(mp->m_qflags == 0);
+               mp->m_qflags = quotaflags;
+
+               xfs_qm_mount_quotas(mp);
+       }
+
+#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
+       if (XFS_IS_QUOTA_ON(mp))
+               xfs_fs_cmn_err(CE_NOTE, mp, "Disk quotas turned on");
+       else
+               xfs_fs_cmn_err(CE_NOTE, mp, "Disk quotas not turned on");
+#endif
 
        /*
         * Now we are mounted, reserve a small amount of unused space for
@@ -1279,12 +1356,7 @@ xfs_unmountfs(
        __uint64_t              resblks;
        int                     error;
 
-       /*
-        * Release dquot that rootinode, rbmino and rsumino might be holding,
-        * and release the quota inodes.
-        */
-       XFS_QM_UNMOUNT(mp);
-
+       xfs_qm_unmount_quotas(mp);
        xfs_rtunmount_inodes(mp);
        IRELE(mp->m_rootip);
 
@@ -1299,12 +1371,9 @@ xfs_unmountfs(
         * need to force the log first.
         */
        xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC);
-       xfs_reclaim_inodes(mp, 0, XFS_IFLUSH_ASYNC);
-
-       XFS_QM_DQPURGEALL(mp, XFS_QMOPT_QUOTALL | XFS_QMOPT_UMOUNTING);
+       xfs_reclaim_inodes(mp, XFS_IFLUSH_ASYNC);
 
-       if (mp->m_quotainfo)
-               XFS_QM_DONE(mp);
+       xfs_qm_unmount(mp);
 
        /*
         * Flush out the log synchronously so that we know for sure
index d6a64392f983d22bbc376936d44836ce46f5891a..a5122382afde2c569897bac565118226a31e0ca5 100644 (file)
@@ -64,6 +64,8 @@ struct xfs_swapext;
 struct xfs_mru_cache;
 struct xfs_nameops;
 struct xfs_ail;
+struct xfs_quotainfo;
+
 
 /*
  * Prototypes and functions for the Data Migration subsystem.
@@ -107,86 +109,6 @@ typedef struct xfs_dmops {
        (*(mp)->m_dm_ops->xfs_send_unmount)(mp,ip,right,mode,rval,fl)
 
 
-/*
- * Prototypes and functions for the Quota Management subsystem.
- */
-
-struct xfs_dquot;
-struct xfs_dqtrxops;
-struct xfs_quotainfo;
-
-typedef int    (*xfs_qminit_t)(struct xfs_mount *, uint *, uint *);
-typedef int    (*xfs_qmmount_t)(struct xfs_mount *, uint, uint);
-typedef void   (*xfs_qmunmount_t)(struct xfs_mount *);
-typedef void   (*xfs_qmdone_t)(struct xfs_mount *);
-typedef void   (*xfs_dqrele_t)(struct xfs_dquot *);
-typedef int    (*xfs_dqattach_t)(struct xfs_inode *, uint);
-typedef void   (*xfs_dqdetach_t)(struct xfs_inode *);
-typedef int    (*xfs_dqpurgeall_t)(struct xfs_mount *, uint);
-typedef int    (*xfs_dqvopalloc_t)(struct xfs_mount *,
-                       struct xfs_inode *, uid_t, gid_t, prid_t, uint,
-                       struct xfs_dquot **, struct xfs_dquot **);
-typedef void   (*xfs_dqvopcreate_t)(struct xfs_trans *, struct xfs_inode *,
-                       struct xfs_dquot *, struct xfs_dquot *);
-typedef int    (*xfs_dqvoprename_t)(struct xfs_inode **);
-typedef struct xfs_dquot * (*xfs_dqvopchown_t)(
-                       struct xfs_trans *, struct xfs_inode *,
-                       struct xfs_dquot **, struct xfs_dquot *);
-typedef int    (*xfs_dqvopchownresv_t)(struct xfs_trans *, struct xfs_inode *,
-                       struct xfs_dquot *, struct xfs_dquot *, uint);
-typedef void   (*xfs_dqstatvfs_t)(struct xfs_inode *, struct kstatfs *);
-typedef int    (*xfs_dqsync_t)(struct xfs_mount *, int flags);
-
-typedef struct xfs_qmops {
-       xfs_qminit_t            xfs_qminit;
-       xfs_qmdone_t            xfs_qmdone;
-       xfs_qmmount_t           xfs_qmmount;
-       xfs_qmunmount_t         xfs_qmunmount;
-       xfs_dqrele_t            xfs_dqrele;
-       xfs_dqattach_t          xfs_dqattach;
-       xfs_dqdetach_t          xfs_dqdetach;
-       xfs_dqpurgeall_t        xfs_dqpurgeall;
-       xfs_dqvopalloc_t        xfs_dqvopalloc;
-       xfs_dqvopcreate_t       xfs_dqvopcreate;
-       xfs_dqvoprename_t       xfs_dqvoprename;
-       xfs_dqvopchown_t        xfs_dqvopchown;
-       xfs_dqvopchownresv_t    xfs_dqvopchownresv;
-       xfs_dqstatvfs_t         xfs_dqstatvfs;
-       xfs_dqsync_t            xfs_dqsync;
-       struct xfs_dqtrxops     *xfs_dqtrxops;
-} xfs_qmops_t;
-
-#define XFS_QM_INIT(mp, mnt, fl) \
-       (*(mp)->m_qm_ops->xfs_qminit)(mp, mnt, fl)
-#define XFS_QM_MOUNT(mp, mnt, fl) \
-       (*(mp)->m_qm_ops->xfs_qmmount)(mp, mnt, fl)
-#define XFS_QM_UNMOUNT(mp) \
-       (*(mp)->m_qm_ops->xfs_qmunmount)(mp)
-#define XFS_QM_DONE(mp) \
-       (*(mp)->m_qm_ops->xfs_qmdone)(mp)
-#define XFS_QM_DQRELE(mp, dq) \
-       (*(mp)->m_qm_ops->xfs_dqrele)(dq)
-#define XFS_QM_DQATTACH(mp, ip, fl) \
-       (*(mp)->m_qm_ops->xfs_dqattach)(ip, fl)
-#define XFS_QM_DQDETACH(mp, ip) \
-       (*(mp)->m_qm_ops->xfs_dqdetach)(ip)
-#define XFS_QM_DQPURGEALL(mp, fl) \
-       (*(mp)->m_qm_ops->xfs_dqpurgeall)(mp, fl)
-#define XFS_QM_DQVOPALLOC(mp, ip, uid, gid, prid, fl, dq1, dq2) \
-       (*(mp)->m_qm_ops->xfs_dqvopalloc)(mp, ip, uid, gid, prid, fl, dq1, dq2)
-#define XFS_QM_DQVOPCREATE(mp, tp, ip, dq1, dq2) \
-       (*(mp)->m_qm_ops->xfs_dqvopcreate)(tp, ip, dq1, dq2)
-#define XFS_QM_DQVOPRENAME(mp, ip) \
-       (*(mp)->m_qm_ops->xfs_dqvoprename)(ip)
-#define XFS_QM_DQVOPCHOWN(mp, tp, ip, dqp, dq) \
-       (*(mp)->m_qm_ops->xfs_dqvopchown)(tp, ip, dqp, dq)
-#define XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, dq1, dq2, fl) \
-       (*(mp)->m_qm_ops->xfs_dqvopchownresv)(tp, ip, dq1, dq2, fl)
-#define XFS_QM_DQSTATVFS(ip, statp) \
-       (*(ip)->i_mount->m_qm_ops->xfs_dqstatvfs)(ip, statp)
-#define XFS_QM_DQSYNC(mp, flags) \
-       (*(mp)->m_qm_ops->xfs_dqsync)(mp, flags)
-
 #ifdef HAVE_PERCPU_SB
 
 /*
@@ -510,8 +432,6 @@ extern int  xfs_sb_validate_fsb_count(struct xfs_sb *, __uint64_t);
 
 extern int     xfs_dmops_get(struct xfs_mount *);
 extern void    xfs_dmops_put(struct xfs_mount *);
-extern int     xfs_qmops_get(struct xfs_mount *);
-extern void    xfs_qmops_put(struct xfs_mount *);
 
 extern struct xfs_dmops xfs_dmcore_xfs;
 
diff --git a/fs/xfs/xfs_qmops.c b/fs/xfs/xfs_qmops.c
deleted file mode 100644 (file)
index e101790..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (c) 2000-2005 Silicon Graphics, 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.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT 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 the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-#include "xfs.h"
-#include "xfs_fs.h"
-#include "xfs_types.h"
-#include "xfs_log.h"
-#include "xfs_inum.h"
-#include "xfs_trans.h"
-#include "xfs_sb.h"
-#include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
-#include "xfs_mount.h"
-#include "xfs_quota.h"
-#include "xfs_error.h"
-
-
-STATIC struct xfs_dquot *
-xfs_dqvopchown_default(
-       struct xfs_trans        *tp,
-       struct xfs_inode        *ip,
-       struct xfs_dquot        **dqp,
-       struct xfs_dquot        *dq)
-{
-       return NULL;
-}
-
-/*
- * Clear the quotaflags in memory and in the superblock.
- */
-int
-xfs_mount_reset_sbqflags(xfs_mount_t *mp)
-{
-       int                     error;
-       xfs_trans_t             *tp;
-
-       mp->m_qflags = 0;
-       /*
-        * It is OK to look at sb_qflags here in mount path,
-        * without m_sb_lock.
-        */
-       if (mp->m_sb.sb_qflags == 0)
-               return 0;
-       spin_lock(&mp->m_sb_lock);
-       mp->m_sb.sb_qflags = 0;
-       spin_unlock(&mp->m_sb_lock);
-
-       /*
-        * if the fs is readonly, let the incore superblock run
-        * with quotas off but don't flush the update out to disk
-        */
-       if (mp->m_flags & XFS_MOUNT_RDONLY)
-               return 0;
-#ifdef QUOTADEBUG
-       xfs_fs_cmn_err(CE_NOTE, mp, "Writing superblock quota changes");
-#endif
-       tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);
-       if ((error = xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
-                                     XFS_DEFAULT_LOG_COUNT))) {
-               xfs_trans_cancel(tp, 0);
-               xfs_fs_cmn_err(CE_ALERT, mp,
-                       "xfs_mount_reset_sbqflags: Superblock update failed!");
-               return error;
-       }
-       xfs_mod_sb(tp, XFS_SB_QFLAGS);
-       error = xfs_trans_commit(tp, 0);
-       return error;
-}
-
-STATIC int
-xfs_noquota_init(
-       xfs_mount_t     *mp,
-       uint            *needquotamount,
-       uint            *quotaflags)
-{
-       int             error = 0;
-
-       *quotaflags = 0;
-       *needquotamount = B_FALSE;
-
-       ASSERT(!XFS_IS_QUOTA_ON(mp));
-
-       /*
-        * If a file system had quotas running earlier, but decided to
-        * mount without -o uquota/pquota/gquota options, revoke the
-        * quotachecked license.
-        */
-       if (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_ACCT) {
-               cmn_err(CE_NOTE,
-                        "XFS resetting qflags for filesystem %s",
-                        mp->m_fsname);
-
-               error = xfs_mount_reset_sbqflags(mp);
-       }
-       return error;
-}
-
-static struct xfs_qmops xfs_qmcore_stub = {
-       .xfs_qminit             = (xfs_qminit_t) xfs_noquota_init,
-       .xfs_qmdone             = (xfs_qmdone_t) fs_noerr,
-       .xfs_qmmount            = (xfs_qmmount_t) fs_noerr,
-       .xfs_qmunmount          = (xfs_qmunmount_t) fs_noerr,
-       .xfs_dqrele             = (xfs_dqrele_t) fs_noerr,
-       .xfs_dqattach           = (xfs_dqattach_t) fs_noerr,
-       .xfs_dqdetach           = (xfs_dqdetach_t) fs_noerr,
-       .xfs_dqpurgeall         = (xfs_dqpurgeall_t) fs_noerr,
-       .xfs_dqvopalloc         = (xfs_dqvopalloc_t) fs_noerr,
-       .xfs_dqvopcreate        = (xfs_dqvopcreate_t) fs_noerr,
-       .xfs_dqvoprename        = (xfs_dqvoprename_t) fs_noerr,
-       .xfs_dqvopchown         = xfs_dqvopchown_default,
-       .xfs_dqvopchownresv     = (xfs_dqvopchownresv_t) fs_noerr,
-       .xfs_dqstatvfs          = (xfs_dqstatvfs_t) fs_noval,
-       .xfs_dqsync             = (xfs_dqsync_t) fs_noerr,
-};
-
-int
-xfs_qmops_get(struct xfs_mount *mp)
-{
-       if (XFS_IS_QUOTA_RUNNING(mp)) {
-#ifdef CONFIG_XFS_QUOTA
-               mp->m_qm_ops = &xfs_qmcore_xfs;
-#else
-               cmn_err(CE_WARN,
-                       "XFS: qouta support not available in this kernel.");
-               return EINVAL;
-#endif
-       } else {
-               mp->m_qm_ops = &xfs_qmcore_stub;
-       }
-
-       return 0;
-}
-
-void
-xfs_qmops_put(struct xfs_mount *mp)
-{
-}
index f5d1202dde258a85f806472e987e0f44fd9f4989..3ec91ac74c2af0182ff4bbc0839d100a99347947 100644 (file)
@@ -197,7 +197,6 @@ typedef struct xfs_qoff_logformat {
 #define XFS_QMOPT_UMOUNTING    0x0000100 /* filesys is being unmounted */
 #define XFS_QMOPT_DOLOG                0x0000200 /* log buf changes (in quotacheck) */
 #define XFS_QMOPT_DOWARN        0x0000400 /* increase warning cnt if needed */
-#define XFS_QMOPT_ILOCKED      0x0000800 /* inode is already locked (excl) */
 #define XFS_QMOPT_DQREPAIR     0x0001000 /* repair dquot if damaged */
 #define XFS_QMOPT_GQUOTA       0x0002000 /* group dquot requested */
 #define XFS_QMOPT_ENOSPC       0x0004000 /* enospc instead of edquot (prj) */
@@ -302,69 +301,79 @@ typedef struct xfs_dqtrx {
        long            qt_delrtb_delta;  /* delayed RT blk count changes */
 } xfs_dqtrx_t;
 
-/*
- * Dquot transaction functions, used if quota is enabled.
- */
-typedef void   (*qo_dup_dqinfo_t)(struct xfs_trans *, struct xfs_trans *);
-typedef void   (*qo_mod_dquot_byino_t)(struct xfs_trans *,
-                               struct xfs_inode *, uint, long);
-typedef void   (*qo_free_dqinfo_t)(struct xfs_trans *);
-typedef void   (*qo_apply_dquot_deltas_t)(struct xfs_trans *);
-typedef void   (*qo_unreserve_and_mod_dquots_t)(struct xfs_trans *);
-typedef int    (*qo_reserve_quota_nblks_t)(
-                               struct xfs_trans *, struct xfs_mount *,
-                               struct xfs_inode *, long, long, uint);
-typedef int    (*qo_reserve_quota_bydquots_t)(
-                               struct xfs_trans *, struct xfs_mount *,
-                               struct xfs_dquot *, struct xfs_dquot *,
-                               long, long, uint);
-typedef struct xfs_dqtrxops {
-       qo_dup_dqinfo_t                 qo_dup_dqinfo;
-       qo_free_dqinfo_t                qo_free_dqinfo;
-       qo_mod_dquot_byino_t            qo_mod_dquot_byino;
-       qo_apply_dquot_deltas_t         qo_apply_dquot_deltas;
-       qo_reserve_quota_nblks_t        qo_reserve_quota_nblks;
-       qo_reserve_quota_bydquots_t     qo_reserve_quota_bydquots;
-       qo_unreserve_and_mod_dquots_t   qo_unreserve_and_mod_dquots;
-} xfs_dqtrxops_t;
-
-#define XFS_DQTRXOP(mp, tp, op, args...) \
-               ((mp)->m_qm_ops->xfs_dqtrxops ? \
-               ((mp)->m_qm_ops->xfs_dqtrxops->op)(tp, ## args) : 0)
-
-#define XFS_DQTRXOP_VOID(mp, tp, op, args...) \
-               ((mp)->m_qm_ops->xfs_dqtrxops ? \
-               ((mp)->m_qm_ops->xfs_dqtrxops->op)(tp, ## args) : (void)0)
-
-#define XFS_TRANS_DUP_DQINFO(mp, otp, ntp) \
-       XFS_DQTRXOP_VOID(mp, otp, qo_dup_dqinfo, ntp)
-#define XFS_TRANS_FREE_DQINFO(mp, tp) \
-       XFS_DQTRXOP_VOID(mp, tp, qo_free_dqinfo)
-#define XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, field, delta) \
-       XFS_DQTRXOP_VOID(mp, tp, qo_mod_dquot_byino, ip, field, delta)
-#define XFS_TRANS_APPLY_DQUOT_DELTAS(mp, tp) \
-       XFS_DQTRXOP_VOID(mp, tp, qo_apply_dquot_deltas)
-#define XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, nblks, ninos, fl) \
-       XFS_DQTRXOP(mp, tp, qo_reserve_quota_nblks, mp, ip, nblks, ninos, fl)
-#define XFS_TRANS_RESERVE_QUOTA_BYDQUOTS(mp, tp, ud, gd, nb, ni, fl) \
-       XFS_DQTRXOP(mp, tp, qo_reserve_quota_bydquots, mp, ud, gd, nb, ni, fl)
-#define XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(mp, tp) \
-       XFS_DQTRXOP_VOID(mp, tp, qo_unreserve_and_mod_dquots)
-
-#define XFS_TRANS_UNRESERVE_QUOTA_NBLKS(mp, tp, ip, nblks, ninos, flags) \
-       XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, -(nblks), -(ninos), flags)
-#define XFS_TRANS_RESERVE_QUOTA(mp, tp, ud, gd, nb, ni, f) \
-       XFS_TRANS_RESERVE_QUOTA_BYDQUOTS(mp, tp, ud, gd, nb, ni, \
-                               f | XFS_QMOPT_RES_REGBLKS)
-#define XFS_TRANS_UNRESERVE_QUOTA(mp, tp, ud, gd, nb, ni, f) \
-       XFS_TRANS_RESERVE_QUOTA_BYDQUOTS(mp, tp, ud, gd, -(nb), -(ni), \
+#ifdef CONFIG_XFS_QUOTA
+extern void xfs_trans_dup_dqinfo(struct xfs_trans *, struct xfs_trans *);
+extern void xfs_trans_free_dqinfo(struct xfs_trans *);
+extern void xfs_trans_mod_dquot_byino(struct xfs_trans *, struct xfs_inode *,
+               uint, long);
+extern void xfs_trans_apply_dquot_deltas(struct xfs_trans *);
+extern void xfs_trans_unreserve_and_mod_dquots(struct xfs_trans *);
+extern int xfs_trans_reserve_quota_nblks(struct xfs_trans *,
+               struct xfs_inode *, long, long, uint);
+extern int xfs_trans_reserve_quota_bydquots(struct xfs_trans *,
+               struct xfs_mount *, struct xfs_dquot *,
+               struct xfs_dquot *, long, long, uint);
+
+extern int xfs_qm_vop_dqalloc(struct xfs_inode *, uid_t, gid_t, prid_t, uint,
+               struct xfs_dquot **, struct xfs_dquot **);
+extern void xfs_qm_vop_create_dqattach(struct xfs_trans *, struct xfs_inode *,
+               struct xfs_dquot *, struct xfs_dquot *);
+extern int xfs_qm_vop_rename_dqattach(struct xfs_inode **);
+extern struct xfs_dquot *xfs_qm_vop_chown(struct xfs_trans *,
+               struct xfs_inode *, struct xfs_dquot **, struct xfs_dquot *);
+extern int xfs_qm_vop_chown_reserve(struct xfs_trans *, struct xfs_inode *,
+               struct xfs_dquot *, struct xfs_dquot *, uint);
+extern int xfs_qm_dqattach(struct xfs_inode *, uint);
+extern int xfs_qm_dqattach_locked(struct xfs_inode *, uint);
+extern void xfs_qm_dqdetach(struct xfs_inode *);
+extern void xfs_qm_dqrele(struct xfs_dquot *);
+extern void xfs_qm_statvfs(struct xfs_inode *, struct kstatfs *);
+extern int xfs_qm_sync(struct xfs_mount *, int);
+extern int xfs_qm_newmount(struct xfs_mount *, uint *, uint *);
+extern void xfs_qm_mount_quotas(struct xfs_mount *);
+extern void xfs_qm_unmount(struct xfs_mount *);
+extern void xfs_qm_unmount_quotas(struct xfs_mount *);
+
+#else
+static inline int
+xfs_qm_vop_dqalloc(struct xfs_inode *ip, uid_t uid, gid_t gid, prid_t prid,
+               uint flags, struct xfs_dquot **udqp, struct xfs_dquot **gdqp)
+{
+       *udqp = NULL;
+       *gdqp = NULL;
+       return 0;
+}
+#define xfs_trans_dup_dqinfo(tp, tp2)
+#define xfs_trans_free_dqinfo(tp)
+#define xfs_trans_mod_dquot_byino(tp, ip, fields, delta)
+#define xfs_trans_apply_dquot_deltas(tp)
+#define xfs_trans_unreserve_and_mod_dquots(tp)
+#define xfs_trans_reserve_quota_nblks(tp, ip, nblks, ninos, flags)     (0)
+#define xfs_trans_reserve_quota_bydquots(tp, mp, u, g, nb, ni, fl)     (0)
+#define xfs_qm_vop_create_dqattach(tp, ip, u, g)
+#define xfs_qm_vop_rename_dqattach(it)                                 (0)
+#define xfs_qm_vop_chown(tp, ip, old, new)                             (NULL)
+#define xfs_qm_vop_chown_reserve(tp, ip, u, g, fl)                     (0)
+#define xfs_qm_dqattach(ip, fl)                                                (0)
+#define xfs_qm_dqattach_locked(ip, fl)                                 (0)
+#define xfs_qm_dqdetach(ip)
+#define xfs_qm_dqrele(d)
+#define xfs_qm_statvfs(ip, s)
+#define xfs_qm_sync(mp, fl)                                            (0)
+#define xfs_qm_newmount(mp, a, b)                                      (0)
+#define xfs_qm_mount_quotas(mp)
+#define xfs_qm_unmount(mp)
+#define xfs_qm_unmount_quotas(mp)                                      (0)
+#endif /* CONFIG_XFS_QUOTA */
+
+#define xfs_trans_unreserve_quota_nblks(tp, ip, nblks, ninos, flags) \
+       xfs_trans_reserve_quota_nblks(tp, ip, -(nblks), -(ninos), flags)
+#define xfs_trans_reserve_quota(tp, mp, ud, gd, nb, ni, f) \
+       xfs_trans_reserve_quota_bydquots(tp, mp, ud, gd, nb, ni, \
                                f | XFS_QMOPT_RES_REGBLKS)
 
 extern int xfs_qm_dqcheck(xfs_disk_dquot_t *, xfs_dqid_t, uint, uint, char *);
 extern int xfs_mount_reset_sbqflags(struct xfs_mount *);
 
-extern struct xfs_qmops xfs_qmcore_xfs;
-
 #endif /* __KERNEL__ */
-
 #endif /* __XFS_QUOTA_H__ */
index 58f85e9cd11d4c90c5d4cae03b35539a181f0da9..b81deea0ce1944ec4f34e0a1b020128274eaf4e4 100644 (file)
@@ -166,7 +166,8 @@ xfs_rename(
        /*
         * Attach the dquots to the inodes
         */
-       if ((error = XFS_QM_DQVOPRENAME(mp, inodes))) {
+       error = xfs_qm_vop_rename_dqattach(inodes);
+       if (error) {
                xfs_trans_cancel(tp, cancel_flags);
                goto std_return;
        }
index 36f3a21c54d295aa835ebabe3f13a390696482c7..fea68615ed23bdd65d1953ec6d4d8907c57046f1 100644 (file)
@@ -41,7 +41,6 @@
 #include "xfs_ialloc.h"
 #include "xfs_attr.h"
 #include "xfs_bmap.h"
-#include "xfs_acl.h"
 #include "xfs_error.h"
 #include "xfs_buf_item.h"
 #include "xfs_rw.h"
index bcc39d358ad3963e5a9d304d39c178a1df0f15b3..66b849358e62d16e9a01fc307bc5a03dc1605ffb 100644 (file)
@@ -297,7 +297,7 @@ xfs_trans_dup(
        tp->t_rtx_res = tp->t_rtx_res_used;
        ntp->t_pflags = tp->t_pflags;
 
-       XFS_TRANS_DUP_DQINFO(tp->t_mountp, tp, ntp);
+       xfs_trans_dup_dqinfo(tp, ntp);
 
        atomic_inc(&tp->t_mountp->m_active_trans);
        return ntp;
@@ -829,7 +829,7 @@ shut_us_down:
                 * means is that we have some (non-persistent) quota
                 * reservations that need to be unreserved.
                 */
-               XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(mp, tp);
+               xfs_trans_unreserve_and_mod_dquots(tp);
                if (tp->t_ticket) {
                        commit_lsn = xfs_log_done(mp, tp->t_ticket,
                                                        NULL, log_flags);
@@ -848,10 +848,9 @@ shut_us_down:
        /*
         * If we need to update the superblock, then do it now.
         */
-       if (tp->t_flags & XFS_TRANS_SB_DIRTY) {
+       if (tp->t_flags & XFS_TRANS_SB_DIRTY)
                xfs_trans_apply_sb_deltas(tp);
-       }
-       XFS_TRANS_APPLY_DQUOT_DELTAS(mp, tp);
+       xfs_trans_apply_dquot_deltas(tp);
 
        /*
         * Ask each log item how many log_vector entries it will
@@ -1056,7 +1055,7 @@ xfs_trans_uncommit(
        }
 
        xfs_trans_unreserve_and_mod_sb(tp);
-       XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(tp->t_mountp, tp);
+       xfs_trans_unreserve_and_mod_dquots(tp);
 
        xfs_trans_free_items(tp, flags);
        xfs_trans_free_busy(tp);
@@ -1181,7 +1180,7 @@ xfs_trans_cancel(
        }
 #endif
        xfs_trans_unreserve_and_mod_sb(tp);
-       XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(mp, tp);
+       xfs_trans_unreserve_and_mod_dquots(tp);
 
        if (tp->t_ticket) {
                if (flags & XFS_TRANS_RELEASE_LOG_RES) {
@@ -1211,7 +1210,7 @@ xfs_trans_free(
        xfs_trans_t     *tp)
 {
        atomic_dec(&tp->t_mountp->m_active_trans);
-       XFS_TRANS_FREE_DQINFO(tp->t_mountp, tp);
+       xfs_trans_free_dqinfo(tp);
        kmem_zone_free(xfs_trans_zone, tp);
 }
 
index 79b9e5ea53590c25f8fd85797202653124ae35f7..4d88616bde914ea4fe07696a30fdbd81fca878fa 100644 (file)
@@ -166,7 +166,7 @@ xfs_dir_ialloc(
                        xfs_buf_relse(ialloc_context);
                        if (dqinfo) {
                                tp->t_dqinfo = dqinfo;
-                               XFS_TRANS_FREE_DQINFO(tp->t_mountp, tp);
+                               xfs_trans_free_dqinfo(tp);
                        }
                        *tpp = ntp;
                        *ipp = NULL;
index 19cf90a9c762841dc8b189676cb684ee4304946f..c4eca5ed5dabf81d6c0133294a1f6dbad73d2a4a 100644 (file)
@@ -42,6 +42,7 @@
 #include "xfs_ialloc.h"
 #include "xfs_alloc.h"
 #include "xfs_bmap.h"
+#include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_rw.h"
 #include "xfs_error.h"
@@ -118,7 +119,7 @@ xfs_setattr(
                 */
                ASSERT(udqp == NULL);
                ASSERT(gdqp == NULL);
-               code = XFS_QM_DQVOPALLOC(mp, ip, uid, gid, ip->i_d.di_projid,
+               code = xfs_qm_vop_dqalloc(ip, uid, gid, ip->i_d.di_projid,
                                         qflags, &udqp, &gdqp);
                if (code)
                        return code;
@@ -180,10 +181,11 @@ xfs_setattr(
                 * Do a quota reservation only if uid/gid is actually
                 * going to change.
                 */
-               if ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) ||
-                   (XFS_IS_GQUOTA_ON(mp) && igid != gid)) {
+               if (XFS_IS_QUOTA_RUNNING(mp) &&
+                   ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) ||
+                    (XFS_IS_GQUOTA_ON(mp) && igid != gid))) {
                        ASSERT(tp);
-                       code = XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, udqp, gdqp,
+                       code = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp,
                                                capable(CAP_FOWNER) ?
                                                XFS_QMOPT_FORCE_RES : 0);
                        if (code)       /* out of quota */
@@ -217,7 +219,7 @@ xfs_setattr(
                /*
                 * Make sure that the dquots are attached to the inode.
                 */
-               code = XFS_QM_DQATTACH(mp, ip, XFS_QMOPT_ILOCKED);
+               code = xfs_qm_dqattach_locked(ip, 0);
                if (code)
                        goto error_return;
 
@@ -351,21 +353,21 @@ xfs_setattr(
                 * in the transaction.
                 */
                if (iuid != uid) {
-                       if (XFS_IS_UQUOTA_ON(mp)) {
+                       if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_UQUOTA_ON(mp)) {
                                ASSERT(mask & ATTR_UID);
                                ASSERT(udqp);
-                               olddquot1 = XFS_QM_DQVOPCHOWN(mp, tp, ip,
+                               olddquot1 = xfs_qm_vop_chown(tp, ip,
                                                        &ip->i_udquot, udqp);
                        }
                        ip->i_d.di_uid = uid;
                        inode->i_uid = uid;
                }
                if (igid != gid) {
-                       if (XFS_IS_GQUOTA_ON(mp)) {
+                       if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_GQUOTA_ON(mp)) {
                                ASSERT(!XFS_IS_PQUOTA_ON(mp));
                                ASSERT(mask & ATTR_GID);
                                ASSERT(gdqp);
-                               olddquot2 = XFS_QM_DQVOPCHOWN(mp, tp, ip,
+                               olddquot2 = xfs_qm_vop_chown(tp, ip,
                                                        &ip->i_gdquot, gdqp);
                        }
                        ip->i_d.di_gid = gid;
@@ -461,13 +463,25 @@ xfs_setattr(
        /*
         * Release any dquot(s) the inode had kept before chown.
         */
-       XFS_QM_DQRELE(mp, olddquot1);
-       XFS_QM_DQRELE(mp, olddquot2);
-       XFS_QM_DQRELE(mp, udqp);
-       XFS_QM_DQRELE(mp, gdqp);
+       xfs_qm_dqrele(olddquot1);
+       xfs_qm_dqrele(olddquot2);
+       xfs_qm_dqrele(udqp);
+       xfs_qm_dqrele(gdqp);
 
-       if (code) {
+       if (code)
                return code;
+
+       /*
+        * XXX(hch): Updating the ACL entries is not atomic vs the i_mode
+        *           update.  We could avoid this with linked transactions
+        *           and passing down the transaction pointer all the way
+        *           to attr_set.  No previous user of the generic
+        *           Posix ACL code seems to care about this issue either.
+        */
+       if ((mask & ATTR_MODE) && !(flags & XFS_ATTR_NOACL)) {
+               code = -xfs_acl_chmod(inode);
+               if (code)
+                       return XFS_ERROR(code);
        }
 
        if (DM_EVENT_ENABLED(ip, DM_EVENT_ATTRIBUTE) &&
@@ -482,8 +496,8 @@ xfs_setattr(
        commit_flags |= XFS_TRANS_ABORT;
        /* FALLTHROUGH */
  error_return:
-       XFS_QM_DQRELE(mp, udqp);
-       XFS_QM_DQRELE(mp, gdqp);
+       xfs_qm_dqrele(udqp);
+       xfs_qm_dqrele(gdqp);
        if (tp) {
                xfs_trans_cancel(tp, commit_flags);
        }
@@ -739,7 +753,8 @@ xfs_free_eofblocks(
                /*
                 * Attach the dquots to the inode up front.
                 */
-               if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
+               error = xfs_qm_dqattach(ip, 0);
+               if (error)
                        return error;
 
                /*
@@ -1181,7 +1196,8 @@ xfs_inactive(
 
        ASSERT(ip->i_d.di_nlink == 0);
 
-       if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
+       error = xfs_qm_dqattach(ip, 0);
+       if (error)
                return VN_INACTIVE_CACHE;
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
@@ -1307,7 +1323,7 @@ xfs_inactive(
                /*
                 * Credit the quota account(s). The inode is gone.
                 */
-               XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, XFS_TRANS_DQ_ICOUNT, -1);
+               xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_ICOUNT, -1);
 
                /*
                 * Just ignore errors at this point.  There is nothing we can
@@ -1323,11 +1339,11 @@ xfs_inactive(
                        xfs_fs_cmn_err(CE_NOTE, mp, "xfs_inactive: "
                                "xfs_trans_commit() returned error %d", error);
        }
+
        /*
         * Release the dquots held by inode, if any.
         */
-       XFS_QM_DQDETACH(mp, ip);
-
+       xfs_qm_dqdetach(ip);
        xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
 
  out:
@@ -1427,8 +1443,7 @@ xfs_create(
        /*
         * Make sure that we have allocated dquot(s) on disk.
         */
-       error = XFS_QM_DQVOPALLOC(mp, dp,
-                       current_fsuid(), current_fsgid(), prid,
+       error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
                        XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
        if (error)
                goto std_return;
@@ -1489,7 +1504,7 @@ xfs_create(
        /*
         * Reserve disk quota and the inode.
         */
-       error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0);
+       error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp, resblks, 1, 0);
        if (error)
                goto out_trans_cancel;
 
@@ -1561,7 +1576,7 @@ xfs_create(
         * These ids of the inode couldn't have changed since the new
         * inode has been locked ever since it was created.
         */
-       XFS_QM_DQVOPCREATE(mp, tp, ip, udqp, gdqp);
+       xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp);
 
        /*
         * xfs_trans_commit normally decrements the vnode ref count
@@ -1580,8 +1595,8 @@ xfs_create(
                goto out_dqrele;
        }
 
-       XFS_QM_DQRELE(mp, udqp);
-       XFS_QM_DQRELE(mp, gdqp);
+       xfs_qm_dqrele(udqp);
+       xfs_qm_dqrele(gdqp);
 
        *ipp = ip;
 
@@ -1602,8 +1617,8 @@ xfs_create(
  out_trans_cancel:
        xfs_trans_cancel(tp, cancel_flags);
  out_dqrele:
-       XFS_QM_DQRELE(mp, udqp);
-       XFS_QM_DQRELE(mp, gdqp);
+       xfs_qm_dqrele(udqp);
+       xfs_qm_dqrele(gdqp);
 
        if (unlock_dp_on_error)
                xfs_iunlock(dp, XFS_ILOCK_EXCL);
@@ -1837,11 +1852,11 @@ xfs_remove(
                        return error;
        }
 
-       error = XFS_QM_DQATTACH(mp, dp, 0);
+       error = xfs_qm_dqattach(dp, 0);
        if (error)
                goto std_return;
 
-       error = XFS_QM_DQATTACH(mp, ip, 0);
+       error = xfs_qm_dqattach(ip, 0);
        if (error)
                goto std_return;
 
@@ -2028,11 +2043,11 @@ xfs_link(
 
        /* Return through std_return after this point. */
 
-       error = XFS_QM_DQATTACH(mp, sip, 0);
+       error = xfs_qm_dqattach(sip, 0);
        if (error)
                goto std_return;
 
-       error = XFS_QM_DQATTACH(mp, tdp, 0);
+       error = xfs_qm_dqattach(tdp, 0);
        if (error)
                goto std_return;
 
@@ -2205,8 +2220,7 @@ xfs_symlink(
        /*
         * Make sure that we have allocated dquot(s) on disk.
         */
-       error = XFS_QM_DQVOPALLOC(mp, dp,
-                       current_fsuid(), current_fsgid(), prid,
+       error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
                        XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
        if (error)
                goto std_return;
@@ -2248,7 +2262,7 @@ xfs_symlink(
        /*
         * Reserve disk quota : blocks and inode.
         */
-       error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0);
+       error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp, resblks, 1, 0);
        if (error)
                goto error_return;
 
@@ -2288,7 +2302,7 @@ xfs_symlink(
        /*
         * Also attach the dquot(s) to it, if applicable.
         */
-       XFS_QM_DQVOPCREATE(mp, tp, ip, udqp, gdqp);
+       xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp);
 
        if (resblks)
                resblks -= XFS_IALLOC_SPACE_RES(mp);
@@ -2376,8 +2390,8 @@ xfs_symlink(
                goto error2;
        }
        error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
-       XFS_QM_DQRELE(mp, udqp);
-       XFS_QM_DQRELE(mp, gdqp);
+       xfs_qm_dqrele(udqp);
+       xfs_qm_dqrele(gdqp);
 
        /* Fall through to std_return with error = 0 or errno from
         * xfs_trans_commit     */
@@ -2401,8 +2415,8 @@ std_return:
        cancel_flags |= XFS_TRANS_ABORT;
  error_return:
        xfs_trans_cancel(tp, cancel_flags);
-       XFS_QM_DQRELE(mp, udqp);
-       XFS_QM_DQRELE(mp, gdqp);
+       xfs_qm_dqrele(udqp);
+       xfs_qm_dqrele(gdqp);
 
        if (unlock_dp_on_error)
                xfs_iunlock(dp, XFS_ILOCK_EXCL);
@@ -2541,7 +2555,8 @@ xfs_alloc_file_space(
        if (XFS_FORCED_SHUTDOWN(mp))
                return XFS_ERROR(EIO);
 
-       if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
+       error = xfs_qm_dqattach(ip, 0);
+       if (error)
                return error;
 
        if (len <= 0)
@@ -2628,8 +2643,8 @@ retry:
                        break;
                }
                xfs_ilock(ip, XFS_ILOCK_EXCL);
-               error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip,
-                                                     qblocks, 0, quota_flag);
+               error = xfs_trans_reserve_quota_nblks(tp, ip, qblocks,
+                                                     0, quota_flag);
                if (error)
                        goto error1;
 
@@ -2688,7 +2703,7 @@ dmapi_enospc_check:
 
 error0:        /* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */
        xfs_bmap_cancel(&free_list);
-       XFS_TRANS_UNRESERVE_QUOTA_NBLKS(mp, tp, ip, qblocks, 0, quota_flag);
+       xfs_trans_unreserve_quota_nblks(tp, ip, qblocks, 0, quota_flag);
 
 error1:        /* Just cancel transaction */
        xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
@@ -2827,7 +2842,8 @@ xfs_free_file_space(
 
        xfs_itrace_entry(ip);
 
-       if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
+       error = xfs_qm_dqattach(ip, 0);
+       if (error)
                return error;
 
        error = 0;
@@ -2953,9 +2969,9 @@ xfs_free_file_space(
                        break;
                }
                xfs_ilock(ip, XFS_ILOCK_EXCL);
-               error = XFS_TRANS_RESERVE_QUOTA(mp, tp,
-                               ip->i_udquot, ip->i_gdquot, resblks, 0,
-                               XFS_QMOPT_RES_REGBLKS);
+               error = xfs_trans_reserve_quota(tp, mp,
+                               ip->i_udquot, ip->i_gdquot,
+                               resblks, 0, XFS_QMOPT_RES_REGBLKS);
                if (error)
                        goto error1;
 
index 04373c6c61ff83f71d49df2f3f4250e7eb81f56d..a9e102de71a19c35d1bac05181b910d496e180fa 100644 (file)
@@ -18,6 +18,7 @@ int xfs_setattr(struct xfs_inode *ip, struct iattr *vap, int flags);
 #define        XFS_ATTR_DMI            0x01    /* invocation from a DMI function */
 #define        XFS_ATTR_NONBLOCK       0x02    /* return EAGAIN if operation would block */
 #define XFS_ATTR_NOLOCK                0x04    /* Don't grab any conflicting locks */
+#define XFS_ATTR_NOACL         0x08    /* Don't call xfs_acl_chmod */
 
 int xfs_readlink(struct xfs_inode *ip, char *link);
 int xfs_fsync(struct xfs_inode *ip);
index 4c9932a2503f9d465caa909f5475b9ba5e6cc194..eb62334cda2978489d6bd3fa8bad130ac885d335 100644 (file)
@@ -1,11 +1,33 @@
+header-y += auxvec.h
+header-y += bitsperlong.h
 header-y += errno-base.h
 header-y += errno.h
 header-y += fcntl.h
 header-y += ioctl.h
+header-y += ioctls.h
+header-y += ipcbuf.h
+header-y += mman-common.h
 header-y += mman.h
+header-y += msgbuf.h
+header-y += param.h
 header-y += poll.h
+header-y += posix_types.h
+header-y += sembuf.h
+header-y += setup.h
+header-y += shmbuf.h
+header-y += shmparam.h
+header-y += signal-defs.h
 header-y += signal.h
+header-y += socket.h
+header-y += sockios.h
+header-y += stat.h
 header-y += statfs.h
+header-y += swab.h
+header-y += termbits.h
+header-y += termios.h
+header-y += types.h
+header-y += ucontext.h
+header-y += unistd.h
 
 unifdef-y += int-l64.h
 unifdef-y += int-ll64.h
index 70d185534b9de84dc5340862250a5cbc6b441eb5..290910e4ede4a7412b0d4f21a5a400163f68b9c2 100644 (file)
@@ -9,6 +9,7 @@ unifdef-y += a.out.h
 endif
 unifdef-y += auxvec.h
 unifdef-y += byteorder.h
+unifdef-y += bitsperlong.h
 unifdef-y += errno.h
 unifdef-y += fcntl.h
 unifdef-y += ioctl.h
diff --git a/include/asm-generic/atomic-long.h b/include/asm-generic/atomic-long.h
new file mode 100644 (file)
index 0000000..b7babf0
--- /dev/null
@@ -0,0 +1,258 @@
+#ifndef _ASM_GENERIC_ATOMIC_LONG_H
+#define _ASM_GENERIC_ATOMIC_LONG_H
+/*
+ * Copyright (C) 2005 Silicon Graphics, Inc.
+ *     Christoph Lameter
+ *
+ * Allows to provide arch independent atomic definitions without the need to
+ * edit all arch specific atomic.h files.
+ */
+
+#include <asm/types.h>
+
+/*
+ * Suppport for atomic_long_t
+ *
+ * Casts for parameters are avoided for existing atomic functions in order to
+ * avoid issues with cast-as-lval under gcc 4.x and other limitations that the
+ * macros of a platform may have.
+ */
+
+#if BITS_PER_LONG == 64
+
+typedef atomic64_t atomic_long_t;
+
+#define ATOMIC_LONG_INIT(i)    ATOMIC64_INIT(i)
+
+static inline long atomic_long_read(atomic_long_t *l)
+{
+       atomic64_t *v = (atomic64_t *)l;
+
+       return (long)atomic64_read(v);
+}
+
+static inline void atomic_long_set(atomic_long_t *l, long i)
+{
+       atomic64_t *v = (atomic64_t *)l;
+
+       atomic64_set(v, i);
+}
+
+static inline void atomic_long_inc(atomic_long_t *l)
+{
+       atomic64_t *v = (atomic64_t *)l;
+
+       atomic64_inc(v);
+}
+
+static inline void atomic_long_dec(atomic_long_t *l)
+{
+       atomic64_t *v = (atomic64_t *)l;
+
+       atomic64_dec(v);
+}
+
+static inline void atomic_long_add(long i, atomic_long_t *l)
+{
+       atomic64_t *v = (atomic64_t *)l;
+
+       atomic64_add(i, v);
+}
+
+static inline void atomic_long_sub(long i, atomic_long_t *l)
+{
+       atomic64_t *v = (atomic64_t *)l;
+
+       atomic64_sub(i, v);
+}
+
+static inline int atomic_long_sub_and_test(long i, atomic_long_t *l)
+{
+       atomic64_t *v = (atomic64_t *)l;
+
+       return atomic64_sub_and_test(i, v);
+}
+
+static inline int atomic_long_dec_and_test(atomic_long_t *l)
+{
+       atomic64_t *v = (atomic64_t *)l;
+
+       return atomic64_dec_and_test(v);
+}
+
+static inline int atomic_long_inc_and_test(atomic_long_t *l)
+{
+       atomic64_t *v = (atomic64_t *)l;
+
+       return atomic64_inc_and_test(v);
+}
+
+static inline int atomic_long_add_negative(long i, atomic_long_t *l)
+{
+       atomic64_t *v = (atomic64_t *)l;
+
+       return atomic64_add_negative(i, v);
+}
+
+static inline long atomic_long_add_return(long i, atomic_long_t *l)
+{
+       atomic64_t *v = (atomic64_t *)l;
+
+       return (long)atomic64_add_return(i, v);
+}
+
+static inline long atomic_long_sub_return(long i, atomic_long_t *l)
+{
+       atomic64_t *v = (atomic64_t *)l;
+
+       return (long)atomic64_sub_return(i, v);
+}
+
+static inline long atomic_long_inc_return(atomic_long_t *l)
+{
+       atomic64_t *v = (atomic64_t *)l;
+
+       return (long)atomic64_inc_return(v);
+}
+
+static inline long atomic_long_dec_return(atomic_long_t *l)
+{
+       atomic64_t *v = (atomic64_t *)l;
+
+       return (long)atomic64_dec_return(v);
+}
+
+static inline long atomic_long_add_unless(atomic_long_t *l, long a, long u)
+{
+       atomic64_t *v = (atomic64_t *)l;
+
+       return (long)atomic64_add_unless(v, a, u);
+}
+
+#define atomic_long_inc_not_zero(l) atomic64_inc_not_zero((atomic64_t *)(l))
+
+#define atomic_long_cmpxchg(l, old, new) \
+       (atomic64_cmpxchg((atomic64_t *)(l), (old), (new)))
+#define atomic_long_xchg(v, new) \
+       (atomic64_xchg((atomic64_t *)(v), (new)))
+
+#else  /*  BITS_PER_LONG == 64  */
+
+typedef atomic_t atomic_long_t;
+
+#define ATOMIC_LONG_INIT(i)    ATOMIC_INIT(i)
+static inline long atomic_long_read(atomic_long_t *l)
+{
+       atomic_t *v = (atomic_t *)l;
+
+       return (long)atomic_read(v);
+}
+
+static inline void atomic_long_set(atomic_long_t *l, long i)
+{
+       atomic_t *v = (atomic_t *)l;
+
+       atomic_set(v, i);
+}
+
+static inline void atomic_long_inc(atomic_long_t *l)
+{
+       atomic_t *v = (atomic_t *)l;
+
+       atomic_inc(v);
+}
+
+static inline void atomic_long_dec(atomic_long_t *l)
+{
+       atomic_t *v = (atomic_t *)l;
+
+       atomic_dec(v);
+}
+
+static inline void atomic_long_add(long i, atomic_long_t *l)
+{
+       atomic_t *v = (atomic_t *)l;
+
+       atomic_add(i, v);
+}
+
+static inline void atomic_long_sub(long i, atomic_long_t *l)
+{
+       atomic_t *v = (atomic_t *)l;
+
+       atomic_sub(i, v);
+}
+
+static inline int atomic_long_sub_and_test(long i, atomic_long_t *l)
+{
+       atomic_t *v = (atomic_t *)l;
+
+       return atomic_sub_and_test(i, v);
+}
+
+static inline int atomic_long_dec_and_test(atomic_long_t *l)
+{
+       atomic_t *v = (atomic_t *)l;
+
+       return atomic_dec_and_test(v);
+}
+
+static inline int atomic_long_inc_and_test(atomic_long_t *l)
+{
+       atomic_t *v = (atomic_t *)l;
+
+       return atomic_inc_and_test(v);
+}
+
+static inline int atomic_long_add_negative(long i, atomic_long_t *l)
+{
+       atomic_t *v = (atomic_t *)l;
+
+       return atomic_add_negative(i, v);
+}
+
+static inline long atomic_long_add_return(long i, atomic_long_t *l)
+{
+       atomic_t *v = (atomic_t *)l;
+
+       return (long)atomic_add_return(i, v);
+}
+
+static inline long atomic_long_sub_return(long i, atomic_long_t *l)
+{
+       atomic_t *v = (atomic_t *)l;
+
+       return (long)atomic_sub_return(i, v);
+}
+
+static inline long atomic_long_inc_return(atomic_long_t *l)
+{
+       atomic_t *v = (atomic_t *)l;
+
+       return (long)atomic_inc_return(v);
+}
+
+static inline long atomic_long_dec_return(atomic_long_t *l)
+{
+       atomic_t *v = (atomic_t *)l;
+
+       return (long)atomic_dec_return(v);
+}
+
+static inline long atomic_long_add_unless(atomic_long_t *l, long a, long u)
+{
+       atomic_t *v = (atomic_t *)l;
+
+       return (long)atomic_add_unless(v, a, u);
+}
+
+#define atomic_long_inc_not_zero(l) atomic_inc_not_zero((atomic_t *)(l))
+
+#define atomic_long_cmpxchg(l, old, new) \
+       (atomic_cmpxchg((atomic_t *)(l), (old), (new)))
+#define atomic_long_xchg(v, new) \
+       (atomic_xchg((atomic_t *)(v), (new)))
+
+#endif  /*  BITS_PER_LONG == 64  */
+
+#endif  /*  _ASM_GENERIC_ATOMIC_LONG_H  */
index 81d3be459efb55e931662ad492c072749538d5e8..c99c64dc5f3dcfe1a9fbf192c44f30bf84a47ea9 100644 (file)
-#ifndef _ASM_GENERIC_ATOMIC_H
-#define _ASM_GENERIC_ATOMIC_H
 /*
- * Copyright (C) 2005 Silicon Graphics, Inc.
- *     Christoph Lameter
+ * Generic C implementation of atomic counter operations
+ * Originally implemented for MN10300.
  *
- * Allows to provide arch independent atomic definitions without the need to
- * edit all arch specific atomic.h files.
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
  */
+#ifndef __ASM_GENERIC_ATOMIC_H
+#define __ASM_GENERIC_ATOMIC_H
 
-#include <asm/types.h>
+#ifdef CONFIG_SMP
+#error not SMP safe
+#endif
 
 /*
- * Suppport for atomic_long_t
- *
- * Casts for parameters are avoided for existing atomic functions in order to
- * avoid issues with cast-as-lval under gcc 4.x and other limitations that the
- * macros of a platform may have.
+ * Atomic operations that C can't guarantee us.  Useful for
+ * resource counting etc..
  */
 
-#if BITS_PER_LONG == 64
-
-typedef atomic64_t atomic_long_t;
-
-#define ATOMIC_LONG_INIT(i)    ATOMIC64_INIT(i)
+#define ATOMIC_INIT(i) { (i) }
 
-static inline long atomic_long_read(atomic_long_t *l)
-{
-       atomic64_t *v = (atomic64_t *)l;
-
-       return (long)atomic64_read(v);
-}
-
-static inline void atomic_long_set(atomic_long_t *l, long i)
-{
-       atomic64_t *v = (atomic64_t *)l;
-
-       atomic64_set(v, i);
-}
-
-static inline void atomic_long_inc(atomic_long_t *l)
-{
-       atomic64_t *v = (atomic64_t *)l;
-
-       atomic64_inc(v);
-}
-
-static inline void atomic_long_dec(atomic_long_t *l)
-{
-       atomic64_t *v = (atomic64_t *)l;
-
-       atomic64_dec(v);
-}
-
-static inline void atomic_long_add(long i, atomic_long_t *l)
-{
-       atomic64_t *v = (atomic64_t *)l;
-
-       atomic64_add(i, v);
-}
-
-static inline void atomic_long_sub(long i, atomic_long_t *l)
-{
-       atomic64_t *v = (atomic64_t *)l;
-
-       atomic64_sub(i, v);
-}
-
-static inline int atomic_long_sub_and_test(long i, atomic_long_t *l)
-{
-       atomic64_t *v = (atomic64_t *)l;
-
-       return atomic64_sub_and_test(i, v);
-}
-
-static inline int atomic_long_dec_and_test(atomic_long_t *l)
-{
-       atomic64_t *v = (atomic64_t *)l;
-
-       return atomic64_dec_and_test(v);
-}
-
-static inline int atomic_long_inc_and_test(atomic_long_t *l)
-{
-       atomic64_t *v = (atomic64_t *)l;
-
-       return atomic64_inc_and_test(v);
-}
-
-static inline int atomic_long_add_negative(long i, atomic_long_t *l)
-{
-       atomic64_t *v = (atomic64_t *)l;
-
-       return atomic64_add_negative(i, v);
-}
-
-static inline long atomic_long_add_return(long i, atomic_long_t *l)
-{
-       atomic64_t *v = (atomic64_t *)l;
-
-       return (long)atomic64_add_return(i, v);
-}
-
-static inline long atomic_long_sub_return(long i, atomic_long_t *l)
-{
-       atomic64_t *v = (atomic64_t *)l;
+#ifdef __KERNEL__
 
-       return (long)atomic64_sub_return(i, v);
-}
-
-static inline long atomic_long_inc_return(atomic_long_t *l)
-{
-       atomic64_t *v = (atomic64_t *)l;
-
-       return (long)atomic64_inc_return(v);
-}
-
-static inline long atomic_long_dec_return(atomic_long_t *l)
-{
-       atomic64_t *v = (atomic64_t *)l;
-
-       return (long)atomic64_dec_return(v);
-}
-
-static inline long atomic_long_add_unless(atomic_long_t *l, long a, long u)
-{
-       atomic64_t *v = (atomic64_t *)l;
-
-       return (long)atomic64_add_unless(v, a, u);
-}
-
-#define atomic_long_inc_not_zero(l) atomic64_inc_not_zero((atomic64_t *)(l))
-
-#define atomic_long_cmpxchg(l, old, new) \
-       (atomic64_cmpxchg((atomic64_t *)(l), (old), (new)))
-#define atomic_long_xchg(v, new) \
-       (atomic64_xchg((atomic64_t *)(v), (new)))
-
-#else  /*  BITS_PER_LONG == 64  */
-
-typedef atomic_t atomic_long_t;
-
-#define ATOMIC_LONG_INIT(i)    ATOMIC_INIT(i)
-static inline long atomic_long_read(atomic_long_t *l)
-{
-       atomic_t *v = (atomic_t *)l;
-
-       return (long)atomic_read(v);
-}
+/**
+ * atomic_read - read atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically reads the value of @v.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+#define atomic_read(v) ((v)->counter)
 
-static inline void atomic_long_set(atomic_long_t *l, long i)
-{
-       atomic_t *v = (atomic_t *)l;
+/**
+ * atomic_set - set atomic variable
+ * @v: pointer of type atomic_t
+ * @i: required value
+ *
+ * Atomically sets the value of @v to @i.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+#define atomic_set(v, i) (((v)->counter) = (i))
 
-       atomic_set(v, i);
-}
+#include <asm/system.h>
 
-static inline void atomic_long_inc(atomic_long_t *l)
+/**
+ * atomic_add_return - add integer to atomic variable
+ * @i: integer value to add
+ * @v: pointer of type atomic_t
+ *
+ * Atomically adds @i to @v and returns the result
+ * Note that the guaranteed useful range of an atomic_t is only 24 bits.
+ */
+static inline int atomic_add_return(int i, atomic_t *v)
 {
-       atomic_t *v = (atomic_t *)l;
-
-       atomic_inc(v);
-}
+       unsigned long flags;
+       int temp;
 
-static inline void atomic_long_dec(atomic_long_t *l)
-{
-       atomic_t *v = (atomic_t *)l;
+       local_irq_save(flags);
+       temp = v->counter;
+       temp += i;
+       v->counter = temp;
+       local_irq_restore(flags);
 
-       atomic_dec(v);
+       return temp;
 }
 
-static inline void atomic_long_add(long i, atomic_long_t *l)
+/**
+ * atomic_sub_return - subtract integer from atomic variable
+ * @i: integer value to subtract
+ * @v: pointer of type atomic_t
+ *
+ * Atomically subtracts @i from @v and returns the result
+ * Note that the guaranteed useful range of an atomic_t is only 24 bits.
+ */
+static inline int atomic_sub_return(int i, atomic_t *v)
 {
-       atomic_t *v = (atomic_t *)l;
-
-       atomic_add(i, v);
-}
+       unsigned long flags;
+       int temp;
 
-static inline void atomic_long_sub(long i, atomic_long_t *l)
-{
-       atomic_t *v = (atomic_t *)l;
+       local_irq_save(flags);
+       temp = v->counter;
+       temp -= i;
+       v->counter = temp;
+       local_irq_restore(flags);
 
-       atomic_sub(i, v);
+       return temp;
 }
 
-static inline int atomic_long_sub_and_test(long i, atomic_long_t *l)
+static inline int atomic_add_negative(int i, atomic_t *v)
 {
-       atomic_t *v = (atomic_t *)l;
-
-       return atomic_sub_and_test(i, v);
+       return atomic_add_return(i, v) < 0;
 }
 
-static inline int atomic_long_dec_and_test(atomic_long_t *l)
+static inline void atomic_add(int i, atomic_t *v)
 {
-       atomic_t *v = (atomic_t *)l;
-
-       return atomic_dec_and_test(v);
+       atomic_add_return(i, v);
 }
 
-static inline int atomic_long_inc_and_test(atomic_long_t *l)
+static inline void atomic_sub(int i, atomic_t *v)
 {
-       atomic_t *v = (atomic_t *)l;
-
-       return atomic_inc_and_test(v);
+       atomic_sub_return(i, v);
 }
 
-static inline int atomic_long_add_negative(long i, atomic_long_t *l)
+static inline void atomic_inc(atomic_t *v)
 {
-       atomic_t *v = (atomic_t *)l;
-
-       return atomic_add_negative(i, v);
+       atomic_add_return(1, v);
 }
 
-static inline long atomic_long_add_return(long i, atomic_long_t *l)
+static inline void atomic_dec(atomic_t *v)
 {
-       atomic_t *v = (atomic_t *)l;
-
-       return (long)atomic_add_return(i, v);
+       atomic_sub_return(1, v);
 }
 
-static inline long atomic_long_sub_return(long i, atomic_long_t *l)
-{
-       atomic_t *v = (atomic_t *)l;
+#define atomic_dec_return(v)           atomic_sub_return(1, (v))
+#define atomic_inc_return(v)           atomic_add_return(1, (v))
 
-       return (long)atomic_sub_return(i, v);
-}
+#define atomic_sub_and_test(i, v)      (atomic_sub_return((i), (v)) == 0)
+#define atomic_dec_and_test(v)         (atomic_sub_return(1, (v)) == 0)
+#define atomic_inc_and_test(v)         (atomic_add_return(1, (v)) == 0)
 
-static inline long atomic_long_inc_return(atomic_long_t *l)
-{
-       atomic_t *v = (atomic_t *)l;
+#define atomic_add_unless(v, a, u)                             \
+({                                                             \
+       int c, old;                                             \
+       c = atomic_read(v);                                     \
+       while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+               c = old;                                        \
+       c != (u);                                               \
+})
 
-       return (long)atomic_inc_return(v);
-}
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
-static inline long atomic_long_dec_return(atomic_long_t *l)
+static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
 {
-       atomic_t *v = (atomic_t *)l;
+       unsigned long flags;
 
-       return (long)atomic_dec_return(v);
+       mask = ~mask;
+       local_irq_save(flags);
+       *addr &= mask;
+       local_irq_restore(flags);
 }
 
-static inline long atomic_long_add_unless(atomic_long_t *l, long a, long u)
-{
-       atomic_t *v = (atomic_t *)l;
+#define atomic_xchg(ptr, v)            (xchg(&(ptr)->counter, (v)))
+#define atomic_cmpxchg(v, old, new)    (cmpxchg(&((v)->counter), (old), (new)))
 
-       return (long)atomic_add_unless(v, a, u);
-}
+#define cmpxchg_local(ptr, o, n)                                              \
+       ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
+                       (unsigned long)(n), sizeof(*(ptr))))
 
-#define atomic_long_inc_not_zero(l) atomic_inc_not_zero((atomic_t *)(l))
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
 
-#define atomic_long_cmpxchg(l, old, new) \
-       (atomic_cmpxchg((atomic_t *)(l), (old), (new)))
-#define atomic_long_xchg(v, new) \
-       (atomic_xchg((atomic_t *)(v), (new)))
+/* Assume that atomic operations are already serializing */
+#define smp_mb__before_atomic_dec()    barrier()
+#define smp_mb__after_atomic_dec()     barrier()
+#define smp_mb__before_atomic_inc()    barrier()
+#define smp_mb__after_atomic_inc()     barrier()
 
-#endif  /*  BITS_PER_LONG == 64  */
+#include <asm-generic/atomic-long.h>
 
-#endif  /*  _ASM_GENERIC_ATOMIC_H  */
+#endif /* __KERNEL__ */
+#endif /* __ASM_GENERIC_ATOMIC_H */
diff --git a/include/asm-generic/auxvec.h b/include/asm-generic/auxvec.h
new file mode 100644 (file)
index 0000000..b99573b
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __ASM_GENERIC_AUXVEC_H
+#define __ASM_GENERIC_AUXVEC_H
+/*
+ * Not all architectures need their own auxvec.h, the most
+ * common definitions are already in linux/auxvec.h.
+ */
+
+#endif /* __ASM_GENERIC_AUXVEC_H */
index c9f369c4bd7ed3d9fd2e65ff5ee65634d48cf77e..a54f4421a24d8bc738815fdf9c1c5884795a94f3 100644 (file)
@@ -1,19 +1,29 @@
-#ifndef _ASM_GENERIC_BITOPS_H_
-#define _ASM_GENERIC_BITOPS_H_
+#ifndef __ASM_GENERIC_BITOPS_H
+#define __ASM_GENERIC_BITOPS_H
 
 /*
  * For the benefit of those who are trying to port Linux to another
  * architecture, here are some C-language equivalents.  You should
  * recode these in the native assembly language, if at all possible.
- * 
+ *
  * C language equivalents written by Theodore Ts'o, 9/26/92
  */
 
-#include <asm-generic/bitops/atomic.h>
-#include <asm-generic/bitops/non-atomic.h>
+#include <linux/irqflags.h>
+#include <linux/compiler.h>
+
+/*
+ * clear_bit may not imply a memory barrier
+ */
+#ifndef smp_mb__before_clear_bit
+#define smp_mb__before_clear_bit()     smp_mb()
+#define smp_mb__after_clear_bit()      smp_mb()
+#endif
+
 #include <asm-generic/bitops/__ffs.h>
 #include <asm-generic/bitops/ffz.h>
 #include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/__fls.h>
 #include <asm-generic/bitops/fls64.h>
 #include <asm-generic/bitops/find.h>
 
 #include <asm-generic/bitops/hweight.h>
 #include <asm-generic/bitops/lock.h>
 
+#include <asm-generic/bitops/atomic.h>
+#include <asm-generic/bitops/non-atomic.h>
 #include <asm-generic/bitops/ext2-non-atomic.h>
 #include <asm-generic/bitops/ext2-atomic.h>
 #include <asm-generic/bitops/minix.h>
 
-#endif /* _ASM_GENERIC_BITOPS_H */
+#endif /* __ASM_GENERIC_BITOPS_H */
index 4657f3e410fce4a71ca7e7903f97e92a92676bd9..c8946465e63ac872113c74241e06028aba8086f3 100644 (file)
@@ -2,6 +2,7 @@
 #define _ASM_GENERIC_BITOPS_ATOMIC_H_
 
 #include <asm/types.h>
+#include <asm/system.h>
 
 #ifdef CONFIG_SMP
 #include <asm/spinlock.h>
diff --git a/include/asm-generic/bitsperlong.h b/include/asm-generic/bitsperlong.h
new file mode 100644 (file)
index 0000000..4ae54e0
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef __ASM_GENERIC_BITS_PER_LONG
+#define __ASM_GENERIC_BITS_PER_LONG
+
+/*
+ * There seems to be no way of detecting this automatically from user
+ * space, so 64 bit architectures should override this in their
+ * bitsperlong.h. In particular, an architecture that supports
+ * both 32 and 64 bit user space must not rely on CONFIG_64BIT
+ * to decide it, but rather check a compiler provided macro.
+ */
+#ifndef __BITS_PER_LONG
+#define __BITS_PER_LONG 32
+#endif
+
+#ifdef __KERNEL__
+
+#ifdef CONFIG_64BIT
+#define BITS_PER_LONG 64
+#else
+#define BITS_PER_LONG 32
+#endif /* CONFIG_64BIT */
+
+/*
+ * FIXME: The check currently breaks x86-64 build, so it's
+ * temporarily disabled. Please fix x86-64 and reenable
+ */
+#if 0 && BITS_PER_LONG != __BITS_PER_LONG
+#error Inconsistent word size. Check asm/bitsperlong.h
+#endif
+
+#endif /* __KERNEL__ */
+#endif /* __ASM_GENERIC_BITS_PER_LONG */
diff --git a/include/asm-generic/bugs.h b/include/asm-generic/bugs.h
new file mode 100644 (file)
index 0000000..6c4f62e
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __ASM_GENERIC_BUGS_H
+#define __ASM_GENERIC_BUGS_H
+/*
+ * This file is included by 'init/main.c' to check for
+ * architecture-dependent bugs.
+ */
+
+static inline void check_bugs(void) { }
+
+#endif /* __ASM_GENERIC_BUGS_H */
diff --git a/include/asm-generic/cache.h b/include/asm-generic/cache.h
new file mode 100644 (file)
index 0000000..1bfcfe5
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef __ASM_GENERIC_CACHE_H
+#define __ASM_GENERIC_CACHE_H
+/*
+ * 32 bytes appears to be the most common cache line size,
+ * so make that the default here. Architectures with larger
+ * cache lines need to provide their own cache.h.
+ */
+
+#define L1_CACHE_SHIFT         5
+#define L1_CACHE_BYTES         (1 << L1_CACHE_SHIFT)
+
+#endif /* __ASM_GENERIC_CACHE_H */
diff --git a/include/asm-generic/cacheflush.h b/include/asm-generic/cacheflush.h
new file mode 100644 (file)
index 0000000..ba4ec39
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef __ASM_CACHEFLUSH_H
+#define __ASM_CACHEFLUSH_H
+
+/* Keep includes the same across arches.  */
+#include <linux/mm.h>
+
+/*
+ * The cache doesn't need to be flushed when TLB entries change when
+ * the cache is mapped to physical memory, not virtual memory
+ */
+#define flush_cache_all()                      do { } while (0)
+#define flush_cache_mm(mm)                     do { } while (0)
+#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 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)
+#define flush_icache_range(start, end)         do { } while (0)
+#define flush_icache_page(vma,pg)              do { } while (0)
+#define flush_icache_user_range(vma,pg,adr,len)        do { } while (0)
+#define flush_cache_vmap(start, end)           do { } while (0)
+#define flush_cache_vunmap(start, end)         do { } while (0)
+
+#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
+       memcpy(dst, src, len)
+#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
+       memcpy(dst, src, len)
+
+#endif /* __ASM_CACHEFLUSH_H */
diff --git a/include/asm-generic/checksum.h b/include/asm-generic/checksum.h
new file mode 100644 (file)
index 0000000..4647c76
--- /dev/null
@@ -0,0 +1,79 @@
+#ifndef __ASM_GENERIC_CHECKSUM_H
+#define __ASM_GENERIC_CHECKSUM_H
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+extern __wsum csum_partial(const void *buff, int len, __wsum sum);
+
+/*
+ * the same as csum_partial, but copies from src while it
+ * checksums
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+extern __wsum csum_partial_copy(const void *src, void *dst, int len, __wsum sum);
+
+/*
+ * the same as csum_partial_copy, but copies from user space.
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+extern __wsum csum_partial_copy_from_user(const void __user *src, void *dst,
+                                       int len, __wsum sum, int *csum_err);
+
+#define csum_partial_copy_nocheck(src, dst, len, sum)  \
+       csum_partial_copy((src), (dst), (len), (sum))
+
+/*
+ * This is a version of ip_compute_csum() optimized for IP headers,
+ * which always checksum on 4 octet boundaries.
+ */
+extern __sum16 ip_fast_csum(const void *iph, unsigned int ihl);
+
+/*
+ * Fold a partial checksum
+ */
+static inline __sum16 csum_fold(__wsum csum)
+{
+       u32 sum = (__force u32)csum;
+       sum = (sum & 0xffff) + (sum >> 16);
+       sum = (sum & 0xffff) + (sum >> 16);
+       return (__force __sum16)~sum;
+}
+
+#ifndef csum_tcpudp_nofold
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+extern __wsum
+csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
+               unsigned short proto, __wsum sum);
+#endif
+
+static inline __sum16
+csum_tcpudp_magic(__be32 saddr, __be32 daddr, unsigned short len,
+                 unsigned short proto, __wsum sum)
+{
+       return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+extern __sum16 ip_compute_csum(const void *buff, int len);
+
+#endif /* __ASM_GENERIC_CHECKSUM_H */
diff --git a/include/asm-generic/current.h b/include/asm-generic/current.h
new file mode 100644 (file)
index 0000000..5e86f6a
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef __ASM_GENERIC_CURRENT_H
+#define __ASM_GENERIC_CURRENT_H
+
+#include <linux/thread_info.h>
+
+#define get_current() (current_thread_info()->task)
+#define current get_current()
+
+#endif /* __ASM_GENERIC_CURRENT_H */
diff --git a/include/asm-generic/delay.h b/include/asm-generic/delay.h
new file mode 100644 (file)
index 0000000..4586fec
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef __ASM_GENERIC_DELAY_H
+#define __ASM_GENERIC_DELAY_H
+
+extern void __udelay(unsigned long usecs);
+extern void __delay(unsigned long loops);
+
+#define udelay(n) __udelay(n)
+
+#endif /* __ASM_GENERIC_DELAY_H */
diff --git a/include/asm-generic/dma.h b/include/asm-generic/dma.h
new file mode 100644 (file)
index 0000000..9dfc3a7
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __ASM_GENERIC_DMA_H
+#define __ASM_GENERIC_DMA_H
+/*
+ * This file traditionally describes the i8237 PC style DMA controller.
+ * Most architectures don't have these any more and can get the minimal
+ * implementation from kernel/dma.c by not defining MAX_DMA_CHANNELS.
+ *
+ * Some code relies on seeing MAX_DMA_ADDRESS though.
+ */
+#define MAX_DMA_ADDRESS PAGE_OFFSET
+
+extern int request_dma(unsigned int dmanr, const char *device_id);
+extern void free_dma(unsigned int dmanr);
+
+#endif /* __ASM_GENERIC_DMA_H */
diff --git a/include/asm-generic/fb.h b/include/asm-generic/fb.h
new file mode 100644 (file)
index 0000000..fe8ca7f
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef __ASM_GENERIC_FB_H_
+#define __ASM_GENERIC_FB_H_
+#include <linux/fb.h>
+
+#define fb_pgprotect(...) do {} while (0)
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+       return 0;
+}
+
+#endif /* __ASM_GENERIC_FB_H_ */
diff --git a/include/asm-generic/getorder.h b/include/asm-generic/getorder.h
new file mode 100644 (file)
index 0000000..67e7245
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef __ASM_GENERIC_GETORDER_H
+#define __ASM_GENERIC_GETORDER_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/compiler.h>
+
+/* Pure 2^n version of get_order */
+static inline __attribute_const__ int get_order(unsigned long size)
+{
+       int order;
+
+       size = (size - 1) >> (PAGE_SHIFT - 1);
+       order = -1;
+       do {
+               size >>= 1;
+               order++;
+       } while (size);
+       return order;
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_GENERIC_GETORDER_H */
diff --git a/include/asm-generic/hardirq.h b/include/asm-generic/hardirq.h
new file mode 100644 (file)
index 0000000..3d5d2c9
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef __ASM_GENERIC_HARDIRQ_H
+#define __ASM_GENERIC_HARDIRQ_H
+
+#include <linux/cache.h>
+#include <linux/threads.h>
+#include <linux/irq.h>
+
+typedef struct {
+       unsigned long __softirq_pending;
+} ____cacheline_aligned irq_cpustat_t;
+
+#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
+
+#ifndef HARDIRQ_BITS
+#define HARDIRQ_BITS   8
+#endif
+
+/*
+ * The hardirq mask has to be large enough to have
+ * space for potentially all IRQ sources in the system
+ * nesting on a single CPU:
+ */
+#if (1 << HARDIRQ_BITS) < NR_IRQS
+# error HARDIRQ_BITS is too low!
+#endif
+
+#ifndef ack_bad_irq
+static inline void ack_bad_irq(unsigned int irq)
+{
+       printk(KERN_CRIT "unexpected IRQ trap at vector %02x\n", irq);
+}
+#endif
+
+#endif /* __ASM_GENERIC_HARDIRQ_H */
diff --git a/include/asm-generic/hw_irq.h b/include/asm-generic/hw_irq.h
new file mode 100644 (file)
index 0000000..89036d7
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef __ASM_GENERIC_HW_IRQ_H
+#define __ASM_GENERIC_HW_IRQ_H
+/*
+ * hw_irq.h has internal declarations for the low-level interrupt
+ * controller, like the original i8259A.
+ * In general, this is not needed for new architectures.
+ */
+
+#endif /* __ASM_GENERIC_HW_IRQ_H */
index 2af9b75d77db330cc5da1b64fee6a8eb0807f23b..1ca3efc976cc0b66541c4a7dfa8f4800361bf05f 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef _ASM_GENERIC_INT_L64_H
 #define _ASM_GENERIC_INT_L64_H
 
+#include <asm/bitsperlong.h>
+
 #ifndef __ASSEMBLY__
 /*
  * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
index f9bc9ac29b36edafca055190ca4df361f9152f52..f394147c07397b776185f9e502b3966035c838c7 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef _ASM_GENERIC_INT_LL64_H
 #define _ASM_GENERIC_INT_LL64_H
 
+#include <asm/bitsperlong.h>
+
 #ifndef __ASSEMBLY__
 /*
  * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
new file mode 100644 (file)
index 0000000..bcee636
--- /dev/null
@@ -0,0 +1,300 @@
+/* Generic I/O port emulation, based on MN10300 code
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#ifndef __ASM_GENERIC_IO_H
+#define __ASM_GENERIC_IO_H
+
+#include <asm/page.h> /* I/O is all done through memory accesses */
+#include <asm/cacheflush.h>
+#include <linux/types.h>
+
+#ifdef CONFIG_GENERIC_IOMAP
+#include <asm-generic/iomap.h>
+#endif
+
+#define mmiowb() do {} while (0)
+
+/*****************************************************************************/
+/*
+ * readX/writeX() are used to access memory mapped devices. On some
+ * architectures the memory mapped IO stuff needs to be accessed
+ * differently. On the simple architectures, we just read/write the
+ * memory location directly.
+ */
+static inline u8 __raw_readb(const volatile void __iomem *addr)
+{
+       return *(const volatile u8 __force *) addr;
+}
+
+static inline u16 __raw_readw(const volatile void __iomem *addr)
+{
+       return *(const volatile u16 __force *) addr;
+}
+
+static inline u32 __raw_readl(const volatile void __iomem *addr)
+{
+       return *(const volatile u32 __force *) addr;
+}
+
+#define readb __raw_readb
+#define readw(addr) __le16_to_cpu(__raw_readw(addr))
+#define readl(addr) __le32_to_cpu(__raw_readl(addr))
+
+static inline void __raw_writeb(u8 b, volatile void __iomem *addr)
+{
+       *(volatile u8 __force *) addr = b;
+}
+
+static inline void __raw_writew(u16 b, volatile void __iomem *addr)
+{
+       *(volatile u16 __force *) addr = b;
+}
+
+static inline void __raw_writel(u32 b, volatile void __iomem *addr)
+{
+       *(volatile u32 __force *) addr = b;
+}
+
+#define writeb __raw_writeb
+#define writew(b,addr) __raw_writew(__cpu_to_le16(b),addr)
+#define writel(b,addr) __raw_writel(__cpu_to_le32(b),addr)
+
+#ifdef CONFIG_64BIT
+static inline u64 __raw_readq(const volatile void __iomem *addr)
+{
+       return *(const volatile u64 __force *) addr;
+}
+#define readq(addr) __le64_to_cpu(__raw_readq(addr))
+
+static inline void __raw_writeq(u64 b, volatile void __iomem *addr)
+{
+       *(volatile u64 __force *) addr = b;
+}
+#define writeq(b,addr) __raw_writeq(__cpu_to_le64(b),addr)
+#endif
+
+/*****************************************************************************/
+/*
+ * traditional input/output functions
+ */
+
+static inline u8 inb(unsigned long addr)
+{
+       return readb((volatile void __iomem *) addr);
+}
+
+static inline u16 inw(unsigned long addr)
+{
+       return readw((volatile void __iomem *) addr);
+}
+
+static inline u32 inl(unsigned long addr)
+{
+       return readl((volatile void __iomem *) addr);
+}
+
+static inline void outb(u8 b, unsigned long addr)
+{
+       writeb(b, (volatile void __iomem *) addr);
+}
+
+static inline void outw(u16 b, unsigned long addr)
+{
+       writew(b, (volatile void __iomem *) addr);
+}
+
+static inline void outl(u32 b, unsigned long addr)
+{
+       writel(b, (volatile void __iomem *) addr);
+}
+
+#define inb_p(addr)    inb(addr)
+#define inw_p(addr)    inw(addr)
+#define inl_p(addr)    inl(addr)
+#define outb_p(x, addr)        outb((x), (addr))
+#define outw_p(x, addr)        outw((x), (addr))
+#define outl_p(x, addr)        outl((x), (addr))
+
+static inline void insb(unsigned long addr, void *buffer, int count)
+{
+       if (count) {
+               u8 *buf = buffer;
+               do {
+                       u8 x = inb(addr);
+                       *buf++ = x;
+               } while (--count);
+       }
+}
+
+static inline void insw(unsigned long addr, void *buffer, int count)
+{
+       if (count) {
+               u16 *buf = buffer;
+               do {
+                       u16 x = inw(addr);
+                       *buf++ = x;
+               } while (--count);
+       }
+}
+
+static inline void insl(unsigned long addr, void *buffer, int count)
+{
+       if (count) {
+               u32 *buf = buffer;
+               do {
+                       u32 x = inl(addr);
+                       *buf++ = x;
+               } while (--count);
+       }
+}
+
+static inline void outsb(unsigned long addr, const void *buffer, int count)
+{
+       if (count) {
+               const u8 *buf = buffer;
+               do {
+                       outb(*buf++, addr);
+               } while (--count);
+       }
+}
+
+static inline void outsw(unsigned long addr, const void *buffer, int count)
+{
+       if (count) {
+               const u16 *buf = buffer;
+               do {
+                       outw(*buf++, addr);
+               } while (--count);
+       }
+}
+
+static inline void outsl(unsigned long addr, const void *buffer, int count)
+{
+       if (count) {
+               const u32 *buf = buffer;
+               do {
+                       outl(*buf++, addr);
+               } while (--count);
+       }
+}
+
+#ifndef CONFIG_GENERIC_IOMAP
+#define ioread8(addr)          readb(addr)
+#define ioread16(addr)         readw(addr)
+#define ioread32(addr)         readl(addr)
+
+#define iowrite8(v, addr)      writeb((v), (addr))
+#define iowrite16(v, addr)     writew((v), (addr))
+#define iowrite32(v, addr)     writel((v), (addr))
+
+#define ioread8_rep(p, dst, count) \
+       insb((unsigned long) (p), (dst), (count))
+#define ioread16_rep(p, dst, count) \
+       insw((unsigned long) (p), (dst), (count))
+#define ioread32_rep(p, dst, count) \
+       insl((unsigned long) (p), (dst), (count))
+
+#define iowrite8_rep(p, src, count) \
+       outsb((unsigned long) (p), (src), (count))
+#define iowrite16_rep(p, src, count) \
+       outsw((unsigned long) (p), (src), (count))
+#define iowrite32_rep(p, src, count) \
+       outsl((unsigned long) (p), (src), (count))
+#endif /* CONFIG_GENERIC_IOMAP */
+
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+#ifdef __KERNEL__
+
+#include <linux/vmalloc.h>
+#define __io_virt(x) ((void __force *) (x))
+
+#ifndef CONFIG_GENERIC_IOMAP
+/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
+struct pci_dev;
+extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
+static inline void pci_iounmap(struct pci_dev *dev, void __iomem *p)
+{
+}
+#endif /* CONFIG_GENERIC_IOMAP */
+
+/*
+ * Change virtual addresses to physical addresses and vv.
+ * These are pretty trivial
+ */
+static inline unsigned long virt_to_phys(volatile void *address)
+{
+       return __pa((unsigned long)address);
+}
+
+static inline void *phys_to_virt(unsigned long address)
+{
+       return __va(address);
+}
+
+/*
+ * Change "struct page" to physical address.
+ */
+static inline void __iomem *ioremap(phys_addr_t offset, unsigned long size)
+{
+       return (void __iomem*) (unsigned long)offset;
+}
+
+#define __ioremap(offset, size, flags) ioremap(offset, size)
+
+#ifndef ioremap_nocache
+#define ioremap_nocache ioremap
+#endif
+
+#ifndef ioremap_wc
+#define ioremap_wc ioremap_nocache
+#endif
+
+static inline void iounmap(void *addr)
+{
+}
+
+#ifndef CONFIG_GENERIC_IOMAP
+static inline void __iomem *ioport_map(unsigned long port, unsigned int nr)
+{
+       return (void __iomem *) port;
+}
+
+static inline void ioport_unmap(void __iomem *p)
+{
+}
+#else /* CONFIG_GENERIC_IOMAP */
+extern void __iomem *ioport_map(unsigned long port, unsigned int nr);
+extern void ioport_unmap(void __iomem *p);
+#endif /* CONFIG_GENERIC_IOMAP */
+
+#define xlate_dev_kmem_ptr(p)  p
+#define xlate_dev_mem_ptr(p)   ((void *) (p))
+
+#ifndef virt_to_bus
+static inline unsigned long virt_to_bus(volatile void *address)
+{
+       return ((unsigned long) address);
+}
+
+static inline void *bus_to_virt(unsigned long address)
+{
+       return (void *) address;
+}
+#endif
+
+#define memset_io(a, b, c)     memset(__io_virt(a), (b), (c))
+#define memcpy_fromio(a, b, c) memcpy((a), __io_virt(b), (c))
+#define memcpy_toio(a, b, c)   memcpy(__io_virt(a), (b), (c))
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_GENERIC_IO_H */
diff --git a/include/asm-generic/ioctls.h b/include/asm-generic/ioctls.h
new file mode 100644 (file)
index 0000000..a799e20
--- /dev/null
@@ -0,0 +1,110 @@
+#ifndef __ASM_GENERIC_IOCTLS_H
+#define __ASM_GENERIC_IOCTLS_H
+
+#include <linux/ioctl.h>
+
+/*
+ * These are the most common definitions for tty ioctl numbers.
+ * Most of them do not use the recommended _IOC(), but there is
+ * probably some source code out there hardcoding the number,
+ * so we might as well use them for all new platforms.
+ *
+ * The architectures that use different values here typically
+ * try to be compatible with some Unix variants for the same
+ * architecture.
+ */
+
+/* 0x54 is just a magic number to make these relatively unique ('T') */
+
+#define TCGETS         0x5401
+#define TCSETS         0x5402
+#define TCSETSW                0x5403
+#define TCSETSF                0x5404
+#define TCGETA         0x5405
+#define TCSETA         0x5406
+#define TCSETAW                0x5407
+#define TCSETAF                0x5408
+#define TCSBRK         0x5409
+#define TCXONC         0x540A
+#define TCFLSH         0x540B
+#define TIOCEXCL       0x540C
+#define TIOCNXCL       0x540D
+#define TIOCSCTTY      0x540E
+#define TIOCGPGRP      0x540F
+#define TIOCSPGRP      0x5410
+#define TIOCOUTQ       0x5411
+#define TIOCSTI                0x5412
+#define TIOCGWINSZ     0x5413
+#define TIOCSWINSZ     0x5414
+#define TIOCMGET       0x5415
+#define TIOCMBIS       0x5416
+#define TIOCMBIC       0x5417
+#define TIOCMSET       0x5418
+#define TIOCGSOFTCAR   0x5419
+#define TIOCSSOFTCAR   0x541A
+#define FIONREAD       0x541B
+#define TIOCINQ                FIONREAD
+#define TIOCLINUX      0x541C
+#define TIOCCONS       0x541D
+#define TIOCGSERIAL    0x541E
+#define TIOCSSERIAL    0x541F
+#define TIOCPKT                0x5420
+#define FIONBIO                0x5421
+#define TIOCNOTTY      0x5422
+#define TIOCSETD       0x5423
+#define TIOCGETD       0x5424
+#define TCSBRKP                0x5425  /* Needed for POSIX tcsendbreak() */
+#define TIOCSBRK       0x5427  /* BSD compatibility */
+#define TIOCCBRK       0x5428  /* BSD compatibility */
+#define TIOCGSID       0x5429  /* Return the session ID of FD */
+#define TCGETS2                _IOR('T', 0x2A, struct termios2)
+#define TCSETS2                _IOW('T', 0x2B, struct termios2)
+#define TCSETSW2       _IOW('T', 0x2C, struct termios2)
+#define TCSETSF2       _IOW('T', 0x2D, struct termios2)
+#define TIOCGRS485     0x542E
+#define TIOCSRS485     0x542F
+#define TIOCGPTN       _IOR('T', 0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TIOCSPTLCK     _IOW('T', 0x31, int)  /* Lock/unlock Pty */
+#define TCGETX         0x5432 /* SYS5 TCGETX compatibility */
+#define TCSETX         0x5433
+#define TCSETXF                0x5434
+#define TCSETXW                0x5435
+
+#define FIONCLEX       0x5450
+#define FIOCLEX                0x5451
+#define FIOASYNC       0x5452
+#define TIOCSERCONFIG  0x5453
+#define TIOCSERGWILD   0x5454
+#define TIOCSERSWILD   0x5455
+#define TIOCGLCKTRMIOS 0x5456
+#define TIOCSLCKTRMIOS 0x5457
+#define TIOCSERGSTRUCT 0x5458 /* For debugging only */
+#define TIOCSERGETLSR   0x5459 /* Get line status register */
+#define TIOCSERGETMULTI 0x545A /* Get multiport config  */
+#define TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TIOCMIWAIT     0x545C  /* wait for a change on serial input line(s) */
+#define TIOCGICOUNT    0x545D  /* read serial port inline interrupt counts */
+
+/*
+ * some architectures define FIOQSIZE as 0x545E, which is used for
+ * TIOCGHAYESESP on others
+ */
+#ifndef FIOQSIZE
+# define TIOCGHAYESESP 0x545E  /* Get Hayes ESP configuration */
+# define TIOCSHAYESESP 0x545F  /* Set Hayes ESP configuration */
+# define FIOQSIZE      0x5460
+#endif
+
+/* Used for packet mode */
+#define TIOCPKT_DATA            0
+#define TIOCPKT_FLUSHREAD       1
+#define TIOCPKT_FLUSHWRITE      2
+#define TIOCPKT_STOP            4
+#define TIOCPKT_START           8
+#define TIOCPKT_NOSTOP         16
+#define TIOCPKT_DOSTOP         32
+
+#define TIOCSER_TEMT   0x01    /* Transmitter physically empty */
+
+#endif /* __ASM_GENERIC_IOCTLS_H */
diff --git a/include/asm-generic/ipcbuf.h b/include/asm-generic/ipcbuf.h
new file mode 100644 (file)
index 0000000..76982b2
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef __ASM_GENERIC_IPCBUF_H
+#define __ASM_GENERIC_IPCBUF_H
+
+/*
+ * The generic ipc64_perm structure:
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * ipc64_perm was originally meant to be architecture specific, but
+ * everyone just ended up making identical copies without specific
+ * optimizations, so we may just as well all use the same one.
+ *
+ * Pad space is left for:
+ * - 32-bit mode_t on architectures that only had 16 bit
+ * - 32-bit seq
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct ipc64_perm {
+       __kernel_key_t          key;
+       __kernel_uid32_t        uid;
+       __kernel_gid32_t        gid;
+       __kernel_uid32_t        cuid;
+       __kernel_gid32_t        cgid;
+       __kernel_mode_t         mode;
+                               /* pad if mode_t is u16: */
+       unsigned char           __pad1[4 - sizeof(__kernel_mode_t)];
+       unsigned short          seq;
+       unsigned short          __pad2;
+       unsigned long           __unused1;
+       unsigned long           __unused2;
+};
+
+#endif /* __ASM_GENERIC_IPCBUF_H */
diff --git a/include/asm-generic/irq.h b/include/asm-generic/irq.h
new file mode 100644 (file)
index 0000000..b90ec0b
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef __ASM_GENERIC_IRQ_H
+#define __ASM_GENERIC_IRQ_H
+
+/*
+ * NR_IRQS is the upper bound of how many interrupts can be handled
+ * in the platform. It is used to size the static irq_map array,
+ * so don't make it too big.
+ */
+#ifndef NR_IRQS
+#define NR_IRQS 64
+#endif
+
+static inline int irq_canonicalize(int irq)
+{
+       return irq;
+}
+
+#endif /* __ASM_GENERIC_IRQ_H */
diff --git a/include/asm-generic/irqflags.h b/include/asm-generic/irqflags.h
new file mode 100644 (file)
index 0000000..9aebf61
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef __ASM_GENERIC_IRQFLAGS_H
+#define __ASM_GENERIC_IRQFLAGS_H
+
+/*
+ * All architectures should implement at least the first two functions,
+ * usually inline assembly will be the best way.
+ */
+#ifndef RAW_IRQ_DISABLED
+#define RAW_IRQ_DISABLED 0
+#define RAW_IRQ_ENABLED 1
+#endif
+
+/* read interrupt enabled status */
+#ifndef __raw_local_save_flags
+unsigned long __raw_local_save_flags(void);
+#endif
+
+/* set interrupt enabled status */
+#ifndef raw_local_irq_restore
+void raw_local_irq_restore(unsigned long flags);
+#endif
+
+/* get status and disable interrupts */
+#ifndef __raw_local_irq_save
+static inline unsigned long __raw_local_irq_save(void)
+{
+       unsigned long flags;
+       flags = __raw_local_save_flags();
+       raw_local_irq_restore(RAW_IRQ_DISABLED);
+       return flags;
+}
+#endif
+
+/* test flags */
+#ifndef raw_irqs_disabled_flags
+static inline int raw_irqs_disabled_flags(unsigned long flags)
+{
+       return flags == RAW_IRQ_DISABLED;
+}
+#endif
+
+/* unconditionally enable interrupts */
+#ifndef raw_local_irq_enable
+static inline void raw_local_irq_enable(void)
+{
+       raw_local_irq_restore(RAW_IRQ_ENABLED);
+}
+#endif
+
+/* unconditionally disable interrupts */
+#ifndef raw_local_irq_disable
+static inline void raw_local_irq_disable(void)
+{
+       raw_local_irq_restore(RAW_IRQ_DISABLED);
+}
+#endif
+
+/* test hardware interrupt enable bit */
+#ifndef raw_irqs_disabled
+static inline int raw_irqs_disabled(void)
+{
+       return raw_irqs_disabled_flags(__raw_local_save_flags());
+}
+#endif
+
+#define raw_local_save_flags(flags) \
+       do { (flags) = __raw_local_save_flags(); } while (0)
+
+#define raw_local_irq_save(flags) \
+       do { (flags) = __raw_local_irq_save(); } while (0)
+
+#endif /* __ASM_GENERIC_IRQFLAGS_H */
diff --git a/include/asm-generic/kmap_types.h b/include/asm-generic/kmap_types.h
new file mode 100644 (file)
index 0000000..58c3305
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef _ASM_GENERIC_KMAP_TYPES_H
+#define _ASM_GENERIC_KMAP_TYPES_H
+
+#ifdef CONFIG_DEBUG_HIGHMEM
+# define D(n) __KM_FENCE_##n ,
+#else
+# define D(n)
+#endif
+
+enum km_type {
+D(0)   KM_BOUNCE_READ,
+D(1)   KM_SKB_SUNRPC_DATA,
+D(2)   KM_SKB_DATA_SOFTIRQ,
+D(3)   KM_USER0,
+D(4)   KM_USER1,
+D(5)   KM_BIO_SRC_IRQ,
+D(6)   KM_BIO_DST_IRQ,
+D(7)   KM_PTE0,
+D(8)   KM_PTE1,
+D(9)   KM_IRQ0,
+D(10)  KM_IRQ1,
+D(11)  KM_SOFTIRQ0,
+D(12)  KM_SOFTIRQ1,
+D(13)  KM_SYNC_ICACHE,
+D(14)  KM_SYNC_DCACHE,
+D(15)  KM_UML_USERCOPY, /* UML specific, for copy_*_user - used in do_op_one_page */
+D(16)  KM_TYPE_NR
+};
+
+#undef D
+
+#endif
diff --git a/include/asm-generic/linkage.h b/include/asm-generic/linkage.h
new file mode 100644 (file)
index 0000000..fef7a01
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __ASM_GENERIC_LINKAGE_H
+#define __ASM_GENERIC_LINKAGE_H
+/*
+ * linux/linkage.h provides reasonable defaults.
+ * an architecture can override them by providing its own version.
+ */
+
+#endif /* __ASM_GENERIC_LINKAGE_H */
diff --git a/include/asm-generic/mman-common.h b/include/asm-generic/mman-common.h
new file mode 100644 (file)
index 0000000..3b69ad3
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef __ASM_GENERIC_MMAN_COMMON_H
+#define __ASM_GENERIC_MMAN_COMMON_H
+
+/*
+ Author: Michael S. Tsirkin <mst@mellanox.co.il>, Mellanox Technologies Ltd.
+ Based on: asm-xxx/mman.h
+*/
+
+#define PROT_READ      0x1             /* page can be read */
+#define PROT_WRITE     0x2             /* page can be written */
+#define PROT_EXEC      0x4             /* page can be executed */
+#define PROT_SEM       0x8             /* page may be used for atomic ops */
+#define PROT_NONE      0x0             /* page can not be accessed */
+#define PROT_GROWSDOWN 0x01000000      /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP   0x02000000      /* mprotect flag: extend change to end of growsup vma */
+
+#define MAP_SHARED     0x01            /* Share changes */
+#define MAP_PRIVATE    0x02            /* Changes are private */
+#define MAP_TYPE       0x0f            /* Mask for type of mapping */
+#define MAP_FIXED      0x10            /* Interpret addr exactly */
+#define MAP_ANONYMOUS  0x20            /* don't use a file */
+
+#define MS_ASYNC       1               /* sync memory asynchronously */
+#define MS_INVALIDATE  2               /* invalidate the caches */
+#define MS_SYNC                4               /* synchronous memory sync */
+
+#define MADV_NORMAL    0               /* no further special treatment */
+#define MADV_RANDOM    1               /* expect random page references */
+#define MADV_SEQUENTIAL        2               /* expect sequential page references */
+#define MADV_WILLNEED  3               /* will need these pages */
+#define MADV_DONTNEED  4               /* don't need these pages */
+
+/* common parameters: try to keep these consistent across architectures */
+#define MADV_REMOVE    9               /* remove these pages & resources */
+#define MADV_DONTFORK  10              /* don't inherit across fork */
+#define MADV_DOFORK    11              /* do inherit across fork */
+
+/* compatibility flags */
+#define MAP_FILE       0
+
+#endif /* __ASM_GENERIC_MMAN_COMMON_H */
index 5e3dde2ee5adf37f5ccd62fa11f9b3878bc5a653..7cab4de2bca6a3a74cad234301fa69a013f8273b 100644 (file)
@@ -1,41 +1,18 @@
-#ifndef _ASM_GENERIC_MMAN_H
-#define _ASM_GENERIC_MMAN_H
+#ifndef __ASM_GENERIC_MMAN_H
+#define __ASM_GENERIC_MMAN_H
 
-/*
- Author: Michael S. Tsirkin <mst@mellanox.co.il>, Mellanox Technologies Ltd.
- Based on: asm-xxx/mman.h
-*/
+#include <asm-generic/mman-common.h>
 
-#define PROT_READ      0x1             /* page can be read */
-#define PROT_WRITE     0x2             /* page can be written */
-#define PROT_EXEC      0x4             /* page can be executed */
-#define PROT_SEM       0x8             /* page may be used for atomic ops */
-#define PROT_NONE      0x0             /* page can not be accessed */
-#define PROT_GROWSDOWN 0x01000000      /* mprotect flag: extend change to start of growsdown vma */
-#define PROT_GROWSUP   0x02000000      /* mprotect flag: extend change to end of growsup vma */
+#define MAP_GROWSDOWN  0x0100          /* stack-like segment */
+#define MAP_DENYWRITE  0x0800          /* ETXTBSY */
+#define MAP_EXECUTABLE 0x1000          /* mark it as an executable */
+#define MAP_LOCKED     0x2000          /* pages are locked */
+#define MAP_NORESERVE  0x4000          /* don't check for reservations */
+#define MAP_POPULATE   0x8000          /* populate (prefault) pagetables */
+#define MAP_NONBLOCK   0x10000         /* do not block on IO */
+#define MAP_STACK      0x20000         /* give out an address that is best suited for process/thread stacks */
 
-#define MAP_SHARED     0x01            /* Share changes */
-#define MAP_PRIVATE    0x02            /* Changes are private */
-#define MAP_TYPE       0x0f            /* Mask for type of mapping */
-#define MAP_FIXED      0x10            /* Interpret addr exactly */
-#define MAP_ANONYMOUS  0x20            /* don't use a file */
+#define MCL_CURRENT    1               /* lock all current mappings */
+#define MCL_FUTURE     2               /* lock all future mappings */
 
-#define MS_ASYNC       1               /* sync memory asynchronously */
-#define MS_INVALIDATE  2               /* invalidate the caches */
-#define MS_SYNC                4               /* synchronous memory sync */
-
-#define MADV_NORMAL    0               /* no further special treatment */
-#define MADV_RANDOM    1               /* expect random page references */
-#define MADV_SEQUENTIAL        2               /* expect sequential page references */
-#define MADV_WILLNEED  3               /* will need these pages */
-#define MADV_DONTNEED  4               /* don't need these pages */
-
-/* common parameters: try to keep these consistent across architectures */
-#define MADV_REMOVE    9               /* remove these pages & resources */
-#define MADV_DONTFORK  10              /* don't inherit across fork */
-#define MADV_DOFORK    11              /* do inherit across fork */
-
-/* compatibility flags */
-#define MAP_FILE       0
-
-#endif
+#endif /* __ASM_GENERIC_MMAN_H */
diff --git a/include/asm-generic/mmu.h b/include/asm-generic/mmu.h
new file mode 100644 (file)
index 0000000..4f4aa56
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __ASM_GENERIC_MMU_H
+#define __ASM_GENERIC_MMU_H
+
+/*
+ * This is the mmu.h header for nommu implementations.
+ * Architectures with an MMU need something more complex.
+ */
+#ifndef __ASSEMBLY__
+typedef struct {
+       struct vm_list_struct   *vmlist;
+       unsigned long           end_brk;
+} mm_context_t;
+#endif
+
+#endif /* __ASM_GENERIC_MMU_H */
diff --git a/include/asm-generic/mmu_context.h b/include/asm-generic/mmu_context.h
new file mode 100644 (file)
index 0000000..a7eec91
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef __ASM_GENERIC_MMU_CONTEXT_H
+#define __ASM_GENERIC_MMU_CONTEXT_H
+
+/*
+ * Generic hooks for NOMMU architectures, which do not need to do
+ * anything special here.
+ */
+
+#include <asm-generic/mm_hooks.h>
+
+struct task_struct;
+struct mm_struct;
+
+static inline void enter_lazy_tlb(struct mm_struct *mm,
+                       struct task_struct *tsk)
+{
+}
+
+static inline int init_new_context(struct task_struct *tsk,
+                       struct mm_struct *mm)
+{
+       return 0;
+}
+
+static inline void destroy_context(struct mm_struct *mm)
+{
+}
+
+static inline void deactivate_mm(struct task_struct *task,
+                       struct mm_struct *mm)
+{
+}
+
+static inline void switch_mm(struct mm_struct *prev,
+                       struct mm_struct *next,
+                       struct task_struct *tsk)
+{
+}
+
+static inline void activate_mm(struct mm_struct *prev_mm,
+                              struct mm_struct *next_mm)
+{
+}
+
+#endif /* __ASM_GENERIC_MMU_CONTEXT_H */
diff --git a/include/asm-generic/module.h b/include/asm-generic/module.h
new file mode 100644 (file)
index 0000000..ed5b44d
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef __ASM_GENERIC_MODULE_H
+#define __ASM_GENERIC_MODULE_H
+
+/*
+ * Many architectures just need a simple module
+ * loader without arch specific data.
+ */
+struct mod_arch_specific
+{
+};
+
+#ifdef CONFIG_64BIT
+#define Elf_Shdr Elf64_Shdr
+#define Elf_Sym Elf64_Sym
+#define Elf_Ehdr Elf64_Ehdr
+#else
+#define Elf_Shdr Elf32_Shdr
+#define Elf_Sym Elf32_Sym
+#define Elf_Ehdr Elf32_Ehdr
+#endif
+
+#endif /* __ASM_GENERIC_MODULE_H */
diff --git a/include/asm-generic/msgbuf.h b/include/asm-generic/msgbuf.h
new file mode 100644 (file)
index 0000000..aec850d
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef __ASM_GENERIC_MSGBUF_H
+#define __ASM_GENERIC_MSGBUF_H
+
+#include <asm/bitsperlong.h>
+/*
+ * generic msqid64_ds structure.
+ *
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * msqid64_ds was originally meant to be architecture specific, but
+ * everyone just ended up making identical copies without specific
+ * optimizations, so we may just as well all use the same one.
+ *
+ * 64 bit architectures typically define a 64 bit __kernel_time_t,
+ * so they do not need the first three padding words.
+ * On big-endian systems, the padding is in the wrong place.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct msqid64_ds {
+       struct ipc64_perm msg_perm;
+       __kernel_time_t msg_stime;      /* last msgsnd time */
+#if __BITS_PER_LONG != 64
+       unsigned long   __unused1;
+#endif
+       __kernel_time_t msg_rtime;      /* last msgrcv time */
+#if __BITS_PER_LONG != 64
+       unsigned long   __unused2;
+#endif
+       __kernel_time_t msg_ctime;      /* last change time */
+#if __BITS_PER_LONG != 64
+       unsigned long   __unused3;
+#endif
+       unsigned long  msg_cbytes;      /* current number of bytes on queue */
+       unsigned long  msg_qnum;        /* number of messages in queue */
+       unsigned long  msg_qbytes;      /* max number of bytes on queue */
+       __kernel_pid_t msg_lspid;       /* pid of last msgsnd */
+       __kernel_pid_t msg_lrpid;       /* last receive pid */
+       unsigned long  __unused4;
+       unsigned long  __unused5;
+};
+
+#endif /* __ASM_GENERIC_MSGBUF_H */
diff --git a/include/asm-generic/mutex.h b/include/asm-generic/mutex.h
new file mode 100644 (file)
index 0000000..fe91ab5
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef __ASM_GENERIC_MUTEX_H
+#define __ASM_GENERIC_MUTEX_H
+/*
+ * Pull in the generic implementation for the mutex fastpath,
+ * which is a reasonable default on many architectures.
+ */
+
+#include <asm-generic/mutex-dec.h>
+#endif /* __ASM_GENERIC_MUTEX_H */
index 14db733b8e68e7df3cb95bb685eb97cc0125a094..75fec18cdc59e1f92ee55ce5f93414e47e76dc5a 100644 (file)
@@ -1,24 +1,99 @@
-#ifndef _ASM_GENERIC_PAGE_H
-#define _ASM_GENERIC_PAGE_H
+#ifndef __ASM_GENERIC_PAGE_H
+#define __ASM_GENERIC_PAGE_H
+/*
+ * Generic page.h implementation, for NOMMU architectures.
+ * This provides the dummy definitions for the memory management.
+ */
+
+#ifdef CONFIG_MMU
+#error need to prove a real asm/page.h
+#endif
+
+
+/* PAGE_SHIFT determines the page size */
+
+#define PAGE_SHIFT     12
+#ifdef __ASSEMBLY__
+#define PAGE_SIZE      (1 << PAGE_SHIFT)
+#else
+#define PAGE_SIZE      (1UL << PAGE_SHIFT)
+#endif
+#define PAGE_MASK      (~(PAGE_SIZE-1))
+
+#include <asm/setup.h>
+
+#ifndef __ASSEMBLY__
+
+#define get_user_page(vaddr)           __get_free_page(GFP_KERNEL)
+#define free_user_page(page, addr)     free_page(addr)
+
+#define clear_page(page)       memset((page), 0, PAGE_SIZE)
+#define copy_page(to,from)     memcpy((to), (from), PAGE_SIZE)
+
+#define clear_user_page(page, vaddr, pg)       clear_page(page)
+#define copy_user_page(to, from, vaddr, pg)    copy_page(to, from)
+
+/*
+ * These are used to make use of C type-checking..
+ */
+typedef struct {
+       unsigned long pte;
+} pte_t;
+typedef struct {
+       unsigned long pmd[16];
+} pmd_t;
+typedef struct {
+       unsigned long pgd;
+} pgd_t;
+typedef struct {
+       unsigned long pgprot;
+} pgprot_t;
+typedef struct page *pgtable_t;
+
+#define pte_val(x)     ((x).pte)
+#define pmd_val(x)     ((&x)->pmd[0])
+#define pgd_val(x)     ((x).pgd)
+#define pgprot_val(x)  ((x).pgprot)
+
+#define __pte(x)       ((pte_t) { (x) } )
+#define __pmd(x)       ((pmd_t) { (x) } )
+#define __pgd(x)       ((pgd_t) { (x) } )
+#define __pgprot(x)    ((pgprot_t) { (x) } )
+
+extern unsigned long memory_start;
+extern unsigned long memory_end;
+
+#endif /* !__ASSEMBLY__ */
+
+#ifdef CONFIG_KERNEL_RAM_BASE_ADDRESS
+#define PAGE_OFFSET            (CONFIG_KERNEL_RAM_BASE_ADDRESS)
+#else
+#define PAGE_OFFSET            (0)
+#endif
 
 #ifndef __ASSEMBLY__
 
-#include <linux/compiler.h>
+#define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET))
+#define __pa(x) ((unsigned long) (x) - PAGE_OFFSET)
+
+#define virt_to_pfn(kaddr)     (__pa(kaddr) >> PAGE_SHIFT)
+#define pfn_to_virt(pfn)       __va((pfn) << PAGE_SHIFT)
+
+#define virt_to_page(addr)     (mem_map + (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT))
+#define page_to_virt(page)     ((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET)
+
+#ifndef page_to_phys
+#define page_to_phys(page)      ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT)
+#endif
+
+#define pfn_valid(pfn)         ((pfn) < max_mapnr)
 
-/* Pure 2^n version of get_order */
-static __inline__ __attribute_const__ int get_order(unsigned long size)
-{
-       int order;
+#define        virt_addr_valid(kaddr)  (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \
+                               ((void *)(kaddr) < (void *)memory_end))
 
-       size = (size - 1) >> (PAGE_SHIFT - 1);
-       order = -1;
-       do {
-               size >>= 1;
-               order++;
-       } while (size);
-       return order;
-}
+#endif /* __ASSEMBLY__ */
 
-#endif /* __ASSEMBLY__ */
+#include <asm-generic/memory_model.h>
+#include <asm-generic/getorder.h>
 
-#endif /* _ASM_GENERIC_PAGE_H */
+#endif /* __ASM_GENERIC_PAGE_H */
diff --git a/include/asm-generic/param.h b/include/asm-generic/param.h
new file mode 100644 (file)
index 0000000..cdf8251
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef __ASM_GENERIC_PARAM_H
+#define __ASM_GENERIC_PARAM_H
+
+#ifdef __KERNEL__
+# define HZ            CONFIG_HZ       /* Internal kernel timer frequency */
+# define USER_HZ       100             /* some user interfaces are */
+# define CLOCKS_PER_SEC        (USER_HZ)       /* in "ticks" like times() */
+#endif
+
+#ifndef HZ
+#define HZ 100
+#endif
+
+#ifndef EXEC_PAGESIZE
+#define EXEC_PAGESIZE  4096
+#endif
+
+#ifndef NOGROUP
+#define NOGROUP                (-1)
+#endif
+
+#define MAXHOSTNAMELEN 64      /* max length of hostname */
+
+#endif /* __ASM_GENERIC_PARAM_H */
diff --git a/include/asm-generic/parport.h b/include/asm-generic/parport.h
new file mode 100644 (file)
index 0000000..40528cb
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef __ASM_GENERIC_PARPORT_H
+#define __ASM_GENERIC_PARPORT_H
+
+/*
+ * An ISA bus may have i8255 parallel ports at well-known
+ * locations in the I/O space, which are scanned by
+ * parport_pc_find_isa_ports.
+ *
+ * Without ISA support, the driver will only attach
+ * to devices on the PCI bus.
+ */
+
+static int __devinit parport_pc_find_isa_ports(int autoirq, int autodma);
+static int __devinit parport_pc_find_nonpci_ports(int autoirq, int autodma)
+{
+#ifdef CONFIG_ISA
+       return parport_pc_find_isa_ports(autoirq, autodma);
+#else
+       return 0;
+#endif
+}
+
+#endif /* __ASM_GENERIC_PARPORT_H */
index c36a77d3bf44473b603b9c7d2a4749521f708a79..515c6e2e3218e5c193275e6b420ac3312218cae6 100644 (file)
@@ -52,4 +52,12 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
 }
 #endif /* HAVE_ARCH_PCI_GET_LEGACY_IDE_IRQ */
 
+/*
+ * By default, assume that no iommu is in use and that the PCI
+ * space is mapped to address physical 0.
+ */
+#ifndef PCI_DMA_BUS_IS_PHYS
+#define PCI_DMA_BUS_IS_PHYS    (1)
 #endif
+
+#endif /* _ASM_GENERIC_PCI_H */
diff --git a/include/asm-generic/pgalloc.h b/include/asm-generic/pgalloc.h
new file mode 100644 (file)
index 0000000..9e429d0
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef __ASM_GENERIC_PGALLOC_H
+#define __ASM_GENERIC_PGALLOC_H
+/*
+ * an empty file is enough for a nommu architecture
+ */
+#ifdef CONFIG_MMU
+#error need to implement an architecture specific asm/pgalloc.h
+#endif
+
+#define check_pgt_cache()          do { } while (0)
+
+#endif /* __ASM_GENERIC_PGALLOC_H */
diff --git a/include/asm-generic/posix_types.h b/include/asm-generic/posix_types.h
new file mode 100644 (file)
index 0000000..3dab008
--- /dev/null
@@ -0,0 +1,165 @@
+#ifndef __ASM_GENERIC_POSIX_TYPES_H
+#define __ASM_GENERIC_POSIX_TYPES_H
+
+#include <asm/bitsperlong.h>
+/*
+ * This file is generally used by user-level software, so you need to
+ * be a little careful about namespace pollution etc.
+ *
+ * First the types that are often defined in different ways across
+ * architectures, so that you can override them.
+ */
+
+#ifndef __kernel_ino_t
+typedef unsigned long  __kernel_ino_t;
+#endif
+
+#ifndef __kernel_mode_t
+typedef unsigned int   __kernel_mode_t;
+#endif
+
+#ifndef __kernel_nlink_t
+typedef unsigned long  __kernel_nlink_t;
+#endif
+
+#ifndef __kernel_pid_t
+typedef int            __kernel_pid_t;
+#endif
+
+#ifndef __kernel_ipc_pid_t
+typedef int            __kernel_ipc_pid_t;
+#endif
+
+#ifndef __kernel_uid_t
+typedef unsigned int   __kernel_uid_t;
+typedef unsigned int   __kernel_gid_t;
+#endif
+
+#ifndef __kernel_suseconds_t
+typedef long           __kernel_suseconds_t;
+#endif
+
+#ifndef __kernel_daddr_t
+typedef int            __kernel_daddr_t;
+#endif
+
+#ifndef __kernel_uid32_t
+typedef __kernel_uid_t __kernel_uid32_t;
+typedef __kernel_gid_t __kernel_gid32_t;
+#endif
+
+#ifndef __kernel_old_uid_t
+typedef __kernel_uid_t __kernel_old_uid_t;
+typedef __kernel_gid_t __kernel_old_gid_t;
+#endif
+
+#ifndef __kernel_old_dev_t
+typedef unsigned int   __kernel_old_dev_t;
+#endif
+
+/*
+ * Most 32 bit architectures use "unsigned int" size_t,
+ * and all 64 bit architectures use "unsigned long" size_t.
+ */
+#ifndef __kernel_size_t
+#if __BITS_PER_LONG != 64
+typedef unsigned int   __kernel_size_t;
+typedef int            __kernel_ssize_t;
+typedef int            __kernel_ptrdiff_t;
+#else
+typedef unsigned long  __kernel_size_t;
+typedef long           __kernel_ssize_t;
+typedef long           __kernel_ptrdiff_t;
+#endif
+#endif
+
+/*
+ * anything below here should be completely generic
+ */
+typedef long           __kernel_off_t;
+typedef long long      __kernel_loff_t;
+typedef long           __kernel_time_t;
+typedef long           __kernel_clock_t;
+typedef int            __kernel_timer_t;
+typedef int            __kernel_clockid_t;
+typedef char *         __kernel_caddr_t;
+typedef unsigned short __kernel_uid16_t;
+typedef unsigned short __kernel_gid16_t;
+
+typedef struct {
+       int     val[2];
+} __kernel_fsid_t;
+
+#ifdef __KERNEL__
+
+#undef __FD_SET
+static inline void __FD_SET(unsigned long __fd, __kernel_fd_set *__fdsetp)
+{
+       unsigned long __tmp = __fd / __NFDBITS;
+       unsigned long __rem = __fd % __NFDBITS;
+       __fdsetp->fds_bits[__tmp] |= (1UL<<__rem);
+}
+
+#undef __FD_CLR
+static inline void __FD_CLR(unsigned long __fd, __kernel_fd_set *__fdsetp)
+{
+       unsigned long __tmp = __fd / __NFDBITS;
+       unsigned long __rem = __fd % __NFDBITS;
+       __fdsetp->fds_bits[__tmp] &= ~(1UL<<__rem);
+}
+
+#undef __FD_ISSET
+static inline int __FD_ISSET(unsigned long __fd, const __kernel_fd_set *__p)
+{
+       unsigned long __tmp = __fd / __NFDBITS;
+       unsigned long __rem = __fd % __NFDBITS;
+       return (__p->fds_bits[__tmp] & (1UL<<__rem)) != 0;
+}
+
+/*
+ * This will unroll the loop for the normal constant case (8 ints,
+ * for a 256-bit fd_set)
+ */
+#undef __FD_ZERO
+static inline void __FD_ZERO(__kernel_fd_set *__p)
+{
+       unsigned long *__tmp = __p->fds_bits;
+       int __i;
+
+       if (__builtin_constant_p(__FDSET_LONGS)) {
+               switch (__FDSET_LONGS) {
+               case 16:
+                       __tmp[ 0] = 0; __tmp[ 1] = 0;
+                       __tmp[ 2] = 0; __tmp[ 3] = 0;
+                       __tmp[ 4] = 0; __tmp[ 5] = 0;
+                       __tmp[ 6] = 0; __tmp[ 7] = 0;
+                       __tmp[ 8] = 0; __tmp[ 9] = 0;
+                       __tmp[10] = 0; __tmp[11] = 0;
+                       __tmp[12] = 0; __tmp[13] = 0;
+                       __tmp[14] = 0; __tmp[15] = 0;
+                       return;
+
+               case 8:
+                       __tmp[ 0] = 0; __tmp[ 1] = 0;
+                       __tmp[ 2] = 0; __tmp[ 3] = 0;
+                       __tmp[ 4] = 0; __tmp[ 5] = 0;
+                       __tmp[ 6] = 0; __tmp[ 7] = 0;
+                       return;
+
+               case 4:
+                       __tmp[ 0] = 0; __tmp[ 1] = 0;
+                       __tmp[ 2] = 0; __tmp[ 3] = 0;
+                       return;
+               }
+       }
+       __i = __FDSET_LONGS;
+       while (__i) {
+               __i--;
+               *__tmp = 0;
+               __tmp++;
+       }
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_GENERIC_POSIX_TYPES_H */
index 763e3b060f432542e07a6730a837185853418148..fa86f240c874328121862d0332930abc7e053ba8 100644 (file)
@@ -202,7 +202,7 @@ static inline unsigned int get_rtc_ss(void)
 {
        struct rtc_time h;
 
-       __get_rtc_time(&h);
+       get_rtc_time(&h);
        return h.tm_sec;
 }
 
diff --git a/include/asm-generic/scatterlist.h b/include/asm-generic/scatterlist.h
new file mode 100644 (file)
index 0000000..8b94544
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef __ASM_GENERIC_SCATTERLIST_H
+#define __ASM_GENERIC_SCATTERLIST_H
+
+#include <linux/types.h>
+
+struct scatterlist {
+#ifdef CONFIG_DEBUG_SG
+       unsigned long   sg_magic;
+#endif
+       unsigned long   page_link;
+       unsigned int    offset;
+       unsigned int    length;
+       dma_addr_t      dma_address;
+       unsigned int    dma_length;
+};
+
+/*
+ * These macros should be used after a dma_map_sg call has been done
+ * to get bus addresses of each of the SG entries and their lengths.
+ * You should only work with the number of sg entries pci_map_sg
+ * returns, or alternatively stop on the first sg_dma_len(sg) which
+ * is 0.
+ */
+#define sg_dma_address(sg)     ((sg)->dma_address)
+#ifndef sg_dma_len
+/*
+ * Normally, you have an iommu on 64 bit machines, but not on 32 bit
+ * machines. Architectures that are differnt should override this.
+ */
+#if __BITS_PER_LONG == 64
+#define sg_dma_len(sg)         ((sg)->dma_length)
+#else
+#define sg_dma_len(sg)         ((sg)->length)
+#endif /* 64 bit */
+#endif /* sg_dma_len */
+
+#ifndef ISA_DMA_THRESHOLD
+#define ISA_DMA_THRESHOLD      (~0UL)
+#endif
+
+#define ARCH_HAS_SG_CHAIN
+
+#endif /* __ASM_GENERIC_SCATTERLIST_H */
diff --git a/include/asm-generic/segment.h b/include/asm-generic/segment.h
new file mode 100644 (file)
index 0000000..5580eac
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef __ASM_GENERIC_SEGMENT_H
+#define __ASM_GENERIC_SEGMENT_H
+/*
+ * Only here because we have some old header files that expect it...
+ *
+ * New architectures probably don't want to have their own version.
+ */
+
+#endif /* __ASM_GENERIC_SEGMENT_H */
diff --git a/include/asm-generic/sembuf.h b/include/asm-generic/sembuf.h
new file mode 100644 (file)
index 0000000..4cb2c13
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef __ASM_GENERIC_SEMBUF_H
+#define __ASM_GENERIC_SEMBUF_H
+
+#include <asm/bitsperlong.h>
+
+/*
+ * The semid64_ds structure for x86 architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * semid64_ds was originally meant to be architecture specific, but
+ * everyone just ended up making identical copies without specific
+ * optimizations, so we may just as well all use the same one.
+ *
+ * 64 bit architectures typically define a 64 bit __kernel_time_t,
+ * so they do not need the first two padding words.
+ * On big-endian systems, the padding is in the wrong place.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+struct semid64_ds {
+       struct ipc64_perm sem_perm;     /* permissions .. see ipc.h */
+       __kernel_time_t sem_otime;      /* last semop time */
+#if __BITS_PER_LONG != 64
+       unsigned long   __unused1;
+#endif
+       __kernel_time_t sem_ctime;      /* last change time */
+#if __BITS_PER_LONG != 64
+       unsigned long   __unused2;
+#endif
+       unsigned long   sem_nsems;      /* no. of semaphores in array */
+       unsigned long   __unused3;
+       unsigned long   __unused4;
+};
+
+#endif /* __ASM_GENERIC_SEMBUF_H */
diff --git a/include/asm-generic/serial.h b/include/asm-generic/serial.h
new file mode 100644 (file)
index 0000000..5e29109
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __ASM_GENERIC_SERIAL_H
+#define __ASM_GENERIC_SERIAL_H
+
+/*
+ * This should not be an architecture specific #define, oh well.
+ *
+ * Traditionally, it just describes i8250 and related serial ports
+ * that have this clock rate.
+ */
+
+#define BASE_BAUD (1843200 / 16)
+
+#endif /* __ASM_GENERIC_SERIAL_H */
diff --git a/include/asm-generic/setup.h b/include/asm-generic/setup.h
new file mode 100644 (file)
index 0000000..6fc26a5
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __ASM_GENERIC_SETUP_H
+#define __ASM_GENERIC_SETUP_H
+
+#define COMMAND_LINE_SIZE      512
+
+#endif /* __ASM_GENERIC_SETUP_H */
diff --git a/include/asm-generic/shmbuf.h b/include/asm-generic/shmbuf.h
new file mode 100644 (file)
index 0000000..5768fa6
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef __ASM_GENERIC_SHMBUF_H
+#define __ASM_GENERIC_SHMBUF_H
+
+#include <asm/bitsperlong.h>
+
+/*
+ * The shmid64_ds structure for x86 architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * shmid64_ds was originally meant to be architecture specific, but
+ * everyone just ended up making identical copies without specific
+ * optimizations, so we may just as well all use the same one.
+ *
+ * 64 bit architectures typically define a 64 bit __kernel_time_t,
+ * so they do not need the first two padding words.
+ * On big-endian systems, the padding is in the wrong place.
+ *
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct shmid64_ds {
+       struct ipc64_perm       shm_perm;       /* operation perms */
+       size_t                  shm_segsz;      /* size of segment (bytes) */
+       __kernel_time_t         shm_atime;      /* last attach time */
+#if __BITS_PER_LONG != 64
+       unsigned long           __unused1;
+#endif
+       __kernel_time_t         shm_dtime;      /* last detach time */
+#if __BITS_PER_LONG != 64
+       unsigned long           __unused2;
+#endif
+       __kernel_time_t         shm_ctime;      /* last change time */
+#if __BITS_PER_LONG != 64
+       unsigned long           __unused3;
+#endif
+       __kernel_pid_t          shm_cpid;       /* pid of creator */
+       __kernel_pid_t          shm_lpid;       /* pid of last operator */
+       unsigned long           shm_nattch;     /* no. of current attaches */
+       unsigned long           __unused4;
+       unsigned long           __unused5;
+};
+
+struct shminfo64 {
+       unsigned long   shmmax;
+       unsigned long   shmmin;
+       unsigned long   shmmni;
+       unsigned long   shmseg;
+       unsigned long   shmall;
+       unsigned long   __unused1;
+       unsigned long   __unused2;
+       unsigned long   __unused3;
+       unsigned long   __unused4;
+};
+
+#endif /* __ASM_GENERIC_SHMBUF_H */
diff --git a/include/asm-generic/shmparam.h b/include/asm-generic/shmparam.h
new file mode 100644 (file)
index 0000000..51a3852
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __ASM_GENERIC_SHMPARAM_H
+#define __ASM_GENERIC_SHMPARAM_H
+
+#define SHMLBA PAGE_SIZE        /* attach addr a multiple of this */
+
+#endif /* _ASM_GENERIC_SHMPARAM_H */
diff --git a/include/asm-generic/signal-defs.h b/include/asm-generic/signal-defs.h
new file mode 100644 (file)
index 0000000..00f95df
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef __ASM_GENERIC_SIGNAL_DEFS_H
+#define __ASM_GENERIC_SIGNAL_DEFS_H
+
+#include <linux/compiler.h>
+
+#ifndef SIG_BLOCK
+#define SIG_BLOCK          0   /* for blocking signals */
+#endif
+#ifndef SIG_UNBLOCK
+#define SIG_UNBLOCK        1   /* for unblocking signals */
+#endif
+#ifndef SIG_SETMASK
+#define SIG_SETMASK        2   /* for setting the signal mask */
+#endif
+
+#ifndef __ASSEMBLY__
+typedef void __signalfn_t(int);
+typedef __signalfn_t __user *__sighandler_t;
+
+typedef void __restorefn_t(void);
+typedef __restorefn_t __user *__sigrestore_t;
+
+#define SIG_DFL        ((__force __sighandler_t)0)     /* default signal handling */
+#define SIG_IGN        ((__force __sighandler_t)1)     /* ignore signal */
+#define SIG_ERR        ((__force __sighandler_t)-1)    /* error return from signal */
+#endif
+
+#endif /* __ASM_GENERIC_SIGNAL_DEFS_H */
index dae1d8720076fde1aad89772b6390f22b1db3345..555c0aee8a47844c360e3510fc5ec326b434436e 100644 (file)
 #ifndef __ASM_GENERIC_SIGNAL_H
 #define __ASM_GENERIC_SIGNAL_H
 
-#include <linux/compiler.h>
+#include <linux/types.h>
 
-#ifndef SIG_BLOCK
-#define SIG_BLOCK          0   /* for blocking signals */
-#endif
-#ifndef SIG_UNBLOCK
-#define SIG_UNBLOCK        1   /* for unblocking signals */
-#endif
-#ifndef SIG_SETMASK
-#define SIG_SETMASK        2   /* for setting the signal mask */
+#define _NSIG          64
+#define _NSIG_BPW      __BITS_PER_LONG
+#define _NSIG_WORDS    (_NSIG / _NSIG_BPW)
+
+#define SIGHUP          1
+#define SIGINT          2
+#define SIGQUIT                 3
+#define SIGILL          4
+#define SIGTRAP                 5
+#define SIGABRT                 6
+#define SIGIOT          6
+#define SIGBUS          7
+#define SIGFPE          8
+#define SIGKILL                 9
+#define SIGUSR1                10
+#define SIGSEGV                11
+#define SIGUSR2                12
+#define SIGPIPE                13
+#define SIGALRM                14
+#define SIGTERM                15
+#define SIGSTKFLT      16
+#define SIGCHLD                17
+#define SIGCONT                18
+#define SIGSTOP                19
+#define SIGTSTP                20
+#define SIGTTIN                21
+#define SIGTTOU                22
+#define SIGURG         23
+#define SIGXCPU                24
+#define SIGXFSZ                25
+#define SIGVTALRM      26
+#define SIGPROF                27
+#define SIGWINCH       28
+#define SIGIO          29
+#define SIGPOLL                SIGIO
+/*
+#define SIGLOST                29
+*/
+#define SIGPWR         30
+#define SIGSYS         31
+#define        SIGUNUSED       31
+
+/* These should not be considered constants from userland.  */
+#define SIGRTMIN       32
+#ifndef SIGRTMAX
+#define SIGRTMAX       _NSIG
 #endif
 
+/*
+ * SA_FLAGS values:
+ *
+ * SA_ONSTACK indicates that a registered stack_t will be used.
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
+ * SA_RESETHAND clears the handler when the signal is delivered.
+ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
+ * SA_NODEFER prevents the current signal from being masked in the handler.
+ *
+ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
+ * Unix names RESETHAND and NODEFER respectively.
+ */
+#define SA_NOCLDSTOP   0x00000001
+#define SA_NOCLDWAIT   0x00000002
+#define SA_SIGINFO     0x00000004
+#define SA_ONSTACK     0x08000000
+#define SA_RESTART     0x10000000
+#define SA_NODEFER     0x40000000
+#define SA_RESETHAND   0x80000000
+
+#define SA_NOMASK      SA_NODEFER
+#define SA_ONESHOT     SA_RESETHAND
+
+/*
+ * New architectures should not define the obsolete
+ *     SA_RESTORER     0x04000000
+ */
+
+/*
+ * sigaltstack controls
+ */
+#define SS_ONSTACK     1
+#define SS_DISABLE     2
+
+#define MINSIGSTKSZ    2048
+#define SIGSTKSZ       8192
+
 #ifndef __ASSEMBLY__
-typedef void __signalfn_t(int);
-typedef __signalfn_t __user *__sighandler_t;
+typedef struct {
+       unsigned long sig[_NSIG_WORDS];
+} sigset_t;
+
+/* not actually used, but required for linux/syscalls.h */
+typedef unsigned long old_sigset_t;
 
-typedef void __restorefn_t(void);
-typedef __restorefn_t __user *__sigrestore_t;
+#include <asm-generic/signal-defs.h>
 
-#define SIG_DFL        ((__force __sighandler_t)0)     /* default signal handling */
-#define SIG_IGN        ((__force __sighandler_t)1)     /* ignore signal */
-#define SIG_ERR        ((__force __sighandler_t)-1)    /* error return from signal */
+struct sigaction {
+       __sighandler_t sa_handler;
+       unsigned long sa_flags;
+#ifdef SA_RESTORER
+       __sigrestore_t sa_restorer;
 #endif
+       sigset_t sa_mask;               /* mask last for extensibility */
+};
+
+struct k_sigaction {
+       struct sigaction sa;
+};
+
+typedef struct sigaltstack {
+       void __user *ss_sp;
+       int ss_flags;
+       size_t ss_size;
+} stack_t;
+
+#ifdef __KERNEL__
+
+#include <asm/sigcontext.h>
+#undef __HAVE_ARCH_SIG_BITOPS
+
+#define ptrace_signal_deliver(regs, cookie) do { } while (0)
+
+#endif /* __KERNEL__ */
+#endif /* __ASSEMBLY__ */
 
-#endif /* __ASM_GENERIC_SIGNAL_H */
+#endif /* _ASM_GENERIC_SIGNAL_H */
diff --git a/include/asm-generic/socket.h b/include/asm-generic/socket.h
new file mode 100644 (file)
index 0000000..5d79e40
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef __ASM_GENERIC_SOCKET_H
+#define __ASM_GENERIC_SOCKET_H
+
+#include <asm/sockios.h>
+
+/* For setsockopt(2) */
+#define SOL_SOCKET     1
+
+#define SO_DEBUG       1
+#define SO_REUSEADDR   2
+#define SO_TYPE                3
+#define SO_ERROR       4
+#define SO_DONTROUTE   5
+#define SO_BROADCAST   6
+#define SO_SNDBUF      7
+#define SO_RCVBUF      8
+#define SO_SNDBUFFORCE 32
+#define SO_RCVBUFFORCE 33
+#define SO_KEEPALIVE   9
+#define SO_OOBINLINE   10
+#define SO_NO_CHECK    11
+#define SO_PRIORITY    12
+#define SO_LINGER      13
+#define SO_BSDCOMPAT   14
+/* To add :#define SO_REUSEPORT 15 */
+
+#ifndef SO_PASSCRED /* powerpc only differs in these */
+#define SO_PASSCRED    16
+#define SO_PEERCRED    17
+#define SO_RCVLOWAT    18
+#define SO_SNDLOWAT    19
+#define SO_RCVTIMEO    20
+#define SO_SNDTIMEO    21
+#endif
+
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+#define SO_SECURITY_AUTHENTICATION             22
+#define SO_SECURITY_ENCRYPTION_TRANSPORT       23
+#define SO_SECURITY_ENCRYPTION_NETWORK         24
+
+#define SO_BINDTODEVICE        25
+
+/* Socket filtering */
+#define SO_ATTACH_FILTER       26
+#define SO_DETACH_FILTER       27
+
+#define SO_PEERNAME            28
+#define SO_TIMESTAMP           29
+#define SCM_TIMESTAMP          SO_TIMESTAMP
+
+#define SO_ACCEPTCONN          30
+
+#define SO_PEERSEC             31
+#define SO_PASSSEC             34
+#define SO_TIMESTAMPNS         35
+#define SCM_TIMESTAMPNS                SO_TIMESTAMPNS
+
+#define SO_MARK                        36
+
+#define SO_TIMESTAMPING                37
+#define SCM_TIMESTAMPING       SO_TIMESTAMPING
+
+#endif /* __ASM_GENERIC_SOCKET_H */
diff --git a/include/asm-generic/sockios.h b/include/asm-generic/sockios.h
new file mode 100644 (file)
index 0000000..9a61a36
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __ASM_GENERIC_SOCKIOS_H
+#define __ASM_GENERIC_SOCKIOS_H
+
+/* Socket-level I/O control calls. */
+#define FIOSETOWN      0x8901
+#define SIOCSPGRP      0x8902
+#define FIOGETOWN      0x8903
+#define SIOCGPGRP      0x8904
+#define SIOCATMARK     0x8905
+#define SIOCGSTAMP     0x8906          /* Get stamp (timeval) */
+#define SIOCGSTAMPNS   0x8907          /* Get stamp (timespec) */
+
+#endif /* __ASM_GENERIC_SOCKIOS_H */
diff --git a/include/asm-generic/spinlock.h b/include/asm-generic/spinlock.h
new file mode 100644 (file)
index 0000000..1547a03
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __ASM_GENERIC_SPINLOCK_H
+#define __ASM_GENERIC_SPINLOCK_H
+/*
+ * You need to implement asm/spinlock.h for SMP support. The generic
+ * version does not handle SMP.
+ */
+#ifdef CONFIG_SMP
+#error need an architecture specific asm/spinlock.h
+#endif
+
+#endif /* __ASM_GENERIC_SPINLOCK_H */
diff --git a/include/asm-generic/stat.h b/include/asm-generic/stat.h
new file mode 100644 (file)
index 0000000..47e6417
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef __ASM_GENERIC_STAT_H
+#define __ASM_GENERIC_STAT_H
+
+/*
+ * Everybody gets this wrong and has to stick with it for all
+ * eternity. Hopefully, this version gets used by new architectures
+ * so they don't fall into the same traps.
+ *
+ * stat64 is copied from powerpc64, with explicit padding added.
+ * stat is the same structure layout on 64-bit, without the 'long long'
+ * types.
+ *
+ * By convention, 64 bit architectures use the stat interface, while
+ * 32 bit architectures use the stat64 interface. Note that we don't
+ * provide an __old_kernel_stat here, which new architecture should
+ * not have to start with.
+ */
+
+#include <asm/bitsperlong.h>
+
+#define STAT_HAVE_NSEC 1
+
+struct stat {
+       unsigned long   st_dev;         /* Device.  */
+       unsigned long   st_ino;         /* File serial number.  */
+       unsigned int    st_mode;        /* File mode.  */
+       unsigned int    st_nlink;       /* Link count.  */
+       unsigned int    st_uid;         /* User ID of the file's owner.  */
+       unsigned int    st_gid;         /* Group ID of the file's group. */
+       unsigned long   st_rdev;        /* Device number, if device.  */
+       unsigned long   __pad1;
+       long            st_size;        /* Size of file, in bytes.  */
+       int             st_blksize;     /* Optimal block size for I/O.  */
+       int             __pad2;
+       long            st_blocks;      /* Number 512-byte blocks allocated. */
+       int             st_atime;       /* Time of last access.  */
+       unsigned int    st_atime_nsec;
+       int             st_mtime;       /* Time of last modification.  */
+       unsigned int    st_mtime_nsec;
+       int             st_ctime;       /* Time of last status change.  */
+       unsigned int    st_ctime_nsec;
+       unsigned int    __unused4;
+       unsigned int    __unused5;
+};
+
+#if __BITS_PER_LONG != 64
+/* This matches struct stat64 in glibc2.1. Only used for 32 bit. */
+struct stat64 {
+       unsigned long long st_dev;      /* Device.  */
+       unsigned long long st_ino;      /* File serial number.  */
+       unsigned int    st_mode;        /* File mode.  */
+       unsigned int    st_nlink;       /* Link count.  */
+       unsigned int    st_uid;         /* User ID of the file's owner.  */
+       unsigned int    st_gid;         /* Group ID of the file's group. */
+       unsigned long long st_rdev;     /* Device number, if device.  */
+       unsigned long long __pad1;
+       long long       st_size;        /* Size of file, in bytes.  */
+       int             st_blksize;     /* Optimal block size for I/O.  */
+       int             __pad2;
+       long long       st_blocks;      /* Number 512-byte blocks allocated. */
+       int             st_atime;       /* Time of last access.  */
+       unsigned int    st_atime_nsec;
+       int             st_mtime;       /* Time of last modification.  */
+       unsigned int    st_mtime_nsec;
+       int             st_ctime;       /* Time of last status change.  */
+       unsigned int    st_ctime_nsec;
+       unsigned int    __unused4;
+       unsigned int    __unused5;
+};
+#endif
+
+#endif /* __ASM_GENERIC_STAT_H */
diff --git a/include/asm-generic/string.h b/include/asm-generic/string.h
new file mode 100644 (file)
index 0000000..de5e020
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __ASM_GENERIC_STRING_H
+#define __ASM_GENERIC_STRING_H
+/*
+ * The kernel provides all required functions in lib/string.c
+ *
+ * Architectures probably want to provide at least their own optimized
+ * memcpy and memset functions though.
+ */
+
+#endif /* __ASM_GENERIC_STRING_H */
diff --git a/include/asm-generic/swab.h b/include/asm-generic/swab.h
new file mode 100644 (file)
index 0000000..a8e9029
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _ASM_GENERIC_SWAB_H
+#define _ASM_GENERIC_SWAB_H
+
+#include <asm/bitsperlong.h>
+
+/*
+ * 32 bit architectures typically (but not always) want to
+ * set __SWAB_64_THRU_32__. In user space, this is only
+ * valid if the compiler supports 64 bit data types.
+ */
+
+#if __BITS_PER_LONG == 32
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__) || defined(__KERNEL__)
+#define __SWAB_64_THRU_32__
+#endif
+#endif
+
+#endif /* _ASM_GENERIC_SWAB_H */
diff --git a/include/asm-generic/syscalls.h b/include/asm-generic/syscalls.h
new file mode 100644 (file)
index 0000000..df84e3b
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef __ASM_GENERIC_SYSCALLS_H
+#define __ASM_GENERIC_SYSCALLS_H
+
+#include <linux/compiler.h>
+#include <linux/linkage.h>
+
+/*
+ * Calling conventions for these system calls can differ, so
+ * it's possible to override them.
+ */
+#ifndef sys_clone
+asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp,
+                       void __user *parent_tid, void __user *child_tid,
+                       struct pt_regs *regs);
+#endif
+
+#ifndef sys_fork
+asmlinkage long sys_fork(struct pt_regs *regs);
+#endif
+
+#ifndef sys_vfork
+asmlinkage long sys_vfork(struct pt_regs *regs);
+#endif
+
+#ifndef sys_execve
+asmlinkage long sys_execve(char __user *filename, char __user * __user *argv,
+                       char __user * __user *envp, struct pt_regs *regs);
+#endif
+
+#ifndef sys_mmap2
+asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
+                       unsigned long prot, unsigned long flags,
+                       unsigned long fd, unsigned long pgoff);
+#endif
+
+#ifndef sys_mmap
+asmlinkage long sys_mmap(unsigned long addr, unsigned long len,
+                       unsigned long prot, unsigned long flags,
+                       unsigned long fd, off_t pgoff);
+#endif
+
+#ifndef sys_sigaltstack
+asmlinkage long sys_sigaltstack(const stack_t __user *, stack_t __user *,
+                       struct pt_regs *);
+#endif
+
+#ifndef sys_rt_sigreturn
+asmlinkage long sys_rt_sigreturn(struct pt_regs *regs);
+#endif
+
+#ifndef sys_rt_sigsuspend
+asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize);
+#endif
+
+#ifndef sys_rt_sigaction
+asmlinkage long sys_rt_sigaction(int sig, const struct sigaction __user *act,
+                        struct sigaction __user *oact, size_t sigsetsize);
+#endif
+
+#endif /* __ASM_GENERIC_SYSCALLS_H */
diff --git a/include/asm-generic/system.h b/include/asm-generic/system.h
new file mode 100644 (file)
index 0000000..efa403b
--- /dev/null
@@ -0,0 +1,161 @@
+/* Generic system definitions, based on MN10300 definitions.
+ *
+ * It should be possible to use these on really simple architectures,
+ * but it serves more as a starting point for new ports.
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#ifndef __ASM_GENERIC_SYSTEM_H
+#define __ASM_GENERIC_SYSTEM_H
+
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+#include <linux/irqflags.h>
+
+#include <asm/cmpxchg-local.h>
+
+struct task_struct;
+
+/* context switching is now performed out-of-line in switch_to.S */
+extern struct task_struct *__switch_to(struct task_struct *,
+               struct task_struct *);
+#define switch_to(prev, next, last)                                    \
+       do {                                                            \
+               ((last) = __switch_to((prev), (next)));                 \
+       } while (0)
+
+#define arch_align_stack(x) (x)
+
+#define nop() asm volatile ("nop")
+
+#endif /* !__ASSEMBLY__ */
+
+/*
+ * Force strict CPU ordering.
+ * And yes, this is required on UP too when we're talking
+ * to devices.
+ *
+ * This implementation only contains a compiler barrier.
+ */
+
+#define mb()   asm volatile ("": : :"memory")
+#define rmb()  mb()
+#define wmb()  asm volatile ("": : :"memory")
+
+#ifdef CONFIG_SMP
+#define smp_mb()       mb()
+#define smp_rmb()      rmb()
+#define smp_wmb()      wmb()
+#else
+#define smp_mb()       barrier()
+#define smp_rmb()      barrier()
+#define smp_wmb()      barrier()
+#endif
+
+#define set_mb(var, value)  do { var = value;  mb(); } while (0)
+#define set_wmb(var, value) do { var = value; wmb(); } while (0)
+
+#define read_barrier_depends()         do {} while (0)
+#define smp_read_barrier_depends()     do {} while (0)
+
+/*
+ * we make sure local_irq_enable() doesn't cause priority inversion
+ */
+#ifndef __ASSEMBLY__
+
+/* This function doesn't exist, so you'll get a linker error
+ *    if something tries to do an invalid xchg().  */
+extern void __xchg_called_with_bad_pointer(void);
+
+static inline
+unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
+{
+       unsigned long ret, flags;
+
+       switch (size) {
+       case 1:
+#ifdef __xchg_u8
+               return __xchg_u8(x, ptr);
+#else
+               local_irq_save(flags);
+               ret = *(volatile u8 *)ptr;
+               *(volatile u8 *)ptr = x;
+               local_irq_restore(flags);
+               return ret;
+#endif /* __xchg_u8 */
+
+       case 2:
+#ifdef __xchg_u16
+               return __xchg_u16(x, ptr);
+#else
+               local_irq_save(flags);
+               ret = *(volatile u16 *)ptr;
+               *(volatile u16 *)ptr = x;
+               local_irq_restore(flags);
+               return ret;
+#endif /* __xchg_u16 */
+
+       case 4:
+#ifdef __xchg_u32
+               return __xchg_u32(x, ptr);
+#else
+               local_irq_save(flags);
+               ret = *(volatile u32 *)ptr;
+               *(volatile u32 *)ptr = x;
+               local_irq_restore(flags);
+               return ret;
+#endif /* __xchg_u32 */
+
+#ifdef CONFIG_64BIT
+       case 8:
+#ifdef __xchg_u64
+               return __xchg_u64(x, ptr);
+#else
+               local_irq_save(flags);
+               ret = *(volatile u64 *)ptr;
+               *(volatile u64 *)ptr = x;
+               local_irq_restore(flags);
+               return ret;
+#endif /* __xchg_u64 */
+#endif /* CONFIG_64BIT */
+
+       default:
+               __xchg_called_with_bad_pointer();
+               return x;
+       }
+}
+
+#define xchg(ptr, x) \
+       ((__typeof__(*(ptr))) __xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
+
+static inline unsigned long __cmpxchg(volatile unsigned long *m,
+                                     unsigned long old, unsigned long new)
+{
+       unsigned long retval;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       retval = *m;
+       if (retval == old)
+               *m = new;
+       local_irq_restore(flags);
+       return retval;
+}
+
+#define cmpxchg(ptr, o, n)                                     \
+       ((__typeof__(*(ptr))) __cmpxchg((unsigned long *)(ptr), \
+                                       (unsigned long)(o),     \
+                                       (unsigned long)(n)))
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* __KERNEL__ */
+#endif /* __ASM_GENERIC_SYSTEM_H */
diff --git a/include/asm-generic/termbits.h b/include/asm-generic/termbits.h
new file mode 100644 (file)
index 0000000..1c9773d
--- /dev/null
@@ -0,0 +1,198 @@
+#ifndef __ASM_GENERIC_TERMBITS_H
+#define __ASM_GENERIC_TERMBITS_H
+
+#include <linux/posix_types.h>
+
+typedef unsigned char  cc_t;
+typedef unsigned int   speed_t;
+typedef unsigned int   tcflag_t;
+
+#define NCCS 19
+struct termios {
+       tcflag_t c_iflag;               /* input mode flags */
+       tcflag_t c_oflag;               /* output mode flags */
+       tcflag_t c_cflag;               /* control mode flags */
+       tcflag_t c_lflag;               /* local mode flags */
+       cc_t c_line;                    /* line discipline */
+       cc_t c_cc[NCCS];                /* control characters */
+};
+
+struct termios2 {
+       tcflag_t c_iflag;               /* input mode flags */
+       tcflag_t c_oflag;               /* output mode flags */
+       tcflag_t c_cflag;               /* control mode flags */
+       tcflag_t c_lflag;               /* local mode flags */
+       cc_t c_line;                    /* line discipline */
+       cc_t c_cc[NCCS];                /* control characters */
+       speed_t c_ispeed;               /* input speed */
+       speed_t c_ospeed;               /* output speed */
+};
+
+struct ktermios {
+       tcflag_t c_iflag;               /* input mode flags */
+       tcflag_t c_oflag;               /* output mode flags */
+       tcflag_t c_cflag;               /* control mode flags */
+       tcflag_t c_lflag;               /* local mode flags */
+       cc_t c_line;                    /* line discipline */
+       cc_t c_cc[NCCS];                /* control characters */
+       speed_t c_ispeed;               /* input speed */
+       speed_t c_ospeed;               /* output speed */
+};
+
+/* c_cc characters */
+#define VINTR 0
+#define VQUIT 1
+#define VERASE 2
+#define VKILL 3
+#define VEOF 4
+#define VTIME 5
+#define VMIN 6
+#define VSWTC 7
+#define VSTART 8
+#define VSTOP 9
+#define VSUSP 10
+#define VEOL 11
+#define VREPRINT 12
+#define VDISCARD 13
+#define VWERASE 14
+#define VLNEXT 15
+#define VEOL2 16
+
+/* c_iflag bits */
+#define IGNBRK 0000001
+#define BRKINT 0000002
+#define IGNPAR 0000004
+#define PARMRK 0000010
+#define INPCK  0000020
+#define ISTRIP 0000040
+#define INLCR  0000100
+#define IGNCR  0000200
+#define ICRNL  0000400
+#define IUCLC  0001000
+#define IXON   0002000
+#define IXANY  0004000
+#define IXOFF  0010000
+#define IMAXBEL        0020000
+#define IUTF8  0040000
+
+/* c_oflag bits */
+#define OPOST  0000001
+#define OLCUC  0000002
+#define ONLCR  0000004
+#define OCRNL  0000010
+#define ONOCR  0000020
+#define ONLRET 0000040
+#define OFILL  0000100
+#define OFDEL  0000200
+#define NLDLY  0000400
+#define   NL0  0000000
+#define   NL1  0000400
+#define CRDLY  0003000
+#define   CR0  0000000
+#define   CR1  0001000
+#define   CR2  0002000
+#define   CR3  0003000
+#define TABDLY 0014000
+#define   TAB0 0000000
+#define   TAB1 0004000
+#define   TAB2 0010000
+#define   TAB3 0014000
+#define   XTABS        0014000
+#define BSDLY  0020000
+#define   BS0  0000000
+#define   BS1  0020000
+#define VTDLY  0040000
+#define   VT0  0000000
+#define   VT1  0040000
+#define FFDLY  0100000
+#define   FF0  0000000
+#define   FF1  0100000
+
+/* c_cflag bit meaning */
+#define CBAUD  0010017
+#define  B0    0000000         /* hang up */
+#define  B50   0000001
+#define  B75   0000002
+#define  B110  0000003
+#define  B134  0000004
+#define  B150  0000005
+#define  B200  0000006
+#define  B300  0000007
+#define  B600  0000010
+#define  B1200 0000011
+#define  B1800 0000012
+#define  B2400 0000013
+#define  B4800 0000014
+#define  B9600 0000015
+#define  B19200        0000016
+#define  B38400        0000017
+#define EXTA B19200
+#define EXTB B38400
+#define CSIZE  0000060
+#define   CS5  0000000
+#define   CS6  0000020
+#define   CS7  0000040
+#define   CS8  0000060
+#define CSTOPB 0000100
+#define CREAD  0000200
+#define PARENB 0000400
+#define PARODD 0001000
+#define HUPCL  0002000
+#define CLOCAL 0004000
+#define CBAUDEX 0010000
+#define    BOTHER 0010000
+#define    B57600 0010001
+#define   B115200 0010002
+#define   B230400 0010003
+#define   B460800 0010004
+#define   B500000 0010005
+#define   B576000 0010006
+#define   B921600 0010007
+#define  B1000000 0010010
+#define  B1152000 0010011
+#define  B1500000 0010012
+#define  B2000000 0010013
+#define  B2500000 0010014
+#define  B3000000 0010015
+#define  B3500000 0010016
+#define  B4000000 0010017
+#define CIBAUD   002003600000  /* input baud rate */
+#define CMSPAR   010000000000  /* mark or space (stick) parity */
+#define CRTSCTS          020000000000  /* flow control */
+
+#define IBSHIFT          16            /* Shift from CBAUD to CIBAUD */
+
+/* c_lflag bits */
+#define ISIG   0000001
+#define ICANON 0000002
+#define XCASE  0000004
+#define ECHO   0000010
+#define ECHOE  0000020
+#define ECHOK  0000040
+#define ECHONL 0000100
+#define NOFLSH 0000200
+#define TOSTOP 0000400
+#define ECHOCTL        0001000
+#define ECHOPRT        0002000
+#define ECHOKE 0004000
+#define FLUSHO 0010000
+#define PENDIN 0040000
+#define IEXTEN 0100000
+
+/* tcflow() and TCXONC use these */
+#define        TCOOFF          0
+#define        TCOON           1
+#define        TCIOFF          2
+#define        TCION           3
+
+/* tcflush() and TCFLSH use these */
+#define        TCIFLUSH        0
+#define        TCOFLUSH        1
+#define        TCIOFLUSH       2
+
+/* tcsetattr uses these */
+#define        TCSANOW         0
+#define        TCSADRAIN       1
+#define        TCSAFLUSH       2
+
+#endif /* __ASM_GENERIC_TERMBITS_H */
diff --git a/include/asm-generic/termios-base.h b/include/asm-generic/termios-base.h
new file mode 100644 (file)
index 0000000..0a769fe
--- /dev/null
@@ -0,0 +1,77 @@
+/* termios.h: generic termios/termio user copying/translation
+ */
+
+#ifndef _ASM_GENERIC_TERMIOS_BASE_H
+#define _ASM_GENERIC_TERMIOS_BASE_H
+
+#include <asm/uaccess.h>
+
+#ifndef __ARCH_TERMIO_GETPUT
+
+/*
+ * Translate a "termio" structure into a "termios". Ugh.
+ */
+static inline int user_termio_to_kernel_termios(struct ktermios *termios,
+                                               struct termio __user *termio)
+{
+       unsigned short tmp;
+
+       if (get_user(tmp, &termio->c_iflag) < 0)
+               goto fault;
+       termios->c_iflag = (0xffff0000 & termios->c_iflag) | tmp;
+
+       if (get_user(tmp, &termio->c_oflag) < 0)
+               goto fault;
+       termios->c_oflag = (0xffff0000 & termios->c_oflag) | tmp;
+
+       if (get_user(tmp, &termio->c_cflag) < 0)
+               goto fault;
+       termios->c_cflag = (0xffff0000 & termios->c_cflag) | tmp;
+
+       if (get_user(tmp, &termio->c_lflag) < 0)
+               goto fault;
+       termios->c_lflag = (0xffff0000 & termios->c_lflag) | tmp;
+
+       if (get_user(termios->c_line, &termio->c_line) < 0)
+               goto fault;
+
+       if (copy_from_user(termios->c_cc, termio->c_cc, NCC) != 0)
+               goto fault;
+
+       return 0;
+
+ fault:
+       return -EFAULT;
+}
+
+/*
+ * Translate a "termios" structure into a "termio". Ugh.
+ */
+static inline int kernel_termios_to_user_termio(struct termio __user *termio,
+                                               struct ktermios *termios)
+{
+       if (put_user(termios->c_iflag, &termio->c_iflag) < 0 ||
+           put_user(termios->c_oflag, &termio->c_oflag) < 0 ||
+           put_user(termios->c_cflag, &termio->c_cflag) < 0 ||
+           put_user(termios->c_lflag, &termio->c_lflag) < 0 ||
+           put_user(termios->c_line,  &termio->c_line) < 0 ||
+           copy_to_user(termio->c_cc, termios->c_cc, NCC) != 0)
+               return -EFAULT;
+
+       return 0;
+}
+
+#ifndef user_termios_to_kernel_termios
+#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
+#endif
+
+#ifndef kernel_termios_to_user_termios
+#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
+#endif
+
+#define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios))
+#define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios))
+
+#endif /* __ARCH_TERMIO_GETPUT */
+
+#endif /* _ASM_GENERIC_TERMIOS_BASE_H */
index 7d39ecc92d9430380ccd00d4be4021932b1db8c3..d0922adc56d46949cf4fca9b768ad1296b1feb88 100644 (file)
@@ -1,18 +1,68 @@
-/* termios.h: generic termios/termio user copying/translation
- */
-
 #ifndef _ASM_GENERIC_TERMIOS_H
 #define _ASM_GENERIC_TERMIOS_H
+/*
+ * Most architectures have straight copies of the x86 code, with
+ * varying levels of bug fixes on top. Usually it's a good idea
+ * to use this generic version instead, but be careful to avoid
+ * ABI changes.
+ * New architectures should not provide their own version.
+ */
+
+#include <asm/termbits.h>
+#include <asm/ioctls.h>
+
+struct winsize {
+       unsigned short ws_row;
+       unsigned short ws_col;
+       unsigned short ws_xpixel;
+       unsigned short ws_ypixel;
+};
+
+#define NCC 8
+struct termio {
+       unsigned short c_iflag;         /* input mode flags */
+       unsigned short c_oflag;         /* output mode flags */
+       unsigned short c_cflag;         /* control mode flags */
+       unsigned short c_lflag;         /* local mode flags */
+       unsigned char c_line;           /* line discipline */
+       unsigned char c_cc[NCC];        /* control characters */
+};
+
+/* modem lines */
+#define TIOCM_LE       0x001
+#define TIOCM_DTR      0x002
+#define TIOCM_RTS      0x004
+#define TIOCM_ST       0x008
+#define TIOCM_SR       0x010
+#define TIOCM_CTS      0x020
+#define TIOCM_CAR      0x040
+#define TIOCM_RNG      0x080
+#define TIOCM_DSR      0x100
+#define TIOCM_CD       TIOCM_CAR
+#define TIOCM_RI       TIOCM_RNG
+#define TIOCM_OUT1     0x2000
+#define TIOCM_OUT2     0x4000
+#define TIOCM_LOOP     0x8000
+
+/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+
+#ifdef __KERNEL__
 
 #include <asm/uaccess.h>
 
-#ifndef __ARCH_TERMIO_GETPUT
+/*     intr=^C         quit=^\         erase=del       kill=^U
+       eof=^D          vtime=\0        vmin=\1         sxtc=\0
+       start=^Q        stop=^S         susp=^Z         eol=\0
+       reprint=^R      discard=^U      werase=^W       lnext=^V
+       eol2=\0
+*/
+#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
 
 /*
  * Translate a "termio" structure into a "termios". Ugh.
  */
 static inline int user_termio_to_kernel_termios(struct ktermios *termios,
-                                               struct termio __user *termio)
+                                               const struct termio __user *termio)
 {
        unsigned short tmp;
 
@@ -61,17 +111,44 @@ static inline int kernel_termios_to_user_termio(struct termio __user *termio,
        return 0;
 }
 
-#ifndef user_termios_to_kernel_termios
-#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
-#endif
+#ifdef TCGETS2
+static inline int user_termios_to_kernel_termios(struct ktermios *k,
+                                                struct termios2 __user *u)
+{
+       return copy_from_user(k, u, sizeof(struct termios2));
+}
 
-#ifndef kernel_termios_to_user_termios
-#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
-#endif
+static inline int kernel_termios_to_user_termios(struct termios2 __user *u,
+                                                struct ktermios *k)
+{
+       return copy_to_user(u, k, sizeof(struct termios2));
+}
 
-#define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios))
-#define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios))
+static inline int user_termios_to_kernel_termios_1(struct ktermios *k,
+                                                  struct termios __user *u)
+{
+       return copy_from_user(k, u, sizeof(struct termios));
+}
+
+static inline int kernel_termios_to_user_termios_1(struct termios __user *u,
+                                                  struct ktermios *k)
+{
+       return copy_to_user(u, k, sizeof(struct termios));
+}
+#else /* TCGETS2 */
+static inline int user_termios_to_kernel_termios(struct ktermios *k,
+                                                struct termios __user *u)
+{
+       return copy_from_user(k, u, sizeof(struct termios));
+}
+
+static inline int kernel_termios_to_user_termios(struct termios __user *u,
+                                                struct ktermios *k)
+{
+       return copy_to_user(u, k, sizeof(struct termios));
+}
+#endif /* TCGETS2 */
 
-#endif /* __ARCH_TERMIO_GETPUT */
+#endif /* __KERNEL__ */
 
 #endif /* _ASM_GENERIC_TERMIOS_H */
diff --git a/include/asm-generic/timex.h b/include/asm-generic/timex.h
new file mode 100644 (file)
index 0000000..b2243cb
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef __ASM_GENERIC_TIMEX_H
+#define __ASM_GENERIC_TIMEX_H
+
+/*
+ * If you have a cycle counter, return the value here.
+ */
+typedef unsigned long cycles_t;
+#ifndef get_cycles
+static inline cycles_t get_cycles(void)
+{
+       return 0;
+}
+#endif
+
+/*
+ * Architectures are encouraged to implement read_current_timer
+ * and define this in order to avoid the expensive delay loop
+ * calibration during boot.
+ */
+#undef ARCH_HAS_READ_CURRENT_TIMER
+
+#endif /* __ASM_GENERIC_TIMEX_H */
diff --git a/include/asm-generic/tlbflush.h b/include/asm-generic/tlbflush.h
new file mode 100644 (file)
index 0000000..c7af037
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef __ASM_GENERIC_TLBFLUSH_H
+#define __ASM_GENERIC_TLBFLUSH_H
+/*
+ * This is a dummy tlbflush implementation that can be used on all
+ * nommu architectures.
+ * If you have an MMU, you need to write your own functions.
+ */
+#ifdef CONFIG_MMU
+#error need to implement an architecture specific asm/tlbflush.h
+#endif
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+       BUG();
+}
+
+
+#endif /* __ASM_GENERIC_TLBFLUSH_H */
diff --git a/include/asm-generic/types.h b/include/asm-generic/types.h
new file mode 100644 (file)
index 0000000..fba7d33
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef _ASM_GENERIC_TYPES_H
+#define _ASM_GENERIC_TYPES_H
+/*
+ * int-ll64 is used practically everywhere now,
+ * so use it as a reasonable default.
+ */
+#include <asm-generic/int-ll64.h>
+
+#ifndef __ASSEMBLY__
+
+typedef unsigned short umode_t;
+
+#endif /* __ASSEMBLY__ */
+
+/*
+ * These aren't exported outside the kernel to avoid name space clashes
+ */
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+/*
+ * DMA addresses may be very different from physical addresses
+ * and pointers. i386 and powerpc may have 64 bit DMA on 32 bit
+ * systems, while sparc64 uses 32 bit DMA addresses for 64 bit
+ * physical addresses.
+ * This default defines dma_addr_t to have the same size as
+ * phys_addr_t, which is the most common way.
+ * Do not define the dma64_addr_t type, which never really
+ * worked.
+ */
+#ifndef dma_addr_t
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+typedef u64 dma_addr_t;
+#else
+typedef u32 dma_addr_t;
+#endif /* CONFIG_PHYS_ADDR_T_64BIT */
+#endif /* dma_addr_t */
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_GENERIC_TYPES_H */
diff --git a/include/asm-generic/uaccess-unaligned.h b/include/asm-generic/uaccess-unaligned.h
new file mode 100644 (file)
index 0000000..67deb89
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef __ASM_GENERIC_UACCESS_UNALIGNED_H
+#define __ASM_GENERIC_UACCESS_UNALIGNED_H
+
+/*
+ * This macro should be used instead of __get_user() when accessing
+ * values at locations that are not known to be aligned.
+ */
+#define __get_user_unaligned(x, ptr)                                   \
+({                                                                     \
+       __typeof__ (*(ptr)) __x;                                        \
+       __copy_from_user(&__x, (ptr), sizeof(*(ptr))) ? -EFAULT : 0;    \
+       (x) = __x;                                                      \
+})
+
+
+/*
+ * This macro should be used instead of __put_user() when accessing
+ * values at locations that are not known to be aligned.
+ */
+#define __put_user_unaligned(x, ptr)                                   \
+({                                                                     \
+       __typeof__ (*(ptr)) __x = (x);                                  \
+       __copy_to_user((ptr), &__x, sizeof(*(ptr))) ? -EFAULT : 0;      \
+})
+
+#endif /* __ASM_GENERIC_UACCESS_UNALIGNED_H */
index 549cb3a1640a5c7d3afba681d68a58cfbcc8664c..6d8cab22e2941b943dda136a924f4698114a44a9 100644 (file)
-#ifndef _ASM_GENERIC_UACCESS_H_
-#define _ASM_GENERIC_UACCESS_H_
+#ifndef __ASM_GENERIC_UACCESS_H
+#define __ASM_GENERIC_UACCESS_H
 
 /*
- * This macro should be used instead of __get_user() when accessing
- * values at locations that are not known to be aligned.
+ * User space memory access functions, these should work
+ * on a ny machine that has kernel and user data in the same
+ * address space, e.g. all NOMMU machines.
  */
-#define __get_user_unaligned(x, ptr)                                   \
-({                                                                     \
-       __typeof__ (*(ptr)) __x;                                        \
-       __copy_from_user(&__x, (ptr), sizeof(*(ptr))) ? -EFAULT : 0;    \
-       (x) = __x;                                                      \
-})
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+
+#include <asm/segment.h>
+
+#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
+
+#ifndef KERNEL_DS
+#define KERNEL_DS      MAKE_MM_SEG(~0UL)
+#endif
+
+#ifndef USER_DS
+#define USER_DS                MAKE_MM_SEG(TASK_SIZE - 1)
+#endif
+
+#ifndef get_fs
+#define get_ds()       (KERNEL_DS)
+#define get_fs()       (current_thread_info()->addr_limit)
+
+static inline void set_fs(mm_segment_t fs)
+{
+       current_thread_info()->addr_limit = fs;
+}
+#endif
 
+#define segment_eq(a, b) ((a).seg == (b).seg)
+
+#define VERIFY_READ    0
+#define VERIFY_WRITE   1
+
+#define access_ok(type, addr, size) __access_ok((unsigned long)(addr),(size))
+
+/*
+ * The architecture should really override this if possible, at least
+ * doing a check on the get_fs()
+ */
+#ifndef __access_ok
+static inline int __access_ok(unsigned long addr, unsigned long size)
+{
+       return 1;
+}
+#endif
 
 /*
- * This macro should be used instead of __put_user() when accessing
- * values at locations that are not known to be aligned.
+ * The exception table consists of pairs of addresses: the first is the
+ * address of an instruction that is allowed to fault, and the second is
+ * the address at which the program should continue.  No registers are
+ * modified, so it is entirely up to the continuation code to figure out
+ * what to do.
+ *
+ * All the routines below use bits of fixup code that are out of line
+ * with the main instruction path.  This means when everything is well,
+ * we don't even have to jump over them.  Further, they do not intrude
+ * on our cache or tlb entries.
  */
-#define __put_user_unaligned(x, ptr)                                   \
-({                                                                     \
-       __typeof__ (*(ptr)) __x = (x);                                  \
-       __copy_to_user((ptr), &__x, sizeof(*(ptr))) ? -EFAULT : 0;      \
+
+struct exception_table_entry
+{
+       unsigned long insn, fixup;
+};
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table(unsigned long);
+
+/*
+ * architectures with an MMU should override these two
+ */
+#ifndef __copy_from_user
+static inline __must_check long __copy_from_user(void *to,
+               const void __user * from, unsigned long n)
+{
+       if (__builtin_constant_p(n)) {
+               switch(n) {
+               case 1:
+                       *(u8 *)to = *(u8 __force *)from;
+                       return 0;
+               case 2:
+                       *(u16 *)to = *(u16 __force *)from;
+                       return 0;
+               case 4:
+                       *(u32 *)to = *(u32 __force *)from;
+                       return 0;
+#ifdef CONFIG_64BIT
+               case 8:
+                       *(u64 *)to = *(u64 __force *)from;
+                       return 0;
+#endif
+               default:
+                       break;
+               }
+       }
+
+       memcpy(to, (const void __force *)from, n);
+       return 0;
+}
+#endif
+
+#ifndef __copy_to_user
+static inline __must_check long __copy_to_user(void __user *to,
+               const void *from, unsigned long n)
+{
+       if (__builtin_constant_p(n)) {
+               switch(n) {
+               case 1:
+                       *(u8 __force *)to = *(u8 *)from;
+                       return 0;
+               case 2:
+                       *(u16 __force *)to = *(u16 *)from;
+                       return 0;
+               case 4:
+                       *(u32 __force *)to = *(u32 *)from;
+                       return 0;
+#ifdef CONFIG_64BIT
+               case 8:
+                       *(u64 __force *)to = *(u64 *)from;
+                       return 0;
+#endif
+               default:
+                       break;
+               }
+       }
+
+       memcpy((void __force *)to, from, n);
+       return 0;
+}
+#endif
+
+/*
+ * These are the main single-value transfer routines.  They automatically
+ * use the right size if we just have the right pointer type.
+ * This version just falls back to copy_{from,to}_user, which should
+ * provide a fast-path for small values.
+ */
+#define __put_user(x, ptr) \
+({                                                             \
+       __typeof__(*(ptr)) __x = (x);                           \
+       int __pu_err = -EFAULT;                                 \
+        __chk_user_ptr(ptr);                                    \
+       switch (sizeof (*(ptr))) {                              \
+       case 1:                                                 \
+       case 2:                                                 \
+       case 4:                                                 \
+       case 8:                                                 \
+               __pu_err = __put_user_fn(sizeof (*(ptr)),       \
+                                        ptr, &__x);            \
+               break;                                          \
+       default:                                                \
+               __put_user_bad();                               \
+               break;                                          \
+        }                                                      \
+       __pu_err;                                               \
+})
+
+#define put_user(x, ptr)                                       \
+({                                                             \
+       might_sleep();                                          \
+       __access_ok(ptr, sizeof (*ptr)) ?                       \
+               __put_user(x, ptr) :                            \
+               -EFAULT;                                        \
 })
 
-#endif /* _ASM_GENERIC_UACCESS_H */
+static inline int __put_user_fn(size_t size, void __user *ptr, void *x)
+{
+       size = __copy_to_user(ptr, x, size);
+       return size ? -EFAULT : size;
+}
+
+extern int __put_user_bad(void) __attribute__((noreturn));
+
+#define __get_user(x, ptr)                                     \
+({                                                             \
+       int __gu_err = -EFAULT;                                 \
+       __chk_user_ptr(ptr);                                    \
+       switch (sizeof(*(ptr))) {                               \
+       case 1: {                                               \
+               unsigned char __x;                              \
+               __gu_err = __get_user_fn(sizeof (*(ptr)),       \
+                                        ptr, &__x);            \
+               (x) = *(__force __typeof__(*(ptr)) *) &__x;     \
+               break;                                          \
+       };                                                      \
+       case 2: {                                               \
+               unsigned short __x;                             \
+               __gu_err = __get_user_fn(sizeof (*(ptr)),       \
+                                        ptr, &__x);            \
+               (x) = *(__force __typeof__(*(ptr)) *) &__x;     \
+               break;                                          \
+       };                                                      \
+       case 4: {                                               \
+               unsigned int __x;                               \
+               __gu_err = __get_user_fn(sizeof (*(ptr)),       \
+                                        ptr, &__x);            \
+               (x) = *(__force __typeof__(*(ptr)) *) &__x;     \
+               break;                                          \
+       };                                                      \
+       case 8: {                                               \
+               unsigned long long __x;                         \
+               __gu_err = __get_user_fn(sizeof (*(ptr)),       \
+                                        ptr, &__x);            \
+               (x) = *(__force __typeof__(*(ptr)) *) &__x;     \
+               break;                                          \
+       };                                                      \
+       default:                                                \
+               __get_user_bad();                               \
+               break;                                          \
+       }                                                       \
+       __gu_err;                                               \
+})
+
+#define get_user(x, ptr)                                       \
+({                                                             \
+       might_sleep();                                          \
+       __access_ok(ptr, sizeof (*ptr)) ?                       \
+               __get_user(x, ptr) :                            \
+               -EFAULT;                                        \
+})
+
+static inline int __get_user_fn(size_t size, const void __user *ptr, void *x)
+{
+       size = __copy_from_user(x, ptr, size);
+       return size ? -EFAULT : size;
+}
+
+extern int __get_user_bad(void) __attribute__((noreturn));
+
+#ifndef __copy_from_user_inatomic
+#define __copy_from_user_inatomic __copy_from_user
+#endif
+
+#ifndef __copy_to_user_inatomic
+#define __copy_to_user_inatomic __copy_to_user
+#endif
+
+static inline long copy_from_user(void *to,
+               const void __user * from, unsigned long n)
+{
+       might_sleep();
+       if (__access_ok(from, n))
+               return __copy_from_user(to, from, n);
+       else
+               return n;
+}
+
+static inline long copy_to_user(void __user *to,
+               const void *from, unsigned long n)
+{
+       might_sleep();
+       if (__access_ok(to, n))
+               return __copy_to_user(to, from, n);
+       else
+               return n;
+}
+
+/*
+ * Copy a null terminated string from userspace.
+ */
+#ifndef __strncpy_from_user
+static inline long
+__strncpy_from_user(char *dst, const char __user *src, long count)
+{
+       char *tmp;
+       strncpy(dst, (const char __force *)src, count);
+       for (tmp = dst; *tmp && count > 0; tmp++, count--)
+               ;
+       return (tmp - dst);
+}
+#endif
+
+static inline long
+strncpy_from_user(char *dst, const char __user *src, long count)
+{
+       if (!__access_ok(src, 1))
+               return -EFAULT;
+       return __strncpy_from_user(dst, src, count);
+}
+
+/*
+ * Return the size of a string (including the ending 0)
+ *
+ * Return 0 on exception, a value greater than N if too long
+ */
+#ifndef strnlen_user
+static inline long strnlen_user(const char __user *src, long n)
+{
+       return strlen((void * __force)src) + 1;
+}
+#endif
+
+static inline long strlen_user(const char __user *src)
+{
+       return strnlen_user(src, 32767);
+}
+
+/*
+ * Zero Userspace
+ */
+#ifndef __clear_user
+static inline __must_check unsigned long
+__clear_user(void __user *to, unsigned long n)
+{
+       memset((void __force *)to, 0, n);
+       return 0;
+}
+#endif
+
+static inline __must_check unsigned long
+clear_user(void __user *to, unsigned long n)
+{
+       might_sleep();
+       if (!__access_ok(to, n))
+               return n;
+
+       return __clear_user(to, n);
+}
+
+#endif /* __ASM_GENERIC_UACCESS_H */
diff --git a/include/asm-generic/ucontext.h b/include/asm-generic/ucontext.h
new file mode 100644 (file)
index 0000000..ad77343
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef __ASM_GENERIC_UCONTEXT_H
+#define __ASM_GENERIC_UCONTEXT_H
+
+struct ucontext {
+       unsigned long     uc_flags;
+       struct ucontext  *uc_link;
+       stack_t           uc_stack;
+       struct sigcontext uc_mcontext;
+       sigset_t          uc_sigmask;   /* mask last for extensibility */
+};
+
+#endif /* __ASM_GENERIC_UCONTEXT_H */
diff --git a/include/asm-generic/unaligned.h b/include/asm-generic/unaligned.h
new file mode 100644 (file)
index 0000000..03cf593
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef __ASM_GENERIC_UNALIGNED_H
+#define __ASM_GENERIC_UNALIGNED_H
+
+/*
+ * This is the most generic implementation of unaligned accesses
+ * and should work almost anywhere.
+ *
+ * If an architecture can handle unaligned accesses in hardware,
+ * it may want to use the linux/unaligned/access_ok.h implementation
+ * instead.
+ */
+#include <asm/byteorder.h>
+
+#if defined(__LITTLE_ENDIAN)
+# include <linux/unaligned/le_struct.h>
+# include <linux/unaligned/be_byteshift.h>
+# include <linux/unaligned/generic.h>
+# define get_unaligned __get_unaligned_le
+# define put_unaligned __put_unaligned_le
+#elif defined(__BIG_ENDIAN)
+# include <linux/unaligned/be_struct.h>
+# include <linux/unaligned/le_byteshift.h>
+# include <linux/unaligned/generic.h>
+# define get_unaligned __get_unaligned_be
+# define put_unaligned __put_unaligned_be
+#else
+# error need to define endianess
+#endif
+
+#endif /* __ASM_GENERIC_UNALIGNED_H */
diff --git a/include/asm-generic/unistd.h b/include/asm-generic/unistd.h
new file mode 100644 (file)
index 0000000..5b34b62
--- /dev/null
@@ -0,0 +1,854 @@
+#if !defined(_ASM_GENERIC_UNISTD_H) || defined(__SYSCALL)
+#define _ASM_GENERIC_UNISTD_H
+
+#include <asm/bitsperlong.h>
+
+/*
+ * This file contains the system call numbers, based on the
+ * layout of the x86-64 architecture, which embeds the
+ * pointer to the syscall in the table.
+ *
+ * As a basic principle, no duplication of functionality
+ * should be added, e.g. we don't use lseek when llseek
+ * is present. New architectures should use this file
+ * and implement the less feature-full calls in user space.
+ */
+
+#ifndef __SYSCALL
+#define __SYSCALL(x, y)
+#endif
+
+#if __BITS_PER_LONG == 32
+#define __SC_3264(_nr, _32, _64) __SYSCALL(_nr, _32)
+#else
+#define __SC_3264(_nr, _32, _64) __SYSCALL(_nr, _64)
+#endif
+
+#define __NR_io_setup 0
+__SYSCALL(__NR_io_setup, sys_io_setup)
+#define __NR_io_destroy 1
+__SYSCALL(__NR_io_destroy, sys_io_destroy)
+#define __NR_io_submit 2
+__SYSCALL(__NR_io_submit, sys_io_submit)
+#define __NR_io_cancel 3
+__SYSCALL(__NR_io_cancel, sys_io_cancel)
+#define __NR_io_getevents 4
+__SYSCALL(__NR_io_getevents, sys_io_getevents)
+
+/* fs/xattr.c */
+#define __NR_setxattr 5
+__SYSCALL(__NR_setxattr, sys_setxattr)
+#define __NR_lsetxattr 6
+__SYSCALL(__NR_lsetxattr, sys_lsetxattr)
+#define __NR_fsetxattr 7
+__SYSCALL(__NR_fsetxattr, sys_fsetxattr)
+#define __NR_getxattr 8
+__SYSCALL(__NR_getxattr, sys_getxattr)
+#define __NR_lgetxattr 9
+__SYSCALL(__NR_lgetxattr, sys_lgetxattr)
+#define __NR_fgetxattr 10
+__SYSCALL(__NR_fgetxattr, sys_fgetxattr)
+#define __NR_listxattr 11
+__SYSCALL(__NR_listxattr, sys_listxattr)
+#define __NR_llistxattr 12
+__SYSCALL(__NR_llistxattr, sys_llistxattr)
+#define __NR_flistxattr 13
+__SYSCALL(__NR_flistxattr, sys_flistxattr)
+#define __NR_removexattr 14
+__SYSCALL(__NR_removexattr, sys_removexattr)
+#define __NR_lremovexattr 15
+__SYSCALL(__NR_lremovexattr, sys_lremovexattr)
+#define __NR_fremovexattr 16
+__SYSCALL(__NR_fremovexattr, sys_fremovexattr)
+
+/* fs/dcache.c */
+#define __NR_getcwd 17
+__SYSCALL(__NR_getcwd, sys_getcwd)
+
+/* fs/cookies.c */
+#define __NR_lookup_dcookie 18
+__SYSCALL(__NR_lookup_dcookie, sys_lookup_dcookie)
+
+/* fs/eventfd.c */
+#define __NR_eventfd2 19
+__SYSCALL(__NR_eventfd2, sys_eventfd2)
+
+/* fs/eventpoll.c */
+#define __NR_epoll_create1 20
+__SYSCALL(__NR_epoll_create1, sys_epoll_create1)
+#define __NR_epoll_ctl 21
+__SYSCALL(__NR_epoll_ctl, sys_epoll_ctl)
+#define __NR_epoll_pwait 22
+__SYSCALL(__NR_epoll_pwait, sys_epoll_pwait)
+
+/* fs/fcntl.c */
+#define __NR_dup 23
+__SYSCALL(__NR_dup, sys_dup)
+#define __NR_dup3 24
+__SYSCALL(__NR_dup3, sys_dup3)
+#define __NR3264_fcntl 25
+__SC_3264(__NR3264_fcntl, sys_fcntl64, sys_fcntl)
+
+/* fs/inotify_user.c */
+#define __NR_inotify_init1 26
+__SYSCALL(__NR_inotify_init1, sys_inotify_init1)
+#define __NR_inotify_add_watch 27
+__SYSCALL(__NR_inotify_add_watch, sys_inotify_add_watch)
+#define __NR_inotify_rm_watch 28
+__SYSCALL(__NR_inotify_rm_watch, sys_inotify_rm_watch)
+
+/* fs/ioctl.c */
+#define __NR_ioctl 29
+__SYSCALL(__NR_ioctl, sys_ioctl)
+
+/* fs/ioprio.c */
+#define __NR_ioprio_set 30
+__SYSCALL(__NR_ioprio_set, sys_ioprio_set)
+#define __NR_ioprio_get 31
+__SYSCALL(__NR_ioprio_get, sys_ioprio_get)
+
+/* fs/locks.c */
+#define __NR_flock 32
+__SYSCALL(__NR_flock, sys_flock)
+
+/* fs/namei.c */
+#define __NR_mknodat 33
+__SYSCALL(__NR_mknodat, sys_mknodat)
+#define __NR_mkdirat 34
+__SYSCALL(__NR_mkdirat, sys_mkdirat)
+#define __NR_unlinkat 35
+__SYSCALL(__NR_unlinkat, sys_unlinkat)
+#define __NR_symlinkat 36
+__SYSCALL(__NR_symlinkat, sys_symlinkat)
+#define __NR_linkat 37
+__SYSCALL(__NR_linkat, sys_linkat)
+#define __NR_renameat 38
+__SYSCALL(__NR_renameat, sys_renameat)
+
+/* fs/namespace.c */
+#define __NR_umount2 39
+__SYSCALL(__NR_umount2, sys_umount)
+#define __NR_mount 40
+__SYSCALL(__NR_mount, sys_mount)
+#define __NR_pivot_root 41
+__SYSCALL(__NR_pivot_root, sys_pivot_root)
+
+/* fs/nfsctl.c */
+#define __NR_nfsservctl 42
+__SYSCALL(__NR_nfsservctl, sys_nfsservctl)
+
+/* fs/open.c */
+#define __NR3264_statfs 43
+__SC_3264(__NR3264_statfs, sys_statfs64, sys_statfs)
+#define __NR3264_fstatfs 44
+__SC_3264(__NR3264_fstatfs, sys_fstatfs64, sys_fstatfs)
+#define __NR3264_truncate 45
+__SC_3264(__NR3264_truncate, sys_truncate64, sys_truncate)
+#define __NR3264_ftruncate 46
+__SC_3264(__NR3264_ftruncate, sys_ftruncate64, sys_ftruncate)
+
+#define __NR_fallocate 47
+__SYSCALL(__NR_fallocate, sys_fallocate)
+#define __NR_faccessat 48
+__SYSCALL(__NR_faccessat, sys_faccessat)
+#define __NR_chdir 49
+__SYSCALL(__NR_chdir, sys_chdir)
+#define __NR_fchdir 50
+__SYSCALL(__NR_fchdir, sys_fchdir)
+#define __NR_chroot 51
+__SYSCALL(__NR_chroot, sys_chroot)
+#define __NR_fchmod 52
+__SYSCALL(__NR_fchmod, sys_fchmod)
+#define __NR_fchmodat 53
+__SYSCALL(__NR_fchmodat, sys_fchmodat)
+#define __NR_fchownat 54
+__SYSCALL(__NR_fchownat, sys_fchownat)
+#define __NR_fchown 55
+__SYSCALL(__NR_fchown, sys_fchown)
+#define __NR_openat 56
+__SYSCALL(__NR_openat, sys_openat)
+#define __NR_close 57
+__SYSCALL(__NR_close, sys_close)
+#define __NR_vhangup 58
+__SYSCALL(__NR_vhangup, sys_vhangup)
+
+/* fs/pipe.c */
+#define __NR_pipe2 59
+__SYSCALL(__NR_pipe2, sys_pipe2)
+
+/* fs/quota.c */
+#define __NR_quotactl 60
+__SYSCALL(__NR_quotactl, sys_quotactl)
+
+/* fs/readdir.c */
+#define __NR_getdents64 61
+__SYSCALL(__NR_getdents64, sys_getdents64)
+
+/* fs/read_write.c */
+#define __NR3264_lseek 62
+__SC_3264(__NR3264_lseek, sys_llseek, sys_lseek)
+#define __NR_read 63
+__SYSCALL(__NR_read, sys_read)
+#define __NR_write 64
+__SYSCALL(__NR_write, sys_write)
+#define __NR_readv 65
+__SYSCALL(__NR_readv, sys_readv)
+#define __NR_writev 66
+__SYSCALL(__NR_writev, sys_writev)
+#define __NR_pread64 67
+__SYSCALL(__NR_pread64, sys_pread64)
+#define __NR_pwrite64 68
+__SYSCALL(__NR_pwrite64, sys_pwrite64)
+#define __NR_preadv 69
+__SYSCALL(__NR_preadv, sys_preadv)
+#define __NR_pwritev 70
+__SYSCALL(__NR_pwritev, sys_pwritev)
+
+/* fs/sendfile.c */
+#define __NR3264_sendfile 71
+__SC_3264(__NR3264_sendfile, sys_sendfile64, sys_sendfile)
+
+/* fs/select.c */
+#define __NR_pselect6 72
+__SYSCALL(__NR_pselect6, sys_pselect6)
+#define __NR_ppoll 73
+__SYSCALL(__NR_ppoll, sys_ppoll)
+
+/* fs/signalfd.c */
+#define __NR_signalfd4 74
+__SYSCALL(__NR_signalfd4, sys_signalfd4)
+
+/* fs/splice.c */
+#define __NR_vmsplice 75
+__SYSCALL(__NR_vmsplice, sys_vmsplice)
+#define __NR_splice 76
+__SYSCALL(__NR_splice, sys_splice)
+#define __NR_tee 77
+__SYSCALL(__NR_tee, sys_tee)
+
+/* fs/stat.c */
+#define __NR_readlinkat 78
+__SYSCALL(__NR_readlinkat, sys_readlinkat)
+#define __NR3264_fstatat 79
+__SC_3264(__NR3264_fstatat, sys_fstatat64, sys_newfstatat)
+#define __NR3264_fstat 80
+__SC_3264(__NR3264_fstat, sys_fstat64, sys_newfstat)
+
+/* fs/sync.c */
+#define __NR_sync 81
+__SYSCALL(__NR_sync, sys_sync)
+#define __NR_fsync 82
+__SYSCALL(__NR_fsync, sys_fsync)
+#define __NR_fdatasync 83
+__SYSCALL(__NR_fdatasync, sys_fdatasync)
+#define __NR_sync_file_range 84
+__SYSCALL(__NR_sync_file_range, sys_sync_file_range) /* .long sys_sync_file_range2, */
+
+/* fs/timerfd.c */
+#define __NR_timerfd_create 85
+__SYSCALL(__NR_timerfd_create, sys_timerfd_create)
+#define __NR_timerfd_settime 86
+__SYSCALL(__NR_timerfd_settime, sys_timerfd_settime)
+#define __NR_timerfd_gettime 87
+__SYSCALL(__NR_timerfd_gettime, sys_timerfd_gettime)
+
+/* fs/utimes.c */
+#define __NR_utimensat 88
+__SYSCALL(__NR_utimensat, sys_utimensat)
+
+/* kernel/acct.c */
+#define __NR_acct 89
+__SYSCALL(__NR_acct, sys_acct)
+
+/* kernel/capability.c */
+#define __NR_capget 90
+__SYSCALL(__NR_capget, sys_capget)
+#define __NR_capset 91
+__SYSCALL(__NR_capset, sys_capset)
+
+/* kernel/exec_domain.c */
+#define __NR_personality 92
+__SYSCALL(__NR_personality, sys_personality)
+
+/* kernel/exit.c */
+#define __NR_exit 93
+__SYSCALL(__NR_exit, sys_exit)
+#define __NR_exit_group 94
+__SYSCALL(__NR_exit_group, sys_exit_group)
+#define __NR_waitid 95
+__SYSCALL(__NR_waitid, sys_waitid)
+
+/* kernel/fork.c */
+#define __NR_set_tid_address 96
+__SYSCALL(__NR_set_tid_address, sys_set_tid_address)
+#define __NR_unshare 97
+__SYSCALL(__NR_unshare, sys_unshare)
+
+/* kernel/futex.c */
+#define __NR_futex 98
+__SYSCALL(__NR_futex, sys_futex)
+#define __NR_set_robust_list 99
+__SYSCALL(__NR_set_robust_list, sys_set_robust_list)
+#define __NR_get_robust_list 100
+__SYSCALL(__NR_get_robust_list, sys_get_robust_list)
+
+/* kernel/hrtimer.c */
+#define __NR_nanosleep 101
+__SYSCALL(__NR_nanosleep, sys_nanosleep)
+
+/* kernel/itimer.c */
+#define __NR_getitimer 102
+__SYSCALL(__NR_getitimer, sys_getitimer)
+#define __NR_setitimer 103
+__SYSCALL(__NR_setitimer, sys_setitimer)
+
+/* kernel/kexec.c */
+#define __NR_kexec_load 104
+__SYSCALL(__NR_kexec_load, sys_kexec_load)
+
+/* kernel/module.c */
+#define __NR_init_module 105
+__SYSCALL(__NR_init_module, sys_init_module)
+#define __NR_delete_module 106
+__SYSCALL(__NR_delete_module, sys_delete_module)
+
+/* kernel/posix-timers.c */
+#define __NR_timer_create 107
+__SYSCALL(__NR_timer_create, sys_timer_create)
+#define __NR_timer_gettime 108
+__SYSCALL(__NR_timer_gettime, sys_timer_gettime)
+#define __NR_timer_getoverrun 109
+__SYSCALL(__NR_timer_getoverrun, sys_timer_getoverrun)
+#define __NR_timer_settime 110
+__SYSCALL(__NR_timer_settime, sys_timer_settime)
+#define __NR_timer_delete 111
+__SYSCALL(__NR_timer_delete, sys_timer_delete)
+#define __NR_clock_settime 112
+__SYSCALL(__NR_clock_settime, sys_clock_settime)
+#define __NR_clock_gettime 113
+__SYSCALL(__NR_clock_gettime, sys_clock_gettime)
+#define __NR_clock_getres 114
+__SYSCALL(__NR_clock_getres, sys_clock_getres)
+#define __NR_clock_nanosleep 115
+__SYSCALL(__NR_clock_nanosleep, sys_clock_nanosleep)
+
+/* kernel/printk.c */
+#define __NR_syslog 116
+__SYSCALL(__NR_syslog, sys_syslog)
+
+/* kernel/ptrace.c */
+#define __NR_ptrace 117
+__SYSCALL(__NR_ptrace, sys_ptrace)
+
+/* kernel/sched.c */
+#define __NR_sched_setparam 118
+__SYSCALL(__NR_sched_setparam, sys_sched_setparam)
+#define __NR_sched_setscheduler 119
+__SYSCALL(__NR_sched_setscheduler, sys_sched_setscheduler)
+#define __NR_sched_getscheduler 120
+__SYSCALL(__NR_sched_getscheduler, sys_sched_getscheduler)
+#define __NR_sched_getparam 121
+__SYSCALL(__NR_sched_getparam, sys_sched_getparam)
+#define __NR_sched_setaffinity 122
+__SYSCALL(__NR_sched_setaffinity, sys_sched_setaffinity)
+#define __NR_sched_getaffinity 123
+__SYSCALL(__NR_sched_getaffinity, sys_sched_getaffinity)
+#define __NR_sched_yield 124
+__SYSCALL(__NR_sched_yield, sys_sched_yield)
+#define __NR_sched_get_priority_max 125
+__SYSCALL(__NR_sched_get_priority_max, sys_sched_get_priority_max)
+#define __NR_sched_get_priority_min 126
+__SYSCALL(__NR_sched_get_priority_min, sys_sched_get_priority_min)
+#define __NR_sched_rr_get_interval 127
+__SYSCALL(__NR_sched_rr_get_interval, sys_sched_rr_get_interval)
+
+/* kernel/signal.c */
+#define __NR_restart_syscall 128
+__SYSCALL(__NR_restart_syscall, sys_restart_syscall)
+#define __NR_kill 129
+__SYSCALL(__NR_kill, sys_kill)
+#define __NR_tkill 130
+__SYSCALL(__NR_tkill, sys_tkill)
+#define __NR_tgkill 131
+__SYSCALL(__NR_tgkill, sys_tgkill)
+#define __NR_sigaltstack 132
+__SYSCALL(__NR_sigaltstack, sys_sigaltstack)
+#define __NR_rt_sigsuspend 133
+__SYSCALL(__NR_rt_sigsuspend, sys_rt_sigsuspend) /* __ARCH_WANT_SYS_RT_SIGSUSPEND */
+#define __NR_rt_sigaction 134
+__SYSCALL(__NR_rt_sigaction, sys_rt_sigaction) /* __ARCH_WANT_SYS_RT_SIGACTION */
+#define __NR_rt_sigprocmask 135
+__SYSCALL(__NR_rt_sigprocmask, sys_rt_sigprocmask)
+#define __NR_rt_sigpending 136
+__SYSCALL(__NR_rt_sigpending, sys_rt_sigpending)
+#define __NR_rt_sigtimedwait 137
+__SYSCALL(__NR_rt_sigtimedwait, sys_rt_sigtimedwait)
+#define __NR_rt_sigqueueinfo 138
+__SYSCALL(__NR_rt_sigqueueinfo, sys_rt_sigqueueinfo)
+#define __NR_rt_sigreturn 139
+__SYSCALL(__NR_rt_sigreturn, sys_rt_sigreturn) /* sys_rt_sigreturn_wrapper, */
+
+/* kernel/sys.c */
+#define __NR_setpriority 140
+__SYSCALL(__NR_setpriority, sys_setpriority)
+#define __NR_getpriority 141
+__SYSCALL(__NR_getpriority, sys_getpriority)
+#define __NR_reboot 142
+__SYSCALL(__NR_reboot, sys_reboot)
+#define __NR_setregid 143
+__SYSCALL(__NR_setregid, sys_setregid)
+#define __NR_setgid 144
+__SYSCALL(__NR_setgid, sys_setgid)
+#define __NR_setreuid 145
+__SYSCALL(__NR_setreuid, sys_setreuid)
+#define __NR_setuid 146
+__SYSCALL(__NR_setuid, sys_setuid)
+#define __NR_setresuid 147
+__SYSCALL(__NR_setresuid, sys_setresuid)
+#define __NR_getresuid 148
+__SYSCALL(__NR_getresuid, sys_getresuid)
+#define __NR_setresgid 149
+__SYSCALL(__NR_setresgid, sys_setresgid)
+#define __NR_getresgid 150
+__SYSCALL(__NR_getresgid, sys_getresgid)
+#define __NR_setfsuid 151
+__SYSCALL(__NR_setfsuid, sys_setfsuid)
+#define __NR_setfsgid 152
+__SYSCALL(__NR_setfsgid, sys_setfsgid)
+#define __NR_times 153
+__SYSCALL(__NR_times, sys_times)
+#define __NR_setpgid 154
+__SYSCALL(__NR_setpgid, sys_setpgid)
+#define __NR_getpgid 155
+__SYSCALL(__NR_getpgid, sys_getpgid)
+#define __NR_getsid 156
+__SYSCALL(__NR_getsid, sys_getsid)
+#define __NR_setsid 157
+__SYSCALL(__NR_setsid, sys_setsid)
+#define __NR_getgroups 158
+__SYSCALL(__NR_getgroups, sys_getgroups)
+#define __NR_setgroups 159
+__SYSCALL(__NR_setgroups, sys_setgroups)
+#define __NR_uname 160
+__SYSCALL(__NR_uname, sys_newuname)
+#define __NR_sethostname 161
+__SYSCALL(__NR_sethostname, sys_sethostname)
+#define __NR_setdomainname 162
+__SYSCALL(__NR_setdomainname, sys_setdomainname)
+#define __NR_getrlimit 163
+__SYSCALL(__NR_getrlimit, sys_getrlimit)
+#define __NR_setrlimit 164
+__SYSCALL(__NR_setrlimit, sys_setrlimit)
+#define __NR_getrusage 165
+__SYSCALL(__NR_getrusage, sys_getrusage)
+#define __NR_umask 166
+__SYSCALL(__NR_umask, sys_umask)
+#define __NR_prctl 167
+__SYSCALL(__NR_prctl, sys_prctl)
+#define __NR_getcpu 168
+__SYSCALL(__NR_getcpu, sys_getcpu)
+
+/* kernel/time.c */
+#define __NR_gettimeofday 169
+__SYSCALL(__NR_gettimeofday, sys_gettimeofday)
+#define __NR_settimeofday 170
+__SYSCALL(__NR_settimeofday, sys_settimeofday)
+#define __NR_adjtimex 171
+__SYSCALL(__NR_adjtimex, sys_adjtimex)
+
+/* kernel/timer.c */
+#define __NR_getpid 172
+__SYSCALL(__NR_getpid, sys_getpid)
+#define __NR_getppid 173
+__SYSCALL(__NR_getppid, sys_getppid)
+#define __NR_getuid 174
+__SYSCALL(__NR_getuid, sys_getuid)
+#define __NR_geteuid 175
+__SYSCALL(__NR_geteuid, sys_geteuid)
+#define __NR_getgid 176
+__SYSCALL(__NR_getgid, sys_getgid)
+#define __NR_getegid 177
+__SYSCALL(__NR_getegid, sys_getegid)
+#define __NR_gettid 178
+__SYSCALL(__NR_gettid, sys_gettid)
+#define __NR_sysinfo 179
+__SYSCALL(__NR_sysinfo, sys_sysinfo)
+
+/* ipc/mqueue.c */
+#define __NR_mq_open 180
+__SYSCALL(__NR_mq_open, sys_mq_open)
+#define __NR_mq_unlink 181
+__SYSCALL(__NR_mq_unlink, sys_mq_unlink)
+#define __NR_mq_timedsend 182
+__SYSCALL(__NR_mq_timedsend, sys_mq_timedsend)
+#define __NR_mq_timedreceive 183
+__SYSCALL(__NR_mq_timedreceive, sys_mq_timedreceive)
+#define __NR_mq_notify 184
+__SYSCALL(__NR_mq_notify, sys_mq_notify)
+#define __NR_mq_getsetattr 185
+__SYSCALL(__NR_mq_getsetattr, sys_mq_getsetattr)
+
+/* ipc/msg.c */
+#define __NR_msgget 186
+__SYSCALL(__NR_msgget, sys_msgget)
+#define __NR_msgctl 187
+__SYSCALL(__NR_msgctl, sys_msgctl)
+#define __NR_msgrcv 188
+__SYSCALL(__NR_msgrcv, sys_msgrcv)
+#define __NR_msgsnd 189
+__SYSCALL(__NR_msgsnd, sys_msgsnd)
+
+/* ipc/sem.c */
+#define __NR_semget 190
+__SYSCALL(__NR_semget, sys_semget)
+#define __NR_semctl 191
+__SYSCALL(__NR_semctl, sys_semctl)
+#define __NR_semtimedop 192
+__SYSCALL(__NR_semtimedop, sys_semtimedop)
+#define __NR_semop 193
+__SYSCALL(__NR_semop, sys_semop)
+
+/* ipc/shm.c */
+#define __NR_shmget 194
+__SYSCALL(__NR_shmget, sys_shmget)
+#define __NR_shmctl 195
+__SYSCALL(__NR_shmctl, sys_shmctl)
+#define __NR_shmat 196
+__SYSCALL(__NR_shmat, sys_shmat)
+#define __NR_shmdt 197
+__SYSCALL(__NR_shmdt, sys_shmdt)
+
+/* net/socket.c */
+#define __NR_socket 198
+__SYSCALL(__NR_socket, sys_socket)
+#define __NR_socketpair 199
+__SYSCALL(__NR_socketpair, sys_socketpair)
+#define __NR_bind 200
+__SYSCALL(__NR_bind, sys_bind)
+#define __NR_listen 201
+__SYSCALL(__NR_listen, sys_listen)
+#define __NR_accept 202
+__SYSCALL(__NR_accept, sys_accept)
+#define __NR_connect 203
+__SYSCALL(__NR_connect, sys_connect)
+#define __NR_getsockname 204
+__SYSCALL(__NR_getsockname, sys_getsockname)
+#define __NR_getpeername 205
+__SYSCALL(__NR_getpeername, sys_getpeername)
+#define __NR_sendto 206
+__SYSCALL(__NR_sendto, sys_sendto)
+#define __NR_recvfrom 207
+__SYSCALL(__NR_recvfrom, sys_recvfrom)
+#define __NR_setsockopt 208
+__SYSCALL(__NR_setsockopt, sys_setsockopt)
+#define __NR_getsockopt 209
+__SYSCALL(__NR_getsockopt, sys_getsockopt)
+#define __NR_shutdown 210
+__SYSCALL(__NR_shutdown, sys_shutdown)
+#define __NR_sendmsg 211
+__SYSCALL(__NR_sendmsg, sys_sendmsg)
+#define __NR_recvmsg 212
+__SYSCALL(__NR_recvmsg, sys_recvmsg)
+
+/* mm/filemap.c */
+#define __NR_readahead 213
+__SYSCALL(__NR_readahead, sys_readahead)
+
+/* mm/nommu.c, also with MMU */
+#define __NR_brk 214
+__SYSCALL(__NR_brk, sys_brk)
+#define __NR_munmap 215
+__SYSCALL(__NR_munmap, sys_munmap)
+#define __NR_mremap 216
+__SYSCALL(__NR_mremap, sys_mremap)
+
+/* security/keys/keyctl.c */
+#define __NR_add_key 217
+__SYSCALL(__NR_add_key, sys_add_key)
+#define __NR_request_key 218
+__SYSCALL(__NR_request_key, sys_request_key)
+#define __NR_keyctl 219
+__SYSCALL(__NR_keyctl, sys_keyctl)
+
+/* arch/example/kernel/sys_example.c */
+#define __NR_clone 220
+__SYSCALL(__NR_clone, sys_clone)       /* .long sys_clone_wrapper */
+#define __NR_execve 221
+__SYSCALL(__NR_execve, sys_execve)     /* .long sys_execve_wrapper */
+
+#define __NR3264_mmap 222
+__SC_3264(__NR3264_mmap, sys_mmap2, sys_mmap)
+/* mm/fadvise.c */
+#define __NR3264_fadvise64 223
+__SC_3264(__NR3264_fadvise64, sys_fadvise64_64, sys_fadvise64)
+
+/* mm/, CONFIG_MMU only */
+#ifndef __ARCH_NOMMU
+#define __NR_swapon 224
+__SYSCALL(__NR_swapon, sys_swapon)
+#define __NR_swapoff 225
+__SYSCALL(__NR_swapoff, sys_swapoff)
+#define __NR_mprotect 226
+__SYSCALL(__NR_mprotect, sys_mprotect)
+#define __NR_msync 227
+__SYSCALL(__NR_msync, sys_msync)
+#define __NR_mlock 228
+__SYSCALL(__NR_mlock, sys_mlock)
+#define __NR_munlock 229
+__SYSCALL(__NR_munlock, sys_munlock)
+#define __NR_mlockall 230
+__SYSCALL(__NR_mlockall, sys_mlockall)
+#define __NR_munlockall 231
+__SYSCALL(__NR_munlockall, sys_munlockall)
+#define __NR_mincore 232
+__SYSCALL(__NR_mincore, sys_mincore)
+#define __NR_madvise 233
+__SYSCALL(__NR_madvise, sys_madvise)
+#define __NR_remap_file_pages 234
+__SYSCALL(__NR_remap_file_pages, sys_remap_file_pages)
+#define __NR_mbind 235
+__SYSCALL(__NR_mbind, sys_mbind)
+#define __NR_get_mempolicy 236
+__SYSCALL(__NR_get_mempolicy, sys_get_mempolicy)
+#define __NR_set_mempolicy 237
+__SYSCALL(__NR_set_mempolicy, sys_set_mempolicy)
+#define __NR_migrate_pages 238
+__SYSCALL(__NR_migrate_pages, sys_migrate_pages)
+#define __NR_move_pages 239
+__SYSCALL(__NR_move_pages, sys_move_pages)
+#endif
+
+#undef __NR_syscalls
+#define __NR_syscalls 240
+
+/*
+ * All syscalls below here should go away really,
+ * these are provided for both review and as a porting
+ * help for the C library version.
+*
+ * Last chance: are any of these important enought to
+ * enable by default?
+ */
+#ifdef __ARCH_WANT_SYSCALL_NO_AT
+#define __NR_open 1024
+__SYSCALL(__NR_open, sys_open)
+#define __NR_link 1025
+__SYSCALL(__NR_link, sys_link)
+#define __NR_unlink 1026
+__SYSCALL(__NR_unlink, sys_unlink)
+#define __NR_mknod 1027
+__SYSCALL(__NR_mknod, sys_mknod)
+#define __NR_chmod 1028
+__SYSCALL(__NR_chmod, sys_chmod)
+#define __NR_chown 1029
+__SYSCALL(__NR_chown, sys_chown)
+#define __NR_mkdir 1030
+__SYSCALL(__NR_mkdir, sys_mkdir)
+#define __NR_rmdir 1031
+__SYSCALL(__NR_rmdir, sys_rmdir)
+#define __NR_lchown 1032
+__SYSCALL(__NR_lchown, sys_lchown)
+#define __NR_access 1033
+__SYSCALL(__NR_access, sys_access)
+#define __NR_rename 1034
+__SYSCALL(__NR_rename, sys_rename)
+#define __NR_readlink 1035
+__SYSCALL(__NR_readlink, sys_readlink)
+#define __NR_symlink 1036
+__SYSCALL(__NR_symlink, sys_symlink)
+#define __NR_utimes 1037
+__SYSCALL(__NR_utimes, sys_utimes)
+#define __NR3264_stat 1038
+__SC_3264(__NR3264_stat, sys_stat64, sys_newstat)
+#define __NR3264_lstat 1039
+__SC_3264(__NR3264_lstat, sys_lstat64, sys_newlstat)
+
+#undef __NR_syscalls
+#define __NR_syscalls (__NR3264_lstat+1)
+#endif /* __ARCH_WANT_SYSCALL_NO_AT */
+
+#ifdef __ARCH_WANT_SYSCALL_NO_FLAGS
+#define __NR_pipe 1040
+__SYSCALL(__NR_pipe, sys_pipe)
+#define __NR_dup2 1041
+__SYSCALL(__NR_dup2, sys_dup2)
+#define __NR_epoll_create 1042
+__SYSCALL(__NR_epoll_create, sys_epoll_create)
+#define __NR_inotify_init 1043
+__SYSCALL(__NR_inotify_init, sys_inotify_init)
+#define __NR_eventfd 1044
+__SYSCALL(__NR_eventfd, sys_eventfd)
+#define __NR_signalfd 1045
+__SYSCALL(__NR_signalfd, sys_signalfd)
+
+#undef __NR_syscalls
+#define __NR_syscalls (__NR_signalfd+1)
+#endif /* __ARCH_WANT_SYSCALL_NO_FLAGS */
+
+#if __BITS_PER_LONG == 32 && defined(__ARCH_WANT_SYSCALL_OFF_T)
+#define __NR_sendfile 1046
+__SYSCALL(__NR_sendfile, sys_sendfile)
+#define __NR_ftruncate 1047
+__SYSCALL(__NR_ftruncate, sys_ftruncate)
+#define __NR_truncate 1048
+__SYSCALL(__NR_truncate, sys_truncate)
+#define __NR_stat 1049
+__SYSCALL(__NR_stat, sys_newstat)
+#define __NR_lstat 1050
+__SYSCALL(__NR_lstat, sys_newlstat)
+#define __NR_fstat 1051
+__SYSCALL(__NR_fstat, sys_newfstat)
+#define __NR_fcntl 1052
+__SYSCALL(__NR_fcntl, sys_fcntl)
+#define __NR_fadvise64 1053
+#define __ARCH_WANT_SYS_FADVISE64
+__SYSCALL(__NR_fadvise64, sys_fadvise64)
+#define __NR_newfstatat 1054
+#define __ARCH_WANT_SYS_NEWFSTATAT
+__SYSCALL(__NR_newfstatat, sys_newfstatat)
+#define __NR_fstatfs 1055
+__SYSCALL(__NR_fstatfs, sys_fstatfs)
+#define __NR_statfs 1056
+__SYSCALL(__NR_statfs, sys_statfs)
+#define __NR_lseek 1057
+__SYSCALL(__NR_lseek, sys_lseek)
+#define __NR_mmap 1058
+__SYSCALL(__NR_mmap, sys_mmap)
+
+#undef __NR_syscalls
+#define __NR_syscalls (__NR_mmap+1)
+#endif /* 32 bit off_t syscalls */
+
+#ifdef __ARCH_WANT_SYSCALL_DEPRECATED
+#define __NR_alarm 1059
+#define __ARCH_WANT_SYS_ALARM
+__SYSCALL(__NR_alarm, sys_alarm)
+#define __NR_getpgrp 1060
+#define __ARCH_WANT_SYS_GETPGRP
+__SYSCALL(__NR_getpgrp, sys_getpgrp)
+#define __NR_pause 1061
+#define __ARCH_WANT_SYS_PAUSE
+__SYSCALL(__NR_pause, sys_pause)
+#define __NR_time 1062
+#define __ARCH_WANT_SYS_TIME
+__SYSCALL(__NR_time, sys_time)
+#define __NR_utime 1063
+#define __ARCH_WANT_SYS_UTIME
+__SYSCALL(__NR_utime, sys_utime)
+
+#define __NR_creat 1064
+__SYSCALL(__NR_creat, sys_creat)
+#define __NR_getdents 1065
+#define __ARCH_WANT_SYS_GETDENTS
+__SYSCALL(__NR_getdents, sys_getdents)
+#define __NR_futimesat 1066
+__SYSCALL(__NR_futimesat, sys_futimesat)
+#define __NR_select 1067
+#define __ARCH_WANT_SYS_SELECT
+__SYSCALL(__NR_select, sys_select)
+#define __NR_poll 1068
+__SYSCALL(__NR_poll, sys_poll)
+#define __NR_epoll_wait 1069
+__SYSCALL(__NR_epoll_wait, sys_epoll_wait)
+#define __NR_ustat 1070
+__SYSCALL(__NR_ustat, sys_ustat)
+#define __NR_vfork 1071
+__SYSCALL(__NR_vfork, sys_vfork)
+#define __NR_wait4 1072
+__SYSCALL(__NR_wait4, sys_wait4)
+#define __NR_recv 1073
+__SYSCALL(__NR_recv, sys_recv)
+#define __NR_send 1074
+__SYSCALL(__NR_send, sys_send)
+#define __NR_bdflush 1075
+__SYSCALL(__NR_bdflush, sys_bdflush)
+#define __NR_umount 1076
+__SYSCALL(__NR_umount, sys_oldumount)
+#define __ARCH_WANT_SYS_OLDUMOUNT
+#define __NR_uselib 1077
+__SYSCALL(__NR_uselib, sys_uselib)
+#define __NR__sysctl 1078
+__SYSCALL(__NR__sysctl, sys_sysctl)
+
+#define __NR_fork 1079
+#ifdef CONFIG_MMU
+__SYSCALL(__NR_fork, sys_fork)
+#else
+__SYSCALL(__NR_fork, sys_ni_syscall)
+#endif /* CONFIG_MMU */
+
+#undef __NR_syscalls
+#define __NR_syscalls (__NR_fork+1)
+
+#endif /* __ARCH_WANT_SYSCALL_DEPRECATED */
+
+/*
+ * 32 bit systems traditionally used different
+ * syscalls for off_t and loff_t arguments, while
+ * 64 bit systems only need the off_t version.
+ * For new 32 bit platforms, there is no need to
+ * implement the old 32 bit off_t syscalls, so
+ * they take different names.
+ * Here we map the numbers so that both versions
+ * use the same syscall table layout.
+ */
+#if __BITS_PER_LONG == 64
+#define __NR_fcntl __NR3264_fcntl
+#define __NR_statfs __NR3264_statfs
+#define __NR_fstatfs __NR3264_fstatfs
+#define __NR_truncate __NR3264_truncate
+#define __NR_ftruncate __NR3264_truncate
+#define __NR_lseek __NR3264_lseek
+#define __NR_sendfile __NR3264_sendfile
+#define __NR_newfstatat __NR3264_fstatat
+#define __NR_fstat __NR3264_fstat
+#define __NR_mmap __NR3264_mmap
+#define __NR_fadvise64 __NR3264_fadvise64
+#ifdef __NR3264_stat
+#define __NR_stat __NR3264_stat
+#define __NR_lstat __NR3264_lstat
+#endif
+#else
+#define __NR_fcntl64 __NR3264_fcntl
+#define __NR_statfs64 __NR3264_statfs
+#define __NR_fstatfs64 __NR3264_fstatfs
+#define __NR_truncate64 __NR3264_truncate
+#define __NR_ftruncate64 __NR3264_truncate
+#define __NR_llseek __NR3264_lseek
+#define __NR_sendfile64 __NR3264_sendfile
+#define __NR_fstatat64 __NR3264_fstatat
+#define __NR_fstat64 __NR3264_fstat
+#define __NR_mmap2 __NR3264_mmap
+#define __NR_fadvise64_64 __NR3264_fadvise64
+#ifdef __NR3264_stat
+#define __NR_stat64 __NR3264_stat
+#define __NR_lstat64 __NR3264_lstat
+#endif
+#endif
+
+#ifdef __KERNEL__
+
+/*
+ * These are required system calls, we should
+ * invert the logic eventually and let them
+ * be selected by default.
+ */
+#if __BITS_PER_LONG == 32
+#define __ARCH_WANT_STAT64
+#define __ARCH_WANT_SYS_LLSEEK
+#endif
+#define __ARCH_WANT_SYS_RT_SIGACTION
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
+
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on all toolchains, so we just do it by hand
+ */
+#ifndef cond_syscall
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
+#endif
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_GENERIC_UNISTD_H */
diff --git a/include/asm-generic/user.h b/include/asm-generic/user.h
new file mode 100644 (file)
index 0000000..8b9c3c9
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __ASM_GENERIC_USER_H
+#define __ASM_GENERIC_USER_H
+/*
+ * This file may define a 'struct user' structure. However, it it only
+ * used for a.out file, which are not supported on new architectures.
+ */
+
+#endif /* __ASM_GENERIC_USER_H */
diff --git a/include/asm-generic/vga.h b/include/asm-generic/vga.h
new file mode 100644 (file)
index 0000000..36c8ff5
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ *     Access to VGA videoram
+ *
+ *     (c) 1998 Martin Mares <mj@ucw.cz>
+ */
+#ifndef __ASM_GENERIC_VGA_H
+#define __ASM_GENERIC_VGA_H
+
+/*
+ *     On most architectures that support VGA, we can just
+ *     recalculate addresses and then access the videoram
+ *     directly without any black magic.
+ *
+ *     Everyone else needs to ioremap the address and use
+ *     proper I/O accesses.
+ */
+#ifndef VGA_MAP_MEM
+#define VGA_MAP_MEM(x, s) (unsigned long)phys_to_virt(x)
+#endif
+
+#define vga_readb(x) (*(x))
+#define vga_writeb(x, y) (*(y) = (x))
+
+#endif /* _ASM_GENERIC_VGA_H */
index f1736ca7922cb0022244087119f73a70e85f8b23..6bdba10fef4a51c88af6cb9fb154b32d885d2fa9 100644 (file)
@@ -1,4 +1,57 @@
-#include <linux/section-names.h>
+/*
+ * Helper macros to support writing architecture specific
+ * linker scripts.
+ *
+ * A minimal linker scripts has following content:
+ * [This is a sample, architectures may have special requiriements]
+ *
+ * OUTPUT_FORMAT(...)
+ * OUTPUT_ARCH(...)
+ * ENTRY(...)
+ * SECTIONS
+ * {
+ *     . = START;
+ *     __init_begin = .;
+ *     HEAD_TEXT_SECTION
+ *     INIT_TEXT_SECTION(PAGE_SIZE)
+ *     INIT_DATA_SECTION(...)
+ *     PERCPU(PAGE_SIZE)
+ *     __init_end = .;
+ *
+ *     _stext = .;
+ *     TEXT_SECTION = 0
+ *     _etext = .;
+ *
+ *      _sdata = .;
+ *     RO_DATA_SECTION(PAGE_SIZE)
+ *     RW_DATA_SECTION(...)
+ *     _edata = .;
+ *
+ *     EXCEPTION_TABLE(...)
+ *     NOTES
+ *
+ *     __bss_start = .;
+ *     BSS_SECTION(0, 0)
+ *     __bss_stop = .;
+ *     _end = .;
+ *
+ *     /DISCARD/ : {
+ *             EXIT_TEXT
+ *             EXIT_DATA
+ *             EXIT_CALL
+ *     }
+ *     STABS_DEBUG
+ *     DWARF_DEBUG
+ * }
+ *
+ * [__init_begin, __init_end] is the init section that may be freed after init
+ * [_stext, _etext] is the text section
+ * [_sdata, _edata] is the data section
+ *
+ * Some of the included output section have their own set of constants.
+ * Examples are: [__initramfs_start, __initramfs_end] for initramfs and
+ *               [__nosave_begin, __nosave_end] for the nosave data
+ */
 
 #ifndef LOAD_OFFSET
 #define LOAD_OFFSET 0
        FTRACE_EVENTS()                                                 \
        TRACE_SYSCALLS()
 
-#define RO_DATA(align)                                                 \
+/*
+ * Data section helpers
+ */
+#define NOSAVE_DATA                                                    \
+       . = ALIGN(PAGE_SIZE);                                           \
+       VMLINUX_SYMBOL(__nosave_begin) = .;                             \
+       *(.data.nosave)                                                 \
+       . = ALIGN(PAGE_SIZE);                                           \
+       VMLINUX_SYMBOL(__nosave_end) = .;
+
+#define PAGE_ALIGNED_DATA(page_align)                                  \
+       . = ALIGN(page_align);                                          \
+       *(.data.page_aligned)
+
+#define READ_MOSTLY_DATA(align)                                                \
+       . = ALIGN(align);                                               \
+       *(.data.read_mostly)
+
+#define CACHELINE_ALIGNED_DATA(align)                                  \
+       . = ALIGN(align);                                               \
+       *(.data.cacheline_aligned)
+
+#define INIT_TASK(align)                                               \
+       . = ALIGN(align);                                               \
+       *(.data.init_task)
+
+/*
+ * Read only Data
+ */
+#define RO_DATA_SECTION(align)                                         \
        . = ALIGN((align));                                             \
        .rodata           : AT(ADDR(.rodata) - LOAD_OFFSET) {           \
                VMLINUX_SYMBOL(__start_rodata) = .;                     \
        }                                                               \
        . = ALIGN((align));
 
-/* RODATA provided for backward compatibility.
+/* RODATA & RO_DATA provided for backward compatibility.
  * All archs are supposed to use RO_DATA() */
-#define RODATA RO_DATA(4096)
+#define RODATA          RO_DATA_SECTION(4096)
+#define RO_DATA(align)  RO_DATA_SECTION(align)
 
 #define SECURITY_INIT                                                  \
        .security_initcall.init : AT(ADDR(.security_initcall.init) - LOAD_OFFSET) { \
 #endif
 
 /* Section used for early init (in .S files) */
-#define HEAD_TEXT  *(HEAD_TEXT_SECTION)
+#define HEAD_TEXT  *(.head.text)
+
+#define HEAD_TEXT_SECTION                                                      \
+       .head.text : AT(ADDR(.head.text) - LOAD_OFFSET) {               \
+               HEAD_TEXT                                               \
+       }
+
+/*
+ * Exception table
+ */
+#define EXCEPTION_TABLE(align)                                         \
+       . = ALIGN(align);                                               \
+       __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {               \
+               VMLINUX_SYMBOL(__start___ex_table) = .;                 \
+               *(__ex_table)                                           \
+               VMLINUX_SYMBOL(__stop___ex_table) = .;                  \
+       }
+
+/*
+ * Init task
+ */
+#define INIT_TASK_DATA(align)                                          \
+       . = ALIGN(align);                                               \
+       .data.init_task : {                                             \
+               INIT_TASK                                               \
+       }
 
 /* init and exit section handling */
 #define INIT_DATA                                                      \
        *(.init.data)                                                   \
        DEV_DISCARD(init.data)                                          \
-       DEV_DISCARD(init.rodata)                                        \
        CPU_DISCARD(init.data)                                          \
-       CPU_DISCARD(init.rodata)                                        \
        MEM_DISCARD(init.data)                                          \
+       *(.init.rodata)                                                 \
+       DEV_DISCARD(init.rodata)                                        \
+       CPU_DISCARD(init.rodata)                                        \
        MEM_DISCARD(init.rodata)
 
 #define INIT_TEXT                                                      \
        CPU_DISCARD(exit.text)                                          \
        MEM_DISCARD(exit.text)
 
-               /* DWARF debug sections.
-               Symbols in the DWARF debugging sections are relative to
-               the beginning of the section so we begin them at 0.  */
+#define EXIT_CALL                                                      \
+       *(.exitcall.exit)
+
+/*
+ * bss (Block Started by Symbol) - uninitialized data
+ * zeroed during startup
+ */
+#define SBSS                                                           \
+       .sbss : AT(ADDR(.sbss) - LOAD_OFFSET) {                         \
+               *(.sbss)                                                \
+               *(.scommon)                                             \
+       }
+
+#define BSS(bss_align)                                                 \
+       . = ALIGN(bss_align);                                           \
+       .bss : AT(ADDR(.bss) - LOAD_OFFSET) {                           \
+               VMLINUX_SYMBOL(__bss_start) = .;                        \
+               *(.bss.page_aligned)                                    \
+               *(.dynbss)                                              \
+               *(.bss)                                                 \
+               *(COMMON)                                               \
+               VMLINUX_SYMBOL(__bss_stop) = .;                         \
+       }
+
+/*
+ * DWARF debug sections.
+ * Symbols in the DWARF debugging sections are relative to
+ * the beginning of the section so we begin them at 0.
+ */
 #define DWARF_DEBUG                                                    \
                /* DWARF 1 */                                           \
                .debug          0 : { *(.debug) }                       \
                VMLINUX_SYMBOL(__stop_notes) = .;                       \
        }
 
+#define INIT_SETUP(initsetup_align)                                    \
+               . = ALIGN(initsetup_align);                             \
+               VMLINUX_SYMBOL(__setup_start) = .;                      \
+               *(.init.setup)                                          \
+               VMLINUX_SYMBOL(__setup_end) = .;
+
 #define INITCALLS                                                      \
        *(.initcallearly.init)                                          \
        VMLINUX_SYMBOL(__early_initcall_end) = .;                       \
        *(.initcall7.init)                                              \
        *(.initcall7s.init)
 
+#define INIT_CALLS                                                     \
+               VMLINUX_SYMBOL(__initcall_start) = .;                   \
+               INITCALLS                                               \
+               VMLINUX_SYMBOL(__initcall_end) = .;
+
+#define CON_INITCALL                                                   \
+               VMLINUX_SYMBOL(__con_initcall_start) = .;               \
+               *(.con_initcall.init)                                   \
+               VMLINUX_SYMBOL(__con_initcall_end) = .;
+
+#define SECURITY_INITCALL                                              \
+               VMLINUX_SYMBOL(__security_initcall_start) = .;          \
+               *(.security_initcall.init)                              \
+               VMLINUX_SYMBOL(__security_initcall_end) = .;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+#define INIT_RAM_FS                                                    \
+       . = ALIGN(PAGE_SIZE);                                           \
+       VMLINUX_SYMBOL(__initramfs_start) = .;                          \
+       *(.init.ramfs)                                                  \
+       VMLINUX_SYMBOL(__initramfs_end) = .;
+#else
+#define INITRAMFS
+#endif
+
 /**
  * PERCPU_VADDR - define output section for percpu area
  * @vaddr: explicit base address (optional)
                *(.data.percpu.shared_aligned)                          \
                VMLINUX_SYMBOL(__per_cpu_end) = .;                      \
        }
+
+
+/*
+ * Definition of the high level *_SECTION macros
+ * They will fit only a subset of the architectures
+ */
+
+
+/*
+ * Writeable data.
+ * All sections are combined in a single .data section.
+ * The sections following CONSTRUCTORS are arranged so their
+ * typical alignment matches.
+ * A cacheline is typical/always less than a PAGE_SIZE so
+ * the sections that has this restriction (or similar)
+ * is located before the ones requiring PAGE_SIZE alignment.
+ * NOSAVE_DATA starts and ends with a PAGE_SIZE alignment which
+ * matches the requirment of PAGE_ALIGNED_DATA.
+ *
+ * use 0 as page_align if page_aligned data is not used */
+#define RW_DATA_SECTION(cacheline, nosave, pagealigned, inittask)      \
+       . = ALIGN(PAGE_SIZE);                                           \
+       .data : AT(ADDR(.data) - LOAD_OFFSET) {                         \
+               INIT_TASK(inittask)                                     \
+               CACHELINE_ALIGNED_DATA(cacheline)                       \
+               READ_MOSTLY_DATA(cacheline)                             \
+               DATA_DATA                                               \
+               CONSTRUCTORS                                            \
+               NOSAVE_DATA(nosave)                                     \
+               PAGE_ALIGNED_DATA(pagealigned)                          \
+       }
+
+#define INIT_TEXT_SECTION(inittext_align)                              \
+       . = ALIGN(inittext_align);                                      \
+       .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) {               \
+               VMLINUX_SYMBOL(_sinittext) = .;                         \
+               INIT_TEXT                                               \
+               VMLINUX_SYMBOL(_einittext) = .;                         \
+       }
+
+#define INIT_DATA_SECTION(initsetup_align)                             \
+       .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) {               \
+               INIT_DATA                                               \
+               INIT_SETUP(initsetup_align)                             \
+               INIT_CALLS                                              \
+               CON_INITCALL                                            \
+               SECURITY_INITCALL                                       \
+               INIT_RAM_FS                                             \
+       }
+
+#define BSS_SECTION(sbss_align, bss_align)                             \
+       SBSS                                                            \
+       BSS(bss_align)                                                  \
+       . = ALIGN(4);
+
index b84d8ae35e6f4a8fd9f5cb6d4df08ba8d274d3e6..d4ddc22e46bb5ba91ecd1368315e894461154eab 100644 (file)
@@ -86,7 +86,17 @@ struct drm_device;
 
 #include "drm_os_linux.h"
 #include "drm_hashtab.h"
+#include "drm_mm.h"
 
+#define DRM_UT_CORE            0x01
+#define DRM_UT_DRIVER          0x02
+#define DRM_UT_KMS             0x04
+#define DRM_UT_MODE            0x08
+
+extern void drm_ut_debug_printk(unsigned int request_level,
+                               const char *prefix,
+                               const char *function_name,
+                               const char *format, ...);
 /***********************************************************************/
 /** \name DRM template customization defaults */
 /*@{*/
@@ -186,15 +196,57 @@ struct drm_device;
  * \param arg arguments
  */
 #if DRM_DEBUG_CODE
-#define DRM_DEBUG(fmt, arg...)                                         \
+#define DRM_DEBUG(fmt, args...)                                                \
+       do {                                                            \
+               drm_ut_debug_printk(DRM_UT_CORE, DRM_NAME,              \
+                                       __func__, fmt, ##args);         \
+       } while (0)
+
+#define DRM_DEBUG_DRIVER(prefix, fmt, args...)                         \
+       do {                                                            \
+               drm_ut_debug_printk(DRM_UT_DRIVER, prefix,              \
+                                       __func__, fmt, ##args);         \
+       } while (0)
+#define DRM_DEBUG_KMS(prefix, fmt, args...)                            \
+       do {                                                            \
+               drm_ut_debug_printk(DRM_UT_KMS, prefix,                 \
+                                        __func__, fmt, ##args);        \
+       } while (0)
+#define DRM_DEBUG_MODE(prefix, fmt, args...)                           \
+       do {                                                            \
+               drm_ut_debug_printk(DRM_UT_MODE, prefix,                \
+                                        __func__, fmt, ##args);        \
+       } while (0)
+#define DRM_LOG(fmt, args...)                                          \
+       do {                                                            \
+               drm_ut_debug_printk(DRM_UT_CORE, NULL,                  \
+                                       NULL, fmt, ##args);             \
+       } while (0)
+#define DRM_LOG_KMS(fmt, args...)                                      \
+       do {                                                            \
+               drm_ut_debug_printk(DRM_UT_KMS, NULL,                   \
+                                       NULL, fmt, ##args);             \
+       } while (0)
+#define DRM_LOG_MODE(fmt, args...)                                     \
+       do {                                                            \
+               drm_ut_debug_printk(DRM_UT_MODE, NULL,                  \
+                                       NULL, fmt, ##args);             \
+       } while (0)
+#define DRM_LOG_DRIVER(fmt, args...)                                   \
        do {                                                            \
-               if ( drm_debug )                        \
-                       printk(KERN_DEBUG                               \
-                              "[" DRM_NAME ":%s] " fmt ,       \
-                              __func__ , ##arg);                       \
+               drm_ut_debug_printk(DRM_UT_DRIVER, NULL,                \
+                                       NULL, fmt, ##args);             \
        } while (0)
 #else
+#define DRM_DEBUG_DRIVER(prefix, fmt, args...) do { } while (0)
+#define DRM_DEBUG_KMS(prefix, fmt, args...)    do { } while (0)
+#define DRM_DEBUG_MODE(prefix, fmt, args...)   do { } while (0)
 #define DRM_DEBUG(fmt, arg...)          do { } while (0)
+#define DRM_LOG(fmt, arg...)           do { } while (0)
+#define DRM_LOG_KMS(fmt, args...) do { } while (0)
+#define DRM_LOG_MODE(fmt, arg...) do { } while (0)
+#define DRM_LOG_DRIVER(fmt, arg...) do { } while (0)
+
 #endif
 
 #define DRM_PROC_LIMIT (PAGE_SIZE-80)
@@ -237,15 +289,15 @@ struct drm_device;
  * \param dev DRM device.
  * \param filp file pointer of the caller.
  */
-#define LOCK_TEST_WITH_RETURN( dev, file_priv )                                \
-do {                                                                   \
-       if (!_DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock) ||                \
-           file_priv->master->lock.file_priv != file_priv)     {                       \
+#define LOCK_TEST_WITH_RETURN( dev, _file_priv )                               \
+do {                                                                           \
+       if (!_DRM_LOCK_IS_HELD(_file_priv->master->lock.hw_lock->lock) ||       \
+           _file_priv->master->lock.file_priv != _file_priv)   {               \
                DRM_ERROR( "%s called without lock held, held  %d owner %p %p\n",\
-                          __func__, _DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock),\
-                          file_priv->master->lock.file_priv, file_priv);               \
-               return -EINVAL;                                         \
-       }                                                               \
+                          __func__, _DRM_LOCK_IS_HELD(_file_priv->master->lock.hw_lock->lock),\
+                          _file_priv->master->lock.file_priv, _file_priv);     \
+               return -EINVAL;                                                 \
+       }                                                                       \
 } while (0)
 
 /**
@@ -502,26 +554,6 @@ struct drm_sigdata {
 };
 
 
-/*
- * Generic memory manager structs
- */
-
-struct drm_mm_node {
-       struct list_head fl_entry;
-       struct list_head ml_entry;
-       int free;
-       unsigned long start;
-       unsigned long size;
-       struct drm_mm *mm;
-       void *private;
-};
-
-struct drm_mm {
-       struct list_head fl_entry;
-       struct list_head ml_entry;
-};
-
-
 /**
  * Kernel side of a mapping
  */
@@ -1385,22 +1417,6 @@ extern char *drm_get_connector_status_name(enum drm_connector_status status);
 extern int drm_sysfs_connector_add(struct drm_connector *connector);
 extern void drm_sysfs_connector_remove(struct drm_connector *connector);
 
-/*
- * Basic memory manager support (drm_mm.c)
- */
-extern struct drm_mm_node *drm_mm_get_block(struct drm_mm_node * parent,
-                                      unsigned long size,
-                                      unsigned alignment);
-extern void drm_mm_put_block(struct drm_mm_node * cur);
-extern struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm, unsigned long size,
-                                        unsigned alignment, int best_match);
-extern int drm_mm_init(struct drm_mm *mm, unsigned long start, unsigned long size);
-extern void drm_mm_takedown(struct drm_mm *mm);
-extern int drm_mm_clean(struct drm_mm *mm);
-extern unsigned long drm_mm_tail_space(struct drm_mm *mm);
-extern int drm_mm_remove_space_from_tail(struct drm_mm *mm, unsigned long size);
-extern int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size);
-
 /* Graphics Execution Manager library functions (drm_gem.c) */
 int drm_gem_init(struct drm_device *dev);
 void drm_gem_destroy(struct drm_device *dev);
@@ -1522,18 +1538,14 @@ static __inline__ void *drm_calloc(size_t nmemb, size_t size, int area)
 
 static __inline__ void *drm_calloc_large(size_t nmemb, size_t size)
 {
-       u8 *addr;
-
-       if (size <= PAGE_SIZE)
+       if (size * nmemb <= PAGE_SIZE)
            return kcalloc(nmemb, size, GFP_KERNEL);
 
-       addr = vmalloc(nmemb * size);
-       if (!addr)
+       if (size != 0 && nmemb > ULONG_MAX / size)
                return NULL;
 
-       memset(addr, 0, nmemb * size);
-
-       return addr;
+       return __vmalloc(size * nmemb,
+                        GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL);
 }
 
 static __inline void drm_free_large(void *ptr)
index cd2b189e1be6caac74fd2402d1d84d4119fbca22..0af087a4d3b38e7ecaf8aeb05f3b3e1ee2d224f0 100644 (file)
@@ -35,6 +35,8 @@
 #ifndef DRM_HASHTAB_H
 #define DRM_HASHTAB_H
 
+#include <linux/list.h>
+
 #define drm_hash_entry(_ptr, _type, _member) container_of(_ptr, _type, _member)
 
 struct drm_hash_item {
diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h
new file mode 100644 (file)
index 0000000..5662f42
--- /dev/null
@@ -0,0 +1,90 @@
+/**************************************************************************
+ *
+ * Copyright 2006-2008 Tungsten Graphics, Inc., Cedar Park, TX. USA.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ **************************************************************************/
+/*
+ * Authors:
+ * Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
+ */
+
+#ifndef _DRM_MM_H_
+#define _DRM_MM_H_
+
+/*
+ * Generic range manager structs
+ */
+#include <linux/list.h>
+
+struct drm_mm_node {
+       struct list_head fl_entry;
+       struct list_head ml_entry;
+       int free;
+       unsigned long start;
+       unsigned long size;
+       struct drm_mm *mm;
+       void *private;
+};
+
+struct drm_mm {
+       struct list_head fl_entry;
+       struct list_head ml_entry;
+       struct list_head unused_nodes;
+       int num_unused;
+       spinlock_t unused_lock;
+};
+
+/*
+ * Basic range manager support (drm_mm.c)
+ */
+
+extern struct drm_mm_node *drm_mm_get_block(struct drm_mm_node *parent,
+                                           unsigned long size,
+                                           unsigned alignment);
+extern struct drm_mm_node *drm_mm_get_block_atomic(struct drm_mm_node *parent,
+                                                  unsigned long size,
+                                                  unsigned alignment);
+extern void drm_mm_put_block(struct drm_mm_node *cur);
+extern struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm,
+                                             unsigned long size,
+                                             unsigned alignment,
+                                             int best_match);
+extern int drm_mm_init(struct drm_mm *mm, unsigned long start,
+                      unsigned long size);
+extern void drm_mm_takedown(struct drm_mm *mm);
+extern int drm_mm_clean(struct drm_mm *mm);
+extern unsigned long drm_mm_tail_space(struct drm_mm *mm);
+extern int drm_mm_remove_space_from_tail(struct drm_mm *mm,
+                                        unsigned long size);
+extern int drm_mm_add_space_to_tail(struct drm_mm *mm,
+                                   unsigned long size, int atomic);
+extern int drm_mm_pre_get(struct drm_mm *mm);
+
+static inline struct drm_mm *drm_get_mm(struct drm_mm_node *block)
+{
+       return block->mm;
+}
+
+#endif
index fc55db78019943f30637668258682ccaa6c62f09..f8634ab53b8f98166a05af894d8789e790ee7435 100644 (file)
        {0x1002, 0x940A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x940B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x940F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x94A0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x94A1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x94B1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x94B3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x94B5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x9440, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x9441, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x9442, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x9456, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x945A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x945B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x946A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x946B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x947A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x8086, 0xa001, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \
        {0x8086, 0xa011, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \
        {0x8086, 0x35e8, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \
+       {0x8086, 0x0042, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \
+       {0x8086, 0x0046, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \
        {0, 0, 0}
diff --git a/include/linux/amba/pl022.h b/include/linux/amba/pl022.h
new file mode 100644 (file)
index 0000000..dcad0ff
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * include/linux/amba/pl022.h
+ *
+ * Copyright (C) 2008-2009 ST-Ericsson AB
+ * Copyright (C) 2006 STMicroelectronics Pvt. Ltd.
+ *
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ *
+ * Initial version inspired by:
+ *     linux-2.6.17-rc3-mm1/drivers/spi/pxa2xx_spi.c
+ * Initial adoption to PL022 by:
+ *      Sachin Verma <sachin.verma@st.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _SSP_PL022_H
+#define _SSP_PL022_H
+
+#include <linux/device.h>
+
+/**
+ * whether SSP is in loopback mode or not
+ */
+enum ssp_loopback {
+       LOOPBACK_DISABLED,
+       LOOPBACK_ENABLED
+};
+
+/**
+ * enum ssp_interface - interfaces allowed for this SSP Controller
+ * @SSP_INTERFACE_MOTOROLA_SPI: Motorola Interface
+ * @SSP_INTERFACE_TI_SYNC_SERIAL: Texas Instrument Synchronous Serial
+ * interface
+ * @SSP_INTERFACE_NATIONAL_MICROWIRE: National Semiconductor Microwire
+ * interface
+ * @SSP_INTERFACE_UNIDIRECTIONAL: Unidirectional interface (STn8810
+ * &STn8815 only)
+ */
+enum ssp_interface {
+       SSP_INTERFACE_MOTOROLA_SPI,
+       SSP_INTERFACE_TI_SYNC_SERIAL,
+       SSP_INTERFACE_NATIONAL_MICROWIRE,
+       SSP_INTERFACE_UNIDIRECTIONAL
+};
+
+/**
+ * enum ssp_hierarchy - whether SSP is configured as Master or Slave
+ */
+enum ssp_hierarchy {
+       SSP_MASTER,
+       SSP_SLAVE
+};
+
+/**
+ * enum ssp_clock_params - clock parameters, to set SSP clock at a
+ * desired freq
+ */
+struct ssp_clock_params {
+       u8 cpsdvsr; /* value from 2 to 254 (even only!) */
+       u8 scr;     /* value from 0 to 255 */
+};
+
+/**
+ * enum ssp_rx_endian - endianess of Rx FIFO Data
+ */
+enum ssp_rx_endian {
+       SSP_RX_MSB,
+       SSP_RX_LSB
+};
+
+/**
+ * enum ssp_tx_endian - endianess of Tx FIFO Data
+ */
+enum ssp_tx_endian {
+       SSP_TX_MSB,
+       SSP_TX_LSB
+};
+
+/**
+ * enum ssp_data_size - number of bits in one data element
+ */
+enum ssp_data_size {
+       SSP_DATA_BITS_4 = 0x03, SSP_DATA_BITS_5, SSP_DATA_BITS_6,
+       SSP_DATA_BITS_7, SSP_DATA_BITS_8, SSP_DATA_BITS_9,
+       SSP_DATA_BITS_10, SSP_DATA_BITS_11, SSP_DATA_BITS_12,
+       SSP_DATA_BITS_13, SSP_DATA_BITS_14, SSP_DATA_BITS_15,
+       SSP_DATA_BITS_16, SSP_DATA_BITS_17, SSP_DATA_BITS_18,
+       SSP_DATA_BITS_19, SSP_DATA_BITS_20, SSP_DATA_BITS_21,
+       SSP_DATA_BITS_22, SSP_DATA_BITS_23, SSP_DATA_BITS_24,
+       SSP_DATA_BITS_25, SSP_DATA_BITS_26, SSP_DATA_BITS_27,
+       SSP_DATA_BITS_28, SSP_DATA_BITS_29, SSP_DATA_BITS_30,
+       SSP_DATA_BITS_31, SSP_DATA_BITS_32
+};
+
+/**
+ * enum ssp_mode - SSP mode of operation (Communication modes)
+ */
+enum ssp_mode {
+       INTERRUPT_TRANSFER,
+       POLLING_TRANSFER,
+       DMA_TRANSFER
+};
+
+/**
+ * enum ssp_rx_level_trig - receive FIFO watermark level which triggers
+ * IT: Interrupt fires when _N_ or more elements in RX FIFO.
+ */
+enum ssp_rx_level_trig {
+       SSP_RX_1_OR_MORE_ELEM,
+       SSP_RX_4_OR_MORE_ELEM,
+       SSP_RX_8_OR_MORE_ELEM,
+       SSP_RX_16_OR_MORE_ELEM,
+       SSP_RX_32_OR_MORE_ELEM
+};
+
+/**
+ * Transmit FIFO watermark level which triggers (IT Interrupt fires
+ * when _N_ or more empty locations in TX FIFO)
+ */
+enum ssp_tx_level_trig {
+       SSP_TX_1_OR_MORE_EMPTY_LOC,
+       SSP_TX_4_OR_MORE_EMPTY_LOC,
+       SSP_TX_8_OR_MORE_EMPTY_LOC,
+       SSP_TX_16_OR_MORE_EMPTY_LOC,
+       SSP_TX_32_OR_MORE_EMPTY_LOC
+};
+
+/**
+ * enum SPI Clock Phase - clock phase (Motorola SPI interface only)
+ * @SSP_CLK_RISING_EDGE: Receive data on rising edge
+ * @SSP_CLK_FALLING_EDGE: Receive data on falling edge
+ */
+enum ssp_spi_clk_phase {
+       SSP_CLK_RISING_EDGE,
+       SSP_CLK_FALLING_EDGE
+};
+
+/**
+ * enum SPI Clock Polarity - clock polarity (Motorola SPI interface only)
+ * @SSP_CLK_POL_IDLE_LOW: Low inactive level
+ * @SSP_CLK_POL_IDLE_HIGH: High inactive level
+ */
+enum ssp_spi_clk_pol {
+       SSP_CLK_POL_IDLE_LOW,
+       SSP_CLK_POL_IDLE_HIGH
+};
+
+/**
+ * Microwire Conrol Lengths Command size in microwire format
+ */
+enum ssp_microwire_ctrl_len {
+       SSP_BITS_4 = 0x03, SSP_BITS_5, SSP_BITS_6,
+       SSP_BITS_7, SSP_BITS_8, SSP_BITS_9,
+       SSP_BITS_10, SSP_BITS_11, SSP_BITS_12,
+       SSP_BITS_13, SSP_BITS_14, SSP_BITS_15,
+       SSP_BITS_16, SSP_BITS_17, SSP_BITS_18,
+       SSP_BITS_19, SSP_BITS_20, SSP_BITS_21,
+       SSP_BITS_22, SSP_BITS_23, SSP_BITS_24,
+       SSP_BITS_25, SSP_BITS_26, SSP_BITS_27,
+       SSP_BITS_28, SSP_BITS_29, SSP_BITS_30,
+       SSP_BITS_31, SSP_BITS_32
+};
+
+/**
+ * enum Microwire Wait State
+ * @SSP_MWIRE_WAIT_ZERO: No wait state inserted after last command bit
+ * @SSP_MWIRE_WAIT_ONE: One wait state inserted after last command bit
+ */
+enum ssp_microwire_wait_state {
+       SSP_MWIRE_WAIT_ZERO,
+       SSP_MWIRE_WAIT_ONE
+};
+
+/**
+ * enum Microwire - whether Full/Half Duplex
+ * @SSP_MICROWIRE_CHANNEL_FULL_DUPLEX: SSPTXD becomes bi-directional,
+ *     SSPRXD not used
+ * @SSP_MICROWIRE_CHANNEL_HALF_DUPLEX: SSPTXD is an output, SSPRXD is
+ *     an input.
+ */
+enum ssp_duplex {
+       SSP_MICROWIRE_CHANNEL_FULL_DUPLEX,
+       SSP_MICROWIRE_CHANNEL_HALF_DUPLEX
+};
+
+/**
+ * CHIP select/deselect commands
+ */
+enum ssp_chip_select {
+       SSP_CHIP_SELECT,
+       SSP_CHIP_DESELECT
+};
+
+
+/**
+ * struct pl022_ssp_master - device.platform_data for SPI controller devices.
+ * @num_chipselect: chipselects are used to distinguish individual
+ *     SPI slaves, and are numbered from zero to num_chipselects - 1.
+ *     each slave has a chipselect signal, but it's common that not
+ *     every chipselect is connected to a slave.
+ * @enable_dma: if true enables DMA driven transfers.
+ */
+struct pl022_ssp_controller {
+       u16 bus_id;
+       u8 num_chipselect;
+       u8 enable_dma:1;
+};
+
+/**
+ * struct ssp_config_chip - spi_board_info.controller_data for SPI
+ * slave devices, copied to spi_device.controller_data.
+ *
+ * @lbm: used for test purpose to internally connect RX and TX
+ * @iface: Interface type(Motorola, TI, Microwire, Universal)
+ * @hierarchy: sets whether interface is master or slave
+ * @slave_tx_disable: SSPTXD is disconnected (in slave mode only)
+ * @clk_freq: Tune freq parameters of SSP(when in master mode)
+ * @endian_rx: Endianess of Data in Rx FIFO
+ * @endian_tx: Endianess of Data in Tx FIFO
+ * @data_size: Width of data element(4 to 32 bits)
+ * @com_mode: communication mode: polling, Interrupt or DMA
+ * @rx_lev_trig: Rx FIFO watermark level (for IT & DMA mode)
+ * @tx_lev_trig: Tx FIFO watermark level (for IT & DMA mode)
+ * @clk_phase: Motorola SPI interface Clock phase
+ * @clk_pol: Motorola SPI interface Clock polarity
+ * @ctrl_len: Microwire interface: Control length
+ * @wait_state: Microwire interface: Wait state
+ * @duplex: Microwire interface: Full/Half duplex
+ * @cs_control: function pointer to board-specific function to
+ * assert/deassert I/O port to control HW generation of devices chip-select.
+ * @dma_xfer_type: Type of DMA xfer (Mem-to-periph or Periph-to-Periph)
+ * @dma_config: DMA configuration for SSP controller and peripheral
+ */
+struct pl022_config_chip {
+       struct device *dev;
+       enum ssp_loopback lbm;
+       enum ssp_interface iface;
+       enum ssp_hierarchy hierarchy;
+       bool slave_tx_disable;
+       struct ssp_clock_params clk_freq;
+       enum ssp_rx_endian endian_rx;
+       enum ssp_tx_endian endian_tx;
+       enum ssp_data_size data_size;
+       enum ssp_mode com_mode;
+       enum ssp_rx_level_trig rx_lev_trig;
+       enum ssp_tx_level_trig tx_lev_trig;
+       enum ssp_spi_clk_phase clk_phase;
+       enum ssp_spi_clk_pol clk_pol;
+       enum ssp_microwire_ctrl_len ctrl_len;
+       enum ssp_microwire_wait_state wait_state;
+       enum ssp_duplex duplex;
+       void (*cs_control) (u32 control);
+};
+
+#endif /* _SSP_PL022_H */
index 64a982ea5d5fc08d6c57204ebf6555ad70aa6610..5a5a7fd62490ca34fe27baa952f48de8831d8197 100644 (file)
 #define UART011_IFLS_TX4_8     (2 << 0)
 #define UART011_IFLS_TX6_8     (3 << 0)
 #define UART011_IFLS_TX7_8     (4 << 0)
+/* special values for ST vendor with deeper fifo */
+#define UART011_IFLS_RX_HALF   (5 << 3)
+#define UART011_IFLS_TX_HALF   (5 << 0)
 
 #define UART011_OEIM           (1 << 10)       /* overrun error interrupt mask */
 #define UART011_BEIM           (1 << 9)        /* break error interrupt mask */
index 2f1f95737acb5d7e9e6df044a7190363522038e6..57b1846a3c876baf138214b2d511c693143fefa8 100644 (file)
@@ -10,6 +10,7 @@
  * @bus_width: Number of data lines wired up the slot
  * @detect_pin: GPIO pin wired to the card detect switch
  * @wp_pin: GPIO pin wired to the write protect sensor
+ * @detect_is_active_high: The state of the detect pin when it is active
  *
  * If a given slot is not present on the board, @bus_width should be
  * set to 0. The other fields are ignored in this case.
@@ -24,6 +25,7 @@ struct mci_slot_pdata {
        unsigned int            bus_width;
        int                     detect_pin;
        int                     wp_pin;
+       bool                    detect_is_active_high;
 };
 
 /**
index ebdfde8fe556166f19a81a59736cdb3b9aacaf6f..0b1a6cae9de1ebbc5010c2464ddc43cf33ae462b 100644 (file)
@@ -1226,6 +1226,8 @@ struct block_device_operations {
        int (*direct_access) (struct block_device *, sector_t,
                                                void **, unsigned long *);
        int (*media_changed) (struct gendisk *);
+       unsigned long long (*set_capacity) (struct gendisk *,
+                                               unsigned long long);
        int (*revalidate_disk) (struct gendisk *);
        int (*getgeo)(struct block_device *, struct hd_geometry *);
        struct module *owner;
diff --git a/include/linux/cb710.h b/include/linux/cb710.h
new file mode 100644 (file)
index 0000000..63bc9a4
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ *  cb710/cb710.h
+ *
+ *  Copyright by MichaÅ‚ MirosÅ‚aw, 2008-2009
+ *
+ * This 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_CB710_DRIVER_H
+#define LINUX_CB710_DRIVER_H
+
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/mmc/host.h>
+
+struct cb710_slot;
+
+typedef int (*cb710_irq_handler_t)(struct cb710_slot *);
+
+/* per-virtual-slot structure */
+struct cb710_slot {
+       struct platform_device  pdev;
+       void __iomem            *iobase;
+       cb710_irq_handler_t     irq_handler;
+};
+
+/* per-device structure */
+struct cb710_chip {
+       struct pci_dev          *pdev;
+       void __iomem            *iobase;
+       unsigned                platform_id;
+#ifdef CONFIG_CB710_DEBUG_ASSUMPTIONS
+       atomic_t                slot_refs_count;
+#endif
+       unsigned                slot_mask;
+       unsigned                slots;
+       spinlock_t              irq_lock;
+       struct cb710_slot       slot[0];
+};
+
+/* NOTE: cb710_chip.slots is modified only during device init/exit and
+ * they are all serialized wrt themselves */
+
+/* cb710_chip.slot_mask values */
+#define CB710_SLOT_MMC         1
+#define CB710_SLOT_MS          2
+#define CB710_SLOT_SM          4
+
+/* slot port accessors - so the logic is more clear in the code */
+#define CB710_PORT_ACCESSORS(t) \
+static inline void cb710_write_port_##t(struct cb710_slot *slot,       \
+       unsigned port, u##t value)                                      \
+{                                                                      \
+       iowrite##t(value, slot->iobase + port);                         \
+}                                                                      \
+                                                                       \
+static inline u##t cb710_read_port_##t(struct cb710_slot *slot,                \
+       unsigned port)                                                  \
+{                                                                      \
+       return ioread##t(slot->iobase + port);                          \
+}                                                                      \
+                                                                       \
+static inline void cb710_modify_port_##t(struct cb710_slot *slot,      \
+       unsigned port, u##t set, u##t clear)                            \
+{                                                                      \
+       iowrite##t(                                                     \
+               (ioread##t(slot->iobase + port) & ~clear)|set,          \
+               slot->iobase + port);                                   \
+}
+
+CB710_PORT_ACCESSORS(8)
+CB710_PORT_ACCESSORS(16)
+CB710_PORT_ACCESSORS(32)
+
+void cb710_pci_update_config_reg(struct pci_dev *pdev,
+       int reg, uint32_t and, uint32_t xor);
+void cb710_set_irq_handler(struct cb710_slot *slot,
+       cb710_irq_handler_t handler);
+
+/* some device struct walking */
+
+static inline struct cb710_slot *cb710_pdev_to_slot(
+       struct platform_device *pdev)
+{
+       return container_of(pdev, struct cb710_slot, pdev);
+}
+
+static inline struct cb710_chip *cb710_slot_to_chip(struct cb710_slot *slot)
+{
+       return dev_get_drvdata(slot->pdev.dev.parent);
+}
+
+static inline struct device *cb710_slot_dev(struct cb710_slot *slot)
+{
+       return &slot->pdev.dev;
+}
+
+static inline struct device *cb710_chip_dev(struct cb710_chip *chip)
+{
+       return &chip->pdev->dev;
+}
+
+/* debugging aids */
+
+#ifdef CONFIG_CB710_DEBUG
+void cb710_dump_regs(struct cb710_chip *chip, unsigned dump);
+#else
+#define cb710_dump_regs(c, d) do {} while (0)
+#endif
+
+#define CB710_DUMP_REGS_MMC    0x0F
+#define CB710_DUMP_REGS_MS     0x30
+#define CB710_DUMP_REGS_SM     0xC0
+#define CB710_DUMP_REGS_ALL    0xFF
+#define CB710_DUMP_REGS_MASK   0xFF
+
+#define CB710_DUMP_ACCESS_8    0x100
+#define CB710_DUMP_ACCESS_16   0x200
+#define CB710_DUMP_ACCESS_32   0x400
+#define CB710_DUMP_ACCESS_ALL  0x700
+#define CB710_DUMP_ACCESS_MASK 0x700
+
+#endif /* LINUX_CB710_DRIVER_H */
+/*
+ *  cb710/sgbuf2.h
+ *
+ *  Copyright by MichaÅ‚ MirosÅ‚aw, 2008-2009
+ *
+ * This 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_CB710_SG_H
+#define LINUX_CB710_SG_H
+
+#include <linux/highmem.h>
+#include <linux/scatterlist.h>
+
+/**
+ * cb710_sg_miter_stop_writing - stop mapping iteration after writing
+ * @miter: sg mapping iter to be stopped
+ *
+ * Description:
+ *   Stops mapping iterator @miter.  @miter should have been started
+ *   started using sg_miter_start().  A stopped iteration can be
+ *   resumed by calling sg_miter_next() on it.  This is useful when
+ *   resources (kmap) need to be released during iteration.
+ *
+ *   This is a convenience wrapper that will be optimized out for arches
+ *   that don't need flush_kernel_dcache_page().
+ *
+ * Context:
+ *   IRQ disabled if the SG_MITER_ATOMIC is set.  Don't care otherwise.
+ */
+static inline void cb710_sg_miter_stop_writing(struct sg_mapping_iter *miter)
+{
+       if (miter->page)
+               flush_kernel_dcache_page(miter->page);
+       sg_miter_stop(miter);
+}
+
+/*
+ * 32-bit PIO mapping sg iterator
+ *
+ * Hides scatterlist access issues - fragment boundaries, alignment, page
+ * mapping - for drivers using 32-bit-word-at-a-time-PIO (ie. PCI devices
+ * without DMA support).
+ *
+ * Best-case reading (transfer from device):
+ *   sg_miter_start();
+ *   cb710_sg_dwiter_write_from_io();
+ *   cb710_sg_miter_stop_writing();
+ *
+ * Best-case writing (transfer to device):
+ *   sg_miter_start();
+ *   cb710_sg_dwiter_read_to_io();
+ *   sg_miter_stop();
+ */
+
+uint32_t cb710_sg_dwiter_read_next_block(struct sg_mapping_iter *miter);
+void cb710_sg_dwiter_write_next_block(struct sg_mapping_iter *miter, uint32_t data);
+
+/**
+ * cb710_sg_dwiter_write_from_io - transfer data to mapped buffer from 32-bit IO port
+ * @miter: sg mapping iter
+ * @port: PIO port - IO or MMIO address
+ * @count: number of 32-bit words to transfer
+ *
+ * Description:
+ *   Reads @count 32-bit words from register @port and stores it in
+ *   buffer iterated by @miter.  Data that would overflow the buffer
+ *   is silently ignored.  Iterator is advanced by 4*@count bytes
+ *   or to the buffer's end whichever is closer.
+ *
+ * Context:
+ *   IRQ disabled if the SG_MITER_ATOMIC is set.  Don't care otherwise.
+ */
+static inline void cb710_sg_dwiter_write_from_io(struct sg_mapping_iter *miter,
+       void __iomem *port, size_t count)
+{
+       while (count-- > 0)
+               cb710_sg_dwiter_write_next_block(miter, ioread32(port));
+}
+
+/**
+ * cb710_sg_dwiter_read_to_io - transfer data to 32-bit IO port from mapped buffer
+ * @miter: sg mapping iter
+ * @port: PIO port - IO or MMIO address
+ * @count: number of 32-bit words to transfer
+ *
+ * Description:
+ *   Writes @count 32-bit words to register @port from buffer iterated
+ *   through @miter.  If buffer ends before @count words are written
+ *   missing data is replaced by zeroes. @miter is advanced by 4*@count
+ *   bytes or to the buffer's end whichever is closer.
+ *
+ * Context:
+ *   IRQ disabled if the SG_MITER_ATOMIC is set.  Don't care otherwise.
+ */
+static inline void cb710_sg_dwiter_read_to_io(struct sg_mapping_iter *miter,
+       void __iomem *port, size_t count)
+{
+       while (count-- > 0)
+               iowrite32(cb710_sg_dwiter_read_next_block(miter), port);
+}
+
+#endif /* LINUX_CB710_SG_H */
index 1db9bbf444a302f5cf18b31257789d5daa9709a2..1d37f42ac294bd9ca18b493ef947ec0f9d08cab0 100644 (file)
@@ -142,4 +142,17 @@ struct clk *clk_get_parent(struct clk *clk);
  */
 struct clk *clk_get_sys(const char *dev_id, const char *con_id);
 
+/**
+ * clk_add_alias - add a new clock alias
+ * @alias: name for clock alias
+ * @alias_dev_name: device name
+ * @id: platform specific clock name
+ * @dev: device
+ *
+ * Allows using generic clock names for drivers by adding a new alias.
+ * Assumes clkdev, see clkdev.h for more info.
+ */
+int clk_add_alias(const char *alias, const char *alias_dev_name, char *id,
+                       struct device *dev);
+
 #endif
index 37bcb50a4d7c85b1ac203982cc71f11e75511cde..04fb5135b4e16eea28e3e847d2ed36c01c78a88a 100644 (file)
@@ -261,6 +261,11 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
 # define __section(S) __attribute__ ((__section__(#S)))
 #endif
 
+/* Are two types/vars the same type (ignoring qualifiers)? */
+#ifndef __same_type
+# define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
+#endif
+
 /*
  * Prevent the compiler from merging or refetching accesses.  The compiler
  * is also forbidden from reordering successive instances of ACCESS_ONCE(),
index 5d5c197bad456be01863bd258113a5402a7d595c..a4a7b10aaa48a8b086142876272466a888069ce4 100644 (file)
@@ -62,8 +62,6 @@ struct bus_type {
        void (*shutdown)(struct device *dev);
 
        int (*suspend)(struct device *dev, pm_message_t state);
-       int (*suspend_late)(struct device *dev, pm_message_t state);
-       int (*resume_early)(struct device *dev);
        int (*resume)(struct device *dev);
 
        struct dev_pm_ops *pm;
@@ -291,9 +289,6 @@ struct device_type {
        int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
        void (*release)(struct device *dev);
 
-       int (*suspend)(struct device *dev, pm_message_t state);
-       int (*resume)(struct device *dev);
-
        struct dev_pm_ops *pm;
 };
 
index b9cd38603fd8325bf21c21206ab7fe246d026c6c..0b3518c4235697371df40558366345697e361df9 100644 (file)
@@ -81,8 +81,8 @@ struct dlm_lksb {
  * the cluster, the calling node joins it.
  */
 
-int dlm_new_lockspace(char *name, int namelen, dlm_lockspace_t **lockspace,
-                     uint32_t flags, int lvblen);
+int dlm_new_lockspace(const char *name, int namelen,
+                     dlm_lockspace_t **lockspace, uint32_t flags, int lvblen);
 
 /*
  * dlm_release_lockspace
index 162e5defe68358a250535974d4146412c4ff48b9..d41ed593f79fe01f8cc5ea25b3e6ea000cdc0e4c 100644 (file)
@@ -120,6 +120,13 @@ struct fuse_file_lock {
 #define FUSE_EXPORT_SUPPORT    (1 << 4)
 #define FUSE_BIG_WRITES                (1 << 5)
 
+/**
+ * CUSE INIT request/reply flags
+ *
+ * CUSE_UNRESTRICTED_IOCTL:  use unrestricted ioctl
+ */
+#define CUSE_UNRESTRICTED_IOCTL        (1 << 0)
+
 /**
  * Release flags
  */
@@ -210,6 +217,9 @@ enum fuse_opcode {
        FUSE_DESTROY       = 38,
        FUSE_IOCTL         = 39,
        FUSE_POLL          = 40,
+
+       /* CUSE specific operations */
+       CUSE_INIT          = 4096,
 };
 
 enum fuse_notify_code {
@@ -401,6 +411,27 @@ struct fuse_init_out {
        __u32   max_write;
 };
 
+#define CUSE_INIT_INFO_MAX 4096
+
+struct cuse_init_in {
+       __u32   major;
+       __u32   minor;
+       __u32   unused;
+       __u32   flags;
+};
+
+struct cuse_init_out {
+       __u32   major;
+       __u32   minor;
+       __u32   unused;
+       __u32   flags;
+       __u32   max_read;
+       __u32   max_write;
+       __u32   dev_major;              /* chardev major */
+       __u32   dev_minor;              /* chardev minor */
+       __u32   spare[10];
+};
+
 struct fuse_interrupt_in {
        __u64   unique;
 };
index 149fda264c86c9a404befd350d1a7c2006ab3213..7cbd38d363a2f051af1abbd30d7bbf90c066151e 100644 (file)
@@ -114,6 +114,7 @@ struct hd_struct {
 #define GENHD_FL_UP                            16
 #define GENHD_FL_SUPPRESS_PARTITION_INFO       32
 #define GENHD_FL_EXT_DEVT                      64 /* allow extended devt */
+#define GENHD_FL_NATIVE_CAPACITY               128
 
 #define BLK_SCSI_MAX_CMDS      (256)
 #define BLK_SCSI_CMD_PER_LONG  (BLK_SCSI_MAX_CMDS / (sizeof(long) * 8))
index 3885e7f7556216ff8769ca48b418e98befddef30..80e14b8c2e78313444f6fdad260a993975e9247d 100644 (file)
@@ -97,6 +97,9 @@ struct vm_area_struct;
                        __GFP_NOWARN|__GFP_REPEAT|__GFP_NOFAIL|\
                        __GFP_NORETRY|__GFP_NOMEMALLOC)
 
+/* Control slab gfp mask during early boot */
+#define SLAB_GFP_BOOT_MASK __GFP_BITS_MASK & ~(__GFP_WAIT|__GFP_IO|__GFP_FS)
+
 /* Control allocation constraints */
 #define GFP_CONSTRAINT_MASK (__GFP_HARDWALL|__GFP_THISNODE)
 
index a72876e435892cb3ce896e234e84084728434064..53489fd4d7006e35e6fe7bc95a50a0a956aee8dd 100644 (file)
@@ -238,6 +238,42 @@ struct hid_item {
 #define HID_GD_RIGHT           0x00010092
 #define HID_GD_LEFT            0x00010093
 
+#define HID_DG_DIGITIZER       0x000d0001
+#define HID_DG_PEN             0x000d0002
+#define HID_DG_LIGHTPEN                0x000d0003
+#define HID_DG_TOUCHSCREEN     0x000d0004
+#define HID_DG_TOUCHPAD                0x000d0005
+#define HID_DG_STYLUS          0x000d0020
+#define HID_DG_PUCK            0x000d0021
+#define HID_DG_FINGER          0x000d0022
+#define HID_DG_TIPPRESSURE     0x000d0030
+#define HID_DG_BARRELPRESSURE  0x000d0031
+#define HID_DG_INRANGE         0x000d0032
+#define HID_DG_TOUCH           0x000d0033
+#define HID_DG_UNTOUCH         0x000d0034
+#define HID_DG_TAP             0x000d0035
+#define HID_DG_TABLETFUNCTIONKEY       0x000d0039
+#define HID_DG_PROGRAMCHANGEKEY        0x000d003a
+#define HID_DG_INVERT          0x000d003c
+#define HID_DG_TIPSWITCH       0x000d0042
+#define HID_DG_TIPSWITCH2      0x000d0043
+#define HID_DG_BARRELSWITCH    0x000d0044
+#define HID_DG_ERASER          0x000d0045
+#define HID_DG_TABLETPICK      0x000d0046
+/*
+ * as of May 20, 2009 the usages below are not yet in the official USB spec
+ * but are being pushed by Microsft as described in their paper "Digitizer
+ * Drivers for Windows Touch and Pen-Based Computers"
+ */
+#define HID_DG_CONFIDENCE      0x000d0047
+#define HID_DG_WIDTH           0x000d0048
+#define HID_DG_HEIGHT          0x000d0049
+#define HID_DG_CONTACTID       0x000d0051
+#define HID_DG_INPUTMODE       0x000d0052
+#define HID_DG_DEVICEINDEX     0x000d0053
+#define HID_DG_CONTACTCOUNT    0x000d0054
+#define HID_DG_CONTACTMAX      0x000d0055
+
 /*
  * HID report types --- Ouch! HID spec says 1 2 3!
  */
index 8ed591b0887ea4a2babca0ad904ea73ccc436959..4d5e57ff66144f48fce709bcf5d151b96f8f1530 100644 (file)
@@ -14,6 +14,8 @@
 struct ocores_i2c_platform_data {
        u32 regstep;   /* distance between registers */
        u32 clock_khz; /* input clock in kHz */
+       u8 num_devices; /* number of devices in the devices list */
+       struct i2c_board_info const *devices; /* devices connected to the bus */
 };
 
 #endif /* _LINUX_I2C_OCORES_H */
index 867cb68d84619a8631670f839bf908a2db99b56b..a6c6a2fad7c88b107c6e7cfcb5a22fc3a46e7b26 100644 (file)
@@ -178,7 +178,7 @@ typedef u8 hwif_chipset_t;
 /*
  * Structure to hold all information about the location of this port
  */
-typedef struct hw_regs_s {
+struct ide_hw {
        union {
                struct ide_io_ports     io_ports;
                unsigned long           io_ports_array[IDE_NR_PORTS];
@@ -186,12 +186,11 @@ typedef struct hw_regs_s {
 
        int             irq;                    /* our irq number */
        ide_ack_intr_t  *ack_intr;              /* acknowledge interrupt */
-       hwif_chipset_t  chipset;
        struct device   *dev, *parent;
        unsigned long   config;
-} hw_regs_t;
+};
 
-static inline void ide_std_init_ports(hw_regs_t *hw,
+static inline void ide_std_init_ports(struct ide_hw *hw,
                                      unsigned long io_addr,
                                      unsigned long ctl_addr)
 {
@@ -218,21 +217,12 @@ static inline void ide_std_init_ports(hw_regs_t *hw,
 
 /*
  * Special Driver Flags
- *
- * set_geometry        : respecify drive geometry
- * recalibrate : seek to cyl 0
- * set_multmode        : set multmode count
- * reserved    : unused
  */
-typedef union {
-       unsigned all                    : 8;
-       struct {
-               unsigned set_geometry   : 1;
-               unsigned recalibrate    : 1;
-               unsigned set_multmode   : 1;
-               unsigned reserved       : 5;
-       } b;
-} special_t;
+enum {
+       IDE_SFLAG_SET_GEOMETRY          = (1 << 0),
+       IDE_SFLAG_RECALIBRATE           = (1 << 1),
+       IDE_SFLAG_SET_MULTMODE          = (1 << 2),
+};
 
 /*
  * Status returned from various ide_ functions
@@ -391,6 +381,7 @@ struct ide_drive_s;
 struct ide_disk_ops {
        int             (*check)(struct ide_drive_s *, const char *);
        int             (*get_capacity)(struct ide_drive_s *);
+       u64             (*set_capacity)(struct ide_drive_s *, u64);
        void            (*setup)(struct ide_drive_s *);
        void            (*flush)(struct ide_drive_s *);
        int             (*init_media)(struct ide_drive_s *, struct gendisk *);
@@ -468,6 +459,8 @@ enum {
        IDE_DFLAG_NICE1                 = (1 << 5),
        /* device is physically present */
        IDE_DFLAG_PRESENT               = (1 << 6),
+       /* disable Host Protected Area */
+       IDE_DFLAG_NOHPA                 = (1 << 7),
        /* id read from device (synthetic if not set) */
        IDE_DFLAG_ID_READ               = (1 << 8),
        IDE_DFLAG_NOPROBE               = (1 << 9),
@@ -506,6 +499,7 @@ enum {
        /* write protect */
        IDE_DFLAG_WP                    = (1 << 29),
        IDE_DFLAG_FORMAT_IN_PROGRESS    = (1 << 30),
+       IDE_DFLAG_NIEN_QUIRK            = (1 << 31),
 };
 
 struct ide_drive_s {
@@ -530,14 +524,13 @@ struct ide_drive_s {
        unsigned long sleep;            /* sleep until this time */
        unsigned long timeout;          /* max time to wait for irq */
 
-       special_t       special;        /* special action flags */
+       u8      special_flags;          /* special action flags */
 
        u8      select;                 /* basic drive/head select reg value */
        u8      retry_pio;              /* retrying dma capable host in pio */
        u8      waiting_for_dma;        /* dma currently in progress */
        u8      dma;                    /* atapi dma flag */
 
-        u8     quirk_list;     /* considered quirky, set for a specific host */
         u8     init_speed;     /* transfer rate set at boot */
         u8     current_speed;  /* current transfer rate set */
        u8      desired_speed;  /* desired transfer rate set */
@@ -562,8 +555,7 @@ struct ide_drive_s {
        unsigned int    drive_data;     /* used by set_pio_mode/dev_select() */
        unsigned int    failures;       /* current failure count */
        unsigned int    max_failures;   /* maximum allowed failure count */
-       u64             probed_capacity;/* initial reported media capacity (ide-cd only currently) */
-
+       u64             probed_capacity;/* initial/native media capacity */
        u64             capacity64;     /* total number of sectors */
 
        int             lun;            /* logical unit */
@@ -1222,7 +1214,7 @@ static inline int ide_pci_is_in_compatibility_mode(struct pci_dev *dev)
 }
 
 void ide_pci_setup_ports(struct pci_dev *, const struct ide_port_info *,
-                        hw_regs_t *, hw_regs_t **);
+                        struct ide_hw *, struct ide_hw **);
 void ide_setup_pci_noise(struct pci_dev *, const struct ide_port_info *);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PCI
@@ -1461,16 +1453,18 @@ static inline void ide_acpi_set_state(ide_hwif_t *hwif, int on) {}
 void ide_register_region(struct gendisk *);
 void ide_unregister_region(struct gendisk *);
 
+void ide_check_nien_quirk_list(ide_drive_t *);
 void ide_undecoded_slave(ide_drive_t *);
 
 void ide_port_apply_params(ide_hwif_t *);
 int ide_sysfs_register_port(ide_hwif_t *);
 
-struct ide_host *ide_host_alloc(const struct ide_port_info *, hw_regs_t **);
+struct ide_host *ide_host_alloc(const struct ide_port_info *, struct ide_hw **,
+                               unsigned int);
 void ide_host_free(struct ide_host *);
 int ide_host_register(struct ide_host *, const struct ide_port_info *,
-                     hw_regs_t **);
-int ide_host_add(const struct ide_port_info *, hw_regs_t **,
+                     struct ide_hw **);
+int ide_host_add(const struct ide_port_info *, struct ide_hw **, unsigned int,
                 struct ide_host **);
 void ide_host_remove(struct ide_host *);
 int ide_legacy_device_add(const struct ide_port_info *, unsigned long);
index cfe4fe1b7132016c4a30f480895a27812c09c959..60e8934d10b5e070ab2289a19c787935026722b1 100644 (file)
@@ -79,6 +79,7 @@
 #define ETH_P_AOE      0x88A2          /* ATA over Ethernet            */
 #define ETH_P_TIPC     0x88CA          /* TIPC                         */
 #define ETH_P_FCOE     0x8906          /* Fibre Channel over Ethernet  */
+#define ETH_P_FIP      0x8914          /* FCoE Initialization Protocol */
 #define ETH_P_EDSA     0xDADA          /* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
 
 /*
index 0e06c176f18568d987168b8abb5bb6b84ac0b887..b2189803f19afb4ff111fed17bd56b0c514e3f43 100644 (file)
@@ -2,8 +2,6 @@
 #define _LINUX_INIT_H
 
 #include <linux/compiler.h>
-#include <linux/section-names.h>
-#include <linux/stringify.h>
 
 /* These macros are used to mark some functions or 
  * initialized data (doesn't apply to uninitialized data)
 #define __memexitconst   __section(.memexit.rodata)
 
 /* For assembly routines */
-#define __HEAD         .section        __stringify(HEAD_TEXT_SECTION),"ax"
+#define __HEAD         .section        ".head.text","ax"
 #define __INIT         .section        ".init.text","ax"
 #define __FINIT                .previous
 
@@ -225,7 +223,8 @@ struct obs_kernel_param {
  * obs_kernel_param "array" too far apart in .init.setup.
  */
 #define __setup_param(str, unique_id, fn, early)                       \
-       static char __setup_str_##unique_id[] __initdata __aligned(1) = str; \
+       static const char __setup_str_##unique_id[] __initconst \
+               __aligned(1) = str; \
        static struct obs_kernel_param __setup_##unique_id      \
                __used __section(.init.setup)                   \
                __attribute__((aligned((sizeof(long)))))        \
index dd574d51bcaa8c0c88f3b2e2085f62ed07c32347..2721f07e93548150a195123bb13e02e1bfa4664b 100644 (file)
@@ -183,6 +183,7 @@ extern void disable_irq(unsigned int irq);
 extern void enable_irq(unsigned int irq);
 
 /* The following three functions are for the core kernel use only. */
+#ifdef CONFIG_GENERIC_HARDIRQS
 extern void suspend_device_irqs(void);
 extern void resume_device_irqs(void);
 #ifdef CONFIG_PM_SLEEP
@@ -190,6 +191,11 @@ extern int check_wakeup_irqs(void);
 #else
 static inline int check_wakeup_irqs(void) { return 0; }
 #endif
+#else
+static inline void suspend_device_irqs(void) { };
+static inline void resume_device_irqs(void) { };
+static inline int check_wakeup_irqs(void) { return 0; }
+#endif
 
 #if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_HARDIRQS)
 
index a3c984d780f0144422da0e0e9a4a754dc208510f..33a63f62d57fe3c375e45abe183bddbf5cafab7c 100644 (file)
@@ -56,6 +56,7 @@ extern int unregister_keyboard_notifier(struct notifier_block *nb);
 #define KT_ASCII       9
 #define KT_LOCK                10
 #define KT_SLOCK       12
+#define KT_DEAD2       13
 #define KT_BRL         14
 
 #define K(t,v)         (((t)<<8)|(v))
index 175e63f4a8c08d90de05b5a41382c60e8ffcabba..7bc1440fc47305418967134e2f65e0e23ea24572 100644 (file)
@@ -30,6 +30,10 @@ struct lguest_data
        /* Wallclock time set by the Host. */
        struct timespec time;
 
+       /* Interrupt pending set by the Host.  The Guest should do a hypercall
+        * if it re-enables interrupts and sees this set (to X86_EFLAGS_IF). */
+       int irq_pending;
+
        /* Async hypercall ring.  Instead of directly making hypercalls, we can
         * place them in here for processing the next time the Host wants.
         * This batching can be quite efficient. */
index a53407a4165c838ee457ee368e03758e3cea5560..bfefbdf7498a925856ec5e8425a5df24eb4cbac7 100644 (file)
@@ -57,7 +57,8 @@ enum lguest_req
        LHREQ_INITIALIZE, /* + base, pfnlimit, start */
        LHREQ_GETDMA, /* No longer used */
        LHREQ_IRQ, /* + irq */
-       LHREQ_BREAK, /* + on/off flag (on blocks until someone does off) */
+       LHREQ_BREAK, /* No longer used */
+       LHREQ_EVENTFD, /* + address, fd. */
 };
 
 /* The alignment to use between consumer and producer parts of vring.
index 516d955ab8a1bb9e63120a3bb79c0f0d4e08e297..c377118884e66bd61fd87d5ffaa247effd5fb5ae 100644 (file)
        writew((val) >> 16, (addr) + 2); \
        } while (0)
 
+/*
+ * data for the MMC controller
+ */
+struct tmio_mmc_data {
+       unsigned int            hclk;
+};
+
 /*
  * data for the NAND controller
  */
index 3aff8a6a389e1e0403ac234f0441283c724c23fc..ce7cc6c7bcbb6eaa12d818311723d97190e324d5 100644 (file)
@@ -210,6 +210,7 @@ struct mlx4_caps {
        int                     num_comp_vectors;
        int                     num_mpts;
        int                     num_mtt_segs;
+       int                     mtts_per_seg;
        int                     fmr_reserved_mtts;
        int                     reserved_mtts;
        int                     reserved_mrws;
index bf8f11982dae374f70f3b8b79494823ca96d2e36..9f29d86e5dc96fd4169911b918051b645d4b306d 100644 (file)
@@ -165,6 +165,7 @@ enum {
        MLX4_WQE_CTRL_IP_CSUM           = 1 << 4,
        MLX4_WQE_CTRL_TCP_UDP_CSUM      = 1 << 5,
        MLX4_WQE_CTRL_INS_VLAN          = 1 << 6,
+       MLX4_WQE_CTRL_STRONG_ORDER      = 1 << 7,
 };
 
 struct mlx4_wqe_ctrl_seg {
index a8f2c0aa4c328af87718285f715bc72b19d7f55f..a7bc6e7b43a7c429b9e4993933a900057034cf77 100644 (file)
@@ -77,6 +77,7 @@ search_extable(const struct exception_table_entry *first,
 void sort_extable(struct exception_table_entry *start,
                  struct exception_table_entry *finish);
 void sort_main_extable(void);
+void trim_init_extable(struct module *m);
 
 #ifdef MODULE
 #define MODULE_GENERIC_TABLE(gtype,name)                       \
index a4f0b931846c25e2e0db59e863490287f62d4b63..6547c3cdbc4c17cddda61d0f92fe83352de2f77c 100644 (file)
@@ -36,9 +36,14 @@ typedef int (*param_set_fn)(const char *val, struct kernel_param *kp);
 /* Returns length written or -errno.  Buffer is 4k (ie. be short!) */
 typedef int (*param_get_fn)(char *buffer, struct kernel_param *kp);
 
+/* Flag bits for kernel_param.flags */
+#define KPARAM_KMALLOCED       1
+#define KPARAM_ISBOOL          2
+
 struct kernel_param {
        const char *name;
-       unsigned int perm;
+       u16 perm;
+       u16 flags;
        param_set_fn set;
        param_get_fn get;
        union {
@@ -79,7 +84,7 @@ struct kparam_array
    parameters.  perm sets the visibility in sysfs: 000 means it's
    not there, read bits mean it's readable, write bits mean it's
    writable. */
-#define __module_param_call(prefix, name, set, get, arg, perm)         \
+#define __module_param_call(prefix, name, set, get, arg, isbool, perm) \
        /* Default value instead of permissions? */                     \
        static int __param_perm_check_##name __attribute__((unused)) =  \
        BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2))  \
@@ -88,10 +93,13 @@ struct kparam_array
        static struct kernel_param __moduleparam_const __param_##name   \
        __used                                                          \
     __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \
-       = { __param_str_##name, perm, set, get, { arg } }
+       = { __param_str_##name, perm, isbool ? KPARAM_ISBOOL : 0,       \
+           set, get, { arg } }
 
 #define module_param_call(name, set, get, arg, perm)                         \
-       __module_param_call(MODULE_PARAM_PREFIX, name, set, get, arg, perm)
+       __module_param_call(MODULE_PARAM_PREFIX,                              \
+                           name, set, get, arg,                              \
+                           __same_type(*(arg), bool), perm)
 
 /* Helper functions: type is byte, short, ushort, int, uint, long,
    ulong, charp, bool or invbool, or XXX if you define param_get_XXX,
@@ -120,15 +128,16 @@ struct kparam_array
 #define core_param(name, var, type, perm)                              \
        param_check_##type(name, &(var));                               \
        __module_param_call("", name, param_set_##type, param_get_##type, \
-                           &var, perm)
+                           &var, __same_type(var, bool), perm)
 #endif /* !MODULE */
 
 /* Actually copy string: maxlen param is usually sizeof(string). */
 #define module_param_string(name, string, len, perm)                   \
        static const struct kparam_string __param_string_##name         \
                = { len, string };                                      \
-       module_param_call(name, param_set_copystring, param_get_string, \
-                         .str = &__param_string_##name, perm);         \
+       __module_param_call(MODULE_PARAM_PREFIX, name,                  \
+                           param_set_copystring, param_get_string,     \
+                           .str = &__param_string_##name, 0, perm);    \
        __MODULE_PARM_TYPE(name, "string")
 
 /* Called on module insert or kernel boot */
@@ -186,21 +195,30 @@ extern int param_set_charp(const char *val, struct kernel_param *kp);
 extern int param_get_charp(char *buffer, struct kernel_param *kp);
 #define param_check_charp(name, p) __param_check(name, p, char *)
 
+/* For historical reasons "bool" parameters can be (unsigned) "int". */
 extern int param_set_bool(const char *val, struct kernel_param *kp);
 extern int param_get_bool(char *buffer, struct kernel_param *kp);
-#define param_check_bool(name, p) __param_check(name, p, int)
+#define param_check_bool(name, p)                                      \
+       static inline void __check_##name(void)                         \
+       {                                                               \
+               BUILD_BUG_ON(!__same_type(*(p), bool) &&                \
+                            !__same_type(*(p), unsigned int) &&        \
+                            !__same_type(*(p), int));                  \
+       }
 
 extern int param_set_invbool(const char *val, struct kernel_param *kp);
 extern int param_get_invbool(char *buffer, struct kernel_param *kp);
-#define param_check_invbool(name, p) __param_check(name, p, int)
+#define param_check_invbool(name, p) __param_check(name, p, bool)
 
 /* Comma-separated array: *nump is set to number they actually specified. */
 #define module_param_array_named(name, array, type, nump, perm)                \
        static const struct kparam_array __param_arr_##name             \
        = { ARRAY_SIZE(array), nump, param_set_##type, param_get_##type,\
            sizeof(array[0]), array };                                  \
-       module_param_call(name, param_array_set, param_array_get,       \
-                         .arr = &__param_arr_##name, perm);            \
+       __module_param_call(MODULE_PARAM_PREFIX, name,                  \
+                           param_array_set, param_array_get,           \
+                           .arr = &__param_arr_##name,                 \
+                           __same_type(array[0], bool), perm);         \
        __MODULE_PARM_TYPE(name, "array of " #type)
 
 #define module_param_array(name, type, nump, perm)             \
index 7339c7bf73315e56a981b382229abfc39384e23b..13f126c89ae8f1e5e35355eff8b94e1c9095906e 100644 (file)
@@ -18,7 +18,19 @@ struct page_cgroup {
 };
 
 void __meminit pgdat_page_cgroup_init(struct pglist_data *pgdat);
-void __init page_cgroup_init(void);
+
+#ifdef CONFIG_SPARSEMEM
+static inline void __init page_cgroup_init_flatmem(void)
+{
+}
+extern void __init page_cgroup_init(void);
+#else
+void __init page_cgroup_init_flatmem(void);
+static inline void __init page_cgroup_init(void)
+{
+}
+#endif
+
 struct page_cgroup *lookup_page_cgroup(struct page *page);
 
 enum {
@@ -87,6 +99,10 @@ static inline void page_cgroup_init(void)
 {
 }
 
+static inline void __init page_cgroup_init_flatmem(void)
+{
+}
+
 #endif
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
index d7d1c41a0b17db03da5768b35233f409b98b9b7d..9f36e1cdbf01c4016b1e21ba4d40a83fe5b43cc6 100644 (file)
 #define PCI_DEVICE_ID_PLX_PCI200SYN    0x3196
 #define PCI_DEVICE_ID_PLX_9030          0x9030
 #define PCI_DEVICE_ID_PLX_9050         0x9050
+#define PCI_DEVICE_ID_PLX_9056         0x9056
 #define PCI_DEVICE_ID_PLX_9080         0x9080
 #define PCI_DEVICE_ID_PLX_GTEK_SERIAL2 0xa001
 
 
 #define PCI_VENDOR_ID_CREATIVE         0x1102 /* duplicate: ECTIVA */
 #define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002
+#define PCI_DEVICE_ID_CREATIVE_20K1    0x0005
+#define PCI_DEVICE_ID_CREATIVE_20K2    0x000b
+#define PCI_SUBDEVICE_ID_CREATIVE_SB0760       0x0024
+#define PCI_SUBDEVICE_ID_CREATIVE_SB08801      0x0041
+#define PCI_SUBDEVICE_ID_CREATIVE_SB08802      0x0042
+#define PCI_SUBDEVICE_ID_CREATIVE_SB08803      0x0043
+#define PCI_SUBDEVICE_ID_CREATIVE_HENDRIX      0x6000
 
 #define PCI_VENDOR_ID_ECTIVA           0x1102 /* duplicate: CREATIVE */
 #define PCI_DEVICE_ID_ECTIVA_EV1938    0x8938
 #define PCI_SUBDEVICE_ID_HYPERCOPE_METRO       0x0107
 #define PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2      0x0108
 
+#define PCI_VENDOR_ID_DIGIGRAM         0x1369
+#define PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_SERIAL_SUBSYSTEM    0xc001
+#define PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_CAE_SERIAL_SUBSYSTEM        0xc002
+
 #define PCI_VENDOR_ID_KAWASAKI         0x136b
 #define PCI_DEVICE_ID_MCHIP_KL5A72002  0xff01
 
 #define PCI_VENDOR_ID_MAINPINE         0x1522
 #define PCI_DEVICE_ID_MAINPINE_PBRIDGE 0x0100
 #define PCI_VENDOR_ID_ENE              0x1524
+#define PCI_DEVICE_ID_ENE_CB710_FLASH  0x0510
 #define PCI_DEVICE_ID_ENE_CB712_SD     0x0550
 #define PCI_DEVICE_ID_ENE_CB712_SD_2   0x0551
 #define PCI_DEVICE_ID_ENE_CB714_SD     0x0750
index 6e133954e2e44a95e968c09a7a8b3669280ce74d..1b3118a1023abfb3f8c7c3f8b0204e1f87d5d212 100644 (file)
@@ -120,6 +120,8 @@ enum perf_counter_sample_format {
        PERF_SAMPLE_ID                          = 1U << 6,
        PERF_SAMPLE_CPU                         = 1U << 7,
        PERF_SAMPLE_PERIOD                      = 1U << 8,
+
+       PERF_SAMPLE_MAX = 1U << 9,              /* non-ABI */
 };
 
 /*
@@ -131,17 +133,26 @@ enum perf_counter_read_format {
        PERF_FORMAT_TOTAL_TIME_ENABLED          = 1U << 0,
        PERF_FORMAT_TOTAL_TIME_RUNNING          = 1U << 1,
        PERF_FORMAT_ID                          = 1U << 2,
+
+       PERF_FORMAT_MAX = 1U << 3,              /* non-ABI */
 };
 
+#define PERF_ATTR_SIZE_VER0    64      /* sizeof first published struct */
+
 /*
  * Hardware event to monitor via a performance monitoring counter:
  */
 struct perf_counter_attr {
+
        /*
         * Major type: hardware/software/tracepoint/etc.
         */
        __u32                   type;
-       __u32                   __reserved_1;
+
+       /*
+        * Size of the attr structure, for fwd/bwd compat.
+        */
+       __u32                   size;
 
        /*
         * Type specific configuration information.
@@ -168,12 +179,12 @@ struct perf_counter_attr {
                                comm           :  1, /* include comm data     */
                                freq           :  1, /* use freq, not period  */
 
-                               __reserved_2   : 53;
+                               __reserved_1   : 53;
 
        __u32                   wakeup_events;  /* wakeup every n events */
-       __u32                   __reserved_3;
+       __u32                   __reserved_2;
 
-       __u64                   __reserved_4;
+       __u64                   __reserved_3;
 };
 
 /*
@@ -621,7 +632,8 @@ extern int perf_counter_overflow(struct perf_counter *counter, int nmi,
 static inline int is_software_counter(struct perf_counter *counter)
 {
        return (counter->attr.type != PERF_TYPE_RAW) &&
-               (counter->attr.type != PERF_TYPE_HARDWARE);
+               (counter->attr.type != PERF_TYPE_HARDWARE) &&
+               (counter->attr.type != PERF_TYPE_HW_CACHE);
 }
 
 extern void perf_swcounter_event(u32, u64, int, struct pt_regs *, u64);
index 1d4e2d289821d1d74f9e203dc966ed0ed1e5e0ef..b3f74764a5869dc579aae27792381619ce2bbf4b 100644 (file)
@@ -382,14 +382,13 @@ struct dev_pm_info {
 #ifdef CONFIG_PM_SLEEP
 extern void device_pm_lock(void);
 extern int sysdev_resume(void);
-extern void device_power_up(pm_message_t state);
-extern void device_resume(pm_message_t state);
+extern void dpm_resume_noirq(pm_message_t state);
+extern void dpm_resume_end(pm_message_t state);
 
 extern void device_pm_unlock(void);
 extern int sysdev_suspend(pm_message_t state);
-extern int device_power_down(pm_message_t state);
-extern int device_suspend(pm_message_t state);
-extern int device_prepare_suspend(pm_message_t state);
+extern int dpm_suspend_noirq(pm_message_t state);
+extern int dpm_suspend_start(pm_message_t state);
 
 extern void __suspend_report_result(const char *function, void *fn, int ret);
 
@@ -403,7 +402,7 @@ extern void __suspend_report_result(const char *function, void *fn, int ret);
 #define device_pm_lock() do {} while (0)
 #define device_pm_unlock() do {} while (0)
 
-static inline int device_suspend(pm_message_t state)
+static inline int dpm_suspend_start(pm_message_t state)
 {
        return 0;
 }
index ca3c88773028046f36a807741f2f6fa16b9c65fe..b063c7328ba5b103b444fea061d07b7f55d24d03 100644 (file)
@@ -446,6 +446,7 @@ int pnp_start_dev(struct pnp_dev *dev);
 int pnp_stop_dev(struct pnp_dev *dev);
 int pnp_activate_dev(struct pnp_dev *dev);
 int pnp_disable_dev(struct pnp_dev *dev);
+int pnp_range_reserved(resource_size_t start, resource_size_t end);
 
 /* protocol helpers */
 int pnp_is_active(struct pnp_dev *dev);
@@ -476,6 +477,7 @@ static inline int pnp_start_dev(struct pnp_dev *dev) { return -ENODEV; }
 static inline int pnp_stop_dev(struct pnp_dev *dev) { return -ENODEV; }
 static inline int pnp_activate_dev(struct pnp_dev *dev) { return -ENODEV; }
 static inline int pnp_disable_dev(struct pnp_dev *dev) { return -ENODEV; }
+static inline int pnp_range_reserved(resource_size_t start, resource_size_t end) { return 0;}
 
 /* protocol helpers */
 static inline int pnp_is_active(struct pnp_dev *dev) { return 0; }
diff --git a/include/linux/section-names.h b/include/linux/section-names.h
deleted file mode 100644 (file)
index c956f4e..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __LINUX_SECTION_NAMES_H
-#define __LINUX_SECTION_NAMES_H
-
-#define HEAD_TEXT_SECTION .head.text
-
-#endif /* !__LINUX_SECTION_NAMES_H */
index e339fcf17cd36fb6d5f5ad17cae1a28916e1d0b1..2da8372519f5e96a32027a9be8b0efc66f35b907 100644 (file)
@@ -326,4 +326,6 @@ static inline void *kzalloc_node(size_t size, gfp_t flags, int node)
        return kmalloc_node(size, flags | __GFP_ZERO, node);
 }
 
+void __init kmem_cache_init_late(void);
+
 #endif /* _LINUX_SLAB_H */
index 0ec00b39d006471e585a11e74759ff832f6f028b..bb5368df4be84397f28ec90b134b63687fdcaed6 100644 (file)
@@ -34,4 +34,9 @@ static __always_inline void *__kmalloc(size_t size, gfp_t flags)
        return kmalloc(size, flags);
 }
 
+static inline void kmem_cache_init_late(void)
+{
+       /* Nothing to do */
+}
+
 #endif /* __LINUX_SLOB_DEF_H */
index be5d40c43bd2e7aa96264e624b074f4a884826f4..4dcbc2c71491ec9dc736b83c1eeedb03f4650a95 100644 (file)
@@ -302,4 +302,6 @@ static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
 }
 #endif
 
+void __init kmem_cache_init_late(void);
+
 #endif /* _LINUX_SLUB_DEF_H */
index 795032edfc46eca55687c1739b0022364dc1fb14..cd15df6c63cdc07f51d2823ccb2a7e77b070c8ee 100644 (file)
@@ -245,11 +245,6 @@ extern unsigned long get_safe_page(gfp_t gfp_mask);
 
 extern void hibernation_set_ops(struct platform_hibernation_ops *ops);
 extern int hibernate(void);
-extern int hibernate_nvs_register(unsigned long start, unsigned long size);
-extern int hibernate_nvs_alloc(void);
-extern void hibernate_nvs_free(void);
-extern void hibernate_nvs_save(void);
-extern void hibernate_nvs_restore(void);
 extern bool system_entering_hibernation(void);
 #else /* CONFIG_HIBERNATION */
 static inline int swsusp_page_is_forbidden(struct page *p) { return 0; }
@@ -258,6 +253,16 @@ static inline void swsusp_unset_page_free(struct page *p) {}
 
 static inline void hibernation_set_ops(struct platform_hibernation_ops *ops) {}
 static inline int hibernate(void) { return -ENOSYS; }
+static inline bool system_entering_hibernation(void) { return false; }
+#endif /* CONFIG_HIBERNATION */
+
+#ifdef CONFIG_HIBERNATION_NVS
+extern int hibernate_nvs_register(unsigned long start, unsigned long size);
+extern int hibernate_nvs_alloc(void);
+extern void hibernate_nvs_free(void);
+extern void hibernate_nvs_save(void);
+extern void hibernate_nvs_restore(void);
+#else /* CONFIG_HIBERNATION_NVS */
 static inline int hibernate_nvs_register(unsigned long a, unsigned long b)
 {
        return 0;
@@ -266,8 +271,7 @@ static inline int hibernate_nvs_alloc(void) { return 0; }
 static inline void hibernate_nvs_free(void) {}
 static inline void hibernate_nvs_save(void) {}
 static inline void hibernate_nvs_restore(void) {}
-static inline bool system_entering_hibernation(void) { return false; }
-#endif /* CONFIG_HIBERNATION */
+#endif /* CONFIG_HIBERNATION_NVS */
 
 #ifdef CONFIG_PM_SLEEP
 void save_processor_state(void);
index c6c84ad8bd7119dea51f73ab13ee34987c5d152d..418d90f5effe72ff9921a6ea066bb526a7337127 100644 (file)
@@ -758,6 +758,6 @@ int kernel_execve(const char *filename, char *const argv[], char *const envp[]);
 
 
 asmlinkage long sys_perf_counter_open(
-               const struct perf_counter_attr __user *attr_uptr,
+               struct perf_counter_attr __user *attr_uptr,
                pid_t pid, int cpu, int group_fd, unsigned long flags);
 #endif
index 6b7703e75cecfbed566ab21c7a423c506ca8672e..71339dc531c5e45634951ec0c2e1bbd5c4bb50c2 100644 (file)
@@ -34,7 +34,7 @@
  *             _GUS_VOICEOFF   - Stops voice (no parameters)
  *             _GUS_VOICEFADE  - Stops the voice smoothly.
  *             _GUS_VOICEMODE  - Alters the voice mode, don't start or stop voice (P1=voice mode)
- *             _GUS_VOICEBALA  - Sets voice balence (P1, 0=left, 7=middle and 15=right, default 7)
+ *             _GUS_VOICEBALA  - Sets voice balance (P1, 0=left, 7=middle and 15=right, default 7)
  *             _GUS_VOICEFREQ  - Sets voice (sample) playback frequency (P1=Hz)
  *             _GUS_VOICEVOL   - Sets voice volume (P1=volume, 0xfff=max, 0xeff=half, 0x000=off)
  *             _GUS_VOICEVOL2  - Sets voice volume (P1=volume, 0xfff=max, 0xeff=half, 0x000=off)
index 06005fa9e982e0f703a7eef56f4108378c566f24..4fca4f5440ba47c93d7f903b8395a7b98791a021 100644 (file)
 
 /**
  * virtqueue - a queue to register buffers for sending or receiving.
+ * @list: the chain of virtqueues for this device
  * @callback: the function to call when buffers are consumed (can be NULL).
+ * @name: the name of this virtqueue (mainly for debugging)
  * @vdev: the virtio device this queue was created for.
  * @vq_ops: the operations for this virtqueue (see below).
  * @priv: a pointer for the virtqueue implementation to use.
  */
-struct virtqueue
-{
+struct virtqueue {
+       struct list_head list;
        void (*callback)(struct virtqueue *vq);
+       const char *name;
        struct virtio_device *vdev;
        struct virtqueue_ops *vq_ops;
        void *priv;
@@ -76,15 +79,16 @@ struct virtqueue_ops {
  * @dev: underlying device.
  * @id: the device type identification (used to match it with a driver).
  * @config: the configuration ops for this device.
+ * @vqs: the list of virtqueues for this device.
  * @features: the features supported by both driver and device.
  * @priv: private pointer for the driver's use.
  */
-struct virtio_device
-{
+struct virtio_device {
        int index;
        struct device dev;
        struct virtio_device_id id;
        struct virtio_config_ops *config;
+       struct list_head vqs;
        /* Note that this is a Linux set_bit-style bitmap. */
        unsigned long features[1];
        void *priv;
@@ -99,8 +103,7 @@ void unregister_virtio_device(struct virtio_device *dev);
  * @id_table: the ids serviced by this driver.
  * @feature_table: an array of feature numbers supported by this device.
  * @feature_table_size: number of entries in the feature table array.
- * @probe: the function to call when a device is found.  Returns a token for
- *    remove, or PTR_ERR().
+ * @probe: the function to call when a device is found.  Returns 0 or -errno.
  * @remove: the function when a device is removed.
  * @config_changed: optional function to call when the device configuration
  *    changes; may be called in interrupt context.
index bf8ec283b232af65116af4fa338ad602f1b8d798..99f514575f6afa1fe0e6ceeb4c50c7fb4e6520a5 100644 (file)
@@ -29,6 +29,7 @@
 #define VIRTIO_F_NOTIFY_ON_EMPTY       24
 
 #ifdef __KERNEL__
+#include <linux/err.h>
 #include <linux/virtio.h>
 
 /**
  * @set_status: write the status byte
  *     vdev: the virtio_device
  *     status: the new status byte
+ * @request_vqs: request the specified number of virtqueues
+ *     vdev: the virtio_device
+ *     max_vqs: the max number of virtqueues we want
+ *      If supplied, must call before any virtqueues are instantiated.
+ *      To modify the max number of virtqueues after request_vqs has been
+ *      called, call free_vqs and then request_vqs with a new value.
+ * @free_vqs: cleanup resources allocated by request_vqs
+ *     vdev: the virtio_device
+ *      If supplied, must call after all virtqueues have been deleted.
  * @reset: reset the device
  *     vdev: the virtio device
  *     After this, status and feature negotiation must be done again
- * @find_vq: find a virtqueue and instantiate it.
+ * @find_vqs: find virtqueues and instantiate them.
  *     vdev: the virtio_device
- *     index: the 0-based virtqueue number in case there's more than one.
- *     callback: the virqtueue callback
- *     Returns the new virtqueue or ERR_PTR() (eg. -ENOENT).
- * @del_vq: free a virtqueue found by find_vq().
+ *     nvqs: the number of virtqueues to find
+ *     vqs: on success, includes new virtqueues
+ *     callbacks: array of callbacks, for each virtqueue
+ *     names: array of virtqueue names (mainly for debugging)
+ *     Returns 0 on success or error status
+ * @del_vqs: free virtqueues found by find_vqs().
  * @get_features: get the array of feature bits for this device.
  *     vdev: the virtio_device
  *     Returns the first 32 feature bits (all we currently need).
@@ -66,6 +78,7 @@
  *     This gives the final feature bits for the device: it can change
  *     the dev->feature bits if it wants.
  */
+typedef void vq_callback_t(struct virtqueue *);
 struct virtio_config_ops
 {
        void (*get)(struct virtio_device *vdev, unsigned offset,
@@ -75,10 +88,11 @@ struct virtio_config_ops
        u8 (*get_status)(struct virtio_device *vdev);
        void (*set_status)(struct virtio_device *vdev, u8 status);
        void (*reset)(struct virtio_device *vdev);
-       struct virtqueue *(*find_vq)(struct virtio_device *vdev,
-                                    unsigned index,
-                                    void (*callback)(struct virtqueue *));
-       void (*del_vq)(struct virtqueue *vq);
+       int (*find_vqs)(struct virtio_device *, unsigned nvqs,
+                       struct virtqueue *vqs[],
+                       vq_callback_t *callbacks[],
+                       const char *names[]);
+       void (*del_vqs)(struct virtio_device *);
        u32 (*get_features)(struct virtio_device *vdev);
        void (*finalize_features)(struct virtio_device *vdev);
 };
@@ -99,7 +113,9 @@ static inline bool virtio_has_feature(const struct virtio_device *vdev,
        if (__builtin_constant_p(fbit))
                BUILD_BUG_ON(fbit >= 32);
 
-       virtio_check_driver_offered_feature(vdev, fbit);
+       if (fbit < VIRTIO_TRANSPORT_F_START)
+               virtio_check_driver_offered_feature(vdev, fbit);
+
        return test_bit(fbit, vdev->features);
 }
 
@@ -126,5 +142,18 @@ static inline int virtio_config_buf(struct virtio_device *vdev,
        vdev->config->get(vdev, offset, buf, len);
        return 0;
 }
+
+static inline
+struct virtqueue *virtio_find_single_vq(struct virtio_device *vdev,
+                                       vq_callback_t *c, const char *n)
+{
+       vq_callback_t *callbacks[] = { c };
+       const char *names[] = { n };
+       struct virtqueue *vq;
+       int err = vdev->config->find_vqs(vdev, 1, &vq, callbacks, names);
+       if (err < 0)
+               return ERR_PTR(err);
+       return vq;
+}
 #endif /* __KERNEL__ */
 #endif /* _LINUX_VIRTIO_CONFIG_H */
index cd0fd5d181a6f259e8e24f7fb12f107cd35a4515..9a3d7c48c622d8c3e525ce5653fd12e98b4d9f9a 100644 (file)
 /* The bit of the ISR which indicates a device configuration change. */
 #define VIRTIO_PCI_ISR_CONFIG          0x2
 
+/* MSI-X registers: only enabled if MSI-X is enabled. */
+/* A 16-bit vector for configuration changes. */
+#define VIRTIO_MSI_CONFIG_VECTOR        20
+/* A 16-bit vector for selected queue notifications. */
+#define VIRTIO_MSI_QUEUE_VECTOR         22
+/* Vector value used to disable MSI for queue */
+#define VIRTIO_MSI_NO_VECTOR            0xffff
+
 /* The remaining space is defined by each driver as the per-driver
  * configuration space */
-#define VIRTIO_PCI_CONFIG              20
+#define VIRTIO_PCI_CONFIG(dev)         ((dev)->msix_enabled ? 24 : 20)
 
 /* Virtio ABI version, this must match exactly */
 #define VIRTIO_PCI_ABI_VERSION         0
index 71e03722fb5946fa60ab67a88a7250bee3c77b7c..693e0ec5afa67f9ec2c18d48563cccdba3261409 100644 (file)
@@ -14,6 +14,8 @@
 #define VRING_DESC_F_NEXT      1
 /* This marks a buffer as write-only (otherwise read-only). */
 #define VRING_DESC_F_WRITE     2
+/* This means the buffer contains a list of buffer descriptors. */
+#define VRING_DESC_F_INDIRECT  4
 
 /* The Host uses this in used->flags to advise the Guest: don't kick me when
  * you add a buffer.  It's unreliable, so it's simply an optimization.  Guest
@@ -24,6 +26,9 @@
  * optimization.  */
 #define VRING_AVAIL_F_NO_INTERRUPT     1
 
+/* We support indirect buffer descriptors */
+#define VIRTIO_RING_F_INDIRECT_DESC    28
+
 /* Virtio ring descriptors: 16 bytes.  These can chain together via "next". */
 struct vring_desc
 {
@@ -119,7 +124,8 @@ struct virtqueue *vring_new_virtqueue(unsigned int num,
                                      struct virtio_device *vdev,
                                      void *pages,
                                      void (*notify)(struct virtqueue *vq),
-                                     void (*callback)(struct virtqueue *vq));
+                                     void (*callback)(struct virtqueue *vq),
+                                     const char *name);
 void vring_del_virtqueue(struct virtqueue *vq);
 /* Filter out transport-specific feature bits. */
 void vring_transport_features(struct virtio_device *vdev);
index 0627a9ae6347c206f7388dd9dcd8959e52ae55c6..3d138c1fcf8abb14fe2f024c4760448e4a965f4c 100644 (file)
  * http://www.t11.org/ftp/t11/pub/fc/bb-5/08-543v1.pdf
  */
 
-/*
- * The FIP ethertype eventually goes in net/if_ether.h.
- */
-#ifndef ETH_P_FIP
-#define ETH_P_FIP      0x8914  /* FIP Ethertype */
-#endif
-
 #define FIP_DEF_PRI    128     /* default selection priority */
 #define FIP_DEF_FC_MAP 0x0efc00 /* default FCoE MAP (MAC OUI) value */
 #define FIP_DEF_FKA    8000    /* default FCF keep-alive/advert period (mS) */
index d0ed5226f8c4f02db9ad40df1c8455d83c053f92..4426f00da5ffcbf1ca9f92409bbb860479e60a18 100644 (file)
 #define ISCSI_IF_H
 
 #include <scsi/iscsi_proto.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+
+#define ISCSI_NL_GRP_ISCSID    1
+#define ISCSI_NL_GRP_UIP       2
 
 #define UEVENT_BASE                    10
 #define KEVENT_BASE                    100
@@ -50,7 +55,10 @@ enum iscsi_uevent_e {
        ISCSI_UEVENT_TGT_DSCVR          = UEVENT_BASE + 15,
        ISCSI_UEVENT_SET_HOST_PARAM     = UEVENT_BASE + 16,
        ISCSI_UEVENT_UNBIND_SESSION     = UEVENT_BASE + 17,
-       ISCSI_UEVENT_CREATE_BOUND_SESSION       = UEVENT_BASE + 18,
+       ISCSI_UEVENT_CREATE_BOUND_SESSION               = UEVENT_BASE + 18,
+       ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST  = UEVENT_BASE + 19,
+
+       ISCSI_UEVENT_PATH_UPDATE        = UEVENT_BASE + 20,
 
        /* up events */
        ISCSI_KEVENT_RECV_PDU           = KEVENT_BASE + 1,
@@ -59,6 +67,9 @@ enum iscsi_uevent_e {
        ISCSI_KEVENT_DESTROY_SESSION    = KEVENT_BASE + 4,
        ISCSI_KEVENT_UNBIND_SESSION     = KEVENT_BASE + 5,
        ISCSI_KEVENT_CREATE_SESSION     = KEVENT_BASE + 6,
+
+       ISCSI_KEVENT_PATH_REQ           = KEVENT_BASE + 7,
+       ISCSI_KEVENT_IF_DOWN            = KEVENT_BASE + 8,
 };
 
 enum iscsi_tgt_dscvr {
@@ -131,6 +142,10 @@ struct iscsi_uevent {
                struct msg_transport_connect {
                        uint32_t        non_blocking;
                } ep_connect;
+               struct msg_transport_connect_through_host {
+                       uint32_t        host_no;
+                       uint32_t        non_blocking;
+               } ep_connect_through_host;
                struct msg_transport_poll {
                        uint64_t        ep_handle;
                        uint32_t        timeout_ms;
@@ -154,6 +169,9 @@ struct iscsi_uevent {
                        uint32_t        param; /* enum iscsi_host_param */
                        uint32_t        len;
                } set_host_param;
+               struct msg_set_path {
+                       uint32_t        host_no;
+               } set_path;
        } u;
        union {
                /* messages k -> u */
@@ -187,9 +205,38 @@ struct iscsi_uevent {
                struct msg_transport_connect_ret {
                        uint64_t        handle;
                } ep_connect_ret;
+               struct msg_req_path {
+                       uint32_t        host_no;
+               } req_path;
+               struct msg_notify_if_down {
+                       uint32_t        host_no;
+               } notify_if_down;
        } r;
 } __attribute__ ((aligned (sizeof(uint64_t))));
 
+/*
+ * To keep the struct iscsi_uevent size the same for userspace code
+ * compatibility, the main structure for ISCSI_UEVENT_PATH_UPDATE and
+ * ISCSI_KEVENT_PATH_REQ is defined separately and comes after the
+ * struct iscsi_uevent in the NETLINK_ISCSI message.
+ */
+struct iscsi_path {
+       uint64_t        handle;
+       uint8_t         mac_addr[6];
+       uint8_t         mac_addr_old[6];
+       uint32_t        ip_addr_len;    /* 4 or 16 */
+       union {
+               struct in_addr  v4_addr;
+               struct in6_addr v6_addr;
+       } src;
+       union {
+               struct in_addr  v4_addr;
+               struct in6_addr v6_addr;
+       } dst;
+       uint16_t        vlan_id;
+       uint16_t        pmtu;
+} __attribute__ ((aligned (sizeof(uint64_t))));
+
 /*
  * Common error codes
  */
index 45f9cc642c46572623eaf09568332edcd17f475c..ebdd9f4cf070da669c2b80a817c9b156e51f360e 100644 (file)
@@ -679,6 +679,7 @@ struct fc_lport {
        unsigned int            e_d_tov;
        unsigned int            r_a_tov;
        u8                      max_retry_count;
+       u8                      max_rport_retry_count;
        u16                     link_speed;
        u16                     link_supported_speeds;
        u16                     lro_xid;        /* max xid for fcoe lro */
index 0289f5745fb9a687e92f46625a8bd38fa81407d0..196525cd402f6a86d09d208557f03217dd9bc08a 100644 (file)
@@ -82,9 +82,12 @@ enum {
 
 
 enum {
+       ISCSI_TASK_FREE,
        ISCSI_TASK_COMPLETED,
        ISCSI_TASK_PENDING,
        ISCSI_TASK_RUNNING,
+       ISCSI_TASK_ABRT_TMF,            /* aborted due to TMF */
+       ISCSI_TASK_ABRT_SESS_RECOV,     /* aborted due to session recovery */
 };
 
 struct iscsi_r2t_info {
@@ -181,9 +184,7 @@ struct iscsi_conn {
 
        /* xmit */
        struct list_head        mgmtqueue;      /* mgmt (control) xmit queue */
-       struct list_head        mgmt_run_list;  /* list of control tasks */
-       struct list_head        xmitqueue;      /* data-path cmd queue */
-       struct list_head        run_list;       /* list of cmds in progress */
+       struct list_head        cmdqueue;       /* data-path cmd queue */
        struct list_head        requeue;        /* tasks needing another run */
        struct work_struct      xmitwork;       /* per-conn. xmit workqueue */
        unsigned long           suspend_tx;     /* suspend Tx */
@@ -406,6 +407,7 @@ extern int __iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *,
                                char *, int);
 extern int iscsi_verify_itt(struct iscsi_conn *, itt_t);
 extern struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *, itt_t);
+extern struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *, itt_t);
 extern void iscsi_requeue_task(struct iscsi_task *task);
 extern void iscsi_put_task(struct iscsi_task *task);
 extern void __iscsi_get_task(struct iscsi_task *task);
index f888a6fda07302b3df0dffc731e4c04aa0985863..56e920ade3269f4895546c13bc419bad045f2400 100644 (file)
@@ -29,6 +29,7 @@ enum {
        OSD_APAGE_PARTITION_INFORMATION = OSD_APAGE_PARTITION_FIRST + 1,
        OSD_APAGE_PARTITION_QUOTAS      = OSD_APAGE_PARTITION_FIRST + 2,
        OSD_APAGE_PARTITION_TIMESTAMP   = OSD_APAGE_PARTITION_FIRST + 3,
+       OSD_APAGE_PARTITION_ATTR_ACCESS = OSD_APAGE_PARTITION_FIRST + 4,
        OSD_APAGE_PARTITION_SECURITY    = OSD_APAGE_PARTITION_FIRST + 5,
        OSD_APAGE_PARTITION_LAST        = 0x5FFFFFFF,
 
@@ -51,7 +52,9 @@ enum {
        OSD_APAGE_RESERVED_TYPE_LAST    = 0xEFFFFFFF,
 
        OSD_APAGE_COMMON_FIRST          = 0xF0000000,
-       OSD_APAGE_COMMON_LAST           = 0xFFFFFFFE,
+       OSD_APAGE_COMMON_LAST           = 0xFFFFFFFD,
+
+       OSD_APAGE_CURRENT_COMMAND       = 0xFFFFFFFE,
 
        OSD_APAGE_REQUEST_ALL           = 0xFFFFFFFF,
 };
@@ -106,10 +109,30 @@ enum {
        OSD_ATTR_RI_PRODUCT_REVISION_LEVEL   = 0x7,   /* 4        */
        OSD_ATTR_RI_PRODUCT_SERIAL_NUMBER    = 0x8,   /* variable */
        OSD_ATTR_RI_OSD_NAME                 = 0x9,   /* variable */
+       OSD_ATTR_RI_MAX_CDB_CONTINUATION_LEN = 0xA,   /* 4        */
        OSD_ATTR_RI_TOTAL_CAPACITY           = 0x80,  /* 8        */
        OSD_ATTR_RI_USED_CAPACITY            = 0x81,  /* 8        */
        OSD_ATTR_RI_NUMBER_OF_PARTITIONS     = 0xC0,  /* 8        */
        OSD_ATTR_RI_CLOCK                    = 0x100, /* 6        */
+       OARI_DEFAULT_ISOLATION_METHOD        = 0X110, /* 1        */
+       OARI_SUPPORTED_ISOLATION_METHODS     = 0X111, /* 32       */
+
+       OARI_DATA_ATOMICITY_GUARANTEE                   = 0X120,   /* 8       */
+       OARI_DATA_ATOMICITY_ALIGNMENT                   = 0X121,   /* 8       */
+       OARI_ATTRIBUTES_ATOMICITY_GUARANTEE             = 0X122,   /* 8       */
+       OARI_DATA_ATTRIBUTES_ATOMICITY_MULTIPLIER       = 0X123,   /* 1       */
+
+       OARI_MAXIMUM_SNAPSHOTS_COUNT                    = 0X1C1,    /* 0 or 4 */
+       OARI_MAXIMUM_CLONES_COUNT                       = 0X1C2,    /* 0 or 4 */
+       OARI_MAXIMUM_BRANCH_DEPTH                       = 0X1CC,    /* 0 or 4 */
+       OARI_SUPPORTED_OBJECT_DUPLICATION_METHOD_FIRST  = 0X200,    /* 0 or 4 */
+       OARI_SUPPORTED_OBJECT_DUPLICATION_METHOD_LAST   = 0X2ff,    /* 0 or 4 */
+       OARI_SUPPORTED_TIME_OF_DUPLICATION_METHOD_FIRST = 0X300,    /* 0 or 4 */
+       OARI_SUPPORTED_TIME_OF_DUPLICATION_METHOD_LAST  = 0X30F,    /* 0 or 4 */
+       OARI_SUPPORT_FOR_DUPLICATED_OBJECT_FREEZING     = 0X310,    /* 0 or 4 */
+       OARI_SUPPORT_FOR_SNAPSHOT_REFRESHING            = 0X311,    /* 0 or 1 */
+       OARI_SUPPORTED_CDB_CONTINUATION_DESC_TYPE_FIRST = 0X7000001,/* 0 or 4 */
+       OARI_SUPPORTED_CDB_CONTINUATION_DESC_TYPE_LAST  = 0X700FFFF,/* 0 or 4 */
 };
 /* Root_Information_attributes_page does not have a get_page structure */
 
@@ -120,7 +143,15 @@ enum {
        OSD_ATTR_PI_PARTITION_ID            = 0x1,     /* 8        */
        OSD_ATTR_PI_USERNAME                = 0x9,     /* variable */
        OSD_ATTR_PI_USED_CAPACITY           = 0x81,    /* 8        */
+       OSD_ATTR_PI_USED_CAPACITY_INCREMENT = 0x84,    /* 0 or 8   */
        OSD_ATTR_PI_NUMBER_OF_OBJECTS       = 0xC1,    /* 8        */
+
+       OSD_ATTR_PI_ACTUAL_DATA_SPACE                      = 0xD1, /* 0 or 8 */
+       OSD_ATTR_PI_RESERVED_DATA_SPACE                    = 0xD2, /* 0 or 8 */
+       OSD_ATTR_PI_DEFAULT_SNAPSHOT_DUPLICATION_METHOD    = 0x200,/* 0 or 4 */
+       OSD_ATTR_PI_DEFAULT_CLONE_DUPLICATION_METHOD       = 0x201,/* 0 or 4 */
+       OSD_ATTR_PI_DEFAULT_SP_TIME_OF_DUPLICATION         = 0x300,/* 0 or 4 */
+       OSD_ATTR_PI_DEFAULT_CLONE_TIME_OF_DUPLICATION      = 0x301,/* 0 or 4 */
 };
 /* Partition Information attributes page does not have a get_page structure */
 
@@ -131,6 +162,7 @@ enum {
        OSD_ATTR_CI_PARTITION_ID           = 0x1,       /* 8        */
        OSD_ATTR_CI_COLLECTION_OBJECT_ID   = 0x2,       /* 8        */
        OSD_ATTR_CI_USERNAME               = 0x9,       /* variable */
+       OSD_ATTR_CI_COLLECTION_TYPE        = 0xA,       /* 1        */
        OSD_ATTR_CI_USED_CAPACITY          = 0x81,      /* 8        */
 };
 /* Collection Information attributes page does not have a get_page structure */
@@ -144,6 +176,8 @@ enum {
        OSD_ATTR_OI_USERNAME             = 0x9,       /* variable */
        OSD_ATTR_OI_USED_CAPACITY        = 0x81,      /* 8        */
        OSD_ATTR_OI_LOGICAL_LENGTH       = 0x82,      /* 8        */
+       SD_ATTR_OI_ACTUAL_DATA_SPACE     = 0XD1,      /* 0 OR 8   */
+       SD_ATTR_OI_RESERVED_DATA_SPACE   = 0XD2,      /* 0 OR 8   */
 };
 /* Object Information attributes page does not have a get_page structure */
 
@@ -248,7 +282,18 @@ struct object_timestamps_attributes_page {
        struct osd_timestamp data_modified_time;
 }  __packed;
 
-/* 7.1.2.19 Collections attributes page */
+/* OSD2r05: 7.1.3.19 Attributes Access attributes page
+ * (OSD_APAGE_PARTITION_ATTR_ACCESS)
+ *
+ * each attribute is of the form below. Total array length is deduced
+ * from the attribute's length
+ * (See allowed_attributes_access of the struct osd_cap_object_descriptor)
+ */
+struct attributes_access_attr {
+       struct osd_attributes_list_attrid attr_list[0];
+} __packed;
+
+/* OSD2r05: 7.1.2.21 Collections attributes page */
 /* TBD */
 
 /* 7.1.2.20 Root Policy/Security attributes page (OSD_APAGE_ROOT_SECURITY) */
@@ -324,4 +369,29 @@ struct object_security_attributes_page {
        __be32 policy_access_tag;
 }  __packed;
 
+/* OSD2r05: 7.1.3.31 Current Command attributes page
+ * (OSD_APAGE_CURRENT_COMMAND)
+ */
+enum {
+       OSD_ATTR_CC_RESPONSE_INTEGRITY_CHECK_VALUE     = 0x1, /* 32  */
+       OSD_ATTR_CC_OBJECT_TYPE                        = 0x2, /* 1   */
+       OSD_ATTR_CC_PARTITION_ID                       = 0x3, /* 8   */
+       OSD_ATTR_CC_OBJECT_ID                          = 0x4, /* 8   */
+       OSD_ATTR_CC_STARTING_BYTE_ADDRESS_OF_APPEND    = 0x5, /* 8   */
+       OSD_ATTR_CC_CHANGE_IN_USED_CAPACITY            = 0x6, /* 8   */
+};
+
+/*TBD: osdv1_current_command_attributes_page */
+
+struct osdv2_current_command_attributes_page {
+       struct osd_attr_page_header hdr;  /* id=0xFFFFFFFE, size=0x44 */
+       u8 response_integrity_check_value[OSD_CRYPTO_KEYID_SIZE];
+       u8 object_type;
+       u8 reserved[3];
+       __be64 partition_id;
+       __be64 object_id;
+       __be64 starting_byte_address_of_append;
+       __be64 change_in_used_capacity;
+};
+
 #endif /*ndef __OSD_ATTRIBUTES_H__*/
index b24d9616eb469f2afbcdd02f32dbdd9cae6eae3d..02bd9f7163570512e19c0e98e17295a5f47561e8 100644 (file)
@@ -18,6 +18,7 @@
 #include "osd_types.h"
 
 #include <linux/blkdev.h>
+#include <scsi/scsi_device.h>
 
 /* Note: "NI" in comments below means "Not Implemented yet" */
 
@@ -47,6 +48,7 @@ enum osd_std_version {
  */
 struct osd_dev {
        struct scsi_device *scsi_device;
+       struct file *file;
        unsigned def_timeout;
 
 #ifdef OSD_VER1_SUPPORT
@@ -69,6 +71,10 @@ void osd_dev_fini(struct osd_dev *od);
 
 /* some hi level device operations */
 int osd_auto_detect_ver(struct osd_dev *od, void *caps);    /* GFP_KERNEL */
+static inline struct request_queue *osd_request_queue(struct osd_dev *od)
+{
+       return od->scsi_device->request_queue;
+}
 
 /* we might want to use function vector in the future */
 static inline void osd_dev_set_ver(struct osd_dev *od, enum osd_std_version v)
@@ -363,7 +369,9 @@ void osd_req_create_object(struct osd_request *or, struct osd_obj_id *);
 void osd_req_remove_object(struct osd_request *or, struct osd_obj_id *);
 
 void osd_req_write(struct osd_request *or,
-       const struct osd_obj_id *, struct bio *data_out, u64 offset);
+       const struct osd_obj_id *obj, u64 offset, struct bio *bio, u64 len);
+int osd_req_write_kern(struct osd_request *or,
+       const struct osd_obj_id *obj, u64 offset, void *buff, u64 len);
 void osd_req_append(struct osd_request *or,
        const struct osd_obj_id *, struct bio *data_out);/* NI */
 void osd_req_create_write(struct osd_request *or,
@@ -378,7 +386,9 @@ void osd_req_flush_object(struct osd_request *or,
        /*V2*/ u64 offset, /*V2*/ u64 len);
 
 void osd_req_read(struct osd_request *or,
-       const struct osd_obj_id *, struct bio *data_in, u64 offset);
+       const struct osd_obj_id *obj, u64 offset, struct bio *bio, u64 len);
+int osd_req_read_kern(struct osd_request *or,
+       const struct osd_obj_id *obj, u64 offset, void *buff, u64 len);
 
 /*
  * Root/Partition/Collection/Object Attributes commands
index 62b2ab8c69d45318ba93419184b608348928d5e2..2cc8e8b1cc19da61757676325ab3ae9cd9050e2d 100644 (file)
@@ -303,7 +303,15 @@ enum osd_service_actions {
        OSD_ACT_V2(REMOVE_MEMBER_OBJECTS,       0x21)
        OSD_ACT_V2(GET_MEMBER_ATTRIBUTES,       0x22)
        OSD_ACT_V2(SET_MEMBER_ATTRIBUTES,       0x23)
+
+       OSD_ACT_V2(CREATE_CLONE,                0x28)
+       OSD_ACT_V2(CREATE_SNAPSHOT,             0x29)
+       OSD_ACT_V2(DETACH_CLONE,                0x2A)
+       OSD_ACT_V2(REFRESH_SNAPSHOT_CLONE,      0x2B)
+       OSD_ACT_V2(RESTORE_PARTITION_FROM_SNAPSHOT, 0x2C)
+
        OSD_ACT_V2(READ_MAP,                    0x31)
+       OSD_ACT_V2(READ_MAPS_COMPARE,           0x32)
 
        OSD_ACT_V1_V2(PERFORM_SCSI_COMMAND,     0x8F7E, 0x8F7C)
        OSD_ACT_V1_V2(SCSI_TASK_MANAGEMENT,     0x8F7F, 0x8F7D)
index 457588e1119bd4cf3c429ffe6cea6aa8ded3deff..349c7f30720d8f652c79b1db0251f3a44180505a 100644 (file)
@@ -126,12 +126,14 @@ struct iscsi_transport {
                               int *index, int *age);
 
        void (*session_recovery_timedout) (struct iscsi_cls_session *session);
-       struct iscsi_endpoint *(*ep_connect) (struct sockaddr *dst_addr,
+       struct iscsi_endpoint *(*ep_connect) (struct Scsi_Host *shost,
+                                             struct sockaddr *dst_addr,
                                              int non_blocking);
        int (*ep_poll) (struct iscsi_endpoint *ep, int timeout_ms);
        void (*ep_disconnect) (struct iscsi_endpoint *ep);
        int (*tgt_dscvr) (struct Scsi_Host *shost, enum iscsi_tgt_dscvr type,
                          uint32_t enable, struct sockaddr *dst_addr);
+       int (*set_path) (struct Scsi_Host *shost, struct iscsi_path *params);
 };
 
 /*
@@ -148,6 +150,10 @@ extern void iscsi_conn_error_event(struct iscsi_cls_conn *conn,
 extern int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
                          char *data, uint32_t data_size);
 
+extern int iscsi_offload_mesg(struct Scsi_Host *shost,
+                             struct iscsi_transport *transport, uint32_t type,
+                             char *data, uint16_t data_size);
+
 struct iscsi_cls_conn {
        struct list_head conn_list;     /* item in connlist */
        void *dd_data;                  /* LLD private data */
index 6add80fc251200ef9a99e0e576a433e29f9a1b7a..82aed3f47534f3d47d53930e4869c9285de5652d 100644 (file)
@@ -255,6 +255,7 @@ typedef int __bitwise snd_pcm_subformat_t;
 #define SNDRV_PCM_INFO_HALF_DUPLEX     0x00100000      /* only half duplex */
 #define SNDRV_PCM_INFO_JOINT_DUPLEX    0x00200000      /* playback and capture stream are somewhat correlated */
 #define SNDRV_PCM_INFO_SYNC_START      0x00400000      /* pcm support some kind of sync go */
+#define SNDRV_PCM_INFO_FIFO_IN_FRAMES  0x80000000      /* internal kernel flag - FIFO size is in frames */
 
 typedef int __bitwise snd_pcm_state_t;
 #define        SNDRV_PCM_STATE_OPEN            ((__force snd_pcm_state_t) 0) /* stream is open */
index 3dea79829acc0c53673533d421aa9ca15f3b9c06..309cb9659a05907576fb933b822b100afd3e56bb 100644 (file)
@@ -300,19 +300,10 @@ int snd_card_create(int idx, const char *id,
                    struct module *module, int extra_size,
                    struct snd_card **card_ret);
 
-static inline __deprecated
-struct snd_card *snd_card_new(int idx, const char *id,
-                             struct module *module, int extra_size)
-{
-       struct snd_card *card;
-       if (snd_card_create(idx, id, module, extra_size, &card) < 0)
-               return NULL;
-       return card;
-}
-
 int snd_card_disconnect(struct snd_card *card);
 int snd_card_free(struct snd_card *card);
 int snd_card_free_when_closed(struct snd_card *card);
+void snd_card_set_id(struct snd_card *card, const char *id);
 int snd_card_register(struct snd_card *card);
 int snd_card_info_init(void);
 int snd_card_info_done(void);
diff --git a/include/sound/driver.h b/include/sound/driver.h
deleted file mode 100644 (file)
index f035943..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#warning "This file is deprecated"
index c172968916170b3e3c4e42aa1793b729f21e3670..23893523dc8ce16023cc347dcd3672f3c6be4033 100644 (file)
@@ -98,6 +98,7 @@ struct snd_pcm_ops {
 #define SNDRV_PCM_IOCTL1_INFO          1
 #define SNDRV_PCM_IOCTL1_CHANNEL_INFO  2
 #define SNDRV_PCM_IOCTL1_GSTATE                3
+#define SNDRV_PCM_IOCTL1_FIFO_SIZE     4
 
 #define SNDRV_PCM_TRIGGER_STOP         0
 #define SNDRV_PCM_TRIGGER_START                1
@@ -270,6 +271,7 @@ struct snd_pcm_runtime {
        snd_pcm_uframes_t hw_ptr_base;  /* Position at buffer restart */
        snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */
        unsigned long hw_ptr_jiffies;   /* Time when hw_ptr is updated */
+       snd_pcm_sframes_t delay;        /* extra delay; typically FIFO size */
 
        /* -- HW params -- */
        snd_pcm_access_t access;        /* access mode */
@@ -486,80 +488,6 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream);
 void snd_pcm_vma_notify_data(void *client, void *data);
 int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area);
 
-#if BITS_PER_LONG >= 64
-
-static inline void div64_32(u_int64_t *n, u_int32_t div, u_int32_t *rem)
-{
-       *rem = *n % div;
-       *n /= div;
-}
-
-#elif defined(i386)
-
-static inline void div64_32(u_int64_t *n, u_int32_t div, u_int32_t *rem)
-{
-       u_int32_t low, high;
-       low = *n & 0xffffffff;
-       high = *n >> 32;
-       if (high) {
-               u_int32_t high1 = high % div;
-               high /= div;
-               asm("divl %2":"=a" (low), "=d" (*rem):"rm" (div), "a" (low), "d" (high1));
-               *n = (u_int64_t)high << 32 | low;
-       } else {
-               *n = low / div;
-               *rem = low % div;
-       }
-}
-#else
-
-static inline void divl(u_int32_t high, u_int32_t low,
-                       u_int32_t div,
-                       u_int32_t *q, u_int32_t *r)
-{
-       u_int64_t n = (u_int64_t)high << 32 | low;
-       u_int64_t d = (u_int64_t)div << 31;
-       u_int32_t q1 = 0;
-       int c = 32;
-       while (n > 0xffffffffU) {
-               q1 <<= 1;
-               if (n >= d) {
-                       n -= d;
-                       q1 |= 1;
-               }
-               d >>= 1;
-               c--;
-       }
-       q1 <<= c;
-       if (n) {
-               low = n;
-               *q = q1 | (low / div);
-               *r = low % div;
-       } else {
-               *r = 0;
-               *q = q1;
-       }
-       return;
-}
-
-static inline void div64_32(u_int64_t *n, u_int32_t div, u_int32_t *rem)
-{
-       u_int32_t low, high;
-       low = *n & 0xffffffff;
-       high = *n >> 32;
-       if (high) {
-               u_int32_t high1 = high % div;
-               u_int32_t low1 = low;
-               high /= div;
-               divl(high1, low1, div, &low, rem);
-               *n = (u_int64_t)high << 32 | low;
-       } else {
-               *n = low / div;
-               *rem = low % div;
-       }
-}
-#endif
-
 /*
  *  PCM library
  */
index 13676472ddfcca7ace85a4bc407c66d40a746b79..352d7eee9b6d912739fecbf48ec20aef0485a0d0 100644 (file)
@@ -44,24 +44,6 @@ struct snd_pcm_substream;
 #define SND_SOC_DAIFMT_CONT            (0 << 4) /* continuous clock */
 #define SND_SOC_DAIFMT_GATED           (1 << 4) /* clock is gated */
 
-/*
- * DAI Left/Right Clocks.
- *
- * Specifies whether the DAI can support different samples for similtanious
- * playback and capture. This usually requires a seperate physical frame
- * clock for playback and capture.
- */
-#define SND_SOC_DAIFMT_SYNC            (0 << 5) /* Tx FRM = Rx FRM */
-#define SND_SOC_DAIFMT_ASYNC           (1 << 5) /* Tx FRM ~ Rx FRM */
-
-/*
- * TDM
- *
- * Time Division Multiplexing. Allows PCM data to be multplexed with other
- * data on the DAI.
- */
-#define SND_SOC_DAIFMT_TDM             (1 << 6)
-
 /*
  * DAI hardware signal inversions.
  *
@@ -96,6 +78,10 @@ struct snd_pcm_substream;
 #define SND_SOC_CLOCK_IN               0
 #define SND_SOC_CLOCK_OUT              1
 
+#define SND_SOC_STD_AC97_FMTS (SNDRV_PCM_FMTBIT_S16_LE |\
+                               SNDRV_PCM_FMTBIT_S32_LE |\
+                               SNDRV_PCM_FMTBIT_S32_BE)
+
 struct snd_soc_dai_ops;
 struct snd_soc_dai;
 struct snd_ac97_bus_ops;
@@ -208,6 +194,7 @@ struct snd_soc_dai {
        /* DAI capabilities */
        struct snd_soc_pcm_stream capture;
        struct snd_soc_pcm_stream playback;
+       unsigned int symmetric_rates:1;
 
        /* DAI runtime info */
        struct snd_pcm_runtime *runtime;
@@ -219,11 +206,8 @@ struct snd_soc_dai {
        /* DAI private data */
        void *private_data;
 
-       /* parent codec/platform */
-       union {
-               struct snd_soc_codec *codec;
-               struct snd_soc_platform *platform;
-       };
+       /* parent platform */
+       struct snd_soc_platform *platform;
 
        struct list_head list;
 };
index a7def6a9a030e00671cb40ea6da2498ffca9caa2..ec8a45f9a06950f6bf1cfa0ea0d46ed3ca5200f0 100644 (file)
 #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \
 {      .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \
        .shift = wshift, .invert = winvert}
+#define SND_SOC_DAPM_DAC_E(wname, stname, wreg, wshift, winvert, \
+                          wevent, wflags)                              \
+{      .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \
+       .shift = wshift, .invert = winvert, \
+       .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_ADC(wname, stname, wreg, wshift, winvert) \
 {      .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \
        .shift = wshift, .invert = winvert}
+#define SND_SOC_DAPM_ADC_E(wname, stname, wreg, wshift, winvert, \
+                          wevent, wflags)                              \
+{      .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \
+       .shift = wshift, .invert = winvert, \
+       .event = wevent, .event_flags = wflags}
 
-/* generic register modifier widget */
+/* generic widgets */
 #define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \
 {      .id = wid, .name = wname, .kcontrols = NULL, .num_kcontrols = 0, \
        .reg = -((wreg) + 1), .shift = wshift, .mask = wmask, \
        .on_val = won_val, .off_val = woff_val, .event = dapm_reg_event, \
        .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
+#define SND_SOC_DAPM_SUPPLY(wname, wreg, wshift, winvert, wevent, wflags) \
+{      .id = snd_soc_dapm_supply, .name = wname, .reg = wreg,  \
+       .shift = wshift, .invert = winvert, .event = wevent, \
+       .event_flags = wflags}
 
 /* dapm kcontrol types */
 #define SOC_DAPM_SINGLE(xname, reg, shift, max, invert) \
@@ -265,8 +279,6 @@ int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
 /* dapm events */
 int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream,
        int event);
-int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
-       enum snd_soc_bias_level level);
 
 /* dapm sys fs - used by the core */
 int snd_soc_dapm_sys_add(struct device *dev);
@@ -298,6 +310,7 @@ enum snd_soc_dapm_type {
        snd_soc_dapm_vmid,                      /* codec bias/vmid - to minimise pops */
        snd_soc_dapm_pre,                       /* machine specific pre widget - exec first */
        snd_soc_dapm_post,                      /* machine specific post widget - exec last */
+       snd_soc_dapm_supply,            /* power/clock supply */
 };
 
 /*
@@ -357,6 +370,8 @@ struct snd_soc_dapm_widget {
        unsigned char suspend:1;                /* was active before suspend */
        unsigned char pmdown:1;                 /* waiting for timeout */
 
+       int (*power_check)(struct snd_soc_dapm_widget *w);
+
        /* external events */
        unsigned short event_flags;             /* flags to specify event types */
        int (*event)(struct snd_soc_dapm_widget*, struct snd_kcontrol *, int);
@@ -368,6 +383,9 @@ struct snd_soc_dapm_widget {
        /* widget input and outputs */
        struct list_head sources;
        struct list_head sinks;
+
+       /* used during DAPM updates */
+       struct list_head power_list;
 };
 
 #endif
index a40bc6f316fc668b6328374315aded850a40262d..cf6111d72b17015572a131a26c4c7913378adcd0 100644 (file)
        .info = snd_soc_info_volsw, \
        .get = xhandler_get, .put = xhandler_put, \
        .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) }
+#define SOC_DOUBLE_EXT(xname, xreg, shift_left, shift_right, xmax, xinvert,\
+        xhandler_get, xhandler_put) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
+       .info = snd_soc_info_volsw, \
+       .get = xhandler_get, .put = xhandler_put, \
+       .private_value = (unsigned long)&(struct soc_mixer_control) \
+               {.reg = xreg, .shift = shift_left, .rshift = shift_right, \
+                .max = xmax, .invert = xinvert} }
 #define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\
         xhandler_get, xhandler_put, tlv_array) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
@@ -206,10 +214,6 @@ void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
                        struct snd_soc_jack_gpio *gpios);
 #endif
 
-/* codec IO */
-#define snd_soc_read(codec, reg) codec->read(codec, reg)
-#define snd_soc_write(codec, reg, value) codec->write(codec, reg, value)
-
 /* codec register bit access */
 int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
                                unsigned short mask, unsigned short value);
@@ -331,6 +335,7 @@ struct snd_soc_codec {
        struct module *owner;
        struct mutex mutex;
        struct device *dev;
+       struct snd_soc_device *socdev;
 
        struct list_head list;
 
@@ -364,6 +369,8 @@ struct snd_soc_codec {
        enum snd_soc_bias_level bias_level;
        enum snd_soc_bias_level suspend_bias_level;
        struct delayed_work delayed_work;
+       struct list_head up_list;
+       struct list_head down_list;
 
        /* codec DAI's */
        struct snd_soc_dai *dai;
@@ -417,6 +424,12 @@ struct snd_soc_dai_link  {
        /* codec/machine specific init - e.g. add machine controls */
        int (*init)(struct snd_soc_codec *codec);
 
+       /* Symmetry requirements */
+       unsigned int symmetric_rates:1;
+
+       /* Symmetry data - only valid if symmetry is being enforced */
+       unsigned int rate;
+
        /* DAI pcm */
        struct snd_pcm *pcm;
 };
@@ -490,6 +503,19 @@ struct soc_enum {
        void *dapm;
 };
 
+/* codec IO */
+static inline unsigned int snd_soc_read(struct snd_soc_codec *codec,
+                                       unsigned int reg)
+{
+       return codec->read(codec, reg);
+}
+
+static inline unsigned int snd_soc_write(struct snd_soc_codec *codec,
+                                        unsigned int reg, unsigned int val)
+{
+       return codec->write(codec, reg, val);
+}
+
 #include <sound/soc-dai.h>
 
 #endif
diff --git a/include/sound/wm9081.h b/include/sound/wm9081.h
new file mode 100644 (file)
index 0000000..e173ddb
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * linux/sound/wm9081.h -- Platform data for WM9081
+ *
+ * Copyright 2009 Wolfson Microelectronics. PLC.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_SND_WM_9081_H
+#define __LINUX_SND_WM_9081_H
+
+struct wm9081_retune_mobile_setting {
+       const char *name;
+       unsigned int rate;
+       u16 config[20];
+};
+
+struct wm9081_retune_mobile_config {
+       struct wm9081_retune_mobile_setting *configs;
+       int num_configs;
+};
+
+#endif
diff --git a/include/video/pxa168fb.h b/include/video/pxa168fb.h
new file mode 100644 (file)
index 0000000..b5cc72f
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * linux/arch/arm/mach-mmp/include/mach/pxa168fb.h
+ *
+ *  Copyright (C) 2009 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_MACH_PXA168FB_H
+#define __ASM_MACH_PXA168FB_H
+
+#include <linux/fb.h>
+#include <linux/interrupt.h>
+
+/* Dumb interface */
+#define PIN_MODE_DUMB_24               0
+#define PIN_MODE_DUMB_18_SPI           1
+#define PIN_MODE_DUMB_18_GPIO          2
+#define PIN_MODE_DUMB_16_SPI           3
+#define PIN_MODE_DUMB_16_GPIO          4
+#define PIN_MODE_DUMB_12_SPI_GPIO      5
+#define PIN_MODE_SMART_18_SPI          6
+#define PIN_MODE_SMART_16_SPI          7
+#define PIN_MODE_SMART_8_SPI_GPIO      8
+
+/* Dumb interface pin allocation */
+#define DUMB_MODE_RGB565               0
+#define DUMB_MODE_RGB565_UPPER         1
+#define DUMB_MODE_RGB666               2
+#define DUMB_MODE_RGB666_UPPER         3
+#define DUMB_MODE_RGB444               4
+#define DUMB_MODE_RGB444_UPPER         5
+#define DUMB_MODE_RGB888               6
+
+/* default fb buffer size WVGA-32bits */
+#define DEFAULT_FB_SIZE        (800 * 480 * 4)
+
+/*
+ * Buffer pixel format
+ * bit0 is for rb swap.
+ * bit12 is for Y UorV swap
+ */
+#define PIX_FMT_RGB565         0
+#define PIX_FMT_BGR565         1
+#define PIX_FMT_RGB1555                2
+#define PIX_FMT_BGR1555                3
+#define PIX_FMT_RGB888PACK     4
+#define PIX_FMT_BGR888PACK     5
+#define PIX_FMT_RGB888UNPACK   6
+#define PIX_FMT_BGR888UNPACK   7
+#define PIX_FMT_RGBA888                8
+#define PIX_FMT_BGRA888                9
+#define PIX_FMT_YUV422PACK     10
+#define PIX_FMT_YVU422PACK     11
+#define PIX_FMT_YUV422PLANAR   12
+#define PIX_FMT_YVU422PLANAR   13
+#define PIX_FMT_YUV420PLANAR   14
+#define PIX_FMT_YVU420PLANAR   15
+#define PIX_FMT_PSEUDOCOLOR    20
+#define PIX_FMT_UYVY422PACK    (0x1000|PIX_FMT_YUV422PACK)
+
+/*
+ * PXA LCD controller private state.
+ */
+struct pxa168fb_info {
+       struct device           *dev;
+       struct clk              *clk;
+       struct fb_info          *info;
+
+       void __iomem            *reg_base;
+       dma_addr_t              fb_start_dma;
+       u32                     pseudo_palette[16];
+
+       int                     pix_fmt;
+       unsigned                is_blanked:1;
+       unsigned                panel_rbswap:1;
+       unsigned                active:1;
+};
+
+/*
+ * PXA fb machine information
+ */
+struct pxa168fb_mach_info {
+       char    id[16];
+
+       int             num_modes;
+       struct fb_videomode *modes;
+
+       /*
+        * Pix_fmt
+        */
+       unsigned        pix_fmt;
+
+       /*
+        * I/O pin allocation.
+        */
+       unsigned        io_pin_allocation_mode:4;
+
+       /*
+        * Dumb panel -- assignment of R/G/B component info to the 24
+        * available external data lanes.
+        */
+       unsigned        dumb_mode:4;
+       unsigned        panel_rgb_reverse_lanes:1;
+
+       /*
+        * Dumb panel -- GPIO output data.
+        */
+       unsigned        gpio_output_mask:8;
+       unsigned        gpio_output_data:8;
+
+       /*
+        * Dumb panel -- configurable output signal polarity.
+        */
+       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;
+};
+
+#endif /* __ASM_MACH_PXA168FB_H */
index c649657e22590e74610f05d5eb904d9534d4fd2f..fed6dc31b0dae854c26ac29216fc5a08824eaa53 100644 (file)
@@ -809,14 +809,6 @@ config KALLSYMS_EXTRA_PASS
           you wait for kallsyms to be fixed.
 
 
-config STRIP_ASM_SYMS
-       bool "Strip assembler-generated symbols during link"
-       default n
-       help
-         Strip internal assembler-generated symbols during a link (symbols
-         that look like '.Lxxx') so they don't pollute the output of
-         get_wchan() and suchlike.
-
 config HOTPLUG
        bool "Support for hot-pluggable devices" if EMBEDDED
        default y
@@ -936,6 +928,8 @@ config AIO
 
 config HAVE_PERF_COUNTERS
        bool
+       help
+         See tools/perf/design.txt for details.
 
 menu "Performance Counters"
 
@@ -996,6 +990,14 @@ config SLUB_DEBUG
          SLUB sysfs support. /sys/slab will not exist and there will be
          no support for cache validation etc.
 
+config STRIP_ASM_SYMS
+       bool "Strip assembler-generated symbols during link"
+       default n
+       help
+         Strip internal assembler-generated symbols during a link (symbols
+         that look like '.Lxxx') so they don't pollute the output of
+         get_wchan() and suchlike.
+
 config COMPAT_BRK
        bool "Disable heap randomization"
        default y
index e3c335e47cd264f6ad56665bad74182ed30a49f2..7becd8b5c5bfafab40654a9219eadbee2d158559 100644 (file)
@@ -540,6 +540,11 @@ void __init __weak thread_info_cache_init(void)
  */
 static void __init mm_init(void)
 {
+       /*
+        * page_cgroup requires countinous pages as memmap
+        * and it's bigger than MAX_ORDER unless SPARSEMEM.
+        */
+       page_cgroup_init_flatmem();
        mem_init();
        kmem_cache_init();
        vmalloc_init();
@@ -636,6 +641,7 @@ asmlinkage void __init start_kernel(void)
                                 "enabled early\n");
        early_boot_irqs_on();
        local_irq_enable();
+       kmem_cache_init_late();
 
        /*
         * HACK ALERT! This is early. We're enabling the console before
index 1045785412305ef99ae4445c962d14b45e0aa432..065205bdd920bfd9751d72b0d0e6a7024ecbf774 100644 (file)
@@ -45,7 +45,7 @@ void handle_bad_irq(unsigned int irq, struct irq_desc *desc)
 #if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_HARDIRQS)
 static void __init init_irq_default_affinity(void)
 {
-       alloc_bootmem_cpumask_var(&irq_default_affinity);
+       alloc_cpumask_var(&irq_default_affinity, GFP_NOWAIT);
        cpumask_setall(irq_default_affinity);
 }
 #else
index 374faf9bfdc79c5fcac1ef2d70ce3671765362f7..3a29dbe7898e329e9ddd61f141dfb44f68a59ca8 100644 (file)
 #define all_var 0
 #endif
 
-/* These will be re-linked against their real values during the second link stage */
+/*
+ * These will be re-linked against their real values
+ * during the second link stage.
+ */
 extern const unsigned long kallsyms_addresses[] __attribute__((weak));
 extern const u8 kallsyms_names[] __attribute__((weak));
 
-/* tell the compiler that the count isn't in the small data section if the arch
- * has one (eg: FRV)
+/*
+ * Tell the compiler that the count isn't in the small data section if the arch
+ * has one (eg: FRV).
  */
 extern const unsigned long kallsyms_num_syms
 __attribute__((weak, section(".rodata")));
@@ -75,31 +79,37 @@ static int is_ksym_addr(unsigned long addr)
        return is_kernel_text(addr) || is_kernel_inittext(addr);
 }
 
-/* expand a compressed symbol data into the resulting uncompressed string,
-   given the offset to where the symbol is in the compressed stream */
+/*
+ * Expand a compressed symbol data into the resulting uncompressed string,
+ * given the offset to where the symbol is in the compressed stream.
+ */
 static unsigned int kallsyms_expand_symbol(unsigned int off, char *result)
 {
        int len, skipped_first = 0;
        const u8 *tptr, *data;
 
-       /* get the compressed symbol length from the first symbol byte */
+       /* Get the compressed symbol length from the first symbol byte. */
        data = &kallsyms_names[off];
        len = *data;
        data++;
 
-       /* update the offset to return the offset for the next symbol on
-        * the compressed stream */
+       /*
+        * Update the offset to return the offset for the next symbol on
+        * the compressed stream.
+        */
        off += len + 1;
 
-       /* for every byte on the compressed symbol data, copy the table
-          entry for that byte */
-       while(len) {
-               tptr = &kallsyms_token_table[ kallsyms_token_index[*data] ];
+       /*
+        * For every byte on the compressed symbol data, copy the table
+        * entry for that byte.
+        */
+       while (len) {
+               tptr = &kallsyms_token_table[kallsyms_token_index[*data]];
                data++;
                len--;
 
                while (*tptr) {
-                       if(skipped_first) {
+                       if (skipped_first) {
                                *result = *tptr;
                                result++;
                        } else
@@ -110,36 +120,46 @@ static unsigned int kallsyms_expand_symbol(unsigned int off, char *result)
 
        *result = '\0';
 
-       /* return to offset to the next symbol */
+       /* Return to offset to the next symbol. */
        return off;
 }
 
-/* get symbol type information. This is encoded as a single char at the
- * begining of the symbol name */
+/*
+ * Get symbol type information. This is encoded as a single char at the
+ * beginning of the symbol name.
+ */
 static char kallsyms_get_symbol_type(unsigned int off)
 {
-       /* get just the first code, look it up in the token table, and return the
-        * first char from this token */
-       return kallsyms_token_table[ kallsyms_token_index[ kallsyms_names[off+1] ] ];
+       /*
+        * Get just the first code, look it up in the token table,
+        * and return the first char from this token.
+        */
+       return kallsyms_token_table[kallsyms_token_index[kallsyms_names[off + 1]]];
 }
 
 
-/* find the offset on the compressed stream given and index in the
- * kallsyms array */
+/*
+ * Find the offset on the compressed stream given and index in the
+ * kallsyms array.
+ */
 static unsigned int get_symbol_offset(unsigned long pos)
 {
        const u8 *name;
        int i;
 
-       /* use the closest marker we have. We have markers every 256 positions,
-        * so that should be close enough */
-       name = &kallsyms_names[ kallsyms_markers[pos>>8] ];
+       /*
+        * Use the closest marker we have. We have markers every 256 positions,
+        * so that should be close enough.
+        */
+       name = &kallsyms_names[kallsyms_markers[pos >> 8]];
 
-       /* sequentially scan all the symbols up to the point we're searching for.
-        * Every symbol is stored in a [<len>][<len> bytes of data] format, so we
-        * just need to add the len to the current pointer for every symbol we
-        * wish to skip */
-       for(i = 0; i < (pos&0xFF); i++)
+       /*
+        * Sequentially scan all the symbols up to the point we're searching
+        * for. Every symbol is stored in a [<len>][<len> bytes of data] format,
+        * so we just need to add the len to the current pointer for every
+        * symbol we wish to skip.
+        */
+       for (i = 0; i < (pos & 0xFF); i++)
                name = name + (*name) + 1;
 
        return name - kallsyms_names;
@@ -190,7 +210,7 @@ static unsigned long get_symbol_pos(unsigned long addr,
        /* This kernel should never had been booted. */
        BUG_ON(!kallsyms_addresses);
 
-       /* do a binary search on the sorted kallsyms_addresses array */
+       /* Do a binary search on the sorted kallsyms_addresses array. */
        low = 0;
        high = kallsyms_num_syms;
 
@@ -203,15 +223,15 @@ static unsigned long get_symbol_pos(unsigned long addr,
        }
 
        /*
-        * search for the first aliased symbol. Aliased
-        * symbols are symbols with the same address
+        * Search for the first aliased symbol. Aliased
+        * symbols are symbols with the same address.
         */
        while (low && kallsyms_addresses[low-1] == kallsyms_addresses[low])
                --low;
 
        symbol_start = kallsyms_addresses[low];
 
-       /* Search for next non-aliased symbol */
+       /* Search for next non-aliased symbol. */
        for (i = low + 1; i < kallsyms_num_syms; i++) {
                if (kallsyms_addresses[i] > symbol_start) {
                        symbol_end = kallsyms_addresses[i];
@@ -219,7 +239,7 @@ static unsigned long get_symbol_pos(unsigned long addr,
                }
        }
 
-       /* if we found no next symbol, we use the end of the section */
+       /* If we found no next symbol, we use the end of the section. */
        if (!symbol_end) {
                if (is_kernel_inittext(addr))
                        symbol_end = (unsigned long)_einittext;
@@ -252,10 +272,10 @@ int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize,
 
 /*
  * Lookup an address
- * - modname is set to NULL if it's in the kernel
- * - we guarantee that the returned name is valid until we reschedule even if
- *   it resides in a module
- * - we also guarantee that modname will be valid until rescheduled
+ * - modname is set to NULL if it's in the kernel.
+ * - We guarantee that the returned name is valid until we reschedule even if.
+ *   It resides in a module.
+ * - We also guarantee that modname will be valid until rescheduled.
  */
 const char *kallsyms_lookup(unsigned long addr,
                            unsigned long *symbolsize,
@@ -276,7 +296,7 @@ const char *kallsyms_lookup(unsigned long addr,
                return namebuf;
        }
 
-       /* see if it's in a module */
+       /* See if it's in a module. */
        return module_address_lookup(addr, symbolsize, offset, modname,
                                     namebuf);
 }
@@ -294,7 +314,7 @@ int lookup_symbol_name(unsigned long addr, char *symname)
                kallsyms_expand_symbol(get_symbol_offset(pos), symname);
                return 0;
        }
-       /* see if it's in a module */
+       /* See if it's in a module. */
        return lookup_module_symbol_name(addr, symname);
 }
 
@@ -313,7 +333,7 @@ int lookup_symbol_attrs(unsigned long addr, unsigned long *size,
                modname[0] = '\0';
                return 0;
        }
-       /* see if it's in a module */
+       /* See if it's in a module. */
        return lookup_module_symbol_attrs(addr, size, offset, modname, name);
 }
 
@@ -342,6 +362,7 @@ int sprint_symbol(char *buffer, unsigned long address)
 
        return len;
 }
+EXPORT_SYMBOL_GPL(sprint_symbol);
 
 /* Look up a kernel symbol and print it to the kernel messages. */
 void __print_symbol(const char *fmt, unsigned long address)
@@ -352,13 +373,13 @@ void __print_symbol(const char *fmt, unsigned long address)
 
        printk(fmt, buffer);
 }
+EXPORT_SYMBOL(__print_symbol);
 
 /* To avoid using get_symbol_offset for every symbol, we carry prefix along. */
-struct kallsym_iter
-{
+struct kallsym_iter {
        loff_t pos;
        unsigned long value;
-       unsigned int nameoff; /* If iterating in core kernel symbols */
+       unsigned int nameoff; /* If iterating in core kernel symbols. */
        char type;
        char name[KSYM_NAME_LEN];
        char module_name[MODULE_NAME_LEN];
@@ -404,7 +425,7 @@ static int update_iter(struct kallsym_iter *iter, loff_t pos)
                iter->pos = pos;
                return get_ksymbol_mod(iter);
        }
-       
+
        /* If we're not on the desired position, reset to new position. */
        if (pos != iter->pos)
                reset_iter(iter, pos);
@@ -439,23 +460,25 @@ static int s_show(struct seq_file *m, void *p)
 {
        struct kallsym_iter *iter = m->private;
 
-       /* Some debugging symbols have no name.  Ignore them. */ 
+       /* Some debugging symbols have no name.  Ignore them. */
        if (!iter->name[0])
                return 0;
 
        if (iter->module_name[0]) {
                char type;
 
-               /* Label it "global" if it is exported,
-                * "local" if not exported. */
+               /*
+                * Label it "global" if it is exported,
+                * "local" if not exported.
+                */
                type = iter->exported ? toupper(iter->type) :
                                        tolower(iter->type);
                seq_printf(m, "%0*lx %c %s\t[%s]\n",
-                          (int)(2*sizeof(void*)),
+                          (int)(2 * sizeof(void *)),
                           iter->value, type, iter->name, iter->module_name);
        } else
                seq_printf(m, "%0*lx %c %s\n",
-                          (int)(2*sizeof(void*)),
+                          (int)(2 * sizeof(void *)),
                           iter->value, iter->type, iter->name);
        return 0;
 }
@@ -469,9 +492,11 @@ static const struct seq_operations kallsyms_op = {
 
 static int kallsyms_open(struct inode *inode, struct file *file)
 {
-       /* We keep iterator in m->private, since normal case is to
+       /*
+        * We keep iterator in m->private, since normal case is to
         * s_start from where we left off, so we avoid doing
-        * using get_symbol_offset for every symbol */
+        * using get_symbol_offset for every symbol.
+        */
        struct kallsym_iter *iter;
        int ret;
 
@@ -500,7 +525,4 @@ static int __init kallsyms_init(void)
        proc_create("kallsyms", 0444, NULL, &kallsyms_operations);
        return 0;
 }
-__initcall(kallsyms_init);
-
-EXPORT_SYMBOL(__print_symbol);
-EXPORT_SYMBOL_GPL(sprint_symbol);
+device_initcall(kallsyms_init);
index e4983770913b915e85fb2906e4f9ffd766d0694f..ae1c35201cc873d697921cb2c5da95896d89493d 100644 (file)
@@ -1448,17 +1448,17 @@ int kernel_kexec(void)
                        goto Restore_console;
                }
                suspend_console();
-               error = device_suspend(PMSG_FREEZE);
+               error = dpm_suspend_start(PMSG_FREEZE);
                if (error)
                        goto Resume_console;
-               /* At this point, device_suspend() has been called,
-                * but *not* device_power_down(). We *must*
-                * device_power_down() now.  Otherwise, drivers for
+               /* At this point, dpm_suspend_start() has been called,
+                * but *not* dpm_suspend_noirq(). We *must* call
+                * dpm_suspend_noirq() now.  Otherwise, drivers for
                 * some devices (e.g. interrupt controllers) become
                 * desynchronized with the actual state of the
                 * hardware at resume time, and evil weirdness ensues.
                 */
-               error = device_power_down(PMSG_FREEZE);
+               error = dpm_suspend_noirq(PMSG_FREEZE);
                if (error)
                        goto Resume_devices;
                error = disable_nonboot_cpus();
@@ -1486,9 +1486,9 @@ int kernel_kexec(void)
                local_irq_enable();
  Enable_cpus:
                enable_nonboot_cpus();
-               device_power_up(PMSG_RESTORE);
+               dpm_resume_noirq(PMSG_RESTORE);
  Resume_devices:
-               device_resume(PMSG_RESTORE);
+               dpm_resume_end(PMSG_RESTORE);
  Resume_console:
                resume_console();
                thaw_processes();
index 35f7de00bf0db7aad5b4a34e1311e6157764d331..e4ab36ce767222becc860650e0892399ab58b96d 100644 (file)
@@ -2455,6 +2455,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
        mutex_lock(&module_mutex);
        /* Drop initial reference. */
        module_put(mod);
+       trim_init_extable(mod);
        module_free(mod, mod->module_init);
        mod->module_init = NULL;
        mod->init_size = 0;
index de273ec85bd2a1a9d9ac6077ddb3078f0d8d04ef..7f6912ced2bab2c957da0ef3edc6e70625560837 100644 (file)
@@ -24,9 +24,6 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 
-/* We abuse the high bits of "perm" to record whether we kmalloc'ed. */
-#define KPARAM_KMALLOCED       0x80000000
-
 #if 0
 #define DEBUGP printk
 #else
@@ -220,13 +217,13 @@ int param_set_charp(const char *val, struct kernel_param *kp)
                return -ENOSPC;
        }
 
-       if (kp->perm & KPARAM_KMALLOCED)
+       if (kp->flags & KPARAM_KMALLOCED)
                kfree(*(char **)kp->arg);
 
        /* This is a hack.  We can't need to strdup in early boot, and we
         * don't need to; this mangled commandline is preserved. */
        if (slab_is_available()) {
-               kp->perm |= KPARAM_KMALLOCED;
+               kp->flags |= KPARAM_KMALLOCED;
                *(char **)kp->arg = kstrdup(val, GFP_KERNEL);
                if (!kp->arg)
                        return -ENOMEM;
@@ -241,44 +238,63 @@ int param_get_charp(char *buffer, struct kernel_param *kp)
        return sprintf(buffer, "%s", *((char **)kp->arg));
 }
 
+/* Actually could be a bool or an int, for historical reasons. */
 int param_set_bool(const char *val, struct kernel_param *kp)
 {
+       bool v;
+
        /* No equals means "set"... */
        if (!val) val = "1";
 
        /* One of =[yYnN01] */
        switch (val[0]) {
        case 'y': case 'Y': case '1':
-               *(int *)kp->arg = 1;
-               return 0;
+               v = true;
+               break;
        case 'n': case 'N': case '0':
-               *(int *)kp->arg = 0;
-               return 0;
+               v = false;
+               break;
+       default:
+               return -EINVAL;
        }
-       return -EINVAL;
+
+       if (kp->flags & KPARAM_ISBOOL)
+               *(bool *)kp->arg = v;
+       else
+               *(int *)kp->arg = v;
+       return 0;
 }
 
 int param_get_bool(char *buffer, struct kernel_param *kp)
 {
+       bool val;
+       if (kp->flags & KPARAM_ISBOOL)
+               val = *(bool *)kp->arg;
+       else
+               val = *(int *)kp->arg;
+
        /* Y and N chosen as being relatively non-coder friendly */
-       return sprintf(buffer, "%c", (*(int *)kp->arg) ? 'Y' : 'N');
+       return sprintf(buffer, "%c", val ? 'Y' : 'N');
 }
 
+/* This one must be bool. */
 int param_set_invbool(const char *val, struct kernel_param *kp)
 {
-       int boolval, ret;
+       int ret;
+       bool boolval;
        struct kernel_param dummy;
 
        dummy.arg = &boolval;
+       dummy.flags = KPARAM_ISBOOL;
        ret = param_set_bool(val, &dummy);
        if (ret == 0)
-               *(int *)kp->arg = !boolval;
+               *(bool *)kp->arg = !boolval;
        return ret;
 }
 
 int param_get_invbool(char *buffer, struct kernel_param *kp)
 {
-       return sprintf(buffer, "%c", (*(int *)kp->arg) ? 'N' : 'Y');
+       return sprintf(buffer, "%c", (*(bool *)kp->arg) ? 'N' : 'Y');
 }
 
 /* We break the rule and mangle the string. */
@@ -591,7 +607,7 @@ void destroy_params(const struct kernel_param *params, unsigned num)
        unsigned int i;
 
        for (i = 0; i < num; i++)
-               if (params[i].perm & KPARAM_KMALLOCED)
+               if (params[i].flags & KPARAM_KMALLOCED)
                        kfree(*(char **)params[i].arg);
 }
 
index ef5d8a5b245390130f76e9284f372396dfa7ddd5..29b685f551aac6aa2f5bee8e1356755ae5627001 100644 (file)
@@ -3570,12 +3570,8 @@ perf_counter_alloc(struct perf_counter_attr *attr,
        if (attr->inherit && (attr->sample_type & PERF_SAMPLE_GROUP))
                goto done;
 
-       if (attr->type == PERF_TYPE_RAW) {
-               pmu = hw_perf_counter_init(counter);
-               goto done;
-       }
-
        switch (attr->type) {
+       case PERF_TYPE_RAW:
        case PERF_TYPE_HARDWARE:
        case PERF_TYPE_HW_CACHE:
                pmu = hw_perf_counter_init(counter);
@@ -3588,6 +3584,9 @@ perf_counter_alloc(struct perf_counter_attr *attr,
        case PERF_TYPE_TRACEPOINT:
                pmu = tp_perf_counter_init(counter);
                break;
+
+       default:
+               break;
        }
 done:
        err = 0;
@@ -3614,6 +3613,85 @@ done:
        return counter;
 }
 
+static int perf_copy_attr(struct perf_counter_attr __user *uattr,
+                         struct perf_counter_attr *attr)
+{
+       int ret;
+       u32 size;
+
+       if (!access_ok(VERIFY_WRITE, uattr, PERF_ATTR_SIZE_VER0))
+               return -EFAULT;
+
+       /*
+        * zero the full structure, so that a short copy will be nice.
+        */
+       memset(attr, 0, sizeof(*attr));
+
+       ret = get_user(size, &uattr->size);
+       if (ret)
+               return ret;
+
+       if (size > PAGE_SIZE)   /* silly large */
+               goto err_size;
+
+       if (!size)              /* abi compat */
+               size = PERF_ATTR_SIZE_VER0;
+
+       if (size < PERF_ATTR_SIZE_VER0)
+               goto err_size;
+
+       /*
+        * If we're handed a bigger struct than we know of,
+        * ensure all the unknown bits are 0.
+        */
+       if (size > sizeof(*attr)) {
+               unsigned long val;
+               unsigned long __user *addr;
+               unsigned long __user *end;
+
+               addr = PTR_ALIGN((void __user *)uattr + sizeof(*attr),
+                               sizeof(unsigned long));
+               end  = PTR_ALIGN((void __user *)uattr + size,
+                               sizeof(unsigned long));
+
+               for (; addr < end; addr += sizeof(unsigned long)) {
+                       ret = get_user(val, addr);
+                       if (ret)
+                               return ret;
+                       if (val)
+                               goto err_size;
+               }
+       }
+
+       ret = copy_from_user(attr, uattr, size);
+       if (ret)
+               return -EFAULT;
+
+       /*
+        * If the type exists, the corresponding creation will verify
+        * the attr->config.
+        */
+       if (attr->type >= PERF_TYPE_MAX)
+               return -EINVAL;
+
+       if (attr->__reserved_1 || attr->__reserved_2 || attr->__reserved_3)
+               return -EINVAL;
+
+       if (attr->sample_type & ~(PERF_SAMPLE_MAX-1))
+               return -EINVAL;
+
+       if (attr->read_format & ~(PERF_FORMAT_MAX-1))
+               return -EINVAL;
+
+out:
+       return ret;
+
+err_size:
+       put_user(sizeof(*attr), &uattr->size);
+       ret = -E2BIG;
+       goto out;
+}
+
 /**
  * sys_perf_counter_open - open a performance counter, associate it to a task/cpu
  *
@@ -3623,7 +3701,7 @@ done:
  * @group_fd:          group leader counter fd
  */
 SYSCALL_DEFINE5(perf_counter_open,
-               const struct perf_counter_attr __user *, attr_uptr,
+               struct perf_counter_attr __user *, attr_uptr,
                pid_t, pid, int, cpu, int, group_fd, unsigned long, flags)
 {
        struct perf_counter *counter, *group_leader;
@@ -3639,8 +3717,9 @@ SYSCALL_DEFINE5(perf_counter_open,
        if (flags)
                return -EINVAL;
 
-       if (copy_from_user(&attr, attr_uptr, sizeof(attr)) != 0)
-               return -EFAULT;
+       ret = perf_copy_attr(attr_uptr, &attr);
+       if (ret)
+               return ret;
 
        if (!attr.exclude_kernel) {
                if (perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN))
index 23bd4daeb96b221690ba16ade909d1dd4672093f..72067cbdb37f0839819db9280c1e42b8c250f9d8 100644 (file)
@@ -116,9 +116,13 @@ config SUSPEND_FREEZER
 
          Turning OFF this setting is NOT recommended! If in doubt, say Y.
 
+config HIBERNATION_NVS
+       bool
+
 config HIBERNATION
        bool "Hibernation (aka 'suspend to disk')"
        depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE
+       select HIBERNATION_NVS if HAS_IOMEM
        ---help---
          Enable the suspend to disk (STD) functionality, which is usually
          called "hibernation" in user interfaces.  STD checkpoints the
index 720ea4f781bd4896ef8922b9e55442f447967ab5..c3b81c30e5d57627f082f66a70a7b464d63c412d 100644 (file)
@@ -6,6 +6,9 @@ endif
 obj-$(CONFIG_PM)               += main.o
 obj-$(CONFIG_PM_SLEEP)         += console.o
 obj-$(CONFIG_FREEZER)          += process.o
-obj-$(CONFIG_HIBERNATION)      += swsusp.o disk.o snapshot.o swap.o user.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_NVS)  += hibernate_nvs.o
 
 obj-$(CONFIG_MAGIC_SYSRQ)      += poweroff.o
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
deleted file mode 100644 (file)
index 5cb080e..0000000
+++ /dev/null
@@ -1,955 +0,0 @@
-/*
- * kernel/power/disk.c - Suspend-to-disk support.
- *
- * Copyright (c) 2003 Patrick Mochel
- * Copyright (c) 2003 Open Source Development Lab
- * Copyright (c) 2004 Pavel Machek <pavel@suse.cz>
- *
- * This file is released under the GPLv2.
- *
- */
-
-#include <linux/suspend.h>
-#include <linux/syscalls.h>
-#include <linux/reboot.h>
-#include <linux/string.h>
-#include <linux/device.h>
-#include <linux/kmod.h>
-#include <linux/delay.h>
-#include <linux/fs.h>
-#include <linux/mount.h>
-#include <linux/pm.h>
-#include <linux/console.h>
-#include <linux/cpu.h>
-#include <linux/freezer.h>
-#include <scsi/scsi_scan.h>
-#include <asm/suspend.h>
-
-#include "power.h"
-
-
-static int noresume = 0;
-static char resume_file[256] = CONFIG_PM_STD_PARTITION;
-dev_t swsusp_resume_device;
-sector_t swsusp_resume_block;
-
-enum {
-       HIBERNATION_INVALID,
-       HIBERNATION_PLATFORM,
-       HIBERNATION_TEST,
-       HIBERNATION_TESTPROC,
-       HIBERNATION_SHUTDOWN,
-       HIBERNATION_REBOOT,
-       /* keep last */
-       __HIBERNATION_AFTER_LAST
-};
-#define HIBERNATION_MAX (__HIBERNATION_AFTER_LAST-1)
-#define HIBERNATION_FIRST (HIBERNATION_INVALID + 1)
-
-static int hibernation_mode = HIBERNATION_SHUTDOWN;
-
-static struct platform_hibernation_ops *hibernation_ops;
-
-/**
- * hibernation_set_ops - set the global hibernate operations
- * @ops: the hibernation operations to use in subsequent hibernation transitions
- */
-
-void hibernation_set_ops(struct platform_hibernation_ops *ops)
-{
-       if (ops && !(ops->begin && ops->end &&  ops->pre_snapshot
-           && ops->prepare && ops->finish && ops->enter && ops->pre_restore
-           && ops->restore_cleanup)) {
-               WARN_ON(1);
-               return;
-       }
-       mutex_lock(&pm_mutex);
-       hibernation_ops = ops;
-       if (ops)
-               hibernation_mode = HIBERNATION_PLATFORM;
-       else if (hibernation_mode == HIBERNATION_PLATFORM)
-               hibernation_mode = HIBERNATION_SHUTDOWN;
-
-       mutex_unlock(&pm_mutex);
-}
-
-static bool entering_platform_hibernation;
-
-bool system_entering_hibernation(void)
-{
-       return entering_platform_hibernation;
-}
-EXPORT_SYMBOL(system_entering_hibernation);
-
-#ifdef CONFIG_PM_DEBUG
-static void hibernation_debug_sleep(void)
-{
-       printk(KERN_INFO "hibernation debug: Waiting for 5 seconds.\n");
-       mdelay(5000);
-}
-
-static int hibernation_testmode(int mode)
-{
-       if (hibernation_mode == mode) {
-               hibernation_debug_sleep();
-               return 1;
-       }
-       return 0;
-}
-
-static int hibernation_test(int level)
-{
-       if (pm_test_level == level) {
-               hibernation_debug_sleep();
-               return 1;
-       }
-       return 0;
-}
-#else /* !CONFIG_PM_DEBUG */
-static int hibernation_testmode(int mode) { return 0; }
-static int hibernation_test(int level) { return 0; }
-#endif /* !CONFIG_PM_DEBUG */
-
-/**
- *     platform_begin - tell the platform driver that we're starting
- *     hibernation
- */
-
-static int platform_begin(int platform_mode)
-{
-       return (platform_mode && hibernation_ops) ?
-               hibernation_ops->begin() : 0;
-}
-
-/**
- *     platform_end - tell the platform driver that we've entered the
- *     working state
- */
-
-static void platform_end(int platform_mode)
-{
-       if (platform_mode && hibernation_ops)
-               hibernation_ops->end();
-}
-
-/**
- *     platform_pre_snapshot - prepare the machine for hibernation using the
- *     platform driver if so configured and return an error code if it fails
- */
-
-static int platform_pre_snapshot(int platform_mode)
-{
-       return (platform_mode && hibernation_ops) ?
-               hibernation_ops->pre_snapshot() : 0;
-}
-
-/**
- *     platform_leave - prepare the machine for switching to the normal mode
- *     of operation using the platform driver (called with interrupts disabled)
- */
-
-static void platform_leave(int platform_mode)
-{
-       if (platform_mode && hibernation_ops)
-               hibernation_ops->leave();
-}
-
-/**
- *     platform_finish - switch the machine to the normal mode of operation
- *     using the platform driver (must be called after platform_prepare())
- */
-
-static void platform_finish(int platform_mode)
-{
-       if (platform_mode && hibernation_ops)
-               hibernation_ops->finish();
-}
-
-/**
- *     platform_pre_restore - prepare the platform for the restoration from a
- *     hibernation image.  If the restore fails after this function has been
- *     called, platform_restore_cleanup() must be called.
- */
-
-static int platform_pre_restore(int platform_mode)
-{
-       return (platform_mode && hibernation_ops) ?
-               hibernation_ops->pre_restore() : 0;
-}
-
-/**
- *     platform_restore_cleanup - switch the platform to the normal mode of
- *     operation after a failing restore.  If platform_pre_restore() has been
- *     called before the failing restore, this function must be called too,
- *     regardless of the result of platform_pre_restore().
- */
-
-static void platform_restore_cleanup(int platform_mode)
-{
-       if (platform_mode && hibernation_ops)
-               hibernation_ops->restore_cleanup();
-}
-
-/**
- *     platform_recover - recover the platform from a failure to suspend
- *     devices.
- */
-
-static void platform_recover(int platform_mode)
-{
-       if (platform_mode && hibernation_ops && hibernation_ops->recover)
-               hibernation_ops->recover();
-}
-
-/**
- *     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.
- */
-
-static int create_image(int platform_mode)
-{
-       int error;
-
-       error = arch_prepare_suspend();
-       if (error)
-               return error;
-
-       /* At this point, device_suspend() has been called, but *not*
-        * device_power_down(). We *must* call device_power_down() now.
-        * Otherwise, drivers for some devices (e.g. interrupt controllers)
-        * become desynchronized with the actual state of the hardware
-        * at resume time, and evil weirdness ensues.
-        */
-       error = device_power_down(PMSG_FREEZE);
-       if (error) {
-               printk(KERN_ERR "PM: Some devices failed to power down, "
-                       "aborting hibernation\n");
-               return error;
-       }
-
-       error = platform_pre_snapshot(platform_mode);
-       if (error || hibernation_test(TEST_PLATFORM))
-               goto Platform_finish;
-
-       error = disable_nonboot_cpus();
-       if (error || hibernation_test(TEST_CPUS)
-           || hibernation_testmode(HIBERNATION_TEST))
-               goto Enable_cpus;
-
-       local_irq_disable();
-
-       error = sysdev_suspend(PMSG_FREEZE);
-       if (error) {
-               printk(KERN_ERR "PM: Some system devices failed to power down, "
-                       "aborting hibernation\n");
-               goto Enable_irqs;
-       }
-
-       if (hibernation_test(TEST_CORE))
-               goto Power_up;
-
-       in_suspend = 1;
-       save_processor_state();
-       error = swsusp_arch_suspend();
-       if (error)
-               printk(KERN_ERR "PM: Error %d creating hibernation image\n",
-                       error);
-       /* Restore control flow magically appears here */
-       restore_processor_state();
-       if (!in_suspend)
-               platform_leave(platform_mode);
-
- Power_up:
-       sysdev_resume();
-       /* NOTE:  device_power_up() is just a resume() for devices
-        * that suspended with irqs off ... no overall powerup.
-        */
-
- Enable_irqs:
-       local_irq_enable();
-
- Enable_cpus:
-       enable_nonboot_cpus();
-
- Platform_finish:
-       platform_finish(platform_mode);
-
-       device_power_up(in_suspend ?
-               (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
-
-       return error;
-}
-
-/**
- *     hibernation_snapshot - quiesce devices and create the hibernation
- *     snapshot image.
- *     @platform_mode - if set, use the platform driver, if available, to
- *                      prepare the platform firmware for the power transition.
- *
- *     Must be called with pm_mutex held
- */
-
-int hibernation_snapshot(int platform_mode)
-{
-       int error;
-
-       error = platform_begin(platform_mode);
-       if (error)
-               return error;
-
-       /* Free memory before shutting down devices. */
-       error = swsusp_shrink_memory();
-       if (error)
-               goto Close;
-
-       suspend_console();
-       error = device_suspend(PMSG_FREEZE);
-       if (error)
-               goto Recover_platform;
-
-       if (hibernation_test(TEST_DEVICES))
-               goto Recover_platform;
-
-       error = create_image(platform_mode);
-       /* Control returns here after successful restore */
-
- Resume_devices:
-       device_resume(in_suspend ?
-               (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
-       resume_console();
- Close:
-       platform_end(platform_mode);
-       return error;
-
- Recover_platform:
-       platform_recover(platform_mode);
-       goto Resume_devices;
-}
-
-/**
- *     resume_target_kernel - prepare devices that need to be suspended with
- *     interrupts off, restore the contents of highmem that have not been
- *     restored yet from the image and run the low level code that will restore
- *     the remaining contents of memory and switch to the just restored target
- *     kernel.
- */
-
-static int resume_target_kernel(bool platform_mode)
-{
-       int error;
-
-       error = device_power_down(PMSG_QUIESCE);
-       if (error) {
-               printk(KERN_ERR "PM: Some devices failed to power down, "
-                       "aborting resume\n");
-               return error;
-       }
-
-       error = platform_pre_restore(platform_mode);
-       if (error)
-               goto Cleanup;
-
-       error = disable_nonboot_cpus();
-       if (error)
-               goto Enable_cpus;
-
-       local_irq_disable();
-
-       error = sysdev_suspend(PMSG_QUIESCE);
-       if (error)
-               goto Enable_irqs;
-
-       /* We'll ignore saved state, but this gets preempt count (etc) right */
-       save_processor_state();
-       error = restore_highmem();
-       if (!error) {
-               error = swsusp_arch_resume();
-               /*
-                * The code below is only ever reached in case of a failure.
-                * Otherwise execution continues at place where
-                * swsusp_arch_suspend() was called
-                */
-               BUG_ON(!error);
-               /* This call to restore_highmem() undos the previous one */
-               restore_highmem();
-       }
-       /*
-        * The only reason why swsusp_arch_resume() can fail is memory being
-        * very tight, so we have to free it as soon as we can to avoid
-        * subsequent failures
-        */
-       swsusp_free();
-       restore_processor_state();
-       touch_softlockup_watchdog();
-
-       sysdev_resume();
-
- Enable_irqs:
-       local_irq_enable();
-
- Enable_cpus:
-       enable_nonboot_cpus();
-
- Cleanup:
-       platform_restore_cleanup(platform_mode);
-
-       device_power_up(PMSG_RECOVER);
-
-       return error;
-}
-
-/**
- *     hibernation_restore - quiesce devices and restore the hibernation
- *     snapshot image.  If successful, control returns in hibernation_snaphot()
- *     @platform_mode - if set, use the platform driver, if available, to
- *                      prepare the platform firmware for the transition.
- *
- *     Must be called with pm_mutex held
- */
-
-int hibernation_restore(int platform_mode)
-{
-       int error;
-
-       pm_prepare_console();
-       suspend_console();
-       error = device_suspend(PMSG_QUIESCE);
-       if (!error) {
-               error = resume_target_kernel(platform_mode);
-               device_resume(PMSG_RECOVER);
-       }
-       resume_console();
-       pm_restore_console();
-       return error;
-}
-
-/**
- *     hibernation_platform_enter - enter the hibernation state using the
- *     platform driver (if available)
- */
-
-int hibernation_platform_enter(void)
-{
-       int error;
-
-       if (!hibernation_ops)
-               return -ENOSYS;
-
-       /*
-        * We have cancelled the power transition by running
-        * hibernation_ops->finish() before saving the image, so we should let
-        * the firmware know that we're going to enter the sleep state after all
-        */
-       error = hibernation_ops->begin();
-       if (error)
-               goto Close;
-
-       entering_platform_hibernation = true;
-       suspend_console();
-       error = device_suspend(PMSG_HIBERNATE);
-       if (error) {
-               if (hibernation_ops->recover)
-                       hibernation_ops->recover();
-               goto Resume_devices;
-       }
-
-       error = device_power_down(PMSG_HIBERNATE);
-       if (error)
-               goto Resume_devices;
-
-       error = hibernation_ops->prepare();
-       if (error)
-               goto Platofrm_finish;
-
-       error = disable_nonboot_cpus();
-       if (error)
-               goto Platofrm_finish;
-
-       local_irq_disable();
-       sysdev_suspend(PMSG_HIBERNATE);
-       hibernation_ops->enter();
-       /* We should never get here */
-       while (1);
-
-       /*
-        * We don't need to reenable the nonboot CPUs or resume consoles, since
-        * the system is going to be halted anyway.
-        */
- Platofrm_finish:
-       hibernation_ops->finish();
-
-       device_power_up(PMSG_RESTORE);
-
- Resume_devices:
-       entering_platform_hibernation = false;
-       device_resume(PMSG_RESTORE);
-       resume_console();
-
- Close:
-       hibernation_ops->end();
-
-       return error;
-}
-
-/**
- *     power_down - Shut the machine down for hibernation.
- *
- *     Use the platform driver, if configured so; otherwise try
- *     to power off or reboot.
- */
-
-static void power_down(void)
-{
-       switch (hibernation_mode) {
-       case HIBERNATION_TEST:
-       case HIBERNATION_TESTPROC:
-               break;
-       case HIBERNATION_REBOOT:
-               kernel_restart(NULL);
-               break;
-       case HIBERNATION_PLATFORM:
-               hibernation_platform_enter();
-       case HIBERNATION_SHUTDOWN:
-               kernel_power_off();
-               break;
-       }
-       kernel_halt();
-       /*
-        * Valid image is on the disk, if we continue we risk serious data
-        * corruption after resume.
-        */
-       printk(KERN_CRIT "PM: Please power down manually\n");
-       while(1);
-}
-
-static int prepare_processes(void)
-{
-       int error = 0;
-
-       if (freeze_processes()) {
-               error = -EBUSY;
-               thaw_processes();
-       }
-       return error;
-}
-
-/**
- *     hibernate - The granpappy of the built-in hibernation management
- */
-
-int hibernate(void)
-{
-       int error;
-
-       mutex_lock(&pm_mutex);
-       /* The snapshot device should not be opened while we're running */
-       if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
-               error = -EBUSY;
-               goto Unlock;
-       }
-
-       pm_prepare_console();
-       error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
-       if (error)
-               goto Exit;
-
-       error = usermodehelper_disable();
-       if (error)
-               goto Exit;
-
-       /* Allocate memory management structures */
-       error = create_basic_memory_bitmaps();
-       if (error)
-               goto Exit;
-
-       printk(KERN_INFO "PM: Syncing filesystems ... ");
-       sys_sync();
-       printk("done.\n");
-
-       error = prepare_processes();
-       if (error)
-               goto Finish;
-
-       if (hibernation_test(TEST_FREEZER))
-               goto Thaw;
-
-       if (hibernation_testmode(HIBERNATION_TESTPROC))
-               goto Thaw;
-
-       error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);
-       if (in_suspend && !error) {
-               unsigned int flags = 0;
-
-               if (hibernation_mode == HIBERNATION_PLATFORM)
-                       flags |= SF_PLATFORM_MODE;
-               pr_debug("PM: writing image.\n");
-               error = swsusp_write(flags);
-               swsusp_free();
-               if (!error)
-                       power_down();
-       } else {
-               pr_debug("PM: Image restored successfully.\n");
-               swsusp_free();
-       }
- Thaw:
-       thaw_processes();
- Finish:
-       free_basic_memory_bitmaps();
-       usermodehelper_enable();
- Exit:
-       pm_notifier_call_chain(PM_POST_HIBERNATION);
-       pm_restore_console();
-       atomic_inc(&snapshot_device_available);
- Unlock:
-       mutex_unlock(&pm_mutex);
-       return error;
-}
-
-
-/**
- *     software_resume - Resume from a saved image.
- *
- *     Called as a late_initcall (so all devices are discovered and
- *     initialized), we call swsusp to see if we have a saved image or not.
- *     If so, we quiesce devices, the restore the saved image. We will
- *     return above (in hibernate() ) if everything goes well.
- *     Otherwise, we fail gracefully and return to the normally
- *     scheduled program.
- *
- */
-
-static int software_resume(void)
-{
-       int error;
-       unsigned int flags;
-
-       /*
-        * If the user said "noresume".. bail out early.
-        */
-       if (noresume)
-               return 0;
-
-       /*
-        * name_to_dev_t() below takes a sysfs buffer mutex when sysfs
-        * is configured into the kernel. Since the regular hibernate
-        * trigger path is via sysfs which takes a buffer mutex before
-        * calling hibernate functions (which take pm_mutex) this can
-        * cause lockdep to complain about a possible ABBA deadlock
-        * which cannot happen since we're in the boot code here and
-        * sysfs can't be invoked yet. Therefore, we use a subclass
-        * here to avoid lockdep complaining.
-        */
-       mutex_lock_nested(&pm_mutex, SINGLE_DEPTH_NESTING);
-
-       if (swsusp_resume_device)
-               goto Check_image;
-
-       if (!strlen(resume_file)) {
-               error = -ENOENT;
-               goto Unlock;
-       }
-
-       pr_debug("PM: Checking image partition %s\n", resume_file);
-
-       /* Check if the device is there */
-       swsusp_resume_device = name_to_dev_t(resume_file);
-       if (!swsusp_resume_device) {
-               /*
-                * Some device discovery might still be in progress; we need
-                * to wait for this to finish.
-                */
-               wait_for_device_probe();
-               /*
-                * We can't depend on SCSI devices being available after loading
-                * one of their modules until scsi_complete_async_scans() is
-                * called and the resume device usually is a SCSI one.
-                */
-               scsi_complete_async_scans();
-
-               swsusp_resume_device = name_to_dev_t(resume_file);
-               if (!swsusp_resume_device) {
-                       error = -ENODEV;
-                       goto Unlock;
-               }
-       }
-
- Check_image:
-       pr_debug("PM: Resume from partition %d:%d\n",
-               MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device));
-
-       pr_debug("PM: Checking hibernation image.\n");
-       error = swsusp_check();
-       if (error)
-               goto Unlock;
-
-       /* The snapshot device should not be opened while we're running */
-       if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
-               error = -EBUSY;
-               goto Unlock;
-       }
-
-       pm_prepare_console();
-       error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
-       if (error)
-               goto Finish;
-
-       error = usermodehelper_disable();
-       if (error)
-               goto Finish;
-
-       error = create_basic_memory_bitmaps();
-       if (error)
-               goto Finish;
-
-       pr_debug("PM: Preparing processes for restore.\n");
-       error = prepare_processes();
-       if (error) {
-               swsusp_close(FMODE_READ);
-               goto Done;
-       }
-
-       pr_debug("PM: Reading hibernation image.\n");
-
-       error = swsusp_read(&flags);
-       if (!error)
-               hibernation_restore(flags & SF_PLATFORM_MODE);
-
-       printk(KERN_ERR "PM: Restore failed, recovering.\n");
-       swsusp_free();
-       thaw_processes();
- Done:
-       free_basic_memory_bitmaps();
-       usermodehelper_enable();
- Finish:
-       pm_notifier_call_chain(PM_POST_RESTORE);
-       pm_restore_console();
-       atomic_inc(&snapshot_device_available);
-       /* For success case, the suspend path will release the lock */
- Unlock:
-       mutex_unlock(&pm_mutex);
-       pr_debug("PM: Resume from disk failed.\n");
-       return error;
-}
-
-late_initcall(software_resume);
-
-
-static const char * const hibernation_modes[] = {
-       [HIBERNATION_PLATFORM]  = "platform",
-       [HIBERNATION_SHUTDOWN]  = "shutdown",
-       [HIBERNATION_REBOOT]    = "reboot",
-       [HIBERNATION_TEST]      = "test",
-       [HIBERNATION_TESTPROC]  = "testproc",
-};
-
-/**
- *     disk - Control hibernation mode
- *
- *     Suspend-to-disk can be handled in several ways. We have a few options
- *     for putting the system to sleep - using the platform driver (e.g. ACPI
- *     or other hibernation_ops), powering off the system or rebooting the
- *     system (for testing) as well as the two test modes.
- *
- *     The system can support 'platform', and that is known a priori (and
- *     encoded by the presence of hibernation_ops). However, the user may
- *     choose 'shutdown' or 'reboot' as alternatives, as well as one fo the
- *     test modes, 'test' or 'testproc'.
- *
- *     show() will display what the mode is currently set to.
- *     store() will accept one of
- *
- *     'platform'
- *     'shutdown'
- *     'reboot'
- *     'test'
- *     'testproc'
- *
- *     It will only change to 'platform' if the system
- *     supports it (as determined by having hibernation_ops).
- */
-
-static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
-                        char *buf)
-{
-       int i;
-       char *start = buf;
-
-       for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
-               if (!hibernation_modes[i])
-                       continue;
-               switch (i) {
-               case HIBERNATION_SHUTDOWN:
-               case HIBERNATION_REBOOT:
-               case HIBERNATION_TEST:
-               case HIBERNATION_TESTPROC:
-                       break;
-               case HIBERNATION_PLATFORM:
-                       if (hibernation_ops)
-                               break;
-                       /* not a valid mode, continue with loop */
-                       continue;
-               }
-               if (i == hibernation_mode)
-                       buf += sprintf(buf, "[%s] ", hibernation_modes[i]);
-               else
-                       buf += sprintf(buf, "%s ", hibernation_modes[i]);
-       }
-       buf += sprintf(buf, "\n");
-       return buf-start;
-}
-
-
-static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
-                         const char *buf, size_t n)
-{
-       int error = 0;
-       int i;
-       int len;
-       char *p;
-       int mode = HIBERNATION_INVALID;
-
-       p = memchr(buf, '\n', n);
-       len = p ? p - buf : n;
-
-       mutex_lock(&pm_mutex);
-       for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
-               if (len == strlen(hibernation_modes[i])
-                   && !strncmp(buf, hibernation_modes[i], len)) {
-                       mode = i;
-                       break;
-               }
-       }
-       if (mode != HIBERNATION_INVALID) {
-               switch (mode) {
-               case HIBERNATION_SHUTDOWN:
-               case HIBERNATION_REBOOT:
-               case HIBERNATION_TEST:
-               case HIBERNATION_TESTPROC:
-                       hibernation_mode = mode;
-                       break;
-               case HIBERNATION_PLATFORM:
-                       if (hibernation_ops)
-                               hibernation_mode = mode;
-                       else
-                               error = -EINVAL;
-               }
-       } else
-               error = -EINVAL;
-
-       if (!error)
-               pr_debug("PM: Hibernation mode set to '%s'\n",
-                        hibernation_modes[mode]);
-       mutex_unlock(&pm_mutex);
-       return error ? error : n;
-}
-
-power_attr(disk);
-
-static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr,
-                          char *buf)
-{
-       return sprintf(buf,"%d:%d\n", MAJOR(swsusp_resume_device),
-                      MINOR(swsusp_resume_device));
-}
-
-static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr,
-                           const char *buf, size_t n)
-{
-       unsigned int maj, min;
-       dev_t res;
-       int ret = -EINVAL;
-
-       if (sscanf(buf, "%u:%u", &maj, &min) != 2)
-               goto out;
-
-       res = MKDEV(maj,min);
-       if (maj != MAJOR(res) || min != MINOR(res))
-               goto out;
-
-       mutex_lock(&pm_mutex);
-       swsusp_resume_device = res;
-       mutex_unlock(&pm_mutex);
-       printk(KERN_INFO "PM: Starting manual resume from disk\n");
-       noresume = 0;
-       software_resume();
-       ret = n;
- out:
-       return ret;
-}
-
-power_attr(resume);
-
-static ssize_t image_size_show(struct kobject *kobj, struct kobj_attribute *attr,
-                              char *buf)
-{
-       return sprintf(buf, "%lu\n", image_size);
-}
-
-static ssize_t image_size_store(struct kobject *kobj, struct kobj_attribute *attr,
-                               const char *buf, size_t n)
-{
-       unsigned long size;
-
-       if (sscanf(buf, "%lu", &size) == 1) {
-               image_size = size;
-               return n;
-       }
-
-       return -EINVAL;
-}
-
-power_attr(image_size);
-
-static struct attribute * g[] = {
-       &disk_attr.attr,
-       &resume_attr.attr,
-       &image_size_attr.attr,
-       NULL,
-};
-
-
-static struct attribute_group attr_group = {
-       .attrs = g,
-};
-
-
-static int __init pm_disk_init(void)
-{
-       return sysfs_create_group(power_kobj, &attr_group);
-}
-
-core_initcall(pm_disk_init);
-
-
-static int __init resume_setup(char *str)
-{
-       if (noresume)
-               return 1;
-
-       strncpy( resume_file, str, 255 );
-       return 1;
-}
-
-static int __init resume_offset_setup(char *str)
-{
-       unsigned long long offset;
-
-       if (noresume)
-               return 1;
-
-       if (sscanf(str, "%llu", &offset) == 1)
-               swsusp_resume_block = offset;
-
-       return 1;
-}
-
-static int __init noresume_setup(char *str)
-{
-       noresume = 1;
-       return 1;
-}
-
-__setup("noresume", noresume_setup);
-__setup("resume_offset=", resume_offset_setup);
-__setup("resume=", resume_setup);
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
new file mode 100644 (file)
index 0000000..81d2e74
--- /dev/null
@@ -0,0 +1,955 @@
+/*
+ * kernel/power/hibernate.c - Hibernation (a.k.a suspend-to-disk) support.
+ *
+ * Copyright (c) 2003 Patrick Mochel
+ * Copyright (c) 2003 Open Source Development Lab
+ * Copyright (c) 2004 Pavel Machek <pavel@suse.cz>
+ * Copyright (c) 2009 Rafael J. Wysocki, Novell Inc.
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/suspend.h>
+#include <linux/syscalls.h>
+#include <linux/reboot.h>
+#include <linux/string.h>
+#include <linux/device.h>
+#include <linux/kmod.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/pm.h>
+#include <linux/console.h>
+#include <linux/cpu.h>
+#include <linux/freezer.h>
+#include <scsi/scsi_scan.h>
+#include <asm/suspend.h>
+
+#include "power.h"
+
+
+static int noresume = 0;
+static char resume_file[256] = CONFIG_PM_STD_PARTITION;
+dev_t swsusp_resume_device;
+sector_t swsusp_resume_block;
+
+enum {
+       HIBERNATION_INVALID,
+       HIBERNATION_PLATFORM,
+       HIBERNATION_TEST,
+       HIBERNATION_TESTPROC,
+       HIBERNATION_SHUTDOWN,
+       HIBERNATION_REBOOT,
+       /* keep last */
+       __HIBERNATION_AFTER_LAST
+};
+#define HIBERNATION_MAX (__HIBERNATION_AFTER_LAST-1)
+#define HIBERNATION_FIRST (HIBERNATION_INVALID + 1)
+
+static int hibernation_mode = HIBERNATION_SHUTDOWN;
+
+static struct platform_hibernation_ops *hibernation_ops;
+
+/**
+ * hibernation_set_ops - set the global hibernate operations
+ * @ops: the hibernation operations to use in subsequent hibernation transitions
+ */
+
+void hibernation_set_ops(struct platform_hibernation_ops *ops)
+{
+       if (ops && !(ops->begin && ops->end &&  ops->pre_snapshot
+           && ops->prepare && ops->finish && ops->enter && ops->pre_restore
+           && ops->restore_cleanup)) {
+               WARN_ON(1);
+               return;
+       }
+       mutex_lock(&pm_mutex);
+       hibernation_ops = ops;
+       if (ops)
+               hibernation_mode = HIBERNATION_PLATFORM;
+       else if (hibernation_mode == HIBERNATION_PLATFORM)
+               hibernation_mode = HIBERNATION_SHUTDOWN;
+
+       mutex_unlock(&pm_mutex);
+}
+
+static bool entering_platform_hibernation;
+
+bool system_entering_hibernation(void)
+{
+       return entering_platform_hibernation;
+}
+EXPORT_SYMBOL(system_entering_hibernation);
+
+#ifdef CONFIG_PM_DEBUG
+static void hibernation_debug_sleep(void)
+{
+       printk(KERN_INFO "hibernation debug: Waiting for 5 seconds.\n");
+       mdelay(5000);
+}
+
+static int hibernation_testmode(int mode)
+{
+       if (hibernation_mode == mode) {
+               hibernation_debug_sleep();
+               return 1;
+       }
+       return 0;
+}
+
+static int hibernation_test(int level)
+{
+       if (pm_test_level == level) {
+               hibernation_debug_sleep();
+               return 1;
+       }
+       return 0;
+}
+#else /* !CONFIG_PM_DEBUG */
+static int hibernation_testmode(int mode) { return 0; }
+static int hibernation_test(int level) { return 0; }
+#endif /* !CONFIG_PM_DEBUG */
+
+/**
+ *     platform_begin - tell the platform driver that we're starting
+ *     hibernation
+ */
+
+static int platform_begin(int platform_mode)
+{
+       return (platform_mode && hibernation_ops) ?
+               hibernation_ops->begin() : 0;
+}
+
+/**
+ *     platform_end - tell the platform driver that we've entered the
+ *     working state
+ */
+
+static void platform_end(int platform_mode)
+{
+       if (platform_mode && hibernation_ops)
+               hibernation_ops->end();
+}
+
+/**
+ *     platform_pre_snapshot - prepare the machine for hibernation using the
+ *     platform driver if so configured and return an error code if it fails
+ */
+
+static int platform_pre_snapshot(int platform_mode)
+{
+       return (platform_mode && hibernation_ops) ?
+               hibernation_ops->pre_snapshot() : 0;
+}
+
+/**
+ *     platform_leave - prepare the machine for switching to the normal mode
+ *     of operation using the platform driver (called with interrupts disabled)
+ */
+
+static void platform_leave(int platform_mode)
+{
+       if (platform_mode && hibernation_ops)
+               hibernation_ops->leave();
+}
+
+/**
+ *     platform_finish - switch the machine to the normal mode of operation
+ *     using the platform driver (must be called after platform_prepare())
+ */
+
+static void platform_finish(int platform_mode)
+{
+       if (platform_mode && hibernation_ops)
+               hibernation_ops->finish();
+}
+
+/**
+ *     platform_pre_restore - prepare the platform for the restoration from a
+ *     hibernation image.  If the restore fails after this function has been
+ *     called, platform_restore_cleanup() must be called.
+ */
+
+static int platform_pre_restore(int platform_mode)
+{
+       return (platform_mode && hibernation_ops) ?
+               hibernation_ops->pre_restore() : 0;
+}
+
+/**
+ *     platform_restore_cleanup - switch the platform to the normal mode of
+ *     operation after a failing restore.  If platform_pre_restore() has been
+ *     called before the failing restore, this function must be called too,
+ *     regardless of the result of platform_pre_restore().
+ */
+
+static void platform_restore_cleanup(int platform_mode)
+{
+       if (platform_mode && hibernation_ops)
+               hibernation_ops->restore_cleanup();
+}
+
+/**
+ *     platform_recover - recover the platform from a failure to suspend
+ *     devices.
+ */
+
+static void platform_recover(int platform_mode)
+{
+       if (platform_mode && hibernation_ops && hibernation_ops->recover)
+               hibernation_ops->recover();
+}
+
+/**
+ *     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.
+ */
+
+static int create_image(int platform_mode)
+{
+       int error;
+
+       error = arch_prepare_suspend();
+       if (error)
+               return error;
+
+       /* At this point, dpm_suspend_start() has been called, but *not*
+        * dpm_suspend_noirq(). We *must* call dpm_suspend_noirq() now.
+        * Otherwise, drivers for some devices (e.g. interrupt controllers)
+        * become desynchronized with the actual state of the hardware
+        * at resume time, and evil weirdness ensues.
+        */
+       error = dpm_suspend_noirq(PMSG_FREEZE);
+       if (error) {
+               printk(KERN_ERR "PM: Some devices failed to power down, "
+                       "aborting hibernation\n");
+               return error;
+       }
+
+       error = platform_pre_snapshot(platform_mode);
+       if (error || hibernation_test(TEST_PLATFORM))
+               goto Platform_finish;
+
+       error = disable_nonboot_cpus();
+       if (error || hibernation_test(TEST_CPUS)
+           || hibernation_testmode(HIBERNATION_TEST))
+               goto Enable_cpus;
+
+       local_irq_disable();
+
+       error = sysdev_suspend(PMSG_FREEZE);
+       if (error) {
+               printk(KERN_ERR "PM: Some system devices failed to power down, "
+                       "aborting hibernation\n");
+               goto Enable_irqs;
+       }
+
+       if (hibernation_test(TEST_CORE))
+               goto Power_up;
+
+       in_suspend = 1;
+       save_processor_state();
+       error = swsusp_arch_suspend();
+       if (error)
+               printk(KERN_ERR "PM: Error %d creating hibernation image\n",
+                       error);
+       /* Restore control flow magically appears here */
+       restore_processor_state();
+       if (!in_suspend)
+               platform_leave(platform_mode);
+
+ Power_up:
+       sysdev_resume();
+       /* NOTE:  dpm_resume_noirq() is just a resume() for devices
+        * that suspended with irqs off ... no overall powerup.
+        */
+
+ Enable_irqs:
+       local_irq_enable();
+
+ Enable_cpus:
+       enable_nonboot_cpus();
+
+ Platform_finish:
+       platform_finish(platform_mode);
+
+       dpm_resume_noirq(in_suspend ?
+               (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
+
+       return error;
+}
+
+/**
+ *     hibernation_snapshot - quiesce devices and create the hibernation
+ *     snapshot image.
+ *     @platform_mode - if set, use the platform driver, if available, to
+ *                      prepare the platform firmware for the power transition.
+ *
+ *     Must be called with pm_mutex held
+ */
+
+int hibernation_snapshot(int platform_mode)
+{
+       int error;
+
+       error = platform_begin(platform_mode);
+       if (error)
+               return error;
+
+       /* Free memory before shutting down devices. */
+       error = swsusp_shrink_memory();
+       if (error)
+               goto Close;
+
+       suspend_console();
+       error = dpm_suspend_start(PMSG_FREEZE);
+       if (error)
+               goto Recover_platform;
+
+       if (hibernation_test(TEST_DEVICES))
+               goto Recover_platform;
+
+       error = create_image(platform_mode);
+       /* Control returns here after successful restore */
+
+ Resume_devices:
+       dpm_resume_end(in_suspend ?
+               (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
+       resume_console();
+ Close:
+       platform_end(platform_mode);
+       return error;
+
+ Recover_platform:
+       platform_recover(platform_mode);
+       goto Resume_devices;
+}
+
+/**
+ *     resume_target_kernel - prepare devices that need to be suspended with
+ *     interrupts off, restore the contents of highmem that have not been
+ *     restored yet from the image and run the low level code that will restore
+ *     the remaining contents of memory and switch to the just restored target
+ *     kernel.
+ */
+
+static int resume_target_kernel(bool platform_mode)
+{
+       int error;
+
+       error = dpm_suspend_noirq(PMSG_QUIESCE);
+       if (error) {
+               printk(KERN_ERR "PM: Some devices failed to power down, "
+                       "aborting resume\n");
+               return error;
+       }
+
+       error = platform_pre_restore(platform_mode);
+       if (error)
+               goto Cleanup;
+
+       error = disable_nonboot_cpus();
+       if (error)
+               goto Enable_cpus;
+
+       local_irq_disable();
+
+       error = sysdev_suspend(PMSG_QUIESCE);
+       if (error)
+               goto Enable_irqs;
+
+       /* We'll ignore saved state, but this gets preempt count (etc) right */
+       save_processor_state();
+       error = restore_highmem();
+       if (!error) {
+               error = swsusp_arch_resume();
+               /*
+                * The code below is only ever reached in case of a failure.
+                * Otherwise execution continues at place where
+                * swsusp_arch_suspend() was called
+                */
+               BUG_ON(!error);
+               /* This call to restore_highmem() undos the previous one */
+               restore_highmem();
+       }
+       /*
+        * The only reason why swsusp_arch_resume() can fail is memory being
+        * very tight, so we have to free it as soon as we can to avoid
+        * subsequent failures
+        */
+       swsusp_free();
+       restore_processor_state();
+       touch_softlockup_watchdog();
+
+       sysdev_resume();
+
+ Enable_irqs:
+       local_irq_enable();
+
+ Enable_cpus:
+       enable_nonboot_cpus();
+
+ Cleanup:
+       platform_restore_cleanup(platform_mode);
+
+       dpm_resume_noirq(PMSG_RECOVER);
+
+       return error;
+}
+
+/**
+ *     hibernation_restore - quiesce devices and restore the hibernation
+ *     snapshot image.  If successful, control returns in hibernation_snaphot()
+ *     @platform_mode - if set, use the platform driver, if available, to
+ *                      prepare the platform firmware for the transition.
+ *
+ *     Must be called with pm_mutex held
+ */
+
+int hibernation_restore(int platform_mode)
+{
+       int error;
+
+       pm_prepare_console();
+       suspend_console();
+       error = dpm_suspend_start(PMSG_QUIESCE);
+       if (!error) {
+               error = resume_target_kernel(platform_mode);
+               dpm_resume_end(PMSG_RECOVER);
+       }
+       resume_console();
+       pm_restore_console();
+       return error;
+}
+
+/**
+ *     hibernation_platform_enter - enter the hibernation state using the
+ *     platform driver (if available)
+ */
+
+int hibernation_platform_enter(void)
+{
+       int error;
+
+       if (!hibernation_ops)
+               return -ENOSYS;
+
+       /*
+        * We have cancelled the power transition by running
+        * hibernation_ops->finish() before saving the image, so we should let
+        * the firmware know that we're going to enter the sleep state after all
+        */
+       error = hibernation_ops->begin();
+       if (error)
+               goto Close;
+
+       entering_platform_hibernation = true;
+       suspend_console();
+       error = dpm_suspend_start(PMSG_HIBERNATE);
+       if (error) {
+               if (hibernation_ops->recover)
+                       hibernation_ops->recover();
+               goto Resume_devices;
+       }
+
+       error = dpm_suspend_noirq(PMSG_HIBERNATE);
+       if (error)
+               goto Resume_devices;
+
+       error = hibernation_ops->prepare();
+       if (error)
+               goto Platofrm_finish;
+
+       error = disable_nonboot_cpus();
+       if (error)
+               goto Platofrm_finish;
+
+       local_irq_disable();
+       sysdev_suspend(PMSG_HIBERNATE);
+       hibernation_ops->enter();
+       /* We should never get here */
+       while (1);
+
+       /*
+        * We don't need to reenable the nonboot CPUs or resume consoles, since
+        * the system is going to be halted anyway.
+        */
+ Platofrm_finish:
+       hibernation_ops->finish();
+
+       dpm_suspend_noirq(PMSG_RESTORE);
+
+ Resume_devices:
+       entering_platform_hibernation = false;
+       dpm_resume_end(PMSG_RESTORE);
+       resume_console();
+
+ Close:
+       hibernation_ops->end();
+
+       return error;
+}
+
+/**
+ *     power_down - Shut the machine down for hibernation.
+ *
+ *     Use the platform driver, if configured so; otherwise try
+ *     to power off or reboot.
+ */
+
+static void power_down(void)
+{
+       switch (hibernation_mode) {
+       case HIBERNATION_TEST:
+       case HIBERNATION_TESTPROC:
+               break;
+       case HIBERNATION_REBOOT:
+               kernel_restart(NULL);
+               break;
+       case HIBERNATION_PLATFORM:
+               hibernation_platform_enter();
+       case HIBERNATION_SHUTDOWN:
+               kernel_power_off();
+               break;
+       }
+       kernel_halt();
+       /*
+        * Valid image is on the disk, if we continue we risk serious data
+        * corruption after resume.
+        */
+       printk(KERN_CRIT "PM: Please power down manually\n");
+       while(1);
+}
+
+static int prepare_processes(void)
+{
+       int error = 0;
+
+       if (freeze_processes()) {
+               error = -EBUSY;
+               thaw_processes();
+       }
+       return error;
+}
+
+/**
+ *     hibernate - The granpappy of the built-in hibernation management
+ */
+
+int hibernate(void)
+{
+       int error;
+
+       mutex_lock(&pm_mutex);
+       /* The snapshot device should not be opened while we're running */
+       if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
+               error = -EBUSY;
+               goto Unlock;
+       }
+
+       pm_prepare_console();
+       error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
+       if (error)
+               goto Exit;
+
+       error = usermodehelper_disable();
+       if (error)
+               goto Exit;
+
+       /* Allocate memory management structures */
+       error = create_basic_memory_bitmaps();
+       if (error)
+               goto Exit;
+
+       printk(KERN_INFO "PM: Syncing filesystems ... ");
+       sys_sync();
+       printk("done.\n");
+
+       error = prepare_processes();
+       if (error)
+               goto Finish;
+
+       if (hibernation_test(TEST_FREEZER))
+               goto Thaw;
+
+       if (hibernation_testmode(HIBERNATION_TESTPROC))
+               goto Thaw;
+
+       error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);
+       if (in_suspend && !error) {
+               unsigned int flags = 0;
+
+               if (hibernation_mode == HIBERNATION_PLATFORM)
+                       flags |= SF_PLATFORM_MODE;
+               pr_debug("PM: writing image.\n");
+               error = swsusp_write(flags);
+               swsusp_free();
+               if (!error)
+                       power_down();
+       } else {
+               pr_debug("PM: Image restored successfully.\n");
+               swsusp_free();
+       }
+ Thaw:
+       thaw_processes();
+ Finish:
+       free_basic_memory_bitmaps();
+       usermodehelper_enable();
+ Exit:
+       pm_notifier_call_chain(PM_POST_HIBERNATION);
+       pm_restore_console();
+       atomic_inc(&snapshot_device_available);
+ Unlock:
+       mutex_unlock(&pm_mutex);
+       return error;
+}
+
+
+/**
+ *     software_resume - Resume from a saved image.
+ *
+ *     Called as a late_initcall (so all devices are discovered and
+ *     initialized), we call swsusp to see if we have a saved image or not.
+ *     If so, we quiesce devices, the restore the saved image. We will
+ *     return above (in hibernate() ) if everything goes well.
+ *     Otherwise, we fail gracefully and return to the normally
+ *     scheduled program.
+ *
+ */
+
+static int software_resume(void)
+{
+       int error;
+       unsigned int flags;
+
+       /*
+        * If the user said "noresume".. bail out early.
+        */
+       if (noresume)
+               return 0;
+
+       /*
+        * name_to_dev_t() below takes a sysfs buffer mutex when sysfs
+        * is configured into the kernel. Since the regular hibernate
+        * trigger path is via sysfs which takes a buffer mutex before
+        * calling hibernate functions (which take pm_mutex) this can
+        * cause lockdep to complain about a possible ABBA deadlock
+        * which cannot happen since we're in the boot code here and
+        * sysfs can't be invoked yet. Therefore, we use a subclass
+        * here to avoid lockdep complaining.
+        */
+       mutex_lock_nested(&pm_mutex, SINGLE_DEPTH_NESTING);
+
+       if (swsusp_resume_device)
+               goto Check_image;
+
+       if (!strlen(resume_file)) {
+               error = -ENOENT;
+               goto Unlock;
+       }
+
+       pr_debug("PM: Checking image partition %s\n", resume_file);
+
+       /* Check if the device is there */
+       swsusp_resume_device = name_to_dev_t(resume_file);
+       if (!swsusp_resume_device) {
+               /*
+                * Some device discovery might still be in progress; we need
+                * to wait for this to finish.
+                */
+               wait_for_device_probe();
+               /*
+                * We can't depend on SCSI devices being available after loading
+                * one of their modules until scsi_complete_async_scans() is
+                * called and the resume device usually is a SCSI one.
+                */
+               scsi_complete_async_scans();
+
+               swsusp_resume_device = name_to_dev_t(resume_file);
+               if (!swsusp_resume_device) {
+                       error = -ENODEV;
+                       goto Unlock;
+               }
+       }
+
+ Check_image:
+       pr_debug("PM: Resume from partition %d:%d\n",
+               MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device));
+
+       pr_debug("PM: Checking hibernation image.\n");
+       error = swsusp_check();
+       if (error)
+               goto Unlock;
+
+       /* The snapshot device should not be opened while we're running */
+       if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
+               error = -EBUSY;
+               goto Unlock;
+       }
+
+       pm_prepare_console();
+       error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
+       if (error)
+               goto Finish;
+
+       error = usermodehelper_disable();
+       if (error)
+               goto Finish;
+
+       error = create_basic_memory_bitmaps();
+       if (error)
+               goto Finish;
+
+       pr_debug("PM: Preparing processes for restore.\n");
+       error = prepare_processes();
+       if (error) {
+               swsusp_close(FMODE_READ);
+               goto Done;
+       }
+
+       pr_debug("PM: Reading hibernation image.\n");
+
+       error = swsusp_read(&flags);
+       if (!error)
+               hibernation_restore(flags & SF_PLATFORM_MODE);
+
+       printk(KERN_ERR "PM: Restore failed, recovering.\n");
+       swsusp_free();
+       thaw_processes();
+ Done:
+       free_basic_memory_bitmaps();
+       usermodehelper_enable();
+ Finish:
+       pm_notifier_call_chain(PM_POST_RESTORE);
+       pm_restore_console();
+       atomic_inc(&snapshot_device_available);
+       /* For success case, the suspend path will release the lock */
+ Unlock:
+       mutex_unlock(&pm_mutex);
+       pr_debug("PM: Resume from disk failed.\n");
+       return error;
+}
+
+late_initcall(software_resume);
+
+
+static const char * const hibernation_modes[] = {
+       [HIBERNATION_PLATFORM]  = "platform",
+       [HIBERNATION_SHUTDOWN]  = "shutdown",
+       [HIBERNATION_REBOOT]    = "reboot",
+       [HIBERNATION_TEST]      = "test",
+       [HIBERNATION_TESTPROC]  = "testproc",
+};
+
+/**
+ *     disk - Control hibernation mode
+ *
+ *     Suspend-to-disk can be handled in several ways. We have a few options
+ *     for putting the system to sleep - using the platform driver (e.g. ACPI
+ *     or other hibernation_ops), powering off the system or rebooting the
+ *     system (for testing) as well as the two test modes.
+ *
+ *     The system can support 'platform', and that is known a priori (and
+ *     encoded by the presence of hibernation_ops). However, the user may
+ *     choose 'shutdown' or 'reboot' as alternatives, as well as one fo the
+ *     test modes, 'test' or 'testproc'.
+ *
+ *     show() will display what the mode is currently set to.
+ *     store() will accept one of
+ *
+ *     'platform'
+ *     'shutdown'
+ *     'reboot'
+ *     'test'
+ *     'testproc'
+ *
+ *     It will only change to 'platform' if the system
+ *     supports it (as determined by having hibernation_ops).
+ */
+
+static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
+                        char *buf)
+{
+       int i;
+       char *start = buf;
+
+       for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
+               if (!hibernation_modes[i])
+                       continue;
+               switch (i) {
+               case HIBERNATION_SHUTDOWN:
+               case HIBERNATION_REBOOT:
+               case HIBERNATION_TEST:
+               case HIBERNATION_TESTPROC:
+                       break;
+               case HIBERNATION_PLATFORM:
+                       if (hibernation_ops)
+                               break;
+                       /* not a valid mode, continue with loop */
+                       continue;
+               }
+               if (i == hibernation_mode)
+                       buf += sprintf(buf, "[%s] ", hibernation_modes[i]);
+               else
+                       buf += sprintf(buf, "%s ", hibernation_modes[i]);
+       }
+       buf += sprintf(buf, "\n");
+       return buf-start;
+}
+
+
+static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
+                         const char *buf, size_t n)
+{
+       int error = 0;
+       int i;
+       int len;
+       char *p;
+       int mode = HIBERNATION_INVALID;
+
+       p = memchr(buf, '\n', n);
+       len = p ? p - buf : n;
+
+       mutex_lock(&pm_mutex);
+       for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
+               if (len == strlen(hibernation_modes[i])
+                   && !strncmp(buf, hibernation_modes[i], len)) {
+                       mode = i;
+                       break;
+               }
+       }
+       if (mode != HIBERNATION_INVALID) {
+               switch (mode) {
+               case HIBERNATION_SHUTDOWN:
+               case HIBERNATION_REBOOT:
+               case HIBERNATION_TEST:
+               case HIBERNATION_TESTPROC:
+                       hibernation_mode = mode;
+                       break;
+               case HIBERNATION_PLATFORM:
+                       if (hibernation_ops)
+                               hibernation_mode = mode;
+                       else
+                               error = -EINVAL;
+               }
+       } else
+               error = -EINVAL;
+
+       if (!error)
+               pr_debug("PM: Hibernation mode set to '%s'\n",
+                        hibernation_modes[mode]);
+       mutex_unlock(&pm_mutex);
+       return error ? error : n;
+}
+
+power_attr(disk);
+
+static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr,
+                          char *buf)
+{
+       return sprintf(buf,"%d:%d\n", MAJOR(swsusp_resume_device),
+                      MINOR(swsusp_resume_device));
+}
+
+static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr,
+                           const char *buf, size_t n)
+{
+       unsigned int maj, min;
+       dev_t res;
+       int ret = -EINVAL;
+
+       if (sscanf(buf, "%u:%u", &maj, &min) != 2)
+               goto out;
+
+       res = MKDEV(maj,min);
+       if (maj != MAJOR(res) || min != MINOR(res))
+               goto out;
+
+       mutex_lock(&pm_mutex);
+       swsusp_resume_device = res;
+       mutex_unlock(&pm_mutex);
+       printk(KERN_INFO "PM: Starting manual resume from disk\n");
+       noresume = 0;
+       software_resume();
+       ret = n;
+ out:
+       return ret;
+}
+
+power_attr(resume);
+
+static ssize_t image_size_show(struct kobject *kobj, struct kobj_attribute *attr,
+                              char *buf)
+{
+       return sprintf(buf, "%lu\n", image_size);
+}
+
+static ssize_t image_size_store(struct kobject *kobj, struct kobj_attribute *attr,
+                               const char *buf, size_t n)
+{
+       unsigned long size;
+
+       if (sscanf(buf, "%lu", &size) == 1) {
+               image_size = size;
+               return n;
+       }
+
+       return -EINVAL;
+}
+
+power_attr(image_size);
+
+static struct attribute * g[] = {
+       &disk_attr.attr,
+       &resume_attr.attr,
+       &image_size_attr.attr,
+       NULL,
+};
+
+
+static struct attribute_group attr_group = {
+       .attrs = g,
+};
+
+
+static int __init pm_disk_init(void)
+{
+       return sysfs_create_group(power_kobj, &attr_group);
+}
+
+core_initcall(pm_disk_init);
+
+
+static int __init resume_setup(char *str)
+{
+       if (noresume)
+               return 1;
+
+       strncpy( resume_file, str, 255 );
+       return 1;
+}
+
+static int __init resume_offset_setup(char *str)
+{
+       unsigned long long offset;
+
+       if (noresume)
+               return 1;
+
+       if (sscanf(str, "%llu", &offset) == 1)
+               swsusp_resume_block = offset;
+
+       return 1;
+}
+
+static int __init noresume_setup(char *str)
+{
+       noresume = 1;
+       return 1;
+}
+
+__setup("noresume", noresume_setup);
+__setup("resume_offset=", resume_offset_setup);
+__setup("resume=", resume_setup);
diff --git a/kernel/power/hibernate_nvs.c b/kernel/power/hibernate_nvs.c
new file mode 100644 (file)
index 0000000..39ac698
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * linux/kernel/power/hibernate_nvs.c - Routines for handling NVS memory
+ *
+ * Copyright (C) 2008,2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/suspend.h>
+
+/*
+ * Platforms, like ACPI, may want us to save some memory used by them during
+ * hibernation and to restore the contents of this memory during the subsequent
+ * resume.  The code below implements a mechanism allowing us to do that.
+ */
+
+struct nvs_page {
+       unsigned long phys_start;
+       unsigned int size;
+       void *kaddr;
+       void *data;
+       struct list_head node;
+};
+
+static LIST_HEAD(nvs_list);
+
+/**
+ *     hibernate_nvs_register - register platform NVS memory region to save
+ *     @start - physical address of the region
+ *     @size - size of the region
+ *
+ *     The NVS region need not be page-aligned (both ends) and we arrange
+ *     things so that the data from page-aligned addresses in this region will
+ *     be copied into separate RAM pages.
+ */
+int hibernate_nvs_register(unsigned long start, unsigned long size)
+{
+       struct nvs_page *entry, *next;
+
+       while (size > 0) {
+               unsigned int nr_bytes;
+
+               entry = kzalloc(sizeof(struct nvs_page), GFP_KERNEL);
+               if (!entry)
+                       goto Error;
+
+               list_add_tail(&entry->node, &nvs_list);
+               entry->phys_start = start;
+               nr_bytes = PAGE_SIZE - (start & ~PAGE_MASK);
+               entry->size = (size < nr_bytes) ? size : nr_bytes;
+
+               start += entry->size;
+               size -= entry->size;
+       }
+       return 0;
+
+ Error:
+       list_for_each_entry_safe(entry, next, &nvs_list, node) {
+               list_del(&entry->node);
+               kfree(entry);
+       }
+       return -ENOMEM;
+}
+
+/**
+ *     hibernate_nvs_free - free data pages allocated for saving NVS regions
+ */
+void hibernate_nvs_free(void)
+{
+       struct nvs_page *entry;
+
+       list_for_each_entry(entry, &nvs_list, node)
+               if (entry->data) {
+                       free_page((unsigned long)entry->data);
+                       entry->data = NULL;
+                       if (entry->kaddr) {
+                               iounmap(entry->kaddr);
+                               entry->kaddr = NULL;
+                       }
+               }
+}
+
+/**
+ *     hibernate_nvs_alloc - allocate memory necessary for saving NVS regions
+ */
+int hibernate_nvs_alloc(void)
+{
+       struct nvs_page *entry;
+
+       list_for_each_entry(entry, &nvs_list, node) {
+               entry->data = (void *)__get_free_page(GFP_KERNEL);
+               if (!entry->data) {
+                       hibernate_nvs_free();
+                       return -ENOMEM;
+               }
+       }
+       return 0;
+}
+
+/**
+ *     hibernate_nvs_save - save NVS memory regions
+ */
+void hibernate_nvs_save(void)
+{
+       struct nvs_page *entry;
+
+       printk(KERN_INFO "PM: Saving platform NVS memory\n");
+
+       list_for_each_entry(entry, &nvs_list, node)
+               if (entry->data) {
+                       entry->kaddr = ioremap(entry->phys_start, entry->size);
+                       memcpy(entry->data, entry->kaddr, entry->size);
+               }
+}
+
+/**
+ *     hibernate_nvs_restore - restore NVS memory regions
+ *
+ *     This function is going to be called with interrupts disabled, so it
+ *     cannot iounmap the virtual addresses used to access the NVS region.
+ */
+void hibernate_nvs_restore(void)
+{
+       struct nvs_page *entry;
+
+       printk(KERN_INFO "PM: Restoring platform NVS memory\n");
+
+       list_for_each_entry(entry, &nvs_list, node)
+               if (entry->data)
+                       memcpy(entry->kaddr, entry->data, entry->size);
+}
index 868028280d13474811810098cfa0f1923d212b32..f710e36930cc33ecceac7f5455de6d86fedbd718 100644 (file)
@@ -8,20 +8,9 @@
  *
  */
 
-#include <linux/module.h>
-#include <linux/suspend.h>
 #include <linux/kobject.h>
 #include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/kmod.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/cpu.h>
 #include <linux/resume-trace.h>
-#include <linux/freezer.h>
-#include <linux/vmstat.h>
-#include <linux/syscalls.h>
 
 #include "power.h"
 
@@ -119,373 +108,6 @@ power_attr(pm_test);
 
 #endif /* CONFIG_PM_SLEEP */
 
-#ifdef CONFIG_SUSPEND
-
-static int suspend_test(int level)
-{
-#ifdef CONFIG_PM_DEBUG
-       if (pm_test_level == level) {
-               printk(KERN_INFO "suspend debug: Waiting for 5 seconds.\n");
-               mdelay(5000);
-               return 1;
-       }
-#endif /* !CONFIG_PM_DEBUG */
-       return 0;
-}
-
-#ifdef CONFIG_PM_TEST_SUSPEND
-
-/*
- * We test the system suspend code by setting an RTC wakealarm a short
- * time in the future, then suspending.  Suspending the devices won't
- * normally take long ... some systems only need a few milliseconds.
- *
- * The time it takes is system-specific though, so when we test this
- * during system bootup we allow a LOT of time.
- */
-#define TEST_SUSPEND_SECONDS   5
-
-static unsigned long suspend_test_start_time;
-
-static void suspend_test_start(void)
-{
-       /* FIXME Use better timebase than "jiffies", ideally a clocksource.
-        * What we want is a hardware counter that will work correctly even
-        * during the irqs-are-off stages of the suspend/resume cycle...
-        */
-       suspend_test_start_time = jiffies;
-}
-
-static void suspend_test_finish(const char *label)
-{
-       long nj = jiffies - suspend_test_start_time;
-       unsigned msec;
-
-       msec = jiffies_to_msecs(abs(nj));
-       pr_info("PM: %s took %d.%03d seconds\n", label,
-                       msec / 1000, msec % 1000);
-
-       /* Warning on suspend means the RTC alarm period needs to be
-        * larger -- the system was sooo slooowwww to suspend that the
-        * alarm (should have) fired before the system went to sleep!
-        *
-        * Warning on either suspend or resume also means the system
-        * has some performance issues.  The stack dump of a WARN_ON
-        * is more likely to get the right attention than a printk...
-        */
-       WARN(msec > (TEST_SUSPEND_SECONDS * 1000), "Component: %s\n", label);
-}
-
-#else
-
-static void suspend_test_start(void)
-{
-}
-
-static void suspend_test_finish(const char *label)
-{
-}
-
-#endif
-
-/* This is just an arbitrary number */
-#define FREE_PAGE_NUMBER (100)
-
-static struct platform_suspend_ops *suspend_ops;
-
-/**
- *     suspend_set_ops - Set the global suspend method table.
- *     @ops:   Pointer to ops structure.
- */
-
-void suspend_set_ops(struct platform_suspend_ops *ops)
-{
-       mutex_lock(&pm_mutex);
-       suspend_ops = ops;
-       mutex_unlock(&pm_mutex);
-}
-
-/**
- * suspend_valid_only_mem - generic memory-only valid callback
- *
- * Platform drivers that implement mem suspend only and only need
- * to check for that in their .valid callback can use this instead
- * of rolling their own .valid callback.
- */
-int suspend_valid_only_mem(suspend_state_t state)
-{
-       return state == PM_SUSPEND_MEM;
-}
-
-/**
- *     suspend_prepare - Do prep work before entering low-power state.
- *
- *     This is common code that is called for each state that we're entering.
- *     Run suspend notifiers, allocate a console and stop all processes.
- */
-static int suspend_prepare(void)
-{
-       int error;
-       unsigned int free_pages;
-
-       if (!suspend_ops || !suspend_ops->enter)
-               return -EPERM;
-
-       pm_prepare_console();
-
-       error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
-       if (error)
-               goto Finish;
-
-       error = usermodehelper_disable();
-       if (error)
-               goto Finish;
-
-       if (suspend_freeze_processes()) {
-               error = -EAGAIN;
-               goto Thaw;
-       }
-
-       free_pages = global_page_state(NR_FREE_PAGES);
-       if (free_pages < FREE_PAGE_NUMBER) {
-               pr_debug("PM: free some memory\n");
-               shrink_all_memory(FREE_PAGE_NUMBER - free_pages);
-               if (nr_free_pages() < FREE_PAGE_NUMBER) {
-                       error = -ENOMEM;
-                       printk(KERN_ERR "PM: No enough memory\n");
-               }
-       }
-       if (!error)
-               return 0;
-
- Thaw:
-       suspend_thaw_processes();
-       usermodehelper_enable();
- Finish:
-       pm_notifier_call_chain(PM_POST_SUSPEND);
-       pm_restore_console();
-       return error;
-}
-
-/* default implementation */
-void __attribute__ ((weak)) arch_suspend_disable_irqs(void)
-{
-       local_irq_disable();
-}
-
-/* default implementation */
-void __attribute__ ((weak)) arch_suspend_enable_irqs(void)
-{
-       local_irq_enable();
-}
-
-/**
- *     suspend_enter - enter the desired system sleep state.
- *     @state:         state to enter
- *
- *     This function should be called after devices have been suspended.
- */
-static int suspend_enter(suspend_state_t state)
-{
-       int error;
-
-       if (suspend_ops->prepare) {
-               error = suspend_ops->prepare();
-               if (error)
-                       return error;
-       }
-
-       error = device_power_down(PMSG_SUSPEND);
-       if (error) {
-               printk(KERN_ERR "PM: Some devices failed to power down\n");
-               goto Platfrom_finish;
-       }
-
-       if (suspend_ops->prepare_late) {
-               error = suspend_ops->prepare_late();
-               if (error)
-                       goto Power_up_devices;
-       }
-
-       if (suspend_test(TEST_PLATFORM))
-               goto Platform_wake;
-
-       error = disable_nonboot_cpus();
-       if (error || suspend_test(TEST_CPUS))
-               goto Enable_cpus;
-
-       arch_suspend_disable_irqs();
-       BUG_ON(!irqs_disabled());
-
-       error = sysdev_suspend(PMSG_SUSPEND);
-       if (!error) {
-               if (!suspend_test(TEST_CORE))
-                       error = suspend_ops->enter(state);
-               sysdev_resume();
-       }
-
-       arch_suspend_enable_irqs();
-       BUG_ON(irqs_disabled());
-
- Enable_cpus:
-       enable_nonboot_cpus();
-
- Platform_wake:
-       if (suspend_ops->wake)
-               suspend_ops->wake();
-
- Power_up_devices:
-       device_power_up(PMSG_RESUME);
-
- Platfrom_finish:
-       if (suspend_ops->finish)
-               suspend_ops->finish();
-
-       return error;
-}
-
-/**
- *     suspend_devices_and_enter - suspend devices and enter the desired system
- *                                 sleep state.
- *     @state:           state to enter
- */
-int suspend_devices_and_enter(suspend_state_t state)
-{
-       int error;
-
-       if (!suspend_ops)
-               return -ENOSYS;
-
-       if (suspend_ops->begin) {
-               error = suspend_ops->begin(state);
-               if (error)
-                       goto Close;
-       }
-       suspend_console();
-       suspend_test_start();
-       error = device_suspend(PMSG_SUSPEND);
-       if (error) {
-               printk(KERN_ERR "PM: Some devices failed to suspend\n");
-               goto Recover_platform;
-       }
-       suspend_test_finish("suspend devices");
-       if (suspend_test(TEST_DEVICES))
-               goto Recover_platform;
-
-       suspend_enter(state);
-
- Resume_devices:
-       suspend_test_start();
-       device_resume(PMSG_RESUME);
-       suspend_test_finish("resume devices");
-       resume_console();
- Close:
-       if (suspend_ops->end)
-               suspend_ops->end();
-       return error;
-
- Recover_platform:
-       if (suspend_ops->recover)
-               suspend_ops->recover();
-       goto Resume_devices;
-}
-
-/**
- *     suspend_finish - Do final work before exiting suspend sequence.
- *
- *     Call platform code to clean up, restart processes, and free the 
- *     console that we've allocated. This is not called for suspend-to-disk.
- */
-static void suspend_finish(void)
-{
-       suspend_thaw_processes();
-       usermodehelper_enable();
-       pm_notifier_call_chain(PM_POST_SUSPEND);
-       pm_restore_console();
-}
-
-
-
-
-static const char * const pm_states[PM_SUSPEND_MAX] = {
-       [PM_SUSPEND_STANDBY]    = "standby",
-       [PM_SUSPEND_MEM]        = "mem",
-};
-
-static inline int valid_state(suspend_state_t state)
-{
-       /* All states need lowlevel support and need to be valid
-        * to the lowlevel implementation, no valid callback
-        * implies that none are valid. */
-       if (!suspend_ops || !suspend_ops->valid || !suspend_ops->valid(state))
-               return 0;
-       return 1;
-}
-
-
-/**
- *     enter_state - Do common work of entering low-power state.
- *     @state:         pm_state structure for state we're entering.
- *
- *     Make sure we're the only ones trying to enter a sleep state. Fail
- *     if someone has beat us to it, since we don't want anything weird to
- *     happen when we wake up.
- *     Then, do the setup for suspend, enter the state, and cleaup (after
- *     we've woken up).
- */
-static int enter_state(suspend_state_t state)
-{
-       int error;
-
-       if (!valid_state(state))
-               return -ENODEV;
-
-       if (!mutex_trylock(&pm_mutex))
-               return -EBUSY;
-
-       printk(KERN_INFO "PM: Syncing filesystems ... ");
-       sys_sync();
-       printk("done.\n");
-
-       pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
-       error = suspend_prepare();
-       if (error)
-               goto Unlock;
-
-       if (suspend_test(TEST_FREEZER))
-               goto Finish;
-
-       pr_debug("PM: Entering %s sleep\n", pm_states[state]);
-       error = suspend_devices_and_enter(state);
-
- Finish:
-       pr_debug("PM: Finishing wakeup.\n");
-       suspend_finish();
- Unlock:
-       mutex_unlock(&pm_mutex);
-       return error;
-}
-
-
-/**
- *     pm_suspend - Externally visible function for suspending system.
- *     @state:         Enumerated value of state to enter.
- *
- *     Determine whether or not value is within range, get state 
- *     structure, and enter (above).
- */
-
-int pm_suspend(suspend_state_t state)
-{
-       if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX)
-               return enter_state(state);
-       return -EINVAL;
-}
-
-EXPORT_SYMBOL(pm_suspend);
-
-#endif /* CONFIG_SUSPEND */
-
 struct kobject *power_kobj;
 
 /**
@@ -498,7 +120,6 @@ struct kobject *power_kobj;
  *     store() accepts one of those strings, translates it into the 
  *     proper enumerated value, and initiates a suspend transition.
  */
-
 static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
                          char *buf)
 {
@@ -596,7 +217,6 @@ static struct attribute_group attr_group = {
        .attrs = g,
 };
 
-
 static int __init pm_init(void)
 {
        power_kobj = kobject_create_and_add("power", NULL);
@@ -606,144 +226,3 @@ static int __init pm_init(void)
 }
 
 core_initcall(pm_init);
-
-
-#ifdef CONFIG_PM_TEST_SUSPEND
-
-#include <linux/rtc.h>
-
-/*
- * To test system suspend, we need a hands-off mechanism to resume the
- * system.  RTCs wake alarms are a common self-contained mechanism.
- */
-
-static void __init test_wakealarm(struct rtc_device *rtc, suspend_state_t state)
-{
-       static char err_readtime[] __initdata =
-               KERN_ERR "PM: can't read %s time, err %d\n";
-       static char err_wakealarm [] __initdata =
-               KERN_ERR "PM: can't set %s wakealarm, err %d\n";
-       static char err_suspend[] __initdata =
-               KERN_ERR "PM: suspend test failed, error %d\n";
-       static char info_test[] __initdata =
-               KERN_INFO "PM: test RTC wakeup from '%s' suspend\n";
-
-       unsigned long           now;
-       struct rtc_wkalrm       alm;
-       int                     status;
-
-       /* this may fail if the RTC hasn't been initialized */
-       status = rtc_read_time(rtc, &alm.time);
-       if (status < 0) {
-               printk(err_readtime, dev_name(&rtc->dev), status);
-               return;
-       }
-       rtc_tm_to_time(&alm.time, &now);
-
-       memset(&alm, 0, sizeof alm);
-       rtc_time_to_tm(now + TEST_SUSPEND_SECONDS, &alm.time);
-       alm.enabled = true;
-
-       status = rtc_set_alarm(rtc, &alm);
-       if (status < 0) {
-               printk(err_wakealarm, dev_name(&rtc->dev), status);
-               return;
-       }
-
-       if (state == PM_SUSPEND_MEM) {
-               printk(info_test, pm_states[state]);
-               status = pm_suspend(state);
-               if (status == -ENODEV)
-                       state = PM_SUSPEND_STANDBY;
-       }
-       if (state == PM_SUSPEND_STANDBY) {
-               printk(info_test, pm_states[state]);
-               status = pm_suspend(state);
-       }
-       if (status < 0)
-               printk(err_suspend, status);
-
-       /* Some platforms can't detect that the alarm triggered the
-        * wakeup, or (accordingly) disable it after it afterwards.
-        * It's supposed to give oneshot behavior; cope.
-        */
-       alm.enabled = false;
-       rtc_set_alarm(rtc, &alm);
-}
-
-static int __init has_wakealarm(struct device *dev, void *name_ptr)
-{
-       struct rtc_device *candidate = to_rtc_device(dev);
-
-       if (!candidate->ops->set_alarm)
-               return 0;
-       if (!device_may_wakeup(candidate->dev.parent))
-               return 0;
-
-       *(const char **)name_ptr = dev_name(dev);
-       return 1;
-}
-
-/*
- * Kernel options like "test_suspend=mem" force suspend/resume sanity tests
- * at startup time.  They're normally disabled, for faster boot and because
- * we can't know which states really work on this particular system.
- */
-static suspend_state_t test_state __initdata = PM_SUSPEND_ON;
-
-static char warn_bad_state[] __initdata =
-       KERN_WARNING "PM: can't test '%s' suspend state\n";
-
-static int __init setup_test_suspend(char *value)
-{
-       unsigned i;
-
-       /* "=mem" ==> "mem" */
-       value++;
-       for (i = 0; i < PM_SUSPEND_MAX; i++) {
-               if (!pm_states[i])
-                       continue;
-               if (strcmp(pm_states[i], value) != 0)
-                       continue;
-               test_state = (__force suspend_state_t) i;
-               return 0;
-       }
-       printk(warn_bad_state, value);
-       return 0;
-}
-__setup("test_suspend", setup_test_suspend);
-
-static int __init test_suspend(void)
-{
-       static char             warn_no_rtc[] __initdata =
-               KERN_WARNING "PM: no wakealarm-capable RTC driver is ready\n";
-
-       char                    *pony = NULL;
-       struct rtc_device       *rtc = NULL;
-
-       /* PM is initialized by now; is that state testable? */
-       if (test_state == PM_SUSPEND_ON)
-               goto done;
-       if (!valid_state(test_state)) {
-               printk(warn_bad_state, pm_states[test_state]);
-               goto done;
-       }
-
-       /* RTCs have initialized by now too ... can we use one? */
-       class_find_device(rtc_class, NULL, &pony, has_wakealarm);
-       if (pony)
-               rtc = rtc_class_open(pony);
-       if (!rtc) {
-               printk(warn_no_rtc);
-               goto done;
-       }
-
-       /* go for it */
-       test_wakealarm(rtc, test_state);
-       rtc_class_close(rtc);
-done:
-       return 0;
-}
-late_initcall(test_suspend);
-
-#endif /* CONFIG_PM_TEST_SUSPEND */
index 46b5ec7a3afb243050d04816990780966bab69bc..26d5a26f82e35fe722f5d895e2814f4341ca1ea4 100644 (file)
@@ -45,7 +45,7 @@ static inline char *check_image_kernel(struct swsusp_info *info)
  */
 #define SPARE_PAGES    ((1024 * 1024) >> PAGE_SHIFT)
 
-/* kernel/power/disk.c */
+/* kernel/power/hibernate.c */
 extern int hibernation_snapshot(int platform_mode);
 extern int hibernation_restore(int platform_mode);
 extern int hibernation_platform_enter(void);
@@ -74,7 +74,7 @@ extern asmlinkage int swsusp_arch_resume(void);
 
 extern int create_basic_memory_bitmaps(void);
 extern void free_basic_memory_bitmaps(void);
-extern unsigned int count_data_pages(void);
+extern int swsusp_shrink_memory(void);
 
 /**
  *     Auxiliary structure used for reading the snapshot image data and
@@ -147,9 +147,8 @@ extern int swsusp_swap_in_use(void);
  */
 #define SF_PLATFORM_MODE       1
 
-/* kernel/power/disk.c */
+/* kernel/power/hibernate.c */
 extern int swsusp_check(void);
-extern int swsusp_shrink_memory(void);
 extern void swsusp_free(void);
 extern int swsusp_read(unsigned int *flags_p);
 extern int swsusp_write(unsigned int flags);
@@ -161,22 +160,36 @@ extern void swsusp_show_speed(struct timeval *, struct timeval *,
                                unsigned int, char *);
 
 #ifdef CONFIG_SUSPEND
-/* kernel/power/main.c */
+/* kernel/power/suspend.c */
+extern const char *const pm_states[];
+
+extern bool valid_state(suspend_state_t state);
 extern int suspend_devices_and_enter(suspend_state_t state);
+extern int enter_state(suspend_state_t state);
 #else /* !CONFIG_SUSPEND */
 static inline int suspend_devices_and_enter(suspend_state_t state)
 {
        return -ENOSYS;
 }
+static inline int enter_state(suspend_state_t state) { return -ENOSYS; }
+static inline bool valid_state(suspend_state_t state) { return false; }
 #endif /* !CONFIG_SUSPEND */
 
+#ifdef CONFIG_PM_TEST_SUSPEND
+/* kernel/power/suspend_test.c */
+extern void suspend_test_start(void);
+extern void suspend_test_finish(const char *label);
+#else /* !CONFIG_PM_TEST_SUSPEND */
+static inline void suspend_test_start(void) {}
+static inline void suspend_test_finish(const char *label) {}
+#endif /* !CONFIG_PM_TEST_SUSPEND */
+
 #ifdef CONFIG_PM_SLEEP
 /* kernel/power/main.c */
 extern int pm_notifier_call_chain(unsigned long val);
 #endif
 
 #ifdef CONFIG_HIGHMEM
-unsigned int count_highmem_pages(void);
 int restore_highmem(void);
 #else
 static inline unsigned int count_highmem_pages(void) { return 0; }
index 97890831e1b5b63f5e1e50d5d4c6014bf4b67257..e8b337006276e71e782876db74cb94a4bbcb41a8 100644 (file)
@@ -34,7 +34,7 @@ static struct sysrq_key_op    sysrq_poweroff_op = {
        .handler        = handle_poweroff,
        .help_msg       = "powerOff",
        .action_msg     = "Power Off",
-       .enable_mask    = SYSRQ_ENABLE_BOOT,
+       .enable_mask    = SYSRQ_ENABLE_BOOT,
 };
 
 static int pm_sysrq_init(void)
index 33e2e4a819f97014a6e70e5f06d52e246ba783b3..523a451b45d37404f3ca1c8e0b59d9c31f45b49a 100644 (file)
@@ -39,6 +39,14 @@ static int swsusp_page_is_free(struct page *);
 static void swsusp_set_page_forbidden(struct page *);
 static void swsusp_unset_page_forbidden(struct page *);
 
+/*
+ * Preferred image size in bytes (tunable via /sys/power/image_size).
+ * When it is set to N, swsusp will do its best to ensure the image
+ * size will not exceed N bytes, but if that is impossible, it will
+ * try to create the smallest image possible.
+ */
+unsigned long image_size = 500 * 1024 * 1024;
+
 /* List of PBEs needed for restoring the pages that were allocated before
  * the suspend and included in the suspend image, but have also been
  * allocated by the "resume" kernel, so their contents cannot be written
@@ -840,7 +848,7 @@ static struct page *saveable_highmem_page(struct zone *zone, unsigned long pfn)
  *     pages.
  */
 
-unsigned int count_highmem_pages(void)
+static unsigned int count_highmem_pages(void)
 {
        struct zone *zone;
        unsigned int n = 0;
@@ -902,7 +910,7 @@ static struct page *saveable_page(struct zone *zone, unsigned long pfn)
  *     pages.
  */
 
-unsigned int count_data_pages(void)
+static unsigned int count_data_pages(void)
 {
        struct zone *zone;
        unsigned long pfn, max_zone_pfn;
@@ -1058,6 +1066,74 @@ void swsusp_free(void)
        buffer = NULL;
 }
 
+/**
+ *     swsusp_shrink_memory -  Try to free as much memory as needed
+ *
+ *     ... but do not OOM-kill anyone
+ *
+ *     Notice: all userland should be stopped before it is called, or
+ *     livelock is possible.
+ */
+
+#define SHRINK_BITE    10000
+static inline unsigned long __shrink_memory(long tmp)
+{
+       if (tmp > SHRINK_BITE)
+               tmp = SHRINK_BITE;
+       return shrink_all_memory(tmp);
+}
+
+int swsusp_shrink_memory(void)
+{
+       long tmp;
+       struct zone *zone;
+       unsigned long pages = 0;
+       unsigned int i = 0;
+       char *p = "-\\|/";
+       struct timeval start, stop;
+
+       printk(KERN_INFO "PM: Shrinking memory...  ");
+       do_gettimeofday(&start);
+       do {
+               long size, highmem_size;
+
+               highmem_size = count_highmem_pages();
+               size = count_data_pages() + PAGES_FOR_IO + SPARE_PAGES;
+               tmp = size;
+               size += highmem_size;
+               for_each_populated_zone(zone) {
+                       tmp += snapshot_additional_pages(zone);
+                       if (is_highmem(zone)) {
+                               highmem_size -=
+                                       zone_page_state(zone, NR_FREE_PAGES);
+                       } else {
+                               tmp -= zone_page_state(zone, NR_FREE_PAGES);
+                               tmp += zone->lowmem_reserve[ZONE_NORMAL];
+                       }
+               }
+
+               if (highmem_size < 0)
+                       highmem_size = 0;
+
+               tmp += highmem_size;
+               if (tmp > 0) {
+                       tmp = __shrink_memory(tmp);
+                       if (!tmp)
+                               return -ENOMEM;
+                       pages += tmp;
+               } else if (size > image_size / PAGE_SIZE) {
+                       tmp = __shrink_memory(size - (image_size / PAGE_SIZE));
+                       pages += tmp;
+               }
+               printk("\b%c", p[i++%4]);
+       } while (tmp > 0);
+       do_gettimeofday(&stop);
+       printk("\bdone (%lu pages freed)\n", pages);
+       swsusp_show_speed(&start, &stop, pages, "Freed");
+
+       return 0;
+}
+
 #ifdef CONFIG_HIGHMEM
 /**
   *    count_pages_for_highmem - compute the number of non-highmem pages
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
new file mode 100644 (file)
index 0000000..6f10dfc
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * kernel/power/suspend.c - Suspend to RAM and standby functionality.
+ *
+ * Copyright (c) 2003 Patrick Mochel
+ * Copyright (c) 2003 Open Source Development Lab
+ * Copyright (c) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/cpu.h>
+#include <linux/syscalls.h>
+
+#include "power.h"
+
+const char *const pm_states[PM_SUSPEND_MAX] = {
+       [PM_SUSPEND_STANDBY]    = "standby",
+       [PM_SUSPEND_MEM]        = "mem",
+};
+
+static struct platform_suspend_ops *suspend_ops;
+
+/**
+ *     suspend_set_ops - Set the global suspend method table.
+ *     @ops:   Pointer to ops structure.
+ */
+void suspend_set_ops(struct platform_suspend_ops *ops)
+{
+       mutex_lock(&pm_mutex);
+       suspend_ops = ops;
+       mutex_unlock(&pm_mutex);
+}
+
+bool valid_state(suspend_state_t state)
+{
+       /*
+        * All states need lowlevel support and need to be valid to the lowlevel
+        * implementation, no valid callback implies that none are valid.
+        */
+       return suspend_ops && suspend_ops->valid && suspend_ops->valid(state);
+}
+
+/**
+ * suspend_valid_only_mem - generic memory-only valid callback
+ *
+ * Platform drivers that implement mem suspend only and only need
+ * to check for that in their .valid callback can use this instead
+ * of rolling their own .valid callback.
+ */
+int suspend_valid_only_mem(suspend_state_t state)
+{
+       return state == PM_SUSPEND_MEM;
+}
+
+static int suspend_test(int level)
+{
+#ifdef CONFIG_PM_DEBUG
+       if (pm_test_level == level) {
+               printk(KERN_INFO "suspend debug: Waiting for 5 seconds.\n");
+               mdelay(5000);
+               return 1;
+       }
+#endif /* !CONFIG_PM_DEBUG */
+       return 0;
+}
+
+/**
+ *     suspend_prepare - Do prep work before entering low-power state.
+ *
+ *     This is common code that is called for each state that we're entering.
+ *     Run suspend notifiers, allocate a console and stop all processes.
+ */
+static int suspend_prepare(void)
+{
+       int error;
+
+       if (!suspend_ops || !suspend_ops->enter)
+               return -EPERM;
+
+       pm_prepare_console();
+
+       error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
+       if (error)
+               goto Finish;
+
+       error = usermodehelper_disable();
+       if (error)
+               goto Finish;
+
+       error = suspend_freeze_processes();
+       if (!error)
+               return 0;
+
+       suspend_thaw_processes();
+       usermodehelper_enable();
+ Finish:
+       pm_notifier_call_chain(PM_POST_SUSPEND);
+       pm_restore_console();
+       return error;
+}
+
+/* default implementation */
+void __attribute__ ((weak)) arch_suspend_disable_irqs(void)
+{
+       local_irq_disable();
+}
+
+/* default implementation */
+void __attribute__ ((weak)) arch_suspend_enable_irqs(void)
+{
+       local_irq_enable();
+}
+
+/**
+ *     suspend_enter - enter the desired system sleep state.
+ *     @state:         state to enter
+ *
+ *     This function should be called after devices have been suspended.
+ */
+static int suspend_enter(suspend_state_t state)
+{
+       int error;
+
+       if (suspend_ops->prepare) {
+               error = suspend_ops->prepare();
+               if (error)
+                       return error;
+       }
+
+       error = dpm_suspend_noirq(PMSG_SUSPEND);
+       if (error) {
+               printk(KERN_ERR "PM: Some devices failed to power down\n");
+               goto Platfrom_finish;
+       }
+
+       if (suspend_ops->prepare_late) {
+               error = suspend_ops->prepare_late();
+               if (error)
+                       goto Power_up_devices;
+       }
+
+       if (suspend_test(TEST_PLATFORM))
+               goto Platform_wake;
+
+       error = disable_nonboot_cpus();
+       if (error || suspend_test(TEST_CPUS))
+               goto Enable_cpus;
+
+       arch_suspend_disable_irqs();
+       BUG_ON(!irqs_disabled());
+
+       error = sysdev_suspend(PMSG_SUSPEND);
+       if (!error) {
+               if (!suspend_test(TEST_CORE))
+                       error = suspend_ops->enter(state);
+               sysdev_resume();
+       }
+
+       arch_suspend_enable_irqs();
+       BUG_ON(irqs_disabled());
+
+ Enable_cpus:
+       enable_nonboot_cpus();
+
+ Platform_wake:
+       if (suspend_ops->wake)
+               suspend_ops->wake();
+
+ Power_up_devices:
+       dpm_resume_noirq(PMSG_RESUME);
+
+ Platfrom_finish:
+       if (suspend_ops->finish)
+               suspend_ops->finish();
+
+       return error;
+}
+
+/**
+ *     suspend_devices_and_enter - suspend devices and enter the desired system
+ *                                 sleep state.
+ *     @state:           state to enter
+ */
+int suspend_devices_and_enter(suspend_state_t state)
+{
+       int error;
+
+       if (!suspend_ops)
+               return -ENOSYS;
+
+       if (suspend_ops->begin) {
+               error = suspend_ops->begin(state);
+               if (error)
+                       goto Close;
+       }
+       suspend_console();
+       suspend_test_start();
+       error = dpm_suspend_start(PMSG_SUSPEND);
+       if (error) {
+               printk(KERN_ERR "PM: Some devices failed to suspend\n");
+               goto Recover_platform;
+       }
+       suspend_test_finish("suspend devices");
+       if (suspend_test(TEST_DEVICES))
+               goto Recover_platform;
+
+       suspend_enter(state);
+
+ Resume_devices:
+       suspend_test_start();
+       dpm_resume_end(PMSG_RESUME);
+       suspend_test_finish("resume devices");
+       resume_console();
+ Close:
+       if (suspend_ops->end)
+               suspend_ops->end();
+       return error;
+
+ Recover_platform:
+       if (suspend_ops->recover)
+               suspend_ops->recover();
+       goto Resume_devices;
+}
+
+/**
+ *     suspend_finish - Do final work before exiting suspend sequence.
+ *
+ *     Call platform code to clean up, restart processes, and free the
+ *     console that we've allocated. This is not called for suspend-to-disk.
+ */
+static void suspend_finish(void)
+{
+       suspend_thaw_processes();
+       usermodehelper_enable();
+       pm_notifier_call_chain(PM_POST_SUSPEND);
+       pm_restore_console();
+}
+
+/**
+ *     enter_state - Do common work of entering low-power state.
+ *     @state:         pm_state structure for state we're entering.
+ *
+ *     Make sure we're the only ones trying to enter a sleep state. Fail
+ *     if someone has beat us to it, since we don't want anything weird to
+ *     happen when we wake up.
+ *     Then, do the setup for suspend, enter the state, and cleaup (after
+ *     we've woken up).
+ */
+int enter_state(suspend_state_t state)
+{
+       int error;
+
+       if (!valid_state(state))
+               return -ENODEV;
+
+       if (!mutex_trylock(&pm_mutex))
+               return -EBUSY;
+
+       printk(KERN_INFO "PM: Syncing filesystems ... ");
+       sys_sync();
+       printk("done.\n");
+
+       pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
+       error = suspend_prepare();
+       if (error)
+               goto Unlock;
+
+       if (suspend_test(TEST_FREEZER))
+               goto Finish;
+
+       pr_debug("PM: Entering %s sleep\n", pm_states[state]);
+       error = suspend_devices_and_enter(state);
+
+ Finish:
+       pr_debug("PM: Finishing wakeup.\n");
+       suspend_finish();
+ Unlock:
+       mutex_unlock(&pm_mutex);
+       return error;
+}
+
+/**
+ *     pm_suspend - Externally visible function for suspending system.
+ *     @state:         Enumerated value of state to enter.
+ *
+ *     Determine whether or not value is within range, get state
+ *     structure, and enter (above).
+ */
+int pm_suspend(suspend_state_t state)
+{
+       if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX)
+               return enter_state(state);
+       return -EINVAL;
+}
+EXPORT_SYMBOL(pm_suspend);
diff --git a/kernel/power/suspend_test.c b/kernel/power/suspend_test.c
new file mode 100644 (file)
index 0000000..17d8bb1
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * kernel/power/suspend_test.c - Suspend to RAM and standby test facility.
+ *
+ * Copyright (c) 2009 Pavel Machek <pavel@ucw.cz>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/init.h>
+#include <linux/rtc.h>
+
+#include "power.h"
+
+/*
+ * We test the system suspend code by setting an RTC wakealarm a short
+ * time in the future, then suspending.  Suspending the devices won't
+ * normally take long ... some systems only need a few milliseconds.
+ *
+ * The time it takes is system-specific though, so when we test this
+ * during system bootup we allow a LOT of time.
+ */
+#define TEST_SUSPEND_SECONDS   5
+
+static unsigned long suspend_test_start_time;
+
+void suspend_test_start(void)
+{
+       /* FIXME Use better timebase than "jiffies", ideally a clocksource.
+        * What we want is a hardware counter that will work correctly even
+        * during the irqs-are-off stages of the suspend/resume cycle...
+        */
+       suspend_test_start_time = jiffies;
+}
+
+void suspend_test_finish(const char *label)
+{
+       long nj = jiffies - suspend_test_start_time;
+       unsigned msec;
+
+       msec = jiffies_to_msecs(abs(nj));
+       pr_info("PM: %s took %d.%03d seconds\n", label,
+                       msec / 1000, msec % 1000);
+
+       /* Warning on suspend means the RTC alarm period needs to be
+        * larger -- the system was sooo slooowwww to suspend that the
+        * alarm (should have) fired before the system went to sleep!
+        *
+        * Warning on either suspend or resume also means the system
+        * has some performance issues.  The stack dump of a WARN_ON
+        * is more likely to get the right attention than a printk...
+        */
+       WARN(msec > (TEST_SUSPEND_SECONDS * 1000), "Component: %s\n", label);
+}
+
+/*
+ * To test system suspend, we need a hands-off mechanism to resume the
+ * system.  RTCs wake alarms are a common self-contained mechanism.
+ */
+
+static void __init test_wakealarm(struct rtc_device *rtc, suspend_state_t state)
+{
+       static char err_readtime[] __initdata =
+               KERN_ERR "PM: can't read %s time, err %d\n";
+       static char err_wakealarm [] __initdata =
+               KERN_ERR "PM: can't set %s wakealarm, err %d\n";
+       static char err_suspend[] __initdata =
+               KERN_ERR "PM: suspend test failed, error %d\n";
+       static char info_test[] __initdata =
+               KERN_INFO "PM: test RTC wakeup from '%s' suspend\n";
+
+       unsigned long           now;
+       struct rtc_wkalrm       alm;
+       int                     status;
+
+       /* this may fail if the RTC hasn't been initialized */
+       status = rtc_read_time(rtc, &alm.time);
+       if (status < 0) {
+               printk(err_readtime, dev_name(&rtc->dev), status);
+               return;
+       }
+       rtc_tm_to_time(&alm.time, &now);
+
+       memset(&alm, 0, sizeof alm);
+       rtc_time_to_tm(now + TEST_SUSPEND_SECONDS, &alm.time);
+       alm.enabled = true;
+
+       status = rtc_set_alarm(rtc, &alm);
+       if (status < 0) {
+               printk(err_wakealarm, dev_name(&rtc->dev), status);
+               return;
+       }
+
+       if (state == PM_SUSPEND_MEM) {
+               printk(info_test, pm_states[state]);
+               status = pm_suspend(state);
+               if (status == -ENODEV)
+                       state = PM_SUSPEND_STANDBY;
+       }
+       if (state == PM_SUSPEND_STANDBY) {
+               printk(info_test, pm_states[state]);
+               status = pm_suspend(state);
+       }
+       if (status < 0)
+               printk(err_suspend, status);
+
+       /* Some platforms can't detect that the alarm triggered the
+        * wakeup, or (accordingly) disable it after it afterwards.
+        * It's supposed to give oneshot behavior; cope.
+        */
+       alm.enabled = false;
+       rtc_set_alarm(rtc, &alm);
+}
+
+static int __init has_wakealarm(struct device *dev, void *name_ptr)
+{
+       struct rtc_device *candidate = to_rtc_device(dev);
+
+       if (!candidate->ops->set_alarm)
+               return 0;
+       if (!device_may_wakeup(candidate->dev.parent))
+               return 0;
+
+       *(const char **)name_ptr = dev_name(dev);
+       return 1;
+}
+
+/*
+ * Kernel options like "test_suspend=mem" force suspend/resume sanity tests
+ * at startup time.  They're normally disabled, for faster boot and because
+ * we can't know which states really work on this particular system.
+ */
+static suspend_state_t test_state __initdata = PM_SUSPEND_ON;
+
+static char warn_bad_state[] __initdata =
+       KERN_WARNING "PM: can't test '%s' suspend state\n";
+
+static int __init setup_test_suspend(char *value)
+{
+       unsigned i;
+
+       /* "=mem" ==> "mem" */
+       value++;
+       for (i = 0; i < PM_SUSPEND_MAX; i++) {
+               if (!pm_states[i])
+                       continue;
+               if (strcmp(pm_states[i], value) != 0)
+                       continue;
+               test_state = (__force suspend_state_t) i;
+               return 0;
+       }
+       printk(warn_bad_state, value);
+       return 0;
+}
+__setup("test_suspend", setup_test_suspend);
+
+static int __init test_suspend(void)
+{
+       static char             warn_no_rtc[] __initdata =
+               KERN_WARNING "PM: no wakealarm-capable RTC driver is ready\n";
+
+       char                    *pony = NULL;
+       struct rtc_device       *rtc = NULL;
+
+       /* PM is initialized by now; is that state testable? */
+       if (test_state == PM_SUSPEND_ON)
+               goto done;
+       if (!valid_state(test_state)) {
+               printk(warn_bad_state, pm_states[test_state]);
+               goto done;
+       }
+
+       /* RTCs have initialized by now too ... can we use one? */
+       class_find_device(rtc_class, NULL, &pony, has_wakealarm);
+       if (pony)
+               rtc = rtc_class_open(pony);
+       if (!rtc) {
+               printk(warn_no_rtc);
+               goto done;
+       }
+
+       /* go for it */
+       test_wakealarm(rtc, test_state);
+       rtc_class_close(rtc);
+done:
+       return 0;
+}
+late_initcall(test_suspend);
index 78c35047586dbaf6ad4766a88e73062a56fde543..6a07f4dbf2f8b16d165a050852dbaf4a5d8f8351 100644 (file)
 
 #include "power.h"
 
-/*
- * Preferred image size in bytes (tunable via /sys/power/image_size).
- * When it is set to N, swsusp will do its best to ensure the image
- * size will not exceed N bytes, but if that is impossible, it will
- * try to create the smallest image possible.
- */
-unsigned long image_size = 500 * 1024 * 1024;
-
 int in_suspend __nosavedata = 0;
 
 /**
@@ -194,193 +186,3 @@ void swsusp_show_speed(struct timeval *start, struct timeval *stop,
                        centisecs / 100, centisecs % 100,
                        kps / 1000, (kps % 1000) / 10);
 }
-
-/**
- *     swsusp_shrink_memory -  Try to free as much memory as needed
- *
- *     ... but do not OOM-kill anyone
- *
- *     Notice: all userland should be stopped before it is called, or
- *     livelock is possible.
- */
-
-#define SHRINK_BITE    10000
-static inline unsigned long __shrink_memory(long tmp)
-{
-       if (tmp > SHRINK_BITE)
-               tmp = SHRINK_BITE;
-       return shrink_all_memory(tmp);
-}
-
-int swsusp_shrink_memory(void)
-{
-       long tmp;
-       struct zone *zone;
-       unsigned long pages = 0;
-       unsigned int i = 0;
-       char *p = "-\\|/";
-       struct timeval start, stop;
-
-       printk(KERN_INFO "PM: Shrinking memory...  ");
-       do_gettimeofday(&start);
-       do {
-               long size, highmem_size;
-
-               highmem_size = count_highmem_pages();
-               size = count_data_pages() + PAGES_FOR_IO + SPARE_PAGES;
-               tmp = size;
-               size += highmem_size;
-               for_each_populated_zone(zone) {
-                       tmp += snapshot_additional_pages(zone);
-                       if (is_highmem(zone)) {
-                               highmem_size -=
-                                       zone_page_state(zone, NR_FREE_PAGES);
-                       } else {
-                               tmp -= zone_page_state(zone, NR_FREE_PAGES);
-                               tmp += zone->lowmem_reserve[ZONE_NORMAL];
-                       }
-               }
-
-               if (highmem_size < 0)
-                       highmem_size = 0;
-
-               tmp += highmem_size;
-               if (tmp > 0) {
-                       tmp = __shrink_memory(tmp);
-                       if (!tmp)
-                               return -ENOMEM;
-                       pages += tmp;
-               } else if (size > image_size / PAGE_SIZE) {
-                       tmp = __shrink_memory(size - (image_size / PAGE_SIZE));
-                       pages += tmp;
-               }
-               printk("\b%c", p[i++%4]);
-       } while (tmp > 0);
-       do_gettimeofday(&stop);
-       printk("\bdone (%lu pages freed)\n", pages);
-       swsusp_show_speed(&start, &stop, pages, "Freed");
-
-       return 0;
-}
-
-/*
- * Platforms, like ACPI, may want us to save some memory used by them during
- * hibernation and to restore the contents of this memory during the subsequent
- * resume.  The code below implements a mechanism allowing us to do that.
- */
-
-struct nvs_page {
-       unsigned long phys_start;
-       unsigned int size;
-       void *kaddr;
-       void *data;
-       struct list_head node;
-};
-
-static LIST_HEAD(nvs_list);
-
-/**
- *     hibernate_nvs_register - register platform NVS memory region to save
- *     @start - physical address of the region
- *     @size - size of the region
- *
- *     The NVS region need not be page-aligned (both ends) and we arrange
- *     things so that the data from page-aligned addresses in this region will
- *     be copied into separate RAM pages.
- */
-int hibernate_nvs_register(unsigned long start, unsigned long size)
-{
-       struct nvs_page *entry, *next;
-
-       while (size > 0) {
-               unsigned int nr_bytes;
-
-               entry = kzalloc(sizeof(struct nvs_page), GFP_KERNEL);
-               if (!entry)
-                       goto Error;
-
-               list_add_tail(&entry->node, &nvs_list);
-               entry->phys_start = start;
-               nr_bytes = PAGE_SIZE - (start & ~PAGE_MASK);
-               entry->size = (size < nr_bytes) ? size : nr_bytes;
-
-               start += entry->size;
-               size -= entry->size;
-       }
-       return 0;
-
- Error:
-       list_for_each_entry_safe(entry, next, &nvs_list, node) {
-               list_del(&entry->node);
-               kfree(entry);
-       }
-       return -ENOMEM;
-}
-
-/**
- *     hibernate_nvs_free - free data pages allocated for saving NVS regions
- */
-void hibernate_nvs_free(void)
-{
-       struct nvs_page *entry;
-
-       list_for_each_entry(entry, &nvs_list, node)
-               if (entry->data) {
-                       free_page((unsigned long)entry->data);
-                       entry->data = NULL;
-                       if (entry->kaddr) {
-                               iounmap(entry->kaddr);
-                               entry->kaddr = NULL;
-                       }
-               }
-}
-
-/**
- *     hibernate_nvs_alloc - allocate memory necessary for saving NVS regions
- */
-int hibernate_nvs_alloc(void)
-{
-       struct nvs_page *entry;
-
-       list_for_each_entry(entry, &nvs_list, node) {
-               entry->data = (void *)__get_free_page(GFP_KERNEL);
-               if (!entry->data) {
-                       hibernate_nvs_free();
-                       return -ENOMEM;
-               }
-       }
-       return 0;
-}
-
-/**
- *     hibernate_nvs_save - save NVS memory regions
- */
-void hibernate_nvs_save(void)
-{
-       struct nvs_page *entry;
-
-       printk(KERN_INFO "PM: Saving platform NVS memory\n");
-
-       list_for_each_entry(entry, &nvs_list, node)
-               if (entry->data) {
-                       entry->kaddr = ioremap(entry->phys_start, entry->size);
-                       memcpy(entry->data, entry->kaddr, entry->size);
-               }
-}
-
-/**
- *     hibernate_nvs_restore - restore NVS memory regions
- *
- *     This function is going to be called with interrupts disabled, so it
- *     cannot iounmap the virtual addresses used to access the NVS region.
- */
-void hibernate_nvs_restore(void)
-{
-       struct nvs_page *entry;
-
-       printk(KERN_INFO "PM: Restoring platform NVS memory\n");
-
-       list_for_each_entry(entry, &nvs_list, node)
-               if (entry->data)
-                       memcpy(entry->kaddr, entry->data, entry->size);
-}
index 820c5af44f3ec6472db64bf32daeccba458ab7d7..fcd107a78c5a1070c96ace2719d12bfe59a825f0 100644 (file)
@@ -902,7 +902,7 @@ EXPORT_SYMBOL_GPL(rt_mutex_lock_interruptible);
  * Returns:
  *  0          on success
  * -EINTR      when interrupted by a signal
- * -ETIMEOUT   when the timeout expired
+ * -ETIMEDOUT  when the timeout expired
  * -EDEADLK    when the lock would deadlock (when deadlock detection is on)
  */
 int
index f04aa9664504025ad16e01f1c2c8c8da6a787545..8ec9d13140be832cd88d349248c1cd155fd8da61 100644 (file)
@@ -2192,6 +2192,7 @@ void kick_process(struct task_struct *p)
                smp_send_reschedule(cpu);
        preempt_enable();
 }
+EXPORT_SYMBOL_GPL(kick_process);
 
 /*
  * Return a low guess at the load of a migration-source cpu weighted
index c01e568935ea658a5b243e80bd6791fef99a5994..faf2db897de4b5ef6b82ed81fcef40c6c4452aa9 100644 (file)
@@ -757,6 +757,7 @@ void add_timer_on(struct timer_list *timer, int cpu)
        wake_up_idle_cpu(cpu);
        spin_unlock_irqrestore(&base->lock, flags);
 }
+EXPORT_SYMBOL_GPL(add_timer_on);
 
 /**
  * del_timer - deactive a timer.
index 1f6edefebffe3f7fd94d0348b97d0dd6d80a9dc1..34c5c0e6222ecf289112358c44751badd60569ab 100644 (file)
@@ -93,6 +93,8 @@ obj-$(CONFIG_NLATTR) += nlattr.o
 
 obj-$(CONFIG_DMA_API_DEBUG) += dma-debug.o
 
+obj-$(CONFIG_GENERIC_CSUM) += checksum.o
+
 hostprogs-y    := gen_crc32table
 clean-files    := crc32table.h
 
diff --git a/lib/checksum.c b/lib/checksum.c
new file mode 100644 (file)
index 0000000..12e5a1c
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ *
+ * INET                An implementation of the TCP/IP protocol suite for the LINUX
+ *             operating system.  INET is implemented using the  BSD Socket
+ *             interface as the means of communication with the user level.
+ *
+ *             IP/TCP/UDP checksumming routines
+ *
+ * Authors:    Jorge Cwik, <jorge@laser.satlink.net>
+ *             Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ *             Tom May, <ftom@netcom.com>
+ *             Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de>
+ *             Lots of code moved from tcp.c and ip.c; see those files
+ *             for more names.
+ *
+ * 03/02/96    Jes Sorensen, Andreas Schwab, Roman Hodek:
+ *             Fixed some nasty bugs, causing some horrible crashes.
+ *             A: At some points, the sum (%0) was used as
+ *             length-counter instead of the length counter
+ *             (%1). Thanks to Roman Hodek for pointing this out.
+ *             B: GCC seems to mess up if one uses too many
+ *             data-registers to hold input values and one tries to
+ *             specify d0 and d1 as scratch registers. Letting gcc
+ *             choose these registers itself solves the problem.
+ *
+ *             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.
+ */
+
+/* Revised by Kenneth Albanowski for m68knommu. Basic problem: unaligned access
+ kills, so most of the assembly has to go. */
+
+#include <linux/module.h>
+#include <net/checksum.h>
+
+#include <asm/byteorder.h>
+
+static inline unsigned short from32to16(unsigned long x)
+{
+       /* add up 16-bit and 16-bit for 16+c bit */
+       x = (x & 0xffff) + (x >> 16);
+       /* add up carry.. */
+       x = (x & 0xffff) + (x >> 16);
+       return x;
+}
+
+static unsigned int do_csum(const unsigned char *buff, int len)
+{
+       int odd, count;
+       unsigned long result = 0;
+
+       if (len <= 0)
+               goto out;
+       odd = 1 & (unsigned long) buff;
+       if (odd) {
+               result = *buff;
+               len--;
+               buff++;
+       }
+       count = len >> 1;               /* nr of 16-bit words.. */
+       if (count) {
+               if (2 & (unsigned long) buff) {
+                       result += *(unsigned short *) buff;
+                       count--;
+                       len -= 2;
+                       buff += 2;
+               }
+               count >>= 1;            /* nr of 32-bit words.. */
+               if (count) {
+                       unsigned long carry = 0;
+                       do {
+                               unsigned long w = *(unsigned long *) buff;
+                               count--;
+                               buff += 4;
+                               result += carry;
+                               result += w;
+                               carry = (w > result);
+                       } while (count);
+                       result += carry;
+                       result = (result & 0xffff) + (result >> 16);
+               }
+               if (len & 2) {
+                       result += *(unsigned short *) buff;
+                       buff += 2;
+               }
+       }
+       if (len & 1)
+               result += (*buff << 8);
+       result = from32to16(result);
+       if (odd)
+               result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
+out:
+       return result;
+}
+
+/*
+ *     This is a version of ip_compute_csum() optimized for IP headers,
+ *     which always checksum on 4 octet boundaries.
+ */
+__sum16 ip_fast_csum(const void *iph, unsigned int ihl)
+{
+       return (__force __sum16)~do_csum(iph, ihl*4);
+}
+EXPORT_SYMBOL(ip_fast_csum);
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+__wsum csum_partial(const void *buff, int len, __wsum wsum)
+{
+       unsigned int sum = (__force unsigned int)wsum;
+       unsigned int result = do_csum(buff, len);
+
+       /* add in old sum, and carry.. */
+       result += sum;
+       if (sum > result)
+               result += 1;
+       return (__force __wsum)result;
+}
+EXPORT_SYMBOL(csum_partial);
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+__sum16 ip_compute_csum(const void *buff, int len)
+{
+       return (__force __sum16)~do_csum(buff, len);
+}
+EXPORT_SYMBOL(ip_compute_csum);
+
+/*
+ * copy from fs while checksumming, otherwise like csum_partial
+ */
+__wsum
+csum_partial_copy_from_user(const void __user *src, void *dst, int len,
+                                               __wsum sum, int *csum_err)
+{
+       int missing;
+
+       missing = __copy_from_user(dst, src, len);
+       if (missing) {
+               memset(dst + len - missing, 0, missing);
+               *csum_err = -EFAULT;
+       } else
+               *csum_err = 0;
+
+       return csum_partial(dst, len, sum);
+}
+EXPORT_SYMBOL(csum_partial_copy_from_user);
+
+/*
+ * copy from ds while checksumming, otherwise like csum_partial
+ */
+__wsum
+csum_partial_copy(const void *src, void *dst, int len, __wsum sum)
+{
+       memcpy(dst, src, len);
+       return csum_partial(dst, len, sum);
+}
+EXPORT_SYMBOL(csum_partial_copy);
+
+#ifndef csum_tcpudp_nofold
+__wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
+                       unsigned short len,
+                       unsigned short proto,
+                       __wsum sum)
+{
+       unsigned long long s = (__force u32)sum;
+
+       s += (__force u32)saddr;
+       s += (__force u32)daddr;
+#ifdef __BIG_ENDIAN
+       s += proto + len;
+#else
+       s += (proto + len) << 8;
+#endif
+       s += (s >> 32);
+       return (__force __wsum)s;
+}
+EXPORT_SYMBOL(csum_tcpudp_nofold);
+#endif
index 179c0874559569bf2626cbfc70bfcfef09474097..4cac81ec225e09af4cfd69c36d63a574a8418110 100644 (file)
@@ -39,7 +39,26 @@ void sort_extable(struct exception_table_entry *start,
        sort(start, finish - start, sizeof(struct exception_table_entry),
             cmp_ex, NULL);
 }
-#endif
+
+#ifdef CONFIG_MODULES
+/*
+ * If the exception table is sorted, any referring to the module init
+ * will be at the beginning or the end.
+ */
+void trim_init_extable(struct module *m)
+{
+       /*trim the beginning*/
+       while (m->num_exentries && within_module_init(m->extable[0].insn, m)) {
+               m->extable++;
+               m->num_exentries--;
+       }
+       /*trim the end*/
+       while (m->num_exentries &&
+               within_module_init(m->extable[m->num_exentries-1].insn, m))
+               m->num_exentries--;
+}
+#endif /* CONFIG_MODULES */
+#endif /* !ARCH_HAS_SORT_EXTABLE */
 
 #ifndef ARCH_HAS_SEARCH_EXTABLE
 /*
index ac40796cfb15b8d41d1b0e5f45cd093c31bf7da2..9073695ff25f3db8da8df878e6ade3952542229a 100644 (file)
@@ -39,7 +39,7 @@ EXPORT_SYMBOL_GPL(probe_kernel_read);
  * Safely write to address @dst from the buffer at @src.  If a kernel fault
  * happens, handle that and return -EFAULT.
  */
-long probe_kernel_write(void *dst, void *src, size_t size)
+long notrace __weak probe_kernel_write(void *dst, void *src, size_t size)
 {
        long ret;
        mm_segment_t old_fs = get_fs();
index 3dd4a909a1de8d0c04147c8e08c647127a386c98..11a8a10a3909e973800888da1b600338eb1d8b99 100644 (file)
@@ -47,8 +47,6 @@ static int __init alloc_node_page_cgroup(int nid)
        struct page_cgroup *base, *pc;
        unsigned long table_size;
        unsigned long start_pfn, nr_pages, index;
-       struct page *page;
-       unsigned int order;
 
        start_pfn = NODE_DATA(nid)->node_start_pfn;
        nr_pages = NODE_DATA(nid)->node_spanned_pages;
@@ -57,13 +55,11 @@ static int __init alloc_node_page_cgroup(int nid)
                return 0;
 
        table_size = sizeof(struct page_cgroup) * nr_pages;
-       order = get_order(table_size);
-       page = alloc_pages_node(nid, GFP_NOWAIT | __GFP_ZERO, order);
-       if (!page)
-               page = alloc_pages_node(-1, GFP_NOWAIT | __GFP_ZERO, order);
-       if (!page)
+
+       base = __alloc_bootmem_node_nopanic(NODE_DATA(nid),
+                       table_size, PAGE_SIZE, __pa(MAX_DMA_ADDRESS));
+       if (!base)
                return -ENOMEM;
-       base = page_address(page);
        for (index = 0; index < nr_pages; index++) {
                pc = base + index;
                __init_page_cgroup(pc, start_pfn + index);
@@ -73,7 +69,7 @@ static int __init alloc_node_page_cgroup(int nid)
        return 0;
 }
 
-void __init page_cgroup_init(void)
+void __init page_cgroup_init_flatmem(void)
 {
 
        int nid, fail;
@@ -117,16 +113,11 @@ static int __init_refok init_section_page_cgroup(unsigned long pfn)
        if (!section->page_cgroup) {
                nid = page_to_nid(pfn_to_page(pfn));
                table_size = sizeof(struct page_cgroup) * PAGES_PER_SECTION;
-               if (slab_is_available()) {
-                       base = kmalloc_node(table_size,
-                                       GFP_KERNEL | __GFP_NOWARN, nid);
-                       if (!base)
-                               base = vmalloc_node(table_size, nid);
-               } else {
-                       base = __alloc_bootmem_node_nopanic(NODE_DATA(nid),
-                               table_size,
-                               PAGE_SIZE, __pa(MAX_DMA_ADDRESS));
-               }
+               VM_BUG_ON(!slab_is_available());
+               base = kmalloc_node(table_size,
+                               GFP_KERNEL | __GFP_NOWARN, nid);
+               if (!base)
+                       base = vmalloc_node(table_size, nid);
        } else {
                /*
                 * We don't have to allocate page_cgroup again, but
index 6a1ad0b9a94f51bece1c62b1bf2a7d4da7785205..af3376d0a8333f2f7271f3f093a52a917a8f9881 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -304,6 +304,12 @@ struct kmem_list3 {
        int free_touched;               /* updated without locking */
 };
 
+/*
+ * The slab allocator is initialized with interrupts disabled. Therefore, make
+ * sure early boot allocations don't accidentally enable interrupts.
+ */
+static gfp_t slab_gfp_mask __read_mostly = SLAB_GFP_BOOT_MASK;
+
 /*
  * Need this for bootstrapping a per node allocator.
  */
@@ -673,6 +679,7 @@ static enum {
        NONE,
        PARTIAL_AC,
        PARTIAL_L3,
+       EARLY,
        FULL
 } g_cpucache_up;
 
@@ -681,7 +688,7 @@ static enum {
  */
 int slab_is_available(void)
 {
-       return g_cpucache_up == FULL;
+       return g_cpucache_up >= EARLY;
 }
 
 static DEFINE_PER_CPU(struct delayed_work, reap_work);
@@ -1545,19 +1552,27 @@ void __init kmem_cache_init(void)
                }
        }
 
-       /* 6) resize the head arrays to their final sizes */
-       {
-               struct kmem_cache *cachep;
-               mutex_lock(&cache_chain_mutex);
-               list_for_each_entry(cachep, &cache_chain, next)
-                       if (enable_cpucache(cachep, GFP_NOWAIT))
-                               BUG();
-               mutex_unlock(&cache_chain_mutex);
-       }
+       g_cpucache_up = EARLY;
 
        /* Annotate slab for lockdep -- annotate the malloc caches */
        init_lock_keys();
+}
+
+void __init kmem_cache_init_late(void)
+{
+       struct kmem_cache *cachep;
+
+       /*
+        * Interrupts are enabled now so all GFP allocations are safe.
+        */
+       slab_gfp_mask = __GFP_BITS_MASK;
 
+       /* 6) resize the head arrays to their final sizes */
+       mutex_lock(&cache_chain_mutex);
+       list_for_each_entry(cachep, &cache_chain, next)
+               if (enable_cpucache(cachep, GFP_NOWAIT))
+                       BUG();
+       mutex_unlock(&cache_chain_mutex);
 
        /* Done! */
        g_cpucache_up = FULL;
@@ -2034,7 +2049,7 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep, gfp_t gfp)
                        for_each_online_node(node) {
                                cachep->nodelists[node] =
                                    kmalloc_node(sizeof(struct kmem_list3),
-                                               GFP_KERNEL, node);
+                                               gfp, node);
                                BUG_ON(!cachep->nodelists[node]);
                                kmem_list3_init(cachep->nodelists[node]);
                        }
@@ -3286,6 +3301,8 @@ __cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid,
        unsigned long save_flags;
        void *ptr;
 
+       flags &= slab_gfp_mask;
+
        lockdep_trace_alloc(flags);
 
        if (slab_should_failslab(cachep, flags))
@@ -3369,6 +3386,8 @@ __cache_alloc(struct kmem_cache *cachep, gfp_t flags, void *caller)
        unsigned long save_flags;
        void *objp;
 
+       flags &= slab_gfp_mask;
+
        lockdep_trace_alloc(flags);
 
        if (slab_should_failslab(cachep, flags))
index 898fb5047dcc36e9d5a30042d5676f315ac7df7b..15960a09abb1422ed765c535585a85b602e34231 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -179,6 +179,12 @@ static enum {
        SYSFS           /* Sysfs up */
 } slab_state = DOWN;
 
+/*
+ * The slab allocator is initialized with interrupts disabled. Therefore, make
+ * sure early boot allocations don't accidentally enable interrupts.
+ */
+static gfp_t slab_gfp_mask __read_mostly = SLAB_GFP_BOOT_MASK;
+
 /* A list of all slab caches on the system */
 static DECLARE_RWSEM(slub_lock);
 static LIST_HEAD(slab_caches);
@@ -1618,6 +1624,8 @@ static __always_inline void *slab_alloc(struct kmem_cache *s,
        unsigned long flags;
        unsigned int objsize;
 
+       gfpflags &= slab_gfp_mask;
+
        lockdep_trace_alloc(gfpflags);
        might_sleep_if(gfpflags & __GFP_WAIT);
 
@@ -3132,6 +3140,14 @@ void __init kmem_cache_init(void)
                nr_cpu_ids, nr_node_ids);
 }
 
+void __init kmem_cache_init_late(void)
+{
+       /*
+        * Interrupts are enabled now so all GFP allocations are safe.
+        */
+       slab_gfp_mask = __GFP_BITS_MASK;
+}
+
 /*
  * Find a mergeable slab cache
  */
index d254306562cda93af097d60ed024a71479c9da4d..95c08a8cc2ba4fb015f71b605271f9b8804c68fb 100644 (file)
@@ -2056,7 +2056,7 @@ unsigned long global_lru_pages(void)
                + global_page_state(NR_INACTIVE_FILE);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_HIBERNATION
 /*
  * Helper function for shrink_all_memory().  Tries to reclaim 'nr_pages' pages
  * from LRU lists system-wide, for given pass and priority.
@@ -2196,7 +2196,7 @@ out:
 
        return sc.nr_reclaimed;
 }
-#endif
+#endif /* CONFIG_HIBERNATION */
 
 /* It's optimal to keep kswapds on the same CPUs as their memory, but
    not required for correctness.  So if the last cpu in a node goes
index bb8579a141a86c584db61993a86104316ba4cb43..a49484e67e1ddf2b1dcd2ae1ed0ee71a8872521f 100644 (file)
@@ -246,7 +246,7 @@ static int p9_virtio_probe(struct virtio_device *vdev)
        chan->vdev = vdev;
 
        /* We expect one virtqueue, for requests. */
-       chan->vq = vdev->config->find_vq(vdev, 0, req_done);
+       chan->vq = virtio_find_single_vq(vdev, req_done, "requests");
        if (IS_ERR(chan->vq)) {
                err = PTR_ERR(chan->vq);
                goto out_free_vq;
@@ -261,7 +261,7 @@ static int p9_virtio_probe(struct virtio_device *vdev)
        return 0;
 
 out_free_vq:
-       vdev->config->del_vq(chan->vq);
+       vdev->config->del_vqs(vdev);
 fail:
        mutex_lock(&virtio_9p_lock);
        chan_index--;
@@ -332,7 +332,7 @@ static void p9_virtio_remove(struct virtio_device *vdev)
        BUG_ON(chan->inuse);
 
        if (chan->initialized) {
-               vdev->config->del_vq(chan->vq);
+               vdev->config->del_vqs(vdev);
                chan->initialized = false;
        }
 }
index ca8cb326d1d2bd3397817f90936f93c30a3f7896..ead6c7a42f443f6304715e1b7e64fae3ac9777ef 100644 (file)
@@ -168,7 +168,7 @@ config IPV6_SIT
          into IPv4 packets. This is useful if you want to connect two IPv6
          networks over an IPv4-only path.
 
-         Saying M here will produce a module called sit.ko. If unsure, say Y.
+         Saying M here will produce a module called sit. If unsure, say Y.
 
 config IPV6_NDISC_NODETYPE
        bool
index a8218bc1806a6c541fdeac42eaf00ee66faf0950..597487ae6ce8fbe7a0d34ae5eb4a169d30506d19 100644 (file)
@@ -2765,7 +2765,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
                spin_unlock_bh(&ifp->lock);
                read_unlock_bh(&idev->lock);
                /*
-                * If the defice is not ready:
+                * If the device is not ready:
                 * - keep it tentative if it is a permanent address.
                 * - otherwise, kill it.
                 */
index cb3ad741ebf878f2131e557b84d055a0bfbbe4ac..c26a20c58dde1bbf256fc074a5bfb80c1ad7f2d9 100644 (file)
@@ -327,7 +327,7 @@ config NETFILTER_XT_TARGET_CONNMARK
 
          If you want to compile it as a module, say M here and read
          <file:Documentation/kbuild/modules.txt>.  The module will be called
-         ipt_CONNMARK.ko.  If unsure, say `N'.
+         ipt_CONNMARK.  If unsure, say `N'.
 
 config NETFILTER_XT_TARGET_CONNSECMARK
        tristate '"CONNSECMARK" target support'
@@ -584,7 +584,7 @@ config NETFILTER_XT_MATCH_CONNMARK
 
          If you want to compile it as a module, say M here and read
          <file:Documentation/kbuild/modules.txt>.  The module will be called
-         ipt_connmark.ko.  If unsure, say `N'.
+         ipt_connmark.  If unsure, say `N'.
 
 config NETFILTER_XT_MATCH_CONNTRACK
        tristate '"conntrack" connection tracking match support'
index 9fe8982bd7c905d67086b5073fd72df407dade7a..4a1d94aac20ba96af3c4671a57171d526c174d53 100644 (file)
@@ -116,7 +116,7 @@ int nf_conntrack_acct_init(struct net *net)
        if (net_eq(net, &init_net)) {
 #ifdef CONFIG_NF_CT_ACCT
        printk(KERN_WARNING "CONFIG_NF_CT_ACCT is deprecated and will be removed soon. Please use\n");
-               printk(KERN_WARNING "nf_conntrack.acct=1 kernel paramater, acct=1 nf_conntrack module option or\n");
+               printk(KERN_WARNING "nf_conntrack.acct=1 kernel parameter, acct=1 nf_conntrack module option or\n");
                printk(KERN_WARNING "sysctl net.netfilter.nf_conntrack_acct=1 to enable it.\n");
 #endif
 
index 095cfc8b9dbfbddff4cbbbc3437019e8b2996255..0fcd838387719d4638e960d77108b761af86eb9d 100644 (file)
@@ -54,8 +54,12 @@ quiet_cmd_remove = REMOVE  $(unwanted)
       cmd_remove = rm -f $(unwanted-file)
 
 quiet_cmd_check = CHECK   $(printdir) ($(words $(all-files)) files)
-      cmd_check = $(PERL) $< $(INSTALL_HDR_PATH)/include $(SRCARCH) \
-                  $(addprefix $(install)/, $(all-files));           \
+# Headers list can be pretty long, xargs helps to avoid
+# the "Argument list too long" error.
+      cmd_check = for f in $(all-files); do                          \
+                  echo "$(install)/$${f}"; done                      \
+                  | xargs                                            \
+                  $(PERL) $< $(INSTALL_HDR_PATH)/include $(SRCARCH); \
                  touch $@
 
 PHONY += __headersinst __headerscheck
index 35bdc68b6e66604fc31f184fff4ad1c0e6c5398e..4c9523ef9c00d0a795862cc12e23b1eda80931d2 100644 (file)
@@ -69,7 +69,7 @@ FILELINE * docsection;
 #define NOFUNCTION    "-nofunction"
 #define NODOCSECTIONS "-no-doc-sections"
 
-char *srctree;
+static char *srctree, *kernsrctree;
 
 void usage (void)
 {
@@ -77,7 +77,8 @@ void usage (void)
        fprintf(stderr, "Input is read from file.tmpl. Output is sent to stdout\n");
        fprintf(stderr, "doc: frontend when generating kernel documentation\n");
        fprintf(stderr, "depend: generate list of files referenced within file\n");
-       fprintf(stderr, "Environment variable SRCTREE: absolute path to kernel source tree.\n");
+       fprintf(stderr, "Environment variable SRCTREE: absolute path to sources.\n");
+       fprintf(stderr, "                     KBUILD_SRC: absolute path to kernel source tree.\n");
 }
 
 /*
@@ -96,8 +97,8 @@ void exec_kernel_doc(char **svec)
                        exit(1);
                case  0:
                        memset(real_filename, 0, sizeof(real_filename));
-                       strncat(real_filename, srctree, PATH_MAX);
-                       strncat(real_filename, KERNELDOCPATH KERNELDOC,
+                       strncat(real_filename, kernsrctree, PATH_MAX);
+                       strncat(real_filename, "/" KERNELDOCPATH KERNELDOC,
                                        PATH_MAX - strlen(real_filename));
                        execvp(real_filename, svec);
                        fprintf(stderr, "exec ");
@@ -178,6 +179,7 @@ void find_export_symbols(char * filename)
                char real_filename[PATH_MAX + 1];
                memset(real_filename, 0, sizeof(real_filename));
                strncat(real_filename, srctree, PATH_MAX);
+               strncat(real_filename, "/", PATH_MAX - strlen(real_filename));
                strncat(real_filename, filename,
                                PATH_MAX - strlen(real_filename));
                sym = add_new_file(filename);
@@ -382,6 +384,9 @@ int main(int argc, char *argv[])
        srctree = getenv("SRCTREE");
        if (!srctree)
                srctree = getcwd(NULL, 0);
+       kernsrctree = getenv("KBUILD_SRC");
+       if (!kernsrctree)
+               kernsrctree = srctree;
        if (argc != 3) {
                usage();
                exit(1);
index 8912c0f5460b502f4bb3568dea39f09af5b438d3..72c15205bb2b2b114578f3e33490a0838fd7c47c 100644 (file)
@@ -373,10 +373,11 @@ void print_deps(void)
 void traps(void)
 {
        static char test[] __attribute__((aligned(sizeof(int)))) = "CONF";
+       int *p = (int *)test;
 
-       if (*(int *)test != INT_CONF) {
+       if (*p != INT_CONF) {
                fprintf(stderr, "fixdep: sizeof(int) != 4 or wrong endianess? %#x\n",
-                       *(int *)test);
+                       *p);
                exit(2);
        }
 }
index 60d00d1c4eee2051d0bb9d274ef95a9832962153..66ad375612f27f0aa2ce6902806e9ee59d7b2706 100755 (executable)
@@ -14,6 +14,57 @@ cat << EOF
 #include <asm/types.h>
 #include <asm/unistd.h>
 
+/* *at */
+#define __IGNORE_open          /* openat */
+#define __IGNORE_link          /* linkat */
+#define __IGNORE_unlink                /* unlinkat */
+#define __IGNORE_mknod         /* mknodat */
+#define __IGNORE_chmod         /* fchmodat */
+#define __IGNORE_chown         /* fchownat */
+#define __IGNORE_mkdir         /* mkdirat */
+#define __IGNORE_rmdir         /* unlinkat */
+#define __IGNORE_lchown                /* fchownat */
+#define __IGNORE_access                /* faccessat */
+#define __IGNORE_rename                /* renameat */
+#define __IGNORE_readlink      /* readlinkat */
+#define __IGNORE_symlink       /* symlinkat */
+#define __IGNORE_utimes                /* futimesat */
+#if BITS_PER_LONG == 64
+#define __IGNORE_stat          /* fstatat */
+#define __IGNORE_lstat         /* fstatat */
+#else
+#define __IGNORE_stat64                /* fstatat64 */
+#define __IGNORE_lstat64       /* fstatat64 */
+#endif
+
+/* CLOEXEC flag */
+#define __IGNORE_pipe          /* pipe2 */
+#define __IGNORE_dup2          /* dup3 */
+#define __IGNORE_epoll_create  /* epoll_create1 */
+#define __IGNORE_inotify_init  /* inotify_init1 */
+#define __IGNORE_eventfd       /* eventfd2 */
+#define __IGNORE_signalfd      /* signalfd4 */
+
+/* MMU */
+#ifndef CONFIG_MMU
+#define __IGNORE_madvise
+#define __IGNORE_mbind
+#define __IGNORE_mincore
+#define __IGNORE_mlock
+#define __IGNORE_mlockall
+#define __IGNORE_munlock
+#define __IGNORE_munlockall
+#define __IGNORE_mprotect
+#define __IGNORE_msync
+#define __IGNORE_migrate_pages
+#define __IGNORE_move_pages
+#define __IGNORE_remap_file_pages
+#define __IGNORE_get_mempolicy
+#define __IGNORE_set_mempolicy
+#define __IGNORE_swapoff
+#define __IGNORE_swapon
+#endif
+
 /* System calls for 32-bit kernels only */
 #if BITS_PER_LONG == 64
 #define __IGNORE_sendfile64
@@ -27,6 +78,22 @@ cat << EOF
 #define __IGNORE_fstatat64
 #define __IGNORE_fstatfs64
 #define __IGNORE_statfs64
+#define __IGNORE_llseek
+#define __IGNORE_mmap2
+#else
+#define __IGNORE_sendfile
+#define __IGNORE_ftruncate
+#define __IGNORE_truncate
+#define __IGNORE_stat
+#define __IGNORE_lstat
+#define __IGNORE_fstat
+#define __IGNORE_fcntl
+#define __IGNORE_fadvise64
+#define __IGNORE_newfstatat
+#define __IGNORE_fstatfs
+#define __IGNORE_statfs
+#define __IGNORE_lseek
+#define __IGNORE_mmap
 #endif
 
 /* i386-specific or historical system calls */
@@ -44,7 +111,6 @@ cat << EOF
 #define __IGNORE_idle
 #define __IGNORE_modify_ldt
 #define __IGNORE_ugetrlimit
-#define __IGNORE_mmap2
 #define __IGNORE_vm86
 #define __IGNORE_vm86old
 #define __IGNORE_set_thread_area
@@ -55,7 +121,6 @@ cat << EOF
 #define __IGNORE_oldlstat
 #define __IGNORE_oldolduname
 #define __IGNORE_olduname
-#define __IGNORE_umount2
 #define __IGNORE_umount
 #define __IGNORE_waitpid
 #define __IGNORE_stime
@@ -75,9 +140,12 @@ cat << EOF
 #define __IGNORE__llseek
 #define __IGNORE__newselect
 #define __IGNORE_create_module
-#define __IGNORE_delete_module
 #define __IGNORE_query_module
 #define __IGNORE_get_kernel_syms
+#define __IGNORE_sysfs
+#define __IGNORE_uselib
+#define __IGNORE__sysctl
+
 /* ... including the "new" 32-bit uid syscalls */
 #define __IGNORE_lchown32
 #define __IGNORE_getuid32
@@ -99,6 +167,24 @@ cat << EOF
 #define __IGNORE_setfsuid32
 #define __IGNORE_setfsgid32
 
+/* these can be expressed using other calls */
+#define __IGNORE_alarm         /* setitimer */
+#define __IGNORE_creat         /* open */
+#define __IGNORE_fork          /* clone */
+#define __IGNORE_futimesat     /* utimensat */
+#define __IGNORE_getpgrp       /* getpgid */
+#define __IGNORE_getdents      /* getdents64 */
+#define __IGNORE_pause         /* sigsuspend */
+#define __IGNORE_poll          /* ppoll */
+#define __IGNORE_select                /* pselect6 */
+#define __IGNORE_epoll_wait    /* epoll_pwait */
+#define __IGNORE_time          /* gettimeofday */
+#define __IGNORE_uname         /* newuname */
+#define __IGNORE_ustat         /* statfs */
+#define __IGNORE_utime         /* utimes */
+#define __IGNORE_vfork         /* clone */
+#define __IGNORE_wait4         /* waitid */
+
 /* sync_file_range had a stupid ABI. Allow sync_file_range2 instead */
 #ifdef __NR_sync_file_range2
 #define __IGNORE_sync_file_range
index db6084b78a10dde77acda0f6365aa68ea239369e..608d7fdb13e8d6ac901eaf99cc3b1b5df0a7cc95 100755 (executable)
@@ -9,8 +9,10 @@ config options command ...
 commands:
        --enable|-e option   Enable option
        --disable|-d option  Disable option
-       --module|-m option      Turn option into a module
-       --state|-s option       Print state of option (n,y,m,undef)
+       --module|-m option   Turn option into a module
+       --set-str option value
+                            Set option to "value"
+       --state|-s option    Print state of option (n,y,m,undef)
 
        --enable-after|-E beforeopt option
                              Enable option directly after other option
@@ -26,8 +28,6 @@ options:
 
 config doesn't check the validity of the .config file. This is done at next
  make time.
-The options need to be already in the file before they can be changed,
-but sometimes you can cheat with the --*-after options.
 EOL
        exit 1
 }
@@ -45,8 +45,18 @@ checkarg() {
        ARG="`echo $ARG | tr a-z A-Z`"
 }
 
-replace() {
-       sed -i -e "$@" $FN
+set_var() {
+       local name=$1 new=$2 before=$3
+
+       name_re="^($name=|# $name is not set)"
+       before_re="^($before=|# $before is not set)"
+       if test -n "$before" && grep -Eq "$before_re" "$FN"; then
+               sed -ri "/$before_re/a $new" "$FN"
+       elif grep -Eq "$name_re" "$FN"; then
+               sed -ri "s:$name_re.*:$new:" "$FN"
+       else
+               echo "$new" >>"$FN"
+       fi
 }
 
 if [ "$1" = "--file" ]; then
@@ -54,8 +64,7 @@ if [ "$1" = "--file" ]; then
        if [ "$FN" = "" ] ; then
                usage
        fi
-       shift
-       shift
+       shift 2
 else
        FN=.config
 fi
@@ -68,27 +77,39 @@ while [ "$1" != "" ] ; do
        CMD="$1"
        shift
        case "$CMD" in
-       --enable|-e)
+       --refresh)
+               ;;
+       --*-after)
+               checkarg "$1"
+               A=$ARG
+               checkarg "$2"
+               B=$ARG
+               shift 2
+               ;;
+       --*)
                checkarg "$1"
-               replace "s/# CONFIG_$ARG is not set/CONFIG_$ARG=y/"
                shift
                ;;
+       esac
+       case "$CMD" in
+       --enable|-e)
+               set_var "CONFIG_$ARG" "CONFIG_$ARG=y"
+               ;;
 
        --disable|-d)
-               checkarg "$1"
-               replace "s/CONFIG_$ARG=[my]/# CONFIG_$ARG is not set/"
-               shift
+               set_var "CONFIG_$ARG" "# CONFIG_$ARG is not set"
                ;;
 
        --module|-m)
-               checkarg "$1"
-               replace "s/CONFIG_$ARG=y/CONFIG_$ARG=m/" \
-                       -e "s/# CONFIG_$ARG is not set/CONFIG_$ARG=m/"
+               set_var "CONFIG_$ARG" "CONFIG_$ARG=m"
+               ;;
+
+       --set-str)
+               set_var "CONFIG_$ARG" "CONFIG_$ARG=\"$1\""
                shift
                ;;
 
        --state|-s)
-               checkarg "$1"
                if grep -q "# CONFIG_$ARG is not set" $FN ; then
                        echo n
                else
@@ -101,44 +122,18 @@ while [ "$1" != "" ] ; do
                                echo "$V"
                        fi
                fi
-               shift
                ;;
 
        --enable-after|-E)
-               checkarg "$1"
-               A=$ARG
-               checkarg "$2"
-               B=$ARG
-               replace "/CONFIG_$A=[my]/aCONFIG_$B=y" \
-                       -e "/# CONFIG_$ARG is not set/a/CONFIG_$ARG=y" \
-                       -e "s/# CONFIG_$ARG is not set/CONFIG_$ARG=y/"
-               shift
-               shift
+               set_var "CONFIG_$B" "CONFIG_$B=y" "CONFIG_$A"
                ;;
 
        --disable-after|-D)
-               checkarg "$1"
-               A=$ARG
-               checkarg "$2"
-               B=$ARG
-               replace "/CONFIG_$A=[my]/a# CONFIG_$B is not set" \
-               -e "/# CONFIG_$ARG is not set/a/# CONFIG_$ARG is not set" \
-               -e "s/CONFIG_$ARG=[my]/# CONFIG_$ARG is not set/"
-               shift
-               shift
+               set_var "CONFIG_$B" "# CONFIG_$B is not set" "CONFIG_$A"
                ;;
 
        --module-after|-M)
-               checkarg "$1"
-               A=$ARG
-               checkarg "$2"
-               B=$ARG
-               replace "/CONFIG_$A=[my]/aCONFIG_$B=m" \
-                       -e "/# CONFIG_$ARG is not set/a/CONFIG_$ARG=m" \
-                       -e "s/CONFIG_$ARG=y/CONFIG_$ARG=m/" \
-                       -e "s/# CONFIG_$ARG is not set/CONFIG_$ARG=m/"
-               shift
-               shift
+               set_var "CONFIG_$B" "CONFIG_$B=m" "CONFIG_$A"
                ;;
 
        # undocumented because it ignores --file (fixme)
index cc767b388baf7b30ef04b61650911069818d7ba0..debecb5561c481d8076cb97b36857878e6becb37 100644 (file)
@@ -18,7 +18,7 @@ compiler="$*"
 
 if [ ${#compiler} -eq 0 ]; then
        echo "Error: No compiler specified."
-       echo -e "Usage:\n\t$0 <gcc-command>"
+       printf "Usage:\n\t$0 <gcc-command>\n"
        exit 1
 fi
 
index d33426f866dbbc4ef9078f5bbce492edb06a2223..0308ecc10d5b133858a15bf9f46b3cb2f424d4d6 100755 (executable)
@@ -15,19 +15,12 @@ do_command()
        fi
 }
 
-# Do not try this architecture
-drop="generic um ppc sparc64 cris"
-
 archs=$(ls ${srctree}/arch)
 
 for arch in ${archs}; do
        case ${arch} in
        um)        # no userspace export
                ;;
-       ppc)       # headers exported by powerpc
-               ;;
-       sparc64)   # headers exported by sparc
-               ;;
        cris)      # headers export are known broken
                ;;
        *)
index 56f90a480899dd7bef86b88725b5668160b5fcad..db1dd7a549f2b9e1259148c39175ad6ee6df3d02 100644 (file)
@@ -2,7 +2,7 @@
 #
 # headers_check.pl execute a number of trivial consistency checks
 #
-# Usage: headers_check.pl dir [files...]
+# Usage: headers_check.pl dir arch [files...]
 # dir:   dir to look for included files
 # arch:  architecture
 # files: list of files to check
@@ -37,7 +37,7 @@ foreach my $file (@files) {
                &check_include();
                &check_asm_types();
                &check_sizetypes();
-               &check_prototypes();
+               &check_declarations();
                # Dropped for now. Too much noise &check_config();
        }
        close FH;
@@ -61,16 +61,18 @@ sub check_include
        }
 }
 
-sub check_prototypes
+sub check_declarations
 {
-       if ($line =~ m/^\s*extern\b/) {
-               printf STDERR "$filename:$lineno: extern's make no sense in userspace\n";
+       if ($line =~m/^\s*extern\b/) {
+               printf STDERR "$filename:$lineno: " .
+                             "userspace cannot call function or variable " .
+                             "defined in the kernel\n";
        }
 }
 
 sub check_config
 {
-       if ($line =~ m/[^a-zA-Z0-9_]+CONFIG_([a-zA-Z0-9]+)[^a-zA-Z0-9]/) {
+       if ($line =~ m/[^a-zA-Z0-9_]+CONFIG_([a-zA-Z0-9_]+)[^a-zA-Z0-9_]/) {
                printf STDERR "$filename:$lineno: leaks CONFIG_$1 to userspace where it is not valid\n";
        }
 }
index 6654cbed965b932c2cc515243680edac93b00c0b..3cb57895c9ea5629089f90d7bc79575673d30416 100644 (file)
 #include <string.h>
 #include <ctype.h>
 
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
+#endif
+
 #define KSYM_NAME_LEN          128
 
 struct sym_entry {
@@ -32,9 +36,23 @@ struct sym_entry {
        unsigned char *sym;
 };
 
+struct text_range {
+       const char *stext, *etext;
+       unsigned long long start, end;
+};
+
+static unsigned long long _text;
+static struct text_range text_ranges[] = {
+       { "_stext",     "_etext"     },
+       { "_sinittext", "_einittext" },
+       { "_stext_l1",  "_etext_l1"  }, /* Blackfin on-chip L1 inst SRAM */
+       { "_stext_l2",  "_etext_l2"  }, /* Blackfin on-chip L2 SRAM */
+};
+#define text_range_text     (&text_ranges[0])
+#define text_range_inittext (&text_ranges[1])
+
 static struct sym_entry *table;
 static unsigned int table_size, table_cnt;
-static unsigned long long _text, _stext, _etext, _sinittext, _einittext;
 static int all_symbols = 0;
 static char symbol_prefix_char = '\0';
 
@@ -61,6 +79,26 @@ static inline int is_arm_mapping_symbol(const char *str)
               && (str[2] == '\0' || str[2] == '.');
 }
 
+static int read_symbol_tr(const char *sym, unsigned long long addr)
+{
+       size_t i;
+       struct text_range *tr;
+
+       for (i = 0; i < ARRAY_SIZE(text_ranges); ++i) {
+               tr = &text_ranges[i];
+
+               if (strcmp(sym, tr->stext) == 0) {
+                       tr->start = addr;
+                       return 0;
+               } else if (strcmp(sym, tr->etext) == 0) {
+                       tr->end = addr;
+                       return 0;
+               }
+       }
+
+       return 1;
+}
+
 static int read_symbol(FILE *in, struct sym_entry *s)
 {
        char str[500];
@@ -84,14 +122,8 @@ static int read_symbol(FILE *in, struct sym_entry *s)
        /* Ignore most absolute/undefined (?) symbols. */
        if (strcmp(sym, "_text") == 0)
                _text = s->addr;
-       else if (strcmp(sym, "_stext") == 0)
-               _stext = s->addr;
-       else if (strcmp(sym, "_etext") == 0)
-               _etext = s->addr;
-       else if (strcmp(sym, "_sinittext") == 0)
-               _sinittext = s->addr;
-       else if (strcmp(sym, "_einittext") == 0)
-               _einittext = s->addr;
+       else if (read_symbol_tr(sym, s->addr) == 0)
+               /* nothing to do */;
        else if (toupper(stype) == 'A')
        {
                /* Keep these useful absolute symbols */
@@ -127,6 +159,21 @@ static int read_symbol(FILE *in, struct sym_entry *s)
        return 0;
 }
 
+static int symbol_valid_tr(struct sym_entry *s)
+{
+       size_t i;
+       struct text_range *tr;
+
+       for (i = 0; i < ARRAY_SIZE(text_ranges); ++i) {
+               tr = &text_ranges[i];
+
+               if (s->addr >= tr->start && s->addr < tr->end)
+                       return 0;
+       }
+
+       return 1;
+}
+
 static int symbol_valid(struct sym_entry *s)
 {
        /* Symbols which vary between passes.  Passes 1 and 2 must have
@@ -156,8 +203,7 @@ static int symbol_valid(struct sym_entry *s)
        /* if --all-symbols is not specified, then symbols outside the text
         * and inittext sections are discarded */
        if (!all_symbols) {
-               if ((s->addr < _stext || s->addr > _etext)
-                   && (s->addr < _sinittext || s->addr > _einittext))
+               if (symbol_valid_tr(s) == 0)
                        return 0;
                /* Corner case.  Discard any symbols with the same value as
                 * _etext _einittext; they can move between pass 1 and 2 when
@@ -165,10 +211,10 @@ static int symbol_valid(struct sym_entry *s)
                 * they may get dropped in pass 2, which breaks the kallsyms
                 * rules.
                 */
-               if ((s->addr == _etext &&
-                               strcmp((char *)s->sym + offset, "_etext")) ||
-                   (s->addr == _einittext &&
-                               strcmp((char *)s->sym + offset, "_einittext")))
+               if ((s->addr == text_range_text->end &&
+                               strcmp((char *)s->sym + offset, text_range_text->etext)) ||
+                   (s->addr == text_range_inittext->end &&
+                               strcmp((char *)s->sym + offset, text_range_inittext->etext)))
                        return 0;
        }
 
index b49584c932cc21bf371d29cb0cafd0361d64061f..6a36a76e6606437f3369aeb3345592aa309a547b 100644 (file)
@@ -8,6 +8,9 @@ lex.*.c
 zconf.hash.c
 *.moc
 lkc_defs.h
+gconf.glade.h
+*.pot
+*.mo
 
 #
 # configuration programs
index fa8c2dd9c983ef3fa7617c0c87a28cb9ea4546b0..5ddf8becd7a2120760407b30280424713b9de6c8 100644 (file)
@@ -83,7 +83,7 @@ help:
        @echo  '  xconfig         - Update current config utilising a QT based front-end'
        @echo  '  gconfig         - Update current config utilising a GTK based front-end'
        @echo  '  oldconfig       - Update current config utilising a provided .config as base'
-       @echo  '  silentoldconfig - Same as oldconfig, but quietly'
+       @echo  '  silentoldconfig - Same as oldconfig, but quietly, additionally update deps'
        @echo  '  randconfig      - New config with random answer to all options'
        @echo  '  defconfig       - New config with default answer to all options'
        @echo  '  allmodconfig    - New config selecting modules when possible'
@@ -104,7 +104,7 @@ HOST_EXTRACFLAGS += -DLOCALE
 # ===========================================================================
 # Shared Makefile for the various kconfig executables:
 # conf:          Used for defconfig, oldconfig and related targets
-# mconf:  Used for the mconfig target.
+# mconf:  Used for the menuconfig target
 #         Utilizes the lxdialog package
 # qconf:  Used for the xconfig target
 #         Based on QT which needs to be installed to compile it
index d190092c3b6ebf00d09a68fa4e5cb606afacd364..3baaaecd6b13ef3ba684f8e5320cfef10f1f5a4e 100644 (file)
@@ -498,14 +498,15 @@ int main(int ac, char **av)
        conf_parse(name);
        //zconfdump(stdout);
        if (sync_kconfig) {
-               if (stat(".config", &tmpstat)) {
+               name = conf_get_configname();
+               if (stat(name, &tmpstat)) {
                        fprintf(stderr, _("***\n"
                                "*** You have not yet configured your kernel!\n"
-                               "*** (missing kernel .config file)\n"
+                               "*** (missing kernel config file \"%s\")\n"
                                "***\n"
                                "*** Please run some configurator (e.g. \"make oldconfig\" or\n"
                                "*** \"make menuconfig\" or \"make xconfig\").\n"
-                               "***\n"));
+                               "***\n"), name);
                        exit(1);
                }
        }
index 273d73888f9d4553f3574d9a8474df66533085bc..a04da3459f0fa17ee71e155bcdb56d71a27d71b5 100644 (file)
@@ -41,6 +41,13 @@ const char *conf_get_configname(void)
        return name ? name : ".config";
 }
 
+const char *conf_get_autoconfig_name(void)
+{
+       char *name = getenv("KCONFIG_AUTOCONFIG");
+
+       return name ? name : "include/config/auto.conf";
+}
+
 static char *conf_expand_value(const char *in)
 {
        struct symbol *sym;
@@ -555,15 +562,14 @@ int conf_write(const char *name)
 
 int conf_split_config(void)
 {
-       char *name, path[128];
+       const char *name;
+       char path[128];
        char *s, *d, c;
        struct symbol *sym;
        struct stat sb;
        int res, i, fd;
 
-       name = getenv("KCONFIG_AUTOCONFIG");
-       if (!name)
-               name = "include/config/auto.conf";
+       name = conf_get_autoconfig_name();
        conf_read_simple(name, S_DEF_AUTO);
 
        if (chdir("include/config"))
@@ -670,7 +676,7 @@ int conf_write_autoconf(void)
 {
        struct symbol *sym;
        const char *str;
-       char *name;
+       const char *name;
        FILE *out, *out_h;
        time_t now;
        int i, l;
@@ -773,9 +779,7 @@ int conf_write_autoconf(void)
                name = "include/linux/autoconf.h";
        if (rename(".tmpconfig.h", name))
                return 1;
-       name = getenv("KCONFIG_AUTOCONFIG");
-       if (!name)
-               name = "include/config/auto.conf";
+       name = conf_get_autoconfig_name();
        /*
         * This must be the last step, kbuild has a dependency on auto.conf
         * and this marks the successful completion of the previous steps.
index 4a9af6f7886b8f1362fc593009f3e36374a5e3bd..f379b0bf8c9e7b8d45a6bd9a7f689af7165fcec6 100644 (file)
@@ -74,6 +74,7 @@ char *zconf_curname(void);
 
 /* confdata.c */
 const char *conf_get_configname(void);
+const char *conf_get_autoconfig_name(void);
 char *conf_get_default_confname(void);
 void sym_set_change_count(int count);
 void sym_add_change_count(int count);
index b2a878c936d63c793bca031b9b5d52f62b9e2e19..bcc6f19c3a35f8dedc9809ffefb5e77b1d16493a 100644 (file)
@@ -41,7 +41,8 @@ static void print_item(WINDOW * win, int choice, int selected)
        wmove(win, choice, check_x);
        wattrset(win, selected ? dlg.check_selected.atr
                 : dlg.check.atr);
-       wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' ');
+       if (!item_is_tag(':'))
+               wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' ');
 
        wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr);
        mvwaddch(win, choice, item_x, item_str()[0]);
index 6841e95c0989bcd2007b46ad4178e8ad28dd1bbf..3bcacb4bfd3af8284293a21fa202c886d3339126 100644 (file)
@@ -732,7 +732,12 @@ static void conf_choice(struct menu *menu)
                for (child = menu->list; child; child = child->next) {
                        if (!menu_is_visible(child))
                                continue;
-                       item_make("%s", _(menu_get_prompt(child)));
+                       if (child->sym)
+                               item_make("%s", _(menu_get_prompt(child)));
+                       else {
+                               item_make("*** %s ***", _(menu_get_prompt(child)));
+                               item_set_tag(':');
+                       }
                        item_set_data(child);
                        if (child->sym == active)
                                item_set_selected(1);
@@ -748,6 +753,9 @@ static void conf_choice(struct menu *menu)
                case 0:
                        if (selected) {
                                child = item_data();
+                               if (!child->sym)
+                                       break;
+
                                sym_set_tristate_value(child->sym, yes);
                        }
                        return;
index 5d0fd38b089b937614dee19073ec9a2657b26d22..ce7d508c75200b1072bb40c96e72701f742a6ddc 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <qapplication.h>
 #include <qmainwindow.h>
+#include <qdesktopwidget.h>
 #include <qtoolbar.h>
 #include <qlayout.h>
 #include <qvbox.h>
@@ -297,10 +298,10 @@ void ConfigLineEdit::show(ConfigItem* i)
 void ConfigLineEdit::keyPressEvent(QKeyEvent* e)
 {
        switch (e->key()) {
-       case Key_Escape:
+       case Qt::Key_Escape:
                break;
-       case Key_Return:
-       case Key_Enter:
+       case Qt::Key_Return:
+       case Qt::Key_Enter:
                sym_set_string_value(item->menu->sym, text().latin1());
                parent()->updateList(item);
                break;
@@ -639,7 +640,7 @@ void ConfigList::keyPressEvent(QKeyEvent* ev)
        struct menu *menu;
        enum prop_type type;
 
-       if (ev->key() == Key_Escape && mode != fullMode && mode != listMode) {
+       if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) {
                emit parentSelected();
                ev->accept();
                return;
@@ -652,8 +653,8 @@ void ConfigList::keyPressEvent(QKeyEvent* ev)
        item = (ConfigItem*)i;
 
        switch (ev->key()) {
-       case Key_Return:
-       case Key_Enter:
+       case Qt::Key_Return:
+       case Qt::Key_Enter:
                if (item->goParent) {
                        emit parentSelected();
                        break;
@@ -667,16 +668,16 @@ void ConfigList::keyPressEvent(QKeyEvent* ev)
                        emit menuSelected(menu);
                        break;
                }
-       case Key_Space:
+       case Qt::Key_Space:
                changeValue(item);
                break;
-       case Key_N:
+       case Qt::Key_N:
                setValue(item, no);
                break;
-       case Key_M:
+       case Qt::Key_M:
                setValue(item, mod);
                break;
-       case Key_Y:
+       case Qt::Key_Y:
                setValue(item, yes);
                break;
        default:
@@ -920,7 +921,7 @@ void ConfigView::updateListAll(void)
 }
 
 ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
-       : Parent(parent, name), menu(0), sym(0)
+       : Parent(parent, name), sym(0), menu(0)
 {
        if (name) {
                configSettings->beginGroup(name);
@@ -1199,7 +1200,7 @@ ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *nam
        layout1->addLayout(layout2);
 
        split = new QSplitter(this);
-       split->setOrientation(QSplitter::Vertical);
+       split->setOrientation(Qt::Vertical);
        list = new ConfigView(split, name);
        list->list->mode = listMode;
        info = new ConfigInfoView(split, name);
@@ -1275,7 +1276,7 @@ ConfigMainWindow::ConfigMainWindow(void)
        int x, y, width, height;
        char title[256];
 
-       QWidget *d = configApp->desktop();
+       QDesktopWidget *d = configApp->desktop();
        snprintf(title, sizeof(title), _("Linux Kernel v%s Configuration"),
                getenv("KERNELVERSION"));
        setCaption(title);
@@ -1290,14 +1291,14 @@ ConfigMainWindow::ConfigMainWindow(void)
                move(x, y);
 
        split1 = new QSplitter(this);
-       split1->setOrientation(QSplitter::Horizontal);
+       split1->setOrientation(Qt::Horizontal);
        setCentralWidget(split1);
 
        menuView = new ConfigView(split1, "menu");
        menuList = menuView->list;
 
        split2 = new QSplitter(split1);
-       split2->setOrientation(QSplitter::Vertical);
+       split2->setOrientation(Qt::Vertical);
 
        // create config tree
        configView = new ConfigView(split2, "config");
@@ -1315,18 +1316,18 @@ ConfigMainWindow::ConfigMainWindow(void)
        backAction = new QAction("Back", QPixmap(xpm_back), _("Back"), 0, this);
          connect(backAction, SIGNAL(activated()), SLOT(goBack()));
          backAction->setEnabled(FALSE);
-       QAction *quitAction = new QAction("Quit", _("&Quit"), CTRL+Key_Q, this);
+       QAction *quitAction = new QAction("Quit", _("&Quit"), Qt::CTRL + Qt::Key_Q, this);
          connect(quitAction, SIGNAL(activated()), SLOT(close()));
-       QAction *loadAction = new QAction("Load", QPixmap(xpm_load), _("&Load"), CTRL+Key_L, this);
+       QAction *loadAction = new QAction("Load", QPixmap(xpm_load), _("&Load"), Qt::CTRL + Qt::Key_L, this);
          connect(loadAction, SIGNAL(activated()), SLOT(loadConfig()));
-       saveAction = new QAction("Save", QPixmap(xpm_save), _("&Save"), CTRL+Key_S, this);
+       saveAction = new QAction("Save", QPixmap(xpm_save), _("&Save"), Qt::CTRL + Qt::Key_S, this);
          connect(saveAction, SIGNAL(activated()), SLOT(saveConfig()));
        conf_set_changed_callback(conf_changed);
        // Set saveAction's initial state
        conf_changed();
        QAction *saveAsAction = new QAction("Save As...", _("Save &As..."), 0, this);
          connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs()));
-       QAction *searchAction = new QAction("Find", _("&Find"), CTRL+Key_F, this);
+       QAction *searchAction = new QAction("Find", _("&Find"), Qt::CTRL + Qt::Key_F, this);
          connect(searchAction, SIGNAL(activated()), SLOT(searchConfig()));
        QAction *singleViewAction = new QAction("Single View", QPixmap(xpm_single_view), _("Single View"), 0, this);
          connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView()));
@@ -1447,7 +1448,7 @@ ConfigMainWindow::ConfigMainWindow(void)
 
 void ConfigMainWindow::loadConfig(void)
 {
-       QString s = QFileDialog::getOpenFileName(".config", NULL, this);
+       QString s = QFileDialog::getOpenFileName(conf_get_configname(), NULL, this);
        if (s.isNull())
                return;
        if (conf_read(QFile::encodeName(s)))
@@ -1463,7 +1464,7 @@ void ConfigMainWindow::saveConfig(void)
 
 void ConfigMainWindow::saveConfigAs(void)
 {
-       QString s = QFileDialog::getSaveFileName(".config", NULL, this);
+       QString s = QFileDialog::getSaveFileName(conf_get_configname(), NULL, this);
        if (s.isNull())
                return;
        if (conf_write(QFile::encodeName(s)))
@@ -1524,6 +1525,8 @@ void ConfigMainWindow::setMenuLink(struct menu *menu)
        case fullMode:
                list = configList;
                break;
+       default:
+               break;
        }
 
        if (list) {
@@ -1673,6 +1676,9 @@ void ConfigMainWindow::saveSettings(void)
        case fullMode :
                entry = "full";
                break;
+
+       default:
+               break;
        }
        configSettings->writeEntry("/listMode", entry);
 
index 3cc9f93690362ec220bb97a9d68b35cf74207dce..b6b2a46af14c400b556b61c3f6e1caeed792a87a 100644 (file)
@@ -46,8 +46,8 @@ int file_write_dep(const char *name)
                else
                        fprintf(out, "\t%s\n", file->name);
        }
-       fprintf(out, "\ninclude/config/auto.conf: \\\n"
-                    "\t$(deps_config)\n\n");
+       fprintf(out, "\n%s: \\\n"
+                    "\t$(deps_config)\n\n", conf_get_autoconfig_name());
 
        expr_list_for_each_sym(sym_env_list, e, sym) {
                struct property *prop;
@@ -61,7 +61,7 @@ int file_write_dep(const char *name)
                if (!value)
                        value = "";
                fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value);
-               fprintf(out, "include/config/auto.conf: FORCE\n");
+               fprintf(out, "%s: FORCE\n", conf_get_autoconfig_name());
                fprintf(out, "endif\n");
        }
 
index acd8c4a8e3e0b00f24eaf3331b70156becbecf60..a193fa3f5272fbdd95d979a59ed45fbc054211b7 100755 (executable)
@@ -5,7 +5,7 @@ use strict;
 ## Copyright (c) 1998 Michael Zucchi, All Rights Reserved        ##
 ## Copyright (C) 2000, 1  Tim Waugh <twaugh@redhat.com>          ##
 ## Copyright (C) 2001  Simon Huggins                             ##
-## Copyright (C) 2005-2008  Randy Dunlap                         ##
+## Copyright (C) 2005-2009  Randy Dunlap                         ##
 ##                                                              ##
 ## #define enhancements by Armin Kuster <akuster@mvista.com>    ##
 ## Copyright (c) 2000 MontaVista Software, Inc.                         ##
@@ -85,7 +85,7 @@ use strict;
 #
 # /**
 #  * my_function
-#  **/
+#  */
 #
 # If the Description: header tag is omitted, then there must be a blank line
 # after the last parameter specification.
@@ -105,7 +105,7 @@ use strict;
 #  */
 # etc.
 #
-# Beside functions you can also write documentation for structs, unions,
+# Besides functions you can also write documentation for structs, unions,
 # enums and typedefs. Instead of the function name you must write the name
 # of the declaration;  the struct/union/enum/typedef must always precede
 # the name. Nesting of declarations is not supported.
@@ -223,7 +223,7 @@ sub usage {
 }
 
 # read arguments
-if ($#ARGV==-1) {
+if ($#ARGV == -1) {
     usage();
 }
 
@@ -240,12 +240,12 @@ my $man_date = ('January', 'February', 'March', 'April', 'May', 'June',
   " " . ((localtime)[5]+1900);
 
 # Essentially these are globals
-# They probably want to be tidied up made more localised or summat.
-# CAVEAT EMPTOR!  Some of the others I localised may not want to be which
+# They probably want to be tidied up, made more localised or something.
+# CAVEAT EMPTOR!  Some of the others I localised may not want to be, which
 # could cause "use of undefined value" or other bugs.
-my ($function, %function_table,%parametertypes,$declaration_purpose);
-my ($type,$declaration_name,$return_type);
-my ($newsection,$newcontents,$prototype,$filelist, $brcount, %source_map);
+my ($function, %function_table, %parametertypes, $declaration_purpose);
+my ($type, $declaration_name, $return_type);
+my ($newsection, $newcontents, $prototype, $filelist, $brcount, %source_map);
 
 if (defined($ENV{'KBUILD_VERBOSE'})) {
        $verbose = "$ENV{'KBUILD_VERBOSE'}";
@@ -279,10 +279,10 @@ my $doc_special = "\@\%\$\&";
 my $doc_start = '^/\*\*\s*$'; # Allow whitespace at end of comment start.
 my $doc_end = '\*/';
 my $doc_com = '\s*\*\s*';
-my $doc_decl = $doc_com.'(\w+)';
-my $doc_sect = $doc_com.'(['.$doc_special.']?[\w\s]+):(.*)';
-my $doc_content = $doc_com.'(.*)';
-my $doc_block = $doc_com.'DOC:\s*(.*)?';
+my $doc_decl = $doc_com . '(\w+)';
+my $doc_sect = $doc_com . '([' . $doc_special . ']?[\w\s]+):(.*)';
+my $doc_content = $doc_com . '(.*)';
+my $doc_block = $doc_com . 'DOC:\s*(.*)?';
 
 my %constants;
 my %parameterdescs;
@@ -485,12 +485,12 @@ sub output_enum_html(%) {
     my %args = %{$_[0]};
     my ($parameter);
     my $count;
-    print "<h2>enum ".$args{'enum'}."</h2>\n";
+    print "<h2>enum " . $args{'enum'} . "</h2>\n";
 
-    print "<b>enum ".$args{'enum'}."</b> {<br>\n";
+    print "<b>enum " . $args{'enum'} . "</b> {<br>\n";
     $count = 0;
     foreach $parameter (@{$args{'parameterlist'}}) {
-       print " <b>".$parameter."</b>";
+       print " <b>" . $parameter . "</b>";
        if ($count != $#{$args{'parameterlist'}}) {
            $count++;
            print ",\n";
@@ -502,7 +502,7 @@ sub output_enum_html(%) {
     print "<h3>Constants</h3>\n";
     print "<dl>\n";
     foreach $parameter (@{$args{'parameterlist'}}) {
-       print "<dt><b>".$parameter."</b>\n";
+       print "<dt><b>" . $parameter . "</b>\n";
        print "<dd>";
        output_highlight($args{'parameterdescs'}{$parameter});
     }
@@ -516,9 +516,9 @@ sub output_typedef_html(%) {
     my %args = %{$_[0]};
     my ($parameter);
     my $count;
-    print "<h2>typedef ".$args{'typedef'}."</h2>\n";
+    print "<h2>typedef " . $args{'typedef'} . "</h2>\n";
 
-    print "<b>typedef ".$args{'typedef'}."</b>\n";
+    print "<b>typedef " . $args{'typedef'} . "</b>\n";
     output_section_html(@_);
     print "<hr>\n";
 }
@@ -528,8 +528,8 @@ sub output_struct_html(%) {
     my %args = %{$_[0]};
     my ($parameter);
 
-    print "<h2>".$args{'type'}." ".$args{'struct'}. " - " .$args{'purpose'}."</h2>\n";
-    print "<b>".$args{'type'}." ".$args{'struct'}."</b> {<br>\n";
+    print "<h2>" . $args{'type'} . " " . $args{'struct'} . " - " . $args{'purpose'} . "</h2>\n";
+    print "<b>" . $args{'type'} . " " . $args{'struct'} . "</b> {<br>\n";
     foreach $parameter (@{$args{'parameterlist'}}) {
        if ($parameter =~ /^#/) {
                print "$parameter<br>\n";
@@ -561,7 +561,7 @@ sub output_struct_html(%) {
        $parameter_name =~ s/\[.*//;
 
        ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
-       print "<dt><b>".$parameter."</b>\n";
+       print "<dt><b>" . $parameter . "</b>\n";
        print "<dd>";
        output_highlight($args{'parameterdescs'}{$parameter_name});
     }
@@ -576,9 +576,9 @@ sub output_function_html(%) {
     my ($parameter, $section);
     my $count;
 
-    print "<h2>" .$args{'function'}." - ".$args{'purpose'}."</h2>\n";
-    print "<i>".$args{'functiontype'}."</i>\n";
-    print "<b>".$args{'function'}."</b>\n";
+    print "<h2>" . $args{'function'} . " - " . $args{'purpose'} . "</h2>\n";
+    print "<i>" . $args{'functiontype'} . "</i>\n";
+    print "<b>" . $args{'function'} . "</b>\n";
     print "(";
     $count = 0;
     foreach $parameter (@{$args{'parameterlist'}}) {
@@ -587,7 +587,7 @@ sub output_function_html(%) {
            # pointer-to-function
            print "<i>$1</i><b>$parameter</b>) <i>($2)</i>";
        } else {
-           print "<i>".$type."</i> <b>".$parameter."</b>";
+           print "<i>" . $type . "</i> <b>" . $parameter . "</b>";
        }
        if ($count != $#{$args{'parameterlist'}}) {
            $count++;
@@ -603,7 +603,7 @@ sub output_function_html(%) {
        $parameter_name =~ s/\[.*//;
 
        ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
-       print "<dt><b>".$parameter."</b>\n";
+       print "<dt><b>" . $parameter . "</b>\n";
        print "<dd>";
        output_highlight($args{'parameterdescs'}{$parameter_name});
     }
@@ -657,7 +657,7 @@ sub output_function_xml(%) {
     my $count;
     my $id;
 
-    $id = "API-".$args{'function'};
+    $id = "API-" . $args{'function'};
     $id =~ s/[^A-Za-z0-9]/-/g;
 
     print "<refentry id=\"$id\">\n";
@@ -667,12 +667,12 @@ sub output_function_xml(%) {
     print " <date>$man_date</date>\n";
     print "</refentryinfo>\n";
     print "<refmeta>\n";
-    print " <refentrytitle><phrase>".$args{'function'}."</phrase></refentrytitle>\n";
+    print " <refentrytitle><phrase>" . $args{'function'} . "</phrase></refentrytitle>\n";
     print " <manvolnum>9</manvolnum>\n";
     print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
     print "</refmeta>\n";
     print "<refnamediv>\n";
-    print " <refname>".$args{'function'}."</refname>\n";
+    print " <refname>" . $args{'function'} . "</refname>\n";
     print " <refpurpose>\n";
     print "  ";
     output_highlight ($args{'purpose'});
@@ -682,8 +682,8 @@ sub output_function_xml(%) {
     print "<refsynopsisdiv>\n";
     print " <title>Synopsis</title>\n";
     print "  <funcsynopsis><funcprototype>\n";
-    print "   <funcdef>".$args{'functiontype'}." ";
-    print "<function>".$args{'function'}." </function></funcdef>\n";
+    print "   <funcdef>" . $args{'functiontype'} . " ";
+    print "<function>" . $args{'function'} . " </function></funcdef>\n";
 
     $count = 0;
     if ($#{$args{'parameterlist'}} >= 0) {
@@ -694,7 +694,7 @@ sub output_function_xml(%) {
                print "   <paramdef>$1<parameter>$parameter</parameter>)\n";
                print "     <funcparams>$2</funcparams></paramdef>\n";
            } else {
-               print "   <paramdef>".$type;
+               print "   <paramdef>" . $type;
                print " <parameter>$parameter</parameter></paramdef>\n";
            }
        }
@@ -734,7 +734,7 @@ sub output_struct_xml(%) {
     my ($parameter, $section);
     my $id;
 
-    $id = "API-struct-".$args{'struct'};
+    $id = "API-struct-" . $args{'struct'};
     $id =~ s/[^A-Za-z0-9]/-/g;
 
     print "<refentry id=\"$id\">\n";
@@ -744,12 +744,12 @@ sub output_struct_xml(%) {
     print " <date>$man_date</date>\n";
     print "</refentryinfo>\n";
     print "<refmeta>\n";
-    print " <refentrytitle><phrase>".$args{'type'}." ".$args{'struct'}."</phrase></refentrytitle>\n";
+    print " <refentrytitle><phrase>" . $args{'type'} . " " . $args{'struct'} . "</phrase></refentrytitle>\n";
     print " <manvolnum>9</manvolnum>\n";
     print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
     print "</refmeta>\n";
     print "<refnamediv>\n";
-    print " <refname>".$args{'type'}." ".$args{'struct'}."</refname>\n";
+    print " <refname>" . $args{'type'} . " " . $args{'struct'} . "</refname>\n";
     print " <refpurpose>\n";
     print "  ";
     output_highlight ($args{'purpose'});
@@ -759,7 +759,7 @@ sub output_struct_xml(%) {
     print "<refsynopsisdiv>\n";
     print " <title>Synopsis</title>\n";
     print "  <programlisting>\n";
-    print $args{'type'}." ".$args{'struct'}." {\n";
+    print $args{'type'} . " " . $args{'struct'} . " {\n";
     foreach $parameter (@{$args{'parameterlist'}}) {
        if ($parameter =~ /^#/) {
            print "$parameter\n";
@@ -779,7 +779,7 @@ sub output_struct_xml(%) {
            # bitfield
            print "  $1 $parameter$2;\n";
        } else {
-           print "  ".$type." ".$parameter.";\n";
+           print "  " . $type . " " . $parameter . ";\n";
        }
     }
     print "};";
@@ -824,7 +824,7 @@ sub output_enum_xml(%) {
     my $count;
     my $id;
 
-    $id = "API-enum-".$args{'enum'};
+    $id = "API-enum-" . $args{'enum'};
     $id =~ s/[^A-Za-z0-9]/-/g;
 
     print "<refentry id=\"$id\">\n";
@@ -834,12 +834,12 @@ sub output_enum_xml(%) {
     print " <date>$man_date</date>\n";
     print "</refentryinfo>\n";
     print "<refmeta>\n";
-    print " <refentrytitle><phrase>enum ".$args{'enum'}."</phrase></refentrytitle>\n";
+    print " <refentrytitle><phrase>enum " . $args{'enum'} . "</phrase></refentrytitle>\n";
     print " <manvolnum>9</manvolnum>\n";
     print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
     print "</refmeta>\n";
     print "<refnamediv>\n";
-    print " <refname>enum ".$args{'enum'}."</refname>\n";
+    print " <refname>enum " . $args{'enum'} . "</refname>\n";
     print " <refpurpose>\n";
     print "  ";
     output_highlight ($args{'purpose'});
@@ -849,7 +849,7 @@ sub output_enum_xml(%) {
     print "<refsynopsisdiv>\n";
     print " <title>Synopsis</title>\n";
     print "  <programlisting>\n";
-    print "enum ".$args{'enum'}." {\n";
+    print "enum " . $args{'enum'} . " {\n";
     $count = 0;
     foreach $parameter (@{$args{'parameterlist'}}) {
        print "  $parameter";
@@ -891,7 +891,7 @@ sub output_typedef_xml(%) {
     my ($parameter, $section);
     my $id;
 
-    $id = "API-typedef-".$args{'typedef'};
+    $id = "API-typedef-" . $args{'typedef'};
     $id =~ s/[^A-Za-z0-9]/-/g;
 
     print "<refentry id=\"$id\">\n";
@@ -901,11 +901,11 @@ sub output_typedef_xml(%) {
     print " <date>$man_date</date>\n";
     print "</refentryinfo>\n";
     print "<refmeta>\n";
-    print " <refentrytitle><phrase>typedef ".$args{'typedef'}."</phrase></refentrytitle>\n";
+    print " <refentrytitle><phrase>typedef " . $args{'typedef'} . "</phrase></refentrytitle>\n";
     print " <manvolnum>9</manvolnum>\n";
     print "</refmeta>\n";
     print "<refnamediv>\n";
-    print " <refname>typedef ".$args{'typedef'}."</refname>\n";
+    print " <refname>typedef " . $args{'typedef'} . "</refname>\n";
     print " <refpurpose>\n";
     print "  ";
     output_highlight ($args{'purpose'});
@@ -914,7 +914,7 @@ sub output_typedef_xml(%) {
 
     print "<refsynopsisdiv>\n";
     print " <title>Synopsis</title>\n";
-    print "  <synopsis>typedef ".$args{'typedef'}.";</synopsis>\n";
+    print "  <synopsis>typedef " . $args{'typedef'} . ";</synopsis>\n";
     print "</refsynopsisdiv>\n";
 
     output_section_xml(@_);
@@ -963,15 +963,15 @@ sub output_function_gnome {
     my $count;
     my $id;
 
-    $id = $args{'module'}."-".$args{'function'};
+    $id = $args{'module'} . "-" . $args{'function'};
     $id =~ s/[^A-Za-z0-9]/-/g;
 
     print "<sect2>\n";
-    print " <title id=\"$id\">".$args{'function'}."</title>\n";
+    print " <title id=\"$id\">" . $args{'function'} . "</title>\n";
 
     print "  <funcsynopsis>\n";
-    print "   <funcdef>".$args{'functiontype'}." ";
-    print "<function>".$args{'function'}." ";
+    print "   <funcdef>" . $args{'functiontype'} . " ";
+    print "<function>" . $args{'function'} . " ";
     print "</function></funcdef>\n";
 
     $count = 0;
@@ -983,7 +983,7 @@ sub output_function_gnome {
                print "   <paramdef>$1 <parameter>$parameter</parameter>)\n";
                print "     <funcparams>$2</funcparams></paramdef>\n";
            } else {
-               print "   <paramdef>".$type;
+               print "   <paramdef>" . $type;
                print " <parameter>$parameter</parameter></paramdef>\n";
            }
        }
@@ -1043,13 +1043,13 @@ sub output_function_man(%) {
     print ".TH \"$args{'function'}\" 9 \"$args{'function'}\" \"$man_date\" \"Kernel Hacker's Manual\" LINUX\n";
 
     print ".SH NAME\n";
-    print $args{'function'}." \\- ".$args{'purpose'}."\n";
+    print $args{'function'} . " \\- " . $args{'purpose'} . "\n";
 
     print ".SH SYNOPSIS\n";
     if ($args{'functiontype'} ne "") {
-       print ".B \"".$args{'functiontype'}."\" ".$args{'function'}."\n";
+       print ".B \"" . $args{'functiontype'} . "\" " . $args{'function'} . "\n";
     } else {
-       print ".B \"".$args{'function'}."\n";
+       print ".B \"" . $args{'function'} . "\n";
     }
     $count = 0;
     my $parenth = "(";
@@ -1061,10 +1061,10 @@ sub output_function_man(%) {
        $type = $args{'parametertypes'}{$parameter};
        if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
            # pointer-to-function
-           print ".BI \"".$parenth.$1."\" ".$parameter." \") (".$2.")".$post."\"\n";
+           print ".BI \"" . $parenth . $1 . "\" " . $parameter . " \") (" . $2 . ")" . $post . "\"\n";
        } else {
            $type =~ s/([^\*])$/$1 /;
-           print ".BI \"".$parenth.$type."\" ".$parameter." \"".$post."\"\n";
+           print ".BI \"" . $parenth . $type . "\" " . $parameter . " \"" . $post . "\"\n";
        }
        $count++;
        $parenth = "";
@@ -1075,7 +1075,7 @@ sub output_function_man(%) {
        my $parameter_name = $parameter;
        $parameter_name =~ s/\[.*//;
 
-       print ".IP \"".$parameter."\" 12\n";
+       print ".IP \"" . $parameter . "\" 12\n";
        output_highlight($args{'parameterdescs'}{$parameter_name});
     }
     foreach $section (@{$args{'sectionlist'}}) {
@@ -1094,10 +1094,10 @@ sub output_enum_man(%) {
     print ".TH \"$args{'module'}\" 9 \"enum $args{'enum'}\" \"$man_date\" \"API Manual\" LINUX\n";
 
     print ".SH NAME\n";
-    print "enum ".$args{'enum'}." \\- ".$args{'purpose'}."\n";
+    print "enum " . $args{'enum'} . " \\- " . $args{'purpose'} . "\n";
 
     print ".SH SYNOPSIS\n";
-    print "enum ".$args{'enum'}." {\n";
+    print "enum " . $args{'enum'} . " {\n";
     $count = 0;
     foreach my $parameter (@{$args{'parameterlist'}}) {
        print ".br\n.BI \"    $parameter\"\n";
@@ -1116,7 +1116,7 @@ sub output_enum_man(%) {
        my $parameter_name = $parameter;
        $parameter_name =~ s/\[.*//;
 
-       print ".IP \"".$parameter."\" 12\n";
+       print ".IP \"" . $parameter . "\" 12\n";
        output_highlight($args{'parameterdescs'}{$parameter_name});
     }
     foreach $section (@{$args{'sectionlist'}}) {
@@ -1131,13 +1131,13 @@ sub output_struct_man(%) {
     my %args = %{$_[0]};
     my ($parameter, $section);
 
-    print ".TH \"$args{'module'}\" 9 \"".$args{'type'}." ".$args{'struct'}."\" \"$man_date\" \"API Manual\" LINUX\n";
+    print ".TH \"$args{'module'}\" 9 \"" . $args{'type'} . " " . $args{'struct'} . "\" \"$man_date\" \"API Manual\" LINUX\n";
 
     print ".SH NAME\n";
-    print $args{'type'}." ".$args{'struct'}." \\- ".$args{'purpose'}."\n";
+    print $args{'type'} . " " . $args{'struct'} . " \\- " . $args{'purpose'} . "\n";
 
     print ".SH SYNOPSIS\n";
-    print $args{'type'}." ".$args{'struct'}." {\n.br\n";
+    print $args{'type'} . " " . $args{'struct'} . " {\n.br\n";
 
     foreach my $parameter (@{$args{'parameterlist'}}) {
        if ($parameter =~ /^#/) {
@@ -1151,13 +1151,13 @@ sub output_struct_man(%) {
        $type = $args{'parametertypes'}{$parameter};
        if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
            # pointer-to-function
-           print ".BI \"    ".$1."\" ".$parameter." \") (".$2.")"."\"\n;\n";
+           print ".BI \"    " . $1 . "\" " . $parameter . " \") (" . $2 . ")" . "\"\n;\n";
        } elsif ($type =~ m/^(.*?)\s*(:.*)/) {
            # bitfield
-           print ".BI \"    ".$1."\ \" ".$parameter.$2." \""."\"\n;\n";
+           print ".BI \"    " . $1 . "\ \" " . $parameter . $2 . " \"" . "\"\n;\n";
        } else {
            $type =~ s/([^\*])$/$1 /;
-           print ".BI \"    ".$type."\" ".$parameter." \""."\"\n;\n";
+           print ".BI \"    " . $type . "\" " . $parameter . " \"" . "\"\n;\n";
        }
        print "\n.br\n";
     }
@@ -1171,7 +1171,7 @@ sub output_struct_man(%) {
        $parameter_name =~ s/\[.*//;
 
        ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
-       print ".IP \"".$parameter."\" 12\n";
+       print ".IP \"" . $parameter . "\" 12\n";
        output_highlight($args{'parameterdescs'}{$parameter_name});
     }
     foreach $section (@{$args{'sectionlist'}}) {
@@ -1189,7 +1189,7 @@ sub output_typedef_man(%) {
     print ".TH \"$args{'module'}\" 9 \"$args{'typedef'}\" \"$man_date\" \"API Manual\" LINUX\n";
 
     print ".SH NAME\n";
-    print "typedef ".$args{'typedef'}." \\- ".$args{'purpose'}."\n";
+    print "typedef " . $args{'typedef'} . " \\- " . $args{'purpose'} . "\n";
 
     foreach $section (@{$args{'sectionlist'}}) {
        print ".SH \"$section\"\n";
@@ -1218,13 +1218,13 @@ sub output_function_text(%) {
     my $start;
 
     print "Name:\n\n";
-    print $args{'function'}." - ".$args{'purpose'}."\n";
+    print $args{'function'} . " - " . $args{'purpose'} . "\n";
 
     print "\nSynopsis:\n\n";
     if ($args{'functiontype'} ne "") {
-       $start = $args{'functiontype'}." ".$args{'function'}." (";
+       $start = $args{'functiontype'} . " " . $args{'function'} . " (";
     } else {
-       $start = $args{'function'}." (";
+       $start = $args{'function'} . " (";
     }
     print $start;
 
@@ -1233,9 +1233,9 @@ sub output_function_text(%) {
        $type = $args{'parametertypes'}{$parameter};
        if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
            # pointer-to-function
-           print $1.$parameter.") (".$2;
+           print $1 . $parameter . ") (" . $2;
        } else {
-           print $type." ".$parameter;
+           print $type . " " . $parameter;
        }
        if ($count != $#{$args{'parameterlist'}}) {
            $count++;
@@ -1251,7 +1251,7 @@ sub output_function_text(%) {
        my $parameter_name = $parameter;
        $parameter_name =~ s/\[.*//;
 
-       print $parameter."\n\t".$args{'parameterdescs'}{$parameter_name}."\n";
+       print $parameter . "\n\t" . $args{'parameterdescs'}{$parameter_name} . "\n";
     }
     output_section_text(@_);
 }
@@ -1276,8 +1276,8 @@ sub output_enum_text(%) {
     my $count;
     print "Enum:\n\n";
 
-    print "enum ".$args{'enum'}." - ".$args{'purpose'}."\n\n";
-    print "enum ".$args{'enum'}." {\n";
+    print "enum " . $args{'enum'} . " - " . $args{'purpose'} . "\n\n";
+    print "enum " . $args{'enum'} . " {\n";
     $count = 0;
     foreach $parameter (@{$args{'parameterlist'}}) {
        print "\t$parameter";
@@ -1292,7 +1292,7 @@ sub output_enum_text(%) {
     print "Constants:\n\n";
     foreach $parameter (@{$args{'parameterlist'}}) {
        print "$parameter\n\t";
-       print $args{'parameterdescs'}{$parameter}."\n";
+       print $args{'parameterdescs'}{$parameter} . "\n";
     }
 
     output_section_text(@_);
@@ -1305,7 +1305,7 @@ sub output_typedef_text(%) {
     my $count;
     print "Typedef:\n\n";
 
-    print "typedef ".$args{'typedef'}." - ".$args{'purpose'}."\n";
+    print "typedef " . $args{'typedef'} . " - " . $args{'purpose'} . "\n";
     output_section_text(@_);
 }
 
@@ -1314,8 +1314,8 @@ sub output_struct_text(%) {
     my %args = %{$_[0]};
     my ($parameter);
 
-    print $args{'type'}." ".$args{'struct'}." - ".$args{'purpose'}."\n\n";
-    print $args{'type'}." ".$args{'struct'}." {\n";
+    print $args{'type'} . " " . $args{'struct'} . " - " . $args{'purpose'} . "\n\n";
+    print $args{'type'} . " " . $args{'struct'} . " {\n";
     foreach $parameter (@{$args{'parameterlist'}}) {
        if ($parameter =~ /^#/) {
            print "$parameter\n";
@@ -1334,7 +1334,7 @@ sub output_struct_text(%) {
            # bitfield
            print "\t$1 $parameter$2;\n";
        } else {
-           print "\t".$type." ".$parameter.";\n";
+           print "\t" . $type . " " . $parameter . ";\n";
        }
     }
     print "};\n\n";
@@ -1348,7 +1348,7 @@ sub output_struct_text(%) {
 
        ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
        print "$parameter\n\t";
-       print $args{'parameterdescs'}{$parameter_name}."\n";
+       print $args{'parameterdescs'}{$parameter_name} . "\n";
     }
     print "\n";
     output_section_text(@_);
@@ -1387,7 +1387,7 @@ sub output_declaration {
 # generic output function - calls the right one based on current output mode.
 sub output_blockhead {
     no strict 'refs';
-    my $func = "output_blockhead_".$output_mode;
+    my $func = "output_blockhead_" . $output_mode;
     &$func(@_);
     $section_counter++;
 }
@@ -1398,7 +1398,7 @@ sub output_blockhead {
 sub dump_declaration($$) {
     no strict 'refs';
     my ($prototype, $file) = @_;
-    my $func = "dump_".$decl_type;
+    my $func = "dump_" . $decl_type;
     &$func(@_);
 }
 
@@ -1645,7 +1645,7 @@ sub push_parameter($$$) {
                    "or member '$param' not " .
                    "described in '$declaration_name'\n";
            }
-           print STDERR "Warning(${file}:$.):".
+           print STDERR "Warning(${file}:$.):" .
                         " No description found for parameter '$param'\n";
            ++$warnings;
        }
@@ -1929,7 +1929,7 @@ sub process_state3_type($$) {
            ($2 eq '{') && $brcount++;
            ($2 eq '}') && $brcount--;
            if (($2 eq ';') && ($brcount == 0)) {
-               dump_declaration($prototype,$file);
+               dump_declaration($prototype, $file);
                reset_state();
                last;
            }
@@ -2106,7 +2106,7 @@ sub process_file($) {
                    $section = $section_default;
                    $contents = "";
                } else {
-                   $contents .= $1."\n";
+                   $contents .= $1 . "\n";
                }
            } else {
                # i dont know - bad line?  ignore.
index a3344285ccf4cbd17a66c8fd8118041e3ab5d025..40e0045876ee4fa954039dc1bed7c88a1db1d5d2 100644 (file)
@@ -641,7 +641,7 @@ static int do_virtio_entry(const char *filename, struct virtio_device_id *id,
        id->vendor = TO_NATIVE(id->vendor);
 
        strcpy(alias, "virtio:");
-       ADD(alias, "d", 1, id->device);
+       ADD(alias, "d", id->device != VIRTIO_DEV_ANY_ID, id->device);
        ADD(alias, "v", id->vendor != VIRTIO_DEV_ANY_ID, id->vendor);
 
        add_wildcard(alias);
index 161b7846733e5ee5988ef42d5bf114cd8f0eef4d..4522948a012e0fb1d772949679a8c2a9af529345 100644 (file)
@@ -763,6 +763,8 @@ static void check_section(const char *modname, struct elf_info *elf,
 
 
 #define ALL_INIT_DATA_SECTIONS \
+       ".init.setup$", ".init.rodata$", \
+       ".devinit.rodata$", ".cpuinit.rodata$", ".meminit.rodata$" \
        ".init.data$", ".devinit.data$", ".cpuinit.data$", ".meminit.data$"
 #define ALL_EXIT_DATA_SECTIONS \
        ".exit.data$", ".devexit.data$", ".cpuexit.data$", ".memexit.data$"
@@ -772,21 +774,23 @@ static void check_section(const char *modname, struct elf_info *elf,
 #define ALL_EXIT_TEXT_SECTIONS \
        ".exit.text$", ".devexit.text$", ".cpuexit.text$", ".memexit.text$"
 
-#define ALL_INIT_SECTIONS ALL_INIT_DATA_SECTIONS, ALL_INIT_TEXT_SECTIONS
-#define ALL_EXIT_SECTIONS ALL_EXIT_DATA_SECTIONS, ALL_EXIT_TEXT_SECTIONS
+#define ALL_INIT_SECTIONS INIT_SECTIONS, DEV_INIT_SECTIONS, \
+       CPU_INIT_SECTIONS, MEM_INIT_SECTIONS
+#define ALL_EXIT_SECTIONS EXIT_SECTIONS, DEV_EXIT_SECTIONS, \
+       CPU_EXIT_SECTIONS, MEM_EXIT_SECTIONS
 
 #define DATA_SECTIONS ".data$", ".data.rel$"
 #define TEXT_SECTIONS ".text$"
 
-#define INIT_SECTIONS      ".init.data$", ".init.text$"
-#define DEV_INIT_SECTIONS  ".devinit.data$", ".devinit.text$"
-#define CPU_INIT_SECTIONS  ".cpuinit.data$", ".cpuinit.text$"
-#define MEM_INIT_SECTIONS  ".meminit.data$", ".meminit.text$"
+#define INIT_SECTIONS      ".init.*"
+#define DEV_INIT_SECTIONS  ".devinit.*"
+#define CPU_INIT_SECTIONS  ".cpuinit.*"
+#define MEM_INIT_SECTIONS  ".meminit.*"
 
-#define EXIT_SECTIONS      ".exit.data$", ".exit.text$"
-#define DEV_EXIT_SECTIONS  ".devexit.data$", ".devexit.text$"
-#define CPU_EXIT_SECTIONS  ".cpuexit.data$", ".cpuexit.text$"
-#define MEM_EXIT_SECTIONS  ".memexit.data$", ".memexit.text$"
+#define EXIT_SECTIONS      ".exit.*"
+#define DEV_EXIT_SECTIONS  ".devexit.*"
+#define CPU_EXIT_SECTIONS  ".cpuexit.*"
+#define MEM_EXIT_SECTIONS  ".memexit.*"
 
 /* init data sections */
 static const char *init_data_sections[] = { ALL_INIT_DATA_SECTIONS, NULL };
@@ -869,12 +873,36 @@ const struct sectioncheck sectioncheck[] = {
        .tosec   = { INIT_SECTIONS, NULL },
        .mismatch = XXXINIT_TO_INIT,
 },
+/* Do not reference cpuinit code/data from meminit code/data */
+{
+       .fromsec = { MEM_INIT_SECTIONS, NULL },
+       .tosec   = { CPU_INIT_SECTIONS, NULL },
+       .mismatch = XXXINIT_TO_INIT,
+},
+/* Do not reference meminit code/data from cpuinit code/data */
+{
+       .fromsec = { CPU_INIT_SECTIONS, NULL },
+       .tosec   = { MEM_INIT_SECTIONS, NULL },
+       .mismatch = XXXINIT_TO_INIT,
+},
 /* Do not reference exit code/data from devexit/cpuexit/memexit code/data */
 {
        .fromsec = { DEV_EXIT_SECTIONS, CPU_EXIT_SECTIONS, MEM_EXIT_SECTIONS, NULL },
        .tosec   = { EXIT_SECTIONS, NULL },
        .mismatch = XXXEXIT_TO_EXIT,
 },
+/* Do not reference cpuexit code/data from memexit code/data */
+{
+       .fromsec = { MEM_EXIT_SECTIONS, NULL },
+       .tosec   = { CPU_EXIT_SECTIONS, NULL },
+       .mismatch = XXXEXIT_TO_EXIT,
+},
+/* Do not reference memexit code/data from cpuexit code/data */
+{
+       .fromsec = { CPU_EXIT_SECTIONS, NULL },
+       .tosec   = { MEM_EXIT_SECTIONS, NULL },
+       .mismatch = XXXEXIT_TO_EXIT,
+},
 /* Do not use exit code/data from init code */
 {
        .fromsec = { ALL_INIT_SECTIONS, NULL },
@@ -1168,7 +1196,7 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch,
                "The variable %s references\n"
                "the %s %s%s%s\n"
                "If the reference is valid then annotate the\n"
-               "variable with __init* (see linux/init.h) "
+               "variable with __init* or __refdata (see linux/init.h) "
                "or name the variable:\n",
                fromsym, to, sec2annotation(tosec), tosym, to_p);
                while (*s)
index 1264b8e2829d49a497a02afb9059f862736700f6..01c2d13dd0204367b9655ee1c202f0a437ed2398 100644 (file)
@@ -1,38 +1,58 @@
 #!/bin/sh
 #
-# builddeb 1.2
+# builddeb 1.3
 # Copyright 2003 Wichert Akkerman <wichert@wiggy.net>
 #
 # Simple script to generate a deb package for a Linux kernel. All the
-# complexity of what to do with a kernel after it is installer or removed
+# complexity of what to do with a kernel after it is installed or removed
 # is left to other scripts and packages: they can install scripts in the
-# /etc/kernel/{pre,post}{inst,rm}.d/ directories that will be called on
-# package install and removal.
+# /etc/kernel/{pre,post}{inst,rm}.d/ directories (or an alternative location
+# specified in KDEB_HOOKDIR) that will be called on package install and
+# removal.
 
 set -e
 
+create_package() {
+       local pname="$1" pdir="$2"
+
+       cp debian/copyright "$pdir/usr/share/doc/$pname/"
+
+       # Fix ownership and permissions
+       chown -R root:root "$pdir"
+       chmod -R go-w "$pdir"
+
+       # Create the package
+       dpkg-gencontrol -isp -p$pname -P"$pdir"
+       dpkg --build "$pdir" ..
+}
+
 # Some variables and settings used throughout the script
 version=$KERNELRELEASE
-revision=`cat .version`
+revision=$(cat .version)
+if [ -n "$KDEB_PKGVERSION" ]; then
+       packageversion=$KDEB_PKGVERSION
+else
+       packageversion=$version-$revision
+fi
 tmpdir="$objtree/debian/tmp"
 fwdir="$objtree/debian/fwtmp"
-packagename=linux-$version
+packagename=linux-image-$version
 fwpackagename=linux-firmware-image
 
-if [ "$ARCH" == "um" ] ; then
+if [ "$ARCH" = "um" ] ; then
        packagename=user-mode-linux-$version
 fi
 
 # Setup the directory structure
 rm -rf "$tmpdir" "$fwdir"
-mkdir -p "$tmpdir/DEBIAN" "$tmpdir/lib" "$tmpdir/boot"
-mkdir -p "$fwdir/DEBIAN" "$fwdir/lib"
-if [ "$ARCH" == "um" ] ; then
-       mkdir -p "$tmpdir/usr/lib/uml/modules/$version" "$tmpdir/usr/share/doc/$packagename" "$tmpdir/usr/bin"
+mkdir -p "$tmpdir/DEBIAN" "$tmpdir/lib" "$tmpdir/boot" "$tmpdir/usr/share/doc/$packagename"
+mkdir -p "$fwdir/DEBIAN" "$fwdir/lib" "$fwdir/usr/share/doc/$fwpackagename"
+if [ "$ARCH" = "um" ] ; then
+       mkdir -p "$tmpdir/usr/lib/uml/modules/$version" "$tmpdir/usr/bin"
 fi
 
 # Build and install the kernel
-if [ "$ARCH" == "um" ] ; then
+if [ "$ARCH" = "um" ] ; then
        $MAKE linux
        cp System.map "$tmpdir/usr/lib/uml/modules/$version/System.map"
        cp .config "$tmpdir/usr/share/doc/$packagename/config"
@@ -41,53 +61,100 @@ if [ "$ARCH" == "um" ] ; then
 else 
        cp System.map "$tmpdir/boot/System.map-$version"
        cp .config "$tmpdir/boot/config-$version"
-       cp $KBUILD_IMAGE "$tmpdir/boot/vmlinuz-$version"
+       # Not all arches include the boot path in KBUILD_IMAGE
+       if ! cp $KBUILD_IMAGE "$tmpdir/boot/vmlinuz-$version"; then
+               cp arch/$ARCH/boot/$KBUILD_IMAGE "$tmpdir/boot/vmlinuz-$version"
+       fi
 fi
 
 if grep -q '^CONFIG_MODULES=y' .config ; then
        INSTALL_MOD_PATH="$tmpdir" make KBUILD_SRC= modules_install
-       if [ "$ARCH" == "um" ] ; then
+       if [ "$ARCH" = "um" ] ; then
                mv "$tmpdir/lib/modules/$version"/* "$tmpdir/usr/lib/uml/modules/$version/"
                rmdir "$tmpdir/lib/modules/$version"
        fi
 fi
 
 # Install the maintainer scripts
+# Note: hook scripts under /etc/kernel are also executed by official Debian
+# kernel packages, as well as kernel packages built using make-kpkg
+debhookdir=${KDEB_HOOKDIR:-/etc/kernel}
 for script in postinst postrm preinst prerm ; do
-       mkdir -p "$tmpdir/etc/kernel/$script.d"
+       mkdir -p "$tmpdir$debhookdir/$script.d"
        cat <<EOF > "$tmpdir/DEBIAN/$script"
 #!/bin/sh
 
 set -e
 
-test -d /etc/kernel/$script.d && run-parts --arg="$version" /etc/kernel/$script.d
+# Pass maintainer script parameters to hook scripts
+export DEB_MAINT_PARAMS="\$@"
+
+test -d $debhookdir/$script.d && run-parts --arg="$version" $debhookdir/$script.d
 exit 0
 EOF
        chmod 755 "$tmpdir/DEBIAN/$script"
 done
 
-name="Kernel Compiler <$(id -nu)@$(hostname -f)>"
+# Try to determine maintainer and email values
+if [ -n "$DEBEMAIL" ]; then
+       email=$DEBEMAIL
+elif [ -n "$EMAIL" ]; then
+       email=$EMAIL
+else
+       email=$(id -nu)@$(hostname -f)
+fi
+if [ -n "$DEBFULLNAME" ]; then
+       name=$DEBFULLNAME
+elif [ -n "$NAME" ]; then
+       name=$NAME
+else
+       name="Anonymous"
+fi
+maintainer="$name <$email>"
+
 # Generate a simple changelog template
 cat <<EOF > debian/changelog
-linux ($version-$revision) unstable; urgency=low
+linux-upstream ($packageversion) unstable; urgency=low
 
-  * A standard release
+  * Custom built Linux kernel.
 
- -- $name  $(date -R)
+ -- $maintainer  $(date -R)
 EOF
 
-# Generate a control file
-if [ "$ARCH" == "um" ]; then
+# Generate copyright file
+cat <<EOF > debian/copyright
+This is a packacked upstream version of the Linux kernel.
+
+The sources may be found at most Linux ftp sites, including:
+ftp://ftp.kernel.org/pub/linux/kernel
 
+Copyright: 1991 - 2009 Linus Torvalds and others.
+
+The git repository for mainline kernel development is at:
+git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
+
+    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 dated June, 1991.
+
+On Debian GNU/Linux systems, the complete text of the GNU General Public
+License version 2 can be found in \`/usr/share/common-licenses/GPL-2'.
+EOF
+
+# Generate a control file
 cat <<EOF > debian/control
-Source: linux
-Section: base
+Source: linux-upstream
+Section: admin
 Priority: optional
-Maintainer: $name
-Standards-Version: 3.6.1
+Maintainer: $maintainer
+Standards-Version: 3.8.1
+EOF
+
+if [ "$ARCH" = "um" ]; then
+       cat <<EOF >> debian/control
 
 Package: $packagename
-Provides: kernel-image-$version, linux-image-$version
+Provides: linux-image, linux-image-2.6, linux-modules-$version
 Architecture: any
 Description: User Mode Linux kernel, version $version
  User-mode Linux is a port of the Linux kernel to its own system call
@@ -97,30 +164,22 @@ Description: User Mode Linux kernel, version $version
  many other things.
  .
  This package contains the Linux kernel, modules and corresponding other
- files version $version
+ files, version: $version.
 EOF
 
 else
-cat <<EOF > debian/control
-Source: linux
-Section: base
-Priority: optional
-Maintainer: $name
-Standards-Version: 3.6.1
+       cat <<EOF >> debian/control
 
 Package: $packagename
-Provides: kernel-image-$version, linux-image-$version
+Provides: linux-image, linux-image-2.6, linux-modules-$version
 Suggests: $fwpackagename
 Architecture: any
 Description: Linux kernel, version $version
  This package contains the Linux kernel, modules and corresponding other
- files version $version
+ files, version: $version.
 EOF
-fi
 
-# Fix some ownership and permissions
-chown -R root:root "$tmpdir"
-chmod -R go-w "$tmpdir"
+fi
 
 # Do we have firmware? Move it out of the way and build it into a package.
 if [ -e "$tmpdir/lib/firmware" ]; then
@@ -131,16 +190,12 @@ if [ -e "$tmpdir/lib/firmware" ]; then
 Package: $fwpackagename
 Architecture: all
 Description: Linux kernel firmware, version $version
- This package contains firmware from the Linux kernel, version $version
+ This package contains firmware from the Linux kernel, version $version.
 EOF
 
-       dpkg-gencontrol -isp -p$fwpackagename -P"$fwdir"
-       dpkg --build "$fwdir" ..
+       create_package "$fwpackagename" "$fwdir"
 fi
 
-# Perform the final magic
-dpkg-gencontrol -isp -p$packagename
-dpkg --build "$tmpdir" ..
+create_package "$packagename" "$tmpdir"
 
 exit 0
-
index 0fae7da0529cac497a5337be4b6dd0e89cbf13d6..91033e67321e84e6479816cdff61c372f3be58d1 100755 (executable)
@@ -185,6 +185,19 @@ if ($arch eq "x86_64") {
     $objcopy .= " -O elf32-i386";
     $cc .= " -m32";
 
+} elsif ($arch eq "s390" && $bits == 32) {
+    $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_32\\s+_mcount\$";
+    $alignment = 4;
+    $ld .= " -m elf_s390";
+    $cc .= " -m31";
+
+} elsif ($arch eq "s390" && $bits == 64) {
+    $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_(PC|PLT)32DBL\\s+_mcount\\+0x2\$";
+    $alignment = 8;
+    $type = ".quad";
+    $ld .= " -m elf64_s390";
+    $cc .= " -m64";
+
 } elsif ($arch eq "sh") {
     $alignment = 2;
 
index 00790472f641b8cd5990033a4162b0120aa1453e..46989b88d7345d233ce5d734e2ed9845784df4d0 100755 (executable)
@@ -39,8 +39,10 @@ if head=`git rev-parse --verify --short HEAD 2>/dev/null`; then
                printf -- '-svn%s' "`git svn find-rev $head`"
        fi
 
-       # Are there uncommitted changes?
-       git update-index --refresh --unmerged > /dev/null
+       # Update index only on r/w media
+       [ -w . ] && git update-index --refresh --unmerged > /dev/null
+
+       # Check for uncommitted changes
        if git diff-index --name-only HEAD | grep -v "^scripts/package" \
            | read dummy; then
                printf '%s' -dirty
index 05a31a6c7e1bbda6537dd313e6498abedabbc4ca..30d459fb0709a70a97d6ddd5f8d635e8bb467490 100644 (file)
@@ -678,8 +678,10 @@ eval_unary(const struct ops *ops, int *valp, const char **cpp)
        if (*cp == '!') {
                debug("eval%d !", ops - eval_ops);
                cp++;
-               if (eval_unary(ops, valp, &cp) == LT_IF)
+               if (eval_unary(ops, valp, &cp) == LT_IF) {
+                       *cpp = cp;
                        return (LT_IF);
+               }
                *valp = !*valp;
        } else if (*cp == '(') {
                cp++;
@@ -700,13 +702,16 @@ eval_unary(const struct ops *ops, int *valp, const char **cpp)
                        return (LT_IF);
                cp = skipcomment(cp);
                sym = findsym(cp);
-               if (sym < 0)
-                       return (LT_IF);
-               *valp = (value[sym] != NULL);
                cp = skipsym(cp);
                cp = skipcomment(cp);
                if (*cp++ != ')')
                        return (LT_IF);
+               if (sym >= 0)
+                       *valp = (value[sym] != NULL);
+               else {
+                       *cpp = cp;
+                       return (LT_IF);
+               }
                keepthis = false;
        } else if (!endsym(*cp)) {
                debug("eval%d symbol", ops - eval_ops);
@@ -741,11 +746,11 @@ eval_table(const struct ops *ops, int *valp, const char **cpp)
        const struct op *op;
        const char *cp;
        int val;
+       Linetype lhs, rhs;
 
        debug("eval%d", ops - eval_ops);
        cp = *cpp;
-       if (ops->inner(ops+1, valp, &cp) == LT_IF)
-               return (LT_IF);
+       lhs = ops->inner(ops+1, valp, &cp);
        for (;;) {
                cp = skipcomment(cp);
                for (op = ops->op; op->str != NULL; op++)
@@ -755,14 +760,32 @@ eval_table(const struct ops *ops, int *valp, const char **cpp)
                        break;
                cp += strlen(op->str);
                debug("eval%d %s", ops - eval_ops, op->str);
-               if (ops->inner(ops+1, &val, &cp) == LT_IF)
-                       return (LT_IF);
-               *valp = op->fn(*valp, val);
+               rhs = ops->inner(ops+1, &val, &cp);
+               if (op->fn == op_and && (lhs == LT_FALSE || rhs == LT_FALSE)) {
+                       debug("eval%d: and always false", ops - eval_ops);
+                       if (lhs == LT_IF)
+                               *valp = val;
+                       lhs = LT_FALSE;
+                       continue;
+               }
+               if (op->fn == op_or && (lhs == LT_TRUE || rhs == LT_TRUE)) {
+                       debug("eval%d: or always true", ops - eval_ops);
+                       if (lhs == LT_IF)
+                               *valp = val;
+                       lhs = LT_TRUE;
+                       continue;
+               }
+               if (rhs == LT_IF)
+                       lhs = LT_IF;
+               if (lhs != LT_IF)
+                       *valp = op->fn(*valp, val);
        }
 
        *cpp = cp;
        debug("eval%d = %d", ops - eval_ops, *valp);
-       return (*valp ? LT_TRUE : LT_FALSE);
+       if (lhs != LT_IF)
+               lhs = (*valp ? LT_TRUE : LT_FALSE);
+       return lhs;
 }
 
 /*
@@ -773,12 +796,15 @@ eval_table(const struct ops *ops, int *valp, const char **cpp)
 static Linetype
 ifeval(const char **cpp)
 {
+       const char *cp = *cpp;
        int ret;
        int val;
 
        debug("eval %s", *cpp);
        keepthis = killconsts ? false : true;
-       ret = eval_table(eval_ops, &val, cpp);
+       ret = eval_table(eval_ops, &val, &cp);
+       if (ret != LT_IF)
+               *cpp = cp;
        debug("eval = %d", val);
        return (keepthis ? LT_IF : ret);
 }
index dbb3037f13464893a1a0637435a8598ea59f88cf..7de36df4eaa5877057bf63c6c929debb99e75e90 100755 (executable)
@@ -65,7 +65,7 @@ sed -n -e '/^.*\/libc-\([^/]*\)\.so$/{s//\1/;p;q}' < /proc/self/maps
 ldd -v > /dev/null 2>&1 && ldd -v || ldd --version |head -n 1 | awk \
 'NR==1{print "Dynamic linker (ldd)  ", $NF}'
 
-ls -l /usr/lib/lib{g,stdc}++.so  2>/dev/null | awk -F. \
+ls -l /usr/lib/libg++.so /usr/lib/libstdc++.so  2>/dev/null | awk -F. \
        '{print "Linux C++ Library      " $4"."$5"."$6}'
 
 ps --version 2>&1 | grep version | awk \
index fbf5c933baa4aa1487e9f2559210ac61f262be07..586965f9605fd55d4a6cf9c8f804f01d373647bb 100644 (file)
@@ -1037,7 +1037,7 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
        }
        ldev->selfptr_headphone.ptr = ldev;
        ldev->selfptr_lineout.ptr = ldev;
-       sdev->ofdev.dev.driver_data = ldev;
+       dev_set_drvdata(&sdev->ofdev.dev, ldev);
        list_add(&ldev->list, &layouts_list);
        layouts_list_items++;
 
@@ -1081,7 +1081,7 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
 
 static int aoa_fabric_layout_remove(struct soundbus_dev *sdev)
 {
-       struct layout_dev *ldev = sdev->ofdev.dev.driver_data;
+       struct layout_dev *ldev = dev_get_drvdata(&sdev->ofdev.dev);
        int i;
 
        for (i=0; i<MAX_CODECS_PER_BUS; i++) {
@@ -1114,7 +1114,7 @@ static int aoa_fabric_layout_remove(struct soundbus_dev *sdev)
 #ifdef CONFIG_PM
 static int aoa_fabric_layout_suspend(struct soundbus_dev *sdev, pm_message_t state)
 {
-       struct layout_dev *ldev = sdev->ofdev.dev.driver_data;
+       struct layout_dev *ldev = dev_get_drvdata(&sdev->ofdev.dev);
 
        if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off)
                ldev->gpio.methods->all_amps_off(&ldev->gpio);
@@ -1124,7 +1124,7 @@ static int aoa_fabric_layout_suspend(struct soundbus_dev *sdev, pm_message_t sta
 
 static int aoa_fabric_layout_resume(struct soundbus_dev *sdev)
 {
-       struct layout_dev *ldev = sdev->ofdev.dev.driver_data;
+       struct layout_dev *ldev = dev_get_drvdata(&sdev->ofdev.dev);
 
        if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off)
                ldev->gpio.methods->all_amps_restore(&ldev->gpio);
index 418c84c99d6946d8cb4982569ada0542c1327dfa..4e3b819d49930f07b7ce641c1de0a32b878f8bcd 100644 (file)
@@ -358,14 +358,14 @@ static int i2sbus_probe(struct macio_dev* dev, const struct of_device_id *match)
                return -ENODEV;
        }
 
-       dev->ofdev.dev.driver_data = control;
+       dev_set_drvdata(&dev->ofdev.dev, control);
 
        return 0;
 }
 
 static int i2sbus_remove(struct macio_dev* dev)
 {
-       struct i2sbus_control *control = dev->ofdev.dev.driver_data;
+       struct i2sbus_control *control = dev_get_drvdata(&dev->ofdev.dev);
        struct i2sbus_dev *i2sdev, *tmp;
 
        list_for_each_entry_safe(i2sdev, tmp, &control->list, item)
@@ -377,7 +377,7 @@ static int i2sbus_remove(struct macio_dev* dev)
 #ifdef CONFIG_PM
 static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state)
 {
-       struct i2sbus_control *control = dev->ofdev.dev.driver_data;
+       struct i2sbus_control *control = dev_get_drvdata(&dev->ofdev.dev);
        struct codec_info_item *cii;
        struct i2sbus_dev* i2sdev;
        int err, ret = 0;
@@ -407,7 +407,7 @@ static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state)
 
 static int i2sbus_resume(struct macio_dev* dev)
 {
-       struct i2sbus_control *control = dev->ofdev.dev.driver_data;
+       struct i2sbus_control *control = dev_get_drvdata(&dev->ofdev.dev);
        struct codec_info_item *cii;
        struct i2sbus_dev* i2sdev;
        int err, ret = 0;
index 5c48e36038f2a351a1b6212422ccb3250d1cf71f..dc78272fc39ff2cb01a42e5206d16041987e5d98 100644 (file)
@@ -1089,7 +1089,7 @@ static int __devinit aaci_probe(struct amba_device *dev, struct amba_id *id)
                goto out;
        }
 
-       aaci->base = ioremap(dev->res.start, SZ_4K);
+       aaci->base = ioremap(dev->res.start, resource_size(&dev->res));
        if (!aaci->base) {
                ret = -ENOMEM;
                goto out;
index 7bbdda041a991a991f264b09959025dd2f298295..6061fb5f4e1c14a8d1cc4b38ec3babe68f17a92d 100644 (file)
@@ -205,3 +205,5 @@ config SND_PCM_XRUN_DEBUG
 
 config SND_VMASTER
        bool
+
+source "sound/core/seq/Kconfig"
index fd56afe846ed6321d71e328147a5659423e2bce2..d5d40d78c409e6b865f0b420683ddd0c3f41d324 100644 (file)
@@ -152,15 +152,8 @@ int snd_card_create(int idx, const char *xid,
        card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL);
        if (!card)
                return -ENOMEM;
-       if (xid) {
-               if (!snd_info_check_reserved_words(xid)) {
-                       snd_printk(KERN_ERR
-                                  "given id string '%s' is reserved.\n", xid);
-                       err = -EBUSY;
-                       goto __error;
-               }
+       if (xid)
                strlcpy(card->id, xid, sizeof(card->id));
-       }
        err = 0;
        mutex_lock(&snd_card_mutex);
        if (idx < 0) {
@@ -483,22 +476,28 @@ int snd_card_free(struct snd_card *card)
 
 EXPORT_SYMBOL(snd_card_free);
 
-static void choose_default_id(struct snd_card *card)
+static void snd_card_set_id_no_lock(struct snd_card *card, const char *nid)
 {
        int i, len, idx_flag = 0, loops = SNDRV_CARDS;
-       char *id, *spos;
+       const char *spos, *src;
+       char *id;
        
-       id = spos = card->shortname;    
-       while (*id != '\0') {
-               if (*id == ' ')
-                       spos = id + 1;
-               id++;
+       if (nid == NULL) {
+               id = card->shortname;
+               spos = src = id;
+               while (*id != '\0') {
+                       if (*id == ' ')
+                               spos = id + 1;
+                       id++;
+               }
+       } else {
+               spos = src = nid;
        }
        id = card->id;
        while (*spos != '\0' && !isalnum(*spos))
                spos++;
        if (isdigit(*spos))
-               *id++ = isalpha(card->shortname[0]) ? card->shortname[0] : 'D';
+               *id++ = isalpha(src[0]) ? src[0] : 'D';
        while (*spos != '\0' && (size_t)(id - card->id) < sizeof(card->id) - 1) {
                if (isalnum(*spos))
                        *id++ = *spos;
@@ -513,7 +512,7 @@ static void choose_default_id(struct snd_card *card)
 
        while (1) {
                if (loops-- == 0) {
-                       snd_printk(KERN_ERR "unable to choose default card id (%s)\n", id);
+                       snd_printk(KERN_ERR "unable to set card id (%s)\n", id);
                        strcpy(card->id, card->proc_root->name);
                        return;
                }
@@ -539,14 +538,33 @@ static void choose_default_id(struct snd_card *card)
                        spos = id + len - 2;
                        if ((size_t)len <= sizeof(card->id) - 2)
                                spos++;
-                       *spos++ = '_';
-                       *spos++ = '1';
-                       *spos++ = '\0';
+                       *(char *)spos++ = '_';
+                       *(char *)spos++ = '1';
+                       *(char *)spos++ = '\0';
                        idx_flag++;
                }
        }
 }
 
+/**
+ *  snd_card_set_id - set card identification name
+ *  @card: soundcard structure
+ *  @nid: new identification string
+ *
+ *  This function sets the card identification and checks for name
+ *  collisions.
+ */
+void snd_card_set_id(struct snd_card *card, const char *nid)
+{
+       /* check if user specified own card->id */
+       if (card->id[0] != '\0')
+               return;
+       mutex_lock(&snd_card_mutex);
+       snd_card_set_id_no_lock(card, nid);
+       mutex_unlock(&snd_card_mutex);
+}
+EXPORT_SYMBOL(snd_card_set_id);
+
 #ifndef CONFIG_SYSFS_DEPRECATED
 static ssize_t
 card_id_show_attr(struct device *dev,
@@ -640,8 +658,7 @@ int snd_card_register(struct snd_card *card)
                mutex_unlock(&snd_card_mutex);
                return 0;
        }
-       if (card->id[0] == '\0')
-               choose_default_id(card);
+       snd_card_set_id_no_lock(card, card->id[0] == '\0' ? NULL : card->id);
        snd_cards[card->number] = card;
        mutex_unlock(&snd_card_mutex);
        init_info_for_card(card);
index d54d1a05fe65af20009da1330b3e659d032e6217..f705eec7372a32aad6187651cc393c69c2ce7e78 100644 (file)
@@ -63,7 +63,7 @@ static int snd_jack_dev_register(struct snd_device *device)
 
        /* Default to the sound card device. */
        if (!jack->input_dev->dev.parent)
-               jack->input_dev->dev.parent = card->dev;
+               jack->input_dev->dev.parent = snd_card_get_device_link(card);
 
        err = input_register_device(jack->input_dev);
        if (err == 0)
index dda000b9684cb07469e86fa4b7d324091c5db1a1..dbe406b82591058dd515686d8d13eb800418b416 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/time.h>
 #include <linux/vmalloc.h>
 #include <linux/moduleparam.h>
+#include <linux/math64.h>
 #include <linux/string.h>
 #include <sound/core.h>
 #include <sound/minors.h>
@@ -617,9 +618,7 @@ static long snd_pcm_oss_bytes(struct snd_pcm_substream *substream, long frames)
 #else
        {
                u64 bsize = (u64)runtime->oss.buffer_bytes * (u64)bytes;
-               u32 rem;
-               div64_32(&bsize, buffer_size, &rem);
-               return (long)bsize;
+               return div_u64(bsize, buffer_size);
        }
 #endif
 }
index d659995ac3ac7be2f20e488c71b7b3fe405a879e..333e4dd29450c7e9e823ebec46b7af4bcb6c62fc 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/slab.h>
 #include <linux/time.h>
+#include <linux/math64.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/info.h>
@@ -126,24 +127,37 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
 }
 
 #ifdef CONFIG_SND_PCM_XRUN_DEBUG
-#define xrun_debug(substream)  ((substream)->pstr->xrun_debug)
+#define xrun_debug(substream, mask)    ((substream)->pstr->xrun_debug & (mask))
 #else
-#define xrun_debug(substream)  0
+#define xrun_debug(substream, mask)    0
 #endif
 
-#define dump_stack_on_xrun(substream) do {     \
-               if (xrun_debug(substream) > 1)  \
-                       dump_stack();           \
+#define dump_stack_on_xrun(substream) do {             \
+               if (xrun_debug(substream, 2))           \
+                       dump_stack();                   \
        } while (0)
 
+static void pcm_debug_name(struct snd_pcm_substream *substream,
+                          char *name, size_t len)
+{
+       snprintf(name, len, "pcmC%dD%d%c:%d",
+                substream->pcm->card->number,
+                substream->pcm->device,
+                substream->stream ? 'c' : 'p',
+                substream->number);
+}
+
 static void xrun(struct snd_pcm_substream *substream)
 {
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
+               snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
        snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
-       if (xrun_debug(substream)) {
-               snd_printd(KERN_DEBUG "XRUN: pcmC%dD%d%c\n",
-                          substream->pcm->card->number,
-                          substream->pcm->device,
-                          substream->stream ? 'c' : 'p');
+       if (xrun_debug(substream, 1)) {
+               char name[16];
+               pcm_debug_name(substream, name, sizeof(name));
+               snd_printd(KERN_DEBUG "XRUN: %s\n", name);
                dump_stack_on_xrun(substream);
        }
 }
@@ -154,16 +168,16 @@ snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream,
 {
        snd_pcm_uframes_t pos;
 
-       if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
-               snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
        pos = substream->ops->pointer(substream);
        if (pos == SNDRV_PCM_POS_XRUN)
                return pos; /* XRUN */
        if (pos >= runtime->buffer_size) {
                if (printk_ratelimit()) {
-                       snd_printd(KERN_ERR  "BUG: stream = %i, pos = 0x%lx, "
+                       char name[16];
+                       pcm_debug_name(substream, name, sizeof(name));
+                       snd_printd(KERN_ERR  "BUG: %s, pos = 0x%lx, "
                                   "buffer size = 0x%lx, period size = 0x%lx\n",
-                                  substream->stream, pos, runtime->buffer_size,
+                                  name, pos, runtime->buffer_size,
                                   runtime->period_size);
                }
                pos = 0;
@@ -197,7 +211,7 @@ static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream,
 
 #define hw_ptr_error(substream, fmt, args...)                          \
        do {                                                            \
-               if (xrun_debug(substream)) {                            \
+               if (xrun_debug(substream, 1)) {                         \
                        if (printk_ratelimit()) {                       \
                                snd_printd("PCM: " fmt, ##args);        \
                        }                                               \
@@ -251,7 +265,7 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
        }
 
        /* Do jiffies check only in xrun_debug mode */
-       if (!xrun_debug(substream))
+       if (!xrun_debug(substream, 4))
                goto no_jiffies_check;
 
        /* Skip the jiffies check for hardwares with BATCH flag.
@@ -261,6 +275,9 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
        if (runtime->hw.info & SNDRV_PCM_INFO_BATCH)
                goto no_jiffies_check;
        hdelta = new_hw_ptr - old_hw_ptr;
+       if (hdelta < runtime->delay)
+               goto no_jiffies_check;
+       hdelta -= runtime->delay;
        jdelta = jiffies - runtime->hw_ptr_jiffies;
        if (((hdelta * HZ) / runtime->rate) > jdelta + HZ/100) {
                delta = jdelta /
@@ -294,14 +311,20 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
                hw_ptr_interrupt =
                        new_hw_ptr - new_hw_ptr % runtime->period_size;
        }
+       runtime->hw_ptr_interrupt = hw_ptr_interrupt;
+
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
            runtime->silence_size > 0)
                snd_pcm_playback_silence(substream, new_hw_ptr);
 
+       if (runtime->status->hw_ptr == new_hw_ptr)
+               return 0;
+
        runtime->hw_ptr_base = hw_base;
        runtime->status->hw_ptr = new_hw_ptr;
        runtime->hw_ptr_jiffies = jiffies;
-       runtime->hw_ptr_interrupt = hw_ptr_interrupt;
+       if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
+               snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
 
        return snd_pcm_update_hw_ptr_post(substream, runtime);
 }
@@ -342,8 +365,12 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
                new_hw_ptr = hw_base + pos;
        }
        /* Do jiffies check only in xrun_debug mode */
-       if (xrun_debug(substream) &&
-           ((delta * HZ) / runtime->rate) > jdelta + HZ/100) {
+       if (!xrun_debug(substream, 4))
+               goto no_jiffies_check;
+       if (delta < runtime->delay)
+               goto no_jiffies_check;
+       delta -= runtime->delay;
+       if (((delta * HZ) / runtime->rate) > jdelta + HZ/100) {
                hw_ptr_error(substream,
                             "hw_ptr skipping! "
                             "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu)\n",
@@ -352,13 +379,19 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
                             ((delta * HZ) / runtime->rate));
                return 0;
        }
+ no_jiffies_check:
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
            runtime->silence_size > 0)
                snd_pcm_playback_silence(substream, new_hw_ptr);
 
+       if (runtime->status->hw_ptr == new_hw_ptr)
+               return 0;
+
        runtime->hw_ptr_base = hw_base;
        runtime->status->hw_ptr = new_hw_ptr;
        runtime->hw_ptr_jiffies = jiffies;
+       if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
+               snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
 
        return snd_pcm_update_hw_ptr_post(substream, runtime);
 }
@@ -452,7 +485,7 @@ static inline unsigned int muldiv32(unsigned int a, unsigned int b,
                *r = 0;
                return UINT_MAX;
        }
-       div64_32(&n, c, r);
+       n = div_u64_rem(n, c, r);
        if (n >= UINT_MAX) {
                *r = 0;
                return UINT_MAX;
@@ -1524,6 +1557,23 @@ static int snd_pcm_lib_ioctl_channel_info(struct snd_pcm_substream *substream,
        return 0;
 }
 
+static int snd_pcm_lib_ioctl_fifo_size(struct snd_pcm_substream *substream,
+                                      void *arg)
+{
+       struct snd_pcm_hw_params *params = arg;
+       snd_pcm_format_t format;
+       int channels, width;
+
+       params->fifo_size = substream->runtime->hw.fifo_size;
+       if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_FIFO_IN_FRAMES)) {
+               format = params_format(params);
+               channels = params_channels(params);
+               width = snd_pcm_format_physical_width(format);
+               params->fifo_size /= width * channels;
+       }
+       return 0;
+}
+
 /**
  * snd_pcm_lib_ioctl - a generic PCM ioctl callback
  * @substream: the pcm substream instance
@@ -1545,6 +1595,8 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
                return snd_pcm_lib_ioctl_reset(substream, arg);
        case SNDRV_PCM_IOCTL1_CHANNEL_INFO:
                return snd_pcm_lib_ioctl_channel_info(substream, arg);
+       case SNDRV_PCM_IOCTL1_FIFO_SIZE:
+               return snd_pcm_lib_ioctl_fifo_size(substream, arg);
        }
        return -ENXIO;
 }
index b5da656d1ececa2e41b13dc55ea57b662bcc1b2e..84da3ba17c86911b0d48799772bd0c0960c90693 100644 (file)
@@ -312,9 +312,18 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
 
        hw = &substream->runtime->hw;
        if (!params->info)
-               params->info = hw->info;
-       if (!params->fifo_size)
-               params->fifo_size = hw->fifo_size;
+               params->info = hw->info & ~SNDRV_PCM_INFO_FIFO_IN_FRAMES;
+       if (!params->fifo_size) {
+               if (snd_mask_min(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT]) ==
+                   snd_mask_max(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT]) &&
+                    snd_mask_min(&params->masks[SNDRV_PCM_HW_PARAM_CHANNELS]) ==
+                    snd_mask_max(&params->masks[SNDRV_PCM_HW_PARAM_CHANNELS])) {
+                       changed = substream->ops->ioctl(substream,
+                                       SNDRV_PCM_IOCTL1_FIFO_SIZE, params);
+                       if (params < 0)
+                               return changed;
+               }
+       }
        params->rmask = 0;
        return 0;
 }
@@ -587,14 +596,15 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                status->avail = snd_pcm_playback_avail(runtime);
                if (runtime->status->state == SNDRV_PCM_STATE_RUNNING ||
-                   runtime->status->state == SNDRV_PCM_STATE_DRAINING)
+                   runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
                        status->delay = runtime->buffer_size - status->avail;
-               else
+                       status->delay += runtime->delay;
+               } else
                        status->delay = 0;
        } else {
                status->avail = snd_pcm_capture_avail(runtime);
                if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
-                       status->delay = status->avail;
+                       status->delay = status->avail + runtime->delay;
                else
                        status->delay = 0;
        }
@@ -2410,6 +2420,7 @@ static int snd_pcm_delay(struct snd_pcm_substream *substream,
                        n = snd_pcm_playback_hw_avail(runtime);
                else
                        n = snd_pcm_capture_avail(runtime);
+               n += runtime->delay;
                break;
        case SNDRV_PCM_STATE_XRUN:
                err = -EPIPE;
diff --git a/sound/core/seq/Kconfig b/sound/core/seq/Kconfig
new file mode 100644 (file)
index 0000000..b851fd8
--- /dev/null
@@ -0,0 +1,16 @@
+# define SND_XXX_SEQ to min(SND_SEQUENCER,SND_XXX)
+
+config SND_RAWMIDI_SEQ
+       def_tristate SND_SEQUENCER && SND_RAWMIDI
+
+config SND_OPL3_LIB_SEQ
+       def_tristate SND_SEQUENCER && SND_OPL3_LIB
+
+config SND_OPL4_LIB_SEQ
+       def_tristate SND_SEQUENCER && SND_OPL4_LIB
+
+config SND_SBAWE_SEQ
+       def_tristate SND_SEQUENCER && SND_SBAWE
+
+config SND_EMU10K1_SEQ
+       def_tristate SND_SEQUENCER && SND_EMU10K1
index 069593717fbab0c0deb733c52e883c5b6c638988..1bcb360330e521f37b82bca91452b7cbc0db8803 100644 (file)
@@ -17,14 +17,6 @@ snd-seq-midi-event-objs := seq_midi_event.o
 snd-seq-dummy-objs := seq_dummy.o
 snd-seq-virmidi-objs := seq_virmidi.o
 
-#
-# this function returns:
-#   "m" - CONFIG_SND_SEQUENCER is m
-#   <empty string> - CONFIG_SND_SEQUENCER is undefined
-#   otherwise parameter #1 value
-#
-sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
-
 obj-$(CONFIG_SND_SEQUENCER) += snd-seq.o snd-seq-device.o
 ifeq ($(CONFIG_SND_SEQUENCER_OSS),y)
 obj-$(CONFIG_SND_SEQUENCER) += snd-seq-midi-event.o
@@ -33,8 +25,8 @@ obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_VIRMIDI) += snd-seq-virmidi.o snd-seq-midi-event.o
-obj-$(call sequencer,$(CONFIG_SND_RAWMIDI)) += snd-seq-midi.o snd-seq-midi-event.o
-obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o
-obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o
-obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-seq-midi-emul.o snd-seq-virmidi.o
-obj-$(call sequencer,$(CONFIG_SND_EMU10K1)) += snd-seq-midi-emul.o snd-seq-virmidi.o
+obj-$(CONFIG_SND_RAWMIDI_SEQ) += snd-seq-midi.o snd-seq-midi-event.o
+obj-$(CONFIG_SND_OPL3_LIB_SEQ) += snd-seq-midi-event.o snd-seq-midi-emul.o
+obj-$(CONFIG_SND_OPL4_LIB_SEQ) += snd-seq-midi-event.o snd-seq-midi-emul.o
+obj-$(CONFIG_SND_SBAWE_SEQ) += snd-seq-midi-emul.o snd-seq-virmidi.o
+obj-$(CONFIG_SND_EMU10K1_SEQ) += snd-seq-midi-emul.o snd-seq-virmidi.o
index 19767a6a5c54a9297cb36a2a38293d82a4ec876e..7f2c2a10c4e5c96607c577ffc3c2d8f584a280b9 100644 (file)
@@ -7,14 +7,6 @@ snd-opl3-lib-objs := opl3_lib.o opl3_synth.o
 snd-opl3-synth-y := opl3_seq.o opl3_midi.o opl3_drums.o
 snd-opl3-synth-$(CONFIG_SND_SEQUENCER_OSS) += opl3_oss.o
 
-#
-# this function returns:
-#   "m" - CONFIG_SND_SEQUENCER is m
-#   <empty string> - CONFIG_SND_SEQUENCER is undefined
-#   otherwise parameter #1 value
-#
-sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
-
 obj-$(CONFIG_SND_OPL3_LIB) += snd-opl3-lib.o
 obj-$(CONFIG_SND_OPL4_LIB) += snd-opl3-lib.o
-obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-opl3-synth.o
+obj-$(CONFIG_SND_OPL3_LIB_SEQ) += snd-opl3-synth.o
index d178b39ffa6095416b47aa5d57b1390fd006b4a0..b94009b0b19f994d1ee3c56323fbeb27d15bbae9 100644 (file)
@@ -6,13 +6,5 @@
 snd-opl4-lib-objs := opl4_lib.o opl4_mixer.o opl4_proc.o
 snd-opl4-synth-objs := opl4_seq.o opl4_synth.o yrw801.o
 
-#
-# this function returns:
-#   "m" - CONFIG_SND_SEQUENCER is m
-#   <empty string> - CONFIG_SND_SEQUENCER is undefined
-#   otherwise parameter #1 value
-#
-sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
-
 obj-$(CONFIG_SND_OPL4_LIB) += snd-opl4-lib.o
-obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-opl4-synth.o
+obj-$(CONFIG_SND_OPL4_LIB_SEQ) += snd-opl4-synth.o
index c6942a4de99b3d5afebe9ec0961c961388a10c96..51a7e3777e17750639faf186befa3a4b4d751520 100644 (file)
@@ -177,15 +177,18 @@ config SND_ES18XX
          will be called snd-es18xx.
 
 config SND_SC6000
-       tristate "Gallant SC-6000, Audio Excel DSP 16"
+       tristate "Gallant SC-6000/6600/7000 and Audio Excel DSP 16"
        depends on HAS_IOPORT
        select SND_WSS_LIB
        select SND_OPL3_LIB
        select SND_MPU401_UART
        help
-         Say Y here to include support for Gallant SC-6000 card and clones:
+         Say Y here to include support for Gallant SC-6000, SC-6600, SC-7000
+         cards and clones:
          Audio Excel DSP 16 and Zoltrix AV302.
 
+         These cards are based on CompuMedia ASC-9308 or ASC-9408 chips.
+
          To compile this driver as a module, choose M here: the module
          will be called snd-sc6000.
 
index 442b081cafb755f90ed2181d73cbeea9fe5a2279..07df201ed8fa3d3999074b4415d582539bbe2b1f 100644 (file)
@@ -193,7 +193,7 @@ static int __devexit snd_es1688_remove(struct device *dev, unsigned int n)
 static struct isa_driver snd_es1688_driver = {
        .match          = snd_es1688_match,
        .probe          = snd_es1688_probe,
-       .remove         = snd_es1688_remove,
+       .remove         = __devexit_p(snd_es1688_remove),
 #if 0  /* FIXME */
        .suspend        = snd_es1688_suspend,
        .resume         = snd_es1688_resume,
index 180a8dea6bd94cbec45ba6bcae82282cfe7119fb..65e4b18581a60a93de84efad535836588774a5ec 100644 (file)
@@ -348,7 +348,7 @@ static int __devexit snd_gusextreme_remove(struct device *dev, unsigned int n)
 static struct isa_driver snd_gusextreme_driver = {
        .match          = snd_gusextreme_match,
        .probe          = snd_gusextreme_probe,
-       .remove         = snd_gusextreme_remove,
+       .remove         = __devexit_p(snd_gusextreme_remove),
 #if 0  /* FIXME */
        .suspend        = snd_gusextreme_suspend,
        .resume         = snd_gusextreme_resume,
index 1098a56b2f4b878898aca659d3096eafa6fd3edc..faeffceb01b796c86bbd339dfa940e507f024142 100644 (file)
@@ -13,14 +13,6 @@ snd-sbawe-objs := sbawe.o emu8000.o
 snd-emu8000-synth-objs := emu8000_synth.o emu8000_callback.o emu8000_patch.o emu8000_pcm.o
 snd-es968-objs := es968.o
 
-#
-# this function returns:
-#   "m" - CONFIG_SND_SEQUENCER is m
-#   <empty string> - CONFIG_SND_SEQUENCER is undefined
-#   otherwise parameter #1 value
-#
-sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
-
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_SB_COMMON) += snd-sb-common.o
 obj-$(CONFIG_SND_SB16_DSP) += snd-sb16-dsp.o
@@ -33,4 +25,4 @@ ifeq ($(CONFIG_SND_SB16_CSP),y)
   obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o
   obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o
 endif
-obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-emu8000-synth.o
+obj-$(CONFIG_SND_SBAWE_SEQ) += snd-emu8000-synth.o
index 782010608ef425e51f26e56d4a41335d6459dd9e..9a8bbf6dd62aeaecc1f51ee28d1b66db3d819f4c 100644 (file)
@@ -2,6 +2,8 @@
  *  Driver for Gallant SC-6000 soundcard. This card is also known as
  *  Audio Excel DSP 16 or Zoltrix AV302.
  *  These cards use CompuMedia ASC-9308 chip + AD1848 codec.
+ *  SC-6600 and SC-7000 cards are also supported. They are based on
+ *  CompuMedia ASC-9408 chip and CS4231 codec.
  *
  *  Copyright (C) 2007 Krzysztof Helt <krzysztof.h1@wp.pl>
  *
@@ -54,6 +56,7 @@ static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
                                                /* 0x300, 0x310, 0x320, 0x330 */
 static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;   /* 5, 7, 9, 10, 0 */
 static int dma[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;       /* 0, 1, 3 */
+static bool joystick[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = false };
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for sc-6000 based soundcard.");
@@ -73,6 +76,8 @@ module_param_array(mpu_irq, int, NULL, 0444);
 MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for sc-6000 driver.");
 module_param_array(dma, int, NULL, 0444);
 MODULE_PARM_DESC(dma, "DMA # for sc-6000 driver.");
+module_param_array(joystick, bool, NULL, 0444);
+MODULE_PARM_DESC(joystick, "Enable gameport.");
 
 /*
  * Commands of SC6000's DSP (SBPRO+special).
@@ -191,7 +196,7 @@ static __devinit unsigned char sc6000_mpu_irq_to_softcfg(int mpu_irq)
        return val;
 }
 
-static __devinit int sc6000_wait_data(char __iomem *vport)
+static int sc6000_wait_data(char __iomem *vport)
 {
        int loop = 1000;
        unsigned char val = 0;
@@ -206,7 +211,7 @@ static __devinit int sc6000_wait_data(char __iomem *vport)
        return -EAGAIN;
 }
 
-static __devinit int sc6000_read(char __iomem *vport)
+static int sc6000_read(char __iomem *vport)
 {
        if (sc6000_wait_data(vport))
                return -EBUSY;
@@ -215,7 +220,7 @@ static __devinit int sc6000_read(char __iomem *vport)
 
 }
 
-static __devinit int sc6000_write(char __iomem *vport, int cmd)
+static int sc6000_write(char __iomem *vport, int cmd)
 {
        unsigned char val;
        int loop = 500000;
@@ -276,8 +281,33 @@ static int __devinit sc6000_dsp_reset(char __iomem *vport)
 }
 
 /* detection and initialization */
-static int __devinit sc6000_cfg_write(char __iomem *vport,
-                                     unsigned char softcfg)
+static int __devinit sc6000_hw_cfg_write(char __iomem *vport, const int *cfg)
+{
+       if (sc6000_write(vport, COMMAND_6C) < 0) {
+               snd_printk(KERN_WARNING "CMD 0x%x: failed!\n", COMMAND_6C);
+               return -EIO;
+       }
+       if (sc6000_write(vport, COMMAND_5C) < 0) {
+               snd_printk(KERN_ERR "CMD 0x%x: failed!\n", COMMAND_5C);
+               return -EIO;
+       }
+       if (sc6000_write(vport, cfg[0]) < 0) {
+               snd_printk(KERN_ERR "DATA 0x%x: failed!\n", cfg[0]);
+               return -EIO;
+       }
+       if (sc6000_write(vport, cfg[1]) < 0) {
+               snd_printk(KERN_ERR "DATA 0x%x: failed!\n", cfg[1]);
+               return -EIO;
+       }
+       if (sc6000_write(vport, COMMAND_C5) < 0) {
+               snd_printk(KERN_ERR "CMD 0x%x: failed!\n", COMMAND_C5);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int sc6000_cfg_write(char __iomem *vport, unsigned char softcfg)
 {
 
        if (sc6000_write(vport, WRITE_MDIRQ_CFG)) {
@@ -291,7 +321,7 @@ static int __devinit sc6000_cfg_write(char __iomem *vport,
        return 0;
 }
 
-static int __devinit sc6000_setup_board(char __iomem *vport, int config)
+static int sc6000_setup_board(char __iomem *vport, int config)
 {
        int loop = 10;
 
@@ -334,16 +364,39 @@ static int __devinit sc6000_init_mss(char __iomem *vport, int config,
        return 0;
 }
 
-static int __devinit sc6000_init_board(char __iomem *vport, int irq, int dma,
-                                       char __iomem *vmss_port, int mpu_irq)
+static void __devinit sc6000_hw_cfg_encode(char __iomem *vport, int *cfg,
+                                          long xport, long xmpu,
+                                          long xmss_port, int joystick)
+{
+       cfg[0] = 0;
+       cfg[1] = 0;
+       if (xport == 0x240)
+               cfg[0] |= 1;
+       if (xmpu != SNDRV_AUTO_PORT) {
+               cfg[0] |= (xmpu & 0x30) >> 2;
+               cfg[1] |= 0x20;
+       }
+       if (xmss_port == 0xe80)
+               cfg[0] |= 0x10;
+       cfg[0] |= 0x40;         /* always set */
+       if (!joystick)
+               cfg[0] |= 0x02;
+       cfg[1] |= 0x80;         /* enable WSS system */
+       cfg[1] &= ~0x40;        /* disable IDE */
+       snd_printd("hw cfg %x, %x\n", cfg[0], cfg[1]);
+}
+
+static int __devinit sc6000_init_board(char __iomem *vport,
+                                       char __iomem *vmss_port, int dev)
 {
        char answer[15];
        char version[2];
-       int mss_config = sc6000_irq_to_softcfg(irq) |
-                        sc6000_dma_to_softcfg(dma);
+       int mss_config = sc6000_irq_to_softcfg(irq[dev]) |
+                        sc6000_dma_to_softcfg(dma[dev]);
        int config = mss_config |
-                    sc6000_mpu_irq_to_softcfg(mpu_irq);
+                    sc6000_mpu_irq_to_softcfg(mpu_irq[dev]);
        int err;
+       int old = 0;
 
        err = sc6000_dsp_reset(vport);
        if (err < 0) {
@@ -360,7 +413,6 @@ static int __devinit sc6000_init_board(char __iomem *vport, int irq, int dma,
        /*
         * My SC-6000 card return "SC-6000" in DSPCopyright, so
         * if we have something different, we have to be warned.
-        * Mine returns "SC-6000A " - KH
         */
        if (strncmp("SC-6000", answer, 7))
                snd_printk(KERN_WARNING "Warning: non SC-6000 audio card!\n");
@@ -372,13 +424,32 @@ static int __devinit sc6000_init_board(char __iomem *vport, int irq, int dma,
        printk(KERN_INFO PFX "Detected model: %s, DSP version %d.%d\n",
                answer, version[0], version[1]);
 
-       /*
-        * 0x0A == (IRQ 7, DMA 1, MIRQ 0)
-        */
-       err = sc6000_cfg_write(vport, 0x0a);
+       /* set configuration */
+       sc6000_write(vport, COMMAND_5C);
+       if (sc6000_read(vport) < 0)
+               old = 1;
+
+       if (!old) {
+               int cfg[2];
+               sc6000_hw_cfg_encode(vport, &cfg[0], port[dev], mpu_port[dev],
+                                    mss_port[dev], joystick[dev]);
+               if (sc6000_hw_cfg_write(vport, cfg) < 0) {
+                       snd_printk(KERN_ERR "sc6000_hw_cfg_write: failed!\n");
+                       return -EIO;
+               }
+       }
+       err = sc6000_setup_board(vport, config);
        if (err < 0) {
-               snd_printk(KERN_ERR "sc6000_cfg_write: failed!\n");
-               return -EFAULT;
+               snd_printk(KERN_ERR "sc6000_setup_board: failed!\n");
+               return -ENODEV;
+       }
+
+       sc6000_dsp_reset(vport);
+
+       if (!old) {
+               sc6000_write(vport, COMMAND_60);
+               sc6000_write(vport, 0x02);
+               sc6000_dsp_reset(vport);
        }
 
        err = sc6000_setup_board(vport, config);
@@ -386,10 +457,9 @@ static int __devinit sc6000_init_board(char __iomem *vport, int irq, int dma,
                snd_printk(KERN_ERR "sc6000_setup_board: failed!\n");
                return -ENODEV;
        }
-
        err = sc6000_init_mss(vport, config, vmss_port, mss_config);
        if (err < 0) {
-               snd_printk(KERN_ERR "Can not initialize "
+               snd_printk(KERN_ERR "Cannot initialize "
                           "Microsoft Sound System mode.\n");
                return -ENODEV;
        }
@@ -485,14 +555,16 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev)
        struct snd_card *card;
        struct snd_wss *chip;
        struct snd_opl3 *opl3;
-       char __iomem *vport;
+       char __iomem **vport;
        char __iomem *vmss_port;
 
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, sizeof(vport),
+                               &card);
        if (err < 0)
                return err;
 
+       vport = card->private_data;
        if (xirq == SNDRV_AUTO_IRQ) {
                xirq = snd_legacy_find_free_irq(possible_irqs);
                if (xirq < 0) {
@@ -517,8 +589,8 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev)
                err = -EBUSY;
                goto err_exit;
        }
-       vport = devm_ioport_map(devptr, port[dev], 0x10);
-       if (!vport) {
+       *vport = devm_ioport_map(devptr, port[dev], 0x10);
+       if (*vport == NULL) {
                snd_printk(KERN_ERR PFX
                           "I/O port cannot be iomaped.\n");
                err = -EBUSY;
@@ -533,7 +605,7 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev)
                goto err_unmap1;
        }
        vmss_port = devm_ioport_map(devptr, mss_port[dev], 4);
-       if (!vport) {
+       if (!vmss_port) {
                snd_printk(KERN_ERR PFX
                           "MSS port I/O cannot be iomaped.\n");
                err = -EBUSY;
@@ -544,7 +616,7 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev)
                   port[dev], xirq, xdma,
                   mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]);
 
-       err = sc6000_init_board(vport, xirq, xdma, vmss_port, mpu_irq[dev]);
+       err = sc6000_init_board(*vport, vmss_port, dev);
        if (err < 0)
                goto err_unmap2;
 
@@ -552,7 +624,6 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev)
                             WSS_HW_DETECT, 0, &chip);
        if (err < 0)
                goto err_unmap2;
-       card->private_data = chip;
 
        err = snd_wss_pcm(chip, 0, NULL);
        if (err < 0) {
@@ -608,6 +679,7 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev)
        return 0;
 
 err_unmap2:
+       sc6000_setup_board(*vport, 0);
        release_region(mss_port[dev], 4);
 err_unmap1:
        release_region(port[dev], 0x10);
@@ -618,11 +690,17 @@ err_exit:
 
 static int __devexit snd_sc6000_remove(struct device *devptr, unsigned int dev)
 {
+       struct snd_card *card = dev_get_drvdata(devptr);
+       char __iomem **vport = card->private_data;
+
+       if (sc6000_setup_board(*vport, 0) < 0)
+               snd_printk(KERN_WARNING "sc6000_setup_board failed on exit!\n");
+
        release_region(port[dev], 0x10);
        release_region(mss_port[dev], 4);
 
-       snd_card_free(dev_get_drvdata(devptr));
        dev_set_drvdata(devptr, NULL);
+       snd_card_free(card);
        return 0;
 }
 
index 66f3b48ceafcdcbedb7e4700a4ae8a341283cd3f..e497525bc11bcf50612c071bdfc3c5ba186bacf1 100644 (file)
@@ -619,8 +619,7 @@ static int snd_sgio2audio_pcm_hw_params(struct snd_pcm_substream *substream,
 /* hw_free callback */
 static int snd_sgio2audio_pcm_hw_free(struct snd_pcm_substream *substream)
 {
-       if (substream->runtime->dma_area)
-               vfree(substream->runtime->dma_area);
+       vfree(substream->runtime->dma_area);
        substream->runtime->dma_area = NULL;
        return 0;
 }
index e4282d93a1aaa121aaac6eeac5c9f22cd92083ec..21eb6dce46df28bf17d2aa160244ac29db911425 100644 (file)
@@ -100,7 +100,7 @@ void msnd_fifo_free(msnd_fifo *f)
 int msnd_fifo_alloc(msnd_fifo *f, size_t n)
 {
        msnd_fifo_free(f);
-       f->data = (char *)vmalloc(n);
+       f->data = vmalloc(n);
        f->n = n;
        f->tail = 0;
        f->head = 0;
index 6055fd6d3b38ee90ba6d19895363ef33db38f275..e924492df21dc1b469f7b41020ca890737fa9857 100644 (file)
@@ -935,7 +935,7 @@ snd_harmony_create(struct snd_card *card,
        h->iobase = ioremap_nocache(padev->hpa.start, HARMONY_SIZE);
        if (h->iobase == NULL) {
                printk(KERN_ERR PFX "unable to remap hpa 0x%lx\n",
-                      padev->hpa.start);
+                      (unsigned long)padev->hpa.start);
                err = -EBUSY;
                goto free_and_ret;
        }
@@ -1020,7 +1020,7 @@ static struct parisc_driver snd_harmony_driver = {
        .name = "harmony",
        .id_table = snd_harmony_devtable,
        .probe = snd_harmony_probe,
-       .remove = snd_harmony_remove,
+       .remove = __devexit_p(snd_harmony_remove),
 };
 
 static int __init 
index 93422e3a3f0cc2f642a5a30cfd09ee89cbb55a43..748f6b7d90b7715729d131e831f0299d0d8384fa 100644 (file)
@@ -275,6 +275,16 @@ config SND_CS5535AUDIO
          To compile this driver as a module, choose M here: the module
          will be called snd-cs5535audio.
 
+config SND_CTXFI
+       tristate "Creative Sound Blaster X-Fi"
+       select SND_PCM
+       help
+         If you want to use soundcards based on Creative Sound Blastr X-Fi
+         boards with 20k1 or 20k2 chips, say Y here.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-ctxfi.
+
 config SND_DARLA20
        tristate "(Echoaudio) Darla20"
        select FW_LOADER
@@ -532,6 +542,9 @@ config SND_HDSP
          To compile this driver as a module, choose M here: the module
          will be called snd-hdsp.
 
+comment "Don't forget to add built-in firmwares for HDSP driver"
+       depends on SND_HDSP=y
+
 config SND_HDSPM
        tristate "RME Hammerfall DSP MADI"
        select SND_HWDEP
@@ -622,6 +635,16 @@ config SND_KORG1212
          To compile this driver as a module, choose M here: the module
          will be called snd-korg1212.
 
+config SND_LX6464ES
+       tristate "Digigram LX6464ES"
+       select SND_PCM
+       help
+         Say Y here to include support for Digigram LX6464ES boards.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-lx6464es.
+
+
 config SND_MAESTRO3
        tristate "ESS Allegro/Maestro3"
        select SND_AC97_CODEC
@@ -764,8 +787,8 @@ config SND_VIRTUOSO
        select SND_OXYGEN_LIB
        help
          Say Y here to include support for sound cards based on the
-         Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, and
-         Essence STX.
+         Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X,
+         Essence ST (Deluxe), and Essence STX.
          Support for the HDAV1.3 (Deluxe) is very experimental.
 
          To compile this driver as a module, choose M here: the module
index 65b25d221cd2795135f265dcbb05d47f1dfc8a8f..ecfc609d2b9f427b04330bc31f0acbd35a0126ac 100644 (file)
@@ -59,9 +59,11 @@ obj-$(CONFIG_SND) += \
        ali5451/ \
        au88x0/ \
        aw2/ \
+       ctxfi/ \
        ca0106/ \
        cs46xx/ \
        cs5535audio/ \
+       lx6464es/ \
        echoaudio/ \
        emu10k1/ \
        hda/ \
index 3906f5afe27a3a9b27c9f0bf90e36108664d4925..23f49f356e0f0375a784de99c05b832c2bc66ad4 100644 (file)
@@ -1255,8 +1255,8 @@ static int inline vortex_adbdma_getlinearpos(vortex_t * vortex, int adbdma)
        int temp;
 
        temp = hwread(vortex->mmio, VORTEX_ADBDMA_STAT + (adbdma << 2));
-       temp = (dma->period_virt * dma->period_bytes) + (temp & POS_MASK);
-       return (temp);
+       temp = (dma->period_virt * dma->period_bytes) + (temp & (dma->period_bytes - 1));
+       return temp;
 }
 
 static void vortex_adbdma_startfifo(vortex_t * vortex, int adbdma)
@@ -1504,8 +1504,7 @@ static int inline vortex_wtdma_getlinearpos(vortex_t * vortex, int wtdma)
        int temp;
 
        temp = hwread(vortex->mmio, VORTEX_WTDMA_STAT + (wtdma << 2));
-       //temp = (temp & POS_MASK) + (((temp>>WT_SUBBUF_SHIFT) & WT_SUBBUF_MASK)*(dma->cfg0&POS_MASK));
-       temp = (temp & POS_MASK) + ((dma->period_virt) * (dma->period_bytes));
+       temp = (dma->period_virt * dma->period_bytes) + (temp & (dma->period_bytes - 1));
        return temp;
 }
 
@@ -2441,7 +2440,8 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id)
                spin_lock(&vortex->lock);
                for (i = 0; i < NR_ADB; i++) {
                        if (vortex->dma_adb[i].fifo_status == FIFO_START) {
-                               if (vortex_adbdma_bufshift(vortex, i)) ;
+                               if (!vortex_adbdma_bufshift(vortex, i))
+                                       continue;
                                spin_unlock(&vortex->lock);
                                snd_pcm_period_elapsed(vortex->dma_adb[i].
                                                       substream);
index 6a3891ab69dd09389d7618597c770eddc225429a..296123ab74f7e94b6c911fc52eb852a760e26b6b 100644 (file)
@@ -108,7 +108,7 @@ void snd_aw2_saa7146_setup(struct snd_aw2_saa7146 *chip,
 #endif
        /* WS0_CTRL, WS0_SYNC: input TSL1, I2S */
 
-       /* At initialization WS1 and WS2 are disbaled (configured as input */
+       /* At initialization WS1 and WS2 are disabled (configured as input) */
        acon1 |= 0 * WS1_CTRL;
        acon1 |= 0 * WS2_CTRL;
 
index ce3f2e90f4d7545ac350b5a00fdb29bc0ef5d31a..24585c6c6d019ea7e1a1d2405f942aec8f86c1f3 100644 (file)
@@ -810,6 +810,8 @@ static struct pci_device_id snd_bt87x_ids[] = {
        BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x107d, 0x6606, GENERIC),
        /* Voodoo TV 200 */
        BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x121a, 0x3000, GENERIC),
+       /* Askey Computer Corp. MagicTView'99 */
+       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x144f, 0x3000, GENERIC),
        /* AVerMedia Studio No. 103, 203, ...? */
        BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1461, 0x0003, AVPHONE98),
        /* Prolink PixelView PV-M4900 */
index bfac30f7929f3094b0f95c343f2659cd0381a4a0..57b992a5c05724c6b67e18668464e592d8b82660 100644 (file)
@@ -1319,7 +1319,6 @@ static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device)
         }
 
        pcm->info_flags = 0;
-       pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
        strcpy(pcm->name, "CA0106");
 
        for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; 
index c111efe61c3cc224208828552e1148c5ad689bb7..c8c6f437f5b394d2a37abf335a6b931a3e537ffb 100644 (file)
@@ -739,7 +739,7 @@ static int __devinit rename_ctl(struct snd_card *card, const char *src, const ch
        } while (0)
 
 static __devinitdata
-DECLARE_TLV_DB_SCALE(snd_ca0106_master_db_scale, -6375, 50, 1);
+DECLARE_TLV_DB_SCALE(snd_ca0106_master_db_scale, -6375, 25, 1);
 
 static char *slave_vols[] __devinitdata = {
        "Analog Front Playback Volume",
@@ -841,6 +841,9 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
                                              snd_ca0106_master_db_scale);
        if (!vmaster)
                return -ENOMEM;
+       err = snd_ctl_add(card, vmaster);
+       if (err < 0)
+               return err;
        add_slaves(card, vmaster, slave_vols);
 
        if (emu->details->spi_dac == 1) {
@@ -848,8 +851,13 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
                                                      NULL);
                if (!vmaster)
                        return -ENOMEM;
+               err = snd_ctl_add(card, vmaster);
+               if (err < 0)
+                       return err;
                add_slaves(card, vmaster, slave_sws);
        }
+
+       strcpy(card->mixername, "CA0106");
         return 0;
 }
 
diff --git a/sound/pci/ctxfi/Makefile b/sound/pci/ctxfi/Makefile
new file mode 100644 (file)
index 0000000..15075f8
--- /dev/null
@@ -0,0 +1,5 @@
+snd-ctxfi-objs := xfi.o ctatc.o ctvmem.o ctpcm.o ctmixer.o ctresource.o \
+       ctsrc.o ctamixer.o ctdaio.o ctimap.o cthardware.o cttimer.o \
+       cthw20k2.o cthw20k1.o
+
+obj-$(CONFIG_SND_CTXFI) += snd-ctxfi.o
diff --git a/sound/pci/ctxfi/ct20k1reg.h b/sound/pci/ctxfi/ct20k1reg.h
new file mode 100644 (file)
index 0000000..f2e34e3
--- /dev/null
@@ -0,0 +1,636 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ */
+
+#ifndef CT20K1REG_H
+#define CT20k1REG_H
+
+/* 20k1 registers */
+#define        DSPXRAM_START                   0x000000
+#define        DSPXRAM_END                     0x013FFC
+#define        DSPAXRAM_START                  0x020000
+#define        DSPAXRAM_END                    0x023FFC
+#define        DSPYRAM_START                   0x040000
+#define        DSPYRAM_END                     0x04FFFC
+#define        DSPAYRAM_START                  0x020000
+#define        DSPAYRAM_END                    0x063FFC
+#define        DSPMICRO_START                  0x080000
+#define        DSPMICRO_END                    0x0B3FFC
+#define        DSP0IO_START                    0x100000
+#define        DSP0IO_END                      0x101FFC
+#define        AUDIORINGIPDSP0_START           0x100000
+#define        AUDIORINGIPDSP0_END             0x1003FC
+#define        AUDIORINGOPDSP0_START           0x100400
+#define        AUDIORINGOPDSP0_END             0x1007FC
+#define        AUDPARARINGIODSP0_START         0x100800
+#define        AUDPARARINGIODSP0_END           0x100BFC
+#define        DSP0LOCALHWREG_START            0x100C00
+#define        DSP0LOCALHWREG_END              0x100C3C
+#define        DSP0XYRAMAGINDEX_START          0x100C40
+#define        DSP0XYRAMAGINDEX_END            0x100C5C
+#define        DSP0XYRAMAGMDFR_START           0x100C60
+#define        DSP0XYRAMAGMDFR_END             0x100C7C
+#define        DSP0INTCONTLVEC_START           0x100C80
+#define        DSP0INTCONTLVEC_END             0x100CD8
+#define        INTCONTLGLOBALREG_START         0x100D1C
+#define        INTCONTLGLOBALREG_END           0x100D3C
+#define                HOSTINTFPORTADDRCONTDSP0        0x100D40
+#define                HOSTINTFPORTDATADSP0            0x100D44
+#define                TIME0PERENBDSP0                 0x100D60
+#define                TIME0COUNTERDSP0                0x100D64
+#define                TIME1PERENBDSP0                 0x100D68
+#define                TIME1COUNTERDSP0                0x100D6C
+#define                TIME2PERENBDSP0                 0x100D70
+#define                TIME2COUNTERDSP0                0x100D74
+#define                TIME3PERENBDSP0                 0x100D78
+#define                TIME3COUNTERDSP0                0x100D7C
+#define        XRAMINDOPERREFNOUP_STARTDSP0    0x100D80
+#define        XRAMINDOPERREFNOUP_ENDDSP0      0x100D9C
+#define        XRAMINDOPERREFUP_STARTDSP0      0x100DA0
+#define        XRAMINDOPERREFUP_ENDDSP0        0x100DBC
+#define        YRAMINDOPERREFNOUP_STARTDSP0    0x100DC0
+#define        YRAMINDOPERREFNOUP_ENDDSP0      0x100DDC
+#define        YRAMINDOPERREFUP_STARTDSP0      0x100DE0
+#define        YRAMINDOPERREFUP_ENDDSP0        0x100DFC
+#define        DSP0CONDCODE                    0x100E00
+#define        DSP0STACKFLAG                   0x100E04
+#define        DSP0PROGCOUNTSTACKPTREG         0x100E08
+#define        DSP0PROGCOUNTSTACKDATAREG       0x100E0C
+#define        DSP0CURLOOPADDRREG              0x100E10
+#define        DSP0CURLOOPCOUNT                0x100E14
+#define        DSP0TOPLOOPCOUNTSTACK           0x100E18
+#define        DSP0TOPLOOPADDRSTACK            0x100E1C
+#define        DSP0LOOPSTACKPTR                0x100E20
+#define        DSP0STASSTACKDATAREG            0x100E24
+#define        DSP0STASSTACKPTR                0x100E28
+#define        DSP0PROGCOUNT                   0x100E2C
+#define        GLOBDSPDEBGREG                  0x100E30
+#define        GLOBDSPBREPTRREG                0x100E30
+#define        DSP0XYRAMBASE_START             0x100EA0
+#define        DSP0XYRAMBASE_END               0x100EBC
+#define        DSP0XYRAMLENG_START             0x100EC0
+#define        DSP0XYRAMLENG_END               0x100EDC
+#define                SEMAPHOREREGDSP0                0x100EE0
+#define                DSP0INTCONTMASKREG              0x100EE4
+#define                DSP0INTCONTPENDREG              0x100EE8
+#define                DSP0INTCONTSERVINT              0x100EEC
+#define                DSPINTCONTEXTINTMODREG          0x100EEC
+#define                GPIODSP0                        0x100EFC
+#define        DMADSPBASEADDRREG_STARTDSP0     0x100F00
+#define        DMADSPBASEADDRREG_ENDDSP0       0x100F1C
+#define        DMAHOSTBASEADDRREG_STARTDSP0    0x100F20
+#define        DMAHOSTBASEADDRREG_ENDDSP0      0x100F3C
+#define        DMADSPCURADDRREG_STARTDSP0      0x100F40
+#define        DMADSPCURADDRREG_ENDDSP0        0x100F5C
+#define        DMAHOSTCURADDRREG_STARTDSP0     0x100F60
+#define        DMAHOSTCURADDRREG_ENDDSP0       0x100F7C
+#define        DMATANXCOUNTREG_STARTDSP0       0x100F80
+#define        DMATANXCOUNTREG_ENDDSP0         0x100F9C
+#define        DMATIMEBUGREG_STARTDSP0         0x100FA0
+#define        DMATIMEBUGREG_ENDDSP0           0x100FAC
+#define        DMACNTLMODFREG_STARTDSP0        0x100FA0
+#define        DMACNTLMODFREG_ENDDSP0          0x100FAC
+
+#define        DMAGLOBSTATSREGDSP0             0x100FEC
+#define        DSP0XGPRAM_START                0x101000
+#define        DSP0XGPRAM_END                  0x1017FC
+#define        DSP0YGPRAM_START                0x101800
+#define        DSP0YGPRAM_END                  0x101FFC
+
+
+
+
+#define        AUDIORINGIPDSP1_START           0x102000
+#define        AUDIORINGIPDSP1_END             0x1023FC
+#define        AUDIORINGOPDSP1_START           0x102400
+#define        AUDIORINGOPDSP1_END             0x1027FC
+#define        AUDPARARINGIODSP1_START         0x102800
+#define        AUDPARARINGIODSP1_END           0x102BFC
+#define        DSP1LOCALHWREG_START            0x102C00
+#define        DSP1LOCALHWREG_END              0x102C3C
+#define        DSP1XYRAMAGINDEX_START          0x102C40
+#define        DSP1XYRAMAGINDEX_END            0x102C5C
+#define        DSP1XYRAMAGMDFR_START           0x102C60
+#define        DSP1XYRAMAGMDFR_END             0x102C7C
+#define        DSP1INTCONTLVEC_START           0x102C80
+#define        DSP1INTCONTLVEC_END             0x102CD8
+#define                HOSTINTFPORTADDRCONTDSP1        0x102D40
+#define                HOSTINTFPORTDATADSP1            0x102D44
+#define                TIME0PERENBDSP1                 0x102D60
+#define                TIME0COUNTERDSP1                0x102D64
+#define                TIME1PERENBDSP1                 0x102D68
+#define                TIME1COUNTERDSP1                0x102D6C
+#define                TIME2PERENBDSP1                 0x102D70
+#define                TIME2COUNTERDSP1                0x102D74
+#define                TIME3PERENBDSP1                 0x102D78
+#define                TIME3COUNTERDSP1                0x102D7C
+#define        XRAMINDOPERREFNOUP_STARTDSP1    0x102D80
+#define        XRAMINDOPERREFNOUP_ENDDSP1      0x102D9C
+#define        XRAMINDOPERREFUP_STARTDSP1      0x102DA0
+#define        XRAMINDOPERREFUP_ENDDSP1        0x102DBC
+#define        YRAMINDOPERREFNOUP_STARTDSP1    0x102DC0
+#define        YRAMINDOPERREFNOUP_ENDDSP1      0x102DDC
+#define        YRAMINDOPERREFUP_STARTDSP1      0x102DE0
+#define        YRAMINDOPERREFUP_ENDDSP1        0x102DFC
+
+#define        DSP1CONDCODE                    0x102E00
+#define        DSP1STACKFLAG                   0x102E04
+#define        DSP1PROGCOUNTSTACKPTREG         0x102E08
+#define        DSP1PROGCOUNTSTACKDATAREG       0x102E0C
+#define        DSP1CURLOOPADDRREG              0x102E10
+#define        DSP1CURLOOPCOUNT                0x102E14
+#define        DSP1TOPLOOPCOUNTSTACK           0x102E18
+#define        DSP1TOPLOOPADDRSTACK            0x102E1C
+#define        DSP1LOOPSTACKPTR                0x102E20
+#define        DSP1STASSTACKDATAREG            0x102E24
+#define        DSP1STASSTACKPTR                0x102E28
+#define        DSP1PROGCOUNT                   0x102E2C
+#define        DSP1XYRAMBASE_START             0x102EA0
+#define        DSP1XYRAMBASE_END               0x102EBC
+#define        DSP1XYRAMLENG_START             0x102EC0
+#define        DSP1XYRAMLENG_END               0x102EDC
+#define                SEMAPHOREREGDSP1                0x102EE0
+#define                DSP1INTCONTMASKREG              0x102EE4
+#define                DSP1INTCONTPENDREG              0x102EE8
+#define                DSP1INTCONTSERVINT              0x102EEC
+#define                GPIODSP1                        0x102EFC
+#define        DMADSPBASEADDRREG_STARTDSP1     0x102F00
+#define        DMADSPBASEADDRREG_ENDDSP1       0x102F1C
+#define        DMAHOSTBASEADDRREG_STARTDSP1    0x102F20
+#define        DMAHOSTBASEADDRREG_ENDDSP1      0x102F3C
+#define        DMADSPCURADDRREG_STARTDSP1      0x102F40
+#define        DMADSPCURADDRREG_ENDDSP1        0x102F5C
+#define        DMAHOSTCURADDRREG_STARTDSP1     0x102F60
+#define        DMAHOSTCURADDRREG_ENDDSP1       0x102F7C
+#define        DMATANXCOUNTREG_STARTDSP1       0x102F80
+#define        DMATANXCOUNTREG_ENDDSP1         0x102F9C
+#define        DMATIMEBUGREG_STARTDSP1         0x102FA0
+#define        DMATIMEBUGREG_ENDDSP1           0x102FAC
+#define        DMACNTLMODFREG_STARTDSP1        0x102FA0
+#define        DMACNTLMODFREG_ENDDSP1          0x102FAC
+
+#define        DMAGLOBSTATSREGDSP1             0x102FEC
+#define        DSP1XGPRAM_START                0x103000
+#define        DSP1XGPRAM_END                  0x1033FC
+#define        DSP1YGPRAM_START                0x103400
+#define        DSP1YGPRAM_END                  0x1037FC
+
+
+
+#define        AUDIORINGIPDSP2_START           0x104000
+#define        AUDIORINGIPDSP2_END             0x1043FC
+#define        AUDIORINGOPDSP2_START           0x104400
+#define        AUDIORINGOPDSP2_END             0x1047FC
+#define        AUDPARARINGIODSP2_START         0x104800
+#define        AUDPARARINGIODSP2_END           0x104BFC
+#define        DSP2LOCALHWREG_START            0x104C00
+#define        DSP2LOCALHWREG_END              0x104C3C
+#define        DSP2XYRAMAGINDEX_START          0x104C40
+#define        DSP2XYRAMAGINDEX_END            0x104C5C
+#define        DSP2XYRAMAGMDFR_START           0x104C60
+#define        DSP2XYRAMAGMDFR_END             0x104C7C
+#define        DSP2INTCONTLVEC_START           0x104C80
+#define        DSP2INTCONTLVEC_END             0x104CD8
+#define                HOSTINTFPORTADDRCONTDSP2        0x104D40
+#define                HOSTINTFPORTDATADSP2            0x104D44
+#define                TIME0PERENBDSP2                 0x104D60
+#define                TIME0COUNTERDSP2                0x104D64
+#define                TIME1PERENBDSP2                 0x104D68
+#define                TIME1COUNTERDSP2                0x104D6C
+#define                TIME2PERENBDSP2                 0x104D70
+#define                TIME2COUNTERDSP2                0x104D74
+#define                TIME3PERENBDSP2                 0x104D78
+#define                TIME3COUNTERDSP2                0x104D7C
+#define        XRAMINDOPERREFNOUP_STARTDSP2    0x104D80
+#define        XRAMINDOPERREFNOUP_ENDDSP2      0x104D9C
+#define        XRAMINDOPERREFUP_STARTDSP2      0x104DA0
+#define        XRAMINDOPERREFUP_ENDDSP2        0x104DBC
+#define        YRAMINDOPERREFNOUP_STARTDSP2    0x104DC0
+#define        YRAMINDOPERREFNOUP_ENDDSP2      0x104DDC
+#define        YRAMINDOPERREFUP_STARTDSP2      0x104DE0
+#define        YRAMINDOPERREFUP_ENDDSP2        0x104DFC
+#define        DSP2CONDCODE                    0x104E00
+#define        DSP2STACKFLAG                   0x104E04
+#define        DSP2PROGCOUNTSTACKPTREG         0x104E08
+#define        DSP2PROGCOUNTSTACKDATAREG       0x104E0C
+#define        DSP2CURLOOPADDRREG              0x104E10
+#define        DSP2CURLOOPCOUNT                0x104E14
+#define        DSP2TOPLOOPCOUNTSTACK           0x104E18
+#define        DSP2TOPLOOPADDRSTACK            0x104E1C
+#define        DSP2LOOPSTACKPTR                0x104E20
+#define        DSP2STASSTACKDATAREG            0x104E24
+#define        DSP2STASSTACKPTR                0x104E28
+#define        DSP2PROGCOUNT                   0x104E2C
+#define        DSP2XYRAMBASE_START             0x104EA0
+#define        DSP2XYRAMBASE_END               0x104EBC
+#define        DSP2XYRAMLENG_START             0x104EC0
+#define        DSP2XYRAMLENG_END               0x104EDC
+#define                SEMAPHOREREGDSP2                0x104EE0
+#define                DSP2INTCONTMASKREG              0x104EE4
+#define                DSP2INTCONTPENDREG              0x104EE8
+#define                DSP2INTCONTSERVINT              0x104EEC
+#define                GPIODSP2                        0x104EFC
+#define        DMADSPBASEADDRREG_STARTDSP2     0x104F00
+#define        DMADSPBASEADDRREG_ENDDSP2       0x104F1C
+#define        DMAHOSTBASEADDRREG_STARTDSP2    0x104F20
+#define        DMAHOSTBASEADDRREG_ENDDSP2      0x104F3C
+#define        DMADSPCURADDRREG_STARTDSP2      0x104F40
+#define        DMADSPCURADDRREG_ENDDSP2        0x104F5C
+#define        DMAHOSTCURADDRREG_STARTDSP2     0x104F60
+#define        DMAHOSTCURADDRREG_ENDDSP2       0x104F7C
+#define        DMATANXCOUNTREG_STARTDSP2       0x104F80
+#define        DMATANXCOUNTREG_ENDDSP2         0x104F9C
+#define        DMATIMEBUGREG_STARTDSP2         0x104FA0
+#define        DMATIMEBUGREG_ENDDSP2           0x104FAC
+#define        DMACNTLMODFREG_STARTDSP2        0x104FA0
+#define        DMACNTLMODFREG_ENDDSP2          0x104FAC
+
+#define        DMAGLOBSTATSREGDSP2             0x104FEC
+#define        DSP2XGPRAM_START                0x105000
+#define        DSP2XGPRAM_END                  0x1051FC
+#define        DSP2YGPRAM_START                0x105800
+#define        DSP2YGPRAM_END                  0x1059FC
+
+
+
+#define        AUDIORINGIPDSP3_START           0x106000
+#define        AUDIORINGIPDSP3_END             0x1063FC
+#define        AUDIORINGOPDSP3_START           0x106400
+#define        AUDIORINGOPDSP3_END             0x1067FC
+#define        AUDPARARINGIODSP3_START         0x106800
+#define        AUDPARARINGIODSP3_END           0x106BFC
+#define        DSP3LOCALHWREG_START            0x106C00
+#define        DSP3LOCALHWREG_END              0x106C3C
+#define        DSP3XYRAMAGINDEX_START          0x106C40
+#define        DSP3XYRAMAGINDEX_END            0x106C5C
+#define        DSP3XYRAMAGMDFR_START           0x106C60
+#define        DSP3XYRAMAGMDFR_END             0x106C7C
+#define        DSP3INTCONTLVEC_START           0x106C80
+#define        DSP3INTCONTLVEC_END             0x106CD8
+#define                HOSTINTFPORTADDRCONTDSP3        0x106D40
+#define                HOSTINTFPORTDATADSP3            0x106D44
+#define                TIME0PERENBDSP3                 0x106D60
+#define                TIME0COUNTERDSP3                0x106D64
+#define                TIME1PERENBDSP3                 0x106D68
+#define                TIME1COUNTERDSP3                0x106D6C
+#define                TIME2PERENBDSP3                 0x106D70
+#define                TIME2COUNTERDSP3                0x106D74
+#define                TIME3PERENBDSP3                 0x106D78
+#define                TIME3COUNTERDSP3                0x106D7C
+#define        XRAMINDOPERREFNOUP_STARTDSP3    0x106D80
+#define        XRAMINDOPERREFNOUP_ENDDSP3      0x106D9C
+#define        XRAMINDOPERREFUP_STARTDSP3      0x106DA0
+#define        XRAMINDOPERREFUP_ENDDSP3        0x106DBC
+#define        YRAMINDOPERREFNOUP_STARTDSP3    0x106DC0
+#define        YRAMINDOPERREFNOUP_ENDDSP3      0x106DDC
+#define        YRAMINDOPERREFUP_STARTDSP3      0x106DE0
+#define        YRAMINDOPERREFUP_ENDDSP3        0x100DFC
+
+#define        DSP3CONDCODE                    0x106E00
+#define        DSP3STACKFLAG                   0x106E04
+#define        DSP3PROGCOUNTSTACKPTREG         0x106E08
+#define        DSP3PROGCOUNTSTACKDATAREG       0x106E0C
+#define        DSP3CURLOOPADDRREG              0x106E10
+#define        DSP3CURLOOPCOUNT                0x106E14
+#define        DSP3TOPLOOPCOUNTSTACK           0x106E18
+#define        DSP3TOPLOOPADDRSTACK            0x106E1C
+#define        DSP3LOOPSTACKPTR                0x106E20
+#define        DSP3STASSTACKDATAREG            0x106E24
+#define        DSP3STASSTACKPTR                0x106E28
+#define        DSP3PROGCOUNT                   0x106E2C
+#define        DSP3XYRAMBASE_START             0x106EA0
+#define        DSP3XYRAMBASE_END               0x106EBC
+#define        DSP3XYRAMLENG_START             0x106EC0
+#define        DSP3XYRAMLENG_END               0x106EDC
+#define                SEMAPHOREREGDSP3                0x106EE0
+#define                DSP3INTCONTMASKREG              0x106EE4
+#define                DSP3INTCONTPENDREG              0x106EE8
+#define                DSP3INTCONTSERVINT              0x106EEC
+#define                GPIODSP3                        0x106EFC
+#define        DMADSPBASEADDRREG_STARTDSP3     0x106F00
+#define        DMADSPBASEADDRREG_ENDDSP3       0x106F1C
+#define        DMAHOSTBASEADDRREG_STARTDSP3    0x106F20
+#define        DMAHOSTBASEADDRREG_ENDDSP3      0x106F3C
+#define        DMADSPCURADDRREG_STARTDSP3      0x106F40
+#define        DMADSPCURADDRREG_ENDDSP3        0x106F5C
+#define        DMAHOSTCURADDRREG_STARTDSP3     0x106F60
+#define        DMAHOSTCURADDRREG_ENDDSP3       0x106F7C
+#define        DMATANXCOUNTREG_STARTDSP3       0x106F80
+#define        DMATANXCOUNTREG_ENDDSP3         0x106F9C
+#define        DMATIMEBUGREG_STARTDSP3         0x106FA0
+#define        DMATIMEBUGREG_ENDDSP3           0x106FAC
+#define        DMACNTLMODFREG_STARTDSP3        0x106FA0
+#define        DMACNTLMODFREG_ENDDSP3          0x106FAC
+
+#define        DMAGLOBSTATSREGDSP3             0x106FEC
+#define        DSP3XGPRAM_START                0x107000
+#define        DSP3XGPRAM_END                  0x1071FC
+#define        DSP3YGPRAM_START                0x107800
+#define        DSP3YGPRAM_END                  0x1079FC
+
+/* end of DSP reg definitions */
+
+#define        DSPAIMAP_START                  0x108000
+#define        DSPAIMAP_END                    0x1083FC
+#define        DSPPIMAP_START                  0x108400
+#define        DSPPIMAP_END                    0x1087FC
+#define        DSPPOMAP_START                  0x108800
+#define        DSPPOMAP_END                    0x108BFC
+#define        DSPPOCTL                        0x108C00
+#define        TKCTL_START                     0x110000
+#define        TKCTL_END                       0x110FFC
+#define        TKCC_START                      0x111000
+#define        TKCC_END                        0x111FFC
+#define        TKIMAP_START                    0x112000
+#define        TKIMAP_END                      0x112FFC
+#define                TKDCTR16                        0x113000
+#define                TKPB16                          0x113004
+#define                TKBS16                          0x113008
+#define                TKDCTR32                        0x11300C
+#define                TKPB32                          0x113010
+#define                TKBS32                          0x113014
+#define                ICDCTR16                        0x113018
+#define                ITBS16                          0x11301C
+#define                ICDCTR32                        0x113020
+#define                ITBS32                          0x113024
+#define                ITSTART                         0x113028
+#define                TKSQ                            0x11302C
+
+#define                TKSCCTL_START                   0x114000
+#define                TKSCCTL_END                     0x11403C
+#define                TKSCADR_START                   0x114100
+#define                TKSCADR_END                     0x11413C
+#define                TKSCDATAX_START                 0x114800
+#define                TKSCDATAX_END                   0x1149FC
+#define                TKPCDATAX_START                 0x120000
+#define                TKPCDATAX_END                   0x12FFFC
+
+#define                MALSA                           0x130000
+#define                MAPPHA                          0x130004
+#define                MAPPLA                          0x130008
+#define                MALSB                           0x130010
+#define                MAPPHB                          0x130014
+#define                MAPPLB                          0x130018
+
+#define        TANSPORTMAPABREGS_START         0x130020
+#define        TANSPORTMAPABREGS_END           0x13A2FC
+
+#define                PTPAHX                          0x13B000
+#define                PTPALX                          0x13B004
+
+#define                TANSPPAGETABLEPHYADDR015_START  0x13B008
+#define                TANSPPAGETABLEPHYADDR015_END    0x13B07C
+#define                TRNQADRX_START                  0x13B100
+#define                TRNQADRX_END                    0x13B13C
+#define                TRNQTIMX_START                  0x13B200
+#define                TRNQTIMX_END                    0x13B23C
+#define                TRNQAPARMX_START                0x13B300
+#define                TRNQAPARMX_END                  0x13B33C
+
+#define                TRNQCNT                         0x13B400
+#define                TRNCTL                          0x13B404
+#define                TRNIS                           0x13B408
+#define                TRNCURTS                        0x13B40C
+
+#define                AMOP_START                      0x140000
+#define                AMOPLO                          0x140000
+#define                AMOPHI                          0x140004
+#define                AMOP_END                        0x147FFC
+#define                PMOP_START                      0x148000
+#define                PMOPLO                          0x148000
+#define                PMOPHI                          0x148004
+#define                PMOP_END                        0x14FFFC
+#define                PCURR_START                     0x150000
+#define                PCURR_END                       0x153FFC
+#define                PTRAG_START                     0x154000
+#define                PTRAG_END                       0x157FFC
+#define                PSR_START                       0x158000
+#define                PSR_END                         0x15BFFC
+
+#define                PFSTAT4SEG_START                0x160000
+#define                PFSTAT4SEG_END                  0x160BFC
+#define                PFSTAT2SEG_START                0x160C00
+#define                PFSTAT2SEG_END                  0x1617FC
+#define                PFTARG4SEG_START                0x164000
+#define                PFTARG4SEG_END                  0x164BFC
+#define                PFTARG2SEG_START                0x164C00
+#define                PFTARG2SEG_END                  0x1657FC
+#define                PFSR4SEG_START                  0x168000
+#define                PFSR4SEG_END                    0x168BFC
+#define                PFSR2SEG_START                  0x168C00
+#define                PFSR2SEG_END                    0x1697FC
+#define                PCURRMS4SEG_START               0x16C000
+#define                PCURRMS4SEG_END                 0x16CCFC
+#define                PCURRMS2SEG_START               0x16CC00
+#define                PCURRMS2SEG_END                 0x16D7FC
+#define                PTARGMS4SEG_START               0x170000
+#define                PTARGMS4SEG_END                 0x172FFC
+#define                PTARGMS2SEG_START               0x173000
+#define                PTARGMS2SEG_END                 0x1747FC
+#define                PSRMS4SEG_START                 0x170000
+#define                PSRMS4SEG_END                   0x172FFC
+#define                PSRMS2SEG_START                 0x173000
+#define                PSRMS2SEG_END                   0x1747FC
+
+#define                PRING_LO_START                  0x190000
+#define                PRING_LO_END                    0x193FFC
+#define                PRING_HI_START                  0x194000
+#define                PRING_HI_END                    0x197FFC
+#define                PRING_LO_HI_START               0x198000
+#define                PRING_LO_HI                     0x198000
+#define                PRING_LO_HI_END                 0x19BFFC
+
+#define                PINTFIFO                        0x1A0000
+#define                SRCCTL                          0x1B0000
+#define                SRCCCR                          0x1B0004
+#define                SRCIMAP                         0x1B0008
+#define                SRCODDC                         0x1B000C
+#define                SRCCA                           0x1B0010
+#define                SRCCF                           0x1B0014
+#define                SRCSA                           0x1B0018
+#define                SRCLA                           0x1B001C
+#define                SRCCTLSWR                       0x1B0020
+
+/* SRC HERE */
+#define                SRCALBA                         0x1B002C
+#define                SRCMCTL                         0x1B012C
+#define                SRCCERR                         0x1B022C
+#define                SRCITB                          0x1B032C
+#define                SRCIPM                          0x1B082C
+#define                SRCIP                           0x1B102C
+#define                SRCENBSTAT                      0x1B202C
+#define                SRCENBLO                        0x1B212C
+#define                SRCENBHI                        0x1B222C
+#define                SRCENBS                         0x1B232C
+#define                SRCENB                          0x1B282C
+#define                SRCENB07                        0x1B282C
+#define                SRCENBS07                       0x1B302C
+
+#define                SRCDN0Z                         0x1B0030
+#define                SRCDN0Z0                        0x1B0030
+#define                SRCDN0Z1                        0x1B0034
+#define                SRCDN0Z2                        0x1B0038
+#define                SRCDN0Z3                        0x1B003C
+#define                SRCDN1Z                         0x1B0040
+#define                SRCDN1Z0                        0x1B0040
+#define                SRCDN1Z1                        0x1B0044
+#define                SRCDN1Z2                        0x1B0048
+#define                SRCDN1Z3                        0x1B004C
+#define                SRCDN1Z4                        0x1B0050
+#define                SRCDN1Z5                        0x1B0054
+#define                SRCDN1Z6                        0x1B0058
+#define                SRCDN1Z7                        0x1B005C
+#define                SRCUPZ                          0x1B0060
+#define                SRCUPZ0                         0x1B0060
+#define                SRCUPZ1                         0x1B0064
+#define                SRCUPZ2                         0x1B0068
+#define                SRCUPZ3                         0x1B006C
+#define                SRCUPZ4                         0x1B0070
+#define                SRCUPZ5                         0x1B0074
+#define                SRCUPZ6                         0x1B0078
+#define                SRCUPZ7                         0x1B007C
+#define                SRCCD0                          0x1B0080
+#define                SRCCD1                          0x1B0084
+#define                SRCCD2                          0x1B0088
+#define                SRCCD3                          0x1B008C
+#define                SRCCD4                          0x1B0090
+#define                SRCCD5                          0x1B0094
+#define                SRCCD6                          0x1B0098
+#define                SRCCD7                          0x1B009C
+#define                SRCCD8                          0x1B00A0
+#define                SRCCD9                          0x1B00A4
+#define                SRCCDA                          0x1B00A8
+#define                SRCCDB                          0x1B00AC
+#define                SRCCDC                          0x1B00B0
+#define                SRCCDD                          0x1B00B4
+#define                SRCCDE                          0x1B00B8
+#define                SRCCDF                          0x1B00BC
+#define                SRCCD10                         0x1B00C0
+#define                SRCCD11                         0x1B00C4
+#define                SRCCD12                         0x1B00C8
+#define                SRCCD13                         0x1B00CC
+#define                SRCCD14                         0x1B00D0
+#define                SRCCD15                         0x1B00D4
+#define                SRCCD16                         0x1B00D8
+#define                SRCCD17                         0x1B00DC
+#define                SRCCD18                         0x1B00E0
+#define                SRCCD19                         0x1B00E4
+#define                SRCCD1A                         0x1B00E8
+#define                SRCCD1B                         0x1B00EC
+#define                SRCCD1C                         0x1B00F0
+#define                SRCCD1D                         0x1B00F4
+#define                SRCCD1E                         0x1B00F8
+#define                SRCCD1F                         0x1B00FC
+
+#define                SRCCONTRBLOCK_START             0x1B0100
+#define                SRCCONTRBLOCK_END               0x1BFFFC
+#define                FILTOP_START    0x1C0000
+#define                FILTOP_END      0x1C05FC
+#define                FILTIMAP_START  0x1C0800
+#define                FILTIMAP_END    0x1C0DFC
+#define                FILTZ1_START    0x1C1000
+#define                FILTZ1_END      0x1C15FC
+#define                FILTZ2_START    0x1C1800
+#define                FILTZ2_END      0x1C1DFC
+#define                DAOIMAP_START   0x1C5000
+#define                DAOIMAP         0x1C5000
+#define                DAOIMAP_END     0x1C5124
+
+#define                AC97D           0x1C5400
+#define                AC97A           0x1C5404
+#define                AC97CTL         0x1C5408
+#define                I2SCTL          0x1C5420
+
+#define                SPOS            0x1C5440
+#define                SPOSA           0x1C5440
+#define                SPOSB           0x1C5444
+#define                SPOSC           0x1C5448
+#define                SPOSD           0x1C544C
+
+#define                SPISA           0x1C5450
+#define                SPISB           0x1C5454
+#define                SPISC           0x1C5458
+#define                SPISD           0x1C545C
+
+#define                SPFSCTL         0x1C5460
+
+#define                SPFS0           0x1C5468
+#define                SPFS1           0x1C546C
+#define                SPFS2           0x1C5470
+#define                SPFS3           0x1C5474
+#define                SPFS4           0x1C5478
+#define                SPFS5           0x1C547C
+
+#define                SPOCTL          0x1C5480
+#define                SPICTL          0x1C5484
+#define                SPISTS          0x1C5488
+#define                SPINTP          0x1C548C
+#define                SPINTE          0x1C5490
+#define                SPUTCTLAB       0x1C5494
+#define                SPUTCTLCD       0x1C5498
+
+#define                SRTSPA          0x1C54C0
+#define                SRTSPB          0x1C54C4
+#define                SRTSPC          0x1C54C8
+#define                SRTSPD          0x1C54CC
+
+#define                SRTSCTL         0x1C54D0
+#define                SRTSCTLA        0x1C54D0
+#define                SRTSCTLB        0x1C54D4
+#define                SRTSCTLC        0x1C54D8
+#define                SRTSCTLD        0x1C54DC
+
+#define                SRTI2S          0x1C54E0
+#define                SRTICTL         0x1C54F0
+
+#define                WC              0x1C6000
+#define                TIMR            0x1C6004
+# define       TIMR_IE         (1<<15)
+# define       TIMR_IP         (1<<14)
+
+#define                GIP             0x1C6010
+#define                GIE             0x1C6014
+#define                DIE             0x1C6018
+#define                DIC             0x1C601C
+#define                GPIO            0x1C6020
+#define                GPIOCTL         0x1C6024
+#define                GPIP            0x1C6028
+#define                GPIE            0x1C602C
+#define                DSPINT0         0x1C6030
+#define                DSPEIOC         0x1C6034
+#define                MUADAT          0x1C6040
+#define                MUACMD          0x1C6044
+#define        MUASTAT         0x1C6044
+#define                MUBDAT          0x1C6048
+#define                MUBCMD          0x1C604C
+#define                MUBSTAT         0x1C604C
+#define                UARTCMA         0x1C6050
+#define                UARTCMB         0x1C6054
+#define                UARTIP          0x1C6058
+#define                UARTIE          0x1C605C
+#define                PLLCTL          0x1C6060
+#define                PLLDCD          0x1C6064
+#define                GCTL            0x1C6070
+#define                ID0             0x1C6080
+#define                ID1             0x1C6084
+#define                ID2             0x1C6088
+#define                ID3             0x1C608C
+#define                SDRCTL          0x1C7000
+
+
+#define I2SA_L    0x0L
+#define I2SA_R    0x1L
+#define I2SB_L    0x8L
+#define I2SB_R    0x9L
+#define I2SC_L    0x10L
+#define I2SC_R    0x11L
+#define I2SD_L    0x18L
+#define I2SD_R    0x19L
+
+#endif /* CT20K1REG_H */
+
+
diff --git a/sound/pci/ctxfi/ct20k2reg.h b/sound/pci/ctxfi/ct20k2reg.h
new file mode 100644 (file)
index 0000000..2d07986
--- /dev/null
@@ -0,0 +1,85 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ */
+
+#ifndef _20K2REGISTERS_H_
+#define _20K2REGISTERS_H_
+
+
+/* Timer Registers */
+#define TIMER_TIMR          0x1B7004
+#define INTERRUPT_GIP       0x1B7010
+#define INTERRUPT_GIE       0x1B7014
+
+/* I2C Registers */
+#define I2C_IF_ADDRESS   0x1B9000
+#define I2C_IF_WDATA     0x1B9004
+#define I2C_IF_RDATA     0x1B9008
+#define I2C_IF_STATUS    0x1B900C
+#define I2C_IF_WLOCK     0x1B9010
+
+/* Global Control Registers */
+#define GLOBAL_CNTL_GCTL    0x1B7090
+
+/* PLL Registers */
+#define PLL_CTL                0x1B7080
+#define PLL_STAT               0x1B7084
+#define PLL_ENB                        0x1B7088
+
+/* SRC Registers */
+#define SRC_CTL             0x1A0000 /* 0x1A0000 + (256 * Chn) */
+#define SRC_CCR             0x1A0004 /* 0x1A0004 + (256 * Chn) */
+#define SRC_IMAP            0x1A0008 /* 0x1A0008 + (256 * Chn) */
+#define SRC_CA              0x1A0010 /* 0x1A0010 + (256 * Chn) */
+#define SRC_CF              0x1A0014 /* 0x1A0014 + (256 * Chn) */
+#define SRC_SA              0x1A0018 /* 0x1A0018 + (256 * Chn) */
+#define SRC_LA              0x1A001C /* 0x1A001C + (256 * Chn) */
+#define SRC_CTLSWR         0x1A0020 /* 0x1A0020 + (256 * Chn) */
+#define SRC_CD             0x1A0080 /* 0x1A0080 + (256 * Chn) + (4 * Regn) */
+#define SRC_MCTL               0x1A012C
+#define SRC_IP                 0x1A102C /* 0x1A102C + (256 * Regn) */
+#define SRC_ENB                        0x1A282C /* 0x1A282C + (256 * Regn) */
+#define SRC_ENBSTAT            0x1A202C
+#define SRC_ENBSA              0x1A232C
+#define SRC_DN0Z               0x1A0030
+#define SRC_DN1Z               0x1A0040
+#define SRC_UPZ                        0x1A0060
+
+/* GPIO Registers */
+#define GPIO_DATA           0x1B7020
+#define GPIO_CTRL           0x1B7024
+
+/* Virtual memory registers */
+#define VMEM_PTPAL          0x1C6300 /* 0x1C6300 + (16 * Chn) */
+#define VMEM_PTPAH          0x1C6304 /* 0x1C6304 + (16 * Chn) */
+#define VMEM_CTL            0x1C7000
+
+/* Transport Registers */
+#define TRANSPORT_ENB       0x1B6000
+#define TRANSPORT_CTL       0x1B6004
+#define TRANSPORT_INT       0x1B6008
+
+/* Audio IO */
+#define AUDIO_IO_AIM        0x1B5000 /* 0x1B5000 + (0x04 * Chn) */
+#define AUDIO_IO_TX_CTL     0x1B5400 /* 0x1B5400 + (0x40 * Chn) */
+#define AUDIO_IO_TX_CSTAT_L 0x1B5408 /* 0x1B5408 + (0x40 * Chn) */
+#define AUDIO_IO_TX_CSTAT_H 0x1B540C /* 0x1B540C + (0x40 * Chn) */
+#define AUDIO_IO_RX_CTL     0x1B5410 /* 0x1B5410 + (0x40 * Chn) */
+#define AUDIO_IO_RX_SRT_CTL 0x1B5420 /* 0x1B5420 + (0x40 * Chn) */
+#define AUDIO_IO_MCLK       0x1B5600
+#define AUDIO_IO_TX_BLRCLK  0x1B5604
+#define AUDIO_IO_RX_BLRCLK  0x1B5608
+
+/* Mixer */
+#define MIXER_AMOPLO           0x130000 /* 0x130000 + (8 * Chn) [4095 : 0] */
+#define MIXER_AMOPHI           0x130004 /* 0x130004 + (8 * Chn) [4095 : 0] */
+#define MIXER_PRING_LO_HI      0x188000 /* 0x188000 + (4 * Chn) [4095 : 0] */
+#define MIXER_PMOPLO           0x138000 /* 0x138000 + (8 * Chn) [4095 : 0] */
+#define MIXER_PMOPHI           0x138004 /* 0x138004 + (8 * Chn) [4095 : 0] */
+#define MIXER_AR_ENABLE                0x19000C
+
+#endif
diff --git a/sound/pci/ctxfi/ctamixer.c b/sound/pci/ctxfi/ctamixer.c
new file mode 100644 (file)
index 0000000..a1db51b
--- /dev/null
@@ -0,0 +1,488 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File       ctamixer.c
+ *
+ * @Brief
+ * This file contains the implementation of the Audio Mixer
+ * resource management object.
+ *
+ * @Author     Liu Chun
+ * @Date       May 21 2008
+ *
+ */
+
+#include "ctamixer.h"
+#include "cthardware.h"
+#include <linux/slab.h>
+
+#define AMIXER_RESOURCE_NUM    256
+#define SUM_RESOURCE_NUM       256
+
+#define AMIXER_Y_IMMEDIATE     1
+
+#define BLANK_SLOT             4094
+
+static int amixer_master(struct rsc *rsc)
+{
+       rsc->conj = 0;
+       return rsc->idx = container_of(rsc, struct amixer, rsc)->idx[0];
+}
+
+static int amixer_next_conj(struct rsc *rsc)
+{
+       rsc->conj++;
+       return container_of(rsc, struct amixer, rsc)->idx[rsc->conj];
+}
+
+static int amixer_index(const struct rsc *rsc)
+{
+       return container_of(rsc, struct amixer, rsc)->idx[rsc->conj];
+}
+
+static int amixer_output_slot(const struct rsc *rsc)
+{
+       return (amixer_index(rsc) << 4) + 0x4;
+}
+
+static struct rsc_ops amixer_basic_rsc_ops = {
+       .master         = amixer_master,
+       .next_conj      = amixer_next_conj,
+       .index          = amixer_index,
+       .output_slot    = amixer_output_slot,
+};
+
+static int amixer_set_input(struct amixer *amixer, struct rsc *rsc)
+{
+       struct hw *hw;
+
+       hw = amixer->rsc.hw;
+       hw->amixer_set_mode(amixer->rsc.ctrl_blk, AMIXER_Y_IMMEDIATE);
+       amixer->input = rsc;
+       if (NULL == rsc)
+               hw->amixer_set_x(amixer->rsc.ctrl_blk, BLANK_SLOT);
+       else
+               hw->amixer_set_x(amixer->rsc.ctrl_blk,
+                                       rsc->ops->output_slot(rsc));
+
+       return 0;
+}
+
+/* y is a 14-bit immediate constant */
+static int amixer_set_y(struct amixer *amixer, unsigned int y)
+{
+       struct hw *hw;
+
+       hw = amixer->rsc.hw;
+       hw->amixer_set_y(amixer->rsc.ctrl_blk, y);
+
+       return 0;
+}
+
+static int amixer_set_invalid_squash(struct amixer *amixer, unsigned int iv)
+{
+       struct hw *hw;
+
+       hw = amixer->rsc.hw;
+       hw->amixer_set_iv(amixer->rsc.ctrl_blk, iv);
+
+       return 0;
+}
+
+static int amixer_set_sum(struct amixer *amixer, struct sum *sum)
+{
+       struct hw *hw;
+
+       hw = amixer->rsc.hw;
+       amixer->sum = sum;
+       if (NULL == sum) {
+               hw->amixer_set_se(amixer->rsc.ctrl_blk, 0);
+       } else {
+               hw->amixer_set_se(amixer->rsc.ctrl_blk, 1);
+               hw->amixer_set_sadr(amixer->rsc.ctrl_blk,
+                                       sum->rsc.ops->index(&sum->rsc));
+       }
+
+       return 0;
+}
+
+static int amixer_commit_write(struct amixer *amixer)
+{
+       struct hw *hw;
+       unsigned int index;
+       int i;
+       struct rsc *input;
+       struct sum *sum;
+
+       hw = amixer->rsc.hw;
+       input = amixer->input;
+       sum = amixer->sum;
+
+       /* Program master and conjugate resources */
+       amixer->rsc.ops->master(&amixer->rsc);
+       if (NULL != input)
+               input->ops->master(input);
+
+       if (NULL != sum)
+               sum->rsc.ops->master(&sum->rsc);
+
+       for (i = 0; i < amixer->rsc.msr; i++) {
+               hw->amixer_set_dirty_all(amixer->rsc.ctrl_blk);
+               if (NULL != input) {
+                       hw->amixer_set_x(amixer->rsc.ctrl_blk,
+                                               input->ops->output_slot(input));
+                       input->ops->next_conj(input);
+               }
+               if (NULL != sum) {
+                       hw->amixer_set_sadr(amixer->rsc.ctrl_blk,
+                                               sum->rsc.ops->index(&sum->rsc));
+                       sum->rsc.ops->next_conj(&sum->rsc);
+               }
+               index = amixer->rsc.ops->output_slot(&amixer->rsc);
+               hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk);
+               amixer->rsc.ops->next_conj(&amixer->rsc);
+       }
+       amixer->rsc.ops->master(&amixer->rsc);
+       if (NULL != input)
+               input->ops->master(input);
+
+       if (NULL != sum)
+               sum->rsc.ops->master(&sum->rsc);
+
+       return 0;
+}
+
+static int amixer_commit_raw_write(struct amixer *amixer)
+{
+       struct hw *hw;
+       unsigned int index;
+
+       hw = amixer->rsc.hw;
+       index = amixer->rsc.ops->output_slot(&amixer->rsc);
+       hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk);
+
+       return 0;
+}
+
+static int amixer_get_y(struct amixer *amixer)
+{
+       struct hw *hw;
+
+       hw = amixer->rsc.hw;
+       return hw->amixer_get_y(amixer->rsc.ctrl_blk);
+}
+
+static int amixer_setup(struct amixer *amixer, struct rsc *input,
+                       unsigned int scale, struct sum *sum)
+{
+       amixer_set_input(amixer, input);
+       amixer_set_y(amixer, scale);
+       amixer_set_sum(amixer, sum);
+       amixer_commit_write(amixer);
+       return 0;
+}
+
+static struct amixer_rsc_ops amixer_ops = {
+       .set_input              = amixer_set_input,
+       .set_invalid_squash     = amixer_set_invalid_squash,
+       .set_scale              = amixer_set_y,
+       .set_sum                = amixer_set_sum,
+       .commit_write           = amixer_commit_write,
+       .commit_raw_write       = amixer_commit_raw_write,
+       .setup                  = amixer_setup,
+       .get_scale              = amixer_get_y,
+};
+
+static int amixer_rsc_init(struct amixer *amixer,
+                          const struct amixer_desc *desc,
+                          struct amixer_mgr *mgr)
+{
+       int err;
+
+       err = rsc_init(&amixer->rsc, amixer->idx[0],
+                       AMIXER, desc->msr, mgr->mgr.hw);
+       if (err)
+               return err;
+
+       /* Set amixer specific operations */
+       amixer->rsc.ops = &amixer_basic_rsc_ops;
+       amixer->ops = &amixer_ops;
+       amixer->input = NULL;
+       amixer->sum = NULL;
+
+       amixer_setup(amixer, NULL, 0, NULL);
+
+       return 0;
+}
+
+static int amixer_rsc_uninit(struct amixer *amixer)
+{
+       amixer_setup(amixer, NULL, 0, NULL);
+       rsc_uninit(&amixer->rsc);
+       amixer->ops = NULL;
+       amixer->input = NULL;
+       amixer->sum = NULL;
+       return 0;
+}
+
+static int get_amixer_rsc(struct amixer_mgr *mgr,
+                         const struct amixer_desc *desc,
+                         struct amixer **ramixer)
+{
+       int err, i;
+       unsigned int idx;
+       struct amixer *amixer;
+       unsigned long flags;
+
+       *ramixer = NULL;
+
+       /* Allocate mem for amixer resource */
+       amixer = kzalloc(sizeof(*amixer), GFP_KERNEL);
+       if (NULL == amixer) {
+               err = -ENOMEM;
+               return err;
+       }
+
+       /* Check whether there are sufficient
+        * amixer resources to meet request. */
+       spin_lock_irqsave(&mgr->mgr_lock, flags);
+       for (i = 0; i < desc->msr; i++) {
+               err = mgr_get_resource(&mgr->mgr, 1, &idx);
+               if (err)
+                       break;
+
+               amixer->idx[i] = idx;
+       }
+       spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+       if (err) {
+               printk(KERN_ERR "ctxfi: Can't meet AMIXER resource request!\n");
+               goto error;
+       }
+
+       err = amixer_rsc_init(amixer, desc, mgr);
+       if (err)
+               goto error;
+
+       *ramixer = amixer;
+
+       return 0;
+
+error:
+       spin_lock_irqsave(&mgr->mgr_lock, flags);
+       for (i--; i >= 0; i--)
+               mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]);
+
+       spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+       kfree(amixer);
+       return err;
+}
+
+static int put_amixer_rsc(struct amixer_mgr *mgr, struct amixer *amixer)
+{
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&mgr->mgr_lock, flags);
+       for (i = 0; i < amixer->rsc.msr; i++)
+               mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]);
+
+       spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+       amixer_rsc_uninit(amixer);
+       kfree(amixer);
+
+       return 0;
+}
+
+int amixer_mgr_create(void *hw, struct amixer_mgr **ramixer_mgr)
+{
+       int err;
+       struct amixer_mgr *amixer_mgr;
+
+       *ramixer_mgr = NULL;
+       amixer_mgr = kzalloc(sizeof(*amixer_mgr), GFP_KERNEL);
+       if (NULL == amixer_mgr)
+               return -ENOMEM;
+
+       err = rsc_mgr_init(&amixer_mgr->mgr, AMIXER, AMIXER_RESOURCE_NUM, hw);
+       if (err)
+               goto error;
+
+       spin_lock_init(&amixer_mgr->mgr_lock);
+
+       amixer_mgr->get_amixer = get_amixer_rsc;
+       amixer_mgr->put_amixer = put_amixer_rsc;
+
+       *ramixer_mgr = amixer_mgr;
+
+       return 0;
+
+error:
+       kfree(amixer_mgr);
+       return err;
+}
+
+int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr)
+{
+       rsc_mgr_uninit(&amixer_mgr->mgr);
+       kfree(amixer_mgr);
+       return 0;
+}
+
+/* SUM resource management */
+
+static int sum_master(struct rsc *rsc)
+{
+       rsc->conj = 0;
+       return rsc->idx = container_of(rsc, struct sum, rsc)->idx[0];
+}
+
+static int sum_next_conj(struct rsc *rsc)
+{
+       rsc->conj++;
+       return container_of(rsc, struct sum, rsc)->idx[rsc->conj];
+}
+
+static int sum_index(const struct rsc *rsc)
+{
+       return container_of(rsc, struct sum, rsc)->idx[rsc->conj];
+}
+
+static int sum_output_slot(const struct rsc *rsc)
+{
+       return (sum_index(rsc) << 4) + 0xc;
+}
+
+static struct rsc_ops sum_basic_rsc_ops = {
+       .master         = sum_master,
+       .next_conj      = sum_next_conj,
+       .index          = sum_index,
+       .output_slot    = sum_output_slot,
+};
+
+static int sum_rsc_init(struct sum *sum,
+                       const struct sum_desc *desc,
+                       struct sum_mgr *mgr)
+{
+       int err;
+
+       err = rsc_init(&sum->rsc, sum->idx[0], SUM, desc->msr, mgr->mgr.hw);
+       if (err)
+               return err;
+
+       sum->rsc.ops = &sum_basic_rsc_ops;
+
+       return 0;
+}
+
+static int sum_rsc_uninit(struct sum *sum)
+{
+       rsc_uninit(&sum->rsc);
+       return 0;
+}
+
+static int get_sum_rsc(struct sum_mgr *mgr,
+                      const struct sum_desc *desc,
+                      struct sum **rsum)
+{
+       int err, i;
+       unsigned int idx;
+       struct sum *sum;
+       unsigned long flags;
+
+       *rsum = NULL;
+
+       /* Allocate mem for sum resource */
+       sum = kzalloc(sizeof(*sum), GFP_KERNEL);
+       if (NULL == sum) {
+               err = -ENOMEM;
+               return err;
+       }
+
+       /* Check whether there are sufficient sum resources to meet request. */
+       spin_lock_irqsave(&mgr->mgr_lock, flags);
+       for (i = 0; i < desc->msr; i++) {
+               err = mgr_get_resource(&mgr->mgr, 1, &idx);
+               if (err)
+                       break;
+
+               sum->idx[i] = idx;
+       }
+       spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+       if (err) {
+               printk(KERN_ERR "ctxfi: Can't meet SUM resource request!\n");
+               goto error;
+       }
+
+       err = sum_rsc_init(sum, desc, mgr);
+       if (err)
+               goto error;
+
+       *rsum = sum;
+
+       return 0;
+
+error:
+       spin_lock_irqsave(&mgr->mgr_lock, flags);
+       for (i--; i >= 0; i--)
+               mgr_put_resource(&mgr->mgr, 1, sum->idx[i]);
+
+       spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+       kfree(sum);
+       return err;
+}
+
+static int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum)
+{
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&mgr->mgr_lock, flags);
+       for (i = 0; i < sum->rsc.msr; i++)
+               mgr_put_resource(&mgr->mgr, 1, sum->idx[i]);
+
+       spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+       sum_rsc_uninit(sum);
+       kfree(sum);
+
+       return 0;
+}
+
+int sum_mgr_create(void *hw, struct sum_mgr **rsum_mgr)
+{
+       int err;
+       struct sum_mgr *sum_mgr;
+
+       *rsum_mgr = NULL;
+       sum_mgr = kzalloc(sizeof(*sum_mgr), GFP_KERNEL);
+       if (NULL == sum_mgr)
+               return -ENOMEM;
+
+       err = rsc_mgr_init(&sum_mgr->mgr, SUM, SUM_RESOURCE_NUM, hw);
+       if (err)
+               goto error;
+
+       spin_lock_init(&sum_mgr->mgr_lock);
+
+       sum_mgr->get_sum = get_sum_rsc;
+       sum_mgr->put_sum = put_sum_rsc;
+
+       *rsum_mgr = sum_mgr;
+
+       return 0;
+
+error:
+       kfree(sum_mgr);
+       return err;
+}
+
+int sum_mgr_destroy(struct sum_mgr *sum_mgr)
+{
+       rsc_mgr_uninit(&sum_mgr->mgr);
+       kfree(sum_mgr);
+       return 0;
+}
+
diff --git a/sound/pci/ctxfi/ctamixer.h b/sound/pci/ctxfi/ctamixer.h
new file mode 100644 (file)
index 0000000..cc49e5a
--- /dev/null
@@ -0,0 +1,96 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File       ctamixer.h
+ *
+ * @Brief
+ * This file contains the definition of the Audio Mixer
+ * resource management object.
+ *
+ * @Author     Liu Chun
+ * @Date       May 21 2008
+ *
+ */
+
+#ifndef CTAMIXER_H
+#define CTAMIXER_H
+
+#include "ctresource.h"
+#include <linux/spinlock.h>
+
+/* Define the descriptor of a summation node resource */
+struct sum {
+       struct rsc rsc;         /* Basic resource info */
+       unsigned char idx[8];
+};
+
+/* Define sum resource request description info */
+struct sum_desc {
+       unsigned int msr;
+};
+
+struct sum_mgr {
+       struct rsc_mgr mgr;     /* Basic resource manager info */
+       spinlock_t mgr_lock;
+
+        /* request one sum resource */
+       int (*get_sum)(struct sum_mgr *mgr,
+                       const struct sum_desc *desc, struct sum **rsum);
+       /* return one sum resource */
+       int (*put_sum)(struct sum_mgr *mgr, struct sum *sum);
+};
+
+/* Constructor and destructor of daio resource manager */
+int sum_mgr_create(void *hw, struct sum_mgr **rsum_mgr);
+int sum_mgr_destroy(struct sum_mgr *sum_mgr);
+
+/* Define the descriptor of a amixer resource */
+struct amixer_rsc_ops;
+
+struct amixer {
+       struct rsc rsc;         /* Basic resource info */
+       unsigned char idx[8];
+       struct rsc *input;      /* pointer to a resource acting as source */
+       struct sum *sum;        /* Put amixer output to this summation node */
+       struct amixer_rsc_ops *ops;     /* AMixer specific operations */
+};
+
+struct amixer_rsc_ops {
+       int (*set_input)(struct amixer *amixer, struct rsc *rsc);
+       int (*set_scale)(struct amixer *amixer, unsigned int scale);
+       int (*set_invalid_squash)(struct amixer *amixer, unsigned int iv);
+       int (*set_sum)(struct amixer *amixer, struct sum *sum);
+       int (*commit_write)(struct amixer *amixer);
+       /* Only for interleaved recording */
+       int (*commit_raw_write)(struct amixer *amixer);
+       int (*setup)(struct amixer *amixer, struct rsc *input,
+                       unsigned int scale, struct sum *sum);
+       int (*get_scale)(struct amixer *amixer);
+};
+
+/* Define amixer resource request description info */
+struct amixer_desc {
+       unsigned int msr;
+};
+
+struct amixer_mgr {
+       struct rsc_mgr mgr;     /* Basic resource manager info */
+       spinlock_t mgr_lock;
+
+        /* request one amixer resource */
+       int (*get_amixer)(struct amixer_mgr *mgr,
+                         const struct amixer_desc *desc,
+                         struct amixer **ramixer);
+       /* return one amixer resource */
+       int (*put_amixer)(struct amixer_mgr *mgr, struct amixer *amixer);
+};
+
+/* Constructor and destructor of amixer resource manager */
+int amixer_mgr_create(void *hw, struct amixer_mgr **ramixer_mgr);
+int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr);
+
+#endif /* CTAMIXER_H */
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c
new file mode 100644 (file)
index 0000000..80fb2ba
--- /dev/null
@@ -0,0 +1,1619 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File    ctatc.c
+ *
+ * @Brief
+ * This file contains the implementation of the device resource management
+ * object.
+ *
+ * @Author Liu Chun
+ * @Date Mar 28 2008
+ */
+
+#include "ctatc.h"
+#include "ctpcm.h"
+#include "ctmixer.h"
+#include "cthardware.h"
+#include "ctsrc.h"
+#include "ctamixer.h"
+#include "ctdaio.h"
+#include "cttimer.h"
+#include <linux/delay.h>
+#include <sound/pcm.h>
+#include <sound/control.h>
+#include <sound/asoundef.h>
+
+#define MONO_SUM_SCALE 0x19a8  /* 2^(-0.5) in 14-bit floating format */
+#define DAIONUM                7
+#define MAX_MULTI_CHN  8
+
+#define IEC958_DEFAULT_CON ((IEC958_AES0_NONAUDIO \
+                           | IEC958_AES0_CON_NOT_COPYRIGHT) \
+                           | ((IEC958_AES1_CON_MIXER \
+                           | IEC958_AES1_CON_ORIGINAL) << 8) \
+                           | (0x10 << 16) \
+                           | ((IEC958_AES3_CON_FS_48000) << 24))
+
+static struct snd_pci_quirk __devinitdata subsys_20k1_list[] = {
+       SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0022, "SB055x", CTSB055X),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x002f, "SB055x", CTSB055X),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0029, "SB073x", CTSB073X),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0031, "SB073x", CTSB073X),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000, 0x6000,
+                          "UAA", CTUAA),
+       SND_PCI_QUIRK_VENDOR(PCI_VENDOR_ID_CREATIVE,
+                            "Unknown", CT20K1_UNKNOWN),
+       { } /* terminator */
+};
+
+static struct snd_pci_quirk __devinitdata subsys_20k2_list[] = {
+       SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB0760,
+                     "SB0760", CTSB0760),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08801,
+                     "SB0880", CTSB0880),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08802,
+                     "SB0880", CTSB0880),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08803,
+                     "SB0880", CTSB0880),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000,
+                          PCI_SUBDEVICE_ID_CREATIVE_HENDRIX, "HENDRIX",
+                          CTHENDRIX),
+       { } /* terminator */
+};
+
+static const char *ct_subsys_name[NUM_CTCARDS] = {
+       [CTSB055X]      = "SB055x",
+       [CTSB073X]      = "SB073x",
+       [CTSB0760]      = "SB076x",
+       [CTUAA]         = "UAA",
+       [CT20K1_UNKNOWN] = "Unknown",
+       [CTHENDRIX]     = "Hendrix",
+       [CTSB0880]      = "SB0880",
+};
+
+static struct {
+       int (*create)(struct ct_atc *atc,
+                       enum CTALSADEVS device, const char *device_name);
+       int (*destroy)(void *alsa_dev);
+       const char *public_name;
+} alsa_dev_funcs[NUM_CTALSADEVS] = {
+       [FRONT]         = { .create = ct_alsa_pcm_create,
+                           .destroy = NULL,
+                           .public_name = "Front/WaveIn"},
+       [SURROUND]      = { .create = ct_alsa_pcm_create,
+                           .destroy = NULL,
+                           .public_name = "Surround"},
+       [CLFE]          = { .create = ct_alsa_pcm_create,
+                           .destroy = NULL,
+                           .public_name = "Center/LFE"},
+       [SIDE]          = { .create = ct_alsa_pcm_create,
+                           .destroy = NULL,
+                           .public_name = "Side"},
+       [IEC958]        = { .create = ct_alsa_pcm_create,
+                           .destroy = NULL,
+                           .public_name = "IEC958 Non-audio"},
+
+       [MIXER]         = { .create = ct_alsa_mix_create,
+                           .destroy = NULL,
+                           .public_name = "Mixer"}
+};
+
+typedef int (*create_t)(void *, void **);
+typedef int (*destroy_t)(void *);
+
+static struct {
+       int (*create)(void *hw, void **rmgr);
+       int (*destroy)(void *mgr);
+} rsc_mgr_funcs[NUM_RSCTYP] = {
+       [SRC]           = { .create     = (create_t)src_mgr_create,
+                           .destroy    = (destroy_t)src_mgr_destroy    },
+       [SRCIMP]        = { .create     = (create_t)srcimp_mgr_create,
+                           .destroy    = (destroy_t)srcimp_mgr_destroy },
+       [AMIXER]        = { .create     = (create_t)amixer_mgr_create,
+                           .destroy    = (destroy_t)amixer_mgr_destroy },
+       [SUM]           = { .create     = (create_t)sum_mgr_create,
+                           .destroy    = (destroy_t)sum_mgr_destroy    },
+       [DAIO]          = { .create     = (create_t)daio_mgr_create,
+                           .destroy    = (destroy_t)daio_mgr_destroy   }
+};
+
+static int
+atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm);
+
+/* *
+ * Only mono and interleaved modes are supported now.
+ * Always allocates a contiguous channel block.
+ * */
+
+static int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm)
+{
+       struct snd_pcm_runtime *runtime;
+       struct ct_vm *vm;
+
+       if (NULL == apcm->substream)
+               return 0;
+
+       runtime = apcm->substream->runtime;
+       vm = atc->vm;
+
+       apcm->vm_block = vm->map(vm, apcm->substream, runtime->dma_bytes);
+
+       if (NULL == apcm->vm_block)
+               return -ENOENT;
+
+       return 0;
+}
+
+static void ct_unmap_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm)
+{
+       struct ct_vm *vm;
+
+       if (NULL == apcm->vm_block)
+               return;
+
+       vm = atc->vm;
+
+       vm->unmap(vm, apcm->vm_block);
+
+       apcm->vm_block = NULL;
+}
+
+static unsigned long atc_get_ptp_phys(struct ct_atc *atc, int index)
+{
+       struct ct_vm *vm;
+       void *kvirt_addr;
+       unsigned long phys_addr;
+
+       vm = atc->vm;
+       kvirt_addr = vm->get_ptp_virt(vm, index);
+       if (kvirt_addr == NULL)
+               phys_addr = (~0UL);
+       else
+               phys_addr = virt_to_phys(kvirt_addr);
+
+       return phys_addr;
+}
+
+static unsigned int convert_format(snd_pcm_format_t snd_format)
+{
+       switch (snd_format) {
+       case SNDRV_PCM_FORMAT_U8:
+               return SRC_SF_U8;
+       case SNDRV_PCM_FORMAT_S16_LE:
+               return SRC_SF_S16;
+       case SNDRV_PCM_FORMAT_S24_3LE:
+               return SRC_SF_S24;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               return SRC_SF_S32;
+       case SNDRV_PCM_FORMAT_FLOAT_LE:
+               return SRC_SF_F32;
+       default:
+               printk(KERN_ERR "ctxfi: not recognized snd format is %d \n",
+                       snd_format);
+               return SRC_SF_S16;
+       }
+}
+
+static unsigned int
+atc_get_pitch(unsigned int input_rate, unsigned int output_rate)
+{
+       unsigned int pitch;
+       int b;
+
+       /* get pitch and convert to fixed-point 8.24 format. */
+       pitch = (input_rate / output_rate) << 24;
+       input_rate %= output_rate;
+       input_rate /= 100;
+       output_rate /= 100;
+       for (b = 31; ((b >= 0) && !(input_rate >> b)); )
+               b--;
+
+       if (b >= 0) {
+               input_rate <<= (31 - b);
+               input_rate /= output_rate;
+               b = 24 - (31 - b);
+               if (b >= 0)
+                       input_rate <<= b;
+               else
+                       input_rate >>= -b;
+
+               pitch |= input_rate;
+       }
+
+       return pitch;
+}
+
+static int select_rom(unsigned int pitch)
+{
+       if ((pitch > 0x00428f5c) && (pitch < 0x01b851ec)) {
+               /* 0.26 <= pitch <= 1.72 */
+               return 1;
+       } else if ((0x01d66666 == pitch) || (0x01d66667 == pitch)) {
+               /* pitch == 1.8375 */
+               return 2;
+       } else if (0x02000000 == pitch) {
+               /* pitch == 2 */
+               return 3;
+       } else if ((pitch >= 0x0) && (pitch <= 0x08000000)) {
+               /* 0 <= pitch <= 8 */
+               return 0;
+       } else {
+               return -ENOENT;
+       }
+}
+
+static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
+{
+       struct src_mgr *src_mgr = atc->rsc_mgrs[SRC];
+       struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER];
+       struct src_desc desc = {0};
+       struct amixer_desc mix_dsc = {0};
+       struct src *src;
+       struct amixer *amixer;
+       int err;
+       int n_amixer = apcm->substream->runtime->channels, i = 0;
+       int device = apcm->substream->pcm->device;
+       unsigned int pitch;
+       unsigned long flags;
+
+       if (NULL != apcm->src) {
+               /* Prepared pcm playback */
+               return 0;
+       }
+
+       /* first release old resources */
+       atc->pcm_release_resources(atc, apcm);
+
+       /* Get SRC resource */
+       desc.multi = apcm->substream->runtime->channels;
+       desc.msr = atc->msr;
+       desc.mode = MEMRD;
+       err = src_mgr->get_src(src_mgr, &desc, (struct src **)&apcm->src);
+       if (err)
+               goto error1;
+
+       pitch = atc_get_pitch(apcm->substream->runtime->rate,
+                                               (atc->rsr * atc->msr));
+       src = apcm->src;
+       src->ops->set_pitch(src, pitch);
+       src->ops->set_rom(src, select_rom(pitch));
+       src->ops->set_sf(src, convert_format(apcm->substream->runtime->format));
+       src->ops->set_pm(src, (src->ops->next_interleave(src) != NULL));
+
+       /* Get AMIXER resource */
+       n_amixer = (n_amixer < 2) ? 2 : n_amixer;
+       apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL);
+       if (NULL == apcm->amixers) {
+               err = -ENOMEM;
+               goto error1;
+       }
+       mix_dsc.msr = atc->msr;
+       for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) {
+               err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc,
+                                       (struct amixer **)&apcm->amixers[i]);
+               if (err)
+                       goto error1;
+
+               apcm->n_amixer++;
+       }
+
+       /* Set up device virtual mem map */
+       err = ct_map_audio_buffer(atc, apcm);
+       if (err < 0)
+               goto error1;
+
+       /* Connect resources */
+       src = apcm->src;
+       for (i = 0; i < n_amixer; i++) {
+               amixer = apcm->amixers[i];
+               spin_lock_irqsave(&atc->atc_lock, flags);
+               amixer->ops->setup(amixer, &src->rsc,
+                                       INIT_VOL, atc->pcm[i+device*2]);
+               spin_unlock_irqrestore(&atc->atc_lock, flags);
+               src = src->ops->next_interleave(src);
+               if (NULL == src)
+                       src = apcm->src;
+       }
+
+       ct_timer_prepare(apcm->timer);
+
+       return 0;
+
+error1:
+       atc_pcm_release_resources(atc, apcm);
+       return err;
+}
+
+static int
+atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm)
+{
+       struct src_mgr *src_mgr = atc->rsc_mgrs[SRC];
+       struct srcimp_mgr *srcimp_mgr = atc->rsc_mgrs[SRCIMP];
+       struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER];
+       struct sum_mgr *sum_mgr = atc->rsc_mgrs[SUM];
+       struct srcimp *srcimp;
+       int i;
+
+       if (NULL != apcm->srcimps) {
+               for (i = 0; i < apcm->n_srcimp; i++) {
+                       srcimp = apcm->srcimps[i];
+                       srcimp->ops->unmap(srcimp);
+                       srcimp_mgr->put_srcimp(srcimp_mgr, srcimp);
+                       apcm->srcimps[i] = NULL;
+               }
+               kfree(apcm->srcimps);
+               apcm->srcimps = NULL;
+       }
+
+       if (NULL != apcm->srccs) {
+               for (i = 0; i < apcm->n_srcc; i++) {
+                       src_mgr->put_src(src_mgr, apcm->srccs[i]);
+                       apcm->srccs[i] = NULL;
+               }
+               kfree(apcm->srccs);
+               apcm->srccs = NULL;
+       }
+
+       if (NULL != apcm->amixers) {
+               for (i = 0; i < apcm->n_amixer; i++) {
+                       amixer_mgr->put_amixer(amixer_mgr, apcm->amixers[i]);
+                       apcm->amixers[i] = NULL;
+               }
+               kfree(apcm->amixers);
+               apcm->amixers = NULL;
+       }
+
+       if (NULL != apcm->mono) {
+               sum_mgr->put_sum(sum_mgr, apcm->mono);
+               apcm->mono = NULL;
+       }
+
+       if (NULL != apcm->src) {
+               src_mgr->put_src(src_mgr, apcm->src);
+               apcm->src = NULL;
+       }
+
+       if (NULL != apcm->vm_block) {
+               /* Undo device virtual mem map */
+               ct_unmap_audio_buffer(atc, apcm);
+               apcm->vm_block = NULL;
+       }
+
+       return 0;
+}
+
+static int atc_pcm_playback_start(struct ct_atc *atc, struct ct_atc_pcm *apcm)
+{
+       unsigned int max_cisz;
+       struct src *src = apcm->src;
+
+       if (apcm->started)
+               return 0;
+       apcm->started = 1;
+
+       max_cisz = src->multi * src->rsc.msr;
+       max_cisz = 0x80 * (max_cisz < 8 ? max_cisz : 8);
+
+       src->ops->set_sa(src, apcm->vm_block->addr);
+       src->ops->set_la(src, apcm->vm_block->addr + apcm->vm_block->size);
+       src->ops->set_ca(src, apcm->vm_block->addr + max_cisz);
+       src->ops->set_cisz(src, max_cisz);
+
+       src->ops->set_bm(src, 1);
+       src->ops->set_state(src, SRC_STATE_INIT);
+       src->ops->commit_write(src);
+
+       ct_timer_start(apcm->timer);
+       return 0;
+}
+
+static int atc_pcm_stop(struct ct_atc *atc, struct ct_atc_pcm *apcm)
+{
+       struct src *src;
+       int i;
+
+       ct_timer_stop(apcm->timer);
+
+       src = apcm->src;
+       src->ops->set_bm(src, 0);
+       src->ops->set_state(src, SRC_STATE_OFF);
+       src->ops->commit_write(src);
+
+       if (NULL != apcm->srccs) {
+               for (i = 0; i < apcm->n_srcc; i++) {
+                       src = apcm->srccs[i];
+                       src->ops->set_bm(src, 0);
+                       src->ops->set_state(src, SRC_STATE_OFF);
+                       src->ops->commit_write(src);
+               }
+       }
+
+       apcm->started = 0;
+
+       return 0;
+}
+
+static int
+atc_pcm_playback_position(struct ct_atc *atc, struct ct_atc_pcm *apcm)
+{
+       struct src *src = apcm->src;
+       u32 size, max_cisz;
+       int position;
+
+       if (!src)
+               return 0;
+       position = src->ops->get_ca(src);
+
+       size = apcm->vm_block->size;
+       max_cisz = src->multi * src->rsc.msr;
+       max_cisz = 128 * (max_cisz < 8 ? max_cisz : 8);
+
+       return (position + size - max_cisz - apcm->vm_block->addr) % size;
+}
+
+struct src_node_conf_t {
+       unsigned int pitch;
+       unsigned int msr:8;
+       unsigned int mix_msr:8;
+       unsigned int imp_msr:8;
+       unsigned int vo:1;
+};
+
+static void setup_src_node_conf(struct ct_atc *atc, struct ct_atc_pcm *apcm,
+                               struct src_node_conf_t *conf, int *n_srcc)
+{
+       unsigned int pitch;
+
+       /* get pitch and convert to fixed-point 8.24 format. */
+       pitch = atc_get_pitch((atc->rsr * atc->msr),
+                               apcm->substream->runtime->rate);
+       *n_srcc = 0;
+
+       if (1 == atc->msr) {
+               *n_srcc = apcm->substream->runtime->channels;
+               conf[0].pitch = pitch;
+               conf[0].mix_msr = conf[0].imp_msr = conf[0].msr = 1;
+               conf[0].vo = 1;
+       } else if (2 == atc->msr) {
+               if (0x8000000 < pitch) {
+                       /* Need two-stage SRCs, SRCIMPs and
+                        * AMIXERs for converting format */
+                       conf[0].pitch = (atc->msr << 24);
+                       conf[0].msr = conf[0].mix_msr = 1;
+                       conf[0].imp_msr = atc->msr;
+                       conf[0].vo = 0;
+                       conf[1].pitch = atc_get_pitch(atc->rsr,
+                                       apcm->substream->runtime->rate);
+                       conf[1].msr = conf[1].mix_msr = conf[1].imp_msr = 1;
+                       conf[1].vo = 1;
+                       *n_srcc = apcm->substream->runtime->channels * 2;
+               } else if (0x1000000 < pitch) {
+                       /* Need one-stage SRCs, SRCIMPs and
+                        * AMIXERs for converting format */
+                       conf[0].pitch = pitch;
+                       conf[0].msr = conf[0].mix_msr
+                                   = conf[0].imp_msr = atc->msr;
+                       conf[0].vo = 1;
+                       *n_srcc = apcm->substream->runtime->channels;
+               }
+       }
+}
+
+static int
+atc_pcm_capture_get_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm)
+{
+       struct src_mgr *src_mgr = atc->rsc_mgrs[SRC];
+       struct srcimp_mgr *srcimp_mgr = atc->rsc_mgrs[SRCIMP];
+       struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER];
+       struct sum_mgr *sum_mgr = atc->rsc_mgrs[SUM];
+       struct src_desc src_dsc = {0};
+       struct src *src;
+       struct srcimp_desc srcimp_dsc = {0};
+       struct srcimp *srcimp;
+       struct amixer_desc mix_dsc = {0};
+       struct sum_desc sum_dsc = {0};
+       unsigned int pitch;
+       int multi, err, i;
+       int n_srcimp, n_amixer, n_srcc, n_sum;
+       struct src_node_conf_t src_node_conf[2] = {{0} };
+
+       /* first release old resources */
+       atc_pcm_release_resources(atc, apcm);
+
+       /* The numbers of converting SRCs and SRCIMPs should be determined
+        * by pitch value. */
+
+       multi = apcm->substream->runtime->channels;
+
+       /* get pitch and convert to fixed-point 8.24 format. */
+       pitch = atc_get_pitch((atc->rsr * atc->msr),
+                               apcm->substream->runtime->rate);
+
+       setup_src_node_conf(atc, apcm, src_node_conf, &n_srcc);
+       n_sum = (1 == multi) ? 1 : 0;
+       n_amixer = n_sum * 2 + n_srcc;
+       n_srcimp = n_srcc;
+       if ((multi > 1) && (0x8000000 >= pitch)) {
+               /* Need extra AMIXERs and SRCIMPs for special treatment
+                * of interleaved recording of conjugate channels */
+               n_amixer += multi * atc->msr;
+               n_srcimp += multi * atc->msr;
+       } else {
+               n_srcimp += multi;
+       }
+
+       if (n_srcc) {
+               apcm->srccs = kzalloc(sizeof(void *)*n_srcc, GFP_KERNEL);
+               if (NULL == apcm->srccs)
+                       return -ENOMEM;
+       }
+       if (n_amixer) {
+               apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL);
+               if (NULL == apcm->amixers) {
+                       err = -ENOMEM;
+                       goto error1;
+               }
+       }
+       apcm->srcimps = kzalloc(sizeof(void *)*n_srcimp, GFP_KERNEL);
+       if (NULL == apcm->srcimps) {
+               err = -ENOMEM;
+               goto error1;
+       }
+
+       /* Allocate SRCs for sample rate conversion if needed */
+       src_dsc.multi = 1;
+       src_dsc.mode = ARCRW;
+       for (i = 0, apcm->n_srcc = 0; i < n_srcc; i++) {
+               src_dsc.msr = src_node_conf[i/multi].msr;
+               err = src_mgr->get_src(src_mgr, &src_dsc,
+                                       (struct src **)&apcm->srccs[i]);
+               if (err)
+                       goto error1;
+
+               src = apcm->srccs[i];
+               pitch = src_node_conf[i/multi].pitch;
+               src->ops->set_pitch(src, pitch);
+               src->ops->set_rom(src, select_rom(pitch));
+               src->ops->set_vo(src, src_node_conf[i/multi].vo);
+
+               apcm->n_srcc++;
+       }
+
+       /* Allocate AMIXERs for routing SRCs of conversion if needed */
+       for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) {
+               if (i < (n_sum*2))
+                       mix_dsc.msr = atc->msr;
+               else if (i < (n_sum*2+n_srcc))
+                       mix_dsc.msr = src_node_conf[(i-n_sum*2)/multi].mix_msr;
+               else
+                       mix_dsc.msr = 1;
+
+               err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc,
+                                       (struct amixer **)&apcm->amixers[i]);
+               if (err)
+                       goto error1;
+
+               apcm->n_amixer++;
+       }
+
+       /* Allocate a SUM resource to mix all input channels together */
+       sum_dsc.msr = atc->msr;
+       err = sum_mgr->get_sum(sum_mgr, &sum_dsc, (struct sum **)&apcm->mono);
+       if (err)
+               goto error1;
+
+       pitch = atc_get_pitch((atc->rsr * atc->msr),
+                               apcm->substream->runtime->rate);
+       /* Allocate SRCIMP resources */
+       for (i = 0, apcm->n_srcimp = 0; i < n_srcimp; i++) {
+               if (i < (n_srcc))
+                       srcimp_dsc.msr = src_node_conf[i/multi].imp_msr;
+               else if (1 == multi)
+                       srcimp_dsc.msr = (pitch <= 0x8000000) ? atc->msr : 1;
+               else
+                       srcimp_dsc.msr = 1;
+
+               err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, &srcimp);
+               if (err)
+                       goto error1;
+
+               apcm->srcimps[i] = srcimp;
+               apcm->n_srcimp++;
+       }
+
+       /* Allocate a SRC for writing data to host memory */
+       src_dsc.multi = apcm->substream->runtime->channels;
+       src_dsc.msr = 1;
+       src_dsc.mode = MEMWR;
+       err = src_mgr->get_src(src_mgr, &src_dsc, (struct src **)&apcm->src);
+       if (err)
+               goto error1;
+
+       src = apcm->src;
+       src->ops->set_pitch(src, pitch);
+
+       /* Set up device virtual mem map */
+       err = ct_map_audio_buffer(atc, apcm);
+       if (err < 0)
+               goto error1;
+
+       return 0;
+
+error1:
+       atc_pcm_release_resources(atc, apcm);
+       return err;
+}
+
+static int atc_pcm_capture_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
+{
+       struct src *src;
+       struct amixer *amixer;
+       struct srcimp *srcimp;
+       struct ct_mixer *mixer = atc->mixer;
+       struct sum *mono;
+       struct rsc *out_ports[8] = {NULL};
+       int err, i, j, n_sum, multi;
+       unsigned int pitch;
+       int mix_base = 0, imp_base = 0;
+
+       if (NULL != apcm->src) {
+               /* Prepared pcm capture */
+               return 0;
+       }
+
+       /* Get needed resources. */
+       err = atc_pcm_capture_get_resources(atc, apcm);
+       if (err)
+               return err;
+
+       /* Connect resources */
+       mixer->get_output_ports(mixer, MIX_PCMO_FRONT,
+                               &out_ports[0], &out_ports[1]);
+
+       multi = apcm->substream->runtime->channels;
+       if (1 == multi) {
+               mono = apcm->mono;
+               for (i = 0; i < 2; i++) {
+                       amixer = apcm->amixers[i];
+                       amixer->ops->setup(amixer, out_ports[i],
+                                               MONO_SUM_SCALE, mono);
+               }
+               out_ports[0] = &mono->rsc;
+               n_sum = 1;
+               mix_base = n_sum * 2;
+       }
+
+       for (i = 0; i < apcm->n_srcc; i++) {
+               src = apcm->srccs[i];
+               srcimp = apcm->srcimps[imp_base+i];
+               amixer = apcm->amixers[mix_base+i];
+               srcimp->ops->map(srcimp, src, out_ports[i%multi]);
+               amixer->ops->setup(amixer, &src->rsc, INIT_VOL, NULL);
+               out_ports[i%multi] = &amixer->rsc;
+       }
+
+       pitch = atc_get_pitch((atc->rsr * atc->msr),
+                               apcm->substream->runtime->rate);
+
+       if ((multi > 1) && (pitch <= 0x8000000)) {
+               /* Special connection for interleaved
+                * recording with conjugate channels */
+               for (i = 0; i < multi; i++) {
+                       out_ports[i]->ops->master(out_ports[i]);
+                       for (j = 0; j < atc->msr; j++) {
+                               amixer = apcm->amixers[apcm->n_srcc+j*multi+i];
+                               amixer->ops->set_input(amixer, out_ports[i]);
+                               amixer->ops->set_scale(amixer, INIT_VOL);
+                               amixer->ops->set_sum(amixer, NULL);
+                               amixer->ops->commit_raw_write(amixer);
+                               out_ports[i]->ops->next_conj(out_ports[i]);
+
+                               srcimp = apcm->srcimps[apcm->n_srcc+j*multi+i];
+                               srcimp->ops->map(srcimp, apcm->src,
+                                                       &amixer->rsc);
+                       }
+               }
+       } else {
+               for (i = 0; i < multi; i++) {
+                       srcimp = apcm->srcimps[apcm->n_srcc+i];
+                       srcimp->ops->map(srcimp, apcm->src, out_ports[i]);
+               }
+       }
+
+       ct_timer_prepare(apcm->timer);
+
+       return 0;
+}
+
+static int atc_pcm_capture_start(struct ct_atc *atc, struct ct_atc_pcm *apcm)
+{
+       struct src *src;
+       struct src_mgr *src_mgr = atc->rsc_mgrs[SRC];
+       int i, multi;
+
+       if (apcm->started)
+               return 0;
+
+       apcm->started = 1;
+       multi = apcm->substream->runtime->channels;
+       /* Set up converting SRCs */
+       for (i = 0; i < apcm->n_srcc; i++) {
+               src = apcm->srccs[i];
+               src->ops->set_pm(src, ((i%multi) != (multi-1)));
+               src_mgr->src_disable(src_mgr, src);
+       }
+
+       /*  Set up recording SRC */
+       src = apcm->src;
+       src->ops->set_sf(src, convert_format(apcm->substream->runtime->format));
+       src->ops->set_sa(src, apcm->vm_block->addr);
+       src->ops->set_la(src, apcm->vm_block->addr + apcm->vm_block->size);
+       src->ops->set_ca(src, apcm->vm_block->addr);
+       src_mgr->src_disable(src_mgr, src);
+
+       /* Disable relevant SRCs firstly */
+       src_mgr->commit_write(src_mgr);
+
+       /* Enable SRCs respectively */
+       for (i = 0; i < apcm->n_srcc; i++) {
+               src = apcm->srccs[i];
+               src->ops->set_state(src, SRC_STATE_RUN);
+               src->ops->commit_write(src);
+               src_mgr->src_enable_s(src_mgr, src);
+       }
+       src = apcm->src;
+       src->ops->set_bm(src, 1);
+       src->ops->set_state(src, SRC_STATE_RUN);
+       src->ops->commit_write(src);
+       src_mgr->src_enable_s(src_mgr, src);
+
+       /* Enable relevant SRCs synchronously */
+       src_mgr->commit_write(src_mgr);
+
+       ct_timer_start(apcm->timer);
+       return 0;
+}
+
+static int
+atc_pcm_capture_position(struct ct_atc *atc, struct ct_atc_pcm *apcm)
+{
+       struct src *src = apcm->src;
+
+       if (!src)
+               return 0;
+       return src->ops->get_ca(src) - apcm->vm_block->addr;
+}
+
+static int spdif_passthru_playback_get_resources(struct ct_atc *atc,
+                                                struct ct_atc_pcm *apcm)
+{
+       struct src_mgr *src_mgr = atc->rsc_mgrs[SRC];
+       struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER];
+       struct src_desc desc = {0};
+       struct amixer_desc mix_dsc = {0};
+       struct src *src;
+       int err;
+       int n_amixer = apcm->substream->runtime->channels, i;
+       unsigned int pitch, rsr = atc->pll_rate;
+
+       /* first release old resources */
+       atc_pcm_release_resources(atc, apcm);
+
+       /* Get SRC resource */
+       desc.multi = apcm->substream->runtime->channels;
+       desc.msr = 1;
+       while (apcm->substream->runtime->rate > (rsr * desc.msr))
+               desc.msr <<= 1;
+
+       desc.mode = MEMRD;
+       err = src_mgr->get_src(src_mgr, &desc, (struct src **)&apcm->src);
+       if (err)
+               goto error1;
+
+       pitch = atc_get_pitch(apcm->substream->runtime->rate, (rsr * desc.msr));
+       src = apcm->src;
+       src->ops->set_pitch(src, pitch);
+       src->ops->set_rom(src, select_rom(pitch));
+       src->ops->set_sf(src, convert_format(apcm->substream->runtime->format));
+       src->ops->set_pm(src, (src->ops->next_interleave(src) != NULL));
+       src->ops->set_bp(src, 1);
+
+       /* Get AMIXER resource */
+       n_amixer = (n_amixer < 2) ? 2 : n_amixer;
+       apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL);
+       if (NULL == apcm->amixers) {
+               err = -ENOMEM;
+               goto error1;
+       }
+       mix_dsc.msr = desc.msr;
+       for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) {
+               err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc,
+                                       (struct amixer **)&apcm->amixers[i]);
+               if (err)
+                       goto error1;
+
+               apcm->n_amixer++;
+       }
+
+       /* Set up device virtual mem map */
+       err = ct_map_audio_buffer(atc, apcm);
+       if (err < 0)
+               goto error1;
+
+       return 0;
+
+error1:
+       atc_pcm_release_resources(atc, apcm);
+       return err;
+}
+
+static int atc_pll_init(struct ct_atc *atc, int rate)
+{
+       struct hw *hw = atc->hw;
+       int err;
+       err = hw->pll_init(hw, rate);
+       atc->pll_rate = err ? 0 : rate;
+       return err;
+}
+
+static int
+spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm)
+{
+       struct dao *dao = container_of(atc->daios[SPDIFOO], struct dao, daio);
+       unsigned long flags;
+       unsigned int rate = apcm->substream->runtime->rate;
+       unsigned int status;
+       int err;
+       unsigned char iec958_con_fs;
+
+       switch (rate) {
+       case 48000:
+               iec958_con_fs = IEC958_AES3_CON_FS_48000;
+               break;
+       case 44100:
+               iec958_con_fs = IEC958_AES3_CON_FS_44100;
+               break;
+       case 32000:
+               iec958_con_fs = IEC958_AES3_CON_FS_32000;
+               break;
+       default:
+               return -ENOENT;
+       }
+
+       spin_lock_irqsave(&atc->atc_lock, flags);
+       dao->ops->get_spos(dao, &status);
+       if (((status >> 24) & IEC958_AES3_CON_FS) != iec958_con_fs) {
+               status &= ((~IEC958_AES3_CON_FS) << 24);
+               status |= (iec958_con_fs << 24);
+               dao->ops->set_spos(dao, status);
+               dao->ops->commit_write(dao);
+       }
+       if ((rate != atc->pll_rate) && (32000 != rate))
+               err = atc_pll_init(atc, rate);
+       spin_unlock_irqrestore(&atc->atc_lock, flags);
+
+       return err;
+}
+
+static int
+spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
+{
+       struct src *src;
+       struct amixer *amixer;
+       struct dao *dao;
+       int err;
+       int i;
+       unsigned long flags;
+
+       if (NULL != apcm->src)
+               return 0;
+
+       /* Configure SPDIFOO and PLL to passthrough mode;
+        * determine pll_rate. */
+       err = spdif_passthru_playback_setup(atc, apcm);
+       if (err)
+               return err;
+
+       /* Get needed resources. */
+       err = spdif_passthru_playback_get_resources(atc, apcm);
+       if (err)
+               return err;
+
+       /* Connect resources */
+       src = apcm->src;
+       for (i = 0; i < apcm->n_amixer; i++) {
+               amixer = apcm->amixers[i];
+               amixer->ops->setup(amixer, &src->rsc, INIT_VOL, NULL);
+               src = src->ops->next_interleave(src);
+               if (NULL == src)
+                       src = apcm->src;
+       }
+       /* Connect to SPDIFOO */
+       spin_lock_irqsave(&atc->atc_lock, flags);
+       dao = container_of(atc->daios[SPDIFOO], struct dao, daio);
+       amixer = apcm->amixers[0];
+       dao->ops->set_left_input(dao, &amixer->rsc);
+       amixer = apcm->amixers[1];
+       dao->ops->set_right_input(dao, &amixer->rsc);
+       spin_unlock_irqrestore(&atc->atc_lock, flags);
+
+       ct_timer_prepare(apcm->timer);
+
+       return 0;
+}
+
+static int atc_select_line_in(struct ct_atc *atc)
+{
+       struct hw *hw = atc->hw;
+       struct ct_mixer *mixer = atc->mixer;
+       struct src *src;
+
+       if (hw->is_adc_source_selected(hw, ADC_LINEIN))
+               return 0;
+
+       mixer->set_input_left(mixer, MIX_MIC_IN, NULL);
+       mixer->set_input_right(mixer, MIX_MIC_IN, NULL);
+
+       hw->select_adc_source(hw, ADC_LINEIN);
+
+       src = atc->srcs[2];
+       mixer->set_input_left(mixer, MIX_LINE_IN, &src->rsc);
+       src = atc->srcs[3];
+       mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc);
+
+       return 0;
+}
+
+static int atc_select_mic_in(struct ct_atc *atc)
+{
+       struct hw *hw = atc->hw;
+       struct ct_mixer *mixer = atc->mixer;
+       struct src *src;
+
+       if (hw->is_adc_source_selected(hw, ADC_MICIN))
+               return 0;
+
+       mixer->set_input_left(mixer, MIX_LINE_IN, NULL);
+       mixer->set_input_right(mixer, MIX_LINE_IN, NULL);
+
+       hw->select_adc_source(hw, ADC_MICIN);
+
+       src = atc->srcs[2];
+       mixer->set_input_left(mixer, MIX_MIC_IN, &src->rsc);
+       src = atc->srcs[3];
+       mixer->set_input_right(mixer, MIX_MIC_IN, &src->rsc);
+
+       return 0;
+}
+
+static int atc_have_digit_io_switch(struct ct_atc *atc)
+{
+       struct hw *hw = atc->hw;
+
+       return hw->have_digit_io_switch(hw);
+}
+
+static int atc_select_digit_io(struct ct_atc *atc)
+{
+       struct hw *hw = atc->hw;
+
+       if (hw->is_adc_source_selected(hw, ADC_NONE))
+               return 0;
+
+       hw->select_adc_source(hw, ADC_NONE);
+
+       return 0;
+}
+
+static int atc_daio_unmute(struct ct_atc *atc, unsigned char state, int type)
+{
+       struct daio_mgr *daio_mgr = atc->rsc_mgrs[DAIO];
+
+       if (state)
+               daio_mgr->daio_enable(daio_mgr, atc->daios[type]);
+       else
+               daio_mgr->daio_disable(daio_mgr, atc->daios[type]);
+
+       daio_mgr->commit_write(daio_mgr);
+
+       return 0;
+}
+
+static int
+atc_dao_get_status(struct ct_atc *atc, unsigned int *status, int type)
+{
+       struct dao *dao = container_of(atc->daios[type], struct dao, daio);
+       return dao->ops->get_spos(dao, status);
+}
+
+static int
+atc_dao_set_status(struct ct_atc *atc, unsigned int status, int type)
+{
+       struct dao *dao = container_of(atc->daios[type], struct dao, daio);
+
+       dao->ops->set_spos(dao, status);
+       dao->ops->commit_write(dao);
+       return 0;
+}
+
+static int atc_line_front_unmute(struct ct_atc *atc, unsigned char state)
+{
+       return atc_daio_unmute(atc, state, LINEO1);
+}
+
+static int atc_line_surround_unmute(struct ct_atc *atc, unsigned char state)
+{
+       return atc_daio_unmute(atc, state, LINEO4);
+}
+
+static int atc_line_clfe_unmute(struct ct_atc *atc, unsigned char state)
+{
+       return atc_daio_unmute(atc, state, LINEO3);
+}
+
+static int atc_line_rear_unmute(struct ct_atc *atc, unsigned char state)
+{
+       return atc_daio_unmute(atc, state, LINEO2);
+}
+
+static int atc_line_in_unmute(struct ct_atc *atc, unsigned char state)
+{
+       return atc_daio_unmute(atc, state, LINEIM);
+}
+
+static int atc_spdif_out_unmute(struct ct_atc *atc, unsigned char state)
+{
+       return atc_daio_unmute(atc, state, SPDIFOO);
+}
+
+static int atc_spdif_in_unmute(struct ct_atc *atc, unsigned char state)
+{
+       return atc_daio_unmute(atc, state, SPDIFIO);
+}
+
+static int atc_spdif_out_get_status(struct ct_atc *atc, unsigned int *status)
+{
+       return atc_dao_get_status(atc, status, SPDIFOO);
+}
+
+static int atc_spdif_out_set_status(struct ct_atc *atc, unsigned int status)
+{
+       return atc_dao_set_status(atc, status, SPDIFOO);
+}
+
+static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state)
+{
+       unsigned long flags;
+       struct dao_desc da_dsc = {0};
+       struct dao *dao;
+       int err;
+       struct ct_mixer *mixer = atc->mixer;
+       struct rsc *rscs[2] = {NULL};
+       unsigned int spos = 0;
+
+       spin_lock_irqsave(&atc->atc_lock, flags);
+       dao = container_of(atc->daios[SPDIFOO], struct dao, daio);
+       da_dsc.msr = state ? 1 : atc->msr;
+       da_dsc.passthru = state ? 1 : 0;
+       err = dao->ops->reinit(dao, &da_dsc);
+       if (state) {
+               spos = IEC958_DEFAULT_CON;
+       } else {
+               mixer->get_output_ports(mixer, MIX_SPDIF_OUT,
+                                       &rscs[0], &rscs[1]);
+               dao->ops->set_left_input(dao, rscs[0]);
+               dao->ops->set_right_input(dao, rscs[1]);
+               /* Restore PLL to atc->rsr if needed. */
+               if (atc->pll_rate != atc->rsr)
+                       err = atc_pll_init(atc, atc->rsr);
+       }
+       dao->ops->set_spos(dao, spos);
+       dao->ops->commit_write(dao);
+       spin_unlock_irqrestore(&atc->atc_lock, flags);
+
+       return err;
+}
+
+static int ct_atc_destroy(struct ct_atc *atc)
+{
+       struct daio_mgr *daio_mgr;
+       struct dao *dao;
+       struct dai *dai;
+       struct daio *daio;
+       struct sum_mgr *sum_mgr;
+       struct src_mgr *src_mgr;
+       struct srcimp_mgr *srcimp_mgr;
+       struct srcimp *srcimp;
+       struct ct_mixer *mixer;
+       int i = 0;
+
+       if (NULL == atc)
+               return 0;
+
+       if (atc->timer) {
+               ct_timer_free(atc->timer);
+               atc->timer = NULL;
+       }
+
+       /* Stop hardware and disable all interrupts */
+       if (NULL != atc->hw)
+               ((struct hw *)atc->hw)->card_stop(atc->hw);
+
+       /* Destroy internal mixer objects */
+       if (NULL != atc->mixer) {
+               mixer = atc->mixer;
+               mixer->set_input_left(mixer, MIX_LINE_IN, NULL);
+               mixer->set_input_right(mixer, MIX_LINE_IN, NULL);
+               mixer->set_input_left(mixer, MIX_MIC_IN, NULL);
+               mixer->set_input_right(mixer, MIX_MIC_IN, NULL);
+               mixer->set_input_left(mixer, MIX_SPDIF_IN, NULL);
+               mixer->set_input_right(mixer, MIX_SPDIF_IN, NULL);
+               ct_mixer_destroy(atc->mixer);
+       }
+
+       if (NULL != atc->daios) {
+               daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
+               for (i = 0; i < atc->n_daio; i++) {
+                       daio = atc->daios[i];
+                       if (daio->type < LINEIM) {
+                               dao = container_of(daio, struct dao, daio);
+                               dao->ops->clear_left_input(dao);
+                               dao->ops->clear_right_input(dao);
+                       } else {
+                               dai = container_of(daio, struct dai, daio);
+                               /* some thing to do for dai ... */
+                       }
+                       daio_mgr->put_daio(daio_mgr, daio);
+               }
+               kfree(atc->daios);
+       }
+
+       if (NULL != atc->pcm) {
+               sum_mgr = atc->rsc_mgrs[SUM];
+               for (i = 0; i < atc->n_pcm; i++)
+                       sum_mgr->put_sum(sum_mgr, atc->pcm[i]);
+
+               kfree(atc->pcm);
+       }
+
+       if (NULL != atc->srcs) {
+               src_mgr = atc->rsc_mgrs[SRC];
+               for (i = 0; i < atc->n_src; i++)
+                       src_mgr->put_src(src_mgr, atc->srcs[i]);
+
+               kfree(atc->srcs);
+       }
+
+       if (NULL != atc->srcimps) {
+               srcimp_mgr = atc->rsc_mgrs[SRCIMP];
+               for (i = 0; i < atc->n_srcimp; i++) {
+                       srcimp = atc->srcimps[i];
+                       srcimp->ops->unmap(srcimp);
+                       srcimp_mgr->put_srcimp(srcimp_mgr, atc->srcimps[i]);
+               }
+               kfree(atc->srcimps);
+       }
+
+       for (i = 0; i < NUM_RSCTYP; i++) {
+               if ((NULL != rsc_mgr_funcs[i].destroy) &&
+                   (NULL != atc->rsc_mgrs[i]))
+                       rsc_mgr_funcs[i].destroy(atc->rsc_mgrs[i]);
+
+       }
+
+       if (NULL != atc->hw)
+               destroy_hw_obj((struct hw *)atc->hw);
+
+       /* Destroy device virtual memory manager object */
+       if (NULL != atc->vm) {
+               ct_vm_destroy(atc->vm);
+               atc->vm = NULL;
+       }
+
+       kfree(atc);
+
+       return 0;
+}
+
+static int atc_dev_free(struct snd_device *dev)
+{
+       struct ct_atc *atc = dev->device_data;
+       return ct_atc_destroy(atc);
+}
+
+static int __devinit atc_identify_card(struct ct_atc *atc)
+{
+       const struct snd_pci_quirk *p;
+       const struct snd_pci_quirk *list;
+
+       switch (atc->chip_type) {
+       case ATC20K1:
+               atc->chip_name = "20K1";
+               list = subsys_20k1_list;
+               break;
+       case ATC20K2:
+               atc->chip_name = "20K2";
+               list = subsys_20k2_list;
+               break;
+       default:
+               return -ENOENT;
+       }
+       p = snd_pci_quirk_lookup(atc->pci, list);
+       if (!p)
+               return -ENOENT;
+       atc->model = p->value;
+       atc->model_name = ct_subsys_name[atc->model];
+       snd_printd("ctxfi: chip %s model %s (%04x:%04x) is found\n",
+                  atc->chip_name, atc->model_name,
+                  atc->pci->subsystem_vendor,
+                  atc->pci->subsystem_device);
+       return 0;
+}
+
+int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc)
+{
+       enum CTALSADEVS i;
+       int err;
+
+       alsa_dev_funcs[MIXER].public_name = atc->chip_name;
+
+       for (i = 0; i < NUM_CTALSADEVS; i++) {
+               if (NULL == alsa_dev_funcs[i].create)
+                       continue;
+
+               err = alsa_dev_funcs[i].create(atc, i,
+                               alsa_dev_funcs[i].public_name);
+               if (err) {
+                       printk(KERN_ERR "ctxfi: "
+                              "Creating alsa device %d failed!\n", i);
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+static int __devinit atc_create_hw_devs(struct ct_atc *atc)
+{
+       struct hw *hw;
+       struct card_conf info = {0};
+       int i, err;
+
+       err = create_hw_obj(atc->pci, atc->chip_type, atc->model, &hw);
+       if (err) {
+               printk(KERN_ERR "Failed to create hw obj!!!\n");
+               return err;
+       }
+       atc->hw = hw;
+
+       /* Initialize card hardware. */
+       info.rsr = atc->rsr;
+       info.msr = atc->msr;
+       info.vm_pgt_phys = atc_get_ptp_phys(atc, 0);
+       err = hw->card_init(hw, &info);
+       if (err < 0)
+               return err;
+
+       for (i = 0; i < NUM_RSCTYP; i++) {
+               if (NULL == rsc_mgr_funcs[i].create)
+                       continue;
+
+               err = rsc_mgr_funcs[i].create(atc->hw, &atc->rsc_mgrs[i]);
+               if (err) {
+                       printk(KERN_ERR "ctxfi: "
+                              "Failed to create rsc_mgr %d!!!\n", i);
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+static int __devinit atc_get_resources(struct ct_atc *atc)
+{
+       struct daio_desc da_desc = {0};
+       struct daio_mgr *daio_mgr;
+       struct src_desc src_dsc = {0};
+       struct src_mgr *src_mgr;
+       struct srcimp_desc srcimp_dsc = {0};
+       struct srcimp_mgr *srcimp_mgr;
+       struct sum_desc sum_dsc = {0};
+       struct sum_mgr *sum_mgr;
+       int err, i;
+
+       atc->daios = kzalloc(sizeof(void *)*(DAIONUM), GFP_KERNEL);
+       if (NULL == atc->daios)
+               return -ENOMEM;
+
+       atc->srcs = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL);
+       if (NULL == atc->srcs)
+               return -ENOMEM;
+
+       atc->srcimps = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL);
+       if (NULL == atc->srcimps)
+               return -ENOMEM;
+
+       atc->pcm = kzalloc(sizeof(void *)*(2*4), GFP_KERNEL);
+       if (NULL == atc->pcm)
+               return -ENOMEM;
+
+       daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
+       da_desc.msr = atc->msr;
+       for (i = 0, atc->n_daio = 0; i < DAIONUM-1; i++) {
+               da_desc.type = i;
+               err = daio_mgr->get_daio(daio_mgr, &da_desc,
+                                       (struct daio **)&atc->daios[i]);
+               if (err) {
+                       printk(KERN_ERR "ctxfi: Failed to get DAIO "
+                                       "resource %d!!!\n", i);
+                       return err;
+               }
+               atc->n_daio++;
+       }
+       if (atc->model == CTSB073X)
+               da_desc.type = SPDIFI1;
+       else
+               da_desc.type = SPDIFIO;
+       err = daio_mgr->get_daio(daio_mgr, &da_desc,
+                               (struct daio **)&atc->daios[i]);
+       if (err) {
+               printk(KERN_ERR "ctxfi: Failed to get S/PDIF-in resource!!!\n");
+               return err;
+       }
+       atc->n_daio++;
+
+       src_mgr = atc->rsc_mgrs[SRC];
+       src_dsc.multi = 1;
+       src_dsc.msr = atc->msr;
+       src_dsc.mode = ARCRW;
+       for (i = 0, atc->n_src = 0; i < (2*2); i++) {
+               err = src_mgr->get_src(src_mgr, &src_dsc,
+                                       (struct src **)&atc->srcs[i]);
+               if (err)
+                       return err;
+
+               atc->n_src++;
+       }
+
+       srcimp_mgr = atc->rsc_mgrs[SRCIMP];
+       srcimp_dsc.msr = 8; /* SRCIMPs for S/PDIFIn SRT */
+       for (i = 0, atc->n_srcimp = 0; i < (2*1); i++) {
+               err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc,
+                                       (struct srcimp **)&atc->srcimps[i]);
+               if (err)
+                       return err;
+
+               atc->n_srcimp++;
+       }
+       srcimp_dsc.msr = 8; /* SRCIMPs for LINE/MICIn SRT */
+       for (i = 0; i < (2*1); i++) {
+               err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc,
+                               (struct srcimp **)&atc->srcimps[2*1+i]);
+               if (err)
+                       return err;
+
+               atc->n_srcimp++;
+       }
+
+       sum_mgr = atc->rsc_mgrs[SUM];
+       sum_dsc.msr = atc->msr;
+       for (i = 0, atc->n_pcm = 0; i < (2*4); i++) {
+               err = sum_mgr->get_sum(sum_mgr, &sum_dsc,
+                                       (struct sum **)&atc->pcm[i]);
+               if (err)
+                       return err;
+
+               atc->n_pcm++;
+       }
+
+       err = ct_mixer_create(atc, (struct ct_mixer **)&atc->mixer);
+       if (err) {
+               printk(KERN_ERR "ctxfi: Failed to create mixer obj!!!\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static void __devinit
+atc_connect_dai(struct src_mgr *src_mgr, struct dai *dai,
+               struct src **srcs, struct srcimp **srcimps)
+{
+       struct rsc *rscs[2] = {NULL};
+       struct src *src;
+       struct srcimp *srcimp;
+       int i = 0;
+
+       rscs[0] = &dai->daio.rscl;
+       rscs[1] = &dai->daio.rscr;
+       for (i = 0; i < 2; i++) {
+               src = srcs[i];
+               srcimp = srcimps[i];
+               srcimp->ops->map(srcimp, src, rscs[i]);
+               src_mgr->src_disable(src_mgr, src);
+       }
+
+       src_mgr->commit_write(src_mgr); /* Actually disable SRCs */
+
+       src = srcs[0];
+       src->ops->set_pm(src, 1);
+       for (i = 0; i < 2; i++) {
+               src = srcs[i];
+               src->ops->set_state(src, SRC_STATE_RUN);
+               src->ops->commit_write(src);
+               src_mgr->src_enable_s(src_mgr, src);
+       }
+
+       dai->ops->set_srt_srcl(dai, &(srcs[0]->rsc));
+       dai->ops->set_srt_srcr(dai, &(srcs[1]->rsc));
+
+       dai->ops->set_enb_src(dai, 1);
+       dai->ops->set_enb_srt(dai, 1);
+       dai->ops->commit_write(dai);
+
+       src_mgr->commit_write(src_mgr); /* Synchronously enable SRCs */
+}
+
+static void __devinit atc_connect_resources(struct ct_atc *atc)
+{
+       struct dai *dai;
+       struct dao *dao;
+       struct src *src;
+       struct sum *sum;
+       struct ct_mixer *mixer;
+       struct rsc *rscs[2] = {NULL};
+       int i, j;
+
+       mixer = atc->mixer;
+
+       for (i = MIX_WAVE_FRONT, j = LINEO1; i <= MIX_SPDIF_OUT; i++, j++) {
+               mixer->get_output_ports(mixer, i, &rscs[0], &rscs[1]);
+               dao = container_of(atc->daios[j], struct dao, daio);
+               dao->ops->set_left_input(dao, rscs[0]);
+               dao->ops->set_right_input(dao, rscs[1]);
+       }
+
+       dai = container_of(atc->daios[LINEIM], struct dai, daio);
+       atc_connect_dai(atc->rsc_mgrs[SRC], dai,
+                       (struct src **)&atc->srcs[2],
+                       (struct srcimp **)&atc->srcimps[2]);
+       src = atc->srcs[2];
+       mixer->set_input_left(mixer, MIX_LINE_IN, &src->rsc);
+       src = atc->srcs[3];
+       mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc);
+
+       dai = container_of(atc->daios[SPDIFIO], struct dai, daio);
+       atc_connect_dai(atc->rsc_mgrs[SRC], dai,
+                       (struct src **)&atc->srcs[0],
+                       (struct srcimp **)&atc->srcimps[0]);
+
+       src = atc->srcs[0];
+       mixer->set_input_left(mixer, MIX_SPDIF_IN, &src->rsc);
+       src = atc->srcs[1];
+       mixer->set_input_right(mixer, MIX_SPDIF_IN, &src->rsc);
+
+       for (i = MIX_PCMI_FRONT, j = 0; i <= MIX_PCMI_SURROUND; i++, j += 2) {
+               sum = atc->pcm[j];
+               mixer->set_input_left(mixer, i, &sum->rsc);
+               sum = atc->pcm[j+1];
+               mixer->set_input_right(mixer, i, &sum->rsc);
+       }
+}
+
+static struct ct_atc atc_preset __devinitdata = {
+       .map_audio_buffer = ct_map_audio_buffer,
+       .unmap_audio_buffer = ct_unmap_audio_buffer,
+       .pcm_playback_prepare = atc_pcm_playback_prepare,
+       .pcm_release_resources = atc_pcm_release_resources,
+       .pcm_playback_start = atc_pcm_playback_start,
+       .pcm_playback_stop = atc_pcm_stop,
+       .pcm_playback_position = atc_pcm_playback_position,
+       .pcm_capture_prepare = atc_pcm_capture_prepare,
+       .pcm_capture_start = atc_pcm_capture_start,
+       .pcm_capture_stop = atc_pcm_stop,
+       .pcm_capture_position = atc_pcm_capture_position,
+       .spdif_passthru_playback_prepare = spdif_passthru_playback_prepare,
+       .get_ptp_phys = atc_get_ptp_phys,
+       .select_line_in = atc_select_line_in,
+       .select_mic_in = atc_select_mic_in,
+       .select_digit_io = atc_select_digit_io,
+       .line_front_unmute = atc_line_front_unmute,
+       .line_surround_unmute = atc_line_surround_unmute,
+       .line_clfe_unmute = atc_line_clfe_unmute,
+       .line_rear_unmute = atc_line_rear_unmute,
+       .line_in_unmute = atc_line_in_unmute,
+       .spdif_out_unmute = atc_spdif_out_unmute,
+       .spdif_in_unmute = atc_spdif_in_unmute,
+       .spdif_out_get_status = atc_spdif_out_get_status,
+       .spdif_out_set_status = atc_spdif_out_set_status,
+       .spdif_out_passthru = atc_spdif_out_passthru,
+       .have_digit_io_switch = atc_have_digit_io_switch,
+};
+
+/**
+ *  ct_atc_create - create and initialize a hardware manager
+ *  @card: corresponding alsa card object
+ *  @pci: corresponding kernel pci device object
+ *  @ratc: return created object address in it
+ *
+ *  Creates and initializes a hardware manager.
+ *
+ *  Creates kmallocated ct_atc structure. Initializes hardware.
+ *  Returns 0 if suceeds, or negative error code if fails.
+ */
+
+int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci,
+                           unsigned int rsr, unsigned int msr,
+                           int chip_type, struct ct_atc **ratc)
+{
+       struct ct_atc *atc;
+       static struct snd_device_ops ops = {
+               .dev_free = atc_dev_free,
+       };
+       int err;
+
+       *ratc = NULL;
+
+       atc = kzalloc(sizeof(*atc), GFP_KERNEL);
+       if (NULL == atc)
+               return -ENOMEM;
+
+       /* Set operations */
+       *atc = atc_preset;
+
+       atc->card = card;
+       atc->pci = pci;
+       atc->rsr = rsr;
+       atc->msr = msr;
+       atc->chip_type = chip_type;
+
+       spin_lock_init(&atc->atc_lock);
+
+       /* Find card model */
+       err = atc_identify_card(atc);
+       if (err < 0) {
+               printk(KERN_ERR "ctatc: Card not recognised\n");
+               goto error1;
+       }
+
+       /* Set up device virtual memory management object */
+       err = ct_vm_create(&atc->vm);
+       if (err < 0)
+               goto error1;
+
+       /* Create all atc hw devices */
+       err = atc_create_hw_devs(atc);
+       if (err < 0)
+               goto error1;
+
+       /* Get resources */
+       err = atc_get_resources(atc);
+       if (err < 0)
+               goto error1;
+
+       /* Build topology */
+       atc_connect_resources(atc);
+
+       atc->timer = ct_timer_new(atc);
+       if (!atc->timer)
+               goto error1;
+
+       err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, atc, &ops);
+       if (err < 0)
+               goto error1;
+
+       snd_card_set_dev(card, &pci->dev);
+
+       *ratc = atc;
+       return 0;
+
+error1:
+       ct_atc_destroy(atc);
+       printk(KERN_ERR "ctxfi: Something wrong!!!\n");
+       return err;
+}
diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h
new file mode 100644 (file)
index 0000000..a033472
--- /dev/null
@@ -0,0 +1,147 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File       ctatc.h
+ *
+ * @Brief
+ * This file contains the definition of the device resource management object.
+ *
+ * @Author     Liu Chun
+ * @Date       Mar 28 2008
+ *
+ */
+
+#ifndef CTATC_H
+#define CTATC_H
+
+#include <linux/types.h>
+#include <linux/spinlock_types.h>
+#include <linux/pci.h>
+#include <linux/timer.h>
+#include <sound/core.h>
+
+#include "ctvmem.h"
+#include "ctresource.h"
+
+enum CTALSADEVS {              /* Types of alsa devices */
+       FRONT,
+       SURROUND,
+       CLFE,
+       SIDE,
+       IEC958,
+       MIXER,
+       NUM_CTALSADEVS          /* This should always be the last */
+};
+
+struct ct_atc_chip_sub_details {
+       u16 subsys;
+       const char *nm_model;
+};
+
+struct ct_atc_chip_details {
+       u16 vendor;
+       u16 device;
+       const struct ct_atc_chip_sub_details *sub_details;
+       const char *nm_card;
+};
+
+struct ct_atc;
+struct ct_timer;
+struct ct_timer_instance;
+
+/* alsa pcm stream descriptor */
+struct ct_atc_pcm {
+       struct snd_pcm_substream *substream;
+       void (*interrupt)(struct ct_atc_pcm *apcm);
+       struct ct_timer_instance *timer;
+       unsigned int started:1;
+
+       /* Only mono and interleaved modes are supported now. */
+       struct ct_vm_block *vm_block;
+       void *src;              /* SRC for interacting with host memory */
+       void **srccs;           /* SRCs for sample rate conversion */
+       void **srcimps;         /* SRC Input Mappers */
+       void **amixers;         /* AMIXERs for routing converted data */
+       void *mono;             /* A SUM resource for mixing chs to one */
+       unsigned char n_srcc;   /* Number of converting SRCs */
+       unsigned char n_srcimp; /* Number of SRC Input Mappers */
+       unsigned char n_amixer; /* Number of AMIXERs */
+};
+
+/* Chip resource management object */
+struct ct_atc {
+       struct pci_dev *pci;
+       struct snd_card *card;
+       unsigned int rsr; /* reference sample rate in Hz */
+       unsigned int msr; /* master sample rate in rsr */
+       unsigned int pll_rate; /* current rate of Phase Lock Loop */
+
+       int chip_type;
+       int model;
+       const char *chip_name;
+       const char *model_name;
+
+       struct ct_vm *vm; /* device virtual memory manager for this card */
+       int (*map_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
+       void (*unmap_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
+       unsigned long (*get_ptp_phys)(struct ct_atc *atc, int index);
+
+       spinlock_t atc_lock;
+
+       int (*pcm_playback_prepare)(struct ct_atc *atc,
+                                   struct ct_atc_pcm *apcm);
+       int (*pcm_playback_start)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
+       int (*pcm_playback_stop)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
+       int (*pcm_playback_position)(struct ct_atc *atc,
+                                    struct ct_atc_pcm *apcm);
+       int (*spdif_passthru_playback_prepare)(struct ct_atc *atc,
+                                              struct ct_atc_pcm *apcm);
+       int (*pcm_capture_prepare)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
+       int (*pcm_capture_start)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
+       int (*pcm_capture_stop)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
+       int (*pcm_capture_position)(struct ct_atc *atc,
+                                   struct ct_atc_pcm *apcm);
+       int (*pcm_release_resources)(struct ct_atc *atc,
+                                    struct ct_atc_pcm *apcm);
+       int (*select_line_in)(struct ct_atc *atc);
+       int (*select_mic_in)(struct ct_atc *atc);
+       int (*select_digit_io)(struct ct_atc *atc);
+       int (*line_front_unmute)(struct ct_atc *atc, unsigned char state);
+       int (*line_surround_unmute)(struct ct_atc *atc, unsigned char state);
+       int (*line_clfe_unmute)(struct ct_atc *atc, unsigned char state);
+       int (*line_rear_unmute)(struct ct_atc *atc, unsigned char state);
+       int (*line_in_unmute)(struct ct_atc *atc, unsigned char state);
+       int (*spdif_out_unmute)(struct ct_atc *atc, unsigned char state);
+       int (*spdif_in_unmute)(struct ct_atc *atc, unsigned char state);
+       int (*spdif_out_get_status)(struct ct_atc *atc, unsigned int *status);
+       int (*spdif_out_set_status)(struct ct_atc *atc, unsigned int status);
+       int (*spdif_out_passthru)(struct ct_atc *atc, unsigned char state);
+       int (*have_digit_io_switch)(struct ct_atc *atc);
+
+       /* Don't touch! Used for internal object. */
+       void *rsc_mgrs[NUM_RSCTYP]; /* chip resource managers */
+       void *mixer;            /* internal mixer object */
+       void *hw;               /* chip specific hardware access object */
+       void **daios;           /* digital audio io resources */
+       void **pcm;             /* SUMs for collecting all pcm stream */
+       void **srcs;            /* Sample Rate Converters for input signal */
+       void **srcimps;         /* input mappers for SRCs */
+       unsigned char n_daio;
+       unsigned char n_src;
+       unsigned char n_srcimp;
+       unsigned char n_pcm;
+
+       struct ct_timer *timer;
+};
+
+
+int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci,
+                           unsigned int rsr, unsigned int msr, int chip_type,
+                           struct ct_atc **ratc);
+int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc);
+
+#endif /* CTATC_H */
diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c
new file mode 100644 (file)
index 0000000..082e35c
--- /dev/null
@@ -0,0 +1,769 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File       ctdaio.c
+ *
+ * @Brief
+ * This file contains the implementation of Digital Audio Input Output
+ * resource management object.
+ *
+ * @Author     Liu Chun
+ * @Date       May 23 2008
+ *
+ */
+
+#include "ctdaio.h"
+#include "cthardware.h"
+#include "ctimap.h"
+#include <linux/slab.h>
+#include <linux/kernel.h>
+
+#define DAIO_RESOURCE_NUM      NUM_DAIOTYP
+#define DAIO_OUT_MAX           SPDIFOO
+
+union daio_usage {
+       struct {
+               unsigned short lineo1:1;
+               unsigned short lineo2:1;
+               unsigned short lineo3:1;
+               unsigned short lineo4:1;
+               unsigned short spdifoo:1;
+               unsigned short lineim:1;
+               unsigned short spdifio:1;
+               unsigned short spdifi1:1;
+       } bf;
+       unsigned short data;
+};
+
+struct daio_rsc_idx {
+       unsigned short left;
+       unsigned short right;
+};
+
+struct daio_rsc_idx idx_20k1[NUM_DAIOTYP] = {
+       [LINEO1] = {.left = 0x00, .right = 0x01},
+       [LINEO2] = {.left = 0x18, .right = 0x19},
+       [LINEO3] = {.left = 0x08, .right = 0x09},
+       [LINEO4] = {.left = 0x10, .right = 0x11},
+       [LINEIM] = {.left = 0x1b5, .right = 0x1bd},
+       [SPDIFOO] = {.left = 0x20, .right = 0x21},
+       [SPDIFIO] = {.left = 0x15, .right = 0x1d},
+       [SPDIFI1] = {.left = 0x95, .right = 0x9d},
+};
+
+struct daio_rsc_idx idx_20k2[NUM_DAIOTYP] = {
+       [LINEO1] = {.left = 0x40, .right = 0x41},
+       [LINEO2] = {.left = 0x70, .right = 0x71},
+       [LINEO3] = {.left = 0x50, .right = 0x51},
+       [LINEO4] = {.left = 0x60, .right = 0x61},
+       [LINEIM] = {.left = 0x45, .right = 0xc5},
+       [SPDIFOO] = {.left = 0x00, .right = 0x01},
+       [SPDIFIO] = {.left = 0x05, .right = 0x85},
+};
+
+static int daio_master(struct rsc *rsc)
+{
+       /* Actually, this is not the resource index of DAIO.
+        * For DAO, it is the input mapper index. And, for DAI,
+        * it is the output time-slot index. */
+       return rsc->conj = rsc->idx;
+}
+
+static int daio_index(const struct rsc *rsc)
+{
+       return rsc->conj;
+}
+
+static int daio_out_next_conj(struct rsc *rsc)
+{
+       return rsc->conj += 2;
+}
+
+static int daio_in_next_conj_20k1(struct rsc *rsc)
+{
+       return rsc->conj += 0x200;
+}
+
+static int daio_in_next_conj_20k2(struct rsc *rsc)
+{
+       return rsc->conj += 0x100;
+}
+
+static struct rsc_ops daio_out_rsc_ops = {
+       .master         = daio_master,
+       .next_conj      = daio_out_next_conj,
+       .index          = daio_index,
+       .output_slot    = NULL,
+};
+
+static struct rsc_ops daio_in_rsc_ops_20k1 = {
+       .master         = daio_master,
+       .next_conj      = daio_in_next_conj_20k1,
+       .index          = NULL,
+       .output_slot    = daio_index,
+};
+
+static struct rsc_ops daio_in_rsc_ops_20k2 = {
+       .master         = daio_master,
+       .next_conj      = daio_in_next_conj_20k2,
+       .index          = NULL,
+       .output_slot    = daio_index,
+};
+
+static unsigned int daio_device_index(enum DAIOTYP type, struct hw *hw)
+{
+       switch (hw->chip_type) {
+       case ATC20K1:
+               switch (type) {
+               case SPDIFOO:   return 0;
+               case SPDIFIO:   return 0;
+               case SPDIFI1:   return 1;
+               case LINEO1:    return 4;
+               case LINEO2:    return 7;
+               case LINEO3:    return 5;
+               case LINEO4:    return 6;
+               case LINEIM:    return 7;
+               default:        return -EINVAL;
+               }
+       case ATC20K2:
+               switch (type) {
+               case SPDIFOO:   return 0;
+               case SPDIFIO:   return 0;
+               case LINEO1:    return 4;
+               case LINEO2:    return 7;
+               case LINEO3:    return 5;
+               case LINEO4:    return 6;
+               case LINEIM:    return 4;
+               default:        return -EINVAL;
+               }
+       default:
+               return -EINVAL;
+       }
+}
+
+static int dao_rsc_reinit(struct dao *dao, const struct dao_desc *desc);
+
+static int dao_spdif_get_spos(struct dao *dao, unsigned int *spos)
+{
+       ((struct hw *)dao->hw)->dao_get_spos(dao->ctrl_blk, spos);
+       return 0;
+}
+
+static int dao_spdif_set_spos(struct dao *dao, unsigned int spos)
+{
+       ((struct hw *)dao->hw)->dao_set_spos(dao->ctrl_blk, spos);
+       return 0;
+}
+
+static int dao_commit_write(struct dao *dao)
+{
+       ((struct hw *)dao->hw)->dao_commit_write(dao->hw,
+               daio_device_index(dao->daio.type, dao->hw), dao->ctrl_blk);
+       return 0;
+}
+
+static int dao_set_left_input(struct dao *dao, struct rsc *input)
+{
+       struct imapper *entry;
+       struct daio *daio = &dao->daio;
+       int i;
+
+       entry = kzalloc((sizeof(*entry) * daio->rscl.msr), GFP_KERNEL);
+       if (NULL == entry)
+               return -ENOMEM;
+
+       /* Program master and conjugate resources */
+       input->ops->master(input);
+       daio->rscl.ops->master(&daio->rscl);
+       for (i = 0; i < daio->rscl.msr; i++, entry++) {
+               entry->slot = input->ops->output_slot(input);
+               entry->user = entry->addr = daio->rscl.ops->index(&daio->rscl);
+               dao->mgr->imap_add(dao->mgr, entry);
+               dao->imappers[i] = entry;
+
+               input->ops->next_conj(input);
+               daio->rscl.ops->next_conj(&daio->rscl);
+       }
+       input->ops->master(input);
+       daio->rscl.ops->master(&daio->rscl);
+
+       return 0;
+}
+
+static int dao_set_right_input(struct dao *dao, struct rsc *input)
+{
+       struct imapper *entry;
+       struct daio *daio = &dao->daio;
+       int i;
+
+       entry = kzalloc((sizeof(*entry) * daio->rscr.msr), GFP_KERNEL);
+       if (NULL == entry)
+               return -ENOMEM;
+
+       /* Program master and conjugate resources */
+       input->ops->master(input);
+       daio->rscr.ops->master(&daio->rscr);
+       for (i = 0; i < daio->rscr.msr; i++, entry++) {
+               entry->slot = input->ops->output_slot(input);
+               entry->user = entry->addr = daio->rscr.ops->index(&daio->rscr);
+               dao->mgr->imap_add(dao->mgr, entry);
+               dao->imappers[daio->rscl.msr + i] = entry;
+
+               input->ops->next_conj(input);
+               daio->rscr.ops->next_conj(&daio->rscr);
+       }
+       input->ops->master(input);
+       daio->rscr.ops->master(&daio->rscr);
+
+       return 0;
+}
+
+static int dao_clear_left_input(struct dao *dao)
+{
+       struct imapper *entry;
+       struct daio *daio = &dao->daio;
+       int i;
+
+       if (NULL == dao->imappers[0])
+               return 0;
+
+       entry = dao->imappers[0];
+       dao->mgr->imap_delete(dao->mgr, entry);
+       /* Program conjugate resources */
+       for (i = 1; i < daio->rscl.msr; i++) {
+               entry = dao->imappers[i];
+               dao->mgr->imap_delete(dao->mgr, entry);
+               dao->imappers[i] = NULL;
+       }
+
+       kfree(dao->imappers[0]);
+       dao->imappers[0] = NULL;
+
+       return 0;
+}
+
+static int dao_clear_right_input(struct dao *dao)
+{
+       struct imapper *entry;
+       struct daio *daio = &dao->daio;
+       int i;
+
+       if (NULL == dao->imappers[daio->rscl.msr])
+               return 0;
+
+       entry = dao->imappers[daio->rscl.msr];
+       dao->mgr->imap_delete(dao->mgr, entry);
+       /* Program conjugate resources */
+       for (i = 1; i < daio->rscr.msr; i++) {
+               entry = dao->imappers[daio->rscl.msr + i];
+               dao->mgr->imap_delete(dao->mgr, entry);
+               dao->imappers[daio->rscl.msr + i] = NULL;
+       }
+
+       kfree(dao->imappers[daio->rscl.msr]);
+       dao->imappers[daio->rscl.msr] = NULL;
+
+       return 0;
+}
+
+static struct dao_rsc_ops dao_ops = {
+       .set_spos               = dao_spdif_set_spos,
+       .commit_write           = dao_commit_write,
+       .get_spos               = dao_spdif_get_spos,
+       .reinit                 = dao_rsc_reinit,
+       .set_left_input         = dao_set_left_input,
+       .set_right_input        = dao_set_right_input,
+       .clear_left_input       = dao_clear_left_input,
+       .clear_right_input      = dao_clear_right_input,
+};
+
+static int dai_set_srt_srcl(struct dai *dai, struct rsc *src)
+{
+       src->ops->master(src);
+       ((struct hw *)dai->hw)->dai_srt_set_srcm(dai->ctrl_blk,
+                                               src->ops->index(src));
+       return 0;
+}
+
+static int dai_set_srt_srcr(struct dai *dai, struct rsc *src)
+{
+       src->ops->master(src);
+       ((struct hw *)dai->hw)->dai_srt_set_srco(dai->ctrl_blk,
+                                               src->ops->index(src));
+       return 0;
+}
+
+static int dai_set_srt_msr(struct dai *dai, unsigned int msr)
+{
+       unsigned int rsr;
+
+       for (rsr = 0; msr > 1; msr >>= 1)
+               rsr++;
+
+       ((struct hw *)dai->hw)->dai_srt_set_rsr(dai->ctrl_blk, rsr);
+       return 0;
+}
+
+static int dai_set_enb_src(struct dai *dai, unsigned int enb)
+{
+       ((struct hw *)dai->hw)->dai_srt_set_ec(dai->ctrl_blk, enb);
+       return 0;
+}
+
+static int dai_set_enb_srt(struct dai *dai, unsigned int enb)
+{
+       ((struct hw *)dai->hw)->dai_srt_set_et(dai->ctrl_blk, enb);
+       return 0;
+}
+
+static int dai_commit_write(struct dai *dai)
+{
+       ((struct hw *)dai->hw)->dai_commit_write(dai->hw,
+               daio_device_index(dai->daio.type, dai->hw), dai->ctrl_blk);
+       return 0;
+}
+
+static struct dai_rsc_ops dai_ops = {
+       .set_srt_srcl           = dai_set_srt_srcl,
+       .set_srt_srcr           = dai_set_srt_srcr,
+       .set_srt_msr            = dai_set_srt_msr,
+       .set_enb_src            = dai_set_enb_src,
+       .set_enb_srt            = dai_set_enb_srt,
+       .commit_write           = dai_commit_write,
+};
+
+static int daio_rsc_init(struct daio *daio,
+                        const struct daio_desc *desc,
+                        void *hw)
+{
+       int err;
+       unsigned int idx_l, idx_r;
+
+       switch (((struct hw *)hw)->chip_type) {
+       case ATC20K1:
+               idx_l = idx_20k1[desc->type].left;
+               idx_r = idx_20k1[desc->type].right;
+               break;
+       case ATC20K2:
+               idx_l = idx_20k2[desc->type].left;
+               idx_r = idx_20k2[desc->type].right;
+               break;
+       default:
+               return -EINVAL;
+       }
+       err = rsc_init(&daio->rscl, idx_l, DAIO, desc->msr, hw);
+       if (err)
+               return err;
+
+       err = rsc_init(&daio->rscr, idx_r, DAIO, desc->msr, hw);
+       if (err)
+               goto error1;
+
+       /* Set daio->rscl/r->ops to daio specific ones */
+       if (desc->type <= DAIO_OUT_MAX) {
+               daio->rscl.ops = daio->rscr.ops = &daio_out_rsc_ops;
+       } else {
+               switch (((struct hw *)hw)->chip_type) {
+               case ATC20K1:
+                       daio->rscl.ops = daio->rscr.ops = &daio_in_rsc_ops_20k1;
+                       break;
+               case ATC20K2:
+                       daio->rscl.ops = daio->rscr.ops = &daio_in_rsc_ops_20k2;
+                       break;
+               default:
+                       break;
+               }
+       }
+       daio->type = desc->type;
+
+       return 0;
+
+error1:
+       rsc_uninit(&daio->rscl);
+       return err;
+}
+
+static int daio_rsc_uninit(struct daio *daio)
+{
+       rsc_uninit(&daio->rscl);
+       rsc_uninit(&daio->rscr);
+
+       return 0;
+}
+
+static int dao_rsc_init(struct dao *dao,
+                       const struct daio_desc *desc,
+                       struct daio_mgr *mgr)
+{
+       struct hw *hw = mgr->mgr.hw;
+       unsigned int conf;
+       int err;
+
+       err = daio_rsc_init(&dao->daio, desc, mgr->mgr.hw);
+       if (err)
+               return err;
+
+       dao->imappers = kzalloc(sizeof(void *)*desc->msr*2, GFP_KERNEL);
+       if (NULL == dao->imappers) {
+               err = -ENOMEM;
+               goto error1;
+       }
+       dao->ops = &dao_ops;
+       dao->mgr = mgr;
+       dao->hw = hw;
+       err = hw->dao_get_ctrl_blk(&dao->ctrl_blk);
+       if (err)
+               goto error2;
+
+       hw->daio_mgr_dsb_dao(mgr->mgr.ctrl_blk,
+                       daio_device_index(dao->daio.type, hw));
+       hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk);
+
+       conf = (desc->msr & 0x7) | (desc->passthru << 3);
+       hw->daio_mgr_dao_init(mgr->mgr.ctrl_blk,
+                       daio_device_index(dao->daio.type, hw), conf);
+       hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk,
+                       daio_device_index(dao->daio.type, hw));
+       hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk);
+
+       return 0;
+
+error2:
+       kfree(dao->imappers);
+       dao->imappers = NULL;
+error1:
+       daio_rsc_uninit(&dao->daio);
+       return err;
+}
+
+static int dao_rsc_uninit(struct dao *dao)
+{
+       if (NULL != dao->imappers) {
+               if (NULL != dao->imappers[0])
+                       dao_clear_left_input(dao);
+
+               if (NULL != dao->imappers[dao->daio.rscl.msr])
+                       dao_clear_right_input(dao);
+
+               kfree(dao->imappers);
+               dao->imappers = NULL;
+       }
+       ((struct hw *)dao->hw)->dao_put_ctrl_blk(dao->ctrl_blk);
+       dao->hw = dao->ctrl_blk = NULL;
+       daio_rsc_uninit(&dao->daio);
+
+       return 0;
+}
+
+static int dao_rsc_reinit(struct dao *dao, const struct dao_desc *desc)
+{
+       struct daio_mgr *mgr = dao->mgr;
+       struct daio_desc dsc = {0};
+
+       dsc.type = dao->daio.type;
+       dsc.msr = desc->msr;
+       dsc.passthru = desc->passthru;
+       dao_rsc_uninit(dao);
+       return dao_rsc_init(dao, &dsc, mgr);
+}
+
+static int dai_rsc_init(struct dai *dai,
+                       const struct daio_desc *desc,
+                       struct daio_mgr *mgr)
+{
+       int err;
+       struct hw *hw = mgr->mgr.hw;
+       unsigned int rsr, msr;
+
+       err = daio_rsc_init(&dai->daio, desc, mgr->mgr.hw);
+       if (err)
+               return err;
+
+       dai->ops = &dai_ops;
+       dai->hw = mgr->mgr.hw;
+       err = hw->dai_get_ctrl_blk(&dai->ctrl_blk);
+       if (err)
+               goto error1;
+
+       for (rsr = 0, msr = desc->msr; msr > 1; msr >>= 1)
+               rsr++;
+
+       hw->dai_srt_set_rsr(dai->ctrl_blk, rsr);
+       hw->dai_srt_set_drat(dai->ctrl_blk, 0);
+       /* default to disabling control of a SRC */
+       hw->dai_srt_set_ec(dai->ctrl_blk, 0);
+       hw->dai_srt_set_et(dai->ctrl_blk, 0); /* default to disabling SRT */
+       hw->dai_commit_write(hw,
+               daio_device_index(dai->daio.type, dai->hw), dai->ctrl_blk);
+
+       return 0;
+
+error1:
+       daio_rsc_uninit(&dai->daio);
+       return err;
+}
+
+static int dai_rsc_uninit(struct dai *dai)
+{
+       ((struct hw *)dai->hw)->dai_put_ctrl_blk(dai->ctrl_blk);
+       dai->hw = dai->ctrl_blk = NULL;
+       daio_rsc_uninit(&dai->daio);
+       return 0;
+}
+
+static int daio_mgr_get_rsc(struct rsc_mgr *mgr, enum DAIOTYP type)
+{
+       if (((union daio_usage *)mgr->rscs)->data & (0x1 << type))
+               return -ENOENT;
+
+       ((union daio_usage *)mgr->rscs)->data |= (0x1 << type);
+
+       return 0;
+}
+
+static int daio_mgr_put_rsc(struct rsc_mgr *mgr, enum DAIOTYP type)
+{
+       ((union daio_usage *)mgr->rscs)->data &= ~(0x1 << type);
+
+       return 0;
+}
+
+static int get_daio_rsc(struct daio_mgr *mgr,
+                       const struct daio_desc *desc,
+                       struct daio **rdaio)
+{
+       int err;
+       struct dai *dai = NULL;
+       struct dao *dao = NULL;
+       unsigned long flags;
+
+       *rdaio = NULL;
+
+       /* Check whether there are sufficient daio resources to meet request. */
+       spin_lock_irqsave(&mgr->mgr_lock, flags);
+       err = daio_mgr_get_rsc(&mgr->mgr, desc->type);
+       spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+       if (err) {
+               printk(KERN_ERR "Can't meet DAIO resource request!\n");
+               return err;
+       }
+
+       /* Allocate mem for daio resource */
+       if (desc->type <= DAIO_OUT_MAX) {
+               dao = kzalloc(sizeof(*dao), GFP_KERNEL);
+               if (NULL == dao) {
+                       err = -ENOMEM;
+                       goto error;
+               }
+               err = dao_rsc_init(dao, desc, mgr);
+               if (err)
+                       goto error;
+
+               *rdaio = &dao->daio;
+       } else {
+               dai = kzalloc(sizeof(*dai), GFP_KERNEL);
+               if (NULL == dai) {
+                       err = -ENOMEM;
+                       goto error;
+               }
+               err = dai_rsc_init(dai, desc, mgr);
+               if (err)
+                       goto error;
+
+               *rdaio = &dai->daio;
+       }
+
+       mgr->daio_enable(mgr, *rdaio);
+       mgr->commit_write(mgr);
+
+       return 0;
+
+error:
+       if (NULL != dao)
+               kfree(dao);
+       else if (NULL != dai)
+               kfree(dai);
+
+       spin_lock_irqsave(&mgr->mgr_lock, flags);
+       daio_mgr_put_rsc(&mgr->mgr, desc->type);
+       spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+       return err;
+}
+
+static int put_daio_rsc(struct daio_mgr *mgr, struct daio *daio)
+{
+       unsigned long flags;
+
+       mgr->daio_disable(mgr, daio);
+       mgr->commit_write(mgr);
+
+       spin_lock_irqsave(&mgr->mgr_lock, flags);
+       daio_mgr_put_rsc(&mgr->mgr, daio->type);
+       spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+
+       if (daio->type <= DAIO_OUT_MAX) {
+               dao_rsc_uninit(container_of(daio, struct dao, daio));
+               kfree(container_of(daio, struct dao, daio));
+       } else {
+               dai_rsc_uninit(container_of(daio, struct dai, daio));
+               kfree(container_of(daio, struct dai, daio));
+       }
+
+       return 0;
+}
+
+static int daio_mgr_enb_daio(struct daio_mgr *mgr, struct daio *daio)
+{
+       struct hw *hw = mgr->mgr.hw;
+
+       if (DAIO_OUT_MAX >= daio->type) {
+               hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk,
+                               daio_device_index(daio->type, hw));
+       } else {
+               hw->daio_mgr_enb_dai(mgr->mgr.ctrl_blk,
+                               daio_device_index(daio->type, hw));
+       }
+       return 0;
+}
+
+static int daio_mgr_dsb_daio(struct daio_mgr *mgr, struct daio *daio)
+{
+       struct hw *hw = mgr->mgr.hw;
+
+       if (DAIO_OUT_MAX >= daio->type) {
+               hw->daio_mgr_dsb_dao(mgr->mgr.ctrl_blk,
+                               daio_device_index(daio->type, hw));
+       } else {
+               hw->daio_mgr_dsb_dai(mgr->mgr.ctrl_blk,
+                               daio_device_index(daio->type, hw));
+       }
+       return 0;
+}
+
+static int daio_map_op(void *data, struct imapper *entry)
+{
+       struct rsc_mgr *mgr = &((struct daio_mgr *)data)->mgr;
+       struct hw *hw = mgr->hw;
+
+       hw->daio_mgr_set_imaparc(mgr->ctrl_blk, entry->slot);
+       hw->daio_mgr_set_imapnxt(mgr->ctrl_blk, entry->next);
+       hw->daio_mgr_set_imapaddr(mgr->ctrl_blk, entry->addr);
+       hw->daio_mgr_commit_write(mgr->hw, mgr->ctrl_blk);
+
+       return 0;
+}
+
+static int daio_imap_add(struct daio_mgr *mgr, struct imapper *entry)
+{
+       unsigned long flags;
+       int err;
+
+       spin_lock_irqsave(&mgr->imap_lock, flags);
+       if ((0 == entry->addr) && (mgr->init_imap_added)) {
+               input_mapper_delete(&mgr->imappers, mgr->init_imap,
+                                                       daio_map_op, mgr);
+               mgr->init_imap_added = 0;
+       }
+       err = input_mapper_add(&mgr->imappers, entry, daio_map_op, mgr);
+       spin_unlock_irqrestore(&mgr->imap_lock, flags);
+
+       return err;
+}
+
+static int daio_imap_delete(struct daio_mgr *mgr, struct imapper *entry)
+{
+       unsigned long flags;
+       int err;
+
+       spin_lock_irqsave(&mgr->imap_lock, flags);
+       err = input_mapper_delete(&mgr->imappers, entry, daio_map_op, mgr);
+       if (list_empty(&mgr->imappers)) {
+               input_mapper_add(&mgr->imappers, mgr->init_imap,
+                                                       daio_map_op, mgr);
+               mgr->init_imap_added = 1;
+       }
+       spin_unlock_irqrestore(&mgr->imap_lock, flags);
+
+       return err;
+}
+
+static int daio_mgr_commit_write(struct daio_mgr *mgr)
+{
+       struct hw *hw = mgr->mgr.hw;
+
+       hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk);
+       return 0;
+}
+
+int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr)
+{
+       int err, i;
+       struct daio_mgr *daio_mgr;
+       struct imapper *entry;
+
+       *rdaio_mgr = NULL;
+       daio_mgr = kzalloc(sizeof(*daio_mgr), GFP_KERNEL);
+       if (NULL == daio_mgr)
+               return -ENOMEM;
+
+       err = rsc_mgr_init(&daio_mgr->mgr, DAIO, DAIO_RESOURCE_NUM, hw);
+       if (err)
+               goto error1;
+
+       spin_lock_init(&daio_mgr->mgr_lock);
+       spin_lock_init(&daio_mgr->imap_lock);
+       INIT_LIST_HEAD(&daio_mgr->imappers);
+       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+       if (NULL == entry) {
+               err = -ENOMEM;
+               goto error2;
+       }
+       entry->slot = entry->addr = entry->next = entry->user = 0;
+       list_add(&entry->list, &daio_mgr->imappers);
+       daio_mgr->init_imap = entry;
+       daio_mgr->init_imap_added = 1;
+
+       daio_mgr->get_daio = get_daio_rsc;
+       daio_mgr->put_daio = put_daio_rsc;
+       daio_mgr->daio_enable = daio_mgr_enb_daio;
+       daio_mgr->daio_disable = daio_mgr_dsb_daio;
+       daio_mgr->imap_add = daio_imap_add;
+       daio_mgr->imap_delete = daio_imap_delete;
+       daio_mgr->commit_write = daio_mgr_commit_write;
+
+       for (i = 0; i < 8; i++) {
+               ((struct hw *)hw)->daio_mgr_dsb_dao(daio_mgr->mgr.ctrl_blk, i);
+               ((struct hw *)hw)->daio_mgr_dsb_dai(daio_mgr->mgr.ctrl_blk, i);
+       }
+       ((struct hw *)hw)->daio_mgr_commit_write(hw, daio_mgr->mgr.ctrl_blk);
+
+       *rdaio_mgr = daio_mgr;
+
+       return 0;
+
+error2:
+       rsc_mgr_uninit(&daio_mgr->mgr);
+error1:
+       kfree(daio_mgr);
+       return err;
+}
+
+int daio_mgr_destroy(struct daio_mgr *daio_mgr)
+{
+       unsigned long flags;
+
+       /* free daio input mapper list */
+       spin_lock_irqsave(&daio_mgr->imap_lock, flags);
+       free_input_mapper_list(&daio_mgr->imappers);
+       spin_unlock_irqrestore(&daio_mgr->imap_lock, flags);
+
+       rsc_mgr_uninit(&daio_mgr->mgr);
+       kfree(daio_mgr);
+
+       return 0;
+}
+
diff --git a/sound/pci/ctxfi/ctdaio.h b/sound/pci/ctxfi/ctdaio.h
new file mode 100644 (file)
index 0000000..0f52ce5
--- /dev/null
@@ -0,0 +1,122 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File       ctdaio.h
+ *
+ * @Brief
+ * This file contains the definition of Digital Audio Input Output
+ * resource management object.
+ *
+ * @Author     Liu Chun
+ * @Date       May 23 2008
+ *
+ */
+
+#ifndef CTDAIO_H
+#define CTDAIO_H
+
+#include "ctresource.h"
+#include "ctimap.h"
+#include <linux/spinlock.h>
+#include <linux/list.h>
+
+/* Define the descriptor of a daio resource */
+enum DAIOTYP {
+       LINEO1,
+       LINEO2,
+       LINEO3,
+       LINEO4,
+       SPDIFOO,        /* S/PDIF Out (Flexijack/Optical) */
+       LINEIM,
+       SPDIFIO,        /* S/PDIF In (Flexijack/Optical) on the card */
+       SPDIFI1,        /* S/PDIF In on internal Drive Bay */
+       NUM_DAIOTYP
+};
+
+struct dao_rsc_ops;
+struct dai_rsc_ops;
+struct daio_mgr;
+
+struct daio {
+       struct rsc rscl;        /* Basic resource info for left TX/RX */
+       struct rsc rscr;        /* Basic resource info for right TX/RX */
+       enum DAIOTYP type;
+};
+
+struct dao {
+       struct daio daio;
+       struct dao_rsc_ops *ops;        /* DAO specific operations */
+       struct imapper **imappers;
+       struct daio_mgr *mgr;
+       void *hw;
+       void *ctrl_blk;
+};
+
+struct dai {
+       struct daio daio;
+       struct dai_rsc_ops *ops;        /* DAI specific operations */
+       void *hw;
+       void *ctrl_blk;
+};
+
+struct dao_desc {
+       unsigned int msr:4;
+       unsigned int passthru:1;
+};
+
+struct dao_rsc_ops {
+       int (*set_spos)(struct dao *dao, unsigned int spos);
+       int (*commit_write)(struct dao *dao);
+       int (*get_spos)(struct dao *dao, unsigned int *spos);
+       int (*reinit)(struct dao *dao, const struct dao_desc *desc);
+       int (*set_left_input)(struct dao *dao, struct rsc *input);
+       int (*set_right_input)(struct dao *dao, struct rsc *input);
+       int (*clear_left_input)(struct dao *dao);
+       int (*clear_right_input)(struct dao *dao);
+};
+
+struct dai_rsc_ops {
+       int (*set_srt_srcl)(struct dai *dai, struct rsc *src);
+       int (*set_srt_srcr)(struct dai *dai, struct rsc *src);
+       int (*set_srt_msr)(struct dai *dai, unsigned int msr);
+       int (*set_enb_src)(struct dai *dai, unsigned int enb);
+       int (*set_enb_srt)(struct dai *dai, unsigned int enb);
+       int (*commit_write)(struct dai *dai);
+};
+
+/* Define daio resource request description info */
+struct daio_desc {
+       unsigned int type:4;
+       unsigned int msr:4;
+       unsigned int passthru:1;
+};
+
+struct daio_mgr {
+       struct rsc_mgr mgr;     /* Basic resource manager info */
+       spinlock_t mgr_lock;
+       spinlock_t imap_lock;
+       struct list_head imappers;
+       struct imapper *init_imap;
+       unsigned int init_imap_added;
+
+        /* request one daio resource */
+       int (*get_daio)(struct daio_mgr *mgr,
+                       const struct daio_desc *desc, struct daio **rdaio);
+       /* return one daio resource */
+       int (*put_daio)(struct daio_mgr *mgr, struct daio *daio);
+       int (*daio_enable)(struct daio_mgr *mgr, struct daio *daio);
+       int (*daio_disable)(struct daio_mgr *mgr, struct daio *daio);
+       int (*imap_add)(struct daio_mgr *mgr, struct imapper *entry);
+       int (*imap_delete)(struct daio_mgr *mgr, struct imapper *entry);
+       int (*commit_write)(struct daio_mgr *mgr);
+};
+
+/* Constructor and destructor of daio resource manager */
+int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr);
+int daio_mgr_destroy(struct daio_mgr *daio_mgr);
+
+#endif /* CTDAIO_H */
diff --git a/sound/pci/ctxfi/cthardware.c b/sound/pci/ctxfi/cthardware.c
new file mode 100644 (file)
index 0000000..8e64f48
--- /dev/null
@@ -0,0 +1,91 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File       cthardware.c
+ *
+ * @Brief
+ * This file contains the implementation of hardware access methord.
+ *
+ * @Author     Liu Chun
+ * @Date       Jun 26 2008
+ *
+ */
+
+#include "cthardware.h"
+#include "cthw20k1.h"
+#include "cthw20k2.h"
+#include <linux/bug.h>
+
+int __devinit create_hw_obj(struct pci_dev *pci, enum CHIPTYP chip_type,
+                           enum CTCARDS model, struct hw **rhw)
+{
+       int err;
+
+       switch (chip_type) {
+       case ATC20K1:
+               err = create_20k1_hw_obj(rhw);
+               break;
+       case ATC20K2:
+               err = create_20k2_hw_obj(rhw);
+               break;
+       default:
+               err = -ENODEV;
+               break;
+       }
+       if (err)
+               return err;
+
+       (*rhw)->pci = pci;
+       (*rhw)->chip_type = chip_type;
+       (*rhw)->model = model;
+
+       return 0;
+}
+
+int destroy_hw_obj(struct hw *hw)
+{
+       int err;
+
+       switch (hw->pci->device) {
+       case 0x0005:    /* 20k1 device */
+               err = destroy_20k1_hw_obj(hw);
+               break;
+       case 0x000B:    /* 20k2 device */
+               err = destroy_20k2_hw_obj(hw);
+               break;
+       default:
+               err = -ENODEV;
+               break;
+       }
+
+       return err;
+}
+
+unsigned int get_field(unsigned int data, unsigned int field)
+{
+       int i;
+
+       BUG_ON(!field);
+       /* @field should always be greater than 0 */
+       for (i = 0; !(field & (1 << i)); )
+               i++;
+
+       return (data & field) >> i;
+}
+
+void set_field(unsigned int *data, unsigned int field, unsigned int value)
+{
+       int i;
+
+       BUG_ON(!field);
+       /* @field should always be greater than 0 */
+       for (i = 0; !(field & (1 << i)); )
+               i++;
+
+       *data = (*data & (~field)) | ((value << i) & field);
+}
+
diff --git a/sound/pci/ctxfi/cthardware.h b/sound/pci/ctxfi/cthardware.h
new file mode 100644 (file)
index 0000000..4a8e04f
--- /dev/null
@@ -0,0 +1,196 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File       cthardware.h
+ *
+ * @Brief
+ * This file contains the definition of hardware access methord.
+ *
+ * @Author     Liu Chun
+ * @Date       May 13 2008
+ *
+ */
+
+#ifndef CTHARDWARE_H
+#define CTHARDWARE_H
+
+#include <linux/types.h>
+#include <linux/pci.h>
+
+enum CHIPTYP {
+       ATC20K1,
+       ATC20K2,
+       ATCNONE
+};
+
+enum CTCARDS {
+       /* 20k1 models */
+       CTSB055X,
+       CTSB073X,
+       CTUAA,
+       CT20K1_UNKNOWN,
+       /* 20k2 models */
+       CTSB0760,
+       CTHENDRIX,
+       CTSB0880,
+       NUM_CTCARDS             /* This should always be the last */
+};
+
+/* Type of input source for ADC */
+enum ADCSRC{
+       ADC_MICIN,
+       ADC_LINEIN,
+       ADC_VIDEO,
+       ADC_AUX,
+       ADC_NONE        /* Switch to digital input */
+};
+
+struct card_conf {
+       /* device virtual mem page table page physical addr
+        * (supporting one page table page now) */
+       unsigned long vm_pgt_phys;
+       unsigned int rsr;       /* reference sample rate in Hzs*/
+       unsigned int msr;       /* master sample rate in rsrs */
+};
+
+struct hw {
+       int (*card_init)(struct hw *hw, struct card_conf *info);
+       int (*card_stop)(struct hw *hw);
+       int (*pll_init)(struct hw *hw, unsigned int rsr);
+       int (*is_adc_source_selected)(struct hw *hw, enum ADCSRC source);
+       int (*select_adc_source)(struct hw *hw, enum ADCSRC source);
+       int (*have_digit_io_switch)(struct hw *hw);
+
+       /* SRC operations */
+       int (*src_rsc_get_ctrl_blk)(void **rblk);
+       int (*src_rsc_put_ctrl_blk)(void *blk);
+       int (*src_set_state)(void *blk, unsigned int state);
+       int (*src_set_bm)(void *blk, unsigned int bm);
+       int (*src_set_rsr)(void *blk, unsigned int rsr);
+       int (*src_set_sf)(void *blk, unsigned int sf);
+       int (*src_set_wr)(void *blk, unsigned int wr);
+       int (*src_set_pm)(void *blk, unsigned int pm);
+       int (*src_set_rom)(void *blk, unsigned int rom);
+       int (*src_set_vo)(void *blk, unsigned int vo);
+       int (*src_set_st)(void *blk, unsigned int st);
+       int (*src_set_ie)(void *blk, unsigned int ie);
+       int (*src_set_ilsz)(void *blk, unsigned int ilsz);
+       int (*src_set_bp)(void *blk, unsigned int bp);
+       int (*src_set_cisz)(void *blk, unsigned int cisz);
+       int (*src_set_ca)(void *blk, unsigned int ca);
+       int (*src_set_sa)(void *blk, unsigned int sa);
+       int (*src_set_la)(void *blk, unsigned int la);
+       int (*src_set_pitch)(void *blk, unsigned int pitch);
+       int (*src_set_clear_zbufs)(void *blk, unsigned int clear);
+       int (*src_set_dirty)(void *blk, unsigned int flags);
+       int (*src_set_dirty_all)(void *blk);
+       int (*src_commit_write)(struct hw *hw, unsigned int idx, void *blk);
+       int (*src_get_ca)(struct hw *hw, unsigned int idx, void *blk);
+       unsigned int (*src_get_dirty)(void *blk);
+       unsigned int (*src_dirty_conj_mask)(void);
+       int (*src_mgr_get_ctrl_blk)(void **rblk);
+       int (*src_mgr_put_ctrl_blk)(void *blk);
+       /* syncly enable src @idx */
+       int (*src_mgr_enbs_src)(void *blk, unsigned int idx);
+       /* enable src @idx */
+       int (*src_mgr_enb_src)(void *blk, unsigned int idx);
+       /* disable src @idx */
+       int (*src_mgr_dsb_src)(void *blk, unsigned int idx);
+       int (*src_mgr_commit_write)(struct hw *hw, void *blk);
+
+       /* SRC Input Mapper operations */
+       int (*srcimp_mgr_get_ctrl_blk)(void **rblk);
+       int (*srcimp_mgr_put_ctrl_blk)(void *blk);
+       int (*srcimp_mgr_set_imaparc)(void *blk, unsigned int slot);
+       int (*srcimp_mgr_set_imapuser)(void *blk, unsigned int user);
+       int (*srcimp_mgr_set_imapnxt)(void *blk, unsigned int next);
+       int (*srcimp_mgr_set_imapaddr)(void *blk, unsigned int addr);
+       int (*srcimp_mgr_commit_write)(struct hw *hw, void *blk);
+
+       /* AMIXER operations */
+       int (*amixer_rsc_get_ctrl_blk)(void **rblk);
+       int (*amixer_rsc_put_ctrl_blk)(void *blk);
+       int (*amixer_mgr_get_ctrl_blk)(void **rblk);
+       int (*amixer_mgr_put_ctrl_blk)(void *blk);
+       int (*amixer_set_mode)(void *blk, unsigned int mode);
+       int (*amixer_set_iv)(void *blk, unsigned int iv);
+       int (*amixer_set_x)(void *blk, unsigned int x);
+       int (*amixer_set_y)(void *blk, unsigned int y);
+       int (*amixer_set_sadr)(void *blk, unsigned int sadr);
+       int (*amixer_set_se)(void *blk, unsigned int se);
+       int (*amixer_set_dirty)(void *blk, unsigned int flags);
+       int (*amixer_set_dirty_all)(void *blk);
+       int (*amixer_commit_write)(struct hw *hw, unsigned int idx, void *blk);
+       int (*amixer_get_y)(void *blk);
+       unsigned int (*amixer_get_dirty)(void *blk);
+
+       /* DAIO operations */
+       int (*dai_get_ctrl_blk)(void **rblk);
+       int (*dai_put_ctrl_blk)(void *blk);
+       int (*dai_srt_set_srco)(void *blk, unsigned int src);
+       int (*dai_srt_set_srcm)(void *blk, unsigned int src);
+       int (*dai_srt_set_rsr)(void *blk, unsigned int rsr);
+       int (*dai_srt_set_drat)(void *blk, unsigned int drat);
+       int (*dai_srt_set_ec)(void *blk, unsigned int ec);
+       int (*dai_srt_set_et)(void *blk, unsigned int et);
+       int (*dai_commit_write)(struct hw *hw, unsigned int idx, void *blk);
+       int (*dao_get_ctrl_blk)(void **rblk);
+       int (*dao_put_ctrl_blk)(void *blk);
+       int (*dao_set_spos)(void *blk, unsigned int spos);
+       int (*dao_commit_write)(struct hw *hw, unsigned int idx, void *blk);
+       int (*dao_get_spos)(void *blk, unsigned int *spos);
+
+       int (*daio_mgr_get_ctrl_blk)(struct hw *hw, void **rblk);
+       int (*daio_mgr_put_ctrl_blk)(void *blk);
+       int (*daio_mgr_enb_dai)(void *blk, unsigned int idx);
+       int (*daio_mgr_dsb_dai)(void *blk, unsigned int idx);
+       int (*daio_mgr_enb_dao)(void *blk, unsigned int idx);
+       int (*daio_mgr_dsb_dao)(void *blk, unsigned int idx);
+       int (*daio_mgr_dao_init)(void *blk, unsigned int idx,
+                                               unsigned int conf);
+       int (*daio_mgr_set_imaparc)(void *blk, unsigned int slot);
+       int (*daio_mgr_set_imapnxt)(void *blk, unsigned int next);
+       int (*daio_mgr_set_imapaddr)(void *blk, unsigned int addr);
+       int (*daio_mgr_commit_write)(struct hw *hw, void *blk);
+
+       int (*set_timer_irq)(struct hw *hw, int enable);
+       int (*set_timer_tick)(struct hw *hw, unsigned int tick);
+       unsigned int (*get_wc)(struct hw *hw);
+
+       void (*irq_callback)(void *data, unsigned int bit);
+       void *irq_callback_data;
+
+       struct pci_dev *pci;    /* the pci kernel structure of this card */
+       int irq;
+       unsigned long io_base;
+       unsigned long mem_base;
+
+       enum CHIPTYP chip_type;
+       enum CTCARDS model;
+};
+
+int create_hw_obj(struct pci_dev *pci, enum CHIPTYP chip_type,
+                 enum CTCARDS model, struct hw **rhw);
+int destroy_hw_obj(struct hw *hw);
+
+unsigned int get_field(unsigned int data, unsigned int field);
+void set_field(unsigned int *data, unsigned int field, unsigned int value);
+
+/* IRQ bits */
+#define        PLL_INT         (1 << 10) /* PLL input-clock out-of-range */
+#define FI_INT         (1 << 9)  /* forced interrupt */
+#define IT_INT         (1 << 8)  /* timer interrupt */
+#define PCI_INT                (1 << 7)  /* PCI bus error pending */
+#define URT_INT                (1 << 6)  /* UART Tx/Rx */
+#define GPI_INT                (1 << 5)  /* GPI pin */
+#define MIX_INT                (1 << 4)  /* mixer parameter segment FIFO channels */
+#define DAI_INT                (1 << 3)  /* DAI (SR-tracker or SPDIF-receiver) */
+#define TP_INT         (1 << 2)  /* transport priority queue */
+#define DSP_INT                (1 << 1)  /* DSP */
+#define SRC_INT                (1 << 0)  /* SRC channels */
+
+#endif /* CTHARDWARE_H */
diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c
new file mode 100644 (file)
index 0000000..cb69d9d
--- /dev/null
@@ -0,0 +1,2248 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File       cthw20k1.c
+ *
+ * @Brief
+ * This file contains the implementation of hardware access methord for 20k1.
+ *
+ * @Author     Liu Chun
+ * @Date       Jun 24 2008
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include "cthw20k1.h"
+#include "ct20k1reg.h"
+
+#if BITS_PER_LONG == 32
+#define CT_XFI_DMA_MASK                DMA_BIT_MASK(32) /* 32 bit PTE */
+#else
+#define CT_XFI_DMA_MASK                DMA_BIT_MASK(64) /* 64 bit PTE */
+#endif
+
+struct hw20k1 {
+       struct hw hw;
+       spinlock_t reg_20k1_lock;
+       spinlock_t reg_pci_lock;
+};
+
+static u32 hw_read_20kx(struct hw *hw, u32 reg);
+static void hw_write_20kx(struct hw *hw, u32 reg, u32 data);
+static u32 hw_read_pci(struct hw *hw, u32 reg);
+static void hw_write_pci(struct hw *hw, u32 reg, u32 data);
+
+/*
+ * Type definition block.
+ * The layout of control structures can be directly applied on 20k2 chip.
+ */
+
+/*
+ * SRC control block definitions.
+ */
+
+/* SRC resource control block */
+#define SRCCTL_STATE   0x00000007
+#define SRCCTL_BM      0x00000008
+#define SRCCTL_RSR     0x00000030
+#define SRCCTL_SF      0x000001C0
+#define SRCCTL_WR      0x00000200
+#define SRCCTL_PM      0x00000400
+#define SRCCTL_ROM     0x00001800
+#define SRCCTL_VO      0x00002000
+#define SRCCTL_ST      0x00004000
+#define SRCCTL_IE      0x00008000
+#define SRCCTL_ILSZ    0x000F0000
+#define SRCCTL_BP      0x00100000
+
+#define SRCCCR_CISZ    0x000007FF
+#define SRCCCR_CWA     0x001FF800
+#define SRCCCR_D       0x00200000
+#define SRCCCR_RS      0x01C00000
+#define SRCCCR_NAL     0x3E000000
+#define SRCCCR_RA      0xC0000000
+
+#define SRCCA_CA       0x03FFFFFF
+#define SRCCA_RS       0x1C000000
+#define SRCCA_NAL      0xE0000000
+
+#define SRCSA_SA       0x03FFFFFF
+
+#define SRCLA_LA       0x03FFFFFF
+
+/* Mixer Parameter Ring ram Low and Hight register.
+ * Fixed-point value in 8.24 format for parameter channel */
+#define MPRLH_PITCH    0xFFFFFFFF
+
+/* SRC resource register dirty flags */
+union src_dirty {
+       struct {
+               u16 ctl:1;
+               u16 ccr:1;
+               u16 sa:1;
+               u16 la:1;
+               u16 ca:1;
+               u16 mpr:1;
+               u16 czbfs:1;    /* Clear Z-Buffers */
+               u16 rsv:9;
+       } bf;
+       u16 data;
+};
+
+struct src_rsc_ctrl_blk {
+       unsigned int    ctl;
+       unsigned int    ccr;
+       unsigned int    ca;
+       unsigned int    sa;
+       unsigned int    la;
+       unsigned int    mpr;
+       union src_dirty dirty;
+};
+
+/* SRC manager control block */
+union src_mgr_dirty {
+       struct {
+               u16 enb0:1;
+               u16 enb1:1;
+               u16 enb2:1;
+               u16 enb3:1;
+               u16 enb4:1;
+               u16 enb5:1;
+               u16 enb6:1;
+               u16 enb7:1;
+               u16 enbsa:1;
+               u16 rsv:7;
+       } bf;
+       u16 data;
+};
+
+struct src_mgr_ctrl_blk {
+       unsigned int            enbsa;
+       unsigned int            enb[8];
+       union src_mgr_dirty     dirty;
+};
+
+/* SRCIMP manager control block */
+#define SRCAIM_ARC     0x00000FFF
+#define SRCAIM_NXT     0x00FF0000
+#define SRCAIM_SRC     0xFF000000
+
+struct srcimap {
+       unsigned int srcaim;
+       unsigned int idx;
+};
+
+/* SRCIMP manager register dirty flags */
+union srcimp_mgr_dirty {
+       struct {
+               u16 srcimap:1;
+               u16 rsv:15;
+       } bf;
+       u16 data;
+};
+
+struct srcimp_mgr_ctrl_blk {
+       struct srcimap          srcimap;
+       union srcimp_mgr_dirty  dirty;
+};
+
+/*
+ * Function implementation block.
+ */
+
+static int src_get_rsc_ctrl_blk(void **rblk)
+{
+       struct src_rsc_ctrl_blk *blk;
+
+       *rblk = NULL;
+       blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+       if (NULL == blk)
+               return -ENOMEM;
+
+       *rblk = blk;
+
+       return 0;
+}
+
+static int src_put_rsc_ctrl_blk(void *blk)
+{
+       kfree((struct src_rsc_ctrl_blk *)blk);
+
+       return 0;
+}
+
+static int src_set_state(void *blk, unsigned int state)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ctl, SRCCTL_STATE, state);
+       ctl->dirty.bf.ctl = 1;
+       return 0;
+}
+
+static int src_set_bm(void *blk, unsigned int bm)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ctl, SRCCTL_BM, bm);
+       ctl->dirty.bf.ctl = 1;
+       return 0;
+}
+
+static int src_set_rsr(void *blk, unsigned int rsr)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ctl, SRCCTL_RSR, rsr);
+       ctl->dirty.bf.ctl = 1;
+       return 0;
+}
+
+static int src_set_sf(void *blk, unsigned int sf)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ctl, SRCCTL_SF, sf);
+       ctl->dirty.bf.ctl = 1;
+       return 0;
+}
+
+static int src_set_wr(void *blk, unsigned int wr)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ctl, SRCCTL_WR, wr);
+       ctl->dirty.bf.ctl = 1;
+       return 0;
+}
+
+static int src_set_pm(void *blk, unsigned int pm)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ctl, SRCCTL_PM, pm);
+       ctl->dirty.bf.ctl = 1;
+       return 0;
+}
+
+static int src_set_rom(void *blk, unsigned int rom)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ctl, SRCCTL_ROM, rom);
+       ctl->dirty.bf.ctl = 1;
+       return 0;
+}
+
+static int src_set_vo(void *blk, unsigned int vo)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ctl, SRCCTL_VO, vo);
+       ctl->dirty.bf.ctl = 1;
+       return 0;
+}
+
+static int src_set_st(void *blk, unsigned int st)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ctl, SRCCTL_ST, st);
+       ctl->dirty.bf.ctl = 1;
+       return 0;
+}
+
+static int src_set_ie(void *blk, unsigned int ie)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ctl, SRCCTL_IE, ie);
+       ctl->dirty.bf.ctl = 1;
+       return 0;
+}
+
+static int src_set_ilsz(void *blk, unsigned int ilsz)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ctl, SRCCTL_ILSZ, ilsz);
+       ctl->dirty.bf.ctl = 1;
+       return 0;
+}
+
+static int src_set_bp(void *blk, unsigned int bp)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ctl, SRCCTL_BP, bp);
+       ctl->dirty.bf.ctl = 1;
+       return 0;
+}
+
+static int src_set_cisz(void *blk, unsigned int cisz)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ccr, SRCCCR_CISZ, cisz);
+       ctl->dirty.bf.ccr = 1;
+       return 0;
+}
+
+static int src_set_ca(void *blk, unsigned int ca)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ca, SRCCA_CA, ca);
+       ctl->dirty.bf.ca = 1;
+       return 0;
+}
+
+static int src_set_sa(void *blk, unsigned int sa)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->sa, SRCSA_SA, sa);
+       ctl->dirty.bf.sa = 1;
+       return 0;
+}
+
+static int src_set_la(void *blk, unsigned int la)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->la, SRCLA_LA, la);
+       ctl->dirty.bf.la = 1;
+       return 0;
+}
+
+static int src_set_pitch(void *blk, unsigned int pitch)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->mpr, MPRLH_PITCH, pitch);
+       ctl->dirty.bf.mpr = 1;
+       return 0;
+}
+
+static int src_set_clear_zbufs(void *blk, unsigned int clear)
+{
+       ((struct src_rsc_ctrl_blk *)blk)->dirty.bf.czbfs = (clear ? 1 : 0);
+       return 0;
+}
+
+static int src_set_dirty(void *blk, unsigned int flags)
+{
+       ((struct src_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff);
+       return 0;
+}
+
+static int src_set_dirty_all(void *blk)
+{
+       ((struct src_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0);
+       return 0;
+}
+
+#define AR_SLOT_SIZE           4096
+#define AR_SLOT_BLOCK_SIZE     16
+#define AR_PTS_PITCH           6
+#define AR_PARAM_SRC_OFFSET    0x60
+
+static unsigned int src_param_pitch_mixer(unsigned int src_idx)
+{
+       return ((src_idx << 4) + AR_PTS_PITCH + AR_SLOT_SIZE
+                       - AR_PARAM_SRC_OFFSET) % AR_SLOT_SIZE;
+
+}
+
+static int src_commit_write(struct hw *hw, unsigned int idx, void *blk)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+       int i;
+
+       if (ctl->dirty.bf.czbfs) {
+               /* Clear Z-Buffer registers */
+               for (i = 0; i < 8; i++)
+                       hw_write_20kx(hw, SRCUPZ+idx*0x100+i*0x4, 0);
+
+               for (i = 0; i < 4; i++)
+                       hw_write_20kx(hw, SRCDN0Z+idx*0x100+i*0x4, 0);
+
+               for (i = 0; i < 8; i++)
+                       hw_write_20kx(hw, SRCDN1Z+idx*0x100+i*0x4, 0);
+
+               ctl->dirty.bf.czbfs = 0;
+       }
+       if (ctl->dirty.bf.mpr) {
+               /* Take the parameter mixer resource in the same group as that
+                * the idx src is in for simplicity. Unlike src, all conjugate
+                * parameter mixer resources must be programmed for
+                * corresponding conjugate src resources. */
+               unsigned int pm_idx = src_param_pitch_mixer(idx);
+               hw_write_20kx(hw, PRING_LO_HI+4*pm_idx, ctl->mpr);
+               hw_write_20kx(hw, PMOPLO+8*pm_idx, 0x3);
+               hw_write_20kx(hw, PMOPHI+8*pm_idx, 0x0);
+               ctl->dirty.bf.mpr = 0;
+       }
+       if (ctl->dirty.bf.sa) {
+               hw_write_20kx(hw, SRCSA+idx*0x100, ctl->sa);
+               ctl->dirty.bf.sa = 0;
+       }
+       if (ctl->dirty.bf.la) {
+               hw_write_20kx(hw, SRCLA+idx*0x100, ctl->la);
+               ctl->dirty.bf.la = 0;
+       }
+       if (ctl->dirty.bf.ca) {
+               hw_write_20kx(hw, SRCCA+idx*0x100, ctl->ca);
+               ctl->dirty.bf.ca = 0;
+       }
+
+       /* Write srccf register */
+       hw_write_20kx(hw, SRCCF+idx*0x100, 0x0);
+
+       if (ctl->dirty.bf.ccr) {
+               hw_write_20kx(hw, SRCCCR+idx*0x100, ctl->ccr);
+               ctl->dirty.bf.ccr = 0;
+       }
+       if (ctl->dirty.bf.ctl) {
+               hw_write_20kx(hw, SRCCTL+idx*0x100, ctl->ctl);
+               ctl->dirty.bf.ctl = 0;
+       }
+
+       return 0;
+}
+
+static int src_get_ca(struct hw *hw, unsigned int idx, void *blk)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       ctl->ca = hw_read_20kx(hw, SRCCA+idx*0x100);
+       ctl->dirty.bf.ca = 0;
+
+       return get_field(ctl->ca, SRCCA_CA);
+}
+
+static unsigned int src_get_dirty(void *blk)
+{
+       return ((struct src_rsc_ctrl_blk *)blk)->dirty.data;
+}
+
+static unsigned int src_dirty_conj_mask(void)
+{
+       return 0x20;
+}
+
+static int src_mgr_enbs_src(void *blk, unsigned int idx)
+{
+       ((struct src_mgr_ctrl_blk *)blk)->enbsa = ~(0x0);
+       ((struct src_mgr_ctrl_blk *)blk)->dirty.bf.enbsa = 1;
+       ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32));
+       return 0;
+}
+
+static int src_mgr_enb_src(void *blk, unsigned int idx)
+{
+       ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32));
+       ((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32));
+       return 0;
+}
+
+static int src_mgr_dsb_src(void *blk, unsigned int idx)
+{
+       ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] &= ~(0x1 << (idx%32));
+       ((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32));
+       return 0;
+}
+
+static int src_mgr_commit_write(struct hw *hw, void *blk)
+{
+       struct src_mgr_ctrl_blk *ctl = blk;
+       int i;
+       unsigned int ret;
+
+       if (ctl->dirty.bf.enbsa) {
+               do {
+                       ret = hw_read_20kx(hw, SRCENBSTAT);
+               } while (ret & 0x1);
+               hw_write_20kx(hw, SRCENBS, ctl->enbsa);
+               ctl->dirty.bf.enbsa = 0;
+       }
+       for (i = 0; i < 8; i++) {
+               if ((ctl->dirty.data & (0x1 << i))) {
+                       hw_write_20kx(hw, SRCENB+(i*0x100), ctl->enb[i]);
+                       ctl->dirty.data &= ~(0x1 << i);
+               }
+       }
+
+       return 0;
+}
+
+static int src_mgr_get_ctrl_blk(void **rblk)
+{
+       struct src_mgr_ctrl_blk *blk;
+
+       *rblk = NULL;
+       blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+       if (NULL == blk)
+               return -ENOMEM;
+
+       *rblk = blk;
+
+       return 0;
+}
+
+static int src_mgr_put_ctrl_blk(void *blk)
+{
+       kfree((struct src_mgr_ctrl_blk *)blk);
+
+       return 0;
+}
+
+static int srcimp_mgr_get_ctrl_blk(void **rblk)
+{
+       struct srcimp_mgr_ctrl_blk *blk;
+
+       *rblk = NULL;
+       blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+       if (NULL == blk)
+               return -ENOMEM;
+
+       *rblk = blk;
+
+       return 0;
+}
+
+static int srcimp_mgr_put_ctrl_blk(void *blk)
+{
+       kfree((struct srcimp_mgr_ctrl_blk *)blk);
+
+       return 0;
+}
+
+static int srcimp_mgr_set_imaparc(void *blk, unsigned int slot)
+{
+       struct srcimp_mgr_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->srcimap.srcaim, SRCAIM_ARC, slot);
+       ctl->dirty.bf.srcimap = 1;
+       return 0;
+}
+
+static int srcimp_mgr_set_imapuser(void *blk, unsigned int user)
+{
+       struct srcimp_mgr_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->srcimap.srcaim, SRCAIM_SRC, user);
+       ctl->dirty.bf.srcimap = 1;
+       return 0;
+}
+
+static int srcimp_mgr_set_imapnxt(void *blk, unsigned int next)
+{
+       struct srcimp_mgr_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->srcimap.srcaim, SRCAIM_NXT, next);
+       ctl->dirty.bf.srcimap = 1;
+       return 0;
+}
+
+static int srcimp_mgr_set_imapaddr(void *blk, unsigned int addr)
+{
+       struct srcimp_mgr_ctrl_blk *ctl = blk;
+
+       ctl->srcimap.idx = addr;
+       ctl->dirty.bf.srcimap = 1;
+       return 0;
+}
+
+static int srcimp_mgr_commit_write(struct hw *hw, void *blk)
+{
+       struct srcimp_mgr_ctrl_blk *ctl = blk;
+
+       if (ctl->dirty.bf.srcimap) {
+               hw_write_20kx(hw, SRCIMAP+ctl->srcimap.idx*0x100,
+                                               ctl->srcimap.srcaim);
+               ctl->dirty.bf.srcimap = 0;
+       }
+
+       return 0;
+}
+
+/*
+ * AMIXER control block definitions.
+ */
+
+#define AMOPLO_M       0x00000003
+#define AMOPLO_X       0x0003FFF0
+#define AMOPLO_Y       0xFFFC0000
+
+#define AMOPHI_SADR    0x000000FF
+#define AMOPHI_SE      0x80000000
+
+/* AMIXER resource register dirty flags */
+union amixer_dirty {
+       struct {
+               u16 amoplo:1;
+               u16 amophi:1;
+               u16 rsv:14;
+       } bf;
+       u16 data;
+};
+
+/* AMIXER resource control block */
+struct amixer_rsc_ctrl_blk {
+       unsigned int            amoplo;
+       unsigned int            amophi;
+       union amixer_dirty      dirty;
+};
+
+static int amixer_set_mode(void *blk, unsigned int mode)
+{
+       struct amixer_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->amoplo, AMOPLO_M, mode);
+       ctl->dirty.bf.amoplo = 1;
+       return 0;
+}
+
+static int amixer_set_iv(void *blk, unsigned int iv)
+{
+       /* 20k1 amixer does not have this field */
+       return 0;
+}
+
+static int amixer_set_x(void *blk, unsigned int x)
+{
+       struct amixer_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->amoplo, AMOPLO_X, x);
+       ctl->dirty.bf.amoplo = 1;
+       return 0;
+}
+
+static int amixer_set_y(void *blk, unsigned int y)
+{
+       struct amixer_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->amoplo, AMOPLO_Y, y);
+       ctl->dirty.bf.amoplo = 1;
+       return 0;
+}
+
+static int amixer_set_sadr(void *blk, unsigned int sadr)
+{
+       struct amixer_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->amophi, AMOPHI_SADR, sadr);
+       ctl->dirty.bf.amophi = 1;
+       return 0;
+}
+
+static int amixer_set_se(void *blk, unsigned int se)
+{
+       struct amixer_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->amophi, AMOPHI_SE, se);
+       ctl->dirty.bf.amophi = 1;
+       return 0;
+}
+
+static int amixer_set_dirty(void *blk, unsigned int flags)
+{
+       ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff);
+       return 0;
+}
+
+static int amixer_set_dirty_all(void *blk)
+{
+       ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0);
+       return 0;
+}
+
+static int amixer_commit_write(struct hw *hw, unsigned int idx, void *blk)
+{
+       struct amixer_rsc_ctrl_blk *ctl = blk;
+
+       if (ctl->dirty.bf.amoplo || ctl->dirty.bf.amophi) {
+               hw_write_20kx(hw, AMOPLO+idx*8, ctl->amoplo);
+               ctl->dirty.bf.amoplo = 0;
+               hw_write_20kx(hw, AMOPHI+idx*8, ctl->amophi);
+               ctl->dirty.bf.amophi = 0;
+       }
+
+       return 0;
+}
+
+static int amixer_get_y(void *blk)
+{
+       struct amixer_rsc_ctrl_blk *ctl = blk;
+
+       return get_field(ctl->amoplo, AMOPLO_Y);
+}
+
+static unsigned int amixer_get_dirty(void *blk)
+{
+       return ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data;
+}
+
+static int amixer_rsc_get_ctrl_blk(void **rblk)
+{
+       struct amixer_rsc_ctrl_blk *blk;
+
+       *rblk = NULL;
+       blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+       if (NULL == blk)
+               return -ENOMEM;
+
+       *rblk = blk;
+
+       return 0;
+}
+
+static int amixer_rsc_put_ctrl_blk(void *blk)
+{
+       kfree((struct amixer_rsc_ctrl_blk *)blk);
+
+       return 0;
+}
+
+static int amixer_mgr_get_ctrl_blk(void **rblk)
+{
+       /*amixer_mgr_ctrl_blk_t *blk;*/
+
+       *rblk = NULL;
+       /*blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+       if (NULL == blk)
+               return -ENOMEM;
+
+       *rblk = blk;*/
+
+       return 0;
+}
+
+static int amixer_mgr_put_ctrl_blk(void *blk)
+{
+       /*kfree((amixer_mgr_ctrl_blk_t *)blk);*/
+
+       return 0;
+}
+
+/*
+ * DAIO control block definitions.
+ */
+
+/* Receiver Sample Rate Tracker Control register */
+#define SRTCTL_SRCR    0x000000FF
+#define SRTCTL_SRCL    0x0000FF00
+#define SRTCTL_RSR     0x00030000
+#define SRTCTL_DRAT    0x000C0000
+#define SRTCTL_RLE     0x10000000
+#define SRTCTL_RLP     0x20000000
+#define SRTCTL_EC      0x40000000
+#define SRTCTL_ET      0x80000000
+
+/* DAIO Receiver register dirty flags */
+union dai_dirty {
+       struct {
+               u16 srtctl:1;
+               u16 rsv:15;
+       } bf;
+       u16 data;
+};
+
+/* DAIO Receiver control block */
+struct dai_ctrl_blk {
+       unsigned int    srtctl;
+       union dai_dirty dirty;
+};
+
+/* S/PDIF Transmitter register dirty flags */
+union dao_dirty {
+       struct {
+               u16 spos:1;
+               u16 rsv:15;
+       } bf;
+       u16 data;
+};
+
+/* S/PDIF Transmitter control block */
+struct dao_ctrl_blk {
+       unsigned int    spos; /* S/PDIF Output Channel Status Register */
+       union dao_dirty dirty;
+};
+
+/* Audio Input Mapper RAM */
+#define AIM_ARC                0x00000FFF
+#define AIM_NXT                0x007F0000
+
+struct daoimap {
+       unsigned int aim;
+       unsigned int idx;
+};
+
+/* I2S Transmitter/Receiver Control register */
+#define I2SCTL_EA      0x00000004
+#define I2SCTL_EI      0x00000010
+
+/* S/PDIF Transmitter Control register */
+#define SPOCTL_OE      0x00000001
+#define SPOCTL_OS      0x0000000E
+#define SPOCTL_RIV     0x00000010
+#define SPOCTL_LIV     0x00000020
+#define SPOCTL_SR      0x000000C0
+
+/* S/PDIF Receiver Control register */
+#define SPICTL_EN      0x00000001
+#define SPICTL_I24     0x00000002
+#define SPICTL_IB      0x00000004
+#define SPICTL_SM      0x00000008
+#define SPICTL_VM      0x00000010
+
+/* DAIO manager register dirty flags */
+union daio_mgr_dirty {
+       struct {
+               u32 i2soctl:4;
+               u32 i2sictl:4;
+               u32 spoctl:4;
+               u32 spictl:4;
+               u32 daoimap:1;
+               u32 rsv:15;
+       } bf;
+       u32 data;
+};
+
+/* DAIO manager control block */
+struct daio_mgr_ctrl_blk {
+       unsigned int            i2sctl;
+       unsigned int            spoctl;
+       unsigned int            spictl;
+       struct daoimap          daoimap;
+       union daio_mgr_dirty    dirty;
+};
+
+static int dai_srt_set_srcr(void *blk, unsigned int src)
+{
+       struct dai_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->srtctl, SRTCTL_SRCR, src);
+       ctl->dirty.bf.srtctl = 1;
+       return 0;
+}
+
+static int dai_srt_set_srcl(void *blk, unsigned int src)
+{
+       struct dai_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->srtctl, SRTCTL_SRCL, src);
+       ctl->dirty.bf.srtctl = 1;
+       return 0;
+}
+
+static int dai_srt_set_rsr(void *blk, unsigned int rsr)
+{
+       struct dai_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->srtctl, SRTCTL_RSR, rsr);
+       ctl->dirty.bf.srtctl = 1;
+       return 0;
+}
+
+static int dai_srt_set_drat(void *blk, unsigned int drat)
+{
+       struct dai_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->srtctl, SRTCTL_DRAT, drat);
+       ctl->dirty.bf.srtctl = 1;
+       return 0;
+}
+
+static int dai_srt_set_ec(void *blk, unsigned int ec)
+{
+       struct dai_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->srtctl, SRTCTL_EC, ec ? 1 : 0);
+       ctl->dirty.bf.srtctl = 1;
+       return 0;
+}
+
+static int dai_srt_set_et(void *blk, unsigned int et)
+{
+       struct dai_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->srtctl, SRTCTL_ET, et ? 1 : 0);
+       ctl->dirty.bf.srtctl = 1;
+       return 0;
+}
+
+static int dai_commit_write(struct hw *hw, unsigned int idx, void *blk)
+{
+       struct dai_ctrl_blk *ctl = blk;
+
+       if (ctl->dirty.bf.srtctl) {
+               if (idx < 4) {
+                       /* S/PDIF SRTs */
+                       hw_write_20kx(hw, SRTSCTL+0x4*idx, ctl->srtctl);
+               } else {
+                       /* I2S SRT */
+                       hw_write_20kx(hw, SRTICTL, ctl->srtctl);
+               }
+               ctl->dirty.bf.srtctl = 0;
+       }
+
+       return 0;
+}
+
+static int dai_get_ctrl_blk(void **rblk)
+{
+       struct dai_ctrl_blk *blk;
+
+       *rblk = NULL;
+       blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+       if (NULL == blk)
+               return -ENOMEM;
+
+       *rblk = blk;
+
+       return 0;
+}
+
+static int dai_put_ctrl_blk(void *blk)
+{
+       kfree((struct dai_ctrl_blk *)blk);
+
+       return 0;
+}
+
+static int dao_set_spos(void *blk, unsigned int spos)
+{
+       ((struct dao_ctrl_blk *)blk)->spos = spos;
+       ((struct dao_ctrl_blk *)blk)->dirty.bf.spos = 1;
+       return 0;
+}
+
+static int dao_commit_write(struct hw *hw, unsigned int idx, void *blk)
+{
+       struct dao_ctrl_blk *ctl = blk;
+
+       if (ctl->dirty.bf.spos) {
+               if (idx < 4) {
+                       /* S/PDIF SPOSx */
+                       hw_write_20kx(hw, SPOS+0x4*idx, ctl->spos);
+               }
+               ctl->dirty.bf.spos = 0;
+       }
+
+       return 0;
+}
+
+static int dao_get_spos(void *blk, unsigned int *spos)
+{
+       *spos = ((struct dao_ctrl_blk *)blk)->spos;
+       return 0;
+}
+
+static int dao_get_ctrl_blk(void **rblk)
+{
+       struct dao_ctrl_blk *blk;
+
+       *rblk = NULL;
+       blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+       if (NULL == blk)
+               return -ENOMEM;
+
+       *rblk = blk;
+
+       return 0;
+}
+
+static int dao_put_ctrl_blk(void *blk)
+{
+       kfree((struct dao_ctrl_blk *)blk);
+
+       return 0;
+}
+
+static int daio_mgr_enb_dai(void *blk, unsigned int idx)
+{
+       struct daio_mgr_ctrl_blk *ctl = blk;
+
+       if (idx < 4) {
+               /* S/PDIF input */
+               set_field(&ctl->spictl, SPICTL_EN << (idx*8), 1);
+               ctl->dirty.bf.spictl |= (0x1 << idx);
+       } else {
+               /* I2S input */
+               idx %= 4;
+               set_field(&ctl->i2sctl, I2SCTL_EI << (idx*8), 1);
+               ctl->dirty.bf.i2sictl |= (0x1 << idx);
+       }
+       return 0;
+}
+
+static int daio_mgr_dsb_dai(void *blk, unsigned int idx)
+{
+       struct daio_mgr_ctrl_blk *ctl = blk;
+
+       if (idx < 4) {
+               /* S/PDIF input */
+               set_field(&ctl->spictl, SPICTL_EN << (idx*8), 0);
+               ctl->dirty.bf.spictl |= (0x1 << idx);
+       } else {
+               /* I2S input */
+               idx %= 4;
+               set_field(&ctl->i2sctl, I2SCTL_EI << (idx*8), 0);
+               ctl->dirty.bf.i2sictl |= (0x1 << idx);
+       }
+       return 0;
+}
+
+static int daio_mgr_enb_dao(void *blk, unsigned int idx)
+{
+       struct daio_mgr_ctrl_blk *ctl = blk;
+
+       if (idx < 4) {
+               /* S/PDIF output */
+               set_field(&ctl->spoctl, SPOCTL_OE << (idx*8), 1);
+               ctl->dirty.bf.spoctl |= (0x1 << idx);
+       } else {
+               /* I2S output */
+               idx %= 4;
+               set_field(&ctl->i2sctl, I2SCTL_EA << (idx*8), 1);
+               ctl->dirty.bf.i2soctl |= (0x1 << idx);
+       }
+       return 0;
+}
+
+static int daio_mgr_dsb_dao(void *blk, unsigned int idx)
+{
+       struct daio_mgr_ctrl_blk *ctl = blk;
+
+       if (idx < 4) {
+               /* S/PDIF output */
+               set_field(&ctl->spoctl, SPOCTL_OE << (idx*8), 0);
+               ctl->dirty.bf.spoctl |= (0x1 << idx);
+       } else {
+               /* I2S output */
+               idx %= 4;
+               set_field(&ctl->i2sctl, I2SCTL_EA << (idx*8), 0);
+               ctl->dirty.bf.i2soctl |= (0x1 << idx);
+       }
+       return 0;
+}
+
+static int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf)
+{
+       struct daio_mgr_ctrl_blk *ctl = blk;
+
+       if (idx < 4) {
+               /* S/PDIF output */
+               switch ((conf & 0x7)) {
+               case 0:
+                       set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 3);
+                       break; /* CDIF */
+               case 1:
+                       set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 0);
+                       break;
+               case 2:
+                       set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 1);
+                       break;
+               case 4:
+                       set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 2);
+                       break;
+               default:
+                       break;
+               }
+               set_field(&ctl->spoctl, SPOCTL_LIV << (idx*8),
+                         (conf >> 4) & 0x1); /* Non-audio */
+               set_field(&ctl->spoctl, SPOCTL_RIV << (idx*8),
+                         (conf >> 4) & 0x1); /* Non-audio */
+               set_field(&ctl->spoctl, SPOCTL_OS << (idx*8),
+                         ((conf >> 3) & 0x1) ? 2 : 2); /* Raw */
+
+               ctl->dirty.bf.spoctl |= (0x1 << idx);
+       } else {
+               /* I2S output */
+               /*idx %= 4; */
+       }
+       return 0;
+}
+
+static int daio_mgr_set_imaparc(void *blk, unsigned int slot)
+{
+       struct daio_mgr_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->daoimap.aim, AIM_ARC, slot);
+       ctl->dirty.bf.daoimap = 1;
+       return 0;
+}
+
+static int daio_mgr_set_imapnxt(void *blk, unsigned int next)
+{
+       struct daio_mgr_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->daoimap.aim, AIM_NXT, next);
+       ctl->dirty.bf.daoimap = 1;
+       return 0;
+}
+
+static int daio_mgr_set_imapaddr(void *blk, unsigned int addr)
+{
+       struct daio_mgr_ctrl_blk *ctl = blk;
+
+       ctl->daoimap.idx = addr;
+       ctl->dirty.bf.daoimap = 1;
+       return 0;
+}
+
+static int daio_mgr_commit_write(struct hw *hw, void *blk)
+{
+       struct daio_mgr_ctrl_blk *ctl = blk;
+       int i;
+
+       if (ctl->dirty.bf.i2sictl || ctl->dirty.bf.i2soctl) {
+               for (i = 0; i < 4; i++) {
+                       if ((ctl->dirty.bf.i2sictl & (0x1 << i)))
+                               ctl->dirty.bf.i2sictl &= ~(0x1 << i);
+
+                       if ((ctl->dirty.bf.i2soctl & (0x1 << i)))
+                               ctl->dirty.bf.i2soctl &= ~(0x1 << i);
+               }
+               hw_write_20kx(hw, I2SCTL, ctl->i2sctl);
+               mdelay(1);
+       }
+       if (ctl->dirty.bf.spoctl) {
+               for (i = 0; i < 4; i++) {
+                       if ((ctl->dirty.bf.spoctl & (0x1 << i)))
+                               ctl->dirty.bf.spoctl &= ~(0x1 << i);
+               }
+               hw_write_20kx(hw, SPOCTL, ctl->spoctl);
+               mdelay(1);
+       }
+       if (ctl->dirty.bf.spictl) {
+               for (i = 0; i < 4; i++) {
+                       if ((ctl->dirty.bf.spictl & (0x1 << i)))
+                               ctl->dirty.bf.spictl &= ~(0x1 << i);
+               }
+               hw_write_20kx(hw, SPICTL, ctl->spictl);
+               mdelay(1);
+       }
+       if (ctl->dirty.bf.daoimap) {
+               hw_write_20kx(hw, DAOIMAP+ctl->daoimap.idx*4,
+                                       ctl->daoimap.aim);
+               ctl->dirty.bf.daoimap = 0;
+       }
+
+       return 0;
+}
+
+static int daio_mgr_get_ctrl_blk(struct hw *hw, void **rblk)
+{
+       struct daio_mgr_ctrl_blk *blk;
+
+       *rblk = NULL;
+       blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+       if (NULL == blk)
+               return -ENOMEM;
+
+       blk->i2sctl = hw_read_20kx(hw, I2SCTL);
+       blk->spoctl = hw_read_20kx(hw, SPOCTL);
+       blk->spictl = hw_read_20kx(hw, SPICTL);
+
+       *rblk = blk;
+
+       return 0;
+}
+
+static int daio_mgr_put_ctrl_blk(void *blk)
+{
+       kfree((struct daio_mgr_ctrl_blk *)blk);
+
+       return 0;
+}
+
+/* Timer interrupt */
+static int set_timer_irq(struct hw *hw, int enable)
+{
+       hw_write_20kx(hw, GIE, enable ? IT_INT : 0);
+       return 0;
+}
+
+static int set_timer_tick(struct hw *hw, unsigned int ticks)
+{
+       if (ticks)
+               ticks |= TIMR_IE | TIMR_IP;
+       hw_write_20kx(hw, TIMR, ticks);
+       return 0;
+}
+
+static unsigned int get_wc(struct hw *hw)
+{
+       return hw_read_20kx(hw, WC);
+}
+
+/* Card hardware initialization block */
+struct dac_conf {
+       unsigned int msr; /* master sample rate in rsrs */
+};
+
+struct adc_conf {
+       unsigned int msr;       /* master sample rate in rsrs */
+       unsigned char input;    /* the input source of ADC */
+       unsigned char mic20db;  /* boost mic by 20db if input is microphone */
+};
+
+struct daio_conf {
+       unsigned int msr; /* master sample rate in rsrs */
+};
+
+struct trn_conf {
+       unsigned long vm_pgt_phys;
+};
+
+static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
+{
+       u32 i2sorg;
+       u32 spdorg;
+
+       /* Read I2S CTL.  Keep original value. */
+       /*i2sorg = hw_read_20kx(hw, I2SCTL);*/
+       i2sorg = 0x94040404; /* enable all audio out and I2S-D input */
+       /* Program I2S with proper master sample rate and enable
+        * the correct I2S channel. */
+       i2sorg &= 0xfffffffc;
+
+       /* Enable S/PDIF-out-A in fixed 24-bit data
+        * format and default to 48kHz. */
+       /* Disable all before doing any changes. */
+       hw_write_20kx(hw, SPOCTL, 0x0);
+       spdorg = 0x05;
+
+       switch (info->msr) {
+       case 1:
+               i2sorg |= 1;
+               spdorg |= (0x0 << 6);
+               break;
+       case 2:
+               i2sorg |= 2;
+               spdorg |= (0x1 << 6);
+               break;
+       case 4:
+               i2sorg |= 3;
+               spdorg |= (0x2 << 6);
+               break;
+       default:
+               i2sorg |= 1;
+               break;
+       }
+
+       hw_write_20kx(hw, I2SCTL, i2sorg);
+       hw_write_20kx(hw, SPOCTL, spdorg);
+
+       /* Enable S/PDIF-in-A in fixed 24-bit data format. */
+       /* Disable all before doing any changes. */
+       hw_write_20kx(hw, SPICTL, 0x0);
+       mdelay(1);
+       spdorg = 0x0a0a0a0a;
+       hw_write_20kx(hw, SPICTL, spdorg);
+       mdelay(1);
+
+       return 0;
+}
+
+/* TRANSPORT operations */
+static int hw_trn_init(struct hw *hw, const struct trn_conf *info)
+{
+       u32 trnctl;
+       u32 ptp_phys_low, ptp_phys_high;
+
+       /* Set up device page table */
+       if ((~0UL) == info->vm_pgt_phys) {
+               printk(KERN_ERR "Wrong device page table page address!\n");
+               return -1;
+       }
+
+       trnctl = 0x13;  /* 32-bit, 4k-size page */
+       ptp_phys_low = (u32)info->vm_pgt_phys;
+       ptp_phys_high = upper_32_bits(info->vm_pgt_phys);
+       if (sizeof(void *) == 8) /* 64bit address */
+               trnctl |= (1 << 2);
+#if 0 /* Only 4k h/w pages for simplicitiy */
+#if PAGE_SIZE == 8192
+       trnctl |= (1<<5);
+#endif
+#endif
+       hw_write_20kx(hw, PTPALX, ptp_phys_low);
+       hw_write_20kx(hw, PTPAHX, ptp_phys_high);
+       hw_write_20kx(hw, TRNCTL, trnctl);
+       hw_write_20kx(hw, TRNIS, 0x200c01); /* realy needed? */
+
+       return 0;
+}
+
+/* Card initialization */
+#define GCTL_EAC       0x00000001
+#define GCTL_EAI       0x00000002
+#define GCTL_BEP       0x00000004
+#define GCTL_BES       0x00000008
+#define GCTL_DSP       0x00000010
+#define GCTL_DBP       0x00000020
+#define GCTL_ABP       0x00000040
+#define GCTL_TBP       0x00000080
+#define GCTL_SBP       0x00000100
+#define GCTL_FBP       0x00000200
+#define GCTL_XA                0x00000400
+#define GCTL_ET                0x00000800
+#define GCTL_PR                0x00001000
+#define GCTL_MRL       0x00002000
+#define GCTL_SDE       0x00004000
+#define GCTL_SDI       0x00008000
+#define GCTL_SM                0x00010000
+#define GCTL_SR                0x00020000
+#define GCTL_SD                0x00040000
+#define GCTL_SE                0x00080000
+#define GCTL_AID       0x00100000
+
+static int hw_pll_init(struct hw *hw, unsigned int rsr)
+{
+       unsigned int pllctl;
+       int i;
+
+       pllctl = (48000 == rsr) ? 0x1480a001 : 0x1480a731;
+       for (i = 0; i < 3; i++) {
+               if (hw_read_20kx(hw, PLLCTL) == pllctl)
+                       break;
+
+               hw_write_20kx(hw, PLLCTL, pllctl);
+               mdelay(40);
+       }
+       if (i >= 3) {
+               printk(KERN_ALERT "PLL initialization failed!!!\n");
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static int hw_auto_init(struct hw *hw)
+{
+       unsigned int gctl;
+       int i;
+
+       gctl = hw_read_20kx(hw, GCTL);
+       set_field(&gctl, GCTL_EAI, 0);
+       hw_write_20kx(hw, GCTL, gctl);
+       set_field(&gctl, GCTL_EAI, 1);
+       hw_write_20kx(hw, GCTL, gctl);
+       mdelay(10);
+       for (i = 0; i < 400000; i++) {
+               gctl = hw_read_20kx(hw, GCTL);
+               if (get_field(gctl, GCTL_AID))
+                       break;
+       }
+       if (!get_field(gctl, GCTL_AID)) {
+               printk(KERN_ALERT "Card Auto-init failed!!!\n");
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static int i2c_unlock(struct hw *hw)
+{
+       if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
+               return 0;
+
+       hw_write_pci(hw, 0xcc, 0x8c);
+       hw_write_pci(hw, 0xcc, 0x0e);
+       if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
+               return 0;
+
+       hw_write_pci(hw, 0xcc, 0xee);
+       hw_write_pci(hw, 0xcc, 0xaa);
+       if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
+               return 0;
+
+       return -1;
+}
+
+static void i2c_lock(struct hw *hw)
+{
+       if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa)
+               hw_write_pci(hw, 0xcc, 0x00);
+}
+
+static void i2c_write(struct hw *hw, u32 device, u32 addr, u32 data)
+{
+       unsigned int ret;
+
+       do {
+               ret = hw_read_pci(hw, 0xEC);
+       } while (!(ret & 0x800000));
+       hw_write_pci(hw, 0xE0, device);
+       hw_write_pci(hw, 0xE4, (data << 8) | (addr & 0xff));
+}
+
+/* DAC operations */
+
+static int hw_reset_dac(struct hw *hw)
+{
+       u32 i;
+       u16 gpioorg;
+       unsigned int ret;
+
+       if (i2c_unlock(hw))
+               return -1;
+
+       do {
+               ret = hw_read_pci(hw, 0xEC);
+       } while (!(ret & 0x800000));
+       hw_write_pci(hw, 0xEC, 0x05);  /* write to i2c status control */
+
+       /* To be effective, need to reset the DAC twice. */
+       for (i = 0; i < 2;  i++) {
+               /* set gpio */
+               mdelay(100);
+               gpioorg = (u16)hw_read_20kx(hw, GPIO);
+               gpioorg &= 0xfffd;
+               hw_write_20kx(hw, GPIO, gpioorg);
+               mdelay(1);
+               hw_write_20kx(hw, GPIO, gpioorg | 0x2);
+       }
+
+       i2c_write(hw, 0x00180080, 0x01, 0x80);
+       i2c_write(hw, 0x00180080, 0x02, 0x10);
+
+       i2c_lock(hw);
+
+       return 0;
+}
+
+static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
+{
+       u32 data;
+       u16 gpioorg;
+       unsigned int ret;
+
+       if (hw->model == CTSB055X) {
+               /* SB055x, unmute outputs */
+               gpioorg = (u16)hw_read_20kx(hw, GPIO);
+               gpioorg &= 0xffbf;      /* set GPIO6 to low */
+               gpioorg |= 2;           /* set GPIO1 to high */
+               hw_write_20kx(hw, GPIO, gpioorg);
+               return 0;
+       }
+
+       /* mute outputs */
+       gpioorg = (u16)hw_read_20kx(hw, GPIO);
+       gpioorg &= 0xffbf;
+       hw_write_20kx(hw, GPIO, gpioorg);
+
+       hw_reset_dac(hw);
+
+       if (i2c_unlock(hw))
+               return -1;
+
+       hw_write_pci(hw, 0xEC, 0x05);  /* write to i2c status control */
+       do {
+               ret = hw_read_pci(hw, 0xEC);
+       } while (!(ret & 0x800000));
+
+       switch (info->msr) {
+       case 1:
+               data = 0x24;
+               break;
+       case 2:
+               data = 0x25;
+               break;
+       case 4:
+               data = 0x26;
+               break;
+       default:
+               data = 0x24;
+               break;
+       }
+
+       i2c_write(hw, 0x00180080, 0x06, data);
+       i2c_write(hw, 0x00180080, 0x09, data);
+       i2c_write(hw, 0x00180080, 0x0c, data);
+       i2c_write(hw, 0x00180080, 0x0f, data);
+
+       i2c_lock(hw);
+
+       /* unmute outputs */
+       gpioorg = (u16)hw_read_20kx(hw, GPIO);
+       gpioorg = gpioorg | 0x40;
+       hw_write_20kx(hw, GPIO, gpioorg);
+
+       return 0;
+}
+
+/* ADC operations */
+
+static int is_adc_input_selected_SB055x(struct hw *hw, enum ADCSRC type)
+{
+       return 0;
+}
+
+static int is_adc_input_selected_SBx(struct hw *hw, enum ADCSRC type)
+{
+       u32 data;
+
+       data = hw_read_20kx(hw, GPIO);
+       switch (type) {
+       case ADC_MICIN:
+               data = ((data & (0x1<<7)) && (data & (0x1<<8)));
+               break;
+       case ADC_LINEIN:
+               data = (!(data & (0x1<<7)) && (data & (0x1<<8)));
+               break;
+       case ADC_NONE: /* Digital I/O */
+               data = (!(data & (0x1<<8)));
+               break;
+       default:
+               data = 0;
+       }
+       return data;
+}
+
+static int is_adc_input_selected_hendrix(struct hw *hw, enum ADCSRC type)
+{
+       u32 data;
+
+       data = hw_read_20kx(hw, GPIO);
+       switch (type) {
+       case ADC_MICIN:
+               data = (data & (0x1 << 7)) ? 1 : 0;
+               break;
+       case ADC_LINEIN:
+               data = (data & (0x1 << 7)) ? 0 : 1;
+               break;
+       default:
+               data = 0;
+       }
+       return data;
+}
+
+static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type)
+{
+       switch (hw->model) {
+       case CTSB055X:
+               return is_adc_input_selected_SB055x(hw, type);
+       case CTSB073X:
+               return is_adc_input_selected_hendrix(hw, type);
+       case CTUAA:
+               return is_adc_input_selected_hendrix(hw, type);
+       default:
+               return is_adc_input_selected_SBx(hw, type);
+       }
+}
+
+static int
+adc_input_select_SB055x(struct hw *hw, enum ADCSRC type, unsigned char boost)
+{
+       u32 data;
+
+       /*
+        * check and set the following GPIO bits accordingly
+        * ADC_Gain             = GPIO2
+        * DRM_off              = GPIO3
+        * Mic_Pwr_on           = GPIO7
+        * Digital_IO_Sel       = GPIO8
+        * Mic_Sw               = GPIO9
+        * Aux/MicLine_Sw       = GPIO12
+        */
+       data = hw_read_20kx(hw, GPIO);
+       data &= 0xec73;
+       switch (type) {
+       case ADC_MICIN:
+               data |= (0x1<<7) | (0x1<<8) | (0x1<<9) ;
+               data |= boost ? (0x1<<2) : 0;
+               break;
+       case ADC_LINEIN:
+               data |= (0x1<<8);
+               break;
+       case ADC_AUX:
+               data |= (0x1<<8) | (0x1<<12);
+               break;
+       case ADC_NONE:
+               data |= (0x1<<12);  /* set to digital */
+               break;
+       default:
+               return -1;
+       }
+
+       hw_write_20kx(hw, GPIO, data);
+
+       return 0;
+}
+
+
+static int
+adc_input_select_SBx(struct hw *hw, enum ADCSRC type, unsigned char boost)
+{
+       u32 data;
+       u32 i2c_data;
+       unsigned int ret;
+
+       if (i2c_unlock(hw))
+               return -1;
+
+       do {
+               ret = hw_read_pci(hw, 0xEC);
+       } while (!(ret & 0x800000)); /* i2c ready poll */
+       /* set i2c access mode as Direct Control */
+       hw_write_pci(hw, 0xEC, 0x05);
+
+       data = hw_read_20kx(hw, GPIO);
+       switch (type) {
+       case ADC_MICIN:
+               data |= ((0x1 << 7) | (0x1 << 8));
+               i2c_data = 0x1;  /* Mic-in */
+               break;
+       case ADC_LINEIN:
+               data &= ~(0x1 << 7);
+               data |= (0x1 << 8);
+               i2c_data = 0x2; /* Line-in */
+               break;
+       case ADC_NONE:
+               data &= ~(0x1 << 8);
+               i2c_data = 0x0; /* set to Digital */
+               break;
+       default:
+               i2c_lock(hw);
+               return -1;
+       }
+       hw_write_20kx(hw, GPIO, data);
+       i2c_write(hw, 0x001a0080, 0x2a, i2c_data);
+       if (boost) {
+               i2c_write(hw, 0x001a0080, 0x1c, 0xe7); /* +12dB boost */
+               i2c_write(hw, 0x001a0080, 0x1e, 0xe7); /* +12dB boost */
+       } else {
+               i2c_write(hw, 0x001a0080, 0x1c, 0xcf); /* No boost */
+               i2c_write(hw, 0x001a0080, 0x1e, 0xcf); /* No boost */
+       }
+
+       i2c_lock(hw);
+
+       return 0;
+}
+
+static int
+adc_input_select_hendrix(struct hw *hw, enum ADCSRC type, unsigned char boost)
+{
+       u32 data;
+       u32 i2c_data;
+       unsigned int ret;
+
+       if (i2c_unlock(hw))
+               return -1;
+
+       do {
+               ret = hw_read_pci(hw, 0xEC);
+       } while (!(ret & 0x800000)); /* i2c ready poll */
+       /* set i2c access mode as Direct Control */
+       hw_write_pci(hw, 0xEC, 0x05);
+
+       data = hw_read_20kx(hw, GPIO);
+       switch (type) {
+       case ADC_MICIN:
+               data |= (0x1 << 7);
+               i2c_data = 0x1;  /* Mic-in */
+               break;
+       case ADC_LINEIN:
+               data &= ~(0x1 << 7);
+               i2c_data = 0x2; /* Line-in */
+               break;
+       default:
+               i2c_lock(hw);
+               return -1;
+       }
+       hw_write_20kx(hw, GPIO, data);
+       i2c_write(hw, 0x001a0080, 0x2a, i2c_data);
+       if (boost) {
+               i2c_write(hw, 0x001a0080, 0x1c, 0xe7); /* +12dB boost */
+               i2c_write(hw, 0x001a0080, 0x1e, 0xe7); /* +12dB boost */
+       } else {
+               i2c_write(hw, 0x001a0080, 0x1c, 0xcf); /* No boost */
+               i2c_write(hw, 0x001a0080, 0x1e, 0xcf); /* No boost */
+       }
+
+       i2c_lock(hw);
+
+       return 0;
+}
+
+static int hw_adc_input_select(struct hw *hw, enum ADCSRC type)
+{
+       int state = type == ADC_MICIN;
+
+       switch (hw->model) {
+       case CTSB055X:
+               return adc_input_select_SB055x(hw, type, state);
+       case CTSB073X:
+               return adc_input_select_hendrix(hw, type, state);
+       case CTUAA:
+               return adc_input_select_hendrix(hw, type, state);
+       default:
+               return adc_input_select_SBx(hw, type, state);
+       }
+}
+
+static int adc_init_SB055x(struct hw *hw, int input, int mic20db)
+{
+       return adc_input_select_SB055x(hw, input, mic20db);
+}
+
+static int adc_init_SBx(struct hw *hw, int input, int mic20db)
+{
+       u16 gpioorg;
+       u16 input_source;
+       u32 adcdata;
+       unsigned int ret;
+
+       input_source = 0x100;  /* default to analog */
+       switch (input) {
+       case ADC_MICIN:
+               adcdata = 0x1;
+               input_source = 0x180;  /* set GPIO7 to select Mic */
+               break;
+       case ADC_LINEIN:
+               adcdata = 0x2;
+               break;
+       case ADC_VIDEO:
+               adcdata = 0x4;
+               break;
+       case ADC_AUX:
+               adcdata = 0x8;
+               break;
+       case ADC_NONE:
+               adcdata = 0x0;
+               input_source = 0x0;  /* set to Digital */
+               break;
+       default:
+               adcdata = 0x0;
+               break;
+       }
+
+       if (i2c_unlock(hw))
+               return -1;
+
+       do {
+               ret = hw_read_pci(hw, 0xEC);
+       } while (!(ret & 0x800000)); /* i2c ready poll */
+       hw_write_pci(hw, 0xEC, 0x05);  /* write to i2c status control */
+
+       i2c_write(hw, 0x001a0080, 0x0e, 0x08);
+       i2c_write(hw, 0x001a0080, 0x18, 0x0a);
+       i2c_write(hw, 0x001a0080, 0x28, 0x86);
+       i2c_write(hw, 0x001a0080, 0x2a, adcdata);
+
+       if (mic20db) {
+               i2c_write(hw, 0x001a0080, 0x1c, 0xf7);
+               i2c_write(hw, 0x001a0080, 0x1e, 0xf7);
+       } else {
+               i2c_write(hw, 0x001a0080, 0x1c, 0xcf);
+               i2c_write(hw, 0x001a0080, 0x1e, 0xcf);
+       }
+
+       if (!(hw_read_20kx(hw, ID0) & 0x100))
+               i2c_write(hw, 0x001a0080, 0x16, 0x26);
+
+       i2c_lock(hw);
+
+       gpioorg = (u16)hw_read_20kx(hw,  GPIO);
+       gpioorg &= 0xfe7f;
+       gpioorg |= input_source;
+       hw_write_20kx(hw, GPIO, gpioorg);
+
+       return 0;
+}
+
+static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
+{
+       if (hw->model == CTSB055X)
+               return adc_init_SB055x(hw, info->input, info->mic20db);
+       else
+               return adc_init_SBx(hw, info->input, info->mic20db);
+}
+
+static int hw_have_digit_io_switch(struct hw *hw)
+{
+       /* SB073x and Vista compatible cards have no digit IO switch */
+       return !(hw->model == CTSB073X || hw->model == CTUAA);
+}
+
+#define CTLBITS(a, b, c, d)    (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
+
+#define UAA_CFG_PWRSTATUS      0x44
+#define UAA_CFG_SPACE_FLAG     0xA0
+#define UAA_CORE_CHANGE                0x3FFC
+static int uaa_to_xfi(struct pci_dev *pci)
+{
+       unsigned int bar0, bar1, bar2, bar3, bar4, bar5;
+       unsigned int cmd, irq, cl_size, l_timer, pwr;
+       unsigned int is_uaa;
+       unsigned int data[4] = {0};
+       unsigned int io_base;
+       void *mem_base;
+       int i;
+       const u32 CTLX = CTLBITS('C', 'T', 'L', 'X');
+       const u32 CTL_ = CTLBITS('C', 'T', 'L', '-');
+       const u32 CTLF = CTLBITS('C', 'T', 'L', 'F');
+       const u32 CTLi = CTLBITS('C', 'T', 'L', 'i');
+       const u32 CTLA = CTLBITS('C', 'T', 'L', 'A');
+       const u32 CTLZ = CTLBITS('C', 'T', 'L', 'Z');
+       const u32 CTLL = CTLBITS('C', 'T', 'L', 'L');
+
+       /* By default, Hendrix card UAA Bar0 should be using memory... */
+       io_base = pci_resource_start(pci, 0);
+       mem_base = ioremap(io_base, pci_resource_len(pci, 0));
+       if (NULL == mem_base)
+               return -ENOENT;
+
+       /* Read current mode from Mode Change Register */
+       for (i = 0; i < 4; i++)
+               data[i] = readl(mem_base + UAA_CORE_CHANGE);
+
+       /* Determine current mode... */
+       if (data[0] == CTLA) {
+               is_uaa = ((data[1] == CTLZ && data[2] == CTLL
+                         && data[3] == CTLA) || (data[1] == CTLA
+                         && data[2] == CTLZ && data[3] == CTLL));
+       } else if (data[0] == CTLZ) {
+               is_uaa = (data[1] == CTLL
+                               && data[2] == CTLA && data[3] == CTLA);
+       } else if (data[0] == CTLL) {
+               is_uaa = (data[1] == CTLA
+                               && data[2] == CTLA && data[3] == CTLZ);
+       } else {
+               is_uaa = 0;
+       }
+
+       if (!is_uaa) {
+               /* Not in UAA mode currently. Return directly. */
+               iounmap(mem_base);
+               return 0;
+       }
+
+       pci_read_config_dword(pci, PCI_BASE_ADDRESS_0, &bar0);
+       pci_read_config_dword(pci, PCI_BASE_ADDRESS_1, &bar1);
+       pci_read_config_dword(pci, PCI_BASE_ADDRESS_2, &bar2);
+       pci_read_config_dword(pci, PCI_BASE_ADDRESS_3, &bar3);
+       pci_read_config_dword(pci, PCI_BASE_ADDRESS_4, &bar4);
+       pci_read_config_dword(pci, PCI_BASE_ADDRESS_5, &bar5);
+       pci_read_config_dword(pci, PCI_INTERRUPT_LINE, &irq);
+       pci_read_config_dword(pci, PCI_CACHE_LINE_SIZE, &cl_size);
+       pci_read_config_dword(pci, PCI_LATENCY_TIMER, &l_timer);
+       pci_read_config_dword(pci, UAA_CFG_PWRSTATUS, &pwr);
+       pci_read_config_dword(pci, PCI_COMMAND, &cmd);
+
+       /* Set up X-Fi core PCI configuration space. */
+       /* Switch to X-Fi config space with BAR0 exposed. */
+       pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x87654321);
+       /* Copy UAA's BAR5 into X-Fi BAR0 */
+       pci_write_config_dword(pci, PCI_BASE_ADDRESS_0, bar5);
+       /* Switch to X-Fi config space without BAR0 exposed. */
+       pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x12345678);
+       pci_write_config_dword(pci, PCI_BASE_ADDRESS_1, bar1);
+       pci_write_config_dword(pci, PCI_BASE_ADDRESS_2, bar2);
+       pci_write_config_dword(pci, PCI_BASE_ADDRESS_3, bar3);
+       pci_write_config_dword(pci, PCI_BASE_ADDRESS_4, bar4);
+       pci_write_config_dword(pci, PCI_INTERRUPT_LINE, irq);
+       pci_write_config_dword(pci, PCI_CACHE_LINE_SIZE, cl_size);
+       pci_write_config_dword(pci, PCI_LATENCY_TIMER, l_timer);
+       pci_write_config_dword(pci, UAA_CFG_PWRSTATUS, pwr);
+       pci_write_config_dword(pci, PCI_COMMAND, cmd);
+
+       /* Switch to X-Fi mode */
+       writel(CTLX, (mem_base + UAA_CORE_CHANGE));
+       writel(CTL_, (mem_base + UAA_CORE_CHANGE));
+       writel(CTLF, (mem_base + UAA_CORE_CHANGE));
+       writel(CTLi, (mem_base + UAA_CORE_CHANGE));
+
+       iounmap(mem_base);
+
+       return 0;
+}
+
+static irqreturn_t ct_20k1_interrupt(int irq, void *dev_id)
+{
+       struct hw *hw = dev_id;
+       unsigned int status;
+
+       status = hw_read_20kx(hw, GIP);
+       if (!status)
+               return IRQ_NONE;
+
+       if (hw->irq_callback)
+               hw->irq_callback(hw->irq_callback_data, status);
+
+       hw_write_20kx(hw, GIP, status);
+       return IRQ_HANDLED;
+}
+
+static int hw_card_start(struct hw *hw)
+{
+       int err;
+       struct pci_dev *pci = hw->pci;
+
+       err = pci_enable_device(pci);
+       if (err < 0)
+               return err;
+
+       /* Set DMA transfer mask */
+       if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 ||
+           pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) {
+               printk(KERN_ERR "architecture does not support PCI "
+                               "busmaster DMA with mask 0x%llx\n",
+                      CT_XFI_DMA_MASK);
+               err = -ENXIO;
+               goto error1;
+       }
+
+       err = pci_request_regions(pci, "XFi");
+       if (err < 0)
+               goto error1;
+
+       /* Switch to X-Fi mode from UAA mode if neeeded */
+       if (hw->model == CTUAA) {
+               err = uaa_to_xfi(pci);
+               if (err)
+                       goto error2;
+
+               hw->io_base = pci_resource_start(pci, 5);
+       } else {
+               hw->io_base = pci_resource_start(pci, 0);
+       }
+
+       err = request_irq(pci->irq, ct_20k1_interrupt, IRQF_SHARED,
+                         "ctxfi", hw);
+       if (err < 0) {
+               printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq);
+               goto error2;
+       }
+       hw->irq = pci->irq;
+
+       pci_set_master(pci);
+
+       return 0;
+
+error2:
+       pci_release_regions(pci);
+       hw->io_base = 0;
+error1:
+       pci_disable_device(pci);
+       return err;
+}
+
+static int hw_card_stop(struct hw *hw)
+{
+       /* TODO: Disable interrupt and so on... */
+       if (hw->irq >= 0)
+               synchronize_irq(hw->irq);
+       return 0;
+}
+
+static int hw_card_shutdown(struct hw *hw)
+{
+       if (hw->irq >= 0)
+               free_irq(hw->irq, hw);
+
+       hw->irq = -1;
+
+       if (NULL != ((void *)hw->mem_base))
+               iounmap((void *)hw->mem_base);
+
+       hw->mem_base = (unsigned long)NULL;
+
+       if (hw->io_base)
+               pci_release_regions(hw->pci);
+
+       hw->io_base = 0;
+
+       pci_disable_device(hw->pci);
+
+       return 0;
+}
+
+static int hw_card_init(struct hw *hw, struct card_conf *info)
+{
+       int err;
+       unsigned int gctl;
+       u32 data;
+       struct dac_conf dac_info = {0};
+       struct adc_conf adc_info = {0};
+       struct daio_conf daio_info = {0};
+       struct trn_conf trn_info = {0};
+
+       /* Get PCI io port base address and do Hendrix switch if needed. */
+       if (!hw->io_base) {
+               err = hw_card_start(hw);
+               if (err)
+                       return err;
+       }
+
+       /* PLL init */
+       err = hw_pll_init(hw, info->rsr);
+       if (err < 0)
+               return err;
+
+       /* kick off auto-init */
+       err = hw_auto_init(hw);
+       if (err < 0)
+               return err;
+
+       /* Enable audio ring */
+       gctl = hw_read_20kx(hw, GCTL);
+       set_field(&gctl, GCTL_EAC, 1);
+       set_field(&gctl, GCTL_DBP, 1);
+       set_field(&gctl, GCTL_TBP, 1);
+       set_field(&gctl, GCTL_FBP, 1);
+       set_field(&gctl, GCTL_ET, 1);
+       hw_write_20kx(hw, GCTL, gctl);
+       mdelay(10);
+
+       /* Reset all global pending interrupts */
+       hw_write_20kx(hw, GIE, 0);
+       /* Reset all SRC pending interrupts */
+       hw_write_20kx(hw, SRCIP, 0);
+       mdelay(30);
+
+       /* Detect the card ID and configure GPIO accordingly. */
+       switch (hw->model) {
+       case CTSB055X:
+               hw_write_20kx(hw, GPIOCTL, 0x13fe);
+               break;
+       case CTSB073X:
+               hw_write_20kx(hw, GPIOCTL, 0x00e6);
+               break;
+       case CTUAA:
+               hw_write_20kx(hw, GPIOCTL, 0x00c2);
+               break;
+       default:
+               hw_write_20kx(hw, GPIOCTL, 0x01e6);
+               break;
+       }
+
+       trn_info.vm_pgt_phys = info->vm_pgt_phys;
+       err = hw_trn_init(hw, &trn_info);
+       if (err < 0)
+               return err;
+
+       daio_info.msr = info->msr;
+       err = hw_daio_init(hw, &daio_info);
+       if (err < 0)
+               return err;
+
+       dac_info.msr = info->msr;
+       err = hw_dac_init(hw, &dac_info);
+       if (err < 0)
+               return err;
+
+       adc_info.msr = info->msr;
+       adc_info.input = ADC_LINEIN;
+       adc_info.mic20db = 0;
+       err = hw_adc_init(hw, &adc_info);
+       if (err < 0)
+               return err;
+
+       data = hw_read_20kx(hw, SRCMCTL);
+       data |= 0x1; /* Enables input from the audio ring */
+       hw_write_20kx(hw, SRCMCTL, data);
+
+       return 0;
+}
+
+static u32 hw_read_20kx(struct hw *hw, u32 reg)
+{
+       u32 value;
+       unsigned long flags;
+
+       spin_lock_irqsave(
+               &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
+       outl(reg, hw->io_base + 0x0);
+       value = inl(hw->io_base + 0x4);
+       spin_unlock_irqrestore(
+               &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
+
+       return value;
+}
+
+static void hw_write_20kx(struct hw *hw, u32 reg, u32 data)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(
+               &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
+       outl(reg, hw->io_base + 0x0);
+       outl(data, hw->io_base + 0x4);
+       spin_unlock_irqrestore(
+               &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
+
+}
+
+static u32 hw_read_pci(struct hw *hw, u32 reg)
+{
+       u32 value;
+       unsigned long flags;
+
+       spin_lock_irqsave(
+               &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
+       outl(reg, hw->io_base + 0x10);
+       value = inl(hw->io_base + 0x14);
+       spin_unlock_irqrestore(
+               &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
+
+       return value;
+}
+
+static void hw_write_pci(struct hw *hw, u32 reg, u32 data)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(
+               &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
+       outl(reg, hw->io_base + 0x10);
+       outl(data, hw->io_base + 0x14);
+       spin_unlock_irqrestore(
+               &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
+}
+
+static struct hw ct20k1_preset __devinitdata = {
+       .irq = -1,
+
+       .card_init = hw_card_init,
+       .card_stop = hw_card_stop,
+       .pll_init = hw_pll_init,
+       .is_adc_source_selected = hw_is_adc_input_selected,
+       .select_adc_source = hw_adc_input_select,
+       .have_digit_io_switch = hw_have_digit_io_switch,
+
+       .src_rsc_get_ctrl_blk = src_get_rsc_ctrl_blk,
+       .src_rsc_put_ctrl_blk = src_put_rsc_ctrl_blk,
+       .src_mgr_get_ctrl_blk = src_mgr_get_ctrl_blk,
+       .src_mgr_put_ctrl_blk = src_mgr_put_ctrl_blk,
+       .src_set_state = src_set_state,
+       .src_set_bm = src_set_bm,
+       .src_set_rsr = src_set_rsr,
+       .src_set_sf = src_set_sf,
+       .src_set_wr = src_set_wr,
+       .src_set_pm = src_set_pm,
+       .src_set_rom = src_set_rom,
+       .src_set_vo = src_set_vo,
+       .src_set_st = src_set_st,
+       .src_set_ie = src_set_ie,
+       .src_set_ilsz = src_set_ilsz,
+       .src_set_bp = src_set_bp,
+       .src_set_cisz = src_set_cisz,
+       .src_set_ca = src_set_ca,
+       .src_set_sa = src_set_sa,
+       .src_set_la = src_set_la,
+       .src_set_pitch = src_set_pitch,
+       .src_set_dirty = src_set_dirty,
+       .src_set_clear_zbufs = src_set_clear_zbufs,
+       .src_set_dirty_all = src_set_dirty_all,
+       .src_commit_write = src_commit_write,
+       .src_get_ca = src_get_ca,
+       .src_get_dirty = src_get_dirty,
+       .src_dirty_conj_mask = src_dirty_conj_mask,
+       .src_mgr_enbs_src = src_mgr_enbs_src,
+       .src_mgr_enb_src = src_mgr_enb_src,
+       .src_mgr_dsb_src = src_mgr_dsb_src,
+       .src_mgr_commit_write = src_mgr_commit_write,
+
+       .srcimp_mgr_get_ctrl_blk = srcimp_mgr_get_ctrl_blk,
+       .srcimp_mgr_put_ctrl_blk = srcimp_mgr_put_ctrl_blk,
+       .srcimp_mgr_set_imaparc = srcimp_mgr_set_imaparc,
+       .srcimp_mgr_set_imapuser = srcimp_mgr_set_imapuser,
+       .srcimp_mgr_set_imapnxt = srcimp_mgr_set_imapnxt,
+       .srcimp_mgr_set_imapaddr = srcimp_mgr_set_imapaddr,
+       .srcimp_mgr_commit_write = srcimp_mgr_commit_write,
+
+       .amixer_rsc_get_ctrl_blk = amixer_rsc_get_ctrl_blk,
+       .amixer_rsc_put_ctrl_blk = amixer_rsc_put_ctrl_blk,
+       .amixer_mgr_get_ctrl_blk = amixer_mgr_get_ctrl_blk,
+       .amixer_mgr_put_ctrl_blk = amixer_mgr_put_ctrl_blk,
+       .amixer_set_mode = amixer_set_mode,
+       .amixer_set_iv = amixer_set_iv,
+       .amixer_set_x = amixer_set_x,
+       .amixer_set_y = amixer_set_y,
+       .amixer_set_sadr = amixer_set_sadr,
+       .amixer_set_se = amixer_set_se,
+       .amixer_set_dirty = amixer_set_dirty,
+       .amixer_set_dirty_all = amixer_set_dirty_all,
+       .amixer_commit_write = amixer_commit_write,
+       .amixer_get_y = amixer_get_y,
+       .amixer_get_dirty = amixer_get_dirty,
+
+       .dai_get_ctrl_blk = dai_get_ctrl_blk,
+       .dai_put_ctrl_blk = dai_put_ctrl_blk,
+       .dai_srt_set_srco = dai_srt_set_srcr,
+       .dai_srt_set_srcm = dai_srt_set_srcl,
+       .dai_srt_set_rsr = dai_srt_set_rsr,
+       .dai_srt_set_drat = dai_srt_set_drat,
+       .dai_srt_set_ec = dai_srt_set_ec,
+       .dai_srt_set_et = dai_srt_set_et,
+       .dai_commit_write = dai_commit_write,
+
+       .dao_get_ctrl_blk = dao_get_ctrl_blk,
+       .dao_put_ctrl_blk = dao_put_ctrl_blk,
+       .dao_set_spos = dao_set_spos,
+       .dao_commit_write = dao_commit_write,
+       .dao_get_spos = dao_get_spos,
+
+       .daio_mgr_get_ctrl_blk = daio_mgr_get_ctrl_blk,
+       .daio_mgr_put_ctrl_blk = daio_mgr_put_ctrl_blk,
+       .daio_mgr_enb_dai = daio_mgr_enb_dai,
+       .daio_mgr_dsb_dai = daio_mgr_dsb_dai,
+       .daio_mgr_enb_dao = daio_mgr_enb_dao,
+       .daio_mgr_dsb_dao = daio_mgr_dsb_dao,
+       .daio_mgr_dao_init = daio_mgr_dao_init,
+       .daio_mgr_set_imaparc = daio_mgr_set_imaparc,
+       .daio_mgr_set_imapnxt = daio_mgr_set_imapnxt,
+       .daio_mgr_set_imapaddr = daio_mgr_set_imapaddr,
+       .daio_mgr_commit_write = daio_mgr_commit_write,
+
+       .set_timer_irq = set_timer_irq,
+       .set_timer_tick = set_timer_tick,
+       .get_wc = get_wc,
+};
+
+int __devinit create_20k1_hw_obj(struct hw **rhw)
+{
+       struct hw20k1 *hw20k1;
+
+       *rhw = NULL;
+       hw20k1 = kzalloc(sizeof(*hw20k1), GFP_KERNEL);
+       if (NULL == hw20k1)
+               return -ENOMEM;
+
+       spin_lock_init(&hw20k1->reg_20k1_lock);
+       spin_lock_init(&hw20k1->reg_pci_lock);
+
+       hw20k1->hw = ct20k1_preset;
+
+       *rhw = &hw20k1->hw;
+
+       return 0;
+}
+
+int destroy_20k1_hw_obj(struct hw *hw)
+{
+       if (hw->io_base)
+               hw_card_shutdown(hw);
+
+       kfree(container_of(hw, struct hw20k1, hw));
+       return 0;
+}
diff --git a/sound/pci/ctxfi/cthw20k1.h b/sound/pci/ctxfi/cthw20k1.h
new file mode 100644 (file)
index 0000000..02f72fb
--- /dev/null
@@ -0,0 +1,26 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File       cthw20k1.h
+ *
+ * @Brief
+ * This file contains the definition of hardware access methord.
+ *
+ * @Author     Liu Chun
+ * @Date       May 13 2008
+ *
+ */
+
+#ifndef CTHW20K1_H
+#define CTHW20K1_H
+
+#include "cthardware.h"
+
+int create_20k1_hw_obj(struct hw **rhw);
+int destroy_20k1_hw_obj(struct hw *hw);
+
+#endif /* CTHW20K1_H */
diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c
new file mode 100644 (file)
index 0000000..4493a51
--- /dev/null
@@ -0,0 +1,2137 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File       cthw20k2.c
+ *
+ * @Brief
+ * This file contains the implementation of hardware access methord for 20k2.
+ *
+ * @Author     Liu Chun
+ * @Date       May 14 2008
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include "cthw20k2.h"
+#include "ct20k2reg.h"
+
+#if BITS_PER_LONG == 32
+#define CT_XFI_DMA_MASK                DMA_BIT_MASK(32) /* 32 bit PTE */
+#else
+#define CT_XFI_DMA_MASK                DMA_BIT_MASK(64) /* 64 bit PTE */
+#endif
+
+struct hw20k2 {
+       struct hw hw;
+       /* for i2c */
+       unsigned char dev_id;
+       unsigned char addr_size;
+       unsigned char data_size;
+};
+
+static u32 hw_read_20kx(struct hw *hw, u32 reg);
+static void hw_write_20kx(struct hw *hw, u32 reg, u32 data);
+
+/*
+ * Type definition block.
+ * The layout of control structures can be directly applied on 20k2 chip.
+ */
+
+/*
+ * SRC control block definitions.
+ */
+
+/* SRC resource control block */
+#define SRCCTL_STATE   0x00000007
+#define SRCCTL_BM      0x00000008
+#define SRCCTL_RSR     0x00000030
+#define SRCCTL_SF      0x000001C0
+#define SRCCTL_WR      0x00000200
+#define SRCCTL_PM      0x00000400
+#define SRCCTL_ROM     0x00001800
+#define SRCCTL_VO      0x00002000
+#define SRCCTL_ST      0x00004000
+#define SRCCTL_IE      0x00008000
+#define SRCCTL_ILSZ    0x000F0000
+#define SRCCTL_BP      0x00100000
+
+#define SRCCCR_CISZ    0x000007FF
+#define SRCCCR_CWA     0x001FF800
+#define SRCCCR_D       0x00200000
+#define SRCCCR_RS      0x01C00000
+#define SRCCCR_NAL     0x3E000000
+#define SRCCCR_RA      0xC0000000
+
+#define SRCCA_CA       0x0FFFFFFF
+#define SRCCA_RS       0xE0000000
+
+#define SRCSA_SA       0x0FFFFFFF
+
+#define SRCLA_LA       0x0FFFFFFF
+
+/* Mixer Parameter Ring ram Low and Hight register.
+ * Fixed-point value in 8.24 format for parameter channel */
+#define MPRLH_PITCH    0xFFFFFFFF
+
+/* SRC resource register dirty flags */
+union src_dirty {
+       struct {
+               u16 ctl:1;
+               u16 ccr:1;
+               u16 sa:1;
+               u16 la:1;
+               u16 ca:1;
+               u16 mpr:1;
+               u16 czbfs:1;    /* Clear Z-Buffers */
+               u16 rsv:9;
+       } bf;
+       u16 data;
+};
+
+struct src_rsc_ctrl_blk {
+       unsigned int    ctl;
+       unsigned int    ccr;
+       unsigned int    ca;
+       unsigned int    sa;
+       unsigned int    la;
+       unsigned int    mpr;
+       union src_dirty dirty;
+};
+
+/* SRC manager control block */
+union src_mgr_dirty {
+       struct {
+               u16 enb0:1;
+               u16 enb1:1;
+               u16 enb2:1;
+               u16 enb3:1;
+               u16 enb4:1;
+               u16 enb5:1;
+               u16 enb6:1;
+               u16 enb7:1;
+               u16 enbsa:1;
+               u16 rsv:7;
+       } bf;
+       u16 data;
+};
+
+struct src_mgr_ctrl_blk {
+       unsigned int            enbsa;
+       unsigned int            enb[8];
+       union src_mgr_dirty     dirty;
+};
+
+/* SRCIMP manager control block */
+#define SRCAIM_ARC     0x00000FFF
+#define SRCAIM_NXT     0x00FF0000
+#define SRCAIM_SRC     0xFF000000
+
+struct srcimap {
+       unsigned int srcaim;
+       unsigned int idx;
+};
+
+/* SRCIMP manager register dirty flags */
+union srcimp_mgr_dirty {
+       struct {
+               u16 srcimap:1;
+               u16 rsv:15;
+       } bf;
+       u16 data;
+};
+
+struct srcimp_mgr_ctrl_blk {
+       struct srcimap          srcimap;
+       union srcimp_mgr_dirty  dirty;
+};
+
+/*
+ * Function implementation block.
+ */
+
+static int src_get_rsc_ctrl_blk(void **rblk)
+{
+       struct src_rsc_ctrl_blk *blk;
+
+       *rblk = NULL;
+       blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+       if (NULL == blk)
+               return -ENOMEM;
+
+       *rblk = blk;
+
+       return 0;
+}
+
+static int src_put_rsc_ctrl_blk(void *blk)
+{
+       kfree(blk);
+
+       return 0;
+}
+
+static int src_set_state(void *blk, unsigned int state)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ctl, SRCCTL_STATE, state);
+       ctl->dirty.bf.ctl = 1;
+       return 0;
+}
+
+static int src_set_bm(void *blk, unsigned int bm)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ctl, SRCCTL_BM, bm);
+       ctl->dirty.bf.ctl = 1;
+       return 0;
+}
+
+static int src_set_rsr(void *blk, unsigned int rsr)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ctl, SRCCTL_RSR, rsr);
+       ctl->dirty.bf.ctl = 1;
+       return 0;
+}
+
+static int src_set_sf(void *blk, unsigned int sf)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ctl, SRCCTL_SF, sf);
+       ctl->dirty.bf.ctl = 1;
+       return 0;
+}
+
+static int src_set_wr(void *blk, unsigned int wr)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ctl, SRCCTL_WR, wr);
+       ctl->dirty.bf.ctl = 1;
+       return 0;
+}
+
+static int src_set_pm(void *blk, unsigned int pm)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ctl, SRCCTL_PM, pm);
+       ctl->dirty.bf.ctl = 1;
+       return 0;
+}
+
+static int src_set_rom(void *blk, unsigned int rom)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ctl, SRCCTL_ROM, rom);
+       ctl->dirty.bf.ctl = 1;
+       return 0;
+}
+
+static int src_set_vo(void *blk, unsigned int vo)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ctl, SRCCTL_VO, vo);
+       ctl->dirty.bf.ctl = 1;
+       return 0;
+}
+
+static int src_set_st(void *blk, unsigned int st)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ctl, SRCCTL_ST, st);
+       ctl->dirty.bf.ctl = 1;
+       return 0;
+}
+
+static int src_set_ie(void *blk, unsigned int ie)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ctl, SRCCTL_IE, ie);
+       ctl->dirty.bf.ctl = 1;
+       return 0;
+}
+
+static int src_set_ilsz(void *blk, unsigned int ilsz)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ctl, SRCCTL_ILSZ, ilsz);
+       ctl->dirty.bf.ctl = 1;
+       return 0;
+}
+
+static int src_set_bp(void *blk, unsigned int bp)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ctl, SRCCTL_BP, bp);
+       ctl->dirty.bf.ctl = 1;
+       return 0;
+}
+
+static int src_set_cisz(void *blk, unsigned int cisz)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ccr, SRCCCR_CISZ, cisz);
+       ctl->dirty.bf.ccr = 1;
+       return 0;
+}
+
+static int src_set_ca(void *blk, unsigned int ca)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->ca, SRCCA_CA, ca);
+       ctl->dirty.bf.ca = 1;
+       return 0;
+}
+
+static int src_set_sa(void *blk, unsigned int sa)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->sa, SRCSA_SA, sa);
+       ctl->dirty.bf.sa = 1;
+       return 0;
+}
+
+static int src_set_la(void *blk, unsigned int la)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->la, SRCLA_LA, la);
+       ctl->dirty.bf.la = 1;
+       return 0;
+}
+
+static int src_set_pitch(void *blk, unsigned int pitch)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->mpr, MPRLH_PITCH, pitch);
+       ctl->dirty.bf.mpr = 1;
+       return 0;
+}
+
+static int src_set_clear_zbufs(void *blk, unsigned int clear)
+{
+       ((struct src_rsc_ctrl_blk *)blk)->dirty.bf.czbfs = (clear ? 1 : 0);
+       return 0;
+}
+
+static int src_set_dirty(void *blk, unsigned int flags)
+{
+       ((struct src_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff);
+       return 0;
+}
+
+static int src_set_dirty_all(void *blk)
+{
+       ((struct src_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0);
+       return 0;
+}
+
+#define AR_SLOT_SIZE           4096
+#define AR_SLOT_BLOCK_SIZE     16
+#define AR_PTS_PITCH           6
+#define AR_PARAM_SRC_OFFSET    0x60
+
+static unsigned int src_param_pitch_mixer(unsigned int src_idx)
+{
+       return ((src_idx << 4) + AR_PTS_PITCH + AR_SLOT_SIZE
+                       - AR_PARAM_SRC_OFFSET) % AR_SLOT_SIZE;
+
+}
+
+static int src_commit_write(struct hw *hw, unsigned int idx, void *blk)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+       int i;
+
+       if (ctl->dirty.bf.czbfs) {
+               /* Clear Z-Buffer registers */
+               for (i = 0; i < 8; i++)
+                       hw_write_20kx(hw, SRC_UPZ+idx*0x100+i*0x4, 0);
+
+               for (i = 0; i < 4; i++)
+                       hw_write_20kx(hw, SRC_DN0Z+idx*0x100+i*0x4, 0);
+
+               for (i = 0; i < 8; i++)
+                       hw_write_20kx(hw, SRC_DN1Z+idx*0x100+i*0x4, 0);
+
+               ctl->dirty.bf.czbfs = 0;
+       }
+       if (ctl->dirty.bf.mpr) {
+               /* Take the parameter mixer resource in the same group as that
+                * the idx src is in for simplicity. Unlike src, all conjugate
+                * parameter mixer resources must be programmed for
+                * corresponding conjugate src resources. */
+               unsigned int pm_idx = src_param_pitch_mixer(idx);
+               hw_write_20kx(hw, MIXER_PRING_LO_HI+4*pm_idx, ctl->mpr);
+               hw_write_20kx(hw, MIXER_PMOPLO+8*pm_idx, 0x3);
+               hw_write_20kx(hw, MIXER_PMOPHI+8*pm_idx, 0x0);
+               ctl->dirty.bf.mpr = 0;
+       }
+       if (ctl->dirty.bf.sa) {
+               hw_write_20kx(hw, SRC_SA+idx*0x100, ctl->sa);
+               ctl->dirty.bf.sa = 0;
+       }
+       if (ctl->dirty.bf.la) {
+               hw_write_20kx(hw, SRC_LA+idx*0x100, ctl->la);
+               ctl->dirty.bf.la = 0;
+       }
+       if (ctl->dirty.bf.ca) {
+               hw_write_20kx(hw, SRC_CA+idx*0x100, ctl->ca);
+               ctl->dirty.bf.ca = 0;
+       }
+
+       /* Write srccf register */
+       hw_write_20kx(hw, SRC_CF+idx*0x100, 0x0);
+
+       if (ctl->dirty.bf.ccr) {
+               hw_write_20kx(hw, SRC_CCR+idx*0x100, ctl->ccr);
+               ctl->dirty.bf.ccr = 0;
+       }
+       if (ctl->dirty.bf.ctl) {
+               hw_write_20kx(hw, SRC_CTL+idx*0x100, ctl->ctl);
+               ctl->dirty.bf.ctl = 0;
+       }
+
+       return 0;
+}
+
+static int src_get_ca(struct hw *hw, unsigned int idx, void *blk)
+{
+       struct src_rsc_ctrl_blk *ctl = blk;
+
+       ctl->ca = hw_read_20kx(hw, SRC_CA+idx*0x100);
+       ctl->dirty.bf.ca = 0;
+
+       return get_field(ctl->ca, SRCCA_CA);
+}
+
+static unsigned int src_get_dirty(void *blk)
+{
+       return ((struct src_rsc_ctrl_blk *)blk)->dirty.data;
+}
+
+static unsigned int src_dirty_conj_mask(void)
+{
+       return 0x20;
+}
+
+static int src_mgr_enbs_src(void *blk, unsigned int idx)
+{
+       ((struct src_mgr_ctrl_blk *)blk)->enbsa |= (0x1 << ((idx%128)/4));
+       ((struct src_mgr_ctrl_blk *)blk)->dirty.bf.enbsa = 1;
+       ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32));
+       return 0;
+}
+
+static int src_mgr_enb_src(void *blk, unsigned int idx)
+{
+       ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32));
+       ((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32));
+       return 0;
+}
+
+static int src_mgr_dsb_src(void *blk, unsigned int idx)
+{
+       ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] &= ~(0x1 << (idx%32));
+       ((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32));
+       return 0;
+}
+
+static int src_mgr_commit_write(struct hw *hw, void *blk)
+{
+       struct src_mgr_ctrl_blk *ctl = blk;
+       int i;
+       unsigned int ret;
+
+       if (ctl->dirty.bf.enbsa) {
+               do {
+                       ret = hw_read_20kx(hw, SRC_ENBSTAT);
+               } while (ret & 0x1);
+               hw_write_20kx(hw, SRC_ENBSA, ctl->enbsa);
+               ctl->dirty.bf.enbsa = 0;
+       }
+       for (i = 0; i < 8; i++) {
+               if ((ctl->dirty.data & (0x1 << i))) {
+                       hw_write_20kx(hw, SRC_ENB+(i*0x100), ctl->enb[i]);
+                       ctl->dirty.data &= ~(0x1 << i);
+               }
+       }
+
+       return 0;
+}
+
+static int src_mgr_get_ctrl_blk(void **rblk)
+{
+       struct src_mgr_ctrl_blk *blk;
+
+       *rblk = NULL;
+       blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+       if (NULL == blk)
+               return -ENOMEM;
+
+       *rblk = blk;
+
+       return 0;
+}
+
+static int src_mgr_put_ctrl_blk(void *blk)
+{
+       kfree(blk);
+
+       return 0;
+}
+
+static int srcimp_mgr_get_ctrl_blk(void **rblk)
+{
+       struct srcimp_mgr_ctrl_blk *blk;
+
+       *rblk = NULL;
+       blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+       if (NULL == blk)
+               return -ENOMEM;
+
+       *rblk = blk;
+
+       return 0;
+}
+
+static int srcimp_mgr_put_ctrl_blk(void *blk)
+{
+       kfree(blk);
+
+       return 0;
+}
+
+static int srcimp_mgr_set_imaparc(void *blk, unsigned int slot)
+{
+       struct srcimp_mgr_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->srcimap.srcaim, SRCAIM_ARC, slot);
+       ctl->dirty.bf.srcimap = 1;
+       return 0;
+}
+
+static int srcimp_mgr_set_imapuser(void *blk, unsigned int user)
+{
+       struct srcimp_mgr_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->srcimap.srcaim, SRCAIM_SRC, user);
+       ctl->dirty.bf.srcimap = 1;
+       return 0;
+}
+
+static int srcimp_mgr_set_imapnxt(void *blk, unsigned int next)
+{
+       struct srcimp_mgr_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->srcimap.srcaim, SRCAIM_NXT, next);
+       ctl->dirty.bf.srcimap = 1;
+       return 0;
+}
+
+static int srcimp_mgr_set_imapaddr(void *blk, unsigned int addr)
+{
+       ((struct srcimp_mgr_ctrl_blk *)blk)->srcimap.idx = addr;
+       ((struct srcimp_mgr_ctrl_blk *)blk)->dirty.bf.srcimap = 1;
+       return 0;
+}
+
+static int srcimp_mgr_commit_write(struct hw *hw, void *blk)
+{
+       struct srcimp_mgr_ctrl_blk *ctl = blk;
+
+       if (ctl->dirty.bf.srcimap) {
+               hw_write_20kx(hw, SRC_IMAP+ctl->srcimap.idx*0x100,
+                                               ctl->srcimap.srcaim);
+               ctl->dirty.bf.srcimap = 0;
+       }
+
+       return 0;
+}
+
+/*
+ * AMIXER control block definitions.
+ */
+
+#define AMOPLO_M       0x00000003
+#define AMOPLO_IV      0x00000004
+#define AMOPLO_X       0x0003FFF0
+#define AMOPLO_Y       0xFFFC0000
+
+#define AMOPHI_SADR    0x000000FF
+#define AMOPHI_SE      0x80000000
+
+/* AMIXER resource register dirty flags */
+union amixer_dirty {
+       struct {
+               u16 amoplo:1;
+               u16 amophi:1;
+               u16 rsv:14;
+       } bf;
+       u16 data;
+};
+
+/* AMIXER resource control block */
+struct amixer_rsc_ctrl_blk {
+       unsigned int            amoplo;
+       unsigned int            amophi;
+       union amixer_dirty      dirty;
+};
+
+static int amixer_set_mode(void *blk, unsigned int mode)
+{
+       struct amixer_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->amoplo, AMOPLO_M, mode);
+       ctl->dirty.bf.amoplo = 1;
+       return 0;
+}
+
+static int amixer_set_iv(void *blk, unsigned int iv)
+{
+       struct amixer_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->amoplo, AMOPLO_IV, iv);
+       ctl->dirty.bf.amoplo = 1;
+       return 0;
+}
+
+static int amixer_set_x(void *blk, unsigned int x)
+{
+       struct amixer_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->amoplo, AMOPLO_X, x);
+       ctl->dirty.bf.amoplo = 1;
+       return 0;
+}
+
+static int amixer_set_y(void *blk, unsigned int y)
+{
+       struct amixer_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->amoplo, AMOPLO_Y, y);
+       ctl->dirty.bf.amoplo = 1;
+       return 0;
+}
+
+static int amixer_set_sadr(void *blk, unsigned int sadr)
+{
+       struct amixer_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->amophi, AMOPHI_SADR, sadr);
+       ctl->dirty.bf.amophi = 1;
+       return 0;
+}
+
+static int amixer_set_se(void *blk, unsigned int se)
+{
+       struct amixer_rsc_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->amophi, AMOPHI_SE, se);
+       ctl->dirty.bf.amophi = 1;
+       return 0;
+}
+
+static int amixer_set_dirty(void *blk, unsigned int flags)
+{
+       ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff);
+       return 0;
+}
+
+static int amixer_set_dirty_all(void *blk)
+{
+       ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0);
+       return 0;
+}
+
+static int amixer_commit_write(struct hw *hw, unsigned int idx, void *blk)
+{
+       struct amixer_rsc_ctrl_blk *ctl = blk;
+
+       if (ctl->dirty.bf.amoplo || ctl->dirty.bf.amophi) {
+               hw_write_20kx(hw, MIXER_AMOPLO+idx*8, ctl->amoplo);
+               ctl->dirty.bf.amoplo = 0;
+               hw_write_20kx(hw, MIXER_AMOPHI+idx*8, ctl->amophi);
+               ctl->dirty.bf.amophi = 0;
+       }
+
+       return 0;
+}
+
+static int amixer_get_y(void *blk)
+{
+       struct amixer_rsc_ctrl_blk *ctl = blk;
+
+       return get_field(ctl->amoplo, AMOPLO_Y);
+}
+
+static unsigned int amixer_get_dirty(void *blk)
+{
+       return ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data;
+}
+
+static int amixer_rsc_get_ctrl_blk(void **rblk)
+{
+       struct amixer_rsc_ctrl_blk *blk;
+
+       *rblk = NULL;
+       blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+       if (NULL == blk)
+               return -ENOMEM;
+
+       *rblk = blk;
+
+       return 0;
+}
+
+static int amixer_rsc_put_ctrl_blk(void *blk)
+{
+       kfree(blk);
+
+       return 0;
+}
+
+static int amixer_mgr_get_ctrl_blk(void **rblk)
+{
+       *rblk = NULL;
+
+       return 0;
+}
+
+static int amixer_mgr_put_ctrl_blk(void *blk)
+{
+       return 0;
+}
+
+/*
+ * DAIO control block definitions.
+ */
+
+/* Receiver Sample Rate Tracker Control register */
+#define SRTCTL_SRCO    0x000000FF
+#define SRTCTL_SRCM    0x0000FF00
+#define SRTCTL_RSR     0x00030000
+#define SRTCTL_DRAT    0x00300000
+#define SRTCTL_EC      0x01000000
+#define SRTCTL_ET      0x10000000
+
+/* DAIO Receiver register dirty flags */
+union dai_dirty {
+       struct {
+               u16 srt:1;
+               u16 rsv:15;
+       } bf;
+       u16 data;
+};
+
+/* DAIO Receiver control block */
+struct dai_ctrl_blk {
+       unsigned int    srt;
+       union dai_dirty dirty;
+};
+
+/* Audio Input Mapper RAM */
+#define AIM_ARC                0x00000FFF
+#define AIM_NXT                0x007F0000
+
+struct daoimap {
+       unsigned int aim;
+       unsigned int idx;
+};
+
+/* Audio Transmitter Control and Status register */
+#define ATXCTL_EN      0x00000001
+#define ATXCTL_MODE    0x00000010
+#define ATXCTL_CD      0x00000020
+#define ATXCTL_RAW     0x00000100
+#define ATXCTL_MT      0x00000200
+#define ATXCTL_NUC     0x00003000
+#define ATXCTL_BEN     0x00010000
+#define ATXCTL_BMUX    0x00700000
+#define ATXCTL_B24     0x01000000
+#define ATXCTL_CPF     0x02000000
+#define ATXCTL_RIV     0x10000000
+#define ATXCTL_LIV     0x20000000
+#define ATXCTL_RSAT    0x40000000
+#define ATXCTL_LSAT    0x80000000
+
+/* XDIF Transmitter register dirty flags */
+union dao_dirty {
+       struct {
+               u16 atxcsl:1;
+               u16 rsv:15;
+       } bf;
+       u16 data;
+};
+
+/* XDIF Transmitter control block */
+struct dao_ctrl_blk {
+       /* XDIF Transmitter Channel Status Low Register */
+       unsigned int    atxcsl;
+       union dao_dirty dirty;
+};
+
+/* Audio Receiver Control register */
+#define ARXCTL_EN      0x00000001
+
+/* DAIO manager register dirty flags */
+union daio_mgr_dirty {
+       struct {
+               u32 atxctl:8;
+               u32 arxctl:8;
+               u32 daoimap:1;
+               u32 rsv:15;
+       } bf;
+       u32 data;
+};
+
+/* DAIO manager control block */
+struct daio_mgr_ctrl_blk {
+       struct daoimap          daoimap;
+       unsigned int            txctl[8];
+       unsigned int            rxctl[8];
+       union daio_mgr_dirty    dirty;
+};
+
+static int dai_srt_set_srco(void *blk, unsigned int src)
+{
+       struct dai_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->srt, SRTCTL_SRCO, src);
+       ctl->dirty.bf.srt = 1;
+       return 0;
+}
+
+static int dai_srt_set_srcm(void *blk, unsigned int src)
+{
+       struct dai_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->srt, SRTCTL_SRCM, src);
+       ctl->dirty.bf.srt = 1;
+       return 0;
+}
+
+static int dai_srt_set_rsr(void *blk, unsigned int rsr)
+{
+       struct dai_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->srt, SRTCTL_RSR, rsr);
+       ctl->dirty.bf.srt = 1;
+       return 0;
+}
+
+static int dai_srt_set_drat(void *blk, unsigned int drat)
+{
+       struct dai_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->srt, SRTCTL_DRAT, drat);
+       ctl->dirty.bf.srt = 1;
+       return 0;
+}
+
+static int dai_srt_set_ec(void *blk, unsigned int ec)
+{
+       struct dai_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->srt, SRTCTL_EC, ec ? 1 : 0);
+       ctl->dirty.bf.srt = 1;
+       return 0;
+}
+
+static int dai_srt_set_et(void *blk, unsigned int et)
+{
+       struct dai_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->srt, SRTCTL_ET, et ? 1 : 0);
+       ctl->dirty.bf.srt = 1;
+       return 0;
+}
+
+static int dai_commit_write(struct hw *hw, unsigned int idx, void *blk)
+{
+       struct dai_ctrl_blk *ctl = blk;
+
+       if (ctl->dirty.bf.srt) {
+               hw_write_20kx(hw, AUDIO_IO_RX_SRT_CTL+0x40*idx, ctl->srt);
+               ctl->dirty.bf.srt = 0;
+       }
+
+       return 0;
+}
+
+static int dai_get_ctrl_blk(void **rblk)
+{
+       struct dai_ctrl_blk *blk;
+
+       *rblk = NULL;
+       blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+       if (NULL == blk)
+               return -ENOMEM;
+
+       *rblk = blk;
+
+       return 0;
+}
+
+static int dai_put_ctrl_blk(void *blk)
+{
+       kfree(blk);
+
+       return 0;
+}
+
+static int dao_set_spos(void *blk, unsigned int spos)
+{
+       ((struct dao_ctrl_blk *)blk)->atxcsl = spos;
+       ((struct dao_ctrl_blk *)blk)->dirty.bf.atxcsl = 1;
+       return 0;
+}
+
+static int dao_commit_write(struct hw *hw, unsigned int idx, void *blk)
+{
+       struct dao_ctrl_blk *ctl = blk;
+
+       if (ctl->dirty.bf.atxcsl) {
+               if (idx < 4) {
+                       /* S/PDIF SPOSx */
+                       hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_L+0x40*idx,
+                                                       ctl->atxcsl);
+               }
+               ctl->dirty.bf.atxcsl = 0;
+       }
+
+       return 0;
+}
+
+static int dao_get_spos(void *blk, unsigned int *spos)
+{
+       *spos = ((struct dao_ctrl_blk *)blk)->atxcsl;
+       return 0;
+}
+
+static int dao_get_ctrl_blk(void **rblk)
+{
+       struct dao_ctrl_blk *blk;
+
+       *rblk = NULL;
+       blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+       if (NULL == blk)
+               return -ENOMEM;
+
+       *rblk = blk;
+
+       return 0;
+}
+
+static int dao_put_ctrl_blk(void *blk)
+{
+       kfree(blk);
+
+       return 0;
+}
+
+static int daio_mgr_enb_dai(void *blk, unsigned int idx)
+{
+       struct daio_mgr_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->rxctl[idx], ARXCTL_EN, 1);
+       ctl->dirty.bf.arxctl |= (0x1 << idx);
+       return 0;
+}
+
+static int daio_mgr_dsb_dai(void *blk, unsigned int idx)
+{
+       struct daio_mgr_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->rxctl[idx], ARXCTL_EN, 0);
+
+       ctl->dirty.bf.arxctl |= (0x1 << idx);
+       return 0;
+}
+
+static int daio_mgr_enb_dao(void *blk, unsigned int idx)
+{
+       struct daio_mgr_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->txctl[idx], ATXCTL_EN, 1);
+       ctl->dirty.bf.atxctl |= (0x1 << idx);
+       return 0;
+}
+
+static int daio_mgr_dsb_dao(void *blk, unsigned int idx)
+{
+       struct daio_mgr_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->txctl[idx], ATXCTL_EN, 0);
+       ctl->dirty.bf.atxctl |= (0x1 << idx);
+       return 0;
+}
+
+static int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf)
+{
+       struct daio_mgr_ctrl_blk *ctl = blk;
+
+       if (idx < 4) {
+               /* S/PDIF output */
+               switch ((conf & 0x7)) {
+               case 1:
+                       set_field(&ctl->txctl[idx], ATXCTL_NUC, 0);
+                       break;
+               case 2:
+                       set_field(&ctl->txctl[idx], ATXCTL_NUC, 1);
+                       break;
+               case 4:
+                       set_field(&ctl->txctl[idx], ATXCTL_NUC, 2);
+                       break;
+               case 8:
+                       set_field(&ctl->txctl[idx], ATXCTL_NUC, 3);
+                       break;
+               default:
+                       break;
+               }
+               /* CDIF */
+               set_field(&ctl->txctl[idx], ATXCTL_CD, (!(conf & 0x7)));
+               /* Non-audio */
+               set_field(&ctl->txctl[idx], ATXCTL_LIV, (conf >> 4) & 0x1);
+               /* Non-audio */
+               set_field(&ctl->txctl[idx], ATXCTL_RIV, (conf >> 4) & 0x1);
+               set_field(&ctl->txctl[idx], ATXCTL_RAW,
+                         ((conf >> 3) & 0x1) ? 0 : 0);
+               ctl->dirty.bf.atxctl |= (0x1 << idx);
+       } else {
+               /* I2S output */
+               /*idx %= 4; */
+       }
+       return 0;
+}
+
+static int daio_mgr_set_imaparc(void *blk, unsigned int slot)
+{
+       struct daio_mgr_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->daoimap.aim, AIM_ARC, slot);
+       ctl->dirty.bf.daoimap = 1;
+       return 0;
+}
+
+static int daio_mgr_set_imapnxt(void *blk, unsigned int next)
+{
+       struct daio_mgr_ctrl_blk *ctl = blk;
+
+       set_field(&ctl->daoimap.aim, AIM_NXT, next);
+       ctl->dirty.bf.daoimap = 1;
+       return 0;
+}
+
+static int daio_mgr_set_imapaddr(void *blk, unsigned int addr)
+{
+       ((struct daio_mgr_ctrl_blk *)blk)->daoimap.idx = addr;
+       ((struct daio_mgr_ctrl_blk *)blk)->dirty.bf.daoimap = 1;
+       return 0;
+}
+
+static int daio_mgr_commit_write(struct hw *hw, void *blk)
+{
+       struct daio_mgr_ctrl_blk *ctl = blk;
+       unsigned int data;
+       int i;
+
+       for (i = 0; i < 8; i++) {
+               if ((ctl->dirty.bf.atxctl & (0x1 << i))) {
+                       data = ctl->txctl[i];
+                       hw_write_20kx(hw, (AUDIO_IO_TX_CTL+(0x40*i)), data);
+                       ctl->dirty.bf.atxctl &= ~(0x1 << i);
+                       mdelay(1);
+               }
+               if ((ctl->dirty.bf.arxctl & (0x1 << i))) {
+                       data = ctl->rxctl[i];
+                       hw_write_20kx(hw, (AUDIO_IO_RX_CTL+(0x40*i)), data);
+                       ctl->dirty.bf.arxctl &= ~(0x1 << i);
+                       mdelay(1);
+               }
+       }
+       if (ctl->dirty.bf.daoimap) {
+               hw_write_20kx(hw, AUDIO_IO_AIM+ctl->daoimap.idx*4,
+                                               ctl->daoimap.aim);
+               ctl->dirty.bf.daoimap = 0;
+       }
+
+       return 0;
+}
+
+static int daio_mgr_get_ctrl_blk(struct hw *hw, void **rblk)
+{
+       struct daio_mgr_ctrl_blk *blk;
+       int i;
+
+       *rblk = NULL;
+       blk = kzalloc(sizeof(*blk), GFP_KERNEL);
+       if (NULL == blk)
+               return -ENOMEM;
+
+       for (i = 0; i < 8; i++) {
+               blk->txctl[i] = hw_read_20kx(hw, AUDIO_IO_TX_CTL+(0x40*i));
+               blk->rxctl[i] = hw_read_20kx(hw, AUDIO_IO_RX_CTL+(0x40*i));
+       }
+
+       *rblk = blk;
+
+       return 0;
+}
+
+static int daio_mgr_put_ctrl_blk(void *blk)
+{
+       kfree(blk);
+
+       return 0;
+}
+
+/* Card hardware initialization block */
+struct dac_conf {
+       unsigned int msr; /* master sample rate in rsrs */
+};
+
+struct adc_conf {
+       unsigned int msr;       /* master sample rate in rsrs */
+       unsigned char input;    /* the input source of ADC */
+       unsigned char mic20db;  /* boost mic by 20db if input is microphone */
+};
+
+struct daio_conf {
+       unsigned int msr; /* master sample rate in rsrs */
+};
+
+struct trn_conf {
+       unsigned long vm_pgt_phys;
+};
+
+static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
+{
+       u32 data;
+       int i;
+
+       /* Program I2S with proper sample rate and enable the correct I2S
+        * channel. ED(0/8/16/24): Enable all I2S/I2X master clock output */
+       if (1 == info->msr) {
+               hw_write_20kx(hw, AUDIO_IO_MCLK, 0x01010101);
+               hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x01010101);
+               hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
+       } else if (2 == info->msr) {
+               hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11111111);
+               /* Specify all playing 96khz
+                * EA [0]       - Enabled
+                * RTA [4:5]    - 96kHz
+                * EB [8]       - Enabled
+                * RTB [12:13]  - 96kHz
+                * EC [16]      - Enabled
+                * RTC [20:21]  - 96kHz
+                * ED [24]      - Enabled
+                * RTD [28:29]  - 96kHz */
+               hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x11111111);
+               hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
+       } else {
+               printk(KERN_ALERT "ctxfi: ERROR!!! Invalid sampling rate!!!\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < 8; i++) {
+               if (i <= 3) {
+                       /* 1st 3 channels are SPDIFs (SB0960) */
+                       if (i == 3)
+                               data = 0x1001001;
+                       else
+                               data = 0x1000001;
+
+                       hw_write_20kx(hw, (AUDIO_IO_TX_CTL+(0x40*i)), data);
+                       hw_write_20kx(hw, (AUDIO_IO_RX_CTL+(0x40*i)), data);
+
+                       /* Initialize the SPDIF Out Channel status registers.
+                        * The value specified here is based on the typical
+                        * values provided in the specification, namely: Clock
+                        * Accuracy of 1000ppm, Sample Rate of 48KHz,
+                        * unspecified source number, Generation status = 1,
+                        * Category code = 0x12 (Digital Signal Mixer),
+                        * Mode = 0, Emph = 0, Copy Permitted, AN = 0
+                        * (indicating that we're transmitting digital audio,
+                        * and the Professional Use bit is 0. */
+
+                       hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_L+(0x40*i),
+                                       0x02109204); /* Default to 48kHz */
+
+                       hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_H+(0x40*i), 0x0B);
+               } else {
+                       /* Next 5 channels are I2S (SB0960) */
+                       data = 0x11;
+                       hw_write_20kx(hw, AUDIO_IO_RX_CTL+(0x40*i), data);
+                       if (2 == info->msr) {
+                               /* Four channels per sample period */
+                               data |= 0x1000;
+                       }
+                       hw_write_20kx(hw, AUDIO_IO_TX_CTL+(0x40*i), data);
+               }
+       }
+
+       return 0;
+}
+
+/* TRANSPORT operations */
+static int hw_trn_init(struct hw *hw, const struct trn_conf *info)
+{
+       u32 vmctl, data;
+       u32 ptp_phys_low, ptp_phys_high;
+       int i;
+
+       /* Set up device page table */
+       if ((~0UL) == info->vm_pgt_phys) {
+               printk(KERN_ALERT "ctxfi: "
+                      "Wrong device page table page address!!!\n");
+               return -1;
+       }
+
+       vmctl = 0x80000C0F;  /* 32-bit, 4k-size page */
+       ptp_phys_low = (u32)info->vm_pgt_phys;
+       ptp_phys_high = upper_32_bits(info->vm_pgt_phys);
+       if (sizeof(void *) == 8) /* 64bit address */
+               vmctl |= (3 << 8);
+       /* Write page table physical address to all PTPAL registers */
+       for (i = 0; i < 64; i++) {
+               hw_write_20kx(hw, VMEM_PTPAL+(16*i), ptp_phys_low);
+               hw_write_20kx(hw, VMEM_PTPAH+(16*i), ptp_phys_high);
+       }
+       /* Enable virtual memory transfer */
+       hw_write_20kx(hw, VMEM_CTL, vmctl);
+       /* Enable transport bus master and queueing of request */
+       hw_write_20kx(hw, TRANSPORT_CTL, 0x03);
+       hw_write_20kx(hw, TRANSPORT_INT, 0x200c01);
+       /* Enable transport ring */
+       data = hw_read_20kx(hw, TRANSPORT_ENB);
+       hw_write_20kx(hw, TRANSPORT_ENB, (data | 0x03));
+
+       return 0;
+}
+
+/* Card initialization */
+#define GCTL_AIE       0x00000001
+#define GCTL_UAA       0x00000002
+#define GCTL_DPC       0x00000004
+#define GCTL_DBP       0x00000008
+#define GCTL_ABP       0x00000010
+#define GCTL_TBP       0x00000020
+#define GCTL_SBP       0x00000040
+#define GCTL_FBP       0x00000080
+#define GCTL_ME                0x00000100
+#define GCTL_AID       0x00001000
+
+#define PLLCTL_SRC     0x00000007
+#define PLLCTL_SPE     0x00000008
+#define PLLCTL_RD      0x000000F0
+#define PLLCTL_FD      0x0001FF00
+#define PLLCTL_OD      0x00060000
+#define PLLCTL_B       0x00080000
+#define PLLCTL_AS      0x00100000
+#define PLLCTL_LF      0x03E00000
+#define PLLCTL_SPS     0x1C000000
+#define PLLCTL_AD      0x60000000
+
+#define PLLSTAT_CCS    0x00000007
+#define PLLSTAT_SPL    0x00000008
+#define PLLSTAT_CRD    0x000000F0
+#define PLLSTAT_CFD    0x0001FF00
+#define PLLSTAT_SL     0x00020000
+#define PLLSTAT_FAS    0x00040000
+#define PLLSTAT_B      0x00080000
+#define PLLSTAT_PD     0x00100000
+#define PLLSTAT_OCA    0x00200000
+#define PLLSTAT_NCA    0x00400000
+
+static int hw_pll_init(struct hw *hw, unsigned int rsr)
+{
+       unsigned int pllenb;
+       unsigned int pllctl;
+       unsigned int pllstat;
+       int i;
+
+       pllenb = 0xB;
+       hw_write_20kx(hw, PLL_ENB, pllenb);
+       pllctl = 0x20D00000;
+       set_field(&pllctl, PLLCTL_FD, 16 - 4);
+       hw_write_20kx(hw, PLL_CTL, pllctl);
+       mdelay(40);
+       pllctl = hw_read_20kx(hw, PLL_CTL);
+       set_field(&pllctl, PLLCTL_B, 0);
+       if (48000 == rsr) {
+               set_field(&pllctl, PLLCTL_FD, 16 - 2);
+               set_field(&pllctl, PLLCTL_RD, 1 - 1);
+       } else { /* 44100 */
+               set_field(&pllctl, PLLCTL_FD, 147 - 2);
+               set_field(&pllctl, PLLCTL_RD, 10 - 1);
+       }
+       hw_write_20kx(hw, PLL_CTL, pllctl);
+       mdelay(40);
+       for (i = 0; i < 1000; i++) {
+               pllstat = hw_read_20kx(hw, PLL_STAT);
+               if (get_field(pllstat, PLLSTAT_PD))
+                       continue;
+
+               if (get_field(pllstat, PLLSTAT_B) !=
+                                       get_field(pllctl, PLLCTL_B))
+                       continue;
+
+               if (get_field(pllstat, PLLSTAT_CCS) !=
+                                       get_field(pllctl, PLLCTL_SRC))
+                       continue;
+
+               if (get_field(pllstat, PLLSTAT_CRD) !=
+                                       get_field(pllctl, PLLCTL_RD))
+                       continue;
+
+               if (get_field(pllstat, PLLSTAT_CFD) !=
+                                       get_field(pllctl, PLLCTL_FD))
+                       continue;
+
+               break;
+       }
+       if (i >= 1000) {
+               printk(KERN_ALERT "ctxfi: PLL initialization failed!!!\n");
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static int hw_auto_init(struct hw *hw)
+{
+       unsigned int gctl;
+       int i;
+
+       gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL);
+       set_field(&gctl, GCTL_AIE, 0);
+       hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl);
+       set_field(&gctl, GCTL_AIE, 1);
+       hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl);
+       mdelay(10);
+       for (i = 0; i < 400000; i++) {
+               gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL);
+               if (get_field(gctl, GCTL_AID))
+                       break;
+       }
+       if (!get_field(gctl, GCTL_AID)) {
+               printk(KERN_ALERT "ctxfi: Card Auto-init failed!!!\n");
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+/* DAC operations */
+
+#define CS4382_MC1             0x1
+#define CS4382_MC2             0x2
+#define CS4382_MC3             0x3
+#define CS4382_FC              0x4
+#define CS4382_IC              0x5
+#define CS4382_XC1             0x6
+#define CS4382_VCA1            0x7
+#define CS4382_VCB1            0x8
+#define CS4382_XC2             0x9
+#define CS4382_VCA2            0xA
+#define CS4382_VCB2            0xB
+#define CS4382_XC3             0xC
+#define CS4382_VCA3            0xD
+#define CS4382_VCB3            0xE
+#define CS4382_XC4             0xF
+#define CS4382_VCA4            0x10
+#define CS4382_VCB4            0x11
+#define CS4382_CREV            0x12
+
+/* I2C status */
+#define STATE_LOCKED           0x00
+#define STATE_UNLOCKED         0xAA
+#define DATA_READY             0x800000    /* Used with I2C_IF_STATUS */
+#define DATA_ABORT             0x10000     /* Used with I2C_IF_STATUS */
+
+#define I2C_STATUS_DCM 0x00000001
+#define I2C_STATUS_BC  0x00000006
+#define I2C_STATUS_APD 0x00000008
+#define I2C_STATUS_AB  0x00010000
+#define I2C_STATUS_DR  0x00800000
+
+#define I2C_ADDRESS_PTAD       0x0000FFFF
+#define I2C_ADDRESS_SLAD       0x007F0000
+
+struct regs_cs4382 {
+       u32 mode_control_1;
+       u32 mode_control_2;
+       u32 mode_control_3;
+
+       u32 filter_control;
+       u32 invert_control;
+
+       u32 mix_control_P1;
+       u32 vol_control_A1;
+       u32 vol_control_B1;
+
+       u32 mix_control_P2;
+       u32 vol_control_A2;
+       u32 vol_control_B2;
+
+       u32 mix_control_P3;
+       u32 vol_control_A3;
+       u32 vol_control_B3;
+
+       u32 mix_control_P4;
+       u32 vol_control_A4;
+       u32 vol_control_B4;
+};
+
+static int hw20k2_i2c_unlock_full_access(struct hw *hw)
+{
+       u8 UnlockKeySequence_FLASH_FULLACCESS_MODE[2] =  {0xB3, 0xD4};
+
+       /* Send keys for forced BIOS mode */
+       hw_write_20kx(hw, I2C_IF_WLOCK,
+                       UnlockKeySequence_FLASH_FULLACCESS_MODE[0]);
+       hw_write_20kx(hw, I2C_IF_WLOCK,
+                       UnlockKeySequence_FLASH_FULLACCESS_MODE[1]);
+       /* Check whether the chip is unlocked */
+       if (hw_read_20kx(hw, I2C_IF_WLOCK) == STATE_UNLOCKED)
+               return 0;
+
+       return -1;
+}
+
+static int hw20k2_i2c_lock_chip(struct hw *hw)
+{
+       /* Write twice */
+       hw_write_20kx(hw, I2C_IF_WLOCK, STATE_LOCKED);
+       hw_write_20kx(hw, I2C_IF_WLOCK, STATE_LOCKED);
+       if (hw_read_20kx(hw, I2C_IF_WLOCK) == STATE_LOCKED)
+               return 0;
+
+       return -1;
+}
+
+static int hw20k2_i2c_init(struct hw *hw, u8 dev_id, u8 addr_size, u8 data_size)
+{
+       struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
+       int err;
+       unsigned int i2c_status;
+       unsigned int i2c_addr;
+
+       err = hw20k2_i2c_unlock_full_access(hw);
+       if (err < 0)
+               return err;
+
+       hw20k2->addr_size = addr_size;
+       hw20k2->data_size = data_size;
+       hw20k2->dev_id = dev_id;
+
+       i2c_addr = 0;
+       set_field(&i2c_addr, I2C_ADDRESS_SLAD, dev_id);
+
+       hw_write_20kx(hw, I2C_IF_ADDRESS, i2c_addr);
+
+       i2c_status = hw_read_20kx(hw, I2C_IF_STATUS);
+
+       set_field(&i2c_status, I2C_STATUS_DCM, 1); /* Direct control mode */
+
+       hw_write_20kx(hw, I2C_IF_STATUS, i2c_status);
+
+       return 0;
+}
+
+static int hw20k2_i2c_uninit(struct hw *hw)
+{
+       unsigned int i2c_status;
+       unsigned int i2c_addr;
+
+       i2c_addr = 0;
+       set_field(&i2c_addr, I2C_ADDRESS_SLAD, 0x57); /* I2C id */
+
+       hw_write_20kx(hw, I2C_IF_ADDRESS, i2c_addr);
+
+       i2c_status = hw_read_20kx(hw, I2C_IF_STATUS);
+
+       set_field(&i2c_status, I2C_STATUS_DCM, 0); /* I2C mode */
+
+       hw_write_20kx(hw, I2C_IF_STATUS, i2c_status);
+
+       return hw20k2_i2c_lock_chip(hw);
+}
+
+static int hw20k2_i2c_wait_data_ready(struct hw *hw)
+{
+       int i = 0x400000;
+       unsigned int ret;
+
+       do {
+               ret = hw_read_20kx(hw, I2C_IF_STATUS);
+       } while ((!(ret & DATA_READY)) && --i);
+
+       return i;
+}
+
+static int hw20k2_i2c_read(struct hw *hw, u16 addr, u32 *datap)
+{
+       struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
+       unsigned int i2c_status;
+
+       i2c_status = hw_read_20kx(hw, I2C_IF_STATUS);
+       set_field(&i2c_status, I2C_STATUS_BC,
+                 (4 == hw20k2->addr_size) ? 0 : hw20k2->addr_size);
+       hw_write_20kx(hw, I2C_IF_STATUS, i2c_status);
+       if (!hw20k2_i2c_wait_data_ready(hw))
+               return -1;
+
+       hw_write_20kx(hw, I2C_IF_WDATA, addr);
+       if (!hw20k2_i2c_wait_data_ready(hw))
+               return -1;
+
+       /* Force a read operation */
+       hw_write_20kx(hw, I2C_IF_RDATA, 0);
+       if (!hw20k2_i2c_wait_data_ready(hw))
+               return -1;
+
+       *datap = hw_read_20kx(hw, I2C_IF_RDATA);
+
+       return 0;
+}
+
+static int hw20k2_i2c_write(struct hw *hw, u16 addr, u32 data)
+{
+       struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
+       unsigned int i2c_data = (data << (hw20k2->addr_size * 8)) | addr;
+       unsigned int i2c_status;
+
+       i2c_status = hw_read_20kx(hw, I2C_IF_STATUS);
+
+       set_field(&i2c_status, I2C_STATUS_BC,
+                 (4 == (hw20k2->addr_size + hw20k2->data_size)) ?
+                 0 : (hw20k2->addr_size + hw20k2->data_size));
+
+       hw_write_20kx(hw, I2C_IF_STATUS, i2c_status);
+       hw20k2_i2c_wait_data_ready(hw);
+       /* Dummy write to trigger the write oprtation */
+       hw_write_20kx(hw, I2C_IF_WDATA, 0);
+       hw20k2_i2c_wait_data_ready(hw);
+
+       /* This is the real data */
+       hw_write_20kx(hw, I2C_IF_WDATA, i2c_data);
+       hw20k2_i2c_wait_data_ready(hw);
+
+       return 0;
+}
+
+static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
+{
+       int err;
+       u32 data;
+       int i;
+       struct regs_cs4382 cs_read = {0};
+       struct regs_cs4382 cs_def = {
+                                  0x00000001,  /* Mode Control 1 */
+                                  0x00000000,  /* Mode Control 2 */
+                                  0x00000084,  /* Mode Control 3 */
+                                  0x00000000,  /* Filter Control */
+                                  0x00000000,  /* Invert Control */
+                                  0x00000024,  /* Mixing Control Pair 1 */
+                                  0x00000000,  /* Vol Control A1 */
+                                  0x00000000,  /* Vol Control B1 */
+                                  0x00000024,  /* Mixing Control Pair 2 */
+                                  0x00000000,  /* Vol Control A2 */
+                                  0x00000000,  /* Vol Control B2 */
+                                  0x00000024,  /* Mixing Control Pair 3 */
+                                  0x00000000,  /* Vol Control A3 */
+                                  0x00000000,  /* Vol Control B3 */
+                                  0x00000024,  /* Mixing Control Pair 4 */
+                                  0x00000000,  /* Vol Control A4 */
+                                  0x00000000   /* Vol Control B4 */
+                                };
+
+       /* Set DAC reset bit as output */
+       data = hw_read_20kx(hw, GPIO_CTRL);
+       data |= 0x02;
+       hw_write_20kx(hw, GPIO_CTRL, data);
+
+       err = hw20k2_i2c_init(hw, 0x18, 1, 1);
+       if (err < 0)
+               goto End;
+
+       for (i = 0; i < 2; i++) {
+               /* Reset DAC twice just in-case the chip
+                * didn't initialized properly */
+               data = hw_read_20kx(hw, GPIO_DATA);
+               /* GPIO data bit 1 */
+               data &= 0xFFFFFFFD;
+               hw_write_20kx(hw, GPIO_DATA, data);
+               mdelay(10);
+               data |= 0x2;
+               hw_write_20kx(hw, GPIO_DATA, data);
+               mdelay(50);
+
+               /* Reset the 2nd time */
+               data &= 0xFFFFFFFD;
+               hw_write_20kx(hw, GPIO_DATA, data);
+               mdelay(10);
+               data |= 0x2;
+               hw_write_20kx(hw, GPIO_DATA, data);
+               mdelay(50);
+
+               if (hw20k2_i2c_read(hw, CS4382_MC1,  &cs_read.mode_control_1))
+                       continue;
+
+               if (hw20k2_i2c_read(hw, CS4382_MC2,  &cs_read.mode_control_2))
+                       continue;
+
+               if (hw20k2_i2c_read(hw, CS4382_MC3,  &cs_read.mode_control_3))
+                       continue;
+
+               if (hw20k2_i2c_read(hw, CS4382_FC,   &cs_read.filter_control))
+                       continue;
+
+               if (hw20k2_i2c_read(hw, CS4382_IC,   &cs_read.invert_control))
+                       continue;
+
+               if (hw20k2_i2c_read(hw, CS4382_XC1,  &cs_read.mix_control_P1))
+                       continue;
+
+               if (hw20k2_i2c_read(hw, CS4382_VCA1, &cs_read.vol_control_A1))
+                       continue;
+
+               if (hw20k2_i2c_read(hw, CS4382_VCB1, &cs_read.vol_control_B1))
+                       continue;
+
+               if (hw20k2_i2c_read(hw, CS4382_XC2,  &cs_read.mix_control_P2))
+                       continue;
+
+               if (hw20k2_i2c_read(hw, CS4382_VCA2, &cs_read.vol_control_A2))
+                       continue;
+
+               if (hw20k2_i2c_read(hw, CS4382_VCB2, &cs_read.vol_control_B2))
+                       continue;
+
+               if (hw20k2_i2c_read(hw, CS4382_XC3,  &cs_read.mix_control_P3))
+                       continue;
+
+               if (hw20k2_i2c_read(hw, CS4382_VCA3, &cs_read.vol_control_A3))
+                       continue;
+
+               if (hw20k2_i2c_read(hw, CS4382_VCB3, &cs_read.vol_control_B3))
+                       continue;
+
+               if (hw20k2_i2c_read(hw, CS4382_XC4,  &cs_read.mix_control_P4))
+                       continue;
+
+               if (hw20k2_i2c_read(hw, CS4382_VCA4, &cs_read.vol_control_A4))
+                       continue;
+
+               if (hw20k2_i2c_read(hw, CS4382_VCB4, &cs_read.vol_control_B4))
+                       continue;
+
+               if (memcmp(&cs_read, &cs_def, sizeof(cs_read)))
+                       continue;
+               else
+                       break;
+       }
+
+       if (i >= 2)
+               goto End;
+
+       /* Note: Every I2C write must have some delay.
+        * This is not a requirement but the delay works here... */
+       hw20k2_i2c_write(hw, CS4382_MC1, 0x80);
+       hw20k2_i2c_write(hw, CS4382_MC2, 0x10);
+       if (1 == info->msr) {
+               hw20k2_i2c_write(hw, CS4382_XC1, 0x24);
+               hw20k2_i2c_write(hw, CS4382_XC2, 0x24);
+               hw20k2_i2c_write(hw, CS4382_XC3, 0x24);
+               hw20k2_i2c_write(hw, CS4382_XC4, 0x24);
+       } else if (2 == info->msr) {
+               hw20k2_i2c_write(hw, CS4382_XC1, 0x25);
+               hw20k2_i2c_write(hw, CS4382_XC2, 0x25);
+               hw20k2_i2c_write(hw, CS4382_XC3, 0x25);
+               hw20k2_i2c_write(hw, CS4382_XC4, 0x25);
+       } else {
+               hw20k2_i2c_write(hw, CS4382_XC1, 0x26);
+               hw20k2_i2c_write(hw, CS4382_XC2, 0x26);
+               hw20k2_i2c_write(hw, CS4382_XC3, 0x26);
+               hw20k2_i2c_write(hw, CS4382_XC4, 0x26);
+       }
+
+       return 0;
+End:
+
+       hw20k2_i2c_uninit(hw);
+       return -1;
+}
+
+/* ADC operations */
+#define MAKE_WM8775_ADDR(addr, data)   (u32)(((addr<<1)&0xFE)|((data>>8)&0x1))
+#define MAKE_WM8775_DATA(data) (u32)(data&0xFF)
+
+#define WM8775_IC       0x0B
+#define WM8775_MMC      0x0C
+#define WM8775_AADCL    0x0E
+#define WM8775_AADCR    0x0F
+#define WM8775_ADCMC    0x15
+#define WM8775_RESET    0x17
+
+static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type)
+{
+       u32 data;
+
+       data = hw_read_20kx(hw, GPIO_DATA);
+       switch (type) {
+       case ADC_MICIN:
+               data = (data & (0x1 << 14)) ? 1 : 0;
+               break;
+       case ADC_LINEIN:
+               data = (data & (0x1 << 14)) ? 0 : 1;
+               break;
+       default:
+               data = 0;
+       }
+       return data;
+}
+
+static int hw_adc_input_select(struct hw *hw, enum ADCSRC type)
+{
+       u32 data;
+
+       data = hw_read_20kx(hw, GPIO_DATA);
+       switch (type) {
+       case ADC_MICIN:
+               data |= (0x1 << 14);
+               hw_write_20kx(hw, GPIO_DATA, data);
+               hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101),
+                               MAKE_WM8775_DATA(0x101)); /* Mic-in */
+               hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xE7),
+                               MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
+               hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xE7),
+                               MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
+               break;
+       case ADC_LINEIN:
+               data &= ~(0x1 << 14);
+               hw_write_20kx(hw, GPIO_DATA, data);
+               hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102),
+                               MAKE_WM8775_DATA(0x102)); /* Line-in */
+               hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF),
+                               MAKE_WM8775_DATA(0xCF)); /* No boost */
+               hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF),
+                               MAKE_WM8775_DATA(0xCF)); /* No boost */
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
+{
+       int err;
+       u32 mux = 2, data, ctl;
+
+       /*  Set ADC reset bit as output */
+       data = hw_read_20kx(hw, GPIO_CTRL);
+       data |= (0x1 << 15);
+       hw_write_20kx(hw, GPIO_CTRL, data);
+
+       /* Initialize I2C */
+       err = hw20k2_i2c_init(hw, 0x1A, 1, 1);
+       if (err < 0) {
+               printk(KERN_ALERT "ctxfi: Failure to acquire I2C!!!\n");
+               goto error;
+       }
+
+       /* Make ADC in normal operation */
+       data = hw_read_20kx(hw, GPIO_DATA);
+       data &= ~(0x1 << 15);
+       mdelay(10);
+       data |= (0x1 << 15);
+       hw_write_20kx(hw, GPIO_DATA, data);
+       mdelay(50);
+
+       /* Set the master mode (256fs) */
+       if (1 == info->msr) {
+               hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x02),
+                                               MAKE_WM8775_DATA(0x02));
+       } else if (2 == info->msr) {
+               hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x0A),
+                                               MAKE_WM8775_DATA(0x0A));
+       } else {
+               printk(KERN_ALERT "ctxfi: Invalid master sampling "
+                                 "rate (msr %d)!!!\n", info->msr);
+               err = -EINVAL;
+               goto error;
+       }
+
+       /* Configure GPIO bit 14 change to line-in/mic-in */
+       ctl = hw_read_20kx(hw, GPIO_CTRL);
+       ctl |= 0x1 << 14;
+       hw_write_20kx(hw, GPIO_CTRL, ctl);
+
+       /* Check using Mic-in or Line-in */
+       data = hw_read_20kx(hw, GPIO_DATA);
+
+       if (mux == 1) {
+               /* Configures GPIO data to select Mic-in */
+               data |= 0x1 << 14;
+               hw_write_20kx(hw, GPIO_DATA, data);
+
+               hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101),
+                               MAKE_WM8775_DATA(0x101)); /* Mic-in */
+               hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xE7),
+                               MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
+               hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xE7),
+                               MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
+       } else if (mux == 2) {
+               /* Configures GPIO data to select Line-in */
+               data &= ~(0x1 << 14);
+               hw_write_20kx(hw, GPIO_DATA, data);
+
+               /* Setup ADC */
+               hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102),
+                               MAKE_WM8775_DATA(0x102)); /* Line-in */
+               hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF),
+                               MAKE_WM8775_DATA(0xCF)); /* No boost */
+               hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF),
+                               MAKE_WM8775_DATA(0xCF)); /* No boost */
+       } else {
+               printk(KERN_ALERT "ctxfi: ERROR!!! Invalid input mux!!!\n");
+               err = -EINVAL;
+               goto error;
+       }
+
+       return 0;
+
+error:
+       hw20k2_i2c_uninit(hw);
+       return err;
+}
+
+static int hw_have_digit_io_switch(struct hw *hw)
+{
+       return 0;
+}
+
+static int hw_card_start(struct hw *hw)
+{
+       int err = 0;
+       struct pci_dev *pci = hw->pci;
+       unsigned int gctl;
+
+       err = pci_enable_device(pci);
+       if (err < 0)
+               return err;
+
+       /* Set DMA transfer mask */
+       if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 ||
+           pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) {
+               printk(KERN_ERR "ctxfi: architecture does not support PCI "
+               "busmaster DMA with mask 0x%llx\n", CT_XFI_DMA_MASK);
+               err = -ENXIO;
+               goto error1;
+       }
+
+       err = pci_request_regions(pci, "XFi");
+       if (err < 0)
+               goto error1;
+
+       hw->io_base = pci_resource_start(hw->pci, 2);
+       hw->mem_base = (unsigned long)ioremap(hw->io_base,
+                                       pci_resource_len(hw->pci, 2));
+       if (NULL == (void *)hw->mem_base) {
+               err = -ENOENT;
+               goto error2;
+       }
+
+       /* Switch to 20k2 mode from UAA mode. */
+       gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL);
+       set_field(&gctl, GCTL_UAA, 0);
+       hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl);
+
+       /*if ((err = request_irq(pci->irq, ct_atc_interrupt, IRQF_SHARED,
+                               atc->chip_details->nm_card, hw))) {
+               goto error3;
+       }
+       hw->irq = pci->irq;
+       */
+
+       pci_set_master(pci);
+
+       return 0;
+
+/*error3:
+       iounmap((void *)hw->mem_base);
+       hw->mem_base = (unsigned long)NULL;*/
+error2:
+       pci_release_regions(pci);
+       hw->io_base = 0;
+error1:
+       pci_disable_device(pci);
+       return err;
+}
+
+static int hw_card_stop(struct hw *hw)
+{
+       /* TODO: Disable interrupt and so on... */
+       return 0;
+}
+
+static int hw_card_shutdown(struct hw *hw)
+{
+       if (hw->irq >= 0)
+               free_irq(hw->irq, hw);
+
+       hw->irq = -1;
+
+       if (NULL != ((void *)hw->mem_base))
+               iounmap((void *)hw->mem_base);
+
+       hw->mem_base = (unsigned long)NULL;
+
+       if (hw->io_base)
+               pci_release_regions(hw->pci);
+
+       hw->io_base = 0;
+
+       pci_disable_device(hw->pci);
+
+       return 0;
+}
+
+static int hw_card_init(struct hw *hw, struct card_conf *info)
+{
+       int err;
+       unsigned int gctl;
+       u32 data = 0;
+       struct dac_conf dac_info = {0};
+       struct adc_conf adc_info = {0};
+       struct daio_conf daio_info = {0};
+       struct trn_conf trn_info = {0};
+
+       /* Get PCI io port/memory base address and
+        * do 20kx core switch if needed. */
+       if (!hw->io_base) {
+               err = hw_card_start(hw);
+               if (err)
+                       return err;
+       }
+
+       /* PLL init */
+       err = hw_pll_init(hw, info->rsr);
+       if (err < 0)
+               return err;
+
+       /* kick off auto-init */
+       err = hw_auto_init(hw);
+       if (err < 0)
+               return err;
+
+       gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL);
+       set_field(&gctl, GCTL_DBP, 1);
+       set_field(&gctl, GCTL_TBP, 1);
+       set_field(&gctl, GCTL_FBP, 1);
+       set_field(&gctl, GCTL_DPC, 0);
+       hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl);
+
+       /* Reset all global pending interrupts */
+       hw_write_20kx(hw, INTERRUPT_GIE, 0);
+       /* Reset all SRC pending interrupts */
+       hw_write_20kx(hw, SRC_IP, 0);
+
+       /* TODO: detect the card ID and configure GPIO accordingly. */
+       /* Configures GPIO (0xD802 0x98028) */
+       /*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/
+       /* Configures GPIO (SB0880) */
+       /*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/
+       hw_write_20kx(hw, GPIO_CTRL, 0xD802);
+
+       /* Enable audio ring */
+       hw_write_20kx(hw, MIXER_AR_ENABLE, 0x01);
+
+       trn_info.vm_pgt_phys = info->vm_pgt_phys;
+       err = hw_trn_init(hw, &trn_info);
+       if (err < 0)
+               return err;
+
+       daio_info.msr = info->msr;
+       err = hw_daio_init(hw, &daio_info);
+       if (err < 0)
+               return err;
+
+       dac_info.msr = info->msr;
+       err = hw_dac_init(hw, &dac_info);
+       if (err < 0)
+               return err;
+
+       adc_info.msr = info->msr;
+       adc_info.input = ADC_LINEIN;
+       adc_info.mic20db = 0;
+       err = hw_adc_init(hw, &adc_info);
+       if (err < 0)
+               return err;
+
+       data = hw_read_20kx(hw, SRC_MCTL);
+       data |= 0x1; /* Enables input from the audio ring */
+       hw_write_20kx(hw, SRC_MCTL, data);
+
+       return 0;
+}
+
+static u32 hw_read_20kx(struct hw *hw, u32 reg)
+{
+       return readl((void *)(hw->mem_base + reg));
+}
+
+static void hw_write_20kx(struct hw *hw, u32 reg, u32 data)
+{
+       writel(data, (void *)(hw->mem_base + reg));
+}
+
+static struct hw ct20k2_preset __devinitdata = {
+       .irq = -1,
+
+       .card_init = hw_card_init,
+       .card_stop = hw_card_stop,
+       .pll_init = hw_pll_init,
+       .is_adc_source_selected = hw_is_adc_input_selected,
+       .select_adc_source = hw_adc_input_select,
+       .have_digit_io_switch = hw_have_digit_io_switch,
+
+       .src_rsc_get_ctrl_blk = src_get_rsc_ctrl_blk,
+       .src_rsc_put_ctrl_blk = src_put_rsc_ctrl_blk,
+       .src_mgr_get_ctrl_blk = src_mgr_get_ctrl_blk,
+       .src_mgr_put_ctrl_blk = src_mgr_put_ctrl_blk,
+       .src_set_state = src_set_state,
+       .src_set_bm = src_set_bm,
+       .src_set_rsr = src_set_rsr,
+       .src_set_sf = src_set_sf,
+       .src_set_wr = src_set_wr,
+       .src_set_pm = src_set_pm,
+       .src_set_rom = src_set_rom,
+       .src_set_vo = src_set_vo,
+       .src_set_st = src_set_st,
+       .src_set_ie = src_set_ie,
+       .src_set_ilsz = src_set_ilsz,
+       .src_set_bp = src_set_bp,
+       .src_set_cisz = src_set_cisz,
+       .src_set_ca = src_set_ca,
+       .src_set_sa = src_set_sa,
+       .src_set_la = src_set_la,
+       .src_set_pitch = src_set_pitch,
+       .src_set_dirty = src_set_dirty,
+       .src_set_clear_zbufs = src_set_clear_zbufs,
+       .src_set_dirty_all = src_set_dirty_all,
+       .src_commit_write = src_commit_write,
+       .src_get_ca = src_get_ca,
+       .src_get_dirty = src_get_dirty,
+       .src_dirty_conj_mask = src_dirty_conj_mask,
+       .src_mgr_enbs_src = src_mgr_enbs_src,
+       .src_mgr_enb_src = src_mgr_enb_src,
+       .src_mgr_dsb_src = src_mgr_dsb_src,
+       .src_mgr_commit_write = src_mgr_commit_write,
+
+       .srcimp_mgr_get_ctrl_blk = srcimp_mgr_get_ctrl_blk,
+       .srcimp_mgr_put_ctrl_blk = srcimp_mgr_put_ctrl_blk,
+       .srcimp_mgr_set_imaparc = srcimp_mgr_set_imaparc,
+       .srcimp_mgr_set_imapuser = srcimp_mgr_set_imapuser,
+       .srcimp_mgr_set_imapnxt = srcimp_mgr_set_imapnxt,
+       .srcimp_mgr_set_imapaddr = srcimp_mgr_set_imapaddr,
+       .srcimp_mgr_commit_write = srcimp_mgr_commit_write,
+
+       .amixer_rsc_get_ctrl_blk = amixer_rsc_get_ctrl_blk,
+       .amixer_rsc_put_ctrl_blk = amixer_rsc_put_ctrl_blk,
+       .amixer_mgr_get_ctrl_blk = amixer_mgr_get_ctrl_blk,
+       .amixer_mgr_put_ctrl_blk = amixer_mgr_put_ctrl_blk,
+       .amixer_set_mode = amixer_set_mode,
+       .amixer_set_iv = amixer_set_iv,
+       .amixer_set_x = amixer_set_x,
+       .amixer_set_y = amixer_set_y,
+       .amixer_set_sadr = amixer_set_sadr,
+       .amixer_set_se = amixer_set_se,
+       .amixer_set_dirty = amixer_set_dirty,
+       .amixer_set_dirty_all = amixer_set_dirty_all,
+       .amixer_commit_write = amixer_commit_write,
+       .amixer_get_y = amixer_get_y,
+       .amixer_get_dirty = amixer_get_dirty,
+
+       .dai_get_ctrl_blk = dai_get_ctrl_blk,
+       .dai_put_ctrl_blk = dai_put_ctrl_blk,
+       .dai_srt_set_srco = dai_srt_set_srco,
+       .dai_srt_set_srcm = dai_srt_set_srcm,
+       .dai_srt_set_rsr = dai_srt_set_rsr,
+       .dai_srt_set_drat = dai_srt_set_drat,
+       .dai_srt_set_ec = dai_srt_set_ec,
+       .dai_srt_set_et = dai_srt_set_et,
+       .dai_commit_write = dai_commit_write,
+
+       .dao_get_ctrl_blk = dao_get_ctrl_blk,
+       .dao_put_ctrl_blk = dao_put_ctrl_blk,
+       .dao_set_spos = dao_set_spos,
+       .dao_commit_write = dao_commit_write,
+       .dao_get_spos = dao_get_spos,
+
+       .daio_mgr_get_ctrl_blk = daio_mgr_get_ctrl_blk,
+       .daio_mgr_put_ctrl_blk = daio_mgr_put_ctrl_blk,
+       .daio_mgr_enb_dai = daio_mgr_enb_dai,
+       .daio_mgr_dsb_dai = daio_mgr_dsb_dai,
+       .daio_mgr_enb_dao = daio_mgr_enb_dao,
+       .daio_mgr_dsb_dao = daio_mgr_dsb_dao,
+       .daio_mgr_dao_init = daio_mgr_dao_init,
+       .daio_mgr_set_imaparc = daio_mgr_set_imaparc,
+       .daio_mgr_set_imapnxt = daio_mgr_set_imapnxt,
+       .daio_mgr_set_imapaddr = daio_mgr_set_imapaddr,
+       .daio_mgr_commit_write = daio_mgr_commit_write,
+};
+
+int __devinit create_20k2_hw_obj(struct hw **rhw)
+{
+       struct hw20k2 *hw20k2;
+
+       *rhw = NULL;
+       hw20k2 = kzalloc(sizeof(*hw20k2), GFP_KERNEL);
+       if (!hw20k2)
+               return -ENOMEM;
+
+       hw20k2->hw = ct20k2_preset;
+       *rhw = &hw20k2->hw;
+
+       return 0;
+}
+
+int destroy_20k2_hw_obj(struct hw *hw)
+{
+       if (hw->io_base)
+               hw_card_shutdown(hw);
+
+       kfree(hw);
+       return 0;
+}
diff --git a/sound/pci/ctxfi/cthw20k2.h b/sound/pci/ctxfi/cthw20k2.h
new file mode 100644 (file)
index 0000000..d2b7daa
--- /dev/null
@@ -0,0 +1,26 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File       cthw20k2.h
+ *
+ * @Brief
+ * This file contains the definition of hardware access methord.
+ *
+ * @Author     Liu Chun
+ * @Date       May 13 2008
+ *
+ */
+
+#ifndef CTHW20K2_H
+#define CTHW20K2_H
+
+#include "cthardware.h"
+
+int create_20k2_hw_obj(struct hw **rhw);
+int destroy_20k2_hw_obj(struct hw *hw);
+
+#endif /* CTHW20K2_H */
diff --git a/sound/pci/ctxfi/ctimap.c b/sound/pci/ctxfi/ctimap.c
new file mode 100644 (file)
index 0000000..0b73368
--- /dev/null
@@ -0,0 +1,112 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File       ctimap.c
+ *
+ * @Brief
+ * This file contains the implementation of generic input mapper operations
+ * for input mapper management.
+ *
+ * @Author     Liu Chun
+ * @Date       May 23 2008
+ *
+ */
+
+#include "ctimap.h"
+#include <linux/slab.h>
+
+int input_mapper_add(struct list_head *mappers, struct imapper *entry,
+                    int (*map_op)(void *, struct imapper *), void *data)
+{
+       struct list_head *pos, *pre, *head;
+       struct imapper *pre_ent, *pos_ent;
+
+       head = mappers;
+
+       if (list_empty(head)) {
+               entry->next = entry->addr;
+               map_op(data, entry);
+               list_add(&entry->list, head);
+               return 0;
+       }
+
+       list_for_each(pos, head) {
+               pos_ent = list_entry(pos, struct imapper, list);
+               if (pos_ent->slot > entry->slot) {
+                       /* found a position in list */
+                       break;
+               }
+       }
+
+       if (pos != head) {
+               pre = pos->prev;
+               if (pre == head)
+                       pre = head->prev;
+
+               __list_add(&entry->list, pos->prev, pos);
+       } else {
+               pre = head->prev;
+               pos = head->next;
+               list_add_tail(&entry->list, head);
+       }
+
+       pre_ent = list_entry(pre, struct imapper, list);
+       pos_ent = list_entry(pos, struct imapper, list);
+
+       entry->next = pos_ent->addr;
+       map_op(data, entry);
+       pre_ent->next = entry->addr;
+       map_op(data, pre_ent);
+
+       return 0;
+}
+
+int input_mapper_delete(struct list_head *mappers, struct imapper *entry,
+                    int (*map_op)(void *, struct imapper *), void *data)
+{
+       struct list_head *next, *pre, *head;
+       struct imapper *pre_ent, *next_ent;
+
+       head = mappers;
+
+       if (list_empty(head))
+               return 0;
+
+       pre = (entry->list.prev == head) ? head->prev : entry->list.prev;
+       next = (entry->list.next == head) ? head->next : entry->list.next;
+
+       if (pre == &entry->list) {
+               /* entry is the only one node in mappers list */
+               entry->next = entry->addr = entry->user = entry->slot = 0;
+               map_op(data, entry);
+               list_del(&entry->list);
+               return 0;
+       }
+
+       pre_ent = list_entry(pre, struct imapper, list);
+       next_ent = list_entry(next, struct imapper, list);
+
+       pre_ent->next = next_ent->addr;
+       map_op(data, pre_ent);
+       list_del(&entry->list);
+
+       return 0;
+}
+
+void free_input_mapper_list(struct list_head *head)
+{
+       struct imapper *entry;
+       struct list_head *pos;
+
+       while (!list_empty(head)) {
+               pos = head->next;
+               list_del(pos);
+               entry = list_entry(pos, struct imapper, list);
+               kfree(entry);
+       }
+}
+
diff --git a/sound/pci/ctxfi/ctimap.h b/sound/pci/ctxfi/ctimap.h
new file mode 100644 (file)
index 0000000..53ccf9b
--- /dev/null
@@ -0,0 +1,40 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File       ctimap.h
+ *
+ * @Brief
+ * This file contains the definition of generic input mapper operations
+ * for input mapper management.
+ *
+ * @Author     Liu Chun
+ * @Date       May 23 2008
+ *
+ */
+
+#ifndef CTIMAP_H
+#define CTIMAP_H
+
+#include <linux/list.h>
+
+struct imapper {
+       unsigned short slot; /* the id of the slot containing input data */
+       unsigned short user; /* the id of the user resource consuming data */
+       unsigned short addr; /* the input mapper ram id */
+       unsigned short next; /* the next input mapper ram id */
+       struct list_head        list;
+};
+
+int input_mapper_add(struct list_head *mappers, struct imapper *entry,
+                    int (*map_op)(void *, struct imapper *), void *data);
+
+int input_mapper_delete(struct list_head *mappers, struct imapper *entry,
+                    int (*map_op)(void *, struct imapper *), void *data);
+
+void free_input_mapper_list(struct list_head *mappers);
+
+#endif /* CTIMAP_H */
diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c
new file mode 100644 (file)
index 0000000..666722d
--- /dev/null
@@ -0,0 +1,1123 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File       ctmixer.c
+ *
+ * @Brief
+ * This file contains the implementation of alsa mixer device functions.
+ *
+ * @Author     Liu Chun
+ * @Date       May 28 2008
+ *
+ */
+
+
+#include "ctmixer.h"
+#include "ctamixer.h"
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/asoundef.h>
+#include <sound/pcm.h>
+#include <sound/tlv.h>
+
+enum CT_SUM_CTL {
+       SUM_IN_F,
+       SUM_IN_R,
+       SUM_IN_C,
+       SUM_IN_S,
+       SUM_IN_F_C,
+
+       NUM_CT_SUMS
+};
+
+enum CT_AMIXER_CTL {
+       /* volume control mixers */
+       AMIXER_MASTER_F,
+       AMIXER_MASTER_R,
+       AMIXER_MASTER_C,
+       AMIXER_MASTER_S,
+       AMIXER_PCM_F,
+       AMIXER_PCM_R,
+       AMIXER_PCM_C,
+       AMIXER_PCM_S,
+       AMIXER_SPDIFI,
+       AMIXER_LINEIN,
+       AMIXER_MIC,
+       AMIXER_SPDIFO,
+       AMIXER_WAVE_F,
+       AMIXER_WAVE_R,
+       AMIXER_WAVE_C,
+       AMIXER_WAVE_S,
+       AMIXER_MASTER_F_C,
+       AMIXER_PCM_F_C,
+       AMIXER_SPDIFI_C,
+       AMIXER_LINEIN_C,
+       AMIXER_MIC_C,
+
+       /* this should always be the last one */
+       NUM_CT_AMIXERS
+};
+
+enum CTALSA_MIXER_CTL {
+       /* volume control mixers */
+       MIXER_MASTER_P,
+       MIXER_PCM_P,
+       MIXER_LINEIN_P,
+       MIXER_MIC_P,
+       MIXER_SPDIFI_P,
+       MIXER_SPDIFO_P,
+       MIXER_WAVEF_P,
+       MIXER_WAVER_P,
+       MIXER_WAVEC_P,
+       MIXER_WAVES_P,
+       MIXER_MASTER_C,
+       MIXER_PCM_C,
+       MIXER_LINEIN_C,
+       MIXER_MIC_C,
+       MIXER_SPDIFI_C,
+
+       /* switch control mixers */
+       MIXER_PCM_C_S,
+       MIXER_LINEIN_C_S,
+       MIXER_MIC_C_S,
+       MIXER_SPDIFI_C_S,
+       MIXER_LINEIN_P_S,
+       MIXER_SPDIFO_P_S,
+       MIXER_SPDIFI_P_S,
+       MIXER_WAVEF_P_S,
+       MIXER_WAVER_P_S,
+       MIXER_WAVEC_P_S,
+       MIXER_WAVES_P_S,
+       MIXER_DIGITAL_IO_S,
+       MIXER_IEC958_MASK,
+       MIXER_IEC958_DEFAULT,
+       MIXER_IEC958_STREAM,
+
+       /* this should always be the last one */
+       NUM_CTALSA_MIXERS
+};
+
+#define VOL_MIXER_START                MIXER_MASTER_P
+#define VOL_MIXER_END          MIXER_SPDIFI_C
+#define VOL_MIXER_NUM          (VOL_MIXER_END - VOL_MIXER_START + 1)
+#define SWH_MIXER_START                MIXER_PCM_C_S
+#define SWH_MIXER_END          MIXER_DIGITAL_IO_S
+#define SWH_CAPTURE_START      MIXER_PCM_C_S
+#define SWH_CAPTURE_END                MIXER_SPDIFI_C_S
+
+#define CHN_NUM                2
+
+struct ct_kcontrol_init {
+       unsigned char ctl;
+       char *name;
+};
+
+static struct ct_kcontrol_init
+ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
+       [MIXER_MASTER_P] = {
+               .ctl = 1,
+               .name = "Master Playback Volume",
+       },
+       [MIXER_MASTER_C] = {
+               .ctl = 1,
+               .name = "Master Capture Volume",
+       },
+       [MIXER_PCM_P] = {
+               .ctl = 1,
+               .name = "PCM Playback Volume",
+       },
+       [MIXER_PCM_C] = {
+               .ctl = 1,
+               .name = "PCM Capture Volume",
+       },
+       [MIXER_LINEIN_P] = {
+               .ctl = 1,
+               .name = "Line-in Playback Volume",
+       },
+       [MIXER_LINEIN_C] = {
+               .ctl = 1,
+               .name = "Line-in Capture Volume",
+       },
+       [MIXER_MIC_P] = {
+               .ctl = 1,
+               .name = "Mic Playback Volume",
+       },
+       [MIXER_MIC_C] = {
+               .ctl = 1,
+               .name = "Mic Capture Volume",
+       },
+       [MIXER_SPDIFI_P] = {
+               .ctl = 1,
+               .name = "S/PDIF-in Playback Volume",
+       },
+       [MIXER_SPDIFI_C] = {
+               .ctl = 1,
+               .name = "S/PDIF-in Capture Volume",
+       },
+       [MIXER_SPDIFO_P] = {
+               .ctl = 1,
+               .name = "S/PDIF-out Playback Volume",
+       },
+       [MIXER_WAVEF_P] = {
+               .ctl = 1,
+               .name = "Front Playback Volume",
+       },
+       [MIXER_WAVES_P] = {
+               .ctl = 1,
+               .name = "Side Playback Volume",
+       },
+       [MIXER_WAVEC_P] = {
+               .ctl = 1,
+               .name = "Center/LFE Playback Volume",
+       },
+       [MIXER_WAVER_P] = {
+               .ctl = 1,
+               .name = "Surround Playback Volume",
+       },
+
+       [MIXER_PCM_C_S] = {
+               .ctl = 1,
+               .name = "PCM Capture Switch",
+       },
+       [MIXER_LINEIN_C_S] = {
+               .ctl = 1,
+               .name = "Line-in Capture Switch",
+       },
+       [MIXER_MIC_C_S] = {
+               .ctl = 1,
+               .name = "Mic Capture Switch",
+       },
+       [MIXER_SPDIFI_C_S] = {
+               .ctl = 1,
+               .name = "S/PDIF-in Capture Switch",
+       },
+       [MIXER_LINEIN_P_S] = {
+               .ctl = 1,
+               .name = "Line-in Playback Switch",
+       },
+       [MIXER_SPDIFO_P_S] = {
+               .ctl = 1,
+               .name = "S/PDIF-out Playback Switch",
+       },
+       [MIXER_SPDIFI_P_S] = {
+               .ctl = 1,
+               .name = "S/PDIF-in Playback Switch",
+       },
+       [MIXER_WAVEF_P_S] = {
+               .ctl = 1,
+               .name = "Front Playback Switch",
+       },
+       [MIXER_WAVES_P_S] = {
+               .ctl = 1,
+               .name = "Side Playback Switch",
+       },
+       [MIXER_WAVEC_P_S] = {
+               .ctl = 1,
+               .name = "Center/LFE Playback Switch",
+       },
+       [MIXER_WAVER_P_S] = {
+               .ctl = 1,
+               .name = "Surround Playback Switch",
+       },
+       [MIXER_DIGITAL_IO_S] = {
+               .ctl = 0,
+               .name = "Digit-IO Playback Switch",
+       },
+};
+
+static void
+ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type);
+
+static void
+ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type);
+
+static struct snd_kcontrol *kctls[2] = {NULL};
+
+static enum CT_AMIXER_CTL get_amixer_index(enum CTALSA_MIXER_CTL alsa_index)
+{
+       switch (alsa_index) {
+       case MIXER_MASTER_P:    return AMIXER_MASTER_F;
+       case MIXER_MASTER_C:    return AMIXER_MASTER_F_C;
+       case MIXER_PCM_P:       return AMIXER_PCM_F;
+       case MIXER_PCM_C:
+       case MIXER_PCM_C_S:     return AMIXER_PCM_F_C;
+       case MIXER_LINEIN_P:    return AMIXER_LINEIN;
+       case MIXER_LINEIN_C:
+       case MIXER_LINEIN_C_S:  return AMIXER_LINEIN_C;
+       case MIXER_MIC_P:       return AMIXER_MIC;
+       case MIXER_MIC_C:
+       case MIXER_MIC_C_S:     return AMIXER_MIC_C;
+       case MIXER_SPDIFI_P:    return AMIXER_SPDIFI;
+       case MIXER_SPDIFI_C:
+       case MIXER_SPDIFI_C_S:  return AMIXER_SPDIFI_C;
+       case MIXER_SPDIFO_P:    return AMIXER_SPDIFO;
+       case MIXER_WAVEF_P:     return AMIXER_WAVE_F;
+       case MIXER_WAVES_P:     return AMIXER_WAVE_S;
+       case MIXER_WAVEC_P:     return AMIXER_WAVE_C;
+       case MIXER_WAVER_P:     return AMIXER_WAVE_R;
+       default:                return NUM_CT_AMIXERS;
+       }
+}
+
+static enum CT_AMIXER_CTL get_recording_amixer(enum CT_AMIXER_CTL index)
+{
+       switch (index) {
+       case AMIXER_MASTER_F:   return AMIXER_MASTER_F_C;
+       case AMIXER_PCM_F:      return AMIXER_PCM_F_C;
+       case AMIXER_SPDIFI:     return AMIXER_SPDIFI_C;
+       case AMIXER_LINEIN:     return AMIXER_LINEIN_C;
+       case AMIXER_MIC:        return AMIXER_MIC_C;
+       default:                return NUM_CT_AMIXERS;
+       }
+}
+
+static unsigned char
+get_switch_state(struct ct_mixer *mixer, enum CTALSA_MIXER_CTL type)
+{
+       return (mixer->switch_state & (0x1 << (type - SWH_MIXER_START)))
+               ? 1 : 0;
+}
+
+static void
+set_switch_state(struct ct_mixer *mixer,
+                enum CTALSA_MIXER_CTL type, unsigned char state)
+{
+       if (state)
+               mixer->switch_state |= (0x1 << (type - SWH_MIXER_START));
+       else
+               mixer->switch_state &= ~(0x1 << (type - SWH_MIXER_START));
+}
+
+#if 0 /* not used */
+/* Map integer value ranging from 0 to 65535 to 14-bit float value ranging
+ * from 2^-6 to (1+1023/1024) */
+static unsigned int uint16_to_float14(unsigned int x)
+{
+       unsigned int i;
+
+       if (x < 17)
+               return 0;
+
+       x *= 2031;
+       x /= 65535;
+       x += 16;
+
+       /* i <= 6 */
+       for (i = 0; !(x & 0x400); i++)
+               x <<= 1;
+
+       x = (((7 - i) & 0x7) << 10) | (x & 0x3ff);
+
+       return x;
+}
+
+static unsigned int float14_to_uint16(unsigned int x)
+{
+       unsigned int e;
+
+       if (!x)
+               return x;
+
+       e = (x >> 10) & 0x7;
+       x &= 0x3ff;
+       x += 1024;
+       x >>= (7 - e);
+       x -= 16;
+       x *= 65535;
+       x /= 2031;
+
+       return x;
+}
+#endif /* not used */
+
+#define VOL_SCALE      0x1c
+#define VOL_MAX                0x100
+
+static const DECLARE_TLV_DB_SCALE(ct_vol_db_scale, -6400, 25, 1);
+
+static int ct_alsa_mix_volume_info(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = VOL_MAX;
+
+       return 0;
+}
+
+static int ct_alsa_mix_volume_get(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
+       enum CT_AMIXER_CTL type = get_amixer_index(kcontrol->private_value);
+       struct amixer *amixer;
+       int i, val;
+
+       for (i = 0; i < 2; i++) {
+               amixer = ((struct ct_mixer *)atc->mixer)->
+                                               amixers[type*CHN_NUM+i];
+               val = amixer->ops->get_scale(amixer) / VOL_SCALE;
+               if (val < 0)
+                       val = 0;
+               else if (val > VOL_MAX)
+                       val = VOL_MAX;
+               ucontrol->value.integer.value[i] = val;
+       }
+
+       return 0;
+}
+
+static int ct_alsa_mix_volume_put(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
+       struct ct_mixer *mixer = atc->mixer;
+       enum CT_AMIXER_CTL type = get_amixer_index(kcontrol->private_value);
+       struct amixer *amixer;
+       int i, j, val, oval, change = 0;
+
+       for (i = 0; i < 2; i++) {
+               val = ucontrol->value.integer.value[i];
+               if (val < 0)
+                       val = 0;
+               else if (val > VOL_MAX)
+                       val = VOL_MAX;
+               val *= VOL_SCALE;
+               amixer = mixer->amixers[type*CHN_NUM+i];
+               oval = amixer->ops->get_scale(amixer);
+               if (val != oval) {
+                       amixer->ops->set_scale(amixer, val);
+                       amixer->ops->commit_write(amixer);
+                       change = 1;
+                       /* Synchronize Master/PCM playback AMIXERs. */
+                       if (AMIXER_MASTER_F == type || AMIXER_PCM_F == type) {
+                               for (j = 1; j < 4; j++) {
+                                       amixer = mixer->
+                                               amixers[(type+j)*CHN_NUM+i];
+                                       amixer->ops->set_scale(amixer, val);
+                                       amixer->ops->commit_write(amixer);
+                               }
+                       }
+               }
+       }
+
+       return change;
+}
+
+static struct snd_kcontrol_new vol_ctl = {
+       .access         = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                         SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+       .iface          = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .info           = ct_alsa_mix_volume_info,
+       .get            = ct_alsa_mix_volume_get,
+       .put            = ct_alsa_mix_volume_put,
+       .tlv            = { .p =  ct_vol_db_scale },
+};
+
+static void
+do_line_mic_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type)
+{
+
+       if (MIXER_LINEIN_C_S == type) {
+               atc->select_line_in(atc);
+               set_switch_state(atc->mixer, MIXER_MIC_C_S, 0);
+               snd_ctl_notify(atc->card, SNDRV_CTL_EVENT_MASK_VALUE,
+                                                       &kctls[1]->id);
+       } else if (MIXER_MIC_C_S == type) {
+               atc->select_mic_in(atc);
+               set_switch_state(atc->mixer, MIXER_LINEIN_C_S, 0);
+               snd_ctl_notify(atc->card, SNDRV_CTL_EVENT_MASK_VALUE,
+                                                       &kctls[0]->id);
+       }
+}
+
+static void
+do_digit_io_switch(struct ct_atc *atc, int state)
+{
+       struct ct_mixer *mixer = atc->mixer;
+
+       if (state) {
+               atc->select_digit_io(atc);
+               atc->spdif_out_unmute(atc,
+                               get_switch_state(mixer, MIXER_SPDIFO_P_S));
+               atc->spdif_in_unmute(atc, 1);
+               atc->line_in_unmute(atc, 0);
+               return;
+       }
+
+       if (get_switch_state(mixer, MIXER_LINEIN_C_S))
+               atc->select_line_in(atc);
+       else if (get_switch_state(mixer, MIXER_MIC_C_S))
+               atc->select_mic_in(atc);
+
+       atc->spdif_out_unmute(atc, 0);
+       atc->spdif_in_unmute(atc, 0);
+       atc->line_in_unmute(atc, 1);
+       return;
+}
+
+static int ct_alsa_mix_switch_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;
+       uinfo->value.integer.step = 1;
+
+       return 0;
+}
+
+static int ct_alsa_mix_switch_get(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct ct_mixer *mixer =
+               ((struct ct_atc *)snd_kcontrol_chip(kcontrol))->mixer;
+       enum CTALSA_MIXER_CTL type = kcontrol->private_value;
+
+       ucontrol->value.integer.value[0] = get_switch_state(mixer, type);
+       return 0;
+}
+
+static int ct_alsa_mix_switch_put(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
+       struct ct_mixer *mixer = atc->mixer;
+       enum CTALSA_MIXER_CTL type = kcontrol->private_value;
+       int state;
+
+       state = ucontrol->value.integer.value[0];
+       if (get_switch_state(mixer, type) == state)
+               return 0;
+
+       set_switch_state(mixer, type, state);
+       /* Do changes in mixer. */
+       if ((SWH_CAPTURE_START <= type) && (SWH_CAPTURE_END >= type)) {
+               if (state) {
+                       ct_mixer_recording_select(mixer,
+                                                 get_amixer_index(type));
+               } else {
+                       ct_mixer_recording_unselect(mixer,
+                                                   get_amixer_index(type));
+               }
+       }
+       /* Do changes out of mixer. */
+       if (state && (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type))
+               do_line_mic_switch(atc, type);
+       else if (MIXER_WAVEF_P_S == type)
+               atc->line_front_unmute(atc, state);
+       else if (MIXER_WAVES_P_S == type)
+               atc->line_surround_unmute(atc, state);
+       else if (MIXER_WAVEC_P_S == type)
+               atc->line_clfe_unmute(atc, state);
+       else if (MIXER_WAVER_P_S == type)
+               atc->line_rear_unmute(atc, state);
+       else if (MIXER_LINEIN_P_S == type)
+               atc->line_in_unmute(atc, state);
+       else if (MIXER_SPDIFO_P_S == type)
+               atc->spdif_out_unmute(atc, state);
+       else if (MIXER_SPDIFI_P_S == type)
+               atc->spdif_in_unmute(atc, state);
+       else if (MIXER_DIGITAL_IO_S == type)
+               do_digit_io_switch(atc, state);
+
+       return 1;
+}
+
+static struct snd_kcontrol_new swh_ctl = {
+       .access         = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .iface          = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .info           = ct_alsa_mix_switch_info,
+       .get            = ct_alsa_mix_switch_get,
+       .put            = ct_alsa_mix_switch_put
+};
+
+static int ct_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 ct_spdif_get_mask(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.iec958.status[0] = 0xff;
+       ucontrol->value.iec958.status[1] = 0xff;
+       ucontrol->value.iec958.status[2] = 0xff;
+       ucontrol->value.iec958.status[3] = 0xff;
+       return 0;
+}
+
+static int ct_spdif_default_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       unsigned int status = SNDRV_PCM_DEFAULT_CON_SPDIF;
+
+       ucontrol->value.iec958.status[0] = (status >> 0) & 0xff;
+       ucontrol->value.iec958.status[1] = (status >> 8) & 0xff;
+       ucontrol->value.iec958.status[2] = (status >> 16) & 0xff;
+       ucontrol->value.iec958.status[3] = (status >> 24) & 0xff;
+
+       return 0;
+}
+
+static int ct_spdif_get(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
+       unsigned int status;
+
+       atc->spdif_out_get_status(atc, &status);
+       ucontrol->value.iec958.status[0] = (status >> 0) & 0xff;
+       ucontrol->value.iec958.status[1] = (status >> 8) & 0xff;
+       ucontrol->value.iec958.status[2] = (status >> 16) & 0xff;
+       ucontrol->value.iec958.status[3] = (status >> 24) & 0xff;
+
+       return 0;
+}
+
+static int ct_spdif_put(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
+       int change;
+       unsigned int status, old_status;
+
+       status = (ucontrol->value.iec958.status[0] << 0) |
+                (ucontrol->value.iec958.status[1] << 8) |
+                (ucontrol->value.iec958.status[2] << 16) |
+                (ucontrol->value.iec958.status[3] << 24);
+
+       atc->spdif_out_get_status(atc, &old_status);
+       change = (old_status != status);
+       if (change)
+               atc->spdif_out_set_status(atc, status);
+
+       return change;
+}
+
+static struct snd_kcontrol_new iec958_mask_ctl = {
+       .access         = SNDRV_CTL_ELEM_ACCESS_READ,
+       .iface          = SNDRV_CTL_ELEM_IFACE_PCM,
+       .name           = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
+       .count          = 1,
+       .info           = ct_spdif_info,
+       .get            = ct_spdif_get_mask,
+       .private_value  = MIXER_IEC958_MASK
+};
+
+static struct snd_kcontrol_new iec958_default_ctl = {
+       .iface          = SNDRV_CTL_ELEM_IFACE_PCM,
+       .name           = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+       .count          = 1,
+       .info           = ct_spdif_info,
+       .get            = ct_spdif_default_get,
+       .put            = ct_spdif_put,
+       .private_value  = MIXER_IEC958_DEFAULT
+};
+
+static struct snd_kcontrol_new iec958_ctl = {
+       .access         = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .iface          = SNDRV_CTL_ELEM_IFACE_PCM,
+       .name           = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
+       .count          = 1,
+       .info           = ct_spdif_info,
+       .get            = ct_spdif_get,
+       .put            = ct_spdif_put,
+       .private_value  = MIXER_IEC958_STREAM
+};
+
+#define NUM_IEC958_CTL 3
+
+static int
+ct_mixer_kcontrol_new(struct ct_mixer *mixer, struct snd_kcontrol_new *new)
+{
+       struct snd_kcontrol *kctl;
+       int err;
+
+       kctl = snd_ctl_new1(new, mixer->atc);
+       if (NULL == kctl)
+               return -ENOMEM;
+
+       if (SNDRV_CTL_ELEM_IFACE_PCM == kctl->id.iface)
+               kctl->id.device = IEC958;
+
+       err = snd_ctl_add(mixer->atc->card, kctl);
+       if (err)
+               return err;
+
+       switch (new->private_value) {
+       case MIXER_LINEIN_C_S:
+               kctls[0] = kctl; break;
+       case MIXER_MIC_C_S:
+               kctls[1] = kctl; break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)
+{
+       enum CTALSA_MIXER_CTL type;
+       struct ct_atc *atc = mixer->atc;
+       int err;
+
+       /* Create snd kcontrol instances on demand */
+       for (type = VOL_MIXER_START; type <= VOL_MIXER_END; type++) {
+               if (ct_kcontrol_init_table[type].ctl) {
+                       vol_ctl.name = ct_kcontrol_init_table[type].name;
+                       vol_ctl.private_value = (unsigned long)type;
+                       err = ct_mixer_kcontrol_new(mixer, &vol_ctl);
+                       if (err)
+                               return err;
+               }
+       }
+
+       ct_kcontrol_init_table[MIXER_DIGITAL_IO_S].ctl =
+                                       atc->have_digit_io_switch(atc);
+       for (type = SWH_MIXER_START; type <= SWH_MIXER_END; type++) {
+               if (ct_kcontrol_init_table[type].ctl) {
+                       swh_ctl.name = ct_kcontrol_init_table[type].name;
+                       swh_ctl.private_value = (unsigned long)type;
+                       err = ct_mixer_kcontrol_new(mixer, &swh_ctl);
+                       if (err)
+                               return err;
+               }
+       }
+
+       err = ct_mixer_kcontrol_new(mixer, &iec958_mask_ctl);
+       if (err)
+               return err;
+
+       err = ct_mixer_kcontrol_new(mixer, &iec958_default_ctl);
+       if (err)
+               return err;
+
+       err = ct_mixer_kcontrol_new(mixer, &iec958_ctl);
+       if (err)
+               return err;
+
+       atc->line_front_unmute(atc, 1);
+       set_switch_state(mixer, MIXER_WAVEF_P_S, 1);
+       atc->line_surround_unmute(atc, 0);
+       set_switch_state(mixer, MIXER_WAVES_P_S, 0);
+       atc->line_clfe_unmute(atc, 0);
+       set_switch_state(mixer, MIXER_WAVEC_P_S, 0);
+       atc->line_rear_unmute(atc, 0);
+       set_switch_state(mixer, MIXER_WAVER_P_S, 0);
+       atc->spdif_out_unmute(atc, 0);
+       set_switch_state(mixer, MIXER_SPDIFO_P_S, 0);
+       atc->line_in_unmute(atc, 0);
+       set_switch_state(mixer, MIXER_LINEIN_P_S, 0);
+       atc->spdif_in_unmute(atc, 0);
+       set_switch_state(mixer, MIXER_SPDIFI_P_S, 0);
+
+       set_switch_state(mixer, MIXER_PCM_C_S, 1);
+       set_switch_state(mixer, MIXER_LINEIN_C_S, 1);
+       set_switch_state(mixer, MIXER_SPDIFI_C_S, 1);
+
+       return 0;
+}
+
+static void
+ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type)
+{
+       struct amixer *amix_d;
+       struct sum *sum_c;
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               amix_d = mixer->amixers[type*CHN_NUM+i];
+               sum_c = mixer->sums[SUM_IN_F_C*CHN_NUM+i];
+               amix_d->ops->set_sum(amix_d, sum_c);
+               amix_d->ops->commit_write(amix_d);
+       }
+}
+
+static void
+ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type)
+{
+       struct amixer *amix_d;
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               amix_d = mixer->amixers[type*CHN_NUM+i];
+               amix_d->ops->set_sum(amix_d, NULL);
+               amix_d->ops->commit_write(amix_d);
+       }
+}
+
+static int ct_mixer_get_resources(struct ct_mixer *mixer)
+{
+       struct sum_mgr *sum_mgr;
+       struct sum *sum;
+       struct sum_desc sum_desc = {0};
+       struct amixer_mgr *amixer_mgr;
+       struct amixer *amixer;
+       struct amixer_desc am_desc = {0};
+       int err;
+       int i;
+
+       /* Allocate sum resources for mixer obj */
+       sum_mgr = (struct sum_mgr *)mixer->atc->rsc_mgrs[SUM];
+       sum_desc.msr = mixer->atc->msr;
+       for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) {
+               err = sum_mgr->get_sum(sum_mgr, &sum_desc, &sum);
+               if (err) {
+                       printk(KERN_ERR "ctxfi:Failed to get sum resources for "
+                                         "front output!\n");
+                       break;
+               }
+               mixer->sums[i] = sum;
+       }
+       if (err)
+               goto error1;
+
+       /* Allocate amixer resources for mixer obj */
+       amixer_mgr = (struct amixer_mgr *)mixer->atc->rsc_mgrs[AMIXER];
+       am_desc.msr = mixer->atc->msr;
+       for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) {
+               err = amixer_mgr->get_amixer(amixer_mgr, &am_desc, &amixer);
+               if (err) {
+                       printk(KERN_ERR "ctxfi:Failed to get amixer resources "
+                              "for mixer obj!\n");
+                       break;
+               }
+               mixer->amixers[i] = amixer;
+       }
+       if (err)
+               goto error2;
+
+       return 0;
+
+error2:
+       for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) {
+               if (NULL != mixer->amixers[i]) {
+                       amixer = mixer->amixers[i];
+                       amixer_mgr->put_amixer(amixer_mgr, amixer);
+                       mixer->amixers[i] = NULL;
+               }
+       }
+error1:
+       for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) {
+               if (NULL != mixer->sums[i]) {
+                       sum_mgr->put_sum(sum_mgr, (struct sum *)mixer->sums[i]);
+                       mixer->sums[i] = NULL;
+               }
+       }
+
+       return err;
+}
+
+static int ct_mixer_get_mem(struct ct_mixer **rmixer)
+{
+       struct ct_mixer *mixer;
+       int err;
+
+       *rmixer = NULL;
+       /* Allocate mem for mixer obj */
+       mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);
+       if (NULL == mixer)
+               return -ENOMEM;
+
+       mixer->amixers = kzalloc(sizeof(void *)*(NUM_CT_AMIXERS*CHN_NUM),
+                                GFP_KERNEL);
+       if (NULL == mixer->amixers) {
+               err = -ENOMEM;
+               goto error1;
+       }
+       mixer->sums = kzalloc(sizeof(void *)*(NUM_CT_SUMS*CHN_NUM), GFP_KERNEL);
+       if (NULL == mixer->sums) {
+               err = -ENOMEM;
+               goto error2;
+       }
+
+       *rmixer = mixer;
+       return 0;
+
+error2:
+       kfree(mixer->amixers);
+error1:
+       kfree(mixer);
+       return err;
+}
+
+static int ct_mixer_topology_build(struct ct_mixer *mixer)
+{
+       struct sum *sum;
+       struct amixer *amix_d, *amix_s;
+       enum CT_AMIXER_CTL i, j;
+
+       /* Build topology from destination to source */
+
+       /* Set up Master mixer */
+       for (i = AMIXER_MASTER_F, j = SUM_IN_F;
+                                       i <= AMIXER_MASTER_S; i++, j++) {
+               amix_d = mixer->amixers[i*CHN_NUM];
+               sum = mixer->sums[j*CHN_NUM];
+               amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
+               amix_d = mixer->amixers[i*CHN_NUM+1];
+               sum = mixer->sums[j*CHN_NUM+1];
+               amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
+       }
+
+       /* Set up Wave-out mixer */
+       for (i = AMIXER_WAVE_F, j = AMIXER_MASTER_F;
+                                       i <= AMIXER_WAVE_S; i++, j++) {
+               amix_d = mixer->amixers[i*CHN_NUM];
+               amix_s = mixer->amixers[j*CHN_NUM];
+               amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
+               amix_d = mixer->amixers[i*CHN_NUM+1];
+               amix_s = mixer->amixers[j*CHN_NUM+1];
+               amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
+       }
+
+       /* Set up S/PDIF-out mixer */
+       amix_d = mixer->amixers[AMIXER_SPDIFO*CHN_NUM];
+       amix_s = mixer->amixers[AMIXER_MASTER_F*CHN_NUM];
+       amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
+       amix_d = mixer->amixers[AMIXER_SPDIFO*CHN_NUM+1];
+       amix_s = mixer->amixers[AMIXER_MASTER_F*CHN_NUM+1];
+       amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
+
+       /* Set up PCM-in mixer */
+       for (i = AMIXER_PCM_F, j = SUM_IN_F; i <= AMIXER_PCM_S; i++, j++) {
+               amix_d = mixer->amixers[i*CHN_NUM];
+               sum = mixer->sums[j*CHN_NUM];
+               amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+               amix_d = mixer->amixers[i*CHN_NUM+1];
+               sum = mixer->sums[j*CHN_NUM+1];
+               amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+       }
+
+       /* Set up Line-in mixer */
+       amix_d = mixer->amixers[AMIXER_LINEIN*CHN_NUM];
+       sum = mixer->sums[SUM_IN_F*CHN_NUM];
+       amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+       amix_d = mixer->amixers[AMIXER_LINEIN*CHN_NUM+1];
+       sum = mixer->sums[SUM_IN_F*CHN_NUM+1];
+       amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+
+       /* Set up Mic-in mixer */
+       amix_d = mixer->amixers[AMIXER_MIC*CHN_NUM];
+       sum = mixer->sums[SUM_IN_F*CHN_NUM];
+       amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+       amix_d = mixer->amixers[AMIXER_MIC*CHN_NUM+1];
+       sum = mixer->sums[SUM_IN_F*CHN_NUM+1];
+       amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+
+       /* Set up S/PDIF-in mixer */
+       amix_d = mixer->amixers[AMIXER_SPDIFI*CHN_NUM];
+       sum = mixer->sums[SUM_IN_F*CHN_NUM];
+       amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+       amix_d = mixer->amixers[AMIXER_SPDIFI*CHN_NUM+1];
+       sum = mixer->sums[SUM_IN_F*CHN_NUM+1];
+       amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+
+       /* Set up Master recording mixer */
+       amix_d = mixer->amixers[AMIXER_MASTER_F_C*CHN_NUM];
+       sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
+       amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
+       amix_d = mixer->amixers[AMIXER_MASTER_F_C*CHN_NUM+1];
+       sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
+       amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
+
+       /* Set up PCM-in recording mixer */
+       amix_d = mixer->amixers[AMIXER_PCM_F_C*CHN_NUM];
+       sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
+       amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+       amix_d = mixer->amixers[AMIXER_PCM_F_C*CHN_NUM+1];
+       sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
+       amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+
+       /* Set up Line-in recording mixer */
+       amix_d = mixer->amixers[AMIXER_LINEIN_C*CHN_NUM];
+       sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
+       amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+       amix_d = mixer->amixers[AMIXER_LINEIN_C*CHN_NUM+1];
+       sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
+       amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+
+       /* Set up Mic-in recording mixer */
+       amix_d = mixer->amixers[AMIXER_MIC_C*CHN_NUM];
+       sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
+       amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+       amix_d = mixer->amixers[AMIXER_MIC_C*CHN_NUM+1];
+       sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
+       amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+
+       /* Set up S/PDIF-in recording mixer */
+       amix_d = mixer->amixers[AMIXER_SPDIFI_C*CHN_NUM];
+       sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
+       amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+       amix_d = mixer->amixers[AMIXER_SPDIFI_C*CHN_NUM+1];
+       sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
+       amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
+
+       return 0;
+}
+
+static int mixer_set_input_port(struct amixer *amixer, struct rsc *rsc)
+{
+       amixer->ops->set_input(amixer, rsc);
+       amixer->ops->commit_write(amixer);
+
+       return 0;
+}
+
+static enum CT_AMIXER_CTL port_to_amixer(enum MIXER_PORT_T type)
+{
+       switch (type) {
+       case MIX_WAVE_FRONT:    return AMIXER_WAVE_F;
+       case MIX_WAVE_SURROUND: return AMIXER_WAVE_S;
+       case MIX_WAVE_CENTLFE:  return AMIXER_WAVE_C;
+       case MIX_WAVE_REAR:     return AMIXER_WAVE_R;
+       case MIX_PCMO_FRONT:    return AMIXER_MASTER_F_C;
+       case MIX_SPDIF_OUT:     return AMIXER_SPDIFO;
+       case MIX_LINE_IN:       return AMIXER_LINEIN;
+       case MIX_MIC_IN:        return AMIXER_MIC;
+       case MIX_SPDIF_IN:      return AMIXER_SPDIFI;
+       case MIX_PCMI_FRONT:    return AMIXER_PCM_F;
+       case MIX_PCMI_SURROUND: return AMIXER_PCM_S;
+       case MIX_PCMI_CENTLFE:  return AMIXER_PCM_C;
+       case MIX_PCMI_REAR:     return AMIXER_PCM_R;
+       default:                return 0;
+       }
+}
+
+static int mixer_get_output_ports(struct ct_mixer *mixer,
+                                 enum MIXER_PORT_T type,
+                                 struct rsc **rleft, struct rsc **rright)
+{
+       enum CT_AMIXER_CTL amix = port_to_amixer(type);
+
+       if (NULL != rleft)
+               *rleft = &((struct amixer *)mixer->amixers[amix*CHN_NUM])->rsc;
+
+       if (NULL != rright)
+               *rright =
+                       &((struct amixer *)mixer->amixers[amix*CHN_NUM+1])->rsc;
+
+       return 0;
+}
+
+static int mixer_set_input_left(struct ct_mixer *mixer,
+                               enum MIXER_PORT_T type, struct rsc *rsc)
+{
+       enum CT_AMIXER_CTL amix = port_to_amixer(type);
+
+       mixer_set_input_port(mixer->amixers[amix*CHN_NUM], rsc);
+       amix = get_recording_amixer(amix);
+       if (amix < NUM_CT_AMIXERS)
+               mixer_set_input_port(mixer->amixers[amix*CHN_NUM], rsc);
+
+       return 0;
+}
+
+static int
+mixer_set_input_right(struct ct_mixer *mixer,
+                     enum MIXER_PORT_T type, struct rsc *rsc)
+{
+       enum CT_AMIXER_CTL amix = port_to_amixer(type);
+
+       mixer_set_input_port(mixer->amixers[amix*CHN_NUM+1], rsc);
+       amix = get_recording_amixer(amix);
+       if (amix < NUM_CT_AMIXERS)
+               mixer_set_input_port(mixer->amixers[amix*CHN_NUM+1], rsc);
+
+       return 0;
+}
+
+int ct_mixer_destroy(struct ct_mixer *mixer)
+{
+       struct sum_mgr *sum_mgr = (struct sum_mgr *)mixer->atc->rsc_mgrs[SUM];
+       struct amixer_mgr *amixer_mgr =
+                       (struct amixer_mgr *)mixer->atc->rsc_mgrs[AMIXER];
+       struct amixer *amixer;
+       int i = 0;
+
+       /* Release amixer resources */
+       for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) {
+               if (NULL != mixer->amixers[i]) {
+                       amixer = mixer->amixers[i];
+                       amixer_mgr->put_amixer(amixer_mgr, amixer);
+               }
+       }
+
+       /* Release sum resources */
+       for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) {
+               if (NULL != mixer->sums[i])
+                       sum_mgr->put_sum(sum_mgr, (struct sum *)mixer->sums[i]);
+       }
+
+       /* Release mem assigned to mixer object */
+       kfree(mixer->sums);
+       kfree(mixer->amixers);
+       kfree(mixer);
+
+       return 0;
+}
+
+int ct_mixer_create(struct ct_atc *atc, struct ct_mixer **rmixer)
+{
+       struct ct_mixer *mixer;
+       int err;
+
+       *rmixer = NULL;
+
+       /* Allocate mem for mixer obj */
+       err = ct_mixer_get_mem(&mixer);
+       if (err)
+               return err;
+
+       mixer->switch_state = 0;
+       mixer->atc = atc;
+       /* Set operations */
+       mixer->get_output_ports = mixer_get_output_ports;
+       mixer->set_input_left = mixer_set_input_left;
+       mixer->set_input_right = mixer_set_input_right;
+
+       /* Allocate chip resources for mixer obj */
+       err = ct_mixer_get_resources(mixer);
+       if (err)
+               goto error;
+
+       /* Build internal mixer topology */
+       ct_mixer_topology_build(mixer);
+
+       *rmixer = mixer;
+
+       return 0;
+
+error:
+       ct_mixer_destroy(mixer);
+       return err;
+}
+
+int ct_alsa_mix_create(struct ct_atc *atc,
+                      enum CTALSADEVS device,
+                      const char *device_name)
+{
+       int err;
+
+       /* Create snd kcontrol instances on demand */
+       /* vol_ctl.device = swh_ctl.device = device; */ /* better w/ device 0 */
+       err = ct_mixer_kcontrols_create((struct ct_mixer *)atc->mixer);
+       if (err)
+               return err;
+
+       strcpy(atc->card->mixername, device_name);
+
+       return 0;
+}
diff --git a/sound/pci/ctxfi/ctmixer.h b/sound/pci/ctxfi/ctmixer.h
new file mode 100644 (file)
index 0000000..e2d96eb
--- /dev/null
@@ -0,0 +1,67 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File       ctmixer.h
+ *
+ * @Brief
+ * This file contains the definition of the mixer device functions.
+ *
+ * @Author     Liu Chun
+ * @Date       Mar 28 2008
+ *
+ */
+
+#ifndef CTMIXER_H
+#define CTMIXER_H
+
+#include "ctatc.h"
+#include "ctresource.h"
+
+#define INIT_VOL       0x1c00
+
+enum MIXER_PORT_T {
+       MIX_WAVE_FRONT,
+       MIX_WAVE_REAR,
+       MIX_WAVE_CENTLFE,
+       MIX_WAVE_SURROUND,
+       MIX_SPDIF_OUT,
+       MIX_PCMO_FRONT,
+       MIX_MIC_IN,
+       MIX_LINE_IN,
+       MIX_SPDIF_IN,
+       MIX_PCMI_FRONT,
+       MIX_PCMI_REAR,
+       MIX_PCMI_CENTLFE,
+       MIX_PCMI_SURROUND,
+
+       NUM_MIX_PORTS
+};
+
+/* alsa mixer descriptor */
+struct ct_mixer {
+       struct ct_atc *atc;
+
+       void **amixers;         /* amixer resources for volume control */
+       void **sums;            /* sum resources for signal collection */
+       unsigned int switch_state; /* A bit-map to indicate state of switches */
+
+       int (*get_output_ports)(struct ct_mixer *mixer, enum MIXER_PORT_T type,
+                                 struct rsc **rleft, struct rsc **rright);
+
+       int (*set_input_left)(struct ct_mixer *mixer,
+                             enum MIXER_PORT_T type, struct rsc *rsc);
+       int (*set_input_right)(struct ct_mixer *mixer,
+                              enum MIXER_PORT_T type, struct rsc *rsc);
+};
+
+int ct_alsa_mix_create(struct ct_atc *atc,
+                      enum CTALSADEVS device,
+                      const char *device_name);
+int ct_mixer_create(struct ct_atc *atc, struct ct_mixer **rmixer);
+int ct_mixer_destroy(struct ct_mixer *mixer);
+
+#endif /* CTMIXER_H */
diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c
new file mode 100644 (file)
index 0000000..9e5c0c4
--- /dev/null
@@ -0,0 +1,426 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File       ctpcm.c
+ *
+ * @Brief
+ * This file contains the definition of the pcm device functions.
+ *
+ * @Author     Liu Chun
+ * @Date       Apr 2 2008
+ *
+ */
+
+#include "ctpcm.h"
+#include "cttimer.h"
+#include <sound/pcm.h>
+
+/* Hardware descriptions for playback */
+static struct snd_pcm_hardware ct_pcm_playback_hw = {
+       .info                   = (SNDRV_PCM_INFO_MMAP |
+                                  SNDRV_PCM_INFO_INTERLEAVED |
+                                  SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                                  SNDRV_PCM_INFO_MMAP_VALID |
+                                  SNDRV_PCM_INFO_PAUSE),
+       .formats                = (SNDRV_PCM_FMTBIT_U8 |
+                                  SNDRV_PCM_FMTBIT_S16_LE |
+                                  SNDRV_PCM_FMTBIT_S24_3LE |
+                                  SNDRV_PCM_FMTBIT_S32_LE |
+                                  SNDRV_PCM_FMTBIT_FLOAT_LE),
+       .rates                  = (SNDRV_PCM_RATE_CONTINUOUS |
+                                  SNDRV_PCM_RATE_8000_192000),
+       .rate_min               = 8000,
+       .rate_max               = 192000,
+       .channels_min           = 1,
+       .channels_max           = 2,
+       .buffer_bytes_max       = (128*1024),
+       .period_bytes_min       = (64),
+       .period_bytes_max       = (128*1024),
+       .periods_min            = 2,
+       .periods_max            = 1024,
+       .fifo_size              = 0,
+};
+
+static struct snd_pcm_hardware ct_spdif_passthru_playback_hw = {
+       .info                   = (SNDRV_PCM_INFO_MMAP |
+                                  SNDRV_PCM_INFO_INTERLEAVED |
+                                  SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                                  SNDRV_PCM_INFO_MMAP_VALID |
+                                  SNDRV_PCM_INFO_PAUSE),
+       .formats                = SNDRV_PCM_FMTBIT_S16_LE,
+       .rates                  = (SNDRV_PCM_RATE_48000 |
+                                  SNDRV_PCM_RATE_44100 |
+                                  SNDRV_PCM_RATE_32000),
+       .rate_min               = 32000,
+       .rate_max               = 48000,
+       .channels_min           = 2,
+       .channels_max           = 2,
+       .buffer_bytes_max       = (128*1024),
+       .period_bytes_min       = (64),
+       .period_bytes_max       = (128*1024),
+       .periods_min            = 2,
+       .periods_max            = 1024,
+       .fifo_size              = 0,
+};
+
+/* Hardware descriptions for capture */
+static struct snd_pcm_hardware ct_pcm_capture_hw = {
+       .info                   = (SNDRV_PCM_INFO_MMAP |
+                                  SNDRV_PCM_INFO_INTERLEAVED |
+                                  SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                                  SNDRV_PCM_INFO_PAUSE |
+                                  SNDRV_PCM_INFO_MMAP_VALID),
+       .formats                = (SNDRV_PCM_FMTBIT_U8 |
+                                  SNDRV_PCM_FMTBIT_S16_LE |
+                                  SNDRV_PCM_FMTBIT_S24_3LE |
+                                  SNDRV_PCM_FMTBIT_S32_LE |
+                                  SNDRV_PCM_FMTBIT_FLOAT_LE),
+       .rates                  = (SNDRV_PCM_RATE_CONTINUOUS |
+                                  SNDRV_PCM_RATE_8000_96000),
+       .rate_min               = 8000,
+       .rate_max               = 96000,
+       .channels_min           = 1,
+       .channels_max           = 2,
+       .buffer_bytes_max       = (128*1024),
+       .period_bytes_min       = (384),
+       .period_bytes_max       = (64*1024),
+       .periods_min            = 2,
+       .periods_max            = 1024,
+       .fifo_size              = 0,
+};
+
+static void ct_atc_pcm_interrupt(struct ct_atc_pcm *atc_pcm)
+{
+       struct ct_atc_pcm *apcm = atc_pcm;
+
+       if (NULL == apcm->substream)
+               return;
+
+       snd_pcm_period_elapsed(apcm->substream);
+}
+
+static void ct_atc_pcm_free_substream(struct snd_pcm_runtime *runtime)
+{
+       struct ct_atc_pcm *apcm = runtime->private_data;
+       struct ct_atc *atc = snd_pcm_substream_chip(apcm->substream);
+
+       atc->pcm_release_resources(atc, apcm);
+       ct_timer_instance_free(apcm->timer);
+       kfree(apcm);
+       runtime->private_data = NULL;
+}
+
+/* pcm playback operations */
+static int ct_pcm_playback_open(struct snd_pcm_substream *substream)
+{
+       struct ct_atc *atc = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct ct_atc_pcm *apcm;
+       int err;
+
+       apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
+       if (NULL == apcm)
+               return -ENOMEM;
+
+       apcm->substream = substream;
+       apcm->interrupt = ct_atc_pcm_interrupt;
+       runtime->private_data = apcm;
+       runtime->private_free = ct_atc_pcm_free_substream;
+       if (IEC958 == substream->pcm->device) {
+               runtime->hw = ct_spdif_passthru_playback_hw;
+               atc->spdif_out_passthru(atc, 1);
+       } else {
+               runtime->hw = ct_pcm_playback_hw;
+               if (FRONT == substream->pcm->device)
+                       runtime->hw.channels_max = 8;
+       }
+
+       err = snd_pcm_hw_constraint_integer(runtime,
+                                           SNDRV_PCM_HW_PARAM_PERIODS);
+       if (err < 0) {
+               kfree(apcm);
+               return err;
+       }
+       err = snd_pcm_hw_constraint_minmax(runtime,
+                                          SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+                                          1024, UINT_MAX);
+       if (err < 0) {
+               kfree(apcm);
+               return err;
+       }
+
+       apcm->timer = ct_timer_instance_new(atc->timer, apcm);
+       if (!apcm->timer)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static int ct_pcm_playback_close(struct snd_pcm_substream *substream)
+{
+       struct ct_atc *atc = snd_pcm_substream_chip(substream);
+
+       /* TODO: Notify mixer inactive. */
+       if (IEC958 == substream->pcm->device)
+               atc->spdif_out_passthru(atc, 0);
+
+       /* The ct_atc_pcm object will be freed by runtime->private_free */
+
+       return 0;
+}
+
+static int ct_pcm_hw_params(struct snd_pcm_substream *substream,
+                                    struct snd_pcm_hw_params *hw_params)
+{
+       struct ct_atc *atc = snd_pcm_substream_chip(substream);
+       struct ct_atc_pcm *apcm = substream->runtime->private_data;
+       int err;
+
+       err = snd_pcm_lib_malloc_pages(substream,
+                                       params_buffer_bytes(hw_params));
+       if (err < 0)
+               return err;
+       /* clear previous resources */
+       atc->pcm_release_resources(atc, apcm);
+       return err;
+}
+
+static int ct_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       struct ct_atc *atc = snd_pcm_substream_chip(substream);
+       struct ct_atc_pcm *apcm = substream->runtime->private_data;
+
+       /* clear previous resources */
+       atc->pcm_release_resources(atc, apcm);
+       /* Free snd-allocated pages */
+       return snd_pcm_lib_free_pages(substream);
+}
+
+
+static int ct_pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+       int err;
+       struct ct_atc *atc = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct ct_atc_pcm *apcm = runtime->private_data;
+
+       if (IEC958 == substream->pcm->device)
+               err = atc->spdif_passthru_playback_prepare(atc, apcm);
+       else
+               err = atc->pcm_playback_prepare(atc, apcm);
+
+       if (err < 0) {
+               printk(KERN_ERR "ctxfi: Preparing pcm playback failed!!!\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static int
+ct_pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct ct_atc *atc = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct ct_atc_pcm *apcm = runtime->private_data;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               atc->pcm_playback_start(atc, apcm);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               atc->pcm_playback_stop(atc, apcm);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static snd_pcm_uframes_t
+ct_pcm_playback_pointer(struct snd_pcm_substream *substream)
+{
+       unsigned long position;
+       struct ct_atc *atc = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct ct_atc_pcm *apcm = runtime->private_data;
+
+       /* Read out playback position */
+       position = atc->pcm_playback_position(atc, apcm);
+       position = bytes_to_frames(runtime, position);
+       if (position >= runtime->buffer_size)
+               position = 0;
+       return position;
+}
+
+/* pcm capture operations */
+static int ct_pcm_capture_open(struct snd_pcm_substream *substream)
+{
+       struct ct_atc *atc = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct ct_atc_pcm *apcm;
+       int err;
+
+       apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
+       if (NULL == apcm)
+               return -ENOMEM;
+
+       apcm->started = 0;
+       apcm->substream = substream;
+       apcm->interrupt = ct_atc_pcm_interrupt;
+       runtime->private_data = apcm;
+       runtime->private_free = ct_atc_pcm_free_substream;
+       runtime->hw = ct_pcm_capture_hw;
+       runtime->hw.rate_max = atc->rsr * atc->msr;
+
+       err = snd_pcm_hw_constraint_integer(runtime,
+                                           SNDRV_PCM_HW_PARAM_PERIODS);
+       if (err < 0) {
+               kfree(apcm);
+               return err;
+       }
+       err = snd_pcm_hw_constraint_minmax(runtime,
+                                          SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+                                          1024, UINT_MAX);
+       if (err < 0) {
+               kfree(apcm);
+               return err;
+       }
+
+       apcm->timer = ct_timer_instance_new(atc->timer, apcm);
+       if (!apcm->timer)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static int ct_pcm_capture_close(struct snd_pcm_substream *substream)
+{
+       /* The ct_atc_pcm object will be freed by runtime->private_free */
+       /* TODO: Notify mixer inactive. */
+       return 0;
+}
+
+static int ct_pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+       int err;
+       struct ct_atc *atc = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct ct_atc_pcm *apcm = runtime->private_data;
+
+       err = atc->pcm_capture_prepare(atc, apcm);
+       if (err < 0) {
+               printk(KERN_ERR "ctxfi: Preparing pcm capture failed!!!\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static int
+ct_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct ct_atc *atc = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct ct_atc_pcm *apcm = runtime->private_data;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               atc->pcm_capture_start(atc, apcm);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               atc->pcm_capture_stop(atc, apcm);
+               break;
+       default:
+               atc->pcm_capture_stop(atc, apcm);
+               break;
+       }
+
+       return 0;
+}
+
+static snd_pcm_uframes_t
+ct_pcm_capture_pointer(struct snd_pcm_substream *substream)
+{
+       unsigned long position;
+       struct ct_atc *atc = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct ct_atc_pcm *apcm = runtime->private_data;
+
+       /* Read out playback position */
+       position = atc->pcm_capture_position(atc, apcm);
+       position = bytes_to_frames(runtime, position);
+       if (position >= runtime->buffer_size)
+               position = 0;
+       return position;
+}
+
+/* PCM operators for playback */
+static struct snd_pcm_ops ct_pcm_playback_ops = {
+       .open           = ct_pcm_playback_open,
+       .close          = ct_pcm_playback_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = ct_pcm_hw_params,
+       .hw_free        = ct_pcm_hw_free,
+       .prepare        = ct_pcm_playback_prepare,
+       .trigger        = ct_pcm_playback_trigger,
+       .pointer        = ct_pcm_playback_pointer,
+       .page           = snd_pcm_sgbuf_ops_page,
+};
+
+/* PCM operators for capture */
+static struct snd_pcm_ops ct_pcm_capture_ops = {
+       .open           = ct_pcm_capture_open,
+       .close          = ct_pcm_capture_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = ct_pcm_hw_params,
+       .hw_free        = ct_pcm_hw_free,
+       .prepare        = ct_pcm_capture_prepare,
+       .trigger        = ct_pcm_capture_trigger,
+       .pointer        = ct_pcm_capture_pointer,
+       .page           = snd_pcm_sgbuf_ops_page,
+};
+
+/* Create ALSA pcm device */
+int ct_alsa_pcm_create(struct ct_atc *atc,
+                      enum CTALSADEVS device,
+                      const char *device_name)
+{
+       struct snd_pcm *pcm;
+       int err;
+       int playback_count, capture_count;
+
+       playback_count = (IEC958 == device) ? 1 : 8;
+       capture_count = (FRONT == device) ? 1 : 0;
+       err = snd_pcm_new(atc->card, "ctxfi", device,
+                         playback_count, capture_count, &pcm);
+       if (err < 0) {
+               printk(KERN_ERR "ctxfi: snd_pcm_new failed!! Err=%d\n", err);
+               return err;
+       }
+
+       pcm->private_data = atc;
+       pcm->info_flags = 0;
+       pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
+       strlcpy(pcm->name, device_name, sizeof(pcm->name));
+
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ct_pcm_playback_ops);
+
+       if (FRONT == device)
+               snd_pcm_set_ops(pcm,
+                               SNDRV_PCM_STREAM_CAPTURE, &ct_pcm_capture_ops);
+
+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+                       snd_dma_pci_data(atc->pci), 128*1024, 128*1024);
+
+       return 0;
+}
diff --git a/sound/pci/ctxfi/ctpcm.h b/sound/pci/ctxfi/ctpcm.h
new file mode 100644 (file)
index 0000000..178da0d
--- /dev/null
@@ -0,0 +1,27 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File       ctpcm.h
+ *
+ * @Brief
+ * This file contains the definition of the pcm device functions.
+ *
+ * @Author     Liu Chun
+ * @Date       Mar 28 2008
+ *
+ */
+
+#ifndef CTPCM_H
+#define CTPCM_H
+
+#include "ctatc.h"
+
+int ct_alsa_pcm_create(struct ct_atc *atc,
+                      enum CTALSADEVS device,
+                      const char *device_name);
+
+#endif /* CTPCM_H */
diff --git a/sound/pci/ctxfi/ctresource.c b/sound/pci/ctxfi/ctresource.c
new file mode 100644 (file)
index 0000000..889c495
--- /dev/null
@@ -0,0 +1,301 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File       ctresource.c
+ *
+ * @Brief
+ * This file contains the implementation of some generic helper functions.
+ *
+ * @Author     Liu Chun
+ * @Date       May 15 2008
+ *
+ */
+
+#include "ctresource.h"
+#include "cthardware.h"
+#include <linux/err.h>
+#include <linux/slab.h>
+
+#define AUDIO_SLOT_BLOCK_NUM   256
+
+/* Resource allocation based on bit-map management mechanism */
+static int
+get_resource(u8 *rscs, unsigned int amount,
+            unsigned int multi, unsigned int *ridx)
+{
+       int i, j, k, n;
+
+       /* Check whether there are sufficient resources to meet request. */
+       for (i = 0, n = multi; i < amount; i++) {
+               j = i / 8;
+               k = i % 8;
+               if (rscs[j] & ((u8)1 << k)) {
+                       n = multi;
+                       continue;
+               }
+               if (!(--n))
+                       break; /* found sufficient contiguous resources */
+       }
+
+       if (i >= amount) {
+               /* Can not find sufficient contiguous resources */
+               return -ENOENT;
+       }
+
+       /* Mark the contiguous bits in resource bit-map as used */
+       for (n = multi; n > 0; n--) {
+               j = i / 8;
+               k = i % 8;
+               rscs[j] |= ((u8)1 << k);
+               i--;
+       }
+
+       *ridx = i + 1;
+
+       return 0;
+}
+
+static int put_resource(u8 *rscs, unsigned int multi, unsigned int idx)
+{
+       unsigned int i, j, k, n;
+
+       /* Mark the contiguous bits in resource bit-map as used */
+       for (n = multi, i = idx; n > 0; n--) {
+               j = i / 8;
+               k = i % 8;
+               rscs[j] &= ~((u8)1 << k);
+               i++;
+       }
+
+       return 0;
+}
+
+int mgr_get_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int *ridx)
+{
+       int err;
+
+       if (n > mgr->avail)
+               return -ENOENT;
+
+       err = get_resource(mgr->rscs, mgr->amount, n, ridx);
+       if (!err)
+               mgr->avail -= n;
+
+       return err;
+}
+
+int mgr_put_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int idx)
+{
+       put_resource(mgr->rscs, n, idx);
+       mgr->avail += n;
+
+       return 0;
+}
+
+static unsigned char offset_in_audio_slot_block[NUM_RSCTYP] = {
+       /* SRC channel is at Audio Ring slot 1 every 16 slots. */
+       [SRC]           = 0x1,
+       [AMIXER]        = 0x4,
+       [SUM]           = 0xc,
+};
+
+static int rsc_index(const struct rsc *rsc)
+{
+    return rsc->conj;
+}
+
+static int audio_ring_slot(const struct rsc *rsc)
+{
+    return (rsc->conj << 4) + offset_in_audio_slot_block[rsc->type];
+}
+
+static int rsc_next_conj(struct rsc *rsc)
+{
+       unsigned int i;
+       for (i = 0; (i < 8) && (!(rsc->msr & (0x1 << i))); )
+               i++;
+       rsc->conj += (AUDIO_SLOT_BLOCK_NUM >> i);
+       return rsc->conj;
+}
+
+static int rsc_master(struct rsc *rsc)
+{
+       return rsc->conj = rsc->idx;
+}
+
+static struct rsc_ops rsc_generic_ops = {
+       .index          = rsc_index,
+       .output_slot    = audio_ring_slot,
+       .master         = rsc_master,
+       .next_conj      = rsc_next_conj,
+};
+
+int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw)
+{
+       int err = 0;
+
+       rsc->idx = idx;
+       rsc->conj = idx;
+       rsc->type = type;
+       rsc->msr = msr;
+       rsc->hw = hw;
+       rsc->ops = &rsc_generic_ops;
+       if (NULL == hw) {
+               rsc->ctrl_blk = NULL;
+               return 0;
+       }
+
+       switch (type) {
+       case SRC:
+               err = ((struct hw *)hw)->src_rsc_get_ctrl_blk(&rsc->ctrl_blk);
+               break;
+       case AMIXER:
+               err = ((struct hw *)hw)->
+                               amixer_rsc_get_ctrl_blk(&rsc->ctrl_blk);
+               break;
+       case SRCIMP:
+       case SUM:
+       case DAIO:
+               break;
+       default:
+               printk(KERN_ERR
+                      "ctxfi: Invalid resource type value %d!\n", type);
+               return -EINVAL;
+       }
+
+       if (err) {
+               printk(KERN_ERR
+                      "ctxfi: Failed to get resource control block!\n");
+               return err;
+       }
+
+       return 0;
+}
+
+int rsc_uninit(struct rsc *rsc)
+{
+       if ((NULL != rsc->hw) && (NULL != rsc->ctrl_blk)) {
+               switch (rsc->type) {
+               case SRC:
+                       ((struct hw *)rsc->hw)->
+                               src_rsc_put_ctrl_blk(rsc->ctrl_blk);
+                       break;
+               case AMIXER:
+                       ((struct hw *)rsc->hw)->
+                               amixer_rsc_put_ctrl_blk(rsc->ctrl_blk);
+                       break;
+               case SUM:
+               case DAIO:
+                       break;
+               default:
+                       printk(KERN_ERR "ctxfi: "
+                              "Invalid resource type value %d!\n", rsc->type);
+                       break;
+               }
+
+               rsc->hw = rsc->ctrl_blk = NULL;
+       }
+
+       rsc->idx = rsc->conj = 0;
+       rsc->type = NUM_RSCTYP;
+       rsc->msr = 0;
+
+       return 0;
+}
+
+int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type,
+                unsigned int amount, void *hw_obj)
+{
+       int err = 0;
+       struct hw *hw = hw_obj;
+
+       mgr->type = NUM_RSCTYP;
+
+       mgr->rscs = kzalloc(((amount + 8 - 1) / 8), GFP_KERNEL);
+       if (NULL == mgr->rscs)
+               return -ENOMEM;
+
+       switch (type) {
+       case SRC:
+               err = hw->src_mgr_get_ctrl_blk(&mgr->ctrl_blk);
+               break;
+       case SRCIMP:
+               err = hw->srcimp_mgr_get_ctrl_blk(&mgr->ctrl_blk);
+               break;
+       case AMIXER:
+               err = hw->amixer_mgr_get_ctrl_blk(&mgr->ctrl_blk);
+               break;
+       case DAIO:
+               err = hw->daio_mgr_get_ctrl_blk(hw, &mgr->ctrl_blk);
+               break;
+       case SUM:
+               break;
+       default:
+               printk(KERN_ERR
+                      "ctxfi: Invalid resource type value %d!\n", type);
+               err = -EINVAL;
+               goto error;
+       }
+
+       if (err) {
+               printk(KERN_ERR
+                      "ctxfi: Failed to get manager control block!\n");
+               goto error;
+       }
+
+       mgr->type = type;
+       mgr->avail = mgr->amount = amount;
+       mgr->hw = hw;
+
+       return 0;
+
+error:
+       kfree(mgr->rscs);
+       return err;
+}
+
+int rsc_mgr_uninit(struct rsc_mgr *mgr)
+{
+       if (NULL != mgr->rscs) {
+               kfree(mgr->rscs);
+               mgr->rscs = NULL;
+       }
+
+       if ((NULL != mgr->hw) && (NULL != mgr->ctrl_blk)) {
+               switch (mgr->type) {
+               case SRC:
+                       ((struct hw *)mgr->hw)->
+                               src_mgr_put_ctrl_blk(mgr->ctrl_blk);
+                       break;
+               case SRCIMP:
+                       ((struct hw *)mgr->hw)->
+                               srcimp_mgr_put_ctrl_blk(mgr->ctrl_blk);
+                       break;
+               case AMIXER:
+                       ((struct hw *)mgr->hw)->
+                               amixer_mgr_put_ctrl_blk(mgr->ctrl_blk);
+                       break;
+               case DAIO:
+                       ((struct hw *)mgr->hw)->
+                               daio_mgr_put_ctrl_blk(mgr->ctrl_blk);
+                       break;
+               case SUM:
+                       break;
+               default:
+                       printk(KERN_ERR "ctxfi: "
+                              "Invalid resource type value %d!\n", mgr->type);
+                       break;
+               }
+
+               mgr->hw = mgr->ctrl_blk = NULL;
+       }
+
+       mgr->type = NUM_RSCTYP;
+       mgr->avail = mgr->amount = 0;
+
+       return 0;
+}
diff --git a/sound/pci/ctxfi/ctresource.h b/sound/pci/ctxfi/ctresource.h
new file mode 100644 (file)
index 0000000..0838c2e
--- /dev/null
@@ -0,0 +1,72 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File       ctresource.h
+ *
+ * @Brief
+ * This file contains the definition of generic hardware resources for
+ * resource management.
+ *
+ * @Author     Liu Chun
+ * @Date       May 13 2008
+ *
+ */
+
+#ifndef CTRESOURCE_H
+#define CTRESOURCE_H
+
+#include <linux/types.h>
+
+enum RSCTYP {
+       SRC,
+       SRCIMP,
+       AMIXER,
+       SUM,
+       DAIO,
+       NUM_RSCTYP      /* This must be the last one and less than 16 */
+};
+
+struct rsc_ops;
+
+struct rsc {
+       u32 idx:12;     /* The index of a resource */
+       u32 type:4;     /* The type (RSCTYP) of a resource */
+       u32 conj:12;    /* Current conjugate index */
+       u32 msr:4;      /* The Master Sample Rate a resource working on */
+       void *ctrl_blk; /* Chip specific control info block for a resource */
+       void *hw;       /* Chip specific object for hardware access means */
+       struct rsc_ops *ops;    /* Generic resource operations */
+};
+
+struct rsc_ops {
+       int (*master)(struct rsc *rsc); /* Move to master resource */
+       int (*next_conj)(struct rsc *rsc); /* Move to next conjugate resource */
+       int (*index)(const struct rsc *rsc); /* Return the index of resource */
+       /* Return the output slot number */
+       int (*output_slot)(const struct rsc *rsc);
+};
+
+int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw);
+int rsc_uninit(struct rsc *rsc);
+
+struct rsc_mgr {
+       enum RSCTYP type; /* The type (RSCTYP) of resource to manage */
+       unsigned int amount; /* The total amount of a kind of resource */
+       unsigned int avail; /* The amount of currently available resources */
+       unsigned char *rscs; /* The bit-map for resource allocation */
+       void *ctrl_blk; /* Chip specific control info block */
+       void *hw; /* Chip specific object for hardware access */
+};
+
+/* Resource management is based on bit-map mechanism */
+int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type,
+                unsigned int amount, void *hw);
+int rsc_mgr_uninit(struct rsc_mgr *mgr);
+int mgr_get_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int *ridx);
+int mgr_put_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int idx);
+
+#endif /* CTRESOURCE_H */
diff --git a/sound/pci/ctxfi/ctsrc.c b/sound/pci/ctxfi/ctsrc.c
new file mode 100644 (file)
index 0000000..e1c145d
--- /dev/null
@@ -0,0 +1,886 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File       ctsrc.c
+ *
+ * @Brief
+ * This file contains the implementation of the Sample Rate Convertor
+ * resource management object.
+ *
+ * @Author     Liu Chun
+ * @Date       May 13 2008
+ *
+ */
+
+#include "ctsrc.h"
+#include "cthardware.h"
+#include <linux/slab.h>
+
+#define SRC_RESOURCE_NUM       64
+#define SRCIMP_RESOURCE_NUM    256
+
+static unsigned int conj_mask;
+
+static int src_default_config_memrd(struct src *src);
+static int src_default_config_memwr(struct src *src);
+static int src_default_config_arcrw(struct src *src);
+
+static int (*src_default_config[3])(struct src *) = {
+       [MEMRD] = src_default_config_memrd,
+       [MEMWR] = src_default_config_memwr,
+       [ARCRW] = src_default_config_arcrw
+};
+
+static int src_set_state(struct src *src, unsigned int state)
+{
+       struct hw *hw;
+
+       hw = src->rsc.hw;
+       hw->src_set_state(src->rsc.ctrl_blk, state);
+
+       return 0;
+}
+
+static int src_set_bm(struct src *src, unsigned int bm)
+{
+       struct hw *hw;
+
+       hw = src->rsc.hw;
+       hw->src_set_bm(src->rsc.ctrl_blk, bm);
+
+       return 0;
+}
+
+static int src_set_sf(struct src *src, unsigned int sf)
+{
+       struct hw *hw;
+
+       hw = src->rsc.hw;
+       hw->src_set_sf(src->rsc.ctrl_blk, sf);
+
+       return 0;
+}
+
+static int src_set_pm(struct src *src, unsigned int pm)
+{
+       struct hw *hw;
+
+       hw = src->rsc.hw;
+       hw->src_set_pm(src->rsc.ctrl_blk, pm);
+
+       return 0;
+}
+
+static int src_set_rom(struct src *src, unsigned int rom)
+{
+       struct hw *hw;
+
+       hw = src->rsc.hw;
+       hw->src_set_rom(src->rsc.ctrl_blk, rom);
+
+       return 0;
+}
+
+static int src_set_vo(struct src *src, unsigned int vo)
+{
+       struct hw *hw;
+
+       hw = src->rsc.hw;
+       hw->src_set_vo(src->rsc.ctrl_blk, vo);
+
+       return 0;
+}
+
+static int src_set_st(struct src *src, unsigned int st)
+{
+       struct hw *hw;
+
+       hw = src->rsc.hw;
+       hw->src_set_st(src->rsc.ctrl_blk, st);
+
+       return 0;
+}
+
+static int src_set_bp(struct src *src, unsigned int bp)
+{
+       struct hw *hw;
+
+       hw = src->rsc.hw;
+       hw->src_set_bp(src->rsc.ctrl_blk, bp);
+
+       return 0;
+}
+
+static int src_set_cisz(struct src *src, unsigned int cisz)
+{
+       struct hw *hw;
+
+       hw = src->rsc.hw;
+       hw->src_set_cisz(src->rsc.ctrl_blk, cisz);
+
+       return 0;
+}
+
+static int src_set_ca(struct src *src, unsigned int ca)
+{
+       struct hw *hw;
+
+       hw = src->rsc.hw;
+       hw->src_set_ca(src->rsc.ctrl_blk, ca);
+
+       return 0;
+}
+
+static int src_set_sa(struct src *src, unsigned int sa)
+{
+       struct hw *hw;
+
+       hw = src->rsc.hw;
+       hw->src_set_sa(src->rsc.ctrl_blk, sa);
+
+       return 0;
+}
+
+static int src_set_la(struct src *src, unsigned int la)
+{
+       struct hw *hw;
+
+       hw = src->rsc.hw;
+       hw->src_set_la(src->rsc.ctrl_blk, la);
+
+       return 0;
+}
+
+static int src_set_pitch(struct src *src, unsigned int pitch)
+{
+       struct hw *hw;
+
+       hw = src->rsc.hw;
+       hw->src_set_pitch(src->rsc.ctrl_blk, pitch);
+
+       return 0;
+}
+
+static int src_set_clear_zbufs(struct src *src)
+{
+       struct hw *hw;
+
+       hw = src->rsc.hw;
+       hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1);
+
+       return 0;
+}
+
+static int src_commit_write(struct src *src)
+{
+       struct hw *hw;
+       int i;
+       unsigned int dirty = 0;
+
+       hw = src->rsc.hw;
+       src->rsc.ops->master(&src->rsc);
+       if (src->rsc.msr > 1) {
+               /* Save dirty flags for conjugate resource programming */
+               dirty = hw->src_get_dirty(src->rsc.ctrl_blk) & conj_mask;
+       }
+       hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc),
+                                               src->rsc.ctrl_blk);
+
+       /* Program conjugate parameter mixer resources */
+       if (MEMWR == src->mode)
+               return 0;
+
+       for (i = 1; i < src->rsc.msr; i++) {
+               src->rsc.ops->next_conj(&src->rsc);
+               hw->src_set_dirty(src->rsc.ctrl_blk, dirty);
+               hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc),
+                                                       src->rsc.ctrl_blk);
+       }
+       src->rsc.ops->master(&src->rsc);
+
+       return 0;
+}
+
+static int src_get_ca(struct src *src)
+{
+       struct hw *hw;
+
+       hw = src->rsc.hw;
+       return hw->src_get_ca(hw, src->rsc.ops->index(&src->rsc),
+                                               src->rsc.ctrl_blk);
+}
+
+static int src_init(struct src *src)
+{
+       src_default_config[src->mode](src);
+
+       return 0;
+}
+
+static struct src *src_next_interleave(struct src *src)
+{
+       return src->intlv;
+}
+
+static int src_default_config_memrd(struct src *src)
+{
+       struct hw *hw = src->rsc.hw;
+       unsigned int rsr, msr;
+
+       hw->src_set_state(src->rsc.ctrl_blk, SRC_STATE_OFF);
+       hw->src_set_bm(src->rsc.ctrl_blk, 1);
+       for (rsr = 0, msr = src->rsc.msr; msr > 1; msr >>= 1)
+               rsr++;
+
+       hw->src_set_rsr(src->rsc.ctrl_blk, rsr);
+       hw->src_set_sf(src->rsc.ctrl_blk, SRC_SF_S16);
+       hw->src_set_wr(src->rsc.ctrl_blk, 0);
+       hw->src_set_pm(src->rsc.ctrl_blk, 0);
+       hw->src_set_rom(src->rsc.ctrl_blk, 0);
+       hw->src_set_vo(src->rsc.ctrl_blk, 0);
+       hw->src_set_st(src->rsc.ctrl_blk, 0);
+       hw->src_set_ilsz(src->rsc.ctrl_blk, src->multi - 1);
+       hw->src_set_cisz(src->rsc.ctrl_blk, 0x80);
+       hw->src_set_sa(src->rsc.ctrl_blk, 0x0);
+       hw->src_set_la(src->rsc.ctrl_blk, 0x1000);
+       hw->src_set_ca(src->rsc.ctrl_blk, 0x80);
+       hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000);
+       hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1);
+
+       src->rsc.ops->master(&src->rsc);
+       hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc),
+                                               src->rsc.ctrl_blk);
+
+       for (msr = 1; msr < src->rsc.msr; msr++) {
+               src->rsc.ops->next_conj(&src->rsc);
+               hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000);
+               hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc),
+                                                       src->rsc.ctrl_blk);
+       }
+       src->rsc.ops->master(&src->rsc);
+
+       return 0;
+}
+
+static int src_default_config_memwr(struct src *src)
+{
+       struct hw *hw = src->rsc.hw;
+
+       hw->src_set_state(src->rsc.ctrl_blk, SRC_STATE_OFF);
+       hw->src_set_bm(src->rsc.ctrl_blk, 1);
+       hw->src_set_rsr(src->rsc.ctrl_blk, 0);
+       hw->src_set_sf(src->rsc.ctrl_blk, SRC_SF_S16);
+       hw->src_set_wr(src->rsc.ctrl_blk, 1);
+       hw->src_set_pm(src->rsc.ctrl_blk, 0);
+       hw->src_set_rom(src->rsc.ctrl_blk, 0);
+       hw->src_set_vo(src->rsc.ctrl_blk, 0);
+       hw->src_set_st(src->rsc.ctrl_blk, 0);
+       hw->src_set_ilsz(src->rsc.ctrl_blk, 0);
+       hw->src_set_cisz(src->rsc.ctrl_blk, 0x80);
+       hw->src_set_sa(src->rsc.ctrl_blk, 0x0);
+       hw->src_set_la(src->rsc.ctrl_blk, 0x1000);
+       hw->src_set_ca(src->rsc.ctrl_blk, 0x80);
+       hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000);
+       hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1);
+
+       src->rsc.ops->master(&src->rsc);
+       hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc),
+                                               src->rsc.ctrl_blk);
+
+       return 0;
+}
+
+static int src_default_config_arcrw(struct src *src)
+{
+       struct hw *hw = src->rsc.hw;
+       unsigned int rsr, msr;
+       unsigned int dirty;
+
+       hw->src_set_state(src->rsc.ctrl_blk, SRC_STATE_OFF);
+       hw->src_set_bm(src->rsc.ctrl_blk, 0);
+       for (rsr = 0, msr = src->rsc.msr; msr > 1; msr >>= 1)
+               rsr++;
+
+       hw->src_set_rsr(src->rsc.ctrl_blk, rsr);
+       hw->src_set_sf(src->rsc.ctrl_blk, SRC_SF_F32);
+       hw->src_set_wr(src->rsc.ctrl_blk, 0);
+       hw->src_set_pm(src->rsc.ctrl_blk, 0);
+       hw->src_set_rom(src->rsc.ctrl_blk, 0);
+       hw->src_set_vo(src->rsc.ctrl_blk, 0);
+       hw->src_set_st(src->rsc.ctrl_blk, 0);
+       hw->src_set_ilsz(src->rsc.ctrl_blk, 0);
+       hw->src_set_cisz(src->rsc.ctrl_blk, 0x80);
+       hw->src_set_sa(src->rsc.ctrl_blk, 0x0);
+       /*hw->src_set_sa(src->rsc.ctrl_blk, 0x100);*/
+       hw->src_set_la(src->rsc.ctrl_blk, 0x1000);
+       /*hw->src_set_la(src->rsc.ctrl_blk, 0x03ffffe0);*/
+       hw->src_set_ca(src->rsc.ctrl_blk, 0x80);
+       hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000);
+       hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1);
+
+       dirty = hw->src_get_dirty(src->rsc.ctrl_blk);
+       src->rsc.ops->master(&src->rsc);
+       for (msr = 0; msr < src->rsc.msr; msr++) {
+               hw->src_set_dirty(src->rsc.ctrl_blk, dirty);
+               hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc),
+                                                       src->rsc.ctrl_blk);
+               src->rsc.ops->next_conj(&src->rsc);
+       }
+       src->rsc.ops->master(&src->rsc);
+
+       return 0;
+}
+
+static struct src_rsc_ops src_rsc_ops = {
+       .set_state              = src_set_state,
+       .set_bm                 = src_set_bm,
+       .set_sf                 = src_set_sf,
+       .set_pm                 = src_set_pm,
+       .set_rom                = src_set_rom,
+       .set_vo                 = src_set_vo,
+       .set_st                 = src_set_st,
+       .set_bp                 = src_set_bp,
+       .set_cisz               = src_set_cisz,
+       .set_ca                 = src_set_ca,
+       .set_sa                 = src_set_sa,
+       .set_la                 = src_set_la,
+       .set_pitch              = src_set_pitch,
+       .set_clr_zbufs          = src_set_clear_zbufs,
+       .commit_write           = src_commit_write,
+       .get_ca                 = src_get_ca,
+       .init                   = src_init,
+       .next_interleave        = src_next_interleave,
+};
+
+static int
+src_rsc_init(struct src *src, u32 idx,
+            const struct src_desc *desc, struct src_mgr *mgr)
+{
+       int err;
+       int i, n;
+       struct src *p;
+
+       n = (MEMRD == desc->mode) ? desc->multi : 1;
+       for (i = 0, p = src; i < n; i++, p++) {
+               err = rsc_init(&p->rsc, idx + i, SRC, desc->msr, mgr->mgr.hw);
+               if (err)
+                       goto error1;
+
+               /* Initialize src specific rsc operations */
+               p->ops = &src_rsc_ops;
+               p->multi = (0 == i) ? desc->multi : 1;
+               p->mode = desc->mode;
+               src_default_config[desc->mode](p);
+               mgr->src_enable(mgr, p);
+               p->intlv = p + 1;
+       }
+       (--p)->intlv = NULL;    /* Set @intlv of the last SRC to NULL */
+
+       mgr->commit_write(mgr);
+
+       return 0;
+
+error1:
+       for (i--, p--; i >= 0; i--, p--) {
+               mgr->src_disable(mgr, p);
+               rsc_uninit(&p->rsc);
+       }
+       mgr->commit_write(mgr);
+       return err;
+}
+
+static int src_rsc_uninit(struct src *src, struct src_mgr *mgr)
+{
+       int i, n;
+       struct src *p;
+
+       n = (MEMRD == src->mode) ? src->multi : 1;
+       for (i = 0, p = src; i < n; i++, p++) {
+               mgr->src_disable(mgr, p);
+               rsc_uninit(&p->rsc);
+               p->multi = 0;
+               p->ops = NULL;
+               p->mode = NUM_SRCMODES;
+               p->intlv = NULL;
+       }
+       mgr->commit_write(mgr);
+
+       return 0;
+}
+
+static int
+get_src_rsc(struct src_mgr *mgr, const struct src_desc *desc, struct src **rsrc)
+{
+       unsigned int idx = SRC_RESOURCE_NUM;
+       int err;
+       struct src *src;
+       unsigned long flags;
+
+       *rsrc = NULL;
+
+       /* Check whether there are sufficient src resources to meet request. */
+       spin_lock_irqsave(&mgr->mgr_lock, flags);
+       if (MEMRD == desc->mode)
+               err = mgr_get_resource(&mgr->mgr, desc->multi, &idx);
+       else
+               err = mgr_get_resource(&mgr->mgr, 1, &idx);
+
+       spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+       if (err) {
+               printk(KERN_ERR "ctxfi: Can't meet SRC resource request!\n");
+               return err;
+       }
+
+       /* Allocate mem for master src resource */
+       if (MEMRD == desc->mode)
+               src = kzalloc(sizeof(*src)*desc->multi, GFP_KERNEL);
+       else
+               src = kzalloc(sizeof(*src), GFP_KERNEL);
+
+       if (NULL == src) {
+               err = -ENOMEM;
+               goto error1;
+       }
+
+       err = src_rsc_init(src, idx, desc, mgr);
+       if (err)
+               goto error2;
+
+       *rsrc = src;
+
+       return 0;
+
+error2:
+       kfree(src);
+error1:
+       spin_lock_irqsave(&mgr->mgr_lock, flags);
+       if (MEMRD == desc->mode)
+               mgr_put_resource(&mgr->mgr, desc->multi, idx);
+       else
+               mgr_put_resource(&mgr->mgr, 1, idx);
+
+       spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+       return err;
+}
+
+static int put_src_rsc(struct src_mgr *mgr, struct src *src)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mgr->mgr_lock, flags);
+       src->rsc.ops->master(&src->rsc);
+       if (MEMRD == src->mode)
+               mgr_put_resource(&mgr->mgr, src->multi,
+                                src->rsc.ops->index(&src->rsc));
+       else
+               mgr_put_resource(&mgr->mgr, 1, src->rsc.ops->index(&src->rsc));
+
+       spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+       src_rsc_uninit(src, mgr);
+       kfree(src);
+
+       return 0;
+}
+
+static int src_enable_s(struct src_mgr *mgr, struct src *src)
+{
+       struct hw *hw = mgr->mgr.hw;
+       int i;
+
+       src->rsc.ops->master(&src->rsc);
+       for (i = 0; i < src->rsc.msr; i++) {
+               hw->src_mgr_enbs_src(mgr->mgr.ctrl_blk,
+                                    src->rsc.ops->index(&src->rsc));
+               src->rsc.ops->next_conj(&src->rsc);
+       }
+       src->rsc.ops->master(&src->rsc);
+
+       return 0;
+}
+
+static int src_enable(struct src_mgr *mgr, struct src *src)
+{
+       struct hw *hw = mgr->mgr.hw;
+       int i;
+
+       src->rsc.ops->master(&src->rsc);
+       for (i = 0; i < src->rsc.msr; i++) {
+               hw->src_mgr_enb_src(mgr->mgr.ctrl_blk,
+                                   src->rsc.ops->index(&src->rsc));
+               src->rsc.ops->next_conj(&src->rsc);
+       }
+       src->rsc.ops->master(&src->rsc);
+
+       return 0;
+}
+
+static int src_disable(struct src_mgr *mgr, struct src *src)
+{
+       struct hw *hw = mgr->mgr.hw;
+       int i;
+
+       src->rsc.ops->master(&src->rsc);
+       for (i = 0; i < src->rsc.msr; i++) {
+               hw->src_mgr_dsb_src(mgr->mgr.ctrl_blk,
+                                   src->rsc.ops->index(&src->rsc));
+               src->rsc.ops->next_conj(&src->rsc);
+       }
+       src->rsc.ops->master(&src->rsc);
+
+       return 0;
+}
+
+static int src_mgr_commit_write(struct src_mgr *mgr)
+{
+       struct hw *hw = mgr->mgr.hw;
+
+       hw->src_mgr_commit_write(hw, mgr->mgr.ctrl_blk);
+
+       return 0;
+}
+
+int src_mgr_create(void *hw, struct src_mgr **rsrc_mgr)
+{
+       int err, i;
+       struct src_mgr *src_mgr;
+
+       *rsrc_mgr = NULL;
+       src_mgr = kzalloc(sizeof(*src_mgr), GFP_KERNEL);
+       if (NULL == src_mgr)
+               return -ENOMEM;
+
+       err = rsc_mgr_init(&src_mgr->mgr, SRC, SRC_RESOURCE_NUM, hw);
+       if (err)
+               goto error1;
+
+       spin_lock_init(&src_mgr->mgr_lock);
+       conj_mask = ((struct hw *)hw)->src_dirty_conj_mask();
+
+       src_mgr->get_src = get_src_rsc;
+       src_mgr->put_src = put_src_rsc;
+       src_mgr->src_enable_s = src_enable_s;
+       src_mgr->src_enable = src_enable;
+       src_mgr->src_disable = src_disable;
+       src_mgr->commit_write = src_mgr_commit_write;
+
+       /* Disable all SRC resources. */
+       for (i = 0; i < 256; i++)
+               ((struct hw *)hw)->src_mgr_dsb_src(src_mgr->mgr.ctrl_blk, i);
+
+       ((struct hw *)hw)->src_mgr_commit_write(hw, src_mgr->mgr.ctrl_blk);
+
+       *rsrc_mgr = src_mgr;
+
+       return 0;
+
+error1:
+       kfree(src_mgr);
+       return err;
+}
+
+int src_mgr_destroy(struct src_mgr *src_mgr)
+{
+       rsc_mgr_uninit(&src_mgr->mgr);
+       kfree(src_mgr);
+
+       return 0;
+}
+
+/* SRCIMP resource manager operations */
+
+static int srcimp_master(struct rsc *rsc)
+{
+       rsc->conj = 0;
+       return rsc->idx = container_of(rsc, struct srcimp, rsc)->idx[0];
+}
+
+static int srcimp_next_conj(struct rsc *rsc)
+{
+       rsc->conj++;
+       return container_of(rsc, struct srcimp, rsc)->idx[rsc->conj];
+}
+
+static int srcimp_index(const struct rsc *rsc)
+{
+       return container_of(rsc, struct srcimp, rsc)->idx[rsc->conj];
+}
+
+static struct rsc_ops srcimp_basic_rsc_ops = {
+       .master         = srcimp_master,
+       .next_conj      = srcimp_next_conj,
+       .index          = srcimp_index,
+       .output_slot    = NULL,
+};
+
+static int srcimp_map(struct srcimp *srcimp, struct src *src, struct rsc *input)
+{
+       struct imapper *entry;
+       int i;
+
+       srcimp->rsc.ops->master(&srcimp->rsc);
+       src->rsc.ops->master(&src->rsc);
+       input->ops->master(input);
+
+       /* Program master and conjugate resources */
+       for (i = 0; i < srcimp->rsc.msr; i++) {
+               entry = &srcimp->imappers[i];
+               entry->slot = input->ops->output_slot(input);
+               entry->user = src->rsc.ops->index(&src->rsc);
+               entry->addr = srcimp->rsc.ops->index(&srcimp->rsc);
+               srcimp->mgr->imap_add(srcimp->mgr, entry);
+               srcimp->mapped |= (0x1 << i);
+
+               srcimp->rsc.ops->next_conj(&srcimp->rsc);
+               input->ops->next_conj(input);
+       }
+
+       srcimp->rsc.ops->master(&srcimp->rsc);
+       input->ops->master(input);
+
+       return 0;
+}
+
+static int srcimp_unmap(struct srcimp *srcimp)
+{
+       int i;
+
+       /* Program master and conjugate resources */
+       for (i = 0; i < srcimp->rsc.msr; i++) {
+               if (srcimp->mapped & (0x1 << i)) {
+                       srcimp->mgr->imap_delete(srcimp->mgr,
+                                                &srcimp->imappers[i]);
+                       srcimp->mapped &= ~(0x1 << i);
+               }
+       }
+
+       return 0;
+}
+
+static struct srcimp_rsc_ops srcimp_ops = {
+       .map = srcimp_map,
+       .unmap = srcimp_unmap
+};
+
+static int srcimp_rsc_init(struct srcimp *srcimp,
+                          const struct srcimp_desc *desc,
+                          struct srcimp_mgr *mgr)
+{
+       int err;
+
+       err = rsc_init(&srcimp->rsc, srcimp->idx[0],
+                      SRCIMP, desc->msr, mgr->mgr.hw);
+       if (err)
+               return err;
+
+       /* Reserve memory for imapper nodes */
+       srcimp->imappers = kzalloc(sizeof(struct imapper)*desc->msr,
+                                  GFP_KERNEL);
+       if (NULL == srcimp->imappers) {
+               err = -ENOMEM;
+               goto error1;
+       }
+
+       /* Set srcimp specific operations */
+       srcimp->rsc.ops = &srcimp_basic_rsc_ops;
+       srcimp->ops = &srcimp_ops;
+       srcimp->mgr = mgr;
+
+       srcimp->rsc.ops->master(&srcimp->rsc);
+
+       return 0;
+
+error1:
+       rsc_uninit(&srcimp->rsc);
+       return err;
+}
+
+static int srcimp_rsc_uninit(struct srcimp *srcimp)
+{
+       if (NULL != srcimp->imappers) {
+               kfree(srcimp->imappers);
+               srcimp->imappers = NULL;
+       }
+       srcimp->ops = NULL;
+       srcimp->mgr = NULL;
+       rsc_uninit(&srcimp->rsc);
+
+       return 0;
+}
+
+static int get_srcimp_rsc(struct srcimp_mgr *mgr,
+                         const struct srcimp_desc *desc,
+                         struct srcimp **rsrcimp)
+{
+       int err, i;
+       unsigned int idx;
+       struct srcimp *srcimp;
+       unsigned long flags;
+
+       *rsrcimp = NULL;
+
+       /* Allocate mem for SRCIMP resource */
+       srcimp = kzalloc(sizeof(*srcimp), GFP_KERNEL);
+       if (NULL == srcimp) {
+               err = -ENOMEM;
+               return err;
+       }
+
+       /* Check whether there are sufficient SRCIMP resources. */
+       spin_lock_irqsave(&mgr->mgr_lock, flags);
+       for (i = 0; i < desc->msr; i++) {
+               err = mgr_get_resource(&mgr->mgr, 1, &idx);
+               if (err)
+                       break;
+
+               srcimp->idx[i] = idx;
+       }
+       spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+       if (err) {
+               printk(KERN_ERR "ctxfi: Can't meet SRCIMP resource request!\n");
+               goto error1;
+       }
+
+       err = srcimp_rsc_init(srcimp, desc, mgr);
+       if (err)
+               goto error1;
+
+       *rsrcimp = srcimp;
+
+       return 0;
+
+error1:
+       spin_lock_irqsave(&mgr->mgr_lock, flags);
+       for (i--; i >= 0; i--)
+               mgr_put_resource(&mgr->mgr, 1, srcimp->idx[i]);
+
+       spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+       kfree(srcimp);
+       return err;
+}
+
+static int put_srcimp_rsc(struct srcimp_mgr *mgr, struct srcimp *srcimp)
+{
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&mgr->mgr_lock, flags);
+       for (i = 0; i < srcimp->rsc.msr; i++)
+               mgr_put_resource(&mgr->mgr, 1, srcimp->idx[i]);
+
+       spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+       srcimp_rsc_uninit(srcimp);
+       kfree(srcimp);
+
+       return 0;
+}
+
+static int srcimp_map_op(void *data, struct imapper *entry)
+{
+       struct rsc_mgr *mgr = &((struct srcimp_mgr *)data)->mgr;
+       struct hw *hw = mgr->hw;
+
+       hw->srcimp_mgr_set_imaparc(mgr->ctrl_blk, entry->slot);
+       hw->srcimp_mgr_set_imapuser(mgr->ctrl_blk, entry->user);
+       hw->srcimp_mgr_set_imapnxt(mgr->ctrl_blk, entry->next);
+       hw->srcimp_mgr_set_imapaddr(mgr->ctrl_blk, entry->addr);
+       hw->srcimp_mgr_commit_write(mgr->hw, mgr->ctrl_blk);
+
+       return 0;
+}
+
+static int srcimp_imap_add(struct srcimp_mgr *mgr, struct imapper *entry)
+{
+       unsigned long flags;
+       int err;
+
+       spin_lock_irqsave(&mgr->imap_lock, flags);
+       if ((0 == entry->addr) && (mgr->init_imap_added)) {
+               input_mapper_delete(&mgr->imappers,
+                                   mgr->init_imap, srcimp_map_op, mgr);
+               mgr->init_imap_added = 0;
+       }
+       err = input_mapper_add(&mgr->imappers, entry, srcimp_map_op, mgr);
+       spin_unlock_irqrestore(&mgr->imap_lock, flags);
+
+       return err;
+}
+
+static int srcimp_imap_delete(struct srcimp_mgr *mgr, struct imapper *entry)
+{
+       unsigned long flags;
+       int err;
+
+       spin_lock_irqsave(&mgr->imap_lock, flags);
+       err = input_mapper_delete(&mgr->imappers, entry, srcimp_map_op, mgr);
+       if (list_empty(&mgr->imappers)) {
+               input_mapper_add(&mgr->imappers, mgr->init_imap,
+                                srcimp_map_op, mgr);
+               mgr->init_imap_added = 1;
+       }
+       spin_unlock_irqrestore(&mgr->imap_lock, flags);
+
+       return err;
+}
+
+int srcimp_mgr_create(void *hw, struct srcimp_mgr **rsrcimp_mgr)
+{
+       int err;
+       struct srcimp_mgr *srcimp_mgr;
+       struct imapper *entry;
+
+       *rsrcimp_mgr = NULL;
+       srcimp_mgr = kzalloc(sizeof(*srcimp_mgr), GFP_KERNEL);
+       if (NULL == srcimp_mgr)
+               return -ENOMEM;
+
+       err = rsc_mgr_init(&srcimp_mgr->mgr, SRCIMP, SRCIMP_RESOURCE_NUM, hw);
+       if (err)
+               goto error1;
+
+       spin_lock_init(&srcimp_mgr->mgr_lock);
+       spin_lock_init(&srcimp_mgr->imap_lock);
+       INIT_LIST_HEAD(&srcimp_mgr->imappers);
+       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+       if (NULL == entry) {
+               err = -ENOMEM;
+               goto error2;
+       }
+       entry->slot = entry->addr = entry->next = entry->user = 0;
+       list_add(&entry->list, &srcimp_mgr->imappers);
+       srcimp_mgr->init_imap = entry;
+       srcimp_mgr->init_imap_added = 1;
+
+       srcimp_mgr->get_srcimp = get_srcimp_rsc;
+       srcimp_mgr->put_srcimp = put_srcimp_rsc;
+       srcimp_mgr->imap_add = srcimp_imap_add;
+       srcimp_mgr->imap_delete = srcimp_imap_delete;
+
+       *rsrcimp_mgr = srcimp_mgr;
+
+       return 0;
+
+error2:
+       rsc_mgr_uninit(&srcimp_mgr->mgr);
+error1:
+       kfree(srcimp_mgr);
+       return err;
+}
+
+int srcimp_mgr_destroy(struct srcimp_mgr *srcimp_mgr)
+{
+       unsigned long flags;
+
+       /* free src input mapper list */
+       spin_lock_irqsave(&srcimp_mgr->imap_lock, flags);
+       free_input_mapper_list(&srcimp_mgr->imappers);
+       spin_unlock_irqrestore(&srcimp_mgr->imap_lock, flags);
+
+       rsc_mgr_uninit(&srcimp_mgr->mgr);
+       kfree(srcimp_mgr);
+
+       return 0;
+}
diff --git a/sound/pci/ctxfi/ctsrc.h b/sound/pci/ctxfi/ctsrc.h
new file mode 100644 (file)
index 0000000..259366a
--- /dev/null
@@ -0,0 +1,149 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File       ctsrc.h
+ *
+ * @Brief
+ * This file contains the definition of the Sample Rate Convertor
+ * resource management object.
+ *
+ * @Author     Liu Chun
+ * @Date       May 13 2008
+ *
+ */
+
+#ifndef CTSRC_H
+#define CTSRC_H
+
+#include "ctresource.h"
+#include "ctimap.h"
+#include <linux/spinlock.h>
+#include <linux/list.h>
+
+#define SRC_STATE_OFF  0x0
+#define SRC_STATE_INIT 0x4
+#define SRC_STATE_RUN  0x5
+
+#define SRC_SF_U8      0x0
+#define SRC_SF_S16     0x1
+#define SRC_SF_S24     0x2
+#define SRC_SF_S32     0x3
+#define SRC_SF_F32     0x4
+
+/* Define the descriptor of a src resource */
+enum SRCMODE {
+       MEMRD,          /* Read data from host memory */
+       MEMWR,          /* Write data to host memory */
+       ARCRW,          /* Read from and write to audio ring channel */
+       NUM_SRCMODES
+};
+
+struct src_rsc_ops;
+
+struct src {
+       struct rsc rsc; /* Basic resource info */
+       struct src *intlv; /* Pointer to next interleaved SRC in a series */
+       struct src_rsc_ops *ops; /* SRC specific operations */
+       /* Number of contiguous srcs for interleaved usage */
+       unsigned char multi;
+       unsigned char mode; /* Working mode of this SRC resource */
+};
+
+struct src_rsc_ops {
+       int (*set_state)(struct src *src, unsigned int state);
+       int (*set_bm)(struct src *src, unsigned int bm);
+       int (*set_sf)(struct src *src, unsigned int sf);
+       int (*set_pm)(struct src *src, unsigned int pm);
+       int (*set_rom)(struct src *src, unsigned int rom);
+       int (*set_vo)(struct src *src, unsigned int vo);
+       int (*set_st)(struct src *src, unsigned int st);
+       int (*set_bp)(struct src *src, unsigned int bp);
+       int (*set_cisz)(struct src *src, unsigned int cisz);
+       int (*set_ca)(struct src *src, unsigned int ca);
+       int (*set_sa)(struct src *src, unsigned int sa);
+       int (*set_la)(struct src *src, unsigned int la);
+       int (*set_pitch)(struct src *src, unsigned int pitch);
+       int (*set_clr_zbufs)(struct src *src);
+       int (*commit_write)(struct src *src);
+       int (*get_ca)(struct src *src);
+       int (*init)(struct src *src);
+       struct src* (*next_interleave)(struct src *src);
+};
+
+/* Define src resource request description info */
+struct src_desc {
+       /* Number of contiguous master srcs for interleaved usage */
+       unsigned char multi;
+       unsigned char msr;
+       unsigned char mode; /* Working mode of the requested srcs */
+};
+
+/* Define src manager object */
+struct src_mgr {
+       struct rsc_mgr mgr;     /* Basic resource manager info */
+       spinlock_t mgr_lock;
+
+        /* request src resource */
+       int (*get_src)(struct src_mgr *mgr,
+                      const struct src_desc *desc, struct src **rsrc);
+       /* return src resource */
+       int (*put_src)(struct src_mgr *mgr, struct src *src);
+       int (*src_enable_s)(struct src_mgr *mgr, struct src *src);
+       int (*src_enable)(struct src_mgr *mgr, struct src *src);
+       int (*src_disable)(struct src_mgr *mgr, struct src *src);
+       int (*commit_write)(struct src_mgr *mgr);
+};
+
+/* Define the descriptor of a SRC Input Mapper resource */
+struct srcimp_mgr;
+struct srcimp_rsc_ops;
+
+struct srcimp {
+       struct rsc rsc;
+       unsigned char idx[8];
+       struct imapper *imappers;
+       unsigned int mapped; /* A bit-map indicating which conj rsc is mapped */
+       struct srcimp_mgr *mgr;
+       struct srcimp_rsc_ops *ops;
+};
+
+struct srcimp_rsc_ops {
+       int (*map)(struct srcimp *srcimp, struct src *user, struct rsc *input);
+       int (*unmap)(struct srcimp *srcimp);
+};
+
+/* Define SRCIMP resource request description info */
+struct srcimp_desc {
+       unsigned int msr;
+};
+
+struct srcimp_mgr {
+       struct rsc_mgr mgr;     /* Basic resource manager info */
+       spinlock_t mgr_lock;
+       spinlock_t imap_lock;
+       struct list_head imappers;
+       struct imapper *init_imap;
+       unsigned int init_imap_added;
+
+        /* request srcimp resource */
+       int (*get_srcimp)(struct srcimp_mgr *mgr,
+                         const struct srcimp_desc *desc,
+                         struct srcimp **rsrcimp);
+       /* return srcimp resource */
+       int (*put_srcimp)(struct srcimp_mgr *mgr, struct srcimp *srcimp);
+       int (*imap_add)(struct srcimp_mgr *mgr, struct imapper *entry);
+       int (*imap_delete)(struct srcimp_mgr *mgr, struct imapper *entry);
+};
+
+/* Constructor and destructor of SRC resource manager */
+int src_mgr_create(void *hw, struct src_mgr **rsrc_mgr);
+int src_mgr_destroy(struct src_mgr *src_mgr);
+/* Constructor and destructor of SRCIMP resource manager */
+int srcimp_mgr_create(void *hw, struct srcimp_mgr **rsrc_mgr);
+int srcimp_mgr_destroy(struct srcimp_mgr *srcimp_mgr);
+
+#endif /* CTSRC_H */
diff --git a/sound/pci/ctxfi/cttimer.c b/sound/pci/ctxfi/cttimer.c
new file mode 100644 (file)
index 0000000..779c6c3
--- /dev/null
@@ -0,0 +1,441 @@
+/*
+ * PCM timer handling on ctxfi
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ */
+
+#include <linux/slab.h>
+#include <linux/math64.h>
+#include <linux/moduleparam.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include "ctatc.h"
+#include "cthardware.h"
+#include "cttimer.h"
+
+static int use_system_timer;
+MODULE_PARM_DESC(use_system_timer, "Foce to use system-timer");
+module_param(use_system_timer, bool, S_IRUGO);
+
+struct ct_timer_ops {
+       void (*init)(struct ct_timer_instance *);
+       void (*prepare)(struct ct_timer_instance *);
+       void (*start)(struct ct_timer_instance *);
+       void (*stop)(struct ct_timer_instance *);
+       void (*free_instance)(struct ct_timer_instance *);
+       void (*interrupt)(struct ct_timer *);
+       void (*free_global)(struct ct_timer *);
+};
+
+/* timer instance -- assigned to each PCM stream */
+struct ct_timer_instance {
+       spinlock_t lock;
+       struct ct_timer *timer_base;
+       struct ct_atc_pcm *apcm;
+       struct snd_pcm_substream *substream;
+       struct timer_list timer;
+       struct list_head instance_list;
+       struct list_head running_list;
+       unsigned int position;
+       unsigned int frag_count;
+       unsigned int running:1;
+       unsigned int need_update:1;
+};
+
+/* timer instance manager */
+struct ct_timer {
+       spinlock_t lock;                /* global timer lock (for xfitimer) */
+       spinlock_t list_lock;           /* lock for instance list */
+       struct ct_atc *atc;
+       struct ct_timer_ops *ops;
+       struct list_head instance_head;
+       struct list_head running_head;
+       unsigned int wc;                /* current wallclock */
+       unsigned int irq_handling:1;    /* in IRQ handling */
+       unsigned int reprogram:1;       /* need to reprogram the internval */
+       unsigned int running:1;         /* global timer running */
+};
+
+
+/*
+ * system-timer-based updates
+ */
+
+static void ct_systimer_callback(unsigned long data)
+{
+       struct ct_timer_instance *ti = (struct ct_timer_instance *)data;
+       struct snd_pcm_substream *substream = ti->substream;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct ct_atc_pcm *apcm = ti->apcm;
+       unsigned int period_size = runtime->period_size;
+       unsigned int buffer_size = runtime->buffer_size;
+       unsigned long flags;
+       unsigned int position, dist, interval;
+
+       position = substream->ops->pointer(substream);
+       dist = (position + buffer_size - ti->position) % buffer_size;
+       if (dist >= period_size ||
+           position / period_size != ti->position / period_size) {
+               apcm->interrupt(apcm);
+               ti->position = position;
+       }
+       /* Add extra HZ*5/1000 to avoid overrun issue when recording
+        * at 8kHz in 8-bit format or at 88kHz in 24-bit format. */
+       interval = ((period_size - (position % period_size))
+                  * HZ + (runtime->rate - 1)) / runtime->rate + HZ * 5 / 1000;
+       spin_lock_irqsave(&ti->lock, flags);
+       if (ti->running)
+               mod_timer(&ti->timer, jiffies + interval);
+       spin_unlock_irqrestore(&ti->lock, flags);
+}
+
+static void ct_systimer_init(struct ct_timer_instance *ti)
+{
+       setup_timer(&ti->timer, ct_systimer_callback,
+                   (unsigned long)ti);
+}
+
+static void ct_systimer_start(struct ct_timer_instance *ti)
+{
+       struct snd_pcm_runtime *runtime = ti->substream->runtime;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ti->lock, flags);
+       ti->running = 1;
+       mod_timer(&ti->timer,
+                 jiffies + (runtime->period_size * HZ +
+                            (runtime->rate - 1)) / runtime->rate);
+       spin_unlock_irqrestore(&ti->lock, flags);
+}
+
+static void ct_systimer_stop(struct ct_timer_instance *ti)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ti->lock, flags);
+       ti->running = 0;
+       del_timer(&ti->timer);
+       spin_unlock_irqrestore(&ti->lock, flags);
+}
+
+static void ct_systimer_prepare(struct ct_timer_instance *ti)
+{
+       ct_systimer_stop(ti);
+       try_to_del_timer_sync(&ti->timer);
+}
+
+#define ct_systimer_free       ct_systimer_prepare
+
+static struct ct_timer_ops ct_systimer_ops = {
+       .init = ct_systimer_init,
+       .free_instance = ct_systimer_free,
+       .prepare = ct_systimer_prepare,
+       .start = ct_systimer_start,
+       .stop = ct_systimer_stop,
+};
+
+
+/*
+ * Handling multiple streams using a global emu20k1 timer irq
+ */
+
+#define CT_TIMER_FREQ  48000
+#define MIN_TICKS      1
+#define MAX_TICKS      ((1 << 13) - 1)
+
+static void ct_xfitimer_irq_rearm(struct ct_timer *atimer, int ticks)
+{
+       struct hw *hw = atimer->atc->hw;
+       if (ticks > MAX_TICKS)
+               ticks = MAX_TICKS;
+       hw->set_timer_tick(hw, ticks);
+       if (!atimer->running)
+               hw->set_timer_irq(hw, 1);
+       atimer->running = 1;
+}
+
+static void ct_xfitimer_irq_stop(struct ct_timer *atimer)
+{
+       if (atimer->running) {
+               struct hw *hw = atimer->atc->hw;
+               hw->set_timer_irq(hw, 0);
+               hw->set_timer_tick(hw, 0);
+               atimer->running = 0;
+       }
+}
+
+static inline unsigned int ct_xfitimer_get_wc(struct ct_timer *atimer)
+{
+       struct hw *hw = atimer->atc->hw;
+       return hw->get_wc(hw);
+}
+
+/*
+ * reprogram the timer interval;
+ * checks the running instance list and determines the next timer interval.
+ * also updates the each stream position, returns the number of streams
+ * to call snd_pcm_period_elapsed() appropriately
+ *
+ * call this inside the lock and irq disabled
+ */
+static int ct_xfitimer_reprogram(struct ct_timer *atimer)
+{
+       struct ct_timer_instance *ti;
+       unsigned int min_intr = (unsigned int)-1;
+       int updates = 0;
+       unsigned int wc, diff;
+
+       if (list_empty(&atimer->running_head)) {
+               ct_xfitimer_irq_stop(atimer);
+               atimer->reprogram = 0; /* clear flag */
+               return 0;
+       }
+
+       wc = ct_xfitimer_get_wc(atimer);
+       diff = wc - atimer->wc;
+       atimer->wc = wc;
+       list_for_each_entry(ti, &atimer->running_head, running_list) {
+               if (ti->frag_count > diff)
+                       ti->frag_count -= diff;
+               else {
+                       unsigned int pos;
+                       unsigned int period_size, rate;
+
+                       period_size = ti->substream->runtime->period_size;
+                       rate = ti->substream->runtime->rate;
+                       pos = ti->substream->ops->pointer(ti->substream);
+                       if (pos / period_size != ti->position / period_size) {
+                               ti->need_update = 1;
+                               ti->position = pos;
+                               updates++;
+                       }
+                       pos %= period_size;
+                       pos = period_size - pos;
+                       ti->frag_count = div_u64((u64)pos * CT_TIMER_FREQ +
+                                                rate - 1, rate);
+               }
+               if (ti->frag_count < min_intr)
+                       min_intr = ti->frag_count;
+       }
+
+       if (min_intr < MIN_TICKS)
+               min_intr = MIN_TICKS;
+       ct_xfitimer_irq_rearm(atimer, min_intr);
+       atimer->reprogram = 0; /* clear flag */
+       return updates;
+}
+
+/* look through the instance list and call period_elapsed if needed */
+static void ct_xfitimer_check_period(struct ct_timer *atimer)
+{
+       struct ct_timer_instance *ti;
+       unsigned long flags;
+
+       spin_lock_irqsave(&atimer->list_lock, flags);
+       list_for_each_entry(ti, &atimer->instance_head, instance_list) {
+               if (ti->need_update) {
+                       ti->need_update = 0;
+                       ti->apcm->interrupt(ti->apcm);
+               }
+       }
+       spin_unlock_irqrestore(&atimer->list_lock, flags);
+}
+
+/* Handle timer-interrupt */
+static void ct_xfitimer_callback(struct ct_timer *atimer)
+{
+       int update;
+       unsigned long flags;
+
+       spin_lock_irqsave(&atimer->lock, flags);
+       atimer->irq_handling = 1;
+       do {
+               update = ct_xfitimer_reprogram(atimer);
+               spin_unlock(&atimer->lock);
+               if (update)
+                       ct_xfitimer_check_period(atimer);
+               spin_lock(&atimer->lock);
+       } while (atimer->reprogram);
+       atimer->irq_handling = 0;
+       spin_unlock_irqrestore(&atimer->lock, flags);
+}
+
+static void ct_xfitimer_prepare(struct ct_timer_instance *ti)
+{
+       ti->frag_count = ti->substream->runtime->period_size;
+       ti->need_update = 0;
+}
+
+
+/* start/stop the timer */
+static void ct_xfitimer_update(struct ct_timer *atimer)
+{
+       unsigned long flags;
+       int update;
+
+       spin_lock_irqsave(&atimer->lock, flags);
+       if (atimer->irq_handling) {
+               /* reached from IRQ handler; let it handle later */
+               atimer->reprogram = 1;
+               spin_unlock_irqrestore(&atimer->lock, flags);
+               return;
+       }
+
+       ct_xfitimer_irq_stop(atimer);
+       update = ct_xfitimer_reprogram(atimer);
+       spin_unlock_irqrestore(&atimer->lock, flags);
+       if (update)
+               ct_xfitimer_check_period(atimer);
+}
+
+static void ct_xfitimer_start(struct ct_timer_instance *ti)
+{
+       struct ct_timer *atimer = ti->timer_base;
+       unsigned long flags;
+
+       spin_lock_irqsave(&atimer->lock, flags);
+       if (list_empty(&ti->running_list))
+               atimer->wc = ct_xfitimer_get_wc(atimer);
+       list_add(&ti->running_list, &atimer->running_head);
+       spin_unlock_irqrestore(&atimer->lock, flags);
+       ct_xfitimer_update(atimer);
+}
+
+static void ct_xfitimer_stop(struct ct_timer_instance *ti)
+{
+       struct ct_timer *atimer = ti->timer_base;
+       unsigned long flags;
+
+       spin_lock_irqsave(&atimer->lock, flags);
+       list_del_init(&ti->running_list);
+       ti->need_update = 0;
+       spin_unlock_irqrestore(&atimer->lock, flags);
+       ct_xfitimer_update(atimer);
+}
+
+static void ct_xfitimer_free_global(struct ct_timer *atimer)
+{
+       ct_xfitimer_irq_stop(atimer);
+}
+
+static struct ct_timer_ops ct_xfitimer_ops = {
+       .prepare = ct_xfitimer_prepare,
+       .start = ct_xfitimer_start,
+       .stop = ct_xfitimer_stop,
+       .interrupt = ct_xfitimer_callback,
+       .free_global = ct_xfitimer_free_global,
+};
+
+/*
+ * timer instance
+ */
+
+struct ct_timer_instance *
+ct_timer_instance_new(struct ct_timer *atimer, struct ct_atc_pcm *apcm)
+{
+       struct ct_timer_instance *ti;
+
+       ti = kzalloc(sizeof(*ti), GFP_KERNEL);
+       if (!ti)
+               return NULL;
+       spin_lock_init(&ti->lock);
+       INIT_LIST_HEAD(&ti->instance_list);
+       INIT_LIST_HEAD(&ti->running_list);
+       ti->timer_base = atimer;
+       ti->apcm = apcm;
+       ti->substream = apcm->substream;
+       if (atimer->ops->init)
+               atimer->ops->init(ti);
+
+       spin_lock_irq(&atimer->list_lock);
+       list_add(&ti->instance_list, &atimer->instance_head);
+       spin_unlock_irq(&atimer->list_lock);
+
+       return ti;
+}
+
+void ct_timer_prepare(struct ct_timer_instance *ti)
+{
+       if (ti->timer_base->ops->prepare)
+               ti->timer_base->ops->prepare(ti);
+       ti->position = 0;
+       ti->running = 0;
+}
+
+void ct_timer_start(struct ct_timer_instance *ti)
+{
+       struct ct_timer *atimer = ti->timer_base;
+       atimer->ops->start(ti);
+}
+
+void ct_timer_stop(struct ct_timer_instance *ti)
+{
+       struct ct_timer *atimer = ti->timer_base;
+       atimer->ops->stop(ti);
+}
+
+void ct_timer_instance_free(struct ct_timer_instance *ti)
+{
+       struct ct_timer *atimer = ti->timer_base;
+
+       atimer->ops->stop(ti); /* to be sure */
+       if (atimer->ops->free_instance)
+               atimer->ops->free_instance(ti);
+
+       spin_lock_irq(&atimer->list_lock);
+       list_del(&ti->instance_list);
+       spin_unlock_irq(&atimer->list_lock);
+
+       kfree(ti);
+}
+
+/*
+ * timer manager
+ */
+
+static void ct_timer_interrupt(void *data, unsigned int status)
+{
+       struct ct_timer *timer = data;
+
+       /* Interval timer interrupt */
+       if ((status & IT_INT) && timer->ops->interrupt)
+               timer->ops->interrupt(timer);
+}
+
+struct ct_timer *ct_timer_new(struct ct_atc *atc)
+{
+       struct ct_timer *atimer;
+       struct hw *hw;
+
+       atimer = kzalloc(sizeof(*atimer), GFP_KERNEL);
+       if (!atimer)
+               return NULL;
+       spin_lock_init(&atimer->lock);
+       spin_lock_init(&atimer->list_lock);
+       INIT_LIST_HEAD(&atimer->instance_head);
+       INIT_LIST_HEAD(&atimer->running_head);
+       atimer->atc = atc;
+       hw = atc->hw;
+       if (!use_system_timer && hw->set_timer_irq) {
+               snd_printd(KERN_INFO "ctxfi: Use xfi-native timer\n");
+               atimer->ops = &ct_xfitimer_ops;
+               hw->irq_callback_data = atimer;
+               hw->irq_callback = ct_timer_interrupt;
+       } else {
+               snd_printd(KERN_INFO "ctxfi: Use system timer\n");
+               atimer->ops = &ct_systimer_ops;
+       }
+       return atimer;
+}
+
+void ct_timer_free(struct ct_timer *atimer)
+{
+       struct hw *hw = atimer->atc->hw;
+       hw->irq_callback = NULL;
+       if (atimer->ops->free_global)
+               atimer->ops->free_global(atimer);
+       kfree(atimer);
+}
+
diff --git a/sound/pci/ctxfi/cttimer.h b/sound/pci/ctxfi/cttimer.h
new file mode 100644 (file)
index 0000000..9793482
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Timer handling
+ */
+
+#ifndef __CTTIMER_H
+#define __CTTIMER_H
+
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+
+struct snd_pcm_substream;
+struct ct_atc;
+struct ct_atc_pcm;
+
+struct ct_timer;
+struct ct_timer_instance;
+
+struct ct_timer *ct_timer_new(struct ct_atc *atc);
+void ct_timer_free(struct ct_timer *atimer);
+
+struct ct_timer_instance *
+ct_timer_instance_new(struct ct_timer *atimer, struct ct_atc_pcm *apcm);
+void ct_timer_instance_free(struct ct_timer_instance *ti);
+void ct_timer_start(struct ct_timer_instance *ti);
+void ct_timer_stop(struct ct_timer_instance *ti);
+void ct_timer_prepare(struct ct_timer_instance *ti);
+
+#endif /* __CTTIMER_H */
diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c
new file mode 100644 (file)
index 0000000..67665a7
--- /dev/null
@@ -0,0 +1,250 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File    ctvmem.c
+ *
+ * @Brief
+ * This file contains the implementation of virtual memory management object
+ * for card device.
+ *
+ * @Author Liu Chun
+ * @Date Apr 1 2008
+ */
+
+#include "ctvmem.h"
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/io.h>
+#include <sound/pcm.h>
+
+#define CT_PTES_PER_PAGE (CT_PAGE_SIZE / sizeof(void *))
+#define CT_ADDRS_PER_PAGE (CT_PTES_PER_PAGE * CT_PAGE_SIZE)
+
+/* *
+ * Find or create vm block based on requested @size.
+ * @size must be page aligned.
+ * */
+static struct ct_vm_block *
+get_vm_block(struct ct_vm *vm, unsigned int size)
+{
+       struct ct_vm_block *block = NULL, *entry;
+       struct list_head *pos;
+
+       size = CT_PAGE_ALIGN(size);
+       if (size > vm->size) {
+               printk(KERN_ERR "ctxfi: Fail! No sufficient device virtural "
+                                 "memory space available!\n");
+               return NULL;
+       }
+
+       mutex_lock(&vm->lock);
+       list_for_each(pos, &vm->unused) {
+               entry = list_entry(pos, struct ct_vm_block, list);
+               if (entry->size >= size)
+                       break; /* found a block that is big enough */
+       }
+       if (pos == &vm->unused)
+               goto out;
+
+       if (entry->size == size) {
+               /* Move the vm node from unused list to used list directly */
+               list_del(&entry->list);
+               list_add(&entry->list, &vm->used);
+               vm->size -= size;
+               block = entry;
+               goto out;
+       }
+
+       block = kzalloc(sizeof(*block), GFP_KERNEL);
+       if (NULL == block)
+               goto out;
+
+       block->addr = entry->addr;
+       block->size = size;
+       list_add(&block->list, &vm->used);
+       entry->addr += size;
+       entry->size -= size;
+       vm->size -= size;
+
+ out:
+       mutex_unlock(&vm->lock);
+       return block;
+}
+
+static void put_vm_block(struct ct_vm *vm, struct ct_vm_block *block)
+{
+       struct ct_vm_block *entry, *pre_ent;
+       struct list_head *pos, *pre;
+
+       block->size = CT_PAGE_ALIGN(block->size);
+
+       mutex_lock(&vm->lock);
+       list_del(&block->list);
+       vm->size += block->size;
+
+       list_for_each(pos, &vm->unused) {
+               entry = list_entry(pos, struct ct_vm_block, list);
+               if (entry->addr >= (block->addr + block->size))
+                       break; /* found a position */
+       }
+       if (pos == &vm->unused) {
+               list_add_tail(&block->list, &vm->unused);
+               entry = block;
+       } else {
+               if ((block->addr + block->size) == entry->addr) {
+                       entry->addr = block->addr;
+                       entry->size += block->size;
+                       kfree(block);
+               } else {
+                       __list_add(&block->list, pos->prev, pos);
+                       entry = block;
+               }
+       }
+
+       pos = &entry->list;
+       pre = pos->prev;
+       while (pre != &vm->unused) {
+               entry = list_entry(pos, struct ct_vm_block, list);
+               pre_ent = list_entry(pre, struct ct_vm_block, list);
+               if ((pre_ent->addr + pre_ent->size) > entry->addr)
+                       break;
+
+               pre_ent->size += entry->size;
+               list_del(pos);
+               kfree(entry);
+               pos = pre;
+               pre = pos->prev;
+       }
+       mutex_unlock(&vm->lock);
+}
+
+/* Map host addr (kmalloced/vmalloced) to device logical addr. */
+static struct ct_vm_block *
+ct_vm_map(struct ct_vm *vm, struct snd_pcm_substream *substream, int size)
+{
+       struct ct_vm_block *block;
+       unsigned int pte_start;
+       unsigned i, pages;
+       unsigned long *ptp;
+
+       block = get_vm_block(vm, size);
+       if (block == NULL) {
+               printk(KERN_ERR "ctxfi: No virtual memory block that is big "
+                                 "enough to allocate!\n");
+               return NULL;
+       }
+
+       ptp = vm->ptp[0];
+       pte_start = (block->addr >> CT_PAGE_SHIFT);
+       pages = block->size >> CT_PAGE_SHIFT;
+       for (i = 0; i < pages; i++) {
+               unsigned long addr;
+               addr = snd_pcm_sgbuf_get_addr(substream, i << CT_PAGE_SHIFT);
+               ptp[pte_start + i] = addr;
+       }
+
+       block->size = size;
+       return block;
+}
+
+static void ct_vm_unmap(struct ct_vm *vm, struct ct_vm_block *block)
+{
+       /* do unmapping */
+       put_vm_block(vm, block);
+}
+
+/* *
+ * return the host (kmalloced) addr of the @index-th device
+ * page talbe page on success, or NULL on failure.
+ * The first returned NULL indicates the termination.
+ * */
+static void *
+ct_get_ptp_virt(struct ct_vm *vm, int index)
+{
+       void *addr;
+
+       addr = (index >= CT_PTP_NUM) ? NULL : vm->ptp[index];
+
+       return addr;
+}
+
+int ct_vm_create(struct ct_vm **rvm)
+{
+       struct ct_vm *vm;
+       struct ct_vm_block *block;
+       int i;
+
+       *rvm = NULL;
+
+       vm = kzalloc(sizeof(*vm), GFP_KERNEL);
+       if (NULL == vm)
+               return -ENOMEM;
+
+       mutex_init(&vm->lock);
+
+       /* Allocate page table pages */
+       for (i = 0; i < CT_PTP_NUM; i++) {
+               vm->ptp[i] = kmalloc(PAGE_SIZE, GFP_KERNEL);
+               if (NULL == vm->ptp[i])
+                       break;
+       }
+       if (!i) {
+               /* no page table pages are allocated */
+               kfree(vm);
+               return -ENOMEM;
+       }
+       vm->size = CT_ADDRS_PER_PAGE * i;
+       /* Initialise remaining ptps */
+       for (; i < CT_PTP_NUM; i++)
+               vm->ptp[i] = NULL;
+
+       vm->map = ct_vm_map;
+       vm->unmap = ct_vm_unmap;
+       vm->get_ptp_virt = ct_get_ptp_virt;
+       INIT_LIST_HEAD(&vm->unused);
+       INIT_LIST_HEAD(&vm->used);
+       block = kzalloc(sizeof(*block), GFP_KERNEL);
+       if (NULL != block) {
+               block->addr = 0;
+               block->size = vm->size;
+               list_add(&block->list, &vm->unused);
+       }
+
+       *rvm = vm;
+       return 0;
+}
+
+/* The caller must ensure no mapping pages are being used
+ * by hardware before calling this function */
+void ct_vm_destroy(struct ct_vm *vm)
+{
+       int i;
+       struct list_head *pos;
+       struct ct_vm_block *entry;
+
+       /* free used and unused list nodes */
+       while (!list_empty(&vm->used)) {
+               pos = vm->used.next;
+               list_del(pos);
+               entry = list_entry(pos, struct ct_vm_block, list);
+               kfree(entry);
+       }
+       while (!list_empty(&vm->unused)) {
+               pos = vm->unused.next;
+               list_del(pos);
+               entry = list_entry(pos, struct ct_vm_block, list);
+               kfree(entry);
+       }
+
+       /* free allocated page table pages */
+       for (i = 0; i < CT_PTP_NUM; i++)
+               kfree(vm->ptp[i]);
+
+       vm->size = 0;
+
+       kfree(vm);
+}
diff --git a/sound/pci/ctxfi/ctvmem.h b/sound/pci/ctxfi/ctvmem.h
new file mode 100644 (file)
index 0000000..01e4fd0
--- /dev/null
@@ -0,0 +1,61 @@
+/**
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ * @File    ctvmem.h
+ *
+ * @Brief
+ * This file contains the definition of virtual memory management object
+ * for card device.
+ *
+ * @Author Liu Chun
+ * @Date Mar 28 2008
+ */
+
+#ifndef CTVMEM_H
+#define CTVMEM_H
+
+#define CT_PTP_NUM     1       /* num of device page table pages */
+
+#include <linux/mutex.h>
+#include <linux/list.h>
+
+/* The chip can handle the page table of 4k pages
+ * (emu20k1 can handle even 8k pages, but we don't use it right now)
+ */
+#define CT_PAGE_SIZE   4096
+#define CT_PAGE_SHIFT  12
+#define CT_PAGE_MASK   (~(PAGE_SIZE - 1))
+#define CT_PAGE_ALIGN(addr)    ALIGN(addr, CT_PAGE_SIZE)
+
+struct ct_vm_block {
+       unsigned int addr;      /* starting logical addr of this block */
+       unsigned int size;      /* size of this device virtual mem block */
+       struct list_head list;
+};
+
+struct snd_pcm_substream;
+
+/* Virtual memory management object for card device */
+struct ct_vm {
+       void *ptp[CT_PTP_NUM];          /* Device page table pages */
+       unsigned int size;              /* Available addr space in bytes */
+       struct list_head unused;        /* List of unused blocks */
+       struct list_head used;          /* List of used blocks */
+       struct mutex lock;
+
+       /* Map host addr (kmalloced/vmalloced) to device logical addr. */
+       struct ct_vm_block *(*map)(struct ct_vm *, struct snd_pcm_substream *,
+                                  int size);
+       /* Unmap device logical addr area. */
+       void (*unmap)(struct ct_vm *, struct ct_vm_block *block);
+       void *(*get_ptp_virt)(struct ct_vm *vm, int index);
+};
+
+int ct_vm_create(struct ct_vm **rvm);
+void ct_vm_destroy(struct ct_vm *vm);
+
+#endif /* CTVMEM_H */
diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c
new file mode 100644 (file)
index 0000000..2d3dd89
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * xfi linux driver.
+ *
+ * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
+ *
+ * This source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/moduleparam.h>
+#include <linux/pci_ids.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include "ctatc.h"
+#include "cthardware.h"
+
+MODULE_AUTHOR("Creative Technology Ltd");
+MODULE_DESCRIPTION("X-Fi driver version 1.03");
+MODULE_LICENSE("GPL v2");
+MODULE_SUPPORTED_DEVICE("{{Creative Labs, Sound Blaster X-Fi}");
+
+static unsigned int reference_rate = 48000;
+static unsigned int multiple = 2;
+MODULE_PARM_DESC(reference_rate, "Reference rate (default=48000)");
+module_param(reference_rate, uint, S_IRUGO);
+MODULE_PARM_DESC(multiple, "Rate multiplier (default=2)");
+module_param(multiple, uint, S_IRUGO);
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for Creative X-Fi driver");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for Creative X-Fi driver");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable Creative X-Fi driver");
+
+static struct pci_device_id ct_pci_dev_ids[] = {
+       /* only X-Fi is supported, so... */
+       { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_20K1),
+         .driver_data = ATC20K1,
+       },
+       { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_20K2),
+         .driver_data = ATC20K2,
+       },
+       { 0, }
+};
+MODULE_DEVICE_TABLE(pci, ct_pci_dev_ids);
+
+static int __devinit
+ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
+{
+       static int dev;
+       struct snd_card *card;
+       struct ct_atc *atc;
+       int err;
+
+       if (dev >= SNDRV_CARDS)
+               return -ENODEV;
+
+       if (!enable[dev]) {
+               dev++;
+               return -ENOENT;
+       }
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err)
+               return err;
+       if ((reference_rate != 48000) && (reference_rate != 44100)) {
+               printk(KERN_ERR "ctxfi: Invalid reference_rate value %u!!!\n",
+                      reference_rate);
+               printk(KERN_ERR "ctxfi: The valid values for reference_rate "
+                      "are 48000 and 44100, Value 48000 is assumed.\n");
+               reference_rate = 48000;
+       }
+       if ((multiple != 1) && (multiple != 2)) {
+               printk(KERN_ERR "ctxfi: Invalid multiple value %u!!!\n",
+                      multiple);
+               printk(KERN_ERR "ctxfi: The valid values for multiple are "
+                      "1 and 2, Value 2 is assumed.\n");
+               multiple = 2;
+       }
+       err = ct_atc_create(card, pci, reference_rate, multiple,
+                           pci_id->driver_data, &atc);
+       if (err < 0)
+               goto error;
+
+       card->private_data = atc;
+
+       /* Create alsa devices supported by this card */
+       err = ct_atc_create_alsa_devs(atc);
+       if (err < 0)
+               goto error;
+
+       strcpy(card->driver, "SB-XFi");
+       strcpy(card->shortname, "Creative X-Fi");
+       snprintf(card->longname, sizeof(card->longname), "%s %s %s",
+                card->shortname, atc->chip_name, atc->model_name);
+
+       err = snd_card_register(card);
+       if (err < 0)
+               goto error;
+
+       pci_set_drvdata(pci, card);
+       dev++;
+
+       return 0;
+
+error:
+       snd_card_free(card);
+       return err;
+}
+
+static void __devexit ct_card_remove(struct pci_dev *pci)
+{
+       snd_card_free(pci_get_drvdata(pci));
+       pci_set_drvdata(pci, NULL);
+}
+
+static struct pci_driver ct_driver = {
+       .name = "SB-XFi",
+       .id_table = ct_pci_dev_ids,
+       .probe = ct_card_probe,
+       .remove = __devexit_p(ct_card_remove),
+};
+
+static int __init ct_card_init(void)
+{
+       return pci_register_driver(&ct_driver);
+}
+
+static void __exit ct_card_exit(void)
+{
+       pci_unregister_driver(&ct_driver);
+}
+
+module_init(ct_card_init)
+module_exit(ct_card_exit)
index cf2d5636d8be895412e978190a365c63ff7c2bd6..fc5591e7777e3a5f914ae990d89b1c8c60b63562 100644 (file)
@@ -9,15 +9,7 @@ snd-emu10k1-objs := emu10k1.o emu10k1_main.o \
 snd-emu10k1-synth-objs := emu10k1_synth.o emu10k1_callback.o emu10k1_patch.o
 snd-emu10k1x-objs := emu10k1x.o
 
-#
-# this function returns:
-#   "m" - CONFIG_SND_SEQUENCER is m
-#   <empty string> - CONFIG_SND_SEQUENCER is undefined
-#   otherwise parameter #1 value
-#
-sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
-
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_EMU10K1) += snd-emu10k1.o
-obj-$(call sequencer,$(CONFIG_SND_EMU10K1)) += snd-emu10k1-synth.o
+obj-$(CONFIG_SND_EMU10K1_SEQ) += snd-emu10k1-synth.o
 obj-$(CONFIG_SND_EMU10K1X) += snd-emu10k1x.o
index 1970f0e70f37ddcb7a19efaa00e912ae94f2521b..4d3ad793e98fb1618048ebf84d47374695604558 100644 (file)
@@ -858,7 +858,6 @@ static int __devinit snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct s
        }
 
        pcm->info_flags = 0;
-       pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
        switch(device) {
        case 0:
                strcpy(pcm->name, "EMU10K1X Front");
index 78f62fd404c29613c802d4c812fb3d639c28e107..55b83ef73c630e83b2d098a45cce1f570923df7f 100644 (file)
@@ -1736,7 +1736,7 @@ static struct snd_pcm_hardware snd_emu10k1_fx8010_playback =
        .buffer_bytes_max =     (128*1024),
        .period_bytes_min =     1024,
        .period_bytes_max =     (128*1024),
-       .periods_min =          1,
+       .periods_min =          2,
        .periods_max =          1024,
        .fifo_size =            0,
 };
index eb2a19b894a0e650c7a6b79705208667a42f62ec..c710150d5065d8257c52d38a096e0e80e4d97a7e 100644 (file)
@@ -139,6 +139,19 @@ config SND_HDA_CODEC_CONEXANT
          snd-hda-codec-conexant.
          This module is automatically loaded at probing.
 
+config SND_HDA_CODEC_CA0110
+       bool "Build Creative CA0110-IBG codec support"
+       depends on SND_HDA_INTEL
+       default y
+       help
+         Say Y here to include Creative CA0110-IBG codec support in
+         snd-hda-intel driver, found on some Creative X-Fi cards.
+
+         When the HD-audio driver is built as a module, the codec
+         support code is also built as another module,
+         snd-hda-codec-ca0110.
+         This module is automatically loaded at probing.
+
 config SND_HDA_CODEC_CMEDIA
        bool "Build C-Media HD-audio codec support"
        default y
index 50f9d0967251296807caa86eea762f80c56fe3ff..e3081d4586cc4b7779056d654b9f126fb987fc2e 100644 (file)
@@ -13,6 +13,7 @@ snd-hda-codec-analog-objs :=  patch_analog.o
 snd-hda-codec-idt-objs :=      patch_sigmatel.o
 snd-hda-codec-si3054-objs :=   patch_si3054.o
 snd-hda-codec-atihdmi-objs :=  patch_atihdmi.o
+snd-hda-codec-ca0110-objs :=   patch_ca0110.o
 snd-hda-codec-conexant-objs := patch_conexant.o
 snd-hda-codec-via-objs :=      patch_via.o
 snd-hda-codec-nvhdmi-objs :=   patch_nvhdmi.o
@@ -40,6 +41,9 @@ endif
 ifdef CONFIG_SND_HDA_CODEC_ATIHDMI
 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o
 endif
+ifdef CONFIG_SND_HDA_CODEC_CA0110
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0110.o
+endif
 ifdef CONFIG_SND_HDA_CODEC_CONEXANT
 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-conexant.o
 endif
index 4de5bacd392924d94482a45b8885182e966780ab..29272f2e95a07945cf805e6c75867f0f1e2cb762 100644 (file)
@@ -45,6 +45,46 @@ static void snd_hda_generate_beep(struct work_struct *work)
                        AC_VERB_SET_BEEP_CONTROL, beep->tone);
 }
 
+/* (non-standard) Linear beep tone calculation for IDT/STAC codecs 
+ *
+ * The tone frequency of beep generator on IDT/STAC codecs is
+ * defined from the 8bit tone parameter, in Hz,
+ *    freq = 48000 * (257 - tone) / 1024
+ * that is from 12kHz to 93.75kHz in step of 46.875 hz
+ */
+static int beep_linear_tone(struct hda_beep *beep, int hz)
+{
+       hz *= 1000; /* fixed point */
+       hz = hz - DIGBEEP_HZ_MIN;
+       if (hz < 0)
+               hz = 0; /* turn off PC beep*/
+       else if (hz >= (DIGBEEP_HZ_MAX - DIGBEEP_HZ_MIN))
+               hz = 0xff;
+       else {
+               hz /= DIGBEEP_HZ_STEP;
+               hz++;
+       }
+       return hz;
+}
+
+/* HD-audio standard beep tone parameter calculation
+ *
+ * The tone frequency in Hz is calculated as
+ *   freq = 48000 / (tone * 4)
+ * from 47Hz to 12kHz
+ */
+static int beep_standard_tone(struct hda_beep *beep, int hz)
+{
+       if (hz <= 0)
+               return 0; /* disabled */
+       hz = 12000 / hz;
+       if (hz > 0xff)
+               return 0xff;
+       if (hz <= 0)
+               return 1;
+       return hz;
+}
+
 static int snd_hda_beep_event(struct input_dev *dev, unsigned int type,
                                unsigned int code, int hz)
 {
@@ -55,21 +95,14 @@ static int snd_hda_beep_event(struct input_dev *dev, unsigned int type,
                if (hz)
                        hz = 1000;
        case SND_TONE:
-               hz *= 1000; /* fixed point */
-               hz = hz - DIGBEEP_HZ_MIN;
-               if (hz < 0)
-                       hz = 0; /* turn off PC beep*/
-               else if (hz >= (DIGBEEP_HZ_MAX - DIGBEEP_HZ_MIN))
-                       hz = 0xff;
-               else {
-                       hz /= DIGBEEP_HZ_STEP;
-                       hz++;
-               }
+               if (beep->linear_tone)
+                       beep->tone = beep_linear_tone(beep, hz);
+               else
+                       beep->tone = beep_standard_tone(beep, hz);
                break;
        default:
                return -1;
        }
-       beep->tone = hz;
 
        /* schedule beep event */
        schedule_work(&beep->beep_work);
index 51bf6a5daf39bd32bf9f1be6c6f94631426878fa..0c3de787c7171a63e31c85fa8d1aa88117a35c48 100644 (file)
@@ -30,8 +30,9 @@ struct hda_beep {
        struct hda_codec *codec;
        char phys[32];
        int tone;
-       int nid;
-       int enabled;
+       hda_nid_t nid;
+       unsigned int enabled:1;
+       unsigned int linear_tone:1;     /* linear tone for IDT/STAC codec */
        struct work_struct beep_work; /* scheduled task for beep event */
 };
 
index 8820faf6c9d82cd556c7de92ec55cb11efa56ebd..562403a2348801aa9f6ba0dfc5b9a1f653347aef 100644 (file)
@@ -48,6 +48,7 @@ static struct hda_vendor_id hda_vendor_ids[] = {
        { 0x1095, "Silicon Image" },
        { 0x10de, "Nvidia" },
        { 0x10ec, "Realtek" },
+       { 0x1102, "Creative" },
        { 0x1106, "VIA" },
        { 0x111d, "IDT" },
        { 0x11c1, "LSI" },
@@ -157,6 +158,39 @@ make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
        return val;
 }
 
+/*
+ * Send and receive a verb
+ */
+static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
+                          unsigned int *res)
+{
+       struct hda_bus *bus = codec->bus;
+       int err;
+
+       if (res)
+               *res = -1;
+ again:
+       snd_hda_power_up(codec);
+       mutex_lock(&bus->cmd_mutex);
+       err = bus->ops.command(bus, cmd);
+       if (!err && res)
+               *res = bus->ops.get_response(bus);
+       mutex_unlock(&bus->cmd_mutex);
+       snd_hda_power_down(codec);
+       if (res && *res == -1 && bus->rirb_error) {
+               if (bus->response_reset) {
+                       snd_printd("hda_codec: resetting BUS due to "
+                                  "fatal communication error\n");
+                       bus->ops.bus_reset(bus);
+               }
+               goto again;
+       }
+       /* clear reset-flag when the communication gets recovered */
+       if (!err)
+               bus->response_reset = 0;
+       return err;
+}
+
 /**
  * snd_hda_codec_read - send a command and get the response
  * @codec: the HDA codec
@@ -173,18 +207,9 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid,
                                int direct,
                                unsigned int verb, unsigned int parm)
 {
-       struct hda_bus *bus = codec->bus;
+       unsigned cmd = make_codec_cmd(codec, nid, direct, verb, parm);
        unsigned int res;
-
-       res = make_codec_cmd(codec, nid, direct, verb, parm);
-       snd_hda_power_up(codec);
-       mutex_lock(&bus->cmd_mutex);
-       if (!bus->ops.command(bus, res))
-               res = bus->ops.get_response(bus);
-       else
-               res = (unsigned int)-1;
-       mutex_unlock(&bus->cmd_mutex);
-       snd_hda_power_down(codec);
+       codec_exec_verb(codec, cmd, &res);
        return res;
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_read);
@@ -204,17 +229,10 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_read);
 int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct,
                         unsigned int verb, unsigned int parm)
 {
-       struct hda_bus *bus = codec->bus;
+       unsigned int cmd = make_codec_cmd(codec, nid, direct, verb, parm);
        unsigned int res;
-       int err;
-
-       res = make_codec_cmd(codec, nid, direct, verb, parm);
-       snd_hda_power_up(codec);
-       mutex_lock(&bus->cmd_mutex);
-       err = bus->ops.command(bus, res);
-       mutex_unlock(&bus->cmd_mutex);
-       snd_hda_power_down(codec);
-       return err;
+       return codec_exec_verb(codec, cmd,
+                              codec->bus->sync_write ? &res : NULL);
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_write);
 
@@ -613,7 +631,10 @@ static int get_codec_name(struct hda_codec *codec)
        const struct hda_vendor_id *c;
        const char *vendor = NULL;
        u16 vendor_id = codec->vendor_id >> 16;
-       char tmp[16], name[32];
+       char tmp[16];
+
+       if (codec->vendor_name)
+               goto get_chip_name;
 
        for (c = hda_vendor_ids; c->id; c++) {
                if (c->id == vendor_id) {
@@ -625,14 +646,21 @@ static int get_codec_name(struct hda_codec *codec)
                sprintf(tmp, "Generic %04x", vendor_id);
                vendor = tmp;
        }
+       codec->vendor_name = kstrdup(vendor, GFP_KERNEL);
+       if (!codec->vendor_name)
+               return -ENOMEM;
+
+ get_chip_name:
+       if (codec->chip_name)
+               return 0;
+
        if (codec->preset && codec->preset->name)
-               snprintf(name, sizeof(name), "%s %s", vendor,
-                        codec->preset->name);
-       else
-               snprintf(name, sizeof(name), "%s ID %x", vendor,
-                        codec->vendor_id & 0xffff);
-       codec->name = kstrdup(name, GFP_KERNEL);
-       if (!codec->name)
+               codec->chip_name = kstrdup(codec->preset->name, GFP_KERNEL);
+       else {
+               sprintf(tmp, "ID %x", codec->vendor_id & 0xffff);
+               codec->chip_name = kstrdup(tmp, GFP_KERNEL);
+       }
+       if (!codec->chip_name)
                return -ENOMEM;
        return 0;
 }
@@ -838,7 +866,8 @@ static void snd_hda_codec_free(struct hda_codec *codec)
        module_put(codec->owner);
        free_hda_cache(&codec->amp_cache);
        free_hda_cache(&codec->cmd_cache);
-       kfree(codec->name);
+       kfree(codec->vendor_name);
+       kfree(codec->chip_name);
        kfree(codec->modelname);
        kfree(codec->wcaps);
        kfree(codec);
@@ -979,15 +1008,16 @@ int snd_hda_codec_configure(struct hda_codec *codec)
        int err;
 
        codec->preset = find_codec_preset(codec);
-       if (!codec->name) {
+       if (!codec->vendor_name || !codec->chip_name) {
                err = get_codec_name(codec);
                if (err < 0)
                        return err;
        }
        /* audio codec should override the mixer name */
        if (codec->afg || !*codec->bus->card->mixername)
-               strlcpy(codec->bus->card->mixername, codec->name,
-                       sizeof(codec->bus->card->mixername));
+               snprintf(codec->bus->card->mixername,
+                        sizeof(codec->bus->card->mixername),
+                        "%s %s", codec->vendor_name, codec->chip_name);
 
        if (is_generic_config(codec)) {
                err = snd_hda_parse_generic_codec(codec);
@@ -1055,6 +1085,8 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup_stream);
 /* FIXME: more better hash key? */
 #define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24))
 #define HDA_HASH_PINCAP_KEY(nid) (u32)((nid) + (0x02 << 24))
+#define HDA_HASH_PARPCM_KEY(nid) (u32)((nid) + (0x03 << 24))
+#define HDA_HASH_PARSTR_KEY(nid) (u32)((nid) + (0x04 << 24))
 #define INFO_AMP_CAPS  (1<<0)
 #define INFO_AMP_VOL(ch)       (1 << (1 + (ch)))
 
@@ -1145,19 +1177,32 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
 }
 EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps);
 
-u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
+static unsigned int
+query_caps_hash(struct hda_codec *codec, hda_nid_t nid, u32 key,
+               unsigned int (*func)(struct hda_codec *, hda_nid_t))
 {
        struct hda_amp_info *info;
 
-       info = get_alloc_amp_hash(codec, HDA_HASH_PINCAP_KEY(nid));
+       info = get_alloc_amp_hash(codec, key);
        if (!info)
                return 0;
        if (!info->head.val) {
-               info->amp_caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
                info->head.val |= INFO_AMP_CAPS;
+               info->amp_caps = func(codec, nid);
        }
        return info->amp_caps;
 }
+
+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);
+}
+
+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),
+                              read_pin_cap);
+}
 EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps);
 
 /*
@@ -1432,6 +1477,8 @@ _snd_hda_find_mixer_ctl(struct hda_codec *codec,
        memset(&id, 0, sizeof(id));
        id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
        id.index = idx;
+       if (snd_BUG_ON(strlen(name) >= sizeof(id.name)))
+               return NULL;
        strcpy(id.name, name);
        return snd_ctl_find_id(codec->bus->card, &id);
 }
@@ -2242,28 +2289,22 @@ EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls);
 int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
                              int direct, unsigned int verb, unsigned int parm)
 {
-       struct hda_bus *bus = codec->bus;
-       unsigned int res;
-       int err;
+       int err = snd_hda_codec_write(codec, nid, direct, verb, parm);
+       struct hda_cache_head *c;
+       u32 key;
 
-       res = make_codec_cmd(codec, nid, direct, verb, parm);
-       snd_hda_power_up(codec);
-       mutex_lock(&bus->cmd_mutex);
-       err = bus->ops.command(bus, res);
-       if (!err) {
-               struct hda_cache_head *c;
-               u32 key;
-               /* parm may contain the verb stuff for get/set amp */
-               verb = verb | (parm >> 8);
-               parm &= 0xff;
-               key = build_cmd_cache_key(nid, verb);
-               c = get_alloc_hash(&codec->cmd_cache, key);
-               if (c)
-                       c->val = parm;
-       }
-       mutex_unlock(&bus->cmd_mutex);
-       snd_hda_power_down(codec);
-       return err;
+       if (err < 0)
+               return err;
+       /* parm may contain the verb stuff for get/set amp */
+       verb = verb | (parm >> 8);
+       parm &= 0xff;
+       key = build_cmd_cache_key(nid, verb);
+       mutex_lock(&codec->bus->cmd_mutex);
+       c = get_alloc_hash(&codec->cmd_cache, key);
+       if (c)
+               c->val = parm;
+       mutex_unlock(&codec->bus->cmd_mutex);
+       return 0;
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache);
 
@@ -2321,7 +2362,8 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
                if (wcaps & AC_WCAP_POWER) {
                        unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >>
                                AC_WCAP_TYPE_SHIFT;
-                       if (wid_type == AC_WID_PIN) {
+                       if (power_state == AC_PWRST_D3 &&
+                           wid_type == AC_WID_PIN) {
                                unsigned int pincap;
                                /*
                                 * don't power down the widget if it controls
@@ -2333,7 +2375,7 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
                                                nid, 0,
                                                AC_VERB_GET_EAPD_BTLENABLE, 0);
                                        eapd &= 0x02;
-                                       if (power_state == AC_PWRST_D3 && eapd)
+                                       if (eapd)
                                                continue;
                                }
                        }
@@ -2544,6 +2586,41 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
 }
 EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format);
 
+static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid)
+{
+       unsigned int val = 0;
+       if (nid != codec->afg &&
+           (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD))
+               val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
+       if (!val || val == -1)
+               val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM);
+       if (!val || val == -1)
+               return 0;
+       return val;
+}
+
+static unsigned int query_pcm_param(struct hda_codec *codec, hda_nid_t nid)
+{
+       return query_caps_hash(codec, nid, HDA_HASH_PARPCM_KEY(nid),
+                              get_pcm_param);
+}
+
+static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid)
+{
+       unsigned int streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
+       if (!streams || streams == -1)
+               streams = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM);
+       if (!streams || streams == -1)
+               return 0;
+       return streams;
+}
+
+static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid)
+{
+       return query_caps_hash(codec, nid, HDA_HASH_PARSTR_KEY(nid),
+                              get_stream_param);
+}
+
 /**
  * snd_hda_query_supported_pcm - query the supported PCM rates and formats
  * @codec: the HDA codec
@@ -2562,15 +2639,8 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
 {
        unsigned int i, val, wcaps;
 
-       val = 0;
        wcaps = get_wcaps(codec, nid);
-       if (nid != codec->afg && (wcaps & AC_WCAP_FORMAT_OVRD)) {
-               val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
-               if (val == -1)
-                       return -EIO;
-       }
-       if (!val)
-               val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM);
+       val = query_pcm_param(codec, nid);
 
        if (ratesp) {
                u32 rates = 0;
@@ -2592,15 +2662,9 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
                u64 formats = 0;
                unsigned int streams, bps;
 
-               streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
-               if (streams == -1)
+               streams = query_stream_param(codec, nid);
+               if (!streams)
                        return -EIO;
-               if (!streams) {
-                       streams = snd_hda_param_read(codec, codec->afg,
-                                                    AC_PAR_STREAM);
-                       if (streams == -1)
-                               return -EIO;
-               }
 
                bps = 0;
                if (streams & AC_SUPFMT_PCM) {
@@ -2674,17 +2738,9 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
        int i;
        unsigned int val = 0, rate, stream;
 
-       if (nid != codec->afg &&
-           (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) {
-               val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
-               if (val == -1)
-                       return 0;
-       }
-       if (!val) {
-               val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM);
-               if (val == -1)
-                       return 0;
-       }
+       val = query_pcm_param(codec, nid);
+       if (!val)
+               return 0;
 
        rate = format & 0xff00;
        for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++)
@@ -2696,12 +2752,8 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
        if (i >= AC_PAR_PCM_RATE_BITS)
                return 0;
 
-       stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
-       if (stream == -1)
-               return 0;
-       if (!stream && nid != codec->afg)
-               stream = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM);
-       if (!stream || stream == -1)
+       stream = query_stream_param(codec, nid);
+       if (!stream)
                return 0;
 
        if (stream & AC_SUPFMT_PCM) {
@@ -3835,11 +3887,10 @@ EXPORT_SYMBOL_HDA(auto_pin_cfg_labels);
 /**
  * snd_hda_suspend - suspend the codecs
  * @bus: the HDA bus
- * @state: suspsend state
  *
  * Returns 0 if successful.
  */
-int snd_hda_suspend(struct hda_bus *bus, pm_message_t state)
+int snd_hda_suspend(struct hda_bus *bus)
 {
        struct hda_codec *codec;
 
index 2fdecf4b0eb631b89ef15f47ef1f37c3ac2e13ed..cad79efaabc95dfdfa480153fbe7d1dcc076c382 100644 (file)
@@ -574,6 +574,8 @@ struct hda_bus_ops {
        /* attach a PCM stream */
        int (*attach_pcm)(struct hda_bus *bus, struct hda_codec *codec,
                          struct hda_pcm *pcm);
+       /* reset bus for retry verb */
+       void (*bus_reset)(struct hda_bus *bus);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        /* notify power-up/down from codec to controller */
        void (*pm_notify)(struct hda_bus *bus);
@@ -622,7 +624,13 @@ struct hda_bus {
 
        /* misc op flags */
        unsigned int needs_damn_long_delay :1;
+       unsigned int allow_bus_reset:1; /* allow bus reset at fatal error */
+       unsigned int sync_write:1;      /* sync after verb write */
+       /* status for codec/controller */
        unsigned int shutdown :1;       /* being unloaded */
+       unsigned int rirb_error:1;      /* error in codec communication */
+       unsigned int response_reset:1;  /* controller was reset */
+       unsigned int in_reset:1;        /* during reset operation */
 };
 
 /*
@@ -747,7 +755,8 @@ struct hda_codec {
        /* detected preset */
        const struct hda_codec_preset *preset;
        struct module *owner;
-       const char *name;       /* codec name */
+       const char *vendor_name;        /* codec vendor name */
+       const char *chip_name;          /* codec chip name */
        const char *modelname;  /* model name for preset */
 
        /* set by patch */
@@ -905,7 +914,7 @@ void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen);
  * power management
  */
 #ifdef CONFIG_PM
-int snd_hda_suspend(struct hda_bus *bus, pm_message_t state);
+int snd_hda_suspend(struct hda_bus *bus);
 int snd_hda_resume(struct hda_bus *bus);
 #endif
 
index 1c57505c2874d152ca4e76e3fbdefae5ecd81383..6812fbe80fa4d4504d46e0ea3de9424ecc9c7ee0 100644 (file)
@@ -242,7 +242,8 @@ CODEC_INFO_SHOW(subsystem_id);
 CODEC_INFO_SHOW(revision_id);
 CODEC_INFO_SHOW(afg);
 CODEC_INFO_SHOW(mfg);
-CODEC_INFO_STR_SHOW(name);
+CODEC_INFO_STR_SHOW(vendor_name);
+CODEC_INFO_STR_SHOW(chip_name);
 CODEC_INFO_STR_SHOW(modelname);
 
 #define CODEC_INFO_STORE(type)                                 \
@@ -275,7 +276,8 @@ static ssize_t type##_store(struct device *dev,                     \
 CODEC_INFO_STORE(vendor_id);
 CODEC_INFO_STORE(subsystem_id);
 CODEC_INFO_STORE(revision_id);
-CODEC_INFO_STR_STORE(name);
+CODEC_INFO_STR_STORE(vendor_name);
+CODEC_INFO_STR_STORE(chip_name);
 CODEC_INFO_STR_STORE(modelname);
 
 #define CODEC_ACTION_STORE(type)                               \
@@ -499,7 +501,8 @@ static struct device_attribute codec_attrs[] = {
        CODEC_ATTR_RW(revision_id),
        CODEC_ATTR_RO(afg),
        CODEC_ATTR_RO(mfg),
-       CODEC_ATTR_RW(name),
+       CODEC_ATTR_RW(vendor_name),
+       CODEC_ATTR_RW(chip_name),
        CODEC_ATTR_RW(modelname),
        CODEC_ATTR_RW(init_verbs),
        CODEC_ATTR_RW(hints),
index 3128e1a6bc65ded0dfbf62c3d48e8b78ecd97b1b..4e9ea70802701247ef09f6d1a6ce4a68164a216f 100644 (file)
@@ -128,21 +128,33 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
                         "{ULI, M5461}}");
 MODULE_DESCRIPTION("Intel HDA driver");
 
+#ifdef CONFIG_SND_VERBOSE_PRINTK
+#define SFX    /* nop */
+#else
 #define SFX    "hda-intel: "
-
+#endif
 
 /*
  * registers
  */
 #define ICH6_REG_GCAP                  0x00
+#define   ICH6_GCAP_64OK       (1 << 0)   /* 64bit address support */
+#define   ICH6_GCAP_NSDO       (3 << 1)   /* # of serial data out signals */
+#define   ICH6_GCAP_BSS                (31 << 3)  /* # of bidirectional streams */
+#define   ICH6_GCAP_ISS                (15 << 8)  /* # of input streams */
+#define   ICH6_GCAP_OSS                (15 << 12) /* # of output streams */
 #define ICH6_REG_VMIN                  0x02
 #define ICH6_REG_VMAJ                  0x03
 #define ICH6_REG_OUTPAY                        0x04
 #define ICH6_REG_INPAY                 0x06
 #define ICH6_REG_GCTL                  0x08
+#define   ICH6_GCTL_RESET      (1 << 0)   /* controller reset */
+#define   ICH6_GCTL_FCNTRL     (1 << 1)   /* flush control */
+#define   ICH6_GCTL_UNSOL      (1 << 8)   /* accept unsol. response enable */
 #define ICH6_REG_WAKEEN                        0x0c
 #define ICH6_REG_STATESTS              0x0e
 #define ICH6_REG_GSTS                  0x10
+#define   ICH6_GSTS_FSTS       (1 << 1)   /* flush status */
 #define ICH6_REG_INTCTL                        0x20
 #define ICH6_REG_INTSTS                        0x24
 #define ICH6_REG_WALCLK                        0x30
@@ -150,17 +162,27 @@ MODULE_DESCRIPTION("Intel HDA driver");
 #define ICH6_REG_CORBLBASE             0x40
 #define ICH6_REG_CORBUBASE             0x44
 #define ICH6_REG_CORBWP                        0x48
-#define ICH6_REG_CORBRP                        0x4A
+#define ICH6_REG_CORBRP                        0x4a
+#define   ICH6_CORBRP_RST      (1 << 15)  /* read pointer reset */
 #define ICH6_REG_CORBCTL               0x4c
+#define   ICH6_CORBCTL_RUN     (1 << 1)   /* enable DMA */
+#define   ICH6_CORBCTL_CMEIE   (1 << 0)   /* enable memory error irq */
 #define ICH6_REG_CORBSTS               0x4d
+#define   ICH6_CORBSTS_CMEI    (1 << 0)   /* memory error indication */
 #define ICH6_REG_CORBSIZE              0x4e
 
 #define ICH6_REG_RIRBLBASE             0x50
 #define ICH6_REG_RIRBUBASE             0x54
 #define ICH6_REG_RIRBWP                        0x58
+#define   ICH6_RIRBWP_RST      (1 << 15)  /* write pointer reset */
 #define ICH6_REG_RINTCNT               0x5a
 #define ICH6_REG_RIRBCTL               0x5c
+#define   ICH6_RBCTL_IRQ_EN    (1 << 0)   /* enable IRQ */
+#define   ICH6_RBCTL_DMA_EN    (1 << 1)   /* enable DMA */
+#define   ICH6_RBCTL_OVERRUN_EN        (1 << 2)   /* enable overrun irq */
 #define ICH6_REG_RIRBSTS               0x5d
+#define   ICH6_RBSTS_IRQ       (1 << 0)   /* response irq */
+#define   ICH6_RBSTS_OVERRUN   (1 << 2)   /* overrun irq */
 #define ICH6_REG_RIRBSIZE              0x5e
 
 #define ICH6_REG_IC                    0x60
@@ -257,16 +279,6 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
 #define ICH6_INT_CTRL_EN       0x40000000 /* controller interrupt enable bit */
 #define ICH6_INT_GLOBAL_EN     0x80000000 /* global interrupt enable bit */
 
-/* GCTL unsolicited response enable bit */
-#define ICH6_GCTL_UREN         (1<<8)
-
-/* GCTL reset bit */
-#define ICH6_GCTL_RESET                (1<<0)
-
-/* CORB/RIRB control, read/write pointer */
-#define ICH6_RBCTL_DMA_EN      0x02    /* enable DMA */
-#define ICH6_RBCTL_IRQ_EN      0x01    /* enable IRQ */
-#define ICH6_RBRWP_CLR         0x8000  /* read/write pointer clear */
 /* below are so far hardcoded - should read registers in future */
 #define ICH6_MAX_CORB_ENTRIES  256
 #define ICH6_MAX_RIRB_ENTRIES  256
@@ -512,25 +524,25 @@ static void azx_init_cmd_io(struct azx *chip)
        /* set the corb write pointer to 0 */
        azx_writew(chip, CORBWP, 0);
        /* reset the corb hw read pointer */
-       azx_writew(chip, CORBRP, ICH6_RBRWP_CLR);
+       azx_writew(chip, CORBRP, ICH6_CORBRP_RST);
        /* enable corb dma */
-       azx_writeb(chip, CORBCTL, ICH6_RBCTL_DMA_EN);
+       azx_writeb(chip, CORBCTL, ICH6_CORBCTL_RUN);
 
        /* RIRB set up */
        chip->rirb.addr = chip->rb.addr + 2048;
        chip->rirb.buf = (u32 *)(chip->rb.area + 2048);
+       chip->rirb.wp = chip->rirb.rp = chip->rirb.cmds = 0;
        azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr);
        azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr));
 
        /* set the rirb size to 256 entries (ULI requires explicitly) */
        azx_writeb(chip, RIRBSIZE, 0x02);
        /* reset the rirb hw write pointer */
-       azx_writew(chip, RIRBWP, ICH6_RBRWP_CLR);
+       azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST);
        /* set N=1, get RIRB response interrupt for new entry */
        azx_writew(chip, RINTCNT, 1);
        /* enable rirb dma and response irq */
        azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN);
-       chip->rirb.rp = chip->rirb.cmds = 0;
 }
 
 static void azx_free_cmd_io(struct azx *chip)
@@ -606,6 +618,7 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus)
                }
                if (!chip->rirb.cmds) {
                        smp_rmb();
+                       bus->rirb_error = 0;
                        return chip->rirb.res; /* the last value */
                }
                if (time_after(jiffies, timeout))
@@ -619,19 +632,21 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus)
        }
 
        if (chip->msi) {
-               snd_printk(KERN_WARNING "hda_intel: No response from codec, "
+               snd_printk(KERN_WARNING SFX "No response from codec, "
                           "disabling MSI: last cmd=0x%08x\n", chip->last_cmd);
                free_irq(chip->irq, chip);
                chip->irq = -1;
                pci_disable_msi(chip->pci);
                chip->msi = 0;
-               if (azx_acquire_irq(chip, 1) < 0)
+               if (azx_acquire_irq(chip, 1) < 0) {
+                       bus->rirb_error = 1;
                        return -1;
+               }
                goto again;
        }
 
        if (!chip->polling_mode) {
-               snd_printk(KERN_WARNING "hda_intel: azx_get_response timeout, "
+               snd_printk(KERN_WARNING SFX "azx_get_response timeout, "
                           "switching to polling mode: last cmd=0x%08x\n",
                           chip->last_cmd);
                chip->polling_mode = 1;
@@ -646,14 +661,23 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus)
                return -1;
        }
 
+       /* a fatal communication error; need either to reset or to fallback
+        * to the single_cmd mode
+        */
+       bus->rirb_error = 1;
+       if (bus->allow_bus_reset && !bus->response_reset && !bus->in_reset) {
+               bus->response_reset = 1;
+               return -1; /* give a chance to retry */
+       }
+
        snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, "
                   "switching to single_cmd mode: last cmd=0x%08x\n",
                   chip->last_cmd);
-       chip->rirb.rp = azx_readb(chip, RIRBWP);
-       chip->rirb.cmds = 0;
-       /* switch to single_cmd mode */
        chip->single_cmd = 1;
+       bus->response_reset = 0;
+       /* re-initialize CORB/RIRB */
        azx_free_cmd_io(chip);
+       azx_init_cmd_io(chip);
        return -1;
 }
 
@@ -667,12 +691,34 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus)
  *       I left the codes, however, for debugging/testing purposes.
  */
 
+/* receive a response */
+static int azx_single_wait_for_response(struct azx *chip)
+{
+       int timeout = 50;
+
+       while (timeout--) {
+               /* check IRV busy bit */
+               if (azx_readw(chip, IRS) & ICH6_IRS_VALID) {
+                       /* reuse rirb.res as the response return value */
+                       chip->rirb.res = azx_readl(chip, IR);
+                       return 0;
+               }
+               udelay(1);
+       }
+       if (printk_ratelimit())
+               snd_printd(SFX "get_response timeout: IRS=0x%x\n",
+                          azx_readw(chip, IRS));
+       chip->rirb.res = -1;
+       return -EIO;
+}
+
 /* send a command */
 static int azx_single_send_cmd(struct hda_bus *bus, u32 val)
 {
        struct azx *chip = bus->private_data;
        int timeout = 50;
 
+       bus->rirb_error = 0;
        while (timeout--) {
                /* check ICB busy bit */
                if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) {
@@ -682,7 +728,7 @@ static int azx_single_send_cmd(struct hda_bus *bus, u32 val)
                        azx_writel(chip, IC, val);
                        azx_writew(chip, IRS, azx_readw(chip, IRS) |
                                   ICH6_IRS_BUSY);
-                       return 0;
+                       return azx_single_wait_for_response(chip);
                }
                udelay(1);
        }
@@ -696,18 +742,7 @@ static int azx_single_send_cmd(struct hda_bus *bus, u32 val)
 static unsigned int azx_single_get_response(struct hda_bus *bus)
 {
        struct azx *chip = bus->private_data;
-       int timeout = 50;
-
-       while (timeout--) {
-               /* check IRV busy bit */
-               if (azx_readw(chip, IRS) & ICH6_IRS_VALID)
-                       return azx_readl(chip, IR);
-               udelay(1);
-       }
-       if (printk_ratelimit())
-               snd_printd(SFX "get_response timeout: IRS=0x%x\n",
-                          azx_readw(chip, IRS));
-       return (unsigned int)-1;
+       return chip->rirb.res;
 }
 
 /*
@@ -775,17 +810,17 @@ static int azx_reset(struct azx *chip)
 
        /* check to see if controller is ready */
        if (!azx_readb(chip, GCTL)) {
-               snd_printd("azx_reset: controller not ready!\n");
+               snd_printd(SFX "azx_reset: controller not ready!\n");
                return -EBUSY;
        }
 
        /* Accept unsolicited responses */
-       azx_writel(chip, GCTL, azx_readl(chip, GCTL) | ICH6_GCTL_UREN);
+       azx_writel(chip, GCTL, azx_readl(chip, GCTL) | ICH6_GCTL_UNSOL);
 
        /* detect codecs */
        if (!chip->codec_mask) {
                chip->codec_mask = azx_readw(chip, STATESTS);
-               snd_printdd("codec_mask = 0x%x\n", chip->codec_mask);
+               snd_printdd(SFX "codec_mask = 0x%x\n", chip->codec_mask);
        }
 
        return 0;
@@ -895,8 +930,7 @@ static void azx_init_chip(struct azx *chip)
        azx_int_enable(chip);
 
        /* initialize the codec command I/O */
-       if (!chip->single_cmd)
-               azx_init_cmd_io(chip);
+       azx_init_cmd_io(chip);
 
        /* program the position buffer */
        azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);
@@ -953,12 +987,12 @@ static void azx_init_pci(struct azx *chip)
        case AZX_DRIVER_SCH:
                pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop);
                if (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) {
-                       pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, \
+                       pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC,
                                snoop & (~INTEL_SCH_HDA_DEVC_NOSNOOP));
                        pci_read_config_word(chip->pci,
                                INTEL_SCH_HDA_DEVC, &snoop);
-                       snd_printdd("HDA snoop disabled, enabling ... %s\n",\
-                               (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) \
+                       snd_printdd(SFX "HDA snoop disabled, enabling ... %s\n",
+                               (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP)
                                ? "Failed" : "OK");
                }
                break;
@@ -1012,7 +1046,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
        /* clear rirb int */
        status = azx_readb(chip, RIRBSTS);
        if (status & RIRB_INT_MASK) {
-               if (!chip->single_cmd && (status & RIRB_INT_RESPONSE))
+               if (status & RIRB_INT_RESPONSE)
                        azx_update_rirb(chip);
                azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
        }
@@ -1098,7 +1132,7 @@ static int azx_setup_periods(struct azx *chip,
                                pos_align;
                pos_adj = frames_to_bytes(runtime, pos_adj);
                if (pos_adj >= period_bytes) {
-                       snd_printk(KERN_WARNING "Too big adjustment %d\n",
+                       snd_printk(KERN_WARNING SFX "Too big adjustment %d\n",
                                   bdl_pos_adj[chip->dev_index]);
                        pos_adj = 0;
                } else {
@@ -1122,7 +1156,7 @@ static int azx_setup_periods(struct azx *chip,
        return 0;
 
  error:
-       snd_printk(KERN_ERR "Too many BDL entries: buffer=%d, period=%d\n",
+       snd_printk(KERN_ERR SFX "Too many BDL entries: buffer=%d, period=%d\n",
                   azx_dev->bufsize, period_bytes);
        return -EINVAL;
 }
@@ -1215,7 +1249,7 @@ static int probe_codec(struct azx *chip, int addr)
        chip->probing = 0;
        if (res == -1)
                return -EIO;
-       snd_printdd("hda_intel: codec #%d probed OK\n", addr);
+       snd_printdd(SFX "codec #%d probed OK\n", addr);
        return 0;
 }
 
@@ -1223,6 +1257,26 @@ static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
                                 struct hda_pcm *cpcm);
 static void azx_stop_chip(struct azx *chip);
 
+static void azx_bus_reset(struct hda_bus *bus)
+{
+       struct azx *chip = bus->private_data;
+
+       bus->in_reset = 1;
+       azx_stop_chip(chip);
+       azx_init_chip(chip);
+#ifdef CONFIG_PM
+       if (chip->initialized) {
+               int i;
+
+               for (i = 0; i < AZX_MAX_PCMS; i++)
+                       snd_pcm_suspend_all(chip->pcm[i]);
+               snd_hda_suspend(chip->bus);
+               snd_hda_resume(chip->bus);
+       }
+#endif
+       bus->in_reset = 0;
+}
+
 /*
  * Codec initialization
  */
@@ -1246,6 +1300,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model,
        bus_temp.ops.command = azx_send_cmd;
        bus_temp.ops.get_response = azx_get_response;
        bus_temp.ops.attach_pcm = azx_attach_pcm_stream;
+       bus_temp.ops.bus_reset = azx_bus_reset;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        bus_temp.power_save = &power_save;
        bus_temp.ops.pm_notify = azx_power_notify;
@@ -1270,8 +1325,8 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model,
                                /* Some BIOSen give you wrong codec addresses
                                 * that don't exist
                                 */
-                               snd_printk(KERN_WARNING
-                                          "hda_intel: Codec #%d probe error; "
+                               snd_printk(KERN_WARNING SFX
+                                          "Codec #%d probe error; "
                                           "disabling it...\n", c);
                                chip->codec_mask &= ~(1 << c);
                                /* More badly, accessing to a non-existing
@@ -1487,7 +1542,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
        bufsize = snd_pcm_lib_buffer_bytes(substream);
        period_bytes = snd_pcm_lib_period_bytes(substream);
 
-       snd_printdd("azx_pcm_prepare: bufsize=0x%x, format=0x%x\n",
+       snd_printdd(SFX "azx_pcm_prepare: bufsize=0x%x, format=0x%x\n",
                    bufsize, format_val);
 
        if (bufsize != azx_dev->bufsize ||
@@ -1830,7 +1885,7 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
                          &pcm);
        if (err < 0)
                return err;
-       strcpy(pcm->name, cpcm->name);
+       strlcpy(pcm->name, cpcm->name, sizeof(pcm->name));
        apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
        if (apcm == NULL)
                return -ENOMEM;
@@ -1973,7 +2028,7 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state)
        for (i = 0; i < AZX_MAX_PCMS; i++)
                snd_pcm_suspend_all(chip->pcm[i]);
        if (chip->initialized)
-               snd_hda_suspend(chip->bus, state);
+               snd_hda_suspend(chip->bus);
        azx_stop_chip(chip);
        if (chip->irq >= 0) {
                free_irq(chip->irq, chip);
@@ -2265,14 +2320,14 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        synchronize_irq(chip->irq);
 
        gcap = azx_readw(chip, GCAP);
-       snd_printdd("chipset global capabilities = 0x%x\n", gcap);
+       snd_printdd(SFX "chipset global capabilities = 0x%x\n", gcap);
 
        /* ATI chips seems buggy about 64bit DMA addresses */
        if (chip->driver_type == AZX_DRIVER_ATI)
-               gcap &= ~0x01;
+               gcap &= ~ICH6_GCAP_64OK;
 
        /* allow 64bit DMA address if supported by H/W */
-       if ((gcap & 0x01) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
+       if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
                pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64));
        else {
                pci_set_dma_mask(pci, DMA_BIT_MASK(32));
@@ -2309,7 +2364,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev),
                                GFP_KERNEL);
        if (!chip->azx_dev) {
-               snd_printk(KERN_ERR "cannot malloc azx_dev\n");
+               snd_printk(KERN_ERR SFX "cannot malloc azx_dev\n");
                goto errout;
        }
 
@@ -2332,11 +2387,9 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
                goto errout;
        }
        /* allocate CORB/RIRB */
-       if (!chip->single_cmd) {
-               err = azx_alloc_cmd_io(chip);
-               if (err < 0)
-                       goto errout;
-       }
+       err = azx_alloc_cmd_io(chip);
+       if (err < 0)
+               goto errout;
 
        /* initialize streams */
        azx_init_stream(chip);
@@ -2359,9 +2412,11 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        }
 
        strcpy(card->driver, "HDA-Intel");
-       strcpy(card->shortname, driver_short_names[chip->driver_type]);
-       sprintf(card->longname, "%s at 0x%lx irq %i",
-               card->shortname, chip->addr, chip->irq);
+       strlcpy(card->shortname, driver_short_names[chip->driver_type],
+               sizeof(card->shortname));
+       snprintf(card->longname, sizeof(card->longname),
+                "%s at 0x%lx irq %i",
+                card->shortname, chip->addr, chip->irq);
 
        *rchip = chip;
        return 0;
@@ -2514,6 +2569,20 @@ static struct pci_device_id azx_ids[] = {
        { PCI_DEVICE(0x10de, 0x0d97), .driver_data = AZX_DRIVER_NVIDIA },
        /* Teradici */
        { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA },
+       /* Creative X-Fi (CA0110-IBG) */
+#if !defined(CONFIG_SND_CTXFI) && !defined(CONFIG_SND_CTXFI_MODULE)
+       /* the following entry conflicts with snd-ctxfi driver,
+        * as ctxfi driver mutates from HD-audio to native mode with
+        * a special command sequence.
+        */
+       { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_ANY_ID),
+         .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
+         .class_mask = 0xffffff,
+         .driver_data = AZX_DRIVER_GENERIC },
+#else
+       /* this entry seems still valid -- i.e. without emu20kx chip */
+       { PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_GENERIC },
+#endif
        /* AMD Generic, PCI class code and Vendor ID for HD Audio */
        { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID),
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
index 93d7499350c6609f3e4a5a9af6396bf0ac6c8447..418c5d1badaa56a8ea8c1d64b79bb986c6b2ff10 100644 (file)
@@ -466,8 +466,12 @@ static void print_codec_info(struct snd_info_entry *entry,
        hda_nid_t nid;
        int i, nodes;
 
-       snd_iprintf(buffer, "Codec: %s\n",
-                   codec->name ? codec->name : "Not Set");
+       snd_iprintf(buffer, "Codec: ");
+       if (codec->vendor_name && codec->chip_name)
+               snd_iprintf(buffer, "%s %s\n",
+                           codec->vendor_name, codec->chip_name);
+       else
+               snd_iprintf(buffer, "Not Set\n");
        snd_iprintf(buffer, "Address: %d\n", codec->addr);
        snd_iprintf(buffer, "Function Id: 0x%x\n", codec->function_id);
        snd_iprintf(buffer, "Vendor Id: 0x%08x\n", codec->vendor_id);
diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c
new file mode 100644 (file)
index 0000000..392d108
--- /dev/null
@@ -0,0 +1,573 @@
+/*
+ * HD audio interface patch for Creative X-Fi CA0110-IBG chip
+ *
+ * Copyright (c) 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
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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 program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+/*
+ */
+
+struct ca0110_spec {
+       struct auto_pin_cfg autocfg;
+       struct hda_multi_out multiout;
+       hda_nid_t out_pins[AUTO_CFG_MAX_OUTS];
+       hda_nid_t dacs[AUTO_CFG_MAX_OUTS];
+       hda_nid_t hp_dac;
+       hda_nid_t input_pins[AUTO_PIN_LAST];
+       hda_nid_t adcs[AUTO_PIN_LAST];
+       hda_nid_t dig_out;
+       hda_nid_t dig_in;
+       unsigned int num_inputs;
+       const char *input_labels[AUTO_PIN_LAST];
+       struct hda_pcm pcm_rec[2];      /* PCM information */
+};
+
+/*
+ * PCM callbacks
+ */
+static int ca0110_playback_pcm_open(struct hda_pcm_stream *hinfo,
+                                   struct hda_codec *codec,
+                                   struct snd_pcm_substream *substream)
+{
+       struct ca0110_spec *spec = codec->spec;
+       return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+                                            hinfo);
+}
+
+static int ca0110_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 ca0110_spec *spec = codec->spec;
+       return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
+                                               stream_tag, format, substream);
+}
+
+static int ca0110_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                      struct hda_codec *codec,
+                                      struct snd_pcm_substream *substream)
+{
+       struct ca0110_spec *spec = codec->spec;
+       return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
+}
+
+/*
+ * Digital out
+ */
+static int ca0110_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+                                       struct hda_codec *codec,
+                                       struct snd_pcm_substream *substream)
+{
+       struct ca0110_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int ca0110_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+                                        struct hda_codec *codec,
+                                        struct snd_pcm_substream *substream)
+{
+       struct ca0110_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+static int ca0110_dig_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 ca0110_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
+                                            format, substream);
+}
+
+/*
+ * Analog capture
+ */
+static int ca0110_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+                                     struct hda_codec *codec,
+                                     unsigned int stream_tag,
+                                     unsigned int format,
+                                     struct snd_pcm_substream *substream)
+{
+       struct ca0110_spec *spec = codec->spec;
+
+       snd_hda_codec_setup_stream(codec, spec->adcs[substream->number],
+                                  stream_tag, 0, format);
+       return 0;
+}
+
+static int ca0110_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                     struct hda_codec *codec,
+                                     struct snd_pcm_substream *substream)
+{
+       struct ca0110_spec *spec = codec->spec;
+
+       snd_hda_codec_cleanup_stream(codec, spec->adcs[substream->number]);
+       return 0;
+}
+
+/*
+ */
+
+static char *dirstr[2] = { "Playback", "Capture" };
+
+static int _add_switch(struct hda_codec *codec, hda_nid_t nid, const char *pfx,
+                      int chan, int dir)
+{
+       char namestr[44];
+       int type = dir ? HDA_INPUT : HDA_OUTPUT;
+       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));
+}
+
+static int _add_volume(struct hda_codec *codec, hda_nid_t nid, const char *pfx,
+                      int chan, int dir)
+{
+       char namestr[44];
+       int type = dir ? HDA_INPUT : HDA_OUTPUT;
+       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));
+}
+
+#define add_out_switch(codec, nid, pfx)        _add_switch(codec, nid, pfx, 3, 0)
+#define add_out_volume(codec, nid, pfx)        _add_volume(codec, nid, pfx, 3, 0)
+#define add_in_switch(codec, nid, pfx) _add_switch(codec, nid, pfx, 3, 1)
+#define add_in_volume(codec, nid, pfx) _add_volume(codec, nid, pfx, 3, 1)
+#define add_mono_switch(codec, nid, pfx, chan) \
+       _add_switch(codec, nid, pfx, chan, 0)
+#define add_mono_volume(codec, nid, pfx, chan) \
+       _add_volume(codec, nid, pfx, chan, 0)
+
+static int ca0110_build_controls(struct hda_codec *codec)
+{
+       struct ca0110_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       static char *prefix[AUTO_CFG_MAX_OUTS] = {
+               "Front", "Surround", NULL, "Side", "Multi"
+       };
+       hda_nid_t mutenid;
+       int i, err;
+
+       for (i = 0; i < spec->multiout.num_dacs; i++) {
+               if (get_wcaps(codec, spec->out_pins[i]) & AC_WCAP_OUT_AMP)
+                       mutenid = spec->out_pins[i];
+               else
+                       mutenid = spec->multiout.dac_nids[i];
+               if (!prefix[i]) {
+                       err = add_mono_switch(codec, mutenid,
+                                             "Center", 1);
+                       if (err < 0)
+                               return err;
+                       err = add_mono_switch(codec, mutenid,
+                                             "LFE", 1);
+                       if (err < 0)
+                               return err;
+                       err = add_mono_volume(codec, spec->multiout.dac_nids[i],
+                                             "Center", 1);
+                       if (err < 0)
+                               return err;
+                       err = add_mono_volume(codec, spec->multiout.dac_nids[i],
+                                             "LFE", 1);
+                       if (err < 0)
+                               return err;
+               } else {
+                       err = add_out_switch(codec, mutenid,
+                                            prefix[i]);
+                       if (err < 0)
+                               return err;
+                       err = add_out_volume(codec, spec->multiout.dac_nids[i],
+                                        prefix[i]);
+                       if (err < 0)
+                               return err;
+               }
+       }
+       if (cfg->hp_outs) {
+               if (get_wcaps(codec, cfg->hp_pins[0]) & AC_WCAP_OUT_AMP)
+                       mutenid = cfg->hp_pins[0];
+               else
+                       mutenid = spec->multiout.dac_nids[i];
+
+               err = add_out_switch(codec, mutenid, "Headphone");
+               if (err < 0)
+                       return err;
+               if (spec->hp_dac) {
+                       err = add_out_volume(codec, spec->hp_dac, "Headphone");
+                       if (err < 0)
+                               return err;
+               }
+       }
+       for (i = 0; i < spec->num_inputs; i++) {
+               const char *label = spec->input_labels[i];
+               if (get_wcaps(codec, spec->input_pins[i]) & AC_WCAP_IN_AMP)
+                       mutenid = spec->input_pins[i];
+               else
+                       mutenid = spec->adcs[i];
+               err = add_in_switch(codec, mutenid, label);
+               if (err < 0)
+                       return err;
+               err = add_in_volume(codec, spec->adcs[i], label);
+               if (err < 0)
+                       return err;
+       }
+
+       if (spec->dig_out) {
+               err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out);
+               if (err < 0)
+                       return err;
+               err = snd_hda_create_spdif_share_sw(codec, &spec->multiout);
+               if (err < 0)
+                       return err;
+               spec->multiout.share_spdif = 1;
+       }
+       if (spec->dig_in) {
+               err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in);
+               if (err < 0)
+                       return err;
+               err = add_in_volume(codec, spec->dig_in, "IEC958");
+       }
+       return 0;
+}
+
+/*
+ */
+static struct hda_pcm_stream ca0110_pcm_analog_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 8,
+       .ops = {
+               .open = ca0110_playback_pcm_open,
+               .prepare = ca0110_playback_pcm_prepare,
+               .cleanup = ca0110_playback_pcm_cleanup
+       },
+};
+
+static struct hda_pcm_stream ca0110_pcm_analog_capture = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       .ops = {
+               .prepare = ca0110_capture_pcm_prepare,
+               .cleanup = ca0110_capture_pcm_cleanup
+       },
+};
+
+static struct hda_pcm_stream ca0110_pcm_digital_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       .ops = {
+               .open = ca0110_dig_playback_pcm_open,
+               .close = ca0110_dig_playback_pcm_close,
+               .prepare = ca0110_dig_playback_pcm_prepare
+       },
+};
+
+static struct hda_pcm_stream ca0110_pcm_digital_capture = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+};
+
+static int ca0110_build_pcms(struct hda_codec *codec)
+{
+       struct ca0110_spec *spec = codec->spec;
+       struct hda_pcm *info = spec->pcm_rec;
+
+       codec->pcm_info = info;
+       codec->num_pcms = 0;
+
+       info->name = "CA0110 Analog";
+       info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ca0110_pcm_analog_playback;
+       info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dacs[0];
+       info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
+               spec->multiout.max_channels;
+       info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0110_pcm_analog_capture;
+       info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_inputs;
+       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0];
+       codec->num_pcms++;
+
+       if (!spec->dig_out && !spec->dig_in)
+               return 0;
+
+       info++;
+       info->name = "CA0110 Digital";
+       info->pcm_type = HDA_PCM_TYPE_SPDIF;
+       if (spec->dig_out) {
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+                       ca0110_pcm_digital_playback;
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dig_out;
+       }
+       if (spec->dig_in) {
+               info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+                       ca0110_pcm_digital_capture;
+               info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in;
+       }
+       codec->num_pcms++;
+
+       return 0;
+}
+
+static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
+{
+       if (pin) {
+               snd_hda_codec_write(codec, pin, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
+               if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
+                       snd_hda_codec_write(codec, pin, 0,
+                                           AC_VERB_SET_AMP_GAIN_MUTE,
+                                           AMP_OUT_UNMUTE);
+       }
+       if (dac)
+               snd_hda_codec_write(codec, dac, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO);
+}
+
+static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc)
+{
+       if (pin) {
+               snd_hda_codec_write(codec, pin, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80);
+               if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP)
+                       snd_hda_codec_write(codec, pin, 0,
+                                           AC_VERB_SET_AMP_GAIN_MUTE,
+                                           AMP_IN_UNMUTE(0));
+       }
+       if (adc)
+               snd_hda_codec_write(codec, adc, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+                                   AMP_IN_UNMUTE(0));
+}
+
+static int ca0110_init(struct hda_codec *codec)
+{
+       struct ca0110_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i;
+
+       for (i = 0; i < spec->multiout.num_dacs; i++)
+               init_output(codec, spec->out_pins[i],
+                           spec->multiout.dac_nids[i]);
+       init_output(codec, cfg->hp_pins[0], spec->hp_dac);
+       init_output(codec, cfg->dig_out_pins[0], spec->dig_out);
+
+       for (i = 0; i < spec->num_inputs; i++)
+               init_input(codec, spec->input_pins[i], spec->adcs[i]);
+       init_input(codec, cfg->dig_in_pin, spec->dig_in);
+       return 0;
+}
+
+static void ca0110_free(struct hda_codec *codec)
+{
+       kfree(codec->spec);
+}
+
+static struct hda_codec_ops ca0110_patch_ops = {
+       .build_controls = ca0110_build_controls,
+       .build_pcms = ca0110_build_pcms,
+       .init = ca0110_init,
+       .free = ca0110_free,
+};
+
+
+static void parse_line_outs(struct hda_codec *codec)
+{
+       struct ca0110_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i, n;
+       unsigned int def_conf;
+       hda_nid_t nid;
+
+       n = 0;
+       for (i = 0; i < cfg->line_outs; i++) {
+               nid = cfg->line_out_pins[i];
+               def_conf = snd_hda_codec_get_pincfg(codec, nid);
+               if (!def_conf)
+                       continue; /* invalid pin */
+               if (snd_hda_get_connections(codec, nid, &spec->dacs[i], 1) != 1)
+                       continue;
+               spec->out_pins[n++] = nid;
+       }
+       spec->multiout.dac_nids = spec->dacs;
+       spec->multiout.num_dacs = n;
+       spec->multiout.max_channels = n * 2;
+}
+
+static void parse_hp_out(struct hda_codec *codec)
+{
+       struct ca0110_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i;
+       unsigned int def_conf;
+       hda_nid_t nid, dac;
+
+       if (!cfg->hp_outs)
+               return;
+       nid = cfg->hp_pins[0];
+       def_conf = snd_hda_codec_get_pincfg(codec, nid);
+       if (!def_conf) {
+               cfg->hp_outs = 0;
+               return;
+       }
+       if (snd_hda_get_connections(codec, nid, &dac, 1) != 1)
+               return;
+
+       for (i = 0; i < cfg->line_outs; i++)
+               if (dac == spec->dacs[i])
+                       break;
+       if (i >= cfg->line_outs) {
+               spec->hp_dac = dac;
+               spec->multiout.hp_nid = dac;
+       }
+}
+
+static void parse_input(struct hda_codec *codec)
+{
+       struct ca0110_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       hda_nid_t nid, pin;
+       int n, i, j;
+
+       n = 0;
+       nid = codec->start_nid;
+       for (i = 0; i < codec->num_nodes; i++, nid++) {
+               unsigned int wcaps = get_wcaps(codec, nid);
+               unsigned int type = (wcaps & AC_WCAP_TYPE) >>
+                       AC_WCAP_TYPE_SHIFT;
+               if (type != AC_WID_AUD_IN)
+                       continue;
+               if (snd_hda_get_connections(codec, nid, &pin, 1) != 1)
+                       continue;
+               if (pin == cfg->dig_in_pin) {
+                       spec->dig_in = nid;
+                       continue;
+               }
+               for (j = 0; j < AUTO_PIN_LAST; j++)
+                       if (cfg->input_pins[j] == pin)
+                               break;
+               if (j >= AUTO_PIN_LAST)
+                       continue;
+               spec->input_pins[n] = pin;
+               spec->input_labels[n] = auto_pin_cfg_labels[j];
+               spec->adcs[n] = nid;
+               n++;
+       }
+       spec->num_inputs = n;
+}
+
+static void parse_digital(struct hda_codec *codec)
+{
+       struct ca0110_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+
+       if (cfg->dig_outs &&
+           snd_hda_get_connections(codec, cfg->dig_out_pins[0],
+                                   &spec->dig_out, 1) == 1)
+               spec->multiout.dig_out_nid = cfg->dig_out_pins[0];
+}
+
+static int ca0110_parse_auto_config(struct hda_codec *codec)
+{
+       struct ca0110_spec *spec = codec->spec;
+       int err;
+
+       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+       if (err < 0)
+               return err;
+
+       parse_line_outs(codec);
+       parse_hp_out(codec);
+       parse_digital(codec);
+       parse_input(codec);
+       return 0;
+}
+
+
+int patch_ca0110(struct hda_codec *codec)
+{
+       struct ca0110_spec *spec;
+       int err;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       codec->spec = spec;
+
+       codec->bus->needs_damn_long_delay = 1;
+
+       err = ca0110_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       codec->patch_ops = ca0110_patch_ops;
+
+       return 0;
+
+ error:
+       kfree(codec->spec);
+       codec->spec = NULL;
+       return err;
+}
+
+
+/*
+ * patch entries
+ */
+static struct hda_codec_preset snd_hda_preset_ca0110[] = {
+       { .id = 0x1102000a, .name = "CA0110-IBG", .patch = patch_ca0110 },
+       { .id = 0x1102000b, .name = "CA0110-IBG", .patch = patch_ca0110 },
+       { .id = 0x1102000d, .name = "SB0880 X-Fi", .patch = patch_ca0110 },
+       {} /* terminator */
+};
+
+MODULE_ALIAS("snd-hda-codec-id:1102000a");
+MODULE_ALIAS("snd-hda-codec-id:1102000b");
+MODULE_ALIAS("snd-hda-codec-id:1102000d");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Creative CA0110-IBG HD-audio codec");
+
+static struct hda_codec_preset_list ca0110_list = {
+       .preset = snd_hda_preset_ca0110,
+       .owner = THIS_MODULE,
+};
+
+static int __init patch_ca0110_init(void)
+{
+       return snd_hda_add_codec_preset(&ca0110_list);
+}
+
+static void __exit patch_ca0110_exit(void)
+{
+       snd_hda_delete_codec_preset(&ca0110_list);
+}
+
+module_init(patch_ca0110_init)
+module_exit(patch_ca0110_exit)
index d57d8132a06ebedfc6855a4c5e12507aac50651a..f5792e2eea82dd412dd18f7aca3b6f328027444b 100644 (file)
@@ -35,9 +35,28 @@ struct nvhdmi_spec {
        struct hda_pcm pcm_rec;
 };
 
+#define Nv_VERB_SET_Channel_Allocation          0xF79
+#define Nv_VERB_SET_Info_Frame_Checksum         0xF7A
+#define Nv_VERB_SET_Audio_Protection_On         0xF98
+#define Nv_VERB_SET_Audio_Protection_Off        0xF99
+
+#define Nv_Master_Convert_nid   0x04
+#define Nv_Master_Pin_nid       0x05
+
+static hda_nid_t nvhdmi_convert_nids[4] = {
+       /*front, rear, clfe, rear_surr */
+       0x6, 0x8, 0xa, 0xc,
+};
+
 static struct hda_verb nvhdmi_basic_init[] = {
+       /* set audio protect on */
+       { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
        /* enable digital output on pin widget */
-       { 0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+       { 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+       { 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+       { 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+       { 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
        {} /* terminator */
 };
 
@@ -66,48 +85,205 @@ static int nvhdmi_init(struct hda_codec *codec)
  * Digital out
  */
 static int nvhdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
-                                    struct hda_codec *codec,
-                                    struct snd_pcm_substream *substream)
+                                       struct hda_codec *codec,
+                                       struct snd_pcm_substream *substream)
 {
        struct nvhdmi_spec *spec = codec->spec;
        return snd_hda_multi_out_dig_open(codec, &spec->multiout);
 }
 
-static int nvhdmi_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
-                                     struct hda_codec *codec,
-                                     struct snd_pcm_substream *substream)
+static int nvhdmi_dig_playback_pcm_close_8ch(struct hda_pcm_stream *hinfo,
+                                       struct hda_codec *codec,
+                                       struct snd_pcm_substream *substream)
 {
        struct nvhdmi_spec *spec = codec->spec;
+       int i;
+
+       snd_hda_codec_write(codec, Nv_Master_Convert_nid,
+                       0, AC_VERB_SET_CHANNEL_STREAMID, 0);
+       for (i = 0; i < 4; i++) {
+               /* set the stream id */
+               snd_hda_codec_write(codec, nvhdmi_convert_nids[i], 0,
+                               AC_VERB_SET_CHANNEL_STREAMID, 0);
+               /* set the stream format */
+               snd_hda_codec_write(codec, nvhdmi_convert_nids[i], 0,
+                               AC_VERB_SET_STREAM_FORMAT, 0);
+       }
+
        return snd_hda_multi_out_dig_close(codec, &spec->multiout);
 }
 
-static int nvhdmi_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
-                                           struct hda_codec *codec,
-                                           unsigned int stream_tag,
-                                           unsigned int format,
-                                           struct snd_pcm_substream *substream)
+static int nvhdmi_dig_playback_pcm_close_2ch(struct hda_pcm_stream *hinfo,
+                                       struct hda_codec *codec,
+                                       struct snd_pcm_substream *substream)
+{
+       struct nvhdmi_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo,
+                                       struct hda_codec *codec,
+                                       unsigned int stream_tag,
+                                       unsigned int format,
+                                       struct snd_pcm_substream *substream)
+{
+       int chs;
+       unsigned int dataDCC1, dataDCC2, chan, chanmask, channel_id;
+       int i;
+
+       mutex_lock(&codec->spdif_mutex);
+
+       chs = substream->runtime->channels;
+       chan = chs ? (chs - 1) : 1;
+
+       switch (chs) {
+       default:
+       case 0:
+       case 2:
+               chanmask = 0x00;
+               break;
+       case 4:
+               chanmask = 0x08;
+               break;
+       case 6:
+               chanmask = 0x0b;
+               break;
+       case 8:
+               chanmask = 0x13;
+               break;
+       }
+       dataDCC1 = AC_DIG1_ENABLE | AC_DIG1_COPYRIGHT;
+       dataDCC2 = 0x2;
+
+       /* set the Audio InforFrame Channel Allocation */
+       snd_hda_codec_write(codec, 0x1, 0,
+                       Nv_VERB_SET_Channel_Allocation, chanmask);
+
+       /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
+       if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
+               snd_hda_codec_write(codec,
+                               Nv_Master_Convert_nid,
+                               0,
+                               AC_VERB_SET_DIGI_CONVERT_1,
+                               codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
+
+       /* set the stream id */
+       snd_hda_codec_write(codec, Nv_Master_Convert_nid, 0,
+                       AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0);
+
+       /* set the stream format */
+       snd_hda_codec_write(codec, Nv_Master_Convert_nid, 0,
+                       AC_VERB_SET_STREAM_FORMAT, format);
+
+       /* turn on again (if needed) */
+       /* enable and set the channel status audio/data flag */
+       if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) {
+               snd_hda_codec_write(codec,
+                               Nv_Master_Convert_nid,
+                               0,
+                               AC_VERB_SET_DIGI_CONVERT_1,
+                               codec->spdif_ctls & 0xff);
+               snd_hda_codec_write(codec,
+                               Nv_Master_Convert_nid,
+                               0,
+                               AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
+       }
+
+       for (i = 0; i < 4; i++) {
+               if (chs == 2)
+                       channel_id = 0;
+               else
+                       channel_id = i * 2;
+
+               /* turn off SPDIF once;
+                *otherwise the IEC958 bits won't be updated
+                */
+               if (codec->spdif_status_reset &&
+               (codec->spdif_ctls & AC_DIG1_ENABLE))
+                       snd_hda_codec_write(codec,
+                               nvhdmi_convert_nids[i],
+                               0,
+                               AC_VERB_SET_DIGI_CONVERT_1,
+                               codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
+               /* set the stream id */
+               snd_hda_codec_write(codec,
+                               nvhdmi_convert_nids[i],
+                               0,
+                               AC_VERB_SET_CHANNEL_STREAMID,
+                               (stream_tag << 4) | channel_id);
+               /* set the stream format */
+               snd_hda_codec_write(codec,
+                               nvhdmi_convert_nids[i],
+                               0,
+                               AC_VERB_SET_STREAM_FORMAT,
+                               format);
+               /* turn on again (if needed) */
+               /* enable and set the channel status audio/data flag */
+               if (codec->spdif_status_reset &&
+               (codec->spdif_ctls & AC_DIG1_ENABLE)) {
+                       snd_hda_codec_write(codec,
+                                       nvhdmi_convert_nids[i],
+                                       0,
+                                       AC_VERB_SET_DIGI_CONVERT_1,
+                                       codec->spdif_ctls & 0xff);
+                       snd_hda_codec_write(codec,
+                                       nvhdmi_convert_nids[i],
+                                       0,
+                                       AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
+               }
+       }
+
+       /* set the Audio Info Frame Checksum */
+       snd_hda_codec_write(codec, 0x1, 0,
+                       Nv_VERB_SET_Info_Frame_Checksum,
+                       (0x71 - chan - chanmask));
+
+       mutex_unlock(&codec->spdif_mutex);
+       return 0;
+}
+
+static int nvhdmi_dig_playback_pcm_prepare_2ch(struct hda_pcm_stream *hinfo,
+                                       struct hda_codec *codec,
+                                       unsigned int stream_tag,
+                                       unsigned int format,
+                                       struct snd_pcm_substream *substream)
 {
        struct nvhdmi_spec *spec = codec->spec;
        return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
-                                            format, substream);
+                                       format, substream);
 }
 
-static struct hda_pcm_stream nvhdmi_pcm_digital_playback = {
+static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 8,
+       .nid = Nv_Master_Convert_nid,
+       .rates = SNDRV_PCM_RATE_48000,
+       .maxbps = 16,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       .ops = {
+               .open = nvhdmi_dig_playback_pcm_open,
+               .close = nvhdmi_dig_playback_pcm_close_8ch,
+               .prepare = nvhdmi_dig_playback_pcm_prepare_8ch
+       },
+};
+
+static struct hda_pcm_stream nvhdmi_pcm_digital_playback_2ch = {
        .substreams = 1,
        .channels_min = 2,
        .channels_max = 2,
-       .nid = 0x4, /* NID to query formats and rates and setup streams */
+       .nid = Nv_Master_Convert_nid,
        .rates = SNDRV_PCM_RATE_48000,
        .maxbps = 16,
        .formats = SNDRV_PCM_FMTBIT_S16_LE,
        .ops = {
                .open = nvhdmi_dig_playback_pcm_open,
-               .close = nvhdmi_dig_playback_pcm_close,
-               .prepare = nvhdmi_dig_playback_pcm_prepare
+               .close = nvhdmi_dig_playback_pcm_close_2ch,
+               .prepare = nvhdmi_dig_playback_pcm_prepare_2ch
        },
 };
 
-static int nvhdmi_build_pcms(struct hda_codec *codec)
+static int nvhdmi_build_pcms_8ch(struct hda_codec *codec)
 {
        struct nvhdmi_spec *spec = codec->spec;
        struct hda_pcm *info = &spec->pcm_rec;
@@ -117,7 +293,24 @@ static int nvhdmi_build_pcms(struct hda_codec *codec)
 
        info->name = "NVIDIA HDMI";
        info->pcm_type = HDA_PCM_TYPE_HDMI;
-       info->stream[SNDRV_PCM_STREAM_PLAYBACK] = nvhdmi_pcm_digital_playback;
+       info->stream[SNDRV_PCM_STREAM_PLAYBACK]
+                                       = nvhdmi_pcm_digital_playback_8ch;
+
+       return 0;
+}
+
+static int nvhdmi_build_pcms_2ch(struct hda_codec *codec)
+{
+       struct nvhdmi_spec *spec = codec->spec;
+       struct hda_pcm *info = &spec->pcm_rec;
+
+       codec->num_pcms = 1;
+       codec->pcm_info = info;
+
+       info->name = "NVIDIA HDMI";
+       info->pcm_type = HDA_PCM_TYPE_HDMI;
+       info->stream[SNDRV_PCM_STREAM_PLAYBACK]
+                                       = nvhdmi_pcm_digital_playback_2ch;
 
        return 0;
 }
@@ -127,14 +320,40 @@ static void nvhdmi_free(struct hda_codec *codec)
        kfree(codec->spec);
 }
 
-static struct hda_codec_ops nvhdmi_patch_ops = {
+static struct hda_codec_ops nvhdmi_patch_ops_8ch = {
+       .build_controls = nvhdmi_build_controls,
+       .build_pcms = nvhdmi_build_pcms_8ch,
+       .init = nvhdmi_init,
+       .free = nvhdmi_free,
+};
+
+static struct hda_codec_ops nvhdmi_patch_ops_2ch = {
        .build_controls = nvhdmi_build_controls,
-       .build_pcms = nvhdmi_build_pcms,
+       .build_pcms = nvhdmi_build_pcms_2ch,
        .init = nvhdmi_init,
        .free = nvhdmi_free,
 };
 
-static int patch_nvhdmi(struct hda_codec *codec)
+static int patch_nvhdmi_8ch(struct hda_codec *codec)
+{
+       struct nvhdmi_spec *spec;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+
+       spec->multiout.num_dacs = 0;  /* no analog */
+       spec->multiout.max_channels = 8;
+       spec->multiout.dig_out_nid = Nv_Master_Convert_nid;
+
+       codec->patch_ops = nvhdmi_patch_ops_8ch;
+
+       return 0;
+}
+
+static int patch_nvhdmi_2ch(struct hda_codec *codec)
 {
        struct nvhdmi_spec *spec;
 
@@ -144,13 +363,11 @@ static int patch_nvhdmi(struct hda_codec *codec)
 
        codec->spec = spec;
 
-       spec->multiout.num_dacs = 0;      /* no analog */
+       spec->multiout.num_dacs = 0;  /* no analog */
        spec->multiout.max_channels = 2;
-       spec->multiout.dig_out_nid = 0x4; /* NID for copying analog to digital,
-                                          * seems to be unused in pure-digital
-                                          * case. */
+       spec->multiout.dig_out_nid = Nv_Master_Convert_nid;
 
-       codec->patch_ops = nvhdmi_patch_ops;
+       codec->patch_ops = nvhdmi_patch_ops_2ch;
 
        return 0;
 }
@@ -159,11 +376,11 @@ static int patch_nvhdmi(struct hda_codec *codec)
  * patch entries
  */
 static struct hda_codec_preset snd_hda_preset_nvhdmi[] = {
-       { .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi },
-       { .id = 0x10de0006, .name = "MCP78 HDMI", .patch = patch_nvhdmi },
-       { .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi },
-       { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi },
-       { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi },
+       { .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch },
+       { .id = 0x10de0006, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch },
+       { .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi_8ch },
+       { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch },
+       { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch },
        {} /* terminator */
 };
 
index 0fd258eba3a57e917c07cc88fc18096e0b6bc1e0..337d2a59c67e5da26127d35b82cc5ce9460d6cfc 100644 (file)
@@ -190,6 +190,7 @@ enum {
        ALC663_ASUS_MODE6,
        ALC272_DELL,
        ALC272_DELL_ZM1,
+       ALC272_SAMSUNG_NC10,
        ALC662_AUTO,
        ALC662_MODEL_LAST,
 };
@@ -205,6 +206,7 @@ enum {
        ALC882_ASUS_A7M,
        ALC885_MACPRO,
        ALC885_MBP3,
+       ALC885_MB5,
        ALC885_IMAC24,
        ALC882_AUTO,
        ALC882_MODEL_LAST,
@@ -218,9 +220,11 @@ enum {
        ALC883_6ST_DIG,
        ALC883_TARGA_DIG,
        ALC883_TARGA_2ch_DIG,
+       ALC883_TARGA_8ch_DIG,
        ALC883_ACER,
        ALC883_ACER_ASPIRE,
        ALC888_ACER_ASPIRE_4930G,
+       ALC888_ACER_ASPIRE_8930G,
        ALC883_MEDION,
        ALC883_MEDION_MD2,
        ALC883_LAPTOP_EAPD,
@@ -238,7 +242,9 @@ enum {
        ALC883_3ST_6ch_INTEL,
        ALC888_ASUS_M90V,
        ALC888_ASUS_EEE1601,
+       ALC889A_MB31,
        ALC1200_ASUS_P5Q,
+       ALC883_SONY_VAIO_TT,
        ALC883_AUTO,
        ALC883_MODEL_LAST,
 };
@@ -253,6 +259,15 @@ enum {
 /* for GPIO Poll */
 #define GPIO_MASK      0x03
 
+/* extra amp-initialization sequence types */
+enum {
+       ALC_INIT_NONE,
+       ALC_INIT_DEFAULT,
+       ALC_INIT_GPIO1,
+       ALC_INIT_GPIO2,
+       ALC_INIT_GPIO3,
+};
+
 struct alc_spec {
        /* codec parameterization */
        struct snd_kcontrol_new *mixers[5];     /* mixer arrays */
@@ -266,13 +281,13 @@ struct alc_spec {
                                                 */
        unsigned int num_init_verbs;
 
-       char *stream_name_analog;       /* analog PCM stream */
+       char stream_name_analog[16];    /* analog PCM stream */
        struct hda_pcm_stream *stream_analog_playback;
        struct hda_pcm_stream *stream_analog_capture;
        struct hda_pcm_stream *stream_analog_alt_playback;
        struct hda_pcm_stream *stream_analog_alt_capture;
 
-       char *stream_name_digital;      /* digital PCM stream */
+       char stream_name_digital[16];   /* digital PCM stream */
        struct hda_pcm_stream *stream_digital_playback;
        struct hda_pcm_stream *stream_digital_capture;
 
@@ -301,6 +316,8 @@ struct alc_spec {
        const struct hda_channel_mode *channel_mode;
        int num_channel_mode;
        int need_dac_fix;
+       int const_channel_count;
+       int ext_channel_count;
 
        /* PCM information */
        struct hda_pcm pcm_rec[3];      /* used in alc_build_pcms() */
@@ -322,6 +339,7 @@ struct alc_spec {
 
        /* other flags */
        unsigned int no_analog :1; /* digital I/O only */
+       int init_amp;
 
        /* for virtual master */
        hda_nid_t vmaster_nid;
@@ -355,6 +373,7 @@ struct alc_config_preset {
        unsigned int num_channel_mode;
        const struct hda_channel_mode *channel_mode;
        int need_dac_fix;
+       int const_channel_count;
        unsigned int num_mux_defs;
        const struct hda_input_mux *input_mux;
        void (*unsol_event)(struct hda_codec *, unsigned int);
@@ -449,7 +468,7 @@ static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
        struct alc_spec *spec = codec->spec;
        return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
                                   spec->num_channel_mode,
-                                  spec->multiout.max_channels);
+                                  spec->ext_channel_count);
 }
 
 static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
@@ -459,9 +478,12 @@ static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
        struct alc_spec *spec = codec->spec;
        int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
                                      spec->num_channel_mode,
-                                     &spec->multiout.max_channels);
-       if (err >= 0 && spec->need_dac_fix)
-               spec->multiout.num_dacs = spec->multiout.max_channels / 2;
+                                     &spec->ext_channel_count);
+       if (err >= 0 && !spec->const_channel_count) {
+               spec->multiout.max_channels = spec->ext_channel_count;
+               if (spec->need_dac_fix)
+                       spec->multiout.num_dacs = spec->multiout.max_channels / 2;
+       }
        return err;
 }
 
@@ -841,8 +863,13 @@ static void setup_preset(struct alc_spec *spec,
        spec->channel_mode = preset->channel_mode;
        spec->num_channel_mode = preset->num_channel_mode;
        spec->need_dac_fix = preset->need_dac_fix;
+       spec->const_channel_count = preset->const_channel_count;
 
-       spec->multiout.max_channels = spec->channel_mode[0].channels;
+       if (preset->const_channel_count)
+               spec->multiout.max_channels = preset->const_channel_count;
+       else
+               spec->multiout.max_channels = spec->channel_mode[0].channels;
+       spec->ext_channel_count = spec->channel_mode[0].channels;
 
        spec->multiout.num_dacs = preset->num_dacs;
        spec->multiout.dac_nids = preset->dac_nids;
@@ -921,20 +948,26 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
        alc_fix_pll(codec);
 }
 
-static void alc_sku_automute(struct hda_codec *codec)
+static void alc_automute_pin(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
        unsigned int present;
-       unsigned int hp_nid = spec->autocfg.hp_pins[0];
-       unsigned int sp_nid = spec->autocfg.speaker_pins[0];
+       unsigned int nid = spec->autocfg.hp_pins[0];
+       int i;
 
        /* 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,
+       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 & 0x80000000) != 0;
-       snd_hda_codec_write(codec, sp_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                           spec->jack_present ? 0 : PIN_OUT);
+       spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
+       for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
+               nid = spec->autocfg.speaker_pins[i];
+               if (!nid)
+                       break;
+               snd_hda_codec_write(codec, nid, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                   spec->jack_present ? 0 : PIN_OUT);
+       }
 }
 
 #if 0 /* it's broken in some acses -- temporarily disabled */
@@ -969,16 +1002,19 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
                res >>= 28;
        else
                res >>= 26;
-       if (res == ALC880_HP_EVENT)
-               alc_sku_automute(codec);
-
-       if (res == ALC880_MIC_EVENT)
+       switch (res) {
+       case ALC880_HP_EVENT:
+               alc_automute_pin(codec);
+               break;
+       case ALC880_MIC_EVENT:
                alc_mic_automute(codec);
+               break;
+       }
 }
 
 static void alc_inithook(struct hda_codec *codec)
 {
-       alc_sku_automute(codec);
+       alc_automute_pin(codec);
        alc_mic_automute(codec);
 }
 
@@ -1000,69 +1036,21 @@ static void alc888_coef_init(struct hda_codec *codec)
                                    AC_VERB_SET_PROC_COEF, 0x3030);
 }
 
-/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
- *     31 ~ 16 :       Manufacture ID
- *     15 ~ 8  :       SKU ID
- *     7  ~ 0  :       Assembly ID
- *     port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
- */
-static void alc_subsystem_id(struct hda_codec *codec,
-                            unsigned int porta, unsigned int porte,
-                            unsigned int portd)
+static void alc_auto_init_amp(struct hda_codec *codec, int type)
 {
-       unsigned int ass, tmp, i;
-       unsigned nid;
-       struct alc_spec *spec = codec->spec;
-
-       ass = codec->subsystem_id & 0xffff;
-       if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
-               goto do_sku;
-
-       /*
-        * 31~30        : port conetcivity
-        * 29~21        : reserve
-        * 20           : PCBEEP input
-        * 19~16        : Check sum (15:1)
-        * 15~1         : Custom
-        * 0            : override
-       */
-       nid = 0x1d;
-       if (codec->vendor_id == 0x10ec0260)
-               nid = 0x17;
-       ass = snd_hda_codec_get_pincfg(codec, nid);
-       if (!(ass & 1) && !(ass & 0x100000))
-               return;
-       if ((ass >> 30) != 1)   /* no physical connection */
-               return;
+       unsigned int tmp;
 
-       /* check sum */
-       tmp = 0;
-       for (i = 1; i < 16; i++) {
-               if ((ass >> i) & 1)
-                       tmp++;
-       }
-       if (((ass >> 16) & 0xf) != tmp)
-               return;
-do_sku:
-       /*
-        * 0 : override
-        * 1 :  Swap Jack
-        * 2 : 0 --> Desktop, 1 --> Laptop
-        * 3~5 : External Amplifier control
-        * 7~6 : Reserved
-       */
-       tmp = (ass & 0x38) >> 3;        /* external Amp control */
-       switch (tmp) {
-       case 1:
+       switch (type) {
+       case ALC_INIT_GPIO1:
                snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
                break;
-       case 3:
+       case ALC_INIT_GPIO2:
                snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
                break;
-       case 7:
+       case ALC_INIT_GPIO3:
                snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
                break;
-       case 5: /* set EAPD output high */
+       case ALC_INIT_DEFAULT:
                switch (codec->vendor_id) {
                case 0x10ec0260:
                        snd_hda_codec_write(codec, 0x0f, 0,
@@ -1116,7 +1104,7 @@ do_sku:
                                            tmp | 0x2010);
                        break;
                case 0x10ec0888:
-                       /*alc888_coef_init(codec);*/ /* called in alc_init() */
+                       alc888_coef_init(codec);
                        break;
                case 0x10ec0267:
                case 0x10ec0268:
@@ -1131,7 +1119,107 @@ do_sku:
                                            tmp | 0x3000);
                        break;
                }
-       default:
+               break;
+       }
+}
+
+static void alc_init_auto_hp(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (!spec->autocfg.hp_pins[0])
+               return;
+
+       if (!spec->autocfg.speaker_pins[0]) {
+               if (spec->autocfg.line_out_pins[0] &&
+                   spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
+                       spec->autocfg.speaker_pins[0] =
+                               spec->autocfg.line_out_pins[0];
+               else
+                       return;
+       }
+
+       snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
+                   spec->autocfg.hp_pins[0]);
+       snd_hda_codec_write_cache(codec, spec->autocfg.hp_pins[0], 0,
+                                 AC_VERB_SET_UNSOLICITED_ENABLE,
+                                 AC_USRSP_EN | ALC880_HP_EVENT);
+       spec->unsol_event = alc_sku_unsol_event;
+}
+
+/* check subsystem ID and set up device-specific initialization;
+ * return 1 if initialized, 0 if invalid SSID
+ */
+/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
+ *     31 ~ 16 :       Manufacture ID
+ *     15 ~ 8  :       SKU ID
+ *     7  ~ 0  :       Assembly ID
+ *     port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
+ */
+static int alc_subsystem_id(struct hda_codec *codec,
+                           hda_nid_t porta, hda_nid_t porte,
+                           hda_nid_t portd)
+{
+       unsigned int ass, tmp, i;
+       unsigned nid;
+       struct alc_spec *spec = codec->spec;
+
+       ass = codec->subsystem_id & 0xffff;
+       if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
+               goto do_sku;
+
+       /* invalid SSID, check the special NID pin defcfg instead */
+       /*
+        * 31~30        : port conetcivity
+        * 29~21        : reserve
+        * 20           : PCBEEP input
+        * 19~16        : Check sum (15:1)
+        * 15~1         : Custom
+        * 0            : override
+       */
+       nid = 0x1d;
+       if (codec->vendor_id == 0x10ec0260)
+               nid = 0x17;
+       ass = snd_hda_codec_get_pincfg(codec, nid);
+       snd_printd("realtek: No valid SSID, "
+                  "checking pincfg 0x%08x for NID 0x%x\n",
+                  ass, nid);
+       if (!(ass & 1) && !(ass & 0x100000))
+               return 0;
+       if ((ass >> 30) != 1)   /* no physical connection */
+               return 0;
+
+       /* check sum */
+       tmp = 0;
+       for (i = 1; i < 16; i++) {
+               if ((ass >> i) & 1)
+                       tmp++;
+       }
+       if (((ass >> 16) & 0xf) != tmp)
+               return 0;
+do_sku:
+       snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
+                  ass & 0xffff, codec->vendor_id);
+       /*
+        * 0 : override
+        * 1 :  Swap Jack
+        * 2 : 0 --> Desktop, 1 --> Laptop
+        * 3~5 : External Amplifier control
+        * 7~6 : Reserved
+       */
+       tmp = (ass & 0x38) >> 3;        /* external Amp control */
+       switch (tmp) {
+       case 1:
+               spec->init_amp = ALC_INIT_GPIO1;
+               break;
+       case 3:
+               spec->init_amp = ALC_INIT_GPIO2;
+               break;
+       case 7:
+               spec->init_amp = ALC_INIT_GPIO3;
+               break;
+       case 5:
+               spec->init_amp = ALC_INIT_DEFAULT;
                break;
        }
 
@@ -1139,7 +1227,7 @@ do_sku:
         * when the external headphone out jack is plugged"
         */
        if (!(ass & 0x8000))
-               return;
+               return 1;
        /*
         * 10~8 : Jack location
         * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
@@ -1147,14 +1235,6 @@ do_sku:
         * 15   : 1 --> enable the function "Mute internal speaker
         *              when the external headphone out jack is plugged"
         */
-       if (!spec->autocfg.speaker_pins[0]) {
-               if (spec->autocfg.line_out_pins[0])
-                       spec->autocfg.speaker_pins[0] =
-                               spec->autocfg.line_out_pins[0];
-               else
-                       return;
-       }
-
        if (!spec->autocfg.hp_pins[0]) {
                tmp = (ass >> 11) & 0x3;        /* HP to chassis */
                if (tmp == 0)
@@ -1164,23 +1244,23 @@ do_sku:
                else if (tmp == 2)
                        spec->autocfg.hp_pins[0] = portd;
                else
-                       return;
+                       return 1;
        }
-       if (spec->autocfg.hp_pins[0])
-               snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0,
-                       AC_VERB_SET_UNSOLICITED_ENABLE,
-                       AC_USRSP_EN | ALC880_HP_EVENT);
 
-#if 0 /* it's broken in some acses -- temporarily disabled */
-       if (spec->autocfg.input_pins[AUTO_PIN_MIC] &&
-               spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC])
-               snd_hda_codec_write(codec,
-                       spec->autocfg.input_pins[AUTO_PIN_MIC], 0,
-                       AC_VERB_SET_UNSOLICITED_ENABLE,
-                       AC_USRSP_EN | ALC880_MIC_EVENT);
-#endif /* disabled */
+       alc_init_auto_hp(codec);
+       return 1;
+}
 
-       spec->unsol_event = alc_sku_unsol_event;
+static void alc_ssid_check(struct hda_codec *codec,
+                          hda_nid_t porta, hda_nid_t porte, hda_nid_t portd)
+{
+       if (!alc_subsystem_id(codec, porta, porte, portd)) {
+               struct alc_spec *spec = codec->spec;
+               snd_printd("realtek: "
+                          "Enable default setup for auto mode as fallback\n");
+               spec->init_amp = ALC_INIT_DEFAULT;
+               alc_init_auto_hp(codec);
+       }
 }
 
 /*
@@ -1315,32 +1395,58 @@ static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
        {}
 };
 
-static void alc888_fujitsu_xa3530_automute(struct hda_codec *codec)
+static void alc_automute_amp(struct hda_codec *codec)
 {
-       unsigned int present;
-       unsigned int bits;
-       /* Line out presence */
-       present = snd_hda_codec_read(codec, 0x17, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-       /* HP out presence */
-       present = present || snd_hda_codec_read(codec, 0x1b, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-       bits = present ? HDA_AMP_MUTE : 0;
+       struct alc_spec *spec = codec->spec;
+       unsigned int val, mute;
+       hda_nid_t nid;
+       int i;
+
+       spec->jack_present = 0;
+       for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
+               nid = spec->autocfg.hp_pins[i];
+               if (!nid)
+                       break;
+               val = snd_hda_codec_read(codec, nid, 0,
+                                        AC_VERB_GET_PIN_SENSE, 0);
+               if (val & AC_PINSENSE_PRESENCE) {
+                       spec->jack_present = 1;
+                       break;
+               }
+       }
+
+       mute = spec->jack_present ? HDA_AMP_MUTE : 0;
        /* Toggle internal speakers muting */
-       snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, bits);
-       /* Toggle internal bass muting */
-       snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, bits);
+       for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
+               nid = spec->autocfg.speaker_pins[i];
+               if (!nid)
+                       break;
+               snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, mute);
+       }
 }
 
-static void alc888_fujitsu_xa3530_unsol_event(struct hda_codec *codec,
-               unsigned int res)
+static void alc_automute_amp_unsol_event(struct hda_codec *codec,
+                                        unsigned int res)
 {
-       if (res >> 26 == ALC880_HP_EVENT)
-               alc888_fujitsu_xa3530_automute(codec);
+       if (codec->vendor_id == 0x10ec0880)
+               res >>= 28;
+       else
+               res >>= 26;
+       if (res == ALC880_HP_EVENT)
+               alc_automute_amp(codec);
 }
 
+static void alc888_fujitsu_xa3530_init_hook(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x17; /* line-out */
+       spec->autocfg.hp_pins[1] = 0x1b; /* hp */
+       spec->autocfg.speaker_pins[0] = 0x14; /* speaker */
+       spec->autocfg.speaker_pins[1] = 0x15; /* bass */
+       alc_automute_amp(codec);
+}
 
 /*
  * ALC888 Acer Aspire 4930G model
@@ -1364,6 +1470,59 @@ static struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
        { }
 };
 
+/*
+ * ALC889 Acer Aspire 8930G model
+ */
+
+static struct hda_verb alc889_acer_aspire_8930g_verbs[] = {
+/* Front Mic: set to PIN_IN (empty by default) */
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+/* Unselect Front Mic by default in input mixer 3 */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
+/* Enable unsolicited event for HP jack */
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+/* Connect Internal Front to Front */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+/* Connect Internal Rear to Rear */
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
+/* Connect Internal CLFE to CLFE */
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
+/* Connect HP out to Front */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+/* Enable all DACs */
+/*  DAC DISABLE/MUTE 1? */
+/*  setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */
+       {0x20, AC_VERB_SET_COEF_INDEX, 0x03},
+       {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
+/*  DAC DISABLE/MUTE 2? */
+/*  some bit here disables the other DACs. Init=0x4900 */
+       {0x20, AC_VERB_SET_COEF_INDEX, 0x08},
+       {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
+/* Enable amplifiers */
+       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
+       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
+/* DMIC fix
+ * This laptop has a stereo digital microphone. The mics are only 1cm apart
+ * which makes the stereo useless. However, either the mic or the ALC889
+ * makes the signal become a difference/sum signal instead of standard
+ * stereo, which is annoying. So instead we flip this bit which makes the
+ * codec replicate the sum signal to both channels, turning it into a
+ * normal mono mic.
+ */
+/*  DMIC_CONTROL? Init value = 0x0001 */
+       {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
+       {0x20, AC_VERB_SET_PROC_COEF, 0x0003},
+       { }
+};
+
 static struct hda_input_mux alc888_2_capture_sources[2] = {
        /* Front mic only available on one ADC */
        {
@@ -1385,6 +1544,38 @@ static struct hda_input_mux alc888_2_capture_sources[2] = {
        }
 };
 
+static struct hda_input_mux alc889_capture_sources[3] = {
+       /* Digital mic only available on first "ADC" */
+       {
+               .num_items = 5,
+               .items = {
+                       { "Mic", 0x0 },
+                       { "Line", 0x2 },
+                       { "CD", 0x4 },
+                       { "Front Mic", 0xb },
+                       { "Input Mix", 0xa },
+               },
+       },
+       {
+               .num_items = 4,
+               .items = {
+                       { "Mic", 0x0 },
+                       { "Line", 0x2 },
+                       { "CD", 0x4 },
+                       { "Input Mix", 0xa },
+               },
+       },
+       {
+               .num_items = 4,
+               .items = {
+                       { "Mic", 0x0 },
+                       { "Line", 0x2 },
+                       { "CD", 0x4 },
+                       { "Input Mix", 0xa },
+               },
+       }
+};
+
 static struct snd_kcontrol_new alc888_base_mixer[] = {
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
@@ -1407,22 +1598,24 @@ static struct snd_kcontrol_new alc888_base_mixer[] = {
        { } /* end */
 };
 
-static void alc888_acer_aspire_4930g_automute(struct hda_codec *codec)
+static void alc888_acer_aspire_4930g_init_hook(struct hda_codec *codec)
 {
-       unsigned int present;
-       unsigned int bits;
-       present = snd_hda_codec_read(codec, 0x15, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-       bits = present ? HDA_AMP_MUTE : 0;
-       snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, bits);
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       alc_automute_amp(codec);
 }
 
-static void alc888_acer_aspire_4930g_unsol_event(struct hda_codec *codec,
-               unsigned int res)
+static void alc889_acer_aspire_8930g_init_hook(struct hda_codec *codec)
 {
-       if (res >> 26 == ALC880_HP_EVENT)
-               alc888_acer_aspire_4930g_automute(codec);
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x16;
+       spec->autocfg.speaker_pins[2] = 0x1b;
+       alc_automute_amp(codec);
 }
 
 /*
@@ -2390,21 +2583,6 @@ static struct hda_verb alc880_beep_init_verbs[] = {
        { }
 };
 
-/* toggle speaker-output according to the hp-jack state */
-static void alc880_uniwill_hp_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;
-       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, 0x16, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, bits);
-}
-
 /* auto-toggle front mic */
 static void alc880_uniwill_mic_automute(struct hda_codec *codec)
 {
@@ -2417,9 +2595,14 @@ static void alc880_uniwill_mic_automute(struct hda_codec *codec)
        snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
 }
 
-static void alc880_uniwill_automute(struct hda_codec *codec)
+static void alc880_uniwill_init_hook(struct hda_codec *codec)
 {
-       alc880_uniwill_hp_automute(codec);
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x16;
+       alc_automute_amp(codec);
        alc880_uniwill_mic_automute(codec);
 }
 
@@ -2430,24 +2613,22 @@ static void alc880_uniwill_unsol_event(struct hda_codec *codec,
         * definition.  4bit tag is placed at 28 bit!
         */
        switch (res >> 28) {
-       case ALC880_HP_EVENT:
-               alc880_uniwill_hp_automute(codec);
-               break;
        case ALC880_MIC_EVENT:
                alc880_uniwill_mic_automute(codec);
                break;
+       default:
+               alc_automute_amp_unsol_event(codec, res);
+               break;
        }
 }
 
-static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec)
+static void alc880_uniwill_p53_init_hook(struct hda_codec *codec)
 {
-       unsigned int present;
-       unsigned char bits;
+       struct alc_spec *spec = codec->spec;
 
-       present = snd_hda_codec_read(codec, 0x14, 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);
+       spec->autocfg.hp_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x15;
+       alc_automute_amp(codec);
 }
 
 static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
@@ -2469,10 +2650,10 @@ static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
        /* Looks like the unsol event is incompatible with the standard
         * definition.  4bit tag is placed at 28 bit!
         */
-       if ((res >> 28) == ALC880_HP_EVENT)
-               alc880_uniwill_p53_hp_automute(codec);
        if ((res >> 28) == ALC880_DCVOL_EVENT)
                alc880_uniwill_p53_dcvol_automute(codec);
+       else
+               alc_automute_amp_unsol_event(codec, res);
 }
 
 /*
@@ -2542,6 +2723,7 @@ static struct hda_verb alc880_pin_asus_init_verbs[] = {
 /* Enable GPIO mask and set output */
 #define alc880_gpio1_init_verbs        alc_gpio1_init_verbs
 #define alc880_gpio2_init_verbs        alc_gpio2_init_verbs
+#define alc880_gpio3_init_verbs        alc_gpio3_init_verbs
 
 /* Clevo m520g init */
 static struct hda_verb alc880_pin_clevo_init_verbs[] = {
@@ -2704,30 +2886,18 @@ static struct hda_verb alc880_lg_init_verbs[] = {
        {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
        {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        /* jack sense */
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
        { }
 };
 
 /* toggle speaker-output according to the hp-jack state */
-static void alc880_lg_automute(struct hda_codec *codec)
+static void alc880_lg_init_hook(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;
-       bits = present ? HDA_AMP_MUTE : 0;
-       snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, bits);
-}
+       struct alc_spec *spec = codec->spec;
 
-static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       /* Looks like the unsol event is incompatible with the standard
-        * definition.  4bit tag is placed at 28 bit!
-        */
-       if ((res >> 28) == 0x01)
-               alc880_lg_automute(codec);
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.speaker_pins[0] = 0x17;
+       alc_automute_amp(codec);
 }
 
 /*
@@ -2801,30 +2971,18 @@ static struct hda_verb alc880_lg_lw_init_verbs[] = {
        {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
        {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        /* jack sense */
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
        { }
 };
 
 /* toggle speaker-output according to the hp-jack state */
-static void alc880_lg_lw_automute(struct hda_codec *codec)
+static void alc880_lg_lw_init_hook(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;
-       bits = present ? HDA_AMP_MUTE : 0;
-       snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, bits);
-}
+       struct alc_spec *spec = codec->spec;
 
-static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       /* Looks like the unsol event is incompatible with the standard
-        * definition.  4bit tag is placed at 28 bit!
-        */
-       if ((res >> 28) == 0x01)
-               alc880_lg_lw_automute(codec);
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       alc_automute_amp(codec);
 }
 
 static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
@@ -2871,16 +3029,10 @@ static struct hda_verb alc880_medion_rim_init_verbs[] = {
 /* toggle speaker-output according to the hp-jack state */
 static void alc880_medion_rim_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)
-               & AC_PINSENSE_PRESENCE;
-       bits = present ? HDA_AMP_MUTE : 0;
-       snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, bits);
-       if (present)
+       struct alc_spec *spec = codec->spec;
+       alc_automute_amp(codec);
+       /* toggle EAPD */
+       if (spec->jack_present)
                snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
        else
                snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
@@ -2896,6 +3048,15 @@ static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
                alc880_medion_rim_automute(codec);
 }
 
+static void alc880_medion_rim_init_hook(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x1b;
+       alc880_medion_rim_automute(codec);
+}
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 static struct hda_amp_list alc880_loopbacks[] = {
        { 0x0b, HDA_INPUT, 0 },
@@ -2924,8 +3085,7 @@ static int alc_init(struct hda_codec *codec)
        unsigned int i;
 
        alc_fix_pll(codec);
-       if (codec->vendor_id == 0x10ec0888)
-               alc888_coef_init(codec);
+       alc_auto_init_amp(codec, spec->init_amp);
 
        for (i = 0; i < spec->num_init_verbs; i++)
                snd_hda_sequence_write(codec, spec->init_verbs[i]);
@@ -3127,7 +3287,10 @@ static int alc_build_pcms(struct hda_codec *codec)
        if (spec->no_analog)
                goto skip_analog;
 
+       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;
@@ -3153,6 +3316,9 @@ static int alc_build_pcms(struct hda_codec *codec)
  skip_analog:
        /* SPDIF for stream index #1 */
        if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
+               snprintf(spec->stream_name_digital,
+                        sizeof(spec->stream_name_digital),
+                        "%s Digital", codec->chip_name);
                codec->num_pcms = 2;
                codec->slave_dig_outs = spec->multiout.slave_dig_outs;
                info = spec->pcm_rec + 1;
@@ -3755,7 +3921,7 @@ static struct alc_config_preset alc880_presets[] = {
                .channel_mode = alc880_2_jack_modes,
                .input_mux = &alc880_f1734_capture_source,
                .unsol_event = alc880_uniwill_p53_unsol_event,
-               .init_hook = alc880_uniwill_p53_hp_automute,
+               .init_hook = alc880_uniwill_p53_init_hook,
        },
        [ALC880_ASUS] = {
                .mixers = { alc880_asus_mixer },
@@ -3832,7 +3998,7 @@ static struct alc_config_preset alc880_presets[] = {
                .need_dac_fix = 1,
                .input_mux = &alc880_capture_source,
                .unsol_event = alc880_uniwill_unsol_event,
-               .init_hook = alc880_uniwill_automute,
+               .init_hook = alc880_uniwill_init_hook,
        },
        [ALC880_UNIWILL_P53] = {
                .mixers = { alc880_uniwill_p53_mixer },
@@ -3844,7 +4010,7 @@ static struct alc_config_preset alc880_presets[] = {
                .channel_mode = alc880_threestack_modes,
                .input_mux = &alc880_capture_source,
                .unsol_event = alc880_uniwill_p53_unsol_event,
-               .init_hook = alc880_uniwill_p53_hp_automute,
+               .init_hook = alc880_uniwill_p53_init_hook,
        },
        [ALC880_FUJITSU] = {
                .mixers = { alc880_fujitsu_mixer },
@@ -3858,7 +4024,7 @@ static struct alc_config_preset alc880_presets[] = {
                .channel_mode = alc880_2_jack_modes,
                .input_mux = &alc880_capture_source,
                .unsol_event = alc880_uniwill_p53_unsol_event,
-               .init_hook = alc880_uniwill_p53_hp_automute,
+               .init_hook = alc880_uniwill_p53_init_hook,
        },
        [ALC880_CLEVO] = {
                .mixers = { alc880_three_stack_mixer },
@@ -3883,8 +4049,8 @@ static struct alc_config_preset alc880_presets[] = {
                .channel_mode = alc880_lg_ch_modes,
                .need_dac_fix = 1,
                .input_mux = &alc880_lg_capture_source,
-               .unsol_event = alc880_lg_unsol_event,
-               .init_hook = alc880_lg_automute,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .init_hook = alc880_lg_init_hook,
 #ifdef CONFIG_SND_HDA_POWER_SAVE
                .loopbacks = alc880_lg_loopbacks,
 #endif
@@ -3899,8 +4065,8 @@ static struct alc_config_preset alc880_presets[] = {
                .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
                .channel_mode = alc880_lg_lw_modes,
                .input_mux = &alc880_lg_lw_capture_source,
-               .unsol_event = alc880_lg_lw_unsol_event,
-               .init_hook = alc880_lg_lw_automute,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .init_hook = alc880_lg_lw_init_hook,
        },
        [ALC880_MEDION_RIM] = {
                .mixers = { alc880_medion_rim_mixer },
@@ -3914,7 +4080,7 @@ static struct alc_config_preset alc880_presets[] = {
                .channel_mode = alc880_2_jack_modes,
                .input_mux = &alc880_medion_rim_capture_source,
                .unsol_event = alc880_medion_rim_unsol_event,
-               .init_hook = alc880_medion_rim_automute,
+               .init_hook = alc880_medion_rim_init_hook,
        },
 #ifdef CONFIG_SND_DEBUG
        [ALC880_TEST] = {
@@ -4199,7 +4365,6 @@ static void alc880_auto_init_multi_out(struct hda_codec *codec)
        struct alc_spec *spec = codec->spec;
        int i;
 
-       alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
        for (i = 0; i < spec->autocfg.line_outs; i++) {
                hda_nid_t nid = spec->autocfg.line_out_pins[i];
                int pin_type = get_pin_type(spec->autocfg.line_out_type);
@@ -4304,6 +4469,8 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
        spec->num_mux_defs = 1;
        spec->input_mux = &spec->private_imux[0];
 
+       alc_ssid_check(codec, 0x15, 0x1b, 0x14);
+
        return 1;
 }
 
@@ -4361,8 +4528,8 @@ static int patch_alc880(struct hda_codec *codec)
                                                  alc880_models,
                                                  alc880_cfg_tbl);
        if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: Unknown model for ALC880, "
-                      "trying auto-probe from BIOS...\n");
+               printk(KERN_INFO "hda_codec: Unknown model for %s, "
+                      "trying auto-probe from BIOS...\n", codec->chip_name);
                board_config = ALC880_AUTO;
        }
 
@@ -4389,12 +4556,10 @@ static int patch_alc880(struct hda_codec *codec)
        if (board_config != ALC880_AUTO)
                setup_preset(spec, &alc880_presets[board_config]);
 
-       spec->stream_name_analog = "ALC880 Analog";
        spec->stream_analog_playback = &alc880_pcm_analog_playback;
        spec->stream_analog_capture = &alc880_pcm_analog_capture;
        spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
 
-       spec->stream_name_digital = "ALC880 Digital";
        spec->stream_digital_playback = &alc880_pcm_digital_playback;
        spec->stream_digital_capture = &alc880_pcm_digital_capture;
 
@@ -5679,7 +5844,6 @@ static void alc260_auto_init_multi_out(struct hda_codec *codec)
        struct alc_spec *spec = codec->spec;
        hda_nid_t nid;
 
-       alc_subsystem_id(codec, 0x10, 0x15, 0x0f);
        nid = spec->autocfg.line_out_pins[0];
        if (nid) {
                int pin_type = get_pin_type(spec->autocfg.line_out_type);
@@ -5789,6 +5953,8 @@ static int alc260_parse_auto_config(struct hda_codec *codec)
        spec->num_mux_defs = 1;
        spec->input_mux = &spec->private_imux[0];
 
+       alc_ssid_check(codec, 0x10, 0x15, 0x0f);
+
        return 1;
 }
 
@@ -6006,8 +6172,9 @@ static int patch_alc260(struct hda_codec *codec)
                                                  alc260_models,
                                                  alc260_cfg_tbl);
        if (board_config < 0) {
-               snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, "
-                          "trying auto-probe from BIOS...\n");
+               snd_printd(KERN_INFO "hda_codec: Unknown model for %s, "
+                          "trying auto-probe from BIOS...\n",
+                          codec->chip_name);
                board_config = ALC260_AUTO;
        }
 
@@ -6034,11 +6201,9 @@ static int patch_alc260(struct hda_codec *codec)
        if (board_config != ALC260_AUTO)
                setup_preset(spec, &alc260_presets[board_config]);
 
-       spec->stream_name_analog = "ALC260 Analog";
        spec->stream_analog_playback = &alc260_pcm_analog_playback;
        spec->stream_analog_capture = &alc260_pcm_analog_capture;
 
-       spec->stream_name_digital = "ALC260 Digital";
        spec->stream_digital_playback = &alc260_pcm_digital_playback;
        spec->stream_digital_capture = &alc260_pcm_digital_capture;
 
@@ -6115,6 +6280,16 @@ static struct hda_input_mux alc882_capture_source = {
                { "CD", 0x4 },
        },
 };
+
+static struct hda_input_mux mb5_capture_source = {
+       .num_items = 3,
+       .items = {
+               { "Mic", 0x1 },
+               { "Line", 0x2 },
+               { "CD", 0x4 },
+       },
+};
+
 /*
  * 2ch mode
  */
@@ -6202,6 +6377,34 @@ static struct hda_channel_mode alc885_mbp_6ch_modes[2] = {
        { 6, alc885_mbp_ch6_init },
 };
 
+/*
+ * 2ch
+ * Speakers/Woofer/HP = Front
+ * LineIn = Input
+ */
+static struct hda_verb alc885_mb5_ch2_init[] = {
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       { } /* end */
+};
+
+/*
+ * 6ch mode
+ * Speakers/HP = Front
+ * Woofer = LFE
+ * LineIn = Surround
+ */
+static struct hda_verb alc885_mb5_ch6_init[] = {
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+       { } /* end */
+};
+
+static struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
+       { 2, alc885_mb5_ch2_init },
+       { 6, alc885_mb5_ch6_init },
+};
 
 /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
  *                 Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
@@ -6244,6 +6447,25 @@ static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
        HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
        { } /* end */
 };
+
+static struct snd_kcontrol_new alc885_mb5_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE   ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE   ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE   ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("HP Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE   ("HP Playback Switch", 0x0f, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE  ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE  ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x19, 0x00, HDA_INPUT),
+       { } /* end */
+};
+
 static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
@@ -6471,6 +6693,55 @@ static struct hda_verb alc882_macpro_init_verbs[] = {
        { }
 };
 
+/* Macbook 5,1 */
+static struct hda_verb alc885_mb5_init_verbs[] = {
+       /* DACs */
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* Front mixer */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* Surround mixer */
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* LFE mixer */
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* HP mixer */
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* Front Pin (0x0c) */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* LFE Pin (0x0e) */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
+       /* HP Pin (0x0f) */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
+       /* Front Mic pin: input vref at 80% */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Line In pin */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       { }
+};
+
 /* Macbook Pro rev3 */
 static struct hda_verb alc885_mbp3_init_verbs[] = {
        /* Front mixer: unmute input/output amp left and right (volume = 0) */
@@ -6560,45 +6831,23 @@ static struct hda_verb alc885_imac24_init_verbs[] = {
 };
 
 /* Toggle speaker-output according to the hp-jack state */
-static void alc885_imac24_automute(struct hda_codec *codec)
+static void alc885_imac24_automute_init_hook(struct hda_codec *codec)
 {
-       unsigned int present;
-
-       present = snd_hda_codec_read(codec, 0x14, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-       snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-       snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-}
+       struct alc_spec *spec = codec->spec;
 
-/* Processes unsolicited events. */
-static void alc885_imac24_unsol_event(struct hda_codec *codec,
-                                     unsigned int res)
-{
-       /* Headphone insertion or removal. */
-       if ((res >> 26) == ALC880_HP_EVENT)
-               alc885_imac24_automute(codec);
+       spec->autocfg.hp_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x18;
+       spec->autocfg.speaker_pins[1] = 0x1a;
+       alc_automute_amp(codec);
 }
 
-static void alc885_mbp3_automute(struct hda_codec *codec)
+static void alc885_mbp3_init_hook(struct hda_codec *codec)
 {
-       unsigned int present;
-
-       present = snd_hda_codec_read(codec, 0x15, 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,
-                                HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
+       struct alc_spec *spec = codec->spec;
 
-}
-static void alc885_mbp3_unsol_event(struct hda_codec *codec,
-                                   unsigned int res)
-{
-       /* Headphone insertion or removal. */
-       if ((res >> 26) == ALC880_HP_EVENT)
-               alc885_mbp3_automute(codec);
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       alc_automute_amp(codec);
 }
 
 
@@ -6623,24 +6872,25 @@ static struct hda_verb alc882_targa_verbs[] = {
 /* toggle speaker-output according to the hp-jack state */
 static void alc882_targa_automute(struct hda_codec *codec)
 {
-       unsigned int present;
-
-       present = snd_hda_codec_read(codec, 0x14, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-       snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+       struct alc_spec *spec = codec->spec;
+       alc_automute_amp(codec);
        snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
-                                 present ? 1 : 3);
+                                 spec->jack_present ? 1 : 3);
+}
+
+static void alc882_targa_init_hook(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x1b;
+       alc882_targa_automute(codec);
 }
 
 static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
 {
-       /* Looks like the unsol event is incompatible with the standard
-        * definition.  4bit tag is placed at 26 bit!
-        */
-       if (((res >> 26) == ALC880_HP_EVENT)) {
+       if ((res >> 26) == ALC880_HP_EVENT)
                alc882_targa_automute(codec);
-       }
 }
 
 static struct hda_verb alc882_asus_a7j_verbs[] = {
@@ -6722,7 +6972,7 @@ static void alc885_macpro_init_hook(struct hda_codec *codec)
 static void alc885_imac24_init_hook(struct hda_codec *codec)
 {
        alc885_macpro_init_hook(codec);
-       alc885_imac24_automute(codec);
+       alc885_imac24_automute_init_hook(codec);
 }
 
 /*
@@ -6815,6 +7065,7 @@ static const char *alc882_models[ALC882_MODEL_LAST] = {
        [ALC882_ASUS_A7J]       = "asus-a7j",
        [ALC882_ASUS_A7M]       = "asus-a7m",
        [ALC885_MACPRO]         = "macpro",
+       [ALC885_MB5]            = "mb5",
        [ALC885_MBP3]           = "mbp3",
        [ALC885_IMAC24]         = "imac24",
        [ALC882_AUTO]           = "auto",
@@ -6892,8 +7143,20 @@ static struct alc_config_preset alc882_presets[] = {
                .input_mux = &alc882_capture_source,
                .dig_out_nid = ALC882_DIGOUT_NID,
                .dig_in_nid = ALC882_DIGIN_NID,
-               .unsol_event = alc885_mbp3_unsol_event,
-               .init_hook = alc885_mbp3_automute,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .init_hook = alc885_mbp3_init_hook,
+       },
+       [ALC885_MB5] = {
+               .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
+               .init_verbs = { alc885_mb5_init_verbs,
+                               alc880_gpio1_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+               .dac_nids = alc882_dac_nids,
+               .channel_mode = alc885_mb5_6ch_modes,
+               .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
+               .input_mux = &mb5_capture_source,
+               .dig_out_nid = ALC882_DIGOUT_NID,
+               .dig_in_nid = ALC882_DIGIN_NID,
        },
        [ALC885_MACPRO] = {
                .mixers = { alc882_macpro_mixer },
@@ -6917,7 +7180,7 @@ static struct alc_config_preset alc882_presets[] = {
                .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
                .channel_mode = alc882_ch_modes,
                .input_mux = &alc882_capture_source,
-               .unsol_event = alc885_imac24_unsol_event,
+               .unsol_event = alc_automute_amp_unsol_event,
                .init_hook = alc885_imac24_init_hook,
        },
        [ALC882_TARGA] = {
@@ -6934,7 +7197,7 @@ static struct alc_config_preset alc882_presets[] = {
                .need_dac_fix = 1,
                .input_mux = &alc882_capture_source,
                .unsol_event = alc882_targa_unsol_event,
-               .init_hook = alc882_targa_automute,
+               .init_hook = alc882_targa_init_hook,
        },
        [ALC882_ASUS_A7J] = {
                .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
@@ -7014,7 +7277,6 @@ static void alc882_auto_init_multi_out(struct hda_codec *codec)
        struct alc_spec *spec = codec->spec;
        int i;
 
-       alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
        for (i = 0; i <= HDA_SIDE; i++) {
                hda_nid_t nid = spec->autocfg.line_out_pins[i];
                int pin_type = get_pin_type(spec->autocfg.line_out_type);
@@ -7197,10 +7459,17 @@ static int patch_alc882(struct hda_codec *codec)
                case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */
                case 0x106b00a4: /* MacbookPro4,1 */
                case 0x106b2c00: /* Macbook Pro rev3 */
-               case 0x106b3600: /* Macbook 3.1 */
+               /* Macbook 3.1 (0x106b3600) is handled by patch_alc883() */
                case 0x106b3800: /* MacbookPro4,1 - latter revision */
                        board_config = ALC885_MBP3;
                        break;
+               case 0x106b3f00: /* Macbook 5,1 */
+               case 0x106b4000: /* Macbook Pro 5,1 - FIXME: HP jack sense
+                                 *   seems not working, so apparently
+                                 *   no perfect solution yet
+                                 */
+                       board_config = ALC885_MB5;
+                       break;
                default:
                        /* ALC889A is handled better as ALC888-compatible */
                        if (codec->revision_id == 0x100101 ||
@@ -7208,8 +7477,9 @@ static int patch_alc882(struct hda_codec *codec)
                                alc_free(codec);
                                return patch_alc883(codec);
                        }
-                       printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
-                                        "trying auto-probe from BIOS...\n");
+                       printk(KERN_INFO "hda_codec: Unknown model for %s, "
+                              "trying auto-probe from BIOS...\n",
+                              codec->chip_name);
                        board_config = ALC882_AUTO;
                }
        }
@@ -7239,14 +7509,6 @@ static int patch_alc882(struct hda_codec *codec)
        if (board_config != ALC882_AUTO)
                setup_preset(spec, &alc882_presets[board_config]);
 
-       if (codec->vendor_id == 0x10ec0885) {
-               spec->stream_name_analog = "ALC885 Analog";
-               spec->stream_name_digital = "ALC885 Digital";
-       } else {
-               spec->stream_name_analog = "ALC882 Analog";
-               spec->stream_name_digital = "ALC882 Digital";
-       }
-
        spec->stream_analog_playback = &alc882_pcm_analog_playback;
        spec->stream_analog_capture = &alc882_pcm_analog_capture;
        /* FIXME: setup DAC5 */
@@ -7399,6 +7661,17 @@ static struct hda_input_mux alc883_asus_eee1601_capture_source = {
        },
 };
 
+static struct hda_input_mux alc889A_mb31_capture_source = {
+       .num_items = 2,
+       .items = {
+               { "Mic", 0x0 },
+               /* Front Mic (0x01) unused */
+               { "Line", 0x2 },
+               /* Line 2 (0x03) unused */
+               /* CD (0x04) unsused? */
+       },
+};
+
 /*
  * 2ch mode
  */
@@ -7448,6 +7721,73 @@ static struct hda_channel_mode alc883_3ST_6ch_modes[3] = {
        { 6, alc883_3ST_ch6_init },
 };
 
+
+/*
+ * 2ch mode
+ */
+static struct hda_verb alc883_4ST_ch2_init[] = {
+       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { } /* end */
+};
+
+/*
+ * 4ch mode
+ */
+static struct hda_verb alc883_4ST_ch4_init[] = {
+       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { } /* end */
+};
+
+/*
+ * 6ch mode
+ */
+static struct hda_verb alc883_4ST_ch6_init[] = {
+       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { } /* end */
+};
+
+/*
+ * 8ch mode
+ */
+static struct hda_verb alc883_4ST_ch8_init[] = {
+       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { } /* end */
+};
+
+static struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
+       { 2, alc883_4ST_ch2_init },
+       { 4, alc883_4ST_ch4_init },
+       { 6, alc883_4ST_ch6_init },
+       { 8, alc883_4ST_ch8_init },
+};
+
+
 /*
  * 2ch mode
  */
@@ -7517,6 +7857,49 @@ static struct hda_channel_mode alc883_sixstack_modes[2] = {
        { 8, alc883_sixstack_ch8_init },
 };
 
+/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
+static struct hda_verb alc889A_mb31_ch2_init[] = {
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},             /* HP as front */
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},    /* Line as input */
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},   /* Line off */
+       { } /* end */
+};
+
+/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */
+static struct hda_verb alc889A_mb31_ch4_init[] = {
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},             /* HP as front */
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},   /* Line as output */
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
+       { } /* end */
+};
+
+/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */
+static struct hda_verb alc889A_mb31_ch5_init[] = {
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},             /* HP as rear */
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},    /* Line as input */
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},   /* Line off */
+       { } /* end */
+};
+
+/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */
+static struct hda_verb alc889A_mb31_ch6_init[] = {
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},             /* HP as front */
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},   /* Subwoofer off */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},   /* Line as output */
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
+       { } /* end */
+};
+
+static struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
+       { 2, alc889A_mb31_ch2_init },
+       { 4, alc889A_mb31_ch4_init },
+       { 5, alc889A_mb31_ch5_init },
+       { 6, alc889A_mb31_ch6_init },
+};
+
 static struct hda_verb alc883_medion_eapd_verbs[] = {
         /* eanable EAPD on medion laptop */
        {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
@@ -7782,8 +8165,6 @@ static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
        HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
        HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
@@ -7797,6 +8178,42 @@ static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new alc889A_mb31_mixer[] = {
+       /* Output mixers */
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00,
+               HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT),
+       /* Output switches */
+       HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT),
+       /* Boost mixers */
+       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
+       /* Input mixers */
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       { } /* end */
+};
+
+static struct snd_kcontrol_new alc883_vaiott_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
 static struct hda_bind_ctls alc883_bind_cap_vol = {
        .ops = &snd_hda_bind_vol,
        .values = {
@@ -7932,16 +8349,14 @@ static struct hda_verb alc883_init_verbs[] = {
 };
 
 /* toggle speaker-output according to the hp-jack state */
-static void alc883_mitac_hp_automute(struct hda_codec *codec)
+static void alc883_mitac_init_hook(struct hda_codec *codec)
 {
-       unsigned int present;
+       struct alc_spec *spec = codec->spec;
 
-       present = snd_hda_codec_read(codec, 0x15, 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, 0x17, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x17;
+       alc_automute_amp(codec);
 }
 
 /* auto-toggle front mic */
@@ -7958,25 +8373,6 @@ static void alc883_mitac_mic_automute(struct hda_codec *codec)
 }
 */
 
-static void alc883_mitac_automute(struct hda_codec *codec)
-{
-       alc883_mitac_hp_automute(codec);
-       /* alc883_mitac_mic_automute(codec); */
-}
-
-static void alc883_mitac_unsol_event(struct hda_codec *codec,
-                                          unsigned int res)
-{
-       switch (res >> 26) {
-       case ALC880_HP_EVENT:
-               alc883_mitac_hp_automute(codec);
-               break;
-       case ALC880_MIC_EVENT:
-               /* alc883_mitac_mic_automute(codec); */
-               break;
-       }
-}
-
 static struct hda_verb alc883_mitac_verbs[] = {
        /* HP */
        {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -8028,14 +8424,24 @@ static struct hda_verb alc883_tagra_verbs[] = {
        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
        {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 
-       {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+/* Connect Line-Out side jack (SPDIF) to Side */
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
+/* Connect Mic jack to CLFE */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
+/* Connect Line-in jack to Surround */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
+/* Connect HP out jack to Front */
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
 
        {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
-       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
-       {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
 
        { } /* end */
 };
@@ -8094,29 +8500,26 @@ static struct hda_verb alc888_6st_dell_verbs[] = {
        { }
 };
 
-static void alc888_3st_hp_front_automute(struct hda_codec *codec)
-{
-       unsigned int present, bits;
+static struct hda_verb alc883_vaiott_verbs[] = {
+       /* HP */
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 
-       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, 0x14, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, bits);
-       snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, bits);
-       snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, bits);
-}
+       /* enable unsolicited event */
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+
+       { } /* end */
+};
 
-static void alc888_3st_hp_unsol_event(struct hda_codec *codec,
-                                     unsigned int res)
+static void alc888_3st_hp_init_hook(struct hda_codec *codec)
 {
-       switch (res >> 26) {
-       case ALC880_HP_EVENT:
-               alc888_3st_hp_front_automute(codec);
-               break;
-       }
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x16;
+       spec->autocfg.speaker_pins[2] = 0x18;
+       alc_automute_amp(codec);
 }
 
 static struct hda_verb alc888_3st_hp_verbs[] = {
@@ -8213,56 +8616,18 @@ static struct hda_verb alc883_medion_md2_verbs[] = {
 };
 
 /* toggle speaker-output according to the hp-jack state */
-static void alc883_medion_md2_automute(struct hda_codec *codec)
+static void alc883_medion_md2_init_hook(struct hda_codec *codec)
 {
-       unsigned int present;
-
-       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);
-}
-
-static void alc883_medion_md2_unsol_event(struct hda_codec *codec,
-                                         unsigned int res)
-{
-       if ((res >> 26) == ALC880_HP_EVENT)
-               alc883_medion_md2_automute(codec);
-}
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc883_tagra_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;
-       bits = present ? HDA_AMP_MUTE : 0;
-       snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, bits);
-       snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
-                                 present ? 1 : 3);
-}
+       struct alc_spec *spec = codec->spec;
 
-static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       if ((res >> 26) == ALC880_HP_EVENT)
-               alc883_tagra_automute(codec);
+       spec->autocfg.hp_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x15;
+       alc_automute_amp(codec);
 }
 
 /* toggle speaker-output according to the hp-jack state */
-static void alc883_clevo_m720_hp_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;
-       bits = present ? HDA_AMP_MUTE : 0;
-       snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, bits);
-}
+#define alc883_tagra_init_hook         alc882_targa_init_hook
+#define alc883_tagra_unsol_event       alc882_targa_unsol_event
 
 static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
 {
@@ -8274,9 +8639,13 @@ static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
                                 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
 }
 
-static void alc883_clevo_m720_automute(struct hda_codec *codec)
+static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
 {
-       alc883_clevo_m720_hp_automute(codec);
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       alc_automute_amp(codec);
        alc883_clevo_m720_mic_automute(codec);
 }
 
@@ -8284,52 +8653,32 @@ static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
                                           unsigned int res)
 {
        switch (res >> 26) {
-       case ALC880_HP_EVENT:
-               alc883_clevo_m720_hp_automute(codec);
-               break;
        case ALC880_MIC_EVENT:
                alc883_clevo_m720_mic_automute(codec);
                break;
+       default:
+               alc_automute_amp_unsol_event(codec, res);
+               break;
        }
 }
 
 /* toggle speaker-output according to the hp-jack state */
-static void alc883_2ch_fujitsu_pi2515_automute(struct hda_codec *codec)
+static void alc883_2ch_fujitsu_pi2515_init_hook(struct hda_codec *codec)
 {
-       unsigned int present;
-       unsigned char bits;
-
-       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);
-}
+       struct alc_spec *spec = codec->spec;
 
-static void alc883_2ch_fujitsu_pi2515_unsol_event(struct hda_codec *codec,
-                                                 unsigned int res)
-{
-       if ((res >> 26) == ALC880_HP_EVENT)
-               alc883_2ch_fujitsu_pi2515_automute(codec);
+       spec->autocfg.hp_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x15;
+       alc_automute_amp(codec);
 }
 
-static void alc883_haier_w66_automute(struct hda_codec *codec)
+static void alc883_haier_w66_init_hook(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;
-       bits = present ? 0x80 : 0;
-       snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-                                0x80, bits);
-}
+       struct alc_spec *spec = codec->spec;
 
-static void alc883_haier_w66_unsol_event(struct hda_codec *codec,
-                                        unsigned int res)
-{
-       if ((res >> 26) == ALC880_HP_EVENT)
-               alc883_haier_w66_automute(codec);
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       alc_automute_amp(codec);
 }
 
 static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
@@ -8337,8 +8686,8 @@ static void alc883_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_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);
@@ -8368,23 +8717,14 @@ static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
 }
 
 /* toggle speaker-output according to the hp-jack state */
-static void alc883_acer_aspire_automute(struct hda_codec *codec)
+static void alc883_acer_aspire_init_hook(struct hda_codec *codec)
 {
-       unsigned int present;
-
-       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);
-       snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-}
+       struct alc_spec *spec = codec->spec;
 
-static void alc883_acer_aspire_unsol_event(struct hda_codec *codec,
-                                          unsigned int res)
-{
-       if ((res >> 26) == ALC880_HP_EVENT)
-               alc883_acer_aspire_automute(codec);
+       spec->autocfg.hp_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[1] = 0x16;
+       alc_automute_amp(codec);
 }
 
 static struct hda_verb alc883_acer_eapd_verbs[] = {
@@ -8405,75 +8745,39 @@ static struct hda_verb alc883_acer_eapd_verbs[] = {
        { }
 };
 
-static void alc888_6st_dell_front_automute(struct hda_codec *codec)
+static void alc888_6st_dell_init_hook(struct hda_codec *codec)
 {
-       unsigned int present;
-
-       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,
-                               HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-       snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
-                               HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-       snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
-                               HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-}
+       struct alc_spec *spec = codec->spec;
 
-static void alc888_6st_dell_unsol_event(struct hda_codec *codec,
-                                            unsigned int res)
-{
-       switch (res >> 26) {
-       case ALC880_HP_EVENT:
-               /* printk(KERN_DEBUG "hp_event\n"); */
-               alc888_6st_dell_front_automute(codec);
-               break;
-       }
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x15;
+       spec->autocfg.speaker_pins[2] = 0x16;
+       spec->autocfg.speaker_pins[3] = 0x17;
+       alc_automute_amp(codec);
 }
 
-static void alc888_lenovo_sky_front_automute(struct hda_codec *codec)
+static void alc888_lenovo_sky_init_hook(struct hda_codec *codec)
 {
-       unsigned int mute;
-       unsigned int present;
+       struct alc_spec *spec = codec->spec;
 
-       snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
-       present = snd_hda_codec_read(codec, 0x1b, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0);
-       present = (present & 0x80000000) != 0;
-       if (present) {
-               /* mute internal speaker */
-               snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-                                        HDA_AMP_MUTE, HDA_AMP_MUTE);
-               snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-                                        HDA_AMP_MUTE, HDA_AMP_MUTE);
-               snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
-                                        HDA_AMP_MUTE, HDA_AMP_MUTE);
-               snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
-                                        HDA_AMP_MUTE, HDA_AMP_MUTE);
-               snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
-                                        HDA_AMP_MUTE, HDA_AMP_MUTE);
-       } else {
-               /* unmute internal speaker if necessary */
-               mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
-               snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-                                        HDA_AMP_MUTE, mute);
-               snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-                                        HDA_AMP_MUTE, mute);
-               snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
-                                        HDA_AMP_MUTE, mute);
-               snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
-                                        HDA_AMP_MUTE, mute);
-               snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
-                                        HDA_AMP_MUTE, mute);
-       }
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x15;
+       spec->autocfg.speaker_pins[2] = 0x16;
+       spec->autocfg.speaker_pins[3] = 0x17;
+       spec->autocfg.speaker_pins[4] = 0x1a;
+       alc_automute_amp(codec);
 }
 
-static void alc883_lenovo_sky_unsol_event(struct hda_codec *codec,
-                                            unsigned int res)
+static void alc883_vaiott_init_hook(struct hda_codec *codec)
 {
-       if ((res >> 26) == ALC880_HP_EVENT)
-               alc888_lenovo_sky_front_automute(codec);
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x17;
+       alc_automute_amp(codec);
 }
 
 /*
@@ -8561,39 +8865,33 @@ static void alc883_nb_mic_automute(struct hda_codec *codec)
                            0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
 }
 
-static void alc883_M90V_speaker_automute(struct hda_codec *codec)
+static void alc883_M90V_init_hook(struct hda_codec *codec)
 {
-       unsigned int present;
-       unsigned char bits;
+       struct alc_spec *spec = codec->spec;
 
-       present = snd_hda_codec_read(codec, 0x1b, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0)
-               & AC_PINSENSE_PRESENCE;
-       bits = present ? 0 : PIN_OUT;
-       snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                           bits);
-       snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                           bits);
-       snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                           bits);
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x15;
+       spec->autocfg.speaker_pins[2] = 0x16;
+       alc_automute_pin(codec);
 }
 
 static void alc883_mode2_unsol_event(struct hda_codec *codec,
                                           unsigned int res)
 {
        switch (res >> 26) {
-       case ALC880_HP_EVENT:
-               alc883_M90V_speaker_automute(codec);
-               break;
        case ALC880_MIC_EVENT:
                alc883_nb_mic_automute(codec);
                break;
+       default:
+               alc_sku_unsol_event(codec, res);
+               break;
        }
 }
 
 static void alc883_mode2_inithook(struct hda_codec *codec)
 {
-       alc883_M90V_speaker_automute(codec);
+       alc883_M90V_init_hook(codec);
        alc883_nb_mic_automute(codec);
 }
 
@@ -8610,32 +8908,49 @@ static struct hda_verb alc888_asus_eee1601_verbs[] = {
        { } /* end */
 };
 
-static void alc883_eee1601_speaker_automute(struct hda_codec *codec)
+static void alc883_eee1601_inithook(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x1b;
+       alc_automute_pin(codec);
+}
+
+static struct hda_verb alc889A_mb31_verbs[] = {
+       /* Init rear pin (used as headphone output) */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},    /* Apple Headphones */
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},           /* Connect to front */
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+       /* Init line pin (used as output in 4ch and 6ch mode) */
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},           /* Connect to CLFE */
+       /* Init line 2 pin (used as headphone out by default) */
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},  /* Use as input */
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */
+       { } /* end */
+};
+
+/* Mute speakers according to the headphone jack state */
+static void alc889A_mb31_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)
-               & AC_PINSENSE_PRESENCE;
-       bits = present ? 0 : PIN_OUT;
-       snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                           bits);
-}
 
-static void alc883_eee1601_unsol_event(struct hda_codec *codec,
-                                          unsigned int res)
-{
-       switch (res >> 26) {
-       case ALC880_HP_EVENT:
-               alc883_eee1601_speaker_automute(codec);
-               break;
+       /* 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;
+               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,
+                       HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
        }
 }
 
-static void alc883_eee1601_inithook(struct hda_codec *codec)
+static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
 {
-       alc883_eee1601_speaker_automute(codec);
+       if ((res >> 26) == ALC880_HP_EVENT)
+               alc889A_mb31_automute(codec);
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -8659,9 +8974,11 @@ static const char *alc883_models[ALC883_MODEL_LAST] = {
        [ALC883_6ST_DIG]        = "6stack-dig",
        [ALC883_TARGA_DIG]      = "targa-dig",
        [ALC883_TARGA_2ch_DIG]  = "targa-2ch-dig",
+       [ALC883_TARGA_8ch_DIG]  = "targa-8ch-dig",
        [ALC883_ACER]           = "acer",
        [ALC883_ACER_ASPIRE]    = "acer-aspire",
        [ALC888_ACER_ASPIRE_4930G]      = "acer-aspire-4930g",
+       [ALC888_ACER_ASPIRE_8930G]      = "acer-aspire-8930g",
        [ALC883_MEDION]         = "medion",
        [ALC883_MEDION_MD2]     = "medion-md2",
        [ALC883_LAPTOP_EAPD]    = "laptop-eapd",
@@ -8678,6 +8995,8 @@ static const char *alc883_models[ALC883_MODEL_LAST] = {
        [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
        [ALC883_3ST_6ch_INTEL]  = "3stack-6ch-intel",
        [ALC1200_ASUS_P5Q]      = "asus-p5q",
+       [ALC889A_MB31]          = "mb31",
+       [ALC883_SONY_VAIO_TT]   = "sony-vaio-tt",
        [ALC883_AUTO]           = "auto",
 };
 
@@ -8693,14 +9012,18 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
                ALC888_ACER_ASPIRE_4930G),
        SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
                ALC888_ACER_ASPIRE_4930G),
+       SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
+               ALC888_ACER_ASPIRE_8930G),
        SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC883_AUTO),
        SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC883_AUTO),
        SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
                ALC888_ACER_ASPIRE_4930G),
        SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
                ALC888_ACER_ASPIRE_4930G),
-       /* default Acer */
-       SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER),
+       /* default Acer -- disabled as it causes more problems.
+        *    model=auto should work fine now
+        */
+       /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
        SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
        SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
@@ -8736,6 +9059,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
        SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
        SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
+       SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG),
        SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
@@ -8768,6 +9092,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
        SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
        SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC883_3ST_6ch_INTEL),
        SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
+       SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
        {}
 };
 
@@ -8848,7 +9173,7 @@ static struct alc_config_preset alc883_presets[] = {
                .need_dac_fix = 1,
                .input_mux = &alc883_capture_source,
                .unsol_event = alc883_tagra_unsol_event,
-               .init_hook = alc883_tagra_automute,
+               .init_hook = alc883_tagra_init_hook,
        },
        [ALC883_TARGA_2ch_DIG] = {
                .mixers = { alc883_tagra_2ch_mixer},
@@ -8862,7 +9187,25 @@ static struct alc_config_preset alc883_presets[] = {
                .channel_mode = alc883_3ST_2ch_modes,
                .input_mux = &alc883_capture_source,
                .unsol_event = alc883_tagra_unsol_event,
-               .init_hook = alc883_tagra_automute,
+               .init_hook = alc883_tagra_init_hook,
+       },
+       [ALC883_TARGA_8ch_DIG] = {
+               .mixers = { alc883_base_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
+                               alc883_tagra_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
+               .adc_nids = alc883_adc_nids_rev,
+               .capsrc_nids = alc883_capsrc_nids_rev,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes),
+               .channel_mode = alc883_4ST_8ch_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc883_capture_source,
+               .unsol_event = alc883_tagra_unsol_event,
+               .init_hook = alc883_tagra_init_hook,
        },
        [ALC883_ACER] = {
                .mixers = { alc883_base_mixer },
@@ -8887,8 +9230,8 @@ static struct alc_config_preset alc883_presets[] = {
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
                .channel_mode = alc883_3ST_2ch_modes,
                .input_mux = &alc883_capture_source,
-               .unsol_event = alc883_acer_aspire_unsol_event,
-               .init_hook = alc883_acer_aspire_automute,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .init_hook = alc883_acer_aspire_init_hook,
        },
        [ALC888_ACER_ASPIRE_4930G] = {
                .mixers = { alc888_base_mixer,
@@ -8907,8 +9250,29 @@ static struct alc_config_preset alc883_presets[] = {
                .num_mux_defs =
                        ARRAY_SIZE(alc888_2_capture_sources),
                .input_mux = alc888_2_capture_sources,
-               .unsol_event = alc888_acer_aspire_4930g_unsol_event,
-               .init_hook = alc888_acer_aspire_4930g_automute,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .init_hook = alc888_acer_aspire_4930g_init_hook,
+       },
+       [ALC888_ACER_ASPIRE_8930G] = {
+               .mixers = { alc888_base_mixer,
+                               alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
+                               alc889_acer_aspire_8930g_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
+               .adc_nids = alc889_adc_nids,
+               .capsrc_nids = alc889_capsrc_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
+               .channel_mode = alc883_3ST_6ch_modes,
+               .need_dac_fix = 1,
+               .const_channel_count = 6,
+               .num_mux_defs =
+                       ARRAY_SIZE(alc889_capture_sources),
+               .input_mux = alc889_capture_sources,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .init_hook = alc889_acer_aspire_8930g_init_hook,
        },
        [ALC883_MEDION] = {
                .mixers = { alc883_fivestack_mixer,
@@ -8932,8 +9296,8 @@ static struct alc_config_preset alc883_presets[] = {
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
                .channel_mode = alc883_3ST_2ch_modes,
                .input_mux = &alc883_capture_source,
-               .unsol_event = alc883_medion_md2_unsol_event,
-               .init_hook = alc883_medion_md2_automute,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .init_hook = alc883_medion_md2_init_hook,
        },
        [ALC883_LAPTOP_EAPD] = {
                .mixers = { alc883_base_mixer },
@@ -8954,7 +9318,7 @@ static struct alc_config_preset alc883_presets[] = {
                .channel_mode = alc883_3ST_2ch_modes,
                .input_mux = &alc883_capture_source,
                .unsol_event = alc883_clevo_m720_unsol_event,
-               .init_hook = alc883_clevo_m720_automute,
+               .init_hook = alc883_clevo_m720_init_hook,
        },
        [ALC883_LENOVO_101E_2ch] = {
                .mixers = { alc883_lenovo_101e_2ch_mixer},
@@ -8978,8 +9342,8 @@ static struct alc_config_preset alc883_presets[] = {
                .channel_mode = alc883_3ST_2ch_modes,
                .need_dac_fix = 1,
                .input_mux = &alc883_lenovo_nb0763_capture_source,
-               .unsol_event = alc883_medion_md2_unsol_event,
-               .init_hook = alc883_medion_md2_automute,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .init_hook = alc883_medion_md2_init_hook,
        },
        [ALC888_LENOVO_MS7195_DIG] = {
                .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
@@ -9003,8 +9367,8 @@ static struct alc_config_preset alc883_presets[] = {
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
                .channel_mode = alc883_3ST_2ch_modes,
                .input_mux = &alc883_capture_source,
-               .unsol_event = alc883_haier_w66_unsol_event,
-               .init_hook = alc883_haier_w66_automute,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .init_hook = alc883_haier_w66_init_hook,
        },
        [ALC888_3ST_HP] = {
                .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
@@ -9015,8 +9379,8 @@ static struct alc_config_preset alc883_presets[] = {
                .channel_mode = alc888_3st_hp_modes,
                .need_dac_fix = 1,
                .input_mux = &alc883_capture_source,
-               .unsol_event = alc888_3st_hp_unsol_event,
-               .init_hook = alc888_3st_hp_front_automute,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .init_hook = alc888_3st_hp_init_hook,
        },
        [ALC888_6ST_DELL] = {
                .mixers = { alc883_base_mixer, alc883_chmode_mixer },
@@ -9028,8 +9392,8 @@ static struct alc_config_preset alc883_presets[] = {
                .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
                .channel_mode = alc883_sixstack_modes,
                .input_mux = &alc883_capture_source,
-               .unsol_event = alc888_6st_dell_unsol_event,
-               .init_hook = alc888_6st_dell_front_automute,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .init_hook = alc888_6st_dell_init_hook,
        },
        [ALC883_MITAC] = {
                .mixers = { alc883_mitac_mixer },
@@ -9039,8 +9403,8 @@ static struct alc_config_preset alc883_presets[] = {
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
                .channel_mode = alc883_3ST_2ch_modes,
                .input_mux = &alc883_capture_source,
-               .unsol_event = alc883_mitac_unsol_event,
-               .init_hook = alc883_mitac_automute,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .init_hook = alc883_mitac_init_hook,
        },
        [ALC883_FUJITSU_PI2515] = {
                .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
@@ -9052,8 +9416,8 @@ static struct alc_config_preset alc883_presets[] = {
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
                .channel_mode = alc883_3ST_2ch_modes,
                .input_mux = &alc883_fujitsu_pi2515_capture_source,
-               .unsol_event = alc883_2ch_fujitsu_pi2515_unsol_event,
-               .init_hook = alc883_2ch_fujitsu_pi2515_automute,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .init_hook = alc883_2ch_fujitsu_pi2515_init_hook,
        },
        [ALC888_FUJITSU_XA3530] = {
                .mixers = { alc888_base_mixer, alc883_chmode_mixer },
@@ -9070,8 +9434,8 @@ static struct alc_config_preset alc883_presets[] = {
                .num_mux_defs =
                        ARRAY_SIZE(alc888_2_capture_sources),
                .input_mux = alc888_2_capture_sources,
-               .unsol_event = alc888_fujitsu_xa3530_unsol_event,
-               .init_hook = alc888_fujitsu_xa3530_automute,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .init_hook = alc888_fujitsu_xa3530_init_hook,
        },
        [ALC888_LENOVO_SKY] = {
                .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
@@ -9083,8 +9447,8 @@ static struct alc_config_preset alc883_presets[] = {
                .channel_mode = alc883_sixstack_modes,
                .need_dac_fix = 1,
                .input_mux = &alc883_lenovo_sky_capture_source,
-               .unsol_event = alc883_lenovo_sky_unsol_event,
-               .init_hook = alc888_lenovo_sky_front_automute,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .init_hook = alc888_lenovo_sky_init_hook,
        },
        [ALC888_ASUS_M90V] = {
                .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
@@ -9112,7 +9476,7 @@ static struct alc_config_preset alc883_presets[] = {
                .channel_mode = alc883_3ST_2ch_modes,
                .need_dac_fix = 1,
                .input_mux = &alc883_asus_eee1601_capture_source,
-               .unsol_event = alc883_eee1601_unsol_event,
+               .unsol_event = alc_sku_unsol_event,
                .init_hook = alc883_eee1601_inithook,
        },
        [ALC1200_ASUS_P5Q] = {
@@ -9127,6 +9491,32 @@ static struct alc_config_preset alc883_presets[] = {
                .channel_mode = alc883_sixstack_modes,
                .input_mux = &alc883_capture_source,
        },
+       [ALC889A_MB31] = {
+               .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer},
+               .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs,
+                       alc880_gpio1_init_verbs },
+               .adc_nids = alc883_adc_nids,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .channel_mode = alc889A_mb31_6ch_modes,
+               .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes),
+               .input_mux = &alc889A_mb31_capture_source,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .unsol_event = alc889A_mb31_unsol_event,
+               .init_hook = alc889A_mb31_automute,
+       },
+       [ALC883_SONY_VAIO_TT] = {
+               .mixers = { alc883_vaiott_mixer },
+               .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+               .channel_mode = alc883_3ST_2ch_modes,
+               .input_mux = &alc883_capture_source,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .init_hook = alc883_vaiott_init_hook,
+       },
 };
 
 
@@ -9155,7 +9545,6 @@ static void alc883_auto_init_multi_out(struct hda_codec *codec)
        struct alc_spec *spec = codec->spec;
        int i;
 
-       alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
        for (i = 0; i <= HDA_SIDE; i++) {
                hda_nid_t nid = spec->autocfg.line_out_pins[i];
                int pin_type = get_pin_type(spec->autocfg.line_out_type);
@@ -9273,10 +9662,18 @@ static int patch_alc883(struct hda_codec *codec)
        board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
                                                  alc883_models,
                                                  alc883_cfg_tbl);
-       if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: Unknown model for ALC883, "
-                      "trying auto-probe from BIOS...\n");
-               board_config = ALC883_AUTO;
+       if (board_config < 0 || board_config >= ALC883_MODEL_LAST) {
+               /* Pick up systems that don't supply PCI SSID */
+               switch (codec->subsystem_id) {
+               case 0x106b3600: /* Macbook 3.1 */
+                       board_config = ALC889A_MB31;
+                       break;
+               default:
+                       printk(KERN_INFO
+                               "hda_codec: Unknown model for %s, trying "
+                               "auto-probe from BIOS...\n", codec->chip_name);
+                       board_config = ALC883_AUTO;
+               }
        }
 
        if (board_config == ALC883_AUTO) {
@@ -9304,13 +9701,6 @@ static int patch_alc883(struct hda_codec *codec)
 
        switch (codec->vendor_id) {
        case 0x10ec0888:
-               if (codec->revision_id == 0x100101) {
-                       spec->stream_name_analog = "ALC1200 Analog";
-                       spec->stream_name_digital = "ALC1200 Digital";
-               } else {
-                       spec->stream_name_analog = "ALC888 Analog";
-                       spec->stream_name_digital = "ALC888 Digital";
-               }
                if (!spec->num_adc_nids) {
                        spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
                        spec->adc_nids = alc883_adc_nids;
@@ -9318,10 +9708,9 @@ static int patch_alc883(struct hda_codec *codec)
                if (!spec->capsrc_nids)
                        spec->capsrc_nids = alc883_capsrc_nids;
                spec->capture_style = CAPT_MIX; /* matrix-style capture */
+               spec->init_amp = ALC_INIT_DEFAULT; /* always initialize */
                break;
        case 0x10ec0889:
-               spec->stream_name_analog = "ALC889 Analog";
-               spec->stream_name_digital = "ALC889 Digital";
                if (!spec->num_adc_nids) {
                        spec->num_adc_nids = ARRAY_SIZE(alc889_adc_nids);
                        spec->adc_nids = alc889_adc_nids;
@@ -9332,8 +9721,6 @@ static int patch_alc883(struct hda_codec *codec)
                                                        capture */
                break;
        default:
-               spec->stream_name_analog = "ALC883 Analog";
-               spec->stream_name_digital = "ALC883 Digital";
                if (!spec->num_adc_nids) {
                        spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
                        spec->adc_nids = alc883_adc_nids;
@@ -9413,24 +9800,6 @@ static struct snd_kcontrol_new alc262_base_mixer[] = {
        { } /* end */
 };
 
-static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
-       /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
 /* update HP, line and mono-out pins according to the master switch */
 static void alc262_hp_master_update(struct hda_codec *codec)
 {
@@ -9486,14 +9855,7 @@ static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
        alc262_hp_wildwest_automute(codec);
 }
 
-static int alc262_hp_master_sw_get(struct snd_kcontrol *kcontrol,
-                                  struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct alc_spec *spec = codec->spec;
-       *ucontrol->value.integer.value = spec->master_sw;
-       return 0;
-}
+#define alc262_hp_master_sw_get                alc260_hp_master_sw_get
 
 static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
                                   struct snd_ctl_elem_value *ucontrol)
@@ -9509,14 +9871,17 @@ static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
        return 1;
 }
 
+#define ALC262_HP_MASTER_SWITCH                                        \
+       {                                                       \
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,            \
+               .name = "Master Playback Switch",               \
+               .info = snd_ctl_boolean_mono_info,              \
+               .get = alc262_hp_master_sw_get,                 \
+               .put = alc262_hp_master_sw_put,                 \
+       }
+
 static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Switch",
-               .info = snd_ctl_boolean_mono_info,
-               .get = alc262_hp_master_sw_get,
-               .put = alc262_hp_master_sw_put,
-       },
+       ALC262_HP_MASTER_SWITCH,
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
@@ -9540,13 +9905,7 @@ static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
 };
 
 static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Switch",
-               .info = snd_ctl_boolean_mono_info,
-               .get = alc262_hp_master_sw_get,
-               .put = alc262_hp_master_sw_put,
-       },
+       ALC262_HP_MASTER_SWITCH,
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -9573,32 +9932,13 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
 };
 
 /* mute/unmute internal speaker according to the hp jack and mute state */
-static void alc262_hp_t5735_automute(struct hda_codec *codec, int force)
+static void alc262_hp_t5735_init_hook(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
 
-       if (force || !spec->sense_updated) {
-               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->sense_updated = 1;
-       }
-       snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, HDA_AMP_MUTE,
-                                spec->jack_present ? HDA_AMP_MUTE : 0);
-}
-
-static void alc262_hp_t5735_unsol_event(struct hda_codec *codec,
-                                       unsigned int res)
-{
-       if ((res >> 26) != ALC880_HP_EVENT)
-               return;
-       alc262_hp_t5735_automute(codec, 1);
-}
-
-static void alc262_hp_t5735_init_hook(struct hda_codec *codec)
-{
-       alc262_hp_t5735_automute(codec, 1);
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x0c; /* HACK: not actually a pin */
+       alc_automute_amp(codec);
 }
 
 static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
@@ -9651,46 +9991,132 @@ static struct hda_input_mux alc262_hp_rp5700_capture_source = {
        },
 };
 
-/* bind hp and internal speaker mute (with plug check) */
-static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol,
-                                    struct snd_ctl_elem_value *ucontrol)
+/* bind hp and internal speaker mute (with plug check) as master switch */
+static void alc262_hippo_master_update(struct hda_codec *codec)
 {
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       long *valp = ucontrol->value.integer.value;
-       int change;
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
+       hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
+       hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
+       unsigned int mute;
 
-       /* change hp mute */
-       change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
-                                         HDA_AMP_MUTE,
-                                         valp[0] ? 0 : HDA_AMP_MUTE);
-       change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
-                                          HDA_AMP_MUTE,
-                                          valp[1] ? 0 : HDA_AMP_MUTE);
-       if (change) {
-               /* change speaker according to HP jack state */
-               struct alc_spec *spec = codec->spec;
-               unsigned int mute;
-               if (spec->jack_present)
-                       mute = HDA_AMP_MUTE;
-               else
-                       mute = snd_hda_codec_amp_read(codec, 0x15, 0,
-                                                     HDA_OUTPUT, 0);
-               snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+       /* HP */
+       mute = spec->master_sw ? 0 : HDA_AMP_MUTE;
+       snd_hda_codec_amp_stereo(codec, hp_nid, HDA_OUTPUT, 0,
+                                HDA_AMP_MUTE, mute);
+       /* mute internal speaker per jack sense */
+       if (spec->jack_present)
+               mute = HDA_AMP_MUTE;
+       if (line_nid)
+               snd_hda_codec_amp_stereo(codec, line_nid, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, mute);
+       if (speaker_nid && speaker_nid != line_nid)
+               snd_hda_codec_amp_stereo(codec, speaker_nid, HDA_OUTPUT, 0,
                                         HDA_AMP_MUTE, mute);
+}
+
+#define alc262_hippo_master_sw_get     alc262_hp_master_sw_get
+
+static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct alc_spec *spec = codec->spec;
+       int val = !!*ucontrol->value.integer.value;
+
+       if (val == spec->master_sw)
+               return 0;
+       spec->master_sw = val;
+       alc262_hippo_master_update(codec);
+       return 1;
+}
+
+#define ALC262_HIPPO_MASTER_SWITCH                             \
+       {                                                       \
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,            \
+               .name = "Master Playback Switch",               \
+               .info = snd_ctl_boolean_mono_info,              \
+               .get = alc262_hippo_master_sw_get,              \
+               .put = alc262_hippo_master_sw_put,              \
        }
-       return change;
+
+static struct snd_kcontrol_new alc262_hippo_mixer[] = {
+       ALC262_HIPPO_MASTER_SWITCH,
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       { } /* end */
+};
+
+static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       ALC262_HIPPO_MASTER_SWITCH,
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       { } /* end */
+};
+
+/* mute/unmute internal speaker according to the hp jack and mute state */
+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;
+       alc262_hippo_master_update(codec);
+}
+
+static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+       if ((res >> 26) != ALC880_HP_EVENT)
+               return;
+       alc262_hippo_automute(codec);
+}
+
+static void alc262_hippo_init_hook(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       alc262_hippo_automute(codec);
+}
+
+static void alc262_hippo1_init_hook(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       alc262_hippo_automute(codec);
 }
 
+
 static struct snd_kcontrol_new alc262_sony_mixer[] = {
        HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Switch",
-               .info = snd_hda_mixer_amp_switch_info,
-               .get = snd_hda_mixer_amp_switch_get,
-               .put = alc262_sony_master_sw_put,
-               .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
-       },
+       ALC262_HIPPO_MASTER_SWITCH,
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
@@ -9699,8 +10125,8 @@ static struct snd_kcontrol_new alc262_sony_mixer[] = {
 };
 
 static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       ALC262_HIPPO_MASTER_SWITCH,
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
@@ -9741,34 +10167,15 @@ static struct hda_verb alc262_tyan_verbs[] = {
 };
 
 /* unsolicited event for HP jack sensing */
-static void alc262_tyan_automute(struct hda_codec *codec)
+static void alc262_tyan_init_hook(struct hda_codec *codec)
 {
-       unsigned int mute;
-       unsigned int present;
+       struct alc_spec *spec = codec->spec;
 
-       snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
-       present = snd_hda_codec_read(codec, 0x1b, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0);
-       present = (present & 0x80000000) != 0;
-       if (present) {
-               /* mute line output on ATX panel */
-               snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-                                        HDA_AMP_MUTE, HDA_AMP_MUTE);
-       } else {
-               /* unmute line output if necessary */
-               mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
-               snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-                                        HDA_AMP_MUTE, mute);
-       }
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.speaker_pins[0] = 0x15;
+       alc_automute_amp(codec);
 }
 
-static void alc262_tyan_unsol_event(struct hda_codec *codec,
-                                      unsigned int res)
-{
-       if ((res >> 26) != ALC880_HP_EVENT)
-               return;
-       alc262_tyan_automute(codec);
-}
 
 #define alc262_capture_mixer           alc882_capture_mixer
 #define alc262_capture_alt_mixer       alc882_capture_alt_mixer
@@ -9920,102 +10327,28 @@ static void alc262_dmic_automute(struct hda_codec *codec)
        present = snd_hda_codec_read(codec, 0x18, 0,
                                        AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
        snd_hda_codec_write(codec, 0x22, 0,
-                               AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x09);
-}
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc262_toshiba_s06_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;
-       bits = present ? 0 : PIN_OUT;
-       snd_hda_codec_write(codec, 0x14, 0,
-                                       AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
+                               AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x09);
 }
 
 
-
 /* unsolicited event for HP jack sensing */
 static void alc262_toshiba_s06_unsol_event(struct hda_codec *codec,
                                       unsigned int res)
 {
-       if ((res >> 26) == ALC880_HP_EVENT)
-               alc262_toshiba_s06_speaker_automute(codec);
        if ((res >> 26) == ALC880_MIC_EVENT)
                alc262_dmic_automute(codec);
-
+       else
+               alc_sku_unsol_event(codec, res);
 }
 
 static void alc262_toshiba_s06_init_hook(struct hda_codec *codec)
-{
-       alc262_toshiba_s06_speaker_automute(codec);
-       alc262_dmic_automute(codec);
-}
-
-/* mute/unmute internal speaker according to the hp jack and mute state */
-static void alc262_hippo_automute(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       unsigned int mute;
-       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 & 0x80000000) != 0;
-       if (spec->jack_present) {
-               /* mute internal speaker */
-               snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-                                        HDA_AMP_MUTE, HDA_AMP_MUTE);
-       } else {
-               /* unmute internal speaker if necessary */
-               mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
-               snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-                                        HDA_AMP_MUTE, mute);
-       }
-}
-
-/* unsolicited event for HP jack sensing */
-static void alc262_hippo_unsol_event(struct hda_codec *codec,
-                                      unsigned int res)
-{
-       if ((res >> 26) != ALC880_HP_EVENT)
-               return;
-       alc262_hippo_automute(codec);
-}
-
-static void alc262_hippo1_automute(struct hda_codec *codec)
-{
-       unsigned int mute;
-       unsigned int present;
-
-       snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
-       present = snd_hda_codec_read(codec, 0x1b, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0);
-       present = (present & 0x80000000) != 0;
-       if (present) {
-               /* mute internal speaker */
-               snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-                                        HDA_AMP_MUTE, HDA_AMP_MUTE);
-       } else {
-               /* unmute internal speaker if necessary */
-               mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
-               snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-                                        HDA_AMP_MUTE, mute);
-       }
-}
 
-/* unsolicited event for HP jack sensing */
-static void alc262_hippo1_unsol_event(struct hda_codec *codec,
-                                      unsigned int res)
-{
-       if ((res >> 26) != ALC880_HP_EVENT)
-               return;
-       alc262_hippo1_automute(codec);
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       alc_automute_pin(codec);
+       alc262_dmic_automute(codec);
 }
 
 /*
@@ -10285,14 +10618,7 @@ static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
 
 static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
        HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Switch",
-               .info = snd_hda_mixer_amp_switch_info,
-               .get = snd_hda_mixer_amp_switch_get,
-               .put = alc262_sony_master_sw_put,
-               .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
-       },
+       ALC262_HIPPO_MASTER_SWITCH,
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
@@ -10639,31 +10965,46 @@ static struct hda_verb alc262_HP_BPC_init_verbs[] = {
        {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
        {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
 
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
        {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
         {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
        {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
        {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
 
 
        /* FIXME: use matrix-type input source selection */
-       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
-       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */
+       /* Input mixer1: only unmute Mic */
        {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
        /* Input mixer2 */
        {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
        /* Input mixer3 */
        {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
 
        {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
 
@@ -10843,6 +11184,8 @@ static int alc262_parse_auto_config(struct hda_codec *codec)
        if (err < 0)
                return err;
 
+       alc_ssid_check(codec, 0x15, 0x14, 0x1b);
+
        return 1;
 }
 
@@ -10945,7 +11288,7 @@ static struct alc_config_preset alc262_presets[] = {
                .input_mux = &alc262_capture_source,
        },
        [ALC262_HIPPO] = {
-               .mixers = { alc262_base_mixer },
+               .mixers = { alc262_hippo_mixer },
                .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs},
                .num_dacs = ARRAY_SIZE(alc262_dac_nids),
                .dac_nids = alc262_dac_nids,
@@ -10955,7 +11298,7 @@ static struct alc_config_preset alc262_presets[] = {
                .channel_mode = alc262_modes,
                .input_mux = &alc262_capture_source,
                .unsol_event = alc262_hippo_unsol_event,
-               .init_hook = alc262_hippo_automute,
+               .init_hook = alc262_hippo_init_hook,
        },
        [ALC262_HIPPO_1] = {
                .mixers = { alc262_hippo1_mixer },
@@ -10967,8 +11310,8 @@ static struct alc_config_preset alc262_presets[] = {
                .num_channel_mode = ARRAY_SIZE(alc262_modes),
                .channel_mode = alc262_modes,
                .input_mux = &alc262_capture_source,
-               .unsol_event = alc262_hippo1_unsol_event,
-               .init_hook = alc262_hippo1_automute,
+               .unsol_event = alc262_hippo_unsol_event,
+               .init_hook = alc262_hippo1_init_hook,
        },
        [ALC262_FUJITSU] = {
                .mixers = { alc262_fujitsu_mixer },
@@ -11030,7 +11373,7 @@ static struct alc_config_preset alc262_presets[] = {
                .num_channel_mode = ARRAY_SIZE(alc262_modes),
                .channel_mode = alc262_modes,
                .input_mux = &alc262_capture_source,
-               .unsol_event = alc262_hp_t5735_unsol_event,
+               .unsol_event = alc_automute_amp_unsol_event,
                .init_hook = alc262_hp_t5735_init_hook,
        },
        [ALC262_HP_RP5700] = {
@@ -11062,7 +11405,7 @@ static struct alc_config_preset alc262_presets[] = {
                .channel_mode = alc262_modes,
                .input_mux = &alc262_capture_source,
                .unsol_event = alc262_hippo_unsol_event,
-               .init_hook = alc262_hippo_automute,
+               .init_hook = alc262_hippo_init_hook,
        },
        [ALC262_BENQ_T31] = {
                .mixers = { alc262_benq_t31_mixer },
@@ -11074,7 +11417,7 @@ static struct alc_config_preset alc262_presets[] = {
                .channel_mode = alc262_modes,
                .input_mux = &alc262_capture_source,
                .unsol_event = alc262_hippo_unsol_event,
-               .init_hook = alc262_hippo_automute,
+               .init_hook = alc262_hippo_init_hook,
        },
        [ALC262_ULTRA] = {
                .mixers = { alc262_ultra_mixer },
@@ -11139,7 +11482,7 @@ static struct alc_config_preset alc262_presets[] = {
                .channel_mode = alc262_modes,
                .input_mux = &alc262_capture_source,
                .unsol_event = alc262_hippo_unsol_event,
-               .init_hook = alc262_hippo_automute,
+               .init_hook = alc262_hippo_init_hook,
        },
        [ALC262_TYAN] = {
                .mixers = { alc262_tyan_mixer },
@@ -11151,8 +11494,8 @@ static struct alc_config_preset alc262_presets[] = {
                .num_channel_mode = ARRAY_SIZE(alc262_modes),
                .channel_mode = alc262_modes,
                .input_mux = &alc262_capture_source,
-               .unsol_event = alc262_tyan_unsol_event,
-               .init_hook = alc262_tyan_automute,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .init_hook = alc262_tyan_init_hook,
        },
 };
 
@@ -11187,8 +11530,8 @@ static int patch_alc262(struct hda_codec *codec)
                                                  alc262_cfg_tbl);
 
        if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: Unknown model for ALC262, "
-                      "trying auto-probe from BIOS...\n");
+               printk(KERN_INFO "hda_codec: Unknown model for %s, "
+                      "trying auto-probe from BIOS...\n", codec->chip_name);
                board_config = ALC262_AUTO;
        }
 
@@ -11217,11 +11560,9 @@ static int patch_alc262(struct hda_codec *codec)
        if (board_config != ALC262_AUTO)
                setup_preset(spec, &alc262_presets[board_config]);
 
-       spec->stream_name_analog = "ALC262 Analog";
        spec->stream_analog_playback = &alc262_pcm_analog_playback;
        spec->stream_analog_capture = &alc262_pcm_analog_capture;
 
-       spec->stream_name_digital = "ALC262 Digital";
        spec->stream_digital_playback = &alc262_pcm_digital_playback;
        spec->stream_digital_capture = &alc262_pcm_digital_capture;
 
@@ -11296,6 +11637,17 @@ static struct snd_kcontrol_new alc268_base_mixer[] = {
        { }
 };
 
+static struct snd_kcontrol_new alc268_toshiba_mixer[] = {
+       /* output mixer control */
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
+       ALC262_HIPPO_MASTER_SWITCH,
+       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
+       { }
+};
+
 /* bind Beep switches of both NID 0x0f and 0x10 */
 static struct hda_bind_ctls alc268_bind_beep_sw = {
        .ops = &snd_hda_bind_sw,
@@ -11319,8 +11671,6 @@ static struct hda_verb alc268_eapd_verbs[] = {
 };
 
 /* Toshiba specific */
-#define alc268_toshiba_automute        alc262_hippo_automute
-
 static struct hda_verb alc268_toshiba_verbs[] = {
        {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
        { } /* end */
@@ -11456,13 +11806,8 @@ static struct hda_verb alc268_acer_verbs[] = {
 };
 
 /* unsolicited event for HP jack sensing */
-static void alc268_toshiba_unsol_event(struct hda_codec *codec,
-                                      unsigned int res)
-{
-       if ((res >> 26) != ALC880_HP_EVENT)
-               return;
-       alc268_toshiba_automute(codec);
-}
+#define alc268_toshiba_unsol_event     alc262_hippo_unsol_event
+#define alc268_toshiba_init_hook       alc262_hippo_init_hook
 
 static void alc268_acer_unsol_event(struct hda_codec *codec,
                                       unsigned int res)
@@ -11537,30 +11882,15 @@ static struct hda_verb alc268_dell_verbs[] = {
 };
 
 /* mute/unmute internal speaker according to the hp jack and mute state */
-static void alc268_dell_automute(struct hda_codec *codec)
+static void alc268_dell_init_hook(struct hda_codec *codec)
 {
-       unsigned int present;
-       unsigned int mute;
-
-       present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0);
-       if (present & 0x80000000)
-               mute = HDA_AMP_MUTE;
-       else
-               mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
-       snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, mute);
-}
+       struct alc_spec *spec = codec->spec;
 
-static void alc268_dell_unsol_event(struct hda_codec *codec,
-                                   unsigned int res)
-{
-       if ((res >> 26) != ALC880_HP_EVENT)
-               return;
-       alc268_dell_automute(codec);
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       alc_automute_pin(codec);
 }
 
-#define alc268_dell_init_hook  alc268_dell_automute
-
 static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
        HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
@@ -11579,16 +11909,6 @@ static struct hda_verb alc267_quanta_il1_verbs[] = {
        { }
 };
 
-static void alc267_quanta_il1_hp_automute(struct hda_codec *codec)
-{
-       unsigned int present;
-
-       present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
-               & AC_PINSENSE_PRESENCE;
-       snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                           present ? 0 : PIN_OUT);
-}
-
 static void alc267_quanta_il1_mic_automute(struct hda_codec *codec)
 {
        unsigned int present;
@@ -11600,9 +11920,13 @@ static void alc267_quanta_il1_mic_automute(struct hda_codec *codec)
                            present ? 0x00 : 0x01);
 }
 
-static void alc267_quanta_il1_automute(struct hda_codec *codec)
+static void alc267_quanta_il1_init_hook(struct hda_codec *codec)
 {
-       alc267_quanta_il1_hp_automute(codec);
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       alc_automute_pin(codec);
        alc267_quanta_il1_mic_automute(codec);
 }
 
@@ -11610,12 +11934,12 @@ static void alc267_quanta_il1_unsol_event(struct hda_codec *codec,
                                           unsigned int res)
 {
        switch (res >> 26) {
-       case ALC880_HP_EVENT:
-               alc267_quanta_il1_hp_automute(codec);
-               break;
        case ALC880_MIC_EVENT:
                alc267_quanta_il1_mic_automute(codec);
                break;
+       default:
+               alc_sku_unsol_event(codec, res);
+               break;
        }
 }
 
@@ -12063,16 +12387,16 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = {
                                                ALC268_ACER_ASPIRE_ONE),
        SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
        SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron Mini9", ALC268_DELL),
-       SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA),
-       SND_PCI_QUIRK(0x103c, 0x30f1, "HP TX25xx series", ALC268_TOSHIBA),
+       SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
+                          ALC268_TOSHIBA),
        SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
-       SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
-       SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA),
-       SND_PCI_QUIRK(0x1179, 0xff64, "TOSHIBA L305", ALC268_TOSHIBA),
+       SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
+       SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
+                          ALC268_TOSHIBA),
        SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
        SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
        SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
-       SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
+       SND_PCI_QUIRK(0x1854, 0x1775, "LG R510", ALC268_DELL),
        {}
 };
 
@@ -12090,7 +12414,7 @@ static struct alc_config_preset alc268_presets[] = {
                .channel_mode = alc268_modes,
                .input_mux = &alc268_capture_source,
                .unsol_event = alc267_quanta_il1_unsol_event,
-               .init_hook = alc267_quanta_il1_automute,
+               .init_hook = alc267_quanta_il1_init_hook,
        },
        [ALC268_3ST] = {
                .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
@@ -12108,7 +12432,7 @@ static struct alc_config_preset alc268_presets[] = {
                .input_mux = &alc268_capture_source,
        },
        [ALC268_TOSHIBA] = {
-               .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
+               .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
                            alc268_beep_mixer },
                .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
                                alc268_toshiba_verbs },
@@ -12122,7 +12446,7 @@ static struct alc_config_preset alc268_presets[] = {
                .channel_mode = alc268_modes,
                .input_mux = &alc268_capture_source,
                .unsol_event = alc268_toshiba_unsol_event,
-               .init_hook = alc268_toshiba_automute,
+               .init_hook = alc268_toshiba_init_hook,
        },
        [ALC268_ACER] = {
                .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
@@ -12185,7 +12509,7 @@ static struct alc_config_preset alc268_presets[] = {
                .hp_nid = 0x02,
                .num_channel_mode = ARRAY_SIZE(alc268_modes),
                .channel_mode = alc268_modes,
-               .unsol_event = alc268_dell_unsol_event,
+               .unsol_event = alc_sku_unsol_event,
                .init_hook = alc268_dell_init_hook,
                .input_mux = &alc268_capture_source,
        },
@@ -12205,7 +12529,7 @@ static struct alc_config_preset alc268_presets[] = {
                .channel_mode = alc268_modes,
                .input_mux = &alc268_capture_source,
                .unsol_event = alc268_toshiba_unsol_event,
-               .init_hook = alc268_toshiba_automute
+               .init_hook = alc268_toshiba_init_hook
        },
 #ifdef CONFIG_SND_DEBUG
        [ALC268_TEST] = {
@@ -12243,8 +12567,8 @@ static int patch_alc268(struct hda_codec *codec)
                                                  alc268_cfg_tbl);
 
        if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
-               printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
-                      "trying auto-probe from BIOS...\n");
+               printk(KERN_INFO "hda_codec: Unknown model for %s, "
+                      "trying auto-probe from BIOS...\n", codec->chip_name);
                board_config = ALC268_AUTO;
        }
 
@@ -12265,14 +12589,6 @@ static int patch_alc268(struct hda_codec *codec)
        if (board_config != ALC268_AUTO)
                setup_preset(spec, &alc268_presets[board_config]);
 
-       if (codec->vendor_id == 0x10ec0267) {
-               spec->stream_name_analog = "ALC267 Analog";
-               spec->stream_name_digital = "ALC267 Digital";
-       } else {
-               spec->stream_name_analog = "ALC268 Analog";
-               spec->stream_name_digital = "ALC268 Digital";
-       }
-
        spec->stream_analog_playback = &alc268_pcm_analog_playback;
        spec->stream_analog_capture = &alc268_pcm_analog_capture;
        spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
@@ -13099,8 +13415,8 @@ static int patch_alc269(struct hda_codec *codec)
                                                  alc269_cfg_tbl);
 
        if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: Unknown model for ALC269, "
-                      "trying auto-probe from BIOS...\n");
+               printk(KERN_INFO "hda_codec: Unknown model for %s, "
+                      "trying auto-probe from BIOS...\n", codec->chip_name);
                board_config = ALC269_AUTO;
        }
 
@@ -13127,7 +13443,6 @@ static int patch_alc269(struct hda_codec *codec)
        if (board_config != ALC269_AUTO)
                setup_preset(spec, &alc269_presets[board_config]);
 
-       spec->stream_name_analog = "ALC269 Analog";
        if (codec->subsystem_id == 0x17aa3bf8) {
                /* Due to a hardware problem on Lenovo Ideadpad, we need to
                 * fix the sample rate of analog I/O to 44.1kHz
@@ -13138,7 +13453,6 @@ static int patch_alc269(struct hda_codec *codec)
                spec->stream_analog_playback = &alc269_pcm_analog_playback;
                spec->stream_analog_capture = &alc269_pcm_analog_capture;
        }
-       spec->stream_name_digital = "ALC269 Digital";
        spec->stream_digital_playback = &alc269_pcm_digital_playback;
        spec->stream_digital_capture = &alc269_pcm_digital_capture;
 
@@ -13927,7 +14241,6 @@ static void alc861_auto_init_multi_out(struct hda_codec *codec)
        struct alc_spec *spec = codec->spec;
        int i;
 
-       alc_subsystem_id(codec, 0x0e, 0x0f, 0x0b);
        for (i = 0; i < spec->autocfg.line_outs; i++) {
                hda_nid_t nid = spec->autocfg.line_out_pins[i];
                int pin_type = get_pin_type(spec->autocfg.line_out_type);
@@ -14010,6 +14323,8 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
        spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
        set_capture_mixer(spec);
 
+       alc_ssid_check(codec, 0x0e, 0x0f, 0x0b);
+
        return 1;
 }
 
@@ -14199,8 +14514,8 @@ static int patch_alc861(struct hda_codec *codec)
                                                  alc861_cfg_tbl);
 
        if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: Unknown model for ALC861, "
-                      "trying auto-probe from BIOS...\n");
+               printk(KERN_INFO "hda_codec: Unknown model for %s, "
+                      "trying auto-probe from BIOS...\n", codec->chip_name);
                board_config = ALC861_AUTO;
        }
 
@@ -14227,11 +14542,9 @@ static int patch_alc861(struct hda_codec *codec)
        if (board_config != ALC861_AUTO)
                setup_preset(spec, &alc861_presets[board_config]);
 
-       spec->stream_name_analog = "ALC861 Analog";
        spec->stream_analog_playback = &alc861_pcm_analog_playback;
        spec->stream_analog_capture = &alc861_pcm_analog_capture;
 
-       spec->stream_name_digital = "ALC861 Digital";
        spec->stream_digital_playback = &alc861_pcm_digital_playback;
        spec->stream_digital_capture = &alc861_pcm_digital_capture;
 
@@ -14618,19 +14931,6 @@ static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
        {}
 };
 
-/* toggle speaker-output according to the hp-jack state */
-static void alc861vd_lenovo_hp_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;
-       bits = present ? HDA_AMP_MUTE : 0;
-       snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, bits);
-}
-
 static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
 {
        unsigned int present;
@@ -14643,9 +14943,13 @@ static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
                                 HDA_AMP_MUTE, bits);
 }
 
-static void alc861vd_lenovo_automute(struct hda_codec *codec)
+static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
 {
-       alc861vd_lenovo_hp_automute(codec);
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x1b;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       alc_automute_amp(codec);
        alc861vd_lenovo_mic_automute(codec);
 }
 
@@ -14653,12 +14957,12 @@ static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
                                        unsigned int res)
 {
        switch (res >> 26) {
-       case ALC880_HP_EVENT:
-               alc861vd_lenovo_hp_automute(codec);
-               break;
        case ALC880_MIC_EVENT:
                alc861vd_lenovo_mic_automute(codec);
                break;
+       default:
+               alc_automute_amp_unsol_event(codec, res);
+               break;
        }
 }
 
@@ -14708,20 +15012,13 @@ static struct hda_verb alc861vd_dallas_verbs[] = {
 };
 
 /* toggle speaker-output according to the hp-jack state */
-static void alc861vd_dallas_automute(struct hda_codec *codec)
+static void alc861vd_dallas_init_hook(struct hda_codec *codec)
 {
-       unsigned int present;
-
-       present = snd_hda_codec_read(codec, 0x15, 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);
-}
+       struct alc_spec *spec = codec->spec;
 
-static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       if ((res >> 26) == ALC880_HP_EVENT)
-               alc861vd_dallas_automute(codec);
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       alc_automute_amp(codec);
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -14835,7 +15132,7 @@ static struct alc_config_preset alc861vd_presets[] = {
                .channel_mode = alc861vd_3stack_2ch_modes,
                .input_mux = &alc861vd_capture_source,
                .unsol_event = alc861vd_lenovo_unsol_event,
-               .init_hook = alc861vd_lenovo_automute,
+               .init_hook = alc861vd_lenovo_init_hook,
        },
        [ALC861VD_DALLAS] = {
                .mixers = { alc861vd_dallas_mixer },
@@ -14845,8 +15142,8 @@ static struct alc_config_preset alc861vd_presets[] = {
                .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
                .channel_mode = alc861vd_3stack_2ch_modes,
                .input_mux = &alc861vd_dallas_capture_source,
-               .unsol_event = alc861vd_dallas_unsol_event,
-               .init_hook = alc861vd_dallas_automute,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .init_hook = alc861vd_dallas_init_hook,
        },
        [ALC861VD_HP] = {
                .mixers = { alc861vd_hp_mixer },
@@ -14857,8 +15154,8 @@ static struct alc_config_preset alc861vd_presets[] = {
                .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
                .channel_mode = alc861vd_3stack_2ch_modes,
                .input_mux = &alc861vd_hp_capture_source,
-               .unsol_event = alc861vd_dallas_unsol_event,
-               .init_hook = alc861vd_dallas_automute,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .init_hook = alc861vd_dallas_init_hook,
        },
        [ALC660VD_ASUS_V1S] = {
                .mixers = { alc861vd_lenovo_mixer },
@@ -14873,7 +15170,7 @@ static struct alc_config_preset alc861vd_presets[] = {
                .channel_mode = alc861vd_3stack_2ch_modes,
                .input_mux = &alc861vd_capture_source,
                .unsol_event = alc861vd_lenovo_unsol_event,
-               .init_hook = alc861vd_lenovo_automute,
+               .init_hook = alc861vd_lenovo_init_hook,
        },
 };
 
@@ -14891,7 +15188,6 @@ static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
        struct alc_spec *spec = codec->spec;
        int i;
 
-       alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
        for (i = 0; i <= HDA_SIDE; i++) {
                hda_nid_t nid = spec->autocfg.line_out_pins[i];
                int pin_type = get_pin_type(spec->autocfg.line_out_type);
@@ -15109,6 +15405,8 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec)
        if (err < 0)
                return err;
 
+       alc_ssid_check(codec, 0x15, 0x1b, 0x14);
+
        return 1;
 }
 
@@ -15140,8 +15438,8 @@ static int patch_alc861vd(struct hda_codec *codec)
                                                  alc861vd_cfg_tbl);
 
        if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
-               printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/"
-                       "ALC861VD, trying auto-probe from BIOS...\n");
+               printk(KERN_INFO "hda_codec: Unknown model for %s, "
+                      "trying auto-probe from BIOS...\n", codec->chip_name);
                board_config = ALC861VD_AUTO;
        }
 
@@ -15169,13 +15467,8 @@ static int patch_alc861vd(struct hda_codec *codec)
                setup_preset(spec, &alc861vd_presets[board_config]);
 
        if (codec->vendor_id == 0x10ec0660) {
-               spec->stream_name_analog = "ALC660-VD Analog";
-               spec->stream_name_digital = "ALC660-VD Digital";
                /* always turn on EAPD */
                add_verb(spec, alc660vd_eapd_verbs);
-       } else {
-               spec->stream_name_analog = "ALC861VD Analog";
-               spec->stream_name_digital = "ALC861VD Digital";
        }
 
        spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
@@ -15289,6 +15582,38 @@ static struct hda_input_mux alc663_m51va_capture_source = {
        },
 };
 
+#if 1 /* set to 0 for testing other input sources below */
+static struct hda_input_mux alc272_nc10_capture_source = {
+       .num_items = 2,
+       .items = {
+               { "Autoselect Mic", 0x0 },
+               { "Internal Mic", 0x1 },
+       },
+};
+#else
+static struct hda_input_mux alc272_nc10_capture_source = {
+       .num_items = 16,
+       .items = {
+               { "Autoselect Mic", 0x0 },
+               { "Internal Mic", 0x1 },
+               { "In-0x02", 0x2 },
+               { "In-0x03", 0x3 },
+               { "In-0x04", 0x4 },
+               { "In-0x05", 0x5 },
+               { "In-0x06", 0x6 },
+               { "In-0x07", 0x7 },
+               { "In-0x08", 0x8 },
+               { "In-0x09", 0x9 },
+               { "In-0x0a", 0x0a },
+               { "In-0x0b", 0x0b },
+               { "In-0x0c", 0x0c },
+               { "In-0x0d", 0x0d },
+               { "In-0x0e", 0x0e },
+               { "In-0x0f", 0x0f },
+       },
+};
+#endif
+
 /*
  * 2ch mode
  */
@@ -15428,10 +15753,8 @@ static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
 };
 
 static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Line-Out Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       ALC262_HIPPO_MASTER_SWITCH,
 
        HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
@@ -15444,15 +15767,11 @@ static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
 };
 
 static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
-       HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Line-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       ALC262_HIPPO_MASTER_SWITCH,
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
        HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
@@ -15960,51 +16279,25 @@ static void alc662_eeepc_mic_automute(struct hda_codec *codec)
 static void alc662_eeepc_unsol_event(struct hda_codec *codec,
                                     unsigned int res)
 {
-       if ((res >> 26) == ALC880_HP_EVENT)
-               alc262_hippo1_automute( codec );
-
        if ((res >> 26) == ALC880_MIC_EVENT)
                alc662_eeepc_mic_automute(codec);
+       else
+               alc262_hippo_unsol_event(codec, res);
 }
 
 static void alc662_eeepc_inithook(struct hda_codec *codec)
 {
-       alc262_hippo1_automute( codec );
+       alc262_hippo1_init_hook(codec);
        alc662_eeepc_mic_automute(codec);
 }
 
-static void alc662_eeepc_ep20_automute(struct hda_codec *codec)
-{
-       unsigned int mute;
-       unsigned int present;
-
-       snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
-       present = snd_hda_codec_read(codec, 0x14, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0);
-       present = (present & 0x80000000) != 0;
-       if (present) {
-               /* mute internal speaker */
-               snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
-                                       HDA_AMP_MUTE, HDA_AMP_MUTE);
-       } else {
-               /* unmute internal speaker if necessary */
-               mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
-               snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
-                                       HDA_AMP_MUTE, mute);
-       }
-}
-
-/* unsolicited event for HP jack sensing */
-static void alc662_eeepc_ep20_unsol_event(struct hda_codec *codec,
-                                         unsigned int res)
-{
-       if ((res >> 26) == ALC880_HP_EVENT)
-               alc662_eeepc_ep20_automute(codec);
-}
-
 static void alc662_eeepc_ep20_inithook(struct hda_codec *codec)
 {
-       alc662_eeepc_ep20_automute(codec);
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[0] = 0x1b;
+       alc262_hippo_master_update(codec);
 }
 
 static void alc663_m51va_speaker_automute(struct hda_codec *codec)
@@ -16338,35 +16631,9 @@ static void alc663_g50v_inithook(struct hda_codec *codec)
        alc662_eeepc_mic_automute(codec);
 }
 
-/* bind hp and internal speaker mute (with plug check) */
-static int alc662_ecs_master_sw_put(struct snd_kcontrol *kcontrol,
-                                    struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       long *valp = ucontrol->value.integer.value;
-       int change;
-
-       change = snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0,
-                                         HDA_AMP_MUTE,
-                                         valp[0] ? 0 : HDA_AMP_MUTE);
-       change |= snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0,
-                                          HDA_AMP_MUTE,
-                                          valp[1] ? 0 : HDA_AMP_MUTE);
-       if (change)
-               alc262_hippo1_automute(codec);
-       return change;
-}
-
 static struct snd_kcontrol_new alc662_ecs_mixer[] = {
        HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Switch",
-               .info = snd_hda_mixer_amp_switch_info,
-               .get = snd_hda_mixer_amp_switch_get,
-               .put = alc662_ecs_master_sw_put,
-               .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
-       },
+       ALC262_HIPPO_MASTER_SWITCH,
 
        HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
@@ -16378,6 +16645,23 @@ static struct snd_kcontrol_new alc662_ecs_mixer[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new alc272_nc10_mixer[] = {
+       /* Master Playback automatically created from Speaker and Headphone */
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+
+       HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
+       { } /* end */
+};
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #define alc662_loopbacks       alc880_loopbacks
 #endif
@@ -16411,6 +16695,9 @@ static const char *alc662_models[ALC662_MODEL_LAST] = {
        [ALC663_ASUS_MODE4] = "asus-mode4",
        [ALC663_ASUS_MODE5] = "asus-mode5",
        [ALC663_ASUS_MODE6] = "asus-mode6",
+       [ALC272_DELL]           = "dell",
+       [ALC272_DELL_ZM1]       = "dell-zm1",
+       [ALC272_SAMSUNG_NC10]   = "samsung-nc10",
        [ALC662_AUTO]           = "auto",
 };
 
@@ -16468,6 +16755,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = {
        SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
        SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
                      ALC662_3ST_6ch_DIG),
+       SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
        SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
                      ALC662_3ST_6ch_DIG),
        SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
@@ -16558,7 +16846,7 @@ static struct alc_config_preset alc662_presets[] = {
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
                .channel_mode = alc662_3ST_6ch_modes,
                .input_mux = &alc662_lenovo_101e_capture_source,
-               .unsol_event = alc662_eeepc_ep20_unsol_event,
+               .unsol_event = alc662_eeepc_unsol_event,
                .init_hook = alc662_eeepc_ep20_inithook,
        },
        [ALC662_ECS] = {
@@ -16739,6 +17027,18 @@ static struct alc_config_preset alc662_presets[] = {
                .unsol_event = alc663_m51va_unsol_event,
                .init_hook = alc663_m51va_inithook,
        },
+       [ALC272_SAMSUNG_NC10] = {
+               .mixers = { alc272_nc10_mixer },
+               .init_verbs = { alc662_init_verbs,
+                               alc663_21jd_amic_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc272_dac_nids),
+               .dac_nids = alc272_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .input_mux = &alc272_nc10_capture_source,
+               .unsol_event = alc663_mode4_unsol_event,
+               .init_hook = alc663_mode4_inithook,
+       },
 };
 
 
@@ -16933,7 +17233,6 @@ static void alc662_auto_init_multi_out(struct hda_codec *codec)
        struct alc_spec *spec = codec->spec;
        int i;
 
-       alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
        for (i = 0; i <= HDA_SIDE; i++) {
                hda_nid_t nid = spec->autocfg.line_out_pins[i];
                int pin_type = get_pin_type(spec->autocfg.line_out_type);
@@ -17030,6 +17329,8 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
        if (err < 0)
                return err;
 
+       alc_ssid_check(codec, 0x15, 0x1b, 0x14);
+
        return 1;
 }
 
@@ -17062,8 +17363,8 @@ static int patch_alc662(struct hda_codec *codec)
                                                  alc662_models,
                                                  alc662_cfg_tbl);
        if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: Unknown model for ALC662, "
-                      "trying auto-probe from BIOS...\n");
+               printk(KERN_INFO "hda_codec: Unknown model for %s, "
+                      "trying auto-probe from BIOS...\n", codec->chip_name);
                board_config = ALC662_AUTO;
        }
 
@@ -17090,17 +17391,6 @@ static int patch_alc662(struct hda_codec *codec)
        if (board_config != ALC662_AUTO)
                setup_preset(spec, &alc662_presets[board_config]);
 
-       if (codec->vendor_id == 0x10ec0663) {
-               spec->stream_name_analog = "ALC663 Analog";
-               spec->stream_name_digital = "ALC663 Digital";
-       } else if (codec->vendor_id == 0x10ec0272) {
-               spec->stream_name_analog = "ALC272 Analog";
-               spec->stream_name_digital = "ALC272 Digital";
-       } else {
-               spec->stream_name_analog = "ALC662 Analog";
-               spec->stream_name_digital = "ALC662 Digital";
-       }
-
        spec->stream_analog_playback = &alc662_pcm_analog_playback;
        spec->stream_analog_capture = &alc662_pcm_analog_capture;
 
index d2fd8ef6aef846b9c3bf13093348c7d11733b1e3..93e47c96a38bce1800a9df2dbfff5aaa85fd7b47 100644 (file)
@@ -100,6 +100,7 @@ enum {
        STAC_HP_M4,
        STAC_HP_DV5,
        STAC_HP_HDX,
+       STAC_HP_DV4_1222NR,
        STAC_92HD71BXX_MODELS
 };
 
@@ -193,6 +194,7 @@ struct sigmatel_spec {
        unsigned int gpio_dir;
        unsigned int gpio_data;
        unsigned int gpio_mute;
+       unsigned int gpio_led;
 
        /* stream */
        unsigned int stream_delay;
@@ -634,6 +636,40 @@ static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
+static unsigned int stac92xx_vref_set(struct hda_codec *codec,
+                                       hda_nid_t nid, unsigned int new_vref)
+{
+       unsigned int error;
+       unsigned int pincfg;
+       pincfg = snd_hda_codec_read(codec, nid, 0,
+                               AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+
+       pincfg &= 0xff;
+       pincfg &= ~(AC_PINCTL_VREFEN | AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
+       pincfg |= new_vref;
+
+       if (new_vref == AC_PINCTL_VREF_HIZ)
+               pincfg |= AC_PINCTL_OUT_EN;
+       else
+               pincfg |= AC_PINCTL_IN_EN;
+
+       error = snd_hda_codec_write_cache(codec, nid, 0,
+                                       AC_VERB_SET_PIN_WIDGET_CONTROL, pincfg);
+       if (error < 0)
+               return error;
+       else
+               return 1;
+}
+
+static unsigned int stac92xx_vref_get(struct hda_codec *codec, hda_nid_t nid)
+{
+       unsigned int vref;
+       vref = snd_hda_codec_read(codec, nid, 0,
+                               AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+       vref &= AC_PINCTL_VREFEN;
+       return vref;
+}
+
 static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
@@ -995,6 +1031,17 @@ static struct hda_verb stac9205_core_init[] = {
                .private_value = verb_read | (verb_write << 16), \
        }
 
+#define DC_BIAS(xname, idx, nid) \
+       { \
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+               .name = xname, \
+               .index = idx, \
+               .info = stac92xx_dc_bias_info, \
+               .get = stac92xx_dc_bias_get, \
+               .put = stac92xx_dc_bias_put, \
+               .private_value = nid, \
+       }
+
 static struct snd_kcontrol_new stac9200_mixer[] = {
        HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
@@ -1543,6 +1590,8 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
                      "DFI LanParty", STAC_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xfb30,
+                     "SigmaTel",STAC_9205_REF),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
                      "DFI LanParty", STAC_REF),
        /* Dell laptops have BIOS problem */
@@ -1837,6 +1886,7 @@ static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
        [STAC_HP_M4]            = NULL,
        [STAC_HP_DV5]           = NULL,
        [STAC_HP_HDX]           = NULL,
+       [STAC_HP_DV4_1222NR]    = NULL,
 };
 
 static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
@@ -1848,6 +1898,7 @@ static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
        [STAC_HP_M4] = "hp-m4",
        [STAC_HP_DV5] = "hp-dv5",
        [STAC_HP_HDX] = "hp-hdx",
+       [STAC_HP_DV4_1222NR] = "hp-dv4-1222nr",
 };
 
 static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
@@ -1856,6 +1907,8 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
                      "DFI LanParty", STAC_92HD71BXX_REF),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
                      "DFI LanParty", STAC_92HD71BXX_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fb,
+                     "HP dv4-1222nr", STAC_HP_DV4_1222NR),
        SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3080,
                      "HP", STAC_HP_DV5),
        SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x30f0,
@@ -2545,7 +2598,8 @@ static int stac92xx_build_pcms(struct hda_codec *codec)
        return 0;
 }
 
-static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
+static unsigned int stac92xx_get_default_vref(struct hda_codec *codec,
+                                       hda_nid_t nid)
 {
        unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
        pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
@@ -2599,15 +2653,108 @@ static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
        return 1;
 }
 
-#define stac92xx_io_switch_info                snd_ctl_boolean_mono_info
+static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       int i;
+       static char *texts[] = {
+               "Mic In", "Line In", "Line Out"
+       };
+
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+       hda_nid_t nid = kcontrol->private_value;
+
+       if (nid == spec->mic_switch || nid == spec->line_switch)
+               i = 3;
+       else
+               i = 2;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->value.enumerated.items = i;
+       uinfo->count = 1;
+       if (uinfo->value.enumerated.item >= i)
+               uinfo->value.enumerated.item = i-1;
+       strcpy(uinfo->value.enumerated.name,
+               texts[uinfo->value.enumerated.item]);
+
+       return 0;
+}
+
+static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = kcontrol->private_value;
+       unsigned int vref = stac92xx_vref_get(codec, nid);
+
+       if (vref == stac92xx_get_default_vref(codec, nid))
+               ucontrol->value.enumerated.item[0] = 0;
+       else if (vref == AC_PINCTL_VREF_GRD)
+               ucontrol->value.enumerated.item[0] = 1;
+       else if (vref == AC_PINCTL_VREF_HIZ)
+               ucontrol->value.enumerated.item[0] = 2;
+
+       return 0;
+}
+
+static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int new_vref = 0;
+       unsigned int error;
+       hda_nid_t nid = kcontrol->private_value;
+
+       if (ucontrol->value.enumerated.item[0] == 0)
+               new_vref = stac92xx_get_default_vref(codec, nid);
+       else if (ucontrol->value.enumerated.item[0] == 1)
+               new_vref = AC_PINCTL_VREF_GRD;
+       else if (ucontrol->value.enumerated.item[0] == 2)
+               new_vref = AC_PINCTL_VREF_HIZ;
+       else
+               return 0;
+
+       if (new_vref != stac92xx_vref_get(codec, nid)) {
+               error = stac92xx_vref_set(codec, nid, new_vref);
+               return error;
+       }
+
+       return 0;
+}
+
+static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       static char *texts[2];
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (kcontrol->private_value == spec->line_switch)
+               texts[0] = "Line In";
+       else
+               texts[0] = "Mic In";
+       texts[1] = "Line Out";
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->value.enumerated.items = 2;
+       uinfo->count = 1;
+
+       if (uinfo->value.enumerated.item >= 2)
+               uinfo->value.enumerated.item = 1;
+       strcpy(uinfo->value.enumerated.name,
+               texts[uinfo->value.enumerated.item]);
+
+       return 0;
+}
 
 static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct sigmatel_spec *spec = codec->spec;
-       int io_idx = kcontrol-> private_value & 0xff;
+       hda_nid_t nid = kcontrol->private_value;
+       int io_idx = (nid == spec->mic_switch) ? 1 : 0;
 
-       ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
+       ucontrol->value.enumerated.item[0] = spec->io_switch[io_idx];
        return 0;
 }
 
@@ -2615,9 +2762,9 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
 {
         struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct sigmatel_spec *spec = codec->spec;
-        hda_nid_t nid = kcontrol->private_value >> 8;
-       int io_idx = kcontrol-> private_value & 0xff;
-       unsigned short val = !!ucontrol->value.integer.value[0];
+       hda_nid_t nid = kcontrol->private_value;
+       int io_idx = (nid == spec->mic_switch) ? 1 : 0;
+       unsigned short val = !!ucontrol->value.enumerated.item[0];
 
        spec->io_switch[io_idx] = val;
 
@@ -2626,7 +2773,7 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
        else {
                unsigned int pinctl = AC_PINCTL_IN_EN;
                if (io_idx) /* set VREF for mic */
-                       pinctl |= stac92xx_get_vref(codec, nid);
+                       pinctl |= stac92xx_get_default_vref(codec, nid);
                stac92xx_auto_set_pinctl(codec, nid, pinctl);
        }
 
@@ -2707,7 +2854,8 @@ enum {
        STAC_CTL_WIDGET_AMP_VOL,
        STAC_CTL_WIDGET_HP_SWITCH,
        STAC_CTL_WIDGET_IO_SWITCH,
-       STAC_CTL_WIDGET_CLFE_SWITCH
+       STAC_CTL_WIDGET_CLFE_SWITCH,
+       STAC_CTL_WIDGET_DC_BIAS
 };
 
 static struct snd_kcontrol_new stac92xx_control_templates[] = {
@@ -2719,6 +2867,7 @@ static struct snd_kcontrol_new stac92xx_control_templates[] = {
        STAC_CODEC_HP_SWITCH(NULL),
        STAC_CODEC_IO_SWITCH(NULL, 0),
        STAC_CODEC_CLFE_SWITCH(NULL, 0),
+       DC_BIAS(NULL, 0, 0),
 };
 
 /* add dynamic controls */
@@ -2782,6 +2931,34 @@ static struct snd_kcontrol_new stac_input_src_temp = {
        .put = stac92xx_mux_enum_put,
 };
 
+static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec,
+                                               hda_nid_t nid, int idx)
+{
+       int def_conf = snd_hda_codec_get_pincfg(codec, nid);
+       int control = 0;
+       struct sigmatel_spec *spec = codec->spec;
+       char name[22];
+
+       if (!((get_defcfg_connect(def_conf)) & AC_JACK_PORT_FIXED)) {
+               if (stac92xx_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD
+                       && nid == spec->line_switch)
+                       control = STAC_CTL_WIDGET_IO_SWITCH;
+               else if (snd_hda_query_pin_caps(codec, nid)
+                       & (AC_PINCAP_VREF_GRD << AC_PINCAP_VREF_SHIFT))
+                       control = STAC_CTL_WIDGET_DC_BIAS;
+               else if (nid == spec->mic_switch)
+                       control = STAC_CTL_WIDGET_IO_SWITCH;
+       }
+
+       if (control) {
+               strcpy(name, auto_pin_cfg_labels[idx]);
+               return stac92xx_add_control(codec->spec, control,
+                                       strcat(name, " Jack Mode"), nid);
+       }
+
+       return 0;
+}
+
 static int stac92xx_add_input_source(struct sigmatel_spec *spec)
 {
        struct snd_kcontrol_new *knew;
@@ -3144,7 +3321,9 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
                                               const struct auto_pin_cfg *cfg)
 {
        struct sigmatel_spec *spec = codec->spec;
+       hda_nid_t nid;
        int err;
+       int idx;
 
        err = create_multi_out_ctls(codec, cfg->line_outs, cfg->line_out_pins,
                                    spec->multiout.dac_nids,
@@ -3161,20 +3340,13 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
                        return err;
        }
 
-       if (spec->line_switch) {
-               err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH,
-                                          "Line In as Output Switch",
-                                          spec->line_switch << 8);
-               if (err < 0)
-                       return err;
-       }
-
-       if (spec->mic_switch) {
-               err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH,
-                                          "Mic as Output Switch",
-                                          (spec->mic_switch << 8) | 1);
-               if (err < 0)
-                       return err;
+       for (idx = AUTO_PIN_MIC; idx <= AUTO_PIN_FRONT_LINE; idx++) {
+               nid = cfg->input_pins[idx];
+               if (nid) {
+                       err = stac92xx_add_jack_mode_control(codec, nid, idx);
+                       if (err < 0)
+                               return err;
+               }
        }
 
        return 0;
@@ -3639,6 +3811,8 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
                err = snd_hda_attach_beep_device(codec, nid);
                if (err < 0)
                        return err;
+               /* IDT/STAC codecs have linear beep tone parameter */
+               codec->beep->linear_tone = 1;
                /* if no beep switch is available, make its own one */
                caps = query_amp_caps(codec, nid, HDA_OUTPUT);
                if (codec->beep &&
@@ -4082,7 +4256,7 @@ static int stac92xx_init(struct hda_codec *codec)
                        unsigned int pinctl, conf;
                        if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) {
                                /* for mic pins, force to initialize */
-                               pinctl = stac92xx_get_vref(codec, nid);
+                               pinctl = stac92xx_get_default_vref(codec, nid);
                                pinctl |= AC_PINCTL_IN_EN;
                                stac92xx_auto_set_pinctl(codec, nid, pinctl);
                        } else {
@@ -4535,17 +4709,19 @@ static int stac92xx_resume(struct hda_codec *codec)
        return 0;
 }
 
-
 /*
- * using power check for controlling mute led of HP HDX notebooks
+ * using power check for controlling mute led of HP notebooks
  * check for mute state only on Speakers (nid = 0x10)
  *
  * For this feature CONFIG_SND_HDA_POWER_SAVE is needed, otherwise
  * the LED is NOT working properly !
+ *
+ * Changed name to reflect that it now works for any designated
+ * model, not just HP HDX.
  */
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static int stac92xx_hp_hdx_check_power_status(struct hda_codec *codec,
+static int stac92xx_hp_check_power_status(struct hda_codec *codec,
                                              hda_nid_t nid)
 {
        struct sigmatel_spec *spec = codec->spec;
@@ -4553,9 +4729,9 @@ static int stac92xx_hp_hdx_check_power_status(struct hda_codec *codec,
        if (nid == 0x10) {
                if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) &
                    HDA_AMP_MUTE)
-                       spec->gpio_data &= ~0x08;  /* orange */
+                       spec->gpio_data &= ~spec->gpio_led; /* orange */
                else
-                       spec->gpio_data |= 0x08;   /* white */
+                       spec->gpio_data |= spec->gpio_led; /* white */
 
                stac_gpio_set(codec, spec->gpio_mask,
                              spec->gpio_dir,
@@ -5201,6 +5377,15 @@ again:
        if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP)
                snd_hda_sequence_write_cache(codec, unmute_init);
 
+       /* Some HP machines seem to have unstable codec communications
+        * especially with ATI fglrx driver.  For recovering from the
+        * CORB/RIRB stall, allow the BUS reset and keep always sync
+        */
+       if (spec->board_config == STAC_HP_DV5) {
+               codec->bus->sync_write = 1;
+               codec->bus->allow_bus_reset = 1;
+       }
+
        spec->aloopback_ctl = stac92hd71bxx_loopback;
        spec->aloopback_mask = 0x50;
        spec->aloopback_shift = 0;
@@ -5234,6 +5419,15 @@ again:
                spec->num_smuxes = 0;
                spec->num_dmuxes = 1;
                break;
+       case STAC_HP_DV4_1222NR:
+               spec->num_dmics = 1;
+               /* I don't know if it needs 1 or 2 smuxes - will wait for
+                * bug reports to fix if needed
+                */
+               spec->num_smuxes = 1;
+               spec->num_dmuxes = 1;
+               spec->gpio_led = 0x01;
+               /* fallthrough */
        case STAC_HP_DV5:
                snd_hda_codec_set_pincfg(codec, 0x0d, 0x90170010);
                stac92xx_auto_set_pinctl(codec, 0x0d, AC_PINCTL_OUT_EN);
@@ -5242,22 +5436,21 @@ again:
                spec->num_dmics = 1;
                spec->num_dmuxes = 1;
                spec->num_smuxes = 1;
-               /*
-                * For controlling MUTE LED on HP HDX16/HDX18 notebooks,
-                * the CONFIG_SND_HDA_POWER_SAVE is needed to be set.
-                */
-#ifdef CONFIG_SND_HDA_POWER_SAVE
                /* orange/white mute led on GPIO3, orange=0, white=1 */
-               spec->gpio_mask |= 0x08;
-               spec->gpio_dir  |= 0x08;
-               spec->gpio_data |= 0x08;  /* set to white */
+               spec->gpio_led = 0x08;
+               break;
+       }
 
+#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 =
-                   stac92xx_hp_hdx_check_power_status;
+                       stac92xx_hp_check_power_status;
+       }
 #endif 
-               break;
-       };
 
        spec->multiout.dac_nids = spec->dac_nids;
        if (spec->dinput_mux)
@@ -5282,7 +5475,7 @@ again:
        codec->proc_widget_hook = stac92hd7x_proc_hook;
 
        return 0;
-};
+}
 
 static int patch_stac922x(struct hda_codec *codec)
 {
@@ -5437,7 +5630,7 @@ static int patch_stac927x(struct hda_codec *codec)
                        /* correct the device field to SPDIF out */
                        snd_hda_codec_set_pincfg(codec, 0x21, 0x01442070);
                        break;
-               };
+               }
                /* configure the analog microphone on some laptops */
                snd_hda_codec_set_pincfg(codec, 0x0c, 0x90a79130);
                /* correct the front output jack as a hp out */
@@ -5747,6 +5940,7 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = {
        { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
        { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
        { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
+       { .id = 0x83847698, .name = "STAC9205", .patch = patch_stac9205 },
        { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
        { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
        { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
index b25a5cc637d6072cbbad235753d64ff6c12c3ff1..8e004fb6961add86847d11b2a128577488a7821b 100644 (file)
@@ -205,7 +205,7 @@ struct via_spec {
 
        /* playback */
        struct hda_multi_out multiout;
-       hda_nid_t extra_dig_out_nid;
+       hda_nid_t slave_dig_outs[2];
 
        /* capture */
        unsigned int num_adc_nids;
@@ -731,21 +731,6 @@ static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
        return snd_hda_multi_out_dig_close(codec, &spec->multiout);
 }
 
-/* setup SPDIF output stream */
-static void setup_dig_playback_stream(struct hda_codec *codec, hda_nid_t nid,
-                                unsigned int stream_tag, unsigned int format)
-{
-       /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
-       if (codec->spdif_ctls & AC_DIG1_ENABLE)
-               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
-                                   codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
-       snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
-       /* turn on again (if needed) */
-       if (codec->spdif_ctls & AC_DIG1_ENABLE)
-               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
-                                   codec->spdif_ctls & 0xff);
-}
-
 static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
                                        struct hda_codec *codec,
                                        unsigned int stream_tag,
@@ -753,19 +738,16 @@ static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
                                        struct snd_pcm_substream *substream)
 {
        struct via_spec *spec = codec->spec;
-       hda_nid_t nid;
-
-       /* 1st or 2nd S/PDIF */
-       if (substream->number == 0)
-               nid = spec->multiout.dig_out_nid;
-       else if (substream->number == 1)
-               nid = spec->extra_dig_out_nid;
-       else
-               return -1;
+       return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
+                                            stream_tag, format, substream);
+}
 
-       mutex_lock(&codec->spdif_mutex);
-       setup_dig_playback_stream(codec, nid, stream_tag, format);
-       mutex_unlock(&codec->spdif_mutex);
+static int via_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                       struct hda_codec *codec,
+                                       struct snd_pcm_substream *substream)
+{
+       struct via_spec *spec = codec->spec;
+       snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
        return 0;
 }
 
@@ -842,7 +824,8 @@ static struct hda_pcm_stream vt1708_pcm_digital_playback = {
        .ops = {
                .open = via_dig_playback_pcm_open,
                .close = via_dig_playback_pcm_close,
-               .prepare = via_dig_playback_pcm_prepare
+               .prepare = via_dig_playback_pcm_prepare,
+               .cleanup = via_dig_playback_pcm_cleanup
        },
 };
 
@@ -874,13 +857,6 @@ static int via_build_controls(struct hda_codec *codec)
                if (err < 0)
                        return err;
                spec->multiout.share_spdif = 1;
-
-               if (spec->extra_dig_out_nid) {
-                       err = snd_hda_create_spdif_out_ctls(codec,
-                                                   spec->extra_dig_out_nid);
-                       if (err < 0)
-                               return err;
-               }
        }
        if (spec->dig_in_nid) {
                err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
@@ -1013,10 +989,6 @@ static void via_unsol_event(struct hda_codec *codec,
                via_gpio_control(codec);
 }
 
-static hda_nid_t slave_dig_outs[] = {
-       0,
-};
-
 static int via_init(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
@@ -1051,8 +1023,9 @@ static int via_init(struct hda_codec *codec)
                snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
                                    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
 
-       /* no slave outs */
-       codec->slave_dig_outs = slave_dig_outs;
+       /* assign slave outs */
+       if (spec->slave_dig_outs[0])
+               codec->slave_dig_outs = spec->slave_dig_outs;
 
        return 0;
 }
@@ -2134,7 +2107,8 @@ static struct hda_pcm_stream vt1708B_pcm_digital_playback = {
        .ops = {
                .open = via_dig_playback_pcm_open,
                .close = via_dig_playback_pcm_close,
-               .prepare = via_dig_playback_pcm_prepare
+               .prepare = via_dig_playback_pcm_prepare,
+               .cleanup = via_dig_playback_pcm_cleanup
        },
 };
 
@@ -2589,14 +2563,15 @@ static struct hda_pcm_stream vt1708S_pcm_analog_capture = {
 };
 
 static struct hda_pcm_stream vt1708S_pcm_digital_playback = {
-       .substreams = 2,
+       .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
+               .prepare = via_dig_playback_pcm_prepare,
+               .cleanup = via_dig_playback_pcm_cleanup
        },
 };
 
@@ -2805,14 +2780,37 @@ static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec,
        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;
-       static hda_nid_t vt1708s_ignore[] = {0x21, 0};
 
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
-                                          vt1708s_ignore);
+       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);
@@ -2833,10 +2831,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec)
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
-       if (spec->autocfg.dig_outs)
-               spec->multiout.dig_out_nid = VT1708S_DIGOUT_NID;
-
-       spec->extra_dig_out_nid = 0x15;
+       fill_dig_outs(codec);
 
        if (spec->kctls.list)
                spec->mixers[spec->num_mixers++] = spec->kctls.list;
@@ -3000,7 +2995,8 @@ static struct hda_pcm_stream vt1702_pcm_digital_playback = {
        .ops = {
                .open = via_dig_playback_pcm_open,
                .close = via_dig_playback_pcm_close,
-               .prepare = via_dig_playback_pcm_prepare
+               .prepare = via_dig_playback_pcm_prepare,
+               .cleanup = via_dig_playback_pcm_cleanup
        },
 };
 
@@ -3128,10 +3124,8 @@ static int vt1702_parse_auto_config(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
        int err;
-       static hda_nid_t vt1702_ignore[] = {0x1C, 0};
 
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
-                                          vt1702_ignore);
+       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);
@@ -3152,10 +3146,7 @@ static int vt1702_parse_auto_config(struct hda_codec *codec)
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
-       if (spec->autocfg.dig_outs)
-               spec->multiout.dig_out_nid = VT1702_DIGOUT_NID;
-
-       spec->extra_dig_out_nid = 0x1B;
+       fill_dig_outs(codec);
 
        if (spec->kctls.list)
                spec->mixers[spec->num_mixers++] = spec->kctls.list;
index f99fe089495d716ae3c2d05a73903790d4b57fbc..536eae2ccf94d006bbd0e3ea577f17e9ddcea9de 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
+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
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o
index fdae6deba16bc8df8e07690db8ee14d16b869168..adc909ec125c24e51bfa6bac490cfcd05680c3b5 100644 (file)
@@ -335,6 +335,7 @@ struct snd_ice1712 {
        unsigned int force_rdma1:1;     /* VT1720/4 - RDMA1 as non-spdif */
        unsigned int midi_output:1;     /* VT1720/4: MIDI output triggered */
        unsigned int midi_input:1;      /* VT1720/4: MIDI input triggered */
+       unsigned int own_routing:1;     /* VT1720/4: use own routing ctls */
        unsigned int num_total_dacs;    /* total DACs */
        unsigned int num_total_adcs;    /* total ADCs */
        unsigned int cur_rate;          /* current rate */
@@ -458,10 +459,17 @@ static inline int snd_ice1712_gpio_read_bits(struct snd_ice1712 *ice,
        return  snd_ice1712_gpio_read(ice) & mask;
 }
 
+/* route access functions */
+int snd_ice1724_get_route_val(struct snd_ice1712 *ice, int shift);
+int snd_ice1724_put_route_val(struct snd_ice1712 *ice, unsigned int val,
+                                                               int shift);
+
 int snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice);
 
-int snd_ice1712_akm4xxx_init(struct snd_akm4xxx *ak, const struct snd_akm4xxx *template,
-                            const struct snd_ak4xxx_private *priv, struct snd_ice1712 *ice);
+int snd_ice1712_akm4xxx_init(struct snd_akm4xxx *ak,
+                            const struct snd_akm4xxx *template,
+                            const struct snd_ak4xxx_private *priv,
+                            struct snd_ice1712 *ice);
 void snd_ice1712_akm4xxx_free(struct snd_ice1712 *ice);
 int snd_ice1712_akm4xxx_build_controls(struct snd_ice1712 *ice);
 
index 128510e77a785344886cf6d3207b244850ed6245..36ade77cf37116216d6424dc3871e23377ee79cd 100644 (file)
@@ -49,6 +49,7 @@
 #include "prodigy192.h"
 #include "prodigy_hifi.h"
 #include "juli.h"
+#include "maya44.h"
 #include "phase.h"
 #include "wtm.h"
 #include "se.h"
@@ -65,6 +66,7 @@ MODULE_SUPPORTED_DEVICE("{"
               PRODIGY192_DEVICE_DESC
               PRODIGY_HIFI_DEVICE_DESC
               JULI_DEVICE_DESC
+              MAYA44_DEVICE_DESC
               PHASE_DEVICE_DESC
               WTM_DEVICE_DESC
               SE_DEVICE_DESC
@@ -626,7 +628,7 @@ static unsigned char stdclock_set_mclk(struct snd_ice1712 *ice,
        return 0;
 }
 
-static void snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate,
+static int snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate,
                                    int force)
 {
        unsigned long flags;
@@ -634,17 +636,18 @@ static void snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate,
        unsigned int i, old_rate;
 
        if (rate > ice->hw_rates->list[ice->hw_rates->count - 1])
-               return;
+               return -EINVAL;
+
        spin_lock_irqsave(&ice->reg_lock, flags);
        if ((inb(ICEMT1724(ice, DMA_CONTROL)) & DMA_STARTS) ||
            (inb(ICEMT1724(ice, DMA_PAUSE)) & DMA_PAUSES)) {
                /* running? we cannot change the rate now... */
                spin_unlock_irqrestore(&ice->reg_lock, flags);
-               return;
+               return -EBUSY;
        }
        if (!force && is_pro_rate_locked(ice)) {
                spin_unlock_irqrestore(&ice->reg_lock, flags);
-               return;
+               return (rate == ice->cur_rate) ? 0 : -EBUSY;
        }
 
        old_rate = ice->get_rate(ice);
@@ -652,7 +655,7 @@ static void snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate,
                ice->set_rate(ice, rate);
        else if (rate == ice->cur_rate) {
                spin_unlock_irqrestore(&ice->reg_lock, flags);
-               return;
+               return 0;
        }
 
        ice->cur_rate = rate;
@@ -674,13 +677,15 @@ static void snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate,
        }
        if (ice->spdif.ops.setup_rate)
                ice->spdif.ops.setup_rate(ice, rate);
+
+       return 0;
 }
 
 static int snd_vt1724_pcm_hw_params(struct snd_pcm_substream *substream,
                                    struct snd_pcm_hw_params *hw_params)
 {
        struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
-       int i, chs;
+       int i, chs, err;
 
        chs = params_channels(hw_params);
        mutex_lock(&ice->open_mutex);
@@ -715,7 +720,11 @@ static int snd_vt1724_pcm_hw_params(struct snd_pcm_substream *substream,
                }
        }
        mutex_unlock(&ice->open_mutex);
-       snd_vt1724_set_pro_rate(ice, params_rate(hw_params), 0);
+
+       err = snd_vt1724_set_pro_rate(ice, params_rate(hw_params), 0);
+       if (err < 0)
+               return err;
+
        return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
 }
 
@@ -848,20 +857,39 @@ static snd_pcm_uframes_t snd_vt1724_pcm_pointer(struct snd_pcm_substream *substr
 #endif
 }
 
-static const struct vt1724_pcm_reg vt1724_playback_pro_reg = {
+static const struct vt1724_pcm_reg vt1724_pdma0_reg = {
        .addr = VT1724_MT_PLAYBACK_ADDR,
        .size = VT1724_MT_PLAYBACK_SIZE,
        .count = VT1724_MT_PLAYBACK_COUNT,
        .start = VT1724_PDMA0_START,
 };
 
-static const struct vt1724_pcm_reg vt1724_capture_pro_reg = {
+static const struct vt1724_pcm_reg vt1724_pdma4_reg = {
+       .addr = VT1724_MT_PDMA4_ADDR,
+       .size = VT1724_MT_PDMA4_SIZE,
+       .count = VT1724_MT_PDMA4_COUNT,
+       .start = VT1724_PDMA4_START,
+};
+
+static const struct vt1724_pcm_reg vt1724_rdma0_reg = {
        .addr = VT1724_MT_CAPTURE_ADDR,
        .size = VT1724_MT_CAPTURE_SIZE,
        .count = VT1724_MT_CAPTURE_COUNT,
        .start = VT1724_RDMA0_START,
 };
 
+static const struct vt1724_pcm_reg vt1724_rdma1_reg = {
+       .addr = VT1724_MT_RDMA1_ADDR,
+       .size = VT1724_MT_RDMA1_SIZE,
+       .count = VT1724_MT_RDMA1_COUNT,
+       .start = VT1724_RDMA1_START,
+};
+
+#define vt1724_playback_pro_reg vt1724_pdma0_reg
+#define vt1724_playback_spdif_reg vt1724_pdma4_reg
+#define vt1724_capture_pro_reg vt1724_rdma0_reg
+#define vt1724_capture_spdif_reg vt1724_rdma1_reg
+
 static const struct snd_pcm_hardware snd_vt1724_playback_pro = {
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -1077,20 +1105,6 @@ static int __devinit snd_vt1724_pcm_profi(struct snd_ice1712 *ice, int device)
  * SPDIF PCM
  */
 
-static const struct vt1724_pcm_reg vt1724_playback_spdif_reg = {
-       .addr = VT1724_MT_PDMA4_ADDR,
-       .size = VT1724_MT_PDMA4_SIZE,
-       .count = VT1724_MT_PDMA4_COUNT,
-       .start = VT1724_PDMA4_START,
-};
-
-static const struct vt1724_pcm_reg vt1724_capture_spdif_reg = {
-       .addr = VT1724_MT_RDMA1_ADDR,
-       .size = VT1724_MT_RDMA1_SIZE,
-       .count = VT1724_MT_RDMA1_COUNT,
-       .start = VT1724_RDMA1_START,
-};
-
 /* update spdif control bits; call with reg_lock */
 static void update_spdif_bits(struct snd_ice1712 *ice, unsigned int val)
 {
@@ -1963,7 +1977,7 @@ static inline int digital_route_shift(int idx)
        return idx * 3;
 }
 
-static int get_route_val(struct snd_ice1712 *ice, int shift)
+int snd_ice1724_get_route_val(struct snd_ice1712 *ice, int shift)
 {
        unsigned long val;
        unsigned char eitem;
@@ -1982,7 +1996,8 @@ static int get_route_val(struct snd_ice1712 *ice, int shift)
        return eitem;
 }
 
-static int put_route_val(struct snd_ice1712 *ice, unsigned int val, int shift)
+int snd_ice1724_put_route_val(struct snd_ice1712 *ice, unsigned int val,
+                                                               int shift)
 {
        unsigned int old_val, nval;
        int change;
@@ -2010,7 +2025,7 @@ static int snd_vt1724_pro_route_analog_get(struct snd_kcontrol *kcontrol,
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
        ucontrol->value.enumerated.item[0] =
-               get_route_val(ice, analog_route_shift(idx));
+               snd_ice1724_get_route_val(ice, analog_route_shift(idx));
        return 0;
 }
 
@@ -2019,8 +2034,9 @@ static int snd_vt1724_pro_route_analog_put(struct snd_kcontrol *kcontrol,
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-       return put_route_val(ice, ucontrol->value.enumerated.item[0],
-                            analog_route_shift(idx));
+       return snd_ice1724_put_route_val(ice,
+                                        ucontrol->value.enumerated.item[0],
+                                        analog_route_shift(idx));
 }
 
 static int snd_vt1724_pro_route_spdif_get(struct snd_kcontrol *kcontrol,
@@ -2029,7 +2045,7 @@ static int snd_vt1724_pro_route_spdif_get(struct snd_kcontrol *kcontrol,
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
        ucontrol->value.enumerated.item[0] =
-               get_route_val(ice, digital_route_shift(idx));
+               snd_ice1724_get_route_val(ice, digital_route_shift(idx));
        return 0;
 }
 
@@ -2038,11 +2054,13 @@ static int snd_vt1724_pro_route_spdif_put(struct snd_kcontrol *kcontrol,
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
        int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-       return put_route_val(ice, ucontrol->value.enumerated.item[0],
-                            digital_route_shift(idx));
+       return snd_ice1724_put_route_val(ice,
+                                        ucontrol->value.enumerated.item[0],
+                                        digital_route_shift(idx));
 }
 
-static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata = {
+static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata =
+{
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "H/W Playback Route",
        .info = snd_vt1724_pro_route_info,
@@ -2109,6 +2127,7 @@ static struct snd_ice1712_card_info *card_tables[] __devinitdata = {
        snd_vt1724_prodigy_hifi_cards,
        snd_vt1724_prodigy192_cards,
        snd_vt1724_juli_cards,
+       snd_vt1724_maya44_cards,
        snd_vt1724_phase_cards,
        snd_vt1724_wtm_cards,
        snd_vt1724_se_cards,
@@ -2246,8 +2265,10 @@ static int __devinit snd_vt1724_read_eeprom(struct snd_ice1712 *ice,
 static void __devinit snd_vt1724_chip_reset(struct snd_ice1712 *ice)
 {
        outb(VT1724_RESET , ICEREG1724(ice, CONTROL));
+       inb(ICEREG1724(ice, CONTROL)); /* pci posting flush */
        msleep(10);
        outb(0, ICEREG1724(ice, CONTROL));
+       inb(ICEREG1724(ice, CONTROL)); /* pci posting flush */
        msleep(10);
 }
 
@@ -2277,9 +2298,12 @@ static int __devinit snd_vt1724_spdif_build_controls(struct snd_ice1712 *ice)
        if (snd_BUG_ON(!ice->pcm))
                return -EIO;
 
-       err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_mixer_pro_spdif_route, ice));
-       if (err < 0)
-               return err;
+       if (!ice->own_routing) {
+               err = snd_ctl_add(ice->card,
+                       snd_ctl_new1(&snd_vt1724_mixer_pro_spdif_route, ice));
+               if (err < 0)
+                       return err;
+       }
 
        err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_spdif_switch, ice));
        if (err < 0)
@@ -2326,7 +2350,7 @@ static int __devinit snd_vt1724_build_controls(struct snd_ice1712 *ice)
        if (err < 0)
                return err;
 
-       if (ice->num_total_dacs > 0) {
+       if (!ice->own_routing && ice->num_total_dacs > 0) {
                struct snd_kcontrol_new tmp = snd_vt1724_mixer_pro_analog_route;
                tmp.count = ice->num_total_dacs;
                if (ice->vt1720 && tmp.count > 2)
diff --git a/sound/pci/ice1712/maya44.c b/sound/pci/ice1712/maya44.c
new file mode 100644 (file)
index 0000000..3e1c20a
--- /dev/null
@@ -0,0 +1,779 @@
+/*
+ *   ALSA driver for ICEnsemble VT1724 (Envy24HT)
+ *
+ *   Lowlevel functions for ESI Maya44 cards
+ *
+ *     Copyright (c) 2009 Takashi Iwai <tiwai@suse.de>
+ *     Based on the patches by Rainer Zimmermann <mail@lightshed.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/tlv.h>
+
+#include "ice1712.h"
+#include "envy24ht.h"
+#include "maya44.h"
+
+/* WM8776 register indexes */
+#define WM8776_REG_HEADPHONE_L         0x00
+#define WM8776_REG_HEADPHONE_R         0x01
+#define WM8776_REG_HEADPHONE_MASTER    0x02
+#define WM8776_REG_DAC_ATTEN_L         0x03
+#define WM8776_REG_DAC_ATTEN_R         0x04
+#define WM8776_REG_DAC_ATTEN_MASTER    0x05
+#define WM8776_REG_DAC_PHASE           0x06
+#define WM8776_REG_DAC_CONTROL         0x07
+#define WM8776_REG_DAC_MUTE            0x08
+#define WM8776_REG_DAC_DEEMPH          0x09
+#define WM8776_REG_DAC_IF_CONTROL      0x0a
+#define WM8776_REG_ADC_IF_CONTROL      0x0b
+#define WM8776_REG_MASTER_MODE_CONTROL 0x0c
+#define WM8776_REG_POWERDOWN           0x0d
+#define WM8776_REG_ADC_ATTEN_L         0x0e
+#define WM8776_REG_ADC_ATTEN_R         0x0f
+#define WM8776_REG_ADC_ALC1            0x10
+#define WM8776_REG_ADC_ALC2            0x11
+#define WM8776_REG_ADC_ALC3            0x12
+#define WM8776_REG_ADC_NOISE_GATE      0x13
+#define WM8776_REG_ADC_LIMITER         0x14
+#define WM8776_REG_ADC_MUX             0x15
+#define WM8776_REG_OUTPUT_MUX          0x16
+#define WM8776_REG_RESET               0x17
+
+#define WM8776_NUM_REGS                        0x18
+
+/* clock ratio identifiers for snd_wm8776_set_rate() */
+#define WM8776_CLOCK_RATIO_128FS       0
+#define WM8776_CLOCK_RATIO_192FS       1
+#define WM8776_CLOCK_RATIO_256FS       2
+#define WM8776_CLOCK_RATIO_384FS       3
+#define WM8776_CLOCK_RATIO_512FS       4
+#define WM8776_CLOCK_RATIO_768FS       5
+
+enum { WM_VOL_HP, WM_VOL_DAC, WM_VOL_ADC, WM_NUM_VOLS };
+enum { WM_SW_DAC, WM_SW_BYPASS, WM_NUM_SWITCHES };
+
+struct snd_wm8776 {
+       unsigned char addr;
+       unsigned short regs[WM8776_NUM_REGS];
+       unsigned char volumes[WM_NUM_VOLS][2];
+       unsigned int switch_bits;
+};
+
+struct snd_maya44 {
+       struct snd_ice1712 *ice;
+       struct snd_wm8776 wm[2];
+       struct mutex mutex;
+};
+
+
+/* write the given register and save the data to the cache */
+static void wm8776_write(struct snd_ice1712 *ice, struct snd_wm8776 *wm,
+                        unsigned char reg, unsigned short val)
+{
+       /*
+        * WM8776 registers are up to 9 bits wide, bit 8 is placed in the LSB
+        * of the address field
+        */
+       snd_vt1724_write_i2c(ice, wm->addr,
+                            (reg << 1) | ((val >> 8) & 1),
+                            val & 0xff);
+       wm->regs[reg] = val;
+}
+
+/*
+ * update the given register with and/or mask and save the data to the cache
+ */
+static int wm8776_write_bits(struct snd_ice1712 *ice, struct snd_wm8776 *wm,
+                            unsigned char reg,
+                            unsigned short mask, unsigned short val)
+{
+       val |= wm->regs[reg] & ~mask;
+       if (val != wm->regs[reg]) {
+               wm8776_write(ice, wm, reg, val);
+               return 1;
+       }
+       return 0;
+}
+
+
+/*
+ * WM8776 volume controls
+ */
+
+struct maya_vol_info {
+       unsigned int maxval;            /* volume range: 0..maxval */
+       unsigned char regs[2];          /* left and right registers */
+       unsigned short mask;            /* value mask */
+       unsigned short offset;          /* zero-value offset */
+       unsigned short mute;            /* mute bit */
+       unsigned short update;          /* update bits */
+       unsigned char mux_bits[2];      /* extra bits for ADC mute */
+};
+
+static struct maya_vol_info vol_info[WM_NUM_VOLS] = {
+       [WM_VOL_HP] = {
+               .maxval = 80,
+               .regs = { WM8776_REG_HEADPHONE_L, WM8776_REG_HEADPHONE_R },
+               .mask = 0x7f,
+               .offset = 0x30,
+               .mute = 0x00,
+               .update = 0x180,        /* update and zero-cross enable */
+       },
+       [WM_VOL_DAC] = {
+               .maxval = 255,
+               .regs = { WM8776_REG_DAC_ATTEN_L, WM8776_REG_DAC_ATTEN_R },
+               .mask = 0xff,
+               .offset = 0x01,
+               .mute = 0x00,
+               .update = 0x100,        /* zero-cross enable */
+       },
+       [WM_VOL_ADC] = {
+               .maxval = 91,
+               .regs = { WM8776_REG_ADC_ATTEN_L, WM8776_REG_ADC_ATTEN_R },
+               .mask = 0xff,
+               .offset = 0xa5,
+               .mute = 0xa5,
+               .update = 0x100,        /* update */
+               .mux_bits = { 0x80, 0x40 }, /* ADCMUX bits */
+       },
+};
+
+/*
+ * dB tables
+ */
+/* headphone output: mute, -73..+6db (1db step) */
+static const DECLARE_TLV_DB_SCALE(db_scale_hp, -7400, 100, 1);
+/* DAC output: mute, -127..0db (0.5db step) */
+static const DECLARE_TLV_DB_SCALE(db_scale_dac, -12750, 50, 1);
+/* ADC gain: mute, -21..+24db (0.5db step) */
+static const DECLARE_TLV_DB_SCALE(db_scale_adc, -2100, 50, 1);
+
+static int maya_vol_info(struct snd_kcontrol *kcontrol,
+                        struct snd_ctl_elem_info *uinfo)
+{
+       unsigned int idx = kcontrol->private_value;
+       struct maya_vol_info *vol = &vol_info[idx];
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = vol->maxval;
+       return 0;
+}
+
+static int maya_vol_get(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_wm8776 *wm =
+               &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)];
+       unsigned int idx = kcontrol->private_value;
+
+       mutex_lock(&chip->mutex);
+       ucontrol->value.integer.value[0] = wm->volumes[idx][0];
+       ucontrol->value.integer.value[1] = wm->volumes[idx][1];
+       mutex_unlock(&chip->mutex);
+       return 0;
+}
+
+static int maya_vol_put(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_wm8776 *wm =
+               &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)];
+       unsigned int idx = kcontrol->private_value;
+       struct maya_vol_info *vol = &vol_info[idx];
+       unsigned int val, data;
+       int ch, changed = 0;
+
+       mutex_lock(&chip->mutex);
+       for (ch = 0; ch < 2; ch++) {
+               val = ucontrol->value.integer.value[ch];
+               if (val > vol->maxval)
+                       val = vol->maxval;
+               if (val == wm->volumes[idx][ch])
+                       continue;
+               if (!val)
+                       data = vol->mute;
+               else
+                       data = (val - 1) + vol->offset;
+               data |= vol->update;
+               changed |= wm8776_write_bits(chip->ice, wm, vol->regs[ch],
+                                            vol->mask | vol->update, data);
+               if (vol->mux_bits[ch])
+                       wm8776_write_bits(chip->ice, wm, WM8776_REG_ADC_MUX,
+                                         vol->mux_bits[ch],
+                                         val ? 0 : vol->mux_bits[ch]);
+               wm->volumes[idx][ch] = val;
+       }
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+/*
+ * WM8776 switch controls
+ */
+
+#define COMPOSE_SW_VAL(idx, reg, mask) ((idx) | ((reg) << 8) | ((mask) << 16))
+#define GET_SW_VAL_IDX(val)    ((val) & 0xff)
+#define GET_SW_VAL_REG(val)    (((val) >> 8) & 0xff)
+#define GET_SW_VAL_MASK(val)   (((val) >> 16) & 0xff)
+
+#define maya_sw_info   snd_ctl_boolean_mono_info
+
+static int maya_sw_get(struct snd_kcontrol *kcontrol,
+                      struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_wm8776 *wm =
+               &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)];
+       unsigned int idx = GET_SW_VAL_IDX(kcontrol->private_value);
+
+       ucontrol->value.integer.value[0] = (wm->switch_bits >> idx) & 1;
+       return 0;
+}
+
+static int maya_sw_put(struct snd_kcontrol *kcontrol,
+                      struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_wm8776 *wm =
+               &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)];
+       unsigned int idx = GET_SW_VAL_IDX(kcontrol->private_value);
+       unsigned int mask, val;
+       int changed;
+
+       mutex_lock(&chip->mutex);
+       mask = 1 << idx;
+       wm->switch_bits &= ~mask;
+       val = ucontrol->value.integer.value[0];
+       if (val)
+               wm->switch_bits |= mask;
+       mask = GET_SW_VAL_MASK(kcontrol->private_value);
+       changed = wm8776_write_bits(chip->ice, wm,
+                                   GET_SW_VAL_REG(kcontrol->private_value),
+                                   mask, val ? mask : 0);
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+/*
+ * GPIO pins (known ones for maya44)
+ */
+#define GPIO_PHANTOM_OFF       2
+#define GPIO_MIC_RELAY         4
+#define GPIO_SPDIF_IN_INV      5
+#define GPIO_MUST_BE_0         7
+
+/*
+ * GPIO switch controls
+ */
+
+#define COMPOSE_GPIO_VAL(shift, inv)   ((shift) | ((inv) << 8))
+#define GET_GPIO_VAL_SHIFT(val)                ((val) & 0xff)
+#define GET_GPIO_VAL_INV(val)          (((val) >> 8) & 1)
+
+static int maya_set_gpio_bits(struct snd_ice1712 *ice, unsigned int mask,
+                             unsigned int bits)
+{
+       unsigned int data;
+       data = snd_ice1712_gpio_read(ice);
+       if ((data & mask) == bits)
+               return 0;
+       snd_ice1712_gpio_write(ice, (data & ~mask) | bits);
+       return 1;
+}
+
+#define maya_gpio_sw_info      snd_ctl_boolean_mono_info
+
+static int maya_gpio_sw_get(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
+       unsigned int shift = GET_GPIO_VAL_SHIFT(kcontrol->private_value);
+       unsigned int val;
+
+       val = (snd_ice1712_gpio_read(chip->ice) >> shift) & 1;
+       if (GET_GPIO_VAL_INV(kcontrol->private_value))
+               val = !val;
+       ucontrol->value.integer.value[0] = val;
+       return 0;
+}
+
+static int maya_gpio_sw_put(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
+       unsigned int shift = GET_GPIO_VAL_SHIFT(kcontrol->private_value);
+       unsigned int val, mask;
+       int changed;
+
+       mutex_lock(&chip->mutex);
+       mask = 1 << shift;
+       val = ucontrol->value.integer.value[0];
+       if (GET_GPIO_VAL_INV(kcontrol->private_value))
+               val = !val;
+       val = val ? mask : 0;
+       changed = maya_set_gpio_bits(chip->ice, mask, val);
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+/*
+ * capture source selection
+ */
+
+/* known working input slots (0-4) */
+#define MAYA_LINE_IN   1       /* in-2 */
+#define MAYA_MIC_IN    4       /* in-5 */
+
+static void wm8776_select_input(struct snd_maya44 *chip, int idx, int line)
+{
+       wm8776_write_bits(chip->ice, &chip->wm[idx], WM8776_REG_ADC_MUX,
+                         0x1f, 1 << line);
+}
+
+static int maya_rec_src_info(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_info *uinfo)
+{
+       static char *texts[] = { "Line", "Mic" };
+
+       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 maya_rec_src_get(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
+       int sel;
+
+       if (snd_ice1712_gpio_read(chip->ice) & (1 << GPIO_MIC_RELAY))
+               sel = 1;
+       else
+               sel = 0;
+       ucontrol->value.enumerated.item[0] = sel;
+       return 0;
+}
+
+static int maya_rec_src_put(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
+       int sel = ucontrol->value.enumerated.item[0];
+       int changed;
+
+       mutex_lock(&chip->mutex);
+       changed = maya_set_gpio_bits(chip->ice, GPIO_MIC_RELAY,
+                                    sel ? GPIO_MIC_RELAY : 0);
+       wm8776_select_input(chip, 0, sel ? MAYA_MIC_IN : MAYA_LINE_IN);
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+/*
+ * Maya44 routing switch settings have different meanings than the standard
+ * ice1724 switches as defined in snd_vt1724_pro_route_info (ice1724.c).
+ */
+static int maya_pb_route_info(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_info *uinfo)
+{
+       static char *texts[] = {
+               "PCM Out", /* 0 */
+               "Input 1", "Input 2", "Input 3", "Input 4"
+       };
+
+       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 maya_pb_route_shift(int idx)
+{
+       static const unsigned char shift[10] =
+               { 8, 20, 0, 3, 11, 23, 14, 26, 17, 29 };
+       return shift[idx % 10];
+}
+
+static int maya_pb_route_get(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
+       int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+       ucontrol->value.enumerated.item[0] =
+               snd_ice1724_get_route_val(chip->ice, maya_pb_route_shift(idx));
+       return 0;
+}
+
+static int maya_pb_route_put(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
+       int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+       return snd_ice1724_put_route_val(chip->ice,
+                                        ucontrol->value.enumerated.item[0],
+                                        maya_pb_route_shift(idx));
+}
+
+
+/*
+ * controls to be added
+ */
+
+static struct snd_kcontrol_new maya_controls[] __devinitdata = {
+       {
+               .name = "Crossmix Playback Volume",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                       SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+               .info = maya_vol_info,
+               .get = maya_vol_get,
+               .put = maya_vol_put,
+               .tlv = { .p = db_scale_hp },
+               .private_value = WM_VOL_HP,
+               .count = 2,
+       },
+       {
+               .name = "PCM Playback Volume",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                       SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+               .info = maya_vol_info,
+               .get = maya_vol_get,
+               .put = maya_vol_put,
+               .tlv = { .p = db_scale_dac },
+               .private_value = WM_VOL_DAC,
+               .count = 2,
+       },
+       {
+               .name = "Line Capture Volume",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                       SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+               .info = maya_vol_info,
+               .get = maya_vol_get,
+               .put = maya_vol_put,
+               .tlv = { .p = db_scale_adc },
+               .private_value = WM_VOL_ADC,
+               .count = 2,
+       },
+       {
+               .name = "PCM Playback Switch",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .info = maya_sw_info,
+               .get = maya_sw_get,
+               .put = maya_sw_put,
+               .private_value = COMPOSE_SW_VAL(WM_SW_DAC,
+                                               WM8776_REG_OUTPUT_MUX, 0x01),
+               .count = 2,
+       },
+       {
+               .name = "Bypass Playback Switch",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .info = maya_sw_info,
+               .get = maya_sw_get,
+               .put = maya_sw_put,
+               .private_value = COMPOSE_SW_VAL(WM_SW_BYPASS,
+                                               WM8776_REG_OUTPUT_MUX, 0x04),
+               .count = 2,
+       },
+       {
+               .name = "Capture Source",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .info = maya_rec_src_info,
+               .get = maya_rec_src_get,
+               .put = maya_rec_src_put,
+       },
+       {
+               .name = "Mic Phantom Power Switch",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .info = maya_gpio_sw_info,
+               .get = maya_gpio_sw_get,
+               .put = maya_gpio_sw_put,
+               .private_value = COMPOSE_GPIO_VAL(GPIO_PHANTOM_OFF, 1),
+       },
+       {
+               .name = "SPDIF Capture Switch",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .info = maya_gpio_sw_info,
+               .get = maya_gpio_sw_get,
+               .put = maya_gpio_sw_put,
+               .private_value = COMPOSE_GPIO_VAL(GPIO_SPDIF_IN_INV, 1),
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "H/W Playback Route",
+               .info = maya_pb_route_info,
+               .get = maya_pb_route_get,
+               .put = maya_pb_route_put,
+               .count = 4,  /* FIXME: do controls 5-9 have any meaning? */
+       },
+};
+
+static int __devinit maya44_add_controls(struct snd_ice1712 *ice)
+{
+       int err, i;
+
+       for (i = 0; i < ARRAY_SIZE(maya_controls); i++) {
+               err = snd_ctl_add(ice->card, snd_ctl_new1(&maya_controls[i],
+                                                         ice->spec));
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
+
+/*
+ * initialize a wm8776 chip
+ */
+static void __devinit wm8776_init(struct snd_ice1712 *ice,
+                                 struct snd_wm8776 *wm, unsigned int addr)
+{
+       static const unsigned short inits_wm8776[] = {
+               0x02, 0x100, /* R2: headphone L+R muted + update */
+               0x05, 0x100, /* R5: DAC output L+R muted + update */
+               0x06, 0x000, /* R6: DAC output phase normal */
+               0x07, 0x091, /* R7: DAC enable zero cross detection,
+                               normal output */
+               0x08, 0x000, /* R8: DAC soft mute off */
+               0x09, 0x000, /* R9: no deemph, DAC zero detect disabled */
+               0x0a, 0x022, /* R10: DAC I2C mode, std polarities, 24bit */
+               0x0b, 0x022, /* R11: ADC I2C mode, std polarities, 24bit,
+                               highpass filter enabled */
+               0x0c, 0x042, /* R12: ADC+DAC slave, ADC+DAC 44,1kHz */
+               0x0d, 0x000, /* R13: all power up */
+               0x0e, 0x100, /* R14: ADC left muted,
+                               enable zero cross detection */
+               0x0f, 0x100, /* R15: ADC right muted,
+                               enable zero cross detection */
+                            /* R16: ALC...*/
+               0x11, 0x000, /* R17: disable ALC */
+                            /* R18: ALC...*/
+                            /* R19: noise gate...*/
+               0x15, 0x000, /* R21: ADC input mux init, mute all inputs */
+               0x16, 0x001, /* R22: output mux, select DAC */
+               0xff, 0xff
+       };
+
+       const unsigned short *ptr;
+       unsigned char reg;
+       unsigned short data;
+
+       wm->addr = addr;
+       /* enable DAC output; mute bypass, aux & all inputs */
+       wm->switch_bits = (1 << WM_SW_DAC);
+
+       ptr = inits_wm8776;
+       while (*ptr != 0xff) {
+               reg = *ptr++;
+               data = *ptr++;
+               wm8776_write(ice, wm, reg, data);
+       }
+}
+
+
+/*
+ * change the rate on the WM8776 codecs.
+ * this assumes that the VT17xx's rate is changed by the calling function.
+ * NOTE: even though the WM8776's are running in slave mode and rate
+ * selection is automatic, we need to call snd_wm8776_set_rate() here
+ * to make sure some flags are set correctly.
+ */
+static void set_rate(struct snd_ice1712 *ice, unsigned int rate)
+{
+       struct snd_maya44 *chip = ice->spec;
+       unsigned int ratio, adc_ratio, val;
+       int i;
+
+       switch (rate) {
+       case 192000:
+               ratio = WM8776_CLOCK_RATIO_128FS;
+               break;
+       case 176400:
+               ratio = WM8776_CLOCK_RATIO_128FS;
+               break;
+       case 96000:
+               ratio = WM8776_CLOCK_RATIO_256FS;
+               break;
+       case 88200:
+               ratio = WM8776_CLOCK_RATIO_384FS;
+               break;
+       case 48000:
+               ratio = WM8776_CLOCK_RATIO_512FS;
+               break;
+       case 44100:
+               ratio = WM8776_CLOCK_RATIO_512FS;
+               break;
+       case 32000:
+               ratio = WM8776_CLOCK_RATIO_768FS;
+               break;
+       case 0:
+               /* no hint - S/PDIF input is master, simply return */
+               return;
+       default:
+               snd_BUG();
+               return;
+       }
+
+       /*
+        * this currently sets the same rate for ADC and DAC, but limits
+        * ADC rate to 256X (96kHz). For 256X mode (96kHz), this sets ADC
+        * oversampling to 64x, as recommended by WM8776 datasheet.
+        * Setting the rate is not really necessary in slave mode.
+        */
+       adc_ratio = ratio;
+       if (adc_ratio < WM8776_CLOCK_RATIO_256FS)
+               adc_ratio = WM8776_CLOCK_RATIO_256FS;
+
+       val = adc_ratio;
+       if (adc_ratio == WM8776_CLOCK_RATIO_256FS)
+               val |= 8;
+       val |= ratio << 4;
+
+       mutex_lock(&chip->mutex);
+       for (i = 0; i < 2; i++)
+               wm8776_write_bits(ice, &chip->wm[i],
+                                 WM8776_REG_MASTER_MODE_CONTROL,
+                                 0x180, val);
+       mutex_unlock(&chip->mutex);
+}
+
+/*
+ * supported sample rates (to override the default one)
+ */
+
+static unsigned int rates[] = {
+       32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000
+};
+
+/* playback rates: 32..192 kHz */
+static struct snd_pcm_hw_constraint_list dac_rates = {
+       .count = ARRAY_SIZE(rates),
+       .list = rates,
+       .mask = 0
+};
+
+
+/*
+ * chip addresses on I2C bus
+ */
+static unsigned char wm8776_addr[2] __devinitdata = {
+       0x34, 0x36, /* codec 0 & 1 */
+};
+
+/*
+ * initialize the chip
+ */
+static int __devinit maya44_init(struct snd_ice1712 *ice)
+{
+       int i;
+       struct snd_maya44 *chip;
+
+       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+       mutex_init(&chip->mutex);
+       chip->ice = ice;
+       ice->spec = chip;
+
+       /* initialise codecs */
+       ice->num_total_dacs = 4;
+       ice->num_total_adcs = 4;
+       ice->akm_codecs = 0;
+
+       for (i = 0; i < 2; i++) {
+               wm8776_init(ice, &chip->wm[i], wm8776_addr[i]);
+               wm8776_select_input(chip, i, MAYA_LINE_IN);
+       }
+
+       /* set card specific rates */
+       ice->hw_rates = &dac_rates;
+
+       /* register change rate notifier */
+       ice->gpio.set_pro_rate = set_rate;
+
+       /* RDMA1 (2nd input channel) is used for ADC by default */
+       ice->force_rdma1 = 1;
+
+       /* have an own routing control */
+       ice->own_routing = 1;
+
+       return 0;
+}
+
+
+/*
+ * Maya44 boards don't provide the EEPROM data except for the vendor IDs.
+ * hence the driver needs to sets up it properly.
+ */
+
+static unsigned char maya44_eeprom[] __devinitdata = {
+       [ICE_EEP2_SYSCONF]     = 0x45,
+               /* clock xin1=49.152MHz, mpu401, 2 stereo ADCs+DACs */
+       [ICE_EEP2_ACLINK]      = 0x80,
+               /* I2S */
+       [ICE_EEP2_I2S]         = 0xf8,
+               /* vol, 96k, 24bit, 192k */
+       [ICE_EEP2_SPDIF]       = 0xc3,
+               /* enable spdif out, spdif out supp, spdif-in, ext spdif out */
+       [ICE_EEP2_GPIO_DIR]    = 0xff,
+       [ICE_EEP2_GPIO_DIR1]   = 0xff,
+       [ICE_EEP2_GPIO_DIR2]   = 0xff,
+       [ICE_EEP2_GPIO_MASK]   = 0/*0x9f*/,
+       [ICE_EEP2_GPIO_MASK1]  = 0/*0xff*/,
+       [ICE_EEP2_GPIO_MASK2]  = 0/*0x7f*/,
+       [ICE_EEP2_GPIO_STATE]  = (1 << GPIO_PHANTOM_OFF) |
+                       (1 << GPIO_SPDIF_IN_INV),
+       [ICE_EEP2_GPIO_STATE1] = 0x00,
+       [ICE_EEP2_GPIO_STATE2] = 0x00,
+};
+
+/* entry point */
+struct snd_ice1712_card_info snd_vt1724_maya44_cards[] __devinitdata = {
+       {
+               .subvendor = VT1724_SUBDEVICE_MAYA44,
+               .name = "ESI Maya44",
+               .model = "maya44",
+               .chip_init = maya44_init,
+               .build_controls = maya44_add_controls,
+               .eeprom_size = sizeof(maya44_eeprom),
+               .eeprom_data = maya44_eeprom,
+       },
+       { } /* terminator */
+};
diff --git a/sound/pci/ice1712/maya44.h b/sound/pci/ice1712/maya44.h
new file mode 100644 (file)
index 0000000..eafd03a
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __SOUND_MAYA44_H
+#define __SOUND_MAYA44_H
+
+#define MAYA44_DEVICE_DESC             "{ESI,Maya44},"
+
+#define VT1724_SUBDEVICE_MAYA44                0x34315441      /* Maya44 */
+
+extern struct snd_ice1712_card_info  snd_vt1724_maya44_cards[];
+
+#endif /* __SOUND_MAYA44_H */
diff --git a/sound/pci/lx6464es/Makefile b/sound/pci/lx6464es/Makefile
new file mode 100644 (file)
index 0000000..eb04a6c
--- /dev/null
@@ -0,0 +1,2 @@
+snd-lx6464es-objs := lx6464es.o lx_core.o
+obj-$(CONFIG_SND_LX6464ES) += snd-lx6464es.o
diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c
new file mode 100644 (file)
index 0000000..ccf1b38
--- /dev/null
@@ -0,0 +1,1159 @@
+/* -*- linux-c -*- *
+ *
+ * ALSA driver for the digigram lx6464es interface
+ *
+ * Copyright (c) 2008, 2009 Tim Blechmann <tim@klingt.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; see the file COPYING.  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/init.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/info.h>
+
+#include "lx6464es.h"
+
+MODULE_AUTHOR("Tim Blechmann");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("digigram lx6464es");
+MODULE_SUPPORTED_DEVICE("{digigram lx6464es{}}");
+
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for Digigram LX6464ES interface.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for  Digigram LX6464ES interface.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable/disable specific Digigram LX6464ES soundcards.");
+
+static const char card_name[] = "LX6464ES";
+
+
+#define PCI_DEVICE_ID_PLX_LX6464ES             PCI_DEVICE_ID_PLX_9056
+
+static struct pci_device_id snd_lx6464es_ids[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES),
+         .subvendor = PCI_VENDOR_ID_DIGIGRAM,
+         .subdevice = PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_SERIAL_SUBSYSTEM
+       },                      /* LX6464ES */
+       { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES),
+         .subvendor = PCI_VENDOR_ID_DIGIGRAM,
+         .subdevice = PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_CAE_SERIAL_SUBSYSTEM
+       },                      /* LX6464ES-CAE */
+       { 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, snd_lx6464es_ids);
+
+
+
+/* PGO pour USERo dans le registre pci_0x06/loc_0xEC */
+#define CHIPSC_RESET_XILINX (1L<<16)
+
+
+/* alsa callbacks */
+static struct snd_pcm_hardware lx_caps = {
+       .info             = (SNDRV_PCM_INFO_MMAP |
+                            SNDRV_PCM_INFO_INTERLEAVED |
+                            SNDRV_PCM_INFO_MMAP_VALID |
+                            SNDRV_PCM_INFO_SYNC_START),
+       .formats          = (SNDRV_PCM_FMTBIT_S16_LE |
+                            SNDRV_PCM_FMTBIT_S16_BE |
+                            SNDRV_PCM_FMTBIT_S24_3LE |
+                            SNDRV_PCM_FMTBIT_S24_3BE),
+       .rates            = (SNDRV_PCM_RATE_CONTINUOUS |
+                            SNDRV_PCM_RATE_8000_192000),
+       .rate_min         = 8000,
+       .rate_max         = 192000,
+       .channels_min     = 2,
+       .channels_max     = 64,
+       .buffer_bytes_max = 64*2*3*MICROBLAZE_IBL_MAX*MAX_STREAM_BUFFER,
+       .period_bytes_min = (2*2*MICROBLAZE_IBL_MIN*2),
+       .period_bytes_max = (4*64*MICROBLAZE_IBL_MAX*MAX_STREAM_BUFFER),
+       .periods_min      = 2,
+       .periods_max      = MAX_STREAM_BUFFER,
+};
+
+static int lx_set_granularity(struct lx6464es *chip, u32 gran);
+
+
+static int lx_hardware_open(struct lx6464es *chip,
+                           struct snd_pcm_substream *substream)
+{
+       int err = 0;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int channels = runtime->channels;
+       int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+
+       snd_pcm_uframes_t period_size = runtime->period_size;
+
+       snd_printd(LXP "allocating pipe for %d channels\n", channels);
+       err = lx_pipe_allocate(chip, 0, is_capture, channels);
+       if (err < 0) {
+               snd_printk(KERN_ERR LXP "allocating pipe failed\n");
+               return err;
+       }
+
+       err = lx_set_granularity(chip, period_size);
+       if (err < 0) {
+               snd_printk(KERN_ERR LXP "setting granularity to %ld failed\n",
+                          period_size);
+               return err;
+       }
+
+       return 0;
+}
+
+static int lx_hardware_start(struct lx6464es *chip,
+                            struct snd_pcm_substream *substream)
+{
+       int err = 0;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+
+       snd_printd(LXP "setting stream format\n");
+       err = lx_stream_set_format(chip, runtime, 0, is_capture);
+       if (err < 0) {
+               snd_printk(KERN_ERR LXP "setting stream format failed\n");
+               return err;
+       }
+
+       snd_printd(LXP "starting pipe\n");
+       err = lx_pipe_start(chip, 0, is_capture);
+       if (err < 0) {
+               snd_printk(KERN_ERR LXP "starting pipe failed\n");
+               return err;
+       }
+
+       snd_printd(LXP "waiting for pipe to start\n");
+       err = lx_pipe_wait_for_start(chip, 0, is_capture);
+       if (err < 0) {
+               snd_printk(KERN_ERR LXP "waiting for pipe failed\n");
+               return err;
+       }
+
+       return err;
+}
+
+
+static int lx_hardware_stop(struct lx6464es *chip,
+                           struct snd_pcm_substream *substream)
+{
+       int err = 0;
+       int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+
+       snd_printd(LXP "pausing pipe\n");
+       err = lx_pipe_pause(chip, 0, is_capture);
+       if (err < 0) {
+               snd_printk(KERN_ERR LXP "pausing pipe failed\n");
+               return err;
+       }
+
+       snd_printd(LXP "waiting for pipe to become idle\n");
+       err = lx_pipe_wait_for_idle(chip, 0, is_capture);
+       if (err < 0) {
+               snd_printk(KERN_ERR LXP "waiting for pipe failed\n");
+               return err;
+       }
+
+       snd_printd(LXP "stopping pipe\n");
+       err = lx_pipe_stop(chip, 0, is_capture);
+       if (err < 0) {
+               snd_printk(LXP "stopping pipe failed\n");
+               return err;
+       }
+
+       return err;
+}
+
+
+static int lx_hardware_close(struct lx6464es *chip,
+                            struct snd_pcm_substream *substream)
+{
+       int err = 0;
+       int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+
+       snd_printd(LXP "releasing pipe\n");
+       err = lx_pipe_release(chip, 0, is_capture);
+       if (err < 0) {
+               snd_printk(LXP "releasing pipe failed\n");
+               return err;
+       }
+
+       return err;
+}
+
+
+static int lx_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct lx6464es *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int err = 0;
+       int board_rate;
+
+       snd_printdd("->lx_pcm_open\n");
+       mutex_lock(&chip->setup_mutex);
+
+       /* copy the struct snd_pcm_hardware struct */
+       runtime->hw = lx_caps;
+
+#if 0
+       /* buffer-size should better be multiple of period-size */
+       err = snd_pcm_hw_constraint_integer(runtime,
+                                           SNDRV_PCM_HW_PARAM_PERIODS);
+       if (err < 0) {
+               snd_printk(KERN_WARNING LXP "could not constrain periods\n");
+               goto exit;
+       }
+#endif
+
+       /* the clock rate cannot be changed */
+       board_rate = chip->board_sample_rate;
+       err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE,
+                                          board_rate, board_rate);
+
+       if (err < 0) {
+               snd_printk(KERN_WARNING LXP "could not constrain periods\n");
+               goto exit;
+       }
+
+       /* constrain period size */
+       err = snd_pcm_hw_constraint_minmax(runtime,
+                                          SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+                                          MICROBLAZE_IBL_MIN,
+                                          MICROBLAZE_IBL_MAX);
+       if (err < 0) {
+               snd_printk(KERN_WARNING LXP
+                          "could not constrain period size\n");
+               goto exit;
+       }
+
+       snd_pcm_hw_constraint_step(runtime, 0,
+                                  SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32);
+
+       snd_pcm_set_sync(substream);
+       err = 0;
+
+exit:
+       runtime->private_data = chip;
+
+       mutex_unlock(&chip->setup_mutex);
+       snd_printdd("<-lx_pcm_open, %d\n", err);
+       return err;
+}
+
+static int lx_pcm_close(struct snd_pcm_substream *substream)
+{
+       int err = 0;
+       snd_printdd("->lx_pcm_close\n");
+       return err;
+}
+
+static snd_pcm_uframes_t lx_pcm_stream_pointer(struct snd_pcm_substream
+                                              *substream)
+{
+       struct lx6464es *chip = snd_pcm_substream_chip(substream);
+       snd_pcm_uframes_t pos;
+       unsigned long flags;
+       int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+
+       struct lx_stream *lx_stream = is_capture ? &chip->capture_stream :
+               &chip->playback_stream;
+
+       snd_printdd("->lx_pcm_stream_pointer\n");
+
+       spin_lock_irqsave(&chip->lock, flags);
+       pos = lx_stream->frame_pos * substream->runtime->period_size;
+       spin_unlock_irqrestore(&chip->lock, flags);
+
+       snd_printdd(LXP "stream_pointer at %ld\n", pos);
+       return pos;
+}
+
+static int lx_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       struct lx6464es *chip = snd_pcm_substream_chip(substream);
+       int err = 0;
+       const int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+
+       snd_printdd("->lx_pcm_prepare\n");
+
+       mutex_lock(&chip->setup_mutex);
+
+       if (chip->hardware_running[is_capture]) {
+               err = lx_hardware_stop(chip, substream);
+               if (err < 0) {
+                       snd_printk(KERN_ERR LXP "failed to stop hardware. "
+                                  "Error code %d\n", err);
+                       goto exit;
+               }
+
+               err = lx_hardware_close(chip, substream);
+               if (err < 0) {
+                       snd_printk(KERN_ERR LXP "failed to close hardware. "
+                                  "Error code %d\n", err);
+                       goto exit;
+               }
+       }
+
+       snd_printd(LXP "opening hardware\n");
+       err = lx_hardware_open(chip, substream);
+       if (err < 0) {
+               snd_printk(KERN_ERR LXP "failed to open hardware. "
+                          "Error code %d\n", err);
+               goto exit;
+       }
+
+       err = lx_hardware_start(chip, substream);
+       if (err < 0) {
+               snd_printk(KERN_ERR LXP "failed to start hardware. "
+                          "Error code %d\n", err);
+               goto exit;
+       }
+
+       chip->hardware_running[is_capture] = 1;
+
+       if (chip->board_sample_rate != substream->runtime->rate) {
+               if (!err)
+                       chip->board_sample_rate = substream->runtime->rate;
+       }
+
+exit:
+       mutex_unlock(&chip->setup_mutex);
+       return err;
+}
+
+static int lx_pcm_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *hw_params, int is_capture)
+{
+       struct lx6464es *chip = snd_pcm_substream_chip(substream);
+       int err = 0;
+
+       snd_printdd("->lx_pcm_hw_params\n");
+
+       mutex_lock(&chip->setup_mutex);
+
+       /* set dma buffer */
+       err = snd_pcm_lib_malloc_pages(substream,
+                                      params_buffer_bytes(hw_params));
+
+       if (is_capture)
+               chip->capture_stream.stream = substream;
+       else
+               chip->playback_stream.stream = substream;
+
+       mutex_unlock(&chip->setup_mutex);
+       return err;
+}
+
+static int lx_pcm_hw_params_playback(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *hw_params)
+{
+       return lx_pcm_hw_params(substream, hw_params, 0);
+}
+
+static int lx_pcm_hw_params_capture(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *hw_params)
+{
+       return lx_pcm_hw_params(substream, hw_params, 1);
+}
+
+static int lx_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       struct lx6464es *chip = snd_pcm_substream_chip(substream);
+       int err = 0;
+       int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+
+       snd_printdd("->lx_pcm_hw_free\n");
+       mutex_lock(&chip->setup_mutex);
+
+       if (chip->hardware_running[is_capture]) {
+               err = lx_hardware_stop(chip, substream);
+               if (err < 0) {
+                       snd_printk(KERN_ERR LXP "failed to stop hardware. "
+                                  "Error code %d\n", err);
+                       goto exit;
+               }
+
+               err = lx_hardware_close(chip, substream);
+               if (err < 0) {
+                       snd_printk(KERN_ERR LXP "failed to close hardware. "
+                                  "Error code %d\n", err);
+                       goto exit;
+               }
+
+               chip->hardware_running[is_capture] = 0;
+       }
+
+       err = snd_pcm_lib_free_pages(substream);
+
+       if (is_capture)
+               chip->capture_stream.stream = 0;
+       else
+               chip->playback_stream.stream = 0;
+
+exit:
+       mutex_unlock(&chip->setup_mutex);
+       return err;
+}
+
+static void lx_trigger_start(struct lx6464es *chip, struct lx_stream *lx_stream)
+{
+       struct snd_pcm_substream *substream = lx_stream->stream;
+       const int is_capture = lx_stream->is_capture;
+
+       int err;
+
+       const u32 channels = substream->runtime->channels;
+       const u32 bytes_per_frame = channels * 3;
+       const u32 period_size = substream->runtime->period_size;
+       const u32 periods = substream->runtime->periods;
+       const u32 period_bytes = period_size * bytes_per_frame;
+
+       dma_addr_t buf = substream->dma_buffer.addr;
+       int i;
+
+       u32 needed, freed;
+       u32 size_array[5];
+
+       for (i = 0; i != periods; ++i) {
+               u32 buffer_index = 0;
+
+               err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed,
+                                   size_array);
+               snd_printdd(LXP "starting: needed %d, freed %d\n",
+                           needed, freed);
+
+               err = lx_buffer_give(chip, 0, is_capture, period_bytes,
+                                    lower_32_bits(buf), upper_32_bits(buf),
+                                    &buffer_index);
+
+               snd_printdd(LXP "starting: buffer index %x on %p (%d bytes)\n",
+                           buffer_index, (void *)buf, period_bytes);
+               buf += period_bytes;
+       }
+
+       err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array);
+       snd_printdd(LXP "starting: needed %d, freed %d\n", needed, freed);
+
+       snd_printd(LXP "starting: starting stream\n");
+       err = lx_stream_start(chip, 0, is_capture);
+       if (err < 0)
+               snd_printk(KERN_ERR LXP "couldn't start stream\n");
+       else
+               lx_stream->status = LX_STREAM_STATUS_RUNNING;
+
+       lx_stream->frame_pos = 0;
+}
+
+static void lx_trigger_stop(struct lx6464es *chip, struct lx_stream *lx_stream)
+{
+       const int is_capture = lx_stream->is_capture;
+       int err;
+
+       snd_printd(LXP "stopping: stopping stream\n");
+       err = lx_stream_stop(chip, 0, is_capture);
+       if (err < 0)
+               snd_printk(KERN_ERR LXP "couldn't stop stream\n");
+       else
+               lx_stream->status = LX_STREAM_STATUS_FREE;
+
+}
+
+static void lx_trigger_tasklet_dispatch_stream(struct lx6464es *chip,
+                                              struct lx_stream *lx_stream)
+{
+       switch (lx_stream->status) {
+       case LX_STREAM_STATUS_SCHEDULE_RUN:
+               lx_trigger_start(chip, lx_stream);
+               break;
+
+       case LX_STREAM_STATUS_SCHEDULE_STOP:
+               lx_trigger_stop(chip, lx_stream);
+               break;
+
+       default:
+               break;
+       }
+}
+
+static void lx_trigger_tasklet(unsigned long data)
+{
+       struct lx6464es *chip = (struct lx6464es *)data;
+       unsigned long flags;
+
+       snd_printdd("->lx_trigger_tasklet\n");
+
+       spin_lock_irqsave(&chip->lock, flags);
+       lx_trigger_tasklet_dispatch_stream(chip, &chip->capture_stream);
+       lx_trigger_tasklet_dispatch_stream(chip, &chip->playback_stream);
+       spin_unlock_irqrestore(&chip->lock, flags);
+}
+
+static int lx_pcm_trigger_dispatch(struct lx6464es *chip,
+                                  struct lx_stream *lx_stream, int cmd)
+{
+       int err = 0;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               lx_stream->status = LX_STREAM_STATUS_SCHEDULE_RUN;
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+               lx_stream->status = LX_STREAM_STATUS_SCHEDULE_STOP;
+               break;
+
+       default:
+               err = -EINVAL;
+               goto exit;
+       }
+       tasklet_schedule(&chip->trigger_tasklet);
+
+exit:
+       return err;
+}
+
+
+static int lx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct lx6464es *chip = snd_pcm_substream_chip(substream);
+       const int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+       struct lx_stream *stream = is_capture ? &chip->capture_stream :
+               &chip->playback_stream;
+
+       snd_printdd("->lx_pcm_trigger\n");
+
+       return lx_pcm_trigger_dispatch(chip, stream, cmd);
+}
+
+static int snd_lx6464es_free(struct lx6464es *chip)
+{
+       snd_printdd("->snd_lx6464es_free\n");
+
+       lx_irq_disable(chip);
+
+       if (chip->irq >= 0)
+               free_irq(chip->irq, chip);
+
+       iounmap(chip->port_dsp_bar);
+       ioport_unmap(chip->port_plx_remapped);
+
+       pci_release_regions(chip->pci);
+       pci_disable_device(chip->pci);
+
+       kfree(chip);
+
+       return 0;
+}
+
+static int snd_lx6464es_dev_free(struct snd_device *device)
+{
+       return snd_lx6464es_free(device->device_data);
+}
+
+/* reset the dsp during initialization */
+static int __devinit lx_init_xilinx_reset(struct lx6464es *chip)
+{
+       int i;
+       u32 plx_reg = lx_plx_reg_read(chip, ePLX_CHIPSC);
+
+       snd_printdd("->lx_init_xilinx_reset\n");
+
+       /* activate reset of xilinx */
+       plx_reg &= ~CHIPSC_RESET_XILINX;
+
+       lx_plx_reg_write(chip, ePLX_CHIPSC, plx_reg);
+       msleep(1);
+
+       lx_plx_reg_write(chip, ePLX_MBOX3, 0);
+       msleep(1);
+
+       plx_reg |= CHIPSC_RESET_XILINX;
+       lx_plx_reg_write(chip, ePLX_CHIPSC, plx_reg);
+
+       /* deactivate reset of xilinx */
+       for (i = 0; i != 100; ++i) {
+               u32 reg_mbox3;
+               msleep(10);
+               reg_mbox3 = lx_plx_reg_read(chip, ePLX_MBOX3);
+               if (reg_mbox3) {
+                       snd_printd(LXP "xilinx reset done\n");
+                       snd_printdd(LXP "xilinx took %d loops\n", i);
+                       break;
+               }
+       }
+
+       /* todo: add some error handling? */
+
+       /* clear mr */
+       lx_dsp_reg_write(chip, eReg_CSM, 0);
+
+       /* le xilinx ES peut ne pas etre encore pret, on attend. */
+       msleep(600);
+
+       return 0;
+}
+
+static int __devinit lx_init_xilinx_test(struct lx6464es *chip)
+{
+       u32 reg;
+
+       snd_printdd("->lx_init_xilinx_test\n");
+
+       /* TEST if we have access to Xilinx/MicroBlaze */
+       lx_dsp_reg_write(chip, eReg_CSM, 0);
+
+       reg = lx_dsp_reg_read(chip, eReg_CSM);
+
+       if (reg) {
+               snd_printk(KERN_ERR LXP "Problem: Reg_CSM %x.\n", reg);
+
+               /* PCI9056_SPACE0_REMAP */
+               lx_plx_reg_write(chip, ePLX_PCICR, 1);
+
+               reg = lx_dsp_reg_read(chip, eReg_CSM);
+               if (reg) {
+                       snd_printk(KERN_ERR LXP "Error: Reg_CSM %x.\n", reg);
+                       return -EAGAIN; /* seems to be appropriate */
+               }
+       }
+
+       snd_printd(LXP "Xilinx/MicroBlaze access test successful\n");
+
+       return 0;
+}
+
+/* initialize ethersound */
+static int __devinit lx_init_ethersound_config(struct lx6464es *chip)
+{
+       int i;
+       u32 orig_conf_es = lx_dsp_reg_read(chip, eReg_CONFES);
+
+       u32 default_conf_es = (64 << IOCR_OUTPUTS_OFFSET) |
+               (64 << IOCR_INPUTS_OFFSET) |
+               (FREQ_RATIO_SINGLE_MODE << FREQ_RATIO_OFFSET);
+
+       u32 conf_es = (orig_conf_es & CONFES_READ_PART_MASK)
+               | (default_conf_es & CONFES_WRITE_PART_MASK);
+
+       snd_printdd("->lx_init_ethersound\n");
+
+       chip->freq_ratio = FREQ_RATIO_SINGLE_MODE;
+
+       /*
+        * write it to the card !
+        * this actually kicks the ES xilinx, the first time since poweron.
+        * the MAC address in the Reg_ADMACESMSB Reg_ADMACESLSB registers
+        * is not ready before this is done, and the bit 2 in Reg_CSES is set.
+        * */
+       lx_dsp_reg_write(chip, eReg_CONFES, conf_es);
+
+       for (i = 0; i != 1000; ++i) {
+               if (lx_dsp_reg_read(chip, eReg_CSES) & 4) {
+                       snd_printd(LXP "ethersound initialized after %dms\n",
+                                  i);
+                       goto ethersound_initialized;
+               }
+               msleep(1);
+       }
+       snd_printk(KERN_WARNING LXP
+                  "ethersound could not be initialized after %dms\n", i);
+       return -ETIMEDOUT;
+
+ ethersound_initialized:
+       snd_printd(LXP "ethersound initialized\n");
+       return 0;
+}
+
+static int __devinit lx_init_get_version_features(struct lx6464es *chip)
+{
+       u32 dsp_version;
+
+       int err;
+
+       snd_printdd("->lx_init_get_version_features\n");
+
+       err = lx_dsp_get_version(chip, &dsp_version);
+
+       if (err == 0) {
+               u32 freq;
+
+               snd_printk(LXP "DSP version: V%02d.%02d #%d\n",
+                          (dsp_version>>16) & 0xff, (dsp_version>>8) & 0xff,
+                          dsp_version & 0xff);
+
+               /* later: what firmware version do we expect? */
+
+               /* retrieve Play/Rec features */
+               /* done here because we may have to handle alternate
+                * DSP files. */
+               /* later */
+
+               /* init the EtherSound sample rate */
+               err = lx_dsp_get_clock_frequency(chip, &freq);
+               if (err == 0)
+                       chip->board_sample_rate = freq;
+               snd_printd(LXP "actual clock frequency %d\n", freq);
+       } else {
+               snd_printk(KERN_ERR LXP "DSP corrupted \n");
+               err = -EAGAIN;
+       }
+
+       return err;
+}
+
+static int lx_set_granularity(struct lx6464es *chip, u32 gran)
+{
+       int err = 0;
+       u32 snapped_gran = MICROBLAZE_IBL_MIN;
+
+       snd_printdd("->lx_set_granularity\n");
+
+       /* blocksize is a power of 2 */
+       while ((snapped_gran < gran) &&
+              (snapped_gran < MICROBLAZE_IBL_MAX)) {
+               snapped_gran *= 2;
+       }
+
+       if (snapped_gran == chip->pcm_granularity)
+               return 0;
+
+       err = lx_dsp_set_granularity(chip, snapped_gran);
+       if (err < 0) {
+               snd_printk(KERN_WARNING LXP "could not set granularity\n");
+               err = -EAGAIN;
+       }
+
+       if (snapped_gran != gran)
+               snd_printk(LXP "snapped blocksize to %d\n", snapped_gran);
+
+       snd_printd(LXP "set blocksize on board %d\n", snapped_gran);
+       chip->pcm_granularity = snapped_gran;
+
+       return err;
+}
+
+/* initialize and test the xilinx dsp chip */
+static int __devinit lx_init_dsp(struct lx6464es *chip)
+{
+       int err;
+       u8 mac_address[6];
+       int i;
+
+       snd_printdd("->lx_init_dsp\n");
+
+       snd_printd(LXP "initialize board\n");
+       err = lx_init_xilinx_reset(chip);
+       if (err)
+               return err;
+
+       snd_printd(LXP "testing board\n");
+       err = lx_init_xilinx_test(chip);
+       if (err)
+               return err;
+
+       snd_printd(LXP "initialize ethersound configuration\n");
+       err = lx_init_ethersound_config(chip);
+       if (err)
+               return err;
+
+       lx_irq_enable(chip);
+
+       /** \todo the mac address should be ready by not, but it isn't,
+        *  so we wait for it */
+       for (i = 0; i != 1000; ++i) {
+               err = lx_dsp_get_mac(chip, mac_address);
+               if (err)
+                       return err;
+               if (mac_address[0] || mac_address[1] || mac_address[2] ||
+                   mac_address[3] || mac_address[4] || mac_address[5])
+                       goto mac_ready;
+               msleep(1);
+       }
+       return -ETIMEDOUT;
+
+mac_ready:
+       snd_printd(LXP "mac address ready read after: %dms\n", i);
+       snd_printk(LXP "mac address: %02X.%02X.%02X.%02X.%02X.%02X\n",
+                  mac_address[0], mac_address[1], mac_address[2],
+                  mac_address[3], mac_address[4], mac_address[5]);
+
+       err = lx_init_get_version_features(chip);
+       if (err)
+               return err;
+
+       lx_set_granularity(chip, MICROBLAZE_IBL_DEFAULT);
+
+       chip->playback_mute = 0;
+
+       return err;
+}
+
+static struct snd_pcm_ops lx_ops_playback = {
+       .open      = lx_pcm_open,
+       .close     = lx_pcm_close,
+       .ioctl     = snd_pcm_lib_ioctl,
+       .prepare   = lx_pcm_prepare,
+       .hw_params = lx_pcm_hw_params_playback,
+       .hw_free   = lx_pcm_hw_free,
+       .trigger   = lx_pcm_trigger,
+       .pointer   = lx_pcm_stream_pointer,
+};
+
+static struct snd_pcm_ops lx_ops_capture = {
+       .open      = lx_pcm_open,
+       .close     = lx_pcm_close,
+       .ioctl     = snd_pcm_lib_ioctl,
+       .prepare   = lx_pcm_prepare,
+       .hw_params = lx_pcm_hw_params_capture,
+       .hw_free   = lx_pcm_hw_free,
+       .trigger   = lx_pcm_trigger,
+       .pointer   = lx_pcm_stream_pointer,
+};
+
+static int __devinit lx_pcm_create(struct lx6464es *chip)
+{
+       int err;
+       struct snd_pcm *pcm;
+
+       u32 size = 64 *              /* channels */
+               3 *                  /* 24 bit samples */
+               MAX_STREAM_BUFFER *  /* periods */
+               MICROBLAZE_IBL_MAX * /* frames per period */
+               2;                   /* duplex */
+
+       size = PAGE_ALIGN(size);
+
+       /* hardcoded device name & channel count */
+       err = snd_pcm_new(chip->card, (char *)card_name, 0,
+                         1, 1, &pcm);
+
+       pcm->private_data = chip;
+
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &lx_ops_playback);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &lx_ops_capture);
+
+       pcm->info_flags = 0;
+       strcpy(pcm->name, card_name);
+
+       err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+                                                   snd_dma_pci_data(chip->pci),
+                                                   size, size);
+       if (err < 0)
+               return err;
+
+       chip->pcm = pcm;
+       chip->capture_stream.is_capture = 1;
+
+       return 0;
+}
+
+static int lx_control_playback_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 lx_control_playback_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct lx6464es *chip = snd_kcontrol_chip(kcontrol);
+       ucontrol->value.integer.value[0] = chip->playback_mute;
+       return 0;
+}
+
+static int lx_control_playback_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct lx6464es *chip = snd_kcontrol_chip(kcontrol);
+       int changed = 0;
+       int current_value = chip->playback_mute;
+
+       if (current_value != ucontrol->value.integer.value[0]) {
+               lx_level_unmute(chip, 0, !current_value);
+               chip->playback_mute = !current_value;
+               changed = 1;
+       }
+       return changed;
+}
+
+static struct snd_kcontrol_new lx_control_playback_switch __devinitdata = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "PCM Playback Switch",
+       .index = 0,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .private_value = 0,
+       .info = lx_control_playback_info,
+       .get = lx_control_playback_get,
+       .put = lx_control_playback_put
+};
+
+
+
+static void lx_proc_levels_read(struct snd_info_entry *entry,
+                               struct snd_info_buffer *buffer)
+{
+       u32 levels[64];
+       int err;
+       int i, j;
+       struct lx6464es *chip = entry->private_data;
+
+       snd_iprintf(buffer, "capture levels:\n");
+       err = lx_level_peaks(chip, 1, 64, levels);
+       if (err < 0)
+               return;
+
+       for (i = 0; i != 8; ++i) {
+               for (j = 0; j != 8; ++j)
+                       snd_iprintf(buffer, "%08x ", levels[i*8+j]);
+               snd_iprintf(buffer, "\n");
+       }
+
+       snd_iprintf(buffer, "\nplayback levels:\n");
+
+       err = lx_level_peaks(chip, 0, 64, levels);
+       if (err < 0)
+               return;
+
+       for (i = 0; i != 8; ++i) {
+               for (j = 0; j != 8; ++j)
+                       snd_iprintf(buffer, "%08x ", levels[i*8+j]);
+               snd_iprintf(buffer, "\n");
+       }
+
+       snd_iprintf(buffer, "\n");
+}
+
+static int __devinit lx_proc_create(struct snd_card *card, struct lx6464es *chip)
+{
+       struct snd_info_entry *entry;
+       int err = snd_card_proc_new(card, "levels", &entry);
+       if (err < 0)
+               return err;
+
+       snd_info_set_text_ops(entry, chip, lx_proc_levels_read);
+       return 0;
+}
+
+
+static int __devinit snd_lx6464es_create(struct snd_card *card,
+                                        struct pci_dev *pci,
+                                        struct lx6464es **rchip)
+{
+       struct lx6464es *chip;
+       int err;
+
+       static struct snd_device_ops ops = {
+               .dev_free = snd_lx6464es_dev_free,
+       };
+
+       snd_printdd("->snd_lx6464es_create\n");
+
+       *rchip = NULL;
+
+       /* enable PCI device */
+       err = pci_enable_device(pci);
+       if (err < 0)
+               return err;
+
+       pci_set_master(pci);
+
+       /* check if we can restrict PCI DMA transfers to 32 bits */
+       err = pci_set_dma_mask(pci, DMA_32BIT_MASK);
+       if (err < 0) {
+               snd_printk(KERN_ERR "architecture does not support "
+                          "32bit PCI busmaster DMA\n");
+               pci_disable_device(pci);
+               return -ENXIO;
+       }
+
+       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       if (chip == NULL) {
+               err = -ENOMEM;
+               goto alloc_failed;
+       }
+
+       chip->card = card;
+       chip->pci = pci;
+       chip->irq = -1;
+
+       /* initialize synchronization structs */
+       spin_lock_init(&chip->lock);
+       spin_lock_init(&chip->msg_lock);
+       mutex_init(&chip->setup_mutex);
+       tasklet_init(&chip->trigger_tasklet, lx_trigger_tasklet,
+                    (unsigned long)chip);
+       tasklet_init(&chip->tasklet_capture, lx_tasklet_capture,
+                    (unsigned long)chip);
+       tasklet_init(&chip->tasklet_playback, lx_tasklet_playback,
+                    (unsigned long)chip);
+
+       /* request resources */
+       err = pci_request_regions(pci, card_name);
+       if (err < 0)
+               goto request_regions_failed;
+
+       /* plx port */
+       chip->port_plx = pci_resource_start(pci, 1);
+       chip->port_plx_remapped = ioport_map(chip->port_plx,
+                                            pci_resource_len(pci, 1));
+
+       /* dsp port */
+       chip->port_dsp_bar = pci_ioremap_bar(pci, 2);
+
+       err = request_irq(pci->irq, lx_interrupt, IRQF_SHARED,
+                         card_name, chip);
+       if (err) {
+               snd_printk(KERN_ERR LXP "unable to grab IRQ %d\n", pci->irq);
+               goto request_irq_failed;
+       }
+       chip->irq = pci->irq;
+
+       err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+       if (err < 0)
+               goto device_new_failed;
+
+       err = lx_init_dsp(chip);
+       if (err < 0) {
+               snd_printk(KERN_ERR LXP "error during DSP initialization\n");
+               return err;
+       }
+
+       err = lx_pcm_create(chip);
+       if (err < 0)
+               return err;
+
+       err = lx_proc_create(card, chip);
+       if (err < 0)
+               return err;
+
+       err = snd_ctl_add(card, snd_ctl_new1(&lx_control_playback_switch,
+                                            chip));
+       if (err < 0)
+               return err;
+
+       snd_card_set_dev(card, &pci->dev);
+
+       *rchip = chip;
+       return 0;
+
+device_new_failed:
+       free_irq(pci->irq, chip);
+
+request_irq_failed:
+       pci_release_regions(pci);
+
+request_regions_failed:
+       kfree(chip);
+
+alloc_failed:
+       pci_disable_device(pci);
+
+       return err;
+}
+
+static int __devinit snd_lx6464es_probe(struct pci_dev *pci,
+                                       const struct pci_device_id *pci_id)
+{
+       static int dev;
+       struct snd_card *card;
+       struct lx6464es *chip;
+       int err;
+
+       snd_printdd("->snd_lx6464es_probe\n");
+
+       if (dev >= SNDRV_CARDS)
+               return -ENODEV;
+       if (!enable[dev]) {
+               dev++;
+               return -ENOENT;
+       }
+
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
+
+       err = snd_lx6464es_create(card, pci, &chip);
+       if (err < 0) {
+               snd_printk(KERN_ERR LXP "error during snd_lx6464es_create\n");
+               goto out_free;
+       }
+
+       strcpy(card->driver, "lx6464es");
+       strcpy(card->shortname, "Digigram LX6464ES");
+       sprintf(card->longname, "%s at 0x%lx, 0x%p, irq %i",
+               card->shortname, chip->port_plx,
+               chip->port_dsp_bar, chip->irq);
+
+       err = snd_card_register(card);
+       if (err < 0)
+               goto out_free;
+
+       snd_printdd(LXP "initialization successful\n");
+       pci_set_drvdata(pci, card);
+       dev++;
+       return 0;
+
+out_free:
+       snd_card_free(card);
+       return err;
+
+}
+
+static void __devexit snd_lx6464es_remove(struct pci_dev *pci)
+{
+       snd_card_free(pci_get_drvdata(pci));
+       pci_set_drvdata(pci, NULL);
+}
+
+
+static struct pci_driver driver = {
+       .name =     "Digigram LX6464ES",
+       .id_table = snd_lx6464es_ids,
+       .probe =    snd_lx6464es_probe,
+       .remove = __devexit_p(snd_lx6464es_remove),
+};
+
+
+/* module initialization */
+static int __init mod_init(void)
+{
+       return pci_register_driver(&driver);
+}
+
+static void __exit mod_exit(void)
+{
+       pci_unregister_driver(&driver);
+}
+
+module_init(mod_init);
+module_exit(mod_exit);
diff --git a/sound/pci/lx6464es/lx6464es.h b/sound/pci/lx6464es/lx6464es.h
new file mode 100644 (file)
index 0000000..012c010
--- /dev/null
@@ -0,0 +1,114 @@
+/* -*- linux-c -*- *
+ *
+ * ALSA driver for the digigram lx6464es interface
+ *
+ * Copyright (c) 2009 Tim Blechmann <tim@klingt.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; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef LX6464ES_H
+#define LX6464ES_H
+
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+
+#include "lx_core.h"
+
+#define LXP "LX6464ES: "
+
+enum {
+    ES_cmd_free         = 0,    /* no command executing */
+    ES_cmd_processing   = 1,   /* execution of a read/write command */
+    ES_read_pending     = 2,    /* a asynchron read command is pending */
+    ES_read_finishing   = 3,    /* a read command has finished waiting (set by
+                                * Interrupt or CancelIrp) */
+};
+
+enum lx_stream_status {
+       LX_STREAM_STATUS_FREE,
+/*     LX_STREAM_STATUS_OPEN, */
+       LX_STREAM_STATUS_SCHEDULE_RUN,
+/*     LX_STREAM_STATUS_STARTED, */
+       LX_STREAM_STATUS_RUNNING,
+       LX_STREAM_STATUS_SCHEDULE_STOP,
+/*     LX_STREAM_STATUS_STOPPED, */
+/*     LX_STREAM_STATUS_PAUSED */
+};
+
+
+struct lx_stream {
+       struct snd_pcm_substream  *stream;
+       snd_pcm_uframes_t          frame_pos;
+       enum lx_stream_status      status; /* free, open, running, draining
+                                           * pause */
+       int                        is_capture:1;
+};
+
+
+struct lx6464es {
+       struct snd_card        *card;
+       struct pci_dev         *pci;
+       int                     irq;
+
+       spinlock_t              lock;        /* interrupt spinlock */
+       struct mutex            setup_mutex; /* mutex used in hw_params, open
+                                             * and close */
+
+       struct tasklet_struct   trigger_tasklet; /* trigger tasklet */
+       struct tasklet_struct   tasklet_capture;
+       struct tasklet_struct   tasklet_playback;
+
+       /* ports */
+       unsigned long           port_plx;          /* io port (size=256) */
+       void __iomem           *port_plx_remapped; /* remapped plx port */
+       void __iomem           *port_dsp_bar;      /* memory port (32-bit,
+                                                   * non-prefetchable,
+                                                   * size=8K) */
+
+       /* messaging */
+       spinlock_t              msg_lock;          /* message spinlock */
+       atomic_t                send_message_locked;
+       struct lx_rmh           rmh;
+
+       /* configuration */
+       uint                    freq_ratio : 2;
+       uint                    playback_mute : 1;
+       uint                    hardware_running[2];
+       u32                     board_sample_rate; /* sample rate read from
+                                                   * board */
+       u32                     sample_rate;       /* our sample rate */
+       u16                     pcm_granularity;   /* board blocksize */
+
+       /* dma */
+       struct snd_dma_buffer   capture_dma_buf;
+       struct snd_dma_buffer   playback_dma_buf;
+
+       /* pcm */
+       struct snd_pcm         *pcm;
+
+       /* streams */
+       struct lx_stream        capture_stream;
+       struct lx_stream        playback_stream;
+};
+
+
+#endif /* LX6464ES_H */
diff --git a/sound/pci/lx6464es/lx_core.c b/sound/pci/lx6464es/lx_core.c
new file mode 100644 (file)
index 0000000..5812780
--- /dev/null
@@ -0,0 +1,1444 @@
+/* -*- linux-c -*- *
+ *
+ * ALSA driver for the digigram lx6464es interface
+ * low-level interface
+ *
+ * Copyright (c) 2009 Tim Blechmann <tim@klingt.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; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+/* #define RMH_DEBUG 1 */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "lx6464es.h"
+#include "lx_core.h"
+
+/* low-level register access */
+
+static const unsigned long dsp_port_offsets[] = {
+       0,
+       0x400,
+       0x401,
+       0x402,
+       0x403,
+       0x404,
+       0x405,
+       0x406,
+       0x407,
+       0x408,
+       0x409,
+       0x40a,
+       0x40b,
+       0x40c,
+
+       0x410,
+       0x411,
+       0x412,
+       0x413,
+       0x414,
+       0x415,
+       0x416,
+
+       0x420,
+       0x430,
+       0x431,
+       0x432,
+       0x433,
+       0x434,
+       0x440
+};
+
+static void __iomem *lx_dsp_register(struct lx6464es *chip, int port)
+{
+       void __iomem *base_address = chip->port_dsp_bar;
+       return base_address + dsp_port_offsets[port]*4;
+}
+
+unsigned long lx_dsp_reg_read(struct lx6464es *chip, int port)
+{
+       void __iomem *address = lx_dsp_register(chip, port);
+       return ioread32(address);
+}
+
+void lx_dsp_reg_readbuf(struct lx6464es *chip, int port, u32 *data, u32 len)
+{
+       void __iomem *address = lx_dsp_register(chip, port);
+       memcpy_fromio(data, address, len*sizeof(u32));
+}
+
+
+void lx_dsp_reg_write(struct lx6464es *chip, int port, unsigned data)
+{
+       void __iomem *address = lx_dsp_register(chip, port);
+       iowrite32(data, address);
+}
+
+void lx_dsp_reg_writebuf(struct lx6464es *chip, int port, const u32 *data,
+                        u32 len)
+{
+       void __iomem *address = lx_dsp_register(chip, port);
+       memcpy_toio(address, data, len*sizeof(u32));
+}
+
+
+static const unsigned long plx_port_offsets[] = {
+       0x04,
+       0x40,
+       0x44,
+       0x48,
+       0x4c,
+       0x50,
+       0x54,
+       0x58,
+       0x5c,
+       0x64,
+       0x68,
+       0x6C
+};
+
+static void __iomem *lx_plx_register(struct lx6464es *chip, int port)
+{
+       void __iomem *base_address = chip->port_plx_remapped;
+       return base_address + plx_port_offsets[port];
+}
+
+unsigned long lx_plx_reg_read(struct lx6464es *chip, int port)
+{
+       void __iomem *address = lx_plx_register(chip, port);
+       return ioread32(address);
+}
+
+void lx_plx_reg_write(struct lx6464es *chip, int port, u32 data)
+{
+       void __iomem *address = lx_plx_register(chip, port);
+       iowrite32(data, address);
+}
+
+u32 lx_plx_mbox_read(struct lx6464es *chip, int mbox_nr)
+{
+       int index;
+
+       switch (mbox_nr) {
+       case 1:
+               index = ePLX_MBOX1;    break;
+       case 2:
+               index = ePLX_MBOX2;    break;
+       case 3:
+               index = ePLX_MBOX3;    break;
+       case 4:
+               index = ePLX_MBOX4;    break;
+       case 5:
+               index = ePLX_MBOX5;    break;
+       case 6:
+               index = ePLX_MBOX6;    break;
+       case 7:
+               index = ePLX_MBOX7;    break;
+       case 0:                 /* reserved for HF flags */
+               snd_BUG();
+       default:
+               return 0xdeadbeef;
+       }
+
+       return lx_plx_reg_read(chip, index);
+}
+
+int lx_plx_mbox_write(struct lx6464es *chip, int mbox_nr, u32 value)
+{
+       int index = -1;
+
+       switch (mbox_nr) {
+       case 1:
+               index = ePLX_MBOX1;    break;
+       case 3:
+               index = ePLX_MBOX3;    break;
+       case 4:
+               index = ePLX_MBOX4;    break;
+       case 5:
+               index = ePLX_MBOX5;    break;
+       case 6:
+               index = ePLX_MBOX6;    break;
+       case 7:
+               index = ePLX_MBOX7;    break;
+       case 0:                 /* reserved for HF flags */
+       case 2:                 /* reserved for Pipe States
+                                * the DSP keeps an image of it */
+               snd_BUG();
+               return -EBADRQC;
+       }
+
+       lx_plx_reg_write(chip, index, value);
+       return 0;
+}
+
+
+/* rmh */
+
+#ifdef CONFIG_SND_DEBUG
+#define CMD_NAME(a) a
+#else
+#define CMD_NAME(a) NULL
+#endif
+
+#define Reg_CSM_MR                     0x00000002
+#define Reg_CSM_MC                     0x00000001
+
+struct dsp_cmd_info {
+       u32    dcCodeOp;        /* Op Code of the command (usually 1st 24-bits
+                                * word).*/
+       u16    dcCmdLength;     /* Command length in words of 24 bits.*/
+       u16    dcStatusType;    /* Status type: 0 for fixed length, 1 for
+                                * random. */
+       u16    dcStatusLength;  /* Status length (if fixed).*/
+       char  *dcOpName;
+};
+
+/*
+  Initialization and control data for the Microblaze interface
+  - OpCode:
+    the opcode field of the command set at the proper offset
+  - CmdLength
+    the number of command words
+  - StatusType
+    offset in the status registers: 0 means that the return value may be
+    different from 0, and must be read
+  - StatusLength
+    the number of status words (in addition to the return value)
+*/
+
+static struct dsp_cmd_info dsp_commands[] =
+{
+       { (CMD_00_INFO_DEBUG << OPCODE_OFFSET)                  , 1 /*custom*/
+         , 1   , 0 /**/                    , CMD_NAME("INFO_DEBUG") },
+       { (CMD_01_GET_SYS_CFG << OPCODE_OFFSET)                 , 1 /**/
+         , 1      , 2 /**/                 , CMD_NAME("GET_SYS_CFG") },
+       { (CMD_02_SET_GRANULARITY << OPCODE_OFFSET)             , 1 /**/
+         , 1      , 0 /**/                 , CMD_NAME("SET_GRANULARITY") },
+       { (CMD_03_SET_TIMER_IRQ << OPCODE_OFFSET)               , 1 /**/
+         , 1      , 0 /**/                 , CMD_NAME("SET_TIMER_IRQ") },
+       { (CMD_04_GET_EVENT << OPCODE_OFFSET)                   , 1 /**/
+         , 1      , 0 /*up to 10*/     , CMD_NAME("GET_EVENT") },
+       { (CMD_05_GET_PIPES << OPCODE_OFFSET)                   , 1 /**/
+         , 1      , 2 /*up to 4*/      , CMD_NAME("GET_PIPES") },
+       { (CMD_06_ALLOCATE_PIPE << OPCODE_OFFSET)               , 1 /**/
+         , 0      , 0 /**/                 , CMD_NAME("ALLOCATE_PIPE") },
+       { (CMD_07_RELEASE_PIPE << OPCODE_OFFSET)                , 1 /**/
+         , 0      , 0 /**/                 , CMD_NAME("RELEASE_PIPE") },
+       { (CMD_08_ASK_BUFFERS << OPCODE_OFFSET)                 , 1 /**/
+         , 1      , MAX_STREAM_BUFFER  , CMD_NAME("ASK_BUFFERS") },
+       { (CMD_09_STOP_PIPE << OPCODE_OFFSET)                   , 1 /**/
+         , 0      , 0 /*up to 2*/      , CMD_NAME("STOP_PIPE") },
+       { (CMD_0A_GET_PIPE_SPL_COUNT << OPCODE_OFFSET)          , 1 /**/
+         , 1      , 1 /*up to 2*/      , CMD_NAME("GET_PIPE_SPL_COUNT") },
+       { (CMD_0B_TOGGLE_PIPE_STATE << OPCODE_OFFSET)           , 1 /*up to 5*/
+         , 1      , 0 /**/                 , CMD_NAME("TOGGLE_PIPE_STATE") },
+       { (CMD_0C_DEF_STREAM << OPCODE_OFFSET)                  , 1 /*up to 4*/
+         , 1      , 0 /**/                 , CMD_NAME("DEF_STREAM") },
+       { (CMD_0D_SET_MUTE  << OPCODE_OFFSET)                   , 3 /**/
+         , 1      , 0 /**/                 , CMD_NAME("SET_MUTE") },
+       { (CMD_0E_GET_STREAM_SPL_COUNT << OPCODE_OFFSET)        , 1/**/
+         , 1      , 2 /**/                 , CMD_NAME("GET_STREAM_SPL_COUNT") },
+       { (CMD_0F_UPDATE_BUFFER << OPCODE_OFFSET)               , 3 /*up to 4*/
+         , 0      , 1 /**/                 , CMD_NAME("UPDATE_BUFFER") },
+       { (CMD_10_GET_BUFFER << OPCODE_OFFSET)                  , 1 /**/
+         , 1      , 4 /**/                 , CMD_NAME("GET_BUFFER") },
+       { (CMD_11_CANCEL_BUFFER << OPCODE_OFFSET)               , 1 /**/
+         , 1      , 1 /*up to 4*/      , CMD_NAME("CANCEL_BUFFER") },
+       { (CMD_12_GET_PEAK << OPCODE_OFFSET)                    , 1 /**/
+         , 1      , 1 /**/                 , CMD_NAME("GET_PEAK") },
+       { (CMD_13_SET_STREAM_STATE << OPCODE_OFFSET)            , 1 /**/
+         , 1      , 0 /**/                 , CMD_NAME("SET_STREAM_STATE") },
+};
+
+static void lx_message_init(struct lx_rmh *rmh, enum cmd_mb_opcodes cmd)
+{
+       snd_BUG_ON(cmd >= CMD_14_INVALID);
+
+       rmh->cmd[0] = dsp_commands[cmd].dcCodeOp;
+       rmh->cmd_len = dsp_commands[cmd].dcCmdLength;
+       rmh->stat_len = dsp_commands[cmd].dcStatusLength;
+       rmh->dsp_stat = dsp_commands[cmd].dcStatusType;
+       rmh->cmd_idx = cmd;
+       memset(&rmh->cmd[1], 0, (REG_CRM_NUMBER - 1) * sizeof(u32));
+
+#ifdef CONFIG_SND_DEBUG
+       memset(rmh->stat, 0, REG_CRM_NUMBER * sizeof(u32));
+#endif
+#ifdef RMH_DEBUG
+       rmh->cmd_idx = cmd;
+#endif
+}
+
+#ifdef RMH_DEBUG
+#define LXRMH "lx6464es rmh: "
+static void lx_message_dump(struct lx_rmh *rmh)
+{
+       u8 idx = rmh->cmd_idx;
+       int i;
+
+       snd_printk(LXRMH "command %s\n", dsp_commands[idx].dcOpName);
+
+       for (i = 0; i != rmh->cmd_len; ++i)
+               snd_printk(LXRMH "\tcmd[%d] %08x\n", i, rmh->cmd[i]);
+
+       for (i = 0; i != rmh->stat_len; ++i)
+               snd_printk(LXRMH "\tstat[%d]: %08x\n", i, rmh->stat[i]);
+       snd_printk("\n");
+}
+#else
+static inline void lx_message_dump(struct lx_rmh *rmh)
+{}
+#endif
+
+
+
+/* sleep 500 - 100 = 400 times 100us -> the timeout is >= 40 ms */
+#define XILINX_TIMEOUT_MS       40
+#define XILINX_POLL_NO_SLEEP    100
+#define XILINX_POLL_ITERATIONS  150
+
+#if 0 /* not used now */
+static int lx_message_send(struct lx6464es *chip, struct lx_rmh *rmh)
+{
+       u32 reg = ED_DSP_TIMED_OUT;
+       int dwloop;
+       int answer_received;
+
+       if (lx_dsp_reg_read(chip, eReg_CSM) & (Reg_CSM_MC | Reg_CSM_MR)) {
+               snd_printk(KERN_ERR LXP "PIOSendMessage eReg_CSM %x\n", reg);
+               return -EBUSY;
+       }
+
+       /* write command */
+       lx_dsp_reg_writebuf(chip, eReg_CRM1, rmh->cmd, rmh->cmd_len);
+
+       snd_BUG_ON(atomic_read(&chip->send_message_locked) != 0);
+       atomic_set(&chip->send_message_locked, 1);
+
+       /* MicoBlaze gogogo */
+       lx_dsp_reg_write(chip, eReg_CSM, Reg_CSM_MC);
+
+       /* wait for interrupt to answer */
+       for (dwloop = 0; dwloop != XILINX_TIMEOUT_MS; ++dwloop) {
+               answer_received = atomic_read(&chip->send_message_locked);
+               if (answer_received == 0)
+                       break;
+               msleep(1);
+       }
+
+       if (answer_received == 0) {
+               /* in Debug mode verify Reg_CSM_MR */
+               snd_BUG_ON(!(lx_dsp_reg_read(chip, eReg_CSM) & Reg_CSM_MR));
+
+               /* command finished, read status */
+               if (rmh->dsp_stat == 0)
+                       reg = lx_dsp_reg_read(chip, eReg_CRM1);
+               else
+                       reg = 0;
+       } else {
+               int i;
+               snd_printk(KERN_WARNING LXP "TIMEOUT lx_message_send! "
+                          "Interrupts disabled?\n");
+
+               /* attente bit Reg_CSM_MR */
+               for (i = 0; i != XILINX_POLL_ITERATIONS; i++) {
+                       if ((lx_dsp_reg_read(chip, eReg_CSM) & Reg_CSM_MR)) {
+                               if (rmh->dsp_stat == 0)
+                                       reg = lx_dsp_reg_read(chip, eReg_CRM1);
+                               else
+                                       reg = 0;
+                               goto polling_successful;
+                       }
+
+                       if (i > XILINX_POLL_NO_SLEEP)
+                               msleep(1);
+               }
+               snd_printk(KERN_WARNING LXP "TIMEOUT lx_message_send! "
+                          "polling failed\n");
+
+polling_successful:
+               atomic_set(&chip->send_message_locked, 0);
+       }
+
+       if ((reg & ERROR_VALUE) == 0) {
+               /* read response */
+               if (rmh->stat_len) {
+                       snd_BUG_ON(rmh->stat_len >= (REG_CRM_NUMBER-1));
+
+                       lx_dsp_reg_readbuf(chip, eReg_CRM2, rmh->stat,
+                                          rmh->stat_len);
+               }
+       } else
+               snd_printk(KERN_WARNING LXP "lx_message_send: error_value %x\n",
+                          reg);
+
+       /* clear Reg_CSM_MR */
+       lx_dsp_reg_write(chip, eReg_CSM, 0);
+
+       switch (reg) {
+       case ED_DSP_TIMED_OUT:
+               snd_printk(KERN_WARNING LXP "lx_message_send: dsp timeout\n");
+               return -ETIMEDOUT;
+
+       case ED_DSP_CRASHED:
+               snd_printk(KERN_WARNING LXP "lx_message_send: dsp crashed\n");
+               return -EAGAIN;
+       }
+
+       lx_message_dump(rmh);
+       return 0;
+}
+#endif /* not used now */
+
+static int lx_message_send_atomic(struct lx6464es *chip, struct lx_rmh *rmh)
+{
+       u32 reg = ED_DSP_TIMED_OUT;
+       int dwloop;
+
+       if (lx_dsp_reg_read(chip, eReg_CSM) & (Reg_CSM_MC | Reg_CSM_MR)) {
+               snd_printk(KERN_ERR LXP "PIOSendMessage eReg_CSM %x\n", reg);
+               return -EBUSY;
+       }
+
+       /* write command */
+       lx_dsp_reg_writebuf(chip, eReg_CRM1, rmh->cmd, rmh->cmd_len);
+
+       /* MicoBlaze gogogo */
+       lx_dsp_reg_write(chip, eReg_CSM, Reg_CSM_MC);
+
+       /* wait for interrupt to answer */
+       for (dwloop = 0; dwloop != XILINX_TIMEOUT_MS * 1000; ++dwloop) {
+               if (lx_dsp_reg_read(chip, eReg_CSM) & Reg_CSM_MR) {
+                       if (rmh->dsp_stat == 0)
+                               reg = lx_dsp_reg_read(chip, eReg_CRM1);
+                       else
+                               reg = 0;
+                       goto polling_successful;
+               } else
+                       udelay(1);
+       }
+       snd_printk(KERN_WARNING LXP "TIMEOUT lx_message_send_atomic! "
+                  "polling failed\n");
+
+polling_successful:
+       if ((reg & ERROR_VALUE) == 0) {
+               /* read response */
+               if (rmh->stat_len) {
+                       snd_BUG_ON(rmh->stat_len >= (REG_CRM_NUMBER-1));
+                       lx_dsp_reg_readbuf(chip, eReg_CRM2, rmh->stat,
+                                          rmh->stat_len);
+               }
+       } else
+               snd_printk(LXP "rmh error: %08x\n", reg);
+
+       /* clear Reg_CSM_MR */
+       lx_dsp_reg_write(chip, eReg_CSM, 0);
+
+       switch (reg) {
+       case ED_DSP_TIMED_OUT:
+               snd_printk(KERN_WARNING LXP "lx_message_send: dsp timeout\n");
+               return -ETIMEDOUT;
+
+       case ED_DSP_CRASHED:
+               snd_printk(KERN_WARNING LXP "lx_message_send: dsp crashed\n");
+               return -EAGAIN;
+       }
+
+       lx_message_dump(rmh);
+
+       return reg;
+}
+
+
+/* low-level dsp access */
+int __devinit lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version)
+{
+       u16 ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&chip->msg_lock, flags);
+
+       lx_message_init(&chip->rmh, CMD_01_GET_SYS_CFG);
+       ret = lx_message_send_atomic(chip, &chip->rmh);
+
+       *rdsp_version = chip->rmh.stat[1];
+       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       return ret;
+}
+
+int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq)
+{
+       u16 ret = 0;
+       unsigned long flags;
+       u32 freq_raw = 0;
+       u32 freq = 0;
+       u32 frequency = 0;
+
+       spin_lock_irqsave(&chip->msg_lock, flags);
+
+       lx_message_init(&chip->rmh, CMD_01_GET_SYS_CFG);
+       ret = lx_message_send_atomic(chip, &chip->rmh);
+
+       if (ret == 0) {
+               freq_raw = chip->rmh.stat[0] >> FREQ_FIELD_OFFSET;
+               freq = freq_raw & XES_FREQ_COUNT8_MASK;
+
+               if ((freq < XES_FREQ_COUNT8_48_MAX) ||
+                   (freq > XES_FREQ_COUNT8_44_MIN))
+                       frequency = 0; /* unknown */
+               else if (freq >= XES_FREQ_COUNT8_44_MAX)
+                       frequency = 44100;
+               else
+                       frequency = 48000;
+       }
+
+       spin_unlock_irqrestore(&chip->msg_lock, flags);
+
+       *rfreq = frequency * chip->freq_ratio;
+
+       return ret;
+}
+
+int lx_dsp_get_mac(struct lx6464es *chip, u8 *mac_address)
+{
+       u32 macmsb, maclsb;
+
+       macmsb = lx_dsp_reg_read(chip, eReg_ADMACESMSB) & 0x00FFFFFF;
+       maclsb = lx_dsp_reg_read(chip, eReg_ADMACESLSB) & 0x00FFFFFF;
+
+       /* todo: endianess handling */
+       mac_address[5] = ((u8 *)(&maclsb))[0];
+       mac_address[4] = ((u8 *)(&maclsb))[1];
+       mac_address[3] = ((u8 *)(&maclsb))[2];
+       mac_address[2] = ((u8 *)(&macmsb))[0];
+       mac_address[1] = ((u8 *)(&macmsb))[1];
+       mac_address[0] = ((u8 *)(&macmsb))[2];
+
+       return 0;
+}
+
+
+int lx_dsp_set_granularity(struct lx6464es *chip, u32 gran)
+{
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&chip->msg_lock, flags);
+
+       lx_message_init(&chip->rmh, CMD_02_SET_GRANULARITY);
+       chip->rmh.cmd[0] |= gran;
+
+       ret = lx_message_send_atomic(chip, &chip->rmh);
+       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       return ret;
+}
+
+int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data)
+{
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&chip->msg_lock, flags);
+
+       lx_message_init(&chip->rmh, CMD_04_GET_EVENT);
+       chip->rmh.stat_len = 9; /* we don't necessarily need the full length */
+
+       ret = lx_message_send_atomic(chip, &chip->rmh);
+
+       if (!ret)
+               memcpy(data, chip->rmh.stat, chip->rmh.stat_len * sizeof(u32));
+
+       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       return ret;
+}
+
+#define CSES_TIMEOUT        100     /* microseconds */
+#define CSES_CE             0x0001
+#define CSES_BROADCAST      0x0002
+#define CSES_UPDATE_LDSV    0x0004
+
+int lx_dsp_es_check_pipeline(struct lx6464es *chip)
+{
+       int i;
+
+       for (i = 0; i != CSES_TIMEOUT; ++i) {
+               /*
+                * le bit CSES_UPDATE_LDSV est ÃƒÂ  1 dés que le macprog
+                * est pret. il re-passe ÃƒÂ  0 lorsque le premier read a
+                * ÃƒÂ©té fait. pour l'instant on retire le test car ce bit
+                * passe a 1 environ 200 ÃƒÂ  400 ms aprés que le registre
+                * confES ÃƒÂ  ÃƒÂ©té ÃƒÂ©crit (kick du xilinx ES).
+                *
+                * On ne teste que le bit CE.
+                * */
+
+               u32 cses = lx_dsp_reg_read(chip, eReg_CSES);
+
+               if ((cses & CSES_CE) == 0)
+                       return 0;
+
+               udelay(1);
+       }
+
+       return -ETIMEDOUT;
+}
+
+
+#define PIPE_INFO_TO_CMD(capture, pipe)                                        \
+       ((u32)((u32)(pipe) | ((capture) ? ID_IS_CAPTURE : 0L)) << ID_OFFSET)
+
+
+
+/* low-level pipe handling */
+int lx_pipe_allocate(struct lx6464es *chip, u32 pipe, int is_capture,
+                    int channels)
+{
+       int err;
+       unsigned long flags;
+
+       u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+       spin_lock_irqsave(&chip->msg_lock, flags);
+       lx_message_init(&chip->rmh, CMD_06_ALLOCATE_PIPE);
+
+       chip->rmh.cmd[0] |= pipe_cmd;
+       chip->rmh.cmd[0] |= channels;
+
+       err = lx_message_send_atomic(chip, &chip->rmh);
+       spin_unlock_irqrestore(&chip->msg_lock, flags);
+
+       if (err != 0)
+               snd_printk(KERN_ERR "lx6464es: could not allocate pipe\n");
+
+       return err;
+}
+
+int lx_pipe_release(struct lx6464es *chip, u32 pipe, int is_capture)
+{
+       int err;
+       unsigned long flags;
+
+       u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+       spin_lock_irqsave(&chip->msg_lock, flags);
+       lx_message_init(&chip->rmh, CMD_07_RELEASE_PIPE);
+
+       chip->rmh.cmd[0] |= pipe_cmd;
+
+       err = lx_message_send_atomic(chip, &chip->rmh);
+       spin_unlock_irqrestore(&chip->msg_lock, flags);
+
+       return err;
+}
+
+int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture,
+                 u32 *r_needed, u32 *r_freed, u32 *size_array)
+{
+       int err;
+       unsigned long flags;
+
+       u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+#ifdef CONFIG_SND_DEBUG
+       if (size_array)
+               memset(size_array, 0, sizeof(u32)*MAX_STREAM_BUFFER);
+#endif
+
+       *r_needed = 0;
+       *r_freed = 0;
+
+       spin_lock_irqsave(&chip->msg_lock, flags);
+       lx_message_init(&chip->rmh, CMD_08_ASK_BUFFERS);
+
+       chip->rmh.cmd[0] |= pipe_cmd;
+
+       err = lx_message_send_atomic(chip, &chip->rmh);
+
+       if (!err) {
+               int i;
+               for (i = 0; i < MAX_STREAM_BUFFER; ++i) {
+                       u32 stat = chip->rmh.stat[i];
+                       if (stat & (BF_EOB << BUFF_FLAGS_OFFSET)) {
+                               /* finished */
+                               *r_freed += 1;
+                               if (size_array)
+                                       size_array[i] = stat & MASK_DATA_SIZE;
+                       } else if ((stat & (BF_VALID << BUFF_FLAGS_OFFSET))
+                                  == 0)
+                               /* free */
+                               *r_needed += 1;
+               }
+
+#if 0
+               snd_printdd(LXP "CMD_08_ASK_BUFFERS: needed %d, freed %d\n",
+                           *r_needed, *r_freed);
+               for (i = 0; i < MAX_STREAM_BUFFER; ++i) {
+                       for (i = 0; i != chip->rmh.stat_len; ++i)
+                               snd_printdd("  stat[%d]: %x, %x\n", i,
+                                           chip->rmh.stat[i],
+                                           chip->rmh.stat[i] & MASK_DATA_SIZE);
+               }
+#endif
+       }
+
+       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       return err;
+}
+
+
+int lx_pipe_stop(struct lx6464es *chip, u32 pipe, int is_capture)
+{
+       int err;
+       unsigned long flags;
+
+       u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+       spin_lock_irqsave(&chip->msg_lock, flags);
+       lx_message_init(&chip->rmh, CMD_09_STOP_PIPE);
+
+       chip->rmh.cmd[0] |= pipe_cmd;
+
+       err = lx_message_send_atomic(chip, &chip->rmh);
+
+       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       return err;
+}
+
+static int lx_pipe_toggle_state(struct lx6464es *chip, u32 pipe, int is_capture)
+{
+       int err;
+       unsigned long flags;
+
+       u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+       spin_lock_irqsave(&chip->msg_lock, flags);
+       lx_message_init(&chip->rmh, CMD_0B_TOGGLE_PIPE_STATE);
+
+       chip->rmh.cmd[0] |= pipe_cmd;
+
+       err = lx_message_send_atomic(chip, &chip->rmh);
+
+       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       return err;
+}
+
+
+int lx_pipe_start(struct lx6464es *chip, u32 pipe, int is_capture)
+{
+       int err;
+
+       err = lx_pipe_wait_for_idle(chip, pipe, is_capture);
+       if (err < 0)
+               return err;
+
+       err = lx_pipe_toggle_state(chip, pipe, is_capture);
+
+       return err;
+}
+
+int lx_pipe_pause(struct lx6464es *chip, u32 pipe, int is_capture)
+{
+       int err = 0;
+
+       err = lx_pipe_wait_for_start(chip, pipe, is_capture);
+       if (err < 0)
+               return err;
+
+       err = lx_pipe_toggle_state(chip, pipe, is_capture);
+
+       return err;
+}
+
+
+int lx_pipe_sample_count(struct lx6464es *chip, u32 pipe, int is_capture,
+                        u64 *rsample_count)
+{
+       int err;
+       unsigned long flags;
+
+       u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+       spin_lock_irqsave(&chip->msg_lock, flags);
+       lx_message_init(&chip->rmh, CMD_0A_GET_PIPE_SPL_COUNT);
+
+       chip->rmh.cmd[0] |= pipe_cmd;
+       chip->rmh.stat_len = 2; /* need all words here! */
+
+       err = lx_message_send_atomic(chip, &chip->rmh); /* don't sleep! */
+
+       if (err != 0)
+               snd_printk(KERN_ERR
+                          "lx6464es: could not query pipe's sample count\n");
+       else {
+               *rsample_count = ((u64)(chip->rmh.stat[0] & MASK_SPL_COUNT_HI)
+                                 << 24)     /* hi part */
+                       + chip->rmh.stat[1]; /* lo part */
+       }
+
+       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       return err;
+}
+
+int lx_pipe_state(struct lx6464es *chip, u32 pipe, int is_capture, u16 *rstate)
+{
+       int err;
+       unsigned long flags;
+
+       u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+       spin_lock_irqsave(&chip->msg_lock, flags);
+       lx_message_init(&chip->rmh, CMD_0A_GET_PIPE_SPL_COUNT);
+
+       chip->rmh.cmd[0] |= pipe_cmd;
+
+       err = lx_message_send_atomic(chip, &chip->rmh);
+
+       if (err != 0)
+               snd_printk(KERN_ERR "lx6464es: could not query pipe's state\n");
+       else
+               *rstate = (chip->rmh.stat[0] >> PSTATE_OFFSET) & 0x0F;
+
+       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       return err;
+}
+
+static int lx_pipe_wait_for_state(struct lx6464es *chip, u32 pipe,
+                                 int is_capture, u16 state)
+{
+       int i;
+
+       /* max 2*PCMOnlyGranularity = 2*1024 at 44100 = < 50 ms:
+        * timeout 50 ms */
+       for (i = 0; i != 50; ++i) {
+               u16 current_state;
+               int err = lx_pipe_state(chip, pipe, is_capture, &current_state);
+
+               if (err < 0)
+                       return err;
+
+               if (current_state == state)
+                       return 0;
+
+               mdelay(1);
+       }
+
+       return -ETIMEDOUT;
+}
+
+int lx_pipe_wait_for_start(struct lx6464es *chip, u32 pipe, int is_capture)
+{
+       return lx_pipe_wait_for_state(chip, pipe, is_capture, PSTATE_RUN);
+}
+
+int lx_pipe_wait_for_idle(struct lx6464es *chip, u32 pipe, int is_capture)
+{
+       return lx_pipe_wait_for_state(chip, pipe, is_capture, PSTATE_IDLE);
+}
+
+/* low-level stream handling */
+int lx_stream_set_state(struct lx6464es *chip, u32 pipe,
+                              int is_capture, enum stream_state_t state)
+{
+       int err;
+       unsigned long flags;
+
+       u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+       spin_lock_irqsave(&chip->msg_lock, flags);
+       lx_message_init(&chip->rmh, CMD_13_SET_STREAM_STATE);
+
+       chip->rmh.cmd[0] |= pipe_cmd;
+       chip->rmh.cmd[0] |= state;
+
+       err = lx_message_send_atomic(chip, &chip->rmh);
+       spin_unlock_irqrestore(&chip->msg_lock, flags);
+
+       return err;
+}
+
+int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime,
+                        u32 pipe, int is_capture)
+{
+       int err;
+       unsigned long flags;
+
+       u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+       u32 channels = runtime->channels;
+
+       if (runtime->channels != channels)
+               snd_printk(KERN_ERR LXP "channel count mismatch: %d vs %d",
+                          runtime->channels, channels);
+
+       spin_lock_irqsave(&chip->msg_lock, flags);
+       lx_message_init(&chip->rmh, CMD_0C_DEF_STREAM);
+
+       chip->rmh.cmd[0] |= pipe_cmd;
+
+       if (runtime->sample_bits == 16)
+               /* 16 bit format */
+               chip->rmh.cmd[0] |= (STREAM_FMT_16b << STREAM_FMT_OFFSET);
+
+       if (snd_pcm_format_little_endian(runtime->format))
+               /* little endian/intel format */
+               chip->rmh.cmd[0] |= (STREAM_FMT_intel << STREAM_FMT_OFFSET);
+
+       chip->rmh.cmd[0] |= channels-1;
+
+       err = lx_message_send_atomic(chip, &chip->rmh);
+       spin_unlock_irqrestore(&chip->msg_lock, flags);
+
+       return err;
+}
+
+int lx_stream_state(struct lx6464es *chip, u32 pipe, int is_capture,
+                   int *rstate)
+{
+       int err;
+       unsigned long flags;
+
+       u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+       spin_lock_irqsave(&chip->msg_lock, flags);
+       lx_message_init(&chip->rmh, CMD_0E_GET_STREAM_SPL_COUNT);
+
+       chip->rmh.cmd[0] |= pipe_cmd;
+
+       err = lx_message_send_atomic(chip, &chip->rmh);
+
+       *rstate = (chip->rmh.stat[0] & SF_START) ? START_STATE : PAUSE_STATE;
+
+       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       return err;
+}
+
+int lx_stream_sample_position(struct lx6464es *chip, u32 pipe, int is_capture,
+                             u64 *r_bytepos)
+{
+       int err;
+       unsigned long flags;
+
+       u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+       spin_lock_irqsave(&chip->msg_lock, flags);
+       lx_message_init(&chip->rmh, CMD_0E_GET_STREAM_SPL_COUNT);
+
+       chip->rmh.cmd[0] |= pipe_cmd;
+
+       err = lx_message_send_atomic(chip, &chip->rmh);
+
+       *r_bytepos = ((u64) (chip->rmh.stat[0] & MASK_SPL_COUNT_HI)
+                     << 32)         /* hi part */
+               + chip->rmh.stat[1]; /* lo part */
+
+       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       return err;
+}
+
+/* low-level buffer handling */
+int lx_buffer_give(struct lx6464es *chip, u32 pipe, int is_capture,
+                  u32 buffer_size, u32 buf_address_lo, u32 buf_address_hi,
+                  u32 *r_buffer_index)
+{
+       int err;
+       unsigned long flags;
+
+       u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+       spin_lock_irqsave(&chip->msg_lock, flags);
+       lx_message_init(&chip->rmh, CMD_0F_UPDATE_BUFFER);
+
+       chip->rmh.cmd[0] |= pipe_cmd;
+       chip->rmh.cmd[0] |= BF_NOTIFY_EOB; /* request interrupt notification */
+
+       /* todo: pause request, circular buffer */
+
+       chip->rmh.cmd[1] = buffer_size & MASK_DATA_SIZE;
+       chip->rmh.cmd[2] = buf_address_lo;
+
+       if (buf_address_hi) {
+               chip->rmh.cmd_len = 4;
+               chip->rmh.cmd[3] = buf_address_hi;
+               chip->rmh.cmd[0] |= BF_64BITS_ADR;
+       }
+
+       err = lx_message_send_atomic(chip, &chip->rmh);
+
+       if (err == 0) {
+               *r_buffer_index = chip->rmh.stat[0];
+               goto done;
+       }
+
+       if (err == EB_RBUFFERS_TABLE_OVERFLOW)
+               snd_printk(LXP "lx_buffer_give EB_RBUFFERS_TABLE_OVERFLOW\n");
+
+       if (err == EB_INVALID_STREAM)
+               snd_printk(LXP "lx_buffer_give EB_INVALID_STREAM\n");
+
+       if (err == EB_CMD_REFUSED)
+               snd_printk(LXP "lx_buffer_give EB_CMD_REFUSED\n");
+
+ done:
+       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       return err;
+}
+
+int lx_buffer_free(struct lx6464es *chip, u32 pipe, int is_capture,
+                  u32 *r_buffer_size)
+{
+       int err;
+       unsigned long flags;
+
+       u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+       spin_lock_irqsave(&chip->msg_lock, flags);
+       lx_message_init(&chip->rmh, CMD_11_CANCEL_BUFFER);
+
+       chip->rmh.cmd[0] |= pipe_cmd;
+       chip->rmh.cmd[0] |= MASK_BUFFER_ID; /* ask for the current buffer: the
+                                            * microblaze will seek for it */
+
+       err = lx_message_send_atomic(chip, &chip->rmh);
+
+       if (err == 0)
+               *r_buffer_size = chip->rmh.stat[0]  & MASK_DATA_SIZE;
+
+       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       return err;
+}
+
+int lx_buffer_cancel(struct lx6464es *chip, u32 pipe, int is_capture,
+                    u32 buffer_index)
+{
+       int err;
+       unsigned long flags;
+
+       u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
+
+       spin_lock_irqsave(&chip->msg_lock, flags);
+       lx_message_init(&chip->rmh, CMD_11_CANCEL_BUFFER);
+
+       chip->rmh.cmd[0] |= pipe_cmd;
+       chip->rmh.cmd[0] |= buffer_index;
+
+       err = lx_message_send_atomic(chip, &chip->rmh);
+
+       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       return err;
+}
+
+
+/* low-level gain/peak handling
+ *
+ * \todo: can we unmute capture/playback channels independently?
+ *
+ * */
+int lx_level_unmute(struct lx6464es *chip, int is_capture, int unmute)
+{
+       int err;
+       unsigned long flags;
+
+       /* bit set to 1: channel muted */
+       u64 mute_mask = unmute ? 0 : 0xFFFFFFFFFFFFFFFFLLU;
+
+       spin_lock_irqsave(&chip->msg_lock, flags);
+       lx_message_init(&chip->rmh, CMD_0D_SET_MUTE);
+
+       chip->rmh.cmd[0] |= PIPE_INFO_TO_CMD(is_capture, 0);
+
+       chip->rmh.cmd[1] = (u32)(mute_mask >> (u64)32);        /* hi part */
+       chip->rmh.cmd[2] = (u32)(mute_mask & (u64)0xFFFFFFFF); /* lo part */
+
+       snd_printk("mute %x %x %x\n", chip->rmh.cmd[0], chip->rmh.cmd[1],
+                  chip->rmh.cmd[2]);
+
+       err = lx_message_send_atomic(chip, &chip->rmh);
+
+       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       return err;
+}
+
+static u32 peak_map[] = {
+       0x00000109, /* -90.308dB */
+       0x0000083B, /* -72.247dB */
+       0x000020C4, /* -60.205dB */
+       0x00008273, /* -48.030dB */
+       0x00020756, /* -36.005dB */
+       0x00040C37, /* -30.001dB */
+       0x00081385, /* -24.002dB */
+       0x00101D3F, /* -18.000dB */
+       0x0016C310, /* -15.000dB */
+       0x002026F2, /* -12.001dB */
+       0x002D6A86, /* -9.000dB */
+       0x004026E6, /* -6.004dB */
+       0x005A9DF6, /* -3.000dB */
+       0x0065AC8B, /* -2.000dB */
+       0x00721481, /* -1.000dB */
+       0x007FFFFF, /* FS */
+};
+
+int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels,
+                  u32 *r_levels)
+{
+       int err = 0;
+       unsigned long flags;
+       int i;
+       spin_lock_irqsave(&chip->msg_lock, flags);
+
+       for (i = 0; i < channels; i += 4) {
+               u32 s0, s1, s2, s3;
+
+               lx_message_init(&chip->rmh, CMD_12_GET_PEAK);
+               chip->rmh.cmd[0] |= PIPE_INFO_TO_CMD(is_capture, i);
+
+               err = lx_message_send_atomic(chip, &chip->rmh);
+
+               if (err == 0) {
+                       s0 = peak_map[chip->rmh.stat[0] & 0x0F];
+                       s1 = peak_map[(chip->rmh.stat[0] >>  4) & 0xf];
+                       s2 = peak_map[(chip->rmh.stat[0] >>  8) & 0xf];
+                       s3 = peak_map[(chip->rmh.stat[0] >>  12) & 0xf];
+               } else
+                       s0 = s1 = s2 = s3 = 0;
+
+               r_levels[0] = s0;
+               r_levels[1] = s1;
+               r_levels[2] = s2;
+               r_levels[3] = s3;
+
+               r_levels += 4;
+       }
+
+       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       return err;
+}
+
+/* interrupt handling */
+#define PCX_IRQ_NONE 0
+#define IRQCS_ACTIVE_PCIDB  0x00002000L         /* Bit nÃ\83¸ 13 */
+#define IRQCS_ENABLE_PCIIRQ 0x00000100L         /* Bit nÃ\83¸ 08 */
+#define IRQCS_ENABLE_PCIDB  0x00000200L         /* Bit nÃ\83¸ 09 */
+
+static u32 lx_interrupt_test_ack(struct lx6464es *chip)
+{
+       u32 irqcs = lx_plx_reg_read(chip, ePLX_IRQCS);
+
+       /* Test if PCI Doorbell interrupt is active */
+       if (irqcs & IRQCS_ACTIVE_PCIDB) {
+               u32 temp;
+               irqcs = PCX_IRQ_NONE;
+
+               while ((temp = lx_plx_reg_read(chip, ePLX_L2PCIDB))) {
+                       /* RAZ interrupt */
+                       irqcs |= temp;
+                       lx_plx_reg_write(chip, ePLX_L2PCIDB, temp);
+               }
+
+               return irqcs;
+       }
+       return PCX_IRQ_NONE;
+}
+
+static int lx_interrupt_ack(struct lx6464es *chip, u32 *r_irqsrc,
+                           int *r_async_pending, int *r_async_escmd)
+{
+       u32 irq_async;
+       u32 irqsrc = lx_interrupt_test_ack(chip);
+
+       if (irqsrc == PCX_IRQ_NONE)
+               return 0;
+
+       *r_irqsrc = irqsrc;
+
+       irq_async = irqsrc & MASK_SYS_ASYNC_EVENTS; /* + EtherSound response
+                                                    * (set by xilinx) + EOB */
+
+       if (irq_async & MASK_SYS_STATUS_ESA) {
+               irq_async &= ~MASK_SYS_STATUS_ESA;
+               *r_async_escmd = 1;
+       }
+
+       if (irqsrc & MASK_SYS_STATUS_CMD_DONE)
+               /* xilinx command notification */
+               atomic_set(&chip->send_message_locked, 0);
+
+       if (irq_async) {
+               /* snd_printd("interrupt: async event pending\n"); */
+               *r_async_pending = 1;
+       }
+
+       return 1;
+}
+
+static int lx_interrupt_handle_async_events(struct lx6464es *chip, u32 irqsrc,
+                                           int *r_freq_changed,
+                                           u64 *r_notified_in_pipe_mask,
+                                           u64 *r_notified_out_pipe_mask)
+{
+       int err;
+       u32 stat[9];            /* answer from CMD_04_GET_EVENT */
+
+       /* On peut optimiser pour ne pas lire les evenements vides
+        * les mots de rÃ\83©ponse sont dans l'ordre suivant :
+        * Stat[0]      mot de status gÃ\83©nÃ\83©ral
+        * Stat[1]      fin de buffer OUT pF
+        * Stat[2]      fin de buffer OUT pf
+        * Stat[3]      fin de buffer IN pF
+        * Stat[4]      fin de buffer IN pf
+        * Stat[5]      underrun poid fort
+        * Stat[6]      underrun poid faible
+        * Stat[7]      overrun poid fort
+        * Stat[8]      overrun poid faible
+        * */
+
+       u64 orun_mask;
+       u64 urun_mask;
+#if 0
+       int has_underrun   = (irqsrc & MASK_SYS_STATUS_URUN) ? 1 : 0;
+       int has_overrun    = (irqsrc & MASK_SYS_STATUS_ORUN) ? 1 : 0;
+#endif
+       int eb_pending_out = (irqsrc & MASK_SYS_STATUS_EOBO) ? 1 : 0;
+       int eb_pending_in  = (irqsrc & MASK_SYS_STATUS_EOBI) ? 1 : 0;
+
+       *r_freq_changed = (irqsrc & MASK_SYS_STATUS_FREQ) ? 1 : 0;
+
+       err = lx_dsp_read_async_events(chip, stat);
+       if (err < 0)
+               return err;
+
+       if (eb_pending_in) {
+               *r_notified_in_pipe_mask = ((u64)stat[3] << 32)
+                       + stat[4];
+               snd_printdd(LXP "interrupt: EOBI pending %llx\n",
+                           *r_notified_in_pipe_mask);
+       }
+       if (eb_pending_out) {
+               *r_notified_out_pipe_mask = ((u64)stat[1] << 32)
+                       + stat[2];
+               snd_printdd(LXP "interrupt: EOBO pending %llx\n",
+                           *r_notified_out_pipe_mask);
+       }
+
+       orun_mask = ((u64)stat[7] << 32) + stat[8];
+       urun_mask = ((u64)stat[5] << 32) + stat[6];
+
+       /* todo: handle xrun notification */
+
+       return err;
+}
+
+static int lx_interrupt_request_new_buffer(struct lx6464es *chip,
+                                          struct lx_stream *lx_stream)
+{
+       struct snd_pcm_substream *substream = lx_stream->stream;
+       int is_capture = lx_stream->is_capture;
+       int err;
+       unsigned long flags;
+
+       const u32 channels = substream->runtime->channels;
+       const u32 bytes_per_frame = channels * 3;
+       const u32 period_size = substream->runtime->period_size;
+       const u32 period_bytes = period_size * bytes_per_frame;
+       const u32 pos = lx_stream->frame_pos;
+       const u32 next_pos = ((pos+1) == substream->runtime->periods) ?
+               0 : pos + 1;
+
+       dma_addr_t buf = substream->dma_buffer.addr + pos * period_bytes;
+       u32 buf_hi = 0;
+       u32 buf_lo = 0;
+       u32 buffer_index = 0;
+
+       u32 needed, freed;
+       u32 size_array[MAX_STREAM_BUFFER];
+
+       snd_printdd("->lx_interrupt_request_new_buffer\n");
+
+       spin_lock_irqsave(&chip->lock, flags);
+
+       err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array);
+       snd_printdd(LXP "interrupt: needed %d, freed %d\n", needed, freed);
+
+       unpack_pointer(buf, &buf_lo, &buf_hi);
+       err = lx_buffer_give(chip, 0, is_capture, period_bytes, buf_lo, buf_hi,
+                            &buffer_index);
+       snd_printdd(LXP "interrupt: gave buffer index %x on %p (%d bytes)\n",
+                   buffer_index, (void *)buf, period_bytes);
+
+       lx_stream->frame_pos = next_pos;
+       spin_unlock_irqrestore(&chip->lock, flags);
+
+       return err;
+}
+
+void lx_tasklet_playback(unsigned long data)
+{
+       struct lx6464es *chip = (struct lx6464es *)data;
+       struct lx_stream *lx_stream = &chip->playback_stream;
+       int err;
+
+       snd_printdd("->lx_tasklet_playback\n");
+
+       err = lx_interrupt_request_new_buffer(chip, lx_stream);
+       if (err < 0)
+               snd_printk(KERN_ERR LXP
+                          "cannot request new buffer for playback\n");
+
+       snd_pcm_period_elapsed(lx_stream->stream);
+}
+
+void lx_tasklet_capture(unsigned long data)
+{
+       struct lx6464es *chip = (struct lx6464es *)data;
+       struct lx_stream *lx_stream = &chip->capture_stream;
+       int err;
+
+       snd_printdd("->lx_tasklet_capture\n");
+       err = lx_interrupt_request_new_buffer(chip, lx_stream);
+       if (err < 0)
+               snd_printk(KERN_ERR LXP
+                          "cannot request new buffer for capture\n");
+
+       snd_pcm_period_elapsed(lx_stream->stream);
+}
+
+
+
+static int lx_interrupt_handle_audio_transfer(struct lx6464es *chip,
+                                             u64 notified_in_pipe_mask,
+                                             u64 notified_out_pipe_mask)
+{
+       int err = 0;
+
+       if (notified_in_pipe_mask) {
+               snd_printdd(LXP "requesting audio transfer for capture\n");
+               tasklet_hi_schedule(&chip->tasklet_capture);
+       }
+
+       if (notified_out_pipe_mask) {
+               snd_printdd(LXP "requesting audio transfer for playback\n");
+               tasklet_hi_schedule(&chip->tasklet_playback);
+       }
+
+       return err;
+}
+
+
+irqreturn_t lx_interrupt(int irq, void *dev_id)
+{
+       struct lx6464es *chip = dev_id;
+       int async_pending, async_escmd;
+       u32 irqsrc;
+
+       spin_lock(&chip->lock);
+
+       snd_printdd("**************************************************\n");
+
+       if (!lx_interrupt_ack(chip, &irqsrc, &async_pending, &async_escmd)) {
+               spin_unlock(&chip->lock);
+               snd_printdd("IRQ_NONE\n");
+               return IRQ_NONE; /* this device did not cause the interrupt */
+       }
+
+       if (irqsrc & MASK_SYS_STATUS_CMD_DONE)
+               goto exit;
+
+#if 0
+       if (irqsrc & MASK_SYS_STATUS_EOBI)
+               snd_printdd(LXP "interrupt: EOBI\n");
+
+       if (irqsrc & MASK_SYS_STATUS_EOBO)
+               snd_printdd(LXP "interrupt: EOBO\n");
+
+       if (irqsrc & MASK_SYS_STATUS_URUN)
+               snd_printdd(LXP "interrupt: URUN\n");
+
+       if (irqsrc & MASK_SYS_STATUS_ORUN)
+               snd_printdd(LXP "interrupt: ORUN\n");
+#endif
+
+       if (async_pending) {
+               u64 notified_in_pipe_mask = 0;
+               u64 notified_out_pipe_mask = 0;
+               int freq_changed;
+               int err;
+
+               /* handle async events */
+               err = lx_interrupt_handle_async_events(chip, irqsrc,
+                                                      &freq_changed,
+                                                      &notified_in_pipe_mask,
+                                                      &notified_out_pipe_mask);
+               if (err)
+                       snd_printk(KERN_ERR LXP
+                                  "error handling async events\n");
+
+               err = lx_interrupt_handle_audio_transfer(chip,
+                                                        notified_in_pipe_mask,
+                                                        notified_out_pipe_mask
+                       );
+               if (err)
+                       snd_printk(KERN_ERR LXP
+                                  "error during audio transfer\n");
+       }
+
+       if (async_escmd) {
+#if 0
+               /* backdoor for ethersound commands
+                *
+                * for now, we do not need this
+                *
+                * */
+
+               snd_printdd("lx6464es: interrupt requests escmd handling\n");
+#endif
+       }
+
+exit:
+       spin_unlock(&chip->lock);
+       return IRQ_HANDLED;     /* this device caused the interrupt */
+}
+
+
+static void lx_irq_set(struct lx6464es *chip, int enable)
+{
+       u32 reg = lx_plx_reg_read(chip, ePLX_IRQCS);
+
+       /* enable/disable interrupts
+        *
+        * Set the Doorbell and PCI interrupt enable bits
+        *
+        * */
+       if (enable)
+               reg |=  (IRQCS_ENABLE_PCIIRQ | IRQCS_ENABLE_PCIDB);
+       else
+               reg &= ~(IRQCS_ENABLE_PCIIRQ | IRQCS_ENABLE_PCIDB);
+       lx_plx_reg_write(chip, ePLX_IRQCS, reg);
+}
+
+void lx_irq_enable(struct lx6464es *chip)
+{
+       snd_printdd("->lx_irq_enable\n");
+       lx_irq_set(chip, 1);
+}
+
+void lx_irq_disable(struct lx6464es *chip)
+{
+       snd_printdd("->lx_irq_disable\n");
+       lx_irq_set(chip, 0);
+}
diff --git a/sound/pci/lx6464es/lx_core.h b/sound/pci/lx6464es/lx_core.h
new file mode 100644 (file)
index 0000000..6bd9cbb
--- /dev/null
@@ -0,0 +1,242 @@
+/* -*- linux-c -*- *
+ *
+ * ALSA driver for the digigram lx6464es interface
+ * low-level interface
+ *
+ * Copyright (c) 2009 Tim Blechmann <tim@klingt.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; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef LX_CORE_H
+#define LX_CORE_H
+
+#include <linux/interrupt.h>
+
+#include "lx_defs.h"
+
+#define REG_CRM_NUMBER         12
+
+struct lx6464es;
+
+/* low-level register access */
+
+/* dsp register access */
+enum {
+       eReg_BASE,
+       eReg_CSM,
+       eReg_CRM1,
+       eReg_CRM2,
+       eReg_CRM3,
+       eReg_CRM4,
+       eReg_CRM5,
+       eReg_CRM6,
+       eReg_CRM7,
+       eReg_CRM8,
+       eReg_CRM9,
+       eReg_CRM10,
+       eReg_CRM11,
+       eReg_CRM12,
+
+       eReg_ICR,
+       eReg_CVR,
+       eReg_ISR,
+       eReg_RXHTXH,
+       eReg_RXMTXM,
+       eReg_RHLTXL,
+       eReg_RESETDSP,
+
+       eReg_CSUF,
+       eReg_CSES,
+       eReg_CRESMSB,
+       eReg_CRESLSB,
+       eReg_ADMACESMSB,
+       eReg_ADMACESLSB,
+       eReg_CONFES,
+
+       eMaxPortLx
+};
+
+unsigned long lx_dsp_reg_read(struct lx6464es *chip, int port);
+void lx_dsp_reg_readbuf(struct lx6464es *chip, int port, u32 *data, u32 len);
+void lx_dsp_reg_write(struct lx6464es *chip, int port, unsigned data);
+void lx_dsp_reg_writebuf(struct lx6464es *chip, int port, const u32 *data,
+                        u32 len);
+
+/* plx register access */
+enum {
+    ePLX_PCICR,
+
+    ePLX_MBOX0,
+    ePLX_MBOX1,
+    ePLX_MBOX2,
+    ePLX_MBOX3,
+    ePLX_MBOX4,
+    ePLX_MBOX5,
+    ePLX_MBOX6,
+    ePLX_MBOX7,
+
+    ePLX_L2PCIDB,
+    ePLX_IRQCS,
+    ePLX_CHIPSC,
+
+    eMaxPort
+};
+
+unsigned long lx_plx_reg_read(struct lx6464es *chip, int port);
+void lx_plx_reg_write(struct lx6464es *chip, int port, u32 data);
+
+/* rhm */
+struct lx_rmh {
+       u16     cmd_len;        /* length of the command to send (WORDs) */
+       u16     stat_len;       /* length of the status received (WORDs) */
+       u16     dsp_stat;       /* status type, RMP_SSIZE_XXX */
+       u16     cmd_idx;        /* index of the command */
+       u32     cmd[REG_CRM_NUMBER];
+       u32     stat[REG_CRM_NUMBER];
+};
+
+
+/* low-level dsp access */
+int __devinit lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version);
+int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq);
+int lx_dsp_set_granularity(struct lx6464es *chip, u32 gran);
+int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data);
+int lx_dsp_get_mac(struct lx6464es *chip, u8 *mac_address);
+
+
+/* low-level pipe handling */
+int lx_pipe_allocate(struct lx6464es *chip, u32 pipe, int is_capture,
+                    int channels);
+int lx_pipe_release(struct lx6464es *chip, u32 pipe, int is_capture);
+int lx_pipe_sample_count(struct lx6464es *chip, u32 pipe, int is_capture,
+                        u64 *rsample_count);
+int lx_pipe_state(struct lx6464es *chip, u32 pipe, int is_capture, u16 *rstate);
+int lx_pipe_stop(struct lx6464es *chip, u32 pipe, int is_capture);
+int lx_pipe_start(struct lx6464es *chip, u32 pipe, int is_capture);
+int lx_pipe_pause(struct lx6464es *chip, u32 pipe, int is_capture);
+
+int lx_pipe_wait_for_start(struct lx6464es *chip, u32 pipe, int is_capture);
+int lx_pipe_wait_for_idle(struct lx6464es *chip, u32 pipe, int is_capture);
+
+/* low-level stream handling */
+int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime,
+                        u32 pipe, int is_capture);
+int lx_stream_state(struct lx6464es *chip, u32 pipe, int is_capture,
+                   int *rstate);
+int lx_stream_sample_position(struct lx6464es *chip, u32 pipe, int is_capture,
+                             u64 *r_bytepos);
+
+int lx_stream_set_state(struct lx6464es *chip, u32 pipe,
+                       int is_capture, enum stream_state_t state);
+
+static inline int lx_stream_start(struct lx6464es *chip, u32 pipe,
+                                 int is_capture)
+{
+       snd_printdd("->lx_stream_start\n");
+       return lx_stream_set_state(chip, pipe, is_capture, SSTATE_RUN);
+}
+
+static inline int lx_stream_pause(struct lx6464es *chip, u32 pipe,
+                                 int is_capture)
+{
+       snd_printdd("->lx_stream_pause\n");
+       return lx_stream_set_state(chip, pipe, is_capture, SSTATE_PAUSE);
+}
+
+static inline int lx_stream_stop(struct lx6464es *chip, u32 pipe,
+                                int is_capture)
+{
+       snd_printdd("->lx_stream_stop\n");
+       return lx_stream_set_state(chip, pipe, is_capture, SSTATE_STOP);
+}
+
+/* low-level buffer handling */
+int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture,
+                 u32 *r_needed, u32 *r_freed, u32 *size_array);
+int lx_buffer_give(struct lx6464es *chip, u32 pipe, int is_capture,
+                  u32 buffer_size, u32 buf_address_lo, u32 buf_address_hi,
+                  u32 *r_buffer_index);
+int lx_buffer_free(struct lx6464es *chip, u32 pipe, int is_capture,
+                  u32 *r_buffer_size);
+int lx_buffer_cancel(struct lx6464es *chip, u32 pipe, int is_capture,
+                    u32 buffer_index);
+
+/* low-level gain/peak handling */
+int lx_level_unmute(struct lx6464es *chip, int is_capture, int unmute);
+int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels,
+                  u32 *r_levels);
+
+
+/* interrupt handling */
+irqreturn_t lx_interrupt(int irq, void *dev_id);
+void lx_irq_enable(struct lx6464es *chip);
+void lx_irq_disable(struct lx6464es *chip);
+
+void lx_tasklet_capture(unsigned long data);
+void lx_tasklet_playback(unsigned long data);
+
+
+/* Stream Format Header Defines (for LIN and IEEE754) */
+#define HEADER_FMT_BASE                HEADER_FMT_BASE_LIN
+#define HEADER_FMT_BASE_LIN    0xFED00000
+#define HEADER_FMT_BASE_FLOAT  0xFAD00000
+#define HEADER_FMT_MONO                0x00000080 /* bit 23 in header_lo. WARNING: old
+                                           * bit 22 is ignored in float
+                                           * format */
+#define HEADER_FMT_INTEL       0x00008000
+#define HEADER_FMT_16BITS      0x00002000
+#define HEADER_FMT_24BITS      0x00004000
+#define HEADER_FMT_UPTO11      0x00000200 /* frequency is less or equ. to 11k.
+                                           * */
+#define HEADER_FMT_UPTO32      0x00000100 /* frequency is over 11k and less
+                                           * then 32k.*/
+
+
+#define BIT_FMP_HEADER          23
+#define BIT_FMP_SD              22
+#define BIT_FMP_MULTICHANNEL    19
+
+#define START_STATE             1
+#define PAUSE_STATE             0
+
+
+
+
+
+/* from PcxAll_e.h */
+/* Start/Pause condition for pipes (PCXStartPipe, PCXPausePipe) */
+#define START_PAUSE_IMMEDIATE           0
+#define START_PAUSE_ON_SYNCHRO          1
+#define START_PAUSE_ON_TIME_CODE        2
+
+
+/* Pipe / Stream state */
+#define START_STATE             1
+#define PAUSE_STATE             0
+
+static inline void unpack_pointer(dma_addr_t ptr, u32 *r_low, u32 *r_high)
+{
+       *r_low = (u32)(ptr & 0xffffffff);
+#if BITS_PER_LONG == 32
+       *r_high = 0;
+#else
+       *r_high = (u32)((u64)ptr>>32);
+#endif
+}
+
+#endif /* LX_CORE_H */
diff --git a/sound/pci/lx6464es/lx_defs.h b/sound/pci/lx6464es/lx_defs.h
new file mode 100644 (file)
index 0000000..49d36bd
--- /dev/null
@@ -0,0 +1,376 @@
+/* -*- linux-c -*- *
+ *
+ * ALSA driver for the digigram lx6464es interface
+ * adapted upstream headers
+ *
+ * Copyright (c) 2009 Tim Blechmann <tim@klingt.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; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef LX_DEFS_H
+#define LX_DEFS_H
+
+/* code adapted from ethersound.h */
+#define        XES_FREQ_COUNT8_MASK    0x00001FFF /* compteur 25MHz entre 8 ech. */
+#define        XES_FREQ_COUNT8_44_MIN  0x00001288 /* 25M /
+                                           * [ 44k - ( 44.1k + 48k ) / 2 ]
+                                           * * 8 */
+#define        XES_FREQ_COUNT8_44_MAX  0x000010F0 /* 25M / [ ( 44.1k + 48k ) / 2 ]
+                                           * * 8 */
+#define        XES_FREQ_COUNT8_48_MAX  0x00000F08 /* 25M /
+                                           * [ 48k + ( 44.1k + 48k ) / 2 ]
+                                           * * 8 */
+
+/* code adapted from LXES_registers.h */
+
+#define IOCR_OUTPUTS_OFFSET 0  /* (rw) offset for the number of OUTs in the
+                                * ConfES register. */
+#define IOCR_INPUTS_OFFSET  8  /* (rw) offset for the number of INs in the
+                                * ConfES register. */
+#define FREQ_RATIO_OFFSET  19  /* (rw) offset for frequency ratio in the
+                                * ConfES register. */
+#define        FREQ_RATIO_SINGLE_MODE 0x01 /* value for single mode frequency ratio:
+                                    * sample rate = frequency rate. */
+
+#define CONFES_READ_PART_MASK  0x00070000
+#define CONFES_WRITE_PART_MASK 0x00F80000
+
+/* code adapted from if_drv_mb.h */
+
+#define MASK_SYS_STATUS_ERROR  (1L << 31) /* events that lead to a PCI irq if
+                                           * not yet pending */
+#define MASK_SYS_STATUS_URUN   (1L << 30)
+#define MASK_SYS_STATUS_ORUN   (1L << 29)
+#define MASK_SYS_STATUS_EOBO   (1L << 28)
+#define MASK_SYS_STATUS_EOBI   (1L << 27)
+#define MASK_SYS_STATUS_FREQ   (1L << 26)
+#define MASK_SYS_STATUS_ESA    (1L << 25) /* reserved, this is set by the
+                                           * XES */
+#define MASK_SYS_STATUS_TIMER  (1L << 24)
+
+#define MASK_SYS_ASYNC_EVENTS  (MASK_SYS_STATUS_ERROR |                \
+                                MASK_SYS_STATUS_URUN  |                \
+                                MASK_SYS_STATUS_ORUN  |                \
+                                MASK_SYS_STATUS_EOBO  |                \
+                                MASK_SYS_STATUS_EOBI  |                \
+                                MASK_SYS_STATUS_FREQ  |                \
+                                MASK_SYS_STATUS_ESA)
+
+#define MASK_SYS_PCI_EVENTS            (MASK_SYS_ASYNC_EVENTS |        \
+                                        MASK_SYS_STATUS_TIMER)
+
+#define MASK_SYS_TIMER_COUNT   0x0000FFFF
+
+#define MASK_SYS_STATUS_EOT_PLX                (1L << 22) /* event that remains
+                                                   * internal: reserved fo end
+                                                   * of plx dma */
+#define MASK_SYS_STATUS_XES            (1L << 21) /* event that remains
+                                                   * internal: pending XES
+                                                   * IRQ */
+#define MASK_SYS_STATUS_CMD_DONE       (1L << 20) /* alternate command
+                                                   * management: notify driver
+                                                   * instead of polling */
+
+
+#define MAX_STREAM_BUFFER 5    /* max amount of stream buffers. */
+
+#define MICROBLAZE_IBL_MIN              32
+#define MICROBLAZE_IBL_DEFAULT         128
+#define MICROBLAZE_IBL_MAX             512
+/* #define MASK_GRANULARITY            (2*MICROBLAZE_IBL_MAX-1) */
+
+
+
+/* command opcodes, see reference for details */
+
+/*
+ the capture bit position in the object_id field in driver commands
+ depends upon the number of managed channels. For now, 64 IN + 64 OUT are
+ supported. HOwever, the communication protocol forsees 1024 channels, hence
+ bit 10 indicates a capture (input) object).
+*/
+#define ID_IS_CAPTURE (1L << 10)
+#define ID_OFFSET      13      /* object ID is at the 13th bit in the
+                                * 1st command word.*/
+#define ID_CH_MASK    0x3F
+#define OPCODE_OFFSET  24      /* offset of the command opcode in the first
+                                * command word.*/
+
+enum cmd_mb_opcodes {
+       CMD_00_INFO_DEBUG               = 0x00,
+       CMD_01_GET_SYS_CFG              = 0x01,
+       CMD_02_SET_GRANULARITY          = 0x02,
+       CMD_03_SET_TIMER_IRQ            = 0x03,
+       CMD_04_GET_EVENT                = 0x04,
+       CMD_05_GET_PIPES                = 0x05,
+
+       CMD_06_ALLOCATE_PIPE            = 0x06,
+       CMD_07_RELEASE_PIPE             = 0x07,
+       CMD_08_ASK_BUFFERS              = 0x08,
+       CMD_09_STOP_PIPE                = 0x09,
+       CMD_0A_GET_PIPE_SPL_COUNT       = 0x0a,
+       CMD_0B_TOGGLE_PIPE_STATE        = 0x0b,
+
+       CMD_0C_DEF_STREAM               = 0x0c,
+       CMD_0D_SET_MUTE                 = 0x0d,
+       CMD_0E_GET_STREAM_SPL_COUNT     = 0x0e,
+       CMD_0F_UPDATE_BUFFER            = 0x0f,
+       CMD_10_GET_BUFFER               = 0x10,
+       CMD_11_CANCEL_BUFFER            = 0x11,
+       CMD_12_GET_PEAK                 = 0x12,
+       CMD_13_SET_STREAM_STATE         = 0x13,
+       CMD_14_INVALID                  = 0x14,
+};
+
+/* pipe states */
+enum pipe_state_t {
+       PSTATE_IDLE     = 0,    /* the pipe is not processed in the XES_IRQ
+                                * (free or stopped, or paused). */
+       PSTATE_RUN      = 1,    /* sustained play/record state. */
+       PSTATE_PURGE    = 2,    /* the ES channels are now off, render pipes do
+                                * not DMA, record pipe do a last DMA. */
+       PSTATE_ACQUIRE  = 3,    /* the ES channels are now on, render pipes do
+                                * not yet increase their sample count, record
+                                * pipes do not DMA. */
+       PSTATE_CLOSING  = 4,    /* the pipe is releasing, and may not yet
+                                * receive an "alloc" command. */
+};
+
+/* stream states */
+enum stream_state_t {
+       SSTATE_STOP     =  0x00,       /* setting to stop resets the stream spl
+                                       * count.*/
+       SSTATE_RUN      = (0x01 << 0), /* start DMA and spl count handling. */
+       SSTATE_PAUSE    = (0x01 << 1), /* pause DMA and spl count handling. */
+};
+
+/* buffer flags */
+enum buffer_flags {
+       BF_VALID        = 0x80, /* set if the buffer is valid, clear if free.*/
+       BF_CURRENT      = 0x40, /* set if this is the current buffer (there is
+                                * always a current buffer).*/
+       BF_NOTIFY_EOB   = 0x20, /* set if this buffer must cause a PCI event
+                                * when finished.*/
+       BF_CIRCULAR     = 0x10, /* set if buffer[1] must be copied to buffer[0]
+                                * by the end of this buffer.*/
+       BF_64BITS_ADR   = 0x08, /* set if the hi part of the address is valid.*/
+       BF_xx           = 0x04, /* future extension.*/
+       BF_EOB          = 0x02, /* set if finished, but not yet free.*/
+       BF_PAUSE        = 0x01, /* pause stream at buffer end.*/
+       BF_ZERO         = 0x00, /* no flags (init).*/
+};
+
+/**
+*      Stream Flags definitions
+*/
+enum stream_flags {
+       SF_ZERO         = 0x00000000, /* no flags (stream invalid). */
+       SF_VALID        = 0x10000000, /* the stream has a valid DMA_conf
+                                      * info (setstreamformat). */
+       SF_XRUN         = 0x20000000, /* the stream is un x-run state. */
+       SF_START        = 0x40000000, /* the DMA is running.*/
+       SF_ASIO         = 0x80000000, /* ASIO.*/
+};
+
+
+#define MASK_SPL_COUNT_HI 0x00FFFFFF /* 4 MSBits are status bits */
+#define PSTATE_OFFSET             28 /* 4 MSBits are status bits */
+
+
+#define MASK_STREAM_HAS_MAPPING        (1L << 12)
+#define MASK_STREAM_IS_ASIO    (1L <<  9)
+#define STREAM_FMT_OFFSET      10   /* the stream fmt bits start at the 10th
+                                     * bit in the command word. */
+
+#define STREAM_FMT_16b          0x02
+#define STREAM_FMT_intel        0x01
+
+#define FREQ_FIELD_OFFSET      15  /* offset of the freq field in the response
+                                    * word */
+
+#define BUFF_FLAGS_OFFSET        24 /*  offset of the buffer flags in the
+                                     *  response word. */
+#define MASK_DATA_SIZE   0x00FFFFFF /* this must match the field size of
+                                     * datasize in the buffer_t structure. */
+
+#define MASK_BUFFER_ID         0xFF /* the cancel command awaits a buffer ID,
+                                     * may be 0xFF for "current". */
+
+
+/* code adapted from PcxErr_e.h */
+
+/* Bits masks */
+
+#define ERROR_MASK              0x8000
+
+#define SOURCE_MASK             0x7800
+
+#define E_SOURCE_BOARD          0x4000 /* 8 >> 1 */
+#define E_SOURCE_DRV            0x2000 /* 4 >> 1 */
+#define E_SOURCE_API            0x1000 /* 2 >> 1 */
+/* Error tools */
+#define E_SOURCE_TOOLS          0x0800 /* 1 >> 1 */
+/* Error pcxaudio */
+#define E_SOURCE_AUDIO          0x1800 /* 3 >> 1 */
+/* Error virtual pcx */
+#define E_SOURCE_VPCX           0x2800 /* 5 >> 1 */
+/* Error dispatcher */
+#define E_SOURCE_DISPATCHER     0x3000 /* 6 >> 1 */
+/* Error from CobraNet firmware */
+#define E_SOURCE_COBRANET       0x3800 /* 7 >> 1 */
+
+#define E_SOURCE_USER           0x7800
+
+#define CLASS_MASK              0x0700
+
+#define CODE_MASK               0x00FF
+
+/* Bits values */
+
+/* Values for the error/warning bit */
+#define ERROR_VALUE             0x8000
+#define WARNING_VALUE           0x0000
+
+/* Class values */
+#define E_CLASS_GENERAL                  0x0000
+#define E_CLASS_INVALID_CMD              0x0100
+#define E_CLASS_INVALID_STD_OBJECT       0x0200
+#define E_CLASS_RSRC_IMPOSSIBLE          0x0300
+#define E_CLASS_WRONG_CONTEXT            0x0400
+#define E_CLASS_BAD_SPECIFIC_PARAMETER   0x0500
+#define E_CLASS_REAL_TIME_ERROR          0x0600
+#define E_CLASS_DIRECTSHOW               0x0700
+#define E_CLASS_FREE                     0x0700
+
+
+/* Complete DRV error code for the general class */
+#define ED_GN           (ERROR_VALUE | E_SOURCE_DRV | E_CLASS_GENERAL)
+#define ED_CONCURRENCY                  (ED_GN | 0x01)
+#define ED_DSP_CRASHED                  (ED_GN | 0x02)
+#define ED_UNKNOWN_BOARD                (ED_GN | 0x03)
+#define ED_NOT_INSTALLED                (ED_GN | 0x04)
+#define ED_CANNOT_OPEN_SVC_MANAGER      (ED_GN | 0x05)
+#define ED_CANNOT_READ_REGISTRY         (ED_GN | 0x06)
+#define ED_DSP_VERSION_MISMATCH         (ED_GN | 0x07)
+#define ED_UNAVAILABLE_FEATURE          (ED_GN | 0x08)
+#define ED_CANCELLED                    (ED_GN | 0x09)
+#define ED_NO_RESPONSE_AT_IRQA          (ED_GN | 0x10)
+#define ED_INVALID_ADDRESS              (ED_GN | 0x11)
+#define ED_DSP_CORRUPTED                (ED_GN | 0x12)
+#define ED_PENDING_OPERATION            (ED_GN | 0x13)
+#define ED_NET_ALLOCATE_MEMORY_IMPOSSIBLE   (ED_GN | 0x14)
+#define ED_NET_REGISTER_ERROR               (ED_GN | 0x15)
+#define ED_NET_THREAD_ERROR                 (ED_GN | 0x16)
+#define ED_NET_OPEN_ERROR                   (ED_GN | 0x17)
+#define ED_NET_CLOSE_ERROR                  (ED_GN | 0x18)
+#define ED_NET_NO_MORE_PACKET               (ED_GN | 0x19)
+#define ED_NET_NO_MORE_BUFFER               (ED_GN | 0x1A)
+#define ED_NET_SEND_ERROR                   (ED_GN | 0x1B)
+#define ED_NET_RECEIVE_ERROR                (ED_GN | 0x1C)
+#define ED_NET_WRONG_MSG_SIZE               (ED_GN | 0x1D)
+#define ED_NET_WAIT_ERROR                   (ED_GN | 0x1E)
+#define ED_NET_EEPROM_ERROR                 (ED_GN | 0x1F)
+#define ED_INVALID_RS232_COM_NUMBER         (ED_GN | 0x20)
+#define ED_INVALID_RS232_INIT               (ED_GN | 0x21)
+#define ED_FILE_ERROR                       (ED_GN | 0x22)
+#define ED_INVALID_GPIO_CMD                 (ED_GN | 0x23)
+#define ED_RS232_ALREADY_OPENED             (ED_GN | 0x24)
+#define ED_RS232_NOT_OPENED                 (ED_GN | 0x25)
+#define ED_GPIO_ALREADY_OPENED              (ED_GN | 0x26)
+#define ED_GPIO_NOT_OPENED                  (ED_GN | 0x27)
+#define ED_REGISTRY_ERROR                   (ED_GN | 0x28) /* <- NCX */
+#define ED_INVALID_SERVICE                  (ED_GN | 0x29) /* <- NCX */
+
+#define ED_READ_FILE_ALREADY_OPENED        (ED_GN | 0x2a) /* <- Decalage
+                                                           * pour RCX
+                                                           * (old 0x28)
+                                                           * */
+#define ED_READ_FILE_INVALID_COMMAND       (ED_GN | 0x2b) /* ~ */
+#define ED_READ_FILE_INVALID_PARAMETER     (ED_GN | 0x2c) /* ~ */
+#define ED_READ_FILE_ALREADY_CLOSED        (ED_GN | 0x2d) /* ~ */
+#define ED_READ_FILE_NO_INFORMATION        (ED_GN | 0x2e) /* ~ */
+#define ED_READ_FILE_INVALID_HANDLE        (ED_GN | 0x2f) /* ~ */
+#define ED_READ_FILE_END_OF_FILE           (ED_GN | 0x30) /* ~ */
+#define ED_READ_FILE_ERROR                 (ED_GN | 0x31) /* ~ */
+
+#define ED_DSP_CRASHED_EXC_DSPSTACK_OVERFLOW (ED_GN | 0x32) /* <- Decalage pour
+                                                            * PCX (old 0x14) */
+#define ED_DSP_CRASHED_EXC_SYSSTACK_OVERFLOW (ED_GN | 0x33) /* ~ */
+#define ED_DSP_CRASHED_EXC_ILLEGAL           (ED_GN | 0x34) /* ~ */
+#define ED_DSP_CRASHED_EXC_TIMER_REENTRY     (ED_GN | 0x35) /* ~ */
+#define ED_DSP_CRASHED_EXC_FATAL_ERROR       (ED_GN | 0x36) /* ~ */
+
+#define ED_FLASH_PCCARD_NOT_PRESENT          (ED_GN | 0x37)
+
+#define ED_NO_CURRENT_CLOCK                  (ED_GN | 0x38)
+
+/* Complete DRV error code for real time class */
+#define ED_RT           (ERROR_VALUE | E_SOURCE_DRV | E_CLASS_REAL_TIME_ERROR)
+#define ED_DSP_TIMED_OUT                (ED_RT | 0x01)
+#define ED_DSP_CHK_TIMED_OUT            (ED_RT | 0x02)
+#define ED_STREAM_OVERRUN               (ED_RT | 0x03)
+#define ED_DSP_BUSY                     (ED_RT | 0x04)
+#define ED_DSP_SEMAPHORE_TIME_OUT       (ED_RT | 0x05)
+#define ED_BOARD_TIME_OUT               (ED_RT | 0x06)
+#define ED_XILINX_ERROR                 (ED_RT | 0x07)
+#define ED_COBRANET_ITF_NOT_RESPONDING  (ED_RT | 0x08)
+
+/* Complete BOARD error code for the invaid standard object class */
+#define EB_ISO          (ERROR_VALUE | E_SOURCE_BOARD | \
+                        E_CLASS_INVALID_STD_OBJECT)
+#define EB_INVALID_EFFECT               (EB_ISO | 0x00)
+#define EB_INVALID_PIPE                 (EB_ISO | 0x40)
+#define EB_INVALID_STREAM               (EB_ISO | 0x80)
+#define EB_INVALID_AUDIO                (EB_ISO | 0xC0)
+
+/* Complete BOARD error code for impossible resource allocation class */
+#define EB_RI           (ERROR_VALUE | E_SOURCE_BOARD | E_CLASS_RSRC_IMPOSSIBLE)
+#define EB_ALLOCATE_ALL_STREAM_TRANSFERT_BUFFERS_IMPOSSIBLE (EB_RI | 0x01)
+#define EB_ALLOCATE_PIPE_SAMPLE_BUFFER_IMPOSSIBLE           (EB_RI | 0x02)
+
+#define EB_ALLOCATE_MEM_STREAM_IMPOSSIBLE              \
+       EB_ALLOCATE_ALL_STREAM_TRANSFERT_BUFFERS_IMPOSSIBLE
+#define EB_ALLOCATE_MEM_PIPE_IMPOSSIBLE                        \
+       EB_ALLOCATE_PIPE_SAMPLE_BUFFER_IMPOSSIBLE
+
+#define EB_ALLOCATE_DIFFERED_CMD_IMPOSSIBLE     (EB_RI | 0x03)
+#define EB_TOO_MANY_DIFFERED_CMD                (EB_RI | 0x04)
+#define EB_RBUFFERS_TABLE_OVERFLOW              (EB_RI | 0x05)
+#define EB_ALLOCATE_EFFECTS_IMPOSSIBLE          (EB_RI | 0x08)
+#define EB_ALLOCATE_EFFECT_POS_IMPOSSIBLE       (EB_RI | 0x09)
+#define EB_RBUFFER_NOT_AVAILABLE                (EB_RI | 0x0A)
+#define EB_ALLOCATE_CONTEXT_LIII_IMPOSSIBLE     (EB_RI | 0x0B)
+#define EB_STATUS_DIALOG_IMPOSSIBLE             (EB_RI | 0x1D)
+#define EB_CONTROL_CMD_IMPOSSIBLE               (EB_RI | 0x1E)
+#define EB_STATUS_SEND_IMPOSSIBLE               (EB_RI | 0x1F)
+#define EB_ALLOCATE_PIPE_IMPOSSIBLE             (EB_RI | 0x40)
+#define EB_ALLOCATE_STREAM_IMPOSSIBLE           (EB_RI | 0x80)
+#define EB_ALLOCATE_AUDIO_IMPOSSIBLE            (EB_RI | 0xC0)
+
+/* Complete BOARD error code for wrong call context class */
+#define EB_WCC          (ERROR_VALUE | E_SOURCE_BOARD | E_CLASS_WRONG_CONTEXT)
+#define EB_CMD_REFUSED                  (EB_WCC | 0x00)
+#define EB_START_STREAM_REFUSED         (EB_WCC | 0xFC)
+#define EB_SPC_REFUSED                  (EB_WCC | 0xFD)
+#define EB_CSN_REFUSED                  (EB_WCC | 0xFE)
+#define EB_CSE_REFUSED                  (EB_WCC | 0xFF)
+
+
+
+
+#endif /* LX_DEFS_H */
index c262049961e15a0dd9840645f753584373dac52a..3b5ca70c9d4d2745223ac6f66102f8fd78e11161 100644 (file)
@@ -487,10 +487,14 @@ static int oxygen_hw_free(struct snd_pcm_substream *substream)
 {
        struct oxygen *chip = snd_pcm_substream_chip(substream);
        unsigned int channel = oxygen_substream_channel(substream);
+       unsigned int channel_mask = 1 << channel;
 
        spin_lock_irq(&chip->reg_lock);
-       chip->interrupt_mask &= ~(1 << channel);
+       chip->interrupt_mask &= ~channel_mask;
        oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask);
+
+       oxygen_set_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask);
+       oxygen_clear_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask);
        spin_unlock_irq(&chip->reg_lock);
 
        return snd_pcm_lib_free_pages(substream);
index bc5ce11c8b1444fa632b81ba2684ac4f0410bd08..bf971f7cfdc652984d4824576306e96aaa88b4d6 100644 (file)
  */
 
 /*
- * Xonar Essence STX
- * -----------------
+ * Xonar Essence ST (Deluxe)/STX
+ * -----------------------------
  *
  * CMI8788:
  *
@@ -180,6 +180,8 @@ enum {
        MODEL_DX,
        MODEL_HDAV,     /* without daughterboard */
        MODEL_HDAV_H6,  /* with H6 daughterboard */
+       MODEL_ST,
+       MODEL_ST_H6,
        MODEL_STX,
 };
 
@@ -188,8 +190,10 @@ static struct pci_device_id xonar_ids[] __devinitdata = {
        { 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_BROKEN_EEPROM },
        { }
 };
@@ -210,9 +214,9 @@ MODULE_DEVICE_TABLE(pci, xonar_ids);
 #define GPIO_DX_FRONT_PANEL    0x0002
 #define GPIO_DX_INPUT_ROUTE    0x0100
 
-#define GPIO_HDAV_DB_MASK      0x0030
-#define GPIO_HDAV_DB_H6                0x0000
-#define GPIO_HDAV_DB_XX                0x0020
+#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
@@ -530,7 +534,7 @@ static void xonar_hdav_init(struct oxygen *chip)
        snd_component_add(chip->card, "CS5381");
 }
 
-static void xonar_stx_init(struct oxygen *chip)
+static void xonar_st_init(struct oxygen *chip)
 {
        struct xonar_data *data = chip->model_data;
 
@@ -539,12 +543,11 @@ static void xonar_stx_init(struct oxygen *chip)
                       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 = 1;
+       data->dacs = chip->model.private_data == MODEL_ST_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);
@@ -560,6 +563,17 @@ static void xonar_stx_init(struct oxygen *chip)
        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;
@@ -1021,7 +1035,8 @@ static const struct oxygen_model model_xonar_hdav = {
        .model_data_size = sizeof(struct xonar_data),
        .device_config = PLAYBACK_0_TO_I2S |
                         PLAYBACK_1_TO_SPDIF |
-                        CAPTURE_0_FROM_I2S_2,
+                        CAPTURE_0_FROM_I2S_2 |
+                        CAPTURE_1_FROM_SPDIF,
        .dac_channels = 8,
        .dac_volume_min = 255 - 2*60,
        .dac_volume_max = 255,
@@ -1034,7 +1049,7 @@ static const struct oxygen_model model_xonar_hdav = {
 static const struct oxygen_model model_xonar_st = {
        .longname = "Asus Virtuoso 100",
        .chip = "AV200",
-       .init = xonar_stx_init,
+       .init = xonar_st_init,
        .control_filter = xonar_st_control_filter,
        .mixer_init = xonar_st_mixer_init,
        .cleanup = xonar_st_cleanup,
@@ -1067,6 +1082,7 @@ static int __devinit get_xonar_model(struct oxygen *chip,
                [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[] = {
@@ -1076,6 +1092,8 @@ static int __devinit get_xonar_model(struct oxygen *chip,
                [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;
@@ -1092,21 +1110,27 @@ static int __devinit get_xonar_model(struct oxygen *chip,
                chip->model.init = xonar_dx_init;
                break;
        case MODEL_HDAV:
-               oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
-                                   GPIO_HDAV_DB_MASK);
-               switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) &
-                       GPIO_HDAV_DB_MASK) {
-               case GPIO_HDAV_DB_H6:
+               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_HDAV_DB_XX:
+               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:
-               oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
-                                   GPIO_HDAV_DB_MASK);
+               chip->model.init = xonar_stx_init;
+               oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK);
                break;
        }
 
index e51a5ef1954dc6f933e51e69a59bad674daaa372..235a71e5ac8de6782f9d24027a347b5dc7852046 100644 (file)
@@ -507,41 +507,19 @@ static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip);
  */
 
 static struct pci_device_id snd_riptide_ids[] = {
-       {
-        .vendor = 0x127a,.device = 0x4310,
-        .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID,
-        },
-       {
-        .vendor = 0x127a,.device = 0x4320,
-        .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID,
-        },
-       {
-        .vendor = 0x127a,.device = 0x4330,
-        .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID,
-        },
-       {
-        .vendor = 0x127a,.device = 0x4340,
-        .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID,
-        },
+       { PCI_DEVICE(0x127a, 0x4310) },
+       { PCI_DEVICE(0x127a, 0x4320) },
+       { PCI_DEVICE(0x127a, 0x4330) },
+       { PCI_DEVICE(0x127a, 0x4340) },
        {0,},
 };
 
 #ifdef SUPPORT_JOYSTICK
 static struct pci_device_id snd_riptide_joystick_ids[] __devinitdata = {
-       {
-        .vendor = 0x127a,.device = 0x4312,
-        .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID,
-        },
-       {
-        .vendor = 0x127a,.device = 0x4322,
-        .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID,
-        },
-       {.vendor = 0x127a,.device = 0x4332,
-        .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID,
-        },
-       {.vendor = 0x127a,.device = 0x4342,
-        .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID,
-        },
+       { PCI_DEVICE(0x127a, 0x4312) },
+       { PCI_DEVICE(0x127a, 0x4322) },
+       { PCI_DEVICE(0x127a, 0x4332) },
+       { PCI_DEVICE(0x127a, 0x4342) },
        {0,},
 };
 #endif
@@ -1209,12 +1187,79 @@ static int riptide_resume(struct pci_dev *pci)
 }
 #endif
 
+static int try_to_load_firmware(struct cmdif *cif, struct snd_riptide *chip)
+{
+       union firmware_version firmware = { .ret = CMDRET_ZERO };
+       int i, timeout, err;
+
+       for (i = 0; i < 2; i++) {
+               WRITE_PORT_ULONG(cif->hwport->port[i].data1, 0);
+               WRITE_PORT_ULONG(cif->hwport->port[i].data2, 0);
+       }
+       SET_GRESET(cif->hwport);
+       udelay(100);
+       UNSET_GRESET(cif->hwport);
+       udelay(100);
+
+       for (timeout = 100000; --timeout; udelay(10)) {
+               if (IS_READY(cif->hwport) && !IS_GERR(cif->hwport))
+                       break;
+       }
+       if (!timeout) {
+               snd_printk(KERN_ERR
+                          "Riptide: device not ready, audio status: 0x%x "
+                          "ready: %d gerr: %d\n",
+                          READ_AUDIO_STATUS(cif->hwport),
+                          IS_READY(cif->hwport), IS_GERR(cif->hwport));
+               return -EIO;
+       } else {
+               snd_printdd
+                       ("Riptide: audio status: 0x%x ready: %d gerr: %d\n",
+                        READ_AUDIO_STATUS(cif->hwport),
+                        IS_READY(cif->hwport), IS_GERR(cif->hwport));
+       }
+
+       SEND_GETV(cif, &firmware.ret);
+       snd_printdd("Firmware version: ASIC: %d CODEC %d AUXDSP %d PROG %d\n",
+                   firmware.firmware.ASIC, firmware.firmware.CODEC,
+                   firmware.firmware.AUXDSP, firmware.firmware.PROG);
+
+       for (i = 0; i < FIRMWARE_VERSIONS; i++) {
+               if (!memcmp(&firmware_versions[i], &firmware, sizeof(firmware)))
+                       break;
+       }
+       if (i >= FIRMWARE_VERSIONS)
+               return 0; /* no match */
+
+       if (!chip)
+               return 1; /* OK */
+
+       snd_printdd("Writing Firmware\n");
+       if (!chip->fw_entry) {
+               err = request_firmware(&chip->fw_entry, "riptide.hex",
+                                      &chip->pci->dev);
+               if (err) {
+                       snd_printk(KERN_ERR
+                                  "Riptide: Firmware not available %d\n", err);
+                       return -EIO;
+               }
+       }
+       err = loadfirmware(cif, chip->fw_entry->data, chip->fw_entry->size);
+       if (err) {
+               snd_printk(KERN_ERR
+                          "Riptide: Could not load firmware %d\n", err);
+               return err;
+       }
+
+       chip->firmware = firmware;
+
+       return 1; /* OK */
+}
+
 static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip)
 {
-       int timeout, tries;
        union cmdret rptr = CMDRET_ZERO;
-       union firmware_version firmware;
-       int i, j, err, has_firmware;
+       int err, tries;
 
        if (!cif)
                return -EINVAL;
@@ -1227,75 +1272,11 @@ static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip)
        cif->is_reset = 0;
 
        tries = RESET_TRIES;
-       has_firmware = 0;
-       while (has_firmware == 0 && tries-- > 0) {
-               for (i = 0; i < 2; i++) {
-                       WRITE_PORT_ULONG(cif->hwport->port[i].data1, 0);
-                       WRITE_PORT_ULONG(cif->hwport->port[i].data2, 0);
-               }
-               SET_GRESET(cif->hwport);
-               udelay(100);
-               UNSET_GRESET(cif->hwport);
-               udelay(100);
-
-               for (timeout = 100000; --timeout; udelay(10)) {
-                       if (IS_READY(cif->hwport) && !IS_GERR(cif->hwport))
-                               break;
-               }
-               if (timeout == 0) {
-                       snd_printk(KERN_ERR
-                                  "Riptide: device not ready, audio status: 0x%x ready: %d gerr: %d\n",
-                                  READ_AUDIO_STATUS(cif->hwport),
-                                  IS_READY(cif->hwport), IS_GERR(cif->hwport));
-                       return -EIO;
-               } else {
-                       snd_printdd
-                           ("Riptide: audio status: 0x%x ready: %d gerr: %d\n",
-                            READ_AUDIO_STATUS(cif->hwport),
-                            IS_READY(cif->hwport), IS_GERR(cif->hwport));
-               }
-
-               SEND_GETV(cif, &rptr);
-               for (i = 0; i < 4; i++)
-                       firmware.ret.retwords[i] = rptr.retwords[i];
-
-               snd_printdd
-                   ("Firmware version: ASIC: %d CODEC %d AUXDSP %d PROG %d\n",
-                    firmware.firmware.ASIC, firmware.firmware.CODEC,
-                    firmware.firmware.AUXDSP, firmware.firmware.PROG);
-
-               for (j = 0; j < FIRMWARE_VERSIONS; j++) {
-                       has_firmware = 1;
-                       for (i = 0; i < 4; i++) {
-                               if (firmware_versions[j].ret.retwords[i] !=
-                                   firmware.ret.retwords[i])
-                                       has_firmware = 0;
-                       }
-                       if (has_firmware)
-                               break;
-               }
-
-               if (chip != NULL && has_firmware == 0) {
-                       snd_printdd("Writing Firmware\n");
-                       if (!chip->fw_entry) {
-                               if ((err =
-                                    request_firmware(&chip->fw_entry,
-                                                     "riptide.hex",
-                                                     &chip->pci->dev)) != 0) {
-                                       snd_printk(KERN_ERR
-                                                  "Riptide: Firmware not available %d\n",
-                                                  err);
-                                       return -EIO;
-                               }
-                       }
-                       err = loadfirmware(cif, chip->fw_entry->data,
-                                          chip->fw_entry->size);
-                       if (err)
-                               snd_printk(KERN_ERR
-                                          "Riptide: Could not load firmware %d\n",
-                                          err);
-               }
-       }
+       do {
+               err = try_to_load_firmware(cif, chip);
+               if (err < 0)
+                       return err;
+       } while (!err && --tries);
 
        SEND_SACR(cif, 0, AC97_RESET);
        SEND_RACR(cif, AC97_RESET, &rptr);
@@ -1337,11 +1318,6 @@ static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip)
        SET_AIE(cif->hwport);
        SET_AIACK(cif->hwport);
        cif->is_reset = 1;
-       if (chip) {
-               for (i = 0; i < 4; i++)
-                       chip->firmware.ret.retwords[i] =
-                           firmware.ret.retwords[i];
-       }
 
        return 0;
 }
@@ -2038,14 +2014,12 @@ static int __devinit snd_riptide_mixer(struct snd_riptide *chip)
 }
 
 #ifdef SUPPORT_JOYSTICK
-static int have_joystick;
-static struct pci_dev *riptide_gameport_pci;
-static struct gameport *riptide_gameport;
 
 static int __devinit
 snd_riptide_joystick_probe(struct pci_dev *pci, const struct pci_device_id *id)
 {
        static int dev;
+       struct gameport *gameport;
 
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
@@ -2054,36 +2028,33 @@ snd_riptide_joystick_probe(struct pci_dev *pci, const struct pci_device_id *id)
                return -ENOENT;
        }
 
-       if (joystick_port[dev]) {
-               riptide_gameport = gameport_allocate_port();
-               if (riptide_gameport) {
-                       if (!request_region
-                           (joystick_port[dev], 8, "Riptide gameport")) {
-                               snd_printk(KERN_WARNING
-                                          "Riptide: cannot grab gameport 0x%x\n",
-                                          joystick_port[dev]);
-                               gameport_free_port(riptide_gameport);
-                               riptide_gameport = NULL;
-                       } else {
-                               riptide_gameport_pci = pci;
-                               riptide_gameport->io = joystick_port[dev];
-                               gameport_register_port(riptide_gameport);
-                       }
-               }
+       if (!joystick_port[dev++])
+               return 0;
+
+       gameport = gameport_allocate_port();
+       if (!gameport)
+               return -ENOMEM;
+       if (!request_region(joystick_port[dev], 8, "Riptide gameport")) {
+               snd_printk(KERN_WARNING
+                          "Riptide: cannot grab gameport 0x%x\n",
+                          joystick_port[dev]);
+               gameport_free_port(gameport);
+               return -EBUSY;
        }
-       dev++;
+
+       gameport->io = joystick_port[dev];
+       gameport_register_port(gameport);
+       pci_set_drvdata(pci, gameport);
        return 0;
 }
 
 static void __devexit snd_riptide_joystick_remove(struct pci_dev *pci)
 {
-       if (riptide_gameport) {
-               if (riptide_gameport_pci == pci) {
-                       release_region(riptide_gameport->io, 8);
-                       riptide_gameport_pci = NULL;
-                       gameport_unregister_port(riptide_gameport);
-                       riptide_gameport = NULL;
-               }
+       struct gameport *gameport = pci_get_drvdata(pci);
+       if (gameport) {
+               release_region(gameport->io, 8);
+               gameport_unregister_port(gameport);
+               pci_set_drvdata(pci, NULL);
        }
 }
 #endif
@@ -2094,8 +2065,8 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
        static int dev;
        struct snd_card *card;
        struct snd_riptide *chip;
-       unsigned short addr;
-       int err = 0;
+       unsigned short val;
+       int err;
 
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
@@ -2107,60 +2078,63 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
        err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
        if (err < 0)
                return err;
-       if ((err = snd_riptide_create(card, pci, &chip)) < 0) {
-               snd_card_free(card);
-               return err;
-       }
+       err = snd_riptide_create(card, pci, &chip);
+       if (err < 0)
+               goto error;
        card->private_data = chip;
-       if ((err = snd_riptide_pcm(chip, 0, NULL)) < 0) {
-               snd_card_free(card);
-               return err;
-       }
-       if ((err = snd_riptide_mixer(chip)) < 0) {
-               snd_card_free(card);
-               return err;
-       }
-       pci_write_config_word(chip->pci, PCI_EXT_Legacy_Mask, LEGACY_ENABLE_ALL
-                             | (opl3_port[dev] ? LEGACY_ENABLE_FM : 0)
+       err = snd_riptide_pcm(chip, 0, NULL);
+       if (err < 0)
+               goto error;
+       err = snd_riptide_mixer(chip);
+       if (err < 0)
+               goto error;
+
+       val = LEGACY_ENABLE_ALL;
+       if (opl3_port[dev])
+               val |= LEGACY_ENABLE_FM;
 #ifdef SUPPORT_JOYSTICK
-                             | (joystick_port[dev] ? LEGACY_ENABLE_GAMEPORT :
-                                0)
+       if (joystick_port[dev])
+               val |= LEGACY_ENABLE_GAMEPORT;
 #endif
-                             | (mpu_port[dev]
-                                ? (LEGACY_ENABLE_MPU_INT | LEGACY_ENABLE_MPU) :
-                                0)
-                             | ((chip->irq << 4) & 0xF0));
-       if ((addr = mpu_port[dev]) != 0) {
-               pci_write_config_word(chip->pci, PCI_EXT_MPU_Base, addr);
-               if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_RIPTIDE,
-                                              addr, 0, chip->irq, 0,
-                                              &chip->rmidi)) < 0)
+       if (mpu_port[dev])
+               val |= LEGACY_ENABLE_MPU_INT | LEGACY_ENABLE_MPU;
+       val |= (chip->irq << 4) & 0xf0;
+       pci_write_config_word(chip->pci, PCI_EXT_Legacy_Mask, val);
+       if (mpu_port[dev]) {
+               val = mpu_port[dev];
+               pci_write_config_word(chip->pci, PCI_EXT_MPU_Base, val);
+               err = snd_mpu401_uart_new(card, 0, MPU401_HW_RIPTIDE,
+                                         val, 0, chip->irq, 0,
+                                         &chip->rmidi);
+               if (err < 0)
                        snd_printk(KERN_WARNING
                                   "Riptide: Can't Allocate MPU at 0x%x\n",
-                                  addr);
+                                  val);
                else
-                       chip->mpuaddr = addr;
+                       chip->mpuaddr = val;
        }
-       if ((addr = opl3_port[dev]) != 0) {
-               pci_write_config_word(chip->pci, PCI_EXT_FM_Base, addr);
-               if ((err = snd_opl3_create(card, addr, addr + 2,
-                                          OPL3_HW_RIPTIDE, 0,
-                                          &chip->opl3)) < 0)
+       if (opl3_port[dev]) {
+               val = opl3_port[dev];
+               pci_write_config_word(chip->pci, PCI_EXT_FM_Base, val);
+               err = snd_opl3_create(card, val, val + 2,
+                                     OPL3_HW_RIPTIDE, 0, &chip->opl3);
+               if (err < 0)
                        snd_printk(KERN_WARNING
                                   "Riptide: Can't Allocate OPL3 at 0x%x\n",
-                                  addr);
+                                  val);
                else {
-                       chip->opladdr = addr;
-                       if ((err =
-                            snd_opl3_hwdep_new(chip->opl3, 0, 1, NULL)) < 0)
+                       chip->opladdr = val;
+                       err = snd_opl3_hwdep_new(chip->opl3, 0, 1, NULL);
+                       if (err < 0)
                                snd_printk(KERN_WARNING
                                           "Riptide: Can't Allocate OPL3-HWDEP\n");
                }
        }
 #ifdef SUPPORT_JOYSTICK
-       if ((addr = joystick_port[dev]) != 0) {
-               pci_write_config_word(chip->pci, PCI_EXT_Game_Base, addr);
-               chip->gameaddr = addr;
+       if (joystick_port[dev]) {
+               val = joystick_port[dev];
+               pci_write_config_word(chip->pci, PCI_EXT_Game_Base, val);
+               chip->gameaddr = val;
        }
 #endif
 
@@ -2178,13 +2152,16 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                 chip->opladdr);
 #endif
        snd_riptide_proc_init(chip);
-       if ((err = snd_card_register(card)) < 0) {
-               snd_card_free(card);
-               return err;
-       }
+       err = snd_card_register(card);
+       if (err < 0)
+               goto error;
        pci_set_drvdata(pci, card);
        dev++;
        return 0;
+
+ error:
+       snd_card_free(card);
+       return err;
 }
 
 static void __devexit snd_card_riptide_remove(struct pci_dev *pci)
@@ -2216,14 +2193,11 @@ static struct pci_driver joystick_driver = {
 static int __init alsa_card_riptide_init(void)
 {
        int err;
-       if ((err = pci_register_driver(&driver)) < 0)
+       err = pci_register_driver(&driver);
+       if (err < 0)
                return err;
 #if defined(SUPPORT_JOYSTICK)
-       if (pci_register_driver(&joystick_driver) < 0) {
-               have_joystick = 0;
-               snd_printk(KERN_INFO "no joystick found\n");
-       } else
-               have_joystick = 1;
+       pci_register_driver(&joystick_driver);
 #endif
        return 0;
 }
@@ -2232,8 +2206,7 @@ static void __exit alsa_card_riptide_exit(void)
 {
        pci_unregister_driver(&driver);
 #if defined(SUPPORT_JOYSTICK)
-       if (have_joystick)
-               pci_unregister_driver(&joystick_driver);
+       pci_unregister_driver(&joystick_driver);
 #endif
 }
 
index 314e73531bd176121dead403390c1cdfca4dc13f..3da5c029f93bc763ad25322ee0cfe7e1eb356728 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/pci.h>
 #include <linux/firmware.h>
 #include <linux/moduleparam.h>
+#include <linux/math64.h>
 
 #include <sound/core.h>
 #include <sound/control.h>
@@ -402,9 +403,9 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin");
 #define HDSP_DMA_AREA_BYTES ((HDSP_MAX_CHANNELS+1) * HDSP_CHANNEL_BUFFER_BYTES)
 #define HDSP_DMA_AREA_KILOBYTES (HDSP_DMA_AREA_BYTES/1024)
 
-/* use hotplug firmeare loader? */
+/* use hotplug firmware loader? */
 #if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
-#if !defined(HDSP_USE_HWDEP_LOADER) && !defined(CONFIG_SND_HDSP)
+#if !defined(HDSP_USE_HWDEP_LOADER)
 #define HDSP_FW_LOADER
 #endif
 #endif
@@ -1047,7 +1048,6 @@ static int hdsp_set_interrupt_interval(struct hdsp *s, unsigned int frames)
 static void hdsp_set_dds_value(struct hdsp *hdsp, int rate)
 {
        u64 n;
-       u32 r;
 
        if (rate >= 112000)
                rate /= 4;
@@ -1055,7 +1055,7 @@ static void hdsp_set_dds_value(struct hdsp *hdsp, int rate)
                rate /= 2;
 
        n = DDS_NUMERATOR;
-       div64_32(&n, rate, &r);
+       n = div_u64(n, rate);
        /* n should be less than 2^32 for being written to FREQ register */
        snd_BUG_ON(n >> 32);
        /* HDSP_freqReg and HDSP_resetPointer are the same, so keep the DDS
@@ -3097,7 +3097,6 @@ static int snd_hdsp_get_adat_sync_check(struct snd_kcontrol *kcontrol, struct sn
 static int hdsp_dds_offset(struct hdsp *hdsp)
 {
        u64 n;
-       u32 r;
        unsigned int dds_value = hdsp->dds_value;
        int system_sample_rate = hdsp->system_sample_rate;
 
@@ -3109,7 +3108,7 @@ static int hdsp_dds_offset(struct hdsp *hdsp)
         * dds_value = n / rate
         * rate = n / dds_value
         */
-       div64_32(&n, dds_value, &r);
+       n = div_u64(n, dds_value);
        if (system_sample_rate >= 112000)
                n *= 4;
        else if (system_sample_rate >= 56000)
index bac2dc0c5d85698bd7bb6796525b6f622d2fbe3d..0dce331a2a3b105e565e7deaa315fdb39c575d4d 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/moduleparam.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
+#include <linux/math64.h>
 #include <asm/io.h>
 
 #include <sound/core.h>
@@ -831,7 +832,6 @@ static int hdspm_set_interrupt_interval(struct hdspm * s, unsigned int frames)
 static void hdspm_set_dds_value(struct hdspm *hdspm, int rate)
 {
        u64 n;
-       u32 r;
        
        if (rate >= 112000)
                rate /= 4;
@@ -844,7 +844,7 @@ static void hdspm_set_dds_value(struct hdspm *hdspm, int rate)
         */        
        /* n = 104857600000000ULL; */ /*  =  2^20 * 10^8 */
        n = 110100480000000ULL;    /* Value checked for AES32 and MADI */
-       div64_32(&n, rate, &r);
+       n = div_u64(n, rate);
        /* n should be less than 2^32 for being written to FREQ register */
        snd_BUG_ON(n >> 32);
        hdspm_write(hdspm, HDSPM_freqReg, (u32)n);
index 013b6739a742ce3d829ed9b374015f7e9a4f6462..bc8c768194080e9794855fedaed239fd6bcf75f1 100644 (file)
 #define SIS_WEISR_B    0xac
 
 
-/* Playback DMA parameters (paramter RAM) */
+/* Playback DMA parameters (parameter RAM) */
 #define SIS_PLAY_DMA_OFFSET    0x0000
 #define SIS_PLAY_DMA_SIZE      0x10
 #define SIS_PLAY_DMA_ADDR(addr, num) \
 #define                SIS_PLAY_DMA_SSO_MASK           0xffff0000
 #define                SIS_PLAY_DMA_ESO_MASK           0x0000ffff
 
-/* Capture DMA parameters (paramter RAM) */
+/* Capture DMA parameters (parameter RAM) */
 #define SIS_CAPTURE_DMA_OFFSET 0x0800
 #define SIS_CAPTURE_DMA_SIZE   0x10
 #define SIS_CAPTURE_DMA_ADDR(addr, num) \
index c0efe4491116bf1857255bbb6a1dcde1e91afe3e..6416d3f0c7be8210559f1ad8dda61f1a974fc023 100644 (file)
@@ -367,7 +367,7 @@ static int vx2_load_xilinx_binary(struct vx_core *chip, const struct firmware *x
        unsigned int port;
        const unsigned char *image;
 
-       /* XILINX reset (wait at least 1 milisecond between reset on and off). */
+       /* XILINX reset (wait at least 1 millisecond between reset on and off). */
        vx_outl(chip, CNTRL, VX_CNTRL_REGISTER_VALUE | VX_XILINX_RESET_MASK);
        vx_inl(chip, CNTRL);
        msleep(10);
index 80df9b1f651e01fbfec1302d77cd8673308a7b31..2cc0eda4f20ea4cf760fb7158617a46c69e6da6e 100644 (file)
@@ -477,7 +477,7 @@ static int snd_pmac_awacs_put_master_amp(struct snd_kcontrol *kcontrol,
 #define AMP_CH_SPK     0
 #define AMP_CH_HD      1
 
-static struct snd_kcontrol_new snd_pmac_awacs_amp_vol[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_awacs_amp_vol[] __devinitdata = {
        { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
          .name = "PC Speaker Playback Volume",
          .info = snd_pmac_awacs_info_volume_amp,
@@ -514,7 +514,7 @@ static struct snd_kcontrol_new snd_pmac_awacs_amp_vol[] __initdata = {
        },
 };
 
-static struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw __initdata = {
+static struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw __devinitdata = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "Headphone Playback Switch",
        .info = snd_pmac_boolean_stereo_info,
@@ -523,7 +523,7 @@ static struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw __initdata = {
        .private_value = AMP_CH_HD,
 };
 
-static struct snd_kcontrol_new snd_pmac_awacs_amp_spk_sw __initdata = {
+static struct snd_kcontrol_new snd_pmac_awacs_amp_spk_sw __devinitdata = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "PC Speaker Playback Switch",
        .info = snd_pmac_boolean_stereo_info,
@@ -595,46 +595,46 @@ static int snd_pmac_screamer_mic_boost_put(struct snd_kcontrol *kcontrol,
 /*
  * lists of mixer elements
  */
-static struct snd_kcontrol_new snd_pmac_awacs_mixers[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_awacs_mixers[] __devinitdata = {
        AWACS_SWITCH("Master Capture Switch", 1, SHIFT_LOOPTHRU, 0),
        AWACS_VOLUME("Master Capture Volume", 0, 4, 0),
 /*     AWACS_SWITCH("Unknown Playback Switch", 6, SHIFT_PAROUT0, 0), */
 };
 
-static struct snd_kcontrol_new snd_pmac_screamer_mixers_beige[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_screamer_mixers_beige[] __devinitdata = {
        AWACS_VOLUME("Master Playback Volume", 2, 6, 1),
        AWACS_VOLUME("Play-through Playback Volume", 5, 6, 1),
        AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0),
        AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_LINE, 0),
 };
 
-static struct snd_kcontrol_new snd_pmac_screamer_mixers_lo[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_screamer_mixers_lo[] __devinitdata = {
        AWACS_VOLUME("Line out Playback Volume", 2, 6, 1),
 };
 
-static struct snd_kcontrol_new snd_pmac_screamer_mixers_imac[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_screamer_mixers_imac[] __devinitdata = {
        AWACS_VOLUME("Play-through Playback Volume", 5, 6, 1),
        AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
 };
 
-static struct snd_kcontrol_new snd_pmac_screamer_mixers_g4agp[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_screamer_mixers_g4agp[] __devinitdata = {
        AWACS_VOLUME("Line out Playback Volume", 2, 6, 1),
        AWACS_VOLUME("Master Playback Volume", 5, 6, 1),
        AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
        AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0),
 };
 
-static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac7500[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac7500[] __devinitdata = {
        AWACS_VOLUME("Line out Playback Volume", 2, 6, 1),
        AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
        AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0),
 };
 
-static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac5500[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac5500[] __devinitdata = {
        AWACS_VOLUME("Headphone Playback Volume", 2, 6, 1),
 };
 
-static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac[] __devinitdata = {
        AWACS_VOLUME("Master Playback Volume", 2, 6, 1),
        AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
 };
@@ -642,34 +642,34 @@ static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac[] __initdata = {
 /* FIXME: is this correct order?
  * screamer (powerbook G3 pismo) seems to have different bits...
  */
-static struct snd_kcontrol_new snd_pmac_awacs_mixers2[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_awacs_mixers2[] __devinitdata = {
        AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_LINE, 0),
        AWACS_SWITCH("Mic Capture Switch", 0, SHIFT_MUX_MIC, 0),
 };
 
-static struct snd_kcontrol_new snd_pmac_screamer_mixers2[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_screamer_mixers2[] __devinitdata = {
        AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0),
        AWACS_SWITCH("Mic Capture Switch", 0, SHIFT_MUX_LINE, 0),
 };
 
-static struct snd_kcontrol_new snd_pmac_awacs_mixers2_pmac5500[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_awacs_mixers2_pmac5500[] __devinitdata = {
        AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
 };
 
-static struct snd_kcontrol_new snd_pmac_awacs_master_sw __initdata =
+static struct snd_kcontrol_new snd_pmac_awacs_master_sw __devinitdata =
 AWACS_SWITCH("Master Playback Switch", 1, SHIFT_HDMUTE, 1);
 
-static struct snd_kcontrol_new snd_pmac_awacs_master_sw_imac __initdata =
+static struct snd_kcontrol_new snd_pmac_awacs_master_sw_imac __devinitdata =
 AWACS_SWITCH("Line out Playback Switch", 1, SHIFT_HDMUTE, 1);
 
-static struct snd_kcontrol_new snd_pmac_awacs_master_sw_pmac5500 __initdata =
+static struct snd_kcontrol_new snd_pmac_awacs_master_sw_pmac5500 __devinitdata =
 AWACS_SWITCH("Headphone Playback Switch", 1, SHIFT_HDMUTE, 1);
 
-static struct snd_kcontrol_new snd_pmac_awacs_mic_boost[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_awacs_mic_boost[] __devinitdata = {
        AWACS_SWITCH("Mic Boost Capture Switch", 0, SHIFT_GAINLINE, 0),
 };
 
-static struct snd_kcontrol_new snd_pmac_screamer_mic_boost[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_screamer_mic_boost[] __devinitdata = {
        { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
          .name = "Mic Boost Capture Volume",
          .info = snd_pmac_screamer_mic_boost_info,
@@ -678,34 +678,34 @@ static struct snd_kcontrol_new snd_pmac_screamer_mic_boost[] __initdata = {
        },
 };
 
-static struct snd_kcontrol_new snd_pmac_awacs_mic_boost_pmac7500[] __initdata =
+static struct snd_kcontrol_new snd_pmac_awacs_mic_boost_pmac7500[] __devinitdata =
 {
        AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0),
 };
 
-static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_beige[] __initdata =
+static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_beige[] __devinitdata =
 {
        AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0),
        AWACS_SWITCH("CD Boost Capture Switch", 6, SHIFT_MIC_BOOST, 0),
 };
 
-static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_imac[] __initdata =
+static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_imac[] __devinitdata =
 {
        AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0),
        AWACS_SWITCH("Mic Boost Capture Switch", 6, SHIFT_MIC_BOOST, 0),
 };
 
-static struct snd_kcontrol_new snd_pmac_awacs_speaker_vol[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_awacs_speaker_vol[] __devinitdata = {
        AWACS_VOLUME("PC Speaker Playback Volume", 4, 6, 1),
 };
 
-static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw __initdata =
+static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw __devinitdata =
 AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_SPKMUTE, 1);
 
-static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac1 __initdata =
+static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac1 __devinitdata =
 AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_PAROUT1, 1);
 
-static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac2 __initdata =
+static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac2 __devinitdata =
 AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_PAROUT1, 0);
 
 
@@ -872,7 +872,7 @@ static void snd_pmac_awacs_update_automute(struct snd_pmac *chip, int do_notify)
 /*
  * initialize chip
  */
-int __init
+int __devinit
 snd_pmac_awacs_init(struct snd_pmac *chip)
 {
        int pm7500 = IS_PM7500;
index 89f5c328acfe04952c1dcb4a2c0c66b0a16a70ea..a9d350789f5563a22f1f3184826125599ef8b36e 100644 (file)
@@ -215,7 +215,7 @@ static struct snd_kcontrol_new snd_pmac_beep_mixer = {
 };
 
 /* Initialize beep stuff */
-int __init snd_pmac_attach_beep(struct snd_pmac *chip)
+int __devinit snd_pmac_attach_beep(struct snd_pmac *chip)
 {
        struct pmac_beep *beep;
        struct input_dev *input_dev;
index 45a76297c38d2224abd7fee9b3994f04fd2b2dcf..16ed240e423cfc5ebdb3da1272915e24f0a9c509 100644 (file)
@@ -46,12 +46,12 @@ snd_pmac_burgundy_extend_wait(struct snd_pmac *chip)
        timeout = 50;
        while (!(in_le32(&chip->awacs->codec_stat) & MASK_EXTEND) && timeout--)
                udelay(1);
-       if (! timeout)
+       if (timeout < 0)
                printk(KERN_DEBUG "burgundy_extend_wait: timeout #1\n");
        timeout = 50;
        while ((in_le32(&chip->awacs->codec_stat) & MASK_EXTEND) && timeout--)
                udelay(1);
-       if (! timeout)
+       if (timeout < 0)
                printk(KERN_DEBUG "burgundy_extend_wait: timeout #2\n");
 }
 
@@ -468,7 +468,7 @@ static int snd_pmac_burgundy_put_switch_b(struct snd_kcontrol *kcontrol,
 /*
  * Burgundy mixers
  */
-static struct snd_kcontrol_new snd_pmac_burgundy_mixers[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_burgundy_mixers[] __devinitdata = {
        BURGUNDY_VOLUME_W("Master Playback Volume", 0,
                        MASK_ADDR_BURGUNDY_MASTER_VOLUME, 8),
        BURGUNDY_VOLUME_W("CD Capture Volume", 0,
@@ -496,7 +496,7 @@ static struct snd_kcontrol_new snd_pmac_burgundy_mixers[] __initdata = {
  */    BURGUNDY_SWITCH_B("PCM Capture Switch", 0,
                        MASK_ADDR_BURGUNDY_HOSTIFEH, 0x01, 0, 0)
 };
-static struct snd_kcontrol_new snd_pmac_burgundy_mixers_imac[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_burgundy_mixers_imac[] __devinitdata = {
        BURGUNDY_VOLUME_W("Line in Capture Volume", 0,
                        MASK_ADDR_BURGUNDY_VOLLINE, 16),
        BURGUNDY_VOLUME_W("Mic Capture Volume", 0,
@@ -522,7 +522,7 @@ static struct snd_kcontrol_new snd_pmac_burgundy_mixers_imac[] __initdata = {
        BURGUNDY_SWITCH_B("Mic Boost Capture Switch", 0,
                        MASK_ADDR_BURGUNDY_INPBOOST, 0x40, 0x80, 1)
 };
-static struct snd_kcontrol_new snd_pmac_burgundy_mixers_pmac[] __initdata = {
+static struct snd_kcontrol_new snd_pmac_burgundy_mixers_pmac[] __devinitdata = {
        BURGUNDY_VOLUME_W("Line in Capture Volume", 0,
                        MASK_ADDR_BURGUNDY_VOLMIC, 16),
        BURGUNDY_VOLUME_B("Line in Gain Capture Volume", 0,
@@ -538,33 +538,33 @@ static struct snd_kcontrol_new snd_pmac_burgundy_mixers_pmac[] __initdata = {
 /*     BURGUNDY_SWITCH_B("Line in Boost Capture Switch", 0,
  *             MASK_ADDR_BURGUNDY_INPBOOST, 0x40, 0x80, 1) */
 };
-static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_imac __initdata =
+static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_imac __devinitdata =
 BURGUNDY_SWITCH_B("Master Playback Switch", 0,
        MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
        BURGUNDY_OUTPUT_LEFT | BURGUNDY_LINEOUT_LEFT | BURGUNDY_HP_LEFT,
        BURGUNDY_OUTPUT_RIGHT | BURGUNDY_LINEOUT_RIGHT | BURGUNDY_HP_RIGHT, 1);
-static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_pmac __initdata =
+static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_pmac __devinitdata =
 BURGUNDY_SWITCH_B("Master Playback Switch", 0,
        MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
        BURGUNDY_OUTPUT_INTERN
        | BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1);
-static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_imac __initdata =
+static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_imac __devinitdata =
 BURGUNDY_SWITCH_B("PC 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 __initdata =
+static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_pmac __devinitdata =
 BURGUNDY_SWITCH_B("PC 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 __initdata =
+static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_imac __devinitdata =
 BURGUNDY_SWITCH_B("Line out Playback Switch", 0,
        MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
        BURGUNDY_LINEOUT_LEFT, BURGUNDY_LINEOUT_RIGHT, 1);
-static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_pmac __initdata =
+static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_pmac __devinitdata =
 BURGUNDY_SWITCH_B("Line out Playback Switch", 0,
        MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
        BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1);
-static struct snd_kcontrol_new snd_pmac_burgundy_hp_sw_imac __initdata =
+static struct snd_kcontrol_new snd_pmac_burgundy_hp_sw_imac __devinitdata =
 BURGUNDY_SWITCH_B("Headphone Playback Switch", 0,
        MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
        BURGUNDY_HP_LEFT, BURGUNDY_HP_RIGHT, 1);
@@ -618,7 +618,7 @@ static void snd_pmac_burgundy_update_automute(struct snd_pmac *chip, int do_noti
 /*
  * initialize burgundy
  */
-int __init snd_pmac_burgundy_init(struct snd_pmac *chip)
+int __devinit snd_pmac_burgundy_init(struct snd_pmac *chip)
 {
        int imac = machine_is_compatible("iMac");
        int i, err;
index f8d478c2da62b252d719b067ddff75805a8aa561..24200b7bdacec5a74ab335fbb4ec0fc78062d2d3 100644 (file)
@@ -244,7 +244,7 @@ static void daca_cleanup(struct snd_pmac *chip)
 }
 
 /* exported */
-int __init snd_pmac_daca_init(struct snd_pmac *chip)
+int __devinit snd_pmac_daca_init(struct snd_pmac *chip)
 {
        int i, err;
        struct pmac_daca *mix;
index a5afb2682e7fe7f5196621d62f84379a112dfde2..835fa19ed461864018fb152aa3c41eb57261cb4b 100644 (file)
 static struct pmac_keywest *keywest_ctx;
 
 
-#ifndef i2c_device_name
-#define i2c_device_name(x)     ((x)->name)
-#endif
-
 static int keywest_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
@@ -56,7 +52,7 @@ static int keywest_attach_adapter(struct i2c_adapter *adapter)
        if (! keywest_ctx)
                return -EINVAL;
 
-       if (strncmp(i2c_device_name(adapter), "mac-io", 6))
+       if (strncmp(adapter->name, "mac-io", 6))
                return 0; /* ignored */
 
        memset(&info, 0, sizeof(struct i2c_board_info));
@@ -109,7 +105,7 @@ void snd_pmac_keywest_cleanup(struct pmac_keywest *i2c)
        }
 }
 
-int __init snd_pmac_tumbler_post_init(void)
+int __devinit snd_pmac_tumbler_post_init(void)
 {
        int err;
        
@@ -124,7 +120,7 @@ int __init snd_pmac_tumbler_post_init(void)
 }
 
 /* exported */
-int __init snd_pmac_keywest_init(struct pmac_keywest *i2c)
+int __devinit snd_pmac_keywest_init(struct pmac_keywest *i2c)
 {
        int err;
 
index 9b4e9c316695e2b44cc08099427d3cf015695876..7bc492ee77ecf1978f659e5180e62e55fb990cd9 100644 (file)
@@ -702,7 +702,7 @@ static struct snd_pcm_ops snd_pmac_capture_ops = {
        .pointer =      snd_pmac_capture_pointer,
 };
 
-int __init snd_pmac_pcm_new(struct snd_pmac *chip)
+int __devinit snd_pmac_pcm_new(struct snd_pmac *chip)
 {
        struct snd_pcm *pcm;
        int err;
@@ -908,7 +908,7 @@ static int snd_pmac_dev_free(struct snd_device *device)
  * check the machine support byteswap (little-endian)
  */
 
-static void __init detect_byte_swap(struct snd_pmac *chip)
+static void __devinit detect_byte_swap(struct snd_pmac *chip)
 {
        struct device_node *mio;
 
@@ -934,7 +934,7 @@ static void __init detect_byte_swap(struct snd_pmac *chip)
 /*
  * detect a sound chip
  */
-static int __init snd_pmac_detect(struct snd_pmac *chip)
+static int __devinit snd_pmac_detect(struct snd_pmac *chip)
 {
        struct device_node *sound;
        struct device_node *dn;
@@ -1143,7 +1143,7 @@ static int pmac_hp_detect_get(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-static struct snd_kcontrol_new auto_mute_controls[] __initdata = {
+static struct snd_kcontrol_new auto_mute_controls[] __devinitdata = {
        { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
          .name = "Auto Mute Switch",
          .info = snd_pmac_boolean_mono_info,
@@ -1158,7 +1158,7 @@ static struct snd_kcontrol_new auto_mute_controls[] __initdata = {
        },
 };
 
-int __init snd_pmac_add_automute(struct snd_pmac *chip)
+int __devinit snd_pmac_add_automute(struct snd_pmac *chip)
 {
        int err;
        chip->auto_mute = 1;
@@ -1175,7 +1175,7 @@ int __init snd_pmac_add_automute(struct snd_pmac *chip)
 /*
  * create and detect a pmac chip record
  */
-int __init snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
+int __devinit snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
 {
        struct snd_pmac *chip;
        struct device_node *np;
index f361c26506aacefd1b5a683c232163294c6f9480..53c81a547613ee0482c8dd64b9c3bb0a7b88f2e6 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
 #include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/io.h>
 #include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include <sound/asound.h>
+#include <sound/control.h>
 #include <sound/core.h>
 #include <sound/initval.h>
-#include <sound/pcm.h>
-#include <sound/asound.h>
 #include <sound/memalloc.h>
+#include <sound/pcm.h>
 #include <sound/pcm_params.h>
-#include <sound/control.h>
-#include <linux/dmapool.h>
-#include <linux/dma-mapping.h>
-#include <asm/firmware.h>
+
 #include <asm/dma.h>
+#include <asm/firmware.h>
 #include <asm/lv1call.h>
 #include <asm/ps3.h>
 #include <asm/ps3av.h>
 
-#include "snd_ps3_reg.h"
 #include "snd_ps3.h"
+#include "snd_ps3_reg.h"
 
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("PS3 sound driver");
-MODULE_AUTHOR("Sony Computer Entertainment Inc.");
-
-/* module  entries */
-static int __init snd_ps3_init(void);
-static void __exit snd_ps3_exit(void);
-
-/* ALSA snd driver ops */
-static int snd_ps3_pcm_open(struct snd_pcm_substream *substream);
-static int snd_ps3_pcm_close(struct snd_pcm_substream *substream);
-static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream);
-static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream,
-                                int cmd);
-static snd_pcm_uframes_t snd_ps3_pcm_pointer(struct snd_pcm_substream
-                                            *substream);
-static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream,
-                                struct snd_pcm_hw_params *hw_params);
-static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream);
-
-
-/* ps3_system_bus_driver entries */
-static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev);
-static int snd_ps3_driver_remove(struct ps3_system_bus_device *dev);
-
-/* address setup */
-static int snd_ps3_map_mmio(void);
-static void snd_ps3_unmap_mmio(void);
-static int snd_ps3_allocate_irq(void);
-static void snd_ps3_free_irq(void);
-static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start);
-
-/* interrupt handler */
-static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id);
-
-
-/* set sampling rate/format */
-static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream);
-/* take effect parameter change */
-static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card);
-/* initialize avsetting and take it effect */
-static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card);
-/* setup dma */
-static int snd_ps3_program_dma(struct snd_ps3_card_info *card,
-                              enum snd_ps3_dma_filltype filltype);
-static void snd_ps3_wait_for_dma_stop(struct snd_ps3_card_info *card);
-
-static dma_addr_t v_to_bus(struct snd_ps3_card_info *, void  *vaddr, int ch);
-
-
-module_init(snd_ps3_init);
-module_exit(snd_ps3_exit);
 
 /*
  * global
@@ -165,25 +115,13 @@ static const struct snd_pcm_hardware snd_ps3_pcm_hw = {
        .fifo_size = PS3_AUDIO_FIFO_SIZE
 };
 
-static struct snd_pcm_ops snd_ps3_pcm_spdif_ops =
-{
-       .open = snd_ps3_pcm_open,
-       .close = snd_ps3_pcm_close,
-       .prepare = snd_ps3_pcm_prepare,
-       .ioctl = snd_pcm_lib_ioctl,
-       .trigger = snd_ps3_pcm_trigger,
-       .pointer = snd_ps3_pcm_pointer,
-       .hw_params = snd_ps3_pcm_hw_params,
-       .hw_free = snd_ps3_pcm_hw_free
-};
-
 static int snd_ps3_verify_dma_stop(struct snd_ps3_card_info *card,
                                   int count, int force_stop)
 {
        int dma_ch, done, retries, stop_forced = 0;
        uint32_t status;
 
-       for (dma_ch = 0; dma_ch < 8; dma_ch ++) {
+       for (dma_ch = 0; dma_ch < 8; dma_ch++) {
                retries = count;
                do {
                        status = read_reg(PS3_AUDIO_KICK(dma_ch)) &
@@ -259,9 +197,7 @@ static void snd_ps3_kick_dma(struct snd_ps3_card_info *card)
 /*
  * convert virtual addr to ioif bus addr.
  */
-static dma_addr_t v_to_bus(struct snd_ps3_card_info *card,
-                          void * paddr,
-                          int ch)
+static dma_addr_t v_to_bus(struct snd_ps3_card_info *card, void *paddr, int ch)
 {
        return card->dma_start_bus_addr[ch] +
                (paddr - card->dma_start_vaddr[ch]);
@@ -321,7 +257,7 @@ static int snd_ps3_program_dma(struct snd_ps3_card_info *card,
        spin_lock_irqsave(&card->dma_lock, irqsave);
        for (ch = 0; ch < 2; ch++) {
                start_vaddr = card->dma_next_transfer_vaddr[0];
-               for (stage = 0; stage < fill_stages; stage ++) {
+               for (stage = 0; stage < fill_stages; stage++) {
                        dma_ch = stage * 2 + ch;
                        if (silent)
                                dma_addr = card->null_buffer_start_dma_addr;
@@ -371,6 +307,71 @@ static int snd_ps3_program_dma(struct snd_ps3_card_info *card,
        return 0;
 }
 
+/*
+ * Interrupt handler
+ */
+static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id)
+{
+
+       uint32_t port_intr;
+       int underflow_occured = 0;
+       struct snd_ps3_card_info *card = dev_id;
+
+       if (!card->running) {
+               update_reg(PS3_AUDIO_AX_IS, 0);
+               update_reg(PS3_AUDIO_INTR_0, 0);
+               return IRQ_HANDLED;
+       }
+
+       port_intr = read_reg(PS3_AUDIO_AX_IS);
+       /*
+        *serial buffer empty detected (every 4 times),
+        *program next dma and kick it
+        */
+       if (port_intr & PS3_AUDIO_AX_IE_ASOBEIE(0)) {
+               write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBEIE(0));
+               if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) {
+                       write_reg(PS3_AUDIO_AX_IS, port_intr);
+                       underflow_occured = 1;
+               }
+               if (card->silent) {
+                       /* we are still in silent time */
+                       snd_ps3_program_dma(card,
+                               (underflow_occured) ?
+                               SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL :
+                               SND_PS3_DMA_FILLTYPE_SILENT_RUNNING);
+                       snd_ps3_kick_dma(card);
+                       card->silent--;
+               } else {
+                       snd_ps3_program_dma(card,
+                               (underflow_occured) ?
+                               SND_PS3_DMA_FILLTYPE_FIRSTFILL :
+                               SND_PS3_DMA_FILLTYPE_RUNNING);
+                       snd_ps3_kick_dma(card);
+                       snd_pcm_period_elapsed(card->substream);
+               }
+       } else if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) {
+               write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBUIE(0));
+               /*
+                * serial out underflow, but buffer empty not detected.
+                * in this case, fill fifo with 0 to recover.  After
+                * filling dummy data, serial automatically start to
+                * consume them and then will generate normal buffer
+                * empty interrupts.
+                * If both buffer underflow and buffer empty are occured,
+                * it is better to do nomal data transfer than empty one
+                */
+               snd_ps3_program_dma(card,
+                                   SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
+               snd_ps3_kick_dma(card);
+               snd_ps3_program_dma(card,
+                                   SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
+               snd_ps3_kick_dma(card);
+       }
+       /* clear interrupt cause */
+       return IRQ_HANDLED;
+};
+
 /*
  * audio mute on/off
  * mute_on : 0 output enabled
@@ -381,6 +382,142 @@ static int snd_ps3_mute(int mute_on)
        return ps3av_audio_mute(mute_on);
 }
 
+/*
+ * av setting
+ * NOTE: calling this function may generate audio interrupt.
+ */
+static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card)
+{
+       int ret, retries, i;
+       pr_debug("%s: start\n", __func__);
+
+       ret = ps3av_set_audio_mode(card->avs.avs_audio_ch,
+                                 card->avs.avs_audio_rate,
+                                 card->avs.avs_audio_width,
+                                 card->avs.avs_audio_format,
+                                 card->avs.avs_audio_source);
+       /*
+        * Reset the following unwanted settings:
+        */
+
+       /* disable all 3wire buffers */
+       update_mask_reg(PS3_AUDIO_AO_3WMCTRL,
+                       ~(PS3_AUDIO_AO_3WMCTRL_ASOEN(0) |
+                         PS3_AUDIO_AO_3WMCTRL_ASOEN(1) |
+                         PS3_AUDIO_AO_3WMCTRL_ASOEN(2) |
+                         PS3_AUDIO_AO_3WMCTRL_ASOEN(3)),
+                       0);
+       wmb();  /* ensure the hardware sees the change */
+       /* wait for actually stopped */
+       retries = 1000;
+       while ((read_reg(PS3_AUDIO_AO_3WMCTRL) &
+               (PS3_AUDIO_AO_3WMCTRL_ASORUN(0) |
+                PS3_AUDIO_AO_3WMCTRL_ASORUN(1) |
+                PS3_AUDIO_AO_3WMCTRL_ASORUN(2) |
+                PS3_AUDIO_AO_3WMCTRL_ASORUN(3))) &&
+              --retries) {
+               udelay(1);
+       }
+
+       /* reset buffer pointer */
+       for (i = 0; i < 4; i++) {
+               update_reg(PS3_AUDIO_AO_3WCTRL(i),
+                          PS3_AUDIO_AO_3WCTRL_ASOBRST_RESET);
+               udelay(10);
+       }
+       wmb(); /* ensure the hardware actually start resetting */
+
+       /* enable 3wire#0 buffer */
+       update_reg(PS3_AUDIO_AO_3WMCTRL, PS3_AUDIO_AO_3WMCTRL_ASOEN(0));
+
+
+       /* In 24bit mode,ALSA inserts a zero byte at first byte of per sample */
+       update_mask_reg(PS3_AUDIO_AO_3WCTRL(0),
+                       ~PS3_AUDIO_AO_3WCTRL_ASODF,
+                       PS3_AUDIO_AO_3WCTRL_ASODF_LSB);
+       update_mask_reg(PS3_AUDIO_AO_SPDCTRL(0),
+                       ~PS3_AUDIO_AO_SPDCTRL_SPODF,
+                       PS3_AUDIO_AO_SPDCTRL_SPODF_LSB);
+       /* ensure all the setting above is written back to register */
+       wmb();
+       /* avsetting driver altered AX_IE, caller must reset it if you want */
+       pr_debug("%s: end\n", __func__);
+       return ret;
+}
+
+/*
+ *  set sampling rate according to the substream
+ */
+static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream)
+{
+       struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
+       struct snd_ps3_avsetting_info avs;
+       int ret;
+
+       avs = card->avs;
+
+       pr_debug("%s: called freq=%d width=%d\n", __func__,
+                substream->runtime->rate,
+                snd_pcm_format_width(substream->runtime->format));
+
+       pr_debug("%s: before freq=%d width=%d\n", __func__,
+                card->avs.avs_audio_rate, card->avs.avs_audio_width);
+
+       /* sample rate */
+       switch (substream->runtime->rate) {
+       case 44100:
+               avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_44K;
+               break;
+       case 48000:
+               avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K;
+               break;
+       case 88200:
+               avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_88K;
+               break;
+       case 96000:
+               avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_96K;
+               break;
+       default:
+               pr_info("%s: invalid rate %d\n", __func__,
+                       substream->runtime->rate);
+               return 1;
+       }
+
+       /* width */
+       switch (snd_pcm_format_width(substream->runtime->format)) {
+       case 16:
+               avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16;
+               break;
+       case 24:
+               avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_24;
+               break;
+       default:
+               pr_info("%s: invalid width %d\n", __func__,
+                       snd_pcm_format_width(substream->runtime->format));
+               return 1;
+       }
+
+       memcpy(avs.avs_cs_info, ps3av_mode_cs_info, 8);
+
+       if (memcmp(&card->avs, &avs, sizeof(avs))) {
+               pr_debug("%s: after freq=%d width=%d\n", __func__,
+                        card->avs.avs_audio_rate, card->avs.avs_audio_width);
+
+               card->avs = avs;
+               snd_ps3_change_avsetting(card);
+               ret = 0;
+       } else
+               ret = 1;
+
+       /* check CS non-audio bit and mute accordingly */
+       if (avs.avs_cs_info[0] & 0x02)
+               ps3av_audio_mute_analog(1); /* mute if non-audio */
+       else
+               ps3av_audio_mute_analog(0);
+
+       return ret;
+}
+
 /*
  * PCM operators
  */
@@ -406,6 +543,13 @@ static int snd_ps3_pcm_open(struct snd_pcm_substream *substream)
        return 0;
 };
 
+static int snd_ps3_pcm_close(struct snd_pcm_substream *substream)
+{
+       /* mute on */
+       snd_ps3_mute(1);
+       return 0;
+};
+
 static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *hw_params)
 {
@@ -417,6 +561,13 @@ static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream,
        return 0;
 };
 
+static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       int ret;
+       ret = snd_pcm_lib_free_pages(substream);
+       return ret;
+};
+
 static int snd_ps3_delay_to_bytes(struct snd_pcm_substream *substream,
                                  unsigned int delay_ms)
 {
@@ -473,284 +624,88 @@ static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream)
                card->dma_last_transfer_vaddr[SND_PS3_CH_R] =
                        card->dma_next_transfer_vaddr[SND_PS3_CH_R] =
                        card->dma_start_vaddr[SND_PS3_CH_R] =
-                       runtime->dma_area + (runtime->dma_bytes / 2);
-               card->dma_start_bus_addr[SND_PS3_CH_R] =
-                       runtime->dma_addr + (runtime->dma_bytes / 2);
-
-               pr_debug("%s: vaddr=%p bus=%#llx\n", __func__,
-                        card->dma_start_vaddr[SND_PS3_CH_L],
-                        card->dma_start_bus_addr[SND_PS3_CH_L]);
-
-       }
-       spin_unlock_irqrestore(&card->dma_lock, irqsave);
-
-       /* ensure the hardware sees the change */
-       mb();
-
-       return 0;
-};
-
-static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream,
-                              int cmd)
-{
-       struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
-       int ret = 0;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               /* clear outstanding interrupts  */
-               update_reg(PS3_AUDIO_AX_IS, 0);
-
-               spin_lock(&card->dma_lock);
-               {
-                       card->running = 1;
-               }
-               spin_unlock(&card->dma_lock);
-
-               snd_ps3_program_dma(card,
-                                   SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
-               snd_ps3_kick_dma(card);
-               while (read_reg(PS3_AUDIO_KICK(7)) &
-                      PS3_AUDIO_KICK_STATUS_MASK) {
-                       udelay(1);
-               }
-               snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_RUNNING);
-               snd_ps3_kick_dma(card);
-               break;
-
-       case SNDRV_PCM_TRIGGER_STOP:
-               spin_lock(&card->dma_lock);
-               {
-                       card->running = 0;
-               }
-               spin_unlock(&card->dma_lock);
-               snd_ps3_wait_for_dma_stop(card);
-               break;
-       default:
-               break;
-
-       }
-
-       return ret;
-};
-
-/*
- * report current pointer
- */
-static snd_pcm_uframes_t snd_ps3_pcm_pointer(
-       struct snd_pcm_substream *substream)
-{
-       struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
-       size_t bytes;
-       snd_pcm_uframes_t ret;
-
-       spin_lock(&card->dma_lock);
-       {
-               bytes = (size_t)(card->dma_last_transfer_vaddr[SND_PS3_CH_L] -
-                                card->dma_start_vaddr[SND_PS3_CH_L]);
-       }
-       spin_unlock(&card->dma_lock);
-
-       ret = bytes_to_frames(substream->runtime, bytes * 2);
-
-       return ret;
-};
-
-static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-       int ret;
-       ret = snd_pcm_lib_free_pages(substream);
-       return ret;
-};
-
-static int snd_ps3_pcm_close(struct snd_pcm_substream *substream)
-{
-       /* mute on */
-       snd_ps3_mute(1);
-       return 0;
-};
-
-static void snd_ps3_audio_fixup(struct snd_ps3_card_info *card)
-{
-       /*
-        * avsetting driver seems to never change the followings
-        * so, init them here once
-        */
-
-       /* no dma interrupt needed */
-       write_reg(PS3_AUDIO_INTR_EN_0, 0);
-
-       /* use every 4 buffer empty interrupt */
-       update_mask_reg(PS3_AUDIO_AX_IC,
-                       PS3_AUDIO_AX_IC_AASOIMD_MASK,
-                       PS3_AUDIO_AX_IC_AASOIMD_EVERY4);
-
-       /* enable 3wire clocks */
-       update_mask_reg(PS3_AUDIO_AO_3WMCTRL,
-                       ~(PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_DISABLED |
-                         PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_DISABLED),
-                       0);
-       update_reg(PS3_AUDIO_AO_3WMCTRL,
-                  PS3_AUDIO_AO_3WMCTRL_ASOPLRCK_DEFAULT);
-}
-
-/*
- * av setting
- * NOTE: calling this function may generate audio interrupt.
- */
-static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card)
-{
-       int ret, retries, i;
-       pr_debug("%s: start\n", __func__);
-
-       ret = ps3av_set_audio_mode(card->avs.avs_audio_ch,
-                                 card->avs.avs_audio_rate,
-                                 card->avs.avs_audio_width,
-                                 card->avs.avs_audio_format,
-                                 card->avs.avs_audio_source);
-       /*
-        * Reset the following unwanted settings:
-        */
-
-       /* disable all 3wire buffers */
-       update_mask_reg(PS3_AUDIO_AO_3WMCTRL,
-                       ~(PS3_AUDIO_AO_3WMCTRL_ASOEN(0) |
-                         PS3_AUDIO_AO_3WMCTRL_ASOEN(1) |
-                         PS3_AUDIO_AO_3WMCTRL_ASOEN(2) |
-                         PS3_AUDIO_AO_3WMCTRL_ASOEN(3)),
-                       0);
-       wmb();  /* ensure the hardware sees the change */
-       /* wait for actually stopped */
-       retries = 1000;
-       while ((read_reg(PS3_AUDIO_AO_3WMCTRL) &
-               (PS3_AUDIO_AO_3WMCTRL_ASORUN(0) |
-                PS3_AUDIO_AO_3WMCTRL_ASORUN(1) |
-                PS3_AUDIO_AO_3WMCTRL_ASORUN(2) |
-                PS3_AUDIO_AO_3WMCTRL_ASORUN(3))) &&
-              --retries) {
-               udelay(1);
-       }
-
-       /* reset buffer pointer */
-       for (i = 0; i < 4; i++) {
-               update_reg(PS3_AUDIO_AO_3WCTRL(i),
-                          PS3_AUDIO_AO_3WCTRL_ASOBRST_RESET);
-               udelay(10);
-       }
-       wmb(); /* ensure the hardware actually start resetting */
-
-       /* enable 3wire#0 buffer */
-       update_reg(PS3_AUDIO_AO_3WMCTRL, PS3_AUDIO_AO_3WMCTRL_ASOEN(0));
-
-
-       /* In 24bit mode,ALSA inserts a zero byte at first byte of per sample */
-       update_mask_reg(PS3_AUDIO_AO_3WCTRL(0),
-                       ~PS3_AUDIO_AO_3WCTRL_ASODF,
-                       PS3_AUDIO_AO_3WCTRL_ASODF_LSB);
-       update_mask_reg(PS3_AUDIO_AO_SPDCTRL(0),
-                       ~PS3_AUDIO_AO_SPDCTRL_SPODF,
-                       PS3_AUDIO_AO_SPDCTRL_SPODF_LSB);
-       /* ensure all the setting above is written back to register */
-       wmb();
-       /* avsetting driver altered AX_IE, caller must reset it if you want */
-       pr_debug("%s: end\n", __func__);
-       return ret;
-}
+                       runtime->dma_area + (runtime->dma_bytes / 2);
+               card->dma_start_bus_addr[SND_PS3_CH_R] =
+                       runtime->dma_addr + (runtime->dma_bytes / 2);
 
-static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card)
-{
-       int ret;
-       pr_debug("%s: start\n", __func__);
-       card->avs.avs_audio_ch = PS3AV_CMD_AUDIO_NUM_OF_CH_2;
-       card->avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K;
-       card->avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16;
-       card->avs.avs_audio_format = PS3AV_CMD_AUDIO_FORMAT_PCM;
-       card->avs.avs_audio_source = PS3AV_CMD_AUDIO_SOURCE_SERIAL;
-       memcpy(card->avs.avs_cs_info, ps3av_mode_cs_info, 8);
+               pr_debug("%s: vaddr=%p bus=%#llx\n", __func__,
+                        card->dma_start_vaddr[SND_PS3_CH_L],
+                        card->dma_start_bus_addr[SND_PS3_CH_L]);
 
-       ret = snd_ps3_change_avsetting(card);
+       }
+       spin_unlock_irqrestore(&card->dma_lock, irqsave);
 
-       snd_ps3_audio_fixup(card);
+       /* ensure the hardware sees the change */
+       mb();
 
-       /* to start to generate SPDIF signal, fill data */
-       snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
-       snd_ps3_kick_dma(card);
-       pr_debug("%s: end\n", __func__);
-       return ret;
-}
+       return 0;
+};
 
-/*
- *  set sampling rate according to the substream
- */
-static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream)
+static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream,
+                              int cmd)
 {
        struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
-       struct snd_ps3_avsetting_info avs;
-       int ret;
-
-       avs = card->avs;
+       int ret = 0;
 
-       pr_debug("%s: called freq=%d width=%d\n", __func__,
-                substream->runtime->rate,
-                snd_pcm_format_width(substream->runtime->format));
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               /* clear outstanding interrupts  */
+               update_reg(PS3_AUDIO_AX_IS, 0);
 
-       pr_debug("%s: before freq=%d width=%d\n", __func__,
-                card->avs.avs_audio_rate, card->avs.avs_audio_width);
+               spin_lock(&card->dma_lock);
+               {
+                       card->running = 1;
+               }
+               spin_unlock(&card->dma_lock);
 
-       /* sample rate */
-       switch (substream->runtime->rate) {
-       case 44100:
-               avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_44K;
-               break;
-       case 48000:
-               avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K;
-               break;
-       case 88200:
-               avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_88K;
-               break;
-       case 96000:
-               avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_96K;
+               snd_ps3_program_dma(card,
+                                   SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
+               snd_ps3_kick_dma(card);
+               while (read_reg(PS3_AUDIO_KICK(7)) &
+                      PS3_AUDIO_KICK_STATUS_MASK) {
+                       udelay(1);
+               }
+               snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_RUNNING);
+               snd_ps3_kick_dma(card);
                break;
-       default:
-               pr_info("%s: invalid rate %d\n", __func__,
-                       substream->runtime->rate);
-               return 1;
-       }
 
-       /* width */
-       switch (snd_pcm_format_width(substream->runtime->format)) {
-       case 16:
-               avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16;
-               break;
-       case 24:
-               avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_24;
+       case SNDRV_PCM_TRIGGER_STOP:
+               spin_lock(&card->dma_lock);
+               {
+                       card->running = 0;
+               }
+               spin_unlock(&card->dma_lock);
+               snd_ps3_wait_for_dma_stop(card);
                break;
        default:
-               pr_info("%s: invalid width %d\n", __func__,
-                       snd_pcm_format_width(substream->runtime->format));
-               return 1;
+               break;
+
        }
 
-       memcpy(avs.avs_cs_info, ps3av_mode_cs_info, 8);
+       return ret;
+};
 
-       if (memcmp(&card->avs, &avs, sizeof(avs))) {
-               pr_debug("%s: after freq=%d width=%d\n", __func__,
-                        card->avs.avs_audio_rate, card->avs.avs_audio_width);
+/*
+ * report current pointer
+ */
+static snd_pcm_uframes_t snd_ps3_pcm_pointer(
+       struct snd_pcm_substream *substream)
+{
+       struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
+       size_t bytes;
+       snd_pcm_uframes_t ret;
 
-               card->avs = avs;
-               snd_ps3_change_avsetting(card);
-               ret = 0;
-       } else
-               ret = 1;
+       spin_lock(&card->dma_lock);
+       {
+               bytes = (size_t)(card->dma_last_transfer_vaddr[SND_PS3_CH_L] -
+                                card->dma_start_vaddr[SND_PS3_CH_L]);
+       }
+       spin_unlock(&card->dma_lock);
 
-       /* check CS non-audio bit and mute accordingly */
-       if (avs.avs_cs_info[0] & 0x02)
-               ps3av_audio_mute_analog(1); /* mute if non-audio */
-       else
-               ps3av_audio_mute_analog(0);
+       ret = bytes_to_frames(substream->runtime, bytes * 2);
 
        return ret;
-}
+};
 
 /*
  * SPDIF status bits controls
@@ -798,28 +753,39 @@ static struct snd_kcontrol_new spdif_ctls[] = {
        {
                .access = SNDRV_CTL_ELEM_ACCESS_READ,
                .iface = SNDRV_CTL_ELEM_IFACE_PCM,
-               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
+               .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
                .info = snd_ps3_spdif_mask_info,
                .get = snd_ps3_spdif_cmask_get,
        },
        {
                .access = SNDRV_CTL_ELEM_ACCESS_READ,
                .iface = SNDRV_CTL_ELEM_IFACE_PCM,
-               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
+               .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PRO_MASK),
                .info = snd_ps3_spdif_mask_info,
                .get = snd_ps3_spdif_pmask_get,
        },
        {
                .iface = SNDRV_CTL_ELEM_IFACE_PCM,
-               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
+               .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
                .info = snd_ps3_spdif_mask_info,
                .get = snd_ps3_spdif_default_get,
                .put = snd_ps3_spdif_default_put,
        },
 };
 
+static struct snd_pcm_ops snd_ps3_pcm_spdif_ops = {
+       .open = snd_ps3_pcm_open,
+       .close = snd_ps3_pcm_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = snd_ps3_pcm_hw_params,
+       .hw_free = snd_ps3_pcm_hw_free,
+       .prepare = snd_ps3_pcm_prepare,
+       .trigger = snd_ps3_pcm_trigger,
+       .pointer = snd_ps3_pcm_pointer,
+};
+
 
-static int snd_ps3_map_mmio(void)
+static int __devinit snd_ps3_map_mmio(void)
 {
        the_card.mapped_mmio_vaddr =
                ioremap(the_card.ps3_dev->m_region->bus_addr,
@@ -841,7 +807,7 @@ static void snd_ps3_unmap_mmio(void)
        the_card.mapped_mmio_vaddr = NULL;
 }
 
-static int snd_ps3_allocate_irq(void)
+static int __devinit snd_ps3_allocate_irq(void)
 {
        int ret;
        u64 lpar_addr, lpar_size;
@@ -899,7 +865,7 @@ static void snd_ps3_free_irq(void)
        ps3_irq_plug_destroy(the_card.irq_no);
 }
 
-static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start)
+static void __devinit snd_ps3_audio_set_base_addr(uint64_t ioaddr_start)
 {
        uint64_t val;
        int ret;
@@ -915,7 +881,53 @@ static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start)
                        ret);
 }
 
-static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
+static void __devinit snd_ps3_audio_fixup(struct snd_ps3_card_info *card)
+{
+       /*
+        * avsetting driver seems to never change the followings
+        * so, init them here once
+        */
+
+       /* no dma interrupt needed */
+       write_reg(PS3_AUDIO_INTR_EN_0, 0);
+
+       /* use every 4 buffer empty interrupt */
+       update_mask_reg(PS3_AUDIO_AX_IC,
+                       PS3_AUDIO_AX_IC_AASOIMD_MASK,
+                       PS3_AUDIO_AX_IC_AASOIMD_EVERY4);
+
+       /* enable 3wire clocks */
+       update_mask_reg(PS3_AUDIO_AO_3WMCTRL,
+                       ~(PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_DISABLED |
+                         PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_DISABLED),
+                       0);
+       update_reg(PS3_AUDIO_AO_3WMCTRL,
+                  PS3_AUDIO_AO_3WMCTRL_ASOPLRCK_DEFAULT);
+}
+
+static int __devinit snd_ps3_init_avsetting(struct snd_ps3_card_info *card)
+{
+       int ret;
+       pr_debug("%s: start\n", __func__);
+       card->avs.avs_audio_ch = PS3AV_CMD_AUDIO_NUM_OF_CH_2;
+       card->avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K;
+       card->avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16;
+       card->avs.avs_audio_format = PS3AV_CMD_AUDIO_FORMAT_PCM;
+       card->avs.avs_audio_source = PS3AV_CMD_AUDIO_SOURCE_SERIAL;
+       memcpy(card->avs.avs_cs_info, ps3av_mode_cs_info, 8);
+
+       ret = snd_ps3_change_avsetting(card);
+
+       snd_ps3_audio_fixup(card);
+
+       /* to start to generate SPDIF signal, fill data */
+       snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
+       snd_ps3_kick_dma(card);
+       pr_debug("%s: end\n", __func__);
+       return ret;
+}
+
+static int __devinit snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
 {
        int i, ret;
        u64 lpar_addr, lpar_size;
@@ -1020,11 +1032,12 @@ static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
         * its size should be lager than PS3_AUDIO_FIFO_STAGE_SIZE * 2
         * PAGE_SIZE is enogh
         */
-       if (!(the_card.null_buffer_start_vaddr =
-             dma_alloc_coherent(&the_card.ps3_dev->core,
-                                PAGE_SIZE,
-                                &the_card.null_buffer_start_dma_addr,
-                                GFP_KERNEL))) {
+       the_card.null_buffer_start_vaddr =
+               dma_alloc_coherent(&the_card.ps3_dev->core,
+                                  PAGE_SIZE,
+                                  &the_card.null_buffer_start_dma_addr,
+                                  GFP_KERNEL);
+       if (!the_card.null_buffer_start_vaddr) {
                pr_info("%s: nullbuffer alloc failed\n", __func__);
                goto clean_preallocate;
        }
@@ -1114,71 +1127,6 @@ static struct ps3_system_bus_driver snd_ps3_bus_driver_info = {
 };
 
 
-/*
- * Interrupt handler
- */
-static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id)
-{
-
-       uint32_t port_intr;
-       int underflow_occured = 0;
-       struct snd_ps3_card_info *card = dev_id;
-
-       if (!card->running) {
-               update_reg(PS3_AUDIO_AX_IS, 0);
-               update_reg(PS3_AUDIO_INTR_0, 0);
-               return IRQ_HANDLED;
-       }
-
-       port_intr = read_reg(PS3_AUDIO_AX_IS);
-       /*
-        *serial buffer empty detected (every 4 times),
-        *program next dma and kick it
-        */
-       if (port_intr & PS3_AUDIO_AX_IE_ASOBEIE(0)) {
-               write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBEIE(0));
-               if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) {
-                       write_reg(PS3_AUDIO_AX_IS, port_intr);
-                       underflow_occured = 1;
-               }
-               if (card->silent) {
-                       /* we are still in silent time */
-                       snd_ps3_program_dma(card,
-                               (underflow_occured) ?
-                               SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL :
-                               SND_PS3_DMA_FILLTYPE_SILENT_RUNNING);
-                       snd_ps3_kick_dma(card);
-                       card->silent --;
-               } else {
-                       snd_ps3_program_dma(card,
-                               (underflow_occured) ?
-                               SND_PS3_DMA_FILLTYPE_FIRSTFILL :
-                               SND_PS3_DMA_FILLTYPE_RUNNING);
-                       snd_ps3_kick_dma(card);
-                       snd_pcm_period_elapsed(card->substream);
-               }
-       } else if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) {
-               write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBUIE(0));
-               /*
-                * serial out underflow, but buffer empty not detected.
-                * in this case, fill fifo with 0 to recover.  After
-                * filling dummy data, serial automatically start to
-                * consume them and then will generate normal buffer
-                * empty interrupts.
-                * If both buffer underflow and buffer empty are occured,
-                * it is better to do nomal data transfer than empty one
-                */
-               snd_ps3_program_dma(card,
-                                   SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
-               snd_ps3_kick_dma(card);
-               snd_ps3_program_dma(card,
-                                   SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
-               snd_ps3_kick_dma(card);
-       }
-       /* clear interrupt cause */
-       return IRQ_HANDLED;
-};
-
 /*
  * module/subsystem initialize/terminate
  */
@@ -1197,10 +1145,15 @@ static int __init snd_ps3_init(void)
 
        return ret;
 }
+module_init(snd_ps3_init);
 
 static void __exit snd_ps3_exit(void)
 {
        ps3_system_bus_driver_unregister(&snd_ps3_bus_driver_info);
 }
+module_exit(snd_ps3_exit);
 
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PS3 sound driver");
+MODULE_AUTHOR("Sony Computer Entertainment Inc.");
 MODULE_ALIAS(PS3_MODULE_ALIAS_SOUND);
index 40222fcc08783048bd56c06659d027cdb903ce54..08e584d1453af17d22d43547cebf7d0bdf50d75f 100644 (file)
@@ -838,7 +838,7 @@ static int snapper_put_capture_source(struct snd_kcontrol *kcontrol,
 
 /*
  */
-static struct snd_kcontrol_new tumbler_mixers[] __initdata = {
+static struct snd_kcontrol_new tumbler_mixers[] __devinitdata = {
        { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
          .name = "Master Playback Volume",
          .info = tumbler_info_master_volume,
@@ -862,7 +862,7 @@ static struct snd_kcontrol_new tumbler_mixers[] __initdata = {
        },
 };
 
-static struct snd_kcontrol_new snapper_mixers[] __initdata = {
+static struct snd_kcontrol_new snapper_mixers[] __devinitdata = {
        { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
          .name = "Master Playback Volume",
          .info = tumbler_info_master_volume,
@@ -895,7 +895,7 @@ static struct snd_kcontrol_new snapper_mixers[] __initdata = {
        },
 };
 
-static struct snd_kcontrol_new tumbler_hp_sw __initdata = {
+static struct snd_kcontrol_new tumbler_hp_sw __devinitdata = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "Headphone Playback Switch",
        .info = snd_pmac_boolean_mono_info,
@@ -903,7 +903,7 @@ static struct snd_kcontrol_new tumbler_hp_sw __initdata = {
        .put = tumbler_put_mute_switch,
        .private_value = TUMBLER_MUTE_HP,
 };
-static struct snd_kcontrol_new tumbler_speaker_sw __initdata = {
+static struct snd_kcontrol_new tumbler_speaker_sw __devinitdata = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "PC Speaker Playback Switch",
        .info = snd_pmac_boolean_mono_info,
@@ -911,7 +911,7 @@ static struct snd_kcontrol_new tumbler_speaker_sw __initdata = {
        .put = tumbler_put_mute_switch,
        .private_value = TUMBLER_MUTE_AMP,
 };
-static struct snd_kcontrol_new tumbler_lineout_sw __initdata = {
+static struct snd_kcontrol_new tumbler_lineout_sw __devinitdata = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "Line Out Playback Switch",
        .info = snd_pmac_boolean_mono_info,
@@ -919,7 +919,7 @@ static struct snd_kcontrol_new tumbler_lineout_sw __initdata = {
        .put = tumbler_put_mute_switch,
        .private_value = TUMBLER_MUTE_LINE,
 };
-static struct snd_kcontrol_new tumbler_drc_sw __initdata = {
+static struct snd_kcontrol_new tumbler_drc_sw __devinitdata = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "DRC Switch",
        .info = snd_pmac_boolean_mono_info,
@@ -1269,7 +1269,7 @@ static void tumbler_resume(struct snd_pmac *chip)
 #endif
 
 /* initialize tumbler */
-static int __init tumbler_init(struct snd_pmac *chip)
+static int __devinit tumbler_init(struct snd_pmac *chip)
 {
        int irq;
        struct pmac_tumbler *mix = chip->mixer_data;
@@ -1339,7 +1339,7 @@ static void tumbler_cleanup(struct snd_pmac *chip)
 }
 
 /* exported */
-int __init snd_pmac_tumbler_init(struct snd_pmac *chip)
+int __devinit snd_pmac_tumbler_init(struct snd_pmac *chip)
 {
        int i, err;
        struct pmac_tumbler *mix;
index 3d2bb6fc6dcc46ad7f95ef5703059d6144be7849..d3e786a9a0a7ec08a69564700910ef49ac4f4927 100644 (file)
@@ -32,7 +32,9 @@ source "sound/soc/fsl/Kconfig"
 source "sound/soc/omap/Kconfig"
 source "sound/soc/pxa/Kconfig"
 source "sound/soc/s3c24xx/Kconfig"
+source "sound/soc/s6000/Kconfig"
 source "sound/soc/sh/Kconfig"
+source "sound/soc/txx9/Kconfig"
 
 # Supported codecs
 source "sound/soc/codecs/Kconfig"
index 0237879fd4125b47330a7a65a24449643fdaf3a7..6f1e28de23cf325383824299f9eb33fdfe43bec3 100644 (file)
@@ -10,4 +10,6 @@ obj-$(CONFIG_SND_SOC) += fsl/
 obj-$(CONFIG_SND_SOC)  += omap/
 obj-$(CONFIG_SND_SOC)  += pxa/
 obj-$(CONFIG_SND_SOC)  += s3c24xx/
+obj-$(CONFIG_SND_SOC)  += s6000/
 obj-$(CONFIG_SND_SOC)  += sh/
+obj-$(CONFIG_SND_SOC)  += txx9/
index a608d7009dbd61117444570a45f7e1627ae30ff4..e720d5e6f04cfdd135ea42e5b74ed74e75724bed 100644 (file)
@@ -41,3 +41,11 @@ config SND_AT32_SOC_PLAYPAQ_SLAVE
           and FRAME signals on the PlayPaq.  Unless you want to play
           with the AT32 as the SSC master, you probably want to say N here,
           as this will give you better sound quality.
+
+config SND_AT91_SOC_AFEB9260
+       tristate "SoC Audio support for AFEB9260 board"
+       depends on ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC
+       select SND_ATMEL_SOC_SSC
+       select SND_SOC_TLV320AIC23
+       help
+         Say Y here to support sound on AFEB9260 board.
index f54a7cc68e663bffe6c504a6bfb46fea13a5ed3b..e7ea56bd5f82a94de94d4169c464e809d34dfb5e 100644 (file)
@@ -13,3 +13,4 @@ snd-soc-playpaq-objs := playpaq_wm8510.o
 
 obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
 obj-$(CONFIG_SND_AT32_SOC_PLAYPAQ) += snd-soc-playpaq.o
+obj-$(CONFIG_SND_AT91_SOC_AFEB9260) += snd-soc-afeb9260.o
index 70657534e6b1f68ad3d9a89d4bc7e8698a4fafe5..9eb610c2ba917d42f8e81afc0972879302986928 100644 (file)
@@ -117,7 +117,7 @@ static struct ssc_clock_data playpaq_wm8510_calc_ssc_clock(
         * Find actual rate, compare to requested rate
         */
        actual_rate = (cd.ssc_rate / (cd.cmr_div * 2)) / (2 * (cd.period + 1));
-       pr_debug("playpaq_wm8510: Request rate = %d, actual rate = %d\n",
+       pr_debug("playpaq_wm8510: Request rate = %u, actual rate = %u\n",
                 rate, actual_rate);
 
 
diff --git a/sound/soc/atmel/snd-soc-afeb9260.c b/sound/soc/atmel/snd-soc-afeb9260.c
new file mode 100644 (file)
index 0000000..23349de
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * afeb9260.c  --  SoC audio for AFEB9260
+ *
+ * Copyright (C) 2009 Sergey Lapin <slapin@ossfans.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include <linux/atmel-ssc.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <linux/gpio.h>
+
+#include "../codecs/tlv320aic23.h"
+#include "atmel-pcm.h"
+#include "atmel_ssc_dai.h"
+
+#define CODEC_CLOCK    12000000
+
+static int afeb9260_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 err;
+
+       /* Set codec DAI configuration */
+       err = snd_soc_dai_set_fmt(codec_dai,
+                                 SND_SOC_DAIFMT_I2S|
+                                 SND_SOC_DAIFMT_NB_IF |
+                                 SND_SOC_DAIFMT_CBM_CFM);
+       if (err < 0) {
+               printk(KERN_ERR "can't set codec DAI configuration\n");
+               return err;
+       }
+
+       /* Set cpu DAI configuration */
+       err = snd_soc_dai_set_fmt(cpu_dai,
+                                 SND_SOC_DAIFMT_I2S |
+                                 SND_SOC_DAIFMT_NB_IF |
+                                 SND_SOC_DAIFMT_CBM_CFM);
+       if (err < 0) {
+               printk(KERN_ERR "can't set cpu DAI configuration\n");
+               return err;
+       }
+
+       /* Set the codec system clock for DAC and ADC */
+       err =
+           snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN);
+
+       if (err < 0) {
+               printk(KERN_ERR "can't set codec system clock\n");
+               return err;
+       }
+
+       return err;
+}
+
+static struct snd_soc_ops afeb9260_ops = {
+       .hw_params = afeb9260_hw_params,
+};
+
+static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_LINE("Line In", NULL),
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       {"Headphone Jack", NULL, "LHPOUT"},
+       {"Headphone Jack", NULL, "RHPOUT"},
+
+       {"LLINEIN", NULL, "Line In"},
+       {"RLINEIN", NULL, "Line In"},
+
+       {"MICIN", NULL, "Mic Jack"},
+};
+
+static int afeb9260_tlv320aic23_init(struct snd_soc_codec *codec)
+{
+
+       /* Add afeb9260 specific widgets */
+       snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
+                                 ARRAY_SIZE(tlv320aic23_dapm_widgets));
+
+       /* Set up afeb9260 specific audio path audio_map */
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+       snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+       snd_soc_dapm_enable_pin(codec, "Line In");
+       snd_soc_dapm_enable_pin(codec, "Mic Jack");
+
+       snd_soc_dapm_sync(codec);
+
+       return 0;
+}
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link afeb9260_dai = {
+       .name = "TLV320AIC23",
+       .stream_name = "AIC23",
+       .cpu_dai = &atmel_ssc_dai[0],
+       .codec_dai = &tlv320aic23_dai,
+       .init = afeb9260_tlv320aic23_init,
+       .ops = &afeb9260_ops,
+};
+
+/* Audio machine driver */
+static struct snd_soc_card snd_soc_machine_afeb9260 = {
+       .name = "AFEB9260",
+       .platform = &atmel_soc_platform,
+       .dai_link = &afeb9260_dai,
+       .num_links = 1,
+};
+
+/* Audio subsystem */
+static struct snd_soc_device afeb9260_snd_devdata = {
+       .card = &snd_soc_machine_afeb9260,
+       .codec_dev = &soc_codec_dev_tlv320aic23,
+};
+
+static struct platform_device *afeb9260_snd_device;
+
+static int __init afeb9260_soc_init(void)
+{
+       int err;
+       struct device *dev;
+       struct atmel_ssc_info *ssc_p = afeb9260_dai.cpu_dai->private_data;
+       struct ssc_device *ssc = NULL;
+
+       if (!(machine_is_afeb9260()))
+               return -ENODEV;
+
+       ssc = ssc_request(0);
+       if (IS_ERR(ssc)) {
+               printk(KERN_ERR "ASoC: Failed to request SSC 0\n");
+               err = PTR_ERR(ssc);
+               ssc = NULL;
+               goto err_ssc;
+       }
+       ssc_p->ssc = ssc;
+
+       afeb9260_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!afeb9260_snd_device) {
+               printk(KERN_ERR "ASoC: Platform device allocation failed\n");
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(afeb9260_snd_device, &afeb9260_snd_devdata);
+       afeb9260_snd_devdata.dev = &afeb9260_snd_device->dev;
+       err = platform_device_add(afeb9260_snd_device);
+       if (err)
+               goto err1;
+
+       dev = &afeb9260_snd_device->dev;
+
+       return 0;
+err1:
+       platform_device_del(afeb9260_snd_device);
+       platform_device_put(afeb9260_snd_device);
+err_ssc:
+       return err;
+
+}
+
+static void __exit afeb9260_soc_exit(void)
+{
+       platform_device_unregister(afeb9260_snd_device);
+}
+
+module_init(afeb9260_soc_init);
+module_exit(afeb9260_soc_exit);
+
+MODULE_AUTHOR("Sergey Lapin <slapin@ossfans.org>");
+MODULE_DESCRIPTION("ALSA SoC for AFEB9260");
+MODULE_LICENSE("GPL");
+
index 8a935f2d17674683186fc26d48d890c835ad3f3c..b1ed423fabd51f56bb278e165e2d8c0369406caa 100644 (file)
 #include "bf5xx-sport.h"
 #include "bf5xx-ac97.h"
 
+/* Anomaly notes:
+ *  05000250 - AD1980 is running in TDM mode and RFS/TFS are generated by SPORT
+ *             contrtoller. But, RFSDIV and TFSDIV are always set to 16*16-1,
+ *             while the max AC97 data size is 13*16. The DIV is always larger
+ *             than data size. AD73311 and ad2602 are not running in TDM mode.
+ *             AD1836 and AD73322 depend on external RFS/TFS only. So, this
+ *             anomaly does not affect blackfin sound drivers.
+*/
+
 static int *cmd_count;
 static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
 
index b7953c8cf8382a05df6ef9b280b0403a7b214f77..469ce7fab20ca6aad3d6474d8c63deeacb3f5101 100644 (file)
@@ -190,7 +190,7 @@ static inline int sport_hook_rx_dummy(struct sport_device *sport)
        desc = get_dma_next_desc_ptr(sport->dma_rx_chan);
        /* Copy the descriptor which will be damaged to backup */
        temp_desc = *desc;
-       desc->x_count = 0xa;
+       desc->x_count = sport->dummy_count / 2;
        desc->y_count = 0;
        desc->next_desc_addr = sport->dummy_rx_desc;
        local_irq_restore(flags);
@@ -309,7 +309,7 @@ static inline int sport_hook_tx_dummy(struct sport_device *sport)
        desc = get_dma_next_desc_ptr(sport->dma_tx_chan);
        /* Store the descriptor which will be damaged */
        temp_desc = *desc;
-       desc->x_count = 0xa;
+       desc->x_count = sport->dummy_count / 2;
        desc->y_count = 0;
        desc->next_desc_addr = sport->dummy_tx_desc;
        local_irq_restore(flags);
index b6c7f7a01cb03756a321651b02f5135eccdd2a4a..bbc97fd7664893b58871e9d026cc20e9d9863774 100644 (file)
@@ -18,7 +18,9 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_AK4535 if I2C
        select SND_SOC_CS4270 if I2C
        select SND_SOC_PCM3008
+       select SND_SOC_SPDIF
        select SND_SOC_SSM2602 if I2C
+       select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
        select SND_SOC_TLV320AIC23 if I2C
        select SND_SOC_TLV320AIC26 if SPI_MASTER
        select SND_SOC_TLV320AIC3X if I2C
@@ -35,8 +37,12 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8900 if I2C
        select SND_SOC_WM8903 if I2C
+       select SND_SOC_WM8940 if I2C
+       select SND_SOC_WM8960 if I2C
        select SND_SOC_WM8971 if I2C
+       select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8990 if I2C
+       select SND_SOC_WM9081 if I2C
        select SND_SOC_WM9705 if SND_SOC_AC97_BUS
        select SND_SOC_WM9712 if SND_SOC_AC97_BUS
        select SND_SOC_WM9713 if SND_SOC_AC97_BUS
@@ -86,9 +92,15 @@ config SND_SOC_L3
 config SND_SOC_PCM3008
        tristate
 
+config SND_SOC_SPDIF
+       tristate
+
 config SND_SOC_SSM2602
        tristate
 
+config SND_SOC_STAC9766
+       tristate
+
 config SND_SOC_TLV320AIC23
        tristate
 
@@ -138,12 +150,24 @@ config SND_SOC_WM8900
 config SND_SOC_WM8903
        tristate
 
+config SND_SOC_WM8940
+        tristate
+
+config SND_SOC_WM8960
+       tristate
+
 config SND_SOC_WM8971
        tristate
 
+config SND_SOC_WM8988
+       tristate
+
 config SND_SOC_WM8990
        tristate
 
+config SND_SOC_WM9081
+       tristate
+
 config SND_SOC_WM9705
        tristate
 
index f2653803ede8faf37be341e40c3ae0f5d5169956..8b7530546f4dece45018f54a4894eaa3875d954f 100644 (file)
@@ -6,7 +6,9 @@ snd-soc-ak4535-objs := ak4535.o
 snd-soc-cs4270-objs := cs4270.o
 snd-soc-l3-objs := l3.o
 snd-soc-pcm3008-objs := pcm3008.o
+snd-soc-spdif-objs := spdif_transciever.o
 snd-soc-ssm2602-objs := ssm2602.o
+snd-soc-stac9766-objs := stac9766.o
 snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
@@ -23,8 +25,12 @@ snd-soc-wm8750-objs := wm8750.o
 snd-soc-wm8753-objs := wm8753.o
 snd-soc-wm8900-objs := wm8900.o
 snd-soc-wm8903-objs := wm8903.o
+snd-soc-wm8940-objs := wm8940.o
+snd-soc-wm8960-objs := wm8960.o
 snd-soc-wm8971-objs := wm8971.o
+snd-soc-wm8988-objs := wm8988.o
 snd-soc-wm8990-objs := wm8990.o
+snd-soc-wm9081-objs := wm9081.o
 snd-soc-wm9705-objs := wm9705.o
 snd-soc-wm9712-objs := wm9712.o
 snd-soc-wm9713-objs := wm9713.o
@@ -37,7 +43,9 @@ obj-$(CONFIG_SND_SOC_AK4535)  += snd-soc-ak4535.o
 obj-$(CONFIG_SND_SOC_CS4270)   += snd-soc-cs4270.o
 obj-$(CONFIG_SND_SOC_L3)       += snd-soc-l3.o
 obj-$(CONFIG_SND_SOC_PCM3008)  += snd-soc-pcm3008.o
+obj-$(CONFIG_SND_SOC_SPDIF)    += snd-soc-spdif.o
 obj-$(CONFIG_SND_SOC_SSM2602)  += snd-soc-ssm2602.o
+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
@@ -55,7 +63,11 @@ obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o
 obj-$(CONFIG_SND_SOC_WM8900)   += snd-soc-wm8900.o
 obj-$(CONFIG_SND_SOC_WM8903)   += snd-soc-wm8903.o
 obj-$(CONFIG_SND_SOC_WM8971)   += snd-soc-wm8971.o
+obj-$(CONFIG_SND_SOC_WM8940)   += snd-soc-wm8940.o
+obj-$(CONFIG_SND_SOC_WM8960)   += snd-soc-wm8960.o
+obj-$(CONFIG_SND_SOC_WM8988)   += snd-soc-wm8988.o
 obj-$(CONFIG_SND_SOC_WM8990)   += snd-soc-wm8990.o
+obj-$(CONFIG_SND_SOC_WM9081)   += snd-soc-wm9081.o
 obj-$(CONFIG_SND_SOC_WM9705)   += snd-soc-wm9705.o
 obj-$(CONFIG_SND_SOC_WM9712)   += snd-soc-wm9712.o
 obj-$(CONFIG_SND_SOC_WM9713)   += snd-soc-wm9713.o
index b0d4af145b873900509ce18239e2c85899aa9069..932299bb5d1e006a7f0108bd7d7ab0000b3969bc 100644 (file)
@@ -53,13 +53,13 @@ struct snd_soc_dai ac97_dai = {
                .channels_min = 1,
                .channels_max = 2,
                .rates = STD_AC97_RATES,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+               .formats = SND_SOC_STD_AC97_FMTS,},
        .capture = {
                .stream_name = "AC97 Capture",
                .channels_min = 1,
                .channels_max = 2,
                .rates = STD_AC97_RATES,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+               .formats = SND_SOC_STD_AC97_FMTS,},
        .ops = &ac97_dai_ops,
 };
 EXPORT_SYMBOL_GPL(ac97_dai);
index ddb3b08ac23c441dd93112295a7182881c856041..d7440a982d22794928940c3590cde1765fe56d9a 100644 (file)
@@ -137,13 +137,13 @@ struct snd_soc_dai ad1980_dai = {
                .channels_min = 2,
                .channels_max = 6,
                .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE, },
+               .formats = SND_SOC_STD_AC97_FMTS, },
        .capture = {
                .stream_name = "Capture",
                .channels_min = 2,
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE, },
+               .formats = SND_SOC_STD_AC97_FMTS, },
 };
 EXPORT_SYMBOL_GPL(ad1980_dai);
 
index 7fa09a387622cbff69b28b88e83819faa876d4e9..a32b8226c8a43bc19a2f3852ef24b3e802238c05 100644 (file)
@@ -18,7 +18,7 @@
  * - The machine driver's 'startup' function must call
  *   cs4270_set_dai_sysclk() with the value of MCLK.
  * - Only I2S and left-justified modes are supported
- * - Power management is not supported
+ * - Power management is supported
  */
 
 #include <linux/module.h>
@@ -27,6 +27,7 @@
 #include <sound/soc.h>
 #include <sound/initval.h>
 #include <linux/i2c.h>
+#include <linux/delay.h>
 
 #include "cs4270.h"
 
@@ -56,6 +57,7 @@
 #define CS4270_FIRSTREG        0x01
 #define CS4270_LASTREG 0x08
 #define CS4270_NUMREGS (CS4270_LASTREG - CS4270_FIRSTREG + 1)
+#define CS4270_I2C_INCR        0x80
 
 /* Bit masks for the CS4270 registers */
 #define CS4270_CHIPID_ID       0xF0
@@ -64,6 +66,8 @@
 #define CS4270_PWRCTL_PDN_ADC  0x20
 #define CS4270_PWRCTL_PDN_DAC  0x02
 #define CS4270_PWRCTL_PDN      0x01
+#define CS4270_PWRCTL_PDN_ALL  \
+       (CS4270_PWRCTL_PDN_ADC | CS4270_PWRCTL_PDN_DAC | CS4270_PWRCTL_PDN)
 #define CS4270_MODE_SPEED_MASK 0x30
 #define CS4270_MODE_1X         0x00
 #define CS4270_MODE_2X         0x10
@@ -109,6 +113,7 @@ struct cs4270_private {
        unsigned int mclk; /* Input frequency of the MCLK pin */
        unsigned int mode; /* The mode (I2S or left-justified) */
        unsigned int slave_mode;
+       unsigned int manual_mute;
 };
 
 /**
@@ -295,7 +300,7 @@ static int cs4270_fill_cache(struct snd_soc_codec *codec)
        s32 length;
 
        length = i2c_smbus_read_i2c_block_data(i2c_client,
-               CS4270_FIRSTREG | 0x80, CS4270_NUMREGS, cache);
+               CS4270_FIRSTREG | CS4270_I2C_INCR, CS4270_NUMREGS, cache);
 
        if (length != CS4270_NUMREGS) {
                dev_err(codec->dev, "i2c read failure, addr=0x%x\n",
@@ -453,7 +458,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
 }
 
 /**
- * cs4270_mute - enable/disable the CS4270 external mute
+ * cs4270_dai_mute - enable/disable the CS4270 external mute
  * @dai: the SOC DAI
  * @mute: 0 = disable mute, 1 = enable mute
  *
@@ -462,21 +467,52 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
  * board does not have the MUTEA or MUTEB pins connected to such circuitry,
  * then this function will do nothing.
  */
-static int cs4270_mute(struct snd_soc_dai *dai, int mute)
+static int cs4270_dai_mute(struct snd_soc_dai *dai, int mute)
 {
        struct snd_soc_codec *codec = dai->codec;
+       struct cs4270_private *cs4270 = codec->private_data;
        int reg6;
 
        reg6 = snd_soc_read(codec, CS4270_MUTE);
 
        if (mute)
                reg6 |= CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B;
-       else
+       else {
                reg6 &= ~(CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B);
+               reg6 |= cs4270->manual_mute;
+       }
 
        return snd_soc_write(codec, CS4270_MUTE, reg6);
 }
 
+/**
+ * cs4270_soc_put_mute - put callback for the 'Master Playback switch'
+ *                      alsa control.
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * This function basically passes the arguments on to the generic
+ * snd_soc_put_volsw() function and saves the mute information in
+ * our private data structure. This is because we want to prevent
+ * cs4270_dai_mute() neglecting the user's decision to manually
+ * mute the codec's output.
+ *
+ * Returns 0 for success.
+ */
+static int cs4270_soc_put_mute(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct cs4270_private *cs4270 = codec->private_data;
+       int left = !ucontrol->value.integer.value[0];
+       int right = !ucontrol->value.integer.value[1];
+
+       cs4270->manual_mute = (left ? CS4270_MUTE_DAC_A : 0) |
+                             (right ? CS4270_MUTE_DAC_B : 0);
+
+       return snd_soc_put_volsw(kcontrol, ucontrol);
+}
+
 /* A list of non-DAPM controls that the CS4270 supports */
 static const struct snd_kcontrol_new cs4270_snd_controls[] = {
        SOC_DOUBLE_R("Master Playback Volume",
@@ -486,7 +522,9 @@ static const struct snd_kcontrol_new cs4270_snd_controls[] = {
        SOC_SINGLE("Zero Cross Switch", CS4270_TRANS, 5, 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, 0)
+       SOC_DOUBLE("Master Capture Switch", CS4270_MUTE, 3, 4, 1, 1),
+       SOC_DOUBLE_EXT("Master Playback Switch", CS4270_MUTE, 0, 1, 1, 1,
+               snd_soc_get_volsw, cs4270_soc_put_mute),
 };
 
 /*
@@ -506,7 +544,7 @@ static struct snd_soc_dai_ops cs4270_dai_ops = {
        .hw_params      = cs4270_hw_params,
        .set_sysclk     = cs4270_set_dai_sysclk,
        .set_fmt        = cs4270_set_dai_fmt,
-       .digital_mute   = cs4270_mute,
+       .digital_mute   = cs4270_dai_mute,
 };
 
 struct snd_soc_dai cs4270_dai = {
@@ -753,6 +791,57 @@ static struct i2c_device_id cs4270_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, cs4270_id);
 
+#ifdef CONFIG_PM
+
+/* This suspend/resume implementation can handle both - a simple standby
+ * where the codec remains powered, and a full suspend, where the voltage
+ * domain the codec is connected to is teared down and/or any other hardware
+ * reset condition is asserted.
+ *
+ * The codec's own power saving features are enabled in the suspend callback,
+ * 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;
+       int reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL;
+
+       return snd_soc_write(codec, CS4270_PWRCTL, reg);
+}
+
+static int cs4270_i2c_resume(struct i2c_client *client)
+{
+       struct cs4270_private *cs4270 = i2c_get_clientdata(client);
+       struct snd_soc_codec *codec = &cs4270->codec;
+       int reg;
+
+       /* In case the device was put to hard reset during sleep, we need to
+        * wait 500ns here before any I2C communication. */
+       ndelay(500);
+
+       /* first restore the entire register cache ... */
+       for (reg = CS4270_FIRSTREG; reg <= CS4270_LASTREG; reg++) {
+               u8 val = snd_soc_read(codec, reg);
+
+               if (i2c_smbus_write_byte_data(client, reg, val)) {
+                       dev_err(codec->dev, "i2c write failed\n");
+                       return -EIO;
+               }
+       }
+
+       /* ... then disable the power-down bits */
+       reg = snd_soc_read(codec, CS4270_PWRCTL);
+       reg &= ~CS4270_PWRCTL_PDN_ALL;
+
+       return snd_soc_write(codec, CS4270_PWRCTL, reg);
+}
+#else
+#define cs4270_i2c_suspend     NULL
+#define cs4270_i2c_resume      NULL
+#endif /* CONFIG_PM */
+
 /*
  * cs4270_i2c_driver - I2C device identification
  *
@@ -767,6 +856,8 @@ 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,
 };
 
 /*
diff --git a/sound/soc/codecs/spdif_transciever.c b/sound/soc/codecs/spdif_transciever.c
new file mode 100644 (file)
index 0000000..218b33a
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * ALSA SoC SPDIF DIT driver
+ *
+ *  This driver is used by controllers which can operate in DIT (SPDI/F) where
+ *  no codec is needed.  This file provides stub codec that can be used
+ *  in these configurations. TI DaVinci Audio controller uses this driver.
+ *
+ * Author:      Steve Chen,  <schen@mvista.com>
+ * Copyright:   (C) 2009 MontaVista Software, Inc., <source@mvista.com>
+ * Copyright:   (C) 2009  Texas Instruments, India
+ *
+ * This 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 <sound/soc.h>
+#include <sound/pcm.h>
+
+#include "spdif_transciever.h"
+
+#define STUB_RATES     SNDRV_PCM_RATE_8000_96000
+#define STUB_FORMATS   SNDRV_PCM_FMTBIT_S16_LE
+
+struct snd_soc_dai dit_stub_dai = {
+       .name           = "DIT",
+       .playback       = {
+               .stream_name    = "Playback",
+               .channels_min   = 1,
+               .channels_max   = 384,
+               .rates          = STUB_RATES,
+               .formats        = STUB_FORMATS,
+       },
+};
+
+static int spdif_dit_probe(struct platform_device *pdev)
+{
+       dit_stub_dai.dev = &pdev->dev;
+       return snd_soc_register_dai(&dit_stub_dai);
+}
+
+static int spdif_dit_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_dai(&dit_stub_dai);
+       return 0;
+}
+
+static struct platform_driver spdif_dit_driver = {
+       .probe          = spdif_dit_probe,
+       .remove         = spdif_dit_remove,
+       .driver         = {
+               .name   = "spdif-dit",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init dit_modinit(void)
+{
+       return platform_driver_register(&spdif_dit_driver);
+}
+
+static void __exit dit_exit(void)
+{
+       platform_driver_unregister(&spdif_dit_driver);
+}
+
+module_init(dit_modinit);
+module_exit(dit_exit);
+
diff --git a/sound/soc/codecs/spdif_transciever.h b/sound/soc/codecs/spdif_transciever.h
new file mode 100644 (file)
index 0000000..296f2eb
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * ALSA SoC DIT/DIR driver header
+ *
+ * Author:      Steve Chen,  <schen@mvista.com>
+ * Copyright:   (C) 2008 MontaVista Software, Inc., <source@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef CODEC_STUBS_H
+#define CODEC_STUBS_H
+
+extern struct snd_soc_dai dit_stub_dai;
+
+#endif /* CODEC_STUBS_H */
index 87f606c7682292af24e5f213cf7c919465116fd1..1fc4c8e0899c18ec1f7f12750cf80023140cd5b7 100644 (file)
@@ -336,15 +336,17 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,
                        master_runtime->sample_bits,
                        master_runtime->rate);
 
-               snd_pcm_hw_constraint_minmax(substream->runtime,
-                                            SNDRV_PCM_HW_PARAM_RATE,
-                                            master_runtime->rate,
-                                            master_runtime->rate);
-
-               snd_pcm_hw_constraint_minmax(substream->runtime,
-                                            SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
-                                            master_runtime->sample_bits,
-                                            master_runtime->sample_bits);
+               if (master_runtime->rate != 0)
+                       snd_pcm_hw_constraint_minmax(substream->runtime,
+                                                    SNDRV_PCM_HW_PARAM_RATE,
+                                                    master_runtime->rate,
+                                                    master_runtime->rate);
+
+               if (master_runtime->sample_bits != 0)
+                       snd_pcm_hw_constraint_minmax(substream->runtime,
+                                                    SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+                                                    master_runtime->sample_bits,
+                                                    master_runtime->sample_bits);
 
                ssm2602->slave_substream = substream;
        } else
@@ -372,6 +374,11 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream,
        struct snd_soc_device *socdev = rtd->socdev;
        struct snd_soc_codec *codec = socdev->card->codec;
        struct ssm2602_priv *ssm2602 = codec->private_data;
+
+       if (ssm2602->master_substream == substream)
+               ssm2602->master_substream = ssm2602->slave_substream;
+
+       ssm2602->slave_substream = NULL;
        /* deactivate */
        if (!codec->active)
                ssm2602_write(codec, SSM2602_ACTIVE, 0);
@@ -497,11 +504,9 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-#define SSM2602_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 | SNDRV_PCM_RATE_88200 |\
-               SNDRV_PCM_RATE_96000)
+#define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_32000 |\
+               SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
+               SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
 
 #define SSM2602_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
                SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c
new file mode 100644 (file)
index 0000000..8ad4b7b
--- /dev/null
@@ -0,0 +1,463 @@
+/*
+ * stac9766.c  --  ALSA SoC STAC9766 codec support
+ *
+ * Copyright 2009 Jon Smirl, Digispeaker
+ * Author: Jon Smirl <jonsmirl@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.
+ *
+ *  Features:-
+ *
+ *   o Support for AC97 Codec, S/PDIF
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/soc-of-simple.h>
+
+#include "stac9766.h"
+
+#define STAC9766_VERSION "0.10"
+
+/*
+ * STAC9766 register cache
+ */
+static const u16 stac9766_reg[] = {
+       0x6A90, 0x8000, 0x8000, 0x8000, /* 6 */
+       0x0000, 0x0000, 0x8008, 0x8008, /* e */
+       0x8808, 0x8808, 0x8808, 0x8808, /* 16 */
+       0x8808, 0x0000, 0x8000, 0x0000, /* 1e */
+       0x0000, 0x0000, 0x0000, 0x000f, /* 26 */
+       0x0a05, 0x0400, 0xbb80, 0x0000, /* 2e */
+       0x0000, 0xbb80, 0x0000, 0x0000, /* 36 */
+       0x0000, 0x2000, 0x0000, 0x0100, /* 3e */
+       0x0000, 0x0000, 0x0080, 0x0000, /* 46 */
+       0x0000, 0x0000, 0x0003, 0xffff, /* 4e */
+       0x0000, 0x0000, 0x0000, 0x0000, /* 56 */
+       0x4000, 0x0000, 0x0000, 0x0000, /* 5e */
+       0x1201, 0xFFFF, 0xFFFF, 0x0000, /* 66 */
+       0x0000, 0x0000, 0x0000, 0x0000, /* 6e */
+       0x0000, 0x0000, 0x0000, 0x0006, /* 76 */
+       0x0000, 0x0000, 0x0000, 0x0000, /* 7e */
+};
+
+static const char *stac9766_record_mux[] = {"Mic", "CD", "Video", "AUX",
+                       "Line", "Stereo Mix", "Mono Mix", "Phone"};
+static const char *stac9766_mono_mux[] = {"Mix", "Mic"};
+static const char *stac9766_mic_mux[] = {"Mic1", "Mic2"};
+static const char *stac9766_SPDIF_mux[] = {"PCM", "ADC Record"};
+static const char *stac9766_popbypass_mux[] = {"Normal", "Bypass Mixer"};
+static const char *stac9766_record_all_mux[] = {"All analog",
+       "Analog plus DAC"};
+static const char *stac9766_boost1[] = {"0dB", "10dB"};
+static const char *stac9766_boost2[] = {"0dB", "20dB"};
+static const char *stac9766_stereo_mic[] = {"Off", "On"};
+
+static const struct soc_enum stac9766_record_enum =
+       SOC_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 8, stac9766_record_mux);
+static const struct soc_enum stac9766_mono_enum =
+       SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 9, 2, stac9766_mono_mux);
+static const struct soc_enum stac9766_mic_enum =
+       SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 8, 2, stac9766_mic_mux);
+static const struct soc_enum stac9766_SPDIF_enum =
+       SOC_ENUM_SINGLE(AC97_STAC_DA_CONTROL, 1, 2, stac9766_SPDIF_mux);
+static const struct soc_enum stac9766_popbypass_enum =
+       SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 15, 2, stac9766_popbypass_mux);
+static const struct soc_enum stac9766_record_all_enum =
+       SOC_ENUM_SINGLE(AC97_STAC_ANALOG_SPECIAL, 12, 2,
+                       stac9766_record_all_mux);
+static const struct soc_enum stac9766_boost1_enum =
+       SOC_ENUM_SINGLE(AC97_MIC, 6, 2, stac9766_boost1); /* 0/10dB */
+static const struct soc_enum stac9766_boost2_enum =
+       SOC_ENUM_SINGLE(AC97_STAC_ANALOG_SPECIAL, 2, 2, stac9766_boost2); /* 0/20dB */
+static const struct soc_enum stac9766_stereo_mic_enum =
+       SOC_ENUM_SINGLE(AC97_STAC_STEREO_MIC, 2, 1, stac9766_stereo_mic);
+
+static const DECLARE_TLV_DB_LINEAR(master_tlv, -4600, 0);
+static const DECLARE_TLV_DB_LINEAR(record_tlv, 0, 2250);
+static const DECLARE_TLV_DB_LINEAR(beep_tlv, -4500, 0);
+static const DECLARE_TLV_DB_LINEAR(mix_tlv, -3450, 1200);
+
+static const struct snd_kcontrol_new stac9766_snd_ac97_controls[] = {
+       SOC_DOUBLE_TLV("Speaker Volume", AC97_MASTER, 8, 0, 31, 1, master_tlv),
+       SOC_SINGLE("Speaker Switch", AC97_MASTER, 15, 1, 1),
+       SOC_DOUBLE_TLV("Headphone Volume", AC97_HEADPHONE, 8, 0, 31, 1,
+                      master_tlv),
+       SOC_SINGLE("Headphone Switch", AC97_HEADPHONE, 15, 1, 1),
+       SOC_SINGLE_TLV("Mono Out Volume", AC97_MASTER_MONO, 0, 31, 1,
+                      master_tlv),
+       SOC_SINGLE("Mono Out Switch", AC97_MASTER_MONO, 15, 1, 1),
+
+       SOC_DOUBLE_TLV("Record Volume", AC97_REC_GAIN, 8, 0, 15, 0, record_tlv),
+       SOC_SINGLE("Record Switch", AC97_REC_GAIN, 15, 1, 1),
+
+
+       SOC_SINGLE_TLV("Beep Volume", AC97_PC_BEEP, 1, 15, 1, beep_tlv),
+       SOC_SINGLE("Beep Switch", AC97_PC_BEEP, 15, 1, 1),
+       SOC_SINGLE("Beep Frequency", AC97_PC_BEEP, 5, 127, 1),
+       SOC_SINGLE_TLV("Phone Volume", AC97_PHONE, 0, 31, 1, mix_tlv),
+       SOC_SINGLE("Phone Switch", AC97_PHONE, 15, 1, 1),
+
+       SOC_ENUM("Mic Boost1", stac9766_boost1_enum),
+       SOC_ENUM("Mic Boost2", stac9766_boost2_enum),
+       SOC_SINGLE_TLV("Mic Volume", AC97_MIC, 0, 31, 1, mix_tlv),
+       SOC_SINGLE("Mic Switch", AC97_MIC, 15, 1, 1),
+       SOC_ENUM("Stereo Mic", stac9766_stereo_mic_enum),
+
+       SOC_DOUBLE_TLV("Line Volume", AC97_LINE, 8, 0, 31, 1, mix_tlv),
+       SOC_SINGLE("Line Switch", AC97_LINE, 15, 1, 1),
+       SOC_DOUBLE_TLV("CD Volume", AC97_CD, 8, 0, 31, 1, mix_tlv),
+       SOC_SINGLE("CD Switch", AC97_CD, 15, 1, 1),
+       SOC_DOUBLE_TLV("AUX Volume", AC97_AUX, 8, 0, 31, 1, mix_tlv),
+       SOC_SINGLE("AUX Switch", AC97_AUX, 15, 1, 1),
+       SOC_DOUBLE_TLV("Video Volume", AC97_VIDEO, 8, 0, 31, 1, mix_tlv),
+       SOC_SINGLE("Video Switch", AC97_VIDEO, 15, 1, 1),
+
+       SOC_DOUBLE_TLV("DAC Volume", AC97_PCM, 8, 0, 31, 1, mix_tlv),
+       SOC_SINGLE("DAC Switch", AC97_PCM, 15, 1, 1),
+       SOC_SINGLE("Loopback Test Switch", AC97_GENERAL_PURPOSE, 7, 1, 0),
+       SOC_SINGLE("3D Volume", AC97_3D_CONTROL, 3, 2, 1),
+       SOC_SINGLE("3D Switch", AC97_GENERAL_PURPOSE, 13, 1, 0),
+
+       SOC_ENUM("SPDIF Mux", stac9766_SPDIF_enum),
+       SOC_ENUM("Mic1/2 Mux", stac9766_mic_enum),
+       SOC_ENUM("Record All Mux", stac9766_record_all_enum),
+       SOC_ENUM("Record Mux", stac9766_record_enum),
+       SOC_ENUM("Mono Mux", stac9766_mono_enum),
+       SOC_ENUM("Pop Bypass Mux", stac9766_popbypass_enum),
+};
+
+static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg,
+                              unsigned int val)
+{
+       u16 *cache = codec->reg_cache;
+
+       if (reg > AC97_STAC_PAGE0) {
+               stac9766_ac97_write(codec, AC97_INT_PAGING, 0);
+               soc_ac97_ops.write(codec->ac97, reg, val);
+               stac9766_ac97_write(codec, AC97_INT_PAGING, 1);
+               return 0;
+       }
+       if (reg / 2 > ARRAY_SIZE(stac9766_reg))
+               return -EIO;
+
+       soc_ac97_ops.write(codec->ac97, reg, val);
+       cache[reg / 2] = val;
+       return 0;
+}
+
+static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec,
+                                      unsigned int reg)
+{
+       u16 val = 0, *cache = codec->reg_cache;
+
+       if (reg > AC97_STAC_PAGE0) {
+               stac9766_ac97_write(codec, AC97_INT_PAGING, 0);
+               val = soc_ac97_ops.read(codec->ac97, reg - AC97_STAC_PAGE0);
+               stac9766_ac97_write(codec, AC97_INT_PAGING, 1);
+               return val;
+       }
+       if (reg / 2 > ARRAY_SIZE(stac9766_reg))
+               return -EIO;
+
+       if (reg == AC97_RESET || reg == AC97_GPIO_STATUS ||
+               reg == AC97_INT_PAGING || reg == AC97_VENDOR_ID1 ||
+               reg == AC97_VENDOR_ID2) {
+
+               val = soc_ac97_ops.read(codec->ac97, reg);
+               return val;
+       }
+       return cache[reg / 2];
+}
+
+static int ac97_analog_prepare(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       unsigned short reg, vra;
+
+       vra = stac9766_ac97_read(codec, AC97_EXTENDED_STATUS);
+
+       vra |= 0x1; /* enable variable rate audio */
+
+       stac9766_ac97_write(codec, AC97_EXTENDED_STATUS, vra);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               reg = AC97_PCM_FRONT_DAC_RATE;
+       else
+               reg = AC97_PCM_LR_ADC_RATE;
+
+       return stac9766_ac97_write(codec, reg, runtime->rate);
+}
+
+static int ac97_digital_prepare(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       unsigned short reg, vra;
+
+       stac9766_ac97_write(codec, AC97_SPDIF, 0x2002);
+
+       vra = stac9766_ac97_read(codec, AC97_EXTENDED_STATUS);
+       vra |= 0x5; /* Enable VRA and SPDIF out */
+
+       stac9766_ac97_write(codec, AC97_EXTENDED_STATUS, vra);
+
+       reg = AC97_PCM_FRONT_DAC_RATE;
+
+       return stac9766_ac97_write(codec, reg, runtime->rate);
+}
+
+static int ac97_digital_trigger(struct snd_pcm_substream *substream,
+                               int cmd, struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       unsigned short vra;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_STOP:
+               vra = stac9766_ac97_read(codec, AC97_EXTENDED_STATUS);
+               vra &= !0x04;
+               stac9766_ac97_write(codec, AC97_EXTENDED_STATUS, vra);
+               break;
+       }
+       return 0;
+}
+
+static int stac9766_set_bias_level(struct snd_soc_codec *codec,
+                                  enum snd_soc_bias_level level)
+{
+       switch (level) {
+       case SND_SOC_BIAS_ON: /* full On */
+       case SND_SOC_BIAS_PREPARE: /* partial On */
+       case SND_SOC_BIAS_STANDBY: /* Off, with power */
+               stac9766_ac97_write(codec, AC97_POWERDOWN, 0x0000);
+               break;
+       case SND_SOC_BIAS_OFF: /* Off, without power */
+               /* disable everything including AC link */
+               stac9766_ac97_write(codec, AC97_POWERDOWN, 0xffff);
+               break;
+       }
+       codec->bias_level = level;
+       return 0;
+}
+
+static int stac9766_reset(struct snd_soc_codec *codec, int try_warm)
+{
+       if (try_warm && soc_ac97_ops.warm_reset) {
+               soc_ac97_ops.warm_reset(codec->ac97);
+               if (stac9766_ac97_read(codec, 0) == stac9766_reg[0])
+                       return 1;
+       }
+
+       soc_ac97_ops.reset(codec->ac97);
+       if (soc_ac97_ops.warm_reset)
+               soc_ac97_ops.warm_reset(codec->ac97);
+       if (stac9766_ac97_read(codec, 0) != stac9766_reg[0])
+               return -EIO;
+       return 0;
+}
+
+static int stac9766_codec_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;
+
+       stac9766_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int stac9766_codec_resume(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->card->codec;
+       u16 id, reset;
+
+       reset = 0;
+       /* give the codec an AC97 warm reset to start the link */
+reset:
+       if (reset > 5) {
+               printk(KERN_ERR "stac9766 failed to resume");
+               return -EIO;
+       }
+       codec->ac97->bus->ops->warm_reset(codec->ac97);
+       id = soc_ac97_ops.read(codec->ac97, AC97_VENDOR_ID2);
+       if (id != 0x4c13) {
+               stac9766_reset(codec, 0);
+               reset++;
+               goto reset;
+       }
+       stac9766_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       if (codec->suspend_bias_level == SND_SOC_BIAS_ON)
+               stac9766_set_bias_level(codec, SND_SOC_BIAS_ON);
+
+       return 0;
+}
+
+static struct snd_soc_dai_ops stac9766_dai_ops_analog = {
+       .prepare = ac97_analog_prepare,
+};
+
+static struct snd_soc_dai_ops stac9766_dai_ops_digital = {
+       .prepare = ac97_digital_prepare,
+       .trigger = ac97_digital_trigger,
+};
+
+struct snd_soc_dai stac9766_dai[] = {
+{
+       .name = "stac9766 analog",
+       .id = 0,
+       .ac97_control = 1,
+
+       /* stream cababilities */
+       .playback = {
+               .stream_name = "stac9766 analog",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = SND_SOC_STD_AC97_FMTS,
+       },
+       .capture = {
+               .stream_name = "stac9766 analog",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = SND_SOC_STD_AC97_FMTS,
+       },
+       /* alsa ops */
+       .ops = &stac9766_dai_ops_analog,
+},
+{
+       .name = "stac9766 IEC958",
+       .id = 1,
+       .ac97_control = 1,
+
+       /* stream cababilities */
+       .playback = {
+               .stream_name = "stac9766 IEC958",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_32000 | \
+                       SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE,
+       },
+       /* alsa ops */
+       .ops = &stac9766_dai_ops_digital,
+}
+};
+EXPORT_SYMBOL_GPL(stac9766_dai);
+
+static int stac9766_codec_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec;
+       int ret = 0;
+
+       printk(KERN_INFO "STAC9766 SoC Audio Codec %s\n", STAC9766_VERSION);
+
+       socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (socdev->card->codec == NULL)
+               return -ENOMEM;
+       codec = socdev->card->codec;
+       mutex_init(&codec->mutex);
+
+       codec->reg_cache = kmemdup(stac9766_reg, sizeof(stac9766_reg),
+                                  GFP_KERNEL);
+       if (codec->reg_cache == NULL) {
+               ret = -ENOMEM;
+               goto cache_err;
+       }
+       codec->reg_cache_size = sizeof(stac9766_reg);
+       codec->reg_cache_step = 2;
+
+       codec->name = "STAC9766";
+       codec->owner = THIS_MODULE;
+       codec->dai = stac9766_dai;
+       codec->num_dai = ARRAY_SIZE(stac9766_dai);
+       codec->write = stac9766_ac97_write;
+       codec->read = stac9766_ac97_read;
+       codec->set_bias_level = stac9766_set_bias_level;
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
+       if (ret < 0)
+               goto codec_err;
+
+       /* register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0)
+               goto pcm_err;
+
+       /* do a cold reset for the controller and then try
+        * a warm reset followed by an optional cold reset for codec */
+       stac9766_reset(codec, 0);
+       ret = stac9766_reset(codec, 1);
+       if (ret < 0) {
+               printk(KERN_ERR "Failed to reset STAC9766: AC97 link error\n");
+               goto reset_err;
+       }
+
+       stac9766_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       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:
+       snd_soc_free_pcms(socdev);
+pcm_err:
+       snd_soc_free_ac97_codec(codec);
+codec_err:
+       kfree(codec->private_data);
+cache_err:
+       kfree(socdev->card->codec);
+       socdev->card->codec = NULL;
+       return ret;
+}
+
+static int stac9766_codec_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);
+       snd_soc_free_ac97_codec(codec);
+       kfree(codec->reg_cache);
+       kfree(codec);
+       return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_stac9766 = {
+       .probe = stac9766_codec_probe,
+       .remove = stac9766_codec_remove,
+       .suspend = stac9766_codec_suspend,
+       .resume = stac9766_codec_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_stac9766);
+
+MODULE_DESCRIPTION("ASoC stac9766 driver");
+MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/stac9766.h b/sound/soc/codecs/stac9766.h
new file mode 100644 (file)
index 0000000..65642eb
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * stac9766.h  --  STAC9766 Soc Audio driver
+ */
+
+#ifndef _STAC9766_H
+#define _STAC9766_H
+
+#define AC97_STAC_PAGE0 0x1000
+#define AC97_STAC_DA_CONTROL (AC97_STAC_PAGE0 | 0x6A)
+#define AC97_STAC_ANALOG_SPECIAL (AC97_STAC_PAGE0 | 0x6E)
+#define AC97_STAC_STEREO_MIC 0x78
+
+/* STAC9766 DAI ID's */
+#define STAC9766_DAI_AC97_ANALOG               0
+#define STAC9766_DAI_AC97_DIGITAL              1
+
+extern struct snd_soc_dai stac9766_dai[];
+extern struct snd_soc_codec_device soc_codec_dev_stac9766;
+
+
+#endif
index c3f4afb5d0173a581d0bcb18e8670d88c2d4d498..0b8dcb5cd729281bfd80264acdb5a58b9025636e 100644 (file)
@@ -86,7 +86,7 @@ static int tlv320aic23_write(struct snd_soc_codec *codec, unsigned int reg,
         */
 
        if ((reg < 0 || reg > 9) && (reg != 15)) {
-               printk(KERN_WARNING "%s Invalid register R%d\n", __func__, reg);
+               printk(KERN_WARNING "%s Invalid register R%u\n", __func__, reg);
                return -1;
        }
 
@@ -98,7 +98,7 @@ static int tlv320aic23_write(struct snd_soc_codec *codec, unsigned int reg,
        if (codec->hw_write(codec->control_data, data, 2) == 2)
                return 0;
 
-       printk(KERN_ERR "%s cannot write %03x to register R%d\n", __func__,
+       printk(KERN_ERR "%s cannot write %03x to register R%u\n", __func__,
               value, reg);
 
        return -EIO;
@@ -273,14 +273,14 @@ static const unsigned short sr_valid_mask[] = {
  * Every divisor is a factor of 11*12
  */
 #define SR_MULT (11*12)
-#define A(x) (x) ? (SR_MULT/x) : 0
+#define A(x) (SR_MULT/x)
 static const unsigned char sr_adc_mult_table[] = {
-       A(2), A(2), A(12), A(12),  A(0), A(0), A(3), A(1),
-       A(2), A(2), A(11), A(11),  A(0), A(0), A(0), A(1)
+       A(2), A(2), A(12), A(12),  0, 0, A(3), A(1),
+       A(2), A(2), A(11), A(11),  0, 0, 0, A(1)
 };
 static const unsigned char sr_dac_mult_table[] = {
-       A(2), A(12), A(2), A(12),  A(0), A(0), A(3), A(1),
-       A(2), A(11), A(2), A(11),  A(0), A(0), A(0), A(1)
+       A(2), A(12), A(2), A(12),  0, 0, A(3), A(1),
+       A(2), A(11), A(2), A(11),  0, 0, 0, A(1)
 };
 
 static unsigned get_score(int adc, int adc_l, int adc_h, int need_adc,
@@ -523,6 +523,8 @@ static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai,
        case SND_SOC_DAIFMT_I2S:
                iface_reg |= TLV320AIC23_FOR_I2S;
                break;
+       case SND_SOC_DAIFMT_DSP_A:
+               iface_reg |= TLV320AIC23_LRP_ON;
        case SND_SOC_DAIFMT_DSP_B:
                iface_reg |= TLV320AIC23_FOR_DSP;
                break;
index df7c8c281d2f8bec0aff69307bb7f1a5985fe1d3..4dbb853eef5ad056fec1e6cca89f0becbe579251 100644 (file)
@@ -115,6 +115,7 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
        0x00, /* REG_VIBRA_PWM_SET      (0x47)  */
        0x00, /* REG_ANAMIC_GAIN        (0x48)  */
        0x00, /* REG_MISC_SET_2         (0x49)  */
+       0x00, /* REG_SW_SHADOW          (0x4A)  - Shadow, non HW register */
 };
 
 /* codec private data */
@@ -125,6 +126,17 @@ struct twl4030_priv {
 
        struct snd_pcm_substream *master_substream;
        struct snd_pcm_substream *slave_substream;
+
+       unsigned int configured;
+       unsigned int rate;
+       unsigned int sample_bits;
+       unsigned int channels;
+
+       unsigned int sysclk;
+
+       /* Headset output state handling */
+       unsigned int hsl_enabled;
+       unsigned int hsr_enabled;
 };
 
 /*
@@ -161,7 +173,11 @@ static int twl4030_write(struct snd_soc_codec *codec,
                        unsigned int reg, unsigned int value)
 {
        twl4030_write_reg_cache(codec, reg, value);
-       return twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg);
+       if (likely(reg < TWL4030_REG_SW_SHADOW))
+               return twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value,
+                                           reg);
+       else
+               return 0;
 }
 
 static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable)
@@ -188,6 +204,7 @@ static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable)
 
 static void twl4030_init_chip(struct snd_soc_codec *codec)
 {
+       u8 *cache = codec->reg_cache;
        int i;
 
        /* clear CODECPDZ prior to setting register defaults */
@@ -195,7 +212,7 @@ 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, twl4030_reg[i]);
+               twl4030_write(codec, i, cache[i]);
 
 }
 
@@ -232,7 +249,7 @@ static void twl4030_codec_mute(struct snd_soc_codec *codec, int mute)
                                        TWL4030_REG_PRECKL_CTL);
                reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_PRECKR_CTL);
                twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
-                                       reg_val & (~TWL4030_PRECKL_GAIN),
+                                       reg_val & (~TWL4030_PRECKR_GAIN),
                                        TWL4030_REG_PRECKR_CTL);
 
                /* Disable PLL */
@@ -316,104 +333,60 @@ static void twl4030_power_down(struct snd_soc_codec *codec)
 }
 
 /* Earpiece */
-static const char *twl4030_earpiece_texts[] =
-               {"Off", "DACL1", "DACL2", "DACR1"};
-
-static const unsigned int twl4030_earpiece_values[] =
-               {0x0, 0x1, 0x2, 0x4};
-
-static const struct soc_enum twl4030_earpiece_enum =
-       SOC_VALUE_ENUM_SINGLE(TWL4030_REG_EAR_CTL, 1, 0x7,
-                       ARRAY_SIZE(twl4030_earpiece_texts),
-                       twl4030_earpiece_texts,
-                       twl4030_earpiece_values);
-
-static const struct snd_kcontrol_new twl4030_dapm_earpiece_control =
-SOC_DAPM_VALUE_ENUM("Route", twl4030_earpiece_enum);
+static const struct snd_kcontrol_new twl4030_dapm_earpiece_controls[] = {
+       SOC_DAPM_SINGLE("Voice", TWL4030_REG_EAR_CTL, 0, 1, 0),
+       SOC_DAPM_SINGLE("AudioL1", TWL4030_REG_EAR_CTL, 1, 1, 0),
+       SOC_DAPM_SINGLE("AudioL2", TWL4030_REG_EAR_CTL, 2, 1, 0),
+       SOC_DAPM_SINGLE("AudioR1", TWL4030_REG_EAR_CTL, 3, 1, 0),
+};
 
 /* PreDrive Left */
-static const char *twl4030_predrivel_texts[] =
-               {"Off", "DACL1", "DACL2", "DACR2"};
-
-static const unsigned int twl4030_predrivel_values[] =
-               {0x0, 0x1, 0x2, 0x4};
-
-static const struct soc_enum twl4030_predrivel_enum =
-       SOC_VALUE_ENUM_SINGLE(TWL4030_REG_PREDL_CTL, 1, 0x7,
-                       ARRAY_SIZE(twl4030_predrivel_texts),
-                       twl4030_predrivel_texts,
-                       twl4030_predrivel_values);
-
-static const struct snd_kcontrol_new twl4030_dapm_predrivel_control =
-SOC_DAPM_VALUE_ENUM("Route", twl4030_predrivel_enum);
+static const struct snd_kcontrol_new twl4030_dapm_predrivel_controls[] = {
+       SOC_DAPM_SINGLE("Voice", TWL4030_REG_PREDL_CTL, 0, 1, 0),
+       SOC_DAPM_SINGLE("AudioL1", TWL4030_REG_PREDL_CTL, 1, 1, 0),
+       SOC_DAPM_SINGLE("AudioL2", TWL4030_REG_PREDL_CTL, 2, 1, 0),
+       SOC_DAPM_SINGLE("AudioR2", TWL4030_REG_PREDL_CTL, 3, 1, 0),
+};
 
 /* PreDrive Right */
-static const char *twl4030_predriver_texts[] =
-               {"Off", "DACR1", "DACR2", "DACL2"};
-
-static const unsigned int twl4030_predriver_values[] =
-               {0x0, 0x1, 0x2, 0x4};
-
-static const struct soc_enum twl4030_predriver_enum =
-       SOC_VALUE_ENUM_SINGLE(TWL4030_REG_PREDR_CTL, 1, 0x7,
-                       ARRAY_SIZE(twl4030_predriver_texts),
-                       twl4030_predriver_texts,
-                       twl4030_predriver_values);
-
-static const struct snd_kcontrol_new twl4030_dapm_predriver_control =
-SOC_DAPM_VALUE_ENUM("Route", twl4030_predriver_enum);
+static const struct snd_kcontrol_new twl4030_dapm_predriver_controls[] = {
+       SOC_DAPM_SINGLE("Voice", TWL4030_REG_PREDR_CTL, 0, 1, 0),
+       SOC_DAPM_SINGLE("AudioR1", TWL4030_REG_PREDR_CTL, 1, 1, 0),
+       SOC_DAPM_SINGLE("AudioR2", TWL4030_REG_PREDR_CTL, 2, 1, 0),
+       SOC_DAPM_SINGLE("AudioL2", TWL4030_REG_PREDR_CTL, 3, 1, 0),
+};
 
 /* Headset Left */
-static const char *twl4030_hsol_texts[] =
-               {"Off", "DACL1", "DACL2"};
-
-static const struct soc_enum twl4030_hsol_enum =
-       SOC_ENUM_SINGLE(TWL4030_REG_HS_SEL, 1,
-                       ARRAY_SIZE(twl4030_hsol_texts),
-                       twl4030_hsol_texts);
-
-static const struct snd_kcontrol_new twl4030_dapm_hsol_control =
-SOC_DAPM_ENUM("Route", twl4030_hsol_enum);
+static const struct snd_kcontrol_new twl4030_dapm_hsol_controls[] = {
+       SOC_DAPM_SINGLE("Voice", TWL4030_REG_HS_SEL, 0, 1, 0),
+       SOC_DAPM_SINGLE("AudioL1", TWL4030_REG_HS_SEL, 1, 1, 0),
+       SOC_DAPM_SINGLE("AudioL2", TWL4030_REG_HS_SEL, 2, 1, 0),
+};
 
 /* Headset Right */
-static const char *twl4030_hsor_texts[] =
-               {"Off", "DACR1", "DACR2"};
-
-static const struct soc_enum twl4030_hsor_enum =
-       SOC_ENUM_SINGLE(TWL4030_REG_HS_SEL, 4,
-                       ARRAY_SIZE(twl4030_hsor_texts),
-                       twl4030_hsor_texts);
-
-static const struct snd_kcontrol_new twl4030_dapm_hsor_control =
-SOC_DAPM_ENUM("Route", twl4030_hsor_enum);
+static const struct snd_kcontrol_new twl4030_dapm_hsor_controls[] = {
+       SOC_DAPM_SINGLE("Voice", TWL4030_REG_HS_SEL, 3, 1, 0),
+       SOC_DAPM_SINGLE("AudioR1", TWL4030_REG_HS_SEL, 4, 1, 0),
+       SOC_DAPM_SINGLE("AudioR2", TWL4030_REG_HS_SEL, 5, 1, 0),
+};
 
 /* Carkit Left */
-static const char *twl4030_carkitl_texts[] =
-               {"Off", "DACL1", "DACL2"};
-
-static const struct soc_enum twl4030_carkitl_enum =
-       SOC_ENUM_SINGLE(TWL4030_REG_PRECKL_CTL, 1,
-                       ARRAY_SIZE(twl4030_carkitl_texts),
-                       twl4030_carkitl_texts);
-
-static const struct snd_kcontrol_new twl4030_dapm_carkitl_control =
-SOC_DAPM_ENUM("Route", twl4030_carkitl_enum);
+static const struct snd_kcontrol_new twl4030_dapm_carkitl_controls[] = {
+       SOC_DAPM_SINGLE("Voice", TWL4030_REG_PRECKL_CTL, 0, 1, 0),
+       SOC_DAPM_SINGLE("AudioL1", TWL4030_REG_PRECKL_CTL, 1, 1, 0),
+       SOC_DAPM_SINGLE("AudioL2", TWL4030_REG_PRECKL_CTL, 2, 1, 0),
+};
 
 /* Carkit Right */
-static const char *twl4030_carkitr_texts[] =
-               {"Off", "DACR1", "DACR2"};
-
-static const struct soc_enum twl4030_carkitr_enum =
-       SOC_ENUM_SINGLE(TWL4030_REG_PRECKR_CTL, 1,
-                       ARRAY_SIZE(twl4030_carkitr_texts),
-                       twl4030_carkitr_texts);
-
-static const struct snd_kcontrol_new twl4030_dapm_carkitr_control =
-SOC_DAPM_ENUM("Route", twl4030_carkitr_enum);
+static const struct snd_kcontrol_new twl4030_dapm_carkitr_controls[] = {
+       SOC_DAPM_SINGLE("Voice", TWL4030_REG_PRECKR_CTL, 0, 1, 0),
+       SOC_DAPM_SINGLE("AudioR1", TWL4030_REG_PRECKR_CTL, 1, 1, 0),
+       SOC_DAPM_SINGLE("AudioR2", TWL4030_REG_PRECKR_CTL, 2, 1, 0),
+};
 
 /* Handsfree Left */
 static const char *twl4030_handsfreel_texts[] =
-               {"Voice", "DACL1", "DACL2", "DACR2"};
+               {"Voice", "AudioL1", "AudioL2", "AudioR2"};
 
 static const struct soc_enum twl4030_handsfreel_enum =
        SOC_ENUM_SINGLE(TWL4030_REG_HFL_CTL, 0,
@@ -423,9 +396,13 @@ static const struct soc_enum twl4030_handsfreel_enum =
 static const struct snd_kcontrol_new twl4030_dapm_handsfreel_control =
 SOC_DAPM_ENUM("Route", twl4030_handsfreel_enum);
 
+/* Handsfree Left virtual mute */
+static const struct snd_kcontrol_new twl4030_dapm_handsfreelmute_control =
+       SOC_DAPM_SINGLE("Switch", TWL4030_REG_SW_SHADOW, 0, 1, 0);
+
 /* Handsfree Right */
 static const char *twl4030_handsfreer_texts[] =
-               {"Voice", "DACR1", "DACR2", "DACL2"};
+               {"Voice", "AudioR1", "AudioR2", "AudioL2"};
 
 static const struct soc_enum twl4030_handsfreer_enum =
        SOC_ENUM_SINGLE(TWL4030_REG_HFR_CTL, 0,
@@ -435,37 +412,48 @@ static const struct soc_enum twl4030_handsfreer_enum =
 static const struct snd_kcontrol_new twl4030_dapm_handsfreer_control =
 SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum);
 
-/* Left analog microphone selection */
-static const char *twl4030_analoglmic_texts[] =
-               {"Off", "Main mic", "Headset mic", "AUXL", "Carkit mic"};
+/* Handsfree Right virtual mute */
+static const struct snd_kcontrol_new twl4030_dapm_handsfreermute_control =
+       SOC_DAPM_SINGLE("Switch", TWL4030_REG_SW_SHADOW, 1, 1, 0);
 
-static const unsigned int twl4030_analoglmic_values[] =
-               {0x0, 0x1, 0x2, 0x4, 0x8};
+/* Vibra */
+/* Vibra audio path selection */
+static const char *twl4030_vibra_texts[] =
+               {"AudioL1", "AudioR1", "AudioL2", "AudioR2"};
 
-static const struct soc_enum twl4030_analoglmic_enum =
-       SOC_VALUE_ENUM_SINGLE(TWL4030_REG_ANAMICL, 0, 0xf,
-                       ARRAY_SIZE(twl4030_analoglmic_texts),
-                       twl4030_analoglmic_texts,
-                       twl4030_analoglmic_values);
+static const struct soc_enum twl4030_vibra_enum =
+       SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 2,
+                       ARRAY_SIZE(twl4030_vibra_texts),
+                       twl4030_vibra_texts);
 
-static const struct snd_kcontrol_new twl4030_dapm_analoglmic_control =
-SOC_DAPM_VALUE_ENUM("Route", twl4030_analoglmic_enum);
+static const struct snd_kcontrol_new twl4030_dapm_vibra_control =
+SOC_DAPM_ENUM("Route", twl4030_vibra_enum);
 
-/* Right analog microphone selection */
-static const char *twl4030_analogrmic_texts[] =
-               {"Off", "Sub mic", "AUXR"};
+/* Vibra path selection: local vibrator (PWM) or audio driven */
+static const char *twl4030_vibrapath_texts[] =
+               {"Local vibrator", "Audio"};
 
-static const unsigned int twl4030_analogrmic_values[] =
-               {0x0, 0x1, 0x4};
+static const struct soc_enum twl4030_vibrapath_enum =
+       SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 4,
+                       ARRAY_SIZE(twl4030_vibrapath_texts),
+                       twl4030_vibrapath_texts);
 
-static const struct soc_enum twl4030_analogrmic_enum =
-       SOC_VALUE_ENUM_SINGLE(TWL4030_REG_ANAMICR, 0, 0x5,
-                       ARRAY_SIZE(twl4030_analogrmic_texts),
-                       twl4030_analogrmic_texts,
-                       twl4030_analogrmic_values);
+static const struct snd_kcontrol_new twl4030_dapm_vibrapath_control =
+SOC_DAPM_ENUM("Route", twl4030_vibrapath_enum);
 
-static const struct snd_kcontrol_new twl4030_dapm_analogrmic_control =
-SOC_DAPM_VALUE_ENUM("Route", twl4030_analogrmic_enum);
+/* Left analog microphone selection */
+static const struct snd_kcontrol_new twl4030_dapm_analoglmic_controls[] = {
+       SOC_DAPM_SINGLE("Main mic", TWL4030_REG_ANAMICL, 0, 1, 0),
+       SOC_DAPM_SINGLE("Headset mic", TWL4030_REG_ANAMICL, 1, 1, 0),
+       SOC_DAPM_SINGLE("AUXL", TWL4030_REG_ANAMICL, 2, 1, 0),
+       SOC_DAPM_SINGLE("Carkit mic", TWL4030_REG_ANAMICL, 3, 1, 0),
+};
+
+/* Right analog microphone selection */
+static const struct snd_kcontrol_new twl4030_dapm_analogrmic_controls[] = {
+       SOC_DAPM_SINGLE("Sub mic", TWL4030_REG_ANAMICR, 0, 1, 0),
+       SOC_DAPM_SINGLE("AUXR", TWL4030_REG_ANAMICR, 2, 1, 0),
+};
 
 /* TX1 L/R Analog/Digital microphone selection */
 static const char *twl4030_micpathtx1_texts[] =
@@ -507,6 +495,10 @@ static const struct snd_kcontrol_new twl4030_dapm_abypassr2_control =
 static const struct snd_kcontrol_new twl4030_dapm_abypassl2_control =
        SOC_DAPM_SINGLE("Switch", TWL4030_REG_ARXL2_APGA_CTL, 2, 1, 0);
 
+/* Analog bypass for Voice */
+static const struct snd_kcontrol_new twl4030_dapm_abypassv_control =
+       SOC_DAPM_SINGLE("Switch", TWL4030_REG_VDL_APGA_CTL, 2, 1, 0);
+
 /* Digital bypass gain, 0 mutes the bypass */
 static const unsigned int twl4030_dapm_dbypass_tlv[] = {
        TLV_DB_RANGE_HEAD(2),
@@ -526,6 +518,18 @@ static const struct snd_kcontrol_new twl4030_dapm_dbypassr_control =
                        TWL4030_REG_ATX2ARXPGA, 0, 7, 0,
                        twl4030_dapm_dbypass_tlv);
 
+/*
+ * Voice Sidetone GAIN volume control:
+ * from -51 to -10 dB in 1 dB steps (mute instead of -51 dB)
+ */
+static DECLARE_TLV_DB_SCALE(twl4030_dapm_dbypassv_tlv, -5100, 100, 1);
+
+/* Digital bypass voice: sidetone (VUL -> VDL)*/
+static const struct snd_kcontrol_new twl4030_dapm_dbypassv_control =
+       SOC_DAPM_SINGLE_TLV("Volume",
+                       TWL4030_REG_VSTPGA, 0, 0x29, 0,
+                       twl4030_dapm_dbypassv_tlv);
+
 static int micpath_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
@@ -556,63 +560,143 @@ static int micpath_event(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
-static int handsfree_event(struct snd_soc_dapm_widget *w,
-               struct snd_kcontrol *kcontrol, int event)
+static void handsfree_ramp(struct snd_soc_codec *codec, int reg, int ramp)
 {
-       struct soc_enum *e = (struct soc_enum *)w->kcontrols->private_value;
        unsigned char hs_ctl;
 
-       hs_ctl = twl4030_read_reg_cache(w->codec, e->reg);
+       hs_ctl = twl4030_read_reg_cache(codec, reg);
 
-       if (hs_ctl & TWL4030_HF_CTL_REF_EN) {
+       if (ramp) {
+               /* HF ramp-up */
+               hs_ctl |= TWL4030_HF_CTL_REF_EN;
+               twl4030_write(codec, reg, hs_ctl);
+               udelay(10);
                hs_ctl |= TWL4030_HF_CTL_RAMP_EN;
-               twl4030_write(w->codec, e->reg, hs_ctl);
+               twl4030_write(codec, reg, hs_ctl);
+               udelay(40);
                hs_ctl |= TWL4030_HF_CTL_LOOP_EN;
-               twl4030_write(w->codec, e->reg, hs_ctl);
                hs_ctl |= TWL4030_HF_CTL_HB_EN;
-               twl4030_write(w->codec, e->reg, hs_ctl);
+               twl4030_write(codec, reg, hs_ctl);
        } else {
-               hs_ctl &= ~(TWL4030_HF_CTL_RAMP_EN | TWL4030_HF_CTL_LOOP_EN
-                               | TWL4030_HF_CTL_HB_EN);
-               twl4030_write(w->codec, e->reg, hs_ctl);
+               /* HF ramp-down */
+               hs_ctl &= ~TWL4030_HF_CTL_LOOP_EN;
+               hs_ctl &= ~TWL4030_HF_CTL_HB_EN;
+               twl4030_write(codec, reg, hs_ctl);
+               hs_ctl &= ~TWL4030_HF_CTL_RAMP_EN;
+               twl4030_write(codec, reg, hs_ctl);
+               udelay(40);
+               hs_ctl &= ~TWL4030_HF_CTL_REF_EN;
+               twl4030_write(codec, reg, hs_ctl);
        }
+}
 
+static int handsfreelpga_event(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol, int event)
+{
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               handsfree_ramp(w->codec, TWL4030_REG_HFL_CTL, 1);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               handsfree_ramp(w->codec, TWL4030_REG_HFL_CTL, 0);
+               break;
+       }
        return 0;
 }
 
-static int headsetl_event(struct snd_soc_dapm_widget *w,
+static int handsfreerpga_event(struct snd_soc_dapm_widget *w,
                struct snd_kcontrol *kcontrol, int event)
+{
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               handsfree_ramp(w->codec, TWL4030_REG_HFR_CTL, 1);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               handsfree_ramp(w->codec, TWL4030_REG_HFR_CTL, 0);
+               break;
+       }
+       return 0;
+}
+
+static void headset_ramp(struct snd_soc_codec *codec, int ramp)
 {
        unsigned char hs_gain, hs_pop;
+       struct twl4030_priv *twl4030 = codec->private_data;
+       /* Base values for ramp delay calculation: 2^19 - 2^26 */
+       unsigned int ramp_base[] = {524288, 1048576, 2097152, 4194304,
+                                   8388608, 16777216, 33554432, 67108864};
 
-       /* Save the current volume */
-       hs_gain = twl4030_read_reg_cache(w->codec, TWL4030_REG_HS_GAIN_SET);
-       hs_pop = twl4030_read_reg_cache(w->codec, TWL4030_REG_HS_POPN_SET);
+       hs_gain = twl4030_read_reg_cache(codec, TWL4030_REG_HS_GAIN_SET);
+       hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
 
-       switch (event) {
-       case SND_SOC_DAPM_POST_PMU:
-               /* Do the anti-pop/bias ramp enable according to the TRM */
+       if (ramp) {
+               /* Headset ramp-up according to the TRM */
                hs_pop |= TWL4030_VMID_EN;
-               twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop);
-               /* Is this needed? Can we just use whatever gain here? */
-               twl4030_write(w->codec, TWL4030_REG_HS_GAIN_SET,
-                               (hs_gain & (~0x0f)) | 0x0a);
+               twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+               twl4030_write(codec, TWL4030_REG_HS_GAIN_SET, hs_gain);
                hs_pop |= TWL4030_RAMP_EN;
-               twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop);
-
-               /* Restore the original volume */
-               twl4030_write(w->codec, TWL4030_REG_HS_GAIN_SET, hs_gain);
-               break;
-       case SND_SOC_DAPM_POST_PMD:
-               /* Do the anti-pop/bias ramp disable according to the TRM */
+               twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+       } else {
+               /* Headset ramp-down _not_ according to
+                * the TRM, but in a way that it is working */
                hs_pop &= ~TWL4030_RAMP_EN;
-               twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+               twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+               /* Wait ramp delay time + 1, so the VMID can settle */
+               mdelay((ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] /
+                       twl4030->sysclk) + 1);
                /* Bypass the reg_cache to mute the headset */
                twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
                                        hs_gain & (~0x0f),
                                        TWL4030_REG_HS_GAIN_SET);
+
                hs_pop &= ~TWL4030_VMID_EN;
-               twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+               twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+       }
+}
+
+static int headsetlpga_event(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol, int event)
+{
+       struct twl4030_priv *twl4030 = w->codec->private_data;
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               /* Do the ramp-up only once */
+               if (!twl4030->hsr_enabled)
+                       headset_ramp(w->codec, 1);
+
+               twl4030->hsl_enabled = 1;
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               /* Do the ramp-down only if both headsetL/R is disabled */
+               if (!twl4030->hsr_enabled)
+                       headset_ramp(w->codec, 0);
+
+               twl4030->hsl_enabled = 0;
+               break;
+       }
+       return 0;
+}
+
+static int headsetrpga_event(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol, int event)
+{
+       struct twl4030_priv *twl4030 = w->codec->private_data;
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               /* Do the ramp-up only once */
+               if (!twl4030->hsl_enabled)
+                       headset_ramp(w->codec, 1);
+
+               twl4030->hsr_enabled = 1;
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               /* Do the ramp-down only if both headsetL/R is disabled */
+               if (!twl4030->hsl_enabled)
+                       headset_ramp(w->codec, 0);
+
+               twl4030->hsr_enabled = 0;
                break;
        }
        return 0;
@@ -624,7 +708,7 @@ static int bypass_event(struct snd_soc_dapm_widget *w,
        struct soc_mixer_control *m =
                (struct soc_mixer_control *)w->kcontrols->private_value;
        struct twl4030_priv *twl4030 = w->codec->private_data;
-       unsigned char reg;
+       unsigned char reg, misc;
 
        reg = twl4030_read_reg_cache(w->codec, m->reg);
 
@@ -636,14 +720,34 @@ static int bypass_event(struct snd_soc_dapm_widget *w,
                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 if (m->reg == TWL4030_REG_VSTPGA) {
+               /* Voice digital bypass */
+               if (reg)
+                       twl4030->bypass_state |= (1 << 5);
+               else
+                       twl4030->bypass_state &= ~(1 << 5);
        } else {
                /* Digital bypass */
                if (reg & (0x7 << m->shift))
-                       twl4030->bypass_state |= (1 << (m->shift ? 5 : 4));
+                       twl4030->bypass_state |= (1 << (m->shift ? 7 : 6));
                else
-                       twl4030->bypass_state &= ~(1 << (m->shift ? 5 : 4));
+                       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);
@@ -810,6 +914,48 @@ static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
        return err;
 }
 
+/* Codec operation modes */
+static const char *twl4030_op_modes_texts[] = {
+       "Option 2 (voice/audio)", "Option 1 (audio)"
+};
+
+static const struct soc_enum twl4030_op_modes_enum =
+       SOC_ENUM_SINGLE(TWL4030_REG_CODEC_MODE, 0,
+                       ARRAY_SIZE(twl4030_op_modes_texts),
+                       twl4030_op_modes_texts);
+
+int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct twl4030_priv *twl4030 = codec->private_data;
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       unsigned short val;
+       unsigned short mask, bitmask;
+
+       if (twl4030->configured) {
+               printk(KERN_ERR "twl4030 operation mode cannot be "
+                       "changed on-the-fly\n");
+               return -EBUSY;
+       }
+
+       for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
+               ;
+       if (ucontrol->value.enumerated.item[0] > e->max - 1)
+               return -EINVAL;
+
+       val = ucontrol->value.enumerated.item[0] << e->shift_l;
+       mask = (bitmask - 1) << e->shift_l;
+       if (e->shift_l != e->shift_r) {
+               if (ucontrol->value.enumerated.item[1] > e->max - 1)
+                       return -EINVAL;
+               val |= ucontrol->value.enumerated.item[1] << e->shift_r;
+               mask |= (bitmask - 1) << e->shift_r;
+       }
+
+       return snd_soc_update_bits(codec, e->reg, mask, val);
+}
+
 /*
  * FGAIN volume control:
  * from -62 to 0 dB in 1 dB steps (mute instead of -63 dB)
@@ -823,6 +969,12 @@ static DECLARE_TLV_DB_SCALE(digital_fine_tlv, -6300, 100, 1);
  */
 static DECLARE_TLV_DB_SCALE(digital_coarse_tlv, 0, 600, 0);
 
+/*
+ * Voice Downlink GAIN volume control:
+ * from -37 to 12 dB in 1 dB steps (mute instead of -37 dB)
+ */
+static DECLARE_TLV_DB_SCALE(digital_voice_downlink_tlv, -3700, 100, 1);
+
 /*
  * Analog playback gain
  * -24 dB to 12 dB in 2 dB steps
@@ -864,7 +1016,32 @@ static const struct soc_enum twl4030_rampdelay_enum =
                        ARRAY_SIZE(twl4030_rampdelay_texts),
                        twl4030_rampdelay_texts);
 
+/* Vibra H-bridge direction mode */
+static const char *twl4030_vibradirmode_texts[] = {
+       "Vibra H-bridge direction", "Audio data MSB",
+};
+
+static const struct soc_enum twl4030_vibradirmode_enum =
+       SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 5,
+                       ARRAY_SIZE(twl4030_vibradirmode_texts),
+                       twl4030_vibradirmode_texts);
+
+/* Vibra H-bridge direction */
+static const char *twl4030_vibradir_texts[] = {
+       "Positive polarity", "Negative polarity",
+};
+
+static const struct soc_enum twl4030_vibradir_enum =
+       SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 1,
+                       ARRAY_SIZE(twl4030_vibradir_texts),
+                       twl4030_vibradir_texts);
+
 static const struct snd_kcontrol_new twl4030_snd_controls[] = {
+       /* Codec operation mode control */
+       SOC_ENUM_EXT("Codec Operation Mode", twl4030_op_modes_enum,
+               snd_soc_get_enum_double,
+               snd_soc_put_twl4030_opmode_enum_double),
+
        /* Common playback gain controls */
        SOC_DOUBLE_R_TLV("DAC1 Digital Fine Playback Volume",
                TWL4030_REG_ARXL1PGA, TWL4030_REG_ARXR1PGA,
@@ -893,6 +1070,16 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = {
                TWL4030_REG_ARXL2_APGA_CTL, TWL4030_REG_ARXR2_APGA_CTL,
                1, 1, 0),
 
+       /* Common voice downlink gain controls */
+       SOC_SINGLE_TLV("DAC Voice Digital Downlink Volume",
+               TWL4030_REG_VRXPGA, 0, 0x31, 0, digital_voice_downlink_tlv),
+
+       SOC_SINGLE_TLV("DAC Voice Analog Downlink Volume",
+               TWL4030_REG_VDL_APGA_CTL, 3, 0x12, 1, analog_tlv),
+
+       SOC_SINGLE("DAC Voice Analog Downlink Switch",
+               TWL4030_REG_VDL_APGA_CTL, 1, 1, 0),
+
        /* Separate output gain controls */
        SOC_DOUBLE_R_TLV_TWL4030("PreDriv Playback Volume",
                TWL4030_REG_PREDL_CTL, TWL4030_REG_PREDR_CTL,
@@ -920,6 +1107,9 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = {
                0, 3, 5, 0, input_gain_tlv),
 
        SOC_ENUM("HS ramp delay", twl4030_rampdelay_enum),
+
+       SOC_ENUM("Vibra H-bridge mode", twl4030_vibradirmode_enum),
+       SOC_ENUM("Vibra H-bridge direction", twl4030_vibradir_enum),
 };
 
 static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
@@ -947,26 +1137,19 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
        SND_SOC_DAPM_OUTPUT("CARKITR"),
        SND_SOC_DAPM_OUTPUT("HFL"),
        SND_SOC_DAPM_OUTPUT("HFR"),
+       SND_SOC_DAPM_OUTPUT("VIBRA"),
 
        /* DACs */
-       SND_SOC_DAPM_DAC("DAC Right1", "Right Front Playback",
+       SND_SOC_DAPM_DAC("DAC Right1", "Right Front HiFi Playback",
                        SND_SOC_NOPM, 0, 0),
-       SND_SOC_DAPM_DAC("DAC Left1", "Left Front Playback",
+       SND_SOC_DAPM_DAC("DAC Left1", "Left Front HiFi Playback",
                        SND_SOC_NOPM, 0, 0),
-       SND_SOC_DAPM_DAC("DAC Right2", "Right Rear Playback",
+       SND_SOC_DAPM_DAC("DAC Right2", "Right Rear HiFi Playback",
                        SND_SOC_NOPM, 0, 0),
-       SND_SOC_DAPM_DAC("DAC Left2", "Left Rear Playback",
+       SND_SOC_DAPM_DAC("DAC Left2", "Left Rear HiFi Playback",
+                       SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("DAC Voice", "Voice Playback",
                        SND_SOC_NOPM, 0, 0),
-
-       /* Analog PGAs */
-       SND_SOC_DAPM_PGA("ARXR1_APGA", TWL4030_REG_ARXR1_APGA_CTL,
-                       0, 0, NULL, 0),
-       SND_SOC_DAPM_PGA("ARXL1_APGA", TWL4030_REG_ARXL1_APGA_CTL,
-                       0, 0, NULL, 0),
-       SND_SOC_DAPM_PGA("ARXR2_APGA", TWL4030_REG_ARXR2_APGA_CTL,
-                       0, 0, NULL, 0),
-       SND_SOC_DAPM_PGA("ARXL2_APGA", TWL4030_REG_ARXL2_APGA_CTL,
-                       0, 0, NULL, 0),
 
        /* Analog bypasses */
        SND_SOC_DAPM_SWITCH_E("Right1 Analog Loopback", SND_SOC_NOPM, 0, 0,
@@ -981,6 +1164,9 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
        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),
 
        /* Digital bypasses */
        SND_SOC_DAPM_SWITCH_E("Left Digital Loopback", SND_SOC_NOPM, 0, 0,
@@ -989,43 +1175,88 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
        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_MIXER("Analog R1 Playback Mixer", TWL4030_REG_AVDAC_CTL,
-                       0, 0, NULL, 0),
-       SND_SOC_DAPM_MIXER("Analog L1 Playback Mixer", TWL4030_REG_AVDAC_CTL,
-                       1, 0, NULL, 0),
-       SND_SOC_DAPM_MIXER("Analog R2 Playback Mixer", TWL4030_REG_AVDAC_CTL,
-                       2, 0, NULL, 0),
-       SND_SOC_DAPM_MIXER("Analog L2 Playback Mixer", TWL4030_REG_AVDAC_CTL,
-                       3, 0, NULL, 0),
-
-       /* Output MUX controls */
+       /* Digital mixers, power control for the physical DACs */
+       SND_SOC_DAPM_MIXER("Digital R1 Playback Mixer",
+                       TWL4030_REG_AVDAC_CTL, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Digital L1 Playback Mixer",
+                       TWL4030_REG_AVDAC_CTL, 1, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Digital R2 Playback Mixer",
+                       TWL4030_REG_AVDAC_CTL, 2, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Digital L2 Playback Mixer",
+                       TWL4030_REG_AVDAC_CTL, 3, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Digital Voice Playback Mixer",
+                       TWL4030_REG_AVDAC_CTL, 4, 0, NULL, 0),
+
+       /* Analog mixers, power control for the physical PGAs */
+       SND_SOC_DAPM_MIXER("Analog R1 Playback Mixer",
+                       TWL4030_REG_ARXR1_APGA_CTL, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Analog L1 Playback Mixer",
+                       TWL4030_REG_ARXL1_APGA_CTL, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Analog R2 Playback Mixer",
+                       TWL4030_REG_ARXR2_APGA_CTL, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Analog L2 Playback Mixer",
+                       TWL4030_REG_ARXL2_APGA_CTL, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Analog Voice Playback Mixer",
+                       TWL4030_REG_VDL_APGA_CTL, 0, 0, NULL, 0),
+
+       /* Output MIXER controls */
        /* Earpiece */
-       SND_SOC_DAPM_VALUE_MUX("Earpiece Mux", SND_SOC_NOPM, 0, 0,
-               &twl4030_dapm_earpiece_control),
+       SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0,
+                       &twl4030_dapm_earpiece_controls[0],
+                       ARRAY_SIZE(twl4030_dapm_earpiece_controls)),
        /* PreDrivL/R */
-       SND_SOC_DAPM_VALUE_MUX("PredriveL Mux", SND_SOC_NOPM, 0, 0,
-               &twl4030_dapm_predrivel_control),
-       SND_SOC_DAPM_VALUE_MUX("PredriveR Mux", SND_SOC_NOPM, 0, 0,
-               &twl4030_dapm_predriver_control),
+       SND_SOC_DAPM_MIXER("PredriveL Mixer", SND_SOC_NOPM, 0, 0,
+                       &twl4030_dapm_predrivel_controls[0],
+                       ARRAY_SIZE(twl4030_dapm_predrivel_controls)),
+       SND_SOC_DAPM_MIXER("PredriveR Mixer", SND_SOC_NOPM, 0, 0,
+                       &twl4030_dapm_predriver_controls[0],
+                       ARRAY_SIZE(twl4030_dapm_predriver_controls)),
        /* HeadsetL/R */
-       SND_SOC_DAPM_MUX_E("HeadsetL Mux", SND_SOC_NOPM, 0, 0,
-               &twl4030_dapm_hsol_control, headsetl_event,
-               SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
-       SND_SOC_DAPM_MUX("HeadsetR Mux", SND_SOC_NOPM, 0, 0,
-               &twl4030_dapm_hsor_control),
+       SND_SOC_DAPM_MIXER("HeadsetL Mixer", SND_SOC_NOPM, 0, 0,
+                       &twl4030_dapm_hsol_controls[0],
+                       ARRAY_SIZE(twl4030_dapm_hsol_controls)),
+       SND_SOC_DAPM_PGA_E("HeadsetL PGA", SND_SOC_NOPM,
+                       0, 0, NULL, 0, headsetlpga_event,
+                       SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MIXER("HeadsetR Mixer", SND_SOC_NOPM, 0, 0,
+                       &twl4030_dapm_hsor_controls[0],
+                       ARRAY_SIZE(twl4030_dapm_hsor_controls)),
+       SND_SOC_DAPM_PGA_E("HeadsetR PGA", SND_SOC_NOPM,
+                       0, 0, NULL, 0, headsetrpga_event,
+                       SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
        /* CarkitL/R */
-       SND_SOC_DAPM_MUX("CarkitL Mux", SND_SOC_NOPM, 0, 0,
-               &twl4030_dapm_carkitl_control),
-       SND_SOC_DAPM_MUX("CarkitR Mux", SND_SOC_NOPM, 0, 0,
-               &twl4030_dapm_carkitr_control),
+       SND_SOC_DAPM_MIXER("CarkitL Mixer", SND_SOC_NOPM, 0, 0,
+                       &twl4030_dapm_carkitl_controls[0],
+                       ARRAY_SIZE(twl4030_dapm_carkitl_controls)),
+       SND_SOC_DAPM_MIXER("CarkitR Mixer", SND_SOC_NOPM, 0, 0,
+                       &twl4030_dapm_carkitr_controls[0],
+                       ARRAY_SIZE(twl4030_dapm_carkitr_controls)),
+
+       /* Output MUX controls */
        /* HandsfreeL/R */
-       SND_SOC_DAPM_MUX_E("HandsfreeL Mux", TWL4030_REG_HFL_CTL, 5, 0,
-               &twl4030_dapm_handsfreel_control, handsfree_event,
-               SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
-       SND_SOC_DAPM_MUX_E("HandsfreeR Mux", TWL4030_REG_HFR_CTL, 5, 0,
-               &twl4030_dapm_handsfreer_control, handsfree_event,
-               SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MUX("HandsfreeL Mux", SND_SOC_NOPM, 0, 0,
+               &twl4030_dapm_handsfreel_control),
+       SND_SOC_DAPM_SWITCH("HandsfreeL Switch", SND_SOC_NOPM, 0, 0,
+                       &twl4030_dapm_handsfreelmute_control),
+       SND_SOC_DAPM_PGA_E("HandsfreeL PGA", SND_SOC_NOPM,
+                       0, 0, NULL, 0, handsfreelpga_event,
+                       SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MUX("HandsfreeR Mux", SND_SOC_NOPM, 5, 0,
+               &twl4030_dapm_handsfreer_control),
+       SND_SOC_DAPM_SWITCH("HandsfreeR Switch", SND_SOC_NOPM, 0, 0,
+                       &twl4030_dapm_handsfreermute_control),
+       SND_SOC_DAPM_PGA_E("HandsfreeR PGA", SND_SOC_NOPM,
+                       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("Vibra Route", SND_SOC_NOPM, 0, 0,
+               &twl4030_dapm_vibrapath_control),
 
        /* Introducing four virtual ADC, since TWL4030 have four channel for
           capture */
@@ -1050,11 +1281,15 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
                SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD|
                SND_SOC_DAPM_POST_REG),
 
-       /* Analog input muxes with switch for the capture amplifiers */
-       SND_SOC_DAPM_VALUE_MUX("Analog Left Capture Route",
-               TWL4030_REG_ANAMICL, 4, 0, &twl4030_dapm_analoglmic_control),
-       SND_SOC_DAPM_VALUE_MUX("Analog Right Capture Route",
-               TWL4030_REG_ANAMICR, 4, 0, &twl4030_dapm_analogrmic_control),
+       /* Analog input mixers for the capture amplifiers */
+       SND_SOC_DAPM_MIXER("Analog Left Capture Route",
+               TWL4030_REG_ANAMICL, 4, 0,
+               &twl4030_dapm_analoglmic_controls[0],
+               ARRAY_SIZE(twl4030_dapm_analoglmic_controls)),
+       SND_SOC_DAPM_MIXER("Analog Right Capture Route",
+               TWL4030_REG_ANAMICR, 4, 0,
+               &twl4030_dapm_analogrmic_controls[0],
+               ARRAY_SIZE(twl4030_dapm_analogrmic_controls)),
 
        SND_SOC_DAPM_PGA("ADC Physical Left",
                TWL4030_REG_AVADC_CTL, 3, 0, NULL, 0),
@@ -1073,62 +1308,86 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
 };
 
 static const struct snd_soc_dapm_route intercon[] = {
-       {"Analog L1 Playback Mixer", NULL, "DAC Left1"},
-       {"Analog R1 Playback Mixer", NULL, "DAC Right1"},
-       {"Analog L2 Playback Mixer", NULL, "DAC Left2"},
-       {"Analog R2 Playback Mixer", NULL, "DAC Right2"},
-
-       {"ARXL1_APGA", NULL, "Analog L1 Playback Mixer"},
-       {"ARXR1_APGA", NULL, "Analog R1 Playback Mixer"},
-       {"ARXL2_APGA", NULL, "Analog L2 Playback Mixer"},
-       {"ARXR2_APGA", NULL, "Analog R2 Playback Mixer"},
+       {"Digital L1 Playback Mixer", NULL, "DAC Left1"},
+       {"Digital R1 Playback Mixer", NULL, "DAC Right1"},
+       {"Digital L2 Playback Mixer", NULL, "DAC Left2"},
+       {"Digital R2 Playback Mixer", NULL, "DAC Right2"},
+       {"Digital Voice Playback Mixer", NULL, "DAC Voice"},
+
+       {"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"},
+       {"Analog R2 Playback Mixer", NULL, "Digital R2 Playback Mixer"},
+       {"Analog Voice Playback Mixer", NULL, "Digital Voice Playback Mixer"},
 
        /* Internal playback routings */
        /* Earpiece */
-       {"Earpiece Mux", "DACL1", "ARXL1_APGA"},
-       {"Earpiece Mux", "DACL2", "ARXL2_APGA"},
-       {"Earpiece Mux", "DACR1", "ARXR1_APGA"},
+       {"Earpiece Mixer", "Voice", "Analog Voice Playback Mixer"},
+       {"Earpiece Mixer", "AudioL1", "Analog L1 Playback Mixer"},
+       {"Earpiece Mixer", "AudioL2", "Analog L2 Playback Mixer"},
+       {"Earpiece Mixer", "AudioR1", "Analog R1 Playback Mixer"},
        /* PreDrivL */
-       {"PredriveL Mux", "DACL1", "ARXL1_APGA"},
-       {"PredriveL Mux", "DACL2", "ARXL2_APGA"},
-       {"PredriveL Mux", "DACR2", "ARXR2_APGA"},
+       {"PredriveL Mixer", "Voice", "Analog Voice Playback Mixer"},
+       {"PredriveL Mixer", "AudioL1", "Analog L1 Playback Mixer"},
+       {"PredriveL Mixer", "AudioL2", "Analog L2 Playback Mixer"},
+       {"PredriveL Mixer", "AudioR2", "Analog R2 Playback Mixer"},
        /* PreDrivR */
-       {"PredriveR Mux", "DACR1", "ARXR1_APGA"},
-       {"PredriveR Mux", "DACR2", "ARXR2_APGA"},
-       {"PredriveR Mux", "DACL2", "ARXL2_APGA"},
+       {"PredriveR Mixer", "Voice", "Analog Voice Playback Mixer"},
+       {"PredriveR Mixer", "AudioR1", "Analog R1 Playback Mixer"},
+       {"PredriveR Mixer", "AudioR2", "Analog R2 Playback Mixer"},
+       {"PredriveR Mixer", "AudioL2", "Analog L2 Playback Mixer"},
        /* HeadsetL */
-       {"HeadsetL Mux", "DACL1", "ARXL1_APGA"},
-       {"HeadsetL Mux", "DACL2", "ARXL2_APGA"},
+       {"HeadsetL Mixer", "Voice", "Analog Voice Playback Mixer"},
+       {"HeadsetL Mixer", "AudioL1", "Analog L1 Playback Mixer"},
+       {"HeadsetL Mixer", "AudioL2", "Analog L2 Playback Mixer"},
+       {"HeadsetL PGA", NULL, "HeadsetL Mixer"},
        /* HeadsetR */
-       {"HeadsetR Mux", "DACR1", "ARXR1_APGA"},
-       {"HeadsetR Mux", "DACR2", "ARXR2_APGA"},
+       {"HeadsetR Mixer", "Voice", "Analog Voice Playback Mixer"},
+       {"HeadsetR Mixer", "AudioR1", "Analog R1 Playback Mixer"},
+       {"HeadsetR Mixer", "AudioR2", "Analog R2 Playback Mixer"},
+       {"HeadsetR PGA", NULL, "HeadsetR Mixer"},
        /* CarkitL */
-       {"CarkitL Mux", "DACL1", "ARXL1_APGA"},
-       {"CarkitL Mux", "DACL2", "ARXL2_APGA"},
+       {"CarkitL Mixer", "Voice", "Analog Voice Playback Mixer"},
+       {"CarkitL Mixer", "AudioL1", "Analog L1 Playback Mixer"},
+       {"CarkitL Mixer", "AudioL2", "Analog L2 Playback Mixer"},
        /* CarkitR */
-       {"CarkitR Mux", "DACR1", "ARXR1_APGA"},
-       {"CarkitR Mux", "DACR2", "ARXR2_APGA"},
+       {"CarkitR Mixer", "Voice", "Analog Voice Playback Mixer"},
+       {"CarkitR Mixer", "AudioR1", "Analog R1 Playback Mixer"},
+       {"CarkitR Mixer", "AudioR2", "Analog R2 Playback Mixer"},
        /* HandsfreeL */
-       {"HandsfreeL Mux", "DACL1", "ARXL1_APGA"},
-       {"HandsfreeL Mux", "DACL2", "ARXL2_APGA"},
-       {"HandsfreeL Mux", "DACR2", "ARXR2_APGA"},
+       {"HandsfreeL Mux", "Voice", "Analog Voice Playback Mixer"},
+       {"HandsfreeL Mux", "AudioL1", "Analog L1 Playback Mixer"},
+       {"HandsfreeL Mux", "AudioL2", "Analog L2 Playback Mixer"},
+       {"HandsfreeL Mux", "AudioR2", "Analog R2 Playback Mixer"},
+       {"HandsfreeL Switch", "Switch", "HandsfreeL Mux"},
+       {"HandsfreeL PGA", NULL, "HandsfreeL Switch"},
        /* HandsfreeR */
-       {"HandsfreeR Mux", "DACR1", "ARXR1_APGA"},
-       {"HandsfreeR Mux", "DACR2", "ARXR2_APGA"},
-       {"HandsfreeR Mux", "DACL2", "ARXL2_APGA"},
+       {"HandsfreeR Mux", "Voice", "Analog Voice Playback Mixer"},
+       {"HandsfreeR Mux", "AudioR1", "Analog R1 Playback Mixer"},
+       {"HandsfreeR Mux", "AudioR2", "Analog R2 Playback Mixer"},
+       {"HandsfreeR Mux", "AudioL2", "Analog L2 Playback Mixer"},
+       {"HandsfreeR Switch", "Switch", "HandsfreeR Mux"},
+       {"HandsfreeR PGA", NULL, "HandsfreeR Switch"},
+       /* Vibra */
+       {"Vibra Mux", "AudioL1", "DAC Left1"},
+       {"Vibra Mux", "AudioR1", "DAC Right1"},
+       {"Vibra Mux", "AudioL2", "DAC Left2"},
+       {"Vibra Mux", "AudioR2", "DAC Right2"},
 
        /* outputs */
-       {"OUTL", NULL, "ARXL2_APGA"},
-       {"OUTR", NULL, "ARXR2_APGA"},
-       {"EARPIECE", NULL, "Earpiece Mux"},
-       {"PREDRIVEL", NULL, "PredriveL Mux"},
-       {"PREDRIVER", NULL, "PredriveR Mux"},
-       {"HSOL", NULL, "HeadsetL Mux"},
-       {"HSOR", NULL, "HeadsetR Mux"},
-       {"CARKITL", NULL, "CarkitL Mux"},
-       {"CARKITR", NULL, "CarkitR Mux"},
-       {"HFL", NULL, "HandsfreeL Mux"},
-       {"HFR", NULL, "HandsfreeR Mux"},
+       {"OUTL", NULL, "Analog L2 Playback Mixer"},
+       {"OUTR", NULL, "Analog R2 Playback Mixer"},
+       {"EARPIECE", NULL, "Earpiece Mixer"},
+       {"PREDRIVEL", NULL, "PredriveL Mixer"},
+       {"PREDRIVER", NULL, "PredriveR Mixer"},
+       {"HSOL", NULL, "HeadsetL PGA"},
+       {"HSOR", NULL, "HeadsetR PGA"},
+       {"CARKITL", NULL, "CarkitL Mixer"},
+       {"CARKITR", NULL, "CarkitR Mixer"},
+       {"HFL", NULL, "HandsfreeL PGA"},
+       {"HFR", NULL, "HandsfreeR PGA"},
+       {"Vibra Route", "Audio", "Vibra Mux"},
+       {"VIBRA", NULL, "Vibra Route"},
 
        /* Capture path */
        {"Analog Left Capture Route", "Main mic", "MAINMIC"},
@@ -1168,18 +1427,22 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"Left1 Analog Loopback", "Switch", "Analog Left Capture Route"},
        {"Right2 Analog Loopback", "Switch", "Analog Right Capture Route"},
        {"Left2 Analog Loopback", "Switch", "Analog Left Capture Route"},
+       {"Voice Analog Loopback", "Switch", "Analog Left Capture Route"},
 
        {"Analog R1 Playback Mixer", NULL, "Right1 Analog Loopback"},
        {"Analog L1 Playback Mixer", NULL, "Left1 Analog Loopback"},
        {"Analog R2 Playback Mixer", NULL, "Right2 Analog Loopback"},
        {"Analog L2 Playback Mixer", NULL, "Left2 Analog Loopback"},
+       {"Analog Voice Playback Mixer", NULL, "Voice Analog Loopback"},
 
        /* Digital bypass routes */
        {"Right Digital Loopback", "Volume", "TX1 Capture Route"},
        {"Left Digital Loopback", "Volume", "TX1 Capture Route"},
+       {"Voice Digital Loopback", "Volume", "TX2 Capture Route"},
 
-       {"Analog R2 Playback Mixer", NULL, "Right Digital Loopback"},
-       {"Analog L2 Playback Mixer", NULL, "Left Digital Loopback"},
+       {"Digital R2 Playback Mixer", NULL, "Right Digital Loopback"},
+       {"Digital L2 Playback Mixer", NULL, "Left Digital Loopback"},
+       {"Digital Voice Playback Mixer", NULL, "Voice Digital Loopback"},
 
 };
 
@@ -1226,6 +1489,58 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
+static void twl4030_constraints(struct twl4030_priv *twl4030,
+                               struct snd_pcm_substream *mst_substream)
+{
+       struct snd_pcm_substream *slv_substream;
+
+       /* Pick the stream, which need to be constrained */
+       if (mst_substream == twl4030->master_substream)
+               slv_substream = twl4030->slave_substream;
+       else if (mst_substream == twl4030->slave_substream)
+               slv_substream = twl4030->master_substream;
+       else /* This should not happen.. */
+               return;
+
+       /* Set the constraints according to the already configured stream */
+       snd_pcm_hw_constraint_minmax(slv_substream->runtime,
+                               SNDRV_PCM_HW_PARAM_RATE,
+                               twl4030->rate,
+                               twl4030->rate);
+
+       snd_pcm_hw_constraint_minmax(slv_substream->runtime,
+                               SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+                               twl4030->sample_bits,
+                               twl4030->sample_bits);
+
+       snd_pcm_hw_constraint_minmax(slv_substream->runtime,
+                               SNDRV_PCM_HW_PARAM_CHANNELS,
+                               twl4030->channels,
+                               twl4030->channels);
+}
+
+/* In case of 4 channel mode, the RX1 L/R for playback and the TX2 L/R for
+ * capture has to be enabled/disabled. */
+static void twl4030_tdm_enable(struct snd_soc_codec *codec, int direction,
+                               int enable)
+{
+       u8 reg, mask;
+
+       reg = twl4030_read_reg_cache(codec, TWL4030_REG_OPTION);
+
+       if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+               mask = TWL4030_ARXL1_VRX_EN | TWL4030_ARXR1_EN;
+       else
+               mask = TWL4030_ATXL2_VTXL_EN | TWL4030_ATXR2_VTXR_EN;
+
+       if (enable)
+               reg |= mask;
+       else
+               reg &= ~mask;
+
+       twl4030_write(codec, TWL4030_REG_OPTION, reg);
+}
+
 static int twl4030_startup(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
@@ -1234,26 +1549,25 @@ static int twl4030_startup(struct snd_pcm_substream *substream,
        struct snd_soc_codec *codec = socdev->card->codec;
        struct twl4030_priv *twl4030 = codec->private_data;
 
-       /* If we already have a playback or capture going then constrain
-        * this substream to match it.
-        */
        if (twl4030->master_substream) {
-               struct snd_pcm_runtime *master_runtime;
-               master_runtime = twl4030->master_substream->runtime;
-
-               snd_pcm_hw_constraint_minmax(substream->runtime,
-                                            SNDRV_PCM_HW_PARAM_RATE,
-                                            master_runtime->rate,
-                                            master_runtime->rate);
-
-               snd_pcm_hw_constraint_minmax(substream->runtime,
-                                            SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
-                                            master_runtime->sample_bits,
-                                            master_runtime->sample_bits);
-
                twl4030->slave_substream = substream;
-       } else
+               /* The DAI has one configuration for playback and capture, so
+                * if the DAI has been already configured then constrain this
+                * substream to match it. */
+               if (twl4030->configured)
+                       twl4030_constraints(twl4030, twl4030->master_substream);
+       } else {
+               if (!(twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE) &
+                       TWL4030_OPTION_1)) {
+                       /* In option2 4 channel is not supported, set the
+                        * constraint for the first stream for channels, the
+                        * second stream will 'inherit' this cosntraint */
+                       snd_pcm_hw_constraint_minmax(substream->runtime,
+                                               SNDRV_PCM_HW_PARAM_CHANNELS,
+                                               2, 2);
+               }
                twl4030->master_substream = substream;
+       }
 
        return 0;
 }
@@ -1270,6 +1584,17 @@ static void twl4030_shutdown(struct snd_pcm_substream *substream,
                twl4030->master_substream = twl4030->slave_substream;
 
        twl4030->slave_substream = NULL;
+
+       /* If all streams are closed, or the remaining stream has not yet
+        * been configured than set the DAI as not configured. */
+       if (!twl4030->master_substream)
+               twl4030->configured = 0;
+        else if (!twl4030->master_substream->runtime->channels)
+               twl4030->configured = 0;
+
+        /* If the closing substream had 4 channel, do the necessary cleanup */
+       if (substream->runtime->channels == 4)
+               twl4030_tdm_enable(codec, substream->stream, 0);
 }
 
 static int twl4030_hw_params(struct snd_pcm_substream *substream,
@@ -1282,8 +1607,24 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
        struct twl4030_priv *twl4030 = codec->private_data;
        u8 mode, old_mode, format, old_format;
 
-       if (substream == twl4030->slave_substream)
-               /* Ignoring hw_params for slave substream */
+        /* If the substream has 4 channel, do the necessary setup */
+       if (params_channels(params) == 4) {
+               u8 format, mode;
+
+               format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF);
+               mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE);
+
+               /* Safety check: are we in the correct operating mode and
+                * the interface is in TDM mode? */
+               if ((mode & TWL4030_OPTION_1) &&
+                   ((format & TWL4030_AIF_FORMAT) == TWL4030_AIF_FORMAT_TDM))
+                       twl4030_tdm_enable(codec, substream->stream, 1);
+               else
+                       return -EINVAL;
+       }
+
+       if (twl4030->configured)
+               /* Ignoring hw_params for already configured DAI */
                return 0;
 
        /* bit rate */
@@ -1363,6 +1704,21 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
                /* set CODECPDZ afterwards */
                twl4030_codec_enable(codec, 1);
        }
+
+       /* Store the important parameters for the DAI configuration and set
+        * the DAI as configured */
+       twl4030->configured = 1;
+       twl4030->rate = params_rate(params);
+       twl4030->sample_bits = hw_param_interval(params,
+                                       SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min;
+       twl4030->channels = params_channels(params);
+
+       /* If both playback and capture streams are open, and one of them
+        * is setting the hw parameters right now (since we are here), set
+        * constraints to the other stream to match the current one. */
+       if (twl4030->slave_substream)
+               twl4030_constraints(twl4030, substream);
+
        return 0;
 }
 
@@ -1370,17 +1726,21 @@ static int twl4030_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 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",
@@ -1424,6 +1784,9 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
        case SND_SOC_DAIFMT_I2S:
                format |= TWL4030_AIF_FORMAT_CODEC;
                break;
+       case SND_SOC_DAIFMT_DSP_A:
+               format |= TWL4030_AIF_FORMAT_TDM;
+               break;
        default:
                return -EINVAL;
        }
@@ -1443,6 +1806,180 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
        return 0;
 }
 
+/* In case of voice mode, the RX1 L(VRX) for downlink and the TX2 L/R
+ * (VTXL, VTXR) for uplink has to be enabled/disabled. */
+static void twl4030_voice_enable(struct snd_soc_codec *codec, int direction,
+                               int enable)
+{
+       u8 reg, mask;
+
+       reg = twl4030_read_reg_cache(codec, TWL4030_REG_OPTION);
+
+       if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+               mask = TWL4030_ARXL1_VRX_EN;
+       else
+               mask = TWL4030_ATXL2_VTXL_EN | TWL4030_ATXR2_VTXR_EN;
+
+       if (enable)
+               reg |= mask;
+       else
+               reg &= ~mask;
+
+       twl4030_write(codec, TWL4030_REG_OPTION, reg);
+}
+
+static int twl4030_voice_startup(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;
+       u8 infreq;
+       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");
+               return -EINVAL;
+       }
+
+       /* If the codec mode is not option2, the voice PCM interface is not
+        * avilable.
+        */
+       mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE)
+               & TWL4030_OPT_MODE;
+
+       if (mode != TWL4030_OPTION_2) {
+               printk(KERN_ERR "TWL4030 voice startup: "
+                       "the codec mode is not option2\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void twl4030_voice_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;
+
+       /* Enable voice digital filters */
+       twl4030_voice_enable(codec, substream->stream, 0);
+}
+
+static int twl4030_voice_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;
+       u8 old_mode, mode;
+
+       /* Enable voice digital filters */
+       twl4030_voice_enable(codec, substream->stream, 1);
+
+       /* bit rate */
+       old_mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE)
+               & ~(TWL4030_CODECPDZ);
+       mode = old_mode;
+
+       switch (params_rate(params)) {
+       case 8000:
+               mode &= ~(TWL4030_SEL_16K);
+               break;
+       case 16000:
+               mode |= TWL4030_SEL_16K;
+               break;
+       default:
+               printk(KERN_ERR "TWL4030 voice hw params: unknown rate %d\n",
+                       params_rate(params));
+               return -EINVAL;
+       }
+
+       if (mode != old_mode) {
+               /* change rate and set CODECPDZ */
+               twl4030_codec_enable(codec, 0);
+               twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
+               twl4030_codec_enable(codec, 1);
+       }
+
+       return 0;
+}
+
+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;
+
+       switch (freq) {
+       case 26000000:
+               infreq = TWL4030_APLL_INFREQ_26000KHZ;
+               break;
+       default:
+               printk(KERN_ERR "TWL4030 voice set sysclk: unknown rate %d\n",
+                       freq);
+               return -EINVAL;
+       }
+
+       infreq |= TWL4030_APLL_EN;
+       twl4030_write(codec, TWL4030_REG_APLL_CTL, infreq);
+
+       return 0;
+}
+
+static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
+               unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u8 old_format, format;
+
+       /* get format */
+       old_format = twl4030_read_reg_cache(codec, TWL4030_REG_VOICE_IF);
+       format = old_format;
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFM:
+               format &= ~(TWL4030_VIF_SLAVE_EN);
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               format |= TWL4030_VIF_SLAVE_EN;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* clock inversion */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_IB_NF:
+               format &= ~(TWL4030_VIF_FORMAT);
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               format |= TWL4030_VIF_FORMAT;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (format != old_format) {
+               /* change format and set CODECPDZ */
+               twl4030_codec_enable(codec, 0);
+               twl4030_write(codec, TWL4030_REG_VOICE_IF, format);
+               twl4030_codec_enable(codec, 1);
+       }
+
+       return 0;
+}
+
 #define TWL4030_RATES   (SNDRV_PCM_RATE_8000_48000)
 #define TWL4030_FORMATS         (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE)
 
@@ -1454,21 +1991,47 @@ static struct snd_soc_dai_ops twl4030_dai_ops = {
        .set_fmt        = twl4030_set_dai_fmt,
 };
 
-struct snd_soc_dai twl4030_dai = {
+static struct snd_soc_dai_ops twl4030_dai_voice_ops = {
+       .startup        = twl4030_voice_startup,
+       .shutdown       = twl4030_voice_shutdown,
+       .hw_params      = twl4030_voice_hw_params,
+       .set_sysclk     = twl4030_voice_set_dai_sysclk,
+       .set_fmt        = twl4030_voice_set_dai_fmt,
+};
+
+struct snd_soc_dai twl4030_dai[] = {
+{
        .name = "twl4030",
        .playback = {
-               .stream_name = "Playback",
+               .stream_name = "HiFi Playback",
                .channels_min = 2,
-               .channels_max = 2,
+               .channels_max = 4,
                .rates = TWL4030_RATES | SNDRV_PCM_RATE_96000,
                .formats = TWL4030_FORMATS,},
        .capture = {
                .stream_name = "Capture",
                .channels_min = 2,
-               .channels_max = 2,
+               .channels_max = 4,
                .rates = TWL4030_RATES,
                .formats = TWL4030_FORMATS,},
        .ops = &twl4030_dai_ops,
+},
+{
+       .name = "twl4030 Voice",
+       .playback = {
+               .stream_name = "Voice Playback",
+               .channels_min = 1,
+               .channels_max = 1,
+               .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+       .ops = &twl4030_dai_voice_ops,
+},
 };
 EXPORT_SYMBOL_GPL(twl4030_dai);
 
@@ -1500,6 +2063,8 @@ static int twl4030_resume(struct platform_device *pdev)
 static int twl4030_init(struct snd_soc_device *socdev)
 {
        struct snd_soc_codec *codec = socdev->card->codec;
+       struct twl4030_setup_data *setup = socdev->codec_data;
+       struct twl4030_priv *twl4030 = codec->private_data;
        int ret = 0;
 
        printk(KERN_INFO "TWL4030 Audio Codec init \n");
@@ -1509,14 +2074,31 @@ static int twl4030_init(struct snd_soc_device *socdev)
        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 = 1;
+       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;
 
+       /* 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;
+
+               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) {
@@ -1604,13 +2186,13 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_twl4030);
 
 static int __init twl4030_modinit(void)
 {
-       return snd_soc_register_dai(&twl4030_dai);
+       return snd_soc_register_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai));
 }
 module_init(twl4030_modinit);
 
 static void __exit twl4030_exit(void)
 {
-       snd_soc_unregister_dai(&twl4030_dai);
+       snd_soc_unregister_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai));
 }
 module_exit(twl4030_exit);
 
index cb63765db1df13a898b6c4380d7afdbf3c50af79..fe5f395d9e4fe8bdcce9b4ca29c82aceecb57a7c 100644 (file)
@@ -92,8 +92,9 @@
 #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
 
-#define TWL4030_CACHEREGNUM    (TWL4030_REG_MISC_SET_2 + 1)
+#define TWL4030_CACHEREGNUM    (TWL4030_REG_SW_SHADOW + 1)
 
 /* Bitfield Definitions */
 
 #define TWL4030_APLL_RATE_44100                0x90
 #define TWL4030_APLL_RATE_48000                0xA0
 #define TWL4030_APLL_RATE_96000                0xE0
-#define TWL4030_SEL_16K                        0x04
+#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_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
 
 #define TWL4030_SMOOTH_ANAVOL_EN       0x02
 #define TWL4030_DIGMIC_LR_SWAP_EN      0x01
 
-extern struct snd_soc_dai twl4030_dai;
+/* TWL4030_REG_SW_SHADOW (0x4A) Fields */
+#define TWL4030_HFL_EN                 0x01
+#define TWL4030_HFR_EN                 0x02
+
+#define TWL4030_DAI_HIFI               0
+#define TWL4030_DAI_VOICE              1
+
+extern struct snd_soc_dai twl4030_dai[2];
 extern struct snd_soc_codec_device soc_codec_dev_twl4030;
 
+struct twl4030_setup_data {
+       unsigned int ramp_delay_value;
+       unsigned int sysclk;
+};
+
 #endif /* End of __TWL4030_AUDIO_H__ */
index ddefb8f80145bb1830253cde7277f3bf6ae50818..269b108e1de612f6aaff359b09b59be3f904abaa 100644 (file)
@@ -101,7 +101,7 @@ static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg,
        pr_debug("%s reg: %02X, value:%02X\n", __func__, reg, value);
 
        if (reg >= UDA134X_REGS_NUM) {
-               printk(KERN_ERR "%s unkown register: reg: %d",
+               printk(KERN_ERR "%s unkown register: reg: %u",
                       __func__, reg);
                return -EINVAL;
        }
@@ -296,7 +296,7 @@ static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
        struct snd_soc_codec *codec = codec_dai->codec;
        struct uda134x_priv *uda134x = codec->private_data;
 
-       pr_debug("%s clk_id: %d, freq: %d, dir: %d\n", __func__,
+       pr_debug("%s clk_id: %d, freq: %u, dir: %d\n", __func__,
                 clk_id, freq, dir);
 
        /* Anything between 256fs*8Khz and 512fs*48Khz should be acceptable
index 0275321ff8ab29840c994bb107c3b54d8529f1aa..e7348d341b761d5870889a97f814f8f5a927b0cd 100644 (file)
@@ -1108,7 +1108,7 @@ static int wm8350_set_fll(struct snd_soc_dai *codec_dai,
        if (ret < 0)
                return ret;
        dev_dbg(wm8350->dev,
-               "FLL in %d FLL out %d N 0x%x K 0x%x div %d ratio %d",
+               "FLL in %u FLL out %u N 0x%x K 0x%x div %d ratio %d",
                freq_in, freq_out, fll_div.n, fll_div.k, fll_div.div,
                fll_div.ratio);
 
index d11bd9288cf9170761e735e2ff4094c52353a437..d088eb4b88bb85ca2ee2d260dc46003ea9e5241e 100644 (file)
@@ -13,6 +13,7 @@
 #define _WM8350_H
 
 #include <sound/soc.h>
+#include <linux/mfd/wm8350/audio.h>
 
 extern struct snd_soc_dai wm8350_dai;
 extern struct snd_soc_codec_device soc_codec_dev_wm8350;
index 510efa6040088a03cc30f39ac8bfd015f8ba74f9..502eefac1ecd797dd02ff8382e31e19f8d8b972b 100644 (file)
@@ -954,7 +954,7 @@ static int fll_factors(struct wm8400_priv *wm8400, struct fll_factors *factors,
                factors->outdiv *= 2;
                if (factors->outdiv > 32) {
                        dev_err(wm8400->wm8400->dev,
-                               "Unsupported FLL output frequency %dHz\n",
+                               "Unsupported FLL output frequency %uHz\n",
                                Fout);
                        return -EINVAL;
                }
@@ -1003,7 +1003,7 @@ static int fll_factors(struct wm8400_priv *wm8400, struct fll_factors *factors,
        factors->k = K / 10;
 
        dev_dbg(wm8400->wm8400->dev,
-               "FLL: Fref=%d Fout=%d N=%x K=%x, FRATIO=%x OUTDIV=%x\n",
+               "FLL: Fref=%u Fout=%u N=%x K=%x, FRATIO=%x OUTDIV=%x\n",
                Fref, Fout,
                factors->n, factors->k, factors->fratio, factors->outdiv);
 
@@ -1473,8 +1473,8 @@ static int wm8400_codec_probe(struct platform_device *dev)
 
        codec = &priv->codec;
        codec->private_data = priv;
-       codec->control_data = dev->dev.driver_data;
-       priv->wm8400 = dev->dev.driver_data;
+       codec->control_data = dev_get_drvdata(&dev->dev);
+       priv->wm8400 = dev_get_drvdata(&dev->dev);
 
        ret = regulator_bulk_get(priv->wm8400->dev,
                                 ARRAY_SIZE(power), &power[0]);
index 6a4cea09c45dbe624ba2941442c68e3fdb5971c2..c8b8dba858907d0ec7d9bc3f64b2a19cc6b876fc 100644 (file)
@@ -298,7 +298,7 @@ static void pll_factors(unsigned int target, unsigned int source)
 
        if ((Ndiv < 6) || (Ndiv > 12))
                printk(KERN_WARNING
-                       "WM8510 N value %d outwith recommended range!d\n",
+                       "WM8510 N value %u outwith recommended range!d\n",
                        Ndiv);
 
        pll_div.n = Ndiv;
index 9f6be3d31ac0a8268473463c39ac6c3066b01b75..86c4b24db8172aa610d283120476440587035c3d 100644 (file)
@@ -415,7 +415,7 @@ static int pll_factors(struct _pll_div *pll_div, unsigned int target,
        unsigned int K, Ndiv, Nmod;
        int i;
 
-       pr_debug("wm8580: PLL %dHz->%dHz\n", source, target);
+       pr_debug("wm8580: PLL %uHz->%uHz\n", source, target);
 
        /* Scale the output frequency up; the PLL should run in the
         * region of 90-100MHz.
@@ -447,7 +447,7 @@ static int pll_factors(struct _pll_div *pll_div, unsigned int target,
 
        if ((Ndiv < 5) || (Ndiv > 13)) {
                printk(KERN_ERR
-                       "WM8580 N=%d outside supported range\n", Ndiv);
+                       "WM8580 N=%u outside supported range\n", Ndiv);
                return -EINVAL;
        }
 
index e043e3f60008b46579e4ae97e411a0df1790e15b..7a205876ef4f0dc4e0982855694c62f2ea5e4def 100644 (file)
@@ -666,14 +666,14 @@ static int __devinit wm8731_spi_probe(struct spi_device *spi)
        codec->hw_write = (hw_write_t)wm8731_spi_write;
        codec->dev = &spi->dev;
 
-       spi->dev.driver_data = wm8731;
+       dev_set_drvdata(&spi->dev, wm8731);
 
        return wm8731_register(wm8731);
 }
 
 static int __devexit wm8731_spi_remove(struct spi_device *spi)
 {
-       struct wm8731_priv *wm8731 = spi->dev.driver_data;
+       struct wm8731_priv *wm8731 = dev_get_drvdata(&spi->dev);
 
        wm8731_unregister(wm8731);
 
index a6e8f3f7f052ee4dc45b8ef4540f4cf31c9f411e..d28eeaceb8573a504f3c7c5471f9f2f296c5618c 100644 (file)
@@ -703,7 +703,7 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target,
 
        if ((Ndiv < 6) || (Ndiv > 12))
                printk(KERN_WARNING
-                       "wm8753: unsupported N = %d\n", Ndiv);
+                       "wm8753: unsupported N = %u\n", Ndiv);
 
        pll_div->n = Ndiv;
        Nmod = target % source;
@@ -1822,14 +1822,14 @@ static int __devinit wm8753_spi_probe(struct spi_device *spi)
        codec->hw_write = (hw_write_t)wm8753_spi_write;
        codec->dev = &spi->dev;
 
-       spi->dev.driver_data = wm8753;
+       dev_set_drvdata(&spi->dev, wm8753);
 
        return wm8753_register(wm8753);
 }
 
 static int __devexit wm8753_spi_remove(struct spi_device *spi)
 {
-       struct wm8753_priv *wm8753 = spi->dev.driver_data;
+       struct wm8753_priv *wm8753 = dev_get_drvdata(&spi->dev);
        wm8753_unregister(wm8753);
        return 0;
 }
index 46c5ea1ff921aea8c3f6be8fd13ed7bd8de1f897..3c78945244b8df516f12f0181f0194a4b1a1b949 100644 (file)
@@ -778,11 +778,11 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
        }
 
        if (target > 100000000)
-               printk(KERN_WARNING "wm8900: FLL rate %d out of range, Fref=%d"
-                      " Fout=%d\n", target, Fref, Fout);
+               printk(KERN_WARNING "wm8900: FLL rate %u out of range, Fref=%u"
+                      " Fout=%u\n", target, Fref, Fout);
        if (div > 32) {
                printk(KERN_ERR "wm8900: Invalid FLL division rate %u, "
-                      "Fref=%d, Fout=%d, target=%d\n",
+                      "Fref=%u, Fout=%u, target=%u\n",
                       div, Fref, Fout, target);
                return -EINVAL;
        }
index 8cf571f1a803d3ae7b1b1e561aedb01470cc19dd..d8a9222fbf745c53077bd3a5f12e89c3f70bded0 100644 (file)
@@ -217,7 +217,6 @@ struct wm8903_priv {
        int sysclk;
 
        /* Reference counts */
-       int charge_pump_users;
        int class_w_users;
        int playback_active;
        int capture_active;
@@ -373,6 +372,15 @@ static void wm8903_reset(struct snd_soc_codec *codec)
 #define WM8903_OUTPUT_INT   0x2
 #define WM8903_OUTPUT_IN    0x1
 
+static int wm8903_cp_event(struct snd_soc_dapm_widget *w,
+                          struct snd_kcontrol *kcontrol, int event)
+{
+       WARN_ON(event != SND_SOC_DAPM_POST_PMU);
+       mdelay(4);
+
+       return 0;
+}
+
 /*
  * Event for headphone and line out amplifier power changes.  Special
  * power up/down sequences are required in order to maximise pop/click
@@ -382,19 +390,20 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w,
                               struct snd_kcontrol *kcontrol, int event)
 {
        struct snd_soc_codec *codec = w->codec;
-       struct wm8903_priv *wm8903 = codec->private_data;
-       struct i2c_client *i2c = codec->control_data;
        u16 val;
        u16 reg;
+       u16 dcs_reg;
+       u16 dcs_bit;
        int shift;
-       u16 cp_reg = wm8903_read(codec, WM8903_CHARGE_PUMP_0);
 
        switch (w->reg) {
        case WM8903_POWER_MANAGEMENT_2:
                reg = WM8903_ANALOGUE_HP_0;
+               dcs_bit = 0 + w->shift;
                break;
        case WM8903_POWER_MANAGEMENT_3:
                reg = WM8903_ANALOGUE_LINEOUT_0;
+               dcs_bit = 2 + w->shift;
                break;
        default:
                BUG();
@@ -419,18 +428,6 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w,
                /* Short the output */
                val &= ~(WM8903_OUTPUT_SHORT << shift);
                wm8903_write(codec, reg, val);
-
-               wm8903->charge_pump_users++;
-
-               dev_dbg(&i2c->dev, "Charge pump use count now %d\n",
-                       wm8903->charge_pump_users);
-
-               if (wm8903->charge_pump_users == 1) {
-                       dev_dbg(&i2c->dev, "Enabling charge pump\n");
-                       wm8903_write(codec, WM8903_CHARGE_PUMP_0,
-                                    cp_reg | WM8903_CP_ENA);
-                       mdelay(4);
-               }
        }
 
        if (event & SND_SOC_DAPM_POST_PMU) {
@@ -446,6 +443,11 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w,
                val |= (WM8903_OUTPUT_OUT << shift);
                wm8903_write(codec, reg, val);
 
+               /* Enable the DC servo */
+               dcs_reg = wm8903_read(codec, WM8903_DC_SERVO_0);
+               dcs_reg |= dcs_bit;
+               wm8903_write(codec, WM8903_DC_SERVO_0, dcs_reg);
+
                /* Remove the short */
                val |= (WM8903_OUTPUT_SHORT << shift);
                wm8903_write(codec, reg, val);
@@ -458,25 +460,17 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w,
                val &= ~(WM8903_OUTPUT_SHORT << shift);
                wm8903_write(codec, reg, val);
 
+               /* Disable the DC servo */
+               dcs_reg = wm8903_read(codec, WM8903_DC_SERVO_0);
+               dcs_reg &= ~dcs_bit;
+               wm8903_write(codec, WM8903_DC_SERVO_0, dcs_reg);
+
                /* Then disable the intermediate and output stages */
                val &= ~((WM8903_OUTPUT_OUT | WM8903_OUTPUT_INT |
                          WM8903_OUTPUT_IN) << shift);
                wm8903_write(codec, reg, val);
        }
 
-       if (event & SND_SOC_DAPM_POST_PMD) {
-               wm8903->charge_pump_users--;
-
-               dev_dbg(&i2c->dev, "Charge pump use count now %d\n",
-                       wm8903->charge_pump_users);
-
-               if (wm8903->charge_pump_users == 0) {
-                       dev_dbg(&i2c->dev, "Disabling charge pump\n");
-                       wm8903_write(codec, WM8903_CHARGE_PUMP_0,
-                                    cp_reg & ~WM8903_CP_ENA);
-               }
-       }
-
        return 0;
 }
 
@@ -539,6 +533,7 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
 /* ALSA can only do steps of .01dB */
 static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
 
+static const DECLARE_TLV_DB_SCALE(digital_sidetone_tlv, -3600, 300, 0);
 static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
 
 static const DECLARE_TLV_DB_SCALE(drc_tlv_thresh, 0, 75, 0);
@@ -657,6 +652,16 @@ static const struct soc_enum rinput_inv_enum =
        SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 4, 3, rinput_mux_text);
 
 
+static const char *sidetone_text[] = {
+       "None", "Left", "Right"
+};
+
+static const struct soc_enum lsidetone_enum =
+       SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 2, 3, sidetone_text);
+
+static const struct soc_enum rsidetone_enum =
+       SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 0, 3, sidetone_text);
+
 static const struct snd_kcontrol_new wm8903_snd_controls[] = {
 
 /* Input PGAs - No TLV since the scale depends on PGA mode */
@@ -700,6 +705,9 @@ SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8903_ADC_DIGITAL_VOLUME_LEFT,
 SOC_ENUM("ADC Companding Mode", adc_companding),
 SOC_SINGLE("ADC Companding Switch", WM8903_AUDIO_INTERFACE_0, 3, 1, 0),
 
+SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8903_DAC_DIGITAL_0, 4, 8,
+              12, 0, digital_sidetone_tlv),
+
 /* DAC */
 SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8903_DAC_DIGITAL_VOLUME_LEFT,
                 WM8903_DAC_DIGITAL_VOLUME_RIGHT, 1, 120, 0, digital_tlv),
@@ -762,6 +770,12 @@ static const struct snd_kcontrol_new rinput_mux =
 static const struct snd_kcontrol_new rinput_inv_mux =
        SOC_DAPM_ENUM("Right Inverting Input Mux", rinput_inv_enum);
 
+static const struct snd_kcontrol_new lsidetone_mux =
+       SOC_DAPM_ENUM("DACL Sidetone Mux", lsidetone_enum);
+
+static const struct snd_kcontrol_new rsidetone_mux =
+       SOC_DAPM_ENUM("DACR Sidetone Mux", rsidetone_enum);
+
 static const struct snd_kcontrol_new left_output_mixer[] = {
 SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_LEFT_MIX_0, 3, 1, 0),
 SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_LEFT_MIX_0, 2, 1, 0),
@@ -828,6 +842,9 @@ SND_SOC_DAPM_PGA("Right Input PGA", WM8903_POWER_MANAGEMENT_0, 0, 0, NULL, 0),
 SND_SOC_DAPM_ADC("ADCL", "Left HiFi Capture", WM8903_POWER_MANAGEMENT_6, 1, 0),
 SND_SOC_DAPM_ADC("ADCR", "Right HiFi Capture", WM8903_POWER_MANAGEMENT_6, 0, 0),
 
+SND_SOC_DAPM_MUX("DACL Sidetone", SND_SOC_NOPM, 0, 0, &lsidetone_mux),
+SND_SOC_DAPM_MUX("DACR Sidetone", SND_SOC_NOPM, 0, 0, &rsidetone_mux),
+
 SND_SOC_DAPM_DAC("DACL", "Left Playback", WM8903_POWER_MANAGEMENT_6, 3, 0),
 SND_SOC_DAPM_DAC("DACR", "Right Playback", WM8903_POWER_MANAGEMENT_6, 2, 0),
 
@@ -844,26 +861,29 @@ SND_SOC_DAPM_MIXER("Right Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 0, 0,
 SND_SOC_DAPM_PGA_E("Left Headphone Output PGA", WM8903_POWER_MANAGEMENT_2,
                   1, 0, NULL, 0, wm8903_output_event,
                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+                  SND_SOC_DAPM_PRE_PMD),
 SND_SOC_DAPM_PGA_E("Right Headphone Output PGA", WM8903_POWER_MANAGEMENT_2,
                   0, 0, NULL, 0, wm8903_output_event,
                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+                  SND_SOC_DAPM_PRE_PMD),
 
 SND_SOC_DAPM_PGA_E("Left Line Output PGA", WM8903_POWER_MANAGEMENT_3, 1, 0,
                   NULL, 0, wm8903_output_event,
                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+                  SND_SOC_DAPM_PRE_PMD),
 SND_SOC_DAPM_PGA_E("Right Line Output PGA", WM8903_POWER_MANAGEMENT_3, 0, 0,
                   NULL, 0, wm8903_output_event,
                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+                  SND_SOC_DAPM_PRE_PMD),
 
 SND_SOC_DAPM_PGA("Left Speaker PGA", WM8903_POWER_MANAGEMENT_5, 1, 0,
                 NULL, 0),
 SND_SOC_DAPM_PGA("Right Speaker PGA", WM8903_POWER_MANAGEMENT_5, 0, 0,
                 NULL, 0),
 
+SND_SOC_DAPM_SUPPLY("Charge Pump", WM8903_CHARGE_PUMP_0, 0, 0,
+                   wm8903_cp_event, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8903_CLOCK_RATES_2, 1, 0, NULL, 0),
 };
 
 static const struct snd_soc_dapm_route intercon[] = {
@@ -909,7 +929,19 @@ static const struct snd_soc_dapm_route intercon[] = {
        { "Right Input PGA", NULL, "Right Input Mode Mux" },
 
        { "ADCL", NULL, "Left Input PGA" },
+       { "ADCL", NULL, "CLK_DSP" },
        { "ADCR", NULL, "Right Input PGA" },
+       { "ADCR", NULL, "CLK_DSP" },
+
+       { "DACL Sidetone", "Left", "ADCL" },
+       { "DACL Sidetone", "Right", "ADCR" },
+       { "DACR Sidetone", "Left", "ADCL" },
+       { "DACR Sidetone", "Right", "ADCR" },
+
+       { "DACL", NULL, "DACL Sidetone" },
+       { "DACL", NULL, "CLK_DSP" },
+       { "DACR", NULL, "DACR Sidetone" },
+       { "DACR", NULL, "CLK_DSP" },
 
        { "Left Output Mixer", "Left Bypass Switch", "Left Input PGA" },
        { "Left Output Mixer", "Right Bypass Switch", "Right Input PGA" },
@@ -951,6 +983,11 @@ static const struct snd_soc_dapm_route intercon[] = {
 
        { "ROP", NULL, "Right Speaker PGA" },
        { "RON", NULL, "Right Speaker PGA" },
+
+       { "Left Headphone Output PGA", NULL, "Charge Pump" },
+       { "Right Headphone Output PGA", NULL, "Charge Pump" },
+       { "Left Line Output PGA", NULL, "Charge Pump" },
+       { "Right Line Output PGA", NULL, "Charge Pump" },
 };
 
 static int wm8903_add_widgets(struct snd_soc_codec *codec)
@@ -985,6 +1022,11 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec,
                        wm8903_write(codec, WM8903_CLOCK_RATES_2,
                                     WM8903_CLK_SYS_ENA);
 
+                       /* Change DC servo dither level in startup sequence */
+                       wm8903_write(codec, WM8903_WRITE_SEQUENCER_0, 0x11);
+                       wm8903_write(codec, WM8903_WRITE_SEQUENCER_1, 0x1257);
+                       wm8903_write(codec, WM8903_WRITE_SEQUENCER_2, 0x2);
+
                        wm8903_run_sequence(codec, 0);
                        wm8903_sync_reg_cache(codec, codec->reg_cache);
 
@@ -1277,14 +1319,8 @@ static int wm8903_startup(struct snd_pcm_substream *substream,
        if (wm8903->master_substream) {
                master_runtime = wm8903->master_substream->runtime;
 
-               dev_dbg(&i2c->dev, "Constraining to %d bits at %dHz\n",
-                       master_runtime->sample_bits,
-                       master_runtime->rate);
-
-               snd_pcm_hw_constraint_minmax(substream->runtime,
-                                            SNDRV_PCM_HW_PARAM_RATE,
-                                            master_runtime->rate,
-                                            master_runtime->rate);
+               dev_dbg(&i2c->dev, "Constraining to %d bits\n",
+                       master_runtime->sample_bits);
 
                snd_pcm_hw_constraint_minmax(substream->runtime,
                                             SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
@@ -1523,6 +1559,7 @@ struct snd_soc_dai wm8903_dai = {
                 .formats = WM8903_FORMATS,
         },
        .ops = &wm8903_dai_ops,
+       .symmetric_rates = 1,
 };
 EXPORT_SYMBOL_GPL(wm8903_dai);
 
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
new file mode 100644 (file)
index 0000000..b8e17d6
--- /dev/null
@@ -0,0 +1,955 @@
+/*
+ * wm8940.c  --  WM8940 ALSA Soc Audio driver
+ *
+ * Author: Jonathan Cameron <jic23@cam.ac.uk>
+ *
+ * Based on wm8510.c
+ *    Copyright  2006 Wolfson Microelectronics PLC.
+ *    Author:  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 version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Not currently handled:
+ * Notch filter control
+ * AUXMode (inverting vs mixer)
+ * No means to obtain current gain if alc enabled.
+ * No use made of gpio
+ * Fast VMID discharge for power down
+ * Soft Start
+ * DLR and ALR Swaps not enabled
+ * Digital Sidetone not supported
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.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/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8940.h"
+
+struct wm8940_priv {
+       unsigned int sysclk;
+       u16 reg_cache[WM8940_CACHEREGNUM];
+       struct snd_soc_codec codec;
+};
+
+static u16 wm8940_reg_defaults[] = {
+       0x8940, /* Soft Reset */
+       0x0000, /* Power 1 */
+       0x0000, /* Power 2 */
+       0x0000, /* Power 3 */
+       0x0010, /* Interface Control */
+       0x0000, /* Companding Control */
+       0x0140, /* Clock Control */
+       0x0000, /* Additional Controls */
+       0x0000, /* GPIO Control */
+       0x0002, /* Auto Increment Control */
+       0x0000, /* DAC Control */
+       0x00FF, /* DAC Volume */
+       0,
+       0,
+       0x0100, /* ADC Control */
+       0x00FF, /* ADC Volume */
+       0x0000, /* Notch Filter 1 Control 1 */
+       0x0000, /* Notch Filter 1 Control 2 */
+       0x0000, /* Notch Filter 2 Control 1 */
+       0x0000, /* Notch Filter 2 Control 2 */
+       0x0000, /* Notch Filter 3 Control 1 */
+       0x0000, /* Notch Filter 3 Control 2 */
+       0x0000, /* Notch Filter 4 Control 1 */
+       0x0000, /* Notch Filter 4 Control 2 */
+       0x0032, /* DAC Limit Control 1 */
+       0x0000, /* DAC Limit Control 2 */
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0x0038, /* ALC Control 1 */
+       0x000B, /* ALC Control 2 */
+       0x0032, /* ALC Control 3 */
+       0x0000, /* Noise Gate */
+       0x0041, /* PLLN */
+       0x000C, /* PLLK1 */
+       0x0093, /* PLLK2 */
+       0x00E9, /* PLLK3 */
+       0,
+       0,
+       0x0030, /* ALC Control 4 */
+       0,
+       0x0002, /* Input Control */
+       0x0050, /* PGA Gain */
+       0,
+       0x0002, /* ADC Boost Control */
+       0,
+       0x0002, /* Output Control */
+       0x0000, /* Speaker Mixer Control */
+       0,
+       0,
+       0,
+       0x0079, /* Speaker Volume */
+       0,
+       0x0000, /* Mono Mixer Control */
+};
+
+static inline unsigned int wm8940_read_reg_cache(struct snd_soc_codec *codec,
+                                                unsigned int reg)
+{
+       u16 *cache = codec->reg_cache;
+
+       if (reg >= ARRAY_SIZE(wm8940_reg_defaults))
+               return -1;
+
+       return cache[reg];
+}
+
+static inline int wm8940_write_reg_cache(struct snd_soc_codec *codec,
+                                         u16 reg, unsigned int value)
+{
+       u16 *cache = codec->reg_cache;
+
+       if (reg >= ARRAY_SIZE(wm8940_reg_defaults))
+               return -1;
+
+       cache[reg] = value;
+
+       return 0;
+}
+
+static int wm8940_write(struct snd_soc_codec *codec, unsigned int reg,
+                       unsigned int value)
+{
+       int ret;
+       u8 data[3] = { reg,
+                      (value & 0xff00) >> 8,
+                      (value & 0x00ff)
+       };
+
+       wm8940_write_reg_cache(codec, reg, value);
+
+       ret = codec->hw_write(codec->control_data, data, 3);
+
+       if (ret < 0)
+               return ret;
+       else if (ret != 3)
+               return -EIO;
+       return 0;
+}
+
+static const char *wm8940_companding[] = { "Off", "NC", "u-law", "A-law" };
+static const struct soc_enum wm8940_adc_companding_enum
+= SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 1, 4, wm8940_companding);
+static const struct soc_enum wm8940_dac_companding_enum
+= SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 3, 4, wm8940_companding);
+
+static const char *wm8940_alc_mode_text[] = {"ALC", "Limiter"};
+static const struct soc_enum wm8940_alc_mode_enum
+= SOC_ENUM_SINGLE(WM8940_ALC3, 8, 2, wm8940_alc_mode_text);
+
+static const char *wm8940_mic_bias_level_text[] = {"0.9", "0.65"};
+static const struct soc_enum wm8940_mic_bias_level_enum
+= SOC_ENUM_SINGLE(WM8940_INPUTCTL, 8, 2, wm8940_mic_bias_level_text);
+
+static const char *wm8940_filter_mode_text[] = {"Audio", "Application"};
+static const struct soc_enum wm8940_filter_mode_enum
+= SOC_ENUM_SINGLE(WM8940_ADC, 7, 2, wm8940_filter_mode_text);
+
+static DECLARE_TLV_DB_SCALE(wm8940_spk_vol_tlv, -5700, 100, 1);
+static DECLARE_TLV_DB_SCALE(wm8940_att_tlv, -1000, 1000, 0);
+static DECLARE_TLV_DB_SCALE(wm8940_pga_vol_tlv, -1200, 75, 0);
+static DECLARE_TLV_DB_SCALE(wm8940_alc_min_tlv, -1200, 600, 0);
+static DECLARE_TLV_DB_SCALE(wm8940_alc_max_tlv, 675, 600, 0);
+static DECLARE_TLV_DB_SCALE(wm8940_alc_tar_tlv, -2250, 50, 0);
+static DECLARE_TLV_DB_SCALE(wm8940_lim_boost_tlv, 0, 100, 0);
+static DECLARE_TLV_DB_SCALE(wm8940_lim_thresh_tlv, -600, 100, 0);
+static DECLARE_TLV_DB_SCALE(wm8940_adc_tlv, -12750, 50, 1);
+static DECLARE_TLV_DB_SCALE(wm8940_capture_boost_vol_tlv, 0, 2000, 0);
+
+static const struct snd_kcontrol_new wm8940_snd_controls[] = {
+       SOC_SINGLE("Digital Loopback Switch", WM8940_COMPANDINGCTL,
+                  6, 1, 0),
+       SOC_ENUM("DAC Companding", wm8940_dac_companding_enum),
+       SOC_ENUM("ADC Companding", wm8940_adc_companding_enum),
+
+       SOC_ENUM("ALC Mode", wm8940_alc_mode_enum),
+       SOC_SINGLE("ALC Switch", WM8940_ALC1, 8, 1, 0),
+       SOC_SINGLE_TLV("ALC Capture Max Gain", WM8940_ALC1,
+                      3, 7, 1, wm8940_alc_max_tlv),
+       SOC_SINGLE_TLV("ALC Capture Min Gain", WM8940_ALC1,
+                      0, 7, 0, wm8940_alc_min_tlv),
+       SOC_SINGLE_TLV("ALC Capture Target", WM8940_ALC2,
+                      0, 14, 0, wm8940_alc_tar_tlv),
+       SOC_SINGLE("ALC Capture Hold", WM8940_ALC2, 4, 10, 0),
+       SOC_SINGLE("ALC Capture Decay", WM8940_ALC3, 4, 10, 0),
+       SOC_SINGLE("ALC Capture Attach", WM8940_ALC3, 0, 10, 0),
+       SOC_SINGLE("ALC ZC Switch", WM8940_ALC4, 1, 1, 0),
+       SOC_SINGLE("ALC Capture Noise Gate Switch", WM8940_NOISEGATE,
+                  3, 1, 0),
+       SOC_SINGLE("ALC Capture Noise Gate Threshold", WM8940_NOISEGATE,
+                  0, 7, 0),
+
+       SOC_SINGLE("DAC Playback Limiter Switch", WM8940_DACLIM1, 8, 1, 0),
+       SOC_SINGLE("DAC Playback Limiter Attack", WM8940_DACLIM1, 0, 9, 0),
+       SOC_SINGLE("DAC Playback Limiter Decay", WM8940_DACLIM1, 4, 11, 0),
+       SOC_SINGLE_TLV("DAC Playback Limiter Threshold", WM8940_DACLIM2,
+                      4, 9, 1, wm8940_lim_thresh_tlv),
+       SOC_SINGLE_TLV("DAC Playback Limiter Boost", WM8940_DACLIM2,
+                      0, 12, 0, wm8940_lim_boost_tlv),
+
+       SOC_SINGLE("Capture PGA ZC Switch", WM8940_PGAGAIN, 7, 1, 0),
+       SOC_SINGLE_TLV("Capture PGA Volume", WM8940_PGAGAIN,
+                      0, 63, 0, wm8940_pga_vol_tlv),
+       SOC_SINGLE_TLV("Digital Playback Volume", WM8940_DACVOL,
+                      0, 255, 0, wm8940_adc_tlv),
+       SOC_SINGLE_TLV("Digital Capture Volume", WM8940_ADCVOL,
+                      0, 255, 0, wm8940_adc_tlv),
+       SOC_ENUM("Mic Bias Level", wm8940_mic_bias_level_enum),
+       SOC_SINGLE_TLV("Capture Boost Volue", WM8940_ADCBOOST,
+                      8, 1, 0, wm8940_capture_boost_vol_tlv),
+       SOC_SINGLE_TLV("Speaker Playback Volume", WM8940_SPKVOL,
+                      0, 63, 0, wm8940_spk_vol_tlv),
+       SOC_SINGLE("Speaker Playback Switch", WM8940_SPKVOL,  6, 1, 1),
+
+       SOC_SINGLE_TLV("Speaker Mixer Line Bypass Volume", WM8940_SPKVOL,
+                      8, 1, 1, wm8940_att_tlv),
+       SOC_SINGLE("Speaker Playback ZC Switch", WM8940_SPKVOL, 7, 1, 0),
+
+       SOC_SINGLE("Mono Out Switch", WM8940_MONOMIX, 6, 1, 1),
+       SOC_SINGLE_TLV("Mono Mixer Line Bypass Volume", WM8940_MONOMIX,
+                      7, 1, 1, wm8940_att_tlv),
+
+       SOC_SINGLE("High Pass Filter Switch", WM8940_ADC, 8, 1, 0),
+       SOC_ENUM("High Pass Filter Mode", wm8940_filter_mode_enum),
+       SOC_SINGLE("High Pass Filter Cut Off", WM8940_ADC, 4, 7, 0),
+       SOC_SINGLE("ADC Inversion Switch", WM8940_ADC, 0, 1, 0),
+       SOC_SINGLE("DAC Inversion Switch", WM8940_DAC, 0, 1, 0),
+       SOC_SINGLE("DAC Auto Mute Switch", WM8940_DAC, 2, 1, 0),
+       SOC_SINGLE("ZC Timeout Clock Switch", WM8940_ADDCNTRL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8940_speaker_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Line Bypass Switch", WM8940_SPKMIX, 1, 1, 0),
+       SOC_DAPM_SINGLE("Aux Playback Switch", WM8940_SPKMIX, 5, 1, 0),
+       SOC_DAPM_SINGLE("PCM Playback Switch", WM8940_SPKMIX, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8940_mono_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Line Bypass Switch", WM8940_MONOMIX, 1, 1, 0),
+       SOC_DAPM_SINGLE("Aux Playback Switch", WM8940_MONOMIX, 2, 1, 0),
+       SOC_DAPM_SINGLE("PCM Playback Switch", WM8940_MONOMIX, 0, 1, 0),
+};
+
+static DECLARE_TLV_DB_SCALE(wm8940_boost_vol_tlv, -1500, 300, 1);
+static const struct snd_kcontrol_new wm8940_input_boost_controls[] = {
+       SOC_DAPM_SINGLE("Mic PGA Switch", WM8940_PGAGAIN, 6, 1, 1),
+       SOC_DAPM_SINGLE_TLV("Aux Volume", WM8940_ADCBOOST,
+                           0, 7, 0, wm8940_boost_vol_tlv),
+       SOC_DAPM_SINGLE_TLV("Mic Volume", WM8940_ADCBOOST,
+                           4, 7, 0, wm8940_boost_vol_tlv),
+};
+
+static const struct snd_kcontrol_new wm8940_micpga_controls[] = {
+       SOC_DAPM_SINGLE("AUX Switch", WM8940_INPUTCTL, 2, 1, 0),
+       SOC_DAPM_SINGLE("MICP Switch", WM8940_INPUTCTL, 0, 1, 0),
+       SOC_DAPM_SINGLE("MICN Switch", WM8940_INPUTCTL, 1, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8940_dapm_widgets[] = {
+       SND_SOC_DAPM_MIXER("Speaker Mixer", WM8940_POWER3, 2, 0,
+                          &wm8940_speaker_mixer_controls[0],
+                          ARRAY_SIZE(wm8940_speaker_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Mono Mixer", WM8940_POWER3, 3, 0,
+                          &wm8940_mono_mixer_controls[0],
+                          ARRAY_SIZE(wm8940_mono_mixer_controls)),
+       SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8940_POWER3, 0, 0),
+
+       SND_SOC_DAPM_PGA("SpkN Out", WM8940_POWER3, 5, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("SpkP Out", WM8940_POWER3, 6, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Mono Out", WM8940_POWER3, 7, 0, NULL, 0),
+       SND_SOC_DAPM_OUTPUT("MONOOUT"),
+       SND_SOC_DAPM_OUTPUT("SPKOUTP"),
+       SND_SOC_DAPM_OUTPUT("SPKOUTN"),
+
+       SND_SOC_DAPM_PGA("Aux Input", WM8940_POWER1, 6, 0, NULL, 0),
+       SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8940_POWER2, 0, 0),
+       SND_SOC_DAPM_MIXER("Mic PGA", WM8940_POWER2, 2, 0,
+                          &wm8940_micpga_controls[0],
+                          ARRAY_SIZE(wm8940_micpga_controls)),
+       SND_SOC_DAPM_MIXER("Boost Mixer", WM8940_POWER2, 4, 0,
+                          &wm8940_input_boost_controls[0],
+                          ARRAY_SIZE(wm8940_input_boost_controls)),
+       SND_SOC_DAPM_MICBIAS("Mic Bias", WM8940_POWER1, 4, 0),
+
+       SND_SOC_DAPM_INPUT("MICN"),
+       SND_SOC_DAPM_INPUT("MICP"),
+       SND_SOC_DAPM_INPUT("AUX"),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       /* Mono output mixer */
+       {"Mono Mixer", "PCM Playback Switch", "DAC"},
+       {"Mono Mixer", "Aux Playback Switch", "Aux Input"},
+       {"Mono Mixer", "Line Bypass Switch", "Boost Mixer"},
+
+       /* Speaker output mixer */
+       {"Speaker Mixer", "PCM Playback Switch", "DAC"},
+       {"Speaker Mixer", "Aux Playback Switch", "Aux Input"},
+       {"Speaker Mixer", "Line Bypass Switch", "Boost Mixer"},
+
+       /* Outputs */
+       {"Mono Out", NULL, "Mono Mixer"},
+       {"MONOOUT", NULL, "Mono Out"},
+       {"SpkN Out", NULL, "Speaker Mixer"},
+       {"SpkP Out", NULL, "Speaker Mixer"},
+       {"SPKOUTN", NULL, "SpkN Out"},
+       {"SPKOUTP", NULL, "SpkP Out"},
+
+       /*  Microphone PGA */
+       {"Mic PGA", "MICN Switch", "MICN"},
+       {"Mic PGA", "MICP Switch", "MICP"},
+       {"Mic PGA", "AUX Switch", "AUX"},
+
+       /* Boost Mixer */
+       {"Boost Mixer", "Mic PGA Switch", "Mic PGA"},
+       {"Boost Mixer", "Mic Volume",  "MICP"},
+       {"Boost Mixer", "Aux Volume", "Aux Input"},
+
+       {"ADC", NULL, "Boost Mixer"},
+};
+
+static int wm8940_add_widgets(struct snd_soc_codec *codec)
+{
+       int ret;
+
+       ret = snd_soc_dapm_new_controls(codec, wm8940_dapm_widgets,
+                                       ARRAY_SIZE(wm8940_dapm_widgets));
+       if (ret)
+               goto error_ret;
+       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;
+}
+
+#define wm8940_reset(c) wm8940_write(c, WM8940_SOFTRESET, 0);
+
+static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                             unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u16 iface = wm8940_read_reg_cache(codec, WM8940_IFACE) & 0xFE67;
+       u16 clk = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0x1fe;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               clk |= 1;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       default:
+               return -EINVAL;
+       }
+       wm8940_write(codec, WM8940_CLOCK, clk);
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               iface |= (2 << 3);
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               iface |= (1 << 3);
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               iface |= (3 << 3);
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               iface |= (3 << 3) | (1 << 7);
+               break;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               iface |= (1 << 7);
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               iface |= (1 << 8);
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               iface |= (1 << 8) | (1 << 7);
+               break;
+       }
+
+       wm8940_write(codec, WM8940_IFACE, iface);
+
+       return 0;
+}
+
+static int wm8940_i2s_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;
+       u16 iface = wm8940_read_reg_cache(codec, WM8940_IFACE) & 0xFD9F;
+       u16 addcntrl = wm8940_read_reg_cache(codec, WM8940_ADDCNTRL) & 0xFFF1;
+       u16 companding =  wm8940_read_reg_cache(codec,
+                                               WM8940_COMPANDINGCTL) & 0xFFDF;
+       int ret;
+
+       /* LoutR control */
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE
+           && params_channels(params) == 2)
+               iface |= (1 << 9);
+
+       switch (params_rate(params)) {
+       case SNDRV_PCM_RATE_8000:
+               addcntrl |= (0x5 << 1);
+               break;
+       case SNDRV_PCM_RATE_11025:
+               addcntrl |= (0x4 << 1);
+               break;
+       case SNDRV_PCM_RATE_16000:
+               addcntrl |= (0x3 << 1);
+               break;
+       case SNDRV_PCM_RATE_22050:
+               addcntrl |= (0x2 << 1);
+               break;
+       case SNDRV_PCM_RATE_32000:
+               addcntrl |= (0x1 << 1);
+               break;
+       case SNDRV_PCM_RATE_44100:
+       case SNDRV_PCM_RATE_48000:
+               break;
+       }
+       ret = wm8940_write(codec, WM8940_ADDCNTRL, addcntrl);
+       if (ret)
+               goto error_ret;
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S8:
+               companding = companding | (1 << 5);
+               break;
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               iface |= (1 << 5);
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               iface |= (2 << 5);
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               iface |= (3 << 5);
+               break;
+       }
+       ret = wm8940_write(codec, WM8940_COMPANDINGCTL, companding);
+       if (ret)
+               goto error_ret;
+       ret = wm8940_write(codec, WM8940_IFACE, iface);
+
+error_ret:
+       return ret;
+}
+
+static int wm8940_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       u16 mute_reg = wm8940_read_reg_cache(codec, WM8940_DAC) & 0xffbf;
+
+       if (mute)
+               mute_reg |= 0x40;
+
+       return wm8940_write(codec, WM8940_DAC, mute_reg);
+}
+
+static int wm8940_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       u16 val;
+       u16 pwr_reg = wm8940_read_reg_cache(codec, WM8940_POWER1) & 0x1F0;
+       int ret = 0;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               /* ensure bufioen and biasen */
+               pwr_reg |= (1 << 2) | (1 << 3);
+               /* Enable thermal shutdown */
+               val = wm8940_read_reg_cache(codec, WM8940_OUTPUTCTL);
+               ret = wm8940_write(codec, WM8940_OUTPUTCTL, val | 0x2);
+               if (ret)
+                       break;
+               /* set vmid to 75k */
+               ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x1);
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               /* ensure bufioen and biasen */
+               pwr_reg |= (1 << 2) | (1 << 3);
+               ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x1);
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               /* ensure bufioen and biasen */
+               pwr_reg |= (1 << 2) | (1 << 3);
+               /* set vmid to 300k for standby */
+               ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x2);
+               break;
+       case SND_SOC_BIAS_OFF:
+               ret = wm8940_write(codec, WM8940_POWER1, pwr_reg);
+               break;
+       }
+
+       return ret;
+}
+
+struct pll_ {
+       unsigned int pre_scale:2;
+       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)
+{
+       unsigned long long Kpart;
+       unsigned int K, Ndiv, Nmod;
+       /* The left shift ist to avoid accuracy loss when right shifting */
+       Ndiv = target / source;
+
+       if (Ndiv > 12) {
+               source <<= 1;
+               /* Multiply by 2 */
+               pll_div.pre_scale = 0;
+               Ndiv = target / source;
+       } else if (Ndiv < 3) {
+               source >>= 2;
+               /* Divide by 4 */
+               pll_div.pre_scale = 3;
+               Ndiv = target / source;
+       } else if (Ndiv < 6) {
+               source >>= 1;
+               /* divide by 2 */
+               pll_div.pre_scale = 2;
+               Ndiv = target / source;
+       } else
+               pll_div.pre_scale = 1;
+
+       if ((Ndiv < 6) || (Ndiv > 12))
+               printk(KERN_WARNING
+                       "WM8940 N value %d outwith recommended range!d\n",
+                       Ndiv);
+
+       pll_div.n = Ndiv;
+       Nmod = target % source;
+       Kpart = FIXED_PLL_SIZE * (long long)Nmod;
+
+       do_div(Kpart, source);
+
+       K = Kpart & 0xFFFFFFFF;
+
+       /* Check if we need to round */
+       if ((K % 10) >= 5)
+               K += 5;
+
+       /* Move down to proper range now rounding is done */
+       K /= 10;
+
+       pll_div.k = K;
+}
+
+/* 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)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u16 reg;
+
+       /* Turn off PLL */
+       reg = wm8940_read_reg_cache(codec, WM8940_POWER1);
+       wm8940_write(codec, WM8940_POWER1, reg & 0x1df);
+
+       if (freq_in == 0 || freq_out == 0) {
+               /* Clock CODEC directly from MCLK */
+               reg = wm8940_read_reg_cache(codec, WM8940_CLOCK);
+               wm8940_write(codec, WM8940_CLOCK, reg & 0x0ff);
+               /* Pll power down */
+               wm8940_write(codec, WM8940_PLLN, (1 << 7));
+               return 0;
+       }
+
+       /* Pll is followed by a frequency divide by 4 */
+       pll_factors(freq_out*4, freq_in);
+       if (pll_div.k)
+               wm8940_write(codec, WM8940_PLLN,
+                            (pll_div.pre_scale << 4) | pll_div.n | (1 << 6));
+       else /* No factional component */
+               wm8940_write(codec, WM8940_PLLN,
+                            (pll_div.pre_scale << 4) | pll_div.n);
+       wm8940_write(codec, WM8940_PLLK1, pll_div.k >> 18);
+       wm8940_write(codec, WM8940_PLLK2, (pll_div.k >> 9) & 0x1ff);
+       wm8940_write(codec, WM8940_PLLK3, pll_div.k & 0x1ff);
+       /* Enable the PLL */
+       reg = wm8940_read_reg_cache(codec, WM8940_POWER1);
+       wm8940_write(codec, WM8940_POWER1, reg | 0x020);
+
+       /* Run CODEC from PLL instead of MCLK */
+       reg = wm8940_read_reg_cache(codec, WM8940_CLOCK);
+       wm8940_write(codec, WM8940_CLOCK, reg | 0x100);
+
+       return 0;
+}
+
+static int wm8940_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 wm8940_priv *wm8940 = codec->private_data;
+
+       switch (freq) {
+       case 11289600:
+       case 12000000:
+       case 12288000:
+       case 16934400:
+       case 18432000:
+               wm8940->sysclk = freq;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int wm8940_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+                                int div_id, int div)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u16 reg;
+       int ret = 0;
+
+       switch (div_id) {
+       case WM8940_BCLKDIV:
+               reg = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0xFFEF3;
+               ret = wm8940_write(codec, WM8940_CLOCK, reg | (div << 2));
+               break;
+       case WM8940_MCLKDIV:
+               reg = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0xFF1F;
+               ret = wm8940_write(codec, WM8940_CLOCK, reg | (div << 5));
+               break;
+       case WM8940_OPCLKDIV:
+               reg = wm8940_read_reg_cache(codec, WM8940_ADDCNTRL) & 0xFFCF;
+               ret = wm8940_write(codec, WM8940_ADDCNTRL, reg | (div << 4));
+               break;
+       }
+       return ret;
+}
+
+#define WM8940_RATES SNDRV_PCM_RATE_8000_48000
+
+#define WM8940_FORMATS (SNDRV_PCM_FMTBIT_S8 |                          \
+                       SNDRV_PCM_FMTBIT_S16_LE |                       \
+                       SNDRV_PCM_FMTBIT_S20_3LE |                      \
+                       SNDRV_PCM_FMTBIT_S24_LE |                       \
+                       SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops wm8940_dai_ops = {
+       .hw_params = wm8940_i2s_hw_params,
+       .set_sysclk = wm8940_set_dai_sysclk,
+       .digital_mute = wm8940_mute,
+       .set_fmt = wm8940_set_dai_fmt,
+       .set_clkdiv = wm8940_set_dai_clkdiv,
+       .set_pll = wm8940_set_dai_pll,
+};
+
+struct snd_soc_dai wm8940_dai = {
+       .name = "WM8940",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = WM8940_RATES,
+               .formats = WM8940_FORMATS,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = WM8940_RATES,
+               .formats = WM8940_FORMATS,
+       },
+       .ops = &wm8940_dai_ops,
+       .symmetric_rates = 1,
+};
+EXPORT_SYMBOL_GPL(wm8940_dai);
+
+static int wm8940_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;
+
+       return wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF);
+}
+
+static int wm8940_resume(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->card->codec;
+       int i;
+       int ret;
+       u8 data[3];
+       u16 *cache = codec->reg_cache;
+
+       /* Sync reg_cache with the hardware
+        * Could use auto incremented writes to speed this up
+        */
+       for (i = 0; i < ARRAY_SIZE(wm8940_reg_defaults); i++) {
+               data[0] = i;
+               data[1] = (cache[i] & 0xFF00) >> 8;
+               data[2] = cache[i] & 0x00FF;
+               ret = codec->hw_write(codec->control_data, data, 3);
+               if (ret < 0)
+                       goto error_ret;
+               else if (ret != 3) {
+                       ret = -EIO;
+                       goto error_ret;
+               }
+       }
+       ret = wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       if (ret)
+               goto error_ret;
+       ret = wm8940_set_bias_level(codec, codec->suspend_bias_level);
+
+error_ret:
+       return ret;
+}
+
+static struct snd_soc_codec *wm8940_codec;
+
+static int wm8940_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec;
+
+       int ret = 0;
+
+       if (wm8940_codec == NULL) {
+               dev_err(&pdev->dev, "Codec device not registered\n");
+               return -ENODEV;
+       }
+
+       socdev->card->codec = wm8940_codec;
+       codec = wm8940_codec;
+
+       mutex_init(&codec->mutex);
+       /* 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;
+       }
+
+       ret = snd_soc_add_controls(codec, wm8940_snd_controls,
+                            ARRAY_SIZE(wm8940_snd_controls));
+       if (ret)
+               goto error_free_pcms;
+       ret = wm8940_add_widgets(codec);
+       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:
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+pcm_err:
+       return ret;
+}
+
+static int wm8940_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_wm8940 = {
+       .probe = wm8940_probe,
+       .remove = wm8940_remove,
+       .suspend = wm8940_suspend,
+       .resume = wm8940_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8940);
+
+static int wm8940_register(struct wm8940_priv *wm8940)
+{
+       struct wm8940_setup_data *pdata = wm8940->codec.dev->platform_data;
+       struct snd_soc_codec *codec = &wm8940->codec;
+       int ret;
+       u16 reg;
+       if (wm8940_codec) {
+               dev_err(codec->dev, "Another WM8940 is registered\n");
+               return -EINVAL;
+       }
+
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       codec->private_data = wm8940;
+       codec->name = "WM8940";
+       codec->owner = THIS_MODULE;
+       codec->read = wm8940_read_reg_cache;
+       codec->write = wm8940_write;
+       codec->bias_level = SND_SOC_BIAS_OFF;
+       codec->set_bias_level = wm8940_set_bias_level;
+       codec->dai = &wm8940_dai;
+       codec->num_dai = 1;
+       codec->reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults);
+       codec->reg_cache = &wm8940->reg_cache;
+
+       memcpy(codec->reg_cache, wm8940_reg_defaults,
+              sizeof(wm8940_reg_defaults));
+
+       ret = wm8940_reset(codec);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to issue reset\n");
+               return ret;
+       }
+
+       wm8940_dai.dev = codec->dev;
+
+       wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       ret = wm8940_write(codec, WM8940_POWER1, 0x180);
+       if (ret < 0)
+               return ret;
+
+       if (!pdata)
+               dev_warn(codec->dev, "No platform data supplied\n");
+       else {
+               reg = wm8940_read_reg_cache(codec, WM8940_OUTPUTCTL);
+               ret = wm8940_write(codec, WM8940_OUTPUTCTL, reg | pdata->vroi);
+               if (ret < 0)
+                       return ret;
+       }
+
+
+       wm8940_codec = codec;
+
+       ret = snd_soc_register_codec(codec);
+       if (ret) {
+               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_register_dai(&wm8940_dai);
+       if (ret) {
+               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+               snd_soc_unregister_codec(codec);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void wm8940_unregister(struct wm8940_priv *wm8940)
+{
+       wm8940_set_bias_level(&wm8940->codec, SND_SOC_BIAS_OFF);
+       snd_soc_unregister_dai(&wm8940_dai);
+       snd_soc_unregister_codec(&wm8940->codec);
+       kfree(wm8940);
+       wm8940_codec = NULL;
+}
+
+static int wm8940_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
+{
+       struct wm8940_priv *wm8940;
+       struct snd_soc_codec *codec;
+
+       wm8940 = kzalloc(sizeof *wm8940, GFP_KERNEL);
+       if (wm8940 == NULL)
+               return -ENOMEM;
+
+       codec = &wm8940->codec;
+       codec->hw_write = (hw_write_t)i2c_master_send;
+       i2c_set_clientdata(i2c, wm8940);
+       codec->control_data = i2c;
+       codec->dev = &i2c->dev;
+
+       return wm8940_register(wm8940);
+}
+
+static int __devexit wm8940_i2c_remove(struct i2c_client *client)
+{
+       struct wm8940_priv *wm8940 = i2c_get_clientdata(client);
+
+       wm8940_unregister(wm8940);
+
+       return 0;
+}
+
+static const struct i2c_device_id wm8940_i2c_id[] = {
+       { "wm8940", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8940_i2c_id);
+
+static struct i2c_driver wm8940_i2c_driver = {
+       .driver = {
+               .name = "WM8940 I2C Codec",
+               .owner = THIS_MODULE,
+       },
+       .probe = wm8940_i2c_probe,
+       .remove = __devexit_p(wm8940_i2c_remove),
+       .id_table = wm8940_i2c_id,
+};
+
+static int __init wm8940_modinit(void)
+{
+       int ret;
+
+       ret = i2c_add_driver(&wm8940_i2c_driver);
+       if (ret)
+               printk(KERN_ERR "Failed to register WM8940 I2C driver: %d\n",
+                      ret);
+       return ret;
+}
+module_init(wm8940_modinit);
+
+static void __exit wm8940_exit(void)
+{
+       i2c_del_driver(&wm8940_i2c_driver);
+}
+module_exit(wm8940_exit);
+
+MODULE_DESCRIPTION("ASoC WM8940 driver");
+MODULE_AUTHOR("Jonathan Cameron");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8940.h b/sound/soc/codecs/wm8940.h
new file mode 100644 (file)
index 0000000..8410eed
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * wm8940.h -- WM8940 Soc Audio driver
+ *
+ * This 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 _WM8940_H
+#define _WM8940_H
+
+struct wm8940_setup_data {
+       /* Vref to analogue output resistance */
+#define WM8940_VROI_1K 0
+#define WM8940_VROI_30K 1
+       unsigned int vroi:1;
+};
+extern struct snd_soc_dai wm8940_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8940;
+
+/* WM8940 register space */
+#define WM8940_SOFTRESET       0x00
+#define WM8940_POWER1          0x01
+#define WM8940_POWER2          0x02
+#define WM8940_POWER3          0x03
+#define WM8940_IFACE           0x04
+#define WM8940_COMPANDINGCTL   0x05
+#define WM8940_CLOCK           0x06
+#define WM8940_ADDCNTRL                0x07
+#define WM8940_GPIO            0x08
+#define WM8940_CTLINT          0x09
+#define WM8940_DAC             0x0A
+#define WM8940_DACVOL          0x0B
+
+#define WM8940_ADC             0x0E
+#define WM8940_ADCVOL          0x0F
+#define WM8940_NOTCH1          0x10
+#define WM8940_NOTCH2          0x11
+#define WM8940_NOTCH3          0x12
+#define WM8940_NOTCH4          0x13
+#define WM8940_NOTCH5          0x14
+#define WM8940_NOTCH6          0x15
+#define WM8940_NOTCH7          0x16
+#define WM8940_NOTCH8          0x17
+#define WM8940_DACLIM1         0x18
+#define WM8940_DACLIM2         0x19
+
+#define WM8940_ALC1            0x20
+#define WM8940_ALC2            0x21
+#define WM8940_ALC3            0x22
+#define WM8940_NOISEGATE       0x23
+#define WM8940_PLLN            0x24
+#define WM8940_PLLK1           0x25
+#define WM8940_PLLK2           0x26
+#define WM8940_PLLK3           0x27
+
+#define WM8940_ALC4            0x2A
+
+#define WM8940_INPUTCTL                0x2C
+#define WM8940_PGAGAIN         0x2D
+
+#define WM8940_ADCBOOST                0x2F
+
+#define WM8940_OUTPUTCTL       0x31
+#define WM8940_SPKMIX          0x32
+
+#define WM8940_SPKVOL          0x36
+
+#define WM8940_MONOMIX         0x38
+
+#define WM8940_CACHEREGNUM  0x57
+
+
+/* Clock divider Id's */
+#define WM8940_BCLKDIV 0
+#define WM8940_MCLKDIV 1
+#define WM8940_OPCLKDIV 2
+
+/* MCLK clock dividers */
+#define WM8940_MCLKDIV_1       0
+#define WM8940_MCLKDIV_1_5     1
+#define WM8940_MCLKDIV_2       2
+#define WM8940_MCLKDIV_3       3
+#define WM8940_MCLKDIV_4       4
+#define WM8940_MCLKDIV_6       5
+#define WM8940_MCLKDIV_8       6
+#define WM8940_MCLKDIV_12      7
+
+/* BCLK clock dividers */
+#define WM8940_BCLKDIV_1 0
+#define WM8940_BCLKDIV_2 1
+#define WM8940_BCLKDIV_4 2
+#define WM8940_BCLKDIV_8 3
+#define WM8940_BCLKDIV_16 4
+#define WM8940_BCLKDIV_32 5
+
+/* PLL Out Dividers */
+#define WM8940_OPCLKDIV_1 0
+#define WM8940_OPCLKDIV_2 1
+#define WM8940_OPCLKDIV_3 2
+#define WM8940_OPCLKDIV_4 3
+
+#endif /* _WM8940_H */
+
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
new file mode 100644 (file)
index 0000000..e224d8a
--- /dev/null
@@ -0,0 +1,969 @@
+/*
+ * wm8960.c  --  WM8960 ALSA SoC Audio driver
+ *
+ * Author: Liam Girdwood
+ *
+ * This 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 <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 "wm8960.h"
+
+#define AUDIO_NAME "wm8960"
+
+struct snd_soc_codec_device soc_codec_dev_wm8960;
+
+/* R25 - Power 1 */
+#define WM8960_VREF      0x40
+
+/* R28 - Anti-pop 1 */
+#define WM8960_POBCTRL   0x80
+#define WM8960_BUFDCOPEN 0x10
+#define WM8960_BUFIOEN   0x08
+#define WM8960_SOFT_ST   0x04
+#define WM8960_HPSTBY    0x01
+
+/* R29 - Anti-pop 2 */
+#define WM8960_DISOP     0x40
+
+/*
+ * wm8960 register cache
+ * We can't read the WM8960 register space when we are
+ * using 2 wire for device control, so we cache them instead.
+ */
+static const u16 wm8960_reg[WM8960_CACHEREGNUM] = {
+       0x0097, 0x0097, 0x0000, 0x0000,
+       0x0000, 0x0008, 0x0000, 0x000a,
+       0x01c0, 0x0000, 0x00ff, 0x00ff,
+       0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x007b, 0x0100, 0x0032,
+       0x0000, 0x00c3, 0x00c3, 0x01c0,
+       0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000,
+       0x0100, 0x0100, 0x0050, 0x0050,
+       0x0050, 0x0050, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0040, 0x0000,
+       0x0000, 0x0050, 0x0050, 0x0000,
+       0x0002, 0x0037, 0x004d, 0x0080,
+       0x0008, 0x0031, 0x0026, 0x00e9,
+};
+
+struct wm8960_priv {
+       u16 reg_cache[WM8960_CACHEREGNUM];
+       struct snd_soc_codec codec;
+};
+
+/*
+ * read wm8960 register cache
+ */
+static inline unsigned int wm8960_read_reg_cache(struct snd_soc_codec *codec,
+       unsigned int reg)
+{
+       u16 *cache = codec->reg_cache;
+       if (reg == WM8960_RESET)
+               return 0;
+       if (reg >= WM8960_CACHEREGNUM)
+               return -1;
+       return cache[reg];
+}
+
+/*
+ * write wm8960 register cache
+ */
+static inline void wm8960_write_reg_cache(struct snd_soc_codec *codec,
+       u16 reg, unsigned int value)
+{
+       u16 *cache = codec->reg_cache;
+       if (reg >= WM8960_CACHEREGNUM)
+               return;
+       cache[reg] = value;
+}
+
+static inline unsigned int wm8960_read(struct snd_soc_codec *codec,
+       unsigned int reg)
+{
+       return wm8960_read_reg_cache(codec, reg);
+}
+
+/*
+ * write to the WM8960 register space
+ */
+static int wm8960_write(struct snd_soc_codec *codec, unsigned int reg,
+       unsigned int value)
+{
+       u8 data[2];
+
+       /* data is
+        *   D15..D9 WM8960 register offset
+        *   D8...D0 register data
+        */
+       data[0] = (reg << 1) | ((value >> 8) & 0x0001);
+       data[1] = value & 0x00ff;
+
+       wm8960_write_reg_cache(codec, reg, value);
+       if (codec->hw_write(codec->control_data, data, 2) == 2)
+               return 0;
+       else
+               return -EIO;
+}
+
+#define wm8960_reset(c)        wm8960_write(c, WM8960_RESET, 0)
+
+/* enumerated controls */
+static const char *wm8960_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+static const char *wm8960_polarity[] = {"No Inversion", "Left Inverted",
+       "Right Inverted", "Stereo Inversion"};
+static const char *wm8960_3d_upper_cutoff[] = {"High", "Low"};
+static const char *wm8960_3d_lower_cutoff[] = {"Low", "High"};
+static const char *wm8960_alcfunc[] = {"Off", "Right", "Left", "Stereo"};
+static const char *wm8960_alcmode[] = {"ALC", "Limiter"};
+
+static const struct soc_enum wm8960_enum[] = {
+       SOC_ENUM_SINGLE(WM8960_DACCTL1, 1, 4, wm8960_deemph),
+       SOC_ENUM_SINGLE(WM8960_DACCTL1, 5, 4, wm8960_polarity),
+       SOC_ENUM_SINGLE(WM8960_DACCTL2, 5, 4, wm8960_polarity),
+       SOC_ENUM_SINGLE(WM8960_3D, 6, 2, wm8960_3d_upper_cutoff),
+       SOC_ENUM_SINGLE(WM8960_3D, 5, 2, wm8960_3d_lower_cutoff),
+       SOC_ENUM_SINGLE(WM8960_ALC1, 7, 4, wm8960_alcfunc),
+       SOC_ENUM_SINGLE(WM8960_ALC3, 8, 2, wm8960_alcmode),
+};
+
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -9700, 50, 0);
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1);
+static const DECLARE_TLV_DB_SCALE(bypass_tlv, -2100, 300, 0);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
+
+static const struct snd_kcontrol_new wm8960_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Capture Volume", WM8960_LINVOL, WM8960_RINVOL,
+                0, 63, 0, adc_tlv),
+SOC_DOUBLE_R("Capture Volume ZC Switch", WM8960_LINVOL, WM8960_RINVOL,
+       6, 1, 0),
+SOC_DOUBLE_R("Capture Switch", WM8960_LINVOL, WM8960_RINVOL,
+       7, 1, 0),
+
+SOC_DOUBLE_R_TLV("Playback Volume", WM8960_LDAC, WM8960_RDAC,
+                0, 255, 0, dac_tlv),
+
+SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8960_LOUT1, WM8960_ROUT1,
+                0, 127, 0, out_tlv),
+SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8960_LOUT1, WM8960_ROUT1,
+       7, 1, 0),
+
+SOC_DOUBLE_R_TLV("Speaker Playback Volume", WM8960_LOUT2, WM8960_ROUT2,
+                0, 127, 0, out_tlv),
+SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8960_LOUT2, WM8960_ROUT2,
+       7, 1, 0),
+SOC_SINGLE("Speaker DC Volume", WM8960_CLASSD3, 3, 5, 0),
+SOC_SINGLE("Speaker AC Volume", WM8960_CLASSD3, 0, 5, 0),
+
+SOC_SINGLE("PCM Playback -6dB Switch", WM8960_DACCTL1, 7, 1, 0),
+SOC_ENUM("ADC Polarity", wm8960_enum[1]),
+SOC_ENUM("Playback De-emphasis", wm8960_enum[0]),
+SOC_SINGLE("ADC High Pass Filter Switch", WM8960_DACCTL1, 0, 1, 0),
+
+SOC_ENUM("DAC Polarity", wm8960_enum[2]),
+
+SOC_ENUM("3D Filter Upper Cut-Off", wm8960_enum[3]),
+SOC_ENUM("3D Filter Lower Cut-Off", wm8960_enum[4]),
+SOC_SINGLE("3D Volume", WM8960_3D, 1, 15, 0),
+SOC_SINGLE("3D Switch", WM8960_3D, 0, 1, 0),
+
+SOC_ENUM("ALC Function", wm8960_enum[5]),
+SOC_SINGLE("ALC Max Gain", WM8960_ALC1, 4, 7, 0),
+SOC_SINGLE("ALC Target", WM8960_ALC1, 0, 15, 1),
+SOC_SINGLE("ALC Min Gain", WM8960_ALC2, 4, 7, 0),
+SOC_SINGLE("ALC Hold Time", WM8960_ALC2, 0, 15, 0),
+SOC_ENUM("ALC Mode", wm8960_enum[6]),
+SOC_SINGLE("ALC Decay", WM8960_ALC3, 4, 15, 0),
+SOC_SINGLE("ALC Attack", WM8960_ALC3, 0, 15, 0),
+
+SOC_SINGLE("Noise Gate Threshold", WM8960_NOISEG, 3, 31, 0),
+SOC_SINGLE("Noise Gate Switch", WM8960_NOISEG, 0, 1, 0),
+
+SOC_DOUBLE_R("ADC PCM Capture Volume", WM8960_LINPATH, WM8960_RINPATH,
+       0, 127, 0),
+
+SOC_SINGLE_TLV("Left Output Mixer Boost Bypass Volume",
+              WM8960_BYPASS1, 4, 7, 1, bypass_tlv),
+SOC_SINGLE_TLV("Left Output Mixer LINPUT3 Volume",
+              WM8960_LOUTMIX, 4, 7, 1, bypass_tlv),
+SOC_SINGLE_TLV("Right Output Mixer Boost Bypass Volume",
+              WM8960_BYPASS2, 4, 7, 1, bypass_tlv),
+SOC_SINGLE_TLV("Right Output Mixer RINPUT3 Volume",
+              WM8960_ROUTMIX, 4, 7, 1, bypass_tlv),
+};
+
+static const struct snd_kcontrol_new wm8960_lin_boost[] = {
+SOC_DAPM_SINGLE("LINPUT2 Switch", WM8960_LINPATH, 6, 1, 0),
+SOC_DAPM_SINGLE("LINPUT3 Switch", WM8960_LINPATH, 7, 1, 0),
+SOC_DAPM_SINGLE("LINPUT1 Switch", WM8960_LINPATH, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8960_lin[] = {
+SOC_DAPM_SINGLE("Boost Switch", WM8960_LINPATH, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8960_rin_boost[] = {
+SOC_DAPM_SINGLE("RINPUT2 Switch", WM8960_RINPATH, 6, 1, 0),
+SOC_DAPM_SINGLE("RINPUT3 Switch", WM8960_RINPATH, 7, 1, 0),
+SOC_DAPM_SINGLE("RINPUT1 Switch", WM8960_RINPATH, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8960_rin[] = {
+SOC_DAPM_SINGLE("Boost Switch", WM8960_RINPATH, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8960_loutput_mixer[] = {
+SOC_DAPM_SINGLE("PCM Playback Switch", WM8960_LOUTMIX, 8, 1, 0),
+SOC_DAPM_SINGLE("LINPUT3 Switch", WM8960_LOUTMIX, 7, 1, 0),
+SOC_DAPM_SINGLE("Boost Bypass Switch", WM8960_BYPASS1, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8960_routput_mixer[] = {
+SOC_DAPM_SINGLE("PCM Playback Switch", WM8960_ROUTMIX, 8, 1, 0),
+SOC_DAPM_SINGLE("RINPUT3 Switch", WM8960_ROUTMIX, 7, 1, 0),
+SOC_DAPM_SINGLE("Boost Bypass Switch", WM8960_BYPASS2, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8960_mono_out[] = {
+SOC_DAPM_SINGLE("Left Switch", WM8960_MONOMIX1, 7, 1, 0),
+SOC_DAPM_SINGLE("Right Switch", WM8960_MONOMIX2, 7, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8960_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("LINPUT1"),
+SND_SOC_DAPM_INPUT("RINPUT1"),
+SND_SOC_DAPM_INPUT("LINPUT2"),
+SND_SOC_DAPM_INPUT("RINPUT2"),
+SND_SOC_DAPM_INPUT("LINPUT3"),
+SND_SOC_DAPM_INPUT("RINPUT3"),
+
+SND_SOC_DAPM_MICBIAS("MICB", WM8960_POWER1, 1, 0),
+
+SND_SOC_DAPM_MIXER("Left Boost Mixer", WM8960_POWER1, 5, 0,
+                  wm8960_lin_boost, ARRAY_SIZE(wm8960_lin_boost)),
+SND_SOC_DAPM_MIXER("Right Boost Mixer", WM8960_POWER1, 4, 0,
+                  wm8960_rin_boost, ARRAY_SIZE(wm8960_rin_boost)),
+
+SND_SOC_DAPM_MIXER("Left Input Mixer", WM8960_POWER3, 5, 0,
+                  wm8960_lin, ARRAY_SIZE(wm8960_lin)),
+SND_SOC_DAPM_MIXER("Right Input Mixer", WM8960_POWER3, 4, 0,
+                  wm8960_rin, ARRAY_SIZE(wm8960_rin)),
+
+SND_SOC_DAPM_ADC("Left ADC", "Capture", WM8960_POWER2, 3, 0),
+SND_SOC_DAPM_ADC("Right ADC", "Capture", WM8960_POWER2, 2, 0),
+
+SND_SOC_DAPM_DAC("Left DAC", "Playback", WM8960_POWER2, 8, 0),
+SND_SOC_DAPM_DAC("Right DAC", "Playback", WM8960_POWER2, 7, 0),
+
+SND_SOC_DAPM_MIXER("Left Output Mixer", WM8960_POWER3, 3, 0,
+       &wm8960_loutput_mixer[0],
+       ARRAY_SIZE(wm8960_loutput_mixer)),
+SND_SOC_DAPM_MIXER("Right Output Mixer", WM8960_POWER3, 2, 0,
+       &wm8960_routput_mixer[0],
+       ARRAY_SIZE(wm8960_routput_mixer)),
+
+SND_SOC_DAPM_MIXER("Mono Output Mixer", WM8960_POWER2, 1, 0,
+       &wm8960_mono_out[0],
+       ARRAY_SIZE(wm8960_mono_out)),
+
+SND_SOC_DAPM_PGA("LOUT1 PGA", WM8960_POWER2, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ROUT1 PGA", WM8960_POWER2, 5, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Left Speaker PGA", WM8960_POWER2, 4, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Speaker PGA", WM8960_POWER2, 3, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Right Speaker Output", WM8960_CLASSD1, 7, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Left Speaker Output", WM8960_CLASSD1, 6, 0, NULL, 0),
+
+SND_SOC_DAPM_OUTPUT("SPK_LP"),
+SND_SOC_DAPM_OUTPUT("SPK_LN"),
+SND_SOC_DAPM_OUTPUT("HP_L"),
+SND_SOC_DAPM_OUTPUT("HP_R"),
+SND_SOC_DAPM_OUTPUT("SPK_RP"),
+SND_SOC_DAPM_OUTPUT("SPK_RN"),
+SND_SOC_DAPM_OUTPUT("OUT3"),
+};
+
+static const struct snd_soc_dapm_route audio_paths[] = {
+       { "Left Boost Mixer", "LINPUT1 Switch", "LINPUT1" },
+       { "Left Boost Mixer", "LINPUT2 Switch", "LINPUT2" },
+       { "Left Boost Mixer", "LINPUT3 Switch", "LINPUT3" },
+
+       { "Left Input Mixer", "Boost Switch", "Left Boost Mixer", },
+       { "Left Input Mixer", NULL, "LINPUT1", },  /* Really Boost Switch */
+       { "Left Input Mixer", NULL, "LINPUT2" },
+       { "Left Input Mixer", NULL, "LINPUT3" },
+
+       { "Right Boost Mixer", "RINPUT1 Switch", "RINPUT1" },
+       { "Right Boost Mixer", "RINPUT2 Switch", "RINPUT2" },
+       { "Right Boost Mixer", "RINPUT3 Switch", "RINPUT3" },
+
+       { "Right Input Mixer", "Boost Switch", "Right Boost Mixer", },
+       { "Right Input Mixer", NULL, "RINPUT1", },  /* Really Boost Switch */
+       { "Right Input Mixer", NULL, "RINPUT2" },
+       { "Right Input Mixer", NULL, "LINPUT3" },
+
+       { "Left ADC", NULL, "Left Input Mixer" },
+       { "Right ADC", NULL, "Right Input Mixer" },
+
+       { "Left Output Mixer", "LINPUT3 Switch", "LINPUT3" },
+       { "Left Output Mixer", "Boost Bypass Switch", "Left Boost Mixer"} ,
+       { "Left Output Mixer", "PCM Playback Switch", "Left DAC" },
+
+       { "Right Output Mixer", "RINPUT3 Switch", "RINPUT3" },
+       { "Right Output Mixer", "Boost Bypass Switch", "Right Boost Mixer" } ,
+       { "Right Output Mixer", "PCM Playback Switch", "Right DAC" },
+
+       { "Mono Output Mixer", "Left Switch", "Left Output Mixer" },
+       { "Mono Output Mixer", "Right Switch", "Right Output Mixer" },
+
+       { "LOUT1 PGA", NULL, "Left Output Mixer" },
+       { "ROUT1 PGA", NULL, "Right Output Mixer" },
+
+       { "HP_L", NULL, "LOUT1 PGA" },
+       { "HP_R", NULL, "ROUT1 PGA" },
+
+       { "Left Speaker PGA", NULL, "Left Output Mixer" },
+       { "Right Speaker PGA", NULL, "Right Output Mixer" },
+
+       { "Left Speaker Output", NULL, "Left Speaker PGA" },
+       { "Right Speaker Output", NULL, "Right Speaker PGA" },
+
+       { "SPK_LN", NULL, "Left Speaker Output" },
+       { "SPK_LP", NULL, "Left Speaker Output" },
+       { "SPK_RN", NULL, "Right Speaker Output" },
+       { "SPK_RP", NULL, "Right Speaker Output" },
+
+       { "OUT3", NULL, "Mono Output Mixer", }
+};
+
+static int wm8960_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_new_controls(codec, wm8960_dapm_widgets,
+                                 ARRAY_SIZE(wm8960_dapm_widgets));
+
+       snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
+
+       snd_soc_dapm_new_widgets(codec);
+       return 0;
+}
+
+static int wm8960_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 */
+       wm8960_write(codec, WM8960_IFACE1, iface);
+       return 0;
+}
+
+static int wm8960_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;
+       u16 iface = wm8960_read(codec, WM8960_IFACE1) & 0xfff3;
+
+       /* 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;
+       }
+
+       /* set iface */
+       wm8960_write(codec, WM8960_IFACE1, iface);
+       return 0;
+}
+
+static int wm8960_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       u16 mute_reg = wm8960_read(codec, WM8960_DACCTL1) & 0xfff7;
+
+       if (mute)
+               wm8960_write(codec, WM8960_DACCTL1, mute_reg | 0x8);
+       else
+               wm8960_write(codec, WM8960_DACCTL1, mute_reg);
+       return 0;
+}
+
+static int wm8960_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       struct wm8960_data *pdata = codec->dev->platform_data;
+       u16 reg;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+
+       case SND_SOC_BIAS_PREPARE:
+               /* Set VMID to 2x50k */
+               reg = wm8960_read(codec, WM8960_POWER1);
+               reg &= ~0x180;
+               reg |= 0x80;
+               wm8960_write(codec, WM8960_POWER1, reg);
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       /* Enable anti-pop features */
+                       wm8960_write(codec, WM8960_APOP1,
+                                    WM8960_POBCTRL | WM8960_SOFT_ST |
+                                    WM8960_BUFDCOPEN | WM8960_BUFIOEN);
+
+                       /* Discharge HP output */
+                       reg = WM8960_DISOP;
+                       if (pdata)
+                               reg |= pdata->dres << 4;
+                       wm8960_write(codec, WM8960_APOP2, reg);
+
+                       msleep(400);
+
+                       wm8960_write(codec, WM8960_APOP2, 0);
+
+                       /* Enable & ramp VMID at 2x50k */
+                       reg = wm8960_read(codec, WM8960_POWER1);
+                       reg |= 0x80;
+                       wm8960_write(codec, WM8960_POWER1, reg);
+                       msleep(100);
+
+                       /* Enable VREF */
+                       wm8960_write(codec, WM8960_POWER1, reg | WM8960_VREF);
+
+                       /* Disable anti-pop features */
+                       wm8960_write(codec, WM8960_APOP1, WM8960_BUFIOEN);
+               }
+
+               /* Set VMID to 2x250k */
+               reg = wm8960_read(codec, WM8960_POWER1);
+               reg &= ~0x180;
+               reg |= 0x100;
+               wm8960_write(codec, WM8960_POWER1, reg);
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               /* Enable anti-pop features */
+               wm8960_write(codec, WM8960_APOP1,
+                            WM8960_POBCTRL | WM8960_SOFT_ST |
+                            WM8960_BUFDCOPEN | WM8960_BUFIOEN);
+
+               /* Disable VMID and VREF, let them discharge */
+               wm8960_write(codec, WM8960_POWER1, 0);
+               msleep(600);
+
+               wm8960_write(codec, WM8960_APOP1, 0);
+               break;
+       }
+
+       codec->bias_level = level;
+
+       return 0;
+}
+
+/* PLL divisors */
+struct _pll_div {
+       u32 pre_div:1;
+       u32 n:4;
+       u32 k:24;
+};
+
+/* The size in bits of the pll divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_PLL_SIZE ((1 << 24) * 10)
+
+static int pll_factors(unsigned int source, unsigned int target,
+                      struct _pll_div *pll_div)
+{
+       unsigned long long Kpart;
+       unsigned int K, Ndiv, Nmod;
+
+       pr_debug("WM8960 PLL: setting %dHz->%dHz\n", source, target);
+
+       /* Scale up target to PLL operating frequency */
+       target *= 4;
+
+       Ndiv = target / source;
+       if (Ndiv < 6) {
+               source >>= 1;
+               pll_div->pre_div = 1;
+               Ndiv = target / source;
+       } else
+               pll_div->pre_div = 0;
+
+       if ((Ndiv < 6) || (Ndiv > 12)) {
+               pr_err("WM8960 PLL: Unsupported N=%d\n", Ndiv);
+               return -EINVAL;
+       }
+
+       pll_div->n = Ndiv;
+       Nmod = target % source;
+       Kpart = FIXED_PLL_SIZE * (long long)Nmod;
+
+       do_div(Kpart, source);
+
+       K = Kpart & 0xFFFFFFFF;
+
+       /* Check if we need to round */
+       if ((K % 10) >= 5)
+               K += 5;
+
+       /* Move down to proper range now rounding is done */
+       K /= 10;
+
+       pll_div->k = K;
+
+       pr_debug("WM8960 PLL: N=%x K=%x pre_div=%d\n",
+                pll_div->n, pll_div->k, pll_div->pre_div);
+
+       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)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u16 reg;
+       static struct _pll_div pll_div;
+       int ret;
+
+       if (freq_in && freq_out) {
+               ret = pll_factors(freq_in, freq_out, &pll_div);
+               if (ret != 0)
+                       return ret;
+       }
+
+       /* Disable the PLL: even if we are changing the frequency the
+        * PLL needs to be disabled while we do so. */
+       wm8960_write(codec, WM8960_CLOCK1,
+                    wm8960_read(codec, WM8960_CLOCK1) & ~1);
+       wm8960_write(codec, WM8960_POWER2,
+                    wm8960_read(codec, WM8960_POWER2) & ~1);
+
+       if (!freq_in || !freq_out)
+               return 0;
+
+       reg = wm8960_read(codec, WM8960_PLL1) & ~0x3f;
+       reg |= pll_div.pre_div << 4;
+       reg |= pll_div.n;
+
+       if (pll_div.k) {
+               reg |= 0x20;
+
+               wm8960_write(codec, WM8960_PLL2, (pll_div.k >> 18) & 0x3f);
+               wm8960_write(codec, WM8960_PLL3, (pll_div.k >> 9) & 0x1ff);
+               wm8960_write(codec, WM8960_PLL4, pll_div.k & 0x1ff);
+       }
+       wm8960_write(codec, WM8960_PLL1, reg);
+
+       /* Turn it on */
+       wm8960_write(codec, WM8960_POWER2,
+                    wm8960_read(codec, WM8960_POWER2) | 1);
+       msleep(250);
+       wm8960_write(codec, WM8960_CLOCK1,
+                    wm8960_read(codec, WM8960_CLOCK1) | 1);
+
+       return 0;
+}
+
+static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+               int div_id, int div)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u16 reg;
+
+       switch (div_id) {
+       case WM8960_SYSCLKSEL:
+               reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1fe;
+               wm8960_write(codec, WM8960_CLOCK1, reg | div);
+               break;
+       case WM8960_SYSCLKDIV:
+               reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1f9;
+               wm8960_write(codec, WM8960_CLOCK1, reg | div);
+               break;
+       case WM8960_DACDIV:
+               reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1c7;
+               wm8960_write(codec, WM8960_CLOCK1, reg | div);
+               break;
+       case WM8960_OPCLKDIV:
+               reg = wm8960_read(codec, WM8960_PLL1) & 0x03f;
+               wm8960_write(codec, WM8960_PLL1, reg | div);
+               break;
+       case WM8960_DCLKDIV:
+               reg = wm8960_read(codec, WM8960_CLOCK2) & 0x03f;
+               wm8960_write(codec, WM8960_CLOCK2, reg | div);
+               break;
+       case WM8960_TOCLKSEL:
+               reg = wm8960_read(codec, WM8960_ADDCTL1) & 0x1fd;
+               wm8960_write(codec, WM8960_ADDCTL1, reg | div);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+#define WM8960_RATES SNDRV_PCM_RATE_8000_48000
+
+#define WM8960_FORMATS \
+       (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+       SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops wm8960_dai_ops = {
+       .hw_params = wm8960_hw_params,
+       .digital_mute = wm8960_mute,
+       .set_fmt = wm8960_set_dai_fmt,
+       .set_clkdiv = wm8960_set_dai_clkdiv,
+       .set_pll = wm8960_set_dai_pll,
+};
+
+struct snd_soc_dai wm8960_dai = {
+       .name = "WM8960",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = WM8960_RATES,
+               .formats = WM8960_FORMATS,},
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = WM8960_RATES,
+               .formats = WM8960_FORMATS,},
+       .ops = &wm8960_dai_ops,
+       .symmetric_rates = 1,
+};
+EXPORT_SYMBOL_GPL(wm8960_dai);
+
+static int wm8960_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;
+
+       wm8960_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int wm8960_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(wm8960_reg); i++) {
+               data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
+               data[1] = cache[i] & 0x00ff;
+               codec->hw_write(codec->control_data, data, 2);
+       }
+
+       wm8960_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       wm8960_set_bias_level(codec, codec->suspend_bias_level);
+       return 0;
+}
+
+static struct snd_soc_codec *wm8960_codec;
+
+static int wm8960_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec;
+       int ret = 0;
+
+       if (wm8960_codec == NULL) {
+               dev_err(&pdev->dev, "Codec device not registered\n");
+               return -ENODEV;
+       }
+
+       socdev->card->codec = wm8960_codec;
+       codec = wm8960_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, 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;
+}
+
+/* power down chip */
+static int wm8960_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_wm8960 = {
+       .probe =        wm8960_probe,
+       .remove =       wm8960_remove,
+       .suspend =      wm8960_suspend,
+       .resume =       wm8960_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8960);
+
+static int wm8960_register(struct wm8960_priv *wm8960)
+{
+       struct wm8960_data *pdata = wm8960->codec.dev->platform_data;
+       struct snd_soc_codec *codec = &wm8960->codec;
+       int ret;
+       u16 reg;
+
+       if (wm8960_codec) {
+               dev_err(codec->dev, "Another WM8960 is registered\n");
+               return -EINVAL;
+       }
+
+       if (!pdata) {
+               dev_warn(codec->dev, "No platform data supplied\n");
+       } else {
+               if (pdata->dres > WM8960_DRES_MAX) {
+                       dev_err(codec->dev, "Invalid DRES: %d\n", pdata->dres);
+                       pdata->dres = 0;
+               }
+       }
+
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       codec->private_data = wm8960;
+       codec->name = "WM8960";
+       codec->owner = THIS_MODULE;
+       codec->read = wm8960_read_reg_cache;
+       codec->write = wm8960_write;
+       codec->bias_level = SND_SOC_BIAS_OFF;
+       codec->set_bias_level = wm8960_set_bias_level;
+       codec->dai = &wm8960_dai;
+       codec->num_dai = 1;
+       codec->reg_cache_size = WM8960_CACHEREGNUM;
+       codec->reg_cache = &wm8960->reg_cache;
+
+       memcpy(codec->reg_cache, wm8960_reg, sizeof(wm8960_reg));
+
+       ret = wm8960_reset(codec);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to issue reset\n");
+               return ret;
+       }
+
+       wm8960_dai.dev = codec->dev;
+
+       wm8960_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       /* Latch the update bits */
+       reg = wm8960_read(codec, WM8960_LINVOL);
+       wm8960_write(codec, WM8960_LINVOL, reg | 0x100);
+       reg = wm8960_read(codec, WM8960_RINVOL);
+       wm8960_write(codec, WM8960_RINVOL, reg | 0x100);
+       reg = wm8960_read(codec, WM8960_LADC);
+       wm8960_write(codec, WM8960_LADC, reg | 0x100);
+       reg = wm8960_read(codec, WM8960_RADC);
+       wm8960_write(codec, WM8960_RADC, reg | 0x100);
+       reg = wm8960_read(codec, WM8960_LDAC);
+       wm8960_write(codec, WM8960_LDAC, reg | 0x100);
+       reg = wm8960_read(codec, WM8960_RDAC);
+       wm8960_write(codec, WM8960_RDAC, reg | 0x100);
+       reg = wm8960_read(codec, WM8960_LOUT1);
+       wm8960_write(codec, WM8960_LOUT1, reg | 0x100);
+       reg = wm8960_read(codec, WM8960_ROUT1);
+       wm8960_write(codec, WM8960_ROUT1, reg | 0x100);
+       reg = wm8960_read(codec, WM8960_LOUT2);
+       wm8960_write(codec, WM8960_LOUT2, reg | 0x100);
+       reg = wm8960_read(codec, WM8960_ROUT2);
+       wm8960_write(codec, WM8960_ROUT2, reg | 0x100);
+
+       wm8960_codec = codec;
+
+       ret = snd_soc_register_codec(codec);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_register_dai(&wm8960_dai);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+               snd_soc_unregister_codec(codec);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void wm8960_unregister(struct wm8960_priv *wm8960)
+{
+       wm8960_set_bias_level(&wm8960->codec, SND_SOC_BIAS_OFF);
+       snd_soc_unregister_dai(&wm8960_dai);
+       snd_soc_unregister_codec(&wm8960->codec);
+       kfree(wm8960);
+       wm8960_codec = NULL;
+}
+
+static __devinit int wm8960_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct wm8960_priv *wm8960;
+       struct snd_soc_codec *codec;
+
+       wm8960 = kzalloc(sizeof(struct wm8960_priv), GFP_KERNEL);
+       if (wm8960 == NULL)
+               return -ENOMEM;
+
+       codec = &wm8960->codec;
+       codec->hw_write = (hw_write_t)i2c_master_send;
+
+       i2c_set_clientdata(i2c, wm8960);
+       codec->control_data = i2c;
+
+       codec->dev = &i2c->dev;
+
+       return wm8960_register(wm8960);
+}
+
+static __devexit int wm8960_i2c_remove(struct i2c_client *client)
+{
+       struct wm8960_priv *wm8960 = i2c_get_clientdata(client);
+       wm8960_unregister(wm8960);
+       return 0;
+}
+
+static const struct i2c_device_id wm8960_i2c_id[] = {
+       { "wm8960", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8960_i2c_id);
+
+static struct i2c_driver wm8960_i2c_driver = {
+       .driver = {
+               .name = "WM8960 I2C Codec",
+               .owner = THIS_MODULE,
+       },
+       .probe =    wm8960_i2c_probe,
+       .remove =   __devexit_p(wm8960_i2c_remove),
+       .id_table = wm8960_i2c_id,
+};
+
+static int __init wm8960_modinit(void)
+{
+       int ret;
+
+       ret = i2c_add_driver(&wm8960_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register WM8960 I2C driver: %d\n",
+                      ret);
+       }
+
+       return ret;
+}
+module_init(wm8960_modinit);
+
+static void __exit wm8960_exit(void)
+{
+       i2c_del_driver(&wm8960_i2c_driver);
+}
+module_exit(wm8960_exit);
+
+
+MODULE_DESCRIPTION("ASoC WM8960 driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8960.h b/sound/soc/codecs/wm8960.h
new file mode 100644 (file)
index 0000000..c9af56c
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * wm8960.h  --  WM8960 Soc Audio driver
+ *
+ * This 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 _WM8960_H
+#define _WM8960_H
+
+/* WM8960 register space */
+
+
+#define WM8960_CACHEREGNUM     56
+
+#define WM8960_LINVOL          0x0
+#define WM8960_RINVOL          0x1
+#define WM8960_LOUT1           0x2
+#define WM8960_ROUT1           0x3
+#define WM8960_CLOCK1          0x4
+#define WM8960_DACCTL1         0x5
+#define WM8960_DACCTL2         0x6
+#define WM8960_IFACE1          0x7
+#define WM8960_CLOCK2          0x8
+#define WM8960_IFACE2          0x9
+#define WM8960_LDAC            0xa
+#define WM8960_RDAC            0xb
+
+#define WM8960_RESET           0xf
+#define WM8960_3D              0x10
+#define WM8960_ALC1            0x11
+#define WM8960_ALC2            0x12
+#define WM8960_ALC3            0x13
+#define WM8960_NOISEG          0x14
+#define WM8960_LADC            0x15
+#define WM8960_RADC            0x16
+#define WM8960_ADDCTL1         0x17
+#define WM8960_ADDCTL2         0x18
+#define WM8960_POWER1          0x19
+#define WM8960_POWER2          0x1a
+#define WM8960_ADDCTL3         0x1b
+#define WM8960_APOP1           0x1c
+#define WM8960_APOP2           0x1d
+
+#define WM8960_LINPATH         0x20
+#define WM8960_RINPATH         0x21
+#define WM8960_LOUTMIX         0x22
+
+#define WM8960_ROUTMIX         0x25
+#define WM8960_MONOMIX1                0x26
+#define WM8960_MONOMIX2                0x27
+#define WM8960_LOUT2           0x28
+#define WM8960_ROUT2           0x29
+#define WM8960_MONO            0x2a
+#define WM8960_INBMIX1         0x2b
+#define WM8960_INBMIX2         0x2c
+#define WM8960_BYPASS1         0x2d
+#define WM8960_BYPASS2         0x2e
+#define WM8960_POWER3          0x2f
+#define WM8960_ADDCTL4         0x30
+#define WM8960_CLASSD1         0x31
+
+#define WM8960_CLASSD3         0x33
+#define WM8960_PLL1            0x34
+#define WM8960_PLL2            0x35
+#define WM8960_PLL3            0x36
+#define WM8960_PLL4            0x37
+
+
+/*
+ * WM8960 Clock dividers
+ */
+#define WM8960_SYSCLKDIV               0
+#define WM8960_DACDIV                  1
+#define WM8960_OPCLKDIV                        2
+#define WM8960_DCLKDIV                 3
+#define WM8960_TOCLKSEL                        4
+#define WM8960_SYSCLKSEL               5
+
+#define WM8960_SYSCLK_DIV_1            (0 << 1)
+#define WM8960_SYSCLK_DIV_2            (2 << 1)
+
+#define WM8960_SYSCLK_MCLK             (0 << 0)
+#define WM8960_SYSCLK_PLL              (1 << 0)
+
+#define WM8960_DAC_DIV_1               (0 << 3)
+#define WM8960_DAC_DIV_1_5             (1 << 3)
+#define WM8960_DAC_DIV_2               (2 << 3)
+#define WM8960_DAC_DIV_3               (3 << 3)
+#define WM8960_DAC_DIV_4               (4 << 3)
+#define WM8960_DAC_DIV_5_5             (5 << 3)
+#define WM8960_DAC_DIV_6               (6 << 3)
+
+#define WM8960_DCLK_DIV_1_5            (0 << 6)
+#define WM8960_DCLK_DIV_2              (1 << 6)
+#define WM8960_DCLK_DIV_3              (2 << 6)
+#define WM8960_DCLK_DIV_4              (3 << 6)
+#define WM8960_DCLK_DIV_6              (4 << 6)
+#define WM8960_DCLK_DIV_8              (5 << 6)
+#define WM8960_DCLK_DIV_12             (6 << 6)
+#define WM8960_DCLK_DIV_16             (7 << 6)
+
+#define WM8960_TOCLK_F19               (0 << 1)
+#define WM8960_TOCLK_F21               (1 << 1)
+
+#define WM8960_OPCLK_DIV_1             (0 << 0)
+#define WM8960_OPCLK_DIV_2             (1 << 0)
+#define WM8960_OPCLK_DIV_3             (2 << 0)
+#define WM8960_OPCLK_DIV_4             (3 << 0)
+#define WM8960_OPCLK_DIV_5_5           (4 << 0)
+#define WM8960_OPCLK_DIV_6             (5 << 0)
+
+extern struct snd_soc_dai wm8960_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8960;
+
+#define WM8960_DRES_400R 0
+#define WM8960_DRES_200R 1
+#define WM8960_DRES_600R 2
+#define WM8960_DRES_150R 3
+#define WM8960_DRES_MAX  3
+
+struct wm8960_data {
+       int dres;
+};
+
+#endif
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
new file mode 100644 (file)
index 0000000..c05f718
--- /dev/null
@@ -0,0 +1,1097 @@
+/*
+ * wm8988.c -- WM8988 ALSA SoC audio driver
+ *
+ * Copyright 2009 Wolfson Microelectronics plc
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 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/spi/spi.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "wm8988.h"
+
+/*
+ * wm8988 register cache
+ * We can't read the WM8988 register space when we
+ * are using 2 wire for device control, so we cache them instead.
+ */
+static const u16 wm8988_reg[] = {
+       0x0097, 0x0097, 0x0079, 0x0079,  /*  0 */
+       0x0000, 0x0008, 0x0000, 0x000a,  /*  4 */
+       0x0000, 0x0000, 0x00ff, 0x00ff,  /*  8 */
+       0x000f, 0x000f, 0x0000, 0x0000,  /* 12 */
+       0x0000, 0x007b, 0x0000, 0x0032,  /* 16 */
+       0x0000, 0x00c3, 0x00c3, 0x00c0,  /* 20 */
+       0x0000, 0x0000, 0x0000, 0x0000,  /* 24 */
+       0x0000, 0x0000, 0x0000, 0x0000,  /* 28 */
+       0x0000, 0x0000, 0x0050, 0x0050,  /* 32 */
+       0x0050, 0x0050, 0x0050, 0x0050,  /* 36 */
+       0x0079, 0x0079, 0x0079,          /* 40 */
+};
+
+/* codec private data */
+struct wm8988_priv {
+       unsigned int sysclk;
+       struct snd_soc_codec codec;
+       struct snd_pcm_hw_constraint_list *sysclk_constraints;
+       u16 reg_cache[WM8988_NUM_REG];
+};
+
+
+/*
+ * read wm8988 register cache
+ */
+static inline unsigned int wm8988_read_reg_cache(struct snd_soc_codec *codec,
+       unsigned int reg)
+{
+       u16 *cache = codec->reg_cache;
+       if (reg > WM8988_NUM_REG)
+               return -1;
+       return cache[reg];
+}
+
+/*
+ * write wm8988 register cache
+ */
+static inline void wm8988_write_reg_cache(struct snd_soc_codec *codec,
+       unsigned int reg, unsigned int value)
+{
+       u16 *cache = codec->reg_cache;
+       if (reg > WM8988_NUM_REG)
+               return;
+       cache[reg] = value;
+}
+
+static int wm8988_write(struct snd_soc_codec *codec, unsigned int reg,
+       unsigned int value)
+{
+       u8 data[2];
+
+       /* data is
+        *   D15..D9 WM8753 register offset
+        *   D8...D0 register data
+        */
+       data[0] = (reg << 1) | ((value >> 8) & 0x0001);
+       data[1] = value & 0x00ff;
+
+       wm8988_write_reg_cache(codec, reg, value);
+       if (codec->hw_write(codec->control_data, data, 2) == 2)
+               return 0;
+       else
+               return -EIO;
+}
+
+#define wm8988_reset(c)        wm8988_write(c, WM8988_RESET, 0)
+
+/*
+ * WM8988 Controls
+ */
+
+static const char *bass_boost_txt[] = {"Linear Control", "Adaptive Boost"};
+static const struct soc_enum bass_boost =
+       SOC_ENUM_SINGLE(WM8988_BASS, 7, 2, bass_boost_txt);
+
+static const char *bass_filter_txt[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" };
+static const struct soc_enum bass_filter =
+       SOC_ENUM_SINGLE(WM8988_BASS, 6, 2, bass_filter_txt);
+
+static const char *treble_txt[] = {"8kHz", "4kHz"};
+static const struct soc_enum treble =
+       SOC_ENUM_SINGLE(WM8988_TREBLE, 6, 2, treble_txt);
+
+static const char *stereo_3d_lc_txt[] = {"200Hz", "500Hz"};
+static const struct soc_enum stereo_3d_lc =
+       SOC_ENUM_SINGLE(WM8988_3D, 5, 2, stereo_3d_lc_txt);
+
+static const char *stereo_3d_uc_txt[] = {"2.2kHz", "1.5kHz"};
+static const struct soc_enum stereo_3d_uc =
+       SOC_ENUM_SINGLE(WM8988_3D, 6, 2, stereo_3d_uc_txt);
+
+static const char *stereo_3d_func_txt[] = {"Capture", "Playback"};
+static const struct soc_enum stereo_3d_func =
+       SOC_ENUM_SINGLE(WM8988_3D, 7, 2, stereo_3d_func_txt);
+
+static const char *alc_func_txt[] = {"Off", "Right", "Left", "Stereo"};
+static const struct soc_enum alc_func =
+       SOC_ENUM_SINGLE(WM8988_ALC1, 7, 4, alc_func_txt);
+
+static const char *ng_type_txt[] = {"Constant PGA Gain",
+                                   "Mute ADC Output"};
+static const struct soc_enum ng_type =
+       SOC_ENUM_SINGLE(WM8988_NGATE, 1, 2, ng_type_txt);
+
+static const char *deemph_txt[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+static const struct soc_enum deemph =
+       SOC_ENUM_SINGLE(WM8988_ADCDAC, 1, 4, deemph_txt);
+
+static const char *adcpol_txt[] = {"Normal", "L Invert", "R Invert",
+                                  "L + R Invert"};
+static const struct soc_enum adcpol =
+       SOC_ENUM_SINGLE(WM8988_ADCDAC, 5, 4, adcpol_txt);
+
+static const DECLARE_TLV_DB_SCALE(pga_tlv, -1725, 75, 0);
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
+static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
+
+static const struct snd_kcontrol_new wm8988_snd_controls[] = {
+
+SOC_ENUM("Bass Boost", bass_boost),
+SOC_ENUM("Bass Filter", bass_filter),
+SOC_SINGLE("Bass Volume", WM8988_BASS, 0, 15, 1),
+
+SOC_SINGLE("Treble Volume", WM8988_TREBLE, 0, 15, 0),
+SOC_ENUM("Treble Cut-off", treble),
+
+SOC_SINGLE("3D Switch", WM8988_3D, 0, 1, 0),
+SOC_SINGLE("3D Volume", WM8988_3D, 1, 15, 0),
+SOC_ENUM("3D Lower Cut-off", stereo_3d_lc),
+SOC_ENUM("3D Upper Cut-off", stereo_3d_uc),
+SOC_ENUM("3D Mode", stereo_3d_func),
+
+SOC_SINGLE("ALC Capture Target Volume", WM8988_ALC1, 0, 7, 0),
+SOC_SINGLE("ALC Capture Max Volume", WM8988_ALC1, 4, 7, 0),
+SOC_ENUM("ALC Capture Function", alc_func),
+SOC_SINGLE("ALC Capture ZC Switch", WM8988_ALC2, 7, 1, 0),
+SOC_SINGLE("ALC Capture Hold Time", WM8988_ALC2, 0, 15, 0),
+SOC_SINGLE("ALC Capture Decay Time", WM8988_ALC3, 4, 15, 0),
+SOC_SINGLE("ALC Capture Attack Time", WM8988_ALC3, 0, 15, 0),
+SOC_SINGLE("ALC Capture NG Threshold", WM8988_NGATE, 3, 31, 0),
+SOC_ENUM("ALC Capture NG Type", ng_type),
+SOC_SINGLE("ALC Capture NG Switch", WM8988_NGATE, 0, 1, 0),
+
+SOC_SINGLE("ZC Timeout Switch", WM8988_ADCTL1, 0, 1, 0),
+
+SOC_DOUBLE_R_TLV("Capture Digital Volume", WM8988_LADC, WM8988_RADC,
+                0, 255, 0, adc_tlv),
+SOC_DOUBLE_R_TLV("Capture Volume", WM8988_LINVOL, WM8988_RINVOL,
+                0, 63, 0, pga_tlv),
+SOC_DOUBLE_R("Capture ZC Switch", WM8988_LINVOL, WM8988_RINVOL, 6, 1, 0),
+SOC_DOUBLE_R("Capture Switch", WM8988_LINVOL, WM8988_RINVOL, 7, 1, 1),
+
+SOC_ENUM("Playback De-emphasis", deemph),
+
+SOC_ENUM("Capture Polarity", adcpol),
+SOC_SINGLE("Playback 6dB Attenuate", WM8988_ADCDAC, 7, 1, 0),
+SOC_SINGLE("Capture 6dB Attenuate", WM8988_ADCDAC, 8, 1, 0),
+
+SOC_DOUBLE_R_TLV("PCM Volume", WM8988_LDAC, WM8988_RDAC, 0, 255, 0, dac_tlv),
+
+SOC_SINGLE_TLV("Left Mixer Left Bypass Volume", WM8988_LOUTM1, 4, 7, 1,
+              bypass_tlv),
+SOC_SINGLE_TLV("Left Mixer Right Bypass Volume", WM8988_LOUTM2, 4, 7, 1,
+              bypass_tlv),
+SOC_SINGLE_TLV("Right Mixer Left Bypass Volume", WM8988_ROUTM1, 4, 7, 1,
+              bypass_tlv),
+SOC_SINGLE_TLV("Right Mixer Right Bypass Volume", WM8988_ROUTM2, 4, 7, 1,
+              bypass_tlv),
+
+SOC_DOUBLE_R("Output 1 Playback ZC Switch", WM8988_LOUT1V,
+            WM8988_ROUT1V, 7, 1, 0),
+SOC_DOUBLE_R_TLV("Output 1 Playback Volume", WM8988_LOUT1V, WM8988_ROUT1V,
+                0, 127, 0, out_tlv),
+
+SOC_DOUBLE_R("Output 2 Playback ZC Switch", WM8988_LOUT2V,
+            WM8988_ROUT2V, 7, 1, 0),
+SOC_DOUBLE_R_TLV("Output 2 Playback Volume", WM8988_LOUT2V, WM8988_ROUT2V,
+                0, 127, 0, out_tlv),
+
+};
+
+/*
+ * DAPM Controls
+ */
+
+static int wm8988_lrc_control(struct snd_soc_dapm_widget *w,
+                             struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       u16 adctl2 = wm8988_read_reg_cache(codec, WM8988_ADCTL2);
+
+       /* Use the DAC to gate LRC if active, otherwise use ADC */
+       if (wm8988_read_reg_cache(codec, WM8988_PWR2) & 0x180)
+               adctl2 &= ~0x4;
+       else
+               adctl2 |= 0x4;
+
+       return wm8988_write(codec, WM8988_ADCTL2, adctl2);
+}
+
+static const char *wm8988_line_texts[] = {
+       "Line 1", "Line 2", "PGA", "Differential"};
+
+static const unsigned int wm8988_line_values[] = {
+       0, 1, 3, 4};
+
+static const struct soc_enum wm8988_lline_enum =
+       SOC_VALUE_ENUM_SINGLE(WM8988_LOUTM1, 0, 7,
+                             ARRAY_SIZE(wm8988_line_texts),
+                             wm8988_line_texts,
+                             wm8988_line_values);
+static const struct snd_kcontrol_new wm8988_left_line_controls =
+       SOC_DAPM_VALUE_ENUM("Route", wm8988_lline_enum);
+
+static const struct soc_enum wm8988_rline_enum =
+       SOC_VALUE_ENUM_SINGLE(WM8988_ROUTM1, 0, 7,
+                             ARRAY_SIZE(wm8988_line_texts),
+                             wm8988_line_texts,
+                             wm8988_line_values);
+static const struct snd_kcontrol_new wm8988_right_line_controls =
+       SOC_DAPM_VALUE_ENUM("Route", wm8988_lline_enum);
+
+/* Left Mixer */
+static const struct snd_kcontrol_new wm8988_left_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Playback Switch", WM8988_LOUTM1, 8, 1, 0),
+       SOC_DAPM_SINGLE("Left Bypass Switch", WM8988_LOUTM1, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right Playback Switch", WM8988_LOUTM2, 8, 1, 0),
+       SOC_DAPM_SINGLE("Right Bypass Switch", WM8988_LOUTM2, 7, 1, 0),
+};
+
+/* Right Mixer */
+static const struct snd_kcontrol_new wm8988_right_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left Playback Switch", WM8988_ROUTM1, 8, 1, 0),
+       SOC_DAPM_SINGLE("Left Bypass Switch", WM8988_ROUTM1, 7, 1, 0),
+       SOC_DAPM_SINGLE("Playback Switch", WM8988_ROUTM2, 8, 1, 0),
+       SOC_DAPM_SINGLE("Right Bypass Switch", WM8988_ROUTM2, 7, 1, 0),
+};
+
+static const char *wm8988_pga_sel[] = {"Line 1", "Line 2", "Differential"};
+static const unsigned int wm8988_pga_val[] = { 0, 1, 3 };
+
+/* Left PGA Mux */
+static const struct soc_enum wm8988_lpga_enum =
+       SOC_VALUE_ENUM_SINGLE(WM8988_LADCIN, 6, 3,
+                             ARRAY_SIZE(wm8988_pga_sel),
+                             wm8988_pga_sel,
+                             wm8988_pga_val);
+static const struct snd_kcontrol_new wm8988_left_pga_controls =
+       SOC_DAPM_VALUE_ENUM("Route", wm8988_lpga_enum);
+
+/* Right PGA Mux */
+static const struct soc_enum wm8988_rpga_enum =
+       SOC_VALUE_ENUM_SINGLE(WM8988_RADCIN, 6, 3,
+                             ARRAY_SIZE(wm8988_pga_sel),
+                             wm8988_pga_sel,
+                             wm8988_pga_val);
+static const struct snd_kcontrol_new wm8988_right_pga_controls =
+       SOC_DAPM_VALUE_ENUM("Route", wm8988_rpga_enum);
+
+/* Differential Mux */
+static const char *wm8988_diff_sel[] = {"Line 1", "Line 2"};
+static const struct soc_enum diffmux =
+       SOC_ENUM_SINGLE(WM8988_ADCIN, 8, 2, wm8988_diff_sel);
+static const struct snd_kcontrol_new wm8988_diffmux_controls =
+       SOC_DAPM_ENUM("Route", diffmux);
+
+/* Mono ADC Mux */
+static const char *wm8988_mono_mux[] = {"Stereo", "Mono (Left)",
+       "Mono (Right)", "Digital Mono"};
+static const struct soc_enum monomux =
+       SOC_ENUM_SINGLE(WM8988_ADCIN, 6, 4, wm8988_mono_mux);
+static const struct snd_kcontrol_new wm8988_monomux_controls =
+       SOC_DAPM_ENUM("Route", monomux);
+
+static const struct snd_soc_dapm_widget wm8988_dapm_widgets[] = {
+       SND_SOC_DAPM_MICBIAS("Mic Bias", WM8988_PWR1, 1, 0),
+
+       SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0,
+               &wm8988_diffmux_controls),
+       SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0,
+               &wm8988_monomux_controls),
+       SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0,
+               &wm8988_monomux_controls),
+
+       SND_SOC_DAPM_MUX("Left PGA Mux", WM8988_PWR1, 5, 0,
+               &wm8988_left_pga_controls),
+       SND_SOC_DAPM_MUX("Right PGA Mux", WM8988_PWR1, 4, 0,
+               &wm8988_right_pga_controls),
+
+       SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0,
+               &wm8988_left_line_controls),
+       SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0,
+               &wm8988_right_line_controls),
+
+       SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8988_PWR1, 2, 0),
+       SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8988_PWR1, 3, 0),
+
+       SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8988_PWR2, 7, 0),
+       SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8988_PWR2, 8, 0),
+
+       SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
+               &wm8988_left_mixer_controls[0],
+               ARRAY_SIZE(wm8988_left_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
+               &wm8988_right_mixer_controls[0],
+               ARRAY_SIZE(wm8988_right_mixer_controls)),
+
+       SND_SOC_DAPM_PGA("Right Out 2", WM8988_PWR2, 3, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Left Out 2", WM8988_PWR2, 4, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Right Out 1", WM8988_PWR2, 5, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Left Out 1", WM8988_PWR2, 6, 0, NULL, 0),
+
+       SND_SOC_DAPM_POST("LRC control", wm8988_lrc_control),
+
+       SND_SOC_DAPM_OUTPUT("LOUT1"),
+       SND_SOC_DAPM_OUTPUT("ROUT1"),
+       SND_SOC_DAPM_OUTPUT("LOUT2"),
+       SND_SOC_DAPM_OUTPUT("ROUT2"),
+       SND_SOC_DAPM_OUTPUT("VREF"),
+
+       SND_SOC_DAPM_INPUT("LINPUT1"),
+       SND_SOC_DAPM_INPUT("LINPUT2"),
+       SND_SOC_DAPM_INPUT("RINPUT1"),
+       SND_SOC_DAPM_INPUT("RINPUT2"),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+
+       { "Left Line Mux", "Line 1", "LINPUT1" },
+       { "Left Line Mux", "Line 2", "LINPUT2" },
+       { "Left Line Mux", "PGA", "Left PGA Mux" },
+       { "Left Line Mux", "Differential", "Differential Mux" },
+
+       { "Right Line Mux", "Line 1", "RINPUT1" },
+       { "Right Line Mux", "Line 2", "RINPUT2" },
+       { "Right Line Mux", "PGA", "Right PGA Mux" },
+       { "Right Line Mux", "Differential", "Differential Mux" },
+
+       { "Left PGA Mux", "Line 1", "LINPUT1" },
+       { "Left PGA Mux", "Line 2", "LINPUT2" },
+       { "Left PGA Mux", "Differential", "Differential Mux" },
+
+       { "Right PGA Mux", "Line 1", "RINPUT1" },
+       { "Right PGA Mux", "Line 2", "RINPUT2" },
+       { "Right PGA Mux", "Differential", "Differential Mux" },
+
+       { "Differential Mux", "Line 1", "LINPUT1" },
+       { "Differential Mux", "Line 1", "RINPUT1" },
+       { "Differential Mux", "Line 2", "LINPUT2" },
+       { "Differential Mux", "Line 2", "RINPUT2" },
+
+       { "Left ADC Mux", "Stereo", "Left PGA Mux" },
+       { "Left ADC Mux", "Mono (Left)", "Left PGA Mux" },
+       { "Left ADC Mux", "Digital Mono", "Left PGA Mux" },
+
+       { "Right ADC Mux", "Stereo", "Right PGA Mux" },
+       { "Right ADC Mux", "Mono (Right)", "Right PGA Mux" },
+       { "Right ADC Mux", "Digital Mono", "Right PGA Mux" },
+
+       { "Left ADC", NULL, "Left ADC Mux" },
+       { "Right ADC", NULL, "Right ADC Mux" },
+
+       { "Left Line Mux", "Line 1", "LINPUT1" },
+       { "Left Line Mux", "Line 2", "LINPUT2" },
+       { "Left Line Mux", "PGA", "Left PGA Mux" },
+       { "Left Line Mux", "Differential", "Differential Mux" },
+
+       { "Right Line Mux", "Line 1", "RINPUT1" },
+       { "Right Line Mux", "Line 2", "RINPUT2" },
+       { "Right Line Mux", "PGA", "Right PGA Mux" },
+       { "Right Line Mux", "Differential", "Differential Mux" },
+
+       { "Left Mixer", "Playback Switch", "Left DAC" },
+       { "Left Mixer", "Left Bypass Switch", "Left Line Mux" },
+       { "Left Mixer", "Right Playback Switch", "Right DAC" },
+       { "Left Mixer", "Right Bypass Switch", "Right Line Mux" },
+
+       { "Right Mixer", "Left Playback Switch", "Left DAC" },
+       { "Right Mixer", "Left Bypass Switch", "Left Line Mux" },
+       { "Right Mixer", "Playback Switch", "Right DAC" },
+       { "Right Mixer", "Right Bypass Switch", "Right Line Mux" },
+
+       { "Left Out 1", NULL, "Left Mixer" },
+       { "LOUT1", NULL, "Left Out 1" },
+       { "Right Out 1", NULL, "Right Mixer" },
+       { "ROUT1", NULL, "Right Out 1" },
+
+       { "Left Out 2", NULL, "Left Mixer" },
+       { "LOUT2", NULL, "Left Out 2" },
+       { "Right Out 2", NULL, "Right Mixer" },
+       { "ROUT2", NULL, "Right Out 2" },
+};
+
+struct _coeff_div {
+       u32 mclk;
+       u32 rate;
+       u16 fs;
+       u8 sr:5;
+       u8 usb:1;
+};
+
+/* codec hifi mclk clock divider coefficients */
+static const struct _coeff_div coeff_div[] = {
+       /* 8k */
+       {12288000, 8000, 1536, 0x6, 0x0},
+       {11289600, 8000, 1408, 0x16, 0x0},
+       {18432000, 8000, 2304, 0x7, 0x0},
+       {16934400, 8000, 2112, 0x17, 0x0},
+       {12000000, 8000, 1500, 0x6, 0x1},
+
+       /* 11.025k */
+       {11289600, 11025, 1024, 0x18, 0x0},
+       {16934400, 11025, 1536, 0x19, 0x0},
+       {12000000, 11025, 1088, 0x19, 0x1},
+
+       /* 16k */
+       {12288000, 16000, 768, 0xa, 0x0},
+       {18432000, 16000, 1152, 0xb, 0x0},
+       {12000000, 16000, 750, 0xa, 0x1},
+
+       /* 22.05k */
+       {11289600, 22050, 512, 0x1a, 0x0},
+       {16934400, 22050, 768, 0x1b, 0x0},
+       {12000000, 22050, 544, 0x1b, 0x1},
+
+       /* 32k */
+       {12288000, 32000, 384, 0xc, 0x0},
+       {18432000, 32000, 576, 0xd, 0x0},
+       {12000000, 32000, 375, 0xa, 0x1},
+
+       /* 44.1k */
+       {11289600, 44100, 256, 0x10, 0x0},
+       {16934400, 44100, 384, 0x11, 0x0},
+       {12000000, 44100, 272, 0x11, 0x1},
+
+       /* 48k */
+       {12288000, 48000, 256, 0x0, 0x0},
+       {18432000, 48000, 384, 0x1, 0x0},
+       {12000000, 48000, 250, 0x0, 0x1},
+
+       /* 88.2k */
+       {11289600, 88200, 128, 0x1e, 0x0},
+       {16934400, 88200, 192, 0x1f, 0x0},
+       {12000000, 88200, 136, 0x1f, 0x1},
+
+       /* 96k */
+       {12288000, 96000, 128, 0xe, 0x0},
+       {18432000, 96000, 192, 0xf, 0x0},
+       {12000000, 96000, 125, 0xe, 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 -EINVAL;
+}
+
+/* The set of rates we can generate from the above for each SYSCLK */
+
+static unsigned int rates_12288[] = {
+       8000, 12000, 16000, 24000, 24000, 32000, 48000, 96000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_12288 = {
+       .count  = ARRAY_SIZE(rates_12288),
+       .list   = rates_12288,
+};
+
+static unsigned int rates_112896[] = {
+       8000, 11025, 22050, 44100,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_112896 = {
+       .count  = ARRAY_SIZE(rates_112896),
+       .list   = rates_112896,
+};
+
+static unsigned int rates_12[] = {
+       8000, 11025, 12000, 16000, 22050, 2400, 32000, 41100, 48000,
+       48000, 88235, 96000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_12 = {
+       .count  = ARRAY_SIZE(rates_12),
+       .list   = rates_12,
+};
+
+/*
+ * Note that this should be called from init rather than from hw_params.
+ */
+static int wm8988_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 wm8988_priv *wm8988 = codec->private_data;
+
+       switch (freq) {
+       case 11289600:
+       case 18432000:
+       case 22579200:
+       case 36864000:
+               wm8988->sysclk_constraints = &constraints_112896;
+               wm8988->sysclk = freq;
+               return 0;
+
+       case 12288000:
+       case 16934400:
+       case 24576000:
+       case 33868800:
+               wm8988->sysclk_constraints = &constraints_12288;
+               wm8988->sysclk = freq;
+               return 0;
+
+       case 12000000:
+       case 24000000:
+               wm8988->sysclk_constraints = &constraints_12;
+               wm8988->sysclk = freq;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int wm8988_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;
+       }
+
+       wm8988_write(codec, WM8988_IFACE, iface);
+       return 0;
+}
+
+static int wm8988_pcm_startup(struct snd_pcm_substream *substream,
+                             struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm8988_priv *wm8988 = codec->private_data;
+
+       /* The set of sample rates that can be supported depends on the
+        * MCLK supplied to the CODEC - enforce this.
+        */
+       if (!wm8988->sysclk) {
+               dev_err(codec->dev,
+                       "No MCLK configured, call set_sysclk() on init\n");
+               return -EINVAL;
+       }
+
+       snd_pcm_hw_constraint_list(substream->runtime, 0,
+                                  SNDRV_PCM_HW_PARAM_RATE,
+                                  wm8988->sysclk_constraints);
+
+       return 0;
+}
+
+static int wm8988_pcm_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;
+       struct wm8988_priv *wm8988 = codec->private_data;
+       u16 iface = wm8988_read_reg_cache(codec, WM8988_IFACE) & 0x1f3;
+       u16 srate = wm8988_read_reg_cache(codec, WM8988_SRATE) & 0x180;
+       int coeff;
+
+       coeff = get_coeff(wm8988->sysclk, params_rate(params));
+       if (coeff < 0) {
+               coeff = get_coeff(wm8988->sysclk / 2, params_rate(params));
+               srate |= 0x40;
+       }
+       if (coeff < 0) {
+               dev_err(codec->dev,
+                       "Unable to configure sample rate %dHz with %dHz MCLK\n",
+                       params_rate(params), wm8988->sysclk);
+               return coeff;
+       }
+
+       /* 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;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               iface |= 0x000c;
+               break;
+       }
+
+       /* set iface & srate */
+       wm8988_write(codec, WM8988_IFACE, iface);
+       if (coeff >= 0)
+               wm8988_write(codec, WM8988_SRATE, srate |
+                       (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb);
+
+       return 0;
+}
+
+static int wm8988_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       u16 mute_reg = wm8988_read_reg_cache(codec, WM8988_ADCDAC) & 0xfff7;
+
+       if (mute)
+               wm8988_write(codec, WM8988_ADCDAC, mute_reg | 0x8);
+       else
+               wm8988_write(codec, WM8988_ADCDAC, mute_reg);
+       return 0;
+}
+
+static int wm8988_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       u16 pwr_reg = wm8988_read_reg_cache(codec, WM8988_PWR1) & ~0x1c1;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+
+       case SND_SOC_BIAS_PREPARE:
+               /* VREF, VMID=2x50k, digital enabled */
+               wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x00c0);
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       /* VREF, VMID=2x5k */
+                       wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x1c1);
+
+                       /* Charge caps */
+                       msleep(100);
+               }
+
+               /* VREF, VMID=2*500k, digital stopped */
+               wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x0141);
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               wm8988_write(codec, WM8988_PWR1, 0x0000);
+               break;
+       }
+       codec->bias_level = level;
+       return 0;
+}
+
+#define WM8988_RATES SNDRV_PCM_RATE_8000_96000
+
+#define WM8988_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+       SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops wm8988_ops = {
+       .startup = wm8988_pcm_startup,
+       .hw_params = wm8988_pcm_hw_params,
+       .set_fmt = wm8988_set_dai_fmt,
+       .set_sysclk = wm8988_set_dai_sysclk,
+       .digital_mute = wm8988_mute,
+};
+
+struct snd_soc_dai wm8988_dai = {
+       .name = "WM8988",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = WM8988_RATES,
+               .formats = WM8988_FORMATS,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = WM8988_RATES,
+               .formats = WM8988_FORMATS,
+        },
+       .ops = &wm8988_ops,
+       .symmetric_rates = 1,
+};
+EXPORT_SYMBOL_GPL(wm8988_dai);
+
+static int wm8988_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;
+
+       wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int wm8988_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 < WM8988_NUM_REG; i++) {
+               if (i == WM8988_RESET)
+                       continue;
+               data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
+               data[1] = cache[i] & 0x00ff;
+               codec->hw_write(codec->control_data, data, 2);
+       }
+
+       wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       return 0;
+}
+
+static struct snd_soc_codec *wm8988_codec;
+
+static int wm8988_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec;
+       int ret = 0;
+
+       if (wm8988_codec == NULL) {
+               dev_err(&pdev->dev, "Codec device not registered\n");
+               return -ENODEV;
+       }
+
+       socdev->card->codec = wm8988_codec;
+       codec = wm8988_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, wm8988_snd_controls,
+                               ARRAY_SIZE(wm8988_snd_controls));
+       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;
+}
+
+static int wm8988_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_wm8988 = {
+       .probe =        wm8988_probe,
+       .remove =       wm8988_remove,
+       .suspend =      wm8988_suspend,
+       .resume =       wm8988_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8988);
+
+static int wm8988_register(struct wm8988_priv *wm8988)
+{
+       struct snd_soc_codec *codec = &wm8988->codec;
+       int ret;
+       u16 reg;
+
+       if (wm8988_codec) {
+               dev_err(codec->dev, "Another WM8988 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 = wm8988;
+       codec->name = "WM8988";
+       codec->owner = THIS_MODULE;
+       codec->read = wm8988_read_reg_cache;
+       codec->write = wm8988_write;
+       codec->dai = &wm8988_dai;
+       codec->num_dai = 1;
+       codec->reg_cache_size = ARRAY_SIZE(wm8988->reg_cache);
+       codec->reg_cache = &wm8988->reg_cache;
+       codec->bias_level = SND_SOC_BIAS_OFF;
+       codec->set_bias_level = wm8988_set_bias_level;
+
+       memcpy(codec->reg_cache, wm8988_reg,
+              sizeof(wm8988_reg));
+
+       ret = wm8988_reset(codec);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to issue reset\n");
+               return ret;
+       }
+
+       /* set the update bits (we always update left then right) */
+       reg = wm8988_read_reg_cache(codec, WM8988_RADC);
+       wm8988_write(codec, WM8988_RADC, reg | 0x100);
+       reg = wm8988_read_reg_cache(codec, WM8988_RDAC);
+       wm8988_write(codec, WM8988_RDAC, reg | 0x0100);
+       reg = wm8988_read_reg_cache(codec, WM8988_ROUT1V);
+       wm8988_write(codec, WM8988_ROUT1V, reg | 0x0100);
+       reg = wm8988_read_reg_cache(codec, WM8988_ROUT2V);
+       wm8988_write(codec, WM8988_ROUT2V, reg | 0x0100);
+       reg = wm8988_read_reg_cache(codec, WM8988_RINVOL);
+       wm8988_write(codec, WM8988_RINVOL, reg | 0x0100);
+
+       wm8988_set_bias_level(&wm8988->codec, SND_SOC_BIAS_STANDBY);
+
+       wm8988_dai.dev = codec->dev;
+
+       wm8988_codec = codec;
+
+       ret = snd_soc_register_codec(codec);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_register_dai(&wm8988_dai);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+               snd_soc_unregister_codec(codec);
+               return ret;
+       }
+
+       return 0;
+
+err:
+       kfree(wm8988);
+       return ret;
+}
+
+static void wm8988_unregister(struct wm8988_priv *wm8988)
+{
+       wm8988_set_bias_level(&wm8988->codec, SND_SOC_BIAS_OFF);
+       snd_soc_unregister_dai(&wm8988_dai);
+       snd_soc_unregister_codec(&wm8988->codec);
+       kfree(wm8988);
+       wm8988_codec = NULL;
+}
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static int wm8988_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
+{
+       struct wm8988_priv *wm8988;
+       struct snd_soc_codec *codec;
+
+       wm8988 = kzalloc(sizeof(struct wm8988_priv), GFP_KERNEL);
+       if (wm8988 == NULL)
+               return -ENOMEM;
+
+       codec = &wm8988->codec;
+       codec->hw_write = (hw_write_t)i2c_master_send;
+
+       i2c_set_clientdata(i2c, wm8988);
+       codec->control_data = i2c;
+
+       codec->dev = &i2c->dev;
+
+       return wm8988_register(wm8988);
+}
+
+static int wm8988_i2c_remove(struct i2c_client *client)
+{
+       struct wm8988_priv *wm8988 = i2c_get_clientdata(client);
+       wm8988_unregister(wm8988);
+       return 0;
+}
+
+static const struct i2c_device_id wm8988_i2c_id[] = {
+       { "wm8988", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8988_i2c_id);
+
+static struct i2c_driver wm8988_i2c_driver = {
+       .driver = {
+               .name = "WM8988",
+               .owner = THIS_MODULE,
+       },
+       .probe = wm8988_i2c_probe,
+       .remove = wm8988_i2c_remove,
+       .id_table = wm8988_i2c_id,
+};
+#endif
+
+#if defined(CONFIG_SPI_MASTER)
+static int wm8988_spi_write(struct spi_device *spi, const char *data, int len)
+{
+       struct spi_transfer t;
+       struct spi_message m;
+       u8 msg[2];
+
+       if (len <= 0)
+               return 0;
+
+       msg[0] = data[0];
+       msg[1] = data[1];
+
+       spi_message_init(&m);
+       memset(&t, 0, (sizeof t));
+
+       t.tx_buf = &msg[0];
+       t.len = len;
+
+       spi_message_add_tail(&t, &m);
+       spi_sync(spi, &m);
+
+       return len;
+}
+
+static int __devinit wm8988_spi_probe(struct spi_device *spi)
+{
+       struct wm8988_priv *wm8988;
+       struct snd_soc_codec *codec;
+
+       wm8988 = kzalloc(sizeof(struct wm8988_priv), GFP_KERNEL);
+       if (wm8988 == NULL)
+               return -ENOMEM;
+
+       codec = &wm8988->codec;
+       codec->hw_write = (hw_write_t)wm8988_spi_write;
+       codec->control_data = spi;
+       codec->dev = &spi->dev;
+
+       spi->dev.driver_data = wm8988;
+
+       return wm8988_register(wm8988);
+}
+
+static int __devexit wm8988_spi_remove(struct spi_device *spi)
+{
+       struct wm8988_priv *wm8988 = spi->dev.driver_data;
+
+       wm8988_unregister(wm8988);
+
+       return 0;
+}
+
+static struct spi_driver wm8988_spi_driver = {
+       .driver = {
+               .name   = "wm8988",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = wm8988_spi_probe,
+       .remove         = __devexit_p(wm8988_spi_remove),
+};
+#endif
+
+static int __init wm8988_modinit(void)
+{
+       int ret;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&wm8988_i2c_driver);
+       if (ret != 0)
+               pr_err("WM8988: Unable to register I2C driver: %d\n", ret);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       ret = spi_register_driver(&wm8988_spi_driver);
+       if (ret != 0)
+               pr_err("WM8988: Unable to register SPI driver: %d\n", ret);
+#endif
+       return ret;
+}
+module_init(wm8988_modinit);
+
+static void __exit wm8988_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&wm8988_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       spi_unregister_driver(&wm8988_spi_driver);
+#endif
+}
+module_exit(wm8988_exit);
+
+
+MODULE_DESCRIPTION("ASoC WM8988 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8988.h b/sound/soc/codecs/wm8988.h
new file mode 100644 (file)
index 0000000..4552d37
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@openedhand.com>
+ *
+ * Based on WM8753.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 _WM8988_H
+#define _WM8988_H
+
+/* WM8988 register space */
+
+#define WM8988_LINVOL    0x00
+#define WM8988_RINVOL    0x01
+#define WM8988_LOUT1V    0x02
+#define WM8988_ROUT1V    0x03
+#define WM8988_ADCDAC    0x05
+#define WM8988_IFACE     0x07
+#define WM8988_SRATE     0x08
+#define WM8988_LDAC      0x0a
+#define WM8988_RDAC      0x0b
+#define WM8988_BASS      0x0c
+#define WM8988_TREBLE    0x0d
+#define WM8988_RESET     0x0f
+#define WM8988_3D        0x10
+#define WM8988_ALC1      0x11
+#define WM8988_ALC2      0x12
+#define WM8988_ALC3      0x13
+#define WM8988_NGATE     0x14
+#define WM8988_LADC      0x15
+#define WM8988_RADC      0x16
+#define WM8988_ADCTL1    0x17
+#define WM8988_ADCTL2    0x18
+#define WM8988_PWR1      0x19
+#define WM8988_PWR2      0x1a
+#define WM8988_ADCTL3    0x1b
+#define WM8988_ADCIN     0x1f
+#define WM8988_LADCIN    0x20
+#define WM8988_RADCIN    0x21
+#define WM8988_LOUTM1    0x22
+#define WM8988_LOUTM2    0x23
+#define WM8988_ROUTM1    0x24
+#define WM8988_ROUTM2    0x25
+#define WM8988_LOUT2V    0x28
+#define WM8988_ROUT2V    0x29
+#define WM8988_LPPB      0x43
+#define WM8988_NUM_REG   0x44
+
+#define WM8988_SYSCLK  0
+
+extern struct snd_soc_dai wm8988_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8988;
+
+#endif
index 40cd274eb1ef51f60588ffaf7ba09e6c44f10a1f..d029818350e9fe9d5778c3fbb4087b0245d58023 100644 (file)
@@ -998,7 +998,7 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target,
 
        if ((Ndiv < 6) || (Ndiv > 12))
                printk(KERN_WARNING
-               "WM8990 N value outwith recommended range! N = %d\n", Ndiv);
+               "WM8990 N value outwith recommended range! N = %u\n", Ndiv);
 
        pll_div->n = Ndiv;
        Nmod = target % source;
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
new file mode 100644 (file)
index 0000000..86fc57e
--- /dev/null
@@ -0,0 +1,1534 @@
+/*
+ * wm9081.c  --  WM9081 ALSA SoC Audio driver
+ *
+ * Author: Mark Brown
+ *
+ * Copyright 2009 Wolfson Microelectronics plc
+ *
+ * This 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 <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/wm9081.h>
+#include "wm9081.h"
+
+static u16 wm9081_reg_defaults[] = {
+       0x0000,     /* R0  - Software Reset */
+       0x0000,     /* R1 */
+       0x00B9,     /* R2  - Analogue Lineout */
+       0x00B9,     /* R3  - Analogue Speaker PGA */
+       0x0001,     /* R4  - VMID Control */
+       0x0068,     /* R5  - Bias Control 1 */
+       0x0000,     /* R6 */
+       0x0000,     /* R7  - Analogue Mixer */
+       0x0000,     /* R8  - Anti Pop Control */
+       0x01DB,     /* R9  - Analogue Speaker 1 */
+       0x0018,     /* R10 - Analogue Speaker 2 */
+       0x0180,     /* R11 - Power Management */
+       0x0000,     /* R12 - Clock Control 1 */
+       0x0038,     /* R13 - Clock Control 2 */
+       0x4000,     /* R14 - Clock Control 3 */
+       0x0000,     /* R15 */
+       0x0000,     /* R16 - FLL Control 1 */
+       0x0200,     /* R17 - FLL Control 2 */
+       0x0000,     /* R18 - FLL Control 3 */
+       0x0204,     /* R19 - FLL Control 4 */
+       0x0000,     /* R20 - FLL Control 5 */
+       0x0000,     /* R21 */
+       0x0000,     /* R22 - Audio Interface 1 */
+       0x0002,     /* R23 - Audio Interface 2 */
+       0x0008,     /* R24 - Audio Interface 3 */
+       0x0022,     /* R25 - Audio Interface 4 */
+       0x0000,     /* R26 - Interrupt Status */
+       0x0006,     /* R27 - Interrupt Status Mask */
+       0x0000,     /* R28 - Interrupt Polarity */
+       0x0000,     /* R29 - Interrupt Control */
+       0x00C0,     /* R30 - DAC Digital 1 */
+       0x0008,     /* R31 - DAC Digital 2 */
+       0x09AF,     /* R32 - DRC 1 */
+       0x4201,     /* R33 - DRC 2 */
+       0x0000,     /* R34 - DRC 3 */
+       0x0000,     /* R35 - DRC 4 */
+       0x0000,     /* R36 */
+       0x0000,     /* R37 */
+       0x0000,     /* R38 - Write Sequencer 1 */
+       0x0000,     /* R39 - Write Sequencer 2 */
+       0x0002,     /* R40 - MW Slave 1 */
+       0x0000,     /* R41 */
+       0x0000,     /* R42 - EQ 1 */
+       0x0000,     /* R43 - EQ 2 */
+       0x0FCA,     /* R44 - EQ 3 */
+       0x0400,     /* R45 - EQ 4 */
+       0x00B8,     /* R46 - EQ 5 */
+       0x1EB5,     /* R47 - EQ 6 */
+       0xF145,     /* R48 - EQ 7 */
+       0x0B75,     /* R49 - EQ 8 */
+       0x01C5,     /* R50 - EQ 9 */
+       0x169E,     /* R51 - EQ 10 */
+       0xF829,     /* R52 - EQ 11 */
+       0x07AD,     /* R53 - EQ 12 */
+       0x1103,     /* R54 - EQ 13 */
+       0x1C58,     /* R55 - EQ 14 */
+       0xF373,     /* R56 - EQ 15 */
+       0x0A54,     /* R57 - EQ 16 */
+       0x0558,     /* R58 - EQ 17 */
+       0x0564,     /* R59 - EQ 18 */
+       0x0559,     /* R60 - EQ 19 */
+       0x4000,     /* R61 - EQ 20 */
+};
+
+static struct {
+       int ratio;
+       int clk_sys_rate;
+} clk_sys_rates[] = {
+       { 64,   0 },
+       { 128,  1 },
+       { 192,  2 },
+       { 256,  3 },
+       { 384,  4 },
+       { 512,  5 },
+       { 768,  6 },
+       { 1024, 7 },
+       { 1408, 8 },
+       { 1536, 9 },
+};
+
+static struct {
+       int rate;
+       int sample_rate;
+} sample_rates[] = {
+       { 8000,  0  },
+       { 11025, 1  },
+       { 12000, 2  },
+       { 16000, 3  },
+       { 22050, 4  },
+       { 24000, 5  },
+       { 32000, 6  },
+       { 44100, 7  },
+       { 48000, 8  },
+       { 88200, 9  },
+       { 96000, 10 },
+};
+
+static struct {
+       int div; /* *10 due to .5s */
+       int bclk_div;
+} bclk_divs[] = {
+       { 10,  0  },
+       { 15,  1  },
+       { 20,  2  },
+       { 30,  3  },
+       { 40,  4  },
+       { 50,  5  },
+       { 55,  6  },
+       { 60,  7  },
+       { 80,  8  },
+       { 100, 9  },
+       { 110, 10 },
+       { 120, 11 },
+       { 160, 12 },
+       { 200, 13 },
+       { 220, 14 },
+       { 240, 15 },
+       { 250, 16 },
+       { 300, 17 },
+       { 320, 18 },
+       { 440, 19 },
+       { 480, 20 },
+};
+
+struct wm9081_priv {
+       struct snd_soc_codec codec;
+       u16 reg_cache[WM9081_MAX_REGISTER + 1];
+       int sysclk_source;
+       int mclk_rate;
+       int sysclk_rate;
+       int fs;
+       int bclk;
+       int master;
+       int fll_fref;
+       int fll_fout;
+       struct wm9081_retune_mobile_config *retune;
+};
+
+static int wm9081_reg_is_volatile(int reg)
+{
+       switch (reg) {
+       default:
+               return 0;
+       }
+}
+
+static unsigned int wm9081_read_reg_cache(struct snd_soc_codec *codec,
+                                         unsigned int reg)
+{
+       u16 *cache = codec->reg_cache;
+       BUG_ON(reg > WM9081_MAX_REGISTER);
+       return cache[reg];
+}
+
+static unsigned int wm9081_read_hw(struct snd_soc_codec *codec, u8 reg)
+{
+       struct i2c_msg xfer[2];
+       u16 data;
+       int ret;
+       struct i2c_client *client = codec->control_data;
+
+       BUG_ON(reg > WM9081_MAX_REGISTER);
+
+       /* Write register */
+       xfer[0].addr = client->addr;
+       xfer[0].flags = 0;
+       xfer[0].len = 1;
+       xfer[0].buf = &reg;
+
+       /* Read data */
+       xfer[1].addr = client->addr;
+       xfer[1].flags = I2C_M_RD;
+       xfer[1].len = 2;
+       xfer[1].buf = (u8 *)&data;
+
+       ret = i2c_transfer(client->adapter, xfer, 2);
+       if (ret != 2) {
+               dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
+               return 0;
+       }
+
+       return (data >> 8) | ((data & 0xff) << 8);
+}
+
+static unsigned int wm9081_read(struct snd_soc_codec *codec, unsigned int reg)
+{
+       if (wm9081_reg_is_volatile(reg))
+               return wm9081_read_hw(codec, reg);
+       else
+               return wm9081_read_reg_cache(codec, reg);
+}
+
+static int wm9081_write(struct snd_soc_codec *codec, unsigned int reg,
+                       unsigned int value)
+{
+       u16 *cache = codec->reg_cache;
+       u8 data[3];
+
+       BUG_ON(reg > WM9081_MAX_REGISTER);
+
+       if (!wm9081_reg_is_volatile(reg))
+               cache[reg] = value;
+
+       data[0] = reg;
+       data[1] = value >> 8;
+       data[2] = value & 0x00ff;
+
+       if (codec->hw_write(codec->control_data, data, 3) == 3)
+               return 0;
+       else
+               return -EIO;
+}
+
+static int wm9081_reset(struct snd_soc_codec *codec)
+{
+       return wm9081_write(codec, WM9081_SOFTWARE_RESET, 0);
+}
+
+static const DECLARE_TLV_DB_SCALE(drc_in_tlv, -4500, 75, 0);
+static const DECLARE_TLV_DB_SCALE(drc_out_tlv, -2250, 75, 0);
+static const DECLARE_TLV_DB_SCALE(drc_min_tlv, -1800, 600, 0);
+static unsigned int drc_max_tlv[] = {
+       TLV_DB_RANGE_HEAD(4),
+       0, 0, TLV_DB_SCALE_ITEM(1200, 0, 0),
+       1, 1, TLV_DB_SCALE_ITEM(1800, 0, 0),
+       2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
+       3, 3, TLV_DB_SCALE_ITEM(3600, 0, 0),
+};
+static const DECLARE_TLV_DB_SCALE(drc_qr_tlv, 1200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(drc_startup_tlv, -300, 50, 0);
+
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+
+static const DECLARE_TLV_DB_SCALE(in_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -7200, 75, 1);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
+
+static const char *drc_high_text[] = {
+       "1",
+       "1/2",
+       "1/4",
+       "1/8",
+       "1/16",
+       "0",
+};
+
+static const struct soc_enum drc_high =
+       SOC_ENUM_SINGLE(WM9081_DRC_3, 3, 6, drc_high_text);
+
+static const char *drc_low_text[] = {
+       "1",
+       "1/2",
+       "1/4",
+       "1/8",
+       "0",
+};
+
+static const struct soc_enum drc_low =
+       SOC_ENUM_SINGLE(WM9081_DRC_3, 0, 5, drc_low_text);
+
+static const char *drc_atk_text[] = {
+       "181us",
+       "181us",
+       "363us",
+       "726us",
+       "1.45ms",
+       "2.9ms",
+       "5.8ms",
+       "11.6ms",
+       "23.2ms",
+       "46.4ms",
+       "92.8ms",
+       "185.6ms",
+};
+
+static const struct soc_enum drc_atk =
+       SOC_ENUM_SINGLE(WM9081_DRC_2, 12, 12, drc_atk_text);
+
+static const char *drc_dcy_text[] = {
+       "186ms",
+       "372ms",
+       "743ms",
+       "1.49s",
+       "2.97s",
+       "5.94s",
+       "11.89s",
+       "23.78s",
+       "47.56s",
+};
+
+static const struct soc_enum drc_dcy =
+       SOC_ENUM_SINGLE(WM9081_DRC_2, 8, 9, drc_dcy_text);
+
+static const char *drc_qr_dcy_text[] = {
+       "0.725ms",
+       "1.45ms",
+       "5.8ms",
+};
+
+static const struct soc_enum drc_qr_dcy =
+       SOC_ENUM_SINGLE(WM9081_DRC_2, 4, 3, drc_qr_dcy_text);
+
+static const char *dac_deemph_text[] = {
+       "None",
+       "32kHz",
+       "44.1kHz",
+       "48kHz",
+};
+
+static const struct soc_enum dac_deemph =
+       SOC_ENUM_SINGLE(WM9081_DAC_DIGITAL_2, 1, 4, dac_deemph_text);
+
+static const char *speaker_mode_text[] = {
+       "Class D",
+       "Class AB",
+};
+
+static const struct soc_enum speaker_mode =
+       SOC_ENUM_SINGLE(WM9081_ANALOGUE_SPEAKER_2, 6, 2, speaker_mode_text);
+
+static int speaker_mode_get(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int reg;
+
+       reg = wm9081_read(codec, WM9081_ANALOGUE_SPEAKER_2);
+       if (reg & WM9081_SPK_MODE)
+               ucontrol->value.integer.value[0] = 1;
+       else
+               ucontrol->value.integer.value[0] = 0;
+
+       return 0;
+}
+
+/*
+ * Stop any attempts to change speaker mode while the speaker is enabled.
+ *
+ * We also have some special anti-pop controls dependant on speaker
+ * mode which must be changed along with the mode.
+ */
+static int speaker_mode_put(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int reg_pwr = wm9081_read(codec, WM9081_POWER_MANAGEMENT);
+       unsigned int reg2 = wm9081_read(codec, WM9081_ANALOGUE_SPEAKER_2);
+
+       /* Are we changing anything? */
+       if (ucontrol->value.integer.value[0] ==
+           ((reg2 & WM9081_SPK_MODE) != 0))
+               return 0;
+
+       /* Don't try to change modes while enabled */
+       if (reg_pwr & WM9081_SPK_ENA)
+               return -EINVAL;
+
+       if (ucontrol->value.integer.value[0]) {
+               /* Class AB */
+               reg2 &= ~(WM9081_SPK_INV_MUTE | WM9081_OUT_SPK_CTRL);
+               reg2 |= WM9081_SPK_MODE;
+       } else {
+               /* Class D */
+               reg2 |= WM9081_SPK_INV_MUTE | WM9081_OUT_SPK_CTRL;
+               reg2 &= ~WM9081_SPK_MODE;
+       }
+
+       wm9081_write(codec, WM9081_ANALOGUE_SPEAKER_2, reg2);
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new wm9081_snd_controls[] = {
+SOC_SINGLE_TLV("IN1 Volume", WM9081_ANALOGUE_MIXER, 1, 1, 1, in_tlv),
+SOC_SINGLE_TLV("IN2 Volume", WM9081_ANALOGUE_MIXER, 3, 1, 1, in_tlv),
+
+SOC_SINGLE_TLV("Playback Volume", WM9081_DAC_DIGITAL_1, 1, 96, 0, dac_tlv),
+
+SOC_SINGLE("LINEOUT Switch", WM9081_ANALOGUE_LINEOUT, 7, 1, 1),
+SOC_SINGLE("LINEOUT ZC Switch", WM9081_ANALOGUE_LINEOUT, 6, 1, 0),
+SOC_SINGLE_TLV("LINEOUT Volume", WM9081_ANALOGUE_LINEOUT, 0, 63, 0, out_tlv),
+
+SOC_SINGLE("DRC Switch", WM9081_DRC_1, 15, 1, 0),
+SOC_ENUM("DRC High Slope", drc_high),
+SOC_ENUM("DRC Low Slope", drc_low),
+SOC_SINGLE_TLV("DRC Input Volume", WM9081_DRC_4, 5, 60, 1, drc_in_tlv),
+SOC_SINGLE_TLV("DRC Output Volume", WM9081_DRC_4, 0, 30, 1, drc_out_tlv),
+SOC_SINGLE_TLV("DRC Minimum Volume", WM9081_DRC_2, 2, 3, 1, drc_min_tlv),
+SOC_SINGLE_TLV("DRC Maximum Volume", WM9081_DRC_2, 0, 3, 0, drc_max_tlv),
+SOC_ENUM("DRC Attack", drc_atk),
+SOC_ENUM("DRC Decay", drc_dcy),
+SOC_SINGLE("DRC Quick Release Switch", WM9081_DRC_1, 2, 1, 0),
+SOC_SINGLE_TLV("DRC Quick Release Volume", WM9081_DRC_2, 6, 3, 0, drc_qr_tlv),
+SOC_ENUM("DRC Quick Release Decay", drc_qr_dcy),
+SOC_SINGLE_TLV("DRC Startup Volume", WM9081_DRC_1, 6, 18, 0, drc_startup_tlv),
+
+SOC_SINGLE("EQ Switch", WM9081_EQ_1, 0, 1, 0),
+
+SOC_SINGLE("Speaker DC Volume", WM9081_ANALOGUE_SPEAKER_1, 3, 5, 0),
+SOC_SINGLE("Speaker AC Volume", WM9081_ANALOGUE_SPEAKER_1, 0, 5, 0),
+SOC_SINGLE("Speaker Switch", WM9081_ANALOGUE_SPEAKER_PGA, 7, 1, 1),
+SOC_SINGLE("Speaker ZC Switch", WM9081_ANALOGUE_SPEAKER_PGA, 6, 1, 0),
+SOC_SINGLE_TLV("Speaker Volume", WM9081_ANALOGUE_SPEAKER_PGA, 0, 63, 0,
+              out_tlv),
+SOC_ENUM("DAC Deemphasis", dac_deemph),
+SOC_ENUM_EXT("Speaker Mode", speaker_mode, speaker_mode_get, speaker_mode_put),
+};
+
+static const struct snd_kcontrol_new wm9081_eq_controls[] = {
+SOC_SINGLE_TLV("EQ1 Volume", WM9081_EQ_1, 11, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 Volume", WM9081_EQ_1, 6, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 Volume", WM9081_EQ_1, 1, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 Volume", WM9081_EQ_2, 11, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ5 Volume", WM9081_EQ_2, 6, 24, 0, eq_tlv),
+};
+
+static const struct snd_kcontrol_new mixer[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM9081_ANALOGUE_MIXER, 0, 1, 0),
+SOC_DAPM_SINGLE("IN2 Switch", WM9081_ANALOGUE_MIXER, 2, 1, 0),
+SOC_DAPM_SINGLE("Playback Switch", WM9081_ANALOGUE_MIXER, 4, 1, 0),
+};
+
+static int speaker_event(struct snd_soc_dapm_widget *w,
+                        struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       unsigned int reg = wm9081_read(codec, WM9081_POWER_MANAGEMENT);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               reg |= WM9081_SPK_ENA;
+               break;
+
+       case SND_SOC_DAPM_PRE_PMD:
+               reg &= ~WM9081_SPK_ENA;
+               break;
+       }
+
+       wm9081_write(codec, WM9081_POWER_MANAGEMENT, reg);
+
+       return 0;
+}
+
+struct _fll_div {
+       u16 fll_fratio;
+       u16 fll_outdiv;
+       u16 fll_clk_ref_div;
+       u16 n;
+       u16 k;
+};
+
+/* The size in bits of the FLL divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_FLL_SIZE ((1 << 16) * 10)
+
+static struct {
+       unsigned int min;
+       unsigned int max;
+       u16 fll_fratio;
+       int ratio;
+} fll_fratios[] = {
+       {       0,    64000, 4, 16 },
+       {   64000,   128000, 3,  8 },
+       {  128000,   256000, 2,  4 },
+       {  256000,  1000000, 1,  2 },
+       { 1000000, 13500000, 0,  1 },
+};
+
+static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
+                      unsigned int Fout)
+{
+       u64 Kpart;
+       unsigned int K, Ndiv, Nmod, target;
+       unsigned int div;
+       int i;
+
+       /* Fref must be <=13.5MHz */
+       div = 1;
+       while ((Fref / div) > 13500000) {
+               div *= 2;
+
+               if (div > 8) {
+                       pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
+                              Fref);
+                       return -EINVAL;
+               }
+       }
+       fll_div->fll_clk_ref_div = div / 2;
+
+       pr_debug("Fref=%u Fout=%u\n", Fref, Fout);
+
+       /* Apply the division for our remaining calculations */
+       Fref /= div;
+
+       /* Fvco should be 90-100MHz; don't check the upper bound */
+       div = 0;
+       target = Fout * 2;
+       while (target < 90000000) {
+               div++;
+               target *= 2;
+               if (div > 7) {
+                       pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
+                              Fout);
+                       return -EINVAL;
+               }
+       }
+       fll_div->fll_outdiv = div;
+
+       pr_debug("Fvco=%dHz\n", target);
+
+       /* Find an appropraite FLL_FRATIO and factor it out of the target */
+       for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
+               if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
+                       fll_div->fll_fratio = fll_fratios[i].fll_fratio;
+                       target /= fll_fratios[i].ratio;
+                       break;
+               }
+       }
+       if (i == ARRAY_SIZE(fll_fratios)) {
+               pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
+               return -EINVAL;
+       }
+
+       /* Now, calculate N.K */
+       Ndiv = target / Fref;
+
+       fll_div->n = Ndiv;
+       Nmod = target % Fref;
+       pr_debug("Nmod=%d\n", Nmod);
+
+       /* Calculate fractional part - scale up so we can round. */
+       Kpart = FIXED_FLL_SIZE * (long long)Nmod;
+
+       do_div(Kpart, Fref);
+
+       K = Kpart & 0xFFFFFFFF;
+
+       if ((K % 10) >= 5)
+               K += 5;
+
+       /* Move down to proper range now rounding is done */
+       fll_div->k = K / 10;
+
+       pr_debug("N=%x K=%x FLL_FRATIO=%x FLL_OUTDIV=%x FLL_CLK_REF_DIV=%x\n",
+                fll_div->n, fll_div->k,
+                fll_div->fll_fratio, fll_div->fll_outdiv,
+                fll_div->fll_clk_ref_div);
+
+       return 0;
+}
+
+static int wm9081_set_fll(struct snd_soc_codec *codec, int fll_id,
+                         unsigned int Fref, unsigned int Fout)
+{
+       struct wm9081_priv *wm9081 = codec->private_data;
+       u16 reg1, reg4, reg5;
+       struct _fll_div fll_div;
+       int ret;
+       int clk_sys_reg;
+
+       /* Any change? */
+       if (Fref == wm9081->fll_fref && Fout == wm9081->fll_fout)
+               return 0;
+
+       /* Disable the FLL */
+       if (Fout == 0) {
+               dev_dbg(codec->dev, "FLL disabled\n");
+               wm9081->fll_fref = 0;
+               wm9081->fll_fout = 0;
+
+               return 0;
+       }
+
+       ret = fll_factors(&fll_div, Fref, Fout);
+       if (ret != 0)
+               return ret;
+
+       reg5 = wm9081_read(codec, WM9081_FLL_CONTROL_5);
+       reg5 &= ~WM9081_FLL_CLK_SRC_MASK;
+
+       switch (fll_id) {
+       case WM9081_SYSCLK_FLL_MCLK:
+               reg5 |= 0x1;
+               break;
+
+       default:
+               dev_err(codec->dev, "Unknown FLL ID %d\n", fll_id);
+               return -EINVAL;
+       }
+
+       /* Disable CLK_SYS while we reconfigure */
+       clk_sys_reg = wm9081_read(codec, WM9081_CLOCK_CONTROL_3);
+       if (clk_sys_reg & WM9081_CLK_SYS_ENA)
+               wm9081_write(codec, WM9081_CLOCK_CONTROL_3,
+                            clk_sys_reg & ~WM9081_CLK_SYS_ENA);
+
+       /* Any FLL configuration change requires that the FLL be
+        * disabled first. */
+       reg1 = wm9081_read(codec, WM9081_FLL_CONTROL_1);
+       reg1 &= ~WM9081_FLL_ENA;
+       wm9081_write(codec, WM9081_FLL_CONTROL_1, reg1);
+
+       /* Apply the configuration */
+       if (fll_div.k)
+               reg1 |= WM9081_FLL_FRAC_MASK;
+       else
+               reg1 &= ~WM9081_FLL_FRAC_MASK;
+       wm9081_write(codec, WM9081_FLL_CONTROL_1, reg1);
+
+       wm9081_write(codec, WM9081_FLL_CONTROL_2,
+                    (fll_div.fll_outdiv << WM9081_FLL_OUTDIV_SHIFT) |
+                    (fll_div.fll_fratio << WM9081_FLL_FRATIO_SHIFT));
+       wm9081_write(codec, WM9081_FLL_CONTROL_3, fll_div.k);
+
+       reg4 = wm9081_read(codec, WM9081_FLL_CONTROL_4);
+       reg4 &= ~WM9081_FLL_N_MASK;
+       reg4 |= fll_div.n << WM9081_FLL_N_SHIFT;
+       wm9081_write(codec, WM9081_FLL_CONTROL_4, reg4);
+
+       reg5 &= ~WM9081_FLL_CLK_REF_DIV_MASK;
+       reg5 |= fll_div.fll_clk_ref_div << WM9081_FLL_CLK_REF_DIV_SHIFT;
+       wm9081_write(codec, WM9081_FLL_CONTROL_5, reg5);
+
+       /* Enable the FLL */
+       wm9081_write(codec, WM9081_FLL_CONTROL_1, reg1 | WM9081_FLL_ENA);
+
+       /* Then bring CLK_SYS up again if it was disabled */
+       if (clk_sys_reg & WM9081_CLK_SYS_ENA)
+               wm9081_write(codec, WM9081_CLOCK_CONTROL_3, clk_sys_reg);
+
+       dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout);
+
+       wm9081->fll_fref = Fref;
+       wm9081->fll_fout = Fout;
+
+       return 0;
+}
+
+static int configure_clock(struct snd_soc_codec *codec)
+{
+       struct wm9081_priv *wm9081 = codec->private_data;
+       int new_sysclk, i, target;
+       unsigned int reg;
+       int ret = 0;
+       int mclkdiv = 0;
+       int fll = 0;
+
+       switch (wm9081->sysclk_source) {
+       case WM9081_SYSCLK_MCLK:
+               if (wm9081->mclk_rate > 12225000) {
+                       mclkdiv = 1;
+                       wm9081->sysclk_rate = wm9081->mclk_rate / 2;
+               } else {
+                       wm9081->sysclk_rate = wm9081->mclk_rate;
+               }
+               wm9081_set_fll(codec, WM9081_SYSCLK_FLL_MCLK, 0, 0);
+               break;
+
+       case WM9081_SYSCLK_FLL_MCLK:
+               /* If we have a sample rate calculate a CLK_SYS that
+                * gives us a suitable DAC configuration, plus BCLK.
+                * Ideally we would check to see if we can clock
+                * directly from MCLK and only use the FLL if this is
+                * not the case, though care must be taken with free
+                * running mode.
+                */
+               if (wm9081->master && wm9081->bclk) {
+                       /* Make sure we can generate CLK_SYS and BCLK
+                        * and that we've got 3MHz for optimal
+                        * performance. */
+                       for (i = 0; i < ARRAY_SIZE(clk_sys_rates); i++) {
+                               target = wm9081->fs * clk_sys_rates[i].ratio;
+                               new_sysclk = target;
+                               if (target >= wm9081->bclk &&
+                                   target > 3000000)
+                                       break;
+                       }
+               } else if (wm9081->fs) {
+                       for (i = 0; i < ARRAY_SIZE(clk_sys_rates); i++) {
+                               new_sysclk = clk_sys_rates[i].ratio
+                                       * wm9081->fs;
+                               if (new_sysclk > 3000000)
+                                       break;
+                       }
+               } else {
+                       new_sysclk = 12288000;
+               }
+
+               ret = wm9081_set_fll(codec, WM9081_SYSCLK_FLL_MCLK,
+                                    wm9081->mclk_rate, new_sysclk);
+               if (ret == 0) {
+                       wm9081->sysclk_rate = new_sysclk;
+
+                       /* Switch SYSCLK over to FLL */
+                       fll = 1;
+               } else {
+                       wm9081->sysclk_rate = wm9081->mclk_rate;
+               }
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       reg = wm9081_read(codec, WM9081_CLOCK_CONTROL_1);
+       if (mclkdiv)
+               reg |= WM9081_MCLKDIV2;
+       else
+               reg &= ~WM9081_MCLKDIV2;
+       wm9081_write(codec, WM9081_CLOCK_CONTROL_1, reg);
+
+       reg = wm9081_read(codec, WM9081_CLOCK_CONTROL_3);
+       if (fll)
+               reg |= WM9081_CLK_SRC_SEL;
+       else
+               reg &= ~WM9081_CLK_SRC_SEL;
+       wm9081_write(codec, WM9081_CLOCK_CONTROL_3, reg);
+
+       dev_dbg(codec->dev, "CLK_SYS is %dHz\n", wm9081->sysclk_rate);
+
+       return ret;
+}
+
+static int clk_sys_event(struct snd_soc_dapm_widget *w,
+                        struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct wm9081_priv *wm9081 = codec->private_data;
+
+       /* This should be done on init() for bypass paths */
+       switch (wm9081->sysclk_source) {
+       case WM9081_SYSCLK_MCLK:
+               dev_dbg(codec->dev, "Using %dHz MCLK\n", wm9081->mclk_rate);
+               break;
+       case WM9081_SYSCLK_FLL_MCLK:
+               dev_dbg(codec->dev, "Using %dHz MCLK with FLL\n",
+                       wm9081->mclk_rate);
+               break;
+       default:
+               dev_err(codec->dev, "System clock not configured\n");
+               return -EINVAL;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               configure_clock(codec);
+               break;
+
+       case SND_SOC_DAPM_POST_PMD:
+               /* Disable the FLL if it's running */
+               wm9081_set_fll(codec, 0, 0, 0);
+               break;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget wm9081_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN1"),
+SND_SOC_DAPM_INPUT("IN2"),
+
+SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM9081_POWER_MANAGEMENT, 0, 0),
+
+SND_SOC_DAPM_MIXER_NAMED_CTL("Mixer", SND_SOC_NOPM, 0, 0,
+                            mixer, ARRAY_SIZE(mixer)),
+
+SND_SOC_DAPM_PGA("LINEOUT PGA", WM9081_POWER_MANAGEMENT, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_E("Speaker PGA", WM9081_POWER_MANAGEMENT, 2, 0, NULL, 0,
+                  speaker_event,
+                  SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_OUTPUT("LINEOUT"),
+SND_SOC_DAPM_OUTPUT("SPKN"),
+SND_SOC_DAPM_OUTPUT("SPKP"),
+
+SND_SOC_DAPM_SUPPLY("CLK_SYS", WM9081_CLOCK_CONTROL_3, 0, 0, clk_sys_event,
+                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("CLK_DSP", WM9081_CLOCK_CONTROL_3, 1, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("TOCLK", WM9081_CLOCK_CONTROL_3, 2, 0, NULL, 0),
+};
+
+
+static const struct snd_soc_dapm_route audio_paths[] = {
+       { "DAC", NULL, "CLK_SYS" },
+       { "DAC", NULL, "CLK_DSP" },
+
+       { "Mixer", "IN1 Switch", "IN1" },
+       { "Mixer", "IN2 Switch", "IN2" },
+       { "Mixer", "Playback Switch", "DAC" },
+
+       { "LINEOUT PGA", NULL, "Mixer" },
+       { "LINEOUT PGA", NULL, "TOCLK" },
+       { "LINEOUT PGA", NULL, "CLK_SYS" },
+
+       { "LINEOUT", NULL, "LINEOUT PGA" },
+
+       { "Speaker PGA", NULL, "Mixer" },
+       { "Speaker PGA", NULL, "TOCLK" },
+       { "Speaker PGA", NULL, "CLK_SYS" },
+
+       { "SPKN", NULL, "Speaker PGA" },
+       { "SPKP", NULL, "Speaker PGA" },
+};
+
+static int wm9081_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       u16 reg;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+
+       case SND_SOC_BIAS_PREPARE:
+               /* VMID=2*40k */
+               reg = wm9081_read(codec, WM9081_VMID_CONTROL);
+               reg &= ~WM9081_VMID_SEL_MASK;
+               reg |= 0x2;
+               wm9081_write(codec, WM9081_VMID_CONTROL, reg);
+
+               /* Normal bias current */
+               reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1);
+               reg &= ~WM9081_STBY_BIAS_ENA;
+               wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg);
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               /* Initial cold start */
+               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       /* Disable LINEOUT discharge */
+                       reg = wm9081_read(codec, WM9081_ANTI_POP_CONTROL);
+                       reg &= ~WM9081_LINEOUT_DISCH;
+                       wm9081_write(codec, WM9081_ANTI_POP_CONTROL, reg);
+
+                       /* Select startup bias source */
+                       reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1);
+                       reg |= WM9081_BIAS_SRC | WM9081_BIAS_ENA;
+                       wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg);
+
+                       /* VMID 2*4k; Soft VMID ramp enable */
+                       reg = wm9081_read(codec, WM9081_VMID_CONTROL);
+                       reg |= WM9081_VMID_RAMP | 0x6;
+                       wm9081_write(codec, WM9081_VMID_CONTROL, reg);
+
+                       mdelay(100);
+
+                       /* Normal bias enable & soft start off */
+                       reg |= WM9081_BIAS_ENA;
+                       reg &= ~WM9081_VMID_RAMP;
+                       wm9081_write(codec, WM9081_VMID_CONTROL, reg);
+
+                       /* Standard bias source */
+                       reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1);
+                       reg &= ~WM9081_BIAS_SRC;
+                       wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg);
+               }
+
+               /* VMID 2*240k */
+               reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1);
+               reg &= ~WM9081_VMID_SEL_MASK;
+               reg |= 0x40;
+               wm9081_write(codec, WM9081_VMID_CONTROL, reg);
+
+               /* Standby bias current on */
+               reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1);
+               reg |= WM9081_STBY_BIAS_ENA;
+               wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg);
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               /* Startup bias source */
+               reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1);
+               reg |= WM9081_BIAS_SRC;
+               wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg);
+
+               /* Disable VMID and biases with soft ramping */
+               reg = wm9081_read(codec, WM9081_VMID_CONTROL);
+               reg &= ~(WM9081_VMID_SEL_MASK | WM9081_BIAS_ENA);
+               reg |= WM9081_VMID_RAMP;
+               wm9081_write(codec, WM9081_VMID_CONTROL, reg);
+
+               /* Actively discharge LINEOUT */
+               reg = wm9081_read(codec, WM9081_ANTI_POP_CONTROL);
+               reg |= WM9081_LINEOUT_DISCH;
+               wm9081_write(codec, WM9081_ANTI_POP_CONTROL, reg);
+               break;
+       }
+
+       codec->bias_level = level;
+
+       return 0;
+}
+
+static int wm9081_set_dai_fmt(struct snd_soc_dai *dai,
+                             unsigned int fmt)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm9081_priv *wm9081 = codec->private_data;
+       unsigned int aif2 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_2);
+
+       aif2 &= ~(WM9081_AIF_BCLK_INV | WM9081_AIF_LRCLK_INV |
+                 WM9081_BCLK_DIR | WM9081_LRCLK_DIR | WM9081_AIF_FMT_MASK);
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               wm9081->master = 0;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               aif2 |= WM9081_LRCLK_DIR;
+               wm9081->master = 1;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               aif2 |= WM9081_BCLK_DIR;
+               wm9081->master = 1;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               aif2 |= WM9081_LRCLK_DIR | WM9081_BCLK_DIR;
+               wm9081->master = 1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_B:
+               aif2 |= WM9081_AIF_LRCLK_INV;
+       case SND_SOC_DAIFMT_DSP_A:
+               aif2 |= 0x3;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               aif2 |= 0x2;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               aif2 |= 0x1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+       case SND_SOC_DAIFMT_DSP_B:
+               /* frame inversion not valid for DSP modes */
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       aif2 |= WM9081_AIF_BCLK_INV;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+
+       case SND_SOC_DAIFMT_I2S:
+       case SND_SOC_DAIFMT_RIGHT_J:
+       case SND_SOC_DAIFMT_LEFT_J:
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_IB_IF:
+                       aif2 |= WM9081_AIF_BCLK_INV | WM9081_AIF_LRCLK_INV;
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       aif2 |= WM9081_AIF_BCLK_INV;
+                       break;
+               case SND_SOC_DAIFMT_NB_IF:
+                       aif2 |= WM9081_AIF_LRCLK_INV;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       wm9081_write(codec, WM9081_AUDIO_INTERFACE_2, aif2);
+
+       return 0;
+}
+
+static int wm9081_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 wm9081_priv *wm9081 = codec->private_data;
+       int ret, i, best, best_val, cur_val;
+       unsigned int clk_ctrl2, aif1, aif2, aif3, aif4;
+
+       clk_ctrl2 = wm9081_read(codec, WM9081_CLOCK_CONTROL_2);
+       clk_ctrl2 &= ~(WM9081_CLK_SYS_RATE_MASK | WM9081_SAMPLE_RATE_MASK);
+
+       aif1 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_1);
+
+       aif2 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_2);
+       aif2 &= ~WM9081_AIF_WL_MASK;
+
+       aif3 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_3);
+       aif3 &= ~WM9081_BCLK_DIV_MASK;
+
+       aif4 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_4);
+       aif4 &= ~WM9081_LRCLK_RATE_MASK;
+
+       /* What BCLK do we need? */
+       wm9081->fs = params_rate(params);
+       wm9081->bclk = 2 * wm9081->fs;
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               wm9081->bclk *= 16;
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               wm9081->bclk *= 20;
+               aif2 |= 0x4;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               wm9081->bclk *= 24;
+               aif2 |= 0x8;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               wm9081->bclk *= 32;
+               aif2 |= 0xc;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (aif1 & WM9081_AIFDAC_TDM_MODE_MASK) {
+               int slots = ((aif1 & WM9081_AIFDAC_TDM_MODE_MASK) >>
+                            WM9081_AIFDAC_TDM_MODE_SHIFT) + 1;
+               wm9081->bclk *= slots;
+       }
+
+       dev_dbg(codec->dev, "Target BCLK is %dHz\n", wm9081->bclk);
+
+       ret = configure_clock(codec);
+       if (ret != 0)
+               return ret;
+
+       /* Select nearest CLK_SYS_RATE */
+       best = 0;
+       best_val = abs((wm9081->sysclk_rate / clk_sys_rates[0].ratio)
+                      - wm9081->fs);
+       for (i = 1; i < ARRAY_SIZE(clk_sys_rates); i++) {
+               cur_val = abs((wm9081->sysclk_rate /
+                              clk_sys_rates[i].ratio) - wm9081->fs);;
+               if (cur_val < best_val) {
+                       best = i;
+                       best_val = cur_val;
+               }
+       }
+       dev_dbg(codec->dev, "Selected CLK_SYS_RATIO of %d\n",
+               clk_sys_rates[best].ratio);
+       clk_ctrl2 |= (clk_sys_rates[best].clk_sys_rate
+                     << WM9081_CLK_SYS_RATE_SHIFT);
+
+       /* SAMPLE_RATE */
+       best = 0;
+       best_val = abs(wm9081->fs - sample_rates[0].rate);
+       for (i = 1; i < ARRAY_SIZE(sample_rates); i++) {
+               /* Closest match */
+               cur_val = abs(wm9081->fs - sample_rates[i].rate);
+               if (cur_val < best_val) {
+                       best = i;
+                       best_val = cur_val;
+               }
+       }
+       dev_dbg(codec->dev, "Selected SAMPLE_RATE of %dHz\n",
+               sample_rates[best].rate);
+       clk_ctrl2 |= (sample_rates[best].sample_rate
+                       << WM9081_SAMPLE_RATE_SHIFT);
+
+       /* BCLK_DIV */
+       best = 0;
+       best_val = INT_MAX;
+       for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+               cur_val = ((wm9081->sysclk_rate * 10) / bclk_divs[i].div)
+                       - wm9081->bclk;
+               if (cur_val < 0) /* Table is sorted */
+                       break;
+               if (cur_val < best_val) {
+                       best = i;
+                       best_val = cur_val;
+               }
+       }
+       wm9081->bclk = (wm9081->sysclk_rate * 10) / bclk_divs[best].div;
+       dev_dbg(codec->dev, "Selected BCLK_DIV of %d for %dHz BCLK\n",
+               bclk_divs[best].div, wm9081->bclk);
+       aif3 |= bclk_divs[best].bclk_div;
+
+       /* LRCLK is a simple fraction of BCLK */
+       dev_dbg(codec->dev, "LRCLK_RATE is %d\n", wm9081->bclk / wm9081->fs);
+       aif4 |= wm9081->bclk / wm9081->fs;
+
+       /* Apply a ReTune Mobile configuration if it's in use */
+       if (wm9081->retune) {
+               struct wm9081_retune_mobile_config *retune = wm9081->retune;
+               struct wm9081_retune_mobile_setting *s;
+               int eq1;
+
+               best = 0;
+               best_val = abs(retune->configs[0].rate - wm9081->fs);
+               for (i = 0; i < retune->num_configs; i++) {
+                       cur_val = abs(retune->configs[i].rate - wm9081->fs);
+                       if (cur_val < best_val) {
+                               best_val = cur_val;
+                               best = i;
+                       }
+               }
+               s = &retune->configs[best];
+
+               dev_dbg(codec->dev, "ReTune Mobile %s tuned for %dHz\n",
+                       s->name, s->rate);
+
+               /* If the EQ is enabled then disable it while we write out */
+               eq1 = wm9081_read(codec, WM9081_EQ_1) & WM9081_EQ_ENA;
+               if (eq1 & WM9081_EQ_ENA)
+                       wm9081_write(codec, WM9081_EQ_1, 0);
+
+               /* Write out the other values */
+               for (i = 1; i < ARRAY_SIZE(s->config); i++)
+                       wm9081_write(codec, WM9081_EQ_1 + i, s->config[i]);
+
+               eq1 |= (s->config[0] & ~WM9081_EQ_ENA);
+               wm9081_write(codec, WM9081_EQ_1, eq1);
+       }
+
+       wm9081_write(codec, WM9081_CLOCK_CONTROL_2, clk_ctrl2);
+       wm9081_write(codec, WM9081_AUDIO_INTERFACE_2, aif2);
+       wm9081_write(codec, WM9081_AUDIO_INTERFACE_3, aif3);
+       wm9081_write(codec, WM9081_AUDIO_INTERFACE_4, aif4);
+
+       return 0;
+}
+
+static int wm9081_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       unsigned int reg;
+
+       reg = wm9081_read(codec, WM9081_DAC_DIGITAL_2);
+
+       if (mute)
+               reg |= WM9081_DAC_MUTE;
+       else
+               reg &= ~WM9081_DAC_MUTE;
+
+       wm9081_write(codec, WM9081_DAC_DIGITAL_2, reg);
+
+       return 0;
+}
+
+static int wm9081_set_sysclk(struct snd_soc_dai *codec_dai,
+                            int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct wm9081_priv *wm9081 = codec->private_data;
+
+       switch (clk_id) {
+       case WM9081_SYSCLK_MCLK:
+       case WM9081_SYSCLK_FLL_MCLK:
+               wm9081->sysclk_source = clk_id;
+               wm9081->mclk_rate = freq;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int wm9081_set_tdm_slot(struct snd_soc_dai *dai,
+                              unsigned int mask, int slots)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       unsigned int aif1 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_1);
+
+       aif1 &= ~(WM9081_AIFDAC_TDM_SLOT_MASK | WM9081_AIFDAC_TDM_MODE_MASK);
+
+       if (slots < 1 || slots > 4)
+               return -EINVAL;
+
+       aif1 |= (slots - 1) << WM9081_AIFDAC_TDM_MODE_SHIFT;
+
+       switch (mask) {
+       case 1:
+               break;
+       case 2:
+               aif1 |= 0x10;
+               break;
+       case 4:
+               aif1 |= 0x20;
+               break;
+       case 8:
+               aif1 |= 0x30;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       wm9081_write(codec, WM9081_AUDIO_INTERFACE_1, aif1);
+
+       return 0;
+}
+
+#define WM9081_RATES SNDRV_PCM_RATE_8000_96000
+
+#define WM9081_FORMATS \
+       (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+        SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops wm9081_dai_ops = {
+       .hw_params = wm9081_hw_params,
+       .set_sysclk = wm9081_set_sysclk,
+       .set_fmt = wm9081_set_dai_fmt,
+       .digital_mute = wm9081_digital_mute,
+       .set_tdm_slot = wm9081_set_tdm_slot,
+};
+
+/* We report two channels because the CODEC processes a stereo signal, even
+ * though it is only capable of handling a mono output.
+ */
+struct snd_soc_dai wm9081_dai = {
+       .name = "WM9081",
+       .playback = {
+               .stream_name = "HiFi Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = WM9081_RATES,
+               .formats = WM9081_FORMATS,
+       },
+       .ops = &wm9081_dai_ops,
+};
+EXPORT_SYMBOL_GPL(wm9081_dai);
+
+
+static struct snd_soc_codec *wm9081_codec;
+
+static int wm9081_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec;
+       struct wm9081_priv *wm9081;
+       int ret = 0;
+
+       if (wm9081_codec == NULL) {
+               dev_err(&pdev->dev, "Codec device not registered\n");
+               return -ENODEV;
+       }
+
+       socdev->card->codec = wm9081_codec;
+       codec = wm9081_codec;
+       wm9081 = codec->private_data;
+
+       /* 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, wm9081_snd_controls,
+                            ARRAY_SIZE(wm9081_snd_controls));
+       if (!wm9081->retune) {
+               dev_dbg(codec->dev,
+                       "No ReTune Mobile data, using normal EQ\n");
+               snd_soc_add_controls(codec, wm9081_eq_controls,
+                                    ARRAY_SIZE(wm9081_eq_controls));
+       }
+
+       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;
+}
+
+static int wm9081_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;
+}
+
+#ifdef CONFIG_PM
+static int wm9081_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;
+
+       wm9081_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+static int wm9081_resume(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->card->codec;
+       u16 *reg_cache = codec->reg_cache;
+       int i;
+
+       for (i = 0; i < codec->reg_cache_size; i++) {
+               if (i == WM9081_SOFTWARE_RESET)
+                       continue;
+
+               wm9081_write(codec, i, reg_cache[i]);
+       }
+
+       wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       return 0;
+}
+#else
+#define wm9081_suspend NULL
+#define wm9081_resume NULL
+#endif
+
+struct snd_soc_codec_device soc_codec_dev_wm9081 = {
+       .probe =        wm9081_probe,
+       .remove =       wm9081_remove,
+       .suspend =      wm9081_suspend,
+       .resume =       wm9081_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm9081);
+
+static int wm9081_register(struct wm9081_priv *wm9081)
+{
+       struct snd_soc_codec *codec = &wm9081->codec;
+       int ret;
+       u16 reg;
+
+       if (wm9081_codec) {
+               dev_err(codec->dev, "Another WM9081 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 = wm9081;
+       codec->name = "WM9081";
+       codec->owner = THIS_MODULE;
+       codec->read = wm9081_read;
+       codec->write = wm9081_write;
+       codec->dai = &wm9081_dai;
+       codec->num_dai = 1;
+       codec->reg_cache_size = ARRAY_SIZE(wm9081->reg_cache);
+       codec->reg_cache = &wm9081->reg_cache;
+       codec->bias_level = SND_SOC_BIAS_OFF;
+       codec->set_bias_level = wm9081_set_bias_level;
+
+       memcpy(codec->reg_cache, wm9081_reg_defaults,
+              sizeof(wm9081_reg_defaults));
+
+       reg = wm9081_read_hw(codec, WM9081_SOFTWARE_RESET);
+       if (reg != 0x9081) {
+               dev_err(codec->dev, "Device is not a WM9081: ID=0x%x\n", reg);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       ret = wm9081_reset(codec);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to issue reset\n");
+               return ret;
+       }
+
+       wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       /* Enable zero cross by default */
+       reg = wm9081_read(codec, WM9081_ANALOGUE_LINEOUT);
+       wm9081_write(codec, WM9081_ANALOGUE_LINEOUT, reg | WM9081_LINEOUTZC);
+       reg = wm9081_read(codec, WM9081_ANALOGUE_SPEAKER_PGA);
+       wm9081_write(codec, WM9081_ANALOGUE_SPEAKER_PGA,
+                    reg | WM9081_SPKPGAZC);
+
+       wm9081_dai.dev = codec->dev;
+
+       wm9081_codec = codec;
+
+       ret = snd_soc_register_codec(codec);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_register_dai(&wm9081_dai);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+               snd_soc_unregister_codec(codec);
+               return ret;
+       }
+
+       return 0;
+
+err:
+       kfree(wm9081);
+       return ret;
+}
+
+static void wm9081_unregister(struct wm9081_priv *wm9081)
+{
+       wm9081_set_bias_level(&wm9081->codec, SND_SOC_BIAS_OFF);
+       snd_soc_unregister_dai(&wm9081_dai);
+       snd_soc_unregister_codec(&wm9081->codec);
+       kfree(wm9081);
+       wm9081_codec = NULL;
+}
+
+static __devinit int wm9081_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct wm9081_priv *wm9081;
+       struct snd_soc_codec *codec;
+
+       wm9081 = kzalloc(sizeof(struct wm9081_priv), GFP_KERNEL);
+       if (wm9081 == NULL)
+               return -ENOMEM;
+
+       codec = &wm9081->codec;
+       codec->hw_write = (hw_write_t)i2c_master_send;
+       wm9081->retune = i2c->dev.platform_data;
+
+       i2c_set_clientdata(i2c, wm9081);
+       codec->control_data = i2c;
+
+       codec->dev = &i2c->dev;
+
+       return wm9081_register(wm9081);
+}
+
+static __devexit int wm9081_i2c_remove(struct i2c_client *client)
+{
+       struct wm9081_priv *wm9081 = i2c_get_clientdata(client);
+       wm9081_unregister(wm9081);
+       return 0;
+}
+
+static const struct i2c_device_id wm9081_i2c_id[] = {
+       { "wm9081", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm9081_i2c_id);
+
+static struct i2c_driver wm9081_i2c_driver = {
+       .driver = {
+               .name = "wm9081",
+               .owner = THIS_MODULE,
+       },
+       .probe =    wm9081_i2c_probe,
+       .remove =   __devexit_p(wm9081_i2c_remove),
+       .id_table = wm9081_i2c_id,
+};
+
+static int __init wm9081_modinit(void)
+{
+       int ret;
+
+       ret = i2c_add_driver(&wm9081_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register WM9081 I2C driver: %d\n",
+                      ret);
+       }
+
+       return ret;
+}
+module_init(wm9081_modinit);
+
+static void __exit wm9081_exit(void)
+{
+       i2c_del_driver(&wm9081_i2c_driver);
+}
+module_exit(wm9081_exit);
+
+
+MODULE_DESCRIPTION("ASoC WM9081 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm9081.h b/sound/soc/codecs/wm9081.h
new file mode 100644 (file)
index 0000000..42d3bc7
--- /dev/null
@@ -0,0 +1,787 @@
+#ifndef WM9081_H
+#define WM9081_H
+
+/*
+ * wm9081.c  --  WM9081 ALSA SoC Audio driver
+ *
+ * Author: Mark Brown
+ *
+ * Copyright 2009 Wolfson Microelectronics plc
+ *
+ * This 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 <sound/soc.h>
+
+extern struct snd_soc_dai wm9081_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm9081;
+
+/*
+ * SYSCLK sources
+ */
+#define WM9081_SYSCLK_MCLK      1   /* Use MCLK without FLL */
+#define WM9081_SYSCLK_FLL_MCLK  2   /* Use MCLK, enabling FLL if required */
+
+/*
+ * Register values.
+ */
+#define WM9081_SOFTWARE_RESET                   0x00
+#define WM9081_ANALOGUE_LINEOUT                 0x02
+#define WM9081_ANALOGUE_SPEAKER_PGA             0x03
+#define WM9081_VMID_CONTROL                     0x04
+#define WM9081_BIAS_CONTROL_1                   0x05
+#define WM9081_ANALOGUE_MIXER                   0x07
+#define WM9081_ANTI_POP_CONTROL                 0x08
+#define WM9081_ANALOGUE_SPEAKER_1               0x09
+#define WM9081_ANALOGUE_SPEAKER_2               0x0A
+#define WM9081_POWER_MANAGEMENT                 0x0B
+#define WM9081_CLOCK_CONTROL_1                  0x0C
+#define WM9081_CLOCK_CONTROL_2                  0x0D
+#define WM9081_CLOCK_CONTROL_3                  0x0E
+#define WM9081_FLL_CONTROL_1                    0x10
+#define WM9081_FLL_CONTROL_2                    0x11
+#define WM9081_FLL_CONTROL_3                    0x12
+#define WM9081_FLL_CONTROL_4                    0x13
+#define WM9081_FLL_CONTROL_5                    0x14
+#define WM9081_AUDIO_INTERFACE_1                0x16
+#define WM9081_AUDIO_INTERFACE_2                0x17
+#define WM9081_AUDIO_INTERFACE_3                0x18
+#define WM9081_AUDIO_INTERFACE_4                0x19
+#define WM9081_INTERRUPT_STATUS                 0x1A
+#define WM9081_INTERRUPT_STATUS_MASK            0x1B
+#define WM9081_INTERRUPT_POLARITY               0x1C
+#define WM9081_INTERRUPT_CONTROL                0x1D
+#define WM9081_DAC_DIGITAL_1                    0x1E
+#define WM9081_DAC_DIGITAL_2                    0x1F
+#define WM9081_DRC_1                            0x20
+#define WM9081_DRC_2                            0x21
+#define WM9081_DRC_3                            0x22
+#define WM9081_DRC_4                            0x23
+#define WM9081_WRITE_SEQUENCER_1                0x26
+#define WM9081_WRITE_SEQUENCER_2                0x27
+#define WM9081_MW_SLAVE_1                       0x28
+#define WM9081_EQ_1                             0x2A
+#define WM9081_EQ_2                             0x2B
+#define WM9081_EQ_3                             0x2C
+#define WM9081_EQ_4                             0x2D
+#define WM9081_EQ_5                             0x2E
+#define WM9081_EQ_6                             0x2F
+#define WM9081_EQ_7                             0x30
+#define WM9081_EQ_8                             0x31
+#define WM9081_EQ_9                             0x32
+#define WM9081_EQ_10                            0x33
+#define WM9081_EQ_11                            0x34
+#define WM9081_EQ_12                            0x35
+#define WM9081_EQ_13                            0x36
+#define WM9081_EQ_14                            0x37
+#define WM9081_EQ_15                            0x38
+#define WM9081_EQ_16                            0x39
+#define WM9081_EQ_17                            0x3A
+#define WM9081_EQ_18                            0x3B
+#define WM9081_EQ_19                            0x3C
+#define WM9081_EQ_20                            0x3D
+
+#define WM9081_REGISTER_COUNT                   55
+#define WM9081_MAX_REGISTER                     0x3D
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Software Reset
+ */
+#define WM9081_SW_RST_DEV_ID1_MASK              0xFFFF  /* SW_RST_DEV_ID1 - [15:0] */
+#define WM9081_SW_RST_DEV_ID1_SHIFT                  0  /* SW_RST_DEV_ID1 - [15:0] */
+#define WM9081_SW_RST_DEV_ID1_WIDTH                 16  /* SW_RST_DEV_ID1 - [15:0] */
+
+/*
+ * R2 (0x02) - Analogue Lineout
+ */
+#define WM9081_LINEOUT_MUTE                     0x0080  /* LINEOUT_MUTE */
+#define WM9081_LINEOUT_MUTE_MASK                0x0080  /* LINEOUT_MUTE */
+#define WM9081_LINEOUT_MUTE_SHIFT                    7  /* LINEOUT_MUTE */
+#define WM9081_LINEOUT_MUTE_WIDTH                    1  /* LINEOUT_MUTE */
+#define WM9081_LINEOUTZC                        0x0040  /* LINEOUTZC */
+#define WM9081_LINEOUTZC_MASK                   0x0040  /* LINEOUTZC */
+#define WM9081_LINEOUTZC_SHIFT                       6  /* LINEOUTZC */
+#define WM9081_LINEOUTZC_WIDTH                       1  /* LINEOUTZC */
+#define WM9081_LINEOUT_VOL_MASK                 0x003F  /* LINEOUT_VOL - [5:0] */
+#define WM9081_LINEOUT_VOL_SHIFT                     0  /* LINEOUT_VOL - [5:0] */
+#define WM9081_LINEOUT_VOL_WIDTH                     6  /* LINEOUT_VOL - [5:0] */
+
+/*
+ * R3 (0x03) - Analogue Speaker PGA
+ */
+#define WM9081_SPKPGA_MUTE                      0x0080  /* SPKPGA_MUTE */
+#define WM9081_SPKPGA_MUTE_MASK                 0x0080  /* SPKPGA_MUTE */
+#define WM9081_SPKPGA_MUTE_SHIFT                     7  /* SPKPGA_MUTE */
+#define WM9081_SPKPGA_MUTE_WIDTH                     1  /* SPKPGA_MUTE */
+#define WM9081_SPKPGAZC                         0x0040  /* SPKPGAZC */
+#define WM9081_SPKPGAZC_MASK                    0x0040  /* SPKPGAZC */
+#define WM9081_SPKPGAZC_SHIFT                        6  /* SPKPGAZC */
+#define WM9081_SPKPGAZC_WIDTH                        1  /* SPKPGAZC */
+#define WM9081_SPKPGA_VOL_MASK                  0x003F  /* SPKPGA_VOL - [5:0] */
+#define WM9081_SPKPGA_VOL_SHIFT                      0  /* SPKPGA_VOL - [5:0] */
+#define WM9081_SPKPGA_VOL_WIDTH                      6  /* SPKPGA_VOL - [5:0] */
+
+/*
+ * R4 (0x04) - VMID Control
+ */
+#define WM9081_VMID_BUF_ENA                     0x0020  /* VMID_BUF_ENA */
+#define WM9081_VMID_BUF_ENA_MASK                0x0020  /* VMID_BUF_ENA */
+#define WM9081_VMID_BUF_ENA_SHIFT                    5  /* VMID_BUF_ENA */
+#define WM9081_VMID_BUF_ENA_WIDTH                    1  /* VMID_BUF_ENA */
+#define WM9081_VMID_RAMP                        0x0008  /* VMID_RAMP */
+#define WM9081_VMID_RAMP_MASK                   0x0008  /* VMID_RAMP */
+#define WM9081_VMID_RAMP_SHIFT                       3  /* VMID_RAMP */
+#define WM9081_VMID_RAMP_WIDTH                       1  /* VMID_RAMP */
+#define WM9081_VMID_SEL_MASK                    0x0006  /* VMID_SEL - [2:1] */
+#define WM9081_VMID_SEL_SHIFT                        1  /* VMID_SEL - [2:1] */
+#define WM9081_VMID_SEL_WIDTH                        2  /* VMID_SEL - [2:1] */
+#define WM9081_VMID_FAST_ST                     0x0001  /* VMID_FAST_ST */
+#define WM9081_VMID_FAST_ST_MASK                0x0001  /* VMID_FAST_ST */
+#define WM9081_VMID_FAST_ST_SHIFT                    0  /* VMID_FAST_ST */
+#define WM9081_VMID_FAST_ST_WIDTH                    1  /* VMID_FAST_ST */
+
+/*
+ * R5 (0x05) - Bias Control 1
+ */
+#define WM9081_BIAS_SRC                         0x0040  /* BIAS_SRC */
+#define WM9081_BIAS_SRC_MASK                    0x0040  /* BIAS_SRC */
+#define WM9081_BIAS_SRC_SHIFT                        6  /* BIAS_SRC */
+#define WM9081_BIAS_SRC_WIDTH                        1  /* BIAS_SRC */
+#define WM9081_STBY_BIAS_LVL                    0x0020  /* STBY_BIAS_LVL */
+#define WM9081_STBY_BIAS_LVL_MASK               0x0020  /* STBY_BIAS_LVL */
+#define WM9081_STBY_BIAS_LVL_SHIFT                   5  /* STBY_BIAS_LVL */
+#define WM9081_STBY_BIAS_LVL_WIDTH                   1  /* STBY_BIAS_LVL */
+#define WM9081_STBY_BIAS_ENA                    0x0010  /* STBY_BIAS_ENA */
+#define WM9081_STBY_BIAS_ENA_MASK               0x0010  /* STBY_BIAS_ENA */
+#define WM9081_STBY_BIAS_ENA_SHIFT                   4  /* STBY_BIAS_ENA */
+#define WM9081_STBY_BIAS_ENA_WIDTH                   1  /* STBY_BIAS_ENA */
+#define WM9081_BIAS_LVL_MASK                    0x000C  /* BIAS_LVL - [3:2] */
+#define WM9081_BIAS_LVL_SHIFT                        2  /* BIAS_LVL - [3:2] */
+#define WM9081_BIAS_LVL_WIDTH                        2  /* BIAS_LVL - [3:2] */
+#define WM9081_BIAS_ENA                         0x0002  /* BIAS_ENA */
+#define WM9081_BIAS_ENA_MASK                    0x0002  /* BIAS_ENA */
+#define WM9081_BIAS_ENA_SHIFT                        1  /* BIAS_ENA */
+#define WM9081_BIAS_ENA_WIDTH                        1  /* BIAS_ENA */
+#define WM9081_STARTUP_BIAS_ENA                 0x0001  /* STARTUP_BIAS_ENA */
+#define WM9081_STARTUP_BIAS_ENA_MASK            0x0001  /* STARTUP_BIAS_ENA */
+#define WM9081_STARTUP_BIAS_ENA_SHIFT                0  /* STARTUP_BIAS_ENA */
+#define WM9081_STARTUP_BIAS_ENA_WIDTH                1  /* STARTUP_BIAS_ENA */
+
+/*
+ * R7 (0x07) - Analogue Mixer
+ */
+#define WM9081_DAC_SEL                          0x0010  /* DAC_SEL */
+#define WM9081_DAC_SEL_MASK                     0x0010  /* DAC_SEL */
+#define WM9081_DAC_SEL_SHIFT                         4  /* DAC_SEL */
+#define WM9081_DAC_SEL_WIDTH                         1  /* DAC_SEL */
+#define WM9081_IN2_VOL                          0x0008  /* IN2_VOL */
+#define WM9081_IN2_VOL_MASK                     0x0008  /* IN2_VOL */
+#define WM9081_IN2_VOL_SHIFT                         3  /* IN2_VOL */
+#define WM9081_IN2_VOL_WIDTH                         1  /* IN2_VOL */
+#define WM9081_IN2_ENA                          0x0004  /* IN2_ENA */
+#define WM9081_IN2_ENA_MASK                     0x0004  /* IN2_ENA */
+#define WM9081_IN2_ENA_SHIFT                         2  /* IN2_ENA */
+#define WM9081_IN2_ENA_WIDTH                         1  /* IN2_ENA */
+#define WM9081_IN1_VOL                          0x0002  /* IN1_VOL */
+#define WM9081_IN1_VOL_MASK                     0x0002  /* IN1_VOL */
+#define WM9081_IN1_VOL_SHIFT                         1  /* IN1_VOL */
+#define WM9081_IN1_VOL_WIDTH                         1  /* IN1_VOL */
+#define WM9081_IN1_ENA                          0x0001  /* IN1_ENA */
+#define WM9081_IN1_ENA_MASK                     0x0001  /* IN1_ENA */
+#define WM9081_IN1_ENA_SHIFT                         0  /* IN1_ENA */
+#define WM9081_IN1_ENA_WIDTH                         1  /* IN1_ENA */
+
+/*
+ * R8 (0x08) - Anti Pop Control
+ */
+#define WM9081_LINEOUT_DISCH                    0x0004  /* LINEOUT_DISCH */
+#define WM9081_LINEOUT_DISCH_MASK               0x0004  /* LINEOUT_DISCH */
+#define WM9081_LINEOUT_DISCH_SHIFT                   2  /* LINEOUT_DISCH */
+#define WM9081_LINEOUT_DISCH_WIDTH                   1  /* LINEOUT_DISCH */
+#define WM9081_LINEOUT_VROI                     0x0002  /* LINEOUT_VROI */
+#define WM9081_LINEOUT_VROI_MASK                0x0002  /* LINEOUT_VROI */
+#define WM9081_LINEOUT_VROI_SHIFT                    1  /* LINEOUT_VROI */
+#define WM9081_LINEOUT_VROI_WIDTH                    1  /* LINEOUT_VROI */
+#define WM9081_LINEOUT_CLAMP                    0x0001  /* LINEOUT_CLAMP */
+#define WM9081_LINEOUT_CLAMP_MASK               0x0001  /* LINEOUT_CLAMP */
+#define WM9081_LINEOUT_CLAMP_SHIFT                   0  /* LINEOUT_CLAMP */
+#define WM9081_LINEOUT_CLAMP_WIDTH                   1  /* LINEOUT_CLAMP */
+
+/*
+ * R9 (0x09) - Analogue Speaker 1
+ */
+#define WM9081_SPK_DCGAIN_MASK                  0x0038  /* SPK_DCGAIN - [5:3] */
+#define WM9081_SPK_DCGAIN_SHIFT                      3  /* SPK_DCGAIN - [5:3] */
+#define WM9081_SPK_DCGAIN_WIDTH                      3  /* SPK_DCGAIN - [5:3] */
+#define WM9081_SPK_ACGAIN_MASK                  0x0007  /* SPK_ACGAIN - [2:0] */
+#define WM9081_SPK_ACGAIN_SHIFT                      0  /* SPK_ACGAIN - [2:0] */
+#define WM9081_SPK_ACGAIN_WIDTH                      3  /* SPK_ACGAIN - [2:0] */
+
+/*
+ * R10 (0x0A) - Analogue Speaker 2
+ */
+#define WM9081_SPK_MODE                         0x0040  /* SPK_MODE */
+#define WM9081_SPK_MODE_MASK                    0x0040  /* SPK_MODE */
+#define WM9081_SPK_MODE_SHIFT                        6  /* SPK_MODE */
+#define WM9081_SPK_MODE_WIDTH                        1  /* SPK_MODE */
+#define WM9081_SPK_INV_MUTE                     0x0010  /* SPK_INV_MUTE */
+#define WM9081_SPK_INV_MUTE_MASK                0x0010  /* SPK_INV_MUTE */
+#define WM9081_SPK_INV_MUTE_SHIFT                    4  /* SPK_INV_MUTE */
+#define WM9081_SPK_INV_MUTE_WIDTH                    1  /* SPK_INV_MUTE */
+#define WM9081_OUT_SPK_CTRL                     0x0008  /* OUT_SPK_CTRL */
+#define WM9081_OUT_SPK_CTRL_MASK                0x0008  /* OUT_SPK_CTRL */
+#define WM9081_OUT_SPK_CTRL_SHIFT                    3  /* OUT_SPK_CTRL */
+#define WM9081_OUT_SPK_CTRL_WIDTH                    1  /* OUT_SPK_CTRL */
+
+/*
+ * R11 (0x0B) - Power Management
+ */
+#define WM9081_TSHUT_ENA                        0x0100  /* TSHUT_ENA */
+#define WM9081_TSHUT_ENA_MASK                   0x0100  /* TSHUT_ENA */
+#define WM9081_TSHUT_ENA_SHIFT                       8  /* TSHUT_ENA */
+#define WM9081_TSHUT_ENA_WIDTH                       1  /* TSHUT_ENA */
+#define WM9081_TSENSE_ENA                       0x0080  /* TSENSE_ENA */
+#define WM9081_TSENSE_ENA_MASK                  0x0080  /* TSENSE_ENA */
+#define WM9081_TSENSE_ENA_SHIFT                      7  /* TSENSE_ENA */
+#define WM9081_TSENSE_ENA_WIDTH                      1  /* TSENSE_ENA */
+#define WM9081_TEMP_SHUT                        0x0040  /* TEMP_SHUT */
+#define WM9081_TEMP_SHUT_MASK                   0x0040  /* TEMP_SHUT */
+#define WM9081_TEMP_SHUT_SHIFT                       6  /* TEMP_SHUT */
+#define WM9081_TEMP_SHUT_WIDTH                       1  /* TEMP_SHUT */
+#define WM9081_LINEOUT_ENA                      0x0010  /* LINEOUT_ENA */
+#define WM9081_LINEOUT_ENA_MASK                 0x0010  /* LINEOUT_ENA */
+#define WM9081_LINEOUT_ENA_SHIFT                     4  /* LINEOUT_ENA */
+#define WM9081_LINEOUT_ENA_WIDTH                     1  /* LINEOUT_ENA */
+#define WM9081_SPKPGA_ENA                       0x0004  /* SPKPGA_ENA */
+#define WM9081_SPKPGA_ENA_MASK                  0x0004  /* SPKPGA_ENA */
+#define WM9081_SPKPGA_ENA_SHIFT                      2  /* SPKPGA_ENA */
+#define WM9081_SPKPGA_ENA_WIDTH                      1  /* SPKPGA_ENA */
+#define WM9081_SPK_ENA                          0x0002  /* SPK_ENA */
+#define WM9081_SPK_ENA_MASK                     0x0002  /* SPK_ENA */
+#define WM9081_SPK_ENA_SHIFT                         1  /* SPK_ENA */
+#define WM9081_SPK_ENA_WIDTH                         1  /* SPK_ENA */
+#define WM9081_DAC_ENA                          0x0001  /* DAC_ENA */
+#define WM9081_DAC_ENA_MASK                     0x0001  /* DAC_ENA */
+#define WM9081_DAC_ENA_SHIFT                         0  /* DAC_ENA */
+#define WM9081_DAC_ENA_WIDTH                         1  /* DAC_ENA */
+
+/*
+ * R12 (0x0C) - Clock Control 1
+ */
+#define WM9081_CLK_OP_DIV_MASK                  0x1C00  /* CLK_OP_DIV - [12:10] */
+#define WM9081_CLK_OP_DIV_SHIFT                     10  /* CLK_OP_DIV - [12:10] */
+#define WM9081_CLK_OP_DIV_WIDTH                      3  /* CLK_OP_DIV - [12:10] */
+#define WM9081_CLK_TO_DIV_MASK                  0x0300  /* CLK_TO_DIV - [9:8] */
+#define WM9081_CLK_TO_DIV_SHIFT                      8  /* CLK_TO_DIV - [9:8] */
+#define WM9081_CLK_TO_DIV_WIDTH                      2  /* CLK_TO_DIV - [9:8] */
+#define WM9081_MCLKDIV2                         0x0080  /* MCLKDIV2 */
+#define WM9081_MCLKDIV2_MASK                    0x0080  /* MCLKDIV2 */
+#define WM9081_MCLKDIV2_SHIFT                        7  /* MCLKDIV2 */
+#define WM9081_MCLKDIV2_WIDTH                        1  /* MCLKDIV2 */
+
+/*
+ * R13 (0x0D) - Clock Control 2
+ */
+#define WM9081_CLK_SYS_RATE_MASK                0x00F0  /* CLK_SYS_RATE - [7:4] */
+#define WM9081_CLK_SYS_RATE_SHIFT                    4  /* CLK_SYS_RATE - [7:4] */
+#define WM9081_CLK_SYS_RATE_WIDTH                    4  /* CLK_SYS_RATE - [7:4] */
+#define WM9081_SAMPLE_RATE_MASK                 0x000F  /* SAMPLE_RATE - [3:0] */
+#define WM9081_SAMPLE_RATE_SHIFT                     0  /* SAMPLE_RATE - [3:0] */
+#define WM9081_SAMPLE_RATE_WIDTH                     4  /* SAMPLE_RATE - [3:0] */
+
+/*
+ * R14 (0x0E) - Clock Control 3
+ */
+#define WM9081_CLK_SRC_SEL                      0x2000  /* CLK_SRC_SEL */
+#define WM9081_CLK_SRC_SEL_MASK                 0x2000  /* CLK_SRC_SEL */
+#define WM9081_CLK_SRC_SEL_SHIFT                    13  /* CLK_SRC_SEL */
+#define WM9081_CLK_SRC_SEL_WIDTH                     1  /* CLK_SRC_SEL */
+#define WM9081_CLK_OP_ENA                       0x0020  /* CLK_OP_ENA */
+#define WM9081_CLK_OP_ENA_MASK                  0x0020  /* CLK_OP_ENA */
+#define WM9081_CLK_OP_ENA_SHIFT                      5  /* CLK_OP_ENA */
+#define WM9081_CLK_OP_ENA_WIDTH                      1  /* CLK_OP_ENA */
+#define WM9081_CLK_TO_ENA                       0x0004  /* CLK_TO_ENA */
+#define WM9081_CLK_TO_ENA_MASK                  0x0004  /* CLK_TO_ENA */
+#define WM9081_CLK_TO_ENA_SHIFT                      2  /* CLK_TO_ENA */
+#define WM9081_CLK_TO_ENA_WIDTH                      1  /* CLK_TO_ENA */
+#define WM9081_CLK_DSP_ENA                      0x0002  /* CLK_DSP_ENA */
+#define WM9081_CLK_DSP_ENA_MASK                 0x0002  /* CLK_DSP_ENA */
+#define WM9081_CLK_DSP_ENA_SHIFT                     1  /* CLK_DSP_ENA */
+#define WM9081_CLK_DSP_ENA_WIDTH                     1  /* CLK_DSP_ENA */
+#define WM9081_CLK_SYS_ENA                      0x0001  /* CLK_SYS_ENA */
+#define WM9081_CLK_SYS_ENA_MASK                 0x0001  /* CLK_SYS_ENA */
+#define WM9081_CLK_SYS_ENA_SHIFT                     0  /* CLK_SYS_ENA */
+#define WM9081_CLK_SYS_ENA_WIDTH                     1  /* CLK_SYS_ENA */
+
+/*
+ * R16 (0x10) - FLL Control 1
+ */
+#define WM9081_FLL_HOLD                         0x0008  /* FLL_HOLD */
+#define WM9081_FLL_HOLD_MASK                    0x0008  /* FLL_HOLD */
+#define WM9081_FLL_HOLD_SHIFT                        3  /* FLL_HOLD */
+#define WM9081_FLL_HOLD_WIDTH                        1  /* FLL_HOLD */
+#define WM9081_FLL_FRAC                         0x0004  /* FLL_FRAC */
+#define WM9081_FLL_FRAC_MASK                    0x0004  /* FLL_FRAC */
+#define WM9081_FLL_FRAC_SHIFT                        2  /* FLL_FRAC */
+#define WM9081_FLL_FRAC_WIDTH                        1  /* FLL_FRAC */
+#define WM9081_FLL_ENA                          0x0001  /* FLL_ENA */
+#define WM9081_FLL_ENA_MASK                     0x0001  /* FLL_ENA */
+#define WM9081_FLL_ENA_SHIFT                         0  /* FLL_ENA */
+#define WM9081_FLL_ENA_WIDTH                         1  /* FLL_ENA */
+
+/*
+ * R17 (0x11) - FLL Control 2
+ */
+#define WM9081_FLL_OUTDIV_MASK                  0x0700  /* FLL_OUTDIV - [10:8] */
+#define WM9081_FLL_OUTDIV_SHIFT                      8  /* FLL_OUTDIV - [10:8] */
+#define WM9081_FLL_OUTDIV_WIDTH                      3  /* FLL_OUTDIV - [10:8] */
+#define WM9081_FLL_CTRL_RATE_MASK               0x0070  /* FLL_CTRL_RATE - [6:4] */
+#define WM9081_FLL_CTRL_RATE_SHIFT                   4  /* FLL_CTRL_RATE - [6:4] */
+#define WM9081_FLL_CTRL_RATE_WIDTH                   3  /* FLL_CTRL_RATE - [6:4] */
+#define WM9081_FLL_FRATIO_MASK                  0x0007  /* FLL_FRATIO - [2:0] */
+#define WM9081_FLL_FRATIO_SHIFT                      0  /* FLL_FRATIO - [2:0] */
+#define WM9081_FLL_FRATIO_WIDTH                      3  /* FLL_FRATIO - [2:0] */
+
+/*
+ * R18 (0x12) - FLL Control 3
+ */
+#define WM9081_FLL_K_MASK                       0xFFFF  /* FLL_K - [15:0] */
+#define WM9081_FLL_K_SHIFT                           0  /* FLL_K - [15:0] */
+#define WM9081_FLL_K_WIDTH                          16  /* FLL_K - [15:0] */
+
+/*
+ * R19 (0x13) - FLL Control 4
+ */
+#define WM9081_FLL_N_MASK                       0x7FE0  /* FLL_N - [14:5] */
+#define WM9081_FLL_N_SHIFT                           5  /* FLL_N - [14:5] */
+#define WM9081_FLL_N_WIDTH                          10  /* FLL_N - [14:5] */
+#define WM9081_FLL_GAIN_MASK                    0x000F  /* FLL_GAIN - [3:0] */
+#define WM9081_FLL_GAIN_SHIFT                        0  /* FLL_GAIN - [3:0] */
+#define WM9081_FLL_GAIN_WIDTH                        4  /* FLL_GAIN - [3:0] */
+
+/*
+ * R20 (0x14) - FLL Control 5
+ */
+#define WM9081_FLL_CLK_REF_DIV_MASK             0x0018  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM9081_FLL_CLK_REF_DIV_SHIFT                 3  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM9081_FLL_CLK_REF_DIV_WIDTH                 2  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM9081_FLL_CLK_SRC_MASK                 0x0003  /* FLL_CLK_SRC - [1:0] */
+#define WM9081_FLL_CLK_SRC_SHIFT                     0  /* FLL_CLK_SRC - [1:0] */
+#define WM9081_FLL_CLK_SRC_WIDTH                     2  /* FLL_CLK_SRC - [1:0] */
+
+/*
+ * R22 (0x16) - Audio Interface 1
+ */
+#define WM9081_AIFDAC_CHAN                      0x0040  /* AIFDAC_CHAN */
+#define WM9081_AIFDAC_CHAN_MASK                 0x0040  /* AIFDAC_CHAN */
+#define WM9081_AIFDAC_CHAN_SHIFT                     6  /* AIFDAC_CHAN */
+#define WM9081_AIFDAC_CHAN_WIDTH                     1  /* AIFDAC_CHAN */
+#define WM9081_AIFDAC_TDM_SLOT_MASK             0x0030  /* AIFDAC_TDM_SLOT - [5:4] */
+#define WM9081_AIFDAC_TDM_SLOT_SHIFT                 4  /* AIFDAC_TDM_SLOT - [5:4] */
+#define WM9081_AIFDAC_TDM_SLOT_WIDTH                 2  /* AIFDAC_TDM_SLOT - [5:4] */
+#define WM9081_AIFDAC_TDM_MODE_MASK             0x000C  /* AIFDAC_TDM_MODE - [3:2] */
+#define WM9081_AIFDAC_TDM_MODE_SHIFT                 2  /* AIFDAC_TDM_MODE - [3:2] */
+#define WM9081_AIFDAC_TDM_MODE_WIDTH                 2  /* AIFDAC_TDM_MODE - [3:2] */
+#define WM9081_DAC_COMP                         0x0002  /* DAC_COMP */
+#define WM9081_DAC_COMP_MASK                    0x0002  /* DAC_COMP */
+#define WM9081_DAC_COMP_SHIFT                        1  /* DAC_COMP */
+#define WM9081_DAC_COMP_WIDTH                        1  /* DAC_COMP */
+#define WM9081_DAC_COMPMODE                     0x0001  /* DAC_COMPMODE */
+#define WM9081_DAC_COMPMODE_MASK                0x0001  /* DAC_COMPMODE */
+#define WM9081_DAC_COMPMODE_SHIFT                    0  /* DAC_COMPMODE */
+#define WM9081_DAC_COMPMODE_WIDTH                    1  /* DAC_COMPMODE */
+
+/*
+ * R23 (0x17) - Audio Interface 2
+ */
+#define WM9081_AIF_TRIS                         0x0200  /* AIF_TRIS */
+#define WM9081_AIF_TRIS_MASK                    0x0200  /* AIF_TRIS */
+#define WM9081_AIF_TRIS_SHIFT                        9  /* AIF_TRIS */
+#define WM9081_AIF_TRIS_WIDTH                        1  /* AIF_TRIS */
+#define WM9081_DAC_DAT_INV                      0x0100  /* DAC_DAT_INV */
+#define WM9081_DAC_DAT_INV_MASK                 0x0100  /* DAC_DAT_INV */
+#define WM9081_DAC_DAT_INV_SHIFT                     8  /* DAC_DAT_INV */
+#define WM9081_DAC_DAT_INV_WIDTH                     1  /* DAC_DAT_INV */
+#define WM9081_AIF_BCLK_INV                     0x0080  /* AIF_BCLK_INV */
+#define WM9081_AIF_BCLK_INV_MASK                0x0080  /* AIF_BCLK_INV */
+#define WM9081_AIF_BCLK_INV_SHIFT                    7  /* AIF_BCLK_INV */
+#define WM9081_AIF_BCLK_INV_WIDTH                    1  /* AIF_BCLK_INV */
+#define WM9081_BCLK_DIR                         0x0040  /* BCLK_DIR */
+#define WM9081_BCLK_DIR_MASK                    0x0040  /* BCLK_DIR */
+#define WM9081_BCLK_DIR_SHIFT                        6  /* BCLK_DIR */
+#define WM9081_BCLK_DIR_WIDTH                        1  /* BCLK_DIR */
+#define WM9081_LRCLK_DIR                        0x0020  /* LRCLK_DIR */
+#define WM9081_LRCLK_DIR_MASK                   0x0020  /* LRCLK_DIR */
+#define WM9081_LRCLK_DIR_SHIFT                       5  /* LRCLK_DIR */
+#define WM9081_LRCLK_DIR_WIDTH                       1  /* LRCLK_DIR */
+#define WM9081_AIF_LRCLK_INV                    0x0010  /* AIF_LRCLK_INV */
+#define WM9081_AIF_LRCLK_INV_MASK               0x0010  /* AIF_LRCLK_INV */
+#define WM9081_AIF_LRCLK_INV_SHIFT                   4  /* AIF_LRCLK_INV */
+#define WM9081_AIF_LRCLK_INV_WIDTH                   1  /* AIF_LRCLK_INV */
+#define WM9081_AIF_WL_MASK                      0x000C  /* AIF_WL - [3:2] */
+#define WM9081_AIF_WL_SHIFT                          2  /* AIF_WL - [3:2] */
+#define WM9081_AIF_WL_WIDTH                          2  /* AIF_WL - [3:2] */
+#define WM9081_AIF_FMT_MASK                     0x0003  /* AIF_FMT - [1:0] */
+#define WM9081_AIF_FMT_SHIFT                         0  /* AIF_FMT - [1:0] */
+#define WM9081_AIF_FMT_WIDTH                         2  /* AIF_FMT - [1:0] */
+
+/*
+ * R24 (0x18) - Audio Interface 3
+ */
+#define WM9081_BCLK_DIV_MASK                    0x001F  /* BCLK_DIV - [4:0] */
+#define WM9081_BCLK_DIV_SHIFT                        0  /* BCLK_DIV - [4:0] */
+#define WM9081_BCLK_DIV_WIDTH                        5  /* BCLK_DIV - [4:0] */
+
+/*
+ * R25 (0x19) - Audio Interface 4
+ */
+#define WM9081_LRCLK_RATE_MASK                  0x07FF  /* LRCLK_RATE - [10:0] */
+#define WM9081_LRCLK_RATE_SHIFT                      0  /* LRCLK_RATE - [10:0] */
+#define WM9081_LRCLK_RATE_WIDTH                     11  /* LRCLK_RATE - [10:0] */
+
+/*
+ * R26 (0x1A) - Interrupt Status
+ */
+#define WM9081_WSEQ_BUSY_EINT                   0x0004  /* WSEQ_BUSY_EINT */
+#define WM9081_WSEQ_BUSY_EINT_MASK              0x0004  /* WSEQ_BUSY_EINT */
+#define WM9081_WSEQ_BUSY_EINT_SHIFT                  2  /* WSEQ_BUSY_EINT */
+#define WM9081_WSEQ_BUSY_EINT_WIDTH                  1  /* WSEQ_BUSY_EINT */
+#define WM9081_TSHUT_EINT                       0x0001  /* TSHUT_EINT */
+#define WM9081_TSHUT_EINT_MASK                  0x0001  /* TSHUT_EINT */
+#define WM9081_TSHUT_EINT_SHIFT                      0  /* TSHUT_EINT */
+#define WM9081_TSHUT_EINT_WIDTH                      1  /* TSHUT_EINT */
+
+/*
+ * R27 (0x1B) - Interrupt Status Mask
+ */
+#define WM9081_IM_WSEQ_BUSY_EINT                0x0004  /* IM_WSEQ_BUSY_EINT */
+#define WM9081_IM_WSEQ_BUSY_EINT_MASK           0x0004  /* IM_WSEQ_BUSY_EINT */
+#define WM9081_IM_WSEQ_BUSY_EINT_SHIFT               2  /* IM_WSEQ_BUSY_EINT */
+#define WM9081_IM_WSEQ_BUSY_EINT_WIDTH               1  /* IM_WSEQ_BUSY_EINT */
+#define WM9081_IM_TSHUT_EINT                    0x0001  /* IM_TSHUT_EINT */
+#define WM9081_IM_TSHUT_EINT_MASK               0x0001  /* IM_TSHUT_EINT */
+#define WM9081_IM_TSHUT_EINT_SHIFT                   0  /* IM_TSHUT_EINT */
+#define WM9081_IM_TSHUT_EINT_WIDTH                   1  /* IM_TSHUT_EINT */
+
+/*
+ * R28 (0x1C) - Interrupt Polarity
+ */
+#define WM9081_TSHUT_INV                        0x0001  /* TSHUT_INV */
+#define WM9081_TSHUT_INV_MASK                   0x0001  /* TSHUT_INV */
+#define WM9081_TSHUT_INV_SHIFT                       0  /* TSHUT_INV */
+#define WM9081_TSHUT_INV_WIDTH                       1  /* TSHUT_INV */
+
+/*
+ * R29 (0x1D) - Interrupt Control
+ */
+#define WM9081_IRQ_POL                          0x8000  /* IRQ_POL */
+#define WM9081_IRQ_POL_MASK                     0x8000  /* IRQ_POL */
+#define WM9081_IRQ_POL_SHIFT                        15  /* IRQ_POL */
+#define WM9081_IRQ_POL_WIDTH                         1  /* IRQ_POL */
+#define WM9081_IRQ_OP_CTRL                      0x0001  /* IRQ_OP_CTRL */
+#define WM9081_IRQ_OP_CTRL_MASK                 0x0001  /* IRQ_OP_CTRL */
+#define WM9081_IRQ_OP_CTRL_SHIFT                     0  /* IRQ_OP_CTRL */
+#define WM9081_IRQ_OP_CTRL_WIDTH                     1  /* IRQ_OP_CTRL */
+
+/*
+ * R30 (0x1E) - DAC Digital 1
+ */
+#define WM9081_DAC_VOL_MASK                     0x00FF  /* DAC_VOL - [7:0] */
+#define WM9081_DAC_VOL_SHIFT                         0  /* DAC_VOL - [7:0] */
+#define WM9081_DAC_VOL_WIDTH                         8  /* DAC_VOL - [7:0] */
+
+/*
+ * R31 (0x1F) - DAC Digital 2
+ */
+#define WM9081_DAC_MUTERATE                     0x0400  /* DAC_MUTERATE */
+#define WM9081_DAC_MUTERATE_MASK                0x0400  /* DAC_MUTERATE */
+#define WM9081_DAC_MUTERATE_SHIFT                   10  /* DAC_MUTERATE */
+#define WM9081_DAC_MUTERATE_WIDTH                    1  /* DAC_MUTERATE */
+#define WM9081_DAC_MUTEMODE                     0x0200  /* DAC_MUTEMODE */
+#define WM9081_DAC_MUTEMODE_MASK                0x0200  /* DAC_MUTEMODE */
+#define WM9081_DAC_MUTEMODE_SHIFT                    9  /* DAC_MUTEMODE */
+#define WM9081_DAC_MUTEMODE_WIDTH                    1  /* DAC_MUTEMODE */
+#define WM9081_DAC_MUTE                         0x0008  /* DAC_MUTE */
+#define WM9081_DAC_MUTE_MASK                    0x0008  /* DAC_MUTE */
+#define WM9081_DAC_MUTE_SHIFT                        3  /* DAC_MUTE */
+#define WM9081_DAC_MUTE_WIDTH                        1  /* DAC_MUTE */
+#define WM9081_DEEMPH_MASK                      0x0006  /* DEEMPH - [2:1] */
+#define WM9081_DEEMPH_SHIFT                          1  /* DEEMPH - [2:1] */
+#define WM9081_DEEMPH_WIDTH                          2  /* DEEMPH - [2:1] */
+
+/*
+ * R32 (0x20) - DRC 1
+ */
+#define WM9081_DRC_ENA                          0x8000  /* DRC_ENA */
+#define WM9081_DRC_ENA_MASK                     0x8000  /* DRC_ENA */
+#define WM9081_DRC_ENA_SHIFT                        15  /* DRC_ENA */
+#define WM9081_DRC_ENA_WIDTH                         1  /* DRC_ENA */
+#define WM9081_DRC_STARTUP_GAIN_MASK            0x07C0  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM9081_DRC_STARTUP_GAIN_SHIFT                6  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM9081_DRC_STARTUP_GAIN_WIDTH                5  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM9081_DRC_FF_DLY                       0x0020  /* DRC_FF_DLY */
+#define WM9081_DRC_FF_DLY_MASK                  0x0020  /* DRC_FF_DLY */
+#define WM9081_DRC_FF_DLY_SHIFT                      5  /* DRC_FF_DLY */
+#define WM9081_DRC_FF_DLY_WIDTH                      1  /* DRC_FF_DLY */
+#define WM9081_DRC_QR                           0x0004  /* DRC_QR */
+#define WM9081_DRC_QR_MASK                      0x0004  /* DRC_QR */
+#define WM9081_DRC_QR_SHIFT                          2  /* DRC_QR */
+#define WM9081_DRC_QR_WIDTH                          1  /* DRC_QR */
+#define WM9081_DRC_ANTICLIP                     0x0002  /* DRC_ANTICLIP */
+#define WM9081_DRC_ANTICLIP_MASK                0x0002  /* DRC_ANTICLIP */
+#define WM9081_DRC_ANTICLIP_SHIFT                    1  /* DRC_ANTICLIP */
+#define WM9081_DRC_ANTICLIP_WIDTH                    1  /* DRC_ANTICLIP */
+
+/*
+ * R33 (0x21) - DRC 2
+ */
+#define WM9081_DRC_ATK_MASK                     0xF000  /* DRC_ATK - [15:12] */
+#define WM9081_DRC_ATK_SHIFT                        12  /* DRC_ATK - [15:12] */
+#define WM9081_DRC_ATK_WIDTH                         4  /* DRC_ATK - [15:12] */
+#define WM9081_DRC_DCY_MASK                     0x0F00  /* DRC_DCY - [11:8] */
+#define WM9081_DRC_DCY_SHIFT                         8  /* DRC_DCY - [11:8] */
+#define WM9081_DRC_DCY_WIDTH                         4  /* DRC_DCY - [11:8] */
+#define WM9081_DRC_QR_THR_MASK                  0x00C0  /* DRC_QR_THR - [7:6] */
+#define WM9081_DRC_QR_THR_SHIFT                      6  /* DRC_QR_THR - [7:6] */
+#define WM9081_DRC_QR_THR_WIDTH                      2  /* DRC_QR_THR - [7:6] */
+#define WM9081_DRC_QR_DCY_MASK                  0x0030  /* DRC_QR_DCY - [5:4] */
+#define WM9081_DRC_QR_DCY_SHIFT                      4  /* DRC_QR_DCY - [5:4] */
+#define WM9081_DRC_QR_DCY_WIDTH                      2  /* DRC_QR_DCY - [5:4] */
+#define WM9081_DRC_MINGAIN_MASK                 0x000C  /* DRC_MINGAIN - [3:2] */
+#define WM9081_DRC_MINGAIN_SHIFT                     2  /* DRC_MINGAIN - [3:2] */
+#define WM9081_DRC_MINGAIN_WIDTH                     2  /* DRC_MINGAIN - [3:2] */
+#define WM9081_DRC_MAXGAIN_MASK                 0x0003  /* DRC_MAXGAIN - [1:0] */
+#define WM9081_DRC_MAXGAIN_SHIFT                     0  /* DRC_MAXGAIN - [1:0] */
+#define WM9081_DRC_MAXGAIN_WIDTH                     2  /* DRC_MAXGAIN - [1:0] */
+
+/*
+ * R34 (0x22) - DRC 3
+ */
+#define WM9081_DRC_HI_COMP_MASK                 0x0038  /* DRC_HI_COMP - [5:3] */
+#define WM9081_DRC_HI_COMP_SHIFT                     3  /* DRC_HI_COMP - [5:3] */
+#define WM9081_DRC_HI_COMP_WIDTH                     3  /* DRC_HI_COMP - [5:3] */
+#define WM9081_DRC_LO_COMP_MASK                 0x0007  /* DRC_LO_COMP - [2:0] */
+#define WM9081_DRC_LO_COMP_SHIFT                     0  /* DRC_LO_COMP - [2:0] */
+#define WM9081_DRC_LO_COMP_WIDTH                     3  /* DRC_LO_COMP - [2:0] */
+
+/*
+ * R35 (0x23) - DRC 4
+ */
+#define WM9081_DRC_KNEE_IP_MASK                 0x07E0  /* DRC_KNEE_IP - [10:5] */
+#define WM9081_DRC_KNEE_IP_SHIFT                     5  /* DRC_KNEE_IP - [10:5] */
+#define WM9081_DRC_KNEE_IP_WIDTH                     6  /* DRC_KNEE_IP - [10:5] */
+#define WM9081_DRC_KNEE_OP_MASK                 0x001F  /* DRC_KNEE_OP - [4:0] */
+#define WM9081_DRC_KNEE_OP_SHIFT                     0  /* DRC_KNEE_OP - [4:0] */
+#define WM9081_DRC_KNEE_OP_WIDTH                     5  /* DRC_KNEE_OP - [4:0] */
+
+/*
+ * R38 (0x26) - Write Sequencer 1
+ */
+#define WM9081_WSEQ_ENA                         0x8000  /* WSEQ_ENA */
+#define WM9081_WSEQ_ENA_MASK                    0x8000  /* WSEQ_ENA */
+#define WM9081_WSEQ_ENA_SHIFT                       15  /* WSEQ_ENA */
+#define WM9081_WSEQ_ENA_WIDTH                        1  /* WSEQ_ENA */
+#define WM9081_WSEQ_ABORT                       0x0200  /* WSEQ_ABORT */
+#define WM9081_WSEQ_ABORT_MASK                  0x0200  /* WSEQ_ABORT */
+#define WM9081_WSEQ_ABORT_SHIFT                      9  /* WSEQ_ABORT */
+#define WM9081_WSEQ_ABORT_WIDTH                      1  /* WSEQ_ABORT */
+#define WM9081_WSEQ_START                       0x0100  /* WSEQ_START */
+#define WM9081_WSEQ_START_MASK                  0x0100  /* WSEQ_START */
+#define WM9081_WSEQ_START_SHIFT                      8  /* WSEQ_START */
+#define WM9081_WSEQ_START_WIDTH                      1  /* WSEQ_START */
+#define WM9081_WSEQ_START_INDEX_MASK            0x007F  /* WSEQ_START_INDEX - [6:0] */
+#define WM9081_WSEQ_START_INDEX_SHIFT                0  /* WSEQ_START_INDEX - [6:0] */
+#define WM9081_WSEQ_START_INDEX_WIDTH                7  /* WSEQ_START_INDEX - [6:0] */
+
+/*
+ * R39 (0x27) - Write Sequencer 2
+ */
+#define WM9081_WSEQ_CURRENT_INDEX_MASK          0x07F0  /* WSEQ_CURRENT_INDEX - [10:4] */
+#define WM9081_WSEQ_CURRENT_INDEX_SHIFT              4  /* WSEQ_CURRENT_INDEX - [10:4] */
+#define WM9081_WSEQ_CURRENT_INDEX_WIDTH              7  /* WSEQ_CURRENT_INDEX - [10:4] */
+#define WM9081_WSEQ_BUSY                        0x0001  /* WSEQ_BUSY */
+#define WM9081_WSEQ_BUSY_MASK                   0x0001  /* WSEQ_BUSY */
+#define WM9081_WSEQ_BUSY_SHIFT                       0  /* WSEQ_BUSY */
+#define WM9081_WSEQ_BUSY_WIDTH                       1  /* WSEQ_BUSY */
+
+/*
+ * R40 (0x28) - MW Slave 1
+ */
+#define WM9081_SPI_CFG                          0x0020  /* SPI_CFG */
+#define WM9081_SPI_CFG_MASK                     0x0020  /* SPI_CFG */
+#define WM9081_SPI_CFG_SHIFT                         5  /* SPI_CFG */
+#define WM9081_SPI_CFG_WIDTH                         1  /* SPI_CFG */
+#define WM9081_SPI_4WIRE                        0x0010  /* SPI_4WIRE */
+#define WM9081_SPI_4WIRE_MASK                   0x0010  /* SPI_4WIRE */
+#define WM9081_SPI_4WIRE_SHIFT                       4  /* SPI_4WIRE */
+#define WM9081_SPI_4WIRE_WIDTH                       1  /* SPI_4WIRE */
+#define WM9081_ARA_ENA                          0x0008  /* ARA_ENA */
+#define WM9081_ARA_ENA_MASK                     0x0008  /* ARA_ENA */
+#define WM9081_ARA_ENA_SHIFT                         3  /* ARA_ENA */
+#define WM9081_ARA_ENA_WIDTH                         1  /* ARA_ENA */
+#define WM9081_AUTO_INC                         0x0002  /* AUTO_INC */
+#define WM9081_AUTO_INC_MASK                    0x0002  /* AUTO_INC */
+#define WM9081_AUTO_INC_SHIFT                        1  /* AUTO_INC */
+#define WM9081_AUTO_INC_WIDTH                        1  /* AUTO_INC */
+
+/*
+ * R42 (0x2A) - EQ 1
+ */
+#define WM9081_EQ_B1_GAIN_MASK                  0xF800  /* EQ_B1_GAIN - [15:11] */
+#define WM9081_EQ_B1_GAIN_SHIFT                     11  /* EQ_B1_GAIN - [15:11] */
+#define WM9081_EQ_B1_GAIN_WIDTH                      5  /* EQ_B1_GAIN - [15:11] */
+#define WM9081_EQ_B2_GAIN_MASK                  0x07C0  /* EQ_B2_GAIN - [10:6] */
+#define WM9081_EQ_B2_GAIN_SHIFT                      6  /* EQ_B2_GAIN - [10:6] */
+#define WM9081_EQ_B2_GAIN_WIDTH                      5  /* EQ_B2_GAIN - [10:6] */
+#define WM9081_EQ_B4_GAIN_MASK                  0x003E  /* EQ_B4_GAIN - [5:1] */
+#define WM9081_EQ_B4_GAIN_SHIFT                      1  /* EQ_B4_GAIN - [5:1] */
+#define WM9081_EQ_B4_GAIN_WIDTH                      5  /* EQ_B4_GAIN - [5:1] */
+#define WM9081_EQ_ENA                           0x0001  /* EQ_ENA */
+#define WM9081_EQ_ENA_MASK                      0x0001  /* EQ_ENA */
+#define WM9081_EQ_ENA_SHIFT                          0  /* EQ_ENA */
+#define WM9081_EQ_ENA_WIDTH                          1  /* EQ_ENA */
+
+/*
+ * R43 (0x2B) - EQ 2
+ */
+#define WM9081_EQ_B3_GAIN_MASK                  0xF800  /* EQ_B3_GAIN - [15:11] */
+#define WM9081_EQ_B3_GAIN_SHIFT                     11  /* EQ_B3_GAIN - [15:11] */
+#define WM9081_EQ_B3_GAIN_WIDTH                      5  /* EQ_B3_GAIN - [15:11] */
+#define WM9081_EQ_B5_GAIN_MASK                  0x07C0  /* EQ_B5_GAIN - [10:6] */
+#define WM9081_EQ_B5_GAIN_SHIFT                      6  /* EQ_B5_GAIN - [10:6] */
+#define WM9081_EQ_B5_GAIN_WIDTH                      5  /* EQ_B5_GAIN - [10:6] */
+
+/*
+ * R44 (0x2C) - EQ 3
+ */
+#define WM9081_EQ_B1_A_MASK                     0xFFFF  /* EQ_B1_A - [15:0] */
+#define WM9081_EQ_B1_A_SHIFT                         0  /* EQ_B1_A - [15:0] */
+#define WM9081_EQ_B1_A_WIDTH                        16  /* EQ_B1_A - [15:0] */
+
+/*
+ * R45 (0x2D) - EQ 4
+ */
+#define WM9081_EQ_B1_B_MASK                     0xFFFF  /* EQ_B1_B - [15:0] */
+#define WM9081_EQ_B1_B_SHIFT                         0  /* EQ_B1_B - [15:0] */
+#define WM9081_EQ_B1_B_WIDTH                        16  /* EQ_B1_B - [15:0] */
+
+/*
+ * R46 (0x2E) - EQ 5
+ */
+#define WM9081_EQ_B1_PG_MASK                    0xFFFF  /* EQ_B1_PG - [15:0] */
+#define WM9081_EQ_B1_PG_SHIFT                        0  /* EQ_B1_PG - [15:0] */
+#define WM9081_EQ_B1_PG_WIDTH                       16  /* EQ_B1_PG - [15:0] */
+
+/*
+ * R47 (0x2F) - EQ 6
+ */
+#define WM9081_EQ_B2_A_MASK                     0xFFFF  /* EQ_B2_A - [15:0] */
+#define WM9081_EQ_B2_A_SHIFT                         0  /* EQ_B2_A - [15:0] */
+#define WM9081_EQ_B2_A_WIDTH                        16  /* EQ_B2_A - [15:0] */
+
+/*
+ * R48 (0x30) - EQ 7
+ */
+#define WM9081_EQ_B2_B_MASK                     0xFFFF  /* EQ_B2_B - [15:0] */
+#define WM9081_EQ_B2_B_SHIFT                         0  /* EQ_B2_B - [15:0] */
+#define WM9081_EQ_B2_B_WIDTH                        16  /* EQ_B2_B - [15:0] */
+
+/*
+ * R49 (0x31) - EQ 8
+ */
+#define WM9081_EQ_B2_C_MASK                     0xFFFF  /* EQ_B2_C - [15:0] */
+#define WM9081_EQ_B2_C_SHIFT                         0  /* EQ_B2_C - [15:0] */
+#define WM9081_EQ_B2_C_WIDTH                        16  /* EQ_B2_C - [15:0] */
+
+/*
+ * R50 (0x32) - EQ 9
+ */
+#define WM9081_EQ_B2_PG_MASK                    0xFFFF  /* EQ_B2_PG - [15:0] */
+#define WM9081_EQ_B2_PG_SHIFT                        0  /* EQ_B2_PG - [15:0] */
+#define WM9081_EQ_B2_PG_WIDTH                       16  /* EQ_B2_PG - [15:0] */
+
+/*
+ * R51 (0x33) - EQ 10
+ */
+#define WM9081_EQ_B4_A_MASK                     0xFFFF  /* EQ_B4_A - [15:0] */
+#define WM9081_EQ_B4_A_SHIFT                         0  /* EQ_B4_A - [15:0] */
+#define WM9081_EQ_B4_A_WIDTH                        16  /* EQ_B4_A - [15:0] */
+
+/*
+ * R52 (0x34) - EQ 11
+ */
+#define WM9081_EQ_B4_B_MASK                     0xFFFF  /* EQ_B4_B - [15:0] */
+#define WM9081_EQ_B4_B_SHIFT                         0  /* EQ_B4_B - [15:0] */
+#define WM9081_EQ_B4_B_WIDTH                        16  /* EQ_B4_B - [15:0] */
+
+/*
+ * R53 (0x35) - EQ 12
+ */
+#define WM9081_EQ_B4_C_MASK                     0xFFFF  /* EQ_B4_C - [15:0] */
+#define WM9081_EQ_B4_C_SHIFT                         0  /* EQ_B4_C - [15:0] */
+#define WM9081_EQ_B4_C_WIDTH                        16  /* EQ_B4_C - [15:0] */
+
+/*
+ * R54 (0x36) - EQ 13
+ */
+#define WM9081_EQ_B4_PG_MASK                    0xFFFF  /* EQ_B4_PG - [15:0] */
+#define WM9081_EQ_B4_PG_SHIFT                        0  /* EQ_B4_PG - [15:0] */
+#define WM9081_EQ_B4_PG_WIDTH                       16  /* EQ_B4_PG - [15:0] */
+
+/*
+ * R55 (0x37) - EQ 14
+ */
+#define WM9081_EQ_B3_A_MASK                     0xFFFF  /* EQ_B3_A - [15:0] */
+#define WM9081_EQ_B3_A_SHIFT                         0  /* EQ_B3_A - [15:0] */
+#define WM9081_EQ_B3_A_WIDTH                        16  /* EQ_B3_A - [15:0] */
+
+/*
+ * R56 (0x38) - EQ 15
+ */
+#define WM9081_EQ_B3_B_MASK                     0xFFFF  /* EQ_B3_B - [15:0] */
+#define WM9081_EQ_B3_B_SHIFT                         0  /* EQ_B3_B - [15:0] */
+#define WM9081_EQ_B3_B_WIDTH                        16  /* EQ_B3_B - [15:0] */
+
+/*
+ * R57 (0x39) - EQ 16
+ */
+#define WM9081_EQ_B3_C_MASK                     0xFFFF  /* EQ_B3_C - [15:0] */
+#define WM9081_EQ_B3_C_SHIFT                         0  /* EQ_B3_C - [15:0] */
+#define WM9081_EQ_B3_C_WIDTH                        16  /* EQ_B3_C - [15:0] */
+
+/*
+ * R58 (0x3A) - EQ 17
+ */
+#define WM9081_EQ_B3_PG_MASK                    0xFFFF  /* EQ_B3_PG - [15:0] */
+#define WM9081_EQ_B3_PG_SHIFT                        0  /* EQ_B3_PG - [15:0] */
+#define WM9081_EQ_B3_PG_WIDTH                       16  /* EQ_B3_PG - [15:0] */
+
+/*
+ * R59 (0x3B) - EQ 18
+ */
+#define WM9081_EQ_B5_A_MASK                     0xFFFF  /* EQ_B5_A - [15:0] */
+#define WM9081_EQ_B5_A_SHIFT                         0  /* EQ_B5_A - [15:0] */
+#define WM9081_EQ_B5_A_WIDTH                        16  /* EQ_B5_A - [15:0] */
+
+/*
+ * R60 (0x3C) - EQ 19
+ */
+#define WM9081_EQ_B5_B_MASK                     0xFFFF  /* EQ_B5_B - [15:0] */
+#define WM9081_EQ_B5_B_SHIFT                         0  /* EQ_B5_B - [15:0] */
+#define WM9081_EQ_B5_B_WIDTH                        16  /* EQ_B5_B - [15:0] */
+
+/*
+ * R61 (0x3D) - EQ 20
+ */
+#define WM9081_EQ_B5_PG_MASK                    0xFFFF  /* EQ_B5_PG - [15:0] */
+#define WM9081_EQ_B5_PG_SHIFT                        0  /* EQ_B5_PG - [15:0] */
+#define WM9081_EQ_B5_PG_WIDTH                       16  /* EQ_B5_PG - [15:0] */
+
+
+#endif
index c2d1a7a18fa3893757eef782372fa976314702e6..fa88b463e71f37f4a07bc830db69c50d2e52b39c 100644 (file)
@@ -282,14 +282,14 @@ struct snd_soc_dai wm9705_dai[] = {
                        .channels_min = 1,
                        .channels_max = 2,
                        .rates = WM9705_AC97_RATES,
-                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                       .formats = SND_SOC_STD_AC97_FMTS,
                },
                .capture = {
                        .stream_name = "HiFi Capture",
                        .channels_min = 1,
                        .channels_max = 2,
                        .rates = WM9705_AC97_RATES,
-                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                       .formats = SND_SOC_STD_AC97_FMTS,
                },
                .ops = &wm9705_dai_ops,
        },
index 765cf1e7369eb37c3a8f85a5e8257a22c2957f8e..1fd4e88f50cff74db693676172518601671532ab 100644 (file)
@@ -534,13 +534,13 @@ struct snd_soc_dai wm9712_dai[] = {
                .channels_min = 1,
                .channels_max = 2,
                .rates = WM9712_AC97_RATES,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+               .formats = SND_SOC_STD_AC97_FMTS,},
        .capture = {
                .stream_name = "HiFi Capture",
                .channels_min = 1,
                .channels_max = 2,
                .rates = WM9712_AC97_RATES,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+               .formats = SND_SOC_STD_AC97_FMTS,},
        .ops = &wm9712_dai_ops_hifi,
 },
 {
@@ -550,7 +550,7 @@ struct snd_soc_dai wm9712_dai[] = {
                .channels_min = 1,
                .channels_max = 1,
                .rates = WM9712_AC97_RATES,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+               .formats = SND_SOC_STD_AC97_FMTS,},
        .ops = &wm9712_dai_ops_aux,
 }
 };
@@ -585,6 +585,8 @@ static int wm9712_reset(struct snd_soc_codec *codec, int try_warm)
        }
 
        soc_ac97_ops.reset(codec->ac97);
+       if (soc_ac97_ops.warm_reset)
+               soc_ac97_ops.warm_reset(codec->ac97);
        if (ac97_read(codec, 0) != wm9712_reg[0])
                goto err;
        return 0;
index 523bad077fa04cc3f84a74feb7289bbb01c2c6a5..abed37acf78714be6b7f5dd534df94dc6c2be319 100644 (file)
@@ -189,6 +189,26 @@ SOC_SINGLE("3D Lower Cut-off Switch", AC97_REC_GAIN_MIC, 4, 1, 0),
 SOC_SINGLE("3D Depth", AC97_REC_GAIN_MIC, 0, 15, 1),
 };
 
+static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w,
+                                struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       u16 status, rate;
+
+       BUG_ON(event != SND_SOC_DAPM_PRE_PMD);
+
+       /* Gracefully shut down the voice interface. */
+       status = ac97_read(codec, AC97_EXTENDED_MID) | 0x1000;
+       rate = ac97_read(codec, AC97_HANDSET_RATE) & 0xF0FF;
+       ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0200);
+       schedule_timeout_interruptible(msecs_to_jiffies(1));
+       ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0F00);
+       ac97_write(codec, AC97_EXTENDED_MID, status);
+
+       return 0;
+}
+
+
 /* We have to create a fake left and right HP mixers because
  * the codec only has a single control that is shared by both channels.
  * This makes it impossible to determine the audio path using the current
@@ -400,7 +420,8 @@ SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
 SND_SOC_DAPM_MIXER("HP Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
 SND_SOC_DAPM_MIXER("Line Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
 SND_SOC_DAPM_MIXER("Capture Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
-SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback", AC97_EXTENDED_MID, 12, 1),
+SND_SOC_DAPM_DAC_E("Voice DAC", "Voice Playback", AC97_EXTENDED_MID, 12, 1,
+                  wm9713_voice_shutdown, SND_SOC_DAPM_PRE_PMD),
 SND_SOC_DAPM_DAC("Aux DAC", "Aux Playback", AC97_EXTENDED_MID, 11, 1),
 SND_SOC_DAPM_PGA("Left ADC", AC97_EXTENDED_MID, 5, 1, NULL, 0),
 SND_SOC_DAPM_PGA("Right ADC", AC97_EXTENDED_MID, 4, 1, NULL, 0),
@@ -689,7 +710,7 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int source)
        Ndiv = target / source;
        if ((Ndiv < 5) || (Ndiv > 12))
                printk(KERN_WARNING
-                       "WM9713 PLL N value %d out of recommended range!\n",
+                       "WM9713 PLL N value %u out of recommended range!\n",
                        Ndiv);
 
        pll_div->n = Ndiv;
@@ -936,21 +957,6 @@ static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static void wm9713_voiceshutdown(struct snd_pcm_substream *substream,
-                                struct snd_soc_dai *dai)
-{
-       struct snd_soc_codec *codec = dai->codec;
-       u16 status, rate;
-
-       /* Gracefully shut down the voice interface. */
-       status = ac97_read(codec, AC97_EXTENDED_STATUS) | 0x1000;
-       rate = ac97_read(codec, AC97_HANDSET_RATE) & 0xF0FF;
-       ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0200);
-       schedule_timeout_interruptible(msecs_to_jiffies(1));
-       ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0F00);
-       ac97_write(codec, AC97_EXTENDED_MID, status);
-}
-
 static int ac97_hifi_prepare(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
@@ -1019,7 +1025,6 @@ static struct snd_soc_dai_ops wm9713_dai_ops_aux = {
 
 static struct snd_soc_dai_ops wm9713_dai_ops_voice = {
        .hw_params      = wm9713_pcm_hw_params,
-       .shutdown       = wm9713_voiceshutdown,
        .set_clkdiv     = wm9713_set_dai_clkdiv,
        .set_pll        = wm9713_set_dai_pll,
        .set_fmt        = wm9713_set_dai_fmt,
@@ -1035,13 +1040,13 @@ struct snd_soc_dai wm9713_dai[] = {
                .channels_min = 1,
                .channels_max = 2,
                .rates = WM9713_RATES,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+               .formats = SND_SOC_STD_AC97_FMTS,},
        .capture = {
                .stream_name = "HiFi Capture",
                .channels_min = 1,
                .channels_max = 2,
                .rates = WM9713_RATES,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+               .formats = SND_SOC_STD_AC97_FMTS,},
        .ops = &wm9713_dai_ops_hifi,
        },
        {
@@ -1051,7 +1056,7 @@ struct snd_soc_dai wm9713_dai[] = {
                .channels_min = 1,
                .channels_max = 1,
                .rates = WM9713_RATES,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+               .formats = SND_SOC_STD_AC97_FMTS,},
        .ops = &wm9713_dai_ops_aux,
        },
        {
@@ -1069,6 +1074,7 @@ struct snd_soc_dai wm9713_dai[] = {
                .rates = WM9713_PCM_RATES,
                .formats = WM9713_PCM_FORMATS,},
        .ops = &wm9713_dai_ops_voice,
+       .symmetric_rates = 1,
        },
 };
 EXPORT_SYMBOL_GPL(wm9713_dai);
index 9fc9082833716dc4b16df21bf6e5e30267913f8f..5dbebf82249ca735776d942ed9e3335e7b300b09 100644 (file)
@@ -1,5 +1,8 @@
 config SND_SOC_OF_SIMPLE
        tristate
+       
+config SND_MPC52xx_DMA
+       tristate
 
 # ASoC platform support for the Freescale MPC8610 SOC.  This compiles drivers
 # for the SSI and the Elo DMA controller.  You will still need to select
@@ -22,7 +25,34 @@ config SND_SOC_MPC8610_HPCD
 config SND_SOC_MPC5200_I2S
        tristate "Freescale MPC5200 PSC in I2S mode driver"
        depends on PPC_MPC52xx && PPC_BESTCOMM
-       select SND_SOC_OF_SIMPLE
+       select SND_MPC52xx_DMA
        select PPC_BESTCOMM_GEN_BD
        help
          Say Y here to support the MPC5200 PSCs in I2S mode.
+
+config SND_SOC_MPC5200_AC97
+       tristate "Freescale MPC5200 PSC in AC97 mode driver"
+       depends on PPC_MPC52xx && PPC_BESTCOMM
+       select AC97_BUS
+       select SND_MPC52xx_DMA
+       select PPC_BESTCOMM_GEN_BD
+       help
+         Say Y here to support the MPC5200 PSCs in AC97 mode.
+
+config SND_MPC52xx_SOC_PCM030
+       tristate "SoC AC97 Audio support for Phytec pcm030 and WM9712"
+       depends on PPC_MPC5200_SIMPLE && BROKEN
+       select SND_SOC_MPC5200_AC97
+       select SND_SOC_WM9712
+       help
+         Say Y if you want to add support for sound on the Phytec pcm030
+         baseboard.
+
+config SND_MPC52xx_SOC_EFIKA
+       tristate "SoC AC97 Audio support for bbplan Efika and STAC9766"
+       depends on PPC_EFIKA && BROKEN
+       select SND_SOC_MPC5200_AC97
+       select SND_SOC_STAC9766
+       help
+         Say Y if you want to add support for sound on the Efika.
+
index f85134c863871f6a73a5dca1e96f371893a8e602..a83a73967ec666a14409bb8f64c3b540c8b0f401 100644 (file)
@@ -10,5 +10,12 @@ snd-soc-fsl-ssi-objs := fsl_ssi.o
 snd-soc-fsl-dma-objs := fsl_dma.o
 obj-$(CONFIG_SND_SOC_MPC8610) += snd-soc-fsl-ssi.o snd-soc-fsl-dma.o
 
+# MPC5200 Platform Support
+obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o
 obj-$(CONFIG_SND_SOC_MPC5200_I2S) += mpc5200_psc_i2s.o
+obj-$(CONFIG_SND_SOC_MPC5200_AC97) += mpc5200_psc_ac97.o
+
+# MPC5200 Machine Support
+obj-$(CONFIG_SND_MPC52xx_SOC_PCM030) += pcm030-audio-fabric.o
+obj-$(CONFIG_SND_MPC52xx_SOC_EFIKA) += efika-audio-fabric.o
 
diff --git a/sound/soc/fsl/efika-audio-fabric.c b/sound/soc/fsl/efika-audio-fabric.c
new file mode 100644 (file)
index 0000000..85b0e75
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Efika driver for the PSC of the Freescale MPC52xx
+ * configured as AC97 interface
+ *
+ * Copyright 2008 Jon Smirl, Digispeaker
+ * Author: Jon Smirl <jonsmirl@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/soc-of-simple.h>
+
+#include "mpc5200_dma.h"
+#include "mpc5200_psc_ac97.h"
+#include "../codecs/stac9766.h"
+
+static struct snd_soc_device device;
+static struct snd_soc_card card;
+
+static struct snd_soc_dai_link efika_fabric_dai[] = {
+{
+       .name = "AC97",
+       .stream_name = "AC97 Analog",
+       .codec_dai = &stac9766_dai[STAC9766_DAI_AC97_ANALOG],
+       .cpu_dai = &psc_ac97_dai[MPC5200_AC97_NORMAL],
+},
+{
+       .name = "AC97",
+       .stream_name = "AC97 IEC958",
+       .codec_dai = &stac9766_dai[STAC9766_DAI_AC97_DIGITAL],
+       .cpu_dai = &psc_ac97_dai[MPC5200_AC97_SPDIF],
+},
+};
+
+static __init int efika_fabric_init(void)
+{
+       struct platform_device *pdev;
+       int rc;
+
+       if (!machine_is_compatible("bplan,efika"))
+               return -ENODEV;
+
+       card.platform = &mpc5200_audio_dma_platform;
+       card.name = "Efika";
+       card.dai_link = efika_fabric_dai;
+       card.num_links = ARRAY_SIZE(efika_fabric_dai);
+
+       device.card = &card;
+       device.codec_dev = &soc_codec_dev_stac9766;
+
+       pdev = platform_device_alloc("soc-audio", 1);
+       if (!pdev) {
+               pr_err("efika_fabric_init: platform_device_alloc() failed\n");
+               return -ENODEV;
+       }
+
+       platform_set_drvdata(pdev, &device);
+       device.dev = &pdev->dev;
+
+       rc = platform_device_add(pdev);
+       if (rc) {
+               pr_err("efika_fabric_init: platform_device_add() failed\n");
+               return -ENODEV;
+       }
+       return 0;
+}
+
+module_init(efika_fabric_init);
+
+
+MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
+MODULE_DESCRIPTION(DRV_NAME ": mpc5200 Efika fabric driver");
+MODULE_LICENSE("GPL");
+
index 3711d8454d96b893117c77941d8bd6794e0890db..93f0f38a32c99fb26299c288d3ce0ca442f55914 100644 (file)
@@ -375,18 +375,14 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
                struct snd_pcm_runtime *first_runtime =
                        ssi_private->first_stream->runtime;
 
-               if (!first_runtime->rate || !first_runtime->sample_bits) {
+               if (!first_runtime->sample_bits) {
                        dev_err(substream->pcm->card->dev,
-                               "set sample rate and size in %s stream first\n",
+                               "set sample size in %s stream first\n",
                                substream->stream == SNDRV_PCM_STREAM_PLAYBACK
                                ? "capture" : "playback");
                        return -EAGAIN;
                }
 
-               snd_pcm_hw_constraint_minmax(substream->runtime,
-                       SNDRV_PCM_HW_PARAM_RATE,
-                       first_runtime->rate, first_runtime->rate);
-
                /* If we're in synchronous mode, then we need to constrain
                 * the sample size as well.  We don't support independent sample
                 * rates in asynchronous mode.
@@ -674,7 +670,7 @@ struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info)
        ssi_private->dev = ssi_info->dev;
        ssi_private->asynchronous = ssi_info->asynchronous;
 
-       ssi_private->dev->driver_data = fsl_ssi_dai;
+       dev_set_drvdata(ssi_private->dev, fsl_ssi_dai);
 
        /* Initialize the the device_attribute structure */
        dev_attr->attr.name = "ssi-stats";
@@ -693,6 +689,7 @@ struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info)
        fsl_ssi_dai->name = ssi_private->name;
        fsl_ssi_dai->id = ssi_info->id;
        fsl_ssi_dai->dev = ssi_info->dev;
+       fsl_ssi_dai->symmetric_rates = 1;
 
        ret = snd_soc_register_dai(fsl_ssi_dai);
        if (ret != 0) {
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
new file mode 100644 (file)
index 0000000..efec33a
--- /dev/null
@@ -0,0 +1,564 @@
+/*
+ * Freescale MPC5200 PSC DMA
+ * ALSA SoC Platform driver
+ *
+ * Copyright (C) 2008 Secret Lab Technologies Ltd.
+ * Copyright (C) 2009 Jon Smirl, Digispeaker
+ */
+
+#include <linux/module.h>
+#include <linux/of_device.h>
+
+#include <sound/soc.h>
+
+#include <sysdev/bestcomm/bestcomm.h>
+#include <sysdev/bestcomm/gen_bd.h>
+#include <asm/mpc52xx_psc.h>
+
+#include "mpc5200_dma.h"
+
+/*
+ * Interrupt handlers
+ */
+static irqreturn_t psc_dma_status_irq(int irq, void *_psc_dma)
+{
+       struct psc_dma *psc_dma = _psc_dma;
+       struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
+       u16 isr;
+
+       isr = in_be16(&regs->mpc52xx_psc_isr);
+
+       /* Playback underrun error */
+       if (psc_dma->playback.active && (isr & MPC52xx_PSC_IMR_TXEMP))
+               psc_dma->stats.underrun_count++;
+
+       /* Capture overrun error */
+       if (psc_dma->capture.active && (isr & MPC52xx_PSC_IMR_ORERR))
+               psc_dma->stats.overrun_count++;
+
+       out_8(&regs->command, MPC52xx_PSC_RST_ERR_STAT);
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * psc_dma_bcom_enqueue_next_buffer - Enqueue another audio buffer
+ * @s: pointer to stream private data structure
+ *
+ * Enqueues another audio period buffer into the bestcomm queue.
+ *
+ * Note: The routine must only be called when there is space available in
+ * the queue.  Otherwise the enqueue will fail and the audio ring buffer
+ * will get out of sync
+ */
+static void psc_dma_bcom_enqueue_next_buffer(struct psc_dma_stream *s)
+{
+       struct bcom_bd *bd;
+
+       /* 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;
+       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)
+{
+       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);
+       }
+}
+
+/* Bestcomm DMA irq handler */
+static irqreturn_t psc_dma_bcom_irq_tx(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;
+       }
+       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;
+
+               psc_dma_bcom_enqueue_next_buffer(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 int psc_dma_hw_free(struct snd_pcm_substream *substream)
+{
+       snd_pcm_set_runtime_buffer(substream, NULL);
+       return 0;
+}
+
+/**
+ * psc_dma_trigger: start and stop the DMA transfer.
+ *
+ * This function is called by ALSA to start, stop, pause, and resume the DMA
+ * transfer of data.
+ */
+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 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:
+               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->active = 1;
+
+               /* track appl_ptr so that we have a better chance of detecting
+                * end of stream and not over running it.
+                */
+               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) {
+                       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 {
+                       bcom_gen_bd_tx_reset(s->bcom_task);
+                       psc_dma_bcom_enqueue_tx(s);
+               }
+
+               bcom_enable(s->bcom_task);
+               spin_unlock_irqrestore(&psc_dma->lock, flags);
+
+               out_8(&regs->command, MPC52xx_PSC_RST_ERR_STAT);
+
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+               s->active = 0;
+
+               spin_lock_irqsave(&psc_dma->lock, flags);
+               bcom_disable(s->bcom_task);
+               if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+                       bcom_gen_bd_rx_reset(s->bcom_task);
+               else
+                       bcom_gen_bd_tx_reset(s->bcom_task);
+               spin_unlock_irqrestore(&psc_dma->lock, flags);
+
+               break;
+
+       default:
+               dev_dbg(psc_dma->dev, "invalid command\n");
+               return -EINVAL;
+       }
+
+       /* Update interrupt enable settings */
+       imr = 0;
+       if (psc_dma->playback.active)
+               imr |= MPC52xx_PSC_IMR_TXEMP;
+       if (psc_dma->capture.active)
+               imr |= MPC52xx_PSC_IMR_ORERR;
+       out_be16(&regs->isr_imr.imr, psc_dma->imr | imr);
+
+       return 0;
+}
+
+
+/* ---------------------------------------------------------------------
+ * The PSC DMA 'ASoC platform' driver
+ *
+ * Can be referenced by an 'ASoC machine' driver
+ * This driver only deals with the audio bus; it doesn't have any
+ * interaction with the attached codec
+ */
+
+static const struct snd_pcm_hardware psc_dma_hardware = {
+       .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_BATCH,
+       .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE |
+               SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE,
+       .rate_min = 8000,
+       .rate_max = 48000,
+       .channels_min = 1,
+       .channels_max = 2,
+       .period_bytes_max       = 1024 * 1024,
+       .period_bytes_min       = 32,
+       .periods_min            = 2,
+       .periods_max            = 256,
+       .buffer_bytes_max       = 2 * 1024 * 1024,
+       .fifo_size              = 512,
+};
+
+static int psc_dma_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       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;
+       int rc;
+
+       dev_dbg(psc_dma->dev, "psc_dma_open(substream=%p)\n", substream);
+
+       if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+               s = &psc_dma->capture;
+       else
+               s = &psc_dma->playback;
+
+       snd_soc_set_runtime_hwparams(substream, &psc_dma_hardware);
+
+       rc = snd_pcm_hw_constraint_integer(runtime,
+               SNDRV_PCM_HW_PARAM_PERIODS);
+       if (rc < 0) {
+               dev_err(substream->pcm->card->dev, "invalid buffer size\n");
+               return rc;
+       }
+
+       s->stream = substream;
+       return 0;
+}
+
+static int psc_dma_close(struct snd_pcm_substream *substream)
+{
+       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;
+
+       dev_dbg(psc_dma->dev, "psc_dma_close(substream=%p)\n", substream);
+
+       if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+               s = &psc_dma->capture;
+       else
+               s = &psc_dma->playback;
+
+       if (!psc_dma->playback.active &&
+           !psc_dma->capture.active) {
+
+               /* Disable all interrupts and reset the PSC */
+               out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);
+               out_8(&psc_dma->psc_regs->command, 4 << 4); /* reset error */
+       }
+       s->stream = NULL;
+       return 0;
+}
+
+static snd_pcm_uframes_t
+psc_dma_pointer(struct snd_pcm_substream *substream)
+{
+       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;
+       dma_addr_t count;
+
+       if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+               s = &psc_dma->capture;
+       else
+               s = &psc_dma->playback;
+
+       count = s->period_current_pt - s->period_start;
+
+       return bytes_to_frames(substream->runtime, count);
+}
+
+static int
+psc_dma_hw_params(struct snd_pcm_substream *substream,
+                        struct snd_pcm_hw_params *params)
+{
+       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+       return 0;
+}
+
+static struct snd_pcm_ops psc_dma_ops = {
+       .open           = psc_dma_open,
+       .close          = psc_dma_close,
+       .hw_free        = psc_dma_hw_free,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .pointer        = psc_dma_pointer,
+       .trigger        = psc_dma_trigger,
+       .hw_params      = psc_dma_hw_params,
+};
+
+static u64 psc_dma_dmamask = 0xffffffff;
+static int psc_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
+                          struct snd_pcm *pcm)
+{
+       struct snd_soc_pcm_runtime *rtd = pcm->private_data;
+       struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+       size_t size = psc_dma_hardware.buffer_bytes_max;
+       int rc = 0;
+
+       dev_dbg(rtd->socdev->dev, "psc_dma_new(card=%p, dai=%p, pcm=%p)\n",
+               card, dai, pcm);
+
+       if (!card->dev->dma_mask)
+               card->dev->dma_mask = &psc_dma_dmamask;
+       if (!card->dev->coherent_dma_mask)
+               card->dev->coherent_dma_mask = 0xffffffff;
+
+       if (pcm->streams[0].substream) {
+               rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev,
+                               size, &pcm->streams[0].substream->dma_buffer);
+               if (rc)
+                       goto playback_alloc_err;
+       }
+
+       if (pcm->streams[1].substream) {
+               rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev,
+                               size, &pcm->streams[1].substream->dma_buffer);
+               if (rc)
+                       goto capture_alloc_err;
+       }
+
+       if (rtd->socdev->card->codec->ac97)
+               rtd->socdev->card->codec->ac97->private_data = psc_dma;
+
+       return 0;
+
+ capture_alloc_err:
+       if (pcm->streams[0].substream)
+               snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
+
+ playback_alloc_err:
+       dev_err(card->dev, "Cannot allocate buffer(s)\n");
+
+       return -ENOMEM;
+}
+
+static void psc_dma_free(struct snd_pcm *pcm)
+{
+       struct snd_soc_pcm_runtime *rtd = pcm->private_data;
+       struct snd_pcm_substream *substream;
+       int stream;
+
+       dev_dbg(rtd->socdev->dev, "psc_dma_free(pcm=%p)\n", pcm);
+
+       for (stream = 0; stream < 2; stream++) {
+               substream = pcm->streams[stream].substream;
+               if (substream) {
+                       snd_dma_free_pages(&substream->dma_buffer);
+                       substream->dma_buffer.area = NULL;
+                       substream->dma_buffer.addr = 0;
+               }
+       }
+}
+
+struct snd_soc_platform mpc5200_audio_dma_platform = {
+       .name           = "mpc5200-psc-audio",
+       .pcm_ops        = &psc_dma_ops,
+       .pcm_new        = &psc_dma_new,
+       .pcm_free       = &psc_dma_free,
+};
+EXPORT_SYMBOL_GPL(mpc5200_audio_dma_platform);
+
+int mpc5200_audio_dma_create(struct of_device *op)
+{
+       phys_addr_t fifo;
+       struct psc_dma *psc_dma;
+       struct resource res;
+       int size, irq, rc;
+       const __be32 *prop;
+       void __iomem *regs;
+
+       /* Fetch the registers and IRQ of the PSC */
+       irq = irq_of_parse_and_map(op->node, 0);
+       if (of_address_to_resource(op->node, 0, &res)) {
+               dev_err(&op->dev, "Missing reg property\n");
+               return -ENODEV;
+       }
+       regs = ioremap(res.start, 1 + res.end - res.start);
+       if (!regs) {
+               dev_err(&op->dev, "Could not map registers\n");
+               return -ENODEV;
+       }
+
+       /* Allocate and initialize the driver private data */
+       psc_dma = kzalloc(sizeof *psc_dma, GFP_KERNEL);
+       if (!psc_dma) {
+               iounmap(regs);
+               return -ENOMEM;
+       }
+
+       /* Get the PSC ID */
+       prop = of_get_property(op->node, "cell-index", &size);
+       if (!prop || size < sizeof *prop)
+               return -ENODEV;
+
+       spin_lock_init(&psc_dma->lock);
+       psc_dma->id = be32_to_cpu(*prop);
+       psc_dma->irq = irq;
+       psc_dma->psc_regs = regs;
+       psc_dma->fifo_regs = regs + sizeof *psc_dma->psc_regs;
+       psc_dma->dev = &op->dev;
+       psc_dma->playback.psc_dma = psc_dma;
+       psc_dma->capture.psc_dma = psc_dma;
+       snprintf(psc_dma->name, sizeof psc_dma->name, "PSC%u", psc_dma->id);
+
+       /* Find the address of the fifo data registers and setup the
+        * DMA tasks */
+       fifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32);
+       psc_dma->capture.bcom_task =
+               bcom_psc_gen_bd_rx_init(psc_dma->id, 10, fifo, 512);
+       psc_dma->playback.bcom_task =
+               bcom_psc_gen_bd_tx_init(psc_dma->id, 10, fifo);
+       if (!psc_dma->capture.bcom_task ||
+           !psc_dma->playback.bcom_task) {
+               dev_err(&op->dev, "Could not allocate bestcomm tasks\n");
+               iounmap(regs);
+               kfree(psc_dma);
+               return -ENODEV;
+       }
+
+       /* Disable all interrupts and reset the PSC */
+       out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);
+        /* reset receiver */
+       out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_RX);
+        /* reset transmitter */
+       out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_TX);
+        /* reset error */
+       out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_ERR_STAT);
+        /* reset mode */
+       out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_SEL_MODE_REG_1);
+
+       /* Set up mode register;
+        * First write: RxRdy (FIFO Alarm) generates rx FIFO irq
+        * Second write: register Normal mode for non loopback
+        */
+       out_8(&psc_dma->psc_regs->mode, 0);
+       out_8(&psc_dma->psc_regs->mode, 0);
+
+       /* Set the TX and RX fifo alarm thresholds */
+       out_be16(&psc_dma->fifo_regs->rfalarm, 0x100);
+       out_8(&psc_dma->fifo_regs->rfcntl, 0x4);
+       out_be16(&psc_dma->fifo_regs->tfalarm, 0x100);
+       out_8(&psc_dma->fifo_regs->tfcntl, 0x7);
+
+       /* Lookup the IRQ numbers */
+       psc_dma->playback.irq =
+               bcom_get_task_irq(psc_dma->playback.bcom_task);
+       psc_dma->capture.irq =
+               bcom_get_task_irq(psc_dma->capture.bcom_task);
+
+       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,
+                         "psc-dma-capture", &psc_dma->capture);
+       rc |= request_irq(psc_dma->playback.irq,
+                         &psc_dma_bcom_irq_tx, IRQF_SHARED,
+                         "psc-dma-playback", &psc_dma->playback);
+       if (rc) {
+               free_irq(psc_dma->irq, psc_dma);
+               free_irq(psc_dma->capture.irq,
+                        &psc_dma->capture);
+               free_irq(psc_dma->playback.irq,
+                        &psc_dma->playback);
+               return -ENODEV;
+       }
+
+       /* Save what we've done so it can be found again later */
+       dev_set_drvdata(&op->dev, psc_dma);
+
+       /* Tell the ASoC OF helpers about it */
+       return snd_soc_register_platform(&mpc5200_audio_dma_platform);
+}
+EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create);
+
+int mpc5200_audio_dma_destroy(struct of_device *op)
+{
+       struct psc_dma *psc_dma = dev_get_drvdata(&op->dev);
+
+       dev_dbg(&op->dev, "mpc5200_audio_dma_destroy()\n");
+
+       snd_soc_unregister_platform(&mpc5200_audio_dma_platform);
+
+       bcom_gen_bd_rx_release(psc_dma->capture.bcom_task);
+       bcom_gen_bd_tx_release(psc_dma->playback.bcom_task);
+
+       /* Release irqs */
+       free_irq(psc_dma->irq, psc_dma);
+       free_irq(psc_dma->capture.irq, &psc_dma->capture);
+       free_irq(psc_dma->playback.irq, &psc_dma->playback);
+
+       iounmap(psc_dma->psc_regs);
+       kfree(psc_dma);
+       dev_set_drvdata(&op->dev, NULL);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mpc5200_audio_dma_destroy);
+
+MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
+MODULE_DESCRIPTION("Freescale MPC5200 PSC in DMA mode ASoC Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/mpc5200_dma.h b/sound/soc/fsl/mpc5200_dma.h
new file mode 100644 (file)
index 0000000..2000803
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Freescale MPC5200 Audio DMA driver
+ */
+
+#ifndef __SOUND_SOC_FSL_MPC5200_DMA_H__
+#define __SOUND_SOC_FSL_MPC5200_DMA_H__
+
+#define PSC_STREAM_NAME_LEN 32
+
+/**
+ * psc_ac97_stream - Data specific to a single stream (playback or capture)
+ * @active:            flag indicating if the stream is active
+ * @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
+ */
+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_bytes;
+       int period_size;
+};
+
+/**
+ * psc_dma - Private driver data
+ * @name: short name for this device ("PSC0", "PSC1", etc)
+ * @psc_regs: pointer to the PSC's registers
+ * @fifo_regs: pointer to the PSC's FIFO registers
+ * @irq: IRQ of this PSC
+ * @dev: struct device pointer
+ * @dai: the CPU DAI for this device
+ * @sicr: Base value used in serial interface control register; mode is ORed
+ *        with this value.
+ * @playback: Playback stream context data
+ * @capture: Capture stream context data
+ */
+struct psc_dma {
+       char name[32];
+       struct mpc52xx_psc __iomem *psc_regs;
+       struct mpc52xx_psc_fifo __iomem *fifo_regs;
+       unsigned int irq;
+       struct device *dev;
+       spinlock_t lock;
+       u32 sicr;
+       uint sysclk;
+       int imr;
+       int id;
+       unsigned int slots;
+
+       /* per-stream data */
+       struct psc_dma_stream playback;
+       struct psc_dma_stream capture;
+
+       /* Statistics */
+       struct {
+               unsigned long overrun_count;
+               unsigned long underrun_count;
+       } stats;
+};
+
+int mpc5200_audio_dma_create(struct of_device *op);
+int mpc5200_audio_dma_destroy(struct of_device *op);
+
+extern struct snd_soc_platform mpc5200_audio_dma_platform;
+
+#endif /* __SOUND_SOC_FSL_MPC5200_DMA_H__ */
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c
new file mode 100644 (file)
index 0000000..794a247
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+ * linux/sound/mpc5200-ac97.c -- AC97 support for the Freescale MPC52xx chip.
+ *
+ * Copyright (C) 2009 Jon Smirl, Digispeaker
+ * Author: Jon Smirl <jonsmirl@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/time.h>
+#include <asm/delay.h>
+#include <asm/mpc52xx_psc.h>
+
+#include "mpc5200_dma.h"
+#include "mpc5200_psc_ac97.h"
+
+#define DRV_NAME "mpc5200-psc-ac97"
+
+/* ALSA only supports a single AC97 device so static is recommend here */
+static struct psc_dma *psc_dma;
+
+static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
+{
+       int status;
+       unsigned int val;
+
+       /* Wait for command send status zero = ready */
+       status = spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) &
+                               MPC52xx_PSC_SR_CMDSEND), 100, 0);
+       if (status == 0) {
+               pr_err("timeout on ac97 bus (rdy)\n");
+               return -ENODEV;
+       }
+       /* Send the read */
+       out_be32(&psc_dma->psc_regs->ac97_cmd, (1<<31) | ((reg & 0x7f) << 24));
+
+       /* Wait for the answer */
+       status = spin_event_timeout((in_be16(&psc_dma->psc_regs->sr_csr.status) &
+                               MPC52xx_PSC_SR_DATA_VAL), 100, 0);
+       if (status == 0) {
+               pr_err("timeout on ac97 read (val) %x\n",
+                               in_be16(&psc_dma->psc_regs->sr_csr.status));
+               return -ENODEV;
+       }
+       /* Get the data */
+       val = in_be32(&psc_dma->psc_regs->ac97_data);
+       if (((val >> 24) & 0x7f) != reg) {
+               pr_err("reg echo error on ac97 read\n");
+               return -ENODEV;
+       }
+       val = (val >> 8) & 0xffff;
+
+       return (unsigned short) val;
+}
+
+static void psc_ac97_write(struct snd_ac97 *ac97,
+                               unsigned short reg, unsigned short val)
+{
+       int status;
+
+       /* Wait for command status zero = ready */
+       status = spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) &
+                               MPC52xx_PSC_SR_CMDSEND), 100, 0);
+       if (status == 0) {
+               pr_err("timeout on ac97 bus (write)\n");
+               return;
+       }
+       /* Write data */
+       out_be32(&psc_dma->psc_regs->ac97_cmd,
+                       ((reg & 0x7f) << 24) | (val << 8));
+}
+
+static void psc_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+       struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
+
+       out_be32(&regs->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_AWR);
+       udelay(3);
+       out_be32(&regs->sicr, psc_dma->sicr);
+}
+
+static void psc_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+       struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
+
+       /* Do a cold reset */
+       out_8(&regs->op1, MPC52xx_PSC_OP_RES);
+       udelay(10);
+       out_8(&regs->op0, MPC52xx_PSC_OP_RES);
+       udelay(50);
+       psc_ac97_warm_reset(ac97);
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+       .read           = psc_ac97_read,
+       .write          = psc_ac97_write,
+       .reset          = psc_ac97_cold_reset,
+       .warm_reset     = psc_ac97_warm_reset,
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+static int psc_ac97_hw_analog_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *cpu_dai)
+{
+       struct psc_dma *psc_dma = cpu_dai->private_data;
+
+       dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
+               " periods=%i buffer_size=%i  buffer_bytes=%i channels=%i"
+               " rate=%i format=%i\n",
+               __func__, substream, params_period_size(params),
+               params_period_bytes(params), params_periods(params),
+               params_buffer_size(params), params_buffer_bytes(params),
+               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);
+
+       return 0;
+}
+
+static int psc_ac97_hw_digital_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *cpu_dai)
+{
+       struct psc_dma *psc_dma = cpu_dai->private_data;
+
+       if (params_channels(params) == 1)
+               out_be32(&psc_dma->psc_regs->ac97_slots, 0x01000000);
+       else
+               out_be32(&psc_dma->psc_regs->ac97_slots, 0x03000000);
+
+       return 0;
+}
+
+static int psc_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
+                                                       struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_STOP:
+               if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+                       psc_dma->slots &= 0xFFFF0000;
+               else
+                       psc_dma->slots &= 0x0000FFFF;
+
+               out_be32(&psc_dma->psc_regs->ac97_slots, psc_dma->slots);
+               break;
+       }
+       return 0;
+}
+
+static int psc_ac97_probe(struct platform_device *pdev,
+                                       struct snd_soc_dai *cpu_dai)
+{
+       struct psc_dma *psc_dma = cpu_dai->private_data;
+       struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
+
+       /* Go */
+       out_8(&regs->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
+       return 0;
+}
+
+/* ---------------------------------------------------------------------
+ * ALSA SoC Bindings
+ *
+ * - Digital Audio Interface (DAI) template
+ * - create/destroy dai hooks
+ */
+
+/**
+ * psc_ac97_dai_template: template CPU Digital Audio Interface
+ */
+static struct snd_soc_dai_ops psc_ac97_analog_ops = {
+       .hw_params      = psc_ac97_hw_analog_params,
+       .trigger        = psc_ac97_trigger,
+};
+
+static struct snd_soc_dai_ops psc_ac97_digital_ops = {
+       .hw_params      = psc_ac97_hw_digital_params,
+};
+
+struct snd_soc_dai psc_ac97_dai[] = {
+{
+       .name   = "AC97",
+       .ac97_control = 1,
+       .probe  = psc_ac97_probe,
+       .playback = {
+               .channels_min   = 1,
+               .channels_max   = 6,
+               .rates          = SNDRV_PCM_RATE_8000_48000,
+               .formats = SNDRV_PCM_FMTBIT_S32_BE,
+       },
+       .capture = {
+               .channels_min   = 1,
+               .channels_max   = 2,
+               .rates          = SNDRV_PCM_RATE_8000_48000,
+               .formats = SNDRV_PCM_FMTBIT_S32_BE,
+       },
+       .ops = &psc_ac97_analog_ops,
+},
+{
+       .name   = "SPDIF",
+       .ac97_control = 1,
+       .playback = {
+               .channels_min   = 1,
+               .channels_max   = 2,
+               .rates          = SNDRV_PCM_RATE_32000 | \
+                       SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE,
+       },
+       .ops = &psc_ac97_digital_ops,
+} };
+EXPORT_SYMBOL_GPL(psc_ac97_dai);
+
+
+
+/* ---------------------------------------------------------------------
+ * OF platform bus binding code:
+ * - Probe/remove operations
+ * - OF device match table
+ */
+static int __devinit psc_ac97_of_probe(struct of_device *op,
+                                     const struct of_device_id *match)
+{
+       int rc, i;
+       struct snd_ac97 ac97;
+       struct mpc52xx_psc __iomem *regs;
+
+       rc = mpc5200_audio_dma_create(op);
+       if (rc != 0)
+               return rc;
+
+       for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++)
+               psc_ac97_dai[i].dev = &op->dev;
+
+       rc = snd_soc_register_dais(psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
+       if (rc != 0) {
+               dev_err(&op->dev, "Failed to register DAI\n");
+               return rc;
+       }
+
+       psc_dma = dev_get_drvdata(&op->dev);
+       regs = psc_dma->psc_regs;
+       ac97.private_data = psc_dma;
+
+       for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++)
+               psc_ac97_dai[i].private_data = psc_dma;
+
+       psc_dma->imr = 0;
+       out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);
+
+       /* Configure the serial interface mode to AC97 */
+       psc_dma->sicr = MPC52xx_PSC_SICR_SIM_AC97 | MPC52xx_PSC_SICR_ENAC97;
+       out_be32(&regs->sicr, psc_dma->sicr);
+
+       /* No slots active */
+       out_be32(&regs->ac97_slots, 0x00000000);
+
+       return 0;
+}
+
+static int __devexit psc_ac97_of_remove(struct of_device *op)
+{
+       return mpc5200_audio_dma_destroy(op);
+}
+
+/* Match table for of_platform binding */
+static struct of_device_id psc_ac97_match[] __devinitdata = {
+       { .compatible = "fsl,mpc5200-psc-ac97", },
+       { .compatible = "fsl,mpc5200b-psc-ac97", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, psc_ac97_match);
+
+static struct of_platform_driver psc_ac97_driver = {
+       .match_table = psc_ac97_match,
+       .probe = psc_ac97_of_probe,
+       .remove = __devexit_p(psc_ac97_of_remove),
+       .driver = {
+               .name = "mpc5200-psc-ac97",
+               .owner = THIS_MODULE,
+       },
+};
+
+/* ---------------------------------------------------------------------
+ * Module setup and teardown; simply register the of_platform driver
+ * for the PSC in AC97 mode.
+ */
+static int __init psc_ac97_init(void)
+{
+       return of_register_platform_driver(&psc_ac97_driver);
+}
+module_init(psc_ac97_init);
+
+static void __exit psc_ac97_exit(void)
+{
+       of_unregister_platform_driver(&psc_ac97_driver);
+}
+module_exit(psc_ac97_exit);
+
+MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
+MODULE_DESCRIPTION("mpc5200 AC97 module");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.h b/sound/soc/fsl/mpc5200_psc_ac97.h
new file mode 100644 (file)
index 0000000..4bc18c3
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Freescale MPC5200 PSC in AC97 mode
+ * ALSA SoC Digital Audio Interface (DAI) driver
+ *
+ */
+
+#ifndef __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__
+#define __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__
+
+extern struct snd_soc_dai psc_ac97_dai[];
+
+#define MPC5200_AC97_NORMAL 0
+#define MPC5200_AC97_SPDIF 1
+
+#endif /* __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__ */
index 1111c710118a2b8bd84fd6796d9c26a096437fa5..ce8de90fb94ae54d5ce7adbd05735f5395a4d7f7 100644 (file)
@@ -3,31 +3,21 @@
  * ALSA SoC Digital Audio Interface (DAI) driver
  *
  * Copyright (C) 2008 Secret Lab Technologies Ltd.
+ * Copyright (C) 2009 Jon Smirl, Digispeaker
  */
 
-#include <linux/init.h>
 #include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/delay.h>
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
-#include <linux/dma-mapping.h>
 
-#include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
-#include <sound/initval.h>
 #include <sound/soc.h>
-#include <sound/soc-of-simple.h>
 
-#include <sysdev/bestcomm/bestcomm.h>
-#include <sysdev/bestcomm/gen_bd.h>
 #include <asm/mpc52xx_psc.h>
 
-MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
-MODULE_DESCRIPTION("Freescale MPC5200 PSC in I2S mode ASoC Driver");
-MODULE_LICENSE("GPL");
+#include "mpc5200_psc_i2s.h"
+#include "mpc5200_dma.h"
 
 /**
  * PSC_I2S_RATES: sample rates supported by the I2S
@@ -44,191 +34,17 @@ MODULE_LICENSE("GPL");
  * PSC_I2S_FORMATS: audio formats supported by the PSC I2S mode
  */
 #define PSC_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \
-                        SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S24_BE | \
-                        SNDRV_PCM_FMTBIT_S32_BE)
-
-/**
- * psc_i2s_stream - Data specific to a single stream (playback or capture)
- * @active:            flag indicating if the stream is active
- * @psc_i2s:           pointer back to parent psc_i2s 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
- */
-struct psc_i2s_stream {
-       int active;
-       struct psc_i2s *psc_i2s;
-       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_bytes;
-};
-
-/**
- * psc_i2s - Private driver data
- * @name: short name for this device ("PSC0", "PSC1", etc)
- * @psc_regs: pointer to the PSC's registers
- * @fifo_regs: pointer to the PSC's FIFO registers
- * @irq: IRQ of this PSC
- * @dev: struct device pointer
- * @dai: the CPU DAI for this device
- * @sicr: Base value used in serial interface control register; mode is ORed
- *        with this value.
- * @playback: Playback stream context data
- * @capture: Capture stream context data
- */
-struct psc_i2s {
-       char name[32];
-       struct mpc52xx_psc __iomem *psc_regs;
-       struct mpc52xx_psc_fifo __iomem *fifo_regs;
-       unsigned int irq;
-       struct device *dev;
-       struct snd_soc_dai dai;
-       spinlock_t lock;
-       u32 sicr;
-
-       /* per-stream data */
-       struct psc_i2s_stream playback;
-       struct psc_i2s_stream capture;
-
-       /* Statistics */
-       struct {
-               int overrun_count;
-               int underrun_count;
-       } stats;
-};
-
-/*
- * Interrupt handlers
- */
-static irqreturn_t psc_i2s_status_irq(int irq, void *_psc_i2s)
-{
-       struct psc_i2s *psc_i2s = _psc_i2s;
-       struct mpc52xx_psc __iomem *regs = psc_i2s->psc_regs;
-       u16 isr;
-
-       isr = in_be16(&regs->mpc52xx_psc_isr);
-
-       /* Playback underrun error */
-       if (psc_i2s->playback.active && (isr & MPC52xx_PSC_IMR_TXEMP))
-               psc_i2s->stats.underrun_count++;
-
-       /* Capture overrun error */
-       if (psc_i2s->capture.active && (isr & MPC52xx_PSC_IMR_ORERR))
-               psc_i2s->stats.overrun_count++;
-
-       out_8(&regs->command, 4 << 4);  /* reset the error status */
-
-       return IRQ_HANDLED;
-}
-
-/**
- * psc_i2s_bcom_enqueue_next_buffer - Enqueue another audio buffer
- * @s: pointer to stream private data structure
- *
- * Enqueues another audio period buffer into the bestcomm queue.
- *
- * Note: The routine must only be called when there is space available in
- * the queue.  Otherwise the enqueue will fail and the audio ring buffer
- * will get out of sync
- */
-static void psc_i2s_bcom_enqueue_next_buffer(struct psc_i2s_stream *s)
-{
-       struct bcom_bd *bd;
-
-       /* 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;
-       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;
-}
-
-/* Bestcomm DMA irq handler */
-static irqreturn_t psc_i2s_bcom_irq(int irq, void *_psc_i2s_stream)
-{
-       struct psc_i2s_stream *s = _psc_i2s_stream;
-
-       /* 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;
-               psc_i2s_bcom_enqueue_next_buffer(s);
-               bcom_enable(s->bcom_task);
-       }
-
-       /* 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;
-}
-
-/**
- * psc_i2s_startup: create a new substream
- *
- * This is the first function called when a stream is opened.
- *
- * If this is the first stream open, then grab the IRQ and program most of
- * the PSC registers.
- */
-static int psc_i2s_startup(struct snd_pcm_substream *substream,
-                          struct snd_soc_dai *dai)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
-       int rc;
-
-       dev_dbg(psc_i2s->dev, "psc_i2s_startup(substream=%p)\n", substream);
-
-       if (!psc_i2s->playback.active &&
-           !psc_i2s->capture.active) {
-               /* Setup the IRQs */
-               rc = request_irq(psc_i2s->irq, &psc_i2s_status_irq, IRQF_SHARED,
-                                "psc-i2s-status", psc_i2s);
-               rc |= request_irq(psc_i2s->capture.irq,
-                                 &psc_i2s_bcom_irq, IRQF_SHARED,
-                                 "psc-i2s-capture", &psc_i2s->capture);
-               rc |= request_irq(psc_i2s->playback.irq,
-                                 &psc_i2s_bcom_irq, IRQF_SHARED,
-                                 "psc-i2s-playback", &psc_i2s->playback);
-               if (rc) {
-                       free_irq(psc_i2s->irq, psc_i2s);
-                       free_irq(psc_i2s->capture.irq,
-                                &psc_i2s->capture);
-                       free_irq(psc_i2s->playback.irq,
-                                &psc_i2s->playback);
-                       return -ENODEV;
-               }
-       }
-
-       return 0;
-}
+                        SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE)
 
 static int psc_i2s_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 psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
+       struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
        u32 mode;
 
-       dev_dbg(psc_i2s->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
+       dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
                " periods=%i buffer_size=%i  buffer_bytes=%i\n",
                __func__, substream, params_period_size(params),
                params_period_bytes(params), params_periods(params),
@@ -248,174 +64,14 @@ static int psc_i2s_hw_params(struct snd_pcm_substream *substream,
                mode = MPC52xx_PSC_SICR_SIM_CODEC_32;
                break;
        default:
-               dev_dbg(psc_i2s->dev, "invalid format\n");
-               return -EINVAL;
-       }
-       out_be32(&psc_i2s->psc_regs->sicr, psc_i2s->sicr | mode);
-
-       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-
-       return 0;
-}
-
-static int psc_i2s_hw_free(struct snd_pcm_substream *substream,
-                          struct snd_soc_dai *dai)
-{
-       snd_pcm_set_runtime_buffer(substream, NULL);
-       return 0;
-}
-
-/**
- * psc_i2s_trigger: start and stop the DMA transfer.
- *
- * This function is called by ALSA to start, stop, pause, and resume the DMA
- * transfer of data.
- */
-static int psc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
-                          struct snd_soc_dai *dai)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct psc_i2s_stream *s;
-       struct mpc52xx_psc __iomem *regs = psc_i2s->psc_regs;
-       u16 imr;
-       u8 psc_cmd;
-       unsigned long flags;
-
-       if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
-               s = &psc_i2s->capture;
-       else
-               s = &psc_i2s->playback;
-
-       dev_dbg(psc_i2s->dev, "psc_i2s_trigger(substream=%p, cmd=%i)"
-               " stream_id=%i\n",
-               substream, cmd, substream->pstr->stream);
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               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->active = 1;
-
-               /* First; reset everything */
-               if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
-                       out_8(&regs->command, MPC52xx_PSC_RST_RX);
-                       out_8(&regs->command, MPC52xx_PSC_RST_ERR_STAT);
-               } else {
-                       out_8(&regs->command, MPC52xx_PSC_RST_TX);
-                       out_8(&regs->command, MPC52xx_PSC_RST_ERR_STAT);
-               }
-
-               /* Next, fill up the bestcomm bd queue and enable DMA.
-                * This will begin filling the PSC's fifo. */
-               if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
-                       bcom_gen_bd_rx_reset(s->bcom_task);
-               else
-                       bcom_gen_bd_tx_reset(s->bcom_task);
-               while (!bcom_queue_full(s->bcom_task))
-                       psc_i2s_bcom_enqueue_next_buffer(s);
-               bcom_enable(s->bcom_task);
-
-               /* Due to errata in the i2s mode; need to line up enabling
-                * the transmitter with a transition on the frame sync
-                * line */
-
-               spin_lock_irqsave(&psc_i2s->lock, flags);
-               /* first make sure it is low */
-               while ((in_8(&regs->ipcr_acr.ipcr) & 0x80) != 0)
-                       ;
-               /* then wait for the transition to high */
-               while ((in_8(&regs->ipcr_acr.ipcr) & 0x80) == 0)
-                       ;
-               /* Finally, enable the PSC.
-                * Receiver must always be enabled; even when we only want
-                * transmit.  (see 15.3.2.3 of MPC5200B User's Guide) */
-               psc_cmd = MPC52xx_PSC_RX_ENABLE;
-               if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       psc_cmd |= MPC52xx_PSC_TX_ENABLE;
-               out_8(&regs->command, psc_cmd);
-               spin_unlock_irqrestore(&psc_i2s->lock, flags);
-
-               break;
-
-       case SNDRV_PCM_TRIGGER_STOP:
-               /* Turn off the PSC */
-               s->active = 0;
-               if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
-                       if (!psc_i2s->playback.active) {
-                               out_8(&regs->command, 2 << 4);  /* reset rx */
-                               out_8(&regs->command, 3 << 4);  /* reset tx */
-                               out_8(&regs->command, 4 << 4);  /* reset err */
-                       }
-               } else {
-                       out_8(&regs->command, 3 << 4);  /* reset tx */
-                       out_8(&regs->command, 4 << 4);  /* reset err */
-                       if (!psc_i2s->capture.active)
-                               out_8(&regs->command, 2 << 4);  /* reset rx */
-               }
-
-               bcom_disable(s->bcom_task);
-               while (!bcom_queue_empty(s->bcom_task))
-                       bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
-
-               break;
-
-       default:
-               dev_dbg(psc_i2s->dev, "invalid command\n");
+               dev_dbg(psc_dma->dev, "invalid format\n");
                return -EINVAL;
        }
-
-       /* Update interrupt enable settings */
-       imr = 0;
-       if (psc_i2s->playback.active)
-               imr |= MPC52xx_PSC_IMR_TXEMP;
-       if (psc_i2s->capture.active)
-               imr |= MPC52xx_PSC_IMR_ORERR;
-       out_be16(&regs->isr_imr.imr, imr);
+       out_be32(&psc_dma->psc_regs->sicr, psc_dma->sicr | mode);
 
        return 0;
 }
 
-/**
- * psc_i2s_shutdown: shutdown the data transfer on a stream
- *
- * Shutdown the PSC if there are no other substreams open.
- */
-static void psc_i2s_shutdown(struct snd_pcm_substream *substream,
-                            struct snd_soc_dai *dai)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
-
-       dev_dbg(psc_i2s->dev, "psc_i2s_shutdown(substream=%p)\n", substream);
-
-       /*
-        * If this is the last active substream, disable the PSC and release
-        * the IRQ.
-        */
-       if (!psc_i2s->playback.active &&
-           !psc_i2s->capture.active) {
-
-               /* Disable all interrupts and reset the PSC */
-               out_be16(&psc_i2s->psc_regs->isr_imr.imr, 0);
-               out_8(&psc_i2s->psc_regs->command, 3 << 4); /* reset tx */
-               out_8(&psc_i2s->psc_regs->command, 2 << 4); /* reset rx */
-               out_8(&psc_i2s->psc_regs->command, 1 << 4); /* reset mode */
-               out_8(&psc_i2s->psc_regs->command, 4 << 4); /* reset error */
-
-               /* Release irqs */
-               free_irq(psc_i2s->irq, psc_i2s);
-               free_irq(psc_i2s->capture.irq, &psc_i2s->capture);
-               free_irq(psc_i2s->playback.irq, &psc_i2s->playback);
-       }
-}
-
 /**
  * psc_i2s_set_sysclk: set the clock frequency and direction
  *
@@ -433,8 +89,8 @@ static void psc_i2s_shutdown(struct snd_pcm_substream *substream,
 static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
                              int clk_id, unsigned int freq, int dir)
 {
-       struct psc_i2s *psc_i2s = cpu_dai->private_data;
-       dev_dbg(psc_i2s->dev, "psc_i2s_set_sysclk(cpu_dai=%p, dir=%i)\n",
+       struct psc_dma *psc_dma = cpu_dai->private_data;
+       dev_dbg(psc_dma->dev, "psc_i2s_set_sysclk(cpu_dai=%p, dir=%i)\n",
                                cpu_dai, dir);
        return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL;
 }
@@ -452,8 +108,8 @@ static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
  */
 static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
 {
-       struct psc_i2s *psc_i2s = cpu_dai->private_data;
-       dev_dbg(psc_i2s->dev, "psc_i2s_set_fmt(cpu_dai=%p, format=%i)\n",
+       struct psc_dma *psc_dma = cpu_dai->private_data;
+       dev_dbg(psc_dma->dev, "psc_i2s_set_fmt(cpu_dai=%p, format=%i)\n",
                                cpu_dai, format);
        return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL;
 }
@@ -469,16 +125,13 @@ static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
  * psc_i2s_dai_template: template CPU Digital Audio Interface
  */
 static struct snd_soc_dai_ops psc_i2s_dai_ops = {
-       .startup        = psc_i2s_startup,
        .hw_params      = psc_i2s_hw_params,
-       .hw_free        = psc_i2s_hw_free,
-       .shutdown       = psc_i2s_shutdown,
-       .trigger        = psc_i2s_trigger,
        .set_sysclk     = psc_i2s_set_sysclk,
        .set_fmt        = psc_i2s_set_fmt,
 };
 
-static struct snd_soc_dai psc_i2s_dai_template = {
+struct snd_soc_dai psc_i2s_dai[] = {{
+       .name   = "I2S",
        .playback = {
                .channels_min = 2,
                .channels_max = 2,
@@ -492,223 +145,8 @@ static struct snd_soc_dai psc_i2s_dai_template = {
                .formats = PSC_I2S_FORMATS,
        },
        .ops = &psc_i2s_dai_ops,
-};
-
-/* ---------------------------------------------------------------------
- * The PSC I2S 'ASoC platform' driver
- *
- * Can be referenced by an 'ASoC machine' driver
- * This driver only deals with the audio bus; it doesn't have any
- * interaction with the attached codec
- */
-
-static const struct snd_pcm_hardware psc_i2s_pcm_hardware = {
-       .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
-               SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
-               SNDRV_PCM_INFO_BATCH,
-       .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE |
-                  SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE,
-       .rate_min = 8000,
-       .rate_max = 48000,
-       .channels_min = 2,
-       .channels_max = 2,
-       .period_bytes_max       = 1024 * 1024,
-       .period_bytes_min       = 32,
-       .periods_min            = 2,
-       .periods_max            = 256,
-       .buffer_bytes_max       = 2 * 1024 * 1024,
-       .fifo_size              = 0,
-};
-
-static int psc_i2s_pcm_open(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
-       struct psc_i2s_stream *s;
-
-       dev_dbg(psc_i2s->dev, "psc_i2s_pcm_open(substream=%p)\n", substream);
-
-       if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
-               s = &psc_i2s->capture;
-       else
-               s = &psc_i2s->playback;
-
-       snd_soc_set_runtime_hwparams(substream, &psc_i2s_pcm_hardware);
-
-       s->stream = substream;
-       return 0;
-}
-
-static int psc_i2s_pcm_close(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
-       struct psc_i2s_stream *s;
-
-       dev_dbg(psc_i2s->dev, "psc_i2s_pcm_close(substream=%p)\n", substream);
-
-       if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
-               s = &psc_i2s->capture;
-       else
-               s = &psc_i2s->playback;
-
-       s->stream = NULL;
-       return 0;
-}
-
-static snd_pcm_uframes_t
-psc_i2s_pcm_pointer(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
-       struct psc_i2s_stream *s;
-       dma_addr_t count;
-
-       if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
-               s = &psc_i2s->capture;
-       else
-               s = &psc_i2s->playback;
-
-       count = s->period_current_pt - s->period_start;
-
-       return bytes_to_frames(substream->runtime, count);
-}
-
-static struct snd_pcm_ops psc_i2s_pcm_ops = {
-       .open           = psc_i2s_pcm_open,
-       .close          = psc_i2s_pcm_close,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .pointer        = psc_i2s_pcm_pointer,
-};
-
-static u64 psc_i2s_pcm_dmamask = 0xffffffff;
-static int psc_i2s_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
-                          struct snd_pcm *pcm)
-{
-       struct snd_soc_pcm_runtime *rtd = pcm->private_data;
-       size_t size = psc_i2s_pcm_hardware.buffer_bytes_max;
-       int rc = 0;
-
-       dev_dbg(rtd->socdev->dev, "psc_i2s_pcm_new(card=%p, dai=%p, pcm=%p)\n",
-               card, dai, pcm);
-
-       if (!card->dev->dma_mask)
-               card->dev->dma_mask = &psc_i2s_pcm_dmamask;
-       if (!card->dev->coherent_dma_mask)
-               card->dev->coherent_dma_mask = 0xffffffff;
-
-       if (pcm->streams[0].substream) {
-               rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, size,
-                                       &pcm->streams[0].substream->dma_buffer);
-               if (rc)
-                       goto playback_alloc_err;
-       }
-
-       if (pcm->streams[1].substream) {
-               rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, size,
-                                       &pcm->streams[1].substream->dma_buffer);
-               if (rc)
-                       goto capture_alloc_err;
-       }
-
-       return 0;
-
- capture_alloc_err:
-       if (pcm->streams[0].substream)
-               snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
- playback_alloc_err:
-       dev_err(card->dev, "Cannot allocate buffer(s)\n");
-       return -ENOMEM;
-}
-
-static void psc_i2s_pcm_free(struct snd_pcm *pcm)
-{
-       struct snd_soc_pcm_runtime *rtd = pcm->private_data;
-       struct snd_pcm_substream *substream;
-       int stream;
-
-       dev_dbg(rtd->socdev->dev, "psc_i2s_pcm_free(pcm=%p)\n", pcm);
-
-       for (stream = 0; stream < 2; stream++) {
-               substream = pcm->streams[stream].substream;
-               if (substream) {
-                       snd_dma_free_pages(&substream->dma_buffer);
-                       substream->dma_buffer.area = NULL;
-                       substream->dma_buffer.addr = 0;
-               }
-       }
-}
-
-struct snd_soc_platform psc_i2s_pcm_soc_platform = {
-       .name           = "mpc5200-psc-audio",
-       .pcm_ops        = &psc_i2s_pcm_ops,
-       .pcm_new        = &psc_i2s_pcm_new,
-       .pcm_free       = &psc_i2s_pcm_free,
-};
-
-/* ---------------------------------------------------------------------
- * Sysfs attributes for debugging
- */
-
-static ssize_t psc_i2s_status_show(struct device *dev,
-                          struct device_attribute *attr, char *buf)
-{
-       struct psc_i2s *psc_i2s = dev_get_drvdata(dev);
-
-       return sprintf(buf, "status=%.4x sicr=%.8x rfnum=%i rfstat=0x%.4x "
-                       "tfnum=%i tfstat=0x%.4x\n",
-                       in_be16(&psc_i2s->psc_regs->sr_csr.status),
-                       in_be32(&psc_i2s->psc_regs->sicr),
-                       in_be16(&psc_i2s->fifo_regs->rfnum) & 0x1ff,
-                       in_be16(&psc_i2s->fifo_regs->rfstat),
-                       in_be16(&psc_i2s->fifo_regs->tfnum) & 0x1ff,
-                       in_be16(&psc_i2s->fifo_regs->tfstat));
-}
-
-static int *psc_i2s_get_stat_attr(struct psc_i2s *psc_i2s, const char *name)
-{
-       if (strcmp(name, "playback_underrun") == 0)
-               return &psc_i2s->stats.underrun_count;
-       if (strcmp(name, "capture_overrun") == 0)
-               return &psc_i2s->stats.overrun_count;
-
-       return NULL;
-}
-
-static ssize_t psc_i2s_stat_show(struct device *dev,
-                                struct device_attribute *attr, char *buf)
-{
-       struct psc_i2s *psc_i2s = dev_get_drvdata(dev);
-       int *attrib;
-
-       attrib = psc_i2s_get_stat_attr(psc_i2s, attr->attr.name);
-       if (!attrib)
-               return 0;
-
-       return sprintf(buf, "%i\n", *attrib);
-}
-
-static ssize_t psc_i2s_stat_store(struct device *dev,
-                                 struct device_attribute *attr,
-                                 const char *buf,
-                                 size_t count)
-{
-       struct psc_i2s *psc_i2s = dev_get_drvdata(dev);
-       int *attrib;
-
-       attrib = psc_i2s_get_stat_attr(psc_i2s, attr->attr.name);
-       if (!attrib)
-               return 0;
-
-       *attrib = simple_strtoul(buf, NULL, 0);
-       return count;
-}
-
-static DEVICE_ATTR(status, 0644, psc_i2s_status_show, NULL);
-static DEVICE_ATTR(playback_underrun, 0644, psc_i2s_stat_show,
-                       psc_i2s_stat_store);
-static DEVICE_ATTR(capture_overrun, 0644, psc_i2s_stat_show,
-                       psc_i2s_stat_store);
+} };
+EXPORT_SYMBOL_GPL(psc_i2s_dai);
 
 /* ---------------------------------------------------------------------
  * OF platform bus binding code:
@@ -718,150 +156,65 @@ static DEVICE_ATTR(capture_overrun, 0644, psc_i2s_stat_show,
 static int __devinit psc_i2s_of_probe(struct of_device *op,
                                      const struct of_device_id *match)
 {
-       phys_addr_t fifo;
-       struct psc_i2s *psc_i2s;
-       struct resource res;
-       int size, psc_id, irq, rc;
-       const __be32 *prop;
-       void __iomem *regs;
-
-       dev_dbg(&op->dev, "probing psc i2s device\n");
-
-       /* Get the PSC ID */
-       prop = of_get_property(op->node, "cell-index", &size);
-       if (!prop || size < sizeof *prop)
-               return -ENODEV;
-       psc_id = be32_to_cpu(*prop);
-
-       /* Fetch the registers and IRQ of the PSC */
-       irq = irq_of_parse_and_map(op->node, 0);
-       if (of_address_to_resource(op->node, 0, &res)) {
-               dev_err(&op->dev, "Missing reg property\n");
-               return -ENODEV;
-       }
-       regs = ioremap(res.start, 1 + res.end - res.start);
-       if (!regs) {
-               dev_err(&op->dev, "Could not map registers\n");
-               return -ENODEV;
-       }
+       int rc;
+       struct psc_dma *psc_dma;
+       struct mpc52xx_psc __iomem *regs;
 
-       /* Allocate and initialize the driver private data */
-       psc_i2s = kzalloc(sizeof *psc_i2s, GFP_KERNEL);
-       if (!psc_i2s) {
-               iounmap(regs);
-               return -ENOMEM;
-       }
-       spin_lock_init(&psc_i2s->lock);
-       psc_i2s->irq = irq;
-       psc_i2s->psc_regs = regs;
-       psc_i2s->fifo_regs = regs + sizeof *psc_i2s->psc_regs;
-       psc_i2s->dev = &op->dev;
-       psc_i2s->playback.psc_i2s = psc_i2s;
-       psc_i2s->capture.psc_i2s = psc_i2s;
-       snprintf(psc_i2s->name, sizeof psc_i2s->name, "PSC%u", psc_id+1);
-
-       /* Fill out the CPU DAI structure */
-       memcpy(&psc_i2s->dai, &psc_i2s_dai_template, sizeof psc_i2s->dai);
-       psc_i2s->dai.private_data = psc_i2s;
-       psc_i2s->dai.name = psc_i2s->name;
-       psc_i2s->dai.id = psc_id;
-
-       /* Find the address of the fifo data registers and setup the
-        * DMA tasks */
-       fifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32);
-       psc_i2s->capture.bcom_task =
-               bcom_psc_gen_bd_rx_init(psc_id, 10, fifo, 512);
-       psc_i2s->playback.bcom_task =
-               bcom_psc_gen_bd_tx_init(psc_id, 10, fifo);
-       if (!psc_i2s->capture.bcom_task ||
-           !psc_i2s->playback.bcom_task) {
-               dev_err(&op->dev, "Could not allocate bestcomm tasks\n");
-               iounmap(regs);
-               kfree(psc_i2s);
-               return -ENODEV;
+       rc = mpc5200_audio_dma_create(op);
+       if (rc != 0)
+               return rc;
+
+       rc = snd_soc_register_dais(psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
+       if (rc != 0) {
+               pr_err("Failed to register DAI\n");
+               return 0;
        }
 
-       /* Disable all interrupts and reset the PSC */
-       out_be16(&psc_i2s->psc_regs->isr_imr.imr, 0);
-       out_8(&psc_i2s->psc_regs->command, 3 << 4); /* reset transmitter */
-       out_8(&psc_i2s->psc_regs->command, 2 << 4); /* reset receiver */
-       out_8(&psc_i2s->psc_regs->command, 1 << 4); /* reset mode */
-       out_8(&psc_i2s->psc_regs->command, 4 << 4); /* reset error */
+       psc_dma = dev_get_drvdata(&op->dev);
+       regs = psc_dma->psc_regs;
 
        /* Configure the serial interface mode; defaulting to CODEC8 mode */
-       psc_i2s->sicr = MPC52xx_PSC_SICR_DTS1 | MPC52xx_PSC_SICR_I2S |
+       psc_dma->sicr = MPC52xx_PSC_SICR_DTS1 | MPC52xx_PSC_SICR_I2S |
                        MPC52xx_PSC_SICR_CLKPOL;
-       if (of_get_property(op->node, "fsl,cellslave", NULL))
-               psc_i2s->sicr |= MPC52xx_PSC_SICR_CELLSLAVE |
-                                MPC52xx_PSC_SICR_GENCLK;
-       out_be32(&psc_i2s->psc_regs->sicr,
-                psc_i2s->sicr | MPC52xx_PSC_SICR_SIM_CODEC_8);
+       out_be32(&psc_dma->psc_regs->sicr,
+                psc_dma->sicr | MPC52xx_PSC_SICR_SIM_CODEC_8);
 
        /* Check for the codec handle.  If it is not present then we
         * are done */
        if (!of_get_property(op->node, "codec-handle", NULL))
                return 0;
 
-       /* Set up mode register;
-        * First write: RxRdy (FIFO Alarm) generates rx FIFO irq
-        * Second write: register Normal mode for non loopback
-        */
-       out_8(&psc_i2s->psc_regs->mode, 0);
-       out_8(&psc_i2s->psc_regs->mode, 0);
-
-       /* Set the TX and RX fifo alarm thresholds */
-       out_be16(&psc_i2s->fifo_regs->rfalarm, 0x100);
-       out_8(&psc_i2s->fifo_regs->rfcntl, 0x4);
-       out_be16(&psc_i2s->fifo_regs->tfalarm, 0x100);
-       out_8(&psc_i2s->fifo_regs->tfcntl, 0x7);
-
-       /* Lookup the IRQ numbers */
-       psc_i2s->playback.irq =
-               bcom_get_task_irq(psc_i2s->playback.bcom_task);
-       psc_i2s->capture.irq =
-               bcom_get_task_irq(psc_i2s->capture.bcom_task);
-
-       /* Save what we've done so it can be found again later */
-       dev_set_drvdata(&op->dev, psc_i2s);
-
-       /* Register the SYSFS files */
-       rc = device_create_file(psc_i2s->dev, &dev_attr_status);
-       rc |= device_create_file(psc_i2s->dev, &dev_attr_capture_overrun);
-       rc |= device_create_file(psc_i2s->dev, &dev_attr_playback_underrun);
-       if (rc)
-               dev_info(psc_i2s->dev, "error creating sysfs files\n");
-
-       snd_soc_register_platform(&psc_i2s_pcm_soc_platform);
-
-       /* Tell the ASoC OF helpers about it */
-       of_snd_soc_register_platform(&psc_i2s_pcm_soc_platform, op->node,
-                                    &psc_i2s->dai);
+       /* Due to errata in the dma mode; need to line up enabling
+        * the transmitter with a transition on the frame sync
+        * line */
+
+       /* first make sure it is low */
+       while ((in_8(&regs->ipcr_acr.ipcr) & 0x80) != 0)
+               ;
+       /* then wait for the transition to high */
+       while ((in_8(&regs->ipcr_acr.ipcr) & 0x80) == 0)
+               ;
+       /* Finally, enable the PSC.
+        * Receiver must always be enabled; even when we only want
+        * transmit.  (see 15.3.2.3 of MPC5200B User's Guide) */
+
+       /* Go */
+       out_8(&psc_dma->psc_regs->command,
+                       MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
 
        return 0;
+
 }
 
 static int __devexit psc_i2s_of_remove(struct of_device *op)
 {
-       struct psc_i2s *psc_i2s = dev_get_drvdata(&op->dev);
-
-       dev_dbg(&op->dev, "psc_i2s_remove()\n");
-
-       snd_soc_unregister_platform(&psc_i2s_pcm_soc_platform);
-
-       bcom_gen_bd_rx_release(psc_i2s->capture.bcom_task);
-       bcom_gen_bd_tx_release(psc_i2s->playback.bcom_task);
-
-       iounmap(psc_i2s->psc_regs);
-       iounmap(psc_i2s->fifo_regs);
-       kfree(psc_i2s);
-       dev_set_drvdata(&op->dev, NULL);
-
-       return 0;
+       return mpc5200_audio_dma_destroy(op);
 }
 
 /* Match table for of_platform binding */
 static struct of_device_id psc_i2s_match[] __devinitdata = {
        { .compatible = "fsl,mpc5200-psc-i2s", },
+       { .compatible = "fsl,mpc5200b-psc-i2s", },
        {}
 };
 MODULE_DEVICE_TABLE(of, psc_i2s_match);
@@ -892,4 +245,7 @@ static void __exit psc_i2s_exit(void)
 }
 module_exit(psc_i2s_exit);
 
+MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
+MODULE_DESCRIPTION("Freescale MPC5200 PSC in I2S mode ASoC Driver");
+MODULE_LICENSE("GPL");
 
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.h b/sound/soc/fsl/mpc5200_psc_i2s.h
new file mode 100644 (file)
index 0000000..ce55e07
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * Freescale MPC5200 PSC in I2S mode
+ * ALSA SoC Digital Audio Interface (DAI) driver
+ *
+ */
+
+#ifndef __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__
+#define __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__
+
+extern struct snd_soc_dai psc_i2s_dai[];
+
+#endif /* __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__ */
diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c
new file mode 100644 (file)
index 0000000..8766f7a
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Phytec pcm030 driver for the PSC of the Freescale MPC52xx
+ * configured as AC97 interface
+ *
+ * Copyright 2008 Jon Smirl, Digispeaker
+ * Author: Jon Smirl <jonsmirl@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/soc-of-simple.h>
+
+#include "mpc5200_dma.h"
+#include "mpc5200_psc_ac97.h"
+#include "../codecs/wm9712.h"
+
+static struct snd_soc_device device;
+static struct snd_soc_card card;
+
+static struct snd_soc_dai_link pcm030_fabric_dai[] = {
+{
+       .name = "AC97",
+       .stream_name = "AC97 Analog",
+       .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+       .cpu_dai = &psc_ac97_dai[MPC5200_AC97_NORMAL],
+},
+{
+       .name = "AC97",
+       .stream_name = "AC97 IEC958",
+       .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+       .cpu_dai = &psc_ac97_dai[MPC5200_AC97_SPDIF],
+},
+};
+
+static __init int pcm030_fabric_init(void)
+{
+       struct platform_device *pdev;
+       int rc;
+
+       if (!machine_is_compatible("phytec,pcm030"))
+               return -ENODEV;
+
+       card.platform = &mpc5200_audio_dma_platform;
+       card.name = "pcm030";
+       card.dai_link = pcm030_fabric_dai;
+       card.num_links = ARRAY_SIZE(pcm030_fabric_dai);
+
+       device.card = &card;
+       device.codec_dev = &soc_codec_dev_wm9712;
+
+       pdev = platform_device_alloc("soc-audio", 1);
+       if (!pdev) {
+               pr_err("pcm030_fabric_init: platform_device_alloc() failed\n");
+               return -ENODEV;
+       }
+
+       platform_set_drvdata(pdev, &device);
+       device.dev = &pdev->dev;
+
+       rc = platform_device_add(pdev);
+       if (rc) {
+               pr_err("pcm030_fabric_init: platform_device_add() failed\n");
+               return -ENODEV;
+       }
+       return 0;
+}
+
+module_init(pcm030_fabric_init);
+
+
+MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
+MODULE_DESCRIPTION(DRV_NAME ": mpc5200 pcm030 fabric driver");
+MODULE_LICENSE("GPL");
+
index 675732e724d5ccfa5a824deec7365fecbaf86f96..b771238662b6407fa8a10aa5e1050dbc633a1389 100644 (file)
@@ -39,6 +39,14 @@ config SND_OMAP_SOC_OMAP2EVM
        help
          Say Y if you want to add support for SoC audio on the omap2evm board.
 
+config SND_OMAP_SOC_OMAP3EVM
+       tristate "SoC Audio support for OMAP3EVM board"
+       depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3EVM
+       select SND_OMAP_SOC_MCBSP
+       select SND_SOC_TWL4030
+       help
+         Say Y if you want to add support for SoC audio on the omap3evm board.
+
 config SND_OMAP_SOC_SDP3430
        tristate "SoC Audio support for Texas Instruments SDP3430"
        depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_3430SDP
index 0c9e4ac376601051a2136a861e68ae921ba439c0..a37f498623896426d0b50a6529834d1b9ee90888 100644 (file)
@@ -10,6 +10,7 @@ snd-soc-n810-objs := n810.o
 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-sdp3430-objs := sdp3430.o
 snd-soc-omap3pandora-objs := omap3pandora.o
 snd-soc-omap3beagle-objs := omap3beagle.o
@@ -18,6 +19,7 @@ obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
 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_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
index 91ef17992de52c68711da692679be075b7069aec..b60b1dfbc435f0036f9d18447b6e45c617e39439 100644 (file)
@@ -383,10 +383,9 @@ static int __init n810_soc_init(void)
        clk_set_parent(sys_clkout2_src, func96m_clk);
        clk_set_rate(sys_clkout2, 12000000);
 
-       if (gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0)
-               BUG();
-       if (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0)
-               BUG();
+       BUG_ON((gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0) ||
+              (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0));
+
        gpio_direction_output(N810_HEADSET_AMP_GPIO, 0);
        gpio_direction_output(N810_SPEAKER_AMP_GPIO, 0);
 
index 9126142838486926c00fbb3b6586c06f9b1c696b..a5d46a7b196a324cebce928cfaed329afaec8cf3 100644 (file)
@@ -215,8 +215,9 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
        struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
        struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
        int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id;
-       int wlen, channels;
+       int wlen, channels, wpf;
        unsigned long port;
+       unsigned int format;
 
        if (cpu_class_is_omap1()) {
                dma = omap1_dma_reqs[bus_id][substream->stream];
@@ -244,18 +245,24 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
                return 0;
        }
 
-       channels = params_channels(params);
+       format = mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+       wpf = channels = params_channels(params);
        switch (channels) {
        case 2:
-               /* Use dual-phase frames */
-               regs->rcr2      |= RPHASE;
-               regs->xcr2      |= XPHASE;
+               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:
-               /* Set 1 word per (McBSP) frame */
-               regs->rcr2      |= RFRLEN2(1 - 1);
-               regs->rcr1      |= RFRLEN1(1 - 1);
-               regs->xcr2      |= XFRLEN2(1 - 1);
-               regs->xcr1      |= XFRLEN1(1 - 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 */
@@ -277,11 +284,12 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
        }
 
        /* Set FS period and length in terms of bit clock periods */
-       switch (mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       switch (format) {
        case SND_SOC_DAIFMT_I2S:
-               regs->srgr2     |= FPER(wlen * 2 - 1);
+               regs->srgr2     |= FPER(wlen * channels - 1);
                regs->srgr1     |= FWID(wlen - 1);
                break;
+       case SND_SOC_DAIFMT_DSP_A:
        case SND_SOC_DAIFMT_DSP_B:
                regs->srgr2     |= FPER(wlen * channels - 1);
                regs->srgr1     |= FWID(0);
@@ -326,6 +334,13 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                regs->rcr2      |= RDATDLY(1);
                regs->xcr2      |= XDATDLY(1);
                break;
+       case SND_SOC_DAIFMT_DSP_A:
+               /* 1-bit data delay */
+               regs->rcr2      |= RDATDLY(1);
+               regs->xcr2      |= XDATDLY(1);
+               /* Invert FS polarity configuration */
+               temp_fmt ^= SND_SOC_DAIFMT_NB_IF;
+               break;
        case SND_SOC_DAIFMT_DSP_B:
                /* 0-bit data delay */
                regs->rcr2      |= RDATDLY(0);
@@ -492,13 +507,13 @@ static struct snd_soc_dai_ops omap_mcbsp_dai_ops = {
        .id = (link_id),                                        \
        .playback = {                                           \
                .channels_min = 1,                              \
-               .channels_max = 2,                              \
+               .channels_max = 4,                              \
                .rates = OMAP_MCBSP_RATES,                      \
                .formats = SNDRV_PCM_FMTBIT_S16_LE,             \
        },                                                      \
        .capture = {                                            \
                .channels_min = 1,                              \
-               .channels_max = 2,                              \
+               .channels_max = 4,                              \
                .rates = OMAP_MCBSP_RATES,                      \
                .formats = SNDRV_PCM_FMTBIT_S16_LE,             \
        },                                                      \
index 07cf7f46b584f37f83404d59133731eaa965df9b..6454e15f7d28cb274bf3e21abe76b9b1ee6f06ee 100644 (file)
@@ -87,8 +87,10 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
        struct omap_pcm_dma_data *dma_data = rtd->dai->cpu_dai->dma_data;
        int err = 0;
 
+       /* return if this is a bufferless transfer e.g.
+        * codec <--> BT codec or GSM modem -- lg FIXME */
        if (!dma_data)
-               return -ENODEV;
+               return 0;
 
        snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
        runtime->dma_bytes = params_buffer_bytes(params);
@@ -134,6 +136,11 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream)
        struct omap_pcm_dma_data *dma_data = prtd->dma_data;
        struct omap_dma_channel_params dma_params;
 
+       /* return if this is a bufferless transfer e.g.
+        * codec <--> BT codec or GSM modem -- lg FIXME */
+       if (!prtd->dma_data)
+               return 0;
+
        memset(&dma_params, 0, sizeof(dma_params));
        /*
         * Note: Regardless of interface data formats supported by OMAP McBSP
index 0c2322dcf02a489c82653a257dcd8fe80aa4e33b..027e1a40f8a10d774b31b9aad597ada5655dc59a 100644 (file)
@@ -86,7 +86,7 @@ static struct snd_soc_dai_link omap2evm_dai = {
        .name = "TWL4030",
        .stream_name = "TWL4030",
        .cpu_dai = &omap_mcbsp_dai[0],
-       .codec_dai = &twl4030_dai,
+       .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
        .ops = &omap2evm_ops,
 };
 
index fd24a4acd2f5d622888b5f7dd8481a17361ac4b9..b0cff9f33b7eb30be7b2ce51376e643adc237d22 100644 (file)
@@ -41,23 +41,33 @@ static int omap3beagle_hw_params(struct snd_pcm_substream *substream,
        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;
        int ret;
 
+       switch (params_channels(params)) {
+       case 2: /* Stereo I2S mode */
+               fmt =   SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBM_CFM;
+               break;
+       case 4: /* Four channel TDM mode */
+               fmt =   SND_SOC_DAIFMT_DSP_A |
+                       SND_SOC_DAIFMT_IB_NF |
+                       SND_SOC_DAIFMT_CBM_CFM;
+               break;
+       default:
+               return -EINVAL;
+       }
+
        /* 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);
+       ret = snd_soc_dai_set_fmt(codec_dai, fmt);
        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);
+       ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
        if (ret < 0) {
                printk(KERN_ERR "can't set cpu DAI configuration\n");
                return ret;
@@ -83,7 +93,7 @@ static struct snd_soc_dai_link omap3beagle_dai = {
        .name = "TWL4030",
        .stream_name = "TWL4030",
        .cpu_dai = &omap_mcbsp_dai[0],
-       .codec_dai = &twl4030_dai,
+       .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
        .ops = &omap3beagle_ops,
 };
 
diff --git a/sound/soc/omap/omap3evm.c b/sound/soc/omap/omap3evm.c
new file mode 100644 (file)
index 0000000..9114c26
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * omap3evm.c  -- ALSA SoC support for OMAP3 EVM
+ *
+ * Author: Anuj Aggarwal <anuj.aggarwal@ti.com>
+ *
+ * Based on sound/soc/omap/beagle.c by Steve Sakoman
+ *
+ * Copyright (C) 2008 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 <mach/mcbsp.h>
+
+#include "omap-mcbsp.h"
+#include "omap-pcm.h"
+#include "../codecs/twl4030.h"
+
+static int omap3evm_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 omap3evm_ops = {
+       .hw_params = omap3evm_hw_params,
+};
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link omap3evm_dai = {
+       .name           = "TWL4030",
+       .stream_name    = "TWL4030",
+       .cpu_dai        = &omap_mcbsp_dai[0],
+       .codec_dai      = &twl4030_dai[TWL4030_DAI_HIFI],
+       .ops            = &omap3evm_ops,
+};
+
+/* Audio machine driver */
+static struct snd_soc_card snd_soc_omap3evm = {
+       .name = "omap3evm",
+       .platform = &omap_soc_platform,
+       .dai_link = &omap3evm_dai,
+       .num_links = 1,
+};
+
+/* Audio subsystem */
+static struct snd_soc_device omap3evm_snd_devdata = {
+       .card = &snd_soc_omap3evm,
+       .codec_dev = &soc_codec_dev_twl4030,
+};
+
+static struct platform_device *omap3evm_snd_device;
+
+static int __init omap3evm_soc_init(void)
+{
+       int ret;
+
+       if (!machine_is_omap3evm()) {
+               pr_err("Not OMAP3 EVM!\n");
+               return -ENODEV;
+       }
+       pr_info("OMAP3 EVM SoC init\n");
+
+       omap3evm_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!omap3evm_snd_device) {
+               printk(KERN_ERR "Platform device allocation failed\n");
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(omap3evm_snd_device, &omap3evm_snd_devdata);
+       omap3evm_snd_devdata.dev = &omap3evm_snd_device->dev;
+       *(unsigned int *)omap3evm_dai.cpu_dai->private_data = 1;
+
+       ret = platform_device_add(omap3evm_snd_device);
+       if (ret)
+               goto err1;
+
+       return 0;
+
+err1:
+       printk(KERN_ERR "Unable to add platform device\n");
+       platform_device_put(omap3evm_snd_device);
+
+       return ret;
+}
+
+static void __exit omap3evm_soc_exit(void)
+{
+       platform_device_unregister(omap3evm_snd_device);
+}
+
+module_init(omap3evm_soc_init);
+module_exit(omap3evm_soc_exit);
+
+MODULE_AUTHOR("Anuj Aggarwal <anuj.aggarwal@ti.com>");
+MODULE_DESCRIPTION("ALSA SoC OMAP3 EVM");
+MODULE_LICENSE("GPLv2");
index fe282d4ef4222d559e51a8c8566bbccb813fb6fb..ad219aaf7cb80678ae80c1263f41df565803cfe0 100644 (file)
@@ -228,14 +228,14 @@ static struct snd_soc_dai_link omap3pandora_dai[] = {
                .name = "PCM1773",
                .stream_name = "HiFi Out",
                .cpu_dai = &omap_mcbsp_dai[0],
-               .codec_dai = &twl4030_dai,
+               .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
                .ops = &omap3pandora_out_ops,
                .init = omap3pandora_out_init,
        }, {
                .name = "TWL4030",
                .stream_name = "Line/Mic In",
                .cpu_dai = &omap_mcbsp_dai[1],
-               .codec_dai = &twl4030_dai,
+               .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
                .ops = &omap3pandora_in_ops,
                .init = omap3pandora_in_init,
        }
index a72dc4e159e5f813ff1369c93a788671ba5747c2..ec4f8fd8b3a2ae9a1e79a3cb91c033a2b1ae4cf6 100644 (file)
@@ -83,7 +83,7 @@ static struct snd_soc_dai_link overo_dai = {
        .name = "TWL4030",
        .stream_name = "TWL4030",
        .cpu_dai = &omap_mcbsp_dai[0],
-       .codec_dai = &twl4030_dai,
+       .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
        .ops = &overo_ops,
 };
 
index 10f1c867f11d672692aef958f64750f7f691d5c3..b719e5db4f574cbced41497987e7953591eca81e 100644 (file)
@@ -84,6 +84,49 @@ static struct snd_soc_ops sdp3430_ops = {
        .hw_params = sdp3430_hw_params,
 };
 
+static int sdp3430_hw_voice_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_A |
+                               SND_SOC_DAIFMT_IB_NF |
+                               SND_SOC_DAIFMT_CBS_CFM);
+       if (ret) {
+               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_A |
+                               SND_SOC_DAIFMT_IB_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 sdp3430_voice_ops = {
+       .hw_params = sdp3430_hw_voice_params,
+};
+
 /* Headset jack */
 static struct snd_soc_jack hs_jack;
 
@@ -192,28 +235,58 @@ static int sdp3430_twl4030_init(struct snd_soc_codec *codec)
        return ret;
 }
 
+static int sdp3430_twl4030_voice_init(struct snd_soc_codec *codec)
+{
+       unsigned short reg;
+
+       /* Enable voice interface */
+       reg = codec->read(codec, TWL4030_REG_VOICE_IF);
+       reg |= TWL4030_VIF_DIN_EN | TWL4030_VIF_DOUT_EN | TWL4030_VIF_EN;
+       codec->write(codec, TWL4030_REG_VOICE_IF, reg);
+
+       return 0;
+}
+
+
 /* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link sdp3430_dai = {
-       .name = "TWL4030",
-       .stream_name = "TWL4030",
-       .cpu_dai = &omap_mcbsp_dai[0],
-       .codec_dai = &twl4030_dai,
-       .init = sdp3430_twl4030_init,
-       .ops = &sdp3430_ops,
+static struct snd_soc_dai_link sdp3430_dai[] = {
+       {
+               .name = "TWL4030 I2S",
+               .stream_name = "TWL4030 Audio",
+               .cpu_dai = &omap_mcbsp_dai[0],
+               .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+               .init = sdp3430_twl4030_init,
+               .ops = &sdp3430_ops,
+       },
+       {
+               .name = "TWL4030 PCM",
+               .stream_name = "TWL4030 Voice",
+               .cpu_dai = &omap_mcbsp_dai[1],
+               .codec_dai = &twl4030_dai[TWL4030_DAI_VOICE],
+               .init = sdp3430_twl4030_voice_init,
+               .ops = &sdp3430_voice_ops,
+       },
 };
 
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_sdp3430 = {
        .name = "SDP3430",
        .platform = &omap_soc_platform,
-       .dai_link = &sdp3430_dai,
-       .num_links = 1,
+       .dai_link = sdp3430_dai,
+       .num_links = ARRAY_SIZE(sdp3430_dai),
+};
+
+/* twl4030 setup */
+static struct twl4030_setup_data twl4030_setup = {
+       .ramp_delay_value = 3,
+       .sysclk = 26000,
 };
 
 /* Audio subsystem */
 static struct snd_soc_device sdp3430_snd_devdata = {
        .card = &snd_soc_sdp3430,
        .codec_dev = &soc_codec_dev_twl4030,
+       .codec_data = &twl4030_setup,
 };
 
 static struct platform_device *sdp3430_snd_device;
@@ -236,7 +309,8 @@ static int __init sdp3430_soc_init(void)
 
        platform_set_drvdata(sdp3430_snd_device, &sdp3430_snd_devdata);
        sdp3430_snd_devdata.dev = &sdp3430_snd_device->dev;
-       *(unsigned int *)sdp3430_dai.cpu_dai->private_data = 1; /* McBSP2 */
+       *(unsigned int *)sdp3430_dai[0].cpu_dai->private_data = 1; /* McBSP2 */
+       *(unsigned int *)sdp3430_dai[1].cpu_dai->private_data = 2; /* McBSP3 */
 
        ret = platform_device_add(sdp3430_snd_device);
        if (ret)
index ad8a10fe629826d22b96fe7efbb52f8a885237e7..6375b4ea525dc572ca4feae6a8b69db703ecce1a 100644 (file)
@@ -89,22 +89,23 @@ config SND_PXA2XX_SOC_E800
          Toshiba e800 PDA
 
 config SND_PXA2XX_SOC_EM_X270
-       tristate "SoC Audio support for CompuLab EM-x270"
+       tristate "SoC Audio support for CompuLab EM-x270, eXeda and CM-X300"
        depends on SND_PXA2XX_SOC && MACH_EM_X270
        select SND_PXA2XX_SOC_AC97
        select SND_SOC_WM9712
        help
          Say Y if you want to add support for SoC audio on
-         CompuLab EM-x270.
+         CompuLab EM-x270, eXeda and CM-X300 machines.
 
 config SND_PXA2XX_SOC_PALM27X
-       bool "SoC Audio support for Palm T|X, T5 and LifeDrive"
-       depends on SND_PXA2XX_SOC && (MACH_PALMLD || MACH_PALMTX || MACH_PALMT5)
+       bool "SoC Audio support for Palm T|X, T5, E2 and LifeDrive"
+       depends on SND_PXA2XX_SOC && (MACH_PALMLD || MACH_PALMTX || \
+                       MACH_PALMT5 || MACH_PALMTE2)
        select SND_PXA2XX_SOC_AC97
        select SND_SOC_WM9712
        help
          Say Y if you want to add support for SoC audio on
-         Palm T|X, T5 or LifeDrive handheld computer.
+         Palm T|X, T5, E2 or LifeDrive handheld computer.
 
 config SND_SOC_ZYLONITE
        tristate "SoC Audio support for Marvell Zylonite"
@@ -134,3 +135,12 @@ config SND_PXA2XX_SOC_MIOA701
         help
           Say Y if you want to add support for SoC audio on the
           MIO A701.
+
+config SND_PXA2XX_SOC_IMOTE2
+       tristate "SoC Audio support for IMote 2"
+       depends on SND_PXA2XX_SOC && MACH_INTELMOTE2
+       select SND_PXA2XX_SOC_I2S
+       select SND_SOC_WM8940
+       help
+         Say Y if you want to add support for SoC audio on the
+        IMote 2.
index 4b90c3ccae4510209dc7f99f8b802ec299778278..6e096b48033550f4ad4305bb7ab08f7cff06efe4 100644 (file)
@@ -22,6 +22,7 @@ snd-soc-palm27x-objs := palm27x.o
 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
 
 obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o
 obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o
@@ -35,3 +36,4 @@ obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o
 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
index 949be9c2a01ba88bab7724d5d81c13c9c510c0d7..f4756e4025fd1dd0c06080d0e26a8c121dc52c2e 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * em-x270.c  --  SoC audio for EM-X270
+ * SoC audio driver for EM-X270, eXeda and CM-X300
  *
- * Copyright 2007 CompuLab, Ltd.
+ * Copyright 2007, 2009 CompuLab, Ltd.
  *
  * Author: Mike Rapoport <mike@compulab.co.il>
  *
@@ -68,7 +68,8 @@ static int __init em_x270_init(void)
 {
        int ret;
 
-       if (!machine_is_em_x270())
+       if (!(machine_is_em_x270() || machine_is_exeda()
+             || machine_is_cm_x300()))
                return -ENODEV;
 
        em_x270_snd_device = platform_device_alloc("soc-audio", -1);
@@ -95,5 +96,5 @@ module_exit(em_x270_exit);
 
 /* Module information */
 MODULE_AUTHOR("Mike Rapoport");
-MODULE_DESCRIPTION("ALSA SoC EM-X270");
+MODULE_DESCRIPTION("ALSA SoC EM-X270, eXeda and CM-X300");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/imote2.c b/sound/soc/pxa/imote2.c
new file mode 100644 (file)
index 0000000..405587a
--- /dev/null
@@ -0,0 +1,114 @@
+
+#include <linux/module.h>
+#include <sound/soc.h>
+
+#include <asm/mach-types.h>
+
+#include "../codecs/wm8940.h"
+#include "pxa2xx-i2s.h"
+#include "pxa2xx-pcm.h"
+
+static int imote2_asoc_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       unsigned int clk = 0;
+       int ret;
+
+       switch (params_rate(params)) {
+       case 8000:
+       case 16000:
+       case 48000:
+       case 96000:
+               clk = 12288000;
+               break;
+       case 11025:
+       case 22050:
+       case 44100:
+               clk = 11289600;
+               break;
+       }
+
+       /* set codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
+                                 | SND_SOC_DAIFMT_NB_NF
+                                 | SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       /* CPU should be clock master */
+       ret = snd_soc_dai_set_fmt(cpu_dai,  SND_SOC_DAIFMT_I2S
+                                 | SND_SOC_DAIFMT_NB_NF
+                                 | SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
+                                    SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       /* set the I2S system clock as input (unused) */
+       ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, clk,
+               SND_SOC_CLOCK_OUT);
+
+       return ret;
+}
+
+static struct snd_soc_ops imote2_asoc_ops = {
+       .hw_params = imote2_asoc_hw_params,
+};
+
+static struct snd_soc_dai_link imote2_dai = {
+       .name = "WM8940",
+       .stream_name = "WM8940",
+       .cpu_dai = &pxa_i2s_dai,
+       .codec_dai = &wm8940_dai,
+       .ops = &imote2_asoc_ops,
+};
+
+static struct snd_soc_card snd_soc_imote2 = {
+       .name = "Imote2",
+       .platform = &pxa2xx_soc_platform,
+       .dai_link = &imote2_dai,
+       .num_links = 1,
+};
+
+static struct snd_soc_device imote2_snd_devdata = {
+       .card = &snd_soc_imote2,
+       .codec_dev = &soc_codec_dev_wm8940,
+};
+
+static struct platform_device *imote2_snd_device;
+
+static int __init imote2_asoc_init(void)
+{
+       int ret;
+
+       if (!machine_is_intelmote2())
+               return -ENODEV;
+       imote2_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!imote2_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(imote2_snd_device, &imote2_snd_devdata);
+       imote2_snd_devdata.dev = &imote2_snd_device->dev;
+       ret = platform_device_add(imote2_snd_device);
+       if (ret)
+               platform_device_put(imote2_snd_device);
+
+       return ret;
+}
+module_init(imote2_asoc_init);
+
+static void __exit imote2_asoc_exit(void)
+{
+       platform_device_unregister(imote2_snd_device);
+}
+module_exit(imote2_asoc_exit);
+
+MODULE_AUTHOR("Jonathan Cameron");
+MODULE_DESCRIPTION("ALSA SoC Imote 2");
+MODULE_LICENSE("GPL");
index 0625c342a1c909b9f14f7d5f05fad3a8f1060886..c89a3cdf31e4aea8ad464baf720512deb0ccd319 100644 (file)
@@ -106,7 +106,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream,
                        /* 513156 Hz ~= _2_ * 8000 Hz * 32 (+0.23%) */
                        acds = PXA_SSP_CLK_AUDIO_DIV_16;
                        break;
-               case 32:
+               default: /* 32 */
                        /* 1026312 Hz ~= _2_ * 8000 Hz * 64 (+0.23%) */
                        acds = PXA_SSP_CLK_AUDIO_DIV_8;
                }
@@ -118,7 +118,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream,
                        /* 351375 Hz ~= 11025 Hz * 32 (-0.41%) */
                        acds = PXA_SSP_CLK_AUDIO_DIV_4;
                        break;
-               case 32:
+               default: /* 32 */
                        /* 702750 Hz ~= 11025 Hz * 64 (-0.41%) */
                        acds = PXA_SSP_CLK_AUDIO_DIV_2;
                }
@@ -130,7 +130,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream,
                        /* 702750 Hz ~= 22050 Hz * 32 (-0.41%) */
                        acds = PXA_SSP_CLK_AUDIO_DIV_2;
                        break;
-               case 32:
+               default: /* 32 */
                        /* 1405500 Hz ~= 22050 Hz * 64 (-0.41%) */
                        acds = PXA_SSP_CLK_AUDIO_DIV_1;
                }
@@ -142,7 +142,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream,
                        /* 1405500 Hz ~= 44100 Hz * 32 (-0.41%) */
                        acds = PXA_SSP_CLK_AUDIO_DIV_2;
                        break;
-               case 32:
+               default: /* 32 */
                        /* 2811000 Hz ~= 44100 Hz * 64 (-0.41%) */
                        acds = PXA_SSP_CLK_AUDIO_DIV_1;
                }
@@ -154,19 +154,20 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream,
                        /* 1529375 Hz ~= 48000 Hz * 32 (-0.44%) */
                        acds = PXA_SSP_CLK_AUDIO_DIV_2;
                        break;
-               case 32:
+               default: /* 32 */
                        /* 3058750 Hz ~= 48000 Hz * 64 (-0.44%) */
                        acds = PXA_SSP_CLK_AUDIO_DIV_1;
                }
                break;
        case 96000:
+       default:
                acps = 12235000;
                switch (width) {
                case 16:
                        /* 3058750 Hz ~= 96000 Hz * 32 (-0.44%) */
                        acds = PXA_SSP_CLK_AUDIO_DIV_1;
                        break;
-               case 32:
+               default: /* 32 */
                        /* 6117500 Hz ~= 96000 Hz * 64 (-0.44%) */
                        acds = PXA_SSP_CLK_AUDIO_DIV_2;
                        div4 = PXA_SSP_CLK_SCDB_1;
index 44fcc4e01e08ea17a2bfc1ebd20eae6e03b2966e..e6102fda0a7fbbe55fb654a80ebe04e668acd173 100644 (file)
@@ -205,7 +205,7 @@ static int palm27x_asoc_probe(struct platform_device *pdev)
        int ret;
 
        if (!(machine_is_palmtx() || machine_is_palmt5() ||
-               machine_is_palmld()))
+               machine_is_palmld() || machine_is_palmte2()))
                return -ENODEV;
 
        if (pdev->dev.platform_data)
index 286be31545df7599fc7b50b6b27e1a43136830c5..19c45409d94c10257548fff8219395f833412fac 100644 (file)
@@ -50,139 +50,6 @@ struct ssp_priv {
 #endif
 };
 
-#define PXA2xx_SSP1_BASE       0x41000000
-#define PXA27x_SSP2_BASE       0x41700000
-#define PXA27x_SSP3_BASE       0x41900000
-#define PXA3xx_SSP4_BASE       0x41a00000
-
-static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_mono_out = {
-       .name                   = "SSP1 PCM Mono out",
-       .dev_addr               = PXA2xx_SSP1_BASE + SSDR,
-       .drcmr                  = &DRCMR(14),
-       .dcmd                   = DCMD_INCSRCADDR | DCMD_FLOWTRG |
-                                 DCMD_BURST16 | DCMD_WIDTH2,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_mono_in = {
-       .name                   = "SSP1 PCM Mono in",
-       .dev_addr               = PXA2xx_SSP1_BASE + SSDR,
-       .drcmr                  = &DRCMR(13),
-       .dcmd                   = DCMD_INCTRGADDR | DCMD_FLOWSRC |
-                                 DCMD_BURST16 | DCMD_WIDTH2,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_stereo_out = {
-       .name                   = "SSP1 PCM Stereo out",
-       .dev_addr               = PXA2xx_SSP1_BASE + SSDR,
-       .drcmr                  = &DRCMR(14),
-       .dcmd                   = DCMD_INCSRCADDR | DCMD_FLOWTRG |
-                                 DCMD_BURST16 | DCMD_WIDTH4,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_stereo_in = {
-       .name                   = "SSP1 PCM Stereo in",
-       .dev_addr               = PXA2xx_SSP1_BASE + SSDR,
-       .drcmr                  = &DRCMR(13),
-       .dcmd                   = DCMD_INCTRGADDR | DCMD_FLOWSRC |
-                                 DCMD_BURST16 | DCMD_WIDTH4,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_mono_out = {
-       .name                   = "SSP2 PCM Mono out",
-       .dev_addr               = PXA27x_SSP2_BASE + SSDR,
-       .drcmr                  = &DRCMR(16),
-       .dcmd                   = DCMD_INCSRCADDR | DCMD_FLOWTRG |
-                                 DCMD_BURST16 | DCMD_WIDTH2,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_mono_in = {
-       .name                   = "SSP2 PCM Mono in",
-       .dev_addr               = PXA27x_SSP2_BASE + SSDR,
-       .drcmr                  = &DRCMR(15),
-       .dcmd                   = DCMD_INCTRGADDR | DCMD_FLOWSRC |
-                                 DCMD_BURST16 | DCMD_WIDTH2,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_stereo_out = {
-       .name                   = "SSP2 PCM Stereo out",
-       .dev_addr               = PXA27x_SSP2_BASE + SSDR,
-       .drcmr                  = &DRCMR(16),
-       .dcmd                   = DCMD_INCSRCADDR | DCMD_FLOWTRG |
-                                 DCMD_BURST16 | DCMD_WIDTH4,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_stereo_in = {
-       .name                   = "SSP2 PCM Stereo in",
-       .dev_addr               = PXA27x_SSP2_BASE + SSDR,
-       .drcmr                  = &DRCMR(15),
-       .dcmd                   = DCMD_INCTRGADDR | DCMD_FLOWSRC |
-                                 DCMD_BURST16 | DCMD_WIDTH4,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_mono_out = {
-       .name                   = "SSP3 PCM Mono out",
-       .dev_addr               = PXA27x_SSP3_BASE + SSDR,
-       .drcmr                  = &DRCMR(67),
-       .dcmd                   = DCMD_INCSRCADDR | DCMD_FLOWTRG |
-                                 DCMD_BURST16 | DCMD_WIDTH2,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_mono_in = {
-       .name                   = "SSP3 PCM Mono in",
-       .dev_addr               = PXA27x_SSP3_BASE + SSDR,
-       .drcmr                  = &DRCMR(66),
-       .dcmd                   = DCMD_INCTRGADDR | DCMD_FLOWSRC |
-                                 DCMD_BURST16 | DCMD_WIDTH2,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_stereo_out = {
-       .name                   = "SSP3 PCM Stereo out",
-       .dev_addr               = PXA27x_SSP3_BASE + SSDR,
-       .drcmr                  = &DRCMR(67),
-       .dcmd                   = DCMD_INCSRCADDR | DCMD_FLOWTRG |
-                                 DCMD_BURST16 | DCMD_WIDTH4,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_stereo_in = {
-       .name                   = "SSP3 PCM Stereo in",
-       .dev_addr               = PXA27x_SSP3_BASE + SSDR,
-       .drcmr                  = &DRCMR(66),
-       .dcmd                   = DCMD_INCTRGADDR | DCMD_FLOWSRC |
-                                 DCMD_BURST16 | DCMD_WIDTH4,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_mono_out = {
-       .name                   = "SSP4 PCM Mono out",
-       .dev_addr               = PXA3xx_SSP4_BASE + SSDR,
-       .drcmr                  = &DRCMR(67),
-       .dcmd                   = DCMD_INCSRCADDR | DCMD_FLOWTRG |
-                                 DCMD_BURST16 | DCMD_WIDTH2,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_mono_in = {
-       .name                   = "SSP4 PCM Mono in",
-       .dev_addr               = PXA3xx_SSP4_BASE + SSDR,
-       .drcmr                  = &DRCMR(66),
-       .dcmd                   = DCMD_INCTRGADDR | DCMD_FLOWSRC |
-                                 DCMD_BURST16 | DCMD_WIDTH2,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_stereo_out = {
-       .name                   = "SSP4 PCM Stereo out",
-       .dev_addr               = PXA3xx_SSP4_BASE + SSDR,
-       .drcmr                  = &DRCMR(67),
-       .dcmd                   = DCMD_INCSRCADDR | DCMD_FLOWTRG |
-                                 DCMD_BURST16 | DCMD_WIDTH4,
-};
-
-static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_stereo_in = {
-       .name                   = "SSP4 PCM Stereo in",
-       .dev_addr               = PXA3xx_SSP4_BASE + SSDR,
-       .drcmr                  = &DRCMR(66),
-       .dcmd                   = DCMD_INCTRGADDR | DCMD_FLOWSRC |
-                                 DCMD_BURST16 | DCMD_WIDTH4,
-};
-
 static void dump_registers(struct ssp_device *ssp)
 {
        dev_dbg(&ssp->pdev->dev, "SSCR0 0x%08x SSCR1 0x%08x SSTO 0x%08x\n",
@@ -194,25 +61,33 @@ static void dump_registers(struct ssp_device *ssp)
                 ssp_read_reg(ssp, SSACD));
 }
 
-static struct pxa2xx_pcm_dma_params *ssp_dma_params[4][4] = {
-       {
-               &pxa_ssp1_pcm_mono_out, &pxa_ssp1_pcm_mono_in,
-               &pxa_ssp1_pcm_stereo_out, &pxa_ssp1_pcm_stereo_in,
-       },
-       {
-               &pxa_ssp2_pcm_mono_out, &pxa_ssp2_pcm_mono_in,
-               &pxa_ssp2_pcm_stereo_out, &pxa_ssp2_pcm_stereo_in,
-       },
-       {
-               &pxa_ssp3_pcm_mono_out, &pxa_ssp3_pcm_mono_in,
-               &pxa_ssp3_pcm_stereo_out, &pxa_ssp3_pcm_stereo_in,
-       },
-       {
-               &pxa_ssp4_pcm_mono_out, &pxa_ssp4_pcm_mono_in,
-               &pxa_ssp4_pcm_stereo_out, &pxa_ssp4_pcm_stereo_in,
-       },
+struct pxa2xx_pcm_dma_data {
+       struct pxa2xx_pcm_dma_params params;
+       char name[20];
 };
 
+static struct pxa2xx_pcm_dma_params *
+ssp_get_dma_params(struct ssp_device *ssp, int width4, int out)
+{
+       struct pxa2xx_pcm_dma_data *dma;
+
+       dma = kzalloc(sizeof(struct pxa2xx_pcm_dma_data), GFP_KERNEL);
+       if (dma == NULL)
+               return NULL;
+
+       snprintf(dma->name, 20, "SSP%d PCM %s %s", ssp->port_id,
+                       width4 ? "32-bit" : "16-bit", out ? "out" : "in");
+
+       dma->params.name = dma->name;
+       dma->params.drcmr = &DRCMR(out ? ssp->drcmr_tx : ssp->drcmr_rx);
+       dma->params.dcmd = (out ? (DCMD_INCSRCADDR | DCMD_FLOWTRG) :
+                                 (DCMD_INCTRGADDR | DCMD_FLOWSRC)) |
+                       (width4 ? DCMD_WIDTH4 : DCMD_WIDTH2) | DCMD_BURST16;
+       dma->params.dev_addr = ssp->phys_base + SSDR;
+
+       return &dma->params;
+}
+
 static int pxa_ssp_startup(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
@@ -227,6 +102,11 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream,
                clk_enable(priv->dev.ssp->clk);
                ssp_disable(&priv->dev);
        }
+
+       if (cpu_dai->dma_data) {
+               kfree(cpu_dai->dma_data);
+               cpu_dai->dma_data = NULL;
+       }
        return ret;
 }
 
@@ -241,6 +121,11 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream,
                ssp_disable(&priv->dev);
                clk_disable(priv->dev.ssp->clk);
        }
+
+       if (cpu_dai->dma_data) {
+               kfree(cpu_dai->dma_data);
+               cpu_dai->dma_data = NULL;
+       }
 }
 
 #ifdef CONFIG_PM
@@ -323,7 +208,7 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
                ~(SSCR0_ECS |  SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
 
        dev_dbg(&ssp->pdev->dev,
-               "pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %d\n",
+               "pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %u\n",
                cpu_dai->id, clk_id, freq);
 
        switch (clk_id) {
@@ -472,7 +357,7 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai,
                        ssacd |= (0x6 << 4);
 
                        dev_dbg(&ssp->pdev->dev,
-                               "Using SSACDD %x to supply %dHz\n",
+                               "Using SSACDD %x to supply %uHz\n",
                                val, freq_out);
                        break;
                }
@@ -589,7 +474,10 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                case SND_SOC_DAIFMT_NB_IF:
                        break;
                case SND_SOC_DAIFMT_IB_IF:
-                       sspsp |= SSPSP_SCMODE(3);
+                       sspsp |= SSPSP_SCMODE(2);
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       sspsp |= SSPSP_SCMODE(2) | SSPSP_SFRMP;
                        break;
                default:
                        return -EINVAL;
@@ -606,7 +494,13 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                case SND_SOC_DAIFMT_NB_NF:
                        sspsp |= SSPSP_SFRMP;
                        break;
+               case SND_SOC_DAIFMT_NB_IF:
+                       break;
                case SND_SOC_DAIFMT_IB_IF:
+                       sspsp |= SSPSP_SCMODE(2);
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       sspsp |= SSPSP_SCMODE(2) | SSPSP_SFRMP;
                        break;
                default:
                        return -EINVAL;
@@ -644,25 +538,23 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        struct ssp_priv *priv = cpu_dai->private_data;
        struct ssp_device *ssp = priv->dev.ssp;
-       int dma = 0, chn = params_channels(params);
+       int chn = params_channels(params);
        u32 sscr0;
        u32 sspsp;
        int width = snd_pcm_format_physical_width(params_format(params));
        int ttsa = ssp_read_reg(ssp, SSTSA) & 0xf;
 
-       /* select correct DMA params */
-       if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
-               dma = 1; /* capture DMA offset is 1,3 */
+       /* generate correct DMA params */
+       if (cpu_dai->dma_data)
+               kfree(cpu_dai->dma_data);
+
        /* Network mode with one active slot (ttsa == 1) can be used
         * to force 16-bit frame width on the wire (for S16_LE), even
         * with two channels. Use 16-bit DMA transfers for this case.
         */
-       if (((chn == 2) && (ttsa != 1)) || (width == 32))
-               dma += 2; /* 32-bit DMA offset is 2, 16-bit is 0 */
-
-       cpu_dai->dma_data = ssp_dma_params[cpu_dai->id][dma];
-
-       dev_dbg(&ssp->pdev->dev, "pxa_ssp_hw_params: dma %d\n", dma);
+       cpu_dai->dma_data = ssp_get_dma_params(ssp,
+                       ((chn == 2) && (ttsa != 1)) || (width == 32),
+                       substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
 
        /* we can only change the settings if the port is not in use */
        if (ssp_read_reg(ssp, SSCR0) & SSCR0_SSE)
index 2f4b6e489b7849a68eae4a76e4bb011c92bef129..4743e262895d9f1068260762ca6c4f64df5dd17d 100644 (file)
@@ -106,10 +106,8 @@ static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream,
        if (IS_ERR(clk_i2s))
                return PTR_ERR(clk_i2s);
 
-       if (!cpu_dai->active) {
-               SACR0 |= SACR0_RST;
+       if (!cpu_dai->active)
                SACR0 = 0;
-       }
 
        return 0;
 }
@@ -178,9 +176,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
 
        /* is port used by another stream */
        if (!(SACR0 & SACR0_ENB)) {
-
                SACR0 = 0;
-               SACR1 = 0;
                if (pxa_i2s.master)
                        SACR0 |= SACR0_BCKD;
 
@@ -226,6 +222,10 @@ static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       SACR1 &= ~SACR1_DRPL;
+               else
+                       SACR1 &= ~SACR1_DREC;
                SACR0 |= SACR0_ENB;
                break;
        case SNDRV_PCM_TRIGGER_RESUME:
@@ -252,21 +252,16 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream,
                SAIMR &= ~SAIMR_RFS;
        }
 
-       if (SACR1 & (SACR1_DREC | SACR1_DRPL)) {
+       if ((SACR1 & (SACR1_DREC | SACR1_DRPL)) == (SACR1_DREC | SACR1_DRPL)) {
                SACR0 &= ~SACR0_ENB;
                pxa_i2s_wait();
                clk_disable(clk_i2s);
        }
-
-       clk_put(clk_i2s);
 }
 
 #ifdef CONFIG_PM
 static int pxa2xx_i2s_suspend(struct snd_soc_dai *dai)
 {
-       if (!dai->active)
-               return 0;
-
        /* store registers */
        pxa_i2s.sacr0 = SACR0;
        pxa_i2s.sacr1 = SACR1;
@@ -281,16 +276,14 @@ static int pxa2xx_i2s_suspend(struct snd_soc_dai *dai)
 
 static int pxa2xx_i2s_resume(struct snd_soc_dai *dai)
 {
-       if (!dai->active)
-               return 0;
-
        pxa_i2s_wait();
 
-       SACR0 = pxa_i2s.sacr0 &= ~SACR0_ENB;
+       SACR0 = pxa_i2s.sacr0 & ~SACR0_ENB;
        SACR1 = pxa_i2s.sacr1;
        SAIMR = pxa_i2s.saimr;
        SADIV = pxa_i2s.sadiv;
-       SACR0 |= SACR0_ENB;
+
+       SACR0 = pxa_i2s.sacr0;
 
        return 0;
 }
@@ -329,6 +322,7 @@ struct snd_soc_dai pxa_i2s_dai = {
                .rates = PXA2XX_I2S_RATES,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
        .ops = &pxa_i2s_dai_ops,
+       .symmetric_rates = 1,
 };
 
 EXPORT_SYMBOL_GPL(pxa_i2s_dai);
@@ -346,6 +340,19 @@ static int pxa2xx_i2s_probe(struct platform_device *dev)
        if (ret != 0)
                clk_put(clk_i2s);
 
+       /*
+        * PXA Developer's Manual:
+        * If SACR0[ENB] is toggled in the middle of a normal operation,
+        * the SACR0[RST] bit must also be set and cleared to reset all
+        * I2S controller registers.
+        */
+       SACR0 = SACR0_RST;
+       SACR0 = 0;
+       /* Make sure RPL and REC are disabled */
+       SACR1 = SACR1_DRPL | SACR1_DREC;
+       /* Along with FIFO servicing */
+       SAIMR &= ~(SAIMR_RFS | SAIMR_TFS);
+
        return ret;
 }
 
index 289fadf60b1038a24585f3c4bf7e65f8046a8b46..906709e6dd5f36182d2ec3ef7db497747d05c627 100644 (file)
@@ -345,9 +345,11 @@ static void lm4857_write_regs(void)
 static int lm4857_get_reg(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       int reg = kcontrol->private_value & 0xFF;
-       int shift = (kcontrol->private_value >> 8) & 0x0F;
-       int mask = (kcontrol->private_value >> 16) & 0xFF;
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       int reg = mc->reg;
+       int shift = mc->shift;
+       int mask = mc->max;
 
        pr_debug("Entered %s\n", __func__);
 
@@ -358,9 +360,11 @@ static int lm4857_get_reg(struct snd_kcontrol *kcontrol,
 static int lm4857_set_reg(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       int reg = kcontrol->private_value & 0xFF;
-       int shift = (kcontrol->private_value >> 8) & 0x0F;
-       int mask = (kcontrol->private_value >> 16) & 0xFF;
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       int reg = mc->reg;
+       int shift = mc->shift;
+       int mask = mc->max;
 
        if (((lm4857_regs[reg] >> shift) & mask) ==
                ucontrol->value.integer.value[0])
index ab680aac3fcb0edb064e6bad6ee2f03c7b03f707..1a283170ca92d80e00394f3cbc7cb6d01ebafc98 100644 (file)
 
 #include "s3c-i2s-v2.h"
 
+#undef S3C_IIS_V2_SUPPORTED
+
+#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
+#define S3C_IIS_V2_SUPPORTED
+#endif
+
+#ifdef CONFIG_PLAT_S3C64XX
+#define S3C_IIS_V2_SUPPORTED
+#endif
+
+#ifndef S3C_IIS_V2_SUPPORTED
+#error Unsupported CPU model
+#endif
+
 #define S3C2412_I2S_DEBUG_CON 0
 
 static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
@@ -75,7 +89,7 @@ static inline void dbg_showcon(const char *fn, u32 con)
 
 
 /* Turn on or off the transmission path. */
-void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on)
+static void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on)
 {
        void __iomem *regs = i2s->regs;
        u32 fic, con, mod;
@@ -105,7 +119,9 @@ void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on)
                        break;
 
                default:
-                       dev_err(i2s->dev, "TXEN: Invalid MODE in IISMOD\n");
+                       dev_err(i2s->dev, "TXEN: Invalid MODE %x in IISMOD\n",
+                               mod & S3C2412_IISMOD_MODE_MASK);
+                       break;
                }
 
                writel(con, regs + S3C2412_IISCON);
@@ -132,7 +148,9 @@ void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on)
                        break;
 
                default:
-                       dev_err(i2s->dev, "TXDIS: Invalid MODE in IISMOD\n");
+                       dev_err(i2s->dev, "TXDIS: Invalid MODE %x in IISMOD\n",
+                               mod & S3C2412_IISMOD_MODE_MASK);
+                       break;
                }
 
                writel(mod, regs + S3C2412_IISMOD);
@@ -143,9 +161,8 @@ void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on)
        dbg_showcon(__func__, con);
        pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
 }
-EXPORT_SYMBOL_GPL(s3c2412_snd_txctrl);
 
-void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on)
+static void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on)
 {
        void __iomem *regs = i2s->regs;
        u32 fic, con, mod;
@@ -175,7 +192,8 @@ void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on)
                        break;
 
                default:
-                       dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n");
+                       dev_err(i2s->dev, "RXEN: Invalid MODE %x in IISMOD\n",
+                               mod & S3C2412_IISMOD_MODE_MASK);
                }
 
                writel(mod, regs + S3C2412_IISMOD);
@@ -199,7 +217,8 @@ void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on)
                        break;
 
                default:
-                       dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n");
+                       dev_err(i2s->dev, "RXDIS: Invalid MODE %x in IISMOD\n",
+                               mod & S3C2412_IISMOD_MODE_MASK);
                }
 
                writel(con, regs + S3C2412_IISCON);
@@ -209,7 +228,6 @@ void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on)
        fic = readl(regs + S3C2412_IISFIC);
        pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
 }
-EXPORT_SYMBOL_GPL(s3c2412_snd_rxctrl);
 
 /*
  * Wait for the LR signal to allow synchronisation to the L/R clock
@@ -266,7 +284,7 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
  */
 #define IISMOD_MASTER_MASK (1 << 11)
 #define IISMOD_SLAVE (1 << 11)
-#define IISMOD_MASTER (0x0)
+#define IISMOD_MASTER (0 << 11)
 #endif
 
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -281,7 +299,7 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
                iismod |= IISMOD_MASTER;
                break;
        default:
-               pr_debug("unknwon master/slave format\n");
+               pr_err("unknwon master/slave format\n");
                return -EINVAL;
        }
 
@@ -298,7 +316,7 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
                iismod |= S3C2412_IISMOD_SDF_IIS;
                break;
        default:
-               pr_debug("Unknown data format\n");
+               pr_err("Unknown data format\n");
                return -EINVAL;
        }
 
@@ -327,6 +345,7 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
        iismod = readl(i2s->regs + S3C2412_IISMOD);
        pr_debug("%s: r: IISMOD: %x\n", __func__, iismod);
 
+#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S8:
                iismod |= S3C2412_IISMOD_8BIT;
@@ -335,6 +354,25 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
                iismod &= ~S3C2412_IISMOD_8BIT;
                break;
        }
+#endif
+
+#ifdef CONFIG_PLAT_S3C64XX
+       iismod &= ~0x606;
+       /* Sample size */
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S8:
+               /* 8 bit sample, 16fs BCLK */
+               iismod |= 0x2004;
+               break;
+       case SNDRV_PCM_FORMAT_S16_LE:
+               /* 16 bit sample, 32fs BCLK */
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               /* 24 bit sample, 48fs BCLK */
+               iismod |= 0x4002;
+               break;
+       }
+#endif
 
        writel(iismod, i2s->regs + S3C2412_IISMOD);
        pr_debug("%s: w: IISMOD: %x\n", __func__, iismod);
@@ -489,6 +527,8 @@ int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
        unsigned int best_rate = 0;
        unsigned int best_deviation = INT_MAX;
 
+       pr_debug("Input clock rate %ldHz\n", clkrate);
+
        if (fstab == NULL)
                fstab = iis_fs_tab;
 
@@ -507,7 +547,7 @@ int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
                actual = clkrate / (fsdiv * div);
                deviation = actual - rate;
 
-               printk(KERN_DEBUG "%dfs: div %d => result %d, deviation %d\n",
+               printk(KERN_DEBUG "%ufs: div %u => result %u, deviation %d\n",
                       fsdiv, div, actual, deviation);
 
                deviation = abs(deviation);
@@ -523,7 +563,7 @@ int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
                        break;
        }
 
-       printk(KERN_DEBUG "best: fs=%d, div=%d, rate=%d\n",
+       printk(KERN_DEBUG "best: fs=%u, div=%u, rate=%u\n",
               best_fs, best_div, best_rate);
 
        info->fs_div = best_fs;
@@ -539,12 +579,31 @@ int s3c_i2sv2_probe(struct platform_device *pdev,
                    unsigned long base)
 {
        struct device *dev = &pdev->dev;
+       unsigned int iismod;
 
        i2s->dev = dev;
 
        /* record our i2s structure for later use in the callbacks */
        dai->private_data = i2s;
 
+       if (!base) {
+               struct resource *res = platform_get_resource(pdev,
+                                                            IORESOURCE_MEM,
+                                                            0);
+               if (!res) {
+                       dev_err(dev, "Unable to get register resource\n");
+                       return -ENXIO;
+               }
+
+               if (!request_mem_region(res->start, resource_size(res),
+                                       "s3c64xx-i2s-v4")) {
+                       dev_err(dev, "Unable to request register region\n");
+                       return -EBUSY;
+               }
+
+               base = res->start;
+       }
+
        i2s->regs = ioremap(base, 0x100);
        if (i2s->regs == NULL) {
                dev_err(dev, "cannot ioremap registers\n");
@@ -560,12 +619,16 @@ int s3c_i2sv2_probe(struct platform_device *pdev,
 
        clk_enable(i2s->iis_pclk);
 
+       /* Mark ourselves as in TXRX mode so we can run through our cleanup
+        * process without warnings. */
+       iismod = readl(i2s->regs + S3C2412_IISMOD);
+       iismod |= S3C2412_IISMOD_MODE_TXRX;
+       writel(iismod, i2s->regs + S3C2412_IISMOD);
        s3c2412_snd_txctrl(i2s, 0);
        s3c2412_snd_rxctrl(i2s, 0);
 
        return 0;
 }
-
 EXPORT_SYMBOL_GPL(s3c_i2sv2_probe);
 
 #ifdef CONFIG_PM
index b7e0b3f0bfc8f5c6dda3cb418742cf035f1a319c..a587ec40b449689df4d27a214d16c5d0ef28f7c4 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/delay.h>
+#include <linux/gpio.h>
 #include <linux/clk.h>
 #include <linux/kernel.h>
 #include <linux/io.h>
@@ -120,7 +121,7 @@ static int s3c2412_i2s_probe(struct platform_device *pdev,
 
        s3c2412_i2s.iis_cclk = clk_get(&pdev->dev, "i2sclk");
        if (s3c2412_i2s.iis_cclk == NULL) {
-               pr_debug("failed to get i2sclk clock\n");
+               pr_err("failed to get i2sclk clock\n");
                iounmap(s3c2412_i2s.regs);
                return -ENODEV;
        }
index 3698f707c44d0e53fdbc916d717211bf97a279ca..3f03d5ddfacda0b3392c0fe3b0fd487332d33052 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/io.h>
 #include <linux/wait.h>
 #include <linux/delay.h>
+#include <linux/gpio.h>
 #include <linux/clk.h>
 
 #include <sound/core.h>
index cc066964dad6fe34eb7709115474c522ac0d80ba..556e35f0ab7341416fbf6c30c38d713f3a709b92 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/clk.h>
 #include <linux/jiffies.h>
 #include <linux/io.h>
+#include <linux/gpio.h>
+
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
index 169ddad31575e9601e3e703074a75c1fca398533..eecfa5eba06b0bf0b450d518368df1fe90cc52f6 100644 (file)
@@ -218,24 +218,17 @@ static int s3c24xx_pcm_prepare(struct snd_pcm_substream *substream)
         * sync to pclk, half-word transfers to the IIS-FIFO. */
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                s3c2410_dma_devconfig(prtd->params->channel,
-                               S3C2410_DMASRC_MEM, S3C2410_DISRCC_INC |
-                               S3C2410_DISRCC_APB, prtd->params->dma_addr);
-
-               s3c2410_dma_config(prtd->params->channel,
-                               prtd->params->dma_size,
-                               S3C2410_DCON_SYNC_PCLK |
-                               S3C2410_DCON_HANDSHAKE);
+                                     S3C2410_DMASRC_MEM,
+                                     prtd->params->dma_addr);
        } else {
-               s3c2410_dma_config(prtd->params->channel,
-                               prtd->params->dma_size,
-                               S3C2410_DCON_HANDSHAKE |
-                               S3C2410_DCON_SYNC_PCLK);
-
                s3c2410_dma_devconfig(prtd->params->channel,
-                                       S3C2410_DMASRC_HW, 0x3,
-                                       prtd->params->dma_addr);
+                                     S3C2410_DMASRC_HW,
+                                     prtd->params->dma_addr);
        }
 
+       s3c2410_dma_config(prtd->params->channel,
+                          prtd->params->dma_size);
+
        /* flush the DMA channel */
        s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH);
        prtd->dma_loaded = 0;
index 33c5de7e255f3769d00b6de48425085abc48dc56..3c06c401d0fb86ce6a4b98cb55264af36c807b4c 100644 (file)
@@ -108,48 +108,19 @@ static int s3c64xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
        return 0;
 }
 
-
-unsigned long s3c64xx_i2s_get_clockrate(struct snd_soc_dai *dai)
+struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai)
 {
        struct s3c_i2sv2_info *i2s = to_info(dai);
 
-       return clk_get_rate(i2s->iis_cclk);
+       return i2s->iis_cclk;
 }
-EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clockrate);
+EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clock);
 
 static int s3c64xx_i2s_probe(struct platform_device *pdev,
                             struct snd_soc_dai *dai)
 {
-       struct device *dev = &pdev->dev;
-       struct s3c_i2sv2_info *i2s;
-       int ret;
-
-       dev_dbg(dev, "%s: probing dai %d\n", __func__, pdev->id);
-
-       if (pdev->id < 0 || pdev->id > ARRAY_SIZE(s3c64xx_i2s)) {
-               dev_err(dev, "id %d out of range\n", pdev->id);
-               return -EINVAL;
-       }
-
-       i2s = &s3c64xx_i2s[pdev->id];
-
-       ret = s3c_i2sv2_probe(pdev, dai, i2s,
-                             pdev->id ? S3C64XX_PA_IIS1 : S3C64XX_PA_IIS0);
-       if (ret)
-               return ret;
-
-       i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id];
-       i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id];
-
-       i2s->iis_cclk = clk_get(dev, "audio-bus");
-       if (IS_ERR(i2s->iis_cclk)) {
-               dev_err(dev, "failed to get audio-bus");
-               iounmap(i2s->regs);
-               return -ENODEV;
-       }
-
        /* configure GPIO for i2s port */
-       switch (pdev->id) {
+       switch (dai->id) {
        case 0:
                s3c_gpio_cfgpin(S3C64XX_GPD(0), S3C64XX_GPD0_I2S0_CLK);
                s3c_gpio_cfgpin(S3C64XX_GPD(1), S3C64XX_GPD1_I2S0_CDCLK);
@@ -175,41 +146,122 @@ static int s3c64xx_i2s_probe(struct platform_device *pdev,
        SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
 
 #define S3C64XX_I2S_FMTS \
-       (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE)
+       (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
+        SNDRV_PCM_FMTBIT_S24_LE)
 
 static struct snd_soc_dai_ops s3c64xx_i2s_dai_ops = {
        .set_sysclk     = s3c64xx_i2s_set_sysclk,       
 };
 
-struct snd_soc_dai s3c64xx_i2s_dai = {
-       .name           = "s3c64xx-i2s",
-       .id             = 0,
-       .probe          = s3c64xx_i2s_probe,
-       .playback = {
-               .channels_min   = 2,
-               .channels_max   = 2,
-               .rates          = S3C64XX_I2S_RATES,
-               .formats        = S3C64XX_I2S_FMTS,
+struct snd_soc_dai s3c64xx_i2s_dai[] = {
+       {
+               .name           = "s3c64xx-i2s",
+               .id             = 0,
+               .probe          = s3c64xx_i2s_probe,
+               .playback = {
+                       .channels_min   = 2,
+                       .channels_max   = 2,
+                       .rates          = S3C64XX_I2S_RATES,
+                       .formats        = S3C64XX_I2S_FMTS,
+               },
+               .capture = {
+                        .channels_min  = 2,
+                        .channels_max  = 2,
+                        .rates         = S3C64XX_I2S_RATES,
+                        .formats       = S3C64XX_I2S_FMTS,
+                },
+               .ops = &s3c64xx_i2s_dai_ops,
+               .symmetric_rates = 1,
        },
-       .capture = {
-               .channels_min   = 2,
-               .channels_max   = 2,
-               .rates          = S3C64XX_I2S_RATES,
-               .formats        = S3C64XX_I2S_FMTS,
+       {
+               .name           = "s3c64xx-i2s",
+               .id             = 1,
+               .probe          = s3c64xx_i2s_probe,
+               .playback = {
+                       .channels_min   = 2,
+                       .channels_max   = 2,
+                       .rates          = S3C64XX_I2S_RATES,
+                       .formats        = S3C64XX_I2S_FMTS,
+               },
+               .capture = {
+                        .channels_min  = 2,
+                        .channels_max  = 2,
+                        .rates         = S3C64XX_I2S_RATES,
+                        .formats       = S3C64XX_I2S_FMTS,
+                },
+               .ops = &s3c64xx_i2s_dai_ops,
+               .symmetric_rates = 1,
        },
-       .ops = &s3c64xx_i2s_dai_ops,
 };
 EXPORT_SYMBOL_GPL(s3c64xx_i2s_dai);
 
+static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev)
+{
+       struct s3c_i2sv2_info *i2s;
+       struct snd_soc_dai *dai;
+       int ret;
+
+       if (pdev->id >= ARRAY_SIZE(s3c64xx_i2s)) {
+               dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
+               return -EINVAL;
+       }
+
+       i2s = &s3c64xx_i2s[pdev->id];
+       dai = &s3c64xx_i2s_dai[pdev->id];
+       dai->dev = &pdev->dev;
+
+       i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id];
+       i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id];
+
+       i2s->iis_cclk = clk_get(&pdev->dev, "audio-bus");
+       if (IS_ERR(i2s->iis_cclk)) {
+               dev_err(&pdev->dev, "failed to get audio-bus\n");
+               ret = PTR_ERR(i2s->iis_cclk);
+               goto err;
+       }
+
+       ret = s3c_i2sv2_probe(pdev, dai, i2s, 0);
+       if (ret)
+               goto err_clk;
+
+       ret = s3c_i2sv2_register_dai(dai);
+       if (ret != 0)
+               goto err_i2sv2;
+
+       return 0;
+
+err_i2sv2:
+       /* Not implemented for I2Sv2 core yet */
+err_clk:
+       clk_put(i2s->iis_cclk);
+err:
+       return ret;
+}
+
+static __devexit int s3c64xx_iis_dev_remove(struct platform_device *pdev)
+{
+       dev_err(&pdev->dev, "Device removal not yet supported\n");
+       return 0;
+}
+
+static struct platform_driver s3c64xx_iis_driver = {
+       .probe  = s3c64xx_iis_dev_probe,
+       .remove = s3c64xx_iis_dev_remove,
+       .driver = {
+               .name = "s3c64xx-iis",
+               .owner = THIS_MODULE,
+       },
+};
+
 static int __init s3c64xx_i2s_init(void)
 {
-       return  s3c_i2sv2_register_dai(&s3c64xx_i2s_dai);
+       return platform_driver_register(&s3c64xx_iis_driver);
 }
 module_init(s3c64xx_i2s_init);
 
 static void __exit s3c64xx_i2s_exit(void)
 {
-       snd_soc_unregister_dai(&s3c64xx_i2s_dai);
+       platform_driver_unregister(&s3c64xx_iis_driver);
 }
 module_exit(s3c64xx_i2s_exit);
 
@@ -217,6 +269,3 @@ module_exit(s3c64xx_i2s_exit);
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 MODULE_DESCRIPTION("S3C64XX I2S SoC Interface");
 MODULE_LICENSE("GPL");
-
-
-
index b7ffe3c38b664794b0f7f97906950d081c46cc3d..02148cee26139fe1ca4df20df734d9314ca43486 100644 (file)
@@ -15,6 +15,8 @@
 #ifndef __SND_SOC_S3C24XX_S3C64XX_I2S_H
 #define __SND_SOC_S3C24XX_S3C64XX_I2S_H __FILE__
 
+struct clk;
+
 #include "s3c-i2s-v2.h"
 
 #define S3C64XX_DIV_BCLK       S3C_I2SV2_DIV_BCLK
@@ -24,8 +26,8 @@
 #define S3C64XX_CLKSRC_PCLK    (0)
 #define S3C64XX_CLKSRC_MUX     (1)
 
-extern struct snd_soc_dai s3c64xx_i2s_dai;
+extern struct snd_soc_dai s3c64xx_i2s_dai[];
 
-extern unsigned long s3c64xx_i2s_get_clockrate(struct snd_soc_dai *cpu_dai);
+extern struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai);
 
 #endif /* __SND_SOC_S3C24XX_S3C64XX_I2S_H */
diff --git a/sound/soc/s6000/Kconfig b/sound/soc/s6000/Kconfig
new file mode 100644 (file)
index 0000000..c74eb3d
--- /dev/null
@@ -0,0 +1,19 @@
+config SND_S6000_SOC
+       tristate "SoC Audio for the Stretch s6000 family"
+       depends on XTENSA_VARIANT_S6000
+       help
+         Say Y or M if you want to add support for codecs attached to
+         s6000 family chips. You will also need to select the platform
+         to support below.
+
+config SND_S6000_SOC_I2S
+       tristate
+
+config SND_S6000_SOC_S6IPCAM
+       tristate "SoC Audio support for Stretch 6105 IP Camera"
+       depends on SND_S6000_SOC && XTENSA_PLATFORM_S6105
+       select SND_S6000_SOC_I2S
+       select SND_SOC_TLV320AIC3X
+       help
+         Say Y if you want to add support for SoC audio on the
+         Stretch s6105 IP Camera Reference Design.
diff --git a/sound/soc/s6000/Makefile b/sound/soc/s6000/Makefile
new file mode 100644 (file)
index 0000000..7a61361
--- /dev/null
@@ -0,0 +1,11 @@
+# s6000 Platform Support
+snd-soc-s6000-objs := s6000-pcm.o
+snd-soc-s6000-i2s-objs := s6000-i2s.o
+
+obj-$(CONFIG_SND_S6000_SOC) += snd-soc-s6000.o
+obj-$(CONFIG_SND_S6000_SOC_I2S) += snd-soc-s6000-i2s.o
+
+# s6105 Machine Support
+snd-soc-s6ipcam-objs := s6105-ipcam.o
+
+obj-$(CONFIG_SND_S6000_SOC_S6IPCAM) += snd-soc-s6ipcam.o
diff --git a/sound/soc/s6000/s6000-i2s.c b/sound/soc/s6000/s6000-i2s.c
new file mode 100644 (file)
index 0000000..c5cda18
--- /dev/null
@@ -0,0 +1,629 @@
+/*
+ * ALSA SoC I2S Audio Layer for the Stretch S6000 family
+ *
+ * Author:      Daniel Gloeckner, <dg@emlix.com>
+ * Copyright:   (C) 2009 emlix GmbH <info@emlix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/interrupt.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 "s6000-i2s.h"
+#include "s6000-pcm.h"
+
+struct s6000_i2s_dev {
+       dma_addr_t sifbase;
+       u8 __iomem *scbbase;
+       unsigned int wide;
+       unsigned int channel_in;
+       unsigned int channel_out;
+       unsigned int lines_in;
+       unsigned int lines_out;
+       struct s6000_pcm_dma_params dma_params;
+};
+
+#define S6_I2S_INTERRUPT_STATUS        0x00
+#define   S6_I2S_INT_OVERRUN   1
+#define   S6_I2S_INT_UNDERRUN  2
+#define   S6_I2S_INT_ALIGNMENT 4
+#define S6_I2S_INTERRUPT_ENABLE        0x04
+#define S6_I2S_INTERRUPT_RAW   0x08
+#define S6_I2S_INTERRUPT_CLEAR 0x0C
+#define S6_I2S_INTERRUPT_SET   0x10
+#define S6_I2S_MODE            0x20
+#define   S6_I2S_DUAL          0
+#define   S6_I2S_WIDE          1
+#define S6_I2S_TX_DEFAULT      0x24
+#define S6_I2S_DATA_CFG(c)     (0x40 + 0x10 * (c))
+#define   S6_I2S_IN            0
+#define   S6_I2S_OUT           1
+#define   S6_I2S_UNUSED                2
+#define S6_I2S_INTERFACE_CFG(c)        (0x44 + 0x10 * (c))
+#define   S6_I2S_DIV_MASK      0x001fff
+#define   S6_I2S_16BIT         0x000000
+#define   S6_I2S_20BIT         0x002000
+#define   S6_I2S_24BIT         0x004000
+#define   S6_I2S_32BIT         0x006000
+#define   S6_I2S_BITS_MASK     0x006000
+#define   S6_I2S_MEM_16BIT     0x000000
+#define   S6_I2S_MEM_32BIT     0x008000
+#define   S6_I2S_MEM_MASK      0x008000
+#define   S6_I2S_CHANNELS_SHIFT        16
+#define   S6_I2S_CHANNELS_MASK 0x030000
+#define   S6_I2S_SCK_IN                0x000000
+#define   S6_I2S_SCK_OUT       0x040000
+#define   S6_I2S_SCK_DIR       0x040000
+#define   S6_I2S_WS_IN         0x000000
+#define   S6_I2S_WS_OUT                0x080000
+#define   S6_I2S_WS_DIR                0x080000
+#define   S6_I2S_LEFT_FIRST    0x000000
+#define   S6_I2S_RIGHT_FIRST   0x100000
+#define   S6_I2S_FIRST         0x100000
+#define   S6_I2S_CUR_SCK       0x200000
+#define   S6_I2S_CUR_WS                0x400000
+#define S6_I2S_ENABLE(c)       (0x48 + 0x10 * (c))
+#define   S6_I2S_DISABLE_IF    0x02
+#define   S6_I2S_ENABLE_IF     0x03
+#define   S6_I2S_IS_BUSY       0x04
+#define   S6_I2S_DMA_ACTIVE    0x08
+#define   S6_I2S_IS_ENABLED    0x10
+
+#define S6_I2S_NUM_LINES       4
+
+#define S6_I2S_SIF_PORT0       0x0000000
+#define S6_I2S_SIF_PORT1       0x0000080 /* docs say 0x0000010 */
+
+static inline void s6_i2s_write_reg(struct s6000_i2s_dev *dev, int reg, u32 val)
+{
+       writel(val, dev->scbbase + reg);
+}
+
+static inline u32 s6_i2s_read_reg(struct s6000_i2s_dev *dev, int reg)
+{
+       return readl(dev->scbbase + reg);
+}
+
+static inline void s6_i2s_mod_reg(struct s6000_i2s_dev *dev, int reg,
+                                 u32 mask, u32 val)
+{
+       val ^= s6_i2s_read_reg(dev, reg) & ~mask;
+       s6_i2s_write_reg(dev, reg, val);
+}
+
+static void s6000_i2s_start_channel(struct s6000_i2s_dev *dev, int channel)
+{
+       int i, j, cur, prev;
+
+       /*
+        * Wait for WCLK to toggle 5 times before enabling the channel
+        * s6000 Family Datasheet 3.6.4:
+        *   "At least two cycles of WS must occur between commands
+        *    to disable or enable the interface"
+        */
+       j = 0;
+       prev = ~S6_I2S_CUR_WS;
+       for (i = 1000000; --i && j < 6; ) {
+               cur = s6_i2s_read_reg(dev, S6_I2S_INTERFACE_CFG(channel))
+                      & S6_I2S_CUR_WS;
+               if (prev != cur) {
+                       prev = cur;
+                       j++;
+               }
+       }
+       if (j < 6)
+               printk(KERN_WARNING "s6000-i2s: timeout waiting for WCLK\n");
+
+       s6_i2s_write_reg(dev, S6_I2S_ENABLE(channel), S6_I2S_ENABLE_IF);
+}
+
+static void s6000_i2s_stop_channel(struct s6000_i2s_dev *dev, int channel)
+{
+       s6_i2s_write_reg(dev, S6_I2S_ENABLE(channel), S6_I2S_DISABLE_IF);
+}
+
+static void s6000_i2s_start(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct s6000_i2s_dev *dev = rtd->dai->cpu_dai->private_data;
+       int channel;
+
+       channel = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+                       dev->channel_out : dev->channel_in;
+
+       s6000_i2s_start_channel(dev, channel);
+}
+
+static void s6000_i2s_stop(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct s6000_i2s_dev *dev = rtd->dai->cpu_dai->private_data;
+       int channel;
+
+       channel = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+                       dev->channel_out : dev->channel_in;
+
+       s6000_i2s_stop_channel(dev, channel);
+}
+
+static int s6000_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+                            int after)
+{
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) ^ !after)
+                       s6000_i2s_start(substream);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (!after)
+                       s6000_i2s_stop(substream);
+       }
+       return 0;
+}
+
+static unsigned int s6000_i2s_int_sources(struct s6000_i2s_dev *dev)
+{
+       unsigned int pending;
+       pending = s6_i2s_read_reg(dev, S6_I2S_INTERRUPT_RAW);
+       pending &= S6_I2S_INT_ALIGNMENT |
+                  S6_I2S_INT_UNDERRUN |
+                  S6_I2S_INT_OVERRUN;
+       s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_CLEAR, pending);
+
+       return pending;
+}
+
+static unsigned int s6000_i2s_check_xrun(struct snd_soc_dai *cpu_dai)
+{
+       struct s6000_i2s_dev *dev = cpu_dai->private_data;
+       unsigned int errors;
+       unsigned int ret;
+
+       errors = s6000_i2s_int_sources(dev);
+       if (likely(!errors))
+               return 0;
+
+       ret = 0;
+       if (errors & S6_I2S_INT_ALIGNMENT)
+               printk(KERN_ERR "s6000-i2s: WCLK misaligned\n");
+       if (errors & S6_I2S_INT_UNDERRUN)
+               ret |= 1 << SNDRV_PCM_STREAM_PLAYBACK;
+       if (errors & S6_I2S_INT_OVERRUN)
+               ret |= 1 << SNDRV_PCM_STREAM_CAPTURE;
+       return ret;
+}
+
+static void s6000_i2s_wait_disabled(struct s6000_i2s_dev *dev)
+{
+       int channel;
+       int n = 50;
+       for (channel = 0; channel < 2; channel++) {
+               while (--n >= 0) {
+                       int v = s6_i2s_read_reg(dev, S6_I2S_ENABLE(channel));
+                       if ((v & S6_I2S_IS_ENABLED)
+                           || !(v & (S6_I2S_DMA_ACTIVE | S6_I2S_IS_BUSY)))
+                               break;
+                       udelay(20);
+               }
+       }
+       if (n < 0)
+               printk(KERN_WARNING "s6000-i2s: timeout disabling interfaces");
+}
+
+static int s6000_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+                                  unsigned int fmt)
+{
+       struct s6000_i2s_dev *dev = cpu_dai->private_data;
+       u32 w;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               w = S6_I2S_SCK_IN | S6_I2S_WS_IN;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               w = S6_I2S_SCK_OUT | S6_I2S_WS_IN;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               w = S6_I2S_SCK_IN | S6_I2S_WS_OUT;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               w = S6_I2S_SCK_OUT | S6_I2S_WS_OUT;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               w |= S6_I2S_LEFT_FIRST;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               w |= S6_I2S_RIGHT_FIRST;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(0),
+                      S6_I2S_FIRST | S6_I2S_WS_DIR | S6_I2S_SCK_DIR, w);
+       s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(1),
+                      S6_I2S_FIRST | S6_I2S_WS_DIR | S6_I2S_SCK_DIR, w);
+
+       return 0;
+}
+
+static int s6000_i2s_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
+{
+       struct s6000_i2s_dev *dev = dai->private_data;
+
+       if (!div || (div & 1) || div > (S6_I2S_DIV_MASK + 1) * 2)
+               return -EINVAL;
+
+       s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(div_id),
+                      S6_I2S_DIV_MASK, div / 2 - 1);
+       return 0;
+}
+
+static int s6000_i2s_hw_params(struct snd_pcm_substream *substream,
+                              struct snd_pcm_hw_params *params,
+                              struct snd_soc_dai *dai)
+{
+       struct s6000_i2s_dev *dev = dai->private_data;
+       int interf;
+       u32 w = 0;
+
+       if (dev->wide)
+               interf = 0;
+       else {
+               w |= (((params_channels(params) - 2) / 2)
+                     << S6_I2S_CHANNELS_SHIFT) & S6_I2S_CHANNELS_MASK;
+               interf = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                               ? dev->channel_out : dev->channel_in;
+       }
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               w |= S6_I2S_16BIT | S6_I2S_MEM_16BIT;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               w |= S6_I2S_32BIT | S6_I2S_MEM_32BIT;
+               break;
+       default:
+               printk(KERN_WARNING "s6000-i2s: unsupported PCM format %x\n",
+                      params_format(params));
+               return -EINVAL;
+       }
+
+       if (s6_i2s_read_reg(dev, S6_I2S_INTERFACE_CFG(interf))
+            & S6_I2S_IS_ENABLED) {
+               printk(KERN_ERR "s6000-i2s: interface already enabled\n");
+               return -EBUSY;
+       }
+
+       s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(interf),
+                      S6_I2S_CHANNELS_MASK|S6_I2S_MEM_MASK|S6_I2S_BITS_MASK,
+                      w);
+
+       return 0;
+}
+
+static int s6000_i2s_dai_probe(struct platform_device *pdev,
+                              struct snd_soc_dai *dai)
+{
+       struct s6000_i2s_dev *dev = dai->private_data;
+       struct s6000_snd_platform_data *pdata = pdev->dev.platform_data;
+
+       if (!pdata)
+               return -EINVAL;
+
+       dev->wide = pdata->wide;
+       dev->channel_in = pdata->channel_in;
+       dev->channel_out = pdata->channel_out;
+       dev->lines_in = pdata->lines_in;
+       dev->lines_out = pdata->lines_out;
+
+       s6_i2s_write_reg(dev, S6_I2S_MODE,
+                        dev->wide ? S6_I2S_WIDE : S6_I2S_DUAL);
+
+       if (dev->wide) {
+               int i;
+
+               if (dev->lines_in + dev->lines_out > S6_I2S_NUM_LINES)
+                       return -EINVAL;
+
+               dev->channel_in = 0;
+               dev->channel_out = 1;
+               dai->capture.channels_min = 2 * dev->lines_in;
+               dai->capture.channels_max = dai->capture.channels_min;
+               dai->playback.channels_min = 2 * dev->lines_out;
+               dai->playback.channels_max = dai->playback.channels_min;
+
+               for (i = 0; i < dev->lines_out; i++)
+                       s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i), S6_I2S_OUT);
+
+               for (; i < S6_I2S_NUM_LINES - dev->lines_in; i++)
+                       s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i),
+                                        S6_I2S_UNUSED);
+
+               for (; i < S6_I2S_NUM_LINES; i++)
+                       s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i), S6_I2S_IN);
+       } else {
+               unsigned int cfg[2] = {S6_I2S_UNUSED, S6_I2S_UNUSED};
+
+               if (dev->lines_in > 1 || dev->lines_out > 1)
+                       return -EINVAL;
+
+               dai->capture.channels_min = 2 * dev->lines_in;
+               dai->capture.channels_max = 8 * dev->lines_in;
+               dai->playback.channels_min = 2 * dev->lines_out;
+               dai->playback.channels_max = 8 * dev->lines_out;
+
+               if (dev->lines_in)
+                       cfg[dev->channel_in] = S6_I2S_IN;
+               if (dev->lines_out)
+                       cfg[dev->channel_out] = S6_I2S_OUT;
+
+               s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(0), cfg[0]);
+               s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(1), cfg[1]);
+       }
+
+       if (dev->lines_out) {
+               if (dev->lines_in) {
+                       if (!dev->dma_params.dma_out)
+                               return -ENODEV;
+               } else {
+                       dev->dma_params.dma_out = dev->dma_params.dma_in;
+                       dev->dma_params.dma_in = 0;
+               }
+       }
+       dev->dma_params.sif_in = dev->sifbase + (dev->channel_in ?
+                                       S6_I2S_SIF_PORT1 : S6_I2S_SIF_PORT0);
+       dev->dma_params.sif_out = dev->sifbase + (dev->channel_out ?
+                                       S6_I2S_SIF_PORT1 : S6_I2S_SIF_PORT0);
+       dev->dma_params.same_rate = pdata->same_rate | pdata->wide;
+       return 0;
+}
+
+#define S6000_I2S_RATES        (SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_5512 | \
+                        SNDRV_PCM_RATE_8000_192000)
+#define S6000_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops s6000_i2s_dai_ops = {
+       .set_fmt = s6000_i2s_set_dai_fmt,
+       .set_clkdiv = s6000_i2s_set_clkdiv,
+       .hw_params = s6000_i2s_hw_params,
+};
+
+struct snd_soc_dai s6000_i2s_dai = {
+       .name = "s6000-i2s",
+       .id = 0,
+       .probe = s6000_i2s_dai_probe,
+       .playback = {
+               .channels_min = 2,
+               .channels_max = 8,
+               .formats = S6000_I2S_FORMATS,
+               .rates = S6000_I2S_RATES,
+               .rate_min = 0,
+               .rate_max = 1562500,
+       },
+       .capture = {
+               .channels_min = 2,
+               .channels_max = 8,
+               .formats = S6000_I2S_FORMATS,
+               .rates = S6000_I2S_RATES,
+               .rate_min = 0,
+               .rate_max = 1562500,
+       },
+       .ops = &s6000_i2s_dai_ops,
+}
+EXPORT_SYMBOL_GPL(s6000_i2s_dai);
+
+static int __devinit s6000_i2s_probe(struct platform_device *pdev)
+{
+       struct s6000_i2s_dev *dev;
+       struct resource *scbmem, *sifmem, *region, *dma1, *dma2;
+       u8 __iomem *mmio;
+       int ret;
+
+       scbmem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!scbmem) {
+               dev_err(&pdev->dev, "no mem resource?\n");
+               ret = -ENODEV;
+               goto err_release_none;
+       }
+
+       region = request_mem_region(scbmem->start,
+                                   scbmem->end - scbmem->start + 1,
+                                   pdev->name);
+       if (!region) {
+               dev_err(&pdev->dev, "I2S SCB region already claimed\n");
+               ret = -EBUSY;
+               goto err_release_none;
+       }
+
+       mmio = ioremap(scbmem->start, scbmem->end - scbmem->start + 1);
+       if (!mmio) {
+               dev_err(&pdev->dev, "can't ioremap SCB region\n");
+               ret = -ENOMEM;
+               goto err_release_scb;
+       }
+
+       sifmem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!sifmem) {
+               dev_err(&pdev->dev, "no second mem resource?\n");
+               ret = -ENODEV;
+               goto err_release_map;
+       }
+
+       region = request_mem_region(sifmem->start,
+                                   sifmem->end - sifmem->start + 1,
+                                   pdev->name);
+       if (!region) {
+               dev_err(&pdev->dev, "I2S SIF region already claimed\n");
+               ret = -EBUSY;
+               goto err_release_map;
+       }
+
+       dma1 = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       if (!dma1) {
+               dev_err(&pdev->dev, "no dma resource?\n");
+               ret = -ENODEV;
+               goto err_release_sif;
+       }
+
+       region = request_mem_region(dma1->start, dma1->end - dma1->start + 1,
+                                   pdev->name);
+       if (!region) {
+               dev_err(&pdev->dev, "I2S DMA region already claimed\n");
+               ret = -EBUSY;
+               goto err_release_sif;
+       }
+
+       dma2 = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+       if (dma2) {
+               region = request_mem_region(dma2->start,
+                                           dma2->end - dma2->start + 1,
+                                           pdev->name);
+               if (!region) {
+                       dev_err(&pdev->dev,
+                               "I2S DMA region already claimed\n");
+                       ret = -EBUSY;
+                       goto err_release_dma1;
+               }
+       }
+
+       dev = kzalloc(sizeof(struct s6000_i2s_dev), GFP_KERNEL);
+       if (!dev) {
+               ret = -ENOMEM;
+               goto err_release_dma2;
+       }
+
+       s6000_i2s_dai.dev = &pdev->dev;
+       s6000_i2s_dai.private_data = dev;
+       s6000_i2s_dai.dma_data = &dev->dma_params;
+
+       dev->sifbase = sifmem->start;
+       dev->scbbase = mmio;
+
+       s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE, 0);
+       s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_CLEAR,
+                        S6_I2S_INT_ALIGNMENT |
+                        S6_I2S_INT_UNDERRUN |
+                        S6_I2S_INT_OVERRUN);
+
+       s6000_i2s_stop_channel(dev, 0);
+       s6000_i2s_stop_channel(dev, 1);
+       s6000_i2s_wait_disabled(dev);
+
+       dev->dma_params.check_xrun = s6000_i2s_check_xrun;
+       dev->dma_params.trigger = s6000_i2s_trigger;
+       dev->dma_params.dma_in = dma1->start;
+       dev->dma_params.dma_out = dma2 ? dma2->start : 0;
+       dev->dma_params.irq = platform_get_irq(pdev, 0);
+       if (dev->dma_params.irq < 0) {
+               dev_err(&pdev->dev, "no irq resource?\n");
+               ret = -ENODEV;
+               goto err_release_dev;
+       }
+
+       s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE,
+                        S6_I2S_INT_ALIGNMENT |
+                        S6_I2S_INT_UNDERRUN |
+                        S6_I2S_INT_OVERRUN);
+
+       ret = snd_soc_register_dai(&s6000_i2s_dai);
+       if (ret)
+               goto err_release_dev;
+
+       return 0;
+
+err_release_dev:
+       kfree(dev);
+err_release_dma2:
+       if (dma2)
+               release_mem_region(dma2->start, dma2->end - dma2->start + 1);
+err_release_dma1:
+       release_mem_region(dma1->start, dma1->end - dma1->start + 1);
+err_release_sif:
+       release_mem_region(sifmem->start, (sifmem->end - sifmem->start) + 1);
+err_release_map:
+       iounmap(mmio);
+err_release_scb:
+       release_mem_region(scbmem->start, (scbmem->end - scbmem->start) + 1);
+err_release_none:
+       return ret;
+}
+
+static void __devexit s6000_i2s_remove(struct platform_device *pdev)
+{
+       struct s6000_i2s_dev *dev = s6000_i2s_dai.private_data;
+       struct resource *region;
+       void __iomem *mmio = dev->scbbase;
+
+       snd_soc_unregister_dai(&s6000_i2s_dai);
+
+       s6000_i2s_stop_channel(dev, 0);
+       s6000_i2s_stop_channel(dev, 1);
+
+       s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE, 0);
+       s6000_i2s_dai.private_data = 0;
+       kfree(dev);
+
+       region = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       release_mem_region(region->start, region->end - region->start + 1);
+
+       region = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+       if (region)
+               release_mem_region(region->start,
+                                  region->end - region->start + 1);
+
+       region = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(region->start, (region->end - region->start) + 1);
+
+       iounmap(mmio);
+       region = platform_get_resource(pdev, IORESOURCE_IO, 0);
+       release_mem_region(region->start, (region->end - region->start) + 1);
+}
+
+static struct platform_driver s6000_i2s_driver = {
+       .probe  = s6000_i2s_probe,
+       .remove = __devexit_p(s6000_i2s_remove),
+       .driver = {
+               .name   = "s6000-i2s",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init s6000_i2s_init(void)
+{
+       return platform_driver_register(&s6000_i2s_driver);
+}
+module_init(s6000_i2s_init);
+
+static void __exit s6000_i2s_exit(void)
+{
+       platform_driver_unregister(&s6000_i2s_driver);
+}
+module_exit(s6000_i2s_exit);
+
+MODULE_AUTHOR("Daniel Gloeckner");
+MODULE_DESCRIPTION("Stretch s6000 family I2S SoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s6000/s6000-i2s.h b/sound/soc/s6000/s6000-i2s.h
new file mode 100644 (file)
index 0000000..2375fdf
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * ALSA SoC I2S Audio Layer for the Stretch s6000 family
+ *
+ * Author:      Daniel Gloeckner, <dg@emlix.com>
+ * Copyright:   (C) 2009 emlix GmbH <info@emlix.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 _S6000_I2S_H
+#define _S6000_I2S_H
+
+extern struct snd_soc_dai s6000_i2s_dai;
+
+struct s6000_snd_platform_data {
+       int lines_in;
+       int lines_out;
+       int channel_in;
+       int channel_out;
+       int wide;
+       int same_rate;
+};
+#endif
diff --git a/sound/soc/s6000/s6000-pcm.c b/sound/soc/s6000/s6000-pcm.c
new file mode 100644 (file)
index 0000000..83b8028
--- /dev/null
@@ -0,0 +1,497 @@
+/*
+ * ALSA PCM interface for the Stetch s6000 family
+ *
+ * Author:      Daniel Gloeckner, <dg@emlix.com>
+ * Copyright:   (C) 2009 emlix GmbH <info@emlix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/dma.h>
+#include <variant/dmac.h>
+
+#include "s6000-pcm.h"
+
+#define S6_PCM_PREALLOCATE_SIZE (96 * 1024)
+#define S6_PCM_PREALLOCATE_MAX  (2048 * 1024)
+
+static struct snd_pcm_hardware s6000_pcm_hardware = {
+       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_JOINT_DUPLEX),
+       .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE),
+       .rates = (SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_5512 | \
+                 SNDRV_PCM_RATE_8000_192000),
+       .rate_min = 0,
+       .rate_max = 1562500,
+       .channels_min = 2,
+       .channels_max = 8,
+       .buffer_bytes_max = 0x7ffffff0,
+       .period_bytes_min = 16,
+       .period_bytes_max = 0xfffff0,
+       .periods_min = 2,
+       .periods_max = 1024, /* no limit */
+       .fifo_size = 0,
+};
+
+struct s6000_runtime_data {
+       spinlock_t lock;
+       int period;             /* current DMA period */
+};
+
+static void s6000_pcm_enqueue_dma(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct s6000_runtime_data *prtd = runtime->private_data;
+       struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+       struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data;
+       int channel;
+       unsigned int period_size;
+       unsigned int dma_offset;
+       dma_addr_t dma_pos;
+       dma_addr_t src, dst;
+
+       period_size = snd_pcm_lib_period_bytes(substream);
+       dma_offset = prtd->period * period_size;
+       dma_pos = runtime->dma_addr + dma_offset;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               src = dma_pos;
+               dst = par->sif_out;
+               channel = par->dma_out;
+       } else {
+               src = par->sif_in;
+               dst = dma_pos;
+               channel = par->dma_in;
+       }
+
+       if (!s6dmac_channel_enabled(DMA_MASK_DMAC(channel),
+                                   DMA_INDEX_CHNL(channel)))
+               return;
+
+       if (s6dmac_fifo_full(DMA_MASK_DMAC(channel), DMA_INDEX_CHNL(channel))) {
+               printk(KERN_ERR "s6000-pcm: fifo full\n");
+               return;
+       }
+
+       BUG_ON(period_size & 15);
+       s6dmac_put_fifo(DMA_MASK_DMAC(channel), DMA_INDEX_CHNL(channel),
+                       src, dst, period_size);
+
+       prtd->period++;
+       if (unlikely(prtd->period >= runtime->periods))
+               prtd->period = 0;
+}
+
+static irqreturn_t s6000_pcm_irq(int irq, void *data)
+{
+       struct snd_pcm *pcm = data;
+       struct snd_soc_pcm_runtime *runtime = pcm->private_data;
+       struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data;
+       struct s6000_runtime_data *prtd;
+       unsigned int has_xrun;
+       int i, ret = IRQ_NONE;
+       u32 channel[2] = {
+               [SNDRV_PCM_STREAM_PLAYBACK] = params->dma_out,
+               [SNDRV_PCM_STREAM_CAPTURE] = params->dma_in
+       };
+
+       has_xrun = params->check_xrun(runtime->dai->cpu_dai);
+
+       for (i = 0; i < ARRAY_SIZE(channel); ++i) {
+               struct snd_pcm_substream *substream = pcm->streams[i].substream;
+               unsigned int pending;
+
+               if (!channel[i])
+                       continue;
+
+               if (unlikely(has_xrun & (1 << i)) &&
+                   substream->runtime &&
+                   snd_pcm_running(substream)) {
+                       dev_dbg(pcm->dev, "xrun\n");
+                       snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+                       ret = IRQ_HANDLED;
+               }
+
+               pending = s6dmac_int_sources(DMA_MASK_DMAC(channel[i]),
+                                            DMA_INDEX_CHNL(channel[i]));
+
+               if (pending & 1) {
+                       ret = IRQ_HANDLED;
+                       if (likely(substream->runtime &&
+                                  snd_pcm_running(substream))) {
+                               snd_pcm_period_elapsed(substream);
+                               dev_dbg(pcm->dev, "period elapsed %x %x\n",
+                                      s6dmac_cur_src(DMA_MASK_DMAC(channel[i]),
+                                                  DMA_INDEX_CHNL(channel[i])),
+                                      s6dmac_cur_dst(DMA_MASK_DMAC(channel[i]),
+                                                  DMA_INDEX_CHNL(channel[i])));
+                               prtd = substream->runtime->private_data;
+                               spin_lock(&prtd->lock);
+                               s6000_pcm_enqueue_dma(substream);
+                               spin_unlock(&prtd->lock);
+                       }
+               }
+
+               if (unlikely(pending & ~7)) {
+                       if (pending & (1 << 3))
+                               printk(KERN_WARNING
+                                      "s6000-pcm: DMA %x Underflow\n",
+                                      channel[i]);
+                       if (pending & (1 << 4))
+                               printk(KERN_WARNING
+                                      "s6000-pcm: DMA %x Overflow\n",
+                                      channel[i]);
+                       if (pending & 0x1e0)
+                               printk(KERN_WARNING
+                                      "s6000-pcm: DMA %x Master Error "
+                                      "(mask %x)\n",
+                                      channel[i], pending >> 5);
+
+               }
+       }
+
+       return ret;
+}
+
+static int s6000_pcm_start(struct snd_pcm_substream *substream)
+{
+       struct s6000_runtime_data *prtd = substream->runtime->private_data;
+       struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+       struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data;
+       unsigned long flags;
+       int srcinc;
+       u32 dma;
+
+       spin_lock_irqsave(&prtd->lock, flags);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               srcinc = 1;
+               dma = par->dma_out;
+       } else {
+               srcinc = 0;
+               dma = par->dma_in;
+       }
+       s6dmac_enable_chan(DMA_MASK_DMAC(dma), DMA_INDEX_CHNL(dma),
+                          1 /* priority 1 (0 is max) */,
+                          0 /* peripheral requests w/o xfer length mode */,
+                          srcinc /* source address increment */,
+                          srcinc^1 /* destination address increment */,
+                          0 /* chunksize 0 (skip impossible on this dma) */,
+                          0 /* source skip after chunk (impossible) */,
+                          0 /* destination skip after chunk (impossible) */,
+                          4 /* 16 byte burst size */,
+                          -1 /* don't conserve bandwidth */,
+                          0 /* low watermark irq descriptor theshold */,
+                          0 /* disable hardware timestamps */,
+                          1 /* enable channel */);
+
+       s6000_pcm_enqueue_dma(substream);
+       s6000_pcm_enqueue_dma(substream);
+
+       spin_unlock_irqrestore(&prtd->lock, flags);
+
+       return 0;
+}
+
+static int s6000_pcm_stop(struct snd_pcm_substream *substream)
+{
+       struct s6000_runtime_data *prtd = substream->runtime->private_data;
+       struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+       struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data;
+       unsigned long flags;
+       u32 channel;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               channel = par->dma_out;
+       else
+               channel = par->dma_in;
+
+       s6dmac_set_terminal_count(DMA_MASK_DMAC(channel),
+                                 DMA_INDEX_CHNL(channel), 0);
+
+       spin_lock_irqsave(&prtd->lock, flags);
+
+       s6dmac_disable_chan(DMA_MASK_DMAC(channel), DMA_INDEX_CHNL(channel));
+
+       spin_unlock_irqrestore(&prtd->lock, flags);
+
+       return 0;
+}
+
+static int s6000_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+       struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data;
+       int ret;
+
+       ret = par->trigger(substream, cmd, 0);
+       if (ret < 0)
+               return ret;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               ret = s6000_pcm_start(substream);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               ret = s6000_pcm_stop(substream);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       if (ret < 0)
+               return ret;
+
+       return par->trigger(substream, cmd, 1);
+}
+
+static int s6000_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       struct s6000_runtime_data *prtd = substream->runtime->private_data;
+
+       prtd->period = 0;
+
+       return 0;
+}
+
+static snd_pcm_uframes_t s6000_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+       struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct s6000_runtime_data *prtd = runtime->private_data;
+       unsigned long flags;
+       unsigned int offset;
+       dma_addr_t count;
+
+       spin_lock_irqsave(&prtd->lock, flags);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               count = s6dmac_cur_src(DMA_MASK_DMAC(par->dma_out),
+                                      DMA_INDEX_CHNL(par->dma_out));
+       else
+               count = s6dmac_cur_dst(DMA_MASK_DMAC(par->dma_in),
+                                      DMA_INDEX_CHNL(par->dma_in));
+
+       count -= runtime->dma_addr;
+
+       spin_unlock_irqrestore(&prtd->lock, flags);
+
+       offset = bytes_to_frames(runtime, count);
+       if (unlikely(offset >= runtime->buffer_size))
+               offset = 0;
+
+       return offset;
+}
+
+static int s6000_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+       struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct s6000_runtime_data *prtd;
+       int ret;
+
+       snd_soc_set_runtime_hwparams(substream, &s6000_pcm_hardware);
+
+       ret = snd_pcm_hw_constraint_step(runtime, 0,
+                                        SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 16);
+       if (ret < 0)
+               return ret;
+       ret = snd_pcm_hw_constraint_step(runtime, 0,
+                                        SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16);
+       if (ret < 0)
+               return ret;
+       ret = snd_pcm_hw_constraint_integer(runtime,
+                                           SNDRV_PCM_HW_PARAM_PERIODS);
+       if (ret < 0)
+               return ret;
+
+       if (par->same_rate) {
+               int rate;
+               spin_lock(&par->lock); /* needed? */
+               rate = par->rate;
+               spin_unlock(&par->lock);
+               if (rate != -1) {
+                       ret = snd_pcm_hw_constraint_minmax(runtime,
+                                                       SNDRV_PCM_HW_PARAM_RATE,
+                                                       rate, rate);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+
+       prtd = kzalloc(sizeof(struct s6000_runtime_data), GFP_KERNEL);
+       if (prtd == NULL)
+               return -ENOMEM;
+
+       spin_lock_init(&prtd->lock);
+
+       runtime->private_data = prtd;
+
+       return 0;
+}
+
+static int s6000_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct s6000_runtime_data *prtd = runtime->private_data;
+
+       kfree(prtd);
+
+       return 0;
+}
+
+static int s6000_pcm_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *hw_params)
+{
+       struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+       struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data;
+       int ret;
+       ret = snd_pcm_lib_malloc_pages(substream,
+                                      params_buffer_bytes(hw_params));
+       if (ret < 0) {
+               printk(KERN_WARNING "s6000-pcm: allocation of memory failed\n");
+               return ret;
+       }
+
+       if (par->same_rate) {
+               spin_lock(&par->lock);
+               if (par->rate == -1 ||
+                   !(par->in_use & ~(1 << substream->stream))) {
+                       par->rate = params_rate(hw_params);
+                       par->in_use |= 1 << substream->stream;
+               } else if (params_rate(hw_params) != par->rate) {
+                       snd_pcm_lib_free_pages(substream);
+                       par->in_use &= ~(1 << substream->stream);
+                       ret = -EBUSY;
+               }
+               spin_unlock(&par->lock);
+       }
+       return ret;
+}
+
+static int s6000_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+       struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data;
+
+       spin_lock(&par->lock);
+       par->in_use &= ~(1 << substream->stream);
+       if (!par->in_use)
+               par->rate = -1;
+       spin_unlock(&par->lock);
+
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static struct snd_pcm_ops s6000_pcm_ops = {
+       .open =         s6000_pcm_open,
+       .close =        s6000_pcm_close,
+       .ioctl =        snd_pcm_lib_ioctl,
+       .hw_params =    s6000_pcm_hw_params,
+       .hw_free =      s6000_pcm_hw_free,
+       .trigger =      s6000_pcm_trigger,
+       .prepare =      s6000_pcm_prepare,
+       .pointer =      s6000_pcm_pointer,
+};
+
+static void s6000_pcm_free(struct snd_pcm *pcm)
+{
+       struct snd_soc_pcm_runtime *runtime = pcm->private_data;
+       struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data;
+
+       free_irq(params->irq, pcm);
+       snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static u64 s6000_pcm_dmamask = DMA_32BIT_MASK;
+
+static int s6000_pcm_new(struct snd_card *card,
+                        struct snd_soc_dai *dai, struct snd_pcm *pcm)
+{
+       struct snd_soc_pcm_runtime *runtime = pcm->private_data;
+       struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data;
+       int res;
+
+       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;
+
+       if (params->dma_in) {
+               s6dmac_disable_chan(DMA_MASK_DMAC(params->dma_in),
+                                   DMA_INDEX_CHNL(params->dma_in));
+               s6dmac_int_sources(DMA_MASK_DMAC(params->dma_in),
+                                  DMA_INDEX_CHNL(params->dma_in));
+       }
+
+       if (params->dma_out) {
+               s6dmac_disable_chan(DMA_MASK_DMAC(params->dma_out),
+                                   DMA_INDEX_CHNL(params->dma_out));
+               s6dmac_int_sources(DMA_MASK_DMAC(params->dma_out),
+                                  DMA_INDEX_CHNL(params->dma_out));
+       }
+
+       res = request_irq(params->irq, s6000_pcm_irq, IRQF_SHARED,
+                         s6000_soc_platform.name, pcm);
+       if (res) {
+               printk(KERN_ERR "s6000-pcm couldn't get IRQ\n");
+               return res;
+       }
+
+       res = snd_pcm_lib_preallocate_pages_for_all(pcm,
+                                                   SNDRV_DMA_TYPE_DEV,
+                                                   card->dev,
+                                                   S6_PCM_PREALLOCATE_SIZE,
+                                                   S6_PCM_PREALLOCATE_MAX);
+       if (res)
+               printk(KERN_WARNING "s6000-pcm: preallocation failed\n");
+
+       spin_lock_init(&params->lock);
+       params->in_use = 0;
+       params->rate = -1;
+       return 0;
+}
+
+struct snd_soc_platform s6000_soc_platform = {
+       .name =         "s6000-audio",
+       .pcm_ops =      &s6000_pcm_ops,
+       .pcm_new =      s6000_pcm_new,
+       .pcm_free =     s6000_pcm_free,
+};
+EXPORT_SYMBOL_GPL(s6000_soc_platform);
+
+static int __init s6000_pcm_init(void)
+{
+       return snd_soc_register_platform(&s6000_soc_platform);
+}
+module_init(s6000_pcm_init);
+
+static void __exit s6000_pcm_exit(void)
+{
+       snd_soc_unregister_platform(&s6000_soc_platform);
+}
+module_exit(s6000_pcm_exit);
+
+MODULE_AUTHOR("Daniel Gloeckner");
+MODULE_DESCRIPTION("Stretch s6000 family PCM DMA module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s6000/s6000-pcm.h b/sound/soc/s6000/s6000-pcm.h
new file mode 100644 (file)
index 0000000..96f23f6
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * ALSA PCM interface for the Stretch s6000 family
+ *
+ * Author:      Daniel Gloeckner, <dg@emlix.com>
+ * Copyright:   (C) 2009 emlix GmbH <info@emlix.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 _S6000_PCM_H
+#define _S6000_PCM_H
+
+struct snd_soc_dai;
+struct snd_pcm_substream;
+
+struct s6000_pcm_dma_params {
+       unsigned int (*check_xrun)(struct snd_soc_dai *cpu_dai);
+       int (*trigger)(struct snd_pcm_substream *substream, int cmd, int after);
+       dma_addr_t sif_in;
+       dma_addr_t sif_out;
+       u32 dma_in;
+       u32 dma_out;
+       int irq;
+       int same_rate;
+
+       spinlock_t lock;
+       int in_use;
+       int rate;
+};
+
+extern struct snd_soc_platform s6000_soc_platform;
+
+#endif
diff --git a/sound/soc/s6000/s6105-ipcam.c b/sound/soc/s6000/s6105-ipcam.c
new file mode 100644 (file)
index 0000000..b5f95f9
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * ASoC driver for Stretch s6105 IP camera platform
+ *
+ * Author:      Daniel Gloeckner, <dg@emlix.com>
+ * Copyright:   (C) 2009 emlix GmbH <info@emlix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <variant/dmac.h>
+
+#include "../codecs/tlv320aic3x.h"
+#include "s6000-pcm.h"
+#include "s6000-i2s.h"
+
+#define S6105_CAM_CODEC_CLOCK 12288000
+
+static int s6105_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 = 0;
+
+       /* set codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+                                            SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       /* set cpu DAI configuration */
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM |
+                                          SND_SOC_DAIFMT_NB_NF);
+       if (ret < 0)
+               return ret;
+
+       /* set the codec system clock */
+       ret = snd_soc_dai_set_sysclk(codec_dai, 0, S6105_CAM_CODEC_CLOCK,
+                                           SND_SOC_CLOCK_OUT);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static struct snd_soc_ops s6105_ops = {
+       .hw_params = s6105_hw_params,
+};
+
+/* s6105 machine dapm widgets */
+static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
+       SND_SOC_DAPM_LINE("Audio Out Differential", NULL),
+       SND_SOC_DAPM_LINE("Audio Out Stereo", NULL),
+       SND_SOC_DAPM_LINE("Audio In", NULL),
+};
+
+/* s6105 machine audio_mapnections to the codec pins */
+static const struct snd_soc_dapm_route audio_map[] = {
+       /* Audio Out connected to HPLOUT, HPLCOM, HPROUT */
+       {"Audio Out Differential", NULL, "HPLOUT"},
+       {"Audio Out Differential", NULL, "HPLCOM"},
+       {"Audio Out Stereo", NULL, "HPLOUT"},
+       {"Audio Out Stereo", NULL, "HPROUT"},
+
+       /* Audio In connected to LINE1L, LINE1R */
+       {"LINE1L", NULL, "Audio In"},
+       {"LINE1R", NULL, "Audio In"},
+};
+
+static int output_type_info(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = 2;
+       if (uinfo->value.enumerated.item) {
+               uinfo->value.enumerated.item = 1;
+               strcpy(uinfo->value.enumerated.name, "HPLOUT/HPROUT");
+       } else {
+               strcpy(uinfo->value.enumerated.name, "HPLOUT/HPLCOM");
+       }
+       return 0;
+}
+
+static int output_type_get(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.enumerated.item[0] = kcontrol->private_value;
+       return 0;
+}
+
+static int output_type_put(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = kcontrol->private_data;
+       unsigned int val = (ucontrol->value.enumerated.item[0] != 0);
+       char *differential = "Audio Out Differential";
+       char *stereo = "Audio Out Stereo";
+
+       if (kcontrol->private_value == val)
+               return 0;
+       kcontrol->private_value = val;
+       snd_soc_dapm_disable_pin(codec, val ? differential : stereo);
+       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_enable_pin(codec, val ? stereo : differential);
+       snd_soc_dapm_sync(codec);
+
+       return 1;
+}
+
+static const struct snd_kcontrol_new audio_out_mux = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Master Output Mux",
+       .index = 0,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .info = output_type_info,
+       .get = output_type_get,
+       .put = output_type_put,
+       .private_value = 1 /* default to stereo */
+};
+
+/* Logic for a aic3x as connected on the s6105 ip camera ref design */
+static int s6105_aic3x_init(struct snd_soc_codec *codec)
+{
+       /* Add s6105 specific widgets */
+       snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets,
+                                 ARRAY_SIZE(aic3x_dapm_widgets));
+
+       /* Set up s6105 specific audio path audio_map */
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+       /* not present */
+       snd_soc_dapm_nc_pin(codec, "MONO_LOUT");
+       snd_soc_dapm_nc_pin(codec, "LINE2L");
+       snd_soc_dapm_nc_pin(codec, "LINE2R");
+
+       /* not connected */
+       snd_soc_dapm_nc_pin(codec, "MIC3L"); /* LINE2L on this chip */
+       snd_soc_dapm_nc_pin(codec, "MIC3R"); /* LINE2R on this chip */
+       snd_soc_dapm_nc_pin(codec, "LLOUT");
+       snd_soc_dapm_nc_pin(codec, "RLOUT");
+       snd_soc_dapm_nc_pin(codec, "HPRCOM");
+
+       /* always connected */
+       snd_soc_dapm_enable_pin(codec, "Audio In");
+
+       /* must correspond to audio_out_mux.private_value initializer */
+       snd_soc_dapm_disable_pin(codec, "Audio Out Differential");
+       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_enable_pin(codec, "Audio Out Stereo");
+
+       snd_soc_dapm_sync(codec);
+
+       snd_ctl_add(codec->card, snd_ctl_new1(&audio_out_mux, codec));
+
+       return 0;
+}
+
+/* s6105 digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link s6105_dai = {
+       .name = "TLV320AIC31",
+       .stream_name = "AIC31",
+       .cpu_dai = &s6000_i2s_dai,
+       .codec_dai = &aic3x_dai,
+       .init = s6105_aic3x_init,
+       .ops = &s6105_ops,
+};
+
+/* s6105 audio machine driver */
+static struct snd_soc_card snd_soc_card_s6105 = {
+       .name = "Stretch IP Camera",
+       .platform = &s6000_soc_platform,
+       .dai_link = &s6105_dai,
+       .num_links = 1,
+};
+
+/* s6105 audio private data */
+static struct aic3x_setup_data s6105_aic3x_setup = {
+       .i2c_bus = 0,
+       .i2c_address = 0x18,
+};
+
+/* s6105 audio subsystem */
+static struct snd_soc_device s6105_snd_devdata = {
+       .card = &snd_soc_card_s6105,
+       .codec_dev = &soc_codec_dev_aic3x,
+       .codec_data = &s6105_aic3x_setup,
+};
+
+static struct s6000_snd_platform_data __initdata s6105_snd_data = {
+       .wide           = 0,
+       .channel_in     = 0,
+       .channel_out    = 1,
+       .lines_in       = 1,
+       .lines_out      = 1,
+       .same_rate      = 1,
+};
+
+static struct platform_device *s6105_snd_device;
+
+static int __init s6105_init(void)
+{
+       int ret;
+
+       s6105_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!s6105_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(s6105_snd_device, &s6105_snd_devdata);
+       s6105_snd_devdata.dev = &s6105_snd_device->dev;
+       platform_device_add_data(s6105_snd_device, &s6105_snd_data,
+                                sizeof(s6105_snd_data));
+
+       ret = platform_device_add(s6105_snd_device);
+       if (ret)
+               platform_device_put(s6105_snd_device);
+
+       return ret;
+}
+
+static void __exit s6105_exit(void)
+{
+       platform_device_unregister(s6105_snd_device);
+}
+
+module_init(s6105_init);
+module_exit(s6105_exit);
+
+MODULE_AUTHOR("Daniel Gloeckner");
+MODULE_DESCRIPTION("Stretch s6105 IP camera ASoC driver");
+MODULE_LICENSE("GPL");
index 56fa0872abbbb54a2bfd8cfcbb6a579cbd1bc8be..b378096cadb1566e4e6dad55ae94cf7c0f6e9e25 100644 (file)
@@ -145,7 +145,7 @@ static int ssi_hw_params(struct snd_pcm_substream *substream,
        recv = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 0 : 1;
 
        pr_debug("ssi_hw_params() enter\nssicr was    %08lx\n", ssicr);
-       pr_debug("bits: %d channels: %d\n", bits, channels);
+       pr_debug("bits: %u channels: %u\n", bits, channels);
 
        ssicr &= ~(CR_TRMD | CR_CHNL_MASK | CR_DWL_MASK | CR_PDTA |
                   CR_SWL_MASK);
index 1cd149b9ce69e4060c13c1cae1e75115e24c948b..3f44150d8e30b6a9d8f5920e497627b397c0f049 100644 (file)
@@ -113,6 +113,35 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec)
 }
 #endif
 
+static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_card *card = socdev->card;
+       struct snd_soc_dai_link *machine = rtd->dai;
+       struct snd_soc_dai *cpu_dai = machine->cpu_dai;
+       struct snd_soc_dai *codec_dai = machine->codec_dai;
+       int ret;
+
+       if (codec_dai->symmetric_rates || cpu_dai->symmetric_rates ||
+           machine->symmetric_rates) {
+               dev_dbg(card->dev, "Symmetry forces %dHz rate\n", 
+                       machine->rate);
+
+               ret = snd_pcm_hw_constraint_minmax(substream->runtime,
+                                                  SNDRV_PCM_HW_PARAM_RATE,
+                                                  machine->rate,
+                                                  machine->rate);
+               if (ret < 0) {
+                       dev_err(card->dev,
+                               "Unable to apply rate symmetry constraint: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
 /*
  * Called by ALSA when a PCM substream is opened, the runtime->hw record is
  * then initialized and any private data can be allocated. This also calls
@@ -221,6 +250,13 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
                goto machine_err;
        }
 
+       /* Symmetry only applies if we've already got an active stream. */
+       if (cpu_dai->active || codec_dai->active) {
+               ret = soc_pcm_apply_symmetry(substream);
+               if (ret != 0)
+                       goto machine_err;
+       }
+
        pr_debug("asoc: %s <-> %s info:\n", codec_dai->name, cpu_dai->name);
        pr_debug("asoc: rate mask 0x%x\n", runtime->hw.rates);
        pr_debug("asoc: min ch %d max ch %d\n", runtime->hw.channels_min,
@@ -263,7 +299,6 @@ static void close_delayed_work(struct work_struct *work)
 {
        struct snd_soc_card *card = container_of(work, struct snd_soc_card,
                                                 delayed_work.work);
-       struct snd_soc_device *socdev = card->socdev;
        struct snd_soc_codec *codec = card->codec;
        struct snd_soc_dai *codec_dai;
        int i;
@@ -279,27 +314,10 @@ static void close_delayed_work(struct work_struct *work)
 
                /* are we waiting on this codec DAI stream */
                if (codec_dai->pop_wait == 1) {
-
-                       /* Reduce power if no longer active */
-                       if (codec->active == 0) {
-                               pr_debug("pop wq D1 %s %s\n", codec->name,
-                                        codec_dai->playback.stream_name);
-                               snd_soc_dapm_set_bias_level(socdev,
-                                       SND_SOC_BIAS_PREPARE);
-                       }
-
                        codec_dai->pop_wait = 0;
                        snd_soc_dapm_stream_event(codec,
                                codec_dai->playback.stream_name,
                                SND_SOC_DAPM_STREAM_STOP);
-
-                       /* Fall into standby if no longer active */
-                       if (codec->active == 0) {
-                               pr_debug("pop wq D3 %s %s\n", codec->name,
-                                        codec_dai->playback.stream_name);
-                               snd_soc_dapm_set_bias_level(socdev,
-                                       SND_SOC_BIAS_STANDBY);
-                       }
                }
        }
        mutex_unlock(&pcm_mutex);
@@ -363,10 +381,6 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
                snd_soc_dapm_stream_event(codec,
                        codec_dai->capture.stream_name,
                        SND_SOC_DAPM_STREAM_STOP);
-
-               if (codec->active == 0 && codec_dai->pop_wait == 0)
-                       snd_soc_dapm_set_bias_level(socdev,
-                                               SND_SOC_BIAS_STANDBY);
        }
 
        mutex_unlock(&pcm_mutex);
@@ -431,36 +445,16 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
                cancel_delayed_work(&card->delayed_work);
        }
 
-       /* do we need to power up codec */
-       if (codec->bias_level != SND_SOC_BIAS_ON) {
-               snd_soc_dapm_set_bias_level(socdev,
-                                           SND_SOC_BIAS_PREPARE);
-
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       snd_soc_dapm_stream_event(codec,
-                                       codec_dai->playback.stream_name,
-                                       SND_SOC_DAPM_STREAM_START);
-               else
-                       snd_soc_dapm_stream_event(codec,
-                                       codec_dai->capture.stream_name,
-                                       SND_SOC_DAPM_STREAM_START);
-
-               snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_ON);
-               snd_soc_dai_digital_mute(codec_dai, 0);
-
-       } else {
-               /* codec already powered - power on widgets */
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       snd_soc_dapm_stream_event(codec,
-                                       codec_dai->playback.stream_name,
-                                       SND_SOC_DAPM_STREAM_START);
-               else
-                       snd_soc_dapm_stream_event(codec,
-                                       codec_dai->capture.stream_name,
-                                       SND_SOC_DAPM_STREAM_START);
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               snd_soc_dapm_stream_event(codec,
+                                         codec_dai->playback.stream_name,
+                                         SND_SOC_DAPM_STREAM_START);
+       else
+               snd_soc_dapm_stream_event(codec,
+                                         codec_dai->capture.stream_name,
+                                         SND_SOC_DAPM_STREAM_START);
 
-               snd_soc_dai_digital_mute(codec_dai, 0);
-       }
+       snd_soc_dai_digital_mute(codec_dai, 0);
 
 out:
        mutex_unlock(&pcm_mutex);
@@ -521,6 +515,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
                }
        }
 
+       machine->rate = params_rate(params);
+
 out:
        mutex_unlock(&pcm_mutex);
        return ret;
@@ -632,6 +628,12 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state)
        struct snd_soc_codec *codec = card->codec;
        int i;
 
+       /* If the initialization of this soc device failed, there is no codec
+        * associated with it. Just bail out in this case.
+        */
+       if (!codec)
+               return 0;
+
        /* Due to the resume being scheduled into a workqueue we could
        * suspend before that's finished - wait for it to complete.
         */
@@ -1334,6 +1336,7 @@ int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid)
                return ret;
        }
 
+       codec->socdev = socdev;
        codec->card->dev = socdev->dev;
        codec->card->private_data = codec;
        strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver));
@@ -1744,7 +1747,7 @@ int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol,
 {
        int max = kcontrol->private_value;
 
-       if (max == 1)
+       if (max == 1 && !strstr(kcontrol->id.name, " Volume"))
                uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
        else
                uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
@@ -1774,7 +1777,7 @@ int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
        unsigned int shift = mc->shift;
        unsigned int rshift = mc->rshift;
 
-       if (max == 1)
+       if (max == 1 && !strstr(kcontrol->id.name, " Volume"))
                uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
        else
                uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
@@ -1881,7 +1884,7 @@ int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol,
                (struct soc_mixer_control *)kcontrol->private_value;
        int max = mc->max;
 
-       if (max == 1)
+       if (max == 1 && !strstr(kcontrol->id.name, " Volume"))
                uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
        else
                uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
@@ -2065,7 +2068,7 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8);
 int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
        unsigned int freq, int dir)
 {
-       if (dai->ops->set_sysclk)
+       if (dai->ops && dai->ops->set_sysclk)
                return dai->ops->set_sysclk(dai, clk_id, freq, dir);
        else
                return -EINVAL;
@@ -2085,7 +2088,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
 int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
        int div_id, int div)
 {
-       if (dai->ops->set_clkdiv)
+       if (dai->ops && dai->ops->set_clkdiv)
                return dai->ops->set_clkdiv(dai, div_id, div);
        else
                return -EINVAL;
@@ -2104,7 +2107,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv);
 int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
        int pll_id, unsigned int freq_in, unsigned int freq_out)
 {
-       if (dai->ops->set_pll)
+       if (dai->ops && dai->ops->set_pll)
                return dai->ops->set_pll(dai, pll_id, freq_in, freq_out);
        else
                return -EINVAL;
@@ -2120,7 +2123,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll);
  */
 int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-       if (dai->ops->set_fmt)
+       if (dai->ops && dai->ops->set_fmt)
                return dai->ops->set_fmt(dai, fmt);
        else
                return -EINVAL;
@@ -2139,7 +2142,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
 int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
        unsigned int mask, int slots)
 {
-       if (dai->ops->set_sysclk)
+       if (dai->ops && dai->ops->set_tdm_slot)
                return dai->ops->set_tdm_slot(dai, mask, slots);
        else
                return -EINVAL;
@@ -2155,7 +2158,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
  */
 int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
 {
-       if (dai->ops->set_sysclk)
+       if (dai->ops && dai->ops->set_tristate)
                return dai->ops->set_tristate(dai, tristate);
        else
                return -EINVAL;
@@ -2171,7 +2174,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate);
  */
 int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute)
 {
-       if (dai->ops->digital_mute)
+       if (dai->ops && dai->ops->digital_mute)
                return dai->ops->digital_mute(dai, mute);
        else
                return -EINVAL;
@@ -2352,6 +2355,39 @@ void snd_soc_unregister_platform(struct snd_soc_platform *platform)
 }
 EXPORT_SYMBOL_GPL(snd_soc_unregister_platform);
 
+static u64 codec_format_map[] = {
+       SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE,
+       SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE,
+       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE,
+       SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE,
+       SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE,
+       SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE,
+       SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3BE,
+       SNDRV_PCM_FMTBIT_U24_3LE | SNDRV_PCM_FMTBIT_U24_3BE,
+       SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE,
+       SNDRV_PCM_FMTBIT_U20_3LE | SNDRV_PCM_FMTBIT_U20_3BE,
+       SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE,
+       SNDRV_PCM_FMTBIT_U18_3LE | SNDRV_PCM_FMTBIT_U18_3BE,
+       SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE,
+       SNDRV_PCM_FMTBIT_FLOAT64_LE | SNDRV_PCM_FMTBIT_FLOAT64_BE,
+       SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE
+       | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE,
+};
+
+/* Fix up the DAI formats for endianness: codecs don't actually see
+ * the endianness of the data but we're using the CPU format
+ * definitions which do need to include endianness so we ensure that
+ * codec DAIs always have both big and little endian variants set.
+ */
+static void fixup_codec_formats(struct snd_soc_pcm_stream *stream)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(codec_format_map); i++)
+               if (stream->formats & codec_format_map[i])
+                       stream->formats |= codec_format_map[i];
+}
+
 /**
  * snd_soc_register_codec - Register a codec with the ASoC core
  *
@@ -2359,6 +2395,8 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_platform);
  */
 int snd_soc_register_codec(struct snd_soc_codec *codec)
 {
+       int i;
+
        if (!codec->name)
                return -EINVAL;
 
@@ -2368,6 +2406,11 @@ int snd_soc_register_codec(struct snd_soc_codec *codec)
 
        INIT_LIST_HEAD(&codec->list);
 
+       for (i = 0; i < codec->num_dai; i++) {
+               fixup_codec_formats(&codec->dai[i].playback);
+               fixup_codec_formats(&codec->dai[i].capture);
+       }
+
        mutex_lock(&client_mutex);
        list_add(&codec->list, &codec_list);
        snd_soc_instantiate_cards();
index 735903a7467500f4d93d750e527a693d67eabaa2..21c69074aa17a1819f7bb4b95255cafa7c57a433 100644 (file)
@@ -12,7 +12,7 @@
  *  Features:
  *    o Changes power status of internal codec blocks depending on the
  *      dynamic configuration of codec internal audio paths and active
- *      DAC's/ADC's.
+ *      DACs/ADCs.
  *    o Platform power domain - can support external components i.e. amps and
  *      mic/meadphone insertion events.
  *    o Automatic Mic Bias support
 
 /* dapm power sequences - make this per codec in the future */
 static int dapm_up_seq[] = {
-       snd_soc_dapm_pre, snd_soc_dapm_micbias, snd_soc_dapm_mic,
-       snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_dac,
-       snd_soc_dapm_mixer, snd_soc_dapm_mixer_named_ctl, snd_soc_dapm_pga,
-       snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, snd_soc_dapm_post
+       snd_soc_dapm_pre, snd_soc_dapm_supply, snd_soc_dapm_micbias,
+       snd_soc_dapm_mic, snd_soc_dapm_mux, snd_soc_dapm_value_mux,
+       snd_soc_dapm_dac, snd_soc_dapm_mixer, snd_soc_dapm_mixer_named_ctl,
+       snd_soc_dapm_pga, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk,
+       snd_soc_dapm_post
 };
 
 static int dapm_down_seq[] = {
        snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk,
        snd_soc_dapm_pga, snd_soc_dapm_mixer_named_ctl, snd_soc_dapm_mixer,
        snd_soc_dapm_dac, snd_soc_dapm_mic, snd_soc_dapm_micbias,
-       snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_post
+       snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_supply,
+       snd_soc_dapm_post
 };
 
-static int dapm_status = 1;
-module_param(dapm_status, int, 0);
-MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries");
-
 static void pop_wait(u32 pop_time)
 {
        if (pop_time)
@@ -96,6 +94,48 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
        return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
 }
 
+/**
+ * snd_soc_dapm_set_bias_level - set the bias level for the system
+ * @socdev: audio device
+ * @level: level to configure
+ *
+ * Configure the bias (power) levels for the SoC audio device.
+ *
+ * Returns 0 for success else error.
+ */
+static int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
+                                      enum snd_soc_bias_level level)
+{
+       struct snd_soc_card *card = socdev->card;
+       struct snd_soc_codec *codec = socdev->card->codec;
+       int ret = 0;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               dev_dbg(socdev->dev, "Setting full bias\n");
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               dev_dbg(socdev->dev, "Setting bias prepare\n");
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               dev_dbg(socdev->dev, "Setting standby bias\n");
+               break;
+       case SND_SOC_BIAS_OFF:
+               dev_dbg(socdev->dev, "Setting bias off\n");
+               break;
+       default:
+               dev_err(socdev->dev, "Setting invalid bias %d\n", level);
+               return -EINVAL;
+       }
+
+       if (card->set_bias_level)
+               ret = card->set_bias_level(card, level);
+       if (ret == 0 && codec->set_bias_level)
+               ret = codec->set_bias_level(codec, level);
+
+       return ret;
+}
+
 /* set up initial codec paths */
 static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
        struct snd_soc_dapm_path *p, int i)
@@ -165,6 +205,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
        case snd_soc_dapm_dac:
        case snd_soc_dapm_micbias:
        case snd_soc_dapm_vmid:
+       case snd_soc_dapm_supply:
                p->connect = 1;
        break;
        /* does effect routing - dynamically connected */
@@ -179,7 +220,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
        }
 }
 
-/* connect mux widget to it's interconnecting audio paths */
+/* connect mux widget to its interconnecting audio paths */
 static int dapm_connect_mux(struct snd_soc_codec *codec,
        struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
        struct snd_soc_dapm_path *path, const char *control_name,
@@ -202,7 +243,7 @@ static int dapm_connect_mux(struct snd_soc_codec *codec,
        return -ENODEV;
 }
 
-/* connect mixer widget to it's interconnecting audio paths */
+/* connect mixer widget to its interconnecting audio paths */
 static int dapm_connect_mixer(struct snd_soc_codec *codec,
        struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
        struct snd_soc_dapm_path *path, const char *control_name)
@@ -357,8 +398,9 @@ static int dapm_new_mixer(struct snd_soc_codec *codec,
                                path->long_name);
                        ret = snd_ctl_add(codec->card, path->kcontrol);
                        if (ret < 0) {
-                               printk(KERN_ERR "asoc: failed to add dapm kcontrol %s\n",
-                                               path->long_name);
+                               printk(KERN_ERR "asoc: failed to add dapm kcontrol %s: %d\n",
+                                      path->long_name,
+                                      ret);
                                kfree(path->long_name);
                                path->long_name = NULL;
                                return ret;
@@ -434,6 +476,9 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
        struct snd_soc_dapm_path *path;
        int con = 0;
 
+       if (widget->id == snd_soc_dapm_supply)
+               return 0;
+
        if (widget->id == snd_soc_dapm_adc && widget->active)
                return 1;
 
@@ -470,6 +515,9 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
        struct snd_soc_dapm_path *path;
        int con = 0;
 
+       if (widget->id == snd_soc_dapm_supply)
+               return 0;
+
        /* active stream ? */
        if (widget->id == snd_soc_dapm_dac && widget->active)
                return 1;
@@ -521,84 +569,12 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w,
 }
 EXPORT_SYMBOL_GPL(dapm_reg_event);
 
-/*
- * Scan a single DAPM widget for a complete audio path and update the
- * power status appropriately.
+/* Standard power change method, used to apply power changes to most
+ * widgets.
  */
-static int dapm_power_widget(struct snd_soc_codec *codec, int event,
-                            struct snd_soc_dapm_widget *w)
+static int dapm_generic_apply_power(struct snd_soc_dapm_widget *w)
 {
-       int in, out, power_change, power, ret;
-
-       /* vmid - no action */
-       if (w->id == snd_soc_dapm_vmid)
-               return 0;
-
-       /* active ADC */
-       if (w->id == snd_soc_dapm_adc && w->active) {
-               in = is_connected_input_ep(w);
-               dapm_clear_walk(w->codec);
-               w->power = (in != 0) ? 1 : 0;
-               dapm_update_bits(w);
-               return 0;
-       }
-
-       /* active DAC */
-       if (w->id == snd_soc_dapm_dac && w->active) {
-               out = is_connected_output_ep(w);
-               dapm_clear_walk(w->codec);
-               w->power = (out != 0) ? 1 : 0;
-               dapm_update_bits(w);
-               return 0;
-       }
-
-       /* pre and post event widgets */
-       if (w->id == snd_soc_dapm_pre) {
-               if (!w->event)
-                       return 0;
-
-               if (event == SND_SOC_DAPM_STREAM_START) {
-                       ret = w->event(w,
-                                      NULL, SND_SOC_DAPM_PRE_PMU);
-                       if (ret < 0)
-                               return ret;
-               } else if (event == SND_SOC_DAPM_STREAM_STOP) {
-                       ret = w->event(w,
-                                      NULL, SND_SOC_DAPM_PRE_PMD);
-                       if (ret < 0)
-                               return ret;
-               }
-               return 0;
-       }
-       if (w->id == snd_soc_dapm_post) {
-               if (!w->event)
-                       return 0;
-
-               if (event == SND_SOC_DAPM_STREAM_START) {
-                       ret = w->event(w,
-                                      NULL, SND_SOC_DAPM_POST_PMU);
-                       if (ret < 0)
-                               return ret;
-               } else if (event == SND_SOC_DAPM_STREAM_STOP) {
-                       ret = w->event(w,
-                                      NULL, SND_SOC_DAPM_POST_PMD);
-                       if (ret < 0)
-                               return ret;
-               }
-               return 0;
-       }
-
-       /* all other widgets */
-       in = is_connected_input_ep(w);
-       dapm_clear_walk(w->codec);
-       out = is_connected_output_ep(w);
-       dapm_clear_walk(w->codec);
-       power = (out != 0 && in != 0) ? 1 : 0;
-       power_change = (w->power == power) ? 0 : 1;
-       w->power = power;
-
-       if (!power_change)
-               return 0;
+       int ret;
 
        /* call any power change event handlers */
        if (w->event)
@@ -607,7 +583,7 @@ static int dapm_power_widget(struct snd_soc_codec *codec, int event,
                         w->name, w->event_flags);
 
        /* power up pre event */
-       if (power && w->event &&
+       if (w->power && w->event &&
            (w->event_flags & SND_SOC_DAPM_PRE_PMU)) {
                ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMU);
                if (ret < 0)
@@ -615,7 +591,7 @@ static int dapm_power_widget(struct snd_soc_codec *codec, int event,
        }
 
        /* power down pre event */
-       if (!power && w->event &&
+       if (!w->power && w->event &&
            (w->event_flags & SND_SOC_DAPM_PRE_PMD)) {
                ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMD);
                if (ret < 0)
@@ -623,17 +599,17 @@ static int dapm_power_widget(struct snd_soc_codec *codec, int event,
        }
 
        /* Lower PGA volume to reduce pops */
-       if (w->id == snd_soc_dapm_pga && !power)
-               dapm_set_pga(w, power);
+       if (w->id == snd_soc_dapm_pga && !w->power)
+               dapm_set_pga(w, w->power);
 
        dapm_update_bits(w);
 
        /* Raise PGA volume to reduce pops */
-       if (w->id == snd_soc_dapm_pga && power)
-               dapm_set_pga(w, power);
+       if (w->id == snd_soc_dapm_pga && w->power)
+               dapm_set_pga(w, w->power);
 
        /* power up post event */
-       if (power && w->event &&
+       if (w->power && w->event &&
            (w->event_flags & SND_SOC_DAPM_POST_PMU)) {
                ret = w->event(w,
                               NULL, SND_SOC_DAPM_POST_PMU);
@@ -642,7 +618,7 @@ static int dapm_power_widget(struct snd_soc_codec *codec, int event,
        }
 
        /* power down post event */
-       if (!power && w->event &&
+       if (!w->power && w->event &&
            (w->event_flags & SND_SOC_DAPM_POST_PMD)) {
                ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMD);
                if (ret < 0)
@@ -652,6 +628,116 @@ static int dapm_power_widget(struct snd_soc_codec *codec, int event,
        return 0;
 }
 
+/* Generic check to see if a widget should be powered.
+ */
+static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
+{
+       int in, out;
+
+       in = is_connected_input_ep(w);
+       dapm_clear_walk(w->codec);
+       out = is_connected_output_ep(w);
+       dapm_clear_walk(w->codec);
+       return out != 0 && in != 0;
+}
+
+/* Check to see if an ADC has power */
+static int dapm_adc_check_power(struct snd_soc_dapm_widget *w)
+{
+       int in;
+
+       if (w->active) {
+               in = is_connected_input_ep(w);
+               dapm_clear_walk(w->codec);
+               return in != 0;
+       } else {
+               return dapm_generic_check_power(w);
+       }
+}
+
+/* Check to see if a DAC has power */
+static int dapm_dac_check_power(struct snd_soc_dapm_widget *w)
+{
+       int out;
+
+       if (w->active) {
+               out = is_connected_output_ep(w);
+               dapm_clear_walk(w->codec);
+               return out != 0;
+       } else {
+               return dapm_generic_check_power(w);
+       }
+}
+
+/* Check to see if a power supply is needed */
+static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
+{
+       struct snd_soc_dapm_path *path;
+       int power = 0;
+
+       /* Check if one of our outputs is connected */
+       list_for_each_entry(path, &w->sinks, list_source) {
+               if (path->sink && path->sink->power_check &&
+                   path->sink->power_check(path->sink)) {
+                       power = 1;
+                       break;
+               }
+       }
+
+       dapm_clear_walk(w->codec);
+
+       return power;
+}
+
+/*
+ * Scan a single DAPM widget for a complete audio path and update the
+ * power status appropriately.
+ */
+static int dapm_power_widget(struct snd_soc_codec *codec, int event,
+                            struct snd_soc_dapm_widget *w)
+{
+       int ret;
+
+       switch (w->id) {
+       case snd_soc_dapm_pre:
+               if (!w->event)
+                       return 0;
+
+               if (event == SND_SOC_DAPM_STREAM_START) {
+                       ret = w->event(w,
+                                      NULL, SND_SOC_DAPM_PRE_PMU);
+                       if (ret < 0)
+                               return ret;
+               } else if (event == SND_SOC_DAPM_STREAM_STOP) {
+                       ret = w->event(w,
+                                      NULL, SND_SOC_DAPM_PRE_PMD);
+                       if (ret < 0)
+                               return ret;
+               }
+               return 0;
+
+       case snd_soc_dapm_post:
+               if (!w->event)
+                       return 0;
+
+               if (event == SND_SOC_DAPM_STREAM_START) {
+                       ret = w->event(w,
+                                      NULL, SND_SOC_DAPM_POST_PMU);
+                       if (ret < 0)
+                               return ret;
+               } else if (event == SND_SOC_DAPM_STREAM_STOP) {
+                       ret = w->event(w,
+                                      NULL, SND_SOC_DAPM_POST_PMD);
+                       if (ret < 0)
+                               return ret;
+               }
+               return 0;
+
+       default:
+               return dapm_generic_apply_power(w);
+       }
+}
+
 /*
  * Scan each dapm widget for complete audio path.
  * A complete path is a route that has valid endpoints i.e.:-
@@ -663,31 +749,102 @@ static int dapm_power_widget(struct snd_soc_codec *codec, int event,
  */
 static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
 {
+       struct snd_soc_device *socdev = codec->socdev;
        struct snd_soc_dapm_widget *w;
-       int i, c = 1, *seq = NULL, ret = 0;
-
-       /* do we have a sequenced stream event */
-       if (event == SND_SOC_DAPM_STREAM_START) {
-               c = ARRAY_SIZE(dapm_up_seq);
-               seq = dapm_up_seq;
-       } else if (event == SND_SOC_DAPM_STREAM_STOP) {
-               c = ARRAY_SIZE(dapm_down_seq);
-               seq = dapm_down_seq;
+       int ret = 0;
+       int i, power;
+       int sys_power = 0;
+
+       INIT_LIST_HEAD(&codec->up_list);
+       INIT_LIST_HEAD(&codec->down_list);
+
+       /* Check which widgets we need to power and store them in
+        * lists indicating if they should be powered up or down.
+        */
+       list_for_each_entry(w, &codec->dapm_widgets, list) {
+               switch (w->id) {
+               case snd_soc_dapm_pre:
+                       list_add_tail(&codec->down_list, &w->power_list);
+                       break;
+               case snd_soc_dapm_post:
+                       list_add_tail(&codec->up_list, &w->power_list);
+                       break;
+
+               default:
+                       if (!w->power_check)
+                               continue;
+
+                       power = w->power_check(w);
+                       if (power)
+                               sys_power = 1;
+
+                       if (w->power == power)
+                               continue;
+
+                       if (power)
+                               list_add_tail(&w->power_list, &codec->up_list);
+                       else
+                               list_add_tail(&w->power_list,
+                                             &codec->down_list);
+
+                       w->power = power;
+                       break;
+               }
        }
 
-       for (i = 0; i < c; i++) {
-               list_for_each_entry(w, &codec->dapm_widgets, list) {
+       /* If we're changing to all on or all off then prepare */
+       if ((sys_power && codec->bias_level == SND_SOC_BIAS_STANDBY) ||
+           (!sys_power && codec->bias_level == SND_SOC_BIAS_ON)) {
+               ret = snd_soc_dapm_set_bias_level(socdev,
+                                                 SND_SOC_BIAS_PREPARE);
+               if (ret != 0)
+                       pr_err("Failed to prepare bias: %d\n", ret);
+       }
 
+       /* Power down widgets first; try to avoid amplifying pops. */
+       for (i = 0; i < ARRAY_SIZE(dapm_down_seq); i++) {
+               list_for_each_entry(w, &codec->down_list, power_list) {
                        /* is widget in stream order */
-                       if (seq && seq[i] && w->id != seq[i])
+                       if (w->id != dapm_down_seq[i])
                                continue;
 
                        ret = dapm_power_widget(codec, event, w);
                        if (ret != 0)
-                               return ret;
+                               pr_err("Failed to power down %s: %d\n",
+                                      w->name, ret);
                }
        }
 
+       /* Now power up. */
+       for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) {
+               list_for_each_entry(w, &codec->up_list, power_list) {
+                       /* is widget in stream order */
+                       if (w->id != dapm_up_seq[i])
+                               continue;
+
+                       ret = dapm_power_widget(codec, event, w);
+                       if (ret != 0)
+                               pr_err("Failed to power up %s: %d\n",
+                                      w->name, ret);
+               }
+       }
+
+       /* If we just powered the last thing off drop to standby bias */
+       if (codec->bias_level == SND_SOC_BIAS_PREPARE && !sys_power) {
+               ret = snd_soc_dapm_set_bias_level(socdev,
+                                                 SND_SOC_BIAS_STANDBY);
+               if (ret != 0)
+                       pr_err("Failed to apply standby bias: %d\n", ret);
+       }
+
+       /* If we just powered up then move to active bias */
+       if (codec->bias_level == SND_SOC_BIAS_PREPARE && sys_power) {
+               ret = snd_soc_dapm_set_bias_level(socdev,
+                                                 SND_SOC_BIAS_ON);
+               if (ret != 0)
+                       pr_err("Failed to apply active bias: %d\n", ret);
+       }
+
        return 0;
 }
 
@@ -723,6 +880,7 @@ static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action)
                case snd_soc_dapm_pga:
                case snd_soc_dapm_mixer:
                case snd_soc_dapm_mixer_named_ctl:
+               case snd_soc_dapm_supply:
                        if (w->name) {
                                in = is_connected_input_ep(w);
                                dapm_clear_walk(w->codec);
@@ -851,6 +1009,7 @@ static ssize_t dapm_widget_show(struct device *dev,
                case snd_soc_dapm_pga:
                case snd_soc_dapm_mixer:
                case snd_soc_dapm_mixer_named_ctl:
+               case snd_soc_dapm_supply:
                        if (w->name)
                                count += sprintf(buf + count, "%s: %s\n",
                                        w->name, w->power ? "On":"Off");
@@ -883,16 +1042,12 @@ static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
 
 int snd_soc_dapm_sys_add(struct device *dev)
 {
-       if (!dapm_status)
-               return 0;
        return device_create_file(dev, &dev_attr_dapm_widget);
 }
 
 static void snd_soc_dapm_sys_remove(struct device *dev)
 {
-       if (dapm_status) {
-               device_remove_file(dev, &dev_attr_dapm_widget);
-       }
+       device_remove_file(dev, &dev_attr_dapm_widget);
 }
 
 /* free all dapm widgets and resources */
@@ -1015,6 +1170,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
        case snd_soc_dapm_vmid:
        case snd_soc_dapm_pre:
        case snd_soc_dapm_post:
+       case snd_soc_dapm_supply:
                list_add(&path->list, &codec->dapm_paths);
                list_add(&path->list_sink, &wsink->sources);
                list_add(&path->list_source, &wsource->sinks);
@@ -1108,15 +1264,22 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec)
                case snd_soc_dapm_switch:
                case snd_soc_dapm_mixer:
                case snd_soc_dapm_mixer_named_ctl:
+                       w->power_check = dapm_generic_check_power;
                        dapm_new_mixer(codec, w);
                        break;
                case snd_soc_dapm_mux:
                case snd_soc_dapm_value_mux:
+                       w->power_check = dapm_generic_check_power;
                        dapm_new_mux(codec, w);
                        break;
                case snd_soc_dapm_adc:
+                       w->power_check = dapm_adc_check_power;
+                       break;
                case snd_soc_dapm_dac:
+                       w->power_check = dapm_dac_check_power;
+                       break;
                case snd_soc_dapm_pga:
+                       w->power_check = dapm_generic_check_power;
                        dapm_new_pga(codec, w);
                        break;
                case snd_soc_dapm_input:
@@ -1126,6 +1289,10 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec)
                case snd_soc_dapm_hp:
                case snd_soc_dapm_mic:
                case snd_soc_dapm_line:
+                       w->power_check = dapm_generic_check_power;
+                       break;
+               case snd_soc_dapm_supply:
+                       w->power_check = dapm_supply_check_power;
                case snd_soc_dapm_vmid:
                case snd_soc_dapm_pre:
                case snd_soc_dapm_post:
@@ -1625,36 +1792,12 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec,
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);
 
-/**
- * snd_soc_dapm_set_bias_level - set the bias level for the system
- * @socdev: audio device
- * @level: level to configure
- *
- * Configure the bias (power) levels for the SoC audio device.
- *
- * Returns 0 for success else error.
- */
-int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
-                               enum snd_soc_bias_level level)
-{
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_codec *codec = socdev->card->codec;
-       int ret = 0;
-
-       if (card->set_bias_level)
-               ret = card->set_bias_level(card, level);
-       if (ret == 0 && codec->set_bias_level)
-               ret = codec->set_bias_level(codec, level);
-
-       return ret;
-}
-
 /**
  * snd_soc_dapm_enable_pin - enable pin.
  * @codec: SoC codec
  * @pin: pin name
  *
- * Enables input/output pin and it's parents or children widgets iff there is
+ * Enables input/output pin and its parents or children widgets iff there is
  * a valid audio route and active audio stream.
  * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
  * do any widget power switching.
@@ -1670,7 +1813,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
  * @codec: SoC codec
  * @pin: pin name
  *
- * Disables input/output pin and it's parents or children widgets.
+ * Disables input/output pin and its parents or children widgets.
  * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
  * do any widget power switching.
  */
diff --git a/sound/soc/txx9/Kconfig b/sound/soc/txx9/Kconfig
new file mode 100644 (file)
index 0000000..ebc9327
--- /dev/null
@@ -0,0 +1,29 @@
+##
+## TXx9 ACLC
+##
+config SND_SOC_TXX9ACLC
+       tristate "SoC Audio for TXx9"
+       depends on HAS_TXX9_ACLC && TXX9_DMAC
+       help
+         This option enables support for the AC Link Controllers in TXx9 SoC.
+
+config HAS_TXX9_ACLC
+       bool
+
+config SND_SOC_TXX9ACLC_AC97
+       tristate
+       select AC97_BUS
+       select SND_AC97_CODEC
+       select SND_SOC_AC97_BUS
+
+
+##
+## Boards
+##
+config SND_SOC_TXX9ACLC_GENERIC
+       tristate "Generic TXx9 ACLC sound machine"
+       depends on SND_SOC_TXX9ACLC
+       select SND_SOC_TXX9ACLC_AC97
+       select SND_SOC_AC97_CODEC
+       help
+         This is a generic AC97 sound machine for use in TXx9 based systems.
diff --git a/sound/soc/txx9/Makefile b/sound/soc/txx9/Makefile
new file mode 100644 (file)
index 0000000..551f16c
--- /dev/null
@@ -0,0 +1,11 @@
+# Platform
+snd-soc-txx9aclc-objs := txx9aclc.o
+snd-soc-txx9aclc-ac97-objs := txx9aclc-ac97.o
+
+obj-$(CONFIG_SND_SOC_TXX9ACLC) += snd-soc-txx9aclc.o
+obj-$(CONFIG_SND_SOC_TXX9ACLC_AC97) += snd-soc-txx9aclc-ac97.o
+
+# Machine
+snd-soc-txx9aclc-generic-objs := txx9aclc-generic.o
+
+obj-$(CONFIG_SND_SOC_TXX9ACLC_GENERIC) += snd-soc-txx9aclc-generic.o
diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c
new file mode 100644 (file)
index 0000000..0f83bdb
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * TXx9 ACLC AC97 driver
+ *
+ * Copyright (C) 2009 Atsushi Nemoto
+ *
+ * Based on RBTX49xx patch from CELF patch archive.
+ * (C) Copyright TOSHIBA CORPORATION 2004-2006
+ *
+ * This 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/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include "txx9aclc.h"
+
+#define AC97_DIR       \
+       (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE)
+
+#define AC97_RATES     \
+       SNDRV_PCM_RATE_8000_48000
+
+#ifdef __BIG_ENDIAN
+#define AC97_FMTS      SNDRV_PCM_FMTBIT_S16_BE
+#else
+#define AC97_FMTS      SNDRV_PCM_FMTBIT_S16_LE
+#endif
+
+static DECLARE_WAIT_QUEUE_HEAD(ac97_waitq);
+
+/* REVISIT: How to find txx9aclc_soc_device from snd_ac97? */
+static struct txx9aclc_soc_device *txx9aclc_soc_dev;
+
+static int txx9aclc_regready(struct txx9aclc_soc_device *dev)
+{
+       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+
+       return __raw_readl(drvdata->base + ACINTSTS) & ACINT_REGACCRDY;
+}
+
+/* AC97 controller reads codec register */
+static unsigned short txx9aclc_ac97_read(struct snd_ac97 *ac97,
+                                        unsigned short reg)
+{
+       struct txx9aclc_soc_device *dev = txx9aclc_soc_dev;
+       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+       void __iomem *base = drvdata->base;
+       u32 dat;
+
+       if (!(__raw_readl(base + ACINTSTS) & ACINT_CODECRDY(ac97->num)))
+               return 0xffff;
+       reg |= ac97->num << 7;
+       dat = (reg << ACREGACC_REG_SHIFT) | ACREGACC_READ;
+       __raw_writel(dat, base + ACREGACC);
+       __raw_writel(ACINT_REGACCRDY, base + ACINTEN);
+       if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(dev), HZ)) {
+               __raw_writel(ACINT_REGACCRDY, base + ACINTDIS);
+               dev_err(dev->soc_dev.dev, "ac97 read timeout (reg %#x)\n", reg);
+               dat = 0xffff;
+               goto done;
+       }
+       dat = __raw_readl(base + ACREGACC);
+       if (((dat >> ACREGACC_REG_SHIFT) & 0xff) != reg) {
+               dev_err(dev->soc_dev.dev, "reg mismatch %x with %x\n",
+                       dat, reg);
+               dat = 0xffff;
+               goto done;
+       }
+       dat = (dat >> ACREGACC_DAT_SHIFT) & 0xffff;
+done:
+       __raw_writel(ACINT_REGACCRDY, base + ACINTDIS);
+       return dat;
+}
+
+/* AC97 controller writes to codec register */
+static void txx9aclc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+                               unsigned short val)
+{
+       struct txx9aclc_soc_device *dev = txx9aclc_soc_dev;
+       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+       void __iomem *base = drvdata->base;
+
+       __raw_writel(((reg | (ac97->num << 7)) << ACREGACC_REG_SHIFT) |
+                    (val << ACREGACC_DAT_SHIFT),
+                    base + ACREGACC);
+       __raw_writel(ACINT_REGACCRDY, base + ACINTEN);
+       if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(dev), HZ)) {
+               dev_err(dev->soc_dev.dev,
+                       "ac97 write timeout (reg %#x)\n", reg);
+       }
+       __raw_writel(ACINT_REGACCRDY, base + ACINTDIS);
+}
+
+static void txx9aclc_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+       struct txx9aclc_soc_device *dev = txx9aclc_soc_dev;
+       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+       void __iomem *base = drvdata->base;
+       u32 ready = ACINT_CODECRDY(ac97->num) | ACINT_REGACCRDY;
+
+       __raw_writel(ACCTL_ENLINK, base + ACCTLDIS);
+       mmiowb();
+       udelay(1);
+       __raw_writel(ACCTL_ENLINK, base + ACCTLEN);
+       /* wait for primary codec ready status */
+       __raw_writel(ready, base + ACINTEN);
+       if (!wait_event_timeout(ac97_waitq,
+                               (__raw_readl(base + ACINTSTS) & ready) == ready,
+                               HZ)) {
+               dev_err(&ac97->dev, "primary codec is not ready "
+                       "(status %#x)\n",
+                       __raw_readl(base + ACINTSTS));
+       }
+       __raw_writel(ACINT_REGACCRDY, base + ACINTSTS);
+       __raw_writel(ready, base + ACINTDIS);
+}
+
+/* AC97 controller operations */
+struct snd_ac97_bus_ops soc_ac97_ops = {
+       .read           = txx9aclc_ac97_read,
+       .write          = txx9aclc_ac97_write,
+       .reset          = txx9aclc_ac97_cold_reset,
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+static irqreturn_t txx9aclc_ac97_irq(int irq, void *dev_id)
+{
+       struct txx9aclc_plat_drvdata *drvdata = dev_id;
+       void __iomem *base = drvdata->base;
+
+       __raw_writel(__raw_readl(base + ACINTMSTS), base + ACINTDIS);
+       wake_up(&ac97_waitq);
+       return IRQ_HANDLED;
+}
+
+static int txx9aclc_ac97_probe(struct platform_device *pdev,
+                              struct snd_soc_dai *dai)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct txx9aclc_soc_device *dev =
+               container_of(socdev, struct txx9aclc_soc_device, soc_dev);
+
+       dev->aclc_pdev = to_platform_device(dai->dev);
+       txx9aclc_soc_dev = dev;
+       return 0;
+}
+
+static void txx9aclc_ac97_remove(struct platform_device *pdev,
+                                struct snd_soc_dai *dai)
+{
+       struct platform_device *aclc_pdev = to_platform_device(dai->dev);
+       struct txx9aclc_plat_drvdata *drvdata = platform_get_drvdata(aclc_pdev);
+
+       /* disable AC-link */
+       __raw_writel(ACCTL_ENLINK, drvdata->base + ACCTLDIS);
+       txx9aclc_soc_dev = NULL;
+}
+
+struct snd_soc_dai txx9aclc_ac97_dai = {
+       .name                   = "txx9aclc_ac97",
+       .ac97_control           = 1,
+       .probe                  = txx9aclc_ac97_probe,
+       .remove                 = txx9aclc_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,
+       },
+};
+EXPORT_SYMBOL_GPL(txx9aclc_ac97_dai);
+
+static int __devinit txx9aclc_ac97_dev_probe(struct platform_device *pdev)
+{
+       struct txx9aclc_plat_drvdata *drvdata;
+       struct resource *r;
+       int err;
+       int irq;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r)
+               return -EBUSY;
+
+       if (!devm_request_mem_region(&pdev->dev, r->start, resource_size(r),
+                                    dev_name(&pdev->dev)))
+               return -EBUSY;
+
+       drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
+       if (!drvdata)
+               return -ENOMEM;
+       platform_set_drvdata(pdev, drvdata);
+       drvdata->physbase = r->start;
+       if (sizeof(drvdata->physbase) > sizeof(r->start) &&
+           r->start >= TXX9_DIRECTMAP_BASE &&
+           r->start < TXX9_DIRECTMAP_BASE + 0x400000)
+               drvdata->physbase |= 0xf00000000ull;
+       drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
+       if (!drvdata->base)
+               return -EBUSY;
+       err = devm_request_irq(&pdev->dev, irq, txx9aclc_ac97_irq,
+                              IRQF_DISABLED, dev_name(&pdev->dev), drvdata);
+       if (err < 0)
+               return err;
+
+       txx9aclc_ac97_dai.dev = &pdev->dev;
+       return snd_soc_register_dai(&txx9aclc_ac97_dai);
+}
+
+static int __devexit txx9aclc_ac97_dev_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_dai(&txx9aclc_ac97_dai);
+       return 0;
+}
+
+static struct platform_driver txx9aclc_ac97_driver = {
+       .probe          = txx9aclc_ac97_dev_probe,
+       .remove         = __devexit_p(txx9aclc_ac97_dev_remove),
+       .driver         = {
+               .name   = "txx9aclc-ac97",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init txx9aclc_ac97_init(void)
+{
+       return platform_driver_register(&txx9aclc_ac97_driver);
+}
+
+static void __exit txx9aclc_ac97_exit(void)
+{
+       platform_driver_unregister(&txx9aclc_ac97_driver);
+}
+
+module_init(txx9aclc_ac97_init);
+module_exit(txx9aclc_ac97_exit);
+
+MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
+MODULE_DESCRIPTION("TXx9 ACLC AC97 driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/txx9/txx9aclc-generic.c b/sound/soc/txx9/txx9aclc-generic.c
new file mode 100644 (file)
index 0000000..3175de9
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Generic TXx9 ACLC machine driver
+ *
+ * Copyright (C) 2009 Atsushi Nemoto
+ *
+ * Based on RBTX49xx patch from CELF patch archive.
+ * (C) Copyright TOSHIBA CORPORATION 2004-2006
+ *
+ * This 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 is a very generic AC97 sound machine driver for boards which
+ * have (AC97) audio at ACLC (e.g. RBTX49XX boards).
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include "../codecs/ac97.h"
+#include "txx9aclc.h"
+
+static struct snd_soc_dai_link txx9aclc_generic_dai = {
+       .name = "AC97",
+       .stream_name = "AC97 HiFi",
+       .cpu_dai = &txx9aclc_ac97_dai,
+       .codec_dai = &ac97_dai,
+};
+
+static struct snd_soc_card txx9aclc_generic_card = {
+       .name           = "Generic TXx9 ACLC Audio",
+       .platform       = &txx9aclc_soc_platform,
+       .dai_link       = &txx9aclc_generic_dai,
+       .num_links      = 1,
+};
+
+static struct txx9aclc_soc_device txx9aclc_generic_soc_device = {
+       .soc_dev = {
+               .card           = &txx9aclc_generic_card,
+               .codec_dev      = &soc_codec_dev_ac97,
+       },
+};
+
+static int __init txx9aclc_generic_probe(struct platform_device *pdev)
+{
+       struct txx9aclc_soc_device *dev = &txx9aclc_generic_soc_device;
+       struct platform_device *soc_pdev;
+       int ret;
+
+       soc_pdev = platform_device_alloc("soc-audio", -1);
+       if (!soc_pdev)
+               return -ENOMEM;
+       platform_set_drvdata(soc_pdev, &dev->soc_dev);
+       dev->soc_dev.dev = &soc_pdev->dev;
+       ret = platform_device_add(soc_pdev);
+       if (ret) {
+               platform_device_put(soc_pdev);
+               return ret;
+       }
+       platform_set_drvdata(pdev, soc_pdev);
+       return 0;
+}
+
+static int __exit txx9aclc_generic_remove(struct platform_device *pdev)
+{
+       struct platform_device *soc_pdev = platform_get_drvdata(pdev);
+
+       platform_device_unregister(soc_pdev);
+       return 0;
+}
+
+static struct platform_driver txx9aclc_generic_driver = {
+       .remove = txx9aclc_generic_remove,
+       .driver = {
+               .name = "txx9aclc-generic",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init txx9aclc_generic_init(void)
+{
+       return platform_driver_probe(&txx9aclc_generic_driver,
+                                    txx9aclc_generic_probe);
+}
+
+static void __exit txx9aclc_generic_exit(void)
+{
+       platform_driver_unregister(&txx9aclc_generic_driver);
+}
+
+module_init(txx9aclc_generic_init);
+module_exit(txx9aclc_generic_exit);
+
+MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
+MODULE_DESCRIPTION("Generic TXx9 ACLC ALSA SoC audio driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c
new file mode 100644 (file)
index 0000000..fa33661
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ * Generic TXx9 ACLC platform driver
+ *
+ * Copyright (C) 2009 Atsushi Nemoto
+ *
+ * Based on RBTX49xx patch from CELF patch archive.
+ * (C) Copyright TOSHIBA CORPORATION 2004-2006
+ *
+ * This 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/platform_device.h>
+#include <linux/scatterlist.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "txx9aclc.h"
+
+static const struct snd_pcm_hardware txx9aclc_pcm_hardware = {
+       /*
+        * REVISIT: SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID
+        * needs more works for noncoherent MIPS.
+        */
+       .info             = SNDRV_PCM_INFO_INTERLEAVED |
+                           SNDRV_PCM_INFO_BATCH |
+                           SNDRV_PCM_INFO_PAUSE,
+#ifdef __BIG_ENDIAN
+       .formats          = SNDRV_PCM_FMTBIT_S16_BE,
+#else
+       .formats          = SNDRV_PCM_FMTBIT_S16_LE,
+#endif
+       .period_bytes_min = 1024,
+       .period_bytes_max = 8 * 1024,
+       .periods_min      = 2,
+       .periods_max      = 4096,
+       .buffer_bytes_max = 32 * 1024,
+};
+
+static int txx9aclc_pcm_hw_params(struct snd_pcm_substream *substream,
+                                 struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct txx9aclc_dmadata *dmadata = runtime->private_data;
+       int ret;
+
+       ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+       if (ret < 0)
+               return ret;
+
+       dev_dbg(socdev->dev,
+               "runtime->dma_area = %#lx dma_addr = %#lx dma_bytes = %zd "
+               "runtime->min_align %ld\n",
+               (unsigned long)runtime->dma_area,
+               (unsigned long)runtime->dma_addr, runtime->dma_bytes,
+               runtime->min_align);
+       dev_dbg(socdev->dev,
+               "periods %d period_bytes %d stream %d\n",
+               params_periods(params), params_period_bytes(params),
+               substream->stream);
+
+       dmadata->substream = substream;
+       dmadata->pos = 0;
+       return 0;
+}
+
+static int txx9aclc_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static int txx9aclc_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct txx9aclc_dmadata *dmadata = runtime->private_data;
+
+       dmadata->dma_addr = runtime->dma_addr;
+       dmadata->buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
+       dmadata->period_bytes = snd_pcm_lib_period_bytes(substream);
+
+       if (dmadata->buffer_bytes == dmadata->period_bytes) {
+               dmadata->frag_bytes = dmadata->period_bytes >> 1;
+               dmadata->frags = 2;
+       } else {
+               dmadata->frag_bytes = dmadata->period_bytes;
+               dmadata->frags = dmadata->buffer_bytes / dmadata->period_bytes;
+       }
+       dmadata->frag_count = 0;
+       dmadata->pos = 0;
+       return 0;
+}
+
+static void txx9aclc_dma_complete(void *arg)
+{
+       struct txx9aclc_dmadata *dmadata = arg;
+       unsigned long flags;
+
+       /* dma completion handler cannot submit new operations */
+       spin_lock_irqsave(&dmadata->dma_lock, flags);
+       if (dmadata->frag_count >= 0) {
+               dmadata->dmacount--;
+               BUG_ON(dmadata->dmacount < 0);
+               tasklet_schedule(&dmadata->tasklet);
+       }
+       spin_unlock_irqrestore(&dmadata->dma_lock, flags);
+}
+
+static struct dma_async_tx_descriptor *
+txx9aclc_dma_submit(struct txx9aclc_dmadata *dmadata, dma_addr_t buf_dma_addr)
+{
+       struct dma_chan *chan = dmadata->dma_chan;
+       struct dma_async_tx_descriptor *desc;
+       struct scatterlist sg;
+
+       sg_init_table(&sg, 1);
+       sg_set_page(&sg, pfn_to_page(PFN_DOWN(buf_dma_addr)),
+                   dmadata->frag_bytes, buf_dma_addr & (PAGE_SIZE - 1));
+       sg_dma_address(&sg) = buf_dma_addr;
+       desc = chan->device->device_prep_slave_sg(chan, &sg, 1,
+               dmadata->substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+               DMA_TO_DEVICE : DMA_FROM_DEVICE,
+               DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!desc) {
+               dev_err(&chan->dev->device, "cannot prepare slave dma\n");
+               return NULL;
+       }
+       desc->callback = txx9aclc_dma_complete;
+       desc->callback_param = dmadata;
+       desc->tx_submit(desc);
+       return desc;
+}
+
+#define NR_DMA_CHAIN           2
+
+static void txx9aclc_dma_tasklet(unsigned long data)
+{
+       struct txx9aclc_dmadata *dmadata = (struct txx9aclc_dmadata *)data;
+       struct dma_chan *chan = dmadata->dma_chan;
+       struct dma_async_tx_descriptor *desc;
+       struct snd_pcm_substream *substream = dmadata->substream;
+       u32 ctlbit = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+               ACCTL_AUDODMA : ACCTL_AUDIDMA;
+       int i;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dmadata->dma_lock, flags);
+       if (dmadata->frag_count < 0) {
+               struct txx9aclc_soc_device *dev =
+                       container_of(dmadata, struct txx9aclc_soc_device,
+                                    dmadata[substream->stream]);
+               struct txx9aclc_plat_drvdata *drvdata =
+                       txx9aclc_get_plat_drvdata(dev);
+               void __iomem *base = drvdata->base;
+
+               spin_unlock_irqrestore(&dmadata->dma_lock, flags);
+               chan->device->device_terminate_all(chan);
+               /* first time */
+               for (i = 0; i < NR_DMA_CHAIN; i++) {
+                       desc = txx9aclc_dma_submit(dmadata,
+                               dmadata->dma_addr + i * dmadata->frag_bytes);
+                       if (!desc)
+                               return;
+               }
+               dmadata->dmacount = NR_DMA_CHAIN;
+               chan->device->device_issue_pending(chan);
+               spin_lock_irqsave(&dmadata->dma_lock, flags);
+               __raw_writel(ctlbit, base + ACCTLEN);
+               dmadata->frag_count = NR_DMA_CHAIN % dmadata->frags;
+               spin_unlock_irqrestore(&dmadata->dma_lock, flags);
+               return;
+       }
+       BUG_ON(dmadata->dmacount >= NR_DMA_CHAIN);
+       while (dmadata->dmacount < NR_DMA_CHAIN) {
+               dmadata->dmacount++;
+               spin_unlock_irqrestore(&dmadata->dma_lock, flags);
+               desc = txx9aclc_dma_submit(dmadata,
+                       dmadata->dma_addr +
+                       dmadata->frag_count * dmadata->frag_bytes);
+               if (!desc)
+                       return;
+               chan->device->device_issue_pending(chan);
+
+               spin_lock_irqsave(&dmadata->dma_lock, flags);
+               dmadata->frag_count++;
+               dmadata->frag_count %= dmadata->frags;
+               dmadata->pos += dmadata->frag_bytes;
+               dmadata->pos %= dmadata->buffer_bytes;
+               if ((dmadata->frag_count * dmadata->frag_bytes) %
+                   dmadata->period_bytes == 0)
+                       snd_pcm_period_elapsed(substream);
+       }
+       spin_unlock_irqrestore(&dmadata->dma_lock, flags);
+}
+
+static int txx9aclc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct txx9aclc_dmadata *dmadata = substream->runtime->private_data;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct txx9aclc_soc_device *dev =
+               container_of(rtd->socdev, struct txx9aclc_soc_device, soc_dev);
+       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+       void __iomem *base = drvdata->base;
+       unsigned long flags;
+       int ret = 0;
+       u32 ctlbit = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+               ACCTL_AUDODMA : ACCTL_AUDIDMA;
+
+       spin_lock_irqsave(&dmadata->dma_lock, flags);
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               dmadata->frag_count = -1;
+               tasklet_schedule(&dmadata->tasklet);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               __raw_writel(ctlbit, base + ACCTLDIS);
+               break;
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+       case SNDRV_PCM_TRIGGER_RESUME:
+               __raw_writel(ctlbit, base + ACCTLEN);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       spin_unlock_irqrestore(&dmadata->dma_lock, flags);
+       return ret;
+}
+
+static snd_pcm_uframes_t
+txx9aclc_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct txx9aclc_dmadata *dmadata = substream->runtime->private_data;
+
+       return bytes_to_frames(substream->runtime, dmadata->pos);
+}
+
+static int txx9aclc_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct txx9aclc_soc_device *dev =
+               container_of(rtd->socdev, struct txx9aclc_soc_device, soc_dev);
+       struct txx9aclc_dmadata *dmadata = &dev->dmadata[substream->stream];
+       int ret;
+
+       ret = snd_soc_set_runtime_hwparams(substream, &txx9aclc_pcm_hardware);
+       if (ret)
+               return ret;
+       /* ensure that buffer size is a multiple of period size */
+       ret = snd_pcm_hw_constraint_integer(substream->runtime,
+                                           SNDRV_PCM_HW_PARAM_PERIODS);
+       if (ret < 0)
+               return ret;
+       substream->runtime->private_data = dmadata;
+       return 0;
+}
+
+static int txx9aclc_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct txx9aclc_dmadata *dmadata = substream->runtime->private_data;
+       struct dma_chan *chan = dmadata->dma_chan;
+
+       dmadata->frag_count = -1;
+       chan->device->device_terminate_all(chan);
+       return 0;
+}
+
+static struct snd_pcm_ops txx9aclc_pcm_ops = {
+       .open           = txx9aclc_pcm_open,
+       .close          = txx9aclc_pcm_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = txx9aclc_pcm_hw_params,
+       .hw_free        = txx9aclc_pcm_hw_free,
+       .prepare        = txx9aclc_pcm_prepare,
+       .trigger        = txx9aclc_pcm_trigger,
+       .pointer        = txx9aclc_pcm_pointer,
+};
+
+static void txx9aclc_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+       snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static int txx9aclc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
+                           struct snd_pcm *pcm)
+{
+       return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+               card->dev, 64 * 1024, 4 * 1024 * 1024);
+}
+
+static bool filter(struct dma_chan *chan, void *param)
+{
+       struct txx9aclc_dmadata *dmadata = param;
+       char devname[BUS_ID_SIZE + 2];
+
+       sprintf(devname, "%s.%d", dmadata->dma_res->name,
+               (int)dmadata->dma_res->start);
+       if (strcmp(dev_name(chan->device->dev), devname) == 0) {
+               chan->private = &dmadata->dma_slave;
+               return true;
+       }
+       return false;
+}
+
+static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev,
+                            struct txx9aclc_dmadata *dmadata)
+{
+       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+       struct txx9dmac_slave *ds = &dmadata->dma_slave;
+       dma_cap_mask_t mask;
+
+       spin_lock_init(&dmadata->dma_lock);
+
+       ds->reg_width = sizeof(u32);
+       if (dmadata->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               ds->tx_reg = drvdata->physbase + ACAUDODAT;
+               ds->rx_reg = 0;
+       } else {
+               ds->tx_reg = 0;
+               ds->rx_reg = drvdata->physbase + ACAUDIDAT;
+       }
+
+       /* Try to grab a DMA channel */
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+       dmadata->dma_chan = dma_request_channel(mask, filter, dmadata);
+       if (!dmadata->dma_chan) {
+               dev_err(dev->soc_dev.dev,
+                       "DMA channel for %s is not available\n",
+                       dmadata->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+                       "playback" : "capture");
+               return -EBUSY;
+       }
+       tasklet_init(&dmadata->tasklet, txx9aclc_dma_tasklet,
+                    (unsigned long)dmadata);
+       return 0;
+}
+
+static int txx9aclc_pcm_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct txx9aclc_soc_device *dev =
+               container_of(socdev, struct txx9aclc_soc_device, soc_dev);
+       struct resource *r;
+       int i;
+       int ret;
+
+       dev->dmadata[0].stream = SNDRV_PCM_STREAM_PLAYBACK;
+       dev->dmadata[1].stream = SNDRV_PCM_STREAM_CAPTURE;
+       for (i = 0; i < 2; i++) {
+               r = platform_get_resource(dev->aclc_pdev, IORESOURCE_DMA, i);
+               if (!r) {
+                       ret = -EBUSY;
+                       goto exit;
+               }
+               dev->dmadata[i].dma_res = r;
+               ret = txx9aclc_dma_init(dev, &dev->dmadata[i]);
+               if (ret)
+                       goto exit;
+       }
+       return 0;
+
+exit:
+       for (i = 0; i < 2; i++) {
+               if (dev->dmadata[i].dma_chan)
+                       dma_release_channel(dev->dmadata[i].dma_chan);
+               dev->dmadata[i].dma_chan = NULL;
+       }
+       return ret;
+}
+
+static int txx9aclc_pcm_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct txx9aclc_soc_device *dev =
+               container_of(socdev, struct txx9aclc_soc_device, soc_dev);
+       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+       void __iomem *base = drvdata->base;
+       int i;
+
+       /* disable all FIFO DMAs */
+       __raw_writel(ACCTL_AUDODMA | ACCTL_AUDIDMA, base + ACCTLDIS);
+       /* dummy R/W to clear pending DMAREQ if any */
+       __raw_writel(__raw_readl(base + ACAUDIDAT), base + ACAUDODAT);
+
+       for (i = 0; i < 2; i++) {
+               struct txx9aclc_dmadata *dmadata = &dev->dmadata[i];
+               struct dma_chan *chan = dmadata->dma_chan;
+               if (chan) {
+                       dmadata->frag_count = -1;
+                       chan->device->device_terminate_all(chan);
+                       dma_release_channel(chan);
+               }
+               dev->dmadata[i].dma_chan = NULL;
+       }
+       return 0;
+}
+
+struct snd_soc_platform txx9aclc_soc_platform = {
+       .name           = "txx9aclc-audio",
+       .probe          = txx9aclc_pcm_probe,
+       .remove         = txx9aclc_pcm_remove,
+       .pcm_ops        = &txx9aclc_pcm_ops,
+       .pcm_new        = txx9aclc_pcm_new,
+       .pcm_free       = txx9aclc_pcm_free_dma_buffers,
+};
+EXPORT_SYMBOL_GPL(txx9aclc_soc_platform);
+
+static int __init txx9aclc_soc_platform_init(void)
+{
+       return snd_soc_register_platform(&txx9aclc_soc_platform);
+}
+
+static void __exit txx9aclc_soc_platform_exit(void)
+{
+       snd_soc_unregister_platform(&txx9aclc_soc_platform);
+}
+
+module_init(txx9aclc_soc_platform_init);
+module_exit(txx9aclc_soc_platform_exit);
+
+MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
+MODULE_DESCRIPTION("TXx9 ACLC Audio DMA driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/txx9/txx9aclc.h b/sound/soc/txx9/txx9aclc.h
new file mode 100644 (file)
index 0000000..6769aab
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * TXx9 SoC AC Link Controller
+ *
+ * This 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 __TXX9ACLC_H
+#define __TXX9ACLC_H
+
+#include <linux/interrupt.h>
+#include <asm/txx9/dmac.h>
+
+#define ACCTLEN                        0x00    /* control enable */
+#define ACCTLDIS               0x04    /* control disable */
+#define   ACCTL_ENLINK         0x00000001      /* enable/disable AC-link */
+#define   ACCTL_AUDODMA                0x00000100      /* AUDODMA enable/disable */
+#define   ACCTL_AUDIDMA                0x00001000      /* AUDIDMA enable/disable */
+#define   ACCTL_AUDOEHLT       0x00010000      /* AUDO error halt
+                                                  enable/disable */
+#define   ACCTL_AUDIEHLT       0x00100000      /* AUDI error halt
+                                                  enable/disable */
+#define ACREGACC               0x08    /* codec register access */
+#define   ACREGACC_DAT_SHIFT   0       /* data field */
+#define   ACREGACC_REG_SHIFT   16      /* address field */
+#define   ACREGACC_CODECID_SHIFT       24      /* CODEC ID field */
+#define   ACREGACC_READ                0x80000000      /* CODEC read */
+#define   ACREGACC_WRITE       0x00000000      /* CODEC write */
+#define ACINTSTS               0x10    /* interrupt status */
+#define ACINTMSTS              0x14    /* interrupt masked status */
+#define ACINTEN                        0x18    /* interrupt enable */
+#define ACINTDIS               0x1c    /* interrupt disable */
+#define   ACINT_CODECRDY(n)    (0x00000001 << (n))     /* CODECn ready */
+#define   ACINT_REGACCRDY      0x00000010      /* ACREGACC ready */
+#define   ACINT_AUDOERR                0x00000100      /* AUDO underrun error */
+#define   ACINT_AUDIERR                0x00001000      /* AUDI overrun error */
+#define ACDMASTS               0x80    /* DMA request status */
+#define   ACDMA_AUDO           0x00000001      /* AUDODMA pending */
+#define   ACDMA_AUDI           0x00000010      /* AUDIDMA pending */
+#define ACAUDODAT              0xa0    /* audio out data */
+#define ACAUDIDAT              0xb0    /* audio in data */
+#define ACREVID                        0xfc    /* revision ID */
+
+struct txx9aclc_dmadata {
+       struct resource *dma_res;
+       struct txx9dmac_slave dma_slave;
+       struct dma_chan *dma_chan;
+       struct tasklet_struct tasklet;
+       spinlock_t dma_lock;
+       int stream; /* SNDRV_PCM_STREAM_PLAYBACK or SNDRV_PCM_STREAM_CAPTURE */
+       struct snd_pcm_substream *substream;
+       unsigned long pos;
+       dma_addr_t dma_addr;
+       unsigned long buffer_bytes;
+       unsigned long period_bytes;
+       unsigned long frag_bytes;
+       int frags;
+       int frag_count;
+       int dmacount;
+};
+
+struct txx9aclc_plat_drvdata {
+       void __iomem *base;
+       u64 physbase;
+};
+
+struct txx9aclc_soc_device {
+       struct snd_soc_device soc_dev;
+       struct platform_device *aclc_pdev;      /* for ioresources, drvdata */
+       struct txx9aclc_dmadata dmadata[2];
+};
+
+static inline struct txx9aclc_plat_drvdata *txx9aclc_get_plat_drvdata(
+       struct txx9aclc_soc_device *sdev)
+{
+       return platform_get_drvdata(sdev->aclc_pdev);
+}
+
+extern struct snd_soc_platform txx9aclc_soc_platform;
+extern struct snd_soc_dai txx9aclc_ac97_dai;
+
+#endif /* __TXX9ACLC_H */
index e99fd76caa1724a23cfa34185dd6e0890c589fbc..11eb06ac2eca09ce6d80bcc0fec4ba8cfdbb7563 100644 (file)
@@ -5,16 +5,8 @@
 
 snd-util-mem-objs := util_mem.o
 
-#
-# this function returns:
-#   "m" - CONFIG_SND_SEQUENCER is m
-#   <empty string> - CONFIG_SND_SEQUENCER is undefined
-#   otherwise parameter #1 value
-#
-sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
-
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_EMU10K1) += snd-util-mem.o
 obj-$(CONFIG_SND_TRIDENT) += snd-util-mem.o
-obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-util-mem.o
-obj-$(call sequencer,$(CONFIG_SND)) += emux/
+obj-$(CONFIG_SND_SBAWE_SEQ) += snd-util-mem.o
+obj-$(CONFIG_SND_SEQUENCER) += emux/
index b69035240cf68399cb757dc52af65d34007d1801..328594e6152dc4670dcf897829c95ccd1b31986d 100644 (file)
@@ -7,14 +7,6 @@ snd-emux-synth-objs := emux.o emux_synth.o emux_seq.o emux_nrpn.o \
                       emux_effect.o emux_proc.o emux_hwdep.o soundfont.o \
                       $(if $(CONFIG_SND_SEQUENCER_OSS),emux_oss.o)
 
-#
-# this function returns:
-#   "m" - CONFIG_SND_SEQUENCER is m
-#   <empty string> - CONFIG_SND_SEQUENCER is undefined
-#   otherwise parameter #1 value
-#
-sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
-
 # Toplevel Module Dependencies
-obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-emux-synth.o
-obj-$(call sequencer,$(CONFIG_SND_EMU10K1)) += snd-emux-synth.o
+obj-$(CONFIG_SND_SBAWE_SEQ) += snd-emux-synth.o
+obj-$(CONFIG_SND_EMU10K1_SEQ) += snd-emux-synth.o
index b13ce767ac7235314bd8dad23373d640302167ca..b14451342166a7630b820731d131b0536e71b9bd 100644 (file)
        (stream << 1) | (~(i / (dev->n_streams * BYTES_PER_SAMPLE_USB)) & 1)
 
 static struct snd_pcm_hardware snd_usb_caiaq_pcm_hardware = {
-       .info           = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 
+       .info           = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                           SNDRV_PCM_INFO_BLOCK_TRANSFER),
        .formats        = SNDRV_PCM_FMTBIT_S24_3BE,
-       .rates          = (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | 
+       .rates          = (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
                           SNDRV_PCM_RATE_96000),
        .rate_min       = 44100,
        .rate_max       = 0, /* will overwrite later */
@@ -68,7 +68,7 @@ activate_substream(struct snd_usb_caiaqdev *dev,
                dev->sub_capture[sub->number] = sub;
 }
 
-static void 
+static void
 deactivate_substream(struct snd_usb_caiaqdev *dev,
                     struct snd_pcm_substream *sub)
 {
@@ -118,7 +118,7 @@ static int stream_start(struct snd_usb_caiaqdev *dev)
                        return -EPIPE;
                }
        }
-       
+
        return 0;
 }
 
@@ -129,7 +129,7 @@ static void stream_stop(struct snd_usb_caiaqdev *dev)
        debug("%s(%p)\n", __func__, dev);
        if (!dev->streaming)
                return;
-       
+
        dev->streaming = 0;
 
        for (i = 0; i < N_URBS; i++) {
@@ -154,7 +154,7 @@ static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream)
        debug("%s(%p)\n", __func__, substream);
        if (all_substreams_zero(dev->sub_playback) &&
            all_substreams_zero(dev->sub_capture)) {
-               /* when the last client has stopped streaming, 
+               /* when the last client has stopped streaming,
                 * all sample rates are allowed again */
                stream_stop(dev);
                dev->pcm_info.rates = dev->samplerates;
@@ -194,7 +194,7 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime = substream->runtime;
 
        debug("%s(%p)\n", __func__, substream);
-       
+
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                dev->period_out_count[index] = BYTES_PER_SAMPLE + 1;
                dev->audio_out_buf_pos[index] = BYTES_PER_SAMPLE + 1;
@@ -205,19 +205,19 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)
 
        if (dev->streaming)
                return 0;
-       
+
        /* the first client that opens a stream defines the sample rate
         * setting for all subsequent calls, until the last client closed. */
        for (i=0; i < ARRAY_SIZE(rates); i++)
                if (runtime->rate == rates[i])
                        dev->pcm_info.rates = 1 << i;
-       
+
        snd_pcm_limit_hw_rates(runtime);
 
        bytes_per_sample = BYTES_PER_SAMPLE;
        if (dev->spec.data_alignment == 2)
                bytes_per_sample++;
-       
+
        bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE)
                * bytes_per_sample * CHANNELS_PER_STREAM * dev->n_streams;
 
@@ -232,7 +232,7 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)
        ret = stream_start(dev);
        if (ret)
                return ret;
-       
+
        dev->output_running = 0;
        wait_event_timeout(dev->prepare_wait_queue, dev->output_running, HZ);
        if (!dev->output_running) {
@@ -273,7 +273,7 @@ snd_usb_caiaq_pcm_pointer(struct snd_pcm_substream *sub)
                return SNDRV_PCM_POS_XRUN;
 
        if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               return bytes_to_frames(sub->runtime, 
+               return bytes_to_frames(sub->runtime,
                                        dev->audio_out_buf_pos[index]);
        else
                return bytes_to_frames(sub->runtime,
@@ -291,7 +291,7 @@ static struct snd_pcm_ops snd_usb_caiaq_ops = {
        .trigger =      snd_usb_caiaq_pcm_trigger,
        .pointer =      snd_usb_caiaq_pcm_pointer
 };
-       
+
 static void check_for_elapsed_periods(struct snd_usb_caiaqdev *dev,
                                      struct snd_pcm_substream **subs)
 {
@@ -333,7 +333,7 @@ static void read_in_urb_mode0(struct snd_usb_caiaqdev *dev,
                                struct snd_pcm_runtime *rt = sub->runtime;
                                char *audio_buf = rt->dma_area;
                                int sz = frames_to_bytes(rt, rt->buffer_size);
-                               audio_buf[dev->audio_in_buf_pos[stream]++] 
+                               audio_buf[dev->audio_in_buf_pos[stream]++]
                                        = usb_buf[i];
                                dev->period_in_count[stream]++;
                                if (dev->audio_in_buf_pos[stream] == sz)
@@ -354,14 +354,14 @@ static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev,
 
        for (i = 0; i < iso->actual_length;) {
                if (i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == 0) {
-                       for (stream = 0; 
-                            stream < dev->n_streams; 
+                       for (stream = 0;
+                            stream < dev->n_streams;
                             stream++, i++) {
                                if (dev->first_packet)
                                        continue;
 
                                check_byte = MAKE_CHECKBYTE(dev, stream, i);
-                               
+
                                if ((usb_buf[i] & 0x3f) != check_byte)
                                        dev->input_panic = 1;
 
@@ -410,21 +410,21 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev,
        }
 
        if ((dev->input_panic || dev->output_panic) && !dev->warned) {
-               debug("streaming error detected %s %s\n", 
+               debug("streaming error detected %s %s\n",
                                dev->input_panic ? "(input)" : "",
                                dev->output_panic ? "(output)" : "");
                dev->warned = 1;
        }
 }
 
-static void fill_out_urb(struct snd_usb_caiaqdev *dev, 
-                        struct urb *urb, 
+static void fill_out_urb(struct snd_usb_caiaqdev *dev,
+                        struct urb *urb,
                         const struct usb_iso_packet_descriptor *iso)
 {
        unsigned char *usb_buf = urb->transfer_buffer + iso->offset;
        struct snd_pcm_substream *sub;
        int stream, i;
-       
+
        for (i = 0; i < iso->length;) {
                for (stream = 0; stream < dev->n_streams; stream++, i++) {
                        sub = dev->sub_playback[stream];
@@ -444,7 +444,7 @@ static void fill_out_urb(struct snd_usb_caiaqdev *dev,
 
                /* fill in the check bytes */
                if (dev->spec.data_alignment == 2 &&
-                   i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == 
+                   i % (dev->n_streams * BYTES_PER_SAMPLE_USB) ==
                        (dev->n_streams * CHANNELS_PER_STREAM))
                    for (stream = 0; stream < dev->n_streams; stream++, i++)
                        usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i);
@@ -453,7 +453,7 @@ static void fill_out_urb(struct snd_usb_caiaqdev *dev,
 
 static void read_completed(struct urb *urb)
 {
-       struct snd_usb_caiaq_cb_info *info = urb->context; 
+       struct snd_usb_caiaq_cb_info *info = urb->context;
        struct snd_usb_caiaqdev *dev;
        struct urb *out;
        int frame, len, send_it = 0, outframe = 0;
@@ -478,7 +478,7 @@ static void read_completed(struct urb *urb)
                out->iso_frame_desc[outframe].length = len;
                out->iso_frame_desc[outframe].actual_length = 0;
                out->iso_frame_desc[outframe].offset = BYTES_PER_FRAME * frame;
-               
+
                if (len > 0) {
                        spin_lock(&dev->spinlock);
                        fill_out_urb(dev, out, &out->iso_frame_desc[outframe]);
@@ -497,14 +497,14 @@ static void read_completed(struct urb *urb)
                out->transfer_flags = URB_ISO_ASAP;
                usb_submit_urb(out, GFP_ATOMIC);
        }
-       
+
        /* re-submit inbound urb */
        for (frame = 0; frame < FRAMES_PER_URB; frame++) {
                urb->iso_frame_desc[frame].offset = BYTES_PER_FRAME * frame;
                urb->iso_frame_desc[frame].length = BYTES_PER_FRAME;
                urb->iso_frame_desc[frame].actual_length = 0;
        }
-       
+
        urb->number_of_packets = FRAMES_PER_URB;
        urb->transfer_flags = URB_ISO_ASAP;
        usb_submit_urb(urb, GFP_ATOMIC);
@@ -528,7 +528,7 @@ static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret)
        struct usb_device *usb_dev = dev->chip.dev;
        unsigned int pipe;
 
-       pipe = (dir == SNDRV_PCM_STREAM_PLAYBACK) ? 
+       pipe = (dir == SNDRV_PCM_STREAM_PLAYBACK) ?
                usb_sndisocpipe(usb_dev, ENDPOINT_PLAYBACK) :
                usb_rcvisocpipe(usb_dev, ENDPOINT_CAPTURE);
 
@@ -547,25 +547,25 @@ static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret)
                        return urbs;
                }
 
-               urbs[i]->transfer_buffer = 
+               urbs[i]->transfer_buffer =
                        kmalloc(FRAMES_PER_URB * BYTES_PER_FRAME, GFP_KERNEL);
                if (!urbs[i]->transfer_buffer) {
                        log("unable to kmalloc() transfer buffer, OOM!?\n");
                        *ret = -ENOMEM;
                        return urbs;
                }
-               
+
                for (frame = 0; frame < FRAMES_PER_URB; frame++) {
-                       struct usb_iso_packet_descriptor *iso = 
+                       struct usb_iso_packet_descriptor *iso =
                                &urbs[i]->iso_frame_desc[frame];
-                       
+
                        iso->offset = BYTES_PER_FRAME * frame;
                        iso->length = BYTES_PER_FRAME;
                }
-               
+
                urbs[i]->dev = usb_dev;
                urbs[i]->pipe = pipe;
-               urbs[i]->transfer_buffer_length = FRAMES_PER_URB 
+               urbs[i]->transfer_buffer_length = FRAMES_PER_URB
                                                * BYTES_PER_FRAME;
                urbs[i]->context = &dev->data_cb_info[i];
                urbs[i]->interval = 1;
@@ -589,7 +589,7 @@ static void free_urbs(struct urb **urbs)
        for (i = 0; i < N_URBS; i++) {
                if (!urbs[i])
                        continue;
-               
+
                usb_kill_urb(urbs[i]);
                kfree(urbs[i]->transfer_buffer);
                usb_free_urb(urbs[i]);
@@ -602,11 +602,11 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev)
 {
        int i, ret;
 
-       dev->n_audio_in  = max(dev->spec.num_analog_audio_in, 
-                              dev->spec.num_digital_audio_in) / 
+       dev->n_audio_in  = max(dev->spec.num_analog_audio_in,
+                              dev->spec.num_digital_audio_in) /
                                CHANNELS_PER_STREAM;
        dev->n_audio_out = max(dev->spec.num_analog_audio_out,
-                              dev->spec.num_digital_audio_out) / 
+                              dev->spec.num_digital_audio_out) /
                                CHANNELS_PER_STREAM;
        dev->n_streams = max(dev->n_audio_in, dev->n_audio_out);
 
@@ -619,7 +619,7 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev)
                return -EINVAL;
        }
 
-       ret = snd_pcm_new(dev->chip.card, dev->product_name, 0, 
+       ret = snd_pcm_new(dev->chip.card, dev->product_name, 0,
                        dev->n_audio_out, dev->n_audio_in, &dev->pcm);
 
        if (ret < 0) {
@@ -632,7 +632,7 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev)
 
        memset(dev->sub_playback, 0, sizeof(dev->sub_playback));
        memset(dev->sub_capture, 0, sizeof(dev->sub_capture));
-       
+
        memcpy(&dev->pcm_info, &snd_usb_caiaq_pcm_hardware,
                        sizeof(snd_usb_caiaq_pcm_hardware));
 
@@ -651,9 +651,9 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev)
                break;
        }
 
-       snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, 
+       snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK,
                                &snd_usb_caiaq_ops);
-       snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 
+       snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE,
                                &snd_usb_caiaq_ops);
 
        snd_pcm_lib_preallocate_pages_for_all(dev->pcm,
@@ -662,7 +662,7 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev)
                                        MAX_BUFFER_SIZE, MAX_BUFFER_SIZE);
 
        dev->data_cb_info =
-               kmalloc(sizeof(struct snd_usb_caiaq_cb_info) * N_URBS, 
+               kmalloc(sizeof(struct snd_usb_caiaq_cb_info) * N_URBS,
                                        GFP_KERNEL);
 
        if (!dev->data_cb_info)
@@ -672,14 +672,14 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev)
                dev->data_cb_info[i].dev = dev;
                dev->data_cb_info[i].index = i;
        }
-       
+
        dev->data_urbs_in = alloc_urbs(dev, SNDRV_PCM_STREAM_CAPTURE, &ret);
        if (ret < 0) {
                kfree(dev->data_cb_info);
                free_urbs(dev->data_urbs_in);
                return ret;
        }
-       
+
        dev->data_urbs_out = alloc_urbs(dev, SNDRV_PCM_STREAM_PLAYBACK, &ret);
        if (ret < 0) {
                kfree(dev->data_cb_info);
index 515de1cd2a3ecbaf30649cb48deab0a5732be1b2..22406245a98bb9a4a105161e2eceb44d13e44418 100644 (file)
@@ -35,7 +35,7 @@
 #include "input.h"
 
 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
-MODULE_DESCRIPTION("caiaq USB audio, version 1.3.14");
+MODULE_DESCRIPTION("caiaq USB audio, version 1.3.16");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
                         "{Native Instruments, RigKontrol3},"
@@ -79,7 +79,7 @@ static struct usb_device_id snd_usb_id_table[] = {
        {
                .match_flags =  USB_DEVICE_ID_MATCH_DEVICE,
                .idVendor =     USB_VID_NATIVEINSTRUMENTS,
-               .idProduct =    USB_PID_RIGKONTROL2 
+               .idProduct =    USB_PID_RIGKONTROL2
        },
        {
                .match_flags =  USB_DEVICE_ID_MATCH_DEVICE,
@@ -197,7 +197,7 @@ int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *dev,
 
        if (buffer && len > 0)
                memcpy(dev->ep1_out_buf+1, buffer, len);
-       
+
        dev->ep1_out_buf[0] = command;
        return usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, 1),
                           dev->ep1_out_buf, len+1, &actual_len, 200);
@@ -208,7 +208,7 @@ int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev,
 {
        int ret;
        char tmp[5];
-       
+
        switch (rate) {
        case 44100:     tmp[0] = SAMPLERATE_44100;   break;
        case 48000:     tmp[0] = SAMPLERATE_48000;   break;
@@ -237,12 +237,12 @@ int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev,
 
        if (ret)
                return ret;
-       
-       if (!wait_event_timeout(dev->ep1_wait_queue, 
+
+       if (!wait_event_timeout(dev->ep1_wait_queue,
            dev->audio_parm_answer >= 0, HZ))
                return -EPIPE;
-               
-       if (dev->audio_parm_answer != 1) 
+
+       if (dev->audio_parm_answer != 1)
                debug("unable to set the device's audio params\n");
        else
                dev->bpp = bpp;
@@ -250,8 +250,8 @@ int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev,
        return dev->audio_parm_answer == 1 ? 0 : -EINVAL;
 }
 
-int snd_usb_caiaq_set_auto_msg (struct snd_usb_caiaqdev *dev, 
-                               int digital, int analog, int erp)
+int snd_usb_caiaq_set_auto_msg(struct snd_usb_caiaqdev *dev,
+                              int digital, int analog, int erp)
 {
        char tmp[3] = { digital, analog, erp };
        return snd_usb_caiaq_send_command(dev, EP1_CMD_AUTO_MSG,
@@ -262,7 +262,7 @@ static void __devinit setup_card(struct snd_usb_caiaqdev *dev)
 {
        int ret;
        char val[4];
-       
+
        /* device-specific startup specials */
        switch (dev->chip.usb_id) {
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):
@@ -314,7 +314,7 @@ static void __devinit setup_card(struct snd_usb_caiaqdev *dev)
                        dev->control_state, 1);
                break;
        }
-       
+
        if (dev->spec.num_analog_audio_out +
            dev->spec.num_analog_audio_in +
            dev->spec.num_digital_audio_out +
@@ -323,7 +323,7 @@ static void __devinit setup_card(struct snd_usb_caiaqdev *dev)
                if (ret < 0)
                        log("Unable to set up audio system (ret=%d)\n", ret);
        }
-       
+
        if (dev->spec.num_midi_in +
            dev->spec.num_midi_out > 0) {
                ret = snd_usb_caiaq_midi_init(dev);
@@ -363,7 +363,7 @@ static int create_card(struct usb_device* usb_dev, struct snd_card **cardp)
        if (devnum >= SNDRV_CARDS)
                return -ENODEV;
 
-       err = snd_card_create(index[devnum], id[devnum], THIS_MODULE, 
+       err = snd_card_create(index[devnum], id[devnum], THIS_MODULE,
                              sizeof(struct snd_usb_caiaqdev), &card);
        if (err < 0)
                return err;
@@ -382,11 +382,11 @@ static int create_card(struct usb_device* usb_dev, struct snd_card **cardp)
 
 static int __devinit init_card(struct snd_usb_caiaqdev *dev)
 {
-       char *c;
+       char *c, usbpath[32];
        struct usb_device *usb_dev = dev->chip.dev;
        struct snd_card *card = dev->chip.card;
        int err, len;
-       
+
        if (usb_set_interface(usb_dev, 0, 1) != 0) {
                log("can't set alt interface.\n");
                return -EIO;
@@ -395,19 +395,19 @@ static int __devinit init_card(struct snd_usb_caiaqdev *dev)
        usb_init_urb(&dev->ep1_in_urb);
        usb_init_urb(&dev->midi_out_urb);
 
-       usb_fill_bulk_urb(&dev->ep1_in_urb, usb_dev, 
+       usb_fill_bulk_urb(&dev->ep1_in_urb, usb_dev,
                          usb_rcvbulkpipe(usb_dev, 0x1),
-                         dev->ep1_in_buf, EP1_BUFSIZE, 
+                         dev->ep1_in_buf, EP1_BUFSIZE,
                          usb_ep1_command_reply_dispatch, dev);
 
-       usb_fill_bulk_urb(&dev->midi_out_urb, usb_dev, 
+       usb_fill_bulk_urb(&dev->midi_out_urb, usb_dev,
                          usb_sndbulkpipe(usb_dev, 0x1),
-                         dev->midi_out_buf, EP1_BUFSIZE, 
+                         dev->midi_out_buf, EP1_BUFSIZE,
                          snd_usb_caiaq_midi_output_done, dev);
-       
+
        init_waitqueue_head(&dev->ep1_wait_queue);
        init_waitqueue_head(&dev->prepare_wait_queue);
-       
+
        if (usb_submit_urb(&dev->ep1_in_urb, GFP_KERNEL) != 0)
                return -EIO;
 
@@ -420,47 +420,52 @@ static int __devinit init_card(struct snd_usb_caiaqdev *dev)
 
        usb_string(usb_dev, usb_dev->descriptor.iManufacturer,
                   dev->vendor_name, CAIAQ_USB_STR_LEN);
-       
+
        usb_string(usb_dev, usb_dev->descriptor.iProduct,
                   dev->product_name, CAIAQ_USB_STR_LEN);
-       
-       usb_string(usb_dev, usb_dev->descriptor.iSerialNumber,
-                  dev->serial, CAIAQ_USB_STR_LEN);
-
-       /* terminate serial string at first white space occurence */
-       c = strchr(dev->serial, ' ');
-       if (c)
-               *c = '\0';
-       
-       strcpy(card->driver, MODNAME);
-       strcpy(card->shortname, dev->product_name);
-
-       len = snprintf(card->longname, sizeof(card->longname),
-                      "%s %s (serial %s, ",
-                      dev->vendor_name, dev->product_name, dev->serial);
-
-       if (len < sizeof(card->longname) - 2)
-               len += usb_make_path(usb_dev, card->longname + len,
-                                    sizeof(card->longname) - len);
-
-       card->longname[len++] = ')';
-       card->longname[len] = '\0';
+
+       strlcpy(card->driver, MODNAME, sizeof(card->driver));
+       strlcpy(card->shortname, dev->product_name, sizeof(card->shortname));
+       strlcpy(card->mixername, dev->product_name, sizeof(card->mixername));
+
+       /* if the id was not passed as module option, fill it with a shortened
+        * version of the product string which does not contain any
+        * whitespaces */
+
+       if (*card->id == '\0') {
+               char id[sizeof(card->id)];
+
+               memset(id, 0, sizeof(id));
+
+               for (c = card->shortname, len = 0;
+                       *c && len < sizeof(card->id); c++)
+                       if (*c != ' ')
+                               id[len++] = *c;
+
+               snd_card_set_id(card, id);
+       }
+
+       usb_make_path(usb_dev, usbpath, sizeof(usbpath));
+       snprintf(card->longname, sizeof(card->longname),
+                      "%s %s (%s)",
+                      dev->vendor_name, dev->product_name, usbpath);
+
        setup_card(dev);
        return 0;
 }
 
-static int __devinit snd_probe(struct usb_interface *intf, 
+static int __devinit snd_probe(struct usb_interface *intf,
                     const struct usb_device_id *id)
 {
        int ret;
        struct snd_card *card;
        struct usb_device *device = interface_to_usbdev(intf);
-       
+
        ret = create_card(device, &card);
-       
+
        if (ret < 0)
                return ret;
-                       
+
        usb_set_intfdata(intf, card);
        ret = init_card(caiaqdev(card));
        if (ret < 0) {
@@ -468,7 +473,7 @@ static int __devinit snd_probe(struct usb_interface *intf,
                snd_card_free(card);
                return ret;
        }
-       
+
        return 0;
 }
 
@@ -489,10 +494,10 @@ static void snd_disconnect(struct usb_interface *intf)
        snd_usb_caiaq_input_free(dev);
 #endif
        snd_usb_caiaq_audio_free(dev);
-       
+
        usb_kill_urb(&dev->ep1_in_urb);
        usb_kill_urb(&dev->midi_out_urb);
-       
+
        snd_card_free(card);
        usb_reset_device(interface_to_usbdev(intf));
 }
index 4cce1ad7493db4ec138216bb3a56b6ae20fcc90f..ece73514854e2f302ab88da1d1a857d3f43ee3ec 100644 (file)
@@ -81,7 +81,6 @@ struct snd_usb_caiaqdev {
 
        char vendor_name[CAIAQ_USB_STR_LEN];
        char product_name[CAIAQ_USB_STR_LEN];
-       char serial[CAIAQ_USB_STR_LEN];
 
        int n_streams, n_audio_in, n_audio_out;
        int streaming, first_packet, output_running;
index 8fa8cd88d7634689592b7b512d85640a7128de5e..538e8c00d31aadac2c8555df958c1312051265b5 100644 (file)
@@ -40,7 +40,7 @@ static void snd_usb_caiaq_midi_input_trigger(struct snd_rawmidi_substream *subst
 
        if (!dev)
                return;
-       
+
        dev->midi_receive_substream = up ? substream : NULL;
 }
 
@@ -64,18 +64,18 @@ static void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *dev,
                                    struct snd_rawmidi_substream *substream)
 {
        int len, ret;
-       
+
        dev->midi_out_buf[0] = EP1_CMD_MIDI_WRITE;
        dev->midi_out_buf[1] = 0; /* port */
        len = snd_rawmidi_transmit(substream, dev->midi_out_buf + 3,
                                   EP1_BUFSIZE - 3);
-       
+
        if (len <= 0)
                return;
-       
+
        dev->midi_out_buf[2] = len;
        dev->midi_out_urb.transfer_buffer_length = len+3;
-       
+
        ret = usb_submit_urb(&dev->midi_out_urb, GFP_ATOMIC);
        if (ret < 0)
                log("snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed,"
@@ -88,7 +88,7 @@ static void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *dev,
 static void snd_usb_caiaq_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
 {
        struct snd_usb_caiaqdev *dev = substream->rmidi->private_data;
-       
+
        if (up) {
                dev->midi_out_substream = substream;
                if (!dev->midi_out_active)
@@ -113,12 +113,12 @@ static struct snd_rawmidi_ops snd_usb_caiaq_midi_input =
        .trigger =      snd_usb_caiaq_midi_input_trigger,
 };
 
-void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *dev, 
+void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *dev,
                                     int port, const char *buf, int len)
 {
        if (!dev->midi_receive_substream)
                return;
-       
+
        snd_rawmidi_receive(dev->midi_receive_substream, buf, len);
 }
 
@@ -142,16 +142,16 @@ int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device)
 
        if (device->spec.num_midi_out > 0) {
                rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
-               snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, 
+               snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
                                    &snd_usb_caiaq_midi_output);
        }
 
        if (device->spec.num_midi_in > 0) {
                rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
-               snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, 
+               snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
                                    &snd_usb_caiaq_midi_input);
        }
-       
+
        device->rmidi = rmidi;
 
        return 0;
@@ -160,7 +160,7 @@ int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device)
 void snd_usb_caiaq_midi_output_done(struct urb* urb)
 {
        struct snd_usb_caiaqdev *dev = urb->context;
-       
+
        dev->midi_out_active = 0;
        if (urb->status != 0)
                return;
index a6b88482637be9fbdc9b3c0fa56e2293a73ce0ab..c7b902358b7b268a3dd25178639f41009dedf125 100644 (file)
@@ -627,6 +627,7 @@ static int prepare_playback_urb(struct snd_usb_substream *subs,
        subs->hwptr_done += offs;
        if (subs->hwptr_done >= runtime->buffer_size)
                subs->hwptr_done -= runtime->buffer_size;
+       runtime->delay += offs;
        spin_unlock_irqrestore(&subs->lock, flags);
        urb->transfer_buffer_length = offs * stride;
        if (period_elapsed)
@@ -636,12 +637,22 @@ static int prepare_playback_urb(struct snd_usb_substream *subs,
 
 /*
  * process after playback data complete
- * - nothing to do
+ * - decrease the delay count again
  */
 static int retire_playback_urb(struct snd_usb_substream *subs,
                               struct snd_pcm_runtime *runtime,
                               struct urb *urb)
 {
+       unsigned long flags;
+       int stride = runtime->frame_bits >> 3;
+       int processed = urb->transfer_buffer_length / stride;
+
+       spin_lock_irqsave(&subs->lock, flags);
+       if (processed > runtime->delay)
+               runtime->delay = 0;
+       else
+               runtime->delay -= processed;
+       spin_unlock_irqrestore(&subs->lock, flags);
        return 0;
 }
 
@@ -1520,6 +1531,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
        subs->hwptr_done = 0;
        subs->transfer_done = 0;
        subs->phase = 0;
+       runtime->delay = 0;
 
        /* clear urbs (to be sure) */
        deactivate_urbs(subs, 0, 1);
@@ -3279,6 +3291,25 @@ static int snd_usb_cm106_boot_quirk(struct usb_device *dev)
        return snd_usb_cm106_write_int_reg(dev, 2, 0x8004);
 }
 
+/*
+ * C-Media CM6206 is based on CM106 with two additional
+ * registers that are not documented in the data sheet.
+ * Values here are chosen based on sniffing USB traffic
+ * under Windows.
+ */
+static int snd_usb_cm6206_boot_quirk(struct usb_device *dev)
+{
+       int err, reg;
+       int val[] = {0x200c, 0x3000, 0xf800, 0x143f, 0x0000, 0x3000};
+
+       for (reg = 0; reg < ARRAY_SIZE(val); reg++) {
+               err = snd_usb_cm106_write_int_reg(dev, reg, val[reg]);
+               if (err < 0)
+                       return err;
+       }
+
+       return err;
+}
 
 /*
  * Setup quirks
@@ -3565,6 +3596,12 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
                        goto __err_val;
        }
 
+       /* C-Media CM6206 / CM106-Like Sound Device */
+       if (id == USB_ID(0x0d8c, 0x0102)) {
+               if (snd_usb_cm6206_boot_quirk(dev) < 0)
+                       goto __err_val;
+       }
+
        /*
         * found a config.  now register to ALSA
         */
index ecb58e7a6245f5bea88294093628a23c54744643..4bd3a7a0edc100c2dd6007a98f8247b9084b8969 100644 (file)
@@ -423,7 +423,7 @@ static int set_ctl_value(struct usb_mixer_elem_info *cval, int request, int vali
        value_set = convert_bytes_value(cval, value_set);
        buf[0] = value_set & 0xff;
        buf[1] = (value_set >> 8) & 0xff;
-       while (timeout -- > 0)
+       while (timeout-- > 0)
                if (snd_usb_ctl_msg(cval->mixer->chip->dev,
                                    usb_sndctrlpipe(cval->mixer->chip->dev, 0),
                                    request,
index 5d955aaad85f9a5d2ac96a990e97972a00e48905..f0f7624f91781efd574a883b78da048b5f9dbafb 100644 (file)
@@ -1469,6 +1469,41 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
+{
+       /* Edirol M-16DX */
+       /* FIXME: This quirk gives a good-working capture stream but the
+        *        playback seems problematic because of lacking of sync
+        *        with capture stream.  It needs to sync with the capture
+        *        clock.  As now, you'll get frequent sound distortions
+        *        via the playback.
+        */
+       USB_DEVICE(0x0582, 0x00c4),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
+                               .data = & (const struct snd_usb_midi_endpoint_info) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
 {
        /* BOSS GT-10 */
        USB_DEVICE(0x0582, 0x00da),
@@ -1950,6 +1985,14 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                .type = QUIRK_MIDI_STANDARD_INTERFACE
        }
 },
+{
+       USB_DEVICE(0x0ccd, 0x0028),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               .vendor_name = "TerraTec",
+               .product_name = "Aureon 5.1 MkII",
+               .ifnum = QUIRK_NO_INTERFACE
+       }
+},
 {
        USB_DEVICE(0x0ccd, 0x0035),
        .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
index 29259e74dcfa7b4b9d89202ed0987d2312b0eec5..0f5771f615dae24cd9a4073eb9b5ee95419f1124 100644 (file)
@@ -568,8 +568,11 @@ int cmd_record(int argc, const char **argv, const char *prefix)
        if (!argc && target_pid == -1 && !system_wide)
                usage_with_options(record_usage, options);
 
-       if (!nr_counters)
-               nr_counters = 1;
+       if (!nr_counters) {
+               nr_counters     = 1;
+               attrs[0].type   = PERF_TYPE_HARDWARE;
+               attrs[0].config = PERF_COUNT_HW_CPU_CYCLES;
+       }
 
        for (counter = 0; counter < nr_counters; counter++) {
                if (attrs[counter].sample_period)
index 860e116d979c834e0bdd68825a4cb83b8adf25da..f71e0d245cbada875af754e3cbae74a418fabbce 100644 (file)
@@ -440,3 +440,18 @@ by this process or by another, and doesn't affect any counters that
 this process has created on other processes.  It only enables or
 disables the group leaders, not any other members in the groups.
 
+
+Arch requirements
+-----------------
+
+If your architecture does not have hardware performance metrics, you can
+still use the generic software counters based on hrtimers for sampling.
+
+So to start with, in order to add HAVE_PERF_COUNTERS to your Kconfig, you
+will need at least this:
+       - asm/perf_counter.h - a basic stub will suffice at first
+       - support for atomic64 types (and associated helper functions)
+       - set_perf_counter_pending() implemented
+
+If your architecture does have hardware capabilities, you can override the
+weak stub hw_perf_counter_init() to register hardware counters.
index af0a5046d743a22b718b0360b392cc4107fdc6ef..87a1aca4a4246e0dad3ea82276ccd5487cddacf0 100644 (file)
@@ -53,11 +53,12 @@ static inline unsigned long long rdclock(void)
        _min1 < _min2 ? _min1 : _min2; })
 
 static inline int
-sys_perf_counter_open(struct perf_counter_attr *attr_uptr,
+sys_perf_counter_open(struct perf_counter_attr *attr,
                      pid_t pid, int cpu, int group_fd,
                      unsigned long flags)
 {
-       return syscall(__NR_perf_counter_open, attr_uptr, pid, cpu,
+       attr->size = sizeof(*attr);
+       return syscall(__NR_perf_counter_open, attr, pid, cpu,
                       group_fd, flags);
 }
 
index 9d5f1ca50e6fe4fc8466f3d97f8051a1e39253f2..5a72586e1df04dfcc7295ba1eb122a5e0d58f8de 100644 (file)
@@ -75,7 +75,7 @@ static char *sw_event_names[] = {
 #define MAX_ALIASES 8
 
 static char *hw_cache [][MAX_ALIASES] = {
-       { "L1-data"             , "l1-d", "l1d", "l1"                           },
+       { "L1-data"             , "l1-d", "l1d"                                 },
        { "L1-instruction"      , "l1-i", "l1i"                                 },
        { "L2"                  , "l2"                                          },
        { "Data-TLB"            , "dtlb", "d-tlb"                               },